[PATCH 1/1] Renamed all *.txt files to .adoc of Documentation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



All the .*txt  files of the Documentation directory has been
renamed to .adoc except the files of the RelNotes directory , the
includes directory . The needed changes are also made to Makefile and
the meason.build of the respective folders inside the Documentation
directory.

Signed-off-by: Moumita <dhar61595@xxxxxxxxx>
---
 .cirrus.yml                                   |    22 +
 .clang-format                                 |   225 +
 .editorconfig                                 |    16 +
 .gitattributes                                |    18 +
 .github/CONTRIBUTING.md                       |    22 +
 .github/PULL_REQUEST_TEMPLATE.md              |    10 +
 .github/workflows/check-style.yml             |    34 +
 .github/workflows/check-whitespace.yml        |    32 +
 .github/workflows/coverity.yml                |   163 +
 .github/workflows/l10n.yml                    |   111 +
 .github/workflows/main.yml                    |   434 +
 .gitignore                                    |   252 +
 .gitlab-ci.yml                                |   220 +
 .gitmodules                                   |     4 +
 .mailmap                                      |   304 +
 .tsan-suppressions                            |    16 +
 CODE_OF_CONDUCT.md                            |   145 +
 COPYING                                       |   360 +
 Documentation/.gitattributes                  |     1 +
 Documentation/.gitignore                      |    20 +
 Documentation/BreakingChanges.adoc            |   174 +
 Documentation/CodingGuidelines                |   947 +
 Documentation/DecisionMaking.adoc             |    74 +
 Documentation/Makefile                        |   526 +
 Documentation/MyFirstContribution.adoc        |  1395 +
 Documentation/MyFirstObjectWalk.adoc          |   898 +
 Documentation/RelNotes/1.5.0.1.txt            |    42 +
 Documentation/RelNotes/1.5.0.2.txt            |    65 +
 Documentation/RelNotes/1.5.0.3.txt            |    58 +
 Documentation/RelNotes/1.5.0.4.txt            |    22 +
 Documentation/RelNotes/1.5.0.5.txt            |    26 +
 Documentation/RelNotes/1.5.0.6.txt            |    21 +
 Documentation/RelNotes/1.5.0.7.txt            |    18 +
 Documentation/RelNotes/1.5.0.txt              |   469 +
 Documentation/RelNotes/1.5.1.1.txt            |    65 +
 Documentation/RelNotes/1.5.1.2.txt            |    50 +
 Documentation/RelNotes/1.5.1.3.txt            |    45 +
 Documentation/RelNotes/1.5.1.4.txt            |    30 +
 Documentation/RelNotes/1.5.1.5.txt            |    42 +
 Documentation/RelNotes/1.5.1.6.txt            |    45 +
 Documentation/RelNotes/1.5.1.txt              |   371 +
 Documentation/RelNotes/1.5.2.1.txt            |    47 +
 Documentation/RelNotes/1.5.2.2.txt            |    61 +
 Documentation/RelNotes/1.5.2.3.txt            |    27 +
 Documentation/RelNotes/1.5.2.4.txt            |    28 +
 Documentation/RelNotes/1.5.2.5.txt            |    30 +
 Documentation/RelNotes/1.5.2.txt              |   197 +
 Documentation/RelNotes/1.5.3.1.txt            |    10 +
 Documentation/RelNotes/1.5.3.2.txt            |    58 +
 Documentation/RelNotes/1.5.3.3.txt            |    31 +
 Documentation/RelNotes/1.5.3.4.txt            |    35 +
 Documentation/RelNotes/1.5.3.5.txt            |    94 +
 Documentation/RelNotes/1.5.3.6.txt            |    48 +
 Documentation/RelNotes/1.5.3.7.txt            |    45 +
 Documentation/RelNotes/1.5.3.8.txt            |    25 +
 Documentation/RelNotes/1.5.3.txt              |   366 +
 Documentation/RelNotes/1.5.4.1.txt            |    17 +
 Documentation/RelNotes/1.5.4.2.txt            |    43 +
 Documentation/RelNotes/1.5.4.3.txt            |    27 +
 Documentation/RelNotes/1.5.4.4.txt            |    66 +
 Documentation/RelNotes/1.5.4.5.txt            |    56 +
 Documentation/RelNotes/1.5.4.6.txt            |    43 +
 Documentation/RelNotes/1.5.4.7.txt            |    10 +
 Documentation/RelNotes/1.5.4.txt              |   377 +
 Documentation/RelNotes/1.5.5.1.txt            |    44 +
 Documentation/RelNotes/1.5.5.2.txt            |    27 +
 Documentation/RelNotes/1.5.5.3.txt            |    12 +
 Documentation/RelNotes/1.5.5.4.txt            |     7 +
 Documentation/RelNotes/1.5.5.5.txt            |    11 +
 Documentation/RelNotes/1.5.5.6.txt            |    10 +
 Documentation/RelNotes/1.5.5.txt              |   207 +
 Documentation/RelNotes/1.5.6.1.txt            |    28 +
 Documentation/RelNotes/1.5.6.2.txt            |    40 +
 Documentation/RelNotes/1.5.6.3.txt            |    52 +
 Documentation/RelNotes/1.5.6.4.txt            |    47 +
 Documentation/RelNotes/1.5.6.5.txt            |    29 +
 Documentation/RelNotes/1.5.6.6.txt            |    10 +
 Documentation/RelNotes/1.5.6.txt              |   115 +
 Documentation/RelNotes/1.6.0.1.txt            |    36 +
 Documentation/RelNotes/1.6.0.2.txt            |    81 +
 Documentation/RelNotes/1.6.0.3.txt            |   117 +
 Documentation/RelNotes/1.6.0.4.txt            |    39 +
 Documentation/RelNotes/1.6.0.5.txt            |    56 +
 Documentation/RelNotes/1.6.0.6.txt            |    33 +
 Documentation/RelNotes/1.6.0.txt              |   258 +
 Documentation/RelNotes/1.6.1.1.txt            |    59 +
 Documentation/RelNotes/1.6.1.2.txt            |    39 +
 Documentation/RelNotes/1.6.1.3.txt            |    28 +
 Documentation/RelNotes/1.6.1.4.txt            |    41 +
 Documentation/RelNotes/1.6.1.txt              |   280 +
 Documentation/RelNotes/1.6.2.1.txt            |    19 +
 Documentation/RelNotes/1.6.2.2.txt            |    45 +
 Documentation/RelNotes/1.6.2.3.txt            |    22 +
 Documentation/RelNotes/1.6.2.4.txt            |    39 +
 Documentation/RelNotes/1.6.2.5.txt            |    21 +
 Documentation/RelNotes/1.6.2.txt              |   164 +
 Documentation/RelNotes/1.6.3.1.txt            |    10 +
 Documentation/RelNotes/1.6.3.2.txt            |    61 +
 Documentation/RelNotes/1.6.3.3.txt            |    38 +
 Documentation/RelNotes/1.6.3.4.txt            |    36 +
 Documentation/RelNotes/1.6.3.txt              |   182 +
 Documentation/RelNotes/1.6.4.1.txt            |    46 +
 Documentation/RelNotes/1.6.4.2.txt            |    32 +
 Documentation/RelNotes/1.6.4.3.txt            |    29 +
 Documentation/RelNotes/1.6.4.4.txt            |    26 +
 Documentation/RelNotes/1.6.4.5.txt            |    20 +
 Documentation/RelNotes/1.6.4.txt              |   147 +
 Documentation/RelNotes/1.6.5.1.txt            |    20 +
 Documentation/RelNotes/1.6.5.2.txt            |    19 +
 Documentation/RelNotes/1.6.5.3.txt            |    63 +
 Documentation/RelNotes/1.6.5.4.txt            |    32 +
 Documentation/RelNotes/1.6.5.5.txt            |    49 +
 Documentation/RelNotes/1.6.5.6.txt            |    23 +
 Documentation/RelNotes/1.6.5.7.txt            |    19 +
 Documentation/RelNotes/1.6.5.8.txt            |    28 +
 Documentation/RelNotes/1.6.5.9.txt            |    18 +
 Documentation/RelNotes/1.6.5.txt              |   169 +
 Documentation/RelNotes/1.6.6.1.txt            |    37 +
 Documentation/RelNotes/1.6.6.2.txt            |    46 +
 Documentation/RelNotes/1.6.6.3.txt            |    23 +
 Documentation/RelNotes/1.6.6.txt              |   224 +
 Documentation/RelNotes/1.7.0.1.txt            |    35 +
 Documentation/RelNotes/1.7.0.2.txt            |    40 +
 Documentation/RelNotes/1.7.0.3.txt            |    34 +
 Documentation/RelNotes/1.7.0.4.txt            |    27 +
 Documentation/RelNotes/1.7.0.5.txt            |    26 +
 Documentation/RelNotes/1.7.0.6.txt            |    13 +
 Documentation/RelNotes/1.7.0.7.txt            |    16 +
 Documentation/RelNotes/1.7.0.8.txt            |    10 +
 Documentation/RelNotes/1.7.0.9.txt            |     8 +
 Documentation/RelNotes/1.7.0.txt              |   214 +
 Documentation/RelNotes/1.7.1.1.txt            |    96 +
 Documentation/RelNotes/1.7.1.2.txt            |    28 +
 Documentation/RelNotes/1.7.1.3.txt            |    10 +
 Documentation/RelNotes/1.7.1.4.txt            |     8 +
 Documentation/RelNotes/1.7.1.txt              |    89 +
 Documentation/RelNotes/1.7.10.1.txt           |    78 +
 Documentation/RelNotes/1.7.10.2.txt           |    85 +
 Documentation/RelNotes/1.7.10.3.txt           |    43 +
 Documentation/RelNotes/1.7.10.4.txt           |    29 +
 Documentation/RelNotes/1.7.10.5.txt           |    12 +
 Documentation/RelNotes/1.7.10.txt             |   219 +
 Documentation/RelNotes/1.7.11.1.txt           |     9 +
 Documentation/RelNotes/1.7.11.2.txt           |    53 +
 Documentation/RelNotes/1.7.11.3.txt           |    53 +
 Documentation/RelNotes/1.7.11.4.txt           |    31 +
 Documentation/RelNotes/1.7.11.5.txt           |    36 +
 Documentation/RelNotes/1.7.11.6.txt           |    84 +
 Documentation/RelNotes/1.7.11.7.txt           |    46 +
 Documentation/RelNotes/1.7.11.txt             |   139 +
 Documentation/RelNotes/1.7.12.1.txt           |   134 +
 Documentation/RelNotes/1.7.12.2.txt           |    40 +
 Documentation/RelNotes/1.7.12.3.txt           |    34 +
 Documentation/RelNotes/1.7.12.4.txt           |    23 +
 Documentation/RelNotes/1.7.12.txt             |   136 +
 Documentation/RelNotes/1.7.2.1.txt            |    25 +
 Documentation/RelNotes/1.7.2.2.txt            |    22 +
 Documentation/RelNotes/1.7.2.3.txt            |    39 +
 Documentation/RelNotes/1.7.2.4.txt            |    10 +
 Documentation/RelNotes/1.7.2.5.txt            |     8 +
 Documentation/RelNotes/1.7.2.txt              |   151 +
 Documentation/RelNotes/1.7.3.1.txt            |    14 +
 Documentation/RelNotes/1.7.3.2.txt            |     5 +
 Documentation/RelNotes/1.7.3.3.txt            |    54 +
 Documentation/RelNotes/1.7.3.4.txt            |    45 +
 Documentation/RelNotes/1.7.3.5.txt            |    34 +
 Documentation/RelNotes/1.7.3.txt              |    76 +
 Documentation/RelNotes/1.7.4.1.txt            |    27 +
 Documentation/RelNotes/1.7.4.2.txt            |    58 +
 Documentation/RelNotes/1.7.4.3.txt            |    32 +
 Documentation/RelNotes/1.7.4.4.txt            |    35 +
 Documentation/RelNotes/1.7.4.5.txt            |     4 +
 Documentation/RelNotes/1.7.4.txt              |   156 +
 Documentation/RelNotes/1.7.5.1.txt            |    47 +
 Documentation/RelNotes/1.7.5.2.txt            |    57 +
 Documentation/RelNotes/1.7.5.3.txt            |    32 +
 Documentation/RelNotes/1.7.5.4.txt            |    21 +
 Documentation/RelNotes/1.7.5.txt              |   132 +
 Documentation/RelNotes/1.7.6.1.txt            |    63 +
 Documentation/RelNotes/1.7.6.2.txt            |     8 +
 Documentation/RelNotes/1.7.6.3.txt            |    24 +
 Documentation/RelNotes/1.7.6.4.txt            |    32 +
 Documentation/RelNotes/1.7.6.5.txt            |    26 +
 Documentation/RelNotes/1.7.6.6.txt            |    16 +
 Documentation/RelNotes/1.7.6.txt              |   136 +
 Documentation/RelNotes/1.7.7.1.txt            |    60 +
 Documentation/RelNotes/1.7.7.2.txt            |    44 +
 Documentation/RelNotes/1.7.7.3.txt            |    19 +
 Documentation/RelNotes/1.7.7.4.txt            |    14 +
 Documentation/RelNotes/1.7.7.5.txt            |    14 +
 Documentation/RelNotes/1.7.7.6.txt            |    20 +
 Documentation/RelNotes/1.7.7.7.txt            |    13 +
 Documentation/RelNotes/1.7.7.txt              |   134 +
 Documentation/RelNotes/1.7.8.1.txt            |    38 +
 Documentation/RelNotes/1.7.8.2.txt            |    71 +
 Documentation/RelNotes/1.7.8.3.txt            |    16 +
 Documentation/RelNotes/1.7.8.4.txt            |    23 +
 Documentation/RelNotes/1.7.8.5.txt            |    19 +
 Documentation/RelNotes/1.7.8.6.txt            |    22 +
 Documentation/RelNotes/1.7.8.txt              |   161 +
 Documentation/RelNotes/1.7.9.1.txt            |    63 +
 Documentation/RelNotes/1.7.9.2.txt            |    69 +
 Documentation/RelNotes/1.7.9.3.txt            |    51 +
 Documentation/RelNotes/1.7.9.4.txt            |    24 +
 Documentation/RelNotes/1.7.9.5.txt            |    23 +
 Documentation/RelNotes/1.7.9.6.txt            |    12 +
 Documentation/RelNotes/1.7.9.7.txt            |    13 +
 Documentation/RelNotes/1.7.9.txt              |   112 +
 Documentation/RelNotes/1.8.0.1.txt            |    64 +
 Documentation/RelNotes/1.8.0.2.txt            |    34 +
 Documentation/RelNotes/1.8.0.3.txt            |    14 +
 Documentation/RelNotes/1.8.0.txt              |   267 +
 Documentation/RelNotes/1.8.1.1.txt            |    87 +
 Documentation/RelNotes/1.8.1.2.txt            |    25 +
 Documentation/RelNotes/1.8.1.3.txt            |    47 +
 Documentation/RelNotes/1.8.1.4.txt            |    11 +
 Documentation/RelNotes/1.8.1.5.txt            |    47 +
 Documentation/RelNotes/1.8.1.6.txt            |    39 +
 Documentation/RelNotes/1.8.1.txt              |   241 +
 Documentation/RelNotes/1.8.2.1.txt            |   115 +
 Documentation/RelNotes/1.8.2.2.txt            |    61 +
 Documentation/RelNotes/1.8.2.3.txt            |    19 +
 Documentation/RelNotes/1.8.2.txt              |   495 +
 Documentation/RelNotes/1.8.3.1.txt            |    14 +
 Documentation/RelNotes/1.8.3.2.txt            |    59 +
 Documentation/RelNotes/1.8.3.3.txt            |    47 +
 Documentation/RelNotes/1.8.3.4.txt            |    20 +
 Documentation/RelNotes/1.8.3.txt              |   436 +
 Documentation/RelNotes/1.8.4.1.txt            |    71 +
 Documentation/RelNotes/1.8.4.2.txt            |    77 +
 Documentation/RelNotes/1.8.4.3.txt            |    54 +
 Documentation/RelNotes/1.8.4.4.txt            |    10 +
 Documentation/RelNotes/1.8.4.5.txt            |    13 +
 Documentation/RelNotes/1.8.4.txt              |   486 +
 Documentation/RelNotes/1.8.5.1.txt            |     9 +
 Documentation/RelNotes/1.8.5.2.txt            |    20 +
 Documentation/RelNotes/1.8.5.3.txt            |    27 +
 Documentation/RelNotes/1.8.5.4.txt            |    48 +
 Documentation/RelNotes/1.8.5.5.txt            |    37 +
 Documentation/RelNotes/1.8.5.6.txt            |    34 +
 Documentation/RelNotes/1.8.5.txt              |   456 +
 Documentation/RelNotes/1.9.0.txt              |   345 +
 Documentation/RelNotes/1.9.1.txt              |    59 +
 Documentation/RelNotes/1.9.2.txt              |    67 +
 Documentation/RelNotes/1.9.3.txt              |    21 +
 Documentation/RelNotes/1.9.4.txt              |    16 +
 Documentation/RelNotes/1.9.5.txt              |    34 +
 Documentation/RelNotes/2.0.0.txt              |   364 +
 Documentation/RelNotes/2.0.1.txt              |   115 +
 Documentation/RelNotes/2.0.2.txt              |    32 +
 Documentation/RelNotes/2.0.3.txt              |    17 +
 Documentation/RelNotes/2.0.4.txt              |     5 +
 Documentation/RelNotes/2.0.5.txt              |    34 +
 Documentation/RelNotes/2.1.0.txt              |   391 +
 Documentation/RelNotes/2.1.1.txt              |    44 +
 Documentation/RelNotes/2.1.2.txt              |    20 +
 Documentation/RelNotes/2.1.3.txt              |    26 +
 Documentation/RelNotes/2.1.4.txt              |    34 +
 Documentation/RelNotes/2.10.0.txt             |   675 +
 Documentation/RelNotes/2.10.1.txt             |   131 +
 Documentation/RelNotes/2.10.2.txt             |   111 +
 Documentation/RelNotes/2.10.3.txt             |    55 +
 Documentation/RelNotes/2.10.4.txt             |     4 +
 Documentation/RelNotes/2.10.5.txt             |    17 +
 Documentation/RelNotes/2.11.0.txt             |   593 +
 Documentation/RelNotes/2.11.1.txt             |   168 +
 Documentation/RelNotes/2.11.2.txt             |    12 +
 Documentation/RelNotes/2.11.3.txt             |     4 +
 Documentation/RelNotes/2.11.4.txt             |    17 +
 Documentation/RelNotes/2.12.0.txt             |   500 +
 Documentation/RelNotes/2.12.1.txt             |    41 +
 Documentation/RelNotes/2.12.2.txt             |    83 +
 Documentation/RelNotes/2.12.3.txt             |    64 +
 Documentation/RelNotes/2.12.4.txt             |     4 +
 Documentation/RelNotes/2.12.5.txt             |    17 +
 Documentation/RelNotes/2.13.0.txt             |   618 +
 Documentation/RelNotes/2.13.1.txt             |   114 +
 Documentation/RelNotes/2.13.2.txt             |    54 +
 Documentation/RelNotes/2.13.3.txt             |    62 +
 Documentation/RelNotes/2.13.4.txt             |    28 +
 Documentation/RelNotes/2.13.5.txt             |     4 +
 Documentation/RelNotes/2.13.6.txt             |    17 +
 Documentation/RelNotes/2.13.7.txt             |    20 +
 Documentation/RelNotes/2.14.0.txt             |   517 +
 Documentation/RelNotes/2.14.1.txt             |     4 +
 Documentation/RelNotes/2.14.2.txt             |   105 +
 Documentation/RelNotes/2.14.3.txt             |    99 +
 Documentation/RelNotes/2.14.4.txt             |     5 +
 Documentation/RelNotes/2.14.5.txt             |    16 +
 Documentation/RelNotes/2.14.6.txt             |    54 +
 Documentation/RelNotes/2.15.0.txt             |   508 +
 Documentation/RelNotes/2.15.1.txt             |    88 +
 Documentation/RelNotes/2.15.2.txt             |    50 +
 Documentation/RelNotes/2.15.3.txt             |     6 +
 Documentation/RelNotes/2.15.4.txt             |    11 +
 Documentation/RelNotes/2.16.0.txt             |   482 +
 Documentation/RelNotes/2.16.1.txt             |    11 +
 Documentation/RelNotes/2.16.2.txt             |    30 +
 Documentation/RelNotes/2.16.3.txt             |    49 +
 Documentation/RelNotes/2.16.4.txt             |     5 +
 Documentation/RelNotes/2.16.5.txt             |     6 +
 Documentation/RelNotes/2.16.6.txt             |     8 +
 Documentation/RelNotes/2.17.0.txt             |   398 +
 Documentation/RelNotes/2.17.1.txt             |    16 +
 Documentation/RelNotes/2.17.2.txt             |    12 +
 Documentation/RelNotes/2.17.3.txt             |    12 +
 Documentation/RelNotes/2.17.4.txt             |    16 +
 Documentation/RelNotes/2.17.5.txt             |    22 +
 Documentation/RelNotes/2.17.6.txt             |    16 +
 Documentation/RelNotes/2.18.0.txt             |   583 +
 Documentation/RelNotes/2.18.1.txt             |     6 +
 Documentation/RelNotes/2.18.2.txt             |     8 +
 Documentation/RelNotes/2.18.3.txt             |     5 +
 Documentation/RelNotes/2.18.4.txt             |     5 +
 Documentation/RelNotes/2.18.5.txt             |     6 +
 Documentation/RelNotes/2.19.0.txt             |   615 +
 Documentation/RelNotes/2.19.1.txt             |     6 +
 Documentation/RelNotes/2.19.2.txt             |   108 +
 Documentation/RelNotes/2.19.3.txt             |     8 +
 Documentation/RelNotes/2.19.4.txt             |     5 +
 Documentation/RelNotes/2.19.5.txt             |     5 +
 Documentation/RelNotes/2.19.6.txt             |     6 +
 Documentation/RelNotes/2.2.0.txt              |   313 +
 Documentation/RelNotes/2.2.1.txt              |    34 +
 Documentation/RelNotes/2.2.2.txt              |    63 +
 Documentation/RelNotes/2.2.3.txt              |     9 +
 Documentation/RelNotes/2.20.0.txt             |   700 +
 Documentation/RelNotes/2.20.1.txt             |    20 +
 Documentation/RelNotes/2.20.2.txt             |    18 +
 Documentation/RelNotes/2.20.3.txt             |     5 +
 Documentation/RelNotes/2.20.4.txt             |     5 +
 Documentation/RelNotes/2.20.5.txt             |     6 +
 Documentation/RelNotes/2.21.0.txt             |   451 +
 Documentation/RelNotes/2.21.1.txt             |    12 +
 Documentation/RelNotes/2.21.2.txt             |     5 +
 Documentation/RelNotes/2.21.3.txt             |     5 +
 Documentation/RelNotes/2.21.4.txt             |     6 +
 Documentation/RelNotes/2.22.0.txt             |   597 +
 Documentation/RelNotes/2.22.1.txt             |   150 +
 Documentation/RelNotes/2.22.2.txt             |     8 +
 Documentation/RelNotes/2.22.3.txt             |     5 +
 Documentation/RelNotes/2.22.4.txt             |     5 +
 Documentation/RelNotes/2.22.5.txt             |     7 +
 Documentation/RelNotes/2.23.0.txt             |   348 +
 Documentation/RelNotes/2.23.1.txt             |     8 +
 Documentation/RelNotes/2.23.2.txt             |     5 +
 Documentation/RelNotes/2.23.3.txt             |     5 +
 Documentation/RelNotes/2.23.4.txt             |     7 +
 Documentation/RelNotes/2.24.0.txt             |   398 +
 Documentation/RelNotes/2.24.1.txt             |     8 +
 Documentation/RelNotes/2.24.2.txt             |     5 +
 Documentation/RelNotes/2.24.3.txt             |     5 +
 Documentation/RelNotes/2.24.4.txt             |     7 +
 Documentation/RelNotes/2.25.0.txt             |   370 +
 Documentation/RelNotes/2.25.1.txt             |    55 +
 Documentation/RelNotes/2.25.2.txt             |    60 +
 Documentation/RelNotes/2.25.3.txt             |     5 +
 Documentation/RelNotes/2.25.4.txt             |     5 +
 Documentation/RelNotes/2.25.5.txt             |     7 +
 Documentation/RelNotes/2.26.0.txt             |   341 +
 Documentation/RelNotes/2.26.1.txt             |     5 +
 Documentation/RelNotes/2.26.2.txt             |     5 +
 Documentation/RelNotes/2.26.3.txt             |     7 +
 Documentation/RelNotes/2.27.0.txt             |   525 +
 Documentation/RelNotes/2.27.1.txt             |     7 +
 Documentation/RelNotes/2.28.0.txt             |   236 +
 Documentation/RelNotes/2.28.1.txt             |     7 +
 Documentation/RelNotes/2.29.0.txt             |   514 +
 Documentation/RelNotes/2.29.1.txt             |    11 +
 Documentation/RelNotes/2.29.2.txt             |    12 +
 Documentation/RelNotes/2.29.3.txt             |     8 +
 Documentation/RelNotes/2.3.0.txt              |   300 +
 Documentation/RelNotes/2.3.1.txt              |    52 +
 Documentation/RelNotes/2.3.10.txt             |    18 +
 Documentation/RelNotes/2.3.2.txt              |    79 +
 Documentation/RelNotes/2.3.3.txt              |    39 +
 Documentation/RelNotes/2.3.4.txt              |    32 +
 Documentation/RelNotes/2.3.5.txt              |    44 +
 Documentation/RelNotes/2.3.6.txt              |    13 +
 Documentation/RelNotes/2.3.7.txt              |    21 +
 Documentation/RelNotes/2.3.8.txt              |    22 +
 Documentation/RelNotes/2.3.9.txt              |     9 +
 Documentation/RelNotes/2.30.0.txt             |   401 +
 Documentation/RelNotes/2.30.1.txt             |    55 +
 Documentation/RelNotes/2.30.2.txt             |     8 +
 Documentation/RelNotes/2.30.3.txt             |    24 +
 Documentation/RelNotes/2.30.4.txt             |    21 +
 Documentation/RelNotes/2.30.5.txt             |    12 +
 Documentation/RelNotes/2.30.6.txt             |    60 +
 Documentation/RelNotes/2.30.7.txt             |    86 +
 Documentation/RelNotes/2.30.8.txt             |    51 +
 Documentation/RelNotes/2.30.9.txt             |    43 +
 Documentation/RelNotes/2.31.0.txt             |   365 +
 Documentation/RelNotes/2.31.1.txt             |    27 +
 Documentation/RelNotes/2.31.2.txt             |     6 +
 Documentation/RelNotes/2.31.3.txt             |     4 +
 Documentation/RelNotes/2.31.4.txt             |     6 +
 Documentation/RelNotes/2.31.5.txt             |     5 +
 Documentation/RelNotes/2.31.6.txt             |     5 +
 Documentation/RelNotes/2.31.7.txt             |     6 +
 Documentation/RelNotes/2.31.8.txt             |     6 +
 Documentation/RelNotes/2.32.0.txt             |   416 +
 Documentation/RelNotes/2.32.1.txt             |     6 +
 Documentation/RelNotes/2.32.2.txt             |     4 +
 Documentation/RelNotes/2.32.3.txt             |     6 +
 Documentation/RelNotes/2.32.4.txt             |     5 +
 Documentation/RelNotes/2.32.5.txt             |     8 +
 Documentation/RelNotes/2.32.6.txt             |     6 +
 Documentation/RelNotes/2.32.7.txt             |     7 +
 Documentation/RelNotes/2.33.0.txt             |   279 +
 Documentation/RelNotes/2.33.1.txt             |   138 +
 Documentation/RelNotes/2.33.2.txt             |    15 +
 Documentation/RelNotes/2.33.3.txt             |     4 +
 Documentation/RelNotes/2.33.4.txt             |     6 +
 Documentation/RelNotes/2.33.5.txt             |     5 +
 Documentation/RelNotes/2.33.6.txt             |     5 +
 Documentation/RelNotes/2.33.7.txt             |     7 +
 Documentation/RelNotes/2.33.8.txt             |     7 +
 Documentation/RelNotes/2.34.0.txt             |   438 +
 Documentation/RelNotes/2.34.1.txt             |    23 +
 Documentation/RelNotes/2.34.2.txt             |     6 +
 Documentation/RelNotes/2.34.3.txt             |     4 +
 Documentation/RelNotes/2.34.4.txt             |     6 +
 Documentation/RelNotes/2.34.5.txt             |     5 +
 Documentation/RelNotes/2.34.6.txt             |     5 +
 Documentation/RelNotes/2.34.7.txt             |     7 +
 Documentation/RelNotes/2.34.8.txt             |     7 +
 Documentation/RelNotes/2.35.0.txt             |   412 +
 Documentation/RelNotes/2.35.1.txt             |     6 +
 Documentation/RelNotes/2.35.2.txt             |     7 +
 Documentation/RelNotes/2.35.3.txt             |     4 +
 Documentation/RelNotes/2.35.4.txt             |     7 +
 Documentation/RelNotes/2.35.5.txt             |     5 +
 Documentation/RelNotes/2.35.6.txt             |     5 +
 Documentation/RelNotes/2.35.7.txt             |     7 +
 Documentation/RelNotes/2.35.8.txt             |     7 +
 Documentation/RelNotes/2.36.0.txt             |   429 +
 Documentation/RelNotes/2.36.1.txt             |    33 +
 Documentation/RelNotes/2.36.2.txt             |    56 +
 Documentation/RelNotes/2.36.3.txt             |     5 +
 Documentation/RelNotes/2.36.4.txt             |     5 +
 Documentation/RelNotes/2.36.5.txt             |     7 +
 Documentation/RelNotes/2.36.6.txt             |     7 +
 Documentation/RelNotes/2.37.0.txt             |   337 +
 Documentation/RelNotes/2.37.1.txt             |    17 +
 Documentation/RelNotes/2.37.2.txt             |    88 +
 Documentation/RelNotes/2.37.3.txt             |    46 +
 Documentation/RelNotes/2.37.4.txt             |    65 +
 Documentation/RelNotes/2.37.5.txt             |     5 +
 Documentation/RelNotes/2.37.6.txt             |     7 +
 Documentation/RelNotes/2.37.7.txt             |     7 +
 Documentation/RelNotes/2.38.0.txt             |   404 +
 Documentation/RelNotes/2.38.1.txt             |     5 +
 Documentation/RelNotes/2.38.2.txt             |    67 +
 Documentation/RelNotes/2.38.3.txt             |     5 +
 Documentation/RelNotes/2.38.4.txt             |     7 +
 Documentation/RelNotes/2.38.5.txt             |     8 +
 Documentation/RelNotes/2.39.0.txt             |   346 +
 Documentation/RelNotes/2.39.1.txt             |     5 +
 Documentation/RelNotes/2.39.2.txt             |     7 +
 Documentation/RelNotes/2.39.3.txt             |    64 +
 Documentation/RelNotes/2.39.4.txt             |    79 +
 Documentation/RelNotes/2.39.5.txt             |    26 +
 Documentation/RelNotes/2.4.0.txt              |   514 +
 Documentation/RelNotes/2.4.1.txt              |    40 +
 Documentation/RelNotes/2.4.10.txt             |    18 +
 Documentation/RelNotes/2.4.11.txt             |    11 +
 Documentation/RelNotes/2.4.12.txt             |    12 +
 Documentation/RelNotes/2.4.2.txt              |    45 +
 Documentation/RelNotes/2.4.3.txt              |    76 +
 Documentation/RelNotes/2.4.4.txt              |    35 +
 Documentation/RelNotes/2.4.5.txt              |    28 +
 Documentation/RelNotes/2.4.6.txt              |    23 +
 Documentation/RelNotes/2.4.7.txt              |    53 +
 Documentation/RelNotes/2.4.8.txt              |    21 +
 Documentation/RelNotes/2.4.9.txt              |     9 +
 Documentation/RelNotes/2.40.0.txt             |   320 +
 Documentation/RelNotes/2.40.1.txt             |     8 +
 Documentation/RelNotes/2.40.2.txt             |     7 +
 Documentation/RelNotes/2.40.3.txt             |    26 +
 Documentation/RelNotes/2.40.4.txt             |     5 +
 Documentation/RelNotes/2.41.0.txt             |   399 +
 Documentation/RelNotes/2.41.1.txt             |     7 +
 Documentation/RelNotes/2.41.2.txt             |    26 +
 Documentation/RelNotes/2.41.3.txt             |     6 +
 Documentation/RelNotes/2.42.0.txt             |   329 +
 Documentation/RelNotes/2.42.1.txt             |    88 +
 Documentation/RelNotes/2.42.2.txt             |     7 +
 Documentation/RelNotes/2.42.3.txt             |    26 +
 Documentation/RelNotes/2.42.4.txt             |     6 +
 Documentation/RelNotes/2.43.0.txt             |   323 +
 Documentation/RelNotes/2.43.1.txt             |    82 +
 Documentation/RelNotes/2.43.2.txt             |    37 +
 Documentation/RelNotes/2.43.3.txt             |    12 +
 Documentation/RelNotes/2.43.4.txt             |     7 +
 Documentation/RelNotes/2.43.5.txt             |    26 +
 Documentation/RelNotes/2.43.6.txt             |     7 +
 Documentation/RelNotes/2.44.0.txt             |   334 +
 Documentation/RelNotes/2.44.1.txt             |     8 +
 Documentation/RelNotes/2.44.2.txt             |    26 +
 Documentation/RelNotes/2.44.3.txt             |     7 +
 Documentation/RelNotes/2.45.0.txt             |   476 +
 Documentation/RelNotes/2.45.1.txt             |     8 +
 Documentation/RelNotes/2.45.2.txt             |    26 +
 Documentation/RelNotes/2.45.3.txt             |   112 +
 Documentation/RelNotes/2.46.0.txt             |   461 +
 Documentation/RelNotes/2.46.1.txt             |    75 +
 Documentation/RelNotes/2.46.2.txt             |    23 +
 Documentation/RelNotes/2.46.3.txt             |     6 +
 Documentation/RelNotes/2.47.0.txt             |   342 +
 Documentation/RelNotes/2.47.1.txt             |    31 +
 Documentation/RelNotes/2.47.2.txt             |     7 +
 Documentation/RelNotes/2.48.0.txt             |   330 +
 Documentation/RelNotes/2.48.1.txt             |     7 +
 Documentation/RelNotes/2.49.0.txt             |   118 +
 Documentation/RelNotes/2.5.0.txt              |   564 +
 Documentation/RelNotes/2.5.1.txt              |    65 +
 Documentation/RelNotes/2.5.2.txt              |    63 +
 Documentation/RelNotes/2.5.3.txt              |    17 +
 Documentation/RelNotes/2.5.4.txt              |    18 +
 Documentation/RelNotes/2.5.5.txt              |    11 +
 Documentation/RelNotes/2.5.6.txt              |    12 +
 Documentation/RelNotes/2.6.0.txt              |   370 +
 Documentation/RelNotes/2.6.1.txt              |    18 +
 Documentation/RelNotes/2.6.2.txt              |    65 +
 Documentation/RelNotes/2.6.3.txt              |   111 +
 Documentation/RelNotes/2.6.4.txt              |    63 +
 Documentation/RelNotes/2.6.5.txt              |    58 +
 Documentation/RelNotes/2.6.6.txt              |    11 +
 Documentation/RelNotes/2.6.7.txt              |    12 +
 Documentation/RelNotes/2.7.0.txt              |   414 +
 Documentation/RelNotes/2.7.1.txt              |    87 +
 Documentation/RelNotes/2.7.2.txt              |    41 +
 Documentation/RelNotes/2.7.3.txt              |    62 +
 Documentation/RelNotes/2.7.4.txt              |    11 +
 Documentation/RelNotes/2.7.5.txt              |    14 +
 Documentation/RelNotes/2.7.6.txt              |    25 +
 Documentation/RelNotes/2.8.0.txt              |   439 +
 Documentation/RelNotes/2.8.1.txt              |     9 +
 Documentation/RelNotes/2.8.2.txt              |    70 +
 Documentation/RelNotes/2.8.3.txt              |   101 +
 Documentation/RelNotes/2.8.4.txt              |    69 +
 Documentation/RelNotes/2.8.5.txt              |    12 +
 Documentation/RelNotes/2.8.6.txt              |     4 +
 Documentation/RelNotes/2.9.0.txt              |   512 +
 Documentation/RelNotes/2.9.1.txt              |   117 +
 Documentation/RelNotes/2.9.2.txt              |    13 +
 Documentation/RelNotes/2.9.3.txt              |   170 +
 Documentation/RelNotes/2.9.4.txt              |    90 +
 Documentation/RelNotes/2.9.5.txt              |     4 +
 Documentation/ReviewingGuidelines.adoc        |   179 +
 Documentation/SubmittingPatches               |   838 +
 Documentation/ToolsForGit.adoc                |    51 +
 Documentation/asciidoc.conf.in                |    92 +
 Documentation/asciidoctor-extensions.rb.in    |   134 +
 Documentation/blame-options.adoc              |   149 +
 Documentation/build-docdep.perl               |    49 +
 Documentation/cat-texi.perl                   |    46 +
 Documentation/cmd-list.perl                   |    80 +
 Documentation/config.adoc                     |   557 +
 Documentation/config/add.adoc                 |    12 +
 Documentation/config/advice.adoc              |   169 +
 Documentation/config/alias.adoc               |    43 +
 Documentation/config/am.adoc                  |    14 +
 Documentation/config/apply.adoc               |    11 +
 Documentation/config/attr.adoc                |     6 +
 Documentation/config/bitmap-pseudo-merge.adoc |    91 +
 Documentation/config/blame.adoc               |    37 +
 Documentation/config/branch.adoc              |   103 +
 Documentation/config/browser.adoc             |     9 +
 Documentation/config/bundle.adoc              |    31 +
 Documentation/config/checkout.adoc            |    44 +
 Documentation/config/clean.adoc               |     3 +
 Documentation/config/clone.adoc               |    23 +
 Documentation/config/color.adoc               |   206 +
 Documentation/config/column.adoc              |    55 +
 Documentation/config/commit.adoc              |    34 +
 Documentation/config/commitgraph.adoc         |    37 +
 Documentation/config/completion.adoc          |     7 +
 Documentation/config/core.adoc                |   760 +
 Documentation/config/credential.adoc          |    55 +
 Documentation/config/diff.adoc                |   267 +
 Documentation/config/difftool.adoc            |    45 +
 Documentation/config/extensions.adoc          |   103 +
 Documentation/config/fastimport.adoc          |     8 +
 Documentation/config/feature.adoc             |    37 +
 Documentation/config/fetch.adoc               |   128 +
 Documentation/config/filter.adoc              |     9 +
 Documentation/config/fmt-merge-msg.adoc       |    22 +
 Documentation/config/format.adoc              |   153 +
 Documentation/config/fsck.adoc                |    71 +
 Documentation/config/fsmonitor--daemon.adoc   |    11 +
 Documentation/config/gc.adoc                  |   181 +
 Documentation/config/gitcvs.adoc              |    67 +
 Documentation/config/gitweb.adoc              |    16 +
 Documentation/config/gpg.adoc                 |    85 +
 Documentation/config/grep.adoc                |    28 +
 Documentation/config/gui.adoc                 |    57 +
 Documentation/config/guitool.adoc             |    50 +
 Documentation/config/help.adoc                |    26 +
 Documentation/config/http.adoc                |   355 +
 Documentation/config/i18n.adoc                |    10 +
 Documentation/config/imap.adoc                |    44 +
 Documentation/config/includeif.adoc           |     6 +
 Documentation/config/index.adoc               |    43 +
 Documentation/config/init.adoc                |    20 +
 Documentation/config/instaweb.adoc            |    20 +
 Documentation/config/interactive.adoc         |    15 +
 Documentation/config/log.adoc                 |    64 +
 Documentation/config/lsrefs.adoc              |     9 +
 Documentation/config/mailinfo.adoc            |     6 +
 Documentation/config/mailmap.adoc             |    15 +
 Documentation/config/maintenance.adoc         |    71 +
 Documentation/config/man.adoc                 |    12 +
 Documentation/config/merge.adoc               |   125 +
 Documentation/config/mergetool.adoc           |   101 +
 Documentation/config/notes.adoc               |    68 +
 Documentation/config/pack.adoc                |   207 +
 Documentation/config/pager.adoc               |     8 +
 Documentation/config/pretty.adoc              |     9 +
 Documentation/config/promisor.adoc            |     3 +
 Documentation/config/protocol.adoc            |    63 +
 Documentation/config/pull.adoc                |    33 +
 Documentation/config/push.adoc                |   134 +
 Documentation/config/rebase.adoc              |    87 +
 Documentation/config/receive.adoc             |   145 +
 Documentation/config/reftable.adoc            |    56 +
 Documentation/config/remote.adoc              |   121 +
 Documentation/config/remotes.adoc             |     3 +
 Documentation/config/repack.adoc              |    41 +
 Documentation/config/rerere.adoc              |    12 +
 Documentation/config/revert.adoc              |     3 +
 Documentation/config/safe.adoc                |    62 +
 Documentation/config/sendemail.adoc           |   115 +
 Documentation/config/sequencer.adoc           |     5 +
 Documentation/config/showbranch.adoc          |     3 +
 Documentation/config/sparse.adoc              |    27 +
 Documentation/config/splitindex.adoc          |    24 +
 Documentation/config/ssh.adoc                 |    35 +
 Documentation/config/stash.adoc               |    14 +
 Documentation/config/status.adoc              |    79 +
 Documentation/config/submodule.adoc           |   108 +
 Documentation/config/tag.adoc                 |    17 +
 Documentation/config/tar.adoc                 |     6 +
 Documentation/config/trace2.adoc              |    71 +
 Documentation/config/transfer.adoc            |   127 +
 Documentation/config/uploadarchive.adoc       |     6 +
 Documentation/config/uploadpack.adoc          |    88 +
 Documentation/config/url.adoc                 |    30 +
 Documentation/config/user.adoc                |    48 +
 Documentation/config/versionsort.adoc         |    33 +
 Documentation/config/web.adoc                 |     4 +
 Documentation/config/worktree.adoc            |    19 +
 Documentation/date-formats.adoc               |    31 +
 Documentation/diff-format.adoc                |   185 +
 Documentation/diff-generate-patch.adoc        |   210 +
 Documentation/diff-options.adoc               |   891 +
 Documentation/doc-diff                        |   186 +
 Documentation/docbook-xsl.css                 |   296 +
 Documentation/docbook.xsl                     |     8 +
 Documentation/docinfo-html.in                 |     5 +
 Documentation/everyday.txto                   |     9 +
 Documentation/fetch-options.adoc              |   331 +
 Documentation/fix-texi.perl                   |    15 +
 Documentation/fsck-msgids.adoc                |   221 +
 Documentation/generate-mergetool-list.sh      |    17 +
 Documentation/git-add.adoc                    |   456 +
 Documentation/git-am.adoc                     |   298 +
 Documentation/git-annotate.adoc               |    33 +
 Documentation/git-apply.adoc                  |   298 +
 Documentation/git-archimport.adoc             |   113 +
 Documentation/git-archive.adoc                |   243 +
 Documentation/git-bisect-lk2009.adoc          |  1358 +
 Documentation/git-bisect.adoc                 |   517 +
 Documentation/git-blame.adoc                  |   257 +
 Documentation/git-branch.adoc                 |   430 +
 Documentation/git-bugreport.adoc              |    77 +
 Documentation/git-bundle.adoc                 |   372 +
 Documentation/git-cat-file.adoc               |   412 +
 Documentation/git-check-attr.adoc             |   125 +
 Documentation/git-check-ignore.adoc           |   126 +
 Documentation/git-check-mailmap.adoc          |    64 +
 Documentation/git-check-ref-format.adoc       |   140 +
 Documentation/git-checkout-index.adoc         |   183 +
 Documentation/git-checkout.adoc               |   626 +
 Documentation/git-cherry-pick.adoc            |   259 +
 Documentation/git-cherry.adoc                 |   145 +
 Documentation/git-citool.adoc                 |    25 +
 Documentation/git-clean.adoc                  |   153 +
 Documentation/git-clone.adoc                  |   408 +
 Documentation/git-column.adoc                 |    86 +
 Documentation/git-commit-graph.adoc           |   163 +
 Documentation/git-commit-tree.adoc            |   101 +
 Documentation/git-commit.adoc                 |   589 +
 Documentation/git-config.adoc                 |   638 +
 Documentation/git-count-objects.adoc          |    54 +
 .../git-credential-cache--daemon.adoc         |    30 +
 Documentation/git-credential-cache.adoc       |   100 +
 Documentation/git-credential-store.adoc       |   110 +
 Documentation/git-credential.adoc             |   294 +
 Documentation/git-cvsexportcommit.adoc        |   118 +
 Documentation/git-cvsimport.adoc              |   228 +
 Documentation/git-cvsserver.adoc              |   433 +
 Documentation/git-daemon.adoc                 |   341 +
 Documentation/git-describe.adoc               |   211 +
 Documentation/git-diagnose.adoc               |    65 +
 Documentation/git-diff-files.adoc             |    52 +
 Documentation/git-diff-index.adoc             |   127 +
 Documentation/git-diff-tree.adoc              |   131 +
 Documentation/git-diff.adoc                   |   252 +
 Documentation/git-difftool.adoc               |   139 +
 Documentation/git-fast-export.adoc            |   284 +
 Documentation/git-fast-import.adoc            |  1591 +
 Documentation/git-fetch-pack.adoc             |   136 +
 Documentation/git-fetch.adoc                  |   317 +
 Documentation/git-filter-branch.adoc          |   703 +
 Documentation/git-fmt-merge-msg.adoc          |    82 +
 Documentation/git-for-each-ref.adoc           |   549 +
 Documentation/git-for-each-repo.adoc          |    68 +
 Documentation/git-format-patch.adoc           |   797 +
 Documentation/git-fsck-objects.adoc           |    22 +
 Documentation/git-fsck.adoc                   |   181 +
 Documentation/git-fsmonitor--daemon.adoc      |   106 +
 Documentation/git-gc.adoc                     |   178 +
 Documentation/git-get-tar-commit-id.adoc      |    30 +
 Documentation/git-grep.adoc                   |   360 +
 Documentation/git-gui.adoc                    |   121 +
 Documentation/git-hash-object.adoc            |    65 +
 Documentation/git-help.adoc                   |   231 +
 Documentation/git-hook.adoc                   |    50 +
 Documentation/git-http-backend.adoc           |   301 +
 Documentation/git-http-fetch.adoc             |    62 +
 Documentation/git-http-push.adoc              |    96 +
 Documentation/git-imap-send.adoc              |   146 +
 Documentation/git-index-pack.adoc             |   162 +
 Documentation/git-init-db.adoc                |    23 +
 Documentation/git-init.adoc                   |   189 +
 Documentation/git-instaweb.adoc               |    94 +
 Documentation/git-interpret-trailers.adoc     |   523 +
 Documentation/git-log.adoc                    |   220 +
 Documentation/git-ls-files.adoc               |   344 +
 Documentation/git-ls-remote.adoc              |   157 +
 Documentation/git-ls-tree.adoc                |   165 +
 Documentation/git-mailinfo.adoc               |   127 +
 Documentation/git-mailsplit.adoc              |    57 +
 Documentation/git-maintenance.adoc            |   419 +
 Documentation/git-merge-base.adoc             |   247 +
 Documentation/git-merge-file.adoc             |   122 +
 Documentation/git-merge-index.adoc            |    83 +
 Documentation/git-merge-one-file.adoc         |    21 +
 Documentation/git-merge-tree.adoc             |   330 +
 Documentation/git-merge.adoc                  |   413 +
 Documentation/git-mergetool--lib.adoc         |    53 +
 Documentation/git-mergetool.adoc              |   130 +
 Documentation/git-mktag.adoc                  |    66 +
 Documentation/git-mktree.adoc                 |    40 +
 Documentation/git-multi-pack-index.adoc       |   147 +
 Documentation/git-mv.adoc                     |    69 +
 Documentation/git-name-rev.adoc               |   112 +
 Documentation/git-notes.adoc                  |   386 +
 Documentation/git-p4.adoc                     |   803 +
 Documentation/git-pack-objects.adoc           |   460 +
 Documentation/git-pack-redundant.adoc         |    64 +
 Documentation/git-pack-refs.adoc              |   109 +
 Documentation/git-patch-id.adoc               |    69 +
 Documentation/git-prune-packed.adoc           |    47 +
 Documentation/git-prune.adoc                  |    89 +
 Documentation/git-pull.adoc                   |   254 +
 Documentation/git-push.adoc                   |   709 +
 Documentation/git-quiltimport.adoc            |    64 +
 Documentation/git-range-diff.adoc             |   312 +
 Documentation/git-read-tree.adoc              |   437 +
 Documentation/git-rebase.adoc                 |  1304 +
 Documentation/git-receive-pack.adoc           |   261 +
 Documentation/git-reflog.adoc                 |   138 +
 Documentation/git-refs.adoc                   |    72 +
 Documentation/git-remote-ext.adoc             |   125 +
 Documentation/git-remote-fd.adoc              |    59 +
 Documentation/git-remote-helpers.txto         |     9 +
 Documentation/git-remote.adoc                 |   269 +
 Documentation/git-repack.adoc                 |   279 +
 Documentation/git-replace.adoc                |   161 +
 Documentation/git-replay.adoc                 |   127 +
 Documentation/git-request-pull.adoc           |    79 +
 Documentation/git-rerere.adoc                 |   222 +
 Documentation/git-reset.adoc                  |   506 +
 Documentation/git-restore.adoc                |   222 +
 Documentation/git-rev-list.adoc               |   129 +
 Documentation/git-rev-parse.adoc              |   516 +
 Documentation/git-revert.adoc                 |   168 +
 Documentation/git-rm.adoc                     |   204 +
 Documentation/git-send-email.adoc             |   543 +
 Documentation/git-send-pack.adoc              |   157 +
 Documentation/git-sh-i18n--envsubst.adoc      |    36 +
 Documentation/git-sh-i18n.adoc                |    43 +
 Documentation/git-sh-setup.adoc               |    95 +
 Documentation/git-shell.adoc                  |   106 +
 Documentation/git-shortlog.adoc               |   130 +
 Documentation/git-show-branch.adoc            |   211 +
 Documentation/git-show-index.adoc             |    52 +
 Documentation/git-show-ref.adoc               |   214 +
 Documentation/git-show.adoc                   |    90 +
 Documentation/git-sparse-checkout.adoc        |   483 +
 Documentation/git-stage.adoc                  |    23 +
 Documentation/git-stash.adoc                  |   406 +
 Documentation/git-status.adoc                 |   529 +
 Documentation/git-stripspace.adoc             |    94 +
 Documentation/git-submodule.adoc              |   473 +
 Documentation/git-svn.adoc                    |  1174 +
 Documentation/git-switch.adoc                 |   287 +
 Documentation/git-symbolic-ref.adoc           |    82 +
 Documentation/git-tag.adoc                    |   418 +
 Documentation/git-tools.adoc                  |    10 +
 Documentation/git-unpack-file.adoc            |    28 +
 Documentation/git-unpack-objects.adoc         |    52 +
 Documentation/git-update-index.adoc           |   613 +
 Documentation/git-update-ref.adoc             |   199 +
 Documentation/git-update-server-info.adoc     |    41 +
 Documentation/git-upload-archive.adoc         |    62 +
 Documentation/git-upload-pack.adoc            |    95 +
 Documentation/git-var.adoc                    |   105 +
 Documentation/git-verify-commit.adoc          |    32 +
 Documentation/git-verify-pack.adoc            |    53 +
 Documentation/git-verify-tag.adoc             |    32 +
 Documentation/git-version.adoc                |    28 +
 Documentation/git-web--browse.adoc            |   124 +
 Documentation/git-whatchanged.adoc            |    43 +
 Documentation/git-worktree.adoc               |   529 +
 Documentation/git-write-tree.adoc             |    42 +
 Documentation/git.adoc                        |  1190 +
 Documentation/gitattributes.adoc              |  1374 +
 Documentation/gitcli.adoc                     |   269 +
 Documentation/gitcore-tutorial.adoc           |  1660 +
 Documentation/gitcredentials.adoc             |   336 +
 Documentation/gitcvs-migration.adoc           |   206 +
 Documentation/gitdiffcore.adoc                |   333 +
 Documentation/giteveryday.adoc                |   455 +
 Documentation/gitfaq.adoc                     |   542 +
 Documentation/gitformat-bundle.adoc           |   111 +
 Documentation/gitformat-chunk.adoc            |   133 +
 Documentation/gitformat-commit-graph.adoc     |   186 +
 Documentation/gitformat-index.adoc            |   424 +
 Documentation/gitformat-pack.adoc             |   681 +
 Documentation/gitformat-signature.adoc        |   229 +
 Documentation/gitglossary.adoc                |    27 +
 Documentation/githooks.adoc                   |   767 +
 Documentation/gitignore.adoc                  |   243 +
 Documentation/gitk.adoc                       |   188 +
 Documentation/gitmailmap.adoc                 |   130 +
 Documentation/gitmodules.adoc                 |   135 +
 Documentation/gitnamespaces.adoc              |    68 +
 Documentation/gitpacking.adoc                 |   195 +
 Documentation/gitprotocol-capabilities.adoc   |   396 +
 Documentation/gitprotocol-common.adoc         |   118 +
 Documentation/gitprotocol-http.adoc           |   543 +
 Documentation/gitprotocol-pack.adoc           |   725 +
 Documentation/gitprotocol-v2.adoc             |   786 +
 Documentation/gitremote-helpers.adoc          |   562 +
 Documentation/gitrepository-layout.adoc       |   311 +
 Documentation/gitrevisions.adoc               |    36 +
 Documentation/gitsubmodules.adoc              |   287 +
 Documentation/gittutorial-2.adoc              |   436 +
 Documentation/gittutorial.adoc                |   676 +
 Documentation/gitweb.adoc                     |   703 +
 Documentation/gitweb.conf.adoc                |   981 +
 Documentation/gitworkflows.adoc               |   479 +
 Documentation/glossary-content.adoc           |   766 +
 Documentation/howto-index.adoc                |     6 +
 .../howto/coordinate-embargoed-releases.adoc  |   246 +
 Documentation/howto/howto-index.sh            |    56 +
 .../howto/keep-canonical-history-correct.adoc |   216 +
 Documentation/howto/maintain-git.adoc         |   595 +
 Documentation/howto/meson.build               |    62 +
 Documentation/howto/new-command.adoc          |   106 +
 .../howto/rebase-from-internal-branch.adoc    |   164 +
 .../howto/rebuild-from-update-hook.adoc       |    90 +
 .../howto/recover-corrupted-blob-object.adoc  |   144 +
 .../recover-corrupted-object-harder.adoc      |   479 +
 .../howto/revert-a-faulty-merge.adoc          |   273 +
 Documentation/howto/revert-branch-rebase.adoc |   187 +
 .../howto/separating-topic-branches.adoc      |    94 +
 .../howto/setup-git-server-over-http.adoc     |   285 +
 Documentation/howto/update-hook-example.adoc  |   192 +
 Documentation/howto/use-git-daemon.adoc       |    54 +
 Documentation/howto/using-merge-subtree.adoc  |    75 +
 .../using-signed-tag-in-pull-request.adoc     |   217 +
 Documentation/i18n.adoc                       |    70 +
 .../includes/cmd-config-section-all.txt       |     3 +
 .../includes/cmd-config-section-rest.txt      |     3 +
 Documentation/install-doc-quick.sh            |    40 +
 Documentation/install-webdoc.sh               |    39 +
 Documentation/line-range-format.adoc          |    32 +
 Documentation/line-range-options.adoc         |    15 +
 Documentation/lint-fsck-msgids.perl           |    70 +
 Documentation/lint-gitlink.perl               |    69 +
 Documentation/lint-man-end-blurb.perl         |    24 +
 Documentation/lint-man-section-order.perl     |   108 +
 Documentation/lint-manpages.sh                |   108 +
 Documentation/manpage-bold-literal.xsl        |    16 +
 Documentation/manpage-normal.xsl              |    14 +
 Documentation/manpage.xsl                     |     3 +
 Documentation/merge-options.adoc              |   210 +
 Documentation/merge-strategies.adoc           |   153 +
 Documentation/mergetools/vimdiff.txt          |   195 +
 Documentation/meson.build                     |   504 +
 Documentation/object-format-disclaimer.adoc   |     9 +
 Documentation/pretty-formats.adoc             |   388 +
 Documentation/pretty-options.adoc             |   102 +
 Documentation/pull-fetch-param.adoc           |   120 +
 Documentation/ref-reachability-filters.adoc   |     7 +
 Documentation/ref-storage-format.adoc         |     3 +
 Documentation/rerere-options.adoc             |     9 +
 Documentation/rev-list-description.adoc       |    61 +
 Documentation/rev-list-options.adoc           |  1216 +
 Documentation/revisions.adoc                  |   421 +
 Documentation/scalar.adoc                     |   179 +
 Documentation/sequencer.adoc                  |    16 +
 Documentation/signoff-option.adoc             |    18 +
 Documentation/technical/.gitignore            |     1 +
 .../technical/api-error-handling.adoc         |   103 +
 Documentation/technical/api-index-skel.adoc   |    13 +
 Documentation/technical/api-index.sh          |    39 +
 Documentation/technical/api-merge.adoc        |    36 +
 .../technical/api-parse-options.adoc          |   349 +
 Documentation/technical/api-path-walk.adoc    |    63 +
 Documentation/technical/api-simple-ipc.adoc   |   105 +
 Documentation/technical/api-trace2.adoc       |  1352 +
 Documentation/technical/bitmap-format.adoc    |   398 +
 Documentation/technical/build-systems.adoc    |   224 +
 Documentation/technical/bundle-uri.adoc       |   572 +
 Documentation/technical/commit-graph.adoc     |   401 +
 .../technical/directory-rename-detection.adoc |   118 +
 .../technical/hash-function-transition.adoc   |   830 +
 .../long-running-process-protocol.adoc        |    50 +
 Documentation/technical/meson.build           |    67 +
 Documentation/technical/multi-pack-index.adoc |   203 +
 Documentation/technical/pack-heuristics.adoc  |   460 +
 Documentation/technical/packfile-uri.adoc     |    82 +
 .../technical/parallel-checkout.adoc          |   270 +
 Documentation/technical/partial-clone.adoc    |   367 +
 Documentation/technical/platform-support.adoc |   190 +
 Documentation/technical/racy-git.adoc         |   201 +
 Documentation/technical/reftable.adoc         |  1098 +
 .../technical/remembering-renames.adoc        |   671 +
 .../technical/repository-version.adoc         |    70 +
 Documentation/technical/rerere.adoc           |   186 +
 Documentation/technical/scalar.adoc           |    66 +
 .../technical/send-pack-pipeline.adoc         |    63 +
 Documentation/technical/shallow.adoc          |    60 +
 Documentation/technical/sparse-checkout.adoc  |  1103 +
 Documentation/technical/sparse-index.adoc     |   208 +
 Documentation/technical/trivial-merge.adoc    |   121 +
 Documentation/technical/unit-tests.adoc       |   242 +
 Documentation/texi.xsl                        |    26 +
 Documentation/trace2-target-values.adoc       |    12 +
 Documentation/transfer-data-leaks.adoc        |    30 +
 Documentation/urls-remotes.adoc               |    96 +
 Documentation/urls.adoc                       |   110 +
 Documentation/user-manual.adoc                |  4638 +++
 GIT-BUILD-OPTIONS.in                          |    48 +
 GIT-VERSION-FILE.in                           |     1 +
 GIT-VERSION-GEN                               |    96 +
 INSTALL                                       |   236 +
 LGPL-2.1                                      |   511 +
 Makefile                                      |  3889 ++
 README.md                                     |    74 +
 RelNotes                                      |     1 +
 SECURITY.md                                   |    51 +
 abspath.c                                     |   327 +
 abspath.h                                     |    54 +
 aclocal.m4                                    |    40 +
 add-interactive.c                             |  1211 +
 add-interactive.h                             |    41 +
 add-patch.c                                   |  1820 +
 advice.c                                      |   313 +
 advice.h                                      |    86 +
 alias.c                                       |   139 +
 alias.h                                       |    15 +
 alloc.c                                       |   123 +
 alloc.h                                       |    20 +
 apply.c                                       |  5163 +++
 apply.h                                       |   190 +
 archive-tar.c                                 |   550 +
 archive-zip.c                                 |   659 +
 archive.c                                     |   809 +
 archive.h                                     |    63 +
 attr.c                                        |  1348 +
 attr.h                                        |   286 +
 banned.h                                      |    44 +
 base85.c                                      |   132 +
 base85.h                                      |     7 +
 bin-wrappers/.gitignore                       |     9 +
 bin-wrappers/meson.build                      |    28 +
 bin-wrappers/wrap-for-bin.sh                  |    37 +
 bisect.c                                      |  1224 +
 bisect.h                                      |    85 +
 blame.c                                       |  2953 ++
 blame.h                                       |   191 +
 blob.c                                        |    18 +
 blob.h                                        |    24 +
 block-sha1/sha1.c                             |   230 +
 block-sha1/sha1.h                             |    24 +
 bloom.c                                       |   542 +
 bloom.h                                       |   140 +
 branch.c                                      |   860 +
 branch.h                                      |   158 +
 builtin.h                                     |   257 +
 builtin/add.c                                 |   593 +
 builtin/am.c                                  |  2544 ++
 builtin/annotate.c                            |    36 +
 builtin/apply.c                               |    46 +
 builtin/archive.c                             |   117 +
 builtin/bisect.c                              |  1470 +
 builtin/blame.c                               |  1247 +
 builtin/branch.c                              |  1023 +
 builtin/bugreport.c                           |   208 +
 builtin/bundle.c                              |   255 +
 builtin/cat-file.c                            |  1101 +
 builtin/check-attr.c                          |   207 +
 builtin/check-ignore.c                        |   201 +
 builtin/check-mailmap.c                       |    86 +
 builtin/check-ref-format.c                    |   100 +
 builtin/checkout--worker.c                    |   153 +
 builtin/checkout-index.c                      |   350 +
 builtin/checkout.c                            |  2085 ++
 builtin/clean.c                               |  1099 +
 builtin/clone.c                               |  1596 +
 builtin/column.c                              |    68 +
 builtin/commit-graph.c                        |   359 +
 builtin/commit-tree.c                         |   151 +
 builtin/commit.c                              |  1927 +
 builtin/config.c                              |  1436 +
 builtin/count-objects.c                       |   177 +
 builtin/credential-cache--daemon.c            |   354 +
 builtin/credential-cache.c                    |   207 +
 builtin/credential-store.c                    |   227 +
 builtin/credential.c                          |    51 +
 builtin/describe.c                            |   743 +
 builtin/diagnose.c                            |    70 +
 builtin/diff-files.c                          |    93 +
 builtin/diff-index.c                          |    85 +
 builtin/diff-tree.c                           |   238 +
 builtin/diff.c                                |   635 +
 builtin/difftool.c                            |   804 +
 builtin/fast-export.c                         |  1315 +
 builtin/fast-import.c                         |  3690 ++
 builtin/fetch-pack.c                          |   304 +
 builtin/fetch.c                               |  2693 ++
 builtin/fmt-merge-msg.c                       |    78 +
 builtin/for-each-ref.c                        |   114 +
 builtin/for-each-repo.c                       |    75 +
 builtin/fsck.c                                |  1119 +
 builtin/fsmonitor--daemon.c                   |  1606 +
 builtin/gc.c                                  |  3015 ++
 builtin/get-tar-commit-id.c                   |    58 +
 builtin/grep.c                                |  1286 +
 builtin/hash-object.c                         |   180 +
 builtin/help.c                                |   734 +
 builtin/hook.c                                |    86 +
 builtin/index-pack.c                          |  2130 ++
 builtin/init-db.c                             |   260 +
 builtin/interpret-trailers.c                  |   247 +
 builtin/log.c                                 |  2721 ++
 builtin/ls-files.c                            |   768 +
 builtin/ls-remote.c                           |   179 +
 builtin/ls-tree.c                             |   451 +
 builtin/mailinfo.c                            |   119 +
 builtin/mailsplit.c                           |   377 +
 builtin/merge-base.c                          |   207 +
 builtin/merge-file.c                          |   190 +
 builtin/merge-index.c                         |   131 +
 builtin/merge-ours.c                          |    38 +
 builtin/merge-recursive.c                     |   100 +
 builtin/merge-tree.c                          |   680 +
 builtin/merge.c                               |  1825 +
 builtin/mktag.c                               |   115 +
 builtin/mktree.c                              |   208 +
 builtin/multi-pack-index.c                    |   308 +
 builtin/mv.c                                  |   593 +
 builtin/name-rev.c                            |   690 +
 builtin/notes.c                               |  1162 +
 builtin/pack-objects.c                        |  4704 +++
 builtin/pack-redundant.c                      |   705 +
 builtin/pack-refs.c                           |    61 +
 builtin/patch-id.c                            |   262 +
 builtin/prune-packed.c                        |    35 +
 builtin/prune.c                               |   219 +
 builtin/pull.c                                |  1167 +
 builtin/push.c                                |   672 +
 builtin/range-diff.c                          |   175 +
 builtin/read-tree.c                           |   289 +
 builtin/rebase.c                              |  1892 +
 builtin/receive-pack.c                        |  2641 ++
 builtin/reflog.c                              |   479 +
 builtin/refs.c                                |   120 +
 builtin/remote-ext.c                          |   211 +
 builtin/remote-fd.c                           |    88 +
 builtin/remote.c                              |  1858 +
 builtin/repack.c                              |  1587 +
 builtin/replace.c                             |   640 +
 builtin/replay.c                              |   463 +
 builtin/rerere.c                              |   129 +
 builtin/reset.c                               |   534 +
 builtin/rev-list.c                            |   831 +
 builtin/rev-parse.c                           |  1177 +
 builtin/revert.c                              |   306 +
 builtin/rm.c                                  |   449 +
 builtin/send-pack.c                           |   350 +
 builtin/shortlog.c                            |   534 +
 builtin/show-branch.c                         |  1004 +
 builtin/show-index.c                          |   125 +
 builtin/show-ref.c                            |   343 +
 builtin/sparse-checkout.c                     |  1090 +
 builtin/stash.c                               |  1948 +
 builtin/stripspace.c                          |    73 +
 builtin/submodule--helper.c                   |  3601 ++
 builtin/symbolic-ref.c                        |    97 +
 builtin/tag.c                                 |   709 +
 builtin/unpack-file.c                         |    49 +
 builtin/unpack-objects.c                      |   689 +
 builtin/update-index.c                        |  1256 +
 builtin/update-ref.c                          |   805 +
 builtin/update-server-info.c                  |    31 +
 builtin/upload-archive.c                      |   147 +
 builtin/upload-pack.c                         |    89 +
 builtin/var.c                                 |   247 +
 builtin/verify-commit.c                       |    84 +
 builtin/verify-pack.c                         |    95 +
 builtin/verify-tag.c                          |    73 +
 builtin/worktree.c                            |  1441 +
 builtin/write-tree.c                          |    66 +
 bulk-checkin.c                                |   390 +
 bulk-checkin.h                                |    39 +
 bundle-uri.c                                  |   954 +
 bundle-uri.h                                  |   168 +
 bundle.c                                      |   632 +
 bundle.h                                      |    72 +
 cache-tree.c                                  |  1028 +
 cache-tree.h                                  |    55 +
 cbtree.c                                      |   136 +
 cbtree.h                                      |    54 +
 chdir-notify.c                                |    96 +
 chdir-notify.h                                |    73 +
 check-builtins.sh                             |    34 +
 checkout.c                                    |    75 +
 checkout.h                                    |    15 +
 chunk-format.c                                |   215 +
 chunk-format.h                                |    73 +
 ci/check-directional-formatting.bash          |    27 +
 ci/check-whitespace.sh                        |   101 +
 ci/config/README                              |    14 +
 ci/install-dependencies.sh                    |   160 +
 ci/install-sdk.ps1                            |    12 +
 ci/lib.sh                                     |   399 +
 ci/make-test-artifacts.sh                     |    12 +
 ci/mount-fileshare.sh                         |    25 +
 ci/print-test-failures.sh                     |    94 +
 ci/run-build-and-minimal-fuzzers.sh           |    31 +
 ci/run-build-and-tests.sh                     |    77 +
 ci/run-static-analysis.sh                     |    34 +
 ci/run-style-check.sh                         |    25 +
 ci/run-test-slice.sh                          |    23 +
 ci/test-documentation.sh                      |    46 +
 ci/util/extract-trash-dirs.sh                 |    50 +
 color.c                                       |   489 +
 color.h                                       |   140 +
 column.c                                      |   412 +
 column.h                                      |    46 +
 combine-diff.c                                |  1669 +
 command-list.txt                              |   242 +
 commit-graph.c                                |  2924 ++
 commit-graph.h                                |   216 +
 commit-reach.c                                |  1363 +
 commit-reach.h                                |   159 +
 commit-slab-decl.h                            |    44 +
 commit-slab-impl.h                            |   105 +
 commit-slab.h                                 |    66 +
 commit.c                                      |  1961 +
 commit.h                                      |   376 +
 common-main.c                                 |    92 +
 compat/.gitattributes                         |     1 +
 compat/access.c                               |    31 +
 compat/apple-common-crypto.h                  |    96 +
 compat/basename.c                             |    83 +
 compat/bswap.h                                |   193 +
 compat/compiler.h                             |    40 +
 compat/disk.h                                 |    57 +
 compat/fileno.c                               |     7 +
 compat/fopen.c                                |    37 +
 compat/fsmonitor/fsm-darwin-gcc.h             |    90 +
 compat/fsmonitor/fsm-health-darwin.c          |    24 +
 compat/fsmonitor/fsm-health-win32.c           |   280 +
 compat/fsmonitor/fsm-health.h                 |    47 +
 compat/fsmonitor/fsm-ipc-darwin.c             |    59 +
 compat/fsmonitor/fsm-ipc-win32.c              |    11 +
 compat/fsmonitor/fsm-listen-darwin.c          |   545 +
 compat/fsmonitor/fsm-listen-win32.c           |   879 +
 compat/fsmonitor/fsm-listen.h                 |    49 +
 compat/fsmonitor/fsm-path-utils-darwin.c      |   138 +
 compat/fsmonitor/fsm-path-utils-win32.c       |   148 +
 compat/fsmonitor/fsm-settings-darwin.c        |    63 +
 compat/fsmonitor/fsm-settings-win32.c         |    37 +
 compat/hstrerror.c                            |    21 +
 compat/inet_ntop.c                            |   185 +
 compat/inet_pton.c                            |   215 +
 compat/linux/procinfo.c                       |   176 +
 compat/memmem.c                               |    32 +
 compat/mingw.c                                |  3338 ++
 compat/mingw.h                                |   639 +
 compat/mkdir.c                                |    24 +
 compat/mkdtemp.c                              |     8 +
 compat/mmap.c                                 |    45 +
 compat/msvc.c                                 |     6 +
 compat/msvc.h                                 |    33 +
 compat/nedmalloc/License.txt                  |    23 +
 compat/nedmalloc/Readme.txt                   |   136 +
 compat/nedmalloc/malloc.c.h                   |  5761 +++
 compat/nedmalloc/nedmalloc.c                  |   954 +
 compat/nedmalloc/nedmalloc.h                  |   180 +
 compat/nonblock.c                             |    50 +
 compat/nonblock.h                             |     9 +
 compat/obstack.c                              |   413 +
 compat/obstack.h                              |   511 +
 compat/open.c                                 |    25 +
 compat/poll/poll.c                            |   610 +
 compat/poll/poll.h                            |    67 +
 compat/pread.c                                |    19 +
 compat/precompose_utf8.c                      |   202 +
 compat/precompose_utf8.h                      |    47 +
 compat/qsort_s.c                              |    63 +
 compat/regcomp_enhanced.c                     |     9 +
 compat/regex/regcomp.c                        |  3893 ++
 compat/regex/regex.c                          |    90 +
 compat/regex/regex.h                          |   586 +
 compat/regex/regex_internal.c                 |  1743 +
 compat/regex/regex_internal.h                 |   808 +
 compat/regex/regexec.c                        |  4368 +++
 compat/setenv.c                               |    40 +
 compat/sha1-chunked.c                         |    20 +
 compat/sha1-chunked.h                         |     2 +
 compat/simple-ipc/ipc-shared.c                |    30 +
 compat/simple-ipc/ipc-unix-socket.c           |  1048 +
 compat/simple-ipc/ipc-win32.c                 |   944 +
 compat/snprintf.c                             |    69 +
 compat/stat.c                                 |    48 +
 compat/strcasestr.c                           |    22 +
 compat/strdup.c                               |    11 +
 compat/strlcpy.c                              |    13 +
 compat/strtoimax.c                            |    10 +
 compat/strtoumax.c                            |    10 +
 compat/stub/procinfo.c                        |    11 +
 compat/terminal.c                             |   620 +
 compat/terminal.h                             |    27 +
 compat/unsetenv.c                             |    29 +
 compat/vcbuild/.gitignore                     |     3 +
 compat/vcbuild/README                         |   112 +
 compat/vcbuild/find_vs_env.bat                |   168 +
 compat/vcbuild/include/sys/param.h            |     1 +
 compat/vcbuild/include/sys/time.h             |     1 +
 compat/vcbuild/include/sys/utime.h            |    34 +
 compat/vcbuild/include/unistd.h               |   107 +
 compat/vcbuild/include/utime.h                |     1 +
 compat/vcbuild/scripts/clink.pl               |   133 +
 compat/vcbuild/scripts/lib.pl                 |    26 +
 compat/vcbuild/vcpkg_copy_dlls.bat            |    39 +
 compat/vcbuild/vcpkg_install.bat              |    80 +
 compat/win32.h                                |    41 +
 compat/win32/alloca.h                         |     1 +
 compat/win32/dirent.c                         |    92 +
 compat/win32/dirent.h                         |    20 +
 compat/win32/flush.c                          |    28 +
 compat/win32/git.manifest                     |    25 +
 compat/win32/headless.c                       |   118 +
 compat/win32/lazyload.h                       |    61 +
 compat/win32/path-utils.c                     |    91 +
 compat/win32/path-utils.h                     |    37 +
 compat/win32/pthread.c                        |    61 +
 compat/win32/pthread.h                        |   100 +
 compat/win32/syslog.c                         |    83 +
 compat/win32/syslog.h                         |    20 +
 compat/win32/trace2_win32_process_info.c      |   195 +
 compat/win32mmap.c                            |    48 +
 compat/winansi.c                              |   685 +
 compat/zlib-uncompress2.c                     |    96 +
 config.c                                      |  3812 ++
 config.h                                      |   848 +
 config.mak.dev                                |   101 +
 config.mak.in                                 |    24 +
 config.mak.uname                              |   837 +
 configure.ac                                  |  1295 +
 connect.c                                     |  1527 +
 connect.h                                     |    33 +
 connected.c                                   |   167 +
 connected.h                                   |    72 +
 contrib/README                                |    43 +
 contrib/buildsystems/CMakeLists.txt           |  1243 +
 contrib/buildsystems/Generators.pm            |    42 +
 contrib/buildsystems/Generators/QMake.pm      |   189 +
 contrib/buildsystems/Generators/Vcproj.pm     |   579 +
 contrib/buildsystems/Generators/Vcxproj.pm    |   402 +
 contrib/buildsystems/engine.pl                |   395 +
 contrib/buildsystems/generate                 |    29 +
 contrib/buildsystems/git-version.in           |     1 +
 contrib/buildsystems/parse.pl                 |   228 +
 contrib/coccinelle/.gitignore                 |     1 +
 contrib/coccinelle/README                     |   124 +
 contrib/coccinelle/array.cocci                |   103 +
 contrib/coccinelle/commit.cocci               |    52 +
 .../coccinelle/config_fn_ctx.pending.cocci    |   144 +
 contrib/coccinelle/equals-null.cocci          |    30 +
 contrib/coccinelle/flex_alloc.cocci           |    13 +
 contrib/coccinelle/free.cocci                 |    45 +
 contrib/coccinelle/git_config_number.cocci    |    27 +
 contrib/coccinelle/hashmap.cocci              |    16 +
 contrib/coccinelle/index-compatibility.cocci  |   157 +
 contrib/coccinelle/object_id.cocci            |    75 +
 contrib/coccinelle/preincr.cocci              |     5 +
 contrib/coccinelle/qsort.cocci                |    37 +
 contrib/coccinelle/refs.cocci                 |   103 +
 contrib/coccinelle/spatchcache                |   304 +
 contrib/coccinelle/strbuf.cocci               |    62 +
 contrib/coccinelle/swap.cocci                 |    28 +
 contrib/coccinelle/tests/free.c               |    11 +
 contrib/coccinelle/tests/free.res             |     9 +
 contrib/coccinelle/the_repository.cocci       |   123 +
 contrib/coccinelle/xcalloc.cocci              |    10 +
 contrib/coccinelle/xopen.cocci                |    19 +
 contrib/coccinelle/xstrdup_or_null.cocci      |     5 +
 contrib/coccinelle/xstrncmpz.cocci            |    28 +
 contrib/completion/.gitattributes             |     1 +
 contrib/completion/git-completion.bash        |  3984 +++
 contrib/completion/git-completion.tcsh        |   127 +
 contrib/completion/git-completion.zsh         |   295 +
 contrib/completion/git-prompt.sh              |   672 +
 contrib/completion/meson.build                |    16 +
 contrib/contacts/.gitignore                   |     3 +
 contrib/contacts/Makefile                     |    71 +
 contrib/contacts/git-contacts                 |   203 +
 contrib/contacts/git-contacts.txt             |    94 +
 contrib/coverage-diff.sh                      |   103 +
 contrib/credential/libsecret/.gitignore       |     1 +
 contrib/credential/libsecret/Makefile         |    25 +
 .../libsecret/git-credential-libsecret.c      |   454 +
 contrib/credential/netrc/.gitignore           |     1 +
 contrib/credential/netrc/Makefile             |    30 +
 .../netrc/git-credential-netrc.perl           |   443 +
 .../netrc/t-git-credential-netrc.sh           |    22 +
 .../credential/netrc/test.command-option-gpg  |     2 +
 contrib/credential/netrc/test.git-config-gpg  |     2 +
 contrib/credential/netrc/test.netrc           |    13 +
 contrib/credential/netrc/test.netrc.gpg       |     0
 contrib/credential/netrc/test.pl              |   139 +
 contrib/credential/osxkeychain/.gitignore     |     1 +
 contrib/credential/osxkeychain/Makefile       |    18 +
 .../osxkeychain/git-credential-osxkeychain.c  |   447 +
 contrib/credential/wincred/Makefile           |    22 +
 .../wincred/git-credential-wincred.c          |   352 +
 contrib/diff-highlight/.gitignore             |     2 +
 contrib/diff-highlight/DiffHighlight.pm       |   285 +
 contrib/diff-highlight/Makefile               |    23 +
 contrib/diff-highlight/README                 |   223 +
 contrib/diff-highlight/diff-highlight.perl    |     8 +
 contrib/diff-highlight/t/.gitignore           |     2 +
 contrib/diff-highlight/t/Makefile             |    22 +
 .../diff-highlight/t/t9400-diff-highlight.sh  |   341 +
 contrib/emacs/README                          |    33 +
 contrib/emacs/git-blame.el                    |     6 +
 contrib/emacs/git.el                          |     6 +
 contrib/examples/README                       |    20 +
 contrib/fast-import/git-import.perl           |    64 +
 contrib/fast-import/git-import.sh             |    38 +
 contrib/fast-import/git-p4.README             |    12 +
 contrib/fast-import/import-directories.perl   |   416 +
 contrib/fast-import/import-tars.perl          |   227 +
 contrib/fast-import/import-zips.py            |    78 +
 contrib/git-jump/README                       |   123 +
 contrib/git-jump/git-jump                     |   117 +
 contrib/git-resurrect.sh                      |   181 +
 contrib/git-shell-commands/README             |    18 +
 contrib/git-shell-commands/help               |    18 +
 contrib/git-shell-commands/list               |    10 +
 contrib/hooks/multimail/README.Git            |     7 +
 contrib/hooks/post-receive-email              |   759 +
 contrib/hooks/pre-auto-gc-battery             |    42 +
 contrib/hooks/setgitperms.perl                |   214 +
 contrib/hooks/update-paranoid                 |   421 +
 contrib/long-running-filter/example.pl        |   132 +
 contrib/meson.build                           |     3 +
 contrib/mw-to-git/.gitignore                  |     2 +
 contrib/mw-to-git/.perlcriticrc               |    28 +
 contrib/mw-to-git/Git/Mediawiki.pm            |   101 +
 contrib/mw-to-git/Makefile                    |    58 +
 contrib/mw-to-git/bin-wrapper/git             |    14 +
 contrib/mw-to-git/git-mw.perl                 |   368 +
 contrib/mw-to-git/git-remote-mediawiki.perl   |  1390 +
 contrib/mw-to-git/git-remote-mediawiki.txt    |     7 +
 contrib/mw-to-git/t/.gitignore                |     4 +
 contrib/mw-to-git/t/Makefile                  |    31 +
 contrib/mw-to-git/t/README                    |   124 +
 contrib/mw-to-git/t/install-wiki.sh           |    55 +
 contrib/mw-to-git/t/push-pull-tests.sh        |   144 +
 contrib/mw-to-git/t/t9360-mw-to-git-clone.sh  |   257 +
 .../mw-to-git/t/t9361-mw-to-git-push-pull.sh  |    24 +
 contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh   |   347 +
 .../t/t9363-mw-to-git-export-import.sh        |   218 +
 contrib/mw-to-git/t/t9364-pull-by-rev.sh      |    17 +
 .../mw-to-git/t/t9365-continuing-queries.sh   |    23 +
 contrib/mw-to-git/t/test-gitmw-lib.sh         |   432 +
 contrib/mw-to-git/t/test-gitmw.pl             |   223 +
 contrib/mw-to-git/t/test.config               |    40 +
 contrib/persistent-https/LICENSE              |   202 +
 contrib/persistent-https/Makefile             |    40 +
 contrib/persistent-https/README               |    72 +
 contrib/persistent-https/client.go            |   189 +
 contrib/persistent-https/main.go              |    82 +
 contrib/persistent-https/proxy.go             |   190 +
 contrib/persistent-https/socket.go            |    97 +
 contrib/remote-helpers/README                 |    15 +
 contrib/remote-helpers/git-remote-bzr         |    11 +
 contrib/remote-helpers/git-remote-hg          |    11 +
 contrib/remotes2config.sh                     |    33 +
 contrib/rerere-train.sh                       |   102 +
 contrib/stats/git-common-hash                 |    26 +
 contrib/stats/mailmap.pl                      |    70 +
 contrib/stats/packinfo.pl                     |   212 +
 contrib/subtree/.gitignore                    |     9 +
 contrib/subtree/COPYING                       |   339 +
 contrib/subtree/INSTALL                       |    28 +
 contrib/subtree/Makefile                      |   110 +
 contrib/subtree/README                        |     8 +
 contrib/subtree/git-subtree.sh                |  1132 +
 contrib/subtree/git-subtree.txt               |   353 +
 contrib/subtree/meson.build                   |    71 +
 contrib/subtree/t/Makefile                    |    85 +
 contrib/subtree/t/t7900-subtree.sh            |  1566 +
 contrib/subtree/todo                          |    48 +
 contrib/thunderbird-patch-inline/README       |    20 +
 contrib/thunderbird-patch-inline/appp.sh      |    55 +
 contrib/update-unicode/.gitignore             |     3 +
 contrib/update-unicode/README                 |    20 +
 contrib/update-unicode/update_unicode.sh      |    33 +
 contrib/vscode/.gitattributes                 |     1 +
 contrib/vscode/README.md                      |    18 +
 contrib/vscode/init.sh                        |   377 +
 contrib/workdir/.gitattributes                |     1 +
 contrib/workdir/git-new-workdir               |   105 +
 convert.c                                     |  2060 ++
 convert.h                                     |   240 +
 copy.c                                        |    72 +
 copy.h                                        |    10 +
 credential.c                                  |   710 +
 credential.h                                  |   311 +
 csum-file.c                                   |   253 +
 csum-file.h                                   |    96 +
 ctype.c                                       |    30 +
 daemon.c                                      |  1466 +
 date.c                                        |  1420 +
 date.h                                        |    73 +
 decorate.c                                    |   101 +
 decorate.h                                    |    71 +
 delta-islands.c                               |   559 +
 delta-islands.h                               |    19 +
 delta.h                                       |   104 +
 detect-compiler                               |    58 +
 diagnose.c                                    |   282 +
 diagnose.h                                    |    21 +
 diff-delta.c                                  |   498 +
 diff-lib.c                                    |   729 +
 diff-merges.c                                 |   192 +
 diff-merges.h                                 |    28 +
 diff-no-index.c                               |   374 +
 diff.c                                        |  7391 ++++
 diff.h                                        |   710 +
 diffcore-break.c                              |   313 +
 diffcore-delta.c                              |   236 +
 diffcore-order.c                              |   129 +
 diffcore-pickaxe.c                            |   292 +
 diffcore-rename.c                             |  1723 +
 diffcore-rotate.c                             |    47 +
 diffcore.h                                    |   236 +
 dir-iterator.c                                |   307 +
 dir-iterator.h                                |   117 +
 dir.c                                         |  4138 +++
 dir.h                                         |   677 +
 editor.c                                      |   167 +
 editor.h                                      |    35 +
 entry.c                                       |   613 +
 entry.h                                       |    71 +
 environment.c                                 |   254 +
 environment.h                                 |   228 +
 ewah/bitmap.c                                 |   311 +
 ewah/ewah_bitmap.c                            |   475 +
 ewah/ewah_io.c                                |   137 +
 ewah/ewah_rlw.c                               |   109 +
 ewah/ewok.h                                   |   202 +
 ewah/ewok_rlw.h                               |   114 +
 exec-cmd.c                                    |   396 +
 exec-cmd.h                                    |    16 +
 fetch-negotiator.c                            |    30 +
 fetch-negotiator.h                            |    67 +
 fetch-pack.c                                  |  2271 ++
 fetch-pack.h                                  |   120 +
 fmt-merge-msg.c                               |   723 +
 fmt-merge-msg.h                               |    22 +
 fsck.c                                        |  1391 +
 fsck.h                                        |   291 +
 fsmonitor--daemon.h                           |   171 +
 fsmonitor-ipc.c                               |   176 +
 fsmonitor-ipc.h                               |    50 +
 fsmonitor-ll.h                                |    52 +
 fsmonitor-path-utils.h                        |    60 +
 fsmonitor-settings.c                          |   290 +
 fsmonitor-settings.h                          |    54 +
 fsmonitor.c                                   |   822 +
 fsmonitor.h                                   |    71 +
 generate-cmdlist.sh                           |   120 +
 generate-configlist.sh                        |    31 +
 generate-hooklist.sh                          |    33 +
 generate-perl.sh                              |    37 +
 generate-python.sh                            |    20 +
 generate-script.sh                            |    34 +
 gettext.c                                     |   159 +
 gettext.h                                     |    69 +
 git-archimport.perl                           |  1134 +
 git-compat-util.h                             |  1598 +
 git-curl-compat.h                             |    48 +
 git-cvsexportcommit.perl                      |   467 +
 git-cvsimport.perl                            |  1183 +
 git-cvsserver.perl                            |  5128 +++
 git-difftool--helper.sh                       |   125 +
 git-filter-branch.sh                          |   664 +
 git-gui/.gitattributes                        |     6 +
 git-gui/.gitignore                            |     8 +
 git-gui/GIT-VERSION-GEN                       |    80 +
 git-gui/Makefile                              |   334 +
 git-gui/README.md                             |   174 +
 git-gui/git-gui--askpass                      |    84 +
 git-gui/git-gui.sh                            |  4147 +++
 git-gui/lib/about.tcl                         |    70 +
 git-gui/lib/blame.tcl                         |  1374 +
 git-gui/lib/branch.tcl                        |    40 +
 git-gui/lib/branch_checkout.tcl               |    93 +
 git-gui/lib/branch_create.tcl                 |   224 +
 git-gui/lib/branch_delete.tcl                 |   147 +
 git-gui/lib/branch_rename.tcl                 |   134 +
 git-gui/lib/browser.tcl                       |   322 +
 git-gui/lib/checkout_op.tcl                   |   646 +
 git-gui/lib/choose_font.tcl                   |   171 +
 git-gui/lib/choose_repository.tcl             |  1124 +
 git-gui/lib/choose_rev.tcl                    |   634 +
 git-gui/lib/chord.tcl                         |   158 +
 git-gui/lib/class.tcl                         |   194 +
 git-gui/lib/commit.tcl                        |   557 +
 git-gui/lib/console.tcl                       |   225 +
 git-gui/lib/database.tcl                      |   115 +
 git-gui/lib/date.tcl                          |    53 +
 git-gui/lib/diff.tcl                          |   891 +
 git-gui/lib/encoding.tcl                      |   466 +
 git-gui/lib/error.tcl                         |   119 +
 git-gui/lib/git-gui.ico                       |   Bin 0 -> 3638 bytes
 git-gui/lib/index.tcl                         |   753 +
 git-gui/lib/line.tcl                          |    81 +
 git-gui/lib/logo.tcl                          |    43 +
 git-gui/lib/merge.tcl                         |   285 +
 git-gui/lib/mergetool.tcl                     |   417 +
 git-gui/lib/option.tcl                        |   349 +
 git-gui/lib/remote.tcl                        |   333 +
 git-gui/lib/remote_add.tcl                    |   190 +
 git-gui/lib/remote_branch_delete.tcl          |   359 +
 git-gui/lib/search.tcl                        |   300 +
 git-gui/lib/shortcut.tcl                      |   140 +
 git-gui/lib/spellcheck.tcl                    |   415 +
 git-gui/lib/sshkey.tcl                        |   131 +
 git-gui/lib/status_bar.tcl                    |   312 +
 git-gui/lib/themed.tcl                        |   410 +
 git-gui/lib/tools.tcl                         |   168 +
 git-gui/lib/tools_dlg.tcl                     |   414 +
 git-gui/lib/transport.tcl                     |   232 +
 git-gui/lib/win32.tcl                         |    26 +
 git-gui/lib/win32_shortcut.js                 |    34 +
 git-gui/macosx/AppMain.tcl                    |    29 +
 git-gui/macosx/Info.plist                     |    30 +
 git-gui/macosx/git-gui.icns                   |   Bin 0 -> 28866 bytes
 git-gui/po/.gitignore                         |     2 +
 git-gui/po/README                             |   251 +
 git-gui/po/bg.po                              |  2866 ++
 git-gui/po/de.po                              |  2874 ++
 git-gui/po/el.po                              |  2005 ++
 git-gui/po/fr.po                              |  2604 ++
 git-gui/po/git-gui.pot                        |  2666 ++
 git-gui/po/glossary/Makefile                  |     9 +
 git-gui/po/glossary/bg.po                     |   287 +
 git-gui/po/glossary/de.po                     |   430 +
 git-gui/po/glossary/el.po                     |   171 +
 git-gui/po/glossary/fr.po                     |   166 +
 git-gui/po/glossary/git-gui-glossary.pot      |   398 +
 git-gui/po/glossary/git-gui-glossary.txt      |    96 +
 git-gui/po/glossary/it.po                     |   184 +
 git-gui/po/glossary/pt_br.po                  |   169 +
 git-gui/po/glossary/pt_pt.po                  |   293 +
 git-gui/po/glossary/txt-to-pot.sh             |    48 +
 git-gui/po/glossary/zh_cn.po                  |   170 +
 git-gui/po/hu.po                              |  2602 ++
 git-gui/po/it.po                              |  2591 ++
 git-gui/po/ja.po                              |  2685 ++
 git-gui/po/nb.po                              |  2474 ++
 git-gui/po/po2msg.sh                          |   152 +
 git-gui/po/pt_br.po                           |  2568 ++
 git-gui/po/pt_pt.po                           |  2716 ++
 git-gui/po/ru.po                              |  2651 ++
 git-gui/po/sv.po                              |  2809 ++
 git-gui/po/vi.po                              |  2690 ++
 git-gui/po/zh_cn.po                           |  1967 +
 git-gui/windows/git-gui.sh                    |    25 +
 git-instaweb.sh                               |   786 +
 git-merge-octopus.sh                          |   112 +
 git-merge-one-file.sh                         |   167 +
 git-merge-resolve.sh                          |    64 +
 git-mergetool--lib.sh                         |   549 +
 git-mergetool.sh                              |   579 +
 git-p4.py                                     |  4628 +++
 git-quiltimport.sh                            |   155 +
 git-request-pull.sh                           |   172 +
 git-send-email.perl                           |  2281 ++
 git-sh-i18n.sh                                |    79 +
 git-sh-setup.sh                               |   358 +
 git-submodule.sh                              |   671 +
 git-svn.perl                                  |  2250 ++
 git-web--browse.sh                            |   196 +
 git-zlib.c                                    |   274 +
 git-zlib.h                                    |    28 +
 git.c                                         |   973 +
 git.rc.in                                     |    24 +
 gitk-git/.gitignore                           |     2 +
 gitk-git/Makefile                             |    80 +
 gitk-git/gitk                                 | 12774 +++++++
 gitk-git/po/.gitignore                        |     1 +
 gitk-git/po/bg.po                             |  1447 +
 gitk-git/po/ca.po                             |  1369 +
 gitk-git/po/de.po                             |  1387 +
 gitk-git/po/es.po                             |  1405 +
 gitk-git/po/fr.po                             |  1400 +
 gitk-git/po/hu.po                             |  1419 +
 gitk-git/po/it.po                             |  1387 +
 gitk-git/po/ja.po                             |  1379 +
 gitk-git/po/po2msg.sh                         |   133 +
 gitk-git/po/pt_br.po                          |  1390 +
 gitk-git/po/pt_pt.po                          |  1376 +
 gitk-git/po/ru.po                             |  1371 +
 gitk-git/po/sv.po                             |  1433 +
 gitk-git/po/vi.po                             |  1379 +
 gitk-git/po/zh_cn.po                          |  1367 +
 gitweb/GITWEB-BUILD-OPTIONS.in                |    24 +
 gitweb/INSTALL                                |   328 +
 gitweb/Makefile                               |   146 +
 gitweb/README                                 |    70 +
 gitweb/generate-gitweb-cgi.sh                 |    47 +
 gitweb/generate-gitweb-js.sh                  |    12 +
 gitweb/gitweb.perl                            |  8490 +++++
 gitweb/meson.build                            |    89 +
 gitweb/static/git-favicon.png                 |   Bin 0 -> 115 bytes
 gitweb/static/git-logo.png                    |   Bin 0 -> 207 bytes
 gitweb/static/gitweb.css                      |   686 +
 gitweb/static/js/README                       |    20 +
 gitweb/static/js/adjust-timezone.js           |   330 +
 gitweb/static/js/blame_incremental.js         |   692 +
 gitweb/static/js/javascript-detection.js      |    43 +
 gitweb/static/js/lib/common-lib.js            |   224 +
 gitweb/static/js/lib/cookies.js               |   114 +
 gitweb/static/js/lib/datetime.js              |   176 +
 gpg-interface.c                               |  1115 +
 gpg-interface.h                               |    95 +
 graph.c                                       |  1555 +
 graph.h                                       |   265 +
 grep.c                                        |  2018 ++
 grep.h                                        |   266 +
 hash-lookup.c                                 |   134 +
 hash-lookup.h                                 |    32 +
 hash.h                                        |   444 +
 hashmap.c                                     |   351 +
 hashmap.h                                     |   577 +
 help.c                                        |   859 +
 help.h                                        |    92 +
 hex-ll.c                                      |    49 +
 hex-ll.h                                      |    27 +
 hex.c                                         |   124 +
 hex.h                                         |    70 +
 hook.c                                        |   196 +
 hook.h                                        |    94 +
 http-backend.c                                |   822 +
 http-fetch.c                                  |   182 +
 http-push.c                                   |  2002 ++
 http-walker.c                                 |   632 +
 http.c                                        |  2810 ++
 http.h                                        |   255 +
 ident.c                                       |   732 +
 ident.h                                       |    69 +
 imap-send.c                                   |  1593 +
 iterator.h                                    |    81 +
 json-writer.c                                 |   411 +
 json-writer.h                                 |   110 +
 khash.h                                       |   338 +
 kwset.c                                       |   813 +
 kwset.h                                       |    67 +
 levenshtein.c                                 |    86 +
 levenshtein.h                                 |     8 +
 line-log.c                                    |  1349 +
 line-log.h                                    |    63 +
 line-range.c                                  |   297 +
 line-range.h                                  |    41 +
 linear-assignment.c                           |   207 +
 linear-assignment.h                           |    22 +
 list-objects-filter-options.c                 |   413 +
 list-objects-filter-options.h                 |   165 +
 list-objects-filter.c                         |   825 +
 list-objects-filter.h                         |    97 +
 list-objects.c                                |   446 +
 list-objects.h                                |    36 +
 list.h                                        |   207 +
 lockfile.c                                    |   218 +
 lockfile.h                                    |   331 +
 log-tree.c                                    |  1204 +
 log-tree.h                                    |    42 +
 loose.c                                       |   260 +
 loose.h                                       |    24 +
 ls-refs.c                                     |   213 +
 ls-refs.h                                     |     9 +
 mailinfo.c                                    |  1316 +
 mailinfo.h                                    |    58 +
 mailmap.c                                     |   327 +
 mailmap.h                                     |    22 +
 match-trees.c                                 |   379 +
 match-trees.h                                 |    10 +
 mem-pool.c                                    |   220 +
 mem-pool.h                                    |    69 +
 merge-blobs.c                                 |   106 +
 merge-blobs.h                                 |    11 +
 merge-ll.c                                    |   470 +
 merge-ll.h                                    |   114 +
 merge-ort-wrappers.c                          |    66 +
 merge-ort-wrappers.h                          |    25 +
 merge-ort.c                                   |  5287 +++
 merge-ort.h                                   |   117 +
 merge-recursive.c                             |  4080 +++
 merge-recursive.h                             |   132 +
 merge.c                                       |   113 +
 merge.h                                       |    17 +
 mergesort.h                                   |   105 +
 mergetools/araxis                             |    26 +
 mergetools/bc                                 |    37 +
 mergetools/codecompare                        |    31 +
 mergetools/deltawalker                        |    33 +
 mergetools/diffmerge                          |    26 +
 mergetools/diffuse                            |    23 +
 mergetools/ecmerge                            |    22 +
 mergetools/emerge                             |    34 +
 mergetools/examdiff                           |    24 +
 mergetools/guiffy                             |    26 +
 mergetools/gvimdiff                           |     1 +
 mergetools/kdiff3                             |    44 +
 mergetools/kompare                            |    19 +
 mergetools/meld                               |    97 +
 mergetools/nvimdiff                           |     1 +
 mergetools/opendiff                           |    22 +
 mergetools/p4merge                            |    44 +
 mergetools/smerge                             |    20 +
 mergetools/tkdiff                             |    24 +
 mergetools/tortoisemerge                      |    40 +
 mergetools/vimdiff                            |   645 +
 mergetools/vscode                             |    19 +
 mergetools/winmerge                           |    23 +
 mergetools/xxdiff                             |    38 +
 meson.build                                   |  1955 +
 meson_options.txt                             |    99 +
 midx-write.c                                  |  1788 +
 midx.c                                        |  1019 +
 midx.h                                        |   146 +
 name-hash.c                                   |   758 +
 name-hash.h                                   |    21 +
 negotiator/default.c                          |   200 +
 negotiator/default.h                          |     8 +
 negotiator/noop.c                             |    45 +
 negotiator/noop.h                             |     8 +
 negotiator/skipping.c                         |   271 +
 negotiator/skipping.h                         |     8 +
 notes-cache.c                                 |   103 +
 notes-cache.h                                 |    22 +
 notes-merge.c                                 |   766 +
 notes-merge.h                                 |    87 +
 notes-utils.c                                 |   200 +
 notes-utils.h                                 |    55 +
 notes.c                                       |  1379 +
 notes.h                                       |   347 +
 object-file-convert.c                         |   280 +
 object-file-convert.h                         |    24 +
 object-file.c                                 |  3148 ++
 object-file.h                                 |   137 +
 object-name.c                                 |  2186 ++
 object-name.h                                 |   133 +
 object-store-ll.h                             |   556 +
 object-store.h                                |    11 +
 object.c                                      |   687 +
 object.h                                      |   347 +
 oid-array.c                                   |   103 +
 oid-array.h                                   |   137 +
 oidmap.c                                      |    62 +
 oidmap.h                                      |    93 +
 oidset.c                                      |    94 +
 oidset.h                                      |   124 +
 oidtree.c                                     |   109 +
 oidtree.h                                     |    22 +
 oss-fuzz/.gitignore                           |     8 +
 oss-fuzz/dummy-cmd-main.c                     |    14 +
 oss-fuzz/fuzz-commit-graph.c                  |    32 +
 oss-fuzz/fuzz-config.c                        |    33 +
 oss-fuzz/fuzz-credential-from-url-gently.c    |    32 +
 oss-fuzz/fuzz-date.c                          |    49 +
 oss-fuzz/fuzz-pack-headers.c                  |    15 +
 oss-fuzz/fuzz-pack-idx.c                      |    14 +
 oss-fuzz/fuzz-parse-attr-line.c               |    41 +
 oss-fuzz/fuzz-url-decode-mem.c                |    43 +
 pack-bitmap-write.c                           |  1083 +
 pack-bitmap.c                                 |  3070 ++
 pack-bitmap.h                                 |   168 +
 pack-check.c                                  |   203 +
 pack-mtimes.c                                 |   133 +
 pack-mtimes.h                                 |    24 +
 pack-objects.c                                |   242 +
 pack-objects.h                                |   309 +
 pack-revindex.c                               |   583 +
 pack-revindex.h                               |   148 +
 pack-write.c                                  |   601 +
 pack.h                                        |   132 +
 packfile.c                                    |  2337 ++
 packfile.h                                    |   225 +
 pager.c                                       |   307 +
 pager.h                                       |    19 +
 parallel-checkout.c                           |   677 +
 parallel-checkout.h                           |   113 +
 parse-options-cb.c                            |   318 +
 parse-options.c                               |  1385 +
 parse-options.h                               |   610 +
 parse.c                                       |   211 +
 parse.h                                       |    21 +
 patch-delta.c                                 |    94 +
 patch-ids.c                                   |   136 +
 patch-ids.h                                   |    47 +
 path-walk.c                                   |   591 +
 path-walk.h                                   |    69 +
 path.c                                        |  1486 +
 path.h                                        |   330 +
 pathspec.c                                    |   890 +
 pathspec.h                                    |   199 +
 perl/.gitignore                               |     1 +
 perl/FromCPAN/.gitattributes                  |     1 +
 perl/FromCPAN/Error.pm                        |  1040 +
 perl/FromCPAN/Mail/Address.pm                 |   280 +
 perl/FromCPAN/Mail/meson.build                |     8 +
 perl/FromCPAN/meson.build                     |    10 +
 perl/Git.pm                                   |  1767 +
 perl/Git/I18N.pm                              |   125 +
 perl/Git/IndexInfo.pm                         |    35 +
 perl/Git/LoadCPAN.pm                          |   104 +
 perl/Git/LoadCPAN/Error.pm                    |    10 +
 perl/Git/LoadCPAN/Mail/Address.pm             |    10 +
 perl/Git/LoadCPAN/Mail/meson.build            |     8 +
 perl/Git/LoadCPAN/meson.build                 |    10 +
 perl/Git/Packet.pm                            |   173 +
 perl/Git/SVN.pm                               |  2573 ++
 perl/Git/SVN/Editor.pm                        |   605 +
 perl/Git/SVN/Fetcher.pm                       |   622 +
 perl/Git/SVN/GlobSpec.pm                      |    65 +
 perl/Git/SVN/Log.pm                           |   400 +
 perl/Git/SVN/Memoize/YAML.pm                  |    93 +
 perl/Git/SVN/Memoize/meson.build              |     8 +
 perl/Git/SVN/Migration.pm                     |   265 +
 perl/Git/SVN/Prompt.pm                        |   184 +
 perl/Git/SVN/Ra.pm                            |   708 +
 perl/Git/SVN/Utils.pm                         |   232 +
 perl/Git/SVN/meson.build                      |    21 +
 perl/Git/meson.build                          |    19 +
 .../header_templates/fixed_prefix.template.pl |     1 +
 .../runtime_prefix.template.pl                |    42 +
 perl/meson.build                              |    13 +
 pkt-line.c                                    |   711 +
 pkt-line.h                                    |   254 +
 po/.gitignore                                 |     3 +
 po/README.md                                  |   460 +
 po/TEAMS                                      |    92 +
 po/bg.po                                      | 24566 +++++++++++++
 po/ca.po                                      | 29760 ++++++++++++++++
 po/de.po                                      | 24196 +++++++++++++
 po/el.po                                      | 21468 +++++++++++
 po/es.po                                      | 22396 ++++++++++++
 po/fr.po                                      | 24132 +++++++++++++
 po/id.po                                      | 29336 +++++++++++++++
 po/is.po                                      |   103 +
 po/it.po                                      | 26670 ++++++++++++++
 po/ko.po                                      | 18000 ++++++++++
 po/meson.build                                |    27 +
 po/pl.po                                      | 27504 ++++++++++++++
 po/pt_PT.po                                   | 26666 ++++++++++++++
 po/ru.po                                      | 21696 +++++++++++
 po/sv.po                                      | 23375 ++++++++++++
 po/tr.po                                      | 23521 ++++++++++++
 po/uk.po                                      | 23789 ++++++++++++
 po/vi.po                                      | 23538 ++++++++++++
 po/zh_CN.po                                   | 28890 +++++++++++++++
 po/zh_TW.po                                   | 28899 +++++++++++++++
 preload-index.c                               |   186 +
 preload-index.h                               |    15 +
 pretty.c                                      |  2372 ++
 pretty.h                                      |   173 +
 prio-queue.c                                  |    99 +
 prio-queue.h                                  |    60 +
 progress.c                                    |   383 +
 progress.h                                    |    32 +
 promisor-remote.c                             |   294 +
 promisor-remote.h                             |    35 +
 prompt.c                                      |    88 +
 prompt.h                                      |    11 +
 protocol-caps.c                               |   115 +
 protocol-caps.h                               |     8 +
 protocol.c                                    |    99 +
 protocol.h                                    |    55 +
 prune-packed.c                                |    49 +
 prune-packed.h                                |     9 +
 pseudo-merge.c                                |   786 +
 pseudo-merge.h                                |   218 +
 quote.c                                       |   586 +
 quote.h                                       |   105 +
 range-diff.c                                  |   630 +
 range-diff.h                                  |    37 +
 reachable.c                                   |   406 +
 reachable.h                                   |    19 +
 read-cache-ll.h                               |   489 +
 read-cache.c                                  |  3999 +++
 read-cache.h                                  |    45 +
 rebase-interactive.c                          |   250 +
 rebase-interactive.h                          |    22 +
 rebase.c                                      |    37 +
 rebase.h                                      |    14 +
 ref-filter.c                                  |  3662 ++
 ref-filter.h                                  |   214 +
 reflog-walk.c                                 |   383 +
 reflog-walk.h                                 |    27 +
 reflog.c                                      |   445 +
 reflog.h                                      |    43 +
 refs.c                                        |  3118 ++
 refs.h                                        |  1172 +
 refs/debug.c                                  |   452 +
 refs/files-backend.c                          |  3870 ++
 refs/iterator.c                               |   472 +
 refs/packed-backend.c                         |  1790 +
 refs/packed-backend.h                         |    46 +
 refs/ref-cache.c                              |   512 +
 refs/ref-cache.h                              |   223 +
 refs/refs-internal.h                          |   774 +
 refs/reftable-backend.c                       |  2680 ++
 refspec.c                                     |   278 +
 refspec.h                                     |    74 +
 reftable/LICENSE                              |    31 +
 reftable/basics.c                             |   286 +
 reftable/basics.h                             |   184 +
 reftable/block.c                              |   582 +
 reftable/block.h                              |   148 +
 reftable/blocksource.c                        |   139 +
 reftable/blocksource.h                        |    21 +
 reftable/constants.h                          |    22 +
 reftable/error.c                              |    46 +
 reftable/iter.c                               |   303 +
 reftable/iter.h                               |    89 +
 reftable/merged.c                             |   303 +
 reftable/merged.h                             |    34 +
 reftable/pq.c                                 |    73 +
 reftable/pq.h                                 |    40 +
 reftable/reader.c                             |   878 +
 reftable/reader.h                             |    67 +
 reftable/record.c                             |  1319 +
 reftable/record.h                             |   164 +
 reftable/reftable-basics.h                    |    31 +
 reftable/reftable-blocksource.h               |    52 +
 reftable/reftable-error.h                     |    69 +
 reftable/reftable-iterator.h                  |    60 +
 reftable/reftable-merged.h                    |    61 +
 reftable/reftable-reader.h                    |    72 +
 reftable/reftable-record.h                    |   110 +
 reftable/reftable-stack.h                     |   155 +
 reftable/reftable-writer.h                    |   185 +
 reftable/stack.c                              |  1809 +
 reftable/stack.h                              |    41 +
 reftable/system.c                             |   126 +
 reftable/system.h                             |   101 +
 reftable/tree.c                               |    74 +
 reftable/tree.h                               |    45 +
 reftable/writer.c                             |   854 +
 reftable/writer.h                             |    53 +
 remote-curl.c                                 |  1659 +
 remote.c                                      |  3005 ++
 remote.h                                      |   464 +
 replace-object.c                              |   115 +
 replace-object.h                              |    63 +
 repo-settings.c                               |   169 +
 repo-settings.h                               |    82 +
 repository.c                                  |   456 +
 repository.h                                  |   236 +
 rerere.c                                      |  1274 +
 rerere.h                                      |    44 +
 reset.c                                       |   189 +
 reset.h                                       |    60 +
 resolve-undo.c                                |   179 +
 resolve-undo.h                                |    25 +
 revision.c                                    |  4543 +++
 revision.h                                    |   565 +
 run-command.c                                 |  1983 +
 run-command.h                                 |   581 +
 sane-ctype.h                                  |    66 +
 scalar.c                                      |  1002 +
 send-pack.c                                   |   791 +
 send-pack.h                                   |    43 +
 sequencer.c                                   |  6824 ++++
 sequencer.h                                   |   274 +
 serve.c                                       |   346 +
 serve.h                                       |     9 +
 server-info.c                                 |   376 +
 server-info.h                                 |     9 +
 setup.c                                       |  2640 ++
 setup.h                                       |   234 +
 sh-i18n--envsubst.c                           |   427 +
 sha1/openssl.h                                |    51 +
 sha1collisiondetection                        |     1 +
 sha1dc/.gitattributes                         |     1 +
 sha1dc/LICENSE.txt                            |    30 +
 sha1dc/sha1.c                                 |  1911 +
 sha1dc/sha1.h                                 |   110 +
 sha1dc/ubc_check.c                            |   372 +
 sha1dc/ubc_check.h                            |    52 +
 sha1dc_git.c                                  |    40 +
 sha1dc_git.h                                  |    27 +
 sha256/block/sha256.c                         |   196 +
 sha256/block/sha256.h                         |    24 +
 sha256/gcrypt.h                               |    39 +
 sha256/nettle.h                               |    31 +
 sha256/openssl.h                              |    49 +
 shallow.c                                     |   858 +
 shallow.h                                     |    85 +
 shared.mak                                    |   129 +
 shell.c                                       |   231 +
 shortlog.h                                    |    42 +
 sideband.c                                    |   285 +
 sideband.h                                    |    33 +
 sigchain.c                                    |    61 +
 sigchain.h                                    |    57 +
 simple-ipc.h                                  |   243 +
 sparse-index.c                                |   749 +
 sparse-index.h                                |    49 +
 split-index.c                                 |   492 +
 split-index.h                                 |    39 +
 stable-qsort.c                                |    56 +
 statinfo.c                                    |   132 +
 statinfo.h                                    |    97 +
 strbuf.c                                      |  1088 +
 strbuf.h                                      |   696 +
 streaming.c                                   |   551 +
 streaming.h                                   |    21 +
 string-list.c                                 |   338 +
 string-list.h                                 |   284 +
 strmap.c                                      |   179 +
 strmap.h                                      |   268 +
 strvec.c                                      |   149 +
 strvec.h                                      |   116 +
 sub-process.c                                 |   217 +
 sub-process.h                                 |    97 +
 submodule-config.c                            |  1052 +
 submodule-config.h                            |   142 +
 submodule.c                                   |  2634 ++
 submodule.h                                   |   183 +
 subprojects/.gitignore                        |     1 +
 subprojects/curl.wrap                         |    13 +
 subprojects/expat.wrap                        |    13 +
 subprojects/openssl.wrap                      |    15 +
 subprojects/pcre2.wrap                        |    16 +
 subprojects/zlib.wrap                         |    13 +
 symlinks.c                                    |   352 +
 symlinks.h                                    |    28 +
 t/.gitattributes                              |    25 +
 t/.gitignore                                  |     6 +
 t/Git-SVN/00compile.t                         |    14 +
 t/Git-SVN/Utils/add_path_to_url.t             |    27 +
 t/Git-SVN/Utils/can_compress.t                |    11 +
 t/Git-SVN/Utils/canonicalize_url.t            |    26 +
 t/Git-SVN/Utils/collapse_dotdot.t             |    23 +
 t/Git-SVN/Utils/fatal.t                       |    34 +
 t/Git-SVN/Utils/join_paths.t                  |    32 +
 t/Makefile                                    |   179 +
 t/README                                      |  1287 +
 t/aggregate-results.sh                        |    63 +
 t/annotate-tests.sh                           |   677 +
 t/chainlint-cat.pl                            |    29 +
 t/chainlint.pl                                |   883 +
 t/chainlint/arithmetic-expansion.expect       |     9 +
 t/chainlint/arithmetic-expansion.test         |    13 +
 t/chainlint/bash-array.expect                 |    10 +
 t/chainlint/bash-array.test                   |    14 +
 t/chainlint/blank-line-before-esac.expect     |    18 +
 t/chainlint/blank-line-before-esac.test       |    21 +
 t/chainlint/blank-line.expect                 |     8 +
 t/chainlint/blank-line.test                   |    12 +
 t/chainlint/block-comment.expect              |     8 +
 t/chainlint/block-comment.test                |    10 +
 t/chainlint/block.expect                      |    23 +
 t/chainlint/block.test                        |    29 +
 t/chainlint/broken-chain.expect               |     6 +
 t/chainlint/broken-chain.test                 |    10 +
 t/chainlint/case-comment.expect               |    11 +
 t/chainlint/case-comment.test                 |    13 +
 t/chainlint/case.expect                       |    19 +
 t/chainlint/case.test                         |    25 +
 t/chainlint/chain-break-background.expect     |     9 +
 t/chainlint/chain-break-background.test       |    12 +
 t/chainlint/chain-break-continue.expect       |    12 +
 t/chainlint/chain-break-continue.test         |    15 +
 t/chainlint/chain-break-false.expect          |     9 +
 t/chainlint/chain-break-false.test            |    12 +
 t/chainlint/chain-break-return-exit.expect    |    19 +
 t/chainlint/chain-break-return-exit.test      |    25 +
 t/chainlint/chain-break-status.expect         |     9 +
 t/chainlint/chain-break-status.test           |    13 +
 t/chainlint/chained-block.expect              |     9 +
 t/chainlint/chained-block.test                |    13 +
 t/chainlint/chained-subshell.expect           |    10 +
 t/chainlint/chained-subshell.test             |    15 +
 .../close-nested-and-parent-together.expect   |     3 +
 .../close-nested-and-parent-together.test     |     5 +
 t/chainlint/close-subshell.expect             |    26 +
 t/chainlint/close-subshell.test               |    29 +
 .../command-substitution-subsubshell.expect   |     2 +
 .../command-substitution-subsubshell.test     |     5 +
 t/chainlint/command-substitution.expect       |     9 +
 t/chainlint/command-substitution.test         |    13 +
 t/chainlint/comment.expect                    |     8 +
 t/chainlint/comment.test                      |    13 +
 t/chainlint/complex-if-in-cuddled-loop.expect |     9 +
 t/chainlint/complex-if-in-cuddled-loop.test   |    13 +
 t/chainlint/cuddled-if-then-else.expect       |     6 +
 t/chainlint/cuddled-if-then-else.test         |     9 +
 t/chainlint/cuddled-loop.expect               |     4 +
 t/chainlint/cuddled-loop.test                 |     9 +
 t/chainlint/cuddled.expect                    |    17 +
 t/chainlint/cuddled.test                      |    24 +
 t/chainlint/double-here-doc.expect            |    12 +
 t/chainlint/double-here-doc.test              |    14 +
 t/chainlint/dqstring-line-splice.expect       |     5 +
 t/chainlint/dqstring-line-splice.test         |     9 +
 t/chainlint/dqstring-no-interpolate.expect    |    12 +
 t/chainlint/dqstring-no-interpolate.test      |    17 +
 t/chainlint/empty-here-doc.expect             |     4 +
 t/chainlint/empty-here-doc.test               |     7 +
 t/chainlint/exclamation.expect                |     4 +
 t/chainlint/exclamation.test                  |    10 +
 t/chainlint/exit-loop.expect                  |    24 +
 t/chainlint/exit-loop.test                    |    29 +
 t/chainlint/exit-subshell.expect              |     5 +
 t/chainlint/exit-subshell.test                |     8 +
 t/chainlint/for-loop-abbreviated.expect       |     5 +
 t/chainlint/for-loop-abbreviated.test         |     8 +
 t/chainlint/for-loop.expect                   |    14 +
 t/chainlint/for-loop.test                     |    21 +
 t/chainlint/function.expect                   |    11 +
 t/chainlint/function.test                     |    15 +
 t/chainlint/here-doc-body-indent.expect       |     2 +
 t/chainlint/here-doc-body-indent.test         |     4 +
 t/chainlint/here-doc-body-pathological.expect |     7 +
 t/chainlint/here-doc-body-pathological.test   |     9 +
 t/chainlint/here-doc-body.expect              |     7 +
 t/chainlint/here-doc-body.test                |     9 +
 t/chainlint/here-doc-close-subshell.expect    |     4 +
 t/chainlint/here-doc-close-subshell.test      |     7 +
 t/chainlint/here-doc-double.expect            |     2 +
 t/chainlint/here-doc-double.test              |    10 +
 t/chainlint/here-doc-indent-operator.expect   |    11 +
 t/chainlint/here-doc-indent-operator.test     |    15 +
 .../here-doc-multi-line-command-subst.expect  |     8 +
 .../here-doc-multi-line-command-subst.test    |    11 +
 t/chainlint/here-doc-multi-line-string.expect |     7 +
 t/chainlint/here-doc-multi-line-string.test   |    10 +
 t/chainlint/here-doc.expect                   |    25 +
 t/chainlint/here-doc.test                     |    32 +
 t/chainlint/if-condition-split.expect         |     7 +
 t/chainlint/if-condition-split.test           |    10 +
 t/chainlint/if-in-loop.expect                 |    12 +
 t/chainlint/if-in-loop.test                   |    17 +
 t/chainlint/if-then-else.expect               |    22 +
 t/chainlint/if-then-else.test                 |    31 +
 t/chainlint/incomplete-line.expect            |    10 +
 t/chainlint/incomplete-line.test              |    14 +
 t/chainlint/inline-comment.expect             |     8 +
 t/chainlint/inline-comment.test               |    14 +
 t/chainlint/loop-detect-failure.expect        |    15 +
 t/chainlint/loop-detect-failure.test          |    19 +
 t/chainlint/loop-detect-status.expect         |    18 +
 t/chainlint/loop-detect-status.test           |    21 +
 t/chainlint/loop-in-if.expect                 |    12 +
 t/chainlint/loop-in-if.test                   |    17 +
 t/chainlint/loop-upstream-pipe.expect         |    10 +
 t/chainlint/loop-upstream-pipe.test           |    13 +
 ...ti-line-nested-command-substitution.expect |    18 +
 ...ulti-line-nested-command-substitution.test |    20 +
 t/chainlint/multi-line-string.expect          |    14 +
 t/chainlint/multi-line-string.test            |    17 +
 t/chainlint/negated-one-liner.expect          |     5 +
 t/chainlint/negated-one-liner.test            |     9 +
 t/chainlint/nested-cuddled-subshell.expect    |    25 +
 t/chainlint/nested-cuddled-subshell.test      |    33 +
 t/chainlint/nested-here-doc.expect            |    30 +
 t/chainlint/nested-here-doc.test              |    35 +
 t/chainlint/nested-loop-detect-failure.expect |    31 +
 t/chainlint/nested-loop-detect-failure.test   |    37 +
 t/chainlint/nested-subshell-comment.expect    |    11 +
 t/chainlint/nested-subshell-comment.test      |    15 +
 t/chainlint/nested-subshell.expect            |    13 +
 t/chainlint/nested-subshell.test              |    15 +
 t/chainlint/not-heredoc.expect                |    14 +
 t/chainlint/not-heredoc.test                  |    18 +
 t/chainlint/one-liner-for-loop.expect         |     9 +
 t/chainlint/one-liner-for-loop.test           |    12 +
 t/chainlint/one-liner.expect                  |     9 +
 t/chainlint/one-liner.test                    |    14 +
 t/chainlint/p4-filespec.expect                |     4 +
 t/chainlint/p4-filespec.test                  |     7 +
 t/chainlint/pipe.expect                       |    10 +
 t/chainlint/pipe.test                         |    14 +
 t/chainlint/return-loop.expect                |     5 +
 t/chainlint/return-loop.test                  |     8 +
 t/chainlint/semicolon.expect                  |    19 +
 t/chainlint/semicolon.test                    |    27 +
 t/chainlint/sqstring-in-sqstring.expect       |     4 +
 t/chainlint/sqstring-in-sqstring.test         |     7 +
 t/chainlint/subshell-here-doc.expect          |    30 +
 t/chainlint/subshell-here-doc.test            |    37 +
 t/chainlint/subshell-one-liner.expect         |    19 +
 t/chainlint/subshell-one-liner.test           |    26 +
 t/chainlint/t7900-subtree.expect              |    22 +
 t/chainlint/t7900-subtree.test                |    24 +
 t/chainlint/token-pasting.expect              |    27 +
 t/chainlint/token-pasting.test                |    34 +
 t/chainlint/unclosed-here-doc-indent.expect   |     4 +
 t/chainlint/unclosed-here-doc-indent.test     |     6 +
 t/chainlint/unclosed-here-doc.expect          |     7 +
 t/chainlint/unclosed-here-doc.test            |     9 +
 t/chainlint/while-loop.expect                 |    14 +
 t/chainlint/while-loop.test                   |    21 +
 t/check-non-portable-shell.pl                 |    58 +
 t/helper/.gitignore                           |     2 +
 t/helper/meson.build                          |    92 +
 t/helper/test-advise.c                        |    24 +
 t/helper/test-bitmap.c                        |    55 +
 t/helper/test-bloom.c                         |   104 +
 t/helper/test-bundle-uri.c                    |   133 +
 t/helper/test-cache-tree.c                    |    71 +
 t/helper/test-chmtime.c                       |   163 +
 t/helper/test-config.c                        |   241 +
 t/helper/test-crontab.c                       |    35 +
 t/helper/test-csprng.c                        |    28 +
 t/helper/test-date.c                          |   135 +
 t/helper/test-delete-gpgsig.c                 |    62 +
 t/helper/test-delta.c                         |    85 +
 t/helper/test-dir-iterator.c                  |    63 +
 t/helper/test-drop-caches.c                   |   164 +
 t/helper/test-dump-cache-tree.c               |    79 +
 t/helper/test-dump-fsmonitor.c                |    25 +
 t/helper/test-dump-split-index.c              |    43 +
 t/helper/test-dump-untracked-cache.c          |    74 +
 t/helper/test-env-helper.c                    |   100 +
 t/helper/test-example-tap.c                   |   131 +
 t/helper/test-fake-ssh.c                      |    32 +
 t/helper/test-find-pack.c                     |    52 +
 t/helper/test-fsmonitor-client.c              |   226 +
 t/helper/test-genrandom.c                     |    34 +
 t/helper/test-genzeros.c                      |    37 +
 t/helper/test-getcwd.c                        |    26 +
 t/helper/test-hash-speed.c                    |    60 +
 t/helper/test-hash.c                          |    59 +
 t/helper/test-hashmap.c                       |   179 +
 t/helper/test-hexdump.c                       |    30 +
 t/helper/test-json-writer.c                   |   594 +
 t/helper/test-lazy-init-name-hash.c           |   268 +
 t/helper/test-match-trees.c                   |    33 +
 t/helper/test-mergesort.c                     |   408 +
 t/helper/test-mktemp.c                        |    15 +
 t/helper/test-online-cpus.c                   |     9 +
 t/helper/test-pack-mtimes.c                   |    59 +
 t/helper/test-parse-options.c                 |   342 +
 t/helper/test-parse-pathspec-file.c           |    33 +
 t/helper/test-partial-clone.c                 |    46 +
 t/helper/test-path-utils.c                    |   510 +
 t/helper/test-path-walk.c                     |   112 +
 t/helper/test-pcre2-config.c                  |    11 +
 t/helper/test-pkt-line.c                      |   188 +
 t/helper/test-proc-receive.c                  |   207 +
 t/helper/test-progress.c                      |   101 +
 t/helper/test-reach.c                         |   191 +
 t/helper/test-read-cache.c                    |    41 +
 t/helper/test-read-graph.c                    |   102 +
 t/helper/test-read-midx.c                     |   158 +
 t/helper/test-ref-store.c                     |   352 +
 t/helper/test-reftable.c                      |   200 +
 t/helper/test-regex.c                         |   117 +
 t/helper/test-repository.c                    |   102 +
 t/helper/test-revision-walking.c              |    74 +
 t/helper/test-rot13-filter.c                  |   383 +
 t/helper/test-run-command.c                   |   480 +
 t/helper/test-scrap-cache-tree.c              |    24 +
 t/helper/test-serve-v2.c                      |    39 +
 t/helper/test-sha1.c                          |    15 +
 t/helper/test-sha1.sh                         |    83 +
 t/helper/test-sha256.c                        |     7 +
 t/helper/test-sigchain.c                      |    23 +
 t/helper/test-simple-ipc.c                    |   687 +
 t/helper/test-string-list.c                   |   131 +
 t/helper/test-submodule-config.c              |    71 +
 t/helper/test-submodule-nested-repo-config.c  |    34 +
 t/helper/test-submodule.c                     |   244 +
 t/helper/test-subprocess.c                    |    20 +
 t/helper/test-tool-utils.h                    |     9 +
 t/helper/test-tool.c                          |   135 +
 t/helper/test-tool.h                          |    87 +
 t/helper/test-trace2.c                        |   557 +
 t/helper/test-truncate.c                      |    25 +
 t/helper/test-userdiff.c                      |    50 +
 t/helper/test-wildmatch.c                     |    24 +
 t/helper/test-windows-named-pipe.c            |    72 +
 t/helper/test-write-cache.c                   |    25 +
 t/helper/test-xml-encode.c                    |    80 +
 t/interop/.gitignore                          |     4 +
 t/interop/Makefile                            |    19 +
 t/interop/README                              |    92 +
 t/interop/i0000-basic.sh                      |    27 +
 t/interop/i5500-git-daemon.sh                 |    41 +
 t/interop/i5700-protocol-transition.sh        |    68 +
 t/interop/interop-lib.sh                      |    94 +
 t/lib-bash.sh                                 |    19 +
 t/lib-bitmap.sh                               |   449 +
 t/lib-bundle-uri-protocol.sh                  |   216 +
 t/lib-bundle.sh                               |    42 +
 t/lib-chunk.sh                                |    18 +
 t/lib-chunk/corrupt-chunk-file.pl             |    90 +
 t/lib-commit-graph.sh                         |    74 +
 t/lib-credential.sh                           |   685 +
 t/lib-cvs.sh                                  |    78 +
 t/lib-diff-alternative.sh                     |   227 +
 t/lib-diff-data.sh                            |    22 +
 t/lib-diff.sh                                 |    41 +
 t/lib-encoding.sh                             |    25 +
 t/lib-gettext.sh                              |    63 +
 t/lib-git-daemon.sh                           |   120 +
 t/lib-git-p4.sh                               |   225 +
 t/lib-git-svn.sh                              |   145 +
 t/lib-gitweb.sh                               |   128 +
 t/lib-gpg.sh                                  |   200 +
 t/lib-gpg/gpgsm-gen-key.in                    |     8 +
 t/lib-gpg/gpgsm_cert.p12                      |   Bin 0 -> 2652 bytes
 t/lib-gpg/keyring.gpg                         |   192 +
 t/lib-gpg/ownertrust                          |     4 +
 t/lib-httpd.sh                                |   370 +
 t/lib-httpd/apache.conf                       |   292 +
 t/lib-httpd/apply-one-time-perl.sh            |    27 +
 t/lib-httpd/broken-smart-http.sh              |    10 +
 t/lib-httpd/error-no-report.sh                |     6 +
 t/lib-httpd/error-smart-http.sh               |     3 +
 t/lib-httpd/error.sh                          |    31 +
 .../incomplete-body-upload-pack-v2-http.sh    |     3 +
 .../incomplete-length-upload-pack-v2-http.sh  |     3 +
 t/lib-httpd/nph-custom-auth.sh                |    48 +
 t/lib-httpd/passwd                            |     1 +
 t/lib-httpd/proxy-passwd                      |     1 +
 t/lib-httpd/ssl.cnf                           |     8 +
 t/lib-log-graph.sh                            |    28 +
 t/lib-merge.sh                                |    13 +
 t/lib-midx.sh                                 |    36 +
 t/lib-pack.sh                                 |   140 +
 t/lib-pager.sh                                |    15 +
 t/lib-parallel-checkout.sh                    |    49 +
 t/lib-patch-mode.sh                           |    55 +
 t/lib-perl.sh                                 |    19 +
 t/lib-proto-disable.sh                        |   220 +
 t/lib-read-tree-m-3way.sh                     |   158 +
 t/lib-read-tree.sh                            |    41 +
 t/lib-rebase.sh                               |   231 +
 t/lib-submodule-update.sh                     |  1099 +
 t/lib-subtest.sh                              |    95 +
 t/lib-sudo.sh                                 |    15 +
 t/lib-t3100.sh                                |    10 +
 t/lib-t6000.sh                                |   136 +
 t/lib-terminal.sh                             |    36 +
 t/lib-unicode-nfc-nfd.sh                      |   162 +
 t/lib-unique-files.sh                         |    34 +
 t/meson.build                                 |  1151 +
 t/oid-info/README                             |    19 +
 t/oid-info/hash-info                          |    29 +
 t/oid-info/oid                                |    31 +
 t/perf/.gitignore                             |     4 +
 t/perf/Makefile                               |    21 +
 t/perf/README                                 |   210 +
 t/perf/aggregate.perl                         |   357 +
 t/perf/bisect_regression                      |    73 +
 t/perf/bisect_run_script                      |    53 +
 t/perf/config                                 |     2 +
 t/perf/lib-bitmap.sh                          |   100 +
 t/perf/lib-pack.sh                            |    25 +
 t/perf/min_time.perl                          |    21 +
 t/perf/p0000-perf-lib-sanity.sh               |    57 +
 t/perf/p0001-rev-list.sh                      |    48 +
 t/perf/p0002-read-cache.sh                    |    14 +
 t/perf/p0003-delta-base-cache.sh              |    31 +
 t/perf/p0004-lazy-init-name-hash.sh           |    56 +
 t/perf/p0005-status.sh                        |    49 +
 t/perf/p0006-read-tree-checkout.sh            |    75 +
 t/perf/p0007-write-cache.sh                   |    29 +
 t/perf/p0008-odb-fsync.sh                     |    82 +
 t/perf/p0071-sort.sh                          |    52 +
 t/perf/p0090-cache-tree.sh                    |    36 +
 t/perf/p0100-globbing.sh                      |    43 +
 t/perf/p1006-cat-file.sh                      |    12 +
 t/perf/p1400-update-ref.sh                    |    33 +
 t/perf/p1450-fsck.sh                          |    13 +
 t/perf/p1451-fsck-skip-list.sh                |    40 +
 t/perf/p1500-graph-walks.sh                   |    81 +
 t/perf/p2000-sparse-operations.sh             |   139 +
 t/perf/p3400-rebase.sh                        |    56 +
 t/perf/p3404-rebase-interactive.sh            |    36 +
 t/perf/p4000-diff-algorithms.sh               |    29 +
 t/perf/p4001-diff-no-index.sh                 |    22 +
 t/perf/p4002-diff-color-moved.sh              |    57 +
 t/perf/p4205-log-pretty-formats.sh            |    16 +
 t/perf/p4209-pickaxe.sh                       |    70 +
 t/perf/p4211-line-log.sh                      |    42 +
 t/perf/p4220-log-grep-engines.sh              |    54 +
 t/perf/p4221-log-grep-engines-fixed.sh        |    45 +
 t/perf/p5302-pack-index.sh                    |    50 +
 t/perf/p5303-many-packs.sh                    |   144 +
 t/perf/p5304-prune.sh                         |    35 +
 t/perf/p5310-pack-bitmaps.sh                  |    40 +
 t/perf/p5311-pack-bitmaps-fetch.sh            |    54 +
 t/perf/p5312-pack-bitmaps-revs.sh             |    34 +
 t/perf/p5326-multi-pack-bitmaps.sh            |    67 +
 t/perf/p5332-multi-pack-reuse.sh              |    81 +
 t/perf/p5333-pseudo-merge-bitmaps.sh          |    32 +
 t/perf/p5550-fetch-tags.sh                    |    78 +
 t/perf/p5551-fetch-rescan.sh                  |    55 +
 t/perf/p5600-partial-clone.sh                 |    42 +
 t/perf/p5601-clone-reference.sh               |    27 +
 t/perf/p6100-describe.sh                      |    30 +
 t/perf/p6300-for-each-ref.sh                  |    87 +
 t/perf/p7000-filter-branch.sh                 |    24 +
 t/perf/p7102-reset.sh                         |    21 +
 t/perf/p7300-clean.sh                         |    35 +
 t/perf/p7519-fsmonitor.sh                     |   314 +
 t/perf/p7527-builtin-fsmonitor.sh             |   257 +
 t/perf/p7810-grep.sh                          |    23 +
 t/perf/p7820-grep-engines.sh                  |    90 +
 t/perf/p7821-grep-engines-fixed.sh            |    74 +
 t/perf/p7822-grep-perl-character.sh           |    42 +
 t/perf/p9210-scalar.sh                        |    39 +
 t/perf/p9300-fast-import-export.sh            |    23 +
 t/perf/perf-lib.sh                            |   334 +
 t/perf/repos/.gitignore                       |     1 +
 t/perf/repos/inflate-repo.sh                  |    85 +
 t/perf/repos/many-files.sh                    |   110 +
 t/perf/run                                    |   258 +
 t/run-test.sh                                 |    18 +
 t/socks4-proxy.pl                             |    48 +
 t/t0000-basic.sh                              |  1250 +
 t/t0001-init.sh                               |   898 +
 t/t0002-gitfile.sh                            |   138 +
 t/t0003-attributes.sh                         |   667 +
 t/t0004-unwritable.sh                         |    83 +
 t/t0005-signals.sh                            |    54 +
 t/t0006-date.sh                               |   216 +
 t/t0007-git-var.sh                            |   279 +
 t/t0008-ignores.sh                            |   955 +
 t/t0010-racy-git.sh                           |    32 +
 t/t0012-help.sh                               |   265 +
 t/t0013-sha1dc.sh                             |    22 +
 t/t0013/shattered-1.pdf                       |   Bin 0 -> 422435 bytes
 t/t0014-alias.sh                              |    58 +
 t/t0017-env-helper.sh                         |   106 +
 t/t0018-advice.sh                             |   101 +
 t/t0019-json-writer.sh                        |   332 +
 t/t0019/parse_json.perl                       |    55 +
 t/t0020-crlf.sh                               |   400 +
 t/t0021-conversion.sh                         |  1154 +
 t/t0022-crlf-rename.sh                        |    33 +
 t/t0023-crlf-am.sh                            |    44 +
 t/t0024-crlf-archive.sh                       |    43 +
 t/t0025-crlf-renormalize.sh                   |    39 +
 t/t0026-eol-config.sh                         |   103 +
 t/t0027-auto-crlf.sh                          |   631 +
 t/t0028-working-tree-encoding.sh              |   310 +
 t/t0029-core-unsetenvvars.sh                  |    29 +
 t/t0030-stripspace.sh                         |   469 +
 t/t0033-safe-directory.sh                     |   299 +
 t/t0034-root-safe-directory.sh                |    93 +
 t/t0035-safe-bare-repository.sh               |   106 +
 t/t0040-parse-options.sh                      |   786 +
 t/t0041-usage.sh                              |   110 +
 t/t0050-filesystem.sh                         |   158 +
 t/t0051-windows-named-pipe.sh                 |    22 +
 t/t0052-simple-ipc.sh                         |   122 +
 t/t0055-beyond-symlinks.sh                    |    35 +
 t/t0056-git-C.sh                              |    94 +
 t/t0060-path-utils.sh                         |   612 +
 t/t0061-run-command.sh                        |   271 +
 t/t0062-revision-walking.sh                   |    33 +
 t/t0063-string-list.sh                        |   142 +
 t/t0066-dir-iterator.sh                       |   133 +
 t/t0067-parse_pathspec_file.sh                |   108 +
 t/t0068-for-each-repo.sh                      |    77 +
 t/t0070-fundamental.sh                        |   109 +
 t/t0071-sort.sh                               |    11 +
 t/t0080-unit-test-output.sh                   |    92 +
 t/t0081-find-pack.sh                          |    81 +
 t/t0090-cache-tree.sh                         |   281 +
 t/t0091-bugreport.sh                          |   156 +
 t/t0092-diagnose.sh                           |    71 +
 t/t0095-bloom.sh                              |   126 +
 t/t0100-previous.sh                           |    75 +
 t/t0101-at-syntax.sh                          |    46 +
 t/t0200-gettext-basic.sh                      |   108 +
 t/t0200/test.c                                |    23 +
 t/t0200/test.perl                             |    14 +
 t/t0200/test.sh                               |    14 +
 t/t0201-gettext-fallbacks.sh                  |    67 +
 t/t0202-gettext-perl.sh                       |    17 +
 t/t0202/test.pl                               |   122 +
 t/t0203-gettext-setlocale-sanity.sh           |    26 +
 t/t0204-gettext-reencode-sanity.sh            |    87 +
 t/t0210-trace2-normal.sh                      |   312 +
 t/t0210/scrub_normal.perl                     |    54 +
 t/t0211-trace2-perf.sh                        |   522 +
 t/t0211/scrub_perf.perl                       |    91 +
 t/t0212-trace2-event.sh                       |   365 +
 t/t0212/parse_events.perl                     |   261 +
 t/t0300-credentials.sh                        |  1046 +
 t/t0301-credential-cache.sh                   |   139 +
 t/t0302-credential-store.sh                   |   213 +
 t/t0303-credential-external.sh                |    84 +
 t/t0410-partial-clone.sh                      |   782 +
 t/t0411-clone-from-partial.sh                 |    75 +
 t/t0450-txt-doc-vs-help.sh                    |   170 +
 t/t0450/txt-help-mismatches                   |    57 +
 t/t0500-progress-display.sh                   |   377 +
 t/t0600-reffiles-backend.sh                   |   502 +
 t/t0601-reffiles-pack-refs.sh                 |   448 +
 t/t0602-reffiles-fsck.sh                      |   599 +
 t/t0610-reftable-basics.sh                    |  1136 +
 t/t0611-reftable-httpd.sh                     |    26 +
 t/t0612-reftable-jgit-compatibility.sh        |   132 +
 t/t0613-reftable-write-options.sh             |   286 +
 t/t1000-read-tree-m-3way.sh                   |   512 +
 t/t1001-read-tree-m-2way.sh                   |   419 +
 t/t1002-read-tree-m-u-2way.sh                 |   347 +
 t/t1003-read-tree-prefix.sh                   |    37 +
 t/t1004-read-tree-m-u-wf.sh                   |   242 +
 t/t1005-read-tree-reset.sh                    |   111 +
 t/t1006-cat-file.sh                           |  1356 +
 t/t1007-hash-object.sh                        |   268 +
 t/t1008-read-tree-overlay.sh                  |    35 +
 t/t1009-read-tree-new-index.sh                |    28 +
 t/t1010-mktree.sh                             |    69 +
 t/t1011-read-tree-sparse-checkout.sh          |   306 +
 t/t1012-read-tree-df.sh                       |   103 +
 t/t1013-read-tree-submodule.sh                |    18 +
 t/t1014-read-tree-confusing.sh                |    64 +
 t/t1015-read-index-unmerged.sh                |   124 +
 t/t1016-compatObjectFormat.sh                 |   278 +
 t/t1016/gpg                                   |     2 +
 t/t1020-subdirectory.sh                       |   195 +
 t/t1021-rerere-in-workdir.sh                  |    58 +
 t/t1022-read-tree-partial-clone.sh            |    29 +
 t/t1050-large.sh                              |   215 +
 t/t1051-large-conversion.sh                   |   113 +
 t/t1060-object-corruption.sh                  |   148 +
 t/t1090-sparse-checkout-scope.sh              |   109 +
 t/t1091-sparse-checkout-builtin.sh            |  1054 +
 t/t1092-sparse-checkout-compatibility.sh      |  2400 ++
 t/t1100-commit-tree-options.sh                |    63 +
 t/t1300-config.sh                             |  2854 ++
 t/t1301-shared-repo.sh                        |   213 +
 t/t1302-repo-version.sh                       |   124 +
 t/t1303-wacky-config.sh                       |   135 +
 t/t1304-default-acl.sh                        |    65 +
 t/t1305-config-include.sh                     |   399 +
 t/t1306-xdg-files.sh                          |   195 +
 t/t1307-config-blob.sh                        |    79 +
 t/t1308-config-set.sh                         |   399 +
 t/t1309-early-config.sh                       |   102 +
 t/t1310-config-default.sh                     |    36 +
 t/t1350-config-hooks-path.sh                  |    51 +
 t/t1400-update-ref.sh                         |  2080 ++
 t/t1401-symbolic-ref.sh                       |   225 +
 t/t1402-check-ref-format.sh                   |   218 +
 t/t1403-show-ref.sh                           |   296 +
 t/t1404-update-ref-errors.sh                  |   395 +
 t/t1405-main-ref-store.sh                     |   125 +
 t/t1406-submodule-ref-store.sh                |    98 +
 t/t1407-worktree-ref-store.sh                 |    55 +
 t/t1408-packed-refs.sh                        |    45 +
 t/t1409-avoid-packing-refs.sh                 |   124 +
 t/t1410-reflog.sh                             |   554 +
 t/t1411-reflog-show.sh                        |   172 +
 t/t1412-reflog-loop.sh                        |    32 +
 t/t1413-reflog-detach.sh                      |    72 +
 t/t1414-reflog-walk.sh                        |   138 +
 t/t1415-worktree-refs.sh                      |   104 +
 t/t1416-ref-transaction-hooks.sh              |   211 +
 t/t1417-reflog-updateref.sh                   |    68 +
 t/t1418-reflog-exists.sh                      |    37 +
 t/t1419-exclude-refs.sh                       |   158 +
 t/t1420-lost-found.sh                         |    36 +
 t/t1430-bad-ref-name.sh                       |   392 +
 t/t1450-fsck.sh                               |  1063 +
 t/t1451-fsck-buffer.sh                        |   141 +
 t/t1460-refs-migrate.sh                       |   288 +
 t/t1500-rev-parse.sh                          |   327 +
 t/t1501-work-tree.sh                          |   447 +
 t/t1502-rev-parse-parseopt.sh                 |   337 +
 t/t1502/.gitattributes                        |     1 +
 t/t1502/optionspec-neg                        |     8 +
 t/t1502/optionspec-neg.help                   |    12 +
 t/t1502/optionspec.help                       |    36 +
 t/t1503-rev-parse-verify.sh                   |   159 +
 t/t1504-ceiling-dirs.sh                       |   186 +
 t/t1505-rev-parse-last.sh                     |    64 +
 t/t1506-rev-parse-diagnosis.sh                |   285 +
 t/t1507-rev-parse-upstream.sh                 |   280 +
 t/t1508-at-combinations.sh                    |   118 +
 t/t1509-root-work-tree.sh                     |   264 +
 t/t1509/excludes                              |    14 +
 t/t1509/prepare-chroot.sh                     |    58 +
 t/t1510-repo-setup.sh                         |   805 +
 t/t1511-rev-parse-caret.sh                    |   134 +
 t/t1512-rev-parse-disambiguation.sh           |   479 +
 t/t1513-rev-parse-prefix.sh                   |    99 +
 t/t1514-rev-parse-push.sh                     |    76 +
 t/t1515-rev-parse-outside-repo.sh             |    46 +
 t/t1517-outside-repo.sh                       |   110 +
 t/t1600-index.sh                              |   136 +
 t/t1601-index-bogus.sh                        |    23 +
 t/t1700-split-index.sh                        |   547 +
 t/t1701-racy-split-index.sh                   |   214 +
 t/t1800-hook.sh                               |   187 +
 t/t2000-conflict-when-checking-files-out.sh   |   135 +
 t/t2002-checkout-cache-u.sh                   |    33 +
 t/t2003-checkout-cache-mkdir.sh               |   119 +
 t/t2004-checkout-cache-temp.sh                |   249 +
 t/t2005-checkout-index-symlinks.sh            |    30 +
 t/t2006-checkout-index-basic.sh               |   103 +
 t/t2007-checkout-symlink.sh                   |    55 +
 t/t2008-checkout-subdir.sh                    |    82 +
 t/t2009-checkout-statinfo.sh                  |    55 +
 t/t2010-checkout-ambiguous.sh                 |    68 +
 t/t2011-checkout-invalid-head.sh              |    61 +
 t/t2012-checkout-last.sh                      |   169 +
 t/t2013-checkout-submodule.sh                 |    75 +
 t/t2014-checkout-switch.sh                    |    29 +
 t/t2015-checkout-unborn.sh                    |    64 +
 t/t2016-checkout-patch.sh                     |   133 +
 t/t2017-checkout-orphan.sh                    |   137 +
 t/t2018-checkout-branch.sh                    |   288 +
 t/t2019-checkout-ambiguous-ref.sh             |    60 +
 t/t2020-checkout-detach.sh                    |   350 +
 t/t2021-checkout-overwrite.sh                 |    82 +
 t/t2022-checkout-paths.sh                     |    95 +
 t/t2023-checkout-m.sh                         |    76 +
 t/t2024-checkout-dwim.sh                      |   350 +
 t/t2025-checkout-no-overlay.sh                |    59 +
 t/t2026-checkout-pathspec-file.sh             |   163 +
 t/t2027-checkout-track.sh                     |    50 +
 t/t2030-unresolve-info.sh                     |   305 +
 t/t2050-git-dir-relative.sh                   |    55 +
 t/t2060-switch.sh                             |   180 +
 t/t2070-restore.sh                            |   223 +
 t/t2071-restore-patch.sh                      |   122 +
 t/t2072-restore-pathspec-file.sh              |   177 +
 t/t2080-parallel-checkout-basics.sh           |   277 +
 t/t2081-parallel-checkout-collisions.sh       |   162 +
 t/t2082-parallel-checkout-attributes.sh       |   191 +
 t/t2100-update-cache-badpath.sh               |    61 +
 t/t2101-update-index-reupdate.sh              |    91 +
 t/t2102-update-index-symlinks.sh              |    31 +
 t/t2103-update-index-ignore-missing.sh        |    89 +
 t/t2104-update-index-skip-worktree.sh         |    66 +
 t/t2105-update-index-gitfile.sh               |    38 +
 t/t2106-update-index-assume-unchanged.sh      |    27 +
 t/t2107-update-index-basic.sh                 |   145 +
 t/t2108-update-index-refresh-racy.sh          |    63 +
 t/t2200-add-update.sh                         |   220 +
 t/t2201-add-update-typechange.sh              |   148 +
 t/t2202-add-addremove.sh                      |    54 +
 t/t2203-add-intent.sh                         |   314 +
 t/t2204-add-ignored.sh                        |    92 +
 t/t2205-add-worktree-config.sh                |   265 +
 t/t2300-cd-to-toplevel.sh                     |    46 +
 t/t2400-worktree-add.sh                       |  1255 +
 t/t2401-worktree-prune.sh                     |   142 +
 t/t2402-worktree-list.sh                      |   310 +
 t/t2403-worktree-move.sh                      |   274 +
 t/t2404-worktree-config.sh                    |    81 +
 t/t2405-worktree-submodule.sh                 |    94 +
 t/t2406-worktree-repair.sh                    |   257 +
 t/t2407-worktree-heads.sh                     |   179 +
 t/t2500-untracked-overwriting.sh              |   244 +
 t/t2501-cwd-empty.sh                          |   277 +
 t/t3000-ls-files-others.sh                    |   232 +
 t/t3001-ls-files-others-exclude.sh            |   306 +
 t/t3002-ls-files-dashpath.sh                  |    76 +
 t/t3003-ls-files-exclude.sh                   |    41 +
 t/t3004-ls-files-basic.sh                     |    54 +
 t/t3005-ls-files-relative.sh                  |    62 +
 t/t3006-ls-files-long.sh                      |    40 +
 t/t3007-ls-files-recurse-submodules.sh        |   348 +
 t/t3008-ls-files-lazy-init-name-hash.sh       |    27 +
 t/t3009-ls-files-others-nonsubmodule.sh       |    50 +
 t/t3010-ls-files-killed-modified.sh           |   127 +
 ...common-prefixes-and-directory-traversal.sh |   209 +
 t/t3012-ls-files-dedup.sh                     |    66 +
 t/t3013-ls-files-format.sh                    |   145 +
 t/t3020-ls-files-error-unmatch.sh             |    29 +
 t/t3040-subprojects-basic.sh                  |    83 +
 t/t3050-subprojects-fetch.sh                  |    52 +
 t/t3060-ls-files-with-tree.sh                 |   105 +
 t/t3070-wildmatch.sh                          |   444 +
 t/t3100-ls-tree-restrict.sh                   |   166 +
 t/t3101-ls-tree-dirname.sh                    |   241 +
 t/t3102-ls-tree-wildcards.sh                  |    36 +
 t/t3103-ls-tree-misc.sh                       |    40 +
 t/t3104-ls-tree-format.sh                     |    79 +
 t/t3105-ls-tree-output.sh                     |   191 +
 t/t3200-branch.sh                             |  1705 +
 t/t3201-branch-contains.sh                    |   267 +
 t/t3202-show-branch.sh                        |   286 +
 t/t3203-branch-output.sh                      |   488 +
 t/t3204-branch-name-interpretation.sh         |   170 +
 t/t3205-branch-color.sh                       |    44 +
 t/t3206-range-diff.sh                         |   927 +
 t/t3206/history.export                        |   709 +
 t/t3207-branch-submodule.sh                   |   329 +
 t/t3211-peel-ref.sh                           |    76 +
 t/t3300-funny-names.sh                        |   217 +
 t/t3301-notes.sh                              |  1632 +
 t/t3302-notes-index-expensive.sh              |   138 +
 t/t3303-notes-subtrees.sh                     |   198 +
 t/t3304-notes-mixed.sh                        |   209 +
 t/t3305-notes-fanout.sh                       |   140 +
 t/t3306-notes-prune.sh                        |   138 +
 t/t3307-notes-man.sh                          |    38 +
 t/t3308-notes-merge.sh                        |   394 +
 t/t3309-notes-merge-auto-resolve.sh           |   791 +
 t/t3310-notes-merge-manual-resolve.sh         |   617 +
 t/t3311-notes-merge-fanout.sh                 |   446 +
 t/t3320-notes-merge-worktrees.sh              |    77 +
 t/t3321-notes-stripspace.sh                   |   577 +
 t/t3400-rebase.sh                             |   477 +
 t/t3401-rebase-and-am-rename.sh               |   213 +
 t/t3402-rebase-merge.sh                       |   224 +
 t/t3403-rebase-skip.sh                        |   202 +
 t/t3404-rebase-interactive.sh                 |  2291 ++
 t/t3405-rebase-malformed.sh                   |    93 +
 t/t3406-rebase-message.sh                     |   258 +
 t/t3407-rebase-abort.sh                       |   131 +
 t/t3408-rebase-multi-line.sh                  |    58 +
 t/t3409-rebase-environ.sh                     |    23 +
 t/t3412-rebase-root.sh                        |   241 +
 t/t3413-rebase-hook.sh                        |   141 +
 t/t3415-rebase-autosquash.sh                  |   487 +
 t/t3416-rebase-onto-threedots.sh              |   228 +
 t/t3417-rebase-whitespace-fix.sh              |   124 +
 t/t3418-rebase-continue.sh                    |   357 +
 t/t3419-rebase-patch-id.sh                    |   117 +
 t/t3420-rebase-autostash.sh                   |   386 +
 t/t3421-rebase-topology-linear.sh             |   360 +
 t/t3422-rebase-incompatible-options.sh        |   133 +
 t/t3423-rebase-reword.sh                      |    48 +
 t/t3424-rebase-empty.sh                       |   219 +
 t/t3425-rebase-topology-merges.sh             |   110 +
 t/t3426-rebase-submodule.sh                   |    64 +
 t/t3427-rebase-subtree.sh                     |    93 +
 t/t3428-rebase-signoff.sh                     |   140 +
 t/t3429-rebase-edit-todo.sh                   |    90 +
 t/t3430-rebase-merges.sh                      |   613 +
 t/t3431-rebase-fork-point.sh                  |   115 +
 t/t3432-rebase-fast-forward.sh                |   141 +
 t/t3433-rebase-across-mode-change.sh          |    48 +
 t/t3434-rebase-i18n.sh                        |    93 +
 t/t3434/ISO8859-1.txt                         |     3 +
 t/t3434/eucJP.txt                             |     4 +
 t/t3435-rebase-gpg-sign.sh                    |   123 +
 t/t3436-rebase-more-options.sh                |   209 +
 t/t3437-rebase-fixup-options.sh               |   237 +
 t/t3437/expected-combined-message             |    21 +
 t/t3437/expected-squash-message               |    51 +
 t/t3438-rebase-broken-files.sh                |    69 +
 t/t3500-cherry.sh                             |    81 +
 t/t3501-revert-cherry-pick.sh                 |   259 +
 t/t3502-cherry-pick-merge.sh                  |   135 +
 t/t3503-cherry-pick-root.sh                   |    81 +
 t/t3504-cherry-pick-rerere.sh                 |   106 +
 t/t3505-cherry-pick-empty.sh                  |   151 +
 t/t3506-cherry-pick-ff.sh                     |   123 +
 t/t3507-cherry-pick-conflict.sh               |   590 +
 t/t3508-cherry-pick-many-commits.sh           |   199 +
 t/t3509-cherry-pick-merge-df.sh               |   104 +
 t/t3510-cherry-pick-sequence.sh               |   724 +
 t/t3511-cherry-pick-x.sh                      |   321 +
 t/t3512-cherry-pick-submodule.sh              |    56 +
 t/t3513-revert-submodule.sh                   |    39 +
 t/t3514-cherry-pick-revert-gpg.sh             |    86 +
 t/t3600-rm.sh                                 |   908 +
 t/t3601-rm-pathspec-file.sh                   |    79 +
 t/t3602-rm-sparse-checkout.sh                 |   139 +
 t/t3650-replay-basics.sh                      |   198 +
 t/t3700-add.sh                                |   551 +
 t/t3701-add-interactive.sh                    |  1233 +
 t/t3702-add-edit.sh                           |   128 +
 t/t3703-add-magic-pathspec.sh                 |    58 +
 t/t3704-add-pathspec-file.sh                  |   159 +
 t/t3705-add-sparse-checkout.sh                |   236 +
 t/t3800-mktag.sh                              |   586 +
 t/t3900-i18n-commit.sh                        |   246 +
 t/t3900/1-UTF-8.txt                           |     3 +
 t/t3900/2-UTF-8.txt                           |     4 +
 t/t3900/ISO-2022-JP.txt                       |     4 +
 t/t3900/ISO8859-1.txt                         |     3 +
 t/t3900/UTF-16.txt                            |   Bin 0 -> 146 bytes
 t/t3900/eucJP.txt                             |     4 +
 t/t3901-i18n-patch.sh                         |   325 +
 t/t3901/8859-1.txt                            |     4 +
 t/t3901/utf8.txt                              |     4 +
 t/t3902-quoted.sh                             |   152 +
 t/t3903-stash.sh                              |  1595 +
 t/t3904-stash-patch.sh                        |   110 +
 t/t3905-stash-include-untracked.sh            |   431 +
 t/t3906-stash-submodule.sh                    |    69 +
 t/t3907-stash-show-config.sh                  |    83 +
 t/t3908-stash-in-worktree.sh                  |    27 +
 t/t3909-stash-pathspec-file.sh                |   100 +
 t/t3910-mac-os-precompose.sh                  |   260 +
 t/t3920-crlf-messages.sh                      |   127 +
 t/t4000-diff-format.sh                        |   125 +
 t/t4001-diff-rename.sh                        |   312 +
 t/t4002-diff-basic.sh                         |   413 +
 t/t4003-diff-rename-1.sh                      |   129 +
 t/t4004-diff-rename-symlink.sh                |    70 +
 t/t4005-diff-rename-2.sh                      |    78 +
 t/t4006-diff-mode.sh                          |    67 +
 t/t4007-rename-3.sh                           |    91 +
 t/t4008-diff-break-rewrite.sh                 |   160 +
 t/t4009-diff-rename-4.sh                      |    99 +
 t/t4010-diff-pathspec.sh                      |   153 +
 t/t4011-diff-symlink.sh                       |   176 +
 t/t4012-diff-binary.sh                        |   133 +
 t/t4013-diff-various.sh                       |   707 +
 ...nfig_format.subjectprefix_DIFFERENT_PREFIX |     2 +
 ...ee_--cc_--patch-with-stat_--summary_master |    34 +
 ...tree_--cc_--patch-with-stat_--summary_side |    39 +
 ...ff.diff-tree_--cc_--patch-with-stat_master |    34 +
 .../diff.diff-tree_--cc_--shortstat_master    |     4 +
 ...iff.diff-tree_--cc_--stat_--summary_master |     6 +
 .../diff.diff-tree_--cc_--stat_--summary_side |     8 +
 t/t4013/diff.diff-tree_--cc_--stat_master     |     6 +
 t/t4013/diff.diff-tree_--cc_--summary_REVERSE |     6 +
 t/t4013/diff.diff-tree_--cc_master            |    30 +
 t/t4013/diff.diff-tree_--format=%N_note       |     6 +
 .../diff.diff-tree_--patch-with-raw_initial   |     2 +
 .../diff.diff-tree_--patch-with-stat_initial  |     2 +
 ..._--pretty=oneline_--patch-with-raw_initial |     2 +
 ...--pretty=oneline_--patch-with-stat_initial |     2 +
 ...ty=oneline_--root_--patch-with-raw_initial |    33 +
 ...y=oneline_--root_--patch-with-stat_initial |    34 +
 ...ff-tree_--pretty=oneline_--root_-p_initial |    29 +
 ....diff-tree_--pretty=oneline_--root_initial |     6 +
 ...diff.diff-tree_--pretty=oneline_-p_initial |     2 +
 .../diff.diff-tree_--pretty=oneline_initial   |     2 +
 t/t4013/diff.diff-tree_--pretty_--notes_note  |    12 +
 ...iff-tree_--pretty_--patch-with-raw_initial |     2 +
 ...ff-tree_--pretty_--patch-with-stat_initial |     2 +
 ....diff-tree_--pretty_--patch-with-stat_side |    43 +
 ...e_--pretty_--root_--patch-with-raw_initial |    38 +
 ..._--pretty_--root_--patch-with-stat_initial |    39 +
 ...ty_--root_--stat_--compact-summary_initial |    12 +
 ...e_--pretty_--root_--stat_--summary_initial |    15 +
 ...f.diff-tree_--pretty_--root_--stat_initial |    12 +
 ...-tree_--pretty_--root_--summary_-r_initial |    11 +
 ...iff-tree_--pretty_--root_--summary_initial |    11 +
 .../diff.diff-tree_--pretty_--root_-p_initial |    34 +
 .../diff.diff-tree_--pretty_--root_initial    |    11 +
 ...iff-tree_--pretty_--stat_--summary_initial |     2 +
 .../diff.diff-tree_--pretty_--stat_initial    |     2 +
 .../diff.diff-tree_--pretty_--summary_initial |     2 +
 ...-R_--root_--stat_--compact-summary_initial |    12 +
 t/t4013/diff.diff-tree_--pretty_-p_initial    |     2 +
 t/t4013/diff.diff-tree_--pretty_-p_side       |    38 +
 t/t4013/diff.diff-tree_--pretty_initial       |     2 +
 t/t4013/diff.diff-tree_--pretty_note          |     9 +
 t/t4013/diff.diff-tree_--pretty_side          |    11 +
 .../diff.diff-tree_--root_--abbrev_initial    |     6 +
 ....diff-tree_--root_--patch-with-raw_initial |    33 +
 ...diff-tree_--root_--patch-with-stat_initial |    34 +
 ...ff.diff-tree_--root_-p_--abbrev=10_initial |    29 +
 ...--root_-p_--full-index_--abbrev=10_initial |    29 +
 ...f.diff-tree_--root_-p_--full-index_initial |    29 +
 t/t4013/diff.diff-tree_--root_-p_initial      |    29 +
 ...iff.diff-tree_--root_-r_--abbrev=4_initial |     6 +
 .../diff.diff-tree_--root_-r_--abbrev_initial |     6 +
 t/t4013/diff.diff-tree_--root_-r_initial      |     6 +
 t/t4013/diff.diff-tree_--root_initial         |     6 +
 ...tree_--stat_--compact-summary_initial_mode |     4 +
 t/t4013/diff.diff-tree_--stat_initial_mode    |     4 +
 t/t4013/diff.diff-tree_--summary_initial_mode |     3 +
 ...e_-R_--stat_--compact-summary_initial_mode |     4 +
 t/t4013/diff.diff-tree_-c_--abbrev_master     |     5 +
 .../diff.diff-tree_-c_--stat_--summary_master |     6 +
 .../diff.diff-tree_-c_--stat_--summary_side   |     8 +
 t/t4013/diff.diff-tree_-c_--stat_master       |     6 +
 t/t4013/diff.diff-tree_-c_master              |     5 +
 t/t4013/diff.diff-tree_-m_master              |    11 +
 t/t4013/diff.diff-tree_-p_-m_master           |    80 +
 t/t4013/diff.diff-tree_-p_initial             |     2 +
 t/t4013/diff.diff-tree_-p_master              |     2 +
 t/t4013/diff.diff-tree_-r_--abbrev=4_initial  |     2 +
 t/t4013/diff.diff-tree_-r_--abbrev_initial    |     2 +
 t/t4013/diff.diff-tree_-r_initial             |     2 +
 t/t4013/diff.diff-tree_initial                |     2 +
 t/t4013/diff.diff-tree_initial_mode           |     3 +
 t/t4013/diff.diff-tree_master                 |     2 +
 t/t4013/diff.diff_--abbrev_initial..side      |    32 +
 t/t4013/diff.diff_--cached                    |    38 +
 t/t4013/diff.diff_--cached_--_file0           |    15 +
 ...f.diff_--dirstat-by-file_initial_rearrange |     3 +
 .../diff.diff_--dirstat_--cc_master~1_master  |     3 +
 t/t4013/diff.diff_--dirstat_initial_rearrange |     3 +
 t/t4013/diff.diff_--dirstat_master~1_master~2 |     3 +
 ...diff_--line-prefix=abc_master_master^_side |    29 +
 .../diff.diff_--line-prefix_--cached_--_file0 |    15 +
 t/t4013/diff.diff_--name-status_dir2_dir      |     2 +
 ....diff_--no-index_--name-status_--_dir2_dir |     3 +
 ...iff.diff_--no-index_--name-status_dir2_dir |     3 +
 ....diff_--no-index_--raw_--abbrev=4_dir2_dir |     3 +
 ...diff_--no-index_--raw_--no-abbrev_dir2_dir |     3 +
 t/t4013/diff.diff_--no-index_--raw_dir2_dir   |     3 +
 t/t4013/diff.diff_--no-index_dir_dir3         |     2 +
 ...iff.diff_--patch-with-raw_-r_initial..side |    36 +
 .../diff.diff_--patch-with-raw_initial..side  |    36 +
 ...ff.diff_--patch-with-stat_-r_initial..side |    37 +
 .../diff.diff_--patch-with-stat_initial..side |    37 +
 t/t4013/diff.diff_--raw_--abbrev=4_initial    |     6 +
 t/t4013/diff.diff_--raw_--no-abbrev_initial   |     6 +
 t/t4013/diff.diff_--raw_initial               |     6 +
 t/t4013/diff.diff_--stat_initial..side        |     6 +
 t/t4013/diff.diff_-U1_initial..side           |    29 +
 t/t4013/diff.diff_-U2_initial..side           |    31 +
 t/t4013/diff.diff_-U_initial..side            |    32 +
 t/t4013/diff.diff_-r_--stat_initial..side     |     6 +
 t/t4013/diff.diff_-r_initial..side            |    32 +
 t/t4013/diff.diff_initial..side               |    32 +
 t/t4013/diff.diff_master_master^_side         |    29 +
 ...tach_--stdout_--suffix=.diff_initial..side |    61 +
 ...at-patch_--attach_--stdout_initial..master |   170 +
 ...t-patch_--attach_--stdout_initial..master^ |   110 +
 ...rmat-patch_--attach_--stdout_initial..side |    61 +
 ..._--stdout_--numbered-files_initial..master |   170 +
 ..._--subject-prefix=TESTCASE_initial..master |   170 +
 ...at-patch_--inline_--stdout_initial..master |   170 +
 ...t-patch_--inline_--stdout_initial..master^ |   110 +
 ...-patch_--inline_--stdout_initial..master^^ |    62 +
 ...rmat-patch_--inline_--stdout_initial..side |    61 +
 ...-stdout_--cover-letter_-n_initial..master^ |   103 +
 ...tch_--stdout_--no-numbered_initial..master |   127 +
 ...-patch_--stdout_--numbered_initial..master |   127 +
 ...diff.format-patch_--stdout_initial..master |   127 +
 ...iff.format-patch_--stdout_initial..master^ |    81 +
 .../diff.format-patch_--stdout_initial..side  |    47 +
 t/t4013/diff.log_--cc_-m_-p_master            |   200 +
 t/t4013/diff.log_--decorate=full_--all        |    61 +
 ..._--decorate=full_--clear-decorations_--all |    61 +
 ...f.log_--decorate=full_--decorate-all_--all |    61 +
 t/t4013/diff.log_--decorate_--all             |    61 +
 ...f.log_--decorate_--clear-decorations_--all |    61 +
 .../diff.log_--decorate_--decorate-all_--all  |    61 +
 ...diff.log_--diff-merges=first-parent_master |    56 +
 ...--diff-merges=off_-p_--first-parent_master |    78 +
 ...--first-parent_--diff-merges=off_-p_master |    78 +
 ..._--no-diff-merges_-p_--first-parent_master |    78 +
 ...--patch-with-stat_--summary_master_--_dir_ |    74 +
 t/t4013/diff.log_--patch-with-stat_master     |   129 +
 .../diff.log_--patch-with-stat_master_--_dir_ |    74 +
 ...ot_--cc_--patch-with-stat_--summary_master |   199 +
 ..._--root_--patch-with-stat_--summary_master |   167 +
 .../diff.log_--root_--patch-with-stat_master  |   161 +
 ...root_-c_--patch-with-stat_--summary_master |   199 +
 t/t4013/diff.log_--root_-p_master             |   142 +
 t/t4013/diff.log_--root_master                |    34 +
 t/t4013/diff.log_-GF_-p_--pickaxe-all_master  |    27 +
 t/t4013/diff.log_-GF_-p_master                |    18 +
 t/t4013/diff.log_-GF_master                   |     7 +
 t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_master    |    99 +
 t/t4013/diff.log_-SF_-p_master                |    18 +
 t/t4013/diff.log_-SF_master                   |     7 +
 t/t4013/diff.log_-SF_master_--max-count=0     |     2 +
 t/t4013/diff.log_-SF_master_--max-count=1     |     7 +
 t/t4013/diff.log_-SF_master_--max-count=2     |     7 +
 t/t4013/diff.log_-S_F_master                  |     7 +
 t/t4013/diff.log_-c_-m_-p_master              |   200 +
 t/t4013/diff.log_-m_--raw_master              |    61 +
 t/t4013/diff.log_-m_--stat_master             |    66 +
 t/t4013/diff.log_-m_-p_--first-parent_master  |   100 +
 t/t4013/diff.log_-m_-p_master                 |   200 +
 ...f.log_-p_--diff-merges=first-parent_master |   137 +
 t/t4013/diff.log_-p_--first-parent_master     |   100 +
 t/t4013/diff.log_-p_master                    |   115 +
 t/t4013/diff.log_master                       |    34 +
 ...ellipses-diff-tree_--root_--abbrev_initial |     6 +
 ...ses-diff-tree_--root_-r_--abbrev=4_initial |     6 +
 ...ipses-diff-tree_--root_-r_--abbrev_initial |     6 +
 ...ff.noellipses-diff-tree_-c_--abbrev_master |     5 +
 ...-diff_--no-index_--raw_--abbrev=4_dir2_dir |     3 +
 ....noellipses-diff_--no-index_--raw_dir2_dir |     3 +
 ...ses-diff_--patch-with-raw_-r_initial..side |    36 +
 ...lipses-diff_--patch-with-raw_initial..side |    36 +
 ...f.noellipses-diff_--raw_--abbrev=4_initial |     6 +
 t/t4013/diff.noellipses-diff_--raw_initial    |     6 +
 ...diff.noellipses-show_--patch-with-raw_side |    42 +
 .../diff.noellipses-whatchanged_--root_master |    42 +
 .../diff.noellipses-whatchanged_-SF_master    |     9 +
 t/t4013/diff.noellipses-whatchanged_master    |    32 +
 t/t4013/diff.rev-list_--children_HEAD         |     7 +
 t/t4013/diff.rev-list_--parents_HEAD          |     7 +
 t/t4013/diff.show_--first-parent_master       |    30 +
 t/t4013/diff.show_--patch-with-raw_side       |    42 +
 ...diff.show_--patch-with-stat_--summary_side |    44 +
 t/t4013/diff.show_--patch-with-stat_side      |    43 +
 t/t4013/diff.show_--root_initial              |    34 +
 t/t4013/diff.show_--stat_--summary_side       |    13 +
 t/t4013/diff.show_--stat_side                 |    12 +
 t/t4013/diff.show_-c_master                   |    36 +
 t/t4013/diff.show_-m_master                   |    93 +
 t/t4013/diff.show_initial                     |     7 +
 t/t4013/diff.show_master                      |    36 +
 t/t4013/diff.show_side                        |    38 +
 ...--patch-with-stat_--summary_master_--_dir_ |    61 +
 .../diff.whatchanged_--patch-with-stat_master |   116 +
 ...atchanged_--patch-with-stat_master_--_dir_ |    61 +
 ...ot_--cc_--patch-with-stat_--summary_master |   199 +
 ..._--root_--patch-with-stat_--summary_master |   160 +
 ...hatchanged_--root_--patch-with-stat_master |   154 +
 ...root_-c_--patch-with-stat_--summary_master |   199 +
 t/t4013/diff.whatchanged_--root_-p_master     |   135 +
 t/t4013/diff.whatchanged_--root_master        |    42 +
 t/t4013/diff.whatchanged_-SF_-p_master        |    18 +
 t/t4013/diff.whatchanged_-SF_master           |     9 +
 t/t4013/diff.whatchanged_-p_master            |   102 +
 t/t4013/diff.whatchanged_master               |    32 +
 t/t4014-format-patch.sh                       |  2550 ++
 t/t4015-diff-whitespace.sh                    |  2388 ++
 t/t4016-diff-quote.sh                         |    88 +
 t/t4017-diff-retval.sh                        |   190 +
 t/t4018-diff-funcname.sh                      |   122 +
 t/t4018/README                                |    15 +
 t/t4018/bash-arithmetic-function              |     4 +
 t/t4018/bash-bashism-style-compact            |     6 +
 t/t4018/bash-bashism-style-function           |     4 +
 t/t4018/bash-bashism-style-whitespace         |     4 +
 t/t4018/bash-conditional-function             |     4 +
 t/t4018/bash-missing-parentheses              |     6 +
 t/t4018/bash-mixed-style-compact              |     4 +
 t/t4018/bash-mixed-style-function             |     4 +
 t/t4018/bash-nested-functions                 |     6 +
 t/t4018/bash-other-characters                 |     4 +
 t/t4018/bash-posix-style-compact              |     4 +
 t/t4018/bash-posix-style-function             |     4 +
 t/t4018/bash-posix-style-whitespace           |     4 +
 t/t4018/bash-subshell-function                |     4 +
 t/t4018/bash-trailing-comment                 |     4 +
 t/t4018/cpp-c++-function                      |     4 +
 t/t4018/cpp-class-constructor                 |     4 +
 t/t4018/cpp-class-constructor-mem-init        |     5 +
 t/t4018/cpp-class-definition                  |     4 +
 t/t4018/cpp-class-definition-derived          |     5 +
 t/t4018/cpp-class-destructor                  |     4 +
 t/t4018/cpp-function-returning-global-type    |     4 +
 t/t4018/cpp-function-returning-nested         |     5 +
 t/t4018/cpp-function-returning-pointer        |     4 +
 t/t4018/cpp-function-returning-reference      |     4 +
 t/t4018/cpp-gnu-style-function                |     5 +
 t/t4018/cpp-namespace-definition              |     4 +
 t/t4018/cpp-operator-definition               |     4 +
 t/t4018/cpp-skip-access-specifiers            |     8 +
 t/t4018/cpp-skip-comment-block                |     9 +
 t/t4018/cpp-skip-labels                       |     8 +
 t/t4018/cpp-struct-definition                 |     9 +
 t/t4018/cpp-struct-single-line                |     7 +
 t/t4018/cpp-template-function-definition      |     4 +
 t/t4018/cpp-union-definition                  |     4 +
 t/t4018/cpp-void-c-function                   |     4 +
 t/t4018/csharp-exclude-assignments            |    20 +
 t/t4018/csharp-exclude-control-statements     |    34 +
 t/t4018/csharp-exclude-exceptions             |    29 +
 t/t4018/csharp-exclude-generic-method-calls   |    12 +
 t/t4018/csharp-exclude-init-dispose           |    22 +
 t/t4018/csharp-exclude-iterations             |    26 +
 t/t4018/csharp-exclude-method-calls           |    20 +
 t/t4018/csharp-exclude-other                  |    18 +
 t/t4018/csharp-method                         |    10 +
 t/t4018/csharp-method-array                   |    10 +
 t/t4018/csharp-method-explicit                |    12 +
 t/t4018/csharp-method-generics                |    11 +
 .../csharp-method-generics-alternate-spaces   |    11 +
 t/t4018/csharp-method-modifiers               |    13 +
 t/t4018/csharp-method-multiline               |    10 +
 t/t4018/csharp-method-params                  |    10 +
 t/t4018/csharp-method-special-chars           |    11 +
 t/t4018/csharp-method-with-spacing            |    10 +
 t/t4018/csharp-property                       |    11 +
 t/t4018/csharp-property-braces-same-line      |    10 +
 t/t4018/css-attribute-value-selector          |     4 +
 t/t4018/css-block-level-@-statements          |    10 +
 t/t4018/css-brace-in-col-1                    |     5 +
 t/t4018/css-class-selector                    |     4 +
 t/t4018/css-colon-eol                         |     4 +
 t/t4018/css-colon-selector                    |     5 +
 t/t4018/css-common                            |     4 +
 t/t4018/css-id-selector                       |     4 +
 t/t4018/css-long-selector-list                |     6 +
 t/t4018/css-prop-sans-indent                  |     5 +
 t/t4018/css-root-selector                     |     4 +
 t/t4018/css-short-selector-list               |     4 +
 t/t4018/css-trailing-space                    |     5 +
 t/t4018/custom1-pattern                       |    17 +
 t/t4018/custom2-match-to-end-of-line          |     8 +
 t/t4018/custom3-alternation-in-pattern        |    17 +
 t/t4018/dts-labels                            |     9 +
 t/t4018/dts-node-unitless                     |     8 +
 t/t4018/dts-nodes                             |     8 +
 t/t4018/dts-nodes-boolean-prop                |     9 +
 t/t4018/dts-nodes-comment1                    |     8 +
 t/t4018/dts-nodes-comment2                    |     8 +
 t/t4018/dts-nodes-multiline-prop              |    13 +
 t/t4018/dts-reference                         |     9 +
 t/t4018/dts-root                              |     5 +
 t/t4018/dts-root-comment                      |     8 +
 t/t4018/elixir-do-not-pick-end                |     5 +
 t/t4018/elixir-ex-unit-test                   |     6 +
 t/t4018/elixir-function                       |     5 +
 t/t4018/elixir-macro                          |     5 +
 t/t4018/elixir-module                         |     9 +
 t/t4018/elixir-module-func                    |     8 +
 t/t4018/elixir-nested-module                  |     9 +
 t/t4018/elixir-private-function               |     5 +
 t/t4018/elixir-protocol                       |     6 +
 t/t4018/elixir-protocol-implementation        |     5 +
 t/t4018/fortran-block-data                    |     5 +
 t/t4018/fortran-comment                       |    13 +
 t/t4018/fortran-comment-keyword               |    14 +
 t/t4018/fortran-comment-legacy                |    13 +
 t/t4018/fortran-comment-legacy-star           |    13 +
 t/t4018/fortran-external-function             |     9 +
 t/t4018/fortran-external-subroutine           |     5 +
 t/t4018/fortran-module                        |     5 +
 t/t4018/fortran-module-procedure              |    13 +
 t/t4018/fortran-program                       |     5 +
 t/t4018/fountain-scene                        |     4 +
 t/t4018/golang-complex-function               |     8 +
 t/t4018/golang-func                           |     4 +
 t/t4018/golang-interface                      |     4 +
 t/t4018/golang-long-func                      |     5 +
 t/t4018/golang-struct                         |     4 +
 t/t4018/java-class-brace-on-separate-line     |     6 +
 t/t4018/java-class-member-function            |    12 +
 .../java-class-space-before-type-parameters   |     6 +
 t/t4018/java-class-type-parameters            |     6 +
 t/t4018/java-class-type-parameters-implements |     6 +
 t/t4018/java-enum-constant                    |     6 +
 t/t4018/java-interface-type-parameters        |     6 +
 .../java-interface-type-parameters-extends    |     6 +
 t/t4018/java-method-return-generic-bounded    |     9 +
 t/t4018/java-method-return-generic-wildcard   |     9 +
 t/t4018/java-nested-field                     |     6 +
 t/t4018/java-non-sealed                       |     8 +
 t/t4018/java-record                           |     6 +
 t/t4018/java-record-space-before-components   |     6 +
 t/t4018/java-record-type-parameters           |     6 +
 t/t4018/java-sealed                           |     7 +
 t/t4018/java-sealed-permits                   |     6 +
 t/t4018/java-sealed-type-parameters           |     6 +
 ...-sealed-type-parameters-implements-permits |     6 +
 t/t4018/java-sealed-type-parameters-permits   |     6 +
 t/t4018/kotlin-class                          |     5 +
 t/t4018/kotlin-enum-class                     |     5 +
 t/t4018/kotlin-fun                            |     5 +
 t/t4018/kotlin-inheritace-class               |     5 +
 t/t4018/kotlin-inline-class                   |     5 +
 t/t4018/kotlin-interface                      |     5 +
 t/t4018/kotlin-nested-fun                     |     9 +
 t/t4018/kotlin-public-class                   |     5 +
 t/t4018/kotlin-sealed-class                   |     5 +
 t/t4018/markdown-heading-indented             |     6 +
 t/t4018/markdown-heading-non-headings         |    17 +
 t/t4018/matlab-class-definition               |     5 +
 t/t4018/matlab-function                       |     4 +
 t/t4018/matlab-octave-section-1               |     3 +
 t/t4018/matlab-octave-section-2               |     3 +
 t/t4018/matlab-section                        |     3 +
 t/t4018/perl-skip-end-of-heredoc              |     8 +
 t/t4018/perl-skip-forward-decl                |    10 +
 t/t4018/perl-skip-sub-in-pod                  |    18 +
 t/t4018/perl-sub-definition                   |     4 +
 t/t4018/perl-sub-definition-kr-brace          |     4 +
 t/t4018/php-abstract-class                    |     4 +
 t/t4018/php-abstract-method                   |     7 +
 t/t4018/php-class                             |     4 +
 t/t4018/php-enum                              |     4 +
 t/t4018/php-final-class                       |     4 +
 t/t4018/php-final-method                      |     7 +
 t/t4018/php-function                          |     4 +
 t/t4018/php-interface                         |     4 +
 t/t4018/php-method                            |     7 +
 t/t4018/php-trait                             |     7 +
 t/t4018/python-async-def                      |     4 +
 t/t4018/python-class                          |     4 +
 t/t4018/python-def                            |     4 +
 t/t4018/python-indented-async-def             |     7 +
 t/t4018/python-indented-class                 |     5 +
 t/t4018/python-indented-def                   |     7 +
 t/t4018/rust-fn                               |     5 +
 t/t4018/rust-impl                             |     5 +
 t/t4018/rust-macro-rules                      |     6 +
 t/t4018/rust-struct                           |     5 +
 t/t4018/rust-trait                            |     5 +
 t/t4018/scheme-class                          |     7 +
 t/t4018/scheme-def                            |     4 +
 t/t4018/scheme-def-variant                    |     4 +
 t/t4018/scheme-define-slash-public            |     7 +
 t/t4018/scheme-define-syntax                  |     8 +
 t/t4018/scheme-define-variant                 |     4 +
 t/t4018/scheme-library                        |    11 +
 t/t4018/scheme-local-define                   |     4 +
 t/t4018/scheme-module                         |     6 +
 t/t4018/scheme-top-level-define               |     4 +
 t/t4018/scheme-user-defined-define            |     6 +
 t/t4019-diff-wserror.sh                       |   297 +
 t/t4020-diff-external.sh                      |   339 +
 t/t4020/diff.NUL                              |   Bin 0 -> 116 bytes
 t/t4021-format-patch-numbered.sh              |   141 +
 t/t4022-diff-rewrite.sh                       |   101 +
 t/t4023-diff-rename-typechange.sh             |    88 +
 t/t4024-diff-optimize-common.sh               |   157 +
 t/t4025-hunk-header.sh                        |    38 +
 t/t4026-color.sh                              |   178 +
 t/t4027-diff-submodule.sh                     |   291 +
 t/t4028-format-patch-mime-headers.sh          |    31 +
 t/t4029-diff-trailing-space.sh                |    43 +
 t/t4030-diff-textconv.sh                      |   174 +
 t/t4031-diff-rewrite-binary.sh                |    80 +
 t/t4032-diff-inter-hunk-context.sh            |   117 +
 t/t4033-diff-patience.sh                      |    20 +
 t/t4034-diff-words.sh                         |   415 +
 t/t4034/ada/expect                            |    27 +
 t/t4034/ada/post                              |    13 +
 t/t4034/ada/pre                               |    13 +
 t/t4034/bibtex/expect                         |    15 +
 t/t4034/bibtex/post                           |    10 +
 t/t4034/bibtex/pre                            |     9 +
 t/t4034/cpp/expect                            |    35 +
 t/t4034/cpp/post                              |    30 +
 t/t4034/cpp/pre                               |    30 +
 t/t4034/csharp/expect                         |    35 +
 t/t4034/csharp/post                           |    18 +
 t/t4034/csharp/pre                            |    18 +
 t/t4034/css/expect                            |    16 +
 t/t4034/css/post                              |    10 +
 t/t4034/css/pre                               |    10 +
 t/t4034/dts/expect                            |    37 +
 t/t4034/dts/post                              |    32 +
 t/t4034/dts/pre                               |    32 +
 t/t4034/fortran/expect                        |    10 +
 t/t4034/fortran/post                          |     5 +
 t/t4034/fortran/pre                           |     5 +
 t/t4034/html/expect                           |     8 +
 t/t4034/html/post                             |     3 +
 t/t4034/html/pre                              |     3 +
 t/t4034/java/expect                           |    36 +
 t/t4034/java/post                             |    19 +
 t/t4034/java/pre                              |    19 +
 t/t4034/kotlin/expect                         |    43 +
 t/t4034/kotlin/post                           |    30 +
 t/t4034/kotlin/pre                            |    30 +
 t/t4034/matlab/expect                         |    14 +
 t/t4034/matlab/post                           |     9 +
 t/t4034/matlab/pre                            |     9 +
 t/t4034/objc/expect                           |    35 +
 t/t4034/objc/post                             |    18 +
 t/t4034/objc/pre                              |    18 +
 t/t4034/pascal/expect                         |    35 +
 t/t4034/pascal/post                           |    18 +
 t/t4034/pascal/pre                            |    18 +
 t/t4034/perl/expect                           |    13 +
 t/t4034/perl/post                             |    22 +
 t/t4034/perl/pre                              |    22 +
 t/t4034/php/expect                            |    35 +
 t/t4034/php/post                              |    18 +
 t/t4034/php/pre                               |    18 +
 t/t4034/python/expect                         |    34 +
 t/t4034/python/post                           |    17 +
 t/t4034/python/pre                            |    17 +
 t/t4034/ruby/expect                           |    34 +
 t/t4034/ruby/post                             |    17 +
 t/t4034/ruby/pre                              |    17 +
 t/t4034/scheme/expect                         |    11 +
 t/t4034/scheme/post                           |     6 +
 t/t4034/scheme/pre                            |     6 +
 t/t4034/tex/expect                            |     9 +
 t/t4034/tex/post                              |     4 +
 t/t4034/tex/pre                               |     4 +
 t/t4035-diff-quiet.sh                         |   164 +
 t/t4036-format-patch-signer-mime.sh           |    50 +
 t/t4037-diff-r-t-dirs.sh                      |    53 +
 t/t4038-diff-combined.sh                      |   546 +
 t/t4039-diff-assume-unchanged.sh              |    42 +
 t/t4040-whitespace-status.sh                  |    75 +
 t/t4041-diff-submodule-option.sh              |   557 +
 t/t4042-diff-textconv-caching.sh              |   144 +
 t/t4043-diff-rename-binary.sh                 |    45 +
 t/t4044-diff-index-unique-abbrev.sh           |    56 +
 t/t4045-diff-relative.sh                      |   248 +
 t/t4046-diff-unmerged.sh                      |   108 +
 t/t4047-diff-dirstat.sh                       |   992 +
 t/t4048-diff-combined-binary.sh               |   221 +
 t/t4049-diff-stat-count.sh                    |    69 +
 t/t4050-diff-histogram.sh                     |    12 +
 t/t4051-diff-function-context.sh              |   212 +
 t/t4051/appended1.c                           |    15 +
 t/t4051/appended2.c                           |    35 +
 t/t4051/dummy.c                               |     7 +
 t/t4051/hello.c                               |    24 +
 t/t4051/includes.c                            |    20 +
 t/t4052-stat-output.sh                        |   416 +
 t/t4053-diff-no-index.sh                      |   298 +
 t/t4054-diff-bogus-tree.sh                    |    83 +
 t/t4055-diff-context.sh                       |    92 +
 t/t4056-diff-order.sh                         |   200 +
 t/t4057-diff-combined-paths.sh                |   109 +
 t/t4058-diff-duplicates.sh                    |   191 +
 t/t4059-diff-submodule-not-initialized.sh     |   133 +
 t/t4060-diff-submodule-option-diff-format.sh  |   981 +
 t/t4061-diff-indent.sh                        |   371 +
 t/t4062-diff-pickaxe.sh                       |    29 +
 t/t4063-diff-blobs.sh                         |    97 +
 t/t4064-diff-oidfind.sh                       |   124 +
 t/t4065-diff-anchored.sh                      |    94 +
 t/t4066-diff-emit-delay.sh                    |    82 +
 t/t4067-diff-partial-clone.sh                 |   183 +
 t/t4068-diff-symmetric-merge-base.sh          |   203 +
 t/t4069-remerge-diff.sh                       |   362 +
 t/t4100-apply-stat.sh                         |    41 +
 t/t4100/t-apply-1.expect                      |    11 +
 t/t4100/t-apply-1.patch                       |   194 +
 t/t4100/t-apply-2.expect                      |     5 +
 t/t4100/t-apply-2.patch                       |    72 +
 t/t4100/t-apply-3.expect                      |     7 +
 t/t4100/t-apply-3.patch                       |   567 +
 t/t4100/t-apply-4.expect                      |     5 +
 t/t4100/t-apply-4.patch                       |     7 +
 t/t4100/t-apply-5.expect                      |    19 +
 t/t4100/t-apply-5.patch                       |   612 +
 t/t4100/t-apply-6.expect                      |     5 +
 t/t4100/t-apply-6.patch                       |   101 +
 t/t4100/t-apply-7.expect                      |     6 +
 t/t4100/t-apply-7.patch                       |   494 +
 t/t4100/t-apply-8.expect                      |     2 +
 t/t4100/t-apply-8.patch                       |    11 +
 t/t4100/t-apply-9.expect                      |     2 +
 t/t4100/t-apply-9.patch                       |    11 +
 t/t4101-apply-nonl.sh                         |    32 +
 t/t4101/diff.0-1                              |     6 +
 t/t4101/diff.0-2                              |     7 +
 t/t4101/diff.0-3                              |     8 +
 t/t4101/diff.1-0                              |     6 +
 t/t4101/diff.1-2                              |     8 +
 t/t4101/diff.1-3                              |     8 +
 t/t4101/diff.2-0                              |     7 +
 t/t4101/diff.2-1                              |     8 +
 t/t4101/diff.2-3                              |     7 +
 t/t4101/diff.3-0                              |     8 +
 t/t4101/diff.3-1                              |     8 +
 t/t4101/diff.3-2                              |     7 +
 t/t4102-apply-rename.sh                       |    58 +
 t/t4103-apply-binary.sh                       |   184 +
 t/t4104-apply-boundary.sh                     |   113 +
 t/t4105-apply-fuzz.sh                         |    52 +
 t/t4106-apply-stdin.sh                        |    30 +
 t/t4107-apply-ignore-whitespace.sh            |   194 +
 t/t4108-apply-threeway.sh                     |   336 +
 t/t4109-apply-multifrag.sh                    |    36 +
 t/t4109/expect-1                              |    31 +
 t/t4109/expect-2                              |    23 +
 t/t4109/expect-3                              |    24 +
 t/t4109/patch1.patch                          |    28 +
 t/t4109/patch2.patch                          |    30 +
 t/t4109/patch3.patch                          |    31 +
 t/t4109/patch4.patch                          |    30 +
 t/t4110-apply-scan.sh                         |    23 +
 t/t4110/expect                                |    20 +
 t/t4110/patch1.patch                          |    17 +
 t/t4110/patch2.patch                          |    11 +
 t/t4110/patch3.patch                          |    14 +
 t/t4110/patch4.patch                          |    11 +
 t/t4110/patch5.patch                          |    11 +
 t/t4111-apply-subdir.sh                       |   156 +
 t/t4112-apply-renames.sh                      |   145 +
 t/t4113-apply-ending.sh                       |    53 +
 t/t4114-apply-typechange.sh                   |   129 +
 t/t4115-apply-symlink.sh                      |   143 +
 t/t4116-apply-reverse.sh                      |    92 +
 t/t4117-apply-reject.sh                       |   107 +
 t/t4118-apply-empty-context.sh                |    52 +
 t/t4119-apply-config.sh                       |   180 +
 t/t4120-apply-popt.sh                         |    89 +
 t/t4121-apply-diffs.sh                        |    35 +
 t/t4122-apply-symlink-inside.sh               |   157 +
 t/t4123-apply-shrink.sh                       |    46 +
 t/t4124-apply-ws-rule.sh                      |   559 +
 t/t4125-apply-ws-fuzz.sh                      |   100 +
 t/t4126-apply-empty.sh                        |    92 +
 t/t4127-apply-same-fn.sh                      |    97 +
 t/t4128-apply-root.sh                         |   122 +
 t/t4129-apply-samemode.sh                     |   194 +
 t/t4130-apply-criss-cross-rename.sh           |    71 +
 t/t4131-apply-fake-ancestor.sh                |    42 +
 t/t4132-apply-removal.sh                      |    97 +
 t/t4133-apply-filenames.sh                    |    63 +
 t/t4134-apply-submodule.sh                    |    39 +
 t/t4135-apply-weird-filenames.sh              |   101 +
 t/t4135/.gitignore                            |     3 +
 t/t4135/add-plain.diff                        |     5 +
 t/t4135/add-with backslash.diff               |     5 +
 t/t4135/add-with quote.diff                   |     5 +
 t/t4135/add-with spaces.diff                  |     5 +
 t/t4135/add-with tab.diff                     |     5 +
 t/t4135/damaged-tz.diff                       |     5 +
 t/t4135/damaged.diff                          |     5 +
 t/t4135/diff-plain.diff                       |     5 +
 t/t4135/diff-with backslash.diff              |     5 +
 t/t4135/diff-with quote.diff                  |     5 +
 t/t4135/diff-with spaces.diff                 |     5 +
 t/t4135/diff-with tab.diff                    |     5 +
 t/t4135/funny-tz.diff                         |     5 +
 t/t4135/git-plain.diff                        |     7 +
 t/t4135/git-with backslash.diff               |     7 +
 t/t4135/git-with quote.diff                   |     7 +
 t/t4135/git-with spaces.diff                  |     7 +
 t/t4135/git-with tab.diff                     |     7 +
 t/t4135/make-patches                          |    45 +
 t/t4136-apply-check.sh                        |    63 +
 t/t4137-apply-submodule.sh                    |    24 +
 t/t4138-apply-ws-expansion.sh                 |   121 +
 t/t4139-apply-escape.sh                       |   142 +
 t/t4140-apply-ita.sh                          |    56 +
 t/t4141-apply-too-large.sh                    |    22 +
 t/t4150-am.sh                                 |  1282 +
 t/t4151-am-abort.sh                           |   227 +
 t/t4152-am-subjects.sh                        |    78 +
 t/t4153-am-resume-override-opts.sh            |   106 +
 t/t4200-rerere.sh                             |   737 +
 t/t4201-shortlog.sh                           |   437 +
 t/t4202-log.sh                                |  2393 ++
 t/t4203-mailmap.sh                            |  1124 +
 t/t4204-patch-id.sh                           |   347 +
 t/t4205-log-pretty-formats.sh                 |  1224 +
 t/t4206-log-follow-harder-copies.sh           |    57 +
 t/t4207-log-decoration-colors.sh              |   134 +
 t/t4208-log-magic-pathspec.sh                 |   145 +
 t/t4209-log-pickaxe.sh                        |   227 +
 t/t4210-log-i18n.sh                           |   141 +
 t/t4211-line-log.sh                           |   368 +
 t/t4211/history.export                        |   406 +
 t/t4211/sha1/expect.beginning-of-file         |    43 +
 t/t4211/sha1/expect.end-of-file               |    62 +
 t/t4211/sha1/expect.move-support-f            |    80 +
 t/t4211/sha1/expect.multiple                  |   104 +
 t/t4211/sha1/expect.multiple-overlapping      |   187 +
 t/t4211/sha1/expect.multiple-superset         |   187 +
 t/t4211/sha1/expect.parallel-change-f-to-main |   160 +
 t/t4211/sha1/expect.simple-f                  |    59 +
 t/t4211/sha1/expect.simple-f-to-main          |   100 +
 t/t4211/sha1/expect.simple-main               |    68 +
 t/t4211/sha1/expect.simple-main-to-end        |    70 +
 t/t4211/sha1/expect.two-ranges                |   102 +
 t/t4211/sha1/expect.vanishes-early            |    39 +
 t/t4211/sha256/expect.beginning-of-file       |    43 +
 t/t4211/sha256/expect.end-of-file             |    62 +
 t/t4211/sha256/expect.move-support-f          |    80 +
 t/t4211/sha256/expect.multiple                |   104 +
 t/t4211/sha256/expect.multiple-overlapping    |   187 +
 t/t4211/sha256/expect.multiple-superset       |   187 +
 .../sha256/expect.parallel-change-f-to-main   |   160 +
 t/t4211/sha256/expect.simple-f                |    59 +
 t/t4211/sha256/expect.simple-f-to-main        |   100 +
 t/t4211/sha256/expect.simple-main             |    68 +
 t/t4211/sha256/expect.simple-main-to-end      |    70 +
 t/t4211/sha256/expect.two-ranges              |   102 +
 t/t4211/sha256/expect.vanishes-early          |    39 +
 t/t4212-log-corrupt.sh                        |   135 +
 t/t4213-log-tabexpand.sh                      |   105 +
 t/t4214-log-graph-octopus.sh                  |   350 +
 t/t4215-log-skewed-merges.sh                  |   373 +
 t/t4216-log-bloom.sh                          |   776 +
 t/t4217-log-limit.sh                          |    41 +
 t/t4252-am-options.sh                         |    79 +
 t/t4252/am-test-1-1                           |    19 +
 t/t4252/am-test-1-2                           |    21 +
 t/t4252/am-test-2-1                           |    19 +
 t/t4252/am-test-2-2                           |    21 +
 t/t4252/am-test-3-1                           |    19 +
 t/t4252/am-test-3-2                           |    21 +
 t/t4252/am-test-4-1                           |    19 +
 t/t4252/am-test-4-2                           |    22 +
 t/t4252/am-test-5-1                           |    20 +
 t/t4252/am-test-5-2                           |    15 +
 t/t4252/am-test-6-1                           |    21 +
 t/t4252/file-1-0                              |     7 +
 t/t4252/file-2-0                              |     7 +
 t/t4253-am-keep-cr-dos.sh                     |   101 +
 t/t4254-am-corrupt.sh                         |    89 +
 t/t4255-am-submodule.sh                       |    97 +
 t/t4256-am-format-flowed.sh                   |    19 +
 t/t4256/1/mailinfo.c                          |  1245 +
 t/t4256/1/mailinfo.c.orig                     |  1185 +
 t/t4256/1/patch                               |   129 +
 t/t4257-am-interactive.sh                     |    53 +
 t/t4258-am-quoted-cr.sh                       |    37 +
 t/t4258/mbox                                  |    12 +
 t/t4300-merge-tree.sh                         |   381 +
 t/t4301-merge-tree-write-tree.sh              |   993 +
 t/t5000-tar-tree.sh                           |   555 +
 t/t5000/huge-and-future.tar                   |   Bin 0 -> 2048 bytes
 t/t5000/huge-object                           |   Bin 0 -> 2048 bytes
 t/t5000/pax.tar                               |   Bin 0 -> 10240 bytes
 t/t5001-archive-attr.sh                       |   165 +
 t/t5002-archive-attr-pattern.sh               |    87 +
 t/t5003-archive-zip.sh                        |   276 +
 t/t5003/infozip-symlinks.zip                  |   Bin 0 -> 328 bytes
 t/t5004-archive-corner-cases.sh               |   228 +
 t/t5004/big-pack.zip                          |   Bin 0 -> 7373 bytes
 t/t5004/empty-with-pax-header.tar             |   Bin 0 -> 10240 bytes
 t/t5004/empty.zip                             |   Bin 0 -> 62 bytes
 t/t5100-mailinfo.sh                           |   303 +
 t/t5100/.gitattributes                        |     4 +
 t/t5100/0001mboxrd                            |     4 +
 t/t5100/0002mboxrd                            |     5 +
 t/t5100/comment.expect                        |     5 +
 t/t5100/comment.in                            |     9 +
 t/t5100/embed-from.expect                     |     5 +
 t/t5100/embed-from.in                         |    13 +
 t/t5100/empty                                 |     0
 t/t5100/info-from.expect                      |     5 +
 t/t5100/info-from.in                          |     8 +
 t/t5100/info0001                              |     5 +
 t/t5100/info0002                              |     5 +
 t/t5100/info0003                              |     5 +
 t/t5100/info0004                              |     5 +
 t/t5100/info0005                              |     5 +
 t/t5100/info0006                              |     5 +
 t/t5100/info0007                              |     5 +
 t/t5100/info0008                              |     5 +
 t/t5100/info0009                              |     5 +
 t/t5100/info0010                              |     5 +
 t/t5100/info0011                              |     5 +
 t/t5100/info0012                              |     5 +
 t/t5100/info0012--message-id                  |     5 +
 t/t5100/info0013                              |     5 +
 t/t5100/info0014                              |     5 +
 t/t5100/info0014--scissors                    |     5 +
 t/t5100/info0015                              |     5 +
 t/t5100/info0015--no-inbody-headers           |     5 +
 t/t5100/info0016                              |     5 +
 t/t5100/info0016--no-inbody-headers           |     5 +
 t/t5100/info0017                              |     5 +
 t/t5100/info0018                              |     5 +
 t/t5100/info0018--no-inbody-headers           |     5 +
 t/t5100/msg0001                               |     2 +
 t/t5100/msg0002                               |    21 +
 t/t5100/msg0003                               |     9 +
 t/t5100/msg0004                               |     7 +
 t/t5100/msg0005                               |    13 +
 t/t5100/msg0006                               |     2 +
 t/t5100/msg0007                               |     2 +
 t/t5100/msg0008                               |     4 +
 t/t5100/msg0009                               |     2 +
 t/t5100/msg0010                               |     5 +
 t/t5100/msg0011                               |     2 +
 t/t5100/msg0012                               |     7 +
 t/t5100/msg0012--message-id                   |     8 +
 t/t5100/msg0013                               |     0
 t/t5100/msg0014                               |    18 +
 t/t5100/msg0014--scissors                     |     4 +
 t/t5100/msg0015                               |     0
 t/t5100/msg0015--no-inbody-headers            |     3 +
 t/t5100/msg0016                               |     2 +
 t/t5100/msg0016--no-inbody-headers            |     4 +
 t/t5100/msg0017                               |     2 +
 t/t5100/msg0018                               |     2 +
 t/t5100/msg0018--no-inbody-headers            |     8 +
 t/t5100/nul-b64.expect                        |   Bin 0 -> 1672 bytes
 t/t5100/nul-b64.in                            |    37 +
 t/t5100/nul-plain                             |   Bin 0 -> 91 bytes
 t/t5100/patch0001                             |    14 +
 t/t5100/patch0002                             |    14 +
 t/t5100/patch0003                             |    14 +
 t/t5100/patch0004                             |    93 +
 t/t5100/patch0005                             |    69 +
 t/t5100/patch0006                             |    14 +
 t/t5100/patch0007                             |     0
 t/t5100/patch0008                             |     0
 t/t5100/patch0009                             |    13 +
 t/t5100/patch0010                             |    20 +
 t/t5100/patch0011                             |    22 +
 t/t5100/patch0012                             |    30 +
 t/t5100/patch0012--message-id                 |    30 +
 t/t5100/patch0013                             |     0
 t/t5100/patch0014                             |    64 +
 t/t5100/patch0014--scissors                   |    64 +
 t/t5100/patch0015                             |     8 +
 t/t5100/patch0015--no-inbody-headers          |     8 +
 t/t5100/patch0016                             |     8 +
 t/t5100/patch0016--no-inbody-headers          |     8 +
 t/t5100/patch0017                             |     6 +
 t/t5100/patch0018                             |     6 +
 t/t5100/patch0018--no-inbody-headers          |     6 +
 t/t5100/quoted-cr-info                        |     5 +
 t/t5100/quoted-cr-msg                         |     2 +
 t/t5100/quoted-cr-patch                       |    22 +
 t/t5100/quoted-cr.mbox                        |    47 +
 t/t5100/quoted-from.expect                    |     3 +
 t/t5100/quoted-from.in                        |    10 +
 t/t5100/quoted-string.expect                  |     5 +
 t/t5100/quoted-string.in                      |     9 +
 t/t5100/rfc2047-info-0001                     |     4 +
 t/t5100/rfc2047-info-0002                     |     4 +
 t/t5100/rfc2047-info-0003                     |     4 +
 t/t5100/rfc2047-info-0004                     |     4 +
 t/t5100/rfc2047-info-0005                     |     2 +
 t/t5100/rfc2047-info-0006                     |     2 +
 t/t5100/rfc2047-info-0007                     |     2 +
 t/t5100/rfc2047-info-0008                     |     2 +
 t/t5100/rfc2047-info-0009                     |     2 +
 t/t5100/rfc2047-info-0010                     |     2 +
 t/t5100/rfc2047-info-0011                     |     2 +
 t/t5100/rfc2047-samples.mbox                  |    48 +
 t/t5100/sample.mbox                           |   720 +
 t/t5100/sample.mboxrd                         |    19 +
 t/t5150-request-pull.sh                       |   309 +
 t/t5200-update-server-info.sh                 |    49 +
 t/t5300-pack-object.sh                        |   692 +
 t/t5301-sliding-window.sh                     |    61 +
 t/t5302-pack-index.sh                         |   296 +
 t/t5303-pack-corruption-resilience.sh         |   409 +
 t/t5304-prune.sh                              |   367 +
 t/t5305-include-tag.sh                        |   121 +
 t/t5306-pack-nobase.sh                        |    77 +
 t/t5307-pack-missing-commit.sh                |    39 +
 t/t5308-pack-detect-duplicates.sh             |    82 +
 t/t5309-pack-delta-cycles.sh                  |    78 +
 t/t5310-pack-bitmaps.sh                       |   538 +
 t/t5311-pack-bitmaps-shallow.sh               |    57 +
 t/t5312-prune-corruption.sh                   |   113 +
 t/t5313-pack-bounds-checks.sh                 |   195 +
 t/t5314-pack-cycle-detection.sh               |   114 +
 t/t5315-pack-objects-compression.sh           |    38 +
 t/t5316-pack-delta-depth.sh                   |   120 +
 t/t5317-pack-objects-filter-objects.sh        |   481 +
 t/t5318-commit-graph.sh                       |   949 +
 t/t5319-multi-pack-index.sh                   |  1266 +
 t/t5319/no-objects.midx                       |   Bin 0 -> 1116 bytes
 t/t5320-delta-islands.sh                      |   144 +
 t/t5321-pack-large-objects.sh                 |    33 +
 t/t5322-pack-objects-sparse.sh                |   141 +
 t/t5323-pack-redundant.sh                     |   498 +
 t/t5324-split-commit-graph.sh                 |   744 +
 t/t5325-reverse-index.sh                      |   207 +
 t/t5326-multi-pack-bitmaps.sh                 |   585 +
 t/t5327-multi-pack-bitmaps-rev.sh             |    43 +
 t/t5328-commit-graph-64bit-time.sh            |    86 +
 t/t5329-pack-objects-cruft.sh                 |   948 +
 t/t5330-no-lazy-fetch-with-commit-graph.sh    |    47 +
 t/t5331-pack-objects-stdin.sh                 |   239 +
 t/t5332-multi-pack-reuse.sh                   |   283 +
 t/t5333-pseudo-merge-bitmaps.sh               |   449 +
 t/t5334-incremental-multi-pack-index.sh       |    47 +
 t/t5351-unpack-large-objects.sh               |   102 +
 t/t5400-send-pack.sh                          |   303 +
 t/t5401-update-hooks.sh                       |   142 +
 t/t5402-post-merge-hook.sh                    |    61 +
 t/t5403-post-checkout-hook.sh                 |   115 +
 t/t5404-tracking-branches.sh                  |    65 +
 t/t5405-send-pack-rewind.sh                   |    45 +
 t/t5406-remote-rejects.sh                     |    24 +
 t/t5407-post-rewrite-hook.sh                  |   313 +
 t/t5408-send-pack-stdin.sh                    |    93 +
 t/t5409-colorize-remote-messages.sh           |   101 +
 t/t5410-receive-pack-alternates.sh            |    44 +
 t/t5411-proc-receive-hook.sh                  |   120 +
 t/t5411/common-functions.sh                   |    73 +
 t/t5411/once-0010-report-status-v1.sh         |    91 +
 t/t5411/test-0000-standard-git-push.sh        |   134 +
 .../test-0001-standard-git-push--porcelain.sh |   138 +
 t/t5411/test-0002-pre-receive-declined.sh     |    31 +
 ...st-0003-pre-receive-declined--porcelain.sh |    32 +
 t/t5411/test-0010-proc-receive-settings.sh    |     7 +
 t/t5411/test-0011-no-hook-error.sh            |    60 +
 t/t5411/test-0012-no-hook-error--porcelain.sh |    62 +
 t/t5411/test-0013-bad-protocol.sh             |   302 +
 t/t5411/test-0014-bad-protocol--porcelain.sh  |   304 +
 t/t5411/test-0020-report-ng.sh                |    63 +
 t/t5411/test-0021-report-ng--porcelain.sh     |    65 +
 t/t5411/test-0022-report-unexpect-ref.sh      |    43 +
 ...est-0023-report-unexpect-ref--porcelain.sh |    44 +
 t/t5411/test-0024-report-unknown-ref.sh       |    32 +
 ...test-0025-report-unknown-ref--porcelain.sh |    33 +
 t/t5411/test-0026-push-options.sh             |   133 +
 t/t5411/test-0027-push-options--porcelain.sh  |   138 +
 t/t5411/test-0030-report-ok.sh                |    33 +
 t/t5411/test-0031-report-ok--porcelain.sh     |    34 +
 t/t5411/test-0032-report-with-options.sh      |   253 +
 ...est-0033-report-with-options--porcelain.sh |   262 +
 t/t5411/test-0034-report-ft.sh                |    42 +
 t/t5411/test-0035-report-ft--porcelain.sh     |    43 +
 ...t-0036-report-multi-rewrite-for-one-ref.sh |   221 +
 ...rt-multi-rewrite-for-one-ref--porcelain.sh |   166 +
 t/t5411/test-0038-report-mixed-refs.sh        |    87 +
 .../test-0039-report-mixed-refs--porcelain.sh |    89 +
 t/t5411/test-0040-process-all-refs.sh         |   111 +
 .../test-0041-process-all-refs--porcelain.sh  |   112 +
 ...t-0050-proc-receive-refs-with-modifiers.sh |   129 +
 t/t5500-fetch-pack.sh                         |  1092 +
 t/t5501-fetch-push-alternates.sh              |    69 +
 t/t5502-quickfetch.sh                         |   145 +
 t/t5503-tagfollow.sh                          |   163 +
 t/t5504-fetch-receive-strict.sh               |   382 +
 t/t5505-remote.sh                             |  1637 +
 t/t5506-remote-groups.sh                      |   110 +
 t/t5507-remote-environment.sh                 |    35 +
 t/t5509-fetch-push-namespaces.sh              |   178 +
 t/t5510-fetch.sh                              |  1489 +
 t/t5511-refspec.sh                            |    96 +
 t/t5512-ls-remote.sh                          |   421 +
 t/t5513-fetch-track.sh                        |    30 +
 t/t5514-fetch-multiple.sh                     |   386 +
 t/t5515-fetch-merge-logic.sh                  |   229 +
 t/t5515/fetch.br-branches-default             |     8 +
 t/t5515/fetch.br-branches-default-merge       |     9 +
 ...br-branches-default-merge_branches-default |     9 +
 t/t5515/fetch.br-branches-default-octopus     |    10 +
 ...-branches-default-octopus_branches-default |    10 +
 ...fetch.br-branches-default_branches-default |     8 +
 t/t5515/fetch.br-branches-one                 |     8 +
 t/t5515/fetch.br-branches-one-merge           |     9 +
 .../fetch.br-branches-one-merge_branches-one  |     9 +
 t/t5515/fetch.br-branches-one-octopus         |     9 +
 ...fetch.br-branches-one-octopus_branches-one |     9 +
 t/t5515/fetch.br-branches-one_branches-one    |     8 +
 t/t5515/fetch.br-config-explicit              |    11 +
 t/t5515/fetch.br-config-explicit-merge        |    11 +
 ...h.br-config-explicit-merge_config-explicit |    11 +
 t/t5515/fetch.br-config-explicit-octopus      |    11 +
 ...br-config-explicit-octopus_config-explicit |    11 +
 .../fetch.br-config-explicit_config-explicit  |    11 +
 t/t5515/fetch.br-config-glob                  |    11 +
 t/t5515/fetch.br-config-glob-merge            |    11 +
 .../fetch.br-config-glob-merge_config-glob    |    11 +
 t/t5515/fetch.br-config-glob-octopus          |    11 +
 .../fetch.br-config-glob-octopus_config-glob  |    11 +
 t/t5515/fetch.br-config-glob_config-glob      |    11 +
 t/t5515/fetch.br-remote-explicit              |    11 +
 t/t5515/fetch.br-remote-explicit-merge        |    11 +
 ...h.br-remote-explicit-merge_remote-explicit |    11 +
 t/t5515/fetch.br-remote-explicit-octopus      |    11 +
 ...br-remote-explicit-octopus_remote-explicit |    11 +
 .../fetch.br-remote-explicit_remote-explicit  |    11 +
 t/t5515/fetch.br-remote-glob                  |    11 +
 t/t5515/fetch.br-remote-glob-merge            |    11 +
 .../fetch.br-remote-glob-merge_remote-glob    |    11 +
 t/t5515/fetch.br-remote-glob-octopus          |    11 +
 .../fetch.br-remote-glob-octopus_remote-glob  |    11 +
 t/t5515/fetch.br-remote-glob_remote-glob      |    11 +
 t/t5515/fetch.br-unconfig                     |    11 +
 t/t5515/fetch.br-unconfig_--tags_.._.git      |     8 +
 t/t5515/fetch.br-unconfig_.._.git             |     2 +
 t/t5515/fetch.br-unconfig_.._.git_one         |     2 +
 ....._.git_one_tag_tag-one_tag_tag-three-file |     8 +
 t/t5515/fetch.br-unconfig_.._.git_one_two     |     3 +
 ...._.git_tag_tag-one-tree_tag_tag-three-file |     7 +
 ...unconfig_.._.git_tag_tag-one_tag_tag-three |     7 +
 t/t5515/fetch.br-unconfig_branches-default    |     8 +
 t/t5515/fetch.br-unconfig_branches-one        |     8 +
 t/t5515/fetch.br-unconfig_config-explicit     |    11 +
 t/t5515/fetch.br-unconfig_config-glob         |    11 +
 t/t5515/fetch.br-unconfig_remote-explicit     |    11 +
 t/t5515/fetch.br-unconfig_remote-glob         |    11 +
 t/t5515/fetch.main                            |    11 +
 t/t5515/fetch.main_--tags_.._.git             |     8 +
 t/t5515/fetch.main_.._.git                    |     2 +
 t/t5515/fetch.main_.._.git_one                |     2 +
 ....._.git_one_tag_tag-one_tag_tag-three-file |     8 +
 t/t5515/fetch.main_.._.git_one_two            |     3 +
 ...._.git_tag_tag-one-tree_tag_tag-three-file |     7 +
 ...tch.main_.._.git_tag_tag-one_tag_tag-three |     7 +
 t/t5515/fetch.main_branches-default           |     8 +
 t/t5515/fetch.main_branches-one               |     8 +
 t/t5515/fetch.main_config-explicit            |    11 +
 t/t5515/fetch.main_config-glob                |    11 +
 t/t5515/fetch.main_remote-explicit            |    11 +
 t/t5515/fetch.main_remote-glob                |    11 +
 t/t5515/refs.br-branches-default              |    12 +
 t/t5515/refs.br-branches-default-merge        |    12 +
 ...br-branches-default-merge_branches-default |    12 +
 t/t5515/refs.br-branches-default-octopus      |    12 +
 ...-branches-default-octopus_branches-default |    12 +
 .../refs.br-branches-default_branches-default |    12 +
 t/t5515/refs.br-branches-one                  |    12 +
 t/t5515/refs.br-branches-one-merge            |    12 +
 .../refs.br-branches-one-merge_branches-one   |    12 +
 t/t5515/refs.br-branches-one-octopus          |    12 +
 .../refs.br-branches-one-octopus_branches-one |    12 +
 t/t5515/refs.br-branches-one_branches-one     |    12 +
 t/t5515/refs.br-config-explicit               |    15 +
 t/t5515/refs.br-config-explicit-merge         |    15 +
 ...s.br-config-explicit-merge_config-explicit |    15 +
 t/t5515/refs.br-config-explicit-octopus       |    15 +
 ...br-config-explicit-octopus_config-explicit |    15 +
 .../refs.br-config-explicit_config-explicit   |    15 +
 t/t5515/refs.br-config-glob                   |    15 +
 t/t5515/refs.br-config-glob-merge             |    15 +
 t/t5515/refs.br-config-glob-merge_config-glob |    15 +
 t/t5515/refs.br-config-glob-octopus           |    15 +
 .../refs.br-config-glob-octopus_config-glob   |    15 +
 t/t5515/refs.br-config-glob_config-glob       |    15 +
 t/t5515/refs.br-remote-explicit               |    15 +
 t/t5515/refs.br-remote-explicit-merge         |    15 +
 ...s.br-remote-explicit-merge_remote-explicit |    15 +
 t/t5515/refs.br-remote-explicit-octopus       |    15 +
 ...br-remote-explicit-octopus_remote-explicit |    15 +
 .../refs.br-remote-explicit_remote-explicit   |    15 +
 t/t5515/refs.br-remote-glob                   |    15 +
 t/t5515/refs.br-remote-glob-merge             |    15 +
 t/t5515/refs.br-remote-glob-merge_remote-glob |    15 +
 t/t5515/refs.br-remote-glob-octopus           |    15 +
 .../refs.br-remote-glob-octopus_remote-glob   |    15 +
 t/t5515/refs.br-remote-glob_remote-glob       |    15 +
 t/t5515/refs.br-unconfig                      |    11 +
 t/t5515/refs.br-unconfig_--tags_.._.git       |    11 +
 t/t5515/refs.br-unconfig_.._.git              |     5 +
 t/t5515/refs.br-unconfig_.._.git_one          |     5 +
 ....._.git_one_tag_tag-one_tag_tag-three-file |    11 +
 t/t5515/refs.br-unconfig_.._.git_one_two      |     5 +
 ...._.git_tag_tag-one-tree_tag_tag-three-file |    11 +
 ...unconfig_.._.git_tag_tag-one_tag_tag-three |    11 +
 t/t5515/refs.br-unconfig_branches-default     |    12 +
 t/t5515/refs.br-unconfig_branches-one         |    12 +
 t/t5515/refs.br-unconfig_config-explicit      |    15 +
 t/t5515/refs.br-unconfig_config-glob          |    15 +
 t/t5515/refs.br-unconfig_remote-explicit      |    15 +
 t/t5515/refs.br-unconfig_remote-glob          |    15 +
 t/t5515/refs.main                             |    11 +
 t/t5515/refs.main_--tags_.._.git              |    11 +
 t/t5515/refs.main_.._.git                     |     5 +
 t/t5515/refs.main_.._.git_one                 |     5 +
 ....._.git_one_tag_tag-one_tag_tag-three-file |    11 +
 t/t5515/refs.main_.._.git_one_two             |     5 +
 ...._.git_tag_tag-one-tree_tag_tag-three-file |    11 +
 ...efs.main_.._.git_tag_tag-one_tag_tag-three |    11 +
 t/t5515/refs.main_branches-default            |    12 +
 t/t5515/refs.main_branches-one                |    12 +
 t/t5515/refs.main_config-explicit             |    15 +
 t/t5515/refs.main_config-glob                 |    15 +
 t/t5515/refs.main_remote-explicit             |    15 +
 t/t5515/refs.main_remote-glob                 |    15 +
 t/t5516-fetch-push.sh                         |  1912 +
 t/t5517-push-mirror.sh                        |   281 +
 t/t5518-fetch-exit-status.sh                  |    40 +
 t/t5519-push-alternates.sh                    |   146 +
 t/t5520-pull.sh                               |   831 +
 t/t5521-pull-options.sh                       |   255 +
 t/t5522-pull-symlink.sh                       |    86 +
 t/t5523-push-upstream.sh                      |   137 +
 t/t5524-pull-msg.sh                           |    52 +
 t/t5525-fetch-tagopt.sh                       |    54 +
 t/t5526-fetch-submodules.sh                   |  1196 +
 t/t5527-fetch-odd-refs.sh                     |    66 +
 t/t5528-push-default.sh                       |   297 +
 t/t5529-push-errors.sh                        |    66 +
 t/t5530-upload-pack-error.sh                  |   122 +
 t/t5531-deep-submodule-push.sh                |   640 +
 t/t5532-fetch-proxy.sh                        |    52 +
 t/t5533-push-cas.sh                           |   399 +
 t/t5534-push-signed.sh                        |   392 +
 t/t5535-fetch-push-symref.sh                  |    42 +
 t/t5536-fetch-conflicts.sh                    |    86 +
 t/t5537-fetch-shallow.sh                      |   299 +
 t/t5538-push-shallow.sh                       |   126 +
 t/t5539-fetch-http-shallow.sh                 |   157 +
 t/t5540-http-push-webdav.sh                   |   204 +
 t/t5541-http-push-smart.sh                    |   506 +
 t/t5542-push-http-shallow.sh                  |    96 +
 t/t5543-atomic-push.sh                        |   283 +
 t/t5544-pack-objects-hook.sh                  |    78 +
 t/t5545-push-options.sh                       |   291 +
 t/t5546-receive-limits.sh                     |    85 +
 t/t5547-push-quarantine.sh                    |    73 +
 t/t5548-push-porcelain.sh                     |   278 +
 t/t5549-fetch-push-http.sh                    |    72 +
 t/t5550-http-fetch-dumb.sh                    |   533 +
 t/t5551-http-fetch-smart.sh                   |   775 +
 t/t5552-skipping-fetch-negotiator.sh          |   226 +
 t/t5553-set-upstream.sh                       |   203 +
 t/t5554-noop-fetch-negotiator.sh              |    23 +
 t/t5555-http-smart-common.sh                  |   160 +
 t/t5557-http-get.sh                           |    38 +
 t/t5558-clone-bundle-uri.sh                   |  1255 +
 t/t5559-http-fetch-smart-http2.sh             |     5 +
 t/t5560-http-backend-noserver.sh              |    77 +
 t/t5561-http-backend.sh                       |   138 +
 t/t5562-http-backend-content-length.sh        |   174 +
 t/t5562/invoke-with-content-length.pl         |    36 +
 t/t5563-simple-http-auth.sh                   |   677 +
 t/t5564-http-proxy.sh                         |    96 +
 t/t556x_common                                |   110 +
 t/t5570-git-daemon.sh                         |   235 +
 t/t5571-pre-push-hook.sh                      |   141 +
 t/t5572-pull-submodule.sh                     |   268 +
 t/t5573-pull-verify-signatures.sh             |   153 +
 t/t5574-fetch-output.sh                       |   304 +
 t/t5580-unc-paths.sh                          |    92 +
 t/t5581-http-curl-verbose.sh                  |    29 +
 t/t5582-fetch-negative-refspec.sh             |   289 +
 t/t5583-push-branches.sh                      |   115 +
 t/t5600-clone-fail-cleanup.sh                 |   109 +
 t/t5601-clone.sh                              |   945 +
 t/t5602-clone-remote-exec.sh                  |    27 +
 t/t5603-clone-dirname.sh                      |   109 +
 t/t5604-clone-reference.sh                    |   363 +
 t/t5605-clone-local.sh                        |   179 +
 t/t5606-clone-options.sh                      |   200 +
 t/t5607-clone-bundle.sh                       |   214 +
 t/t5608-clone-2gb.sh                          |    52 +
 t/t5609-clone-branch.sh                       |    73 +
 t/t5610-clone-detached.sh                     |    79 +
 t/t5611-clone-config.sh                       |   136 +
 t/t5612-clone-refspec.sh                      |   238 +
 t/t5613-info-alternate.sh                     |   140 +
 t/t5614-clone-submodules-shallow.sh           |   130 +
 t/t5615-alternate-env.sh                      |    91 +
 t/t5616-partial-clone.sh                      |   909 +
 t/t5617-clone-submodules-remote.sh            |   110 +
 t/t5618-alternate-refs.sh                     |    61 +
 t/t5619-clone-local-ambiguous-transport.sh    |    70 +
 t/t5700-protocol-v1.sh                        |   344 +
 t/t5701-git-serve.sh                          |   404 +
 t/t5702-protocol-v2.sh                        |  1483 +
 t/t5703-upload-pack-ref-in-want.sh            |   539 +
 t/t5704-protocol-violations.sh                |    51 +
 t/t5705-session-id-in-capabilities.sh         |    87 +
 t/t5730-protocol-v2-bundle-uri-file.sh        |    17 +
 t/t5731-protocol-v2-bundle-uri-git.sh         |    17 +
 t/t5732-protocol-v2-bundle-uri-http.sh        |    17 +
 t/t5750-bundle-uri-parse.sh                   |   289 +
 t/t5801-remote-helpers.sh                     |   358 +
 t/t5801/git-remote-nourl                      |     3 +
 t/t5801/git-remote-testgit                    |   165 +
 t/t5802-connect-helper.sh                     |   102 +
 t/t5810-proto-disable-local.sh                |    38 +
 t/t5811-proto-disable-git.sh                  |    21 +
 t/t5812-proto-disable-http.sh                 |    38 +
 t/t5813-proto-disable-ssh.sh                  |    44 +
 t/t5814-proto-disable-ext.sh                  |    19 +
 t/t5815-submodule-protos.sh                   |    44 +
 t/t5900-repo-selection.sh                     |   101 +
 t/t6000-rev-list-misc.sh                      |   185 +
 t/t6001-rev-list-graft.sh                     |   127 +
 t/t6002-rev-list-bisect.sh                    |   316 +
 t/t6003-rev-list-topo-order.sh                |   444 +
 t/t6004-rev-list-path-optim.sh                |    99 +
 t/t6005-rev-list-count.sh                     |    65 +
 t/t6006-rev-list-format.sh                    |   629 +
 t/t6007-rev-list-cherry-pick-file.sh          |   284 +
 t/t6008-rev-list-submodule.sh                 |    45 +
 t/t6009-rev-list-parent.sh                    |   163 +
 t/t6010-merge-base.sh                         |   308 +
 t/t6011-rev-list-with-bad-commit.sh           |    59 +
 t/t6012-rev-list-simplify.sh                  |   288 +
 t/t6013-rev-list-reverse-parents.sh           |    45 +
 t/t6014-rev-list-all.sh                       |    42 +
 t/t6016-rev-list-graph-simplify-history.sh    |   246 +
 t/t6017-rev-list-stdin.sh                     |   151 +
 t/t6018-rev-list-glob.sh                      |   426 +
 t/t6019-rev-list-ancestry-path.sh             |   132 +
 t/t6020-bundle-misc.sh                        |   730 +
 t/t6021-rev-list-exclude-hidden.sh            |   163 +
 t/t6022-rev-list-missing.sh                   |   148 +
 t/t6030-bisect-porcelain.sh                   |  1262 +
 t/t6040-tracking-info.sh                      |   295 +
 t/t6041-bisect-submodule.sh                   |    37 +
 t/t6050-replace.sh                            |   549 +
 t/t6060-merge-index.sh                        |    98 +
 t/t6100-rev-list-in-order.sh                  |    77 +
 t/t6101-rev-parse-parents.sh                  |   230 +
 t/t6102-rev-list-unexpected-objects.sh        |   132 +
 t/t6110-rev-list-sparse.sh                    |    23 +
 t/t6111-rev-list-treesame.sh                  |   197 +
 t/t6112-rev-list-filters-objects.sh           |   716 +
 t/t6113-rev-list-bitmap-filters.sh            |   159 +
 t/t6114-keep-packs.sh                         |    70 +
 t/t6115-rev-list-du.sh                        |    81 +
 t/t6120-describe.sh                           |   752 +
 t/t6130-pathspec-noglob.sh                    |   161 +
 t/t6131-pathspec-icase.sh                     |   110 +
 t/t6132-pathspec-exclude.sh                   |   428 +
 t/t6133-pathspec-rev-dwim.sh                  |    49 +
 t/t6134-pathspec-in-submodule.sh              |    32 +
 t/t6135-pathspec-with-attrs.sh                |   424 +
 t/t6136-pathspec-in-bare.sh                   |    38 +
 t/t6200-fmt-merge-msg.sh                      |   704 +
 t/t6300-for-each-ref.sh                       |  2143 ++
 t/t6301-for-each-ref-errors.sh                |    69 +
 t/t6302-for-each-ref-filter.sh                |   544 +
 t/t6400-merge-df.sh                           |   163 +
 t/t6401-merge-criss-cross.sh                  |    68 +
 t/t6402-merge-rename.sh                       |   973 +
 t/t6403-merge-file.sh                         |   571 +
 t/t6404-recursive-merge.sh                    |   152 +
 t/t6405-merge-symlinks.sh                     |    65 +
 t/t6406-merge-attr.sh                         |   311 +
 t/t6407-merge-binary.sh                       |    60 +
 t/t6408-merge-up-to-date.sh                   |    92 +
 t/t6409-merge-subtree.sh                      |   155 +
 t/t6411-merge-filemode.sh                     |   103 +
 t/t6412-merge-large-rename.sh                 |   106 +
 t/t6413-merge-crlf.sh                         |    47 +
 t/t6414-merge-rename-nocruft.sh               |   100 +
 t/t6415-merge-dir-to-symlink.sh               |   177 +
 t/t6416-recursive-corner-cases.sh             |  1885 +
 t/t6417-merge-ours-theirs.sh                  |   108 +
 t/t6418-merge-text-auto.sh                    |   233 +
 t/t6419-merge-ignorecase.sh                   |    56 +
 t/t6421-merge-partial-clone.sh                |   443 +
 t/t6422-merge-rename-corner-cases.sh          |  1465 +
 t/t6423-merge-rename-directories.sh           |  5835 +++
 t/t6424-merge-unrelated-index-changes.sh      |   310 +
 t/t6425-merge-rename-delete.sh                |    27 +
 t/t6426-merge-skip-unneeded-updates.sh        |   767 +
 t/t6427-diff3-conflict-markers.sh             |   304 +
 t/t6428-merge-conflicts-sparse.sh             |   145 +
 t/t6429-merge-sequence-rename-caching.sh      |   772 +
 t/t6430-merge-recursive.sh                    |   776 +
 t/t6431-merge-criscross.sh                    |    95 +
 t/t6432-merge-recursive-space-options.sh      |   210 +
 t/t6433-merge-toplevel.sh                     |   177 +
 t/t6434-merge-recursive-rename-options.sh     |   333 +
 t/t6435-merge-sparse.sh                       |    60 +
 t/t6436-merge-overwrite.sh                    |   207 +
 t/t6437-submodule-merge.sh                    |   545 +
 t/t6438-submodule-directory-file-conflicts.sh |    22 +
 t/t6439-merge-co-error-msgs.sh                |   142 +
 t/t6500-gc.sh                                 |   440 +
 t/t6501-freshen-objects.sh                    |   183 +
 t/t6600-test-reach.sh                         |   765 +
 t/t6601-path-walk.sh                          |   368 +
 t/t6700-tree-depth.sh                         |    94 +
 t/t7001-mv.sh                                 |   565 +
 t/t7002-mv-sparse-checkout.sh                 |   517 +
 t/t7003-filter-branch.sh                      |   540 +
 t/t7004-tag.sh                                |  2335 ++
 t/t7005-editor.sh                             |   131 +
 t/t7006-pager.sh                              |   761 +
 t/t7007-show.sh                               |   170 +
 t/t7008-filter-branch-null-sha1.sh            |    56 +
 t/t7010-setup.sh                              |   161 +
 t/t7011-skip-worktree-reading.sh              |   147 +
 t/t7012-skip-worktree-writing.sh              |   198 +
 t/t7030-verify-tag.sh                         |   206 +
 t/t7031-verify-tag-signed-ssh.sh              |   213 +
 t/t7060-wtstatus.sh                           |   254 +
 t/t7061-wtstatus-ignore.sh                    |   316 +
 t/t7062-wtstatus-ignorecase.sh                |    20 +
 t/t7063-status-untracked-cache.sh             |   994 +
 t/t7064-wtstatus-pv2.sh                       |   673 +
 t/t7101-reset-empty-subdirs.sh                |    65 +
 t/t7102-reset.sh                              |   637 +
 t/t7103-reset-bare.sh                         |    73 +
 t/t7104-reset-hard.sh                         |    46 +
 t/t7105-reset-patch.sh                        |    97 +
 t/t7106-reset-unborn-branch.sh                |    68 +
 t/t7107-reset-pathspec-file.sh                |   178 +
 t/t7110-reset-merge.sh                        |   295 +
 t/t7111-reset-table.sh                        |   121 +
 t/t7112-reset-submodule.sh                    |    20 +
 t/t7113-post-index-change-hook.sh             |   146 +
 t/t7201-co.sh                                 |   804 +
 t/t7300-clean.sh                              |   803 +
 t/t7301-clean-interactive.sh                  |   485 +
 t/t7400-submodule-basic.sh                    |  1485 +
 t/t7401-submodule-summary.sh                  |   315 +
 t/t7402-submodule-rebase.sh                   |   134 +
 t/t7403-submodule-sync.sh                     |   355 +
 t/t7406-submodule-update.sh                   |  1253 +
 t/t7407-submodule-foreach.sh                  |   440 +
 t/t7408-submodule-reference.sh                |   228 +
 t/t7409-submodule-detached-work-tree.sh       |    91 +
 t/t7411-submodule-config.sh                   |   261 +
 t/t7412-submodule-absorbgitdirs.sh            |   183 +
 t/t7413-submodule-is-active.sh                |   127 +
 t/t7414-submodule-mistakes.sh                 |    39 +
 t/t7416-submodule-dash-url.sh                 |   224 +
 t/t7417-submodule-path-url.sh                 |    52 +
 t/t7418-submodule-sparse-gitmodules.sh        |   130 +
 t/t7419-submodule-set-branch.sh               |   130 +
 t/t7420-submodule-set-url.sh                  |    81 +
 t/t7421-submodule-summary-add.sh              |    73 +
 t/t7422-submodule-output.sh                   |   176 +
 t/t7423-submodule-symlinks.sh                 |    67 +
 t/t7424-submodule-mixed-ref-formats.sh        |   143 +
 t/t7450-bad-git-dotfiles.sh                   |   375 +
 t/t7500-commit-template-squash-signoff.sh     |   561 +
 t/t7500/add-comments                          |     4 +
 t/t7500/add-content                           |     3 +
 t/t7500/add-content-and-comment               |     5 +
 t/t7500/add-signed-off                        |     3 +
 t/t7500/add-whitespaced-content               |     8 +
 t/t7500/edit-content                          |     4 +
 t/t7501-commit-basic-functionality.sh         |   796 +
 t/t7502-commit-porcelain.sh                   |   985 +
 ...3-pre-commit-and-pre-merge-commit-hooks.sh |   282 +
 t/t7504-commit-msg-hook.sh                    |   310 +
 t/t7505-prepare-commit-msg-hook.sh            |   311 +
 t/t7505/expected-rebase-i                     |    18 +
 t/t7505/expected-rebase-p                     |    18 +
 t/t7506-status-submodule.sh                   |   414 +
 t/t7507-commit-verbose.sh                     |   169 +
 t/t7508-status.sh                             |  1777 +
 t/t7509-commit-authorship.sh                  |   174 +
 t/t7510-signed-commit.sh                      |   448 +
 t/t7511-status-index.sh                       |    50 +
 t/t7512-status-help.sh                        |  1064 +
 t/t7513-interpret-trailers.sh                 |  1992 ++
 t/t7514-commit-patch.sh                       |    29 +
 t/t7515-status-symlinks.sh                    |    43 +
 t/t7516-commit-races.sh                       |    32 +
 t/t7517-per-repo-email.sh                     |   152 +
 t/t7518-ident-corner-cases.sh                 |    57 +
 t/t7519-status-fsmonitor.sh                   |   480 +
 t/t7519/fsmonitor-all                         |    23 +
 t/t7519/fsmonitor-all-v2                      |    21 +
 t/t7519/fsmonitor-env                         |    24 +
 t/t7519/fsmonitor-none                        |    22 +
 t/t7519/fsmonitor-watchman                    |   127 +
 t/t7519/fsmonitor-watchman-v2                 |   173 +
 t/t7520-ignored-hook-warning.sh               |    38 +
 t/t7521-ignored-mode.sh                       |   233 +
 t/t7524-commit-summary.sh                     |    32 +
 t/t7525-status-rename.sh                      |   113 +
 t/t7526-commit-pathspec-file.sh               |   164 +
 t/t7527-builtin-fsmonitor.sh                  |  1314 +
 t/t7528-signed-commit-ssh.sh                  |   462 +
 t/t7600-merge.sh                              |  1096 +
 t/t7601-merge-pull-config.sh                  |   525 +
 t/t7602-merge-octopus-many.sh                 |   107 +
 t/t7603-merge-reduce-heads.sh                 |   164 +
 t/t7604-merge-custom-message.sh               |   115 +
 t/t7605-merge-resolve.sh                      |    52 +
 t/t7606-merge-custom.sh                       |    93 +
 t/t7607-merge-state.sh                        |    32 +
 t/t7608-merge-messages.sh                     |    63 +
 t/t7609-mergetool--lib.sh                     |    14 +
 t/t7610-mergetool.sh                          |   909 +
 t/t7611-merge-abort.sh                        |   204 +
 t/t7612-merge-verify-signatures.sh            |   138 +
 t/t7614-merge-signoff.sh                      |    72 +
 t/t7615-diff-algo-with-mergy-operations.sh    |    59 +
 t/t7615/base.c                                |    17 +
 t/t7615/ours.c                                |    17 +
 t/t7615/theirs.c                              |    17 +
 t/t7700-repack.sh                             |   829 +
 t/t7701-repack-unpack-unreachable.sh          |   198 +
 t/t7702-repack-cyclic-alternate.sh            |    25 +
 t/t7703-repack-geometric.sh                   |   448 +
 t/t7704-repack-cruft.sh                       |   414 +
 t/t7800-difftool.sh                           |   933 +
 t/t7810-grep.sh                               |  1932 +
 t/t7811-grep-open.sh                          |   158 +
 t/t7812-grep-icase-non-ascii.sh               |   152 +
 t/t7813-grep-icase-iso.sh                     |    19 +
 t/t7814-grep-recurse-submodules.sh            |   637 +
 t/t7815-grep-binary.sh                        |   148 +
 t/t7816-grep-binary-pattern.sh                |   127 +
 t/t7817-grep-sparse-checkout.sh               |   181 +
 t/t7900-maintenance.sh                        |  1027 +
 t/t8001-annotate.sh                           |    20 +
 t/t8002-blame.sh                              |   170 +
 t/t8003-blame-corner-cases.sh                 |   319 +
 t/t8004-blame-with-conflicts.sh               |    76 +
 t/t8005-blame-i18n.sh                         |   103 +
 t/t8005/euc-japan.txt                         |     2 +
 t/t8005/sjis.txt                              |     2 +
 t/t8005/utf8.txt                              |     2 +
 t/t8006-blame-textconv.sh                     |   158 +
 t/t8007-cat-file-textconv.sh                  |   129 +
 t/t8008-blame-formats.sh                      |   110 +
 t/t8009-blame-vs-topicbranches.sh             |    37 +
 t/t8010-cat-file-filters.sh                   |    70 +
 t/t8011-blame-split-file.sh                   |   118 +
 t/t8012-blame-colors.sh                       |    52 +
 t/t8013-blame-ignore-revs.sh                  |   292 +
 t/t8014-blame-ignore-fuzzy.sh                 |   438 +
 t/t9001-send-email.sh                         |  2838 ++
 t/t9002-column.sh                             |   209 +
 t/t9003-help-autocorrect.sh                   |    70 +
 t/t9100-git-svn-basic.sh                      |   333 +
 t/t9101-git-svn-props.sh                      |   236 +
 t/t9102-git-svn-deep-rmdir.sh                 |    32 +
 t/t9103-git-svn-tracked-directory-removed.sh  |    41 +
 t/t9104-git-svn-follow-parent.sh              |   230 +
 t/t9105-git-svn-commit-diff.sh                |    44 +
 t/t9106-git-svn-commit-diff-clobber.sh        |   107 +
 t/t9107-git-svn-migrate.sh                    |   136 +
 t/t9108-git-svn-glob.sh                       |   116 +
 t/t9109-git-svn-multi-glob.sh                 |   167 +
 t/t9110-git-svn-use-svm-props.sh              |    61 +
 t/t9110/svm.dump                              |   511 +
 t/t9111-git-svn-use-svnsync-props.sh          |    51 +
 t/t9111/svnsync.dump                          |   560 +
 t/t9112-git-svn-md5less-file.sh               |    47 +
 t/t9113-git-svn-dcommit-new-file.sh           |    35 +
 t/t9114-git-svn-dcommit-merge.sh              |    95 +
 t/t9115-git-svn-dcommit-funky-renames.sh      |   123 +
 t/t9115/funky-names.dump                      |   103 +
 t/t9116-git-svn-log.sh                        |   150 +
 t/t9117-git-svn-init-clone.sh                 |   122 +
 t/t9118-git-svn-funky-branch-names.sh         |    90 +
 t/t9119-git-svn-info.sh                       |   391 +
 t/t9120-git-svn-clone-with-percent-escapes.sh |    77 +
 t/t9121-git-svn-fetch-renamed-dir.sh          |    20 +
 t/t9121/renamed-dir.dump                      |    90 +
 t/t9122-git-svn-author.sh                     |    85 +
 t/t9123-git-svn-rebuild-with-rewriteroot.sh   |    32 +
 t/t9124-git-svn-dcommit-auto-props.sh         |   105 +
 t/t9125-git-svn-multi-glob-branch-names.sh    |    37 +
 ...it-svn-follow-deleted-readded-directory.sh |    22 +
 t/t9126/follow-deleted-readded.dump           |   201 +
 t/t9127-git-svn-partial-rebuild.sh            |    60 +
 t/t9128-git-svn-cmd-branch.sh                 |    79 +
 t/t9129-git-svn-i18n-commitencoding.sh        |    91 +
 t/t9130-git-svn-authors-file.sh               |   131 +
 t/t9131-git-svn-empty-symlink.sh              |   110 +
 t/t9132-git-svn-broken-symlink.sh             |   102 +
 t/t9133-git-svn-nested-git-repo.sh            |   101 +
 t/t9134-git-svn-ignore-paths.sh               |   147 +
 t/t9135-git-svn-moved-branch-empty-file.sh    |    20 +
 t/t9135/svn.dump                              |   192 +
 ...136-git-svn-recreated-branch-empty-file.sh |    12 +
 t/t9136/svn.dump                              |   192 +
 t/t9137-git-svn-dcommit-clobber-series.sh     |    63 +
 t/t9138-git-svn-authors-prog.sh               |   107 +
 t/t9139-git-svn-non-utf8-commitencoding.sh    |    47 +
 t/t9140-git-svn-reset.sh                      |    66 +
 t/t9141-git-svn-multiple-branches.sh          |   122 +
 t/t9142-git-svn-shallow-clone.sh              |    29 +
 t/t9143-git-svn-gc.sh                         |    51 +
 t/t9144-git-svn-old-rev_map.sh                |    31 +
 t/t9145-git-svn-master-branch.sh              |    28 +
 t/t9146-git-svn-empty-dirs.sh                 |   128 +
 t/t9147-git-svn-include-paths.sh              |   149 +
 t/t9148-git-svn-propset.sh                    |    98 +
 t/t9150-svk-mergetickets.sh                   |    25 +
 t/t9150/make-svk-dump                         |    57 +
 t/t9150/svk-merge.dump                        |   616 +
 t/t9151-svn-mergeinfo.sh                      |    54 +
 t/t9151/.gitignore                            |     2 +
 t/t9151/make-svnmerge-dump                    |   305 +
 t/t9151/svn-mergeinfo.dump                    |  2388 ++
 t/t9152-svn-empty-dirs-after-gc.sh            |    40 +
 t/t9153-git-svn-rewrite-uuid.sh               |    25 +
 t/t9153/svn.dump                              |    75 +
 t/t9154-git-svn-fancy-glob.sh                 |    51 +
 t/t9154/svn.dump                              |   222 +
 t/t9155-git-svn-fetch-deleted-tag.sh          |    45 +
 t/t9156-git-svn-fetch-deleted-tag-2.sh        |    47 +
 t/t9157-git-svn-fetch-merge.sh                |    58 +
 t/t9158-git-svn-mergeinfo.sh                  |    52 +
 t/t9159-git-svn-no-parent-mergeinfo.sh        |    41 +
 t/t9160-git-svn-preserve-empty-dirs.sh        |   152 +
 t/t9161-git-svn-mergeinfo-push.sh             |   103 +
 t/t9161/branches.dump                         |   374 +
 t/t9162-git-svn-dcommit-interactive.sh        |    65 +
 t/t9163-git-svn-reset-clears-caches.sh        |    81 +
 t/t9164-git-svn-dcommit-concurrent.sh         |   224 +
 ...65-git-svn-fetch-merge-branch-of-branch.sh |    60 +
 ...6-git-svn-fetch-merge-branch-of-branch2.sh |    53 +
 t/t9167-git-svn-cmd-branch-subproject.sh      |    49 +
 t/t9168-git-svn-partially-globbed-names.sh    |   229 +
 t/t9169-git-svn-dcommit-crlf.sh               |    30 +
 t/t9200-git-cvsexportcommit.sh                |   341 +
 t/t9210-scalar.sh                             |   301 +
 t/t9211-scalar-clone.sh                       |   195 +
 t/t9300-fast-import.sh                        |  3938 ++
 t/t9301-fast-import-notes.sh                  |   727 +
 t/t9302-fast-import-unpack-limit.sh           |   106 +
 t/t9303-fast-import-compression.sh            |    62 +
 t/t9304-fast-import-marks.sh                  |    82 +
 t/t9350-fast-export.sh                        |   804 +
 t/t9350/broken-iso-8859-7-commit-message.txt  |     1 +
 t/t9350/simple-iso-8859-7-commit-message.txt  |     1 +
 t/t9351-fast-export-anonymize.sh              |   141 +
 t/t9400-git-cvsserver-server.sh               |   669 +
 t/t9401-git-cvsserver-crlf.sh                 |   372 +
 t/t9402-git-cvsserver-refs.sh                 |   554 +
 t/t9500-gitweb-standalone-no-errors.sh        |   815 +
 t/t9501-gitweb-standalone-http-status.sh      |   220 +
 t/t9502-gitweb-standalone-parse-output.sh     |   237 +
 t/t9600-cvsimport.sh                          |   167 +
 t/t9601-cvsimport-vendor-branch.sh            |    88 +
 t/t9601/cvsroot/.gitattributes                |     1 +
 t/t9601/cvsroot/CVSROOT/.gitignore            |     2 +
 t/t9601/cvsroot/module/added-imported.txt,v   |    44 +
 .../cvsroot/module/imported-anonymously.txt,v |    42 +
 .../module/imported-modified-imported.txt,v   |    76 +
 .../cvsroot/module/imported-modified.txt,v    |    59 +
 t/t9601/cvsroot/module/imported-once.txt,v    |    43 +
 t/t9601/cvsroot/module/imported-twice.txt,v   |    60 +
 t/t9602-cvsimport-branches-tags.sh            |    81 +
 t/t9602/README                                |    62 +
 t/t9602/cvsroot/.gitattributes                |     1 +
 t/t9602/cvsroot/CVSROOT/.gitignore            |     2 +
 t/t9602/cvsroot/module/default,v              |   102 +
 t/t9602/cvsroot/module/sub1/default,v         |   102 +
 t/t9602/cvsroot/module/sub1/subsubA/default,v |   101 +
 t/t9602/cvsroot/module/sub1/subsubB/default,v |   107 +
 .../module/sub2/Attic/branch_B_MIXED_only,v   |    59 +
 t/t9602/cvsroot/module/sub2/default,v         |   102 +
 t/t9602/cvsroot/module/sub2/subsubA/default,v |   102 +
 t/t9602/cvsroot/module/sub3/default,v         |   102 +
 t/t9603-cvsimport-patchsets.sh                |    40 +
 t/t9603/cvsroot/.gitattributes                |     1 +
 t/t9603/cvsroot/CVSROOT/.gitignore            |     2 +
 t/t9603/cvsroot/module/a,v                    |    74 +
 t/t9603/cvsroot/module/b,v                    |    90 +
 t/t9604-cvsimport-timestamps.sh               |    89 +
 t/t9604/cvsroot/.gitattributes                |     1 +
 t/t9604/cvsroot/CVSROOT/.gitignore            |     2 +
 t/t9604/cvsroot/module/a,v                    |   264 +
 t/t9700-perl-git.sh                           |    56 +
 t/t9700/test.pl                               |   165 +
 t/t9800-git-p4-basic.sh                       |   433 +
 t/t9801-git-p4-branch.sh                      |   760 +
 t/t9802-git-p4-filetype.sh                    |   382 +
 t/t9803-git-p4-shell-metachars.sh             |   108 +
 t/t9804-git-p4-label.sh                       |   111 +
 t/t9805-git-p4-skip-submit-edit.sh            |   101 +
 t/t9806-git-p4-options.sh                     |   306 +
 t/t9807-git-p4-submit.sh                      |   599 +
 t/t9808-git-p4-chdir.sh                       |    86 +
 t/t9809-git-p4-client-view.sh                 |   839 +
 t/t9810-git-p4-rcs.sh                         |   377 +
 t/t9811-git-p4-label-import.sh                |   265 +
 t/t9812-git-p4-wildcards.sh                   |   214 +
 t/t9813-git-p4-preserve-users.sh              |   141 +
 t/t9814-git-p4-rename.sh                      |   245 +
 t/t9815-git-p4-submit-fail.sh                 |   425 +
 t/t9816-git-p4-locked.sh                      |   141 +
 t/t9817-git-p4-exclude.sh                     |   108 +
 t/t9818-git-p4-block.sh                       |   149 +
 t/t9819-git-p4-case-folding.sh                |    56 +
 t/t9820-git-p4-editor-handling.sh             |    34 +
 t/t9821-git-p4-path-variations.sh             |   196 +
 t/t9822-git-p4-path-encoding.sh               |    77 +
 t/t9823-git-p4-mock-lfs.sh                    |   188 +
 t/t9824-git-p4-git-lfs.sh                     |   290 +
 t/t9825-git-p4-handle-utf16-without-bom.sh    |    62 +
 t/t9826-git-p4-keep-empty-commits.sh          |   130 +
 t/t9827-git-p4-change-filetype.sh             |    62 +
 t/t9828-git-p4-map-user.sh                    |    57 +
 t/t9829-git-p4-jobs.sh                        |    95 +
 t/t9830-git-p4-symlink-dir.sh                 |    39 +
 t/t9831-git-p4-triggers.sh                    |    99 +
 t/t9832-unshelve.sh                           |   188 +
 t/t9833-errors.sh                             |    48 +
 t/t9834-git-p4-file-dir-bug.sh                |    70 +
 t/t9835-git-p4-metadata-encoding-python2.sh   |   213 +
 t/t9836-git-p4-metadata-encoding-python3.sh   |   214 +
 t/t9850-shell.sh                              |    38 +
 t/t9901-git-web--browse.sh                    |    63 +
 t/t9902-completion.sh                         |  3089 ++
 t/t9903-bash-prompt.sh                        |   778 +
 t/test-binary-1.png                           |   Bin 0 -> 5660 bytes
 t/test-binary-2.png                           |   Bin 0 -> 275 bytes
 t/test-lib-functions.sh                       |  2019 ++
 t/test-lib-github-workflow-markup.sh          |    56 +
 t/test-lib-junit.sh                           |   132 +
 t/test-lib.sh                                 |  1893 +
 t/test-terminal.perl                          |    82 +
 t/unit-tests/.gitignore                       |     3 +
 t/unit-tests/clar/.editorconfig               |    13 +
 t/unit-tests/clar/.github/workflows/ci.yml    |    35 +
 t/unit-tests/clar/.gitignore                  |     1 +
 t/unit-tests/clar/CMakeLists.txt              |    28 +
 t/unit-tests/clar/COPYING                     |    15 +
 t/unit-tests/clar/README.md                   |   329 +
 t/unit-tests/clar/clar.c                      |   857 +
 t/unit-tests/clar/clar.h                      |   173 +
 t/unit-tests/clar/clar/fixtures.h             |    50 +
 t/unit-tests/clar/clar/fs.h                   |   524 +
 t/unit-tests/clar/clar/print.h                |   216 +
 t/unit-tests/clar/clar/sandbox.h              |   158 +
 t/unit-tests/clar/clar/summary.h              |   139 +
 t/unit-tests/clar/generate.py                 |   266 +
 t/unit-tests/clar/test/CMakeLists.txt         |    39 +
 t/unit-tests/clar/test/clar_test.h            |    16 +
 t/unit-tests/clar/test/main.c                 |    40 +
 t/unit-tests/clar/test/main.c.sample          |    27 +
 t/unit-tests/clar/test/resources/test/file    |     1 +
 t/unit-tests/clar/test/sample.c               |    84 +
 t/unit-tests/generate-clar-decls.sh           |    20 +
 t/unit-tests/generate-clar-suites.sh          |    63 +
 t/unit-tests/lib-oid.c                        |    52 +
 t/unit-tests/lib-oid.h                        |    25 +
 t/unit-tests/lib-reftable.c                   |    98 +
 t/unit-tests/lib-reftable.h                   |    21 +
 t/unit-tests/t-example-decorate.c             |    74 +
 t/unit-tests/t-hashmap.c                      |   361 +
 t/unit-tests/t-oid-array.c                    |   126 +
 t/unit-tests/t-oidmap.c                       |   181 +
 t/unit-tests/t-oidtree.c                      |   122 +
 t/unit-tests/t-reftable-basics.c              |   201 +
 t/unit-tests/t-reftable-block.c               |   383 +
 t/unit-tests/t-reftable-merged.c              |   546 +
 t/unit-tests/t-reftable-pq.c                  |   153 +
 t/unit-tests/t-reftable-reader.c              |    96 +
 t/unit-tests/t-reftable-readwrite.c           |   985 +
 t/unit-tests/t-reftable-record.c              |   569 +
 t/unit-tests/t-reftable-stack.c               |  1403 +
 t/unit-tests/t-strbuf.c                       |   122 +
 t/unit-tests/t-strcmp-offset.c                |    35 +
 t/unit-tests/t-trailer.c                      |   317 +
 t/unit-tests/t-urlmatch-normalization.c       |   271 +
 t/unit-tests/test-lib.c                       |   456 +
 t/unit-tests/test-lib.h                       |   183 +
 t/unit-tests/u-ctype.c                        |   102 +
 t/unit-tests/u-hash.c                         |   109 +
 t/unit-tests/u-mem-pool.c                     |    25 +
 t/unit-tests/u-prio-queue.c                   |    94 +
 t/unit-tests/u-reftable-tree.c                |    78 +
 t/unit-tests/u-strvec.c                       |   316 +
 t/unit-tests/unit-test.c                      |    64 +
 t/unit-tests/unit-test.h                      |    10 +
 t/valgrind/.gitignore                         |     2 +
 t/valgrind/analyze.sh                         |   127 +
 t/valgrind/default.supp                       |    51 +
 t/valgrind/valgrind.sh                        |    40 +
 tag.c                                         |   245 +
 tag.h                                         |    24 +
 tar.h                                         |    30 +
 tempfile.c                                    |   373 +
 tempfile.h                                    |   285 +
 templates/.gitignore                          |     2 +
 templates/Makefile                            |    75 +
 templates/description                         |     1 +
 templates/hooks/applypatch-msg.sample         |    15 +
 templates/hooks/commit-msg.sample             |    24 +
 templates/hooks/fsmonitor-watchman.sample     |   174 +
 templates/hooks/meson.build                   |    26 +
 templates/hooks/post-update.sample            |     8 +
 templates/hooks/pre-applypatch.sample         |    14 +
 templates/hooks/pre-commit.sample             |    49 +
 templates/hooks/pre-merge-commit.sample       |    13 +
 templates/hooks/pre-push.sample               |    53 +
 templates/hooks/pre-rebase.sample             |   169 +
 templates/hooks/pre-receive.sample            |    24 +
 templates/hooks/prepare-commit-msg.sample     |    42 +
 templates/hooks/push-to-checkout.sample       |    78 +
 templates/hooks/sendemail-validate.sample     |    77 +
 templates/hooks/update.sample                 |   128 +
 templates/info/exclude                        |     6 +
 templates/info/meson.build                    |     7 +
 templates/meson.build                         |    15 +
 thread-utils.c                                |   125 +
 thread-utils.h                                |    57 +
 tmp-objdir.c                                  |   335 +
 tmp-objdir.h                                  |    86 +
 trace.c                                       |   430 +
 trace.h                                       |   279 +
 trace2.c                                      |  1044 +
 trace2.h                                      |   593 +
 trace2/tr2_cfg.c                              |   160 +
 trace2/tr2_cfg.h                              |    27 +
 trace2/tr2_cmd_name.c                         |    31 +
 trace2/tr2_cmd_name.h                         |    24 +
 trace2/tr2_ctr.c                              |   120 +
 trace2/tr2_ctr.h                              |   104 +
 trace2/tr2_dst.c                              |   396 +
 trace2/tr2_dst.h                              |    38 +
 trace2/tr2_sid.c                              |   114 +
 trace2/tr2_sid.h                              |    18 +
 trace2/tr2_sysenv.c                           |   138 +
 trace2/tr2_sysenv.h                           |    39 +
 trace2/tr2_tbuf.c                             |    47 +
 trace2/tr2_tbuf.h                             |    24 +
 trace2/tr2_tgt.h                              |   160 +
 trace2/tr2_tgt_event.c                        |   721 +
 trace2/tr2_tgt_normal.c                       |   409 +
 trace2/tr2_tgt_perf.c                         |   634 +
 trace2/tr2_tls.c                              |   203 +
 trace2/tr2_tls.h                              |   123 +
 trace2/tr2_tmr.c                              |   182 +
 trace2/tr2_tmr.h                              |   140 +
 trailer.c                                     |  1237 +
 trailer.h                                     |   205 +
 transport-helper.c                            |  1674 +
 transport-internal.h                          |    71 +
 transport.c                                   |  1698 +
 transport.h                                   |   349 +
 tree-diff.c                                   |   748 +
 tree-walk.c                                   |  1288 +
 tree-walk.h                                   |   231 +
 tree.c                                        |   222 +
 tree.h                                        |    56 +
 unicode-width.h                               |   494 +
 unimplemented.sh                              |     4 +
 unix-socket.c                                 |   139 +
 unix-socket.h                                 |    15 +
 unix-stream-server.c                          |   125 +
 unix-stream-server.h                          |    33 +
 unpack-trees.c                                |  3070 ++
 unpack-trees.h                                |   140 +
 upload-pack.c                                 |  1880 +
 upload-pack.h                                 |    15 +
 url.c                                         |   121 +
 url.h                                         |    24 +
 urlmatch.c                                    |   624 +
 urlmatch.h                                    |    78 +
 usage.c                                       |   374 +
 userdiff.c                                    |   571 +
 userdiff.h                                    |    61 +
 utf8.c                                        |   826 +
 utf8.h                                        |   110 +
 varint.c                                      |    30 +
 varint.h                                      |     7 +
 version-def.h.in                              |     8 +
 version.c                                     |    44 +
 version.h                                     |    10 +
 versioncmp.c                                  |   202 +
 versioncmp.h                                  |     6 +
 walker.c                                      |   360 +
 walker.h                                      |    38 +
 wildmatch.c                                   |   287 +
 wildmatch.h                                   |    11 +
 worktree.c                                    |  1051 +
 worktree.h                                    |   232 +
 wrapper.c                                     |   831 +
 wrapper.h                                     |   169 +
 write-or-die.c                                |   109 +
 write-or-die.h                                |    78 +
 ws.c                                          |   391 +
 ws.h                                          |    33 +
 wt-status.c                                   |  2689 ++
 wt-status.h                                   |   188 +
 xdiff-interface.c                             |   342 +
 xdiff-interface.h                             |    75 +
 xdiff/xdiff.h                                 |   153 +
 xdiff/xdiffi.c                                |  1090 +
 xdiff/xdiffi.h                                |    62 +
 xdiff/xemit.c                                 |   330 +
 xdiff/xemit.h                                 |    36 +
 xdiff/xhistogram.c                            |   370 +
 xdiff/xinclude.h                              |    38 +
 xdiff/xmacros.h                               |    71 +
 xdiff/xmerge.c                                |   739 +
 xdiff/xpatience.c                             |   373 +
 xdiff/xprepare.c                              |   461 +
 xdiff/xprepare.h                              |    34 +
 xdiff/xtypes.h                                |    67 +
 xdiff/xutils.c                                |   451 +
 xdiff/xutils.h                                |    48 +
 4591 files changed, 1515175 insertions(+)
 create mode 100644 .cirrus.yml
 create mode 100644 .clang-format
 create mode 100644 .editorconfig
 create mode 100644 .gitattributes
 create mode 100644 .github/CONTRIBUTING.md
 create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
 create mode 100644 .github/workflows/check-style.yml
 create mode 100644 .github/workflows/check-whitespace.yml
 create mode 100644 .github/workflows/coverity.yml
 create mode 100644 .github/workflows/l10n.yml
 create mode 100644 .github/workflows/main.yml
 create mode 100644 .gitignore
 create mode 100644 .gitlab-ci.yml
 create mode 100644 .gitmodules
 create mode 100644 .mailmap
 create mode 100644 .tsan-suppressions
 create mode 100644 CODE_OF_CONDUCT.md
 create mode 100644 COPYING
 create mode 100644 Documentation/.gitattributes
 create mode 100644 Documentation/.gitignore
 create mode 100644 Documentation/BreakingChanges.adoc
 create mode 100644 Documentation/CodingGuidelines
 create mode 100644 Documentation/DecisionMaking.adoc
 create mode 100644 Documentation/Makefile
 create mode 100644 Documentation/MyFirstContribution.adoc
 create mode 100644 Documentation/MyFirstObjectWalk.adoc
 create mode 100644 Documentation/RelNotes/1.5.0.1.txt
 create mode 100644 Documentation/RelNotes/1.5.0.2.txt
 create mode 100644 Documentation/RelNotes/1.5.0.3.txt
 create mode 100644 Documentation/RelNotes/1.5.0.4.txt
 create mode 100644 Documentation/RelNotes/1.5.0.5.txt
 create mode 100644 Documentation/RelNotes/1.5.0.6.txt
 create mode 100644 Documentation/RelNotes/1.5.0.7.txt
 create mode 100644 Documentation/RelNotes/1.5.0.txt
 create mode 100644 Documentation/RelNotes/1.5.1.1.txt
 create mode 100644 Documentation/RelNotes/1.5.1.2.txt
 create mode 100644 Documentation/RelNotes/1.5.1.3.txt
 create mode 100644 Documentation/RelNotes/1.5.1.4.txt
 create mode 100644 Documentation/RelNotes/1.5.1.5.txt
 create mode 100644 Documentation/RelNotes/1.5.1.6.txt
 create mode 100644 Documentation/RelNotes/1.5.1.txt
 create mode 100644 Documentation/RelNotes/1.5.2.1.txt
 create mode 100644 Documentation/RelNotes/1.5.2.2.txt
 create mode 100644 Documentation/RelNotes/1.5.2.3.txt
 create mode 100644 Documentation/RelNotes/1.5.2.4.txt
 create mode 100644 Documentation/RelNotes/1.5.2.5.txt
 create mode 100644 Documentation/RelNotes/1.5.2.txt
 create mode 100644 Documentation/RelNotes/1.5.3.1.txt
 create mode 100644 Documentation/RelNotes/1.5.3.2.txt
 create mode 100644 Documentation/RelNotes/1.5.3.3.txt
 create mode 100644 Documentation/RelNotes/1.5.3.4.txt
 create mode 100644 Documentation/RelNotes/1.5.3.5.txt
 create mode 100644 Documentation/RelNotes/1.5.3.6.txt
 create mode 100644 Documentation/RelNotes/1.5.3.7.txt
 create mode 100644 Documentation/RelNotes/1.5.3.8.txt
 create mode 100644 Documentation/RelNotes/1.5.3.txt
 create mode 100644 Documentation/RelNotes/1.5.4.1.txt
 create mode 100644 Documentation/RelNotes/1.5.4.2.txt
 create mode 100644 Documentation/RelNotes/1.5.4.3.txt
 create mode 100644 Documentation/RelNotes/1.5.4.4.txt
 create mode 100644 Documentation/RelNotes/1.5.4.5.txt
 create mode 100644 Documentation/RelNotes/1.5.4.6.txt
 create mode 100644 Documentation/RelNotes/1.5.4.7.txt
 create mode 100644 Documentation/RelNotes/1.5.4.txt
 create mode 100644 Documentation/RelNotes/1.5.5.1.txt
 create mode 100644 Documentation/RelNotes/1.5.5.2.txt
 create mode 100644 Documentation/RelNotes/1.5.5.3.txt
 create mode 100644 Documentation/RelNotes/1.5.5.4.txt
 create mode 100644 Documentation/RelNotes/1.5.5.5.txt
 create mode 100644 Documentation/RelNotes/1.5.5.6.txt
 create mode 100644 Documentation/RelNotes/1.5.5.txt
 create mode 100644 Documentation/RelNotes/1.5.6.1.txt
 create mode 100644 Documentation/RelNotes/1.5.6.2.txt
 create mode 100644 Documentation/RelNotes/1.5.6.3.txt
 create mode 100644 Documentation/RelNotes/1.5.6.4.txt
 create mode 100644 Documentation/RelNotes/1.5.6.5.txt
 create mode 100644 Documentation/RelNotes/1.5.6.6.txt
 create mode 100644 Documentation/RelNotes/1.5.6.txt
 create mode 100644 Documentation/RelNotes/1.6.0.1.txt
 create mode 100644 Documentation/RelNotes/1.6.0.2.txt
 create mode 100644 Documentation/RelNotes/1.6.0.3.txt
 create mode 100644 Documentation/RelNotes/1.6.0.4.txt
 create mode 100644 Documentation/RelNotes/1.6.0.5.txt
 create mode 100644 Documentation/RelNotes/1.6.0.6.txt
 create mode 100644 Documentation/RelNotes/1.6.0.txt
 create mode 100644 Documentation/RelNotes/1.6.1.1.txt
 create mode 100644 Documentation/RelNotes/1.6.1.2.txt
 create mode 100644 Documentation/RelNotes/1.6.1.3.txt
 create mode 100644 Documentation/RelNotes/1.6.1.4.txt
 create mode 100644 Documentation/RelNotes/1.6.1.txt
 create mode 100644 Documentation/RelNotes/1.6.2.1.txt
 create mode 100644 Documentation/RelNotes/1.6.2.2.txt
 create mode 100644 Documentation/RelNotes/1.6.2.3.txt
 create mode 100644 Documentation/RelNotes/1.6.2.4.txt
 create mode 100644 Documentation/RelNotes/1.6.2.5.txt
 create mode 100644 Documentation/RelNotes/1.6.2.txt
 create mode 100644 Documentation/RelNotes/1.6.3.1.txt
 create mode 100644 Documentation/RelNotes/1.6.3.2.txt
 create mode 100644 Documentation/RelNotes/1.6.3.3.txt
 create mode 100644 Documentation/RelNotes/1.6.3.4.txt
 create mode 100644 Documentation/RelNotes/1.6.3.txt
 create mode 100644 Documentation/RelNotes/1.6.4.1.txt
 create mode 100644 Documentation/RelNotes/1.6.4.2.txt
 create mode 100644 Documentation/RelNotes/1.6.4.3.txt
 create mode 100644 Documentation/RelNotes/1.6.4.4.txt
 create mode 100644 Documentation/RelNotes/1.6.4.5.txt
 create mode 100644 Documentation/RelNotes/1.6.4.txt
 create mode 100644 Documentation/RelNotes/1.6.5.1.txt
 create mode 100644 Documentation/RelNotes/1.6.5.2.txt
 create mode 100644 Documentation/RelNotes/1.6.5.3.txt
 create mode 100644 Documentation/RelNotes/1.6.5.4.txt
 create mode 100644 Documentation/RelNotes/1.6.5.5.txt
 create mode 100644 Documentation/RelNotes/1.6.5.6.txt
 create mode 100644 Documentation/RelNotes/1.6.5.7.txt
 create mode 100644 Documentation/RelNotes/1.6.5.8.txt
 create mode 100644 Documentation/RelNotes/1.6.5.9.txt
 create mode 100644 Documentation/RelNotes/1.6.5.txt
 create mode 100644 Documentation/RelNotes/1.6.6.1.txt
 create mode 100644 Documentation/RelNotes/1.6.6.2.txt
 create mode 100644 Documentation/RelNotes/1.6.6.3.txt
 create mode 100644 Documentation/RelNotes/1.6.6.txt
 create mode 100644 Documentation/RelNotes/1.7.0.1.txt
 create mode 100644 Documentation/RelNotes/1.7.0.2.txt
 create mode 100644 Documentation/RelNotes/1.7.0.3.txt
 create mode 100644 Documentation/RelNotes/1.7.0.4.txt
 create mode 100644 Documentation/RelNotes/1.7.0.5.txt
 create mode 100644 Documentation/RelNotes/1.7.0.6.txt
 create mode 100644 Documentation/RelNotes/1.7.0.7.txt
 create mode 100644 Documentation/RelNotes/1.7.0.8.txt
 create mode 100644 Documentation/RelNotes/1.7.0.9.txt
 create mode 100644 Documentation/RelNotes/1.7.0.txt
 create mode 100644 Documentation/RelNotes/1.7.1.1.txt
 create mode 100644 Documentation/RelNotes/1.7.1.2.txt
 create mode 100644 Documentation/RelNotes/1.7.1.3.txt
 create mode 100644 Documentation/RelNotes/1.7.1.4.txt
 create mode 100644 Documentation/RelNotes/1.7.1.txt
 create mode 100644 Documentation/RelNotes/1.7.10.1.txt
 create mode 100644 Documentation/RelNotes/1.7.10.2.txt
 create mode 100644 Documentation/RelNotes/1.7.10.3.txt
 create mode 100644 Documentation/RelNotes/1.7.10.4.txt
 create mode 100644 Documentation/RelNotes/1.7.10.5.txt
 create mode 100644 Documentation/RelNotes/1.7.10.txt
 create mode 100644 Documentation/RelNotes/1.7.11.1.txt
 create mode 100644 Documentation/RelNotes/1.7.11.2.txt
 create mode 100644 Documentation/RelNotes/1.7.11.3.txt
 create mode 100644 Documentation/RelNotes/1.7.11.4.txt
 create mode 100644 Documentation/RelNotes/1.7.11.5.txt
 create mode 100644 Documentation/RelNotes/1.7.11.6.txt
 create mode 100644 Documentation/RelNotes/1.7.11.7.txt
 create mode 100644 Documentation/RelNotes/1.7.11.txt
 create mode 100644 Documentation/RelNotes/1.7.12.1.txt
 create mode 100644 Documentation/RelNotes/1.7.12.2.txt
 create mode 100644 Documentation/RelNotes/1.7.12.3.txt
 create mode 100644 Documentation/RelNotes/1.7.12.4.txt
 create mode 100644 Documentation/RelNotes/1.7.12.txt
 create mode 100644 Documentation/RelNotes/1.7.2.1.txt
 create mode 100644 Documentation/RelNotes/1.7.2.2.txt
 create mode 100644 Documentation/RelNotes/1.7.2.3.txt
 create mode 100644 Documentation/RelNotes/1.7.2.4.txt
 create mode 100644 Documentation/RelNotes/1.7.2.5.txt
 create mode 100644 Documentation/RelNotes/1.7.2.txt
 create mode 100644 Documentation/RelNotes/1.7.3.1.txt
 create mode 100644 Documentation/RelNotes/1.7.3.2.txt
 create mode 100644 Documentation/RelNotes/1.7.3.3.txt
 create mode 100644 Documentation/RelNotes/1.7.3.4.txt
 create mode 100644 Documentation/RelNotes/1.7.3.5.txt
 create mode 100644 Documentation/RelNotes/1.7.3.txt
 create mode 100644 Documentation/RelNotes/1.7.4.1.txt
 create mode 100644 Documentation/RelNotes/1.7.4.2.txt
 create mode 100644 Documentation/RelNotes/1.7.4.3.txt
 create mode 100644 Documentation/RelNotes/1.7.4.4.txt
 create mode 100644 Documentation/RelNotes/1.7.4.5.txt
 create mode 100644 Documentation/RelNotes/1.7.4.txt
 create mode 100644 Documentation/RelNotes/1.7.5.1.txt
 create mode 100644 Documentation/RelNotes/1.7.5.2.txt
 create mode 100644 Documentation/RelNotes/1.7.5.3.txt
 create mode 100644 Documentation/RelNotes/1.7.5.4.txt
 create mode 100644 Documentation/RelNotes/1.7.5.txt
 create mode 100644 Documentation/RelNotes/1.7.6.1.txt
 create mode 100644 Documentation/RelNotes/1.7.6.2.txt
 create mode 100644 Documentation/RelNotes/1.7.6.3.txt
 create mode 100644 Documentation/RelNotes/1.7.6.4.txt
 create mode 100644 Documentation/RelNotes/1.7.6.5.txt
 create mode 100644 Documentation/RelNotes/1.7.6.6.txt
 create mode 100644 Documentation/RelNotes/1.7.6.txt
 create mode 100644 Documentation/RelNotes/1.7.7.1.txt
 create mode 100644 Documentation/RelNotes/1.7.7.2.txt
 create mode 100644 Documentation/RelNotes/1.7.7.3.txt
 create mode 100644 Documentation/RelNotes/1.7.7.4.txt
 create mode 100644 Documentation/RelNotes/1.7.7.5.txt
 create mode 100644 Documentation/RelNotes/1.7.7.6.txt
 create mode 100644 Documentation/RelNotes/1.7.7.7.txt
 create mode 100644 Documentation/RelNotes/1.7.7.txt
 create mode 100644 Documentation/RelNotes/1.7.8.1.txt
 create mode 100644 Documentation/RelNotes/1.7.8.2.txt
 create mode 100644 Documentation/RelNotes/1.7.8.3.txt
 create mode 100644 Documentation/RelNotes/1.7.8.4.txt
 create mode 100644 Documentation/RelNotes/1.7.8.5.txt
 create mode 100644 Documentation/RelNotes/1.7.8.6.txt
 create mode 100644 Documentation/RelNotes/1.7.8.txt
 create mode 100644 Documentation/RelNotes/1.7.9.1.txt
 create mode 100644 Documentation/RelNotes/1.7.9.2.txt
 create mode 100644 Documentation/RelNotes/1.7.9.3.txt
 create mode 100644 Documentation/RelNotes/1.7.9.4.txt
 create mode 100644 Documentation/RelNotes/1.7.9.5.txt
 create mode 100644 Documentation/RelNotes/1.7.9.6.txt
 create mode 100644 Documentation/RelNotes/1.7.9.7.txt
 create mode 100644 Documentation/RelNotes/1.7.9.txt
 create mode 100644 Documentation/RelNotes/1.8.0.1.txt
 create mode 100644 Documentation/RelNotes/1.8.0.2.txt
 create mode 100644 Documentation/RelNotes/1.8.0.3.txt
 create mode 100644 Documentation/RelNotes/1.8.0.txt
 create mode 100644 Documentation/RelNotes/1.8.1.1.txt
 create mode 100644 Documentation/RelNotes/1.8.1.2.txt
 create mode 100644 Documentation/RelNotes/1.8.1.3.txt
 create mode 100644 Documentation/RelNotes/1.8.1.4.txt
 create mode 100644 Documentation/RelNotes/1.8.1.5.txt
 create mode 100644 Documentation/RelNotes/1.8.1.6.txt
 create mode 100644 Documentation/RelNotes/1.8.1.txt
 create mode 100644 Documentation/RelNotes/1.8.2.1.txt
 create mode 100644 Documentation/RelNotes/1.8.2.2.txt
 create mode 100644 Documentation/RelNotes/1.8.2.3.txt
 create mode 100644 Documentation/RelNotes/1.8.2.txt
 create mode 100644 Documentation/RelNotes/1.8.3.1.txt
 create mode 100644 Documentation/RelNotes/1.8.3.2.txt
 create mode 100644 Documentation/RelNotes/1.8.3.3.txt
 create mode 100644 Documentation/RelNotes/1.8.3.4.txt
 create mode 100644 Documentation/RelNotes/1.8.3.txt
 create mode 100644 Documentation/RelNotes/1.8.4.1.txt
 create mode 100644 Documentation/RelNotes/1.8.4.2.txt
 create mode 100644 Documentation/RelNotes/1.8.4.3.txt
 create mode 100644 Documentation/RelNotes/1.8.4.4.txt
 create mode 100644 Documentation/RelNotes/1.8.4.5.txt
 create mode 100644 Documentation/RelNotes/1.8.4.txt
 create mode 100644 Documentation/RelNotes/1.8.5.1.txt
 create mode 100644 Documentation/RelNotes/1.8.5.2.txt
 create mode 100644 Documentation/RelNotes/1.8.5.3.txt
 create mode 100644 Documentation/RelNotes/1.8.5.4.txt
 create mode 100644 Documentation/RelNotes/1.8.5.5.txt
 create mode 100644 Documentation/RelNotes/1.8.5.6.txt
 create mode 100644 Documentation/RelNotes/1.8.5.txt
 create mode 100644 Documentation/RelNotes/1.9.0.txt
 create mode 100644 Documentation/RelNotes/1.9.1.txt
 create mode 100644 Documentation/RelNotes/1.9.2.txt
 create mode 100644 Documentation/RelNotes/1.9.3.txt
 create mode 100644 Documentation/RelNotes/1.9.4.txt
 create mode 100644 Documentation/RelNotes/1.9.5.txt
 create mode 100644 Documentation/RelNotes/2.0.0.txt
 create mode 100644 Documentation/RelNotes/2.0.1.txt
 create mode 100644 Documentation/RelNotes/2.0.2.txt
 create mode 100644 Documentation/RelNotes/2.0.3.txt
 create mode 100644 Documentation/RelNotes/2.0.4.txt
 create mode 100644 Documentation/RelNotes/2.0.5.txt
 create mode 100644 Documentation/RelNotes/2.1.0.txt
 create mode 100644 Documentation/RelNotes/2.1.1.txt
 create mode 100644 Documentation/RelNotes/2.1.2.txt
 create mode 100644 Documentation/RelNotes/2.1.3.txt
 create mode 100644 Documentation/RelNotes/2.1.4.txt
 create mode 100644 Documentation/RelNotes/2.10.0.txt
 create mode 100644 Documentation/RelNotes/2.10.1.txt
 create mode 100644 Documentation/RelNotes/2.10.2.txt
 create mode 100644 Documentation/RelNotes/2.10.3.txt
 create mode 100644 Documentation/RelNotes/2.10.4.txt
 create mode 100644 Documentation/RelNotes/2.10.5.txt
 create mode 100644 Documentation/RelNotes/2.11.0.txt
 create mode 100644 Documentation/RelNotes/2.11.1.txt
 create mode 100644 Documentation/RelNotes/2.11.2.txt
 create mode 100644 Documentation/RelNotes/2.11.3.txt
 create mode 100644 Documentation/RelNotes/2.11.4.txt
 create mode 100644 Documentation/RelNotes/2.12.0.txt
 create mode 100644 Documentation/RelNotes/2.12.1.txt
 create mode 100644 Documentation/RelNotes/2.12.2.txt
 create mode 100644 Documentation/RelNotes/2.12.3.txt
 create mode 100644 Documentation/RelNotes/2.12.4.txt
 create mode 100644 Documentation/RelNotes/2.12.5.txt
 create mode 100644 Documentation/RelNotes/2.13.0.txt
 create mode 100644 Documentation/RelNotes/2.13.1.txt
 create mode 100644 Documentation/RelNotes/2.13.2.txt
 create mode 100644 Documentation/RelNotes/2.13.3.txt
 create mode 100644 Documentation/RelNotes/2.13.4.txt
 create mode 100644 Documentation/RelNotes/2.13.5.txt
 create mode 100644 Documentation/RelNotes/2.13.6.txt
 create mode 100644 Documentation/RelNotes/2.13.7.txt
 create mode 100644 Documentation/RelNotes/2.14.0.txt
 create mode 100644 Documentation/RelNotes/2.14.1.txt
 create mode 100644 Documentation/RelNotes/2.14.2.txt
 create mode 100644 Documentation/RelNotes/2.14.3.txt
 create mode 100644 Documentation/RelNotes/2.14.4.txt
 create mode 100644 Documentation/RelNotes/2.14.5.txt
 create mode 100644 Documentation/RelNotes/2.14.6.txt
 create mode 100644 Documentation/RelNotes/2.15.0.txt
 create mode 100644 Documentation/RelNotes/2.15.1.txt
 create mode 100644 Documentation/RelNotes/2.15.2.txt
 create mode 100644 Documentation/RelNotes/2.15.3.txt
 create mode 100644 Documentation/RelNotes/2.15.4.txt
 create mode 100644 Documentation/RelNotes/2.16.0.txt
 create mode 100644 Documentation/RelNotes/2.16.1.txt
 create mode 100644 Documentation/RelNotes/2.16.2.txt
 create mode 100644 Documentation/RelNotes/2.16.3.txt
 create mode 100644 Documentation/RelNotes/2.16.4.txt
 create mode 100644 Documentation/RelNotes/2.16.5.txt
 create mode 100644 Documentation/RelNotes/2.16.6.txt
 create mode 100644 Documentation/RelNotes/2.17.0.txt
 create mode 100644 Documentation/RelNotes/2.17.1.txt
 create mode 100644 Documentation/RelNotes/2.17.2.txt
 create mode 100644 Documentation/RelNotes/2.17.3.txt
 create mode 100644 Documentation/RelNotes/2.17.4.txt
 create mode 100644 Documentation/RelNotes/2.17.5.txt
 create mode 100644 Documentation/RelNotes/2.17.6.txt
 create mode 100644 Documentation/RelNotes/2.18.0.txt
 create mode 100644 Documentation/RelNotes/2.18.1.txt
 create mode 100644 Documentation/RelNotes/2.18.2.txt
 create mode 100644 Documentation/RelNotes/2.18.3.txt
 create mode 100644 Documentation/RelNotes/2.18.4.txt
 create mode 100644 Documentation/RelNotes/2.18.5.txt
 create mode 100644 Documentation/RelNotes/2.19.0.txt
 create mode 100644 Documentation/RelNotes/2.19.1.txt
 create mode 100644 Documentation/RelNotes/2.19.2.txt
 create mode 100644 Documentation/RelNotes/2.19.3.txt
 create mode 100644 Documentation/RelNotes/2.19.4.txt
 create mode 100644 Documentation/RelNotes/2.19.5.txt
 create mode 100644 Documentation/RelNotes/2.19.6.txt
 create mode 100644 Documentation/RelNotes/2.2.0.txt
 create mode 100644 Documentation/RelNotes/2.2.1.txt
 create mode 100644 Documentation/RelNotes/2.2.2.txt
 create mode 100644 Documentation/RelNotes/2.2.3.txt
 create mode 100644 Documentation/RelNotes/2.20.0.txt
 create mode 100644 Documentation/RelNotes/2.20.1.txt
 create mode 100644 Documentation/RelNotes/2.20.2.txt
 create mode 100644 Documentation/RelNotes/2.20.3.txt
 create mode 100644 Documentation/RelNotes/2.20.4.txt
 create mode 100644 Documentation/RelNotes/2.20.5.txt
 create mode 100644 Documentation/RelNotes/2.21.0.txt
 create mode 100644 Documentation/RelNotes/2.21.1.txt
 create mode 100644 Documentation/RelNotes/2.21.2.txt
 create mode 100644 Documentation/RelNotes/2.21.3.txt
 create mode 100644 Documentation/RelNotes/2.21.4.txt
 create mode 100644 Documentation/RelNotes/2.22.0.txt
 create mode 100644 Documentation/RelNotes/2.22.1.txt
 create mode 100644 Documentation/RelNotes/2.22.2.txt
 create mode 100644 Documentation/RelNotes/2.22.3.txt
 create mode 100644 Documentation/RelNotes/2.22.4.txt
 create mode 100644 Documentation/RelNotes/2.22.5.txt
 create mode 100644 Documentation/RelNotes/2.23.0.txt
 create mode 100644 Documentation/RelNotes/2.23.1.txt
 create mode 100644 Documentation/RelNotes/2.23.2.txt
 create mode 100644 Documentation/RelNotes/2.23.3.txt
 create mode 100644 Documentation/RelNotes/2.23.4.txt
 create mode 100644 Documentation/RelNotes/2.24.0.txt
 create mode 100644 Documentation/RelNotes/2.24.1.txt
 create mode 100644 Documentation/RelNotes/2.24.2.txt
 create mode 100644 Documentation/RelNotes/2.24.3.txt
 create mode 100644 Documentation/RelNotes/2.24.4.txt
 create mode 100644 Documentation/RelNotes/2.25.0.txt
 create mode 100644 Documentation/RelNotes/2.25.1.txt
 create mode 100644 Documentation/RelNotes/2.25.2.txt
 create mode 100644 Documentation/RelNotes/2.25.3.txt
 create mode 100644 Documentation/RelNotes/2.25.4.txt
 create mode 100644 Documentation/RelNotes/2.25.5.txt
 create mode 100644 Documentation/RelNotes/2.26.0.txt
 create mode 100644 Documentation/RelNotes/2.26.1.txt
 create mode 100644 Documentation/RelNotes/2.26.2.txt
 create mode 100644 Documentation/RelNotes/2.26.3.txt
 create mode 100644 Documentation/RelNotes/2.27.0.txt
 create mode 100644 Documentation/RelNotes/2.27.1.txt
 create mode 100644 Documentation/RelNotes/2.28.0.txt
 create mode 100644 Documentation/RelNotes/2.28.1.txt
 create mode 100644 Documentation/RelNotes/2.29.0.txt
 create mode 100644 Documentation/RelNotes/2.29.1.txt
 create mode 100644 Documentation/RelNotes/2.29.2.txt
 create mode 100644 Documentation/RelNotes/2.29.3.txt
 create mode 100644 Documentation/RelNotes/2.3.0.txt
 create mode 100644 Documentation/RelNotes/2.3.1.txt
 create mode 100644 Documentation/RelNotes/2.3.10.txt
 create mode 100644 Documentation/RelNotes/2.3.2.txt
 create mode 100644 Documentation/RelNotes/2.3.3.txt
 create mode 100644 Documentation/RelNotes/2.3.4.txt
 create mode 100644 Documentation/RelNotes/2.3.5.txt
 create mode 100644 Documentation/RelNotes/2.3.6.txt
 create mode 100644 Documentation/RelNotes/2.3.7.txt
 create mode 100644 Documentation/RelNotes/2.3.8.txt
 create mode 100644 Documentation/RelNotes/2.3.9.txt
 create mode 100644 Documentation/RelNotes/2.30.0.txt
 create mode 100644 Documentation/RelNotes/2.30.1.txt
 create mode 100644 Documentation/RelNotes/2.30.2.txt
 create mode 100644 Documentation/RelNotes/2.30.3.txt
 create mode 100644 Documentation/RelNotes/2.30.4.txt
 create mode 100644 Documentation/RelNotes/2.30.5.txt
 create mode 100644 Documentation/RelNotes/2.30.6.txt
 create mode 100644 Documentation/RelNotes/2.30.7.txt
 create mode 100644 Documentation/RelNotes/2.30.8.txt
 create mode 100644 Documentation/RelNotes/2.30.9.txt
 create mode 100644 Documentation/RelNotes/2.31.0.txt
 create mode 100644 Documentation/RelNotes/2.31.1.txt
 create mode 100644 Documentation/RelNotes/2.31.2.txt
 create mode 100644 Documentation/RelNotes/2.31.3.txt
 create mode 100644 Documentation/RelNotes/2.31.4.txt
 create mode 100644 Documentation/RelNotes/2.31.5.txt
 create mode 100644 Documentation/RelNotes/2.31.6.txt
 create mode 100644 Documentation/RelNotes/2.31.7.txt
 create mode 100644 Documentation/RelNotes/2.31.8.txt
 create mode 100644 Documentation/RelNotes/2.32.0.txt
 create mode 100644 Documentation/RelNotes/2.32.1.txt
 create mode 100644 Documentation/RelNotes/2.32.2.txt
 create mode 100644 Documentation/RelNotes/2.32.3.txt
 create mode 100644 Documentation/RelNotes/2.32.4.txt
 create mode 100644 Documentation/RelNotes/2.32.5.txt
 create mode 100644 Documentation/RelNotes/2.32.6.txt
 create mode 100644 Documentation/RelNotes/2.32.7.txt
 create mode 100644 Documentation/RelNotes/2.33.0.txt
 create mode 100644 Documentation/RelNotes/2.33.1.txt
 create mode 100644 Documentation/RelNotes/2.33.2.txt
 create mode 100644 Documentation/RelNotes/2.33.3.txt
 create mode 100644 Documentation/RelNotes/2.33.4.txt
 create mode 100644 Documentation/RelNotes/2.33.5.txt
 create mode 100644 Documentation/RelNotes/2.33.6.txt
 create mode 100644 Documentation/RelNotes/2.33.7.txt
 create mode 100644 Documentation/RelNotes/2.33.8.txt
 create mode 100644 Documentation/RelNotes/2.34.0.txt
 create mode 100644 Documentation/RelNotes/2.34.1.txt
 create mode 100644 Documentation/RelNotes/2.34.2.txt
 create mode 100644 Documentation/RelNotes/2.34.3.txt
 create mode 100644 Documentation/RelNotes/2.34.4.txt
 create mode 100644 Documentation/RelNotes/2.34.5.txt
 create mode 100644 Documentation/RelNotes/2.34.6.txt
 create mode 100644 Documentation/RelNotes/2.34.7.txt
 create mode 100644 Documentation/RelNotes/2.34.8.txt
 create mode 100644 Documentation/RelNotes/2.35.0.txt
 create mode 100644 Documentation/RelNotes/2.35.1.txt
 create mode 100644 Documentation/RelNotes/2.35.2.txt
 create mode 100644 Documentation/RelNotes/2.35.3.txt
 create mode 100644 Documentation/RelNotes/2.35.4.txt
 create mode 100644 Documentation/RelNotes/2.35.5.txt
 create mode 100644 Documentation/RelNotes/2.35.6.txt
 create mode 100644 Documentation/RelNotes/2.35.7.txt
 create mode 100644 Documentation/RelNotes/2.35.8.txt
 create mode 100644 Documentation/RelNotes/2.36.0.txt
 create mode 100644 Documentation/RelNotes/2.36.1.txt
 create mode 100644 Documentation/RelNotes/2.36.2.txt
 create mode 100644 Documentation/RelNotes/2.36.3.txt
 create mode 100644 Documentation/RelNotes/2.36.4.txt
 create mode 100644 Documentation/RelNotes/2.36.5.txt
 create mode 100644 Documentation/RelNotes/2.36.6.txt
 create mode 100644 Documentation/RelNotes/2.37.0.txt
 create mode 100644 Documentation/RelNotes/2.37.1.txt
 create mode 100644 Documentation/RelNotes/2.37.2.txt
 create mode 100644 Documentation/RelNotes/2.37.3.txt
 create mode 100644 Documentation/RelNotes/2.37.4.txt
 create mode 100644 Documentation/RelNotes/2.37.5.txt
 create mode 100644 Documentation/RelNotes/2.37.6.txt
 create mode 100644 Documentation/RelNotes/2.37.7.txt
 create mode 100644 Documentation/RelNotes/2.38.0.txt
 create mode 100644 Documentation/RelNotes/2.38.1.txt
 create mode 100644 Documentation/RelNotes/2.38.2.txt
 create mode 100644 Documentation/RelNotes/2.38.3.txt
 create mode 100644 Documentation/RelNotes/2.38.4.txt
 create mode 100644 Documentation/RelNotes/2.38.5.txt
 create mode 100644 Documentation/RelNotes/2.39.0.txt
 create mode 100644 Documentation/RelNotes/2.39.1.txt
 create mode 100644 Documentation/RelNotes/2.39.2.txt
 create mode 100644 Documentation/RelNotes/2.39.3.txt
 create mode 100644 Documentation/RelNotes/2.39.4.txt
 create mode 100644 Documentation/RelNotes/2.39.5.txt
 create mode 100644 Documentation/RelNotes/2.4.0.txt
 create mode 100644 Documentation/RelNotes/2.4.1.txt
 create mode 100644 Documentation/RelNotes/2.4.10.txt
 create mode 100644 Documentation/RelNotes/2.4.11.txt
 create mode 100644 Documentation/RelNotes/2.4.12.txt
 create mode 100644 Documentation/RelNotes/2.4.2.txt
 create mode 100644 Documentation/RelNotes/2.4.3.txt
 create mode 100644 Documentation/RelNotes/2.4.4.txt
 create mode 100644 Documentation/RelNotes/2.4.5.txt
 create mode 100644 Documentation/RelNotes/2.4.6.txt
 create mode 100644 Documentation/RelNotes/2.4.7.txt
 create mode 100644 Documentation/RelNotes/2.4.8.txt
 create mode 100644 Documentation/RelNotes/2.4.9.txt
 create mode 100644 Documentation/RelNotes/2.40.0.txt
 create mode 100644 Documentation/RelNotes/2.40.1.txt
 create mode 100644 Documentation/RelNotes/2.40.2.txt
 create mode 100644 Documentation/RelNotes/2.40.3.txt
 create mode 100644 Documentation/RelNotes/2.40.4.txt
 create mode 100644 Documentation/RelNotes/2.41.0.txt
 create mode 100644 Documentation/RelNotes/2.41.1.txt
 create mode 100644 Documentation/RelNotes/2.41.2.txt
 create mode 100644 Documentation/RelNotes/2.41.3.txt
 create mode 100644 Documentation/RelNotes/2.42.0.txt
 create mode 100644 Documentation/RelNotes/2.42.1.txt
 create mode 100644 Documentation/RelNotes/2.42.2.txt
 create mode 100644 Documentation/RelNotes/2.42.3.txt
 create mode 100644 Documentation/RelNotes/2.42.4.txt
 create mode 100644 Documentation/RelNotes/2.43.0.txt
 create mode 100644 Documentation/RelNotes/2.43.1.txt
 create mode 100644 Documentation/RelNotes/2.43.2.txt
 create mode 100644 Documentation/RelNotes/2.43.3.txt
 create mode 100644 Documentation/RelNotes/2.43.4.txt
 create mode 100644 Documentation/RelNotes/2.43.5.txt
 create mode 100644 Documentation/RelNotes/2.43.6.txt
 create mode 100644 Documentation/RelNotes/2.44.0.txt
 create mode 100644 Documentation/RelNotes/2.44.1.txt
 create mode 100644 Documentation/RelNotes/2.44.2.txt
 create mode 100644 Documentation/RelNotes/2.44.3.txt
 create mode 100644 Documentation/RelNotes/2.45.0.txt
 create mode 100644 Documentation/RelNotes/2.45.1.txt
 create mode 100644 Documentation/RelNotes/2.45.2.txt
 create mode 100644 Documentation/RelNotes/2.45.3.txt
 create mode 100644 Documentation/RelNotes/2.46.0.txt
 create mode 100644 Documentation/RelNotes/2.46.1.txt
 create mode 100644 Documentation/RelNotes/2.46.2.txt
 create mode 100644 Documentation/RelNotes/2.46.3.txt
 create mode 100644 Documentation/RelNotes/2.47.0.txt
 create mode 100644 Documentation/RelNotes/2.47.1.txt
 create mode 100644 Documentation/RelNotes/2.47.2.txt
 create mode 100644 Documentation/RelNotes/2.48.0.txt
 create mode 100644 Documentation/RelNotes/2.48.1.txt
 create mode 100644 Documentation/RelNotes/2.49.0.txt
 create mode 100644 Documentation/RelNotes/2.5.0.txt
 create mode 100644 Documentation/RelNotes/2.5.1.txt
 create mode 100644 Documentation/RelNotes/2.5.2.txt
 create mode 100644 Documentation/RelNotes/2.5.3.txt
 create mode 100644 Documentation/RelNotes/2.5.4.txt
 create mode 100644 Documentation/RelNotes/2.5.5.txt
 create mode 100644 Documentation/RelNotes/2.5.6.txt
 create mode 100644 Documentation/RelNotes/2.6.0.txt
 create mode 100644 Documentation/RelNotes/2.6.1.txt
 create mode 100644 Documentation/RelNotes/2.6.2.txt
 create mode 100644 Documentation/RelNotes/2.6.3.txt
 create mode 100644 Documentation/RelNotes/2.6.4.txt
 create mode 100644 Documentation/RelNotes/2.6.5.txt
 create mode 100644 Documentation/RelNotes/2.6.6.txt
 create mode 100644 Documentation/RelNotes/2.6.7.txt
 create mode 100644 Documentation/RelNotes/2.7.0.txt
 create mode 100644 Documentation/RelNotes/2.7.1.txt
 create mode 100644 Documentation/RelNotes/2.7.2.txt
 create mode 100644 Documentation/RelNotes/2.7.3.txt
 create mode 100644 Documentation/RelNotes/2.7.4.txt
 create mode 100644 Documentation/RelNotes/2.7.5.txt
 create mode 100644 Documentation/RelNotes/2.7.6.txt
 create mode 100644 Documentation/RelNotes/2.8.0.txt
 create mode 100644 Documentation/RelNotes/2.8.1.txt
 create mode 100644 Documentation/RelNotes/2.8.2.txt
 create mode 100644 Documentation/RelNotes/2.8.3.txt
 create mode 100644 Documentation/RelNotes/2.8.4.txt
 create mode 100644 Documentation/RelNotes/2.8.5.txt
 create mode 100644 Documentation/RelNotes/2.8.6.txt
 create mode 100644 Documentation/RelNotes/2.9.0.txt
 create mode 100644 Documentation/RelNotes/2.9.1.txt
 create mode 100644 Documentation/RelNotes/2.9.2.txt
 create mode 100644 Documentation/RelNotes/2.9.3.txt
 create mode 100644 Documentation/RelNotes/2.9.4.txt
 create mode 100644 Documentation/RelNotes/2.9.5.txt
 create mode 100644 Documentation/ReviewingGuidelines.adoc
 create mode 100644 Documentation/SubmittingPatches
 create mode 100644 Documentation/ToolsForGit.adoc
 create mode 100644 Documentation/asciidoc.conf.in
 create mode 100644 Documentation/asciidoctor-extensions.rb.in
 create mode 100644 Documentation/blame-options.adoc
 create mode 100755 Documentation/build-docdep.perl
 create mode 100755 Documentation/cat-texi.perl
 create mode 100755 Documentation/cmd-list.perl
 create mode 100644 Documentation/config.adoc
 create mode 100644 Documentation/config/add.adoc
 create mode 100644 Documentation/config/advice.adoc
 create mode 100644 Documentation/config/alias.adoc
 create mode 100644 Documentation/config/am.adoc
 create mode 100644 Documentation/config/apply.adoc
 create mode 100644 Documentation/config/attr.adoc
 create mode 100644 Documentation/config/bitmap-pseudo-merge.adoc
 create mode 100644 Documentation/config/blame.adoc
 create mode 100644 Documentation/config/branch.adoc
 create mode 100644 Documentation/config/browser.adoc
 create mode 100644 Documentation/config/bundle.adoc
 create mode 100644 Documentation/config/checkout.adoc
 create mode 100644 Documentation/config/clean.adoc
 create mode 100644 Documentation/config/clone.adoc
 create mode 100644 Documentation/config/color.adoc
 create mode 100644 Documentation/config/column.adoc
 create mode 100644 Documentation/config/commit.adoc
 create mode 100644 Documentation/config/commitgraph.adoc
 create mode 100644 Documentation/config/completion.adoc
 create mode 100644 Documentation/config/core.adoc
 create mode 100644 Documentation/config/credential.adoc
 create mode 100644 Documentation/config/diff.adoc
 create mode 100644 Documentation/config/difftool.adoc
 create mode 100644 Documentation/config/extensions.adoc
 create mode 100644 Documentation/config/fastimport.adoc
 create mode 100644 Documentation/config/feature.adoc
 create mode 100644 Documentation/config/fetch.adoc
 create mode 100644 Documentation/config/filter.adoc
 create mode 100644 Documentation/config/fmt-merge-msg.adoc
 create mode 100644 Documentation/config/format.adoc
 create mode 100644 Documentation/config/fsck.adoc
 create mode 100644 Documentation/config/fsmonitor--daemon.adoc
 create mode 100644 Documentation/config/gc.adoc
 create mode 100644 Documentation/config/gitcvs.adoc
 create mode 100644 Documentation/config/gitweb.adoc
 create mode 100644 Documentation/config/gpg.adoc
 create mode 100644 Documentation/config/grep.adoc
 create mode 100644 Documentation/config/gui.adoc
 create mode 100644 Documentation/config/guitool.adoc
 create mode 100644 Documentation/config/help.adoc
 create mode 100644 Documentation/config/http.adoc
 create mode 100644 Documentation/config/i18n.adoc
 create mode 100644 Documentation/config/imap.adoc
 create mode 100644 Documentation/config/includeif.adoc
 create mode 100644 Documentation/config/index.adoc
 create mode 100644 Documentation/config/init.adoc
 create mode 100644 Documentation/config/instaweb.adoc
 create mode 100644 Documentation/config/interactive.adoc
 create mode 100644 Documentation/config/log.adoc
 create mode 100644 Documentation/config/lsrefs.adoc
 create mode 100644 Documentation/config/mailinfo.adoc
 create mode 100644 Documentation/config/mailmap.adoc
 create mode 100644 Documentation/config/maintenance.adoc
 create mode 100644 Documentation/config/man.adoc
 create mode 100644 Documentation/config/merge.adoc
 create mode 100644 Documentation/config/mergetool.adoc
 create mode 100644 Documentation/config/notes.adoc
 create mode 100644 Documentation/config/pack.adoc
 create mode 100644 Documentation/config/pager.adoc
 create mode 100644 Documentation/config/pretty.adoc
 create mode 100644 Documentation/config/promisor.adoc
 create mode 100644 Documentation/config/protocol.adoc
 create mode 100644 Documentation/config/pull.adoc
 create mode 100644 Documentation/config/push.adoc
 create mode 100644 Documentation/config/rebase.adoc
 create mode 100644 Documentation/config/receive.adoc
 create mode 100644 Documentation/config/reftable.adoc
 create mode 100644 Documentation/config/remote.adoc
 create mode 100644 Documentation/config/remotes.adoc
 create mode 100644 Documentation/config/repack.adoc
 create mode 100644 Documentation/config/rerere.adoc
 create mode 100644 Documentation/config/revert.adoc
 create mode 100644 Documentation/config/safe.adoc
 create mode 100644 Documentation/config/sendemail.adoc
 create mode 100644 Documentation/config/sequencer.adoc
 create mode 100644 Documentation/config/showbranch.adoc
 create mode 100644 Documentation/config/sparse.adoc
 create mode 100644 Documentation/config/splitindex.adoc
 create mode 100644 Documentation/config/ssh.adoc
 create mode 100644 Documentation/config/stash.adoc
 create mode 100644 Documentation/config/status.adoc
 create mode 100644 Documentation/config/submodule.adoc
 create mode 100644 Documentation/config/tag.adoc
 create mode 100644 Documentation/config/tar.adoc
 create mode 100644 Documentation/config/trace2.adoc
 create mode 100644 Documentation/config/transfer.adoc
 create mode 100644 Documentation/config/uploadarchive.adoc
 create mode 100644 Documentation/config/uploadpack.adoc
 create mode 100644 Documentation/config/url.adoc
 create mode 100644 Documentation/config/user.adoc
 create mode 100644 Documentation/config/versionsort.adoc
 create mode 100644 Documentation/config/web.adoc
 create mode 100644 Documentation/config/worktree.adoc
 create mode 100644 Documentation/date-formats.adoc
 create mode 100644 Documentation/diff-format.adoc
 create mode 100644 Documentation/diff-generate-patch.adoc
 create mode 100644 Documentation/diff-options.adoc
 create mode 100755 Documentation/doc-diff
 create mode 100644 Documentation/docbook-xsl.css
 create mode 100644 Documentation/docbook.xsl
 create mode 100644 Documentation/docinfo-html.in
 create mode 100644 Documentation/everyday.txto
 create mode 100644 Documentation/fetch-options.adoc
 create mode 100755 Documentation/fix-texi.perl
 create mode 100644 Documentation/fsck-msgids.adoc
 create mode 100755 Documentation/generate-mergetool-list.sh
 create mode 100644 Documentation/git-add.adoc
 create mode 100644 Documentation/git-am.adoc
 create mode 100644 Documentation/git-annotate.adoc
 create mode 100644 Documentation/git-apply.adoc
 create mode 100644 Documentation/git-archimport.adoc
 create mode 100644 Documentation/git-archive.adoc
 create mode 100644 Documentation/git-bisect-lk2009.adoc
 create mode 100644 Documentation/git-bisect.adoc
 create mode 100644 Documentation/git-blame.adoc
 create mode 100644 Documentation/git-branch.adoc
 create mode 100644 Documentation/git-bugreport.adoc
 create mode 100644 Documentation/git-bundle.adoc
 create mode 100644 Documentation/git-cat-file.adoc
 create mode 100644 Documentation/git-check-attr.adoc
 create mode 100644 Documentation/git-check-ignore.adoc
 create mode 100644 Documentation/git-check-mailmap.adoc
 create mode 100644 Documentation/git-check-ref-format.adoc
 create mode 100644 Documentation/git-checkout-index.adoc
 create mode 100644 Documentation/git-checkout.adoc
 create mode 100644 Documentation/git-cherry-pick.adoc
 create mode 100644 Documentation/git-cherry.adoc
 create mode 100644 Documentation/git-citool.adoc
 create mode 100644 Documentation/git-clean.adoc
 create mode 100644 Documentation/git-clone.adoc
 create mode 100644 Documentation/git-column.adoc
 create mode 100644 Documentation/git-commit-graph.adoc
 create mode 100644 Documentation/git-commit-tree.adoc
 create mode 100644 Documentation/git-commit.adoc
 create mode 100644 Documentation/git-config.adoc
 create mode 100644 Documentation/git-count-objects.adoc
 create mode 100644 Documentation/git-credential-cache--daemon.adoc
 create mode 100644 Documentation/git-credential-cache.adoc
 create mode 100644 Documentation/git-credential-store.adoc
 create mode 100644 Documentation/git-credential.adoc
 create mode 100644 Documentation/git-cvsexportcommit.adoc
 create mode 100644 Documentation/git-cvsimport.adoc
 create mode 100644 Documentation/git-cvsserver.adoc
 create mode 100644 Documentation/git-daemon.adoc
 create mode 100644 Documentation/git-describe.adoc
 create mode 100644 Documentation/git-diagnose.adoc
 create mode 100644 Documentation/git-diff-files.adoc
 create mode 100644 Documentation/git-diff-index.adoc
 create mode 100644 Documentation/git-diff-tree.adoc
 create mode 100644 Documentation/git-diff.adoc
 create mode 100644 Documentation/git-difftool.adoc
 create mode 100644 Documentation/git-fast-export.adoc
 create mode 100644 Documentation/git-fast-import.adoc
 create mode 100644 Documentation/git-fetch-pack.adoc
 create mode 100644 Documentation/git-fetch.adoc
 create mode 100644 Documentation/git-filter-branch.adoc
 create mode 100644 Documentation/git-fmt-merge-msg.adoc
 create mode 100644 Documentation/git-for-each-ref.adoc
 create mode 100644 Documentation/git-for-each-repo.adoc
 create mode 100644 Documentation/git-format-patch.adoc
 create mode 100644 Documentation/git-fsck-objects.adoc
 create mode 100644 Documentation/git-fsck.adoc
 create mode 100644 Documentation/git-fsmonitor--daemon.adoc
 create mode 100644 Documentation/git-gc.adoc
 create mode 100644 Documentation/git-get-tar-commit-id.adoc
 create mode 100644 Documentation/git-grep.adoc
 create mode 100644 Documentation/git-gui.adoc
 create mode 100644 Documentation/git-hash-object.adoc
 create mode 100644 Documentation/git-help.adoc
 create mode 100644 Documentation/git-hook.adoc
 create mode 100644 Documentation/git-http-backend.adoc
 create mode 100644 Documentation/git-http-fetch.adoc
 create mode 100644 Documentation/git-http-push.adoc
 create mode 100644 Documentation/git-imap-send.adoc
 create mode 100644 Documentation/git-index-pack.adoc
 create mode 100644 Documentation/git-init-db.adoc
 create mode 100644 Documentation/git-init.adoc
 create mode 100644 Documentation/git-instaweb.adoc
 create mode 100644 Documentation/git-interpret-trailers.adoc
 create mode 100644 Documentation/git-log.adoc
 create mode 100644 Documentation/git-ls-files.adoc
 create mode 100644 Documentation/git-ls-remote.adoc
 create mode 100644 Documentation/git-ls-tree.adoc
 create mode 100644 Documentation/git-mailinfo.adoc
 create mode 100644 Documentation/git-mailsplit.adoc
 create mode 100644 Documentation/git-maintenance.adoc
 create mode 100644 Documentation/git-merge-base.adoc
 create mode 100644 Documentation/git-merge-file.adoc
 create mode 100644 Documentation/git-merge-index.adoc
 create mode 100644 Documentation/git-merge-one-file.adoc
 create mode 100644 Documentation/git-merge-tree.adoc
 create mode 100644 Documentation/git-merge.adoc
 create mode 100644 Documentation/git-mergetool--lib.adoc
 create mode 100644 Documentation/git-mergetool.adoc
 create mode 100644 Documentation/git-mktag.adoc
 create mode 100644 Documentation/git-mktree.adoc
 create mode 100644 Documentation/git-multi-pack-index.adoc
 create mode 100644 Documentation/git-mv.adoc
 create mode 100644 Documentation/git-name-rev.adoc
 create mode 100644 Documentation/git-notes.adoc
 create mode 100644 Documentation/git-p4.adoc
 create mode 100644 Documentation/git-pack-objects.adoc
 create mode 100644 Documentation/git-pack-redundant.adoc
 create mode 100644 Documentation/git-pack-refs.adoc
 create mode 100644 Documentation/git-patch-id.adoc
 create mode 100644 Documentation/git-prune-packed.adoc
 create mode 100644 Documentation/git-prune.adoc
 create mode 100644 Documentation/git-pull.adoc
 create mode 100644 Documentation/git-push.adoc
 create mode 100644 Documentation/git-quiltimport.adoc
 create mode 100644 Documentation/git-range-diff.adoc
 create mode 100644 Documentation/git-read-tree.adoc
 create mode 100644 Documentation/git-rebase.adoc
 create mode 100644 Documentation/git-receive-pack.adoc
 create mode 100644 Documentation/git-reflog.adoc
 create mode 100644 Documentation/git-refs.adoc
 create mode 100644 Documentation/git-remote-ext.adoc
 create mode 100644 Documentation/git-remote-fd.adoc
 create mode 100644 Documentation/git-remote-helpers.txto
 create mode 100644 Documentation/git-remote.adoc
 create mode 100644 Documentation/git-repack.adoc
 create mode 100644 Documentation/git-replace.adoc
 create mode 100644 Documentation/git-replay.adoc
 create mode 100644 Documentation/git-request-pull.adoc
 create mode 100644 Documentation/git-rerere.adoc
 create mode 100644 Documentation/git-reset.adoc
 create mode 100644 Documentation/git-restore.adoc
 create mode 100644 Documentation/git-rev-list.adoc
 create mode 100644 Documentation/git-rev-parse.adoc
 create mode 100644 Documentation/git-revert.adoc
 create mode 100644 Documentation/git-rm.adoc
 create mode 100644 Documentation/git-send-email.adoc
 create mode 100644 Documentation/git-send-pack.adoc
 create mode 100644 Documentation/git-sh-i18n--envsubst.adoc
 create mode 100644 Documentation/git-sh-i18n.adoc
 create mode 100644 Documentation/git-sh-setup.adoc
 create mode 100644 Documentation/git-shell.adoc
 create mode 100644 Documentation/git-shortlog.adoc
 create mode 100644 Documentation/git-show-branch.adoc
 create mode 100644 Documentation/git-show-index.adoc
 create mode 100644 Documentation/git-show-ref.adoc
 create mode 100644 Documentation/git-show.adoc
 create mode 100644 Documentation/git-sparse-checkout.adoc
 create mode 100644 Documentation/git-stage.adoc
 create mode 100644 Documentation/git-stash.adoc
 create mode 100644 Documentation/git-status.adoc
 create mode 100644 Documentation/git-stripspace.adoc
 create mode 100644 Documentation/git-submodule.adoc
 create mode 100644 Documentation/git-svn.adoc
 create mode 100644 Documentation/git-switch.adoc
 create mode 100644 Documentation/git-symbolic-ref.adoc
 create mode 100644 Documentation/git-tag.adoc
 create mode 100644 Documentation/git-tools.adoc
 create mode 100644 Documentation/git-unpack-file.adoc
 create mode 100644 Documentation/git-unpack-objects.adoc
 create mode 100644 Documentation/git-update-index.adoc
 create mode 100644 Documentation/git-update-ref.adoc
 create mode 100644 Documentation/git-update-server-info.adoc
 create mode 100644 Documentation/git-upload-archive.adoc
 create mode 100644 Documentation/git-upload-pack.adoc
 create mode 100644 Documentation/git-var.adoc
 create mode 100644 Documentation/git-verify-commit.adoc
 create mode 100644 Documentation/git-verify-pack.adoc
 create mode 100644 Documentation/git-verify-tag.adoc
 create mode 100644 Documentation/git-version.adoc
 create mode 100644 Documentation/git-web--browse.adoc
 create mode 100644 Documentation/git-whatchanged.adoc
 create mode 100644 Documentation/git-worktree.adoc
 create mode 100644 Documentation/git-write-tree.adoc
 create mode 100644 Documentation/git.adoc
 create mode 100644 Documentation/gitattributes.adoc
 create mode 100644 Documentation/gitcli.adoc
 create mode 100644 Documentation/gitcore-tutorial.adoc
 create mode 100644 Documentation/gitcredentials.adoc
 create mode 100644 Documentation/gitcvs-migration.adoc
 create mode 100644 Documentation/gitdiffcore.adoc
 create mode 100644 Documentation/giteveryday.adoc
 create mode 100644 Documentation/gitfaq.adoc
 create mode 100644 Documentation/gitformat-bundle.adoc
 create mode 100644 Documentation/gitformat-chunk.adoc
 create mode 100644 Documentation/gitformat-commit-graph.adoc
 create mode 100644 Documentation/gitformat-index.adoc
 create mode 100644 Documentation/gitformat-pack.adoc
 create mode 100644 Documentation/gitformat-signature.adoc
 create mode 100644 Documentation/gitglossary.adoc
 create mode 100644 Documentation/githooks.adoc
 create mode 100644 Documentation/gitignore.adoc
 create mode 100644 Documentation/gitk.adoc
 create mode 100644 Documentation/gitmailmap.adoc
 create mode 100644 Documentation/gitmodules.adoc
 create mode 100644 Documentation/gitnamespaces.adoc
 create mode 100644 Documentation/gitpacking.adoc
 create mode 100644 Documentation/gitprotocol-capabilities.adoc
 create mode 100644 Documentation/gitprotocol-common.adoc
 create mode 100644 Documentation/gitprotocol-http.adoc
 create mode 100644 Documentation/gitprotocol-pack.adoc
 create mode 100644 Documentation/gitprotocol-v2.adoc
 create mode 100644 Documentation/gitremote-helpers.adoc
 create mode 100644 Documentation/gitrepository-layout.adoc
 create mode 100644 Documentation/gitrevisions.adoc
 create mode 100644 Documentation/gitsubmodules.adoc
 create mode 100644 Documentation/gittutorial-2.adoc
 create mode 100644 Documentation/gittutorial.adoc
 create mode 100644 Documentation/gitweb.adoc
 create mode 100644 Documentation/gitweb.conf.adoc
 create mode 100644 Documentation/gitworkflows.adoc
 create mode 100644 Documentation/glossary-content.adoc
 create mode 100644 Documentation/howto-index.adoc
 create mode 100644 Documentation/howto/coordinate-embargoed-releases.adoc
 create mode 100755 Documentation/howto/howto-index.sh
 create mode 100644 Documentation/howto/keep-canonical-history-correct.adoc
 create mode 100644 Documentation/howto/maintain-git.adoc
 create mode 100644 Documentation/howto/meson.build
 create mode 100644 Documentation/howto/new-command.adoc
 create mode 100644 Documentation/howto/rebase-from-internal-branch.adoc
 create mode 100644 Documentation/howto/rebuild-from-update-hook.adoc
 create mode 100644 Documentation/howto/recover-corrupted-blob-object.adoc
 create mode 100644 Documentation/howto/recover-corrupted-object-harder.adoc
 create mode 100644 Documentation/howto/revert-a-faulty-merge.adoc
 create mode 100644 Documentation/howto/revert-branch-rebase.adoc
 create mode 100644 Documentation/howto/separating-topic-branches.adoc
 create mode 100644 Documentation/howto/setup-git-server-over-http.adoc
 create mode 100644 Documentation/howto/update-hook-example.adoc
 create mode 100644 Documentation/howto/use-git-daemon.adoc
 create mode 100644 Documentation/howto/using-merge-subtree.adoc
 create mode 100644 Documentation/howto/using-signed-tag-in-pull-request.adoc
 create mode 100644 Documentation/i18n.adoc
 create mode 100644 Documentation/includes/cmd-config-section-all.txt
 create mode 100644 Documentation/includes/cmd-config-section-rest.txt
 create mode 100755 Documentation/install-doc-quick.sh
 create mode 100755 Documentation/install-webdoc.sh
 create mode 100644 Documentation/line-range-format.adoc
 create mode 100644 Documentation/line-range-options.adoc
 create mode 100755 Documentation/lint-fsck-msgids.perl
 create mode 100755 Documentation/lint-gitlink.perl
 create mode 100755 Documentation/lint-man-end-blurb.perl
 create mode 100755 Documentation/lint-man-section-order.perl
 create mode 100755 Documentation/lint-manpages.sh
 create mode 100644 Documentation/manpage-bold-literal.xsl
 create mode 100644 Documentation/manpage-normal.xsl
 create mode 100644 Documentation/manpage.xsl
 create mode 100644 Documentation/merge-options.adoc
 create mode 100644 Documentation/merge-strategies.adoc
 create mode 100644 Documentation/mergetools/vimdiff.txt
 create mode 100644 Documentation/meson.build
 create mode 100644 Documentation/object-format-disclaimer.adoc
 create mode 100644 Documentation/pretty-formats.adoc
 create mode 100644 Documentation/pretty-options.adoc
 create mode 100644 Documentation/pull-fetch-param.adoc
 create mode 100644 Documentation/ref-reachability-filters.adoc
 create mode 100644 Documentation/ref-storage-format.adoc
 create mode 100644 Documentation/rerere-options.adoc
 create mode 100644 Documentation/rev-list-description.adoc
 create mode 100644 Documentation/rev-list-options.adoc
 create mode 100644 Documentation/revisions.adoc
 create mode 100644 Documentation/scalar.adoc
 create mode 100644 Documentation/sequencer.adoc
 create mode 100644 Documentation/signoff-option.adoc
 create mode 100644 Documentation/technical/.gitignore
 create mode 100644 Documentation/technical/api-error-handling.adoc
 create mode 100644 Documentation/technical/api-index-skel.adoc
 create mode 100755 Documentation/technical/api-index.sh
 create mode 100644 Documentation/technical/api-merge.adoc
 create mode 100644 Documentation/technical/api-parse-options.adoc
 create mode 100644 Documentation/technical/api-path-walk.adoc
 create mode 100644 Documentation/technical/api-simple-ipc.adoc
 create mode 100644 Documentation/technical/api-trace2.adoc
 create mode 100644 Documentation/technical/bitmap-format.adoc
 create mode 100644 Documentation/technical/build-systems.adoc
 create mode 100644 Documentation/technical/bundle-uri.adoc
 create mode 100644 Documentation/technical/commit-graph.adoc
 create mode 100644 Documentation/technical/directory-rename-detection.adoc
 create mode 100644 Documentation/technical/hash-function-transition.adoc
 create mode 100644 Documentation/technical/long-running-process-protocol.adoc
 create mode 100644 Documentation/technical/meson.build
 create mode 100644 Documentation/technical/multi-pack-index.adoc
 create mode 100644 Documentation/technical/pack-heuristics.adoc
 create mode 100644 Documentation/technical/packfile-uri.adoc
 create mode 100644 Documentation/technical/parallel-checkout.adoc
 create mode 100644 Documentation/technical/partial-clone.adoc
 create mode 100644 Documentation/technical/platform-support.adoc
 create mode 100644 Documentation/technical/racy-git.adoc
 create mode 100644 Documentation/technical/reftable.adoc
 create mode 100644 Documentation/technical/remembering-renames.adoc
 create mode 100644 Documentation/technical/repository-version.adoc
 create mode 100644 Documentation/technical/rerere.adoc
 create mode 100644 Documentation/technical/scalar.adoc
 create mode 100644 Documentation/technical/send-pack-pipeline.adoc
 create mode 100644 Documentation/technical/shallow.adoc
 create mode 100644 Documentation/technical/sparse-checkout.adoc
 create mode 100644 Documentation/technical/sparse-index.adoc
 create mode 100644 Documentation/technical/trivial-merge.adoc
 create mode 100644 Documentation/technical/unit-tests.adoc
 create mode 100644 Documentation/texi.xsl
 create mode 100644 Documentation/trace2-target-values.adoc
 create mode 100644 Documentation/transfer-data-leaks.adoc
 create mode 100644 Documentation/urls-remotes.adoc
 create mode 100644 Documentation/urls.adoc
 create mode 100644 Documentation/user-manual.adoc
 create mode 100644 GIT-BUILD-OPTIONS.in
 create mode 100644 GIT-VERSION-FILE.in
 create mode 100755 GIT-VERSION-GEN
 create mode 100644 INSTALL
 create mode 100644 LGPL-2.1
 create mode 100644 Makefile
 create mode 100644 README.md
 create mode 120000 RelNotes
 create mode 100644 SECURITY.md
 create mode 100644 abspath.c
 create mode 100644 abspath.h
 create mode 100644 aclocal.m4
 create mode 100644 add-interactive.c
 create mode 100644 add-interactive.h
 create mode 100644 add-patch.c
 create mode 100644 advice.c
 create mode 100644 advice.h
 create mode 100644 alias.c
 create mode 100644 alias.h
 create mode 100644 alloc.c
 create mode 100644 alloc.h
 create mode 100644 apply.c
 create mode 100644 apply.h
 create mode 100644 archive-tar.c
 create mode 100644 archive-zip.c
 create mode 100644 archive.c
 create mode 100644 archive.h
 create mode 100644 attr.c
 create mode 100644 attr.h
 create mode 100644 banned.h
 create mode 100644 base85.c
 create mode 100644 base85.h
 create mode 100644 bin-wrappers/.gitignore
 create mode 100644 bin-wrappers/meson.build
 create mode 100755 bin-wrappers/wrap-for-bin.sh
 create mode 100644 bisect.c
 create mode 100644 bisect.h
 create mode 100644 blame.c
 create mode 100644 blame.h
 create mode 100644 blob.c
 create mode 100644 blob.h
 create mode 100644 block-sha1/sha1.c
 create mode 100644 block-sha1/sha1.h
 create mode 100644 bloom.c
 create mode 100644 bloom.h
 create mode 100644 branch.c
 create mode 100644 branch.h
 create mode 100644 builtin.h
 create mode 100644 builtin/add.c
 create mode 100644 builtin/am.c
 create mode 100644 builtin/annotate.c
 create mode 100644 builtin/apply.c
 create mode 100644 builtin/archive.c
 create mode 100644 builtin/bisect.c
 create mode 100644 builtin/blame.c
 create mode 100644 builtin/branch.c
 create mode 100644 builtin/bugreport.c
 create mode 100644 builtin/bundle.c
 create mode 100644 builtin/cat-file.c
 create mode 100644 builtin/check-attr.c
 create mode 100644 builtin/check-ignore.c
 create mode 100644 builtin/check-mailmap.c
 create mode 100644 builtin/check-ref-format.c
 create mode 100644 builtin/checkout--worker.c
 create mode 100644 builtin/checkout-index.c
 create mode 100644 builtin/checkout.c
 create mode 100644 builtin/clean.c
 create mode 100644 builtin/clone.c
 create mode 100644 builtin/column.c
 create mode 100644 builtin/commit-graph.c
 create mode 100644 builtin/commit-tree.c
 create mode 100644 builtin/commit.c
 create mode 100644 builtin/config.c
 create mode 100644 builtin/count-objects.c
 create mode 100644 builtin/credential-cache--daemon.c
 create mode 100644 builtin/credential-cache.c
 create mode 100644 builtin/credential-store.c
 create mode 100644 builtin/credential.c
 create mode 100644 builtin/describe.c
 create mode 100644 builtin/diagnose.c
 create mode 100644 builtin/diff-files.c
 create mode 100644 builtin/diff-index.c
 create mode 100644 builtin/diff-tree.c
 create mode 100644 builtin/diff.c
 create mode 100644 builtin/difftool.c
 create mode 100644 builtin/fast-export.c
 create mode 100644 builtin/fast-import.c
 create mode 100644 builtin/fetch-pack.c
 create mode 100644 builtin/fetch.c
 create mode 100644 builtin/fmt-merge-msg.c
 create mode 100644 builtin/for-each-ref.c
 create mode 100644 builtin/for-each-repo.c
 create mode 100644 builtin/fsck.c
 create mode 100644 builtin/fsmonitor--daemon.c
 create mode 100644 builtin/gc.c
 create mode 100644 builtin/get-tar-commit-id.c
 create mode 100644 builtin/grep.c
 create mode 100644 builtin/hash-object.c
 create mode 100644 builtin/help.c
 create mode 100644 builtin/hook.c
 create mode 100644 builtin/index-pack.c
 create mode 100644 builtin/init-db.c
 create mode 100644 builtin/interpret-trailers.c
 create mode 100644 builtin/log.c
 create mode 100644 builtin/ls-files.c
 create mode 100644 builtin/ls-remote.c
 create mode 100644 builtin/ls-tree.c
 create mode 100644 builtin/mailinfo.c
 create mode 100644 builtin/mailsplit.c
 create mode 100644 builtin/merge-base.c
 create mode 100644 builtin/merge-file.c
 create mode 100644 builtin/merge-index.c
 create mode 100644 builtin/merge-ours.c
 create mode 100644 builtin/merge-recursive.c
 create mode 100644 builtin/merge-tree.c
 create mode 100644 builtin/merge.c
 create mode 100644 builtin/mktag.c
 create mode 100644 builtin/mktree.c
 create mode 100644 builtin/multi-pack-index.c
 create mode 100644 builtin/mv.c
 create mode 100644 builtin/name-rev.c
 create mode 100644 builtin/notes.c
 create mode 100644 builtin/pack-objects.c
 create mode 100644 builtin/pack-redundant.c
 create mode 100644 builtin/pack-refs.c
 create mode 100644 builtin/patch-id.c
 create mode 100644 builtin/prune-packed.c
 create mode 100644 builtin/prune.c
 create mode 100644 builtin/pull.c
 create mode 100644 builtin/push.c
 create mode 100644 builtin/range-diff.c
 create mode 100644 builtin/read-tree.c
 create mode 100644 builtin/rebase.c
 create mode 100644 builtin/receive-pack.c
 create mode 100644 builtin/reflog.c
 create mode 100644 builtin/refs.c
 create mode 100644 builtin/remote-ext.c
 create mode 100644 builtin/remote-fd.c
 create mode 100644 builtin/remote.c
 create mode 100644 builtin/repack.c
 create mode 100644 builtin/replace.c
 create mode 100644 builtin/replay.c
 create mode 100644 builtin/rerere.c
 create mode 100644 builtin/reset.c
 create mode 100644 builtin/rev-list.c
 create mode 100644 builtin/rev-parse.c
 create mode 100644 builtin/revert.c
 create mode 100644 builtin/rm.c
 create mode 100644 builtin/send-pack.c
 create mode 100644 builtin/shortlog.c
 create mode 100644 builtin/show-branch.c
 create mode 100644 builtin/show-index.c
 create mode 100644 builtin/show-ref.c
 create mode 100644 builtin/sparse-checkout.c
 create mode 100644 builtin/stash.c
 create mode 100644 builtin/stripspace.c
 create mode 100644 builtin/submodule--helper.c
 create mode 100644 builtin/symbolic-ref.c
 create mode 100644 builtin/tag.c
 create mode 100644 builtin/unpack-file.c
 create mode 100644 builtin/unpack-objects.c
 create mode 100644 builtin/update-index.c
 create mode 100644 builtin/update-ref.c
 create mode 100644 builtin/update-server-info.c
 create mode 100644 builtin/upload-archive.c
 create mode 100644 builtin/upload-pack.c
 create mode 100644 builtin/var.c
 create mode 100644 builtin/verify-commit.c
 create mode 100644 builtin/verify-pack.c
 create mode 100644 builtin/verify-tag.c
 create mode 100644 builtin/worktree.c
 create mode 100644 builtin/write-tree.c
 create mode 100644 bulk-checkin.c
 create mode 100644 bulk-checkin.h
 create mode 100644 bundle-uri.c
 create mode 100644 bundle-uri.h
 create mode 100644 bundle.c
 create mode 100644 bundle.h
 create mode 100644 cache-tree.c
 create mode 100644 cache-tree.h
 create mode 100644 cbtree.c
 create mode 100644 cbtree.h
 create mode 100644 chdir-notify.c
 create mode 100644 chdir-notify.h
 create mode 100755 check-builtins.sh
 create mode 100644 checkout.c
 create mode 100644 checkout.h
 create mode 100644 chunk-format.c
 create mode 100644 chunk-format.h
 create mode 100755 ci/check-directional-formatting.bash
 create mode 100755 ci/check-whitespace.sh
 create mode 100644 ci/config/README
 create mode 100755 ci/install-dependencies.sh
 create mode 100755 ci/install-sdk.ps1
 create mode 100755 ci/lib.sh
 create mode 100755 ci/make-test-artifacts.sh
 create mode 100755 ci/mount-fileshare.sh
 create mode 100755 ci/print-test-failures.sh
 create mode 100755 ci/run-build-and-minimal-fuzzers.sh
 create mode 100755 ci/run-build-and-tests.sh
 create mode 100755 ci/run-static-analysis.sh
 create mode 100755 ci/run-style-check.sh
 create mode 100755 ci/run-test-slice.sh
 create mode 100755 ci/test-documentation.sh
 create mode 100755 ci/util/extract-trash-dirs.sh
 create mode 100644 color.c
 create mode 100644 color.h
 create mode 100644 column.c
 create mode 100644 column.h
 create mode 100644 combine-diff.c
 create mode 100644 command-list.txt
 create mode 100644 commit-graph.c
 create mode 100644 commit-graph.h
 create mode 100644 commit-reach.c
 create mode 100644 commit-reach.h
 create mode 100644 commit-slab-decl.h
 create mode 100644 commit-slab-impl.h
 create mode 100644 commit-slab.h
 create mode 100644 commit.c
 create mode 100644 commit.h
 create mode 100644 common-main.c
 create mode 100644 compat/.gitattributes
 create mode 100644 compat/access.c
 create mode 100644 compat/apple-common-crypto.h
 create mode 100644 compat/basename.c
 create mode 100644 compat/bswap.h
 create mode 100644 compat/compiler.h
 create mode 100644 compat/disk.h
 create mode 100644 compat/fileno.c
 create mode 100644 compat/fopen.c
 create mode 100644 compat/fsmonitor/fsm-darwin-gcc.h
 create mode 100644 compat/fsmonitor/fsm-health-darwin.c
 create mode 100644 compat/fsmonitor/fsm-health-win32.c
 create mode 100644 compat/fsmonitor/fsm-health.h
 create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c
 create mode 100644 compat/fsmonitor/fsm-ipc-win32.c
 create mode 100644 compat/fsmonitor/fsm-listen-darwin.c
 create mode 100644 compat/fsmonitor/fsm-listen-win32.c
 create mode 100644 compat/fsmonitor/fsm-listen.h
 create mode 100644 compat/fsmonitor/fsm-path-utils-darwin.c
 create mode 100644 compat/fsmonitor/fsm-path-utils-win32.c
 create mode 100644 compat/fsmonitor/fsm-settings-darwin.c
 create mode 100644 compat/fsmonitor/fsm-settings-win32.c
 create mode 100644 compat/hstrerror.c
 create mode 100644 compat/inet_ntop.c
 create mode 100644 compat/inet_pton.c
 create mode 100644 compat/linux/procinfo.c
 create mode 100644 compat/memmem.c
 create mode 100644 compat/mingw.c
 create mode 100644 compat/mingw.h
 create mode 100644 compat/mkdir.c
 create mode 100644 compat/mkdtemp.c
 create mode 100644 compat/mmap.c
 create mode 100644 compat/msvc.c
 create mode 100644 compat/msvc.h
 create mode 100644 compat/nedmalloc/License.txt
 create mode 100644 compat/nedmalloc/Readme.txt
 create mode 100644 compat/nedmalloc/malloc.c.h
 create mode 100644 compat/nedmalloc/nedmalloc.c
 create mode 100644 compat/nedmalloc/nedmalloc.h
 create mode 100644 compat/nonblock.c
 create mode 100644 compat/nonblock.h
 create mode 100644 compat/obstack.c
 create mode 100644 compat/obstack.h
 create mode 100644 compat/open.c
 create mode 100644 compat/poll/poll.c
 create mode 100644 compat/poll/poll.h
 create mode 100644 compat/pread.c
 create mode 100644 compat/precompose_utf8.c
 create mode 100644 compat/precompose_utf8.h
 create mode 100644 compat/qsort_s.c
 create mode 100644 compat/regcomp_enhanced.c
 create mode 100644 compat/regex/regcomp.c
 create mode 100644 compat/regex/regex.c
 create mode 100644 compat/regex/regex.h
 create mode 100644 compat/regex/regex_internal.c
 create mode 100644 compat/regex/regex_internal.h
 create mode 100644 compat/regex/regexec.c
 create mode 100644 compat/setenv.c
 create mode 100644 compat/sha1-chunked.c
 create mode 100644 compat/sha1-chunked.h
 create mode 100644 compat/simple-ipc/ipc-shared.c
 create mode 100644 compat/simple-ipc/ipc-unix-socket.c
 create mode 100644 compat/simple-ipc/ipc-win32.c
 create mode 100644 compat/snprintf.c
 create mode 100644 compat/stat.c
 create mode 100644 compat/strcasestr.c
 create mode 100644 compat/strdup.c
 create mode 100644 compat/strlcpy.c
 create mode 100644 compat/strtoimax.c
 create mode 100644 compat/strtoumax.c
 create mode 100644 compat/stub/procinfo.c
 create mode 100644 compat/terminal.c
 create mode 100644 compat/terminal.h
 create mode 100644 compat/unsetenv.c
 create mode 100644 compat/vcbuild/.gitignore
 create mode 100644 compat/vcbuild/README
 create mode 100644 compat/vcbuild/find_vs_env.bat
 create mode 100644 compat/vcbuild/include/sys/param.h
 create mode 100644 compat/vcbuild/include/sys/time.h
 create mode 100644 compat/vcbuild/include/sys/utime.h
 create mode 100644 compat/vcbuild/include/unistd.h
 create mode 100644 compat/vcbuild/include/utime.h
 create mode 100755 compat/vcbuild/scripts/clink.pl
 create mode 100755 compat/vcbuild/scripts/lib.pl
 create mode 100644 compat/vcbuild/vcpkg_copy_dlls.bat
 create mode 100644 compat/vcbuild/vcpkg_install.bat
 create mode 100644 compat/win32.h
 create mode 100644 compat/win32/alloca.h
 create mode 100644 compat/win32/dirent.c
 create mode 100644 compat/win32/dirent.h
 create mode 100644 compat/win32/flush.c
 create mode 100644 compat/win32/git.manifest
 create mode 100644 compat/win32/headless.c
 create mode 100644 compat/win32/lazyload.h
 create mode 100644 compat/win32/path-utils.c
 create mode 100644 compat/win32/path-utils.h
 create mode 100644 compat/win32/pthread.c
 create mode 100644 compat/win32/pthread.h
 create mode 100644 compat/win32/syslog.c
 create mode 100644 compat/win32/syslog.h
 create mode 100644 compat/win32/trace2_win32_process_info.c
 create mode 100644 compat/win32mmap.c
 create mode 100644 compat/winansi.c
 create mode 100644 compat/zlib-uncompress2.c
 create mode 100644 config.c
 create mode 100644 config.h
 create mode 100644 config.mak.dev
 create mode 100644 config.mak.in
 create mode 100644 config.mak.uname
 create mode 100644 configure.ac
 create mode 100644 connect.c
 create mode 100644 connect.h
 create mode 100644 connected.c
 create mode 100644 connected.h
 create mode 100644 contrib/README
 create mode 100644 contrib/buildsystems/CMakeLists.txt
 create mode 100644 contrib/buildsystems/Generators.pm
 create mode 100644 contrib/buildsystems/Generators/QMake.pm
 create mode 100644 contrib/buildsystems/Generators/Vcproj.pm
 create mode 100644 contrib/buildsystems/Generators/Vcxproj.pm
 create mode 100755 contrib/buildsystems/engine.pl
 create mode 100755 contrib/buildsystems/generate
 create mode 100644 contrib/buildsystems/git-version.in
 create mode 100755 contrib/buildsystems/parse.pl
 create mode 100644 contrib/coccinelle/.gitignore
 create mode 100644 contrib/coccinelle/README
 create mode 100644 contrib/coccinelle/array.cocci
 create mode 100644 contrib/coccinelle/commit.cocci
 create mode 100644 contrib/coccinelle/config_fn_ctx.pending.cocci
 create mode 100644 contrib/coccinelle/equals-null.cocci
 create mode 100644 contrib/coccinelle/flex_alloc.cocci
 create mode 100644 contrib/coccinelle/free.cocci
 create mode 100644 contrib/coccinelle/git_config_number.cocci
 create mode 100644 contrib/coccinelle/hashmap.cocci
 create mode 100644 contrib/coccinelle/index-compatibility.cocci
 create mode 100644 contrib/coccinelle/object_id.cocci
 create mode 100644 contrib/coccinelle/preincr.cocci
 create mode 100644 contrib/coccinelle/qsort.cocci
 create mode 100644 contrib/coccinelle/refs.cocci
 create mode 100755 contrib/coccinelle/spatchcache
 create mode 100644 contrib/coccinelle/strbuf.cocci
 create mode 100644 contrib/coccinelle/swap.cocci
 create mode 100644 contrib/coccinelle/tests/free.c
 create mode 100644 contrib/coccinelle/tests/free.res
 create mode 100644 contrib/coccinelle/the_repository.cocci
 create mode 100644 contrib/coccinelle/xcalloc.cocci
 create mode 100644 contrib/coccinelle/xopen.cocci
 create mode 100644 contrib/coccinelle/xstrdup_or_null.cocci
 create mode 100644 contrib/coccinelle/xstrncmpz.cocci
 create mode 100644 contrib/completion/.gitattributes
 create mode 100644 contrib/completion/git-completion.bash
 create mode 100644 contrib/completion/git-completion.tcsh
 create mode 100644 contrib/completion/git-completion.zsh
 create mode 100644 contrib/completion/git-prompt.sh
 create mode 100644 contrib/completion/meson.build
 create mode 100644 contrib/contacts/.gitignore
 create mode 100644 contrib/contacts/Makefile
 create mode 100755 contrib/contacts/git-contacts
 create mode 100644 contrib/contacts/git-contacts.txt
 create mode 100755 contrib/coverage-diff.sh
 create mode 100644 contrib/credential/libsecret/.gitignore
 create mode 100644 contrib/credential/libsecret/Makefile
 create mode 100644 contrib/credential/libsecret/git-credential-libsecret.c
 create mode 100644 contrib/credential/netrc/.gitignore
 create mode 100644 contrib/credential/netrc/Makefile
 create mode 100755 contrib/credential/netrc/git-credential-netrc.perl
 create mode 100755 contrib/credential/netrc/t-git-credential-netrc.sh
 create mode 100755 contrib/credential/netrc/test.command-option-gpg
 create mode 100755 contrib/credential/netrc/test.git-config-gpg
 create mode 100644 contrib/credential/netrc/test.netrc
 create mode 100644 contrib/credential/netrc/test.netrc.gpg
 create mode 100755 contrib/credential/netrc/test.pl
 create mode 100644 contrib/credential/osxkeychain/.gitignore
 create mode 100644 contrib/credential/osxkeychain/Makefile
 create mode 100644 contrib/credential/osxkeychain/git-credential-osxkeychain.c
 create mode 100644 contrib/credential/wincred/Makefile
 create mode 100644 contrib/credential/wincred/git-credential-wincred.c
 create mode 100644 contrib/diff-highlight/.gitignore
 create mode 100644 contrib/diff-highlight/DiffHighlight.pm
 create mode 100644 contrib/diff-highlight/Makefile
 create mode 100644 contrib/diff-highlight/README
 create mode 100644 contrib/diff-highlight/diff-highlight.perl
 create mode 100644 contrib/diff-highlight/t/.gitignore
 create mode 100644 contrib/diff-highlight/t/Makefile
 create mode 100755 contrib/diff-highlight/t/t9400-diff-highlight.sh
 create mode 100644 contrib/emacs/README
 create mode 100644 contrib/emacs/git-blame.el
 create mode 100644 contrib/emacs/git.el
 create mode 100644 contrib/examples/README
 create mode 100755 contrib/fast-import/git-import.perl
 create mode 100755 contrib/fast-import/git-import.sh
 create mode 100644 contrib/fast-import/git-p4.README
 create mode 100755 contrib/fast-import/import-directories.perl
 create mode 100755 contrib/fast-import/import-tars.perl
 create mode 100755 contrib/fast-import/import-zips.py
 create mode 100644 contrib/git-jump/README
 create mode 100755 contrib/git-jump/git-jump
 create mode 100755 contrib/git-resurrect.sh
 create mode 100644 contrib/git-shell-commands/README
 create mode 100755 contrib/git-shell-commands/help
 create mode 100755 contrib/git-shell-commands/list
 create mode 100644 contrib/hooks/multimail/README.Git
 create mode 100755 contrib/hooks/post-receive-email
 create mode 100755 contrib/hooks/pre-auto-gc-battery
 create mode 100755 contrib/hooks/setgitperms.perl
 create mode 100755 contrib/hooks/update-paranoid
 create mode 100755 contrib/long-running-filter/example.pl
 create mode 100644 contrib/meson.build
 create mode 100644 contrib/mw-to-git/.gitignore
 create mode 100644 contrib/mw-to-git/.perlcriticrc
 create mode 100644 contrib/mw-to-git/Git/Mediawiki.pm
 create mode 100644 contrib/mw-to-git/Makefile
 create mode 100755 contrib/mw-to-git/bin-wrapper/git
 create mode 100755 contrib/mw-to-git/git-mw.perl
 create mode 100755 contrib/mw-to-git/git-remote-mediawiki.perl
 create mode 100644 contrib/mw-to-git/git-remote-mediawiki.txt
 create mode 100644 contrib/mw-to-git/t/.gitignore
 create mode 100644 contrib/mw-to-git/t/Makefile
 create mode 100644 contrib/mw-to-git/t/README
 create mode 100755 contrib/mw-to-git/t/install-wiki.sh
 create mode 100644 contrib/mw-to-git/t/push-pull-tests.sh
 create mode 100755 contrib/mw-to-git/t/t9360-mw-to-git-clone.sh
 create mode 100755 contrib/mw-to-git/t/t9361-mw-to-git-push-pull.sh
 create mode 100755 contrib/mw-to-git/t/t9362-mw-to-git-utf8.sh
 create mode 100755 contrib/mw-to-git/t/t9363-mw-to-git-export-import.sh
 create mode 100755 contrib/mw-to-git/t/t9364-pull-by-rev.sh
 create mode 100755 contrib/mw-to-git/t/t9365-continuing-queries.sh
 create mode 100755 contrib/mw-to-git/t/test-gitmw-lib.sh
 create mode 100755 contrib/mw-to-git/t/test-gitmw.pl
 create mode 100644 contrib/mw-to-git/t/test.config
 create mode 100644 contrib/persistent-https/LICENSE
 create mode 100644 contrib/persistent-https/Makefile
 create mode 100644 contrib/persistent-https/README
 create mode 100644 contrib/persistent-https/client.go
 create mode 100644 contrib/persistent-https/main.go
 create mode 100644 contrib/persistent-https/proxy.go
 create mode 100644 contrib/persistent-https/socket.go
 create mode 100644 contrib/remote-helpers/README
 create mode 100755 contrib/remote-helpers/git-remote-bzr
 create mode 100755 contrib/remote-helpers/git-remote-hg
 create mode 100755 contrib/remotes2config.sh
 create mode 100755 contrib/rerere-train.sh
 create mode 100755 contrib/stats/git-common-hash
 create mode 100755 contrib/stats/mailmap.pl
 create mode 100755 contrib/stats/packinfo.pl
 create mode 100644 contrib/subtree/.gitignore
 create mode 100644 contrib/subtree/COPYING
 create mode 100644 contrib/subtree/INSTALL
 create mode 100644 contrib/subtree/Makefile
 create mode 100644 contrib/subtree/README
 create mode 100755 contrib/subtree/git-subtree.sh
 create mode 100644 contrib/subtree/git-subtree.txt
 create mode 100644 contrib/subtree/meson.build
 create mode 100644 contrib/subtree/t/Makefile
 create mode 100755 contrib/subtree/t/t7900-subtree.sh
 create mode 100644 contrib/subtree/todo
 create mode 100644 contrib/thunderbird-patch-inline/README
 create mode 100755 contrib/thunderbird-patch-inline/appp.sh
 create mode 100644 contrib/update-unicode/.gitignore
 create mode 100644 contrib/update-unicode/README
 create mode 100755 contrib/update-unicode/update_unicode.sh
 create mode 100644 contrib/vscode/.gitattributes
 create mode 100644 contrib/vscode/README.md
 create mode 100755 contrib/vscode/init.sh
 create mode 100644 contrib/workdir/.gitattributes
 create mode 100755 contrib/workdir/git-new-workdir
 create mode 100644 convert.c
 create mode 100644 convert.h
 create mode 100644 copy.c
 create mode 100644 copy.h
 create mode 100644 credential.c
 create mode 100644 credential.h
 create mode 100644 csum-file.c
 create mode 100644 csum-file.h
 create mode 100644 ctype.c
 create mode 100644 daemon.c
 create mode 100644 date.c
 create mode 100644 date.h
 create mode 100644 decorate.c
 create mode 100644 decorate.h
 create mode 100644 delta-islands.c
 create mode 100644 delta-islands.h
 create mode 100644 delta.h
 create mode 100755 detect-compiler
 create mode 100644 diagnose.c
 create mode 100644 diagnose.h
 create mode 100644 diff-delta.c
 create mode 100644 diff-lib.c
 create mode 100644 diff-merges.c
 create mode 100644 diff-merges.h
 create mode 100644 diff-no-index.c
 create mode 100644 diff.c
 create mode 100644 diff.h
 create mode 100644 diffcore-break.c
 create mode 100644 diffcore-delta.c
 create mode 100644 diffcore-order.c
 create mode 100644 diffcore-pickaxe.c
 create mode 100644 diffcore-rename.c
 create mode 100644 diffcore-rotate.c
 create mode 100644 diffcore.h
 create mode 100644 dir-iterator.c
 create mode 100644 dir-iterator.h
 create mode 100644 dir.c
 create mode 100644 dir.h
 create mode 100644 editor.c
 create mode 100644 editor.h
 create mode 100644 entry.c
 create mode 100644 entry.h
 create mode 100644 environment.c
 create mode 100644 environment.h
 create mode 100644 ewah/bitmap.c
 create mode 100644 ewah/ewah_bitmap.c
 create mode 100644 ewah/ewah_io.c
 create mode 100644 ewah/ewah_rlw.c
 create mode 100644 ewah/ewok.h
 create mode 100644 ewah/ewok_rlw.h
 create mode 100644 exec-cmd.c
 create mode 100644 exec-cmd.h
 create mode 100644 fetch-negotiator.c
 create mode 100644 fetch-negotiator.h
 create mode 100644 fetch-pack.c
 create mode 100644 fetch-pack.h
 create mode 100644 fmt-merge-msg.c
 create mode 100644 fmt-merge-msg.h
 create mode 100644 fsck.c
 create mode 100644 fsck.h
 create mode 100644 fsmonitor--daemon.h
 create mode 100644 fsmonitor-ipc.c
 create mode 100644 fsmonitor-ipc.h
 create mode 100644 fsmonitor-ll.h
 create mode 100644 fsmonitor-path-utils.h
 create mode 100644 fsmonitor-settings.c
 create mode 100644 fsmonitor-settings.h
 create mode 100644 fsmonitor.c
 create mode 100644 fsmonitor.h
 create mode 100755 generate-cmdlist.sh
 create mode 100755 generate-configlist.sh
 create mode 100755 generate-hooklist.sh
 create mode 100755 generate-perl.sh
 create mode 100755 generate-python.sh
 create mode 100755 generate-script.sh
 create mode 100644 gettext.c
 create mode 100644 gettext.h
 create mode 100755 git-archimport.perl
 create mode 100644 git-compat-util.h
 create mode 100644 git-curl-compat.h
 create mode 100755 git-cvsexportcommit.perl
 create mode 100755 git-cvsimport.perl
 create mode 100755 git-cvsserver.perl
 create mode 100755 git-difftool--helper.sh
 create mode 100755 git-filter-branch.sh
 create mode 100644 git-gui/.gitattributes
 create mode 100644 git-gui/.gitignore
 create mode 100755 git-gui/GIT-VERSION-GEN
 create mode 100644 git-gui/Makefile
 create mode 100644 git-gui/README.md
 create mode 100755 git-gui/git-gui--askpass
 create mode 100755 git-gui/git-gui.sh
 create mode 100644 git-gui/lib/about.tcl
 create mode 100644 git-gui/lib/blame.tcl
 create mode 100644 git-gui/lib/branch.tcl
 create mode 100644 git-gui/lib/branch_checkout.tcl
 create mode 100644 git-gui/lib/branch_create.tcl
 create mode 100644 git-gui/lib/branch_delete.tcl
 create mode 100644 git-gui/lib/branch_rename.tcl
 create mode 100644 git-gui/lib/browser.tcl
 create mode 100644 git-gui/lib/checkout_op.tcl
 create mode 100644 git-gui/lib/choose_font.tcl
 create mode 100644 git-gui/lib/choose_repository.tcl
 create mode 100644 git-gui/lib/choose_rev.tcl
 create mode 100644 git-gui/lib/chord.tcl
 create mode 100644 git-gui/lib/class.tcl
 create mode 100644 git-gui/lib/commit.tcl
 create mode 100644 git-gui/lib/console.tcl
 create mode 100644 git-gui/lib/database.tcl
 create mode 100644 git-gui/lib/date.tcl
 create mode 100644 git-gui/lib/diff.tcl
 create mode 100644 git-gui/lib/encoding.tcl
 create mode 100644 git-gui/lib/error.tcl
 create mode 100644 git-gui/lib/git-gui.ico
 create mode 100644 git-gui/lib/index.tcl
 create mode 100644 git-gui/lib/line.tcl
 create mode 100644 git-gui/lib/logo.tcl
 create mode 100644 git-gui/lib/merge.tcl
 create mode 100644 git-gui/lib/mergetool.tcl
 create mode 100644 git-gui/lib/option.tcl
 create mode 100644 git-gui/lib/remote.tcl
 create mode 100644 git-gui/lib/remote_add.tcl
 create mode 100644 git-gui/lib/remote_branch_delete.tcl
 create mode 100644 git-gui/lib/search.tcl
 create mode 100644 git-gui/lib/shortcut.tcl
 create mode 100644 git-gui/lib/spellcheck.tcl
 create mode 100644 git-gui/lib/sshkey.tcl
 create mode 100644 git-gui/lib/status_bar.tcl
 create mode 100644 git-gui/lib/themed.tcl
 create mode 100644 git-gui/lib/tools.tcl
 create mode 100644 git-gui/lib/tools_dlg.tcl
 create mode 100644 git-gui/lib/transport.tcl
 create mode 100644 git-gui/lib/win32.tcl
 create mode 100644 git-gui/lib/win32_shortcut.js
 create mode 100644 git-gui/macosx/AppMain.tcl
 create mode 100644 git-gui/macosx/Info.plist
 create mode 100644 git-gui/macosx/git-gui.icns
 create mode 100644 git-gui/po/.gitignore
 create mode 100644 git-gui/po/README
 create mode 100644 git-gui/po/bg.po
 create mode 100644 git-gui/po/de.po
 create mode 100644 git-gui/po/el.po
 create mode 100644 git-gui/po/fr.po
 create mode 100644 git-gui/po/git-gui.pot
 create mode 100644 git-gui/po/glossary/Makefile
 create mode 100644 git-gui/po/glossary/bg.po
 create mode 100644 git-gui/po/glossary/de.po
 create mode 100644 git-gui/po/glossary/el.po
 create mode 100644 git-gui/po/glossary/fr.po
 create mode 100644 git-gui/po/glossary/git-gui-glossary.pot
 create mode 100644 git-gui/po/glossary/git-gui-glossary.txt
 create mode 100644 git-gui/po/glossary/it.po
 create mode 100644 git-gui/po/glossary/pt_br.po
 create mode 100644 git-gui/po/glossary/pt_pt.po
 create mode 100755 git-gui/po/glossary/txt-to-pot.sh
 create mode 100644 git-gui/po/glossary/zh_cn.po
 create mode 100644 git-gui/po/hu.po
 create mode 100644 git-gui/po/it.po
 create mode 100644 git-gui/po/ja.po
 create mode 100644 git-gui/po/nb.po
 create mode 100755 git-gui/po/po2msg.sh
 create mode 100644 git-gui/po/pt_br.po
 create mode 100644 git-gui/po/pt_pt.po
 create mode 100644 git-gui/po/ru.po
 create mode 100644 git-gui/po/sv.po
 create mode 100644 git-gui/po/vi.po
 create mode 100644 git-gui/po/zh_cn.po
 create mode 100755 git-gui/windows/git-gui.sh
 create mode 100755 git-instaweb.sh
 create mode 100755 git-merge-octopus.sh
 create mode 100755 git-merge-one-file.sh
 create mode 100755 git-merge-resolve.sh
 create mode 100644 git-mergetool--lib.sh
 create mode 100755 git-mergetool.sh
 create mode 100755 git-p4.py
 create mode 100755 git-quiltimport.sh
 create mode 100755 git-request-pull.sh
 create mode 100755 git-send-email.perl
 create mode 100644 git-sh-i18n.sh
 create mode 100644 git-sh-setup.sh
 create mode 100755 git-submodule.sh
 create mode 100755 git-svn.perl
 create mode 100755 git-web--browse.sh
 create mode 100644 git-zlib.c
 create mode 100644 git-zlib.h
 create mode 100644 git.c
 create mode 100644 git.rc.in
 create mode 100644 gitk-git/.gitignore
 create mode 100644 gitk-git/Makefile
 create mode 100755 gitk-git/gitk
 create mode 100644 gitk-git/po/.gitignore
 create mode 100644 gitk-git/po/bg.po
 create mode 100644 gitk-git/po/ca.po
 create mode 100644 gitk-git/po/de.po
 create mode 100644 gitk-git/po/es.po
 create mode 100644 gitk-git/po/fr.po
 create mode 100644 gitk-git/po/hu.po
 create mode 100644 gitk-git/po/it.po
 create mode 100644 gitk-git/po/ja.po
 create mode 100755 gitk-git/po/po2msg.sh
 create mode 100644 gitk-git/po/pt_br.po
 create mode 100644 gitk-git/po/pt_pt.po
 create mode 100644 gitk-git/po/ru.po
 create mode 100644 gitk-git/po/sv.po
 create mode 100644 gitk-git/po/vi.po
 create mode 100644 gitk-git/po/zh_cn.po
 create mode 100644 gitweb/GITWEB-BUILD-OPTIONS.in
 create mode 100644 gitweb/INSTALL
 create mode 100644 gitweb/Makefile
 create mode 100644 gitweb/README
 create mode 100755 gitweb/generate-gitweb-cgi.sh
 create mode 100755 gitweb/generate-gitweb-js.sh
 create mode 100755 gitweb/gitweb.perl
 create mode 100644 gitweb/meson.build
 create mode 100644 gitweb/static/git-favicon.png
 create mode 100644 gitweb/static/git-logo.png
 create mode 100644 gitweb/static/gitweb.css
 create mode 100644 gitweb/static/js/README
 create mode 100644 gitweb/static/js/adjust-timezone.js
 create mode 100644 gitweb/static/js/blame_incremental.js
 create mode 100644 gitweb/static/js/javascript-detection.js
 create mode 100644 gitweb/static/js/lib/common-lib.js
 create mode 100644 gitweb/static/js/lib/cookies.js
 create mode 100644 gitweb/static/js/lib/datetime.js
 create mode 100644 gpg-interface.c
 create mode 100644 gpg-interface.h
 create mode 100644 graph.c
 create mode 100644 graph.h
 create mode 100644 grep.c
 create mode 100644 grep.h
 create mode 100644 hash-lookup.c
 create mode 100644 hash-lookup.h
 create mode 100644 hash.h
 create mode 100644 hashmap.c
 create mode 100644 hashmap.h
 create mode 100644 help.c
 create mode 100644 help.h
 create mode 100644 hex-ll.c
 create mode 100644 hex-ll.h
 create mode 100644 hex.c
 create mode 100644 hex.h
 create mode 100644 hook.c
 create mode 100644 hook.h
 create mode 100644 http-backend.c
 create mode 100644 http-fetch.c
 create mode 100644 http-push.c
 create mode 100644 http-walker.c
 create mode 100644 http.c
 create mode 100644 http.h
 create mode 100644 ident.c
 create mode 100644 ident.h
 create mode 100644 imap-send.c
 create mode 100644 iterator.h
 create mode 100644 json-writer.c
 create mode 100644 json-writer.h
 create mode 100644 khash.h
 create mode 100644 kwset.c
 create mode 100644 kwset.h
 create mode 100644 levenshtein.c
 create mode 100644 levenshtein.h
 create mode 100644 line-log.c
 create mode 100644 line-log.h
 create mode 100644 line-range.c
 create mode 100644 line-range.h
 create mode 100644 linear-assignment.c
 create mode 100644 linear-assignment.h
 create mode 100644 list-objects-filter-options.c
 create mode 100644 list-objects-filter-options.h
 create mode 100644 list-objects-filter.c
 create mode 100644 list-objects-filter.h
 create mode 100644 list-objects.c
 create mode 100644 list-objects.h
 create mode 100644 list.h
 create mode 100644 lockfile.c
 create mode 100644 lockfile.h
 create mode 100644 log-tree.c
 create mode 100644 log-tree.h
 create mode 100644 loose.c
 create mode 100644 loose.h
 create mode 100644 ls-refs.c
 create mode 100644 ls-refs.h
 create mode 100644 mailinfo.c
 create mode 100644 mailinfo.h
 create mode 100644 mailmap.c
 create mode 100644 mailmap.h
 create mode 100644 match-trees.c
 create mode 100644 match-trees.h
 create mode 100644 mem-pool.c
 create mode 100644 mem-pool.h
 create mode 100644 merge-blobs.c
 create mode 100644 merge-blobs.h
 create mode 100644 merge-ll.c
 create mode 100644 merge-ll.h
 create mode 100644 merge-ort-wrappers.c
 create mode 100644 merge-ort-wrappers.h
 create mode 100644 merge-ort.c
 create mode 100644 merge-ort.h
 create mode 100644 merge-recursive.c
 create mode 100644 merge-recursive.h
 create mode 100644 merge.c
 create mode 100644 merge.h
 create mode 100644 mergesort.h
 create mode 100644 mergetools/araxis
 create mode 100644 mergetools/bc
 create mode 100644 mergetools/codecompare
 create mode 100644 mergetools/deltawalker
 create mode 100644 mergetools/diffmerge
 create mode 100644 mergetools/diffuse
 create mode 100644 mergetools/ecmerge
 create mode 100644 mergetools/emerge
 create mode 100644 mergetools/examdiff
 create mode 100644 mergetools/guiffy
 create mode 100644 mergetools/gvimdiff
 create mode 100644 mergetools/kdiff3
 create mode 100644 mergetools/kompare
 create mode 100644 mergetools/meld
 create mode 100644 mergetools/nvimdiff
 create mode 100644 mergetools/opendiff
 create mode 100644 mergetools/p4merge
 create mode 100644 mergetools/smerge
 create mode 100644 mergetools/tkdiff
 create mode 100644 mergetools/tortoisemerge
 create mode 100644 mergetools/vimdiff
 create mode 100644 mergetools/vscode
 create mode 100644 mergetools/winmerge
 create mode 100644 mergetools/xxdiff
 create mode 100644 meson.build
 create mode 100644 meson_options.txt
 create mode 100644 midx-write.c
 create mode 100644 midx.c
 create mode 100644 midx.h
 create mode 100644 name-hash.c
 create mode 100644 name-hash.h
 create mode 100644 negotiator/default.c
 create mode 100644 negotiator/default.h
 create mode 100644 negotiator/noop.c
 create mode 100644 negotiator/noop.h
 create mode 100644 negotiator/skipping.c
 create mode 100644 negotiator/skipping.h
 create mode 100644 notes-cache.c
 create mode 100644 notes-cache.h
 create mode 100644 notes-merge.c
 create mode 100644 notes-merge.h
 create mode 100644 notes-utils.c
 create mode 100644 notes-utils.h
 create mode 100644 notes.c
 create mode 100644 notes.h
 create mode 100644 object-file-convert.c
 create mode 100644 object-file-convert.h
 create mode 100644 object-file.c
 create mode 100644 object-file.h
 create mode 100644 object-name.c
 create mode 100644 object-name.h
 create mode 100644 object-store-ll.h
 create mode 100644 object-store.h
 create mode 100644 object.c
 create mode 100644 object.h
 create mode 100644 oid-array.c
 create mode 100644 oid-array.h
 create mode 100644 oidmap.c
 create mode 100644 oidmap.h
 create mode 100644 oidset.c
 create mode 100644 oidset.h
 create mode 100644 oidtree.c
 create mode 100644 oidtree.h
 create mode 100644 oss-fuzz/.gitignore
 create mode 100644 oss-fuzz/dummy-cmd-main.c
 create mode 100644 oss-fuzz/fuzz-commit-graph.c
 create mode 100644 oss-fuzz/fuzz-config.c
 create mode 100644 oss-fuzz/fuzz-credential-from-url-gently.c
 create mode 100644 oss-fuzz/fuzz-date.c
 create mode 100644 oss-fuzz/fuzz-pack-headers.c
 create mode 100644 oss-fuzz/fuzz-pack-idx.c
 create mode 100644 oss-fuzz/fuzz-parse-attr-line.c
 create mode 100644 oss-fuzz/fuzz-url-decode-mem.c
 create mode 100644 pack-bitmap-write.c
 create mode 100644 pack-bitmap.c
 create mode 100644 pack-bitmap.h
 create mode 100644 pack-check.c
 create mode 100644 pack-mtimes.c
 create mode 100644 pack-mtimes.h
 create mode 100644 pack-objects.c
 create mode 100644 pack-objects.h
 create mode 100644 pack-revindex.c
 create mode 100644 pack-revindex.h
 create mode 100644 pack-write.c
 create mode 100644 pack.h
 create mode 100644 packfile.c
 create mode 100644 packfile.h
 create mode 100644 pager.c
 create mode 100644 pager.h
 create mode 100644 parallel-checkout.c
 create mode 100644 parallel-checkout.h
 create mode 100644 parse-options-cb.c
 create mode 100644 parse-options.c
 create mode 100644 parse-options.h
 create mode 100644 parse.c
 create mode 100644 parse.h
 create mode 100644 patch-delta.c
 create mode 100644 patch-ids.c
 create mode 100644 patch-ids.h
 create mode 100644 path-walk.c
 create mode 100644 path-walk.h
 create mode 100644 path.c
 create mode 100644 path.h
 create mode 100644 pathspec.c
 create mode 100644 pathspec.h
 create mode 100644 perl/.gitignore
 create mode 100644 perl/FromCPAN/.gitattributes
 create mode 100644 perl/FromCPAN/Error.pm
 create mode 100644 perl/FromCPAN/Mail/Address.pm
 create mode 100644 perl/FromCPAN/Mail/meson.build
 create mode 100644 perl/FromCPAN/meson.build
 create mode 100644 perl/Git.pm
 create mode 100644 perl/Git/I18N.pm
 create mode 100644 perl/Git/IndexInfo.pm
 create mode 100644 perl/Git/LoadCPAN.pm
 create mode 100644 perl/Git/LoadCPAN/Error.pm
 create mode 100644 perl/Git/LoadCPAN/Mail/Address.pm
 create mode 100644 perl/Git/LoadCPAN/Mail/meson.build
 create mode 100644 perl/Git/LoadCPAN/meson.build
 create mode 100644 perl/Git/Packet.pm
 create mode 100644 perl/Git/SVN.pm
 create mode 100644 perl/Git/SVN/Editor.pm
 create mode 100644 perl/Git/SVN/Fetcher.pm
 create mode 100644 perl/Git/SVN/GlobSpec.pm
 create mode 100644 perl/Git/SVN/Log.pm
 create mode 100644 perl/Git/SVN/Memoize/YAML.pm
 create mode 100644 perl/Git/SVN/Memoize/meson.build
 create mode 100644 perl/Git/SVN/Migration.pm
 create mode 100644 perl/Git/SVN/Prompt.pm
 create mode 100644 perl/Git/SVN/Ra.pm
 create mode 100644 perl/Git/SVN/Utils.pm
 create mode 100644 perl/Git/SVN/meson.build
 create mode 100644 perl/Git/meson.build
 create mode 100644 perl/header_templates/fixed_prefix.template.pl
 create mode 100644 perl/header_templates/runtime_prefix.template.pl
 create mode 100644 perl/meson.build
 create mode 100644 pkt-line.c
 create mode 100644 pkt-line.h
 create mode 100644 po/.gitignore
 create mode 100644 po/README.md
 create mode 100644 po/TEAMS
 create mode 100644 po/bg.po
 create mode 100644 po/ca.po
 create mode 100644 po/de.po
 create mode 100644 po/el.po
 create mode 100644 po/es.po
 create mode 100644 po/fr.po
 create mode 100644 po/id.po
 create mode 100644 po/is.po
 create mode 100644 po/it.po
 create mode 100644 po/ko.po
 create mode 100644 po/meson.build
 create mode 100644 po/pl.po
 create mode 100644 po/pt_PT.po
 create mode 100644 po/ru.po
 create mode 100644 po/sv.po
 create mode 100644 po/tr.po
 create mode 100644 po/uk.po
 create mode 100644 po/vi.po
 create mode 100644 po/zh_CN.po
 create mode 100644 po/zh_TW.po
 create mode 100644 preload-index.c
 create mode 100644 preload-index.h
 create mode 100644 pretty.c
 create mode 100644 pretty.h
 create mode 100644 prio-queue.c
 create mode 100644 prio-queue.h
 create mode 100644 progress.c
 create mode 100644 progress.h
 create mode 100644 promisor-remote.c
 create mode 100644 promisor-remote.h
 create mode 100644 prompt.c
 create mode 100644 prompt.h
 create mode 100644 protocol-caps.c
 create mode 100644 protocol-caps.h
 create mode 100644 protocol.c
 create mode 100644 protocol.h
 create mode 100644 prune-packed.c
 create mode 100644 prune-packed.h
 create mode 100644 pseudo-merge.c
 create mode 100644 pseudo-merge.h
 create mode 100644 quote.c
 create mode 100644 quote.h
 create mode 100644 range-diff.c
 create mode 100644 range-diff.h
 create mode 100644 reachable.c
 create mode 100644 reachable.h
 create mode 100644 read-cache-ll.h
 create mode 100644 read-cache.c
 create mode 100644 read-cache.h
 create mode 100644 rebase-interactive.c
 create mode 100644 rebase-interactive.h
 create mode 100644 rebase.c
 create mode 100644 rebase.h
 create mode 100644 ref-filter.c
 create mode 100644 ref-filter.h
 create mode 100644 reflog-walk.c
 create mode 100644 reflog-walk.h
 create mode 100644 reflog.c
 create mode 100644 reflog.h
 create mode 100644 refs.c
 create mode 100644 refs.h
 create mode 100644 refs/debug.c
 create mode 100644 refs/files-backend.c
 create mode 100644 refs/iterator.c
 create mode 100644 refs/packed-backend.c
 create mode 100644 refs/packed-backend.h
 create mode 100644 refs/ref-cache.c
 create mode 100644 refs/ref-cache.h
 create mode 100644 refs/refs-internal.h
 create mode 100644 refs/reftable-backend.c
 create mode 100644 refspec.c
 create mode 100644 refspec.h
 create mode 100644 reftable/LICENSE
 create mode 100644 reftable/basics.c
 create mode 100644 reftable/basics.h
 create mode 100644 reftable/block.c
 create mode 100644 reftable/block.h
 create mode 100644 reftable/blocksource.c
 create mode 100644 reftable/blocksource.h
 create mode 100644 reftable/constants.h
 create mode 100644 reftable/error.c
 create mode 100644 reftable/iter.c
 create mode 100644 reftable/iter.h
 create mode 100644 reftable/merged.c
 create mode 100644 reftable/merged.h
 create mode 100644 reftable/pq.c
 create mode 100644 reftable/pq.h
 create mode 100644 reftable/reader.c
 create mode 100644 reftable/reader.h
 create mode 100644 reftable/record.c
 create mode 100644 reftable/record.h
 create mode 100644 reftable/reftable-basics.h
 create mode 100644 reftable/reftable-blocksource.h
 create mode 100644 reftable/reftable-error.h
 create mode 100644 reftable/reftable-iterator.h
 create mode 100644 reftable/reftable-merged.h
 create mode 100644 reftable/reftable-reader.h
 create mode 100644 reftable/reftable-record.h
 create mode 100644 reftable/reftable-stack.h
 create mode 100644 reftable/reftable-writer.h
 create mode 100644 reftable/stack.c
 create mode 100644 reftable/stack.h
 create mode 100644 reftable/system.c
 create mode 100644 reftable/system.h
 create mode 100644 reftable/tree.c
 create mode 100644 reftable/tree.h
 create mode 100644 reftable/writer.c
 create mode 100644 reftable/writer.h
 create mode 100644 remote-curl.c
 create mode 100644 remote.c
 create mode 100644 remote.h
 create mode 100644 replace-object.c
 create mode 100644 replace-object.h
 create mode 100644 repo-settings.c
 create mode 100644 repo-settings.h
 create mode 100644 repository.c
 create mode 100644 repository.h
 create mode 100644 rerere.c
 create mode 100644 rerere.h
 create mode 100644 reset.c
 create mode 100644 reset.h
 create mode 100644 resolve-undo.c
 create mode 100644 resolve-undo.h
 create mode 100644 revision.c
 create mode 100644 revision.h
 create mode 100644 run-command.c
 create mode 100644 run-command.h
 create mode 100644 sane-ctype.h
 create mode 100644 scalar.c
 create mode 100644 send-pack.c
 create mode 100644 send-pack.h
 create mode 100644 sequencer.c
 create mode 100644 sequencer.h
 create mode 100644 serve.c
 create mode 100644 serve.h
 create mode 100644 server-info.c
 create mode 100644 server-info.h
 create mode 100644 setup.c
 create mode 100644 setup.h
 create mode 100644 sh-i18n--envsubst.c
 create mode 100644 sha1/openssl.h
 create mode 160000 sha1collisiondetection
 create mode 100644 sha1dc/.gitattributes
 create mode 100644 sha1dc/LICENSE.txt
 create mode 100644 sha1dc/sha1.c
 create mode 100644 sha1dc/sha1.h
 create mode 100644 sha1dc/ubc_check.c
 create mode 100644 sha1dc/ubc_check.h
 create mode 100644 sha1dc_git.c
 create mode 100644 sha1dc_git.h
 create mode 100644 sha256/block/sha256.c
 create mode 100644 sha256/block/sha256.h
 create mode 100644 sha256/gcrypt.h
 create mode 100644 sha256/nettle.h
 create mode 100644 sha256/openssl.h
 create mode 100644 shallow.c
 create mode 100644 shallow.h
 create mode 100644 shared.mak
 create mode 100644 shell.c
 create mode 100644 shortlog.h
 create mode 100644 sideband.c
 create mode 100644 sideband.h
 create mode 100644 sigchain.c
 create mode 100644 sigchain.h
 create mode 100644 simple-ipc.h
 create mode 100644 sparse-index.c
 create mode 100644 sparse-index.h
 create mode 100644 split-index.c
 create mode 100644 split-index.h
 create mode 100644 stable-qsort.c
 create mode 100644 statinfo.c
 create mode 100644 statinfo.h
 create mode 100644 strbuf.c
 create mode 100644 strbuf.h
 create mode 100644 streaming.c
 create mode 100644 streaming.h
 create mode 100644 string-list.c
 create mode 100644 string-list.h
 create mode 100644 strmap.c
 create mode 100644 strmap.h
 create mode 100644 strvec.c
 create mode 100644 strvec.h
 create mode 100644 sub-process.c
 create mode 100644 sub-process.h
 create mode 100644 submodule-config.c
 create mode 100644 submodule-config.h
 create mode 100644 submodule.c
 create mode 100644 submodule.h
 create mode 100644 subprojects/.gitignore
 create mode 100644 subprojects/curl.wrap
 create mode 100644 subprojects/expat.wrap
 create mode 100644 subprojects/openssl.wrap
 create mode 100644 subprojects/pcre2.wrap
 create mode 100644 subprojects/zlib.wrap
 create mode 100644 symlinks.c
 create mode 100644 symlinks.h
 create mode 100644 t/.gitattributes
 create mode 100644 t/.gitignore
 create mode 100755 t/Git-SVN/00compile.t
 create mode 100755 t/Git-SVN/Utils/add_path_to_url.t
 create mode 100755 t/Git-SVN/Utils/can_compress.t
 create mode 100755 t/Git-SVN/Utils/canonicalize_url.t
 create mode 100755 t/Git-SVN/Utils/collapse_dotdot.t
 create mode 100755 t/Git-SVN/Utils/fatal.t
 create mode 100755 t/Git-SVN/Utils/join_paths.t
 create mode 100644 t/Makefile
 create mode 100644 t/README
 create mode 100755 t/aggregate-results.sh
 create mode 100644 t/annotate-tests.sh
 create mode 100644 t/chainlint-cat.pl
 create mode 100755 t/chainlint.pl
 create mode 100644 t/chainlint/arithmetic-expansion.expect
 create mode 100644 t/chainlint/arithmetic-expansion.test
 create mode 100644 t/chainlint/bash-array.expect
 create mode 100644 t/chainlint/bash-array.test
 create mode 100644 t/chainlint/blank-line-before-esac.expect
 create mode 100644 t/chainlint/blank-line-before-esac.test
 create mode 100644 t/chainlint/blank-line.expect
 create mode 100644 t/chainlint/blank-line.test
 create mode 100644 t/chainlint/block-comment.expect
 create mode 100644 t/chainlint/block-comment.test
 create mode 100644 t/chainlint/block.expect
 create mode 100644 t/chainlint/block.test
 create mode 100644 t/chainlint/broken-chain.expect
 create mode 100644 t/chainlint/broken-chain.test
 create mode 100644 t/chainlint/case-comment.expect
 create mode 100644 t/chainlint/case-comment.test
 create mode 100644 t/chainlint/case.expect
 create mode 100644 t/chainlint/case.test
 create mode 100644 t/chainlint/chain-break-background.expect
 create mode 100644 t/chainlint/chain-break-background.test
 create mode 100644 t/chainlint/chain-break-continue.expect
 create mode 100644 t/chainlint/chain-break-continue.test
 create mode 100644 t/chainlint/chain-break-false.expect
 create mode 100644 t/chainlint/chain-break-false.test
 create mode 100644 t/chainlint/chain-break-return-exit.expect
 create mode 100644 t/chainlint/chain-break-return-exit.test
 create mode 100644 t/chainlint/chain-break-status.expect
 create mode 100644 t/chainlint/chain-break-status.test
 create mode 100644 t/chainlint/chained-block.expect
 create mode 100644 t/chainlint/chained-block.test
 create mode 100644 t/chainlint/chained-subshell.expect
 create mode 100644 t/chainlint/chained-subshell.test
 create mode 100644 t/chainlint/close-nested-and-parent-together.expect
 create mode 100644 t/chainlint/close-nested-and-parent-together.test
 create mode 100644 t/chainlint/close-subshell.expect
 create mode 100644 t/chainlint/close-subshell.test
 create mode 100644 t/chainlint/command-substitution-subsubshell.expect
 create mode 100644 t/chainlint/command-substitution-subsubshell.test
 create mode 100644 t/chainlint/command-substitution.expect
 create mode 100644 t/chainlint/command-substitution.test
 create mode 100644 t/chainlint/comment.expect
 create mode 100644 t/chainlint/comment.test
 create mode 100644 t/chainlint/complex-if-in-cuddled-loop.expect
 create mode 100644 t/chainlint/complex-if-in-cuddled-loop.test
 create mode 100644 t/chainlint/cuddled-if-then-else.expect
 create mode 100644 t/chainlint/cuddled-if-then-else.test
 create mode 100644 t/chainlint/cuddled-loop.expect
 create mode 100644 t/chainlint/cuddled-loop.test
 create mode 100644 t/chainlint/cuddled.expect
 create mode 100644 t/chainlint/cuddled.test
 create mode 100644 t/chainlint/double-here-doc.expect
 create mode 100644 t/chainlint/double-here-doc.test
 create mode 100644 t/chainlint/dqstring-line-splice.expect
 create mode 100644 t/chainlint/dqstring-line-splice.test
 create mode 100644 t/chainlint/dqstring-no-interpolate.expect
 create mode 100644 t/chainlint/dqstring-no-interpolate.test
 create mode 100644 t/chainlint/empty-here-doc.expect
 create mode 100644 t/chainlint/empty-here-doc.test
 create mode 100644 t/chainlint/exclamation.expect
 create mode 100644 t/chainlint/exclamation.test
 create mode 100644 t/chainlint/exit-loop.expect
 create mode 100644 t/chainlint/exit-loop.test
 create mode 100644 t/chainlint/exit-subshell.expect
 create mode 100644 t/chainlint/exit-subshell.test
 create mode 100644 t/chainlint/for-loop-abbreviated.expect
 create mode 100644 t/chainlint/for-loop-abbreviated.test
 create mode 100644 t/chainlint/for-loop.expect
 create mode 100644 t/chainlint/for-loop.test
 create mode 100644 t/chainlint/function.expect
 create mode 100644 t/chainlint/function.test
 create mode 100644 t/chainlint/here-doc-body-indent.expect
 create mode 100644 t/chainlint/here-doc-body-indent.test
 create mode 100644 t/chainlint/here-doc-body-pathological.expect
 create mode 100644 t/chainlint/here-doc-body-pathological.test
 create mode 100644 t/chainlint/here-doc-body.expect
 create mode 100644 t/chainlint/here-doc-body.test
 create mode 100644 t/chainlint/here-doc-close-subshell.expect
 create mode 100644 t/chainlint/here-doc-close-subshell.test
 create mode 100644 t/chainlint/here-doc-double.expect
 create mode 100644 t/chainlint/here-doc-double.test
 create mode 100644 t/chainlint/here-doc-indent-operator.expect
 create mode 100644 t/chainlint/here-doc-indent-operator.test
 create mode 100644 t/chainlint/here-doc-multi-line-command-subst.expect
 create mode 100644 t/chainlint/here-doc-multi-line-command-subst.test
 create mode 100644 t/chainlint/here-doc-multi-line-string.expect
 create mode 100644 t/chainlint/here-doc-multi-line-string.test
 create mode 100644 t/chainlint/here-doc.expect
 create mode 100644 t/chainlint/here-doc.test
 create mode 100644 t/chainlint/if-condition-split.expect
 create mode 100644 t/chainlint/if-condition-split.test
 create mode 100644 t/chainlint/if-in-loop.expect
 create mode 100644 t/chainlint/if-in-loop.test
 create mode 100644 t/chainlint/if-then-else.expect
 create mode 100644 t/chainlint/if-then-else.test
 create mode 100644 t/chainlint/incomplete-line.expect
 create mode 100644 t/chainlint/incomplete-line.test
 create mode 100644 t/chainlint/inline-comment.expect
 create mode 100644 t/chainlint/inline-comment.test
 create mode 100644 t/chainlint/loop-detect-failure.expect
 create mode 100644 t/chainlint/loop-detect-failure.test
 create mode 100644 t/chainlint/loop-detect-status.expect
 create mode 100644 t/chainlint/loop-detect-status.test
 create mode 100644 t/chainlint/loop-in-if.expect
 create mode 100644 t/chainlint/loop-in-if.test
 create mode 100644 t/chainlint/loop-upstream-pipe.expect
 create mode 100644 t/chainlint/loop-upstream-pipe.test
 create mode 100644 t/chainlint/multi-line-nested-command-substitution.expect
 create mode 100644 t/chainlint/multi-line-nested-command-substitution.test
 create mode 100644 t/chainlint/multi-line-string.expect
 create mode 100644 t/chainlint/multi-line-string.test
 create mode 100644 t/chainlint/negated-one-liner.expect
 create mode 100644 t/chainlint/negated-one-liner.test
 create mode 100644 t/chainlint/nested-cuddled-subshell.expect
 create mode 100644 t/chainlint/nested-cuddled-subshell.test
 create mode 100644 t/chainlint/nested-here-doc.expect
 create mode 100644 t/chainlint/nested-here-doc.test
 create mode 100644 t/chainlint/nested-loop-detect-failure.expect
 create mode 100644 t/chainlint/nested-loop-detect-failure.test
 create mode 100644 t/chainlint/nested-subshell-comment.expect
 create mode 100644 t/chainlint/nested-subshell-comment.test
 create mode 100644 t/chainlint/nested-subshell.expect
 create mode 100644 t/chainlint/nested-subshell.test
 create mode 100644 t/chainlint/not-heredoc.expect
 create mode 100644 t/chainlint/not-heredoc.test
 create mode 100644 t/chainlint/one-liner-for-loop.expect
 create mode 100644 t/chainlint/one-liner-for-loop.test
 create mode 100644 t/chainlint/one-liner.expect
 create mode 100644 t/chainlint/one-liner.test
 create mode 100644 t/chainlint/p4-filespec.expect
 create mode 100644 t/chainlint/p4-filespec.test
 create mode 100644 t/chainlint/pipe.expect
 create mode 100644 t/chainlint/pipe.test
 create mode 100644 t/chainlint/return-loop.expect
 create mode 100644 t/chainlint/return-loop.test
 create mode 100644 t/chainlint/semicolon.expect
 create mode 100644 t/chainlint/semicolon.test
 create mode 100644 t/chainlint/sqstring-in-sqstring.expect
 create mode 100644 t/chainlint/sqstring-in-sqstring.test
 create mode 100644 t/chainlint/subshell-here-doc.expect
 create mode 100644 t/chainlint/subshell-here-doc.test
 create mode 100644 t/chainlint/subshell-one-liner.expect
 create mode 100644 t/chainlint/subshell-one-liner.test
 create mode 100644 t/chainlint/t7900-subtree.expect
 create mode 100644 t/chainlint/t7900-subtree.test
 create mode 100644 t/chainlint/token-pasting.expect
 create mode 100644 t/chainlint/token-pasting.test
 create mode 100644 t/chainlint/unclosed-here-doc-indent.expect
 create mode 100644 t/chainlint/unclosed-here-doc-indent.test
 create mode 100644 t/chainlint/unclosed-here-doc.expect
 create mode 100644 t/chainlint/unclosed-here-doc.test
 create mode 100644 t/chainlint/while-loop.expect
 create mode 100644 t/chainlint/while-loop.test
 create mode 100755 t/check-non-portable-shell.pl
 create mode 100644 t/helper/.gitignore
 create mode 100644 t/helper/meson.build
 create mode 100644 t/helper/test-advise.c
 create mode 100644 t/helper/test-bitmap.c
 create mode 100644 t/helper/test-bloom.c
 create mode 100644 t/helper/test-bundle-uri.c
 create mode 100644 t/helper/test-cache-tree.c
 create mode 100644 t/helper/test-chmtime.c
 create mode 100644 t/helper/test-config.c
 create mode 100644 t/helper/test-crontab.c
 create mode 100644 t/helper/test-csprng.c
 create mode 100644 t/helper/test-date.c
 create mode 100644 t/helper/test-delete-gpgsig.c
 create mode 100644 t/helper/test-delta.c
 create mode 100644 t/helper/test-dir-iterator.c
 create mode 100644 t/helper/test-drop-caches.c
 create mode 100644 t/helper/test-dump-cache-tree.c
 create mode 100644 t/helper/test-dump-fsmonitor.c
 create mode 100644 t/helper/test-dump-split-index.c
 create mode 100644 t/helper/test-dump-untracked-cache.c
 create mode 100644 t/helper/test-env-helper.c
 create mode 100644 t/helper/test-example-tap.c
 create mode 100644 t/helper/test-fake-ssh.c
 create mode 100644 t/helper/test-find-pack.c
 create mode 100644 t/helper/test-fsmonitor-client.c
 create mode 100644 t/helper/test-genrandom.c
 create mode 100644 t/helper/test-genzeros.c
 create mode 100644 t/helper/test-getcwd.c
 create mode 100644 t/helper/test-hash-speed.c
 create mode 100644 t/helper/test-hash.c
 create mode 100644 t/helper/test-hashmap.c
 create mode 100644 t/helper/test-hexdump.c
 create mode 100644 t/helper/test-json-writer.c
 create mode 100644 t/helper/test-lazy-init-name-hash.c
 create mode 100644 t/helper/test-match-trees.c
 create mode 100644 t/helper/test-mergesort.c
 create mode 100644 t/helper/test-mktemp.c
 create mode 100644 t/helper/test-online-cpus.c
 create mode 100644 t/helper/test-pack-mtimes.c
 create mode 100644 t/helper/test-parse-options.c
 create mode 100644 t/helper/test-parse-pathspec-file.c
 create mode 100644 t/helper/test-partial-clone.c
 create mode 100644 t/helper/test-path-utils.c
 create mode 100644 t/helper/test-path-walk.c
 create mode 100644 t/helper/test-pcre2-config.c
 create mode 100644 t/helper/test-pkt-line.c
 create mode 100644 t/helper/test-proc-receive.c
 create mode 100644 t/helper/test-progress.c
 create mode 100644 t/helper/test-reach.c
 create mode 100644 t/helper/test-read-cache.c
 create mode 100644 t/helper/test-read-graph.c
 create mode 100644 t/helper/test-read-midx.c
 create mode 100644 t/helper/test-ref-store.c
 create mode 100644 t/helper/test-reftable.c
 create mode 100644 t/helper/test-regex.c
 create mode 100644 t/helper/test-repository.c
 create mode 100644 t/helper/test-revision-walking.c
 create mode 100644 t/helper/test-rot13-filter.c
 create mode 100644 t/helper/test-run-command.c
 create mode 100644 t/helper/test-scrap-cache-tree.c
 create mode 100644 t/helper/test-serve-v2.c
 create mode 100644 t/helper/test-sha1.c
 create mode 100755 t/helper/test-sha1.sh
 create mode 100644 t/helper/test-sha256.c
 create mode 100644 t/helper/test-sigchain.c
 create mode 100644 t/helper/test-simple-ipc.c
 create mode 100644 t/helper/test-string-list.c
 create mode 100644 t/helper/test-submodule-config.c
 create mode 100644 t/helper/test-submodule-nested-repo-config.c
 create mode 100644 t/helper/test-submodule.c
 create mode 100644 t/helper/test-subprocess.c
 create mode 100644 t/helper/test-tool-utils.h
 create mode 100644 t/helper/test-tool.c
 create mode 100644 t/helper/test-tool.h
 create mode 100644 t/helper/test-trace2.c
 create mode 100644 t/helper/test-truncate.c
 create mode 100644 t/helper/test-userdiff.c
 create mode 100644 t/helper/test-wildmatch.c
 create mode 100644 t/helper/test-windows-named-pipe.c
 create mode 100644 t/helper/test-write-cache.c
 create mode 100644 t/helper/test-xml-encode.c
 create mode 100644 t/interop/.gitignore
 create mode 100644 t/interop/Makefile
 create mode 100644 t/interop/README
 create mode 100755 t/interop/i0000-basic.sh
 create mode 100755 t/interop/i5500-git-daemon.sh
 create mode 100755 t/interop/i5700-protocol-transition.sh
 create mode 100644 t/interop/interop-lib.sh
 create mode 100644 t/lib-bash.sh
 create mode 100644 t/lib-bitmap.sh
 create mode 100644 t/lib-bundle-uri-protocol.sh
 create mode 100644 t/lib-bundle.sh
 create mode 100644 t/lib-chunk.sh
 create mode 100644 t/lib-chunk/corrupt-chunk-file.pl
 create mode 100755 t/lib-commit-graph.sh
 create mode 100644 t/lib-credential.sh
 create mode 100644 t/lib-cvs.sh
 create mode 100644 t/lib-diff-alternative.sh
 create mode 100644 t/lib-diff-data.sh
 create mode 100644 t/lib-diff.sh
 create mode 100644 t/lib-encoding.sh
 create mode 100644 t/lib-gettext.sh
 create mode 100644 t/lib-git-daemon.sh
 create mode 100644 t/lib-git-p4.sh
 create mode 100644 t/lib-git-svn.sh
 create mode 100644 t/lib-gitweb.sh
 create mode 100644 t/lib-gpg.sh
 create mode 100644 t/lib-gpg/gpgsm-gen-key.in
 create mode 100644 t/lib-gpg/gpgsm_cert.p12
 create mode 100644 t/lib-gpg/keyring.gpg
 create mode 100644 t/lib-gpg/ownertrust
 create mode 100644 t/lib-httpd.sh
 create mode 100644 t/lib-httpd/apache.conf
 create mode 100644 t/lib-httpd/apply-one-time-perl.sh
 create mode 100644 t/lib-httpd/broken-smart-http.sh
 create mode 100644 t/lib-httpd/error-no-report.sh
 create mode 100644 t/lib-httpd/error-smart-http.sh
 create mode 100755 t/lib-httpd/error.sh
 create mode 100644 t/lib-httpd/incomplete-body-upload-pack-v2-http.sh
 create mode 100644 t/lib-httpd/incomplete-length-upload-pack-v2-http.sh
 create mode 100644 t/lib-httpd/nph-custom-auth.sh
 create mode 100644 t/lib-httpd/passwd
 create mode 100644 t/lib-httpd/proxy-passwd
 create mode 100644 t/lib-httpd/ssl.cnf
 create mode 100644 t/lib-log-graph.sh
 create mode 100644 t/lib-merge.sh
 create mode 100644 t/lib-midx.sh
 create mode 100644 t/lib-pack.sh
 create mode 100644 t/lib-pager.sh
 create mode 100644 t/lib-parallel-checkout.sh
 create mode 100644 t/lib-patch-mode.sh
 create mode 100644 t/lib-perl.sh
 create mode 100644 t/lib-proto-disable.sh
 create mode 100644 t/lib-read-tree-m-3way.sh
 create mode 100644 t/lib-read-tree.sh
 create mode 100644 t/lib-rebase.sh
 create mode 100644 t/lib-submodule-update.sh
 create mode 100644 t/lib-subtest.sh
 create mode 100644 t/lib-sudo.sh
 create mode 100644 t/lib-t3100.sh
 create mode 100644 t/lib-t6000.sh
 create mode 100644 t/lib-terminal.sh
 create mode 100755 t/lib-unicode-nfc-nfd.sh
 create mode 100644 t/lib-unique-files.sh
 create mode 100644 t/meson.build
 create mode 100644 t/oid-info/README
 create mode 100644 t/oid-info/hash-info
 create mode 100644 t/oid-info/oid
 create mode 100644 t/perf/.gitignore
 create mode 100644 t/perf/Makefile
 create mode 100644 t/perf/README
 create mode 100755 t/perf/aggregate.perl
 create mode 100755 t/perf/bisect_regression
 create mode 100755 t/perf/bisect_run_script
 create mode 100644 t/perf/config
 create mode 100644 t/perf/lib-bitmap.sh
 create mode 100644 t/perf/lib-pack.sh
 create mode 100755 t/perf/min_time.perl
 create mode 100755 t/perf/p0000-perf-lib-sanity.sh
 create mode 100755 t/perf/p0001-rev-list.sh
 create mode 100755 t/perf/p0002-read-cache.sh
 create mode 100755 t/perf/p0003-delta-base-cache.sh
 create mode 100755 t/perf/p0004-lazy-init-name-hash.sh
 create mode 100755 t/perf/p0005-status.sh
 create mode 100755 t/perf/p0006-read-tree-checkout.sh
 create mode 100755 t/perf/p0007-write-cache.sh
 create mode 100755 t/perf/p0008-odb-fsync.sh
 create mode 100755 t/perf/p0071-sort.sh
 create mode 100755 t/perf/p0090-cache-tree.sh
 create mode 100755 t/perf/p0100-globbing.sh
 create mode 100755 t/perf/p1006-cat-file.sh
 create mode 100755 t/perf/p1400-update-ref.sh
 create mode 100755 t/perf/p1450-fsck.sh
 create mode 100755 t/perf/p1451-fsck-skip-list.sh
 create mode 100755 t/perf/p1500-graph-walks.sh
 create mode 100755 t/perf/p2000-sparse-operations.sh
 create mode 100755 t/perf/p3400-rebase.sh
 create mode 100755 t/perf/p3404-rebase-interactive.sh
 create mode 100755 t/perf/p4000-diff-algorithms.sh
 create mode 100755 t/perf/p4001-diff-no-index.sh
 create mode 100755 t/perf/p4002-diff-color-moved.sh
 create mode 100755 t/perf/p4205-log-pretty-formats.sh
 create mode 100755 t/perf/p4209-pickaxe.sh
 create mode 100755 t/perf/p4211-line-log.sh
 create mode 100755 t/perf/p4220-log-grep-engines.sh
 create mode 100755 t/perf/p4221-log-grep-engines-fixed.sh
 create mode 100755 t/perf/p5302-pack-index.sh
 create mode 100755 t/perf/p5303-many-packs.sh
 create mode 100755 t/perf/p5304-prune.sh
 create mode 100755 t/perf/p5310-pack-bitmaps.sh
 create mode 100755 t/perf/p5311-pack-bitmaps-fetch.sh
 create mode 100755 t/perf/p5312-pack-bitmaps-revs.sh
 create mode 100755 t/perf/p5326-multi-pack-bitmaps.sh
 create mode 100755 t/perf/p5332-multi-pack-reuse.sh
 create mode 100755 t/perf/p5333-pseudo-merge-bitmaps.sh
 create mode 100755 t/perf/p5550-fetch-tags.sh
 create mode 100755 t/perf/p5551-fetch-rescan.sh
 create mode 100755 t/perf/p5600-partial-clone.sh
 create mode 100755 t/perf/p5601-clone-reference.sh
 create mode 100755 t/perf/p6100-describe.sh
 create mode 100755 t/perf/p6300-for-each-ref.sh
 create mode 100755 t/perf/p7000-filter-branch.sh
 create mode 100755 t/perf/p7102-reset.sh
 create mode 100755 t/perf/p7300-clean.sh
 create mode 100755 t/perf/p7519-fsmonitor.sh
 create mode 100755 t/perf/p7527-builtin-fsmonitor.sh
 create mode 100755 t/perf/p7810-grep.sh
 create mode 100755 t/perf/p7820-grep-engines.sh
 create mode 100755 t/perf/p7821-grep-engines-fixed.sh
 create mode 100755 t/perf/p7822-grep-perl-character.sh
 create mode 100755 t/perf/p9210-scalar.sh
 create mode 100755 t/perf/p9300-fast-import-export.sh
 create mode 100644 t/perf/perf-lib.sh
 create mode 100644 t/perf/repos/.gitignore
 create mode 100755 t/perf/repos/inflate-repo.sh
 create mode 100755 t/perf/repos/many-files.sh
 create mode 100755 t/perf/run
 create mode 100755 t/run-test.sh
 create mode 100644 t/socks4-proxy.pl
 create mode 100755 t/t0000-basic.sh
 create mode 100755 t/t0001-init.sh
 create mode 100755 t/t0002-gitfile.sh
 create mode 100755 t/t0003-attributes.sh
 create mode 100755 t/t0004-unwritable.sh
 create mode 100755 t/t0005-signals.sh
 create mode 100755 t/t0006-date.sh
 create mode 100755 t/t0007-git-var.sh
 create mode 100755 t/t0008-ignores.sh
 create mode 100755 t/t0010-racy-git.sh
 create mode 100755 t/t0012-help.sh
 create mode 100755 t/t0013-sha1dc.sh
 create mode 100644 t/t0013/shattered-1.pdf
 create mode 100755 t/t0014-alias.sh
 create mode 100755 t/t0017-env-helper.sh
 create mode 100755 t/t0018-advice.sh
 create mode 100755 t/t0019-json-writer.sh
 create mode 100644 t/t0019/parse_json.perl
 create mode 100755 t/t0020-crlf.sh
 create mode 100755 t/t0021-conversion.sh
 create mode 100755 t/t0022-crlf-rename.sh
 create mode 100755 t/t0023-crlf-am.sh
 create mode 100755 t/t0024-crlf-archive.sh
 create mode 100755 t/t0025-crlf-renormalize.sh
 create mode 100755 t/t0026-eol-config.sh
 create mode 100755 t/t0027-auto-crlf.sh
 create mode 100755 t/t0028-working-tree-encoding.sh
 create mode 100755 t/t0029-core-unsetenvvars.sh
 create mode 100755 t/t0030-stripspace.sh
 create mode 100755 t/t0033-safe-directory.sh
 create mode 100755 t/t0034-root-safe-directory.sh
 create mode 100755 t/t0035-safe-bare-repository.sh
 create mode 100755 t/t0040-parse-options.sh
 create mode 100755 t/t0041-usage.sh
 create mode 100755 t/t0050-filesystem.sh
 create mode 100755 t/t0051-windows-named-pipe.sh
 create mode 100755 t/t0052-simple-ipc.sh
 create mode 100755 t/t0055-beyond-symlinks.sh
 create mode 100755 t/t0056-git-C.sh
 create mode 100755 t/t0060-path-utils.sh
 create mode 100755 t/t0061-run-command.sh
 create mode 100755 t/t0062-revision-walking.sh
 create mode 100755 t/t0063-string-list.sh
 create mode 100755 t/t0066-dir-iterator.sh
 create mode 100755 t/t0067-parse_pathspec_file.sh
 create mode 100755 t/t0068-for-each-repo.sh
 create mode 100755 t/t0070-fundamental.sh
 create mode 100755 t/t0071-sort.sh
 create mode 100755 t/t0080-unit-test-output.sh
 create mode 100755 t/t0081-find-pack.sh
 create mode 100755 t/t0090-cache-tree.sh
 create mode 100755 t/t0091-bugreport.sh
 create mode 100755 t/t0092-diagnose.sh
 create mode 100755 t/t0095-bloom.sh
 create mode 100755 t/t0100-previous.sh
 create mode 100755 t/t0101-at-syntax.sh
 create mode 100755 t/t0200-gettext-basic.sh
 create mode 100644 t/t0200/test.c
 create mode 100644 t/t0200/test.perl
 create mode 100644 t/t0200/test.sh
 create mode 100755 t/t0201-gettext-fallbacks.sh
 create mode 100755 t/t0202-gettext-perl.sh
 create mode 100755 t/t0202/test.pl
 create mode 100755 t/t0203-gettext-setlocale-sanity.sh
 create mode 100755 t/t0204-gettext-reencode-sanity.sh
 create mode 100755 t/t0210-trace2-normal.sh
 create mode 100644 t/t0210/scrub_normal.perl
 create mode 100755 t/t0211-trace2-perf.sh
 create mode 100644 t/t0211/scrub_perf.perl
 create mode 100755 t/t0212-trace2-event.sh
 create mode 100644 t/t0212/parse_events.perl
 create mode 100755 t/t0300-credentials.sh
 create mode 100755 t/t0301-credential-cache.sh
 create mode 100755 t/t0302-credential-store.sh
 create mode 100755 t/t0303-credential-external.sh
 create mode 100755 t/t0410-partial-clone.sh
 create mode 100755 t/t0411-clone-from-partial.sh
 create mode 100755 t/t0450-txt-doc-vs-help.sh
 create mode 100644 t/t0450/txt-help-mismatches
 create mode 100755 t/t0500-progress-display.sh
 create mode 100755 t/t0600-reffiles-backend.sh
 create mode 100755 t/t0601-reffiles-pack-refs.sh
 create mode 100755 t/t0602-reffiles-fsck.sh
 create mode 100755 t/t0610-reftable-basics.sh
 create mode 100755 t/t0611-reftable-httpd.sh
 create mode 100755 t/t0612-reftable-jgit-compatibility.sh
 create mode 100755 t/t0613-reftable-write-options.sh
 create mode 100755 t/t1000-read-tree-m-3way.sh
 create mode 100755 t/t1001-read-tree-m-2way.sh
 create mode 100755 t/t1002-read-tree-m-u-2way.sh
 create mode 100755 t/t1003-read-tree-prefix.sh
 create mode 100755 t/t1004-read-tree-m-u-wf.sh
 create mode 100755 t/t1005-read-tree-reset.sh
 create mode 100755 t/t1006-cat-file.sh
 create mode 100755 t/t1007-hash-object.sh
 create mode 100755 t/t1008-read-tree-overlay.sh
 create mode 100755 t/t1009-read-tree-new-index.sh
 create mode 100755 t/t1010-mktree.sh
 create mode 100755 t/t1011-read-tree-sparse-checkout.sh
 create mode 100755 t/t1012-read-tree-df.sh
 create mode 100755 t/t1013-read-tree-submodule.sh
 create mode 100755 t/t1014-read-tree-confusing.sh
 create mode 100755 t/t1015-read-index-unmerged.sh
 create mode 100755 t/t1016-compatObjectFormat.sh
 create mode 100755 t/t1016/gpg
 create mode 100755 t/t1020-subdirectory.sh
 create mode 100755 t/t1021-rerere-in-workdir.sh
 create mode 100755 t/t1022-read-tree-partial-clone.sh
 create mode 100755 t/t1050-large.sh
 create mode 100755 t/t1051-large-conversion.sh
 create mode 100755 t/t1060-object-corruption.sh
 create mode 100755 t/t1090-sparse-checkout-scope.sh
 create mode 100755 t/t1091-sparse-checkout-builtin.sh
 create mode 100755 t/t1092-sparse-checkout-compatibility.sh
 create mode 100755 t/t1100-commit-tree-options.sh
 create mode 100755 t/t1300-config.sh
 create mode 100755 t/t1301-shared-repo.sh
 create mode 100755 t/t1302-repo-version.sh
 create mode 100755 t/t1303-wacky-config.sh
 create mode 100755 t/t1304-default-acl.sh
 create mode 100755 t/t1305-config-include.sh
 create mode 100755 t/t1306-xdg-files.sh
 create mode 100755 t/t1307-config-blob.sh
 create mode 100755 t/t1308-config-set.sh
 create mode 100755 t/t1309-early-config.sh
 create mode 100755 t/t1310-config-default.sh
 create mode 100755 t/t1350-config-hooks-path.sh
 create mode 100755 t/t1400-update-ref.sh
 create mode 100755 t/t1401-symbolic-ref.sh
 create mode 100755 t/t1402-check-ref-format.sh
 create mode 100755 t/t1403-show-ref.sh
 create mode 100755 t/t1404-update-ref-errors.sh
 create mode 100755 t/t1405-main-ref-store.sh
 create mode 100755 t/t1406-submodule-ref-store.sh
 create mode 100755 t/t1407-worktree-ref-store.sh
 create mode 100755 t/t1408-packed-refs.sh
 create mode 100755 t/t1409-avoid-packing-refs.sh
 create mode 100755 t/t1410-reflog.sh
 create mode 100755 t/t1411-reflog-show.sh
 create mode 100755 t/t1412-reflog-loop.sh
 create mode 100755 t/t1413-reflog-detach.sh
 create mode 100755 t/t1414-reflog-walk.sh
 create mode 100755 t/t1415-worktree-refs.sh
 create mode 100755 t/t1416-ref-transaction-hooks.sh
 create mode 100755 t/t1417-reflog-updateref.sh
 create mode 100755 t/t1418-reflog-exists.sh
 create mode 100755 t/t1419-exclude-refs.sh
 create mode 100755 t/t1420-lost-found.sh
 create mode 100755 t/t1430-bad-ref-name.sh
 create mode 100755 t/t1450-fsck.sh
 create mode 100755 t/t1451-fsck-buffer.sh
 create mode 100755 t/t1460-refs-migrate.sh
 create mode 100755 t/t1500-rev-parse.sh
 create mode 100755 t/t1501-work-tree.sh
 create mode 100755 t/t1502-rev-parse-parseopt.sh
 create mode 100644 t/t1502/.gitattributes
 create mode 100644 t/t1502/optionspec-neg
 create mode 100644 t/t1502/optionspec-neg.help
 create mode 100755 t/t1502/optionspec.help
 create mode 100755 t/t1503-rev-parse-verify.sh
 create mode 100755 t/t1504-ceiling-dirs.sh
 create mode 100755 t/t1505-rev-parse-last.sh
 create mode 100755 t/t1506-rev-parse-diagnosis.sh
 create mode 100755 t/t1507-rev-parse-upstream.sh
 create mode 100755 t/t1508-at-combinations.sh
 create mode 100755 t/t1509-root-work-tree.sh
 create mode 100644 t/t1509/excludes
 create mode 100755 t/t1509/prepare-chroot.sh
 create mode 100755 t/t1510-repo-setup.sh
 create mode 100755 t/t1511-rev-parse-caret.sh
 create mode 100755 t/t1512-rev-parse-disambiguation.sh
 create mode 100755 t/t1513-rev-parse-prefix.sh
 create mode 100755 t/t1514-rev-parse-push.sh
 create mode 100755 t/t1515-rev-parse-outside-repo.sh
 create mode 100755 t/t1517-outside-repo.sh
 create mode 100755 t/t1600-index.sh
 create mode 100755 t/t1601-index-bogus.sh
 create mode 100755 t/t1700-split-index.sh
 create mode 100755 t/t1701-racy-split-index.sh
 create mode 100755 t/t1800-hook.sh
 create mode 100755 t/t2000-conflict-when-checking-files-out.sh
 create mode 100755 t/t2002-checkout-cache-u.sh
 create mode 100755 t/t2003-checkout-cache-mkdir.sh
 create mode 100755 t/t2004-checkout-cache-temp.sh
 create mode 100755 t/t2005-checkout-index-symlinks.sh
 create mode 100755 t/t2006-checkout-index-basic.sh
 create mode 100755 t/t2007-checkout-symlink.sh
 create mode 100755 t/t2008-checkout-subdir.sh
 create mode 100755 t/t2009-checkout-statinfo.sh
 create mode 100755 t/t2010-checkout-ambiguous.sh
 create mode 100755 t/t2011-checkout-invalid-head.sh
 create mode 100755 t/t2012-checkout-last.sh
 create mode 100755 t/t2013-checkout-submodule.sh
 create mode 100755 t/t2014-checkout-switch.sh
 create mode 100755 t/t2015-checkout-unborn.sh
 create mode 100755 t/t2016-checkout-patch.sh
 create mode 100755 t/t2017-checkout-orphan.sh
 create mode 100755 t/t2018-checkout-branch.sh
 create mode 100755 t/t2019-checkout-ambiguous-ref.sh
 create mode 100755 t/t2020-checkout-detach.sh
 create mode 100755 t/t2021-checkout-overwrite.sh
 create mode 100755 t/t2022-checkout-paths.sh
 create mode 100755 t/t2023-checkout-m.sh
 create mode 100755 t/t2024-checkout-dwim.sh
 create mode 100755 t/t2025-checkout-no-overlay.sh
 create mode 100755 t/t2026-checkout-pathspec-file.sh
 create mode 100755 t/t2027-checkout-track.sh
 create mode 100755 t/t2030-unresolve-info.sh
 create mode 100755 t/t2050-git-dir-relative.sh
 create mode 100755 t/t2060-switch.sh
 create mode 100755 t/t2070-restore.sh
 create mode 100755 t/t2071-restore-patch.sh
 create mode 100755 t/t2072-restore-pathspec-file.sh
 create mode 100755 t/t2080-parallel-checkout-basics.sh
 create mode 100755 t/t2081-parallel-checkout-collisions.sh
 create mode 100755 t/t2082-parallel-checkout-attributes.sh
 create mode 100755 t/t2100-update-cache-badpath.sh
 create mode 100755 t/t2101-update-index-reupdate.sh
 create mode 100755 t/t2102-update-index-symlinks.sh
 create mode 100755 t/t2103-update-index-ignore-missing.sh
 create mode 100755 t/t2104-update-index-skip-worktree.sh
 create mode 100755 t/t2105-update-index-gitfile.sh
 create mode 100755 t/t2106-update-index-assume-unchanged.sh
 create mode 100755 t/t2107-update-index-basic.sh
 create mode 100755 t/t2108-update-index-refresh-racy.sh
 create mode 100755 t/t2200-add-update.sh
 create mode 100755 t/t2201-add-update-typechange.sh
 create mode 100755 t/t2202-add-addremove.sh
 create mode 100755 t/t2203-add-intent.sh
 create mode 100755 t/t2204-add-ignored.sh
 create mode 100755 t/t2205-add-worktree-config.sh
 create mode 100755 t/t2300-cd-to-toplevel.sh
 create mode 100755 t/t2400-worktree-add.sh
 create mode 100755 t/t2401-worktree-prune.sh
 create mode 100755 t/t2402-worktree-list.sh
 create mode 100755 t/t2403-worktree-move.sh
 create mode 100755 t/t2404-worktree-config.sh
 create mode 100755 t/t2405-worktree-submodule.sh
 create mode 100755 t/t2406-worktree-repair.sh
 create mode 100755 t/t2407-worktree-heads.sh
 create mode 100755 t/t2500-untracked-overwriting.sh
 create mode 100755 t/t2501-cwd-empty.sh
 create mode 100755 t/t3000-ls-files-others.sh
 create mode 100755 t/t3001-ls-files-others-exclude.sh
 create mode 100755 t/t3002-ls-files-dashpath.sh
 create mode 100755 t/t3003-ls-files-exclude.sh
 create mode 100755 t/t3004-ls-files-basic.sh
 create mode 100755 t/t3005-ls-files-relative.sh
 create mode 100755 t/t3006-ls-files-long.sh
 create mode 100755 t/t3007-ls-files-recurse-submodules.sh
 create mode 100755 t/t3008-ls-files-lazy-init-name-hash.sh
 create mode 100755 t/t3009-ls-files-others-nonsubmodule.sh
 create mode 100755 t/t3010-ls-files-killed-modified.sh
 create mode 100755 t/t3011-common-prefixes-and-directory-traversal.sh
 create mode 100755 t/t3012-ls-files-dedup.sh
 create mode 100755 t/t3013-ls-files-format.sh
 create mode 100755 t/t3020-ls-files-error-unmatch.sh
 create mode 100755 t/t3040-subprojects-basic.sh
 create mode 100755 t/t3050-subprojects-fetch.sh
 create mode 100755 t/t3060-ls-files-with-tree.sh
 create mode 100755 t/t3070-wildmatch.sh
 create mode 100755 t/t3100-ls-tree-restrict.sh
 create mode 100755 t/t3101-ls-tree-dirname.sh
 create mode 100755 t/t3102-ls-tree-wildcards.sh
 create mode 100755 t/t3103-ls-tree-misc.sh
 create mode 100755 t/t3104-ls-tree-format.sh
 create mode 100755 t/t3105-ls-tree-output.sh
 create mode 100755 t/t3200-branch.sh
 create mode 100755 t/t3201-branch-contains.sh
 create mode 100755 t/t3202-show-branch.sh
 create mode 100755 t/t3203-branch-output.sh
 create mode 100755 t/t3204-branch-name-interpretation.sh
 create mode 100755 t/t3205-branch-color.sh
 create mode 100755 t/t3206-range-diff.sh
 create mode 100644 t/t3206/history.export
 create mode 100755 t/t3207-branch-submodule.sh
 create mode 100755 t/t3211-peel-ref.sh
 create mode 100755 t/t3300-funny-names.sh
 create mode 100755 t/t3301-notes.sh
 create mode 100755 t/t3302-notes-index-expensive.sh
 create mode 100755 t/t3303-notes-subtrees.sh
 create mode 100755 t/t3304-notes-mixed.sh
 create mode 100755 t/t3305-notes-fanout.sh
 create mode 100755 t/t3306-notes-prune.sh
 create mode 100755 t/t3307-notes-man.sh
 create mode 100755 t/t3308-notes-merge.sh
 create mode 100755 t/t3309-notes-merge-auto-resolve.sh
 create mode 100755 t/t3310-notes-merge-manual-resolve.sh
 create mode 100755 t/t3311-notes-merge-fanout.sh
 create mode 100755 t/t3320-notes-merge-worktrees.sh
 create mode 100755 t/t3321-notes-stripspace.sh
 create mode 100755 t/t3400-rebase.sh
 create mode 100755 t/t3401-rebase-and-am-rename.sh
 create mode 100755 t/t3402-rebase-merge.sh
 create mode 100755 t/t3403-rebase-skip.sh
 create mode 100755 t/t3404-rebase-interactive.sh
 create mode 100755 t/t3405-rebase-malformed.sh
 create mode 100755 t/t3406-rebase-message.sh
 create mode 100755 t/t3407-rebase-abort.sh
 create mode 100755 t/t3408-rebase-multi-line.sh
 create mode 100755 t/t3409-rebase-environ.sh
 create mode 100755 t/t3412-rebase-root.sh
 create mode 100755 t/t3413-rebase-hook.sh
 create mode 100755 t/t3415-rebase-autosquash.sh
 create mode 100755 t/t3416-rebase-onto-threedots.sh
 create mode 100755 t/t3417-rebase-whitespace-fix.sh
 create mode 100755 t/t3418-rebase-continue.sh
 create mode 100755 t/t3419-rebase-patch-id.sh
 create mode 100755 t/t3420-rebase-autostash.sh
 create mode 100755 t/t3421-rebase-topology-linear.sh
 create mode 100755 t/t3422-rebase-incompatible-options.sh
 create mode 100755 t/t3423-rebase-reword.sh
 create mode 100755 t/t3424-rebase-empty.sh
 create mode 100755 t/t3425-rebase-topology-merges.sh
 create mode 100755 t/t3426-rebase-submodule.sh
 create mode 100755 t/t3427-rebase-subtree.sh
 create mode 100755 t/t3428-rebase-signoff.sh
 create mode 100755 t/t3429-rebase-edit-todo.sh
 create mode 100755 t/t3430-rebase-merges.sh
 create mode 100755 t/t3431-rebase-fork-point.sh
 create mode 100755 t/t3432-rebase-fast-forward.sh
 create mode 100755 t/t3433-rebase-across-mode-change.sh
 create mode 100755 t/t3434-rebase-i18n.sh
 create mode 100644 t/t3434/ISO8859-1.txt
 create mode 100644 t/t3434/eucJP.txt
 create mode 100755 t/t3435-rebase-gpg-sign.sh
 create mode 100755 t/t3436-rebase-more-options.sh
 create mode 100755 t/t3437-rebase-fixup-options.sh
 create mode 100644 t/t3437/expected-combined-message
 create mode 100644 t/t3437/expected-squash-message
 create mode 100755 t/t3438-rebase-broken-files.sh
 create mode 100755 t/t3500-cherry.sh
 create mode 100755 t/t3501-revert-cherry-pick.sh
 create mode 100755 t/t3502-cherry-pick-merge.sh
 create mode 100755 t/t3503-cherry-pick-root.sh
 create mode 100755 t/t3504-cherry-pick-rerere.sh
 create mode 100755 t/t3505-cherry-pick-empty.sh
 create mode 100755 t/t3506-cherry-pick-ff.sh
 create mode 100755 t/t3507-cherry-pick-conflict.sh
 create mode 100755 t/t3508-cherry-pick-many-commits.sh
 create mode 100755 t/t3509-cherry-pick-merge-df.sh
 create mode 100755 t/t3510-cherry-pick-sequence.sh
 create mode 100755 t/t3511-cherry-pick-x.sh
 create mode 100755 t/t3512-cherry-pick-submodule.sh
 create mode 100755 t/t3513-revert-submodule.sh
 create mode 100755 t/t3514-cherry-pick-revert-gpg.sh
 create mode 100755 t/t3600-rm.sh
 create mode 100755 t/t3601-rm-pathspec-file.sh
 create mode 100755 t/t3602-rm-sparse-checkout.sh
 create mode 100755 t/t3650-replay-basics.sh
 create mode 100755 t/t3700-add.sh
 create mode 100755 t/t3701-add-interactive.sh
 create mode 100755 t/t3702-add-edit.sh
 create mode 100755 t/t3703-add-magic-pathspec.sh
 create mode 100755 t/t3704-add-pathspec-file.sh
 create mode 100755 t/t3705-add-sparse-checkout.sh
 create mode 100755 t/t3800-mktag.sh
 create mode 100755 t/t3900-i18n-commit.sh
 create mode 100644 t/t3900/1-UTF-8.txt
 create mode 100644 t/t3900/2-UTF-8.txt
 create mode 100644 t/t3900/ISO-2022-JP.txt
 create mode 100644 t/t3900/ISO8859-1.txt
 create mode 100644 t/t3900/UTF-16.txt
 create mode 100644 t/t3900/eucJP.txt
 create mode 100755 t/t3901-i18n-patch.sh
 create mode 100755 t/t3901/8859-1.txt
 create mode 100755 t/t3901/utf8.txt
 create mode 100755 t/t3902-quoted.sh
 create mode 100755 t/t3903-stash.sh
 create mode 100755 t/t3904-stash-patch.sh
 create mode 100755 t/t3905-stash-include-untracked.sh
 create mode 100755 t/t3906-stash-submodule.sh
 create mode 100755 t/t3907-stash-show-config.sh
 create mode 100755 t/t3908-stash-in-worktree.sh
 create mode 100755 t/t3909-stash-pathspec-file.sh
 create mode 100755 t/t3910-mac-os-precompose.sh
 create mode 100755 t/t3920-crlf-messages.sh
 create mode 100755 t/t4000-diff-format.sh
 create mode 100755 t/t4001-diff-rename.sh
 create mode 100755 t/t4002-diff-basic.sh
 create mode 100755 t/t4003-diff-rename-1.sh
 create mode 100755 t/t4004-diff-rename-symlink.sh
 create mode 100755 t/t4005-diff-rename-2.sh
 create mode 100755 t/t4006-diff-mode.sh
 create mode 100755 t/t4007-rename-3.sh
 create mode 100755 t/t4008-diff-break-rewrite.sh
 create mode 100755 t/t4009-diff-rename-4.sh
 create mode 100755 t/t4010-diff-pathspec.sh
 create mode 100755 t/t4011-diff-symlink.sh
 create mode 100755 t/t4012-diff-binary.sh
 create mode 100755 t/t4013-diff-various.sh
 create mode 100644 t/t4013/diff.config_format.subjectprefix_DIFFERENT_PREFIX
 create mode 100644 t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
 create mode 100644 t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
 create mode 100644 t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
 create mode 100644 t/t4013/diff.diff-tree_--cc_--shortstat_master
 create mode 100644 t/t4013/diff.diff-tree_--cc_--stat_--summary_master
 create mode 100644 t/t4013/diff.diff-tree_--cc_--stat_--summary_side
 create mode 100644 t/t4013/diff.diff-tree_--cc_--stat_master
 create mode 100644 t/t4013/diff.diff-tree_--cc_--summary_REVERSE
 create mode 100644 t/t4013/diff.diff-tree_--cc_master
 create mode 100644 t/t4013/diff.diff-tree_--format=%N_note
 create mode 100644 t/t4013/diff.diff-tree_--patch-with-raw_initial
 create mode 100644 t/t4013/diff.diff-tree_--patch-with-stat_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_--root_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_-p_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty=oneline_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--notes_note
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--stat_--compact-summary_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_--summary_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_-p_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--root_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--stat_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_--summary_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_-R_--root_--stat_--compact-summary_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_-p_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_-p_side
 create mode 100644 t/t4013/diff.diff-tree_--pretty_initial
 create mode 100644 t/t4013/diff.diff-tree_--pretty_note
 create mode 100644 t/t4013/diff.diff-tree_--pretty_side
 create mode 100644 t/t4013/diff.diff-tree_--root_--abbrev_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_--patch-with-raw_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_-p_--abbrev=10_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_-p_--full-index_--abbrev=10_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_-p_--full-index_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_-p_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_-r_--abbrev_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_-r_initial
 create mode 100644 t/t4013/diff.diff-tree_--root_initial
 create mode 100644 t/t4013/diff.diff-tree_--stat_--compact-summary_initial_mode
 create mode 100644 t/t4013/diff.diff-tree_--stat_initial_mode
 create mode 100644 t/t4013/diff.diff-tree_--summary_initial_mode
 create mode 100644 t/t4013/diff.diff-tree_-R_--stat_--compact-summary_initial_mode
 create mode 100644 t/t4013/diff.diff-tree_-c_--abbrev_master
 create mode 100644 t/t4013/diff.diff-tree_-c_--stat_--summary_master
 create mode 100644 t/t4013/diff.diff-tree_-c_--stat_--summary_side
 create mode 100644 t/t4013/diff.diff-tree_-c_--stat_master
 create mode 100644 t/t4013/diff.diff-tree_-c_master
 create mode 100644 t/t4013/diff.diff-tree_-m_master
 create mode 100644 t/t4013/diff.diff-tree_-p_-m_master
 create mode 100644 t/t4013/diff.diff-tree_-p_initial
 create mode 100644 t/t4013/diff.diff-tree_-p_master
 create mode 100644 t/t4013/diff.diff-tree_-r_--abbrev=4_initial
 create mode 100644 t/t4013/diff.diff-tree_-r_--abbrev_initial
 create mode 100644 t/t4013/diff.diff-tree_-r_initial
 create mode 100644 t/t4013/diff.diff-tree_initial
 create mode 100644 t/t4013/diff.diff-tree_initial_mode
 create mode 100644 t/t4013/diff.diff-tree_master
 create mode 100644 t/t4013/diff.diff_--abbrev_initial..side
 create mode 100644 t/t4013/diff.diff_--cached
 create mode 100644 t/t4013/diff.diff_--cached_--_file0
 create mode 100644 t/t4013/diff.diff_--dirstat-by-file_initial_rearrange
 create mode 100644 t/t4013/diff.diff_--dirstat_--cc_master~1_master
 create mode 100644 t/t4013/diff.diff_--dirstat_initial_rearrange
 create mode 100644 t/t4013/diff.diff_--dirstat_master~1_master~2
 create mode 100644 t/t4013/diff.diff_--line-prefix=abc_master_master^_side
 create mode 100644 t/t4013/diff.diff_--line-prefix_--cached_--_file0
 create mode 100644 t/t4013/diff.diff_--name-status_dir2_dir
 create mode 100644 t/t4013/diff.diff_--no-index_--name-status_--_dir2_dir
 create mode 100644 t/t4013/diff.diff_--no-index_--name-status_dir2_dir
 create mode 100644 t/t4013/diff.diff_--no-index_--raw_--abbrev=4_dir2_dir
 create mode 100644 t/t4013/diff.diff_--no-index_--raw_--no-abbrev_dir2_dir
 create mode 100644 t/t4013/diff.diff_--no-index_--raw_dir2_dir
 create mode 100644 t/t4013/diff.diff_--no-index_dir_dir3
 create mode 100644 t/t4013/diff.diff_--patch-with-raw_-r_initial..side
 create mode 100644 t/t4013/diff.diff_--patch-with-raw_initial..side
 create mode 100644 t/t4013/diff.diff_--patch-with-stat_-r_initial..side
 create mode 100644 t/t4013/diff.diff_--patch-with-stat_initial..side
 create mode 100644 t/t4013/diff.diff_--raw_--abbrev=4_initial
 create mode 100644 t/t4013/diff.diff_--raw_--no-abbrev_initial
 create mode 100644 t/t4013/diff.diff_--raw_initial
 create mode 100644 t/t4013/diff.diff_--stat_initial..side
 create mode 100644 t/t4013/diff.diff_-U1_initial..side
 create mode 100644 t/t4013/diff.diff_-U2_initial..side
 create mode 100644 t/t4013/diff.diff_-U_initial..side
 create mode 100644 t/t4013/diff.diff_-r_--stat_initial..side
 create mode 100644 t/t4013/diff.diff_-r_initial..side
 create mode 100644 t/t4013/diff.diff_initial..side
 create mode 100644 t/t4013/diff.diff_master_master^_side
 create mode 100644 t/t4013/diff.format-patch_--attach_--stdout_--suffix=.diff_initial..side
 create mode 100644 t/t4013/diff.format-patch_--attach_--stdout_initial..master
 create mode 100644 t/t4013/diff.format-patch_--attach_--stdout_initial..master^
 create mode 100644 t/t4013/diff.format-patch_--attach_--stdout_initial..side
 create mode 100644 t/t4013/diff.format-patch_--inline_--stdout_--numbered-files_initial..master
 create mode 100644 t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
 create mode 100644 t/t4013/diff.format-patch_--inline_--stdout_initial..master
 create mode 100644 t/t4013/diff.format-patch_--inline_--stdout_initial..master^
 create mode 100644 t/t4013/diff.format-patch_--inline_--stdout_initial..master^^
 create mode 100644 t/t4013/diff.format-patch_--inline_--stdout_initial..side
 create mode 100644 t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
 create mode 100644 t/t4013/diff.format-patch_--stdout_--no-numbered_initial..master
 create mode 100644 t/t4013/diff.format-patch_--stdout_--numbered_initial..master
 create mode 100644 t/t4013/diff.format-patch_--stdout_initial..master
 create mode 100644 t/t4013/diff.format-patch_--stdout_initial..master^
 create mode 100644 t/t4013/diff.format-patch_--stdout_initial..side
 create mode 100644 t/t4013/diff.log_--cc_-m_-p_master
 create mode 100644 t/t4013/diff.log_--decorate=full_--all
 create mode 100644 t/t4013/diff.log_--decorate=full_--clear-decorations_--all
 create mode 100644 t/t4013/diff.log_--decorate=full_--decorate-all_--all
 create mode 100644 t/t4013/diff.log_--decorate_--all
 create mode 100644 t/t4013/diff.log_--decorate_--clear-decorations_--all
 create mode 100644 t/t4013/diff.log_--decorate_--decorate-all_--all
 create mode 100644 t/t4013/diff.log_--diff-merges=first-parent_master
 create mode 100644 t/t4013/diff.log_--diff-merges=off_-p_--first-parent_master
 create mode 100644 t/t4013/diff.log_--first-parent_--diff-merges=off_-p_master
 create mode 100644 t/t4013/diff.log_--no-diff-merges_-p_--first-parent_master
 create mode 100644 t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
 create mode 100644 t/t4013/diff.log_--patch-with-stat_master
 create mode 100644 t/t4013/diff.log_--patch-with-stat_master_--_dir_
 create mode 100644 t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
 create mode 100644 t/t4013/diff.log_--root_--patch-with-stat_--summary_master
 create mode 100644 t/t4013/diff.log_--root_--patch-with-stat_master
 create mode 100644 t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
 create mode 100644 t/t4013/diff.log_--root_-p_master
 create mode 100644 t/t4013/diff.log_--root_master
 create mode 100644 t/t4013/diff.log_-GF_-p_--pickaxe-all_master
 create mode 100644 t/t4013/diff.log_-GF_-p_master
 create mode 100644 t/t4013/diff.log_-GF_master
 create mode 100644 t/t4013/diff.log_-IA_-IB_-I1_-I2_-p_master
 create mode 100644 t/t4013/diff.log_-SF_-p_master
 create mode 100644 t/t4013/diff.log_-SF_master
 create mode 100644 t/t4013/diff.log_-SF_master_--max-count=0
 create mode 100644 t/t4013/diff.log_-SF_master_--max-count=1
 create mode 100644 t/t4013/diff.log_-SF_master_--max-count=2
 create mode 100644 t/t4013/diff.log_-S_F_master
 create mode 100644 t/t4013/diff.log_-c_-m_-p_master
 create mode 100644 t/t4013/diff.log_-m_--raw_master
 create mode 100644 t/t4013/diff.log_-m_--stat_master
 create mode 100644 t/t4013/diff.log_-m_-p_--first-parent_master
 create mode 100644 t/t4013/diff.log_-m_-p_master
 create mode 100644 t/t4013/diff.log_-p_--diff-merges=first-parent_master
 create mode 100644 t/t4013/diff.log_-p_--first-parent_master
 create mode 100644 t/t4013/diff.log_-p_master
 create mode 100644 t/t4013/diff.log_master
 create mode 100644 t/t4013/diff.noellipses-diff-tree_--root_--abbrev_initial
 create mode 100644 t/t4013/diff.noellipses-diff-tree_--root_-r_--abbrev=4_initial
 create mode 100644 t/t4013/diff.noellipses-diff-tree_--root_-r_--abbrev_initial
 create mode 100644 t/t4013/diff.noellipses-diff-tree_-c_--abbrev_master
 create mode 100644 t/t4013/diff.noellipses-diff_--no-index_--raw_--abbrev=4_dir2_dir
 create mode 100644 t/t4013/diff.noellipses-diff_--no-index_--raw_dir2_dir
 create mode 100644 t/t4013/diff.noellipses-diff_--patch-with-raw_-r_initial..side
 create mode 100644 t/t4013/diff.noellipses-diff_--patch-with-raw_initial..side
 create mode 100644 t/t4013/diff.noellipses-diff_--raw_--abbrev=4_initial
 create mode 100644 t/t4013/diff.noellipses-diff_--raw_initial
 create mode 100644 t/t4013/diff.noellipses-show_--patch-with-raw_side
 create mode 100644 t/t4013/diff.noellipses-whatchanged_--root_master
 create mode 100644 t/t4013/diff.noellipses-whatchanged_-SF_master
 create mode 100644 t/t4013/diff.noellipses-whatchanged_master
 create mode 100644 t/t4013/diff.rev-list_--children_HEAD
 create mode 100644 t/t4013/diff.rev-list_--parents_HEAD
 create mode 100644 t/t4013/diff.show_--first-parent_master
 create mode 100644 t/t4013/diff.show_--patch-with-raw_side
 create mode 100644 t/t4013/diff.show_--patch-with-stat_--summary_side
 create mode 100644 t/t4013/diff.show_--patch-with-stat_side
 create mode 100644 t/t4013/diff.show_--root_initial
 create mode 100644 t/t4013/diff.show_--stat_--summary_side
 create mode 100644 t/t4013/diff.show_--stat_side
 create mode 100644 t/t4013/diff.show_-c_master
 create mode 100644 t/t4013/diff.show_-m_master
 create mode 100644 t/t4013/diff.show_initial
 create mode 100644 t/t4013/diff.show_master
 create mode 100644 t/t4013/diff.show_side
 create mode 100644 t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
 create mode 100644 t/t4013/diff.whatchanged_--patch-with-stat_master
 create mode 100644 t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
 create mode 100644 t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
 create mode 100644 t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
 create mode 100644 t/t4013/diff.whatchanged_--root_--patch-with-stat_master
 create mode 100644 t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
 create mode 100644 t/t4013/diff.whatchanged_--root_-p_master
 create mode 100644 t/t4013/diff.whatchanged_--root_master
 create mode 100644 t/t4013/diff.whatchanged_-SF_-p_master
 create mode 100644 t/t4013/diff.whatchanged_-SF_master
 create mode 100644 t/t4013/diff.whatchanged_-p_master
 create mode 100644 t/t4013/diff.whatchanged_master
 create mode 100755 t/t4014-format-patch.sh
 create mode 100755 t/t4015-diff-whitespace.sh
 create mode 100755 t/t4016-diff-quote.sh
 create mode 100755 t/t4017-diff-retval.sh
 create mode 100755 t/t4018-diff-funcname.sh
 create mode 100644 t/t4018/README
 create mode 100644 t/t4018/bash-arithmetic-function
 create mode 100644 t/t4018/bash-bashism-style-compact
 create mode 100644 t/t4018/bash-bashism-style-function
 create mode 100644 t/t4018/bash-bashism-style-whitespace
 create mode 100644 t/t4018/bash-conditional-function
 create mode 100644 t/t4018/bash-missing-parentheses
 create mode 100644 t/t4018/bash-mixed-style-compact
 create mode 100644 t/t4018/bash-mixed-style-function
 create mode 100644 t/t4018/bash-nested-functions
 create mode 100644 t/t4018/bash-other-characters
 create mode 100644 t/t4018/bash-posix-style-compact
 create mode 100644 t/t4018/bash-posix-style-function
 create mode 100644 t/t4018/bash-posix-style-whitespace
 create mode 100644 t/t4018/bash-subshell-function
 create mode 100644 t/t4018/bash-trailing-comment
 create mode 100644 t/t4018/cpp-c++-function
 create mode 100644 t/t4018/cpp-class-constructor
 create mode 100644 t/t4018/cpp-class-constructor-mem-init
 create mode 100644 t/t4018/cpp-class-definition
 create mode 100644 t/t4018/cpp-class-definition-derived
 create mode 100644 t/t4018/cpp-class-destructor
 create mode 100644 t/t4018/cpp-function-returning-global-type
 create mode 100644 t/t4018/cpp-function-returning-nested
 create mode 100644 t/t4018/cpp-function-returning-pointer
 create mode 100644 t/t4018/cpp-function-returning-reference
 create mode 100644 t/t4018/cpp-gnu-style-function
 create mode 100644 t/t4018/cpp-namespace-definition
 create mode 100644 t/t4018/cpp-operator-definition
 create mode 100644 t/t4018/cpp-skip-access-specifiers
 create mode 100644 t/t4018/cpp-skip-comment-block
 create mode 100644 t/t4018/cpp-skip-labels
 create mode 100644 t/t4018/cpp-struct-definition
 create mode 100644 t/t4018/cpp-struct-single-line
 create mode 100644 t/t4018/cpp-template-function-definition
 create mode 100644 t/t4018/cpp-union-definition
 create mode 100644 t/t4018/cpp-void-c-function
 create mode 100644 t/t4018/csharp-exclude-assignments
 create mode 100644 t/t4018/csharp-exclude-control-statements
 create mode 100644 t/t4018/csharp-exclude-exceptions
 create mode 100644 t/t4018/csharp-exclude-generic-method-calls
 create mode 100644 t/t4018/csharp-exclude-init-dispose
 create mode 100644 t/t4018/csharp-exclude-iterations
 create mode 100644 t/t4018/csharp-exclude-method-calls
 create mode 100644 t/t4018/csharp-exclude-other
 create mode 100644 t/t4018/csharp-method
 create mode 100644 t/t4018/csharp-method-array
 create mode 100644 t/t4018/csharp-method-explicit
 create mode 100644 t/t4018/csharp-method-generics
 create mode 100644 t/t4018/csharp-method-generics-alternate-spaces
 create mode 100644 t/t4018/csharp-method-modifiers
 create mode 100644 t/t4018/csharp-method-multiline
 create mode 100644 t/t4018/csharp-method-params
 create mode 100644 t/t4018/csharp-method-special-chars
 create mode 100644 t/t4018/csharp-method-with-spacing
 create mode 100644 t/t4018/csharp-property
 create mode 100644 t/t4018/csharp-property-braces-same-line
 create mode 100644 t/t4018/css-attribute-value-selector
 create mode 100644 t/t4018/css-block-level-@-statements
 create mode 100644 t/t4018/css-brace-in-col-1
 create mode 100644 t/t4018/css-class-selector
 create mode 100644 t/t4018/css-colon-eol
 create mode 100644 t/t4018/css-colon-selector
 create mode 100644 t/t4018/css-common
 create mode 100644 t/t4018/css-id-selector
 create mode 100644 t/t4018/css-long-selector-list
 create mode 100644 t/t4018/css-prop-sans-indent
 create mode 100644 t/t4018/css-root-selector
 create mode 100644 t/t4018/css-short-selector-list
 create mode 100644 t/t4018/css-trailing-space
 create mode 100644 t/t4018/custom1-pattern
 create mode 100644 t/t4018/custom2-match-to-end-of-line
 create mode 100644 t/t4018/custom3-alternation-in-pattern
 create mode 100644 t/t4018/dts-labels
 create mode 100644 t/t4018/dts-node-unitless
 create mode 100644 t/t4018/dts-nodes
 create mode 100644 t/t4018/dts-nodes-boolean-prop
 create mode 100644 t/t4018/dts-nodes-comment1
 create mode 100644 t/t4018/dts-nodes-comment2
 create mode 100644 t/t4018/dts-nodes-multiline-prop
 create mode 100644 t/t4018/dts-reference
 create mode 100644 t/t4018/dts-root
 create mode 100644 t/t4018/dts-root-comment
 create mode 100644 t/t4018/elixir-do-not-pick-end
 create mode 100644 t/t4018/elixir-ex-unit-test
 create mode 100644 t/t4018/elixir-function
 create mode 100644 t/t4018/elixir-macro
 create mode 100644 t/t4018/elixir-module
 create mode 100644 t/t4018/elixir-module-func
 create mode 100644 t/t4018/elixir-nested-module
 create mode 100644 t/t4018/elixir-private-function
 create mode 100644 t/t4018/elixir-protocol
 create mode 100644 t/t4018/elixir-protocol-implementation
 create mode 100644 t/t4018/fortran-block-data
 create mode 100644 t/t4018/fortran-comment
 create mode 100644 t/t4018/fortran-comment-keyword
 create mode 100644 t/t4018/fortran-comment-legacy
 create mode 100644 t/t4018/fortran-comment-legacy-star
 create mode 100644 t/t4018/fortran-external-function
 create mode 100644 t/t4018/fortran-external-subroutine
 create mode 100644 t/t4018/fortran-module
 create mode 100644 t/t4018/fortran-module-procedure
 create mode 100644 t/t4018/fortran-program
 create mode 100644 t/t4018/fountain-scene
 create mode 100644 t/t4018/golang-complex-function
 create mode 100644 t/t4018/golang-func
 create mode 100644 t/t4018/golang-interface
 create mode 100644 t/t4018/golang-long-func
 create mode 100644 t/t4018/golang-struct
 create mode 100644 t/t4018/java-class-brace-on-separate-line
 create mode 100644 t/t4018/java-class-member-function
 create mode 100644 t/t4018/java-class-space-before-type-parameters
 create mode 100644 t/t4018/java-class-type-parameters
 create mode 100644 t/t4018/java-class-type-parameters-implements
 create mode 100644 t/t4018/java-enum-constant
 create mode 100644 t/t4018/java-interface-type-parameters
 create mode 100644 t/t4018/java-interface-type-parameters-extends
 create mode 100644 t/t4018/java-method-return-generic-bounded
 create mode 100644 t/t4018/java-method-return-generic-wildcard
 create mode 100644 t/t4018/java-nested-field
 create mode 100644 t/t4018/java-non-sealed
 create mode 100644 t/t4018/java-record
 create mode 100644 t/t4018/java-record-space-before-components
 create mode 100644 t/t4018/java-record-type-parameters
 create mode 100644 t/t4018/java-sealed
 create mode 100644 t/t4018/java-sealed-permits
 create mode 100644 t/t4018/java-sealed-type-parameters
 create mode 100644 t/t4018/java-sealed-type-parameters-implements-permits
 create mode 100644 t/t4018/java-sealed-type-parameters-permits
 create mode 100644 t/t4018/kotlin-class
 create mode 100644 t/t4018/kotlin-enum-class
 create mode 100644 t/t4018/kotlin-fun
 create mode 100644 t/t4018/kotlin-inheritace-class
 create mode 100644 t/t4018/kotlin-inline-class
 create mode 100644 t/t4018/kotlin-interface
 create mode 100644 t/t4018/kotlin-nested-fun
 create mode 100644 t/t4018/kotlin-public-class
 create mode 100644 t/t4018/kotlin-sealed-class
 create mode 100644 t/t4018/markdown-heading-indented
 create mode 100644 t/t4018/markdown-heading-non-headings
 create mode 100644 t/t4018/matlab-class-definition
 create mode 100644 t/t4018/matlab-function
 create mode 100644 t/t4018/matlab-octave-section-1
 create mode 100644 t/t4018/matlab-octave-section-2
 create mode 100644 t/t4018/matlab-section
 create mode 100644 t/t4018/perl-skip-end-of-heredoc
 create mode 100644 t/t4018/perl-skip-forward-decl
 create mode 100644 t/t4018/perl-skip-sub-in-pod
 create mode 100644 t/t4018/perl-sub-definition
 create mode 100644 t/t4018/perl-sub-definition-kr-brace
 create mode 100644 t/t4018/php-abstract-class
 create mode 100644 t/t4018/php-abstract-method
 create mode 100644 t/t4018/php-class
 create mode 100644 t/t4018/php-enum
 create mode 100644 t/t4018/php-final-class
 create mode 100644 t/t4018/php-final-method
 create mode 100644 t/t4018/php-function
 create mode 100644 t/t4018/php-interface
 create mode 100644 t/t4018/php-method
 create mode 100644 t/t4018/php-trait
 create mode 100644 t/t4018/python-async-def
 create mode 100644 t/t4018/python-class
 create mode 100644 t/t4018/python-def
 create mode 100644 t/t4018/python-indented-async-def
 create mode 100644 t/t4018/python-indented-class
 create mode 100644 t/t4018/python-indented-def
 create mode 100644 t/t4018/rust-fn
 create mode 100644 t/t4018/rust-impl
 create mode 100644 t/t4018/rust-macro-rules
 create mode 100644 t/t4018/rust-struct
 create mode 100644 t/t4018/rust-trait
 create mode 100644 t/t4018/scheme-class
 create mode 100644 t/t4018/scheme-def
 create mode 100644 t/t4018/scheme-def-variant
 create mode 100644 t/t4018/scheme-define-slash-public
 create mode 100644 t/t4018/scheme-define-syntax
 create mode 100644 t/t4018/scheme-define-variant
 create mode 100644 t/t4018/scheme-library
 create mode 100644 t/t4018/scheme-local-define
 create mode 100644 t/t4018/scheme-module
 create mode 100644 t/t4018/scheme-top-level-define
 create mode 100644 t/t4018/scheme-user-defined-define
 create mode 100755 t/t4019-diff-wserror.sh
 create mode 100755 t/t4020-diff-external.sh
 create mode 100644 t/t4020/diff.NUL
 create mode 100755 t/t4021-format-patch-numbered.sh
 create mode 100755 t/t4022-diff-rewrite.sh
 create mode 100755 t/t4023-diff-rename-typechange.sh
 create mode 100755 t/t4024-diff-optimize-common.sh
 create mode 100755 t/t4025-hunk-header.sh
 create mode 100755 t/t4026-color.sh
 create mode 100755 t/t4027-diff-submodule.sh
 create mode 100755 t/t4028-format-patch-mime-headers.sh
 create mode 100755 t/t4029-diff-trailing-space.sh
 create mode 100755 t/t4030-diff-textconv.sh
 create mode 100755 t/t4031-diff-rewrite-binary.sh
 create mode 100755 t/t4032-diff-inter-hunk-context.sh
 create mode 100755 t/t4033-diff-patience.sh
 create mode 100755 t/t4034-diff-words.sh
 create mode 100644 t/t4034/ada/expect
 create mode 100644 t/t4034/ada/post
 create mode 100644 t/t4034/ada/pre
 create mode 100644 t/t4034/bibtex/expect
 create mode 100644 t/t4034/bibtex/post
 create mode 100644 t/t4034/bibtex/pre
 create mode 100644 t/t4034/cpp/expect
 create mode 100644 t/t4034/cpp/post
 create mode 100644 t/t4034/cpp/pre
 create mode 100644 t/t4034/csharp/expect
 create mode 100644 t/t4034/csharp/post
 create mode 100644 t/t4034/csharp/pre
 create mode 100644 t/t4034/css/expect
 create mode 100644 t/t4034/css/post
 create mode 100644 t/t4034/css/pre
 create mode 100644 t/t4034/dts/expect
 create mode 100644 t/t4034/dts/post
 create mode 100644 t/t4034/dts/pre
 create mode 100644 t/t4034/fortran/expect
 create mode 100644 t/t4034/fortran/post
 create mode 100644 t/t4034/fortran/pre
 create mode 100644 t/t4034/html/expect
 create mode 100644 t/t4034/html/post
 create mode 100644 t/t4034/html/pre
 create mode 100644 t/t4034/java/expect
 create mode 100644 t/t4034/java/post
 create mode 100644 t/t4034/java/pre
 create mode 100644 t/t4034/kotlin/expect
 create mode 100644 t/t4034/kotlin/post
 create mode 100644 t/t4034/kotlin/pre
 create mode 100644 t/t4034/matlab/expect
 create mode 100644 t/t4034/matlab/post
 create mode 100644 t/t4034/matlab/pre
 create mode 100644 t/t4034/objc/expect
 create mode 100644 t/t4034/objc/post
 create mode 100644 t/t4034/objc/pre
 create mode 100644 t/t4034/pascal/expect
 create mode 100644 t/t4034/pascal/post
 create mode 100644 t/t4034/pascal/pre
 create mode 100644 t/t4034/perl/expect
 create mode 100644 t/t4034/perl/post
 create mode 100644 t/t4034/perl/pre
 create mode 100644 t/t4034/php/expect
 create mode 100644 t/t4034/php/post
 create mode 100644 t/t4034/php/pre
 create mode 100644 t/t4034/python/expect
 create mode 100644 t/t4034/python/post
 create mode 100644 t/t4034/python/pre
 create mode 100644 t/t4034/ruby/expect
 create mode 100644 t/t4034/ruby/post
 create mode 100644 t/t4034/ruby/pre
 create mode 100644 t/t4034/scheme/expect
 create mode 100644 t/t4034/scheme/post
 create mode 100644 t/t4034/scheme/pre
 create mode 100644 t/t4034/tex/expect
 create mode 100644 t/t4034/tex/post
 create mode 100644 t/t4034/tex/pre
 create mode 100755 t/t4035-diff-quiet.sh
 create mode 100755 t/t4036-format-patch-signer-mime.sh
 create mode 100755 t/t4037-diff-r-t-dirs.sh
 create mode 100755 t/t4038-diff-combined.sh
 create mode 100755 t/t4039-diff-assume-unchanged.sh
 create mode 100755 t/t4040-whitespace-status.sh
 create mode 100755 t/t4041-diff-submodule-option.sh
 create mode 100755 t/t4042-diff-textconv-caching.sh
 create mode 100755 t/t4043-diff-rename-binary.sh
 create mode 100755 t/t4044-diff-index-unique-abbrev.sh
 create mode 100755 t/t4045-diff-relative.sh
 create mode 100755 t/t4046-diff-unmerged.sh
 create mode 100755 t/t4047-diff-dirstat.sh
 create mode 100755 t/t4048-diff-combined-binary.sh
 create mode 100755 t/t4049-diff-stat-count.sh
 create mode 100755 t/t4050-diff-histogram.sh
 create mode 100755 t/t4051-diff-function-context.sh
 create mode 100644 t/t4051/appended1.c
 create mode 100644 t/t4051/appended2.c
 create mode 100644 t/t4051/dummy.c
 create mode 100644 t/t4051/hello.c
 create mode 100644 t/t4051/includes.c
 create mode 100755 t/t4052-stat-output.sh
 create mode 100755 t/t4053-diff-no-index.sh
 create mode 100755 t/t4054-diff-bogus-tree.sh
 create mode 100755 t/t4055-diff-context.sh
 create mode 100755 t/t4056-diff-order.sh
 create mode 100755 t/t4057-diff-combined-paths.sh
 create mode 100755 t/t4058-diff-duplicates.sh
 create mode 100755 t/t4059-diff-submodule-not-initialized.sh
 create mode 100755 t/t4060-diff-submodule-option-diff-format.sh
 create mode 100755 t/t4061-diff-indent.sh
 create mode 100755 t/t4062-diff-pickaxe.sh
 create mode 100755 t/t4063-diff-blobs.sh
 create mode 100755 t/t4064-diff-oidfind.sh
 create mode 100755 t/t4065-diff-anchored.sh
 create mode 100755 t/t4066-diff-emit-delay.sh
 create mode 100755 t/t4067-diff-partial-clone.sh
 create mode 100755 t/t4068-diff-symmetric-merge-base.sh
 create mode 100755 t/t4069-remerge-diff.sh
 create mode 100755 t/t4100-apply-stat.sh
 create mode 100644 t/t4100/t-apply-1.expect
 create mode 100644 t/t4100/t-apply-1.patch
 create mode 100644 t/t4100/t-apply-2.expect
 create mode 100644 t/t4100/t-apply-2.patch
 create mode 100644 t/t4100/t-apply-3.expect
 create mode 100644 t/t4100/t-apply-3.patch
 create mode 100644 t/t4100/t-apply-4.expect
 create mode 100644 t/t4100/t-apply-4.patch
 create mode 100644 t/t4100/t-apply-5.expect
 create mode 100644 t/t4100/t-apply-5.patch
 create mode 100644 t/t4100/t-apply-6.expect
 create mode 100644 t/t4100/t-apply-6.patch
 create mode 100644 t/t4100/t-apply-7.expect
 create mode 100644 t/t4100/t-apply-7.patch
 create mode 100644 t/t4100/t-apply-8.expect
 create mode 100644 t/t4100/t-apply-8.patch
 create mode 100644 t/t4100/t-apply-9.expect
 create mode 100644 t/t4100/t-apply-9.patch
 create mode 100755 t/t4101-apply-nonl.sh
 create mode 100644 t/t4101/diff.0-1
 create mode 100644 t/t4101/diff.0-2
 create mode 100644 t/t4101/diff.0-3
 create mode 100644 t/t4101/diff.1-0
 create mode 100644 t/t4101/diff.1-2
 create mode 100644 t/t4101/diff.1-3
 create mode 100644 t/t4101/diff.2-0
 create mode 100644 t/t4101/diff.2-1
 create mode 100644 t/t4101/diff.2-3
 create mode 100644 t/t4101/diff.3-0
 create mode 100644 t/t4101/diff.3-1
 create mode 100644 t/t4101/diff.3-2
 create mode 100755 t/t4102-apply-rename.sh
 create mode 100755 t/t4103-apply-binary.sh
 create mode 100755 t/t4104-apply-boundary.sh
 create mode 100755 t/t4105-apply-fuzz.sh
 create mode 100755 t/t4106-apply-stdin.sh
 create mode 100755 t/t4107-apply-ignore-whitespace.sh
 create mode 100755 t/t4108-apply-threeway.sh
 create mode 100755 t/t4109-apply-multifrag.sh
 create mode 100644 t/t4109/expect-1
 create mode 100644 t/t4109/expect-2
 create mode 100644 t/t4109/expect-3
 create mode 100644 t/t4109/patch1.patch
 create mode 100644 t/t4109/patch2.patch
 create mode 100644 t/t4109/patch3.patch
 create mode 100644 t/t4109/patch4.patch
 create mode 100755 t/t4110-apply-scan.sh
 create mode 100644 t/t4110/expect
 create mode 100644 t/t4110/patch1.patch
 create mode 100644 t/t4110/patch2.patch
 create mode 100644 t/t4110/patch3.patch
 create mode 100644 t/t4110/patch4.patch
 create mode 100644 t/t4110/patch5.patch
 create mode 100755 t/t4111-apply-subdir.sh
 create mode 100755 t/t4112-apply-renames.sh
 create mode 100755 t/t4113-apply-ending.sh
 create mode 100755 t/t4114-apply-typechange.sh
 create mode 100755 t/t4115-apply-symlink.sh
 create mode 100755 t/t4116-apply-reverse.sh
 create mode 100755 t/t4117-apply-reject.sh
 create mode 100755 t/t4118-apply-empty-context.sh
 create mode 100755 t/t4119-apply-config.sh
 create mode 100755 t/t4120-apply-popt.sh
 create mode 100755 t/t4121-apply-diffs.sh
 create mode 100755 t/t4122-apply-symlink-inside.sh
 create mode 100755 t/t4123-apply-shrink.sh
 create mode 100755 t/t4124-apply-ws-rule.sh
 create mode 100755 t/t4125-apply-ws-fuzz.sh
 create mode 100755 t/t4126-apply-empty.sh
 create mode 100755 t/t4127-apply-same-fn.sh
 create mode 100755 t/t4128-apply-root.sh
 create mode 100755 t/t4129-apply-samemode.sh
 create mode 100755 t/t4130-apply-criss-cross-rename.sh
 create mode 100755 t/t4131-apply-fake-ancestor.sh
 create mode 100755 t/t4132-apply-removal.sh
 create mode 100755 t/t4133-apply-filenames.sh
 create mode 100755 t/t4134-apply-submodule.sh
 create mode 100755 t/t4135-apply-weird-filenames.sh
 create mode 100644 t/t4135/.gitignore
 create mode 100644 t/t4135/add-plain.diff
 create mode 100644 t/t4135/add-with backslash.diff
 create mode 100644 t/t4135/add-with quote.diff
 create mode 100644 t/t4135/add-with spaces.diff
 create mode 100644 t/t4135/add-with tab.diff
 create mode 100644 t/t4135/damaged-tz.diff
 create mode 100644 t/t4135/damaged.diff
 create mode 100644 t/t4135/diff-plain.diff
 create mode 100644 t/t4135/diff-with backslash.diff
 create mode 100644 t/t4135/diff-with quote.diff
 create mode 100644 t/t4135/diff-with spaces.diff
 create mode 100644 t/t4135/diff-with tab.diff
 create mode 100644 t/t4135/funny-tz.diff
 create mode 100644 t/t4135/git-plain.diff
 create mode 100644 t/t4135/git-with backslash.diff
 create mode 100644 t/t4135/git-with quote.diff
 create mode 100644 t/t4135/git-with spaces.diff
 create mode 100644 t/t4135/git-with tab.diff
 create mode 100755 t/t4135/make-patches
 create mode 100755 t/t4136-apply-check.sh
 create mode 100755 t/t4137-apply-submodule.sh
 create mode 100755 t/t4138-apply-ws-expansion.sh
 create mode 100755 t/t4139-apply-escape.sh
 create mode 100755 t/t4140-apply-ita.sh
 create mode 100755 t/t4141-apply-too-large.sh
 create mode 100755 t/t4150-am.sh
 create mode 100755 t/t4151-am-abort.sh
 create mode 100755 t/t4152-am-subjects.sh
 create mode 100755 t/t4153-am-resume-override-opts.sh
 create mode 100755 t/t4200-rerere.sh
 create mode 100755 t/t4201-shortlog.sh
 create mode 100755 t/t4202-log.sh
 create mode 100755 t/t4203-mailmap.sh
 create mode 100755 t/t4204-patch-id.sh
 create mode 100755 t/t4205-log-pretty-formats.sh
 create mode 100755 t/t4206-log-follow-harder-copies.sh
 create mode 100755 t/t4207-log-decoration-colors.sh
 create mode 100755 t/t4208-log-magic-pathspec.sh
 create mode 100755 t/t4209-log-pickaxe.sh
 create mode 100755 t/t4210-log-i18n.sh
 create mode 100755 t/t4211-line-log.sh
 create mode 100644 t/t4211/history.export
 create mode 100644 t/t4211/sha1/expect.beginning-of-file
 create mode 100644 t/t4211/sha1/expect.end-of-file
 create mode 100644 t/t4211/sha1/expect.move-support-f
 create mode 100644 t/t4211/sha1/expect.multiple
 create mode 100644 t/t4211/sha1/expect.multiple-overlapping
 create mode 100644 t/t4211/sha1/expect.multiple-superset
 create mode 100644 t/t4211/sha1/expect.parallel-change-f-to-main
 create mode 100644 t/t4211/sha1/expect.simple-f
 create mode 100644 t/t4211/sha1/expect.simple-f-to-main
 create mode 100644 t/t4211/sha1/expect.simple-main
 create mode 100644 t/t4211/sha1/expect.simple-main-to-end
 create mode 100644 t/t4211/sha1/expect.two-ranges
 create mode 100644 t/t4211/sha1/expect.vanishes-early
 create mode 100644 t/t4211/sha256/expect.beginning-of-file
 create mode 100644 t/t4211/sha256/expect.end-of-file
 create mode 100644 t/t4211/sha256/expect.move-support-f
 create mode 100644 t/t4211/sha256/expect.multiple
 create mode 100644 t/t4211/sha256/expect.multiple-overlapping
 create mode 100644 t/t4211/sha256/expect.multiple-superset
 create mode 100644 t/t4211/sha256/expect.parallel-change-f-to-main
 create mode 100644 t/t4211/sha256/expect.simple-f
 create mode 100644 t/t4211/sha256/expect.simple-f-to-main
 create mode 100644 t/t4211/sha256/expect.simple-main
 create mode 100644 t/t4211/sha256/expect.simple-main-to-end
 create mode 100644 t/t4211/sha256/expect.two-ranges
 create mode 100644 t/t4211/sha256/expect.vanishes-early
 create mode 100755 t/t4212-log-corrupt.sh
 create mode 100755 t/t4213-log-tabexpand.sh
 create mode 100755 t/t4214-log-graph-octopus.sh
 create mode 100755 t/t4215-log-skewed-merges.sh
 create mode 100755 t/t4216-log-bloom.sh
 create mode 100755 t/t4217-log-limit.sh
 create mode 100755 t/t4252-am-options.sh
 create mode 100644 t/t4252/am-test-1-1
 create mode 100644 t/t4252/am-test-1-2
 create mode 100644 t/t4252/am-test-2-1
 create mode 100644 t/t4252/am-test-2-2
 create mode 100644 t/t4252/am-test-3-1
 create mode 100644 t/t4252/am-test-3-2
 create mode 100644 t/t4252/am-test-4-1
 create mode 100644 t/t4252/am-test-4-2
 create mode 100644 t/t4252/am-test-5-1
 create mode 100644 t/t4252/am-test-5-2
 create mode 100644 t/t4252/am-test-6-1
 create mode 100644 t/t4252/file-1-0
 create mode 100644 t/t4252/file-2-0
 create mode 100755 t/t4253-am-keep-cr-dos.sh
 create mode 100755 t/t4254-am-corrupt.sh
 create mode 100755 t/t4255-am-submodule.sh
 create mode 100755 t/t4256-am-format-flowed.sh
 create mode 100644 t/t4256/1/mailinfo.c
 create mode 100644 t/t4256/1/mailinfo.c.orig
 create mode 100644 t/t4256/1/patch
 create mode 100755 t/t4257-am-interactive.sh
 create mode 100755 t/t4258-am-quoted-cr.sh
 create mode 100644 t/t4258/mbox
 create mode 100755 t/t4300-merge-tree.sh
 create mode 100755 t/t4301-merge-tree-write-tree.sh
 create mode 100755 t/t5000-tar-tree.sh
 create mode 100644 t/t5000/huge-and-future.tar
 create mode 100644 t/t5000/huge-object
 create mode 100644 t/t5000/pax.tar
 create mode 100755 t/t5001-archive-attr.sh
 create mode 100755 t/t5002-archive-attr-pattern.sh
 create mode 100755 t/t5003-archive-zip.sh
 create mode 100644 t/t5003/infozip-symlinks.zip
 create mode 100755 t/t5004-archive-corner-cases.sh
 create mode 100644 t/t5004/big-pack.zip
 create mode 100644 t/t5004/empty-with-pax-header.tar
 create mode 100644 t/t5004/empty.zip
 create mode 100755 t/t5100-mailinfo.sh
 create mode 100644 t/t5100/.gitattributes
 create mode 100644 t/t5100/0001mboxrd
 create mode 100644 t/t5100/0002mboxrd
 create mode 100644 t/t5100/comment.expect
 create mode 100644 t/t5100/comment.in
 create mode 100644 t/t5100/embed-from.expect
 create mode 100644 t/t5100/embed-from.in
 create mode 100644 t/t5100/empty
 create mode 100644 t/t5100/info-from.expect
 create mode 100644 t/t5100/info-from.in
 create mode 100644 t/t5100/info0001
 create mode 100644 t/t5100/info0002
 create mode 100644 t/t5100/info0003
 create mode 100644 t/t5100/info0004
 create mode 100644 t/t5100/info0005
 create mode 100644 t/t5100/info0006
 create mode 100644 t/t5100/info0007
 create mode 100644 t/t5100/info0008
 create mode 100644 t/t5100/info0009
 create mode 100644 t/t5100/info0010
 create mode 100644 t/t5100/info0011
 create mode 100644 t/t5100/info0012
 create mode 100644 t/t5100/info0012--message-id
 create mode 100644 t/t5100/info0013
 create mode 100644 t/t5100/info0014
 create mode 100644 t/t5100/info0014--scissors
 create mode 100644 t/t5100/info0015
 create mode 100644 t/t5100/info0015--no-inbody-headers
 create mode 100644 t/t5100/info0016
 create mode 100644 t/t5100/info0016--no-inbody-headers
 create mode 100644 t/t5100/info0017
 create mode 100644 t/t5100/info0018
 create mode 100644 t/t5100/info0018--no-inbody-headers
 create mode 100644 t/t5100/msg0001
 create mode 100644 t/t5100/msg0002
 create mode 100644 t/t5100/msg0003
 create mode 100644 t/t5100/msg0004
 create mode 100644 t/t5100/msg0005
 create mode 100644 t/t5100/msg0006
 create mode 100644 t/t5100/msg0007
 create mode 100644 t/t5100/msg0008
 create mode 100644 t/t5100/msg0009
 create mode 100644 t/t5100/msg0010
 create mode 100644 t/t5100/msg0011
 create mode 100644 t/t5100/msg0012
 create mode 100644 t/t5100/msg0012--message-id
 create mode 100644 t/t5100/msg0013
 create mode 100644 t/t5100/msg0014
 create mode 100644 t/t5100/msg0014--scissors
 create mode 100644 t/t5100/msg0015
 create mode 100644 t/t5100/msg0015--no-inbody-headers
 create mode 100644 t/t5100/msg0016
 create mode 100644 t/t5100/msg0016--no-inbody-headers
 create mode 100644 t/t5100/msg0017
 create mode 100644 t/t5100/msg0018
 create mode 100644 t/t5100/msg0018--no-inbody-headers
 create mode 100644 t/t5100/nul-b64.expect
 create mode 100644 t/t5100/nul-b64.in
 create mode 100644 t/t5100/nul-plain
 create mode 100644 t/t5100/patch0001
 create mode 100644 t/t5100/patch0002
 create mode 100644 t/t5100/patch0003
 create mode 100644 t/t5100/patch0004
 create mode 100644 t/t5100/patch0005
 create mode 100644 t/t5100/patch0006
 create mode 100644 t/t5100/patch0007
 create mode 100644 t/t5100/patch0008
 create mode 100644 t/t5100/patch0009
 create mode 100644 t/t5100/patch0010
 create mode 100644 t/t5100/patch0011
 create mode 100644 t/t5100/patch0012
 create mode 100644 t/t5100/patch0012--message-id
 create mode 100644 t/t5100/patch0013
 create mode 100644 t/t5100/patch0014
 create mode 100644 t/t5100/patch0014--scissors
 create mode 100644 t/t5100/patch0015
 create mode 100644 t/t5100/patch0015--no-inbody-headers
 create mode 100644 t/t5100/patch0016
 create mode 100644 t/t5100/patch0016--no-inbody-headers
 create mode 100644 t/t5100/patch0017
 create mode 100644 t/t5100/patch0018
 create mode 100644 t/t5100/patch0018--no-inbody-headers
 create mode 100644 t/t5100/quoted-cr-info
 create mode 100644 t/t5100/quoted-cr-msg
 create mode 100644 t/t5100/quoted-cr-patch
 create mode 100644 t/t5100/quoted-cr.mbox
 create mode 100644 t/t5100/quoted-from.expect
 create mode 100644 t/t5100/quoted-from.in
 create mode 100644 t/t5100/quoted-string.expect
 create mode 100644 t/t5100/quoted-string.in
 create mode 100644 t/t5100/rfc2047-info-0001
 create mode 100644 t/t5100/rfc2047-info-0002
 create mode 100644 t/t5100/rfc2047-info-0003
 create mode 100644 t/t5100/rfc2047-info-0004
 create mode 100644 t/t5100/rfc2047-info-0005
 create mode 100644 t/t5100/rfc2047-info-0006
 create mode 100644 t/t5100/rfc2047-info-0007
 create mode 100644 t/t5100/rfc2047-info-0008
 create mode 100644 t/t5100/rfc2047-info-0009
 create mode 100644 t/t5100/rfc2047-info-0010
 create mode 100644 t/t5100/rfc2047-info-0011
 create mode 100644 t/t5100/rfc2047-samples.mbox
 create mode 100644 t/t5100/sample.mbox
 create mode 100644 t/t5100/sample.mboxrd
 create mode 100755 t/t5150-request-pull.sh
 create mode 100755 t/t5200-update-server-info.sh
 create mode 100755 t/t5300-pack-object.sh
 create mode 100755 t/t5301-sliding-window.sh
 create mode 100755 t/t5302-pack-index.sh
 create mode 100755 t/t5303-pack-corruption-resilience.sh
 create mode 100755 t/t5304-prune.sh
 create mode 100755 t/t5305-include-tag.sh
 create mode 100755 t/t5306-pack-nobase.sh
 create mode 100755 t/t5307-pack-missing-commit.sh
 create mode 100755 t/t5308-pack-detect-duplicates.sh
 create mode 100755 t/t5309-pack-delta-cycles.sh
 create mode 100755 t/t5310-pack-bitmaps.sh
 create mode 100755 t/t5311-pack-bitmaps-shallow.sh
 create mode 100755 t/t5312-prune-corruption.sh
 create mode 100755 t/t5313-pack-bounds-checks.sh
 create mode 100755 t/t5314-pack-cycle-detection.sh
 create mode 100755 t/t5315-pack-objects-compression.sh
 create mode 100755 t/t5316-pack-delta-depth.sh
 create mode 100755 t/t5317-pack-objects-filter-objects.sh
 create mode 100755 t/t5318-commit-graph.sh
 create mode 100755 t/t5319-multi-pack-index.sh
 create mode 100644 t/t5319/no-objects.midx
 create mode 100755 t/t5320-delta-islands.sh
 create mode 100755 t/t5321-pack-large-objects.sh
 create mode 100755 t/t5322-pack-objects-sparse.sh
 create mode 100755 t/t5323-pack-redundant.sh
 create mode 100755 t/t5324-split-commit-graph.sh
 create mode 100755 t/t5325-reverse-index.sh
 create mode 100755 t/t5326-multi-pack-bitmaps.sh
 create mode 100755 t/t5327-multi-pack-bitmaps-rev.sh
 create mode 100755 t/t5328-commit-graph-64bit-time.sh
 create mode 100755 t/t5329-pack-objects-cruft.sh
 create mode 100755 t/t5330-no-lazy-fetch-with-commit-graph.sh
 create mode 100755 t/t5331-pack-objects-stdin.sh
 create mode 100755 t/t5332-multi-pack-reuse.sh
 create mode 100755 t/t5333-pseudo-merge-bitmaps.sh
 create mode 100755 t/t5334-incremental-multi-pack-index.sh
 create mode 100755 t/t5351-unpack-large-objects.sh
 create mode 100755 t/t5400-send-pack.sh
 create mode 100755 t/t5401-update-hooks.sh
 create mode 100755 t/t5402-post-merge-hook.sh
 create mode 100755 t/t5403-post-checkout-hook.sh
 create mode 100755 t/t5404-tracking-branches.sh
 create mode 100755 t/t5405-send-pack-rewind.sh
 create mode 100755 t/t5406-remote-rejects.sh
 create mode 100755 t/t5407-post-rewrite-hook.sh
 create mode 100755 t/t5408-send-pack-stdin.sh
 create mode 100755 t/t5409-colorize-remote-messages.sh
 create mode 100755 t/t5410-receive-pack-alternates.sh
 create mode 100755 t/t5411-proc-receive-hook.sh
 create mode 100644 t/t5411/common-functions.sh
 create mode 100644 t/t5411/once-0010-report-status-v1.sh
 create mode 100644 t/t5411/test-0000-standard-git-push.sh
 create mode 100644 t/t5411/test-0001-standard-git-push--porcelain.sh
 create mode 100644 t/t5411/test-0002-pre-receive-declined.sh
 create mode 100644 t/t5411/test-0003-pre-receive-declined--porcelain.sh
 create mode 100644 t/t5411/test-0010-proc-receive-settings.sh
 create mode 100644 t/t5411/test-0011-no-hook-error.sh
 create mode 100644 t/t5411/test-0012-no-hook-error--porcelain.sh
 create mode 100644 t/t5411/test-0013-bad-protocol.sh
 create mode 100644 t/t5411/test-0014-bad-protocol--porcelain.sh
 create mode 100644 t/t5411/test-0020-report-ng.sh
 create mode 100644 t/t5411/test-0021-report-ng--porcelain.sh
 create mode 100644 t/t5411/test-0022-report-unexpect-ref.sh
 create mode 100644 t/t5411/test-0023-report-unexpect-ref--porcelain.sh
 create mode 100644 t/t5411/test-0024-report-unknown-ref.sh
 create mode 100644 t/t5411/test-0025-report-unknown-ref--porcelain.sh
 create mode 100644 t/t5411/test-0026-push-options.sh
 create mode 100644 t/t5411/test-0027-push-options--porcelain.sh
 create mode 100644 t/t5411/test-0030-report-ok.sh
 create mode 100644 t/t5411/test-0031-report-ok--porcelain.sh
 create mode 100644 t/t5411/test-0032-report-with-options.sh
 create mode 100644 t/t5411/test-0033-report-with-options--porcelain.sh
 create mode 100644 t/t5411/test-0034-report-ft.sh
 create mode 100644 t/t5411/test-0035-report-ft--porcelain.sh
 create mode 100644 t/t5411/test-0036-report-multi-rewrite-for-one-ref.sh
 create mode 100644 t/t5411/test-0037-report-multi-rewrite-for-one-ref--porcelain.sh
 create mode 100644 t/t5411/test-0038-report-mixed-refs.sh
 create mode 100644 t/t5411/test-0039-report-mixed-refs--porcelain.sh
 create mode 100644 t/t5411/test-0040-process-all-refs.sh
 create mode 100644 t/t5411/test-0041-process-all-refs--porcelain.sh
 create mode 100644 t/t5411/test-0050-proc-receive-refs-with-modifiers.sh
 create mode 100755 t/t5500-fetch-pack.sh
 create mode 100755 t/t5501-fetch-push-alternates.sh
 create mode 100755 t/t5502-quickfetch.sh
 create mode 100755 t/t5503-tagfollow.sh
 create mode 100755 t/t5504-fetch-receive-strict.sh
 create mode 100755 t/t5505-remote.sh
 create mode 100755 t/t5506-remote-groups.sh
 create mode 100755 t/t5507-remote-environment.sh
 create mode 100755 t/t5509-fetch-push-namespaces.sh
 create mode 100755 t/t5510-fetch.sh
 create mode 100755 t/t5511-refspec.sh
 create mode 100755 t/t5512-ls-remote.sh
 create mode 100755 t/t5513-fetch-track.sh
 create mode 100755 t/t5514-fetch-multiple.sh
 create mode 100755 t/t5515-fetch-merge-logic.sh
 create mode 100644 t/t5515/fetch.br-branches-default
 create mode 100644 t/t5515/fetch.br-branches-default-merge
 create mode 100644 t/t5515/fetch.br-branches-default-merge_branches-default
 create mode 100644 t/t5515/fetch.br-branches-default-octopus
 create mode 100644 t/t5515/fetch.br-branches-default-octopus_branches-default
 create mode 100644 t/t5515/fetch.br-branches-default_branches-default
 create mode 100644 t/t5515/fetch.br-branches-one
 create mode 100644 t/t5515/fetch.br-branches-one-merge
 create mode 100644 t/t5515/fetch.br-branches-one-merge_branches-one
 create mode 100644 t/t5515/fetch.br-branches-one-octopus
 create mode 100644 t/t5515/fetch.br-branches-one-octopus_branches-one
 create mode 100644 t/t5515/fetch.br-branches-one_branches-one
 create mode 100644 t/t5515/fetch.br-config-explicit
 create mode 100644 t/t5515/fetch.br-config-explicit-merge
 create mode 100644 t/t5515/fetch.br-config-explicit-merge_config-explicit
 create mode 100644 t/t5515/fetch.br-config-explicit-octopus
 create mode 100644 t/t5515/fetch.br-config-explicit-octopus_config-explicit
 create mode 100644 t/t5515/fetch.br-config-explicit_config-explicit
 create mode 100644 t/t5515/fetch.br-config-glob
 create mode 100644 t/t5515/fetch.br-config-glob-merge
 create mode 100644 t/t5515/fetch.br-config-glob-merge_config-glob
 create mode 100644 t/t5515/fetch.br-config-glob-octopus
 create mode 100644 t/t5515/fetch.br-config-glob-octopus_config-glob
 create mode 100644 t/t5515/fetch.br-config-glob_config-glob
 create mode 100644 t/t5515/fetch.br-remote-explicit
 create mode 100644 t/t5515/fetch.br-remote-explicit-merge
 create mode 100644 t/t5515/fetch.br-remote-explicit-merge_remote-explicit
 create mode 100644 t/t5515/fetch.br-remote-explicit-octopus
 create mode 100644 t/t5515/fetch.br-remote-explicit-octopus_remote-explicit
 create mode 100644 t/t5515/fetch.br-remote-explicit_remote-explicit
 create mode 100644 t/t5515/fetch.br-remote-glob
 create mode 100644 t/t5515/fetch.br-remote-glob-merge
 create mode 100644 t/t5515/fetch.br-remote-glob-merge_remote-glob
 create mode 100644 t/t5515/fetch.br-remote-glob-octopus
 create mode 100644 t/t5515/fetch.br-remote-glob-octopus_remote-glob
 create mode 100644 t/t5515/fetch.br-remote-glob_remote-glob
 create mode 100644 t/t5515/fetch.br-unconfig
 create mode 100644 t/t5515/fetch.br-unconfig_--tags_.._.git
 create mode 100644 t/t5515/fetch.br-unconfig_.._.git
 create mode 100644 t/t5515/fetch.br-unconfig_.._.git_one
 create mode 100644 t/t5515/fetch.br-unconfig_.._.git_one_tag_tag-one_tag_tag-three-file
 create mode 100644 t/t5515/fetch.br-unconfig_.._.git_one_two
 create mode 100644 t/t5515/fetch.br-unconfig_.._.git_tag_tag-one-tree_tag_tag-three-file
 create mode 100644 t/t5515/fetch.br-unconfig_.._.git_tag_tag-one_tag_tag-three
 create mode 100644 t/t5515/fetch.br-unconfig_branches-default
 create mode 100644 t/t5515/fetch.br-unconfig_branches-one
 create mode 100644 t/t5515/fetch.br-unconfig_config-explicit
 create mode 100644 t/t5515/fetch.br-unconfig_config-glob
 create mode 100644 t/t5515/fetch.br-unconfig_remote-explicit
 create mode 100644 t/t5515/fetch.br-unconfig_remote-glob
 create mode 100644 t/t5515/fetch.main
 create mode 100644 t/t5515/fetch.main_--tags_.._.git
 create mode 100644 t/t5515/fetch.main_.._.git
 create mode 100644 t/t5515/fetch.main_.._.git_one
 create mode 100644 t/t5515/fetch.main_.._.git_one_tag_tag-one_tag_tag-three-file
 create mode 100644 t/t5515/fetch.main_.._.git_one_two
 create mode 100644 t/t5515/fetch.main_.._.git_tag_tag-one-tree_tag_tag-three-file
 create mode 100644 t/t5515/fetch.main_.._.git_tag_tag-one_tag_tag-three
 create mode 100644 t/t5515/fetch.main_branches-default
 create mode 100644 t/t5515/fetch.main_branches-one
 create mode 100644 t/t5515/fetch.main_config-explicit
 create mode 100644 t/t5515/fetch.main_config-glob
 create mode 100644 t/t5515/fetch.main_remote-explicit
 create mode 100644 t/t5515/fetch.main_remote-glob
 create mode 100644 t/t5515/refs.br-branches-default
 create mode 100644 t/t5515/refs.br-branches-default-merge
 create mode 100644 t/t5515/refs.br-branches-default-merge_branches-default
 create mode 100644 t/t5515/refs.br-branches-default-octopus
 create mode 100644 t/t5515/refs.br-branches-default-octopus_branches-default
 create mode 100644 t/t5515/refs.br-branches-default_branches-default
 create mode 100644 t/t5515/refs.br-branches-one
 create mode 100644 t/t5515/refs.br-branches-one-merge
 create mode 100644 t/t5515/refs.br-branches-one-merge_branches-one
 create mode 100644 t/t5515/refs.br-branches-one-octopus
 create mode 100644 t/t5515/refs.br-branches-one-octopus_branches-one
 create mode 100644 t/t5515/refs.br-branches-one_branches-one
 create mode 100644 t/t5515/refs.br-config-explicit
 create mode 100644 t/t5515/refs.br-config-explicit-merge
 create mode 100644 t/t5515/refs.br-config-explicit-merge_config-explicit
 create mode 100644 t/t5515/refs.br-config-explicit-octopus
 create mode 100644 t/t5515/refs.br-config-explicit-octopus_config-explicit
 create mode 100644 t/t5515/refs.br-config-explicit_config-explicit
 create mode 100644 t/t5515/refs.br-config-glob
 create mode 100644 t/t5515/refs.br-config-glob-merge
 create mode 100644 t/t5515/refs.br-config-glob-merge_config-glob
 create mode 100644 t/t5515/refs.br-config-glob-octopus
 create mode 100644 t/t5515/refs.br-config-glob-octopus_config-glob
 create mode 100644 t/t5515/refs.br-config-glob_config-glob
 create mode 100644 t/t5515/refs.br-remote-explicit
 create mode 100644 t/t5515/refs.br-remote-explicit-merge
 create mode 100644 t/t5515/refs.br-remote-explicit-merge_remote-explicit
 create mode 100644 t/t5515/refs.br-remote-explicit-octopus
 create mode 100644 t/t5515/refs.br-remote-explicit-octopus_remote-explicit
 create mode 100644 t/t5515/refs.br-remote-explicit_remote-explicit
 create mode 100644 t/t5515/refs.br-remote-glob
 create mode 100644 t/t5515/refs.br-remote-glob-merge
 create mode 100644 t/t5515/refs.br-remote-glob-merge_remote-glob
 create mode 100644 t/t5515/refs.br-remote-glob-octopus
 create mode 100644 t/t5515/refs.br-remote-glob-octopus_remote-glob
 create mode 100644 t/t5515/refs.br-remote-glob_remote-glob
 create mode 100644 t/t5515/refs.br-unconfig
 create mode 100644 t/t5515/refs.br-unconfig_--tags_.._.git
 create mode 100644 t/t5515/refs.br-unconfig_.._.git
 create mode 100644 t/t5515/refs.br-unconfig_.._.git_one
 create mode 100644 t/t5515/refs.br-unconfig_.._.git_one_tag_tag-one_tag_tag-three-file
 create mode 100644 t/t5515/refs.br-unconfig_.._.git_one_two
 create mode 100644 t/t5515/refs.br-unconfig_.._.git_tag_tag-one-tree_tag_tag-three-file
 create mode 100644 t/t5515/refs.br-unconfig_.._.git_tag_tag-one_tag_tag-three
 create mode 100644 t/t5515/refs.br-unconfig_branches-default
 create mode 100644 t/t5515/refs.br-unconfig_branches-one
 create mode 100644 t/t5515/refs.br-unconfig_config-explicit
 create mode 100644 t/t5515/refs.br-unconfig_config-glob
 create mode 100644 t/t5515/refs.br-unconfig_remote-explicit
 create mode 100644 t/t5515/refs.br-unconfig_remote-glob
 create mode 100644 t/t5515/refs.main
 create mode 100644 t/t5515/refs.main_--tags_.._.git
 create mode 100644 t/t5515/refs.main_.._.git
 create mode 100644 t/t5515/refs.main_.._.git_one
 create mode 100644 t/t5515/refs.main_.._.git_one_tag_tag-one_tag_tag-three-file
 create mode 100644 t/t5515/refs.main_.._.git_one_two
 create mode 100644 t/t5515/refs.main_.._.git_tag_tag-one-tree_tag_tag-three-file
 create mode 100644 t/t5515/refs.main_.._.git_tag_tag-one_tag_tag-three
 create mode 100644 t/t5515/refs.main_branches-default
 create mode 100644 t/t5515/refs.main_branches-one
 create mode 100644 t/t5515/refs.main_config-explicit
 create mode 100644 t/t5515/refs.main_config-glob
 create mode 100644 t/t5515/refs.main_remote-explicit
 create mode 100644 t/t5515/refs.main_remote-glob
 create mode 100755 t/t5516-fetch-push.sh
 create mode 100755 t/t5517-push-mirror.sh
 create mode 100755 t/t5518-fetch-exit-status.sh
 create mode 100755 t/t5519-push-alternates.sh
 create mode 100755 t/t5520-pull.sh
 create mode 100755 t/t5521-pull-options.sh
 create mode 100755 t/t5522-pull-symlink.sh
 create mode 100755 t/t5523-push-upstream.sh
 create mode 100755 t/t5524-pull-msg.sh
 create mode 100755 t/t5525-fetch-tagopt.sh
 create mode 100755 t/t5526-fetch-submodules.sh
 create mode 100755 t/t5527-fetch-odd-refs.sh
 create mode 100755 t/t5528-push-default.sh
 create mode 100755 t/t5529-push-errors.sh
 create mode 100755 t/t5530-upload-pack-error.sh
 create mode 100755 t/t5531-deep-submodule-push.sh
 create mode 100755 t/t5532-fetch-proxy.sh
 create mode 100755 t/t5533-push-cas.sh
 create mode 100755 t/t5534-push-signed.sh
 create mode 100755 t/t5535-fetch-push-symref.sh
 create mode 100755 t/t5536-fetch-conflicts.sh
 create mode 100755 t/t5537-fetch-shallow.sh
 create mode 100755 t/t5538-push-shallow.sh
 create mode 100755 t/t5539-fetch-http-shallow.sh
 create mode 100755 t/t5540-http-push-webdav.sh
 create mode 100755 t/t5541-http-push-smart.sh
 create mode 100755 t/t5542-push-http-shallow.sh
 create mode 100755 t/t5543-atomic-push.sh
 create mode 100755 t/t5544-pack-objects-hook.sh
 create mode 100755 t/t5545-push-options.sh
 create mode 100755 t/t5546-receive-limits.sh
 create mode 100755 t/t5547-push-quarantine.sh
 create mode 100755 t/t5548-push-porcelain.sh
 create mode 100755 t/t5549-fetch-push-http.sh
 create mode 100755 t/t5550-http-fetch-dumb.sh
 create mode 100755 t/t5551-http-fetch-smart.sh
 create mode 100755 t/t5552-skipping-fetch-negotiator.sh
 create mode 100755 t/t5553-set-upstream.sh
 create mode 100755 t/t5554-noop-fetch-negotiator.sh
 create mode 100755 t/t5555-http-smart-common.sh
 create mode 100755 t/t5557-http-get.sh
 create mode 100755 t/t5558-clone-bundle-uri.sh
 create mode 100755 t/t5559-http-fetch-smart-http2.sh
 create mode 100755 t/t5560-http-backend-noserver.sh
 create mode 100755 t/t5561-http-backend.sh
 create mode 100755 t/t5562-http-backend-content-length.sh
 create mode 100644 t/t5562/invoke-with-content-length.pl
 create mode 100755 t/t5563-simple-http-auth.sh
 create mode 100755 t/t5564-http-proxy.sh
 create mode 100755 t/t556x_common
 create mode 100755 t/t5570-git-daemon.sh
 create mode 100755 t/t5571-pre-push-hook.sh
 create mode 100755 t/t5572-pull-submodule.sh
 create mode 100755 t/t5573-pull-verify-signatures.sh
 create mode 100755 t/t5574-fetch-output.sh
 create mode 100755 t/t5580-unc-paths.sh
 create mode 100755 t/t5581-http-curl-verbose.sh
 create mode 100755 t/t5582-fetch-negative-refspec.sh
 create mode 100755 t/t5583-push-branches.sh
 create mode 100755 t/t5600-clone-fail-cleanup.sh
 create mode 100755 t/t5601-clone.sh
 create mode 100755 t/t5602-clone-remote-exec.sh
 create mode 100755 t/t5603-clone-dirname.sh
 create mode 100755 t/t5604-clone-reference.sh
 create mode 100755 t/t5605-clone-local.sh
 create mode 100755 t/t5606-clone-options.sh
 create mode 100755 t/t5607-clone-bundle.sh
 create mode 100755 t/t5608-clone-2gb.sh
 create mode 100755 t/t5609-clone-branch.sh
 create mode 100755 t/t5610-clone-detached.sh
 create mode 100755 t/t5611-clone-config.sh
 create mode 100755 t/t5612-clone-refspec.sh
 create mode 100755 t/t5613-info-alternate.sh
 create mode 100755 t/t5614-clone-submodules-shallow.sh
 create mode 100755 t/t5615-alternate-env.sh
 create mode 100755 t/t5616-partial-clone.sh
 create mode 100755 t/t5617-clone-submodules-remote.sh
 create mode 100755 t/t5618-alternate-refs.sh
 create mode 100755 t/t5619-clone-local-ambiguous-transport.sh
 create mode 100755 t/t5700-protocol-v1.sh
 create mode 100755 t/t5701-git-serve.sh
 create mode 100755 t/t5702-protocol-v2.sh
 create mode 100755 t/t5703-upload-pack-ref-in-want.sh
 create mode 100755 t/t5704-protocol-violations.sh
 create mode 100755 t/t5705-session-id-in-capabilities.sh
 create mode 100755 t/t5730-protocol-v2-bundle-uri-file.sh
 create mode 100755 t/t5731-protocol-v2-bundle-uri-git.sh
 create mode 100755 t/t5732-protocol-v2-bundle-uri-http.sh
 create mode 100755 t/t5750-bundle-uri-parse.sh
 create mode 100755 t/t5801-remote-helpers.sh
 create mode 100755 t/t5801/git-remote-nourl
 create mode 100755 t/t5801/git-remote-testgit
 create mode 100755 t/t5802-connect-helper.sh
 create mode 100755 t/t5810-proto-disable-local.sh
 create mode 100755 t/t5811-proto-disable-git.sh
 create mode 100755 t/t5812-proto-disable-http.sh
 create mode 100755 t/t5813-proto-disable-ssh.sh
 create mode 100755 t/t5814-proto-disable-ext.sh
 create mode 100755 t/t5815-submodule-protos.sh
 create mode 100755 t/t5900-repo-selection.sh
 create mode 100755 t/t6000-rev-list-misc.sh
 create mode 100755 t/t6001-rev-list-graft.sh
 create mode 100755 t/t6002-rev-list-bisect.sh
 create mode 100755 t/t6003-rev-list-topo-order.sh
 create mode 100755 t/t6004-rev-list-path-optim.sh
 create mode 100755 t/t6005-rev-list-count.sh
 create mode 100755 t/t6006-rev-list-format.sh
 create mode 100755 t/t6007-rev-list-cherry-pick-file.sh
 create mode 100755 t/t6008-rev-list-submodule.sh
 create mode 100755 t/t6009-rev-list-parent.sh
 create mode 100755 t/t6010-merge-base.sh
 create mode 100755 t/t6011-rev-list-with-bad-commit.sh
 create mode 100755 t/t6012-rev-list-simplify.sh
 create mode 100755 t/t6013-rev-list-reverse-parents.sh
 create mode 100755 t/t6014-rev-list-all.sh
 create mode 100755 t/t6016-rev-list-graph-simplify-history.sh
 create mode 100755 t/t6017-rev-list-stdin.sh
 create mode 100755 t/t6018-rev-list-glob.sh
 create mode 100755 t/t6019-rev-list-ancestry-path.sh
 create mode 100755 t/t6020-bundle-misc.sh
 create mode 100755 t/t6021-rev-list-exclude-hidden.sh
 create mode 100755 t/t6022-rev-list-missing.sh
 create mode 100755 t/t6030-bisect-porcelain.sh
 create mode 100755 t/t6040-tracking-info.sh
 create mode 100755 t/t6041-bisect-submodule.sh
 create mode 100755 t/t6050-replace.sh
 create mode 100755 t/t6060-merge-index.sh
 create mode 100755 t/t6100-rev-list-in-order.sh
 create mode 100755 t/t6101-rev-parse-parents.sh
 create mode 100755 t/t6102-rev-list-unexpected-objects.sh
 create mode 100755 t/t6110-rev-list-sparse.sh
 create mode 100755 t/t6111-rev-list-treesame.sh
 create mode 100755 t/t6112-rev-list-filters-objects.sh
 create mode 100755 t/t6113-rev-list-bitmap-filters.sh
 create mode 100755 t/t6114-keep-packs.sh
 create mode 100755 t/t6115-rev-list-du.sh
 create mode 100755 t/t6120-describe.sh
 create mode 100755 t/t6130-pathspec-noglob.sh
 create mode 100755 t/t6131-pathspec-icase.sh
 create mode 100755 t/t6132-pathspec-exclude.sh
 create mode 100755 t/t6133-pathspec-rev-dwim.sh
 create mode 100755 t/t6134-pathspec-in-submodule.sh
 create mode 100755 t/t6135-pathspec-with-attrs.sh
 create mode 100755 t/t6136-pathspec-in-bare.sh
 create mode 100755 t/t6200-fmt-merge-msg.sh
 create mode 100755 t/t6300-for-each-ref.sh
 create mode 100755 t/t6301-for-each-ref-errors.sh
 create mode 100755 t/t6302-for-each-ref-filter.sh
 create mode 100755 t/t6400-merge-df.sh
 create mode 100755 t/t6401-merge-criss-cross.sh
 create mode 100755 t/t6402-merge-rename.sh
 create mode 100755 t/t6403-merge-file.sh
 create mode 100755 t/t6404-recursive-merge.sh
 create mode 100755 t/t6405-merge-symlinks.sh
 create mode 100755 t/t6406-merge-attr.sh
 create mode 100755 t/t6407-merge-binary.sh
 create mode 100755 t/t6408-merge-up-to-date.sh
 create mode 100755 t/t6409-merge-subtree.sh
 create mode 100755 t/t6411-merge-filemode.sh
 create mode 100755 t/t6412-merge-large-rename.sh
 create mode 100755 t/t6413-merge-crlf.sh
 create mode 100755 t/t6414-merge-rename-nocruft.sh
 create mode 100755 t/t6415-merge-dir-to-symlink.sh
 create mode 100755 t/t6416-recursive-corner-cases.sh
 create mode 100755 t/t6417-merge-ours-theirs.sh
 create mode 100755 t/t6418-merge-text-auto.sh
 create mode 100755 t/t6419-merge-ignorecase.sh
 create mode 100755 t/t6421-merge-partial-clone.sh
 create mode 100755 t/t6422-merge-rename-corner-cases.sh
 create mode 100755 t/t6423-merge-rename-directories.sh
 create mode 100755 t/t6424-merge-unrelated-index-changes.sh
 create mode 100755 t/t6425-merge-rename-delete.sh
 create mode 100755 t/t6426-merge-skip-unneeded-updates.sh
 create mode 100755 t/t6427-diff3-conflict-markers.sh
 create mode 100755 t/t6428-merge-conflicts-sparse.sh
 create mode 100755 t/t6429-merge-sequence-rename-caching.sh
 create mode 100755 t/t6430-merge-recursive.sh
 create mode 100755 t/t6431-merge-criscross.sh
 create mode 100755 t/t6432-merge-recursive-space-options.sh
 create mode 100755 t/t6433-merge-toplevel.sh
 create mode 100755 t/t6434-merge-recursive-rename-options.sh
 create mode 100755 t/t6435-merge-sparse.sh
 create mode 100755 t/t6436-merge-overwrite.sh
 create mode 100755 t/t6437-submodule-merge.sh
 create mode 100755 t/t6438-submodule-directory-file-conflicts.sh
 create mode 100755 t/t6439-merge-co-error-msgs.sh
 create mode 100755 t/t6500-gc.sh
 create mode 100755 t/t6501-freshen-objects.sh
 create mode 100755 t/t6600-test-reach.sh
 create mode 100755 t/t6601-path-walk.sh
 create mode 100755 t/t6700-tree-depth.sh
 create mode 100755 t/t7001-mv.sh
 create mode 100755 t/t7002-mv-sparse-checkout.sh
 create mode 100755 t/t7003-filter-branch.sh
 create mode 100755 t/t7004-tag.sh
 create mode 100755 t/t7005-editor.sh
 create mode 100755 t/t7006-pager.sh
 create mode 100755 t/t7007-show.sh
 create mode 100755 t/t7008-filter-branch-null-sha1.sh
 create mode 100755 t/t7010-setup.sh
 create mode 100755 t/t7011-skip-worktree-reading.sh
 create mode 100755 t/t7012-skip-worktree-writing.sh
 create mode 100755 t/t7030-verify-tag.sh
 create mode 100755 t/t7031-verify-tag-signed-ssh.sh
 create mode 100755 t/t7060-wtstatus.sh
 create mode 100755 t/t7061-wtstatus-ignore.sh
 create mode 100755 t/t7062-wtstatus-ignorecase.sh
 create mode 100755 t/t7063-status-untracked-cache.sh
 create mode 100755 t/t7064-wtstatus-pv2.sh
 create mode 100755 t/t7101-reset-empty-subdirs.sh
 create mode 100755 t/t7102-reset.sh
 create mode 100755 t/t7103-reset-bare.sh
 create mode 100755 t/t7104-reset-hard.sh
 create mode 100755 t/t7105-reset-patch.sh
 create mode 100755 t/t7106-reset-unborn-branch.sh
 create mode 100755 t/t7107-reset-pathspec-file.sh
 create mode 100755 t/t7110-reset-merge.sh
 create mode 100755 t/t7111-reset-table.sh
 create mode 100755 t/t7112-reset-submodule.sh
 create mode 100755 t/t7113-post-index-change-hook.sh
 create mode 100755 t/t7201-co.sh
 create mode 100755 t/t7300-clean.sh
 create mode 100755 t/t7301-clean-interactive.sh
 create mode 100755 t/t7400-submodule-basic.sh
 create mode 100755 t/t7401-submodule-summary.sh
 create mode 100755 t/t7402-submodule-rebase.sh
 create mode 100755 t/t7403-submodule-sync.sh
 create mode 100755 t/t7406-submodule-update.sh
 create mode 100755 t/t7407-submodule-foreach.sh
 create mode 100755 t/t7408-submodule-reference.sh
 create mode 100755 t/t7409-submodule-detached-work-tree.sh
 create mode 100755 t/t7411-submodule-config.sh
 create mode 100755 t/t7412-submodule-absorbgitdirs.sh
 create mode 100755 t/t7413-submodule-is-active.sh
 create mode 100755 t/t7414-submodule-mistakes.sh
 create mode 100755 t/t7416-submodule-dash-url.sh
 create mode 100755 t/t7417-submodule-path-url.sh
 create mode 100755 t/t7418-submodule-sparse-gitmodules.sh
 create mode 100755 t/t7419-submodule-set-branch.sh
 create mode 100755 t/t7420-submodule-set-url.sh
 create mode 100755 t/t7421-submodule-summary-add.sh
 create mode 100755 t/t7422-submodule-output.sh
 create mode 100755 t/t7423-submodule-symlinks.sh
 create mode 100755 t/t7424-submodule-mixed-ref-formats.sh
 create mode 100755 t/t7450-bad-git-dotfiles.sh
 create mode 100755 t/t7500-commit-template-squash-signoff.sh
 create mode 100755 t/t7500/add-comments
 create mode 100755 t/t7500/add-content
 create mode 100755 t/t7500/add-content-and-comment
 create mode 100755 t/t7500/add-signed-off
 create mode 100755 t/t7500/add-whitespaced-content
 create mode 100755 t/t7500/edit-content
 create mode 100755 t/t7501-commit-basic-functionality.sh
 create mode 100755 t/t7502-commit-porcelain.sh
 create mode 100755 t/t7503-pre-commit-and-pre-merge-commit-hooks.sh
 create mode 100755 t/t7504-commit-msg-hook.sh
 create mode 100755 t/t7505-prepare-commit-msg-hook.sh
 create mode 100644 t/t7505/expected-rebase-i
 create mode 100644 t/t7505/expected-rebase-p
 create mode 100755 t/t7506-status-submodule.sh
 create mode 100755 t/t7507-commit-verbose.sh
 create mode 100755 t/t7508-status.sh
 create mode 100755 t/t7509-commit-authorship.sh
 create mode 100755 t/t7510-signed-commit.sh
 create mode 100755 t/t7511-status-index.sh
 create mode 100755 t/t7512-status-help.sh
 create mode 100755 t/t7513-interpret-trailers.sh
 create mode 100755 t/t7514-commit-patch.sh
 create mode 100755 t/t7515-status-symlinks.sh
 create mode 100755 t/t7516-commit-races.sh
 create mode 100755 t/t7517-per-repo-email.sh
 create mode 100755 t/t7518-ident-corner-cases.sh
 create mode 100755 t/t7519-status-fsmonitor.sh
 create mode 100755 t/t7519/fsmonitor-all
 create mode 100755 t/t7519/fsmonitor-all-v2
 create mode 100755 t/t7519/fsmonitor-env
 create mode 100755 t/t7519/fsmonitor-none
 create mode 100755 t/t7519/fsmonitor-watchman
 create mode 100755 t/t7519/fsmonitor-watchman-v2
 create mode 100755 t/t7520-ignored-hook-warning.sh
 create mode 100755 t/t7521-ignored-mode.sh
 create mode 100755 t/t7524-commit-summary.sh
 create mode 100755 t/t7525-status-rename.sh
 create mode 100755 t/t7526-commit-pathspec-file.sh
 create mode 100755 t/t7527-builtin-fsmonitor.sh
 create mode 100755 t/t7528-signed-commit-ssh.sh
 create mode 100755 t/t7600-merge.sh
 create mode 100755 t/t7601-merge-pull-config.sh
 create mode 100755 t/t7602-merge-octopus-many.sh
 create mode 100755 t/t7603-merge-reduce-heads.sh
 create mode 100755 t/t7604-merge-custom-message.sh
 create mode 100755 t/t7605-merge-resolve.sh
 create mode 100755 t/t7606-merge-custom.sh
 create mode 100755 t/t7607-merge-state.sh
 create mode 100755 t/t7608-merge-messages.sh
 create mode 100755 t/t7609-mergetool--lib.sh
 create mode 100755 t/t7610-mergetool.sh
 create mode 100755 t/t7611-merge-abort.sh
 create mode 100755 t/t7612-merge-verify-signatures.sh
 create mode 100755 t/t7614-merge-signoff.sh
 create mode 100755 t/t7615-diff-algo-with-mergy-operations.sh
 create mode 100644 t/t7615/base.c
 create mode 100644 t/t7615/ours.c
 create mode 100644 t/t7615/theirs.c
 create mode 100755 t/t7700-repack.sh
 create mode 100755 t/t7701-repack-unpack-unreachable.sh
 create mode 100755 t/t7702-repack-cyclic-alternate.sh
 create mode 100755 t/t7703-repack-geometric.sh
 create mode 100755 t/t7704-repack-cruft.sh
 create mode 100755 t/t7800-difftool.sh
 create mode 100755 t/t7810-grep.sh
 create mode 100755 t/t7811-grep-open.sh
 create mode 100755 t/t7812-grep-icase-non-ascii.sh
 create mode 100755 t/t7813-grep-icase-iso.sh
 create mode 100755 t/t7814-grep-recurse-submodules.sh
 create mode 100755 t/t7815-grep-binary.sh
 create mode 100755 t/t7816-grep-binary-pattern.sh
 create mode 100755 t/t7817-grep-sparse-checkout.sh
 create mode 100755 t/t7900-maintenance.sh
 create mode 100755 t/t8001-annotate.sh
 create mode 100755 t/t8002-blame.sh
 create mode 100755 t/t8003-blame-corner-cases.sh
 create mode 100755 t/t8004-blame-with-conflicts.sh
 create mode 100755 t/t8005-blame-i18n.sh
 create mode 100644 t/t8005/euc-japan.txt
 create mode 100644 t/t8005/sjis.txt
 create mode 100644 t/t8005/utf8.txt
 create mode 100755 t/t8006-blame-textconv.sh
 create mode 100755 t/t8007-cat-file-textconv.sh
 create mode 100755 t/t8008-blame-formats.sh
 create mode 100755 t/t8009-blame-vs-topicbranches.sh
 create mode 100755 t/t8010-cat-file-filters.sh
 create mode 100755 t/t8011-blame-split-file.sh
 create mode 100755 t/t8012-blame-colors.sh
 create mode 100755 t/t8013-blame-ignore-revs.sh
 create mode 100755 t/t8014-blame-ignore-fuzzy.sh
 create mode 100755 t/t9001-send-email.sh
 create mode 100755 t/t9002-column.sh
 create mode 100755 t/t9003-help-autocorrect.sh
 create mode 100755 t/t9100-git-svn-basic.sh
 create mode 100755 t/t9101-git-svn-props.sh
 create mode 100755 t/t9102-git-svn-deep-rmdir.sh
 create mode 100755 t/t9103-git-svn-tracked-directory-removed.sh
 create mode 100755 t/t9104-git-svn-follow-parent.sh
 create mode 100755 t/t9105-git-svn-commit-diff.sh
 create mode 100755 t/t9106-git-svn-commit-diff-clobber.sh
 create mode 100755 t/t9107-git-svn-migrate.sh
 create mode 100755 t/t9108-git-svn-glob.sh
 create mode 100755 t/t9109-git-svn-multi-glob.sh
 create mode 100755 t/t9110-git-svn-use-svm-props.sh
 create mode 100644 t/t9110/svm.dump
 create mode 100755 t/t9111-git-svn-use-svnsync-props.sh
 create mode 100644 t/t9111/svnsync.dump
 create mode 100755 t/t9112-git-svn-md5less-file.sh
 create mode 100755 t/t9113-git-svn-dcommit-new-file.sh
 create mode 100755 t/t9114-git-svn-dcommit-merge.sh
 create mode 100755 t/t9115-git-svn-dcommit-funky-renames.sh
 create mode 100644 t/t9115/funky-names.dump
 create mode 100755 t/t9116-git-svn-log.sh
 create mode 100755 t/t9117-git-svn-init-clone.sh
 create mode 100755 t/t9118-git-svn-funky-branch-names.sh
 create mode 100755 t/t9119-git-svn-info.sh
 create mode 100755 t/t9120-git-svn-clone-with-percent-escapes.sh
 create mode 100755 t/t9121-git-svn-fetch-renamed-dir.sh
 create mode 100644 t/t9121/renamed-dir.dump
 create mode 100755 t/t9122-git-svn-author.sh
 create mode 100755 t/t9123-git-svn-rebuild-with-rewriteroot.sh
 create mode 100755 t/t9124-git-svn-dcommit-auto-props.sh
 create mode 100755 t/t9125-git-svn-multi-glob-branch-names.sh
 create mode 100755 t/t9126-git-svn-follow-deleted-readded-directory.sh
 create mode 100644 t/t9126/follow-deleted-readded.dump
 create mode 100755 t/t9127-git-svn-partial-rebuild.sh
 create mode 100755 t/t9128-git-svn-cmd-branch.sh
 create mode 100755 t/t9129-git-svn-i18n-commitencoding.sh
 create mode 100755 t/t9130-git-svn-authors-file.sh
 create mode 100755 t/t9131-git-svn-empty-symlink.sh
 create mode 100755 t/t9132-git-svn-broken-symlink.sh
 create mode 100755 t/t9133-git-svn-nested-git-repo.sh
 create mode 100755 t/t9134-git-svn-ignore-paths.sh
 create mode 100755 t/t9135-git-svn-moved-branch-empty-file.sh
 create mode 100644 t/t9135/svn.dump
 create mode 100755 t/t9136-git-svn-recreated-branch-empty-file.sh
 create mode 100644 t/t9136/svn.dump
 create mode 100755 t/t9137-git-svn-dcommit-clobber-series.sh
 create mode 100755 t/t9138-git-svn-authors-prog.sh
 create mode 100755 t/t9139-git-svn-non-utf8-commitencoding.sh
 create mode 100755 t/t9140-git-svn-reset.sh
 create mode 100755 t/t9141-git-svn-multiple-branches.sh
 create mode 100755 t/t9142-git-svn-shallow-clone.sh
 create mode 100755 t/t9143-git-svn-gc.sh
 create mode 100755 t/t9144-git-svn-old-rev_map.sh
 create mode 100755 t/t9145-git-svn-master-branch.sh
 create mode 100755 t/t9146-git-svn-empty-dirs.sh
 create mode 100755 t/t9147-git-svn-include-paths.sh
 create mode 100755 t/t9148-git-svn-propset.sh
 create mode 100755 t/t9150-svk-mergetickets.sh
 create mode 100755 t/t9150/make-svk-dump
 create mode 100644 t/t9150/svk-merge.dump
 create mode 100755 t/t9151-svn-mergeinfo.sh
 create mode 100644 t/t9151/.gitignore
 create mode 100755 t/t9151/make-svnmerge-dump
 create mode 100644 t/t9151/svn-mergeinfo.dump
 create mode 100755 t/t9152-svn-empty-dirs-after-gc.sh
 create mode 100755 t/t9153-git-svn-rewrite-uuid.sh
 create mode 100644 t/t9153/svn.dump
 create mode 100755 t/t9154-git-svn-fancy-glob.sh
 create mode 100644 t/t9154/svn.dump
 create mode 100755 t/t9155-git-svn-fetch-deleted-tag.sh
 create mode 100755 t/t9156-git-svn-fetch-deleted-tag-2.sh
 create mode 100755 t/t9157-git-svn-fetch-merge.sh
 create mode 100755 t/t9158-git-svn-mergeinfo.sh
 create mode 100755 t/t9159-git-svn-no-parent-mergeinfo.sh
 create mode 100755 t/t9160-git-svn-preserve-empty-dirs.sh
 create mode 100755 t/t9161-git-svn-mergeinfo-push.sh
 create mode 100644 t/t9161/branches.dump
 create mode 100755 t/t9162-git-svn-dcommit-interactive.sh
 create mode 100755 t/t9163-git-svn-reset-clears-caches.sh
 create mode 100755 t/t9164-git-svn-dcommit-concurrent.sh
 create mode 100755 t/t9165-git-svn-fetch-merge-branch-of-branch.sh
 create mode 100755 t/t9166-git-svn-fetch-merge-branch-of-branch2.sh
 create mode 100755 t/t9167-git-svn-cmd-branch-subproject.sh
 create mode 100755 t/t9168-git-svn-partially-globbed-names.sh
 create mode 100755 t/t9169-git-svn-dcommit-crlf.sh
 create mode 100755 t/t9200-git-cvsexportcommit.sh
 create mode 100755 t/t9210-scalar.sh
 create mode 100755 t/t9211-scalar-clone.sh
 create mode 100755 t/t9300-fast-import.sh
 create mode 100755 t/t9301-fast-import-notes.sh
 create mode 100755 t/t9302-fast-import-unpack-limit.sh
 create mode 100755 t/t9303-fast-import-compression.sh
 create mode 100755 t/t9304-fast-import-marks.sh
 create mode 100755 t/t9350-fast-export.sh
 create mode 100644 t/t9350/broken-iso-8859-7-commit-message.txt
 create mode 100644 t/t9350/simple-iso-8859-7-commit-message.txt
 create mode 100755 t/t9351-fast-export-anonymize.sh
 create mode 100755 t/t9400-git-cvsserver-server.sh
 create mode 100755 t/t9401-git-cvsserver-crlf.sh
 create mode 100755 t/t9402-git-cvsserver-refs.sh
 create mode 100755 t/t9500-gitweb-standalone-no-errors.sh
 create mode 100755 t/t9501-gitweb-standalone-http-status.sh
 create mode 100755 t/t9502-gitweb-standalone-parse-output.sh
 create mode 100755 t/t9600-cvsimport.sh
 create mode 100755 t/t9601-cvsimport-vendor-branch.sh
 create mode 100644 t/t9601/cvsroot/.gitattributes
 create mode 100644 t/t9601/cvsroot/CVSROOT/.gitignore
 create mode 100644 t/t9601/cvsroot/module/added-imported.txt,v
 create mode 100644 t/t9601/cvsroot/module/imported-anonymously.txt,v
 create mode 100644 t/t9601/cvsroot/module/imported-modified-imported.txt,v
 create mode 100644 t/t9601/cvsroot/module/imported-modified.txt,v
 create mode 100644 t/t9601/cvsroot/module/imported-once.txt,v
 create mode 100644 t/t9601/cvsroot/module/imported-twice.txt,v
 create mode 100755 t/t9602-cvsimport-branches-tags.sh
 create mode 100644 t/t9602/README
 create mode 100644 t/t9602/cvsroot/.gitattributes
 create mode 100644 t/t9602/cvsroot/CVSROOT/.gitignore
 create mode 100644 t/t9602/cvsroot/module/default,v
 create mode 100644 t/t9602/cvsroot/module/sub1/default,v
 create mode 100644 t/t9602/cvsroot/module/sub1/subsubA/default,v
 create mode 100644 t/t9602/cvsroot/module/sub1/subsubB/default,v
 create mode 100644 t/t9602/cvsroot/module/sub2/Attic/branch_B_MIXED_only,v
 create mode 100644 t/t9602/cvsroot/module/sub2/default,v
 create mode 100644 t/t9602/cvsroot/module/sub2/subsubA/default,v
 create mode 100644 t/t9602/cvsroot/module/sub3/default,v
 create mode 100755 t/t9603-cvsimport-patchsets.sh
 create mode 100644 t/t9603/cvsroot/.gitattributes
 create mode 100644 t/t9603/cvsroot/CVSROOT/.gitignore
 create mode 100644 t/t9603/cvsroot/module/a,v
 create mode 100644 t/t9603/cvsroot/module/b,v
 create mode 100755 t/t9604-cvsimport-timestamps.sh
 create mode 100644 t/t9604/cvsroot/.gitattributes
 create mode 100644 t/t9604/cvsroot/CVSROOT/.gitignore
 create mode 100644 t/t9604/cvsroot/module/a,v
 create mode 100755 t/t9700-perl-git.sh
 create mode 100755 t/t9700/test.pl
 create mode 100755 t/t9800-git-p4-basic.sh
 create mode 100755 t/t9801-git-p4-branch.sh
 create mode 100755 t/t9802-git-p4-filetype.sh
 create mode 100755 t/t9803-git-p4-shell-metachars.sh
 create mode 100755 t/t9804-git-p4-label.sh
 create mode 100755 t/t9805-git-p4-skip-submit-edit.sh
 create mode 100755 t/t9806-git-p4-options.sh
 create mode 100755 t/t9807-git-p4-submit.sh
 create mode 100755 t/t9808-git-p4-chdir.sh
 create mode 100755 t/t9809-git-p4-client-view.sh
 create mode 100755 t/t9810-git-p4-rcs.sh
 create mode 100755 t/t9811-git-p4-label-import.sh
 create mode 100755 t/t9812-git-p4-wildcards.sh
 create mode 100755 t/t9813-git-p4-preserve-users.sh
 create mode 100755 t/t9814-git-p4-rename.sh
 create mode 100755 t/t9815-git-p4-submit-fail.sh
 create mode 100755 t/t9816-git-p4-locked.sh
 create mode 100755 t/t9817-git-p4-exclude.sh
 create mode 100755 t/t9818-git-p4-block.sh
 create mode 100755 t/t9819-git-p4-case-folding.sh
 create mode 100755 t/t9820-git-p4-editor-handling.sh
 create mode 100755 t/t9821-git-p4-path-variations.sh
 create mode 100755 t/t9822-git-p4-path-encoding.sh
 create mode 100755 t/t9823-git-p4-mock-lfs.sh
 create mode 100755 t/t9824-git-p4-git-lfs.sh
 create mode 100755 t/t9825-git-p4-handle-utf16-without-bom.sh
 create mode 100755 t/t9826-git-p4-keep-empty-commits.sh
 create mode 100755 t/t9827-git-p4-change-filetype.sh
 create mode 100755 t/t9828-git-p4-map-user.sh
 create mode 100755 t/t9829-git-p4-jobs.sh
 create mode 100755 t/t9830-git-p4-symlink-dir.sh
 create mode 100755 t/t9831-git-p4-triggers.sh
 create mode 100755 t/t9832-unshelve.sh
 create mode 100755 t/t9833-errors.sh
 create mode 100755 t/t9834-git-p4-file-dir-bug.sh
 create mode 100755 t/t9835-git-p4-metadata-encoding-python2.sh
 create mode 100755 t/t9836-git-p4-metadata-encoding-python3.sh
 create mode 100755 t/t9850-shell.sh
 create mode 100755 t/t9901-git-web--browse.sh
 create mode 100755 t/t9902-completion.sh
 create mode 100755 t/t9903-bash-prompt.sh
 create mode 100644 t/test-binary-1.png
 create mode 100644 t/test-binary-2.png
 create mode 100644 t/test-lib-functions.sh
 create mode 100644 t/test-lib-github-workflow-markup.sh
 create mode 100644 t/test-lib-junit.sh
 create mode 100644 t/test-lib.sh
 create mode 100755 t/test-terminal.perl
 create mode 100644 t/unit-tests/.gitignore
 create mode 100644 t/unit-tests/clar/.editorconfig
 create mode 100644 t/unit-tests/clar/.github/workflows/ci.yml
 create mode 100644 t/unit-tests/clar/.gitignore
 create mode 100644 t/unit-tests/clar/CMakeLists.txt
 create mode 100644 t/unit-tests/clar/COPYING
 create mode 100644 t/unit-tests/clar/README.md
 create mode 100644 t/unit-tests/clar/clar.c
 create mode 100644 t/unit-tests/clar/clar.h
 create mode 100644 t/unit-tests/clar/clar/fixtures.h
 create mode 100644 t/unit-tests/clar/clar/fs.h
 create mode 100644 t/unit-tests/clar/clar/print.h
 create mode 100644 t/unit-tests/clar/clar/sandbox.h
 create mode 100644 t/unit-tests/clar/clar/summary.h
 create mode 100755 t/unit-tests/clar/generate.py
 create mode 100644 t/unit-tests/clar/test/CMakeLists.txt
 create mode 100644 t/unit-tests/clar/test/clar_test.h
 create mode 100644 t/unit-tests/clar/test/main.c
 create mode 100644 t/unit-tests/clar/test/main.c.sample
 create mode 100644 t/unit-tests/clar/test/resources/test/file
 create mode 100644 t/unit-tests/clar/test/sample.c
 create mode 100755 t/unit-tests/generate-clar-decls.sh
 create mode 100755 t/unit-tests/generate-clar-suites.sh
 create mode 100644 t/unit-tests/lib-oid.c
 create mode 100644 t/unit-tests/lib-oid.h
 create mode 100644 t/unit-tests/lib-reftable.c
 create mode 100644 t/unit-tests/lib-reftable.h
 create mode 100644 t/unit-tests/t-example-decorate.c
 create mode 100644 t/unit-tests/t-hashmap.c
 create mode 100644 t/unit-tests/t-oid-array.c
 create mode 100644 t/unit-tests/t-oidmap.c
 create mode 100644 t/unit-tests/t-oidtree.c
 create mode 100644 t/unit-tests/t-reftable-basics.c
 create mode 100644 t/unit-tests/t-reftable-block.c
 create mode 100644 t/unit-tests/t-reftable-merged.c
 create mode 100644 t/unit-tests/t-reftable-pq.c
 create mode 100644 t/unit-tests/t-reftable-reader.c
 create mode 100644 t/unit-tests/t-reftable-readwrite.c
 create mode 100644 t/unit-tests/t-reftable-record.c
 create mode 100644 t/unit-tests/t-reftable-stack.c
 create mode 100644 t/unit-tests/t-strbuf.c
 create mode 100644 t/unit-tests/t-strcmp-offset.c
 create mode 100644 t/unit-tests/t-trailer.c
 create mode 100644 t/unit-tests/t-urlmatch-normalization.c
 create mode 100644 t/unit-tests/test-lib.c
 create mode 100644 t/unit-tests/test-lib.h
 create mode 100644 t/unit-tests/u-ctype.c
 create mode 100644 t/unit-tests/u-hash.c
 create mode 100644 t/unit-tests/u-mem-pool.c
 create mode 100644 t/unit-tests/u-prio-queue.c
 create mode 100644 t/unit-tests/u-reftable-tree.c
 create mode 100644 t/unit-tests/u-strvec.c
 create mode 100644 t/unit-tests/unit-test.c
 create mode 100644 t/unit-tests/unit-test.h
 create mode 100644 t/valgrind/.gitignore
 create mode 100755 t/valgrind/analyze.sh
 create mode 100644 t/valgrind/default.supp
 create mode 100755 t/valgrind/valgrind.sh
 create mode 100644 tag.c
 create mode 100644 tag.h
 create mode 100644 tar.h
 create mode 100644 tempfile.c
 create mode 100644 tempfile.h
 create mode 100644 templates/.gitignore
 create mode 100644 templates/Makefile
 create mode 100644 templates/description
 create mode 100755 templates/hooks/applypatch-msg.sample
 create mode 100755 templates/hooks/commit-msg.sample
 create mode 100755 templates/hooks/fsmonitor-watchman.sample
 create mode 100644 templates/hooks/meson.build
 create mode 100755 templates/hooks/post-update.sample
 create mode 100755 templates/hooks/pre-applypatch.sample
 create mode 100755 templates/hooks/pre-commit.sample
 create mode 100755 templates/hooks/pre-merge-commit.sample
 create mode 100755 templates/hooks/pre-push.sample
 create mode 100755 templates/hooks/pre-rebase.sample
 create mode 100755 templates/hooks/pre-receive.sample
 create mode 100755 templates/hooks/prepare-commit-msg.sample
 create mode 100755 templates/hooks/push-to-checkout.sample
 create mode 100755 templates/hooks/sendemail-validate.sample
 create mode 100755 templates/hooks/update.sample
 create mode 100644 templates/info/exclude
 create mode 100644 templates/info/meson.build
 create mode 100644 templates/meson.build
 create mode 100644 thread-utils.c
 create mode 100644 thread-utils.h
 create mode 100644 tmp-objdir.c
 create mode 100644 tmp-objdir.h
 create mode 100644 trace.c
 create mode 100644 trace.h
 create mode 100644 trace2.c
 create mode 100644 trace2.h
 create mode 100644 trace2/tr2_cfg.c
 create mode 100644 trace2/tr2_cfg.h
 create mode 100644 trace2/tr2_cmd_name.c
 create mode 100644 trace2/tr2_cmd_name.h
 create mode 100644 trace2/tr2_ctr.c
 create mode 100644 trace2/tr2_ctr.h
 create mode 100644 trace2/tr2_dst.c
 create mode 100644 trace2/tr2_dst.h
 create mode 100644 trace2/tr2_sid.c
 create mode 100644 trace2/tr2_sid.h
 create mode 100644 trace2/tr2_sysenv.c
 create mode 100644 trace2/tr2_sysenv.h
 create mode 100644 trace2/tr2_tbuf.c
 create mode 100644 trace2/tr2_tbuf.h
 create mode 100644 trace2/tr2_tgt.h
 create mode 100644 trace2/tr2_tgt_event.c
 create mode 100644 trace2/tr2_tgt_normal.c
 create mode 100644 trace2/tr2_tgt_perf.c
 create mode 100644 trace2/tr2_tls.c
 create mode 100644 trace2/tr2_tls.h
 create mode 100644 trace2/tr2_tmr.c
 create mode 100644 trace2/tr2_tmr.h
 create mode 100644 trailer.c
 create mode 100644 trailer.h
 create mode 100644 transport-helper.c
 create mode 100644 transport-internal.h
 create mode 100644 transport.c
 create mode 100644 transport.h
 create mode 100644 tree-diff.c
 create mode 100644 tree-walk.c
 create mode 100644 tree-walk.h
 create mode 100644 tree.c
 create mode 100644 tree.h
 create mode 100644 unicode-width.h
 create mode 100644 unimplemented.sh
 create mode 100644 unix-socket.c
 create mode 100644 unix-socket.h
 create mode 100644 unix-stream-server.c
 create mode 100644 unix-stream-server.h
 create mode 100644 unpack-trees.c
 create mode 100644 unpack-trees.h
 create mode 100644 upload-pack.c
 create mode 100644 upload-pack.h
 create mode 100644 url.c
 create mode 100644 url.h
 create mode 100644 urlmatch.c
 create mode 100644 urlmatch.h
 create mode 100644 usage.c
 create mode 100644 userdiff.c
 create mode 100644 userdiff.h
 create mode 100644 utf8.c
 create mode 100644 utf8.h
 create mode 100644 varint.c
 create mode 100644 varint.h
 create mode 100644 version-def.h.in
 create mode 100644 version.c
 create mode 100644 version.h
 create mode 100644 versioncmp.c
 create mode 100644 versioncmp.h
 create mode 100644 walker.c
 create mode 100644 walker.h
 create mode 100644 wildmatch.c
 create mode 100644 wildmatch.h
 create mode 100644 worktree.c
 create mode 100644 worktree.h
 create mode 100644 wrapper.c
 create mode 100644 wrapper.h
 create mode 100644 write-or-die.c
 create mode 100644 write-or-die.h
 create mode 100644 ws.c
 create mode 100644 ws.h
 create mode 100644 wt-status.c
 create mode 100644 wt-status.h
 create mode 100644 xdiff-interface.c
 create mode 100644 xdiff-interface.h
 create mode 100644 xdiff/xdiff.h
 create mode 100644 xdiff/xdiffi.c
 create mode 100644 xdiff/xdiffi.h
 create mode 100644 xdiff/xemit.c
 create mode 100644 xdiff/xemit.h
 create mode 100644 xdiff/xhistogram.c
 create mode 100644 xdiff/xinclude.h
 create mode 100644 xdiff/xmacros.h
 create mode 100644 xdiff/xmerge.c
 create mode 100644 xdiff/xpatience.c
 create mode 100644 xdiff/xprepare.c
 create mode 100644 xdiff/xprepare.h
 create mode 100644 xdiff/xtypes.h
 create mode 100644 xdiff/xutils.c
 create mode 100644 xdiff/xutils.h

diff --git a/.cirrus.yml b/.cirrus.yml
new file mode 100644
index 0000000000..1fbdc2652b
--- /dev/null
+++ b/.cirrus.yml
@@ -0,0 +1,22 @@
+env:
+  CIRRUS_CLONE_DEPTH: 1
+
+freebsd_task:
+  env:
+    GIT_PROVE_OPTS: "--timer --jobs 10"
+    GIT_TEST_OPTS: "--no-chain-lint --no-bin-wrappers"
+    MAKEFLAGS: "-j4"
+    DEFAULT_TEST_TARGET: prove
+    DEVELOPER: 1
+  freebsd_instance:
+    image_family: freebsd-13-4
+    memory: 2G
+  install_script:
+    pkg install -y gettext gmake perl5
+  create_user_script:
+    - pw useradd git
+    - chown -R git:git .
+  build_script:
+    - su git -c gmake
+  test_script:
+    - su git -c 'gmake DEFAULT_UNIT_TEST_TARGET=unit-tests-prove test unit-tests'
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000000..9547fe1b77
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,225 @@
+# This file is an example configuration for clang-format 5.0.
+#
+# Note that this style definition should only be understood as a hint
+# for writing new code. The rules are still work-in-progress and does
+# not yet exactly match the style we have in the existing code.
+
+# Use tabs whenever we need to fill whitespace that spans at least from one tab
+# stop to the next one.
+#
+# These settings are mirrored in .editorconfig.  Keep them in sync.
+UseTab: Always
+TabWidth: 8
+IndentWidth: 8
+ContinuationIndentWidth: 8
+ColumnLimit: 80
+
+# C Language specifics
+Language: Cpp
+
+# Align parameters on the open bracket
+# someLongFunction(argument1,
+#                  argument2);
+AlignAfterOpenBracket: Align
+
+# Don't align consecutive assignments
+# int aaaa = 12;
+# int b = 14;
+AlignConsecutiveAssignments: false
+
+# Don't align consecutive declarations
+# int aaaa = 12;
+# double b = 3.14;
+AlignConsecutiveDeclarations: false
+
+# Align consecutive macro definitions.
+AlignConsecutiveMacros: true
+
+# Align escaped newlines as far left as possible
+# #define A   \
+#   int aaaa; \
+#   int b;    \
+#   int cccccccc;
+AlignEscapedNewlines: Left
+
+# Align operands of binary and ternary expressions
+# int aaa = bbbbbbbbbbb +
+#           cccccc;
+AlignOperands: true
+
+# Don't align trailing comments
+# int a; // Comment a
+# int b = 2; // Comment b
+AlignTrailingComments: false
+
+# By default don't allow putting parameters onto the next line
+# myFunction(foo, bar, baz);
+AllowAllParametersOfDeclarationOnNextLine: false
+
+# Don't allow short braced statements to be on a single line
+# if (a)           not       if (a) return;
+#   return;
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+
+# By default don't add a line break after the return type of top-level functions
+# int foo();
+AlwaysBreakAfterReturnType: None
+
+# Pack as many parameters or arguments onto the same line as possible
+# int myFunction(int aaaaaaaaaaaa, int bbbbbbbb,
+#                int cccc);
+BinPackArguments: true
+BinPackParameters: true
+
+# Add no space around the bit field
+# unsigned bf:2;
+BitFieldColonSpacing: None
+
+# Attach braces to surrounding context except break before braces on function
+# definitions.
+# void foo()
+# {
+#    if (true) {
+#    } else {
+#    }
+# };
+BreakBeforeBraces: Linux
+
+# Break after operators
+# int value = aaaaaaaaaaaaa +
+#             bbbbbb -
+#             ccccccccccc;
+BreakBeforeBinaryOperators: None
+BreakBeforeTernaryOperators: false
+
+# Don't break string literals
+BreakStringLiterals: false
+
+# Use the same indentation level as for the switch statement.
+# Switch statement body is always indented one level more than case labels.
+IndentCaseLabels: false
+
+# Indents directives before the hash. Each level uses a single space for
+# indentation.
+# #if FOO
+# # include <foo>
+# #endif
+IndentPPDirectives: AfterHash
+PPIndentWidth: 1
+
+# Don't indent a function definition or declaration if it is wrapped after the
+# type
+IndentWrappedFunctionNames: false
+
+# Align pointer to the right
+# int *a;
+PointerAlignment: Right
+
+# Don't insert a space after a cast
+# x = (int32)y;    not    x = (int32) y;
+SpaceAfterCStyleCast: false
+
+# No space is inserted after the logical not operator
+SpaceAfterLogicalNot: false
+
+# Insert spaces before and after assignment operators
+# int a = 5;    not    int a=5;
+# a += 42;             a+=42;
+SpaceBeforeAssignmentOperators: true
+
+# Spaces will be removed before case colon.
+# case 1: break;    not     case 1 : break;
+SpaceBeforeCaseColon: false
+
+# Put a space before opening parentheses only after control statement keywords.
+# void f() {
+#   if (true) {
+#     f();
+#   }
+# }
+SpaceBeforeParens: ControlStatements
+
+# Don't insert spaces inside empty '()'
+SpaceInEmptyParentheses: false
+
+# No space before first '[' in arrays
+# int a[5][5];     not      int a [5][5];
+SpaceBeforeSquareBrackets: false
+
+# No space will be inserted into {}
+# while (true) {}    not    while (true) { }
+SpaceInEmptyBlock: false
+
+# The number of spaces before trailing line comments (// - comments).
+# This does not affect trailing block comments (/* - comments).
+SpacesBeforeTrailingComments: 1
+
+# Don't insert spaces in casts
+# x = (int32) y;    not    x = ( int32 ) y;
+SpacesInCStyleCastParentheses: false
+
+# Don't insert spaces inside container literals
+# var arr = [1, 2, 3];    not    var arr = [ 1, 2, 3 ];
+SpacesInContainerLiterals: false
+
+# Don't insert spaces after '(' or before ')'
+# f(arg);    not    f( arg );
+SpacesInParentheses: false
+
+# Don't insert spaces after '[' or before ']'
+# int a[5];    not    int a[ 5 ];
+SpacesInSquareBrackets: false
+
+# Insert a space after '{' and before '}' in struct initializers
+Cpp11BracedListStyle: false
+
+# A list of macros that should be interpreted as foreach loops instead of as
+# function calls. Taken from:
+#   git grep -h '^#define [^[:space:]]*for_\?each[^[:space:]]*(' |
+#   sed "s/^#define /  - '/; s/(.*$/'/" | sort | uniq
+ForEachMacros:
+  - 'for_each_builtin'
+  - 'for_each_string_list_item'
+  - 'for_each_ut'
+  - 'for_each_wanted_builtin'
+  - 'hashmap_for_each_entry'
+  - 'hashmap_for_each_entry_from'
+  - 'kh_foreach'
+  - 'kh_foreach_value'
+  - 'list_for_each'
+  - 'list_for_each_dir'
+  - 'list_for_each_prev'
+  - 'list_for_each_prev_safe'
+  - 'list_for_each_safe'
+  - 'strintmap_for_each_entry'
+  - 'strmap_for_each_entry'
+  - 'strset_for_each_entry'
+
+# A list of macros that should be interpreted as conditionals instead of as
+# function calls.
+IfMacros:
+  - 'if_test'
+
+# The maximum number of consecutive empty lines to keep.
+MaxEmptyLinesToKeep: 1
+
+# No empty line at the start of a block.
+KeepEmptyLinesAtTheStartOfBlocks: false
+
+# Penalties
+# This decides what order things should be done if a line is too long
+PenaltyBreakAssignment: 5
+PenaltyBreakBeforeFirstCallParameter: 5
+PenaltyBreakComment: 5
+PenaltyBreakFirstLessLess: 0
+PenaltyBreakOpenParenthesis: 300
+PenaltyBreakString: 5
+PenaltyExcessCharacter: 10
+PenaltyReturnTypeOnItsOwnLine: 300
+
+# Don't sort #include's
+SortIncludes: false
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..15d6cbeab1
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,16 @@
+[*]
+charset = utf-8
+insert_final_newline = true
+
+# The settings for C (*.c and *.h) files are mirrored in .clang-format.  Keep
+# them in sync.
+[{*.{c,h,sh,perl,pl,pm,txt},config.mak.*,Makefile}]
+indent_style = tab
+tab_width = 8
+
+[*.py]
+indent_style = space
+indent_size = 4
+
+[COMMIT_EDITMSG]
+max_line_length = 72
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..158c3d45c4
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,18 @@
+* whitespace=!indent,trail,space
+*.[ch] whitespace=indent,trail,space diff=cpp
+*.sh whitespace=indent,trail,space text eol=lf
+*.perl text eol=lf diff=perl
+*.pl text eof=lf diff=perl
+*.pm text eol=lf diff=perl
+*.py text eol=lf diff=python
+*.bat text eol=crlf
+CODE_OF_CONDUCT.md -whitespace
+/Documentation/**/*.txt text eol=lf
+/command-list.txt text eol=lf
+/GIT-VERSION-GEN text eol=lf
+/mergetools/* text eol=lf
+/t/oid-info/* text eol=lf
+/Documentation/git-merge.txt conflict-marker-size=32
+/Documentation/gitk.txt conflict-marker-size=32
+/Documentation/user-manual.txt conflict-marker-size=32
+/t/t????-*.sh conflict-marker-size=32
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000000..c8755e38de
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,22 @@
+## Contributing to Git
+
+Thanks for taking the time to contribute to Git! Please be advised that the
+Git community does not use github.com for their contributions. Instead, we use
+a mailing list (git@xxxxxxxxxxxxxxx) for code submissions, code
+reviews, and bug reports.
+
+Nevertheless, you can use [GitGitGadget](https://gitgitgadget.github.io/) to
+conveniently send your Pull Requests commits to our mailing list.
+
+Please read ["A note from the maintainer"](https://git.kernel.org/pub/scm/git/git.git/plain/MaintNotes?h=todo)
+to learn how the Git project is managed, and how you can work with it.
+In addition, we highly recommend you to read [our submission guidelines](../Documentation/SubmittingPatches).
+
+If you prefer video, then [this talk](https://www.youtube.com/watch?v=Q7i_qQW__q4&feature=youtu.be&t=6m4s)
+might be useful to you as the presenter walks you through the contribution
+process by example.
+
+Or, you can follow the ["My First Contribution"](https://git-scm.com/docs/MyFirstContribution)
+tutorial for another example of the contribution process.
+
+Your friendly Git community!
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000000..37654cdfd7
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,10 @@
+Thanks for taking the time to contribute to Git! Please be advised that the
+Git community does not use github.com for their contributions. Instead, we use
+a mailing list (git@xxxxxxxxxxxxxxx) for code submissions, code reviews, and
+bug reports. Nevertheless, you can use GitGitGadget (https://gitgitgadget.github.io/)
+to conveniently send your Pull Requests commits to our mailing list.
+
+For a single-commit pull request, please *leave the pull request description
+empty*: your commit message itself should describe your changes.
+
+Please read the "guidelines for contributing" linked above!
diff --git a/.github/workflows/check-style.yml b/.github/workflows/check-style.yml
new file mode 100644
index 0000000000..c052a5df23
--- /dev/null
+++ b/.github/workflows/check-style.yml
@@ -0,0 +1,34 @@
+name: check-style
+
+# Get the repository with all commits to ensure that we can analyze
+# all of the commits contributed via the Pull Request.
+
+on:
+  pull_request:
+    types: [opened, synchronize]
+
+# Avoid unnecessary builds. Unlike the main CI jobs, these are not
+# ci-configurable (but could be).
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  check-style:
+    env:
+      CC: clang
+      jobname: ClangFormat
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+
+    - run: ci/install-dependencies.sh
+
+    - name: git clang-format
+      continue-on-error: true
+      id: check_out
+      run: |
+        ./ci/run-style-check.sh \
+          "${{github.event.pull_request.base.sha}}"
diff --git a/.github/workflows/check-whitespace.yml b/.github/workflows/check-whitespace.yml
new file mode 100644
index 0000000000..d0a78fc426
--- /dev/null
+++ b/.github/workflows/check-whitespace.yml
@@ -0,0 +1,32 @@
+name: check-whitespace
+
+# Get the repository with all commits to ensure that we can analyze
+# all of the commits contributed via the Pull Request.
+# Process `git log --check` output to extract just the check errors.
+# Exit with failure upon white-space issues.
+
+on:
+  pull_request:
+    types: [opened, synchronize]
+
+# Avoid unnecessary builds. Unlike the main CI jobs, these are not
+# ci-configurable (but could be).
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  check-whitespace:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 0
+
+    - name: git log --check
+      id: check_out
+      run: |
+        ./ci/check-whitespace.sh \
+          "${{github.event.pull_request.base.sha}}" \
+          "$GITHUB_STEP_SUMMARY" \
+          "https://github.com/${{github.repository}}";
diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml
new file mode 100644
index 0000000000..48341e81f4
--- /dev/null
+++ b/.github/workflows/coverity.yml
@@ -0,0 +1,163 @@
+name: Coverity
+
+# This GitHub workflow automates submitting builds to Coverity Scan. To enable it,
+# set the repository variable `ENABLE_COVERITY_SCAN_FOR_BRANCHES` (for details, see
+# https://docs.github.com/en/actions/learn-github-actions/variables) to a JSON
+# string array containing the names of the branches for which the workflow should be
+# run, e.g. `["main", "next"]`.
+#
+# In addition, two repository secrets must be set (for details how to add secrets, see
+# https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions):
+# `COVERITY_SCAN_EMAIL` and `COVERITY_SCAN_TOKEN`. The former specifies the
+# email to which the Coverity reports should be sent and the latter can be
+# obtained from the Project Settings tab of the Coverity project).
+#
+# The workflow runs on `ubuntu-latest` by default. This can be overridden by setting
+# the repository variable `ENABLE_COVERITY_SCAN_ON_OS` to a JSON string array specifying
+# the operating systems, e.g. `["ubuntu-latest", "windows-latest"]`.
+#
+# By default, the builds are submitted to the Coverity project `git`. To override this,
+# set the repository variable `COVERITY_PROJECT`.
+
+on:
+  push:
+
+defaults:
+  run:
+    shell: bash
+
+jobs:
+  coverity:
+    if: contains(fromJSON(vars.ENABLE_COVERITY_SCAN_FOR_BRANCHES || '[""]'), github.ref_name)
+    strategy:
+      matrix:
+        os: ${{ fromJSON(vars.ENABLE_COVERITY_SCAN_ON_OS || '["ubuntu-latest"]') }}
+    runs-on: ${{ matrix.os }}
+    env:
+      COVERITY_PROJECT: ${{ vars.COVERITY_PROJECT || 'git' }}
+      COVERITY_LANGUAGE: cxx
+      COVERITY_PLATFORM: overridden-below
+    steps:
+      - uses: actions/checkout@v4
+      - name: install minimal Git for Windows SDK
+        if: contains(matrix.os, 'windows')
+        uses: git-for-windows/setup-git-for-windows-sdk@v1
+      - run: ci/install-dependencies.sh
+        if: contains(matrix.os, 'ubuntu') || contains(matrix.os, 'macos')
+        env:
+          distro: ${{ matrix.os }}
+
+      # The Coverity site says the tool is usually updated twice yearly, so the
+      # MD5 of download can be used to determine whether there's been an update.
+      - name: get the Coverity Build Tool hash
+        id: lookup
+        run: |
+          case "${{ matrix.os }}" in
+          *windows*)
+            COVERITY_PLATFORM=win64
+            COVERITY_TOOL_FILENAME=cov-analysis.zip
+            MAKEFLAGS=-j$(nproc)
+            ;;
+          *macos*)
+            COVERITY_PLATFORM=macOSX
+            COVERITY_TOOL_FILENAME=cov-analysis.dmg
+            MAKEFLAGS=-j$(sysctl -n hw.physicalcpu)
+            ;;
+          *ubuntu*)
+            COVERITY_PLATFORM=linux64
+            COVERITY_TOOL_FILENAME=cov-analysis.tgz
+            MAKEFLAGS=-j$(nproc)
+            ;;
+          *)
+            echo '::error::unhandled OS ${{ matrix.os }}' >&2
+            exit 1
+            ;;
+          esac
+          echo "COVERITY_PLATFORM=$COVERITY_PLATFORM" >>$GITHUB_ENV
+          echo "COVERITY_TOOL_FILENAME=$COVERITY_TOOL_FILENAME" >>$GITHUB_ENV
+          echo "MAKEFLAGS=$MAKEFLAGS" >>$GITHUB_ENV
+          MD5=$(curl https://scan.coverity.com/download/$COVERITY_LANGUAGE/$COVERITY_PLATFORM \
+                   --fail \
+                   --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+                   --form project="$COVERITY_PROJECT" \
+                   --form md5=1)
+          case $? in
+          0) ;; # okay
+          22) # 40x, i.e. access denied
+            echo "::error::incorrect token or project?" >&2
+            exit 1
+            ;;
+          *) # other error
+            echo "::error::Failed to retrieve MD5" >&2
+            exit 1
+            ;;
+          esac
+          echo "hash=$MD5" >>$GITHUB_OUTPUT
+
+      # Try to cache the tool to avoid downloading 1GB+ on every run.
+      # A cache miss will add ~30s to create, but a cache hit will save minutes.
+      - name: restore the Coverity Build Tool
+        id: cache
+        uses: actions/cache/restore@v4
+        with:
+          path: ${{ runner.temp }}/cov-analysis
+          key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
+      - name: download the Coverity Build Tool (${{ env.COVERITY_LANGUAGE }} / ${{ env.COVERITY_PLATFORM}})
+        if: steps.cache.outputs.cache-hit != 'true'
+        run: |
+          curl https://scan.coverity.com/download/$COVERITY_LANGUAGE/$COVERITY_PLATFORM \
+            --fail --no-progress-meter \
+            --output $RUNNER_TEMP/$COVERITY_TOOL_FILENAME \
+            --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+            --form project="$COVERITY_PROJECT"
+      - name: extract the Coverity Build Tool
+        if: steps.cache.outputs.cache-hit != 'true'
+        run: |
+          case "$COVERITY_TOOL_FILENAME" in
+          *.tgz)
+            mkdir $RUNNER_TEMP/cov-analysis &&
+            tar -xzf $RUNNER_TEMP/$COVERITY_TOOL_FILENAME --strip 1 -C $RUNNER_TEMP/cov-analysis
+            ;;
+          *.dmg)
+            cd $RUNNER_TEMP &&
+            attach="$(hdiutil attach $COVERITY_TOOL_FILENAME)" &&
+            volume="$(echo "$attach" | cut -f 3 | grep /Volumes/)" &&
+            mkdir cov-analysis &&
+            cd cov-analysis &&
+            sh "$volume"/cov-analysis-macosx-*.sh &&
+            ls -l &&
+            hdiutil detach "$volume"
+            ;;
+          *.zip)
+            cd $RUNNER_TEMP &&
+            mkdir cov-analysis-tmp &&
+            unzip -d cov-analysis-tmp $COVERITY_TOOL_FILENAME &&
+            mv cov-analysis-tmp/* cov-analysis
+            ;;
+          *)
+            echo "::error::unhandled archive type: $COVERITY_TOOL_FILENAME" >&2
+            exit 1
+            ;;
+          esac
+      - name: cache the Coverity Build Tool
+        if: steps.cache.outputs.cache-hit != 'true'
+        uses: actions/cache/save@v4
+        with:
+          path: ${{ runner.temp }}/cov-analysis
+          key: cov-build-${{ env.COVERITY_LANGUAGE }}-${{ env.COVERITY_PLATFORM }}-${{ steps.lookup.outputs.hash }}
+      - name: build with cov-build
+        run: |
+          export PATH="$RUNNER_TEMP/cov-analysis/bin:$PATH" &&
+          cov-configure --gcc &&
+          cov-build --dir cov-int make
+      - name: package the build
+        run: tar -czvf cov-int.tgz cov-int
+      - name: submit the build to Coverity Scan
+        run: |
+          curl \
+            --fail \
+            --form token='${{ secrets.COVERITY_SCAN_TOKEN }}' \
+            --form email='${{ secrets.COVERITY_SCAN_EMAIL }}' \
+            --form file=@cov-int.tgz \
+            --form version='${{ github.sha }}' \
+            "https://scan.coverity.com/builds?project=$COVERITY_PROJECT";
diff --git a/.github/workflows/l10n.yml b/.github/workflows/l10n.yml
new file mode 100644
index 0000000000..e2c3dbdcb5
--- /dev/null
+++ b/.github/workflows/l10n.yml
@@ -0,0 +1,111 @@
+name: git-l10n
+
+on: [push, pull_request_target]
+
+# Avoid unnecessary builds. Unlike the main CI jobs, these are not
+# ci-configurable (but could be).
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
+jobs:
+  git-po-helper:
+    if: >-
+      endsWith(github.repository, '/git-po') ||
+      contains(github.head_ref, 'l10n') ||
+      contains(github.ref, 'l10n')
+    runs-on: ubuntu-latest
+    permissions:
+      pull-requests: write
+    steps:
+      - name: Setup base and head objects
+        id: setup-tips
+        run: |
+          if test "${{ github.event_name }}" = "pull_request_target"
+          then
+            base=${{ github.event.pull_request.base.sha }}
+            head=${{ github.event.pull_request.head.sha }}
+          else
+            base=${{ github.event.before }}
+            head=${{ github.event.after }}
+          fi
+          echo base=$base >>$GITHUB_OUTPUT
+          echo head=$head >>$GITHUB_OUTPUT
+      - name: Run partial clone
+        run: |
+          git -c init.defaultBranch=master init --bare .
+          git remote add \
+            --mirror=fetch \
+            origin \
+            https://github.com/${{ github.repository }}
+          # Fetch tips that may be unreachable from github.ref:
+          # - For a forced push, "$base" may be unreachable.
+          # - For a "pull_request_target" event, "$head" may be unreachable.
+          args=
+          for commit in \
+            ${{ steps.setup-tips.outputs.base }} \
+            ${{ steps.setup-tips.outputs.head }}
+          do
+            case $commit in
+            *[^0]*)
+              args="$args $commit"
+              ;;
+            *)
+              # Should not fetch ZERO-OID.
+              ;;
+            esac
+          done
+          git -c protocol.version=2 fetch \
+            --progress \
+            --no-tags \
+            --no-write-fetch-head \
+            --filter=blob:none \
+            origin \
+            ${{ github.ref }} \
+            $args
+      - uses: actions/setup-go@v5
+        with:
+          go-version: '>=1.16'
+          cache: false
+      - name: Install git-po-helper
+        run: go install github.com/git-l10n/git-po-helper@main
+      - name: Install other dependencies
+        run: |
+          sudo apt-get update -q &&
+          sudo apt-get install -q -y gettext
+      - name: Run git-po-helper
+        id: check-commits
+        run: |
+          exit_code=0
+          git-po-helper check-commits \
+            --github-action-event="${{ github.event_name }}" -- \
+            ${{ steps.setup-tips.outputs.base }}..${{ steps.setup-tips.outputs.head }} \
+            >git-po-helper.out 2>&1 || exit_code=$?
+          if test $exit_code -ne 0 || grep -q WARNING git-po-helper.out
+          then
+            # Remove ANSI colors which are proper for console logs but not
+            # proper for PR comment.
+            echo "COMMENT_BODY<<EOF" >>$GITHUB_ENV
+            perl -pe 's/\e\[[0-9;]*m//g; s/\bEOF$//g' git-po-helper.out >>$GITHUB_ENV
+            echo "EOF" >>$GITHUB_ENV
+          fi
+          cat git-po-helper.out
+          exit $exit_code
+      - name: Create comment in pull request for report
+        uses: mshick/add-pr-comment@v2
+        if: >-
+          always() &&
+          github.event_name == 'pull_request_target' &&
+          env.COMMENT_BODY != ''
+        with:
+          repo-token: ${{ secrets.GITHUB_TOKEN }}
+          message: >
+            ${{ steps.check-commits.outcome == 'failure' && 'Errors and warnings' || 'Warnings' }}
+            found by [git-po-helper](https://github.com/git-l10n/git-po-helper#readme) in workflow
+            [#${{ github.run_number }}](${{ env.GITHUB_SERVER_URL }}/${{ github.repository }}/actions/runs/${{ github.run_id }}):
+
+            ```
+
+            ${{ env.COMMENT_BODY }}
+
+            ```
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000000..900be9957a
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,434 @@
+name: CI
+
+on: [push, pull_request]
+
+env:
+  DEVELOPER: 1
+
+# If more than one workflow run is triggered for the very same commit hash
+# (which happens when multiple branches pointing to the same commit), only
+# the first one is allowed to run, the second will be kept in the "queued"
+# state. This allows a successful completion of the first run to be reused
+# in the second run via the `skip-if-redundant` logic in the `config` job.
+#
+# The only caveat is that if a workflow run is triggered for the same commit
+# hash that another run is already being held, that latter run will be
+# canceled. For more details about the `concurrency` attribute, see:
+# https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency
+concurrency:
+  group: ${{ github.sha }}
+
+jobs:
+  ci-config:
+    name: config
+    if: vars.CI_BRANCHES == '' || contains(vars.CI_BRANCHES, github.ref_name)
+    runs-on: ubuntu-latest
+    outputs:
+      enabled: ${{ steps.check-ref.outputs.enabled }}${{ steps.skip-if-redundant.outputs.enabled }}
+      skip_concurrent: ${{ steps.check-ref.outputs.skip_concurrent }}
+    steps:
+      - name: try to clone ci-config branch
+        run: |
+          git -c protocol.version=2 clone \
+            --no-tags \
+            --single-branch \
+            -b ci-config \
+            --depth 1 \
+            --no-checkout \
+            --filter=blob:none \
+            https://github.com/${{ github.repository }} \
+            config-repo &&
+          cd config-repo &&
+          git checkout HEAD -- ci/config || : ignore
+      - id: check-ref
+        name: check whether CI is enabled for ref
+        run: |
+          enabled=yes
+          if test -x config-repo/ci/config/allow-ref
+          then
+            echo "::warning::ci/config/allow-ref is deprecated; use CI_BRANCHES instead"
+            if ! config-repo/ci/config/allow-ref '${{ github.ref }}'
+            then
+              enabled=no
+            fi
+          fi
+
+          skip_concurrent=yes
+          if test -x config-repo/ci/config/skip-concurrent &&
+             ! config-repo/ci/config/skip-concurrent '${{ github.ref }}'
+          then
+            skip_concurrent=no
+          fi
+          echo "enabled=$enabled" >>$GITHUB_OUTPUT
+          echo "skip_concurrent=$skip_concurrent" >>$GITHUB_OUTPUT
+      - name: skip if the commit or tree was already tested
+        id: skip-if-redundant
+        uses: actions/github-script@v7
+        if: steps.check-ref.outputs.enabled == 'yes'
+        with:
+          github-token: ${{secrets.GITHUB_TOKEN}}
+          script: |
+            try {
+              // Figure out workflow ID, commit and tree
+              const { data: run } = await github.rest.actions.getWorkflowRun({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                run_id: context.runId,
+              });
+              const workflow_id = run.workflow_id;
+              const head_sha = run.head_sha;
+              const tree_id = run.head_commit.tree_id;
+
+              // See whether there is a successful run for that commit or tree
+              const { data: runs } = await github.rest.actions.listWorkflowRuns({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                per_page: 500,
+                status: 'success',
+                workflow_id,
+              });
+              for (const run of runs.workflow_runs) {
+                if (head_sha === run.head_sha) {
+                  core.warning(`Successful run for the commit ${head_sha}: ${run.html_url}`);
+                  core.setOutput('enabled', ' but skip');
+                  break;
+                }
+                if (run.head_commit && tree_id === run.head_commit.tree_id) {
+                  core.warning(`Successful run for the tree ${tree_id}: ${run.html_url}`);
+                  core.setOutput('enabled', ' but skip');
+                  break;
+                }
+              }
+            } catch (e) {
+              core.warning(e);
+            }
+
+  windows-build:
+    name: win build
+    needs: ci-config
+    if: needs.ci-config.outputs.enabled == 'yes'
+    runs-on: windows-latest
+    concurrency:
+      group: windows-build-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    steps:
+    - uses: actions/checkout@v4
+    - uses: git-for-windows/setup-git-for-windows-sdk@v1
+    - name: build
+      shell: bash
+      env:
+        HOME: ${{runner.workspace}}
+        NO_PERL: 1
+      run: . /etc/profile && ci/make-test-artifacts.sh artifacts
+    - name: zip up tracked files
+      run: git archive -o artifacts/tracked.tar.gz HEAD
+    - name: upload tracked files and build artifacts
+      uses: actions/upload-artifact@v4
+      with:
+        name: windows-artifacts
+        path: artifacts
+  windows-test:
+    name: win test
+    runs-on: windows-latest
+    needs: [ci-config, windows-build]
+    strategy:
+      fail-fast: false
+      matrix:
+        nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+    concurrency:
+      group: windows-test-${{ matrix.nr }}-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    steps:
+    - name: download tracked files and build artifacts
+      uses: actions/download-artifact@v4
+      with:
+        name: windows-artifacts
+        path: ${{github.workspace}}
+    - name: extract tracked files and build artifacts
+      shell: bash
+      run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz
+    - uses: git-for-windows/setup-git-for-windows-sdk@v1
+    - name: test
+      shell: bash
+      run: . /etc/profile && ci/run-test-slice.sh ${{matrix.nr}} 10
+    - name: print test failures
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      shell: bash
+      run: ci/print-test-failures.sh
+    - name: Upload failed tests' directories
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      uses: actions/upload-artifact@v4
+      with:
+        name: failed-tests-windows-${{ matrix.nr }}
+        path: ${{env.FAILED_TEST_ARTIFACTS}}
+  vs-build:
+    name: win+VS build
+    needs: ci-config
+    if: github.event.repository.owner.login == 'git-for-windows' && needs.ci-config.outputs.enabled == 'yes'
+    env:
+      NO_PERL: 1
+      GIT_CONFIG_PARAMETERS: "'user.name=CI' 'user.email=ci@git'"
+    runs-on: windows-latest
+    concurrency:
+      group: vs-build-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    steps:
+    - uses: actions/checkout@v4
+    - uses: git-for-windows/setup-git-for-windows-sdk@v1
+    - name: initialize vcpkg
+      uses: actions/checkout@v4
+      with:
+        repository: 'microsoft/vcpkg'
+        path: 'compat/vcbuild/vcpkg'
+    - name: download vcpkg artifacts
+      uses: git-for-windows/get-azure-pipelines-artifact@v0
+      with:
+        repository: git/git
+        definitionId: 9
+    - name: add msbuild to PATH
+      uses: microsoft/setup-msbuild@v2
+    - name: copy dlls to root
+      shell: cmd
+      run: compat\vcbuild\vcpkg_copy_dlls.bat release
+    - name: generate Visual Studio solution
+      shell: bash
+      run: |
+        cmake `pwd`/contrib/buildsystems/ -DCMAKE_PREFIX_PATH=`pwd`/compat/vcbuild/vcpkg/installed/x64-windows \
+        -DNO_GETTEXT=YesPlease -DPERL_TESTS=OFF -DPYTHON_TESTS=OFF -DCURL_NO_CURL_CMAKE=ON
+    - name: MSBuild
+      run: msbuild git.sln -property:Configuration=Release -property:Platform=x64 -maxCpuCount:4 -property:PlatformToolset=v142
+    - name: bundle artifact tar
+      shell: bash
+      env:
+        MSVC: 1
+        VCPKG_ROOT: ${{github.workspace}}\compat\vcbuild\vcpkg
+      run: |
+        mkdir -p artifacts &&
+        eval "$(make -n artifacts-tar INCLUDE_DLLS_IN_ARTIFACTS=YesPlease ARTIFACTS_DIRECTORY=artifacts NO_GETTEXT=YesPlease 2>&1 | grep ^tar)"
+    - name: zip up tracked files
+      run: git archive -o artifacts/tracked.tar.gz HEAD
+    - name: upload tracked files and build artifacts
+      uses: actions/upload-artifact@v4
+      with:
+        name: vs-artifacts
+        path: artifacts
+  vs-test:
+    name: win+VS test
+    runs-on: windows-latest
+    needs: [ci-config, vs-build]
+    strategy:
+      fail-fast: false
+      matrix:
+        nr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
+    concurrency:
+      group: vs-test-${{ matrix.nr }}-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    steps:
+    - uses: git-for-windows/setup-git-for-windows-sdk@v1
+    - name: download tracked files and build artifacts
+      uses: actions/download-artifact@v4
+      with:
+        name: vs-artifacts
+        path: ${{github.workspace}}
+    - name: extract tracked files and build artifacts
+      shell: bash
+      run: tar xf artifacts.tar.gz && tar xf tracked.tar.gz
+    - name: test
+      shell: bash
+      env:
+        NO_SVN_TESTS: 1
+      run: . /etc/profile && ci/run-test-slice.sh ${{matrix.nr}} 10
+    - name: print test failures
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      shell: bash
+      run: ci/print-test-failures.sh
+    - name: Upload failed tests' directories
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      uses: actions/upload-artifact@v4
+      with:
+        name: failed-tests-windows-vs-${{ matrix.nr }}
+        path: ${{env.FAILED_TEST_ARTIFACTS}}
+  regular:
+    name: ${{matrix.vector.jobname}} (${{matrix.vector.pool}})
+    needs: ci-config
+    if: needs.ci-config.outputs.enabled == 'yes'
+    concurrency:
+      group: ${{ matrix.vector.jobname }}-${{ matrix.vector.pool }}-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    strategy:
+      fail-fast: false
+      matrix:
+        vector:
+          - jobname: linux-sha256
+            cc: clang
+            pool: ubuntu-latest
+          - jobname: linux-reftable
+            cc: clang
+            pool: ubuntu-latest
+          - jobname: linux-gcc
+            cc: gcc
+            cc_package: gcc-8
+            pool: ubuntu-20.04
+          - jobname: linux-TEST-vars
+            cc: gcc
+            cc_package: gcc-8
+            pool: ubuntu-20.04
+          - jobname: osx-clang
+            cc: clang
+            pool: macos-13
+          - jobname: osx-reftable
+            cc: clang
+            pool: macos-13
+          - jobname: osx-gcc
+            cc: gcc-13
+            pool: macos-13
+          - jobname: osx-meson
+            cc: clang
+            pool: macos-13
+          - jobname: linux-gcc-default
+            cc: gcc
+            pool: ubuntu-latest
+          - jobname: linux-leaks
+            cc: gcc
+            pool: ubuntu-latest
+          - jobname: linux-reftable-leaks
+            cc: gcc
+            pool: ubuntu-latest
+          - jobname: linux-asan-ubsan
+            cc: clang
+            pool: ubuntu-latest
+          - jobname: linux-meson
+            cc: gcc
+            pool: ubuntu-latest
+    env:
+      CC: ${{matrix.vector.cc}}
+      CC_PACKAGE: ${{matrix.vector.cc_package}}
+      jobname: ${{matrix.vector.jobname}}
+      distro: ${{matrix.vector.pool}}
+      TEST_OUTPUT_DIRECTORY: ${{github.workspace}}/t
+    runs-on: ${{matrix.vector.pool}}
+    steps:
+    - uses: actions/checkout@v4
+    - run: ci/install-dependencies.sh
+    - run: ci/run-build-and-tests.sh
+    - name: print test failures
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      run: ci/print-test-failures.sh
+    - name: Upload failed tests' directories
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      uses: actions/upload-artifact@v4
+      with:
+        name: failed-tests-${{matrix.vector.jobname}}
+        path: ${{env.FAILED_TEST_ARTIFACTS}}
+  fuzz-smoke-test:
+    name: fuzz smoke test
+    needs: ci-config
+    if: needs.ci-config.outputs.enabled == 'yes'
+    env:
+      CC: clang
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v4
+    - run: ci/install-dependencies.sh
+    - run: ci/run-build-and-minimal-fuzzers.sh
+  dockerized:
+    name: ${{matrix.vector.jobname}} (${{matrix.vector.image}})
+    needs: ci-config
+    if: needs.ci-config.outputs.enabled == 'yes'
+    concurrency:
+      group: dockerized-${{ matrix.vector.jobname }}-${{ matrix.vector.image }}-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    strategy:
+      fail-fast: false
+      matrix:
+        vector:
+        - jobname: linux-musl
+          image: alpine
+          distro: alpine-latest
+        # Supported until 2025-04-02.
+        - jobname: linux32
+          image: i386/ubuntu:focal
+          distro: ubuntu32-20.04
+        - jobname: pedantic
+          image: fedora
+          distro: fedora-latest
+        # A RHEL 8 compatible distro.  Supported until 2029-05-31.
+        - jobname: almalinux-8
+          image: almalinux:8
+          distro: almalinux-8
+        # Supported until 2026-08-31.
+        - jobname: debian-11
+          image: debian:11
+          distro: debian-11
+    env:
+      jobname: ${{matrix.vector.jobname}}
+      distro: ${{matrix.vector.distro}}
+    runs-on: ubuntu-latest
+    container: ${{matrix.vector.image}}
+    steps:
+    - name: prepare libc6 for actions
+      if: matrix.vector.jobname == 'linux32'
+      run: apt -q update && apt -q -y install libc6-amd64 lib64stdc++6
+    - uses: actions/checkout@v4
+    - run: ci/install-dependencies.sh
+    - run: ci/run-build-and-tests.sh
+    - name: print test failures
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      run: ci/print-test-failures.sh
+    - name: Upload failed tests' directories
+      if: failure() && env.FAILED_TEST_ARTIFACTS != ''
+      uses: actions/upload-artifact@v4
+      with:
+        name: failed-tests-${{matrix.vector.jobname}}
+        path: ${{env.FAILED_TEST_ARTIFACTS}}
+  static-analysis:
+    needs: ci-config
+    if: needs.ci-config.outputs.enabled == 'yes'
+    env:
+      jobname: StaticAnalysis
+    runs-on: ubuntu-22.04
+    concurrency:
+      group: static-analysis-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    steps:
+    - uses: actions/checkout@v4
+    - run: ci/install-dependencies.sh
+    - run: ci/run-static-analysis.sh
+    - run: ci/check-directional-formatting.bash
+  sparse:
+    needs: ci-config
+    if: needs.ci-config.outputs.enabled == 'yes'
+    env:
+      jobname: sparse
+    runs-on: ubuntu-20.04
+    concurrency:
+      group: sparse-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    steps:
+    - name: Download a current `sparse` package
+      # Ubuntu's `sparse` version is too old for us
+      uses: git-for-windows/get-azure-pipelines-artifact@v0
+      with:
+        repository: git/git
+        definitionId: 10
+        artifact: sparse-20.04
+    - name: Install the current `sparse` package
+      run: sudo dpkg -i sparse-20.04/sparse_*.deb
+    - uses: actions/checkout@v4
+    - name: Install other dependencies
+      run: ci/install-dependencies.sh
+    - run: make sparse
+  documentation:
+    name: documentation
+    needs: ci-config
+    if: needs.ci-config.outputs.enabled == 'yes'
+    concurrency:
+      group: documentation-${{ github.ref }}
+      cancel-in-progress: ${{ needs.ci-config.outputs.skip_concurrent == 'yes' }}
+    env:
+      jobname: Documentation
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v4
+    - run: ci/install-dependencies.sh
+    - run: ci/test-documentation.sh
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..e82aa19df0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,252 @@
+/fuzz_corpora
+/GIT-BUILD-DIR
+/GIT-BUILD-OPTIONS
+/GIT-CFLAGS
+/GIT-LDFLAGS
+/GIT-PREFIX
+/GIT-PERL-DEFINES
+/GIT-PERL-HEADER
+/GIT-PYTHON-VARS
+/GIT-SCRIPT-DEFINES
+/GIT-SPATCH-DEFINES
+/GIT-TEST-SUITES
+/GIT-USER-AGENT
+/GIT-VERSION-FILE
+/git
+/git-add
+/git-am
+/git-annotate
+/git-apply
+/git-archimport
+/git-archive
+/git-bisect
+/git-blame
+/git-branch
+/git-bugreport
+/git-bundle
+/git-cat-file
+/git-check-attr
+/git-check-ignore
+/git-check-mailmap
+/git-check-ref-format
+/git-checkout
+/git-checkout--worker
+/git-checkout-index
+/git-cherry
+/git-cherry-pick
+/git-clean
+/git-clone
+/git-column
+/git-commit
+/git-commit-graph
+/git-commit-tree
+/git-config
+/git-count-objects
+/git-credential
+/git-credential-cache
+/git-credential-cache--daemon
+/git-credential-store
+/git-cvsexportcommit
+/git-cvsimport
+/git-cvsserver
+/git-daemon
+/git-diagnose
+/git-diff
+/git-diff-files
+/git-diff-index
+/git-diff-tree
+/git-difftool
+/git-difftool--helper
+/git-describe
+/git-fast-export
+/git-fast-import
+/git-fetch
+/git-fetch-pack
+/git-filter-branch
+/git-fmt-merge-msg
+/git-for-each-ref
+/git-for-each-repo
+/git-format-patch
+/git-fsck
+/git-fsck-objects
+/git-fsmonitor--daemon
+/git-gc
+/git-get-tar-commit-id
+/git-grep
+/git-hash-object
+/git-help
+/git-hook
+/git-http-backend
+/git-http-fetch
+/git-http-push
+/git-imap-send
+/git-index-pack
+/git-init
+/git-init-db
+/git-interpret-trailers
+/git-instaweb
+/git-log
+/git-ls-files
+/git-ls-remote
+/git-ls-tree
+/git-mailinfo
+/git-mailsplit
+/git-maintenance
+/git-merge
+/git-merge-base
+/git-merge-index
+/git-merge-file
+/git-merge-tree
+/git-merge-octopus
+/git-merge-one-file
+/git-merge-ours
+/git-merge-recursive
+/git-merge-resolve
+/git-merge-subtree
+/git-mergetool
+/git-mergetool--lib
+/git-mktag
+/git-mktree
+/git-multi-pack-index
+/git-mv
+/git-name-rev
+/git-notes
+/git-p4
+/git-pack-redundant
+/git-pack-objects
+/git-pack-refs
+/git-patch-id
+/git-prune
+/git-prune-packed
+/git-pull
+/git-push
+/git-quiltimport
+/git-range-diff
+/git-read-tree
+/git-rebase
+/git-receive-pack
+/git-reflog
+/git-refs
+/git-remote
+/git-remote-http
+/git-remote-https
+/git-remote-ftp
+/git-remote-ftps
+/git-remote-fd
+/git-remote-ext
+/git-repack
+/git-replace
+/git-replay
+/git-request-pull
+/git-rerere
+/git-reset
+/git-restore
+/git-rev-list
+/git-rev-parse
+/git-revert
+/git-rm
+/git-send-email
+/git-send-pack
+/git-sh-i18n
+/git-sh-i18n--envsubst
+/git-sh-setup
+/git-shell
+/git-shortlog
+/git-show
+/git-show-branch
+/git-show-index
+/git-show-ref
+/git-sparse-checkout
+/git-stage
+/git-stash
+/git-status
+/git-stripspace
+/git-submodule
+/git-submodule--helper
+/git-subtree
+/git-svn
+/git-switch
+/git-symbolic-ref
+/git-tag
+/git-unpack-file
+/git-unpack-objects
+/git-update-index
+/git-update-ref
+/git-update-server-info
+/git-upload-archive
+/git-upload-pack
+/git-var
+/git-verify-commit
+/git-verify-pack
+/git-verify-tag
+/git-version
+/git-web--browse
+/git-whatchanged
+/git-worktree
+/git-write-tree
+/scalar
+/git-core-*/?*
+/git.res
+/gitweb/GITWEB-BUILD-OPTIONS
+/gitweb/gitweb.cgi
+/gitweb/static/gitweb.js
+/gitweb/static/gitweb.min.*
+/config-list.h
+/command-list.h
+/hook-list.h
+/version-def.h
+*.tar.gz
+*.dsc
+*.deb
+/git.rc
+/git.spec
+*.exe
+*.[aos]
+*.o.json
+*.py[co]
+.build/
+.depend/
+*.gcda
+*.gcno
+*.gcov
+/coverage-untested-functions
+/cover_db/
+/cover_db_html/
+*+
+/config.mak
+/autom4te.cache
+/config.cache
+/config.log
+/config.status
+/config.mak.autogen
+/config.mak.append
+/configure
+/.vscode/
+/tags
+/TAGS
+/cscope*
+/compile_commands.json
+/.cache/
+*.hcc
+*.obj
+*.lib
+*.sln
+*.sp
+*.suo
+*.ncb
+*.vcproj
+*.user
+*.idb
+*.pdb
+*.ilk
+*.iobj
+*.ipdb
+*.dll
+.vs/
+Debug/
+Release/
+/UpgradeLog*.htm
+/git.VC.VC.opendb
+/git.VC.db
+*.dSYM
+/contrib/buildsystems/out
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000..9254e01583
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,220 @@
+default:
+  timeout: 2h
+
+stages:
+  - build
+  - test
+  - analyze
+
+workflow:
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+    - if: $CI_COMMIT_TAG
+    - if: $CI_COMMIT_REF_PROTECTED == "true"
+
+test:linux:
+  image: $image
+  stage: test
+  needs: [ ]
+  tags:
+    - saas-linux-medium-amd64
+  variables:
+    CUSTOM_PATH: "/custom"
+    TEST_OUTPUT_DIRECTORY: "/tmp/test-output"
+  before_script:
+    - ./ci/install-dependencies.sh
+  script:
+    - useradd builder --create-home
+    - chown -R builder "${CI_PROJECT_DIR}"
+    - sudo --preserve-env --set-home --user=builder ./ci/run-build-and-tests.sh
+  after_script:
+    - |
+      if test "$CI_JOB_STATUS" != 'success'
+      then
+        sudo --preserve-env --set-home --user=builder ./ci/print-test-failures.sh
+        mv "$TEST_OUTPUT_DIRECTORY"/failed-test-artifacts t/
+      fi
+  parallel:
+    matrix:
+      - jobname: linux-old
+        image: ubuntu:20.04
+        CC: gcc
+      - jobname: linux-sha256
+        image: ubuntu:latest
+        CC: clang
+      - jobname: linux-reftable
+        image: ubuntu:latest
+        CC: clang
+      - jobname: linux-gcc
+        image: ubuntu:20.04
+        CC: gcc
+        CC_PACKAGE: gcc-8
+      - jobname: linux-TEST-vars
+        image: ubuntu:20.04
+        CC: gcc
+        CC_PACKAGE: gcc-8
+      - jobname: linux-gcc-default
+        image: ubuntu:latest
+        CC: gcc
+      - jobname: linux-leaks
+        image: ubuntu:latest
+        CC: gcc
+      - jobname: linux-reftable-leaks
+        image: ubuntu:latest
+        CC: gcc
+      - jobname: linux-asan-ubsan
+        image: ubuntu:latest
+        CC: clang
+      - jobname: pedantic
+        image: fedora:latest
+      - jobname: linux-musl
+        image: alpine:latest
+      - jobname: linux-meson
+        image: ubuntu:latest
+        CC: gcc
+  artifacts:
+    paths:
+      - t/failed-test-artifacts
+    when: on_failure
+
+test:osx:
+  image: $image
+  stage: test
+  needs: [ ]
+  tags:
+    - saas-macos-medium-m1
+  variables:
+    TEST_OUTPUT_DIRECTORY: "/Volumes/RAMDisk"
+  before_script:
+    # Create a 4GB RAM disk that we use to store test output on. This small hack
+    # significantly speeds up tests by more than a factor of 2 because the
+    # macOS runners use network-attached storage as disks, which is _really_
+    # slow with the many small writes that our tests do.
+    - sudo diskutil apfs create $(hdiutil attach -nomount ram://8192000) RAMDisk
+    - ./ci/install-dependencies.sh
+  script:
+    - ./ci/run-build-and-tests.sh
+  after_script:
+    - |
+      if test "$CI_JOB_STATUS" != 'success'
+      then
+        ./ci/print-test-failures.sh
+        mv "$TEST_OUTPUT_DIRECTORY"/failed-test-artifacts t/
+      fi
+  parallel:
+    matrix:
+      - jobname: osx-clang
+        image: macos-14-xcode-15
+        CC: clang
+      - jobname: osx-reftable
+        image: macos-14-xcode-15
+        CC: clang
+      - jobname: osx-meson
+        image: macos-14-xcode-15
+        CC: clang
+  artifacts:
+    paths:
+      - t/failed-test-artifacts
+    when: on_failure
+
+build:mingw64:
+  stage: build
+  tags:
+    - saas-windows-medium-amd64
+  variables:
+    NO_PERL: 1
+  before_script:
+    - ./ci/install-sdk.ps1 -directory "git-sdk"
+  script:
+    - git-sdk/usr/bin/bash.exe -l -c 'ci/make-test-artifacts.sh artifacts'
+  artifacts:
+    paths:
+      - artifacts
+      - git-sdk
+
+test:mingw64:
+  stage: test
+  tags:
+    - saas-windows-medium-amd64
+  needs:
+    - job: "build:mingw64"
+      artifacts: true
+  before_script:
+    - git-sdk/usr/bin/bash.exe -l -c 'tar xf artifacts/artifacts.tar.gz'
+    - New-Item -Path .git/info -ItemType Directory
+    - New-Item .git/info/exclude -ItemType File -Value "/git-sdk"
+  script:
+    - git-sdk/usr/bin/bash.exe -l -c "ci/run-test-slice.sh $CI_NODE_INDEX $CI_NODE_TOTAL"
+  after_script:
+    - git-sdk/usr/bin/bash.exe -l -c 'ci/print-test-failures.sh'
+  parallel: 10
+
+test:fuzz-smoke-tests:
+  image: ubuntu:latest
+  stage: test
+  needs: [ ]
+  variables:
+    CC: clang
+  before_script:
+    - ./ci/install-dependencies.sh
+  script:
+    - ./ci/run-build-and-minimal-fuzzers.sh
+
+static-analysis:
+  image: ubuntu:22.04
+  stage: analyze
+  needs: [ ]
+  variables:
+    jobname: StaticAnalysis
+  before_script:
+    - ./ci/install-dependencies.sh
+  script:
+    - ./ci/run-static-analysis.sh
+    - ./ci/check-directional-formatting.bash
+
+check-whitespace:
+  image: ubuntu:latest
+  stage: analyze
+  needs: [ ]
+  before_script:
+    - ./ci/install-dependencies.sh
+  # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged
+  # pipelines, we fallback to $CI_MERGE_REQUEST_DIFF_BASE_SHA, which should
+  # be defined in all pipelines.
+  script:
+    - |
+      R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit
+      ./ci/check-whitespace.sh "$R"
+  rules:
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+
+check-style:
+  image: ubuntu:latest
+  stage: analyze
+  needs: [ ]
+  allow_failure: true
+  variables:
+    CC: clang
+    jobname: ClangFormat
+  before_script:
+    - ./ci/install-dependencies.sh
+  # Since $CI_MERGE_REQUEST_TARGET_BRANCH_SHA is only defined for merged
+  # pipelines, we fallback to $CI_MERGE_REQUEST_DIFF_BASE_SHA, which should
+  # be defined in all pipelines.
+  script:
+    - |
+      R=${CI_MERGE_REQUEST_TARGET_BRANCH_SHA-${CI_MERGE_REQUEST_DIFF_BASE_SHA:?}} || exit
+      ./ci/run-style-check.sh "$R"
+  rules:
+    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
+
+documentation:
+  image: ubuntu:latest
+  stage: analyze
+  needs: [ ]
+  variables:
+    jobname: Documentation
+  before_script:
+    - ./ci/install-dependencies.sh
+  script:
+    - ./ci/test-documentation.sh
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000000..cbeebdab7a
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "sha1collisiondetection"]
+	path = sha1collisiondetection
+	url = https://github.com/cr-marcstevens/sha1collisiondetection.git
+	branch = master
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000000..96c2740fbb
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,304 @@
+#
+# This list is used by git-shortlog to fix a few botched name translations
+# in the git archive, either because the author's full name was messed up
+# and/or not always written the same way, making contributions from the
+# same person appearing not to be so.
+#
+
+<nico@xxxxxxxxxxx> <nico@xxxxxxx>
+Alejandro R. Sedeño <asedeno@xxxxxxx> <asedeno@xxxxxxx>
+Alex Bennée <kernel-hacker@xxxxxxxxxx>
+Alex Riesen <raa.lkml@xxxxxxxxx> <fork0@xxxxxxxxxxx>
+Alex Riesen <raa.lkml@xxxxxxxxx> <raa@limbo.localdomain>
+Alex Riesen <raa.lkml@xxxxxxxxx> <raa@xxxxxxxxxx>
+Alex Vandiver <alex@xxxxxxxxx> <alexmv@xxxxxxx>
+Alexander Gavrilov <angavrilov@xxxxxxxxx>
+Alexander Kuleshov <kuleshovmail@xxxxxxxxx>
+Alexey Shumkin <alex.crezoff@xxxxxxxxx> <zapped@xxxxxxx>
+Alexey Shumkin <alex.crezoff@xxxxxxxxx> <Alex.Crezoff@xxxxxxxxx>
+Anders Kaseorg <andersk@xxxxxxx> <andersk@xxxxxxxxxxx>
+Anders Kaseorg <andersk@xxxxxxx> <andersk@xxxxxxx>
+Andrey Mazo <ahippo@xxxxxxxxxx> Mazo, Andrey <amazo@xxxxxxxxxxxxxx>
+Aneesh Kumar K.V <aneesh.kumar@xxxxxxxxx>
+Amos Waterland <apw@xxxxxxxxxx> <apw@xxxxxxxxxxxxxxxxxx>
+Amos Waterland <apw@xxxxxxxxxx> <apw@xxxxxxxxxx>
+Ben Peart <benpeart@xxxxxxxxxxxxx> <Ben.Peart@xxxxxxxxxxxxx>
+Ben Peart <benpeart@xxxxxxxxxxxxx> <peartben@xxxxxxxxx>
+Ben Walton <bdwalton@xxxxxxxxx> <bwalton@xxxxxxxxxxxxxxxxxx>
+Benoit Sigoure <tsunanet@xxxxxxxxx> <tsuna@xxxxxxxxxxxxx>
+Bernt Hansen <bernt@xxxxxxxxx> <bernt@xxxxxxxxxxxxxxxxxxx>
+Brandon Casey <drafnel@xxxxxxxxx> <casey@xxxxxxxxxxxxxxx>
+Brandon Williams <bwilliams.eng@xxxxxxxxx> <bmwill@xxxxxxxxxx>
+brian m. carlson <sandals@xxxxxxxxxxxxxxxxxxxx>
+brian m. carlson <sandals@xxxxxxxxxxxxxxxxxxxx> <sandals@xxxxxxxxxxxxxxxxxxxxxxx>
+brian m. carlson <sandals@xxxxxxxxxxxxxxxxxxxx> <bk2204@xxxxxxxxxx>
+Bryan Larsen <bryan@xxxxxxxxx> <bryan.larsen@xxxxxxxxx>
+Bryan Larsen <bryan@xxxxxxxxx> <bryanlarsen@xxxxxxxxx>
+Cheng Renquan <crquan@xxxxxxxxx>
+Chris Shoemaker <c.shoemaker@xxxxxxx>
+Chris Wright <chrisw@xxxxxxxxxxxx> <chrisw@xxxxxxxx>
+Christian Ludwig <chrissicool@xxxxxxxxx> <chrissicool@xxxxxxxxxxxxxx>
+Cord Seele <cowose@xxxxxxxxx> <cowose@xxxxxxxxxxxxxx>
+Christian Couder <chriscool@xxxxxxxxxxxxx> <christian.couder@xxxxxxxxx>
+Christian Stimming <stimming@xxxxxxx> <chs@ckiste.goetheallee>
+Christopher Díaz Riveros <chrisadr@xxxxxxxxxx> Christopher Diaz Riveros
+Clemens Buchacher <drizzd@xxxxxxx> <drizzd@xxxxxx>
+Clemens Buchacher <drizzd@xxxxxxx> <clemens.buchacher@xxxxxxxxx>
+Csaba Henk <csaba@xxxxxxxxxxx> <csaba@xxxxxxxxxx>
+Dan Johnson <computerdruid@xxxxxxxxx>
+Dana L. How <danahow@xxxxxxxxx> <how@xxxxxxxxxxxxxxxxxxxxxxx>
+Dana L. How <danahow@xxxxxxxxx> Dana How
+Daniel Barkalow <barkalow@xxxxxxxxxxxx>
+Daniel Knittl-Frank <knittl89@xxxxxxxxxxxxxx> knittl
+Daniel Trstenjak <daniel.trstenjak@xxxxxxxxx> <daniel.trstenjak@xxxxxxxxx>
+Daniel Trstenjak <daniel.trstenjak@xxxxxxxxx> <trsten@xxxxxxxxxxxxxxxxxxxx>
+David Brown <git@xxxxxxxxxx> <davidb@xxxxxxxxxxx>
+David D. Kilzer <ddkilzer@xxxxxxxxxx>
+David Kågedal <davidk@xxxxxxxxxxxxxx>
+David Reiss <dreiss@xxxxxxxxxxxx> <dreiss@dreiss-vmware.(none)>
+David S. Miller <davem@xxxxxxxxxxxxx>
+David Turner <novalis@xxxxxxxxxxx> <dturner@xxxxxxxxxxxxxxxx>
+David Turner <novalis@xxxxxxxxxxx> <dturner@xxxxxxxxxxxx>
+Derrick Stolee <stolee@xxxxxxxxx> <derrickstolee@xxxxxxxxxx>
+Derrick Stolee <stolee@xxxxxxxxx> Derrick Stolee via GitGitGadget <gitgitgadget@xxxxxxxxx>
+Derrick Stolee <stolee@xxxxxxxxx> <dstolee@xxxxxxxxxxxxx>
+Deskin Miller <deskinm@xxxxxxxxx>
+Đoàn Trần Công Danh <congdanhqx@xxxxxxxxx> Doan Tran Cong Danh
+Dirk Süsserott <newsletter@xxxxxxxxxxx>
+Emily Shaffer <nasamuffin@xxxxxxxxxx> <emilyshaffer@xxxxxxxxxx>
+Eric Blake <eblake@xxxxxxxxxx> <ebb9@xxxxxxx>
+Eric Hanchrow <eric.hanchrow@xxxxxxxxx> <offby1@xxxxxxxxx>
+Eric S. Raymond <esr@xxxxxxxxxxx>
+Eric Wong <e@xxxxxxxxx> <normalperson@xxxxxxxx>
+Erik Faye-Lund <kusmabite@xxxxxxxxx> <kusmabite@xxxxxxxxxxxxxx>
+Eyvind Bernhardsen <eyvind.bernhardsen@xxxxxxxxx> <eyvind-git@xxxxxxxxxxxxxx>
+Fangyi Zhou <fangyi.zhou@xxxxxxxxxx> Zhou Fangyi
+Florian Achleitner <florian.achleitner.2.6.31@xxxxxxxxx> <florian.achleitner2.6.31@xxxxxxxxx>
+Franck Bui-Huu <vagabon.xyz@xxxxxxxxx> <fbuihuu@xxxxxxxxx>
+Frank Lichtenheld <frank@xxxxxxxxxxxxxx> <djpig@xxxxxxxxxx>
+Frank Lichtenheld <frank@xxxxxxxxxxxxxx> <flichtenheld@xxxxxxxxxx>
+Fredrik Kuivinen <frekui@xxxxxxxxx> <freku045@xxxxxxxxxxxxxx>
+Frédéric Heitzmann <frederic.heitzmann@xxxxxxxxx>
+Garry Dolley <gdolley@xxxxxxxx> <gdolley@xxxxxxxxxxxxxxx>
+Glen Choo <glencbz@xxxxxxxxx> <chooglen@xxxxxxxxxx>
+Greg Price <price@xxxxxxx> <price@xxxxxxx>
+Greg Price <price@xxxxxxx> <price@xxxxxxxxxxx>
+Heiko Voigt <hvoigt@xxxxxxxxxx> <git-list@xxxxxxxxxx>
+H. Merijn Brand <h.m.brand@xxxxxxxxx> H.Merijn Brand <h.m.brand@xxxxxxxxx>
+H. Peter Anvin <hpa@xxxxxxxxx> <hpa@xxxxxxxxxxxxxxxxxxxxxxx>
+H. Peter Anvin <hpa@xxxxxxxxx> <hpa@xxxxxxxxxxxxxxxxxxxx>
+H. Peter Anvin <hpa@xxxxxxxxx> <hpa@xxxxxxxxxxxxxxxxxxxxxxxxx>
+H. Peter Anvin <hpa@xxxxxxxxx> <hpa@xxxxxxxxxxxxxxxxxxxxx>
+Han-Wen Nienhuys <hanwen@xxxxxxxxxx> Han-Wen Nienhuys <hanwen@xxxxxxxxx>
+Horst H. von Brand <vonbrand@xxxxxxxxxxxx>
+J. Bruce Fields <bfields@xxxxxxxxxxxxxx> <bfields@xxxxxxxxxxxx>
+J. Bruce Fields <bfields@xxxxxxxxxxxxxx> <bfields@xxxxxxxxxxxxxxxxxxxxxxxx>
+J. Bruce Fields <bfields@xxxxxxxxxxxxxx> <bfields@xxxxxxxxxxxxxxxxxxx>
+Jakub Narębski <jnareb@xxxxxxxxx>
+James Y Knight <jknight@xxxxxxxxxxxxxxx> <foom@xxxxxxxx>
+# The 2 following authors are probably the same person,
+# but both emails bounce.
+Jason McMullan <jason.mcmullan@xxxxxxxxxxx>
+Jason McMullan <mcmullan@xxxxxxxxxx>
+Jason Riedy <ejr@xxxxxxxxxxxxxxxxx> <ejr@xxxxxxxxxxxxxxxxx>
+Jason Riedy <ejr@xxxxxxxxxxxxxxxxx> <ejr@xxxxxxxxxxxxxxx>
+Jay Soffian <jaysoffian@xxxxxxxxx> <jaysoffian+git@xxxxxxxxx>
+Jean-Noël Avila <jn.avila@xxxxxxx> Jean-Noel Avila
+Jean-Noël Avila <jn.avila@xxxxxxx> Jean-Noël AVILA
+Jeff King <peff@xxxxxxxx> <peff@xxxxxxxxxx>
+Jeff Muizelaar <jmuizelaar@xxxxxxxxxxx> <jeff@xxxxxxxxxxxx>
+Jens Axboe <axboe@xxxxxxxxx> <axboe@xxxxxxx>
+Jens Axboe <axboe@xxxxxxxxx> <jens.axboe@xxxxxxxxxx>
+Jens Lindström <jl@xxxxxxxxx> Jens Lindstrom <jl@xxxxxxxxx>
+Jim Meyering <jim@xxxxxxxxxxxx> <meyering@xxxxxxxxxx>
+Joachim Berdal Haga <cjhaga@xxxxxxxxxx>
+Joachim Jablon <joachim.jablon@xxxxxxxxxxxxxx> <ewjoachim@xxxxxxxxx>
+Johannes Schindelin <Johannes.Schindelin@xxxxxx> <johannes.schindelin@xxxxxx>
+Johannes Schindelin <Johannes.Schindelin@xxxxxx> Johannes Schindelin via GitGitGadget <gitgitgadget@xxxxxxxxx>
+Johannes Sixt <j6t@xxxxxxxx> <J.Sixt@xxxxxxxxxxxxx>
+Johannes Sixt <j6t@xxxxxxxx> <j.sixt@xxxxxxxxxxxxx>
+Johannes Sixt <j6t@xxxxxxxx> <johannes.sixt@xxxxxxxxxx>
+John 'Warthog9' Hawley <warthog9@xxxxxxxxxx> <warthog9@xxxxxxxxxxxxxx>
+Jon Loeliger <jdl@xxxxxxx> <jdl@xxxxxxxxxxxxx>
+Jon Loeliger <jdl@xxxxxxx> <jdl@xxxxxxxxxxxxx>
+Jon Seymour <jon.seymour@xxxxxxxxx> <jon@xxxxxxxxxxxxxxxxxxxxx>
+Jonathan Nieder <jrnieder@xxxxxxxxx> <jrnieder@xxxxxxxxxxxx>
+Jonathan del Strother <jon.delStrother@xxxxxxxxxxxxx> <maillist@xxxxxxxxxxxxxx>
+Josh Triplett <josh@xxxxxxxxxxxxxxxx> <josh@xxxxxxxxxxxxxxx>
+Josh Triplett <josh@xxxxxxxxxxxxxxxx> <josht@xxxxxxxxxx>
+Julian Phillips <julian@xxxxxxxxxxxxxxxxx> <jp3@xxxxxxxxxxxxxxxxx>
+Junio C Hamano <gitster@xxxxxxxxx> <gitster@xxxxxxxxx>
+Junio C Hamano <gitster@xxxxxxxxx> <junio@xxxxxxxxxxxxxxx>
+Junio C Hamano <gitster@xxxxxxxxx> <junio@xxxxxxxxxx>
+Junio C Hamano <gitster@xxxxxxxxx> <junio@xxxxxxxxx>
+Junio C Hamano <gitster@xxxxxxxxx> <junio@xxxxxxxxxxx>
+Junio C Hamano <gitster@xxxxxxxxx> <junkio@xxxxxxx>
+Junio C Hamano <gitster@xxxxxxxxx> <junkio@xxxxxxxxxxx>
+Kaartic Sivaraam <kaartic.sivaraam@xxxxxxxxx> <kaarticsivaraam91196@xxxxxxxxx>
+Karl Wiberg <kha@xxxxxxxxxxx> Karl  Hasselström
+Karl Wiberg <kha@xxxxxxxxxxx> <kha@xxxxxxxxxxxxxxxxxxxxxxxxx>
+Karsten Blees <blees@xxxxxxx> <karsten.blees@xxxxxxx>
+Karsten Blees <blees@xxxxxxx> <karsten.blees@xxxxxxxxx>
+Kay Sievers <kay.sievers@xxxxxxxx> <kay.sievers@xxxxxxx>
+Kay Sievers <kay.sievers@xxxxxxxx> <kay@mam.(none)>
+Kazuki Saitoh <ksaitoh560@xxxxxxxxx> kazuki saitoh <ksaitoh560@xxxxxxxxx>
+Keith Cascio <keith@xxxxxxxxxxx> <keith@xxxxxxxxxxx>
+Kent Engstrom <kent@xxxxxxxxxxxxxx>
+Kevin Leung <kevinlsk@xxxxxxxxx>
+Kirill Smelkov <kirr@xxxxxxxxxxxxxx> <kirr@xxxxxxxxxxxxxxxxxxx>
+Kirill Smelkov <kirr@xxxxxxxxxxxxxx> <kirr@xxxxxxxxxx>
+Knut Franke <Knut.Franke@xxxxxx> <k.franke@xxxxxxxxxxxxxxxxxxxx>
+Lars Doelle <lars.doelle@on-line ! de>
+Lars Doelle <lars.doelle@xxxxxxxxxx>
+Lars Noschinski <lars@xxxxxxxxxxxxxxxxxxxx> <lars.noschinski@xxxxxxxxxxxxxx>
+Li Hong <leehong@xxxxxxxxxx>
+Linus Arver <linus@xxxxxxxx> <linusa@xxxxxxxxxx>
+Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> <torvalds@xxxxxxxxxxxx>
+Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> <torvalds@xxxxxxxxxxx>
+Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> <torvalds@xxxxxxxx>
+Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> <torvalds@xxxxxxxxxxxxxxx.(none)>
+Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> <torvalds@xxxxxxxxxxxxxxx>
+Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx> <torvalds@xxxxxxxxxxxxxxxxxxxxxxxxxx>
+Lukas Sandström <luksan@xxxxxxxxx> <lukass@xxxxxxxxxxxxxxxx>
+Marc Khouzam <marc.khouzam@xxxxxxxxxxxx> <marc.khouzam@xxxxxxxxx>
+Marc-André Lureau <marcandre.lureau@xxxxxxxxx>
+Marco Costalba <mcostalba@xxxxxxxxx> <mcostalba@xxxxxxxx>
+Mark Levedahl <mdl123@xxxxxxxxxxx> <mlevedahl@xxxxxxxxx>
+Mark Rada <marada@xxxxxxxxxxxx>
+Martin Langhoff <martin@xxxxxxxxxx> <martin@xxxxxxxxxxxxxxx>
+Martin von Zweigbergk <martinvonz@xxxxxxxxx> <martin.von.zweigbergk@xxxxxxxxx>
+Masaya Suzuki <masayasuzuki@xxxxxxxxxx> <draftcode@xxxxxxxxx>
+Matheus Tavares <matheus.tavb@xxxxxxxxx> <matheus.bernardino@xxxxxx>
+Matt Draisey <matt@xxxxxxxxxx> <mattdraisey@xxxxxxxxxxxx>
+Matt Kraai <kraai@xxxxxxxxx> <matt.kraai@xxxxxxxxxxxxxx>
+Matt McCutchen <matt@xxxxxxxxxxxxxxxxx> <hashproduct@xxxxxxxxx>
+Matthias Kestenholz <matthias@xxxxxxxxxxx> <mk@xxxxxxxxxxx>
+Matthias Rüster <matthias.ruester@xxxxxxxxx> Matthias Ruester
+Matthias Urlichs <matthias@xxxxxxxxxx> <smurf@kiste.(none)>
+Matthias Urlichs <matthias@xxxxxxxxxx> <smurf@xxxxxxxxxxxxxx>
+Matthieu Moy <git@xxxxxxxxxxxxxxx> <Matthieu.Moy@xxxxxxx>
+Michael Coleman <tutufan@xxxxxxxxx>
+Michael J Gruber <git@xxxxxxxxx> <michaeljgruber+gmane@xxxxxxxxxxx>
+Michael J Gruber <git@xxxxxxxxx> <git@xxxxxxxxxxxxxxxxxxxx>
+Michael S. Tsirkin <mst@xxxxxxxxxx> <mst@xxxxxxxxxx>
+Michael S. Tsirkin <mst@xxxxxxxxxx> <mst@xxxxxxxxxxxxxx>
+Michael S. Tsirkin <mst@xxxxxxxxxx> <mst@xxxxxxxxxxxxxxxxxx>
+Michael W. Olson <mwolson@xxxxxxx>
+Michael Witten <mfwitten@xxxxxxxxx> <mfwitten@xxxxxxx>
+Michael Witten <mfwitten@xxxxxxxxx> <mfwitten@xxxxxxx>
+Michal Rokos <michal.rokos@xxxxxxxxxxx> <rokos@xxxxxxxxxxx>
+Michele Ballabio <barra_cuda@xxxxxxxxxxxx>
+Miklos Vajna <vmiklos@xxxxxxxxxxxxxx> <vmiklos@xxxxxxx>
+Namhyung Kim <namhyung@xxxxxxxxx> <namhyung.kim@xxxxxxx>
+Namhyung Kim <namhyung@xxxxxxxxx> <namhyung@xxxxxxxxxx>
+Nanako Shiraishi <nanako3@xxxxxxxxxxx> <nanako3@xxxxxxxxxxxxxx>
+Nanako Shiraishi <nanako3@xxxxxxxxxxx>
+Nelson Elhage <nelhage@xxxxxxx> <nelhage@xxxxxxx>
+Nelson Elhage <nelhage@xxxxxxx> <nelhage@xxxxxxxxxxx>
+Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx>
+Nick Stokoe <nick@xxxxxxxxxxxxxxxxxxx> Nick Woolley <nick@xxxxxxxxxxxxxxxxxxx>
+Nick Stokoe <nick@xxxxxxxxxxxxxxxxxxx> Nick Woolley <nickwoolley@xxxxxxxxxxx>
+Nicolas Morey-Chaisemartin <devel-git@xxxxxxxxxxxxxxxxxxxxxx> <nicolas.morey@xxxxxxx>
+Nicolas Morey-Chaisemartin <devel-git@xxxxxxxxxxxxxxxxxxxxxx> <nmorey@xxxxxxxxx>
+Nicolas Morey-Chaisemartin <devel-git@xxxxxxxxxxxxxxxxxxxxxx> <nicolas@xxxxxxxxxxxxxxxxxxxxxx>
+Nicolas Morey-Chaisemartin <devel-git@xxxxxxxxxxxxxxxxxxxxxx> <NMoreyChaisemartin@xxxxxxxx>
+Nicolas Morey-Chaisemartin <devel-git@xxxxxxxxxxxxxxxxxxxxxx> <nmoreychaisemartin@xxxxxxxx>
+Nicolas Sebrecht <nicolas.s.dev@xxxxxx> <ni.s@xxxxxxxxxxx>
+Orgad Shaneh <orgads@xxxxxxxxx> <orgad.shaneh@xxxxxxxxxxxxxx>
+Paolo Bonzini <bonzini@xxxxxxx> <paolo.bonzini@xxxxxxxxxxx>
+Pascal Obry <pascal@xxxxxxxx> <pascal.obry@xxxxxxxxx>
+Pascal Obry <pascal@xxxxxxxx> <pascal.obry@xxxxxxxxxx>
+Pat Notz <patnotz@xxxxxxxxx> <pknotz@xxxxxxxxxx>
+Patrick Steinhardt <ps@xxxxxx> <patrick.steinhardt@xxxxxxxx>
+Paul Mackerras <paulus@xxxxxxxxx> <paulus@dorrigo.(none)>
+Paul Mackerras <paulus@xxxxxxxxx> <paulus@pogo.(none)>
+Peter Baumann <waste.manager@xxxxxx> <Peter.B.Baumann@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
+Peter Baumann <waste.manager@xxxxxx> <siprbaum@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
+Peter Krefting <peter@xxxxxxxxxxxxxxxx> <peter@xxxxxxxxxxxxxxxx>
+Peter Krefting <peter@xxxxxxxxxxxxxxxx> <peter@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx>
+Petr Baudis <pasky@xxxxxx> <pasky@xxxxxxx>
+Petr Baudis <pasky@xxxxxx> <xpasky@machine>
+Phil Hord <hordp@xxxxxxxxx> <phil.hord@xxxxxxxxx>
+Philip Jägenstedt <philip@xxxxxxxxxx> <philip.jagenstedt@xxxxxxxxx>
+Philip Oakley <philipoakley@iee.email> <philipoakley@xxxxxxx> # secondary <philipoakley@xxxxxxxxxxxxx>
+Philipp A. Hartmann <pah@xxxxx> <ph@xxxxxxxx>
+Philippe Bruhat <book@xxxxxxxx>
+Ralf Thielow <ralf.thielow@xxxxxxxxx> <ralf.thielow@xxxxxxxxxxxxxx>
+Ramsay Jones <ramsay@xxxxxxxxxxxxxxxxxxxx> <ramsay@xxxxxxxxxxxxxxxxxxx>
+Ramkumar Ramachandra <r@xxxxxxxxxxxx> <artagnon@xxxxxxxxx>
+Randall S. Becker <randall.becker@xxxxxxxxxxxx> <rsbecker@xxxxxxxxxxxxx>
+René Scharfe <l.s.r@xxxxxx> <rene.scharfe@xxxxxxxxxxxxxx>
+René Scharfe <l.s.r@xxxxxx> Rene Scharfe
+Richard Hansen <rhansen@xxxxxxxxxxx> <hansenr@xxxxxxxxxx>
+Richard Hansen <rhansen@xxxxxxxxxxx> <rhansen@xxxxxxx>
+Robert Fitzsimons <robfitz@xxxxxxxx>
+Robert Shearman <robertshearman@xxxxxxxxx> <rob@xxxxxxxxxxxxxxx>
+Robert Zeh <robert.a.zeh@xxxxxxxxx>
+Robin Rosenberg <robin.rosenberg@xxxxxxxxxx> <robin.rosenberg.lists@xxxxxxxxxx>
+Rutger Nijlunsing <rutger.nijlunsing@xxxxxxxxx> <rutger@xxxxxxxxxx>
+Rutger Nijlunsing <rutger.nijlunsing@xxxxxxxxx> <git@xxxxxxxxxxxxx>
+Ryan Anderson <ryan@xxxxxxxxxxxxxx> <rda@xxxxxxxxxx>
+Salikh Zakirov <salikh.zakirov@xxxxxxxxx> <Salikh.Zakirov@xxxxxxxxx>
+Sam Vilain <sam@xxxxxxxxxx> <sam.vilain@xxxxxxxxxxxxxxx>
+Sam Vilain <sam@xxxxxxxxxx> sam@xxxxxxxxxx
+Santi Béjar <santi@xxxxxxxxxxx> <sbejar@xxxxxxxxx>
+Sean Estabrooks <seanlkml@xxxxxxxxxxxx>
+Sebastian Schuberth <sschuberth@xxxxxxxxx> <sschuberth@xxxxxxxxxxxxxxxxx>
+Seth Falcon <seth@xxxxxxxxxxxxxxx> <sfalcon@xxxxxxxxx>
+Shawn O. Pearce <spearce@xxxxxxxxxxx>
+Wei Shuyu <wsy@xxxxxxxxxx> Shuyu Wei
+Sidhant Sharma <tigerkid001@xxxxxxxxx> Sidhant Sharma [:tk]
+Simon Hausmann <hausmann@xxxxxxx> <simon@xxxxxx>
+Simon Hausmann <hausmann@xxxxxxx> <shausman@xxxxxxxxxxxxx>
+Stefan Beller <stefanbeller@xxxxxxxxx> <stefanbeller@xxxxxxxxxxxxxx>
+Stefan Beller <stefanbeller@xxxxxxxxx> <sbeller@xxxxxxxxxx>
+Stefan Naewe <stefan.naewe@xxxxxxxxx> <stefan.naewe@xxxxxxxxxxxxxxxxxxxx>
+Stefan Naewe <stefan.naewe@xxxxxxxxx> <stefan.naewe@xxxxxxxxxxxxxx>
+Stefan Sperling <stsp@xxxxxxxx> <stsp@xxxxxxxxx>
+Štěpán Němec <stepnem@xxxxxxxxx> <stepan.nemec@xxxxxxxxx>
+Stephen Boyd <bebarino@xxxxxxxxx> <sboyd@xxxxxxxxxxxxxx>
+Stephen P. Smith <ishchis2@xxxxxxxxx> <ischis2@xxxxxxx>
+Steven Drake <sdrake@xxxxxxxxxx> <sdrake@xxxxxxxxxx>
+Steven Grimm <koreth@xxxxxxxxxxxxx> <sgrimm@sgrimm-mbp.local>
+Steven Grimm <koreth@xxxxxxxxxxxxx> koreth@xxxxxxxxxxxxx
+Steven Walter <stevenrwalter@xxxxxxxxx> <swalter@xxxxxxxxxxx>
+Steven Walter <stevenrwalter@xxxxxxxxx> <swalter@xxxxxxxxxxxxxxxxxxxxxxxx>
+Sven Verdoolaege <skimo@xxxxxxxxxx> <Sven.Verdoolaege@xxxxxxxxxxxxxxxxx>
+Sven Verdoolaege <skimo@xxxxxxxxxx> <skimo@xxxxxxxx>
+SZEDER Gábor <szeder.dev@xxxxxxxxx> <szeder@xxxxxxxxxx>
+Tao Qingyun <taoqy@xxxxxxx> <845767657@xxxxxx>
+Tay Ray Chuan <rctay89@xxxxxxxxx>
+Ted Percival <ted@xxxxxxxxxx> <ted.percival@xxxxxxxxx>
+Theodore Ts'o <tytso@xxxxxxx>
+Thomas Ackermann <th.acker@xxxxxxxx> <th.acker66@xxxxxxxx>
+Thomas Rast <tr@xxxxxxxxxxxxx> <trast@xxxxxxxxxxxxxxx>
+Thomas Rast <tr@xxxxxxxxxxxxx> <trast@xxxxxxxxxxx>
+Thomas Rast <tr@xxxxxxxxxxxxx> <trast@xxxxxxxxxx>
+Timo Hirvonen <tihirvon@xxxxxxxxx> <tihirvon@xxxxxxxxxx>
+Toby Allsopp <Toby.Allsopp@xxxxxxxxxxxx> <toby.allsopp@xxxxxxxxxxxx>
+Tom Grennan <tmgrennan@xxxxxxxxx> <tgrennan@xxxxxxxxxxx>
+Tommi Virtanen <tv@xxxxxxxxxx> <tv@xxxxxxxxxx>
+Tommi Virtanen <tv@xxxxxxxxxx> <tv@xxxxxxx>
+Tommy Thorn <tommy-git@xxxxxxxx> <tt1729@xxxxxxxxx>
+Tony Luck <tony.luck@xxxxxxxxx>
+Tor Arne Vestbø <torarnv@xxxxxxxxx> <tavestbo@xxxxxxxxxxxxx>
+Trần Ngọc Quân <vnwildman@xxxxxxxxx> Tran Ngoc Quan <vnwildman@xxxxxxxxx>
+Trent Piepho <tpiepho@xxxxxxxxx> <tpiepho@xxxxxxxxxxxxx>
+Trent Piepho <tpiepho@xxxxxxxxx> <xyzzy@xxxxxxxxxxxxx>
+Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> <Uwe.Kleine-Koenig@xxxxxxxx>
+Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> <ukleinek@xxxxxxxxxxxxxxxxxxxxxxxxxx>
+Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> <uzeisberger@xxxxxxxxxxxxx>
+Uwe Kleine-König <u.kleine-koenig@xxxxxxxxxxxxxx> <zeisberg@xxxxxxxxxxxxxxxxxxxxxxxxxx>
+Ville Skyttä <ville.skytta@xxxxxx> <scop@xxxxxxxxxx>
+Vitaly "_Vi" Shukela <vi0oss@xxxxxxxxx> <public_vi@xxxxxx>
+Vitaly "_Vi" Shukela <vi0oss@xxxxxxxxx> Vitaly _Vi Shukela
+W. Trevor King <wking@xxxxxxxxxx> <wking@xxxxxxxxxx>
+William Pursell <bill.pursell@xxxxxxxxx>
+YONETANI Tomokazu <y0n3t4n1@xxxxxxxxx> <qhwt+git@xxxxxxxxxx>
+YONETANI Tomokazu <y0n3t4n1@xxxxxxxxx> <y0netan1@xxxxxxxxxxxxxxxx>
+YOSHIFUJI Hideaki <yoshfuji@xxxxxxxxxxxxxx>
+Yi-Jyun Pan <pan93412@xxxxxxxxx>
+# the two anonymous contributors are different persons:
+anonymous <linux@xxxxxxxxxxx>
+anonymous <linux@xxxxxxxxxxx>
+İsmail Dönmez <ismail@xxxxxxxxxxxxx>
diff --git a/.tsan-suppressions b/.tsan-suppressions
new file mode 100644
index 0000000000..5ba86d6845
--- /dev/null
+++ b/.tsan-suppressions
@@ -0,0 +1,16 @@
+# Suppressions for ThreadSanitizer (tsan).
+#
+# This file is used by setting the environment variable TSAN_OPTIONS to, e.g.,
+# "suppressions=$(pwd)/.tsan-suppressions". Observe that relative paths such as
+# ".tsan-suppressions" might not work.
+
+# A static variable is written to racily, but we always write the same value, so
+# in practice it (hopefully!) doesn't matter.
+race:^want_color$
+race:^transfer_debug$
+
+# A boolean value, which tells whether the replace_map has been initialized or
+# not, is read racily with an update. As this variable is written to only once,
+# and it's OK if the value change right after reading it, this shouldn't be a
+# problem.
+race:^lookup_replace_object$
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000000..e58917c50a
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,145 @@
+# Git Code of Conduct
+
+This code of conduct outlines our expectations for participants within
+the Git community, as well as steps for reporting unacceptable behavior.
+We are committed to providing a welcoming and inspiring community for
+all and expect our code of conduct to be honored. Anyone who violates
+this code of conduct may be banned from the community.
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, religion, or sexual identity
+and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+  and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the
+  overall community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or
+  advances of any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email
+  address, without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+git@xxxxxxxxxxxxxxxxx, or individually:
+
+  - Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx>
+  - Christian Couder <christian.couder@xxxxxxxxx>
+  - Junio C Hamano <gitster@xxxxxxxxx>
+  - Taylor Blau <me@xxxxxxxxxxxx>
+
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series
+of actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or
+permanent ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior,  harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within
+the community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.0, available at
+[https://www.contributor-covenant.org/version/2/0/code_of_conduct.html][v2.0].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq][FAQ]. Translations are available
+at [https://www.contributor-covenant.org/translations][translations].
+
+[homepage]: https://www.contributor-covenant.org
+[v2.0]: https://www.contributor-covenant.org/version/2/0/code_of_conduct.html
+[Mozilla CoC]: https://github.com/mozilla/diversity
+[FAQ]: https://www.contributor-covenant.org/faq
+[translations]: https://www.contributor-covenant.org/translations
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000000..536e55524d
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,360 @@
+
+ Note that the only valid version of the GPL as far as this project
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+
+ HOWEVER, in order to allow a migration to GPLv3 if that seems like
+ a good idea, I also ask that people involved with the project make
+ their preferences known. In particular, if you trust me to make that
+ decision, you might note so in your copyright message, ie something
+ like
+
+	This file is licensed under the GPL v2, or a later version
+	at the discretion of Linus.
+
+  might avoid issues. But we can also just decide to synchronize and
+  contact all copyright holders on record if/when the occasion arises.
+
+			Linus Torvalds
+
+----------------------------------------
+
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/Documentation/.gitattributes b/Documentation/.gitattributes
new file mode 100644
index 0000000000..ddb030137d
--- /dev/null
+++ b/Documentation/.gitattributes
@@ -0,0 +1 @@
+*.txt whitespace
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
new file mode 100644
index 0000000000..9f4bb3c4bf
--- /dev/null
+++ b/Documentation/.gitignore
@@ -0,0 +1,20 @@
+*.xml
+*.html
+*.[1-8]
+*.made
+*.texi
+*.pdf
+git.info
+gitman.info
+howto-index.txt
+doc.dep
+cmds-*.txt
+mergetools-*.txt
+SubmittingPatches.txt
+tmp-doc-diff/
+tmp-meson-diff/
+GIT-ASCIIDOCFLAGS
+/.build/
+/GIT-EXCLUDED-PROGRAMS
+/asciidoc.conf
+/asciidoctor-extensions.rb
diff --git a/Documentation/BreakingChanges.adoc b/Documentation/BreakingChanges.adoc
new file mode 100644
index 0000000000..27acff86db
--- /dev/null
+++ b/Documentation/BreakingChanges.adoc
@@ -0,0 +1,174 @@
+= Upcoming breaking changes
+
+The Git project aims to ensure backwards compatibility to the best extent
+possible. Minor releases will not break backwards compatibility unless there is
+a very strong reason to do so, like for example a security vulnerability.
+
+Regardless of that, due to the age of the Git project, it is only natural to
+accumulate a backlog of backwards-incompatible changes that will eventually be
+required to keep the project aligned with a changing world. These changes fall
+into several categories:
+
+* Changes to long established defaults.
+* Concepts that have been replaced with a superior design.
+* Concepts, commands, configuration or options that have been lacking in major
+  ways and that cannot be fixed and which will thus be removed without any
+  replacement.
+
+Explicitly not included in this list are fixes to minor bugs that may cause a
+change in user-visible behavior.
+
+The Git project irregularly releases breaking versions that deliberately break
+backwards compatibility with older versions. This is done to ensure that Git
+remains relevant, safe and maintainable going forward. The release cadence of
+breaking versions is typically measured in multiple years. We had the following
+major breaking releases in the past:
+
+* Git 1.6.0, released in August 2008.
+* Git 2.0, released in May 2014.
+
+We use <major>.<minor> release numbers these days, starting from Git 2.0. For
+future releases, our plan is to increment <major> in the release number when we
+make the next breaking release. Before Git 2.0, the release numbers were
+1.<major>.<minor> with the intention to increment <major> for "usual" breaking
+releases, reserving the jump to Git 2.0 for really large backward-compatibility
+breaking changes.
+
+The intent of this document is to track upcoming deprecations for future
+breaking releases. Furthermore, this document also tracks what will _not_ be
+deprecated. This is done such that the outcome of discussions document both
+when the discussion favors deprecation, but also when it rejects a deprecation.
+
+Items should have a clear summary of the reasons why we do or do not want to
+make the described change that can be easily understood without having to read
+the mailing list discussions. If there are alternatives to the changed feature,
+those alternatives should be pointed out to our users.
+
+All items should be accompanied by references to relevant mailing list threads
+where the deprecation was discussed. These references use message-IDs, which
+can visited via
+
+  https://lore.kernel.org/git/$message_id/
+
+to see the message and its surrounding discussion. Such a reference is there to
+make it easier for you to find how the project reached consensus on the
+described item back then.
+
+This is a living document as the environment surrounding the project changes
+over time. If circumstances change, an earlier decision to deprecate or change
+something may need to be revisited from time to time. So do not take items on
+this list to mean "it is settled, do not waste our time bringing it up again".
+
+== Procedure
+
+Discussing the desire to make breaking changes, declaring that breaking
+changes are made at a certain version boundary, and recording these
+decisions in this document, are necessary but not sufficient.
+Because such changes are expected to be numerous, and the design and
+implementation of them are expected to span over time, they have to
+be deployable trivially at such a version boundary.
+
+The breaking changes MUST be guarded with the a compile-time switch,
+WITH_BREAKING_CHANGES, to help this process.  When built with it,
+the resulting Git binary together with its documentation would
+behave as if these breaking changes slated for the next big version
+boundary are already in effect.  We may also want to have a CI job
+or two to exercise the work-in-progress version of Git with these
+breaking changes.
+
+
+== Git 3.0
+
+The following subsections document upcoming breaking changes for Git 3.0. There
+is no planned release date for this breaking version yet.  The early
+adopter configuration used for changes for this release is `feature.git3`.
+
+Proposed changes and removals only include items which are "ready" to be done.
+In other words, this is not supposed to be a wishlist of features that should
+be changed to or replaced in case the alternative was implemented already.
+
+=== Changes
+
+* The default hash function for new repositories will be changed from "sha1"
+  to "sha256". SHA-1 has been deprecated by NIST in 2011 and is nowadays
+  recommended against in FIPS 140-2 and similar certifications. Furthermore,
+  there are practical attacks on SHA-1 that weaken its cryptographic properties:
++
+  ** The SHAppening (2015). The first demonstration of a practical attack
+     against SHA-1 with 2^57 operations.
+  ** SHAttered (2017). Generation of two valid PDF files with 2^63 operations.
+  ** Birthday-Near-Collision (2019). This attack allows for chosen prefix
+     attacks with 2^68 operations.
+  ** Shambles (2020). This attack allows for chosen prefix attacks with 2^63
+     operations.
++
+While we have protections in place against known attacks, it is expected
+that more attacks against SHA-1 will be found by future research. Paired
+with the ever-growing capability of hardware, it is only a matter of time
+before SHA-1 will be considered broken completely. We want to be prepared
+and will thus change the default hash algorithm to "sha256" for newly
+initialized repositories.
++
+An important requirement for this change is that the ecosystem is ready to
+support the "sha256" object format. This includes popular Git libraries,
+applications and forges.
++
+There is no plan to deprecate the "sha1" object format at this point in time.
++
+Cf. <2f5de416-04ba-c23d-1e0b-83bb655829a7@xxxxxxxxxxx>,
+<20170223155046.e7nxivfwqqoprsqj@LykOS.localdomain>,
+<CA+EOSBncr=4a4d8n9xS4FNehyebpmX8JiUwCsXD47EQDE+DiUQ@xxxxxxxxxxxxxx>.
+
+=== Removals
+
+* Support for grafting commits has long been superseded by git-replace(1).
+  Grafts are inferior to replacement refs:
++
+  ** Grafts are a local-only mechanism and cannot be shared across
+     repositories.
+  ** Grafts can lead to hard-to-diagnose problems when transferring objects
+     between repositories.
++
+The grafting mechanism has been marked as outdated since e650d0643b (docs: mark
+info/grafts as outdated, 2014-03-05) and will be removed.
++
+Cf. <20140304174806.GA11561@xxxxxxxxxxxxxxxxxxxxx>.
+
+* The git-pack-redundant(1) command can be used to remove redundant pack files.
+  The subcommand is unusably slow and the reason why nobody reports it as a
+  performance bug is suspected to be the absence of users. We have nominated
+  the command for removal and have started to emit a user-visible warning in
+  c3b58472be (pack-redundant: gauge the usage before proposing its removal,
+  2020-08-25) whenever the command is executed.
++
+So far there was a single complaint about somebody still using the command, but
+that complaint did not cause us to reverse course. On the contrary, we have
+doubled down on the deprecation and starting with 4406522b76 (pack-redundant:
+escalate deprecation warning to an error, 2023-03-23), the command dies unless
+the user passes the `--i-still-use-this` option.
++
+There have not been any subsequent complaints, so this command will finally be
+removed.
++
+Cf. <xmqq1rjuz6n3.fsf_-_@xxxxxxxxxxxxxxxxxxxxxx>,
+    <CAKvOHKAFXQwt4D8yUCCkf_TQL79mYaJ=KAKhtpDNTvHJFuX1NA@xxxxxxxxxxxxxx>,
+    <20230323204047.GA9290@xxxxxxxxxxxxxxxxxxxxxxx>,
+
+== Superseded features that will not be deprecated
+
+Some features have gained newer replacements that aim to improve the design in
+certain ways. The fact that there is a replacement does not automatically mean
+that the old way of doing things will eventually be removed. This section tracks
+those features with newer alternatives.
+
+* The features git-checkout(1) offers are covered by the pair of commands
+  git-restore(1) and git-switch(1). Because the use of git-checkout(1) is still
+  widespread, and it is not expected that this will change anytime soon, all
+  three commands will stay.
++
+This decision may get revisited in case we ever figure out that there are
+almost no users of any of the commands anymore.
++
+Cf. <xmqqttjazwwa.fsf@gitster.g>,
+<xmqqleeubork.fsf@gitster.g>,
+<112b6568912a6de6672bf5592c3a718e@xxxxxxxxxxx>.
diff --git a/Documentation/CodingGuidelines b/Documentation/CodingGuidelines
new file mode 100644
index 0000000000..ba047ed224
--- /dev/null
+++ b/Documentation/CodingGuidelines
@@ -0,0 +1,947 @@
+Like other projects, we also have some guidelines for our code.  For
+Git in general, a few rough rules are:
+
+ - Most importantly, we never say "It's in POSIX; we'll happily
+   ignore your needs should your system not conform to it."
+   We live in the real world.
+
+ - However, we often say "Let's stay away from that construct,
+   it's not even in POSIX".
+
+ - In spite of the above two rules, we sometimes say "Although
+   this is not in POSIX, it (is so convenient | makes the code
+   much more readable | has other good characteristics) and
+   practically all the platforms we care about support it, so
+   let's use it".
+
+   Again, we live in the real world, and it is sometimes a
+   judgement call, the decision based more on real world
+   constraints people face than what the paper standard says.
+
+ - Fixing style violations while working on a real change as a
+   preparatory clean-up step is good, but otherwise avoid useless code
+   churn for the sake of conforming to the style.
+
+   "Once it _is_ in the tree, it's not really worth the patch noise to
+   go and fix it up."
+   Cf. https://lore.kernel.org/all/20100126160632.3bdbe172.akpm@xxxxxxxxxxxxxxxxxxxx/
+
+ - Log messages to explain your changes are as important as the
+   changes themselves.  Clearly written code and in-code comments
+   explain how the code works and what is assumed from the surrounding
+   context.  The log messages explain what the changes wanted to
+   achieve and why the changes were necessary (more on this in the
+   accompanying SubmittingPatches document).
+
+Make your code readable and sensible, and don't try to be clever.
+
+As for more concrete guidelines, just imitate the existing code
+(this is a good guideline, no matter which project you are
+contributing to). It is always preferable to match the _local_
+convention. New code added to Git suite is expected to match
+the overall style of existing code. Modifications to existing
+code are expected to match the style the surrounding code already
+uses (even if it doesn't match the overall style of existing code).
+
+But if you must have a list of rules, here are some language
+specific ones. Note that Documentation/ToolsForGit.txt document
+has a collection of tips to help you use some external tools
+to conform to these guidelines.
+
+For shell scripts specifically (not exhaustive):
+
+ - We use tabs for indentation.
+
+ - Case arms are indented at the same depth as case and esac lines,
+   like this:
+
+	case "$variable" in
+	pattern1)
+		do this
+		;;
+	pattern2)
+		do that
+		;;
+	esac
+
+ - Redirection operators should be written with space before, but no
+   space after them.  In other words, write 'echo test >"$file"'
+   instead of 'echo test> $file' or 'echo test > $file'.  Note that
+   even though it is not required by POSIX to double-quote the
+   redirection target in a variable (as shown above), our code does so
+   because some versions of bash issue a warning without the quotes.
+
+	(incorrect)
+	cat hello > world < universe
+	echo hello >$world
+
+	(correct)
+	cat hello >world <universe
+	echo hello >"$world"
+
+ - We prefer $( ... ) for command substitution; unlike ``, it
+   properly nests.  It should have been the way Bourne spelled
+   it from day one, but unfortunately isn't.
+
+ - If you want to find out if a command is available on the user's
+   $PATH, you should use 'type <command>', instead of 'which <command>'.
+   The output of 'which' is not machine parsable and its exit code
+   is not reliable across platforms.
+
+ - We use POSIX compliant parameter substitutions and avoid bashisms;
+   namely:
+
+   - We use ${parameter-word} and its [-=?+] siblings, and their
+     colon'ed "unset or null" form.
+
+   - We use ${parameter#word} and its [#%] siblings, and their
+     doubled "longest matching" form.
+
+   - No "Substring Expansion" ${parameter:offset:length}.
+
+   - No shell arrays.
+
+   - No pattern replacement ${parameter/pattern/string}.
+
+ - We use Arithmetic Expansion $(( ... )).
+
+ - We do not use Process Substitution <(list) or >(list).
+
+ - Do not write control structures on a single line with semicolon.
+   "then" should be on the next line for if statements, and "do"
+   should be on the next line for "while" and "for".
+
+	(incorrect)
+	if test -f hello; then
+		do this
+	fi
+
+	(correct)
+	if test -f hello
+	then
+		do this
+	fi
+
+ - If a command sequence joined with && or || or | spans multiple
+   lines, put each command on a separate line and put && and || and |
+   operators at the end of each line, rather than the start. This
+   means you don't need to use \ to join lines, since the above
+   operators imply the sequence isn't finished.
+
+	(incorrect)
+	grep blob verify_pack_result \
+	| awk -f print_1.awk \
+	| sort >actual &&
+	...
+
+	(correct)
+	grep blob verify_pack_result |
+	awk -f print_1.awk |
+	sort >actual &&
+	...
+
+ - We prefer "test" over "[ ... ]".
+
+ - We do not write the noiseword "function" in front of shell
+   functions.
+
+ - We prefer a space between the function name and the parentheses,
+   and no space inside the parentheses. The opening "{" should also
+   be on the same line.
+
+	(incorrect)
+	my_function(){
+		...
+
+	(correct)
+	my_function () {
+		...
+
+ - As to use of grep, stick to a subset of BRE (namely, no \{m,n\},
+   [::], [==], or [..]) for portability.
+
+   - We do not use \{m,n\};
+
+   - We do not use ? or + (which are \{0,1\} and \{1,\}
+     respectively in BRE) but that goes without saying as these
+     are ERE elements not BRE (note that \? and \+ are not even part
+     of BRE -- making them accessible from BRE is a GNU extension).
+
+ - Use Git's gettext wrappers in git-sh-i18n to make the user
+   interface translatable. See "Marking strings for translation" in
+   po/README.
+
+ - We do not write our "test" command with "-a" and "-o" and use "&&"
+   or "||" to concatenate multiple "test" commands instead, because
+   the use of "-a/-o" is often error-prone.  E.g.
+
+     test -n "$x" -a "$a" = "$b"
+
+   is buggy and breaks when $x is "=", but
+
+     test -n "$x" && test "$a" = "$b"
+
+   does not have such a problem.
+
+ - Even though "local" is not part of POSIX, we make heavy use of it
+   in our test suite.  We do not use it in scripted Porcelains, and
+   hopefully nobody starts using "local" before all shells that matter
+   support it (notably, ksh from AT&T Research does not support it yet).
+
+ - Some versions of shell do not understand "export variable=value",
+   so we write "variable=value" and then "export variable" on two
+   separate lines.
+
+ - Some versions of dash have broken variable assignment when prefixed
+   with "local", "export", and "readonly", in that the value to be
+   assigned goes through field splitting at $IFS unless quoted.
+
+	(incorrect)
+	local variable=$value
+	local variable=$(command args)
+
+	(correct)
+	local variable="$value"
+	local variable="$(command args)"
+
+ - The common construct
+
+	VAR=VAL command args
+
+   to temporarily set and export environment variable VAR only while
+   "command args" is running is handy, but this triggers an
+   unspecified behaviour according to POSIX when used for a command
+   that is not an external command (like shell functions).  Indeed,
+   dash 0.5.10.2-6 on Ubuntu 20.04, /bin/sh on FreeBSD 13, and AT&T
+   ksh all make a temporary assignment without exporting the variable,
+   in such a case.  As it does not work portably across shells, do not
+   use this syntax for shell functions.  A common workaround is to do
+   an explicit export in a subshell, like so:
+
+	(incorrect)
+	VAR=VAL func args
+
+	(correct)
+	(
+		VAR=VAL &&
+		export VAR &&
+		func args
+	)
+
+   but be careful that the effect "func" makes to the variables in the
+   current shell will be lost across the subshell boundary.
+
+ - Use octal escape sequences (e.g. "\302\242"), not hexadecimal (e.g.
+   "\xc2\xa2") in printf format strings, since hexadecimal escape
+   sequences are not portable.
+
+
+For C programs:
+
+ - We use tabs to indent, and interpret tabs as taking up to
+   8 spaces.
+
+ - Nested C preprocessor directives are indented after the hash by one
+   space per nesting level.
+
+	#if FOO
+	# include <foo.h>
+	# if BAR
+	#  include <bar.h>
+	# endif
+	#endif
+
+ - We try to keep to at most 80 characters per line.
+
+ - As a Git developer we assume you have a reasonably modern compiler
+   and we recommend you to enable the DEVELOPER makefile knob to
+   ensure your patch is clear of all compiler warnings we care about,
+   by e.g. "echo DEVELOPER=1 >>config.mak".
+
+ - When using DEVELOPER=1 mode, you may see warnings from the compiler
+   like "error: unused parameter 'foo' [-Werror=unused-parameter]",
+   which indicates that a function ignores its argument. If the unused
+   parameter can't be removed (e.g., because the function is used as a
+   callback and has to match a certain interface), you can annotate
+   the individual parameters with the UNUSED (or MAYBE_UNUSED)
+   keyword, like "int foo UNUSED".
+
+ - We try to support a wide range of C compilers to compile Git with,
+   including old ones.  As of Git v2.35.0 Git requires C99 (we check
+   "__STDC_VERSION__"). You should not use features from a newer C
+   standard, even if your compiler groks them.
+
+   New C99 features have been phased in gradually, if something's new
+   in C99 but not used yet don't assume that it's safe to use, some
+   compilers we target have only partial support for it. These are
+   considered safe to use:
+
+   . since around 2007 with 2b6854c863a, we have been using
+     initializer elements which are not computable at load time. E.g.:
+
+	const char *args[] = { "constant", variable, NULL };
+
+   . since early 2012 with e1327023ea, we have been using an enum
+     definition whose last element is followed by a comma.  This, like
+     an array initializer that ends with a trailing comma, can be used
+     to reduce the patch noise when adding a new identifier at the end.
+
+   . since mid 2017 with cbc0f81d, we have been using designated
+     initializers for struct (e.g. "struct t v = { .val = 'a' };").
+
+   . since mid 2017 with 512f41cf, we have been using designated
+     initializers for array (e.g. "int array[10] = { [5] = 2 }").
+
+   . since early 2021 with 765dc168882, we have been using variadic
+     macros, mostly for printf-like trace and debug macros.
+
+   . since late 2021 with 44ba10d6, we have had variables declared in
+     the for loop "for (int i = 0; i < 10; i++)".
+
+   New C99 features that we cannot use yet:
+
+   . %z and %zu as a printf() argument for a size_t (the %z being for
+     the POSIX-specific ssize_t). Instead you should use
+     printf("%"PRIuMAX, (uintmax_t)v).  These days the MSVC version we
+     rely on supports %z, but the C library used by MinGW does not.
+
+   . Shorthand like ".a.b = *c" in struct initializations is known to
+     trip up an older IBM XLC version, use ".a = { .b = *c }" instead.
+     See the 33665d98 (reftable: make assignments portable to AIX xlc
+     v12.01, 2022-03-28).
+
+ - Variables have to be declared at the beginning of the block, before
+   the first statement (i.e. -Wdeclaration-after-statement).  It is
+   encouraged to have a blank line between the end of the declarations
+   and the first statement in the block.
+
+ - NULL pointers shall be written as NULL, not as 0.
+
+ - When declaring pointers, the star sides with the variable
+   name, i.e. "char *string", not "char* string" or
+   "char * string".  This makes it easier to understand code
+   like "char *string, c;".
+
+ - Use whitespace around operators and keywords, but not inside
+   parentheses and not around functions. So:
+
+        while (condition)
+		func(bar + 1);
+
+   and not:
+
+        while( condition )
+		func (bar+1);
+
+ - A binary operator (other than ",") and ternary conditional "?:"
+   have a space on each side of the operator to separate it from its
+   operands.  E.g. "A + 1", not "A+1".
+
+ - A unary operator (other than "." and "->") have no space between it
+   and its operand.  E.g. "(char *)ptr", not "(char *) ptr".
+
+ - Do not explicitly compare an integral value with constant 0 or '\0',
+   or a pointer value with constant NULL.  For instance, to validate that
+   counted array <ptr, cnt> is initialized but has no elements, write:
+
+	if (!ptr || cnt)
+		BUG("empty array expected");
+
+   and not:
+
+	if (ptr == NULL || cnt != 0);
+		BUG("empty array expected");
+
+ - We avoid using braces unnecessarily.  I.e.
+
+	if (bla) {
+		x = 1;
+	}
+
+   is frowned upon. But there are a few exceptions:
+
+	- When the statement extends over a few lines (e.g., a while loop
+	  with an embedded conditional, or a comment). E.g.:
+
+		while (foo) {
+			if (x)
+				one();
+			else
+				two();
+		}
+
+		if (foo) {
+			/*
+			 * This one requires some explanation,
+			 * so we're better off with braces to make
+			 * it obvious that the indentation is correct.
+			 */
+			doit();
+		}
+
+	- When there are multiple arms to a conditional and some of them
+	  require braces, enclose even a single line block in braces for
+	  consistency. E.g.:
+
+		if (foo) {
+			doit();
+		} else {
+			one();
+			two();
+			three();
+		}
+
+ - We try to avoid assignments in the condition of an "if" statement.
+
+ - Try to make your code understandable.  You may put comments
+   in, but comments invariably tend to stale out when the code
+   they were describing changes.  Often splitting a function
+   into two makes the intention of the code much clearer.
+
+ - Multi-line comments include their delimiters on separate lines from
+   the text.  E.g.
+
+	/*
+	 * A very long
+	 * multi-line comment.
+	 */
+
+   Note however that a comment that explains a translatable string to
+   translators uses a convention of starting with a magic token
+   "TRANSLATORS: ", e.g.
+
+	/*
+	 * TRANSLATORS: here is a comment that explains the string to
+	 * be translated, that follows immediately after it.
+	 */
+	_("Here is a translatable string explained by the above.");
+
+ - Double negation is often harder to understand than no negation
+   at all.
+
+ - There are two schools of thought when it comes to comparison,
+   especially inside a loop. Some people prefer to have the less stable
+   value on the left hand side and the more stable value on the right hand
+   side, e.g. if you have a loop that counts variable i down to the
+   lower bound,
+
+	while (i > lower_bound) {
+		do something;
+		i--;
+	}
+
+   Other people prefer to have the textual order of values match the
+   actual order of values in their comparison, so that they can
+   mentally draw a number line from left to right and place these
+   values in order, i.e.
+
+	while (lower_bound < i) {
+		do something;
+		i--;
+	}
+
+   Both are valid, and we use both.  However, the more "stable" the
+   stable side becomes, the more we tend to prefer the former
+   (comparison with a constant, "i > 0", is an extreme example).
+   Just do not mix styles in the same part of the code and mimic
+   existing styles in the neighbourhood.
+
+ - There are two schools of thought when it comes to splitting a long
+   logical line into multiple lines.  Some people push the second and
+   subsequent lines far enough to the right with tabs and align them:
+
+        if (the_beginning_of_a_very_long_expression_that_has_to ||
+		span_more_than_a_single_line_of ||
+		the_source_text) {
+                ...
+
+   while other people prefer to align the second and the subsequent
+   lines with the column immediately inside the opening parenthesis,
+   with tabs and spaces, following our "tabstop is always a multiple
+   of 8" convention:
+
+        if (the_beginning_of_a_very_long_expression_that_has_to ||
+	    span_more_than_a_single_line_of ||
+	    the_source_text) {
+                ...
+
+   Both are valid, and we use both.  Again, just do not mix styles in
+   the same part of the code and mimic existing styles in the
+   neighbourhood.
+
+ - When splitting a long logical line, some people change line before
+   a binary operator, so that the result looks like a parse tree when
+   you turn your head 90-degrees counterclockwise:
+
+        if (the_beginning_of_a_very_long_expression_that_has_to
+	    || span_more_than_a_single_line_of_the_source_text) {
+
+   while other people prefer to leave the operator at the end of the
+   line:
+
+        if (the_beginning_of_a_very_long_expression_that_has_to ||
+	    span_more_than_a_single_line_of_the_source_text) {
+
+   Both are valid, but we tend to use the latter more, unless the
+   expression gets fairly complex, in which case the former tends to
+   be easier to read.  Again, just do not mix styles in the same part
+   of the code and mimic existing styles in the neighbourhood.
+
+ - When splitting a long logical line, with everything else being
+   equal, it is preferable to split after the operator at higher
+   level in the parse tree.  That is, this is more preferable:
+
+	if (a_very_long_variable * that_is_used_in +
+	    a_very_long_expression) {
+		...
+
+   than
+
+	if (a_very_long_variable *
+	    that_is_used_in + a_very_long_expression) {
+		...
+
+ - Some clever tricks, like using the !! operator with arithmetic
+   constructs, can be extremely confusing to others.  Avoid them,
+   unless there is a compelling reason to use them.
+
+ - Use the API.  No, really.  We have a strbuf (variable length
+   string), several arrays with the ALLOC_GROW() macro, a
+   string_list for sorted string lists, a hash map (mapping struct
+   objects) named "struct decorate", amongst other things.
+
+ - When you come up with an API, document its functions and structures
+   in the header file that exposes the API to its callers. Use what is
+   in "strbuf.h" as a model for the appropriate tone and level of
+   detail.
+
+ - The first #include in C files, except in platform specific compat/
+   implementations and sha1dc/, must be <git-compat-util.h>.  This
+   header file insulates other header files and source files from
+   platform differences, like which system header files must be
+   included in what order, and what C preprocessor feature macros must
+   be defined to trigger certain features we expect out of the system.
+   A collorary to this is that C files should not directly include
+   system header files themselves.
+
+   There are some exceptions, because certain group of files that
+   implement an API all have to include the same header file that
+   defines the API and it is convenient to include <git-compat-util.h>
+   there.  Namely:
+
+   - the implementation of the built-in commands in the "builtin/"
+     directory that include "builtin.h" for the cmd_foo() prototype
+     definition,
+
+   - the test helper programs in the "t/helper/" directory that include
+     "t/helper/test-tool.h" for the cmd__foo() prototype definition,
+
+   - the xdiff implementation in the "xdiff/" directory that includes
+     "xdiff/xinclude.h" for the xdiff machinery internals,
+
+   - the unit test programs in "t/unit-tests/" directory that include
+     "t/unit-tests/test-lib.h" that gives them the unit-tests
+     framework, and
+
+   - the source files that implement reftable in the "reftable/"
+     directory that include "reftable/system.h" for the reftable
+     internals,
+
+   are allowed to assume that they do not have to include
+   <git-compat-util.h> themselves, as it is included as the first
+   '#include' in these header files.  These headers must be the first
+   header file to be "#include"d in them, though.
+
+ - A C file must directly include the header files that declare the
+   functions and the types it uses, except for the functions and types
+   that are made available to it by including one of the header files
+   it must include by the previous rule.
+
+ - If you are planning a new command, consider writing it in shell
+   or perl first, so that changes in semantics can be easily
+   changed and discussed.  Many Git commands started out like
+   that, and a few are still scripts.
+
+ - Avoid introducing a new dependency into Git. This means you
+   usually should stay away from scripting languages not already
+   used in the Git core command set (unless your command is clearly
+   separate from it, such as an importer to convert random-scm-X
+   repositories to Git).
+
+ - When we pass <string, length> pair to functions, we should try to
+   pass them in that order.
+
+ - Use Git's gettext wrappers to make the user interface
+   translatable. See "Marking strings for translation" in po/README.
+
+ - Variables and functions local to a given source file should be marked
+   with "static". Variables that are visible to other source files
+   must be declared with "extern" in header files. However, function
+   declarations should not use "extern", as that is already the default.
+
+ - You can launch gdb around your program using the shorthand GIT_DEBUGGER.
+   Run `GIT_DEBUGGER=1 ./bin-wrappers/git foo` to simply use gdb as is, or
+   run `GIT_DEBUGGER="<debugger> <debugger-args>" ./bin-wrappers/git foo` to
+   use your own debugger and arguments. Example: `GIT_DEBUGGER="ddd --gdb"
+   ./bin-wrappers/git log` (See `bin-wrappers/wrap-for-bin.sh`.)
+
+ - The primary data structure that a subsystem 'S' deals with is called
+   `struct S`. Functions that operate on `struct S` are named
+   `S_<verb>()` and should generally receive a pointer to `struct S` as
+   first parameter. E.g.
+
+	struct strbuf;
+
+	void strbuf_add(struct strbuf *buf, ...);
+
+	void strbuf_reset(struct strbuf *buf);
+
+    is preferred over:
+
+	struct strbuf;
+
+	void add_string(struct strbuf *buf, ...);
+
+	void reset_strbuf(struct strbuf *buf);
+
+ - There are several common idiomatic names for functions performing
+   specific tasks on a structure `S`:
+
+    - `S_init()` initializes a structure without allocating the
+      structure itself.
+
+    - `S_release()` releases a structure's contents without freeing the
+      structure.
+
+    - `S_clear()` is equivalent to `S_release()` followed by `S_init()`
+      such that the structure is directly usable after clearing it. When
+      `S_clear()` is provided, `S_init()` shall not allocate resources
+      that need to be released again.
+
+    - `S_free()` releases a structure's contents and frees the
+      structure.
+
+ - Function names should be clear and descriptive, accurately reflecting
+   their purpose or behavior. Arbitrary suffixes that do not add meaningful
+   context can lead to confusion, particularly for newcomers to the codebase.
+
+   Historically, the '_1' suffix has been used in situations where:
+
+   - A function handles one element among a group that requires similar
+     processing.
+   - A recursive function has been separated from its setup phase.
+
+   The '_1' suffix can be used as a concise way to indicate these specific
+   cases. However, it is recommended to find a more descriptive name wherever
+   possible to improve the readability and maintainability of the code.
+
+For Perl programs:
+
+ - Most of the C guidelines above apply.
+
+ - We try to support Perl 5.8.1 and later ("use Perl 5.008001").
+
+ - use strict and use warnings are strongly preferred.
+
+ - Don't overuse statement modifiers unless using them makes the
+   result easier to follow.
+
+	... do something ...
+	do_this() unless (condition);
+        ... do something else ...
+
+   is more readable than:
+
+	... do something ...
+	unless (condition) {
+		do_this();
+	}
+        ... do something else ...
+
+   *only* when the condition is so rare that do_this() will be almost
+   always called.
+
+ - We try to avoid assignments inside "if ()" conditions.
+
+ - Learn and use Git.pm if you need that functionality.
+
+For Python scripts:
+
+ - We follow PEP-8 (https://peps.python.org/pep-0008/).
+
+ - As a minimum, we aim to be compatible with Python 2.7.
+
+ - Where required libraries do not restrict us to Python 2, we try to
+   also be compatible with Python 3.1 and later.
+
+
+Program Output
+
+ We make a distinction between a Git command's primary output and
+ output which is merely chatty feedback (for instance, status
+ messages, running transcript, or progress display), as well as error
+ messages. Roughly speaking, a Git command's primary output is that
+ which one might want to capture to a file or send down a pipe; its
+ chatty output should not interfere with these use-cases.
+
+ As such, primary output should be sent to the standard output stream
+ (stdout), and chatty output should be sent to the standard error
+ stream (stderr). Examples of commands which produce primary output
+ include `git log`, `git show`, and `git branch --list` which generate
+ output on the stdout stream.
+
+ Not all Git commands have primary output; this is often true of
+ commands whose main function is to perform an action. Some action
+ commands are silent, whereas others are chatty. An example of a
+ chatty action commands is `git clone` with its "Cloning into
+ '<path>'..." and "Checking connectivity..." status messages which it
+ sends to the stderr stream.
+
+ Error messages from Git commands should always be sent to the stderr
+ stream.
+
+
+Error Messages
+
+ - Do not end a single-sentence error message with a full stop.
+
+ - Do not capitalize the first word, only because it is the first word
+   in the message ("unable to open '%s'", not "Unable to open '%s'").  But
+   "SHA-3 not supported" is fine, because the reason the first word is
+   capitalized is not because it is at the beginning of the sentence,
+   but because the word would be spelled in capital letters even when
+   it appeared in the middle of the sentence.
+
+ - Say what the error is first ("cannot open '%s'", not "%s: cannot open").
+
+ - Enclose the subject of an error inside a pair of single quotes,
+   e.g. `die(_("unable to open '%s'"), path)`.
+
+ - Unless there is a compelling reason not to, error messages from
+   porcelain commands should be marked for translation, e.g.
+   `die(_("bad revision %s"), revision)`.
+
+ - Error messages from the plumbing commands are sometimes meant for
+   machine consumption and should not be marked for translation,
+   e.g., `die("bad revision %s", revision)`.
+
+ - BUG("message") are for communicating the specific error to developers,
+   thus should not be translated.
+
+
+Externally Visible Names
+
+ - For configuration variable names, follow the existing convention:
+
+   . The section name indicates the affected subsystem.
+
+   . The subsection name, if any, indicates which of an unbounded set
+     of things to set the value for.
+
+   . The variable name describes the effect of tweaking this knob.
+
+   The section and variable names that consist of multiple words are
+   formed by concatenating the words without punctuation marks (e.g. `-`),
+   and are broken using bumpyCaps in documentation as a hint to the
+   reader.
+
+   When choosing the variable namespace, do not use variable name for
+   specifying possibly unbounded set of things, most notably anything
+   an end user can freely come up with (e.g. branch names).  Instead,
+   use subsection names or variable values, like the existing variable
+   branch.<name>.description does.
+
+
+Writing Documentation:
+
+ Most (if not all) of the documentation pages are written in the
+ AsciiDoc format in *.txt files (e.g. Documentation/git.txt), and
+ processed into HTML and manpages (e.g. git.html and git.1 in the
+ same directory).
+
+ The documentation liberally mixes US and UK English (en_US/UK)
+ norms for spelling and grammar, which is somewhat unfortunate.
+ In an ideal world, it would have been better if it consistently
+ used only one and not the other, and we would have picked en_US
+ (if you wish to correct the English of some of the existing
+ documentation, please see the documentation-related advice in the
+ Documentation/SubmittingPatches file).
+
+ In order to ensure the documentation is inclusive, avoid assuming
+ that an unspecified example person is male or female, and think
+ twice before using "he", "him", "she", or "her".  Here are some
+ tips to avoid use of gendered pronouns:
+
+  - Prefer succinctness and matter-of-factly describing functionality
+    in the abstract.  E.g.
+
+     `--short`:: Emit output in the short-format.
+
+    and avoid something like these overly verbose alternatives:
+
+     `--short`:: Use this to emit output in the short-format.
+     `--short`:: You can use this to get output in the short-format.
+     `--short`:: A user who prefers shorter output could....
+     `--short`:: Should a person and/or program want shorter output, he
+                 she/they/it can...
+
+    This practice often eliminates the need to involve human actors in
+    your description, but it is a good practice regardless of the
+    avoidance of gendered pronouns.
+
+  - When it becomes awkward to stick to this style, prefer "you" when
+    addressing the hypothetical user, and possibly "we" when
+    discussing how the program might react to the user.  E.g.
+
+      You can use this option instead of `--xyz`, but we might remove
+      support for it in future versions.
+
+    while keeping in mind that you can probably be less verbose, e.g.
+
+      Use this instead of `--xyz`. This option might be removed in future
+      versions.
+
+  - If you still need to refer to an example person that is
+    third-person singular, you may resort to "singular they" to avoid
+    "he/she/him/her", e.g.
+
+      A contributor asks their upstream to pull from them.
+
+    Note that this sounds ungrammatical and unnatural to those who
+    learned that "they" is only used for third-person plural, e.g.
+    those who learn English as a second language in some parts of the
+    world.
+
+ Every user-visible change should be reflected in the documentation.
+ The same general rule as for code applies -- imitate the existing
+ conventions.
+
+
+Markup:
+
+ Literal parts (e.g. use of command-line options, command names,
+ branch names, URLs, pathnames (files and directories), configuration and
+ environment variables) must be typeset as verbatim (i.e. wrapped with
+ backticks):
+   `--pretty=oneline`
+   `git rev-list`
+   `remote.pushDefault`
+   `http://git.example.com`
+   `.git/config`
+   `GIT_DIR`
+   `HEAD`
+   `umask`(2)
+
+ An environment variable must be prefixed with "$" only when referring to its
+ value and not when referring to the variable itself, in this case there is
+ nothing to add except the backticks:
+   `GIT_DIR` is specified
+   `$GIT_DIR/hooks/pre-receive`
+
+ Word phrases enclosed in `backtick characters` are rendered literally
+ and will not be further expanded. The use of `backticks` to achieve the
+ previous rule means that literal examples should not use AsciiDoc
+ escapes.
+   Correct:
+      `--pretty=oneline`
+   Incorrect:
+      `\--pretty=oneline`
+
+ Placeholders are spelled in lowercase and enclosed in
+ angle brackets surrounded by underscores:
+   _<file>_
+   _<commit>_
+
+ If a placeholder has multiple words, they are separated by dashes:
+   _<new-branch-name>_
+   _<template-directory>_
+
+ When needed, use a distinctive identifier for placeholders, usually
+ made of a qualification and a type:
+   _<git-dir>_
+   _<key-id>_
+
+ Git's Asciidoc processor has been tailored to treat backticked text
+ as complex synopsis. When literal and placeholders are mixed, you can
+ use the backtick notation which will take care of correctly typesetting
+ the content.
+   `--jobs <n>`
+   `--sort=<key>`
+   `<directory>/.git`
+   `remote.<name>.mirror`
+   `ssh://[<user>@]<host>[:<port>]/<path-to-git-repo>`
+
+As a side effect, backquoted placeholders are correctly typeset, but
+this style is not recommended.
+
+Synopsis Syntax
+
+ The synopsis (a paragraph with [synopsis] attribute) is automatically
+ formatted by the toolchain and does not need typesetting.
+
+ A few commented examples follow to provide reference when writing or
+ modifying command usage strings and synopsis sections in the manual
+ pages:
+
+ Possibility of multiple occurrences is indicated by three dots:
+   <file>...
+   (One or more of <file>.)
+
+ Optional parts are enclosed in square brackets:
+   [<file>...]
+   (Zero or more of <file>.)
+
+ An optional parameter needs to be typeset with unconstrained pairs
+   [<repository>]
+
+   --exec-path[=<path>]
+   (Option with an optional argument.  Note that the "=" is inside the
+   brackets.)
+
+   [<patch>...]
+   (Zero or more of <patch>.  Note that the dots are inside, not
+   outside the brackets.)
+
+ Multiple alternatives are indicated with vertical bars:
+   [-q | --quiet]
+   [--utf8 | --no-utf8]
+
+ Use spacing around "|" token(s), but not immediately after opening or
+ before closing a [] or () pair:
+   Do: [-q | --quiet]
+   Don't: [-q|--quiet]
+
+ Don't use spacing around "|" tokens when they're used to separate the
+ alternate arguments of an option:
+    Do: --track[=(direct|inherit)]
+    Don't: --track[=(direct | inherit)]
+
+ Parentheses are used for grouping:
+   [(<rev>|<range>)...]
+   (Any number of either <rev> or <range>.  Parens are needed to make
+   it clear that "..." pertains to both <rev> and <range>.)
+
+   [(-p <parent>)...]
+   (Any number of option -p, each with one <parent> argument.)
+
+   git remote set-head <name> (-a|-d|<branch>)
+   (One and only one of "-a", "-d" or "<branch>" _must_ (no square
+   brackets) be provided.)
+
+ And a somewhat more contrived example:
+   --diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]
+   Here "=" is outside the brackets, because "--diff-filter=" is a
+   valid usage.  "*" has its own pair of brackets, because it can
+   (optionally) be specified only when one or more of the letters is
+   also provided.
+
+  A note on notation:
+   Use 'git' (all lowercase) when talking about commands i.e. something
+   the user would type into a shell and use 'Git' (uppercase first letter)
+   when talking about the version control system and its properties.
+
+ If some place in the documentation needs to typeset a command usage
+ example with inline substitutions, it is fine to use +monospaced and
+ inline substituted text+ instead of `monospaced literal text`, and with
+ the former, the part that should not get substituted must be
+ quoted/escaped.
diff --git a/Documentation/DecisionMaking.adoc b/Documentation/DecisionMaking.adoc
new file mode 100644
index 0000000000..b43c472ae5
--- /dev/null
+++ b/Documentation/DecisionMaking.adoc
@@ -0,0 +1,74 @@
+Decision-Making Process in the Git Project
+==========================================
+
+Introduction
+------------
+This document describes the current decision-making process in the Git
+project. It is a descriptive rather than prescriptive doc; that is, we want to
+describe how things work in practice rather than explicitly recommending any
+particular process or changes to the current process.
+
+Here we document how the project makes decisions for discussions
+(with or without patches), in scale larger than an individual patch
+series (which is fully covered by the SubmittingPatches document).
+
+
+Larger Discussions (with patches)
+---------------------------------
+As with discussions on an individual patch series, starting a larger-scale
+discussion often begins by sending a patch or series to the list. This might
+take the form of an initial design doc, with implementation following in later
+iterations of the series (for example,
+link:https://lore.kernel.org/git/0169ce6fb9ccafc089b74ae406db0d1a8ff8ac65.1688165272.git.steadmon@xxxxxxxxxx/[adding unit tests] or
+link:https://lore.kernel.org/git/20200420235310.94493-1-emilyshaffer@xxxxxxxxxx/[config-based hooks]),
+or it might include a full implementation from the beginning.
+In either case, discussion progresses the same way for an individual patch series,
+until consensus is reached or the topic is dropped.
+
+
+Larger Discussions (without patches)
+------------------------------------
+Occasionally, larger discussions might occur without an associated patch series.
+These may be very large-scale technical decisions that are beyond the scope of
+even a single large patch series, or they may be more open-ended,
+policy-oriented discussions (examples:
+link:https://lore.kernel.org/git/ZZ77NQkSuiRxRDwt@nand.local/[introducing Rust]
+or link:https://lore.kernel.org/git/YHofmWcIAidkvJiD@xxxxxxxxxx/[improving submodule UX]).
+In either case, discussion progresses as described above for general patch series.
+
+For larger discussions without a patch series or other concrete implementation,
+it may be hard to judge when consensus has been reached, as there are not any
+official guidelines. If discussion stalls at this point, it may be helpful to
+restart discussion with an RFC patch series (such as a partial, unfinished
+implementation or proof of concept) that can be more easily debated.
+
+When consensus is reached that it is a good idea, the original
+proposer is expected to coordinate the effort to make it happen,
+with help from others who were involved in the discussion, as
+needed.
+
+For decisions that require code changes, it is often the case that the original
+proposer will follow up with a patch series, although it is also common for
+other interested parties to provide an implementation (or parts of the
+implementation, for very large changes).
+
+For non-technical decisions such as community norms or processes, it is up to
+the community as a whole to implement and sustain agreed-upon changes.
+The project leadership committee (PLC) may help the implementation of
+policy decisions.
+
+
+Other Discussion Venues
+-----------------------
+Occasionally decision proposals are presented off-list, e.g. at the semi-regular
+Contributors' Summit. While higher-bandwidth face-to-face discussion is often
+useful for quickly reaching consensus among attendees, generally we expect to
+summarize the discussion in notes that can later be presented on-list. For an
+example, see the thread
+link:https://lore.kernel.org/git/AC2EB721-2979-43FD-922D-C5076A57F24B@xxxxxxxxxxxxxx/[Notes
+from Git Contributor Summit, Los Angeles (April 5, 2020)] by James Ramsay.
+
+We prefer that "official" discussion happens on the list so that the full
+community has opportunity to engage in discussion. This also means that the
+mailing list archives contain a more-or-less complete history of project
+discussions and decisions.
diff --git a/Documentation/Makefile b/Documentation/Makefile
new file mode 100644
index 0000000000..9d239d380d
--- /dev/null
+++ b/Documentation/Makefile
@@ -0,0 +1,526 @@
+# Import tree-wide shared Makefile behavior and libraries
+include ../shared.mak
+
+.PHONY: FORCE
+
+# Guard against environment variables
+MAN1_TXT =
+MAN5_TXT =
+MAN7_TXT =
+HOWTO_TXT =
+DOC_DEP_TXT =
+TECH_DOCS =
+ARTICLES =
+SP_ARTICLES =
+OBSOLETE_HTML =
+
+-include GIT-EXCLUDED-PROGRAMS
+
+MAN1_TXT += $(filter-out \
+		$(patsubst %,%.adoc,$(EXCLUDED_PROGRAMS)) \
+		$(addsuffix .adoc, $(ARTICLES) $(SP_ARTICLES)), \
+		$(wildcard git-*.adoc))
+MAN1_TXT += git.adoc
+MAN1_TXT += gitk.adoc
+MAN1_TXT += gitweb.adoc
+MAN1_TXT += scalar.adoc
+
+# man5 / man7 guides (note: new guides should also be added to command-list.txt)
+MAN5_TXT += gitattributes.adoc
+MAN5_TXT += gitformat-bundle.adoc
+MAN5_TXT += gitformat-chunk.adoc
+MAN5_TXT += gitformat-commit-graph.adoc
+MAN5_TXT += gitformat-index.adoc
+MAN5_TXT += gitformat-pack.adoc
+MAN5_TXT += gitformat-signature.adoc
+MAN5_TXT += githooks.adoc
+MAN5_TXT += gitignore.adoc
+MAN5_TXT += gitmailmap.adoc
+MAN5_TXT += gitmodules.adoc
+MAN5_TXT += gitprotocol-capabilities.adoc
+MAN5_TXT += gitprotocol-common.adoc
+MAN5_TXT += gitprotocol-http.adoc
+MAN5_TXT += gitprotocol-pack.adoc
+MAN5_TXT += gitprotocol-v2.adoc
+MAN5_TXT += gitrepository-layout.adoc
+MAN5_TXT += gitweb.conf.adoc
+
+MAN7_TXT += gitcli.adoc
+MAN7_TXT += gitcore-tutorial.adoc
+MAN7_TXT += gitcredentials.adoc
+MAN7_TXT += gitcvs-migration.adoc
+MAN7_TXT += gitdiffcore.adoc
+MAN7_TXT += giteveryday.adoc
+MAN7_TXT += gitfaq.adoc
+MAN7_TXT += gitglossary.adoc
+MAN7_TXT += gitpacking.adoc
+MAN7_TXT += gitnamespaces.adoc
+MAN7_TXT += gitremote-helpers.adoc
+MAN7_TXT += gitrevisions.adoc
+MAN7_TXT += gitsubmodules.adoc
+MAN7_TXT += gittutorial-2.adoc
+MAN7_TXT += gittutorial.adoc
+MAN7_TXT += gitworkflows.adoc
+
+HOWTO_TXT += $(wildcard howto/*.adoc)
+
+DOC_DEP_TXT += $(wildcard *.adoc)
+DOC_DEP_TXT += $(wildcard config/*.adoc)
+DOC_DEP_TXT += $(wildcard includes/*.adoc)
+
+ifdef MAN_FILTER
+MAN_TXT = $(filter $(MAN_FILTER),$(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT))
+else
+MAN_TXT = $(MAN1_TXT) $(MAN5_TXT) $(MAN7_TXT)
+MAN_FILTER = $(MAN_TXT)
+endif
+
+MAN_XML = $(patsubst %.adoc,%.xml,$(MAN_TXT))
+MAN_HTML = $(patsubst %.adoc,%.html,$(MAN_TXT))
+GIT_MAN_REF = master
+
+OBSOLETE_HTML += everyday.html
+OBSOLETE_HTML += git-remote-helpers.html
+
+ARTICLES += howto-index
+ARTICLES += git-tools
+ARTICLES += git-bisect-lk2009
+# with their own formatting rules.
+SP_ARTICLES += user-manual
+SP_ARTICLES += howto/new-command
+SP_ARTICLES += howto/revert-branch-rebase
+SP_ARTICLES += howto/using-merge-subtree
+SP_ARTICLES += howto/using-signed-tag-in-pull-request
+SP_ARTICLES += howto/use-git-daemon
+SP_ARTICLES += howto/update-hook-example
+SP_ARTICLES += howto/setup-git-server-over-http
+SP_ARTICLES += howto/separating-topic-branches
+SP_ARTICLES += howto/revert-a-faulty-merge
+SP_ARTICLES += howto/recover-corrupted-blob-object
+SP_ARTICLES += howto/recover-corrupted-object-harder
+SP_ARTICLES += howto/rebuild-from-update-hook
+SP_ARTICLES += howto/rebase-from-internal-branch
+SP_ARTICLES += howto/keep-canonical-history-correct
+SP_ARTICLES += howto/maintain-git
+SP_ARTICLES += howto/coordinate-embargoed-releases
+API_DOCS = $(patsubst %.adoc,%,$(filter-out technical/api-index-skel.adoc technical/api-index.adoc, $(wildcard technical/api-*.adoc)))
+SP_ARTICLES += $(API_DOCS)
+
+TECH_DOCS += DecisionMaking
+TECH_DOCS += ReviewingGuidelines
+TECH_DOCS += MyFirstContribution
+TECH_DOCS += MyFirstObjectWalk
+TECH_DOCS += SubmittingPatches
+TECH_DOCS += ToolsForGit
+TECH_DOCS += technical/bitmap-format
+TECH_DOCS += technical/build-systems
+TECH_DOCS += technical/bundle-uri
+TECH_DOCS += technical/hash-function-transition
+TECH_DOCS += technical/long-running-process-protocol
+TECH_DOCS += technical/multi-pack-index
+TECH_DOCS += technical/pack-heuristics
+TECH_DOCS += technical/parallel-checkout
+TECH_DOCS += technical/partial-clone
+TECH_DOCS += technical/platform-support
+TECH_DOCS += technical/racy-git
+TECH_DOCS += technical/reftable
+TECH_DOCS += technical/scalar
+TECH_DOCS += technical/send-pack-pipeline
+TECH_DOCS += technical/shallow
+TECH_DOCS += technical/trivial-merge
+TECH_DOCS += technical/unit-tests
+SP_ARTICLES += $(TECH_DOCS)
+SP_ARTICLES += technical/api-index
+
+ARTICLES_HTML += $(patsubst %,%.html,$(ARTICLES) $(SP_ARTICLES))
+HTML_FILTER ?= $(ARTICLES_HTML) $(OBSOLETE_HTML)
+DOC_HTML = $(MAN_HTML) $(filter $(HTML_FILTER),$(ARTICLES_HTML) $(OBSOLETE_HTML))
+
+DOC_MAN1 = $(patsubst %.adoc,%.1,$(filter $(MAN_FILTER),$(MAN1_TXT)))
+DOC_MAN5 = $(patsubst %.adoc,%.5,$(filter $(MAN_FILTER),$(MAN5_TXT)))
+DOC_MAN7 = $(patsubst %.adoc,%.7,$(filter $(MAN_FILTER),$(MAN7_TXT)))
+
+prefix ?= $(HOME)
+bindir ?= $(prefix)/bin
+htmldir ?= $(prefix)/share/doc/git-doc
+infodir ?= $(prefix)/share/info
+pdfdir ?= $(prefix)/share/doc/git-doc
+mandir ?= $(prefix)/share/man
+man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
+man7dir = $(mandir)/man7
+# DESTDIR =
+
+ASCIIDOC = asciidoc
+ASCIIDOC_EXTRA =
+ASCIIDOC_HTML = xhtml11
+ASCIIDOC_DOCBOOK = docbook
+ASCIIDOC_CONF = -f asciidoc.conf
+ASCIIDOC_COMMON = $(ASCIIDOC) $(ASCIIDOC_EXTRA) $(ASCIIDOC_CONF)
+ASCIIDOC_DEPS = asciidoc.conf GIT-ASCIIDOCFLAGS
+TXT_TO_HTML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_HTML)
+TXT_TO_XML = $(ASCIIDOC_COMMON) -b $(ASCIIDOC_DOCBOOK)
+MANPAGE_XSL = manpage-normal.xsl
+XMLTO = xmlto
+XMLTO_EXTRA =
+INSTALL ?= install
+RM ?= rm -f
+MAN_REPO = ../../git-manpages
+HTML_REPO = ../../git-htmldocs
+
+MAKEINFO = makeinfo
+INSTALL_INFO = install-info
+DOCBOOK2X_TEXI = docbook2x-texi
+DBLATEX = dblatex
+ASCIIDOC_DBLATEX_DIR = /etc/asciidoc/dblatex
+DBLATEX_COMMON = -p $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.xsl -s $(ASCIIDOC_DBLATEX_DIR)/asciidoc-dblatex.sty
+ifndef PERL_PATH
+	PERL_PATH = /usr/bin/perl
+endif
+
+-include ../config.mak.autogen
+-include ../config.mak
+
+# Set GIT_VERSION_OVERRIDE such that version_gen knows to substitute
+# GIT_VERSION in case it was set by the user.
+GIT_VERSION_OVERRIDE := $(GIT_VERSION)
+
+ifndef NO_MAN_BOLD_LITERAL
+XMLTO_EXTRA += -m manpage-bold-literal.xsl
+endif
+
+# Newer DocBook stylesheet emits warning cruft in the output when
+# this is not set, and if set it shows an absolute link.  Older
+# stylesheets simply ignore this parameter.
+#
+# Distros may want to use MAN_BASE_URL=file:///path/to/git/docs/
+# or similar.
+ifndef MAN_BASE_URL
+MAN_BASE_URL = file://$(htmldir)/
+endif
+XMLTO_EXTRA += --stringparam man.base.url.for.relative.links='$(MAN_BASE_URL)'
+
+ifdef USE_ASCIIDOCTOR
+ASCIIDOC = asciidoctor
+ASCIIDOC_CONF =
+ASCIIDOC_HTML = xhtml5
+ASCIIDOC_DOCBOOK = docbook5
+ASCIIDOC_EXTRA += -acompat-mode -atabsize=8
+ASCIIDOC_EXTRA += -I. -rasciidoctor-extensions
+ASCIIDOC_EXTRA += -alitdd='&\#x2d;&\#x2d;'
+ASCIIDOC_EXTRA += -adocinfo=shared
+ASCIIDOC_DEPS = asciidoctor-extensions.rb GIT-ASCIIDOCFLAGS
+DBLATEX_COMMON =
+XMLTO_EXTRA += --skip-validation
+XMLTO_EXTRA += -x manpage.xsl
+
+asciidoctor-extensions.rb: asciidoctor-extensions.rb.in FORCE
+	$(QUIET_GEN)$(call version_gen,"$(shell pwd)/..",$<,$@)
+else
+asciidoc.conf: asciidoc.conf.in FORCE
+	$(QUIET_GEN)$(call version_gen,"$(shell pwd)/..",$<,$@)
+endif
+
+ASCIIDOC_DEPS += docinfo.html
+
+SHELL_PATH ?= $(SHELL)
+# Shell quote;
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+
+ASCIIDOC_EXTRA += -abuild_dir='$(shell pwd)'
+ifdef DEFAULT_PAGER
+DEFAULT_PAGER_SQ = $(subst ','\'',$(DEFAULT_PAGER))
+ASCIIDOC_EXTRA += -a 'git-default-pager=$(DEFAULT_PAGER_SQ)'
+endif
+
+ifdef DEFAULT_EDITOR
+DEFAULT_EDITOR_SQ = $(subst ','\'',$(DEFAULT_EDITOR))
+ASCIIDOC_EXTRA += -a 'git-default-editor=$(DEFAULT_EDITOR_SQ)'
+endif
+
+all: html man
+
+html: $(DOC_HTML)
+
+man: man1 man5 man7
+man1: $(DOC_MAN1)
+man5: $(DOC_MAN5)
+man7: $(DOC_MAN7)
+
+info: git.info gitman.info
+
+pdf: user-manual.pdf
+
+install: install-man
+
+install-man: man
+	$(INSTALL) -d -m 755 $(DESTDIR)$(man1dir)
+	$(INSTALL) -d -m 755 $(DESTDIR)$(man5dir)
+	$(INSTALL) -d -m 755 $(DESTDIR)$(man7dir)
+	$(INSTALL) -m 644 $(DOC_MAN1) $(DESTDIR)$(man1dir)
+	$(INSTALL) -m 644 $(DOC_MAN5) $(DESTDIR)$(man5dir)
+	$(INSTALL) -m 644 $(DOC_MAN7) $(DESTDIR)$(man7dir)
+
+install-info: info
+	$(INSTALL) -d -m 755 $(DESTDIR)$(infodir)
+	$(INSTALL) -m 644 git.info gitman.info $(DESTDIR)$(infodir)
+	if test -r $(DESTDIR)$(infodir)/dir; then \
+	  $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) git.info ;\
+	  $(INSTALL_INFO) --info-dir=$(DESTDIR)$(infodir) gitman.info ;\
+	else \
+	  echo "No directory found in $(DESTDIR)$(infodir)" >&2 ; \
+	fi
+
+install-pdf: pdf
+	$(INSTALL) -d -m 755 $(DESTDIR)$(pdfdir)
+	$(INSTALL) -m 644 user-manual.pdf $(DESTDIR)$(pdfdir)
+
+install-html: html
+	'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(DESTDIR)$(htmldir)
+
+mergetools_txt = mergetools-diff.adoc mergetools-merge.adoc
+
+#
+# Determine "include::" file references in asciidoc files.
+#
+docdep_prereqs = \
+	$(mergetools_txt) \
+	cmd-list.made $(cmds_txt)
+
+doc.dep : $(docdep_prereqs) $(DOC_DEP_TXT) build-docdep.perl
+	$(QUIET_GEN)$(PERL_PATH) ./build-docdep.perl "$(shell pwd)" >$@ $(QUIET_STDERR)
+
+ifneq ($(MAKECMDGOALS),clean)
+-include doc.dep
+endif
+
+cmds_txt = cmds-ancillaryinterrogators.adoc \
+	cmds-ancillarymanipulators.adoc \
+	cmds-mainporcelain.adoc \
+	cmds-plumbinginterrogators.adoc \
+	cmds-plumbingmanipulators.adoc \
+	cmds-synchingrepositories.adoc \
+	cmds-synchelpers.adoc \
+	cmds-guide.adoc \
+	cmds-developerinterfaces.adoc \
+	cmds-userinterfaces.adoc \
+	cmds-purehelpers.adoc \
+	cmds-foreignscminterface.adoc
+
+$(cmds_txt): cmd-list.made
+
+cmd-list.made: cmd-list.perl ../command-list.txt $(MAN1_TXT)
+	$(QUIET_GEN)$(PERL_PATH) ./cmd-list.perl .. . $(cmds_txt) && \
+	date >$@
+
+mergetools-%.adoc: generate-mergetool-list.sh ../git-mergetool--lib.sh $(wildcard ../mergetools/*)
+mergetools-diff.adoc:
+	$(QUIET_GEN)$(SHELL_PATH) ./generate-mergetool-list.sh .. diff $@
+mergetools-merge.adoc:
+	$(QUIET_GEN)$(SHELL_PATH) ./generate-mergetool-list.sh .. merge $@
+
+TRACK_ASCIIDOCFLAGS = $(subst ','\'',$(ASCIIDOC_COMMON):$(ASCIIDOC_HTML):$(ASCIIDOC_DOCBOOK))
+
+GIT-ASCIIDOCFLAGS: FORCE
+	@FLAGS='$(TRACK_ASCIIDOCFLAGS)'; \
+	    if test x"$$FLAGS" != x"`cat GIT-ASCIIDOCFLAGS 2>/dev/null`" ; then \
+		echo >&2 "    * new asciidoc flags"; \
+		echo "$$FLAGS" >GIT-ASCIIDOCFLAGS; \
+            fi
+
+clean:
+	$(RM) -rf .build/
+	$(RM) *.xml *.xml+ *.html *.html+ *.1 *.5 *.7
+	$(RM) *.texi *.texi+ *.texi++ git.info gitman.info
+	$(RM) *.pdf
+	$(RM) howto-index.txt howto/*.html doc.dep
+	$(RM) technical/*.html technical/api-index.adoc
+	$(RM) SubmittingPatches.adoc
+	$(RM) $(cmds_txt) $(mergetools_txt) *.made
+	$(RM) GIT-ASCIIDOCFLAGS
+	$(RM) asciidoc.conf asciidoctor-extensions.rb
+	$(RM) -rf tmp-meson-diff
+
+docinfo.html: docinfo-html.in
+	$(QUIET_GEN)$(RM) $@ && cat $< >$@
+
+$(MAN_HTML): %.html : %.adoc $(ASCIIDOC_DEPS)
+	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) -d manpage -o $@ $<
+
+$(OBSOLETE_HTML): %.html : %.txto $(ASCIIDOC_DEPS)
+	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) -o $@ $<
+
+manpage-prereqs := $(wildcard manpage*.xsl)
+manpage-cmd = $(QUIET_XMLTO)$(XMLTO) -m $(MANPAGE_XSL) $(XMLTO_EXTRA) man $<
+
+%.1 : %.xml $(manpage-prereqs)
+	$(manpage-cmd)
+%.5 : %.xml $(manpage-prereqs)
+	$(manpage-cmd)
+%.7 : %.xml $(manpage-prereqs)
+	$(manpage-cmd)
+
+%.xml : %.adoc $(ASCIIDOC_DEPS)
+	$(QUIET_ASCIIDOC)$(TXT_TO_XML) -d manpage -o $@ $<
+
+user-manual.xml: user-manual.adoc $(ASCIIDOC_DEPS)
+	$(QUIET_ASCIIDOC)$(TXT_TO_XML) -d book -o $@ $<
+
+technical/api-index.adoc: technical/api-index-skel.adoc \
+	technical/api-index.sh $(patsubst %,%.adoc,$(API_DOCS))
+	$(QUIET_GEN)'$(SHELL_PATH_SQ)' technical/api-index.sh ./technical ./technical/api-index.adoc
+
+technical/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
+$(patsubst %,%.html,$(API_DOCS) technical/api-index $(TECH_DOCS)): %.html : %.adoc \
+	$(ASCIIDOC_DEPS)
+	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.adoc
+
+SubmittingPatches.adoc: SubmittingPatches
+	$(QUIET_GEN) cp $< $@
+
+XSLT = docbook.xsl
+XSLTOPTS =
+XSLTOPTS += --xinclude
+XSLTOPTS += --stringparam html.stylesheet docbook-xsl.css
+XSLTOPTS += --param generate.consistent.ids 1
+
+user-manual.html: user-manual.xml $(XSLT)
+	$(QUIET_XSLTPROC)xsltproc $(XSLTOPTS) -o $@ $(XSLT) $<
+
+git.info: user-manual.texi
+	$(QUIET_MAKEINFO)$(MAKEINFO) --no-split -o $@ user-manual.texi
+
+user-manual.texi: user-manual.xml
+	$(QUIET_DB2TEXI)$(DOCBOOK2X_TEXI) user-manual.xml --encoding=UTF-8 --to-stdout >$@+ && \
+	$(PERL_PATH) fix-texi.perl <$@+ >$@ && \
+	$(RM) $@+
+
+user-manual.pdf: user-manual.xml
+	$(QUIET_DBLATEX)$(DBLATEX) -o $@ $(DBLATEX_COMMON) $<
+
+gitman.texi: $(MAN_XML) cat-texi.perl texi.xsl
+	$(QUIET_DB2TEXI) \
+	($(foreach xml,$(sort $(MAN_XML)),xsltproc -o $(xml)+ texi.xsl $(xml) && \
+		$(DOCBOOK2X_TEXI) --encoding=UTF-8 --to-stdout $(xml)+ && \
+		$(RM) $(xml)+ &&) true) > $@+ && \
+	$(PERL_PATH) cat-texi.perl $@ <$@+ >$@ && \
+	$(RM) $@+
+
+gitman.info: gitman.texi
+	$(QUIET_MAKEINFO)$(MAKEINFO) --no-split --no-validate $<
+
+$(patsubst %.adoc,%.texi,$(MAN_TXT)): %.texi : %.xml
+	$(QUIET_DB2TEXI)$(DOCBOOK2X_TEXI) --to-stdout $*.xml >$@
+
+howto-index.adoc: howto/howto-index.sh $(HOWTO_TXT)
+	$(QUIET_GEN)'$(SHELL_PATH_SQ)' ./howto/howto-index.sh $(sort $(HOWTO_TXT)) >$@
+
+$(patsubst %,%.html,$(ARTICLES)) : %.html : %.adoc $(ASCIIDOC_DEPS)
+	$(QUIET_ASCIIDOC)$(TXT_TO_HTML) $*.adoc
+
+WEBDOC_DEST = /pub/software/scm/git/docs
+
+howto/%.html: ASCIIDOC_EXTRA += -a git-relative-html-prefix=../
+$(patsubst %.adoc,%.html,$(HOWTO_TXT)): %.html : %.adoc $(ASCIIDOC_DEPS)
+	$(QUIET_ASCIIDOC) \
+	sed -e '1,/^$$/d' $< | \
+	$(TXT_TO_HTML) - >$@
+
+install-webdoc : html
+	'$(SHELL_PATH_SQ)' ./install-webdoc.sh $(WEBDOC_DEST)
+
+# You must have a clone of 'git-htmldocs' and 'git-manpages' repositories
+# next to the 'git' repository itself for the following to work.
+
+quick-install: quick-install-man
+
+require-manrepo::
+	@if test ! -d $(MAN_REPO); \
+	then echo "git-manpages repository must exist at $(MAN_REPO)"; exit 1; fi
+
+quick-install-man: require-manrepo
+	'$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(MAN_REPO) $(DESTDIR)$(mandir) $(GIT_MAN_REF)
+
+require-htmlrepo::
+	@if test ! -d $(HTML_REPO); \
+	then echo "git-htmldocs repository must exist at $(HTML_REPO)"; exit 1; fi
+
+quick-install-html: require-htmlrepo
+	'$(SHELL_PATH_SQ)' ./install-doc-quick.sh $(HTML_REPO) $(DESTDIR)$(htmldir) $(GIT_MAN_REF)
+
+print-man1:
+	@for i in $(MAN1_TXT); do echo $$i; done
+
+## Lint: gitlink
+LINT_DOCS_GITLINK = $(patsubst %.adoc,.build/lint-docs/gitlink/%.ok,$(HOWTO_TXT) $(DOC_DEP_TXT))
+$(LINT_DOCS_GITLINK): lint-gitlink.perl
+$(LINT_DOCS_GITLINK): .build/lint-docs/gitlink/%.ok: %.adoc
+	$(call mkdir_p_parent_template)
+	$(QUIET_LINT_GITLINK)$(PERL_PATH) lint-gitlink.perl \
+		$< \
+		$(HOWTO_TXT) $(DOC_DEP_TXT) \
+		--section=1 $(MAN1_TXT) \
+		--section=5 $(MAN5_TXT) \
+		--section=7 $(MAN7_TXT) >$@
+.PHONY: lint-docs-gitlink
+lint-docs-gitlink: $(LINT_DOCS_GITLINK)
+
+## Lint: man-end-blurb
+LINT_DOCS_MAN_END_BLURB = $(patsubst %.adoc,.build/lint-docs/man-end-blurb/%.ok,$(MAN_TXT))
+$(LINT_DOCS_MAN_END_BLURB): lint-man-end-blurb.perl
+$(LINT_DOCS_MAN_END_BLURB): .build/lint-docs/man-end-blurb/%.ok: %.adoc
+	$(call mkdir_p_parent_template)
+	$(QUIET_LINT_MANEND)$(PERL_PATH) lint-man-end-blurb.perl $< >$@
+.PHONY: lint-docs-man-end-blurb
+
+## Lint: man-section-order
+LINT_DOCS_MAN_SECTION_ORDER = $(patsubst %.adoc,.build/lint-docs/man-section-order/%.ok,$(MAN_TXT))
+$(LINT_DOCS_MAN_SECTION_ORDER): lint-man-section-order.perl
+$(LINT_DOCS_MAN_SECTION_ORDER): .build/lint-docs/man-section-order/%.ok: %.adoc
+	$(call mkdir_p_parent_template)
+	$(QUIET_LINT_MANSEC)$(PERL_PATH) lint-man-section-order.perl $< >$@
+.PHONY: lint-docs-man-section-order
+lint-docs-man-section-order: $(LINT_DOCS_MAN_SECTION_ORDER)
+
+.PHONY: lint-docs-fsck-msgids
+LINT_DOCS_FSCK_MSGIDS = .build/lint-docs/fsck-msgids.ok
+$(LINT_DOCS_FSCK_MSGIDS): lint-fsck-msgids.perl
+$(LINT_DOCS_FSCK_MSGIDS): ../fsck.h fsck-msgids.adoc
+	$(call mkdir_p_parent_template)
+	$(QUIET_GEN)$(PERL_PATH) lint-fsck-msgids.perl \
+		../fsck.h fsck-msgids.adoc $@
+
+lint-docs-fsck-msgids: $(LINT_DOCS_FSCK_MSGIDS)
+
+lint-docs-manpages:
+	$(QUIET_GEN)./lint-manpages.sh
+
+.PHONY: lint-docs-meson
+lint-docs-meson:
+	@# awk acts up when trying to match single quotes, so we use \047 instead.
+	@mkdir -p tmp-meson-diff && \
+	awk "/^manpages = {$$/ {flag=1 ; next } /^}$$/ { flag=0 } flag { gsub(/^  \047/, \"\"); gsub(/\047 : [157],\$$/, \"\"); print }" meson.build | \
+		grep -v -e '#' -e '^$$' | \
+		sort >tmp-meson-diff/meson.adoc && \
+	ls git*.adoc scalar.adoc | grep -v -e git-bisect-lk2009.adoc -e git-tools.adoc >tmp-meson-diff/actual.adoc && \
+	if ! cmp tmp-meson-diff/meson.adoc tmp-meson-diff/actual.adoc; then \
+		echo "Meson man pages differ from actual man pages:"; \
+		diff -u tmp-meson-diff/meson.adoc tmp-meson-diff/actual.adoc; \
+		exit 1; \
+	fi
+
+## Lint: list of targets above
+.PHONY: lint-docs
+lint-docs: lint-docs-fsck-msgids
+lint-docs: lint-docs-gitlink
+lint-docs: lint-docs-man-end-blurb
+lint-docs: lint-docs-man-section-order
+lint-docs: lint-docs-manpages
+lint-docs: lint-docs-meson
+
+ifeq ($(wildcard po/Makefile),po/Makefile)
+doc-l10n install-l10n::
+	$(MAKE) -C po $@
+endif
+
+.PHONY: FORCE
diff --git a/Documentation/MyFirstContribution.adoc b/Documentation/MyFirstContribution.adoc
new file mode 100644
index 0000000000..e41654c00a
--- /dev/null
+++ b/Documentation/MyFirstContribution.adoc
@@ -0,0 +1,1395 @@
+My First Contribution to the Git Project
+========================================
+:sectanchors:
+
+[[summary]]
+== Summary
+
+This is a tutorial demonstrating the end-to-end workflow of creating a change to
+the Git tree, sending it for review, and making changes based on comments.
+
+[[prerequisites]]
+=== Prerequisites
+
+This tutorial assumes you're already fairly familiar with using Git to manage
+source code.  The Git workflow steps will largely remain unexplained.
+
+[[related-reading]]
+=== Related Reading
+
+This tutorial aims to summarize the following documents, but the reader may find
+useful additional context:
+
+- `Documentation/SubmittingPatches`
+- `Documentation/howto/new-command.txt`
+
+[[getting-help]]
+=== Getting Help
+
+If you get stuck, you can seek help in the following places.
+
+==== git@xxxxxxxxxxxxxxx
+
+This is the main Git project mailing list where code reviews, version
+announcements, design discussions, and more take place. Those interested in
+contributing are welcome to post questions here. The Git list requires
+plain-text-only emails and prefers inline and bottom-posting when replying to
+mail; you will be CC'd in all replies to you. Optionally, you can subscribe to
+the list by sending an email to <git+subscribe@xxxxxxxxxxxxxxx>
+(see https://subspace.kernel.org/subscribing.html for details).
+The https://lore.kernel.org/git[archive] of this mailing list is
+available to view in a browser.
+
+==== https://groups.google.com/forum/#!forum/git-mentoring[git-mentoring@xxxxxxxxxxxxxxxx]
+
+This mailing list is targeted to new contributors and was created as a place to
+post questions and receive answers outside of the public eye of the main list.
+Veteran contributors who are especially interested in helping mentor newcomers
+are present on the list. In order to avoid search indexers, group membership is
+required to view messages; anyone can join and no approval is required.
+
+==== https://web.libera.chat/#git-devel[#git-devel] on Libera Chat
+
+This IRC channel is for conversations between Git contributors. If someone is
+currently online and knows the answer to your question, you can receive help
+in real time. Otherwise, you can read the
+https://colabti.org/irclogger/irclogger_logs/git-devel[scrollback] to see
+whether someone answered you. IRC does not allow offline private messaging, so
+if you try to private message someone and then log out of IRC, they cannot
+respond to you. It's better to ask your questions in the channel so that you
+can be answered if you disconnect and so that others can learn from the
+conversation.
+
+[[getting-started]]
+== Getting Started
+
+[[cloning]]
+=== Clone the Git Repository
+
+Git is mirrored in a number of locations. Clone the repository from one of them;
+https://git-scm.com/downloads suggests one of the best places to clone from is
+the mirror on GitHub.
+
+----
+$ git clone https://github.com/git/git git
+$ cd git
+----
+
+[[dependencies]]
+=== Installing Dependencies
+
+To build Git from source, you need to have a handful of dependencies installed
+on your system. For a hint of what's needed, you can take a look at
+`INSTALL`, paying close attention to the section about Git's dependencies on
+external programs and libraries. That document mentions a way to "test-drive"
+our freshly built Git without installing; that's the method we'll be using in
+this tutorial.
+
+Make sure that your environment has everything you need by building your brand
+new clone of Git from the above step:
+
+----
+$ make
+----
+
+NOTE: The Git build is parallelizable. `-j#` is not included above but you can
+use it as you prefer, here and elsewhere.
+
+[[identify-problem]]
+=== Identify Problem to Solve
+
+////
+Use + to indicate fixed-width here; couldn't get ` to work nicely with the
+quotes around "Pony Saying 'Um, Hello'".
+////
+In this tutorial, we will add a new command, +git psuh+, short for ``Pony Saying
+`Um, Hello''' - a feature which has gone unimplemented despite a high frequency
+of invocation during users' typical daily workflow.
+
+(We've seen some other effort in this space with the implementation of popular
+commands such as `sl`.)
+
+[[setup-workspace]]
+=== Set Up Your Workspace
+
+Let's start by making a development branch to work on our changes. Per
+`Documentation/SubmittingPatches`, since a brand new command is a new feature,
+it's fine to base your work on `master`. However, in the future for bugfixes,
+etc., you should check that document and base it on the appropriate branch.
+
+For the purposes of this document, we will base all our work on the `master`
+branch of the upstream project. Create the `psuh` branch you will use for
+development like so:
+
+----
+$ git checkout -b psuh origin/master
+----
+
+We'll make a number of commits here in order to demonstrate how to send a topic
+with multiple patches up for review simultaneously.
+
+[[code-it-up]]
+== Code It Up!
+
+NOTE: A reference implementation can be found at
+https://github.com/nasamuffin/git/tree/psuh.
+
+[[add-new-command]]
+=== Adding a New Command
+
+Lots of the subcommands are written as builtins, which means they are
+implemented in C and compiled into the main `git` executable. Implementing the
+very simple `psuh` command as a built-in will demonstrate the structure of the
+codebase, the internal API, and the process of working together as a contributor
+with the reviewers and maintainer to integrate this change into the system.
+
+Built-in subcommands are typically implemented in a function named "cmd_"
+followed by the name of the subcommand, in a source file named after the
+subcommand and contained within `builtin/`. So it makes sense to implement your
+command in `builtin/psuh.c`. Create that file, and within it, write the entry
+point for your command in a function matching the style and signature:
+
+----
+int cmd_psuh(int argc, const char **argv, const char *prefix)
+----
+
+We'll also need to add the declaration of psuh; open up `builtin.h`, find the
+declaration for `cmd_pull`, and add a new line for `psuh` immediately before it,
+in order to keep the declarations alphabetically sorted:
+
+----
+int cmd_psuh(int argc, const char **argv, const char *prefix);
+----
+
+Be sure to `#include "builtin.h"` in your `psuh.c`. You'll also need to
+`#include "gettext.h"` to use functions related to printing output text.
+
+Go ahead and add some throwaway printf to the `cmd_psuh` function. This is a
+decent starting point as we can now add build rules and register the command.
+
+NOTE: Your throwaway text, as well as much of the text you will be adding over
+the course of this tutorial, is user-facing. That means it needs to be
+localizable. Take a look at `po/README` under "Marking strings for translation".
+Throughout the tutorial, we will mark strings for translation as necessary; you
+should also do so when writing your user-facing commands in the future.
+
+----
+int cmd_psuh(int argc, const char **argv, const char *prefix)
+{
+	printf(_("Pony saying hello goes here.\n"));
+	return 0;
+}
+----
+
+Let's try to build it.  Open `Makefile`, find where `builtin/pull.o` is added
+to `BUILTIN_OBJS`, and add `builtin/psuh.o` in the same way next to it in
+alphabetical order. Once you've done so, move to the top-level directory and
+build simply with `make`. Also add the `DEVELOPER=1` variable to turn on
+some additional warnings:
+
+----
+$ echo DEVELOPER=1 >config.mak
+$ make
+----
+
+NOTE: When you are developing the Git project, it's preferred that you use the
+`DEVELOPER` flag; if there's some reason it doesn't work for you, you can turn
+it off, but it's a good idea to mention the problem to the mailing list.
+
+Great, now your new command builds happily on its own. But nobody invokes it.
+Let's change that.
+
+The list of commands lives in `git.c`. We can register a new command by adding
+a `cmd_struct` to the `commands[]` array. `struct cmd_struct` takes a string
+with the command name, a function pointer to the command implementation, and a
+setup option flag. For now, let's keep mimicking `push`. Find the line where
+`cmd_push` is registered, copy it, and modify it for `cmd_psuh`, placing the new
+line in alphabetical order (immediately before `cmd_pull`).
+
+The options are documented in `builtin.h` under "Adding a new built-in." Since
+we hope to print some data about the user's current workspace context later,
+we need a Git directory, so choose `RUN_SETUP` as your only option.
+
+Go ahead and build again. You should see a clean build, so let's kick the tires
+and see if it works. There's a binary you can use to test with in the
+`bin-wrappers` directory.
+
+----
+$ ./bin-wrappers/git psuh
+----
+
+Check it out! You've got a command! Nice work! Let's commit this.
+
+`git status` reveals modified `Makefile`, `builtin.h`, and `git.c` as well as
+untracked `builtin/psuh.c` and `git-psuh`. First, let's take care of the binary,
+which should be ignored. Open `.gitignore` in your editor, find `/git-pull`, and
+add an entry for your new command in alphabetical order:
+
+----
+...
+/git-prune-packed
+/git-psuh
+/git-pull
+/git-push
+/git-quiltimport
+/git-range-diff
+...
+----
+
+Checking `git status` again should show that `git-psuh` has been removed from
+the untracked list and `.gitignore` has been added to the modified list. Now we
+can stage and commit:
+
+----
+$ git add Makefile builtin.h builtin/psuh.c git.c .gitignore
+$ git commit -s
+----
+
+You will be presented with your editor in order to write a commit message. Start
+the commit with a 50-column or less subject line, including the name of the
+component you're working on, followed by a blank line (always required) and then
+the body of your commit message, which should provide the bulk of the context.
+Remember to be explicit and provide the "Why" of your change, especially if it
+couldn't easily be understood from your diff. When editing your commit message,
+don't remove the `Signed-off-by` trailer which was added by `-s` above.
+
+----
+psuh: add a built-in by popular demand
+
+Internal metrics indicate this is a command many users expect to be
+present. So here's an implementation to help drive customer
+satisfaction and engagement: a pony which doubtfully greets the user,
+or, a Pony Saying "Um, Hello" (PSUH).
+
+This commit message is intentionally formatted to 72 columns per line,
+starts with a single line as "commit message subject" that is written as
+if to command the codebase to do something (add this, teach a command
+that). The body of the message is designed to add information about the
+commit that is not readily deduced from reading the associated diff,
+such as answering the question "why?".
+
+Signed-off-by: A U Thor <author@xxxxxxxxxxx>
+----
+
+Go ahead and inspect your new commit with `git show`. "psuh:" indicates you
+have modified mainly the `psuh` command. The subject line gives readers an idea
+of what you've changed. The sign-off line (`-s`) indicates that you agree to
+the Developer's Certificate of Origin 1.1 (see the
+`Documentation/SubmittingPatches` +++[[dco]]+++ header).
+
+For the remainder of the tutorial, the subject line only will be listed for the
+sake of brevity. However, fully-fleshed example commit messages are available
+on the reference implementation linked at the top of this document.
+
+[[implementation]]
+=== Implementation
+
+It's probably useful to do at least something besides printing out a string.
+Let's start by having a look at everything we get.
+
+Modify your `cmd_psuh` implementation to dump the args you're passed, keeping
+existing `printf()` calls in place:
+
+----
+	int i;
+
+	...
+
+	printf(Q_("Your args (there is %d):\n",
+		  "Your args (there are %d):\n",
+		  argc),
+	       argc);
+	for (i = 0; i < argc; i++)
+		printf("%d: %s\n", i, argv[i]);
+
+	printf(_("Your current working directory:\n<top-level>%s%s\n"),
+	       prefix ? "/" : "", prefix ? prefix : "");
+
+----
+
+Build and try it. As you may expect, there's pretty much just whatever we give
+on the command line, including the name of our command. (If `prefix` is empty
+for you, try `cd Documentation/ && ../bin-wrappers/git psuh`). That's not so
+helpful. So what other context can we get?
+
+Add a line to `#include "config.h"`. Then, add the following bits to the
+function body:
+
+----
+	const char *cfg_name;
+
+...
+
+	git_config(git_default_config, NULL);
+	if (git_config_get_string_tmp("user.name", &cfg_name) > 0)
+		printf(_("No name is found in config\n"));
+	else
+		printf(_("Your name: %s\n"), cfg_name);
+----
+
+`git_config()` will grab the configuration from config files known to Git and
+apply standard precedence rules. `git_config_get_string_tmp()` will look up
+a specific key ("user.name") and give you the value. There are a number of
+single-key lookup functions like this one; you can see them all (and more info
+about how to use `git_config()`) in `Documentation/technical/api-config.txt`.
+
+You should see that the name printed matches the one you see when you run:
+
+----
+$ git config --get user.name
+----
+
+Great! Now we know how to check for values in the Git config. Let's commit this
+too, so we don't lose our progress.
+
+----
+$ git add builtin/psuh.c
+$ git commit -sm "psuh: show parameters & config opts"
+----
+
+NOTE: Again, the above is for sake of brevity in this tutorial. In a real change
+you should not use `-m` but instead use the editor to write a meaningful
+message.
+
+Still, it'd be nice to know what the user's working context is like. Let's see
+if we can print the name of the user's current branch. We can mimic the
+`git status` implementation; the printer is located in `wt-status.c` and we can
+see that the branch is held in a `struct wt_status`.
+
+`wt_status_print()` gets invoked by `cmd_status()` in `builtin/commit.c`.
+Looking at that implementation we see the status config being populated like so:
+
+----
+status_init_config(&s, git_status_config);
+----
+
+But as we drill down, we can find that `status_init_config()` wraps a call
+to `git_config()`. Let's modify the code we wrote in the previous commit.
+
+Be sure to include the header to allow you to use `struct wt_status`:
+----
+#include "wt-status.h"
+----
+
+Then modify your `cmd_psuh` implementation to declare your `struct wt_status`,
+prepare it, and print its contents:
+
+----
+	struct wt_status status;
+
+...
+
+	wt_status_prepare(the_repository, &status);
+	git_config(git_default_config, &status);
+
+...
+
+	printf(_("Your current branch: %s\n"), status.branch);
+----
+
+Run it again. Check it out - here's the (verbose) name of your current branch!
+
+Let's commit this as well.
+
+----
+$ git add builtin/psuh.c
+$ git commit -sm "psuh: print the current branch"
+----
+
+Now let's see if we can get some info about a specific commit.
+
+Luckily, there are some helpers for us here. `commit.h` has a function called
+`lookup_commit_reference_by_name` to which we can simply provide a hardcoded
+string; `pretty.h` has an extremely handy `pp_commit_easy()` call which doesn't
+require a full format object to be passed.
+
+Add the following includes:
+
+----
+#include "commit.h"
+#include "pretty.h"
+----
+
+Then, add the following lines within your implementation of `cmd_psuh()` near
+the declarations and the logic, respectively.
+
+----
+	struct commit *c = NULL;
+	struct strbuf commitline = STRBUF_INIT;
+
+...
+
+	c = lookup_commit_reference_by_name("origin/master");
+
+	if (c != NULL) {
+		pp_commit_easy(CMIT_FMT_ONELINE, c, &commitline);
+		printf(_("Current commit: %s\n"), commitline.buf);
+	}
+----
+
+The `struct strbuf` provides some safety belts to your basic `char*`, one of
+which is a length member to prevent buffer overruns. It needs to be initialized
+nicely with `STRBUF_INIT`. Keep it in mind when you need to pass around `char*`.
+
+`lookup_commit_reference_by_name` resolves the name you pass it, so you can play
+with the value there and see what kind of things you can come up with.
+
+`pp_commit_easy` is a convenience wrapper in `pretty.h` that takes a single
+format enum shorthand, rather than an entire format struct. It then
+pretty-prints the commit according to that shorthand. These are similar to the
+formats available with `--pretty=FOO` in many Git commands.
+
+Build it and run, and if you're using the same name in the example, you should
+see the subject line of the most recent commit in `origin/master` that you know
+about. Neat! Let's commit that as well.
+
+----
+$ git add builtin/psuh.c
+$ git commit -sm "psuh: display the top of origin/master"
+----
+
+[[add-documentation]]
+=== Adding Documentation
+
+Awesome! You've got a fantastic new command that you're ready to share with the
+community. But hang on just a minute - this isn't very user-friendly. Run the
+following:
+
+----
+$ ./bin-wrappers/git help psuh
+----
+
+Your new command is undocumented! Let's fix that.
+
+Take a look at `Documentation/git-*.txt`. These are the manpages for the
+subcommands that Git knows about. You can open these up and take a look to get
+acquainted with the format, but then go ahead and make a new file
+`Documentation/git-psuh.txt`. Like with most of the documentation in the Git
+project, help pages are written with AsciiDoc (see CodingGuidelines, "Writing
+Documentation" section). Use the following template to fill out your own
+manpage:
+
+// Surprisingly difficult to embed AsciiDoc source within AsciiDoc.
+[listing]
+....
+git-psuh(1)
+===========
+
+NAME
+----
+git-psuh - Delight users' typo with a shy horse
+
+
+SYNOPSIS
+--------
+[verse]
+'git-psuh [<arg>...]'
+
+DESCRIPTION
+-----------
+...
+
+OPTIONS[[OPTIONS]]
+------------------
+...
+
+OUTPUT
+------
+...
+
+GIT
+---
+Part of the linkgit:git[1] suite
+....
+
+The most important pieces of this to note are the file header, underlined by =,
+the NAME section, and the SYNOPSIS, which would normally contain the grammar if
+your command took arguments. Try to use well-established manpage headers so your
+documentation is consistent with other Git and UNIX manpages; this makes life
+easier for your user, who can skip to the section they know contains the
+information they need.
+
+NOTE: Before trying to build the docs, make sure you have the package `asciidoc`
+installed.
+
+Now that you've written your manpage, you'll need to build it explicitly. We
+convert your AsciiDoc to troff which is man-readable like so:
+
+----
+$ make all doc
+$ man Documentation/git-psuh.1
+----
+
+or
+
+----
+$ make -C Documentation/ git-psuh.1
+$ man Documentation/git-psuh.1
+----
+
+While this isn't as satisfying as running through `git help`, you can at least
+check that your help page looks right.
+
+You can also check that the documentation coverage is good (that is, the project
+sees that your command has been implemented as well as documented) by running
+`make check-docs` from the top-level.
+
+Go ahead and commit your new documentation change.
+
+[[add-usage]]
+=== Adding Usage Text
+
+Try and run `./bin-wrappers/git psuh -h`. Your command should crash at the end.
+That's because `-h` is a special case which your command should handle by
+printing usage.
+
+Take a look at `Documentation/technical/api-parse-options.txt`. This is a handy
+tool for pulling out options you need to be able to handle, and it takes a
+usage string.
+
+In order to use it, we'll need to prepare a NULL-terminated array of usage
+strings and a `builtin_psuh_options` array.
+
+Add a line to `#include "parse-options.h"`.
+
+At global scope, add your array of usage strings:
+
+----
+static const char * const psuh_usage[] = {
+	N_("git psuh [<arg>...]"),
+	NULL,
+};
+----
+
+Then, within your `cmd_psuh()` implementation, we can declare and populate our
+`option` struct. Ours is pretty boring but you can add more to it if you want to
+explore `parse_options()` in more detail:
+
+----
+	struct option options[] = {
+		OPT_END()
+	};
+----
+
+Finally, before you print your args and prefix, add the call to
+`parse-options()`:
+
+----
+	argc = parse_options(argc, argv, prefix, options, psuh_usage, 0);
+----
+
+This call will modify your `argv` parameter. It will strip the options you
+specified in `options` from `argv` and the locations pointed to from `options`
+entries will be updated. Be sure to replace your `argc` with the result from
+`parse_options()`, or you will be confused if you try to parse `argv` later.
+
+It's worth noting the special argument `--`. As you may be aware, many Unix
+commands use `--` to indicate "end of named parameters" - all parameters after
+the `--` are interpreted merely as positional arguments. (This can be handy if
+you want to pass as a parameter something which would usually be interpreted as
+a flag.) `parse_options()` will terminate parsing when it reaches `--` and give
+you the rest of the options afterwards, untouched.
+
+Now that you have a usage hint, you can teach Git how to show it in the general
+command list shown by `git help git` or `git help -a`, which is generated from
+`command-list.txt`. Find the line for 'git-pull' so you can add your 'git-psuh'
+line above it in alphabetical order. Now, we can add some attributes about the
+command which impacts where it shows up in the aforementioned help commands. The
+top of `command-list.txt` shares some information about what each attribute
+means; in those help pages, the commands are sorted according to these
+attributes. `git psuh` is user-facing, or porcelain - so we will mark it as
+"mainporcelain". For "mainporcelain" commands, the comments at the top of
+`command-list.txt` indicate we can also optionally add an attribute from another
+list; since `git psuh` shows some information about the user's workspace but
+doesn't modify anything, let's mark it as "info". Make sure to keep your
+attributes in the same style as the rest of `command-list.txt` using spaces to
+align and delineate them:
+
+----
+git-prune-packed                        plumbingmanipulators
+git-psuh                                mainporcelain		info
+git-pull                                mainporcelain           remote
+git-push                                mainporcelain           remote
+----
+
+Build again. Now, when you run with `-h`, you should see your usage printed and
+your command terminated before anything else interesting happens. Great!
+
+Go ahead and commit this one, too.
+
+[[testing]]
+== Testing
+
+It's important to test your code - even for a little toy command like this one.
+Moreover, your patch won't be accepted into the Git tree without tests. Your
+tests should:
+
+* Illustrate the current behavior of the feature
+* Prove the current behavior matches the expected behavior
+* Ensure the externally-visible behavior isn't broken in later changes
+
+So let's write some tests.
+
+Related reading: `t/README`
+
+[[overview-test-structure]]
+=== Overview of Testing Structure
+
+The tests in Git live in `t/` and are named with a 4-digit decimal number using
+the schema shown in the Naming Tests section of `t/README`.
+
+[[write-new-test]]
+=== Writing Your Test
+
+Since this a toy command, let's go ahead and name the test with t9999. However,
+as many of the family/subcmd combinations are full, best practice seems to be
+to find a command close enough to the one you've added and share its naming
+space.
+
+Create a new file `t/t9999-psuh-tutorial.sh`. Begin with the header as so (see
+"Writing Tests" and "Source 'test-lib.sh'" in `t/README`):
+
+----
+#!/bin/sh
+
+test_description='git-psuh test
+
+This test runs git-psuh and makes sure it does not crash.'
+
+. ./test-lib.sh
+----
+
+Tests are framed inside of a `test_expect_success` in order to output TAP
+formatted results. Let's make sure that `git psuh` doesn't exit poorly and does
+mention the right animal somewhere:
+
+----
+test_expect_success 'runs correctly with no args and good output' '
+	git psuh >actual &&
+	grep Pony actual
+'
+----
+
+Indicate that you've run everything you wanted by adding the following at the
+bottom of your script:
+
+----
+test_done
+----
+
+Make sure you mark your test script executable:
+
+----
+$ chmod +x t/t9999-psuh-tutorial.sh
+----
+
+You can get an idea of whether you created your new test script successfully
+by running `make -C t test-lint`, which will check for things like test number
+uniqueness, executable bit, and so on.
+
+[[local-test]]
+=== Running Locally
+
+Let's try and run locally:
+
+----
+$ make
+$ cd t/ && prove t9999-psuh-tutorial.sh
+----
+
+You can run the full test suite and ensure `git-psuh` didn't break anything:
+
+----
+$ cd t/
+$ prove -j$(nproc) --shuffle t[0-9]*.sh
+----
+
+NOTE: You can also do this with `make test` or use any testing harness which can
+speak TAP. `prove` can run concurrently. `shuffle` randomizes the order the
+tests are run in, which makes them resilient against unwanted inter-test
+dependencies. `prove` also makes the output nicer.
+
+Go ahead and commit this change, as well.
+
+[[ready-to-share]]
+== Getting Ready to Share: Anatomy of a Patch Series
+
+You may have noticed already that the Git project performs its code reviews via
+emailed patches, which are then applied by the maintainer when they are ready
+and approved by the community. The Git project does not accept contributions from
+pull requests, and the patches emailed for review need to be formatted a
+specific way.
+
+:patch-series: https://lore.kernel.org/git/pull.1218.git.git.1645209647.gitgitgadget@xxxxxxxxx/
+:lore: https://lore.kernel.org/git/
+
+Before taking a look at how to convert your commits into emailed patches,
+let's analyze what the end result, a "patch series", looks like. Here is an
+{patch-series}[example] of the summary view for a patch series on the web interface of
+the {lore}[Git mailing list archive]:
+
+----
+2022-02-18 18:40 [PATCH 0/3] libify reflog John Cai via GitGitGadget
+2022-02-18 18:40 ` [PATCH 1/3] reflog: libify delete reflog function and helpers John Cai via GitGitGadget
+2022-02-18 19:10   ` Ævar Arnfjörð Bjarmason [this message]
+2022-02-18 19:39     ` Taylor Blau
+2022-02-18 19:48       ` Ævar Arnfjörð Bjarmason
+2022-02-18 19:35   ` Taylor Blau
+2022-02-21  1:43     ` John Cai
+2022-02-21  1:50       ` Taylor Blau
+2022-02-23 19:50         ` John Cai
+2022-02-18 20:00   ` // other replies elided
+2022-02-18 18:40 ` [PATCH 2/3] reflog: call reflog_delete from reflog.c John Cai via GitGitGadget
+2022-02-18 19:15   ` Ævar Arnfjörð Bjarmason
+2022-02-18 20:26     ` Junio C Hamano
+2022-02-18 18:40 ` [PATCH 3/3] stash: call reflog_delete from reflog.c John Cai via GitGitGadget
+2022-02-18 19:20   ` Ævar Arnfjörð Bjarmason
+2022-02-19  0:21     ` Taylor Blau
+2022-02-22  2:36     ` John Cai
+2022-02-22 10:51       ` Ævar Arnfjörð Bjarmason
+2022-02-18 19:29 ` [PATCH 0/3] libify reflog Ævar Arnfjörð Bjarmason
+2022-02-22 18:30 ` [PATCH v2 0/3] libify reflog John Cai via GitGitGadget
+2022-02-22 18:30   ` [PATCH v2 1/3] stash: add test to ensure reflog --rewrite --updatref behavior John Cai via GitGitGadget
+2022-02-23  8:54     ` Ævar Arnfjörð Bjarmason
+2022-02-23 21:27       ` Junio C Hamano
+// continued
+----
+
+We can note a few things:
+
+- Each commit is sent as a separate email, with the commit message title as
+  subject, prefixed with "[PATCH _i_/_n_]" for the _i_-th commit of an
+  _n_-commit series.
+- Each patch is sent as a reply to an introductory email called the _cover
+  letter_ of the series, prefixed "[PATCH 0/_n_]".
+- Subsequent iterations of the patch series are labelled "PATCH v2", "PATCH
+  v3", etc. in place of "PATCH". For example, "[PATCH v2 1/3]" would be the first of
+  three patches in the second iteration. Each iteration is sent with a new cover
+  letter (like "[PATCH v2 0/3]" above), itself a reply to the cover letter of the
+  previous iteration (more on that below).
+
+NOTE: A single-patch topic is sent with "[PATCH]", "[PATCH v2]", etc. without
+_i_/_n_ numbering (in the above thread overview, no single-patch topic appears,
+though).
+
+[[cover-letter]]
+=== The cover letter
+
+In addition to an email per patch, the Git community also expects your patches
+to come with a cover letter. This is an important component of change
+submission as it explains to the community from a high level what you're trying
+to do, and why, in a way that's more apparent than just looking at your
+patches.
+
+The title of your cover letter should be something which succinctly covers the
+purpose of your entire topic branch. It's often in the imperative mood, just
+like our commit message titles. Here is how we'll title our series:
+
+---
+Add the 'psuh' command
+---
+
+The body of the cover letter is used to give additional context to reviewers.
+Be sure to explain anything your patches don't make clear on their own, but
+remember that since the cover letter is not recorded in the commit history,
+anything that might be useful to future readers of the repository's history
+should also be in your commit messages.
+
+Here's an example body for `psuh`:
+
+----
+Our internal metrics indicate widespread interest in the command
+git-psuh - that is, many users are trying to use it, but finding it is
+unavailable, using some unknown workaround instead.
+
+The following handful of patches add the psuh command and implement some
+handy features on top of it.
+
+This patchset is part of the MyFirstContribution tutorial and should not
+be merged.
+----
+
+At this point the tutorial diverges, in order to demonstrate two
+different methods of formatting your patchset and getting it reviewed.
+
+The first method to be covered is GitGitGadget, which is useful for those
+already familiar with GitHub's common pull request workflow. This method
+requires a GitHub account.
+
+The second method to be covered is `git send-email`, which can give slightly
+more fine-grained control over the emails to be sent. This method requires some
+setup which can change depending on your system and will not be covered in this
+tutorial.
+
+Regardless of which method you choose, your engagement with reviewers will be
+the same; the review process will be covered after the sections on GitGitGadget
+and `git send-email`.
+
+[[howto-ggg]]
+== Sending Patches via GitGitGadget
+
+One option for sending patches is to follow a typical pull request workflow and
+send your patches out via GitGitGadget. GitGitGadget is a tool created by
+Johannes Schindelin to make life as a Git contributor easier for those used to
+the GitHub PR workflow. It allows contributors to open pull requests against its
+mirror of the Git project, and does some magic to turn the PR into a set of
+emails and send them out for you. It also runs the Git continuous integration
+suite for you. It's documented at https://gitgitgadget.github.io/.
+
+[[create-fork]]
+=== Forking `git/git` on GitHub
+
+Before you can send your patch off to be reviewed using GitGitGadget, you will
+need to fork the Git project and upload your changes. First thing - make sure
+you have a GitHub account.
+
+Head to the https://github.com/git/git[GitHub mirror] and look for the Fork
+button. Place your fork wherever you deem appropriate and create it.
+
+[[upload-to-fork]]
+=== Uploading to Your Own Fork
+
+To upload your branch to your own fork, you'll need to add the new fork as a
+remote. You can use `git remote -v` to show the remotes you have added already.
+From your new fork's page on GitHub, you can press "Clone or download" to get
+the URL; then you need to run the following to add, replacing your own URL and
+remote name for the examples provided:
+
+----
+$ git remote add remotename git@xxxxxxxxxx:remotename/git.git
+----
+
+or to use the HTTPS URL:
+
+----
+$ git remote add remotename https://github.com/remotename/git/.git
+----
+
+Run `git remote -v` again and you should see the new remote showing up.
+`git fetch remotename` (with the real name of your remote replaced) in order to
+get ready to push.
+
+Next, double-check that you've been doing all your development in a new branch
+by running `git branch`. If you didn't, now is a good time to move your new
+commits to their own branch.
+
+As mentioned briefly at the beginning of this document, we are basing our work
+on `master`, so go ahead and update as shown below, or using your preferred
+workflow.
+
+----
+$ git checkout master
+$ git pull -r
+$ git rebase master psuh
+----
+
+Finally, you're ready to push your new topic branch! (Due to our branch and
+command name choices, be careful when you type the command below.)
+
+----
+$ git push remotename psuh
+----
+
+Now you should be able to go and check out your newly created branch on GitHub.
+
+[[send-pr-ggg]]
+=== Sending a PR to GitGitGadget
+
+In order to have your code tested and formatted for review, you need to start by
+opening a Pull Request against `gitgitgadget/git`. Head to
+https://github.com/gitgitgadget/git and open a PR either with the "New pull
+request" button or the convenient "Compare & pull request" button that may
+appear with the name of your newly pushed branch.
+
+Review the PR's title and description, as they're used by GitGitGadget
+respectively as the subject and body of the cover letter for your change. Refer
+to <<cover-letter,"The cover letter">> above for advice on how to title your
+submission and what content to include in the description.
+
+NOTE: For single-patch contributions, your commit message should already be
+meaningful and explain at a high level the purpose (what is happening and why)
+of your patch, so you usually do not need any additional context. In that case,
+remove the PR description that GitHub automatically generates from your commit
+message (your PR description should be empty). If you do need to supply even
+more context, you can do so in that space and it will be appended to the email
+that GitGitGadget will send, between the three-dash line and the diffstat
+(see <<single-patch,Bonus Chapter: One-Patch Changes>> for how this looks once
+submitted).
+
+When you're happy, submit your pull request.
+
+[[run-ci-ggg]]
+=== Running CI and Getting Ready to Send
+
+If it's your first time using GitGitGadget (which is likely, as you're using
+this tutorial) then someone will need to give you permission to use the tool.
+As mentioned in the GitGitGadget documentation, you just need someone who
+already uses it to comment on your PR with `/allow <username>`. GitGitGadget
+will automatically run your PRs through the CI even without the permission given
+but you will not be able to `/submit` your changes until someone allows you to
+use the tool.
+
+NOTE: You can typically find someone who can `/allow` you on GitGitGadget by
+either examining recent pull requests where someone has been granted `/allow`
+(https://github.com/gitgitgadget/git/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+%22%2Fallow%22[Search:
+is:pr is:open "/allow"]), in which case both the author and the person who
+granted the `/allow` can now `/allow` you, or by inquiring on the
+https://web.libera.chat/#git-devel[#git-devel] IRC channel on Libera Chat
+linking your pull request and asking for someone to `/allow` you.
+
+If the CI fails, you can update your changes with `git rebase -i` and push your
+branch again:
+
+----
+$ git push -f remotename psuh
+----
+
+In fact, you should continue to make changes this way up until the point when
+your patch is accepted into `next`.
+
+////
+TODO https://github.com/gitgitgadget/gitgitgadget/issues/83
+It'd be nice to be able to verify that the patch looks good before sending it
+to everyone on Git mailing list.
+[[check-work-ggg]]
+=== Check Your Work
+////
+
+[[send-mail-ggg]]
+=== Sending Your Patches
+
+Now that your CI is passing and someone has granted you permission to use
+GitGitGadget with the `/allow` command, sending out for review is as simple as
+commenting on your PR with `/submit`.
+
+[[responding-ggg]]
+=== Updating With Comments
+
+Skip ahead to <<reviewing,Responding to Reviews>> for information on how to
+reply to review comments you will receive on the mailing list.
+
+Once you have your branch again in the shape you want following all review
+comments, you can submit again:
+
+----
+$ git push -f remotename psuh
+----
+
+Next, go look at your pull request against GitGitGadget; you should see the CI
+has been kicked off again. Now while the CI is running is a good time for you
+to modify your description at the top of the pull request thread; it will be
+used again as the cover letter. You should use this space to describe what
+has changed since your previous version, so that your reviewers have some idea
+of what they're looking at. When the CI is done running, you can comment once
+more with `/submit` - GitGitGadget will automatically add a v2 mark to your
+changes.
+
+[[howto-git-send-email]]
+== Sending Patches with `git send-email`
+
+If you don't want to use GitGitGadget, you can also use Git itself to mail your
+patches. Some benefits of using Git this way include finer grained control of
+subject line (for example, being able to use the tag [RFC PATCH] in the subject)
+and being able to send a ``dry run'' mail to yourself to ensure it all looks
+good before going out to the list.
+
+[[setup-git-send-email]]
+=== Prerequisite: Setting Up `git send-email`
+
+Configuration for `send-email` can vary based on your operating system and email
+provider, and so will not be covered in this tutorial, beyond stating that in
+many distributions of Linux, `git-send-email` is not packaged alongside the
+typical `git` install. You may need to install this additional package; there
+are a number of resources online to help you do so. You will also need to
+determine the right way to configure it to use your SMTP server; again, as this
+configuration can change significantly based on your system and email setup, it
+is out of scope for the context of this tutorial.
+
+[[format-patch]]
+=== Preparing Initial Patchset
+
+Sending emails with Git is a two-part process; before you can prepare the emails
+themselves, you'll need to prepare the patches. Luckily, this is pretty simple:
+
+----
+$ git format-patch --cover-letter -o psuh/ --base=auto psuh@{u}..psuh
+----
+
+ . The `--cover-letter` option tells `format-patch` to create a
+   cover letter template for you. You will need to fill in the
+   template before you're ready to send - but for now, the template
+   will be next to your other patches.
+
+ . The `-o psuh/` option tells `format-patch` to place the patch
+   files into a directory. This is useful because `git send-email`
+   can take a directory and send out all the patches from there.
+
+ . The `--base=auto` option tells the command to record the "base
+   commit", on which the recipient is expected to apply the patch
+   series.  The `auto` value will cause `format-patch` to compute
+   the base commit automatically, which is the merge base of tip
+   commit of the remote-tracking branch and the specified revision
+   range.
+
+ . The `psuh@{u}..psuh` option tells `format-patch` to generate
+   patches for the commits you created on the `psuh` branch since it
+   forked from its upstream (which is `origin/master` if you
+   followed the example in the "Set up your workspace" section).  If
+   you are already on the `psuh` branch, you can just say `@{u}`,
+   which means "commits on the current branch since it forked from
+   its upstream", which is the same thing.
+
+The command will make one patch file per commit. After you
+run, you can go have a look at each of the patches with your favorite text
+editor and make sure everything looks alright; however, it's not recommended to
+make code fixups via the patch file. It's a better idea to make the change the
+normal way using `git rebase -i` or by adding a new commit than by modifying a
+patch.
+
+NOTE: Optionally, you can also use the `--rfc` flag to prefix your patch subject
+with ``[RFC PATCH]'' instead of ``[PATCH]''. RFC stands for ``request for
+comments'' and indicates that while your code isn't quite ready for submission,
+you'd like to begin the code review process. This can also be used when your
+patch is a proposal, but you aren't sure whether the community wants to solve
+the problem with that approach or not - to conduct a sort of design review. You
+may also see on the list patches marked ``WIP'' - this means they are incomplete
+but want reviewers to look at what they have so far. You can add this flag with
+`--subject-prefix=WIP`.
+
+Check and make sure that your patches and cover letter template exist in the
+directory you specified - you're nearly ready to send out your review!
+
+[[preparing-cover-letter]]
+=== Preparing Email
+
+Since you invoked `format-patch` with `--cover-letter`, you've already got a
+cover letter template ready. Open it up in your favorite editor.
+
+You should see a number of headers present already. Check that your `From:`
+header is correct. Then modify your `Subject:` (see <<cover-letter,above>> for
+how to choose good title for your patch series):
+
+----
+Subject: [PATCH 0/7] Add the 'psuh' command
+----
+
+Make sure you retain the ``[PATCH 0/X]'' part; that's what indicates to the Git
+community that this email is the beginning of a patch series, and many
+reviewers filter their email for this type of flag.
+
+You'll need to add some extra parameters when you invoke `git send-email` to add
+the cover letter.
+
+Next you'll have to fill out the body of your cover letter. Again, see
+<<cover-letter,above>> for what content to include.
+
+The template created by `git format-patch --cover-letter` includes a diffstat.
+This gives reviewers a summary of what they're in for when reviewing your topic.
+The one generated for `psuh` from the sample implementation looks like this:
+
+----
+ Documentation/git-psuh.txt | 40 +++++++++++++++++++++
+ Makefile                   |  1 +
+ builtin.h                  |  1 +
+ builtin/psuh.c             | 73 ++++++++++++++++++++++++++++++++++++++
+ git.c                      |  1 +
+ t/t9999-psuh-tutorial.sh   | 12 +++++++
+ 6 files changed, 128 insertions(+)
+ create mode 100644 Documentation/git-psuh.txt
+ create mode 100644 builtin/psuh.c
+ create mode 100755 t/t9999-psuh-tutorial.sh
+----
+
+Finally, the letter will include the version of Git used to generate the
+patches. You can leave that string alone.
+
+[[sending-git-send-email]]
+=== Sending Email
+
+At this point you should have a directory `psuh/` which is filled with your
+patches and a cover letter. Time to mail it out! You can send it like this:
+
+----
+$ git send-email --to=target@xxxxxxxxxxx psuh/*.patch
+----
+
+NOTE: Check `git help send-email` for some other options which you may find
+valuable, such as changing the Reply-to address or adding more CC and BCC lines.
+
+:contrib-scripts: footnoteref:[contrib-scripts,Scripts under `contrib/` are +
+not part of the core `git` binary and must be called directly. Clone the Git +
+codebase and run `perl contrib/contacts/git-contacts`.]
+
+NOTE: If you're not sure whom to CC, running `contrib/contacts/git-contacts` can
+list potential reviewers. In addition, you can do `git send-email
+--cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch`{contrib-scripts} to
+automatically pass this list of emails to `send-email`.
+
+NOTE: When you are sending a real patch, it will go to git@xxxxxxxxxxxxxxx - but
+please don't send your patchset from the tutorial to the real mailing list! For
+now, you can send it to yourself, to make sure you understand how it will look.
+
+After you run the command above, you will be presented with an interactive
+prompt for each patch that's about to go out. This gives you one last chance to
+edit or quit sending something (but again, don't edit code this way). Once you
+press `y` or `a` at these prompts your emails will be sent! Congratulations!
+
+Awesome, now the community will drop everything and review your changes. (Just
+kidding - be patient!)
+
+[[v2-git-send-email]]
+=== Sending v2
+
+This section will focus on how to send a v2 of your patchset. To learn what
+should go into v2, skip ahead to <<reviewing,Responding to Reviews>> for
+information on how to handle comments from reviewers.
+
+We'll reuse our `psuh` topic branch for v2. Before we make any changes, we'll
+mark the tip of our v1 branch for easy reference:
+
+----
+$ git checkout psuh
+$ git branch psuh-v1
+----
+
+Refine your patch series by using `git rebase -i` to adjust commits based upon
+reviewer comments. Once the patch series is ready for submission, generate your
+patches again, but with some new flags:
+
+----
+$ git format-patch -v2 --cover-letter -o psuh/ --range-diff master..psuh-v1 master..
+----
+
+The `--range-diff master..psuh-v1` parameter tells `format-patch` to include a
+range-diff between `psuh-v1` and `psuh` in the cover letter (see
+linkgit:git-range-diff[1]). This helps tell reviewers about the differences
+between your v1 and v2 patches.
+
+The `-v2` parameter tells `format-patch` to output your patches
+as version "2". For instance, you may notice that your v2 patches are
+all named like `v2-000n-my-commit-subject.patch`. `-v2` will also format
+your patches by prefixing them with "[PATCH v2]" instead of "[PATCH]",
+and your range-diff will be prefaced with "Range-diff against v1".
+
+After you run this command, `format-patch` will output the patches to the `psuh/`
+directory, alongside the v1 patches. Using a single directory makes it easy to
+refer to the old v1 patches while proofreading the v2 patches, but you will need
+to be careful to send out only the v2 patches. We will use a pattern like
+`psuh/v2-*.patch` (not `psuh/*.patch`, which would match v1 and v2 patches).
+
+Edit your cover letter again. Now is a good time to mention what's different
+between your last version and now, if it's something significant. You do not
+need the exact same body in your second cover letter; focus on explaining to
+reviewers the changes you've made that may not be as visible.
+
+You will also need to go and find the Message-ID of your previous cover letter.
+You can either note it when you send the first series, from the output of `git
+send-email`, or you can look it up on the
+https://lore.kernel.org/git[mailing list]. Find your cover letter in the
+archives, click on it, then click "permalink" or "raw" to reveal the Message-ID
+header. It should match:
+
+----
+Message-ID: <foo.12345.author@xxxxxxxxxxx>
+----
+
+Your Message-ID is `<foo.12345.author@xxxxxxxxxxx>`. This example will be used
+below as well; make sure to replace it with the correct Message-ID for your
+**previous cover letter** - that is, if you're sending v2, use the Message-ID
+from v1; if you're sending v3, use the Message-ID from v2.
+
+While you're looking at the email, you should also note who is CC'd, as it's
+common practice in the mailing list to keep all CCs on a thread. You can add
+these CC lines directly to your cover letter with a line like so in the header
+(before the Subject line):
+
+----
+CC: author@xxxxxxxxxxx, Othe R <other@xxxxxxxxxxx>
+----
+
+Now send the emails again, paying close attention to which messages you pass in
+to the command:
+
+----
+$ git send-email --to=target@xxxxxxxxxxx
+		 --in-reply-to="<foo.12345.author@xxxxxxxxxxx>"
+		 psuh/v2-*.patch
+----
+
+[[single-patch]]
+=== Bonus Chapter: One-Patch Changes
+
+In some cases, your very small change may consist of only one patch. When that
+happens, you only need to send one email. Your commit message should already be
+meaningful and explain at a high level the purpose (what is happening and why)
+of your patch, but if you need to supply even more context, you can do so below
+the `---` in your patch. Take the example below, which was generated with `git
+format-patch` on a single commit, and then edited to add the content between
+the `---` and the diffstat.
+
+----
+From 1345bbb3f7ac74abde040c12e737204689a72723 Mon Sep 17 00:00:00 2001
+From: A U Thor <author@xxxxxxxxxxx>
+Date: Thu, 18 Apr 2019 15:11:02 -0700
+Subject: [PATCH] README: change the grammar
+
+I think it looks better this way. This part of the commit message will
+end up in the commit-log.
+
+Signed-off-by: A U Thor <author@xxxxxxxxxxx>
+---
+Let's have a wild discussion about grammar on the mailing list. This
+part of my email will never end up in the commit log. Here is where I
+can add additional context to the mailing list about my intent, outside
+of the context of the commit log. This section was added after `git
+format-patch` was run, by editing the patch file in a text editor.
+
+ README.md | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/README.md b/README.md
+index 88f126184c..38da593a60 100644
+--- a/README.md
++++ b/README.md
+@@ -3,7 +3,7 @@
+ Git - fast, scalable, distributed revision control system
+ =========================================================
+
+-Git is a fast, scalable, distributed revision control system with an
++Git is a fast, scalable, and distributed revision control system with an
+ unusually rich command set that provides both high-level operations
+ and full access to internals.
+
+--
+2.21.0.392.gf8f6787159e-goog
+----
+
+[[now-what]]
+== My Patch Got Emailed - Now What?
+
+Please give reviewers enough time to process your initial patch before
+sending an updated version. That is, resist the temptation to send a new
+version immediately, because others may have already started reviewing
+your initial version.
+
+While waiting for review comments, you may find mistakes in your initial
+patch, or perhaps realize a different and better way to achieve the goal
+of the patch. In this case you may communicate your findings to other
+reviewers as follows:
+
+ - If the mistakes you found are minor, send a reply to your patch as if
+   you were a reviewer and mention that you will fix them in an
+   updated version.
+
+ - On the other hand, if you think you want to change the course so
+   drastically that reviews on the initial patch would be a waste of
+   time (for everyone involved), retract the patch immediately with
+   a reply like "I am working on a much better approach, so please
+   ignore this patch and wait for the updated version."
+
+Now, the above is a good practice if you sent your initial patch
+prematurely without polish.  But a better approach of course is to avoid
+sending your patch prematurely in the first place.
+
+Please be considerate of the time needed by reviewers to examine each
+new version of your patch. Rather than seeing the initial version right
+now (followed by several "oops, I like this version better than the
+previous one" patches over 2 days), reviewers would strongly prefer if a
+single polished version came 2 days later instead, and that version with
+fewer mistakes were the only one they would need to review.
+
+
+[[reviewing]]
+=== Responding to Reviews
+
+After a few days, you will hopefully receive a reply to your patchset with some
+comments. Woohoo! Now you can get back to work.
+
+It's good manners to reply to each comment, notifying the reviewer that you have
+made the change suggested, feel the original is better, or that the comment
+inspired you to do something a new way which is superior to both the original
+and the suggested change. This way reviewers don't need to inspect your v2 to
+figure out whether you implemented their comment or not.
+
+Reviewers may ask you about what you wrote in the patchset, either in
+the proposed commit log message or in the changes themselves.  You
+should answer these questions in your response messages, but often the
+reason why reviewers asked these questions to understand what you meant
+to write is because your patchset needed clarification to be understood.
+
+Do not be satisfied by just answering their questions in your response
+and hear them say that they now understand what you wanted to say.
+Update your patches to clarify the points reviewers had trouble with,
+and prepare your v2; the words you used to explain your v1 to answer
+reviewers' questions may be useful thing to use.  Your goal is to make
+your v2 clear enough so that it becomes unnecessary for you to give the
+same explanation to the next person who reads it.
+
+If you are going to push back on a comment, be polite and explain why you feel
+your original is better; be prepared that the reviewer may still disagree with
+you, and the rest of the community may weigh in on one side or the other. As
+with all code reviews, it's important to keep an open mind to doing something a
+different way than you originally planned; other reviewers have a different
+perspective on the project than you do, and may be thinking of a valid side
+effect which had not occurred to you. It is always okay to ask for clarification
+if you aren't sure why a change was suggested, or what the reviewer is asking
+you to do.
+
+Make sure your email client has a plaintext email mode and it is turned on; the
+Git list rejects HTML email. Please also follow the mailing list etiquette
+outlined in the
+https://kernel.googlesource.com/pub/scm/git/git/+/todo/MaintNotes[Maintainer's
+Note], which are similar to etiquette rules in most open source communities
+surrounding bottom-posting and inline replies.
+
+When you're making changes to your code, it is cleanest - that is, the resulting
+commits are easiest to look at - if you use `git rebase -i` (interactive
+rebase). Take a look at this
+https://www.oreilly.com/library/view/git-pocket-guide/9781449327507/ch10.html[overview]
+from O'Reilly. The general idea is to modify each commit which requires changes;
+this way, instead of having a patch A with a mistake, a patch B which was fine
+and required no upstream reviews in v1, and a patch C which fixes patch A for
+v2, you can just ship a v2 with a correct patch A and correct patch B. This is
+changing history, but since it's local history which you haven't shared with
+anyone, that is okay for now! (Later, it may not make sense to do this; take a
+look at the section below this one for some context.)
+
+[[after-approval]]
+=== After Review Approval
+
+The Git project has four integration branches: `seen`, `next`, `master`, and
+`maint`. Your change will be placed into `seen` fairly early on by the maintainer
+while it is still in the review process; from there, when it is ready for wider
+testing, it will be merged into `next`. Plenty of early testers use `next` and
+may report issues. Eventually, changes in `next` will make it to `master`,
+which is typically considered stable. Finally, when a new release is cut,
+`maint` is used to base bugfixes onto. As mentioned at the beginning of this
+document, you can read `Documents/SubmittingPatches` for some more info about
+the use of the various integration branches.
+
+Back to now: your code has been lauded by the upstream reviewers. It is perfect.
+It is ready to be accepted. You don't need to do anything else; the maintainer
+will merge your topic branch to `next` and life is good.
+
+However, if you discover it isn't so perfect after this point, you may need to
+take some special steps depending on where you are in the process.
+
+If the maintainer has announced in the "What's cooking in git.git" email that
+your topic is marked for `next` - that is, that they plan to merge it to `next`
+but have not yet done so - you should send an email asking the maintainer to
+wait a little longer: "I've sent v4 of my series and you marked it for `next`,
+but I need to change this and that - please wait for v5 before you merge it."
+
+If the topic has already been merged to `next`, rather than modifying your
+patches with `git rebase -i`, you should make further changes incrementally -
+that is, with another commit, based on top of the maintainer's topic branch as
+detailed in https://github.com/gitster/git. Your work is still in the same topic
+but is now incremental, rather than a wholesale rewrite of the topic branch.
+
+The topic branches in the maintainer's GitHub are mirrored in GitGitGadget, so
+if you're sending your reviews out that way, you should be sure to open your PR
+against the appropriate GitGitGadget/Git branch.
+
+If you're using `git send-email`, you can use it the same way as before, but you
+should generate your diffs from `<topic>..<mybranch>` and base your work on
+`<topic>` instead of `master`.
diff --git a/Documentation/MyFirstObjectWalk.adoc b/Documentation/MyFirstObjectWalk.adoc
new file mode 100644
index 0000000000..dec8afe5b1
--- /dev/null
+++ b/Documentation/MyFirstObjectWalk.adoc
@@ -0,0 +1,898 @@
+= My First Object Walk
+
+== What's an Object Walk?
+
+The object walk is a key concept in Git - this is the process that underpins
+operations like object transfer and fsck. Beginning from a given commit, the
+list of objects is found by walking parent relationships between commits (commit
+X based on commit W) and containment relationships between objects (tree Y is
+contained within commit X, and blob Z is located within tree Y, giving our
+working tree for commit X something like `y/z.txt`).
+
+A related concept is the revision walk, which is focused on commit objects and
+their parent relationships and does not delve into other object types. The
+revision walk is used for operations like `git log`.
+
+=== Related Reading
+
+- `Documentation/user-manual.txt` under "Hacking Git" contains some coverage of
+  the revision walker in its various incarnations.
+- `revision.h`
+- https://eagain.net/articles/git-for-computer-scientists/[Git for Computer Scientists]
+  gives a good overview of the types of objects in Git and what your object
+  walk is really describing.
+
+== Setting Up
+
+Create a new branch from `master`.
+
+----
+git checkout -b revwalk origin/master
+----
+
+We'll put our fiddling into a new command. For fun, let's name it `git walken`.
+Open up a new file `builtin/walken.c` and set up the command handler:
+
+----
+/*
+ * "git walken"
+ *
+ * Part of the "My First Object Walk" tutorial.
+ */
+
+#include "builtin.h"
+#include "trace.h"
+
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+	trace_printf(_("cmd_walken incoming...\n"));
+	return 0;
+}
+----
+
+NOTE: `trace_printf()`, defined in `trace.h`, differs from `printf()` in
+that it can be turned on or off at runtime. For the purposes of this
+tutorial, we will write `walken` as though it is intended for use as
+a "plumbing" command: that is, a command which is used primarily in
+scripts, rather than interactively by humans (a "porcelain" command).
+So we will send our debug output to `trace_printf()` instead.
+When running, enable trace output by setting the environment variable `GIT_TRACE`.
+
+Add usage text and `-h` handling, like all subcommands should consistently do
+(our test suite will notice and complain if you fail to do so).
+We'll need to include the `parse-options.h` header.
+
+----
+#include "parse-options.h"
+
+...
+
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+	const char * const walken_usage[] = {
+		N_("git walken"),
+		NULL,
+	};
+	struct option options[] = {
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, walken_usage, 0);
+
+	...
+}
+----
+
+Also add the relevant line in `builtin.h` near `cmd_whatchanged()`:
+
+----
+int cmd_walken(int argc, const char **argv, const char *prefix);
+----
+
+Include the command in `git.c` in `commands[]` near the entry for `whatchanged`,
+maintaining alphabetical ordering:
+
+----
+{ "walken", cmd_walken, RUN_SETUP },
+----
+
+Add it to the `Makefile` near the line for `builtin/worktree.o`:
+
+----
+BUILTIN_OBJS += builtin/walken.o
+----
+
+Build and test out your command, without forgetting to ensure the `DEVELOPER`
+flag is set, and with `GIT_TRACE` enabled so the debug output can be seen:
+
+----
+$ echo DEVELOPER=1 >>config.mak
+$ make
+$ GIT_TRACE=1 ./bin-wrappers/git walken
+----
+
+NOTE: For a more exhaustive overview of the new command process, take a look at
+`Documentation/MyFirstContribution.txt`.
+
+NOTE: A reference implementation can be found at
+https://github.com/nasamuffin/git/tree/revwalk.
+
+=== `struct rev_cmdline_info`
+
+The definition of `struct rev_cmdline_info` can be found in `revision.h`.
+
+This struct is contained within the `rev_info` struct and is used to reflect
+parameters provided by the user over the CLI.
+
+`nr` represents the number of `rev_cmdline_entry` present in the array.
+
+`alloc` is used by the `ALLOC_GROW` macro. Check `alloc.h` - this variable is
+used to track the allocated size of the list.
+
+Per entry, we find:
+
+`item` is the object provided upon which to base the object walk. Items in Git
+can be blobs, trees, commits, or tags. (See `Documentation/gittutorial-2.txt`.)
+
+`name` is the object ID (OID) of the object - a hex string you may be familiar
+with from using Git to organize your source in the past. Check the tutorial
+mentioned above towards the top for a discussion of where the OID can come
+from.
+
+`whence` indicates some information about what to do with the parents of the
+specified object. We'll explore this flag more later on; take a look at
+`Documentation/revisions.txt` to get an idea of what could set the `whence`
+value.
+
+`flags` are used to hint the beginning of the revision walk and are the first
+block under the `#include`s in `revision.h`. The most likely ones to be set in
+the `rev_cmdline_info` are `UNINTERESTING` and `BOTTOM`, but these same flags
+can be used during the walk, as well.
+
+=== `struct rev_info`
+
+This one is quite a bit longer, and many fields are only used during the walk
+by `revision.c` - not configuration options. Most of the configurable flags in
+`struct rev_info` have a mirror in `Documentation/rev-list-options.txt`. It's a
+good idea to take some time and read through that document.
+
+== Basic Commit Walk
+
+First, let's see if we can replicate the output of `git log --oneline`. We'll
+refer back to the implementation frequently to discover norms when performing
+an object walk of our own.
+
+To do so, we'll first find all the commits, in order, which preceded the current
+commit. We'll extract the name and subject of the commit from each.
+
+Ideally, we will also be able to find out which ones are currently at the tip of
+various branches.
+
+=== Setting Up
+
+Preparing for your object walk has some distinct stages.
+
+1. Perform default setup for this mode, and others which may be invoked.
+2. Check configuration files for relevant settings.
+3. Set up the `rev_info` struct.
+4. Tweak the initialized `rev_info` to suit the current walk.
+5. Prepare the `rev_info` for the walk.
+6. Iterate over the objects, processing each one.
+
+==== Default Setups
+
+Before examining configuration files which may modify command behavior, set up
+default state for switches or options your command may have. If your command
+utilizes other Git components, ask them to set up their default states as well.
+For instance, `git log` takes advantage of `grep` and `diff` functionality, so
+its `init_log_defaults()` sets its own state (`decoration_style`) and asks
+`grep` and `diff` to initialize themselves by calling each of their
+initialization functions.
+
+==== Configuring From `.gitconfig`
+
+Next, we should have a look at any relevant configuration settings (i.e.,
+settings readable and settable from `git config`). This is done by providing a
+callback to `git_config()`; within that callback, you can also invoke methods
+from other components you may need that need to intercept these options. Your
+callback will be invoked once per each configuration value which Git knows about
+(global, local, worktree, etc.).
+
+Similarly to the default values, we don't have anything to do here yet
+ourselves; however, we should call `git_default_config()` if we aren't calling
+any other existing config callbacks.
+
+Add a new function to `builtin/walken.c`.
+We'll also need to include the `config.h` header:
+
+----
+#include "config.h"
+
+...
+
+static int git_walken_config(const char *var, const char *value,
+			     const struct config_context *ctx, void *cb)
+{
+	/*
+	 * For now, we don't have any custom configuration, so fall back to
+	 * the default config.
+	 */
+	return git_default_config(var, value, ctx, cb);
+}
+----
+
+Make sure to invoke `git_config()` with it in your `cmd_walken()`:
+
+----
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+	...
+
+	git_config(git_walken_config, NULL);
+
+	...
+}
+----
+
+==== Setting Up `rev_info`
+
+Now that we've gathered external configuration and options, it's time to
+initialize the `rev_info` object which we will use to perform the walk. This is
+typically done by calling `repo_init_revisions()` with the repository you intend
+to target, as well as the `prefix` argument of `cmd_walken` and your `rev_info`
+struct.
+
+Add the `struct rev_info` and the `repo_init_revisions()` call.
+We'll also need to include the `revision.h` header:
+
+----
+#include "revision.h"
+
+...
+
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+	/* This can go wherever you like in your declarations.*/
+	struct rev_info rev;
+	...
+
+	/* This should go after the git_config() call. */
+	repo_init_revisions(the_repository, &rev, prefix);
+
+	...
+}
+----
+
+==== Tweaking `rev_info` For the Walk
+
+We're getting close, but we're still not quite ready to go. Now that `rev` is
+initialized, we can modify it to fit our needs. This is usually done within a
+helper for clarity, so let's add one:
+
+----
+static void final_rev_info_setup(struct rev_info *rev)
+{
+	/*
+	 * We want to mimic the appearance of `git log --oneline`, so let's
+	 * force oneline format.
+	 */
+	get_commit_format("oneline", rev);
+
+	/* Start our object walk at HEAD. */
+	add_head_to_pending(rev);
+}
+----
+
+[NOTE]
+====
+Instead of using the shorthand `add_head_to_pending()`, you could do
+something like this:
+----
+	struct setup_revision_opt opt;
+
+	memset(&opt, 0, sizeof(opt));
+	opt.def = "HEAD";
+	opt.revarg_opt = REVARG_COMMITTISH;
+	setup_revisions(argc, argv, rev, &opt);
+----
+Using a `setup_revision_opt` gives you finer control over your walk's starting
+point.
+====
+
+Then let's invoke `final_rev_info_setup()` after the call to
+`repo_init_revisions()`:
+
+----
+int cmd_walken(int argc, const char **argv, const char *prefix)
+{
+	...
+
+	final_rev_info_setup(&rev);
+
+	...
+}
+----
+
+Later, we may wish to add more arguments to `final_rev_info_setup()`. But for
+now, this is all we need.
+
+==== Preparing `rev_info` For the Walk
+
+Now that `rev` is all initialized and configured, we've got one more setup step
+before we get rolling. We can do this in a helper, which will both prepare the
+`rev_info` for the walk, and perform the walk itself. Let's start the helper
+with the call to `prepare_revision_walk()`, which can return an error without
+dying on its own:
+
+----
+static void walken_commit_walk(struct rev_info *rev)
+{
+	if (prepare_revision_walk(rev))
+		die(_("revision walk setup failed"));
+}
+----
+
+NOTE: `die()` prints to `stderr` and exits the program. Since it will print to
+`stderr` it's likely to be seen by a human, so we will localize it.
+
+==== Performing the Walk!
+
+Finally! We are ready to begin the walk itself. Now we can see that `rev_info`
+can also be used as an iterator; we move to the next item in the walk by using
+`get_revision()` repeatedly. Add the listed variable declarations at the top and
+the walk loop below the `prepare_revision_walk()` call within your
+`walken_commit_walk()`:
+
+----
+#include "pretty.h"
+
+...
+
+static void walken_commit_walk(struct rev_info *rev)
+{
+	struct commit *commit;
+	struct strbuf prettybuf = STRBUF_INIT;
+
+	...
+
+	while ((commit = get_revision(rev))) {
+		strbuf_reset(&prettybuf);
+		pp_commit_easy(CMIT_FMT_ONELINE, commit, &prettybuf);
+		puts(prettybuf.buf);
+	}
+	strbuf_release(&prettybuf);
+}
+----
+
+NOTE: `puts()` prints a `char*` to `stdout`. Since this is the part of the
+command we expect to be machine-parsed, we're sending it directly to stdout.
+
+Give it a shot.
+
+----
+$ make
+$ ./bin-wrappers/git walken
+----
+
+You should see all of the subject lines of all the commits in
+your tree's history, in order, ending with the initial commit, "Initial revision
+of "git", the information manager from hell". Congratulations! You've written
+your first revision walk. You can play with printing some additional fields
+from each commit if you're curious; have a look at the functions available in
+`commit.h`.
+
+=== Adding a Filter
+
+Next, let's try to filter the commits we see based on their author. This is
+equivalent to running `git log --author=<pattern>`. We can add a filter by
+modifying `rev_info.grep_filter`, which is a `struct grep_opt`.
+
+First some setup. Add `grep_config()` to `git_walken_config()`:
+
+----
+static int git_walken_config(const char *var, const char *value,
+			     const struct config_context *ctx, void *cb)
+{
+	grep_config(var, value, ctx, cb);
+	return git_default_config(var, value, ctx, cb);
+}
+----
+
+Next, we can modify the `grep_filter`. This is done with convenience functions
+found in `grep.h`. For fun, we're filtering to only commits from folks using a
+`gmail.com` email address - a not-very-precise guess at who may be working on
+Git as a hobby. Since we're checking the author, which is a specific line in the
+header, we'll use the `append_header_grep_pattern()` helper. We can use
+the `enum grep_header_field` to indicate which part of the commit header we want
+to search.
+
+In `final_rev_info_setup()`, add your filter line:
+
+----
+static void final_rev_info_setup(int argc, const char **argv,
+		const char *prefix, struct rev_info *rev)
+{
+	...
+
+	append_header_grep_pattern(&rev->grep_filter, GREP_HEADER_AUTHOR,
+		"gmail");
+	compile_grep_patterns(&rev->grep_filter);
+
+	...
+}
+----
+
+`append_header_grep_pattern()` adds your new "gmail" pattern to `rev_info`, but
+it won't work unless we compile it with `compile_grep_patterns()`.
+
+NOTE: If you are using `setup_revisions()` (for example, if you are passing a
+`setup_revision_opt` instead of using `add_head_to_pending()`), you don't need
+to call `compile_grep_patterns()` because `setup_revisions()` calls it for you.
+
+NOTE: We could add the same filter via the `append_grep_pattern()` helper if we
+wanted to, but `append_header_grep_pattern()` adds the `enum grep_context` and
+`enum grep_pat_token` for us.
+
+=== Changing the Order
+
+There are a few ways that we can change the order of the commits during a
+revision walk. Firstly, we can use the `enum rev_sort_order` to choose from some
+typical orderings.
+
+`topo_order` is the same as `git log --topo-order`: we avoid showing a parent
+before all of its children have been shown, and we avoid mixing commits which
+are in different lines of history. (`git help log`'s section on `--topo-order`
+has a very nice diagram to illustrate this.)
+
+Let's see what happens when we run with `REV_SORT_BY_COMMIT_DATE` as opposed to
+`REV_SORT_BY_AUTHOR_DATE`. Add the following:
+
+----
+static void final_rev_info_setup(int argc, const char **argv,
+		const char *prefix, struct rev_info *rev)
+{
+	...
+
+	rev->topo_order = 1;
+	rev->sort_order = REV_SORT_BY_COMMIT_DATE;
+
+	...
+}
+----
+
+Let's output this into a file so we can easily diff it with the walk sorted by
+author date.
+
+----
+$ make
+$ ./bin-wrappers/git walken > commit-date.txt
+----
+
+Then, let's sort by author date and run it again.
+
+----
+static void final_rev_info_setup(int argc, const char **argv,
+		const char *prefix, struct rev_info *rev)
+{
+	...
+
+	rev->topo_order = 1;
+	rev->sort_order = REV_SORT_BY_AUTHOR_DATE;
+
+	...
+}
+----
+
+----
+$ make
+$ ./bin-wrappers/git walken > author-date.txt
+----
+
+Finally, compare the two. This is a little less helpful without object names or
+dates, but hopefully we get the idea.
+
+----
+$ diff -u commit-date.txt author-date.txt
+----
+
+This display indicates that commits can be reordered after they're written, for
+example with `git rebase`.
+
+Let's try one more reordering of commits. `rev_info` exposes a `reverse` flag.
+Set that flag somewhere inside of `final_rev_info_setup()`:
+
+----
+static void final_rev_info_setup(int argc, const char **argv, const char *prefix,
+		struct rev_info *rev)
+{
+	...
+
+	rev->reverse = 1;
+
+	...
+}
+----
+
+Run your walk again and note the difference in order. (If you remove the grep
+pattern, you should see the last commit this call gives you as your current
+HEAD.)
+
+== Basic Object Walk
+
+So far we've been walking only commits. But Git has more types of objects than
+that! Let's see if we can walk _all_ objects, and find out some information
+about each one.
+
+We can base our work on an example. `git pack-objects` prepares all kinds of
+objects for packing into a bitmap or packfile. The work we are interested in
+resides in `builtin/pack-objects.c:get_object_list()`; examination of that
+function shows that the all-object walk is being performed by
+`traverse_commit_list()` or `traverse_commit_list_filtered()`. Those two
+functions reside in `list-objects.c`; examining the source shows that, despite
+the name, these functions traverse all kinds of objects. Let's have a look at
+the arguments to `traverse_commit_list()`.
+
+- `struct rev_info *revs`: This is the `rev_info` used for the walk. If
+  its `filter` member is not `NULL`, then `filter` contains information for
+  how to filter the object list.
+- `show_commit_fn show_commit`: A callback which will be used to handle each
+  individual commit object.
+- `show_object_fn show_object`: A callback which will be used to handle each
+  non-commit object (so each blob, tree, or tag).
+- `void *show_data`: A context buffer which is passed in turn to `show_commit`
+  and `show_object`.
+
+In addition, `traverse_commit_list_filtered()` has an additional parameter:
+
+- `struct oidset *omitted`: A linked-list of object IDs which the provided
+  filter caused to be omitted.
+
+It looks like these methods use callbacks we provide instead of needing us
+to call it repeatedly ourselves. Cool! Let's add the callbacks first.
+
+For the sake of this tutorial, we'll simply keep track of how many of each kind
+of object we find. At file scope in `builtin/walken.c` add the following
+tracking variables:
+
+----
+static int commit_count;
+static int tag_count;
+static int blob_count;
+static int tree_count;
+----
+
+Commits are handled by a different callback than other objects; let's do that
+one first:
+
+----
+static void walken_show_commit(struct commit *cmt, void *buf)
+{
+	commit_count++;
+}
+----
+
+The `cmt` argument is fairly self-explanatory. But it's worth mentioning that
+the `buf` argument is actually the context buffer that we can provide to the
+traversal calls - `show_data`, which we mentioned a moment ago.
+
+Since we have the `struct commit` object, we can look at all the same parts that
+we looked at in our earlier commit-only walk. For the sake of this tutorial,
+though, we'll just increment the commit counter and move on.
+
+The callback for non-commits is a little different, as we'll need to check
+which kind of object we're dealing with:
+
+----
+static void walken_show_object(struct object *obj, const char *str, void *buf)
+{
+	switch (obj->type) {
+	case OBJ_TREE:
+		tree_count++;
+		break;
+	case OBJ_BLOB:
+		blob_count++;
+		break;
+	case OBJ_TAG:
+		tag_count++;
+		break;
+	case OBJ_COMMIT:
+		BUG("unexpected commit object in walken_show_object\n");
+	default:
+		BUG("unexpected object type %s in walken_show_object\n",
+			type_name(obj->type));
+	}
+}
+----
+
+Again, `obj` is fairly self-explanatory, and we can guess that `buf` is the same
+context pointer that `walken_show_commit()` receives: the `show_data` argument
+to `traverse_commit_list()` and `traverse_commit_list_filtered()`. Finally,
+`str` contains the name of the object, which ends up being something like
+`foo.txt` (blob), `bar/baz` (tree), or `v1.2.3` (tag).
+
+To help assure us that we aren't double-counting commits, we'll include some
+complaining if a commit object is routed through our non-commit callback; we'll
+also complain if we see an invalid object type. Since those two cases should be
+unreachable, and would only change in the event of a semantic change to the Git
+codebase, we complain by using `BUG()` - which is a signal to a developer that
+the change they made caused unintended consequences, and the rest of the
+codebase needs to be updated to understand that change. `BUG()` is not intended
+to be seen by the public, so it is not localized.
+
+Our main object walk implementation is substantially different from our commit
+walk implementation, so let's make a new function to perform the object walk. We
+can perform setup which is applicable to all objects here, too, to keep separate
+from setup which is applicable to commit-only walks.
+
+We'll start by enabling all types of objects in the `struct rev_info`.  We'll
+also turn on `tree_blobs_in_commit_order`, which means that we will walk a
+commit's tree and everything it points to immediately after we find each commit,
+as opposed to waiting for the end and walking through all trees after the commit
+history has been discovered. With the appropriate settings configured, we are
+ready to call `prepare_revision_walk()`.
+
+----
+static void walken_object_walk(struct rev_info *rev)
+{
+	rev->tree_objects = 1;
+	rev->blob_objects = 1;
+	rev->tag_objects = 1;
+	rev->tree_blobs_in_commit_order = 1;
+
+	if (prepare_revision_walk(rev))
+		die(_("revision walk setup failed"));
+
+	commit_count = 0;
+	tag_count = 0;
+	blob_count = 0;
+	tree_count = 0;
+----
+
+Let's start by calling just the unfiltered walk and reporting our counts.
+Complete your implementation of `walken_object_walk()`.
+We'll also need to include the `list-objects.h` header.
+
+----
+#include "list-objects.h"
+
+...
+
+	traverse_commit_list(rev, walken_show_commit, walken_show_object, NULL);
+
+	printf("commits %d\nblobs %d\ntags %d\ntrees %d\n", commit_count,
+		blob_count, tag_count, tree_count);
+}
+----
+
+NOTE: This output is intended to be machine-parsed. Therefore, we are not
+sending it to `trace_printf()`, and we are not localizing it - we need scripts
+to be able to count on the formatting to be exactly the way it is shown here.
+If we were intending this output to be read by humans, we would need to localize
+it with `_()`.
+
+Finally, we'll ask `cmd_walken()` to use the object walk instead. Discussing
+command line options is out of scope for this tutorial, so we'll just hardcode
+a branch we can change at compile time. Where you call `final_rev_info_setup()`
+and `walken_commit_walk()`, instead branch like so:
+
+----
+	if (1) {
+		add_head_to_pending(&rev);
+		walken_object_walk(&rev);
+	} else {
+		final_rev_info_setup(argc, argv, prefix, &rev);
+		walken_commit_walk(&rev);
+	}
+----
+
+NOTE: For simplicity, we've avoided all the filters and sorts we applied in
+`final_rev_info_setup()` and simply added `HEAD` to our pending queue. If you
+want, you can certainly use the filters we added before by moving
+`final_rev_info_setup()` out of the conditional and removing the call to
+`add_head_to_pending()`.
+
+Now we can try to run our command! It should take noticeably longer than the
+commit walk, but an examination of the output will give you an idea why. Your
+output should look similar to this example, but with different counts:
+
+----
+Object walk completed. Found 55733 commits, 100274 blobs, 0 tags, and 104210 trees.
+----
+
+This makes sense. We have more trees than commits because the Git project has
+lots of subdirectories which can change, plus at least one tree per commit. We
+have no tags because we started on a commit (`HEAD`) and while tags can point to
+commits, commits can't point to tags.
+
+NOTE: You will have different counts when you run this yourself! The number of
+objects grows along with the Git project.
+
+=== Adding a Filter
+
+There are a handful of filters that we can apply to the object walk laid out in
+`Documentation/rev-list-options.txt`. These filters are typically useful for
+operations such as creating packfiles or performing a partial clone. They are
+defined in `list-objects-filter-options.h`. For the purposes of this tutorial we
+will use the "tree:1" filter, which causes the walk to omit all trees and blobs
+which are not directly referenced by commits reachable from the commit in
+`pending` when the walk begins. (`pending` is the list of objects which need to
+be traversed during a walk; you can imagine a breadth-first tree traversal to
+help understand. In our case, that means we omit trees and blobs not directly
+referenced by `HEAD` or `HEAD`'s history, because we begin the walk with only
+`HEAD` in the `pending` list.)
+
+For now, we are not going to track the omitted objects, so we'll replace those
+parameters with `NULL`. For the sake of simplicity, we'll add a simple
+build-time branch to use our filter or not. Preface the line calling
+`traverse_commit_list()` with the following, which will remind us which kind of
+walk we've just performed:
+
+----
+	if (0) {
+		/* Unfiltered: */
+		trace_printf(_("Unfiltered object walk.\n"));
+	} else {
+		trace_printf(
+			_("Filtered object walk with filterspec 'tree:1'.\n"));
+
+		parse_list_objects_filter(&rev->filter, "tree:1");
+	}
+	traverse_commit_list(rev, walken_show_commit,
+			     walken_show_object, NULL);
+----
+
+The `rev->filter` member is usually built directly from a command
+line argument, so the module provides an easy way to build one from a string.
+Even though we aren't taking user input right now, we can still build one with
+a hardcoded string using `parse_list_objects_filter()`.
+
+With the filter spec "tree:1", we are expecting to see _only_ the root tree for
+each commit; therefore, the tree object count should be less than or equal to
+the number of commits. (For an example of why that's true: `git commit --revert`
+points to the same tree object as its grandparent.)
+
+=== Counting Omitted Objects
+
+We also have the capability to enumerate all objects which were omitted by a
+filter, like with `git log --filter=<spec> --filter-print-omitted`. To do this,
+change `traverse_commit_list()` to `traverse_commit_list_filtered()`, which is
+able to populate an `omitted` list.  Asking for this list of filtered objects
+may cause performance degradations, however, because in this case, despite
+filtering objects, the possibly much larger set of all reachable objects must
+be processed in order to populate that list.
+
+First, add the `struct oidset` and related items we will use to iterate it:
+
+----
+#include "oidset.h"
+
+...
+
+static void walken_object_walk(
+	...
+
+	struct oidset omitted;
+	struct oidset_iter oit;
+	struct object_id *oid = NULL;
+	int omitted_count = 0;
+	oidset_init(&omitted, 0);
+
+	...
+----
+
+Replace the call to `traverse_commit_list()` with
+`traverse_commit_list_filtered()` and pass a pointer to the `omitted` oidset
+defined and initialized above:
+
+----
+	...
+
+		traverse_commit_list_filtered(rev,
+			walken_show_commit, walken_show_object, NULL, &omitted);
+
+	...
+----
+
+Then, after your traversal, the `oidset` traversal is pretty straightforward.
+Count all the objects within and modify the print statement:
+
+----
+	/* Count the omitted objects. */
+	oidset_iter_init(&omitted, &oit);
+
+	while ((oid = oidset_iter_next(&oit)))
+		omitted_count++;
+
+	printf("commits %d\nblobs %d\ntags %d\ntrees %d\nomitted %d\n",
+		commit_count, blob_count, tag_count, tree_count, omitted_count);
+----
+
+By running your walk with and without the filter, you should find that the total
+object count in each case is identical. You can also time each invocation of
+the `walken` subcommand, with and without `omitted` being passed in, to confirm
+to yourself the runtime impact of tracking all omitted objects.
+
+=== Changing the Order
+
+Finally, let's demonstrate that you can also reorder walks of all objects, not
+just walks of commits. First, we'll make our handlers chattier - modify
+`walken_show_commit()` and `walken_show_object()` to print the object as they
+go:
+
+----
+#include "hex.h"
+
+...
+
+static void walken_show_commit(struct commit *cmt, void *buf)
+{
+	trace_printf("commit: %s\n", oid_to_hex(&cmt->object.oid));
+	commit_count++;
+}
+
+static void walken_show_object(struct object *obj, const char *str, void *buf)
+{
+	trace_printf("%s: %s\n", type_name(obj->type), oid_to_hex(&obj->oid));
+
+	...
+}
+----
+
+NOTE: Since we will be examining this output directly as humans, we'll use
+`trace_printf()` here. Additionally, since this change introduces a significant
+number of printed lines, using `trace_printf()` will allow us to easily silence
+those lines without having to recompile.
+
+(Leave the counter increment logic in place.)
+
+With only that change, run again (but save yourself some scrollback):
+
+----
+$ GIT_TRACE=1 ./bin-wrappers/git walken 2>&1 | head -n 10
+----
+
+Take a look at the top commit with `git show` and the object ID you printed; it
+should be the same as the output of `git show HEAD`.
+
+Next, let's change a setting on our `struct rev_info` within
+`walken_object_walk()`. Find where you're changing the other settings on `rev`,
+such as `rev->tree_objects` and `rev->tree_blobs_in_commit_order`, and add the
+`reverse` setting at the bottom:
+
+----
+	...
+
+	rev->tree_objects = 1;
+	rev->blob_objects = 1;
+	rev->tag_objects = 1;
+	rev->tree_blobs_in_commit_order = 1;
+	rev->reverse = 1;
+
+	...
+----
+
+Now, run again, but this time, let's grab the last handful of objects instead
+of the first handful:
+
+----
+$ make
+$ GIT_TRACE=1 ./bin-wrappers/git walken 2>&1 | tail -n 10
+----
+
+The last commit object given should have the same OID as the one we saw at the
+top before, and running `git show <oid>` with that OID should give you again
+the same results as `git show HEAD`. Furthermore, if you run and examine the
+first ten lines again (with `head` instead of `tail` like we did before applying
+the `reverse` setting), you should see that now the first commit printed is the
+initial commit, `e83c5163`.
+
+== Wrapping Up
+
+Let's review. In this tutorial, we:
+
+- Built a commit walk from the ground up
+- Enabled a grep filter for that commit walk
+- Changed the sort order of that filtered commit walk
+- Built an object walk (tags, commits, trees, and blobs) from the ground up
+- Learned how to add a filter-spec to an object walk
+- Changed the display order of the filtered object walk
diff --git a/Documentation/RelNotes/1.5.0.1.txt b/Documentation/RelNotes/1.5.0.1.txt
new file mode 100644
index 0000000000..fea3f9935b
--- /dev/null
+++ b/Documentation/RelNotes/1.5.0.1.txt
@@ -0,0 +1,42 @@
+GIT v1.5.0.1 Release Notes
+==========================
+
+Fixes since v1.5.0
+------------------
+
+* Documentation updates
+
+  - Clarifications and corrections to 1.5.0 release notes.
+
+  - The main documentation did not link to git-remote documentation.
+
+  - Clarified introductory text of git-rebase documentation.
+
+  - Converted remaining mentions of update-index on Porcelain
+    documents to git-add/git-rm.
+
+  - Some i18n.* configuration variables were incorrectly
+    described as core.*; fixed.
+
+* Bugfixes
+
+  - git-add and git-update-index on a filesystem on which
+    executable bits are unreliable incorrectly reused st_mode
+    bits even when the path changed between symlink and regular
+    file.
+
+  - git-daemon marks the listening sockets with FD_CLOEXEC so
+    that it won't be leaked into the children.
+
+  - segfault from git-blame when the mandatory pathname
+    parameter was missing was fixed; usage() message is given
+    instead.
+
+  - git-rev-list did not read $GIT_DIR/config file, which means
+    that did not honor i18n.logoutputencoding correctly.
+
+* Tweaks
+
+  - sliding mmap() inefficiently mmaped the same region of a
+    packfile with an access pattern that used objects in the
+    reverse order.  This has been made more efficient.
diff --git a/Documentation/RelNotes/1.5.0.2.txt b/Documentation/RelNotes/1.5.0.2.txt
new file mode 100644
index 0000000000..b061e50ff0
--- /dev/null
+++ b/Documentation/RelNotes/1.5.0.2.txt
@@ -0,0 +1,65 @@
+GIT v1.5.0.2 Release Notes
+==========================
+
+Fixes since v1.5.0.1
+--------------------
+
+* Bugfixes
+
+  - Automated merge conflict handling when changes to symbolic
+    links conflicted were completely broken.  The merge-resolve
+    strategy created a regular file with conflict markers in it
+    in place of the symbolic link.  The default strategy,
+    merge-recursive was even more broken.  It removed the path
+    that was pointed at by the symbolic link.  Both of these
+    problems have been fixed.
+
+  - 'git diff maint master next' did not correctly give combined
+    diff across three trees.
+
+  - 'git fast-import' portability fix for Solaris.
+
+  - 'git show-ref --verify' without arguments did not error out
+    but segfaulted.
+
+  - 'git diff :tracked-file `pwd`/an-untracked-file' gave an extra
+    slashes after a/ and b/.
+
+  - 'git format-patch' produced too long filenames if the commit
+    message had too long line at the beginning.
+
+  - Running 'make all' and then without changing anything
+    running 'make install' still rebuilt some files.  This
+    was inconvenient when building as yourself and then
+    installing as root (especially problematic when the source
+    directory is on NFS and root is mapped to nobody).
+
+  - 'git-rerere' failed to deal with two unconflicted paths that
+    sorted next to each other.
+
+  - 'git-rerere' attempted to open(2) a symlink and failed if
+    there was a conflict.  Since a conflicting change to a
+    symlink would not benefit from rerere anyway, the command
+    now ignores conflicting changes to symlinks.
+
+  - 'git-repack' did not like to pass more than 64 arguments
+    internally to underlying 'rev-list' logic, which made it
+    impossible to repack after accumulating many (small) packs
+    in the repository.
+
+  - 'git-diff' to review the combined diff during a conflicted
+    merge were not reading the working tree version correctly
+    when changes to a symbolic link conflicted.  It should have
+    read the data using readlink(2) but read from the regular
+    file the symbolic link pointed at.
+
+  - 'git-remote' did not like period in a remote's name.
+
+* Documentation updates
+
+  - added and clarified core.bare, core.legacyheaders configurations.
+
+  - updated "git-clone --depth" documentation.
+
+
+* Assorted git-gui fixes.
diff --git a/Documentation/RelNotes/1.5.0.3.txt b/Documentation/RelNotes/1.5.0.3.txt
new file mode 100644
index 0000000000..cd500f96bf
--- /dev/null
+++ b/Documentation/RelNotes/1.5.0.3.txt
@@ -0,0 +1,58 @@
+GIT v1.5.0.3 Release Notes
+==========================
+
+Fixes since v1.5.0.2
+--------------------
+
+* Bugfixes
+
+  - 'git.el' honors the commit coding system from the configuration.
+
+  - 'blameview' in contrib/ correctly digs deeper when a line is
+    clicked.
+
+  - 'http-push' correctly makes sure the remote side has leading
+    path.  Earlier it started in the middle of the path, and
+    incorrectly.
+
+  - 'git-merge' did not exit with non-zero status when the
+    working tree was dirty and cannot fast forward.  It does
+    now.
+
+  - 'cvsexportcommit' does not lose yet-to-be-used message file.
+
+  - int-vs-size_t typefix when running combined diff on files
+    over 2GB long.
+
+  - 'git apply --whitespace=strip' should not touch unmodified
+    lines.
+
+  - 'git-mailinfo' choke when a logical header line was too long.
+
+  - 'git show A..B' did not error out.  Negative ref ("not A" in
+    this example) does not make sense for the purpose of the
+    command, so now it errors out.
+
+  - 'git fmt-merge-msg --file' without file parameter did not
+    correctly error out.
+
+  - 'git archimport' barfed upon encountering a commit without
+    summary.
+
+  - 'git index-pack' did not protect itself from getting a short
+    read out of pread(2).
+
+  - 'git http-push' had a few buffer overruns.
+
+  - Build dependency fixes to rebuild fetch.o when other headers
+    change.
+
+* Documentation updates
+
+  - user-manual updates.
+
+  - Options to 'git remote add' were described insufficiently.
+
+  - Configuration format.suffix was not documented.
+
+  - Other formatting and spelling fixes.
diff --git a/Documentation/RelNotes/1.5.0.4.txt b/Documentation/RelNotes/1.5.0.4.txt
new file mode 100644
index 0000000000..feefa5dfd4
--- /dev/null
+++ b/Documentation/RelNotes/1.5.0.4.txt
@@ -0,0 +1,22 @@
+GIT v1.5.0.4 Release Notes
+==========================
+
+Fixes since v1.5.0.3
+--------------------
+
+* Bugfixes
+
+  - git.el does not add duplicate sign-off lines.
+
+  - git-commit shows the full stat of the resulting commit, not
+    just about the files in the current directory, when run from
+    a subdirectory.
+
+  - "git-checkout -m '@{8 hours ago}'" had a funny failure from
+    eval; fixed.
+
+  - git-gui updates.
+
+* Documentation updates
+
+* User manual updates
diff --git a/Documentation/RelNotes/1.5.0.5.txt b/Documentation/RelNotes/1.5.0.5.txt
new file mode 100644
index 0000000000..eeec3d73d0
--- /dev/null
+++ b/Documentation/RelNotes/1.5.0.5.txt
@@ -0,0 +1,26 @@
+GIT v1.5.0.5 Release Notes
+==========================
+
+Fixes since v1.5.0.3
+--------------------
+
+* Bugfixes
+
+  - git-merge (hence git-pull) did not refuse fast-forwarding
+    when the working tree had local changes that would have
+    conflicted with it.
+
+  - git.el does not add duplicate sign-off lines.
+
+  - git-commit shows the full stat of the resulting commit, not
+    just about the files in the current directory, when run from
+    a subdirectory.
+
+  - "git-checkout -m '@{8 hours ago}'" had a funny failure from
+    eval; fixed.
+
+  - git-gui updates.
+
+* Documentation updates
+
+* User manual updates
diff --git a/Documentation/RelNotes/1.5.0.6.txt b/Documentation/RelNotes/1.5.0.6.txt
new file mode 100644
index 0000000000..c02015ad5f
--- /dev/null
+++ b/Documentation/RelNotes/1.5.0.6.txt
@@ -0,0 +1,21 @@
+GIT v1.5.0.6 Release Notes
+==========================
+
+Fixes since v1.5.0.5
+--------------------
+
+* Bugfixes
+
+  - a handful small fixes to gitweb.
+
+  - build procedure for user-manual is fixed not to require locally
+    installed stylesheets.
+
+  - "git commit $paths" on paths whose earlier contents were
+    already updated in the index were failing out.
+
+* Documentation
+
+  - user-manual has better cross references.
+
+  - gitweb installation/deployment procedure is now documented.
diff --git a/Documentation/RelNotes/1.5.0.7.txt b/Documentation/RelNotes/1.5.0.7.txt
new file mode 100644
index 0000000000..670ad32b85
--- /dev/null
+++ b/Documentation/RelNotes/1.5.0.7.txt
@@ -0,0 +1,18 @@
+GIT v1.5.0.7 Release Notes
+==========================
+
+Fixes since v1.5.0.6
+--------------------
+
+* Bugfixes
+
+  - git-upload-pack failed to close unused pipe ends, resulting
+    in many zombies to hang around.
+
+  - git-rerere was recording the contents of earlier hunks
+    duplicated in later hunks.  This prevented resolving the same
+    conflict when performing the same merge the other way around.
+
+* Documentation
+
+  - a few documentation fixes from Debian package maintainer.
diff --git a/Documentation/RelNotes/1.5.0.txt b/Documentation/RelNotes/1.5.0.txt
new file mode 100644
index 0000000000..d6d42f3183
--- /dev/null
+++ b/Documentation/RelNotes/1.5.0.txt
@@ -0,0 +1,469 @@
+GIT v1.5.0 Release Notes
+========================
+
+Old news
+--------
+
+This section is for people who are upgrading from ancient
+versions of git.  Although all of the changes in this section
+happened before the current v1.4.4 release, they are summarized
+here in the v1.5.0 release notes for people who skipped earlier
+versions.
+
+As of git v1.5.0 there are some optional features that changes
+the repository to allow data to be stored and transferred more
+efficiently.  These features are not enabled by default, as they
+will make the repository unusable with older versions of git.
+Specifically, the available options are:
+
+ - There is a configuration variable core.legacyheaders that
+   changes the format of loose objects so that they are more
+   efficient to pack and to send out of the repository over git
+   native protocol, since v1.4.2.  However, loose objects
+   written in the new format cannot be read by git older than
+   that version; people fetching from your repository using
+   older clients over dumb transports (e.g. http) using older
+   versions of git will also be affected.
+
+   To let git use the new loose object format, you have to
+   set core.legacyheaders to false.
+
+ - Since v1.4.3, configuration repack.usedeltabaseoffset allows
+   packfile to be created in more space efficient format, which
+   cannot be read by git older than that version.
+
+   To let git use the new format for packfiles, you have to
+   set repack.usedeltabaseoffset to true.
+
+The above two new features are not enabled by default and you
+have to explicitly ask for them, because they make repositories
+unreadable by older versions of git, and in v1.5.0 we still do
+not enable them by default for the same reason.  We will change
+this default probably 1 year after 1.4.2's release, when it is
+reasonable to expect everybody to have new enough version of
+git.
+
+ - 'git pack-refs' appeared in v1.4.4; this command allows tags
+   to be accessed much more efficiently than the traditional
+   'one-file-per-tag' format.  Older git-native clients can
+   still fetch from a repository that packed and pruned refs
+   (the server side needs to run the up-to-date version of git),
+   but older dumb transports cannot.  Packing of refs is done by
+   an explicit user action, either by use of "git pack-refs
+   --prune" command or by use of "git gc" command.
+
+ - 'git -p' to paginate anything -- many commands do pagination
+   by default on a tty.  Introduced between v1.4.1 and v1.4.2;
+   this may surprise old timers.
+
+ - 'git archive' superseded 'git tar-tree' in v1.4.3;
+
+ - 'git cvsserver' was new invention in v1.3.0;
+
+ - 'git repo-config', 'git grep', 'git rebase' and 'gitk' were
+   seriously enhanced during v1.4.0 timeperiod.
+
+ - 'gitweb' became part of git.git during v1.4.0 timeperiod and
+   seriously modified since then.
+
+ - reflog is an v1.4.0 invention.  This allows you to name a
+   revision that a branch used to be at (e.g. "git diff
+   master@{yesterday} master" allows you to see changes since
+   yesterday's tip of the branch).
+
+
+Updates in v1.5.0 since v1.4.4 series
+-------------------------------------
+
+* Index manipulation
+
+ - git-add is to add contents to the index (aka "staging area"
+   for the next commit), whether the file the contents happen to
+   be is an existing one or a newly created one.
+
+ - git-add without any argument does not add everything
+   anymore.  Use 'git-add .' instead.  Also you can add
+   otherwise ignored files with an -f option.
+
+ - git-add tries to be more friendly to users by offering an
+   interactive mode ("git-add -i").
+
+ - git-commit <path> used to refuse to commit if <path> was
+   different between HEAD and the index (i.e. update-index was
+   used on it earlier).  This check was removed.
+
+ - git-rm is much saner and safer.  It is used to remove paths
+   from both the index file and the working tree, and makes sure
+   you are not losing any local modification before doing so.
+
+ - git-reset <tree> <paths>... can be used to revert index
+   entries for selected paths.
+
+ - git-update-index is much less visible.  Many suggestions to
+   use the command in git output and documentation have now been
+   replaced by simpler commands such as "git add" or "git rm".
+
+
+* Repository layout and objects transfer
+
+ - The data for origin repository is stored in the configuration
+   file $GIT_DIR/config, not in $GIT_DIR/remotes/, for newly
+   created clones.  The latter is still supported and there is
+   no need to convert your existing repository if you are
+   already comfortable with your workflow with the layout.
+
+ - git-clone always uses what is known as "separate remote"
+   layout for a newly created repository with a working tree.
+
+   A repository with the separate remote layout starts with only
+   one default branch, 'master', to be used for your own
+   development.  Unlike the traditional layout that copied all
+   the upstream branches into your branch namespace (while
+   renaming their 'master' to your 'origin'), the new layout
+   puts upstream branches into local "remote-tracking branches"
+   with their own namespace. These can be referenced with names
+   such as "origin/$upstream_branch_name" and are stored in
+   .git/refs/remotes rather than .git/refs/heads where normal
+   branches are stored.
+
+   This layout keeps your own branch namespace less cluttered,
+   avoids name collision with your upstream, makes it possible
+   to automatically track new branches created at the remote
+   after you clone from it, and makes it easier to interact with
+   more than one remote repository (you can use "git remote" to
+   add other repositories to track).  There might be some
+   surprises:
+
+   * 'git branch' does not show the remote tracking branches.
+     It only lists your own branches.  Use '-r' option to view
+     the tracking branches.
+
+   * If you are forking off of a branch obtained from the
+     upstream, you would have done something like 'git branch
+     my-next next', because traditional layout dropped the
+     tracking branch 'next' into your own branch namespace.
+     With the separate remote layout, you say 'git branch next
+     origin/next', which allows you to use the matching name
+     'next' for your own branch.  It also allows you to track a
+     remote other than 'origin' (i.e. where you initially cloned
+     from) and fork off of a branch from there the same way
+     (e.g. "git branch mingw j6t/master").
+
+   Repositories initialized with the traditional layout continue
+   to work.
+
+ - New branches that appear on the origin side after a clone is
+   made are also tracked automatically.  This is done with an
+   wildcard refspec "refs/heads/*:refs/remotes/origin/*", which
+   older git does not understand, so if you clone with 1.5.0,
+   you would need to downgrade remote.*.fetch in the
+   configuration file to specify each branch you are interested
+   in individually if you plan to fetch into the repository with
+   older versions of git (but why would you?).
+
+ - Similarly, wildcard refspec "refs/heads/*:refs/remotes/me/*"
+   can be given to "git-push" command to update the tracking
+   branches that is used to track the repository you are pushing
+   from on the remote side.
+
+ - git-branch and git-show-branch know remote tracking branches
+   (use the command line switch "-r" to list only tracked branches).
+
+ - git-push can now be used to delete a remote branch or a tag.
+   This requires the updated git on the remote side (use "git
+   push <remote> :refs/heads/<branch>" to delete "branch").
+
+ - git-push more aggressively keeps the transferred objects
+   packed.  Earlier we recommended to monitor amount of loose
+   objects and repack regularly, but you should repack when you
+   accumulated too many small packs this way as well.  Updated
+   git-count-objects helps you with this.
+
+ - git-fetch also more aggressively keeps the transferred objects
+   packed.  This behavior of git-push and git-fetch can be
+   tweaked with a single configuration transfer.unpacklimit (but
+   usually there should not be any need for a user to tweak it).
+
+ - A new command, git-remote, can help you manage your remote
+   tracking branch definitions.
+
+ - You may need to specify explicit paths for upload-pack and/or
+   receive-pack due to your ssh daemon configuration on the
+   other end.  This can now be done via remote.*.uploadpack and
+   remote.*.receivepack configuration.
+
+
+* Bare repositories
+
+ - Certain commands change their behavior in a bare repository
+   (i.e. a repository without associated working tree).  We use
+   a fairly conservative heuristic (if $GIT_DIR is ".git", or
+   ends with "/.git", the repository is not bare) to decide if a
+   repository is bare, but "core.bare" configuration variable
+   can be used to override the heuristic when it misidentifies
+   your repository.
+
+ - git-fetch used to complain updating the current branch but
+   this is now allowed for a bare repository.  So is the use of
+   'git-branch -f' to update the current branch.
+
+ - Porcelain-ish commands that require a working tree refuses to
+   work in a bare repository.
+
+
+* Reflog
+
+ - Reflog records the history from the view point of the local
+   repository. In other words, regardless of the real history,
+   the reflog shows the history as seen by one particular
+   repository (this enables you to ask "what was the current
+   revision in _this_ repository, yesterday at 1pm?").  This
+   facility is enabled by default for repositories with working
+   trees, and can be accessed with the "branch@{time}" and
+   "branch@{Nth}" notation.
+
+ - "git show-branch" learned showing the reflog data with the
+   new -g option.  "git log" has -g option to view reflog
+   entries in a more verbose manner.
+
+ - git-branch knows how to rename branches and moves existing
+   reflog data from the old branch to the new one.
+
+ - In addition to the reflog support in v1.4.4 series, HEAD
+   reference maintains its own log.  "HEAD@{5.minutes.ago}"
+   means the commit you were at 5 minutes ago, which takes
+   branch switching into account.  If you want to know where the
+   tip of your current branch was at 5 minutes ago, you need to
+   explicitly say its name (e.g. "master@{5.minutes.ago}") or
+   omit the refname altogether i.e. "@{5.minutes.ago}".
+
+ - The commits referred to by reflog entries are now protected
+   against pruning.  The new command "git reflog expire" can be
+   used to truncate older reflog entries and entries that refer
+   to commits that have been pruned away previously with older
+   versions of git.
+
+   Existing repositories that have been using reflog may get
+   complaints from fsck-objects and may not be able to run
+   git-repack, if you had run git-prune from older git; please
+   run "git reflog expire --stale-fix --all" first to remove
+   reflog entries that refer to commits that are no longer in
+   the repository when that happens.
+
+
+* Cruft removal
+
+ - We used to say "old commits are retrievable using reflog and
+   'master@{yesterday}' syntax as long as you haven't run
+   git-prune".  We no longer have to say the latter half of the
+   above sentence, as git-prune does not remove things reachable
+   from reflog entries.
+
+ - There is a toplevel garbage collector script, 'git-gc', that
+   runs periodic cleanup functions, including 'git-repack -a -d',
+   'git-reflog expire', 'git-pack-refs --prune', and 'git-rerere
+   gc'.
+
+ - The output from fsck ("fsck-objects" is called just "fsck"
+   now, but the old name continues to work) was needlessly
+   alarming in that it warned missing objects that are reachable
+   only from dangling objects.  This has been corrected and the
+   output is much more useful.
+
+
+* Detached HEAD
+
+ - You can use 'git-checkout' to check out an arbitrary revision
+   or a tag as well, instead of named branches.  This will
+   dissociate your HEAD from the branch you are currently on.
+
+   A typical use of this feature is to "look around".  E.g.
+
+	$ git checkout v2.6.16
+	... compile, test, etc.
+	$ git checkout v2.6.17
+	... compile, test, etc.
+
+ - After detaching your HEAD, you can go back to an existing
+   branch with usual "git checkout $branch".  Also you can
+   start a new branch using "git checkout -b $newbranch" to
+   start a new branch at that commit.
+
+ - You can even pull from other repositories, make merges and
+   commits while your HEAD is detached.  Also you can use "git
+   reset" to jump to arbitrary commit, while still keeping your
+   HEAD detached.
+
+   Remember that a detached state is volatile, i.e. it will be forgotten
+   as soon as you move away from it with the checkout or reset command,
+   unless a branch is created from it as mentioned above.  It is also
+   possible to rescue a lost detached state from the HEAD reflog.
+
+
+* Packed refs
+
+ - Repositories with hundreds of tags have been paying large
+   overhead, both in storage and in runtime, due to the
+   traditional one-ref-per-file format.  A new command,
+   git-pack-refs, can be used to "pack" them in more efficient
+   representation (you can let git-gc do this for you).
+
+ - Clones and fetches over dumb transports are now aware of
+   packed refs and can download from repositories that use
+   them.
+
+
+* Configuration
+
+ - configuration related to color setting are consolidated under
+   color.* namespace (older diff.color.*, status.color.* are
+   still supported).
+
+ - 'git-repo-config' command is accessible as 'git-config' now.
+
+
+* Updated features
+
+ - git-describe uses better criteria to pick a base ref.  It
+   used to pick the one with the newest timestamp, but now it
+   picks the one that is topologically the closest (that is,
+   among ancestors of commit C, the ref T that has the shortest
+   output from "git-rev-list T..C" is chosen).
+
+ - git-describe gives the number of commits since the base ref
+   between the refname and the hash suffix.  E.g. the commit one
+   before v2.6.20-rc6 in the kernel repository is:
+
+	v2.6.20-rc5-306-ga21b069
+
+   which tells you that its object name begins with a21b069,
+   v2.6.20-rc5 is an ancestor of it (meaning, the commit
+   contains everything -rc5 has), and there are 306 commits
+   since v2.6.20-rc5.
+
+ - git-describe with --abbrev=0 can be used to show only the
+   name of the base ref.
+
+ - git-blame learned a new option, --incremental, that tells it
+   to output the blames as they are assigned.  A sample script
+   to use it is also included as contrib/blameview.
+
+ - git-blame starts annotating from the working tree by default.
+
+
+* Less external dependency
+
+ - We no longer require the "merge" program from the RCS suite.
+   All 3-way file-level merges are now done internally.
+
+ - The original implementation of git-merge-recursive which was
+   in Python has been removed; we have a C implementation of it
+   now.
+
+ - git-shortlog is no longer a Perl script.  It no longer
+   requires output piped from git-log; it can accept revision
+   parameters directly on the command line.
+
+
+* I18n
+
+ - We have always encouraged the commit message to be encoded in
+   UTF-8, but the users are allowed to use legacy encoding as
+   appropriate for their projects.  This will continue to be the
+   case.  However, a non UTF-8 commit encoding _must_ be
+   explicitly set with i18n.commitencoding in the repository
+   where a commit is made; otherwise git-commit-tree will
+   complain if the log message does not look like a valid UTF-8
+   string.
+
+ - The value of i18n.commitencoding in the originating
+   repository is recorded in the commit object on the "encoding"
+   header, if it is not UTF-8.  git-log and friends notice this,
+   and re-encodes the message to the log output encoding when
+   displaying, if they are different.  The log output encoding
+   is determined by "git log --encoding=<encoding>",
+   i18n.logoutputencoding configuration, or i18n.commitencoding
+   configuration, in the decreasing order of preference, and
+   defaults to UTF-8.
+
+ - Tools for e-mailed patch application now default to -u
+   behavior; i.e. it always re-codes from the e-mailed encoding
+   to the encoding specified with i18n.commitencoding.  This
+   unfortunately forces projects that have happily been using a
+   legacy encoding without setting i18n.commitencoding to set
+   the configuration, but taken with other improvement, please
+   excuse us for this very minor one-time inconvenience.
+
+
+* e-mailed patches
+
+ - See the above I18n section.
+
+ - git-format-patch now enables --binary without being asked.
+   git-am does _not_ default to it, as sending binary patch via
+   e-mail is unusual and is harder to review than textual
+   patches and it is prudent to require the person who is
+   applying the patch to explicitly ask for it.
+
+ - The default suffix for git-format-patch output is now ".patch",
+   not ".txt".  This can be changed with --suffix=.txt option,
+   or setting the config variable "format.suffix" to ".txt".
+
+
+* Foreign SCM interfaces
+
+ - git-svn now requires the Perl SVN:: libraries, the
+   command-line backend was too slow and limited.
+
+ - the 'commit' subcommand of git-svn has been renamed to
+   'set-tree', and 'dcommit' is the recommended replacement for
+   day-to-day work.
+
+ - git fast-import backend.
+
+
+* User support
+
+ - Quite a lot of documentation updates.
+
+ - Bash completion scripts have been updated heavily.
+
+ - Better error messages for often used Porcelainish commands.
+
+ - Git GUI.  This is a simple Tk based graphical interface for
+   common Git operations.
+
+
+* Sliding mmap
+
+ - We used to assume that we can mmap the whole packfile while
+   in use, but with a large project this consumes huge virtual
+   memory space and truly huge ones would not fit in the
+   userland address space on 32-bit platforms.  We now mmap huge
+   packfile in pieces to avoid this problem.
+
+
+* Shallow clones
+
+ - There is a partial support for 'shallow' repositories that
+   keeps only recent history.  A 'shallow clone' is created by
+   specifying how deep that truncated history should be
+   (e.g. "git clone --depth 5 git://some.where/repo.git").
+
+   Currently a shallow repository has number of limitations:
+
+   - Cloning and fetching _from_ a shallow clone are not
+     supported (nor tested -- so they might work by accident but
+     they are not expected to).
+
+   - Pushing from nor into a shallow clone are not expected to
+     work.
+
+   - Merging inside a shallow repository would work as long as a
+     merge base is found in the recent history, but otherwise it
+     will be like merging unrelated histories and may result in
+     huge conflicts.
+
+   but this would be more than adequate for people who want to
+   look at near the tip of a big project with a deep history and
+   send patches in e-mail format.
diff --git a/Documentation/RelNotes/1.5.1.1.txt b/Documentation/RelNotes/1.5.1.1.txt
new file mode 100644
index 0000000000..91471213bd
--- /dev/null
+++ b/Documentation/RelNotes/1.5.1.1.txt
@@ -0,0 +1,65 @@
+GIT v1.5.1.1 Release Notes
+==========================
+
+Fixes since v1.5.1
+------------------
+
+* Documentation updates
+
+  - The --left-right option of rev-list and friends is documented.
+
+  - The documentation for cvsimport has been majorly improved.
+
+  - "git-show-ref --exclude-existing" was documented.
+
+* Bugfixes
+
+  - The implementation of -p option in "git cvsexportcommit" had
+    the meaning of -C (context reduction) option wrong, and
+    loosened the context requirements when it was told to be
+    strict.
+
+  - "git cvsserver" did not behave like the real cvsserver when
+    client side removed a file from the working tree without
+    doing anything else on the path.  In such a case, it should
+    restore it from the checked out revision.
+
+  - "git fsck" issued an alarming error message on detached
+    HEAD.  It is not an error since at least 1.5.0.
+
+  - "git send-email" produced of References header of unbounded length;
+    fixed this with line-folding.
+
+  - "git archive" to download from remote site should not
+    require you to be in a git repository, but it incorrectly
+    did.
+
+  - "git apply" ignored -p<n> for "diff --git" formatted
+    patches.
+
+  - "git rerere" recorded a conflict that had one side empty
+    (the other side adds) incorrectly; this made merging in the
+    other direction fail to use previously recorded resolution.
+
+  - t4200 test was broken where "wc -l" pads its output with
+    spaces.
+
+  - "git branch -m old new" to rename branch did not work
+    without a configuration file in ".git/config".
+
+  - The sample hook for notification e-mail was misnamed.
+
+  - gitweb did not show type-changing patch correctly in the
+    blobdiff view.
+
+  - git-svn did not error out with incorrect command line options.
+
+  - git-svn fell into an infinite loop when insanely long commit
+    message was found.
+
+  - git-svn dcommit and rebase was confused by patches that were
+    merged from another branch that is managed by git-svn.
+
+  - git-svn used to get confused when globbing remote branch/tag
+    spec (e.g. "branches = proj/branches/*:refs/remotes/origin/*")
+    is used and there was a plain file that matched the glob.
diff --git a/Documentation/RelNotes/1.5.1.2.txt b/Documentation/RelNotes/1.5.1.2.txt
new file mode 100644
index 0000000000..d88456306c
--- /dev/null
+++ b/Documentation/RelNotes/1.5.1.2.txt
@@ -0,0 +1,50 @@
+GIT v1.5.1.2 Release Notes
+==========================
+
+Fixes since v1.5.1.1
+--------------------
+
+* Bugfixes
+
+  - "git clone" over http from a repository that has lost the
+    loose refs by running "git pack-refs" were broken (a code to
+    deal with this was added to "git fetch" in v1.5.0, but it
+    was missing from "git clone").
+
+  - "git diff a/ b/" incorrectly fell in "diff between two
+    filesystem objects" codepath, when the user most likely
+    wanted to limit the extent of output to two tracked
+    directories.
+
+  - git-quiltimport had the same bug as we fixed for
+    git-applymbox in v1.5.1.1 -- it gave an alarming "did not
+    have any patch" message (but did not actually fail and was
+    harmless).
+
+  - various git-svn fixes.
+
+  - Sample update hook incorrectly always refused requests to
+    delete branches through push.
+
+  - git-blame on a very long working tree path had buffer
+    overrun problem.
+
+  - git-apply did not like to be fed two patches in a row that created
+    and then modified the same file.
+
+  - git-svn was confused when a non-project was stored directly under
+    trunk/, branches/ and tags/.
+
+  - git-svn wants the Error.pm module that was at least as new
+    as what we ship as part of git; install ours in our private
+    installation location if the one on the system is older.
+
+  - An earlier update to command line integer parameter parser was
+    botched and made 'update-index --cacheinfo' completely useless.
+
+
+* Documentation updates
+
+  - Various documentation updates from J. Bruce Fields, Frank
+    Lichtenheld, Alex Riesen and others.  Andrew Ruder started a
+    war on undocumented options.
diff --git a/Documentation/RelNotes/1.5.1.3.txt b/Documentation/RelNotes/1.5.1.3.txt
new file mode 100644
index 0000000000..876408b65a
--- /dev/null
+++ b/Documentation/RelNotes/1.5.1.3.txt
@@ -0,0 +1,45 @@
+GIT v1.5.1.3 Release Notes
+==========================
+
+Fixes since v1.5.1.2
+--------------------
+
+* Bugfixes
+
+  - git-add tried to optimize by finding common leading
+    directories across its arguments but botched, causing very
+    confused behaviour.
+
+  - unofficial rpm.spec file shipped with git was letting
+    ETC_GITCONFIG set to /usr/etc/gitconfig.  Tweak the official
+    Makefile to make it harder for distro people to make the
+    same mistake, by setting the variable to /etc/gitconfig if
+    prefix is set to /usr.
+
+  - git-svn inconsistently stripped away username from the URL
+    only when svnsync_props was in use.
+
+  - git-svn got confused when handling symlinks on Mac OS.
+
+  - git-send-email was not quoting recipient names that have
+    period '.' in them.  Also it did not allow overriding
+    envelope sender, which made it impossible to send patches to
+    certain subscriber-only lists.
+
+  - built-in write_tree() routine had a sequence that renamed a
+    file that is still open, which some systems did not like.
+
+  - when memory is very tight, sliding mmap code to read
+    packfiles incorrectly closed the fd that was still being
+    used to read the pack.
+
+  - import-tars contributed front-end for fastimport was passing
+    wrong directory modes without checking.
+
+  - git-fastimport trusted its input too much and allowed to
+    create corrupt tree objects with entries without a name.
+
+  - git-fetch needlessly barfed when too long reflog action
+    description was given by the caller.
+
+Also contains various documentation updates.
diff --git a/Documentation/RelNotes/1.5.1.4.txt b/Documentation/RelNotes/1.5.1.4.txt
new file mode 100644
index 0000000000..df2f66ccb5
--- /dev/null
+++ b/Documentation/RelNotes/1.5.1.4.txt
@@ -0,0 +1,30 @@
+GIT v1.5.1.4 Release Notes
+==========================
+
+Fixes since v1.5.1.3
+--------------------
+
+* Bugfixes
+
+  - "git-http-fetch" did not work around a bug in libcurl
+    earlier than 7.16 (curl_multi_remove_handle() was broken).
+
+  - "git cvsserver" handles a file that was once removed and
+    then added again correctly.
+
+  - import-tars script (in contrib/) handles GNU tar archives
+    that contain pathnames longer than 100 bytes (long-link
+    extension) correctly.
+
+  - xdelta test program did not build correctly.
+
+  - gitweb sometimes tried incorrectly to apply function to
+    decode utf8 twice, resulting in corrupt output.
+
+  - "git blame -C" mishandled text at the end of a group of
+    lines.
+
+  - "git log/rev-list --boundary" did not produce output
+    correctly without --left-right option.
+
+  - Many documentation updates.
diff --git a/Documentation/RelNotes/1.5.1.5.txt b/Documentation/RelNotes/1.5.1.5.txt
new file mode 100644
index 0000000000..b0ab8eb371
--- /dev/null
+++ b/Documentation/RelNotes/1.5.1.5.txt
@@ -0,0 +1,42 @@
+GIT v1.5.1.5 Release Notes
+==========================
+
+Fixes since v1.5.1.4
+--------------------
+
+* Bugfixes
+
+  - git-send-email did not understand aliases file for mutt, which
+    allows leading whitespaces.
+
+  - git-format-patch emitted Content-Type and Content-Transfer-Encoding
+    headers for non ASCII contents, but failed to add MIME-Version.
+
+  - git-name-rev had a buffer overrun with a deep history.
+
+  - contributed script import-tars did not get the directory in
+    tar archives interpreted correctly.
+
+  - git-svn was reported to segfault for many people on list and
+    #git; hopefully this has been fixed.
+
+  - "git-svn clone" does not try to minimize the URL
+    (i.e. connect to higher level hierarchy) by default, as this
+    can prevent clone to fail if only part of the repository
+    (e.g. 'trunk') is open to public.
+
+  - "git checkout branch^0" did not detach the head when you are
+    already on 'branch'; backported the fix from the 'master'.
+
+  - "git-config section.var" did not correctly work when
+    existing configuration file had both [section] and [section "name"]
+    next to each other.
+
+  - "git clone ../other-directory" was fooled if the current
+    directory $PWD points at is a symbolic link.
+
+  - (build) tree_entry_extract() function was both static inline
+    and extern, which caused trouble compiling with Forte12
+    compilers on Sun.
+
+  - Many many documentation fixes and updates.
diff --git a/Documentation/RelNotes/1.5.1.6.txt b/Documentation/RelNotes/1.5.1.6.txt
new file mode 100644
index 0000000000..55f3ac13e3
--- /dev/null
+++ b/Documentation/RelNotes/1.5.1.6.txt
@@ -0,0 +1,45 @@
+GIT v1.5.1.6 Release Notes
+==========================
+
+Fixes since v1.5.1.4
+--------------------
+
+* Bugfixes
+
+  - git-send-email did not understand aliases file for mutt, which
+    allows leading whitespaces.
+
+  - git-format-patch emitted Content-Type and Content-Transfer-Encoding
+    headers for non ASCII contents, but failed to add MIME-Version.
+
+  - git-name-rev had a buffer overrun with a deep history.
+
+  - contributed script import-tars did not get the directory in
+    tar archives interpreted correctly.
+
+  - git-svn was reported to segfault for many people on list and
+    #git; hopefully this has been fixed.
+
+  - git-svn also had a bug to crash svnserve by sending a bad
+    sequence of requests.
+
+  - "git-svn clone" does not try to minimize the URL
+    (i.e. connect to higher level hierarchy) by default, as this
+    can prevent clone to fail if only part of the repository
+    (e.g. 'trunk') is open to public.
+
+  - "git checkout branch^0" did not detach the head when you are
+    already on 'branch'; backported the fix from the 'master'.
+
+  - "git-config section.var" did not correctly work when
+    existing configuration file had both [section] and [section "name"]
+    next to each other.
+
+  - "git clone ../other-directory" was fooled if the current
+    directory $PWD points at is a symbolic link.
+
+  - (build) tree_entry_extract() function was both static inline
+    and extern, which caused trouble compiling with Forte12
+    compilers on Sun.
+
+  - Many many documentation fixes and updates.
diff --git a/Documentation/RelNotes/1.5.1.txt b/Documentation/RelNotes/1.5.1.txt
new file mode 100644
index 0000000000..daed367270
--- /dev/null
+++ b/Documentation/RelNotes/1.5.1.txt
@@ -0,0 +1,371 @@
+GIT v1.5.1 Release Notes
+========================
+
+Updates since v1.5.0
+--------------------
+
+* Deprecated commands and options.
+
+  - git-diff-stages and git-resolve have been removed.
+
+* New commands and options.
+
+  - "git log" and friends take --reverse, which instructs them
+    to give their output in the order opposite from their usual.
+    They typically output from new to old, but with this option
+    their output would read from old to new.  "git shortlog"
+    usually lists older commits first, but with this option,
+    they are shown from new to old.
+
+  - "git log --pretty=format:<string>" to allow more flexible
+    custom log output.
+
+  - "git diff" learned --ignore-space-at-eol.  This is a weaker
+    form of --ignore-space-change.
+
+  - "git diff --no-index pathA pathB" can be used as diff
+    replacement with git specific enhancements.
+
+  - "git diff --no-index" can read from '-' (standard input).
+
+  - "git diff" also learned --exit-code to exit with non-zero
+    status when it found differences.  In the future we might
+    want to make this the default but that would be a rather big
+    backward incompatible change; it will stay as an option for
+    now.
+
+  - "git diff --quiet" is --exit-code with output turned off,
+    meant for scripted use to quickly determine if there is any
+    tree-level difference.
+
+  - Textual patch generation with "git diff" without -w/-b
+    option has been significantly optimized.  "git blame" got
+    faster because of the same change.
+
+  - "git log" and "git rev-list" has been optimized
+    significantly when they are used with pathspecs.
+
+  - "git branch --track" can be used to set up configuration
+    variables to help it easier to base your work on branches
+    you track from a remote site.
+
+  - "git format-patch --attach" now emits attachments.  Use
+    --inline to get an inlined multipart/mixed.
+
+  - "git name-rev" learned --refs=<pattern>, to limit the tags
+    used for naming the given revisions only to the ones
+    matching the given pattern.
+
+  - "git remote update" is to run "git fetch" for defined remotes
+    to update tracking branches.
+
+  - "git cvsimport" can now take '-d' to talk with a CVS
+    repository different from what are recorded in CVS/Root
+    (overriding it with environment CVSROOT does not work).
+
+  - "git bundle" can help sneaker-netting your changes between
+    repositories.
+
+  - "git mergetool" can help 3-way file-level conflict
+    resolution with your favorite graphical merge tools.
+
+  - A new configuration "core.symlinks" can be used to disable
+    symlinks on filesystems that do not support them; they are
+    checked out as regular files instead.
+
+  - You can name a commit object with its first line of the
+    message.  The syntax to use is ':/message text'.  E.g.
+
+    $ git show ":/object name: introduce ':/<oneline prefix>' notation"
+
+    means the same thing as:
+
+    $ git show 28a4d940443806412effa246ecc7768a21553ec7
+
+  - "git bisect" learned a new command "run" that takes a script
+    to run after each revision is checked out to determine if it
+    is good or bad, to automate the bisection process.
+
+  - "git log" family learned a new traversal option --first-parent,
+    which does what the name suggests.
+
+
+* Updated behavior of existing commands.
+
+  - "git-merge-recursive" used to barf when there are more than
+    one common ancestors for the merge, and merging them had a
+    rename/rename conflict.  This has been fixed.
+
+  - "git fsck" does not barf on corrupt loose objects.
+
+  - "git rm" does not remove newly added files without -f.
+
+  - "git archimport" allows remapping when coming up with git
+    branch names from arch names.
+
+  - git-svn got almost a rewrite.
+
+  - core.autocrlf configuration, when set to 'true', makes git
+    to convert CRLF at the end of lines in text files to LF when
+    reading from the filesystem, and convert in reverse when
+    writing to the filesystem.  The variable can be set to
+    'input', in which case the conversion happens only while
+    reading from the filesystem but files are written out with
+    LF at the end of lines.  Currently, which paths to consider
+    'text' (i.e. be subjected to the autocrlf mechanism) is
+    decided purely based on the contents, but the plan is to
+    allow users to explicitly override this heuristic based on
+    paths.
+
+  - The behavior of 'git-apply', when run in a subdirectory,
+    without --index nor --cached were inconsistent with that of
+    the command with these options.  This was fixed to match the
+    behavior with --index.  A patch that is meant to be applied
+    with -p1 from the toplevel of the project tree can be
+    applied with any custom -p<n> option.  A patch that is not
+    relative to the toplevel needs to be applied with -p<n>
+    option with or without --index (or --cached).
+
+  - "git diff" outputs a trailing HT when pathnames have embedded
+    SP on +++/--- header lines, in order to help "GNU patch" to
+    parse its output.  "git apply" was already updated to accept
+    this modified output format since ce74618d (Sep 22, 2006).
+
+  - "git cvsserver" runs hooks/update and honors its exit status.
+
+  - "git cvsserver" can be told to send everything with -kb.
+
+  - "git diff --check" also honors the --color output option.
+
+  - "git name-rev" used to stress the fact that a ref is a tag too
+    much, by saying something like "v1.2.3^0~22".  It now says
+    "v1.2.3~22" in such a case (it still says "v1.2.3^0" if it does
+    not talk about an ancestor of the commit that is tagged, which
+    makes sense).
+
+  - "git rev-list --boundary" now shows boundary markers for the
+    commits omitted by --max-age and --max-count condition.
+
+  - The configuration mechanism now reads $(prefix)/etc/gitconfig.
+
+  - "git apply --verbose" shows what preimage lines were wanted
+    when it couldn't find them.
+
+  - "git status" in a read-only repository got a bit saner.
+
+  - "git fetch" (hence "git clone" and "git pull") are less
+    noisy when the output does not go to tty.
+
+  - "git fetch" between repositories with many refs were slow
+    even when there are not many changes that needed
+    transferring.  This has been sped up by partially rewriting
+    the heaviest parts in C.
+
+  - "git mailinfo" which splits an e-mail into a patch and the
+    meta-information was rewritten, thanks to Don Zickus.  It
+    handles nested multipart better.  The command was broken for
+    a brief period on 'master' branch since 1.5.0 but the
+    breakage is fixed now.
+
+  - send-email learned configurable bcc and chain-reply-to.
+
+  - "git remote show $remote" also talks about branches that
+    would be pushed if you run "git push remote".
+
+  - Using objects from packs is now seriously optimized by clever
+    use of a cache.  This should be most noticeable in git-log
+    family of commands that involve reading many tree objects.
+    In addition, traversing revisions while filtering changes
+    with pathspecs is made faster by terminating the comparison
+    between the trees as early as possible.
+
+
+* Hooks
+
+  - The part to send out notification e-mails was removed from
+    the sample update hook, as it was not an appropriate place
+    to do so.  The proper place to do this is the new post-receive
+    hook.  An example hook has been added to contrib/hooks/.
+
+
+* Others
+
+  - git-revert, git-gc and git-cherry-pick are now built-ins.
+
+Fixes since v1.5.0
+------------------
+
+These are all in v1.5.0.x series.
+
+* Documentation updates
+
+  - Clarifications and corrections to 1.5.0 release notes.
+
+  - The main documentation did not link to git-remote documentation.
+
+  - Clarified introductory text of git-rebase documentation.
+
+  - Converted remaining mentions of update-index on Porcelain
+    documents to git-add/git-rm.
+
+  - Some i18n.* configuration variables were incorrectly
+    described as core.*; fixed.
+
+  - added and clarified core.bare, core.legacyheaders configurations.
+
+  - updated "git-clone --depth" documentation.
+
+  - user-manual updates.
+
+  - Options to 'git remote add' were described insufficiently.
+
+  - Configuration format.suffix was not documented.
+
+  - Other formatting and spelling fixes.
+
+  - user-manual has better cross references.
+
+  - gitweb installation/deployment procedure is now documented.
+
+
+* Bugfixes
+
+  - git-upload-pack closes unused pipe ends; earlier this caused
+    many zombies to hang around.
+
+  - git-rerere was recording the contents of earlier hunks
+    duplicated in later hunks.  This prevented resolving the same
+    conflict when performing the same merge the other way around.
+
+  - git-add and git-update-index on a filesystem on which
+    executable bits are unreliable incorrectly reused st_mode
+    bits even when the path changed between symlink and regular
+    file.
+
+  - git-daemon marks the listening sockets with FD_CLOEXEC so
+    that it won't be leaked into the children.
+
+  - segfault from git-blame when the mandatory pathname
+    parameter was missing was fixed; usage() message is given
+    instead.
+
+  - git-rev-list did not read $GIT_DIR/config file, which means
+    that did not honor i18n.logoutputencoding correctly.
+
+  - Automated merge conflict handling when changes to symbolic
+    links conflicted were completely broken.  The merge-resolve
+    strategy created a regular file with conflict markers in it
+    in place of the symbolic link.  The default strategy,
+    merge-recursive was even more broken.  It removed the path
+    that was pointed at by the symbolic link.  Both of these
+    problems have been fixed.
+
+  - 'git diff maint master next' did not correctly give combined
+    diff across three trees.
+
+  - 'git fast-import' portability fix for Solaris.
+
+  - 'git show-ref --verify' without arguments did not error out
+    but segfaulted.
+
+  - 'git diff :tracked-file `pwd`/an-untracked-file' gave an extra
+    slashes after a/ and b/.
+
+  - 'git format-patch' produced too long filenames if the commit
+    message had too long line at the beginning.
+
+  - Running 'make all' and then without changing anything
+    running 'make install' still rebuilt some files.  This
+    was inconvenient when building as yourself and then
+    installing as root (especially problematic when the source
+    directory is on NFS and root is mapped to nobody).
+
+  - 'git-rerere' failed to deal with two unconflicted paths that
+    sorted next to each other.
+
+  - 'git-rerere' attempted to open(2) a symlink and failed if
+    there was a conflict.  Since a conflicting change to a
+    symlink would not benefit from rerere anyway, the command
+    now ignores conflicting changes to symlinks.
+
+  - 'git-repack' did not like to pass more than 64 arguments
+    internally to underlying 'rev-list' logic, which made it
+    impossible to repack after accumulating many (small) packs
+    in the repository.
+
+  - 'git-diff' to review the combined diff during a conflicted
+    merge were not reading the working tree version correctly
+    when changes to a symbolic link conflicted.  It should have
+    read the data using readlink(2) but read from the regular
+    file the symbolic link pointed at.
+
+  - 'git-remote' did not like period in a remote's name.
+
+  - 'git.el' honors the commit coding system from the configuration.
+
+  - 'blameview' in contrib/ correctly digs deeper when a line is
+    clicked.
+
+  - 'http-push' correctly makes sure the remote side has leading
+    path.  Earlier it started in the middle of the path, and
+    incorrectly.
+
+  - 'git-merge' did not exit with non-zero status when the
+    working tree was dirty and cannot fast forward.  It does
+    now.
+
+  - 'cvsexportcommit' does not lose yet-to-be-used message file.
+
+  - int-vs-size_t typefix when running combined diff on files
+    over 2GB long.
+
+  - 'git apply --whitespace=strip' should not touch unmodified
+    lines.
+
+  - 'git-mailinfo' choke when a logical header line was too long.
+
+  - 'git show A..B' did not error out.  Negative ref ("not A" in
+    this example) does not make sense for the purpose of the
+    command, so now it errors out.
+
+  - 'git fmt-merge-msg --file' without file parameter did not
+    correctly error out.
+
+  - 'git archimport' barfed upon encountering a commit without
+    summary.
+
+  - 'git index-pack' did not protect itself from getting a short
+    read out of pread(2).
+
+  - 'git http-push' had a few buffer overruns.
+
+  - Build dependency fixes to rebuild fetch.o when other headers
+    change.
+
+  - git.el does not add duplicate sign-off lines.
+
+  - git-commit shows the full stat of the resulting commit, not
+    just about the files in the current directory, when run from
+    a subdirectory.
+
+  - "git-checkout -m '@{8 hours ago}'" had a funny failure from
+    eval; fixed.
+
+  - git-merge (hence git-pull) did not refuse fast-forwarding
+    when the working tree had local changes that would have
+    conflicted with it.
+
+  - a handful small fixes to gitweb.
+
+  - build procedure for user-manual is fixed not to require locally
+    installed stylesheets.
+
+  - "git commit $paths" on paths whose earlier contents were
+    already updated in the index were failing out.
+
+
+* Tweaks
+
+  - sliding mmap() inefficiently mmaped the same region of a
+    packfile with an access pattern that used objects in the
+    reverse order.  This has been made more efficient.
diff --git a/Documentation/RelNotes/1.5.2.1.txt b/Documentation/RelNotes/1.5.2.1.txt
new file mode 100644
index 0000000000..d41984df0b
--- /dev/null
+++ b/Documentation/RelNotes/1.5.2.1.txt
@@ -0,0 +1,47 @@
+GIT v1.5.2.1 Release Notes
+==========================
+
+Fixes since v1.5.2
+------------------
+
+* Bugfixes
+
+  - Temporary files that are used when invoking external diff
+    programs did not tolerate a long TMPDIR.
+
+  - git-daemon did not notice when it could not write into its
+    pid file.
+
+  - git-status did not honor core.excludesFile configuration like
+    git-add did.
+
+  - git-annotate did not work from a subdirectory while
+    git-blame did.
+
+  - git-cvsserver should have disabled access to a repository
+    with "gitcvs.pserver.enabled = false" set even when
+    "gitcvs.enabled = true" was set at the same time.  It
+    didn't.
+
+  - git-cvsimport did not work correctly in a repository with
+    its branch heads were packed with pack-refs.
+
+  - ident unexpansion to squash "$Id: xxx $" that is in the
+    repository copy removed incorrect number of bytes.
+
+  - git-svn misbehaved when the subversion repository did not
+    provide MD5 checksums for files.
+
+  - git rebase (and git am) misbehaved on commits that have '\n'
+    (literally backslash and en, not a linefeed) in the title.
+
+  - code to decode base85 used in binary patches had one error
+    return codepath wrong.
+
+  - RFC2047 Q encoding output by git-format-patch used '_' for a
+    space, which is not understood by some programs.  It uses =20
+    which is safer.
+
+  - git-fastimport --import-marks was broken; fixed.
+
+  - A lot of documentation updates, clarifications and fixes.
diff --git a/Documentation/RelNotes/1.5.2.2.txt b/Documentation/RelNotes/1.5.2.2.txt
new file mode 100644
index 0000000000..7bfa341750
--- /dev/null
+++ b/Documentation/RelNotes/1.5.2.2.txt
@@ -0,0 +1,61 @@
+GIT v1.5.2.2 Release Notes
+==========================
+
+Fixes since v1.5.2.1
+--------------------
+
+* Usability fix
+
+  - git-gui is shipped with its updated blame interface.  It is
+    rumored that the older one was not just unusable but was
+    active health hazard, but this one is actually pretty.
+    Please see for yourself.
+
+* Bugfixes
+
+  - "git checkout fubar" was utterly confused when there is a
+    branch fubar and a tag fubar at the same time.  It correctly
+    checks out the branch fubar now.
+
+  - "git clone /path/foo" to clone a local /path/foo.git
+    repository left an incorrect configuration.
+
+  - "git send-email" correctly unquotes RFC 2047 quoted names in
+    the patch-email before using their values.
+
+  - We did not accept number of seconds since epoch older than
+    year 2000 as a valid timestamp.  We now interpret positive
+    integers more than 8 digits as such, which allows us to
+    express timestamps more recent than March 1973.
+
+  - git-cvsimport did not work when you have GIT_DIR to point
+    your repository at a nonstandard location.
+
+  - Some systems (notably, Solaris) lack hstrerror() to make
+    h_errno human readable; prepare a replacement
+    implementation.
+
+  - .gitignore file listed git-core.spec but what we generate is
+    git.spec, and nobody noticed for a long time.
+
+  - "git-merge-recursive" does not try to run file level merge
+    on binary files.
+
+  - "git-branch --track" did not create tracking configuration
+    correctly when the branch name had slash in it.
+
+  - The email address of the user specified with user.email
+    configuration was overridden by EMAIL environment variable.
+
+  - The tree parser did not warn about tree entries with
+    nonsense file modes, and assumed they must be blobs.
+
+  - "git log -z" without any other request to generate diff still
+    invoked the diff machinery, wasting cycles.
+
+* Documentation
+
+  - Many updates to fix stale or missing documentation.
+
+  - Although our documentation was primarily meant to be formatted
+    with AsciiDoc7, formatting with AsciiDoc8 is supported better.
diff --git a/Documentation/RelNotes/1.5.2.3.txt b/Documentation/RelNotes/1.5.2.3.txt
new file mode 100644
index 0000000000..addb22955b
--- /dev/null
+++ b/Documentation/RelNotes/1.5.2.3.txt
@@ -0,0 +1,27 @@
+GIT v1.5.2.3 Release Notes
+==========================
+
+Fixes since v1.5.2.2
+--------------------
+
+ * Bugfixes
+
+   - Version 2 pack index format was introduced in version 1.5.2
+     to support pack files that has offset that cannot be
+     represented in 32-bit.  The runtime code to validate such
+     an index mishandled such an index for an empty pack.
+
+   - Commit walkers (most notably, fetch over http protocol)
+     tried to traverse commit objects contained in trees (aka
+     subproject); they shouldn't.
+
+   - A build option NO_R_TO_GCC_LINKER was not explained in Makefile
+     comment correctly.
+
+ * Documentation Fixes and Updates
+
+   - git-config --regexp was not documented properly.
+
+   - git-repack -a was not documented properly.
+
+   - git-remote -n was not documented properly.
diff --git a/Documentation/RelNotes/1.5.2.4.txt b/Documentation/RelNotes/1.5.2.4.txt
new file mode 100644
index 0000000000..75cff475f6
--- /dev/null
+++ b/Documentation/RelNotes/1.5.2.4.txt
@@ -0,0 +1,28 @@
+GIT v1.5.2.4 Release Notes
+==========================
+
+Fixes since v1.5.2.3
+--------------------
+
+ * Bugfixes
+
+   - "git-gui" bugfixes, including a handful fixes to run it
+     better on Cygwin/MSYS.
+
+   - "git checkout" failed to switch back and forth between
+     branches, one of which has "frotz -> xyzzy" symlink and
+     file "xyzzy/filfre", while the other one has a file
+     "frotz/filfre".
+
+   - "git prune" used to segfault upon seeing a commit that is
+     referred to by a tree object (aka "subproject").
+
+   - "git diff --name-status --no-index" mishandled an added file.
+
+   - "git apply --reverse --whitespace=warn" still complained
+     about whitespaces that a forward application would have
+     introduced.
+
+ * Documentation Fixes and Updates
+
+   - A handful documentation updates.
diff --git a/Documentation/RelNotes/1.5.2.5.txt b/Documentation/RelNotes/1.5.2.5.txt
new file mode 100644
index 0000000000..e8281c72a0
--- /dev/null
+++ b/Documentation/RelNotes/1.5.2.5.txt
@@ -0,0 +1,30 @@
+GIT v1.5.2.5 Release Notes
+==========================
+
+Fixes since v1.5.2.4
+--------------------
+
+ * Bugfixes
+
+   - "git add -u" had a serious data corruption problem in one
+     special case (when the changes to a subdirectory's files
+     consist only deletion of files).
+
+   - "git add -u <path>" did not work from a subdirectory.
+
+   - "git apply" left an empty directory after all its files are
+     renamed away.
+
+   - "git $anycmd foo/bar", when there is a file 'foo' in the
+     working tree, complained that "git $anycmd foo/bar --" form
+     should be used to disambiguate between revs and files,
+     which was completely bogus.
+
+   - "git checkout-index" and other commands that checks out
+     files to the work tree tried unlink(2) on directories,
+     which is a sane thing to do on sane systems, but not on
+     Solaris when you are root.
+
+ * Documentation Fixes and Updates
+
+   - A handful documentation fixes.
diff --git a/Documentation/RelNotes/1.5.2.txt b/Documentation/RelNotes/1.5.2.txt
new file mode 100644
index 0000000000..e8328d090a
--- /dev/null
+++ b/Documentation/RelNotes/1.5.2.txt
@@ -0,0 +1,197 @@
+GIT v1.5.2 Release Notes
+========================
+
+Updates since v1.5.1
+--------------------
+
+* Plumbing level superproject support.
+
+  You can include a subdirectory that has an independent git
+  repository in your index and tree objects of your project
+  ("superproject").  This plumbing (i.e. "core") level
+  superproject support explicitly excludes recursive behaviour.
+
+  The "subproject" entries in the index and trees of a superproject
+  are incompatible with older versions of git.  Experimenting with
+  the plumbing level support is encouraged, but be warned that
+  unless everybody in your project updates to this release or
+  later, using this feature would make your project
+  inaccessible by people with older versions of git.
+
+* Plumbing level gitattributes support.
+
+  The gitattributes mechanism allows you to add 'attributes' to
+  paths in your project, and affect the way certain git
+  operations work.  Currently you can influence if a path is
+  considered a binary or text (the former would be treated by
+  'git diff' not to produce textual output; the latter can go
+  through the line endings conversion process in repositories
+  with core.autocrlf set), expand and unexpand '$Id$' keyword
+  with blob object name, specify a custom 3-way merge driver,
+  and specify a custom diff driver.  You can also apply
+  arbitrary filter to contents on check-in/check-out codepath
+  but this feature is an extremely sharp-edged razor and needs
+  to be handled with caution (do not use it unless you
+  understand the earlier mailing list discussion on keyword
+  expansion).  These conversions apply when checking files in
+  or out, and exporting via git-archive.
+
+* The packfile format now optionally supports 64-bit index.
+
+  This release supports the "version 2" format of the .idx
+  file.  This is automatically enabled when a huge packfile
+  needs more than 32-bit to express offsets of objects in the
+  pack.
+
+* Comes with an updated git-gui 0.7.1
+
+* Updated gitweb:
+
+  - can show combined diff for merges;
+  - uses font size of user's preference, not hardcoded in pixels;
+  - can now 'grep';
+
+* New commands and options.
+
+  - "git bisect start" can optionally take a single bad commit and
+    zero or more good commits on the command line.
+
+  - "git shortlog" can optionally be told to wrap its output.
+
+  - "subtree" merge strategy allows another project to be merged in as
+    your subdirectory.
+
+  - "git format-patch" learned a new --subject-prefix=<string>
+    option, to override the built-in "[PATCH]".
+
+  - "git add -u" is a quick way to do the first stage of "git
+    commit -a" (i.e. update the index to match the working
+    tree); it obviously does not make a commit.
+
+  - "git clean" honors a new configuration, "clean.requireforce".  When
+    set to true, this makes "git clean" a no-op, preventing you
+    from losing files by typing "git clean" when you meant to
+    say "make clean".  You can still say "git clean -f" to
+    override this.
+
+  - "git log" family of commands learned --date={local,relative,default}
+    option.  --date=relative is synonym to the --relative-date.
+    --date=local gives the timestamp in local timezone.
+
+* Updated behavior of existing commands.
+
+  - When $GIT_COMMITTER_EMAIL or $GIT_AUTHOR_EMAIL is not set
+    but $EMAIL is set, the latter is used as a substitute.
+
+  - "git diff --stat" shows size of preimage and postimage blobs
+    for binary contents.  Earlier it only said "Bin".
+
+  - "git lost-found" shows stuff that are unreachable except
+    from reflogs.
+
+  - "git checkout branch^0" now detaches HEAD at the tip commit
+    on the named branch, instead of just switching to the
+    branch (use "git checkout branch" to switch to the branch,
+    as before).
+
+  - "git bisect next" can be used after giving only a bad commit
+    without giving a good one (this starts bisection half-way to
+    the root commit).  We used to refuse to operate without a
+    good and a bad commit.
+
+  - "git push", when pushing into more than one repository, does
+    not stop at the first error.
+
+  - "git archive" does not insist you to give --format parameter
+    anymore; it defaults to "tar".
+
+  - "git cvsserver" can use backends other than sqlite.
+
+  - "gitview" (in contrib/ section) learned to better support
+    "git-annotate".
+
+  - "git diff $commit1:$path2 $commit2:$path2" can now report
+    mode changes between the two blobs.
+
+  - Local "git fetch" from a repository whose object store is
+    one of the alternates (e.g. fetching from the origin in a
+    repository created with "git clone -l -s") avoids
+    downloading objects unnecessarily.
+
+  - "git blame" uses .mailmap to canonicalize the author name
+    just like "git shortlog" does.
+
+  - "git pack-objects" pays attention to pack.depth
+    configuration variable.
+
+  - "git cherry-pick" and "git revert" does not use .msg file in
+    the working tree to prepare commit message; instead it uses
+    $GIT_DIR/MERGE_MSG as other commands do.
+
+* Builds
+
+  - git-p4import has never been installed; now there is an
+    installation option to do so.
+
+  - gitk and git-gui can be configured out.
+
+  - Generated documentation pages automatically get version
+    information from GIT_VERSION.
+
+  - Parallel build with "make -j" descending into subdirectory
+    was fixed.
+
+* Performance Tweaks
+
+  - Optimized "git-rev-list --bisect" (hence "git-bisect").
+
+  - Optimized "git-add $path" in a large directory, most of
+    whose contents are ignored.
+
+  - Optimized "git-diff-tree" for reduced memory footprint.
+
+  - The recursive merge strategy updated a worktree file that
+    was changed identically in two branches, when one of them
+    renamed it.  We do not do that when there is no rename, so
+    match that behaviour.  This avoids excessive rebuilds.
+
+  - The default pack depth has been increased to 50, as the
+    recent addition of delta_base_cache makes deeper delta chains
+    much less expensive to access.  Depending on the project, it was
+    reported that this reduces the resulting pack file by 10%
+    or so.
+
+
+Fixes since v1.5.1
+------------------
+
+All of the fixes in v1.5.1 maintenance series are included in
+this release, unless otherwise noted.
+
+* Bugfixes
+
+  - Switching branches with "git checkout" refused to work when
+    a path changes from a file to a directory between the
+    current branch and the new branch, in order not to lose
+    possible local changes in the directory that is being turned
+    into a file with the switch.  We now allow such a branch
+    switch after making sure that there is no locally modified
+    file nor un-ignored file in the directory.  This has not
+    been backported to 1.5.1.x series, as it is rather an
+    intrusive change.
+
+  - Merging branches that have a file in one and a directory in
+    another at the same path used to get quite confused.  We
+    handle such a case a bit more carefully, even though that is
+    still left as a conflict for the user to sort out.  This
+    will not be backported to 1.5.1.x series, as it is rather an
+    intrusive change.
+
+  - git-fetch had trouble with a remote with insanely large number
+    of refs.
+
+  - "git clean -d -X" now does not remove non-excluded directories.
+
+  - rebasing (without -m) a series that changes a symlink to a directory
+    in the middle of a path confused git-apply greatly and refused to
+    operate.
diff --git a/Documentation/RelNotes/1.5.3.1.txt b/Documentation/RelNotes/1.5.3.1.txt
new file mode 100644
index 0000000000..7ff546c743
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.1.txt
@@ -0,0 +1,10 @@
+GIT v1.5.3.1 Release Notes
+==========================
+
+Fixes since v1.5.3
+------------------
+
+This is solely to fix the generated RPM's dependencies.  We used
+to have git-p4 package but we do not anymore.  As suggested on
+the mailing list, this release makes git-core "Obsolete" git-p4,
+so that yum update would not complain.
diff --git a/Documentation/RelNotes/1.5.3.2.txt b/Documentation/RelNotes/1.5.3.2.txt
new file mode 100644
index 0000000000..4bbde3cab4
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.2.txt
@@ -0,0 +1,58 @@
+GIT v1.5.3.2 Release Notes
+==========================
+
+Fixes since v1.5.3.1
+--------------------
+
+ * git-push sent thin packs by default, which was not good for
+   the public distribution server (no point in saving transfer
+   while pushing; no point in making the resulting pack less
+   optimum).
+
+ * git-svn sometimes terminated with "Malformed network data" when
+   talking over svn:// protocol.
+
+ * git-send-email re-issued the same message-id about 10% of the
+   time if you fired off 30 messages within a single second.
+
+ * git-stash was not terminating the log message of commits it
+   internally creates with LF.
+
+ * git-apply failed to check the size of the patch hunk when its
+   beginning part matched the remainder of the preimage exactly,
+   even though the preimage recorded in the hunk was much larger
+   (therefore the patch should not have applied), leading to a
+   segfault.
+
+ * "git rm foo && git commit foo" complained that 'foo' needs to
+   be added first, instead of committing the removal, which was a
+   nonsense.
+
+ * git grep -c said "/dev/null: 0".
+
+ * git-add -u failed to recognize a blob whose type changed
+   between the index and the work tree.
+
+ * The limit to rename detection has been tightened a lot to
+   reduce performance problems with a huge change.
+
+ * cvsimport and svnimport barfed when the input tried to move
+   a tag.
+
+ * "git apply -pN" did not chop the right number of directories.
+
+ * "git svnimport" did not like SVN tags with funny characters in them.
+
+ * git-gui 0.8.3, with assorted fixes, including:
+
+   - font-chooser on X11 was unusable with large number of fonts;
+   - a diff that contained a deleted symlink made it barf;
+   - an untracked symbolic link to a directory made it fart;
+   - a file with % in its name made it vomit;
+
+
+Documentation updates
+---------------------
+
+User manual has been somewhat restructured.  I think the new
+organization is much easier to read.
diff --git a/Documentation/RelNotes/1.5.3.3.txt b/Documentation/RelNotes/1.5.3.3.txt
new file mode 100644
index 0000000000..d213846951
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.3.txt
@@ -0,0 +1,31 @@
+GIT v1.5.3.3 Release Notes
+==========================
+
+Fixes since v1.5.3.2
+--------------------
+
+ * git-quiltimport did not like it when a patch described in the
+   series file does not exist.
+
+ * p4 importer missed executable bit in some cases.
+
+ * The default shell on some FreeBSD did not execute the
+   argument parsing code correctly and made git unusable.
+
+ * git-svn incorrectly spawned pager even when the user
+   explicitly asked not to.
+
+ * sample post-receive hook overquoted the envelope sender
+   value.
+
+ * git-am got confused when the patch contained a change that is
+   only about type and not contents.
+
+ * git-mergetool did not show our and their version of the
+   conflicted file when started from a subdirectory of the
+   project.
+
+ * git-mergetool did not pass correct options when invoking diff3.
+
+ * git-log sometimes invoked underlying "diff" machinery
+   unnecessarily.
diff --git a/Documentation/RelNotes/1.5.3.4.txt b/Documentation/RelNotes/1.5.3.4.txt
new file mode 100644
index 0000000000..b04b3a45a5
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.4.txt
@@ -0,0 +1,35 @@
+GIT v1.5.3.4 Release Notes
+==========================
+
+Fixes since v1.5.3.3
+--------------------
+
+ * Change to "git-ls-files" in v1.5.3.3 that was introduced to support
+   partial commit of removal better had a segfaulting bug, which was
+   diagnosed and fixed by Keith and Carl.
+
+ * Performance improvements for rename detection has been backported
+   from the 'master' branch.
+
+ * "git-for-each-ref --format='%(numparent)'" was not working
+   correctly at all, and --format='%(parent)' was not working for
+   merge commits.
+
+ * Sample "post-receive-hook" incorrectly sent out push
+   notification e-mails marked as "From: " the committer of the
+   commit that happened to be at the tip of the branch that was
+   pushed, not from the person who pushed.
+
+ * "git-remote" did not exit non-zero status upon error.
+
+ * "git-add -i" did not respond very well to EOF from tty nor
+   bogus input.
+
+ * "git-rebase -i" squash subcommand incorrectly made the
+   author of later commit the author of resulting commit,
+   instead of taking from the first one in the squashed series.
+
+ * "git-stash apply --index" was not documented.
+
+ * autoconfiguration learned that "ar" command is found as "gas" on
+   some systems.
diff --git a/Documentation/RelNotes/1.5.3.5.txt b/Documentation/RelNotes/1.5.3.5.txt
new file mode 100644
index 0000000000..7ff1d5d0d1
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.5.txt
@@ -0,0 +1,94 @@
+GIT v1.5.3.5 Release Notes
+==========================
+
+Fixes since v1.5.3.4
+--------------------
+
+ * Comes with git-gui 0.8.4.
+
+ * "git-config" silently ignored options after --list; now it will
+   error out with a usage message.
+
+ * "git-config --file" failed if the argument used a relative path
+   as it changed directories before opening the file.
+
+ * "git-config --file" now displays a proper error message if it
+   cannot read the file specified on the command line.
+
+ * "git-config", "git-diff", "git-apply" failed if run from a
+   subdirectory with relative GIT_DIR and GIT_WORK_TREE set.
+
+ * "git-blame" crashed if run during a merge conflict.
+
+ * "git-add -i" did not handle single line hunks correctly.
+
+ * "git-rebase -i" and "git-stash apply" failed if external diff
+   drivers were used for one or more files in a commit.  They now
+   avoid calling the external diff drivers.
+
+ * "git-log --follow" did not work unless diff generation (e.g. -p)
+   was also requested.
+
+ * "git-log --follow -B" did not work at all.  Fixed.
+
+ * "git-log -M -B" did not correctly handle cases of very large files
+   being renamed and replaced by very small files in the same commit.
+
+ * "git-log" printed extra newlines between commits when a diff
+   was generated internally (e.g. -S or --follow) but not displayed.
+
+ * "git-push" error message is more helpful when pushing to a
+   repository with no matching refs and none specified.
+
+ * "git-push" now respects + (force push) on wildcard refspecs,
+   matching the behavior of git-fetch.
+
+ * "git-filter-branch" now updates the working directory when it
+   has finished filtering the current branch.
+
+ * "git-instaweb" no longer fails on Mac OS X.
+
+ * "git-cvsexportcommit" didn't always create new parent directories
+   before trying to create new child directories.  Fixed.
+
+ * "git-fetch" printed a scary (but bogus) error message while
+   fetching a tag that pointed to a tree or blob.  The error did
+   not impact correctness, only user perception.  The bogus error
+   is no longer printed.
+
+ * "git-ls-files --ignored" did not properly descend into non-ignored
+   directories that themselves contained ignored files if d_type
+   was not supported by the filesystem.  This bug impacted systems
+   such as AFS.  Fixed.
+
+ * Git segfaulted when reading an invalid .gitattributes file.  Fixed.
+
+ * post-receive-email example hook was fixed for non-fast-forward
+   updates.
+
+ * Documentation updates for supported (but previously undocumented)
+   options of "git-archive" and "git-reflog".
+
+ * "make clean" no longer deletes the configure script that ships
+   with the git tarball, making multiple architecture builds easier.
+
+ * "git-remote show origin" spewed a warning message from Perl
+   when no remote is defined for the current branch via
+   branch.<name>.remote configuration settings.
+
+ * Building with NO_PERL_MAKEMAKER excessively rebuilt contents
+   of perl/ subdirectory by rewriting perl.mak.
+
+ * http.sslVerify configuration settings were not used in scripted
+   Porcelains.
+
+ * "git-add" leaked a bit of memory while scanning for files to add.
+
+ * A few workarounds to squelch false warnings from recent gcc have
+   been added.
+
+ * "git-send-pack $remote frotz" segfaulted when there is nothing
+   named 'frotz' on the local end.
+
+ * "git-rebase --interactive" did not handle its "--strategy" option
+   properly.
diff --git a/Documentation/RelNotes/1.5.3.6.txt b/Documentation/RelNotes/1.5.3.6.txt
new file mode 100644
index 0000000000..069a2b2cf9
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.6.txt
@@ -0,0 +1,48 @@
+GIT v1.5.3.6 Release Notes
+==========================
+
+Fixes since v1.5.3.5
+--------------------
+
+ * git-cvsexportcommit handles root commits better.
+
+ * git-svn dcommit used to clobber when sending a series of
+   patches.
+
+ * git-svn dcommit failed after attempting to rebase when
+   started with a dirty index; now it stops upfront.
+
+ * git-grep sometimes refused to work when your index was
+   unmerged.
+
+ * "git-grep -A1 -B2" acted as if it was told to run "git -A1 -B21".
+
+ * git-hash-object did not honor configuration variables, such as
+   core.compression.
+
+ * git-index-pack choked on a huge pack on 32-bit machines, even when
+   large file offsets are supported.
+
+ * atom feeds from git-web said "10" for the month of November.
+
+ * a memory leak in commit walker was plugged.
+
+ * When git-send-email inserted the original author's From:
+   address in body, it did not mark the message with
+   Content-type: as needed.
+
+ * git-revert and git-cherry-pick incorrectly refused to start
+   when the work tree was dirty.
+
+ * git-clean did not honor core.excludesfile configuration.
+
+ * git-add mishandled ".gitignore" files when applying them to
+   subdirectories.
+
+ * While importing a too branchy history, git-fastimport did not
+   honor delta depth limit properly.
+
+ * Support for zlib implementations that lack ZLIB_VERNUM and definition
+   of deflateBound() has been added.
+
+ * Quite a lot of documentation clarifications.
diff --git a/Documentation/RelNotes/1.5.3.7.txt b/Documentation/RelNotes/1.5.3.7.txt
new file mode 100644
index 0000000000..2f690616c8
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.7.txt
@@ -0,0 +1,45 @@
+GIT v1.5.3.7 Release Notes
+==========================
+
+Fixes since v1.5.3.6
+--------------------
+
+ * git-send-email added 8-bit contents to the payload without
+   marking it as 8-bit in a CTE header.
+
+ * "git-bundle create a.bndl HEAD" dereferenced the symref and
+   did not record the ref as 'HEAD'; this prevented a bundle
+   from being used as a normal source of git-clone.
+
+ * The code to reject nonsense command line of the form
+   "git-commit -a paths..." and "git-commit --interactive
+   paths..." were broken.
+
+ * Adding a signature that is not ASCII-only to an original
+   commit that is ASCII-only would make the result non-ASCII.
+   "git-format-patch -s" did not mark such a message correctly
+   with MIME encoding header.
+
+ * git-add sometimes did not mark the resulting index entry
+   stat-clean.  This affected only cases when adding the
+   contents with the same length as the previously staged
+   contents, and the previous staging made the index entry
+   "racily clean".
+
+ * git-commit did not honor GIT_INDEX_FILE the user had in the
+   environment.
+
+ * When checking out a revision, git-checkout did not report where the
+   updated HEAD is if you happened to have a file called HEAD in the
+   work tree.
+
+ * "git-rev-list --objects" mishandled a tree that points at a
+   submodule.
+
+ * "git cvsimport" was not ready for packed refs that "git gc" can
+   produce and gave incorrect results.
+
+ * Many scripted Porcelains were confused when you happened to have a
+   file called "HEAD" in your work tree.
+
+Also it contains updates to the user manual and documentation.
diff --git a/Documentation/RelNotes/1.5.3.8.txt b/Documentation/RelNotes/1.5.3.8.txt
new file mode 100644
index 0000000000..0e3ff58a46
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.8.txt
@@ -0,0 +1,25 @@
+GIT v1.5.3.8 Release Notes
+==========================
+
+Fixes since v1.5.3.7
+--------------------
+
+ * Some documentation used "email.com" as an example domain.
+
+ * git-svn fix to handle funky branch and project names going over
+   http/https correctly.
+
+ * git-svn fix to tone down a needlessly alarming warning message.
+
+ * git-clone did not correctly report errors while fetching over http.
+
+ * git-send-email added redundant Message-Id: header to the outgoing
+   e-mail when the patch text already had one.
+
+ * a read-beyond-end-of-buffer bug in configuration file updater was fixed.
+
+ * git-grep used to show the same hit repeatedly for unmerged paths.
+
+ * After amending the patch title in "git-am -i", the command did not
+   report the patch it applied with the updated title.
+
diff --git a/Documentation/RelNotes/1.5.3.txt b/Documentation/RelNotes/1.5.3.txt
new file mode 100644
index 0000000000..0668d3c0ca
--- /dev/null
+++ b/Documentation/RelNotes/1.5.3.txt
@@ -0,0 +1,366 @@
+GIT v1.5.3 Release Notes
+========================
+
+Updates since v1.5.2
+--------------------
+
+* The commit walkers other than http are officially deprecated,
+  but still supported for now.
+
+* The submodule support has Porcelain layer.
+
+  Note that the current submodule support is minimal and this is
+  deliberately so.  A design decision we made is that operations
+  at the supermodule level do not recurse into submodules by
+  default.  The expectation is that later we would add a
+  mechanism to tell git which submodules the user is interested
+  in, and this information might be used to determine the
+  recursive behaviour of certain commands (e.g. "git checkout"
+  and "git diff"), but currently we haven't agreed on what that
+  mechanism should look like.  Therefore, if you use submodules,
+  you would probably need "git submodule update" on the
+  submodules you care about after running a "git checkout" at
+  the supermodule level.
+
+* There are a handful pack-objects changes to help you cope better
+  with repositories with pathologically large blobs in them.
+
+* For people who need to import from Perforce, a front-end for
+  fast-import is in contrib/fast-import/.
+
+* Comes with git-gui 0.8.2.
+
+* Comes with updated gitk.
+
+* New commands and options.
+
+  - "git log --date=<format>" can use more formats: iso8601, rfc2822.
+
+  - The hunk header output from "git diff" family can be customized
+    with the attributes mechanism.  See gitattributes(5) for details.
+
+  - "git stash" allows you to quickly save away your work in
+    progress and replay it later on an updated state.
+
+  - "git rebase" learned an "interactive" mode that let you
+    pick and reorder which commits to rebuild.
+
+  - "git fsck" can save its findings in $GIT_DIR/lost-found, without a
+    separate invocation of "git lost-found" command.  The blobs stored by
+    lost-found are stored in plain format to allow you to grep in them.
+
+  - $GIT_WORK_TREE environment variable can be used together with
+    $GIT_DIR to work in a subdirectory of a working tree that is
+    not located at "$GIT_DIR/..".
+
+  - Giving "--file=<file>" option to "git config" is the same as
+    running the command with GIT_CONFIG=<file> environment.
+
+  - "git log" learned a new option "--follow", to follow
+    renaming history of a single file.
+
+  - "git filter-branch" lets you rewrite the revision history of
+    specified branches. You can specify a number of filters to
+    modify the commits, files and trees.
+
+  - "git cvsserver" learned new options (--base-path, --export-all,
+    --strict-paths) inspired by "git daemon".
+
+  - "git daemon --base-path-relaxed" can help migrating a repository URL
+    that did not use to use --base-path to use --base-path.
+
+  - "git commit" can use "-t templatefile" option and commit.template
+    configuration variable to prime the commit message given to you in the
+    editor.
+
+  - "git submodule" command helps you manage the projects from
+    the superproject that contain them.
+
+  - In addition to core.compression configuration option,
+    core.loosecompression and pack.compression options can
+    independently tweak zlib compression levels used for loose
+    and packed objects.
+
+  - "git ls-tree -l" shows size of blobs pointed at by the
+    tree entries, similar to "/bin/ls -l".
+
+  - "git rev-list" learned --regexp-ignore-case and
+    --extended-regexp options to tweak its matching logic used
+    for --grep filtering.
+
+  - "git describe --contains" is a handier way to call more
+    obscure command "git name-rev --tags".
+
+  - "git gc --aggressive" tells the command to spend more cycles
+    to optimize the repository harder.
+
+  - "git repack" learned a "window-memory" limit which
+    dynamically reduces the window size to stay within the
+    specified memory usage.
+
+  - "git repack" can be told to split resulting packs to avoid
+    exceeding limit specified with "--max-pack-size".
+
+  - "git fsck" gained --verbose option.  This is really really
+    verbose but it might help you identify exact commit that is
+    corrupt in your repository.
+
+  - "git format-patch" learned --numbered-files option.  This
+    may be useful for MH users.
+
+  - "git format-patch" learned format.subjectprefix configuration
+    variable, which serves the same purpose as "--subject-prefix"
+    option.
+
+  - "git tag -n -l" shows tag annotations while listing tags.
+
+  - "git cvsimport" can optionally use the separate-remote layout.
+
+  - "git blame" can be told to see through commits that change
+    whitespaces and indentation levels with "-w" option.
+
+  - "git send-email" can be told not to thread the messages when
+    sending out more than one patches.
+
+  - "git send-email" can also be told how to find whom to cc the
+    message to for each message via --cc-cmd.
+
+  - "git config" learned NUL terminated output format via -z to
+    help scripts.
+
+  - "git add" learned "--refresh <paths>..." option to selectively refresh
+    the cached stat information.
+
+  - "git init -q" makes the command quieter.
+
+  - "git -p command" now has a cousin of opposite sex, "git --no-pager
+    command".
+
+* Updated behavior of existing commands.
+
+  - "gitweb" can offer multiple snapshot formats.
+
+    ***NOTE*** Unfortunately, this changes the format of the
+    $feature{snapshot}{default} entry in the per-site
+    configuration file 'gitweb_config.perl'.  It used to be a
+    three-element tuple that describe a single format; with the
+    new configuration item format, you only have to say the name
+    of the format ('tgz', 'tbz2' or 'zip').  Please update the
+    your configuration file accordingly.
+
+  - "git clone" uses -l (hardlink files under .git) by default when
+    cloning locally.
+
+  - URL used for "git clone" and friends can specify nonstandard SSH port
+    by using ssh://host:port/path/to/repo syntax.
+
+  - "git bundle create" can now create a bundle without negative refs,
+    i.e. "everything since the beginning up to certain points".
+
+  - "git diff" (but not the plumbing level "git diff-tree") now
+    recursively descends into trees by default.
+
+  - "git diff" does not show differences that come only from
+    stat-dirtiness in the form of "diff --git" header anymore.
+    It runs "update-index --refresh" silently as needed.
+
+  - "git tag -l" used to match tags by globbing its parameter as if it
+    has wildcard '*' on both ends, which made "git tag -l gui" to match
+    tag 'gitgui-0.7.0'; this was very annoying.  You now have to add
+    asterisk on the sides you want to wildcard yourself.
+
+  - The editor to use with many interactive commands can be
+    overridden with GIT_EDITOR environment variable, or if it
+    does not exist, with core.editor configuration variable.  As
+    before, if you have neither, environment variables VISUAL
+    and EDITOR are consulted in this order, and then finally we
+    fall back on "vi".
+
+  - "git rm --cached" does not complain when removing a newly
+    added file from the index anymore.
+
+  - Options to "git log" to affect how --grep/--author options look for
+    given strings now have shorter abbreviations.  -i is for ignore case,
+    and -E is for extended regexp.
+
+  - "git log" learned --log-size to show the number of bytes in
+    the log message part of the output to help qgit.
+
+  - "git log --name-status" does not require you to give "-r" anymore.
+    As a general rule, Porcelain commands should recurse when showing
+    diff.
+
+  - "git format-patch --root A" can be used to format everything
+    since the beginning up to A.  This was supported with
+    "git format-patch --root A A" for a long time, but was not
+    properly documented.
+
+  - "git svn dcommit" retains local merge information.
+
+  - "git svnimport" allows an empty string to be specified as the
+    trunk/ directory.  This is necessary to suck data from a SVN
+    repository that doe not have trunk/ branches/ and tags/ organization
+    at all.
+
+  - "git config" to set values also honors type flags like --bool
+    and --int.
+
+  - core.quotepath configuration can be used to make textual git
+    output to emit most of the characters in the path literally.
+
+  - "git mergetool" chooses its backend more wisely, taking
+    notice of its environment such as use of X, Gnome/KDE, etc.
+
+  - "gitweb" shows merge commits a lot nicer than before.  The
+    default view uses more compact --cc format, while the UI
+    allows to choose normal diff with any parent.
+
+  - snapshot files "gitweb" creates from a repository at
+    $path/$project/.git are more useful.  We use $project part
+    in the filename, which we used to discard.
+
+  - "git cvsimport" creates lightweight tags; there is no
+    interesting information we can record in an annotated tag,
+    and the handcrafted ones the old code created was not
+    properly formed anyway.
+
+  - "git push" pretends that you immediately fetched back from
+    the remote by updating corresponding remote tracking
+    branches if you have any.
+
+  - The diffstat given after a merge (or a pull) honors the
+    color.diff configuration.
+
+  - "git commit --amend" is now compatible with various message source
+    options such as -m/-C/-c/-F.
+
+  - "git apply --whitespace=strip" removes blank lines added at
+    the end of the file.
+
+  - "git fetch" over git native protocols with "-v" option shows
+    connection status, and the IP address of the other end, to
+    help diagnosing problems.
+
+  - We used to have core.legacyheaders configuration, when
+    set to false, allowed git to write loose objects in a format
+    that mimics the format used by objects stored in packs.  It
+    turns out that this was not so useful.  Although we will
+    continue to read objects written in that format, we do not
+    honor that configuration anymore and create loose objects in
+    the legacy/traditional format.
+
+  - "--find-copies-harder" option to diff family can now be
+    spelled as "-C -C" for brevity.
+
+  - "git mailsplit" (hence "git am") can read from Maildir
+    formatted mailboxes.
+
+  - "git cvsserver" does not barf upon seeing "cvs login"
+    request.
+
+  - "pack-objects" honors "delta" attribute set in
+    .gitattributes.  It does not attempt to deltify blobs that
+    come from paths with delta attribute set to false.
+
+  - "new-workdir" script (in contrib) can now be used with a
+    bare repository.
+
+  - "git mergetool" learned to use gvimdiff.
+
+  - "gitview" (in contrib) has a better blame interface.
+
+  - "git log" and friends did not handle a commit log message
+    that is larger than 16kB; they do now.
+
+  - "--pretty=oneline" output format for "git log" and friends
+    deals with "malformed" commit log messages that have more
+    than one lines in the first paragraph better.  We used to
+    show the first line, cutting the title at mid-sentence; we
+    concatenate them into a single line and treat the result as
+    "oneline".
+
+  - "git p4import" has been demoted to contrib status.  For
+    a superior option, checkout the "git p4" front end to
+    "git fast-import" (also in contrib).  The man page and p4
+    rpm have been removed as well.
+
+  - "git mailinfo" (hence "am") now tries to see if the message
+    is in utf-8 first, instead of assuming iso-8859-1, if
+    incoming e-mail does not say what encoding it is in.
+
+* Builds
+
+  - old-style function definitions (most notably, a function
+    without parameter defined with "func()", not "func(void)")
+    have been eradicated.
+
+  - "git tag" and "git verify-tag" have been rewritten in C.
+
+* Performance Tweaks
+
+  - "git pack-objects" avoids re-deltification cost by caching
+    small enough delta results it creates while looking for the
+    best delta candidates.
+
+  - "git pack-objects" learned a new heuristic to prefer delta
+    that is shallower in depth over the smallest delta
+    possible.  This improves both overall packfile access
+    performance and packfile density.
+
+  - diff-delta code that is used for packing has been improved
+    to work better on big files.
+
+  - when there are more than one pack files in the repository,
+    the runtime used to try finding an object always from the
+    newest packfile; it now tries the same packfile as we found
+    the object requested the last time, which exploits the
+    locality of references.
+
+  - verifying pack contents done by "git fsck --full" got boost
+    by carefully choosing the order to verify objects in them.
+
+  - "git read-tree -m" to read into an already populated index
+    has been optimized vastly.  The effect of this can be seen
+    when switching branches that have differences in only a
+    handful paths.
+
+  - "git add paths..." and "git commit paths..." has also been
+    heavily optimized.
+
+Fixes since v1.5.2
+------------------
+
+All of the fixes in v1.5.2 maintenance series are included in
+this release, unless otherwise noted.
+
+* Bugfixes
+
+  - "gitweb" had trouble handling non UTF-8 text with older
+    Encode.pm Perl module.
+
+  - "git svn" misparsed the data from the commits in the repository when
+    the user had "color.diff = true" in the configuration.  This has been
+    fixed.
+
+  - There was a case where "git svn dcommit" clobbered changes made on the
+    SVN side while committing multiple changes.
+
+  - "git-write-tree" had a bad interaction with racy-git avoidance and
+    gitattributes mechanisms.
+
+  - "git --bare command" overrode existing GIT_DIR setting and always
+    made it treat the current working directory as GIT_DIR.
+
+  - "git ls-files --error-unmatch" does not complain if you give the
+    same path pattern twice by mistake.
+
+  - "git init" autodetected core.filemode but not core.symlinks, which
+    made a new directory created automatically by "git clone" cumbersome
+    to use on filesystems that require these configurations to be set.
+
+  - "git log" family of commands behaved differently when run as "git
+    log" (no pathspec) and as "git log --" (again, no pathspec).  This
+    inconsistency was introduced somewhere in v1.3.0 series but now has
+    been corrected.
+
+  - "git rebase -m" incorrectly displayed commits that were skipped.
diff --git a/Documentation/RelNotes/1.5.4.1.txt b/Documentation/RelNotes/1.5.4.1.txt
new file mode 100644
index 0000000000..d4e44b8b09
--- /dev/null
+++ b/Documentation/RelNotes/1.5.4.1.txt
@@ -0,0 +1,17 @@
+GIT v1.5.4.1 Release Notes
+==========================
+
+Fixes since v1.5.4
+------------------
+
+ * "git-commit -C $tag" used to work but rewrite in C done in
+   1.5.4 broke it.
+
+ * An entry in the .gitattributes file that names a pattern in a
+   subdirectory of the directory it is in did not match
+   correctly (e.g. pattern "b/*.c" in "a/.gitattributes" should
+   match "a/b/foo.c" but it didn't).
+
+ * Customized color specification was parsed incorrectly when
+   numeric color values are used.  This was fixed in 1.5.4.1.
+
diff --git a/Documentation/RelNotes/1.5.4.2.txt b/Documentation/RelNotes/1.5.4.2.txt
new file mode 100644
index 0000000000..21d0df59fb
--- /dev/null
+++ b/Documentation/RelNotes/1.5.4.2.txt
@@ -0,0 +1,43 @@
+GIT v1.5.4.2 Release Notes
+==========================
+
+Fixes since v1.5.4
+------------------
+
+ * The configuration parser was not prepared to see string
+   valued variables misspelled as boolean and segfaulted.
+
+ * Temporary files left behind due to interrupted object
+   transfers were not cleaned up with "git prune".
+
+ * "git config --unset" was confused when the unset variables
+   were spelled with continuation lines in the config file.
+
+ * The merge message detection in "git cvsimport" did not catch
+   a message that began with "Merge...".
+
+ * "git status" suggests "git rm --cached" for unstaging the
+   earlier "git add" before the initial commit.
+
+ * "git status" output was incorrect during a partial commit.
+
+ * "git bisect" refused to start when the HEAD was detached.
+
+ * "git bisect" allowed a wildcard character in the commit
+   message expanded while writing its log file.
+
+ * Manual pages were not formatted correctly with docbook xsl
+   1.72; added a workaround.
+
+ * "git-commit -C $tag" used to work but rewrite in C done in
+   1.5.4 broke it.  This was fixed in 1.5.4.1.
+
+ * An entry in the .gitattributes file that names a pattern in a
+   subdirectory of the directory it is in did not match
+   correctly (e.g. pattern "b/*.c" in "a/.gitattributes" should
+   match "a/b/foo.c" but it didn't).  This was fixed in 1.5.4.1.
+
+ * Customized color specification was parsed incorrectly when
+   numeric color values are used.  This was fixed in 1.5.4.1.
+
+ * http transport misbehaved when linked with curl-gnutls.
diff --git a/Documentation/RelNotes/1.5.4.3.txt b/Documentation/RelNotes/1.5.4.3.txt
new file mode 100644
index 0000000000..b0fc67fb2a
--- /dev/null
+++ b/Documentation/RelNotes/1.5.4.3.txt
@@ -0,0 +1,27 @@
+GIT v1.5.4.3 Release Notes
+==========================
+
+Fixes since v1.5.4.2
+--------------------
+
+ * RPM spec used to pull in everything with 'git'.  This has been
+   changed so that 'git' package contains just the core parts,
+   and we now supply 'git-all' metapackage to slurp in everything.
+   This should match end user's expectation better.
+
+ * When some refs failed to update, git-push reported "failure"
+   which was unclear if some other refs were updated or all of
+   them failed atomically (the answer is the former).  Reworded
+   the message to clarify this.
+
+ * "git clone" from a repository whose HEAD was misconfigured
+   did not set up the remote properly.  Now it tries to do
+   better.
+
+ * Updated git-push documentation to clarify what "matching"
+   means, in order to reduce user confusion.
+
+ * Updated git-add documentation to clarify "add -u" operates in
+   the current subdirectory you are in, just like other commands.
+
+ * git-gui updates to work on OSX and Windows better.
diff --git a/Documentation/RelNotes/1.5.4.4.txt b/Documentation/RelNotes/1.5.4.4.txt
new file mode 100644
index 0000000000..323c1a88c7
--- /dev/null
+++ b/Documentation/RelNotes/1.5.4.4.txt
@@ -0,0 +1,66 @@
+GIT v1.5.4.4 Release Notes
+==========================
+
+Fixes since v1.5.4.3
+--------------------
+
+ * Building and installing with an overtight umask such as 077 made
+   installed templates unreadable by others, while the rest of the install
+   are done in a way that is friendly to umask 022.
+
+ * "git cvsexportcommit -w $cvsdir" misbehaved when GIT_DIR is set to a
+   relative directory.
+
+ * "git http-push" had an invalid memory access that could lead it to
+   segfault.
+
+ * When "git rebase -i" gave control back to the user for a commit that is
+   marked to be edited, it just said "modify it with commit --amend",
+   without saying what to do to continue after modifying it.  Give an
+   explicit instruction to run "rebase --continue" to be more helpful.
+
+ * "git send-email" in 1.5.4.3 issued a bogus empty In-Reply-To: header.
+
+ * "git bisect" showed mysterious "won't bisect on seeked tree" error message.
+   This was leftover from Cogito days to prevent "bisect" starting from a
+   cg-seeked state.  We still keep the Cogito safety, but running "git bisect
+   start" when another bisect was in effect will clean up and start over.
+
+ * "git push" with an explicit PATH to receive-pack did not quite work if
+   receive-pack was not on usual PATH.  We earlier fixed the same issue
+   with "git fetch" and upload-pack, but somehow forgot to do so in the
+   other direction.
+
+ * git-gui's info dialog was not displayed correctly when the user tries
+   to commit nothing (i.e. without staging anything).
+
+ * "git revert" did not properly fail when attempting to run with a
+   dirty index.
+
+ * "git merge --no-commit --no-ff <other>" incorrectly made commits.
+
+ * "git merge --squash --no-ff <other>", which is a nonsense combination
+   of options, was not rejected.
+
+ * "git ls-remote" and "git remote show" against an empty repository
+   failed, instead of just giving an empty result (regression).
+
+ * "git fast-import" did not handle a renamed path whose name needs to be
+   quoted, due to a bug in unquote_c_style() function.
+
+ * "git cvsexportcommit" was confused when multiple files with the same
+   basename needed to be pushed out in the same commit.
+
+ * "git daemon" did not send early errors to syslog.
+
+ * "git log --merge" did not work well with --left-right option.
+
+ * "git svn" prompted for client cert password every time it accessed the
+   server.
+
+ * The reset command in "git fast-import" data stream was documented to
+   end with an optional LF, but it actually required one.
+
+ * "git svn dcommit/rebase" did not honor --rewrite-root option.
+
+Also included are a handful documentation updates.
diff --git a/Documentation/RelNotes/1.5.4.5.txt b/Documentation/RelNotes/1.5.4.5.txt
new file mode 100644
index 0000000000..bbd130e36d
--- /dev/null
+++ b/Documentation/RelNotes/1.5.4.5.txt
@@ -0,0 +1,56 @@
+GIT v1.5.4.5 Release Notes
+==========================
+
+Fixes since v1.5.4.4
+--------------------
+
+ * "git fetch there" when the URL information came from the Cogito style
+   branches/there file did not update refs/heads/there (regression in
+   1.5.4).
+
+ * Bogus refspec configuration such as "remote.there.fetch = =" were not
+   detected as errors (regression in 1.5.4).
+
+ * You couldn't specify a custom editor whose path contains a whitespace
+   via GIT_EDITOR (and core.editor).
+
+ * The subdirectory filter to "git filter-branch" mishandled a history
+   where the subdirectory becomes empty and then later becomes non-empty.
+
+ * "git shortlog" gave an empty line if the original commit message was
+   malformed (e.g. a botched import from foreign SCM).  Now it finds the
+   first non-empty line and uses it for better information.
+
+ * When the user fails to give a revision parameter to "git svn", an error
+   from the Perl interpreter was issued because the script lacked proper
+   error checking.
+
+ * After "git rebase" stopped due to conflicts, if the user played with
+   "git reset" and friends, "git rebase --abort" failed to go back to the
+   correct commit.
+
+ * Additional work trees prepared with git-new-workdir (in contrib/) did
+   not share git-svn metadata directory .git/svn with the original.
+
+ * "git-merge-recursive" did not mark addition of the same path with
+   different filemodes correctly as a conflict.
+
+ * "gitweb" gave malformed URL when pathinfo stype paths are in use.
+
+ * "-n" stands for "--no-tags" again for "git fetch".
+
+ * "git format-patch" did not detect the need to add 8-bit MIME header
+   when the user used format.header configuration.
+
+ * "rev~" revision specifier used to mean "rev", which was inconsistent
+   with how "rev^" worked.  Now "rev~" is the same as "rev~1" (hence it
+   also is the same as "rev^1"), and "rev~0" is the same as "rev^0"
+   (i.e. it has to be a commit).
+
+ * "git quiltimport" did not grok empty lines, lines in "file -pNNN"
+   format to specify the prefix levels and lines with trailing comments.
+
+ * "git rebase -m" triggered pre-commit verification, which made
+   "rebase --continue" impossible.
+
+As usual, it also comes with many documentation fixes and clarifications.
diff --git a/Documentation/RelNotes/1.5.4.6.txt b/Documentation/RelNotes/1.5.4.6.txt
new file mode 100644
index 0000000000..3e3c3e55a3
--- /dev/null
+++ b/Documentation/RelNotes/1.5.4.6.txt
@@ -0,0 +1,43 @@
+GIT v1.5.4.6 Release Notes
+==========================
+
+I personally do not think there is any reason anybody should want to
+run v1.5.4.X series these days, because 'master' version is always
+more stable than any tagged released version of git.
+
+This is primarily to futureproof "git-shell" to accept requests
+without a dash between "git" and subcommand name (e.g. "git
+upload-pack") which the newer client will start to make sometime in
+the future.
+
+Fixes since v1.5.4.5
+--------------------
+
+ * Command line option "-n" to "git-repack" was not correctly parsed.
+
+ * Error messages from "git-apply" when the patchfile cannot be opened
+   have been improved.
+
+ * Error messages from "git-bisect" when given nonsense revisions have
+   been improved.
+
+ * reflog syntax that uses time e.g. "HEAD@{10 seconds ago}:path" did not
+   stop parsing at the closing "}".
+
+ * "git rev-parse --symbolic-full-name ^master^2" printed solitary "^",
+   but it should print nothing.
+
+ * "git apply" did not enforce "match at the beginning" correctly.
+
+ * a path specification "a/b" in .gitattributes file should not match
+   "sub/a/b", but it did.
+
+ * "git log --date-order --topo-order" did not override the earlier
+   date-order with topo-order as expected.
+
+ * "git fast-export" did not export octopus merges correctly.
+
+ * "git archive --prefix=$path/" mishandled gitattributes.
+
+As usual, it also comes with many documentation fixes and clarifications.
+
diff --git a/Documentation/RelNotes/1.5.4.7.txt b/Documentation/RelNotes/1.5.4.7.txt
new file mode 100644
index 0000000000..9065a0e273
--- /dev/null
+++ b/Documentation/RelNotes/1.5.4.7.txt
@@ -0,0 +1,10 @@
+GIT v1.5.4.7 Release Notes
+==========================
+
+Fixes since 1.5.4.7
+-------------------
+
+ * Removed support for an obsolete gitweb request URI, whose
+   implementation ran "git diff" Porcelain, instead of using plumbing,
+   which would have run an external diff command specified in the
+   repository configuration as the gitweb user.
diff --git a/Documentation/RelNotes/1.5.4.txt b/Documentation/RelNotes/1.5.4.txt
new file mode 100644
index 0000000000..f1323b6174
--- /dev/null
+++ b/Documentation/RelNotes/1.5.4.txt
@@ -0,0 +1,377 @@
+GIT v1.5.4 Release Notes
+========================
+
+Removal
+-------
+
+ * "git svnimport" was removed in favor of "git svn".  It is still there
+   in the source tree (contrib/examples) but unsupported.
+
+ * As git-commit and git-status have been rewritten, "git runstatus"
+   helper script lost all its users and has been removed.
+
+
+Temporarily disabled
+--------------------
+
+ * "git http-push" is known not to work well with cURL library older
+   than 7.16, and we had reports of repository corruption.  It is
+   disabled on such platforms for now.  Unfortunately, 1.5.3.8 shares
+   the same issue.  In other words, this does not mean you will be
+   fine if you stick to an older git release.  For now, please do not
+   use http-push from older git with cURL older than 7.16 if you
+   value your data. A proper fix will hopefully materialize in
+   later versions.
+
+
+Deprecation notices
+-------------------
+
+ * From v1.6.0, git will by default install dashed form of commands
+   (e.g. "git-commit") outside of users' normal $PATH, and will install
+   only selected commands ("git" itself, and "gitk") in $PATH.  This
+   implies:
+
+   - Using dashed forms of git commands (e.g. "git-commit") from the
+     command line has been informally deprecated since early 2006, but
+     now it officially is, and will be removed in the future.  Use
+     dash-less forms (e.g. "git commit") instead.
+
+   - Using dashed forms from your scripts, without first prepending the
+     return value from "git --exec-path" to the scripts' PATH, has been
+     informally deprecated since early 2006, but now it officially is.
+
+   - Use of dashed forms with "PATH=$(git --exec-path):$PATH; export
+     PATH" early in your script is not deprecated with this change.
+
+   Users are strongly encouraged to adjust their habits and scripts now
+   to prepare for this change.
+
+ * The post-receive hook was introduced in March 2007 to supersede
+   the post-update hook, primarily to overcome the command line length
+   limitation of the latter.  Use of post-update hook will be deprecated
+   in future versions of git, starting from v1.6.0.
+
+ * "git lost-found" was deprecated in favor of "git fsck"'s --lost-found
+   option, and will be removed in the future.
+
+ * "git peek-remote" is deprecated, as "git ls-remote" was written in C
+   and works for all transports; "git peek-remote" will be removed in
+   the future.
+
+ * "git repo-config" which was an old name for "git config" command
+   has been supported without being advertised for a long time.  The
+   next feature release will remove it.
+
+ * From v1.6.0, the repack.usedeltabaseoffset config option will default
+   to true, which will give denser packfiles (i.e. more efficient storage).
+   The downside is that git older than version 1.4.4 will not be able
+   to directly use a repository packed using this setting.
+
+ * From v1.6.0, the pack.indexversion config option will default to 2,
+   which is slightly more efficient, and makes repacking more immune to
+   data corruptions.  Git older than version 1.5.2 may revert to version 1
+   of the pack index with a manual "git index-pack" to be able to directly
+   access corresponding pack files.
+
+
+Updates since v1.5.3
+--------------------
+
+ * Comes with much improved gitk, with i18n.
+
+ * Comes with git-gui 0.9.2 with i18n.
+
+ * gitk is now merged as a subdirectory of git.git project, in
+   preparation for its i18n.
+
+ * progress displays from many commands are a lot nicer to the eye.
+   Transfer commands show throughput data.
+
+ * many commands that pay attention to per-directory .gitignore now do
+   so lazily, which makes the usual case go much faster.
+
+ * Output processing for '--pretty=format:<user format>' has been
+   optimized.
+
+ * Rename detection of diff family while detecting exact matches has
+   been greatly optimized.
+
+ * Rename detection of diff family tries to make more natural looking
+   pairing.  Earlier, if multiple identical rename sources were
+   found in the preimage, the source used was picked pretty much at random.
+
+ * Value "true" for color.diff and color.status configuration used to
+   mean "always" (even when the output is not going to a terminal).
+   This has been corrected to mean the same thing as "auto".
+
+ * "git diff" Porcelain now respects diff.external configuration, which
+   is another way to specify GIT_EXTERNAL_DIFF.
+
+ * "git diff" can be told to use different prefixes other than
+   "a/" and "b/" e.g. "git diff --src-prefix=l/ --dst-prefix=k/".
+
+ * "git diff" sometimes did not quote paths with funny
+   characters properly.
+
+ * "git log" (and any revision traversal commands) misbehaved
+   when --diff-filter is given but was not asked to actually
+   produce diff.
+
+ * HTTP proxy can be specified per remote repository using
+   remote.*.httpproxy configuration, or global http.proxy configuration
+   variable.
+
+ * Various Perforce importer updates.
+
+ * Example update and post-receive hooks have been improved.
+
+ * Any command that wants to take a commit object name can now use
+   ":/string" syntax to name a commit.
+
+ * "git reset" is now built-in and its output can be squelched with -q.
+
+ * "git reset --hard" does not make any sense in a bare
+   repository, but did not error out; fixed.
+
+ * "git send-email" can optionally talk over ssmtp and use SMTP-AUTH.
+
+ * "git rebase" learned --whitespace option.
+
+ * In "git rebase", when you decide not to replay a particular change
+   after the command stopped with a conflict, you can say "git rebase
+   --skip" without first running "git reset --hard", as the command now
+   runs it for you.
+
+ * "git rebase --interactive" mode can now work on detached HEAD.
+
+ * Other minor to serious bugs in "git rebase -i" have been fixed.
+
+ * "git rebase" now detaches head during its operation, so after a
+   successful "git rebase" operation, the reflog entry branch@{1} for
+   the current branch points at the commit before the rebase was
+   started.
+
+ * "git rebase -i" also triggers rerere to help your repeated merges.
+
+ * "git merge" can call the "post-merge" hook.
+
+ * "git pack-objects" can optionally run deltification with multiple
+   threads.
+
+ * "git archive" can optionally substitute keywords in files marked with
+   export-subst attribute.
+
+ * "git cherry-pick" made a misguided attempt to repeat the original
+   command line in the generated log message, when told to cherry-pick a
+   commit by naming a tag that points at it.  It does not anymore.
+
+ * "git for-each-ref" learned %(xxxdate:<date-format>) syntax to show the
+   various date fields in different formats.
+
+ * "git gc --auto" is a low-impact way to automatically run a variant of
+   "git repack" that does not lose unreferenced objects (read: safer
+   than the usual one) after the user accumulates too many loose
+   objects.
+
+ * "git clean" has been rewritten in C.
+
+ * You need to explicitly set clean.requireForce to "false" to allow
+   "git clean" without -f to do any damage (lack of the configuration
+   variable used to mean "do not require -f option to lose untracked
+   files", but we now use the safer default).
+
+ * The kinds of whitespace errors "git diff" and "git apply" notice (and
+   fix) can be controlled via 'core.whitespace' configuration variable
+   and 'whitespace' attribute in .gitattributes file.
+
+ * "git push" learned --dry-run option to show what would happen if a
+   push is run.
+
+ * "git push" does not update a tracking ref on the local side when the
+   remote refused to update the corresponding ref.
+
+ * "git push" learned --mirror option.  This is to push the local refs
+   one-to-one to the remote, and deletes refs from the remote that do
+   not exist anymore in the repository on the pushing side.
+
+ * "git push" can remove a corrupt ref at the remote site with the usual
+   ":ref" refspec.
+
+ * "git remote" knows --mirror mode.  This is to set up configuration to
+   push into a remote repository to store local branch heads to the same
+   branch on the remote side, and remove branch heads locally removed
+   from local repository at the same time.  Suitable for pushing into a
+   back-up repository.
+
+ * "git remote" learned "rm" subcommand.
+
+ * "git cvsserver" can be run via "git shell".  Also, "cvs" is
+   recognized as a synonym for "git cvsserver", so that CVS users
+   can be switched to git just by changing their login shell.
+
+ * "git cvsserver" acts more like receive-pack by running post-receive
+   and post-update hooks.
+
+ * "git am" and "git rebase" are far less verbose.
+
+ * "git pull" learned to pass --[no-]ff option to underlying "git
+   merge".
+
+ * "git pull --rebase" is a different way to integrate what you fetched
+   into your current branch.
+
+ * "git fast-export" produces data-stream that can be fed to fast-import
+   to reproduce the history recorded in a git repository.
+
+ * "git add -i" takes pathspecs to limit the set of files to work on.
+
+ * "git add -p" is a short-hand to go directly to the selective patch
+   subcommand in the interactive command loop and to exit when done.
+
+ * "git add -i" UI has been colorized.  The interactive prompt
+   and menu can be colored by setting color.interactive
+   configuration.  The diff output (including the hunk picker)
+   are colored with color.diff configuration.
+
+ * "git commit --allow-empty" allows you to create a single-parent
+   commit that records the same tree as its parent, overriding the usual
+   safety valve.
+
+ * "git commit --amend" can amend a merge that does not change the tree
+   from its first parent.
+
+ * "git commit" used to unconditionally strip comment lines that
+   began with '#' and removed excess blank lines.  This behavior has
+   been made configurable.
+
+ * "git commit" has been rewritten in C.
+
+ * "git stash random-text" does not create a new stash anymore.  It was
+   a UI mistake.  Use "git stash save random-text", or "git stash"
+   (without extra args) for that.
+
+ * "git stash clear extra-text" does not clear the whole stash
+   anymore.  It is tempting to expect "git stash clear stash@{2}"
+   to drop only a single named stash entry, and it is rude to
+   discard everything when that is asked (but not provided).
+
+ * "git prune --expire <time>" can exempt young loose objects from
+   getting pruned.
+
+ * "git branch --contains <commit>" can list branches that are
+   descendants of a given commit.
+
+ * "git log" learned --early-output option to help interactive GUI
+   implementations.
+
+ * "git bisect" learned "skip" action to mark untestable commits.
+
+ * "git bisect visualize" learned a shorter synonym "git bisect view".
+
+ * "git bisect visualize" runs "git log" in a non-windowed
+   environments.  It also can be told what command to run (e.g. "git
+   bisect visualize tig").
+
+ * "git format-patch" learned "format.numbered" configuration variable
+   to automatically turn --numbered option on when more than one commits
+   are formatted.
+
+ * "git ls-files" learned "--exclude-standard" to use the canned set of
+   exclude files.
+
+ * "git tag -a -f existing" begins the editor session using the existing
+   annotation message.
+
+ * "git tag -m one -m bar" (multiple -m options) behaves similarly to
+   "git commit"; the parameters to -m options are formatted as separate
+   paragraphs.
+
+ * The format "git show" outputs an annotated tag has been updated to
+   include "Tagger: " and "Date: " lines from the tag itself.  Strictly
+   speaking this is a backward incompatible change, but this is a
+   reasonable usability fix and people's scripts shouldn't have been
+   relying on the exact output from "git show" Porcelain anyway.
+
+ * "git cvsimport" did not notice errors from underlying "cvsps"
+   and produced a corrupt import silently.
+
+ * "git cvsexportcommit" learned -w option to specify and switch to the
+   CVS working directory.
+
+ * "git checkout" from a subdirectory learned to use "../path" to allow
+   checking out a path outside the current directory without cd'ing up.
+
+ * "git checkout" from and to detached HEAD leaves a bit more
+   information in the reflog.
+
+ * "git send-email --dry-run" shows full headers for easier diagnosis.
+
+ * "git merge-ours" is now built-in.
+
+ * "git svn" learned "info" and "show-externals" subcommands.
+
+ * "git svn" run from a subdirectory failed to read settings from the
+   .git/config.
+
+ * "git svn" learned --use-log-author option, which picks up more
+   descriptive name from From: and Signed-off-by: lines in the commit
+   message.
+
+ * "git svn" wasted way too much disk to record revision mappings
+   between svn and git; a new representation that is much more compact
+   for this information has been introduced to correct this.
+
+ * "git svn" left temporary index files it used without cleaning them
+   up; this was corrected.
+
+ * "git status" from a subdirectory now shows relative paths, which
+   makes copy-and-pasting for git-checkout/git-add/git-rm easier.  The
+   traditional behavior to show the full path relative to the top of
+   the work tree can be had by setting status.relativepaths
+   configuration variable to false.
+
+ * "git blame" kept text for each annotated revision in core needlessly;
+   this has been corrected.
+
+ * "git shortlog" learned to default to HEAD when the standard input is
+   a terminal and the user did not give any revision parameter.
+
+ * "git shortlog" learned "-e" option to show e-mail addresses as well as
+   authors' names.
+
+ * "git help" learned "-w" option to show documentation in browsers.
+
+ * In addition there are quite a few internal clean-ups. Notably:
+
+   - many fork/exec have been replaced with run-command API,
+     brought from the msysgit effort.
+
+   - introduction and more use of the option parser API.
+
+   - enhancement and more use of the strbuf API.
+
+ * Makefile tweaks to support HP-UX is in.
+
+Fixes since v1.5.3
+------------------
+
+All of the fixes in v1.5.3 maintenance series are included in
+this release, unless otherwise noted.
+
+These fixes are only in v1.5.4 and not backported to v1.5.3 maintenance
+series.
+
+ * The way "git diff --check" behaves is much more consistent with the way
+   "git apply --whitespace=warn" works.
+
+ * "git svn" talking with the SVN over HTTP will correctly quote branch
+   and project names.
+
+ * "git config" did not work correctly on platforms that define
+   REG_NOMATCH to an even number.
+
+ * Recent versions of AsciiDoc 8 has a change to break our
+   documentation; a workaround has been implemented.
+
+ * "git diff --color-words" colored context lines in a wrong color.
diff --git a/Documentation/RelNotes/1.5.5.1.txt b/Documentation/RelNotes/1.5.5.1.txt
new file mode 100644
index 0000000000..7de419708f
--- /dev/null
+++ b/Documentation/RelNotes/1.5.5.1.txt
@@ -0,0 +1,44 @@
+GIT v1.5.5.1 Release Notes
+==========================
+
+Fixes since v1.5.5
+------------------
+
+ * "git archive --prefix=$path/" mishandled gitattributes.
+
+ * "git fetch -v" that fetches into FETCH_HEAD did not report the summary
+   the same way as done for updating the tracking refs.
+
+ * "git svn" misbehaved when the configuration file customized the "git
+   log" output format using format.pretty.
+
+ * "git submodule status" leaked an unnecessary error message.
+
+ * "git log --date-order --topo-order" did not override the earlier
+   date-order with topo-order as expected.
+
+ * "git bisect good $this" did not check the validity of the revision
+   given properly.
+
+ * "url.<there>.insteadOf" did not work correctly.
+
+ * "git clean" ran inside subdirectory behaved as if the directory was
+   explicitly specified for removal by the end user from the top level.
+
+ * "git bisect" from a detached head leaked an unnecessary error message.
+
+ * "git bisect good $a $b" when $a is Ok but $b is bogus should have
+   atomically failed before marking $a as good.
+
+ * "git fmt-merge-msg" did not clean up leading empty lines from commit
+   log messages like "git log" family does.
+
+ * "git am" recorded a commit with empty Subject: line without
+   complaining.
+
+ * when given a commit log message whose first paragraph consists of
+   multiple lines, "git rebase" squashed it into a single line.
+
+ * "git remote add $bogus_name $url" did not complain properly.
+
+Also comes with various documentation updates.
diff --git a/Documentation/RelNotes/1.5.5.2.txt b/Documentation/RelNotes/1.5.5.2.txt
new file mode 100644
index 0000000000..391a7b02ea
--- /dev/null
+++ b/Documentation/RelNotes/1.5.5.2.txt
@@ -0,0 +1,27 @@
+GIT v1.5.5.2 Release Notes
+==========================
+
+Fixes since v1.5.5.1
+--------------------
+
+ * "git repack -n" was mistakenly made no-op earlier.
+
+ * "git imap-send" wanted to always have imap.host even when use of
+   imap.tunnel made it unnecessary.
+
+ * reflog syntax that uses time e.g. "HEAD@{10 seconds ago}:path" did not
+   stop parsing at the closing "}".
+
+ * "git rev-parse --symbolic-full-name ^master^2" printed solitary "^",
+   but it should print nothing.
+
+ * "git commit" did not detect when it failed to write tree objects.
+
+ * "git fetch" sometimes transferred too many objects unnecessarily.
+
+ * a path specification "a/b" in .gitattributes file should not match
+   "sub/a/b".
+
+ * various gitweb fixes.
+
+Also comes with various documentation updates.
diff --git a/Documentation/RelNotes/1.5.5.3.txt b/Documentation/RelNotes/1.5.5.3.txt
new file mode 100644
index 0000000000..f22f98b734
--- /dev/null
+++ b/Documentation/RelNotes/1.5.5.3.txt
@@ -0,0 +1,12 @@
+GIT v1.5.5.3 Release Notes
+==========================
+
+Fixes since v1.5.5.2
+--------------------
+
+ * "git send-email --compose" did not notice that non-ascii contents
+   needed some MIME magic.
+
+ * "git fast-export" did not export octopus merges correctly.
+
+Also comes with various documentation updates.
diff --git a/Documentation/RelNotes/1.5.5.4.txt b/Documentation/RelNotes/1.5.5.4.txt
new file mode 100644
index 0000000000..2d0279ecce
--- /dev/null
+++ b/Documentation/RelNotes/1.5.5.4.txt
@@ -0,0 +1,7 @@
+GIT v1.5.5.4 Release Notes
+==========================
+
+Fixes since v1.5.5.4
+--------------------
+
+ * "git name-rev --all" used to segfault.
diff --git a/Documentation/RelNotes/1.5.5.5.txt b/Documentation/RelNotes/1.5.5.5.txt
new file mode 100644
index 0000000000..30fa3615c7
--- /dev/null
+++ b/Documentation/RelNotes/1.5.5.5.txt
@@ -0,0 +1,11 @@
+GIT v1.5.5.5 Release Notes
+==========================
+
+I personally do not think there is any reason anybody should want to
+run v1.5.5.X series these days, because 'master' version is always
+more stable than any tagged released version of git.
+
+This is primarily to futureproof "git-shell" to accept requests
+without a dash between "git" and subcommand name (e.g. "git
+upload-pack") which the newer client will start to make sometime in
+the future.
diff --git a/Documentation/RelNotes/1.5.5.6.txt b/Documentation/RelNotes/1.5.5.6.txt
new file mode 100644
index 0000000000..d5e85cb70e
--- /dev/null
+++ b/Documentation/RelNotes/1.5.5.6.txt
@@ -0,0 +1,10 @@
+GIT v1.5.5.6 Release Notes
+==========================
+
+Fixes since 1.5.5.5
+-------------------
+
+ * Removed support for an obsolete gitweb request URI, whose
+   implementation ran "git diff" Porcelain, instead of using plumbing,
+   which would have run an external diff command specified in the
+   repository configuration as the gitweb user.
diff --git a/Documentation/RelNotes/1.5.5.txt b/Documentation/RelNotes/1.5.5.txt
new file mode 100644
index 0000000000..2932212488
--- /dev/null
+++ b/Documentation/RelNotes/1.5.5.txt
@@ -0,0 +1,207 @@
+GIT v1.5.5 Release Notes
+========================
+
+Updates since v1.5.4
+--------------------
+
+(subsystems)
+
+ * Comes with git-gui 0.10.1
+
+(portability)
+
+ * We shouldn't ask for BSD group ownership semantics by setting g+s bit
+   on directories on older BSD systems that refuses chmod() by non root
+   users.  BSD semantics is the default there anyway.
+
+ * Bunch of portability improvement patches coming from an effort to port
+   to Solaris has been applied.
+
+(performance)
+
+ * On platforms with suboptimal qsort(3) implementation, there
+   is an option to use more reasonable substitute we ship with
+   our software.
+
+ * New configuration variable "pack.packsizelimit" can be used
+   in place of command line option --max-pack-size.
+
+ * "git fetch" over the native git protocol used to make a
+   connection to find out the set of current remote refs and
+   another to actually download the pack data.  We now use only
+   one connection for these tasks.
+
+ * "git commit" does not run lstat(2) more than necessary
+   anymore.
+
+(usability, bells and whistles)
+
+ * Bash completion script (in contrib) are aware of more commands and
+   options.
+
+ * You can be warned when core.autocrlf conversion is applied in
+   such a way that results in an irreversible conversion.
+
+ * A catch-all "color.ui" configuration variable can be used to
+   enable coloring of all color-capable commands, instead of
+   individual ones such as "color.status" and "color.branch".
+
+ * The commands refused to take absolute pathnames where they
+   require pathnames relative to the work tree or the current
+   subdirectory.  They now can take absolute pathnames in such a
+   case as long as the pathnames do not refer outside of the
+   work tree.  E.g. "git add $(pwd)/foo" now works.
+
+ * Error messages used to be sent to stderr, only to get hidden,
+   when $PAGER was in use.  They now are sent to stdout along
+   with the command output to be shown in the $PAGER.
+
+ * A pattern "foo/" in .gitignore file now matches a directory
+   "foo".  Pattern "foo" also matches as before.
+
+ * bash completion's prompt helper function can talk about
+   operation in-progress (e.g. merge, rebase, etc.).
+
+ * Configuration variables "url.<usethis>.insteadof = <otherurl>" can be
+   used to tell "git-fetch" and "git-push" to use different URL than what
+   is given from the command line.
+
+ * "git add -i" behaves better even before you make an initial commit.
+
+ * "git am" refused to run from a subdirectory without a good reason.
+
+ * After "git apply --whitespace=fix" fixes whitespace errors in a patch,
+   a line before the fix can appear as a context or preimage line in a
+   later patch, causing the patch not to apply.  The command now knows to
+   see through whitespace fixes done to context lines to successfully
+   apply such a patch series.
+
+ * "git branch" (and "git checkout -b") to branch from a local branch can
+   optionally set "branch.<name>.merge" to mark the new branch to build on
+   the other local branch, when "branch.autosetupmerge" is set to
+   "always", or when passing the command line option "--track" (this option
+   was ignored when branching from local branches).  By default, this does
+   not happen when branching from a local branch.
+
+ * "git checkout" to switch to a branch that has "branch.<name>.merge" set
+   (i.e. marked to build on another branch) reports how much the branch
+   and the other branch diverged.
+
+ * When "git checkout" has to update a lot of paths, it used to be silent
+   for 4 seconds before it showed any progress report.  It is now a bit
+   more impatient and starts showing progress report early.
+
+ * "git commit" learned a new hook "prepare-commit-msg" that can
+   inspect what is going to be committed and prepare the commit
+   log message template to be edited.
+
+ * "git cvsimport" can now take more than one -M options.
+
+ * "git describe" learned to limit the tags to be used for
+   naming with --match option.
+
+ * "git describe --contains" now barfs when the named commit
+   cannot be described.
+
+ * "git describe --exact-match" describes only commits that are tagged.
+
+ * "git describe --long" describes a tagged commit as $tag-0-$sha1,
+   instead of just showing the exact tagname.
+
+ * "git describe" warns when using a tag whose name and path contradict
+   with each other.
+
+ * "git diff" learned "--relative" option to limit and output paths
+   relative to the current directory when working in a subdirectory.
+
+ * "git diff" learned "--dirstat" option to show birds-eye-summary of
+   changes more concisely than "--diffstat".
+
+ * "git format-patch" learned --cover-letter option to generate a cover
+   letter template.
+
+ * "git gc" learned --quiet option.
+
+ * "git gc" now automatically prunes unreachable objects that are two
+   weeks old or older.
+
+ * "git gc --auto" can be disabled more easily by just setting gc.auto
+   to zero.  It also tolerates more packfiles by default.
+
+ * "git grep" now knows "--name-only" is a synonym for the "-l" option.
+
+ * "git help <alias>" now reports "'git <alias>' is alias to <what>",
+   instead of saying "No manual entry for git-<alias>".
+
+ * "git help" can use different backends to show manual pages and this can
+   be configured using "man.viewer" configuration.
+
+ * "gitk" does not restore window position from $HOME/.gitk anymore (it
+   still restores the size).
+
+ * "git log --grep=<what>" learned "--fixed-strings" option to look for
+   <what> without treating it as a regular expression.
+
+ * "git gui" learned an auto-spell checking.
+
+ * "git push <somewhere> HEAD" and "git push <somewhere> +HEAD" works as
+   expected; they push the current branch (and only the current branch).
+   In addition, HEAD can be written as the value of "remote.<there>.push"
+   configuration variable.
+
+ * When the configuration variable "pack.threads" is set to 0, "git
+   repack" auto detects the number of CPUs and uses that many threads.
+
+ * "git send-email" learned to prompt for passwords
+   interactively.
+
+ * "git send-email" learned an easier way to suppress CC
+   recipients.
+
+ * "git stash" learned "pop" command, that applies the latest stash and
+   removes it from the stash, and "drop" command to discard the named
+   stash entry.
+
+ * "git submodule" learned a new subcommand "summary" to show the
+   symmetric difference between the HEAD version and the work tree version
+   of the submodule commits.
+
+ * Various "git cvsimport", "git cvsexportcommit", "git cvsserver",
+   "git svn" and "git p4" improvements.
+
+(internal)
+
+ * Duplicated code between git-help and git-instaweb that
+   launches user's preferred browser has been refactored.
+
+ * It is now easier to write test scripts that records known
+   breakages.
+
+ * "git checkout" is rewritten in C.
+
+ * "git remote" is rewritten in C.
+
+ * Two conflict hunks that are separated by a very short span of common
+   lines are now coalesced into one larger hunk, to make the result easier
+   to read.
+
+ * Run-command API's use of file descriptors is documented clearer and
+   is more consistent now.
+
+ * diff output can be sent to FILE * that is different from stdout.  This
+   will help reimplementing more things in C.
+
+Fixes since v1.5.4
+------------------
+
+All of the fixes in v1.5.4 maintenance series are included in
+this release, unless otherwise noted.
+
+ * "git-http-push" did not allow deletion of remote ref with the usual
+   "push <remote> :<branch>" syntax.
+
+ * "git-rebase --abort" did not go back to the right location if
+   "git-reset" was run during the "git-rebase" session.
+
+ * "git imap-send" without setting imap.host did not error out but
+   segfaulted.
diff --git a/Documentation/RelNotes/1.5.6.1.txt b/Documentation/RelNotes/1.5.6.1.txt
new file mode 100644
index 0000000000..4864b16445
--- /dev/null
+++ b/Documentation/RelNotes/1.5.6.1.txt
@@ -0,0 +1,28 @@
+GIT v1.5.6.1 Release Notes
+==========================
+
+Fixes since v1.5.6
+------------------
+
+* Last minute change broke loose object creation on AIX.
+
+* (performance fix) We used to make $GIT_DIR absolute path early in the
+  programs but keeping it relative to the current directory internally
+  gives 1-3 per-cent performance boost.
+
+* bash completion knows the new --graph option to git-log family.
+
+
+* git-diff -c/--cc showed unnecessary "deletion" lines at the context
+  boundary.
+
+* git-for-each-ref ignored %(object) and %(type) requests for tag
+  objects.
+
+* git-merge usage had a typo.
+
+* Rebuilding of git-svn metainfo database did not take rewriteRoot
+  option into account.
+
+* Running "git-rebase --continue/--skip/--abort" before starting a
+  rebase gave nonsense error messages.
diff --git a/Documentation/RelNotes/1.5.6.2.txt b/Documentation/RelNotes/1.5.6.2.txt
new file mode 100644
index 0000000000..5902a85a78
--- /dev/null
+++ b/Documentation/RelNotes/1.5.6.2.txt
@@ -0,0 +1,40 @@
+GIT v1.5.6.2 Release Notes
+==========================
+
+Futureproof
+-----------
+
+ * "git-shell" accepts requests without a dash between "git" and
+   subcommand name (e.g. "git upload-pack") which the newer client will
+   start to make sometime in the future.
+
+Fixes since v1.5.6.1
+--------------------
+
+* "git clone" from a remote that is named with url.insteadOf setting in
+  $HOME/.gitconfig did not work well.
+
+* "git describe --long --tags" segfaulted when the described revision was
+  tagged with a lightweight tag.
+
+* "git diff --check" did not report the result via its exit status
+  reliably.
+
+* When remote side used to have branch 'foo' and git-fetch finds that now
+  it has branch 'foo/bar', it refuses to lose the existing remote tracking
+  branch and its reflog.  The error message has been improved to suggest
+  pruning the remote if the user wants to proceed and get the latest set
+  of branches from the remote, including such 'foo/bar'.
+
+* "git reset file" should mean the same thing as "git reset HEAD file",
+  but we required disambiguating -- even when "file" is not ambiguous.
+
+* "git show" segfaulted when an annotated tag that points at another
+  annotated tag was given to it.
+
+* Optimization for a large import via "git-svn" introduced in v1.5.6 had a
+  serious memory and temporary file leak, which made it unusable for
+  moderately large import.
+
+* "git-svn" mangled remote nickname used in the configuration file
+  unnecessarily.
diff --git a/Documentation/RelNotes/1.5.6.3.txt b/Documentation/RelNotes/1.5.6.3.txt
new file mode 100644
index 0000000000..f61dd3504a
--- /dev/null
+++ b/Documentation/RelNotes/1.5.6.3.txt
@@ -0,0 +1,52 @@
+GIT v1.5.6.3 Release Notes
+==========================
+
+Fixes since v1.5.6.2
+--------------------
+
+* Setting core.sharedrepository to traditional "true" value was supposed to make
+  the repository group writable but should not affect permission for others.
+  However, since 1.5.6, it was broken to drop permission for others when umask is
+  022, making the repository unreadable by others.
+
+* Setting GIT_TRACE will report spawning of external process via run_command().
+
+* Using an object with very deep delta chain pinned memory needed for extracting
+  intermediate base objects unnecessarily long, leading to excess memory usage.
+
+* Bash completion script did not notice '--' marker on the command
+  line and tried the relatively slow "ref completion" even when
+  completing arguments after one.
+
+* Registering a non-empty blob racily and then truncating the working
+  tree file for it confused "racy-git avoidance" logic into thinking
+  that the path is now unchanged.
+
+* The section that describes attributes related to git-archive were placed
+  in a wrong place in the gitattributes(5) manual page.
+
+* "git am" was not helpful to the users when it detected that the committer
+  information is not set up properly yet.
+
+* "git clone" had a leftover debugging fprintf().
+
+* "git clone -q" was not quiet enough as it used to and gave object count
+  and progress reports.
+
+* "git clone" marked downloaded packfile with .keep; this could be a
+  good thing if the remote side is well packed but otherwise not,
+  especially for a project that is not really big.
+
+* "git daemon" used to call syslog() from a signal handler, which
+  could raise signals of its own but generally is not reentrant.  This
+  was fixed by restructuring the code to report syslog() after the handler
+  returns.
+
+* When "git push" tries to remove a remote ref, and corresponding
+  tracking ref is missing, we used to report error (i.e. failure to
+  remove something that does not exist).
+
+* "git mailinfo" (hence "git am") did not handle commit log messages in a
+  MIME multipart mail correctly.
+
+Contains other various documentation fixes.
diff --git a/Documentation/RelNotes/1.5.6.4.txt b/Documentation/RelNotes/1.5.6.4.txt
new file mode 100644
index 0000000000..d8968f1ecb
--- /dev/null
+++ b/Documentation/RelNotes/1.5.6.4.txt
@@ -0,0 +1,47 @@
+GIT v1.5.6.4 Release Notes
+==========================
+
+Fixes since v1.5.6.3
+--------------------
+
+* Various commands could overflow its internal buffer on a platform
+  with small PATH_MAX value in a repository that has contents with
+  long pathnames.
+
+* There wasn't a way to make --pretty=format:%<> specifiers to honor
+  .mailmap name rewriting for authors and committers.  Now you can with
+  %aN and %cN.
+
+* Bash completion wasted too many cycles; this has been optimized to be
+  usable again.
+
+* Bash completion lost ref part when completing something like "git show
+  pu:Makefile".
+
+* "git-cvsserver" did not clean up its temporary working area after annotate
+  request.
+
+* "git-daemon" called syslog() from its signal handler, which was a
+  no-no.
+
+* "git-fetch" into an empty repository used to remind that the fetch will
+   be huge by saying "no common commits", but this was an unnecessary
+   noise; it is already known by the user anyway.
+
+* "git-http-fetch" would have segfaulted when pack idx file retrieved
+  from the other side was corrupt.
+
+* "git-index-pack" used too much memory when dealing with a deep delta chain.
+
+* "git-mailinfo" (hence "git-am") did not correctly handle in-body [PATCH]
+  line to override the commit title taken from the mail Subject header.
+
+* "git-rebase -i -p" lost parents that are not involved in the history
+  being rewritten.
+
+* "git-rm" lost track of where the index file was when GIT_DIR was
+  specified as a relative path.
+
+* "git-rev-list --quiet" was not quiet as advertised.
+
+Contains other various documentation fixes.
diff --git a/Documentation/RelNotes/1.5.6.5.txt b/Documentation/RelNotes/1.5.6.5.txt
new file mode 100644
index 0000000000..47ca172462
--- /dev/null
+++ b/Documentation/RelNotes/1.5.6.5.txt
@@ -0,0 +1,29 @@
+GIT v1.5.6.5 Release Notes
+==========================
+
+Fixes since v1.5.6.4
+--------------------
+
+* "git cvsimport" used to spit out "UNKNOWN LINE..." diagnostics to stdout.
+
+* "git commit -F filename" and "git tag -F filename" run from subdirectories
+  did not read the right file.
+
+* "git init --template=" with blank "template" parameter linked files
+  under root directories to .git, which was a total nonsense.  Instead, it
+  means "I do not want to use anything from the template directory".
+
+* "git diff-tree" and other diff plumbing ignored diff.renamelimit configuration
+  variable when the user explicitly asked for rename detection.
+
+* "git name-rev --name-only" did not work when "--stdin" option was in effect.
+
+* "git show-branch" mishandled its 8th branch.
+
+* Addition of "git update-index --ignore-submodules" that happened during
+  1.5.6 cycle broke "git update-index --ignore-missing".
+
+* "git send-email" did not parse charset from an existing Content-type:
+  header properly.
+
+Contains other various documentation fixes.
diff --git a/Documentation/RelNotes/1.5.6.6.txt b/Documentation/RelNotes/1.5.6.6.txt
new file mode 100644
index 0000000000..79da23db5a
--- /dev/null
+++ b/Documentation/RelNotes/1.5.6.6.txt
@@ -0,0 +1,10 @@
+GIT v1.5.6.6 Release Notes
+==========================
+
+Fixes since 1.5.6.5
+-------------------
+
+ * Removed support for an obsolete gitweb request URI, whose
+   implementation ran "git diff" Porcelain, instead of using plumbing,
+   which would have run an external diff command specified in the
+   repository configuration as the gitweb user.
diff --git a/Documentation/RelNotes/1.5.6.txt b/Documentation/RelNotes/1.5.6.txt
new file mode 100644
index 0000000000..e143d8d61b
--- /dev/null
+++ b/Documentation/RelNotes/1.5.6.txt
@@ -0,0 +1,115 @@
+GIT v1.5.6 Release Notes
+========================
+
+Updates since v1.5.5
+--------------------
+
+(subsystems)
+
+* Comes with updated gitk and git-gui.
+
+(portability)
+
+* git will build on AIX better than before now.
+
+* core.ignorecase configuration variable can be used to work better on
+  filesystems that are not case sensitive.
+
+* "git init" now autodetects the case sensitivity of the filesystem and
+  sets core.ignorecase accordingly.
+
+* cpio is no longer used; neither "curl" binary (libcurl is still used).
+
+(documentation)
+
+* Many freestanding documentation pages have been converted and made
+  available to "git help" (aka "man git<something>") as section 7 of
+  the manual pages. This means bookmarks to some HTML documentation
+  files may need to be updated (eg "tutorial.html" became
+  "gittutorial.html").
+
+(performance)
+
+* "git clone" was rewritten in C.  This will hopefully help cloning a
+  repository with insane number of refs.
+
+* "git rebase --onto $there $from $branch" used to switch to the tip of
+  $branch only to immediately reset back to $from, smudging work tree
+  files unnecessarily.  This has been optimized.
+
+* Object creation codepath in "git-svn" has been optimized by enhancing
+  plumbing commands git-cat-file and git-hash-object.
+
+(usability, bells and whistles)
+
+* "git add -p" (and the "patch" subcommand of "git add -i") can choose to
+  apply (or not apply) mode changes independently from contents changes.
+
+* "git bisect help" gives longer and more helpful usage information.
+
+* "git bisect" does not use a special branch "bisect" anymore; instead, it
+  does its work on a detached HEAD.
+
+* "git branch" (and "git checkout -b") can be told to set up
+  branch.<name>.rebase automatically, so that later you can say "git pull"
+  and magically cause "git pull --rebase" to happen.
+
+* "git branch --merged" and "git branch --no-merged" can be used to list
+  branches that have already been merged (or not yet merged) to the
+  current branch.
+
+* "git cherry-pick" and "git revert" can add a sign-off.
+
+* "git commit" mentions the author identity when you are committing
+  somebody else's changes.
+
+* "git diff/log --dirstat" output is consistent between binary and textual
+  changes.
+
+* "git filter-branch" rewrites signed tags by demoting them to annotated.
+
+* "git format-patch --no-binary" can produce a patch that lack binary
+  changes (i.e. cannot be used to propagate the whole changes) meant only
+  for reviewing.
+
+* "git init --bare" is a synonym for "git --bare init" now.
+
+* "git gc --auto" honors a new pre-auto-gc hook to temporarily disable it.
+
+* "git log --pretty=tformat:<custom format>" gives a LF after each entry,
+  instead of giving a LF between each pair of entries which is how
+  "git log --pretty=format:<custom format>" works.
+
+* "git log" and friends learned the "--graph" option to show the ancestry
+  graph at the left margin of the output.
+
+* "git log" and friends can be told to use date format that is different
+  from the default via 'log.date' configuration variable.
+
+* "git send-email" now can send out messages outside a git repository.
+
+* "git send-email --compose" was made aware of rfc2047 quoting.
+
+* "git status" can optionally include output from "git submodule
+  summary".
+
+* "git svn" learned --add-author-from option to propagate the authorship
+  by munging the commit log message.
+
+* new object creation and looking up in "git svn" has been optimized.
+
+* "gitweb" can read from a system-wide configuration file.
+
+(internal)
+
+* "git unpack-objects" and "git receive-pack" is now more strict about
+  detecting breakage in the objects they receive over the wire.
+
+
+Fixes since v1.5.5
+------------------
+
+All of the fixes in v1.5.5 maintenance series are included in
+this release, unless otherwise noted.
+
+And there are too numerous small fixes to otherwise note here ;-)
diff --git a/Documentation/RelNotes/1.6.0.1.txt b/Documentation/RelNotes/1.6.0.1.txt
new file mode 100644
index 0000000000..49d7a1cafa
--- /dev/null
+++ b/Documentation/RelNotes/1.6.0.1.txt
@@ -0,0 +1,36 @@
+GIT v1.6.0.1 Release Notes
+==========================
+
+Fixes since v1.6.0
+------------------
+
+* "git diff --cc" did not honor content mangling specified by
+  gitattributes and core.autocrlf when reading from the work tree.
+
+* "git diff --check" incorrectly detected new trailing blank lines when
+  whitespace check was in effect.
+
+* "git for-each-ref" tried to dereference NULL when asked for '%(body)" on
+  a tag with a single incomplete line as its payload.
+
+* "git format-patch" peeked before the beginning of a string when
+  "format.headers" variable is empty (a misconfiguration).
+
+* "git help help" did not work correctly.
+
+* "git mailinfo" (hence "git am") was unhappy when MIME multipart message
+  contained garbage after the finishing boundary.
+
+* "git mailinfo" also was unhappy when the "From: " line only had a bare
+  e-mail address.
+
+* "git merge" did not refresh the index correctly when a merge resulted in
+  a fast-forward.
+
+* "git merge" did not resolve a truly trivial merges that can be done
+  without content level merges.
+
+* "git svn dcommit" to a repository with URL that has embedded usernames
+  did not work correctly.
+
+Contains other various documentation fixes.
diff --git a/Documentation/RelNotes/1.6.0.2.txt b/Documentation/RelNotes/1.6.0.2.txt
new file mode 100644
index 0000000000..7d8fb85e1b
--- /dev/null
+++ b/Documentation/RelNotes/1.6.0.2.txt
@@ -0,0 +1,81 @@
+GIT v1.6.0.2 Release Notes
+==========================
+
+Fixes since v1.6.0.1
+--------------------
+
+* Installation on platforms that needs .exe suffix to git-* programs were
+  broken in 1.6.0.1.
+
+* Installation on filesystems without symbolic links support did not
+  work well.
+
+* In-tree documentations and test scripts now use "git foo" form to set a
+  better example, instead of the "git-foo" form (which is an acceptable
+  form if you have "PATH=$(git --exec-path):$PATH" in your script)
+
+* Many commands did not use the correct working tree location when used
+  with GIT_WORK_TREE environment settings.
+
+* Some systems need to use compatibility fnmatch and regex libraries
+  independent from each other; the compat/ area has been reorganized to
+  allow this.
+
+
+* "git apply --unidiff-zero" incorrectly applied a -U0 patch that inserts
+  a new line before the second line.
+
+* "git blame -c" did not exactly work like "git annotate" when range
+  boundaries are involved.
+
+* "git checkout file" when file is still unmerged checked out contents from
+  a random high order stage, which was confusing.
+
+* "git clone $there $here/" with extra trailing slashes after explicit
+  local directory name $here did not work as expected.
+
+* "git diff" on tracked contents with CRLF line endings did not drive "less"
+  intelligently when showing added or removed lines.
+
+* "git diff --dirstat -M" did not add changes in subdirectories up
+  correctly for renamed paths.
+
+* "git diff --cumulative" did not imply "--dirstat".
+
+* "git for-each-ref refs/heads/" did not work as expected.
+
+* "git gui" allowed users to feed patch without any context to be applied.
+
+* "git gui" botched parsing "diff" output when a line that begins with two
+  dashes and a space gets removed or a line that begins with two pluses
+  and a space gets added.
+
+* "git gui" translation updates and i18n fixes.
+
+* "git index-pack" is more careful against disk corruption while completing
+  a thin pack.
+
+* "git log -i --grep=pattern" did not ignore case; neither "git log -E
+  --grep=pattern" triggered extended regexp.
+
+* "git log --pretty="%ad" --date=short" did not use short format when
+  showing the timestamp.
+
+* "git log --author=author" match incorrectly matched with the
+  timestamp part of "author " line in commit objects.
+
+* "git log -F --author=author" did not work at all.
+
+* Build procedure for "git shell" that used stub versions of some
+  functions and globals was not understood by linkers on some platforms.
+
+* "git stash" was fooled by a stat-dirty but otherwise unmodified paths
+  and refused to work until the user refreshed the index.
+
+* "git svn" was broken on Perl before 5.8 with recent fixes to reduce
+  use of temporary files.
+
+* "git verify-pack -v" did not work correctly when given more than one
+  packfile.
+
+Also contains many documentation updates.
diff --git a/Documentation/RelNotes/1.6.0.3.txt b/Documentation/RelNotes/1.6.0.3.txt
new file mode 100644
index 0000000000..ad36c0f0b7
--- /dev/null
+++ b/Documentation/RelNotes/1.6.0.3.txt
@@ -0,0 +1,117 @@
+GIT v1.6.0.3 Release Notes
+==========================
+
+Fixes since v1.6.0.2
+--------------------
+
+* "git archive --format=zip" did not honor core.autocrlf while
+  --format=tar did.
+
+* Continuing "git rebase -i" was very confused when the user left modified
+  files in the working tree while resolving conflicts.
+
+* Continuing "git rebase -i" was also very confused when the user left
+  some staged changes in the index after "edit".
+
+* "git rebase -i" now honors the pre-rebase hook, just like the
+  other rebase implementations "git rebase" and "git rebase -m".
+
+* "git rebase -i" incorrectly aborted when there is no commit to replay.
+
+* Behaviour of "git diff --quiet" was inconsistent with "diff --exit-code"
+  with the output redirected to /dev/null.
+
+* "git diff --no-index" on binary files no longer outputs a bogus
+  "diff --git" header line.
+
+* "git diff" hunk header patterns with multiple elements separated by LF
+  were not used correctly.
+
+* Hunk headers in "git diff" default to using extended regular
+  expressions, fixing some of the internal patterns on non-GNU
+  platforms.
+
+* New config "diff.*.xfuncname" exposes extended regular expressions
+  for user specified hunk header patterns.
+
+* "git gc" when ejecting otherwise unreachable objects from packfiles into
+  loose form leaked memory.
+
+* "git index-pack" was recently broken and mishandled objects added by
+  thin-pack completion processing under memory pressure.
+
+* "git index-pack" was recently broken and misbehaved when run from inside
+  .git/objects/pack/ directory.
+
+* "git stash apply sash@{1}" was fixed to error out.  Prior versions
+  would have applied stash@{0} incorrectly.
+
+* "git stash apply" now offers a better suggestion on how to continue
+  if the working tree is currently dirty.
+
+* "git for-each-ref --format=%(subject)" fixed for commits with no
+  newline in the message body.
+
+* "git remote" fixed to protect printf from user input.
+
+* "git remote show -v" now displays all URLs of a remote.
+
+* "git checkout -b branch" was confused when branch already existed.
+
+* "git checkout -q" once again suppresses the locally modified file list.
+
+* "git clone -q", "git fetch -q" asks remote side to not send
+  progress messages, actually making their output quiet.
+
+* Cross-directory renames are no longer used when creating packs.  This
+  allows more graceful behavior on filesystems like sshfs.
+
+* Stale temporary files under $GIT_DIR/objects/pack are now cleaned up
+  automatically by "git prune".
+
+* "git merge" once again removes directories after the last file has
+  been removed from it during the merge.
+
+* "git merge" did not allocate enough memory for the structure itself when
+  enumerating the parents of the resulting commit.
+
+* "git blame -C -C" no longer segfaults while trying to pass blame if
+   it encounters a submodule reference.
+
+* "git rm" incorrectly claimed that you have local modifications when a
+  path was merely stat-dirty.
+
+* "git svn" fixed to display an error message when 'set-tree' failed,
+   instead of a Perl compile error.
+
+* "git submodule" fixed to handle checking out a different commit
+  than HEAD after initializing the submodule.
+
+* The "git commit" error message when there are still unmerged
+  files present was clarified to match "git write-tree".
+
+* "git init" was confused when core.bare or core.sharedRepository are set
+  in system or user global configuration file by mistake.  When --bare or
+  --shared is given from the command line, these now override such
+  settings made outside the repositories.
+
+* Some segfaults due to uncaught NULL pointers were fixed in multiple
+  tools such as apply, reset, update-index.
+
+* Solaris builds now default to OLD_ICONV=1 to avoid compile warnings;
+  Solaris 8 does not define NEEDS_LIBICONV by default.
+
+* "Git.pm" tests relied on unnecessarily more recent version of Perl.
+
+* "gitweb" triggered undef warning on commits without log messages.
+
+* "gitweb" triggered undef warnings on missing trees.
+
+* "gitweb" now removes PATH_INFO from its URLs so users don't have
+  to manually set the URL in the gitweb configuration.
+
+* Bash completion removed support for legacy "git-fetch", "git-push"
+  and "git-pull" as these are no longer installed.  Dashless form
+  ("git fetch") is still however supported.
+
+Many other documentation updates.
diff --git a/Documentation/RelNotes/1.6.0.4.txt b/Documentation/RelNotes/1.6.0.4.txt
new file mode 100644
index 0000000000..d522661d31
--- /dev/null
+++ b/Documentation/RelNotes/1.6.0.4.txt
@@ -0,0 +1,39 @@
+GIT v1.6.0.4 Release Notes
+==========================
+
+Fixes since v1.6.0.3
+--------------------
+
+* 'git add -p' said "No changes" when only binary files were changed.
+
+* 'git archive' did not work correctly in bare repositories.
+
+* 'git checkout -t -b newbranch' when you are on detached HEAD was broken.
+
+* when we refuse to detect renames because there are too many new or
+  deleted files, 'git diff' did not say how many there are.
+
+* 'git push --mirror' tried and failed to push the stash; there is no
+  point in sending it to begin with.
+
+* 'git push' did not update the remote tracking reference if the corresponding
+  ref on the remote end happened to be already up to date.
+
+* 'git pull $there $branch:$current_branch' did not work when you were on
+  a branch yet to be born.
+
+* when giving up resolving a conflicted merge, 'git reset --hard' failed
+  to remove new paths from the working tree.
+
+* 'git send-email' had a small fd leak while scanning directory.
+
+* 'git status' incorrectly reported a submodule directory as an untracked
+  directory.
+
+* 'git svn' used deprecated 'git-foo' form of subcommand invocation.
+
+* 'git update-ref -d' to remove a reference did not honor --no-deref option.
+
+* Plugged small memleaks here and there.
+
+* Also contains many documentation updates.
diff --git a/Documentation/RelNotes/1.6.0.5.txt b/Documentation/RelNotes/1.6.0.5.txt
new file mode 100644
index 0000000000..a08bb96738
--- /dev/null
+++ b/Documentation/RelNotes/1.6.0.5.txt
@@ -0,0 +1,56 @@
+GIT v1.6.0.5 Release Notes
+==========================
+
+Fixes since v1.6.0.4
+--------------------
+
+* "git checkout" used to crash when your HEAD was pointing at a deleted
+  branch.
+
+* "git checkout" from an un-checked-out state did not allow switching out
+  of the current branch.
+
+* "git diff" always allowed GIT_EXTERNAL_DIFF and --no-ext-diff was no-op for
+  the command.
+
+* Giving 3 or more tree-ish to "git diff" is supposed to show the combined
+  diff from second and subsequent trees to the first one, but the order was
+  screwed up.
+
+* "git fast-export" did not export all tags.
+
+* "git ls-files --with-tree=<tree>" did not work with options other
+  than -c, most notably with -m.
+
+* "git pack-objects" did not make its best effort to honor --max-pack-size
+  option when a single first object already busted the given limit and
+  placed many objects in a single pack.
+
+* "git-p4" fast import frontend was too eager to trigger its keyword expansion
+  logic, even on a keyword-looking string that does not have closing '$' on the
+  same line.
+
+* "git push $there" when the remote $there is defined in $GIT_DIR/branches/$there
+  behaves more like what cg-push from Cogito used to work.
+
+* when giving up resolving a conflicted merge, "git reset --hard" failed
+  to remove new paths from the working tree.
+
+* "git tag" did not complain when given mutually incompatible set of options.
+
+* The message constructed in the internal editor was discarded when "git
+  tag -s" failed to sign the message, which was often caused by the user
+  not configuring GPG correctly.
+
+* "make check" cannot be run without sparse; people may have meant to say
+  "make test" instead, so suggest that.
+
+* Internal diff machinery had a corner case performance bug that choked on
+  a large file with many repeated contents.
+
+* "git repack" used to grab objects out of packs marked with .keep
+  into a new pack.
+
+* Many unsafe call to sprintf() style varargs functions are corrected.
+
+* Also contains quite a few documentation updates.
diff --git a/Documentation/RelNotes/1.6.0.6.txt b/Documentation/RelNotes/1.6.0.6.txt
new file mode 100644
index 0000000000..64ece1ffd5
--- /dev/null
+++ b/Documentation/RelNotes/1.6.0.6.txt
@@ -0,0 +1,33 @@
+GIT v1.6.0.6 Release Notes
+==========================
+
+Fixes since 1.6.0.5
+-------------------
+
+ * "git fsck" had a deep recursion that wasted stack space.
+
+ * "git fast-export" and "git fast-import" choked on an old style
+   annotated tag that lack the tagger information.
+
+ * "git mergetool -- file" did not correctly skip "--" marker that
+   signals the end of options list.
+
+ * "git show $tag" segfaulted when an annotated $tag pointed at a
+   nonexistent object.
+
+ * "git show 2>error" when the standard output is automatically redirected
+   to the pager redirected the standard error to the pager as well; there
+   was no need to.
+
+ * "git send-email" did not correctly handle list of addresses when
+   they had quoted comma (e.g. "Lastname, Givenname" <mail@xxxxxxxx>).
+
+ * Logic to discover branch ancestry in "git svn" was unreliable when
+   the process to fetch history was interrupted.
+
+ * Removed support for an obsolete gitweb request URI, whose
+   implementation ran "git diff" Porcelain, instead of using plumbing,
+   which would have run an external diff command specified in the
+   repository configuration as the gitweb user.
+
+Also contains numerous documentation typofixes.
diff --git a/Documentation/RelNotes/1.6.0.txt b/Documentation/RelNotes/1.6.0.txt
new file mode 100644
index 0000000000..de7ef166b6
--- /dev/null
+++ b/Documentation/RelNotes/1.6.0.txt
@@ -0,0 +1,258 @@
+GIT v1.6.0 Release Notes
+========================
+
+User visible changes
+--------------------
+
+With the default Makefile settings, most of the programs are now
+installed outside your $PATH, except for "git", "gitk" and
+some server side programs that need to be accessible for technical
+reasons.  Invoking a git subcommand as "git-xyzzy" from the command
+line has been deprecated since early 2006 (and officially announced in
+1.5.4 release notes); use of them from your scripts after adding
+output from "git --exec-path" to the $PATH is still supported in this
+release, but users are again strongly encouraged to adjust their
+scripts to use "git xyzzy" form, as we will stop installing
+"git-xyzzy" hardlinks for built-in commands in later releases.
+
+An earlier change to page "git status" output was overwhelmingly unpopular
+and has been reverted.
+
+Source changes needed for porting to MinGW environment are now all in the
+main git.git codebase.
+
+By default, packfiles created with this version uses delta-base-offset
+encoding introduced in v1.4.4.  Pack idx files are using version 2 that
+allows larger packs and added robustness thanks to its CRC checking,
+introduced in v1.5.2 and v1.4.4.5.  If you want to keep your repositories
+backwards compatible past these versions, set repack.useDeltaBaseOffset
+to false or pack.indexVersion to 1, respectively.
+
+We used to prevent sample hook scripts shipped in templates/ from
+triggering by default by relying on the fact that we install them as
+unexecutable, but on some filesystems, this approach does not work.
+They are now shipped with ".sample" suffix.  If you want to activate
+any of these samples as-is, rename them to drop the ".sample" suffix,
+instead of running "chmod +x" on them.  For example, you can rename
+hooks/post-update.sample to hooks/post-update to enable the sample
+hook that runs update-server-info, in order to make repositories
+friendly to dumb protocols (i.e. HTTP).
+
+GIT_CONFIG, which was only documented as affecting "git config", but
+actually affected all git commands, now only affects "git config".
+GIT_LOCAL_CONFIG, also only documented as affecting "git config" and
+not different from GIT_CONFIG in a useful way, is removed.
+
+The ".dotest" temporary area "git am" and "git rebase" use is now moved
+inside the $GIT_DIR, to avoid mistakes of adding it to the project by
+accident.
+
+An ancient merge strategy "stupid" has been removed.
+
+
+Updates since v1.5.6
+--------------------
+
+(subsystems)
+
+* git-p4 in contrib learned "allowSubmit" configuration to control on
+  which branch to allow "submit" subcommand.
+
+* git-gui learned to stage changes per-line.
+
+(portability)
+
+* Changes for MinGW port have been merged, thanks to Johannes Sixt and
+  gangs.
+
+* Sample hook scripts shipped in templates/ are now suffixed with
+  *.sample.
+
+* perl's in-place edit (-i) does not work well without backup files on Windows;
+  some tests are rewritten to cope with this.
+
+(documentation)
+
+* Updated howto/update-hook-example
+
+* Got rid of usage of "git-foo" from the tutorial and made typography
+  more consistent.
+
+* Disambiguating "--" between revs and paths is finally documented.
+
+(performance, robustness, sanity etc.)
+
+* index-pack used too much memory when dealing with a deep delta chain.
+  This has been optimized.
+
+* reduced excessive inlining to shrink size of the "git" binary.
+
+* verify-pack checks the object CRC when using version 2 idx files.
+
+* When an object is corrupt in a pack, the object became unusable even
+  when the same object is available in a loose form,  We now try harder to
+  fall back to these redundant objects when able.  In particular, "git
+  repack -a -f" can be used to fix such a corruption as long as necessary
+  objects are available.
+
+* Performance of "git-blame -C -C" operation is vastly improved.
+
+* git-clone does not create refs in loose form anymore (it behaves as
+  if you immediately ran git-pack-refs after cloning).  This will help
+  repositories with insanely large number of refs.
+
+* core.fsyncobjectfiles configuration can be used to ensure that the loose
+  objects created will be fsync'ed (this is only useful on filesystems
+  that does not order data writes properly).
+
+* "git commit-tree" plumbing can make Octopus with more than 16 parents.
+  "git commit" has been capable of this for quite some time.
+
+(usability, bells and whistles)
+
+* even more documentation pages are now accessible via "man" and "git help".
+
+* A new environment variable GIT_CEILING_DIRECTORIES can be used to stop
+  the discovery process of the toplevel of working tree; this may be useful
+  when you are working in a slow network disk and are outside any working tree,
+  as bash-completion and "git help" may still need to run in these places.
+
+* By default, stash entries never expire.  Set reflogexpire in [gc
+  "refs/stash"] to a reasonable value to get traditional auto-expiration
+  behaviour back
+
+* Longstanding latency issue with bash completion script has been
+  addressed.  This will need to be backmerged to 'maint' later.
+
+* pager.<cmd> configuration variable can be used to enable/disable the
+  default paging behaviour per command.
+
+* "git-add -i" has a new action 'e/dit' to allow you edit the patch hunk
+  manually.
+
+* git-am records the original tip of the branch in ORIG_HEAD before it
+  starts applying patches.
+
+* git-apply can handle a patch that touches the same path more than once
+  much better than before.
+
+* git-apply can be told not to trust the line counts recorded in the input
+  patch but recount, with the new --recount option.
+
+* git-apply can be told to apply a patch to a path deeper than what the
+  patch records with --directory option.
+
+* git-archive can be told to omit certain paths from its output using
+  export-ignore attributes.
+
+* git-archive uses the zlib default compression level when creating
+  zip archive.
+
+* git-archive's command line options --exec and --remote can take their
+  parameters as separate command line arguments, similar to other commands.
+  IOW, both "--exec=path" and "--exec path" are now supported.
+
+* With -v option, git-branch describes the remote tracking statistics
+  similar to the way git-checkout reports by how many commits your branch
+  is ahead/behind.
+
+* git-branch's --contains option used to always require a commit parameter
+  to limit the branches with; it now defaults to list branches that
+  contains HEAD if this parameter is omitted.
+
+* git-branch's --merged and --no-merged option used to always limit the
+  branches relative to the HEAD, but they can now take an optional commit
+  argument that is used in place of HEAD.
+
+* git-bundle can read the revision arguments from the standard input.
+
+* git-cherry-pick can replay a root commit now.
+
+* git-clone can clone from a remote whose URL would be rewritten by
+  configuration stored in $HOME/.gitconfig now.
+
+* "git-clone --mirror" is a handy way to set up a bare mirror repository.
+
+* git-cvsserver learned to respond to "cvs co -c".
+
+* git-diff --check now checks leftover merge conflict markers.
+
+* "git-diff -p" learned to grab a better hunk header lines in
+  BibTex, Pascal/Delphi, and Ruby files and also pays attention to
+  chapter and part boundary in TeX documents.
+
+* When remote side used to have branch 'foo' and git-fetch finds that now
+  it has branch 'foo/bar', it refuses to lose the existing remote tracking
+  branch and its reflog.  The error message has been improved to suggest
+  pruning the remote if the user wants to proceed and get the latest set
+  of branches from the remote, including such 'foo/bar'.
+
+* fast-export learned to export and import marks file; this can be used to
+  interface with fast-import incrementally.
+
+* fast-import and fast-export learned to export and import gitlinks.
+
+* "gitk" left background process behind after being asked to dig very deep
+  history and the user killed the UI; the process is killed when the UI goes
+  away now.
+
+* git-rebase records the original tip of branch in ORIG_HEAD before it is
+  rewound.
+
+* "git rerere" can be told to update the index with auto-reused resolution
+  with rerere.autoupdate configuration variable.
+
+* git-rev-parse learned $commit^! and $commit^@ notations used in "log"
+  family.  These notations are available in gitk as well, because the gitk
+  command internally uses rev-parse to interpret its arguments.
+
+* git-rev-list learned --children option to show child commits it
+  encountered during the traversal, instead of showing parent commits.
+
+* git-send-mail can talk not just over SSL but over TLS now.
+
+* git-shortlog honors custom output format specified with "--pretty=format:".
+
+* "git-stash save" learned --keep-index option.  This lets you stash away the
+  local changes and bring the changes staged in the index to your working
+  tree for examination and testing.
+
+* git-stash also learned branch subcommand to create a new branch out of
+  stashed changes.
+
+* git-status gives the remote tracking statistics similar to the way
+  git-checkout reports by how many commits your branch is ahead/behind.
+
+* "git-svn dcommit" is now aware of auto-props setting the subversion user
+  has.
+
+* You can tell "git status -u" to even more aggressively omit checking
+  untracked files with --untracked-files=no.
+
+* Original SHA-1 value for "update-ref -d" is optional now.
+
+* Error codes from gitweb are made more descriptive where possible, rather
+  than "403 forbidden" as we used to issue everywhere.
+
+(internal)
+
+* git-merge has been reimplemented in C.
+
+
+Fixes since v1.5.6
+------------------
+
+All of the fixes in v1.5.6 maintenance series are included in
+this release, unless otherwise noted.
+
+ * git-clone ignored its -u option; the fix needs to be backported to
+   'maint';
+
+ * git-mv used to lose the distinction between changes that are staged
+   and that are only in the working tree, by staging both in the index
+   after moving such a path.
+
+ * "git-rebase -i -p" rewrote the parents to wrong ones when amending
+   (either edit or squash) was involved, and did not work correctly
+   when fast forwarding.
+
diff --git a/Documentation/RelNotes/1.6.1.1.txt b/Documentation/RelNotes/1.6.1.1.txt
new file mode 100644
index 0000000000..8c594ba02f
--- /dev/null
+++ b/Documentation/RelNotes/1.6.1.1.txt
@@ -0,0 +1,59 @@
+GIT v1.6.1.1 Release Notes
+==========================
+
+Fixes since v1.6.1
+------------------
+
+* "git add frotz/nitfol" when "frotz" is a submodule should have errored
+  out, but it didn't.
+
+* "git apply" took file modes from the patch text and updated the mode
+  bits of the target tree even when the patch was not about mode changes.
+
+* "git bisect view" on Cygwin did not launch gitk
+
+* "git checkout $tree" did not trigger an error.
+
+* "git commit" tried to remove COMMIT_EDITMSG from the work tree by mistake.
+
+* "git describe --all" complained when a commit is described with a tag,
+  which was nonsense.
+
+* "git diff --no-index --" did not trigger no-index (aka "use git-diff as
+  a replacement of diff on untracked files") behaviour.
+
+* "git format-patch -1 HEAD" on a root commit failed to produce patch
+  text.
+
+* "git fsck branch" did not work as advertised; instead it behaved the same
+  way as "git fsck".
+
+* "git log --pretty=format:%s" did not handle a multi-line subject the
+  same way as built-in log listers (i.e. shortlog, --pretty=oneline, etc.)
+
+* "git daemon", and "git merge-file" are more careful when freopen fails
+  and barf, instead of going on and writing to unopened filehandle.
+
+* "git http-push" did not like some RFC 4918 compliant DAV server
+  responses.
+
+* "git merge -s recursive" mistakenly overwritten an untracked file in the
+  work tree upon delete/modify conflict.
+
+* "git merge -s recursive" didn't leave the index unmerged for entries with
+  rename/delete conflicts.
+
+* "git merge -s recursive" clobbered untracked files in the work tree.
+
+* "git mv -k" with more than one erroneous paths misbehaved.
+
+* "git read-tree -m -u" hence branch switching incorrectly lost a
+  subdirectory in rare cases.
+
+* "git rebase -i" issued an unnecessary error message upon a user error of
+  marking the first commit to be "squash"ed.
+
+* "git shortlog" did not format a commit message with multi-line
+  subject correctly.
+
+Many documentation updates.
diff --git a/Documentation/RelNotes/1.6.1.2.txt b/Documentation/RelNotes/1.6.1.2.txt
new file mode 100644
index 0000000000..be37cbb858
--- /dev/null
+++ b/Documentation/RelNotes/1.6.1.2.txt
@@ -0,0 +1,39 @@
+GIT v1.6.1.2 Release Notes
+==========================
+
+Fixes since v1.6.1.1
+--------------------
+
+* The logic for rename detection in internal diff used by commands like
+  "git diff" and "git blame" has been optimized to avoid loading the same
+  blob repeatedly.
+
+* We did not allow writing out a blob that is larger than 2GB for no good
+  reason.
+
+* "git format-patch -o $dir", when $dir is a relative directory, used it
+  as relative to the root of the work tree, not relative to the current
+  directory.
+
+* v1.6.1 introduced an optimization for "git push" into a repository (A)
+  that borrows its objects from another repository (B) to avoid sending
+  objects that are available in repository B, when they are not yet used
+  by repository A.  However the code on the "git push" sender side was
+  buggy and did not work when repository B had new objects that are not
+  known by the sender.  This caused pushing into a "forked" repository
+  served by v1.6.1 software using "git push" from v1.6.1 sometimes did not
+  work.  The bug was purely on the "git push" sender side, and has been
+  corrected.
+
+* "git status -v" did not paint its diff output in colour even when
+  color.ui configuration was set.
+
+* "git ls-tree" learned --full-tree option to help Porcelain scripts that
+  want to always see the full path regardless of the current working
+  directory.
+
+* "git grep" incorrectly searched in work tree paths even when they are
+  marked as assume-unchanged.  It now searches in the index entries.
+
+* "git gc" with no grace period needlessly ejected packed but unreachable
+  objects in their loose form, only to delete them right away.
diff --git a/Documentation/RelNotes/1.6.1.3.txt b/Documentation/RelNotes/1.6.1.3.txt
new file mode 100644
index 0000000000..cd08d8174e
--- /dev/null
+++ b/Documentation/RelNotes/1.6.1.3.txt
@@ -0,0 +1,28 @@
+GIT v1.6.1.3 Release Notes
+==========================
+
+Fixes since v1.6.1.2
+--------------------
+
+* "git diff --binary | git apply" pipeline did not work well when
+  a binary blob is changed to a symbolic link.
+
+* Some combinations of -b/-w/--ignore-space-at-eol to "git diff" did
+  not work as expected.
+
+* "git grep" did not pass the -I (ignore binary) option when
+  calling out an external grep program.
+
+* "git log" and friends include HEAD to the set of starting points
+  when --all is given.  This makes a difference when you are not
+  on any branch.
+
+* "git mv" to move an untracked file to overwrite a tracked
+  contents misbehaved.
+
+* "git merge -s octopus" with many potential merge bases did not
+  work correctly.
+
+* RPM binary package installed the html manpages in a wrong place.
+
+Also includes minor documentation fixes and updates.
diff --git a/Documentation/RelNotes/1.6.1.4.txt b/Documentation/RelNotes/1.6.1.4.txt
new file mode 100644
index 0000000000..ccbad794c0
--- /dev/null
+++ b/Documentation/RelNotes/1.6.1.4.txt
@@ -0,0 +1,41 @@
+GIT v1.6.1.4 Release Notes
+==========================
+
+Fixes since v1.6.1.3
+--------------------
+
+* .gitignore learned to handle backslash as a quoting mechanism for
+  comment introduction character "#".
+  This fix was first merged to 1.6.2.1.
+
+* "git fast-export" produced wrong output with some parents missing from
+  commits, when the history is clock-skewed.
+
+* "git fast-import" sometimes failed to read back objects it just wrote
+  out and aborted, because it failed to flush stale cached data.
+
+* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when
+  deciding to descend into a subdirectory but they did not match the
+  individual paths correctly.  This caused pathspecs "abc/d ab" to match
+  "abc/0" ("abc/d" made them decide to descend into the directory "abc/",
+  and then "ab" incorrectly matched "abc/0" when it shouldn't).
+  This fix was first merged to 1.6.2.3.
+
+* import-zips script (in contrib) did not compute the common directory
+  prefix correctly.
+  This fix was first merged to 1.6.2.2.
+
+* "git init" segfaulted when given an overlong template location via
+  the --template= option.
+  This fix was first merged to 1.6.2.4.
+
+* "git repack" did not error out when necessary object was missing in the
+  repository.
+
+* git-repack (invoked from git-gc) did not work as nicely as it should in
+  a repository that borrows objects from neighbours via alternates
+  mechanism especially when some packs are marked with the ".keep" flag
+  to prevent them from being repacked.
+  This fix was first merged to 1.6.2.3.
+
+Also includes minor documentation fixes and updates.
diff --git a/Documentation/RelNotes/1.6.1.txt b/Documentation/RelNotes/1.6.1.txt
new file mode 100644
index 0000000000..7b152a6fdc
--- /dev/null
+++ b/Documentation/RelNotes/1.6.1.txt
@@ -0,0 +1,280 @@
+GIT v1.6.1 Release Notes
+========================
+
+Updates since v1.6.0
+--------------------
+
+When some commands (e.g. "git log", "git diff") spawn pager internally, we
+used to make the pager the parent process of the git command that produces
+output.  This meant that the exit status of the whole thing comes from the
+pager, not the underlying git command.  We swapped the order of the
+processes around and you will see the exit code from the command from now
+on.
+
+(subsystems)
+
+* gitk can call out to git-gui to view "git blame" output; git-gui in turn
+  can run gitk from its blame view.
+
+* Various git-gui updates including updated translations.
+
+* Various gitweb updates from repo.or.cz installation.
+
+* Updates to emacs bindings.
+
+(portability)
+
+* A few test scripts used nonportable "grep" that did not work well on
+  some platforms, e.g. Solaris.
+
+* Sample pre-auto-gc script has OS X support.
+
+* Makefile has support for (ancient) FreeBSD 4.9.
+
+(performance)
+
+* Many operations that are lstat(3) heavy can be told to pre-execute
+  necessary lstat(3) in parallel before their main operations, which
+  potentially gives much improved performance for cold-cache cases or in
+  environments with weak metadata caching (e.g. NFS).
+
+* The underlying diff machinery to produce textual output has been
+  optimized, which would result in faster "git blame" processing.
+
+* Most of the test scripts (but not the ones that try to run servers)
+  can be run in parallel.
+
+* Bash completion of refnames in a repository with massive number of
+  refs has been optimized.
+
+* Cygwin port uses native stat/lstat implementations when applicable,
+  which leads to improved performance.
+
+* "git push" pays attention to alternate repositories to avoid sending
+  unnecessary objects.
+
+* "git svn" can rebuild an out-of-date rev_map file.
+
+(usability, bells and whistles)
+
+* When you mistype a command name, git helpfully suggests what it guesses
+  you might have meant to say.  help.autocorrect configuration can be set
+  to a non-zero value to accept the suggestion when git can uniquely
+  guess.
+
+* The packfile machinery hopefully is more robust when dealing with
+  corrupt packs if redundant objects involved in the corruption are
+  available elsewhere.
+
+* "git add -N path..." adds the named paths as an empty blob, so that
+  subsequent "git diff" will show a diff as if they are creation events.
+
+* "git add" gained a built-in synonym for people who want to say "stage
+  changes" instead of "add contents to the staging area" which amounts
+  to the same thing.
+
+* "git apply" learned --include=paths option, similar to the existing
+  --exclude=paths option.
+
+* "git bisect" is careful about a user mistake and suggests testing of
+  merge base first when good is not a strict ancestor of bad.
+
+* "git bisect skip" can take a range of commits.
+
+* "git blame" re-encodes the commit metainfo to UTF-8 from i18n.commitEncoding
+  by default.
+
+* "git check-attr --stdin" can check attributes for multiple paths.
+
+* "git checkout --track origin/hack" used to be a syntax error.  It now
+  DWIMs to create a corresponding local branch "hack", i.e. acts as if you
+  said "git checkout --track -b hack origin/hack".
+
+* "git checkout --ours/--theirs" can be used to check out one side of a
+  conflicting merge during conflict resolution.
+
+* "git checkout -m" can be used to recreate the initial conflicted state
+  during conflict resolution.
+
+* "git cherry-pick" can also utilize rerere for conflict resolution.
+
+* "git clone" learned to be verbose with -v
+
+* "git commit --author=$name" can look up author name from existing
+  commits.
+
+* output from "git commit" has been reworded in a more concise and yet
+  more informative way.
+
+* "git count-objects" reports the on-disk footprint for packfiles and
+  their corresponding idx files.
+
+* "git daemon" learned --max-connections=<count> option.
+
+* "git daemon" exports REMOTE_ADDR to record client address, so that
+  spawned programs can act differently on it.
+
+* "git describe --tags" favours closer lightweight tags than farther
+  annotated tags now.
+
+* "git diff" learned to mimic --suppress-blank-empty from GNU diff via a
+  configuration option.
+
+* "git diff" learned to put more sensible hunk headers for Python,
+  HTML and ObjC contents.
+
+* "git diff" learned to vary the a/ vs b/ prefix depending on what are
+  being compared, controlled by diff.mnemonicprefix configuration.
+
+* "git diff" learned --dirstat-by-file to count changed files, not number
+  of lines, when summarizing the global picture.
+
+* "git diff" learned "textconv" filters --- a binary or hard-to-read
+  contents can be munged into human readable form and the difference
+  between the results of the conversion can be viewed (obviously this
+  cannot produce a patch that can be applied, so this is disabled in
+  format-patch among other things).
+
+* "--cached" option to "git diff has an easier to remember synonym "--staged",
+  to ask "what is the difference between the given commit and the
+  contents staged in the index?"
+
+* "git for-each-ref" learned "refname:short" token that gives an
+  unambiguously abbreviated refname.
+
+* Auto-numbering of the subject lines is the default for "git
+  format-patch" now.
+
+* "git grep" learned to accept -z similar to GNU grep.
+
+* "git help" learned to use GIT_MAN_VIEWER environment variable before
+  using "man" program.
+
+* "git imap-send" can optionally talk SSL.
+
+* "git index-pack" is more careful against disk corruption while
+  completing a thin pack.
+
+* "git log --check" and "git log --exit-code" passes their underlying diff
+  status with their exit status code.
+
+* "git log" learned --simplify-merges, a milder variant of --full-history;
+  "gitk --simplify-merges" is easier to view than with --full-history.
+
+* "git log" learned "--source" to show what ref each commit was reached
+  from.
+
+* "git log" also learned "--simplify-by-decoration" to show the
+  birds-eye-view of the topology of the history.
+
+* "git log --pretty=format:" learned "%d" format element that inserts
+  names of tags that point at the commit.
+
+* "git merge --squash" and "git merge --no-ff" into an unborn branch are
+  noticed as user errors.
+
+* "git merge -s $strategy" can use a custom built strategy if you have a
+  command "git-merge-$strategy" on your $PATH.
+
+* "git pull" (and "git fetch") can be told to operate "-v"erbosely or
+  "-q"uietly.
+
+* "git push" can be told to reject deletion of refs with receive.denyDeletes
+  configuration.
+
+* "git rebase" honours pre-rebase hook; use --no-verify to bypass it.
+
+* "git rebase -p" uses interactive rebase machinery now to preserve the merges.
+
+* "git reflog expire branch" can be used in place of "git reflog expire
+  refs/heads/branch".
+
+* "git remote show $remote" lists remote branches one-per-line now.
+
+* "git send-email" can be given revision range instead of files and
+  maildirs on the command line, and automatically runs format-patch to
+  generate patches for the given revision range.
+
+* "git submodule foreach" subcommand allows you to iterate over checked
+  out submodules.
+
+* "git submodule sync" subcommands allows you to update the origin URL
+  recorded in submodule directories from the toplevel .gitmodules file.
+
+* "git svn branch" can create new branches on the other end.
+
+* "gitweb" can use more saner PATH_INFO based URL.
+
+(internal)
+
+* "git hash-object" learned to lie about the path being hashed, so that
+  correct gitattributes processing can be done while hashing contents
+  stored in a temporary file.
+
+* various callers of git-merge-recursive avoid forking it as an external
+  process.
+
+* Git class defined in "Git.pm" can be subclasses a bit more easily.
+
+* We used to link GNU regex library as a compatibility layer for some
+  platforms, but it turns out it is not necessary on most of them.
+
+* Some path handling routines used fixed number of buffers used alternately
+  but depending on the call depth, this arrangement led to hard to track
+  bugs.  This issue is being addressed.
+
+
+Fixes since v1.6.0
+------------------
+
+All of the fixes in v1.6.0.X maintenance series are included in this
+release, unless otherwise noted.
+
+* Porcelains implemented as shell scripts were utterly confused when you
+  entered to a subdirectory of a work tree from sideways, following a
+  symbolic link (this may need to be backported to older releases later).
+
+* Tracking symbolic links would work better on filesystems whose lstat()
+  returns incorrect st_size value for them.
+
+* "git add" and "git update-index" incorrectly allowed adding S/F when S
+  is a tracked symlink that points at a directory D that has a path F in
+  it (we still need to fix a similar nonsense when S is a submodule and F
+  is a path in it).
+
+* "git am" after stopping at a broken patch lost --whitespace, -C, -p and
+  --3way options given from the command line initially.
+
+* "git diff --stdin" used to take two trees on a line and compared them,
+  but we dropped support for such a use case long time ago.  This has
+  been resurrected.
+
+* "git filter-branch" failed to rewrite a tag name with slashes in it.
+
+* "git http-push" did not understand URI scheme other than opaquelocktoken
+  when acquiring a lock from the server (this may need to be backported to
+  older releases later).
+
+* After "git rebase -p" stopped with conflicts while replaying a merge,
+ "git rebase --continue" did not work (may need to be backported to older
+  releases).
+
+* "git revert" records relative to which parent a revert was made when
+  reverting a merge.  Together with new documentation that explains issues
+  around reverting a merge and merging from the updated branch later, this
+  hopefully will reduce user confusion (this may need to be backported to
+  older releases later).
+
+* "git rm --cached" used to allow an empty blob that was added earlier to
+  be removed without --force, even when the file in the work tree has
+  since been modified.
+
+* "git push --tags --all $there" failed with generic usage message without
+  telling saying these two options are incompatible.
+
+* "git log --author/--committer" match used to potentially match the
+  timestamp part, exposing internal implementation detail.  Also these did
+  not work with --fixed-strings match at all.
+
+* "gitweb" did not mark non-ASCII characters imported from external HTML fragments
+  correctly.
diff --git a/Documentation/RelNotes/1.6.2.1.txt b/Documentation/RelNotes/1.6.2.1.txt
new file mode 100644
index 0000000000..dfa36416af
--- /dev/null
+++ b/Documentation/RelNotes/1.6.2.1.txt
@@ -0,0 +1,19 @@
+GIT v1.6.2.1 Release Notes
+==========================
+
+Fixes since v1.6.2
+------------------
+
+* .gitignore learned to handle backslash as a quoting mechanism for
+  comment introduction character "#".
+
+* timestamp output in --date=relative mode used to display timestamps that
+  are long time ago in the default mode; it now uses "N years M months
+  ago", and "N years ago".
+
+* git-add -i/-p now works with non-ASCII pathnames.
+
+* "git hash-object -w" did not read from the configuration file from the
+  correct .git directory.
+
+* git-send-email learned to correctly handle multiple Cc: addresses.
diff --git a/Documentation/RelNotes/1.6.2.2.txt b/Documentation/RelNotes/1.6.2.2.txt
new file mode 100644
index 0000000000..fafa9986b0
--- /dev/null
+++ b/Documentation/RelNotes/1.6.2.2.txt
@@ -0,0 +1,45 @@
+GIT v1.6.2.2 Release Notes
+==========================
+
+Fixes since v1.6.2.1
+--------------------
+
+* A longstanding confusing description of what --pickaxe option of
+  git-diff does has been clarified in the documentation.
+
+* "git-blame -S" did not quite work near the commits that were given
+  on the command line correctly.
+
+* "git diff --pickaxe-regexp" did not count overlapping matches
+  correctly.
+
+* "git diff" did not feed files in work-tree representation to external
+  diff and textconv.
+
+* "git-fetch" in a repository that was not cloned from anywhere said
+  it cannot find 'origin', which was hard to understand for new people.
+
+* "git-format-patch --numbered-files --stdout" did not have to die of
+  incompatible options; it now simply ignores --numbered-files as no files
+  are produced anyway.
+
+* "git-ls-files --deleted" did not work well with GIT_DIR&GIT_WORK_TREE.
+
+* "git-read-tree A B C..." without -m option has been broken for a long
+  time.
+
+* git-send-email ignored --in-reply-to when --no-thread was given.
+
+* 'git-submodule add' did not tolerate extra slashes and ./ in the path it
+  accepted from the command line; it now is more lenient.
+
+* git-svn misbehaved when the project contained a path that began with
+  two dashes.
+
+* import-zips script (in contrib) did not compute the common directory
+  prefix correctly.
+
+* miscompilation of negated enum constants by old gcc (2.9) affected the
+  codepaths to spawn subprocesses.
+
+Many small documentation updates are included as well.
diff --git a/Documentation/RelNotes/1.6.2.3.txt b/Documentation/RelNotes/1.6.2.3.txt
new file mode 100644
index 0000000000..4d3c1ac91c
--- /dev/null
+++ b/Documentation/RelNotes/1.6.2.3.txt
@@ -0,0 +1,22 @@
+GIT v1.6.2.3 Release Notes
+==========================
+
+Fixes since v1.6.2.2
+--------------------
+
+* Setting an octal mode value to core.sharedrepository configuration to
+  restrict access to the repository to group members did not work as
+  advertised.
+
+* A fairly large and trivial memory leak while rev-list shows list of
+  reachable objects has been identified and plugged.
+
+* "git-commit --interactive" did not abort when underlying "git-add -i"
+  signaled a failure.
+
+* git-repack (invoked from git-gc) did not work as nicely as it should in
+  a repository that borrows objects from neighbours via alternates
+  mechanism especially when some packs are marked with the ".keep" flag
+  to prevent them from being repacked.
+
+Many small documentation updates are included as well.
diff --git a/Documentation/RelNotes/1.6.2.4.txt b/Documentation/RelNotes/1.6.2.4.txt
new file mode 100644
index 0000000000..f4bf1d0986
--- /dev/null
+++ b/Documentation/RelNotes/1.6.2.4.txt
@@ -0,0 +1,39 @@
+GIT v1.6.2.4 Release Notes
+==========================
+
+Fixes since v1.6.2.3
+--------------------
+
+* The configuration parser had a buffer overflow while parsing an overlong
+  value.
+
+* pruning reflog entries that are unreachable from the tip of the ref
+  during "git reflog prune" (hence "git gc") was very inefficient.
+
+* "git-add -p" lacked a way to say "q"uit to refuse staging any hunks for
+  the remaining paths.  You had to say "d" and then ^C.
+
+* "git-checkout <tree-ish> <submodule>" did not update the index entry at
+  the named path; it now does.
+
+* "git-fast-export" choked when seeing a tag that does not point at commit.
+
+* "git init" segfaulted when given an overlong template location via
+  the --template= option.
+
+* "git-ls-tree" and "git-diff-tree" used a pathspec correctly when
+  deciding to descend into a subdirectory but they did not match the
+  individual paths correctly.  This caused pathspecs "abc/d ab" to match
+  "abc/0" ("abc/d" made them decide to descend into the directory "abc/",
+  and then "ab" incorrectly matched "abc/0" when it shouldn't).
+
+* "git-merge-recursive" was broken when a submodule entry was involved in
+  a criss-cross merge situation.
+
+Many small documentation updates are included as well.
+
+---
+exec >/var/tmp/1
+echo O=$(git describe maint)
+O=v1.6.2.3-38-g318b847
+git shortlog --no-merges $O..maint
diff --git a/Documentation/RelNotes/1.6.2.5.txt b/Documentation/RelNotes/1.6.2.5.txt
new file mode 100644
index 0000000000..b23f9e95d1
--- /dev/null
+++ b/Documentation/RelNotes/1.6.2.5.txt
@@ -0,0 +1,21 @@
+GIT v1.6.2.5 Release Notes
+==========================
+
+Fixes since v1.6.2.4
+--------------------
+
+* "git apply" mishandled if you fed a git generated patch that renames
+  file A to B and file B to A at the same time.
+
+* "git diff -c -p" (and "diff --cc") did not expect to see submodule
+  differences and instead refused to work.
+
+* "git grep -e '('" segfaulted, instead of diagnosing a mismatched
+  parentheses error.
+
+* "git fetch" generated packs with offset-delta encoding when both ends of
+  the connection are capable of producing one; this cannot be read by
+  ancient git and the user should be able to disable this by setting
+  repack.usedeltabaseoffset configuration to false.
+
+
diff --git a/Documentation/RelNotes/1.6.2.txt b/Documentation/RelNotes/1.6.2.txt
new file mode 100644
index 0000000000..166d73c60f
--- /dev/null
+++ b/Documentation/RelNotes/1.6.2.txt
@@ -0,0 +1,164 @@
+GIT v1.6.2 Release Notes
+========================
+
+With the next major release, "git push" into a branch that is
+currently checked out will be refused by default.  You can choose
+what should happen upon such a push by setting the configuration
+variable receive.denyCurrentBranch in the receiving repository.
+
+To ease the transition plan, the receiving repository of such a
+push running this release will issue a big warning when the
+configuration variable is missing.  Please refer to:
+
+  https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
+  https://lore.kernel.org/git/7vbptlsuyv.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx/
+
+for more details on the reason why this change is needed and the
+transition plan.
+
+For a similar reason, "git push $there :$killed" to delete the branch
+$killed in a remote repository $there, if $killed branch is the current
+branch pointed at by its HEAD, gets a large warning.  You can choose what
+should happen upon such a push by setting the configuration variable
+receive.denyDeleteCurrent in the receiving repository.
+
+
+Updates since v1.6.1
+--------------------
+
+(subsystems)
+
+* git-svn updates.
+
+* gitweb updates, including a new patch view and RSS/Atom feed
+  improvements.
+
+* (contrib/emacs) git.el now has commands for checking out a branch,
+  creating a branch, cherry-picking and reverting commits; vc-git.el
+  is not shipped with git anymore (it is part of official Emacs).
+
+(performance)
+
+* pack-objects autodetects the number of CPUs available and uses threaded
+  version.
+
+(usability, bells and whistles)
+
+* automatic typo correction works on aliases as well
+
+* @{-1} is a way to refer to the last branch you were on.  This is
+  accepted not only where an object name is expected, but anywhere
+  a branch name is expected and acts as if you typed the branch name.
+  E.g. "git branch --track mybranch @{-1}", "git merge @{-1}", and
+  "git rev-parse --symbolic-full-name @{-1}" would work as expected.
+
+* When refs/remotes/origin/HEAD points at a remote tracking branch that
+  has been pruned away, many git operations issued warning when they
+  internally enumerated the refs.  We now warn only when you say "origin"
+  to refer to that pruned branch.
+
+* The location of .mailmap file can be configured, and its file format was
+  enhanced to allow mapping an incorrect e-mail field as well.
+
+* "git add -p" learned 'g'oto action to jump directly to a hunk.
+
+* "git add -p" learned to find a hunk with given text with '/'.
+
+* "git add -p" optionally can be told to work with just the command letter
+  without Enter.
+
+* when "git am" stops upon a patch that does not apply, it shows the
+  title of the offending patch.
+
+* "git am --directory=<dir>" and "git am --reject" passes these options
+  to underlying "git apply".
+
+* "git am" learned --ignore-date option.
+
+* "git blame" aligns author names better when they are spelled in
+  non US-ASCII encoding.
+
+* "git clone" now makes its best effort when cloning from an empty
+  repository to set up configuration variables to refer to the remote
+  repository.
+
+* "git checkout -" is a shorthand for "git checkout @{-1}".
+
+* "git cherry" defaults to whatever the current branch is tracking (if
+  exists) when the <upstream> argument is not given.
+
+* "git cvsserver" can be told not to add extra "via git-CVS emulator" to
+  the commit log message it serves via gitcvs.commitmsgannotation
+  configuration.
+
+* "git cvsserver" learned to handle 'noop' command some CVS clients seem
+  to expect to work.
+
+* "git diff" learned a new option --inter-hunk-context to coalesce close
+  hunks together and show context between them.
+
+* The definition of what constitutes a word for "git diff --color-words"
+  can be customized via gitattributes, command line or a configuration.
+
+* "git diff" learned --patience to run "patience diff" algorithm.
+
+* "git filter-branch" learned --prune-empty option that discards commits
+  that do not change the contents.
+
+* "git fsck" now checks loose objects in alternate object stores, instead
+  of misreporting them as missing.
+
+* "git gc --prune" was resurrected to allow "git gc --no-prune" and
+  giving non-default expiration period e.g. "git gc --prune=now".
+
+* "git grep -w" and "git grep" for fixed strings have been optimized.
+
+* "git mergetool" learned -y(--no-prompt) option to disable prompting.
+
+* "git rebase -i" can transplant a history down to root to elsewhere
+  with --root option.
+
+* "git reset --merge" is a new mode that works similar to the way
+  "git checkout" switches branches, taking the local changes while
+  switching to another commit.
+
+* "git submodule update" learned --no-fetch option.
+
+* "git tag" learned --contains that works the same way as the same option
+  from "git branch".
+
+
+Fixes since v1.6.1
+------------------
+
+All of the fixes in v1.6.1.X maintenance series are included in this
+release, unless otherwise noted.
+
+Here are fixes that this release has, but have not been backported to
+v1.6.1.X series.
+
+* "git-add sub/file" when sub is a submodule incorrectly added the path to
+  the superproject.
+
+* "git bundle" did not exclude annotated tags even when a range given
+  from the command line wanted to.
+
+* "git filter-branch" unnecessarily refused to work when you had
+  checked out a different commit from what is recorded in the superproject
+  index in a submodule.
+
+* "git filter-branch" incorrectly tried to update a nonexistent work tree
+  at the end when it is run in a bare repository.
+
+* "git gc" did not work if your repository was created with an ancient git
+  and never had any pack files in it before.
+
+* "git mergetool" used to ignore autocrlf and other attributes
+  based content rewriting.
+
+* branch switching and merges had a silly bug that did not validate
+  the correct directory when making sure an existing subdirectory is
+  clean.
+
+* "git -p cmd" when cmd is not a built-in one left the display in funny state
+  when killed in the middle.
diff --git a/Documentation/RelNotes/1.6.3.1.txt b/Documentation/RelNotes/1.6.3.1.txt
new file mode 100644
index 0000000000..2400b72ef7
--- /dev/null
+++ b/Documentation/RelNotes/1.6.3.1.txt
@@ -0,0 +1,10 @@
+GIT v1.6.3.1 Release Notes
+==========================
+
+Fixes since v1.6.3
+------------------
+
+* "git checkout -b new-branch" with a staged change in the index
+  incorrectly primed the in-index cache-tree, resulting a wrong tree
+  object to be written out of the index.  This is a grave regression
+  since the last 1.6.2.X maintenance release.
diff --git a/Documentation/RelNotes/1.6.3.2.txt b/Documentation/RelNotes/1.6.3.2.txt
new file mode 100644
index 0000000000..b2f3f0293c
--- /dev/null
+++ b/Documentation/RelNotes/1.6.3.2.txt
@@ -0,0 +1,61 @@
+GIT v1.6.3.2 Release Notes
+==========================
+
+Fixes since v1.6.3.1
+--------------------
+
+ * A few codepaths picked up the first few bytes from an sha1[] by
+   casting the (char *) pointer to (int *); GCC 4.4 did not like this,
+   and aborted compilation.
+
+ * Some unlink(2) failures went undiagnosed.
+
+ * The "recursive" merge strategy misbehaved when faced rename/delete
+   conflicts while coming up with an intermediate merge base.
+
+ * The low-level merge algorithm did not handle a degenerate case of
+   merging a file with itself using itself as the common ancestor
+   gracefully.  It should produce the file itself, but instead
+   produced an empty result.
+
+ * GIT_TRACE mechanism segfaulted when tracing a shell-quoted aliases.
+
+ * OpenBSD also uses st_ctimspec in "struct stat", instead of "st_ctim".
+
+ * With NO_CROSS_DIRECTORY_HARDLINKS, "make install" can be told not to
+   create hardlinks between $(gitexecdir)/git-$builtin_commands and
+   $(bindir)/git.
+
+ * command completion code in bash did not reliably detect that we are
+   in a bare repository.
+
+ * "git add ." in an empty directory complained that pathspec "." did not
+   match anything, which may be technically correct, but not useful.  We
+   silently make it a no-op now.
+
+ * "git add -p" (and "patch" action in "git add -i") was broken when
+   the first hunk that adds a line at the top was split into two and
+   both halves are marked to be used.
+
+ * "git blame path" misbehaved at the commit where path became file
+   from a directory with some files in it.
+
+ * "git for-each-ref" had a segfaulting bug when dealing with a tag object
+   created by an ancient git.
+
+ * "git format-patch -k" still added patch numbers if format.numbered
+   configuration was set.
+
+ * "git grep --color ''" did not terminate.  The command also had
+   subtle bugs with its -w option.
+
+ * http-push had a small use-after-free bug.
+
+ * "git push" was converting OFS_DELTA pack representation into less
+   efficient REF_DELTA representation unconditionally upon transfer,
+   making the transferred data unnecessarily larger.
+
+ * "git remote show origin" segfaulted when origin was still empty.
+
+Many other general usability updates around help text, diagnostic messages
+and documentation are included as well.
diff --git a/Documentation/RelNotes/1.6.3.3.txt b/Documentation/RelNotes/1.6.3.3.txt
new file mode 100644
index 0000000000..1c28398bb6
--- /dev/null
+++ b/Documentation/RelNotes/1.6.3.3.txt
@@ -0,0 +1,38 @@
+GIT v1.6.3.3 Release Notes
+==========================
+
+Fixes since v1.6.3.2
+--------------------
+
+ * "git archive" running on Cygwin can get stuck in an infinite loop.
+
+ * "git daemon" did not correctly parse the initial line that carries
+   virtual host request information.
+
+ * "git diff --textconv" leaked memory badly when the textconv filter
+   errored out.
+
+ * The built-in regular expressions to pick function names to put on
+   hunk header lines for java and objc were very inefficiently written.
+
+ * in certain error situations git-fetch (and git-clone) on Windows didn't
+   detect connection abort and ended up waiting indefinitely.
+
+ * import-tars script (in contrib) did not import symbolic links correctly.
+
+ * http.c used CURLOPT_SSLKEY even on libcURL version 7.9.2, even though
+   it was only available starting 7.9.3.
+
+ * low-level filelevel merge driver used return value from strdup()
+   without checking if we ran out of memory.
+
+ * "git rebase -i" left stray closing parenthesis in its reflog message.
+
+ * "git remote show" did not show all the URLs associated with the named
+   remote, even though "git remote -v" did.  Made them consistent by
+   making the former show all URLs.
+
+ * "whitespace" attribute that is set was meant to detect all errors known
+   to git, but it told git to ignore trailing carriage-returns.
+
+Includes other documentation fixes.
diff --git a/Documentation/RelNotes/1.6.3.4.txt b/Documentation/RelNotes/1.6.3.4.txt
new file mode 100644
index 0000000000..cad461bc76
--- /dev/null
+++ b/Documentation/RelNotes/1.6.3.4.txt
@@ -0,0 +1,36 @@
+GIT v1.6.3.4 Release Notes
+==========================
+
+Fixes since v1.6.3.3
+--------------------
+
+ * "git add --no-ignore-errors" did not override configured
+   add.ignore-errors configuration.
+
+ * "git apply --whitespace=fix" did not fix trailing whitespace on an
+   incomplete line.
+
+ * "git branch" opened too many commit objects unnecessarily.
+
+ * "git checkout -f $commit" with a path that is a file (or a symlink) in
+   the work tree to a commit that has a directory at the path issued an
+   unnecessary error message.
+
+ * "git diff -c/--cc" was very inefficient in coalescing the removed lines
+   shared between parents.
+
+ * "git diff -c/--cc" showed removed lines at the beginning of a file
+   incorrectly.
+
+ * "git remote show nickname" did not honor configured
+   remote.nickname.uploadpack when inspecting the branches at the remote.
+
+ * "git request-pull" when talking to the terminal for a preview
+   showed some of the output in the pager.
+
+ * "git request-pull start nickname [end]" did not honor configured
+   remote.nickname.uploadpack when it ran git-ls-remote against the remote
+   repository to learn the current tip of branches.
+
+Includes other documentation updates and minor fixes.
+
diff --git a/Documentation/RelNotes/1.6.3.txt b/Documentation/RelNotes/1.6.3.txt
new file mode 100644
index 0000000000..bbf177fc3c
--- /dev/null
+++ b/Documentation/RelNotes/1.6.3.txt
@@ -0,0 +1,182 @@
+GIT v1.6.3 Release Notes
+========================
+
+With the next major release, "git push" into a branch that is
+currently checked out will be refused by default.  You can choose
+what should happen upon such a push by setting the configuration
+variable receive.denyCurrentBranch in the receiving repository.
+
+To ease the transition plan, the receiving repository of such a
+push running this release will issue a big warning when the
+configuration variable is missing.  Please refer to:
+
+  https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
+  https://lore.kernel.org/git/7vbptlsuyv.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx/
+
+for more details on the reason why this change is needed and the
+transition plan.
+
+For a similar reason, "git push $there :$killed" to delete the branch
+$killed in a remote repository $there, if $killed branch is the current
+branch pointed at by its HEAD, gets a large warning.  You can choose what
+should happen upon such a push by setting the configuration variable
+receive.denyDeleteCurrent in the receiving repository.
+
+When the user does not tell "git push" what to push, it has always
+pushed matching refs.  For some people it is unexpected, and a new
+configuration variable push.default has been introduced to allow
+changing a different default behaviour.  To advertise the new feature,
+a big warning is issued if this is not configured and a git push without
+arguments is attempted.
+
+
+Updates since v1.6.2
+--------------------
+
+(subsystems)
+
+* various git-svn updates.
+
+* git-gui updates, including an update to Russian translation, and a
+  fix to an infinite loop when showing an empty diff.
+
+* gitk updates, including an update to Russian translation and improved Windows
+  support.
+
+(performance)
+
+* many uses of lstat(2) in the codepath for "git checkout" have been
+  optimized out.
+
+(usability, bells and whistles)
+
+* Boolean configuration variable yes/no can be written as on/off.
+
+* rsync:/path/to/repo can be used to run git over rsync for local
+  repositories.  It may not be useful in practice; meant primarily for
+  testing.
+
+* http transport learned to prompt and use password when fetching from or
+  pushing to http://user@xxxxxxx/ URL.
+
+* (msysgit) progress output that is sent over the sideband protocol can
+  be handled appropriately in Windows console.
+
+* "--pretty=<style>" option to the log family of commands can now be
+  spelled as "--format=<style>".  In addition, --format=%formatstring
+  is a short-hand for --pretty=tformat:%formatstring.
+
+* "--oneline" is a synonym for "--pretty=oneline --abbrev-commit".
+
+* "--graph" to the "git log" family can draw the commit ancestry graph
+  in colors.
+
+* If you realize that you botched the patch when you are editing hunks
+  with the 'edit' action in git-add -i/-p, you can abort the editor to
+  tell git not to apply it.
+
+* @{-1} is a new way to refer to the last branch you were on introduced in
+  1.6.2, but the initial implementation did not teach this to a few
+  commands.  Now the syntax works with "branch -m @{-1} newname".
+
+* git-archive learned --output=<file> option.
+
+* git-archive takes attributes from the tree being archived; strictly
+  speaking, this is an incompatible behaviour change, but is a good one.
+  Use --worktree-attributes option to allow it to read attributes from
+  the work tree as before (deprecated git-tar tree command always reads
+  attributes from the work tree).
+
+* git-bisect shows not just the number of remaining commits whose goodness
+  is unknown, but also shows the estimated number of remaining rounds.
+
+* You can give --date=<format> option to git-blame.
+
+* "git-branch -r" shows HEAD symref that points at a remote branch in
+  interest of each tracked remote repository.
+
+* "git-branch -v -v" is a new way to get list of names for branches and the
+  "upstream" branch for them.
+
+* git-config learned -e option to open an editor to edit the config file
+  directly.
+
+* git-clone runs post-checkout hook when run without --no-checkout.
+
+* git-difftool is now part of the officially supported command, primarily
+  maintained by David Aguilar.
+
+* git-for-each-ref learned a new "upstream" token.
+
+* git-format-patch can be told to use attachment with a new configuration,
+  format.attach.
+
+* git-format-patch can be told to produce deep or shallow message threads.
+
+* git-format-patch can be told to always add sign-off with a configuration
+  variable.
+
+* git-format-patch learned format.headers configuration to add extra
+  header fields to the output.  This behaviour is similar to the existing
+  --add-header=<header> option of the command.
+
+* git-format-patch gives human readable names to the attached files, when
+  told to send patches as attachments.
+
+* git-grep learned to highlight the found substrings in color.
+
+* git-imap-send learned to work around Thunderbird's inability to easily
+  disable format=flowed with a new configuration, imap.preformattedHTML.
+
+* git-rebase can be told to rebase the series even if your branch is a
+  descendant of the commit you are rebasing onto with --force-rebase
+  option.
+
+* git-rebase can be told to report diffstat with the --stat option.
+
+* Output from git-remote command has been vastly improved.
+
+* "git remote update --prune $remote" updates from the named remote and
+  then prunes stale tracking branches.
+
+* git-send-email learned --confirm option to review the Cc: list before
+  sending the messages out.
+
+(developers)
+
+* Test scripts can be run under valgrind.
+
+* Test scripts can be run with installed git.
+
+* Makefile learned 'coverage' option to run the test suites with
+  coverage tracking enabled.
+
+* Building the manpages with docbook-xsl between 1.69.1 and 1.71.1 now
+  requires setting DOCBOOK_SUPPRESS_SP to work around a docbook-xsl bug.
+  This workaround used to be enabled by default, but causes problems
+  with newer versions of docbook-xsl.  In addition, there are a few more
+  knobs you can tweak to work around issues with various versions of the
+  docbook-xsl package.  See comments in Documentation/Makefile for details.
+
+* Support for building and testing a subset of git on a system without a
+  working perl has been improved.
+
+
+Fixes since v1.6.2
+------------------
+
+All of the fixes in v1.6.2.X maintenance series are included in this
+release, unless otherwise noted.
+
+Here are fixes that this release has, but have not been backported to
+v1.6.2.X series.
+
+* "git-apply" rejected a patch that swaps two files (i.e. renames A to B
+  and B to A at the same time).  May need to be backported by cherry
+  picking d8c81df and then 7fac0ee).
+
+* The initial checkout did not read the attributes from the .gitattribute
+  file that is being checked out.
+
+* git-gc spent excessive amount of time to decide if an object appears
+  in a locally existing pack (if needed, backport by merging 69e020a).
diff --git a/Documentation/RelNotes/1.6.4.1.txt b/Documentation/RelNotes/1.6.4.1.txt
new file mode 100644
index 0000000000..e439e45b96
--- /dev/null
+++ b/Documentation/RelNotes/1.6.4.1.txt
@@ -0,0 +1,46 @@
+GIT v1.6.4.1 Release Notes
+==========================
+
+Fixes since v1.6.4
+------------------
+
+ * An unquoted value in the configuration file, when it contains more than
+   one whitespaces in a row, got them replaced with a single space.
+
+ * "git am" used to accept a single piece of e-mail per file (not a mbox)
+   as its input, but multiple input format support in v1.6.4 broke it.
+   Apparently many people have been depending on this feature.
+
+ * The short help text for "git filter-branch" command was a single long
+   line, wrapped by terminals, and was hard to read.
+
+ * The "recursive" strategy of "git merge" segfaulted when a merge has
+   more than one merge-bases, and merging of these merge-bases involves
+   a rename/rename or a rename/add conflict.
+
+ * "git pull --rebase" did not use the right fork point when the
+   repository has already fetched from the upstream that rewinds the
+   branch it is based on in an earlier fetch.
+
+ * Explain the concept of fast-forward more fully in "git push"
+   documentation, and hint to refer to it from an error message when the
+   command refuses an update to protect the user.
+
+ * The default value for pack.deltacachesize, used by "git repack", is now
+   256M, instead of unbounded.  Otherwise a repack of a moderately sized
+   repository would needlessly eat into swap.
+
+ * Document how "git repack" (hence "git gc") interacts with a repository
+   that borrows its objects from other repositories (e.g. ones created by
+   "git clone -s").
+
+ * "git show" on an annotated tag lacked a delimiting blank line between
+   the tag itself and the contents of the object it tags.
+
+ * "git verify-pack -v" erroneously reported number of objects with too
+   deep delta depths as "chain length 0" objects.
+
+ * Long names of authors and committers outside US-ASCII were sometimes
+   incorrectly shown in "gitweb".
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.4.2.txt b/Documentation/RelNotes/1.6.4.2.txt
new file mode 100644
index 0000000000..c11ec0115c
--- /dev/null
+++ b/Documentation/RelNotes/1.6.4.2.txt
@@ -0,0 +1,32 @@
+GIT v1.6.4.2 Release Notes
+==========================
+
+Fixes since v1.6.4.1
+--------------------
+
+* --date=relative output between 1 and 5 years ago rounded the number of
+    years when saying X years Y months ago, instead of rounding it down.
+
+* "git add -p" did not handle changes in executable bits correctly
+  (a regression around 1.6.3).
+
+* "git apply" did not honor GNU diff's convention to mark the creation/deletion
+  event with UNIX epoch timestamp on missing side.
+
+* "git checkout" incorrectly removed files in a directory pointed by a
+  symbolic link during a branch switch that replaces a directory with
+  a symbolic link.
+
+* "git clean -d -f" happily descended into a subdirectory that is managed by a
+  separate git repository.  It now requires two -f options for safety.
+
+* "git fetch/push" over http transports had two rather grave bugs.
+
+* "git format-patch --cover-letter" did not prepare the cover letter file
+  for use with non-ASCII strings when there are the series contributors with
+  non-ASCII names.
+
+* "git pull origin branch" and "git fetch origin && git merge origin/branch"
+  left different merge messages in the resulting commit.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.4.3.txt b/Documentation/RelNotes/1.6.4.3.txt
new file mode 100644
index 0000000000..5643e6537d
--- /dev/null
+++ b/Documentation/RelNotes/1.6.4.3.txt
@@ -0,0 +1,29 @@
+GIT v1.6.4.3 Release Notes
+==========================
+
+Fixes since v1.6.4.2
+--------------------
+
+* "git clone" from an empty repository gave unnecessary error message,
+  even though it did everything else correctly.
+
+* "git cvsserver" invoked git commands via "git-foo" style, which has long
+  been deprecated.
+
+* "git fetch" and "git clone" had an extra sanity check to verify the
+  presence of the corresponding *.pack file before downloading *.idx
+  file by issuing a HEAD request.  Github server however sometimes
+  gave 500 (Internal server error) response to HEAD even if a GET
+  request for *.pack file to the same URL would have succeeded, and broke
+  clone over HTTP from some of their repositories.  As a workaround, this
+  verification has been removed (as it is not absolutely necessary).
+
+* "git grep" did not like relative pathname to refer outside the current
+  directory when run from a subdirectory.
+
+* an error message from "git push" was formatted in a very ugly way.
+
+* "git svn" did not quote the subversion user name correctly when
+  running its author-prog helper program.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.4.4.txt b/Documentation/RelNotes/1.6.4.4.txt
new file mode 100644
index 0000000000..0ead45fc72
--- /dev/null
+++ b/Documentation/RelNotes/1.6.4.4.txt
@@ -0,0 +1,26 @@
+GIT v1.6.4.4 Release Notes
+==========================
+
+Fixes since v1.6.4.4
+--------------------
+
+* The workaround for Github server that sometimes gave 500 (Internal server
+  error) response to HEAD requests in 1.6.4.3 introduced a regression that
+  caused re-fetching projects over http to segfault in certain cases due
+  to uninitialized pointer being freed.
+
+* "git pull" on an unborn branch used to consider anything in the work
+  tree and the index discardable.
+
+* "git diff -b/w" did not work well on the incomplete line at the end of
+  the file, due to an incorrect hashing of lines in the low-level xdiff
+  routines.
+
+* "git checkout-index --prefix=$somewhere" used to work when $somewhere is
+  a symbolic link to a directory elsewhere, but v1.6.4.2 broke it.
+
+* "git unpack-objects --strict", invoked when receive.fsckobjects
+  configuration is set in the receiving repository of "git push", did not
+  properly check the objects, especially the submodule links, it received.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.4.5.txt b/Documentation/RelNotes/1.6.4.5.txt
new file mode 100644
index 0000000000..eb6307dcbb
--- /dev/null
+++ b/Documentation/RelNotes/1.6.4.5.txt
@@ -0,0 +1,20 @@
+Git v1.6.4.5 Release Notes
+==========================
+
+Fixes since v1.6.4.4
+--------------------
+
+ * Simplified base85 implementation.
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git count-objects" did not handle packs larger than 4G.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.4.txt b/Documentation/RelNotes/1.6.4.txt
new file mode 100644
index 0000000000..0fccfb0bf0
--- /dev/null
+++ b/Documentation/RelNotes/1.6.4.txt
@@ -0,0 +1,147 @@
+GIT v1.6.4 Release Notes
+========================
+
+With the next major release, "git push" into a branch that is
+currently checked out will be refused by default.  You can choose
+what should happen upon such a push by setting the configuration
+variable receive.denyCurrentBranch in the receiving repository.
+
+To ease the transition plan, the receiving repository of such a
+push running this release will issue a big warning when the
+configuration variable is missing.  Please refer to:
+
+  https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
+  https://lore.kernel.org/git/7vbptlsuyv.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx/
+
+for more details on the reason why this change is needed and the
+transition plan.
+
+For a similar reason, "git push $there :$killed" to delete the branch
+$killed in a remote repository $there, if $killed branch is the current
+branch pointed at by its HEAD, gets a large warning.  You can choose what
+should happen upon such a push by setting the configuration variable
+receive.denyDeleteCurrent in the receiving repository.
+
+
+Updates since v1.6.3
+--------------------
+
+(subsystems)
+
+ * gitweb Perl style clean-up.
+
+ * git-svn updates, including a new --authors-prog option to map author
+   names by invoking an external program, 'git svn reset' to unwind
+   'git svn fetch', support for more than one branches, documenting
+   of the useful --minimize-url feature, new "git svn gc" command, etc.
+
+(portability)
+
+ * We feed iconv with "UTF-8" instead of "utf8"; the former is
+   understood more widely.  Similarly updated test scripts to use
+   encoding names more widely understood (e.g. use "ISO8859-1" instead
+   of "ISO-8859-1").
+
+ * Various portability fixes/workarounds for different vintages of
+   SunOS, IRIX, and Windows.
+
+ * Git-over-ssh transport on Windows supports PuTTY plink and TortoisePlink.
+
+(performance)
+
+ * Many repeated use of lstat() are optimized out in "checkout" codepath.
+
+ * git-status (and underlying git-diff-index --cached) are optimized
+   to take advantage of cache-tree information in the index.
+
+(usability, bells and whistles)
+
+ * "git add --edit" lets users edit the whole patch text to fine-tune what
+   is added to the index.
+
+ * "git am" accepts StGIT series file as its input.
+
+ * "git bisect skip" skips to a more randomly chosen place in the hope
+   to avoid testing a commit that is too close to a commit that is
+   already known to be untestable.
+
+ * "git cvsexportcommit" learned -k option to stop CVS keywords expansion
+
+ * "git fast-export" learned to handle history simplification more
+   gracefully.
+
+ * "git fast-export" learned an option --tag-of-filtered-object to handle
+   dangling tags resulting from history simplification more usefully.
+
+ * "git grep" learned -p option to show the location of the match using the
+   same context hunk marker "git diff" uses.
+
+ * https transport can optionally be told that the used client
+   certificate is password protected, in which case it asks the
+   password only once.
+
+ * "git imap-send" is IPv6 aware.
+
+ * "git log --graph" draws graphs more compactly by using horizontal lines
+   when able.
+
+ * "git log --decorate" shows shorter refnames by stripping well-known
+   refs/* prefix.
+
+ * "git push $name" honors remote.$name.pushurl if present before
+   using remote.$name.url.  In other words, the URL used for fetching
+   and pushing can be different.
+
+ * "git send-email" understands quoted aliases in .mailrc files (might
+   have to be backported to 1.6.3.X).
+
+ * "git send-email" can fetch the sender address from the configuration
+   variable "sendmail.from" (and "sendmail.<identity>.from").
+
+ * "git show-branch" can color its output.
+
+ * "add" and "update" subcommands to "git submodule" learned --reference
+   option to use local clone with references.
+
+ * "git submodule update" learned --rebase option to update checked
+   out submodules by rebasing the local changes.
+
+ * "gitweb" can optionally use gravatar to adorn author/committer names.
+
+(developers)
+
+ * A major part of the "git bisect" wrapper has moved to C.
+
+ * Formatting with the new version of AsciiDoc 8.4.1 is now supported.
+
+Fixes since v1.6.3
+------------------
+
+All of the fixes in v1.6.3.X maintenance series are included in this
+release, unless otherwise noted.
+
+Here are fixes that this release has, but have not been backported to
+v1.6.3.X series.
+
+ * "git diff-tree -r -t" used to omit new or removed directories from
+   the output.  df533f3 (diff-tree -r -t: include added/removed
+   directories in the output, 2009-06-13) may need to be cherry-picked
+   to backport this fix.
+
+ * The way Git.pm sets up a Repository object was not friendly to callers
+   that chdir around.  It now internally records the repository location
+   as an absolute path when autodetected.
+
+ * Removing a section with "git config --remove-section", when its
+   section header has a variable definition on the same line, lost
+   that variable definition.
+
+ * "git rebase -p --onto" used to always leave side branches of a merge
+   intact, even when both branches are subject to rewriting.
+
+ * "git repack" used to faithfully follow grafts and considered true
+   parents recorded in the commit object unreachable from the commit.
+   After such a repacking, you cannot remove grafts without corrupting
+   the repository.
+
+ * "git send-email" did not detect erroneous loops in alias expansion.
diff --git a/Documentation/RelNotes/1.6.5.1.txt b/Documentation/RelNotes/1.6.5.1.txt
new file mode 100644
index 0000000000..309ba181b2
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.1.txt
@@ -0,0 +1,20 @@
+GIT v1.6.5.1 Release Notes
+==========================
+
+Fixes since v1.6.5
+------------------
+
+ * An corrupt pack could make codepath to read objects into an
+   infinite loop.
+
+ * Download throughput display was always shown in KiB/s but on fast links
+   it is more appropriate to show it in MiB/s.
+
+ * "git grep -f filename" used uninitialized variable and segfaulted.
+
+ * "git clone -b branch" gave a wrong commit object name to post-checkout
+   hook.
+
+ * "git pull" over http did not work on msys.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.5.2.txt b/Documentation/RelNotes/1.6.5.2.txt
new file mode 100644
index 0000000000..aa7ccce3a2
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.2.txt
@@ -0,0 +1,19 @@
+GIT v1.6.5.2 Release Notes
+==========================
+
+Fixes since v1.6.5.1
+--------------------
+
+ * Installation of templates triggered a bug in busybox when using tar
+   implementation from it.
+
+ * "git add -i" incorrectly ignored paths that are already in the index
+   if they matched .gitignore patterns.
+
+ * "git describe --always" should have produced some output even there
+   were no tags in the repository, but it didn't.
+
+ * "git ls-files" when showing tracked files incorrectly paid attention
+   to the exclude patterns.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.5.3.txt b/Documentation/RelNotes/1.6.5.3.txt
new file mode 100644
index 0000000000..b2fad1b22e
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.3.txt
@@ -0,0 +1,63 @@
+Git v1.6.5.3 Release Notes
+==========================
+
+Fixes since v1.6.5.2
+--------------------
+
+ * info/grafts file didn't ignore trailing CR at the end of lines.
+
+ * Packages generated on newer FC were unreadable by older versions of
+   RPM as the new default is to use stronger hash.
+
+ * output from "git blame" was unreadable when the file ended in an
+   incomplete line.
+
+ * "git add -i/-p" didn't handle deletion of empty files correctly.
+
+ * "git clone" takes up to two parameters, but did not complain when
+   given more arguments than necessary and silently ignored them.
+
+ * "git cvsimport" did not read files given as command line arguments
+   correctly when it is run from a subdirectory.
+
+ * "git diff --color-words -U0" didn't work correctly.
+
+ * The handling of blank lines at the end of file by "git diff/apply
+   --whitespace" was inconsistent with the other kinds of errors.
+   They are now colored, warned against, and fixed the same way as others.
+
+ * There was no way to allow blank lines at the end of file without
+   allowing extra blanks at the end of lines.  You can use blank-at-eof
+   and blank-at-eol whitespace error class to specify them separately.
+   The old trailing-space error class is now a short-hand to set both.
+
+ * "-p" option to "git format-patch" was supposed to suppress diffstat
+   generation, but it was broken since 1.6.1.
+
+ * "git imap-send" did not compile cleanly with newer OpenSSL.
+
+ * "git help -a" outside of a git repository was broken.
+
+ * "git ls-files -i" was supposed to be inverse of "git ls-files" without -i
+   with respect to exclude patterns, but it was broken since 1.6.5.2.
+
+ * "git ls-remote" outside of a git repository over http was broken.
+
+ * "git rebase -i" gave bogus error message when the command word was
+   misspelled.
+
+ * "git receive-pack" that is run in response to "git push" did not run
+   garbage collection nor update-server-info, but in larger hosting sites,
+   these almost always need to be run.  To help site administrators, the
+   command now runs "gc --auto" and "u-s-i" by setting receive.autogc
+   and receive.updateserverinfo configuration variables, respectively.
+
+ * Release notes spelled the package name with incorrect capitalization.
+
+ * "gitweb" did not escape non-ascii characters correctly in the URL.
+
+ * "gitweb" showed "patch" link even for merge commits.
+
+ * "gitweb" showed incorrect links for blob line numbers in pathinfo mode.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.5.4.txt b/Documentation/RelNotes/1.6.5.4.txt
new file mode 100644
index 0000000000..344333de66
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.4.txt
@@ -0,0 +1,32 @@
+Git v1.6.5.4 Release Notes
+==========================
+
+Fixes since v1.6.5.3
+--------------------
+
+ * "git help" (without argument) used to check if you are in a directory
+   under git control. There was no breakage in behaviour per-se, but this
+   was unnecessary.
+
+ * "git prune-packed" gave progress output even when its standard error is
+   not connected to a terminal; this caused cron jobs that run it to
+   produce cruft.
+
+ * "git pack-objects --all-progress" is an option to ask progress output
+   from write-object phase _if_ progress output were to be produced, and
+   shouldn't have forced the progress output.
+
+ * "git apply -p<n> --directory=<elsewhere>" did not work well for a
+   non-default value of n.
+
+ * "git merge foo HEAD" was misparsed as an old-style invocation of the
+   command and produced a confusing error message.  As it does not specify
+   any other branch to merge, it shouldn't be mistaken as such.  We will
+   remove the old style "git merge <message> HEAD <commit>..."  syntax in
+   future versions, but not in this release,
+
+ * "git merge -m <message> <branch>..." added the standard merge message
+   on its own after user-supplied message, which should have overridden the
+   standard one.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.5.5.txt b/Documentation/RelNotes/1.6.5.5.txt
new file mode 100644
index 0000000000..ecfc57d875
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.5.txt
@@ -0,0 +1,49 @@
+Git v1.6.5.5 Release Notes
+==========================
+
+Fixes since v1.6.5.4
+--------------------
+
+ * Manual pages can be formatted with older xmlto again.
+
+ * GREP_OPTIONS exported from user's environment could have broken
+   our scripted commands.
+
+ * In configuration files, a few variables that name paths can begin with
+   ~/ and ~username/ and they are expanded as expected.  This is not a
+   bugfix but 1.6.6 will have this and without backporting users cannot
+   easily use the same ~/.gitconfig across versions.
+
+ * "git diff -B -M" did the same computation to hash lines of contents
+   twice, and held onto memory after it has used the data in it
+   unnecessarily before it freed.
+
+ * "git diff -B" and "git diff --dirstat" was not counting newly added
+   contents correctly.
+
+ * "git format-patch revisions... -- path" issued an incorrect error
+   message that suggested to use "--" on the command line when path
+   does not exist in the current work tree (it is a separate matter if
+   it makes sense to limit format-patch with pathspecs like that
+   without using the --full-diff option).
+
+ * "git grep -F -i StRiNg" did not work as expected.
+
+ * Enumeration of available merge strategies iterated over the list of
+   commands in a wrong way, sometimes producing an incorrect result.
+
+ * "git shortlog" did not honor the "encoding" header embedded in the
+   commit object like "git log" did.
+
+ * Reading progress messages that come from the remote side while running
+   "git pull" is given precedence over reading the actual pack data to
+   prevent garbled progress message on the user's terminal.
+
+ * "git rebase" got confused when the log message began with certain
+   strings that looked like Subject:, Date: or From: header.
+
+ * "git reset" accidentally run in .git/ directory checked out the
+   work tree contents in there.
+
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.5.6.txt b/Documentation/RelNotes/1.6.5.6.txt
new file mode 100644
index 0000000000..a9eaf76f62
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.6.txt
@@ -0,0 +1,23 @@
+Git v1.6.5.6 Release Notes
+==========================
+
+Fixes since v1.6.5.5
+--------------------
+
+ * "git add -p" had a regression since v1.6.5.3 that broke deletion of
+   non-empty files.
+
+ * "git archive -o o.zip -- Makefile" produced an archive in o.zip
+   but in POSIX tar format.
+
+ * Error message given to "git pull --rebase" when the user didn't give
+   enough clue as to what branch to integrate with still talked about
+   "merging with" the branch.
+
+ * Error messages given by "git merge" when the merge resulted in a
+   fast-forward still were in plumbing lingo, even though in v1.6.5
+   we reworded messages in other cases.
+
+ * The post-upload-hook run by upload-pack in response to "git fetch" has
+   been removed, due to security concerns (the hook first appeared in
+   1.6.5).
diff --git a/Documentation/RelNotes/1.6.5.7.txt b/Documentation/RelNotes/1.6.5.7.txt
new file mode 100644
index 0000000000..dc5302c21c
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.7.txt
@@ -0,0 +1,19 @@
+Git v1.6.5.7 Release Notes
+==========================
+
+Fixes since v1.6.5.6
+--------------------
+
+* If a user specifies a color for a <slot> (i.e. a class of things to show
+  in a particular color) that is known only by newer versions of git
+  (e.g. "color.diff.func" was recently added for upcoming 1.6.6 release),
+  an older version of git should just ignore them.  Instead we diagnosed
+  it as an error.
+
+* With help.autocorrect set to non-zero value, the logic to guess typos
+  in the subcommand name misfired and ran a random nonsense command.
+
+* If a command is run with an absolute path as a pathspec inside a bare
+  repository, e.g. "rev-list HEAD -- /home", the code tried to run
+  strlen() on NULL, which is the result of get_git_work_tree(), and
+  segfaulted.
diff --git a/Documentation/RelNotes/1.6.5.8.txt b/Documentation/RelNotes/1.6.5.8.txt
new file mode 100644
index 0000000000..8b24bebb96
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.8.txt
@@ -0,0 +1,28 @@
+Git v1.6.5.8 Release Notes
+==========================
+
+Fixes since v1.6.5.7
+--------------------
+
+* "git count-objects" did not handle packfiles that are bigger than 4G on
+  platforms with 32-bit off_t.
+
+* "git rebase -i" did not abort cleanly if it failed to launch the editor.
+
+* "git blame" did not work well when commit lacked the author name.
+
+* "git fast-import" choked when handling a tag that points at an object
+  that is not a commit.
+
+* "git reset --hard" did not work correctly when GIT_WORK_TREE environment
+  variable is used to point at the root of the true work tree.
+
+* "git grep" fed a buffer that is not NUL-terminated to underlying
+  regexec().
+
+* "git checkout -m other" while on a branch that does not have any commit
+  segfaulted, instead of failing.
+
+* "git branch -a other" should have diagnosed the command as an error.
+
+Other minor documentation updates are also included.
diff --git a/Documentation/RelNotes/1.6.5.9.txt b/Documentation/RelNotes/1.6.5.9.txt
new file mode 100644
index 0000000000..bb469dd71e
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.9.txt
@@ -0,0 +1,18 @@
+Git v1.6.5.9 Release Notes
+==========================
+
+Fixes since v1.6.5.8
+--------------------
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git blame -L $start,$end" segfaulted when too large $start was given.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.5.txt b/Documentation/RelNotes/1.6.5.txt
new file mode 100644
index 0000000000..79cb1b2b6d
--- /dev/null
+++ b/Documentation/RelNotes/1.6.5.txt
@@ -0,0 +1,169 @@
+GIT v1.6.5 Release Notes
+========================
+
+In git 1.7.0, which was planned to be the release after 1.6.5, "git
+push" into a branch that is currently checked out will be refused by
+default.
+
+You can choose what should happen upon such a push by setting the
+configuration variable receive.denyCurrentBranch in the receiving
+repository.
+
+Also, "git push $there :$killed" to delete the branch $killed in a remote
+repository $there, when $killed branch is the current branch pointed at by
+its HEAD, will be refused by default.
+
+You can choose what should happen upon such a push by setting the
+configuration variable receive.denyDeleteCurrent in the receiving
+repository.
+
+To ease the transition plan, the receiving repository of such a
+push running this release will issue a big warning when the
+configuration variable is missing.  Please refer to:
+
+  https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
+  https://lore.kernel.org/git/7vbptlsuyv.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx/
+
+for more details on the reason why this change is needed and the
+transition plan.
+
+Updates since v1.6.4
+--------------------
+
+(subsystems)
+
+ * various updates to gitk, git-svn and gitweb.
+
+(portability)
+
+ * more improvements on mingw port.
+
+ * mingw will also give FRSX as the default value for the LESS
+   environment variable when the user does not have one.
+
+ * initial support to compile git on Windows with MSVC.
+
+(performance)
+
+ * On major platforms, the system can be compiled to use with Linus's
+   block-sha1 implementation of the SHA-1 hash algorithm, which
+   outperforms the default fallback implementation we borrowed from
+   Mozilla.
+
+ * Unnecessary inefficiency in deepening of a shallow repository has
+   been removed.
+
+ * "git clone" does not grab objects that it does not need (i.e.
+   referenced only from refs outside refs/heads and refs/tags
+   hierarchy) anymore.
+
+ * The "git" main binary used to link with libcurl, which then dragged
+   in a large number of external libraries.  When using basic plumbing
+   commands in scripts, this unnecessarily slowed things down.  We now
+   implement http/https/ftp transfer as a separate executable as we
+   used to.
+
+ * "git clone" run locally hardlinks or copies the files in .git/ to
+   newly created repository.  It used to give new mtime to copied files,
+   but this delayed garbage collection to trigger unnecessarily in the
+   cloned repository.  We now preserve mtime for these files to avoid
+   this issue.
+
+(usability, bells and whistles)
+
+ * Human writable date format to various options, e.g. --since=yesterday,
+   master@{2000.09.17}, are taught to infer some omitted input properly.
+
+ * A few programs gave verbose "advice" messages to help uninitiated
+   people when issuing error messages.  An infrastructure to allow
+   users to squelch them has been introduced, and a few such messages
+   can be silenced now.
+
+ * refs/replace/ hierarchy is designed to be usable as a replacement
+   of the "grafts" mechanism, with the added advantage that it can be
+   transferred across repositories.
+
+ * "git am" learned to optionally ignore whitespace differences.
+
+ * "git am" handles input e-mail files that has CRLF line endings sensibly.
+
+ * "git am" learned "--scissors" option to allow you to discard early part
+   of an incoming e-mail.
+
+ * "git archive -o output.zip" works without being told what format to
+   use with an explicit "--format=zip".option.
+
+ * "git checkout", "git reset" and "git stash" learned to pick and
+   choose to use selected changes you made, similar to "git add -p".
+
+ * "git clone" learned a "-b" option to pick a HEAD to check out
+   different from the remote's default branch.
+
+ * "git clone" learned --recursive option.
+
+ * "git clone" from a local repository on a different filesystem used to
+   copy individual object files without preserving the old timestamp, giving
+   them extra lifetime in the new repository until they gc'ed.
+
+ * "git commit --dry-run $args" is a new recommended way to ask "what would
+   happen if I try to commit with these arguments."
+
+ * "git commit --dry-run" and "git status" shows conflicted paths in a
+   separate section to make them easier to spot during a merge.
+
+ * "git cvsimport" now supports password-protected pserver access even
+   when the password is not taken from ~/.cvspass file.
+
+ * "git fast-export" learned --no-data option that can be useful when
+   reordering commits and trees without touching the contents of
+   blobs.
+
+ * "git fast-import" has a pair of new front-end in contrib/ area.
+
+ * "git init" learned to mkdir/chdir into a directory when given an
+   extra argument (i.e. "git init this").
+
+ * "git instaweb" optionally can use mongoose as the web server.
+
+ * "git log --decorate" can optionally be told with --decorate=full to
+   give the reference name in full.
+
+ * "git merge" issued an unnecessarily scary message when it detected
+   that the merge may have to touch the path that the user has local
+   uncommitted changes to. The message has been reworded to make it
+   clear that the command aborted, without doing any harm.
+
+ * "git push" can be told to be --quiet.
+
+ * "git push" pays attention to url.$base.pushInsteadOf and uses a URL
+   that is derived from the URL used for fetching.
+
+ * informational output from "git reset" that lists the locally modified
+   paths is made consistent with that of "git checkout $another_branch".
+
+ * "git submodule" learned to give submodule name to scripts run with
+   "foreach" subcommand.
+
+ * various subcommands to "git submodule" learned --recursive option.
+
+ * "git submodule summary" learned --files option to compare the work
+   tree vs the commit bound at submodule path, instead of comparing
+   the index.
+
+ * "git upload-pack", which is the server side support for "git clone" and
+   "git fetch", can call a new post-upload-pack hook for statistics purposes.
+
+(developers)
+
+ * With GIT_TEST_OPTS="--root=/p/a/t/h", tests can be run outside the
+   source directory; using tmpfs may give faster turnaround.
+
+ * With NO_PERL_MAKEMAKER set, DESTDIR= is now honoured, so you can
+   build for one location, and install into another location to tar it
+   up.
+
+Fixes since v1.6.4
+------------------
+
+All of the fixes in v1.6.4.X maintenance series are included in this
+release, unless otherwise noted.
diff --git a/Documentation/RelNotes/1.6.6.1.txt b/Documentation/RelNotes/1.6.6.1.txt
new file mode 100644
index 0000000000..f1d0a4ae2d
--- /dev/null
+++ b/Documentation/RelNotes/1.6.6.1.txt
@@ -0,0 +1,37 @@
+Git v1.6.6.1 Release Notes
+==========================
+
+Fixes since v1.6.6
+------------------
+
+ * "git blame" did not work well when commit lacked the author name.
+
+ * "git branch -a name" wasn't diagnosed as an error.
+
+ * "git count-objects" did not handle packfiles that are bigger than 4G on
+   platforms with 32-bit off_t.
+
+ * "git checkout -m other" while on a branch that does not have any commit
+   segfaulted, instead of failing.
+
+ * "git fast-import" choked when fed a tag that do not point at a
+   commit.
+
+ * "git grep" finding from work tree files could have fed garbage to
+   the underlying regexec(3).
+
+ * "git grep -L" didn't show empty files (they should never match, and
+   they should always appear in -L output as unmatching).
+
+ * "git rebase -i" did not abort cleanly if it failed to launch the editor.
+
+ * "git reset --hard" did not work correctly when GIT_WORK_TREE environment
+   variable is used to point at the root of the true work tree.
+
+ * http-backend was not listed in the command list in the documentation.
+
+ * Building on FreeBSD (both 7 and 8) needs OLD_ICONV set in the Makefile
+
+ * "git checkout -m some-branch" while on an unborn branch crashed.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.6.2.txt b/Documentation/RelNotes/1.6.6.2.txt
new file mode 100644
index 0000000000..4eaddc0106
--- /dev/null
+++ b/Documentation/RelNotes/1.6.6.2.txt
@@ -0,0 +1,46 @@
+Git v1.6.6.2 Release Notes
+==========================
+
+Fixes since v1.6.6.1
+--------------------
+
+ * recursive merge didn't correctly diagnose its own programming errors,
+   and instead caused the caller to segfault.
+
+ * The new "smart http" aware clients probed the web servers to see if
+   they support smart http, but did not fall back to dumb http transport
+   correctly with some servers.
+
+ * Time based reflog syntax e.g. "@{yesterday}" didn't diagnose a misspelled
+   time specification and instead assumed "@{now}".
+
+ * "git archive HEAD -- no-such-directory" produced an empty archive
+   without complaining.
+
+ * "git blame -L start,end -- file" misbehaved when given a start that is
+   larger than the number of lines in the file.
+
+ * "git checkout -m" didn't correctly call custom merge backend supplied
+   by the end user.
+
+ * "git config -f <file>" misbehaved when run from a subdirectory.
+
+ * "git cvsserver" didn't like having regex metacharacters (e.g. '+') in
+   CVSROOT environment.
+
+ * "git fast-import" did not correctly handle large blobs that may
+   bust the pack size limit.
+
+ * "git gui" is supposed to work even when launched from inside a .git
+   directory.
+
+ * "git gui" misbehaved when applying a hunk that ends with deletion.
+
+ * "git imap-send" did not honor imap.preformattedHTML as documented.
+
+ * "git log" family incorrectly showed the commit notes unconditionally by
+   mistake, which was especially irritating when running "git log --oneline".
+
+ * "git status" shouldn't require an write access to the repository.
+
+Other minor documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.6.3.txt b/Documentation/RelNotes/1.6.6.3.txt
new file mode 100644
index 0000000000..11483acaec
--- /dev/null
+++ b/Documentation/RelNotes/1.6.6.3.txt
@@ -0,0 +1,23 @@
+Git v1.6.6.3 Release Notes
+==========================
+
+Fixes since v1.6.6.2
+--------------------
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git bisect $path" did not correctly diagnose an error when given a
+   non-existent path.
+
+ * "git blame -L $start,$end" segfaulted when too large $start was given.
+
+ * "git imap-send" did not write draft box with CRLF line endings per RFC.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are included.
diff --git a/Documentation/RelNotes/1.6.6.txt b/Documentation/RelNotes/1.6.6.txt
new file mode 100644
index 0000000000..88b86a827e
--- /dev/null
+++ b/Documentation/RelNotes/1.6.6.txt
@@ -0,0 +1,224 @@
+Git v1.6.6 Release Notes
+========================
+
+Notes on behaviour change
+-------------------------
+
+ * In this release, "git fsck" defaults to "git fsck --full" and
+   checks packfiles, and because of this it will take much longer to
+   complete than before.  If you prefer a quicker check only on loose
+   objects (the old default), you can say "git fsck --no-full".  This
+   has been supported by 1.5.4 and newer versions of git, so it is
+   safe to write it in your script even if you use slightly older git
+   on some of your machines.
+
+Preparing yourselves for compatibility issues in 1.7.0
+------------------------------------------------------
+
+In git 1.7.0, which is planned to be the release after 1.6.6, there will
+be a handful of behaviour changes that will break backward compatibility.
+
+These changes were discussed long time ago and existing behaviours have
+been identified as more problematic to the userbase than keeping them for
+the sake of backward compatibility.
+
+When necessary, a transition strategy for existing users has been designed
+not to force them running around setting configuration variables and
+updating their scripts in order to either keep the traditional behaviour
+or adjust to the new behaviour, on the day their sysadmin decides to install
+the new version of git.  When we switched from "git-foo" to "git foo" in
+1.6.0, even though the change had been advertised and the transition
+guide had been provided for a very long time, the users procrastinated
+during the entire transition period, and ended up panicking on the day
+their sysadmins updated their git installation.  We are trying to avoid
+repeating that unpleasantness in the 1.7.0 release.
+
+For changes decided to be in 1.7.0, commands that will be affected
+have been much louder to strongly discourage such procrastination, and
+they continue to be in this release.  If you have been using recent
+versions of git, you would have seen warnings issued when you used
+features whose behaviour will change, with a clear instruction on how
+to keep the existing behaviour if you want to.  You hopefully are
+already well prepared.
+
+Of course, we have also been giving "this and that will change in
+1.7.0; prepare yourselves" warnings in the release notes and
+announcement messages for the past few releases.  Let's see how well
+users will fare this time.
+
+ * "git push" into a branch that is currently checked out (i.e. pointed by
+   HEAD in a repository that is not bare) will be refused by default.
+
+   Similarly, "git push $there :$killed" to delete the branch $killed
+   in a remote repository $there, when $killed branch is the current
+   branch pointed at by its HEAD, will be refused by default.
+
+   Setting the configuration variables receive.denyCurrentBranch and
+   receive.denyDeleteCurrent to 'ignore' in the receiving repository
+   can be used to override these safety features.  Versions of git
+   since 1.6.2 have issued a loud warning when you tried to do these
+   operations without setting the configuration, so repositories of
+   people who still need to be able to perform such a push should
+   already have been future proofed.
+
+   Please refer to:
+
+   https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/GitFaq.html#non-bare
+   https://lore.kernel.org/git/7vbptlsuyv.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx/
+
+   for more details on the reason why this change is needed and the
+   transition process that already took place so far.
+
+ * "git send-email" will not make deep threads by default when sending a
+   patch series with more than two messages.  All messages will be sent
+   as a reply to the first message, i.e. cover letter.  Git 1.6.6 (this
+   release) will issue a warning about the upcoming default change, when
+   it uses the traditional "deep threading" behaviour as the built-in
+   default.  To squelch the warning but still use the "deep threading"
+   behaviour, give --chain-reply-to option or set sendemail.chainreplyto
+   to true.
+
+   It has been possible to configure send-email to send "shallow thread"
+   by setting sendemail.chainreplyto configuration variable to false.
+   The only thing 1.7.0 release will do is to change the default when
+   you haven't configured that variable.
+
+ * "git status" will not be "git commit --dry-run".  This change does not
+   affect you if you run the command without pathspec.
+
+   Nobody sane found the current behaviour of "git status Makefile" useful
+   nor meaningful, and it confused users.  "git commit --dry-run" has been
+   provided as a way to get the current behaviour of this command since
+   1.6.5.
+
+ * "git diff" traditionally treated various "ignore whitespace" options
+   only as a way to filter the patch output.  "git diff --exit-code -b"
+   exited with non-zero status even if all changes were about changing the
+   amount of whitespace and nothing else.  and "git diff -b" showed the
+   "diff --git" header line for such a change without patch text.
+
+   In 1.7.0, the "ignore whitespaces" will affect the semantics of the
+   diff operation itself.  A change that does not affect anything but
+   whitespaces will be reported with zero exit status when run with
+   --exit-code, and there will not be "diff --git" header for such a
+   change.
+
+
+Updates since v1.6.5
+--------------------
+
+(subsystems)
+
+ * various gitk updates including use of themed widgets under Tk 8.5,
+   Japanese translation, a fix to a bug when running "gui blame" from
+   a subdirectory, etc.
+
+ * various git-gui updates including new translations, wm states fixes,
+   Tk bug workaround after quitting, improved heuristics to trigger gc,
+   etc.
+
+ * various git-svn updates.
+
+ * "git fetch" over http learned a new mode that is different from the
+   traditional "dumb commit walker".
+
+(portability)
+
+ * imap-send can be built on mingw port.
+
+(performance)
+
+ * "git diff -B" has smaller memory footprint.
+
+(usability, bells and whistles)
+
+ * The object replace mechanism can be bypassed with --no-replace-objects
+   global option given to the "git" program.
+
+ * In configuration files, a few variables that name paths can begin with ~/
+   and ~username/ and they are expanded as expected.
+
+ * "git subcmd -h" now shows short usage help for many more subcommands.
+
+ * "git bisect reset" can reset to an arbitrary commit.
+
+ * "git checkout frotz" when there is no local branch "frotz" but there
+   is only one remote tracking branch "frotz" is taken as a request to
+   start the named branch at the corresponding remote tracking branch.
+
+ * "git commit -c/-C/--amend" can be told with a new "--reset-author" option
+   to ignore authorship information in the commit it is taking the message
+   from.
+
+ * "git describe" can be told to add "-dirty" suffix with "--dirty" option.
+
+ * "git diff" learned --submodule option to show a list of one-line logs
+   instead of differences between the commit object names.
+
+ * "git diff" learned to honor diff.color.func configuration to paint
+   function name hint printed on the hunk header "@@ -j,k +l,m @@" line
+   in the specified color.
+
+ * "git fetch" learned --all and --multiple options, to run fetch from
+   many repositories, and --prune option to remove remote tracking
+   branches that went stale.  These make "git remote update" and "git
+   remote prune" less necessary (there is no plan to remove "remote
+   update" nor "remote prune", though).
+
+ * "git fsck" by default checks the packfiles (i.e. "--full" is the
+   default); you can turn it off with "git fsck --no-full".
+
+ * "git grep" can use -F (fixed strings) and -i (ignore case) together.
+
+ * import-tars contributed fast-import frontend learned more types of
+   compressed tarballs.
+
+ * "git instaweb" knows how to talk with mod_cgid to apache2.
+
+ * "git log --decorate" shows the location of HEAD as well.
+
+ * "git log" and "git rev-list" learned to take revs and pathspecs from
+   the standard input with the new "--stdin" option.
+
+ * "--pretty=format" option to "log" family of commands learned:
+
+   . to wrap text with the "%w()" specifier.
+   . to show reflog information with "%g[sdD]" specifier.
+
+ * "git notes" command to annotate existing commits.
+
+ * "git merge" (and "git pull") learned --ff-only option to make it fail
+   if the merge does not result in a fast-forward.
+
+ * "git mergetool" learned to use p4merge.
+
+ * "git rebase -i" learned "reword" that acts like "edit" but immediately
+   starts an editor to tweak the log message without returning control to
+   the shell, which is done by "edit" to give an opportunity to tweak the
+   contents.
+
+ * "git send-email" can be told with "--envelope-sender=auto" to use the
+   same address as "From:" address as the envelope sender address.
+
+ * "git send-email" will issue a warning when it defaults to the
+   --chain-reply-to behaviour without being told by the user and
+   instructs to prepare for the change of the default in 1.7.0 release.
+
+ * In "git submodule add <repository> <path>", <path> is now optional and
+   inferred from <repository> the same way "git clone <repository>" does.
+
+ * "git svn" learned to read SVN 1.5+ and SVK merge tickets.
+
+ * "git svn" learned to recreate empty directories tracked only by SVN.
+
+ * "gitweb" can optionally render its "blame" output incrementally (this
+   requires JavaScript on the client side).
+
+ * Author names shown in gitweb output are links to search commits by the
+   author.
+
+Fixes since v1.6.5
+------------------
+
+All of the fixes in v1.6.5.X maintenance series are included in this
+release, unless otherwise noted.
diff --git a/Documentation/RelNotes/1.7.0.1.txt b/Documentation/RelNotes/1.7.0.1.txt
new file mode 100644
index 0000000000..8ff5bcada8
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.1.txt
@@ -0,0 +1,35 @@
+Git v1.7.0.1 Release Notes
+==========================
+
+Fixes since v1.7.0
+------------------
+
+ * In a freshly created repository "rev-parse HEAD^0" complained that
+   it is dangling symref, even though "rev-parse HEAD" didn't.
+
+ * "git show :no-such-name" tried to access the index without bounds
+   check, leading to a potential segfault.
+
+ * Message from "git cherry-pick" was harder to read and use than necessary
+   when it stopped due to conflicting changes.
+
+ * We referred to ".git/refs/" throughout the documentation when we
+   meant to talk about abstract notion of "ref namespace".  Because
+   people's repositories often have packed refs these days, this was
+   confusing.
+
+ * "git diff --output=/path/that/cannot/be/written" did not correctly
+   error out.
+
+ * "git grep -e -pattern-that-begin-with-dash paths..." could not be
+   spelled as "git grep -- -pattern-that-begin-with-dash paths..." which
+   would be a GNU way to use "--" as "end of options".
+
+ * "git grep" compiled with threading support tried to access an
+   uninitialized mutex on boxes with a single CPU.
+
+ * "git stash pop -q --index" failed because the unnecessary --index
+   option was propagated to "git stash drop" that is internally run at the
+   end.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.0.2.txt b/Documentation/RelNotes/1.7.0.2.txt
new file mode 100644
index 0000000000..73ed2b5278
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.2.txt
@@ -0,0 +1,40 @@
+Git v1.7.0.2 Release Notes
+==========================
+
+Fixes since v1.7.0.1
+--------------------
+
+ * GIT_PAGER was not honored consistently by some scripted Porcelains, most
+   notably "git am".
+
+ * updating working tree files after telling git to add them to the
+   index and while it is still working created garbage object files in
+   the repository without diagnosing it as an error.
+
+ * "git bisect -- pathspec..." did not diagnose an error condition properly when
+   the simplification with given pathspec made the history empty.
+
+ * "git rev-list --cherry-pick A...B" now has an obvious optimization when the
+   histories haven't diverged (i.e. when one end is an ancestor of the other).
+
+ * "git diff --quiet -w" did not work as expected.
+
+ * "git fast-import" didn't work with a large input, as it lacked support
+   for producing the pack index in v2 format.
+
+ * "git imap-send" didn't use CRLF line endings over the imap protocol
+   when storing its payload to the draft box, violating RFC 3501.
+
+ * "git log --format='%w(x,y,z)%b'" and friends that rewrap message
+   has been optimized for utf-8 payload.
+
+ * Error messages generated on the receiving end did not come back to "git
+   push".
+
+ * "git status" in 1.7.0 lacked the optimization we used to have in 1.6.X series
+   to speed up scanning of large working tree.
+
+ * "gitweb" did not diagnose parsing errors properly while reading its configuration
+   file.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.0.3.txt b/Documentation/RelNotes/1.7.0.3.txt
new file mode 100644
index 0000000000..3b355737c0
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.3.txt
@@ -0,0 +1,34 @@
+Git v1.7.0.3 Release Notes
+==========================
+
+Fixes since v1.7.0.2
+--------------------
+
+ * Object files are created in a more ACL friendly way in repositories
+   where group permission is ACL controlled.
+
+ * "git add -i" didn't handle a deleted path very well.
+
+ * "git blame" padded line numbers with one extra SP when the total number
+   of lines was one less than multiple of ten due to an off-by-one error.
+
+ * "git fetch --all/--multi" used to discard information for remotes that
+   are fetched earlier.
+
+ * "git log --author=me --grep=it" tried to find commits that have "it"
+   or are written by "me", instead of the ones that have "it" _and_ are
+   written by "me".
+
+ * "git log -g branch" misbehaved when there was no entries in the reflog
+   for the named branch.
+
+ * "git mailinfo" (hence "git am") incorrectly removed initial indent from
+   paragraphs.
+
+ * "git prune" and "git reflog" (hence "git gc" as well) didn't honor
+   an instruction never to expire by setting gc.reflogexpire to never.
+
+ * "git push" misbehaved when branch.<name>.merge was configured without
+   matching branch.<name>.remote.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.0.4.txt b/Documentation/RelNotes/1.7.0.4.txt
new file mode 100644
index 0000000000..cf7f60e60d
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.4.txt
@@ -0,0 +1,27 @@
+Git v1.7.0.4 Release Notes
+==========================
+
+Fixes since v1.7.0.3
+--------------------
+
+ * Optimized ntohl/htonl on big-endian machines were broken.
+
+ * Color values given to "color.<cmd>.<slot>" configuration can now have
+   more than one attributes (e.g. "bold ul").
+
+ * "git add -u nonexistent-path" did not complain.
+
+ * "git apply --whitespace=fix" didn't work well when an early patch in
+   a patch series adds trailing blank lines and a later one depended on
+   such a block of blank lines at the end.
+
+ * "git fast-export" didn't check error status and stop when marks file
+   cannot be opened.
+
+ * "git format-patch --ignore-if-in-upstream" gave unwarranted errors
+   when the range was empty, instead of silently finishing.
+
+ * "git remote prune" did not detect remote tracking refs that became
+   dangling correctly.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.0.5.txt b/Documentation/RelNotes/1.7.0.5.txt
new file mode 100644
index 0000000000..3149c91b7b
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.5.txt
@@ -0,0 +1,26 @@
+Git v1.7.0.5 Release Notes
+==========================
+
+Fixes since v1.7.0.4
+--------------------
+
+ * "git daemon" failed to compile on platforms without sockaddr_storage type.
+
+ * Output from "git rev-list --pretty=oneline" was unparsable when a
+   commit did not have any message, which is abnormal but possible in a
+   repository converted from foreign scm.
+
+ * "git stash show <commit-that-is-not-a-stash>" gave an error message
+   that was not so useful.  Reworded the message to "<it> is not a
+   stash".
+
+ * Python scripts in contrib/ area now start with "#!/usr/bin/env python"
+   to honor user's PATH.
+
+ * "git imap-send" used to mistake any line that begins with "From " as a
+   message separator in format-patch output.
+
+ * Smart http server backend failed to report an internal server error and
+   infinitely looped instead after output pipe was closed.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.0.6.txt b/Documentation/RelNotes/1.7.0.6.txt
new file mode 100644
index 0000000000..b2852b67d0
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.6.txt
@@ -0,0 +1,13 @@
+Git v1.7.0.6 Release Notes
+==========================
+
+Fixes since v1.7.0.5
+--------------------
+
+ * "git diff --stat" used "int" to count the size of differences,
+   which could result in overflowing.
+
+ * "git rev-list --abbrev-commit" defaulted to 40-byte abbreviations, unlike
+   newer tools in the git toolset.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.0.7.txt b/Documentation/RelNotes/1.7.0.7.txt
new file mode 100644
index 0000000000..d0cb7ca7e2
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.7.txt
@@ -0,0 +1,16 @@
+Git v1.7.0.7 Release Notes
+==========================
+
+Fixes since v1.7.0.6
+--------------------
+
+ * "make NO_CURL=NoThanks install" was broken.
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git config --path conf.var" to attempt to expand a variable conf.var
+   that uses "~/" short-hand segfaulted when $HOME environment variable
+   was not set.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.0.8.txt b/Documentation/RelNotes/1.7.0.8.txt
new file mode 100644
index 0000000000..7f05b48e17
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.8.txt
@@ -0,0 +1,10 @@
+Git v1.7.0.8 Release Notes
+==========================
+
+This is primarily to backport support for the new "add.ignoreErrors"
+name given to the existing "add.ignore-errors" configuration variable.
+
+The next version, Git 1.7.4, and future versions, will support both
+old and incorrect name and the new corrected name, but without this
+backport, users who want to use the new name "add.ignoreErrors" in
+their repositories cannot use older versions of Git.
diff --git a/Documentation/RelNotes/1.7.0.9.txt b/Documentation/RelNotes/1.7.0.9.txt
new file mode 100644
index 0000000000..bfb3166387
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.9.txt
@@ -0,0 +1,8 @@
+Git v1.7.0.9 Release Notes
+==========================
+
+Fixes since v1.7.0.8
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
diff --git a/Documentation/RelNotes/1.7.0.txt b/Documentation/RelNotes/1.7.0.txt
new file mode 100644
index 0000000000..0bb8c0b2a2
--- /dev/null
+++ b/Documentation/RelNotes/1.7.0.txt
@@ -0,0 +1,214 @@
+Git v1.7.0 Release Notes
+========================
+
+Notes on behaviour change
+-------------------------
+
+ * "git push" into a branch that is currently checked out (i.e. pointed at by
+   HEAD in a repository that is not bare) is refused by default.
+
+   Similarly, "git push $there :$killed" to delete the branch $killed
+   in a remote repository $there, when $killed branch is the current
+   branch pointed at by its HEAD, will be refused by default.
+
+   Setting the configuration variables receive.denyCurrentBranch and
+   receive.denyDeleteCurrent to 'ignore' in the receiving repository
+   can be used to override these safety features.
+
+ * "git send-email" does not make deep threads by default when sending a
+   patch series with more than two messages.  All messages will be sent
+   as a reply to the first message, i.e. cover letter.
+
+   It has been possible already to configure send-email to send "shallow thread"
+   by setting sendemail.chainreplyto configuration variable to false.  The
+   only thing this release does is to change the default when you haven't
+   configured that variable.
+
+ * "git status" is not "git commit --dry-run" anymore.  This change does
+   not affect you if you run the command without argument.
+
+ * "git diff" traditionally treated various "ignore whitespace" options
+   only as a way to filter the patch output.  "git diff --exit-code -b"
+   exited with non-zero status even if all changes were about changing the
+   amount of whitespace and nothing else;  and "git diff -b" showed the
+   "diff --git" header line for such a change without patch text.
+
+   In this release, the "ignore whitespaces" options affect the semantics
+   of the diff operation.  A change that does not affect anything but
+   whitespaces is reported with zero exit status when run with
+   --exit-code, and there is no "diff --git" header for such a change.
+
+ * External diff and textconv helpers are now executed using the shell.
+   This makes them consistent with other programs executed by git, and
+   allows you to pass command-line parameters to the helpers. Any helper
+   paths containing spaces or other metacharacters now need to be
+   shell-quoted.  The affected helpers are GIT_EXTERNAL_DIFF in the
+   environment, and diff.*.command and diff.*.textconv in the config
+   file.
+
+ * The --max-pack-size argument to 'git repack', 'git pack-objects', and
+   'git fast-import' was assuming the provided size to be expressed in MiB,
+   unlike the corresponding config variable and other similar options accepting
+   a size value.  It is now expecting a size expressed in bytes, with a possible
+   unit suffix of 'k', 'm', or 'g'.
+
+Updates since v1.6.6
+--------------------
+
+(subsystems)
+
+ * "git fast-import" updates; adds "option" and "feature" to detect the
+   mismatch between fast-import and the frontends that produce the input
+   stream.
+
+ * "git svn" support of subversion "merge tickets" and miscellaneous fixes.
+
+ * "gitk" and "git gui" translation updates.
+
+ * "gitweb" updates (code clean-up, load checking etc.)
+
+(portability)
+
+ * Some more MSVC portability patches for msysgit port.
+
+ * Minimum Pthreads emulation for msysgit port.
+
+(performance)
+
+ * More performance improvement patches for msysgit port.
+
+(usability, bells and whistles)
+
+ * More commands learned "--quiet" and "--[no-]progress" options.
+
+ * Various commands given by the end user (e.g. diff.type.textconv,
+   and GIT_EDITOR) can be specified with command line arguments.  E.g. it
+   is now possible to say "[diff "utf8doc"] textconv = nkf -w".
+
+ * "sparse checkout" feature allows only part of the work tree to be
+   checked out.
+
+ * HTTP transfer can use authentication scheme other than basic
+   (i.e./e.g. digest).
+
+ * Switching from a version of superproject that used to have a submodule
+   to another version of superproject that no longer has it did not remove
+   the submodule directory when it should (namely, when you are not
+   interested in the submodule at all and didn't clone/checkout).
+
+ * A new attribute conflict-marker-size can be used to change the size of
+   the conflict markers from the default 7; this is useful when tracked
+   contents (e.g. git-merge documentation) have strings that resemble the
+   conflict markers.
+
+ * A new syntax "<branch>@{upstream}" can be used on the command line to
+   substitute the name of the "upstream" of the branch.  Missing branch
+   defaults to the current branch, so "git fetch && git merge @{upstream}"
+   will be equivalent to "git pull".
+
+ * "git am --resolved" has a synonym "git am --continue".
+
+ * "git branch --set-upstream" can be used to update the (surprise!) upstream,
+   i.e. where the branch is supposed to pull and merge from (or rebase onto).
+
+ * "git checkout A...B" is a way to detach HEAD at the merge base between
+   A and B.
+
+ * "git checkout -m path" to reset the work tree file back into the
+   conflicted state works even when you already ran "git add path" and
+   resolved the conflicts.
+
+ * "git commit --date='<date>'" can be used to override the author date
+   just like "git commit --author='<name> <email>'" can be used to
+   override the author identity.
+
+ * "git commit --no-status" can be used to omit the listing of the index
+   and the work tree status in the editor used to prepare the log message.
+
+ * "git commit" warns a bit more aggressively until you configure user.email,
+   whose default value almost always is not (and fundamentally cannot be)
+   what you want.
+
+ * "git difftool" has been extended to make it easier to integrate it
+   with gitk.
+
+ * "git fetch --all" can now be used in place of "git remote update".
+
+ * "git grep" does not rely on external grep anymore.  It can use more than
+   one thread to accelerate the operation.
+
+ * "git grep" learned "--quiet" option.
+
+ * "git log" and friends learned "--glob=heads/*" syntax that is a more
+   flexible way to complement "--branches/--tags/--remotes".
+
+ * "git merge" learned to pass options specific to strategy-backends.  E.g.
+
+    - "git merge -Xsubtree=path/to/directory" can be used to tell the subtree
+      strategy how much to shift the trees explicitly.
+
+    - "git merge -Xtheirs" can be used to auto-merge as much as possible,
+      while discarding your own changes and taking merged version in
+      conflicted regions.
+
+ * "git push" learned "git push origin --delete branch", a syntactic sugar
+   for "git push origin :branch".
+
+ * "git push" learned "git push --set-upstream origin forker:forkee" that
+   lets you configure your "forker" branch to later pull from "forkee"
+   branch at "origin".
+
+ * "git rebase --onto A...B" means the history is replayed on top of the
+   merge base between A and B.
+
+ * "git rebase -i" learned new action "fixup" that squashes the change
+   but does not affect existing log message.
+
+ * "git rebase -i" also learned --autosquash option that is useful
+   together with the new "fixup" action.
+
+ * "git remote" learned set-url subcommand that updates (surprise!) url
+   for an existing remote nickname.
+
+ * "git rerere" learned "forget path" subcommand.  Together with "git
+   checkout -m path" it will be useful when you recorded a wrong
+   resolution.
+
+ * Use of "git reset --merge" has become easier when resetting away a
+   conflicted mess left in the work tree.
+
+ * "git rerere" had rerere.autoupdate configuration but there was no way
+   to countermand it from the command line; --no-rerere-autoupdate option
+   given to "merge", "revert", etc. fixes this.
+
+ * "git status" learned "-s(hort)" output format.
+
+(developers)
+
+ * The infrastructure to build foreign SCM interface has been updated.
+
+ * Many more commands are now built-in.
+
+ * THREADED_DELTA_SEARCH is no more.  If you build with threads, delta
+   compression will always take advantage of it.
+
+Fixes since v1.6.6
+------------------
+
+All of the fixes in v1.6.6.X maintenance series are included in this
+release, unless otherwise noted.
+
+ * "git branch -d branch" used to refuse deleting the branch even when
+   the branch is fully merged to its upstream branch if it is not merged
+   to the current branch.  It now deletes it in such a case.
+
+ * "filter-branch" command incorrectly said --prune-empty and --filter-commit
+   were incompatible; the latter should be read as --commit-filter.
+
+ * When using "git status" or asking "git diff" to compare the work tree
+   with something, they used to consider that a checked-out submodule with
+   uncommitted changes is not modified; this could cause people to forget
+   committing these changes in the submodule before committing in the
+   superproject. They now consider such a change as a modification and
+   "git diff" will append a "-dirty" to the work tree side when generating
+   patch output or when used with the --submodule option.
diff --git a/Documentation/RelNotes/1.7.1.1.txt b/Documentation/RelNotes/1.7.1.1.txt
new file mode 100644
index 0000000000..3f6b3148a3
--- /dev/null
+++ b/Documentation/RelNotes/1.7.1.1.txt
@@ -0,0 +1,96 @@
+Git v1.7.1.1 Release Notes
+==========================
+
+Fixes since v1.7.1
+------------------
+
+ * Authentication over http transport can now be made lazily, in that the
+   request can first go to a URL without username, get a 401 response and
+   then the client will ask for the username to use.
+
+ * We used to mistakenly think "../work" is a subdirectory of the current
+   directory when we are in "../work-xyz".
+
+ * The attribute mechanism now allows an entry that uses an attribute
+   macro that set/unset one attribute, immediately followed by an
+   overriding setting; this makes attribute macros much easier to use.
+
+ * We didn't recognize timezone "Z" as a synonym for "UTC" (75b37e70).
+
+ * In 1.7.0, read-tree and user commands that use the mechanism such as
+   checkout and merge were fixed to handle switching between branches one
+   of which has a file while the other has a directory at the same path
+   correctly even when there are some "confusing" pathnames in them.  But
+   the algorithm used for this fix was suboptimal and had a terrible
+   performance degradation especially in larger trees.
+
+ * "git am -3" did not show diagnosis when the patch in the message was corrupt.
+
+ * After "git apply --whitespace=fix" removed trailing blank lines in an
+   patch in a patch series, it failed to apply later patches that depend
+   on the presence of such blank lines.
+
+ * "git bundle --stdin" segfaulted.
+
+ * "git checkout" and "git rebase" overwrote paths that are marked "assume
+   unchanged".
+
+ * "git commit --amend" on a commit with an invalid author-name line that
+   lacks the display name didn't work.
+
+ * "git describe" did not tie-break tags that point at the same commit
+   correctly; newer ones are preferred by paying attention to the
+   tagger date now.
+
+ * "git diff" used to tell underlying xdiff machinery to work very hard to
+   minimize the output, but this often was spending too many extra cycles
+   for very little gain.
+
+ * "git diff --color" did not paint extended diff headers per line
+   (i.e. the coloring escape sequence didn't end at the end of line),
+   which confused "less -R".
+
+ * "git fetch" over HTTP verifies the downloaded packfiles more robustly.
+
+ * The memory usage by "git index-pack" (run during "git fetch" and "git
+   push") got leaner.
+
+ * "GIT_DIR=foo.git git init --bare bar.git" created foo.git instead of bar.git.
+
+ * "git log --abbrev=$num --format='%h' ignored --abbrev=$num.
+
+ * "git ls-files ../out/side/cwd" refused to work.
+
+ * "git merge --log" used to replace the custom message given by "-m" with
+   the shortlog, instead of appending to it.
+
+ * "git notes copy" without any other argument segfaulted.
+
+ * "git pull" accepted "--dry-run", gave it to underlying "git fetch" but
+   ignored the option itself, resulting in a bogus attempt to merge
+   unrelated commit.
+
+ * "git rebase" did not faithfully reproduce a malformed author ident, that
+   is often seen in a repository converted from foreign SCMs.
+
+ * "git reset --hard" started from a wrong directory and a working tree in
+   a nonstandard location is in use got confused.
+
+ * "git send-email" lacked a way to specify the domainname used in the
+   EHLO/HELO exchange, causing rejected connection from picky servers.
+   It learned --smtp-domain option to solve this issue.
+
+ * "git send-email" did not declare a content-transfer-encoding and
+   content-type even when its payload needs to be sent in 8-bit.
+
+ * "git show -C -C" and other corner cases lost diff metainfo output
+   in 1.7.0.
+
+ * "git stash" incorrectly lost paths in the working tree that were
+   previously removed from the index.
+
+ * "git status" stopped refreshing the index by mistake in 1.7.1.
+
+ * "git status" showed excess "hints" even when advice.statusHints is set to false.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.1.2.txt b/Documentation/RelNotes/1.7.1.2.txt
new file mode 100644
index 0000000000..61ba14e262
--- /dev/null
+++ b/Documentation/RelNotes/1.7.1.2.txt
@@ -0,0 +1,28 @@
+Git v1.7.1.2 Release Notes
+==========================
+
+Fixes since v1.7.1.1
+--------------------
+
+ * "git commit" did not honor GIT_REFLOG_ACTION environment variable, resulting
+   reflog messages for cherry-pick and revert actions to be recorded as "commit".
+
+ * "git clone/fetch/pull" issued an incorrect error message when a ref and
+   a symref that points to the ref were updated at the same time.  This
+   obviously would update them to the same value, and should not result in
+   an error condition.
+
+ * "git diff" inside a tree with many pathnames that have certain
+   characters has become very slow in 1.7.0 by mistake.
+
+ * "git rev-parse --parseopt --stop-at-non-option" did not stop at non option
+   when --keep-dashdash was in effect.
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git config --path conf.var" to attempt to expand a variable conf.var
+   that uses "~/" short-hand segfaulted when $HOME environment variable
+   was not set.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.1.3.txt b/Documentation/RelNotes/1.7.1.3.txt
new file mode 100644
index 0000000000..5b18518449
--- /dev/null
+++ b/Documentation/RelNotes/1.7.1.3.txt
@@ -0,0 +1,10 @@
+Git v1.7.1.3 Release Notes
+==========================
+
+This is primarily to backport support for the new "add.ignoreErrors"
+name given to the existing "add.ignore-errors" configuration variable.
+
+The next version, Git 1.7.4, and future versions, will support both
+old and incorrect name and the new corrected name, but without this
+backport, users who want to use the new name "add.ignoreErrors" in
+their repositories cannot use older versions of Git.
diff --git a/Documentation/RelNotes/1.7.1.4.txt b/Documentation/RelNotes/1.7.1.4.txt
new file mode 100644
index 0000000000..7c734b4f7b
--- /dev/null
+++ b/Documentation/RelNotes/1.7.1.4.txt
@@ -0,0 +1,8 @@
+Git v1.7.1.4 Release Notes
+==========================
+
+Fixes since v1.7.1.3
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
diff --git a/Documentation/RelNotes/1.7.1.txt b/Documentation/RelNotes/1.7.1.txt
new file mode 100644
index 0000000000..9d89fedb36
--- /dev/null
+++ b/Documentation/RelNotes/1.7.1.txt
@@ -0,0 +1,89 @@
+Git v1.7.1 Release Notes
+========================
+
+Updates since v1.7.0
+--------------------
+
+ * Eric Raymond is the maintainer of updated CIAbot scripts, in contrib/.
+
+ * gitk updates.
+
+ * Some commands (e.g. svn and http interfaces) that interactively ask
+   for a password can be told to use an external program given via
+   GIT_ASKPASS.
+
+ * Conflict markers that lead the common ancestor in diff3-style output
+   now have a label, which hopefully would help third-party tools that
+   expect one.
+
+ * Comes with an updated bash-completion script.
+
+ * "git am" learned "--keep-cr" option to handle inputs that are
+   a mixture of changes to files with and without CRLF line endings.
+
+ * "git cvsimport" learned -R option to leave revision mapping between
+   CVS revisions and resulting git commits.
+
+ * "git diff --submodule" notices and describes dirty submodules.
+
+ * "git for-each-ref" learned %(symref), %(symref:short) and %(flag)
+   tokens.
+
+ * "git hash-object --stdin-paths" can take "--no-filters" option now.
+
+ * "git init" can be told to look at init.templatedir configuration
+   variable (obviously that has to come from either /etc/gitconfig or
+   $HOME/.gitconfig).
+
+ * "git grep" learned "--no-index" option, to search inside contents that
+   are not managed by git.
+
+ * "git grep" learned --color=auto/always/never.
+
+ * "git grep" learned to paint filename and line-number in colors.
+
+ * "git log -p --first-parent -m" shows one-parent diff for merge
+   commits, instead of showing combined diff.
+
+ * "git merge-file" learned to use custom conflict marker size and also
+   to use the "union merge" behaviour.
+
+ * "git notes" command has been rewritten in C and learned many commands
+   and features to help you carry notes forward across rebases and amends.
+
+ * "git request-pull" identifies the commit the request is relative to in
+   a more readable way.
+
+ * "git reset" learned "--keep" option that lets you discard commits
+   near the tip while preserving your local changes in a way similar
+   to how "git checkout branch" does.
+
+ * "git status" notices and describes dirty submodules.
+
+ * "git svn" should work better when interacting with repositories
+   with CRLF line endings.
+
+ * "git imap-send" learned to support CRAM-MD5 authentication.
+
+ * "gitweb" installation procedure can use "minified" js/css files
+   better.
+
+ * Various documentation updates.
+
+Fixes since v1.7.0
+------------------
+
+All of the fixes in v1.7.0.X maintenance series are included in this
+release, unless otherwise noted.
+
+ * "git add frotz/nitfol" did not complain when the entire frotz/ directory
+   was ignored.
+
+ * "git diff --stat" used "int" to count the size of differences,
+   which could result in overflowing.
+
+ * "git rev-list --pretty=oneline" didn't terminate a record with LF for
+   commits without any message.
+
+ * "git rev-list --abbrev-commit" defaulted to 40-byte abbreviations, unlike
+   newer tools in the git toolset.
diff --git a/Documentation/RelNotes/1.7.10.1.txt b/Documentation/RelNotes/1.7.10.1.txt
new file mode 100644
index 0000000000..71a86cb7c6
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.1.txt
@@ -0,0 +1,78 @@
+Git v1.7.10.1 Release Notes
+===========================
+
+Additions since v1.7.10
+-----------------------
+
+Localization message files for Danish and German have been added.
+
+
+Fixes since v1.7.10
+-------------------
+
+ * "git add -p" is not designed to deal with unmerged paths but did
+   not exclude them and tried to apply funny patches only to fail.
+
+ * "git blame" started missing quite a few changes from the origin
+   since we stopped using the diff minimization by default in v1.7.2
+   era.
+
+ * When PATH contains an unreadable directory, alias expansion code
+   did not kick in, and failed with an error that said "git-subcmd"
+   was not found.
+
+ * "git clean -d -f" (not "-d -f -f") is supposed to protect nested
+   working trees of independent git repositories that exist in the
+   current project working tree from getting removed, but the
+   protection applied only to such working trees that are at the
+   top-level of the current project by mistake.
+
+ * "git commit --author=$name" did not tell the name that was being
+   recorded in the resulting commit to hooks, even though it does do
+   so when the end user overrode the authorship via the
+   "GIT_AUTHOR_NAME" environment variable.
+
+ * When "git commit --template F" errors out because the user did not
+   touch the message, it claimed that it aborts due to "empty
+   message", which was utterly wrong.
+
+ * The regexp configured with diff.wordregex was incorrectly reused
+   across files.
+
+ * An age-old corner case bug in combine diff (only triggered with -U0
+   and the hunk at the beginning of the file needs to be shown) has
+   been fixed.
+
+ * Rename detection logic used to match two empty files as renames
+   during merge-recursive, leading to unnatural mismerges.
+
+ * The parser in "fast-import" did not diagnose ":9" style references
+   that is not followed by required SP/LF as an error.
+
+ * When "git fetch" encounters repositories with too many references,
+   the command line of "fetch-pack" that is run by a helper
+   e.g. remote-curl, may fail to hold all of them. Now such an
+   internal invocation can feed the references through the standard
+   input of "fetch-pack".
+
+ * "git fetch" that recurses into submodules on demand did not check
+   if it needs to go into submodules when non branches (most notably,
+   tags) are fetched.
+
+ * "log -p --graph" used with "--stat" had a few formatting error.
+
+ * Running "notes merge --commit" failed to perform correctly when run
+   from any directory inside $GIT_DIR/.  When "notes merge" stops with
+   conflicts, $GIT_DIR/NOTES_MERGE_WORKTREE is the place a user edits
+   to resolve it.
+
+ * The 'push to upstream' implementation was broken in some corner
+   cases. "git push $there" without refspec, when the current branch
+   is set to push to a remote different from $there, used to push to
+   $there using the upstream information to a remote unrelated to
+   $there.
+
+ * Giving "--continue" to a conflicted "rebase -i" session skipped a
+   commit that only results in changes to submodules.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.2.txt b/Documentation/RelNotes/1.7.10.2.txt
new file mode 100644
index 0000000000..7a7e9d6fd1
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.2.txt
@@ -0,0 +1,85 @@
+Git v1.7.10.2 Release Notes
+===========================
+
+Fixes since v1.7.10.1
+---------------------
+
+ * The test scaffolding for git-daemon was flaky.
+
+ * The test scaffolding for fast-import was flaky.
+
+ * The filesystem boundary was not correctly reported when .git directory
+   discovery stopped at a mount point.
+
+ * HTTP transport that requires authentication did not work correctly when
+   multiple connections are used simultaneously.
+
+ * Minor memory leak during unpack_trees (hence "merge" and "checkout"
+   to check out another branch) has been plugged.
+
+ * In the older days, the header "Conflicts:" in "cherry-pick" and "merge"
+   was separated by a blank line from the list of paths that follow for
+   readability, but when "merge" was rewritten in C, we lost it by
+   mistake. Remove the newline from "cherry-pick" to make them match
+   again.
+
+ * The command line parser choked "git cherry-pick $name" when $name can
+   be both revision name and a pathname, even though $name can never be a
+   path in the context of the command.
+
+ * The "include.path" facility in the configuration mechanism added in
+   1.7.10 forgot to interpret "~/path" and "~user/path" as it should.
+
+ * "git config --rename-section" to rename an existing section into a
+   bogus one did not check the new name.
+
+ * The "diff --no-index" codepath used limited-length buffers, risking
+   pathnames getting truncated.  Update it to use the strbuf API.
+
+ * The report from "git fetch" said "new branch" even for a non branch
+   ref.
+
+ * The http-backend (the server side of the smart http transfer) used
+   to overwrite GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL with the
+   value obtained from REMOTE_USER unconditionally, making it
+   impossible for the server side site-specific customization to use
+   different identity sources to affect the names logged. It now uses
+   REMOTE_USER only as a fallback value.
+
+ * "log --graph" was not very friendly with "--stat" option and its
+   output had line breaks at wrong places.
+
+ * Octopus merge strategy did not reduce heads that are recorded in the
+   final commit correctly.
+
+ * "git push" over smart-http lost progress output a few releases ago;
+   this release resurrects it.
+
+ * The error and advice messages given by "git push" when it fails due
+   to non-ff were not very helpful to new users; it has been broken
+   into three cases, and each is given a separate advice message.
+
+ * The insn sheet given by "rebase -i" did not make it clear that the
+   insn lines can be re-ordered to affect the order of the commits in
+   the resulting history.
+
+ * "git repack" used to write out unreachable objects as loose objects
+   when repacking, even if such loose objects will immediately pruned
+   due to its age.
+
+ * A contrib script "rerere-train" did not work out of the box unless
+   user futzed with her $PATH.
+
+ * "git rev-parse --show-prefix" used to emit nothing when run at the
+   top-level of the working tree, but now it gives a blank line.
+
+ * The i18n of error message "git stash save" was not properly done.
+
+ * "git submodule" used a sed script that some platforms mishandled.
+
+ * When using a Perl script on a system where "perl" found on user's
+   $PATH could be ancient or otherwise broken, we allow builders to
+   specify the path to a good copy of Perl with $PERL_PATH.  The
+   gitweb test forgot to use that Perl when running its test.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.3.txt b/Documentation/RelNotes/1.7.10.3.txt
new file mode 100644
index 0000000000..703fbf1d60
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.3.txt
@@ -0,0 +1,43 @@
+Git v1.7.10.3 Release Notes
+===========================
+
+Fixes since v1.7.10.2
+---------------------
+
+ * The message file for German translation has been updated a bit.
+
+ * Running "git checkout" on an unborn branch used to corrupt HEAD.
+
+ * When checking out another commit from an already detached state, we
+   used to report all commits that are not reachable from any of the
+   refs as lossage, but some of them might be reachable from the new
+   HEAD, and there is no need to warn about them.
+
+ * Some time ago, "git clone" lost the progress output for its
+   "checkout" phase; when run without any "--quiet" option, it should
+   give progress to the lengthy operation.
+
+ * The directory path used in "git diff --no-index", when it recurses
+   down, was broken with a recent update after v1.7.10.1 release.
+
+ * "log -z --pretty=tformat:..." did not terminate each record with
+   NUL.  The fix is not entirely correct when the output also asks for
+   --patch and/or --stat, though.
+
+ * The DWIM behaviour for "log --pretty=format:%gd -g" was somewhat
+   broken and gave undue precedence to configured log.date, causing
+   "git stash list" to show "stash@{time stamp string}".
+
+ * "git status --porcelain" ignored "--branch" option by mistake.  The
+   output for "git status --branch -z" was also incorrect and did not
+   terminate the record for the current branch name with NUL as asked.
+
+ * When a submodule repository uses alternate object store mechanism,
+   some commands that were started from the superproject did not
+   notice it and failed with "No such object" errors.  The subcommands
+   of "git submodule" command that recursed into the submodule in a
+   separate process were OK; only the ones that cheated and peeked
+   directly into the submodule's repository from the primary process
+   were affected.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.4.txt b/Documentation/RelNotes/1.7.10.4.txt
new file mode 100644
index 0000000000..57597f2bf3
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.4.txt
@@ -0,0 +1,29 @@
+Git v1.7.10.4 Release Notes
+===========================
+
+Fixes since v1.7.10.3
+---------------------
+
+ * The message file for Swedish translation has been updated a bit.
+
+ * A name taken from mailmap was copied into an internal buffer
+   incorrectly and could overrun the buffer if it is too long.
+
+ * A malformed commit object that has a header line chomped in the
+   middle could kill git with a NULL pointer dereference.
+
+ * An author/committer name that is a single character was mishandled
+   as an invalid name by mistake.
+
+ * The progress indicator for a large "git checkout" was sent to
+   stderr even if it is not a terminal.
+
+ * "git grep -e '$pattern'", unlike the case where the patterns are
+   read from a file, did not treat individual lines in the given
+   pattern argument as separate regular expressions as it should.
+
+ * When "git rebase" was given a bad commit to replay the history on,
+   its error message did not correctly give the command line argument
+   it had trouble parsing.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.10.5.txt b/Documentation/RelNotes/1.7.10.5.txt
new file mode 100644
index 0000000000..4db1770e38
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.5.txt
@@ -0,0 +1,12 @@
+Git v1.7.10.5 Release Notes
+===========================
+
+Fixes since v1.7.10.4
+---------------------
+
+ * "git fast-export" did not give a readable error message when the
+   same mark erroneously appeared twice in the --import-marks input.
+
+ * "git rebase -p" used to pay attention to rebase.autosquash which
+    was wrong.  "git rebase -p -i" should, but "git rebase -p" by
+    itself should not.
diff --git a/Documentation/RelNotes/1.7.10.txt b/Documentation/RelNotes/1.7.10.txt
new file mode 100644
index 0000000000..58100bf04e
--- /dev/null
+++ b/Documentation/RelNotes/1.7.10.txt
@@ -0,0 +1,219 @@
+Git v1.7.10 Release Notes
+=========================
+
+Compatibility Notes
+-------------------
+
+ * From this release on, the "git merge" command in an interactive
+   session will start an editor when it automatically resolves the
+   merge for the user to explain the resulting commit, just like the
+   "git commit" command does when it wasn't given a commit message.
+
+   If you have a script that runs "git merge" and keeps its standard
+   input and output attached to the user's terminal, and if you do not
+   want the user to explain the resulting merge commits, you can
+   export GIT_MERGE_AUTOEDIT environment variable set to "no", like
+   this:
+
+	#!/bin/sh
+	GIT_MERGE_AUTOEDIT=no
+	export GIT_MERGE_AUTOEDIT
+
+   to disable this behavior (if you want your users to explain their
+   merge commits, you do not have to do anything).  Alternatively, you
+   can give the "--no-edit" option to individual invocations of the
+   "git merge" command if you know everybody who uses your script has
+   Git v1.7.8 or newer.
+
+ * The "--binary/-b" options to "git am" have been a no-op for quite a
+   while and were deprecated in mid 2008 (v1.6.0).  When you give these
+   options to "git am", it will now warn and ask you not to use them.
+
+ * When you do not tell which branches and tags to push to the "git
+   push" command in any way, the command used "matching refs" rule to
+   update remote branches and tags with branches and tags with the
+   same name you locally have.  In future versions of Git, this will
+   change to push out only your current branch according to either the
+   "upstream" or the "current" rule.  Although "upstream" may be more
+   powerful once the user understands Git better, the semantics
+   "current" gives is simpler and easier to understand for beginners
+   and may be a safer and better default option.  We haven't decided
+   yet which one to switch to.
+
+
+Updates since v1.7.9
+--------------------
+
+UI, Workflows & Features
+
+ * various "gitk" updates.
+   - show the path to the top level directory in the window title
+   - update preference edit dialog
+   - display file list correctly when directories are given on command line
+   - make "git-describe" output in the log message into a clickable link
+   - avoid matching the UNIX timestamp part when searching all fields
+   - give preference to symbolic font names like sans & monospace
+   - allow comparing two commits using a mark
+   - "gitk" honors log.showroot configuration.
+
+ * Teams for localizing the messages from the Porcelain layer of
+   commands are starting to form, thanks to Jiang Xin who volunteered
+   to be the localization coordinator.  Translated messages for
+   simplified Chinese, Swedish and Portuguese are available.
+
+ * The configuration mechanism learned an "include" facility; an
+   assignment to the include.path pseudo-variable causes the named
+   file to be included in-place when Git looks up configuration
+   variables.
+
+ * A content filter (clean/smudge) used to be just a way to make the
+   recorded contents "more useful", and allowed to fail; a filter can
+   now optionally be marked as "required".
+
+ * Options whose names begin with "--no-" (e.g. the "--no-verify"
+   option of the "git commit" command) can be negated by omitting
+   "no-" from its name, e.g. "git commit --verify".
+
+ * "git am" learned to pass "-b" option to underlying "git mailinfo", so
+   that a bracketed string other than "PATCH" at the beginning can be kept.
+
+ * "git clone" learned "--single-branch" option to limit cloning to a
+   single branch (surprise!); tags that do not point into the history
+   of the branch are not fetched.
+
+ * "git clone" learned to detach the HEAD in the resulting repository
+   when the user specifies a tag with "--branch" (e.g., "--branch=v1.0").
+   Clone also learned to print the usual "detached HEAD" advice in such
+   a case, similar to "git checkout v1.0".
+
+ * When showing a patch while ignoring whitespace changes, the context
+   lines are taken from the postimage, in order to make it easier to
+   view the output.
+
+ * "git diff --stat" learned to adjust the width of the output on
+   wider terminals, and give more columns to pathnames as needed.
+
+ * "diff-highlight" filter (in contrib/) was updated to produce more
+   aesthetically pleasing output.
+
+ * "fsck" learned "--no-dangling" option to omit dangling object
+   information.
+
+ * "git log -G" and "git log -S" learned to pay attention to the "-i"
+   option.  With "-i", "log -G" ignores the case when finding patch
+   hunks that introduce or remove a string that matches the given
+   pattern.  Similarly with "-i", "log -S" ignores the case when
+   finding the commit the given block of text appears or disappears
+   from the file.
+
+ * "git merge" in an interactive session learned to spawn the editor
+   by default to let the user edit the auto-generated merge message,
+   to encourage people to explain their merges better. Legacy scripts
+   can export GIT_MERGE_AUTOEDIT=no to retain the historical behavior.
+   Both "git merge" and "git pull" can be given --no-edit from the
+   command line to accept the auto-generated merge message.
+
+ * The advice message given when the user didn't give enough clue on
+   what to merge to "git pull" and "git merge" has been updated to
+   be more concise and easier to understand.
+
+ * "git push" learned the "--prune" option, similar to "git fetch".
+
+ * The whole directory that houses a top-level superproject managed by
+   "git submodule" can be moved to another place.
+
+ * "git symbolic-ref" learned the "--short" option to abbreviate the
+   refname it shows unambiguously.
+
+ * "git tag --list" can be given "--points-at <object>" to limit its
+   output to those that point at the given object.
+
+ * "gitweb" allows intermediate entries in the directory hierarchy
+   that leads to a project to be clicked, which in turn shows the
+   list of projects inside that directory.
+
+ * "gitweb" learned to read various pieces of information for the
+   repositories lazily, instead of reading everything that could be
+   needed (including the ones that are not necessary for a specific
+   task).
+
+ * Project search in "gitweb" shows the substring that matched in the
+   project name and description highlighted.
+
+ * HTTP transport learned to authenticate with a proxy if needed.
+
+ * A new script "diffall" is added to contrib/; it drives an
+   external tool to perform a directory diff of two Git revisions
+   in one go, unlike "difftool" that compares one file at a time.
+
+Foreign Interface
+
+ * Improved handling of views, labels and branches in "git-p4" (in contrib).
+
+ * "git-p4" (in contrib) suffered from unnecessary merge conflicts when
+   p4 expanded the embedded $RCS$-like keywords; it can be now told to
+   unexpand them.
+
+ * Some "git-svn" updates.
+
+ * "vcs-svn"/"svn-fe" learned to read dumps with svn-deltas and
+   support incremental imports.
+
+ * "git difftool/mergetool" learned to drive DeltaWalker.
+
+Performance
+
+ * Unnecessary calls to parse_object() "git upload-pack" makes in
+   response to "git fetch", have been eliminated, to help performance
+   in repositories with excessive number of refs.
+
+Internal Implementation (please report possible regressions)
+
+ * Recursive call chains in "git index-pack" to deal with long delta
+   chains have been flattened, to reduce the stack footprint.
+
+ * Use of add_extra_ref() API is now gone, to make it possible to
+   cleanly restructure the overall refs API.
+
+ * The command line parser of "git pack-objects" now uses parse-options
+   API.
+
+ * The test suite supports the new "test_pause" helper function.
+
+ * Parallel to the test suite, there is a beginning of performance
+   benchmarking framework.
+
+ * t/Makefile is adjusted to prevent newer versions of GNU make from
+   running tests in seemingly random order.
+
+ * The code to check if a path points at a file beyond a symbolic link
+   has been restructured to be thread-safe.
+
+ * When pruning directories that has become empty during "git prune"
+   and "git prune-packed", call closedir() that iterates over a
+   directory before rmdir() it.
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.9
+------------------
+
+Unless otherwise noted, all the fixes since v1.7.9 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * Build with NO_PERL_MAKEMAKER was broken and Git::I18N did not work
+   with versions of Perl older than 5.8.3.
+   (merge 5eb660e ab/perl-i18n later to maint).
+
+ * "git tag -s" honored "gpg.program" configuration variable since
+   1.7.9, but "git tag -v" and "git verify-tag" didn't.
+   (merge a2c2506 az/verify-tag-use-gpg-config later to maint).
+
+ * "configure" script learned to take "--with-sane-tool-path" from the
+   command line to record SANE_TOOL_PATH (used to avoid broken platform
+   tools in /usr/bin) in config.mak.autogen.  This may be useful for
+   people on Solaris who have saner tools outside /usr/xpg[46]/bin.
+
+ * zsh port of bash completion script needed another workaround.
diff --git a/Documentation/RelNotes/1.7.11.1.txt b/Documentation/RelNotes/1.7.11.1.txt
new file mode 100644
index 0000000000..577eccaacd
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.1.txt
@@ -0,0 +1,9 @@
+Git v1.7.11.1 Release Notes
+===========================
+
+Fixes since v1.7.11
+-------------------
+
+ * The cross links in the HTML version of manual pages were broken.
+
+Also contains minor typofixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.11.2.txt b/Documentation/RelNotes/1.7.11.2.txt
new file mode 100644
index 0000000000..f0cfd02d6f
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.2.txt
@@ -0,0 +1,53 @@
+Git v1.7.11.2 Release Notes
+===========================
+
+Fixes since v1.7.11.1
+---------------------
+
+ * On Cygwin, the platform pread(2) is not thread safe, just like our
+   own compat/ emulation, and cannot be used in the index-pack
+   program.  Makefile variable NO_THREAD_SAFE_PREAD can be defined to
+   avoid use of this function in a threaded program.
+
+ * "git add" allows adding a regular file to the path where a
+   submodule used to exist, but "git update-index" does not allow an
+   equivalent operation to Porcelain writers.
+
+ * "git archive" incorrectly computed the header checksum; the symptom
+   was observed only when using pathnames with hi-bit set.
+
+ * "git blame" did not try to make sure that the abbreviated commit
+   object names in its output are unique.
+
+ * Running "git bundle verify" on a bundle that records a complete
+   history said "it requires these 0 commits".
+
+ * "git clone --single-branch" to clone a single branch did not limit
+   the cloning to the specified branch.
+
+ * "git diff --no-index" did not correctly handle relative paths and
+   did not correctly give exit codes when run under "--quiet" option.
+
+ * "git diff --no-index" did not work with pagers correctly.
+
+ * "git diff COPYING HEAD:COPYING" gave a nonsense error message that
+   claimed that the tree-ish HEAD did not have COPYING in it.
+
+ * When "git log" gets "--simplify-merges/by-decoration" together with
+   "--first-parent", the combination of these options makes the
+   simplification logic to use in-core commit objects that haven't
+   been examined for relevance, either producing incorrect result or
+   taking too long to produce any output.  Teach the simplification
+   logic to ignore commits that the first-parent traversal logic
+   ignored when both are in effect to work around the issue.
+
+ * "git ls-files --exclude=t -i" did not consider anything under t/ as
+   excluded, as it did not pay attention to exclusion of leading paths
+   while walking the index.  Other two users of excluded() are also
+   updated.
+
+ * "git request-pull $url dev" when the tip of "dev" branch was tagged
+   with "ext4-for-linus" used the contents from the tag in the output
+   but still asked the "dev" branch to be pulled, not the tag.
+
+Also contains minor typofixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.11.3.txt b/Documentation/RelNotes/1.7.11.3.txt
new file mode 100644
index 0000000000..64494f89d9
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.3.txt
@@ -0,0 +1,53 @@
+Git v1.7.11.3 Release Notes
+===========================
+
+Fixes since v1.7.11.3
+---------------------
+
+ * The error message from "git push $there :bogo" (and its equivalent
+   "git push $there --delete bogo") mentioned that we tried and failed
+   to guess what ref is being deleted based on the LHS of the refspec,
+   which we don't.
+
+ * A handful of files and directories we create had tighter than
+   necessary permission bits when the user wanted to have group
+   writability (e.g. by setting "umask 002").
+
+ * "commit --amend" used to refuse amending a commit with an empty log
+   message, with or without "--allow-empty-message".
+
+ * "git commit --amend --only --" was meant to allow "Clever" people to
+   rewrite the commit message without making any change even when they
+   have already changes for the next commit added to their index, but
+   it never worked as advertised since it was introduced in 1.3.0 era.
+
+ * Even though the index can record pathnames longer than 1<<12 bytes,
+   in some places we were not comparing them in full, potentially
+   replacing index entries instead of adding.
+
+ * "git show"'s auto-walking behaviour was an unreliable and
+   unpredictable hack; it now behaves just like "git log" does when it
+   walks.
+
+ * "git diff", "git status" and anything that internally uses the
+   comparison machinery was utterly broken when the difference
+   involved a file with "-" as its name.  This was due to the way "git
+   diff --no-index" was incorrectly bolted on to the system, making
+   any comparison that involves a file "-" at the root level
+   incorrectly read from the standard input.
+
+ * We did not have test to make sure "git rebase" without extra options
+   filters out an empty commit in the original history.
+
+ * "git fast-export" produced an input stream for fast-import without
+   properly quoting pathnames when they contain SPs in them.
+
+ * "git checkout --detach", when you are still on an unborn branch,
+   should be forbidden, but it wasn't.
+
+ * Some implementations of Perl terminates "lines" with CRLF even when
+   the script is operating on just a sequence of bytes.  Make sure to
+   use "$PERL_PATH", the version of Perl the user told Git to use, in
+   our tests to avoid unnecessary breakages in tests.
+
+Also contains minor typofixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.11.4.txt b/Documentation/RelNotes/1.7.11.4.txt
new file mode 100644
index 0000000000..3a640c2d4d
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.4.txt
@@ -0,0 +1,31 @@
+Git v1.7.11.4 Release Notes
+===========================
+
+Fixes since v1.7.11.3
+---------------------
+
+ * "$GIT_DIR/COMMIT_EDITMSG" file that is used to hold the commit log
+   message user edits was not documented.
+
+ * The advise() function did not use varargs correctly to format
+   its message.
+
+ * When "git am" failed, old timers knew to check .git/rebase-apply/patch
+   to see what went wrong, but we never told the users about it.
+
+ * "git commit-tree" learned a more natural "-p <parent> <tree>" order
+   of arguments long time ago, but recently forgot it by mistake.
+
+ * "git diff --no-ext-diff" did not output anything for a typechange
+   filepair when GIT_EXTERNAL_DIFF is in effect.
+
+ * In 1.7.9 era, we taught "git rebase" about the raw timestamp format
+   but we did not teach the same trick to "filter-branch", which rolled
+   a similar logic on its own.
+
+ * When "git submodule add" clones a submodule repository, it can get
+   confused where to store the resulting submodule repository in the
+   superproject's .git/ directory when there is a symbolic link in the
+   path to the current directory.
+
+Also contains minor typofixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.11.5.txt b/Documentation/RelNotes/1.7.11.5.txt
new file mode 100644
index 0000000000..0a2ed855c5
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.5.txt
@@ -0,0 +1,36 @@
+Git v1.7.11.5 Release Notes
+===========================
+
+Fixes since v1.7.11.4
+---------------------
+
+ * The Makefile rule to create assembly output (primarily for
+   debugging purposes) did not create it next to the source.
+
+ * The code to avoid mistaken attempt to add the object directory
+   itself as its own alternate could read beyond end of a string while
+   comparison.
+
+ * On some architectures, "block-sha1" did not compile correctly
+   when compilers inferred alignment guarantees from our source we
+   did not intend to make.
+
+ * When talking to a remote running ssh on IPv6 enabled host, whose
+   address is spelled as "[HOST]:PORT", we did not parse the address
+   correctly and failed to connect.
+
+ * git-blame.el (in compat/) have been updated to use Elisp more
+   correctly.
+
+ * "git checkout <branchname>" to come back from a detached HEAD state
+   incorrectly computed reachability of the detached HEAD, resulting
+   in unnecessary warnings.
+
+ * "git mergetool" did not support --tool-help option to give the list
+   of supported backends, like "git difftool" does.
+
+ * "git grep" stopped spawning an external "grep" long time ago, but a
+   duplicated test to check internal and external "grep" was left
+   behind.
+
+Also contains minor typofixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.11.6.txt b/Documentation/RelNotes/1.7.11.6.txt
new file mode 100644
index 0000000000..ba7d3c3966
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.6.txt
@@ -0,0 +1,84 @@
+Git v1.7.11.6 Release Notes
+===========================
+
+Fixes since v1.7.11.5
+---------------------
+
+ * "ciabot" script (in contrib/) has been updated with extensive
+   documentation.
+
+ * "git foo" errored out with "Not a directory" when the user had a
+   non-directory on $PATH, and worse yet it masked an alias "foo" from
+   running.
+
+ * When the user exports a non-default IFS without HT, scripts that
+   rely on being able to parse "ls-files -s | while read a b c..."
+   started to fail.  Protect them from such a misconfiguration.
+
+ * When the user gives an argument that can be taken as both a
+   revision name and a pathname without disambiguating with "--", we
+   used to give a help message "Use '--' to separate".  The message
+   has been clarified to show where that '--' goes on the command
+   line.
+
+ * Documentation for the configuration file format had a confusing
+   example.
+
+ * Older parts of the documentation described as if having a regular
+   file in .git/refs/ hierarchy were the only way to have branches and
+   tags, which is not true for quite some time.
+
+ * It was generally understood that "--long-option"s to many of our
+   subcommands can be abbreviated to the unique prefix, but it was not
+   easy to find it described for new readers of the documentation set.
+
+ * The "--topo-order", "--date-order" (and the lack of either means
+   the default order) options to "rev-list" and "log" family of
+   commands were poorly described in the documentation.
+
+ * "git commit --amend" let the user edit the log message and then
+   died when the human-readable committer name was given
+   insufficiently by getpwent(3).
+
+ * The exit status code from "git config" was way overspecified while
+   being incorrect.  The implementation has been updated to give the
+   documented status for a case that was documented, and introduce a
+   new code for "all other errors".
+
+ * The output from "git diff -B" for a file that ends with an
+   incomplete line did not put "\ No newline..." on a line of its own.
+
+ * "git diff" had a confusion between taking data from a path in the
+   working tree and taking data from an object that happens to have
+   name 0{40} recorded in a tree.
+
+ * The "--rebase" option to "git pull" can be abbreviated to "-r",
+   but we didn't document it.
+
+ * When "git push" triggered the automatic gc on the receiving end, a
+   message from "git prune" that said it was removing cruft leaked to
+   the standard output, breaking the communication protocol.
+
+ * The reflog entries left by "git rebase" and "git rebase -i" were
+   inconsistent (the interactive one gave an abbreviated object name).
+
+ * "git send-email" did not unquote encoded words that appear on the
+   header correctly, and lost "_" from strings.
+
+ * "git stash apply/pop" did not trigger "rerere" upon conflicts
+   unlike other mergy operations.
+
+ * "git submodule <cmd> path" did not error out when the path to the
+   submodule was misspelt.
+
+ * "git submodule update -f" did not update paths in the working tree
+   that has local changes.
+   (merge 01d4721 sz/submodule-force-update later to maint).
+
+ * "gitweb" when used with PATH_INFO failed to notice directories with
+   SP (and other characters that need URL-style quoting) in them.
+
+ * Fallback 'getpass' implementation made unportable use of stdio API.
+
+ * A utility shell function test_seq has been added as a replacement
+   for the 'seq' utility found on some platforms.
diff --git a/Documentation/RelNotes/1.7.11.7.txt b/Documentation/RelNotes/1.7.11.7.txt
new file mode 100644
index 0000000000..e743a2a8e4
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.7.txt
@@ -0,0 +1,46 @@
+Git v1.7.11.7 Release Notes
+===========================
+
+Fixes since v1.7.11.6
+---------------------
+
+ * The synopsis said "checkout [-B branch]" to make it clear the
+   branch name is a parameter to the option, but the heading for the
+   option description was "-B::", not "-B branch::", making the
+   documentation misleading.
+
+ * Git ships with a fall-back regexp implementation for platforms with
+   buggy regexp library, but it was easy for people to keep using their
+   platform regexp.  A new test has been added to check this.
+
+ * "git apply -p0" did not parse pathnames on "diff --git" line
+   correctly.  This caused patches that had pathnames in no other
+   places to be mistakenly rejected (most notably, binary patch that
+   does not rename nor change mode).  Textual patches, renames or mode
+   changes have preimage and postimage pathnames in different places
+   in a form that can be parsed unambiguously and did not suffer from
+   this problem.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+   references" nor "Reload" did not update what is shown as the
+   contents of it, when the user overwrote the tag with "git tag -f".
+
+ * "git for-each-ref" did not correctly support more than one --sort
+   option.
+
+ * "git log .." errored out saying it is both rev range and a path
+   when there is no disambiguating "--" is on the command line.
+   Update the command line parser to interpret ".." as a path in such
+   a case.
+
+ * Pushing to smart HTTP server with recent Git fails without having
+   the username in the URL to force authentication, if the server is
+   configured to allow GET anonymously, while requiring authentication
+   for POST.
+
+ * "git show --format='%ci'" did not give timestamp correctly for
+   commits created without human readable name on "committer" line.
+   (merge e27ddb6 jc/maint-ident-missing-human-name later to maint).
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+   wasn't.
diff --git a/Documentation/RelNotes/1.7.11.txt b/Documentation/RelNotes/1.7.11.txt
new file mode 100644
index 0000000000..15b954ca4b
--- /dev/null
+++ b/Documentation/RelNotes/1.7.11.txt
@@ -0,0 +1,139 @@
+Git v1.7.11 Release Notes
+=========================
+
+Updates since v1.7.10
+---------------------
+
+UI, Workflows & Features
+
+ * A new mode for push, "simple", which is a cross between "current"
+   and "upstream", has been introduced. "git push" without any refspec
+   will push the current branch out to the same name at the remote
+   repository only when it is set to track the branch with the same
+   name over there.  The plan is to make this mode the new default
+   value when push.default is not configured.
+
+ * A couple of commands learned the "--column" option to produce
+   columnar output.
+
+ * A third-party tool "git subtree" is distributed in contrib/
+
+ * A remote helper that acts as a proxy and caches ssl session for the
+   https:// transport is added to the contrib/ area.
+
+ * Error messages given when @{u} is used for a branch without its
+   upstream configured have been clarified.
+
+ * Even with the "-q"uiet option, "checkout" used to report setting up
+   tracking.  Also "branch" learned the "-q"uiet option to squelch
+   informational message.
+
+ * Your build platform may support hardlinks but you may prefer not to
+   use them, e.g. when installing to DESTDIR to make a tarball and
+   untarring on a filesystem that has poor support for hardlinks.
+   There is a Makefile option NO_INSTALL_HARDLINKS for you.
+
+ * The smart-http backend used to always override GIT_COMMITTER_*
+   variables with REMOTE_USER and REMOTE_ADDR, but these variables are
+   now preserved when set.
+
+ * "git am" learned the "--include" option, which is an opposite of
+   existing the "--exclude" option.
+
+ * When "git am -3" needs to fall back to an application of the patch
+   to a synthesized preimage followed by a 3-way merge, the paths that
+   needed such treatment are now reported to the end user, so that the
+   result in them can be eyeballed with extra care.
+
+ * The output from "diff/log --stat" used to always allocate 4 columns
+   to show the number of modified lines, but not anymore.
+
+ * "git difftool" learned the "--dir-diff" option to spawn external
+   diff tools that can compare two directory hierarchies at a time
+   after populating two temporary directories, instead of running an
+   instance of the external tool once per a file pair.
+
+ * The "fmt-merge-msg" command learned to list the primary contributors
+   involved in the side topic you are merging in a comment in the merge
+   commit template.
+
+ * "git rebase" learned to optionally keep commits that do not
+   introduce any change in the original history.
+
+ * "git push --recurse-submodules" learned to optionally look into the
+   histories of submodules bound to the superproject and push them
+   out.
+
+ * A 'snapshot' request to "gitweb" honors If-Modified-Since: header,
+   based on the commit date.
+
+ * "gitweb" learned to highlight the patch it outputs even more.
+
+Foreign Interface
+
+ * "git svn" used to die with unwanted SIGPIPE when talking with an HTTP
+   server that uses keep-alive.
+
+ * "git svn" learned to use platform specific authentication
+   providers, e.g. gnome-keyring, kwallet, etc.
+
+ * "git p4" has been moved out of the contrib/ area and has seen more
+   work on importing labels as tags from (and exporting tags as labels
+   to) p4.
+
+Performance and Internal Implementation (please report possible regressions)
+
+ * Bash completion script (in contrib/) have been cleaned up to make
+   future work on it simpler.
+
+ * An experimental "version 4" format of the index file has been
+   introduced to reduce on-disk footprint and I/O overhead.
+
+ * "git archive" learned to produce its output without reading the
+   blob object it writes out in memory in its entirety.
+
+ * "git index-pack" that runs when fetching or pushing objects to
+   complete the packfile on the receiving end learned to use multiple
+   threads to do its job when available.
+
+ * The code to compute hash values for lines used by the internal diff
+   engine was optimized on little-endian machines, using the same
+   trick the kernel folks came up with.
+
+ * "git apply" had some memory leaks plugged.
+
+ * Setting up a revision traversal with many starting points was
+   inefficient as these were placed in a date-order priority queue
+   one-by-one.  Now they are collected in the queue unordered first,
+   and sorted immediately before getting used.
+
+ * More lower-level commands learned to use the streaming API to read
+   from the object store without keeping everything in core.
+
+ * The weighting parameters to suggestion command name typo have been
+   tweaked, so that "git tags" will suggest "tag?" and not "stage?".
+
+ * Because "sh" on the user's PATH may be utterly broken on some
+   systems, run-command API now uses SHELL_PATH, not /bin/sh, when
+   spawning an external command (not applicable to Windows port).
+
+ * The API to iterate over the refs/ hierarchy has been tweaked to
+   allow walking only a subset of it more efficiently.
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.10
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.10 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * "git submodule init" used to report "registered for path ..."
+   even for submodules that were registered earlier.
+   (cherry-pick c1c259e jl/submodule-report-new-path-once later to maint).
+
+ * "git diff --stat" used to fully count a binary file with modified
+   execution bits whose contents is unmodified, which was not quite
+   right.
diff --git a/Documentation/RelNotes/1.7.12.1.txt b/Documentation/RelNotes/1.7.12.1.txt
new file mode 100644
index 0000000000..b8f04af19f
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.1.txt
@@ -0,0 +1,134 @@
+Git 1.7.12.1 Release Notes
+==========================
+
+Fixes since v1.7.12
+-------------------
+
+ * "git apply -p0" did not parse pathnames on "diff --git" line
+   correctly.  This caused patches that had pathnames in no other
+   places to be mistakenly rejected (most notably, binary patch that
+   does not rename nor change mode).  Textual patches, renames or mode
+   changes have preimage and postimage pathnames in different places
+   in a form that can be parsed unambiguously and did not suffer from
+   this problem.
+
+ * "git cherry-pick A C B" used to replay changes in A and then B and
+   then C if these three commits had committer timestamps in that
+   order, which is not what the user who said "A C B" naturally
+   expects.
+
+ * "git commit --amend" let the user edit the log message and then
+   died when the human-readable committer name was given
+   insufficiently by getpwent(3).
+
+ * Some capabilities were asked by fetch-pack even when upload-pack
+   did not advertise that they are available.  fetch-pack has been
+   fixed not to do so.
+
+ * "git diff" had a confusion between taking data from a path in the
+   working tree and taking data from an object that happens to have
+   name 0{40} recorded in a tree.
+
+ * "git for-each-ref" did not correctly support more than one --sort
+   option.
+
+ * "git log .." errored out saying it is both rev range and a path
+   when there is no disambiguating "--" is on the command line.
+   Update the command line parser to interpret ".." as a path in such
+   a case.
+
+ * The "--topo-order", "--date-order" (and the lack of either means
+   the default order) options to "rev-list" and "log" family of
+   commands were poorly described in the documentation.
+
+ * "git prune" without "-v" used to warn about leftover temporary
+   files (which is an indication of an earlier aborted operation).
+
+ * Pushing to smart HTTP server with recent Git fails without having
+   the username in the URL to force authentication, if the server is
+   configured to allow GET anonymously, while requiring authentication
+   for POST.
+
+ * The reflog entries left by "git rebase" and "git rebase -i" were
+   inconsistent (the interactive one gave an abbreviated object name).
+
+ * When "git push" triggered the automatic gc on the receiving end, a
+   message from "git prune" that said it was removing cruft leaked to
+   the standard output, breaking the communication protocol.
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+   wasn't.
+
+ * "git show --format='%ci'" did not give timestamp correctly for
+   commits created without human readable name on "committer" line.
+
+ * "git send-email" did not unquote encoded words that appear on the
+   header correctly, and lost "_" from strings.
+
+ * The interactive prompt "git send-email" gives was error prone. It
+   asked "What e-mail address do you want to use?" with the address it
+   guessed (correctly) the user would want to use in its prompt,
+   tempting the user to say "y". But the response was taken as "No,
+   please use 'y' as the e-mail address instead", which is most
+   certainly not what the user meant.
+
+ * "gitweb" when used with PATH_INFO failed to notice directories with
+   SP (and other characters that need URL-style quoting) in them.
+
+ * When the user gives an argument that can be taken as both a
+   revision name and a pathname without disambiguating with "--", we
+   used to give a help message "Use '--' to separate".  The message
+   has been clarified to show where that '--' goes on the command
+   line.
+
+ * When the user exports a non-default IFS without HT, scripts that
+   rely on being able to parse "ls-files -s | while read a b c..."
+   started to fail.  Protect them from such a misconfiguration.
+
+ * The attribute system may be asked for a path that itself or its
+   leading directories no longer exists in the working tree, and it is
+   fine if we cannot open .gitattribute file in such a case.  Failure
+   to open per-directory .gitattributes with error status other than
+   ENOENT and ENOTDIR should be diagnosed, but it wasn't.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+   references" nor "Reload" did not update what is shown as the
+   contents of it, when the user overwrote the tag with "git tag -f".
+
+ * "ciabot" script (in contrib/) has been updated with extensive
+   documentation.
+
+ * "git-jump" script (in contrib/) did not work well when
+   diff.noprefix or diff.mnemonicprefix is in effect.
+
+ * Older parts of the documentation described as if having a regular
+   file in .git/refs/ hierarchy were the only way to have branches and
+   tags, which is not true for quite some time.
+
+ * A utility shell function test_seq has been added as a replacement
+   for the 'seq' utility found on some platforms.
+
+ * Compatibility wrapper to learn the maximum number of file
+   descriptors we can open around sysconf(_SC_OPEN_MAX) and
+   getrlimit(RLIMIT_NO_FILE) has been introduced for portability.
+
+ * We used curl_easy_strerror() without checking version of cURL,
+   breaking the build for versions before curl 7.12.0.
+
+ * Code to work around MacOS X UTF-8 gotcha has been cleaned up.
+
+ * Fallback 'getpass' implementation made unportable use of stdio API.
+
+ * The "--rebase" option to "git pull" can be abbreviated to "-r",
+   but we didn't document it.
+
+ * It was generally understood that "--long-option"s to many of our
+   subcommands can be abbreviated to the unique prefix, but it was not
+   easy to find it described for new readers of the documentation set.
+
+ * The synopsis said "checkout [-B branch]" to make it clear the
+   branch name is a parameter to the option, but the heading for the
+   option description was "-B::", not "-B branch::", making the
+   documentation misleading.
+
+Also contains numerous documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.2.txt b/Documentation/RelNotes/1.7.12.2.txt
new file mode 100644
index 0000000000..69255745e6
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.2.txt
@@ -0,0 +1,40 @@
+Git 1.7.12.2 Release Notes
+==========================
+
+Fixes since v1.7.12.1
+---------------------
+
+ * When "git am" is fed an input that has multiple "Content-type: ..."
+   header, it did not grok charset= attribute correctly.
+
+ * Even during a conflicted merge, "git blame $path" always meant to
+   blame uncommitted changes to the "working tree" version; make it
+   more useful by showing cleanly merged parts as coming from the other
+   branch that is being merged.
+
+ * "git blame MAKEFILE" run in a history that has "Makefile" but not
+   "MAKEFILE" should say "No such file MAKEFILE in HEAD", but got
+   confused on a case insensitive filesystem and failed to do so.
+
+ * "git fetch --all", when passed "--no-tags", did not honor the
+   "--no-tags" option while fetching from individual remotes (the same
+   issue existed with "--tags", but combination "--all --tags" makes
+   much less sense than "--all --no-tags").
+
+ * "git log/diff/format-patch --stat" showed the "N line(s) added"
+   comment in user's locale and caused careless submitters to send
+   patches with such a line in them to projects whose project language
+   is not their language, mildly irritating others. Localization to
+   the line has been disabled for now.
+
+ * "git log --all-match --grep=A --grep=B" ought to show commits that
+   mention both A and B, but when these three options are used with
+   --author or --committer, it showed commits that mention either A or
+   B (or both) instead.
+
+ * The subcommand to remove the definition of a remote in "git remote"
+   was named "rm" even though all other subcommands were spelled out.
+   Introduce "git remote remove" to remove confusion, and keep "rm" as
+   a backward compatible synonym.
+
+Also contains a handful of documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.3.txt b/Documentation/RelNotes/1.7.12.3.txt
new file mode 100644
index 0000000000..4b822976b8
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.3.txt
@@ -0,0 +1,34 @@
+Git 1.7.12.3 Release Notes
+==========================
+
+Fixes since v1.7.12.2
+---------------------
+
+ * "git am" mishandled a patch attached as application/octet-stream
+   (e.g. not text/*); Content-Transfer-Encoding (e.g. base64) was not
+   honored correctly.
+
+ * It was unclear in the documentation for "git blame" that it is
+   unnecessary for users to use the "--follow" option.
+
+ * A repository created with "git clone --single" had its fetch
+   refspecs set up just like a clone without "--single", leading the
+   subsequent "git fetch" to slurp all the other branches, defeating
+   the whole point of specifying "only this branch".
+
+ * "git fetch" over http had an old workaround for an unlikely server
+   misconfiguration; it turns out that this hurts debuggability of the
+   configuration in general, and has been reverted.
+
+ * "git fetch" over http advertised that it supports "deflate", which
+   is much less common, and did not advertise the more common "gzip" on
+   its Accept-Encoding header.
+
+ * "git receive-pack" (the counterpart to "git push") did not give
+   progress output while processing objects it received to the user
+   when run over the smart-http protocol.
+
+ * "git status" honored the ignore=dirty settings in .gitmodules but
+   "git commit" didn't.
+
+Also contains a handful of documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.4.txt b/Documentation/RelNotes/1.7.12.4.txt
new file mode 100644
index 0000000000..c6da3cc939
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.4.txt
@@ -0,0 +1,23 @@
+Git 1.7.12.4 Release Notes
+==========================
+
+Fixes since v1.7.12.3
+---------------------
+
+ * "git fetch" over the dumb-http revision walker could segfault when
+   curl's multi interface was used.
+
+ * It was possible to give specific paths for "asciidoc" and other
+   tools in the documentation toolchain, but not for "xmlto".
+
+ * "gitweb" did not give the correct committer timezone in its feed
+   output due to a typo.
+
+ * The "-Xours" (and similarly -Xtheirs) backend option to "git
+   merge -s recursive" was ignored for binary files.  Now it is
+   honored.
+
+ * The "binary" synthetic attribute made "diff" to treat the path as
+   binary, but not "merge".
+
+Also contains many documentation updates.
diff --git a/Documentation/RelNotes/1.7.12.txt b/Documentation/RelNotes/1.7.12.txt
new file mode 100644
index 0000000000..010d8c7de4
--- /dev/null
+++ b/Documentation/RelNotes/1.7.12.txt
@@ -0,0 +1,136 @@
+Git v1.7.12 Release Notes
+=========================
+
+Updates since v1.7.11
+---------------------
+
+UI, Workflows & Features
+
+ * Git can be told to normalize pathnames it read from readdir(3) and
+   all arguments it got from the command line into precomposed UTF-8
+   (assuming that they come as decomposed UTF-8), in order to work
+   around issues on Mac OS.
+
+   I think there still are other places that need conversion
+   (e.g. paths that are read from stdin for some commands), but this
+   should be a good first step in the right direction.
+
+ * Per-user $HOME/.gitconfig file can optionally be stored in
+   $HOME/.config/git/config instead, which is in line with XDG.
+
+ * The value of core.attributesfile and core.excludesfile default to
+   $HOME/.config/git/attributes and $HOME/.config/git/ignore respectively
+   when these files exist.
+
+ * Logic to disambiguate abbreviated object names have been taught to
+   take advantage of object types that are expected in the context,
+   e.g. XXXXXX in the "git describe" output v1.2.3-gXXXXXX must be a
+   commit object, not a blob nor a tree.  This will help us prolong
+   the lifetime of abbreviated object names.
+
+ * "git apply" learned to wiggle the base version and perform three-way
+   merge when a patch does not exactly apply to the version you have.
+
+ * Scripted Porcelain writers now have access to the credential API via
+   the "git credential" plumbing command.
+
+ * "git help" used to always default to "man" format even on platforms
+   where "man" viewer is not widely available.
+
+ * "git clone --local $path" started its life as an experiment to
+   optionally use link/copy when cloning a repository on the disk, but
+   we didn't deprecate it after we made the option a no-op to always
+   use the optimization.  The command learned "--no-local" option to
+   turn this off, as a more explicit alternative over use of file://
+   URL.
+
+ * "git fetch" and friends used to say "remote side hung up
+   unexpectedly" when they failed to get response they expect from the
+   other side, but one common reason why they don't get expected
+   response is that the remote repository does not exist or cannot be
+   read. The error message in this case was updated to give better
+   hints to the user.
+
+ * "git help -w $cmd" can show HTML version of documentation for
+   "git-$cmd" by setting help.htmlpath to somewhere other than the
+   default location where the build procedure installs them locally;
+   the variable can even point at a http:// URL.
+
+ * "git rebase [-i] --root $tip" can now be used to rewrite all the
+   history leading to "$tip" down to the root commit.
+
+ * "git rebase -i" learned "-x <cmd>" to insert "exec <cmd>" after
+   each commit in the resulting history.
+
+ * "git status" gives finer classification to various states of paths
+   in conflicted state and offer advice messages in its output.
+
+ * "git submodule" learned to deal with nested submodule structure
+   where a module is contained within a module whose origin is
+   specified as a relative URL to its superproject's origin.
+
+ * A rather heavy-ish "git completion" script has been split to create
+   a separate "git prompting" script, to help lazy-autoloading of the
+   completion part while making prompting part always available.
+
+ * "gitweb" pays attention to various forms of credits that are
+   similar to "Signed-off-by:" lines in the commit objects and
+   highlights them accordingly.
+
+
+Foreign Interface
+
+ * "mediawiki" remote helper (in contrib/) learned to handle file
+   attachments.
+
+ * "git p4" now uses "Jobs:" and "p4 move" when appropriate.
+
+ * vcs-svn has been updated to clean-up compilation, lift 32-bit
+   limitations, etc.
+
+
+Performance, Internal Implementation, etc. (please report possible regressions)
+
+ * Some tests showed false failures caused by a bug in ecryptofs.
+
+ * We no longer use AsciiDoc7 syntax in our documentation and favor a
+   more modern style.
+
+ * "git am --rebasing" codepath was taught to grab authorship, log
+   message and the patch text directly out of existing commits.  This
+   will help rebasing commits that have confusing "diff" output in
+   their log messages.
+
+ * "git index-pack" and "git pack-objects" use streaming API to read
+   from the object store to avoid having to hold a large blob object
+   in-core while they are doing their thing.
+
+ * Code to match paths with exclude patterns learned to avoid calling
+   fnmatch() by comparing fixed leading substring literally when
+   possible.
+
+ * "git log -n 1 -- rarely-touched-path" was spending unnecessary
+   cycles after showing the first change to find the next one, only to
+   discard it.
+
+ * "git svn" got a large-looking code reorganization at the last
+   minute before the code freeze.
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.11
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.11 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
+
+ * "git submodule add" was confused when the superproject did not have
+   its repository in its usual place in the working tree and GIT_DIR
+   and GIT_WORK_TREE was used to access it.
+
+ * "git commit --amend" let the user edit the log message and then died
+   when the human-readable committer name was given insufficiently by
+   getpwent(3).
diff --git a/Documentation/RelNotes/1.7.2.1.txt b/Documentation/RelNotes/1.7.2.1.txt
new file mode 100644
index 0000000000..1103c47a4f
--- /dev/null
+++ b/Documentation/RelNotes/1.7.2.1.txt
@@ -0,0 +1,25 @@
+Git v1.7.2.1 Release Notes
+==========================
+
+Fixes since v1.7.2
+------------------
+
+ * "git instaweb" wasn't useful when your Apache was installed under a
+   name other than apache2 (e.g. "httpd").
+
+ * Similarly, "git web--browse" (invoked by "git help -w") learned that
+   chrome browser is sometimes called google-chrome.
+
+ * An overlong line after ".gitdir: " in a git file caused out of bounds
+   access to an array on the stack.
+
+ * "git config --path conf.var" to attempt to expand a variable conf.var
+   that uses "~/" short-hand segfaulted when $HOME environment variable
+   was not set.
+
+ * Documentation on Cygwin failed to build.
+
+ * The error message from "git pull blarg" when 'blarg' is an unknown
+   remote name has been improved.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.2.2.txt b/Documentation/RelNotes/1.7.2.2.txt
new file mode 100644
index 0000000000..71eb6a8b0a
--- /dev/null
+++ b/Documentation/RelNotes/1.7.2.2.txt
@@ -0,0 +1,22 @@
+Git v1.7.2.2 Release Notes
+==========================
+
+Fixes since v1.7.2.1
+--------------------
+
+ * Object transfer over smart http transport deadlocked the client when
+   the remote HTTP server returned a failure, instead of erroring it out.
+
+ * git-gui honors custom textconv filters when showing diff and blame;
+
+ * git diff --relative=subdir (without the necessary trailing /) did not
+   work well;
+
+ * "git diff-files -p --submodule" was recently broken;
+
+ * "git checkout -b n ':/token'" did not work;
+
+ * "git index-pack" (hence "git fetch/clone/pull/push") enabled the object
+   replacement machinery by mistake (it never should have);
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.2.3.txt b/Documentation/RelNotes/1.7.2.3.txt
new file mode 100644
index 0000000000..610960cfe1
--- /dev/null
+++ b/Documentation/RelNotes/1.7.2.3.txt
@@ -0,0 +1,39 @@
+Git v1.7.2.3 Release Notes
+==========================
+
+Fixes since v1.7.2.2
+--------------------
+
+ * When people try insane things such as delta-compressing 4GiB files, we
+   threw an assertion failure.
+
+ * "git archive" gave the full commit ID for "$Format:%h$".
+
+ * "git fetch --tags" did not fetch tags when remote.<nick>.tagopt was set
+   to --no-tags.  The command line option now overrides the configuration
+   setting.
+
+ * "git for-each-ref --format='%(objectname:short)'" has been completely
+   broken for a long time.
+
+ * "git gc" incorrectly pruned a rerere record that was created long
+   time ago but still is actively and repeatedly used.
+
+ * "git log --follow -M -p" was seriously broken in 1.7.2, reporting
+   assertion failure.
+
+ * Running "git log" with an incorrect option started pager nevertheless,
+   forcing the user to dismiss it.
+
+ * "git rebase" did not work well when the user has diff.renames
+   configuration variable set.
+
+ * An earlier (and rather old) fix to "git rebase" against a rebased
+   upstream broke a more normal, non rebased upstream case rather badly,
+   attempting to re-apply patches that are already accepted upstream.
+
+ * "git submodule sync" forgot to update the superproject's config file
+   when submodule URL changed.
+
+ * "git pack-refs --all --prune" did not remove a directory that has
+   become empty.
diff --git a/Documentation/RelNotes/1.7.2.4.txt b/Documentation/RelNotes/1.7.2.4.txt
new file mode 100644
index 0000000000..f7950a4c04
--- /dev/null
+++ b/Documentation/RelNotes/1.7.2.4.txt
@@ -0,0 +1,10 @@
+Git v1.7.2.4 Release Notes
+==========================
+
+This is primarily to backport support for the new "add.ignoreErrors"
+name given to the existing "add.ignore-errors" configuration variable.
+
+The next version, Git 1.7.4, and future versions, will support both
+old and incorrect name and the new corrected name, but without this
+backport, users who want to use the new name "add.ignoreErrors" in
+their repositories cannot use older versions of Git.
diff --git a/Documentation/RelNotes/1.7.2.5.txt b/Documentation/RelNotes/1.7.2.5.txt
new file mode 100644
index 0000000000..bf976c40db
--- /dev/null
+++ b/Documentation/RelNotes/1.7.2.5.txt
@@ -0,0 +1,8 @@
+Git v1.7.2.5 Release Notes
+==========================
+
+Fixes since v1.7.2.4
+--------------------
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
diff --git a/Documentation/RelNotes/1.7.2.txt b/Documentation/RelNotes/1.7.2.txt
new file mode 100644
index 0000000000..15cf01178c
--- /dev/null
+++ b/Documentation/RelNotes/1.7.2.txt
@@ -0,0 +1,151 @@
+Git v1.7.2 Release Notes
+========================
+
+Updates since v1.7.1
+--------------------
+
+ * core.eol configuration and text/eol attributes are the new way to control
+   the end of line conventions for files in the working tree.
+
+ * core.autocrlf has been made safer - it will now only handle line
+   endings for new files and files that are LF-only in the
+   repository. To normalize content that has been checked in with
+   CRLF, use the new eol/text attributes.
+
+ * The whitespace rules used in "git apply --whitespace" and "git diff"
+   gained a new member in the family (tab-in-indent) to help projects with
+   policy to indent only with spaces.
+
+ * When working from a subdirectory, by default, git does not look for its
+   metadirectory ".git" across filesystems, primarily to help people who
+   have invocations of git in their custom PS1 prompts, as being outside
+   of a git repository would look for ".git" all the way up to the root
+   directory, and NFS mounts are often slow.  DISCOVERY_ACROSS_FILESYSTEM
+   environment variable can be used to tell git not to stop at a
+   filesystem boundary.
+
+ * Usage help messages generated by parse-options library (i.e. most
+   of the Porcelain commands) are sent to the standard output now.
+
+ * ':/<string>' notation to look for a commit now takes regular expression
+   and it is not anchored at the beginning of the commit log message
+   anymore (this is a backward incompatible change).
+
+ * "git" wrapper learned "-c name=value" option to override configuration
+   variable from the command line.
+
+ * Improved portability for various platforms including older SunOS,
+   HP-UX 10/11, AIX, Tru64, etc. and platforms with Python 2.4.
+
+ * The message from "git am -3" has been improved when conflict
+   resolution ended up making the patch a no-op.
+
+ * "git blame" applies the textconv filter to the contents it works
+   on, when available.
+
+ * "git checkout --orphan newbranch" is similar to "-b newbranch" but
+   prepares to create a root commit that is not connected to any existing
+   commit.
+
+ * "git cherry-pick" learned to pick a range of commits
+   (e.g. "cherry-pick A..B" and "cherry-pick --stdin"), so did "git
+   revert"; these do not support the nicer sequencing control "rebase
+   [-i]" has, though.
+
+ * "git cherry-pick" and "git revert" learned --strategy option to specify
+   the merge strategy to be used when performing three-way merges.
+
+ * "git cvsserver" can be told to use pserver; its password file can be
+   stored outside the repository.
+
+ * The output from the textconv filter used by "git diff" can be cached to
+   speed up their reuse.
+
+ * "git diff --word-diff=<mode>" extends the existing "--color-words"
+   option, making it more useful in color-challenged environments.
+
+ * The regexp to detect function headers used by "git diff" for PHP has
+   been enhanced for visibility modifiers (public, protected, etc.) to
+   better support PHP5.
+
+ * "diff.noprefix" configuration variable can be used to implicitly
+   ask for "diff --no-prefix" behaviour.
+
+ * "git for-each-ref" learned "%(objectname:short)" that gives the object
+   name abbreviated.
+
+ * "git format-patch" learned --signature option and format.signature
+   configuration variable to customize the e-mail signature used in the
+   output.
+
+ * Various options to "git grep" (e.g. --count, --name-only) work better
+   with binary files.
+
+ * "git grep" learned "-Ovi" to open the files with hits in your editor.
+
+ * "git help -w" learned "chrome" and "chromium" browsers.
+
+ * "git log --decorate" shows commit decorations in various colours.
+
+ * "git log --follow <path>" follows across copies (it used to only follow
+   renames).  This may make the processing more expensive.
+
+ * "git log --pretty=format:<template>" specifier learned "% <something>"
+   magic that inserts a space only when %<something> expands to a
+   non-empty string; this is similar to "%+<something>" magic, but is
+   useful in a context to generate a single line output.
+
+ * "git notes prune" learned "-n" (dry-run) and "-v" options, similar to
+   what "git prune" has.
+
+ * "git patch-id" can be fed a mbox without getting confused by the
+   signature line in the format-patch output.
+
+ * "git remote" learned "set-branches" subcommand.
+
+ * "git rev-list A..B" learned --ancestry-path option to further limit
+   the result to the commits that are on the ancestry chain between A and
+   B (i.e. commits that are not descendants of A are excluded).
+
+ * "git show -5" is equivalent to "git show --do-walk 5"; this is similar
+   to the update to make "git show master..next" walk the history,
+   introduced in 1.6.4.
+
+ * "git status [-s] --ignored" can be used to list ignored paths.
+
+ * "git status -s -b" shows the current branch in the output.
+
+ * "git status" learned "--ignore-submodules" option.
+
+ * Various "gitweb" enhancements and clean-ups, including syntax
+   highlighting, "plackup" support for instaweb, .fcgi suffix to run
+   it as FastCGI script, etc.
+
+ * The test harness has been updated to produce TAP-friendly output.
+
+ * Many documentation improvement patches are also included.
+
+
+Fixes since v1.7.1
+------------------
+
+All of the fixes in v1.7.1.X maintenance series are included in this
+release, unless otherwise noted.
+
+ * We didn't URL decode "file:///path/to/repo" correctly when path/to/repo
+   had percent-encoded characters (638794c, 9d2e942, ce83eda, 3c73a1d).
+
+ * "git clone" did not configure remote.origin.url correctly for bare
+   clones (df61c889).
+
+ * "git diff --graph" works better with "--color-words" and other options
+   (81fa024..4297c0a).
+
+ * "git diff" could show ambiguous abbreviation of blob object names on
+   its "index" line (3e5a188).
+
+ * "git reset --hard" started from a wrong directory and a working tree in
+   a nonstandard location is in use got confused (560fb6a1).
+
+ * "git read-tree -m A B" used to switch to branch B while retaining
+   local changes added an incorrect cache-tree information (b1f47514).
diff --git a/Documentation/RelNotes/1.7.3.1.txt b/Documentation/RelNotes/1.7.3.1.txt
new file mode 100644
index 0000000000..002c93b961
--- /dev/null
+++ b/Documentation/RelNotes/1.7.3.1.txt
@@ -0,0 +1,14 @@
+Git v1.7.3.1 Release Notes
+==========================
+
+Fixes since v1.7.3
+------------------
+
+ * "git stash show stash@{$n}" was accidentally broken in 1.7.3 ("git
+   stash show" without any argument still worked, though).
+
+ * "git stash branch $branch stash@{$n}" was accidentally broken in
+   1.7.3 and started dropping the named stash even when branch creation
+   failed.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.3.2.txt b/Documentation/RelNotes/1.7.3.2.txt
new file mode 100644
index 0000000000..5c93b85af4
--- /dev/null
+++ b/Documentation/RelNotes/1.7.3.2.txt
@@ -0,0 +1,5 @@
+Git v1.7.3.2 Release Notes
+==========================
+
+This is primarily to push out many documentation fixes accumulated since
+the 1.7.3.1 release.
diff --git a/Documentation/RelNotes/1.7.3.3.txt b/Documentation/RelNotes/1.7.3.3.txt
new file mode 100644
index 0000000000..9b2b2448df
--- /dev/null
+++ b/Documentation/RelNotes/1.7.3.3.txt
@@ -0,0 +1,54 @@
+Git v1.7.3.3 Release Notes
+==========================
+
+In addition to the usual fixes, this release also includes support for
+the new "add.ignoreErrors" name given to the existing "add.ignore-errors"
+configuration variable.
+
+The next version, Git 1.7.4, and future versions, will support both
+old and incorrect name and the new corrected name, but without this
+backport, users who want to use the new name "add.ignoreErrors" in
+their repositories cannot use older versions of Git.
+
+Fixes since v1.7.3.2
+--------------------
+
+ * "git apply" segfaulted when a bogus input is fed to it.
+
+ * Running "git cherry-pick --ff" on a root commit segfaulted.
+
+ * "diff", "blame" and friends incorrectly applied textconv filters to
+   symlinks.
+
+ * Highlighting of whitespace breakage in "diff" output was showing
+   incorrect amount of whitespaces when blank-at-eol is set and the line
+   consisted only of whitespaces and a TAB.
+
+ * "diff" was overly inefficient when trying to find the line to use for
+   the function header (i.e. equivalent to --show-c-function of GNU diff).
+
+ * "git imap-send" depends on libcrypto but our build rule relied on the
+   linker to implicitly link it via libssl, which was wrong.
+
+ * "git merge-file" can be called from within a subdirectory now.
+
+ * "git repack -f" expanded and recompressed non-delta objects in the
+   existing pack, which was wasteful.  Use new "-F" option if you really
+   want to (e.g. when changing the pack.compression level).
+
+ * "git rev-list --format="...%x00..." incorrectly chopped its output
+   at NUL.
+
+ * "git send-email" did not correctly remove duplicate mail addresses from
+   the Cc: header that appear on the To: header.
+
+ * The completion script (in contrib/completion) ignored lightweight tags
+   in __git_ps1().
+
+ * "git-blame" mode (in contrib/emacs) didn't say (require 'format-spec)
+   even though it depends on it; it didn't work with Emacs 22 or older
+   unless Gnus is used.
+
+ * "git-p4" (in contrib/) did not correctly handle deleted files.
+
+Other minor fixes and documentation updates are also included.
diff --git a/Documentation/RelNotes/1.7.3.4.txt b/Documentation/RelNotes/1.7.3.4.txt
new file mode 100644
index 0000000000..e57f7c176d
--- /dev/null
+++ b/Documentation/RelNotes/1.7.3.4.txt
@@ -0,0 +1,45 @@
+Git v1.7.3.4 Release Notes
+==========================
+
+Fixes since v1.7.3.3
+--------------------
+
+ * Smart HTTP transport used to incorrectly retry redirected POST
+   request with GET request.
+
+ * "git apply" did not correctly handle patches that only change modes
+   if told to apply while stripping leading paths with -p option.
+
+ * "git apply" can deal with patches with timezone formatted with a
+   colon between the hours and minutes part (e.g. "-08:00" instead of
+   "-0800").
+
+ * "git checkout" removed an untracked file "foo" from the working
+   tree when switching to a branch that contains a tracked path
+   "foo/bar".  Prevent this, just like the case where the conflicting
+   path were "foo" (c752e7f..7980872d).
+
+ * "git cherry-pick" or "git revert" refused to work when a path that
+   would be modified by the operation was stat-dirty without a real
+   difference in the contents of the file.
+
+ * "git diff --check" reported an incorrect line number for added
+   blank lines at the end of file.
+
+ * "git imap-send" failed to build under NO_OPENSSL.
+
+ * Setting log.decorate configuration variable to "0" or "1" to mean
+   "false" or "true" did not work.
+
+ * "git push" over dumb HTTP protocol did not work against WebDAV
+   servers that did not terminate a collection name with a slash.
+
+ * "git tag -v" did not work with GPG signatures in rfc1991 mode.
+
+ * The post-receive-email sample hook was accidentally broken in 1.7.3.3
+   update.
+
+ * "gitweb" can sometimes be tricked into parrotting a filename argument
+   given in a request without properly quoting.
+
+Other minor fixes and documentation updates are also included.
diff --git a/Documentation/RelNotes/1.7.3.5.txt b/Documentation/RelNotes/1.7.3.5.txt
new file mode 100644
index 0000000000..40f3ba5795
--- /dev/null
+++ b/Documentation/RelNotes/1.7.3.5.txt
@@ -0,0 +1,34 @@
+Git 1.7.3.5 Release Notes
+=========================
+
+ * The xfuncname pattern used by "git diff" and "git grep" to show the
+   last notable line in context were broken for python and ruby for a long
+   time.
+
+ * "git merge" into an unborn branch removed an untracked file "foo" from
+   the working tree when merged branch had "foo" (this fix was already in
+   1.7.3.3 but was omitted from the release notes by mistake).
+
+ * "git status -s" did not quote unprintable characters in paths as
+   documented.
+
+ * "git am --abort" used to always reset to the commit at the beginning of
+   the last "am" invocation that has stopped, losing any unrelated commits
+   that may have been made since then.  Now it refrains from doing so and
+   instead issues a warning.
+
+ * "git blame" incorrectly reused bogusly cached result of textconv
+   filter for files from the working tree.
+
+ * "git commit" used to abort after the user edited the log message
+   when the committer information was not correctly set up.  It now
+   aborts before starting the editor.
+
+ * "git commit --date=invalid" used to silently ignore the incorrectly
+   specified date; it is now diagnosed as an error.
+
+ * "git rebase --skip" to skip the last commit in a series used to fail
+   to run post-rewrite hook and to copy notes from old commits that have
+   successfully been rebased so far.  Now it do (backmerge ef88ad2).
+
+ * "gitweb" tried to show a wrong feed logo when none was specified.
diff --git a/Documentation/RelNotes/1.7.3.txt b/Documentation/RelNotes/1.7.3.txt
new file mode 100644
index 0000000000..309c33181f
--- /dev/null
+++ b/Documentation/RelNotes/1.7.3.txt
@@ -0,0 +1,76 @@
+Git v1.7.3 Release Notes
+========================
+
+Updates since v1.7.2
+--------------------
+
+ * git-gui, now at version 0.13.0, got various updates and a new
+   maintainer, Pat Thoyts.
+
+ * Gitweb allows its configuration to change per each request; it used to
+   read the configuration once upon startup.
+
+ * When git finds a corrupt object, it now reports the file that contains
+   it.
+
+ * "git checkout -B <it>" is a shorter way to say "git branch -f <it>"
+   followed by "git checkout <it>".
+
+ * When "git checkout" or "git merge" refuse to proceed in order to
+   protect local modification to your working tree, they used to stop
+   after showing just one path that might be lost.  They now show all,
+   in a format that is easier to read.
+
+ * "git clean" learned "-e" ("--exclude") option.
+
+ * Hunk headers produced for C# files by "git diff" and friends show more
+   relevant context than before.
+
+ * diff.ignoresubmodules configuration variable can be used to squelch the
+   differences in submodules reported when running commands (e.g. "diff",
+   "status", etc.) at the superproject level.
+
+ * http.useragent configuration can be used to lie who you are to your
+   restrictive firewall.
+
+ * "git rebase --strategy <s>" learned "-X" option to pass extra options
+   that are understood by the chosen merge strategy.
+
+ * "git rebase -i" learned "exec" that you can insert into the insn sheet
+   to run a command between its steps.
+
+ * "git rebase" between branches that have many binary changes that do
+   not conflict should be faster.
+
+ * "git rebase -i" peeks into rebase.autosquash configuration and acts as
+   if you gave --autosquash from the command line.
+
+
+Also contains various documentation updates.
+
+
+Fixes since v1.7.2
+------------------
+
+All of the fixes in v1.7.2.X maintenance series are included in this
+release, unless otherwise noted.
+
+ * "git merge -s recursive" (which is the default) did not handle cases
+   where a directory becomes a file (or vice versa) very well.
+
+ * "git fetch" and friends were accidentally broken for url with "+" in
+   its path, e.g. "git://git.gnome.org/gtk+".
+
+ * "git fetch $url" (i.e. without refspecs) was broken for quite some
+   time, if the current branch happen to be tracking some remote.
+
+ * "git ls-tree dir dirgarbage", when "dir" was a directory,
+   incorrectly recursed into "dir".
+
+ * "git note remove" created unnecessary extra commit when named object
+   did not have any note to begin with.
+
+ * "git rebase" did not work well if you had diff.noprefix configured.
+
+ * "git -c foo=bar subcmd" did not work well for subcmd that is not
+   implemented as a built-in command.
diff --git a/Documentation/RelNotes/1.7.4.1.txt b/Documentation/RelNotes/1.7.4.1.txt
new file mode 100644
index 0000000000..79923a6d2f
--- /dev/null
+++ b/Documentation/RelNotes/1.7.4.1.txt
@@ -0,0 +1,27 @@
+Git v1.7.4.1 Release Notes
+==========================
+
+Fixes since v1.7.4
+------------------
+
+ * On Windows platform, the codepath to spawn a new child process forgot
+   to first flush the output buffer.
+
+ * "git bundle" did not use OFS_DELTA encoding, making its output a few
+   per-cent larger than necessarily.
+
+ * The option to tell "git clone" to recurse into the submodules was
+   misspelled with an underscore "--recurse_submodules".
+
+ * "git diff --cached HEAD" before the first commit does what an end user
+   would expect (namely, show what would be committed without further "git
+   add").
+
+ * "git fast-import" didn't accept the command to ask for "notes" feature
+   to be present in its input stream, even though it was capable of the
+   feature.
+
+ * "git fsck" gave up scanning loose object files in directories with
+   garbage files.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.4.2.txt b/Documentation/RelNotes/1.7.4.2.txt
new file mode 100644
index 0000000000..ef4ce1fcd3
--- /dev/null
+++ b/Documentation/RelNotes/1.7.4.2.txt
@@ -0,0 +1,58 @@
+Git v1.7.4.2 Release Notes
+==========================
+
+Fixes since v1.7.4.1
+--------------------
+
+ * Many documentation updates to match "git cmd -h" output and the
+   git-cmd manual page.
+
+ * We used to keep one file descriptor open for each and every packfile
+   that we have a mmap window on it (read: "in use"), even when for very
+   tiny packfiles.  We now close the file descriptor early when the entire
+   packfile fits inside one mmap window.
+
+ * "git bisect visualize" tried to run "gitk" in windowing
+   environments even when "gitk" is not installed, resulting in a
+   strange error message.
+
+ * "git clone /no/such/path" did not fail correctly.
+
+ * "git commit" did not correctly error out when the user asked to use a
+   non existent file as the commit message template.
+
+ * "git diff --stat -B" ran on binary files counted the changes in lines,
+   which was nonsensical.
+
+ * "git diff -M" opportunistically detected copies, which was not
+   necessarily a good thing, especially when it is internally run by
+   recursive merge.
+
+ * "git difftool" didn't tell (g)vimdiff that the files it is reading are
+   to be opened read-only.
+
+ * "git merge" didn't pay attention to prepare-commit-msg hook, even
+   though if a merge is conflicted and manually resolved, the subsequent
+   "git commit" would have triggered the hook, which was inconsistent.
+
+ * "git patch-id" (and commands like "format-patch --ignore-in-upstream"
+   that use it as their internal logic) handled changes to files that end
+   with incomplete lines incorrectly.
+
+ * The official value to tell "git push" to push the current branch back
+   to update the upstream branch it forked from is now called "upstream".
+   The old name "tracking" is and will be supported.
+
+ * "git submodule update" used to honor the --merge/--rebase option (or
+   corresponding configuration variables) even for a newly cloned
+   subproject, which made no sense (so/submodule-no-update-first-time).
+
+ * gitweb's "highlight" interface mishandled tabs.
+
+ * gitweb didn't understand timezones with GMT offset that is not
+   multiple of a whole hour.
+
+ * gitweb had a few forward-incompatible syntactic constructs and
+   also used incorrect variable when showing the file mode in a diff.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.4.3.txt b/Documentation/RelNotes/1.7.4.3.txt
new file mode 100644
index 0000000000..02a3d5bdf6
--- /dev/null
+++ b/Documentation/RelNotes/1.7.4.3.txt
@@ -0,0 +1,32 @@
+Git v1.7.4.3 Release Notes
+==========================
+
+Fixes since v1.7.4.2
+--------------------
+
+ * "git apply" used to confuse lines updated by previous hunks as lines
+   that existed before when applying a hunk, contributing misapplication
+   of patches with offsets.
+
+ * "git branch --track" (and "git checkout --track --branch") used to
+   allow setting up a random non-branch that does not make sense to follow
+   as the "upstream".  The command correctly diagnoses it as an error.
+
+ * "git checkout $other_branch" silently removed untracked symbolic links
+   in the working tree that are in the way in order to check out paths
+   under it from the named branch.
+
+ * "git cvsimport" did not bail out immediately when the cvs server cannot
+   be reached, spewing unnecessary error messages that complain about the
+   server response that it never got.
+
+ * "git diff --quiet" did not work very well with the "--diff-filter"
+   option.
+
+ * "git grep -n" lacked a long-hand synonym --line-number.
+
+ * "git stash apply" reported the result of its operation by running
+   "git status" from the top-level of the working tree; it should (and
+   now does) run it from the user's working directory.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.4.4.txt b/Documentation/RelNotes/1.7.4.4.txt
new file mode 100644
index 0000000000..ff06e04a58
--- /dev/null
+++ b/Documentation/RelNotes/1.7.4.4.txt
@@ -0,0 +1,35 @@
+Git v1.7.4.4 Release Notes
+==========================
+
+Fixes since v1.7.4.3
+--------------------
+
+ * Compilation of sha1_file.c on BSD platforms were broken due to our
+   recent use of getrlimit() without including <sys/resource.h>.
+
+ * "git config" did not diagnose incorrect configuration variable names.
+
+ * "git format-patch" did not wrap a long subject line that resulted from
+   rfc2047 encoding.
+
+ * "git instaweb" should work better again with plackup.
+
+ * "git log --max-count=4 -Sfoobar" now shows 4 commits that changes the
+   number of occurrences of string "foobar"; it used to scan only for 4
+   commits and then emitted only matching ones.
+
+ * "git log --first-parent --boundary $c^..$c" segfaulted on a merge.
+
+ * "git pull" into an empty branch should have behaved as if
+   fast-forwarding from emptiness to the version being pulled, with
+   the usual protection against overwriting untracked files.
+
+ * "git submodule" that is run while a merge in the superproject is in
+   conflicted state tried to process each conflicted submodule up to
+   three times.
+
+ * "git status" spent all the effort to notice racily-clean index entries
+   but didn't update the index file to help later operations go faster in
+   some cases.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.4.5.txt b/Documentation/RelNotes/1.7.4.5.txt
new file mode 100644
index 0000000000..b7a0eeb22f
--- /dev/null
+++ b/Documentation/RelNotes/1.7.4.5.txt
@@ -0,0 +1,4 @@
+Git v1.7.4.5 Release Notes
+==========================
+
+This contains only minor documentation fixes accumulated since 1.7.4.4.
diff --git a/Documentation/RelNotes/1.7.4.txt b/Documentation/RelNotes/1.7.4.txt
new file mode 100644
index 0000000000..d5bca731b5
--- /dev/null
+++ b/Documentation/RelNotes/1.7.4.txt
@@ -0,0 +1,156 @@
+Git v1.7.4 Release Notes
+========================
+
+Updates since v1.7.3
+--------------------
+
+ * The documentation Makefile now assumes by default asciidoc 8 and
+   docbook-xsl >= 1.73. If you have older versions, you can set
+   ASCIIDOC7 and ASCIIDOC_ROFF, respectively.
+
+ * The option parsers of various commands that create new branches (or
+   rename existing ones to a new name) were too loose and users were
+   allowed to give a branch a name that begins with a dash by creative
+   abuse of their command line options, which only led to burning
+   themselves.  The name of a branch cannot begin with a dash now.
+
+ * System-wide fallback default attributes can be stored in
+   /etc/gitattributes; the core.attributesfile configuration variable can
+   be used to customize the path to this file.
+
+ * The thread structure generated by "git send-email" has changed
+   slightly.  Setting the cover letter of the latest series as a reply
+   to the cover letter of the previous series with --in-reply-to used
+   to make the new cover letter and all the patches replies to the
+   cover letter of the previous series; this has been changed to make
+   the patches in the new series replies to the new cover letter.
+
+ * The Bash completion script in contrib/ has been adjusted to be usable with
+   Bash 4 (options with '=value' didn't complete).  It has been also made
+   usable with zsh.
+
+ * Different pagers can be chosen depending on which subcommand is
+   being run under the pager, using the "pager.<subcommand>" variable.
+
+ * The hardcoded tab-width of 8 that is used in whitespace breakage checks is now
+   configurable via the attributes mechanism.
+
+ * Support of case insensitive filesystems (i.e. "core.ignorecase") has
+   been improved.  For example, the gitignore mechanism didn't pay attention
+   to case insensitivity.
+
+ * The <tree>:<path> syntax for naming a blob in a tree, and the :<path>
+   syntax for naming a blob in the index (e.g. "master:Makefile",
+   ":hello.c") have been extended.  You can start <path> with "./" to
+   implicitly have the (sub)directory you are in prefixed to the
+   lookup.  Similarly, ":../Makefile" from a subdirectory would mean
+   "the Makefile of the parent directory in the index".
+
+ * "git blame" learned the --show-email option to display the e-mail
+   addresses instead of the names of authors.
+
+ * "git commit" learned the --fixup and --squash options to help later invocation
+   of interactive rebase.
+
+ * Command line options to "git cvsimport" whose names are in capital
+   letters (-A, -M, -R and -S) can now be specified as the default in
+   the .git/config file by their longer names (cvsimport.authorsFile,
+   cvsimport.mergeRegex, cvsimport.trackRevisions, cvsimport.ignorePaths).
+
+ * "git daemon" can be built in the MinGW environment.
+
+ * "git daemon" can take more than one --listen option to listen to
+   multiple addresses.
+
+ * "git describe --exact-match" was optimized not to read commit
+   objects unnecessarily.
+
+ * "git diff" and "git grep" learned what functions and subroutines
+   in Fortran, Pascal and Perl look like.
+
+ * "git fetch" learned the "--recurse-submodules" option.
+
+ * "git mergetool" tells vim/gvim to show a three-way diff by default
+   (use vimdiff2/gvimdiff2 as the tool name for old behavior).
+
+ * "git log -G<pattern>" limits the output to commits whose change has
+   added or deleted lines that match the given pattern.
+
+ * "git read-tree" with no argument as a way to empty the index is
+   deprecated; we might want to remove it in the future.  Users can
+   use the new --empty option to be more explicit instead.
+
+ * "git repack -f" does not spend cycles to recompress objects in the
+   non-delta representation anymore (use -F if you really mean it
+   e.g. after you changed the core.compression variable setting).
+
+ * "git merge --log" used to limit the resulting merge log to 20
+   entries; this is now customizable by giving e.g. "--log=47".
+
+ * "git merge" may work better when all files were moved out of a
+   directory in one branch while a new file is created in place of that
+   directory in the other branch.
+
+ * "git merge" learned the "--abort" option, synonymous to
+   "git reset --merge" when a merge is in progress.
+
+ * "git notes" learned the "merge" subcommand to merge notes refs.
+   In addition to the default manual conflict resolution, there are
+   also several notes merge strategies for automatically resolving
+   notes merge conflicts.
+
+ * "git rebase --autosquash" can use SHA-1 object names to name the
+   commit which is to be fixed up (e.g. "fixup! e83c5163").
+
+ * The default "recursive" merge strategy learned the --rename-threshold
+   option to influence the rename detection, similar to the -M option
+   of "git diff".  From the "git merge" frontend, the "-X<strategy option>"
+   interface, e.g. "git merge -Xrename-threshold=50% ...", can be used
+   to trigger this.
+
+ * The "recursive" strategy also learned to ignore various whitespace
+   changes; the most notable is -Xignore-space-at-eol.
+
+ * "git send-email" learned "--to-cmd", similar to "--cc-cmd", to read
+   the recipient list from a command output.
+
+ * "git send-email" learned to read and use "To:" from its input files.
+
+ * you can extend "git shell", which is often used on boxes that allow
+   git-only login over ssh as login shell, with a custom set of
+   commands.
+
+ * The current branch name in "git status" output can be colored differently
+   from the generic header color by setting the "color.status.branch" variable.
+
+ * "git submodule sync" updates metainformation for all submodules,
+   not just the ones that have been checked out.
+
+ * gitweb can use a custom 'highlight' command with its configuration file.
+
+ * other gitweb updates.
+
+
+Also contains various documentation updates.
+
+
+Fixes since v1.7.3
+------------------
+
+All of the fixes in the v1.7.3.X maintenance series are included in this
+release, unless otherwise noted.
+
+ * "git log --author=me --author=her" did not find commits written by
+   me or by her; instead it looked for commits written by me and by
+   her, which is impossible.
+
+ * "git push --progress" shows progress indicators now.
+
+ * "git rebase -i" showed a confusing error message when given a
+   branch name that does not exist.
+
+ * "git repack" places its temporary packs under $GIT_OBJECT_DIRECTORY/pack
+   instead of $GIT_OBJECT_DIRECTORY/ to avoid cross directory renames.
+
+ * "git submodule update --recursive --other-flags" passes flags down
+   to its subinvocations.
diff --git a/Documentation/RelNotes/1.7.5.1.txt b/Documentation/RelNotes/1.7.5.1.txt
new file mode 100644
index 0000000000..c6ebd76d19
--- /dev/null
+++ b/Documentation/RelNotes/1.7.5.1.txt
@@ -0,0 +1,47 @@
+Git v1.7.5.1 Release Notes
+==========================
+
+Fixes since v1.7.5
+------------------
+
+ * When an object "$tree:$path" does not exist, if $path does exist in the
+   subtree of $tree that corresponds to the subdirectory the user is in,
+   git now suggests using "$tree:./$path" in addition to the advice to use
+   the full path from the root of the working tree.
+
+ * The "--date=relative" output format used to say "X years, 12 months"
+   when it should have said "X+1 years".
+
+ * The smart-HTTP transfer was broken in 1.7.5 when the client needs
+   to issue a small POST (which uses content-length) and then a large
+   POST (which uses chunked) back to back.
+
+ * "git clean" used to fail on an empty directory that is not readable,
+   even though rmdir(2) could remove such a directory.  Now we attempt it
+   as the last resort.
+
+ * The "--dirstat" option of "diff" family of commands used to totally
+   ignore a change that only rearranged lines within a file.  Such a
+   change now counts as at least a minimum but non zero change.
+
+ * The "--dirstat" option of "diff" family of commands used to use the
+   pathname in the original, instead of the pathname in the result,
+   when renames are involved.
+
+ * "git pack-object" did not take core.bigfilethreashold into account
+   (unlike fast-import); now it does.
+
+ * "git reflog" ignored options like "--format=.." on the command line.
+
+ * "git stash apply" used to refuse to work if there was any change in
+   the working tree, even when the change did not overlap with the change
+   the stash recorded.
+
+ * "git stash apply @{99999}" was not diagnosed as an error, even when you
+   did not have that many stash entries.
+
+ * An error message from "git send-email" to diagnose a broken SMTP
+   connection configuration lacked a space between "hello=<smtp-domain>"
+   and "port=<smtp-server-port>".
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.5.2.txt b/Documentation/RelNotes/1.7.5.2.txt
new file mode 100644
index 0000000000..951eb7cb08
--- /dev/null
+++ b/Documentation/RelNotes/1.7.5.2.txt
@@ -0,0 +1,57 @@
+Git v1.7.5.2 Release Notes
+==========================
+
+The release notes to 1.7.5.1 forgot to mention:
+
+ * "git stash -p --no-keep-index" and "git stash --no-keep-index -p" now
+   mean the same thing.
+
+ * "git upload-pack" (hence "git push" over git native protocol) had a
+   subtle race condition that could lead to a deadlock.
+
+Fixes since v1.7.5.1
+--------------------
+
+ * "git add -p" did not work correctly when a hunk is split and then
+   one of them was given to the editor.
+
+ * "git add -u" did not resolve a conflict where our history deleted and
+   their history modified the same file, and the working tree resolved to
+   keep a file.
+
+ * "git cvsimport" did not know that CVSNT stores its password file in a
+   location different from the traditional CVS.
+
+ * "git diff-files" did not show the mode information from the working
+   tree side of an unmerged path correctly.
+
+ * "git diff -M --cached" used to use unmerged path as a possible rename
+   source candidate, which made no sense.
+
+ * The option name parser in "git fast-import" used prefix matches for
+   some options where it shouldn't, and accepted non-existent options,
+   e.g. "--relative-marksmith" or "--forceps".
+
+ * "git format-patch" did not quote RFC822 special characters in the
+   email address (e.g From: Junio C. Hamano <jch@xxxxxxxxxxx>, not
+   From: "Junio C. Hamano" <jch@xxxxxxxxxxx>).
+
+ * "git format-patch" when run with "--quiet" option used to produce a
+   nonsense result that consists of alternating empty output.
+
+ * In "git merge", per-branch branch.<name>.mergeoptions configuration
+   variables did not override the fallback default merge.<option>
+   configuration variables such as merge.ff, merge.log, etc.
+
+ * "git merge-one-file" did not honor GIT_WORK_TREE settings when
+   handling a "both sides added, differently" conflict.
+
+ * "git mergetool" did not handle conflicted submoudules gracefully.
+
+ * "git-p4" (in contrib) used a wrong base image while merge a file that
+   was added on both branches differently.
+
+ * "git rebase -i -p" failed to preserve the history when there is a
+   redundant merge created with the --no-ff option.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.5.3.txt b/Documentation/RelNotes/1.7.5.3.txt
new file mode 100644
index 0000000000..1d24edcf2f
--- /dev/null
+++ b/Documentation/RelNotes/1.7.5.3.txt
@@ -0,0 +1,32 @@
+Git v1.7.5.3 Release Notes
+==========================
+
+Fixes since v1.7.5.2
+--------------------
+
+ * The bash completion scripts should correctly work using zsh's bash
+   completion emulation layer now.
+
+ * Setting $(prefix) in config.mak did not affect where etc/gitconfig
+   file is read from, even though passing it from the command line of
+   $(MAKE) did.
+
+ * The logic to handle "&" (expand to UNIX username) in GECOS field
+   miscounted the length of the name it formatted.
+
+ * "git cherry-pick -s resolve" failed to cherry-pick a root commit.
+
+ * "git diff --word-diff" misbehaved when diff.suppress-blank-empty was
+   in effect.
+
+ * "git log --stdin path" with an input that has additional pathspec
+   used to corrupt memory.
+
+ * "git send-pack" (hence "git push") over smart-HTTP protocol could
+   deadlock when the client side pack-object died early.
+
+ * Compressed tarball gitweb generates used to be made with the timestamp
+   of the tarball generation; this was bad because snapshot from the same
+   tree should result in a same tarball.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.5.4.txt b/Documentation/RelNotes/1.7.5.4.txt
new file mode 100644
index 0000000000..7796df3fe4
--- /dev/null
+++ b/Documentation/RelNotes/1.7.5.4.txt
@@ -0,0 +1,21 @@
+Git v1.7.5.4 Release Notes
+==========================
+
+Fixes since v1.7.5.3
+--------------------
+
+ * The single-key mode of "git add -p" was easily fooled into thinking
+   that it was told to add everything ('a') when up-arrow was pressed by
+   mistake.
+
+ * Setting a git command that uses custom configuration via "-c var=val"
+   as an alias caused a crash due to a realloc(3) failure.
+
+ * "git diff -C -C" used to disable the rename detection entirely when
+   there are too many copy candidate paths in the tree; now it falls
+   back to "-C" when doing so would keep the copy candidate paths
+   under the rename detection limit.
+
+ * "git rerere" did not diagnose a corrupt MERGE_RR file in some cases.
+
+And other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.5.txt b/Documentation/RelNotes/1.7.5.txt
new file mode 100644
index 0000000000..987919c321
--- /dev/null
+++ b/Documentation/RelNotes/1.7.5.txt
@@ -0,0 +1,132 @@
+Git v1.7.5 Release Notes
+========================
+
+Updates since v1.7.4
+--------------------
+
+ * Various MinGW portability fixes.
+
+ * Various git-p4 enhancements (in contrib).
+
+ * Various vcs-svn, git-svn and gitk enhancements and fixes.
+
+ * Various git-gui updates (0.14.0).
+
+ * Update to more modern HP-UX port.
+
+ * The codebase is getting prepared for i18n/l10n; no translated
+   strings nor translation mechanism in the code yet, but the strings
+   are being marked for l10n.
+
+ * The bash completion script can now complete symmetric difference
+   for "git diff" command, e.g. "git diff ...bra<TAB>".
+
+ * The default minimum length of abbreviated and unique object names
+   can now be configured by setting the core.abbrev configuration
+   variable.
+
+ * "git apply -v" reports offset lines when the patch does not apply at
+   the exact location recorded in the diff output.
+
+ * "git config" used to be also known as "git repo-config", but the old
+   name is now officially deprecated.
+
+ * "git checkout --detach <commit>" is a more user friendly synonym for
+   "git checkout <commit>^0".
+
+ * "git checkout" performed on detached HEAD gives a warning and
+   advice when the commit being left behind will become unreachable from
+   any branch or tag.
+
+ * "git cherry-pick" and "git revert" can be told to use a custom merge
+   strategy, similar to "git rebase".
+
+ * "git cherry-pick" remembers which commit failed to apply when it is
+   stopped by conflicts, making it unnecessary to use "commit -c $commit"
+   to conclude it.
+
+ * "git cvsimport" bails out immediately when the cvs server cannot be
+   reached, without spewing unnecessary error messages that complain about
+   the server response it never got.
+
+ * "git fetch" vs "git upload-pack" transfer learned 'no-done'
+   protocol extension to save one round-trip after the content
+   negotiation is done. This saves one HTTP RPC, reducing the overall
+   latency for a trivial fetch.
+
+ * "git fetch" can be told to recursively fetch submodules on-demand.
+
+ * "git grep -f <filename>" learned to treat "-" as "read from the
+   standard input stream".
+
+ * "git grep --no-index" did not honor pathspecs correctly, returning
+   paths outside the specified area.
+
+ * "git init" learned the --separate-git-dir option to allow the git
+   directory for a new repository created elsewhere and linked via the
+   gitdir mechanism. This is primarily to help submodule support later
+   to switch between a branch of superproject that has the submodule
+   and another that does not.
+
+ * "git log" type commands now understand globbing pathspecs.  You
+   can say "git log -- '*.txt'" for example.
+
+ * "git log" family of commands learned --cherry and --cherry-mark
+   options that can be used to view two diverged branches while omitting
+   or highlighting equivalent changes that appear on both sides of a
+   symmetric difference (e.g. "log --cherry A...B").
+
+ * A lazy "git merge" that didn't say what to merge used to be an error.
+   When run on a branch that has an upstream defined, however, the command
+   now merges from the configured upstream.
+
+ * "git mergetool" learned how to drive "beyond compare 3" as well.
+
+ * "git rerere forget" without pathspec used to forget all the saved
+   conflicts that relate to the current merge; it now requires you to
+   give it pathspecs.
+
+ * "git rev-list --objects $revs -- $pathspec" now limits the objects listed
+   in its output properly with the pathspec, in preparation for narrow
+   clones.
+
+ * "git push" with no parameters gives better advice messages when
+   "tracking" is used as the push.default semantics or there is no remote
+   configured yet.
+
+ * A possible value to the "push.default" configuration variable,
+   'tracking', gained a synonym that more naturally describes what it
+   does, 'upstream'.
+
+ * "git rerere" learned a new subcommand "remaining" that is similar to
+   "status" and lists the paths that had conflicts which are known to
+   rerere, but excludes the paths that have already been marked as
+   resolved in the index from its output.  "git mergetool" has been
+   updated to use this facility.
+
+Also contains various documentation updates.
+
+
+Fixes since v1.7.4
+------------------
+
+All of the fixes in the v1.7.4.X maintenance series are included in this
+release, unless otherwise noted.
+
+ * "git fetch" from a client that is mostly following the remote
+   needlessly told all of its refs to the server for both sides to
+   compute the set of objects that need to be transferred efficiently,
+   instead of stopping when the server heard enough. In a project with
+   many tags, this turns out to be extremely wasteful, especially over
+   the smart HTTP transport (sp/maint-{upload,fetch}-pack-stop-early~1).
+
+ * "git fetch" run from a repository that uses the same repository as
+   its alternate object store as the repository it is fetching from
+   did not tell the server that it already has access to objects
+   reachable from the refs in their common alternate object store,
+   causing it to fetch unnecessary objects (jc/maint-fetch-alt).
+
+ * "git remote add --mirror" created a configuration that is suitable for
+   doing both a mirror fetch and a mirror push at the same time, which
+   made little sense.  We now warn and require the command line to specify
+   either --mirror=fetch or --mirror=push.
diff --git a/Documentation/RelNotes/1.7.6.1.txt b/Documentation/RelNotes/1.7.6.1.txt
new file mode 100644
index 0000000000..42e46ab17f
--- /dev/null
+++ b/Documentation/RelNotes/1.7.6.1.txt
@@ -0,0 +1,63 @@
+Git v1.7.6.1 Release Notes
+==========================
+
+Fixes since v1.7.6
+------------------
+
+ * Various codepaths that invoked zlib deflate/inflate assumed that these
+   functions can compress or uncompress more than 4GB data in one call on
+   platforms with 64-bit long, which has been corrected.
+
+ * "git unexecutable" reported that "unexecutable" was not found, even
+   though the actual error was that "unexecutable" was found but did
+   not have a proper she-bang line to be executed.
+
+ * Error exits from $PAGER were silently ignored.
+
+ * "git checkout -b <branch>" was confused when attempting to create a
+   branch whose name ends with "-g" followed by hexadecimal digits,
+   and refused to work.
+
+ * "git checkout -b <branch>" sometimes wrote a bogus reflog entry,
+   causing later "git checkout -" to fail.
+
+ * "git diff --cc" learned to correctly ignore binary files.
+
+ * "git diff -c/--cc" mishandled a deletion that resolves a conflict, and
+   looked in the working tree instead.
+
+ * "git fast-export" forgot to quote pathnames with unsafe characters
+   in its output.
+
+ * "git fetch" over smart-http transport used to abort when the
+   repository was updated between the initial connection and the
+   subsequent object transfer.
+
+ * "git fetch" did not recurse into submodules in subdirectories.
+
+ * "git ls-tree" did not error out when asked to show a corrupt tree.
+
+ * "git pull" without any argument left an extra whitespace after the
+   command name in its reflog.
+
+ * "git push --quiet" was not really quiet.
+
+ * "git rebase -i -p" incorrectly dropped commits from side branches.
+
+ * "git reset [<commit>] paths..." did not reset the index entry correctly
+   for unmerged paths.
+
+ * "git submodule add" did not allow a relative repository path when
+   the superproject did not have any default remote url.
+
+ * "git submodule foreach" failed to correctly give the standard input to
+   the user-supplied command it invoked.
+
+ * submodules that the user has never showed interest in by running
+   "git submodule init" was incorrectly marked as interesting by "git
+   submodule sync".
+
+ * "git submodule update --quiet" was not really quiet.
+
+  * "git tag -l <glob>..." did not take multiple glob patterns from the
+   command line.
diff --git a/Documentation/RelNotes/1.7.6.2.txt b/Documentation/RelNotes/1.7.6.2.txt
new file mode 100644
index 0000000000..67ae414965
--- /dev/null
+++ b/Documentation/RelNotes/1.7.6.2.txt
@@ -0,0 +1,8 @@
+Git v1.7.6.2 Release Notes
+==========================
+
+Fixes since v1.7.6.1
+--------------------
+
+ * v1.7.6.1 broke "git push --quiet"; it used to be a no-op against an old
+   version of Git running on the other end, but v1.7.6.1 made it abort.
diff --git a/Documentation/RelNotes/1.7.6.3.txt b/Documentation/RelNotes/1.7.6.3.txt
new file mode 100644
index 0000000000..95971831b9
--- /dev/null
+++ b/Documentation/RelNotes/1.7.6.3.txt
@@ -0,0 +1,24 @@
+Git v1.7.6.3 Release Notes
+==========================
+
+Fixes since v1.7.6.2
+--------------------
+
+ * "git -c var=value subcmd" misparsed the custom configuration when
+   value contained an equal sign.
+
+ * "git fetch" had a major performance regression, wasting many
+   needless cycles in a repository where there is no submodules
+   present. This was especially bad, when there were many refs.
+
+ * "git reflog $refname" did not default to the "show" subcommand as
+   the documentation advertised the command to do.
+
+ * "git reset" did not leave meaningful log message in the reflog.
+
+ * "git status --ignored" did not show ignored items when there is no
+   untracked items.
+
+ * "git tag --contains $commit" was unnecessarily inefficient.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.6.4.txt b/Documentation/RelNotes/1.7.6.4.txt
new file mode 100644
index 0000000000..e19acac2da
--- /dev/null
+++ b/Documentation/RelNotes/1.7.6.4.txt
@@ -0,0 +1,32 @@
+Git v1.7.6.4 Release Notes
+==========================
+
+Fixes since v1.7.6.3
+--------------------
+
+ * The error reporting logic of "git am" when the command is fed a file
+   whose mail-storage format is unknown was fixed.
+
+ * "git branch --set-upstream @{-1} foo" did not expand @{-1} correctly.
+
+ * "git check-ref-format --print" used to parrot a candidate string that
+   began with a slash (e.g. /refs/heads/master) without stripping it, to make
+   the result a suitably normalized string the caller can append to "$GIT_DIR/".
+
+ * "git clone" failed to clone locally from a ".git" file that itself
+   is not a directory but is a pointer to one.
+
+ * "git clone" from a local repository that borrows from another
+   object store using a relative path in its objects/info/alternates
+   file did not adjust the alternates in the resulting repository.
+
+ * "git describe --dirty" did not refresh the index before checking the
+   state of the working tree files.
+
+ * "git ls-files ../$path" that is run from a subdirectory reported errors
+   incorrectly when there is no such path that matches the given pathspec.
+
+ * "git mergetool" could loop forever prompting when nothing can be read
+   from the standard input.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.6.5.txt b/Documentation/RelNotes/1.7.6.5.txt
new file mode 100644
index 0000000000..6713132a9e
--- /dev/null
+++ b/Documentation/RelNotes/1.7.6.5.txt
@@ -0,0 +1,26 @@
+Git v1.7.6.5 Release Notes
+==========================
+
+Fixes since v1.7.6.4
+--------------------
+
+ * The date parser did not accept timezone designators that lack minutes
+   part and also has a colon between "hh:mm".
+
+ * After fetching from a remote that has very long refname, the reporting
+   output could have corrupted by overrunning a static buffer.
+
+ * "git mergetool" did not use its arguments as pathspec, but as a path to
+   the file that may not even have any conflict.
+
+ * "git name-rev --all" tried to name all _objects_, naturally failing to
+   describe many blobs and trees, instead of showing only commits as
+   advertised in its documentation.
+
+ * "git remote rename $a $b" were not careful to match the remote name
+   against $a (i.e. source side of the remote nickname).
+
+ * "gitweb" used to produce a non-working link while showing the contents
+   of a blob, when JavaScript actions are enabled.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.6.6.txt b/Documentation/RelNotes/1.7.6.6.txt
new file mode 100644
index 0000000000..5343e00400
--- /dev/null
+++ b/Documentation/RelNotes/1.7.6.6.txt
@@ -0,0 +1,16 @@
+Git v1.7.6.6 Release Notes
+==========================
+
+Fixes since v1.7.6.5
+--------------------
+
+ * The code to look up attributes for paths reused entries from a wrong
+   directory when two paths in question are in adjacent directories and
+   the name of the one directory is a prefix of the other.
+
+ * When producing a "thin pack" (primarily used in bundles and smart
+   HTTP transfers) out of a fully packed repository, we unnecessarily
+   avoided sending recent objects as a delta against objects we know
+   the other side has.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.6.txt b/Documentation/RelNotes/1.7.6.txt
new file mode 100644
index 0000000000..9ec498ea39
--- /dev/null
+++ b/Documentation/RelNotes/1.7.6.txt
@@ -0,0 +1,136 @@
+Git v1.7.6 Release Notes
+========================
+
+Updates since v1.7.5
+--------------------
+
+ * Various git-svn updates.
+
+ * Updates the way content tags are handled in gitweb.  Also adds
+   a UI to choose common timezone for displaying the dates.
+
+ * Similar to branch names, tagnames that begin with "-" are now
+   disallowed.
+
+ * Clean-up of the C part of i18n (but not l10n---please wait)
+   continues.
+
+ * The scripting part of the codebase is getting prepared for i18n/l10n.
+
+ * Pushing and pulling from a repository with large number of refs that
+   point to identical commits are optimized by not listing the same commit
+   during the common ancestor negotiation exchange with the other side.
+
+ * Adding a file larger than core.bigfilethreshold (defaults to 1/2 Gig)
+   using "git add" will send the contents straight to a packfile without
+   having to hold it and its compressed representation both at the same
+   time in memory.
+
+ * Processes spawned by "[alias] <name> = !process" in the configuration
+   can inspect GIT_PREFIX environment variable to learn where in the
+   working tree the original command was invoked.
+
+ * A magic pathspec ":/" tells a command that limits its operation to
+   the current directory when ran from a subdirectory to work on the
+   entire working tree. In general, ":/path/to/file" would be relative
+   to the root of the working tree hierarchy.
+
+   After "git reset --hard; edit Makefile; cd t/", "git add -u" would
+   be a no-op, but "git add -u :/" would add the updated contents of
+   the Makefile at the top level. If you want to name a path in the
+   current subdirectory whose unusual name begins with ":/", you can
+   name it by "./:/that/path" or by "\:/that/path".
+
+ * "git blame" learned "--abbrev[=<n>]" option to control the minimum
+   number of hexdigits shown for commit object names.
+
+ * "git blame" learned "--line-porcelain" that is less efficient but is
+   easier to parse.
+
+ * Aborting "git commit --interactive" discards updates to the index
+   made during the interactive session.
+
+ * "git commit" learned a "--patch" option to directly jump to the
+   per-hunk selection UI of the interactive mode.
+
+ * "git diff" and its family of commands learned --dirstat=0 to show
+   directories that contribute less than 0.1% of changes.
+
+ * "git diff" and its family of commands learned --dirstat=lines mode to
+   assess damage to the directory based on number of lines in the patch
+   output, not based on the similarity numbers.
+
+ * "git format-patch" learned "--quiet" option to suppress the output of
+   the names of generated files.
+
+ * "git format-patch" quotes people's names when it has RFC822 special
+   characters in it, e.g. "Junio C. Hamano" <jch@xxxxxxxxxxx>.  Earlier
+   it was up to the user to do this when using its output.
+
+ * "git format-patch" can take an empty --subject-prefix now.
+
+ * "git grep" learned the "-P" option to take pcre regular expressions.
+
+ * "git log" and friends learned a new "--notes" option to replace the
+   "--show-notes" option.  Unlike "--show-notes", "--notes=<ref>" does
+   not imply showing the default notes.
+
+ * They also learned a log.abbrevCommit configuration variable to augment
+   the --abbrev-commit command line option.
+
+ * "git ls-remote" learned "--exit-code" option to consider it a
+   different kind of error when no remote ref to be shown.
+
+ * "git merge" learned "-" as a short-hand for "the previous branch", just
+   like the way "git checkout -" works.
+
+ * "git merge" uses "merge.ff" configuration variable to decide to always
+   create a merge commit (i.e. --no-ff, aka merge.ff=no), refuse to create
+   a merge commit (i.e. --ff-only, aka merge.ff=only). Setting merge.ff=yes
+   (or not setting it at all) restores the default behaviour of allowing
+   fast-forward to happen when possible.
+
+ * p4-import (from contrib) learned a new option --preserve-user.
+
+ * "git read-tree -m" learned "--dry-run" option that reports if a merge
+   would fail without touching the index nor the working tree.
+
+ * "git rebase" that does not specify on top of which branch to rebase
+   the current branch now uses @{upstream} of the current branch.
+
+ * "git rebase" finished either normally or with --abort did not
+   update the reflog for HEAD to record the event to come back to
+   where it started from.
+
+ * "git remote add -t only-this-branch --mirror=fetch" is now allowed. Earlier
+   a fetch-mode mirror meant mirror everything, but now it only means refs are
+   not renamed.
+
+ * "git rev-list --count" used with "--cherry-mark" counts the cherry-picked
+   commits separately, producing more a useful output.
+
+ * "git submodule update" learned "--force" option to get rid of local
+   changes in submodules and replace them with the up-to-date version.
+
+ * "git status" and friends ignore .gitmodules file while the file is
+   still in a conflicted state during a merge, to avoid using information
+   that is not final and possibly corrupt with conflict markers.
+
+Also contains various documentation updates and minor miscellaneous
+changes.
+
+
+Fixes since v1.7.5
+------------------
+
+Unless otherwise noted, all the fixes in 1.7.5.X maintenance track are
+included in this release.
+
+ * "git config" used to choke with an insanely long line.
+   (merge ef/maint-strbuf-init later)
+
+ * "git diff --quiet" did not work well with --diff-filter.
+   (merge jk/diff-not-so-quick later)
+
+ * "git status -z" did not default to --porcelain output format.
+   (merge bc/maint-status-z-to-use-porcelain later)
diff --git a/Documentation/RelNotes/1.7.7.1.txt b/Documentation/RelNotes/1.7.7.1.txt
new file mode 100644
index 0000000000..ac9b838e25
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.1.txt
@@ -0,0 +1,60 @@
+Git v1.7.7.1 Release Notes
+==========================
+
+Fixes since v1.7.7
+------------------
+
+ * On some BSD systems, adding +s bit on directories is detrimental
+   (it is not necessary on BSD to begin with). "git init --shared"
+   has been updated to take this into account without extra makefile
+   settings on platforms the Makefile knows about.
+
+ * After incorrectly written third-party tools store a tag object in
+   HEAD, git diagnosed it as a repository corruption and refused to
+   proceed in order to avoid spreading the damage. We now gracefully
+   recover from such a situation by pretending as if the commit that
+   is pointed at by the tag were in HEAD.
+
+ * "git apply --whitespace=error" did not bother to report the exact
+   line number in the patch that introduced new blank lines at the end
+   of the file.
+
+ * "git apply --index" did not check corrupted patch.
+
+ * "git checkout $tree $directory/" resurrected paths locally removed or
+   modified only in the working tree in $directory/ that did not appear
+   in $directory of the given $tree. They should have been kept intact.
+
+ * "git diff $tree $path" used to apply the pathspec at the output stage,
+   reading the whole tree, wasting resources.
+
+ * The code to check for updated submodules during a "git fetch" of the
+   superproject had an unnecessary quadratic loop.
+
+ * "git fetch" from a large bundle did not enable the progress output.
+
+ * When "git fsck --lost-and-found" found that an empty blob object in the
+   object store is unreachable, it incorrectly reported an error after
+   writing the lost blob out successfully.
+
+ * "git filter-branch" did not refresh the index before checking that the
+   working tree was clean.
+
+ * "git grep $tree" when run with multiple threads had an unsafe access to
+   the object database that should have been protected with mutex.
+
+ * The "--ancestry-path" option to "git log" and friends misbehaved in a
+   history with complex criss-cross merges and showed an uninteresting
+   side history as well.
+
+ * Test t1304 assumed LOGNAME is always set, which may not be true on
+   some systems.
+
+ * Tests with --valgrind failed to find "mergetool" scriptlets.
+
+ * "git patch-id" miscomputed the patch-id in a patch that has a line longer
+   than 1kB.
+
+ * When an "exec" insn failed after modifying the index and/or the working
+   tree during "rebase -i", we now check and warn that the changes need to
+   be cleaned up.
diff --git a/Documentation/RelNotes/1.7.7.2.txt b/Documentation/RelNotes/1.7.7.2.txt
new file mode 100644
index 0000000000..e6bbef2f01
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.2.txt
@@ -0,0 +1,44 @@
+Git v1.7.7.2 Release Notes
+==========================
+
+Fixes since v1.7.7.1
+--------------------
+
+ * We used to drop error messages from libcurl on certain kinds of
+   errors.
+
+ * Error report from smart HTTP transport, when the connection was
+   broken in the middle of a transfer, showed a useless message on
+   a corrupt packet.
+
+ * "git fetch --prune" was unsafe when used with refspecs from the
+   command line.
+
+ * The attribute mechanism did not use case insensitive match when
+   core.ignorecase was set.
+
+ * "git bisect" did not notice when it failed to update the working tree
+   to the next commit to be tested.
+
+ * "git config --bool --get-regexp" failed to separate the variable name
+   and its value "true" when the variable is defined without "= true".
+
+ * "git remote rename $a $b" were not careful to match the remote name
+   against $a (i.e. source side of the remote nickname).
+
+ * "git mergetool" did not use its arguments as pathspec, but as a path to
+   the file that may not even have any conflict.
+
+ * "git diff --[num]stat" used to use the number of lines of context
+   different from the default, potentially giving different results from
+   "git diff | diffstat" and confusing the users.
+
+ * "git pull" and "git rebase" did not work well even when GIT_WORK_TREE is
+   set correctly with GIT_DIR if the current directory is outside the working
+   tree.
+
+ * "git send-email" did not honor the configured hostname when restarting
+   the HELO/EHLO exchange after switching TLS on.
+
+ * "gitweb" used to produce a non-working link while showing the contents
+   of a blob, when JavaScript actions are enabled.
diff --git a/Documentation/RelNotes/1.7.7.3.txt b/Documentation/RelNotes/1.7.7.3.txt
new file mode 100644
index 0000000000..09301f0957
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.3.txt
@@ -0,0 +1,19 @@
+Git v1.7.7.3 Release Notes
+==========================
+
+Fixes since v1.7.7.2
+--------------------
+
+ * Adjust the "quick-install-doc" procedures as preformatted
+   html/manpage are no longer in the source repository.
+
+ * The logic to optimize the locality of the data in a pack introduced in
+   1.7.7 was grossly inefficient.
+
+ * The logic to filter out forked projects in the project list in
+   "gitweb" was broken for some time.
+
+ * "git branch -m/-M" advertised to update RENAME_REF ref in the
+   commit log message that introduced the feature but not anywhere in
+   the documentation, and never did update such a ref anyway. This
+   undocumented misfeature that did not exist has been excised.
diff --git a/Documentation/RelNotes/1.7.7.4.txt b/Documentation/RelNotes/1.7.7.4.txt
new file mode 100644
index 0000000000..e5234485e7
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.4.txt
@@ -0,0 +1,14 @@
+Git v1.7.7.4 Release Notes
+==========================
+
+Fixes since v1.7.7.3
+--------------------
+
+ * A few header dependencies were missing from the Makefile.
+
+ * Some newer parts of the code used C99 __VA_ARGS__ while we still
+   try to cater to older compilers.
+
+ * "git name-rev --all" tried to name all _objects_, naturally failing to
+   describe many blobs and trees, instead of showing only commits as
+   advertised in its documentation.
diff --git a/Documentation/RelNotes/1.7.7.5.txt b/Documentation/RelNotes/1.7.7.5.txt
new file mode 100644
index 0000000000..7b0931987b
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.5.txt
@@ -0,0 +1,14 @@
+Git v1.7.7.5 Release Notes
+==========================
+
+Fixes since v1.7.7.4
+--------------------
+
+ * After fetching from a remote that has very long refname, the reporting
+   output could have corrupted by overrunning a static buffer.
+
+ * "git checkout" and "git merge" treated in-tree .gitignore and exclude
+   file in $GIT_DIR/info/ directory inconsistently when deciding which
+   untracked files are ignored and expendable.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.7.6.txt b/Documentation/RelNotes/1.7.7.6.txt
new file mode 100644
index 0000000000..8df606d452
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.6.txt
@@ -0,0 +1,20 @@
+Git v1.7.7.6 Release Notes
+==========================
+
+Fixes since v1.7.7.5
+--------------------
+
+ * The code to look up attributes for paths reused entries from a wrong
+   directory when two paths in question are in adjacent directories and
+   the name of the one directory is a prefix of the other.
+
+ * A wildcard that matches deeper hierarchy given to the "diff-index" command,
+   e.g. "git diff-index HEAD -- '*.txt'", incorrectly reported additions of
+   matching files even when there is no change.
+
+ * When producing a "thin pack" (primarily used in bundles and smart
+   HTTP transfers) out of a fully packed repository, we unnecessarily
+   avoided sending recent objects as a delta against objects we know
+   the other side has.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.7.7.txt b/Documentation/RelNotes/1.7.7.7.txt
new file mode 100644
index 0000000000..e79118d063
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.7.txt
@@ -0,0 +1,13 @@
+Git v1.7.7.7 Release Notes
+==========================
+
+Fixes since v1.7.7.6
+--------------------
+
+ * An error message from 'git bundle' had an unmatched single quote pair in it.
+
+ * 'git diff --histogram' option was not described.
+
+ * 'git imap-send' carried an unused dead code.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.7.txt b/Documentation/RelNotes/1.7.7.txt
new file mode 100644
index 0000000000..6eff128c80
--- /dev/null
+++ b/Documentation/RelNotes/1.7.7.txt
@@ -0,0 +1,134 @@
+Git v1.7.7 Release Notes
+========================
+
+Updates since v1.7.6
+--------------------
+
+ * The scripting part of the codebase is getting prepared for i18n/l10n.
+
+ * Interix, Cygwin and Minix ports got updated.
+
+ * Various updates to git-p4 (in contrib/), fast-import, and git-svn.
+
+ * Gitweb learned to read from /etc/gitweb-common.conf when it exists,
+   before reading from gitweb_config.perl or from /etc/gitweb.conf
+   (this last one is read only when per-repository gitweb_config.perl
+   does not exist).
+
+ * Various codepaths that invoked zlib deflate/inflate assumed that these
+   functions can compress or uncompress more than 4GB data in one call on
+   platforms with 64-bit long, which has been corrected.
+
+ * Git now recognizes loose objects written by other implementations that
+   use a non-standard window size for zlib deflation (e.g. Agit running on
+   Android with 4kb window). We used to reject anything that was not
+   deflated with 32kb window.
+
+ * Interaction between the use of pager and coloring of the output has
+   been improved, especially when a command that is not built-in was
+   involved.
+
+ * "git am" learned to pass the "--exclude=<path>" option through to underlying
+   "git apply".
+
+ * You can now feed many empty lines before feeding an mbox file to
+   "git am".
+
+ * "git archive" can be told to pass the output to gzip compression and
+   produce "archive.tar.gz".
+
+ * "git bisect" can be used in a bare repository (provided that the test
+   you perform per each iteration does not need a working tree, of
+   course).
+
+ * The length of abbreviated object names in "git branch -v" output
+   now honors the core.abbrev configuration variable.
+
+ * "git check-attr" can take relative paths from the command line.
+
+ * "git check-attr" learned an "--all" option to list the attributes for a
+   given path.
+
+ * "git checkout" (both the code to update the files upon checking out a
+   different branch and the code to checkout a specific set of files) learned
+   to stream the data from object store when possible, without having to
+   read the entire contents of a file into memory first. An earlier round
+   of this code that is not in any released version had a large leak but
+   now it has been plugged.
+
+ * "git clone" can now take a "--config key=value" option to set the
+   repository configuration options that affect the initial checkout.
+
+ * "git commit <paths>..." now lets you feed relative pathspecs that
+   refer to outside your current subdirectory.
+
+ * "git diff --stat" learned a --stat-count option to limit the output of
+   a diffstat report.
+
+ * "git diff" learned a "--histogram" option to use a different diff
+   generation machinery stolen from jgit, which might give better
+   performance.
+
+ * "git diff" had a weird worst case behaviour that can be triggered
+   when comparing files with potentially many places that could match.
+
+ * "git fetch", "git push" and friends no longer show connection
+   errors for addresses that couldn't be connected to when at least one
+   address succeeds (this is arguably a regression but a deliberate
+   one).
+
+ * "git grep" learned "--break" and "--heading" options, to let users mimic
+   the output format of "ack".
+
+ * "git grep" learned a "-W" option that shows wider context using the same
+   logic used by "git diff" to determine the hunk header.
+
+ * Invoking the low-level "git http-fetch" without "-a" option (which
+   git itself never did--normal users should not have to worry about
+   this) is now deprecated.
+
+ * The "--decorate" option to "git log" and its family learned to
+   highlight grafted and replaced commits.
+
+ * "git rebase master topci" no longer spews usage hints after giving
+   the "fatal: no such branch: topci" error message.
+
+ * The recursive merge strategy implementation got a fairly large
+   fix for many corner cases that may rarely happen in real world
+   projects (it has been verified that none of the 16000+ merges in
+   the Linux kernel history back to v2.6.12 is affected with the
+   corner case bugs this update fixes).
+
+ * "git stash" learned an "--include-untracked option".
+
+ * "git submodule update" used to stop at the first error updating a
+   submodule; it now goes on to update other submodules that can be
+   updated, and reports the ones with errors at the end.
+
+ * "git push" can be told with the "--recurse-submodules=check" option to
+   refuse pushing of the supermodule, if any of its submodules'
+   commits hasn't been pushed out to their remotes.
+
+ * "git upload-pack" and "git receive-pack" learned to pretend that only a
+   subset of the refs exist in a repository. This may help a site to
+   put many tiny repositories into one repository (this would not be
+   useful for larger repositories as repacking would be problematic).
+
+ * "git verify-pack" has been rewritten to use the "index-pack" machinery
+   that is more efficient in reading objects in packfiles.
+
+ * test scripts for gitweb tried to run even when CGI-related perl modules
+   are not installed; they now exit early when the latter are unavailable.
+
+Also contains various documentation updates and minor miscellaneous
+changes.
+
+
+Fixes since v1.7.6
+------------------
+
+Unless otherwise noted, all fixes in the 1.7.6.X maintenance track are
+included in this release.
+
+ * "git branch -m" and "git checkout -b" incorrectly allowed the tip
+   of the branch that is currently checked out updated.
diff --git a/Documentation/RelNotes/1.7.8.1.txt b/Documentation/RelNotes/1.7.8.1.txt
new file mode 100644
index 0000000000..33dc948b94
--- /dev/null
+++ b/Documentation/RelNotes/1.7.8.1.txt
@@ -0,0 +1,38 @@
+Git v1.7.8.1 Release Notes
+==========================
+
+Fixes since v1.7.8
+------------------
+
+ * In some codepaths (notably, checkout and merge), the ignore patterns
+   recorded in $GIT_DIR/info/exclude were not honored. They now are.
+
+ * "git apply --check" did not error out when given an empty input
+   without any patch.
+
+ * "git archive" mistakenly allowed remote clients to ask for commits
+   that are not at the tip of any ref.
+
+ * "git checkout" and "git merge" treated in-tree .gitignore and exclude
+   file in $GIT_DIR/info/ directory inconsistently when deciding which
+   untracked files are ignored and expendable.
+
+ * LF-to-CRLF streaming filter used when checking out a large-ish blob
+   fell into an infinite loop with a rare input.
+
+ * The function header pattern for files with "diff=cpp" attribute did
+   not consider "type *funcname(type param1,..." as the beginning of a
+   function.
+
+ * The error message from "git diff" and "git status" when they fail
+   to inspect changes in submodules did not report which submodule they
+   had trouble with.
+
+ * After fetching from a remote that has very long refname, the reporting
+   output could have corrupted by overrunning a static buffer.
+
+ * "git pack-objects" avoids creating cyclic dependencies among deltas
+   when seeing a broken packfile that records the same object in both
+   the deflated form and as a delta.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.8.2.txt b/Documentation/RelNotes/1.7.8.2.txt
new file mode 100644
index 0000000000..b9c66aa1b7
--- /dev/null
+++ b/Documentation/RelNotes/1.7.8.2.txt
@@ -0,0 +1,71 @@
+Git v1.7.8.2 Release Notes
+==========================
+
+Fixes since v1.7.8.1
+--------------------
+
+ * Porcelain commands like "git reset" did not distinguish deletions
+   and type-changes from ordinary modification, and reported them with
+   the same 'M' moniker. They now use 'D' (for deletion) and 'T' (for
+   type-change) to match "git status -s" and "git diff --name-status".
+
+ * The configuration file parser used for sizes (e.g. bigFileThreshold)
+   did not correctly interpret 'g' suffix.
+
+ * The replacement implementation for snprintf used on platforms with
+   native snprintf that is broken did not use va_copy correctly.
+
+ * LF-to-CRLF streaming filter replaced all LF with CRLF, which might
+   be technically correct but not friendly to people who are trying
+   to recover from earlier mistakes of using CRLF in the repository
+   data in the first place. It now refrains from doing so for LF that
+   follows a CR.
+
+ * git native connection going over TCP (not over SSH) did not set
+   SO_KEEPALIVE option which failed to receive link layer errors.
+
+ * "git branch -m <current branch> HEAD" is an obvious no-op but was not
+   allowed.
+
+ * "git checkout -m" did not recreate the conflicted state in a "both
+   sides added, without any common ancestor version" conflict
+   situation.
+
+ * "git cherry-pick $commit" (not a range) created an unnecessary
+   sequencer state and interfered with valid workflow to use the
+   command during a session to cherry-pick multiple commits.
+
+ * You could make "git commit" segfault by giving the "--no-message"
+   option.
+
+ * "fast-import" did not correctly update an existing notes tree,
+   possibly corrupting the fan-out.
+
+ * "git fetch-pack" accepted unqualified refs that do not begin with
+   refs/ by mistake and compensated it by matching the refspec with
+   tail-match, which was doubly wrong. This broke fetching from a
+   repository with a funny named ref "refs/foo/refs/heads/master" and a
+   'master' branch with "git fetch-pack refs/heads/master", as the
+   command incorrectly considered the former a "match".
+
+ * "git log --follow" did not honor the rename threshold score given
+   with the -M option (e.g. "-M50%").
+
+ * "git mv" gave suboptimal error/warning messages when it overwrites
+   target files. It also did not pay attention to "-v" option.
+
+ * Authenticated "git push" over dumb HTTP were broken with a recent
+   change and failed without asking for password when username is
+   given.
+
+ * "git push" to an empty repository over HTTP were broken with a
+   recent change to the ref handling.
+
+ * "git push -v" forgot how to be verbose by mistake. It now properly
+   becomes verbose when asked to.
+
+ * When a "reword" action in "git rebase -i" failed to run "commit --amend",
+   we did not give the control back to the user to resolve the situation, and
+   instead kept the original commit log message.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.8.3.txt b/Documentation/RelNotes/1.7.8.3.txt
new file mode 100644
index 0000000000..a92714c14b
--- /dev/null
+++ b/Documentation/RelNotes/1.7.8.3.txt
@@ -0,0 +1,16 @@
+Git v1.7.8.3 Release Notes
+==========================
+
+Fixes since v1.7.8.2
+--------------------
+
+ * Attempt to fetch from an empty file pretending it to be a bundle did
+   not error out correctly.
+
+ * gitweb did not correctly fall back to configured $fallback_encoding
+   that is not 'latin1'.
+
+ * "git clone --depth $n" did not catch a non-number given as $n as an
+   error.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.8.4.txt b/Documentation/RelNotes/1.7.8.4.txt
new file mode 100644
index 0000000000..9bebdbf13d
--- /dev/null
+++ b/Documentation/RelNotes/1.7.8.4.txt
@@ -0,0 +1,23 @@
+Git v1.7.8.4 Release Notes
+==========================
+
+Fixes since v1.7.8.3
+--------------------
+
+ * The code to look up attributes for paths reused entries from a wrong
+   directory when two paths in question are in adjacent directories and
+   the name of the one directory is a prefix of the other.
+
+ * A wildcard that matches deeper hierarchy given to the "diff-index" command,
+   e.g. "git diff-index HEAD -- '*.txt'", incorrectly reported additions of
+   matching files even when there is no change.
+
+ * When producing a "thin pack" (primarily used in bundles and smart
+   HTTP transfers) out of a fully packed repository, we unnecessarily
+   avoided sending recent objects as a delta against objects we know
+   the other side has.
+
+ * "git send-email" did not properly treat sendemail.multiedit as a
+   boolean (e.g. setting it to "false" did not turn it off).
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.8.5.txt b/Documentation/RelNotes/1.7.8.5.txt
new file mode 100644
index 0000000000..011fd2a428
--- /dev/null
+++ b/Documentation/RelNotes/1.7.8.5.txt
@@ -0,0 +1,19 @@
+Git v1.7.8.5 Release Notes
+==========================
+
+Fixes since v1.7.8.4
+--------------------
+
+ * Dependency on our thread-utils.h header file was missing for
+   objects that depend on it in the Makefile.
+
+ * "git am" when fed an empty file did not correctly finish reading it
+   when it attempts to guess the input format.
+
+ * "git grep -P" (when PCRE is enabled in the build) did not match the
+   beginning and the end of the line correctly with ^ and $.
+
+ * "git rebase -m" tried to run "git notes copy" needlessly when
+   nothing was rewritten.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.8.6.txt b/Documentation/RelNotes/1.7.8.6.txt
new file mode 100644
index 0000000000..d9bf2b741a
--- /dev/null
+++ b/Documentation/RelNotes/1.7.8.6.txt
@@ -0,0 +1,22 @@
+Git v1.7.8.6 Release Notes
+==========================
+
+Fixes since v1.7.8.5
+--------------------
+
+ * An error message from 'git bundle' had an unmatched single quote pair in it.
+
+ * 'git diff --histogram' option was not described.
+
+ * Documentation for 'git rev-list' had minor formatting errors.
+
+ * 'git imap-send' carried an unused dead code.
+
+ * The way 'git fetch' implemented its connectivity check over
+   received objects was overly pessimistic, and wasted a lot of
+   cycles.
+
+ * Various minor backports of fixes from the 'master' and the 'maint'
+   branch.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.8.txt b/Documentation/RelNotes/1.7.8.txt
new file mode 100644
index 0000000000..249311361e
--- /dev/null
+++ b/Documentation/RelNotes/1.7.8.txt
@@ -0,0 +1,161 @@
+Git v1.7.8 Release Notes
+========================
+
+Updates since v1.7.7
+--------------------
+
+ * Some git-svn, git-gui, git-p4 (in contrib) and msysgit updates.
+
+ * Updates to bash completion scripts.
+
+ * The build procedure has been taught to take advantage of computed
+   dependency automatically when the compiler supports it.
+
+ * The date parser now accepts timezone designators that lack minutes
+   part and also has a colon between "hh:mm".
+
+ * The contents of the /etc/mailname file, if exists, is used as the
+   default value of the hostname part of the committer/author e-mail.
+
+ * "git am" learned how to read from patches generated by Hg.
+
+ * "git archive" talking with a remote repository can report errors
+   from the remote side in a more informative way.
+
+ * "git branch" learned an explicit --list option to ask for branches
+   listed, optionally with a glob matching pattern to limit its output.
+
+ * "git check-attr" learned "--cached" option to look at .gitattributes
+   files from the index, not from the working tree.
+
+ * Variants of "git cherry-pick" and "git revert" that take multiple
+   commits learned to "--continue" and "--abort".
+
+ * "git daemon" gives more human readable error messages to clients
+   using ERR packets when appropriate.
+
+ * Errors at the network layer is logged by "git daemon".
+
+ * "git diff" learned "--minimal" option to spend extra cycles to come
+   up with a minimal patch output.
+
+ * "git diff" learned "--function-context" option to show the whole
+   function as context that was affected by a change.
+
+ * "git difftool" can be told to skip launching the tool for a path by
+   answering 'n' to its prompt.
+
+ * "git fetch" learned to honor transfer.fsckobjects configuration to
+   validate the objects that were received from the other end, just like
+   "git receive-pack" (the receiving end of "git push") does.
+
+ * "git fetch" makes sure that the set of objects it received from the
+   other end actually completes the history before updating the refs.
+   "git receive-pack" (the receiving end of "git push") learned to do the
+   same.
+
+ * "git fetch" learned that fetching/cloning from a regular file on the
+   filesystem is not necessarily a request to unpack a bundle file; the
+   file could be ".git" with "gitdir: <path>" in it.
+
+ * "git for-each-ref" learned "%(contents:subject)", "%(contents:body)"
+   and "%(contents:signature)". The last one is useful for signed tags.
+
+ * "git grep" used to incorrectly pay attention to .gitignore files
+   scattered in the directory it was working in even when "--no-index"
+   option was used. It no longer does this. The "--exclude-standard"
+   option needs to be given to explicitly activate the ignore
+   mechanism.
+
+ * "git grep" learned "--untracked" option, where given patterns are
+    searched in untracked (but not ignored) files as well as tracked
+    files in the working tree, so that matches in new but not yet
+    added files do not get missed.
+
+ * The recursive merge backend no longer looks for meaningless
+   existing merges in submodules unless in the outermost merge.
+
+ * "git log" and friends learned "--children" option.
+
+ * "git ls-remote" learned to respond to "-h"(elp) requests.
+
+ * "mediawiki" remote helper can interact with (surprise!) MediaWiki
+   with "git fetch" & "git push".
+
+ * "git merge" learned the "--edit" option to allow users to edit the
+   merge commit log message.
+
+ * "git rebase -i" can be told to use special purpose editor suitable
+   only for its insn sheet via sequence.editor configuration variable.
+
+ * "git send-email" learned to respond to "-h"(elp) requests.
+
+ * "git send-email" allows the value given to sendemail.aliasfile to begin
+   with "~/" to refer to the $HOME directory.
+
+ * "git send-email" forces use of Authen::SASL::Perl to work around
+   issues between Authen::SASL::Cyrus and AUTH PLAIN/LOGIN.
+
+ * "git stash" learned "--include-untracked" option to stash away
+   untracked/ignored cruft from the working tree.
+
+ * "git submodule clone" does not leak an error message to the UI
+   level unnecessarily anymore.
+
+ * "git submodule update" learned to honor "none" as the value for
+   submodule.<name>.update to specify that the named submodule should
+   not be checked out by default.
+
+ * When populating a new submodule directory with "git submodule init",
+   the $GIT_DIR metainformation directory for submodules is created inside
+   $GIT_DIR/modules/<name>/ directory of the superproject and referenced
+   via the gitfile mechanism. This is to make it possible to switch
+   between commits in the superproject that has and does not have the
+   submodule in the tree without re-cloning.
+
+ * "gitweb" leaked unescaped control characters from syntax hiliter
+   outputs.
+
+ * "gitweb" can be told to give custom string at the end of the HTML
+   HEAD element.
+
+ * "gitweb" now has its own manual pages.
+
+
+Also contains other documentation updates and minor code cleanups.
+
+
+Fixes since v1.7.7
+------------------
+
+Unless otherwise noted, all fixes in the 1.7.7.X maintenance track are
+included in this release.
+
+ * HTTP transport did not use pushurl correctly, and also did not tell
+   what host it is trying to authenticate with when asking for
+   credentials.
+   (merge deba493 jk/http-auth later to maint).
+
+ * "git blame" was aborted if started from an uncommitted content and
+   the path had the textconv filter in effect.
+   (merge 8518088 ss/blame-textconv-fake-working-tree later to maint).
+
+ * Adding many refs to the local repository in one go (e.g. "git fetch"
+   that fetches many tags) and looking up a ref by name in a repository
+   with too many refs were unnecessarily slow.
+   (merge 17d68a54d jp/get-ref-dir-unsorted later to maint).
+
+ * Report from "git commit" on untracked files was confused under
+   core.ignorecase option.
+   (merge 395c7356 jk/name-hash-dirent later to maint).
+
+ * "git merge" did not understand ":/<pattern>" as a way to name a commit.
+
+ " "git push" on the receiving end used to call post-receive and post-update
+   hooks for attempted removal of non-existing refs.
+   (merge 160b81ed ph/push-to-delete-nothing later to maint).
+
+ * Help text for "git remote set-url" and "git remote set-branches"
+   were misspelled.
+   (merge c49904e fc/remote-seturl-usage-fix later to maint).
+   (merge 656cdf0 jc/remote-setbranches-usage-fix later to maint).
diff --git a/Documentation/RelNotes/1.7.9.1.txt b/Documentation/RelNotes/1.7.9.1.txt
new file mode 100644
index 0000000000..6957183dbb
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.1.txt
@@ -0,0 +1,63 @@
+Git v1.7.9.1 Release Notes
+==========================
+
+Fixes since v1.7.9
+------------------
+
+ * The makefile allowed environment variable X seep into it result in
+   command names suffixed with unnecessary strings.
+
+ * The set of included header files in compat/inet-{ntop,pton}
+   wrappers was updated for Windows some time ago, but in a way that
+   broke Solaris build.
+
+ * rpmbuild noticed an unpackaged but installed *.mo file and failed.
+
+ * Subprocesses spawned from various git programs were often left running
+   to completion even when the top-level process was killed.
+
+ * "git add -e" learned not to show a diff for an otherwise unmodified
+   submodule that only has uncommitted local changes in the patch
+   prepared by for the user to edit.
+
+ * Typo in "git branch --edit-description my-tpoic" was not diagnosed.
+
+ * Using "git grep -l/-L" together with options -W or --break may not
+   make much sense as the output is to only count the number of hits
+   and there is no place for file breaks, but the latter options made
+   "-l/-L" to miscount the hits.
+
+ * "git log --first-parent $pathspec" did not stay on the first parent
+   chain and veered into side branch from which the whole change to the
+   specified paths came.
+
+ * "git merge --no-edit $tag" failed to honor the --no-edit option.
+
+ * "git merge --ff-only $tag" failed because it cannot record the
+   required mergetag without creating a merge, but this is so common
+   operation for branch that is used _only_ to follow the upstream, so
+   it was changed to allow fast-forwarding without recording the mergetag.
+
+ * "git mergetool" now gives an empty file as the common base version
+   to the backend when dealing with the "both sides added, differently"
+   case.
+
+ * "git push -q" was not sufficiently quiet.
+
+ * When "git push" fails to update any refs, the client side did not
+   report an error correctly to the end user.
+
+ * "rebase" and "commit --amend" failed to work on commits with ancient
+   timestamps near year 1970.
+
+ * When asking for a tag to be pulled, "request-pull" did not show the
+   name of the tag prefixed with "tags/", which would have helped older
+   clients.
+
+ * "git submodule add $path" forgot to recompute the name to be stored
+   in .gitmodules when the submodule at $path was once added to the
+   superproject and already initialized.
+
+ * Many small corner case bugs on "git tag -n" was corrected.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.9.2.txt b/Documentation/RelNotes/1.7.9.2.txt
new file mode 100644
index 0000000000..e500da75dd
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.2.txt
@@ -0,0 +1,69 @@
+Git v1.7.9.2 Release Notes
+==========================
+
+Fixes since v1.7.9.1
+--------------------
+
+ * Bash completion script (in contrib/) did not like a pattern that
+   begins with a dash to be passed to __git_ps1 helper function.
+
+ * Adaptation of the bash completion script (in contrib/) for zsh
+   incorrectly listed all subcommands when "git <TAB><TAB>" was given
+   to ask for list of porcelain subcommands.
+
+ * The build procedure for profile-directed optimized binary was not
+   working very well.
+
+ * Some systems need to explicitly link -lcharset to get locale_charset().
+
+ * t5541 ignored user-supplied port number used for HTTP server testing.
+
+ * The error message emitted when we see an empty loose object was
+   not phrased correctly.
+
+ * The code to ask for password did not fall back to the terminal
+   input when GIT_ASKPASS is set but does not work (e.g. lack of X
+   with GUI askpass helper).
+
+ * We failed to give the true terminal width to any subcommand when
+   they are invoked with the pager, i.e. "git -p cmd".
+
+ * map_user() was not rewriting its output correctly, which resulted
+   in the user visible symptom that "git blame -e" sometimes showed
+   excess '>' at the end of email addresses.
+
+ * "git checkout -b" did not allow switching out of an unborn branch.
+
+ * When you have both .../foo and .../foo.git, "git clone .../foo" did not
+   favor the former but the latter.
+
+ * "git commit" refused to create a commit when entries added with
+   "add -N" remained in the index, without telling Git what their content
+   in the next commit should be. We should have created the commit without
+   these paths.
+
+ * "git diff --stat" said "files", "insertions", and "deletions" even
+   when it is showing one "file", one "insertion" or one "deletion".
+
+ * The output from "git diff --stat" for two paths that have the same
+   amount of changes showed graph bars of different length due to the
+   way we handled rounding errors.
+
+ * "git grep" did not pay attention to -diff (hence -binary) attribute.
+
+ * The transport programs (fetch, push, clone)ignored --no-progress
+   and showed progress when sending their output to a terminal.
+
+ * Sometimes error status detected by a check in an earlier phase of
+   "git receive-pack" (the other end of "git push") was lost by later
+   checks, resulting in false indication of success.
+
+ * "git rev-list --verify" sometimes skipped verification depending on
+   the phase of the moon, which dates back to 1.7.8.x series.
+
+ * Search box in "gitweb" did not accept non-ASCII characters correctly.
+
+ * Search interface of "gitweb" did not show multiple matches in the same file
+   correctly.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.9.3.txt b/Documentation/RelNotes/1.7.9.3.txt
new file mode 100644
index 0000000000..91c65012f9
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.3.txt
@@ -0,0 +1,51 @@
+Git v1.7.9.3 Release Notes
+==========================
+
+Fixes since v1.7.9.2
+--------------------
+
+ * "git p4" (in contrib/) submit the changes to a wrong place when the
+   "--use-client-spec" option is set.
+
+ * The config.mak.autogen generated by optional autoconf support tried
+   to link the binary with -lintl even when libintl.h is missing from
+   the system.
+
+ * When the filter driver exits before reading the content before the
+   main git process writes the contents to be filtered to the pipe to
+   it, the latter could be killed with SIGPIPE instead of ignoring
+   such an event as an error.
+
+ * "git add --refresh <pathspec>" used to warn about unmerged paths
+   outside the given pathspec.
+
+ * The bulk check-in codepath in "git add" streamed contents that
+   needs smudge/clean filters without running them, instead of punting
+   and delegating to the codepath to run filters after slurping
+   everything to core.
+
+ * "git branch --with $that" assumed incorrectly that the user will never
+   ask the question with nonsense value in $that.
+
+ * "git bundle create" produced a corrupt bundle file upon seeing
+   commits with excessively long subject line.
+
+ * When a remote helper exits before reading the blank line from the
+   main git process to signal the end of commands, the latter could be
+   killed with SIGPIPE. Instead we should ignore such event as a
+   non-error.
+
+ * The commit log template given with "git merge --edit" did not have
+   a short instructive text like what "git commit" gives.
+
+ * "git rev-list --verify-objects -q" omitted the extra verification
+   it needs to do over "git rev-list --objects -q" by mistake.
+
+ * "gitweb" used to drop warnings in the log file when "heads" view is
+   accessed in a repository whose HEAD does not point at a valid
+   branch.
+
+ * An invalid regular expression pattern given by an end user made
+   "gitweb" to return garbled response.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.9.4.txt b/Documentation/RelNotes/1.7.9.4.txt
new file mode 100644
index 0000000000..e5217a1889
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.4.txt
@@ -0,0 +1,24 @@
+Git v1.7.9.4 Release Notes
+==========================
+
+Fixes since v1.7.9.3
+--------------------
+
+ * The code to synthesize the fake ancestor tree used by 3-way merge
+   fallback in "git am" was not prepared to read a patch created with
+   a non-standard -p<num> value.
+
+ * "git bundle" did not record boundary commits correctly when there
+   are many of them.
+
+ * "git diff-index" and its friends at the plumbing level showed the
+   "diff --git" header and nothing else for a path whose cached stat
+   info is dirty without actual difference when asked to produce a
+   patch. This was a longstanding bug that we could have fixed long
+   time ago.
+
+ * "gitweb" did use quotemeta() to prepare search string when asked to
+   do a fixed-string project search, but did not use it by mistake and
+   used the user-supplied string instead.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.9.5.txt b/Documentation/RelNotes/1.7.9.5.txt
new file mode 100644
index 0000000000..95cc2bbf2c
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.5.txt
@@ -0,0 +1,23 @@
+Git v1.7.9.5 Release Notes
+==========================
+
+Fixes since v1.7.9.4
+--------------------
+
+ * When "git config" diagnoses an error in a configuration file and
+   shows the line number for the offending line, it miscounted if the
+   error was at the end of line.
+
+ * "git fast-import" accepted "ls" command with an empty path by
+   mistake.
+
+ * Various new-ish output decoration modes of "git grep" were not
+   documented in the manual's synopsis section.
+
+ * The "remaining" subcommand to "git rerere" was not documented.
+
+ * "gitweb" used to drop warnings in the log file when "heads" view is
+   accessed in a repository whose HEAD does not point at a valid
+   branch.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.9.6.txt b/Documentation/RelNotes/1.7.9.6.txt
new file mode 100644
index 0000000000..74bf8825e2
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.6.txt
@@ -0,0 +1,12 @@
+Git v1.7.9.6 Release Notes
+==========================
+
+Fixes since v1.7.9.5
+--------------------
+
+ * "git merge $tag" to merge an annotated tag always opens the editor
+   during an interactive edit session. v1.7.10 series introduced an
+   environment variable GIT_MERGE_AUTOEDIT to help older scripts decline
+   this behaviour, but the maintenance track should also support it.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.9.7.txt b/Documentation/RelNotes/1.7.9.7.txt
new file mode 100644
index 0000000000..59667d0f2a
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.7.txt
@@ -0,0 +1,13 @@
+Git v1.7.9.7 Release Notes
+==========================
+
+Fixes since v1.7.9.6
+--------------------
+
+ * An error message from 'git bundle' had an unmatched single quote pair in it.
+
+ * The way 'git fetch' implemented its connectivity check over
+   received objects was overly pessimistic, and wasted a lot of
+   cycles.
+
+Also contains minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.7.9.txt b/Documentation/RelNotes/1.7.9.txt
new file mode 100644
index 0000000000..95320aad5d
--- /dev/null
+++ b/Documentation/RelNotes/1.7.9.txt
@@ -0,0 +1,112 @@
+Git v1.7.9 Release Notes
+========================
+
+Updates since v1.7.8
+--------------------
+
+ * gitk updates accumulated since early 2011.
+
+ * git-gui updated to 0.16.0.
+
+ * git-p4 (in contrib/) updates.
+
+ * Git uses gettext to translate its most common interface messages
+   into the user's language if translations are available and the
+   locale is appropriately set. Distributors can drop new PO files
+   in po/ to add new translations.
+
+ * The code to handle username/password for HTTP transactions used in
+   "git push" & "git fetch" learned to talk "credential API" to
+   external programs to cache or store them, to allow integration with
+   platform native keychain mechanisms.
+
+ * The input prompts in the terminal use our own getpass() replacement
+   when possible. HTTP transactions used to ask for the username without
+   echoing back what was typed, but with this change you will see it as
+   you type.
+
+ * The internals of "revert/cherry-pick" have been tweaked to prepare
+   building more generic "sequencer" on top of the implementation that
+   drives them.
+
+ * "git rev-parse FETCH_HEAD" after "git fetch" without specifying
+   what to fetch from the command line will now show the commit that
+   would be merged if the command were "git pull".
+
+ * "git add" learned to stream large files directly into a packfile
+   instead of writing them into individual loose object files.
+
+ * "git checkout -B <current branch> <elsewhere>" is a more intuitive
+   way to spell "git reset --keep <elsewhere>".
+
+ * "git checkout" and "git merge" learned "--no-overwrite-ignore" option
+   to tell Git that untracked and ignored files are not expendable.
+
+ * "git commit --amend" learned "--no-edit" option to say that the
+   user is amending the tree being recorded, without updating the
+   commit log message.
+
+ * "git commit" and "git reset" re-learned the optimization to prime
+   the cache-tree information in the index, which makes it faster to
+   write a tree object out after the index entries are updated.
+
+ * "git commit" detects and rejects an attempt to stuff NUL byte in
+   the commit log message.
+
+ * "git commit" learned "-S" to GPG-sign the commit; this can be shown
+   with the "--show-signature" option to "git log".
+
+ * fsck and prune are relatively lengthy operations that still go
+   silent while making the end-user wait. They learned to give progress
+   output like other slow operations.
+
+ * The set of built-in function-header patterns for various languages
+   knows MATLAB.
+
+ * "git log --format='<format>'" learned new %g[nNeE] specifiers to
+   show information from the reflog entries when walking the reflog
+   (i.e. with "-g").
+
+ * "git pull" can be used to fetch and merge an annotated/signed tag,
+   instead of the tip of a topic branch. The GPG signature from the
+   signed tag is recorded in the resulting merge commit for later
+   auditing.
+
+ * "git log" learned "--show-signature" option to show the signed tag
+   that was merged that is embedded in the merge commit. It also can
+   show the signature made on the commit with "git commit -S".
+
+ * "git branch --edit-description" can be used to add descriptive text
+   to explain what a topic branch is about.
+
+ * "git fmt-merge-msg" learned to take the branch description into
+   account when preparing a merge summary that "git merge" records
+   when merging a local branch.
+
+ * "git request-pull" has been updated to convey more information
+   useful for integrators to decide if a topic is worth merging and
+   what is pulled is indeed what the requestor asked to pull,
+   including:
+
+   - the tip of the branch being requested to be merged;
+   - the branch description describing what the topic is about;
+   - the contents of the annotated tag, when requesting to pull a tag.
+
+ * "git pull" learned to notice 'pull.rebase' configuration variable,
+   which serves as a global fallback for setting 'branch.<name>.rebase'
+   configuration variable per branch.
+
+ * "git tag" learned "--cleanup" option to control how the whitespaces
+   and empty lines in tag message are cleaned up.
+
+ * "gitweb" learned to show side-by-side diff.
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.8
+------------------
+
+Unless otherwise noted, all the fixes since v1.7.8 in the maintenance
+releases are contained in this release (see release notes to them for
+details).
diff --git a/Documentation/RelNotes/1.8.0.1.txt b/Documentation/RelNotes/1.8.0.1.txt
new file mode 100644
index 0000000000..1f372fa0b5
--- /dev/null
+++ b/Documentation/RelNotes/1.8.0.1.txt
@@ -0,0 +1,64 @@
+Git v1.8.0.1 Release Notes
+==========================
+
+Fixes since v1.8.0
+------------------
+
+ * The configuration parser had an unnecessary hardcoded limit on
+   variable names that was not checked consistently.
+
+ * The "say" function in the test scaffolding incorrectly allowed
+   "echo" to interpret "\a" as if it were a C-string asking for a
+   BEL output.
+
+ * "git mergetool" feeds /dev/null as a common ancestor when dealing
+   with an add/add conflict, but p4merge backend cannot handle
+   it. Work it around by passing a temporary empty file.
+
+ * "git log -F -E --grep='<ere>'" failed to use the given <ere>
+   pattern as extended regular expression, and instead looked for the
+   string literally.
+
+ * "git grep -e pattern <tree>" asked the attribute system to read
+   "<tree>:.gitattributes" file in the working tree, which was
+   nonsense.
+
+ * A symbolic ref refs/heads/SYM was not correctly removed with "git
+   branch -d SYM"; the command removed the ref pointed by SYM
+   instead.
+
+ * Earlier we fixed documentation to hyphenate "remote-tracking branch"
+   to clarify that these are not a remote entity, but unhyphenated
+   spelling snuck in to a few places since then.
+
+ * "git pull --rebase" run while the HEAD is detached tried to find
+   the upstream branch of the detached HEAD (which by definition
+   does not exist) and emitted unnecessary error messages.
+
+ * The refs/replace hierarchy was not mentioned in the
+   repository-layout docs.
+
+ * Sometimes curl_multi_timeout() function suggested a wrong timeout
+   value when there is no file descriptors to wait on and the http
+   transport ended up sleeping for minutes in select(2) system call.
+   A workaround has been added for this.
+
+ * Various rfc2047 quoting issues around a non-ASCII name on the
+   From: line in the output from format-patch have been corrected.
+
+ * "git diff -G<pattern>" did not honor textconv filter when looking
+   for changes.
+
+ * Bash completion script (in contrib/) did not correctly complete a
+   lazy "git checkout $name_of_remote_tracking_branch_that_is_unique"
+   command line.
+
+ * RSS feed from "gitweb" had a xss hole in its title output.
+
+ * "git config --path $key" segfaulted on "[section] key" (a boolean
+   "true" spelled without "=", not "[section] key = true").
+
+ * "git checkout -b foo" while on an unborn branch did not say
+   "Switched to a new branch 'foo'" like other cases.
+
+Also contains other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.8.0.2.txt b/Documentation/RelNotes/1.8.0.2.txt
new file mode 100644
index 0000000000..8497e051de
--- /dev/null
+++ b/Documentation/RelNotes/1.8.0.2.txt
@@ -0,0 +1,34 @@
+Git v1.8.0.2 Release Notes
+==========================
+
+Fixes since v1.8.0.1
+--------------------
+
+ * Various codepaths have workaround for a common misconfiguration to
+   spell "UTF-8" as "utf8", but it was not used uniformly.  Most
+   notably, mailinfo (which is used by "git am") lacked this support.
+
+ * We failed to mention a file without any content change but whose
+   permission bit was modified, or (worse yet) a new file without any
+   content in the "git diff --stat" output.
+
+ * When "--stat-count" hides a diffstat for binary contents, the total
+   number of added and removed lines at the bottom was computed
+   incorrectly.
+
+ * When "--stat-count" hides a diffstat for unmerged paths, the total
+   number of affected files at the bottom of the "diff --stat" output
+   was computed incorrectly.
+
+ * "diff --shortstat" miscounted the total number of affected files
+   when there were unmerged paths.
+
+ * "git p4" used to try expanding malformed "$keyword$" that spans
+   across multiple lines.
+
+ * "git update-ref -d --deref SYM" to delete a ref through a symbolic
+   ref that points to it did not remove it correctly.
+
+ * Syntax highlighting in "gitweb" was not quite working.
+
+Also contains other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.8.0.3.txt b/Documentation/RelNotes/1.8.0.3.txt
new file mode 100644
index 0000000000..92b1e4b363
--- /dev/null
+++ b/Documentation/RelNotes/1.8.0.3.txt
@@ -0,0 +1,14 @@
+Git v1.8.0.3 Release Notes
+==========================
+
+Fixes since v1.8.0.2
+--------------------
+
+ * "git log -p -S<string>" did not apply the textconv filter while
+   looking for the <string>.
+
+ * In the documentation, some invalid example e-mail addresses were
+   formatted into mailto: links.
+
+Also contains many documentation updates backported from the 'master'
+branch that is preparing for the upcoming 1.8.1 release.
diff --git a/Documentation/RelNotes/1.8.0.txt b/Documentation/RelNotes/1.8.0.txt
new file mode 100644
index 0000000000..63d6e4afa4
--- /dev/null
+++ b/Documentation/RelNotes/1.8.0.txt
@@ -0,0 +1,267 @@
+Git v1.8.0 Release Notes
+========================
+
+Backward compatibility notes
+----------------------------
+
+In the next major release (not *this* one), we will change the
+behavior of the "git push" command.
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  We will use the "simple" semantics that pushes the
+current branch to the branch with the same name, only when the current
+branch is set to integrate with that remote branch.  There is a user
+preference configuration variable "push.default" to change this, and
+"git push" will warn about the upcoming change until you set this
+variable in this release.
+
+"git branch --set-upstream" is deprecated and may be removed in a
+relatively distant future.  "git branch [-u|--set-upstream-to]" has
+been introduced with a saner order of arguments.
+
+
+Updates since v1.7.12
+---------------------
+
+UI, Workflows & Features
+
+ * A credential helper for Win32 to allow access to the keychain of
+   the logged-in user has been added.
+
+ * An initial port to HP NonStop.
+
+ * A credential helper to allow access to the Gnome keyring has been
+   added.
+
+ * When "git am" sanitizes the "Subject:" line, we strip the prefix from
+   "Re: subject" and also from a less common "re: subject", but left
+   the even less common "RE: subject" intact.  Now we strip that too.
+
+ * It was tempting to say "git branch --set-upstream origin/master",
+   but that tells Git to arrange the local branch "origin/master" to
+   integrate with the currently checked out branch, which is highly
+   unlikely what the user meant.  The option is deprecated; use the
+   new "--set-upstream-to" (with a short-and-sweet "-u") option
+   instead.
+
+ * "git cherry-pick" learned the "--allow-empty-message" option to
+   allow it to replay a commit without any log message.
+
+ * After "git cherry-pick -s" gave control back to the user asking
+   help to resolve conflicts, concluding "git commit" used to need to
+   be run with "-s" if the user wants to sign it off; now the command
+   leaves the sign-off line in the log template.
+
+ * "git daemon" learned the "--access-hook" option to allow an
+   external command to decline service based on the client address,
+   repository path, etc.
+
+ * "git difftool --dir-diff" learned to use symbolic links to prepare
+   a temporary copy of the working tree when available.
+
+ * "git grep" learned to use a non-standard pattern type by default if
+   a configuration variable tells it to.
+
+ * Accumulated updates to "git gui" has been merged.
+
+ * "git log -g" learned the "--grep-reflog=<pattern>" option to limit
+   its output to commits with a reflog message that matches the given
+   pattern.
+
+ * "git merge-base" learned the "--is-ancestor A B" option to tell if A is
+   an ancestor of B.  The result is indicated by its exit status code.
+
+ * "git mergetool" now allows users to override the actual command used
+   with the mergetool.$name.cmd configuration variable even for built-in
+   mergetool backends.
+
+ * "git rebase -i" learned the "--edit-todo" option to open an editor
+   to edit the instruction sheet.
+
+
+Foreign Interface
+
+ * "git svn" has been updated to work with SVN 1.7.
+
+ * "git p4" learned the "--conflicts" option to specify what to do when
+   encountering a conflict during "p4 submit".
+
+
+Performance, Internal Implementation, etc.
+
+ * Git ships with a fall-back regexp implementation for platforms with
+   buggy regexp library, but it was easy for people to keep using their
+   platform regexp by mistake.  A new test has been added to check this.
+
+ * The "check-docs" build target has been updated and greatly
+   simplified.
+
+ * The test suite is run under MALLOC_CHECK_ when running with a glibc
+   that supports the feature.
+
+ * The documentation in the TeXinfo format was using indented output
+   for materials meant to be examples that are better typeset in
+   monospace.
+
+ * Compatibility wrapper around some mkdir(2) implementations that
+   reject parameters with trailing slash has been introduced.
+
+ * Compatibility wrapper for systems that lack usable setitimer() has
+   been added.
+
+ * The option parsing of "git checkout" had error checking, dwim and
+   defaulting missing options, all mixed in the code, and issuing an
+   appropriate error message with useful context was getting harder.
+   The code has been reorganized to allow giving a proper diagnosis
+   when the user says "git checkout -b -t foo bar" (e.g. "-t" is not a
+   good name for a branch).
+
+ * Many internal uses of a "git merge-base" equivalent were only to see
+   if one commit fast-forwards to the other, which did not need the
+   full set of merge bases to be computed. They have been updated to
+   use less expensive checks.
+
+ * The heuristics to detect and silently convert latin1 to utf8 when
+   we were told to use utf-8 in the log message has been transplanted
+   from "mailinfo" to "commit" and "commit-tree".
+
+ * Messages given by "git <subcommand> -h" from many subcommands have
+   been marked for translation.
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.7.12
+-------------------
+
+Unless otherwise noted, all the fixes since v1.7.12 in the
+maintenance track are contained in this release (see release notes
+to them for details).
+
+ * The attribute system may be asked for a path that itself or its
+   leading directories no longer exists in the working tree, and it is
+   fine if we cannot open .gitattribute file in such a case.  Failure
+   to open per-directory .gitattributes with error status other than
+   ENOENT and ENOTDIR should be diagnosed, but it wasn't.
+
+ * When looking for $HOME/.gitconfig etc., it is OK if we cannot read
+   them because they do not exist, but we did not diagnose existing
+   files that we cannot read.
+
+ * When "git am" is fed an input that has multiple "Content-type: ..."
+   header, it did not grok charset= attribute correctly.
+
+ * "git am" mishandled a patch attached as application/octet-stream
+   (e.g. not text/*); Content-Transfer-Encoding (e.g. base64) was not
+   honored correctly.
+
+ * "git blame MAKEFILE" run in a history that has "Makefile" but not
+   "MAKEFILE" should say "No such file MAKEFILE in HEAD", but got
+   confused on a case insensitive filesystem and failed to do so.
+
+ * Even during a conflicted merge, "git blame $path" always meant to
+   blame uncommitted changes to the "working tree" version; make it
+   more useful by showing cleanly merged parts as coming from the other
+   branch that is being merged.
+
+ * It was unclear in the documentation for "git blame" that it is
+   unnecessary for users to use the "--follow" option.
+
+ * Output from "git branch -v" contains "(no branch)" that could be
+   localized, but the code to align it along with the names of
+   branches was counting in bytes, not in display columns.
+
+ * "git cherry-pick A C B" used to replay changes in A and then B and
+   then C if these three commits had committer timestamps in that
+   order, which is not what the user who said "A C B" naturally
+   expects.
+
+ * A repository created with "git clone --single" had its fetch
+   refspecs set up just like a clone without "--single", leading the
+   subsequent "git fetch" to slurp all the other branches, defeating
+   the whole point of specifying "only this branch".
+
+ * Documentation talked about "first line of commit log" when it meant
+   the title of the commit.  The description was clarified by defining
+   how the title is decided and rewording the casual mention of "first
+   line" to "title".
+
+ * "git cvsimport" did not thoroughly cleanse tag names that it
+   inferred from the names of the tags it obtained from CVS, which
+   caused "git tag" to barf and stop the import in the middle.
+
+ * Earlier we made the diffstat summary line that shows the number of
+   lines added/deleted localizable, but it was found irritating having
+   to see them in various languages on a list whose discussion language
+   is English, and this change has been reverted.
+
+ * "git fetch --all", when passed "--no-tags", did not honor the
+   "--no-tags" option while fetching from individual remotes (the same
+   issue existed with "--tags", but the combination "--all --tags" makes
+   much less sense than "--all --no-tags").
+
+ * "git fetch" over http had an old workaround for an unlikely server
+   misconfiguration; it turns out that this hurts debuggability of the
+   configuration in general, and has been reverted.
+
+ * "git fetch" over http advertised that it supports "deflate", which
+   is much less common, and did not advertise the more common "gzip" on
+   its Accept-Encoding header.
+
+ * "git fetch" over the dumb-http revision walker could segfault when
+   curl's multi interface was used.
+
+ * "git gc --auto" notified the user that auto-packing has triggered
+    even under the "--quiet" option.
+
+ * After "gitk" showed the contents of a tag, neither "Reread
+   references" nor "Reload" updated what is shown as the
+   contents of it when the user overwrote the tag with "git tag -f".
+
+ * "git log --all-match --grep=A --grep=B" ought to show commits that
+   mention both A and B, but when these three options are used with
+   --author or --committer, it showed commits that mention either A or
+   B (or both) instead.
+
+ * The "-Xours" backend option to "git merge -s recursive" was ignored
+   for binary files.
+
+ * "git p4", when "--use-client-spec" and "--detect-branches" are used
+   together, misdetected branches.
+
+ * "git receive-pack" (the counterpart to "git push") did not give
+   progress output while processing objects it received to the user
+   when run over the smart-http protocol.
+
+ * When you misspell the command name you give to the "exec" action in
+   the "git rebase -i" instruction sheet you were told that 'rebase' is not a
+   git subcommand from "git rebase --continue".
+
+ * The subcommand in "git remote" to remove a defined remote was
+   "rm" and the command did not take a fully-spelled "remove".
+
+ * The interactive prompt that "git send-email" gives was error prone. It
+   asked "What e-mail address do you want to use?" with the address it
+   guessed (correctly) the user would want to use in its prompt,
+   tempting the user to say "y". But the response was taken as "No,
+   please use 'y' as the e-mail address instead", which is most
+   certainly not what the user meant.
+
+ * "git show --format='%ci'" did not give the timestamp correctly for
+   commits created without human readable name on the "committer" line.
+
+ * "git show --quiet" ought to be a synonym for "git show -s", but
+   wasn't.
+
+ * "git submodule frotz" was not diagnosed as "frotz" being an unknown
+   subcommand to "git submodule"; the user instead got a complaint
+   that "git submodule status" was run with an unknown path "frotz".
+
+ * "git status" honored the ignore=dirty settings in .gitmodules but
+   "git commit" didn't.
+
+ * "gitweb" did not give the correct committer timezone in its feed
+   output due to a typo.
diff --git a/Documentation/RelNotes/1.8.1.1.txt b/Documentation/RelNotes/1.8.1.1.txt
new file mode 100644
index 0000000000..6cde07ba29
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.1.txt
@@ -0,0 +1,87 @@
+Git 1.8.1.1 Release Notes
+=========================
+
+Fixes since v1.8.1
+------------------
+
+ * The attribute mechanism didn't allow limiting attributes to be
+   applied to only a single directory itself with "path/" like the
+   exclude mechanism does.
+
+ * When attempting to read the XDG-style $HOME/.config/git/config and
+   finding that $HOME/.config/git is a file, we gave a wrong error
+   message, instead of treating the case as "a custom config file does
+   not exist there" and moving on.
+
+ * After failing to create a temporary file using mkstemp(), failing
+   pathname was not reported correctly on some platforms.
+
+ * http transport was wrong to ask for the username when the
+   authentication is done by certificate identity.
+
+ * The behaviour visible to the end users was confusing, when they
+   attempt to kill a process spawned in the editor that was in turn
+   launched by Git with SIGINT (or SIGQUIT), as Git would catch that
+   signal and die.  We ignore these signals now.
+
+ * A child process that was killed by a signal (e.g. SIGINT) was
+   reported in an inconsistent way depending on how the process was
+   spawned by us, with or without a shell in between.
+
+ * After "git add -N" and then writing a tree object out of the
+   index, the cache-tree data structure got corrupted.
+
+ * "git apply" misbehaved when fixing whitespace breakages by removing
+   excess trailing blank lines in some corner cases.
+
+ * A tar archive created by "git archive" recorded a directory in a
+   way that made NetBSD's implementation of "tar" sometimes unhappy.
+
+ * When "git clone --separate-git-dir=$over_there" is interrupted, it
+   failed to remove the real location of the $GIT_DIR it created.
+   This was most visible when interrupting a submodule update.
+
+ * "git fetch --mirror" and fetch that uses other forms of refspec
+   with wildcard used to attempt to update a symbolic ref that match
+   the wildcard on the receiving end, which made little sense (the
+   real ref that is pointed at by the symbolic ref would be updated
+   anyway).  Symbolic refs no longer are affected by such a fetch.
+
+ * The "log --graph" codepath fell into infinite loop in some
+   corner cases.
+
+ * "git merge" started calling prepare-commit-msg hook like "git
+   commit" does some time ago, but forgot to pay attention to the exit
+   status of the hook.
+
+ * "git pack-refs" that ran in parallel to another process that
+   created new refs had a race that can lose new ones.
+
+ * When a line to be wrapped has a solid run of non space characters
+   whose length exactly is the wrap width, "git shortlog -w" failed
+   to add a newline after such a line.
+
+ * The way "git svn" asked for password using SSH_ASKPASS and
+   GIT_ASKPASS was not in line with the rest of the system.
+
+ * "gitweb", when sorting by age to show repositories with new
+   activities first, used to sort repositories with absolutely
+   nothing in it early, which was not very useful.
+
+ * "gitweb", when sorting by age to show repositories with new
+   activities first, used to sort repositories with absolutely
+   nothing in it early, which was not very useful.
+
+ * When autoconf is used, any build on a different commit always ran
+   "config.status --recheck" even when unnecessary.
+
+ * Some scripted programs written in Python did not get updated when
+   PYTHON_PATH changed.
+
+ * We have been carrying a translated and long-unmaintained copy of an
+   old version of the tutorial; removed.
+
+ * Portability issues in many self-test scripts have been addressed.
+
+
+Also contains other minor fixes and documentation updates.
diff --git a/Documentation/RelNotes/1.8.1.2.txt b/Documentation/RelNotes/1.8.1.2.txt
new file mode 100644
index 0000000000..5ab7b18906
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.2.txt
@@ -0,0 +1,25 @@
+Git 1.8.1.2 Release Notes
+=========================
+
+Fixes since v1.8.1.1
+--------------------
+
+ * An element on GIT_CEILING_DIRECTORIES list that does not name the
+   real path to a directory (i.e. a symbolic link) could have caused
+   the GIT_DIR discovery logic to escape the ceiling.
+
+ * Command line completion for "tcsh" emitted an unwanted space
+   after completing a single directory name.
+
+ * Command line completion leaked an unnecessary error message while
+   looking for possible matches with paths in <tree-ish>.
+
+ * "git archive" did not record uncompressed size in the header when
+   streaming a zip archive, which confused some implementations of unzip.
+
+ * When users spelled "cc:" in lowercase in the fake "header" in the
+   trailer part, "git send-email" failed to pick up the addresses from
+   there. As e-mail headers field names are case insensitive, this
+   script should follow suit and treat "cc:" and "Cc:" the same way.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.3.txt b/Documentation/RelNotes/1.8.1.3.txt
new file mode 100644
index 0000000000..681cb35c0a
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.3.txt
@@ -0,0 +1,47 @@
+Git 1.8.1.3 Release Notes
+=========================
+
+Fixes since v1.8.1.2
+--------------------
+
+ * The attribute mechanism didn't allow limiting attributes to be
+   applied to only a single directory itself with "path/" like the
+   exclude mechanism does.  The fix for this in 1.8.1.2 had
+   performance degradations.
+
+ * Command line completion code was inadvertently made incompatible with
+   older versions of bash by using a newer array notation.
+
+ * Scripts to test bash completion was inherently flaky as it was
+   affected by whatever random things the user may have on $PATH.
+
+ * A fix was added to the build procedure to work around buggy
+   versions of ccache broke the auto-generation of dependencies, which
+   unfortunately is still relevant because some people use ancient
+   distros.
+
+ * We used to stuff "user@" and then append what we read from
+   /etc/mailname to come up with a default e-mail ident, but a bug
+   lost the "user@" part.
+
+ * "git am" did not parse datestamp correctly from Hg generated patch,
+   when it is run in a locale outside C (or en).
+
+ * Attempt to "branch --edit-description" an existing branch, while
+   being on a detached HEAD, errored out.
+
+ * "git cherry-pick" did not replay a root commit to an unborn branch.
+
+ * We forgot to close the file descriptor reading from "gpg" output,
+   killing "git log --show-signature" on a long history.
+
+ * "git rebase --preserve-merges" lost empty merges in recent versions
+   of Git.
+
+ * Rebasing the history of superproject with change in the submodule
+   has been broken since v1.7.12.
+
+ * A failure to push due to non-ff while on an unborn branch
+   dereferenced a NULL pointer when showing an error message.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.4.txt b/Documentation/RelNotes/1.8.1.4.txt
new file mode 100644
index 0000000000..22af1d1643
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.4.txt
@@ -0,0 +1,11 @@
+Git 1.8.1.4 Release Notes
+=========================
+
+Fixes since v1.8.1.3
+--------------------
+
+ * "git imap-send" talking over imaps:// did make sure it received a
+   valid certificate from the other end, but did not check if the
+   certificate matched the host it thought it was talking to.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.5.txt b/Documentation/RelNotes/1.8.1.5.txt
new file mode 100644
index 0000000000..efa68aef22
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.5.txt
@@ -0,0 +1,47 @@
+Git 1.8.1.5 Release Notes
+=========================
+
+Fixes since v1.8.1.4
+--------------------
+
+ * Given a string with a multi-byte character that begins with '-' on
+   the command line where an option is expected, the option parser
+   used just one byte of the unknown letter when reporting an error.
+
+ * In v1.8.1, the attribute parser was tightened too restrictive to
+   error out upon seeing an entry that begins with an ! (exclamation),
+   which may confuse users to expect a "negative match", which does
+   not exist.  This has been demoted to a warning; such an entry is
+   still ignored.
+
+ * "git apply --summary" has been taught to make sure the similarity
+   value shown in its output is sensible, even when the input had a
+   bogus value.
+
+ * "git clean" showed what it was going to do, but sometimes ended
+   up finding that it was not allowed to do so, which resulted in a
+   confusing output (e.g. after saying that it will remove an
+   untracked directory, it found an embedded git repository there
+   which it is not allowed to remove).  It now performs the actions
+   and then reports the outcome more faithfully.
+
+ * "git clone" used to allow --bare and --separate-git-dir=$there
+   options at the same time, which was nonsensical.
+
+ * "git cvsimport" mishandled timestamps at DST boundary.
+
+ * We used to have an arbitrary 32 limit for combined diff input,
+   resulting in incorrect number of leading colons shown when showing
+   the "--raw --cc" output.
+
+ * The smart HTTP clients forgot to verify the content-type that comes
+   back from the server side to make sure that the request is being
+   handled properly.
+
+ * "git help remote-helpers" failed to find the documentation.
+
+ * "gitweb" pages served over HTTPS, when configured to show picon or
+   gravatar, referred to these external resources to be fetched via
+   HTTP, resulting in mixed contents warning in browsers.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.6.txt b/Documentation/RelNotes/1.8.1.6.txt
new file mode 100644
index 0000000000..c15cf2e805
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.6.txt
@@ -0,0 +1,39 @@
+Git 1.8.1.6 Release Notes
+=========================
+
+Fixes since v1.8.1.5
+--------------------
+
+ * An earlier change to the attribute system introduced at v1.8.1.2 by
+   mistake stopped a pattern "dir" (without trailing slash) from
+   matching a directory "dir" (it only wanted to allow pattern "dir/"
+   to also match).
+
+ * The code to keep track of what directory names are known to Git on
+   platforms with case insensitive filesystems can get confused upon a
+   hash collision between these pathnames and looped forever.
+
+ * When the "--prefix" option is used to "checkout-index", the code
+   did not pick the correct output filter based on the attribute
+   setting.
+
+ * Annotated tags outside refs/tags/ hierarchy were not advertised
+   correctly to the ls-remote and fetch with recent version of Git.
+
+ * The logic used by "git diff -M --stat" to shorten the names of
+   files before and after a rename did not work correctly when the
+   common prefix and suffix between the two filenames overlapped.
+
+ * "git update-index -h" did not do the usual "-h(elp)" thing.
+
+ * perl/Git.pm::cat_blob slurped everything in core only to write it
+   out to a file descriptor, which was not a very smart thing to do.
+
+ * The SSL peer verification done by "git imap-send" did not ask for
+   Server Name Indication (RFC 4366), failing to connect SSL/TLS
+   sites that serve multiple hostnames on a single IP.
+
+ * "git bundle verify" did not say "records a complete history" for a
+   bundle that does not have any prerequisites.
+
+Also contains various documentation fixes.
diff --git a/Documentation/RelNotes/1.8.1.txt b/Documentation/RelNotes/1.8.1.txt
new file mode 100644
index 0000000000..d6f9555923
--- /dev/null
+++ b/Documentation/RelNotes/1.8.1.txt
@@ -0,0 +1,241 @@
+Git v1.8.1 Release Notes
+========================
+
+Backward compatibility notes
+----------------------------
+
+In the next major release (not *this* one), we will change the
+behavior of the "git push" command.
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  We will use the "simple" semantics that pushes the
+current branch to the branch with the same name, only when the current
+branch is set to integrate with that remote branch.  There is a user
+preference configuration variable "push.default" to change this, and
+"git push" will warn about the upcoming change until you set this
+variable in this release.
+
+"git branch --set-upstream" is deprecated and may be removed in a
+relatively distant future.  "git branch [-u|--set-upstream-to]" has
+been introduced with a saner order of arguments to replace it.
+
+
+Updates since v1.8.0
+--------------------
+
+UI, Workflows & Features
+
+ * Command-line completion scripts for tcsh and zsh have been added.
+
+ * "git-prompt" scriptlet (in contrib/completion) can be told to paint
+   pieces of the hints in the prompt string in colors.
+
+ * Some documentation pages that used to ship only in the plain text
+   format are now formatted in HTML as well.
+
+ * We used to have a workaround for a bug in ancient "less" that
+   causes it to exit without any output when the terminal is resized.
+   The bug has been fixed in "less" version 406 (June 2007), and the
+   workaround has been removed in this release.
+
+ * When "git checkout" checks out a branch, it tells the user how far
+   behind (or ahead) the new branch is relative to the remote tracking
+   branch it builds upon.  The message now also advises how to sync
+   them up by pushing or pulling.  This can be disabled with the
+   advice.statusHints configuration variable.
+
+ * "git config --get" used to diagnose presence of multiple
+   definitions of the same variable in the same configuration file as
+   an error, but it now applies the "last one wins" rule used by the
+   internal configuration logic.  Strictly speaking, this may be an
+   API regression but it is expected that nobody will notice it in
+   practice.
+
+ * A new configuration variable "diff.context" can be used to
+   give the default number of context lines in the patch output, to
+   override the hardcoded default of 3 lines.
+
+ * "git format-patch" learned the "--notes=<ref>" option to give
+   notes for the commit after the three-dash lines in its output.
+
+ * "git log -p -S<string>" now looks for the <string> after applying
+   the textconv filter (if defined); earlier it inspected the contents
+   of the blobs without filtering.
+
+ * "git log --grep=<pcre>" learned to honor the "grep.patterntype"
+   configuration set to "perl".
+
+ * "git replace -d <object>" now interprets <object> as an extended
+   SHA-1 (e.g. HEAD~4 is allowed), instead of only accepting full hex
+   object name.
+
+ * "git rm $submodule" used to punt on removing a submodule working
+   tree to avoid losing the repository embedded in it.  Because
+   recent git uses a mechanism to separate the submodule repository
+   from the submodule working tree, "git rm" learned to detect this
+   case and removes the submodule working tree when it is safe to do so.
+
+ * "git send-email" used to prompt for the sender address, even when
+   the committer identity is well specified (e.g. via user.name and
+   user.email configuration variables).  The command no longer gives
+   this prompt when not necessary.
+
+ * "git send-email" did not allow non-address garbage strings to
+   appear after addresses on Cc: lines in the patch files (and when
+   told to pick them up to find more recipients), e.g.
+
+     Cc: Stable Kernel <stable@xxxxx> # for v3.2 and up
+
+   The command now strips " # for v3.2 and up" part before adding the
+   remainder of this line to the list of recipients.
+
+ * "git submodule add" learned to add a new submodule at the same
+   path as the path where an unrelated submodule was bound to in an
+   existing revision via the "--name" option.
+
+ * "git submodule sync" learned the "--recursive" option.
+
+ * "diff.submodule" configuration variable can be used to give custom
+   default value to the "git diff --submodule" option.
+
+ * "git symbolic-ref" learned the "-d $symref" option to delete the
+   named symbolic ref, which is more intuitive way to spell it than
+   "update-ref -d --no-deref $symref".
+
+
+Foreign Interface
+
+ * "git cvsimport" can be told to record timezones (other than GMT)
+   per-author via its author info file.
+
+ * The remote helper interface to interact with subversion
+   repositories (one of the GSoC 2012 projects) has been merged.
+
+ * A new remote-helper interface for Mercurial has been added to
+   contrib/remote-helpers.
+
+ * The documentation for git(1) was pointing at a page at an external
+   site for the list of authors that no longer existed.  The link has
+   been updated to point at an alternative site.
+
+
+Performance, Internal Implementation, etc.
+
+ * Compilation on Cygwin with newer header files are supported now.
+
+ * A couple of low-level implementation updates on MinGW.
+
+ * The logic to generate the initial advertisement from "upload-pack"
+   (i.e. what is invoked by "git fetch" on the other side of the
+   connection) to list what refs are available in the repository has
+   been optimized.
+
+ * The logic to find set of attributes that match a given path has
+   been optimized.
+
+ * Use preloadindex in "git diff-index" and "git update-index", which
+   has a nice speedup on systems with slow stat calls (and even on
+   Linux).
+
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.8.0
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.0 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * The configuration parser had an unnecessary hardcoded limit on
+   variable names that was not checked consistently.
+
+ * The "say" function in the test scaffolding incorrectly allowed
+   "echo" to interpret "\a" as if it were a C-string asking for a
+   BEL output.
+
+ * "git mergetool" feeds /dev/null as a common ancestor when dealing
+   with an add/add conflict, but p4merge backend cannot handle
+   it. Work it around by passing a temporary empty file.
+
+ * "git log -F -E --grep='<ere>'" failed to use the given <ere>
+   pattern as extended regular expression, and instead looked for the
+   string literally.
+
+ * "git grep -e pattern <tree>" asked the attribute system to read
+   "<tree>:.gitattributes" file in the working tree, which was
+   nonsense.
+
+ * A symbolic ref refs/heads/SYM was not correctly removed with "git
+   branch -d SYM"; the command removed the ref pointed by SYM
+   instead.
+
+ * Update "remote tracking branch" in the documentation to
+   "remote-tracking branch".
+
+ * "git pull --rebase" run while the HEAD is detached tried to find
+   the upstream branch of the detached HEAD (which by definition
+   does not exist) and emitted unnecessary error messages.
+
+ * The refs/replace hierarchy was not mentioned in the
+   repository-layout docs.
+
+ * Various rfc2047 quoting issues around a non-ASCII name on the
+   From: line in the output from format-patch have been corrected.
+
+ * Sometimes curl_multi_timeout() function suggested a wrong timeout
+   value when there is no file descriptor to wait on and the http
+   transport ended up sleeping for minutes in select(2) system call.
+   A workaround has been added for this.
+
+ * For a fetch refspec (or the result of applying wildcard on one),
+   we always want the RHS to map to something inside "refs/"
+   hierarchy, but the logic to check it was not exactly right.
+   (merge 5c08c1f jc/maint-fetch-tighten-refname-check later to maint).
+
+ * "git diff -G<pattern>" did not honor textconv filter when looking
+   for changes.
+
+ * Some HTTP servers ask for auth only during the actual packing phase
+   (not in ls-remote phase); this is not really a recommended
+   configuration, but the clients used to fail to authenticate with
+   such servers.
+   (merge 2e736fd jk/maint-http-half-auth-fetch later to maint).
+
+ * "git p4" used to try expanding malformed "$keyword$" that spans
+   across multiple lines.
+
+ * Syntax highlighting in "gitweb" was not quite working.
+
+ * RSS feed from "gitweb" had a xss hole in its title output.
+
+ * "git config --path $key" segfaulted on "[section] key" (a boolean
+   "true" spelled without "=", not "[section] key = true").
+
+ * "git checkout -b foo" while on an unborn branch did not say
+   "Switched to a new branch 'foo'" like other cases.
+
+ * Various codepaths have workaround for a common misconfiguration to
+   spell "UTF-8" as "utf8", but it was not used uniformly.  Most
+   notably, mailinfo (which is used by "git am") lacked this support.
+
+ * We failed to mention a file without any content change but whose
+   permission bit was modified, or (worse yet) a new file without any
+   content in the "git diff --stat" output.
+
+ * When "--stat-count" hides a diffstat for binary contents, the total
+   number of added and removed lines at the bottom was computed
+   incorrectly.
+
+ * When "--stat-count" hides a diffstat for unmerged paths, the total
+   number of affected files at the bottom of the "diff --stat" output
+   was computed incorrectly.
+
+ * "diff --shortstat" miscounted the total number of affected files
+   when there were unmerged paths.
+
+ * "update-ref -d --deref SYM" to delete a ref through a symbolic ref
+   that points to it did not remove it correctly.
diff --git a/Documentation/RelNotes/1.8.2.1.txt b/Documentation/RelNotes/1.8.2.1.txt
new file mode 100644
index 0000000000..769a6fc06c
--- /dev/null
+++ b/Documentation/RelNotes/1.8.2.1.txt
@@ -0,0 +1,115 @@
+Git v1.8.2.1 Release Notes
+==========================
+
+Fixes since v1.8.2
+------------------
+
+ * An earlier change to the attribute system introduced at v1.8.1.2 by
+   mistake stopped a pattern "dir" (without trailing slash) from
+   matching a directory "dir" (it only wanted to allow pattern "dir/"
+   to also match).
+
+ * Verification of signed tags were not done correctly when not in C
+   or en/US locale.
+
+ * 'git commit -m "$msg"' used to add an extra newline even when
+   $msg already ended with one.
+
+ * The "--match=<pattern>" option of "git describe", when used with
+   "--all" to allow refs that are not annotated tags to be used as a
+   base of description, did not restrict the output from the command
+   to those that match the given pattern.
+
+ * An aliased command spawned from a bare repository that does not say
+   it is bare with "core.bare = yes" is treated as non-bare by mistake.
+
+ * When "format-patch" quoted a non-ascii strings on the header files,
+   it incorrectly applied rfc2047 and chopped a single character in
+   the middle of it.
+
+ * "git archive" reports a failure when asked to create an archive out
+   of an empty tree.  It would be more intuitive to give an empty
+   archive back in such a case.
+
+ * "git tag -f <tag>" always said "Updated tag '<tag>'" even when
+   creating a new tag (i.e. not overwriting nor updating).
+
+ * "git cmd -- ':(top'" was not diagnosed as an invalid syntax, and
+   instead the parser kept reading beyond the end of the string.
+
+ * Annotated tags outside refs/tags/ hierarchy were not advertised
+   correctly to the ls-remote and fetch with recent version of Git.
+
+ * The code to keep track of what directory names are known to Git on
+   platforms with case insensitive filesystems can get confused upon a
+   hash collision between these pathnames and looped forever.
+
+ * The logic used by "git diff -M --stat" to shorten the names of
+   files before and after a rename did not work correctly when the
+   common prefix and suffix between the two filenames overlapped.
+
+ * "git submodule update", when recursed into sub-submodules, did not
+   accumulate the prefix paths.
+
+ * "git am $maildir/" applied messages in an unexpected order; sort
+   filenames read from the maildir/ in a way that is more likely to
+   sort messages in the order the writing MUA meant to, by sorting
+   numeric segment in numeric order and non-numeric segment in
+   alphabetical order.
+
+ * When export-subst is used, "zip" output recorded incorrect
+   size of the file.
+
+ * Some platforms and users spell UTF-8 differently; retry with the
+   most official "UTF-8" when the system does not understand the
+   user-supplied encoding name that are the common alternative
+   spellings of UTF-8.
+
+ * "git branch" did not bother to check nonsense command line
+   parameters and issue errors in many cases.
+
+ * "git update-index -h" did not do the usual "-h(elp)" thing.
+
+ * perl/Git.pm::cat_blob slurped everything in core only to write it
+   out to a file descriptor, which was not a very smart thing to do.
+
+ * The SSL peer verification done by "git imap-send" did not ask for
+   Server Name Indication (RFC 4366), failing to connect SSL/TLS
+   sites that serve multiple hostnames on a single IP.
+
+ * "git index-pack" had a buffer-overflow while preparing an
+   informational message when the translated version of it was too
+   long.
+
+ * Clarify in the documentation "what" gets pushed to "where" when the
+   command line to "git push" does not say these explicitly.
+
+ * In "git reflog expire", REACHABLE bit was not cleared from the
+   correct objects.
+
+ * The "--color=<when>" argument to the commands in the diff family
+   was described poorly.
+
+ * The arguments given to pre-rebase hook were not documented.
+
+ * The v4 index format was not documented.
+
+ * The "--match=<pattern>" argument "git describe" takes uses glob
+   pattern but it wasn't obvious from the documentation.
+
+ * Some sources failed to compile on systems that lack NI_MAXHOST in
+   their system header (e.g. z/OS).
+
+ * Add an example use of "--env-filter" in "filter-branch"
+   documentation.
+
+ * "git bundle verify" did not say "records a complete history" for a
+   bundle that does not have any prerequisites.
+
+ * In the v1.8.0 era, we changed symbols that do not have to be global
+   to file scope static, but a few functions in graph.c were used by
+   CGit from sideways bypassing the entry points of the API the
+   in-tree users use.
+
+ * "git merge-tree" had a typo in the logic to detect d/f conflicts,
+   which caused it to segfault in some cases.
diff --git a/Documentation/RelNotes/1.8.2.2.txt b/Documentation/RelNotes/1.8.2.2.txt
new file mode 100644
index 0000000000..708df1ae19
--- /dev/null
+++ b/Documentation/RelNotes/1.8.2.2.txt
@@ -0,0 +1,61 @@
+Git v1.8.2.2 Release Notes
+==========================
+
+Fixes since v1.8.2.1
+--------------------
+
+ * Zsh completion forgot that '%' character used to signal untracked
+   files needs to be escaped with another '%'.
+
+ * A commit object whose author or committer ident are malformed
+   crashed some code that trusted that a name, an email and an
+   timestamp can always be found in it.
+
+ * The new core.commentchar configuration was not applied to a few
+   places.
+
+ * "git pull --rebase" did not pass "-v/-q" options to underlying
+   "git rebase".
+
+ * When receive-pack detects error in the pack header it received in
+   order to decide which of unpack-objects or index-pack to run, it
+   returned without closing the error stream, which led to a hang
+   sideband thread.
+
+ * "git diff --diff-algorithm=algo" was understood by the command line
+   parser, but "git diff --diff-algorithm algo" was not.
+
+ * "git log -S/-G" started paying attention to textconv filter, but
+   there was no way to disable this.  Make it honor --no-textconv
+   option.
+
+ * "git merge $(git rev-parse v1.8.2)" behaved quite differently from
+   "git merge v1.8.2", as if v1.8.2 were written as v1.8.2^0 and did
+   not pay much attention to the annotated tag payload.  Make the code
+   notice the type of the tag object, in addition to the dwim_ref()
+   based classification the current code uses (i.e. the name appears
+   in refs/tags/) to decide when to special case merging of tags.
+
+ * "git cherry-pick" and "git revert" can take more than one commit
+   on the command line these days, but it was not mentioned on the usage
+   text.
+
+ * Perl scripts like "git-svn" closed (not redirecting to /dev/null)
+   the standard error stream, which is not a very smart thing to do.
+   Later open may return file descriptor #2 for unrelated purpose, and
+   error reporting code may write into them.
+
+ * "git apply --whitespace=fix" was not prepared to see a line getting
+   longer after fixing whitespaces (e.g. tab-in-indent aka Python).
+
+ * "git diff/log --cc" did not work well with options that ignore
+   whitespace changes.
+
+ * Documentation on setting up a http server that requires
+   authentication only on the push but not fetch has been clarified.
+
+ * A few bugfixes to "git rerere" working on corner case merge
+   conflicts have been applied.
+
+ * "git bundle" did not like a bundle created using a commit without
+   any message as its one of the prerequisites.
diff --git a/Documentation/RelNotes/1.8.2.3.txt b/Documentation/RelNotes/1.8.2.3.txt
new file mode 100644
index 0000000000..613948251a
--- /dev/null
+++ b/Documentation/RelNotes/1.8.2.3.txt
@@ -0,0 +1,19 @@
+Git v1.8.2.3 Release Notes
+==========================
+
+Fixes since v1.8.2.2
+--------------------
+
+ * "rev-list --stdin" and friends kept bogus pointers into the input
+   buffer around as human readable object names.  This was not a
+   huge problem but was exposed by a new change that uses these
+   names in error output.
+
+ * When "git difftool" drove "kdiff3", it mistakenly passed --auto
+   option that was meant while resolving merge conflicts.
+
+ * "git remote add" command did not diagnose extra command line
+   arguments as an error and silently ignored them.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/RelNotes/1.8.2.txt b/Documentation/RelNotes/1.8.2.txt
new file mode 100644
index 0000000000..fc606ae116
--- /dev/null
+++ b/Documentation/RelNotes/1.8.2.txt
@@ -0,0 +1,495 @@
+Git v1.8.2 Release Notes
+========================
+
+Backward compatibility notes (this release)
+-------------------------------------------
+
+"git push $there tag v1.2.3" used to allow replacing a tag v1.2.3
+that already exists in the repository $there, if the rewritten tag
+you are pushing points at a commit that is a descendant of a commit
+that the old tag v1.2.3 points at.  This was found to be error prone
+and starting with this release, any attempt to update an existing
+ref under refs/tags/ hierarchy will fail, without "--force".
+
+When "git add -u" and "git add -A" that does not specify what paths
+to add on the command line is run from inside a subdirectory, the
+scope of the operation has always been limited to the subdirectory.
+Many users found this counter-intuitive, given that "git commit -a"
+and other commands operate on the entire tree regardless of where you
+are.  In this release, these commands give a warning message that
+suggests the users to use "git add -u/-A ." when they want to limit
+the scope to the current directory; doing so will squelch the message,
+while training their fingers.
+
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  In Git 2.0, the default will change to the "simple"
+semantics that pushes the current branch to the branch with the same
+name, only when the current branch is set to integrate with that
+remote branch.  There is a user preference configuration variable
+"push.default" to change this.  If you are an old-timer who is used
+to the "matching" semantics, you can set it to "matching" to keep the
+traditional behaviour.  If you want to live in the future early,
+you can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" and "git add -A", that does not specify what paths
+to add on the command line is run from inside a subdirectory, these
+commands will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands. Because there will be no
+mechanism to make "git add -u" behave as if "git add -u .", it is
+important for those who are used to "git add -u" (without pathspec)
+updating the index only for paths in the current subdirectory to start
+training their fingers to explicitly say "git add -u ." when they mean
+it before Git 2.0 comes.
+
+
+Updates since v1.8.1
+--------------------
+
+UI, Workflows & Features
+
+ * Initial ports to QNX and z/OS UNIX System Services have started.
+
+ * Output from the tests is coloured using "green is okay, yellow is
+   questionable, red is bad and blue is informative" scheme.
+
+ * Mention of "GIT/Git/git" in the documentation have been updated to
+   be more uniform and consistent.  The name of the system and the
+   concept it embodies is "Git"; the command the users type is "git".
+   All-caps "GIT" was merely a way to imitate "Git" typeset in small
+   caps in our ASCII text only documentation and to be avoided.
+
+ * The completion script (in contrib/completion) used to let the
+   default completer to suggest pathnames, which gave too many
+   irrelevant choices (e.g. "git add" would not want to add an
+   unmodified path).  It learnt to use a more git-aware logic to
+   enumerate only relevant ones.
+
+ * In bare repositories, "git shortlog" and other commands now read
+   mailmap files from the tip of the history, to help running these
+   tools in server settings.
+
+ * Color specifiers, e.g. "%C(blue)Hello%C(reset)", used in the
+   "--format=" option of "git log" and friends can be disabled when
+   the output is not sent to a terminal by prefixing them with
+   "auto,", e.g. "%C(auto,blue)Hello%C(auto,reset)".
+
+ * Scripts can ask Git that wildcard patterns in pathspecs they give do
+   not have any significance, i.e. take them as literal strings.
+
+ * The patterns in .gitignore and .gitattributes files can have **/,
+   as a pattern that matches 0 or more levels of subdirectory.
+   E.g. "foo/**/bar" matches "bar" in "foo" itself or in a
+   subdirectory of "foo".
+
+ * When giving arguments without "--" disambiguation, object names
+   that come earlier on the command line must not be interpretable as
+   pathspecs and pathspecs that come later on the command line must
+   not be interpretable as object names.  This disambiguation rule has
+   been tweaked so that ":/" (no other string before or after) is
+   always interpreted as a pathspec; "git cmd -- :/" is no longer
+   needed, you can just say "git cmd :/".
+
+ * Various "hint" lines Git gives when it asks the user to edit
+   messages in the editor are commented out with '#' by default. The
+   core.commentchar configuration variable can be used to customize
+   this '#' to a different character.
+
+ * "git add -u" and "git add -A" without pathspec issues warning to
+   make users aware that they are only operating on paths inside the
+   subdirectory they are in.  Use ":/" (everything from the top) or
+   "." (everything from the $cwd) to disambiguate.
+
+ * "git blame" (and "git diff") learned the "--no-follow" option.
+
+ * "git branch" now rejects some nonsense combinations of command line
+   arguments (e.g. giving more than one branch name to rename) with
+   more case-specific error messages.
+
+ * "git check-ignore" command to help debugging .gitignore files has
+   been added.
+
+ * "git cherry-pick" can be used to replay a root commit to an unborn
+   branch.
+
+ * "git commit" can be told to use --cleanup=whitespace by setting the
+   configuration variable commit.cleanup to 'whitespace'.
+
+ * "git diff" and other Porcelain commands can be told to use a
+   non-standard algorithm by setting diff.algorithm configuration
+   variable.
+
+ * "git fetch --mirror" and fetch that uses other forms of refspec
+   with wildcard used to attempt to update a symbolic ref that match
+   the wildcard on the receiving end, which made little sense (the
+   real ref that is pointed at by the symbolic ref would be updated
+   anyway).  Symbolic refs no longer are affected by such a fetch.
+
+ * "git format-patch" now detects more cases in which a whole branch
+   is being exported, and uses the description for the branch, when
+   asked to write a cover letter for the series.
+
+ * "git format-patch" learned "-v $count" option, and prepends a
+   string "v$count-" to the names of its output files, and also
+   automatically sets the subject prefix to "PATCH v$count". This
+   allows patches from rerolled series to be stored under different
+   names and makes it easier to reuse cover letter messages.
+
+ * "git log" and friends can be told with --use-mailmap option to
+   rewrite the names and email addresses of people using the mailmap
+   mechanism.
+
+ * "git log --cc --graph" now shows the combined diff output with the
+   ancestry graph.
+
+ * "git log --grep=<pattern>" honors i18n.logoutputencoding to look
+   for the pattern after fixing the log message to the specified
+   encoding.
+
+ * "git mergetool" and "git difftool" learned to list the available
+   tool backends in a more consistent manner.
+
+ * "git mergetool" is aware of TortoiseGitMerge now and uses it over
+   TortoiseMerge when available.
+
+ * "git push" now requires "-f" to update a tag, even if it is a
+   fast-forward, as tags are meant to be fixed points.
+
+ * Error messages from "git push" when it stops to prevent remote refs
+   from getting overwritten by mistake have been improved to explain
+   various situations separately.
+
+ * "git push" will stop without doing anything if the new "pre-push"
+   hook exists and exits with a failure.
+
+ * When "git rebase" fails to generate patches to be applied (e.g. due
+   to oom), it failed to detect the failure and instead behaved as if
+   there were nothing to do.  A workaround to use a temporary file has
+   been applied, but we probably would want to revisit this later, as
+   it hurts the common case of not failing at all.
+
+ * Input and preconditions to "git reset" has been loosened where
+   appropriate.  "git reset $fromtree Makefile" requires $fromtree to
+   be any tree (it used to require it to be a commit), for example.
+   "git reset" (without options or parameters) used to error out when
+   you do not have any commits in your history, but it now gives you
+   an empty index (to match non-existent commit you are not even on).
+
+ * "git status" says what branch is being bisected or rebased when
+   able, not just "bisecting" or "rebasing".
+
+ * "git submodule" started learning a new mode to integrate with the
+   tip of the remote branch (as opposed to integrating with the commit
+   recorded in the superproject's gitlink).
+
+ * "git upload-pack" which implements the service "ls-remote" and
+   "fetch" talk to can be told to hide ref hierarchies the server
+   side internally uses (and that clients have no business learning
+   about) with transfer.hiderefs configuration.
+
+
+Foreign Interface
+
+ * "git fast-export" has been updated for its use in the context of
+   the remote helper interface.
+
+ * A new remote helper to interact with bzr has been added to contrib/.
+
+ * "git p4" got various bugfixes around its branch handling.  It is
+   also made usable with Python 2.4/2.5.  In addition, its various
+   portability issues for Cygwin have been addressed.
+
+ * The remote helper to interact with Hg in contrib/ has seen a few
+   fixes.
+
+
+Performance, Internal Implementation, etc.
+
+ * "git fsck" has been taught to be pickier about entries in tree
+   objects that should not be there, e.g. ".", ".git", and "..".
+
+ * Matching paths with common forms of pathspecs that contain wildcard
+   characters has been optimized further.
+
+ * We stopped paying attention to $GIT_CONFIG environment that points
+   at a single configuration file from any command other than "git config"
+   quite a while ago, but "git clone" internally set, exported, and
+   then unexported the variable during its operation unnecessarily.
+
+ * "git reset" internals has been reworked and should be faster in
+   general. We tried to be careful not to break any behaviour but
+   there could be corner cases, especially when running the command
+   from a conflicted state, that we may have missed.
+
+ * The implementation of "imap-send" has been updated to reuse xml
+   quoting code from http-push codepath, and lost a lot of unused
+   code.
+
+ * There is a simple-minded checker for the test scripts in t/
+   directory to catch most common mistakes (it is not enabled by
+   default).
+
+ * You can build with USE_WILDMATCH=YesPlease to use a replacement
+   implementation of pattern matching logic used for pathname-like
+   things, e.g. refnames and paths in the repository.  This new
+   implementation is not expected change the existing behaviour of Git
+   in this release, except for "git for-each-ref" where you can now
+   say "refs/**/master" and match with both refs/heads/master and
+   refs/remotes/origin/master.  We plan to use this new implementation
+   in wider places (e.g. "git ls-files '**/Makefile' may find Makefile
+   at the top-level, and "git log '**/t*.sh'" may find commits that
+   touch a shell script whose name begins with "t" at any level) in
+   future versions of Git, but we are not there yet.  By building with
+   USE_WILDMATCH, using the resulting Git daily and reporting when you
+   find breakages, you can help us get closer to that goal.
+
+ * Some reimplementations of Git do not write all the stat info back
+   to the index due to their implementation limitations (e.g. jgit).
+   A configuration option can tell Git to ignore changes to most of
+   the stat fields and only pay attention to mtime and size, which
+   these implementations can reliably update.  This can be used to
+   avoid excessive revalidation of contents.
+
+ * Some platforms ship with old version of expat where xmlparse.h
+   needs to be included instead of expat.h; the build procedure has
+   been taught about this.
+
+ * "make clean" on platforms that cannot compute header dependencies
+   on the fly did not work with implementations of "rm" that do not
+   like an empty argument list.
+
+Also contains minor documentation updates and code clean-ups.
+
+
+Fixes since v1.8.1
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.1 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * An element on GIT_CEILING_DIRECTORIES list that does not name the
+   real path to a directory (i.e. a symbolic link) could have caused
+   the GIT_DIR discovery logic to escape the ceiling.
+
+ * When attempting to read the XDG-style $HOME/.config/git/config and
+   finding that $HOME/.config/git is a file, we gave a wrong error
+   message, instead of treating the case as "a custom config file does
+   not exist there" and moving on.
+
+ * The behaviour visible to the end users was confusing, when they
+   attempt to kill a process spawned in the editor that was in turn
+   launched by Git with SIGINT (or SIGQUIT), as Git would catch that
+   signal and die.  We ignore these signals now.
+   (merge 0398fc34 pf/editor-ignore-sigint later to maint).
+
+ * A child process that was killed by a signal (e.g. SIGINT) was
+   reported in an inconsistent way depending on how the process was
+   spawned by us, with or without a shell in between.
+
+ * After failing to create a temporary file using mkstemp(), failing
+   pathname was not reported correctly on some platforms.
+
+ * We used to stuff "user@" and then append what we read from
+   /etc/mailname to come up with a default e-mail ident, but a bug
+   lost the "user@" part.
+
+ * The attribute mechanism didn't allow limiting attributes to be
+   applied to only a single directory itself with "path/" like the
+   exclude mechanism does.  The initial implementation of this that
+   was merged to 'maint' and 1.8.1.2 was with a severe performance
+   degradations and needs to merge a fix-up topic.
+
+ * The smart HTTP clients forgot to verify the content-type that comes
+   back from the server side to make sure that the request is being
+   handled properly.
+
+ * "git am" did not parse datestamp correctly from Hg generated patch,
+   when it is run in a locale outside C (or en).
+
+ * "git apply" misbehaved when fixing whitespace breakages by removing
+   excess trailing blank lines.
+
+ * "git apply --summary" has been taught to make sure the similarity
+   value shown in its output is sensible, even when the input had a
+   bogus value.
+
+ * A tar archive created by "git archive" recorded a directory in a
+   way that made NetBSD's implementation of "tar" sometimes unhappy.
+
+ * "git archive" did not record uncompressed size in the header when
+   streaming a zip archive, which confused some implementations of unzip.
+
+ * "git archive" did not parse configuration values in tar.* namespace
+   correctly.
+   (merge b3873c3 jk/config-parsing-cleanup later to maint).
+
+ * Attempt to "branch --edit-description" an existing branch, while
+   being on a detached HEAD, errored out.
+
+ * "git clean" showed what it was going to do, but sometimes end up
+   finding that it was not allowed to do so, which resulted in a
+   confusing output (e.g. after saying that it will remove an
+   untracked directory, it found an embedded git repository there
+   which it is not allowed to remove).  It now performs the actions
+   and then reports the outcome more faithfully.
+
+ * When "git clone --separate-git-dir=$over_there" is interrupted, it
+   failed to remove the real location of the $GIT_DIR it created.
+   This was most visible when interrupting a submodule update.
+
+ * "git cvsimport" mishandled timestamps at DST boundary.
+
+ * We used to have an arbitrary 32 limit for combined diff input,
+   resulting in incorrect number of leading colons shown when showing
+   the "--raw --cc" output.
+
+ * "git fetch --depth" was broken in at least three ways.  The
+   resulting history was deeper than specified by one commit, it was
+   unclear how to wipe the shallowness of the repository with the
+   command, and documentation was misleading.
+   (merge cfb70e1 nd/fetch-depth-is-broken later to maint).
+
+ * "git log --all -p" that walked refs/notes/textconv/ ref can later
+   try to use the textconv data incorrectly after it gets freed.
+
+ * We forgot to close the file descriptor reading from "gpg" output,
+   killing "git log --show-signature" on a long history.
+
+ * The way "git svn" asked for password using SSH_ASKPASS and
+   GIT_ASKPASS was not in line with the rest of the system.
+
+ * The --graph code fell into infinite loop when asked to do what the
+   code did not expect.
+
+ * http transport was wrong to ask for the username when the
+   authentication is done by certificate identity.
+
+ * "git pack-refs" that ran in parallel to another process that
+   created new refs had a nasty race.
+
+ * Rebasing the history of superproject with change in the submodule
+   has been broken since v1.7.12.
+
+ * After "git add -N" and then writing a tree object out of the
+   index, the cache-tree data structure got corrupted.
+
+ * "git clone" used to allow --bare and --separate-git-dir=$there
+   options at the same time, which was nonsensical.
+
+ * "git rebase --preserve-merges" lost empty merges in recent versions
+   of Git.
+
+ * "git merge --no-edit" computed who were involved in the work done
+   on the side branch, even though that information is to be discarded
+   without getting seen in the editor.
+
+ * "git merge" started calling prepare-commit-msg hook like "git
+   commit" does some time ago, but forgot to pay attention to the exit
+   status of the hook.
+
+ * A failure to push due to non-ff while on an unborn branch
+   dereferenced a NULL pointer when showing an error message.
+
+ * When users spell "cc:" in lowercase in the fake "header" in the
+   trailer part, "git send-email" failed to pick up the addresses from
+   there. As e-mail headers field names are case insensitive, this
+   script should follow suit and treat "cc:" and "Cc:" the same way.
+
+ * Output from "git status --ignored" showed an unexpected interaction
+   with "--untracked".
+
+ * "gitweb", when sorting by age to show repositories with new
+   activities first, used to sort repositories with absolutely
+   nothing in it early, which was not very useful.
+
+ * "gitweb"'s code to sanitize control characters before passing it to
+   "highlight" filter lost known-to-be-safe control characters by
+   mistake.
+
+ * "gitweb" pages served over HTTPS, when configured to show picon or
+   gravatar, referred to these external resources to be fetched via
+   HTTP, resulting in mixed contents warning in browsers.
+
+ * When a line to be wrapped has a solid run of non space characters
+   whose length exactly is the wrap width, "git shortlog -w" failed
+   to add a newline after such a line.
+
+ * Command line completion leaked an unnecessary error message while
+   looking for possible matches with paths in <tree-ish>.
+
+ * Command line completion for "tcsh" emitted an unwanted space
+   after completing a single directory name.
+
+ * Command line completion code was inadvertently made incompatible with
+   older versions of bash by using a newer array notation.
+
+ * "git push" was taught to refuse updating the branch that is
+   currently checked out long time ago, but the user manual was left
+   stale.
+   (merge 50995ed wk/man-deny-current-branch-is-default-these-days later to maint).
+
+ * Some shells do not behave correctly when IFS is unset; work it
+   around by explicitly setting it to the default value.
+
+ * Some scripted programs written in Python did not get updated when
+   PYTHON_PATH changed.
+   (cherry-pick 96a4647fca54031974cd6ad1 later to maint).
+
+ * When autoconf is used, any build on a different commit always ran
+   "config.status --recheck" even when unnecessary.
+
+ * A fix was added to the build procedure to work around buggy
+   versions of ccache broke the auto-generation of dependencies, which
+   unfortunately is still relevant because some people use ancient
+   distros.
+
+ * The autoconf subsystem passed --mandir down to generated
+   config.mak.autogen but forgot to do the same for --htmldir.
+   (merge 55d9bf0 ct/autoconf-htmldir later to maint).
+
+ * A change made on v1.8.1.x maintenance track had a nasty regression
+   to break the build when autoconf is used.
+   (merge 7f1b697 jn/less-reconfigure later to maint).
+
+ * We have been carrying a translated and long-unmaintained copy of an
+   old version of the tutorial; removed.
+
+ * t0050 had tests expecting failures from a bug that was fixed some
+   time ago.
+
+ * t4014, t9502 and t0200 tests had various portability issues that
+   broke on OpenBSD.
+
+ * t9020 and t3600 tests had various portability issues.
+
+ * t9200 runs "cvs init" on a directory that already exists, but a
+   platform can configure this fail for the current user (e.g. you
+   need to be in the cvsadmin group on NetBSD 6.0).
+
+ * t9020 and t9810 had a few non-portable shell script construct.
+
+ * Scripts to test bash completion was inherently flaky as it was
+   affected by whatever random things the user may have on $PATH.
+
+ * An element on GIT_CEILING_DIRECTORIES could be a "logical" pathname
+   that uses a symbolic link to point at somewhere else (e.g. /home/me
+   that points at /net/host/export/home/me, and the latter directory
+   is automounted). Earlier when Git saw such a pathname e.g. /home/me
+   on this environment variable, the "ceiling" mechanism did not take
+   effect. With this release (the fix has also been merged to the
+   v1.8.1.x maintenance series), elements on GIT_CEILING_DIRECTORIES
+   are by default checked for such aliasing coming from symbolic
+   links. As this needs to actually resolve symbolic links for each
+   element on the GIT_CEILING_DIRECTORIES, you can disable this
+   mechanism for some elements by listing them after an empty element
+   on the GIT_CEILING_DIRECTORIES. e.g. Setting /home/me::/home/him to
+   GIT_CEILING_DIRECTORIES makes Git resolve symbolic links in
+   /home/me when checking if the current directory is under /home/me,
+   but does not do so for /home/him.
+   (merge 7ec30aa mh/maint-ceil-absolute later to maint).
diff --git a/Documentation/RelNotes/1.8.3.1.txt b/Documentation/RelNotes/1.8.3.1.txt
new file mode 100644
index 0000000000..986637b755
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.1.txt
@@ -0,0 +1,14 @@
+Git v1.8.3.1 Release Notes
+==========================
+
+Fixes since v1.8.3
+------------------
+
+ * When $HOME is misconfigured to point at an unreadable directory, we
+   used to complain and die. The check has been loosened.
+
+ * Handling of negative exclude pattern for directories "!dir" was
+   broken in the update to v1.8.3.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/RelNotes/1.8.3.2.txt b/Documentation/RelNotes/1.8.3.2.txt
new file mode 100644
index 0000000000..26ae142c3d
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.2.txt
@@ -0,0 +1,59 @@
+Git v1.8.3.2 Release Notes
+==========================
+
+Fixes since v1.8.3.1
+--------------------
+
+ * Cloning with "git clone --depth N" while fetch.fsckobjects (or
+   transfer.fsckobjects) is set to true did not tell the cut-off
+   points of the shallow history to the process that validates the
+   objects and the history received, causing the validation to fail.
+
+ * "git checkout foo" DWIMs the intended "upstream" and turns it into
+   "git checkout -t -b foo remotes/origin/foo". This codepath has been
+   updated to correctly take existing remote definitions into account.
+
+ * "git fetch" into a shallow repository from a repository that does
+   not know about the shallow boundary commits (e.g. a different fork
+   from the repository the current shallow repository was cloned from)
+   did not work correctly.
+
+ * "git subtree" (in contrib/) had one codepath with loose error
+   checks to lose data at the remote side.
+
+ * "git log --ancestry-path A...B" did not work as expected, as it did
+   not pay attention to the fact that the merge base between A and B
+   was the bottom of the range being specified.
+
+ * "git diff -c -p" was not showing a deleted line from a hunk when
+   another hunk immediately begins where the earlier one ends.
+
+ * "git merge @{-1}~22" was rewritten to "git merge frotz@{1}~22"
+   incorrectly when your previous branch was "frotz" (it should be
+   rewritten to "git merge frotz~22" instead).
+
+ * "git commit --allow-empty-message -m ''" should not start an
+   editor.
+
+ * "git push --[no-]verify" was not documented.
+
+ * An entry for "file://" scheme in the enumeration of URL types Git
+   can take in the HTML documentation was made into a clickable link
+   by mistake.
+
+ * zsh prompt script that borrowed from bash prompt script did not
+   work due to slight differences in array variable notation between
+   these two shells.
+
+ * The bash prompt code (in contrib/) displayed the name of the branch
+   being rebased when "rebase -i/-m/-p" modes are in use, but not the
+   plain vanilla "rebase".
+
+ * "git push $there HEAD:branch" did not resolve HEAD early enough, so
+   it was easy to flip it around while push is still going on and push
+   out a branch that the user did not originally intended when the
+   command was started.
+
+ * "difftool --dir-diff" did not copy back changes made by the
+   end-user in the diff tool backend to the working tree in some
+   cases.
diff --git a/Documentation/RelNotes/1.8.3.3.txt b/Documentation/RelNotes/1.8.3.3.txt
new file mode 100644
index 0000000000..9ba4f4da0f
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.3.txt
@@ -0,0 +1,47 @@
+Git v1.8.3.3 Release Notes
+==========================
+
+Fixes since v1.8.3.2
+--------------------
+
+ * "git apply" parsed patches that add new files, generated by programs
+   other than Git, incorrectly.  This is an old breakage in v1.7.11.
+
+ * Older cURL wanted piece of memory we call it with to be stable, but
+   we updated the auth material after handing it to a call.
+
+ * "git pull" into nothing trashed "local changes" that were in the
+   index.
+
+ * Many "git submodule" operations did not work on a submodule at a
+   path whose name is not in ASCII.
+
+ * "cherry-pick" had a small leak in its error codepath.
+
+ * Logic used by git-send-email to suppress cc mishandled names like
+   "A U. Thor" <author@xxxxxxxxxx>, where the human readable part
+   needs to be quoted (the user input may not have the double quotes
+   around the name, and comparison was done between quoted and
+   unquoted strings).  It also mishandled names that need RFC2047
+   quoting.
+
+ * "gitweb" forgot to clear a global variable $search_regexp upon each
+   request, mistakenly carrying over the previous search to a new one
+   when used as a persistent CGI.
+
+ * The wildmatch engine did not honor WM_CASEFOLD option correctly.
+
+ * "git log -c --follow $path" segfaulted upon hitting the commit that
+   renamed the $path being followed.
+
+ * When a reflog notation is used for implicit "current branch",
+   e.g. "git log @{u}", we did not say which branch and worse said
+   "branch ''" in the error messages.
+
+ * Mac OS X does not like to write(2) more than INT_MAX number of
+   bytes; work it around by chopping write(2) into smaller pieces.
+
+ * Newer MacOS X encourages the programs to compile and link with
+   their CommonCrypto, not with OpenSSL.
+
+Also contains various minor documentation updates.
diff --git a/Documentation/RelNotes/1.8.3.4.txt b/Documentation/RelNotes/1.8.3.4.txt
new file mode 100644
index 0000000000..56f106e262
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.4.txt
@@ -0,0 +1,20 @@
+Git v1.8.3.4 Release Notes
+==========================
+
+This update is mostly to propagate documentation fixes and test
+updates from the master front back to the maintenance track.
+
+Fixes since v1.8.3.3
+--------------------
+
+ * The bisect log listed incorrect commits when bisection ends with
+   only skipped ones.
+
+ * The test coverage framework was left broken for some time.
+
+ * The test suite for HTTP transport did not run with Apache 2.4.
+
+ * "git diff" used to fail when core.safecrlf is set and the working
+   tree contents had mixed CRLF/LF line endings. Committing such a
+   content must be prohibited, but "git diff" should help the user to
+   locate and fix such problems without failing.
diff --git a/Documentation/RelNotes/1.8.3.txt b/Documentation/RelNotes/1.8.3.txt
new file mode 100644
index 0000000000..ead568e7f1
--- /dev/null
+++ b/Documentation/RelNotes/1.8.3.txt
@@ -0,0 +1,436 @@
+Git v1.8.3 Release Notes
+========================
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  In Git 2.0, the default will change to the "simple"
+semantics that pushes only the current branch to the branch with the same
+name, and only when the current branch is set to integrate with that
+remote branch.  Use the user preference configuration variable
+"push.default" to change this.  If you are an old-timer who is used
+to the "matching" semantics, you can set the variable to "matching"
+to keep the traditional behaviour.  If you want to live in the future
+early, you can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands.  There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes.  A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal.  Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+
+Updates since v1.8.2
+--------------------
+
+Foreign interface
+
+ * remote-hg and remote-bzr helpers (in contrib/ since v1.8.2) have
+   been updated; especially, the latter has been done in an
+   accelerated schedule (read: we may not have merged to this release
+   if we were following the usual "cook sufficiently in next before
+   unleashing it to the world" workflow) in order to help Emacs folks,
+   whose primary SCM seems to be stagnating.
+
+
+UI, Workflows & Features
+
+ * A handful of updates applied to gitk, including an addition of
+   "revert" action, showing dates in tags in a nicer way, making
+   colors configurable, and support for -G'pickaxe' search.
+
+ * The prompt string generator (in contrib/completion/) learned to
+   show how many changes there are in total and how many have been
+   replayed during a "git rebase" session.
+
+ * "git branch --vv" learned to paint the name of the branch it
+   integrates with in a different color (color.branch.upstream,
+   which defaults to blue).
+
+ * In a sparsely populated working tree, "git checkout <pathspec>" no
+   longer unmarks paths that match the given pathspec that were
+   originally ignored with "--sparse" (use --ignore-skip-worktree-bits
+   option to resurrect these paths out of the index if you really want
+   to).
+
+ * "git log --format" specifier learned %C(auto) token that tells Git
+   to use color when interpolating %d (decoration), %h (short commit
+   object name), etc. for terminal output.
+
+ * "git bisect" leaves the final outcome as a comment in its bisect
+   log file.
+
+ * "git clone --reference" can now refer to a gitfile "textual symlink"
+   that points at the real location of the repository.
+
+ * "git count-objects" learned "--human-readable" aka "-H" option to
+   show various large numbers in Ki/Mi/GiB scaled as necessary.
+
+ * "git cherry-pick $blob" and "git cherry-pick $tree" are nonsense,
+   and a more readable error message e.g. "can't cherry-pick a tree"
+   is given (we used to say "expected exactly one commit").
+
+ * The "--annotate" option to "git send-email" can be turned on (or
+   off) by default with sendemail.annotate configuration variable (you
+   can use --no-annotate from the command line to override it).
+
+ * The "--cover-letter" option to "git format-patch" can be turned on
+   (or off) by default with format.coverLetter configuration
+   variable. By setting it to 'auto', you can turn it on only for a
+   series with two or more patches.
+
+ * The bash completion support (in contrib/) learned that cherry-pick
+   takes a few more options than it already knew about.
+
+ * "git help" learned "-g" option to show the list of guides just like
+   list of commands are given with "-a".
+
+ * A triangular "pull from one place, push to another place" workflow
+   is supported better by new remote.pushdefault (overrides the
+   "origin" thing) and branch.*.pushremote (overrides the
+   branch.*.remote) configuration variables.
+
+ * "git status" learned to report that you are in the middle of a
+   revert session, just like it does for a cherry-pick and a bisect
+   session.
+
+ * The handling by "git branch --set-upstream-to" against various forms
+   of erroneous inputs was suboptimal and has been improved.
+
+ * When the interactive access to git-shell is not enabled, it issues
+   a message meant to help the system administrator to enable it.  An
+   explicit way has been added to issue custom messages to refuse an
+   access over the network to help the end users who connect to the
+   service expecting an interactive shell.
+
+ * In addition to the case where the user edits the log message with
+   the "e)dit" option of "am -i", replace the "Applying: this patch"
+   message with the final log message contents after applymsg hook
+   munges it.
+
+ * "git status" suggests users to look into using --untracked=no option
+   when it takes too long.
+
+ * "git status" shows a bit more information during a rebase/bisect
+   session.
+
+ * "git fetch" learned to fetch a commit at the tip of an unadvertised
+   ref by specifying a raw object name from the command line when the
+   server side supports this feature.
+
+ * Output from "git log --graph" works better with submodule log
+   output now.
+
+ * "git count-objects -v" learned to report leftover temporary
+   packfiles and other garbage in the object store.
+
+ * A new read-only credential helper (in contrib/) to interact with
+   the .netrc/.authinfo files has been added.
+
+ * "git send-email" can be used with the credential helper system.
+
+ * There was no Porcelain way to say "I no longer am interested in
+   this submodule", once you express your interest in a submodule with
+   "submodule init".  "submodule deinit" is the way to do so.
+
+ * "git pull --rebase" learned to pass "-v/-q" options to underlying
+   "git rebase".
+
+ * The new "--follow-tags" option tells "git push" to push relevant
+   annotated tags when pushing branches out.
+
+ * "git merge" and "git pull" can optionally be told to inspect and
+   reject when merging a commit that does not carry a trusted GPG
+   signature.
+
+ * "git mergetool" now feeds files to the "p4merge" backend in the
+   order that matches the p4 convention, where "theirs" is usually
+   shown on the left side, which is the opposite from what other backends
+   expect.
+
+ * "show/log" now honors gpg.program configuration just like other
+   parts of the code that use GnuPG.
+
+ * "git log" that shows the difference between the parent and the
+   child has been optimized somewhat.
+
+ * "git difftool" allows the user to write into the temporary files
+   being shown; if the user makes changes to the working tree at the
+   same time, it now refrains from overwriting the copy in the working
+   tree and leaves the temporary file so that changes can be merged
+   manually.
+
+ * There was no good way to ask "I have a random string that came from
+   outside world. I want to turn it into a 40-hex object name while
+   making sure such an object exists".  A new peeling suffix ^{object}
+   can be used for that purpose, together with "rev-parse --verify".
+
+
+Performance, Internal Implementation, etc.
+
+ * Updates for building under msvc.
+
+ * A handful of issues in the code that traverses the working tree to find
+   untracked and/or ignored files have been fixed, and the general
+   codepath involved in "status -u" and "clean" have been cleaned up
+   and optimized.
+
+ * The stack footprint of some codepaths that access an object from a
+   pack has been shrunk.
+
+ * The logic to coalesce the same lines removed from the parents in
+   the output from "diff -c/--cc" has been updated, but with O(n^2)
+   complexity, so this might turn out to be undesirable.
+
+ * The code to enforce permission bits on files in $GIT_DIR/ for
+   shared repositories has been simplified.
+
+ * A few codepaths know how much data they need to put in the
+   hashtables they use when they start, but still began with small tables
+   and repeatedly grew and rehashed them.
+
+ * The API to walk reflog entries from the latest to older, which was
+   necessary for operations such as "git checkout -", was cumbersome
+   to use correctly and also inefficient.
+
+ * Codepaths that inspect log-message-to-be and decide when to add a
+   new Signed-off-by line in various commands have been consolidated.
+
+ * The pkt-line API, implementation and its callers have been cleaned
+   up to make them more robust.
+
+ * The Cygwin port has a faster-but-lying lstat(2) emulation whose
+   incorrectness does not matter in practice except for a few
+   codepaths, and setting permission bits on directories is a codepath
+   that needs to use a more correct one.
+
+ * "git checkout" had repeated pathspec matches on the same paths,
+   which have been consolidated.  Also a bug in "git checkout dir/"
+   that is started from an unmerged index has been fixed.
+
+ * A few bugfixes to "git rerere" working on corner case merge
+   conflicts have been applied.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.2
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.2 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * Recent versions of File::Temp (used by "git svn") started blowing
+   up when its tempfile sub is called as a class method; updated the
+   callsite to call it as a plain vanilla function to fix it.
+   (merge eafc2dd hb/git-pm-tempfile later to maint).
+
+ * Various subcommands of "git remote" simply ignored extraneous
+   command line arguments instead of diagnosing them as errors.
+
+ * When receive-pack detects an error in the pack header it received in
+   order to decide which of unpack-objects or index-pack to run, it
+   returned without closing the error stream, which led to a hung
+   sideband thread.
+
+ * Zsh completion forgot that the '%' character used to signal untracked
+   files needs to be escaped with another '%'.
+
+ * A commit object whose author or committer ident are malformed
+   crashed some code that trusted that a name, an email and a
+   timestamp can always be found in it.
+
+ * When "upload-pack" fails while generating a pack in response to
+   "git fetch" (or "git clone"), the receiving side had
+   a programming error that triggered the die handler
+   recursively.
+
+ * "rev-list --stdin" and friends kept bogus pointers into the input
+   buffer around as human readable object names.  This was not a huge
+   problem but was exposed by a new change that uses these names in
+   error output.
+
+ * Smart-capable HTTP servers were not restricted via the
+   GIT_NAMESPACE mechanism when talking with commit-walking clients,
+   like they are when talking with smart HTTP clients.
+   (merge 6130f86 jk/http-dumb-namespaces later to maint).
+
+ * "git merge-tree" did not omit a merge result that is identical to
+   the "our" side in certain cases.
+   (merge aacecc3 jk/merge-tree-added-identically later to maint).
+
+ * Perl scripts like "git-svn" closed (instead of redirecting to /dev/null)
+   the standard error stream, which is not a very smart thing to do.
+   A later open may return file descriptor #2 for an unrelated purpose, and
+   error reporting code may write into it.
+
+ * "git show-branch" was not prepared to show a very long run of
+   ancestor operators e.g. foobar^2~2^2^2^2...^2~4 correctly.
+
+ * "git diff --diff-algorithm algo" is also understood as "git diff
+   --diff-algorithm=algo".
+
+ * The new core.commentchar configuration was not applied in a few
+   places.
+
+ * "git bundle" erroneously bailed out when parsing a valid bundle
+   containing a prerequisite commit without a commit message.
+
+ * "git log -S/-G" started paying attention to textconv filter, but
+   there was no way to disable this.  Make it honor the --no-textconv
+   option.
+
+ * When used with the "-d temporary-directory" option, "git filter-branch"
+   failed to come back to the original working tree to perform the
+   final clean-up procedure.
+
+ * "git merge $(git rev-parse v1.8.2)" behaved quite differently from
+   "git merge v1.8.2", as if v1.8.2 were written as v1.8.2^0 and did
+   not pay much attention to the annotated tag payload.  Make the code
+   notice the type of the tag object, in addition to the dwim_ref()
+   based classification the current code uses (i.e. the name appears
+   in refs/tags/) to decide when to special-case tag merging.
+
+ * Fix a 1.8.1.x regression that stopped matching "dir" (without a
+   trailing slash) to a directory "dir".
+
+ * "git apply --whitespace=fix" was not prepared to see a line getting
+   longer after fixing whitespaces (e.g. tab-in-indent aka Python).
+
+ * The prompt string generator (in contrib/completion/) did not notice
+   when we are in a middle of a "git revert" session.
+
+ * "submodule summary --summary-limit" option did not support the
+   "--option=value" form.
+
+ * "index-pack --fix-thin" used an uninitialized value to compute
+   the delta depths of objects it appends to the resulting pack.
+
+ * "index-pack --verify-stat" used a few counters outside the protection
+   of a mutex, possibly showing incorrect numbers.
+
+ * The code to keep track of what directory names are known to Git on
+   platforms with case insensitive filesystems could get confused upon a
+   hash collision between these pathnames and would loop forever.
+
+ * Annotated tags outside the refs/tags/ hierarchy were not advertised
+   correctly to ls-remote and fetch with recent versions of Git.
+
+ * Recent optimizations broke shallow clones.
+
+ * "git cmd -- ':(top'" was not diagnosed as an invalid syntax, and
+   instead the parser kept reading beyond the end of the string.
+
+ * "git tag -f <tag>" always said "Updated tag '<tag>'" even when
+   creating a new tag (i.e. neither overwriting nor updating).
+
+ * "git p4" did not behave well when the path to the root of the P4
+   client was not its real path.
+   (merge bbd8486 pw/p4-symlinked-root later to maint).
+
+ * "git archive" reported a failure when asked to create an archive out
+   of an empty tree.  It is more intuitive to give an empty
+   archive back in such a case.
+
+ * When "format-patch" quoted a non-ascii string in header files,
+   it incorrectly applied rfc2047 and chopped a single character in
+   the middle of the string.
+
+ * An aliased command spawned from a bare repository that does not say
+   it is bare with "core.bare = yes" was treated as non-bare by mistake.
+
+ * In "git reflog expire", the REACHABLE bit was not cleared from the
+   correct objects.
+
+ * The logic used by "git diff -M --stat" to shorten the names of
+   files before and after a rename did not work correctly when the
+   common prefix and suffix between the two filenames overlapped.
+
+ * The "--match=<pattern>" option of "git describe", when used with
+   "--all" to allow refs that are not annotated tags to be a
+   base of description, did not restrict the output from the command
+   to those refs that match the given pattern.
+
+ * Clarify in the documentation "what" gets pushed to "where" when the
+   command line to "git push" does not say these explicitly.
+
+ * The "--color=<when>" argument to the commands in the diff family
+   was described poorly.
+
+ * The arguments given to the pre-rebase hook were not documented.
+
+ * The v4 index format was not documented.
+
+ * The "--match=<pattern>" argument "git describe" takes uses glob
+   pattern but it wasn't obvious from the documentation.
+
+ * Some sources failed to compile on systems that lack NI_MAXHOST in
+   their system header (e.g. z/OS).
+
+ * Add an example use of "--env-filter" in "filter-branch"
+   documentation.
+
+ * "git bundle verify" did not say "records a complete history" for a
+   bundle that does not have any prerequisites.
+
+ * In the v1.8.0 era, we changed symbols that do not have to be global
+   to file scope static, but a few functions in graph.c were used by
+   CGit sideways, bypassing the entry points of the API the
+   in-tree users use.
+
+ * "git update-index -h" did not do the usual "-h(elp)" thing.
+
+ * "git index-pack" had a buffer-overflow while preparing an
+   informational message when the translated version of it was too
+   long.
+
+ * 'git commit -m "$msg"' used to add an extra newline even when
+   $msg already ended with one.
+
+ * The SSL peer verification done by "git imap-send" did not ask for
+   Server Name Indication (RFC 4366), failing to connect to SSL/TLS
+   sites that serve multiple hostnames on a single IP.
+
+ * perl/Git.pm::cat_blob slurped everything in core only to write it
+   out to a file descriptor, which was not a very smart thing to do.
+
+ * "git branch" did not bother to check nonsense command line
+   parameters.  It now issues errors in many cases.
+
+ * Verification of signed tags was not done correctly when not in C
+   or en/US locale.
+
+ * Some platforms and users spell UTF-8 differently; retry with the
+   most official "UTF-8" when the system does not understand the
+   user-supplied encoding name that is a common alternative
+   spelling of UTF-8.
+
+ * When export-subst is used, "zip" output recorded an incorrect
+   size of the file.
+
+ * "git am $maildir/" applied messages in an unexpected order; sort
+   filenames read from the maildir/ in a way that is more likely to
+   sort the messages in the order the writing MUA meant to, by sorting
+   numeric segments in numeric order and non-numeric segments in
+   alphabetical order.
+
+ * "git submodule update", when recursed into sub-submodules, did not
+   accumulate the prefix paths.
diff --git a/Documentation/RelNotes/1.8.4.1.txt b/Documentation/RelNotes/1.8.4.1.txt
new file mode 100644
index 0000000000..c257beb114
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.1.txt
@@ -0,0 +1,71 @@
+Git v1.8.4.1 Release Notes
+==========================
+
+Fixes since v1.8.4
+------------------
+
+ * Some old versions of bash do not grok some constructs like
+   'printf -v varname' which the prompt and completion code started
+   to use recently.  The completion and prompt scripts have been
+   adjusted to work better with these old versions of bash.
+
+ * In FreeBSD's and NetBSD's "sh", a return in a dot script in a
+   function returns from the function, not only in the dot script,
+   breaking "git rebase" on these platforms (regression introduced
+   in 1.8.4-rc1).
+
+ * "git rebase -i" and other scripted commands were feeding a
+   random, data dependent error message to 'echo' and expecting it
+   to come out literally.
+
+ * Setting the "submodule.<name>.path" variable to the empty
+   "true" caused the configuration parser to segfault.
+
+ * Output from "git log --full-diff -- <pathspec>" looked strange
+   because comparison was done with the previous ancestor that
+   touched the specified <pathspec>, causing the patches for paths
+   outside the pathspec to show more than the single commit has
+   changed.
+
+ * The auto-tag-following code in "git fetch" tries to reuse the
+   same transport twice when the serving end does not cooperate and
+   does not give tags that point to commits that are asked for as
+   part of the primary transfer.  Unfortunately, Git-aware transport
+   helper interface is not designed to be used more than once, hence
+   this did not work over smart-http transfer.  Fixed.
+
+ * Send a large request to read(2)/write(2) as a smaller but still
+   reasonably large chunks, which would improve the latency when the
+   operation needs to be killed and incidentally works around broken
+   64-bit systems that cannot take a 2GB write or read in one go.
+
+ * A ".mailmap" file that ends with an incomplete line, when read
+   from a blob, was not handled properly.
+
+ * The recent "short-cut clone connectivity check" topic broke a
+   shallow repository when a fetch operation tries to auto-follow
+   tags.
+
+ * When send-email comes up with an error message to die with upon
+   failure to start an SSL session, it tried to read the error
+   string from a wrong place.
+
+ * A call to xread() was used without a loop to cope with short
+   read in the codepath to stream large blobs to a pack.
+
+ * On platforms with fgetc() and friends defined as macros, the
+   configuration parser did not compile.
+
+ * New versions of MediaWiki introduced a new API for returning
+   more than 500 results in response to a query, which would cause
+   the MediaWiki remote helper to go into an infinite loop.
+
+ * Subversion's serf access method (the only one available in
+   Subversion 1.8) for http and https URLs in skelta mode tells its
+   caller to open multiple files at a time, which made "git svn
+   fetch" complain that "Temp file with moniker 'svn_delta' already
+   in use" instead of fetching.
+
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/RelNotes/1.8.4.2.txt b/Documentation/RelNotes/1.8.4.2.txt
new file mode 100644
index 0000000000..bf6fb1a023
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.2.txt
@@ -0,0 +1,77 @@
+Git v1.8.4.2 Release Notes
+==========================
+
+Fixes since v1.8.4.1
+--------------------
+
+ * "git clone" gave some progress messages to the standard output, not
+   to the standard error, and did not allow suppressing them with the
+   "--no-progress" option.
+
+ * "format-patch --from=<whom>" forgot to omit unnecessary in-body
+   from line, i.e. when <whom> is the same as the real author.
+
+ * "git shortlog" used to choke and die when there is a malformed
+   commit (e.g. missing authors); it now simply ignore such a commit
+   and keeps going.
+
+ * "git merge-recursive" did not parse its "--diff-algorithm=" command
+   line option correctly.
+
+ * "git branch --track" had a minor regression in v1.8.3.2 and later
+   that made it impossible to base your local work on anything but a
+   local branch of the upstream repository you are tracking from.
+
+ * "git ls-files -k" needs to crawl only the part of the working tree
+   that may overlap the paths in the index to find killed files, but
+   shared code with the logic to find all the untracked files, which
+   made it unnecessarily inefficient.
+
+ * When there is no sufficient overlap between old and new history
+   during a "git fetch" into a shallow repository, objects that the
+   sending side knows the receiving end has were unnecessarily sent.
+
+ * When running "fetch -q", a long silence while the sender side
+   computes the set of objects to send can be mistaken by proxies as
+   dropped connection.  The server side has been taught to send a
+   small empty messages to keep the connection alive.
+
+ * When the webserver responds with "405 Method Not Allowed", "git
+   http-backend" should tell the client what methods are allowed with
+   the "Allow" header.
+
+ * "git cvsserver" computed the permission mode bits incorrectly for
+   executable files.
+
+ * The implementation of "add -i" has a crippling code to work around
+   ActiveState Perl limitation but it by mistake also triggered on Git
+   for Windows where MSYS perl is used.
+
+ * We made sure that we notice the user-supplied GIT_DIR is actually a
+   gitfile, but did not do the same when the default ".git" is a
+   gitfile.
+
+ * When an object is not found after checking the packfiles and then
+   loose object directory, read_sha1_file() re-checks the packfiles to
+   prevent racing with a concurrent repacker; teach the same logic to
+   has_sha1_file().
+
+ * "git commit --author=$name", when $name is not in the canonical
+   "A. U. Thor <au.thor@xxxxxxxxxx>" format, looks for a matching name
+   from existing history, but did not consult mailmap to grab the
+   preferred author name.
+
+ * The commit object names in the insn sheet that was prepared at the
+   beginning of "rebase -i" session can become ambiguous as the
+   rebasing progresses and the repository gains more commits. Make
+   sure the internal record is kept with full 40-hex object names.
+
+ * "git rebase --preserve-merges" internally used the merge machinery
+   and as a side effect, left merge summary message in the log, but
+   when rebasing, there should not be a need for merge summary.
+
+ * "git rebase -i" forgot that the comment character can be
+   configurable while reading its insn sheet.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/RelNotes/1.8.4.3.txt b/Documentation/RelNotes/1.8.4.3.txt
new file mode 100644
index 0000000000..267a1b34b4
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.3.txt
@@ -0,0 +1,54 @@
+Git v1.8.4.3 Release Notes
+==========================
+
+Fixes since v1.8.4.2
+--------------------
+
+ * The interaction between use of Perl in our test suite and NO_PERL
+   has been clarified a bit.
+
+ * A fast-import stream expresses a pathname with funny characters by
+   quoting them in C style; remote-hg remote helper (in contrib/)
+   forgot to unquote such a path.
+
+ * One long-standing flaw in the pack transfer protocol used by "git
+   clone" was that there was no way to tell the other end which branch
+   "HEAD" points at, and the receiving end needed to guess.  A new
+   capability has been defined in the pack protocol to convey this
+   information so that cloning from a repository with more than one
+   branches pointing at the same commit where the HEAD is at now
+   reliably sets the initial branch in the resulting repository.
+
+ * We did not handle cases where http transport gets redirected during
+   the authorization request (e.g. from http:// to https://).
+
+ * "git rev-list --objects ^v1.0^ v1.0" gave v1.0 tag itself in the
+   output, but "git rev-list --objects v1.0^..v1.0" did not.
+
+ * The fall-back parsing of commit objects with broken author or
+   committer lines were less robust than ideal in picking up the
+   timestamps.
+
+ * Bash prompting code to deal with an SVN remote as an upstream
+   were coded in a way not supported by older Bash versions (3.x).
+
+ * "git checkout topic", when there is not yet a local "topic" branch
+   but there is a unique remote-tracking branch for a remote "topic"
+   branch, pretended as if "git checkout -t -b topic remote/$r/topic"
+   (for that unique remote $r) was run. This hack however was not
+   implemented for "git checkout topic --".
+
+ * Coloring around octopus merges in "log --graph" output was screwy.
+
+ * We did not generate HTML version of documentation to "git subtree"
+   in contrib/.
+
+ * The synopsis section of "git unpack-objects" documentation has been
+   clarified a bit.
+
+ * An ancient How-To on serving Git repositories on an HTTP server
+   lacked a warning that it has been mostly superseded with more
+   modern way.
+
+Also contains a handful of trivial code clean-ups, documentation
+updates, updates to the test suite, etc.
diff --git a/Documentation/RelNotes/1.8.4.4.txt b/Documentation/RelNotes/1.8.4.4.txt
new file mode 100644
index 0000000000..a7c1ce15c0
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.4.txt
@@ -0,0 +1,10 @@
+Git v1.8.4.4 Release Notes
+==========================
+
+Fixes since v1.8.4.3
+--------------------
+
+ * The fix in v1.8.4.3 to the pack transfer protocol to propagate
+   the target of symbolic refs broke "git clone/git fetch" from a
+   repository with too many symbolic refs. As a hotfix/workaround,
+   we transfer only the information on HEAD.
diff --git a/Documentation/RelNotes/1.8.4.5.txt b/Documentation/RelNotes/1.8.4.5.txt
new file mode 100644
index 0000000000..215bd1a7a2
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.5.txt
@@ -0,0 +1,13 @@
+Git v1.8.4.5 Release Notes
+==========================
+
+Fixes since v1.8.4.4
+--------------------
+
+ * Recent update to remote-hg that attempted to make it work better
+   with non ASCII pathnames fed Unicode strings to the underlying Hg
+   API, which was wrong.
+
+ * "git submodule init" copied "submodule.$name.update" settings from
+   .gitmodules to .git/config without making sure if the suggested
+   value was sensible.
diff --git a/Documentation/RelNotes/1.8.4.txt b/Documentation/RelNotes/1.8.4.txt
new file mode 100644
index 0000000000..2e7529928b
--- /dev/null
+++ b/Documentation/RelNotes/1.8.4.txt
@@ -0,0 +1,486 @@
+Git v1.8.4 Release Notes
+========================
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  In Git 2.0, the default will change to the "simple"
+semantics that pushes:
+
+ - only the current branch to the branch with the same name, and only
+   when the current branch is set to integrate with that remote
+   branch, if you are pushing to the same remote as you fetch from; or
+
+ - only the current branch to the branch with the same name, if you
+   are pushing to a remote that is not where you usually fetch from.
+
+Use the user preference configuration variable "push.default" to
+change this.  If you are an old-timer who is used to the "matching"
+semantics, you can set the variable to "matching" to keep the
+traditional behaviour.  If you want to live in the future early, you
+can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands.  There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes.  A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal.  Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+
+Updates since v1.8.3
+--------------------
+
+Foreign interfaces, subsystems and ports.
+
+ * Cygwin port has been updated for more recent Cygwin 1.7.
+
+ * "git rebase -i" now honors --strategy and -X options.
+
+ * Git-gui has been updated to its 0.18.0 version.
+
+ * MediaWiki remote helper (in contrib/) has been updated to use the
+   credential helper interface from Git.pm.
+
+ * Update build for Cygwin 1.[57].  Torsten Bögershausen reports that
+   this is fine with Cygwin 1.7 (cf. <51A606A0.5060101@xxxxxx>) so let's try moving it
+   ahead.
+
+ * The credential helper to talk to keychain on OS X (in contrib/) has
+   been updated to kick in not just when talking http/https but also
+   imap(s) and smtp.
+
+ * Remote transport helper has been updated to report errors and
+   maintain ref hierarchy used to keep track of its own state better.
+
+ * With "export" remote-helper protocol, (1) a push that tries to
+   update a remote ref whose name is different from the pushing side
+   does not work yet, and (2) the helper may not know how to do
+   --dry-run; these problematic cases are disabled for now.
+
+ * git-remote-hg/bzr (in contrib/) updates.
+
+ * git-remote-mw (in contrib/) hints users to check the certificate,
+   when https:// connection failed.
+
+ * git-remote-mw (in contrib/) adds a command to allow previewing the
+   contents locally before pushing it out, when working with a
+   MediaWiki remote.
+
+
+UI, Workflows & Features
+
+ * Sample "post-receive-email" hook script got an enhanced replacement
+   "multimail" (in contrib/).
+
+ * Also in contrib/ is a new "contacts" script that runs "git blame"
+   to find out the people who may be interested in a set of changes.
+
+ * "git clean" command learned an interactive mode.
+
+ * The "--head" option to "git show-ref" was only to add "HEAD" to the
+   list of candidate refs to be filtered by the usual rules
+   (e.g. "--heads" that only show refs under refs/heads).  The meaning
+   of the option has been changed to always show "HEAD" regardless of
+   what filtering will be applied to any other ref.
+
+   This is a backward incompatible change and might cause breakages to
+   people's existing scripts.
+
+ * "git show -s" was less discoverable than it should have been.  It
+   now has a natural synonym "git show --no-patch".
+
+ * "git check-mailmap" is a new command that lets you map usernames
+   and e-mail addresses through the mailmap mechanism, just like many
+   built-in commands do.
+
+ * "git name-rev" learned to name an annotated tag object back to its
+   tagname; "git name-rev $(git rev-parse v1.0.0)" gives "tags/v1.0.0",
+   for example.
+
+ * "git cat-file --batch-check=<format>" is added, primarily to allow
+   on-disk footprint of objects in packfiles (often they are a lot
+   smaller than their true size, when expressed as deltas) to be
+   reported.
+
+ * "git rebase [-i]" used to leave just "rebase" as its reflog messages
+   for some operations. They have been reworded to be more informative.
+
+ * In addition to the choice from "rebase, merge, or checkout-detach",
+   "submodule update" can allow a custom command to be used in to
+   update the working tree of submodules via the "submodule.*.update"
+   configuration variable.
+
+ * "git submodule update" can optionally clone the submodule
+   repositories shallowly.
+
+ * "git format-patch" learned "--from[=whom]" option, which sets the
+   "From: " header to the specified person (or the person who runs the
+   command, if "=whom" part is missing) and move the original author
+   information to an in-body From: header as necessary.
+
+ * The configuration variable "merge.ff" was cleary a tri-state to
+   choose one from "favor fast-forward when possible", "always create
+   a merge even when the history could fast-forward" and "do not
+   create any merge, only update when the history fast-forwards", but
+   the command line parser did not implement the usual convention of
+   "last one wins, and command line overrides the configuration"
+   correctly.
+
+ * "gitweb" learned to optionally place extra links that point at the
+   levels higher than the Gitweb pages themselves in the breadcrumbs,
+   so that it can be used as part of a larger installation.
+
+ * "git log --format=" now honors i18n.logoutputencoding configuration
+   variable.
+
+ * The "push.default=simple" mode of "git push" has been updated to
+   behave like "current" without requiring a remote tracking
+   information, when you push to a remote that is different from where
+   you fetch from (i.e. a triangular workflow).
+
+ * Having multiple "fixup!" on a line in the rebase instruction sheet
+   did not work very well with "git rebase -i --autosquash".
+
+ * "git log" learned the "--author-date-order" option, with which the
+   output is topologically sorted and commits in parallel histories
+   are shown intermixed together based on the author timestamp.
+
+ * Various subcommands of "git submodule" refused to run from anywhere
+   other than the top of the working tree of the superproject, but
+   they have been taught to let you run from a subdirectory.
+
+ * "git diff" learned a mode that ignores hunks whose change consists
+   only of additions and removals of blank lines, which is the same as
+   "diff -B" (ignore blank lines) of GNU diff.
+
+ * "git rm" gives a single message followed by list of paths to report
+   multiple paths that cannot be removed.
+
+ * "git rebase" can be told with ":/look for this string" syntax commits
+   to replay the changes onto and where the work to be replayed begins.
+
+ * Many tutorials teach users to set "color.ui" to "auto" as the first
+   thing after you set "user.name/email" to introduce yourselves to
+   Git.  Now the variable defaults to "auto".
+
+ * On Cygwin, "cygstart" is now recognised as a possible way to start
+   a web browser (used in "help -w" and "instaweb" among others).
+
+ * "git status" learned status.branch and status.short configuration
+   variables to use --branch and --short options by default (override
+   with --no-branch and --no-short options from the command line).
+
+ * "git cmd <name>", when <name> happens to be a 40-hex string,
+   directly uses the 40-hex string as an object name, even if a ref
+   "refs/<some hierarchy>/<name>" exists.  This disambiguation order
+   is unlikely to change, but we should warn about the ambiguity just
+   like we warn when more than one refs/ hierarchies share the same
+   name.
+
+ * "git rebase" learned "--[no-]autostash" option to save local
+   changes instead of refusing to run (to which people's normal
+   response was to stash them and re-run).  This introduced a corner
+   case breakage to "git am --abort" but it has been fixed.
+
+ * "check-ignore" (new feature since 1.8.2) has been updated to work
+   more like "check-attr" over bidi-pipes.
+
+ * "git describe" learned "--first-parent" option to limit its closest
+   tagged commit search to the first-parent chain.
+
+ * "git merge foo" that might have meant "git merge origin/foo" is
+   diagnosed with a more informative error message.
+
+ * "git log -L<line>,<range>:<filename>" has been added.  This may
+   still have leaks and rough edges, though.
+
+ * We used the approxidate() parser for "--expire=<timestamp>" options
+   of various commands, but it is better to treat --expire=all and
+   --expire=now a bit more specially than using the current timestamp.
+   "git gc" and "git reflog" have been updated with a new parsing
+   function for expiry dates.
+
+ * Updates to completion (both bash and zsh) helpers.
+
+ * The behaviour of the "--chain-reply-to" option of "git send-email"
+   have changed at 1.7.0, and we added a warning/advice message to
+   help users adjust to the new behaviour back then, but we kept it
+   around for too long.  The message has finally been removed.
+
+ * "git fetch origin master" unlike "git fetch origin" or "git fetch"
+   did not update "refs/remotes/origin/master"; this was an early
+   design decision to keep the update of remote tracking branches
+   predictable, but in practice it turns out that people find it more
+   convenient to opportunistically update them whenever we have a
+   chance, and we have been updating them when we run "git push" which
+   already breaks the original "predictability" anyway.
+
+ * The configuration variable core.checkstat was advertised in the
+   documentation but the code expected core.statinfo instead.
+   For now, we accept both core.checkstat and core.statinfo, but the
+   latter will be removed in the longer term.
+
+
+Performance, Internal Implementation, etc.
+
+ * On Cygwin, we used to use our own lstat(2) emulation that is
+   allegedly faster than the platform one in codepaths where some of
+   the information it returns did not matter, but it started to bite
+   us in a few codepaths where the trick it uses to cheat does show
+   breakages. This emulation has been removed and we use the native
+   lstat(2) emulation supplied by Cygwin now.
+
+ * The function attributes extensions are used to catch mistakes in
+   use of our own variadic functions that use NULL sentinel at the end
+   (i.e. like execl(3)) and format strings (i.e. like printf(3)).
+
+ * The code to allow configuration data to be read from in-tree blob
+   objects is in.  This may help working in a bare repository and
+   submodule updates.
+
+ * Fetching between repositories with many refs employed O(n^2)
+   algorithm to match up the common objects, which has been corrected.
+
+ * The original way to specify remote repository using .git/branches/
+   used to have a nifty feature.  The code to support the feature was
+   still in a function but the caller was changed not to call it 5
+   years ago, breaking that feature and leaving the supporting code
+   unreachable.  The dead code has been removed.
+
+ * "git pack-refs" that races with new ref creation or deletion have
+   been susceptible to lossage of refs under right conditions, which
+   has been tightened up.
+
+ * We read loose and packed references in two steps, but after
+   deciding to read a loose ref but before actually opening it to read
+   it, another process racing with us can unlink it, which would cause
+   us to barf.  The codepath has been updated to retry when such a
+   race is detected, instead of outright failing.
+
+ * Uses of the platform fnmatch(3) function (many places in the code,
+   matching pathspec, .gitignore and .gitattributes to name a few)
+   have been replaced with wildmatch, allowing "foo/**/bar" that would
+   match foo/bar, foo/a/bar, foo/a/b/bar, etc.
+
+ * Memory ownership and lifetime rules for what for-each-ref feeds to
+   its callbacks have been clarified (in short, "you do not own it, so
+   make a copy if you want to keep it").
+
+ * The revision traversal logic to improve culling of irrelevant
+   parents while traversing a mergy history has been updated.
+
+ * Some leaks in unpack-trees (used in merge, cherry-pick and other
+   codepaths) have been plugged.
+
+ * The codepath to read from marks files in fast-import/export did not
+   have to accept anything but 40-hex representation of the object
+   name.  Further, fast-export did not need full in-core object
+   representation to have parsed wen reading from them.  These
+   codepaths have been optimized by taking advantage of these access
+   patterns.
+
+ * Object lookup logic, when the object hashtable starts to become
+   crowded, has been optimized.
+
+ * When TEST_OUTPUT_DIRECTORY setting is used, it was handled somewhat
+   inconsistently between the test framework and t/Makefile, and logic
+   to summarize the results looked at a wrong place.
+
+ * "git clone" uses a lighter-weight implementation when making sure
+   that the history behind refs are complete.
+
+ * Many warnings from sparse source checker in compat/ area has been
+   squelched.
+
+ * The code to reading and updating packed-refs file has been updated,
+   correcting corner case bugs.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.3
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.3 in the maintenance
+track are contained in this release (see release notes to them for
+details).
+
+ * Newer Net::SMTP::SSL module does not want the user programs to use
+   the default behaviour to let server certificate go without
+   verification, so by default enable the verification with a
+   mechanism to turn it off if needed.
+   (merge 35035bb rr/send-email-ssl-verify later to maint).
+
+ * When "git" is spawned in such a way that any of the low 3 file
+   descriptors is closed, our first open() may yield file descriptor 2,
+   and writing error message to it would screw things up in a big way.
+   (merge a11c396 tr/protect-low-3-fds later to maint).
+
+ * The mailmap mechanism unnecessarily downcased the e-mail addresses
+   in the output, and also ignored the human name when it is a single
+   character name.
+   (merge bd23794 jc/mailmap-case-insensitivity later to maint).
+
+ * In two places we did not check return value (expected to be a file
+   descriptor) correctly.
+   (merge a77f106 tr/fd-gotcha-fixes later to maint).
+
+ * Logic to auto-detect character encodings in the commit log message
+   did not reject overlong and invalid UTF-8 characters.
+   (merge 81050ac bc/commit-invalid-utf8 later to maint).
+
+ * Pass port number as a separate argument when "send-email" initializes
+   Net::SMTP, instead of as a part of the hostname, i.e. host:port.
+   This allows GSSAPI codepath to match with the hostname given.
+   (merge 1a741bf bc/send-email-use-port-as-separate-param later to maint).
+
+ * "git diff" refused to even show difference when core.safecrlf is
+   set to true (i.e. error out) and there are offending lines in the
+   working tree files.
+   (merge 5430bb2 jc/maint-diff-core-safecrlf later to maint).
+
+ * A test that should have failed but didn't revealed a bug that needs
+   to be corrected.
+   (merge 94d75d1 jc/t1512-fix later to maint).
+
+ * An overlong path to a .git directory may have overflown the
+   temporary path buffer used to create a name for lockfiles.
+   (merge 2fbd4f9 mh/maint-lockfile-overflow later to maint).
+
+ * Invocations of "git checkout" used internally by "git rebase" were
+   counted as "checkout", and affected later "git checkout -", which took
+   the user to an unexpected place.
+   (merge 3bed291 rr/rebase-checkout-reflog later to maint).
+
+ * The configuration variable column.ui was poorly documented.
+   (merge 5e62cc1 rr/column-doc later to maint).
+
+ * "git name-rev --refs=tags/v*" were forbidden, which was a bit
+   inconvenient (you had to give a pattern to match refs fully, like
+   --refs=refs/tags/v*).
+   (merge 98c5c4a nk/name-rev-abbreviated-refs later to maint).
+
+ * "git apply" parsed patches that add new files, generated by
+   programs other than Git, incorrectly.  This is an old breakage in
+   v1.7.11 and will need to be merged down to the maintenance tracks.
+
+ * Older cURL wanted piece of memory we call it with to be stable, but
+   we updated the auth material after handing it to a call.
+
+ * "git pull" into nothing trashed "local changes" that were in the
+   index, and this avoids it.
+
+ * Many "git submodule" operations do not work on a submodule at a
+   path whose name is not in ASCII.
+
+ * "cherry-pick" had a small leak in an error codepath.
+
+ * Logic used by git-send-email to suppress cc mishandled names like
+   "A U. Thor" <author@xxxxxxxxxx>, where the human readable part
+   needs to be quoted (the user input may not have the double quotes
+   around the name, and comparison was done between quoted and
+   unquoted strings).  It also mishandled names that need RFC2047
+   quoting.
+
+ * Call to discard_cache/discard_index (used when we use different
+   contents of the index in-core, in many operations like commit,
+   apply, and merge) used to leak memory that held the array of index
+   entries, which has been plugged.
+   (merge a0fc4db rs/discard-index-discard-array later to maint).
+
+ * "gitweb" forgot to clear a global variable $search_regexp upon each
+   request, mistakenly carrying over the previous search to a new one
+   when used as a persistent CGI.
+
+ * The wildmatch engine did not honor WM_CASEFOLD option correctly.
+
+ * "git log -c --follow $path" segfaulted upon hitting the commit that
+   renamed the $path being followed.
+
+ * When a reflog notation is used for implicit "current branch", we
+   did not say which branch and worse said "branch ''".
+
+ * "difftool --dir-diff" did not copy back changes made by the
+   end-user in the diff tool backend to the working tree in some
+   cases.
+
+ * "git push $there HEAD:branch" did not resolve HEAD early enough, so
+   it was easy to flip it around while push is still going on and push
+   out a branch that the user did not originally intended when the
+   command was started.
+
+ * The bash prompt code (in contrib/) displayed the name of the branch
+   being rebased when "rebase -i/-m/-p" modes are in use, but not the
+   plain vanilla "rebase".
+
+ * Handling of negative exclude pattern for directories "!dir" was
+   broken in the update to v1.8.3.
+
+ * zsh prompt script that borrowed from bash prompt script did not
+   work due to slight differences in array variable notation between
+   these two shells.
+
+ * An entry for "file://" scheme in the enumeration of URL types Git
+   can take in the HTML documentation was made into a clickable link
+   by mistake.
+
+ * "git push --[no-]verify" was not documented.
+
+ * Stop installing the git-remote-testpy script that is only used for
+   testing.
+
+ * "git commit --allow-empty-message -m ''" should not start an
+   editor.
+
+ * "git merge @{-1}~22" was rewritten to "git merge frotz@{1}~22"
+   incorrectly when your previous branch was "frotz" (it should be
+   rewritten to "git merge frotz~22" instead).
+
+ * "git diff -c -p" was not showing a deleted line from a hunk when
+   another hunk immediately begins where the earlier one ends.
+
+ * "git log --ancestry-path A...B" did not work as expected, as it did
+   not pay attention to the fact that the merge base between A and B
+   was the bottom of the range being specified.
+
+ * Mac OS X does not like to write(2) more than INT_MAX number of
+   bytes; work it around by chopping write(2) into smaller pieces.
+
+ * Newer MacOS X encourages the programs to compile and link with
+   their CommonCrypto, not with OpenSSL.
+
+ * "git clone foo/bar:baz" cannot be a request to clone from a remote
+   over git-over-ssh specified in the scp style.  This case is now
+   detected and clones from a local repository at "foo/bar:baz".
+
+ * When $HOME is misconfigured to point at an unreadable directory, we
+   used to complain and die. Loosen the check.
+
+ * "git subtree" (in contrib/) had one codepath with loose error
+   checks to lose data at the remote side.
+
+ * "git fetch" into a shallow repository from a repository that does
+   not know about the shallow boundary commits (e.g. a different fork
+   from the repository the current shallow repository was cloned from)
+   did not work correctly.
+
+ * "git checkout foo" DWIMs the intended "upstream" and turns it into
+   "git checkout -t -b foo remotes/origin/foo". This codepath has been
+   updated to correctly take existing remote definitions into account.
diff --git a/Documentation/RelNotes/1.8.5.1.txt b/Documentation/RelNotes/1.8.5.1.txt
new file mode 100644
index 0000000000..7236aaf232
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.1.txt
@@ -0,0 +1,9 @@
+Git v1.8.5.1 Release Notes
+==========================
+
+Fixes since v1.8.5
+------------------
+
+ * "git submodule init" copied "submodule.$name.update" settings from
+   .gitmodules to .git/config without making sure if the suggested
+   value was sensible.
diff --git a/Documentation/RelNotes/1.8.5.2.txt b/Documentation/RelNotes/1.8.5.2.txt
new file mode 100644
index 0000000000..3ac4984f10
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.2.txt
@@ -0,0 +1,20 @@
+Git v1.8.5.2 Release Notes
+==========================
+
+Fixes since v1.8.5.1
+--------------------
+
+ * "git diff -- ':(icase)makefile'" was unnecessarily rejected at the
+   command line parser.
+
+ * "git cat-file --batch-check=ok" did not check the existence of
+   the named object.
+
+ * "git am --abort" sometimes complained about not being able to write
+   a tree with an 0{40} object in it.
+
+ * Two processes creating loose objects at the same time could have
+   failed unnecessarily when the name of their new objects started
+   with the same byte value, due to a race condition.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.3.txt b/Documentation/RelNotes/1.8.5.3.txt
new file mode 100644
index 0000000000..3de2dd0f19
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.3.txt
@@ -0,0 +1,27 @@
+Git v1.8.5.3 Release Notes
+==========================
+
+Fixes since v1.8.5.2
+--------------------
+
+ * The "--[no-]informative-errors" options to "git daemon" were parsed
+   a bit too loosely, allowing any other string after these option
+   names.
+
+ * A "gc" process running as a different user should be able to stop a
+   new "gc" process from starting.
+
+ * An earlier "clean-up" introduced an unnecessary memory leak to the
+   credential subsystem.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+   out, but it didn't.
+
+ * "git rev-parse <revs> -- <paths>" did not implement the usual
+   disambiguation rules the commands in the "git log" family used in
+   the same way.
+
+ * "git cat-file --batch=", an admittedly useless command, did not
+   behave very well.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.4.txt b/Documentation/RelNotes/1.8.5.4.txt
new file mode 100644
index 0000000000..d18c40389e
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.4.txt
@@ -0,0 +1,48 @@
+Git v1.8.5.4 Release Notes
+==========================
+
+Fixes since v1.8.5.3
+--------------------
+
+ * "git fetch --depth=0" was a no-op, and was silently ignored.
+   Diagnose it as an error.
+
+ * Remote repository URL expressed in scp-style host:path notation are
+   parsed more carefully (e.g. "foo/bar:baz" is local, "[::1]:/~user" asks
+   to connect to user's home directory on host at address ::1.
+
+ * SSL-related options were not passed correctly to underlying socket
+   layer in "git send-email".
+
+ * "git commit -v" appends the patch to the log message before
+   editing, and then removes the patch when the editor returned
+   control. However, the patch was not stripped correctly when the
+   first modified path was a submodule.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+   out, but it didn't.
+
+ * When we figure out how many file descriptors to allocate for
+   keeping packfiles open, a system with non-working getrlimit() could
+   cause us to die(), but because we make this call only to get a
+   rough estimate of how many is available and we do not even attempt
+   to use up all file descriptors available ourselves, it is nicer to
+   fall back to a reasonable low value rather than dying.
+
+ * "git log --decorate" did not handle a tag pointed by another tag
+   nicely.
+
+ * "git add -A" (no other arguments) in a totally empty working tree
+   used to emit an error.
+
+ * There is no reason to have a hardcoded upper limit of the number of
+   parents for an octopus merge, created via the graft mechanism, but
+   there was.
+
+ * The implementation of 'git stash $cmd "stash@{...}"' did not quote
+   the stash argument properly and left it split at IFS whitespace.
+
+ * The documentation to "git pull" hinted there is an "-m" option
+   because it incorrectly shared the documentation with "git merge".
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.5.txt b/Documentation/RelNotes/1.8.5.5.txt
new file mode 100644
index 0000000000..9191ce948f
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.5.txt
@@ -0,0 +1,37 @@
+Git v1.8.5.5 Release Notes
+==========================
+
+Fixes since v1.8.5.4
+--------------------
+
+ * The pathspec matching code, while comparing two trees (e.g. "git
+   diff A B -- path1 path2") was too aggressive and failed to match
+   some paths when multiple pathspecs were involved.
+
+ * "git repack --max-pack-size=8g" stopped being parsed correctly when
+   the command was reimplemented in C.
+
+ * A recent update to "git send-email" broke platforms where
+   /etc/ssl/certs/ directory exists but cannot be used as SSL_ca_path
+   (e.g. Fedora rawhide).
+
+ * A handful of bugs around interpreting $branch@{upstream} notation
+   and its lookalike, when $branch part has interesting characters,
+   e.g. "@", and ":", have been fixed.
+
+ * "git clone" would fail to clone from a repository that has a ref
+   directly under "refs/", e.g. "refs/stash", because different
+   validation paths do different things on such a refname.  Loosen the
+   client side's validation to allow such a ref.
+
+ * "git log --left-right A...B" lost the "leftness" of commits
+   reachable from A when A is a tag as a side effect of a recent
+   bugfix.  This is a regression in 1.8.4.x series.
+
+ * "git merge-base --octopus" used to leave cleaning up suboptimal
+   result to the caller, but now it does the clean-up itself.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+   out, but it didn't.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.6.txt b/Documentation/RelNotes/1.8.5.6.txt
new file mode 100644
index 0000000000..92ff92b1e6
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.6.txt
@@ -0,0 +1,34 @@
+Git v1.8.5.6 Release Notes
+==========================
+
+Fixes since v1.8.5.5
+--------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+   running on a case sensitive filesystem, but an attempt to check out
+   such a path with Git that runs on a case insensitive filesystem
+   would have clobbered ".git/config", which is definitely not what
+   the user would have expected.  Git now prevents you from tracking
+   a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+   are mapped to ".git", e.g. "git~1/config" is treated as if it were
+   ".git/config".  HFS+ has a similar issue, where certain unicode
+   codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+   it were ".git/config".  Pathnames with these potential issues are
+   rejected on the affected systems.  Git on systems that are not
+   affected by this issue (e.g. Linux) can also be configured to
+   reject them to ensure cross platform interoperability of the hosted
+   projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+   be confused with ".git", and with receive.fsckObjects configuration
+   set to true, an attempt to "git push" such a tree object will be
+   rejected.  Such a path may not be a problem on a well behaving
+   filesystem but in order to protect those on HFS+ and on case
+   insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/1.8.5.txt b/Documentation/RelNotes/1.8.5.txt
new file mode 100644
index 0000000000..602df0cac2
--- /dev/null
+++ b/Documentation/RelNotes/1.8.5.txt
@@ -0,0 +1,456 @@
+Git v1.8.5 Release Notes
+========================
+
+Backward compatibility notes (for Git 2.0)
+------------------------------------------
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  In Git 2.0, the default will change to the "simple"
+semantics, which pushes:
+
+ - only the current branch to the branch with the same name, and only
+   when the current branch is set to integrate with that remote
+   branch, if you are pushing to the same remote as you fetch from; or
+
+ - only the current branch to the branch with the same name, if you
+   are pushing to a remote that is not where you usually fetch from.
+
+Use the user preference configuration variable "push.default" to
+change this.  If you are an old-timer who is used to the "matching"
+semantics, you can set the variable to "matching" to keep the
+traditional behaviour.  If you want to live in the future early, you
+can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands.  There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes.  A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal.  Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+The default prefix for "git svn" will change in Git 2.0.  For a long
+time, "git svn" created its remote-tracking branches directly under
+refs/remotes, but it will place them under refs/remotes/origin/ unless
+it is told otherwise with its --prefix option.
+
+
+Updates since v1.8.4
+--------------------
+
+Foreign interfaces, subsystems and ports.
+
+ * "git-svn" has been taught to use the serf library, which is the
+   only option SVN 1.8.0 offers us when talking the HTTP protocol.
+
+ * "git-svn" talking over an https:// connection using the serf library
+   dumped core due to a bug in the serf library that SVN uses.  Work
+   around it on our side, even though the SVN side is being fixed.
+
+ * On MacOS X, we detected if the filesystem needs the "pre-composed
+   unicode strings" workaround, but did not automatically enable it.
+   Now we do.
+
+ * remote-hg remote helper misbehaved when interacting with a local Hg
+   repository relative to the home directory, e.g. "clone hg::~/there".
+
+ * imap-send ported to OS X uses Apple's security framework instead of
+   OpenSSL's.
+
+ * "git fast-import" treats an empty path given to "ls" as the root of
+   the tree.
+
+
+UI, Workflows & Features
+
+ * xdg-open can be used as a browser backend for "git web-browse"
+   (hence to show "git help -w" output), when available.
+
+ * "git grep" and "git show" pay attention to the "--textconv" option
+   when these commands are told to operate on blob objects (e.g. "git
+   grep -e pattern --textconv HEAD:Makefile").
+
+ * "git replace" helper no longer allows an object to be replaced with
+   another object of a different type to avoid confusion (you can
+   still manually craft such a replacement using "git update-ref", as an
+   escape hatch).
+
+ * "git status" no longer prints the dirty status information of
+   submodules for which submodule.$name.ignore is set to "all".
+
+ * "git rebase -i" honours core.abbrev when preparing the insn sheet
+   for editing.
+
+ * "git status" during a cherry-pick shows which original commit is
+   being picked.
+
+ * Instead of typing four capital letters "HEAD", you can say "@" now,
+   e.g. "git log @".
+
+ * "git check-ignore" follows the same rule as "git add" and "git
+   status" in that the ignore/exclude mechanism does not take effect
+   on paths that are already tracked.  With the "--no-index" option, it
+   can be used to diagnose which paths that should have been ignored
+   have been mistakenly added to the index.
+
+ * Some irrelevant "advice" messages that are shared with "git status"
+   output have been removed from the commit log template.
+
+ * "update-refs" learned a "--stdin" option to read multiple update
+   requests and perform them in an all-or-none fashion.
+
+ * Just like "make -C <directory>", "git -C <directory> ..." tells Git
+   to go there before doing anything else.
+
+ * Just like "git checkout -" knows to check out, and "git merge -"
+   knows to merge, the branch you were previously on, "git cherry-pick"
+   now understands "git cherry-pick -" to pick from the previous
+   branch.
+
+ * "git status" now omits the prefix to make its output a comment in a
+   commit log editor, which is not necessary for human consumption.
+   Scripts that parse the output of "git status" are advised to use
+   "git status --porcelain" instead, as its format is stable and easier
+   to parse.
+
+ * The ref syntax "foo^{tag}" (with the literal string "{tag}") peels a
+   tag ref to itself, i.e. it's a no-op., and fails if
+   "foo" is not a tag.  "git rev-parse --verify v1.0^{tag}" is
+   a more convenient way than "test $(git cat-file -t v1.0) = tag" to
+   check if v1.0 is a tag.
+
+ * "git branch -v -v" (and "git status") did not distinguish among a
+   branch that is not based on any other branch, a branch that is in
+   sync with its upstream branch, and a branch that is configured with an
+   upstream branch that no longer exists.
+
+ * Earlier we started rejecting any attempt to add the 0{40} object name to
+   the index and to tree objects, but it sometimes is necessary to
+   allow this to be able to use tools like filter-branch to correct such
+   broken tree objects.  "filter-branch" can again be used to do this.
+
+ * "git config" did not provide a way to set or access numbers larger
+   than a native "int" on the platform; it now provides 64-bit signed
+   integers on all platforms.
+
+ * "git pull --rebase" always chose to do the bog-standard flattening
+   rebase.  You can tell it to run "rebase --preserve-merges" with
+   "git pull --rebase=preserve" or by
+   setting "pull.rebase" configuration to "preserve".
+
+ * "git push --no-thin" actually disables the "thin pack transfer"
+   optimization.
+
+ * Magic pathspecs like ":(icase)makefile" (matches both Makefile
+   and makefile) and ":(glob)foo/**/bar" (matches "bar" in "foo"
+   and any subdirectory of "foo") can be used in more places.
+
+ * The "http.*" variables can now be specified for individual URLs.
+   For example,
+
+   [http]
+       sslVerify = true
+   [http "https://weak.example.com/";]
+       sslVerify = false
+
+   would flip http.sslVerify off only when talking to that specific
+   site.
+
+ * "git mv A B" when moving a submodule has been taught to
+   relocate the submodule's working tree and to adjust the paths in the
+   .gitmodules file.
+
+ * "git blame" can now take more than one -L option to discover the
+   origin of multiple blocks of lines.
+
+ * The http transport clients can optionally ask to save cookies
+   with the http.savecookies configuration variable.
+
+ * "git push" learned a more fine grained control over a blunt
+   "--force" when requesting a non-fast-forward update with the
+   "--force-with-lease=<refname>:<expected object name>" option.
+
+ * "git diff --diff-filter=<classes of changes>" can now take
+   lowercase letters (e.g. "--diff-filter=d") to mean "show
+   everything but these classes".  "git diff-files -q" is now a
+   deprecated synonym for "git diff-files --diff-filter=d".
+
+ * "git fetch" (hence "git pull" as well) learned to check
+   "fetch.prune" and "remote.*.prune" configuration variables and
+   to behave as if the "--prune" command line option was given.
+
+ * "git check-ignore -z" applied the NUL termination to both its input
+   (with --stdin) and its output, but "git check-attr -z" ignored the
+   option on the output side. Make both honor -z on the input and
+   output side the same way.
+
+ * "git whatchanged" may still be used by old timers, but mention of
+   it in documents meant for new users will only waste readers' time
+   wondering what the difference is between it and "git log".  Make it
+   less prominent in the general part of the documentation and explain
+   that it is merely a "git log" with different default behaviour in
+   its own document.
+
+
+Performance, Internal Implementation, etc.
+
+ * "git for-each-ref" when asking for merely the object name does not
+   have to parse the object pointed at by the refs; the codepath has
+   been optimized.
+
+ * The HTTP transport will try to use TCP keepalive when able.
+
+ * "git repack" is now written in C.
+
+ * Build procedure for MSVC has been updated.
+
+ * If a build-time fallback is set to "cat" instead of "less", we
+   should apply the same "no subprocess or pipe" optimization as we
+   apply to user-supplied GIT_PAGER=cat.
+
+ * Many commands use a --dashed-option as an operation mode selector
+   (e.g. "git tag --delete") that excludes other operation modes
+   (e.g. "git tag --delete --verify" is nonsense) and that cannot be
+   negated (e.g. "git tag --no-delete" is nonsense).  The parse-options
+   API learned a new OPT_CMDMODE macro to make it easier to implement
+   such a set of options.
+
+ * OPT_BOOLEAN() in the parse-options API was misdesigned to be "counting
+   up" but many subcommands expect it to behave as "on/off". Update
+   them to use OPT_BOOL() which is a proper boolean.
+
+ * "git gc" exits early without doing any work when it detects
+   that another instance of itself is already running.
+
+ * Under memory pressure and/or file descriptor pressure, we used to
+   close pack windows that are not used and also closed filehandles to
+   open but unused packfiles. These are now controlled separately
+   to better cope with the load.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.4
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.4 in the maintenance
+track are contained in this release (see the maintenance releases' notes for
+details).
+
+ * An ancient How-To on serving Git repositories on an HTTP server
+   lacked a warning that it has been mostly superseded with a more
+   modern way.
+   (merge 6d52bc3 sc/doc-howto-dumb-http later to maint).
+
+ * The interaction between the use of Perl in our test suite and NO_PERL
+   has been clarified a bit.
+   (merge f8fc0ee jn/test-prereq-perl-doc later to maint).
+
+ * The synopsis section of the "git unpack-objects" documentation has been
+   clarified a bit.
+   (merge 61e2e22 vd/doc-unpack-objects later to maint).
+
+ * We did not generate the HTML version of the documentation to "git subtree"
+   in contrib/.
+   (merge 95c62fb jk/subtree-install-fix later to maint).
+
+ * A fast-import stream expresses a pathname with funny characters by
+   quoting them in C style; the remote-hg remote helper forgot to unquote
+   such a path.
+   (merge 1136265 ap/remote-hg-unquote-cquote later to maint).
+
+ * "git reset -p HEAD" has a codepath to special-case it to behave
+   differently from resetting to contents of other commits, but a
+   recent change broke it.
+
+ * Coloring around octopus merges in "log --graph" output was screwy.
+   (merge 339c17b hn/log-graph-color-octopus later to maint).
+
+ * "git checkout topic", when there is not yet a local "topic" branch
+   but there is a unique remote-tracking branch for a remote "topic"
+   branch, pretended as if "git checkout -t -b topic remote/$r/topic"
+   (for that unique remote $r) was run. This hack however was not
+   implemented for "git checkout topic --".
+   (merge bca3969 mm/checkout-auto-track-fix later to maint).
+
+ * One long-standing flaw in the pack transfer protocol used by "git
+   clone" was that there was no way to tell the other end which branch
+   "HEAD" points at, and the receiving end needed to guess.  A new
+   capability has been defined in the pack protocol to convey this
+   information so that cloning from a repository with more than one
+   branch pointing at the same commit where the HEAD is at now
+   reliably sets the initial branch in the resulting repository.
+   (merge 360a326 jc/upload-pack-send-symref later to maint).
+
+ * We did not handle cases where the http transport gets redirected during
+   the authorization request (e.g. from http:// to https://).
+   (merge 70900ed jk/http-auth-redirects later to maint).
+
+ * Bash prompting code to deal with an SVN remote as an upstream
+   was coded in a way unsupported by older Bash versions (3.x).
+   (merge 52ec889 sg/prompt-svn-remote-fix later to maint).
+
+ * The fall-back parsing of commit objects with broken author or
+   committer lines was less robust than ideal in picking up the
+   timestamps.
+   (merge 03818a4 jk/split-broken-ident later to maint).
+
+ * "git rev-list --objects ^v1.0^ v1.0" gave the v1.0 tag itself in the
+   output, but "git rev-list --objects v1.0^..v1.0" did not.
+   (merge 895c5ba jc/revision-range-unpeel later to maint).
+
+ * "git clone" wrote some progress messages to standard output, not
+   to standard error, and did not suppress them with the
+   --no-progress option.
+   (merge 643f918 jk/clone-progress-to-stderr later to maint).
+
+ * "format-patch --from=<whom>" forgot to omit an unnecessary in-body
+   from line, i.e. when <whom> is the same as the real author.
+   (merge 662cc30 jk/format-patch-from later to maint).
+
+ * "git shortlog" used to choke and die when there is a malformed
+   commit (e.g. missing authors); it now simply ignores such a commit
+   and keeps going.
+   (merge cd4f09e jk/shortlog-tolerate-broken-commit later to maint).
+
+ * "git merge-recursive" did not parse its "--diff-algorithm=" command
+   line option correctly.
+   (merge 6562928 jk/diff-algo later to maint).
+
+ * When running "fetch -q", a long silence while the sender side
+   computes the set of objects to send can be mistaken by proxies as
+   dropped connection.  The server side has been taught to send a
+   small empty messages to keep the connection alive.
+   (merge 115dedd jk/upload-pack-keepalive later to maint).
+
+ * "git rebase" had a portability regression in v1.8.4 that triggered a
+   bug in some BSD shell implementations.
+   (merge 99855dd mm/rebase-continue-freebsd-WB later to maint).
+
+ * "git branch --track" had a minor regression in v1.8.3.2 and later
+   that made it impossible to base your local work on anything but a
+   local branch of the upstream repository you are tracking.
+   (merge b0f49ff jh/checkout-auto-tracking later to maint).
+
+ * When the web server responds with "405 Method Not Allowed", "git
+   http-backend" should tell the client what methods are allowed with
+   the "Allow" header.
+   (merge 9247be0 bc/http-backend-allow-405 later to maint).
+
+ * When there is no sufficient overlap between old and new history
+   during a "git fetch" into a shallow repository, objects that the
+   sending side knows the receiving end has were unnecessarily sent.
+   (merge f21d2a7 nd/fetch-into-shallow later to maint).
+
+ * "git cvsserver" computed the permission mode bits incorrectly for
+   executable files.
+   (merge 1b48d56 jc/cvsserver-perm-bit-fix later to maint).
+
+ * When send-email obtains an error message to die with upon
+   failure to start an SSL session, it tried to read the error string
+   from a wrong place.
+   (merge 6cb0c88 bc/send-email-ssl-die-message-fix later to maint).
+
+ * The implementation of "add -i" has some crippling code to work around an
+   ActiveState Perl limitation but it by mistake also triggered on Git
+   for Windows where MSYS perl is used.
+   (merge df17e77 js/add-i-mingw later to maint).
+
+ * We made sure that we notice when the user-supplied GIT_DIR is actually a
+   gitfile, but did not do the same when the default ".git" is a
+   gitfile.
+   (merge 487a2b7 nd/git-dir-pointing-at-gitfile later to maint).
+
+ * When an object is not found after checking the packfiles and the
+   loose object directory, read_sha1_file() re-checks the packfiles to
+   prevent racing with a concurrent repacker; teach the same logic to
+   has_sha1_file().
+   (merge 45e8a74 jk/has-sha1-file-retry-packed later to maint).
+
+ * "git commit --author=$name", when $name is not in the canonical
+   "A. U. Thor <au.thor@xxxxxxxxxx>" format, looks for a matching name
+   from existing history, but did not consult mailmap to grab the
+   preferred author name.
+   (merge ea16794 ap/commit-author-mailmap later to maint).
+
+ * "git ls-files -k" needs to crawl only the part of the working tree
+   that may overlap the paths in the index to find killed files, but
+   shared code with the logic to find all the untracked files, which
+   made it unnecessarily inefficient.
+   (merge 680be04 jc/ls-files-killed-optim later to maint).
+
+ * The shortened commit object names in the insn sheet that is prepared at the
+   beginning of a "rebase -i" session can become ambiguous as the
+   rebasing progresses and the repository gains more commits. Make
+   sure the internal record is kept with full 40-hex object names.
+   (merge 75c6976 es/rebase-i-no-abbrev later to maint).
+
+ * "git rebase --preserve-merges" internally used the merge machinery
+   and as a side effect left the merge summary message in the log, but
+   when rebasing there is no need for the merge summary.
+   (merge a9f739c rt/rebase-p-no-merge-summary later to maint).
+
+ * A call to xread() was used without a loop around it to cope with short
+   reads in the codepath to stream new contents to a pack.
+   (merge e92527c js/xread-in-full later to maint).
+
+ * "git rebase -i" forgot that the comment character is
+   configurable while reading its insn sheet.
+   (merge 7bca7af es/rebase-i-respect-core-commentchar later to maint).
+
+ * The mailmap support code read past the allocated buffer when the
+   mailmap file ended with an incomplete line.
+   (merge f972a16 jk/mailmap-incomplete-line later to maint).
+
+ * We used to send a large request to read(2)/write(2) as a single
+   system call, which was bad from the latency point of view when
+   the operation needs to be killed, and also triggered an error on
+   broken 64-bit systems that refuse to read or write more than 2GB
+   in one go.
+   (merge a487916 sp/clip-read-write-to-8mb later to maint).
+
+ * "git fetch" that auto-followed tags incorrectly reused the
+   connection with Git-aware transport helper (like the sample "ext::"
+   helper shipped with Git).
+   (merge 0f73f8b jc/transport-do-not-use-connect-twice-in-fetch later to maint).
+
+ * "git log --full-diff -- <pathspec>" showed a huge diff for paths
+   outside the given <pathspec> for each commit, instead of showing
+   the change relative to the parent of the commit.  "git reflog -p"
+   had a similar problem.
+   (merge 838f9a1 tr/log-full-diff-keep-true-parents later to maint).
+
+ * Setting a submodule.*.path configuration variable to true (without
+   giving "= value") caused Git to segfault.
+   (merge 4b05440 jl/some-submodule-config-are-not-boolean later to maint).
+
+ * "git rebase -i" (there could be others, as the root cause is pretty
+   generic) fed a random, data dependent string to 'echo' and
+   expected it to come out literally, corrupting its error message.
+   (merge 89b0230 mm/no-shell-escape-in-die-message later to maint).
+
+ * Some people still use rather old versions of bash, which cannot
+   grok some constructs like 'printf -v varname' which the prompt and
+   completion code started to use recently.
+   (merge a44aa69 bc/completion-for-bash-3.0 later to maint).
+
+ * Code to read configuration from a blob object did not compile on
+   platforms with fgetc() etc. implemented as macros.
+   (merge 49d6cfa hv/config-from-blob later to maint-1.8.3).
+
+ * The recent "short-cut clone connectivity check" topic broke a
+   shallow repository when a fetch operation tries to auto-follow tags.
+   (merge 6da8bdc nd/fetch-pack-shallow-fix later to maint-1.8.3).
diff --git a/Documentation/RelNotes/1.9.0.txt b/Documentation/RelNotes/1.9.0.txt
new file mode 100644
index 0000000000..4e4b88aa5c
--- /dev/null
+++ b/Documentation/RelNotes/1.9.0.txt
@@ -0,0 +1,345 @@
+Git v1.9.0 Release Notes
+========================
+
+Backward compatibility notes
+----------------------------
+
+"git submodule foreach $cmd $args" used to treat "$cmd $args" the same
+way "ssh" did, concatenating them into a single string and letting the
+shell unquote. Careless users who forget to sufficiently quote $args
+get their argument split at $IFS whitespaces by the shell, and got
+unexpected results due to this. Starting from this release, the
+command line is passed directly to the shell, if it has an argument.
+
+Read-only support for experimental loose-object format, in which users
+could optionally choose to write their loose objects for a short
+while between v1.4.3 and v1.5.3 era, has been dropped.
+
+The meanings of the "--tags" option to "git fetch" has changed; the
+command fetches tags _in addition to_ what is fetched by the same
+command line without the option.
+
+The way "git push $there $what" interprets the $what part given on the
+command line, when it does not have a colon that explicitly tells us
+what ref at the $there repository is to be updated, has been enhanced.
+
+A handful of ancient commands that have long been deprecated are
+finally gone (repo-config, tar-tree, lost-found, and peek-remote).
+
+
+Backward compatibility notes (for Git 2.0.0)
+--------------------------------------------
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  In Git 2.0, the default will change to the "simple"
+semantics, which pushes:
+
+ - only the current branch to the branch with the same name, and only
+   when the current branch is set to integrate with that remote
+   branch, if you are pushing to the same remote as you fetch from; or
+
+ - only the current branch to the branch with the same name, if you
+   are pushing to a remote that is not where you usually fetch from.
+
+Use the user preference configuration variable "push.default" to
+change this.  If you are an old-timer who is used to the "matching"
+semantics, you can set the variable to "matching" to keep the
+traditional behaviour.  If you want to live in the future early, you
+can set it to "simple" today without waiting for Git 2.0.
+
+When "git add -u" (and "git add -A") is run inside a subdirectory and
+does not specify which paths to add on the command line, it
+will operate on the entire tree in Git 2.0 for consistency
+with "git commit -a" and other commands.  There will be no
+mechanism to make plain "git add -u" behave like "git add -u .".
+Current users of "git add -u" (without a pathspec) should start
+training their fingers to explicitly say "git add -u ."
+before Git 2.0 comes.  A warning is issued when these commands are
+run without a pathspec and when you have local changes outside the
+current directory, because the behaviour in Git 2.0 will be different
+from today's version in such a situation.
+
+In Git 2.0, "git add <path>" will behave as "git add -A <path>", so
+that "git add dir/" will notice paths you removed from the directory
+and record the removal.  Versions before Git 2.0, including this
+release, will keep ignoring removals, but the users who rely on this
+behaviour are encouraged to start using "git add --ignore-removal <path>"
+now before 2.0 is released.
+
+The default prefix for "git svn" will change in Git 2.0.  For a long
+time, "git svn" created its remote-tracking branches directly under
+refs/remotes, but it will place them under refs/remotes/origin/ unless
+it is told otherwise with its --prefix option.
+
+
+Updates since v1.8.5
+--------------------
+
+Foreign interfaces, subsystems and ports.
+
+ * The HTTP transport, when talking GSS-Negotiate, uses "100
+   Continue" response to avoid having to rewind and resend a large
+   payload, which may not be always doable.
+
+ * Various bugfixes to remote-bzr and remote-hg (in contrib/).
+
+ * The build procedure is aware of MirBSD now.
+
+ * Various "git p4", "git svn" and "gitk" updates.
+
+
+UI, Workflows & Features
+
+ * Fetching from a shallowly-cloned repository used to be forbidden,
+   primarily because the codepaths involved were not carefully vetted
+   and we did not bother supporting such usage. This release attempts
+   to allow object transfer out of a shallowly-cloned repository in a
+   more controlled way (i.e. the receiver becomes a shallow repository
+   with a truncated history).
+
+ * Just like we give a reasonable default for "less" via the LESS
+   environment variable, we now specify a reasonable default for "lv"
+   via the "LV" environment variable when spawning the pager.
+
+ * Two-level configuration variable names in "branch.*" and "remote.*"
+   hierarchies, whose variables are predominantly three-level, were
+   not completed by hitting a <TAB> in bash and zsh completions.
+
+ * Fetching a 'frotz' branch with "git fetch", while a 'frotz/nitfol'
+   remote-tracking branch from an earlier fetch was still there, would
+   error out, primarily because the command was not told that it is
+   allowed to lose any information on our side.  "git fetch --prune"
+   now can be used to remove 'frotz/nitfol' to make room for fetching and
+   storing the 'frotz' remote-tracking branch.
+
+ * "diff.orderfile=<file>" configuration variable can be used to
+   pretend as if the "-O<file>" option were given from the command
+   line of "git diff", etc.
+
+ * The negative pathspec syntax allows "git log -- . ':!dir'" to tell
+   us "I am interested in everything but 'dir' directory".
+
+ * "git difftool" shows how many different paths there are in total,
+   and how many of them have been shown so far, to indicate progress.
+
+ * "git push origin master" used to push our 'master' branch to update
+   the 'master' branch at the 'origin' repository.  This has been
+   enhanced to use the same ref mapping "git push origin" would use to
+   determine what ref at the 'origin' to be updated with our 'master'.
+   For example, with this configuration
+
+   [remote "origin"]
+      push = refs/heads/*:refs/review/*
+
+   that would cause "git push origin" to push out our local branches
+   to corresponding refs under refs/review/ hierarchy at 'origin',
+   "git push origin master" would update 'refs/review/master' over
+   there.  Alternatively, if push.default is set to 'upstream' and our
+   'master' is set to integrate with 'topic' from the 'origin' branch,
+   running "git push origin" while on our 'master' would update their
+   'topic' branch, and running "git push origin master" while on any
+   of our branches does the same.
+
+ * "gitweb" learned to treat ref hierarchies other than refs/heads as
+   if they are additional branch namespaces (e.g. refs/changes/ in
+   Gerrit).
+
+ * "git for-each-ref --format=..." learned a few formatting directives;
+   e.g. "%(color:red)%(HEAD)%(color:reset) %(refname:short) %(subject)".
+
+ * The command string given to "git submodule foreach" is passed
+   directly to the shell, without being eval'ed.  This is a backward
+   incompatible change that may break existing users.
+
+ * "git log" and friends learned the "--exclude=<glob>" option, to
+   allow people to say "list history of all branches except those that
+   match this pattern" with "git log --exclude='*/*' --branches".
+
+ * "git rev-parse --parseopt" learned a new "--stuck-long" option to
+   help scripts parse options with an optional parameter.
+
+ * The "--tags" option to "git fetch" no longer tells the command to
+   fetch _only_ the tags. It instead fetches tags _in addition to_
+   what are fetched by the same command line without the option.
+
+
+Performance, Internal Implementation, etc.
+
+ * When parsing a 40-hex string into the object name, the string is
+   checked to see if it can be interpreted as a ref so that a warning
+   can be given for ambiguity. The code kicked in even when the
+   core.warnambiguousrefs is set to false to squelch this warning, in
+   which case the cycles spent to look at the ref namespace were an
+   expensive no-op, as the result was discarded without being used.
+
+ * The naming convention of the packfiles has been updated; it used to
+   be based on the enumeration of names of the objects that are
+   contained in the pack, but now it also depends on how the packed
+   result is represented--packing the same set of objects using
+   different settings (or delta order) would produce a pack with
+   different name.
+
+ * "git diff --no-index" mode used to unnecessarily attempt to read
+   the index when there is one.
+
+ * The deprecated parse-options macro OPT_BOOLEAN has been removed;
+   use OPT_BOOL or OPT_COUNTUP in new code.
+
+ * A few duplicate implementations of prefix/suffix string comparison
+   functions have been unified to starts_with() and ends_with().
+
+ * The new PERLLIB_EXTRA makefile variable can be used to specify
+   additional directories Perl modules (e.g. the ones necessary to run
+   git-svn) are installed on the platform when building.
+
+ * "git merge-base" learned the "--fork-point" mode, that implements
+   the same logic used in "git pull --rebase" to find a suitable fork
+   point out of the reflog entries for the remote-tracking branch the
+   work has been based on.  "git rebase" has the same logic that can be
+   triggered with the "--fork-point" option.
+
+ * A third-party "receive-pack" (the responder to "git push") can
+   advertise the "no-thin" capability to tell "git push" not to use
+   the thin-pack optimization. Our receive-pack has always been
+   capable of accepting and fattening a thin-pack, and will continue
+   not to ask "git push" to use a non-thin pack.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v1.8.5
+------------------
+
+Unless otherwise noted, all the fixes since v1.8.5 in the maintenance
+track are contained in this release (see the maintenance releases' notes
+for details).
+
+ * The pathspec matching code, while comparing two trees (e.g. "git
+   diff A B -- path1 path2") was too aggressive and failed to match
+   some paths when multiple pathspecs were involved.
+
+ * "git repack --max-pack-size=8g" stopped being parsed correctly when
+   the command was reimplemented in C.
+
+ * An earlier update in v1.8.4.x to "git rev-list --objects" with
+   negative ref had a performance regression.
+   (merge 200abe7 jk/mark-edges-uninteresting later to maint).
+
+ * A recent update to "git send-email" broke platforms where
+   /etc/ssl/certs/ directory exists but cannot be used as SSL_ca_path
+   (e.g. Fedora rawhide).
+
+ * A handful of bugs around interpreting $branch@{upstream} notation
+   and its lookalike, when $branch part has interesting characters,
+   e.g. "@", and ":", have been fixed.
+
+ * "git clone" would fail to clone from a repository that has a ref
+   directly under "refs/", e.g. "refs/stash", because different
+   validation paths do different things on such a refname.  Loosen the
+   client side's validation to allow such a ref.
+
+ * "git log --left-right A...B" lost the "leftness" of commits
+   reachable from A when A is a tag as a side effect of a recent
+   bugfix.  This is a regression in 1.8.4.x series.
+
+ * documentations to "git pull" hinted there is an "-m" option because
+   it incorrectly shared the documentation with "git merge".
+
+ * "git diff A B submod" and "git diff A B submod/" ought to have done
+   the same for a submodule "submod", but didn't.
+
+ * "git clone $origin foo\bar\baz" on Windows failed to create the
+   leading directories (i.e. a moral-equivalent of "mkdir -p").
+
+ * "submodule.*.update=checkout", when propagated from .gitmodules to
+   .git/config, turned into a "submodule.*.update=none", which did not
+   make much sense.
+   (merge efa8fd7 fp/submodule-checkout-mode later to maint).
+
+ * The implementation of 'git stash $cmd "stash@{...}"' did not quote
+   the stash argument properly and left it split at IFS whitespace.
+
+ * The "--[no-]informative-errors" options to "git daemon" were parsed
+   a bit too loosely, allowing any other string after these option
+   names.
+
+ * There is no reason to have a hardcoded upper limit for the number of
+   parents of an octopus merge, created via the graft mechanism, but
+   there was.
+
+ * The basic test used to leave unnecessary trash directories in the
+   t/ directory.
+   (merge 738a8be jk/test-framework-updates later to maint).
+
+ * "git merge-base --octopus" used to leave cleaning up suboptimal
+   result to the caller, but now it does the clean-up itself.
+
+ * A "gc" process running as a different user should be able to stop a
+   new "gc" process from starting, but it didn't.
+
+ * An earlier "clean-up" introduced an unnecessary memory leak.
+
+ * "git add -A" (no other arguments) in a totally empty working tree
+   used to emit an error.
+
+ * "git log --decorate" did not handle a tag pointed by another tag
+   nicely.
+
+ * When we figure out how many file descriptors to allocate for
+   keeping packfiles open, a system with non-working getrlimit() could
+   cause us to die(), but because we make this call only to get a
+   rough estimate of how many are available and we do not even attempt
+   to use up all available file descriptors ourselves, it is nicer to
+   fall back to a reasonable low value rather than dying.
+
+ * read_sha1_file(), that is the workhorse to read the contents given
+   an object name, honoured object replacements, but there was no
+   corresponding mechanism to sha1_object_info() that was used to
+   obtain the metainfo (e.g. type & size) about the object.  This led
+   callers to weird inconsistencies.
+   (merge 663a856 cc/replace-object-info later to maint).
+
+ * "git cat-file --batch=", an admittedly useless command, did not
+   behave very well.
+
+ * "git rev-parse <revs> -- <paths>" did not implement the usual
+   disambiguation rules the commands in the "git log" family used in
+   the same way.
+
+ * "git mv A B/", when B does not exist as a directory, should error
+   out, but it didn't.
+
+ * A workaround to an old bug in glibc prior to glibc 2.17 has been
+   retired; this would remove a side effect of the workaround that
+   corrupts system error messages in non-C locales.
+
+ * SSL-related options were not passed correctly to underlying socket
+   layer in "git send-email".
+
+ * "git commit -v" appends the patch to the log message before
+   editing, and then removes the patch when the editor returned
+   control. However, the patch was not stripped correctly when the
+   first modified path was a submodule.
+
+ * "git fetch --depth=0" was a no-op, and was silently ignored.
+   Diagnose it as an error.
+
+ * Remote repository URLs expressed in scp-style host:path notation are
+   parsed more carefully (e.g. "foo/bar:baz" is local, "[::1]:/~user" asks
+   to connect to user's home directory on host at address ::1.
+
+ * "git diff -- ':(icase)makefile'" was unnecessarily rejected at the
+   command line parser.
+
+ * "git cat-file --batch-check=ok" did not check the existence of
+   the named object.
+
+ * "git am --abort" sometimes complained about not being able to write
+   a tree with an 0{40} object in it.
+
+ * Two processes creating loose objects at the same time could have
+   failed unnecessarily when the name of their new objects started
+   with the same byte value, due to a race condition.
diff --git a/Documentation/RelNotes/1.9.1.txt b/Documentation/RelNotes/1.9.1.txt
new file mode 100644
index 0000000000..5b0602053c
--- /dev/null
+++ b/Documentation/RelNotes/1.9.1.txt
@@ -0,0 +1,59 @@
+Git v1.9.1 Release Notes
+========================
+
+Fixes since v1.9.0
+------------------
+
+ * "git clean -d pathspec" did not use the given pathspec correctly
+   and ended up cleaning too much.
+
+ * "git difftool" misbehaved when the repository is bound to the
+   working tree with the ".git file" mechanism, where a textual file
+   ".git" tells us where it is.
+
+ * "git push" did not pay attention to branch.*.pushremote if it is
+   defined earlier than remote.pushdefault; the order of these two
+   variables in the configuration file should not matter, but it did
+   by mistake.
+
+ * Codepaths that parse timestamps in commit objects have been
+   tightened.
+
+ * "git diff --external-diff" incorrectly fed the submodule directory
+   in the working tree to the external diff driver when it knew it is
+   the same as one of the versions being compared.
+
+ * "git reset" needs to refresh the index when working in a working
+   tree (it can also be used to match the index to the HEAD in an
+   otherwise bare repository), but it failed to set up the working
+   tree properly, causing GIT_WORK_TREE to be ignored.
+
+ * "git check-attr" when working on a repository with a working tree
+   did not work well when the working tree was specified via the
+   --work-tree (and obviously with --git-dir) option.
+
+ * "merge-recursive" was broken in 1.7.7 era and stopped working in
+   an empty (temporary) working tree, when there are renames
+   involved.  This has been corrected.
+
+ * "git rev-parse" was loose in rejecting command line arguments
+   that do not make sense, e.g. "--default" without the required
+   value for that option.
+
+ * include.path variable (or any variable that expects a path that
+   can use ~username expansion) in the configuration file is not a
+   boolean, but the code failed to check it.
+
+ * "git diff --quiet -- pathspec1 pathspec2" sometimes did not return
+   correct status value.
+
+ * Attempting to deepen a shallow repository by fetching over smart
+   HTTP transport failed in the protocol exchange, when no-done
+   extension was used.  The fetching side waited for the list of
+   shallow boundary commits after the sending end stopped talking to
+   it.
+
+ * Allow "git cmd path/", when the 'path' is where a submodule is
+   bound to the top-level working tree, to match 'path', despite the
+   extra and unnecessary trailing slash (such a slash is often
+   given by command line completion).
diff --git a/Documentation/RelNotes/1.9.2.txt b/Documentation/RelNotes/1.9.2.txt
new file mode 100644
index 0000000000..47a34ca964
--- /dev/null
+++ b/Documentation/RelNotes/1.9.2.txt
@@ -0,0 +1,67 @@
+Git v1.9.2 Release Notes
+========================
+
+Fixes since v1.9.1
+------------------
+
+ * Documentation and in-code comments had many instances of mistaken
+   use of "nor", which have been corrected.
+
+ * "git fetch --prune", when the right-hand-side of multiple fetch
+   refspecs overlap (e.g. storing "refs/heads/*" to
+   "refs/remotes/origin/*", while storing "refs/frotz/*" to
+   "refs/remotes/origin/fr/*"), aggressively thought that lack of
+   "refs/heads/fr/otz" on the origin site meant we should remove
+   "refs/remotes/origin/fr/otz" from us, without checking their
+   "refs/frotz/otz" first.
+
+   Note that such a configuration is inherently unsafe (think what
+   should happen when "refs/heads/fr/otz" does appear on the origin
+   site), but that is not a reason not to be extra careful.
+
+ * "git update-ref --stdin" did not fail a request to create a ref
+   when the ref already existed.
+
+ * "git diff --no-index -Mq a b" fell into an infinite loop.
+
+ * When it is not necessary to edit a commit log message (e.g. "git
+   commit -m" is given a message without specifying "-e"), we used to
+   disable the spawning of the editor by overriding GIT_EDITOR, but
+   this means all the uses of the editor, other than to edit the
+   commit log message, are also affected.
+
+ * "git status --porcelain --branch" showed its output with labels
+   "ahead/behind/gone" translated to the user's locale.
+
+ * "git mv" that moves a submodule forgot to adjust the array that
+   uses to keep track of which submodules were to be moved to update
+   its configuration.
+
+ * Length limit for the pathname used when removing a path in a deep
+   subdirectory has been removed to avoid buffer overflows.
+
+ * The test helper lib-terminal always run an actual test_expect_*
+   when included, which screwed up with the use of skil-all that may
+   have to be done later.
+
+ * "git index-pack" used a wrong variable to name the keep-file in an
+   error message when the file cannot be written or closed.
+
+ * "rebase -i" produced a broken insn sheet when the title of a commit
+   happened to contain '\n' (or ended with '\c') due to a careless use
+   of 'echo'.
+
+ * There were a few instances of 'git-foo' remaining in the
+   documentation that should have been spelled 'git foo'.
+
+ * Serving objects from a shallow repository needs to write a
+   new file to hold the temporary shallow boundaries but it was not
+   cleaned when we exit due to die() or a signal.
+
+ * When "git stash pop" stops after failing to apply the stash
+   (e.g. due to conflicting changes), the stash is not dropped. State
+   that explicitly in the output to let the users know.
+
+ * The labels in "git status" output that describe the nature of
+   conflicts (e.g. "both deleted") were limited to 20 bytes, which was
+   too short for some l10n (e.g. fr).
diff --git a/Documentation/RelNotes/1.9.3.txt b/Documentation/RelNotes/1.9.3.txt
new file mode 100644
index 0000000000..17b05ca7b5
--- /dev/null
+++ b/Documentation/RelNotes/1.9.3.txt
@@ -0,0 +1,21 @@
+Git v1.9.3 Release Notes
+========================
+
+Fixes since v1.9.2
+------------------
+
+ * "git p4" dealing with changes in binary files were broken by a
+   change in 1.9 release.
+
+ * The shell prompt script (in contrib/), when using the PROMPT_COMMAND
+   interface, used an unsafe construct when showing the branch name in
+   $PS1.
+
+ * "git rebase" used a POSIX shell construct FreeBSD /bin/sh does not
+   work well with.
+
+ * Some more Unicode codepoints defined in Unicode 6.3 as having
+   zero width have been taught to our display column counting logic.
+
+ * Some tests used shell constructs that did not work well on
+   FreeBSD.
diff --git a/Documentation/RelNotes/1.9.4.txt b/Documentation/RelNotes/1.9.4.txt
new file mode 100644
index 0000000000..e1d1835436
--- /dev/null
+++ b/Documentation/RelNotes/1.9.4.txt
@@ -0,0 +1,16 @@
+Git v1.9.4 Release Notes
+========================
+
+Fixes since v1.9.3
+------------------
+
+ * Commands that take pathspecs on the command line misbehaved when
+   the pathspec is given as an absolute pathname (which is a
+   practice not particularly encouraged) that points at a symbolic
+   link in the working tree.
+
+ * An earlier fix to the shell prompt script (in contrib/) for using
+   the PROMPT_COMMAND interface did not correctly check if the extra
+   code path needs to trigger, causing the branch name not to appear
+   when 'promptvars' option is disabled in bash or PROMPT_SUBST is
+   unset in zsh.
diff --git a/Documentation/RelNotes/1.9.5.txt b/Documentation/RelNotes/1.9.5.txt
new file mode 100644
index 0000000000..8d6ac0cf53
--- /dev/null
+++ b/Documentation/RelNotes/1.9.5.txt
@@ -0,0 +1,34 @@
+Git v1.9.5 Release Notes
+========================
+
+Fixes since v1.9.4
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+   running on a case sensitive filesystem, but an attempt to check out
+   such a path with Git that runs on a case insensitive filesystem
+   would have clobbered ".git/config", which is definitely not what
+   the user would have expected.  Git now prevents you from tracking
+   a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+   are mapped to ".git", e.g. "git~1/config" is treated as if it were
+   ".git/config".  HFS+ has a similar issue, where certain unicode
+   codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+   it were ".git/config".  Pathnames with these potential issues are
+   rejected on the affected systems.  Git on systems that are not
+   affected by this issue (e.g. Linux) can also be configured to
+   reject them to ensure cross platform interoperability of the hosted
+   projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+   be confused with ".git", and with receive.fsckObjects configuration
+   set to true, an attempt to "git push" such a tree object will be
+   rejected.  Such a path may not be a problem on a well behaving
+   filesystem but in order to protect those on HFS+ and on case
+   insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.0.0.txt b/Documentation/RelNotes/2.0.0.txt
new file mode 100644
index 0000000000..2617372a0c
--- /dev/null
+++ b/Documentation/RelNotes/2.0.0.txt
@@ -0,0 +1,364 @@
+Git v2.0 Release Notes
+======================
+
+Backward compatibility notes
+----------------------------
+
+When "git push [$there]" does not say what to push, we have used the
+traditional "matching" semantics so far (all your branches were sent
+to the remote as long as there already are branches of the same name
+over there).  In Git 2.0, the default is now the "simple" semantics,
+which pushes:
+
+ - only the current branch to the branch with the same name, and only
+   when the current branch is set to integrate with that remote
+   branch, if you are pushing to the same remote as you fetch from; or
+
+ - only the current branch to the branch with the same name, if you
+   are pushing to a remote that is not where you usually fetch from.
+
+You can use the configuration variable "push.default" to change
+this.  If you are an old-timer who wants to keep using the
+"matching" semantics, you can set the variable to "matching", for
+example.  Read the documentation for other possibilities.
+
+When "git add -u" and "git add -A" are run inside a subdirectory
+without specifying which paths to add on the command line, they
+operate on the entire tree for consistency with "git commit -a" and
+other commands (these commands used to operate only on the current
+subdirectory).  Say "git add -u ." or "git add -A ." if you want to
+limit the operation to the current directory.
+
+"git add <path>" is the same as "git add -A <path>" now, so that
+"git add dir/" will notice paths you removed from the directory and
+record the removal.  In older versions of Git, "git add <path>" used
+to ignore removals.  You can say "git add --ignore-removal <path>" to
+add only added or modified paths in <path>, if you really want to.
+
+The "-q" option to "git diff-files", which does *NOT* mean "quiet",
+has been removed (it told Git to ignore deletion, which you can do
+with "git diff-files --diff-filter=d").
+
+"git request-pull" lost a few "heuristics" that often led to mistakes.
+
+The default prefix for "git svn" has changed in Git 2.0.  For a long
+time, "git svn" created its remote-tracking branches directly under
+refs/remotes, but it now places them under refs/remotes/origin/ unless
+it is told otherwise with its "--prefix" option.
+
+
+Updates since v1.9 series
+-------------------------
+
+UI, Workflows & Features
+
+ * The "multi-mail" post-receive hook (in contrib/) has been updated
+   to a more recent version from upstream.
+
+ * The "remote-hg/bzr" remote-helper interfaces (used to be in
+   contrib/) are no more.  They are now maintained separately as
+   third-party plug-ins in their own repositories.
+
+ * "git gc --aggressive" learned "--depth" option and
+   "gc.aggressiveDepth" configuration variable to allow use of a less
+   insane depth than the built-in default value of 250.
+
+ * "git log" learned the "--show-linear-break" option to show where a
+   single strand-of-pearls is broken in its output.
+
+ * The "rev-parse --parseopt" mechanism used by scripted Porcelains to
+   parse command-line options and to give help text learned to take
+   the argv-help (the placeholder string for an option parameter,
+   e.g. "key-id" in "--gpg-sign=<key-id>").
+
+ * The pattern to find where the function begins in C/C++ used in
+   "diff" and "grep -p" has been updated to improve viewing C++
+   sources.
+
+ * "git rebase" learned to interpret a lone "-" as "@{-1}", the
+   branch that we were previously on.
+
+ * "git commit --cleanup=<mode>" learned a new mode, scissors.
+
+ * "git tag --list" output can be sorted using "version sort" with
+   "--sort=version:refname".
+
+ * Discard the accumulated "heuristics" to guess from which branch the
+   result wants to be pulled from and make sure that what the end user
+   specified is not second-guessed by "git request-pull", to avoid
+   mistakes.  When you pushed out your 'master' branch to your public
+   repository as 'for-linus', use the new "master:for-linus" syntax to
+   denote the branch to be pulled.
+
+ * "git grep" learned to behave in a way similar to native grep when
+   "-h" (no header) and "-c" (count) options are given.
+
+ * "git push" via transport-helper interface has been updated to
+   allow forced ref updates in a way similar to the natively
+   supported transports.
+
+ * The "simple" mode is the default for "git push".
+
+ * "git add -u" and "git add -A", when run without any pathspec, is a
+   tree-wide operation even when run inside a subdirectory of a
+   working tree.
+
+ * "git add <path>" is the same as "git add -A <path>" now.
+
+ * "core.statinfo" configuration variable, which is a
+   never-advertised synonym to "core.checkstat", has been removed.
+
+ * The "-q" option to "git diff-files", which does *NOT* mean
+   "quiet", has been removed (it told Git to ignore deletion, which
+   you can do with "git diff-files --diff-filter=d").
+
+ * Server operators can loosen the "tips of refs only" restriction for
+   the remote archive service with the uploadarchive.allowUnreachable
+   configuration option.
+
+ * The progress indicators from various time-consuming commands have
+   been marked for i18n/l10n.
+
+ * "git notes -C <blob>" diagnoses as an error an attempt to use an
+   object that is not a blob.
+
+ * "git config" learned to read from the standard input when "-" is
+   given as the value to its "--file" parameter (attempting an
+   operation to update the configuration in the standard input is
+   rejected, of course).
+
+ * Trailing whitespaces in .gitignore files, unless they are quoted
+   for fnmatch(3), e.g. "path\ ", are warned and ignored.  Strictly
+   speaking, this is a backward-incompatible change, but very unlikely
+   to bite any sane user and adjusting should be obvious and easy.
+
+ * Many commands that create commits, e.g. "pull" and "rebase",
+   learned to take the "--gpg-sign" option on the command line.
+
+ * "git commit" can be told to always GPG sign the resulting commit
+   by setting the "commit.gpgsign" configuration variable to "true"
+   (the command-line option "--no-gpg-sign" should override it).
+
+ * "git pull" can be told to only accept fast-forward by setting the
+   new "pull.ff" configuration variable.
+
+ * "git reset" learned the "-N" option, which does not reset the index
+   fully for paths the index knows about but the tree-ish the command
+   resets to does not (these paths are kept as intend-to-add entries).
+
+
+Performance, Internal Implementation, etc.
+
+ * The compilation options to port to AIX and to MSVC have been
+   updated.
+
+ * We started using wildmatch() in place of fnmatch(3) a few releases
+   ago; complete the process and stop using fnmatch(3).
+
+ * Uses of curl's "multi" interface and "easy" interface do not mix
+   well when we attempt to reuse outgoing connections.  Teach the RPC
+   over HTTP code, used in the smart HTTP transport, not to use the
+   "easy" interface.
+
+ * The bitmap-index feature from JGit has been ported, which should
+   significantly improve performance when serving objects from a
+   repository that uses it.
+
+ * The way "git log --cc" shows a combined diff against multiple
+   parents has been optimized.
+
+ * The prefixcmp() and suffixcmp() functions are gone.  Use
+   starts_with() and ends_with(), and also consider if skip_prefix()
+   suits your needs better when using the former.
+
+
+Also contains various documentation updates and code clean-ups.  Many
+of them came from flurry of activities as GSoC candidate microproject
+exercises.
+
+
+Fixes since v1.9 series
+-----------------------
+
+Unless otherwise noted, all the fixes since v1.9 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git p4" was broken in 1.9 release to deal with changes in binary
+   files.
+   (merge 749b668 cl/p4-use-diff-tree later to maint).
+
+ * The shell prompt script (in contrib/), when using the PROMPT_COMMAND
+   interface, used an unsafe construct when showing the branch name in
+   $PS1.
+   (merge 1e4119c8 rh/prompt-pcmode-avoid-eval-on-refname later to maint).
+
+ * "git rebase" used a POSIX shell construct FreeBSD's /bin/sh does not
+   work well with.
+   (merge 8cd6596 km/avoid-non-function-return-in-rebase later to maint).
+
+ * zsh prompt (in contrib/) leaked unnecessary error messages.
+
+ * Bash completion (in contrib/) did not complete the refs and remotes
+   correctly given "git pu<TAB>" when "pu" is aliased to "push".
+
+ * Some more Unicode code points, defined in Unicode 6.3 as having zero
+   width, have been taught to our display column counting logic.
+   (merge d813ab9 tb/unicode-6.3-zero-width later to maint).
+
+ * Some tests used shell constructs that did not work well on FreeBSD
+   (merge ff7a1c6 km/avoid-bs-in-shell-glob later to maint).
+   (merge 00764ca km/avoid-cp-a later to maint).
+
+ * "git update-ref --stdin" did not fail a request to create a ref
+   when the ref already existed.
+   (merge b9d56b5 mh/update-ref-batch-create-fix later to maint).
+
+ * "git diff --no-index -Mq a b" fell into an infinite loop.
+   (merge ad1c3fb jc/fix-diff-no-index-diff-opt-parse later to maint).
+
+ * "git fetch --prune", when the right-hand side of multiple fetch
+   refspecs overlap (e.g. storing "refs/heads/*" to
+   "refs/remotes/origin/*", while storing "refs/frotz/*" to
+   "refs/remotes/origin/fr/*"), aggressively thought that lack of
+   "refs/heads/fr/otz" on the origin site meant we should remove
+   "refs/remotes/origin/fr/otz" from us, without checking their
+   "refs/frotz/otz" first.
+
+   Note that such a configuration is inherently unsafe (think what
+   should happen when "refs/heads/fr/otz" does appear on the origin
+   site), but that is not a reason not to be extra careful.
+   (merge e6f6371 cn/fetch-prune-overlapping-destination later to maint).
+
+ * "git status --porcelain --branch" showed its output with labels
+   "ahead/behind/gone" translated to the user's locale.
+   (merge 7a76c28 mm/status-porcelain-format-i18n-fix later to maint).
+
+ * A stray environment variable $prefix could have leaked into and
+   affected the behaviour of the "subtree" script (in contrib/).
+
+ * When it is not necessary to edit a commit log message (e.g. "git
+   commit -m" is given a message without specifying "-e"), we used to
+   disable the spawning of the editor by overriding GIT_EDITOR, but
+   this means all the uses of the editor, other than to edit the
+   commit log message, are also affected.
+   (merge b549be0 bp/commit-p-editor later to maint).
+
+ * "git mv" that moves a submodule forgot to adjust the array that
+   uses to keep track of which submodules were to be moved to update
+   its configuration.
+   (merge fb8a4e8 jk/mv-submodules-fix later to maint).
+
+ * Length limit for the pathname used when removing a path in a deep
+   subdirectory has been removed to avoid buffer overflows.
+   (merge 2f29e0c mh/remove-subtree-long-pathname-fix later to maint).
+
+ * The test helper lib-terminal always run an actual test_expect_*
+   when included, which screwed up with the use of skil-all that may
+   have to be done later.
+   (merge 7e27173 jk/lib-terminal-lazy later to maint).
+
+ * "git index-pack" used a wrong variable to name the keep-file in an
+   error message when the file cannot be written or closed.
+   (merge de983a0 nd/index-pack-error-message later to maint).
+
+ * "rebase -i" produced a broken insn sheet when the title of a commit
+   happened to contain '\n' (or ended with '\c') due to a careless use
+   of 'echo'.
+   (merge cb1aefd us/printf-not-echo later to maint).
+
+ * There were a few instances of 'git-foo' remaining in the
+   documentation that should have been spelled 'git foo'.
+   (merge 3c3e6f5 rr/doc-merge-strategies later to maint).
+
+ * Serving objects from a shallow repository needs to write a
+   new file to hold the temporary shallow boundaries, but it was not
+   cleaned when we exit due to die() or a signal.
+   (merge 7839632 jk/shallow-update-fix later to maint).
+
+ * When "git stash pop" stops after failing to apply the stash
+   (e.g. due to conflicting changes), the stash is not dropped. State
+   that explicitly in the output to let the users know.
+   (merge 2d4c993 jc/stash-pop-not-popped later to maint).
+
+ * The labels in "git status" output that describe the nature of
+   conflicts (e.g. "both deleted") were limited to 20 bytes, which was
+   too short for some l10n (e.g. fr).
+   (merge c7cb333 jn/wt-status later to maint).
+
+ * "git clean -d pathspec" did not use the given pathspec correctly
+   and ended up cleaning too much.
+   (merge 1f2e108 jk/clean-d-pathspec later to maint).
+
+ * "git difftool" misbehaved when the repository is bound to the
+   working tree with the ".git file" mechanism, where a textual file
+   ".git" tells us where it is.
+   (merge fcfec8b da/difftool-git-files later to maint).
+
+ * "git push" did not pay attention to "branch.*.pushremote" if it is
+   defined earlier than "remote.pushdefault"; the order of these two
+   variables in the configuration file should not matter, but it did
+   by mistake.
+   (merge 98b406f jk/remote-pushremote-config-reading later to maint).
+
+ * Code paths that parse timestamps in commit objects have been
+   tightened.
+   (merge f80d1f9 jk/commit-dates-parsing-fix later to maint).
+
+ * "git diff --external-diff" incorrectly fed the submodule directory
+   in the working tree to the external diff driver when it knew that it
+   is the same as one of the versions being compared.
+   (merge aba4727 tr/diff-submodule-no-reuse-worktree later to maint).
+
+ * "git reset" needs to refresh the index when working in a working
+   tree (it can also be used to match the index to the HEAD in an
+   otherwise bare repository), but it failed to set up the working
+   tree properly, causing GIT_WORK_TREE to be ignored.
+   (merge b7756d4 nd/reset-setup-worktree later to maint).
+
+ * "git check-attr" when working on a repository with a working tree
+   did not work well when the working tree was specified via the
+   "--work-tree" (and obviously with "--git-dir") option.
+   (merge cdbf623 jc/check-attr-honor-working-tree later to maint).
+
+ * "merge-recursive" was broken in 1.7.7 era and stopped working in
+   an empty (temporary) working tree, when there are renames
+   involved.  This has been corrected.
+   (merge 6e2068a bk/refresh-missing-ok-in-merge-recursive later to maint.)
+
+ * "git rev-parse" was loose in rejecting command-line arguments
+   that do not make sense, e.g. "--default" without the required
+   value for that option.
+   (merge a43219f ds/rev-parse-required-args later to maint.)
+
+ * "include.path" variable (or any variable that expects a path that
+   can use ~username expansion) in the configuration file is not a
+   boolean, but the code failed to check it.
+   (merge 67beb60 jk/config-path-include-fix later to maint.)
+
+ * Commands that take pathspecs on the command line misbehaved when
+   the pathspec is given as an absolute pathname (which is a
+   practice not particularly encouraged) that points at a symbolic
+   link in the working tree.
+   (merge 6127ff6 mw/symlinks later to maint.)
+
+ * "git diff --quiet -- pathspec1 pathspec2" sometimes did not return
+   the correct status value.
+   (merge f34b205 nd/diff-quiet-stat-dirty later to maint.)
+
+ * Attempting to deepen a shallow repository by fetching over smart
+   HTTP transport failed in the protocol exchange, when the no-done
+   extension was used.  The fetching side waited for the list of
+   shallow boundary commits after the sending side stopped talking to
+   it.
+   (merge 0232852 nd/http-fetch-shallow-fix later to maint.)
+
+ * Allow "git cmd path/", when the 'path' is where a submodule is
+   bound to the top-level working tree, to match 'path', despite the
+   extra and unnecessary trailing slash (such a slash is often
+   given by command-line completion).
+   (merge 2e70c01 nd/submodule-pathspec-ending-with-slash later to maint.)
+
+ * Documentation and in-code comments had many instances of mistaken
+   use of "nor", which have been corrected.
+   (merge 235e8d5 jl/nor-or-nand-and later to maint).
diff --git a/Documentation/RelNotes/2.0.1.txt b/Documentation/RelNotes/2.0.1.txt
new file mode 100644
index 0000000000..ce5579db3e
--- /dev/null
+++ b/Documentation/RelNotes/2.0.1.txt
@@ -0,0 +1,115 @@
+Git v2.0.1 Release Notes
+========================
+
+ * We used to unconditionally disable the pager in the pager process
+   we spawn to feed out output, but that prevented people who want to
+   run "less" within "less" from doing so.
+
+ * Tools that read diagnostic output in our standard error stream do
+   not want to see terminal control sequence (e.g. erase-to-eol).
+   Detect them by checking if the standard error stream is connected
+   to a tty.
+ * Reworded the error message given upon a failure to open an existing
+   loose object file due to e.g. permission issues; it was reported as
+   the object being corrupt, but that is not quite true.
+
+ * "git log -2master" is a common typo that shows two commits starting
+   from whichever random branch that is not 'master' that happens to
+   be checked out currently.
+
+ * The "%<(10,trunc)%s" pretty format specifier in the log family of
+   commands is used to truncate the string to a given length (e.g. 10
+   in the example) with padding to column-align the output, but did
+   not take into account that number of bytes and number of display
+   columns are different.
+
+ * The "mailmap.file" configuration option did not support the tilde
+   expansion (i.e. ~user/path and ~/path).
+
+ * The completion scripts (in contrib/) did not know about quite a few
+   options that are common between "git merge" and "git pull", and a
+   couple of options unique to "git merge".
+
+ * "--ignore-space-change" option of "git apply" ignored the spaces
+   at the beginning of line too aggressively, which is inconsistent
+   with the option of the same name "diff" and "git diff" have.
+
+ * "git blame" miscounted number of columns needed to show localized
+   timestamps, resulting in jaggy left-side-edge of the source code
+   lines in its output.
+
+ * "git blame" assigned the blame to the copy in the working-tree if
+   the repository is set to core.autocrlf=input and the file used CRLF
+   line endings.
+
+ * "git commit --allow-empty-message -C $commit" did not work when the
+   commit did not have any log message.
+
+ * "git diff --find-copies-harder" sometimes pretended as if the mode
+   bits have changed for paths that are marked with assume-unchanged
+   bit.
+
+ * "git format-patch" did not enforce the rule that the "--follow"
+   option from the log/diff family of commands must be used with
+   exactly one pathspec.
+
+ * "git gc --auto" was recently changed to run in the background to
+   give control back early to the end-user sitting in front of the
+   terminal, but it forgot that housekeeping involving reflogs should
+   be done without other processes competing for accesses to the refs.
+
+ * "git grep -O" to show the lines that hit in the pager did not work
+   well with case insensitive search.  We now spawn "less" with its
+   "-I" option when it is used as the pager (which is the default).
+
+ * We used to disable threaded "git index-pack" on platforms without
+   thread-safe pread(); use a different workaround for such
+   platforms to allow threaded "git index-pack".
+
+ * The error reporting from "git index-pack" has been improved to
+   distinguish missing objects from type errors.
+
+ * "git mailinfo" used to read beyond the end of header string while
+   parsing an incoming e-mail message to extract the patch.
+
+ * On a case insensitive filesystem, merge-recursive incorrectly
+   deleted the file that is to be renamed to a name that is the same
+   except for case differences.
+
+ * "git pack-objects" unnecessarily copied the previous contents when
+   extending the hashtable, even though it will populate the table
+   from scratch anyway.
+
+ * "git rerere forget" did not work well when merge.conflictstyle
+   was set to a non-default value.
+
+ * "git remote rm" and "git remote prune" can involve removing many
+   refs at once, which is not a very efficient thing to do when very
+   many refs exist in the packed-refs file.
+
+ * "git log --exclude=<glob> --all | git shortlog" worked as expected,
+   but "git shortlog --exclude=<glob> --all", which is supposed to be
+   identical to the above pipeline, was not accepted at the command
+   line argument parser level.
+
+ * The autostash mode of "git rebase -i" did not restore the dirty
+   working tree state if the user aborted the interactive rebase by
+   emptying the insn sheet.
+
+ * "git show -s" (i.e. show log message only) used to incorrectly emit
+   an extra blank line after a merge commit.
+
+ * "git status", even though it is a read-only operation, tries to
+   update the index with refreshed lstat(2) info to optimize future
+   accesses to the working tree opportunistically, but this could
+   race with a "read-write" operation that modify the index while it
+   is running.  Detect such a race and avoid overwriting the index.
+
+ * "git status" (and "git commit") behaved as if changes in a modified
+   submodule are not there if submodule.*.ignore configuration is set,
+   which was misleading.  The configuration is only to unclutter diff
+   output during the course of development, and should not to hide
+   changes in the "status" output to cause the users forget to commit
+   them.
+
+ * The mode to run tests with HTTP server tests disabled was broken.
diff --git a/Documentation/RelNotes/2.0.2.txt b/Documentation/RelNotes/2.0.2.txt
new file mode 100644
index 0000000000..8e8321b2ef
--- /dev/null
+++ b/Documentation/RelNotes/2.0.2.txt
@@ -0,0 +1,32 @@
+Git v2.0.2 Release Notes
+========================
+
+ * Documentation for "git submodule sync" forgot to say that the subcommand
+   can take the "--recursive" option.
+
+ * Mishandling of patterns in .gitignore that has trailing SPs quoted
+   with backslashes (e.g. ones that end with "\ ") have been
+   corrected.
+
+ * Recent updates to "git repack" started to duplicate objects that
+   are in packfiles marked with .keep flag into the new packfile by
+   mistake.
+
+ * "git clone -b brefs/tags/bar" would have mistakenly thought we were
+   following a single tag, even though it was a name of the branch,
+   because it incorrectly used strstr().
+
+ * "%G" (nothing after G) is an invalid pretty format specifier, but
+   the parser did not notice it as garbage.
+
+ * Code to avoid adding the same alternate object store twice was
+   subtly broken for a long time, but nobody seems to have noticed.
+
+ * A handful of code paths had to read the commit object more than
+   once when showing header fields that are usually not parsed.  The
+   internal data structure to keep track of the contents of the commit
+   object has been updated to reduce the need for this double-reading,
+   and to allow the caller find the length of the object.
+
+ * During "git rebase --merge", a conflicted patch could not be
+   skipped with "--skip" if the next one also conflicted.
diff --git a/Documentation/RelNotes/2.0.3.txt b/Documentation/RelNotes/2.0.3.txt
new file mode 100644
index 0000000000..4047b46bbe
--- /dev/null
+++ b/Documentation/RelNotes/2.0.3.txt
@@ -0,0 +1,17 @@
+Git v2.0.3 Release Notes
+========================
+
+ * An ancient rewrite passed a wrong pointer to a curl library
+   function in a rarely used code path.
+
+ * "filter-branch" left an empty single-parent commit that results when
+   all parents of a merge commit gets mapped to the same commit, even
+   under "--prune-empty".
+
+ * "log --show-signature" incorrectly decided the color to paint a
+   mergetag that was and was not correctly validated.
+
+ * "log --show-signature" did not pay attention to "--graph" option.
+
+Also a lot of fixes to the tests and some updates to the docs are
+included.
diff --git a/Documentation/RelNotes/2.0.4.txt b/Documentation/RelNotes/2.0.4.txt
new file mode 100644
index 0000000000..7e340921a2
--- /dev/null
+++ b/Documentation/RelNotes/2.0.4.txt
@@ -0,0 +1,5 @@
+Git v2.0.4 Release Notes
+========================
+
+ * An earlier update to v2.0.2 broken output from "git diff-tree",
+   which is fixed in this release.
diff --git a/Documentation/RelNotes/2.0.5.txt b/Documentation/RelNotes/2.0.5.txt
new file mode 100644
index 0000000000..3a16f697e8
--- /dev/null
+++ b/Documentation/RelNotes/2.0.5.txt
@@ -0,0 +1,34 @@
+Git v2.0.5 Release Notes
+========================
+
+Fixes since v2.0.4
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+   running on a case sensitive filesystem, but an attempt to check out
+   such a path with Git that runs on a case insensitive filesystem
+   would have clobbered ".git/config", which is definitely not what
+   the user would have expected.  Git now prevents you from tracking
+   a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+   are mapped to ".git", e.g. "git~1/config" is treated as if it were
+   ".git/config".  HFS+ has a similar issue, where certain unicode
+   codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+   it were ".git/config".  Pathnames with these potential issues are
+   rejected on the affected systems.  Git on systems that are not
+   affected by this issue (e.g. Linux) can also be configured to
+   reject them to ensure cross platform interoperability of the hosted
+   projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+   be confused with ".git", and with receive.fsckObjects configuration
+   set to true, an attempt to "git push" such a tree object will be
+   rejected.  Such a path may not be a problem on a well behaving
+   filesystem but in order to protect those on HFS+ and on case
+   insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.1.0.txt b/Documentation/RelNotes/2.1.0.txt
new file mode 100644
index 0000000000..ae4753728e
--- /dev/null
+++ b/Documentation/RelNotes/2.1.0.txt
@@ -0,0 +1,391 @@
+Git v2.1 Release Notes
+======================
+
+Backward compatibility notes
+----------------------------
+
+ * The default value we give to the environment variable LESS has been
+   changed from "FRSX" to "FRX", losing "S" (chop long lines instead
+   of wrapping).  Existing users who prefer not to see line-wrapped
+   output may want to set
+
+     $ git config core.pager "less -S"
+
+   to restore the traditional behaviour.  It is expected that people
+   find output from most subcommands easier to read with the new
+   default, except for "blame" which tends to produce really long
+   lines.  To override the new default only for "git blame", you can
+   do this:
+
+     $ git config pager.blame "less -S"
+
+ * A few disused directories in contrib/ have been retired.
+
+
+Updates since v2.0
+------------------
+
+UI, Workflows & Features
+
+ * Since the very beginning of Git, we gave the LESS environment a
+   default value "FRSX" when we spawn "less" as the pager.  "S" (chop
+   long lines instead of wrapping) has been removed from this default
+   set of options, because it is more or less a personal taste thing,
+   as opposed to the others that have good justifications (i.e. "R" is
+   very much justified because many kinds of output we produce are
+   colored and "FX" is justified because output we produce is often
+   shorter than a page).
+
+ * The logic and data used to compute the display width needed for
+   UTF-8 strings have been updated to match Unicode 7.0 better.
+
+ * HTTP-based transports learned to better propagate the error messages from
+   the webserver to the client coming over the HTTP transport.
+
+ * The completion script for bash (in contrib/) has been updated to
+   better handle aliases that define a complex sequence of commands.
+
+ * The "core.preloadindex" configuration variable is enabled by default,
+   allowing modern platforms to take advantage of their
+   multiple cores.
+
+ * "git clone" applies the "if cloning from a local disk, physically
+   copy the repository using hardlinks, unless otherwise told not to with
+   --no-local" optimization when the url.*.insteadOf mechanism rewrites a
+   remote-repository "git clone $URL" into a
+   clone from a local disk.
+
+ * "git commit --date=<date>" option learned more
+   timestamp formats, including "--date=now".
+
+ * The `core.commentChar` configuration variable is used to specify a
+   custom comment character (other than the default "#") for
+   the commit message editor.  This can be set to `auto` to attempt to
+   choose a different character that does not conflict with any that
+   already starts a line in the message being edited, for cases like
+   "git commit --amend".
+
+ * "git format-patch" learned --signature-file=<file> to add the contents
+   of a file as a signature to the mail message it produces.
+
+ * "git grep" learned the grep.fullname configuration variable to force
+   "--full-name" to be the default.  This may cause regressions for
+   scripted users who do not expect this new behaviour.
+
+ * "git imap-send" learned to ask the credential helper for auth
+   material.
+
+ * "git log" and friends now understand the value "auto" for the
+   "log.decorate" configuration variable to enable the "--decorate"
+   option automatically when the output is sent to tty.
+
+ * "git merge" without an argument, even when there is an upstream
+   defined for the current branch, refused to run until
+   merge.defaultToUpstream is set to true.  Flip the default of that
+   configuration variable to true.
+
+ * "git mergetool" learned to drive the vimdiff3 backend.
+
+ * mergetool.prompt used to default to 'true', always asking "do you
+   really want to run the tool on this path?".  The default has been
+   changed to 'false'.  However, the prompt will still appear if
+   mergetool used its autodetection system to guess which tool to use.
+   Users who explicitly specify or configure a tool will no longer see
+   the prompt by default.
+
+   Strictly speaking, this is a backward incompatible change and
+   users need to explicitly set the variable to 'true' if they want
+   to be prompted to confirm running the tool on each path.
+
+ * "git replace" learned the "--edit" subcommand to create a
+   replacement by editing an existing object.
+
+ * "git replace" learned a "--graft" option to rewrite the parents of a
+   commit.
+
+ * "git send-email" learned "--to-cover" and "--cc-cover" options, to
+   tell it to copy To: and Cc: headers found in the first input file
+   when emitting later input files.
+
+ * "git svn" learned to cope with malformed timestamps with only one
+   digit in the hour part, e.g. 2014-01-07T5:01:02.048176Z, emitted
+   by some broken subversion server implementations.
+
+ * "git tag" when editing the tag message shows the name of the tag
+   being edited as a comment in the editor.
+
+ * "git tag" learned to pay attention to "tag.sort" configuration, to
+   be used as the default sort order when no --sort=<value> option
+   is given.
+
+ * A new "git verify-commit" command, to check GPG signatures in signed
+   commits, in a way similar to "git verify-tag" is used to check
+   signed tags, was added.
+
+
+Performance, Internal Implementation, etc.
+
+ * Build procedure for 'subtree' (in contrib/) has been cleaned up.
+
+ * Support for the profile-feedback build, which has
+   bit-rotted for quite a while, has been updated.
+
+ * An experimental format to use two files (the base file and
+   incremental changes relative to it) to represent the index has been
+   introduced; this may reduce I/O cost of rewriting a large index
+   when only small part of the working tree changes.
+
+ * Effort to shrink the size of patches Windows folks maintain on top
+   by upstreaming them continues.  More tests that are not applicable
+   to the Windows environment are identified and either skipped or
+   made more portable.
+
+ * Eradication of "test $condition -a $condition" from our scripts
+   continues.
+
+ * The `core.deltabasecachelimit` used to default to 16 MiB , but this
+   proved to be too small, and has been bumped to 96 MiB.
+
+ * "git blame" has been optimized greatly by reorganising the data
+   structure that is used to keep track of the work to be done.
+
+ * "git diff" that compares 3-or-more trees (e.g. parents and the
+   result of a merge) has been optimized.
+
+ * The API to update/delete references are being converted to handle
+   updates to multiple references in a transactional way.  As an
+   example, "update-ref --stdin [-z]" has been updated to use this
+   API.
+
+ * skip_prefix() and strip_suffix() API functions are used a lot more
+   widely throughout the codebase now.
+
+ * Parts of the test scripts can be skipped by using a range notation,
+   e.g. "sh t1234-test.sh --run='1-4 6 8-'" to omit test piece 5 and 7
+   and run everything else.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.0
+----------------
+
+Unless otherwise noted, all the fixes since v2.0 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * We used to unconditionally disable the pager in the pager process
+   we spawn to feed out output, but that prevented people who want to
+   run "less" within "less" from doing so.
+   (merge c0459ca je/pager-do-not-recurse later to maint).
+
+ * Tools that read diagnostic output in our standard error stream do
+   not want to see terminal control sequence (e.g. erase-to-eol).
+   Detect them by checking if the standard error stream is connected
+   to a tty.
+   (merge 38de156 mn/sideband-no-ansi later to maint).
+
+ * Mishandling of patterns in .gitignore that have trailing SPs quoted
+   with backslashes (e.g. ones that end with "\ ") has been
+   corrected.
+   (merge 97c1364be6b pb/trim-trailing-spaces later to maint).
+
+ * Reworded the error message given upon a failure to open an existing
+   loose object file due to e.g. permission issues; it was reported as
+   the object being corrupt, but that is not quite true.
+   (merge d6c8a05 jk/report-fail-to-read-objects-better later to maint).
+
+ * "git log -2master" is a common typo that shows two commits starting
+   from whichever random branch that is not 'master' that happens to
+   be checked out currently.
+   (merge e3fa568 jc/revision-dash-count-parsing later to maint).
+
+ * Code to avoid adding the same alternate object store twice was
+   subtly broken for a long time, but nobody seems to have noticed.
+   (merge 80b4785 rs/fix-alt-odb-path-comparison later to maint).
+   (merge 539e750 ek/alt-odb-entry-fix later to maint).
+
+ * The "%<(10,trunc)%s" pretty format specifier in the log family of
+   commands is used to truncate the string to a given length (e.g. 10
+   in the example) with padding to column-align the output, but did
+   not take into account that number of bytes and number of display
+   columns are different.
+   (merge 7d50987 as/pretty-truncate later to maint).
+
+ * "%G" (nothing after G) is an invalid pretty format specifier, but
+   the parser did not notice it as garbage.
+   (merge 958b2eb jk/pretty-G-format-fixes later to maint).
+
+ * A handful of code paths had to read the commit object more than
+   once when showing header fields that are usually not parsed.  The
+   internal data structure to keep track of the contents of the commit
+   object has been updated to reduce the need for this double-reading,
+   and to allow the caller find the length of the object.
+   (merge 218aa3a jk/commit-buffer-length later to maint).
+
+ * The "mailmap.file" configuration option did not support tilde
+   expansion (i.e. ~user/path and ~/path).
+   (merge 9352fd5 ow/config-mailmap-pathname later to maint).
+
+ * The completion scripts (in contrib/) did not know about quite a few
+   options that are common between "git merge" and "git pull", and a
+   couple of options unique to "git merge".
+   (merge 8fee872 jk/complete-merge-pull later to maint).
+
+ * The unix-domain socket used by the sample credential cache daemon
+   tried to unlink an existing stale one at a wrong path, if the path
+   to the socket was given as an overlong path that does not fit in
+   the sun_path member of the sockaddr_un structure.
+   (merge 2869b3e rs/fix-unlink-unix-socket later to maint).
+
+ * An ancient rewrite passed a wrong pointer to a curl library
+   function in a rarely used code path.
+   (merge 479eaa8 ah/fix-http-push later to maint).
+
+ * "--ignore-space-change" option of "git apply" ignored the spaces
+   at the beginning of lines too aggressively, which is inconsistent
+   with the option of the same name that "diff" and "git diff" have.
+   (merge 14d3bb4 jc/apply-ignore-whitespace later to maint).
+
+ * "git blame" miscounted the number of columns needed to show localized
+   timestamps, resulting in a jaggy left-side-edge for the source code
+   lines in its output.
+   (merge dd75553 jx/blame-align-relative-time later to maint).
+
+ * "git blame" assigned the blame to the copy in the working-tree if
+   the repository is set to core.autocrlf=input and the file used CRLF
+   line endings.
+   (merge 4d4813a bc/blame-crlf-test later to maint).
+
+ * "git clone -b brefs/tags/bar" would have mistakenly thought we were
+   following a single tag, even though it was a name of the branch,
+   because it incorrectly used strstr().
+   (merge 60a5f5f jc/fix-clone-single-starting-at-a-tag later to maint).
+
+ * "git commit --allow-empty-message -C $commit" did not work when the
+   commit did not have any log message.
+   (merge 076cbd6 jk/commit-C-pick-empty later to maint).
+
+ * "git diff --find-copies-harder" sometimes pretended as if the mode
+   bits have changed for paths that are marked with the assume-unchanged
+   bit.
+   (merge 5304810 jk/diff-files-assume-unchanged later to maint).
+
+ * "filter-branch" left an empty single-parent commit that results when
+   all parents of a merge commit get mapped to the same commit, even
+   under "--prune-empty".
+   (merge 79bc4ef cb/filter-branch-prune-empty-degenerate-merges later to maint).
+
+ * "git format-patch" did not enforce the rule that the "--follow"
+   option from the log/diff family of commands must be used with
+   exactly one pathspec.
+   (merge dd63f16 jk/diff-follow-must-take-one-pathspec later to maint).
+
+ * "git gc --auto" was recently changed to run in the background to
+   give control back early to the end-user sitting in front of the
+   terminal, but it forgot that housekeeping involving reflogs should
+   be done without other processes competing for accesses to the refs.
+   (merge 62aad18 nd/daemonize-gc later to maint).
+
+ * "git grep -O" to show the lines that hit in the pager did not work
+   well with case insensitive search.  We now spawn "less" with its
+   "-I" option when it is used as the pager (which is the default).
+   (merge f7febbe sk/spawn-less-case-insensitively-from-grep-O-i later to maint).
+
+ * We used to disable threaded "git index-pack" on platforms without
+   thread-safe pread(); use a different workaround for such
+   platforms to allow threaded "git index-pack".
+   (merge 3953949 nd/index-pack-one-fd-per-thread later to maint).
+
+ * The error reporting from "git index-pack" has been improved to
+   distinguish missing objects from type errors.
+   (merge 77583e7 jk/index-pack-report-missing later to maint).
+
+ * "log --show-signature" incorrectly decided the color to paint a
+   mergetag that was and was not correctly validated.
+   (merge 42c55ce mg/fix-log-mergetag-color later to maint).
+
+ * "log --show-signature" did not pay attention to the "--graph" option.
+   (merge cf3983d zk/log-graph-showsig later to maint).
+
+ * "git mailinfo" used to read beyond the ends of header strings while
+   parsing an incoming e-mail message to extract the patch.
+   (merge b1a013d rs/mailinfo-header-cmp later to maint).
+
+ * On a case insensitive filesystem, merge-recursive incorrectly
+   deleted the file that is to be renamed to a name that is the same
+   except for case differences.
+   (merge baa37bf dt/merge-recursive-case-insensitive later to maint).
+
+ * Merging changes into a file that ends in an incomplete line made the
+   last line into a complete one, even when the other branch did not
+   change anything around the end of file.
+   (merge ba31180 mk/merge-incomplete-files later to maint).
+
+ * "git pack-objects" unnecessarily copied the previous contents when
+   extending the hashtable, even though it will populate the table
+   from scratch anyway.
+   (merge fb79947 rs/pack-objects-no-unnecessary-realloc later to maint).
+
+ * Recent updates to "git repack" started to duplicate objects that
+   are in packfiles marked with the .keep flag into the new packfile by
+   mistake.
+   (merge d078d85 jk/repack-pack-keep-objects later to maint).
+
+ * "git rerere forget" did not work well when merge.conflictstyle
+   was set to a non-default value.
+   (merge de3d8bb fc/rerere-conflict-style later to maint).
+
+ * "git remote rm" and "git remote prune" can involve removing many
+   refs at once, which is not a very efficient thing to do when very
+   many refs exist in the packed-refs file.
+   (merge e6bea66 jl/remote-rm-prune later to maint).
+
+ * "git log --exclude=<glob> --all | git shortlog" worked as expected,
+   but "git shortlog --exclude=<glob> --all", which is supposed to be
+   identical to the above pipeline, was not accepted at the command
+   line argument parser level.
+   (merge eb07774 jc/shortlog-ref-exclude later to maint).
+
+ * The autostash mode of "git rebase -i" did not restore the dirty
+   working tree state if the user aborted the interactive rebase by
+   emptying the insn sheet.
+   (merge ddb5432 rr/rebase-autostash-fix later to maint).
+
+ * "git rebase --fork-point" did not filter out patch-identical
+   commits correctly.
+
+ * During "git rebase --merge", a conflicted patch could not be
+   skipped with "--skip" if the next one also conflicted.
+   (merge 95104c7 bc/fix-rebase-merge-skip later to maint).
+
+ * "git show -s" (i.e. show log message only) used to incorrectly emit
+   an extra blank line after a merge commit.
+   (merge ad2f725 mk/show-s-no-extra-blank-line-for-merges later to maint).
+
+ * "git status", even though it is a read-only operation, tries to
+   update the index with refreshed lstat(2) info to optimize future
+   accesses to the working tree opportunistically, but this could
+   race with a "read-write" operation that modifies the index while it
+   is running.  Detect such a race and avoid overwriting the index.
+   (merge 426ddee ym/fix-opportunistic-index-update-race later to maint).
+
+ * "git status" (and "git commit") behaved as if changes in a modified
+   submodule are not there if submodule.*.ignore configuration is set,
+   which was misleading.  The configuration is only to unclutter diff
+   output during the course of development, and not to hide
+   changes in the "status" output to cause the users forget to commit
+   them.
+   (merge c215d3d jl/status-added-submodule-is-never-ignored later to maint).
+
+ * Documentation for "git submodule sync" forgot to say that the subcommand
+   can take the "--recursive" option.
+   (merge 9393ae7 mc/doc-submodule-sync-recurse later to maint).
+
+ * "git update-index --cacheinfo" in 2.0 release crashed on a
+   malformed command line.
+   (merge c8e1ee4 jc/rev-parse-argh-dashed-multi-words later to maint).
+
+ * The mode to run tests with HTTP server tests disabled was broken.
+   (merge afa53fe na/no-http-test-in-the-middle later to maint).
diff --git a/Documentation/RelNotes/2.1.1.txt b/Documentation/RelNotes/2.1.1.txt
new file mode 100644
index 0000000000..830fc3cc6d
--- /dev/null
+++ b/Documentation/RelNotes/2.1.1.txt
@@ -0,0 +1,44 @@
+Git v2.1.1 Release Notes
+========================
+
+ * Git 2.0 had a regression where "git fetch" into a shallowly
+   cloned repository from a repository with bitmap object index
+   enabled did not work correctly.  This has been corrected.
+
+ * Git 2.0 had a regression which broke (rarely used) "git diff-tree
+   -t".  This has been corrected.
+
+ * "git log --pretty/format=" with an empty format string did not
+   mean the more obvious "No output whatsoever" but "Use default
+   format", which was counterintuitive.  Now it means "nothing shown
+   for the log message part".
+
+ * "git -c section.var command" and "git -c section.var= command"
+   should pass the configuration differently (the former should be a
+   boolean true, the latter should be an empty string), but they
+   didn't work that way.  Now it does.
+
+ * Applying a patch not generated by Git in a subdirectory used to
+   check the whitespace breakage using the attributes for incorrect
+   paths. Also whitespace checks were performed even for paths
+   excluded via "git apply --exclude=<path>" mechanism.
+
+ * "git bundle create" with date-range specification were meant to
+   exclude tags outside the range, but it did not work correctly.
+
+ * "git add x" where x that used to be a directory has become a
+   symbolic link to a directory misbehaved.
+
+ * The prompt script checked $GIT_DIR/ref/stash file to see if there
+   is a stash, which was a no-no.
+
+ * "git checkout -m" did not switch to another branch while carrying
+   the local changes forward when a path was deleted from the index.
+
+ * With sufficiently long refnames, fast-import could have overflown
+   an on-stack buffer.
+
+ * After "pack-refs --prune" packed refs at the top-level, it failed
+   to prune them.
+
+ * "git gc --auto" triggered from "git fetch --quiet" was not quiet.
diff --git a/Documentation/RelNotes/2.1.2.txt b/Documentation/RelNotes/2.1.2.txt
new file mode 100644
index 0000000000..abc3b8928a
--- /dev/null
+++ b/Documentation/RelNotes/2.1.2.txt
@@ -0,0 +1,20 @@
+Git v2.1.2 Release Notes
+========================
+
+ * "git push" over HTTP transport had an artificial limit on number of
+   refs that can be pushed imposed by the command line length.
+
+ * When receiving an invalid pack stream that records the same object
+   twice, multiple threads got confused due to a race.
+
+ * An attempt to remove the entire tree in the "git fast-import" input
+   stream caused it to misbehave.
+
+ * Reachability check (used in "git prune" and friends) did not add a
+   detached HEAD as a starting point to traverse objects still in use.
+
+ * "git config --add section.var val" used to lose existing
+   section.var whose value was an empty string.
+
+ * "git fsck" failed to report that it found corrupt objects via its
+   exit status in some cases.
diff --git a/Documentation/RelNotes/2.1.3.txt b/Documentation/RelNotes/2.1.3.txt
new file mode 100644
index 0000000000..0dfb17c4fc
--- /dev/null
+++ b/Documentation/RelNotes/2.1.3.txt
@@ -0,0 +1,26 @@
+Git v2.1.3 Release Notes
+========================
+
+ * Some MUAs mangled a line in a message that begins with "From " to
+   ">From " when writing to a mailbox file and feeding such an input to
+   "git am" used to lose such a line.
+
+ * "git daemon" (with NO_IPV6 build configuration) used to incorrectly
+   use the hostname even when gethostbyname() reported that the given
+   hostname is not found.
+
+ * Newer versions of 'meld' breaks the auto-detection we use to see if
+   they are new enough to support the `--output` option.
+
+ * "git pack-objects" forgot to disable the codepath to generate
+   object reachability bitmap when it needs to split the resulting
+   pack.
+
+ * "gitweb" used deprecated CGI::startfrom, which was removed from
+   CGI.pm as of 4.04; use CGI::start_from instead.
+
+ * "git log" documentation had an example section marked up not
+   quite correctly, which passed AsciiDoc but failed with
+   AsciiDoctor.
+
+Also contains some documentation updates.
diff --git a/Documentation/RelNotes/2.1.4.txt b/Documentation/RelNotes/2.1.4.txt
new file mode 100644
index 0000000000..d16e5f041f
--- /dev/null
+++ b/Documentation/RelNotes/2.1.4.txt
@@ -0,0 +1,34 @@
+Git v2.1.4 Release Notes
+========================
+
+Fixes since v2.1.3
+------------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+   running on a case sensitive filesystem, but an attempt to check out
+   such a path with Git that runs on a case insensitive filesystem
+   would have clobbered ".git/config", which is definitely not what
+   the user would have expected.  Git now prevents you from tracking
+   a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+   are mapped to ".git", e.g. "git~1/config" is treated as if it were
+   ".git/config".  HFS+ has a similar issue, where certain unicode
+   codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+   it were ".git/config".  Pathnames with these potential issues are
+   rejected on the affected systems.  Git on systems that are not
+   affected by this issue (e.g. Linux) can also be configured to
+   reject them to ensure cross platform interoperability of the hosted
+   projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+   be confused with ".git", and with receive.fsckObjects configuration
+   set to true, an attempt to "git push" such a tree object will be
+   rejected.  Such a path may not be a problem on a well behaving
+   filesystem but in order to protect those on HFS+ and on case
+   insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.10.0.txt b/Documentation/RelNotes/2.10.0.txt
new file mode 100644
index 0000000000..3792b7d03d
--- /dev/null
+++ b/Documentation/RelNotes/2.10.0.txt
@@ -0,0 +1,675 @@
+Git 2.10 Release Notes
+======================
+
+Backward compatibility notes
+----------------------------
+
+Updates since v2.9
+------------------
+
+UI, Workflows & Features
+
+ * "git pull --rebase --verify-signature" learned to warn the user
+   that "--verify-signature" is a no-op when rebasing.
+
+ * An upstream project can make a recommendation to shallowly clone
+   some submodules in the .gitmodules file it ships.
+
+ * "git worktree add" learned that '-' can be used as a short-hand for
+   "@{-1}", the previous branch.
+
+ * Update the funcname definition to support css files.
+
+ * The completion script (in contrib/) learned to complete "git
+   status" options.
+
+ * Messages that are generated by auto gc during "git push" on the
+   receiving end are now passed back to the sending end in such a way
+   that they are shown with "remote: " prefix to avoid confusing the
+   users.
+
+ * "git add -i/-p" learned to honor diff.compactionHeuristic
+   experimental knob, so that the user can work on the same hunk split
+   as "git diff" output.
+
+ * "upload-pack" allows a custom "git pack-objects" replacement when
+   responding to "fetch/clone" via the uploadpack.packObjectsHook.
+   (merge b738396 jk/upload-pack-hook later to maint).
+
+ * Teach format-patch and mailsplit (hence "am") how a line that
+   happens to begin with "From " in the e-mail message is quoted with
+   ">", so that these lines can be restored to their original shape.
+   (merge d9925d1 ew/mboxrd-format-am later to maint).
+
+ * "git repack" learned the "--keep-unreachable" option, which sends
+   loose unreachable objects to a pack instead of leaving them loose.
+   This helps heuristics based on the number of loose objects
+   (e.g. "gc --auto").
+   (merge e26a8c4 jk/repack-keep-unreachable later to maint).
+
+ * "log --graph --format=" learned that "%>|(N)" specifies the width
+   relative to the terminal's left edge, not relative to the area to
+   draw text that is to the right of the ancestry-graph section.  It
+   also now accepts negative N that means the column limit is relative
+   to the right border.
+
+ * A careless invocation of "git send-email directory/" after editing
+   0001-change.patch with an editor often ends up sending both
+   0001-change.patch and its backup file, 0001-change.patch~, causing
+   embarrassment and a minor confusion.  Detect such an input and
+   offer to skip the backup files when sending the patches out.
+   (merge 531220b jc/send-email-skip-backup later to maint).
+
+ * "git submodule update" that drives many "git clone" could
+   eventually hit flaky servers/network conditions on one of the
+   submodules; the command learned to retry the attempt.
+
+ * The output coloring scheme learned two new attributes, italic and
+   strike, in addition to existing bold, reverse, etc.
+
+ * "git log" learns log.showSignature configuration variable, and a
+   command line option "--no-show-signature" to countermand it.
+   (merge fce04c3 mj/log-show-signature-conf later to maint).
+
+ * More markings of messages for i18n, with updates to various tests
+   to pass GETTEXT_POISON tests.
+
+ * "git archive" learned to handle files that are larger than 8GB and
+   commits far in the future than expressible by the traditional US-TAR
+   format.
+   (merge 560b0e8 jk/big-and-future-archive-tar later to maint).
+
+
+ * A new configuration variable core.sshCommand has been added to
+   specify what value for GIT_SSH_COMMAND to use per repository.
+
+ * "git worktree prune" protected worktrees that are marked as
+   "locked" by creating a file in a known location.  "git worktree"
+   command learned a dedicated command pair to create and remove such
+   a file, so that the users do not have to do this with editor.
+
+ * A handful of "git svn" updates.
+
+ * "git push" learned to accept and pass extra options to the
+   receiving end so that hooks can read and react to them.
+
+ * "git status" learned to suggest "merge --abort" during a conflicted
+   merge, just like it already suggests "rebase --abort" during a
+   conflicted rebase.
+
+ * "git jump" script (in contrib/) has been updated a bit.
+   (merge a91e692 jk/git-jump later to maint).
+
+ * "git push" and "git clone" learned to give better progress meters
+   to the end user who is waiting on the terminal.
+
+ * An entry "git log --decorate" for the tip of the current branch is
+   shown as "HEAD -> name" (where "name" is the name of the branch);
+   the arrow is now painted in the same color as "HEAD", not in the
+   color for commits.
+
+ * "git format-patch" learned format.from configuration variable to
+   specify the default settings for its "--from" option.
+
+ * "git am -3" calls "git merge-recursive" when it needs to fall back
+   to a three-way merge; this call has been turned into an internal
+   subroutine call instead of spawning a separate subprocess.
+
+ * The command line completion scripts (in contrib/) now knows about
+   "git branch --delete/--move [--remote]".
+   (merge 2703c22 vs/completion-branch-fully-spelled-d-m-r later to maint).
+
+ * "git rev-parse --git-path hooks/<hook>" learned to take
+   core.hooksPath configuration variable (introduced during 2.9 cycle)
+   into account.
+   (merge 9445b49 ab/hooks later to maint).
+
+ * "git log --show-signature" and other commands that display the
+   verification status of PGP signature now shows the longer key-id,
+   as 32-bit key-id is so last century.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git fast-import" learned the same performance trick to avoid
+   creating too small a packfile as "git fetch" and "git push" have,
+   using *.unpackLimit configuration.
+
+ * When "git daemon" is run without --[init-]timeout specified, a
+   connection from a client that silently goes offline can hang around
+   for a long time, wasting resources.  The socket-level KEEPALIVE has
+   been enabled to allow the OS to notice such failed connections.
+
+ * "git upload-pack" command has been updated to use the parse-options
+   API.
+
+ * The "git apply" standalone program is being libified; the first
+   step to move many state variables into a structure that can be
+   explicitly (re)initialized to make the machinery callable more
+   than once has been merged.
+
+ * HTTP transport gained an option to produce more detailed debugging
+   trace.
+   (merge 73e57aa ep/http-curl-trace later to maint).
+
+ * Instead of taking advantage of the fact that a struct string_list
+   that is allocated with all NULs happens to be the INIT_NODUP kind,
+   the users of string_list structures are taught to initialize them
+   explicitly as such, to document their behaviour better.
+   (merge 2721ce2 jk/string-list-static-init later to maint).
+
+ * HTTPd tests learned to show the server error log to help diagnosing
+   a failing tests.
+   (merge 44f243d nd/test-lib-httpd-show-error-log-in-verbose later to maint).
+
+ * The ownership rule for the piece of memory that hold references to
+   be fetched in "git fetch" was screwy, which has been cleaned up.
+
+ * "git bisect" makes an internal call to "git diff-tree" when
+   bisection finds the culprit, but this call did not initialize the
+   data structure to pass to the diff-tree API correctly.
+
+ * Further preparatory clean-up for "worktree" feature continues.
+   (merge 0409e0b nd/worktree-cleanup-post-head-protection later to maint).
+
+ * Formats of the various data (and how to validate them) where we use
+   GPG signature have been documented.
+
+ * A new run-command API function pipe_command() is introduced to
+   sanely feed data to the standard input while capturing data from
+   the standard output and the standard error of an external process,
+   which is cumbersome to hand-roll correctly without deadlocking.
+
+ * The codepath to sign data in a prepared buffer with GPG has been
+   updated to use this API to read from the status-fd to check for
+   errors (instead of relying on GPG's exit status).
+   (merge efee955 jk/gpg-interface-cleanup later to maint).
+
+ * Allow t/perf framework to use the features from the most recent
+   version of Git even when testing an older installed version.
+
+ * The commands in the "log/diff" family have had an FILE* pointer in the
+   data structure they pass around for a long time, but some codepaths
+   used to always write to the standard output.  As a preparatory step
+   to make "git format-patch" available to the internal callers, these
+   codepaths have been updated to consistently write into that FILE*
+   instead.
+
+ * Conversion from unsigned char sha1[20] to struct object_id
+   continues.
+
+ * Improve the look of the way "git fetch" reports what happened to
+   each ref that was fetched.
+
+ * The .c/.h sources are marked as such in our .gitattributes file so
+   that "git diff -W" and friends would work better.
+
+ * Code clean-up to avoid using a variable string that compilers may
+   feel untrustable as printf-style format given to write_file()
+   helper function.
+
+ * "git p4" used a location outside $GIT_DIR/refs/ to place its
+   temporary branches, which has been moved to refs/git-p4-tmp/.
+
+ * Existing autoconf generated test for the need to link with pthread
+   library did not check all the functions from pthread libraries;
+   recent FreeBSD has some functions in libc but not others, and we
+   mistakenly thought linking with libc is enough when it is not.
+
+ * When "git fsck" reports a broken link (e.g. a tree object contains
+   a blob that does not exist), both containing object and the object
+   that is referred to were reported with their 40-hex object names.
+   The command learned the "--name-objects" option to show the path to
+   the containing object from existing refs (e.g. "HEAD~24^2:file.txt").
+
+ * Allow http daemon tests in Travis CI tests.
+
+ * Makefile assumed that -lrt is always available on platforms that
+   want to use clock_gettime() and CLOCK_MONOTONIC, which is not a
+   case for recent Mac OS X.  The necessary symbols are often found in
+   libc on many modern systems and having -lrt on the command line, as
+   long as the library exists, had no effect, but when the platform
+   removes librt.a that is a different matter--having -lrt will break
+   the linkage.
+
+   This change could be seen as a regression for those who do need to
+   specify -lrt, as they now specifically ask for NEEDS_LIBRT when
+   building. Hopefully they are in the minority these days.
+
+ * Further preparatory work on the refs API before the pluggable
+   backend series can land.
+
+ * Error handling in the codepaths that updates refs has been
+   improved.
+
+ * The API to iterate over all the refs (i.e. for_each_ref(), etc.)
+   has been revamped.
+
+ * The handling of the "text=auto" attribute has been corrected.
+   $ echo "* text=auto eol=crlf" >.gitattributes
+   used to have the same effect as
+   $ echo "* text eol=crlf" >.gitattributes
+   i.e. declaring all files are text (ignoring "auto").  The
+   combination has been fixed to be equivalent to doing
+   $ git config core.autocrlf true
+
+ * Documentation has been updated to show better example usage
+   of the updated "text=auto" attribute.
+
+ * A few tests that specifically target "git rebase -i" have been
+   added.
+
+ * Dumb http transport on the client side has been optimized.
+   (merge ecba195 ew/http-walker later to maint).
+
+ * Users of the parse_options_concat() API function need to allocate
+   extra slots in advance and fill them with OPT_END() when they want
+   to decide the set of supported options dynamically, which makes the
+   code error-prone and hard to read.  This has been corrected by tweaking
+   the API to allocate and return a new copy of "struct option" array.
+
+ * "git fetch" exchanges batched have/ack messages between the sender
+   and the receiver, initially doubling every time and then falling
+   back to enlarge the window size linearly.  The "smart http"
+   transport, being an half-duplex protocol, outgrows the preset limit
+   too quickly and becomes inefficient when interacting with a large
+   repository.  The internal mechanism learned to grow the window size
+   more aggressively when working with the "smart http" transport.
+
+ * Tests for "git svn" have been taught to reuse the lib-httpd test
+   infrastructure when testing the subversion integration that
+   interacts with subversion repositories served over the http://
+   protocol.
+   (merge a8a5d25 ew/git-svn-http-tests later to maint).
+
+ * "git pack-objects" has a few options that tell it not to pack
+   objects found in certain packfiles, which require it to scan .idx
+   files of all available packs.  The codepaths involved in these
+   operations have been optimized for a common case of not having any
+   non-local pack and/or any .kept pack.
+
+ * The t3700 test about "add --chmod=-x" have been made a bit more
+   robust and generally cleaned up.
+   (merge 766cdc4 ib/t3700-add-chmod-x-updates later to maint).
+
+ * The build procedure learned PAGER_ENV knob that lists what default
+   environment variable settings to export for popular pagers.  This
+   mechanism is used to tweak the default settings to MORE on FreeBSD.
+   (merge 995bc22 ew/build-time-pager-tweaks later to maint).
+
+ * The http-backend (the server-side component of smart-http
+   transport) used to trickle the HTTP header one at a time.  Now
+   these write(2)s are batched.
+   (merge b36045c ew/http-backend-batch-headers later to maint).
+
+ * When "git rebase" tries to compare set of changes on the updated
+   upstream and our own branch, it computes patch-id for all of these
+   changes and attempts to find matches. This has been optimized by
+   lazily computing the full patch-id (which is expensive) to be
+   compared only for changes that touch the same set of paths.
+   (merge ba67504 kw/patch-ids-optim later to maint).
+
+ * A handful of tests that were broken under gettext-poison build have
+   been fixed.
+
+ * The recent i18n patch we added during this cycle did a bit too much
+   refactoring of the messages to avoid word-legos; the repetition has
+   been reduced to help translators.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.9
+----------------
+
+Unless otherwise noted, all the fixes since v2.8 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * The commands in `git log` family take %C(auto) in a custom format
+   string.  This unconditionally turned the color on, ignoring
+   --no-color or with --color=auto when the output is not connected to
+   a tty; this was corrected to make the format truly behave as
+   "auto".
+
+ * "git rev-list --count" whose walk-length is limited with "-n"
+   option did not work well with the counting optimized to look at the
+   bitmap index.
+
+ * "git show -W" (extend hunks to cover the entire function, delimited
+   by lines that match the "funcname" pattern) used to show the entire
+   file when a change added an entire function at the end of the file,
+   which has been fixed.
+
+ * The documentation set has been updated so that literal commands,
+   configuration variables and environment variables are consistently
+   typeset in fixed-width font and bold in manpages.
+
+ * "git svn propset" subcommand that was added in 2.3 days is
+   documented now.
+
+ * The documentation tries to consistently spell "GPG"; when
+   referring to the specific program name, "gpg" is used.
+
+ * "git reflog" stopped upon seeing an entry that denotes a branch
+   creation event (aka "unborn"), which made it appear as if the
+   reflog was truncated.
+
+ * The git-prompt scriptlet (in contrib/) was not friendly with those
+   who uses "set -u", which has been fixed.
+
+ * compat/regex code did not cleanly compile.
+
+ * A codepath that used alloca(3) to place an unbounded amount of data
+   on the stack has been updated to avoid doing so.
+
+ * "git update-index --add --chmod=+x file" may be usable as an escape
+   hatch, but not a friendly thing to force for people who do need to
+   use it regularly.  "git add --chmod=+x file" can be used instead.
+
+ * Build improvements for gnome-keyring (in contrib/)
+
+ * "git status" used to say "working directory" when it meant "working
+   tree".
+
+ * Comments about misbehaving FreeBSD shells have been clarified with
+   the version number (9.x and before are broken, newer ones are OK).
+
+ * "git cherry-pick A" worked on an unborn branch, but "git
+   cherry-pick A..B" didn't.
+
+ * Fix an unintended regression in v2.9 that breaks "clone --depth"
+   that recurses down to submodules by forcing the submodules to also
+   be cloned shallowly, which many server instances that host upstream
+   of the submodules are not prepared for.
+
+ * Fix unnecessarily waste in the idiomatic use of ': ${VAR=default}'
+   to set the default value, without enclosing it in double quotes.
+
+ * Some platform-specific code had non-ANSI strict declarations of C
+   functions that do not take any parameters, which has been
+   corrected.
+
+ * The internal code used to show local timezone offset is not
+   prepared to handle timestamps beyond year 2100, and gave a
+   bogus offset value to the caller.  Use a more benign looking
+   +0000 instead and let "git log" going in such a case, instead
+   of aborting.
+
+ * One among four invocations of readlink(1) in our test suite has
+   been rewritten so that the test can run on systems without the
+   command (others are in valgrind test framework and t9802).
+
+ * t/perf needs /usr/bin/time with GNU extension; the invocation of it
+   is updated to "gtime" on Darwin.
+
+ * A bug, which caused "git p4" while running under verbose mode to
+   report paths that are omitted due to branch prefix incorrectly, has
+   been fixed; the command said "Ignoring file outside of prefix" for
+   paths that are _inside_.
+
+ * The top level documentation "git help git" still pointed at the
+   documentation set hosted at now-defunct google-code repository.
+   Update it to point to https://git.github.io/htmldocs/git.html
+   instead.
+
+ * A helper function that takes the contents of a commit object and
+   finds its subject line did not ignore leading blank lines, as is
+   commonly done by other codepaths.  Make it ignore leading blank
+   lines to match.
+
+ * For a long time, we carried an in-code comment that said our
+   colored output would work only when we use fprintf/fputs on
+   Windows, which no longer is the case for the past few years.
+
+ * "gc.autoPackLimit" when set to 1 should not trigger a repacking
+   when there is only one pack, but the code counted poorly and did
+   so.
+
+ * Add a test to specify the desired behaviour that currently is not
+   available in "git rebase -Xsubtree=...".
+
+ * More mark-up updates to typeset strings that are expected to
+   literally typed by the end user in fixed-width font.
+
+ * "git commit --amend --allow-empty-message -S" for a commit without
+   any message body could have misidentified where the header of the
+   commit object ends.
+
+ * "git rebase -i --autostash" did not restore the auto-stashed change
+   when the operation was aborted.
+
+ * Git does not know what the contents in the index should be for a
+   path added with "git add -N" yet, so "git grep --cached" should not
+   show hits (or show lack of hits, with -L) in such a path, but that
+   logic does not apply to "git grep", i.e. searching in the working
+   tree files.  But we did so by mistake, which has been corrected.
+
+ * "git blame -M" missed a single line that was moved within the file.
+
+ * Fix recently introduced codepaths that are involved in parallel
+   submodule operations, which gave up on reading too early, and
+   could have wasted CPU while attempting to write under a corner
+   case condition.
+
+ * "git grep -i" has been taught to fold case in non-ascii locales
+   correctly.
+
+ * A test that unconditionally used "mktemp" learned that the command
+   is not necessarily available everywhere.
+
+ * There are certain house-keeping tasks that need to be performed at
+   the very beginning of any Git program, and programs that are not
+   built-in commands had to do them exactly the same way as "git"
+   potty does.  It was easy to make mistakes in one-off standalone
+   programs (like test helpers).  A common "main()" function that
+   calls cmd_main() of individual program has been introduced to
+   make it harder to make mistakes.
+   (merge de61ceb jk/common-main later to maint).
+
+ * The test framework learned a new helper test_match_signal to
+   check an exit code from getting killed by an expected signal.
+
+ * General code clean-up around a helper function to write a
+   single-liner to a file.
+   (merge 7eb6e10 jk/write-file later to maint).
+
+ * One part of "git am" had an oddball helper function that called
+   stuff from outside "his" as opposed to calling what we have "ours",
+   which was not gender-neutral and also inconsistent with the rest of
+   the system where outside stuff is usually called "theirs" in
+   contrast to "ours".
+
+ * "git blame file" allowed the lineage of lines in the uncommitted,
+   unadded contents of "file" to be inspected, but it refused when
+   "file" did not appear in the current commit.  When "file" was
+   created by renaming an existing file (but the change has not been
+   committed), this restriction was unnecessarily tight.
+
+ * "git add -N dir/file && git write-tree" produced an incorrect tree
+   when there are other paths in the same directory that sorts after
+   "file".
+
+ * "git fetch http://user:pass@host/repo..."; scrubbed the userinfo
+   part, but "git push" didn't.
+
+ * "git merge" with renormalization did not work well with
+   merge-recursive, due to "safer crlf" conversion kicking in when it
+   shouldn't.
+   (merge 1335d76 jc/renormalize-merge-kill-safer-crlf later to maint).
+
+ * The use of strbuf in "git rm" to build filename to remove was a bit
+   suboptimal, which has been fixed.
+
+ * An age old bug that caused "git diff --ignore-space-at-eol"
+   misbehave has been fixed.
+
+ * "git notes merge" had a code to see if a path exists (and fails if
+   it does) and then open the path for writing (when it doesn't).
+   Replace it with open with O_EXCL.
+
+ * "git pack-objects" and "git index-pack" mostly operate with off_t
+   when talking about the offset of objects in a packfile, but there
+   were a handful of places that used "unsigned long" to hold that
+   value, leading to an unintended truncation.
+
+ * Recent update to "git daemon" tries to enable the socket-level
+   KEEPALIVE, but when it is spawned via inetd, the standard input
+   file descriptor may not necessarily be connected to a socket.
+   Suppress an ENOTSOCK error from setsockopt().
+
+ * Recent FreeBSD stopped making perl available at /usr/bin/perl;
+   switch the default the built-in path to /usr/local/bin/perl on not
+   too ancient FreeBSD releases.
+
+ * "git commit --help" said "--no-verify" is only about skipping the
+   pre-commit hook, and failed to say that it also skipped the
+   commit-msg hook.
+
+ * "git merge" in Git v2.9 was taught to forbid merging an unrelated
+   lines of history by default, but that is exactly the kind of thing
+   the "--rejoin" mode of "git subtree" (in contrib/) wants to do.
+   "git subtree" has been taught to use the "--allow-unrelated-histories"
+   option to override the default.
+
+ * The build procedure for "git persistent-https" helper (in contrib/)
+   has been updated so that it can be built with more recent versions
+   of Go.
+
+ * There is an optimization used in "git diff $treeA $treeB" to borrow
+   an already checked-out copy in the working tree when it is known to
+   be the same as the blob being compared, expecting that open/mmap of
+   such a file is faster than reading it from the object store, which
+   involves inflating and applying delta.  This however kicked in even
+   when the checked-out copy needs to go through the convert-to-git
+   conversion (including the clean filter), which defeats the whole
+   point of the optimization.  The optimization has been disabled when
+   the conversion is necessary.
+
+ * "git -c grep.patternType=extended log --basic-regexp" misbehaved
+   because the internal API to access the grep machinery was not
+   designed well.
+
+ * Windows port was failing some tests in t4130, due to the lack of
+   inum in the returned values by its lstat(2) emulation.
+
+ * The reflog output format is documented better, and a new format
+   --date=unix to report the seconds-since-epoch (without timezone)
+   has been added.
+   (merge 442f6fd jk/reflog-date later to maint).
+
+ * "git difftool <paths>..." started in a subdirectory failed to
+   interpret the paths relative to that directory, which has been
+   fixed.
+
+ * The characters in the label shown for tags/refs for commits in
+   "gitweb" output are now properly escaped for proper HTML output.
+
+ * FreeBSD can lie when asked mtime of a directory, which made the
+   untracked cache code to fall back to a slow-path, which in turn
+   caused tests in t7063 to fail because it wanted to verify the
+   behaviour of the fast-path.
+
+ * Squelch compiler warnings for nedmalloc (in compat/) library.
+
+ * A small memory leak in the command line parsing of "git blame"
+   has been plugged.
+
+ * The API documentation for hashmap was unclear if hashmap_entry
+   can be safely discarded without any other consideration.  State
+   that it is safe to do so.
+
+ * Not-so-recent rewrite of "git am" that started making internal
+   calls into the commit machinery had an unintended regression, in
+   that no matter how many seconds it took to apply many patches, the
+   resulting committer timestamp for the resulting commits were all
+   the same.
+
+ * "git push --force-with-lease" already had enough logic to allow
+   ensuring that such a push results in creation of a ref (i.e. the
+   receiving end did not have another push from sideways that would be
+   discarded by our force-pushing), but didn't expose this possibility
+   to the users.  It does so now.
+   (merge 9eed4f3 jk/push-force-with-lease-creation later to maint).
+
+ * The mechanism to limit the pack window memory size, when packing is
+   done using multiple threads (which is the default), is per-thread,
+   but this was not documented clearly.
+   (merge 954176c ms/document-pack-window-memory-is-per-thread later to maint).
+
+ * "import-tars" fast-import script (in contrib/) used to ignore a
+   hardlink target and replaced it with an empty file, which has been
+   corrected to record the same blob as the other file the hardlink is
+   shared with.
+   (merge 04e0869 js/import-tars-hardlinks later to maint).
+
+ * "git mv dir non-existing-dir/" did not work in some environments
+   the same way as existing mainstream platforms.  The code now moves
+   "dir" to "non-existing-dir", without relying on rename("A", "B/")
+   that strips the trailing slash of '/'.
+   (merge 189d035 js/mv-dir-to-new-directory later to maint).
+
+ * The "t/" hierarchy is prone to get an unusual pathname; "make test"
+   has been taught to make sure they do not contain paths that cannot
+   be checked out on Windows (and the mechanism can be reusable to
+   catch pathnames that are not portable to other platforms as need
+   arises).
+   (merge c2cafd3 js/test-lint-pathname later to maint).
+
+ * When "git merge-recursive" works on history with many criss-cross
+   merges in "verbose" mode, the names the command assigns to the
+   virtual merge bases could have overwritten each other by unintended
+   reuse of the same piece of memory.
+   (merge 5447a76 rs/pull-signed-tag later to maint).
+
+ * "git checkout --detach <branch>" used to give the same advice
+   message as that is issued when "git checkout <tag>" (or anything
+   that is not a branch name) is given, but asking with "--detach" is
+   an explicit enough sign that the user knows what is going on.  The
+   advice message has been squelched in this case.
+   (merge 779b88a sb/checkout-explit-detach-no-advice later to maint).
+
+ * "git difftool" by default ignores the error exit from the backend
+   commands it spawns, because often they signal that they found
+   differences by exiting with a non-zero status code just like "diff"
+   does; the exit status codes 126 and above however are special in
+   that they are used to signal that the command is not executable,
+   does not exist, or killed by a signal.  "git difftool" has been
+   taught to notice these exit status codes.
+   (merge 45a4f5d jk/difftool-command-not-found later to maint).
+
+ * On Windows, help.browser configuration variable used to be ignored,
+   which has been corrected.
+   (merge 6db5967 js/no-html-bypass-on-windows later to maint).
+
+ * The "git -c var[=val] cmd" facility to append a configuration
+   variable definition at the end of the search order was described in
+   git(1) manual page, but not in git-config(1), which was more likely
+   place for people to look for when they ask "can I make a one-shot
+   override, and if so how?"
+   (merge ae1f709 dg/document-git-c-in-git-config-doc later to maint).
+
+ * The tempfile (hence its user lockfile) API lets the caller to open
+   a file descriptor to a temporary file, write into it and then
+   finalize it by first closing the filehandle and then either
+   removing or renaming the temporary file.  When the process spawns a
+   subprocess after obtaining the file descriptor, and if the
+   subprocess has not exited when the attempt to remove or rename is
+   made, the last step fails on Windows, because the subprocess has
+   the file descriptor still open.  Open tempfile with O_CLOEXEC flag
+   to avoid this (on Windows, this is mapped to O_NOINHERIT).
+   (merge 05d1ed6 bw/mingw-avoid-inheriting-fd-to-lockfile later to maint).
+
+ * Correct an age-old calco (is that a typo-like word for calc)
+   in the documentation.
+   (merge 7841c48 ls/packet-line-protocol-doc-fix later to maint).
+
+ * Other minor clean-ups and documentation updates
+   (merge 02a8cfa rs/merge-add-strategies-simplification later to maint).
+   (merge af4941d rs/merge-recursive-string-list-init later to maint).
+   (merge 1eb47f1 rs/use-strbuf-add-unique-abbrev later to maint).
+   (merge ddd0bfa jk/tighten-alloc later to maint).
+   (merge ecf30b2 rs/mailinfo-lib later to maint).
+   (merge 0eb75ce sg/reflog-past-root later to maint).
+   (merge 4369523 hv/doc-commit-reference-style later to maint).
diff --git a/Documentation/RelNotes/2.10.1.txt b/Documentation/RelNotes/2.10.1.txt
new file mode 100644
index 0000000000..70462f7f7e
--- /dev/null
+++ b/Documentation/RelNotes/2.10.1.txt
@@ -0,0 +1,131 @@
+Git v2.10.1 Release Notes
+=========================
+
+Fixes since v2.10
+-----------------
+
+ * Clarify various ways to specify the "revision ranges" in the
+   documentation.
+
+ * "diff-highlight" script (in contrib/) learned to work better with
+   "git log -p --graph" output.
+
+ * The test framework left the number of tests and success/failure
+   count in the t/test-results directory, keyed by the name of the
+   test script plus the process ID.  The latter however turned out not
+   to serve any useful purpose.  The process ID part of the filename
+   has been removed.
+
+ * Having a submodule whose ".git" repository is somehow corrupt
+   caused a few commands that recurse into submodules loop forever.
+
+ * "git symbolic-ref -d HEAD" happily removes the symbolic ref, but
+   the resulting repository becomes an invalid one.  Teach the command
+   to forbid removal of HEAD.
+
+ * A test spawned a short-lived background process, which sometimes
+   prevented the test directory from getting removed at the end of the
+   script on some platforms.
+
+ * Update a few tests that used to use GIT_CURL_VERBOSE to use the
+   newer GIT_TRACE_CURL.
+
+ * Update Japanese translation for "git-gui".
+
+ * "git fetch http::/site/path" did not die correctly and segfaulted
+   instead.
+
+ * "git commit-tree" stopped reading commit.gpgsign configuration
+   variable that was meant for Porcelain "git commit" in Git 2.9; we
+   forgot to update "git gui" to look at the configuration to match
+   this change.
+
+ * "git log --cherry-pick" used to include merge commits as candidates
+   to be matched up with other commits, resulting a lot of wasted time.
+   The patch-id generation logic has been updated to ignore merges to
+   avoid the wastage.
+
+ * The http transport (with curl-multi option, which is the default
+   these days) failed to remove curl-easy handle from a curlm session,
+   which led to unnecessary API failures.
+
+ * "git diff -W" output needs to extend the context backward to
+   include the header line of the current function and also forward to
+   include the body of the entire current function up to the header
+   line of the next one.  This process may have to merge to adjacent
+   hunks, but the code forgot to do so in some cases.
+
+ * Performance tests done via "t/perf" did not use the same set of
+   build configuration if the user relied on autoconf generated
+   configuration.
+
+ * "git format-patch --base=..." feature that was recently added
+   showed the base commit information after "-- " e-mail signature
+   line, which turned out to be inconvenient.  The base information
+   has been moved above the signature line.
+
+ * Even when "git pull --rebase=preserve" (and the underlying "git
+   rebase --preserve") can complete without creating any new commit
+   (i.e. fast-forwards), it still insisted on having a usable ident
+   information (read: user.email is set correctly), which was less
+   than nice.  As the underlying commands used inside "git rebase"
+   would fail with a more meaningful error message and advice text
+   when the bogus ident matters, this extra check was removed.
+
+ * "git gc --aggressive" used to limit the delta-chain length to 250,
+   which is way too deep for gaining additional space savings and is
+   detrimental for runtime performance.  The limit has been reduced to
+   50.
+
+ * Documentation for individual configuration variables to control use
+   of color (like `color.grep`) said that their default value is
+   'false', instead of saying their default is taken from `color.ui`.
+   When we updated the default value for color.ui from 'false' to
+   'auto' quite a while ago, all of them broke.  This has been
+   corrected.
+
+ * A shell script example in check-ref-format documentation has been
+   fixed.
+
+ * "git checkout <word>" does not follow the usual disambiguation
+   rules when the <word> can be both a rev and a path, to allow
+   checking out a branch 'foo' in a project that happens to have a
+   file 'foo' in the working tree without having to disambiguate.
+   This was poorly documented and the check was incorrect when the
+   command was run from a subdirectory.
+
+ * Some codepaths in "git diff" used regexec(3) on a buffer that was
+   mmap(2)ed, which may not have a terminating NUL, leading to a read
+   beyond the end of the mapped region.  This was fixed by introducing
+   a regexec_buf() helper that takes a <ptr,len> pair with REG_STARTEND
+   extension.
+
+ * The procedure to build Git on Mac OS X for Travis CI hardcoded the
+   internal directory structure we assumed HomeBrew uses, which was a
+   no-no.  The procedure has been updated to ask HomeBrew things we
+   need to know to fix this.
+
+ * When "git rebase -i" is given a broken instruction, it told the
+   user to fix it with "--edit-todo", but didn't say what the step
+   after that was (i.e. "--continue").
+
+ * "git add --chmod=+x" added recently lacked documentation, which has
+   been corrected.
+
+ * "git add --chmod=+x <pathspec>" added recently only toggled the
+   executable bit for paths that are either new or modified. This has
+   been corrected to flip the executable bit for all paths that match
+   the given pathspec.
+
+ * "git pack-objects --include-tag" was taught that when we know that
+   we are sending an object C, we want a tag B that directly points at
+   C but also a tag A that points at the tag B.  We used to miss the
+   intermediate tag B in some cases.
+
+ * Documentation around tools to import from CVS was fairly outdated.
+
+ * In the codepath that comes up with the hostname to be used in an
+   e-mail when the user didn't tell us, we looked at ai_canonname
+   field in struct addrinfo without making sure it is not NULL first.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.10.2.txt b/Documentation/RelNotes/2.10.2.txt
new file mode 100644
index 0000000000..abbd331508
--- /dev/null
+++ b/Documentation/RelNotes/2.10.2.txt
@@ -0,0 +1,111 @@
+Git v2.10.2 Release Notes
+=========================
+
+Fixes since v2.10.1
+-------------------
+
+ * The code that parses the format parameter of for-each-ref command
+   has seen a micro-optimization.
+
+ * The "graph" API used in "git log --graph" miscounted the number of
+   output columns consumed so far when drawing a padding line, which
+   has been fixed; this did not affect any existing code as nobody
+   tried to write anything after the padding on such a line, though.
+
+ * Almost everybody uses DEFAULT_ABBREV to refer to the default
+   setting for the abbreviation, but "git blame" peeked into
+   underlying variable bypassing the macro for no good reason.
+
+ * Doc update to clarify what "log -3 --reverse" does.
+
+ * An author name, that spelled a backslash-quoted double quote in the
+   human readable part "My \"double quoted\" name", was not unquoted
+   correctly while applying a patch from a piece of e-mail.
+
+ * The original command line syntax for "git merge", which was "git
+   merge <msg> HEAD <parent>...", has been deprecated for quite some
+   time, and "git gui" was the last in-tree user of the syntax.  This
+   is finally fixed, so that we can move forward with the deprecation.
+
+ * Codepaths that read from an on-disk loose object were too loose in
+   validating what they are reading is a proper object file and
+   sometimes read past the data they read from the disk, which has
+   been corrected.  H/t to Gustavo Grieco for reporting.
+
+ * "git worktree", even though it used the default_abbrev setting that
+   ought to be affected by core.abbrev configuration variable, ignored
+   the variable setting.  The command has been taught to read the
+   default set of configuration variables to correct this.
+
+ * A low-level function verify_packfile() was meant to show errors
+   that were detected without dying itself, but under some conditions
+   it didn't and died instead, which has been fixed.
+
+ * When "git fetch" tries to find where the history of the repository
+   it runs in has diverged from what the other side has, it has a
+   mechanism to avoid digging too deep into irrelevant side branches.
+   This however did not work well over the "smart-http" transport due
+   to a design bug, which has been fixed.
+
+ * When we started cURL to talk to imap server when a new enough
+   version of cURL library is available, we forgot to explicitly add
+   imap(s):// before the destination.  To some folks, that didn't work
+   and the library tried to make HTTP(s) requests instead.
+
+ * The ./configure script generated from configure.ac was taught how
+   to detect support of SSL by libcurl better.
+
+ * http.emptyauth configuration is a way to allow an empty username to
+   pass when attempting to authenticate using mechanisms like
+   Kerberos.  We took an unspecified (NULL) username and sent ":"
+   (i.e. no username, no password) to CURLOPT_USERPWD, but did not do
+   the same when the username is explicitly set to an empty string.
+
+ * "git clone" of a local repository can be done at the filesystem
+   level, but the codepath did not check errors while copying and
+   adjusting the file that lists alternate object stores.
+
+ * Documentation for "git commit" was updated to clarify that "commit
+   -p <paths>" adds to the current contents of the index to come up
+   with what to commit.
+
+ * A stray symbolic link in $GIT_DIR/refs/ directory could make name
+   resolution loop forever, which has been corrected.
+
+ * The "submodule.<name>.path" stored in .gitmodules is never copied
+   to .git/config and such a key in .git/config has no meaning, but
+   the documentation described it and submodule.<name>.url next to
+   each other as if both belong to .git/config.  This has been fixed.
+
+ * Recent git allows submodule.<name>.branch to use a special token
+   "." instead of the branch name; the documentation has been updated
+   to describe it.
+
+ * In a worktree connected to a repository elsewhere, created via "git
+   worktree", "git checkout" attempts to protect users from confusion
+   by refusing to check out a branch that is already checked out in
+   another worktree.  However, this also prevented checking out a
+   branch, which is designated as the primary branch of a bare
+   repository, in a worktree that is connected to the bare
+   repository.  The check has been corrected to allow it.
+
+ * "git rebase" immediately after "git clone" failed to find the fork
+   point from the upstream.
+
+ * When fetching from a remote that has many tags that are irrelevant
+   to branches we are following, we used to waste way too many cycles
+   when checking if the object pointed at by a tag (that we are not
+   going to fetch!) exists in our repository too carefully.
+
+ * The Travis CI configuration we ship ran the tests with --verbose
+   option but this risks non-TAP output that happens to be "ok" to be
+   misinterpreted as TAP signalling a test that passed.  This resulted
+   in unnecessary failure.  This has been corrected by introducing a
+   new mode to run our tests in the test harness to send the verbose
+   output separately to the log file.
+
+ * Some AsciiDoc formatter mishandles a displayed illustration with
+   tabs in it.  Adjust a few of them in merge-base documentation to
+   work around them.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.10.3.txt b/Documentation/RelNotes/2.10.3.txt
new file mode 100644
index 0000000000..ad6a01bf83
--- /dev/null
+++ b/Documentation/RelNotes/2.10.3.txt
@@ -0,0 +1,55 @@
+Git v2.10.3 Release Notes
+=========================
+
+Fixes since v2.10.2
+-------------------
+
+ * Extract a small helper out of the function that reads the authors
+   script file "git am" internally uses.
+   This by itself is not useful until a second caller appears in the
+   future for "rebase -i" helper.
+
+ * The command-line completion script (in contrib/) learned to
+   complete "git cmd ^mas<HT>" to complete the negative end of
+   reference to "git cmd ^master".
+
+ * "git send-email" attempts to pick up valid e-mails from the
+   trailers, but people in real world write non-addresses there, like
+   "Cc: Stable <add@xxxxx> # 4.8+", which broke the output depending
+   on the availability and vintage of Mail::Address perl module.
+
+ * The code that we have used for the past 10+ years to cycle
+   4-element ring buffers turns out to be not quite portable in
+   theoretical world.
+
+ * "git daemon" used fixed-length buffers to turn URL to the
+   repository the client asked for into the server side directory
+   path, using snprintf() to avoid overflowing these buffers, but
+   allowed possibly truncated paths to the directory.  This has been
+   tightened to reject such a request that causes overlong path to be
+   required to serve.
+
+ * Recent update to git-sh-setup (a library of shell functions that
+   are used by our in-tree scripted Porcelain commands) included
+   another shell library git-sh-i18n without specifying where it is,
+   relying on the $PATH.  This has been fixed to be more explicit by
+   prefixing $(git --exec-path) output in front.
+
+ * Fix for a racy false-positive test failure.
+
+ * Portability update and workaround for builds on recent Mac OS X.
+
+ * Update to the test framework made in 2.9 timeframe broke running
+   the tests under valgrind, which has been fixed.
+
+ * Improve the rule to convert "unsigned char [20]" into "struct
+   object_id *" in contrib/coccinelle/
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.10.4.txt b/Documentation/RelNotes/2.10.4.txt
new file mode 100644
index 0000000000..ee8142ad24
--- /dev/null
+++ b/Documentation/RelNotes/2.10.4.txt
@@ -0,0 +1,4 @@
+Git v2.10.4 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.10.5.txt b/Documentation/RelNotes/2.10.5.txt
new file mode 100644
index 0000000000..a498fd6fdc
--- /dev/null
+++ b/Documentation/RelNotes/2.10.5.txt
@@ -0,0 +1,17 @@
+Git v2.10.5 Release Notes
+=========================
+
+Fixes since v2.10.4
+-------------------
+
+ * "git cvsserver" no longer is invoked by "git daemon" by default,
+   as it is old and largely unmaintained.
+
+ * Various Perl scripts did not use safe_pipe_capture() instead of
+   backticks, leaving them susceptible to end-user input.  They have
+   been corrected.
+
+Credits go to joernchen <joernchen@xxxxxxxxxxxx> for finding the
+unsafe constructs in "git cvsserver", and to Jeff King at GitHub for
+finding and fixing instances of the same issue in other scripts.
+
diff --git a/Documentation/RelNotes/2.11.0.txt b/Documentation/RelNotes/2.11.0.txt
new file mode 100644
index 0000000000..b7b7dd361e
--- /dev/null
+++ b/Documentation/RelNotes/2.11.0.txt
@@ -0,0 +1,593 @@
+Git 2.11 Release Notes
+======================
+
+Backward compatibility notes.
+
+ * An empty string used as a pathspec element has always meant
+   'everything matches', but it is too easy to write a script that
+   finds a path to remove in $path and run 'git rm "$paht"' by
+   mistake (when the user meant to give "$path"), which ends up
+   removing everything.  This release starts warning about the
+   use of an empty string that is used for 'everything matches' and
+   asks users to use a more explicit '.' for that instead.
+
+   The hope is that existing users will not mind this change, and
+   eventually the warning can be turned into a hard error, upgrading
+   the deprecation into removal of this (mis)feature.
+
+ * The historical argument order "git merge <msg> HEAD <commit>..."
+   has been deprecated for quite some time, and will be removed in the
+   next release (not this one).
+
+ * The default abbreviation length, which has historically been 7, now
+   scales as the repository grows, using the approximate number of
+   objects in the repository and a bit of math around the birthday
+   paradox.  The logic suggests to use 12 hexdigits for the Linux
+   kernel, and 9 to 10 for Git itself.
+
+
+Updates since v2.10
+-------------------
+
+UI, Workflows & Features
+
+ * Comes with new version of git-gui, now at its 0.21.0 tag.
+
+ * "git format-patch --cover-letter HEAD^" to format a single patch
+   with a separate cover letter now numbers the output as [PATCH 0/1]
+   and [PATCH 1/1] by default.
+
+ * An incoming "git push" that attempts to push too many bytes can now
+   be rejected by setting a new configuration variable at the receiving
+   end.
+
+ * "git nosuchcommand --help" said "No manual entry for gitnosuchcommand",
+   which was not intuitive, given that "git nosuchcommand" said "git:
+   'nosuchcommand' is not a git command".
+
+ * "git clone --recurse-submodules --reference $path $URL" is a way to
+   reduce network transfer cost by borrowing objects in an existing
+   $path repository when cloning the superproject from $URL; it
+   learned to also peek into $path for presence of corresponding
+   repositories of submodules and borrow objects from there when able.
+
+ * The "git diff --submodule={short,log}" mechanism has been enhanced
+   to allow "--submodule=diff" to show the patch between the submodule
+   commits bound to the superproject.
+
+ * Even though "git hash-objects", which is a tool to take an
+   on-filesystem data stream and put it into the Git object store,
+   can perform "outside-world-to-Git" conversions (e.g.
+   end-of-line conversions and application of the clean-filter), and
+   it has had this feature on by default from very early days, its reverse
+   operation "git cat-file", which takes an object from the Git object
+   store and externalizes it for consumption by the outside world,
+   lacked an equivalent mechanism to run the "Git-to-outside-world"
+   conversion.  The command learned the "--filters" option to do so.
+
+ * Output from "git diff" can be made easier to read by intelligently selecting
+   which lines are common and which lines are added/deleted
+   when the lines before and after the changed section
+   are the same.  A command line option (--indent-heuristic) and a
+   configuration variable (diff.indentHeuristic) are added to help with the
+   experiment to find good heuristics.
+
+ * In some projects, it is common to use "[RFC PATCH]" as the subject
+   prefix for a patch meant for discussion rather than application.  A
+   new format-patch option "--rfc" is a short-hand for "--subject-prefix=RFC PATCH"
+   to help the participants of such projects.
+
+ * "git add --chmod={+,-}x <pathspec>" only changed the
+   executable bit for paths that are either new or modified. This has
+   been corrected to change the executable bit for all paths that match
+   the given pathspec.
+
+ * When "git format-patch --stdout" output is placed as an in-body
+   header and it uses RFC2822 header folding, "git am" fails to
+   put the header line back into a single logical line.  The
+   underlying "git mailinfo" was taught to handle this properly.
+
+ * "gitweb" can spawn "highlight" to show blob contents with
+   (programming) language-specific syntax highlighting, but only
+   when the language is known.  "highlight" can however be told
+   to guess the language itself by giving it "--force" option, which
+   has been enabled.
+
+ * "git gui" l10n to Portuguese.
+
+ * When given an abbreviated object name that is not (or more
+   realistically, "no longer") unique, we gave a fatal error
+   "ambiguous argument".  This error is now accompanied by a hint that
+   lists the objects beginning with the given prefix.  During the
+   course of development of this new feature, numerous minor bugs were
+   uncovered and corrected, the most notable one of which is that we
+   gave "short SHA1 xxxx is ambiguous." twice without good reason.
+
+ * "git log rev^..rev" is an often-used revision range specification
+   to show what was done on a side branch merged at rev.  This has
+   gained a short-hand "rev^-1".  In general "rev^-$n" is the same as
+   "^rev^$n rev", i.e. what has happened on other branches while the
+   history leading to nth parent was looking the other way.
+
+ * In recent versions of cURL, GSSAPI credential delegation is
+   disabled by default due to CVE-2011-2192; introduce a http.delegation
+   configuration variable to selectively allow enabling this.
+   (merge 26a7b23429 ps/http-gssapi-cred-delegation later to maint).
+
+ * "git mergetool" learned to honor "-O<orderfile>" to control the
+   order of paths to present to the end user.
+
+ * "git diff/log --ws-error-highlight=<kind>" lacked the corresponding
+   configuration variable (diff.wsErrorHighlight) to set it by default.
+
+ * "git ls-files" learned the "--recurse-submodules" option
+   to get a listing of tracked files across submodules (i.e. this
+   only works with the "--cached" option, not for listing untracked or
+   ignored files).  This would be a useful tool to sit on the upstream
+   side of a pipe that is read with xargs to work on all working tree
+   files from the top-level superproject.
+
+ * A new credential helper that talks via "libsecret" with
+   implementations of XDG Secret Service API has been added to
+   contrib/credential/.
+
+ * The GPG verification status shown by the "%G?" pretty format specifier
+   was not rich enough to differentiate a signature made by an expired
+   key, a signature made by a revoked key, etc.  New output letters
+   have been assigned to express them.
+
+ * In addition to purely abbreviated commit object names, "gitweb"
+   learned to turn "git describe" output (e.g. v2.9.3-599-g2376d31787)
+   into clickable links in its output.
+
+ * "git commit" created an empty commit when invoked with an index
+   consisting solely of intend-to-add paths (added with "git add -N").
+   It now requires the "--allow-empty" option to create such a commit.
+   The same logic prevented "git status" from showing such paths as "new files" in the
+   "Changes not staged for commit" section.
+
+ * The smudge/clean filter API spawns an external process
+   to filter the contents of each path that has a filter defined.  A
+   new type of "process" filter API has been added to allow the first
+   request to run the filter for a path to spawn a single process, and
+   all filtering is served by this single process for multiple
+   paths, reducing the process creation overhead.
+
+ * The user always has to say "stash@{$N}" when naming a single
+   element in the default location of the stash, i.e. reflogs in
+   refs/stash.  The "git stash" command learned to accept "git stash
+   apply 4" as a short-hand for "git stash apply stash@{4}".
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The delta-base-cache mechanism has been a key to the performance in
+   a repository with a tightly packed packfile, but it did not scale
+   well even with a larger value of core.deltaBaseCacheLimit.
+
+ * Enhance "git status --porcelain" output by collecting more data on
+   the state of the index and the working tree files, which may
+   further be used to teach git-prompt (in contrib/) to make fewer
+   calls to git.
+
+ * Extract a small helper out of the function that reads the authors
+   script file "git am" internally uses.
+   (merge a77598e jc/am-read-author-file later to maint).
+
+ * Lift calls to exit(2) and die() higher in the callchain in
+   sequencer.c files so that more helper functions in it can be used
+   by callers that want to handle error conditions themselves.
+
+ * "git am" has been taught to make an internal call to "git apply"'s
+   innards without spawning the latter as a separate process.
+
+ * The ref-store abstraction was introduced to the refs API so that we
+   can plug in different backends to store references.
+
+ * The "unsigned char sha1[20]" to "struct object_id" conversion
+   continues.  Notable changes in this round includes that ce->sha1,
+   i.e. the object name recorded in the cache_entry, turns into an
+   object_id.
+
+ * JGit can show a fake ref "capabilities^{}" to "git fetch" when it
+   does not advertise any refs, but "git fetch" was not prepared to
+   see such an advertisement.  When the other side disconnects without
+   giving any ref advertisement, we used to say "there may not be a
+   repository at that URL", but we may have seen other advertisements
+   like "shallow" and ".have" in which case we definitely know that a
+   repository is there.  The code to detect this case has also been
+   updated.
+
+ * Some codepaths in "git pack-objects" were not ready to use an
+   existing pack bitmap; now they are and as a result they have
+   become faster.
+
+ * The codepath in "git fsck" to detect malformed tree objects has
+   been updated not to die but keep going after detecting them.
+
+ * We call "qsort(array, nelem, sizeof(array[0]), fn)", and most of
+   the time third parameter is redundant.  A new QSORT() macro lets us
+   omit it.
+
+ * "git pack-objects" in a repository with many packfiles used to
+   spend a lot of time looking for/at objects in them; the accesses to
+   the packfiles are now optimized by checking the most-recently-used
+   packfile first.
+   (merge c9af708b1a jk/pack-objects-optim-mru later to maint).
+
+ * Codepaths involved in interacting alternate object stores have
+   been cleaned up.
+
+ * In order for the receiving end of "git push" to inspect the
+   received history and decide to reject the push, the objects sent
+   from the sending end need to be made available to the hook and
+   the mechanism for the connectivity check, and this was done
+   traditionally by storing the objects in the receiving repository
+   and letting "git gc" expire them.  Instead, store the newly
+   received objects in a temporary area, and make them available by
+   reusing the alternate object store mechanism to them only while we
+   decide if we accept the check, and once we decide, either migrate
+   them to the repository or purge them immediately.
+
+ * The require_clean_work_tree() helper was recreated in C when "git
+   pull" was rewritten from shell; the helper is now made available to
+   other callers in preparation for upcoming "rebase -i" work.
+
+ * "git upload-pack" had its code cleaned-up and performance improved
+   by reducing use of timestamp-ordered commit-list, which was
+   replaced with a priority queue.
+
+ * "git diff --no-index" codepath has been updated not to try to peek
+   into a .git/ directory that happens to be under the current
+   directory, when we know we are operating outside any repository.
+
+ * Update of the sequencer codebase to make it reusable to reimplement
+   "rebase -i" continues.
+
+ * Git generally does not explicitly close file descriptors that were
+   open in the parent process when spawning a child process, but most
+   of the time the child does not want to access them. As Windows does
+   not allow removing or renaming a file that has a file descriptor
+   open, a slow-to-exit child can even break the parent process by
+   holding onto them.  Use O_CLOEXEC flag to open files in various
+   codepaths.
+
+ * Update "interpret-trailers" machinery and teach it that people in
+   the real world write all sorts of cruft in the "trailer" that was
+   originally designed to have the neat-o "Mail-Header: like thing"
+   and nothing else.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.10
+-----------------
+
+Unless otherwise noted, all the fixes since v2.9 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * Clarify various ways to specify the "revision ranges" in the
+   documentation.
+
+ * "diff-highlight" script (in contrib/) learned to work better with
+   "git log -p --graph" output.
+
+ * The test framework left the number of tests and success/failure
+   count in the t/test-results directory, keyed by the name of the
+   test script plus the process ID.  The latter however turned out not
+   to serve any useful purpose.  The process ID part of the filename
+   has been removed.
+
+ * Having a submodule whose ".git" repository is somehow corrupt
+   caused a few commands that recurse into submodules to loop forever.
+
+ * "git symbolic-ref -d HEAD" happily removes the symbolic ref, but
+   the resulting repository becomes an invalid one.  Teach the command
+   to forbid removal of HEAD.
+
+ * A test spawned a short-lived background process, which sometimes
+   prevented the test directory from getting removed at the end of the
+   script on some platforms.
+
+ * Update a few tests that used to use GIT_CURL_VERBOSE to use the
+   newer GIT_TRACE_CURL.
+
+ * "git pack-objects --include-tag" was taught that when we know that
+   we are sending an object C, we want a tag B that directly points at
+   C but also a tag A that points at the tag B.  We used to miss the
+   intermediate tag B in some cases.
+
+ * Update Japanese translation for "git-gui".
+
+ * "git fetch http::/site/path" did not die correctly and segfaulted
+   instead.
+
+ * "git commit-tree" stopped reading commit.gpgsign configuration
+   variable that was meant for Porcelain "git commit" in Git 2.9; we
+   forgot to update "git gui" to look at the configuration to match
+   this change.
+
+ * "git add --chmod={+,-}x" added recently lacked documentation, which has
+   been corrected.
+
+ * "git log --cherry-pick" used to include merge commits as candidates
+   to be matched up with other commits, resulting a lot of wasted time.
+   The patch-id generation logic has been updated to ignore merges and
+   avoid the wastage.
+
+ * The http transport (with curl-multi option, which is the default
+   these days) failed to remove curl-easy handle from a curlm session,
+   which led to unnecessary API failures.
+
+ * There were numerous corner cases in which the configuration files
+   are read and used or not read at all depending on the directory a
+   Git command was run, leading to inconsistent behaviour.  The code
+   to set-up repository access at the beginning of a Git process has
+   been updated to fix them.
+   (merge 4d0efa1 jk/setup-sequence-update later to maint).
+
+ * "git diff -W" output needs to extend the context backward to
+   include the header line of the current function and also forward to
+   include the body of the entire current function up to the header
+   line of the next one.  This process may have to merge two adjacent
+   hunks, but the code forgot to do so in some cases.
+
+ * Performance tests done via "t/perf" did not use the right
+   build configuration if the user relied on autoconf generated
+   configuration.
+
+ * "git format-patch --base=..." feature that was recently added
+   showed the base commit information after the "-- " e-mail signature
+   line, which turned out to be inconvenient.  The base information
+   has been moved above the signature line.
+
+ * More i18n.
+
+ * Even when "git pull --rebase=preserve" (and the underlying "git
+   rebase --preserve") can complete without creating any new commits
+   (i.e. fast-forwards), it still insisted on having usable ident
+   information (read: user.email is set correctly), which was less
+   than nice.  As the underlying commands used inside "git rebase"
+   would fail with a more meaningful error message and advice text
+   when the bogus ident matters, this extra check was removed.
+
+ * "git gc --aggressive" used to limit the delta-chain length to 250,
+   which is way too deep for gaining additional space savings and is
+   detrimental for runtime performance.  The limit has been reduced to
+   50.
+
+ * Documentation for individual configuration variables to control use
+   of color (like `color.grep`) said that their default value is
+   'false', instead of saying their default is taken from `color.ui`.
+   When we updated the default value for color.ui from 'false' to
+   'auto' quite a while ago, all of them broke.  This has been
+   corrected.
+
+ * The pretty-format specifier "%C(auto)" used by the "log" family of
+   commands to enable coloring of the output is taught to also issue a
+   color-reset sequence to the output.
+
+ * A shell script example in check-ref-format documentation has been
+   fixed.
+
+ * "git checkout <word>" does not follow the usual disambiguation
+   rules when the <word> can be both a rev and a path, to allow
+   checking out a branch 'foo' in a project that happens to have a
+   file 'foo' in the working tree without having to disambiguate.
+   This was poorly documented and the check was incorrect when the
+   command was run from a subdirectory.
+
+ * Some codepaths in "git diff" used regexec(3) on a buffer that was
+   mmap(2)ed, which may not have a terminating NUL, leading to a read
+   beyond the end of the mapped region.  This was fixed by introducing
+   a regexec_buf() helper that takes a <ptr,len> pair with REG_STARTEND
+   extension.
+
+ * The procedure to build Git on Mac OS X for Travis CI hardcoded the
+   internal directory structure we assumed HomeBrew uses, which was a
+   no-no.  The procedure has been updated to ask HomeBrew things we
+   need to know to fix this.
+
+ * When "git rebase -i" is given a broken instruction, it told the
+   user to fix it with "--edit-todo", but didn't say what the step
+   after that was (i.e. "--continue").
+
+ * Documentation around tools to import from CVS was fairly outdated.
+
+ * "git clone --recurse-submodules" lost the progress eye-candy in
+   a recent update, which has been corrected.
+
+ * A low-level function verify_packfile() was meant to show errors
+   that were detected without dying itself, but under some conditions
+   it didn't and died instead, which has been fixed.
+
+ * When "git fetch" tries to find where the history of the repository
+   it runs in has diverged from what the other side has, it has a
+   mechanism to avoid digging too deep into irrelevant side branches.
+   This however did not work well over the "smart-http" transport due
+   to a design bug, which has been fixed.
+
+ * In the codepath that comes up with the hostname to be used in an
+   e-mail when the user didn't tell us, we looked at the ai_canonname
+   field in struct addrinfo without making sure it is not NULL first.
+
+ * "git worktree", even though it used the default_abbrev setting that
+   ought to be affected by the core.abbrev configuration variable, ignored
+   the variable setting.  The command has been taught to read the
+   default set of configuration variables to correct this.
+
+ * "git init" tried to record core.worktree in the repository's
+   'config' file when the GIT_WORK_TREE environment variable was set and
+   it was different from where GIT_DIR appears as ".git" at its top,
+   but the logic was faulty when .git is a "gitdir:" file that points
+   at the real place, causing trouble in working trees that are
+   managed by "git worktree".  This has been corrected.
+
+ * Codepaths that read from an on-disk loose object were too loose in
+   validating that they are reading a proper object file and
+   sometimes read past the data they read from the disk, which has
+   been corrected.  H/t to Gustavo Grieco for reporting.
+
+ * The original command line syntax for "git merge", which was "git
+   merge <msg> HEAD <parent>...", has been deprecated for quite some
+   time, and "git gui" was the last in-tree user of the syntax.  This
+   is finally fixed, so that we can move forward with the deprecation.
+
+ * An author name that has a backslash-quoted double quote in the
+   human readable part ("My \"double quoted\" name"), was not unquoted
+   correctly while applying a patch from a piece of e-mail.
+
+ * Doc update to clarify what "log -3 --reverse" does.
+
+ * Almost everybody uses DEFAULT_ABBREV to refer to the default
+   setting for the abbreviation, but "git blame" peeked into
+   underlying variable bypassing the macro for no good reason.
+
+ * The "graph" API used in "git log --graph" miscounted the number of
+   output columns consumed so far when drawing a padding line, which
+   has been fixed; this did not affect any existing code as nobody
+   tried to write anything after the padding on such a line, though.
+
+ * The code that parses the format parameter of the for-each-ref command
+   has seen a micro-optimization.
+
+ * When we started to use cURL to talk to an imap server, we forgot to explicitly add
+   imap(s):// before the destination.  To some folks, that didn't work
+   and the library tried to make HTTP(s) requests instead.
+
+ * The ./configure script generated from configure.ac was taught how
+   to detect support of SSL by libcurl better.
+
+ * The command-line completion script (in contrib/) learned to
+   complete "git cmd ^mas<HT>" to complete the negative end of
+   reference to "git cmd ^master".
+   (merge 49416ad22a cp/completion-negative-refs later to maint).
+
+ * The existing "git fetch --depth=<n>" option was hard to use
+   correctly when making the history of an existing shallow clone
+   deeper.  A new option, "--deepen=<n>", has been added to make this
+   easier to use.  "git clone" also learned "--shallow-since=<date>"
+   and "--shallow-exclude=<tag>" options to make it easier to specify
+   "I am interested only in the recent N months worth of history" and
+   "Give me only the history since that version".
+   (merge cccf74e2da nd/shallow-deepen later to maint).
+
+ * "git blame --reverse OLD path" is now DWIMmed to show how lines
+   in path in an old revision OLD have survived up to the current
+   commit.
+   (merge e1d09701a4 jc/blame-reverse later to maint).
+
+ * The http.emptyauth configuration variable is a way to allow an empty username to
+   pass when attempting to authenticate using mechanisms like
+   Kerberos.  We took an unspecified (NULL) username and sent ":"
+   (i.e. no username, no password) to CURLOPT_USERPWD, but did not do
+   the same when the username is explicitly set to an empty string.
+
+ * "git clone" of a local repository can be done at the filesystem
+   level, but the codepath did not check errors while copying and
+   adjusting the file that lists alternate object stores.
+
+ * Documentation for "git commit" was updated to clarify that "commit
+   -p <paths>" adds to the current contents of the index to come up
+   with what to commit.
+
+ * A stray symbolic link in the $GIT_DIR/refs/ directory could make name
+   resolution loop forever, which has been corrected.
+
+ * The "submodule.<name>.path" stored in .gitmodules is never copied
+   to .git/config and such a key in .git/config has no meaning, but
+   the documentation described it next to submodule.<name>.url
+   as if both belong to .git/config.  This has been fixed.
+
+ * In a worktree created via "git
+   worktree", "git checkout" attempts to protect users from confusion
+   by refusing to check out a branch that is already checked out in
+   another worktree.  However, this also prevented checking out a
+   branch which is designated as the primary branch of a bare
+   repository, in a worktree that is connected to the bare
+   repository.  The check has been corrected to allow it.
+
+ * "git rebase" immediately after "git clone" failed to find the fork
+   point from the upstream.
+
+ * When fetching from a remote that has many tags that are irrelevant
+   to branches we are following, we used to waste way too many cycles
+   checking if the object pointed at by a tag (that we are not
+   going to fetch!) exists in our repository too carefully.
+
+ * Protect our code from over-eager compilers.
+
+ * Recent git allows submodule.<name>.branch to use a special token
+   "." instead of the branch name; the documentation has been updated
+   to describe it.
+
+ * "git send-email" attempts to pick up valid e-mails from the
+   trailers, but people in the real world write non-addresses there, like
+   "Cc: Stable <add@xxxxx> # 4.8+", which broke the output depending
+   on the availability and vintage of the Mail::Address perl module.
+   (merge dcfafc5214 mm/send-email-cc-cruft-after-address later to maint).
+
+ * The Travis CI configuration we ship ran the tests with the --verbose
+   option but this risks non-TAP output that happens to be "ok" to be
+   misinterpreted as TAP signalling a test that passed.  This resulted
+   in unnecessary failures.  This has been corrected by introducing a
+   new mode to run our tests in the test harness to send the verbose
+   output separately to the log file.
+
+ * Some AsciiDoc formatters mishandle a displayed illustration with
+   tabs in it.  Adjust a few of them in merge-base documentation to
+   work around them.
+
+ * Fixed a minor regression in "git submodule" that was introduced
+   when more helper functions were reimplemented in C.
+   (merge 77b63ac31e sb/submodule-ignore-trailing-slash later to maint).
+
+ * The code that we have used for the past 10+ years to cycle
+   4-element ring buffers turns out to be not quite portable in
+   theoretical world.
+   (merge bb84735c80 rs/ring-buffer-wraparound later to maint).
+
+ * "git daemon" used fixed-length buffers to turn URLs to the
+   repository the client asked for into the server side directory
+   paths, using snprintf() to avoid overflowing these buffers, but
+   allowed possibly truncated paths to the directory.  This has been
+   tightened to reject such a request that causes an overlong path to be
+   served.
+   (merge 6bdb0083be jk/daemon-path-ok-check-truncation later to maint).
+
+ * Recent update to git-sh-setup (a library of shell functions that
+   are used by our in-tree scripted Porcelain commands) included
+   another shell library git-sh-i18n without specifying where it is,
+   relying on the $PATH.  This has been fixed to be more explicit by
+   prefixing with $(git --exec-path) output.
+   (merge 1073094f30 ak/sh-setup-dot-source-i18n-fix later to maint).
+
+ * Fix for a racy false-positive test failure.
+   (merge fdf4f6c79b as/merge-attr-sleep later to maint).
+
+ * Portability update and workaround for builds on recent Mac OS X.
+   (merge a296bc0132 ls/macos-update later to maint).
+
+ * Using a %(HEAD) placeholder in "for-each-ref --format=" option
+   caused the command to segfault when on an unborn branch.
+   (merge 84679d470d jc/for-each-ref-head-segfault-fix later to maint).
+
+ * "git rebase -i" did not work well with the core.commentchar
+   configuration variable for two reasons, both of which have been
+   fixed.
+   (merge 882cd23777 js/rebase-i-commentchar-fix later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge 5c238e29a8 jk/common-main later to maint).
+   (merge 5a5749e45b ak/pre-receive-hook-template-modefix later to maint).
+   (merge 6d834ac8f1 jk/rebase-config-insn-fmt-docfix later to maint).
+   (merge de9f7fa3b0 rs/commit-pptr-simplify later to maint).
+   (merge 4259d693fc sc/fmt-merge-msg-doc-markup-fix later to maint).
+   (merge 28fab7b23d nd/test-helpers later to maint).
+   (merge c2bb0c1d1e rs/cocci later to maint).
+   (merge 3285b7badb ps/common-info-doc later to maint).
+   (merge 2b090822e8 nd/worktree-lock later to maint).
+   (merge 4bd488ea7c jk/create-branch-remove-unused-param later to maint).
+   (merge 974e0044d6 tk/diffcore-delta-remove-unused later to maint).
diff --git a/Documentation/RelNotes/2.11.1.txt b/Documentation/RelNotes/2.11.1.txt
new file mode 100644
index 0000000000..7d35cf186d
--- /dev/null
+++ b/Documentation/RelNotes/2.11.1.txt
@@ -0,0 +1,168 @@
+Git v2.11.1 Release Notes
+=========================
+
+Fixes since v2.11
+-----------------
+
+ * The default Travis-CI configuration specifies newer P4 and GitLFS.
+
+ * The character width table has been updated to match Unicode 9.0
+
+ * Update the isatty() emulation for Windows by updating the previous
+   hack that depended on internals of (older) MSVC runtime.
+
+ * "git rev-parse --symbolic" failed with a more recent notation like
+   "HEAD^-1" and "HEAD^!".
+
+ * An empty directory in a working tree that can simply be nuked used
+   to interfere while merging or cherry-picking a change to create a
+   submodule directory there, which has been fixed..
+
+ * The code in "git push" to compute if any commit being pushed in the
+   superproject binds a commit in a submodule that hasn't been pushed
+   out was overly inefficient, making it unusable even for a small
+   project that does not have any submodule but have a reasonable
+   number of refs.
+
+ * "git push --dry-run --recurse-submodule=on-demand" wasn't
+   "--dry-run" in the submodules.
+
+ * The output from "git worktree list" was made in readdir() order,
+   and was unstable.
+
+ * mergetool.<tool>.trustExitCode configuration variable did not apply
+   to built-in tools, but now it does.
+
+ * "git p4" LFS support was broken when LFS stores an empty blob.
+
+ * Fix a corner case in merge-recursive regression that crept in
+   during 2.10 development cycle.
+
+ * Update the error messages from the dumb-http client when it fails
+   to obtain loose objects; we used to give sensible error message
+   only upon 404 but we now forbid unexpected redirects that needs to
+   be reported with something sensible.
+
+ * When diff.renames configuration is on (and with Git 2.9 and later,
+   it is enabled by default, which made it worse), "git stash"
+   misbehaved if a file is removed and another file with a very
+   similar content is added.
+
+ * "git diff --no-index" did not take "--no-abbrev" option.
+
+ * "git difftool --dir-diff" had a minor regression when started from
+   a subdirectory, which has been fixed.
+
+ * "git commit --allow-empty --only" (no pathspec) with dirty index
+   ought to be an acceptable way to create a new commit that does not
+   change any paths, but it was forbidden, perhaps because nobody
+   needed it so far.
+
+ * A pathname that begins with "//" or "\\" on Windows is special but
+   path normalization logic was unaware of it.
+
+ * "git pull --rebase", when there is no new commits on our side since
+   we forked from the upstream, should be able to fast-forward without
+   invoking "git rebase", but it didn't.
+
+ * The way to specify hotkeys to "xxdiff" that is used by "git
+   mergetool" has been modernized to match recent versions of xxdiff.
+
+ * Unlike "git am --abort", "git cherry-pick --abort" moved HEAD back
+   to where cherry-pick started while picking multiple changes, when
+   the cherry-pick stopped to ask for help from the user, and the user
+   did "git reset --hard" to a different commit in order to re-attempt
+   the operation.
+
+ * Code cleanup in shallow boundary computation.
+
+ * A recent update to receive-pack to make it easier to drop garbage
+   objects made it clear that GIT_ALTERNATE_OBJECT_DIRECTORIES cannot
+   have a pathname with a colon in it (no surprise!), and this in turn
+   made it impossible to push into a repository at such a path.  This
+   has been fixed by introducing a quoting mechanism used when
+   appending such a path to the colon-separated list.
+
+ * The function usage_msg_opt() has been updated to say "fatal:"
+   before the custom message programs give, when they want to die
+   with a message about wrong command line options followed by the
+   standard usage string.
+
+ * "git index-pack --stdin" needs an access to an existing repository,
+   but "git index-pack file.pack" to generate an .idx file that
+   corresponds to a packfile does not.
+
+ * Fix for NDEBUG builds.
+
+ * A lazy "git push" without refspec did not internally use a fully
+   specified refspec to perform 'current', 'simple', or 'upstream'
+   push, causing unnecessary "ambiguous ref" errors.
+
+ * "git p4" misbehaved when swapping a directory and a symbolic link.
+
+ * Even though an fix was attempted in Git 2.9.3 days, but running
+   "git difftool --dir-diff" from a subdirectory never worked. This
+   has been fixed.
+
+ * "git p4" that tracks multiple p4 paths imported a single changelist
+   that touches files in these multiple paths as one commit, followed
+   by many empty commits.  This has been fixed.
+
+ * A potential but unlikely buffer overflow in Windows port has been
+   fixed.
+
+ * When the http server gives an incomplete response to a smart-http
+   rpc call, it could lead to client waiting for a full response that
+   will never come.  Teach the client side to notice this condition
+   and abort the transfer.
+
+ * Some platforms no longer understand "latin-1" that is still seen in
+   the wild in e-mail headers; replace them with "iso-8859-1" that is
+   more widely known when conversion fails from/to it.
+
+ * Update the procedure to generate "tags" for developer support.
+
+ * Update the definition of the MacOSX test environment used by
+   TravisCI.
+
+ * A few git-svn updates.
+
+ * Compression setting for producing packfiles were spread across
+   three codepaths, one of which did not honor any configuration.
+   Unify these so that all of them honor core.compression and
+   pack.compression variables the same way.
+
+ * "git fast-import" sometimes mishandled while rebalancing notes
+   tree, which has been fixed.
+
+ * Recent update to the default abbreviation length that auto-scales
+   lacked documentation update, which has been corrected.
+
+ * Leakage of lockfiles in the config subsystem has been fixed.
+
+ * It is natural that "git gc --auto" may not attempt to pack
+   everything into a single pack, and there is no point in warning
+   when the user has configured the system to use the pack bitmap,
+   leading to disabling further "gc".
+
+ * "git archive" did not read the standard configuration files, and
+   failed to notice a file that is marked as binary via the userdiff
+   driver configuration.
+
+ * "git blame --porcelain" misidentified the "previous" <commit, path>
+   pair (aka "source") when contents came from two or more files.
+
+ * "git rebase -i" with a recent update started showing an incorrect
+   count when squashing more than 10 commits.
+
+ * "git <cmd> @{push}" on a detached HEAD used to segfault; it has
+   been corrected to error out with a message.
+
+ * Tighten a test to avoid mistaking an extended ERE regexp engine as
+   a PRE regexp engine.
+
+ * Typing ^C to pager, which usually does not kill it, killed Git and
+   took the pager down as a collateral damage in certain process-tree
+   structure.  This has been fixed.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.11.2.txt b/Documentation/RelNotes/2.11.2.txt
new file mode 100644
index 0000000000..7428851168
--- /dev/null
+++ b/Documentation/RelNotes/2.11.2.txt
@@ -0,0 +1,12 @@
+Git v2.11.2 Release Notes
+=========================
+
+Fixes since v2.11.1
+-------------------
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
diff --git a/Documentation/RelNotes/2.11.3.txt b/Documentation/RelNotes/2.11.3.txt
new file mode 100644
index 0000000000..4e3b78d0e8
--- /dev/null
+++ b/Documentation/RelNotes/2.11.3.txt
@@ -0,0 +1,4 @@
+Git v2.11.3 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.11.4.txt b/Documentation/RelNotes/2.11.4.txt
new file mode 100644
index 0000000000..ad4da8eb09
--- /dev/null
+++ b/Documentation/RelNotes/2.11.4.txt
@@ -0,0 +1,17 @@
+Git v2.11.4 Release Notes
+=========================
+
+Fixes since v2.11.3
+-------------------
+
+ * "git cvsserver" no longer is invoked by "git daemon" by default,
+   as it is old and largely unmaintained.
+
+ * Various Perl scripts did not use safe_pipe_capture() instead of
+   backticks, leaving them susceptible to end-user input.  They have
+   been corrected.
+
+Credits go to joernchen <joernchen@xxxxxxxxxxxx> for finding the
+unsafe constructs in "git cvsserver", and to Jeff King at GitHub for
+finding and fixing instances of the same issue in other scripts.
+
diff --git a/Documentation/RelNotes/2.12.0.txt b/Documentation/RelNotes/2.12.0.txt
new file mode 100644
index 0000000000..d2f6a83614
--- /dev/null
+++ b/Documentation/RelNotes/2.12.0.txt
@@ -0,0 +1,500 @@
+Git 2.12 Release Notes
+======================
+
+Backward compatibility notes.
+
+ * Use of an empty string that is used for 'everything matches' is
+   still warned and Git asks users to use a more explicit '.' for that
+   instead.  The hope is that existing users will not mind this
+   change, and eventually the warning can be turned into a hard error,
+   upgrading the deprecation into removal of this (mis)feature.  That
+   is not scheduled to happen in the upcoming release (yet).
+
+ * The historical argument order "git merge <msg> HEAD <commit>..."
+   has been deprecated for quite some time, and will be removed in a
+   future release.
+
+ * An ancient script "git relink" has been removed.
+
+
+Updates since v2.11
+-------------------
+
+UI, Workflows & Features
+
+ * Various updates to "git p4".
+
+ * "git p4" didn't interact with the internal of .git directory
+   correctly in the modern "git-worktree"-enabled world.
+
+ * "git branch --list" and friends learned "--ignore-case" option to
+   optionally sort branches and tags case insensitively.
+
+ * In addition to %(subject), %(body), "log --pretty=format:..."
+   learned a new placeholder %(trailers).
+
+ * "git rebase" learned "--quit" option, which allows a user to
+   remove the metadata left by an earlier "git rebase" that was
+   manually aborted without using "git rebase --abort".
+
+ * "git clone --reference $there --recurse-submodules $super" has been
+   taught to guess repositories usable as references for submodules of
+   $super that are embedded in $there while making a clone of the
+   superproject borrow objects from $there; extend the mechanism to
+   also allow submodules of these submodules to borrow repositories
+   embedded in these clones of the submodules embedded in the clone of
+   the superproject.
+
+ * Porcelain scripts written in Perl are getting internationalized.
+
+ * "git merge --continue" has been added as a synonym to "git commit"
+   to conclude a merge that has stopped due to conflicts.
+
+ * Finer-grained control of what protocols are allowed for transports
+   during clone/fetch/push have been enabled via a new configuration
+   mechanism.
+
+ * "git shortlog" learned "--committer" option to group commits by
+   committer, instead of author.
+
+ * GitLFS integration with "git p4" has been updated.
+
+ * The isatty() emulation for Windows has been updated to eradicate
+   the previous hack that depended on internals of (older) MSVC
+   runtime.
+
+ * Some platforms no longer understand "latin-1" that is still seen in
+   the wild in e-mail headers; replace them with "iso-8859-1" that is
+   more widely known when conversion fails from/to it.
+
+ * "git grep" has been taught to optionally recurse into submodules.
+
+ * "git rm" used to refuse to remove a submodule when it has its own
+   git repository embedded in its working tree.  It learned to move
+   the repository away to $GIT_DIR/modules/ of the superproject
+   instead, and allow the submodule to be deleted (as long as there
+   will be no loss of local modifications, that is).
+
+ * A recent updates to "git p4" was not usable for older p4 but it
+   could be made to work with minimum changes.  Do so.
+
+ * "git diff" learned diff.interHunkContext configuration variable
+   that gives the default value for its --inter-hunk-context option.
+
+ * The prereleaseSuffix feature of version comparison that is used in
+   "git tag -l" did not correctly when two or more prereleases for the
+   same release were present (e.g. when 2.0, 2.0-beta1, and 2.0-beta2
+   are there and the code needs to compare 2.0-beta1 and 2.0-beta2).
+
+ * "git submodule push" learned "--recurse-submodules=only option to
+   push submodules out without pushing the top-level superproject.
+
+ * "git tag" and "git verify-tag" learned to put GPG verification
+   status in their "--format=<placeholders>" output format.
+
+ * An ancient repository conversion tool left in contrib/ has been
+   removed.
+
+ * "git show-ref HEAD" used with "--verify" because the user is not
+   interested in seeing refs/remotes/origin/HEAD, and used with
+   "--head" because the user does not want HEAD to be filtered out,
+   i.e. "git show-ref --head --verify HEAD", did not work as expected.
+
+ * "git submodule add" used to be confused and refused to add a
+   locally created repository; users can now use "--force" option
+   to add them.
+   (merge 619acfc78c sb/submodule-add-force later to maint).
+
+ * Some people feel the default set of colors used by "git log --graph"
+   rather limiting.  A mechanism to customize the set of colors has
+   been introduced.
+
+ * "git read-tree" and its underlying unpack_trees() machinery learned
+   to report problematic paths prefixed with the --super-prefix option.
+
+ * When a submodule "A", which has another submodule "B" nested within
+   it, is "absorbed" into the top-level superproject, the inner
+   submodule "B" used to be left in a strange state.  The logic to
+   adjust the .git pointers in these submodules has been corrected.
+
+ * The user can specify a custom update method that is run when
+   "submodule update" updates an already checked out submodule.  This
+   was ignored when checking the submodule out for the first time and
+   we instead always just checked out the commit that is bound to the
+   path in the superproject's index.
+
+ * The command line completion (in contrib/) learned that
+   "git diff --submodule=" can take "diff" as a recently added option.
+
+ * The "core.logAllRefUpdates" that used to be boolean has been
+   enhanced to take 'always' as well, to record ref updates to refs
+   other than the ones that are expected to be updated (i.e. branches,
+   remote-tracking branches and notes).
+
+ * Comes with more command line completion (in contrib/) for recently
+   introduced options.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Commands that operate on a log message and add lines to the trailer
+   blocks, such as "format-patch -s", "cherry-pick (-x|-s)", and
+   "commit -s", have been taught to use the logic of and share the
+   code with "git interpret-trailer".
+
+ * The default Travis-CI configuration specifies newer P4 and GitLFS.
+
+ * The "fast hash" that had disastrous performance issues in some
+   corner cases has been retired from the internal diff.
+
+ * The character width table has been updated to match Unicode 9.0
+
+ * Update the procedure to generate "tags" for developer support.
+
+ * The codeflow of setting NOATIME and CLOEXEC on file descriptors Git
+   opens has been simplified.
+
+ * "git diff" and its family had two experimental heuristics to shift
+   the contents of a hunk to make the patch easier to read.  One of
+   them turns out to be better than the other, so leave only the
+   "--indent-heuristic" option and remove the other one.
+
+ * A new submodule helper "git submodule embedgitdirs" to make it
+   easier to move embedded .git/ directory for submodules in a
+   superproject to .git/modules/ (and point the latter with the former
+   that is turned into a "gitdir:" file) has been added.
+
+ * "git push \\server\share\dir" has recently regressed and then
+   fixed.  A test has retroactively been added for this breakage.
+
+ * Build updates for Cygwin.
+
+ * The implementation of "real_path()" was to go there with chdir(2)
+   and call getcwd(3), but this obviously wouldn't be usable in a
+   threaded environment.  Rewrite it to manually resolve relative
+   paths including symbolic links in path components.
+
+ * Adjust documentation to help AsciiDoctor render better while not
+   breaking the rendering done by AsciiDoc.
+
+ * The sequencer machinery has been further enhanced so that a later
+   set of patches can start using it to reimplement "rebase -i".
+
+ * Update the definition of the MacOSX test environment used by
+   TravisCI.
+
+ * Rewrite a scripted porcelain "git difftool" in C.
+
+ * "make -C t failed" will now run only the tests that failed in the
+   previous run.  This is usable only when prove is not use, and gives
+   a useless error message when run after "make clean", but otherwise
+   is serviceable.
+
+ * "uchar [40]" to "struct object_id" conversion continues.
+
+
+Also contains various documentation updates and code clean-ups.
+
+Fixes since v2.10
+-----------------
+
+Unless otherwise noted, all the fixes since v2.9 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * We often decide if a session is interactive by checking if the
+   standard I/O streams are connected to a TTY, but isatty() that
+   comes with Windows incorrectly returned true if it is used on NUL
+   (i.e. an equivalent to /dev/null).  This has been fixed.
+
+ * "git svn" did not work well with path components that are "0", and
+   some configuration variable it uses were not documented.
+
+ * "git rev-parse --symbolic" failed with a more recent notation like
+   "HEAD^-1" and "HEAD^!".
+
+ * An empty directory in a working tree that can simply be nuked used
+   to interfere while merging or cherry-picking a change to create a
+   submodule directory there, which has been fixed..
+
+ * The code in "git push" to compute if any commit being pushed in the
+   superproject binds a commit in a submodule that hasn't been pushed
+   out was overly inefficient, making it unusable even for a small
+   project that does not have any submodule but have a reasonable
+   number of refs.
+
+ * "git push --dry-run --recurse-submodule=on-demand" wasn't
+   "--dry-run" in the submodules.
+
+ * The output from "git worktree list" was made in readdir() order,
+   and was unstable.
+
+ * mergetool.<tool>.trustExitCode configuration variable did not apply
+   to built-in tools, but now it does.
+
+ * "git p4" LFS support was broken when LFS stores an empty blob.
+
+ * A corner case in merge-recursive regression that crept in
+   during 2.10 development cycle has been fixed.
+
+ * Transport with dumb http can be fooled into following foreign URLs
+   that the end user does not intend to, especially with the server
+   side redirects and http-alternates mechanism, which can lead to
+   security issues.  Tighten the redirection and make it more obvious
+   to the end user when it happens.
+
+ * Update the error messages from the dumb-http client when it fails
+   to obtain loose objects; we used to give sensible error message
+   only upon 404 but we now forbid unexpected redirects that needs to
+   be reported with something sensible.
+
+ * When diff.renames configuration is on (and with Git 2.9 and later,
+   it is enabled by default, which made it worse), "git stash"
+   misbehaved if a file is removed and another file with a very
+   similar content is added.
+
+ * "git diff --no-index" did not take "--no-abbrev" option.
+
+ * "git difftool --dir-diff" had a minor regression when started from
+   a subdirectory, which has been fixed.
+
+ * "git commit --allow-empty --only" (no pathspec) with dirty index
+   ought to be an acceptable way to create a new commit that does not
+   change any paths, but it was forbidden, perhaps because nobody
+   needed it so far.
+
+ * Git 2.11 had a minor regression in "merge --ff-only" that competed
+   with another process that simultaneously attempted to update the
+   index. We used to explain what went wrong with an error message,
+   but the new code silently failed.  The error message has been
+   resurrected.
+
+ * A pathname that begins with "//" or "\\" on Windows is special but
+   path normalization logic was unaware of it.
+
+ * "git pull --rebase", when there is no new commits on our side since
+   we forked from the upstream, should be able to fast-forward without
+   invoking "git rebase", but it didn't.
+
+ * The way to specify hotkeys to "xxdiff" that is used by "git
+   mergetool" has been modernized to match recent versions of xxdiff.
+
+ * Unlike "git am --abort", "git cherry-pick --abort" moved HEAD back
+   to where cherry-pick started while picking multiple changes, when
+   the cherry-pick stopped to ask for help from the user, and the user
+   did "git reset --hard" to a different commit in order to re-attempt
+   the operation.
+
+ * Code cleanup in shallow boundary computation.
+
+ * A recent update to receive-pack to make it easier to drop garbage
+   objects made it clear that GIT_ALTERNATE_OBJECT_DIRECTORIES cannot
+   have a pathname with a colon in it (no surprise!), and this in turn
+   made it impossible to push into a repository at such a path.  This
+   has been fixed by introducing a quoting mechanism used when
+   appending such a path to the colon-separated list.
+
+ * The function usage_msg_opt() has been updated to say "fatal:"
+   before the custom message programs give, when they want to die
+   with a message about wrong command line options followed by the
+   standard usage string.
+
+ * "git index-pack --stdin" needs an access to an existing repository,
+   but "git index-pack file.pack" to generate an .idx file that
+   corresponds to a packfile does not.
+
+ * Fix for NDEBUG builds.
+
+ * A lazy "git push" without refspec did not internally use a fully
+   specified refspec to perform 'current', 'simple', or 'upstream'
+   push, causing unnecessary "ambiguous ref" errors.
+
+ * "git p4" misbehaved when swapping a directory and a symbolic link.
+
+ * Even though an fix was attempted in Git 2.9.3 days, but running
+   "git difftool --dir-diff" from a subdirectory never worked. This
+   has been fixed.
+
+ * "git p4" that tracks multiple p4 paths imported a single changelist
+   that touches files in these multiple paths as one commit, followed
+   by many empty commits.  This has been fixed.
+
+ * A potential but unlikely buffer overflow in Windows port has been
+   fixed.
+
+ * When the http server gives an incomplete response to a smart-http
+   rpc call, it could lead to client waiting for a full response that
+   will never come.  Teach the client side to notice this condition
+   and abort the transfer.
+
+ * Compression setting for producing packfiles were spread across
+   three codepaths, one of which did not honor any configuration.
+   Unify these so that all of them honor core.compression and
+   pack.compression variables the same way.
+
+ * "git fast-import" sometimes mishandled while rebalancing notes
+   tree, which has been fixed.
+
+ * Recent update to the default abbreviation length that auto-scales
+   lacked documentation update, which has been corrected.
+
+ * Leakage of lockfiles in the config subsystem has been fixed.
+
+ * It is natural that "git gc --auto" may not attempt to pack
+   everything into a single pack, and there is no point in warning
+   when the user has configured the system to use the pack bitmap,
+   leading to disabling further "gc".
+
+ * "git archive" did not read the standard configuration files, and
+   failed to notice a file that is marked as binary via the userdiff
+   driver configuration.
+
+ * "git blame --porcelain" misidentified the "previous" <commit, path>
+   pair (aka "source") when contents came from two or more files.
+
+ * "git rebase -i" with a recent update started showing an incorrect
+   count when squashing more than 10 commits.
+
+ * "git <cmd> @{push}" on a detached HEAD used to segfault; it has
+   been corrected to error out with a message.
+
+ * Running "git add a/b" when "a" is a submodule correctly errored
+   out, but without a meaningful error message.
+   (merge 2d81c48fa7 sb/pathspec-errors later to maint).
+
+ * Typing ^C to pager, which usually does not kill it, killed Git and
+   took the pager down as a collateral damage in certain process-tree
+   structure.  This has been fixed.
+
+ * "git mergetool" without any pathspec on the command line that is
+   run from a subdirectory became no-op in Git v2.11 by mistake, which
+   has been fixed.
+
+ * Retire long unused/unmaintained gitview from the contrib/ area.
+   (merge 3120925c25 sb/remove-gitview later to maint).
+
+ * Tighten a test to avoid mistaking an extended ERE regexp engine as
+   a PRE regexp engine.
+
+ * An error message with an ASCII control character like '\r' in it
+   can alter the message to hide its early part, which is problematic
+   when a remote side gives such an error message that the local side
+   will relay with a "remote: " prefix.
+   (merge f290089879 jk/vreport-sanitize later to maint).
+
+ * "git fsck" inspects loose objects more carefully now.
+   (merge cce044df7f jk/loose-object-fsck later to maint).
+
+ * A crashing bug introduced in v2.11 timeframe has been found (it is
+   triggerable only in fast-import) and fixed.
+   (merge abd5a00268 jk/clear-delta-base-cache-fix later to maint).
+
+ * With an anticipatory tweak for remotes defined in ~/.gitconfig
+   (e.g. "remote.origin.prune" set to true, even though there may or
+   may not actually be "origin" remote defined in a particular Git
+   repository), "git remote rename" and other commands misinterpreted
+   and behaved as if such a non-existing remote actually existed.
+   (merge e459b073fb js/remote-rename-with-half-configured-remote later to maint).
+
+ * A few codepaths had to rely on a global variable when sorting
+   elements of an array because sort(3) API does not allow extra data
+   to be passed to the comparison function.  Use qsort_s() when
+   natively available, and a fallback implementation of it when not,
+   to eliminate the need, which is a prerequisite for making the
+   codepath reentrant.
+
+ * "git fsck --connectivity-check" was not working at all.
+   (merge a2b22854bd jk/fsck-connectivity-check-fix later to maint).
+
+ * After starting "git rebase -i", which first opens the user's editor
+   to edit the series of patches to apply, but before saving the
+   contents of that file, "git status" failed to show the current
+   state (i.e. you are in an interactive rebase session, but you have
+   applied no steps yet) correctly.
+   (merge df9ded4984 js/status-pre-rebase-i later to maint).
+
+ * Test tweak for FreeBSD where /usr/bin/unzip is unsuitable to run
+   our tests but /usr/local/bin/unzip is usable.
+   (merge d98b2c5fce js/unzip-in-usr-bin-workaround later to maint).
+
+ * "git p4" did not work well with multiple git-p4.mapUser entries on
+   Windows.
+   (merge c3c2b05776 gv/mingw-p4-mapuser later to maint).
+
+ * "git help" enumerates executable files in $PATH; the implementation
+   of "is this file executable?" on Windows has been optimized.
+   (merge c755015f79 hv/mingw-help-is-executable later to maint).
+
+ * Test tweaks for those who have default ACL in their git source tree
+   that interfere with the umask test.
+   (merge d549d21307 mm/reset-facl-before-umask-test later to maint).
+
+ * Names of the various hook scripts must be spelled exactly, but on
+   Windows, an .exe binary must be named with .exe suffix; notice
+   $GIT_DIR/hooks/<hookname>.exe as a valid <hookname> hook.
+   (merge 235be51fbe js/mingw-hooks-with-exe-suffix later to maint).
+
+ * Asciidoctor, an alternative reimplementation of AsciiDoc, still
+   needs some changes to work with documents meant to be formatted
+   with AsciiDoc.  "make USE_ASCIIDOCTOR=YesPlease" to use it out of
+   the box to document our pages is getting closer to reality.
+
+ * Correct command line completion (in contrib/) on "git svn"
+   (merge 2cbad17642 ew/complete-svn-authorship-options later to maint).
+
+ * Incorrect usage help message for "git worktree prune" has been fixed.
+   (merge 2488dcab22 ps/worktree-prune-help-fix later to maint).
+
+ * Adjust a perf test to new world order where commands that do
+   require a repository are really strict about having a repository.
+   (merge c86000c1a7 rs/p5302-create-repositories-before-tests later to maint).
+
+ * "git log --graph" did not work well with "--name-only", even though
+   other forms of "diff" output were handled correctly.
+   (merge f5022b5fed jk/log-graph-name-only later to maint).
+
+ * The push-options given via the "--push-options" option were not
+   passed through to external remote helpers such as "smart HTTP" that
+   are invoked via the transport helper.
+
+ * The documentation explained what "git stash" does to the working
+   tree (after stashing away the local changes) in terms of "reset
+   --hard", which was exposing an unnecessary implementation detail.
+   (merge 20a7e06172 tg/stash-doc-cleanup later to maint).
+
+ * When "git p4" imports changelist that removes paths, it failed to
+   convert pathnames when the p4 used encoding different from the one
+   used on the Git side.  This has been corrected.
+   (merge a8b05162e8 ls/p4-path-encoding later to maint).
+
+ * A new coccinelle rule that catches a check of !pointer before the
+   pointer is free(3)d, which most likely is a bug.
+   (merge ec6cd14c7a rs/cocci-check-free-only-null later to maint).
+
+ * "ls-files" run with pathspec has been micro-optimized to avoid
+   having to memmove(3) unnecessary bytes.
+   (merge 96f6d3f61a rs/ls-files-partial-optim later to maint).
+
+ * A hotfix for a topic already in 'master'.
+   (merge a4d92d579f js/mingw-isatty later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge f2627d9b19 sb/submodule-config-cleanup later to maint).
+   (merge 384f1a167b sb/unpack-trees-cleanup later to maint).
+   (merge 874444b704 rh/diff-orderfile-doc later to maint).
+   (merge eafd5d9483 cw/doc-sign-off later to maint).
+   (merge 0aaad415bc rs/absolute-pathdup later to maint).
+   (merge 4432dd6b5b rs/receive-pack-cleanup later to maint).
+   (merge 540a398e9c sg/mailmap-self later to maint).
+   (merge 209df269a6 nd/rev-list-all-includes-HEAD-doc later to maint).
+   (merge 941b9c5270 sb/doc-unify-bottom later to maint).
+   (merge 2aaf37b62c jk/doc-remote-helpers-markup-fix later to maint).
+   (merge e91461b332 jk/doc-submodule-markup-fix later to maint).
+   (merge 8ab9740d9f dp/submodule-doc-markup-fix later to maint).
+   (merge 0838cbc22f jk/tempfile-ferror-fclose-confusion later to maint).
+   (merge 115a40add6 dr/doc-check-ref-format-normalize later to maint).
+   (merge 133f0a299d gp/document-dotfiles-in-templates-are-not-copied later to maint).
+   (merge 2b35a9f4c7 bc/blame-doc-fix later to maint).
+   (merge 7e82388024 ps/doc-gc-aggressive-depth-update later to maint).
+   (merge 9993a7c5f1 bc/worktree-doc-fix-detached later to maint).
+   (merge e519eccdf4 rt/align-add-i-help-text later to maint).
diff --git a/Documentation/RelNotes/2.12.1.txt b/Documentation/RelNotes/2.12.1.txt
new file mode 100644
index 0000000000..a74f7db747
--- /dev/null
+++ b/Documentation/RelNotes/2.12.1.txt
@@ -0,0 +1,41 @@
+Git v2.12.1 Release Notes
+=========================
+
+Fixes since v2.12
+-----------------
+
+ * Reduce authentication round-trip over HTTP when the server supports
+   just a single authentication method.  This also improves the
+   behaviour when Git is misconfigured to enable http.emptyAuth
+   against a server that does not authenticate without a username
+   (i.e. not using Kerberos etc., which makes http.emptyAuth
+   pointless).
+
+ * Windows port wants to use OpenSSL's implementation of SHA-1
+   routines, so let them.
+
+ * Add 32-bit Linux variant to the set of platforms to be tested with
+   Travis CI.
+
+ * When a redirected http transport gets an error during the
+   redirected request, we ignored the error we got from the server,
+   and ended up giving a not-so-useful error message.
+
+ * The patch subcommand of "git add -i" was meant to have paths
+   selection prompt just like other subcommand, unlike "git add -p"
+   directly jumps to hunk selection.  Recently, this was broken and
+   "add -i" lost the paths selection dialog, but it now has been
+   fixed.
+
+ * Git v2.12 was shipped with an embarrassing breakage where various
+   operations that verify paths given from the user stopped dying when
+   seeing an issue, and instead later triggering segfault.
+
+ * The code to parse "git log -L..." command line was buggy when there
+   are many ranges specified with -L; overrun of the allocated buffer
+   has been fixed.
+
+ * The command-line parsing of "git log -L" copied internal data
+   structures using incorrect size on ILP32 systems.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.12.2.txt b/Documentation/RelNotes/2.12.2.txt
new file mode 100644
index 0000000000..441939709c
--- /dev/null
+++ b/Documentation/RelNotes/2.12.2.txt
@@ -0,0 +1,83 @@
+Git v2.12.2 Release Notes
+=========================
+
+Fixes since v2.12.1
+-------------------
+
+ * "git status --porcelain" is supposed to give a stable output, but a
+   few strings were left as translatable by mistake.
+
+ * "Dumb http" transport used to misparse a nonsense http-alternates
+   response, which has been fixed.
+
+ * "git diff --quiet" relies on the size field in diff_filespec to be
+   correctly populated, but diff_populate_filespec() helper function
+   made an incorrect short-cut when asked only to populate the size
+   field for paths that need to go through convert_to_git() (e.g. CRLF
+   conversion).
+
+ * There is no need for Python only to give a few messages to the
+   standard error stream, but we somehow did.
+
+ * A leak in a codepath to read from a packed object in (rare) cases
+   has been plugged.
+
+ * "git upload-pack", which is a counter-part of "git fetch", did not
+   report a request for a ref that was not advertised as invalid.
+   This is generally not a problem (because "git fetch" will stop
+   before making such a request), but is the right thing to do.
+
+ * A "gc.log" file left by a backgrounded "gc --auto" disables further
+   automatic gc; it has been taught to run at least once a day (by
+   default) by ignoring a stale "gc.log" file that is too old.
+
+ * "git remote rm X", when a branch has remote X configured as the
+   value of its branch.*.remote, tried to remove branch.*.remote and
+   branch.*.merge and failed if either is unset.
+
+ * A caller of tempfile API that uses stdio interface to write to
+   files may ignore errors while writing, which is detected when
+   tempfile is closed (with a call to ferror()).  By that time, the
+   original errno that may have told us what went wrong is likely to
+   be long gone and was overwritten by an irrelevant value.
+   close_tempfile() now resets errno to EIO to make errno at least
+   predictable.
+
+ * "git show-branch" expected there were only very short branch names
+   in the repository and used a fixed-length buffer to hold them
+   without checking for overflow.
+
+ * The code that parses header fields in the commit object has been
+   updated for (micro)performance and code hygiene.
+
+ * A test that creates a confusing branch whose name is HEAD has been
+   corrected not to do so.
+
+ * "Cc:" on the trailer part does not have to conform to RFC strictly,
+   unlike in the e-mail header.  "git send-email" has been updated to
+   ignore anything after '>' when picking addresses, to allow non-address
+   cruft like " # stable 4.4" after the address.
+
+ * "git push" had a handful of codepaths that could lead to a deadlock
+   when unexpected error happened, which has been fixed.
+
+ * Code to read submodule.<name>.ignore config did not state the
+   variable name correctly when giving an error message diagnosing
+   misconfiguration.
+
+ * "git ls-remote" and "git archive --remote" are designed to work
+   without being in a directory under Git's control.  However, recent
+   updates revealed that we randomly look into a directory called
+   .git/ without actually doing necessary set-up when working in a
+   repository.  Stop doing so.
+
+ * The code to parse the command line "git grep <patterns>... <rev>
+   [[--] <pathspec>...]" has been cleaned up, and a handful of bugs
+   have been fixed (e.g. we used to check "--" if it is a rev).
+
+ * The code to parse "git -c VAR=VAL cmd" and set configuration
+   variable for the duration of cmd had two small bugs, which have
+   been fixed.
+   This supersedes jc/config-case-cmdline topic that has been discarded.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.12.3.txt b/Documentation/RelNotes/2.12.3.txt
new file mode 100644
index 0000000000..ebca846d5d
--- /dev/null
+++ b/Documentation/RelNotes/2.12.3.txt
@@ -0,0 +1,64 @@
+Git v2.12.3 Release Notes
+=========================
+
+Fixes since v2.12.2
+-------------------
+
+ * The "parse_config_key()" API function has been cleaned up.
+
+ * An helper function to make it easier to append the result from
+   real_path() to a strbuf has been added.
+
+ * The t/perf performance test suite was not prepared to test not so
+   old versions of Git, but now it covers versions of Git that are not
+   so ancient.
+
+ * Picking two versions of Git and running tests to make sure the
+   older one and the newer one interoperate happily has now become
+   possible.
+
+ * Teach the "debug" helper used in the test framework that allows a
+   command to run under "gdb" to make the session interactive.
+
+ * "git repack --depth=<n>" for a long time busted the specified depth
+   when reusing delta from existing packs.  This has been corrected.
+
+ * user.email that consists of only cruft chars should consistently
+   error out, but didn't.
+
+ * A few tests were run conditionally under (rare) conditions where
+   they cannot be run (like running cvs tests under 'root' account).
+
+ * "git branch @" created refs/heads/@ as a branch, and in general the
+   code that handled @{-1} and @{upstream} was a bit too loose in
+   disambiguating.
+
+ * "git fetch" that requests a commit by object name, when the other
+   side does not allow such an request, failed without much
+   explanation.
+
+ * "git filter-branch --prune-empty" drops a single-parent commit that
+   becomes a no-op, but did not drop a root commit whose tree is empty.
+
+ * Recent versions of Git treats http alternates (used in dumb http
+   transport) just like HTTP redirects and requires the client to
+   enable following it, due to security concerns.  But we forgot to
+   give a warning when we decide not to honor the alternates.
+
+ * NO_PTHREADS build has been broken for some time; now fixed.
+
+ * Fix for potential segv introduced in v2.11.0 and later (also
+   v2.10.2).
+
+ * A few unterminated here documents in tests were fixed, which in
+   turn revealed incorrect expectations the tests make. These tests
+   have been updated.
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.12.4.txt b/Documentation/RelNotes/2.12.4.txt
new file mode 100644
index 0000000000..3f56938221
--- /dev/null
+++ b/Documentation/RelNotes/2.12.4.txt
@@ -0,0 +1,4 @@
+Git v2.12.4 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.12.5.txt b/Documentation/RelNotes/2.12.5.txt
new file mode 100644
index 0000000000..8fa73cfce7
--- /dev/null
+++ b/Documentation/RelNotes/2.12.5.txt
@@ -0,0 +1,17 @@
+Git v2.12.5 Release Notes
+=========================
+
+Fixes since v2.12.4
+-------------------
+
+ * "git cvsserver" no longer is invoked by "git daemon" by default,
+   as it is old and largely unmaintained.
+
+ * Various Perl scripts did not use safe_pipe_capture() instead of
+   backticks, leaving them susceptible to end-user input.  They have
+   been corrected.
+
+Credits go to joernchen <joernchen@xxxxxxxxxxxx> for finding the
+unsafe constructs in "git cvsserver", and to Jeff King at GitHub for
+finding and fixing instances of the same issue in other scripts.
+
diff --git a/Documentation/RelNotes/2.13.0.txt b/Documentation/RelNotes/2.13.0.txt
new file mode 100644
index 0000000000..2a47b4cb0c
--- /dev/null
+++ b/Documentation/RelNotes/2.13.0.txt
@@ -0,0 +1,618 @@
+Git 2.13 Release Notes
+======================
+
+Backward compatibility notes.
+
+ * Use of an empty string as a pathspec element that is used for
+   'everything matches' is still warned and Git asks users to use a
+   more explicit '.' for that instead.  The hope is that existing
+   users will not mind this change, and eventually the warning can be
+   turned into a hard error, upgrading the deprecation into removal of
+   this (mis)feature.  That is not scheduled to happen in the upcoming
+   release (yet).
+
+ * The historical argument order "git merge <msg> HEAD <commit>..."
+   has been deprecated for quite some time, and is now removed.
+
+ * The default location "~/.git-credential-cache/socket" for the
+   socket used to communicate with the credential-cache daemon has
+   been moved to "~/.cache/git/credential/socket".
+
+ * Git now avoids blindly falling back to ".git" when the setup
+   sequence said we are _not_ in Git repository.  A corner case that
+   happens to work right now may be broken by a call to die("BUG").
+   We've tried hard to locate such cases and fixed them, but there
+   might still be cases that need to be addressed--bug reports are
+   greatly appreciated.
+
+
+Updates since v2.12
+-------------------
+
+UI, Workflows & Features
+
+ * "git describe" and "git name-rev" have been taught to take more
+   than one refname patterns to restrict the set of refs to base their
+   naming output on, and also learned to take negative patterns to
+   name refs not to be used for naming via their "--exclude" option.
+
+ * Deletion of a branch "foo/bar" could remove .git/refs/heads/foo
+   once there no longer is any other branch whose name begins with
+   "foo/", but we didn't do so so far.  Now we do.
+
+ * When "git merge" detects a path that is renamed in one history
+   while the other history deleted (or modified) it, it now reports
+   both paths to help the user understand what is going on in the two
+   histories being merged.
+
+ * The <url> part in "http.<url>.<variable>" configuration variable
+   can now be spelled with '*' that serves as wildcard.
+   E.g. "http.https://*.example.com.proxy"; can be used to specify the
+   proxy used for https://a.example.com, https://b.example.com, etc.,
+   i.e. any host in the example.com domain.
+
+ * "git tag" did not leave useful message when adding a new entry to
+   reflog; this was left unnoticed for a long time because refs/tags/*
+   doesn't keep reflog by default.
+
+ * The "negative" pathspec feature was somewhat more cumbersome to use
+   than necessary in that its short-hand used "!" which needed to be
+   escaped from shells, and it required "exclude from what?" specified.
+
+ * The command line options for ssh invocation needs to be tweaked for
+   some implementations of SSH (e.g. PuTTY plink wants "-P <port>"
+   while OpenSSH wants "-p <port>" to specify port to connect to), and
+   the variant was guessed when GIT_SSH environment variable is used
+   to specify it.  The logic to guess now applies to the command
+   specified by the newer GIT_SSH_COMMAND and also core.sshcommand
+   configuration variable, and comes with an escape hatch for users to
+   deal with misdetected cases.
+
+ * The "--git-path", "--git-common-dir", and "--shared-index-path"
+   options of "git rev-parse" did not produce usable output.  They are
+   now updated to show the path to the correct file, relative to where
+   the caller is.
+
+ * "git diff -W" has been taught to handle the case where a new
+   function is added at the end of the file better.
+
+ * "git update-ref -d" and other operations to delete references did
+   not leave any entry in HEAD's reflog when the reference being
+   deleted was the current branch.  This is not a problem in practice
+   because you do not want to delete the branch you are currently on,
+   but caused renaming of the current branch to something else not to
+   be logged in a useful way.
+
+ * "Cc:" on the trailer part does not have to conform to RFC strictly,
+   unlike in the e-mail header.  "git send-email" has been updated to
+   ignore anything after '>' when picking addresses, to allow non-address
+   cruft like " # stable 4.4" after the address.
+
+ * When "git submodule init" decides that the submodule in the working
+   tree is its upstream, it now gives a warning as it is not a very
+   common setup.
+
+ * "git stash push" takes a pathspec so that the local changes can be
+   stashed away only partially.
+
+ * Documentation for "git ls-files" did not refer to core.quotePath.
+
+ * The experimental "split index" feature has gained a few
+   configuration variables to make it easier to use.
+
+ * From a working tree of a repository, a new option of "rev-parse"
+   lets you ask if the repository is used as a submodule of another
+   project, and where the root level of the working tree of that
+   project (i.e. your superproject) is.
+
+ * The pathspec mechanism learned to further limit the paths that
+   match the pattern to those that have specified attributes attached
+   via the gitattributes mechanism.
+
+ * Our source code has used the SHA1_HEADER cpp macro after "#include"
+   in the C code to switch among the SHA-1 implementations. Instead,
+   list the exact header file names and switch among implementations
+   using "#ifdef BLK_SHA1/#include "block-sha1/sha1.h"/.../#endif";
+   this helps some IDE tools.
+
+ * The start-up sequence of "git" needs to figure out some configured
+   settings before it finds and set itself up in the location of the
+   repository and was quite messy due to its "chicken-and-egg" nature.
+   The code has been restructured.
+
+ * The command line prompt (in contrib/) learned a new 'tag' style
+   that can be specified with GIT_PS1_DESCRIBE_STYLE, to describe a
+   detached HEAD with "git describe --tags".
+
+ * The configuration file learned a new "includeIf.<condition>.path"
+   that includes the contents of the given path only when the
+   condition holds.  This allows you to say "include this work-related
+   bit only in the repositories under my ~/work/ directory".
+
+ * Recent update to "rebase -i" started showing a message that is not
+   a warning with "warning:" prefix by mistake.  This has been fixed.
+
+ * Recently we started passing the "--push-options" through the
+   external remote helper interface; now the "smart HTTP" remote
+   helper understands what to do with the passed information.
+
+ * "git describe --dirty" dies when it cannot be determined if the
+   state in the working tree matches that of HEAD (e.g. broken
+   repository or broken submodule).  The command learned a new option
+   "git describe --broken" to give "$name-broken" (where $name is the
+   description of HEAD) in such a case.
+
+ * "git checkout" is taught the "--recurse-submodules" option.
+
+ * Recent enhancement to "git stash push" command to support pathspec
+   to allow only a subset of working tree changes to be stashed away
+   was found to be too chatty and exposed the internal implementation
+   detail (e.g. when it uses reset to match the index to HEAD before
+   doing other things, output from reset seeped out).  These, and
+   other chattyness has been fixed.
+
+ * "git merge <message> HEAD <commit>" syntax that has been deprecated
+   since October 2007 has been removed.
+
+ * The refs completion for large number of refs has been sped up,
+   partly by giving up disambiguating ambiguous refs and partly by
+   eliminating most of the shell processing between 'git for-each-ref'
+   and 'ls-remote' and Bash's completion facility.
+
+ * On many keyboards, typing "@{" involves holding down SHIFT key and
+   one can easily end up with "@{Up..." when typing "@{upstream}".  As
+   the upstream/push keywords do not appear anywhere else in the syntax,
+   we can safely accept them case insensitively without introducing
+   ambiguity or confusion to solve this.
+
+ * "git tag/branch/for-each-ref" family of commands long allowed to
+   filter the refs by "--contains X" (show only the refs that are
+   descendants of X), "--merged X" (show only the refs that are
+   ancestors of X), "--no-merged X" (show only the refs that are not
+   ancestors of X).  One curious omission, "--no-contains X" (show
+   only the refs that are not descendants of X) has been added to
+   them.
+
+ * The default behaviour of "git log" in an interactive session has
+   been changed to enable "--decorate".
+
+ * The output from "git status --short" has been extended to show
+   various kinds of dirtiness in submodules differently; instead of to
+   "M" for modified, 'm' and '?' can be shown to signal changes only
+   to the working tree of the submodule but not the commit that is
+   checked out.
+
+ * Allow the http.postbuffer configuration variable to be set to a
+   size that can be expressed in size_t, which can be larger than
+   ulong on some platforms.
+
+ * "git rebase" learns "--signoff" option.
+
+ * The completion script (in contrib/) learned to complete "git push
+   --delete b<TAB>" to complete branch name to be deleted.
+
+ * "git worktree add --lock" allows to lock a worktree immediately
+   after it's created. This helps prevent a race between "git worktree
+   add; git worktree lock" and "git worktree prune".
+
+ * Completion for "git checkout <branch>" that auto-creates the branch
+   out of a remote tracking branch can now be disabled, as this
+   completion often gets in the way when completing to checkout an
+   existing local branch that happens to share the same prefix with
+   bunch of remote tracking branches.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The code to list branches in "git branch" has been consolidated
+   with the more generic ref-filter API.
+
+ * Resource usage while enumerating refs from alternate object store
+   has been optimized to help receiving end of "push" that hosts a
+   repository with many "forks".
+
+ * The gitattributes machinery is being taught to work better in a
+   multi-threaded environment.
+
+ * "git rebase -i" starts using the recently updated "sequencer" code.
+
+ * Code and design clean-up for the refs API.
+
+ * The preload-index code has been taught not to bother with the index
+   entries that are paths that are not checked out by "sparse checkout".
+
+ * Some warning() messages from "git clean" were updated to show the
+   errno from failed system calls.
+
+ * The "parse_config_key()" API function has been cleaned up.
+
+ * A test that creates a confusing branch whose name is HEAD has been
+   corrected not to do so.
+
+ * The code that parses header fields in the commit object has been
+   updated for (micro)performance and code hygiene.
+
+ * An helper function to make it easier to append the result from
+   real_path() to a strbuf has been added.
+
+ * Reduce authentication round-trip over HTTP when the server supports
+   just a single authentication method.  This also improves the
+   behaviour when Git is misconfigured to enable http.emptyAuth
+   against a server that does not authenticate without a username
+   (i.e. not using Kerberos etc., which makes http.emptyAuth
+   pointless).
+
+ * Windows port wants to use OpenSSL's implementation of SHA-1
+   routines, so let them.
+
+ * The t/perf performance test suite was not prepared to test not so
+   old versions of Git, but now it covers versions of Git that are not
+   so ancient.
+
+ * Add 32-bit Linux variant to the set of platforms to be tested with
+   Travis CI.
+
+ * "git branch --list" takes the "--abbrev" and "--no-abbrev" options
+   to control the output of the object name in its "-v"(erbose)
+   output, but a recent update started ignoring them; fix it before
+   the breakage reaches to any released version.
+
+ * Picking two versions of Git and running tests to make sure the
+   older one and the newer one interoperate happily has now become
+   possible.
+
+ * "git tag --contains" used to (ab)use the object bits to keep track
+   of the state of object reachability without clearing them after
+   use; this has been cleaned up and made to use the newer commit-slab
+   facility.
+
+ * The "debug" helper used in the test framework learned to run
+   a command under "gdb" interactively.
+
+ * The "detect attempt to create collisions" variant of SHA-1
+   implementation by Marc Stevens (CWI) and Dan Shumow (Microsoft)
+   has been integrated and made the default.
+
+ * The test framework learned to detect unterminated here documents.
+
+ * The name-hash used for detecting paths that are different only in
+   cases (which matter on case insensitive filesystems) has been
+   optimized to take advantage of multi-threading when it makes sense.
+
+ * An earlier version of sha1dc/sha1.c that was merged to 'master'
+   compiled incorrectly on Windows, which has been fixed.
+
+ * "what URL do we want to update this submodule?" and "are we
+   interested in this submodule?" are split into two distinct
+   concepts, and then the way used to express the latter got extended,
+   paving a way to make it easier to manage a project with many
+   submodules and make it possible to later extend use of multiple
+   worktrees for a project with submodules.
+
+ * Some debugging output from "git describe" were marked for l10n,
+   but some weren't.  Mark missing ones for l10n.
+
+ * Define a new task in .travis.yml that triggers a test session on
+   Windows run elsewhere.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * The "submodule" specific field in the ref_store structure is
+   replaced with a more generic "gitdir" that can later be used also
+   when dealing with ref_store that represents the set of refs visible
+   from the other worktrees.
+
+ * The string-list API used a custom reallocation strategy that was
+   very inefficient, instead of using the usual ALLOC_GROW() macro,
+   which has been fixed.
+   (merge 950a234cbd jh/string-list-micro-optim later to maint).
+
+ * In a 2- and 3-way merge of trees, more than one source trees often
+   end up sharing an identical subtree; optimize by not reading the
+   same tree multiple times in such a case.
+   (merge d12a8cf0af jh/unpack-trees-micro-optim later to maint).
+
+ * The index file has a trailing SHA-1 checksum to detect file
+   corruption, and historically we checked it every time the index
+   file is used.  Omit the validation during normal use, and instead
+   verify only in "git fsck".
+
+ * Having a git command on the upstream side of a pipe in a test
+   script will hide the exit status from the command, which may cause
+   us to fail to notice a breakage; rewrite tests in a script to avoid
+   this issue.
+
+ * Travis CI learns to run coccicheck.
+
+ * "git checkout" that handles a lot of paths has been optimized by
+   reducing the number of unnecessary checks of paths in the
+   has_dir_name() function.
+
+ * The internals of the refs API around the cached refs has been
+   streamlined.
+
+ * Output from perf tests have been updated to align their titles.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.12
+-----------------
+
+Unless otherwise noted, all the fixes since v2.12 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git repack --depth=<n>" for a long time busted the specified depth
+   when reusing delta from existing packs.  This has been corrected.
+
+ * The code to parse the command line "git grep <patterns>... <rev>
+   [[--] <pathspec>...]" has been cleaned up, and a handful of bugs
+   have been fixed (e.g. we used to check "--" if it is a rev).
+
+ * "git ls-remote" and "git archive --remote" are designed to work
+   without being in a directory under Git's control.  However, recent
+   updates revealed that we randomly look into a directory called
+   .git/ without actually doing necessary set-up when working in a
+   repository.  Stop doing so.
+
+ * "git show-branch" expected there were only very short branch names
+   in the repository and used a fixed-length buffer to hold them
+   without checking for overflow.
+
+ * A caller of tempfile API that uses stdio interface to write to
+   files may ignore errors while writing, which is detected when
+   tempfile is closed (with a call to ferror()).  By that time, the
+   original errno that may have told us what went wrong is likely to
+   be long gone and was overwritten by an irrelevant value.
+   close_tempfile() now resets errno to EIO to make errno at least
+   predictable.
+
+ * "git remote rm X", when a branch has remote X configured as the
+   value of its branch.*.remote, tried to remove branch.*.remote and
+   branch.*.merge and failed if either is unset.
+
+ * A "gc.log" file left by a backgrounded "gc --auto" disables further
+   automatic gc; it has been taught to run at least once a day (by
+   default) by ignoring a stale "gc.log" file that is too old.
+
+ * The code to parse "git -c VAR=VAL cmd" and set configuration
+   variable for the duration of cmd had two small bugs, which have
+   been fixed.
+
+ * user.email that consists of only cruft chars should consistently
+   error out, but didn't.
+
+ * "git upload-pack", which is a counter-part of "git fetch", did not
+   report a request for a ref that was not advertised as invalid.
+   This is generally not a problem (because "git fetch" will stop
+   before making such a request), but is the right thing to do.
+
+ * A leak in a codepath to read from a packed object in (rare) cases
+   has been plugged.
+
+ * When a redirected http transport gets an error during the
+   redirected request, we ignored the error we got from the server,
+   and ended up giving a not-so-useful error message.
+
+ * The patch subcommand of "git add -i" was meant to have paths
+   selection prompt just like other subcommand, unlike "git add -p"
+   directly jumps to hunk selection.  Recently, this was broken and
+   "add -i" lost the paths selection dialog, but it now has been
+   fixed.
+
+ * Git v2.12 was shipped with an embarrassing breakage where various
+   operations that verify paths given from the user stopped dying when
+   seeing an issue, and instead later triggering segfault.
+
+ * There is no need for Python only to give a few messages to the
+   standard error stream, but we somehow did.
+
+ * The code to parse "git log -L..." command line was buggy when there
+   are many ranges specified with -L; overrun of the allocated buffer
+   has been fixed.
+
+ * The command-line parsing of "git log -L" copied internal data
+   structures using incorrect size on ILP32 systems.
+
+ * "git diff --quiet" relies on the size field in diff_filespec to be
+   correctly populated, but diff_populate_filespec() helper function
+   made an incorrect short-cut when asked only to populate the size
+   field for paths that need to go through convert_to_git() (e.g. CRLF
+   conversion).
+
+ * A few tests were run conditionally under (rare) conditions where
+   they cannot be run (like running cvs tests under 'root' account).
+
+ * "git branch @" created refs/heads/@ as a branch, and in general the
+   code that handled @{-1} and @{upstream} was a bit too loose in
+   disambiguating.
+
+ * "git fetch" that requests a commit by object name, when the other
+   side does not allow such an request, failed without much
+   explanation.
+
+ * "git filter-branch --prune-empty" drops a single-parent commit that
+   becomes a no-op, but did not drop a root commit whose tree is empty.
+
+ * Recent versions of Git treats http alternates (used in dumb http
+   transport) just like HTTP redirects and requires the client to
+   enable following it, due to security concerns.  But we forgot to
+   give a warning when we decide not to honor the alternates.
+
+ * "git push" had a handful of codepaths that could lead to a deadlock
+   when unexpected error happened, which has been fixed.
+
+ * "Dumb http" transport used to misparse a nonsense http-alternates
+   response, which has been fixed.
+
+ * "git add -p <pathspec>" unnecessarily expanded the pathspec to a
+   list of individual files that matches the pathspec by running "git
+   ls-files <pathspec>", before feeding it to "git diff-index" to see
+   which paths have changes, because historically the pathspec
+   language supported by "diff-index" was weaker.  These days they are
+   equivalent and there is no reason to internally expand it.  This
+   helps both performance and avoids command line argument limit on
+   some platforms.
+   (merge 7288e12cce jk/add-i-use-pathspecs later to maint).
+
+ * "git status --porcelain" is supposed to give a stable output, but a
+   few strings were left as translatable by mistake.
+
+ * "git revert -m 0 $merge_commit" complained that reverting a merge
+   needs to say relative to which parent the reversion needs to
+   happen, as if "-m 0" weren't given.  The correct diagnosis is that
+   "-m 0" does not refer to the first parent ("-m 1" does).  This has
+   been fixed.
+
+ * Code to read submodule.<name>.ignore config did not state the
+   variable name correctly when giving an error message diagnosing
+   misconfiguration.
+
+ * Fix for NO_PTHREADS build.
+
+ * Fix for potential segv introduced in v2.11.0 and later (also
+   v2.10.2) to "git log --pickaxe-regex -S".
+
+ * A few unterminated here documents in tests were fixed, which in
+   turn revealed incorrect expectations the tests make. These tests
+   have been updated.
+
+ * Fix for NO_PTHREADS option.
+   (merge 2225e1ea20 bw/grep-recurse-submodules later to maint).
+
+ * Git now avoids blindly falling back to ".git" when the setup
+   sequence said we are _not_ in Git repository.  A corner case that
+   happens to work right now may be broken by a call to die("BUG").
+   (merge b1ef400eec jk/no-looking-at-dotgit-outside-repo-final later to maint).
+
+ * A few commands that recently learned the "--recurse-submodule"
+   option misbehaved when started from a subdirectory of the
+   superproject.
+   (merge b2dfeb7c00 bw/recurse-submodules-relative-fix later to maint).
+
+ * FreeBSD implementation of getcwd(3) behaved differently when an
+   intermediate directory is unreadable/unsearchable depending on the
+   length of the buffer provided, which our strbuf_getcwd() was not
+   aware of.  strbuf_getcwd() has been taught to cope with it better.
+   (merge a54e938e5b rs/freebsd-getcwd-workaround later to maint).
+
+ * A recent update to "rebase -i" stopped running hooks for the "git
+   commit" command during "reword" action, which has been fixed.
+
+ * Removing an entry from a notes tree and then looking another note
+   entry from the resulting tree using the internal notes API
+   functions did not work as expected.  No in-tree users of the API
+   has such access pattern, but it still is worth fixing.
+
+ * "git receive-pack" could have been forced to die by attempting
+   allocate an unreasonably large amount of memory with a crafted push
+   certificate; this has been fixed.
+   (merge f2214dede9 bc/push-cert-receive-fix later to maint).
+
+ * Update error handling for codepath that deals with corrupt loose
+   objects.
+   (merge 51054177b3 jk/loose-object-info-report-error later to maint).
+
+ * "git diff --submodule=diff" learned to work better in a project
+   with a submodule that in turn has its own submodules.
+   (merge 17b254cda6 sb/show-diff-for-submodule-in-diff-fix later to maint).
+
+ * Update the build dependency so that an update to /usr/bin/perl
+   etc. result in recomputation of perl.mak file.
+   (merge c59c4939c2 ab/regen-perl-mak-with-different-perl later to maint).
+
+ * "git push --recurse-submodules --push-option=<string>" learned to
+   propagate the push option recursively down to pushes in submodules.
+
+ * If a patch e-mail had its first paragraph after an in-body header
+   indented (even after a blank line after the in-body header line),
+   the indented line was mistook as a continuation of the in-body
+   header.  This has been fixed.
+   (merge fd1062e52e lt/mailinfo-in-body-header-continuation later to maint).
+
+ * Clean up fallouts from recent tightening of the set-up sequence,
+   where Git barfs when repository information is accessed without
+   first ensuring that it was started in a repository.
+   (merge bccb22cbb1 jk/no-looking-at-dotgit-outside-repo later to maint).
+
+ * "git p4" used "name-rev HEAD" when it wants to learn what branch is
+   checked out; it should use "symbolic-ref HEAD".
+   (merge eff451101d ld/p4-current-branch-fix later to maint).
+
+ * "http.proxy" set to an empty string is used to disable the usage of
+   proxy.  We broke this early last year.
+   (merge ae51d91105 sr/http-proxy-configuration-fix later to maint).
+
+ * $GIT_DIR may in some cases be normalized with all symlinks resolved
+   while "gitdir" path expansion in the pattern does not receive the
+   same treatment, leading to incorrect mismatch.  This has been fixed.
+
+ * "git submodule" script does not work well with strange pathnames.
+   Protect it from a path with slashes in them, at least.
+
+ * "git fetch-pack" was not prepared to accept ERR packet that the
+   upload-pack can send with a human-readable error message.  It
+   showed the packet contents with ERR prefix, so there was no data
+   loss, but it was redundant to say "ERR" in an error message.
+   (merge 8e2c7bef03 jt/fetch-pack-error-reporting later to maint).
+
+ * "ls-files --recurse-submodules" did not quite work well in a
+   project with nested submodules.
+
+ * gethostname(2) may not NUL terminate the buffer if hostname does
+   not fit; unfortunately there is no easy way to see if our buffer
+   was too small, but at least this will make sure we will not end up
+   using garbage past the end of the buffer.
+   (merge 5781a9a270 dt/xgethostname-nul-termination later to maint).
+
+ * A recent update broke "git add -p ../foo" from a subdirectory.
+
+ * While handy, "git_path()" is a dangerous function to use as a
+   callsite that uses it safely one day can be broken by changes
+   to other code that calls it.  Reduction of its use continues.
+   (merge 16d2676c9e jk/war-on-git-path later to maint).
+
+ * The split-index code configuration code used an unsafe git_path()
+   function without copying its result out.
+
+ * Many stale HTTP(s) links have been updated in our documentation.
+   (merge 613416f0be jk/update-links-in-docs later to maint).
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge df2a6e38b7 jk/pager-in-use later to maint).
+   (merge 75ec4a6cb0 ab/branch-list-doc later to maint).
+   (merge 3e5b36c637 sg/skip-prefix-in-prettify-refname later to maint).
+   (merge 2c5e2865cc jk/fast-import-cleanup later to maint).
+   (merge 4473060bc2 ab/test-readme-updates later to maint).
+   (merge 48a96972fd ab/doc-submitting later to maint).
+   (merge f5c2bc2b96 jk/make-coccicheck-detect-errors later to maint).
+   (merge c105f563d1 cc/untracked later to maint).
+   (merge 8668976b53 jc/unused-symbols later to maint).
+   (merge fba275dc93 jc/bs-t-is-not-a-tab-for-sed later to maint).
+   (merge be6ed145de mm/ls-files-s-doc later to maint).
+   (merge 60b091c679 qp/bisect-docfix later to maint).
+   (merge 47242cd103 ah/diff-files-ours-theirs-doc later to maint).
+   (merge 35ad44cbd8 sb/submodule-rm-absorb later to maint).
+   (merge 0301f1fd92 va/i18n-perl-scripts later to maint).
+   (merge 733e064d98 vn/revision-shorthand-for-side-branch-log later to maint).
+   (merge 85999743e7 tb/doc-eol-normalization later to maint).
+   (merge 0747fb49fd jk/loose-object-fsck later to maint).
+   (merge d8f4481c4f jk/quarantine-received-objects later to maint).
+   (merge 7ba1ceef95 xy/format-patch-base later to maint).
+   (merge fa1912c89a rs/misc-cppcheck-fixes later to maint).
+   (merge f17d642d3b ab/push-cas-doc-n-test later to maint).
+   (merge 61e282425a ss/gitmodules-ignore-doc later to maint).
+   (merge 8d3047cd5b ss/submodule-shallow-doc later to maint).
+   (merge 1f9e18b772 jk/prio-queue-avoid-swap-with-self later to maint).
+   (merge 627fde1025 jk/submodule-init-segv-fix later to maint).
+   (merge d395745d81 rg/doc-pull-typofix later to maint).
+   (merge 01e60a9a22 rg/doc-submittingpatches-wordfix later to maint).
+   (merge 501d3cd7b8 sr/hooks-cwd-doc later to maint).
diff --git a/Documentation/RelNotes/2.13.1.txt b/Documentation/RelNotes/2.13.1.txt
new file mode 100644
index 0000000000..ed7cd976d9
--- /dev/null
+++ b/Documentation/RelNotes/2.13.1.txt
@@ -0,0 +1,114 @@
+Git v2.13.1 Release Notes
+=========================
+
+Fixes since v2.13
+-----------------
+
+ * The Web interface to gmane news archive is long gone, even though
+   the articles are still accessible via NTTP.  Replace the links with
+   ones to public-inbox.org.  Because their message identification is
+   based on the actual message-id, it is likely that it will be easier
+   to migrate away from it if/when necessary.
+
+ * Update tests to pass under GETTEXT_POISON (a mechanism to ensure
+   that output strings that should not be translated are not
+   translated by mistake), and tell TravisCI to run them.
+
+ * Setting "log.decorate=false" in the configuration file did not take
+   effect in v2.13, which has been corrected.
+
+ * An earlier update to test 7400 needed to be skipped on CYGWIN.
+
+ * Git sometimes gives an advice in a rhetorical question that does
+   not require an answer, which can confuse new users and non native
+   speakers.  Attempt to rephrase them.
+
+ * "git read-tree -m" (no tree-ish) gave a nonsense suggestion "use
+   --empty if you want to clear the index".  With "-m", such a request
+   will still fail anyway, as you'd need to name at least one tree-ish
+   to be merged.
+
+ * The codepath in "git am" that is used when running "git rebase"
+   leaked memory held for the log message of the commits being rebased.
+
+ * "pack-objects" can stream a slice of an existing packfile out when
+   the pack bitmap can tell that the reachable objects are all needed
+   in the output, without inspecting individual objects.  This
+   strategy however would not work well when "--local" and other
+   options are in use, and need to be disabled.
+
+ * Clarify documentation for include.path and includeIf.<condition>.path
+   configuration variables.
+
+ * Tag objects, which are not reachable from any ref, that point at
+   missing objects were mishandled by "git gc" and friends (they
+   should silently be ignored instead)
+
+ * A few http:// links that are redirected to https:// in the
+   documentation have been updated to https:// links.
+
+ * Make sure our tests would pass when the sources are checked out
+   with "platform native" line ending convention by default on
+   Windows.  Some "text" files out tests use and the test scripts
+   themselves that are meant to be run with /bin/sh, ought to be
+   checked out with eol=LF even on Windows.
+
+ * Fix memory leaks pointed out by Coverity (and people).
+
+ * The receive-pack program now makes sure that the push certificate
+   records the same set of push options used for pushing.
+
+ * "git cherry-pick" and other uses of the sequencer machinery
+   mishandled a trailer block whose last line is an incomplete line.
+   This has been fixed so that an additional sign-off etc. are added
+   after completing the existing incomplete line.
+
+ * The shell completion script (in contrib/) learned "git stash" has
+   a new "push" subcommand.
+
+ * Travis CI gained a task to format the documentation with both
+   AsciiDoc and AsciiDoctor.
+
+ * Update the C style recommendation for notes for translators, as
+   recent versions of gettext tools can work with our style of
+   multi-line comments.
+
+ * "git clone --config var=val" is a way to populate the
+   per-repository configuration file of the new repository, but it did
+   not work well when val is an empty string.  This has been fixed.
+
+ * A few codepaths in "checkout" and "am" working on an unborn branch
+   tried to access an uninitialized piece of memory.
+
+ * "git for-each-ref --format=..." with %(HEAD) in the format used to
+   resolve the HEAD symref as many times as it had processed refs,
+   which was wasteful, and "git branch" shared the same problem.
+
+ * "git interpret-trailers", when used as GIT_EDITOR for "git commit
+   -v", looked for and appended to a trailer block at the very end,
+   i.e. at the end of the "diff" output.  The command has been
+   corrected to pay attention to the cut-mark line "commit -v" adds to
+   the buffer---the real trailer block should appear just before it.
+
+ * A test allowed both "git push" and "git receive-pack" on the other
+   end write their traces into the same file.  This is OK on platforms
+   that allows atomically appending to a file opened with O_APPEND,
+   but on other platforms led to a mangled output, causing
+   intermittent test failures.  This has been fixed by disabling
+   traces from "receive-pack" in the test.
+
+ * "foo\bar\baz" in "git fetch foo\bar\baz", even though there is no
+   slashes in it, cannot be a nickname for a remote on Windows, as
+   that is likely to be a pathname on a local filesystem.
+
+ * The "collision detecting" SHA-1 implementation shipped with 2.13
+   was quite broken on some big-endian platforms and/or platforms that
+   do not like unaligned fetches.  Update to the upstream code which
+   has already fixed these issues.
+
+ * "git am -h" triggered a BUG().
+
+ * The interaction of "url.*.insteadOf" and custom URL scheme's
+   whitelisting is now documented better.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.13.2.txt b/Documentation/RelNotes/2.13.2.txt
new file mode 100644
index 0000000000..8c2b20071e
--- /dev/null
+++ b/Documentation/RelNotes/2.13.2.txt
@@ -0,0 +1,54 @@
+Git v2.13.2 Release Notes
+=========================
+
+Fixes since v2.13.1
+-------------------
+
+ * The "collision detecting" SHA-1 implementation shipped with 2.13.1
+   was still broken on some platforms.  Update to the upstream code
+   again to take their fix.
+
+ * "git checkout --recurse-submodules" did not quite work with a
+   submodule that itself has submodules.
+
+ * Introduce the BUG() macro to improve die("BUG: ...").
+
+ * The "run-command" API implementation has been made more robust
+   against dead-locking in a threaded environment.
+
+ * A recent update to t5545-push-options.sh started skipping all the
+   tests in the script when a web server testing is disabled or
+   unavailable, not just the ones that require a web server.  Non HTTP
+   tests have been salvaged to always run in this script.
+
+ * "git clean -d" used to clean directories that has ignored files,
+   even though the command should not lose ignored ones without "-x".
+   "git status --ignored"  did not list ignored and untracked files
+   without "-uall".  These have been corrected.
+
+ * The timestamp of the index file is now taken after the file is
+   closed, to help Windows, on which a stale timestamp is reported by
+   fstat() on a file that is opened for writing and data was written
+   but not yet closed.
+
+ * "git pull --rebase --autostash" didn't auto-stash when the local history
+   fast-forwards to the upstream.
+
+ * "git describe --contains" penalized light-weight tags so much that
+   they were almost never considered.  Instead, give them about the
+   same chance to be considered as an annotated tag that is the same
+   age as the underlying commit would.
+
+ * The result from "git diff" that compares two blobs, e.g. "git diff
+   $commit1:$path $commit2:$path", used to be shown with the full
+   object name as given on the command line, but it is more natural to
+   use the $path in the output and use it to look up .gitattributes.
+
+ * A flaky test has been corrected.
+
+ * Help contributors that visit us at GitHub.
+
+ * "git stash push <pathspec>" did not work from a subdirectory at all.
+   Bugfix for a topic in v2.13
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.13.3.txt b/Documentation/RelNotes/2.13.3.txt
new file mode 100644
index 0000000000..384e4de265
--- /dev/null
+++ b/Documentation/RelNotes/2.13.3.txt
@@ -0,0 +1,62 @@
+Git v2.13.3 Release Notes
+=========================
+
+Fixes since v2.13.2
+-------------------
+
+ * The "collision detecting" SHA-1 implementation shipped with 2.13.2
+   was still broken on some platforms.  Update to the upstream code
+   again to take their fix.
+
+ * The 'diff-highlight' program (in contrib/) has been restructured
+   for easier reuse by an external project 'diff-so-fancy'.
+
+ * "git mergetool" learned to work around a wrapper MacOS X adds
+   around underlying meld.
+
+ * An example in documentation that does not work in multi worktree
+   configuration has been corrected.
+
+ * The pretty-format specifiers like '%h', '%t', etc. had an
+   optimization that no longer works correctly.  In preparation/hope
+   of getting it correctly implemented, first discard the optimization
+   that is broken.
+
+ * The code to pick up and execute command alias definition from the
+   configuration used to switch to the top of the working tree and
+   then come back when the expanded alias was executed, which was
+   unnecessarily complex.  Attempt to simplify the logic by using the
+   early-config mechanism that does not chdir around.
+
+ * "git add -p" were updated in 2.12 timeframe to cope with custom
+   core.commentchar but the implementation was buggy and a
+   metacharacter like $ and * did not work.
+
+ * Fix a recent regression to "git rebase -i" and add tests that would
+   have caught it and others.
+
+ * An unaligned 32-bit access in pack-bitmap code has been corrected.
+
+ * Tighten error checks for invalid "git apply" input.
+
+ * The split index code did not honor core.sharedrepository setting
+   correctly.
+
+ * The Makefile rule in contrib/subtree for building documentation
+   learned to honour USE_ASCIIDOCTOR just like the main documentation
+   set does.
+
+ * A few tests that tried to verify the contents of push certificates
+   did not use 'git rev-parse' to formulate the line to look for in
+   the certificate correctly.
+
+ * After "git branch --move" of the currently checked out branch, the
+   code to walk the reflog of HEAD via "log -g" and friends
+   incorrectly stopped at the reflog entry that records the renaming
+   of the branch.
+
+ * The rewrite of "git branch --list" using for-each-ref's internals
+   that happened in v2.13 regressed its handling of color.branch.local;
+   this has been fixed.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.13.4.txt b/Documentation/RelNotes/2.13.4.txt
new file mode 100644
index 0000000000..9a9f8f9599
--- /dev/null
+++ b/Documentation/RelNotes/2.13.4.txt
@@ -0,0 +1,28 @@
+Git v2.13.4 Release Notes
+=========================
+
+Fixes since v2.13.3
+-------------------
+
+ * Update the character width tables.
+
+ * A recent update broke an alias that contained an uppercase letter,
+   which has been fixed.
+
+ * On Cygwin, similar to Windows, "git push //server/share/repository"
+   ought to mean a repository on a network share that can be accessed
+   locally, but this did not work correctly due to stripping the double
+   slashes at the beginning.
+
+ * The progress meter did not give a useful output when we haven't had
+   0.5 seconds to measure the throughput during the interval.  Instead
+   show the overall throughput rate at the end, which is a much more
+   useful number.
+
+ * We run an early part of "git gc" that deals with refs before
+   daemonising (and not under lock) even when running a background
+   auto-gc, which caused multiple gc processes attempting to run the
+   early part at the same time.  This is now prevented by running the
+   early part also under the GC lock.
+
+Also contains a handful of small code and documentation clean-ups.
diff --git a/Documentation/RelNotes/2.13.5.txt b/Documentation/RelNotes/2.13.5.txt
new file mode 100644
index 0000000000..6949fcda78
--- /dev/null
+++ b/Documentation/RelNotes/2.13.5.txt
@@ -0,0 +1,4 @@
+Git v2.13.5 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.13.6.txt b/Documentation/RelNotes/2.13.6.txt
new file mode 100644
index 0000000000..afcae9c808
--- /dev/null
+++ b/Documentation/RelNotes/2.13.6.txt
@@ -0,0 +1,17 @@
+Git v2.13.6 Release Notes
+=========================
+
+Fixes since v2.13.5
+-------------------
+
+ * "git cvsserver" no longer is invoked by "git daemon" by default,
+   as it is old and largely unmaintained.
+
+ * Various Perl scripts did not use safe_pipe_capture() instead of
+   backticks, leaving them susceptible to end-user input.  They have
+   been corrected.
+
+Credits go to joernchen <joernchen@xxxxxxxxxxxx> for finding the
+unsafe constructs in "git cvsserver", and to Jeff King at GitHub for
+finding and fixing instances of the same issue in other scripts.
+
diff --git a/Documentation/RelNotes/2.13.7.txt b/Documentation/RelNotes/2.13.7.txt
new file mode 100644
index 0000000000..09fc01406c
--- /dev/null
+++ b/Documentation/RelNotes/2.13.7.txt
@@ -0,0 +1,20 @@
+Git v2.13.7 Release Notes
+=========================
+
+Fixes since v2.13.6
+-------------------
+
+ * Submodule "names" come from the untrusted .gitmodules file, but we
+   blindly append them to $GIT_DIR/modules to create our on-disk repo
+   paths. This means you can do bad things by putting "../" into the
+   name. We now enforce some rules for submodule names which will cause
+   Git to ignore these malicious names (CVE-2018-11235).
+
+   Credit for finding this vulnerability and the proof of concept from
+   which the test script was adapted goes to Etienne Stalmans.
+
+ * It was possible to trick the code that sanity-checks paths on NTFS
+   into reading random piece of memory (CVE-2018-11233).
+
+Credit for fixing for these bugs goes to Jeff King, Johannes
+Schindelin and others.
diff --git a/Documentation/RelNotes/2.14.0.txt b/Documentation/RelNotes/2.14.0.txt
new file mode 100644
index 0000000000..2711a2529d
--- /dev/null
+++ b/Documentation/RelNotes/2.14.0.txt
@@ -0,0 +1,517 @@
+Git 2.14 Release Notes
+======================
+
+Backward compatibility notes and other notable changes.
+
+ * Use of an empty string as a pathspec element that is used for
+   'everything matches' is still warned and Git asks users to use a
+   more explicit '.' for that instead.  The hope is that existing
+   users will not mind this change, and eventually the warning can be
+   turned into a hard error, upgrading the deprecation into removal of
+   this (mis)feature.  That is not scheduled to happen in the upcoming
+   release (yet).
+
+ * Git now avoids blindly falling back to ".git" when the setup
+   sequence said we are _not_ in Git repository.  A corner case that
+   happens to work right now may be broken by a call to die("BUG").
+   We've tried hard to locate such cases and fixed them, but there
+   might still be cases that need to be addressed--bug reports are
+   greatly appreciated.
+
+ * The experiment to improve the hunk-boundary selection of textual
+   diff output has finished, and the "indent heuristics" has now
+   become the default.
+
+ * Git can now be built with PCRE v2 instead of v1 of the PCRE
+   library. Replace USE_LIBPCRE=YesPlease with USE_LIBPCRE2=YesPlease
+   in existing build scripts to build against the new version.  As the
+   upstream PCRE maintainer has abandoned v1 maintenance for all but
+   the most critical bug fixes, use of v2 is recommended.
+
+
+Updates since v2.13
+-------------------
+
+UI, Workflows & Features
+
+ * The colors in which "git status --short --branch" showed the names
+   of the current branch and its remote-tracking branch are now
+   configurable.
+
+ * "git clone" learned the "--no-tags" option not to fetch all tags
+   initially, and also set up the tagopt not to follow any tags in
+   subsequent fetches.
+
+ * "git archive --format=zip" learned to use zip64 extension when
+   necessary to go beyond the 4GB limit.
+
+ * "git reset" learned "--recurse-submodules" option.
+
+ * "git diff --submodule=diff" now recurses into nested submodules.
+
+ * "git repack" learned to accept the --threads=<n> option and pass it
+   to pack-objects.
+
+ * "git send-email" learned to run sendemail-validate hook to inspect
+   and reject a message before sending it out.
+
+ * There is no good reason why "git fetch $there $sha1" should fail
+   when the $sha1 names an object at the tip of an advertised ref,
+   even when the other side hasn't enabled allowTipSHA1InWant.
+
+ * The "[includeIf "gitdir:$dir"] path=..." mechanism introduced in
+   2.13.0 would canonicalize the path of the gitdir being matched,
+   and did not match e.g. "gitdir:~/work/*" against a repo in
+   "~/work/main" if "~/work" was a symlink to "/mnt/storage/work".
+   Now we match both the resolved canonical path and what "pwd" would
+   show. The include will happen if either one matches.
+
+ * The "indent" heuristics is now the default in "diff". The
+   diff.indentHeuristic configuration variable can be set to "false"
+   for those who do not want it.
+
+ * Many commands learned to pay attention to submodule.recurse
+   configuration.
+
+ * The convention for a command line is to follow "git cmdname
+   --options" with revisions followed by an optional "--"
+   disambiguator and then finally pathspecs.  When "--" is not there,
+   we make sure early ones are all interpretable as revs (and do not
+   look like paths) and later ones are the other way around.  A
+   pathspec with "magic" (e.g. ":/p/a/t/h" that matches p/a/t/h from
+   the top-level of the working tree, no matter what subdirectory you
+   are working from) are conservatively judged as "not a path", which
+   required disambiguation more often.  The command line parser
+   learned to say "it's a pathspec" a bit more often when the syntax
+   looks like so.
+
+ * Update "perl-compatible regular expression" support to enable JIT
+   and also allow linking with the newer PCRE v2 library.
+
+ * "filter-branch" learned a pseudo filter "--setup" that can be used
+   to define common functions/variables that can be used by other
+   filters.
+
+ * Using "git add d/i/r" when d/i/r is the top of the working tree of
+   a separate repository would create a gitlink in the index, which
+   would appear as a not-quite-initialized submodule to others.  We
+   learned to give warnings when this happens.
+
+ * "git status" learned to optionally give how many stash entries there
+   are in its output.
+
+ * "git status" has long shown essentially the same message as "git
+   commit"; the message it gives while preparing for the root commit,
+   i.e. "Initial commit", was hard to understand for some new users.
+   Now it says "No commits yet" to stress more on the current status
+   (rather than the commit the user is preparing for, which is more in
+   line with the focus of "git commit").
+
+ * "git send-email" now has --batch-size and --relogin-delay options
+    which can be used to overcome limitations on SMTP servers that
+    restrict on how many of e-mails can be sent in a single session.
+
+ * An old message shown in the commit log template was removed, as it
+   has outlived its usefulness.
+
+ * "git pull --rebase --recurse-submodules" learns to rebase the
+   branch in the submodules to an updated base.
+
+ * "git log" learned -P as a synonym for --perl-regexp, "git grep"
+   already had such a synonym.
+
+ * "git log" didn't understand --regexp-ignore-case when combined with
+   --perl-regexp. This has been fixed.
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The default packed-git limit value has been raised on larger
+   platforms to save "git fetch" from a (recoverable) failure while
+   "gc" is running in parallel.
+
+ * Code to update the cache-tree has been tightened so that we won't
+   accidentally write out any 0{40} entry in the tree object.
+
+ * Attempt to allow us notice "fishy" situation where we fail to
+   remove the temporary directory used during the test.
+
+ * Travis CI gained a task to format the documentation with both
+   AsciiDoc and AsciiDoctor.
+
+ * Some platforms have ulong that is smaller than time_t, and our
+   historical use of ulong for timestamp would mean they cannot
+   represent some timestamp that the platform allows.  Invent a
+   separate and dedicated timestamp_t (so that we can distinguish
+   timestamps and a vanilla ulongs, which along is already a good
+   move), and then declare uintmax_t is the type to be used as the
+   timestamp_t.
+
+ * We can trigger Windows auto-build tester (credits: Dscho &
+   Microsoft) from our existing Travis CI tester now.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * Simplify parse_pathspec() codepath and stop it from looking at the
+   default in-core index.
+
+ * Add perf-test for wildmatch.
+
+ * Code from "conversion using external process" codepath has been
+   extracted to a separate sub-process.[ch] module.
+
+ * When "git checkout", "git merge", etc. manipulates the in-core
+   index, various pieces of information in the index extensions are
+   discarded from the original state, as it is usually not the case
+   that they are kept up-to-date and in-sync with the operation on the
+   main index.  The untracked cache extension is copied across these
+   operations now, which would speed up "git status" (as long as the
+   cache is properly invalidated).
+
+ * The internal implementation of "git grep" has seen some clean-up.
+
+ * Update the C style recommendation for notes for translators, as
+   recent versions of gettext tools can work with our style of
+   multi-line comments.
+
+ * The implementation of "ref" API around the "packed refs" have been
+   cleaned up, in preparation for further changes.
+
+ * The internal logic used in "git blame" has been libified to make it
+   easier to use by cgit.
+
+ * Our code often opens a path to an optional file, to work on its
+   contents when we can successfully open it.  We can ignore a failure
+   to open if such an optional file does not exist, but we do want to
+   report a failure in opening for other reasons (e.g. we got an I/O
+   error, or the file is there, but we lack the permission to open).
+
+   The exact errors we need to ignore are ENOENT (obviously) and
+   ENOTDIR (less obvious).  Instead of repeating comparison of errno
+   with these two constants, introduce a helper function to do so.
+
+ * We often try to open a file for reading whose existence is
+   optional, and silently ignore errors from open/fopen; report such
+   errors if they are not due to missing files.
+
+ * When an existing repository is used for t/perf testing, we first
+   create bit-for-bit copy of it, which may grab a transient state of
+   the repository and freeze it into the repository used for testing,
+   which then may cause Git operations to fail.  Single out "the index
+   being locked" case and forcibly drop the lock from the copy.
+
+ * Three instances of the same helper function have been consolidated
+   to one.
+
+ * "fast-import" uses a default pack chain depth that is consistent
+   with other parts of the system.
+
+ * A new test to show the interaction between the pattern [^a-z]
+   (which matches '/') and a slash in a path has been added.  The
+   pattern should not match the slash with "pathmatch", but should
+   with "wildmatch".
+
+ * The 'diff-highlight' program (in contrib/) has been restructured
+   for easier reuse by an external project 'diff-so-fancy'.
+
+ * A common pattern to free a piece of memory and assign NULL to the
+   pointer that used to point at it has been replaced with a new
+   FREE_AND_NULL() macro.
+
+ * Traditionally, the default die() routine had a code to prevent it
+   from getting called multiple times, which interacted badly when a
+   threaded program used it (one downside is that the real error may
+   be hidden and instead the only error message given to the user may
+   end up being "die recursion detected", which is not very useful).
+
+ * Introduce a "repository" object to eventually make it easier to
+   work in multiple repositories (the primary focus is to work with
+   the superproject and its submodules) in a single process.
+
+ * Optimize "what are the object names already taken in an alternate
+   object database?" query that is used to derive the length of prefix
+   an object name is uniquely abbreviated to.
+
+ * The hashmap API has been updated so that data to customize the
+   behaviour of the comparison function can be specified at the time a
+   hashmap is initialized.
+
+ * The "collision detecting" SHA-1 implementation shipped with 2.13 is
+   now integrated into git.git as a submodule (the first submodule to
+   ship with git.git). Clone git.git with --recurse-submodules to get
+   it. For now a non-submodule copy of the same code is also shipped
+   as part of the tree.
+
+ * A recent update made it easier to use "-fsanitize=" option while
+   compiling but supported only one sanitize option.  Allow more than
+   one to be combined, joined with a comma, like "make SANITIZE=foo,bar".
+
+ * Use "p4 -G" to make "p4 changes" output more Python-friendly
+   to parse.
+
+ * We started using "%" PRItime, imitating "%" PRIuMAX and friends, as
+   a way to format the internal timestamp value, but this does not
+   play well with gettext(1) i18n framework, and causes "make pot"
+   that is run by the l10n coordinator to create a broken po/git.pot
+   file.  This is a possible workaround for that problem.
+
+ * It turns out that Cygwin also needs the fopen() wrapper that
+   returns failure when a directory is opened for reading.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.13
+-----------------
+
+Unless otherwise noted, all the fixes since v2.13 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git gc" did not interact well with "git worktree"-managed
+   per-worktree refs.
+
+ * "git cherry-pick" and other uses of the sequencer machinery
+   mishandled a trailer block whose last line is an incomplete line.
+   This has been fixed so that an additional sign-off etc. are added
+   after completing the existing incomplete line.
+
+ * The codepath in "git am" that is used when running "git rebase"
+   leaked memory held for the log message of the commits being rebased.
+
+ * "git clone --config var=val" is a way to populate the
+   per-repository configuration file of the new repository, but it did
+   not work well when val is an empty string.  This has been fixed.
+
+ * Setting "log.decorate=false" in the configuration file did not take
+   effect in v2.13, which has been corrected.
+
+ * A few codepaths in "checkout" and "am" working on an unborn branch
+   tried to access an uninitialized piece of memory.
+
+ * The Web interface to gmane news archive is long gone, even though
+   the articles are still accessible via NTTP.  Replace the links with
+   ones to public-inbox.org.  Because their message identification is
+   based on the actual message-id, it is likely that it will be easier
+   to migrate away from it if/when necessary.
+
+ * The receive-pack program now makes sure that the push certificate
+   records the same set of push options used for pushing.
+
+ * Tests have been updated to pass under GETTEXT_POISON (a mechanism
+   to ensure that output strings that should not be translated are
+   not translated by mistake), and TravisCI is told to run them.
+
+ * "git checkout --recurse-submodules" did not quite work with a
+   submodule that itself has submodules.
+
+ * "pack-objects" can stream a slice of an existing packfile out when
+   the pack bitmap can tell that the reachable objects are all needed
+   in the output, without inspecting individual objects.  This
+   strategy however would not work well when "--local" and other
+   options are in use, and need to be disabled.
+
+ * Fix memory leaks pointed out by Coverity (and people).
+
+ * "git read-tree -m" (no tree-ish) gave a nonsense suggestion "use
+   --empty if you want to clear the index".  With "-m", such a request
+   will still fail anyway, as you'd need to name at least one tree-ish
+   to be merged.
+
+ * Make sure our tests would pass when the sources are checked out
+   with "platform native" line ending convention by default on
+   Windows.  Some "text" files out tests use and the test scripts
+   themselves that are meant to be run with /bin/sh, ought to be
+   checked out with eol=LF even on Windows.
+
+ * Introduce the BUG() macro to improve die("BUG: ...").
+
+ * Clarify documentation for include.path and includeIf.<condition>.path
+   configuration variables.
+
+ * Git sometimes gives an advice in a rhetorical question that does
+   not require an answer, which can confuse new users and non native
+   speakers.  Attempt to rephrase them.
+
+ * A few http:// links that are redirected to https:// in the
+   documentation have been updated to https:// links.
+
+ * "git for-each-ref --format=..." with %(HEAD) in the format used to
+   resolve the HEAD symref as many times as it had processed refs,
+   which was wasteful, and "git branch" shared the same problem.
+
+ * Regression fix to topic recently merged to 'master'.
+
+ * The shell completion script (in contrib/) learned "git stash" has
+   a new "push" subcommand.
+
+ * "git interpret-trailers", when used as GIT_EDITOR for "git commit
+   -v", looked for and appended to a trailer block at the very end,
+   i.e. at the end of the "diff" output.  The command has been
+   corrected to pay attention to the cut-mark line "commit -v" adds to
+   the buffer---the real trailer block should appear just before it.
+
+ * A test allowed both "git push" and "git receive-pack" on the other
+   end write their traces into the same file.  This is OK on platforms
+   that allows atomically appending to a file opened with O_APPEND,
+   but on other platforms led to a mangled output, causing
+   intermittent test failures.  This has been fixed by disabling
+   traces from "receive-pack" in the test.
+
+ * Tag objects, which are not reachable from any ref, that point at
+   missing objects were mishandled by "git gc" and friends (they
+   should silently be ignored instead)
+
+ * "git describe --contains" penalized light-weight tags so much that
+   they were almost never considered.  Instead, give them about the
+   same chance to be considered as an annotated tag that is the same
+   age as the underlying commit would.
+
+ * The "run-command" API implementation has been made more robust
+   against dead-locking in a threaded environment.
+
+ * A recent update to t5545-push-options.sh started skipping all the
+   tests in the script when a web server testing is disabled or
+   unavailable, not just the ones that require a web server.  Non HTTP
+   tests have been salvaged to always run in this script.
+
+ * "git send-email" now uses Net::SMTP::SSL, which is obsolete, only
+   when needed.  Recent versions of Net::SMTP can do TLS natively.
+
+ * "foo\bar\baz" in "git fetch foo\bar\baz", even though there is no
+   slashes in it, cannot be a nickname for a remote on Windows, as
+   that is likely to be a pathname on a local filesystem.
+
+ * "git clean -d" used to clean directories that has ignored files,
+   even though the command should not lose ignored ones without "-x".
+   "git status --ignored"  did not list ignored and untracked files
+   without "-uall".  These have been corrected.
+
+ * The result from "git diff" that compares two blobs, e.g. "git diff
+   $commit1:$path $commit2:$path", used to be shown with the full
+   object name as given on the command line, but it is more natural to
+   use the $path in the output and use it to look up .gitattributes.
+
+ * The "collision detecting" SHA-1 implementation shipped with 2.13
+   was quite broken on some big-endian platforms and/or platforms that
+   do not like unaligned fetches.  Update to the upstream code which
+   has already fixed these issues.
+
+ * "git am -h" triggered a BUG().
+
+ * The interaction of "url.*.insteadOf" and custom URL scheme's
+   whitelisting is now documented better.
+
+ * The timestamp of the index file is now taken after the file is
+   closed, to help Windows, on which a stale timestamp is reported by
+   fstat() on a file that is opened for writing and data was written
+   but not yet closed.
+
+ * "git pull --rebase --autostash" didn't auto-stash when the local history
+   fast-forwards to the upstream.
+
+ * A flaky test has been corrected.
+
+ * "git $cmd -h" for builtin commands calls the implementation of the
+   command (i.e. cmd_$cmd() function) without doing any repository
+   set-up, and the commands that expect RUN_SETUP is done by the Git
+   potty needs to be prepared to show the help text without barfing.
+   (merge d691551192 jk/consistent-h later to maint).
+
+ * Help contributors that visit us at GitHub.
+
+ * "git stash push <pathspec>" did not work from a subdirectory at all.
+   Bugfix for a topic in v2.13
+
+ * As there is no portable way to pass timezone information to
+   strftime, some output format from "git log" and friends are
+   impossible to produce.  Teach our own strbuf_addftime to replace %z
+   and %Z with caller-supplied values to help working around this.
+   (merge 6eced3ec5e rs/strbuf-addftime-zZ later to maint).
+
+ * "git mergetool" learned to work around a wrapper MacOS X adds
+   around underlying meld.
+
+ * An example in documentation that does not work in multi worktree
+   configuration has been corrected.
+
+ * The pretty-format specifiers like '%h', '%t', etc. had an
+   optimization that no longer works correctly.  In preparation/hope
+   of getting it correctly implemented, first discard the optimization
+   that is broken.
+
+ * The code to pick up and execute command alias definition from the
+   configuration used to switch to the top of the working tree and
+   then come back when the expanded alias was executed, which was
+   unnecessarily complex.  Attempt to simplify the logic by using the
+   early-config mechanism that does not chdir around.
+
+ * Fix configuration codepath to pay proper attention to commondir
+   that is used in multi-worktree situation, and isolate config API
+   into its own header file.
+   (merge dc8441fdb4 bw/config-h later to maint).
+
+ * "git add -p" were updated in 2.12 timeframe to cope with custom
+   core.commentchar but the implementation was buggy and a
+   metacharacter like $ and * did not work.
+
+ * A recent regression in "git rebase -i" has been fixed and tests
+   that would have caught it and others have been added.
+
+ * An unaligned 32-bit access in pack-bitmap code has been corrected.
+
+ * Tighten error checks for invalid "git apply" input.
+
+ * The split index code did not honor core.sharedRepository setting
+   correctly.
+
+ * The Makefile rule in contrib/subtree for building documentation
+   learned to honour USE_ASCIIDOCTOR just like the main documentation
+   set does.
+
+ * Code clean-up to fix possible buffer over-reading.
+
+ * A few tests that tried to verify the contents of push certificates
+   did not use 'git rev-parse' to formulate the line to look for in
+   the certificate correctly.
+
+ * Update the character width tables.
+
+ * After "git branch --move" of the currently checked out branch, the
+   code to walk the reflog of HEAD via "log -g" and friends
+   incorrectly stopped at the reflog entry that records the renaming
+   of the branch.
+
+ * The rewrite of "git branch --list" using for-each-ref's internals
+   that happened in v2.13 regressed its handling of color.branch.local;
+   this has been fixed.
+
+ * The build procedure has been improved to allow building and testing
+   Git with address sanitizer more easily.
+   (merge 425ca6710b jk/build-with-asan later to maint).
+
+ * On Cygwin, similar to Windows, "git push //server/share/repository"
+   ought to mean a repository on a network share that can be accessed
+   locally, but this did not work correctly due to stripping the double
+   slashes at the beginning.
+
+ * The progress meter did not give a useful output when we haven't had
+   0.5 seconds to measure the throughput during the interval.  Instead
+   show the overall throughput rate at the end, which is a much more
+   useful number.
+
+ * Code clean-up, that makes us in sync with Debian by one patch.
+
+ * We run an early part of "git gc" that deals with refs before
+   daemonising (and not under lock) even when running a background
+   auto-gc, which caused multiple gc processes attempting to run the
+   early part at the same time.  This is now prevented by running the
+   early part also under the GC lock.
+
+ * A recent update broke an alias that contained an uppercase letter.
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge 5053313562 rs/urlmatch-cleanup later to maint).
+   (merge 42c78a216e rs/use-div-round-up later to maint).
+   (merge 5e8d2729ae rs/wt-status-cleanup later to maint).
+   (merge bc9b7e207f as/diff-options-grammofix later to maint).
+   (merge ac05222b31 ah/patch-id-doc later to maint).
diff --git a/Documentation/RelNotes/2.14.1.txt b/Documentation/RelNotes/2.14.1.txt
new file mode 100644
index 0000000000..9403340f7f
--- /dev/null
+++ b/Documentation/RelNotes/2.14.1.txt
@@ -0,0 +1,4 @@
+Git v2.14.1 Release Notes
+=========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.14.2.txt b/Documentation/RelNotes/2.14.2.txt
new file mode 100644
index 0000000000..bec9186ade
--- /dev/null
+++ b/Documentation/RelNotes/2.14.2.txt
@@ -0,0 +1,105 @@
+Git v2.14.2 Release Notes
+=========================
+
+Fixes since v2.14.1
+-------------------
+
+ * Because recent Git for Windows do come with a real msgfmt, the
+   build procedure for git-gui has been updated to use it instead of a
+   hand-rolled substitute.
+
+ * "%C(color name)" in the pretty print format always produced ANSI
+   color escape codes, which was an early design mistake.  They now
+   honor the configuration (e.g. "color.ui = never") and also tty-ness
+   of the output medium.
+
+ * The http.{sslkey,sslCert} configuration variables are to be
+   interpreted as a pathname that honors "~[username]/" prefix, but
+   weren't, which has been fixed.
+
+ * Numerous bugs in walking of reflogs via "log -g" and friends have
+   been fixed.
+
+ * "git commit" when seeing an totally empty message said "you did not
+   edit the message", which is clearly wrong.  The message has been
+   corrected.
+
+ * When a directory is not readable, "gitweb" fails to build the
+   project list.  Work this around by skipping such a directory.
+
+ * A recently added test for the "credential-cache" helper revealed
+   that EOF detection done around the time the connection to the cache
+   daemon is torn down were flaky.  This was fixed by reacting to
+   ECONNRESET and behaving as if we got an EOF.
+
+ * Some versions of GnuPG fail to kill gpg-agent it auto-spawned
+   and such a left-over agent can interfere with a test.  Work it
+   around by attempting to kill one before starting a new test.
+
+ * "git log --tag=no-such-tag" showed log starting from HEAD, which
+   has been fixed---it now shows nothing.
+
+ * The "tag.pager" configuration variable was useless for those who
+   actually create tag objects, as it interfered with the use of an
+   editor.  A new mechanism has been introduced for commands to enable
+   pager depending on what operation is being carried out to fix this,
+   and then "git tag -l" is made to run pager by default.
+
+ * "git push --recurse-submodules $there HEAD:$target" was not
+   propagated down to the submodules, but now it is.
+
+ * Commands like "git rebase" accepted the --rerere-autoupdate option
+   from the command line, but did not always use it.  This has been
+   fixed.
+
+ * "git clone --recurse-submodules --quiet" did not pass the quiet
+   option down to submodules.
+
+ * "git am -s" has been taught that some input may end with a trailer
+   block that is not Signed-off-by: and it should refrain from adding
+   an extra blank line before adding a new sign-off in such a case.
+
+ * "git svn" used with "--localtime" option did not compute the tz
+   offset for the timestamp in question and instead always used the
+   current time, which has been corrected.
+
+ * Memory leaks in a few error codepaths have been plugged.
+
+ * bash 4.4 or newer gave a warning on NUL byte in command
+   substitution done in "git stash"; this has been squelched.
+
+ * "git grep -L" and "git grep --quiet -L" reported different exit
+   codes; this has been corrected.
+
+ * When handshake with a subprocess filter notices that the process
+   asked for an unknown capability, Git did not report what program
+   the offending subprocess was running.  This has been corrected.
+
+ * "git apply" that is used as a better "patch -p1" failed to apply a
+   taken from a file with CRLF line endings to a file with CRLF line
+   endings.  The root cause was because it misused convert_to_git()
+   that tried to do "safe-crlf" processing by looking at the index
+   entry at the same path, which is a nonsense---in that mode, "apply"
+   is not working on the data in (or derived from) the index at all.
+   This has been fixed.
+
+ * Killing "git merge --edit" before the editor returns control left
+   the repository in a state with MERGE_MSG but without MERGE_HEAD,
+   which incorrectly tells the subsequent "git commit" that there was
+   a squash merge in progress.  This has been fixed.
+
+ * "git archive" did not work well with pathspecs and the
+   export-ignore attribute.
+
+ * "git cvsserver" no longer is invoked by "git daemon" by default,
+   as it is old and largely unmaintained.
+
+ * Various Perl scripts did not use safe_pipe_capture() instead of
+   backticks, leaving them susceptible to end-user input.  They have
+   been corrected.
+
+Also contains various documentation updates and code clean-ups.
+
+Credits go to joernchen <joernchen@xxxxxxxxxxxx> for finding the
+unsafe constructs in "git cvsserver", and to Jeff King at GitHub for
+finding and fixing instances of the same issue in other scripts.
diff --git a/Documentation/RelNotes/2.14.3.txt b/Documentation/RelNotes/2.14.3.txt
new file mode 100644
index 0000000000..977c9e857c
--- /dev/null
+++ b/Documentation/RelNotes/2.14.3.txt
@@ -0,0 +1,99 @@
+Git v2.14.3 Release Notes
+=========================
+
+Fixes since v2.14.2
+-------------------
+
+ * A helper function to read a single whole line into strbuf
+   mistakenly triggered OOM error at EOF under certain conditions,
+   which has been fixed.
+
+ * In addition to "cc: <a@xxxxxxxx> # cruft", "cc: a@xxxxxxxx # cruft"
+   was taught to "git send-email" as a valid way to tell it that it
+   needs to also send a carbon copy to <a@xxxxxxxx> in the trailer
+   section.
+
+ * Fix regression to "gitk --bisect" by a recent update.
+
+ * Unlike "git commit-tree < file", "git commit-tree -F file" did not
+   pass the contents of the file verbatim and instead completed an
+   incomplete line at the end, if exists.  The latter has been updated
+   to match the behaviour of the former.
+
+ * "git archive", especially when used with pathspec, stored an empty
+   directory in its output, even though Git itself never does so.
+   This has been fixed.
+
+ * API error-proofing which happens to also squelch warnings from GCC.
+
+ * "git gc" tries to avoid running two instances at the same time by
+   reading and writing pid/host from and to a lock file; it used to
+   use an incorrect fscanf() format when reading, which has been
+   corrected.
+
+ * The test linter has been taught that we do not like "echo -e".
+
+ * Code cmp.std.c nitpick.
+
+ * "git describe --match" learned to take multiple patterns in v2.13
+   series, but the feature ignored the patterns after the first one
+   and did not work at all.  This has been fixed.
+
+ * "git cat-file --textconv" started segfaulting recently, which
+   has been corrected.
+
+ * The built-in pattern to detect the "function header" for HTML did
+   not match <H1>..<H6> elements without any attributes, which has
+   been fixed.
+
+ * "git mailinfo" was loose in decoding quoted printable and produced
+   garbage when the two letters after the equal sign are not
+   hexadecimal.  This has been fixed.
+
+ * The documentation for '-X<option>' for merges was misleadingly
+   written to suggest that "-s theirs" exists, which is not the case.
+
+ * Spell the name of our system as "Git" in the output from
+   request-pull script.
+
+ * Fixes for a handful memory access issues identified by valgrind.
+
+ * Backports a moral equivalent of 2015 fix to the poll emulation from
+   the upstream gnulib to fix occasional breakages on HPE NonStop.
+
+ * In the "--format=..." option of the "git for-each-ref" command (and
+   its friends, i.e. the listing mode of "git branch/tag"), "%(atom:)"
+   (e.g. "%(refname:)", "%(body:)" used to error out.  Instead, treat
+   them as if the colon and an empty string that follows it were not
+   there.
+
+ * Users with "color.ui = always" in their configuration were broken
+   by a recent change that made plumbing commands to pay attention to
+   them as the patch created internally by "git add -p" were colored
+   (heh) and made unusable.  This has been fixed.
+
+ * "git branch -M a b" while on a branch that is completely unrelated
+   to either branch a or branch b misbehaved when multiple worktree
+   was in use.  This has been fixed.
+
+ * "git fast-export" with -M/-C option issued "copy" instruction on a
+   path that is simultaneously modified, which was incorrect.
+
+ * The checkpoint command "git fast-import" did not flush updates to
+   refs and marks unless at least one object was created since the
+   last checkpoint, which has been corrected, as these things can
+   happen without any new object getting created.
+
+ * The scripts to drive TravisCI has been reorganized and then an
+   optimization to avoid spending cycles on a branch whose tip is
+   tagged has been implemented.
+
+ * "git fetch <there> <src>:<dst>" allows an object name on the <src>
+   side when the other side accepts such a request since Git v2.5, but
+   the documentation was left stale.
+
+ * A regression in 2.11 that made the code to read the list of
+   alternate object stores overrun the end of the string has been
+   fixed.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.14.4.txt b/Documentation/RelNotes/2.14.4.txt
new file mode 100644
index 0000000000..97755a89d9
--- /dev/null
+++ b/Documentation/RelNotes/2.14.4.txt
@@ -0,0 +1,5 @@
+Git v2.14.4 Release Notes
+=========================
+
+This release is to forward-port the fixes made in the v2.13.7 version
+of Git.  See its release notes for details.
diff --git a/Documentation/RelNotes/2.14.5.txt b/Documentation/RelNotes/2.14.5.txt
new file mode 100644
index 0000000000..130645fb29
--- /dev/null
+++ b/Documentation/RelNotes/2.14.5.txt
@@ -0,0 +1,16 @@
+Git v2.14.5 Release Notes
+=========================
+
+This release is to address the recently reported CVE-2018-17456.
+
+Fixes since v2.14.4
+-------------------
+
+ * Submodules' "URL"s come from the untrusted .gitmodules file, but
+   we blindly gave it to "git clone" to clone submodules when "git
+   clone --recurse-submodules" was used to clone a project that has
+   such a submodule.  The code has been hardened to reject such
+   malformed URLs (e.g. one that begins with a dash).
+
+Credit for finding and fixing this vulnerability goes to joernchen
+and Jeff King, respectively.
diff --git a/Documentation/RelNotes/2.14.6.txt b/Documentation/RelNotes/2.14.6.txt
new file mode 100644
index 0000000000..72b7af6799
--- /dev/null
+++ b/Documentation/RelNotes/2.14.6.txt
@@ -0,0 +1,54 @@
+Git v2.14.6 Release Notes
+=========================
+
+This release addresses the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, and CVE-2019-1387.
+
+Fixes since v2.14.5
+-------------------
+
+ * CVE-2019-1348:
+   The --export-marks option of git fast-import is exposed also via
+   the in-stream command feature export-marks=... and it allows
+   overwriting arbitrary paths.
+
+ * CVE-2019-1349:
+   When submodules are cloned recursively, under certain circumstances
+   Git could be fooled into using the same Git directory twice. We now
+   require the directory to be empty.
+
+ * CVE-2019-1350:
+   Incorrect quoting of command-line arguments allowed remote code
+   execution during a recursive clone in conjunction with SSH URLs.
+
+ * CVE-2019-1351:
+   While the only permitted drive letters for physical drives on
+   Windows are letters of the US-English alphabet, this restriction
+   does not apply to virtual drives assigned via subst <letter>:
+   <path>. Git mistook such paths for relative paths, allowing writing
+   outside of the worktree while cloning.
+
+ * CVE-2019-1352:
+   Git was unaware of NTFS Alternate Data Streams, allowing files
+   inside the .git/ directory to be overwritten during a clone.
+
+ * CVE-2019-1353:
+   When running Git in the Windows Subsystem for Linux (also known as
+   "WSL") while accessing a working directory on a regular Windows
+   drive, none of the NTFS protections were active.
+
+ * CVE-2019-1354:
+   Filenames on Linux/Unix can contain backslashes. On Windows,
+   backslashes are directory separators. Git did not use to refuse to
+   write out tracked files with such filenames.
+
+ * CVE-2019-1387:
+   Recursive clones are currently affected by a vulnerability that is
+   caused by too-lax validation of submodule names, allowing very
+   targeted attacks via remote code execution in recursive clones.
+
+Credit for finding these vulnerabilities goes to Microsoft Security
+Response Center, in particular to Nicolas Joly. The `fast-import`
+fixes were provided by Jeff King, the other fixes by Johannes
+Schindelin with help from Garima Singh.
diff --git a/Documentation/RelNotes/2.15.0.txt b/Documentation/RelNotes/2.15.0.txt
new file mode 100644
index 0000000000..cdd761bcc2
--- /dev/null
+++ b/Documentation/RelNotes/2.15.0.txt
@@ -0,0 +1,508 @@
+Git 2.15 Release Notes
+======================
+
+Backward compatibility notes and other notable changes.
+
+ * Use of an empty string as a pathspec element that is used for
+   'everything matches' is still warned and Git asks users to use a
+   more explicit '.' for that instead.  The hope is that existing
+   users will not mind this change, and eventually the warning can be
+   turned into a hard error, upgrading the deprecation into removal of
+   this (mis)feature.  That is now scheduled to happen in Git v2.16,
+   the next major release after this one.
+
+ * Git now avoids blindly falling back to ".git" when the setup
+   sequence said we are _not_ in Git repository.  A corner case that
+   happens to work right now may be broken by a call to BUG().
+   We've tried hard to locate such cases and fixed them, but there
+   might still be cases that need to be addressed--bug reports are
+   greatly appreciated.
+
+ * "branch --set-upstream" that has been deprecated in Git 1.8 has
+   finally been retired.
+
+
+Updates since v2.14
+-------------------
+
+UI, Workflows & Features
+
+ * An example that is now obsolete has been removed from a sample hook,
+   and an old example in it that added a sign-off manually has been
+   improved to use the interpret-trailers command.
+
+ * The advice message given when "git rebase" stops for conflicting
+   changes has been improved.
+
+ * The "rerere-train" script (in contrib/) learned the "--overwrite"
+   option to allow overwriting existing recorded resolutions.
+
+ * "git contacts" (in contrib/) now lists the address on the
+   "Reported-by:" trailer to its output, in addition to those on
+   S-o-b: and other trailers, to make it easier to notify (and thank)
+   the original bug reporter.
+
+ * "git rebase", especially when it is run by mistake and ends up
+   trying to replay many changes, spent long time in silence.  The
+   command has been taught to show progress report when it spends
+   long time preparing these many changes to replay (which would give
+   the user a chance to abort with ^C).
+
+ * "git merge" learned a "--signoff" option to add the Signed-off-by:
+   trailer with the committer's name.
+
+ * "git diff" learned to optionally paint new lines that are the same
+   as deleted lines elsewhere differently from genuinely new lines.
+
+ * "git interpret-trailers" learned to take the trailer specifications
+   from the command line that overrides the configured values.
+
+ * "git interpret-trailers" has been taught a "--parse" and a few
+   other options to make it easier for scripts to grab existing
+   trailer lines from a commit log message.
+
+ * The "--format=%(trailers)" option "git log" and its friends take
+   learned to take the 'unfold' and 'only' modifiers to normalize its
+   output, e.g. "git log --format=%(trailers:only,unfold)".
+
+ * "gitweb" shows a link to visit the 'raw' contents of blobs in the
+   history overview page.
+
+ * "[gc] rerereResolved = 5.days" used to be invalid, as the variable
+   is defined to take an integer counting the number of days.  It now
+   is allowed.
+
+ * The code to acquire a lock on a reference (e.g. while accepting a
+   push from a client) used to immediately fail when the reference is
+   already locked---now it waits for a very short while and retries,
+   which can make it succeed if the lock holder was holding it during
+   a read-only operation.
+
+ * "branch --set-upstream" that has been deprecated in Git 1.8 has
+   finally been retired.
+
+ * The codepath to call external process filter for smudge/clean
+   operation learned to show the progress meter.
+
+ * "git rev-parse" learned "--is-shallow-repository", that is to be
+   used in a way similar to existing "--is-bare-repository" and
+   friends.
+
+ * "git describe --match <pattern>" has been taught to play well with
+   the "--all" option.
+
+ * "git branch" learned "-c/-C" to create a new branch by copying an
+   existing one.
+
+ * Some commands (most notably "git status") makes an opportunistic
+   update when performing a read-only operation to help optimize later
+   operations in the same repository.  The new "--no-optional-locks"
+   option can be passed to Git to disable them.
+
+ * "git for-each-ref --format=..." learned a new format element,
+   %(trailers), to show only the commit log trailer part of the log
+   message.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * Start using selected c99 constructs in small, stable and
+   essential part of the system to catch people who care about
+   older compilers that do not grok them.
+
+ * The filter-process interface learned to allow a process with long
+   latency give a "delayed" response.
+
+ * Many uses of comparison callback function the hashmap API uses
+   cast the callback function type when registering it to
+   hashmap_init(), which defeats the compile time type checking when
+   the callback interface changes (e.g. gaining more parameters).
+   The callback implementations have been updated to take "void *"
+   pointers and cast them to the type they expect instead.
+
+ * Because recent Git for Windows do come with a real msgfmt, the
+   build procedure for git-gui has been updated to use it instead of a
+   hand-rolled substitute.
+
+ * "git grep --recurse-submodules" has been reworked to give a more
+   consistent output across submodule boundary (and do its thing
+   without having to fork a separate process).
+
+ * A helper function to read a single whole line into strbuf
+   mistakenly triggered OOM error at EOF under certain conditions,
+   which has been fixed.
+
+ * The "ref-store" code reorganization continues.
+
+ * "git commit" used to discard the index and re-read from the filesystem
+   just in case the pre-commit hook has updated it in the middle; this
+   has been optimized out when we know we do not run the pre-commit hook.
+   (merge 680ee550d7 kw/commit-keep-index-when-pre-commit-is-not-run later to maint).
+
+ * Updates to the HTTP layer we made recently unconditionally used
+   features of libCurl without checking the existence of them, causing
+   compilation errors, which has been fixed.  Also migrate the code to
+   check feature macros, not version numbers, to cope better with
+   libCurl that vendor ships with backported features.
+
+ * The API to start showing progress meter after a short delay has
+   been simplified.
+   (merge 8aade107dd jc/simplify-progress later to maint).
+
+ * Code clean-up to avoid mixing values read from the .gitmodules file
+   and values read from the .git/config file.
+
+ * We used to spend more than necessary cycles allocating and freeing
+   piece of memory while writing each index entry out.  This has been
+   optimized.
+
+ * Platforms that ship with a separate sha1 with collision detection
+   library can link to it instead of using the copy we ship as part of
+   our source tree.
+
+ * Code around "notes" have been cleaned up.
+   (merge 3964281524 mh/notes-cleanup later to maint).
+
+ * The long-standing rule that an in-core lockfile instance, once it
+   is used, must not be freed, has been lifted and the lockfile and
+   tempfile APIs have been updated to reduce the chance of programming
+   errors.
+
+ * Our hashmap implementation in hashmap.[ch] is not thread-safe when
+   adding a new item needs to expand the hashtable by rehashing; add
+   an API to disable the automatic rehashing to work it around.
+
+ * Many of our programs consider that it is OK to release dynamic
+   storage that is used throughout the life of the program by simply
+   exiting, but this makes it harder to leak detection tools to avoid
+   reporting false positives.  Plug many existing leaks and introduce
+   a mechanism for developers to mark that the region of memory
+   pointed by a pointer is not lost/leaking to help these tools.
+
+ * As "git commit" to conclude a conflicted "git merge" honors the
+   commit-msg hook, "git merge" that records a merge commit that
+   cleanly auto-merges should, but it didn't.
+
+ * The codepath for "git merge-recursive" has been cleaned up.
+
+ * Many leaks of strbuf have been fixed.
+
+ * "git imap-send" has our own implementation of the protocol and also
+   can use more recent libCurl with the imap protocol support.  Update
+   the latter so that it can use the credential subsystem, and then
+   make it the default option to use, so that we can eventually
+   deprecate and remove the former.
+
+ * "make style" runs git-clang-format to help developers by pointing
+   out coding style issues.
+
+ * A test to demonstrate "git mv" failing to adjust nested submodules
+   has been added.
+   (merge c514167df2 hv/mv-nested-submodules-test later to maint).
+
+ * On Cygwin, "ulimit -s" does not report failure but it does not work
+   at all, which causes an unexpected success of some tests that
+   expect failures under a limited stack situation.  This has been
+   fixed.
+
+ * Many codepaths have been updated to squelch -Wimplicit-fallthrough
+   warnings from Gcc 7 (which is a good code hygiene).
+
+ * Add a helper for DLL loading in anticipation for its need in a
+   future topic RSN.
+
+ * "git status --ignored", when noticing that a directory without any
+   tracked path is ignored, still enumerated all the ignored paths in
+   the directory, which is unnecessary.  The codepath has been
+   optimized to avoid this overhead.
+
+ * The final batch to "git rebase -i" updates to move more code from
+   the shell script to C has been merged.
+
+ * Operations that do not touch (majority of) packed refs have been
+   optimized by making accesses to packed-refs file lazy; we no longer
+   pre-parse everything, and an access to a single ref in the
+   packed-refs does not touch majority of irrelevant refs, either.
+
+ * Add comment to clarify that the style file is meant to be used with
+   clang-5 and the rules are still work in progress.
+
+ * Many variables that points at a region of memory that will live
+   throughout the life of the program have been marked with UNLEAK
+   marker to help the leak checkers concentrate on real leaks..
+
+ * Plans for weaning us off of SHA-1 has been documented.
+
+ * A new "oidmap" API has been introduced and oidset API has been
+   rewritten to use it.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.14
+-----------------
+
+ * "%C(color name)" in the pretty print format always produced ANSI
+   color escape codes, which was an early design mistake.  They now
+   honor the configuration (e.g. "color.ui = never") and also tty-ness
+   of the output medium.
+
+ * The http.{sslkey,sslCert} configuration variables are to be
+   interpreted as a pathname that honors "~[username]/" prefix, but
+   weren't, which has been fixed.
+
+ * Numerous bugs in walking of reflogs via "log -g" and friends have
+   been fixed.
+
+ * "git commit" when seeing an totally empty message said "you did not
+   edit the message", which is clearly wrong.  The message has been
+   corrected.
+
+ * When a directory is not readable, "gitweb" fails to build the
+   project list.  Work this around by skipping such a directory.
+
+ * Some versions of GnuPG fails to kill gpg-agent it auto-spawned
+   and such a left-over agent can interfere with a test.  Work it
+   around by attempting to kill one before starting a new test.
+
+ * A recently added test for the "credential-cache" helper revealed
+   that EOF detection done around the time the connection to the cache
+   daemon is torn down were flaky.  This was fixed by reacting to
+   ECONNRESET and behaving as if we got an EOF.
+
+ * "git log --tag=no-such-tag" showed log starting from HEAD, which
+   has been fixed---it now shows nothing.
+
+ * The "tag.pager" configuration variable was useless for those who
+   actually create tag objects, as it interfered with the use of an
+   editor.  A new mechanism has been introduced for commands to enable
+   pager depending on what operation is being carried out to fix this,
+   and then "git tag -l" is made to run pager by default.
+
+ * "git push --recurse-submodules $there HEAD:$target" was not
+   propagated down to the submodules, but now it is.
+
+ * Commands like "git rebase" accepted the --rerere-autoupdate option
+   from the command line, but did not always use it.  This has been
+   fixed.
+
+ * "git clone --recurse-submodules --quiet" did not pass the quiet
+   option down to submodules.
+
+ * Test portability fix for OBSD.
+
+ * Portability fix for OBSD.
+
+ * "git am -s" has been taught that some input may end with a trailer
+   block that is not Signed-off-by: and it should refrain from adding
+   an extra blank line before adding a new sign-off in such a case.
+
+ * "git svn" used with "--localtime" option did not compute the tz
+   offset for the timestamp in question and instead always used the
+   current time, which has been corrected.
+
+ * Memory leak in an error codepath has been plugged.
+
+ * "git stash -u" used the contents of the committed version of the
+   ".gitignore" file to decide which paths are ignored, even when the
+   file has local changes.  The command has been taught to instead use
+   the locally modified contents.
+
+ * bash 4.4 or newer gave a warning on NUL byte in command
+   substitution done in "git stash"; this has been squelched.
+
+ * "git grep -L" and "git grep --quiet -L" reported different exit
+   codes; this has been corrected.
+
+ * When handshake with a subprocess filter notices that the process
+   asked for an unknown capability, Git did not report what program
+   the offending subprocess was running.  This has been corrected.
+
+ * "git apply" that is used as a better "patch -p1" failed to apply a
+   taken from a file with CRLF line endings to a file with CRLF line
+   endings.  The root cause was because it misused convert_to_git()
+   that tried to do "safe-crlf" processing by looking at the index
+   entry at the same path, which is a nonsense---in that mode, "apply"
+   is not working on the data in (or derived from) the index at all.
+   This has been fixed.
+
+ * Killing "git merge --edit" before the editor returns control left
+   the repository in a state with MERGE_MSG but without MERGE_HEAD,
+   which incorrectly tells the subsequent "git commit" that there was
+   a squash merge in progress.  This has been fixed.
+
+ * "git archive" did not work well with pathspecs and the
+   export-ignore attribute.
+
+ * In addition to "cc: <a@xxxxxxxx> # cruft", "cc: a@xxxxxxxx # cruft"
+   was taught to "git send-email" as a valid way to tell it that it
+   needs to also send a carbon copy to <a@xxxxxxxx> in the trailer
+   section.
+
+ * "git branch -M a b" while on a branch that is completely unrelated
+   to either branch a or branch b misbehaved when multiple worktree
+   was in use.  This has been fixed.
+   (merge 31824d180d nd/worktree-kill-parse-ref later to maint).
+
+ * "git gc" and friends when multiple worktrees are used off of a
+   single repository did not consider the index and per-worktree refs
+   of other worktrees as the root for reachability traversal, making
+   objects that are in use only in other worktrees to be subject to
+   garbage collection.
+
+ * A regression to "gitk --bisect" by a recent update has been fixed.
+
+ * "git -c submodule.recurse=yes pull" did not work as if the
+   "--recurse-submodules" option was given from the command line.
+   This has been corrected.
+
+ * Unlike "git commit-tree < file", "git commit-tree -F file" did not
+   pass the contents of the file verbatim and instead completed an
+   incomplete line at the end, if exists.  The latter has been updated
+   to match the behaviour of the former.
+
+ * Many codepaths did not diagnose write failures correctly when disks
+   go full, due to their misuse of write_in_full() helper function,
+   which have been corrected.
+   (merge f48ecd38cb jk/write-in-full-fix later to maint).
+
+ * "git help co" now says "co is aliased to ...", not "git co is".
+   (merge b3a8076e0d ks/help-alias-label later to maint).
+
+ * "git archive", especially when used with pathspec, stored an empty
+   directory in its output, even though Git itself never does so.
+   This has been fixed.
+
+ * API error-proofing which happens to also squelch warnings from GCC.
+
+ * The explanation of the cut-line in the commit log editor has been
+   slightly tweaked.
+   (merge 8c4b1a3593 ks/commit-do-not-touch-cut-line later to maint).
+
+ * "git gc" tries to avoid running two instances at the same time by
+   reading and writing pid/host from and to a lock file; it used to
+   use an incorrect fscanf() format when reading, which has been
+   corrected.
+
+ * The scripts to drive TravisCI has been reorganized and then an
+   optimization to avoid spending cycles on a branch whose tip is
+   tagged has been implemented.
+   (merge 8376eb4a8f ls/travis-scriptify later to maint).
+
+ * The test linter has been taught that we do not like "echo -e".
+
+ * Code cmp.std.c nitpick.
+
+ * A regression fix for 2.11 that made the code to read the list of
+   alternate object stores overrun the end of the string.
+   (merge f0f7bebef7 jk/info-alternates-fix later to maint).
+
+ * "git describe --match" learned to take multiple patterns in v2.13
+   series, but the feature ignored the patterns after the first one
+   and did not work at all.  This has been fixed.
+
+ * "git filter-branch" cannot reproduce a history with a tag without
+   the tagger field, which only ancient versions of Git allowed to be
+   created.  This has been corrected.
+   (merge b2c1ca6b4b ic/fix-filter-branch-to-handle-tag-without-tagger later to maint).
+
+ * "git cat-file --textconv" started segfaulting recently, which
+   has been corrected.
+
+ * The built-in pattern to detect the "function header" for HTML did
+   not match <H1>..<H6> elements without any attributes, which has
+   been fixed.
+
+ * "git mailinfo" was loose in decoding quoted printable and produced
+   garbage when the two letters after the equal sign are not
+   hexadecimal.  This has been fixed.
+
+ * The machinery to create xdelta used in pack files received the
+   sizes of the data in size_t, but lost the higher bits of them by
+   storing them in "unsigned int" during the computation, which is
+   fixed.
+
+ * The delta format used in the packfile cannot reference data at
+   offset larger than what can be expressed in 4-byte, but the
+   generator for the data failed to make sure the offset does not
+   overflow.  This has been corrected.
+
+ * The documentation for '-X<option>' for merges was misleadingly
+   written to suggest that "-s theirs" exists, which is not the case.
+
+ * "git fast-export" with -M/-C option issued "copy" instruction on a
+   path that is simultaneously modified, which was incorrect.
+   (merge b3e8ca89cf jt/fast-export-copy-modify-fix later to maint).
+
+ * Many codepaths have been updated to squelch -Wsign-compare
+   warnings.
+   (merge 071bcaab64 rj/no-sign-compare later to maint).
+
+ * Memory leaks in various codepaths have been plugged.
+   (merge 4d01a7fa65 ma/leakplugs later to maint).
+
+ * Recent versions of "git rev-parse --parseopt" did not parse the
+   option specification that does not have the optional flags (*=?!)
+   correctly, which has been corrected.
+   (merge a6304fa4c2 bc/rev-parse-parseopt-fix later to maint).
+
+ * The checkpoint command "git fast-import" did not flush updates to
+   refs and marks unless at least one object was created since the
+   last checkpoint, which has been corrected, as these things can
+   happen without any new object getting created.
+   (merge 30e215a65c er/fast-import-dump-refs-on-checkpoint later to maint).
+
+ * Spell the name of our system as "Git" in the output from
+   request-pull script.
+
+ * Fixes for a handful memory access issues identified by valgrind.
+
+ * Backports a moral equivalent of 2015 fix to the poll() emulation
+   from the upstream gnulib to fix occasional breakages on HPE NonStop.
+
+ * Users with "color.ui = always" in their configuration were broken
+   by a recent change that made plumbing commands to pay attention to
+   them as the patch created internally by "git add -p" were colored
+   (heh) and made unusable.  This has been fixed by reverting the
+   offending change.
+
+ * In the "--format=..." option of the "git for-each-ref" command (and
+   its friends, i.e. the listing mode of "git branch/tag"), "%(atom:)"
+   (e.g. "%(refname:)", "%(body:)" used to error out.  Instead, treat
+   them as if the colon and an empty string that follows it were not
+   there.
+
+ * An ancient bug that made Git misbehave with creation/renaming of
+   refs has been fixed.
+
+ * "git fetch <there> <src>:<dst>" allows an object name on the <src>
+   side when the other side accepts such a request since Git v2.5, but
+   the documentation was left stale.
+   (merge 83558a412a jc/fetch-refspec-doc-update later to maint).
+
+ * Update the documentation for "git filter-branch" so that the filter
+   options are listed in the same order as they are applied, as
+   described in an earlier part of the doc.
+   (merge 07c4984508 dg/filter-branch-filter-order-doc later to maint).
+
+ * A possible oom error is now caught as a fatal error, instead of
+   continuing and dereferencing NULL.
+   (merge 55d7d15847 ao/path-use-xmalloc later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge f094b89a4d ma/parse-maybe-bool later to maint).
+   (merge 6cdf8a7929 ma/ts-cleanups later to maint).
+   (merge 7560f547e6 ma/up-to-date later to maint).
+   (merge 0db3dc75f3 rs/apply-epoch later to maint).
+   (merge 276d0e35c0 ma/split-symref-update-fix later to maint).
+   (merge f777623514 ks/branch-tweak-error-message-for-extra-args later to maint).
+   (merge 33f3c683ec ks/verify-filename-non-option-error-message-tweak later to maint).
+   (merge 7cbbf9d6a2 ls/filter-process-delayed later to maint).
+   (merge 488aa65c8f wk/merge-options-gpg-sign-doc later to maint).
+   (merge e61cb19a27 jc/branch-force-doc-readability-fix later to maint).
+   (merge 32fceba3fd np/config-path-doc later to maint).
+   (merge e38c681fb7 sb/rev-parse-show-superproject-root later to maint).
+   (merge 4f851dc883 sg/rev-list-doc-reorder-fix later to maint).
diff --git a/Documentation/RelNotes/2.15.1.txt b/Documentation/RelNotes/2.15.1.txt
new file mode 100644
index 0000000000..ec06704e63
--- /dev/null
+++ b/Documentation/RelNotes/2.15.1.txt
@@ -0,0 +1,88 @@
+Git v2.15.1 Release Notes
+=========================
+
+Fixes since v2.15
+-----------------
+
+ * TravisCI build updates.
+
+ * "auto" as a value for the columnar output configuration ought to
+   judge "is the output consumed by humans?" with the same criteria as
+   "auto" for coloured output configuration, i.e. either the standard
+   output stream is going to tty, or a pager is in use.  We forgot the
+   latter, which has been fixed.
+
+ * The experimental "color moved lines differently in diff output"
+   feature was buggy around "ignore whitespace changes" edges, which
+   has been corrected.
+
+ * Instead of using custom line comparison and hashing functions to
+   implement "moved lines" coloring in the diff output, use the pair
+   of these functions from lower-layer xdiff/ code.
+
+ * Some codepaths did not check for errors when asking what branch the
+   HEAD points at, which have been fixed.
+
+ * "git commit", after making a commit, did not check for errors when
+   asking on what branch it made the commit, which has been corrected.
+
+ * "git status --ignored -u" did not stop at a working tree of a
+   separate project that is embedded in an ignored directory and
+   listed files in that other project, instead of just showing the
+   directory itself as ignored.
+
+ * A broken access to object databases in recent update to "git grep
+   --recurse-submodules" has been fixed.
+
+ * A recent regression in "git rebase -i" that broke execution of git
+   commands from subdirectories via "exec" instruction has been fixed.
+
+ * "git check-ref-format --branch @{-1}" bit a "BUG()" when run
+   outside a repository for obvious reasons; clarify the documentation
+   and make sure we do not even try to expand the at-mark magic in
+   such a case, but still call the validation logic for branch names.
+
+ * Command line completion (in contrib/) update.
+
+ * Description of blame.{showroot,blankboundary,showemail,date}
+   configuration variables have been added to "git config --help".
+
+ * After an error from lstat(), diff_populate_filespec() function
+   sometimes still went ahead and used invalid data in struct stat,
+   which has been fixed.
+
+ * UNC paths are also relevant in Cygwin builds and they are now
+   tested just like Mingw builds.
+
+ * Correct start-up sequence so that a repository could be placed
+   immediately under the root directory again (which was broken at
+   around Git 2.13).
+
+ * The credential helper for libsecret (in contrib/) has been improved
+   to allow possibly prompting the end user to unlock secrets that are
+   currently locked (otherwise the secrets may not be loaded).
+
+ * Updates from GfW project.
+
+ * "git rebase -i" recently started misbehaving when a submodule that
+   is configured with 'submodule.<name>.ignore' is dirty; this has
+   been corrected.
+
+ * Some error messages did not quote filenames shown in it, which have
+   been fixed.
+
+ * Building with NO_LIBPCRE1_JIT did not disable it, which has been fixed.
+
+ * We used to add an empty alternate object database to the system
+   that does not help anything; it has been corrected.
+
+ * Error checking in "git imap-send" for empty response has been
+   improved.
+
+ * An ancient bug in "git apply --ignore-space-change" codepath has
+   been fixed.
+
+ * There was a recent semantic mismerge in the codepath to write out a
+   section of a configuration section, which has been corrected.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.15.2.txt b/Documentation/RelNotes/2.15.2.txt
new file mode 100644
index 0000000000..b480e56b68
--- /dev/null
+++ b/Documentation/RelNotes/2.15.2.txt
@@ -0,0 +1,50 @@
+Git v2.15.2 Release Notes
+=========================
+
+Fixes since v2.15.1
+-------------------
+
+ * Recent update to the refs infrastructure implementation started
+   rewriting packed-refs file more often than before; this has been
+   optimized again for most trivial cases.
+
+ * The SubmittingPatches document has been converted to produce an
+   HTML version via AsciiDoc/Asciidoctor.
+
+ * Contrary to the documentation, "git pull -4/-6 other-args" did not
+   ask the underlying "git fetch" to go over IPv4/IPv6, which has been
+   corrected.
+
+ * When "git rebase" prepared an mailbox of changes and fed it to "git
+   am" to replay them, it was confused when a stray "From " happened
+   to be in the log message of one of the replayed changes.  This has
+   been corrected.
+
+ * Command line completion (in contrib/) has been taught about the
+   "--copy" option of "git branch".
+
+ * "git apply --inaccurate-eof" when used with "--ignore-space-change"
+   triggered an internal sanity check, which has been fixed.
+
+ * The sequencer machinery (used by "git cherry-pick A..B", and "git
+   rebase -i", among other things) would have lost a commit if stopped
+   due to an unlockable index file, which has been fixed.
+
+ * The three-way merge performed by "git cherry-pick" was confused
+   when a new submodule was added in the meantime, which has been
+   fixed (or "papered over").
+
+ * "git notes" sent its error message to its standard output stream,
+   which was corrected.
+
+ * A few scripts (both in production and tests) incorrectly redirected
+   their error output.  These have been corrected.
+
+ * Clarify and enhance documentation for "merge-base --fork-point", as
+   it was clear what it computed but not why/what for.
+
+ * This release also contains the fixes made in the v2.13.7 version of
+   Git.  See its release notes for details.
+
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.15.3.txt b/Documentation/RelNotes/2.15.3.txt
new file mode 100644
index 0000000000..fd2e6f8df7
--- /dev/null
+++ b/Documentation/RelNotes/2.15.3.txt
@@ -0,0 +1,6 @@
+Git v2.15.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.5 to address
+the recently reported CVE-2018-17456; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.15.4.txt b/Documentation/RelNotes/2.15.4.txt
new file mode 100644
index 0000000000..dc241cba34
--- /dev/null
+++ b/Documentation/RelNotes/2.15.4.txt
@@ -0,0 +1,11 @@
+Git v2.15.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6 to address
+the security issues CVE-2019-1348, CVE-2019-1349, CVE-2019-1350,
+CVE-2019-1351, CVE-2019-1352, CVE-2019-1353, CVE-2019-1354, and
+CVE-2019-1387; see the release notes for that version for details.
+
+In conjunction with a vulnerability that was fixed in v2.20.2,
+`.gitmodules` is no longer allowed to contain entries of the form
+`submodule.<name>.update=!command`.
diff --git a/Documentation/RelNotes/2.16.0.txt b/Documentation/RelNotes/2.16.0.txt
new file mode 100644
index 0000000000..b474781ed8
--- /dev/null
+++ b/Documentation/RelNotes/2.16.0.txt
@@ -0,0 +1,482 @@
+Git 2.16 Release Notes
+======================
+
+Backward compatibility notes and other notable changes.
+
+ * Use of an empty string as a pathspec element that is used for
+   'everything matches' is now an error.
+
+
+Updates since v2.15
+-------------------
+
+UI, Workflows & Features
+
+ * An empty string as a pathspec element that means "everything"
+   i.e. 'git add ""', is now illegal.  We started this by first
+   deprecating and warning a pathspec that has such an element in
+   2.11 (Nov 2016).
+
+ * A hook script that is set unexecutable is simply ignored.  Git
+   notifies when such a file is ignored, unless the message is
+   squelched via advice.ignoredHook configuration.
+
+ * "git pull" has been taught to accept "--[no-]signoff" option and
+   pass it down to "git merge".
+
+ * The "--push-option=<string>" option to "git push" now defaults to a
+   list of strings configured via push.pushOption variable.
+
+ * "gitweb" checks if a directory is searchable with Perl's "-x"
+   operator, which can be enhanced by using "filetest 'access'"
+   pragma, which now we do.
+
+ * "git stash save" has been deprecated in favour of "git stash push".
+
+ * The set of paths output from "git status --ignored" was tied
+   closely with its "--untracked=<mode>" option, but now it can be
+   controlled more flexibly.  Most notably, a directory that is
+   ignored because it is listed to be ignored in the ignore/exclude
+   mechanism can be handled differently from a directory that ends up
+   to be ignored only because all files in it are ignored.
+
+ * The remote-helper for talking to MediaWiki has been updated to
+   truncate an overlong pagename so that ".mw" suffix can still be
+   added.
+
+ * The remote-helper for talking to MediaWiki has been updated to
+   work with mediawiki namespaces.
+
+ * The "--format=..." option "git for-each-ref" takes learned to show
+   the name of the 'remote' repository and the ref at the remote side
+   that is affected for 'upstream' and 'push' via "%(push:remotename)"
+   and friends.
+
+ * Doc and message updates to teach users "bisect view" is a synonym
+   for "bisect visualize".
+
+ * "git bisect run" that did not specify any command to run used to go
+   ahead and treated all commits to be tested as 'good'.  This has
+   been corrected by making the command error out.
+
+ * The SubmittingPatches document has been converted to produce an
+   HTML version via AsciiDoc/Asciidoctor.
+
+ * We learned to optionally talk to a file system monitor via new
+   fsmonitor extension to speed up "git status" and other operations
+   that need to see which paths have been modified.  Currently we only
+   support "watchman".  See File System Monitor section of
+   git-update-index(1) for more detail.
+
+ * The "diff" family of commands learned to ignore differences in
+   carriage return at the end of line.
+
+ * Places that know about "sendemail.to", like documentation and shell
+   completion (in contrib/) have been taught about "sendemail.tocmd",
+   too.
+
+ * "git add --renormalize ." is a new and safer way to record the fact
+   that you are correcting the end-of-line convention and other
+   "convert_to_git()" glitches in the in-repository data.
+
+ * "git branch" and "git checkout -b" are now forbidden from creating
+   a branch whose name is "HEAD".
+
+ * "git branch --list" learned to show its output through the pager by
+   default when the output is going to a terminal, which is controlled
+   by the pager.branch configuration variable.  This is similar to a
+   recent change to "git tag --list".
+
+ * "git grep -W", "git diff -W" and their friends learned a heuristic
+   to extend a pre-context beyond the line that matches the "function
+   pattern" (aka "diff.*.xfuncname") to include a comment block, if
+   exists, that immediately precedes it.
+
+ * "git config --expiry-date gc.reflogexpire" can read "2.weeks" from
+   the configuration and report it as a timestamp, just like "--int"
+   would read "1k" and report 1024, to help consumption by scripts.
+
+ * The shell completion (in contrib/) learned that "git pull" can take
+   the "--autostash" option.
+
+ * The tagnames "git log --decorate" uses to annotate the commits can
+   now be limited to subset of available refs with the two additional
+   options, --decorate-refs[-exclude]=<pattern>.
+
+ * "git grep" compiled with libpcre2 sometimes triggered a segfault,
+   which is being fixed.
+
+ * "git send-email" tries to see if the sendmail program is available
+   in /usr/lib and /usr/sbin; extend the list of locations to be
+   checked to also include directories on $PATH.
+
+ * "git diff" learned, "--anchored", a variant of the "--patience"
+   algorithm, to which the user can specify which 'unique' line to be
+   used as anchoring points.
+
+ * The way "git worktree add" determines what branch to create from
+   where and checkout in the new worktree has been updated a bit.
+
+ * Ancient part of codebase still shows dots after an abbreviated
+   object name just to show that it is not a full object name, but
+   these ellipses are confusing to people who newly discovered Git
+   who are used to seeing abbreviated object names and find them
+   confusing with the range syntax.
+
+ * With a configuration variable rebase.abbreviateCommands set,
+   "git rebase -i" produces the todo list with a single-letter
+   command names.
+
+ * "git worktree add" learned to run the post-checkout hook, just like
+   "git checkout" does, after the initial checkout.
+
+ * "git svn" has been updated to strip CRs in the commit messages, as
+   recent versions of Subversion rejects them.
+
+ * "git imap-send" did not correctly quote the folder name when
+   making a request to the server, which has been corrected.
+
+ * Error messages from "git rebase" have been somewhat cleaned up.
+
+ * Git has been taught to support an https:// URL used for http.proxy
+   when using recent versions of libcurl.
+
+ * "git merge" learned to pay attention to merge.verifySignatures
+   configuration variable and pretend as if '--verify-signatures'
+   option was given from the command line.
+
+ * "git describe" was taught to dig trees deeper to find a
+   <commit-ish>:<path> that refers to a given blob object.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * An earlier update made it possible to use an on-stack in-core
+   lockfile structure (as opposed to having to deliberately leak an
+   on-heap one).  Many codepaths have been updated to take advantage
+   of this new facility.
+
+ * Calling cmd_foo() as if it is a general purpose helper function is
+   a no-no.  Correct two instances of such to set an example.
+
+ * We try to see if somebody runs our test suite with a shell that
+   does not support "local" like bash/dash does.
+
+ * An early part of piece-by-piece rewrite of "git bisect" in C.
+
+ * GSoC to piece-by-piece rewrite "git submodule" in C.
+
+ * Optimize the code to find shortest unique prefix of object names.
+
+ * Pathspec-limited revision traversal was taught not to keep finding
+   unneeded differences once it knows two trees are different inside
+   given pathspec.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * Code cleanup.
+
+ * A single-word "unsigned flags" in the diff options is being split
+   into a structure with many bitfields.
+
+ * TravisCI build updates.
+
+ * Parts of a test to drive the long-running content filter interface
+   has been split into its own module, hopefully to eventually become
+   reusable.
+
+ * Drop (perhaps overly cautious) sanity check before using the index
+   read from the filesystem at runtime.
+
+ * The build procedure has been taught to avoid some unnecessary
+   instability in the build products.
+
+ * A new mechanism to upgrade the wire protocol in place is proposed
+   and demonstrated that it works with the older versions of Git
+   without harming them.
+
+ * An infrastructure to define what hash function is used in Git is
+   introduced, and an effort to plumb that throughout various
+   codepaths has been started.
+
+ * The code to iterate over loose object files got optimized.
+
+ * An internal function that was left for backward compatibility has
+   been removed, as there is no remaining callers.
+
+ * Historically, the diff machinery for rename detection had a
+   hardcoded limit of 32k paths; this is being lifted to allow users
+   trade cycles with a (possibly) easier to read result.
+
+ * The tracing infrastructure has been optimized for cases where no
+   tracing is requested.
+
+ * In preparation for implementing narrow/partial clone, the object
+   walking machinery has been taught a way to tell it to "filter" some
+   objects from enumeration.
+
+ * A few structures and variables that are implementation details of
+   the decorate API have been renamed and then the API got documented
+   better.
+
+ * Assorted updates for TravisCI integration.
+   (merge 4f26366679 sg/travis-fixes later to maint).
+
+ * Introduce a helper to simplify code to parse a common pattern that
+   expects either "--key" or "--key=<something>".
+
+ * "git version --build-options" learned to report the host CPU and
+   the exact commit object name the binary was built from.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.15
+-----------------
+
+ * "auto" as a value for the columnar output configuration ought to
+   judge "is the output consumed by humans?" with the same criteria as
+   "auto" for coloured output configuration, i.e. either the standard
+   output stream is going to tty, or a pager is in use.  We forgot the
+   latter, which has been fixed.
+
+ * The experimental "color moved lines differently in diff output"
+   feature was buggy around "ignore whitespace changes" edges, which
+   has been corrected.
+
+ * Instead of using custom line comparison and hashing functions to
+   implement "moved lines" coloring in the diff output, use the pair
+   of these functions from lower-layer xdiff/ code.
+
+ * Some codepaths did not check for errors when asking what branch the
+   HEAD points at, which have been fixed.
+
+ * "git commit", after making a commit, did not check for errors when
+   asking on what branch it made the commit, which has been corrected.
+
+ * "git status --ignored -u" did not stop at a working tree of a
+   separate project that is embedded in an ignored directory and
+   listed files in that other project, instead of just showing the
+   directory itself as ignored.
+
+ * A broken access to object databases in recent update to "git grep
+   --recurse-submodules" has been fixed.
+
+ * A recent regression in "git rebase -i" that broke execution of git
+   commands from subdirectories via "exec" instruction has been fixed.
+
+ * A (possibly flakey) test fix.
+
+ * "git check-ref-format --branch @{-1}" bit a "BUG()" when run
+   outside a repository for obvious reasons; clarify the documentation
+   and make sure we do not even try to expand the at-mark magic in
+   such a case, but still call the validation logic for branch names.
+
+ * "git fetch --recurse-submodules" now knows that submodules can be
+   moved around in the superproject in addition to getting updated,
+   and finds the ones that need to be fetched accordingly.
+
+ * Command line completion (in contrib/) update.
+
+ * Description of blame.{showroot,blankboundary,showemail,date}
+   configuration variables have been added to "git config --help".
+
+ * After an error from lstat(), diff_populate_filespec() function
+   sometimes still went ahead and used invalid data in struct stat,
+   which has been fixed.
+
+ * UNC paths are also relevant in Cygwin builds and they are now
+   tested just like Mingw builds.
+
+ * Correct start-up sequence so that a repository could be placed
+   immediately under the root directory again (which was broken at
+   around Git 2.13).
+
+ * The credential helper for libsecret (in contrib/) has been improved
+   to allow possibly prompting the end user to unlock secrets that are
+   currently locked (otherwise the secrets may not be loaded).
+
+ * MinGW updates.
+
+ * Error checking in "git imap-send" for empty response has been
+   improved.
+
+ * Recent update to the refs infrastructure implementation started
+   rewriting packed-refs file more often than before; this has been
+   optimized again for most trivial cases.
+
+ * Some error messages did not quote filenames shown in it, which have
+   been fixed.
+
+ * "git rebase -i" recently started misbehaving when a submodule that
+   is configured with 'submodule.<name>.ignore' is dirty; this has
+   been corrected.
+
+ * Building with NO_LIBPCRE1_JIT did not disable it, which has been fixed.
+
+ * We used to add an empty alternate object database to the system
+   that does not help anything; it has been corrected.
+
+ * Doc update around use of "format-patch --subject-prefix" etc.
+
+ * A fix for an ancient bug in "git apply --ignore-space-change" codepath.
+
+ * Clarify and enhance documentation for "merge-base --fork-point", as
+   it was clear what it computed but not why/what for.
+
+ * A few scripts (both in production and tests) incorrectly redirected
+   their error output.  These have been corrected.
+
+ * "git notes" sent its error message to its standard output stream,
+   which was corrected.
+
+ * The three-way merge performed by "git cherry-pick" was confused
+   when a new submodule was added in the meantime, which has been
+   fixed (or "papered over").
+
+ * The sequencer machinery (used by "git cherry-pick A..B", and "git
+   rebase -i", among other things) would have lost a commit if stopped
+   due to an unlockable index file, which has been fixed.
+
+ * "git apply --inaccurate-eof" when used with "--ignore-space-change"
+   triggered an internal sanity check, which has been fixed.
+
+ * Command line completion (in contrib/) has been taught about the
+   "--copy" option of "git branch".
+
+ * When "git rebase" prepared a mailbox of changes and fed it to "git
+   am" to replay them, it was confused when a stray "From " happened
+   to be in the log message of one of the replayed changes.  This has
+   been corrected.
+
+ * There was a recent semantic mismerge in the codepath to write out a
+   section of a configuration section, which has been corrected.
+
+ * Mentions of "git-rebase" and "git-am" (dashed form) still remained
+   in end-user visible strings emitted by the "git rebase" command;
+   they have been corrected.
+
+ * Contrary to the documentation, "git pull -4/-6 other-args" did not
+   ask the underlying "git fetch" to go over IPv4/IPv6, which has been
+   corrected.
+
+ * "git checkout --recursive" may overwrite and rewind the history of
+   the branch that happens to be checked out in submodule
+   repositories, which might not be desirable.  Detach the HEAD but
+   still allow the recursive checkout to succeed in such a case.
+   (merge 57f22bf997 sb/submodule-recursive-checkout-detach-head later to maint).
+
+ * "git branch --set-upstream" has been deprecated and (sort of)
+   removed, as "--set-upstream-to" is the preferred one these days.
+   The documentation still had "--set-upstream" listed on its
+   synopsis section, which has been corrected.
+   (merge a060f3d3d8 tz/branch-doc-remove-set-upstream later to maint).
+
+ * Internally we use 0{40} as a placeholder object name to signal the
+   codepath that there is no such object (e.g. the fast-forward check
+   while "git fetch" stores a new remote-tracking ref says "we know
+   there is no 'old' thing pointed at by the ref, as we are creating
+   it anew" by passing 0{40} for the 'old' side), and expect that a
+   codepath to locate an in-core object to return NULL as a sign that
+   the object does not exist.  A look-up for an object that does not
+   exist however is quite costly with a repository with large number
+   of packfiles.  This access pattern has been optimized.
+   (merge 87b5e236a1 jk/fewer-pack-rescan later to maint).
+
+ * In addition to "git stash -m message", the command learned to
+   accept "git stash -mmessage" form.
+   (merge 5675473fcb ph/stash-save-m-option-fix later to maint).
+
+ * @{-N} in "git checkout @{-N}" may refer to a detached HEAD state,
+   but the documentation was not clear about it, which has been fixed.
+   (merge 75ce149575 ks/doc-checkout-previous later to maint).
+
+ * A regression in the progress eye-candy was fixed.
+   (merge 9c5951cacf jk/progress-delay-fix later to maint).
+
+ * The code internal to the recursive merge strategy was not fully
+   prepared to see a path that is renamed to try overwriting another
+   path that is only different in case on case insensitive systems.
+   This does not matter in the current code, but will start to matter
+   once the rename detection logic starts taking hints from nearby
+   paths moving to some directory and moves a new path along with them.
+   (merge 4cba2b0108 en/merge-recursive-icase-removal later to maint).
+
+ * An v2.12-era regression in pathspec match logic, which made it look
+   into submodule tree even when it is not desired, has been fixed.
+   (merge eef3df5a93 bw/pathspec-match-submodule-boundary later to maint).
+
+ * Amending commits in git-gui broke the author name that is non-ascii
+   due to incorrect encoding conversion.
+
+ * Recent update to the submodule configuration code broke "diff-tree"
+   by accidentally stopping to read from the index upfront.
+   (merge fd66bcc31f bw/submodule-config-cleanup later to maint).
+
+ * Git shows a message to tell the user that it is waiting for the
+   user to finish editing when spawning an editor, in case the editor
+   opens to a hidden window or somewhere obscure and the user gets
+   lost.
+   (merge abfb04d0c7 ls/editor-waiting-message later to maint).
+
+ * The "safe crlf" check incorrectly triggered for contents that does
+   not use CRLF as line endings, which has been corrected.
+   (merge 649f1f0948 tb/check-crlf-for-safe-crlf later to maint).
+
+ * "git clone --shared" to borrow from a (secondary) worktree did not
+   work, even though "git clone --local" did.  Both are now accepted.
+   (merge b3b05971c1 es/clone-shared-worktree later to maint).
+
+ * The build procedure now allows not just the repositories but also
+   the refs to be used to take pre-formatted manpages and html
+   documents to install.
+   (merge 65289e9dcd rb/quick-install-doc later to maint).
+
+ * Update the shell prompt script (in contrib/) to strip trailing CR
+   from strings read from various "state" files.
+   (merge 041fe8fc83 ra/prompt-eread-fix later to maint).
+
+ * "git merge -s recursive" did not correctly abort when the index is
+   dirty, if the merged tree happened to be the same as the current
+   HEAD, which has been fixed.
+
+ * Bytes with high-bit set were encoded incorrectly and made
+   credential helper fail.
+   (merge 4c267f2ae3 jd/fix-strbuf-add-urlencode-bytes later to maint).
+
+ * "git rebase -p -X<option>" did not propagate the option properly
+   down to underlying merge strategy backend.
+   (merge dd6fb0053c js/fix-merge-arg-quoting-in-rebase-p later to maint).
+
+ * "git merge -s recursive" did not correctly abort when the index is
+   dirty, if the merged tree happened to be the same as the current
+   HEAD, which has been fixed.
+   (merge f309e8e768 ew/empty-merge-with-dirty-index-maint later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge 1a1fc2d5b5 rd/man-prune-progress later to maint).
+   (merge 0ba014035a rd/man-reflog-add-n later to maint).
+   (merge e54b63359f rd/doc-notes-prune-fix later to maint).
+   (merge ff4c9b413a sp/doc-info-attributes later to maint).
+   (merge 7db2cbf4f1 jc/receive-pack-hook-doc later to maint).
+   (merge 5a0526264b tg/t-readme-updates later to maint).
+   (merge 5e83cca0b8 jk/no-optional-locks later to maint).
+   (merge 826c778f7c js/hashmap-update-sample later to maint).
+   (merge 176b2d328c sg/setup-doc-update later to maint).
+   (merge 1b09073514 rs/am-builtin-leakfix later to maint).
+   (merge addcf6cfde rs/fmt-merge-msg-string-leak-fix later to maint).
+   (merge c3ff8f6c14 rs/strbuf-read-once-reset-length later to maint).
+   (merge 6b0eb884f9 db/doc-workflows-neuter-the-maintainer later to maint).
+   (merge 8c87bdfb21 jk/cvsimport-quoting later to maint).
+   (merge 176cb979fe rs/fmt-merge-msg-leakfix later to maint).
+   (merge 5a03360e73 tb/delimit-pretty-trailers-args-with-comma later to maint).
+   (merge d0e6326026 ot/pretty later to maint).
+   (merge 44103f4197 sb/test-helper-excludes later to maint).
+   (merge 170078693f jt/transport-no-more-rsync later to maint).
+   (merge c07b3adff1 bw/path-doc later to maint).
+   (merge bf9d7df950 tz/lib-git-svn-svnserve-tests later to maint).
+   (merge dec366c9a8 sr/http-sslverify-config-doc later to maint).
+   (merge 3f824e91c8 jk/test-suite-tracing later to maint).
+   (merge 1feb061701 db/doc-config-section-names-with-bs later to maint).
+   (merge 74dea0e13c jh/memihash-opt later to maint).
+   (merge 2e9fdc795c ma/bisect-leakfix later to maint).
diff --git a/Documentation/RelNotes/2.16.1.txt b/Documentation/RelNotes/2.16.1.txt
new file mode 100644
index 0000000000..66e64361fd
--- /dev/null
+++ b/Documentation/RelNotes/2.16.1.txt
@@ -0,0 +1,11 @@
+Git v2.16.1 Release Notes
+=========================
+
+Fixes since v2.16
+-----------------
+
+ * "git clone" segfaulted when cloning a project that happens to
+   track two paths that differ only in case on a case insensitive
+   filesystem.
+
+Does not contain any other documentation updates or code clean-ups.
diff --git a/Documentation/RelNotes/2.16.2.txt b/Documentation/RelNotes/2.16.2.txt
new file mode 100644
index 0000000000..a216466d3d
--- /dev/null
+++ b/Documentation/RelNotes/2.16.2.txt
@@ -0,0 +1,30 @@
+Git v2.16.2 Release Notes
+=========================
+
+Fixes since v2.16.1
+-------------------
+
+ * An old regression in "git describe --all $annotated_tag^0" has been
+   fixed.
+
+ * "git svn dcommit" did not take into account the fact that a
+   svn+ssh:// URL with a username@ (typically used for pushing) refers
+   to the same SVN repository without the username@ and failed when
+   svn.pushmergeinfo option is set.
+
+ * "git merge -Xours/-Xtheirs" learned to use our/their version when
+   resolving a conflicting updates to a symbolic link.
+
+ * "git clone $there $here" is allowed even when here directory exists
+   as long as it is an empty directory, but the command incorrectly
+   removed it upon a failure of the operation.
+
+ * "git stash -- <pathspec>" incorrectly blew away untracked files in
+   the directory that matched the pathspec, which has been corrected.
+
+ * "git add -p" was taught to ignore local changes to submodules as
+   they do not interfere with the partial addition of regular changes
+   anyway.
+
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.16.3.txt b/Documentation/RelNotes/2.16.3.txt
new file mode 100644
index 0000000000..f0121a8f2d
--- /dev/null
+++ b/Documentation/RelNotes/2.16.3.txt
@@ -0,0 +1,49 @@
+Git v2.16.3 Release Notes
+=========================
+
+Fixes since v2.16.2
+-------------------
+
+ * "git status" after moving a path in the working tree (hence making
+   it appear "removed") and then adding with the -N option (hence
+   making that appear "added") detected it as a rename, but did not
+   report the  old and new pathnames correctly.
+
+ * "git commit --fixup" did not allow "-m<message>" option to be used
+   at the same time; allow it to annotate resulting commit with more
+   text.
+
+ * When resetting the working tree files recursively, the working tree
+   of submodules are now also reset to match.
+
+ * Fix for a commented-out code to adjust it to a rather old API change
+   around object ID.
+
+ * When there are too many changed paths, "git diff" showed a warning
+   message but in the middle of a line.
+
+ * The http tracing code, often used to debug connection issues,
+   learned to redact potentially sensitive information from its output
+   so that it can be more safely shareable.
+
+ * Crash fix for a corner case where an error codepath tried to unlock
+   what it did not acquire lock on.
+
+ * The split-index mode had a few corner case bugs fixed.
+
+ * Assorted fixes to "git daemon".
+
+ * Completion of "git merge -s<strategy>" (in contrib/) did not work
+   well in non-C locale.
+
+ * Workaround for segfault with more recent versions of SVN.
+
+ * Recently introduced leaks in fsck have been plugged.
+
+ * Travis CI integration now builds the executable in 'script' phase
+   to follow the established practice, rather than during
+   'before_script' phase.  This allows the CI categorize the failures
+   better ('failed' is project's fault, 'errored' is build
+   environment's).
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.16.4.txt b/Documentation/RelNotes/2.16.4.txt
new file mode 100644
index 0000000000..6be538ba30
--- /dev/null
+++ b/Documentation/RelNotes/2.16.4.txt
@@ -0,0 +1,5 @@
+Git v2.16.4 Release Notes
+=========================
+
+This release is to forward-port the fixes made in the v2.13.7 version
+of Git.  See its release notes for details.
diff --git a/Documentation/RelNotes/2.16.5.txt b/Documentation/RelNotes/2.16.5.txt
new file mode 100644
index 0000000000..cb8ee02a9a
--- /dev/null
+++ b/Documentation/RelNotes/2.16.5.txt
@@ -0,0 +1,6 @@
+Git v2.16.5 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.5 to address
+the recently reported CVE-2018-17456; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.16.6.txt b/Documentation/RelNotes/2.16.6.txt
new file mode 100644
index 0000000000..438306e60b
--- /dev/null
+++ b/Documentation/RelNotes/2.16.6.txt
@@ -0,0 +1,8 @@
+Git v2.16.6 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6 and in
+v2.15.4 addressing the security issues CVE-2019-1348, CVE-2019-1349,
+CVE-2019-1350, CVE-2019-1351, CVE-2019-1352, CVE-2019-1353,
+CVE-2019-1354, and CVE-2019-1387; see the release notes for those
+versions for details.
diff --git a/Documentation/RelNotes/2.17.0.txt b/Documentation/RelNotes/2.17.0.txt
new file mode 100644
index 0000000000..8b17c26033
--- /dev/null
+++ b/Documentation/RelNotes/2.17.0.txt
@@ -0,0 +1,398 @@
+Git 2.17 Release Notes
+======================
+
+Updates since v2.16
+-------------------
+
+UI, Workflows & Features
+
+ * "diff" family of commands learned "--find-object=<object-id>" option
+   to limit the findings to changes that involve the named object.
+
+ * "git format-patch" learned to give 72-cols to diffstat, which is
+   consistent with other line length limits the subcommand uses for
+   its output meant for e-mails.
+
+ * The log from "git daemon" can be redirected with a new option; one
+   relevant use case is to send the log to standard error (instead of
+   syslog) when running it from inetd.
+
+ * "git rebase" learned to take "--allow-empty-message" option.
+
+ * "git am" has learned the "--quit" option, in addition to the
+   existing "--abort" option; having the pair mirrors a few other
+   commands like "rebase" and "cherry-pick".
+
+ * "git worktree add" learned to run the post-checkout hook, just like
+   "git clone" runs it upon the initial checkout.
+
+ * "git tag" learned an explicit "--edit" option that allows the
+   message given via "-m" and "-F" to be further edited.
+
+ * "git fetch --prune-tags" may be used as a handy short-hand for
+   getting rid of stale tags that are locally held.
+
+ * The new "--show-current-patch" option gives an end-user facing way
+   to get the diff being applied when "git rebase" (and "git am")
+   stops with a conflict.
+
+ * "git add -p" used to offer "/" (look for a matching hunk) as a
+   choice, even there was only one hunk, which has been corrected.
+   Also the single-key help is now given only for keys that are
+   enabled (e.g. help for '/' won't be shown when there is only one
+   hunk).
+
+ * Since Git 1.7.9, "git merge" defaulted to --no-ff (i.e. even when
+   the side branch being merged is a descendant of the current commit,
+   create a merge commit instead of fast-forwarding) when merging a
+   tag object.  This was appropriate default for integrators who pull
+   signed tags from their downstream contributors, but caused an
+   unnecessary merges when used by downstream contributors who
+   habitually "catch up" their topic branches with tagged releases
+   from the upstream.  Update "git merge" to default to --no-ff only
+   when merging a tag object that does *not* sit at its usual place in
+   refs/tags/ hierarchy, and allow fast-forwarding otherwise, to
+   mitigate the problem.
+
+ * "git status" can spend a lot of cycles to compute the relation
+   between the current branch and its upstream, which can now be
+   disabled with "--no-ahead-behind" option.
+
+ * "git diff" and friends learned funcname patterns for Go language
+   source files.
+
+ * "git send-email" learned "--reply-to=<address>" option.
+
+ * Funcname pattern used for C# now recognizes "async" keyword.
+
+ * In a way similar to how "git tag" learned to honor the pager
+   setting only in the list mode, "git config" learned to ignore the
+   pager setting when it is used for setting values (i.e. when the
+   purpose of the operation is not to "show").
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * More perf tests for threaded grep
+
+ * "perf" test output can be sent to codespeed server.
+
+ * The build procedure for perl/ part has been greatly simplified by
+   weaning ourselves off of MakeMaker.
+
+ * Perl 5.8 or greater has been required since Git 1.7.4 released in
+   2010, but we continued to assume some core modules may not exist and
+   used a conditional "eval { require <<module>> }"; we no longer do
+   this.  Some platforms (Fedora/RedHat/CentOS, for example) ship Perl
+   without all core modules by default (e.g. Digest::MD5, File::Temp,
+   File::Spec, Net::Domain, Net::SMTP).  Users on such platforms may
+   need to install these additional modules.
+
+ * As a convenience, we install copies of Perl modules we require which
+   are not part of the core Perl distribution (e.g. Error and
+   Mail::Address).  Users and packagers whose operating system provides
+   these modules can set NO_PERL_CPAN_FALLBACKS to avoid installing the
+   bundled modules.
+
+ * In preparation for implementing narrow/partial clone, the machinery
+   for checking object connectivity used by gc and fsck has been
+   taught that a missing object is OK when it is referenced by a
+   packfile specially marked as coming from trusted repository that
+   promises to make them available on-demand and lazily.
+
+ * The machinery to clone & fetch, which in turn involves packing and
+   unpacking objects, has been told how to omit certain objects using
+   the filtering mechanism introduced by another topic.  It now knows
+   to mark the resulting pack as a promisor pack to tolerate missing
+   objects, laying foundation for "narrow" clones.
+
+ * The first step to getting rid of mru API and using the
+   doubly-linked list API directly instead.
+
+ * Retire mru API as it does not give enough abstraction over
+   underlying list API to be worth it.
+
+ * Rewrite two more "git submodule" subcommands in C.
+
+ * The tracing machinery learned to report tweaking of environment
+   variables as well.
+
+ * Update Coccinelle rules to catch and optimize strbuf_addf(&buf, "%s", str)
+
+ * Prevent "clang-format" from breaking line after function return type.
+
+ * The sequencer infrastructure is shared across "git cherry-pick",
+   "git rebase -i", etc., and has always spawned "git commit" when it
+   needs to create a commit.  It has been taught to do so internally,
+   when able, by reusing the codepath "git commit" itself uses, which
+   gives performance boost for a few tens of percents in some sample
+   scenarios.
+
+ * Push the submodule version of collision-detecting SHA-1 hash
+   implementation a bit harder on builders.
+
+ * Avoid mmapping small files while using packed refs (especially ones
+   with zero size, which would cause later munmap() to fail).
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * More tests for wildmatch functions.
+
+ * The code to binary search starting from a fan-out table (which is
+   how the packfile is indexed with object names) has been refactored
+   into a reusable helper.
+
+ * We now avoid using identifiers that clash with C++ keywords.  Even
+   though it is not a goal to compile Git with C++ compilers, changes
+   like this help use of code analysis tools that targets C++ on our
+   codebase.
+
+ * The executable is now built in 'script' phase in Travis CI integration,
+   to follow the established practice, rather than during 'before_script'
+   phase.  This allows the CI categorize the failures better ('failed'
+   is project's fault, 'errored' is build environment's).
+   (merge 3c93b82920 sg/travis-build-during-script-phase later to maint).
+
+ * Writing out the index file when the only thing that changed in it
+   is the untracked cache information is often wasteful, and this has
+   been optimized out.
+
+ * Various pieces of Perl code we have have been cleaned up.
+
+ * Internal API clean-up to allow write_locked_index() optionally skip
+   writing the in-core index when it is not modified.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.16
+-----------------
+
+ * An old regression in "git describe --all $annotated_tag^0" has been
+   fixed.
+
+ * "git status" after moving a path in the working tree (hence making
+   it appear "removed") and then adding with the -N option (hence
+   making that appear "added") detected it as a rename, but did not
+   report the  old and new pathnames correctly.
+
+ * "git svn dcommit" did not take into account the fact that a
+   svn+ssh:// URL with a username@ (typically used for pushing) refers
+   to the same SVN repository without the username@ and failed when
+   svn.pushmergeinfo option is set.
+
+ * API clean-up around revision traversal.
+
+ * "git merge -Xours/-Xtheirs" learned to use our/their version when
+   resolving a conflicting updates to a symbolic link.
+
+ * "git clone $there $here" is allowed even when here directory exists
+   as long as it is an empty directory, but the command incorrectly
+   removed it upon a failure of the operation.
+
+ * "git commit --fixup" did not allow "-m<message>" option to be used
+   at the same time; allow it to annotate resulting commit with more
+   text.
+
+ * When resetting the working tree files recursively, the working tree
+   of submodules are now also reset to match.
+
+ * "git stash -- <pathspec>" incorrectly blew away untracked files in
+   the directory that matched the pathspec, which has been corrected.
+
+ * Instead of maintaining home-grown email address parsing code, ship
+   a copy of reasonably recent Mail::Address to be used as a fallback
+   in 'git send-email' when the platform lacks it.
+   (merge d60be8acab mm/send-email-fallback-to-local-mail-address later to maint).
+
+ * "git add -p" was taught to ignore local changes to submodules as
+   they do not interfere with the partial addition of regular changes
+   anyway.
+
+ * Avoid showing a warning message in the middle of a line of "git
+   diff" output.
+   (merge 4e056c989f nd/diff-flush-before-warning later to maint).
+
+ * The http tracing code, often used to debug connection issues,
+   learned to redact potentially sensitive information from its output
+   so that it can be more safely shareable.
+   (merge 8ba18e6fa4 jt/http-redact-cookies later to maint).
+
+ * Crash fix for a corner case where an error codepath tried to unlock
+   what it did not acquire lock on.
+   (merge 81fcb698e0 mr/packed-ref-store-fix later to maint).
+
+ * The split-index mode had a few corner case bugs fixed.
+   (merge ae59a4e44f tg/split-index-fixes later to maint).
+
+ * Assorted fixes to "git daemon".
+   (merge ed15e58efe jk/daemon-fixes later to maint).
+
+ * Completion of "git merge -s<strategy>" (in contrib/) did not work
+   well in non-C locale.
+   (merge 7cc763aaa3 nd/list-merge-strategy later to maint).
+
+ * Workaround for segfault with more recent versions of SVN.
+   (merge 7f6f75e97a ew/svn-branch-segfault-fix later to maint).
+
+ * Plug recently introduced leaks in fsck.
+   (merge ba3a08ca0e jt/fsck-code-cleanup later to maint).
+
+ * "git pull --rebase" did not pass verbosity setting down when
+   recursing into a submodule.
+   (merge a56771a668 sb/pull-rebase-submodule later to maint).
+
+ * The way "git reset --hard" reports the commit the updated HEAD
+   points at is made consistent with the way how the commit title is
+   generated by the other parts of the system.  This matters when the
+   title is spread across physically multiple lines.
+   (merge 1cf823fb68 tg/reset-hard-show-head-with-pretty later to maint).
+
+ * Test fixes.
+   (merge 63b1a175ee sg/test-i18ngrep later to maint).
+
+ * Some bugs around "untracked cache" feature have been fixed.  This
+   will notice corrupt data in the untracked cache left by old and
+   buggy code and issue a warning---the index can be fixed by clearing
+   the untracked cache from it.
+   (merge 0cacebf099 nd/fix-untracked-cache-invalidation later to maint).
+   (merge 7bf0be7501 ab/untracked-cache-invalidation-docs later to maint).
+
+ * "git blame HEAD COPYING" in a bare repository failed to run, while
+   "git blame HEAD -- COPYING" run just fine.  This has been corrected.
+
+ * "git add" files in the same directory, but spelling the directory
+   path in different cases on case insensitive filesystem, corrupted
+   the name hash data structure and led to unexpected results.  This
+   has been corrected.
+   (merge c95525e90d bp/name-hash-dirname-fix later to maint).
+
+ * "git rebase -p" mangled log messages of a merge commit, which is
+   now fixed.
+   (merge ed5144d7eb js/fix-merge-arg-quoting-in-rebase-p later to maint).
+
+ * Some low level protocol codepath could crash when they get an
+   unexpected flush packet, which is now fixed.
+   (merge bb1356dc64 js/packet-read-line-check-null later to maint).
+
+ * "git check-ignore" with multiple paths got confused when one is a
+   file and the other is a directory, which has been fixed.
+   (merge d60771e930 rs/check-ignore-multi later to maint).
+
+ * "git describe $garbage" stopped giving any errors when the garbage
+   happens to be a string with 40 hexadecimal letters.
+   (merge a8e7a2bf0f sb/describe-blob later to maint).
+
+ * Code to unquote single-quoted string (used in the parser for
+   configuration files, etc.) did not diagnose bogus input correctly
+   and produced bogus results instead.
+   (merge ddbbf8eb25 jk/sq-dequote-on-bogus-input later to maint).
+
+ * Many places in "git apply" knew that "/dev/null" that signals
+   "there is no such file on this side of the diff" can be followed by
+   whitespace and garbage when parsing a patch, except for one, which
+   made an otherwise valid patch (e.g. ones from subversion) rejected.
+   (merge e454ad4bec tk/apply-dev-null-verify-name-fix later to maint).
+
+ * We no longer create any *.spec file, so "make clean" should not
+   remove it.
+   (merge 4321bdcabb tz/do-not-clean-spec-file later to maint).
+
+ * "git push" over http transport did not unquote the push-options
+   correctly.
+   (merge 90dce21eb0 jk/push-options-via-transport-fix later to maint).
+
+ * "git send-email" learned to complain when the batch-size option is
+   not defined when the relogin-delay option is, since these two are
+   mutually required.
+   (merge 9caa70697b xz/send-email-batch-size later to maint).
+
+ * Y2k20 fix ;-) for our perl scripts.
+   (merge a40e06ee33 bw/perl-timegm-timelocal-fix later to maint).
+
+ * Threaded "git grep" has been optimized to avoid allocation in code
+   section that is covered under a mutex.
+   (merge 38ef24dccf rv/grep-cleanup later to maint).
+
+ * "git subtree" script (in contrib/) scripted around "git log", whose
+   output got affected by end-user configuration like log.showsignature
+   (merge 8841b5222c sg/subtree-signed-commits later to maint).
+
+ * While finding unique object name abbreviation, the code may
+   accidentally have read beyond the end of the array of object names
+   in a pack.
+   (merge 21abed500c ds/find-unique-abbrev-optim later to maint).
+
+ * Micro optimization in revision traversal code.
+   (merge ebbed3ba04 ds/mark-parents-uninteresting-optim later to maint).
+
+ * "git commit" used to run "gc --auto" near the end, which was lost
+   when the command was reimplemented in C by mistake.
+   (merge 095c741edd ab/gc-auto-in-commit later to maint).
+
+ * Allow running a couple of tests with "sh -x".
+   (merge c20bf94abc sg/cvs-tests-with-x later to maint).
+
+ * The codepath to replace an existing entry in the index had a bug in
+   updating the name hash structure, which has been fixed.
+   (merge 0e267b7a24 bp/refresh-cache-ent-rehash-fix later to maint).
+
+ * The transfer.fsckobjects configuration tells "git fetch" to
+   validate the data and connected-ness of objects in the received
+   pack; the code to perform this check has been taught about the
+   narrow clone's convention that missing objects that are reachable
+   from objects in a pack that came from a promisor remote is OK.
+
+ * There was an unused file-scope static variable left in http.c when
+   building for versions of libCURL that is older than 7.19.4, which
+   has been fixed.
+   (merge b8fd6008ec rj/http-code-cleanup later to maint).
+
+ * Shell script portability fix.
+   (merge 206a6ae013 ml/filter-branch-portability-fix later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge e2a5a028c7 bw/oidmap-autoinit later to maint).
+   (merge ec3b4b06f8 cl/t9001-cleanup later to maint).
+   (merge e1b3f3dd38 ks/submodule-doc-updates later to maint).
+   (merge fbac558a9b rs/describe-unique-abbrev later to maint).
+   (merge 8462ff43e4 tb/crlf-conv-flags later to maint).
+   (merge 7d68bb0766 rb/hashmap-h-compilation-fix later to maint).
+   (merge 3449847168 cc/sha1-file-name later to maint).
+   (merge ad622a256f ds/use-get-be64 later to maint).
+   (merge f919ffebed sg/cocci-move-array later to maint).
+   (merge 4e801463c7 jc/mailinfo-cleanup-fix later to maint).
+   (merge ef5b3a6c5e nd/shared-index-fix later to maint).
+   (merge 9f5258cbb8 tz/doc-show-defaults-to-head later to maint).
+   (merge b780e4407d jc/worktree-add-short-help later to maint).
+   (merge ae239fc8e5 rs/cocci-strbuf-addf-to-addstr later to maint).
+   (merge 2e22a85e5c nd/ignore-glob-doc-update later to maint).
+   (merge 3738031581 jk/gettext-poison later to maint).
+   (merge 54360a1956 rj/sparse-updates later to maint).
+   (merge 12e31a6b12 sg/doc-test-must-fail-args later to maint).
+   (merge 760f1ad101 bc/doc-interpret-trailers-grammofix later to maint).
+   (merge 4ccf461f56 bp/fsmonitor later to maint).
+   (merge a6119f82b1 jk/test-hashmap-updates later to maint).
+   (merge 5aea9fe6cc rd/typofix later to maint).
+   (merge e4e5da2796 sb/status-doc-fix later to maint).
+   (merge 7976e901c8 gs/test-unset-xdg-cache-home later to maint).
+   (merge d023df1ee6 tg/worktree-create-tracking later to maint).
+   (merge 4cbe92fd41 sm/mv-dry-run-update later to maint).
+   (merge 75e5e9c3f7 sb/color-h-cleanup later to maint).
+   (merge 2708ef4af6 sg/t6300-modernize later to maint).
+   (merge d88e92d4e0 bw/doc-submodule-recurse-config-with-clone later to maint).
+   (merge f74bbc8dd2 jk/cached-commit-buffer later to maint).
+   (merge 1316416903 ms/non-ascii-ticks later to maint).
+   (merge 878056005e rs/strbuf-read-file-or-whine later to maint).
+   (merge 79f0ba1547 jk/strbuf-read-file-close-error later to maint).
+   (merge edfb8ba068 ot/ref-filter-cleanup later to maint).
+   (merge 11395a3b4b jc/test-must-be-empty later to maint).
+   (merge 768b9d6db7 mk/doc-pretty-fill later to maint).
+   (merge 2caa7b8d27 ab/man-sec-list later to maint).
+   (merge 40c17eb184 ks/t3200-typofix later to maint).
+   (merge bd9958c358 dp/merge-strategy-doc-fix later to maint).
+   (merge 9ee0540a40 js/ming-strftime later to maint).
+   (merge 1775e990f7 tz/complete-tag-delete-tagname later to maint).
+   (merge 00a4b03501 rj/warning-uninitialized-fix later to maint).
+   (merge b635ed97a0 jk/attributes-path-doc later to maint).
diff --git a/Documentation/RelNotes/2.17.1.txt b/Documentation/RelNotes/2.17.1.txt
new file mode 100644
index 0000000000..e01384fe8e
--- /dev/null
+++ b/Documentation/RelNotes/2.17.1.txt
@@ -0,0 +1,16 @@
+Git v2.17.1 Release Notes
+=========================
+
+Fixes since v2.17
+-----------------
+
+ * This release contains the same fixes made in the v2.13.7 version of
+   Git, covering CVE-2018-11233 and 11235, and forward-ported to
+   v2.14.4, v2.15.2 and v2.16.4 releases.  See release notes to
+   v2.13.7 for details.
+
+ * In addition to the above fixes, this release has support on the
+   server side to reject pushes to repositories that attempt to create
+   such problematic .gitmodules file etc. as tracked contents, to help
+   hosting sites protect their customers by preventing malicious
+   contents from spreading.
diff --git a/Documentation/RelNotes/2.17.2.txt b/Documentation/RelNotes/2.17.2.txt
new file mode 100644
index 0000000000..ef021be870
--- /dev/null
+++ b/Documentation/RelNotes/2.17.2.txt
@@ -0,0 +1,12 @@
+Git v2.17.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.5 to address
+the recently reported CVE-2018-17456; see the release notes for that
+version for details.
+
+In addition, this release also teaches "fsck" and the server side
+logic to reject pushes to repositories that attempt to create such a
+problematic ".gitmodules" file as tracked contents, to help hosting
+sites protect their customers by preventing malicious contents from
+spreading.
diff --git a/Documentation/RelNotes/2.17.3.txt b/Documentation/RelNotes/2.17.3.txt
new file mode 100644
index 0000000000..5a46c94271
--- /dev/null
+++ b/Documentation/RelNotes/2.17.3.txt
@@ -0,0 +1,12 @@
+Git v2.17.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6 and in
+v2.15.4 addressing the security issues CVE-2019-1348, CVE-2019-1349,
+CVE-2019-1350, CVE-2019-1351, CVE-2019-1352, CVE-2019-1353,
+CVE-2019-1354, and CVE-2019-1387; see the release notes for those
+versions for details.
+
+In addition, `git fsck` was taught to identify `.gitmodules` entries
+of the form `submodule.<name>.update=!command`, which have been
+disallowed in v2.15.4.
diff --git a/Documentation/RelNotes/2.17.4.txt b/Documentation/RelNotes/2.17.4.txt
new file mode 100644
index 0000000000..7d794ca01a
--- /dev/null
+++ b/Documentation/RelNotes/2.17.4.txt
@@ -0,0 +1,16 @@
+Git v2.17.4 Release Notes
+=========================
+
+This release is to address the security issue: CVE-2020-5260
+
+Fixes since v2.17.3
+-------------------
+
+ * With a crafted URL that contains a newline in it, the credential
+   helper machinery can be fooled to give credential information for
+   a wrong host.  The attack has been made impossible by forbidding
+   a newline character in any value passed via the credential
+   protocol.
+
+Credit for finding the vulnerability goes to Felix Wilhelm of Google
+Project Zero.
diff --git a/Documentation/RelNotes/2.17.5.txt b/Documentation/RelNotes/2.17.5.txt
new file mode 100644
index 0000000000..2abb821a73
--- /dev/null
+++ b/Documentation/RelNotes/2.17.5.txt
@@ -0,0 +1,22 @@
+Git v2.17.5 Release Notes
+=========================
+
+This release is to address a security issue: CVE-2020-11008
+
+Fixes since v2.17.4
+-------------------
+
+ * With a crafted URL that contains a newline or empty host, or lacks
+   a scheme, the credential helper machinery can be fooled into
+   providing credential information that is not appropriate for the
+   protocol in use and host being contacted.
+
+   Unlike the vulnerability CVE-2020-5260 fixed in v2.17.4, the
+   credentials are not for a host of the attacker's choosing; instead,
+   they are for some unspecified host (based on how the configured
+   credential helper handles an absent "host" parameter).
+
+   The attack has been made impossible by refusing to work with
+   under-specified credential patterns.
+
+Credit for finding the vulnerability goes to Carlo Arenas.
diff --git a/Documentation/RelNotes/2.17.6.txt b/Documentation/RelNotes/2.17.6.txt
new file mode 100644
index 0000000000..2f181e8064
--- /dev/null
+++ b/Documentation/RelNotes/2.17.6.txt
@@ -0,0 +1,16 @@
+Git v2.17.6 Release Notes
+=========================
+
+This release addresses the security issues CVE-2021-21300.
+
+Fixes since v2.17.5
+-------------------
+
+ * CVE-2021-21300:
+   On case-insensitive file systems with support for symbolic links,
+   if Git is configured globally to apply delay-capable clean/smudge
+   filters (such as Git LFS), Git could be fooled into running
+   remote code during a clone.
+
+Credit for finding and fixing this vulnerability goes to Matheus
+Tavares, helped by Johannes Schindelin.
diff --git a/Documentation/RelNotes/2.18.0.txt b/Documentation/RelNotes/2.18.0.txt
new file mode 100644
index 0000000000..6c8a0e97c1
--- /dev/null
+++ b/Documentation/RelNotes/2.18.0.txt
@@ -0,0 +1,583 @@
+Git 2.18 Release Notes
+======================
+
+Updates since v2.17
+-------------------
+
+UI, Workflows & Features
+
+ * Rename detection logic that is used in "merge" and "cherry-pick" has
+   learned to guess when all of x/a, x/b and x/c have moved to z/a,
+   z/b and z/c, it is likely that x/d added in the meantime would also
+   want to move to z/d by taking the hint that the entire directory
+   'x' moved to 'z'.  A bug causing dirty files involved in a rename
+   to be overwritten during merge has also been fixed as part of this
+   work.  Incidentally, this also avoids updating a file in the
+   working tree after a (non-trivial) merge whose result matches what
+   our side originally had.
+
+ * "git filter-branch" learned to use a different exit code to allow
+   the callers to tell the case where there was no new commits to
+   rewrite from other error cases.
+
+ * When built with more recent cURL, GIT_SSL_VERSION can now specify
+   "tlsv1.3" as its value.
+
+ * "git gui" learned that "~/.ssh/id_ecdsa.pub" and
+   "~/.ssh/id_ed25519.pub" are also possible SSH key files.
+   (merge 2e2f0288ef bb/git-gui-ssh-key-files later to maint).
+
+ * "git gui" performs commit upon CTRL/CMD+ENTER but the
+   CTRL/CMD+KP_ENTER (i.e. enter key on the numpad) did not have the
+   same key binding.  It now does.
+   (merge 28a1d94a06 bp/git-gui-bind-kp-enter later to maint).
+
+ * "git gui" has been taught to work with old versions of tk (like
+   8.5.7) that do not support "ttk::style theme use" as a way to query
+   the current theme.
+   (merge 4891961105 cb/git-gui-ttk-style later to maint).
+
+ * "git rebase" has learned to honor "--signoff" option when using
+   backends other than "am" (but not "--preserve-merges").
+
+ * "git branch --list" during an interrupted "rebase -i" now lets
+   users distinguish the case where a detached HEAD is being rebased
+   and a normal branch is being rebased.
+
+ * "git mergetools" learned talking to guiffy.
+
+ * The scripts in contrib/emacs/ have outlived their usefulness and
+   have been replaced with a stub that errors out and tells the user
+   there are replacements.
+
+ * The new "working-tree-encoding" attribute can ask Git to convert the
+   contents to the specified encoding when checking out to the working
+   tree (and the other way around when checking in).
+
+ * The "git config" command uses separate options e.g. "--int",
+   "--bool", etc. to specify what type the caller wants the value to
+   be interpreted as.  A new "--type=<typename>" option has been
+   introduced, which would make it cleaner to define new types.
+
+ * "git config --get" learned the "--default" option, to help the
+   calling script.  Building on top of the above changes, the
+   "git config" learns "--type=color" type.  Taken together, you can
+   do things like "git config --get foo.color --default blue" and get
+   the ANSI color sequence for the color given to foo.color variable,
+   or "blue" if the variable does not exist.
+
+ * "git ls-remote" learned an option to allow sorting its output based
+   on the refnames being shown.
+
+ * The command line completion (in contrib/) has been taught that "git
+   stash save" has been deprecated ("git stash push" is the preferred
+   spelling in the new world) and does not offer it as a possible
+   completion candidate when "git stash push" can be.
+
+ * "git gc --prune=nonsense" spent long time repacking and then
+   silently failed when underlying "git prune --expire=nonsense"
+   failed to parse its command line.  This has been corrected.
+
+ * Error messages from "git push" can be painted for more visibility.
+
+ * "git http-fetch" (deprecated) had an optional and experimental
+   "feature" to fetch only commits and/or trees, which nobody used.
+   This has been removed.
+
+ * The functionality of "$GIT_DIR/info/grafts" has been superseded by
+   the "refs/replace/" mechanism for some time now, but the internal
+   code had support for it in many places, which has been cleaned up
+   in order to drop support of the "grafts" mechanism.
+
+ * "git worktree add" learned to check out an existing branch.
+
+ * "git --no-pager cmd" did not have short-and-sweet single letter
+   option. Now it does as "-P".
+   (merge 7213c28818 js/no-pager-shorthand later to maint).
+
+ * "git rebase" learned "--rebase-merges" to transplant the whole
+   topology of commit graph elsewhere.
+
+ * "git status" learned to pay attention to UI related diff
+   configuration variables such as diff.renames.
+
+ * The command line completion mechanism (in contrib/) learned to load
+   custom completion file for "git $command" where $command is a
+   custom "git-$command" that the end user has on the $PATH when using
+   newer version of bash-completion.
+
+ * "git send-email" can sometimes offer confirmation dialog "Send this
+   email?" with choices 'Yes', 'No', 'Quit', and 'All'.  A new action
+   'Edit' has been added to this dialog's choice.
+
+ * With merge.renames configuration set to false, the recursive merge
+   strategy can be told not to spend cycles trying to find renamed
+   paths and merge them accordingly.
+
+ * "git status" learned to honor a new status.renames configuration to
+   skip rename detection, which could be useful for those who want to
+   do so without disabling the default rename detection done by the
+   "git diff" command.
+
+ * Command line completion (in contrib/) learned to complete pathnames
+   for various commands better.
+
+ * "git blame" learns to unhighlight uninteresting metadata from the
+   originating commit on lines that are the same as the previous one,
+   and also paint lines in different colors depending on the age of
+   the commit.
+
+ * Transfer protocol v2 learned to support the partial clone.
+
+ * When a short hexadecimal string is used to name an object but there
+   are multiple objects that share the string as the prefix of their
+   names, the code lists these ambiguous candidates in a help message.
+   These object names are now sorted according to their types for
+   easier eyeballing.
+
+ * "git fetch $there $refspec" that talks over protocol v2 can take
+   advantage of server-side ref filtering; the code has been extended
+   so that this mechanism triggers also when fetching with configured
+   refspec.
+
+ * Our HTTP client code used to advertise that we accept gzip encoding
+   from the other side; instead, just let cURL library to advertise
+   and negotiate the best one.
+
+ * "git p4" learned to "unshelve" shelved commit from P4.
+   (merge 123f631761 ld/p4-unshelve later to maint).
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * A "git fetch" from a repository with insane number of refs into a
+   repository that is already up-to-date still wasted too many cycles
+   making many lstat(2) calls to see if these objects at the tips
+   exist as loose objects locally.  These lstat(2) calls are optimized
+   away by enumerating all loose objects beforehand.
+   It is unknown if the new strategy negatively affects existing use
+   cases, fetching into a repository with many loose objects from a
+   repository with small number of refs.
+
+ * Git can be built to use either v1 or v2 of the PCRE library, and so
+   far, the build-time configuration USE_LIBPCRE=YesPlease instructed
+   the build procedure to use v1, but now it means v2.  USE_LIBPCRE1
+   and USE_LIBPCRE2 can be used to explicitly choose which version to
+   use, as before.
+
+ * The build procedure learned to optionally use symbolic links
+   (instead of hardlinks and copies) to install "git-foo" for built-in
+   commands, whose binaries are all identical.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * The way "git worktree prune" worked internally has been simplified,
+   by assuming how "git worktree move" moves an existing worktree to a
+   different place.
+
+ * Code clean-up for the "repository" abstraction.
+   (merge 00a3da2a13 nd/remove-ignore-env-field later to maint).
+
+ * Code to find the length to uniquely abbreviate object names based
+   on packfile content, which is a relatively recent addition, has been
+   optimized to use the same fan-out table.
+
+ * The mechanism to use parse-options API to automate the command line
+   completion continues to get extended and polished.
+
+ * Copies of old scripted Porcelain commands in contrib/examples/ have
+   been removed.
+
+ * Some tests that rely on the exact hardcoded values of object names
+   have been updated in preparation for hash function migration.
+
+ * Perf-test update.
+
+ * Test helper update.
+
+ * The effort continues to refactor the internal global data structure
+   to make it possible to open multiple repositories, work with and
+   then close them,
+
+ * Small test-helper programs have been consolidated into a single
+   binary.
+
+ * API clean-up around ref-filter code.
+
+ * Shell completion (in contrib) that gives list of paths have been
+   optimized somewhat.
+
+ * The index file is updated to record the fsmonitor section after a
+   full scan was made, to avoid wasting the effort that has already
+   spent.
+
+ * Performance measuring framework in t/perf learned to help bisecting
+   performance regressions.
+
+ * Some multi-word source filenames are being renamed to separate
+   words with dashes instead of underscores.
+
+ * An reusable "memory pool" implementation has been extracted from
+   fast-import.c, which in turn has become the first user of the
+   mem-pool API.
+
+ * A build-time option has been added to allow Git to be told to refer
+   to its associated files relative to the main binary, in the same
+   way that has been possible on Windows for quite some time, for
+   Linux, BSDs and Darwin.
+
+ * Precompute and store information necessary for ancestry traversal
+   in a separate file to optimize graph walking.
+
+ * The effort to pass the repository in-core structure throughout the
+   API continues.  This round deals with the code that implements the
+   refs/replace/ mechanism.
+
+ * The build procedure "make DEVELOPER=YesPlease" learned to enable a
+   bit more warning options depending on the compiler used to help
+   developers more.  There also is "make DEVOPTS=tokens" knob
+   available now, for those who want to help fixing warnings we
+   usually ignore, for example.
+
+ * A new version of the transport protocol is being worked on.
+
+ * The code to interface to GPG has been restructured somewhat to make
+   it cleaner to integrate with other types of signature systems later.
+
+ * The code has been taught to use the duplicated information stored
+   in the commit-graph file to learn the tree object name for a commit
+   to avoid opening and parsing the commit object when it makes sense
+   to do so.
+
+ * "git gc" in a large repository takes a lot of time as it considers
+   to repack all objects into one pack by default.  The command has
+   been taught to pretend as if the largest existing packfile is
+   marked with ".keep" so that it is left untouched while objects in
+   other packs and loose ones are repacked.
+
+ * The transport protocol v2 is getting updated further.
+
+ * The codepath around object-info API has been taught to take the
+   repository object (which in turn tells the API which object store
+   the objects are to be located).
+
+ * "git pack-objects" needs to allocate tons of "struct object_entry"
+   while doing its work, and shrinking its size helps the performance
+   quite a bit.
+
+ * The implementation of "git rebase -i --root" has been updated to use
+   the sequencer machinery more.
+
+ * Developer support update, by using BUG() macro instead of die() to
+   mark codepaths that should not happen more clearly.
+
+ * Developer support.  Use newer GCC on one of the builds done at
+   TravisCI.org to get more warnings and errors diagnosed.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * By code restructuring of submodule merge in merge-recursive,
+   informational messages from the codepath are now given using the
+   same mechanism as other output, and honor the merge.verbosity
+   configuration.  The code also learned to give a few new messages
+   when a submodule three-way merge resolves cleanly when one side
+   records a descendant of the commit chosen by the other side.
+
+ * Avoid unchecked snprintf() to make future code auditing easier.
+   (merge ac4896f007 jk/snprintf-truncation later to maint).
+
+ * Many tests hardcode the raw object names, which would change once
+   we migrate away from SHA-1.  While some of them must test against
+   exact object names, most of them do not have to use hardcoded
+   constants in the test.  The latter kind of tests have been updated
+   to test the moral equivalent of the original without hardcoding the
+   actual object names.
+
+ * The list of commands with their various attributes were spread
+   across a few places in the build procedure, but it now is getting a
+   bit more consolidated to allow more automation.
+
+ * Quite a many tests assumed that newly created refs are made as
+   loose refs using the files backend, which have been updated to use
+   proper plumbing like rev-parse and update-ref, to avoid breakage
+   once we start using different ref backends.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.17
+-----------------
+
+ * "git shortlog cruft" aborted with a BUG message when run outside a
+   Git repository.  The command has been taught to complain about
+   extra and unwanted arguments on its command line instead in such a
+   case.
+   (merge 4aa0161e83 ma/shortlog-revparse later to maint).
+
+ * "git stash push -u -- <pathspec>" gave an unnecessary and confusing
+   error message when there was no tracked files that match the
+   <pathspec>, which has been fixed.
+   (merge 353278687e tg/stash-untracked-with-pathspec-fix later to maint).
+
+ * "git tag --contains no-such-commit" gave a full list of options
+   after giving an error message.
+   (merge 3bb0923f06 ps/contains-id-error-message later to maint).
+
+ * "diff-highlight" filter (in contrib/) learned to understand "git log
+   --graph" output better.
+   (merge 4551fbba14 jk/diff-highlight-graph-fix later to maint).
+
+ * when refs that do not point at committish are given, "git
+   filter-branch" gave a misleading error messages.  This has been
+   corrected.
+   (merge f78ab355e7 yk/filter-branch-non-committish-refs later to maint).
+
+ * "git submodule status" misbehaved on a submodule that has been
+   removed from the working tree.
+   (merge 74b6bda32f rs/status-with-removed-submodule later to maint).
+
+ * When credential helper exits very quickly without reading its
+   input, it used to cause Git to die with SIGPIPE, which has been
+   fixed.
+   (merge a0d51e8d0e eb/cred-helper-ignore-sigpipe later to maint).
+
+ * "git rebase --keep-empty" still removed an empty commit if the
+   other side contained an empty commit (due to the "does an
+   equivalent patch exist already?" check), which has been corrected.
+   (merge 3d946165e1 pw/rebase-keep-empty-fixes later to maint).
+
+ * Some codepaths, including the refs API, get and keep relative
+   paths, that go out of sync when the process does chdir(2).  The
+   chdir-notify API is introduced to let these codepaths adjust these
+   cached paths to the new current directory.
+   (merge fb9c2d2703 jk/relative-directory-fix later to maint).
+
+ * "cd sub/dir && git commit ../path" ought to record the changes to
+   the file "sub/path", but this regressed long time ago.
+   (merge 86238e07ef bw/commit-partial-from-subdirectory-fix later to maint).
+
+ * Recent introduction of "--log-destination" option to "git daemon"
+   did not work well when the daemon was run under "--inetd" mode.
+   (merge e67d906d73 lw/daemon-log-destination later to maint).
+
+ * Small fix to the autoconf build procedure.
+   (merge 249482daf0 es/fread-reads-dir-autoconf-fix later to maint).
+
+ * Fix an unexploitable (because the oversized contents are not under
+   attacker's control) buffer overflow.
+   (merge d8579accfa bp/fsmonitor-bufsize-fix later to maint).
+
+ * Recent simplification of build procedure forgot a bit of tweak to
+   the build procedure of contrib/mw-to-git/
+   (merge d8698987f3 ab/simplify-perl-makefile later to maint).
+
+ * Moving a submodule that itself has submodule in it with "git mv"
+   forgot to make necessary adjustment to the nested sub-submodules;
+   now the codepath learned to recurse into the submodules.
+
+ * "git config --unset a.b", when "a.b" is the last variable in an
+   otherwise empty section "a", left an empty section "a" behind, and
+   worse yet, a subsequent "git config a.c value" did not reuse that
+   empty shell and instead created a new one.  These have been
+   (partially) corrected.
+   (merge c71d8bb38a js/empty-config-section-fix later to maint).
+
+ * "git worktree remove" learned that "-f" is a shorthand for
+   "--force" option, just like for "git worktree add".
+   (merge d228eea514 sb/worktree-remove-opt-force later to maint).
+
+ * The completion script (in contrib/) learned to clear cached list of
+   command line options upon dot-sourcing it again in a more efficient
+   way.
+   (merge 94408dc71c sg/completion-clear-cached later to maint).
+
+ * "git svn" had a minor thinko/typo which has been fixed.
+   (merge 51db271587 ab/git-svn-get-record-typofix later to maint).
+
+ * During a "rebase -i" session, the code could give older timestamp
+   to commits created by later "pick" than an earlier "reword", which
+   has been corrected.
+   (merge 12f7babd6b js/ident-date-fix later to maint).
+
+ * "git submodule status" did not check the symbolic revision name it
+   computed for the submodule HEAD is not the NULL, and threw it at
+   printf routines, which has been corrected.
+   (merge 0b5e2ea7cf nd/submodule-status-fix later to maint).
+
+ * When fed input that already has In-Reply-To: and/or References:
+   headers and told to add the same information, "git send-email"
+   added these headers separately, instead of appending to an existing
+   one, which is a violation of the RFC.  This has been corrected.
+   (merge 256be1d3f0 sa/send-email-dedup-some-headers later to maint).
+
+ * "git fast-export" had a regression in v2.15.0 era where it skipped
+   some merge commits in certain cases, which has been corrected.
+   (merge be011bbe00 ma/fast-export-skip-merge-fix later to maint).
+
+ * The code did not propagate the terminal width to subprocesses via
+   COLUMNS environment variable, which it now does.  This caused
+   trouble to "git column" helper subprocess when "git tag --column=row"
+   tried to list the existing tags on a display with non-default width.
+   (merge b5d5a567fb nd/term-columns later to maint).
+
+ * We learned that our source files with ".pl" and ".py" extensions
+   are Perl and Python files respectively and changes to them are
+   better viewed as such with appropriate diff drivers.
+   (merge 7818b619e2 ab/perl-python-attrs later to maint).
+
+ * "git rebase -i" sometimes left intermediate "# This is a
+   combination of N commits" message meant for the human consumption
+   inside an editor in the final result in certain corner cases, which
+   has been fixed.
+   (merge 15ef69314d js/rebase-i-clean-msg-after-fixup-continue later to maint).
+
+ * A test to see if the filesystem normalizes UTF-8 filename has been
+   updated to check what we need to know in a more direct way, i.e. a
+   path created in NFC form can be accessed with NFD form (or vice
+   versa) to cope with APFS as well as HFS.
+   (merge 742ae10e35 tb/test-apfs-utf8-normalization later to maint).
+
+ * "git format-patch --cover --attach" created a broken MIME multipart
+   message for the cover letter, which has been fixed by keeping the
+   cover letter as plain text file.
+   (merge 50cd54ef4e bc/format-patch-cover-no-attach later to maint).
+
+ * The split-index feature had a long-standing and dormant bug in
+   certain use of the in-core merge machinery, which has been fixed.
+   (merge 7db118303a en/unpack-trees-split-index-fix later to maint).
+
+ * Asciidoctor gives a reasonable imitation for AsciiDoc, but does not
+   render illustration in a literal block correctly when indented with
+   HT by default. The problem is fixed by forcing 8-space tabs.
+   (merge 379805051d bc/asciidoctor-tab-width later to maint).
+
+ * Code clean-up to adjust to a more recent lockfile API convention that
+   allows lockfile instances kept on the stack.
+   (merge 0fa5a2ed8d ma/lockfile-cleanup later to maint).
+
+ * the_repository->index is not a allocated piece of memory but
+   repo_clear() indiscriminately attempted to free(3) it, which has
+   been corrected.
+   (merge 74373b5f10 nd/repo-clear-keep-the-index later to maint).
+
+ * Code clean-up to avoid non-standard-conformant pointer arithmetic.
+   (merge c112084af9 rs/no-null-ptr-arith-in-fast-export later to maint).
+
+ * Code clean-up to turn history traversal more robust in a
+   semi-corrupt repository.
+   (merge 8702b30fd7 jk/unavailable-can-be-missing later to maint).
+
+ * "git update-ref A B" is supposed to ensure that ref A does not yet
+   exist when B is a NULL OID, but this check was not done correctly
+   for pseudo-refs outside refs/ hierarchy, e.g. MERGE_HEAD.
+
+ * "git submodule update" and "git submodule add" supported the
+   "--reference" option to borrow objects from a neighbouring local
+   repository like "git clone" does, but lacked the more recent
+   invention "--dissociate".  Also "git submodule add" has been taught
+   to take the "--progress" option.
+   (merge a0ef29341a cf/submodule-progress-dissociate later to maint).
+
+ * Update credential-netrc helper (in contrib/) to allow customizing
+   the GPG used to decrypt the encrypted .netrc file.
+   (merge 786ef50a23 lm/credential-netrc later to maint).
+
+ * "git submodule update" attempts two different kinds of "git fetch"
+   against the upstream repository to grab a commit bound at the
+   submodule's path, but it incorrectly gave up if the first kind
+   (i.e. a normal fetch) failed, making the second "last resort" one
+   (i.e. fetching an exact commit object by object name) ineffective.
+   This has been corrected.
+   (merge e30d833671 sb/submodule-update-try-harder later to maint).
+
+ * Error behaviour of "git grep" when it cannot read the index was
+   inconsistent with other commands that uses the index, which has
+   been corrected to error out early.
+   (merge b2aa84c789 sb/grep-die-on-unreadable-index later to maint).
+
+ * We used to call regfree() after regcomp() failed in some codepaths,
+   which have been corrected.
+   (merge 17154b1576 ma/regex-no-regfree-after-comp-fail later to maint).
+
+ * The import-tars script (in contrib/) has been taught to handle
+   tarballs with overly long paths that use PAX extended headers.
+   (merge 12ecea46e3 pa/import-tars-long-names later to maint).
+
+ * "git rev-parse Y..." etc. misbehaved when given endpoints were
+   not committishes.
+   (merge 0ed556d38f en/rev-parse-invalid-range later to maint).
+
+ * "git pull --recurse-submodules --rebase", when the submodule
+   repository's history did not have anything common between ours and
+   the upstream's, failed to execute.  We need to fetch from them to
+   continue even in such a case.
+   (merge 4d36f88be7 jt/submodule-pull-recurse-rebase later to maint).
+
+ * "git remote update" can take both a single remote nickname and a
+   nickname for remote groups, but only one of them was documented.
+   (merge a97447a42a nd/remote-update-doc later to maint).
+
+ * "index-pack --strict" has been taught to make sure that it runs the
+   final object integrity checks after making the freshly indexed
+   packfile available to itself.
+   (merge 3737746120 jk/index-pack-maint later to maint).
+
+ * Make zlib inflate codepath more robust against versions of zlib
+   that clobber unused portion of outbuf.
+   (merge b611396e97 jl/zlib-restore-nul-termination later to maint).
+
+ * Fix old merge glitch in Documentation during v2.13-rc0 era.
+   (merge 28cb06020b mw/doc-merge-enumfix later to maint).
+
+ * The code to read compressed bitmap was not careful to avoid reading
+   past the end of the file, which has been corrected.
+   (merge 1140bf01ec jk/ewah-bounds-check later to maint).
+
+ * "make NO_ICONV=NoThanks" did not override NEEDS_LIBICONV
+   (i.e. linkage of -lintl, -liconv, etc. that are platform-specific
+   tweaks), which has been corrected.
+   (merge fdb1fbbc7d es/make-no-iconv later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+   (merge 248f66ed8e nd/trace-with-env later to maint).
+   (merge 14ced5562c ys/bisect-object-id-missing-conversion-fix later to maint).
+   (merge 5988eb631a ab/doc-hash-brokenness later to maint).
+   (merge a4d4e32a70 pk/test-avoid-pipe-hiding-exit-status later to maint).
+   (merge 05e293c1ac jk/flockfile-stdio later to maint).
+   (merge e9184b0789 jk/t5561-missing-curl later to maint).
+   (merge b1801b85a3 nd/worktree-move later to maint).
+   (merge bbd374dd20 ak/bisect-doc-typofix later to maint).
+   (merge 4855f06fb3 mn/send-email-credential-doc later to maint).
+   (merge 8523b1e355 en/doc-typoes later to maint).
+   (merge 43b44ccfe7 js/t5404-path-fix later to maint).
+   (merge decf711fc1 ps/test-chmtime-get later to maint).
+   (merge 22d11a6e8e es/worktree-docs later to maint).
+   (merge 92a5dbbc22 tg/use-git-contacts later to maint).
+   (merge adc887221f tq/t1510 later to maint).
+   (merge bed21a8ad6 sg/doc-gc-quote-mismatch-fix later to maint).
+   (merge 73364e4f10 tz/doc-git-urls-reference later to maint).
+   (merge cd1e606bad bc/mailmap-self later to maint).
+   (merge f7997e3682 ao/config-api-doc later to maint).
+   (merge ee930754d8 jk/apply-p-doc later to maint).
+   (merge 011b648646 nd/pack-format-doc later to maint).
+   (merge 87a6bb701a sg/t5310-jgit-bitmap-test later to maint).
+   (merge f6b82970aa sg/t5516-fixes later to maint).
+   (merge 4362da078e sg/t7005-spaces-in-filenames-cleanup later to maint).
+   (merge 7d0ee47c11 js/test-unset-prereq later to maint).
+   (merge 5356a3c354 ah/misc-doc-updates later to maint).
+   (merge 92c4a7a129 nd/completion-aliasfiletype-typofix later to maint).
+   (merge 58bd77b66a nd/pack-unreachable-objects-doc later to maint).
+   (merge 4ed79d5203 sg/t6500-no-redirect-of-stdin later to maint).
+   (merge 17b8a2d6cd jk/config-blob-sans-repo later to maint).
+   (merge 590551ca2c rd/tag-doc-lightweight later to maint).
+   (merge 44f560fc16 rd/init-typo later to maint).
+   (merge f156a0934a rd/p4-doc-markup-env later to maint).
+   (merge 2a00502b14 tg/doc-sec-list later to maint).
+   (merge 47cc91310a jk/submodule-fsck-loose-fixup later to maint).
+   (merge efde7b725c rd/comment-typofix-in-sha1-file later to maint).
+   (merge 7eedad15df rd/diff-options-typofix later to maint).
+   (merge 58ebd936cc km/doc-workflows-typofix later to maint).
+   (merge 30aa96cdf8 rd/doc-remote-tracking-with-hyphen later to maint).
+   (merge cf317877e3 ks/branch-set-upstream later to maint).
+   (merge 8de19d6be8 sg/t7406-chain-fix later to maint).
diff --git a/Documentation/RelNotes/2.18.1.txt b/Documentation/RelNotes/2.18.1.txt
new file mode 100644
index 0000000000..2098cdd776
--- /dev/null
+++ b/Documentation/RelNotes/2.18.1.txt
@@ -0,0 +1,6 @@
+Git v2.18.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.5 and in
+v2.17.2 to address the recently reported CVE-2018-17456; see the
+release notes for those versions for details.
diff --git a/Documentation/RelNotes/2.18.2.txt b/Documentation/RelNotes/2.18.2.txt
new file mode 100644
index 0000000000..98b168aade
--- /dev/null
+++ b/Documentation/RelNotes/2.18.2.txt
@@ -0,0 +1,8 @@
+Git v2.18.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4
+and in v2.17.3, addressing the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, and CVE-2019-1387; see the release notes
+for those versions for details.
diff --git a/Documentation/RelNotes/2.18.3.txt b/Documentation/RelNotes/2.18.3.txt
new file mode 100644
index 0000000000..25143f0cec
--- /dev/null
+++ b/Documentation/RelNotes/2.18.3.txt
@@ -0,0 +1,5 @@
+Git v2.18.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.18.4.txt b/Documentation/RelNotes/2.18.4.txt
new file mode 100644
index 0000000000..e8ef858a00
--- /dev/null
+++ b/Documentation/RelNotes/2.18.4.txt
@@ -0,0 +1,5 @@
+Git v2.18.4 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.18.5.txt b/Documentation/RelNotes/2.18.5.txt
new file mode 100644
index 0000000000..dfb1de4ceb
--- /dev/null
+++ b/Documentation/RelNotes/2.18.5.txt
@@ -0,0 +1,6 @@
+Git v2.18.5 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6 to address
+the security issue CVE-2021-21300; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.19.0.txt b/Documentation/RelNotes/2.19.0.txt
new file mode 100644
index 0000000000..891c79b9cb
--- /dev/null
+++ b/Documentation/RelNotes/2.19.0.txt
@@ -0,0 +1,615 @@
+Git 2.19 Release Notes
+======================
+
+Updates since v2.18
+-------------------
+
+UI, Workflows & Features
+
+ * "git diff" compares the index and the working tree.  For paths
+   added with intent-to-add bit, the command shows the full contents
+   of them as added, but the paths themselves were not marked as new
+   files.  They are now shown as new by default.
+
+   "git apply" learned the "--intent-to-add" option so that an
+   otherwise working-tree-only application of a patch will add new
+   paths to the index marked with the "intent-to-add" bit.
+
+ * "git grep" learned the "--column" option that gives not just the
+   line number but the column number of the hit.
+
+ * The "-l" option in "git branch -l" is an unfortunate short-hand for
+   "--create-reflog", but many users, both old and new, somehow expect
+   it to be something else, perhaps "--list".  This step warns when "-l"
+   is used as a short-hand for "--create-reflog" and warns about the
+   future repurposing of the it when it is used.
+
+ * The userdiff pattern for .php has been updated.
+
+ * The content-transfer-encoding of the message "git send-email" sends
+   out by default was 8bit, which can cause trouble when there is an
+   overlong line to bust RFC 5322/2822 limit.  A new option 'auto' to
+   automatically switch to quoted-printable when there is such a line
+   in the payload has been introduced and is made the default.
+
+ * "git checkout" and "git worktree add" learned to honor
+   checkout.defaultRemote when auto-vivifying a local branch out of a
+   remote tracking branch in a repository with multiple remotes that
+   have tracking branches that share the same names.
+   (merge 8d7b558bae ab/checkout-default-remote later to maint).
+
+ * "git grep" learned the "--only-matching" option.
+
+ * "git rebase --rebase-merges" mode now handles octopus merges as
+   well.
+
+ * Add a server-side knob to skip commits in exponential/fibbonacci
+   stride in an attempt to cover wider swath of history with a smaller
+   number of iterations, potentially accepting a larger packfile
+   transfer, instead of going back one commit a time during common
+   ancestor discovery during the "git fetch" transaction.
+   (merge 42cc7485a2 jt/fetch-negotiator-skipping later to maint).
+
+ * A new configuration variable core.usereplacerefs has been added,
+   primarily to help server installations that want to ignore the
+   replace mechanism altogether.
+
+ * Teach "git tag -s" etc. a few configuration variables (gpg.format
+   that can be set to "openpgp" or "x509", and gpg.<format>.program
+   that is used to specify what program to use to deal with the format)
+   to allow x.509 certs with CMS via "gpgsm" to be used instead of
+   openpgp via "gnupg".
+
+ * Many more strings are prepared for l10n.
+
+ * "git p4 submit" learns to ask its own pre-submit hook if it should
+   continue with submitting.
+
+ * The test performed at the receiving end of "git push" to prevent
+   bad objects from entering repository can be customized via
+   receive.fsck.* configuration variables; we now have gained a
+   counterpart to do the same on the "git fetch" side, with
+   fetch.fsck.* configuration variables.
+
+ * "git pull --rebase=interactive" learned "i" as a short-hand for
+   "interactive".
+
+ * "git instaweb" has been adjusted to run better with newer Apache on
+   RedHat based distros.
+
+ * "git range-diff" is a reimplementation of "git tbdiff" that lets us
+   compare individual patches in two iterations of a topic.
+
+ * The sideband code learned to optionally paint selected keywords at
+   the beginning of incoming lines on the receiving end.
+
+ * "git branch --list" learned to take the default sort order from the
+   'branch.sort' configuration variable, just like "git tag --list"
+   pays attention to 'tag.sort'.
+
+ * "git worktree" command learned "--quiet" option to make it less
+   verbose.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The bulk of "git submodule foreach" has been rewritten in C.
+
+ * The in-core "commit" object had an all-purpose "void *util" field,
+   which was tricky to use especially in library-ish part of the
+   code.  All of the existing uses of the field has been migrated to a
+   more dedicated "commit-slab" mechanism and the field is eliminated.
+
+ * A less often used command "git show-index" has been modernized.
+   (merge fb3010c31f jk/show-index later to maint).
+
+ * The conversion to pass "the_repository" and then "a_repository"
+   throughout the object access API continues.
+
+ * Continuing with the idea to programmatically enumerate various
+   pieces of data required for command line completion, teach the
+   codebase to report the list of configuration variables
+   subcommands care about to help complete them.
+
+ * Separate "rebase -p" codepath out of "rebase -i" implementation to
+   slim down the latter and make it easier to manage.
+
+ * Make refspec parsing codepath more robust.
+
+ * Some flaky tests have been fixed.
+
+ * Continuing with the idea to programmatically enumerate various
+   pieces of data required for command line completion, the codebase
+   has been taught to enumerate options prefixed with "--no-" to
+   negate them.
+
+ * Build and test procedure for netrc credential helper (in contrib/)
+   has been updated.
+
+ * Remove unused function definitions and declarations from ewah
+   bitmap subsystem.
+
+ * Code preparation to make "git p4" closer to be usable with Python 3.
+
+ * Tighten the API to make it harder to misuse in-tree .gitmodules
+   file, even though it shares the same syntax with configuration
+   files, to read random configuration items from it.
+
+ * "git fast-import" has been updated to avoid attempting to create
+   delta against a zero-byte-long string, which is pointless.
+
+ * The codebase has been updated to compile cleanly with -pedantic
+   option.
+   (merge 2b647a05d7 bb/pedantic later to maint).
+
+ * The character display width table has been updated to match the
+   latest Unicode standard.
+   (merge 570951eea2 bb/unicode-11-width later to maint).
+
+ * test-lint now looks for broken use of "VAR=VAL shell_func" in test
+   scripts.
+
+ * Conversion from uchar[40] to struct object_id continues.
+
+ * Recent "security fix" to pay attention to contents of ".gitmodules"
+   while accepting "git push" was a bit overly strict than necessary,
+   which has been adjusted.
+
+ * "git fsck" learns to make sure the optional commit-graph file is in
+   a sane state.
+
+ * "git diff --color-moved" feature has further been tweaked.
+
+ * Code restructuring and a small fix to transport protocol v2 during
+   fetching.
+
+ * Parsing of -L[<N>][,[<M>]] parameters "git blame" and "git log"
+   take has been tweaked.
+
+ * lookup_commit_reference() and friends have been updated to find
+   in-core object for a specific in-core repository instance.
+
+ * Various glitches in the heuristics of merge-recursive strategy have
+   been documented in new tests.
+
+ * "git fetch" learned a new option "--negotiation-tip" to limit the
+   set of commits it tells the other end as "have", to reduce wasted
+   bandwidth and cycles, which would be helpful when the receiving
+   repository has a lot of refs that have little to do with the
+   history at the remote it is fetching from.
+
+ * For a large tree, the index needs to hold many cache entries
+   allocated on heap.  These cache entries are now allocated out of a
+   dedicated memory pool to amortize malloc(3) overhead.
+
+ * Tests to cover various conflicting cases have been added for
+   merge-recursive.
+
+ * Tests to cover conflict cases that involve submodules have been
+   added for merge-recursive.
+
+ * Look for broken "&&" chains that are hidden in subshell, many of
+   which have been found and corrected.
+
+ * The singleton commit-graph in-core instance is made per in-core
+   repository instance.
+
+ * "make DEVELOPER=1 DEVOPTS=pedantic" allows developers to compile
+   with -pedantic option, which may catch more problematic program
+   constructs and potential bugs.
+
+ * Preparatory code to later add json output for telemetry data has
+   been added.
+
+ * Update the way we use Coccinelle to find out-of-style code that
+   need to be modernised.
+
+ * It is too easy to misuse system API functions such as strcat();
+   these selected functions are now forbidden in this codebase and
+   will cause a compilation failure.
+
+ * Add a script (in contrib/) to help users of VSCode work better with
+   our codebase.
+
+ * The Travis CI scripts were taught to ship back the test data from
+   failed tests.
+   (merge aea8879a6a sg/travis-retrieve-trash-upon-failure later to maint).
+
+ * The parse-options machinery learned to refrain from enclosing
+   placeholder string inside a "<bra" and "ket>" pair automatically
+   without PARSE_OPT_LITERAL_ARGHELP.  Existing help text for option
+   arguments that are not formatted correctly have been identified and
+   fixed.
+   (merge 5f0df44cd7 rs/parse-opt-lithelp later to maint).
+
+ * Noiseword "extern" has been removed from function decls in the
+   header files.
+
+ * A few atoms like %(objecttype) and %(objectsize) in the format
+   specifier of "for-each-ref --format=<format>" can be filled without
+   getting the full contents of the object, but just with the object
+   header.  These cases have been optimized by calling
+   oid_object_info() API (instead of reading and inspecting the data).
+
+ * The end result of documentation update has been made to be
+   inspected more easily to help developers.
+
+ * The API to iterate over all objects learned to optionally list
+   objects in the order they appear in packfiles, which helps locality
+   of access if the caller accesses these objects while as objects are
+   enumerated.
+
+ * Improve built-in facility to catch broken &&-chain in the tests.
+
+ * The more library-ish parts of the codebase learned to work on the
+   in-core index-state instance that is passed in by their callers,
+   instead of always working on the singleton "the_index" instance.
+
+ * A test prerequisite defined by various test scripts with slightly
+   different semantics has been consolidated into a single copy and
+   made into a lazily defined one.
+   (merge 6ec633059a wc/make-funnynames-shared-lazy-prereq later to maint).
+
+ * After a partial clone, repeated fetches from promisor remote would
+   have accumulated many packfiles marked with .promisor bit without
+   getting them coalesced into fewer packfiles, hurting performance.
+   "git repack" now learned to repack them.
+
+ * Partially revert the support for multiple hash functions to regain
+   hash comparison performance; we'd think of a way to do this better
+   in the next cycle.
+
+ * "git help --config" (which is used in command line completion)
+   missed the configuration variables not described in the main
+   config.txt file but are described in another file that is included
+   by it, which has been corrected.
+
+ * The test linter code has learned that the end of here-doc mark
+   "EOF" can be quoted in a double-quote pair, not just in a
+   single-quote pair.
+
+
+Fixes since v2.18
+-----------------
+
+ * "git remote update" can take both a single remote nickname and a
+   nickname for remote groups, and the completion script (in contrib/)
+   has been taught about it.
+   (merge 9cd4382ad5 ls/complete-remote-update-names later to maint).
+
+ * "git fetch --shallow-since=<cutoff>" that specifies the cut-off
+   point that is newer than the existing history used to end up
+   grabbing the entire history.  Such a request now errors out.
+   (merge e34de73c56 nd/reject-empty-shallow-request later to maint).
+
+ * Fix for 2.17-era regression around `core.safecrlf`.
+   (merge 6cb09125be as/safecrlf-quiet-fix later to maint).
+
+ * The recent addition of "partial clone" experimental feature kicked
+   in when it shouldn't, namely, when there is no partial-clone filter
+   defined even if extensions.partialclone is set.
+   (merge cac1137dc4 jh/partial-clone later to maint).
+
+ * "git send-pack --signed" (hence "git push --signed" over the http
+   transport) did not read user ident from the config mechanism to
+   determine whom to sign the push certificate as, which has been
+   corrected.
+   (merge d067d98887 ms/send-pack-honor-config later to maint).
+
+ * "git fetch-pack --all" used to unnecessarily fail upon seeing an
+   annotated tag that points at an object other than a commit.
+   (merge c12c9df527 jk/fetch-all-peeled-fix later to maint).
+
+ * When user edits the patch in "git add -p" and the user's editor is
+   set to strip trailing whitespaces indiscriminately, an empty line
+   that is unchanged in the patch would become completely empty
+   (instead of a line with a sole SP on it).  The code introduced in
+   Git 2.17 timeframe failed to parse such a patch, but now it learned
+   to notice the situation and cope with it.
+   (merge f4d35a6b49 pw/add-p-recount later to maint).
+
+ * The code to try seeing if a fetch is necessary in a submodule
+   during a fetch with --recurse-submodules got confused when the path
+   to the submodule was changed in the range of commits in the
+   superproject, sometimes showing "(null)".  This has been corrected.
+
+ * Bugfix for "rebase -i" corner case regression.
+   (merge a9279c6785 pw/rebase-i-keep-reword-after-conflict later to maint).
+
+ * Recently added "--base" option to "git format-patch" command did
+   not correctly generate prereq patch ids.
+   (merge 15b76c1fb3 xy/format-patch-prereq-patch-id-fix later to maint).
+
+ * POSIX portability fix in Makefile to fix a glitch introduced a few
+   releases ago.
+   (merge 6600054e9b dj/runtime-prefix later to maint).
+
+ * "git filter-branch" when used with the "--state-branch" option
+   still attempted to rewrite the commits whose filtered result is
+   known from the previous attempt (which is recorded on the state
+   branch); the command has been corrected not to waste cycles doing
+   so.
+   (merge 709cfe848a mb/filter-branch-optim later to maint).
+
+ * Clarify that setting core.ignoreCase to deviate from reality would
+   not turn a case-incapable filesystem into a case-capable one.
+   (merge 48294b512a ms/core-icase-doc later to maint).
+
+ * "fsck.skipList" did not prevent a blob object listed there from
+   being inspected for is contents (e.g. we recently started to
+   inspect the contents of ".gitmodules" for certain malicious
+   patterns), which has been corrected.
+   (merge fb16287719 rj/submodule-fsck-skip later to maint).
+
+ * "git checkout --recurse-submodules another-branch" did not report
+   in which submodule it failed to update the working tree, which
+   resulted in an unhelpful error message.
+   (merge ba95d4e4bd sb/submodule-move-head-error-msg later to maint).
+
+ * "git rebase" behaved slightly differently depending on which one of
+   the three backends gets used; this has been documented and an
+   effort to make them more uniform has begun.
+   (merge b00bf1c9a8 en/rebase-consistency later to maint).
+
+ * The "--ignore-case" option of "git for-each-ref" (and its friends)
+   did not work correctly, which has been fixed.
+   (merge e674eb2528 jk/for-each-ref-icase later to maint).
+
+ * "git fetch" failed to correctly validate the set of objects it
+   received when making a shallow history deeper, which has been
+   corrected.
+   (merge cf1e7c0770 jt/connectivity-check-after-unshallow later to maint).
+
+ * Partial clone support of "git clone" has been updated to correctly
+   validate the objects it receives from the other side.  The server
+   side has been corrected to send objects that are directly
+   requested, even if they may match the filtering criteria (e.g. when
+   doing a "lazy blob" partial clone).
+   (merge a7e67c11b8 jt/partial-clone-fsck-connectivity later to maint).
+
+ * Handling of an empty range by "git cherry-pick" was inconsistent
+   depending on how the range ended up to be empty, which has been
+   corrected.
+   (merge c5e358d073 jk/empty-pick-fix later to maint).
+
+ * "git reset --merge" (hence "git merge ---abort") and "git reset --hard"
+   had trouble working correctly in a sparsely checked out working
+   tree after a conflict, which has been corrected.
+   (merge b33fdfc34c mk/merge-in-sparse-checkout later to maint).
+
+ * Correct a broken use of "VAR=VAL shell_func" in a test.
+   (merge 650161a277 jc/t3404-one-shot-export-fix later to maint).
+
+ * "git rev-parse ':/substring'" did not consider the history leading
+   only to HEAD when looking for a commit with the given substring,
+   when the HEAD is detached.  This has been fixed.
+   (merge 6b3351e799 wc/find-commit-with-pattern-on-detached-head later to maint).
+
+ * Build doc update for Windows.
+   (merge ede8d89bb1 nd/command-list later to maint).
+
+ * core.commentchar is now honored when preparing the list of commits
+   to replay in "rebase -i".
+
+ * "git pull --rebase" on a corrupt HEAD caused a segfault.  In
+   general we substitute an empty tree object when running the in-core
+   equivalent of the diff-index command, and the codepath has been
+   corrected to do so as well to fix this issue.
+   (merge 3506dc9445 jk/has-uncommitted-changes-fix later to maint).
+
+ * httpd tests saw occasional breakage due to the way its access log
+   gets inspected by the tests, which has been updated to make them
+   less flaky.
+   (merge e8b3b2e275 sg/httpd-test-unflake later to maint).
+
+ * Tests to cover more D/F conflict cases have been added for
+   merge-recursive.
+
+ * "git gc --auto" opens file descriptors for the packfiles before
+   spawning "git repack/prune", which would upset Windows that does
+   not want a process to work on a file that is open by another
+   process.  The issue has been worked around.
+   (merge 12e73a3ce4 kg/gc-auto-windows-workaround later to maint).
+
+ * The recursive merge strategy did not properly ensure there was no
+   change between HEAD and the index before performing its operation,
+   which has been corrected.
+   (merge 55f39cf755 en/dirty-merge-fixes later to maint).
+
+ * "git rebase" started exporting GIT_DIR environment variable and
+   exposing it to hook scripts when part of it got rewritten in C.
+   Instead of matching the old scripted Porcelains' behaviour,
+   compensate by also exporting GIT_WORK_TREE environment as well to
+   lessen the damage.  This can harm existing hooks that want to
+   operate on different repository, but the current behaviour is
+   already broken for them anyway.
+   (merge ab5e67d751 bc/sequencer-export-work-tree-as-well later to maint).
+
+ * "git send-email" when using in a batched mode that limits the
+   number of messages sent in a single SMTP session lost the contents
+   of the variable used to choose between tls/ssl, unable to send the
+   second and later batches, which has been fixed.
+   (merge 636f3d7ac5 jm/send-email-tls-auth-on-batch later to maint).
+
+ * The lazy clone support had a few places where missing but promised
+   objects were not correctly tolerated, which have been fixed.
+
+ * One of the "diff --color-moved" mode "dimmed_zebra" that was named
+   in an unusual way has been deprecated and replaced by
+   "dimmed-zebra".
+   (merge e3f2f5f9cd es/diff-color-moved-fix later to maint).
+
+ * The wire-protocol v2 relies on the client to send "ref prefixes" to
+   limit the bandwidth spent on the initial ref advertisement.  "git
+   clone" when learned to speak v2 forgot to do so, which has been
+   corrected.
+   (merge 402c47d939 bw/clone-ref-prefixes later to maint).
+
+ * "git diff --histogram" had a bad memory usage pattern, which has
+   been rearranged to reduce the peak usage.
+   (merge 79cb2ebb92 sb/histogram-less-memory later to maint).
+
+ * Code clean-up to use size_t/ssize_t when they are the right type.
+   (merge 7726d360b5 jk/size-t later to maint).
+
+ * The wire-protocol v2 relies on the client to send "ref prefixes" to
+   limit the bandwidth spent on the initial ref advertisement.  "git
+   fetch $remote branch:branch" that asks tags that point into the
+   history leading to the "branch" automatically followed sent to
+   narrow prefix and broke the tag following, which has been fixed.
+   (merge 2b554353a5 jt/tag-following-with-proto-v2-fix later to maint).
+
+ * When the sparse checkout feature is in use, "git cherry-pick" and
+   other mergy operations lost the skip_worktree bit when a path that
+   is excluded from checkout requires content level merge, which is
+   resolved as the same as the HEAD version, without materializing the
+   merge result in the working tree, which made the path appear as
+   deleted.  This has been corrected by preserving the skip_worktree
+   bit (and not materializing the file in the working tree).
+   (merge 2b75fb601c en/merge-recursive-skip-fix later to maint).
+
+ * The "author-script" file "git rebase -i" creates got broken when
+   we started to move the command away from shell script, which is
+   getting fixed now.
+   (merge 5522bbac20 es/rebase-i-author-script-fix later to maint).
+
+ * The automatic tree-matching in "git merge -s subtree" was broken 5
+   years ago and nobody has noticed since then, which is now fixed.
+   (merge 2ec4150713 jk/merge-subtree-heuristics later to maint).
+
+ * "git fetch $there refs/heads/s" ought to fetch the tip of the
+   branch 's', but when "refs/heads/refs/heads/s", i.e. a branch whose
+   name is "refs/heads/s" exists at the same time, fetched that one
+   instead by mistake.  This has been corrected to honor the usual
+   disambiguation rules for abbreviated refnames.
+   (merge 60650a48c0 jt/refspec-dwim-precedence-fix later to maint).
+
+ * Futureproofing a helper function that can easily be misused.
+   (merge 65bb21e77e es/want-color-fd-defensive later to maint).
+
+ * The http-backend (used for smart-http transport) used to slurp the
+   whole input until EOF, without paying attention to CONTENT_LENGTH
+   that is supplied in the environment and instead expecting the Web
+   server to close the input stream.  This has been fixed.
+   (merge eebfe40962 mk/http-backend-content-length later to maint).
+
+ * "git merge --abort" etc. did not clean things up properly when
+   there were conflicted entries in the index in certain order that
+   are involved in D/F conflicts.  This has been corrected.
+   (merge ad3762042a en/abort-df-conflict-fixes later to maint).
+
+ * "git diff --indent-heuristic" had a bad corner case performance.
+   (merge 301ef85401 sb/indent-heuristic-optim later to maint).
+
+ * The "--exec" option to "git rebase --rebase-merges" placed the exec
+   commands at wrong places, which has been corrected.
+
+ * "git verify-tag" and "git verify-commit" have been taught to use
+   the exit status of underlying "gpg --verify" to signal bad or
+   untrusted signature they found.
+   (merge 4e5dc9ca17 jc/gpg-status later to maint).
+
+ * "git mergetool" stopped and gave an extra prompt to continue after
+   the last path has been handled, which did not make much sense.
+   (merge d651a54b8a ng/mergetool-lose-final-prompt later to maint).
+
+ * Among the three codepaths we use O_APPEND to open a file for
+   appending, one used for writing GIT_TRACE output requires O_APPEND
+   implementation that behaves sensibly when multiple processes are
+   writing to the same file.  POSIX emulation used in the Windows port
+   has been updated to improve in this area.
+   (merge d641097589 js/mingw-o-append later to maint).
+
+ * "git pull --rebase -v" in a repository with a submodule barfed as
+   an intermediate process did not understand what "-v(erbose)" flag
+   meant, which has been fixed.
+   (merge e84c3cf3dc sb/pull-rebase-submodule later to maint).
+
+ * Recent update to "git config" broke updating variable in a
+   subsection, which has been corrected.
+   (merge bff7df7a87 sb/config-write-fix later to maint).
+
+ * When "git rebase -i" is told to squash two or more commits into
+   one, it labeled the log message for each commit with its number.
+   It correctly called the first one "1st commit", but the next one
+   was "commit #1", which was off-by-one.  This has been corrected.
+   (merge dd2e36ebac pw/rebase-i-squash-number-fix later to maint).
+
+ * "git rebase -i", when a 'merge <branch>' insn in its todo list
+   fails, segfaulted, which has been (minimally) corrected.
+   (merge bc9238bb09 pw/rebase-i-merge-segv-fix later to maint).
+
+ * "git cherry-pick --quit" failed to remove CHERRY_PICK_HEAD even
+   though we won't be in a cherry-pick session after it returns, which
+   has been corrected.
+   (merge 3e7dd99208 nd/cherry-pick-quit-fix later to maint).
+
+ * In a recent update in 2.18 era, "git pack-objects" started
+   producing a larger than necessary packfiles by missing
+   opportunities to use large deltas.  This has been corrected.
+
+ * The meaning of the possible values the "core.checkStat"
+   configuration variable can take were not adequately documented,
+   which has been fixed.
+   (merge 9bf5d4c4e2 nd/config-core-checkstat-doc later to maint).
+
+ * Recent "git rebase -i" update started to write bogusly formatted
+   author-script, with a matching broken reading code.  These are
+   fixed.
+
+ * Recent addition of "directory rename" heuristics to the
+   merge-recursive backend makes the command susceptible to false
+   positives and false negatives.  In the context of "git am -3",
+   which does not know about surrounding unmodified paths and thus
+   cannot inform the merge machinery about the full trees involved,
+   this risk is particularly severe.  As such, the heuristic is
+   disabled for "git am -3" to keep the machinery "more stupid but
+   predictable".
+
+ * "git merge-base" in 2.19-rc1 has performance regression when the
+   (experimental) commit-graph feature is in use, which has been
+   mitigated.
+
+ * Code cleanup, docfix, build fix, etc.
+   (merge aee9be2ebe sg/update-ref-stdin-cleanup later to maint).
+   (merge 037714252f jc/clean-after-sanity-tests later to maint).
+   (merge 5b26c3c941 en/merge-recursive-cleanup later to maint).
+   (merge 0dcbc0392e bw/config-refer-to-gitsubmodules-doc later to maint).
+   (merge bb4d000e87 bw/protocol-v2 later to maint).
+   (merge 928f0ab4ba vs/typofixes later to maint).
+   (merge d7f590be84 en/rebase-i-microfixes later to maint).
+   (merge 81d395cc85 js/rebase-recreate-merge later to maint).
+   (merge 51d1863168 tz/exclude-doc-smallfixes later to maint).
+   (merge a9aa3c0927 ds/commit-graph later to maint).
+   (merge 5cf8e06474 js/enhanced-version-info later to maint).
+   (merge 6aaded5509 tb/config-default later to maint).
+   (merge 022d2ac1f3 sb/blame-color later to maint).
+   (merge 5a06a20e0c bp/test-drop-caches-for-windows later to maint).
+   (merge dd61cc1c2e jk/ui-color-always-to-auto later to maint).
+   (merge 1e83b9bfdd sb/trailers-docfix later to maint).
+   (merge ab29f1b329 sg/fast-import-dump-refs-on-checkpoint-fix later to maint).
+   (merge 6a8ad880f0 jn/subtree-test-fixes later to maint).
+   (merge ffbd51cc60 nd/pack-objects-threading-doc later to maint).
+   (merge e9dac7be60 es/mw-to-git-chain-fix later to maint).
+   (merge fe583c6c7a rs/remote-mv-leakfix later to maint).
+   (merge 69885ab015 en/t3031-title-fix later to maint).
+   (merge 8578037bed nd/config-blame-sort later to maint).
+   (merge 8ad169c4ba hn/config-in-code-comment later to maint).
+   (merge b7446fcfdf ar/t4150-am-scissors-test-fix later to maint).
+   (merge a8132410ee js/typofixes later to maint).
+   (merge 388d0ff6e5 en/update-index-doc later to maint).
+   (merge e05aa688dd jc/update-index-doc later to maint).
+   (merge 10c600172c sg/t5310-empty-input-fix later to maint).
+   (merge 5641eb9465 jh/partial-clone-doc later to maint).
+   (merge 2711b1ad5e ab/submodule-relative-url-tests later to maint).
+   (merge ce528de023 ab/unconditional-free-and-null later to maint).
+   (merge bbc072f5d8 rs/opt-updates later to maint).
+   (merge 69d846f053 jk/use-compat-util-in-test-tool later to maint).
+   (merge 1820703045 js/larger-timestamps later to maint).
+   (merge c8b35b95e1 sg/t4051-fix later to maint).
+   (merge 30612cb670 sg/t0020-conversion-fix later to maint).
+   (merge 15da753709 sg/t7501-thinkofix later to maint).
+   (merge 79b04f9b60 sg/t3903-missing-fix later to maint).
+   (merge 2745817028 sg/t3420-autostash-fix later to maint).
+   (merge 7afb0d6777 sg/test-rebase-editor-fix later to maint).
+   (merge 6c6ce21baa es/freebsd-iconv-portability later to maint).
diff --git a/Documentation/RelNotes/2.19.1.txt b/Documentation/RelNotes/2.19.1.txt
new file mode 100644
index 0000000000..da7672674e
--- /dev/null
+++ b/Documentation/RelNotes/2.19.1.txt
@@ -0,0 +1,6 @@
+Git v2.19.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.5 and in
+v2.17.2 to address the recently reported CVE-2018-17456; see the
+release notes for those versions for details.
diff --git a/Documentation/RelNotes/2.19.2.txt b/Documentation/RelNotes/2.19.2.txt
new file mode 100644
index 0000000000..759e6ca957
--- /dev/null
+++ b/Documentation/RelNotes/2.19.2.txt
@@ -0,0 +1,108 @@
+Git v2.19.2 Release Notes
+=========================
+
+Fixes since v2.19.1
+-------------------
+
+ * "git interpret-trailers" and its underlying machinery had a buggy
+   code that attempted to ignore patch text after commit log message,
+   which triggered in various codepaths that will always get the log
+   message alone and never get such an input.
+
+ * "git rebase -i" did not clear the state files correctly when a run
+   of "squash/fixup" is aborted and then the user manually amended the
+   commit instead, which has been corrected.
+
+ * When fsmonitor is in use, after operation on submodules updates
+   .gitmodules, we lost track of the fact that we did so and relied on
+   stale fsmonitor data.
+
+ * Fix for a long-standing bug that leaves the index file corrupt when
+   it shrinks during a partial commit.
+
+ * Further fix for O_APPEND emulation on Windows
+
+ * A corner case bugfix in "git rerere" code.
+
+ * "git add ':(attr:foo)'" is not supported and is supposed to be
+   rejected while the command line arguments are parsed, but we fail
+   to reject such a command line upfront.
+
+ * "git rebase" etc. in Git 2.19 fails to abort when given an empty
+   commit log message as result of editing, which has been corrected.
+
+ * The code to backfill objects in lazily cloned repository did not
+   work correctly, which has been corrected.
+
+ * Update error messages given by "git remote" and make them consistent.
+
+ * "git update-ref" learned to make both "--no-deref" and "--stdin"
+   work at the same time.
+
+ * Recently added "range-diff" had a corner-case bug to cause it
+   segfault, which has been corrected.
+
+ * The recently introduced commit-graph auxiliary data is incompatible
+   with mechanisms such as replace & grafts that "breaks" immutable
+   nature of the object reference relationship.  Disable optimizations
+   based on its use (and updating existing commit-graph) when these
+   incompatible features are in use in the repository.
+
+ * The mailmap file update.
+
+ * The code in "git status" sometimes hit an assertion failure.  This
+   was caused by a structure that was reused without cleaning the data
+   used for the first run, which has been corrected.
+
+ * A corner-case bugfix.
+
+ * A partial clone that is configured to lazily fetch missing objects
+   will on-demand issue a "git fetch" request to the originating
+   repository to fill not-yet-obtained objects.  The request has been
+   optimized for requesting a tree object (and not the leaf blob
+   objects contained in it) by telling the originating repository that
+   no blobs are needed.
+
+ * The codepath to support the experimental split-index mode had
+   remaining "racily clean" issues fixed.
+
+ * "git log --graph" showing an octopus merge sometimes miscounted the
+   number of display columns it is consuming to show the merge and its
+   parent commits, which has been corrected.
+
+ * The implementation of run_command() API on the UNIX platforms had a
+   bug that caused a command not on $PATH to be found in the current
+   directory.
+
+ * A mutex used in "git pack-objects" were not correctly initialized
+   and this caused "git repack" to dump core on Windows.
+
+ * Under certain circumstances, "git diff D:/a/b/c D:/a/b/d" on
+   Windows would strip initial parts from the paths because they
+   were not recognized as absolute, which has been corrected.
+
+ * The receive.denyCurrentBranch=updateInstead codepath kicked in even
+   when the push should have been rejected due to other reasons, such
+   as it does not fast-forward or the update-hook rejects it, which
+   has been corrected.
+
+ * "git repack" in a shallow clone did not correctly update the
+   shallow points in the repository, leading to a repository that
+   does not pass fsck.
+
+ * Operations on promisor objects make sense in the context of only a
+   small subset of the commands that internally use the revisions
+   machinery, but the "--exclude-promisor-objects" option were taken
+   and led to nonsense results by commands like "log", to which it
+   didn't make much sense.  This has been corrected.
+
+ * The "container" mode of TravisCI is going away.  Our .travis.yml
+   file is getting prepared for the transition.
+
+ * Our test scripts can now take the '-V' option as a synonym for the
+   '--verbose-log' option.
+
+ * A regression in Git 2.12 era made "git fsck" fall into an infinite
+   loop while processing truncated loose objects.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.19.3.txt b/Documentation/RelNotes/2.19.3.txt
new file mode 100644
index 0000000000..92d7f89de6
--- /dev/null
+++ b/Documentation/RelNotes/2.19.3.txt
@@ -0,0 +1,8 @@
+Git v2.19.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4
+and in v2.17.3, addressing the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, and CVE-2019-1387; see the release notes
+for those versions for details.
diff --git a/Documentation/RelNotes/2.19.4.txt b/Documentation/RelNotes/2.19.4.txt
new file mode 100644
index 0000000000..35d0ae561b
--- /dev/null
+++ b/Documentation/RelNotes/2.19.4.txt
@@ -0,0 +1,5 @@
+Git v2.19.4 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.19.5.txt b/Documentation/RelNotes/2.19.5.txt
new file mode 100644
index 0000000000..18a4dcbfd6
--- /dev/null
+++ b/Documentation/RelNotes/2.19.5.txt
@@ -0,0 +1,5 @@
+Git v2.19.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.19.6.txt b/Documentation/RelNotes/2.19.6.txt
new file mode 100644
index 0000000000..bcca6cd258
--- /dev/null
+++ b/Documentation/RelNotes/2.19.6.txt
@@ -0,0 +1,6 @@
+Git v2.19.6 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6 and
+v2.18.5 to address the security issue CVE-2021-21300; see the
+release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.2.0.txt b/Documentation/RelNotes/2.2.0.txt
new file mode 100644
index 0000000000..e98ecbcff6
--- /dev/null
+++ b/Documentation/RelNotes/2.2.0.txt
@@ -0,0 +1,313 @@
+Git v2.2 Release Notes
+======================
+
+Updates since v2.1
+------------------
+
+Ports
+
+ * Building on older MacOS X systems automatically sets
+   the necessary NO_APPLE_COMMON_CRYPTO build-time option.
+
+ * Building with NO_PTHREADS has been resurrected.
+
+ * Compilation options have been updated a bit to better support the
+   z/OS port.
+
+
+UI, Workflows & Features
+
+ * "git archive" learned to filter what gets archived with a pathspec.
+
+ * "git config --edit --global" starts from a skeletal per-user
+   configuration file contents, instead of a total blank, when the
+   user does not already have any global config.  This immediately
+   reduces the need to later ask "Have you forgotten to set
+   core.user?", and we can add more to the template as we gain
+   more experience.
+
+ * "git stash list -p" used to be almost always a no-op because each
+   stash entry is represented as a merge commit.  It learned to show
+   the difference between the base commit version and the working tree
+   version, which is in line with what "git stash show" gives.
+
+ * Sometimes users want to report a bug they experience on their
+   repository, but they are not at liberty to share the contents of
+   the repository.  "fast-export" was taught an "--anonymize" option
+   to replace blob contents, names of people, paths and log
+   messages with bland and simple strings to help them.
+
+ * "git difftool" learned an option to stop feeding paths to the
+   diff backend when it exits with a non-zero status.
+
+ * "git grep" learned to paint (or not paint) partial matches on
+   context lines when showing "grep -C<num>" output in color.
+
+ * "log --date=iso" uses a slight variant of the ISO 8601 format that is
+   more human readable.  A new "--date=iso-strict" option gives
+   datetime output that conforms more strictly.
+
+ * The logic "git prune" uses is more resilient against various corner
+   cases.
+
+ * A broken reimplementation of Git could write an invalid index that
+   records both stage #0 and higher-stage entries for the same path.
+   We now notice and reject such an index, as there is no sensible
+   fallback (we do not know if the broken tool wanted to resolve and
+   forgot to remove the higher-stage entries, or if it wanted to unresolve
+   and forgot to remove the stage #0 entry).
+
+ * The temporary files "git mergetool" uses are renamed to avoid too
+   many dots in them (e.g. a temporary file for "hello.c" used to be
+   named e.g. "hello.BASE.4321.c" but now uses underscore instead,
+   e.g. "hello_BASE_4321.c", to allow us to have multiple variants).
+
+ * The temporary files "git mergetool" uses can be placed in a newly
+   created temporary directory, instead of the current directory, by
+   setting the mergetool.writeToTemp configuration variable.
+
+ * "git mergetool" understands "--tool bc" now, as version 4 of
+   BeyondCompare can be driven the same way as its version 3 and it
+   feels awkward to say "--tool bc3" to run version 4.
+
+ * The "pre-receive" and "post-receive" hooks are no longer required
+   to consume their input fully (not following this requirement used
+   to result in intermittent errors in "git push").
+
+ * The pretty-format specifier "%d", which expands to " (tagname)"
+   for a tagged commit, gained a cousin "%D" that just gives the
+   "tagname" without frills.
+
+ * "git push" learned "--signed" push, that allows a push (i.e.
+   request to update the refs on the other side to point at a new
+   history, together with the transmission of necessary objects) to be
+   signed, so that it can be verified and audited, using the GPG
+   signature of the person who pushed, that the tips of branches at a
+   public repository really point the commits the pusher wanted to,
+   without having to "trust" the server.
+
+ * "git interpret-trailers" is a new filter to programmatically edit
+   the tail end of the commit log messages, e.g. "Signed-off-by:".
+
+ * "git help everyday" shows the "Everyday Git in 20 commands or so"
+   document, whose contents have been updated to match more modern
+   Git practice.
+
+ * On the "git svn" front, work progresses to reduce memory consumption and
+   to improve handling of mergeinfo.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The API to manipulate the "refs" has been restructured to make it
+   more transactional, with the eventual goal to allow all-or-none
+   atomic updates and migrating the storage to something other than
+   the traditional filesystem based one (e.g. databases).
+
+ * The lockfile API and its users have been cleaned up.
+
+ * We no longer attempt to keep track of individual dependencies to
+   the header files in the build procedure, relying instead on automated
+   dependency generation support from modern compilers.
+
+ * In tests, we have been using NOT_{MINGW,CYGWIN} test prerequisites
+   long before negated prerequisites e.g. !MINGW were invented.
+   The former has been converted to the latter to avoid confusion.
+
+ * Optimized looking up a remote's configuration in a repository with very many
+   remotes defined.
+
+ * There are cases where you lock and open to write a file, close it
+   to show the updated contents to an external processes, and then have
+   to update the file again while still holding the lock; now the
+   lockfile API has support for such an access pattern.
+
+ * The API to allocate the structure to keep track of commit
+   decoration has been updated to make it less cumbersome to use.
+
+ * An in-core caching layer to let us avoid reading the same
+   configuration files several times has been added.  A few commands
+   have been converted to use this subsystem.
+
+ * Various code paths have been cleaned up and simplified by using
+   the "strbuf", "starts_with()", and "skip_prefix()" APIs more.
+
+ * A few codepaths that died when large blobs that would not fit in
+   core are involved in their operation have been taught to punt
+   instead, by e.g. marking a too-large blob as not to be diffed.
+
+ * A few more code paths in "commit" and "checkout" have been taught
+   to repopulate the cache-tree in the index, to help speed up later
+   "write-tree" (used in "commit") and "diff-index --cached" (used in
+   "status").
+
+ * A common programming mistake to assign the same short option name
+   to two separate options is detected by the parse_options() API to help
+   developers.
+
+ * The code path to write out the packed-refs file has been optimized,
+   which especially matters in a repository with a large number of
+   refs.
+
+ * The check to see if a ref $F can be created by making sure no
+   existing ref has $F/ as its prefix has been optimized, which
+   especially matters in a repository with a large number of existing
+   refs.
+
+ * "git fsck" was taught to check the contents of tag objects a bit more.
+
+ * "git hash-object" was taught a "--literally" option to help
+   debugging.
+
+ * When running a required clean filter, we do not have to mmap the
+   original before feeding the filter.  Instead, stream the file
+   contents directly to the filter and process its output.
+
+ * The scripts in the test suite can be run with the "-x" option to show
+   a shell-trace of each command they run.
+
+ * The "run-command" API learned to manage the argv and environment
+   arrays for child process, alleviating the need for the callers to
+   allocate and deallocate them.
+
+ * Some people use AsciiDoctor, instead of AsciiDoc, to format our
+   documentation set; the documentation has been adjusted to be usable
+   by both, as AsciiDoctor is pickier than AsciiDoc about its input
+   mark-up.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.1
+----------------
+
+Unless otherwise noted, all the fixes since v2.1 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git log --pretty/format=" with an empty format string did not
+   mean the more obvious "No output whatsoever" but "Use default
+   format", which was counterintuitive.
+
+ * "git -c section.var command" and "git -c section.var= command"
+   should pass the configuration value differently (the former should be a
+   boolean true, the latter should be an empty string).
+
+ * Applying a patch not generated by Git in a subdirectory used to
+   check for whitespace breakage using the attributes of incorrect
+   paths. Also whitespace checks were performed even for paths
+   excluded via the "git apply --exclude=<path>" mechanism.
+
+ * "git bundle create" with a date-range specification was meant to
+   exclude tags outside the range, but it didn't.
+
+ * "git add x" where x used to be a directory and is now a
+   symbolic link to a directory misbehaved.
+
+ * The prompt script checked the $GIT_DIR/ref/stash file to see if there
+   is a stash, which was a no-no.
+
+ * Pack-protocol documentation had a minor typo.
+
+ * "git checkout -m" did not switch to another branch while carrying
+   the local changes forward when a path was deleted from the index.
+
+ * "git daemon" (with NO_IPV6 build configuration) used to incorrectly
+   use the hostname even when gethostbyname() reported that the given
+   hostname is not found.
+   (merge 107efbe rs/daemon-fixes later to maint).
+
+ * With sufficiently long refnames, "git fast-import" could have
+   overflowed an on-stack buffer.
+
+ * After "pack-refs --prune" packed refs at the top-level, it failed
+   to prune them.
+
+ * Progress output from "git gc --auto" was visible in "git fetch -q".
+
+ * We used to pass -1000 to poll(2), expecting it to also mean "no
+   timeout", which should be spelled as -1.
+
+ * "git rebase" documentation was unclear that it is required to
+   specify on what <upstream> the rebase is to be done when telling it
+   to first check out <branch>.
+   (merge 95c6826 so/rebase-doc later to maint).
+
+ * "git push" over HTTP transport had an artificial limit on the number of
+   refs that can be pushed, imposed by the command line length.
+   (merge 26be19b jk/send-pack-many-refspecs later to maint).
+
+ * When receiving an invalid pack stream that records the same object
+   twice, multiple threads got confused due to a race.
+   (merge ab791dd jk/index-pack-threading-races later to maint).
+
+ * An attempt to remove the entire tree in the "git fast-import" input
+   stream caused it to misbehave.
+   (merge 2668d69 mb/fast-import-delete-root later to maint).
+
+ * Reachability check (used in "git prune" and friends) did not add a
+   detached HEAD as a starting point to traverse objects still in use.
+   (merge c40fdd0 mk/reachable-protect-detached-head later to maint).
+
+ * "git config --add section.var val" when section.var already has an
+   empty-string value used to lose the empty-string value.
+   (merge c1063be ta/config-add-to-empty-or-true-fix later to maint).
+
+ * "git fsck" failed to report that it found corrupt objects via its
+   exit status in some cases.
+   (merge 30d1038 jk/fsck-exit-code-fix later to maint).
+
+ * Use of the "--verbose" option used to break "git branch --merged".
+   (merge 12994dd jk/maint-branch-verbose-merged later to maint).
+
+ * Some MUAs mangle a line in a message that begins with "From " to
+   ">From " when writing to a mailbox file, and feeding such an input
+   to "git am" used to lose such a line.
+   (merge 85de86a jk/mbox-from-line later to maint).
+
+ * "rev-parse --verify --quiet $name" is meant to quietly exit with a
+   non-zero status when $name is not a valid object name, but still
+   gave error messages in some cases.
+
+ * A handful of C source files have been updated to include
+   "git-compat-util.h" as the first thing, to conform better to our
+   coding guidelines.
+   (merge 1c4b660 da/include-compat-util-first-in-c later to maint).
+
+ * The t7004 test, which tried to run Git with small stack space, has been
+   updated to use a bit larger stack to avoid false breakage on some
+   platforms.
+   (merge b9a1907 sk/tag-contains-wo-recursion later to maint).
+
+ * A few documentation pages had example sections marked up not quite
+   correctly, which passed AsciiDoc but failed with AsciiDoctor.
+   (merge c30c43c bc/asciidoc-pretty-formats-fix later to maint).
+   (merge f8a48af bc/asciidoc later to maint).
+
+ * "gitweb" used deprecated CGI::startfrom, which was removed from
+   CGI.pm as of 4.04; use CGI::start_from instead.
+   (merge 4750f4b rm/gitweb-start-form later to maint).
+
+ * Newer versions of 'meld' break the auto-detection we use to see if
+   they are new enough to support the `--output` option.
+   (merge b12d045 da/mergetool-meld later to maint).
+
+ * "git pack-objects" forgot to disable the codepath to generate the
+   object reachability bitmap when it needs to split the resulting
+   pack.
+   (merge 2113471 jk/pack-objects-no-bitmap-when-splitting later to maint).
+
+ * The code to use cache-tree trusted the on-disk data too much and
+   fell into an infinite loop upon seeing an incorrectly recorded
+   index file.
+   (merge 729dbbd jk/cache-tree-protect-from-broken-libgit2 later to maint).
+
+ * "git fetch" into a repository where branch B was deleted earlier,
+   back when it had reflog enabled, and then branch B/C is fetched
+   into it without reflog enabled, which is arguably an unlikely
+   corner case, unnecessarily failed.
+   (merge aae828b jk/fetch-reflog-df-conflict later to maint).
+
+ * "git log --first-parent -L..." used to crash.
+   (merge a8787c5 tm/line-log-first-parent later to maint).
diff --git a/Documentation/RelNotes/2.2.1.txt b/Documentation/RelNotes/2.2.1.txt
new file mode 100644
index 0000000000..d5a3cd9e73
--- /dev/null
+++ b/Documentation/RelNotes/2.2.1.txt
@@ -0,0 +1,34 @@
+Git v2.2.1 Release Notes
+========================
+
+Fixes since v2.2
+----------------
+
+ * We used to allow committing a path ".Git/config" with Git that is
+   running on a case sensitive filesystem, but an attempt to check out
+   such a path with Git that runs on a case insensitive filesystem
+   would have clobbered ".git/config", which is definitely not what
+   the user would have expected.  Git now prevents you from tracking
+   a path with ".Git" (in any case combination) as a path component.
+
+ * On Windows, certain path components that are different from ".git"
+   are mapped to ".git", e.g. "git~1/config" is treated as if it were
+   ".git/config".  HFS+ has a similar issue, where certain unicode
+   codepoints are ignored, e.g. ".g\u200cit/config" is treated as if
+   it were ".git/config".  Pathnames with these potential issues are
+   rejected on the affected systems.  Git on systems that are not
+   affected by this issue (e.g. Linux) can also be configured to
+   reject them to ensure cross platform interoperability of the hosted
+   projects.
+
+ * "git fsck" notices a tree object that records such a path that can
+   be confused with ".git", and with receive.fsckObjects configuration
+   set to true, an attempt to "git push" such a tree object will be
+   rejected.  Such a path may not be a problem on a well behaving
+   filesystem but in order to protect those on HFS+ and on case
+   insensitive filesystems, this check is enabled on all platforms.
+
+A big "thanks!" for bringing this issue to us goes to our friends in
+the Mercurial land, namely, Matt Mackall and Augie Fackler.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.2.2.txt b/Documentation/RelNotes/2.2.2.txt
new file mode 100644
index 0000000000..b19a35d94f
--- /dev/null
+++ b/Documentation/RelNotes/2.2.2.txt
@@ -0,0 +1,63 @@
+Git v2.2.2 Release Notes
+========================
+
+Fixes since v2.2.1
+------------------
+
+ * "git checkout $treeish $path", when $path in the index and the
+   working tree already matched what is in $treeish at the $path,
+   still overwrote the $path unnecessarily.
+
+ * "git config --get-color" did not parse its command line arguments
+   carefully.
+
+ * open() emulated on Windows platforms did not give EISDIR upon
+   an attempt to open a directory for writing.
+
+ * A few code paths used abs() when they should have used labs() on
+   long integers.
+
+ * "gitweb" used to depend on a behaviour recent CGI.pm deprecated.
+
+ * "git init" (hence "git clone") initialized the per-repository
+   configuration file .git/config with x-bit by mistake.
+
+ * Git 2.0 was supposed to make the "simple" mode for the default of
+   "git push", but it didn't.
+
+ * "Everyday" document had a broken link.
+
+ * The build procedure did not bother fixing perl and python scripts
+   when NO_PERL and NO_PYTHON build-time configuration changed.
+
+ * The code that reads the reflog from the newer to the older entries
+   did not handle an entry that crosses a boundary of block it uses to
+   read them correctly.
+
+ * "git apply" was described in the documentation to take --ignore-date
+   option, which it does not.
+
+ * Traditionally we tried to avoid interpreting date strings given by
+   the user as future dates, e.g. GIT_COMMITTER_DATE=2014-12-10 when
+   used early November 2014 was taken as "October 12, 2014" because it
+   is likely that a date in the future, December 10, is a mistake.
+   This heuristics has been loosened to allow people to express future
+   dates (most notably, --until=<date> may want to be far in the
+   future) and we no longer tiebreak by future-ness of the date when
+
+    (1) ISO-like format is used, and
+    (2) the string can make sense interpreted as both y-m-d and y-d-m.
+
+   Git may still have to use the heuristics to tiebreak between dd/mm/yy
+   and mm/dd/yy, though.
+
+ * The code to abbreviate an object name to its short unique prefix
+   has been optimized when no abbreviation was requested.
+
+ * "git add --ignore-errors ..." did not ignore an error to
+   give a file that did not exist.
+
+ * Git did not correctly read an overlong refname from a packed refs
+   file.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.2.3.txt b/Documentation/RelNotes/2.2.3.txt
new file mode 100644
index 0000000000..5bfffa4106
--- /dev/null
+++ b/Documentation/RelNotes/2.2.3.txt
@@ -0,0 +1,9 @@
+Git v2.2.3 Release Notes
+========================
+
+Fixes since v2.2.2
+------------------
+
+ * A handful of codepaths that used to use fixed-sized arrays to hold
+   pathnames have been corrected to use strbuf and other mechanisms to
+   allow longer pathnames without fearing overflows.
diff --git a/Documentation/RelNotes/2.20.0.txt b/Documentation/RelNotes/2.20.0.txt
new file mode 100644
index 0000000000..3dd7e6e1fc
--- /dev/null
+++ b/Documentation/RelNotes/2.20.0.txt
@@ -0,0 +1,700 @@
+Git 2.20 Release Notes
+======================
+
+Backward Compatibility Notes
+----------------------------
+
+ * "git branch -l <foo>" used to be a way to ask a reflog to be
+   created while creating a new branch, but that is no longer the
+   case.  It is a short-hand for "git branch --list <foo>" now.
+
+ * "git push" into refs/tags/* hierarchy is rejected without getting
+   forced, but "git fetch" (misguidedly) used the "fast forwarding"
+   rule used for the refs/heads/* hierarchy; this has been corrected,
+   which means some fetches of tags that did not fail with older
+   version of Git will fail without "--force" with this version.
+
+ * "git help -a" now gives verbose output (same as "git help -av").
+   Those who want the old output may say "git help --no-verbose -a"..
+
+ * "git cpn --help", when "cpn" is an alias to, say, "cherry-pick -n",
+   reported only the alias expansion of "cpn" in earlier versions of
+   Git.  It now runs "git cherry-pick --help" to show the manual page
+   of the command, while sending the alias expansion to the standard
+   error stream.
+
+ * "git send-email" learned to grab address-looking string on any
+   trailer whose name ends with "-by". This is a backward-incompatible
+   change.  Adding "--suppress-cc=misc-by" on the command line, or
+   setting sendemail.suppresscc configuration variable to "misc-by",
+   can be used to disable this behaviour.
+
+
+Updates since v2.19
+-------------------
+
+UI, Workflows & Features
+
+ * Running "git clone" against a project that contain two files with
+   pathnames that differ only in cases on a case insensitive
+   filesystem would result in one of the files lost because the
+   underlying filesystem is incapable of holding both at the same
+   time.  An attempt is made to detect such a case and warn.
+
+ * "git checkout -b newbranch [HEAD]" should not have to do as much as
+   checking out a commit different from HEAD.  An attempt is made to
+   optimize this special case.
+
+ * "git rev-list --stdin </dev/null" used to be an error; it now shows
+   no output without an error.  "git rev-list --stdin --default HEAD"
+   still falls back to the given default when nothing is given on the
+   standard input.
+
+ * Lift code from GitHub to restrict delta computation so that an
+   object that exists in one fork is not made into a delta against
+   another object that does not appear in the same forked repository.
+
+ * "git format-patch" learned new "--interdiff" and "--range-diff"
+   options to explain the difference between this version and the
+   previous attempt in the cover letter (or after the three-dashes as
+   a comment).
+
+ * "git mailinfo" used in "git am" learned to make a best-effort
+   recovery of a patch corrupted by MUA that sends text/plain with
+   format=flawed option.
+   (merge 3aa4d81f88 rs/mailinfo-format-flowed later to maint).
+
+ * The rules used by "git push" and "git fetch" to determine if a ref
+   can or cannot be updated were inconsistent; specifically, fetching
+   to update existing tags were allowed even though tags are supposed
+   to be unmoving anchoring points.  "git fetch" was taught to forbid
+   updates to existing tags without the "--force" option.
+
+ * "git multi-pack-index" learned to detect corruption in the .midx
+   file it uses, and this feature has been integrated into "git fsck".
+
+ * Generation of (experimental) commit-graph files have so far been
+   fairly silent, even though it takes noticeable amount of time in a
+   meaningfully large repository.  The users will now see progress
+   output.
+
+ * The minimum version of Windows supported by Windows port of Git is
+   now set to Vista.
+
+ * The completion script (in contrib/) learned to complete a handful of
+   options "git stash list" command takes.
+
+ * The completion script (in contrib/) learned that "git fetch
+   --multiple" only takes remote names as arguments and no refspecs.
+
+ * "git status" learns to show progress bar when refreshing the index
+   takes a long time.
+   (merge ae9af12287 nd/status-refresh-progress later to maint).
+
+ * "git help -a" and "git help -av" give different pieces of
+   information, and generally the "verbose" version is more friendly
+   to the new users.  "git help -a" by default now uses the more
+   verbose output (with "--no-verbose", you can go back to the
+   original).  Also "git help -av" now lists aliases and external
+   commands, which it did not used to.
+
+ * Unlike "grep", "git grep" by default recurses to the whole tree.
+   The command learned "git grep --recursive" option, so that "git
+   grep --no-recursive" can serve as a synonym to setting the
+   max-depth to 0.
+
+ * When pushing into a repository that borrows its objects from an
+   alternate object store, "git receive-pack" that responds to the
+   push request on the other side lists the tips of refs in the
+   alternate to reduce the amount of objects transferred.  This
+   sometimes is detrimental when the number of refs in the alternate
+   is absurdly large, in which case the bandwidth saved in potentially
+   fewer objects transferred is wasted in excessively large ref
+   advertisement.  The alternate refs that are advertised are now
+   configurable with a pair of configuration variables.
+
+ * "git cmd --help" when "cmd" is aliased used to only say "cmd is
+   aliased to ...".  Now it shows that to the standard error stream
+   and runs "git $cmd --help" where $cmd is the first word of the
+   alias expansion.
+
+ * The documentation of "git gc" has been updated to mention that it
+   is no longer limited to "pruning away cruft" but also updates
+   ancillary files like commit-graph as a part of repository
+   optimization.
+
+ * "git p4 unshelve" improvements.
+
+ * The logic to select the default user name and e-mail on Windows has
+   been improved.
+   (merge 501afcb8b0 js/mingw-default-ident later to maint).
+
+ * The "rev-list --filter" feature learned to exclude all trees via
+   "tree:0" filter.
+
+ * "git send-email" learned to grab address-looking string on any
+   trailer whose name ends with "-by"; --suppress-cc=misc-by on the
+   command line, or setting sendemail.suppresscc configuration
+   variable to "misc-by", can be used to disable this behaviour.
+
+ * "git mergetool" learned to take the "--[no-]gui" option, just like
+   "git difftool" does.
+
+ * "git rebase -i" learned a new insn, 'break', that the user can
+   insert in the to-do list.  Upon hitting it, the command returns
+   control back to the user.
+
+ * New "--pretty=format:" placeholders %GF and %GP that show the GPG
+   key fingerprints have been invented.
+
+ * On platforms with recent cURL library, http.sslBackend configuration
+   variable can be used to choose a different SSL backend at runtime.
+   The Windows port uses this mechanism to switch between OpenSSL and
+   Secure Channel while talking over the HTTPS protocol.
+
+ * "git send-email" learned to disable SMTP authentication via the
+   "--smtp-auth=none" option, even when the smtp username is given
+   (which turns the authentication on by default).
+
+ * A fourth class of configuration files (in addition to the
+   traditional "system wide", "per user in the $HOME directory" and
+   "per repository in the $GIT_DIR/config") has been introduced so
+   that different worktrees that share the same repository (hence the
+   same $GIT_DIR/config file) can use different customization.
+
+ * A pattern with '**' that does not have a slash on either side used
+   to be an invalid one, but the code now treats such double-asterisks
+   the same way as two normal asterisks that happen to be adjacent to
+   each other.
+   (merge e5bbe09e88 nd/wildmatch-double-asterisk later to maint).
+
+ * The "--no-patch" option, which can be used to get a high-level
+   overview without the actual line-by-line patch difference shown, of
+   the "range-diff" command was earlier broken, which has been
+   corrected.
+
+ * The recently merged "rebase in C" has an escape hatch to use the
+   scripted version when necessary, but it hasn't been documented,
+   which has been corrected.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Developer builds now use -Wunused-function compilation option.
+
+ * One of our CI tests to run with "unusual/experimental/random"
+   settings now also uses commit-graph and midx.
+
+ * When there are too many packfiles in a repository (which is not
+   recommended), looking up an object in these would require
+   consulting many pack .idx files; a new mechanism to have a single
+   file that consolidates all of these .idx files is introduced.
+
+ * "git submodule update" is getting rewritten piece-by-piece into C.
+
+ * The code for computing history reachability has been shuffled,
+   obtained a bunch of new tests to cover them, and then being
+   improved.
+
+ * The unpack_trees() API used in checking out a branch and merging
+   walks one or more trees along with the index.  When the cache-tree
+   in the index tells us that we are walking a tree whose flattened
+   contents is known (i.e. matches a span in the index), as linearly
+   scanning a span in the index is much more efficient than having to
+   open tree objects recursively and listing their entries, the walk
+   can be optimized, which has been done.
+
+ * When creating a thin pack, which allows objects to be made into a
+   delta against another object that is not in the resulting pack but
+   is known to be present on the receiving end, the code learned to
+   take advantage of the reachability bitmap; this allows the server
+   to send a delta against a base beyond the "boundary" commit.
+
+ * spatch transformation to replace boolean uses of !hashcmp() to
+   newly introduced oideq() is added, and applied, to regain
+   performance lost due to support of multiple hash algorithms.
+
+ * Fix a bug in which the same path could be registered under multiple
+   worktree entries if the path was missing (for instance, was removed
+   manually).  Also, as a convenience, expand the number of cases in
+   which --force is applicable.
+
+ * Split Documentation/config.txt for easier maintenance.
+   (merge 6014363f0b nd/config-split later to maint).
+
+ * Test helper binaries clean-up.
+   (merge c9a1f4161f nd/test-tool later to maint).
+
+ * Various tests have been updated to make it easier to swap the
+   hash function used for object identification.
+   (merge ae0c89d41b bc/hash-independent-tests later to maint).
+
+ * Update fsck.skipList implementation and documentation.
+   (merge 371a655074 ab/fsck-skiplist later to maint).
+
+ * An alias that expands to another alias has so far been forbidden,
+   but now it is allowed to create such an alias.
+
+ * Various test scripts have been updated for style and also correct
+   handling of exit status of various commands.
+
+ * "gc --auto" ended up calling exit(-1) upon error, which has been
+   corrected to use exit(1).  Also the error reporting behaviour when
+   daemonized has been updated to exit with zero status when stopping
+   due to a previously discovered error (which implies there is no
+   point running gc to improve the situation); we used to exit with
+   failure in such a case.
+
+ * Various codepaths in the core-ish part learned to work on an
+   arbitrary in-core index structure, not necessarily the default
+   instance "the_index".
+   (merge b3c7eef9b0 nd/the-index later to maint).
+
+ * Code clean-up in the internal machinery used by "git status" and
+   "git commit --dry-run".
+   (merge 73ba5d78b4 ss/wt-status-committable later to maint).
+
+ * Some environment variables that control the runtime options of Git
+   used during tests are getting renamed for consistency.
+   (merge 4231d1ba99 bp/rename-test-env-var later to maint).
+
+ * A pair of new extensions to the index file have been introduced.
+   They allow the index file to be read in parallel for performance.
+
+ * The oidset API was built on top of the oidmap API which in turn is
+   on the hashmap API.  Replace the implementation to build on top of
+   the khash API and gain performance.
+
+ * Over some transports, fetching objects with an exact commit object
+   name can be done without first seeing the ref advertisements.  The
+   code has been optimized to exploit this.
+
+ * In a partial clone that will lazily be hydrated from the
+   originating repository, we generally want to avoid "does this
+   object exist (locally)?" on objects that we deliberately omitted
+   when we created the clone.  The cache-tree codepath (which is used
+   to write a tree object out of the index) however insisted that the
+   object exists, even for paths that are outside of the partial
+   checkout area.  The code has been updated to avoid such a check.
+
+ * To help developers, an EditorConfig file that attempts to follow
+   the project convention has been added.
+   (merge b548d698a0 bc/editorconfig later to maint).
+
+ * The result of coverage test can be combined with "git blame" to
+   check the test coverage of code introduced recently with a new
+   'coverage-diff' tool (in contrib/).
+   (merge 783faedd65 ds/coverage-diff later to maint).
+
+ * An experiment to fuzz test a few areas, hopefully we can gain more
+   coverage to various areas.
+
+ * More codepaths are moving away from hardcoded hash sizes.
+
+ * The way the Windows port figures out the current directory has been
+   improved.
+
+ * The way DLLs are loaded on the Windows port has been improved.
+
+ * Some tests have been reorganized and renamed; "ls t/" now gives a
+   better overview of what is tested for these scripts than before.
+
+ * "git rebase" and "git rebase -i" have been reimplemented in C.
+
+ * Windows port learned to use nano-second resolution file timestamps.
+
+ * The overly large Documentation/config.txt file have been split into
+   million little pieces.  This potentially allows each individual piece
+   to be included into the manual page of the command it affects more easily.
+
+ * Replace three string-list instances used as look-up tables in "git
+   fetch" with hashmaps.
+
+ * Unify code to read the author-script used in "git am" and the
+   commands that use the sequencer machinery, e.g. "git rebase -i".
+
+ * In preparation to the day when we can deprecate and remove the
+   "rebase -p", make sure we can skip and later remove tests for
+   it.
+
+ * The history traversal used to implement the tag-following has been
+   optimized by introducing a new helper.
+
+ * The helper function to refresh the cached stat information in the
+   in-core index has learned to perform the lstat() part of the
+   operation in parallel on multi-core platforms.
+
+ * The code to traverse objects for reachability, used to decide what
+   objects are unreferenced and expendable, have been taught to also
+   consider per-worktree refs of other worktrees as starting points to
+   prevent data loss.
+
+ * "git add" needs to internally run "diff-files" equivalent, and the
+   codepath learned the same optimization as "diff-files" has to run
+   lstat(2) in parallel to find which paths have been updated in the
+   working tree.
+
+ * The procedure to install dependencies before testing at Travis CI
+   is getting revamped for both simplicity and flexibility, taking
+   advantage of the recent move to the vm-based environment.
+
+ * The support for format-patch (and send-email) by the command-line
+   completion script (in contrib/) has been simplified a bit.
+
+ * The revision walker machinery learned to take advantage of the
+   commit generation numbers stored in the commit-graph file.
+
+ * The codebase has been cleaned up to reduce "#ifndef NO_PTHREADS".
+
+ * The way -lcurl library gets linked has been simplified by taking
+   advantage of the fact that we can just ask curl-config command how.
+
+ * Various functions have been audited for "-Wunused-parameter" warnings
+   and bugs in them got fixed.
+
+ * A sanity check for start-up sequence has been added in the config
+   API codepath.
+
+ * The build procedure to link for fuzzing test has been made
+   customizable with a new Makefile variable.
+
+ * The way "git rebase" parses and forwards the command line options
+   meant for underlying "git am" has been revamped, which fixed for
+   options with parameters that were not passed correctly.
+
+ * Our testing framework uses a special i18n "poisoned localization"
+   feature to find messages that ought to stay constant but are
+   incorrectly marked to be translated.  This feature has been made
+   into a runtime option (it used to be a compile-time option).
+
+ * "git push" used to check ambiguities between object-names and
+   refnames while processing the list of refs' old and new values,
+   which was unnecessary (as it knew that it is feeding raw object
+   names).  This has been optimized out.
+
+ * The xcurl_off_t() helper function is used to cast size_t to
+   curl_off_t, but some compilers gave warnings against the code to
+   ensure the casting is done without wraparound, when size_t is
+   narrower than curl_off_t.  This warning has been squelched.
+
+ * Code preparation to replace ulong vars with size_t vars where
+   appropriate continues.
+
+ * The "test installed Git" mode of our test suite has been updated to
+   work better.
+
+ * A coding convention around the Coccinelle semantic patches to have
+   two classes to ease code migration process has been proposed and
+   its support has been added to the Makefile.
+
+ * The "container" mode of TravisCI is going away.  Our .travis.yml
+   file is getting prepared for the transition.
+   (merge 32ee384be8 ss/travis-ci-force-vm-mode later to maint).
+
+ * Our test scripts can now take the '-V' option as a synonym for the
+   '--verbose-log' option.
+   (merge a5f52c6dab sg/test-verbose-log later to maint).
+
+
+Fixes since v2.19
+-----------------
+
+ * "git interpret-trailers" and its underlying machinery had a buggy
+   code that attempted to ignore patch text after commit log message,
+   which triggered in various codepaths that will always get the log
+   message alone and never get such an input.
+   (merge 66e83d9b41 jk/trailer-fixes later to maint).
+
+ * Malformed or crafted data in packstream can make our code attempt
+   to read or write past the allocated buffer and abort, instead of
+   reporting an error, which has been fixed.
+
+ * "git rebase -i" did not clear the state files correctly when a run
+   of "squash/fixup" is aborted and then the user manually amended the
+   commit instead, which has been corrected.
+   (merge 10d2f35436 js/rebase-i-autosquash-fix later to maint).
+
+ * When fsmonitor is in use, after operation on submodules updates
+   .gitmodules, we lost track of the fact that we did so and relied on
+   stale fsmonitor data.
+   (merge 43f1180814 bp/mv-submodules-with-fsmonitor later to maint).
+
+ * Fix for a long-standing bug that leaves the index file corrupt when
+   it shrinks during a partial commit.
+   (merge 6c003d6ffb jk/reopen-tempfile-truncate later to maint).
+
+ * Further fix for O_APPEND emulation on Windows
+   (merge eeaf7ddac7 js/mingw-o-append later to maint).
+
+ * A corner case bugfix in "git rerere" code.
+   (merge ad2bf0d9b4 en/rerere-multi-stage-1-fix later to maint).
+
+ * "git add ':(attr:foo)'" is not supported and is supposed to be
+   rejected while the command line arguments are parsed, but we fail
+   to reject such a command line upfront.
+   (merge 84d938b732 nd/attr-pathspec-fix later to maint).
+
+ * Recent update broke the reachability algorithm when refs (e.g.
+   tags) that point at objects that are not commit were involved,
+   which has been fixed.
+
+ * "git rebase" etc. in Git 2.19 fails to abort when given an empty
+   commit log message as result of editing, which has been corrected.
+   (merge a3ec9eaf38 en/sequencer-empty-edit-result-aborts later to maint).
+
+ * The code to backfill objects in lazily cloned repository did not
+   work correctly, which has been corrected.
+   (merge e68302011c jt/lazy-object-fetch-fix later to maint).
+
+ * Update error messages given by "git remote" and make them consistent.
+   (merge 5025425dff ms/remote-error-message-update later to maint).
+
+ * "git update-ref" learned to make both "--no-deref" and "--stdin"
+   work at the same time.
+   (merge d345e9fbe7 en/update-ref-no-deref-stdin later to maint).
+
+ * Recently added "range-diff" had a corner-case bug to cause it
+   segfault, which has been corrected.
+   (merge e467a90c7a tg/range-diff-corner-case-fix later to maint).
+
+ * The recently introduced commit-graph auxiliary data is incompatible
+   with mechanisms such as replace & grafts that "breaks" immutable
+   nature of the object reference relationship.  Disable optimizations
+   based on its use (and updating existing commit-graph) when these
+   incompatible features are in use in the repository.
+   (merge 829a321569 ds/commit-graph-with-grafts later to maint).
+
+ * The mailmap file update.
+   (merge 255eb03edf jn/mailmap-update later to maint).
+
+ * The code in "git status" sometimes hit an assertion failure.  This
+   was caused by a structure that was reused without cleaning the data
+   used for the first run, which has been corrected.
+   (merge 3e73cc62c0 en/status-multiple-renames-to-the-same-target-fix later to maint).
+
+ * "git fetch $repo $object" in a partial clone did not correctly
+   fetch the asked-for object that is referenced by an object in
+   promisor packfile, which has been fixed.
+
+ * A corner-case bugfix.
+   (merge c5cbb27cb5 sm/show-superproject-while-conflicted later to maint).
+
+ * Various fixes to "diff --color-moved-ws".
+
+ * A partial clone that is configured to lazily fetch missing objects
+   will on-demand issue a "git fetch" request to the originating
+   repository to fill not-yet-obtained objects.  The request has been
+   optimized for requesting a tree object (and not the leaf blob
+   objects contained in it) by telling the originating repository that
+   no blobs are needed.
+   (merge 4c7f9567ea jt/non-blob-lazy-fetch later to maint).
+
+ * The codepath to support the experimental split-index mode had
+   remaining "racily clean" issues fixed.
+   (merge 4c490f3d32 sg/split-index-racefix later to maint).
+
+ * "git log --graph" showing an octopus merge sometimes miscounted the
+   number of display columns it is consuming to show the merge and its
+   parent commits, which has been corrected.
+   (merge 04005834ed np/log-graph-octopus-fix later to maint).
+
+ * "git range-diff" did not work well when the compared ranges had
+   changes in submodules and the "--submodule=log" was used.
+
+ * The implementation of run_command() API on the UNIX platforms had a
+   bug that caused a command not on $PATH to be found in the current
+   directory.
+   (merge f67b980771 jk/run-command-notdot later to maint).
+
+ * A mutex used in "git pack-objects" were not correctly initialized
+   and this caused "git repack" to dump core on Windows.
+   (merge 34204c8166 js/pack-objects-mutex-init-fix later to maint).
+
+ * Under certain circumstances, "git diff D:/a/b/c D:/a/b/d" on
+   Windows would strip initial parts from the paths because they
+   were not recognized as absolute, which has been corrected.
+   (merge ffd04e92e2 js/diff-notice-has-drive-prefix later to maint).
+
+ * The receive.denyCurrentBranch=updateInstead codepath kicked in even
+   when the push should have been rejected due to other reasons, such
+   as it does not fast-forward or the update-hook rejects it, which
+   has been corrected.
+   (merge b072a25fad jc/receive-deny-current-branch-fix later to maint).
+
+ * The logic to determine the archive type "git archive" uses did not
+   correctly kick in for "git archive --remote", which has been
+   corrected.
+
+ * "git repack" in a shallow clone did not correctly update the
+   shallow points in the repository, leading to a repository that
+   does not pass fsck.
+   (merge 5dcfbf564c js/shallow-and-fetch-prune later to maint).
+
+ * Some codepaths failed to form a proper URL when .gitmodules record
+   the URL to a submodule repository as relative to the repository of
+   superproject, which has been corrected.
+   (merge e0a862fdaf sb/submodule-url-to-absolute later to maint).
+
+ * "git fetch" over protocol v2 into a shallow repository failed to
+   fetch full history behind a new tip of history that was diverged
+   before the cut-off point of the history that was previously fetched
+   shallowly.
+
+ * The command line completion machinery (in contrib/) has been
+   updated to allow the completion script to tweak the list of options
+   that are reported by the parse-options machinery correctly.
+   (merge 276b49ff34 nd/completion-negation later to maint).
+
+ * Operations on promisor objects make sense in the context of only a
+   small subset of the commands that internally use the revisions
+   machinery, but the "--exclude-promisor-objects" option were taken
+   and led to nonsense results by commands like "log", to which it
+   didn't make much sense.  This has been corrected.
+   (merge 669b1d2aae md/exclude-promisor-objects-fix later to maint).
+
+ * A regression in Git 2.12 era made "git fsck" fall into an infinite
+   loop while processing truncated loose objects.
+   (merge 18ad13e5b2 jk/detect-truncated-zlib-input later to maint).
+
+ * "git ls-remote $there foo" was broken by recent update for the
+   protocol v2 and stopped showing refs that match 'foo' that are not
+   refs/{heads,tags}/foo, which has been fixed.
+   (merge 6a139cdd74 jk/proto-v2-ref-prefix-fix later to maint).
+
+ * Additional comment on a tricky piece of code to help developers.
+   (merge 0afbe3e806 jk/stream-pack-non-delta-clarification later to maint).
+
+ * A couple of tests used to leave the repository in a state that is
+   deliberately corrupt, which have been corrected.
+   (merge aa984dbe5e ab/pack-tests-cleanup later to maint).
+
+ * The submodule support has been updated to read from the blob at
+   HEAD:.gitmodules when the .gitmodules file is missing from the
+   working tree.
+   (merge 2b1257e463 ao/submodule-wo-gitmodules-checked-out later to maint).
+
+ * "git fetch" was a bit loose in parsing responses from the other side
+   when talking over the protocol v2.
+
+ * "git rev-parse --exclude=* --branches --branches"  (i.e. first
+   saying "add only things that do not match '*' out of all branches"
+   and then adding all branches, without any exclusion this time)
+   worked as expected, but "--exclude=* --all --all" did not work the
+   same way, which has been fixed.
+   (merge 5221048092 ag/rev-parse-all-exclude-fix later to maint).
+
+ * "git send-email --transfer-encoding=..." in recent versions of Git
+   sometimes produced an empty "Content-Transfer-Encoding:" header,
+   which has been corrected.
+   (merge 3c88e46f1a al/send-email-auto-cte-fixup later to maint).
+
+ * The interface into "xdiff" library used to discover the offset and
+   size of a generated patch hunk by first formatting it into the
+   textual hunk header "@@ -n,m +k,l @@" and then parsing the numbers
+   out.  A new interface has been introduced to allow callers a more
+   direct access to them.
+   (merge 5eade0746e jk/xdiff-interface later to maint).
+
+ * Pathspec matching against a tree object were buggy when negative
+   pathspec elements were involved, which has been fixed.
+   (merge b7845cebc0 nd/tree-walk-path-exclusion later to maint).
+
+ * "git merge" and "git pull" that merges into an unborn branch used
+   to completely ignore "--verify-signatures", which has been
+   corrected.
+   (merge 01a31f3bca jk/verify-sig-merge-into-void later to maint).
+
+ * "git rebase --autostash" did not correctly re-attach the HEAD at times.
+
+ * "rev-parse --exclude=<pattern> --branches=<pattern>" etc. did not
+   quite work, which has been corrected.
+   (merge 9ab9b5df0e ra/rev-parse-exclude-glob later to maint).
+
+ * When editing a patch in a "git add -i" session, a hunk could be
+   made to no-op.  The "git apply" program used to reject a patch with
+   such a no-op hunk to catch user mistakes, but it is now updated to
+   explicitly allow a no-op hunk in an edited patch.
+   (merge 22cb3835b9 js/apply-recount-allow-noop later to maint).
+
+ * The URL to an MSDN page in a comment has been updated.
+   (merge 2ef2ae2917 js/mingw-msdn-url later to maint).
+
+ * "git ls-remote --sort=<thing>" can feed an object that is not yet
+   available into the comparison machinery and segfault, which has
+   been corrected to check such a request upfront and reject it.
+
+ * When "git bundle" aborts due to an empty commit ranges
+   (i.e. resulting in an empty pack), it left a file descriptor to an
+   lockfile open, which resulted in leftover lockfile on Windows where
+   you cannot remove a file with an open file descriptor.  This has
+   been corrected.
+   (merge 2c8ee1f53c jk/close-duped-fd-before-unlock-for-bundle later to maint).
+
+ * "git format-patch --stat=<width>" can be used to specify the width
+   used by the diffstat (shown in the cover letter).
+   (merge 284aeb7e60 nd/format-patch-cover-letter-stat-width later to maint).
+
+ * The way .git/index and .git/sharedindex* files were initially
+   created gave these files different perm bits until they were
+   adjusted for shared repository settings.  This was made consistent.
+   (merge c9d6c78870 cc/shared-index-permbits later to maint).
+
+ * "git rebase --stat" to transplant a piece of history onto a totally
+   unrelated history were not working before and silently showed wrong
+   result.  With the recent reimplementation in C, it started to instead
+   die with an error message, as the original logic was not prepared
+   to cope with this case.  This has now been fixed.
+
+ * The advice message to tell the user to migrate an existing graft
+   file to the replace system when a graft file was read was shown
+   even when "git replace --convert-graft-file" command, which is the
+   way the message suggests to use, was running, which made little
+   sense.
+   (merge 8821e90a09 ab/replace-graft-with-replace-advice later to maint).
+
+ * "git diff --raw" lost ellipses to adjust the output columns for
+   some time now, but the documentation still showed them.
+
+ * Code cleanup, docfix, build fix, etc.
+   (merge 96a7501aad ts/doc-build-manpage-xsl-quietly later to maint).
+   (merge b9b07efdb2 tg/conflict-marker-size later to maint).
+   (merge fa0aeea770 sg/doc-trace-appends later to maint).
+   (merge d64324cb60 tb/void-check-attr later to maint).
+   (merge c3b9bc94b9 en/double-semicolon-fix later to maint).
+   (merge 79336116f5 sg/t3701-tighten-trace later to maint).
+   (merge 801fa63a90 jk/dev-build-format-security later to maint).
+   (merge 0597dd62ba sb/string-list-remove-unused later to maint).
+   (merge db2d36fad8 bw/protocol-v2 later to maint).
+   (merge 456d7cd3a9 sg/split-index-test later to maint).
+   (merge 7b6057c852 tq/refs-internal-comment-fix later to maint).
+   (merge 29e8dc50ad tg/t5551-with-curl-7.61.1 later to maint).
+   (merge 55f6bce2c9 fe/doc-updates later to maint).
+   (merge 7987d2232d jk/check-everything-connected-is-long-gone later to maint).
+   (merge 4ba3c9be47 dz/credential-doc-url-matching-rules later to maint).
+   (merge 4c399442f7 ma/commit-graph-docs later to maint).
+   (merge fc0503b04e ma/t1400-undebug-test later to maint).
+   (merge e56b53553a nd/packobjectshook-doc-fix later to maint).
+   (merge c56170a0c4 ma/mailing-list-address-in-git-help later to maint).
+   (merge 6e8fc70fce rs/sequencer-oidset-insert-avoids-dups later to maint).
+   (merge ad0b8f9575 mw/doc-typofixes later to maint).
+   (merge d9f079ad1a jc/how-to-document-api later to maint).
+   (merge b1492bf315 ma/t7005-bash-workaround later to maint).
+   (merge ac1f98a0df du/rev-parse-is-plumbing later to maint).
+   (merge ca8ed443a5 mm/doc-no-dashed-git later to maint).
+   (merge ce366a8144 du/get-tar-commit-id-is-plumbing later to maint).
+   (merge 61018fe9e0 du/cherry-is-plumbing later to maint).
+   (merge c7e5fe79b9 sb/strbuf-h-update later to maint).
+   (merge 8d2008196b tq/branch-create-wo-branch-get later to maint).
+   (merge 2e3c894f4b tq/branch-style-fix later to maint).
+   (merge c5d844af9c sg/doc-show-branch-typofix later to maint).
+   (merge 081d91618b ah/doc-updates later to maint).
+   (merge b84c783882 jc/cocci-preincr later to maint).
+   (merge 5e495f8122 uk/merge-subtree-doc-update later to maint).
+   (merge aaaa881822 jk/uploadpack-packobjectshook-fix later to maint).
+   (merge 3063477445 tb/char-may-be-unsigned later to maint).
+   (merge 8c64bc9420 sg/test-rebase-editor-fix later to maint).
+   (merge 71571cd7d6 ma/sequencer-do-reset-saner-loop-termination later to maint).
+   (merge 9a4cb8781e cb/notes-freeing-always-null-fix later to maint).
+   (merge 3006f5ee16 ma/reset-doc-rendering-fix later to maint).
+   (merge 4c2eb06419 sg/daemon-test-signal-fix later to maint).
+   (merge d27525e519 ss/msvc-strcasecmp later to maint).
diff --git a/Documentation/RelNotes/2.20.1.txt b/Documentation/RelNotes/2.20.1.txt
new file mode 100644
index 0000000000..dcba888dba
--- /dev/null
+++ b/Documentation/RelNotes/2.20.1.txt
@@ -0,0 +1,20 @@
+Git v2.20.1 Release Notes
+=========================
+
+This release is primarily to fix brown-paper-bag breakages in the
+2.20.0 release.
+
+Fixes since v2.20
+-----------------
+
+ * A few newly added tests were not portable and caused minority
+   platforms to report false breakages, which have been fixed.
+
+ * Portability fix for a recent update to parse-options API.
+
+ * "git help -a" did not work well when an overly long alias is
+   defined, which has been corrected.
+
+ * A recent update accidentally squelched an error message when the
+   run_command API failed to run a missing command, which has been
+   corrected.
diff --git a/Documentation/RelNotes/2.20.2.txt b/Documentation/RelNotes/2.20.2.txt
new file mode 100644
index 0000000000..8e680cb9fb
--- /dev/null
+++ b/Documentation/RelNotes/2.20.2.txt
@@ -0,0 +1,18 @@
+Git v2.20.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4
+and in v2.17.3, addressing the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, and CVE-2019-1387; see the release notes
+for those versions for details.
+
+The change to disallow `submodule.<name>.update=!command` entries in
+`.gitmodules` which was introduced v2.15.4 (and for which v2.17.3
+added explicit fsck checks) fixes the vulnerability in v2.20.x where a
+recursive clone followed by a submodule update could execute code
+contained within the repository without the user explicitly having
+asked for that (CVE-2019-19604).
+
+Credit for finding this vulnerability goes to Joern Schneeweisz,
+credit for the fixes goes to Jonathan Nieder.
diff --git a/Documentation/RelNotes/2.20.3.txt b/Documentation/RelNotes/2.20.3.txt
new file mode 100644
index 0000000000..f6eccd103b
--- /dev/null
+++ b/Documentation/RelNotes/2.20.3.txt
@@ -0,0 +1,5 @@
+Git v2.20.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.20.4.txt b/Documentation/RelNotes/2.20.4.txt
new file mode 100644
index 0000000000..5a9e24e470
--- /dev/null
+++ b/Documentation/RelNotes/2.20.4.txt
@@ -0,0 +1,5 @@
+Git v2.20.4 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.20.5.txt b/Documentation/RelNotes/2.20.5.txt
new file mode 100644
index 0000000000..1dfb784ded
--- /dev/null
+++ b/Documentation/RelNotes/2.20.5.txt
@@ -0,0 +1,6 @@
+Git v2.20.5 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5
+and v2.19.6 to address the security issue CVE-2021-21300; see
+the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.21.0.txt b/Documentation/RelNotes/2.21.0.txt
new file mode 100644
index 0000000000..7a49deddf3
--- /dev/null
+++ b/Documentation/RelNotes/2.21.0.txt
@@ -0,0 +1,451 @@
+Git 2.21 Release Notes
+======================
+
+Backward Compatibility Notes
+----------------------------
+
+ * Historically, the "-m" (mainline) option can only be used for "git
+   cherry-pick" and "git revert" when working with a merge commit.
+   This version of Git no longer warns or errors out when working with
+   a single-parent commit, as long as the argument to the "-m" option
+   is 1 (i.e. it has only one parent, and the request is to pick or
+   revert relative to that first parent).  Scripts that relied on the
+   behaviour may get broken with this change.
+
+
+Updates since v2.20
+-------------------
+
+UI, Workflows & Features
+
+ * The "http.version" configuration variable can be used with recent
+   enough versions of cURL library to force the version of HTTP used
+   to talk when fetching and pushing.
+
+ * Small fixes and features for fast-export and fast-import, mostly on
+   the fast-export side has been made.
+
+ * "git push $there $src:$dst" rejects when $dst is not a fully
+   qualified refname and it is not clear what the end user meant.  The
+   codepath has been taught to give a clearer error message, and also
+   guess where the push should go by taking the type of the pushed
+   object into account (e.g. a tag object would want to go under
+   refs/tags/).
+
+ * "git checkout [<tree-ish>] path..." learned to report the number of
+   paths that have been checked out of the index or the tree-ish,
+   which gives it the same degree of noisy-ness as the case in which
+   the command checks out a branch.  "git checkout -m <pathspec>" to
+   undo conflict resolution gives a similar message.
+
+ * "git quiltimport" learned "--keep-non-patch" option.
+
+ * "git worktree remove" and "git worktree move" refused to work when
+   there is a submodule involved.  This has been loosened to ignore
+   uninitialized submodules.
+
+ * "git cherry-pick -m1" was forbidden when picking a non-merge
+   commit, even though there _is_ parent number 1 for such a commit.
+   This was done to avoid mistakes back when "cherry-pick" was about
+   picking a single commit, but is no longer useful with "cherry-pick"
+   that can pick a range of commits.  Now the "-m$num" option is
+   allowed when picking any commit, as long as $num names an existing
+   parent of the commit.
+
+ * Update "git multimail" from the upstream.
+
+ * "git p4" update.
+
+ * The "--format=<placeholder>" option of for-each-ref, branch and tag
+   learned to show a few more traits of objects that can be learned by
+   the object_info API.
+
+ * "git rebase -i" learned to re-execute a command given with 'exec'
+   to run after it failed the last time.
+
+ * "git diff --color-moved-ws" updates.
+
+ * Custom userformat "log --format" learned %S atom that stands for
+   the tip the traversal reached the commit from, i.e. --source.
+
+ * "git instaweb" learned to drive http.server that comes with
+   "batteries included" Python installation (both Python2 & 3).
+
+ * A new encoding UTF-16LE-BOM has been invented to force encoding to
+   UTF-16 with BOM in little endian byte order, which cannot be directly
+   generated by using iconv.
+
+ * A new date format "--date=human" that morphs its output depending
+   on how far the time is from the current time has been introduced.
+   "--date=auto:human" can be used to use this new format (or any
+   existing format) when the output is going to the pager or to the
+   terminal, and otherwise the default format.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Code clean-up with optimization for the codepath that checks
+   (non-)existence of loose objects.
+
+ * More codepaths have become aware of working with in-core repository
+   instances other than the default "the_repository".
+
+ * The "strncat()" function is now among the banned functions.
+
+ * Portability updates for the HPE NonStop platform.
+
+ * Earlier we added "-Wformat-security" to developer builds, assuming
+   that "-Wall" (which includes "-Wformat" which in turn is required
+   to use "-Wformat-security") is always in effect.  This is not true
+   when config.mak.autogen is in use, unfortunately.  This has been
+   fixed by unconditionally adding "-Wall" to developer builds.
+
+ * The loose object cache used to optimize existence look-up has been
+   updated.
+
+ * Flaky tests can now be repeatedly run under load with the
+   "--stress" option.
+
+ * Documentation/Makefile is getting prepared for manpage
+   localization.
+
+ * "git fetch-pack" now can talk the version 2 protocol.
+
+ * sha-256 hash has been added and plumbed through the code to allow
+   building Git with the "NewHash".
+
+ * Debugging help for http transport.
+
+ * "git fetch --deepen=<more>" has been corrected to work over v2
+   protocol.
+
+ * The code to walk tree objects has been taught that we may be
+   working with object names that are not computed with SHA-1.
+
+ * The in-core repository instances are passed through more codepaths.
+
+ * Update the protocol message specification to allow only the limited
+   use of scaled quantities.  This is to ensure potential compatibility
+   issues will not get out of hand.
+
+ * Micro-optimize the code that prepares commit objects to be walked
+   by "git rev-list" when the commit-graph is available.
+
+ * "git fetch" and "git upload-pack" learned to send all exchanges over
+   the sideband channel while talking the v2 protocol.
+
+ * The codepath to write out commit-graph has been optimized by
+   following the usual pattern of visiting objects in in-pack order.
+
+ * The codepath to show progress meter while writing out commit-graph
+   file has been improved.
+
+ * Cocci rules have been updated to encourage use of strbuf_addbuf().
+
+ * "git rebase --merge" has been reimplemented by reusing the internal
+   machinery used for "git rebase -i".
+
+ * More code in "git bisect" has been rewritten in C.
+
+ * Instead of going through "git-rebase--am" scriptlet to use the "am"
+   backend, the built-in version of "git rebase" learned to drive the
+   "am" backend directly.
+
+ * The assumption to work on the single "in-core index" instance has
+   been reduced from the library-ish part of the codebase.
+
+ * The test lint learned to catch non-portable "sed" options.
+
+ * "git pack-objects" learned another algorithm to compute the set of
+   objects to send, that trades the resulting packfile off to save
+   traversal cost to favor small pushes.
+
+ * The travis CI scripts have been corrected to build Git with the
+   compiler(s) of our choice.
+
+ * "git submodule update" learned to abort early when core.worktree
+   for the submodule is not set correctly to prevent spreading damage.
+
+ * Test suite has been adjusted to run on Azure Pipeline.
+
+ * Running "Documentation/doc-diff x" from anywhere other than the
+   top-level of the working tree did not show the usage string
+   correctly, which has been fixed.
+
+ * Use of the sparse tool got easier to customize from the command
+   line to help developers.
+
+ * A new target "coverage-prove" to run the coverage test under
+   "prove" has been added.
+
+ * A flakey "p4" test has been removed.
+
+ * The code and tests assume that the system supplied iconv() would
+   always use BOM in its output when asked to encode to UTF-16 (or
+   UTF-32), but apparently some implementations output big-endian
+   without BOM.  A compile-time knob has been added to help such
+   systems (e.g. NonStop) to add BOM to the output to increase
+   portability.
+
+
+Fixes since v2.20
+-----------------
+
+ * Updates for corner cases in merge-recursive.
+   (merge cc4cb0902c en/merge-path-collision later to maint).
+
+ * "git checkout frotz" (without any double-dash) avoids ambiguity by
+   making sure 'frotz' cannot be interpreted as a revision and as a
+   path at the same time.  This safety has been updated to check also
+   a unique remote-tracking branch 'frotz' in a remote, when dwimming
+   to create a local branch 'frotz' out of a remote-tracking branch
+   'frotz' from a remote.
+   (merge be4908f103 nd/checkout-dwim-fix later to maint).
+
+ * Refspecs configured with "git -c var=val clone" did not propagate
+   to the resulting repository, which has been corrected.
+   (merge 7eae4a3ac4 sg/clone-initial-fetch-configuration later to maint).
+
+ * A properly configured username/email is required under
+   user.useConfigOnly in order to create commits; now "git stash"
+   (even though it creates commit objects to represent stash entries)
+   command is exempt from the requirement.
+   (merge 3bc2111fc2 sd/stash-wo-user-name later to maint).
+
+ * The http-backend CGI process did not correctly clean up the child
+   processes it spawns to run upload-pack etc. when it dies itself,
+   which has been corrected.
+   (merge 02818a98d7 mk/http-backend-kill-children-before-exit later to maint).
+
+ * "git rev-list --exclude-promisor-objects" had to take an object
+   that does not exist locally (and is lazily available) from the
+   command line without barfing, but the code dereferenced NULL.
+   (merge 4cf67869b2 md/list-lazy-objects-fix later to maint).
+
+ * The traversal over tree objects has learned to honor
+   ":(attr:label)" pathspec match, which has been implemented only for
+   enumerating paths on the filesystem.
+   (merge 5a0b97b34c nd/attr-pathspec-in-tree-walk later to maint).
+
+ * BSD port updates.
+   (merge 4e3ecbd439 cb/openbsd-allows-reading-directory later to maint).
+   (merge b6bdc2a0f5 cb/t5004-empty-tar-archive-fix later to maint).
+   (merge 82cbc8cde2 cb/test-lint-cp-a later to maint).
+
+ * Lines that begin with a certain keyword that come over the wire, as
+   well as lines that consist only of one of these keywords, ought to
+   be painted in color for easier eyeballing, but the latter was
+   broken ever since the feature was introduced in 2.19, which has
+   been corrected.
+   (merge 1f67290450 hn/highlight-sideband-keywords later to maint).
+
+ * "git log -G<regex>" looked for a hunk in the "git log -p" patch
+   output that contained a string that matches the given pattern.
+   Optimize this code to ignore binary files, which by default will
+   not show any hunk that would match any pattern (unless textconv or
+   the --text option is in effect, that is).
+   (merge e0e7cb8080 tb/log-G-binary later to maint).
+
+ * "git submodule update" ought to use a single job unless asked, but
+   by mistake used multiple jobs, which has been fixed.
+   (merge e3a9d1aca9 sb/submodule-fetchjobs-default-to-one later to maint).
+
+ * "git stripspace" should be usable outside a git repository, but
+   under the "-s" or "-c" mode, it didn't.
+   (merge 957da75802 jn/stripspace-wo-repository later to maint).
+
+ * Some of the documentation pages formatted incorrectly with
+   Asciidoctor, which have been fixed.
+   (merge b62eb1d2f4 ma/asciidoctor later to maint).
+
+ * The core.worktree setting in a submodule repository should not be
+   pointing at a directory when the submodule loses its working tree
+   (e.g. getting deinit'ed), but the code did not properly maintain
+   this invariant.
+
+ * With zsh, "git cmd path<TAB>" was completed to "git cmd path name"
+   when the completed path has a special character like SP in it,
+   without any attempt to keep "path name" a single filename.  This
+   has been fixed to complete it to "git cmd path\ name" just like
+   Bash completion does.
+
+ * The test suite tried to see if it is run under bash, but the check
+   itself failed under some other implementations of shell (notably
+   under NetBSD).  This has been corrected.
+   (merge 54ea72f09c sg/test-bash-version-fix later to maint).
+
+ * "git gc" and "git repack" did not close the open packfiles that
+   they found unneeded before removing them, which didn't work on a
+   platform incapable of removing an open file.  This has been
+   corrected.
+   (merge 5bdece0d70 js/gc-repack-close-before-remove later to maint).
+
+ * The code to drive GIT_EXTERNAL_DIFF command relied on the string
+   returned from getenv() to be non-volatile, which is not true, that
+   has been corrected.
+   (merge 6776a84dae kg/external-diff-save-env later to maint).
+
+ * There were many places the code relied on the string returned from
+   getenv() to be non-volatile, which is not true, that have been
+   corrected.
+   (merge 0da0e9268b jk/save-getenv-result later to maint).
+
+ * The v2 upload-pack protocol implementation failed to honor
+   hidden-ref configuration, which has been corrected.
+   (merge e20b4192a3 jk/proto-v2-hidden-refs-fix later to maint).
+
+ * "git fetch --recurse-submodules" may not fetch the necessary commit
+   that is bound to the superproject, which is getting corrected.
+   (merge be76c21282 sb/submodule-recursive-fetch-gets-the-tip later to maint).
+
+ * "git rebase" internally runs "checkout" to switch between branches,
+   and the command used to call the post-checkout hook, but the
+   reimplementation stopped doing so, which is getting fixed.
+
+ * "git add -e" got confused when the change it wants to let the user
+   edit is smaller than the previous change that was left over in a
+   temporary file.
+   (merge fa6f225e01 js/add-e-clear-patch-before-stating later to maint).
+
+ * "git p4" failed to update a shelved change when there were moved
+   files, which has been corrected.
+   (merge 7a10946ab9 ld/git-p4-shelve-update-fix later to maint).
+
+ * The codepath to read from the commit-graph file attempted to read
+   past the end of it when the file's table-of-contents was corrupt.
+
+ * The compat/obstack code had casts that -Wcast-function-type
+   compilation option found questionable.
+   (merge 764473d257 sg/obstack-cast-function-type-fix later to maint).
+
+ * An obvious typo in an assertion error message has been fixed.
+   (merge 3c27e2e059 cc/test-ref-store-typofix later to maint).
+
+ * In Git for Windows, "git clone \\server\share\path" etc. that uses
+   UNC paths from command line had bad interaction with its shell
+   emulation.
+
+ * "git add --ignore-errors" did not work as advertised and instead
+   worked as an unintended synonym for "git add --renormalize", which
+   has been fixed.
+   (merge e2c2a37545 jk/add-ignore-errors-bit-assignment-fix later to maint).
+
+ * On a case-insensitive filesystem, we failed to compare the part of
+   the path that is above the worktree directory in an absolute
+   pathname, which has been corrected.
+
+ * Asking "git check-attr" about a macro (e.g. "binary") on a specific
+   path did not work correctly, even though "git check-attr -a" listed
+   such a macro correctly.  This has been corrected.
+   (merge 7b95849be4 jk/attr-macro-fix later to maint).
+
+ * "git pack-objects" incorrectly used uninitialized mutex, which has
+   been corrected.
+   (merge edb673cf10 ph/pack-objects-mutex-fix later to maint).
+
+ * "git checkout -b <new> [HEAD]" to create a new branch from the
+   current commit and check it out ought to be a no-op in the index
+   and the working tree in normal cases, but there are corner cases
+   that do require updates to the index and the working tree.  Running
+   it immediately after "git clone --no-checkout" is one of these
+   cases that an earlier optimization kicked in incorrectly, which has
+   been fixed.
+   (merge 8424bfd45b bp/checkout-new-branch-optim later to maint).
+
+ * "git diff --color-moved --cc --stat -p" did not work well due to
+   funny interaction between a bug in color-moved and the rest, which
+   has been fixed.
+   (merge dac03b5518 jk/diff-cc-stat-fixes later to maint).
+
+ * When GIT_SEQUENCE_EDITOR is set, the command was incorrectly
+   started when modes of "git rebase" that implicitly uses the
+   machinery for the interactive rebase are run, which has been
+   corrected.
+   (merge 891d4a0313 pw/no-editor-in-rebase-i-implicit later to maint).
+
+ * The commit-graph facility did not work when in-core objects that
+   are promoted from unknown type to commit (e.g. a commit that is
+   accessed via a tag that refers to it) were involved, which has been
+   corrected.
+   (merge 4468d4435c sg/object-as-type-commit-graph-fix later to maint).
+
+ * "git fetch" output cleanup.
+   (merge dc40b24df4 nd/fetch-compact-update later to maint).
+
+ * "git cat-file --batch" reported a dangling symbolic link by
+   mistake, when it wanted to report that a given name is ambiguous.
+
+ * Documentation around core.crlf has been updated.
+   (merge c9446f0504 jk/autocrlf-overrides-eol-doc later to maint).
+
+ * The documentation of "git commit-tree" said that the command
+   understands "--gpg-sign" in addition to "-S", but the command line
+   parser did not know about the longhand, which has been corrected.
+
+ * "git rebase -x $cmd" did not reject multi-line command, even though
+   the command is incapable of handling such a command.  It now is
+   rejected upfront.
+   (merge c762aada1a pw/rebase-x-sanity-check later to maint).
+
+ * Output from "git help" was not correctly aligned, which has been
+   fixed.
+   (merge 6195a76da4 nd/help-align-command-desc later to maint).
+
+ * The "git submodule summary" subcommand showed shortened commit
+   object names by mechanically truncating them at 7-hexdigit, which
+   has been improved to let "rev-parse --short" scale the length of
+   the abbreviation with the size of the repository.
+   (merge 0586a438f6 sh/submodule-summary-abbrev-fix later to maint).
+
+ * The way the OSX build jobs updates its build environment used the
+   "--quiet" option to "brew update" command, but it wasn't all that
+   quiet to be useful.  The use of the option has been replaced with
+   an explicit redirection to the /dev/null (which incidentally would
+   have worked around a breakage by recent updates to homebrew, which
+   has fixed itself already).
+   (merge a1ccaedd62 sg/travis-osx-brew-breakage-workaround later to maint).
+
+ * "git --work-tree=$there --git-dir=$here describe --dirty" did not
+   work correctly as it did not pay attention to the location of the
+   worktree specified by the user by mistake, which has been
+   corrected.
+   (merge c801170b0c ss/describe-dirty-in-the-right-directory later to maint).
+
+ * "git fetch" over protocol v2 that needs to make a second connection
+   to backfill tags did not clear a variable that holds shallow
+   repository information correctly, leading to an access of freed
+   piece of memory.
+
+ * Some errors from the other side coming over smart HTTP transport
+   were not noticed, which has been corrected.
+
+ * Code cleanup, docfix, build fix, etc.
+   (merge 89ba9a79ae hb/t0061-dot-in-path-fix later to maint).
+   (merge d173e799ea sb/diff-color-moved-config-option-fixup later to maint).
+   (merge a8f5a59067 en/directory-renames-nothanks-doc-update later to maint).
+   (merge ec36c42a63 nd/indentation-fix later to maint).
+   (merge f116ee21cd do/gitweb-strict-export-conf-doc later to maint).
+   (merge 112ea42663 fd/gitweb-snapshot-conf-doc-fix later to maint).
+   (merge 1cadad6f65 tb/use-common-win32-pathfuncs-on-cygwin later to maint).
+   (merge 57e9dcaa65 km/rebase-doc-typofix later to maint).
+   (merge b8b4cb27e6 ds/gc-doc-typofix later to maint).
+   (merge 3b3357626e nd/style-opening-brace later to maint).
+   (merge b4583d5595 es/doc-worktree-guessremote-config later to maint).
+   (merge cce99cd8c6 ds/commit-graph-assert-missing-parents later to maint).
+   (merge 0650614982 cy/completion-typofix later to maint).
+   (merge 6881925ef5 rs/sha1-file-close-mapped-file-on-error later to maint).
+   (merge bd8d6f0def en/show-ref-doc-fix later to maint).
+   (merge 1747125e2c cc/partial-clone-doc-typofix later to maint).
+   (merge e01378753d cc/fetch-error-message-fix later to maint).
+   (merge 54e8c11215 jk/remote-insteadof-cleanup later to maint).
+   (merge d609615f48 js/test-git-installed later to maint).
+   (merge ba170517be ja/doc-style-fix later to maint).
+   (merge 86fb1c4e77 km/init-doc-typofix later to maint).
+   (merge 5cfd4a9d10 nd/commit-doc later to maint).
+   (merge 9fce19a431 ab/diff-tree-doc-fix later to maint).
+   (merge 2e285e7803 tz/gpg-test-fix later to maint).
+   (merge 5427de960b kl/pretty-doc-markup-fix later to maint).
+   (merge 3815f64b0d js/mingw-host-cpu later to maint).
+   (merge 5fe81438b5 rj/sequencer-sign-off-header-static later to maint).
+   (merge 18a4f6be6b nd/fileno-may-be-macro later to maint).
+   (merge 99e9ab54ab kd/t0028-octal-del-is-377-not-777 later to maint).
diff --git a/Documentation/RelNotes/2.21.1.txt b/Documentation/RelNotes/2.21.1.txt
new file mode 100644
index 0000000000..b7594151e4
--- /dev/null
+++ b/Documentation/RelNotes/2.21.1.txt
@@ -0,0 +1,12 @@
+Git v2.21.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4,
+v2.17.3 and in v2.20.2, addressing the security issues CVE-2019-1348,
+CVE-2019-1349, CVE-2019-1350, CVE-2019-1351, CVE-2019-1352,
+CVE-2019-1353, CVE-2019-1354, CVE-2019-1387, and CVE-2019-19604;
+see the release notes for those versions for details.
+
+Additionally, this version also includes a couple of fixes for the
+Windows-specific quoting of command-line arguments when Git executes
+a Unix shell on Windows.
diff --git a/Documentation/RelNotes/2.21.2.txt b/Documentation/RelNotes/2.21.2.txt
new file mode 100644
index 0000000000..a0fb83bb53
--- /dev/null
+++ b/Documentation/RelNotes/2.21.2.txt
@@ -0,0 +1,5 @@
+Git v2.21.2 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.21.3.txt b/Documentation/RelNotes/2.21.3.txt
new file mode 100644
index 0000000000..2ca0aa5c62
--- /dev/null
+++ b/Documentation/RelNotes/2.21.3.txt
@@ -0,0 +1,5 @@
+Git v2.21.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.21.4.txt b/Documentation/RelNotes/2.21.4.txt
new file mode 100644
index 0000000000..0089dd6702
--- /dev/null
+++ b/Documentation/RelNotes/2.21.4.txt
@@ -0,0 +1,6 @@
+Git v2.21.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5,
+v2.19.6 and v2.20.5 to address the security issue CVE-2021-21300;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.22.0.txt b/Documentation/RelNotes/2.22.0.txt
new file mode 100644
index 0000000000..91e6ae9887
--- /dev/null
+++ b/Documentation/RelNotes/2.22.0.txt
@@ -0,0 +1,597 @@
+Git 2.22 Release Notes
+======================
+
+Updates since v2.21
+-------------------
+
+Backward compatibility note
+
+ * The filter specification "--filter=sparse:path=<path>" used to
+   create a lazy/partial clone has been removed.  Using a blob that is
+   part of the project as sparse specification is still supported with
+   the "--filter=sparse:oid=<blob>" option.
+
+UI, Workflows & Features
+
+ * "git checkout --no-overlay" can be used to trigger a new mode of
+   checking out paths out of the tree-ish, that allows paths that
+   match the pathspec that are in the current index and working tree
+   and are not in the tree-ish.
+
+ * The %(trailers) formatter in "git log --format=..."  now allows to
+   optionally pick trailers selectively by keyword, show only values,
+   etc.
+
+ * Four new configuration variables {author,committer}.{name,email}
+   have been introduced to override user.{name,email} in more specific
+   cases.
+
+ * Command-line completion (in contrib/) learned to tab-complete the
+   "git submodule absorbgitdirs" subcommand.
+
+ * "git branch" learned a new subcommand "--show-current".
+
+ * Output from "diff --cc" did not show the original paths when the
+   merge involved renames.  A new option adds the paths in the
+   original trees to the output.
+
+ * The command line completion (in contrib/) has been taught to
+   complete more subcommand parameters.
+
+ * The final report from "git bisect" used to show the suspected
+   culprit using a raw "diff-tree", with which there is no output for
+   a merge commit.  This has been updated to use a more modern and
+   human readable output that still is concise enough.
+
+ * "git rebase --rebase-merges" replaces its old "--preserve-merges"
+   option; the latter is now marked as deprecated.
+
+ * Error message given while cloning with --recurse-submodules has
+   been updated.
+
+ * The completion helper code now pays attention to repository-local
+   configuration (when available), which allows --list-cmds to honour
+   a repository specific setting of completion.commands, for example.
+
+ * "git mergetool" learned to offer Sublime Merge (smerge) as one of
+   its backends.
+
+ * A new hook "post-index-change" is called when the on-disk index
+   file changes, which can help e.g. a virtualized working tree
+   implementation.
+
+ * "git difftool" can now run outside a repository.
+
+ * "git checkout -m <other>" was about carrying the differences
+   between HEAD and the working-tree files forward while checking out
+   another branch, and ignored the differences between HEAD and the
+   index.  The command has been taught to abort when the index and the
+   HEAD are different.
+
+ * A progress indicator has been added to the "index-pack" step, which
+   often makes users wait for completion during "git clone".
+
+ * "git submodule" learns "set-branch" subcommand that allows the
+   submodule.*.branch settings to be modified.
+
+ * "git merge-recursive" backend recently learned a new heuristics to
+   infer file movement based on how other files in the same directory
+   moved.  As this is inherently less robust heuristics than the one
+   based on the content similarity of the file itself (rather than
+   based on what its neighbours are doing), it sometimes gives an
+   outcome unexpected by the end users.  This has been toned down to
+   leave the renamed paths in higher/conflicted stages in the index so
+   that the user can examine and confirm the result.
+
+ * "git tag" learned to give an advice suggesting it might be a
+   mistake when creating an annotated or signed tag that points at
+   another tag.
+
+ * The "git pack-objects" command learned to report the number of
+   objects it packed via the trace2 mechanism.
+
+ * The list of conflicted paths shown in the editor while concluding a
+   conflicted merge was shown above the scissors line when the
+   clean-up mode is set to "scissors", even though it was commented
+   out just like the list of updated paths and other information to
+   help the user explain the merge better.
+
+ * The trace2 tracing facility learned to auto-generate a filename
+   when told to log to a directory.
+
+ * "git clone" learned a new --server-option option when talking over
+   the protocol version 2.
+
+ * The connectivity bitmaps are created by default in bare
+   repositories now; also the pathname hash-cache is created by
+   default to avoid making crappy deltas when repacking.
+
+ * "git branch new A...B" and "git checkout -b new A...B" have been
+   taught that in their contexts, the notation A...B means "the merge
+   base between these two commits", just like "git checkout A...B"
+   detaches HEAD at that commit.
+
+ * Update "git difftool" and "git mergetool" so that the combinations
+   of {diff,merge}.{tool,guitool} configuration variables serve as
+   fallback settings of each other in a sensible order.
+
+ * The "--dir-diff" mode of "git difftool" is not useful in "--no-index"
+   mode; they are now explicitly marked as mutually incompatible.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The diff machinery, one of the oldest parts of the system, which
+   long predates the parse-options API, uses fairly long and complex
+   handcrafted option parser.  This is being rewritten to use the
+   parse-options API.
+
+ * The implementation of pack-redundant has been updated for
+   performance in a repository with many packfiles.
+
+ * A more structured way to obtain execution trace has been added.
+
+ * "git prune" has been taught to take advantage of reachability
+   bitmap when able.
+
+ * The command line parser of "git commit-tree" has been rewritten to
+   use the parse-options API.
+
+ * Suggest GitGitGadget instead of submitGit as a way to submit
+   patches based on GitHub PR to us.
+
+ * The test framework has been updated to help developers by making it
+   easier to run most of the tests under different versions of
+   over-the-wire protocols.
+
+ * Dev support update to make it easier to compare two formatted
+   results from our documentation.
+
+ * The scripted "git rebase" implementation has been retired.
+
+ * "git multi-pack-index verify" did not scale well with the number of
+   packfiles, which is being improved.
+
+ * "git stash" has been rewritten in C.
+
+ * The "check-docs" Makefile target to support developers has been
+   updated.
+
+ * The tests have been updated not to rely on the abbreviated option
+   names the parse-options API offers, to protect us from an
+   abbreviated form of an option that used to be unique within the
+   command getting non-unique when a new option that share the same
+   prefix is added.
+
+ * The scripted version of "git rebase -i" wrote and rewrote the todo
+   list many times during a single step of its operation, and the
+   recent C-rewrite made a faithful conversion of the logic to C.  The
+   implementation has been updated to carry necessary information
+   around in-core to avoid rewriting the same file over and over
+   unnecessarily.
+
+ * Test framework update to more robustly clean up leftover files and
+   processes after tests are done.
+
+ * Conversion from unsigned char[20] to struct object_id continues.
+
+ * While running "git diff" in a lazy clone, we can upfront know which
+   missing blobs we will need, instead of waiting for the on-demand
+   machinery to discover them one by one.  The code learned to aim to
+   achieve better performance by batching the request for these
+   promised blobs.
+
+ * During an initial "git clone --depth=..." partial clone, it is
+   pointless to spend cycles for a large portion of the connectivity
+   check that enumerates and skips promisor objects (which by
+   definition is all objects fetched from the other side).  This has
+   been optimized out.
+
+ * Mechanically and systematically drop "extern" from function
+   declaration.
+
+ * The script to aggregate perf result unconditionally depended on
+   libjson-perl even though it did not have to, which has been
+   corrected.
+
+ * The internal implementation of "git rebase -i" has been updated to
+   avoid forking a separate "rebase--interactive" process.
+
+ * Allow DEP and ASLR for Windows build to for security hardening.
+
+ * Performance test framework has been broken and measured the version
+   of Git that happens to be on $PATH, not the specified one to
+   measure, for a while, which has been corrected.
+
+ * Optionally "make coccicheck" can feed multiple source files to
+   spatch, gaining performance while spending more memory.
+
+ * Attempt to use an abbreviated option in "git clone --recurs" is
+   responded by a request to disambiguate between --recursive and
+   --recurse-submodules, which is bad because these two are synonyms.
+   The parse-options API has been extended to define such synonyms
+   more easily and not produce an unnecessary failure.
+
+ * A pair of private functions in http.c that had names similar to
+   fread/fwrite did not return the number of elements, which was found
+   to be confusing.
+
+ * Update collision-detecting SHA-1 code to build properly on HP-UX.
+
+
+Fixes since v2.21
+-----------------
+
+ * "git prune-packed" did not notice and complain against excess
+   arguments given from the command line, which now it does.
+   (merge 9b0bd87ed2 rj/prune-packed-excess-args later to maint).
+
+ * Split-index fix.
+   (merge 6e37c8ed3c nd/split-index-null-base-fix later to maint).
+
+ * "git diff --no-index" may still want to access Git goodies like
+   --ext-diff and --textconv, but so far these have been ignored,
+   which has been corrected.
+   (merge 287ab28bfa jk/diff-no-index-initialize later to maint).
+
+ * Unify RPC code for smart http in protocol v0/v1 and v2, which fixes
+   a bug in the latter (lack of authentication retry) and generally
+   improves the code base.
+   (merge a97d00799a jt/http-auth-proto-v2-fix later to maint).
+
+ * The include file compat/bswap.h has been updated so that it is safe
+   to (accidentally) include it more than once.
+   (merge 33aa579a55 jk/guard-bswap-header later to maint).
+
+ * The set of header files used by "make hdr-check" unconditionally
+   included sha256/gcrypt.h, even when it is not used, causing the
+   make target to fail.  We now skip it when GCRYPT_SHA256 is not in
+   use.
+   (merge f23aa18e7f rj/hdr-check-gcrypt-fix later to maint).
+
+ * The Makefile uses 'find' utility to enumerate all the *.h header
+   files, which is expensive on platforms with slow filesystems; it
+   now optionally uses "ls-files" if working within a repository,
+   which is a trick similar to how all sources are enumerated to run
+   ETAGS on.
+   (merge 92b88eba9f js/find-lib-h-with-ls-files-when-possible later to maint).
+
+ * "git rebase" that was reimplemented in C did not set ORIG_HEAD
+   correctly, which has been corrected.
+   (merge cbd29ead92 js/rebase-orig-head-fix later to maint).
+
+ * Dev support.
+   (merge f545737144 js/stress-test-ui-tweak later to maint).
+
+ * CFLAGS now can be tweaked when invoking Make while using
+   DEVELOPER=YesPlease; this did not work well before.
+   (merge 6d5d4b4e93 ab/makefile-help-devs-more later to maint).
+
+ * "git fsck --connectivity-only" omits computation necessary to sift
+   the objects that are not reachable from any of the refs into
+   unreachable and dangling.  This is now enabled when dangling
+   objects are requested (which is done by default, but can be
+   overridden with the "--no-dangling" option).
+   (merge 8d8c2a5aef jk/fsck-doc later to maint).
+
+ * On platforms where "git fetch" is killed with SIGPIPE (e.g. OSX),
+   the upload-pack that runs on the other end that hangs up after
+   detecting an error could cause "git fetch" to die with a signal,
+   which led to a flaky test.  "git fetch" now ignores SIGPIPE during
+   the network portion of its operation (this is not a problem as we
+   check the return status from our write(2)s).
+   (merge 143588949c jk/no-sigpipe-during-network-transport later to maint).
+
+ * A recent update broke "is this object available to us?" check for
+   well-known objects like an empty tree (which should yield "yes",
+   even when there is no on-disk object for an empty tree), which has
+   been corrected.
+   (merge f06ab027ef jk/virtual-objects-do-exist later to maint).
+
+ * The setup code has been cleaned up to avoid leaks around the
+   repository_format structure.
+   (merge e8805af1c3 ma/clear-repository-format later to maint).
+
+ * "git config --type=color ..." is meant to replace "git config --get-color"
+   but there is a slight difference that wasn't documented, which is
+   now fixed.
+   (merge cd8e7593b9 jk/config-type-color-ends-with-lf later to maint).
+
+ * When the "clean" filter can reduce the size of a huge file in the
+   working tree down to a small "token" (a la Git LFS), there is no
+   point in allocating a huge scratch area upfront, but the buffer is
+   sized based on the original file size.  The convert mechanism now
+   allocates very minimum and reallocates as it receives the output
+   from the clean filter process.
+   (merge 02156ab031 jh/resize-convert-scratch-buffer later to maint).
+
+ * "git rebase" uses the refs/rewritten/ hierarchy to store its
+   intermediate states, which inherently makes the hierarchy per
+   worktree, but it didn't quite work well.
+   (merge b9317d55a3 nd/rewritten-ref-is-per-worktree later to maint).
+
+ * "git log -L<from>,<to>:<path>" with "-s" did not suppress the patch
+   output as it should.  This has been corrected.
+   (merge 05314efaea jk/line-log-with-patch later to maint).
+
+ * "git worktree add" used to do a "find an available name with stat
+   and then mkdir", which is race-prone.  This has been fixed by using
+   mkdir and reacting to EEXIST in a loop.
+   (merge 7af01f2367 ms/worktree-add-atomic-mkdir later to maint).
+
+ * Build update for SHA-1 with collision detection.
+   (merge 07a20f569b jk/sha1dc later to maint).
+
+ * Build procedure has been fixed around use of asciidoctor instead of
+   asciidoc.
+   (merge 185f9a0ea0 ma/asciidoctor-fixes later to maint).
+
+ * remote-http transport did not anonymize URLs reported in its error
+   messages at places.
+   (merge c1284b21f2 js/anonymize-remote-curl-diag later to maint).
+
+ * Error messages given from the http transport have been updated so
+   that they can be localized.
+   (merge ed8b4132c8 js/remote-curl-i18n later to maint).
+
+ * "git init" forgot to read platform-specific repository
+   configuration, which made Windows port to ignore settings of
+   core.hidedotfiles, for example.
+
+ * A corner-case object name ambiguity while the sequencer machinery
+   is working (e.g. "rebase -i -x") has been fixed.
+
+ * "git format-patch" did not diagnose an error while opening the
+   output file for the cover-letter, which has been corrected.
+   (merge 2fe95f494c jc/format-patch-error-check later to maint).
+
+ * "git checkout -f <branch>" while the index has an unmerged path
+   incorrectly left some paths in an unmerged state, which has been
+   corrected.
+
+ * A corner case bug in the refs API has been corrected.
+   (merge d3322eb28b jk/refs-double-abort later to maint).
+
+ * Unicode update.
+   (merge 584b62c37b bb/unicode-12 later to maint).
+
+ * dumb-http walker has been updated to share more error recovery
+   strategy with the normal codepath.
+
+ * A buglet in configuration parser has been fixed.
+   (merge 19e7fdaa58 nd/include-if-wildmatch later to maint).
+
+ * The documentation for "git read-tree --reset -u" has been updated.
+   (merge b5a0bd694c nd/read-tree-reset-doc later to maint).
+
+ * Code clean-up around a much-less-important-than-it-used-to-be
+   update_server_info() function.
+   (merge b3223761c8 jk/server-info-rabbit-hole later to maint).
+
+ * The message given when "git commit -a <paths>" errors out has been
+   updated.
+   (merge 5a1dbd48bc nd/commit-a-with-paths-msg-update later to maint).
+
+ * "git cherry-pick --options A..B", after giving control back to the
+   user to ask help resolving a conflicted step, did not honor the
+   options it originally received, which has been corrected.
+
+ * Various glitches in "git gc" around reflog handling have been fixed.
+
+ * The code to read from commit-graph file has been cleanup with more
+   careful error checking before using data read from it.
+
+ * Performance fix around "git fetch" that grabs many refs.
+   (merge b764300912 jt/fetch-pack-wanted-refs-optim later to maint).
+
+ * Protocol v2 support in "git fetch-pack" of shallow clones has been
+   corrected.
+
+ * Performance fix around "git blame", especially in a linear history
+   (which is the norm we should optimize for).
+   (merge f892014943 dk/blame-keep-origin-blob later to maint).
+
+ * Performance fix for "rev-list --parents -- pathspec".
+   (merge 8320b1dbe7 jk/revision-rewritten-parents-in-prio-queue later to maint).
+
+ * Updating the display with progress message has been cleaned up to
+   deal better with overlong messages.
+   (merge 545dc345eb sg/overlong-progress-fix later to maint).
+
+ * "git blame -- path" in a non-bare repository starts blaming from
+   the working tree, and the same command in a bare repository errors
+   out because there is no working tree by definition.  The command
+   has been taught to instead start blaming from the commit at HEAD,
+   which is more useful.
+   (merge a544fb08f8 sg/blame-in-bare-start-at-head later to maint).
+
+ * An underallocation in the code to read the untracked cache
+   extension has been corrected.
+   (merge 3a7b45a623 js/untracked-cache-allocfix later to maint).
+
+ * The code is updated to check the result of memory allocation before
+   it is used in more places, by using xmalloc and/or xcalloc calls.
+   (merge 999b951b28 jk/xmalloc later to maint).
+
+ * The GETTEXT_POISON test option has been quite broken ever since it
+   was made runtime-tunable, which has been fixed.
+   (merge f88b9cb603 jc/gettext-test-fix later to maint).
+
+ * Test fix on APFS that is incapable of store paths in Latin-1.
+   (merge 3889149619 js/iso8895-test-on-apfs later to maint).
+
+ * "git submodule foreach <command> --quiet" did not pass the option
+   down correctly, which has been corrected.
+   (merge a282f5a906 nd/submodule-foreach-quiet later to maint).
+
+ * "git send-email" has been taught to use quoted-printable when the
+   payload contains carriage-return.  The use of the mechanism is in
+   line with the design originally added the codepath that chooses QP
+   when the payload has overly long lines.
+   (merge 74d76a1701 bc/send-email-qp-cr later to maint).
+
+ * The recently added feature to add addresses that are on
+   anything-by: trailers in 'git send-email' was found to be way too
+   eager and considered nonsense strings as if they can be legitimate
+   beginning of *-by: trailer.  This has been tightened.
+
+ * Builds with gettext broke on recent macOS w/ Homebrew, which
+   seems to have stopped including from /usr/local/include; this
+   has been corrected.
+   (merge 92a1377a2a js/macos-gettext-build later to maint).
+
+ * Running "git add" on a repository created inside the current
+   repository is an explicit indication that the user wants to add it
+   as a submodule, but when the HEAD of the inner repository is on an
+   unborn branch, it cannot be added as a submodule.  Worse, the files
+   in its working tree can be added as if they are a part of the outer
+   repository, which is not what the user wants.  These problems are
+   being addressed.
+   (merge f937bc2f86 km/empty-repo-is-still-a-repo later to maint).
+
+ * "git cherry-pick" run with the "-x" or the "--signoff" option used
+   to (and more importantly, ought to) clean up the commit log message
+   with the --cleanup=space option by default, but this has been
+   broken since late 2017.  This has been fixed.
+
+ * When given a tag that points at a commit-ish, "git replace --graft"
+   failed to peel the tag before writing a replace ref, which did not
+   make sense because the old graft mechanism the feature wants to
+   mimic only allowed to replace one commit object with another.
+   This has been fixed.
+   (merge ee521ec4cb cc/replace-graft-peel-tags later to maint).
+
+ * Code tightening against a "wrong" object appearing where an object
+   of a different type is expected, instead of blindly assuming that
+   the connection between objects are correctly made.
+   (merge 97dd512af7 tb/unexpected later to maint).
+
+ * An earlier update for MinGW and Cygwin accidentally broke MSVC build,
+   which has been fixed.
+   (merge 22c3634c0f ss/msvc-path-utils-fix later to maint).
+
+ * %(push:track) token used in the --format option to "git
+   for-each-ref" and friends was not showing the right branch, which
+   has been fixed.
+   (merge c646d0934e dr/ref-filter-push-track-fix later to maint).
+
+ * "make check-docs", "git help -a", etc. did not account for cases
+   where a particular build may deliberately omit some subcommands,
+   which has been corrected.
+
+ * The logic to tell if a Git repository has a working tree protects
+   "git branch -D" from removing the branch that is currently checked
+   out by mistake.  The implementation of this logic was broken for
+   repositories with unusual name, which unfortunately is the norm for
+   submodules these days.  This has been fixed.
+   (merge f3534c98e4 jt/submodule-repo-is-with-worktree later to maint).
+
+ * AIX shared the same build issues with other BSDs around fileno(fp),
+   which has been corrected.
+   (merge ee662bf5c6 cc/aix-has-fileno-as-a-macro later to maint).
+
+ * The autoconf generated configure script failed to use the right
+   gettext() implementations from -libintl by ignoring useless stub
+   implementations shipped in some C library, which has been
+   corrected.
+   (merge b71e56a683 vk/autoconf-gettext later to maint).
+
+ * Fix index-pack perf test so that the repeated invocations always
+   run in an empty repository, which emulates the initial clone
+   situation better.
+   (merge 775c71e16d jk/p5302-avoid-collision-check-cost later to maint).
+
+ * A "ls-files" that emulates "find" to enumerate files in the working
+   tree resulted in duplicated Makefile rules that caused the build to
+   issue an unnecessary warning during a trial build after merge
+   conflicts are resolved in working tree *.h files but before the
+   resolved results are added to the index.  This has been corrected.
+
+ * "git cherry-pick" (and "revert" that shares the same runtime engine)
+   that deals with multiple commits got confused when the final step
+   gets stopped with a conflict and the user concluded the sequence
+   with "git commit".  Attempt to fix it by cleaning up the state
+   files used by these commands in such a situation.
+   (merge 4a72486de9 pw/clean-sequencer-state-upon-final-commit later to maint).
+
+ * On a filesystem like HFS+, the names of the refs stored as filesystem
+   entities may become different from what the end-user expects, just
+   like files in the working tree get "renamed".  Work around the
+   mismatch by paying attention to the core.precomposeUnicode
+   configuration.
+   (merge 8e712ef6fc en/unicode-in-refnames later to maint).
+
+ * The code to generate the multi-pack idx file was not prepared to
+   see too many packfiles and ran out of open file descriptor, which
+   has been corrected.
+
+ * To run tests for Git SVN, our scripts for CI used to install the
+   git-svn package (in the hope that it would bring in the right
+   dependencies).  This has been updated to install the more direct
+   dependency, namely, libsvn-perl.
+   (merge db864306cf sg/ci-libsvn-perl later to maint).
+
+ * "git cvsexportcommit" running on msys did not expect cvsnt showed
+   "cvs status" output with CRLF line endings.
+
+ * The fsmonitor interface got out of sync after the in-core index
+   file gets discarded, which has been corrected.
+   (merge 398a3b0899 js/fsmonitor-refresh-after-discarding-index later to maint).
+
+ * "git status" did not know that the "label" instruction in the
+   todo-list "rebase -i -r" uses should not be shown as a hex object
+   name.
+
+ * A prerequisite check in the test suite to see if a working jgit is
+   available was made more robust.
+   (merge abd0f28983 tz/test-lib-check-working-jgit later to maint).
+
+ * The codepath to parse :<path> that obtains the object name for an
+   indexed object has been made more robust.
+
+ * Code cleanup, docfix, build fix, etc.
+   (merge 11f470aee7 jc/test-yes-doc later to maint).
+   (merge 90503a240b js/doc-symref-in-proto-v1 later to maint).
+   (merge 5c326d1252 jk/unused-params later to maint).
+   (merge 68cabbfda3 dl/doc-submodule-wo-subcommand later to maint).
+   (merge 9903623761 ab/receive-pack-use-after-free-fix later to maint).
+   (merge 1ede45e44b en/merge-options-doc later to maint).
+   (merge 3e14dd2c8e rd/doc-hook-used-in-sample later to maint).
+   (merge c271dc28fd nd/no-more-check-racy later to maint).
+   (merge e6e15194a8 yb/utf-16le-bom-spellfix later to maint).
+   (merge bb101aaf0c rd/attr.c-comment-typofix later to maint).
+   (merge 716a5af812 rd/gc-prune-doc-fix later to maint).
+   (merge 50b206371d js/untravis-windows later to maint).
+   (merge dbf47215e3 js/rebase-recreate-merge later to maint).
+   (merge 56cb2d30f8 dl/reset-doc-no-wrt-abbrev later to maint).
+   (merge 64eca306a2 ja/dir-rename-doc-markup-fix later to maint).
+   (merge af91b0230c dl/ignore-docs later to maint).
+   (merge 59a06e947b ra/t3600-test-path-funcs later to maint).
+   (merge e041d0781b ar/t4150-remove-cruft later to maint).
+   (merge 8d75a1d183 ma/asciidoctor-fixes-more later to maint).
+   (merge 74cc547b0f mh/pack-protocol-doc-fix later to maint).
+   (merge ed31851fa6 ab/doc-misc-typofixes later to maint).
+   (merge a7256debd4 nd/checkout-m-doc-update later to maint).
+   (merge 3a9e1ad78d jt/t5551-protocol-v2-does-not-have-half-auth later to maint).
+   (merge 0b918b75af sg/t5318-cleanup later to maint).
+   (merge 68ed71b53c cb/doco-mono later to maint).
+   (merge a34dca2451 nd/interpret-trailers-docfix later to maint).
+   (merge cf7b857a77 en/fast-import-parsing-fix later to maint).
+   (merge fe61ccbc35 po/rerere-doc-fmt later to maint).
+   (merge ffea0248bf po/describe-not-necessarily-7 later to maint).
+   (merge 7cb7283adb tg/ls-files-debug-format-fix later to maint).
+   (merge f64a21bd82 tz/doc-apostrophe-no-longer-needed later to maint).
+   (merge dbe7b41019 js/t3301-unbreak-notes-test later to maint).
+   (merge d8083e4180 km/t3000-retitle later to maint).
+   (merge 9e4cbccbd7 tz/git-svn-doc-markup-fix later to maint).
+   (merge da9ca955a7 jk/ls-files-doc-markup-fix later to maint).
+   (merge 6804ba3a58 cw/diff-highlight later to maint).
+   (merge 1a8787144d nd/submodule-helper-incomplete-line-fix later to maint).
+   (merge d9ef573837 jk/apache-lsan later to maint).
+   (merge c871fbee2b js/t6500-use-windows-pid-on-mingw later to maint).
+   (merge ce4c7bfc90 bl/t4253-exit-code-from-format-patch later to maint).
+   (merge 397a46db78 js/t5580-unc-alternate-test later to maint).
+   (merge d4907720a2 cm/notes-comment-fix later to maint).
+   (merge 9dde06de13 cb/http-push-null-in-message-fix later to maint).
+   (merge 4c785c0edc js/rebase-config-bitfix later to maint).
+   (merge 8e9fe16c87 es/doc-gitsubmodules-markup later to maint).
diff --git a/Documentation/RelNotes/2.22.1.txt b/Documentation/RelNotes/2.22.1.txt
new file mode 100644
index 0000000000..432762f270
--- /dev/null
+++ b/Documentation/RelNotes/2.22.1.txt
@@ -0,0 +1,150 @@
+Git 2.22.1 Release Notes
+========================
+
+Fixes since v2.22
+-----------------
+
+ * A relative pathname given to "git init --template=<path> <repo>"
+   ought to be relative to the directory "git init" gets invoked in,
+   but it instead was made relative to the repository, which has been
+   corrected.
+
+ * "git worktree add" used to fail when another worktree connected to
+   the same repository was corrupt, which has been corrected.
+
+ * The ownership rule for the file descriptor to fast-import remote
+   backend was mixed up, leading to unrelated file descriptor getting
+   closed, which has been fixed.
+
+ * "git update-server-info" used to leave stale packfiles in its
+   output, which has been corrected.
+
+ * The server side support for "git fetch" used to show incorrect
+   value for the HEAD symbolic ref when the namespace feature is in
+   use, which has been corrected.
+
+ * "git am -i --resolved" segfaulted after trying to see a commit as
+   if it were a tree, which has been corrected.
+
+ * "git bundle verify" needs to see if prerequisite objects exist in
+   the receiving repository, but the command did not check if we are
+   in a repository upfront, which has been corrected.
+
+ * "git merge --squash" is designed to update the working tree and the
+   index without creating the commit, and this cannot be countermanded
+   by adding the "--commit" option; the command now refuses to work
+   when both options are given.
+
+ * The data collected by fsmonitor was not properly written back to
+   the on-disk index file, breaking t7519 tests occasionally, which
+   has been corrected.
+
+ * Update to Unicode 12.1 width table.
+
+ * The command line to invoke a "git cat-file" command from inside
+   "git p4" was not properly quoted to protect a caret and running a
+   broken command on Windows, which has been corrected.
+
+ * "git request-pull" learned to warn when the ref we ask them to pull
+   from in the local repository and in the published repository are
+   different.
+
+ * When creating a partial clone, the object filtering criteria is
+   recorded for the origin of the clone, but this incorrectly used a
+   hardcoded name "origin" to name that remote; it has been corrected
+   to honor the "--origin <name>" option.
+
+ * "git fetch" into a lazy clone forgot to fetch base objects that are
+   necessary to complete delta in a thin packfile, which has been
+   corrected.
+
+ * The filter_data used in the list-objects-filter (which manages a
+   lazily sparse clone repository) did not use the dynamic array API
+   correctly---'nr' is supposed to point at one past the last element
+   of the array in use.  This has been corrected.
+
+ * The description about slashes in gitignore patterns (used to
+   indicate things like "anchored to this level only" and "only
+   matches directories") has been revamped.
+
+ * The URL decoding code has been updated to avoid going past the end
+   of the string while parsing %-<hex>-<hex> sequence.
+
+ * The list of for-each like macros used by clang-format has been
+   updated.
+
+ * "git push --atomic" that goes over the transport-helper (namely,
+   the smart http transport) failed to prevent refs to be pushed when
+   it can locally tell that one of the ref update will fail without
+   having to consult the other end, which has been corrected.
+
+ * "git clean" silently skipped a path when it cannot lstat() it; now
+   it gives a warning.
+
+ * A codepath that reads from GPG for signed object verification read
+   past the end of allocated buffer, which has been fixed.
+
+ * "git rm" to resolve a conflicted path leaked an internal message
+   "needs merge" before actually removing the path, which was
+   confusing.  This has been corrected.
+
+ * The "git clone" documentation refers to command line options in its
+   description in the short form; they have been replaced with long
+   forms to make them more recognisable.
+
+ * The configuration variable rebase.rescheduleFailedExec should be
+   effective only while running an interactive rebase and should not
+   affect anything when running a non-interactive one, which was not
+   the case.  This has been corrected.
+
+ * "git submodule foreach" did not protect command line options passed
+   to the command to be run in each submodule correctly, when the
+   "--recursive" option was in use.
+
+ * Use "Erase in Line" CSI sequence that is already used in the editor
+   support to clear cruft in the progress output.
+
+ * The codepath to compute delta islands used to spew progress output
+   without giving the callers any way to squelch it, which has been
+   fixed.
+
+ * The code to parse scaled numbers out of configuration files has
+   been made more robust and also easier to follow.
+
+ * An incorrect list of options was cached after command line
+   completion failed (e.g. trying to complete a command that requires
+   a repository outside one), which has been corrected.
+
+ * "git rebase --abort" used to leave refs/rewritten/ when concluding
+   "git rebase -r", which has been corrected.
+
+ * "git stash show 23" used to work, but no more after getting
+   rewritten in C; this regression has been corrected.
+
+ * "git interpret-trailers" always treated '#' as the comment
+   character, regardless of core.commentChar setting, which has been
+   corrected.
+
+ * Code clean-up to avoid signed integer overlaps during binary search.
+
+ * "git checkout -p" needs to selectively apply a patch in reverse,
+   which did not work well.
+
+ * The commit-graph file is now part of the "files that the runtime
+   may keep open file descriptors on, all of which would need to be
+   closed when done with the object store", and the file descriptor to
+   an existing commit-graph file now is closed before "gc" finalizes a
+   new instance to replace it.
+
+ * Code restructuring during 2.20 period broke fetching tags via
+   "import" based transports.
+
+ * We have been trying out a few language features outside c89; the
+   coding guidelines document did not talk about them and instead had
+   a blanket ban against them.
+
+ * The internal diff machinery can be made to read out of bounds while
+   looking for --funcion-context line in a corner case, which has been
+   corrected.
+
+Also contains various documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.22.2.txt b/Documentation/RelNotes/2.22.2.txt
new file mode 100644
index 0000000000..940a23f0d9
--- /dev/null
+++ b/Documentation/RelNotes/2.22.2.txt
@@ -0,0 +1,8 @@
+Git v2.22.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4,
+v2.17.3, v2.20.2 and in v2.21.1, addressing the security issues
+CVE-2019-1348, CVE-2019-1349, CVE-2019-1350, CVE-2019-1351,
+CVE-2019-1352, CVE-2019-1353, CVE-2019-1354, CVE-2019-1387, and
+CVE-2019-19604; see the release notes for those versions for details.
diff --git a/Documentation/RelNotes/2.22.3.txt b/Documentation/RelNotes/2.22.3.txt
new file mode 100644
index 0000000000..57296f6d17
--- /dev/null
+++ b/Documentation/RelNotes/2.22.3.txt
@@ -0,0 +1,5 @@
+Git v2.22.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.22.4.txt b/Documentation/RelNotes/2.22.4.txt
new file mode 100644
index 0000000000..8b5f3e3f37
--- /dev/null
+++ b/Documentation/RelNotes/2.22.4.txt
@@ -0,0 +1,5 @@
+Git v2.22.4 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.22.5.txt b/Documentation/RelNotes/2.22.5.txt
new file mode 100644
index 0000000000..6b280d9321
--- /dev/null
+++ b/Documentation/RelNotes/2.22.5.txt
@@ -0,0 +1,7 @@
+Git v2.22.5 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6,
+v2.18.5, v2.19.6, v2.20.5 and v2.21.4 to address the security
+issue CVE-2021-21300; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.23.0.txt b/Documentation/RelNotes/2.23.0.txt
new file mode 100644
index 0000000000..e3c4e78265
--- /dev/null
+++ b/Documentation/RelNotes/2.23.0.txt
@@ -0,0 +1,348 @@
+Git 2.23 Release Notes
+======================
+
+Updates since v2.22
+-------------------
+
+Backward compatibility note
+
+ * The "--base" option of "format-patch" computed the patch-ids for
+   prerequisite patches in an unstable way, which has been updated to
+   compute in a way that is compatible with "git patch-id --stable".
+
+ * The "git log" command by default behaves as if the --mailmap option
+   was given.
+
+
+UI, Workflows & Features
+
+ * The "git fast-export/import" pair has been taught to handle commits
+   with log messages in encoding other than UTF-8 better.
+
+ * In recent versions of Git, per-worktree refs are exposed in
+   refs/worktrees/<wtname>/ hierarchy, which means that worktree names
+   must be a valid refname component.  The code now sanitizes the names
+   given to worktrees, to make sure these refs are well-formed.
+
+ * "git merge" learned "--quit" option that cleans up the in-progress
+   merge while leaving the working tree and the index still in a mess.
+
+ * "git format-patch" learns a configuration to set the default for
+   its --notes=<ref> option.
+
+ * The code to show args with potential typo that cannot be
+   interpreted as a commit-ish has been improved.
+
+ * "git clone --recurse-submodules" learned to set up the submodules
+   to ignore commit object names recorded in the superproject gitlink
+   and instead use the commits that happen to be at the tip of the
+   remote-tracking branches from the get-go, by passing the new
+   "--remote-submodules" option.
+
+ * The pattern "git diff/grep" use to extract funcname and words
+   boundary for Matlab has been extend to cover Octave, which is more
+   or less equivalent.
+
+ * "git help git" was hard to discover (well, at least for some
+   people).
+
+ * The pattern "git diff/grep" use to extract funcname and words
+   boundary for Rust has been added.
+
+ * "git status" can be told a non-standard default value for the
+   "--[no-]ahead-behind" option with a new configuration variable
+   status.aheadBehind.
+
+ * "git fetch" and "git pull" reports when a fetch results in
+   non-fast-forward updates to let the user notice unusual situation.
+   The commands learned "--no-show-forced-updates" option to disable
+   this safety feature.
+
+ * Two new commands "git switch" and "git restore" are introduced to
+   split "checking out a branch to work on advancing its history" and
+   "checking out paths out of the index and/or a tree-ish to work on
+   advancing the current history" out of the single "git checkout"
+   command.
+
+ * "git branch --list" learned to always output the detached HEAD as
+   the first item (when the HEAD is detached, of course), regardless
+   of the locale.
+
+ * The conditional inclusion mechanism learned to base the choice on
+   the branch the HEAD currently is on.
+
+ * "git rev-list --objects" learned the "--no-object-names" option to
+   squelch the path to the object that is used as a grouping hint for
+   pack-objects.
+
+ * A new tag.gpgSign configuration variable turns "git tag -a" into
+   "git tag -s".
+
+ * "git multi-pack-index" learned expire and repack subcommands.
+
+ * "git blame" learned to "ignore" commits in the history, whose
+   effects (as well as their presence) get ignored.
+
+ * "git cherry-pick/revert" learned a new "--skip" action.
+
+ * The tips of refs from the alternate object store can be used as
+   starting point for reachability computation now.
+
+ * Extra blank lines in "git status" output have been reduced.
+
+ * The commits in a repository can be described by multiple
+   commit-graph files now, which allows the commit-graph files to be
+   updated incrementally.
+
+ * "git range-diff" output has been tweaked for easier identification
+   of which part of what file the patch shown is about.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Update supporting parts of "git rebase" to remove code that should
+   no longer be used.
+
+ * Developer support to emulate unsatisfied prerequisites in tests to
+   ensure that the remainder of the tests still succeeds when tests
+   with prerequisites are skipped.
+
+ * "git update-server-info" learned not to rewrite the file with the
+   same contents.
+
+ * The way of specifying the path to find dynamic libraries at runtime
+   has been simplified.  The old default to pass -R/path/to/dir has been
+   replaced with the new default to pass -Wl,-rpath,/path/to/dir,
+   which is the more recent GCC uses.  Those who need to build with an
+   old GCC can still use "CC_LD_DYNPATH=-R"
+
+ * Prepare use of reachability index in topological walker that works
+   on a range (A..B).
+
+ * A new tutorial targeting specifically aspiring git-core
+   developers has been added.
+
+ * Auto-detect how to tell HP-UX aCC where to use dynamically linked
+   libraries from at runtime.
+
+ * "git mergetool" and its tests now spawn fewer subprocesses.
+
+ * Dev support update to help tracing out tests.
+
+ * Support to build with MSVC has been updated.
+
+ * "git fetch" that grabs from a group of remotes learned to run the
+   auto-gc only once at the very end.
+
+ * A handful of Windows build patches have been upstreamed.
+
+ * The code to read state files used by the sequencer machinery for
+   "git status" has been made more robust against a corrupt or stale
+   state files.
+
+ * "git for-each-ref" with multiple patterns have been optimized.
+
+ * The tree-walk API learned to pass an in-core repository
+   instance throughout more codepaths.
+
+ * When one step in multi step cherry-pick or revert is reset or
+   committed, the command line prompt script failed to notice the
+   current status, which has been improved.
+
+ * Many GIT_TEST_* environment variables control various aspects of
+   how our tests are run, but a few followed "non-empty is true, empty
+   or unset is false" while others followed the usual "there are a few
+   ways to spell true, like yes, on, etc., and also ways to spell
+   false, like no, off, etc." convention.
+
+ * Adjust the dir-iterator API and apply it to the local clone
+   optimization codepath.
+
+ * We have been trying out a few language features outside c89; the
+   coding guidelines document did not talk about them and instead had
+   a blanket ban against them.
+
+ * A test helper has been introduced to optimize preparation of test
+   repositories with many simple commits, and a handful of test
+   scripts have been updated to use it.
+
+
+Fixes since v2.22
+-----------------
+
+ * A relative pathname given to "git init --template=<path> <repo>"
+   ought to be relative to the directory "git init" gets invoked in,
+   but it instead was made relative to the repository, which has been
+   corrected.
+
+ * "git worktree add" used to fail when another worktree connected to
+   the same repository was corrupt, which has been corrected.
+
+ * The ownership rule for the file descriptor to fast-import remote
+   backend was mixed up, leading to an unrelated file descriptor getting
+   closed, which has been fixed.
+
+ * A "merge -c" instruction during "git rebase --rebase-merges" should
+   give the user a chance to edit the log message, even when there is
+   otherwise no need to create a new merge and replace the existing
+   one (i.e. fast-forward instead), but did not.  Which has been
+   corrected.
+
+ * Code cleanup and futureproof.
+
+ * More parameter validation.
+
+ * "git update-server-info" used to leave stale packfiles in its
+   output, which has been corrected.
+
+ * The server side support for "git fetch" used to show incorrect
+   value for the HEAD symbolic ref when the namespace feature is in
+   use, which has been corrected.
+
+ * "git am -i --resolved" segfaulted after trying to see a commit as
+   if it were a tree, which has been corrected.
+
+ * "git bundle verify" needs to see if prerequisite objects exist in
+   the receiving repository, but the command did not check if we are
+   in a repository upfront, which has been corrected.
+
+ * "git merge --squash" is designed to update the working tree and the
+   index without creating the commit, and this cannot be countermanded
+   by adding the "--commit" option; the command now refuses to work
+   when both options are given.
+
+ * The data collected by fsmonitor was not properly written back to
+   the on-disk index file, breaking t7519 tests occasionally, which
+   has been corrected.
+
+ * Update to Unicode 12.1 width table.
+
+ * The command line to invoke a "git cat-file" command from inside
+   "git p4" was not properly quoted to protect a caret and running a
+   broken command on Windows, which has been corrected.
+
+ * "git request-pull" learned to warn when the ref we ask them to pull
+   from in the local repository and in the published repository are
+   different.
+
+ * When creating a partial clone, the object filtering criteria is
+   recorded for the origin of the clone, but this incorrectly used a
+   hardcoded name "origin" to name that remote; it has been corrected
+   to honor the "--origin <name>" option.
+
+ * "git fetch" into a lazy clone forgot to fetch base objects that are
+   necessary to complete delta in a thin packfile, which has been
+   corrected.
+
+ * The filter_data used in the list-objects-filter (which manages a
+   lazily sparse clone repository) did not use the dynamic array API
+   correctly---'nr' is supposed to point at one past the last element
+   of the array in use.  This has been corrected.
+
+ * The description about slashes in gitignore patterns (used to
+   indicate things like "anchored to this level only" and "only
+   matches directories") has been revamped.
+
+ * The URL decoding code has been updated to avoid going past the end
+   of the string while parsing %-<hex>-<hex> sequence.
+
+ * The list of for-each like macros used by clang-format has been
+   updated.
+
+ * "git branch --list" learned to show branches that are checked out
+   in other worktrees connected to the same repository prefixed with
+   '+', similar to the way the currently checked out branch is shown
+   with '*' in front.
+   (merge 6e9381469e nb/branch-show-other-worktrees-head later to maint).
+
+ * Code restructuring during 2.20 period broke fetching tags via
+   "import" based transports.
+
+ * The commit-graph file is now part of the "files that the runtime
+   may keep open file descriptors on, all of which would need to be
+   closed when done with the object store", and the file descriptor to
+   an existing commit-graph file now is closed before "gc" finalizes a
+   new instance to replace it.
+
+ * "git checkout -p" needs to selectively apply a patch in reverse,
+   which did not work well.
+
+ * Code clean-up to avoid signed integer wraparounds during binary search.
+
+ * "git interpret-trailers" always treated '#' as the comment
+   character, regardless of core.commentChar setting, which has been
+   corrected.
+
+ * "git stash show 23" used to work, but no more after getting
+   rewritten in C; this regression has been corrected.
+
+ * "git rebase --abort" used to leave refs/rewritten/ when concluding
+   "git rebase -r", which has been corrected.
+
+ * An incorrect list of options was cached after command line
+   completion failed (e.g. trying to complete a command that requires
+   a repository outside one), which has been corrected.
+
+ * The code to parse scaled numbers out of configuration files has
+   been made more robust and also easier to follow.
+
+ * The codepath to compute delta islands used to spew progress output
+   without giving the callers any way to squelch it, which has been
+   fixed.
+
+ * Protocol capabilities that go over wire should never be translated,
+   but it was incorrectly marked for translation, which has been
+   corrected.  The output of protocol capabilities for debugging has
+   been tweaked a bit.
+
+ * Use "Erase in Line" CSI sequence that is already used in the editor
+   support to clear cruft in the progress output.
+
+ * "git submodule foreach" did not protect command line options passed
+   to the command to be run in each submodule correctly, when the
+   "--recursive" option was in use.
+
+ * The configuration variable rebase.rescheduleFailedExec should be
+   effective only while running an interactive rebase and should not
+   affect anything when running a non-interactive one, which was not
+   the case.  This has been corrected.
+
+ * The "git clone" documentation refers to command line options in its
+   description in the short form; they have been replaced with long
+   forms to make them more recognisable.
+
+ * Generation of pack bitmaps are now disabled when .keep files exist,
+   as these are mutually exclusive features.
+   (merge 7328482253 ew/repack-with-bitmaps-by-default later to maint).
+
+ * "git rm" to resolve a conflicted path leaked an internal message
+   "needs merge" before actually removing the path, which was
+   confusing.  This has been corrected.
+
+ * "git stash --keep-index" did not work correctly on paths that have
+   been removed, which has been fixed.
+   (merge b932f6a5e8 tg/stash-keep-index-with-removed-paths later to maint).
+
+ * Window 7 update ;-)
+
+ * A codepath that reads from GPG for signed object verification read
+   past the end of allocated buffer, which has been fixed.
+
+ * "git clean" silently skipped a path when it cannot lstat() it; now
+   it gives a warning.
+
+ * "git push --atomic" that goes over the transport-helper (namely,
+   the smart http transport) failed to prevent refs to be pushed when
+   it can locally tell that one of the ref update will fail without
+   having to consult the other end, which has been corrected.
+
+ * The internal diff machinery can be made to read out of bounds while
+   looking for --function-context line in a corner case, which has been
+   corrected.
+   (merge b777f3fd61 jk/xdiff-clamp-funcname-context-index later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge fbec05c210 cc/test-oidmap later to maint).
+   (merge 7a06fb038c jk/no-system-includes-in-dot-c later to maint).
+   (merge 81ed2b405c cb/xdiff-no-system-includes-in-dot-c later to maint).
+   (merge d61e6ce1dd sg/fsck-config-in-doc later to maint).
diff --git a/Documentation/RelNotes/2.23.1.txt b/Documentation/RelNotes/2.23.1.txt
new file mode 100644
index 0000000000..2083b492ce
--- /dev/null
+++ b/Documentation/RelNotes/2.23.1.txt
@@ -0,0 +1,8 @@
+Git v2.23.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4,
+v2.17.3, v2.20.2 and in v2.21.1, addressing the security issues
+CVE-2019-1348, CVE-2019-1349, CVE-2019-1350, CVE-2019-1351,
+CVE-2019-1352, CVE-2019-1353, CVE-2019-1354, CVE-2019-1387, and
+CVE-2019-19604; see the release notes for those versions for details.
diff --git a/Documentation/RelNotes/2.23.2.txt b/Documentation/RelNotes/2.23.2.txt
new file mode 100644
index 0000000000..b697cbe0e3
--- /dev/null
+++ b/Documentation/RelNotes/2.23.2.txt
@@ -0,0 +1,5 @@
+Git v2.23.2 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.23.3.txt b/Documentation/RelNotes/2.23.3.txt
new file mode 100644
index 0000000000..2e35490137
--- /dev/null
+++ b/Documentation/RelNotes/2.23.3.txt
@@ -0,0 +1,5 @@
+Git v2.23.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.23.4.txt b/Documentation/RelNotes/2.23.4.txt
new file mode 100644
index 0000000000..6e5424d0da
--- /dev/null
+++ b/Documentation/RelNotes/2.23.4.txt
@@ -0,0 +1,7 @@
+Git v2.23.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5,
+v2.19.6, v2.20.5, v2.21.4 and v2.22.5 to address the security
+issue CVE-2021-21300; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.24.0.txt b/Documentation/RelNotes/2.24.0.txt
new file mode 100644
index 0000000000..bde154124c
--- /dev/null
+++ b/Documentation/RelNotes/2.24.0.txt
@@ -0,0 +1,398 @@
+Git 2.24 Release Notes
+======================
+
+Updates since v2.23
+-------------------
+
+Backward compatibility note
+
+ * "filter-branch" is showing its age and alternatives are available.
+   From this release, we started to discourage its use and hint
+   people about filter-repo.
+
+UI, Workflows & Features
+
+ * We now have an active interim maintainer for the Git-Gui part of
+   the system.  Praise and thank Pratyush Yadav for volunteering.
+
+ * The command line parser learned "--end-of-options" notation; the
+   standard convention for scripters to have hardcoded set of options
+   first on the command line, and force the command to treat end-user
+   input as non-options, has been to use "--" as the delimiter, but
+   that would not work for commands that use "--" as a delimiter
+   between revs and pathspec.
+
+ * A mechanism to affect the default setting for a (related) group of
+   configuration variables is introduced.
+
+ * "git fetch" learned "--set-upstream" option to help those who first
+   clone from their private fork they intend to push to, add the true
+   upstream via "git remote add" and then "git fetch" from it.
+
+ * Device-tree files learned their own userdiff patterns.
+   (merge 3c81760bc6 sb/userdiff-dts later to maint).
+
+ * "git rebase --rebase-merges" learned to drive different merge
+   strategies and pass strategy specific options to them.
+
+ * A new "pre-merge-commit" hook has been introduced.
+
+ * Command line completion updates for "git -c var.name=val" have been
+   added.
+
+ * The lazy clone machinery has been taught that there can be more
+   than one promisor remote and consult them in order when downloading
+   missing objects on demand.
+
+ * The list-objects-filter API (used to create a sparse/lazy clone)
+   learned to take a combined filter specification.
+
+ * The documentation and tests for "git format-patch" have been
+   cleaned up.
+
+ * On Windows, the root level of UNC share is now allowed to be used
+   just like any other directory.
+
+ * The command line completion support (in contrib/) learned about the
+   "--skip" option of "git revert" and "git cherry-pick".
+
+ * "git rebase --keep-base <upstream>" tries to find the original base
+   of the topic being rebased and rebase on top of that same base,
+   which is useful when running the "git rebase -i" (and its limited
+   variant "git rebase -x").
+
+   The command also has learned to fast-forward in more cases where it
+   can instead of replaying to recreate identical commits.
+
+ * A configuration variable tells "git fetch" to write the commit
+   graph after finishing.
+
+ * "git add -i" has been taught to show the total number of hunks and
+   the hunks that has been processed so far when showing prompts.
+
+ * "git fetch --jobs=<n>" allowed <n> parallel jobs when fetching
+   submodules, but this did not apply to "git fetch --multiple" that
+   fetches from multiple remote repositories.  It now does.
+
+ * The installation instruction for zsh completion script (in
+   contrib/) has been a bit improved.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The code to write commit-graph over given commit object names has
+   been made a bit more robust.
+
+ * The first line of verbose output from each test piece now carries
+   the test name and number to help scanning with eyeballs.
+
+ * Further clean-up of the initialization code.
+
+ * xmalloc() used to have a mechanism to ditch memory and address
+   space resources as the last resort upon seeing an allocation
+   failure from the underlying malloc(), which made the code complex
+   and thread-unsafe with dubious benefit, as major memory resource
+   users already do limit their uses with various other mechanisms.
+   It has been simplified away.
+
+ * Unnecessary full-tree diff in "git log -L" machinery has been
+   optimized away.
+
+ * The http transport lacked some optimization the native transports
+   learned to avoid unnecessary ref advertisement, which has been
+   corrected.
+
+ * Preparation for SHA-256 upgrade continues in the test department.
+   (merge 0c37c41d13 bc/hash-independent-tests-part-5 later to maint).
+
+ * The memory ownership model of the "git fast-import" got
+   straightened out.
+
+ * Output from trace2 subsystem is formatted more prettily now.
+
+ * The internal code originally invented for ".gitignore" processing
+   got reshuffled and renamed to make it less tied to "excluding" and
+   stress more that it is about "matching", as it has been reused for
+   things like sparse checkout specification that want to check if a
+   path is "included".
+
+ * "git stash" learned to write refreshed index back to disk.
+
+ * Coccinelle checks are done on more source files than before now.
+
+ * The cache-tree code has been taught to be less aggressive in
+   attempting to see if a tree object it computed already exists in
+   the repository.
+
+ * The code to parse and use the commit-graph file has been made more
+   robust against corrupted input.
+
+ * The hg-to-git script (in contrib/) has been updated to work with
+   Python 3.
+
+ * Update the way build artifacts in t/helper/ directory are ignored.
+
+ * Preparation for SHA-256 upgrade continues.
+
+ * "git log --graph" for an octopus merge is sometimes colored
+   incorrectly, which is demonstrated and documented but not yet
+   fixed.
+
+ * The trace2 output, when sending them to files in a designated
+   directory, can populate the directory with too many files; a
+   mechanism is introduced to set the maximum number of files and
+   discard further logs when the maximum is reached.
+
+ * We have adopted a Code-of-conduct document.
+   (merge 3f9ef874a7 jk/coc later to maint).
+
+
+Fixes since v2.23
+-----------------
+
+ * "git grep --recurse-submodules" that looks at the working tree
+   files looked at the contents in the index in submodules, instead of
+   files in the working tree.
+   (merge 6a289d45c0 mt/grep-submodules-working-tree later to maint).
+
+ * Codepaths to walk tree objects have been audited for integer
+   overflows and hardened.
+   (merge 5aa02f9868 jk/tree-walk-overflow later to maint).
+
+ * "git pack-refs" can lose refs that are created while running, which
+   is getting corrected.
+   (merge a613d4f817 sc/pack-refs-deletion-racefix later to maint).
+
+ * "git checkout" and "git restore" to re-populate the index from a
+   tree-ish (typically HEAD) did not work correctly for a path that
+   was removed and then added again with the intent-to-add bit, when
+   the corresponding working tree file was empty.  This has been
+   corrected.
+
+ * Compilation fix.
+   (merge 70597e8386 rs/nedalloc-fixlets later to maint).
+
+ * "git gui" learned to call the clean-up procedure before exiting.
+   (merge 0d88f3d2c5 py/git-gui-do-quit later to maint).
+
+ * We promoted the "indent heuristics" that decides where to split
+   diff hunks from experimental to the default a few years ago, but
+   some stale documentation still marked it as experimental, which has
+   been corrected.
+   (merge 64e5e1fba1 sg/diff-indent-heuristic-non-experimental later to maint).
+
+ * Fix a mismerge that happened in 2.22 timeframe.
+   (merge acb7da05ac en/checkout-mismerge-fix later to maint).
+
+ * "git archive" recorded incorrect length in extended pax header in
+   some corner cases, which has been corrected.
+   (merge 71d41ff651 rs/pax-extended-header-length-fix later to maint).
+
+ * On-demand object fetching in lazy clone incorrectly tried to fetch
+   commits from submodule projects, while still working in the
+   superproject, which has been corrected.
+   (merge a63694f523 jt/diff-lazy-fetch-submodule-fix later to maint).
+
+ * Prepare get_short_oid() codepath to be thread-safe.
+   (merge 7cfcb16b0e rs/sort-oid-array-thread-safe later to maint).
+
+ * "for-each-ref" and friends that show refs did not protect themselves
+   against ancient tags that did not record tagger names when asked to
+   show "%(taggername)", which have been corrected.
+   (merge 8b3f33ef11 mp/for-each-ref-missing-name-or-email later to maint).
+
+ * The "git am" based backend of "git rebase" ignored the result of
+   updating ".gitattributes" done in one step when replaying
+   subsequent steps.
+   (merge 2c65d90f75 bc/reread-attributes-during-rebase later to maint).
+
+ * Tell cURL library to use the same malloc() implementation, with the
+   xmalloc() wrapper, as the rest of the system, for consistency.
+   (merge 93b980e58f cb/curl-use-xmalloc later to maint).
+
+ * Build fix to adjust .gitignore to unignore a path that we started to track.
+   (merge aac6ff7b5b js/visual-studio later to maint).
+
+ * A few implementation fixes in the notes API.
+   (merge 60fe477a0b mh/notes-duplicate-entries later to maint).
+
+ * Fix an earlier regression to "git push --all" which should have
+   been forbidden when the target remote repository is set to be a
+   mirror.
+   (merge 8e4c8af058 tg/push-all-in-mirror-forbidden later to maint).
+
+ * Fix an earlier regression in the test suite, which mistakenly
+   stopped running HTTPD tests.
+   (merge 3960290675 sg/git-test-boolean later to maint).
+
+ * "git rebase --autostash <upstream> <branch>", when <branch> is
+   different from the current branch, incorrectly moved the tip of the
+   current branch, which has been corrected.
+   (merge bf1e28e0ad bw/rebase-autostash-keep-current-branch later to maint).
+
+ * Update support for Asciidoctor documentation toolchain.
+   (merge 83b0b8953e ma/asciidoctor-refmiscinfo later to maint).
+
+ * Start using DocBook 5 (instead of DocBook 4.5) as Asciidoctor 2.0
+   no longer works with the older one.
+   (merge f6461b82b9 bc/doc-use-docbook-5 later to maint).
+
+ * The markup used in user-manual has been updated to work better with
+   asciidoctor.
+   (merge c4d2f6143a ma/user-manual-markup-update later to maint).
+
+ * Make sure the grep machinery does not abort when seeing a payload
+   that is not UTF-8 even when JIT is not in use with PCRE1.
+   (merge ad7c543e3b cb/skip-utf8-check-with-pcre1 later to maint).
+
+ * The name of the blob object that stores the filter specification
+   for sparse cloning/fetching was interpreted in a wrong place in the
+   code, causing Git to abort.
+
+ * "git log --decorate-refs-exclude=<pattern>" was incorrectly
+   overruled when the "--simplify-by-decoration" option is used, which
+   has been corrected.
+   (merge 0cc7380d88 rs/simplify-by-deco-with-deco-refs-exclude later to maint).
+
+ * The "upload-pack" (the counterpart of "git fetch") needs to disable
+   commit-graph when responding to a shallow clone/fetch request, but
+   the way this was done made Git panic, which has been corrected.
+
+ * The object traversal machinery has been optimized not to load tree
+   objects when we are only interested in commit history.
+   (merge 72ed80c784 jk/list-objects-optim-wo-trees later to maint).
+
+ * The object name parser for "Nth parent" syntax has been made more
+   robust against integer overflows.
+   (merge 59fa5f5a25 rs/nth-parent-parse later to maint).
+
+ * The code used in following tags in "git fetch" has been optimized.
+   (merge b7e2d8bca5 ms/fetch-follow-tag-optim later to maint).
+
+ * Regression fix for progress output.
+   (merge 2bb74b53a4 sg/progress-fix later to maint).
+
+ * A bug in merge-recursive code that triggers when a branch with a
+   symbolic link is merged with a branch that replaces it with a
+   directory has been fixed.
+   (merge 83e3ad3b12 jt/merge-recursive-symlink-is-not-a-dir-in-way later to maint).
+
+ * The rename detection logic sorts a list of rename source candidates
+   by similarity to pick the best candidate, which means that a tie
+   between sources with the same similarity is broken by the original
+   location in the original candidate list (which is sorted by path).
+   Force the sorting by similarity done with a stable sort, which is
+   not promised by system supplied qsort(3), to ensure consistent
+   results across platforms.
+   (merge 2049b8dc65 js/diff-rename-force-stable-sort later to maint).
+
+ * The code to skip "UTF" and "UTF-" prefix, when computing an advice
+   message, did not work correctly when the prefix was "UTF", which
+   has been fixed.
+   (merge b181676ce9 rs/convert-fix-utf-without-dash later to maint).
+
+ * The author names taken from SVN repositories may have extra leading
+   or trailing whitespaces, which are now munged away.
+   (merge 4ddd4bddb1 tk/git-svn-trim-author-name later to maint).
+
+ * "git rebase -i" showed a wrong HEAD while "reword" open the editor.
+   (merge b0a3186140 pw/rebase-i-show-HEAD-to-reword later to maint).
+
+ * A few simplification and bugfixes to PCRE interface.
+   (merge c581e4a749 ab/pcre-jit-fixes later to maint).
+
+ * PCRE fixes.
+   (merge ff61681b46 cb/pcre1-cleanup later to maint).
+
+ * "git range-diff" segfaulted when diff.noprefix configuration was
+   used, as it blindly expected the patch it internally generates to
+   have the standard a/ and b/ prefixes.  The command now forces the
+   internal patch to be built without any prefix, not to be affected
+   by any end-user configuration.
+   (merge 937b76ed49 js/range-diff-noprefix later to maint).
+
+ * "git stash apply" in a subdirectory of a secondary worktree failed
+   to access the worktree correctly, which has been corrected.
+   (merge dfd557c978 js/stash-apply-in-secondary-worktree later to maint).
+
+ * The merge-recursive machinery is one of the most complex parts of
+   the system that accumulated cruft over time.  This large series
+   cleans up the implementation quite a bit.
+   (merge b657047719 en/merge-recursive-cleanup later to maint).
+
+ * Pretty-printed command line formatter (used in e.g. reporting the
+   command being run by the tracing API) had a bug that lost an
+   argument that is an empty string, which has been corrected.
+   (merge ce2d7ed2fd gs/sq-quote-buf-pretty later to maint).
+
+ * "git range-diff" failed to handle mode-only change, which has been
+   corrected.
+   (merge 2b6a9b13ca tg/range-diff-output-update later to maint).
+
+ * Dev support update.
+   (merge 4f3c1dc5d6 dl/allow-running-cocci-verbosely later to maint).
+
+ * "git format-patch -o <outdir>" did an equivalent of "mkdir <outdir>"
+   not "mkdir -p <outdir>", which was corrected.
+
+ * "git stash save" lost local changes to submodules, which has been
+   corrected.
+   (merge 556895d0c8 jj/stash-reset-only-toplevel later to maint).
+
+ * The atomic push over smart HTTP transport did not work, which has
+   been corrected.
+   (merge 6f1194246a bc/smart-http-atomic-push later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge d1387d3895 en/fast-import-merge-doc later to maint).
+   (merge 1c24a54ea4 bm/repository-layout-typofix later to maint).
+   (merge 415b770b88 ds/midx-expire-repack later to maint).
+   (merge 19800bdc3f nd/diff-parseopt later to maint).
+   (merge 58166c2e9d tg/t0021-racefix later to maint).
+   (merge 7027f508c7 dl/compat-cleanup later to maint).
+   (merge e770fbfeff jc/test-cleanup later to maint).
+   (merge 1fd881d404 rs/trace2-dst-warning later to maint).
+   (merge 7e92756751 mh/http-urlmatch-cleanup later to maint).
+   (merge 9784f97321 mh/release-commit-memory-fix later to maint).
+   (merge 60d198d022 tb/banned-vsprintf-namefix later to maint).
+   (merge 80e3658647 rs/help-unknown-ref-does-not-return later to maint).
+   (merge 0a8bc7068f dt/remote-helper-doc-re-lock-option later to maint).
+   (merge 27fd1e4ea7 en/merge-options-ff-and-friends later to maint).
+   (merge 502c386ff9 sg/clean-nested-repo-with-ignored later to maint).
+   (merge 26e3d1cbea am/mailmap-andrey-mazo later to maint).
+   (merge 47b27c96fa ss/get-time-cleanup later to maint).
+   (merge dd2e50a84e jk/commit-graph-cleanup later to maint).
+   (merge 4fd39c76e6 cs/pretty-formats-doc-typofix later to maint).
+   (merge 40e747e89d dl/submodule-set-branch later to maint).
+   (merge 689a146c91 rs/commit-graph-use-list-count later to maint).
+   (merge 0eb7c37a8a js/doc-patch-text later to maint).
+   (merge 4b3aa170d1 rs/nth-switch-code-simplification later to maint).
+   (merge 0d4304c124 ah/doc-submodule-ignore-submodules later to maint).
+   (merge af78249463 cc/svn-fe-py-shebang later to maint).
+   (merge 7bd97d6dff rs/alias-use-copy-array later to maint).
+   (merge c46ebc2496 sg/travis-help-debug later to maint).
+   (merge 24c681794f ps/my-first-contribution-alphasort later to maint).
+   (merge 75b2c15435 cb/do-not-use-test-cmp-with-a later to maint).
+   (merge cda0d497e3 bw/submodule-helper-usage-fix later to maint).
+   (merge fe0ed5d5e9 am/visual-studio-config-fix later to maint).
+   (merge 2e09c01232 sg/name-rev-cutoff-underflow-fix later to maint).
+   (merge ddb3c856f3 as/shallow-slab-use-fix later to maint).
+   (merge 71f4960b91 js/mingw-spawn-with-spaces-in-path later to maint).
+   (merge 53d687bf5f ah/cleanups later to maint).
+   (merge f537485fa5 rs/test-remove-useless-debugging-cat later to maint).
+   (merge 11a3d3aadd dl/rev-list-doc-cleanup later to maint).
+   (merge d928a8388a am/t0028-utf16-tests later to maint).
+   (merge b05b40930e dl/t0000-skip-test-test later to maint).
+   (merge 03d3b1297c js/xdiffi-comment-updates later to maint).
+   (merge 57d8f4b4c7 js/doc-stash-save later to maint).
+   (merge 8c1cfd58e3 ta/t1308-typofix later to maint).
+   (merge fa364ad790 bb/utf8-wcwidth-cleanup later to maint).
+   (merge 68b69211b2 bb/compat-util-comment-fix later to maint).
+   (merge 5cc6a4be11 rs/http-push-simplify later to maint).
+   (merge a81e42d235 rs/column-use-utf8-strnwidth later to maint).
+   (merge 062a309d36 rs/remote-curl-use-argv-array later to maint).
+   (merge 3b3c79f6c9 nr/diff-highlight-indent-fix later to maint).
+   (merge 3444ec2eb2 wb/fsmonitor-bitmap-fix later to maint).
+   (merge 10da030ab7 cb/pcre2-chartables-leakfix later to maint).
+   (merge 60e6569a12 js/mingw-needs-hiding-fix later to maint).
+   (merge 52bd3e4657 rl/gitweb-blame-prev-fix later to maint).
diff --git a/Documentation/RelNotes/2.24.1.txt b/Documentation/RelNotes/2.24.1.txt
new file mode 100644
index 0000000000..18104850fe
--- /dev/null
+++ b/Documentation/RelNotes/2.24.1.txt
@@ -0,0 +1,8 @@
+Git v2.24.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.14.6, v2.15.4,
+v2.17.3, v2.20.2 and in v2.21.1, addressing the security issues
+CVE-2019-1348, CVE-2019-1349, CVE-2019-1350, CVE-2019-1351,
+CVE-2019-1352, CVE-2019-1353, CVE-2019-1354, CVE-2019-1387, and
+CVE-2019-19604; see the release notes for those versions for details.
diff --git a/Documentation/RelNotes/2.24.2.txt b/Documentation/RelNotes/2.24.2.txt
new file mode 100644
index 0000000000..0049f65503
--- /dev/null
+++ b/Documentation/RelNotes/2.24.2.txt
@@ -0,0 +1,5 @@
+Git v2.24.2 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.24.3.txt b/Documentation/RelNotes/2.24.3.txt
new file mode 100644
index 0000000000..5302e0f73b
--- /dev/null
+++ b/Documentation/RelNotes/2.24.3.txt
@@ -0,0 +1,5 @@
+Git v2.24.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.24.4.txt b/Documentation/RelNotes/2.24.4.txt
new file mode 100644
index 0000000000..4e216eec2a
--- /dev/null
+++ b/Documentation/RelNotes/2.24.4.txt
@@ -0,0 +1,7 @@
+Git v2.24.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5,
+v2.19.6, v2.20.5, v2.21.4, v2.22.5 and v2.23.4 to address the
+security issue CVE-2021-21300; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.25.0.txt b/Documentation/RelNotes/2.25.0.txt
new file mode 100644
index 0000000000..91ceb34927
--- /dev/null
+++ b/Documentation/RelNotes/2.25.0.txt
@@ -0,0 +1,370 @@
+Git 2.25 Release Notes
+======================
+
+Updates since v2.24
+-------------------
+
+Backward compatibility notes
+
+
+UI, Workflows & Features
+
+ * A tutorial on object enumeration has been added.
+
+ * The branch description ("git branch --edit-description") has been
+   used to fill the body of the cover letters by the format-patch
+   command; this has been enhanced so that the subject can also be
+   filled.
+
+ * "git rebase --preserve-merges" has been marked as deprecated; this
+   release stops advertising it in the "git rebase -h" output.
+
+ * The code to generate multi-pack index learned to show (or not to
+   show) progress indicators.
+
+ * "git apply --3way" learned to honor merge.conflictStyle
+   configuration variable, like merges would.
+
+ * The custom format for "git log --format=<format>" learned the l/L
+   placeholder that is similar to e/E that fills in the e-mail
+   address, but only the local part on the left side of '@'.
+
+ * Documentation pages for "git shortlog" now list commit limiting
+   options explicitly.
+
+ * The patterns to detect function boundary for Elixir language has
+   been added.
+
+ * The completion script (in contrib/) learned that the "--onto"
+   option of "git rebase" can take its argument as the value of the
+   option.
+
+ * The userdiff machinery has been taught that "async def" is another
+   way to begin a "function" in Python.
+
+ * "git range-diff" learned to take the "--notes=<ref>" and the
+   "--no-notes" options to control the commit notes included in the
+   log message that gets compared.
+
+ * "git rev-parse --show-toplevel" run outside of any working tree did
+   not error out, which has been corrected.
+
+ * A few commands learned to take the pathspec from the standard input
+   or a named file, instead of taking it as the command line
+   arguments, with the "--pathspec-from-file" option.
+
+ * "git submodule" learned a subcommand "set-url".
+
+ * "git log" family learned "--pretty=reference" that gives the name
+   of a commit in the format that is often used to refer to it in log
+   messages.
+
+ * The interaction between "git clone --recurse-submodules" and
+   alternate object store was ill-designed.  The documentation and
+   code have been taught to make more clear recommendations when the
+   users see failures.
+
+ * Management of sparsely checked-out working tree has gained a
+   dedicated "sparse-checkout" command.
+
+ * Miscellaneous small UX improvements on "git-p4".
+
+ * "git sparse-checkout list" subcommand learned to give its output in
+   a more concise form when the "cone" mode is in effect.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Debugging support for lazy cloning has been a bit improved.
+
+ * Move the definition of a set of bitmask constants from 0ctal
+   literal to (1U<<count) notation.
+
+ * Test updates to prepare for SHA-2 transition continues.
+
+ * Crufty code and logic accumulated over time around the object
+   parsing and low-level object access used in "git fsck" have been
+   cleaned up.
+
+ * The implementation of "git log --graph" got refactored and then its
+   output got simplified.
+
+ * Follow recent push to move API docs from Documentation/ to header
+   files and update config.h
+
+ * "git bundle" has been taught to use the parse options API.  "git
+   bundle verify" learned "--quiet" and "git bundle create" learned
+   options to control the progress output.
+
+ * Handling of commit objects that use non UTF-8 encoding during
+   "rebase -i" has been improved.
+
+ * The beginning of rewriting "git add -i" in C.
+
+ * A label used in the todo list that are generated by "git rebase
+   --rebase-merges" is used as a part of a refname; the logic to come
+   up with the label has been tightened to avoid names that cannot be
+   used as such.
+
+ * The logic to avoid duplicate label names generated by "git rebase
+   --rebase-merges" forgot that the machinery itself uses "onto" as a
+   label name, which must be avoided by auto-generated labels, which
+   has been corrected.
+
+ * We have had compatibility fallback macro definitions for "PRIuMAX",
+   "PRIu32", etc. but did not for "PRIdMAX", while the code used the
+   last one apparently without any hiccup reported recently.  The
+   fallback macro definitions for these <inttypes.h> macros that must
+   appear in C99 systems have been removed.
+
+ * Recently we have declared that GIT_TEST_* variables take the
+   usual boolean values (it used to be that some used "non-empty
+   means true" and taking GIT_TEST_VAR=YesPlease as true); make
+   sure we notice and fail when non-bool strings are given to
+   these variables.
+
+ * Users of oneway_merge() (like "reset --hard") learned to take
+   advantage of fsmonitor to avoid unnecessary lstat(2) calls.
+
+ * Performance tweak on "git push" into a repository with many refs
+   that point at objects we have never heard of.
+
+ * PerfTest fix to avoid stale result mixed up with the latest round
+   of test results.
+
+ * Hide lower-level verify_signed-buffer() API as a pure helper to
+   implement the public check_signature() function, in order to
+   encourage new callers to use the correct and more strict
+   validation.
+
+ * Unnecessary reading of state variables back from the disk during
+   sequencer operation has been reduced.
+
+ * The code has been made to avoid gmtime() and localtime() and prefer
+   their reentrant counterparts.
+
+ * In a repository with many packfiles, the cost of the procedure that
+   avoids registering the same packfile twice was unnecessarily high
+   by using an inefficient search algorithm, which has been corrected.
+
+ * Redo "git name-rev" to avoid recursive calls.
+
+ * FreeBSD CI support via Cirrus-CI has been added.
+
+
+Fixes since v2.24
+-----------------
+
+ * "rebase -i" ceased to run post-commit hook by mistake in an earlier
+   update, which has been corrected.
+
+ * "git notes copy $original" ought to copy the notes attached to the
+   original object to HEAD, but a mistaken tightening to command line
+   parameter validation made earlier disabled that feature by mistake.
+
+ * When all files from some subdirectory were renamed to the root
+   directory, the directory rename heuristics would fail to detect that
+   as a rename/merge of the subdirectory to the root directory, which has
+   been corrected.
+
+ * Code clean-up and a bugfix in the logic used to tell worktree local
+   and repository global refs apart.
+   (merge f45f88b2e4 sg/dir-trie-fixes later to maint).
+
+ * "git stash save" in a working tree that is sparsely checked out
+   mistakenly removed paths that are outside the area of interest.
+   (merge 4a58c3d7f7 js/update-index-ignore-removal-for-skip-worktree later to maint).
+
+ * "git rev-parse --git-path HEAD.lock" did not give the right path
+   when run in a secondary worktree.
+   (merge 76a53d640f js/git-path-head-dot-lock-fix later to maint).
+
+ * "git merge --no-commit" needs "--no-ff" if you do not want to move
+   HEAD, which has been corrected in the manual page for "git bisect".
+   (merge 8dd327b246 ma/bisect-doc-sample-update later to maint).
+
+ * "git worktree add" internally calls "reset --hard" that should not
+   descend into submodules, even when submodule.recurse configuration
+   is set, but it was affected.  This has been corrected.
+   (merge 4782cf2ab6 pb/no-recursive-reset-hard-in-worktree-add later to maint).
+
+ * Messages from die() etc. can be mixed up from multiple processes
+   without even line buffering on Windows, which has been worked
+   around.
+   (merge 116d1fa6c6 js/vreportf-wo-buffering later to maint).
+
+ * HTTP transport had possible allocator/deallocator mismatch, which
+   has been corrected.
+
+ * The watchman integration for fsmonitor was racy, which has been
+   corrected to be more conservative.
+   (merge dd0b61f577 kw/fsmonitor-watchman-fix later to maint).
+
+ * Fetching from multiple remotes into the same repository in parallel
+   had a bad interaction with the recent change to (optionally) update
+   the commit-graph after a fetch job finishes, as these parallel
+   fetches compete with each other.  Which has been corrected.
+
+ * Recent update to "git stash pop" made the command empty the index
+   when run with the "--quiet" option, which has been corrected.
+
+ * "git fetch" codepath had a big "do not lazily fetch missing objects
+   when I ask if something exists" switch.  This has been corrected by
+   marking the "does this thing exist?" calls with "if not please do not
+   lazily fetch it" flag.
+
+ * Test update to avoid wasted cycles.
+   (merge e0316695ec sg/skip-skipped-prereq later to maint).
+
+ * Error handling after "git push" finishes sending the packdata and
+   waits for the response to the remote side has been improved.
+   (merge ad7a403268 jk/send-pack-remote-failure later to maint).
+
+ * Some codepaths in "gitweb" that forgot to escape URLs generated
+   based on end-user input have been corrected.
+   (merge a376e37b2c jk/gitweb-anti-xss later to maint).
+
+ * CI jobs for macOS has been made less chatty when updating perforce
+   package used during testing.
+   (merge 0dbc4a0edf jc/azure-ci-osx-fix-fix later to maint).
+
+ * "git unpack-objects" used to show progress based only on the number
+   of received and unpacked objects, which stalled when it has to
+   handle an unusually large object.  It now shows the throughput as
+   well.
+   (merge bae60ba7e9 sg/unpack-progress-throughput later to maint).
+
+ * The sequencer machinery compared the HEAD and the state it is
+   attempting to commit to decide if the result would be a no-op
+   commit, even when amending a commit, which was incorrect, and
+   has been corrected.
+
+ * The code to parse GPG output used to assume incorrectly that the
+   finterprint for the primary key would always be present for a valid
+   signature, which has been corrected.
+   (merge 67a6ea6300 hi/gpg-optional-pkfp-fix later to maint).
+
+ * "git submodule status" and "git submodule status --cached" show
+   different things, but the documentation did not cover them
+   correctly, which has been corrected.
+   (merge 8d483c8408 mg/doc-submodule-status-cached later to maint).
+
+ * "git reset --patch $object" without any pathspec should allow a
+   tree object to be given, but incorrectly required a committish,
+   which has been corrected.
+
+ * "git submodule status" that is run from a subdirectory of the
+   superproject did not work well, which has been corrected.
+   (merge 1f3aea22c7 mg/submodule-status-from-a-subdirectory later to maint).
+
+ * The revision walking machinery uses resources like per-object flag
+   bits that need to be reset before a new iteration of walking
+   begins, but the resources related to topological walk were not
+   cleared correctly, which has been corrected.
+   (merge 0aa0c2b2ec mh/clear-topo-walk-upon-reset later to maint).
+
+ * TravisCI update.
+   (merge 176441bfb5 sg/osx-force-gcc-9 later to maint).
+
+ * While running "revert" or "cherry-pick --edit" for multiple
+   commits, a recent regression incorrectly detected "nothing to
+   commit, working tree clean", instead of replaying the commits,
+   which has been corrected.
+   (merge befd4f6a81 sg/assume-no-todo-update-in-cherry-pick later to maint).
+
+ * Work around a issue where a FD that is left open when spawning a
+   child process and is kept open in the child can interfere with the
+   operation in the parent process on Windows.
+
+ * One kind of progress messages were always given during commit-graph
+   generation, instead of following the "if it takes more than two
+   seconds, show progress" pattern, which has been corrected.
+
+ * "git rebase" did not work well when format.useAutoBase
+   configuration variable is set, which has been corrected.
+
+ * The "diff" machinery learned not to lose added/removed blank lines
+   in the context when --ignore-blank-lines and --function-context are
+   used at the same time.
+   (merge 0bb313a552 rs/xdiff-ignore-ws-w-func-context later to maint).
+
+ * The test on "fast-import" used to get stuck when "fast-import" died
+   in the middle.
+   (merge 0d9b0d7885 sg/t9300-robustify later to maint).
+
+ * "git format-patch" can take a set of configured format.notes values
+   to specify which notes refs to use in the log message part of the
+   output.  The behaviour of this was not consistent with multiple
+   --notes command line options, which has been corrected.
+   (merge e0f9095aaa dl/format-patch-notes-config-fixup later to maint).
+
+ * "git p4" used to ignore lfs.storage configuration variable, which
+   has been corrected.
+   (merge ea94b16fb8 rb/p4-lfs later to maint).
+
+ * Assorted fixes to the directory traversal API.
+   (merge 6836d2fe06 en/fill-directory-fixes later to maint).
+
+ * Forbid pathnames that the platform's filesystem cannot represent on
+   MinGW.
+   (merge 4dc42c6c18 js/mingw-reserved-filenames later to maint).
+
+ * "git rebase --signoff" stopped working when the command was written
+   in C, which has been corrected.
+   (merge 4fe7e43c53 en/rebase-signoff-fix later to maint).
+
+ * An earlier update to Git for Windows declared that a tree object is
+   invalid if it has a path component with backslash in it, which was
+   overly strict, which has been corrected.  The only protection the
+   Windows users need is to prevent such path (or any path that their
+   filesystem cannot check out) from entering the index.
+   (merge 224c7d70fa js/mingw-loosen-overstrict-tree-entry-checks later to maint).
+
+ * The code to write split commit-graph file(s) upon fetching computed
+   bogus value for the parameter used in splitting the resulting
+   files, which has been corrected.
+   (merge 63020f175f ds/commit-graph-set-size-mult later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 80736d7c5e jc/am-show-current-patch-docfix later to maint).
+   (merge 8b656572ca sg/commit-graph-usage-fix later to maint).
+   (merge 6c02042139 mr/clone-dir-exists-to-path-exists later to maint).
+   (merge 44ae131e38 sg/blame-indent-heuristics-is-now-the-default later to maint).
+   (merge 0115e5d929 dl/doc-diff-no-index-implies-exit-code later to maint).
+   (merge 270de6acbe en/t6024-style later to maint).
+   (merge 14c4776d75 ns/test-desc-typofix later to maint).
+   (merge 68d40f30c4 dj/typofix-merge-strat later to maint).
+   (merge f66e0401ab jk/optim-in-pack-idx-conversion later to maint).
+   (merge 169bed7421 rs/parse-options-dup-null-fix later to maint).
+   (merge 51bd6be32d rs/use-copy-array-in-mingw-shell-command-preparation later to maint).
+   (merge b018719927 ma/t7004 later to maint).
+   (merge 932757b0cc ar/install-doc-update-cmds-needing-the-shell later to maint).
+   (merge 46efd28be1 ep/guard-kset-tar-headers later to maint).
+   (merge 9e5afdf997 ec/fetch-mark-common-refs-trace2 later to maint).
+   (merge f0e58b3fe8 pb/submodule-update-fetches later to maint).
+   (merge 2a02262078 dl/t5520-cleanup later to maint).
+   (merge a4fb016ba1 js/pkt-line-h-typofix later to maint).
+   (merge 54a7a64613 rs/simplify-prepare-cmd later to maint).
+   (merge 3eae30e464 jk/lore-is-the-archive later to maint).
+   (merge 14b7664df8 dl/lore-is-the-archive later to maint).
+   (merge 0e40a73a4c po/bundle-doc-clonable later to maint).
+   (merge e714b898c6 as/t7812-missing-redirects-fix later to maint).
+   (merge 528d9e6d01 jk/perf-wo-git-dot-pm later to maint).
+   (merge fc42f20e24 sg/test-squelch-noise-in-commit-bulk later to maint).
+   (merge c64368e3a2 bc/t9001-zsh-in-posix-emulation-mode later to maint).
+   (merge 11de8dd7ef dr/branch-usage-casefix later to maint).
+   (merge e05e8cf074 rs/archive-zip-code-cleanup later to maint).
+   (merge 147ee35558 rs/commit-export-env-simplify later to maint).
+   (merge 4507ecc771 rs/patch-id-use-oid-to-hex later to maint).
+   (merge 51a0a4ed95 mr/bisect-use-after-free later to maint).
+   (merge cc2bd5c45d pb/submodule-doc-xref later to maint).
+   (merge df5be01669 ja/doc-markup-cleanup later to maint).
+   (merge 7c5cea7242 mr/bisect-save-pointer-to-const-string later to maint).
+   (merge 20a67e8ce9 js/use-test-tool-on-path later to maint).
+   (merge 4e61b2214d ew/packfile-syscall-optim later to maint).
+   (merge ace0f86c7f pb/clarify-line-log-doc later to maint).
+   (merge 763a59e71c en/merge-recursive-oid-eq-simplify later to maint).
+   (merge 4e2c4c0d4f do/gitweb-typofix-in-comments later to maint).
+   (merge 421c0ffb02 jb/doc-multi-pack-idx-fix later to maint).
+   (merge f8740c586b pm/am-in-body-header-doc-update later to maint).
+   (merge 5814d44d9b tm/doc-submodule-absorb-fix later to maint).
diff --git a/Documentation/RelNotes/2.25.1.txt b/Documentation/RelNotes/2.25.1.txt
new file mode 100644
index 0000000000..cd869b02bb
--- /dev/null
+++ b/Documentation/RelNotes/2.25.1.txt
@@ -0,0 +1,55 @@
+Git 2.25.1 Release Notes
+========================
+
+Fixes since v2.25
+-----------------
+
+ * "git commit" gives output similar to "git status" when there is
+   nothing to commit, but without honoring the advise.statusHints
+   configuration variable, which has been corrected.
+
+ * has_object_file() said "no" given an object registered to the
+   system via pretend_object_file(), making it inconsistent with
+   read_object_file(), causing lazy fetch to attempt fetching an
+   empty tree from promisor remotes.
+
+ * The code that tries to skip over the entries for the paths in a
+   single directory using the cache-tree was not careful enough
+   against corrupt index file.
+
+ * Complete an update to tutorial that encourages "git switch" over
+   "git checkout" that was done only half-way.
+
+ * Reduce unnecessary round-trip when running "ls-remote" over the
+   stateless RPC mechanism.
+
+ * "git restore --staged" did not correctly update the cache-tree
+   structure, resulting in bogus trees to be written afterwards, which
+   has been corrected.
+
+ * The code recently added to move to the entry beyond the ones in the
+   same directory in the index in the sparse-cone mode did not count
+   the number of entries to skip over incorrectly, which has been
+   corrected.
+
+ * Work around test breakages caused by custom regex engine used in
+   libasan, when address sanitizer is used with more recent versions
+   of gcc and clang.
+
+ * "git fetch --refmap=" option has got a better documentation.
+
+ * Corner case bugs in "git clean" that stems from a (necessarily for
+   performance reasons) awkward calling convention in the directory
+   enumeration API has been corrected.
+
+ * "git grep --no-index" should not get affected by the contents of
+   the .gitmodules file but when "--recurse-submodules" is given or
+   the "submodule.recurse" variable is set, it did.  Now these
+   settings are ignored in the "--no-index" mode.
+
+ * Technical details of the bundle format has been documented.
+
+ * Unhelpful warning messages during documentation build have been
+   squelched.
+
+Also contains various documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.25.2.txt b/Documentation/RelNotes/2.25.2.txt
new file mode 100644
index 0000000000..303c53a17f
--- /dev/null
+++ b/Documentation/RelNotes/2.25.2.txt
@@ -0,0 +1,60 @@
+Git 2.25.2 Release Notes
+========================
+
+Fixes since v2.25.1
+-------------------
+
+ * Minor bugfixes to "git add -i" that has recently been rewritten in C.
+
+ * An earlier update to show the location of working tree in the error
+   message did not consider the possibility that a git command may be
+   run in a bare repository, which has been corrected.
+
+ * The "--recurse-submodules" option of various subcommands did not
+   work well when run in an alternate worktree, which has been
+   corrected.
+
+ * Running "git rm" on a submodule failed unnecessarily when
+   .gitmodules is only cache-dirty, which has been corrected.
+
+ * "git rebase -i" identifies existing commits in its todo file with
+   their abbreviated object name, which could become ambigous as it
+   goes to create new commits, and has a mechanism to avoid ambiguity
+   in the main part of its execution.  A few other cases however were
+   not covered by the protection against ambiguity, which has been
+   corrected.
+
+ * The index-pack code now diagnoses a bad input packstream that
+   records the same object twice when it is used as delta base; the
+   code used to declare a software bug when encountering such an
+   input, but it is an input error.
+
+ * The code to automatically shrink the fan-out in the notes tree had
+   an off-by-one bug, which has been killed.
+
+ * "git check-ignore" did not work when the given path is explicitly
+   marked as not ignored with a negative entry in the .gitignore file.
+
+ * The merge-recursive machinery failed to refresh the cache entry for
+   a merge result in a couple of places, resulting in an unnecessary
+   merge failure, which has been fixed.
+
+ * Fix for a bug revealed by a recent change to make the protocol v2
+   the default.
+
+ * "git merge signed-tag" while lacking the public key started to say
+   "No signature", which was utterly wrong.  This regression has been
+   reverted.
+
+ * MinGW's poll() emulation has been improved.
+
+ * "git show" and others gave an object name in raw format in its
+   error output, which has been corrected to give it in hex.
+
+ * Both "git ls-remote -h" and "git grep -h" give short usage help,
+   like any other Git subcommand, but it is not unreasonable to expect
+   that the former would behave the same as "git ls-remote --head"
+   (there is no other sensible behaviour for the latter).  The
+   documentation has been updated in an attempt to clarify this.
+
+Also contains various documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.25.3.txt b/Documentation/RelNotes/2.25.3.txt
new file mode 100644
index 0000000000..15f7f21f10
--- /dev/null
+++ b/Documentation/RelNotes/2.25.3.txt
@@ -0,0 +1,5 @@
+Git v2.25.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.25.4.txt b/Documentation/RelNotes/2.25.4.txt
new file mode 100644
index 0000000000..0dbb5daeec
--- /dev/null
+++ b/Documentation/RelNotes/2.25.4.txt
@@ -0,0 +1,5 @@
+Git v2.25.4 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.25.5.txt b/Documentation/RelNotes/2.25.5.txt
new file mode 100644
index 0000000000..fcb9566b15
--- /dev/null
+++ b/Documentation/RelNotes/2.25.5.txt
@@ -0,0 +1,7 @@
+Git v2.25.5 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5,
+v2.19.6, v2.20.5, v2.21.4, v2.22.5, v2.23.4 and v2.24.4 to address
+the security issue CVE-2021-21300; see the release notes for
+these versions for details.
diff --git a/Documentation/RelNotes/2.26.0.txt b/Documentation/RelNotes/2.26.0.txt
new file mode 100644
index 0000000000..3a7a734c26
--- /dev/null
+++ b/Documentation/RelNotes/2.26.0.txt
@@ -0,0 +1,341 @@
+Git 2.26 Release Notes
+======================
+
+Updates since v2.25
+-------------------
+
+Backward compatibility notes
+
+ * "git rebase" uses a different backend that is based on the 'merge'
+   machinery by default.  There are a few known differences in the
+   behaviour from the traditional machinery based on patch+apply.
+
+   If your workflow is negatively affected by this change, please
+   report it to git@xxxxxxxxxxxxxxx so that we can take a look into
+   it.  After doing so, you can set the 'rebase.backend' configuration
+   variable to 'apply', in order to use the old default behaviour in
+   the meantime.
+
+
+UI, Workflows & Features
+
+ * Sample credential helper for using .netrc has been updated to work
+   out of the box.
+
+ * gpg.minTrustLevel configuration variable has been introduced to
+   tell various signature verification codepaths the required minimum
+   trust level.
+
+ * The command line completion (in contrib/) learned to complete
+   subcommands and arguments to "git worktree".
+
+ * Disambiguation logic to tell revisions and pathspec apart has been
+   tweaked so that backslash-escaped glob special characters do not
+   count in the "wildcards are pathspec" rule.
+
+ * One effect of specifying where the GIT_DIR is (either with the
+   environment variable, or with the "git --git-dir=<where> cmd"
+   option) is to disable the repository discovery.  This has been
+   placed a bit more stress in the documentation, as new users often
+   get confused.
+
+ * Two help messages given when "git add" notices the user gave it
+   nothing to add have been updated to use advise() API.
+
+ * A new version of fsmonitor-watchman hook has been introduced, to
+   avoid races.
+
+ * "git config" learned to show in which "scope", in addition to in
+   which file, each config setting comes from.
+
+ * The basic 7 colors learned the brighter counterparts
+   (e.g. "brightred").
+
+ * "git sparse-checkout" learned a new "add" subcommand.
+
+ * A configuration element used for credential subsystem can now use
+   wildcard pattern to specify for which set of URLs the entry
+   applies.
+
+ * "git clone --recurse-submodules --single-branch" now uses the same
+   single-branch option when cloning the submodules.
+
+ * "git rm" and "git stash" learns the new "--pathspec-from-file"
+   option.
+
+ * "git am --show-current-patch" is a way to show the piece of e-mail
+   for the stopped step, which is not suitable to directly feed "git
+   apply" (it is designed to be a good "git am" input).  It learned a
+   new option to show only the patch part.
+
+ * Handling of conflicting renames in merge-recursive have further
+   been made consistent with how existing codepaths try to mimic what
+   is done to add/add conflicts.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Tell .editorconfig that in this project, *.txt files are indented
+   with tabs.
+
+ * The test-lint machinery knew to check "VAR=VAL shell_function"
+   construct, but did not check "VAR= shell_function", which has been
+   corrected.
+
+ * Replace "git config --bool" calls with "git config --type=bool" in
+   sample templates.
+
+ * The effort to move "git-add--interactive" to C continues.
+
+ * Improve error message generation for "git submodule add".
+
+ * Preparation of test scripts for the day when the object names will
+   use SHA-256 continues.
+
+ * Warn programmers about pretend_object_file() that allows the code
+   to tentatively use in-core objects.
+
+ * The way "git pack-objects" reuses objects stored in existing pack
+   to generate its result has been improved.
+
+ * The transport protocol version 2 becomes the default one.
+
+ * Traditionally, we avoided threaded grep while searching in objects
+   (as opposed to files in the working tree) as accesses to the object
+   layer is not thread-safe.  This limitation is getting lifted.
+
+ * "git rebase -i" (and friends) used to unnecessarily check out the
+   tip of the branch to be rebased, which has been corrected.
+
+ * A low-level API function get_oid(), that accepts various ways to
+   name an object, used to issue end-user facing error messages
+   without l10n, which has been updated to be translatable.
+
+ * Unneeded connectivity check is now disabled in a partial clone when
+   fetching into it.
+
+ * Some rough edges in the sparse-checkout feature, especially around
+   the cone mode, have been cleaned up.
+
+ * The diff-* plumbing family of subcommands now pay attention to the
+   diff.wsErrorHighlight configuration, which has been ignored before;
+   this allows "git add -p" to also show the whitespace problems to
+   the end user.
+
+ * Some codepaths were given a repository instance as a parameter to
+   work in the repository, but passed the_repository instance to its
+   callees, which has been cleaned up (somewhat).
+
+ * Memory footprint and performance of "git name-rev" has been
+   improved.
+
+ * The object reachability bitmap machinery and the partial cloning
+   machinery were not prepared to work well together, because some
+   object-filtering criteria that partial clones use inherently rely
+   on object traversal, but the bitmap machinery is an optimization
+   to bypass that object traversal.  There however are some cases
+   where they can work together, and they were taught about them.
+
+ * "git rebase" has learned to use the merge backend (i.e. the
+   machinery that drives "rebase -i") by default, while allowing
+   "--apply" option to use the "apply" backend (e.g. the moral
+   equivalent of "format-patch piped to am").  The rebase.backend
+   configuration variable can be set to customize.
+
+ * Underlying machinery of "git bisect--helper" is being refactored
+   into pieces that are more easily reused.
+
+
+Fixes since v2.25
+-----------------
+
+ * "git commit" gives output similar to "git status" when there is
+   nothing to commit, but without honoring the advise.statusHints
+   configuration variable, which has been corrected.
+
+ * has_object_file() said "no" given an object registered to the
+   system via pretend_object_file(), making it inconsistent with
+   read_object_file(), causing lazy fetch to attempt fetching an
+   empty tree from promisor remotes.
+
+ * Complete an update to tutorial that encourages "git switch" over
+   "git checkout" that was done only half-way.
+
+ * C pedantry ;-) fix.
+
+ * The code that tries to skip over the entries for the paths in a
+   single directory using the cache-tree was not careful enough
+   against corrupt index file.
+
+ * Reduce unnecessary round-trip when running "ls-remote" over the
+   stateless RPC mechanism.
+
+ * "git restore --staged" did not correctly update the cache-tree
+   structure, resulting in bogus trees to be written afterwards, which
+   has been corrected.
+
+ * The code recently added to move to the entry beyond the ones in the
+   same directory in the index in the sparse-cone mode did not count
+   the number of entries to skip over incorrectly, which has been
+   corrected.
+
+ * Rendering by "git log --graph" of ancestry lines leading to a merge
+   commit were made suboptimal to waste vertical space a bit with a
+   recent update, which has been corrected.
+
+ * Work around test breakages caused by custom regex engine used in
+   libasan, when address sanitizer is used with more recent versions
+   of gcc and clang.
+
+ * Minor bugfixes to "git add -i" that has recently been rewritten in C.
+
+ * "git fetch --refmap=" option has got a better documentation.
+
+ * "git checkout X" did not correctly fail when X is not a local
+   branch but could name more than one remote-tracking branches
+   (i.e. to be dwimmed as the starting point to create a corresponding
+   local branch), which has been corrected.
+   (merge fa74180d08 am/checkout-file-and-ref-ref-ambiguity later to maint).
+
+ * Corner case bugs in "git clean" that stems from a (necessarily for
+   performance reasons) awkward calling convention in the directory
+   enumeration API has been corrected.
+
+ * A fetch that is told to recursively fetch updates in submodules
+   inevitably produces reams of output, and it becomes hard to spot
+   error messages.  The command has been taught to enumerate
+   submodules that had errors at the end of the operation.
+   (merge 0222540827 es/fetch-show-failed-submodules-atend later to maint).
+
+ * The "--recurse-submodules" option of various subcommands did not
+   work well when run in an alternate worktree, which has been
+   corrected.
+
+ * Futureproofing a test not to depend on the current implementation
+   detail.
+
+ * Running "git rm" on a submodule failed unnecessarily when
+   .gitmodules is only cache-dirty, which has been corrected.
+
+ * C pedantry ;-) fix.
+
+ * "git grep --no-index" should not get affected by the contents of
+   the .gitmodules file but when "--recurse-submodules" is given or
+   the "submodule.recurse" variable is set, it did.  Now these
+   settings are ignored in the "--no-index" mode.
+
+ * Technical details of the bundle format has been documented.
+
+ * Unhelpful warning messages during documentation build have been squelched.
+
+ * "git rebase -i" identifies existing commits in its todo file with
+   their abbreviated object name, which could become ambiguous as it
+   goes to create new commits, and has a mechanism to avoid ambiguity
+   in the main part of its execution.  A few other cases however were
+   not covered by the protection against ambiguity, which has been
+   corrected.
+
+ * Allow the rebase.missingCommitsCheck configuration to kick in when
+   "rebase --edit-todo" and "rebase --continue" restarts the procedure.
+   (merge 5a5445d878 ag/edit-todo-drop-check later to maint).
+
+ * The way "git submodule status" reports an initialized but not yet
+   populated submodule has not been reimplemented correctly when a
+   part of the "git submodule" command was rewritten in C, which has
+   been corrected.
+   (merge f38c92452d pk/status-of-uncloned-submodule later to maint).
+
+ * The code to automatically shrink the fan-out in the notes tree had
+   an off-by-one bug, which has been killed.
+
+ * The index-pack code now diagnoses a bad input packstream that
+   records the same object twice when it is used as delta base; the
+   code used to declare a software bug when encountering such an
+   input, but it is an input error.
+
+
+ * The code to compute the commit-graph has been taught to use a more
+   robust way to tell if two object directories refer to the same
+   thing.
+   (merge a7df60cac8 tb/commit-graph-object-dir later to maint).
+
+ * "git remote rename X Y" needs to adjust configuration variables
+   (e.g. branch.<name>.remote) whose value used to be X to Y.
+   branch.<name>.pushRemote is now also updated.
+
+ * Update to doc-diff.
+
+ * Doc markup fix.
+
+ * "git check-ignore" did not work when the given path is explicitly
+   marked as not ignored with a negative entry in the .gitignore file.
+
+ * The merge-recursive machinery failed to refresh the cache entry for
+   a merge result in a couple of places, resulting in an unnecessary
+   merge failure, which has been fixed.
+
+ * Fix for a bug revealed by a recent change to make the protocol v2
+   the default.
+
+ * In rare cases "git worktree add <path>" could think that <path>
+   was already a registered worktree even when it wasn't and refuse
+   to add the new worktree. This has been corrected.
+   (merge bb69b3b009 es/worktree-avoid-duplication-fix later to maint).
+
+ * "git push" should stop from updating a branch that is checked out
+   when receive.denyCurrentBranch configuration is set, but it failed
+   to pay attention to checkouts in secondary worktrees.  This has
+   been corrected.
+   (merge 4d864895a2 hv/receive-denycurrent-everywhere later to maint).
+
+ * "git rebase BASE BRANCH" rebased/updated the tip of BRANCH and
+   checked it out, even when the BRANCH is checked out in a different
+   worktree.  This has been corrected.
+   (merge b5cabb4a96 es/do-not-let-rebase-switch-to-protected-branch later to maint).
+
+ * "git describe" in a repository with multiple root commits sometimes
+   gave up looking for the best tag to describe a given commit with
+   too early, which has been adjusted.
+
+ * "git merge signed-tag" while lacking the public key started to say
+   "No signature", which was utterly wrong.  This regression has been
+   reverted.
+
+ * MinGW's poll() emulation has been improved.
+
+ * "git show" and others gave an object name in raw format in its
+   error output, which has been corrected to give it in hex.
+
+ * "git fetch" over HTTP walker protocol did not show any progress
+   output.  We inherently do not know how much work remains, but still
+   we can show something not to bore users.
+   (merge 7655b4119d rs/show-progress-in-dumb-http-fetch later to maint).
+
+ * Both "git ls-remote -h" and "git grep -h" give short usage help,
+   like any other Git subcommand, but it is not unreasonable to expect
+   that the former would behave the same as "git ls-remote --head"
+   (there is no other sensible behaviour for the latter).  The
+   documentation has been updated in an attempt to clarify this.
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge d0d0a357a1 am/update-pathspec-f-f-tests later to maint).
+   (merge f94f7bd00d am/test-pathspec-f-f-error-cases later to maint).
+   (merge c513a958b6 ss/t6025-modernize later to maint).
+   (merge b441717256 dl/test-must-fail-fixes later to maint).
+   (merge d031049da3 mt/sparse-checkout-doc-update later to maint).
+   (merge 145136a95a jc/skip-prefix later to maint).
+   (merge 5290d45134 jk/alloc-cleanups later to maint).
+   (merge 7a9f8ca805 rs/parse-options-concat-dup later to maint).
+   (merge 517b60564e rs/strbuf-insertstr later to maint).
+   (merge f696a2b1c8 jk/mailinfo-cleanup later to maint).
+   (merge de26f02db1 js/test-avoid-pipe later to maint).
+   (merge a2dc43414c es/doc-mentoring later to maint).
+   (merge 02bbbe9df9 es/worktree-cleanup later to maint).
+   (merge 2ce6d075fa rs/micro-cleanups later to maint).
+   (merge 27f182b3fc rs/blame-typefix-for-fingerprint later to maint).
+   (merge 3c29e21eb0 ma/test-cleanup later to maint).
+   (merge 240fc04f81 ag/rebase-remove-redundant-code later to maint).
+   (merge d68ce906c7 rs/commit-graph-code-simplification later to maint).
+   (merge a51d9e8f07 rj/t1050-use-test-path-is-file later to maint).
+   (merge fd0bc17557 kk/complete-diff-color-moved later to maint).
+   (merge 65bf820d0e en/test-cleanup later to maint).
diff --git a/Documentation/RelNotes/2.26.1.txt b/Documentation/RelNotes/2.26.1.txt
new file mode 100644
index 0000000000..1b4ecb3fdc
--- /dev/null
+++ b/Documentation/RelNotes/2.26.1.txt
@@ -0,0 +1,5 @@
+Git v2.26.1 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.4; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.26.2.txt b/Documentation/RelNotes/2.26.2.txt
new file mode 100644
index 0000000000..d434d0c695
--- /dev/null
+++ b/Documentation/RelNotes/2.26.2.txt
@@ -0,0 +1,5 @@
+Git v2.26.2 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.17.5; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.26.3.txt b/Documentation/RelNotes/2.26.3.txt
new file mode 100644
index 0000000000..4111c38f0a
--- /dev/null
+++ b/Documentation/RelNotes/2.26.3.txt
@@ -0,0 +1,7 @@
+Git v2.26.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5,
+v2.19.6, v2.20.5, v2.21.4, v2.22.5, v2.23.4, v2.24.4 and v2.25.5
+to address the security issue CVE-2021-21300; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.27.0.txt b/Documentation/RelNotes/2.27.0.txt
new file mode 100644
index 0000000000..15518d06c1
--- /dev/null
+++ b/Documentation/RelNotes/2.27.0.txt
@@ -0,0 +1,525 @@
+Git 2.27 Release Notes
+======================
+
+Updates since v2.26
+-------------------
+
+Backward compatibility notes
+
+ * When "git describe C" finds that commit C is pointed by a signed or
+   annotated tag, which records T as its tagname in the object, the
+   command gives T as its answer.  Even if the user renames or moves
+   such a tag from its natural location in the "refs/tags/" hierarchy,
+   "git describe C" would still give T as the answer, but in such a
+   case "git show T^0" would no longer work as expected.  There may be
+   nothing at "refs/tags/T" or even worse there may be a different tag
+   instead.
+
+   Starting from this version, "git describe" will always use the
+   "long" version, as if the "--long" option were given, when giving
+   its output based on such a misplaced tag to work around the problem.
+
+ * "git pull" issues a warning message until the pull.rebase
+   configuration variable is explicitly given, which some existing
+   users may find annoying---those who prefer not to rebase need to
+   set the variable to false to squelch the warning.
+
+ * The transport protocol version 2, which was promoted to the default
+   in Git 2.26 release, turned out to have some remaining rough edges,
+   so it has been demoted from the default.
+
+
+UI, Workflows & Features
+
+ * A handful of options to configure SSL when talking to proxies have
+   been added.
+
+ * Smudge/clean conversion filters are now given more information
+   (e.g. the object of the tree-ish in which the blob being converted
+   appears, in addition to its path, which has already been given).
+
+ * When "git describe C" finds an annotated tag with tagname A to be
+   the best name to explain commit C, and the tag is stored in a
+   "wrong" place in the refs/tags hierarchy, e.g. refs/tags/B, the
+   command gave a warning message but used A (not B) to describe C.
+   If C is exactly at the tag, the describe output would be "A", but
+   "git rev-parse A^0" would not be equal as "git rev-parse C^0".  The
+   behavior of the command has been changed to use the "long" form
+   i.e. A-0-gOBJECTNAME, which is correctly interpreted by rev-parse.
+
+ * "git pull" learned to warn when no pull.rebase configuration
+   exists, and neither --[no-]rebase nor --ff-only is given (which
+   would result a merge).
+
+ * "git p4" learned four new hooks and also "--no-verify" option to
+   bypass them (and the existing "p4-pre-submit" hook).
+
+ * "git pull" shares many options with underlying "git fetch", but
+   some of them were not documented and some of those that would make
+   sense to pass down were not passed down.
+
+ * "git rebase" learned the "--no-gpg-sign" option to countermand
+   commit.gpgSign the user may have.
+
+ * The output from "git format-patch" uses RFC 2047 encoding for
+   non-ASCII letters on From: and Subject: headers, so that it can
+   directly be fed to e-mail programs.  A new option has been added
+   to produce these headers in raw.
+
+ * "git log" learned "--show-pulls" that helps pathspec limited
+   history views; a merge commit that takes the whole change from a
+   side branch, which is normally omitted from the output, is shown
+   in addition to the commits that introduce real changes.
+
+ * The interactive input from various codepaths are consolidated and
+   any prompt possibly issued earlier are fflush()ed before we read.
+
+ * Allow "git rebase" to reapply all local commits, even if the may be
+   already in the upstream, without checking first.
+
+ * The 'pack.useSparse' configuration variable now defaults to 'true',
+   enabling an optimization that has been experimental since Git 2.21.
+
+ * "git rebase" happens to call some hooks meant for "checkout" and
+   "commit" by this was not a designed behaviour than historical
+   accident.  This has been documented.
+
+ * "git merge" learns the "--autostash" option.
+
+ * "sparse-checkout" UI improvements.
+
+ * "git update-ref --stdin" learned a handful of new verbs to let the
+   user control ref update transactions more explicitly, which helps
+   as an ingredient to implement two-phase commit-style atomic
+   ref-updates across multiple repositories.
+
+ * "git commit-graph write" learned different ways to write out split
+   files.
+
+ * Introduce an extension to the commit-graph to make it efficient to
+   check for the paths that were modified at each commit using Bloom
+   filters.
+
+ * The approxidate parser learns to parse seconds with fraction and
+   ignore fractional part.
+
+ * The userdiff patterns for Markdown documents have been added.
+
+ * The sparse-checkout patterns have been forbidden from excluding all
+   paths, leaving an empty working tree, for a long time.  This
+   limitation has been lifted.
+
+ * "git restore --staged --worktree" now defaults to take the contents
+   out of "HEAD", instead of erring out.
+
+ * "git p4" learned to recover from a (broken) state where a directory
+   and a file are recorded at the same path in the Perforce repository
+   the same way as their clients do.
+
+ * "git multi-pack-index repack" has been taught to honor some
+   repack.* configuration variables.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The advise API has been revamped to allow more systematic enumeration of
+   advice knobs in the future.
+
+ * SHA-256 transition continues.
+
+ * The code to interface with GnuPG has been refactored.
+
+ * "git stash" has kept an escape hatch to use the scripted version
+   for a few releases, which got stale.  It has been removed.
+
+ * Enable tests that require GnuPG on Windows.
+
+ * Minor test usability improvement.
+
+ * Trace2 enhancement to allow logging of the environment variables.
+
+ * Test clean-up continues.
+
+ * Perf-test update.
+
+ * A Windows-specific test element has been made more robust against
+   misuse from both user's environment and programmer's errors.
+
+ * Various tests have been updated to work around issues found with
+   shell utilities that come with busybox etc.
+
+ * The config API made mixed uses of int and size_t types to represent
+   length of various pieces of text it parsed, which has been updated
+   to use the correct type (i.e. size_t) throughout.
+
+ * The "--decorate-refs" and "--decorate-refs-exclude" options "git
+   log" takes have learned a companion configuration variable
+   log.excludeDecoration that sits at the lowest priority in the
+   family.
+
+ * A new CI job to build and run test suite on linux with musl libc
+   has been added.
+
+ * Update the CI configuration to use GitHub Actions, retiring the one
+   based on Azure Pipelines.
+
+ * The directory traversal code had redundant recursive calls which
+   made its performance characteristics exponential with respect to
+   the depth of the tree, which was corrected.
+
+ * "git blame" learns to take advantage of the "changed-paths" Bloom
+   filter stored in the commit-graph file.
+
+ * The "bugreport" tool has been added.
+
+ * The object walk with object filter "--filter=tree:0" can now take
+   advantage of the pack bitmap when available.
+
+ * Instead of always building all branches at GitHub via Actions,
+   users can specify which branches to build.
+
+ * Codepaths that show progress meter have been taught to also use the
+   start_progress() and the stop_progress() calls as a "region" to be
+   traced.
+
+ * Instead of downloading Windows SDK for CI jobs for windows builds
+   from an external site (wingit.blob.core.windows.net), use the one
+   created in the windows-build job, to work around quota issues at
+   the external site.
+
+
+Fixes since v2.26
+-----------------
+
+ * The real_path() convenience function can easily be misused; with a
+   bit of code refactoring in the callers' side, its use has been
+   eliminated.
+   (merge 49d3c4b481 am/real-path-fix later to maint).
+
+ * Update "git p4" to work with Python 3.
+   (merge 6bb40ed20a yz/p4-py3 later to maint).
+
+ * The mechanism to prevent "git commit" from making an empty commit
+   or amending during an interrupted cherry-pick was broken during the
+   rewrite of "git rebase" in C, which has been corrected.
+   (merge 430b75f720 pw/advise-rebase-skip later to maint).
+
+ * Fix "git checkout --recurse-submodules" of a nested submodule
+   hierarchy.
+   (merge 846f34d351 pb/recurse-submodules-fix later to maint).
+
+ * The "--fork-point" mode of "git rebase" regressed when the command
+   was rewritten in C back in 2.20 era, which has been corrected.
+   (merge f08132f889 at/rebase-fork-point-regression-fix later to maint).
+
+ * The import-tars importer (in contrib/fast-import/) used to create
+   phony files at the top-level of the repository when the archive
+   contains global PAX headers, which made its own logic to detect and
+   omit the common leading directory ineffective, which has been
+   corrected.
+   (merge c839fcff65 js/import-tars-do-not-make-phony-files-from-pax-headers later to maint).
+
+ * Simplify the commit ancestry connectedness check in a partial clone
+   repository in which "promised" objects are assumed to be obtainable
+   lazily on-demand from promisor remote repositories.
+   (merge 2b98478c6f jt/connectivity-check-optim-in-partial-clone later to maint).
+
+ * The server-end of the v2 protocol to serve "git clone" and "git
+   fetch" was not prepared to see a delim packets at unexpected
+   places, which led to a crash.
+   (merge cacae4329f jk/harden-protocol-v2-delim-handling later to maint).
+
+ * When fed a midx that records no objects, some codepaths tried to
+   loop from 0 through (num_objects-1), which, due to integer
+   arithmetic wrapping around, made it nonsense operation with out of
+   bounds array accesses.  The code has been corrected to reject such
+   an midx file.
+   (merge 796d61cdc0 dr/midx-avoid-int-underflow later to maint).
+
+ * Utitiles run via the run_command() API were not spawned correctly
+   on Cygwin, when the paths to them are given as a full path with
+   backslashes.
+   (merge 05ac8582bc ak/run-command-on-cygwin-fix later to maint).
+
+ * "git pull --rebase" tried to run a rebase even after noticing that
+   the pull results in a fast-forward and no rebase is needed nor
+   sensible, for the past few years due to a mistake nobody noticed.
+   (merge fbae70ddc6 en/pull-do-not-rebase-after-fast-forwarding later to maint).
+
+ * "git rebase" with the merge backend did not work well when the
+   rebase.abbreviateCommands configuration was set.
+   (merge de9f1d3ef4 ag/rebase-merge-allow-ff-under-abbrev-command later to maint).
+
+ * The logic to auto-follow tags by "git clone --single-branch" was
+   not careful to avoid lazy-fetching unnecessary tags, which has been
+   corrected.
+   (merge 167a575e2d jk/use-quick-lookup-in-clone-for-tag-following later to maint).
+
+ * "git rebase -i" did not leave the reflog entries correctly.
+   (merge 1f6965f994 en/sequencer-reflog-action later to maint).
+
+ * The more aggressive updates to remote-tracking branches we had for
+   the past 7 years or so were not reflected in the documentation,
+   which has been corrected.
+   (merge a44088435c pb/pull-fetch-doc later to maint).
+
+ * We've left the command line parsing of "git log :/a/b/" broken for
+   about a full year without anybody noticing, which has been
+   corrected.
+   (merge 0220461071 jc/missing-ref-store-fix later to maint).
+
+ * Misc fixes for Windows.
+   (merge 3efc128cd5 js/mingw-fixes later to maint).
+
+ * "git rebase" (again) learns to honor "--no-keep-empty", which lets
+   the user to discard commits that are empty from the beginning (as
+   opposed to the ones that become empty because of rebasing).  The
+   interactive rebase also marks commits that are empty in the todo.
+   (merge 50ed76148a en/rebase-no-keep-empty later to maint).
+
+ * Parsing the host part out of URL for the credential helper has been corrected.
+   (merge 4c5971e18a jk/credential-parsing-end-of-host-in-URL later to maint).
+
+ * Document the recommended way to abort a failing test early (e.g. by
+   exiting a loop), which is to say "return 1".
+   (merge 7cc112dc95 jc/doc-test-leaving-early later to maint).
+
+ * The code that refreshes the last access and modified time of
+   on-disk packfiles and loose object files have been updated.
+   (merge 312cd76130 lr/freshen-file-fix later to maint).
+
+ * Validation of push certificate has been made more robust against
+   timing attacks.
+   (merge 719483e547 bc/constant-memequal later to maint).
+
+ * The custom hash function used by "git fast-import" has been
+   replaced with the one from hashmap.c, which gave us a nice
+   performance boost.
+   (merge d8410a816b jk/fast-import-use-hashmap later to maint).
+
+ * The "git submodule" command did not initialize a few variables it
+   internally uses and was affected by variable settings leaked from
+   the environment.
+   (merge 65d100c4dd lx/submodule-clear-variables later to maint).
+
+ * Raise the minimum required version of docbook-xsl package to 1.74,
+   as 1.74.0 was from late 2008, which is more than 10 years old, and
+   drop compatibility cruft from our documentation suite.
+   (merge 3c255ad660 ma/doc-discard-docbook-xsl-1.73 later to maint).
+
+ * "git log" learns "--[no-]mailmap" as a synonym to "--[no-]use-mailmap"
+   (merge 88acccda38 jc/log-no-mailmap later to maint).
+
+ * "git commit-graph write --expire-time=<timestamp>" did not use the
+   given timestamp correctly, which has been corrected.
+   (merge b09b785c78 ds/commit-graph-expiry-fix later to maint).
+
+ * Tests update to use "test-chmtime" instead of "touch -t".
+   (merge e892a56845 ds/t5319-touch-fix later to maint).
+
+ * "git diff" in a partial clone learned to avoid lazy loading blob
+   objects in more casese when they are not needed.
+   (merge 95acf11a3d jt/avoid-prefetch-when-able-in-diff later to maint).
+
+ * "git push --atomic" used to show failures for refs that weren't
+   even pushed, which has been corrected.
+   (merge dfe1b7f19c jx/atomic-push later to maint).
+
+ * Code in builtin/*, i.e. those can only be called from within
+   built-in subcommands, that implements bulk of a couple of
+   subcommands have been moved to libgit.a so that they could be used
+   by others.
+   (merge 9460fd48b5 dl/libify-a-few later to maint).
+
+ * Allowing the user to split a patch hunk while "git stash -p" does
+   not work well; a band-aid has been added to make this (partially)
+   work better.
+
+ * "git diff-tree --pretty --notes" used to hit an assertion failure,
+   as it forgot to initialize the notes subsystem.
+   (merge 5778b22b3d tb/diff-tree-with-notes later to maint).
+
+ * "git range-diff" fixes.
+   (merge 8d1675eb7f vd/range-diff-with-custom-pretty-format-fix later to maint).
+
+ * "git grep" did not quote a path with unusual character like other
+   commands (like "git diff", "git status") do, but did quote when run
+   from a subdirectory, both of which has been corrected.
+   (merge 45115d8490 mt/grep-cquote-path later to maint).
+
+ * GNU/Hurd is also among the ones that need the fopen() wrapper.
+   (merge 274a1328fb jc/gnu-hurd-lets-fread-read-dirs later to maint).
+
+ * Those fetching over protocol v2 from linux-next and other kernel
+   repositories are reporting that v2 often fetches way too much than
+   needed.
+   (merge 11c7f2a30b jn/demote-proto2-from-default later to maint).
+
+ * The upload-pack protocol v2 gave up too early before finding a
+   common ancestor, resulting in a wasteful fetch from a fork of a
+   project.  This has been corrected to match the behaviour of v0
+   protocol.
+   (merge 2f0a093dd6 jt/v2-fetch-nego-fix later to maint).
+
+ * The build procedure did not use the libcurl library and its include
+   files correctly for a custom-built installation.
+   (merge 0573831950 jk/build-with-right-curl later to maint).
+
+ * Tighten "git mailinfo" to notice and error out when decoded result
+   contains NUL in it.
+   (merge 3919997447 dd/mailinfo-with-nul later to maint).
+
+ * Fix in-core inconsistency after fetching into a shallow repository
+   that broke the code to write out commit-graph.
+   (merge 37b9dcabfc tb/reset-shallow later to maint).
+
+ * The commit-graph code exhausted file descriptors easily when it
+   does not have to.
+   (merge c8828530b7 tb/commit-graph-fd-exhaustion-fix later to maint).
+
+ * The multi-pack-index left mmapped file descriptors open when it
+   does not have to.
+   (merge 6c7ff7cf7f ds/multi-pack-index later to maint).
+
+ * Recent update to Homebrew used by macOS folks breaks build by
+   moving gettext library and necessary headers.
+   (merge a0b3108618 ds/build-homebrew-gettext-fix later to maint).
+
+ * Incompatible options "--root" and "--fork-point" of "git rebase"
+   have been marked and documented as being incompatible.
+   (merge a35413c378 en/rebase-root-and-fork-point-are-incompatible later to maint).
+
+ * Error and verbose trace messages from "git push" did not redact
+   credential material embedded in URLs.
+   (merge d192fa5006 js/anonymise-push-url-in-errors later to maint).
+
+ * Update the parser used for credential.<URL>.<variable>
+   configuration, to handle <URL>s with '/' in them correctly.
+   (merge b44d0118ac bc/wildcard-credential later to maint).
+
+ * Recent updates broke parsing of "credential.<url>.<key>" where
+   <url> is not a full URL (e.g. [credential "https://";] helper = ...)
+   stopped working, which has been corrected.
+   (merge 9a121b0d22 js/partial-urlmatch-2.17 later to maint).
+   (merge cd93e6c029 js/partial-urlmatch later to maint).
+
+ * Some of the files commit-graph subsystem keeps on disk did not
+   correctly honor the core.sharedRepository settings and some were
+   left read-write.
+
+ * In error messages that "git switch" mentions its option to create a
+   new branch, "-b/-B" options were shown, where "-c/-C" options
+   should be, which has been corrected.
+   (merge 7c16ef7577 dl/switch-c-option-in-error-message later to maint).
+
+ * With the recent tightening of the code that is used to parse
+   various parts of a URL for use in the credential subsystem, a
+   hand-edited credential-store file causes the credential helper to
+   die, which is a bit too harsh to the users.  Demote the error
+   behaviour to just ignore and keep using well-formed lines instead.
+   (merge c03859a665 cb/credential-store-ignore-bogus-lines later to maint).
+
+ * The samples in the credential documentation has been updated to
+   make it clear that we depict what would appear in the .git/config
+   file, by adding appropriate quotes as needed..
+   (merge 177681a07e jk/credential-sample-update later to maint).
+
+ * "git branch" and other "for-each-ref" variants accepted multiple
+   --sort=<key> options in the increasing order of precedence, but it
+   had a few breakages around "--ignore-case" handling, and tie-breaking
+   with the refname, which have been fixed.
+   (merge 7c5045fc18 jk/for-each-ref-multi-key-sort-fix later to maint).
+
+ * The coding guideline for shell scripts instructed to refer to a
+   variable with dollar-sign inside arithmetic expansion to work
+   around a bug in old versions of dash, which is a thing of the past.
+   Now we are not forbidden from writing $((var+1)).
+   (merge 32b5fe7f0e jk/arith-expansion-coding-guidelines later to maint).
+
+ * The <stdlib.h> header on NetBSD brings in its own definition of
+   hmac() function (eek), which conflicts with our own and unrelated
+   function with the same name.  Our function has been renamed to work
+   around the issue.
+   (merge 3013118eb8 cb/avoid-colliding-with-netbsd-hmac later to maint).
+
+ * The basic test did not honor $TEST_SHELL_PATH setting, which has
+   been corrected.
+   (merge 0555e4af58 cb/t0000-use-the-configured-shell later to maint).
+
+ * Minor in-code comments and documentation updates around credential
+   API.
+   (merge 1aed817f99 cb/credential-doc-fixes later to maint).
+
+ * Teach "am", "commit", "merge" and "rebase", when they are run with
+   the "--quiet" option, to pass "--quiet" down to "gc --auto".
+   (merge 7c3e9e8cfb jc/auto-gc-quiet later to maint).
+
+ * The code to skip unmerged paths in the index when sparse checkout
+   is in use would have made out-of-bound access of the in-core index
+   when the last path was unmerged, which has been corrected.
+
+ * Serving a "git fetch" client over "git://" and "ssh://" protocols
+   using the on-wire protocol version 2 was buggy on the server end
+   when the client needs to make a follow-up request to
+   e.g. auto-follow tags.
+   (merge 08450ef791 cc/upload-pack-v2-fetch-fix later to maint).
+
+ * "git bisect replay" had trouble with input files when they used
+   CRLF line ending, which has been corrected.
+   (merge 6c722cbe5a cw/bisect-replay-with-dos later to maint).
+
+ * "rebase -i" segfaulted when rearranging a sequence that has a
+   fix-up that applies another fix-up (which may or may not be a
+   fix-up of yet another step).
+   (merge 02471e7e20 js/rebase-autosquash-double-fixup-fix later to maint).
+
+ * "git fsck" ensures that the paths recorded in tree objects are
+   sorted and without duplicates, but it failed to notice a case where
+   a blob is followed by entries that sort before a tree with the same
+   name.  This has been corrected.
+   (merge 9068cfb20f rs/fsck-duplicate-names-in-trees later to maint).
+
+ * Code clean-up by removing a compatibility implementation of a
+   function we no longer use.
+   (merge 84b0115f0d cb/no-more-gmtime later to maint).
+
+ * When a binary file gets modified and renamed on both sides of history
+   to different locations, both files would be written to the working
+   tree but both would have the contents from "ours".  This has been
+   corrected so that the path from each side gets their original content.
+
+ * Fix for a copy-and-paste error introduced during 2.20 era.
+   (merge e68a5272b1 ds/multi-pack-verify later to maint).
+
+ * Update an unconditional use of "grep -a" with a perl script in a test.
+   (merge 1eb7371236 dd/t5703-grep-a-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 564956f358 jc/maintain-doc later to maint).
+   (merge 7422b2a0a1 sg/commit-slab-clarify-peek later to maint).
+   (merge 9c688735f6 rs/doc-passthru-fetch-options later to maint).
+   (merge 757c2ba3e2 en/oidset-uninclude-hashmap later to maint).
+   (merge 8312aa7d74 jc/config-tar later to maint).
+   (merge d00a5bdd50 ss/submodule-foreach-cb later to maint).
+   (merge 64d1022e14 ar/test-style-fixes later to maint).
+   (merge 4a465443a6 ds/doc-clone-filter later to maint).
+   (merge bb2dbe301b jk/t3419-drop-expensive-tests later to maint).
+   (merge d3507cc712 js/test-junit-finalization-fix later to maint).
+   (merge 2149b6748f bc/faq later to maint).
+   (merge 12dc0879f1 jk/test-cleanup later to maint).
+   (merge 344420bf0f pb/rebase-doc-typofix later to maint).
+   (merge 7cd54d37dc dl/wrapper-fix-indentation later to maint).
+   (merge 78725ebda9 jc/allow-strlen-substitution-in-shell-scripts later to maint).
+   (merge 2ecfcdecc6 jm/gitweb-fastcgi-utf8 later to maint).
+   (merge 0740d0a5d3 jk/oid-array-cleanups later to maint).
+   (merge a1aba0c95c js/t0007-typofix later to maint).
+   (merge 76ba7fa225 ma/config-doc-fix later to maint).
+   (merge 826f0c0df2 js/subtree-doc-update-to-asciidoctor-2 later to maint).
+   (merge 88eaf361e0 eb/mboxrd-doc later to maint).
+   (merge 051cc54941 tm/zsh-complete-switch-restore later to maint).
+   (merge 39102cf4fe ms/doc-revision-illustration-fix later to maint).
+   (merge 4d9378bfad eb/gitweb-more-trailers later to maint).
+   (merge bdccbf7047 mt/doc-worktree-ref later to maint).
+   (merge ce9baf234f dl/push-recurse-submodules-fix later to maint).
+   (merge 4153274052 bc/doc-credential-helper-value later to maint).
+   (merge 5c7bb0146e jc/codingstyle-compare-with-null later to maint).
diff --git a/Documentation/RelNotes/2.27.1.txt b/Documentation/RelNotes/2.27.1.txt
new file mode 100644
index 0000000000..a1e08a9f72
--- /dev/null
+++ b/Documentation/RelNotes/2.27.1.txt
@@ -0,0 +1,7 @@
+Git v2.27.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5,
+v2.19.6, v2.20.5, v2.21.4, v2.22.5, v2.23.4, v2.24.4, v2.25.5
+and v2.26.3 to address the security issue CVE-2021-21300; see
+the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.28.0.txt b/Documentation/RelNotes/2.28.0.txt
new file mode 100644
index 0000000000..6baf781380
--- /dev/null
+++ b/Documentation/RelNotes/2.28.0.txt
@@ -0,0 +1,236 @@
+Git 2.28 Release Notes
+======================
+
+Updates since v2.27
+-------------------
+
+Backward compatibility notes
+
+ * "fetch.writeCommitGraph" is deemed to be still a bit too risky and
+   is no longer part of the "feature.experimental" set.
+
+
+UI, Workflows & Features
+
+ * The commands in the "diff" family learned to honor "diff.relative"
+   configuration variable.
+
+ * The check in "git fsck" to ensure that the tree objects are sorted
+   still had corner cases it missed unsorted entries.
+
+ * The interface to redact sensitive information in the trace output
+   has been simplified.
+
+ * The command line completion (in contrib/) learned to complete
+   options that the "git switch" command takes.
+
+ * "git diff" used to take arguments in random and nonsense range
+   notation, e.g. "git diff A..B C", "git diff A..B C...D", etc.,
+   which has been cleaned up.
+
+ * "git diff-files" has been taught to say paths that are marked as
+   intent-to-add are new files, not modified from an empty blob.
+
+ * "git status" learned to report the status of sparse checkout.
+
+ * "git difftool" has trouble dealing with paths added to the index
+   with the intent-to-add bit.
+
+ * "git fast-export --anonymize" learned to take customized mapping to
+   allow its users to tweak its output more usable for debugging.
+
+ * The command line completion support (in contrib/) used to be
+   prepared to work with "set -u" but recent changes got a bit more
+   sloppy.  This has been corrected.
+
+ * "git gui" now allows opening work trees from the start-up dialog.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Code optimization for a common case.
+   (merge 8777616e4d an/merge-single-strategy-optim later to maint).
+
+ * We've adopted a convention that any on-stack structure can be
+   initialized to have zero values in all fields with "= { 0 }",
+   even when the first field happens to be a pointer, but sparse
+   complained that a null pointer should be spelled NULL for a long
+   time.  Start using -Wno-universal-initializer option to squelch
+   it (the latest sparse has it on by default).
+
+ * "git log -L..." now takes advantage of the "which paths are touched
+   by this commit?" info stored in the commit-graph system.
+
+ * As FreeBSD is not the only platform whose regexp library reports
+   a REG_ILLSEQ error when fed invalid UTF-8, add logic to detect that
+   automatically and skip the affected tests.
+
+ * "git bugreport" learns to report what shell is in use.
+
+ * Support for GIT_CURL_VERBOSE has been rewritten in terms of
+   GIT_TRACE_CURL.
+
+ * Preliminary clean-ups around refs API, plus file format
+   specification documentation for the reftable backend.
+
+ * Workaround breakage in MSVC build, where "curl-config --cflags"
+   gives settings appropriate for GCC build.
+
+ * Code clean-up of "git clean" resulted in a fix of recent
+   performance regression.
+
+ * Code clean-up in the codepath that serves "git fetch" continues.
+
+ * "git merge-base --is-ancestor" is taught to take advantage of the
+   commit graph.
+
+ * Rewrite of parts of the scripted "git submodule" Porcelain command
+   continues; this time it is "git submodule set-branch" subcommand's
+   turn.
+
+ * The "fetch/clone" protocol has been updated to allow the server to
+   instruct the clients to grab pre-packaged packfile(s) in addition
+   to the packed object data coming over the wire.
+
+ * A misdesigned strbuf_write_fd() function has been retired.
+
+ * SHA-256 migration work continues, including CVS/SVN interface.
+
+ * A few fields in "struct commit" that do not have to always be
+   present have been moved to commit slabs.
+
+ * API cleanup for get_worktrees()
+
+ * By renumbering object flag bits, "struct object" managed to lose
+   bloated inter-field padding.
+
+ * The name of the primary branch in existing repositories, and the
+   default name used for the first branch in newly created
+   repositories, is made configurable, so that we can eventually wean
+   ourselves off of the hardcoded 'master'.
+
+ * The effort to avoid using test_must_fail on non-git command continues.
+
+ * In 2.28-rc0, we corrected a bug that some repository extensions are
+   honored by mistake even in a version 0 repositories (these
+   configuration variables in extensions.* namespace were supposed to
+   have special meaning in repositories whose version numbers are 1 or
+   higher), but this was a bit too big a change.  The behaviour in
+   recent versions of Git where certain extensions.* were honored by
+   mistake even in version 0 repositories has been restored.
+
+
+Fixes since v2.27
+-----------------
+
+ * The "--prepare-p4-only" option of "git p4" is supposed to stop
+   after replaying one changeset, but kept going (by mistake?)
+
+ * The error message from "git checkout -b foo -t bar baz" was
+   confusing.
+
+ * Some repositories in the wild have commits that record nonsense
+   committer timezone (e.g. rails.git); "git fast-import" learned an
+   option to pass these nonsense timestamps intact to allow recreating
+   existing repositories as-is.
+   (merge d42a2fb72f en/fast-import-looser-date later to maint).
+
+ * The command line completion script (in contrib/) tried to complete
+   "git stash -p" as if it were "git stash push -p", but it was too
+   aggressive and also affected "git stash show -p", which has been
+   corrected.
+   (merge fffd0cf520 vs/complete-stash-show-p-fix later to maint).
+
+ * On-the-wire protocol v2 easily falls into a deadlock between the
+   remote-curl helper and the fetch-pack process when the server side
+   prematurely throws an error and disconnects.  The communication has
+   been updated to make it more robust.
+
+ * "git checkout -p" did not handle a newly added path at all.
+   (merge 2c8bd8471a js/checkout-p-new-file later to maint).
+
+ * The code to parse "git bisect start" command line was lax in
+   validating the arguments.
+   (merge 4d9005ff5d cb/bisect-helper-parser-fix later to maint).
+
+ * Reduce memory usage during "diff --quiet" in a worktree with too
+   many stat-unmatched paths.
+   (merge d2d7fbe129 jk/diff-memuse-optim-with-stat-unmatch later to maint).
+
+ * The reflog entries for "git clone" and "git fetch" did not
+   anonymize the URL they operated on.
+   (merge 46da295a77 js/reflog-anonymize-for-clone-and-fetch later to maint).
+
+ * The behaviour of "sparse-checkout" in the state "git clone
+   --no-checkout" left was changed accidentally in 2.27, which has
+   been corrected.
+
+ * Use of negative pathspec, while collecting paths including
+   untracked ones in the working tree, was broken.
+
+ * The same worktree directory must be registered only once, but
+   "git worktree move" allowed this invariant to be violated, which
+   has been corrected.
+   (merge 810382ed37 es/worktree-duplicate-paths later to maint).
+
+ * The effect of sparse checkout settings on submodules is documented.
+   (merge e7d7c73249 en/sparse-with-submodule-doc later to maint).
+
+ * Code clean-up around "git branch" with a minor bugfix.
+   (merge dc44639904 dl/branch-cleanup later to maint).
+
+ * A branch name used in a test has been clarified to match what is
+   going on.
+   (merge 08dc26061f pb/t4014-unslave later to maint).
+
+ * An in-code comment in "git diff" has been updated.
+   (merge c592fd4c83 dl/diff-usage-comment-update later to maint).
+
+ * The documentation and some tests have been adjusted for the recent
+   renaming of "pu" branch to "seen".
+   (merge 6dca5dbf93 js/pu-to-seen later to maint).
+
+ * The code to push changes over "dumb" HTTP had a bad interaction
+   with the commit reachability code due to incorrect allocation of
+   object flag bits, which has been corrected.
+   (merge 64472d15e9 bc/http-push-flagsfix later to maint).
+
+ * "git send-email --in-reply-to=<msg>" did not use the In-Reply-To:
+   header with the value given from the command line, and let it be
+   overridden by the value on In-Reply-To: header in the messages
+   being sent out (if exists).
+   (merge f9f60d7066 ra/send-email-in-reply-to-from-command-line-wins later to maint).
+
+ * "git log -Lx,y:path --before=date" lost track of where the range
+   should be because it didn't take the changes made by the youngest
+   commits that are omitted from the output into account.
+
+ * When "fetch.writeCommitGraph" configuration is set in a shallow
+   repository and a fetch moves the shallow boundary, we wrote out
+   broken commit-graph files that do not match the reality, which has
+   been corrected.
+
+ * "git checkout" failed to catch an error from fstat() after updating
+   a path in the working tree.
+   (merge 35e6e212fd mt/entry-fstat-fallback-fix later to maint).
+
+ * When an aliased command, whose output is piped to a pager by git,
+   gets killed by a signal, the pager got into a funny state, which
+   has been corrected (again).
+   (merge c0d73a59c9 ta/wait-on-aliased-commands-upon-signal later to maint).
+
+ * The code to produce progress output from "git commit-graph --write"
+   had a few breakages, which have been fixed.
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 2c31a7aa44 jx/pkt-line-doc-count-fix later to maint).
+   (merge d63ae31962 cb/t5608-cleanup later to maint).
+   (merge 788db145c7 dl/t-readme-spell-git-correctly later to maint).
+   (merge 45a87a83bb dl/python-2.7-is-the-floor-version later to maint).
+   (merge b75a219904 es/advertise-contribution-doc later to maint).
+   (merge 0c9a4f638a rs/pull-leakfix later to maint).
+   (merge d546fe2874 rs/commit-reach-leakfix later to maint).
+   (merge 087bf5409c mk/pb-pretty-email-without-domain-part-fix later to maint).
+   (merge 5f4ee57ad9 es/worktree-code-cleanup later to maint).
+   (merge 0172f7834a cc/cat-file-usage-update later to maint).
+   (merge 81de0c01cf ma/rebase-doc-typofix later to maint).
diff --git a/Documentation/RelNotes/2.28.1.txt b/Documentation/RelNotes/2.28.1.txt
new file mode 100644
index 0000000000..8484c8297c
--- /dev/null
+++ b/Documentation/RelNotes/2.28.1.txt
@@ -0,0 +1,7 @@
+Git v2.28.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5,
+v2.19.6, v2.20.5, v2.21.4, v2.22.5, v2.23.4, v2.24.4, v2.25.5,
+v2.26.3 and v2.27.1 to address the security issue CVE-2021-21300;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.29.0.txt b/Documentation/RelNotes/2.29.0.txt
new file mode 100644
index 0000000000..1f41302ebb
--- /dev/null
+++ b/Documentation/RelNotes/2.29.0.txt
@@ -0,0 +1,514 @@
+Git 2.29 Release Notes
+======================
+
+Updates since v2.28
+-------------------
+
+UI, Workflows & Features
+
+ * "git help log" has been enhanced by sharing more material from the
+   documentation for the underlying "git rev-list" command.
+
+ * "git for-each-ref --format=<>" learned %(contents:size).
+
+ * "git merge" learned to selectively omit " into <branch>" at the end
+   of the title of default merge message with merge.suppressDest
+   configuration.
+
+ * The component to respond to "git fetch" request is made more
+   configurable to selectively allow or reject object filtering
+   specification used for partial cloning.
+
+ * Stop when "sendmail.*" configuration variables are defined, which
+   could be a mistaken attempt to define "sendemail.*" variables.
+
+ * The existing backends for "git mergetool" based on variants of vim
+   have been refactored and then support for "nvim" has been added.
+
+ * "git bisect" learns the "--first-parent" option to find the first
+   breakage along the first-parent chain.
+
+ * "git log --first-parent -p" showed patches only for single-parent
+   commits on the first-parent chain; the "--first-parent" option has
+   been made to imply "-m".  Use "--no-diff-merges" to restore the
+   previous behaviour to omit patches for merge commits.
+
+ * The commit labels used to explain each side of conflicted hunks
+   placed by the sequencer machinery have been made more readable by
+   humans.
+
+ * The "--batch-size" option of "git multi-pack-index repack" command
+   is now used to specify that very small packfiles are collected into
+   one until the total size roughly exceeds it.
+
+ * The recent addition of SHA-256 support is marked as experimental in
+   the documentation.
+
+ * "git fetch" learned --no-write-fetch-head option to avoid writing
+   the FETCH_HEAD file.
+
+ * Command line completion (in contrib/) usually omits redundant,
+   deprecated and/or dangerous options from its output; it learned to
+   optionally include all of them.
+
+ * The output from the "diff" family of the commands had abbreviated
+   object names of blobs involved in the patch, but its length was not
+   affected by the --abbrev option.  Now it is.
+
+ * "git worktree" gained a "repair" subcommand to help users recover
+   after moving the worktrees or repository manually without telling
+   Git.  Also, "git init --separate-git-dir" no longer corrupts
+   administrative data related to linked worktrees.
+
+ * The "--format=" option to the "for-each-ref" command and friends
+   learned a few more tricks, e.g. the ":short" suffix that applies to
+   "objectname" now also can be used for "parent", "tree", etc.
+
+ * "git worktree add" learns that the "-d" is a synonym to "--detach"
+   option to create a new worktree without being on a branch.
+
+ * "format-patch --range-diff=<prev> <origin>..HEAD" has been taught
+   not to ignore <origin> when <prev> is a single version.
+
+ * "add -p" now allows editing paths that were only added in intent.
+
+ * The 'meld' backend of the "git mergetool" learned to give the
+   underlying 'meld' the '--auto-merge' option, which would help
+   reduce the amount of text that requires manual merging.
+
+ * "git for-each-ref" and friends that list refs used to allow only
+   one --merged or --no-merged to filter them; they learned to take
+   combination of both kind of filtering.
+
+ * "git maintenance", a "git gc"'s big brother, has been introduced to
+   take care of more repository maintenance tasks, not limited to the
+   object database cleaning.
+
+ * "git receive-pack" that accepts requests by "git push" learned to
+   outsource most of the ref updates to the new "proc-receive" hook.
+
+ * "git push" that wants to be atomic and wants to send push
+   certificate learned not to prepare and sign the push certificate
+   when it fails the local check (hence due to atomicity it is known
+   that no certificate is needed).
+
+ * "git commit-graph write" learned to limit the number of bloom
+   filters that are computed from scratch with the --max-new-filters
+   option.
+
+ * The transport protocol v2 has become the default again.
+
+ * The installation procedure learned to optionally omit "git-foo"
+   executable files for each 'foo' built-in subcommand, which are only
+   required by old timers that still rely on the age old promise that
+   prepending "git --exec-path" output to PATH early in their script
+   will keep the "git-foo" calls they wrote working.
+
+ * The command line completion (in contrib/) learned that "git restore
+   -s <TAB>" is often followed by a refname.
+
+ * "git shortlog" has been taught to group commits by the contents of
+   the trailer lines, like "Reviewed-by:", "Coauthored-by:", etc.
+
+ * "git archive" learns the "--add-file" option to include untracked
+   files into a snapshot from a tree-ish.
+
+ * "git fetch" and "git push" support negative refspecs.
+
+ * "git format-patch" learns to take "whenAble" as a possible value
+   for the format.useAutoBase configuration variable to become no-op
+   when the  automatically computed base does not make sense.
+
+ * Credential helpers are now allowed to terminate lines with CRLF
+   line ending, as well as LF line ending.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The changed-path Bloom filter is improved using ideas from an
+   independent implementation.
+
+ * Updates to the changed-paths bloom filter.
+
+ * The test framework has been updated so that most tests will run
+   with predictable (artificial) timestamps.
+
+ * Preliminary clean-up of the refs API in preparation for adding a
+   new refs backend "reftable".
+
+ * Dev support to limit the use of test_must_fail to only git commands.
+
+ * While packing many objects in a repository with a promissor remote,
+   lazily fetching missing objects from the promissor remote one by
+   one may be inefficient---the code now attempts to fetch all the
+   missing objects in batch (obviously this won't work for a lazy
+   clone that lazily fetches tree objects as you cannot even enumerate
+   what blobs are missing until you learn which trees are missing).
+
+ * The pretend-object mechanism checks if the given object already
+   exists in the object store before deciding to keep the data
+   in-core, but the check would have triggered lazy fetching of such
+   an object from a promissor remote.
+
+ * The argv_array API is useful for not just managing argv but any
+   "vector" (NULL-terminated array) of strings, and has seen adoption
+   to a certain degree.  It has been renamed to "strvec" to reduce the
+   barrier to adoption.
+
+ * The final leg of SHA-256 transition plus doc updates.  Note that
+   there is no interoperability between SHA-1 and SHA-256
+   repositories yet.
+
+ * CMake support to build with MSVC for Windows bypassing the Makefile.
+
+ * A new helper function has_object() has been introduced to make it
+   easier to mark object existence checks that do and don't want to
+   trigger lazy fetches, and a few such checks are converted using it.
+
+ * A no-op replacement function implemented as a C preprocessor macro
+   does not perform as good a job as one implemented as a "static
+   inline" function in catching errors in parameters; replace the
+   former with the latter in <git-compat-util.h> header.
+
+ * Test framework update.
+   (merge d572f52a64 es/test-cmp-typocatcher later to maint).
+
+ * Updates to "git merge" tests, in preparation for a new merge
+   strategy backend.
+
+ * midx and commit-graph files now use the byte defined in their file
+   format specification for identifying the hash function used for
+   object names.
+
+ * The FETCH_HEAD is now always read from the filesystem regardless of
+   the ref backend in use, as its format is much richer than the
+   normal refs, and written directly by "git fetch" as a plain file..
+
+ * An unused binary has been discarded, and a bunch of commands
+   have been turned into built-in.
+
+ * A handful of places in in-tree code still relied on being able to
+   execute the git subcommands, especially built-ins, in "git-foo"
+   form, which have been corrected.
+
+ * When a packfile is removed by "git repack", multi-pack-index gets
+   cleared; the code was taught to do so less aggressively by first
+   checking if the midx actually refers to a pack that no longer
+   exists.
+
+ * Internal API clean-up to handle two options "diff-index" and "log"
+   have, which happen to share the same short form, more sensibly.
+
+ * The "add -i/-p" machinery has been written in C but it is not used
+   by default yet.  It is made default to those who are participating
+   in feature.experimental experiment.
+
+ * Allow maintainers to tweak $(TAR) invocations done while making
+   distribution tarballs.
+
+ * "git index-pack" learned to resolve deltified objects with greater
+   parallelism.
+
+ * "diff-highlight" (in contrib/) had a logic to flush its output upon
+   seeing a blank line but the way it detected a blank line was broken.
+
+ * The logic to skip testing on the tagged commit and the tag itself
+   was not quite consistent which led to failure of Windows test
+   tasks.  It has been revamped to consistently skip revisions that
+   have already been tested, based on the tree object of the revision.
+
+
+Fixes since v2.28
+-----------------
+
+ * The "mediawiki" remote backend which lives in contrib/mw-to-git/
+   and is not built with git by default, had an RCE bug allowing a
+   malicious MediaWiki server operator to inject arbitrary commands
+   for execution by a cloning client. This has been fixed.
+
+   The bug was discovered and reported by Joern Schneeweisz of GitLab
+   to the git-security mailing list. Its practical impact due to the
+   obscurity of git-remote-mediawiki was deemed small enough to forgo
+   a dedicated security release.
+
+ * "git clone --separate-git-dir=$elsewhere" used to stomp on the
+   contents of the existing directory $elsewhere, which has been
+   taught to fail when $elsewhere is not an empty directory.
+   (merge dfaa209a79 bw/fail-cloning-into-non-empty later to maint).
+
+ * With the base fix to 2.27 regresion, any new extensions in a v0
+   repository would still be silently honored, which is not quite
+   right.  Instead, complain and die loudly.
+   (merge ec91ffca04 jk/reject-newer-extensions-in-v0 later to maint).
+
+ * Fetching from a lazily cloned repository resulted at the server
+   side in attempts to lazy fetch objects that the client side has,
+   many of which will not be available from the third-party anyway.
+   (merge 77aa0941ce jt/avoid-lazy-fetching-upon-have-check later to maint).
+
+ * Fix to an ancient bug caused by an over-eager attempt for
+   optimization.
+   (merge a98f7fb366 rs/add-index-entry-optim-fix later to maint).
+
+ * Pushing a ref whose name contains non-ASCII character with the
+   "--force-with-lease" option did not work over smart HTTP protocol,
+   which has been corrected.
+   (merge cd85b447bf bc/push-cas-cquoted-refname later to maint).
+
+ * "git mv src dst", when src is an unmerged path, errored out
+   correctly but with an incorrect error message to claim that src is
+   not tracked, which has been clarified.
+   (merge 9b906af657 ct/mv-unmerged-path-error later to maint).
+
+ * Fix to a regression introduced during 2.27 cycle.
+   (merge cada7308ad en/fill-directory-exponential later to maint).
+
+ * Command line completion (in contrib/) update.
+   (merge 688b87c81b mp/complete-show-color-moved later to maint).
+
+ * All "mergy" operations that internally use the merge-recursive
+   machinery should honor the merge.renormalize configuration, but
+   many of them didn't.
+
+ * Doc cleanup around "worktree".
+   (merge dc9c144be5 es/worktree-doc-cleanups later to maint).
+
+ * The "git blame --first-parent" option was not documented, but now
+   it is.
+   (merge 11bc12ae1e rp/blame-first-parent-doc later to maint).
+
+ * The logic to find the ref transaction hook script attempted to
+   cache the path to the found hook without realizing that it needed
+   to keep a copied value, as the API it used returned a transitory
+   buffer space.  This has been corrected.
+   (merge 09b2aa30c9 ps/ref-transaction-hook later to maint).
+
+ * Recent versions of "git diff-files" shows a diff between the index
+   and the working tree for "intent-to-add" paths as a "new file"
+   patch; "git apply --cached" should be able to take "git diff-files"
+   and should act as an equivalent to "git add" for the path, but the
+   command failed to do so for such a path.
+   (merge 4c025c667e rp/apply-cached-with-i-t-a later to maint).
+
+ * "git diff [<tree-ish>] $path" for a $path that is marked with i-t-a
+   bit was not showing the mode bits from the working tree.
+   (merge cb0dd22b82 rp/ita-diff-modefix later to maint).
+
+ * Ring buffer with size 4 used for bin-hex translation resulted in a
+   wrong object name in the sequencer's todo output, which has been
+   corrected.
+   (merge 5da69c0dac ak/sequencer-fix-find-uniq-abbrev later to maint).
+
+ * When given more than one target line ranges, "git blame -La,b
+   -Lc,d" was over-eager to coalesce groups of original lines and
+   showed incorrect results, which has been corrected.
+   (merge c2ebaa27d6 jk/blame-coalesce-fix later to maint).
+
+ * The regexp to identify the function boundary for FORTRAN programs
+   has been updated.
+   (merge 75c3b6b2e8 pb/userdiff-fortran-update later to maint).
+
+ * A few end-user facing messages have been updated to be
+   hash-algorithm agnostic.
+   (merge 4279000d3e jc/object-names-are-not-sha-1 later to maint).
+
+ * "unlink" emulation on MinGW has been optimized.
+   (merge 680e0b4524 jh/mingw-unlink later to maint).
+
+ * The purpose of "git init --separate-git-dir" is to initialize a
+   new project with the repository separate from the working tree,
+   or, in the case of an existing project, to move the repository
+   (the .git/ directory) out of the working tree. It does not make
+   sense to use --separate-git-dir with a bare repository for which
+   there is no working tree, so disallow its use with bare
+   repositories.
+   (merge ccf236a23a es/init-no-separate-git-dir-in-bare later to maint).
+
+ * "ls-files -o" mishandled the top-level directory of another git
+   working tree that hangs in the current git working tree.
+   (merge ab282aa548 en/dir-nonbare-embedded later to maint).
+
+ * Fix some incorrect UNLEAK() annotations.
+   (merge 3e19816dc0 jk/unleak-fixes later to maint).
+
+ * Use more buffered I/O where we used to call many small write(2)s.
+   (merge a698d67b08 rs/more-buffered-io later to maint).
+
+ * The patch-id computation did not ignore the "incomplete last line"
+   marker like whitespaces.
+   (merge 82a62015a7 rs/patch-id-with-incomplete-line later to maint).
+
+ * Updates into a lazy/partial clone with a submodule did not work
+   well with transfer.fsckobjects set.
+
+ * The parser for "git for-each-ref --format=..." was too loose when
+   parsing the "%(trailers...)" atom, and forgot that "trailers" and
+   "trailers:<modifiers>" are the only two allowed forms, which has
+   been corrected.
+   (merge 2c22e102f8 hv/ref-filter-trailers-atom-parsing-fix later to maint).
+
+ * Long ago, we decided to use 3 threads by default when running the
+   index-pack task in parallel, which has been adjusted a bit upwards.
+   (merge fbff95b67f jk/index-pack-w-more-threads later to maint).
+
+ * "git restore/checkout --no-overlay" with wildcarded pathspec
+   mistakenly removed matching paths in subdirectories, which has been
+   corrected.
+   (merge bfda204ade rs/checkout-no-overlay-pathspec-fix later to maint).
+
+ * The description of --cached/--index options in "git apply --help"
+   has been updated.
+   (merge d064702be3 rp/apply-cached-doc later to maint).
+
+ * Feeding "$ZERO_OID" to "git log --ignore-missing --stdin", and
+   running "git log --ignore-missing $ZERO_OID" fell back to start
+   digging from HEAD; it has been corrected to become a no-op, like
+   "git log --tags=no-tag-matches-this-pattern" does.
+   (merge 04a0e98515 jk/rev-input-given-fix later to maint).
+
+ * Various callers of run_command API have been modernized.
+   (merge afbdba391e jc/run-command-use-embedded-args later to maint).
+
+ * List of options offered and accepted by "git add -i/-p" were
+   inconsistent, which have been corrected.
+   (merge ce910287e7 pw/add-p-allowed-options-fix later to maint).
+
+ * "git diff --stat -w" showed 0-line changes for paths whose changes
+   were only whitespaces, which was not intuitive.  We now omit such
+   paths from the stat output.
+   (merge 1cf3d5db9b mr/diff-hide-stat-wo-textual-change later to maint).
+
+ * It was possible for xrealloc() to send a non-NULL pointer that has
+   been freed, which has been fixed.
+   (merge 6479ea4a8a jk/xrealloc-avoid-use-after-free later to maint).
+
+ * "git status" has trouble showing where it came from by interpreting
+   reflog entries that record certain events, e.g. "checkout @{u}", and
+   gives a hard/fatal error.  Even though it inherently is impossible
+   to give a correct answer because the reflog entries lose some
+   information (e.g. "@{u}" does not record what branch the user was
+   on hence which branch 'the upstream' needs to be computed, and even
+   if the record were available, the relationship between branches may
+   have changed), at least hide the error and allow "status" to show its
+   output.
+
+ * "git status --short" quoted a path with SP in it when tracked, but
+   not those that are untracked, ignored or unmerged.  They are all
+   shown quoted consistently.
+
+ * "git diff/show" on a change that involves a submodule used to read
+   the information on commits in the submodule from a wrong repository
+   and gave a wrong information when the commit-graph is involved.
+   (merge 85a1ec2c32 mf/submodule-summary-with-correct-repository later to maint).
+
+ * Unlike "git config --local", "git config --worktree" did not fail
+   early and cleanly when started outside a git repository.
+   (merge 378fe5fc3d mt/config-fail-nongit-early later to maint).
+
+ * There is a logic to estimate how many objects are in the
+   repository, which is meant to run once per process invocation, but
+   it ran every time the estimated value was requested.
+   (merge 67bb65de5d jk/dont-count-existing-objects-twice later to maint).
+
+ * "git remote set-head" that failed still said something that hints
+   the operation went through, which was misleading.
+   (merge 5a07c6c3c2 cs/don-t-pretend-a-failed-remote-set-head-succeeded later to maint).
+
+ * "git fetch --all --ipv4/--ipv6" forgot to pass the protocol options
+   to instances of the "git fetch" that talk to individual remotes,
+   which has been corrected.
+   (merge 4e735c1326 ar/fetch-ipversion-in-all later to maint).
+
+ * The "unshelve" subcommand of "git p4" incorrectly used commit^N
+   where it meant to say commit~N to name the Nth generation
+   ancestor, which has been corrected.
+   (merge 0acbf5997f ld/p4-unshelve-fix later to maint).
+
+ * "git clone" that clones from SHA-1 repository, while
+   GIT_DEFAULT_HASH set to use SHA-256 already, resulted in an
+   unusable repository that half-claims to be SHA-256 repository
+   with SHA-1 objects and refs.  This has been corrected.
+
+ * Adjust sample hooks for hash algorithm other than SHA-1.
+   (merge d8d3d632f4 dl/zero-oid-in-hooks later to maint).
+
+ * "git range-diff" showed incorrect diffstat, which has been
+   corrected.
+
+ * Earlier we taught "git pull" to warn when the user does not say the
+   histories need to be merged, rebased or accepts only fast-
+   forwarding, but the warning triggered for those who have set the
+   pull.ff configuration variable.
+   (merge 54200cef86 ah/pull later to maint).
+
+ * Compilation fix around type punning.
+   (merge 176380fd11 jk/drop-unaligned-loads later to maint).
+
+ * "git blame --ignore-rev/--ignore-revs-file" failed to validate
+   their input are valid revision, and failed to take into account
+   that the user may want to give an annotated tag instead of a
+   commit, which has been corrected.
+   (merge 610e2b9240 jc/blame-ignore-fix later to maint).
+
+ * "git bisect start X Y", when X and Y are not valid committish
+   object names, should take X and Y as pathspec, but didn't.
+   (merge 73c6de06af cc/bisect-start-fix later to maint).
+
+ * The explanation of the "scissors line" has been clarified.
+   (merge 287416dba6 eg/mailinfo-doc-scissors later to maint).
+
+ * A race that leads to an access to a free'd data was corrected in
+   the codepath that reads pack files.
+   (merge bda959c476 mt/delta-base-cache-races later to maint).
+
+ * in_merge_bases_many(), a way to see if a commit is reachable from
+   any commit in a set of commits, was totally broken when the
+   commit-graph feature was in use, which has been corrected.
+   (merge 8791bf1841 ds/in-merge-bases-many-optim-bug later to maint).
+
+ * "git submodule update --quiet" did not squelch underlying "rebase"
+   and "pull" commands.
+   (merge 3ad0401e9e td/submodule-update-quiet later to maint).
+
+ * The lazy fetching done internally to make missing objects available
+   in a partial clone incorrectly made permanent damage to the partial
+   clone filter in the repository, which has been corrected.
+
+ * "log -c --find-object=X" did not work well to find a merge that
+   involves a change to an object X from only one parent.
+   (merge 957876f17d jk/diff-cc-oidfind-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 84544f2ea3 sk/typofixes later to maint).
+   (merge b17f411ab5 ar/help-guides-doc later to maint).
+   (merge 98c6871fad rs/grep-simpler-parse-object-or-die-call later to maint).
+   (merge 861c4ce141 en/typofixes later to maint).
+   (merge 60e47f6773 sg/ci-git-path-fix-with-pyenv later to maint).
+   (merge e2bfa50ac3 jb/doc-packfile-name later to maint).
+   (merge 918d8ff780 es/worktree-cleanup later to maint).
+   (merge dc156bc31f ma/t1450-quotefix later to maint).
+   (merge 56e743426b en/merge-recursive-comment-fixes later to maint).
+   (merge 7d23ff818f rs/bisect-oid-to-hex-fix later to maint).
+   (merge de20baf2c9 ny/notes-doc-sample-update later to maint).
+   (merge f649aaaf82 so/rev-parser-errormessage-fix later to maint).
+   (merge 6103d58b7f bc/sha-256-cvs-svn-updates later to maint).
+   (merge ac900fddb7 ma/stop-progress-null-fix later to maint).
+   (merge e767963ab6 rs/upload-pack-sigchain-fix later to maint).
+   (merge a831908599 rs/preserve-merges-unused-code-removal later to maint).
+   (merge 6dfefe70a9 jb/commit-graph-doc-fix later to maint).
+   (merge 847b37271e pb/set-url-docfix later to maint).
+   (merge 748f733d54 mt/checkout-entry-dead-code-removal later to maint).
+   (merge ce820cbd58 dl/subtree-docs later to maint).
+   (merge 55fe225dde jk/leakfix later to maint).
+   (merge ee22a29215 so/pretty-abbrev-doc later to maint).
+   (merge 3100fd5588 jc/post-checkout-doc later to maint).
+   (merge 17bae89476 pb/doc-external-diff-env later to maint).
+   (merge 27ed6ccc12 jk/worktree-check-clean-leakfix later to maint).
+   (merge 1302badd16 ea/blame-use-oideq later to maint).
+   (merge e6d5a11fed al/t3200-back-on-a-branch later to maint).
+   (merge 324efcf6b6 pw/add-p-leakfix later to maint).
+   (merge 1c6ffb546b jk/add-i-fixes later to maint).
+   (merge e40e936551 cd/commit-graph-doc later to maint).
+   (merge 0512eabd91 jc/sequencer-stopped-sha-simplify later to maint).
+   (merge d01141de5a so/combine-diff-simplify later to maint).
+   (merge 3be01e5ab1 sn/fast-import-doc later to maint).
diff --git a/Documentation/RelNotes/2.29.1.txt b/Documentation/RelNotes/2.29.1.txt
new file mode 100644
index 0000000000..295ee2135f
--- /dev/null
+++ b/Documentation/RelNotes/2.29.1.txt
@@ -0,0 +1,11 @@
+Git v2.29.1 Release Notes
+=========================
+
+This is to fix the build procedure change in 2.28 where we failed to
+install a few programs that should be installed in /usr/bin (namely,
+receive-pack, upload-archive and upload-pack) when the non-default
+SKIP_DASHED_BUILT_INS installation option is in effect.
+
+A minor glitch in a non-default installation may usually not deserve
+a hotfix, but I know Git for Windows ship binaries built with this
+option, so let's make an exception.
diff --git a/Documentation/RelNotes/2.29.2.txt b/Documentation/RelNotes/2.29.2.txt
new file mode 100644
index 0000000000..632b5b580a
--- /dev/null
+++ b/Documentation/RelNotes/2.29.2.txt
@@ -0,0 +1,12 @@
+Git v2.29.2 Release Notes
+=========================
+
+This release is primarily to fix brown-paper-bag breakages in the
+2.29.0 release.
+
+Fixes since v2.29.1
+-------------------
+
+ * In 2.29, "--committer-date-is-author-date" option of "rebase" and
+   "am" subcommands lost the e-mail address by mistake, which has been
+   corrected.
diff --git a/Documentation/RelNotes/2.29.3.txt b/Documentation/RelNotes/2.29.3.txt
new file mode 100644
index 0000000000..e10eedb35a
--- /dev/null
+++ b/Documentation/RelNotes/2.29.3.txt
@@ -0,0 +1,8 @@
+Git v2.29.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6,
+v2.18.5, v2.19.6, v2.20.5, v2.21.4, v2.22.5, v2.23.4, v2.24.4,
+v2.25.5, v2.26.3, v2.27.1 and v2.28.1 to address the security
+issue CVE-2021-21300; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.3.0.txt b/Documentation/RelNotes/2.3.0.txt
new file mode 100644
index 0000000000..e3c639c840
--- /dev/null
+++ b/Documentation/RelNotes/2.3.0.txt
@@ -0,0 +1,300 @@
+Git v2.3 Release Notes
+======================
+
+This one ended up to be a release with lots of small corrections and
+improvements without big uncomfortably exciting features.  The recent
+security fix that went to 2.2.1 and older maintenance tracks is also
+contained in this update.
+
+
+Updates since v2.2
+------------------
+
+Ports
+
+ * Recent gcc toolchain on Cygwin started throwing compilation warning,
+   which has been squelched.
+
+ * A few updates to build on platforms that lack tv_nsec,
+   clock_gettime, CLOCK_MONOTONIC and HMAC_CTX_cleanup (e.g. older
+   RHEL) have been added.
+
+
+UI, Workflows & Features
+
+ * It was cumbersome to use "GIT_SSH" mechanism when the user wanted
+   to pass an extra set of arguments to the underlying ssh.  A new
+   environment variable GIT_SSH_COMMAND can be used for this.
+
+ * A request to store an empty note via "git notes" meant to remove
+   note from the object but with --allow-empty we will store a
+   (surprise!)  note that is empty.
+
+ * "git interpret-trailers" learned to properly handle the
+   "Conflicts:" block at the end.
+
+ * "git am" learned "--message-id" option to copy the message ID of
+   the incoming e-mail to the log message of resulting commit.
+
+ * "git clone --reference=<over there>" learned the "--dissociate"
+   option to go with it; it borrows objects from the reference object
+   store while cloning only to reduce network traffic and then
+   dissociates the resulting clone from the reference by performing
+   local copies of borrowed objects.
+
+ * "git send-email" learned "--transfer-encoding" option to force a
+   non-fault Content-Transfer-Encoding header (e.g. base64).
+
+ * "git send-email" normally identifies itself via X-Mailer: header in
+   the message it sends out.  A new command line flag --no-xmailer
+   allows the user to squelch the header.
+
+ * "git push" into a repository with a working tree normally refuses
+   to modify the branch that is checked out.  The command learned to
+   optionally do an equivalent of "git reset --hard" only when there
+   is no change to the working tree and the index instead, which would
+   be useful to "deploy" by pushing into a repository.
+
+ * "git new-workdir" (in contrib/) can be used to populate an empty
+   and existing directory now.
+
+ * Credential helpers are asked in turn until one of them give
+   positive response, which is cumbersome to turn off when you need to
+   run Git in an automated setting.  The credential helper interface
+   learned to allow a helper to say "stop, don't ask other helpers."
+   Also GIT_TERMINAL_PROMPT environment can be set to false to disable
+   our built-in prompt mechanism for passwords.
+
+ * "git branch -d" (delete) and "git branch -m" (move) learned to
+   honor "-f" (force) flag; unlike many other subcommands, the way to
+   force these have been with separate "-D/-M" options, which was
+   inconsistent.
+
+ * "diff-highlight" filter (in contrib/) allows its color output to be
+   customized via configuration variables.
+
+ * "git imap-send" learned to take "-v" (verbose) and "-q" (quiet)
+   command line options.
+
+ * "git remote add $name $URL" is now allowed when "url.$URL.insteadOf"
+   is already defined.
+
+ * "git imap-send" now can be built to use cURL library to talk to
+   IMAP servers (if the library is recent enough, of course).
+   This allows you to use authenticate method other than CRAM-MD5,
+   among other things.
+
+ * "git imap-send" now allows GIT_CURL_VERBOSE environment variable to
+   control the verbosity when talking via the cURL library.
+
+ * The prompt script (in contrib/) learned to optionally hide prompt
+   when in an ignored directory by setting GIT_PS1_HIDE_IF_PWD_IGNORED
+   shell variable.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Earlier we made "rev-list --object-edge" more aggressively list the
+   objects at the edge commits, in order to reduce number of objects 
+   fetched into a shallow repository, but the change affected cases
+   other than "fetching into a shallow repository" and made it
+   unusably slow (e.g. fetching into a normal repository should not
+   have to suffer the overhead from extra processing).  Limit it to a
+   more specific case by introducing --objects-edge-aggressive, a new
+   option to rev-list.
+
+ * Squelched useless compiler warnings on Mac OS X regarding the
+   crypto API.
+
+ * The procedure to generate unicode table has been simplified.
+
+ * Some filesystems assign filemodes in a strange way, fooling then
+   automatic "filemode trustability" check done during a new
+   repository creation.  The initialization codepath has been hardened
+   against this issue.
+
+ * The codepath in "git remote update --prune" to drop many refs has
+   been optimized.
+
+ * The API into get_merge_bases*() family of functions was easy to
+   misuse, which has been corrected to make it harder to do so.
+
+ * Long overdue departure from the assumption that S_IFMT is shared by
+   everybody made in 2005, which was necessary to port to z/OS.
+
+ * "git push" and "git fetch" did not communicate an overlong refname
+   correctly.  Now it uses 64kB sideband to accommodate longer ones.
+
+ * Recent GPG changes the keyring format and drops support for RFC1991
+   formatted signatures, breaking our existing tests.
+
+ * "git-prompt" (in contrib/) used a variable from the global scope,
+   possibly contaminating end-user's namespace.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.2
+----------------
+
+Unless otherwise noted, all the fixes since v2.2 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git http-push" over WebDAV (aka dumb http-push) was broken in
+   v2.2.2 when parsing a symbolic ref, resulting in a bogus request
+   that gets rejected by recent versions of cURL library.
+   (merge f6786c8 jk/http-push-symref-fix later to maint).
+
+ * The logic in "git bisect bad HEAD" etc. to avoid forcing the test
+   of the common ancestor of bad and good commits was broken.
+   (merge 07913d5 cc/bisect-rev-parsing later to maint).
+
+ * "git checkout-index --temp=$target $path" did not work correctly
+   for paths outside the current subdirectory in the project.
+   (merge 74c4de5 es/checkout-index-temp later to maint).
+
+ * The report from "git checkout" on a branch that builds on another
+   local branch by setting its branch.*.merge to branch name (not a
+   full refname) incorrectly said that the upstream is gone.
+   (merge 05e7368 jc/checkout-local-track-report later to maint).
+
+ * With The git-prompt support (in contrib/), using the exit status of
+   the last command in the prompt, e.g.  PS1='$(__git_ps1) $? ', did
+   not work well, because the helper function stomped on the exit
+   status.
+   (merge 6babe76 tf/prompt-preserve-exit-status later to maint).
+
+ * Recent update to "git commit" broke amending an existing commit
+   with bogus author/committer lines without a valid e-mail address.
+   (merge c83a509 jk/commit-date-approxidate later to maint).
+
+ * The lockfile API used to get confused which file to clean up when
+   the process moved the $cwd after creating a lockfile.
+   (merge fa137f6 nd/lockfile-absolute later to maint).
+
+ * Traditionally we tried to avoid interpreting date strings given by
+   the user as future dates, e.g. GIT_COMMITTER_DATE=2014-12-10 when
+   used early November 2014 was taken as "October 12, 2014" because it
+   is likely that a date in the future, December 10, is a mistake.
+   This heuristics has been loosened to allow people to express future
+   dates (most notably, --until=<date> may want to be far in the
+   future) and we no longer tiebreak by future-ness of the date when
+
+    (1) ISO-like format is used, and
+    (2) the string can make sense interpreted as both y-m-d and y-d-m.
+
+   Git may still have to use the heuristics to tiebreak between dd/mm/yy
+   and mm/dd/yy, though.
+   (merge d372395 jk/approxidate-avoid-y-d-m-over-future-dates later to maint).
+
+ * Git did not correctly read an overlong refname from a packed refs
+   file.
+   (merge ea41783 jk/read-packed-refs-without-path-max later to maint).
+
+ * "git apply" was described in the documentation to take --ignore-date
+   option, which it does not.
+   (merge 0cef4e7 rw/apply-does-not-take-ignore-date later to maint).
+
+ * "git add -i" did not notice when the interactive command input
+   stream went away and kept asking the same question.
+   (merge a8bec7a jk/add-i-read-error later to maint).
+
+ * "git send-email" did not handle RFC 2047 encoded headers quite
+   right.
+   (merge ab47e2a rd/send-email-2047-fix later to maint).
+
+ * New tag object format validation added in 2.2 showed garbage after
+   a tagname it reported in its error message.
+   (merge a1e920a js/fsck-tag-validation later to maint).
+
+ * The code that reads the reflog from the newer to the older entries
+   did not handle an entry that crosses a boundary of block it uses to
+   read them correctly.
+   (merge 69216bf jk/for-each-reflog-ent-reverse later to maint).
+
+ * "git diff -B -M" after making a new copy B out of an existing file
+   A and then editing A extensively ought to report that B was created
+   by copying A and A was modified, which is what "git diff -C"
+   reports, but it instead said A was renamed to B and A was edited
+   heavily in place.  This was not just incoherent but also failed to
+   apply with "git apply".  The report has been corrected to match what
+   "git diff -C" produces for this case.
+   (merge 6936b58 jc/diff-b-m later to maint).
+
+ * In files we pre-populate for the user to edit with commented hints,
+   a line of hint that is indented with a tab used to show as '#' (or
+   any comment char), ' ' (space), and then the hint text that began
+   with the tab, which some editors flag as an indentation error (tab
+   following space).  We now omit the space after the comment char in
+   such a case.
+   (merge d55aeb7 jc/strbuf-add-lines-avoid-sp-ht-sequence later to maint).
+
+ * "git ls-tree" does not support path selection based on negative
+   pathspecs, but did not error out when negative pathspecs are given.
+   (merge f1f6224 nd/ls-tree-pathspec later to maint).
+
+ * The function sometimes returned a non-freeable memory and some
+   other times returned a piece of memory that must be freed, leading
+   to inevitable leaks.
+   (merge 59362e5 jc/exec-cmd-system-path-leak-fix later to maint).
+
+ * The code to abbreviate an object name to its short unique prefix
+   has been optimized when no abbreviation was requested.
+   (merge 61e704e mh/find-uniq-abbrev later to maint).
+
+ * "git add --ignore-errors ..." did not ignore an error to
+   give a file that did not exist.
+   (merge 1d31e5a mg/add-ignore-errors later to maint).
+
+ * "git checkout $treeish $path", when $path in the index and the
+   working tree already matched what is in $treeish at the $path,
+   still overwrote the $path unnecessarily.
+   (merge c5326bd jk/checkout-from-tree later to maint).
+
+ * "git config --get-color" did not parse its command line arguments
+   carefully.
+   (merge cb35722 jk/colors-fix later to maint).
+
+ * open() emulated on Windows platforms did not give EISDIR upon
+   an attempt to open a directory for writing.
+   (merge ba6fad0 js/windows-open-eisdir-error later to maint).
+
+ * A few code paths used abs() when they should have used labs() on
+   long integers.
+   (merge 83915ba rs/maint-config-use-labs later to maint).
+   (merge 31a8aa1 rs/receive-pack-use-labs later to maint).
+
+ * "gitweb" used to depend on a behaviour recent CGI.pm deprecated.
+   (merge 13dbf46 jk/gitweb-with-newer-cgi-multi-param later to maint).
+
+ * "git init" (hence "git clone") initialized the per-repository
+   configuration file .git/config with x-bit by mistake.
+   (merge 1f32ecf mh/config-flip-xbit-back-after-checking later to maint).
+
+ * Recent update in Git 2.2 started creating objects/info/packs and
+   info/refs files with permission bits tighter than user's umask.
+   (merge d91175b jk/prune-packed-server-info later to maint).
+
+ * Git 2.0 was supposed to make the "simple" mode for the default of
+   "git push", but it didn't.
+   (merge 00a6fa0 jk/push-simple later to maint).
+
+ * "Everyday" document had a broken link.
+   (merge 366c8d4 po/everyday-doc later to maint).
+
+ * A few test fixes.
+   (merge 880ef58 jk/no-perl-tests later to maint).
+
+ * The build procedure did not bother fixing perl and python scripts
+   when NO_PERL and NO_PYTHON build-time configuration changed.
+   (merge ca2051d jk/rebuild-perl-scripts-with-no-perl-seting-change later to maint).
+
+ * The usage string of "git log" command was marked incorrectly for
+   l10n.
+   (merge e66dc0c km/log-usage-string-i18n later to maint).
+
+ * "git for-each-ref" mishandled --format="%(upstream:track)" when a
+   branch is marked to have forked from a non-existing branch.
+   (merge b6160d9 rc/for-each-ref-tracking later to maint).
diff --git a/Documentation/RelNotes/2.3.1.txt b/Documentation/RelNotes/2.3.1.txt
new file mode 100644
index 0000000000..cf96186288
--- /dev/null
+++ b/Documentation/RelNotes/2.3.1.txt
@@ -0,0 +1,52 @@
+Git v2.3.1 Release Notes
+========================
+
+Fixes since v2.3
+----------------
+
+ * The interactive "show a list and let the user choose from it"
+   interface "add -i" used showed and prompted to the user even when
+   the candidate list was empty, against which the only "choice" the
+   user could have made was to choose nothing.
+
+ * "git apply --whitespace=fix" used to under-allocate the memory
+   when the fix resulted in a longer text than the original patch.
+
+ * "git log --help" used to show rev-list options that are irrelevant
+   to the "log" command.
+
+ * The error message from "git commit", when a non-existing author
+   name was given as value to the "--author=" parameter, has been
+   reworded to avoid misunderstanding.
+
+ * A broken pack .idx file in the receiving repository prevented the
+   dumb http transport from fetching a good copy of it from the other
+   side.
+
+ * The documentation incorrectly said that C(opy) and R(ename) are the
+   only ones that can be followed by the score number in the output in
+   the --raw format.
+
+ * Fix a misspelled conditional that is always true.
+
+ * Code to read branch name from various files in .git/ directory
+   would have misbehaved if the code to write them left an empty file.
+
+ * The "git push" documentation made the "--repo=<there>" option
+   easily misunderstood.
+
+ * After attempting and failing a password-less authentication
+   (e.g. kerberos), libcURL refuses to fall back to password based
+   Basic authentication without a bit of help/encouragement.
+
+ * Setting diff.submodule to 'log' made "git format-patch" produce
+   broken patches.
+
+ * "git rerere" (invoked internally from many mergy operations) did
+   not correctly signal errors when told to update the working tree
+   files and failed to do so for whatever reason.
+
+ * "git blame HEAD -- missing" failed to correctly say "HEAD" when it
+   tried to say "No such path 'missing' in HEAD".
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.10.txt b/Documentation/RelNotes/2.3.10.txt
new file mode 100644
index 0000000000..20c2d2cacc
--- /dev/null
+++ b/Documentation/RelNotes/2.3.10.txt
@@ -0,0 +1,18 @@
+Git v2.3.10 Release Notes
+=========================
+
+Fixes since v2.3.9
+------------------
+
+ * xdiff code we use to generate diffs is not prepared to handle
+   extremely large files.  It uses "int" in many places, which can
+   overflow if we have a very large number of lines or even bytes in
+   our input files, for example.  Cap the input size to somewhere
+   around 1GB for now.
+
+ * Some protocols (like git-remote-ext) can execute arbitrary code
+   found in the URL.  The URLs that submodules use may come from
+   arbitrary sources (e.g., .gitmodules files in a remote
+   repository), and can hurt those who blindly enable recursive
+   fetch.  Restrict the allowed protocols to well known and safe
+   ones.
diff --git a/Documentation/RelNotes/2.3.2.txt b/Documentation/RelNotes/2.3.2.txt
new file mode 100644
index 0000000000..93462e45c2
--- /dev/null
+++ b/Documentation/RelNotes/2.3.2.txt
@@ -0,0 +1,79 @@
+Git v2.3.2 Release Notes
+========================
+
+Fixes since v2.3.1
+------------------
+
+ * "update-index --refresh" used to leak when an entry cannot be
+   refreshed for whatever reason.
+
+ * "git fast-import" used to crash when it could not close and
+   conclude the resulting packfile cleanly.
+
+ * "git blame" died, trying to free an uninitialized piece of memory.
+
+ * "git merge-file" did not work correctly in a subdirectory.
+
+ * "git submodule add" failed to squash "path/to/././submodule" to
+   "path/to/submodule".
+
+ * In v2.2.0, we broke "git prune" that runs in a repository that
+   borrows from an alternate object store.
+
+ * Certain older vintages of cURL give irregular output from
+   "curl-config --vernum", which confused our build system.
+
+ * An earlier workaround to squelch unhelpful deprecation warnings
+   from the compiler on Mac OSX unnecessarily set minimum required
+   version of the OS, which the user might want to raise (or lower)
+   for other reasons.
+
+ * Longstanding configuration variable naming rules has been added to
+   the documentation.
+
+ * The credential helper for Windows (in contrib/) used to mishandle
+   a user name with an at-sign in it.
+
+ * Older GnuPG implementations may not correctly import the keyring
+   material we prepare for the tests to use.
+
+ * Clarify in the documentation that "remote.<nick>.pushURL" and
+   "remote.<nick>.URL" are there to name the same repository accessed
+   via different transports, not two separate repositories.
+
+ * The pack bitmap support did not build with older versions of GCC.
+
+ * Reading configuration from a blob object, when it ends with a lone
+   CR, use to confuse the configuration parser.
+
+ * We didn't format an integer that wouldn't fit in "int" but in
+   "uintmax_t" correctly.
+
+ * "git push --signed" gave an incorrectly worded error message when
+   the other side did not support the capability.
+
+ * "git fetch" over a remote-helper that cannot respond to "list"
+   command could not fetch from a symbolic reference e.g. HEAD.
+
+ * The insn sheet "git rebase -i" creates did not fully honor
+   core.abbrev settings.
+
+ * The tests that wanted to see that file becomes unreadable after
+   running "chmod a-r file", and the tests that wanted to make sure it
+   is not run as root, we used "can we write into the / directory?" as
+   a cheap substitute, but on some platforms that is not a good
+   heuristics.  The tests and their prerequisites have been updated to
+   check what they really require.
+
+ * The configuration variable 'mailinfo.scissors' was hard to
+   discover in the documentation.
+
+ * Correct a breakage to git-svn around v2.2 era that triggers
+   premature closing of FileHandle.
+
+ * Even though we officially haven't dropped Perl 5.8 support, the
+   Getopt::Long package that came with it does not support "--no-"
+   prefix to negate a boolean option; manually add support to help
+   people with older Getopt::Long package.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.3.txt b/Documentation/RelNotes/2.3.3.txt
new file mode 100644
index 0000000000..850dc68ede
--- /dev/null
+++ b/Documentation/RelNotes/2.3.3.txt
@@ -0,0 +1,39 @@
+Git v2.3.3 Release Notes
+========================
+
+Fixes since v2.3.2
+------------------
+
+ * A corrupt input to "git diff -M" used cause us to segfault.
+
+ * The borrowed code in kwset API did not follow our usual convention
+   to use "unsigned char" to store values that range from 0-255.
+
+ * Description given by "grep -h" for its --exclude-standard option
+   was phrased poorly.
+
+ * Documentation for "git remote add" mentioned "--tags" and
+   "--no-tags" and it was not clear that fetch from the remote in
+   the future will use the default behaviour when neither is given
+   to override it.
+
+ * "git diff --shortstat --dirstat=changes" showed a dirstat based on
+   lines that was never asked by the end user in addition to the
+   dirstat that the user asked for.
+
+ * The interaction between "git submodule update" and the
+   submodule.*.update configuration was not clearly documented.
+
+ * "git apply" was not very careful about reading from, removing,
+   updating and creating paths outside the working tree (under
+   --index/--cached) or the current directory (when used as a
+   replacement for GNU patch).
+
+ * "git daemon" looked up the hostname even when "%CH" and "%IP"
+   interpolations are not requested, which was unnecessary.
+
+ * The "interpolated-path" option of "git daemon" inserted any string
+   client declared on the "host=" capability request without checking.
+   Sanitize and limit %H and %CH to a saner and a valid DNS name.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.4.txt b/Documentation/RelNotes/2.3.4.txt
new file mode 100644
index 0000000000..094c7b853b
--- /dev/null
+++ b/Documentation/RelNotes/2.3.4.txt
@@ -0,0 +1,32 @@
+Git v2.3.4 Release Notes
+========================
+
+Fixes since v2.3.3
+------------------
+
+ * The 'color.status.unmerged' configuration was not described.
+
+ * "git log --decorate" did not reset colors correctly around the
+   branch names.
+
+ * "git -C '' subcmd" refused to work in the current directory, unlike
+   "cd ''" which silently behaves as a no-op.
+
+ * "git imap-send" learned to optionally talk with an IMAP server via
+   libcURL; because there is no other option when Git is built with
+   NO_OPENSSL option, use that codepath by default under such
+   configuration.
+
+ * A workaround for certain build of GPG that triggered false breakage
+   in a test has been added.
+
+ * "git rebase -i" recently started to include the number of
+   commits in the insn sheet to be processed, but on a platform
+   that prepends leading whitespaces to "wc -l" output, the numbers
+   are shown with extra whitespaces that aren't necessary.
+
+ * We did not parse username followed by literal IPv6 address in SSH
+   transport URLs, e.g. ssh://user@[2001:db8::1]:22/repo.git
+   correctly.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.5.txt b/Documentation/RelNotes/2.3.5.txt
new file mode 100644
index 0000000000..5b309db689
--- /dev/null
+++ b/Documentation/RelNotes/2.3.5.txt
@@ -0,0 +1,44 @@
+Git v2.3.5 Release Notes
+========================
+
+Fixes since v2.3.4
+------------------
+
+ * The prompt script (in contrib/) did not show the untracked sign
+   when working in a subdirectory without any untracked files.
+
+ * Even though "git grep --quiet" is run merely to ask for the exit
+   status, we spawned the pager regardless.  Stop doing that.
+
+ * Recommend format-patch and send-email for those who want to submit
+   patches to this project.
+
+ * An failure early in the "git clone" that started creating the
+   working tree and repository could have resulted in some directories
+   and files left without getting cleaned up.
+
+ * "git fetch" that fetches a commit using the allow-tip-sha1-in-want
+   extension could have failed to fetch all the requested refs.
+
+ * The split-index mode introduced at v2.3.0-rc0~41 was broken in the
+   codepath to protect us against a broken reimplementation of Git
+   that writes an invalid index with duplicated index entries, etc.
+
+ * "git prune" used to largely ignore broken refs when deciding which
+   objects are still being used, which could spread an existing small
+   damage and make it a larger one.
+
+ * "git tag -h" used to show the "--column" and "--sort" options
+   that are about listing in a wrong section.
+
+ * The transfer.hiderefs support did not quite work for smart-http
+   transport.
+
+ * The code that reads from the ctags file in the completion script
+   (in contrib/) did not spell ${param/pattern/string} substitution
+   correctly, which happened to work with bash but not with zsh.
+
+ * The explanation on "rebase --preserve-merges", "pull --rebase=preserve",
+   and "push --force-with-lease" in the documentation was unclear.
+
+Also contains typofixes, documentation updates and trivial code clean-ups.
diff --git a/Documentation/RelNotes/2.3.6.txt b/Documentation/RelNotes/2.3.6.txt
new file mode 100644
index 0000000000..432f770ef3
--- /dev/null
+++ b/Documentation/RelNotes/2.3.6.txt
@@ -0,0 +1,13 @@
+Git v2.3.6 Release Notes
+========================
+
+Fixes since v2.3.5
+------------------
+
+ * "diff-highlight" (in contrib/) used to show byte-by-byte
+   differences, which meant that multi-byte characters can be chopped
+   in the middle.  It learned to pay attention to character boundaries
+   (assuming the UTF-8 payload).
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.3.7.txt b/Documentation/RelNotes/2.3.7.txt
new file mode 100644
index 0000000000..5769184081
--- /dev/null
+++ b/Documentation/RelNotes/2.3.7.txt
@@ -0,0 +1,21 @@
+Git v2.3.7 Release Notes
+========================
+
+Fixes since v2.3.6
+------------------
+
+ * An earlier update to the parser that dissects a URL broke an
+   address, followed by a colon, followed by an empty string (instead
+   of the port number), e.g. ssh://example.com:/path/to/repo.
+
+ * The completion script (in contrib/) contaminated global namespace
+   and clobbered on a shell variable $x.
+
+ * The "git push --signed" protocol extension did not limit what the
+   "nonce" that is a server-chosen string can contain or how long it
+   can be, which was unnecessarily lax.  Limit both the length and the
+   alphabet to a reasonably small space that can still have enough
+   entropy.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.3.8.txt b/Documentation/RelNotes/2.3.8.txt
new file mode 100644
index 0000000000..0b67268a96
--- /dev/null
+++ b/Documentation/RelNotes/2.3.8.txt
@@ -0,0 +1,22 @@
+Git v2.3.8 Release Notes
+========================
+
+Fixes since v2.3.7
+------------------
+
+ * The usual "git diff" when seeing a file turning into a directory
+   showed a patchset to remove the file and create all files in the
+   directory, but "git diff --no-index" simply refused to work.  Also,
+   when asked to compare a file and a directory, imitate POSIX "diff"
+   and compare the file with the file with the same name in the
+   directory, instead of refusing to run.
+
+ * The default $HOME/.gitconfig file created upon "git config --global"
+   that edits it had incorrectly spelled user.name and user.email
+   entries in it.
+
+ * "git commit --date=now" or anything that relies on approxidate lost
+   the daylight-saving-time offset.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.3.9.txt b/Documentation/RelNotes/2.3.9.txt
new file mode 100644
index 0000000000..1a2ad3235a
--- /dev/null
+++ b/Documentation/RelNotes/2.3.9.txt
@@ -0,0 +1,9 @@
+Git v2.3.9 Release Notes
+========================
+
+Fixes since v2.3.8
+------------------
+
+ * A handful of codepaths that used to use fixed-sized arrays to hold
+   pathnames have been corrected to use strbuf and other mechanisms to
+   allow longer pathnames without fearing overflows.
diff --git a/Documentation/RelNotes/2.30.0.txt b/Documentation/RelNotes/2.30.0.txt
new file mode 100644
index 0000000000..c2f1dc7b06
--- /dev/null
+++ b/Documentation/RelNotes/2.30.0.txt
@@ -0,0 +1,401 @@
+Git 2.30 Release Notes
+======================
+
+Updates since v2.29
+-------------------
+
+UI, Workflows & Features
+
+ * Userdiff for PHP update.
+
+ * Userdiff for Rust update.
+
+ * Userdiff for CSS update.
+
+ * The command line completion script (in contrib/) learned that "git
+   stash show" takes the options "git diff" takes.
+
+ * "git worktree list" now shows if each worktree is locked.  This
+   possibly may open us to show other kinds of states in the future.
+
+ * "git maintenance", an extended big brother of "git gc", continues
+   to evolve.
+
+ * "git push --force-with-lease[=<ref>]" can easily be misused to lose
+   commits unless the user takes good care of their own "git fetch".
+   A new option "--force-if-includes" attempts to ensure that what is
+   being force-pushed was created after examining the commit at the
+   tip of the remote ref that is about to be force-replaced.
+
+ * "git clone" learned clone.defaultremotename configuration variable
+   to customize what nickname to use to call the remote the repository
+   was cloned from.
+
+ * "git checkout" learned to use checkout.guess configuration variable
+   and enable/disable its "--[no-]guess" option accordingly.
+
+ * "git resurrect" script (in contrib/) learned that the object names
+   may be longer than 40-hex depending on the hash function in use.
+
+ * "git diff A...B" learned "git diff --merge-base A B", which is a
+   longer short-hand to say the same thing.
+
+ * A sample 'push-to-checkout' hook, that performs the same as
+   what the built-in default action does, has been added.
+
+ * "git diff" family of commands learned the "-I<regex>" option to
+   ignore hunks whose changed lines all match the given pattern.
+
+ * The userdiff pattern learned to identify the function definition in
+   POSIX shells and bash.
+
+ * "git checkout-index" did not consistently signal an error with its
+   exit status, but now it does.
+
+ * A commit and tag object may have CR at the end of each and
+   every line (you can create such an object with hash-object or
+   using --cleanup=verbatim to decline the default clean-up
+   action), but it would make it impossible to have a blank line
+   to separate the title from the body of the message.  We are now
+   more lenient and accept a line with lone CR on it as a blank line,
+   too.
+
+ * Exit codes from "git remote add" etc. were not usable by scripted
+   callers, but now they are.
+
+ * "git archive" now allows compression level higher than "-9"
+   when generating tar.gz output.
+
+ * Zsh autocompletion (in contrib/) update.
+
+ * The maximum length of output filenames "git format-patch" creates
+   has become configurable (used to be capped at 64).
+
+ * "git rev-parse" learned the "--end-of-options" to help scripts to
+   safely take a parameter that is supposed to be a revision, e.g.
+   "git rev-parse --verify -q --end-of-options $rev".
+
+ * The command line completion script (in contrib/) learned to expand
+   commands that are alias of alias.
+
+ * "git update-ref --stdin" learns to take multiple transactions in a
+   single session.
+
+ * Various subcommands of "git config" that take value_regex
+   learned the "--literal-value" option to take the value_regex option
+   as a literal string.
+
+ * The transport layer was taught to optionally exchange the session
+   ID assigned by the trace2 subsystem during fetch/push transactions.
+
+ * "git imap-send" used to ignore configuration variables like
+   core.askpass; this has been corrected.
+
+ * "git $cmd $args", when $cmd is not a recognised subcommand, by
+   default tries to see if $cmd is a typo of an existing subcommand
+   and optionally executes the corrected command if there is only one
+   possibility, depending on the setting of help.autocorrect; the
+   users can now disable the whole thing, including the cycles spent
+   to find a likely typo, by setting the configuration variable to
+   'never'.
+
+ * "@" sometimes worked (e.g. "git push origin @:there") as a part of
+   a refspec element, but "git push origin @" did not work, which has
+   been corrected.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Use "git archive" more to produce the release tarball.
+
+ * GitHub Actions automated test improvement to skip tests on a tree
+   identical to what has already been tested.
+
+ * Test-coverage for running commit-graph task "git maintenance" has
+   been extended.
+
+ * Our test scripts can be told to run only individual pieces while
+   skipping others with the "--run=..." option; they were taught to
+   take a substring of test title, in addition to numbers, to name the
+   test pieces to run.
+
+ * Adjust tests so that they won't scream when the default initial
+   branch name is different from 'master'.
+
+ * Rewriting "git bisect" in C continues.
+
+ * More preliminary tests have been added to document desired outcomes
+   of various "directory rename" situations.
+
+ * Micro clean-up of a couple of test scripts.
+
+ * "git diff" and other commands that share the same machinery to
+   compare with working tree files have been taught to take advantage
+   of the fsmonitor data when available.
+
+ * The code to detect premature EOF in the sideband demultiplexer has
+   been cleaned up.
+
+ * "git fetch --depth=<n>" over the stateless RPC / smart HTTP
+   transport handled EOF from the client poorly at the server end.
+
+ * A specialization of hashmap that uses a string as key has been
+   introduced.  Hopefully it will see wider use over time.
+
+ * "git bisect start/next" in a large span of history spends a lot of
+   time trying to come up with exactly the half-way point; this can be
+   optimized by stopping when we see a commit that is close enough to
+   the half-way point.
+
+ * A lazily defined test prerequisite can now be defined in terms of
+   another lazily defined test prerequisite.
+
+ * Expectation for the original contributor after responding to a
+   review comment to use the explanation in a patch update has been
+   described.
+
+ * Multiple "credential-store" backends can race to lock the same
+   file, causing everybody else but one to fail---reattempt locking
+   with some timeout to reduce the rate of the failure.
+
+ * "git-parse-remote" shell script library outlived its usefulness.
+
+ * Like die() and error(), a call to warning() will also trigger a
+   trace2 event.
+
+ * Use of non-reentrant localtime() has been removed.
+
+ * Non-reentrant time-related library functions and ctime/asctime with
+   awkward calling interfaces are banned from the codebase.
+
+
+Fixes since v2.29
+-----------------
+
+ * In 2.29, "--committer-date-is-author-date" option of "rebase" and
+   "am" subcommands lost the e-mail address by mistake, which has been
+   corrected.
+   (merge 5f35edd9d7 jk/committer-date-is-author-date-fix later to maint).
+
+ * "git checkout -p A...B [-- <path>]" did not work, even though the
+   same command without "-p" correctly used the merge-base between
+   commits A and B.
+   (merge 35166b1fb5 dl/checkout-p-merge-base later to maint).
+
+ * The side-band status report can be sent at the same time as the
+   primary payload multiplexed, but the demultiplexer on the receiving
+   end incorrectly split a single status report into two, which has
+   been corrected.
+   (merge 712b0377db js/avoid-split-sideband-message later to maint).
+
+ * "git fast-import" wasted a lot of memory when many marks were in use.
+   (merge 3f018ec716 jk/fast-import-marks-alloc-fix later to maint).
+
+ * A test helper "test_cmp A B" was taught to diagnose missing files A
+   or B as a bug in test, but some tests legitimately wanted to notice
+   a failure to even create file B as an error, in addition to leaving
+   the expected result in it, and were misdiagnosed as a bug.  This
+   has been corrected.
+   (merge 262d5ad5a5 es/test-cmp-typocatcher later to maint).
+
+ * When "git commit-graph" detects the same commit recorded more than
+   once while it is merging the layers, it used to die.  The code now
+   ignores all but one of them and continues.
+   (merge 85102ac71b ds/commit-graph-merging-fix later to maint).
+
+ * The meaning of a Signed-off-by trailer can vary from project to
+   project; this and also what it means to this project has been
+   clarified in the documentation.
+   (merge 3abd4a67d9 bk/sob-dco later to maint).
+
+ * "git credential' didn't honor the core.askPass configuration
+   variable (among other things), which has been corrected.
+   (merge 567ad2c0f9 tk/credential-config later to maint).
+
+ * Dev support to catch a tentative definition of a variable in our C
+   code as an error.
+   (merge 5539183622 jk/no-common later to maint).
+
+ * "git rebase --rebase-merges" did not correctly pass --gpg-sign
+   command line option to underlying "git merge" when replaying a merge
+   using non-default merge strategy or when replaying an octopus merge
+   (because replaying a two-head merge with the default strategy was
+   done in a separate codepath, the problem did not trigger for most
+   users), which has been corrected.
+   (merge 43ad4f2eca sc/sequencer-gpg-octopus later to maint).
+
+ * "git apply -R" did not handle patches that touch the same path
+   twice correctly, which has been corrected.  This is most relevant
+   in a patch that changes a path from a regular file to a symbolic
+   link (and vice versa).
+   (merge b0f266de11 jt/apply-reverse-twice later to maint).
+
+ * A recent oid->hash conversion missed one spot, breaking "git svn".
+   (merge 03bb366de4 bc/svn-hash-oid-fix later to maint).
+
+ * The documentation on the "--abbrev=<n>" option did not say the
+   output may be longer than "<n>" hexdigits, which has been
+   clarified.
+   (merge cda34e0d0c jc/abbrev-doc later to maint).
+
+ * "git p4" now honors init.defaultBranch configuration.
+   (merge 1b09d1917f js/p4-default-branch later to maint).
+
+ * Recently the format of an internal state file "rebase -i" uses has
+   been tightened up for consistency, which would hurt those who start
+   "rebase -i" with old git and then continue with new git.  Loosen
+   the reader side a bit (which we may want to tighten again in a year
+   or so).
+   (merge c779386182 jc/sequencer-stopped-sha-simplify later to maint).
+
+ * The code to see if "git stash drop" can safely remove refs/stash
+   has been made more careful.
+   (merge 4f44c5659b rs/empty-reflog-check-fix later to maint).
+
+ * "git log -L<range>:<path>" is documented to take no pathspec, but
+   this was not enforced by the command line option parser, which has
+   been corrected.
+   (merge 39664cb0ac jc/line-log-takes-no-pathspec later to maint).
+
+ * "git format-patch --output=there" did not work as expected and
+   instead crashed.  The option is now supported.
+   (merge dc1672dd10 jk/format-patch-output later to maint).
+
+ * Define ARM64 compiled with MSVC to be little-endian.
+   (merge 0c038fc65a dg/bswap-msvc later to maint).
+
+ * "git rebase -i" did not store ORIG_HEAD correctly.
+   (merge 8843302307 pw/rebase-i-orig-head later to maint).
+
+ * "git blame -L :funcname -- path" did not work well for a path for
+   which a userdiff driver is defined.
+
+ * "make DEVELOPER=1 sparse" used to run sparse and let it emit
+   warnings; now such warnings will cause an error.
+   (merge 521dc56270 jc/sparse-error-for-developer-build later to maint).
+
+ * "git blame --ignore-revs-file=<file>" learned to ignore a
+   non-existent object name in the input, instead of complaining.
+   (merge c714d05875 jc/blame-ignore-fix later to maint).
+
+ * Running "git diff" while allowing external diff in a state with
+   unmerged paths used to segfault, which has been corrected.
+   (merge d66851806f jk/diff-release-filespec-fix later to maint).
+
+ * Build configuration cleanup.
+   (merge b990f02fd8 ab/config-mak-uname-simplify later to maint).
+
+ * Fix regression introduced when nvimdiff support in mergetool was added.
+   (merge 12026f46e7 pd/mergetool-nvimdiff later to maint).
+
+ * The exchange between receive-pack and proc-receive hook did not
+   carefully check for errors.
+
+ * The code was not prepared to deal with pack .idx file that is
+   larger than 4GB.
+   (merge 81c4c5cf2e jk/4gb-idx later to maint).
+
+ * Since jgit does not yet work with SHA-256 repositories, mark the
+   tests that use it not to run unless we are testing with ShA-1
+   repositories.
+   (merge ea699b4adc sg/t5310-jgit-wants-sha1 later to maint).
+
+ * Config parser fix for "git notes".
+   (merge 45fef1599a na/notes-displayref-is-not-boolean later to maint).
+
+ * Move a definition of compatibility wrapper from cache.h to
+   git-compat-util.h
+   (merge a76b138daa hn/sleep-millisec-decl later to maint).
+
+ * Error message fix.
+   (merge eaf5341538 km/stash-error-message-fix later to maint).
+
+ * "git pull --rebase --recurse-submodules" checked for local changes
+   in a wrong range and failed to run correctly when it should.
+   (merge 5176f20ffe pb/pull-rebase-recurse-submodules later to maint).
+
+ * "git push" that is killed may leave a pack-objects process behind,
+   still computing to find a good compression, wasting cycles.  This
+   has been corrected.
+   (merge 8b59935114 jk/stop-pack-objects-when-push-is-killed later to maint).
+
+ * "git fetch" that is killed may leave a pack-objects process behind,
+   still computing to find a good compression, wasting cycles.  This
+   has been corrected.
+   (merge 309a4028e7 jk/stop-pack-objects-when-fetch-is-killed later to maint).
+
+ * "git add -i" failed to honor custom colors configured to show
+   patches, which has been corrected.
+   (merge 96386faa03 js/add-i-color-fix later to maint).
+
+ * Processes that access packdata while the .idx file gets removed
+   (e.g. while repacking) did not fail or fall back gracefully as they
+   could.
+   (merge 506ec2fbda tb/idx-midx-race-fix later to maint).
+
+ * "git apply" adjusted the permission bits of working-tree files and
+   directories according to core.sharedRepository setting by mistake and
+   for a long time, which has been corrected.
+   (merge eb3c027e17 mt/do-not-use-scld-in-working-tree later to maint).
+
+ * "fetch-pack" could pass NULL pointer to unlink(2) when it sees an
+   invalid filename; the error checking has been tightened to make
+   this impossible.
+   (merge 6031af387e rs/fetch-pack-invalid-lockfile later to maint).
+
+ * "git maintenance run/start/stop" needed to be run in a repository
+   to hold the lockfile they use, but didn't make sure they are
+   actually in a repository, which has been corrected.
+
+ * The glossary described a branch as an "active" line of development,
+   which is misleading---a stale and non-moving branch is still a
+   branch.
+   (merge eef1ceabd8 so/glossary-branch-is-not-necessarily-active later to maint).
+
+ * Newer versions of xsltproc can assign IDs in HTML documents it
+   generates in a consistent manner.  Use the feature to help format
+   HTML version of the user manual reproducibly.
+   (merge 3569e11d69 ae/doc-reproducible-html later to maint).
+
+ * Tighten error checking in the codepath that responds to "git fetch".
+   (merge d43a21bdbb jk/check-config-parsing-error-in-upload-pack later to maint).
+
+ * "git pack-redundant" when there is only one packfile used to crash,
+   which has been corrected.
+   (merge 0696232390 jx/pack-redundant-on-single-pack later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 3e0a5dc9af cc/doc-filter-branch-typofix later to maint).
+   (merge 32c83afc2c cw/ci-ghwf-check-ws-errors later to maint).
+   (merge 5eb2ed691b rs/tighten-callers-of-deref-tag later to maint).
+   (merge 6db29ab213 jk/fast-import-marks-cleanup later to maint).
+   (merge e5cf6d3df4 nk/dir-c-comment-update later to maint).
+   (merge 5710dcce74 jk/report-fn-typedef later to maint).
+   (merge 9a82db1056 en/sequencer-rollback-lock-cleanup later to maint).
+   (merge 4e1bee9a99 js/t7006-cleanup later to maint).
+   (merge f5bcde6c58 es/tutorial-mention-asciidoc-early later to maint).
+   (merge 714d491af0 so/format-patch-doc-on-default-diff-format later to maint).
+   (merge 0795df4b9b rs/clear-commit-marks-in-repo later to maint).
+   (merge 9542d56379 sd/prompt-local-variable later to maint).
+   (merge 06d43fad18 rs/pack-write-hashwrite-simplify later to maint).
+   (merge b7e20b4373 mc/typofix later to maint).
+   (merge f6bcd9a8a4 js/test-whitespace-fixes later to maint).
+   (merge 53b67a801b js/test-file-size later to maint).
+   (merge 970909c2a7 rs/hashwrite-be64 later to maint).
+   (merge 5a923bb1f0 ma/list-object-filter-opt-msgfix later to maint).
+   (merge 1c3e412916 rs/archive-plug-leak-refname later to maint).
+   (merge d44e5267ea rs/plug-diff-cache-leak later to maint).
+   (merge 793c1464d3 ab/gc-keep-base-option later to maint).
+   (merge b86339b12b mt/worktree-error-message-fix later to maint).
+   (merge e01ae2a4a7 js/pull-rebase-use-advise later to maint).
+   (merge e63d774242 sn/config-doc-typofix later to maint).
+   (merge 08e9df2395 jk/multi-line-indent-style-fix later to maint).
+   (merge e66590348a da/vs-build-iconv-fix later to maint).
+   (merge 7fe07275be js/cmake-extra-built-ins-fix later to maint).
+   (merge 633eebe142 jb/midx-doc-update later to maint).
+   (merge 5885367e8f jh/index-v2-doc-on-fsmn later to maint).
+   (merge 14639a4779 jc/compat-util-setitimer-fix later to maint).
+   (merge 56f56ac50b ab/unreachable-break later to maint).
+   (merge 731d578b4f rb/nonstop-config-mak-uname-update later to maint).
+   (merge f4698738f9 es/perf-export-fix later to maint).
+   (merge 773c694142 nk/refspecs-negative-fix later to maint).
diff --git a/Documentation/RelNotes/2.30.1.txt b/Documentation/RelNotes/2.30.1.txt
new file mode 100644
index 0000000000..249ef1492f
--- /dev/null
+++ b/Documentation/RelNotes/2.30.1.txt
@@ -0,0 +1,55 @@
+Git v2.30.1 Release Notes
+=========================
+
+This release is primarily to merge fixes accumulated on the 'master'
+front to prepare for 2.31 release that are still relevant to 2.30.x
+maintenance track.
+
+Fixes since v2.30
+-----------------
+
+ * "git fetch --recurse-submodules" failed to update a submodule
+   when it has an uninitialized (hence of no interest to the user)
+   sub-submodule, which has been corrected.
+
+ * Command line error of "git rebase" are diagnosed earlier.
+
+ * "git stash" did not work well in a sparsely checked out working
+   tree.
+
+ * Some tests expect that "ls -l" output has either '-' or 'x' for
+   group executable bit, but setgid bit can be inherited from parent
+   directory and make these fields 'S' or 's' instead, causing test
+   failures.
+
+ * "git for-each-repo --config=<var> <cmd>" should not run <cmd> for
+   any repository when the configuration variable <var> is not defined
+   even once.
+
+ * "git mergetool --tool-help" was broken in 2.29 and failed to list
+   all the available tools.
+
+ * Fix for procedure to building CI test environment for mac.
+
+ * Newline characters in the host and path part of git:// URL are
+   now forbidden.
+
+ * When more than one commit with the same patch ID appears on one
+   side, "git log --cherry-pick A...B" did not exclude them all when a
+   commit with the same patch ID appears on the other side.  Now it
+   does.
+
+ * Documentation for "git fsck" lost stale bits that has become
+   incorrect.
+
+ * Doc for packfile URI feature has been clarified.
+
+ * The implementation of "git branch --sort" wrt the detached HEAD
+   display has always been hacky, which has been cleaned up.
+
+ * Our setting of GitHub CI test jobs were a bit too eager to give up
+   once there is even one failure found.  Tweak the knob to allow
+   other jobs keep running even when we see a failure, so that we can
+   find more failures in a single run.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.30.2.txt b/Documentation/RelNotes/2.30.2.txt
new file mode 100644
index 0000000000..bada398501
--- /dev/null
+++ b/Documentation/RelNotes/2.30.2.txt
@@ -0,0 +1,8 @@
+Git v2.30.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.17.6, v2.18.5,
+v2.19.6, v2.20.5, v2.21.4, v2.22.5, v2.23.4, v2.24.4, v2.25.5,
+v2.26.3, v2.27.1, v2.28.1 and v2.29.3 to address the security
+issue CVE-2021-21300; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.30.3.txt b/Documentation/RelNotes/2.30.3.txt
new file mode 100644
index 0000000000..31b2a4daa6
--- /dev/null
+++ b/Documentation/RelNotes/2.30.3.txt
@@ -0,0 +1,24 @@
+Git v2.30.2 Release Notes
+=========================
+
+This release addresses the security issue CVE-2022-24765.
+
+Fixes since v2.30.2
+-------------------
+
+ * Build fix on Windows.
+
+ * Fix `GIT_CEILING_DIRECTORIES` with Windows-style root directories.
+
+ * CVE-2022-24765:
+   On multi-user machines, Git users might find themselves
+   unexpectedly in a Git worktree, e.g. when another user created a
+   repository in `C:\.git`, in a mounted network drive or in a
+   scratch space. Merely having a Git-aware prompt that runs `git
+   status` (or `git diff`) and navigating to a directory which is
+   supposedly not a Git worktree, or opening such a directory in an
+   editor or IDE such as VS Code or Atom, will potentially run
+   commands defined by that other user.
+
+Credit for finding this vulnerability goes to 俞晨东; The fix was
+authored by Johannes Schindelin.
diff --git a/Documentation/RelNotes/2.30.4.txt b/Documentation/RelNotes/2.30.4.txt
new file mode 100644
index 0000000000..4eedb74b16
--- /dev/null
+++ b/Documentation/RelNotes/2.30.4.txt
@@ -0,0 +1,21 @@
+Git v2.30.4 Release Notes
+=========================
+
+This release contains minor fix-ups for the changes that went into
+Git 2.30.3, which was made to address CVE-2022-24765.
+
+ * The code that was meant to parse the new `safe.directory`
+   configuration variable was not checking what configuration
+   variable was being fed to it, which has been corrected.
+
+ * '*' can be used as the value for the `safe.directory` variable to
+   signal that the user considers that any directory is safe.
+
+
+
+Derrick Stolee (2):
+      t0033: add tests for safe.directory
+      setup: opt-out of check with safe.directory=*
+
+Matheus Valadares (1):
+      setup: fix safe.directory key not being checked
diff --git a/Documentation/RelNotes/2.30.5.txt b/Documentation/RelNotes/2.30.5.txt
new file mode 100644
index 0000000000..5191cab3ae
--- /dev/null
+++ b/Documentation/RelNotes/2.30.5.txt
@@ -0,0 +1,12 @@
+Git v2.30.5 Release Notes
+=========================
+
+This release contains minor fix-ups for the changes that went into
+Git 2.30.3 and 2.30.4, addressing CVE-2022-29187.
+
+ * The safety check that verifies a safe ownership of the Git
+   worktree is now extended to also cover the ownership of the Git
+   directory (and the `.git` file, if there is any).
+
+Carlo Marcelo Arenas Belón (1):
+      setup: tighten ownership checks post CVE-2022-24765
diff --git a/Documentation/RelNotes/2.30.6.txt b/Documentation/RelNotes/2.30.6.txt
new file mode 100644
index 0000000000..d649071b79
--- /dev/null
+++ b/Documentation/RelNotes/2.30.6.txt
@@ -0,0 +1,60 @@
+Git v2.30.6 Release Notes
+=========================
+
+This release addresses the security issues CVE-2022-39253 and
+CVE-2022-39260.
+
+Fixes since v2.30.5
+-------------------
+
+ * CVE-2022-39253:
+   When relying on the `--local` clone optimization, Git dereferences
+   symbolic links in the source repository before creating hardlinks
+   (or copies) of the dereferenced link in the destination repository.
+   This can lead to surprising behavior where arbitrary files are
+   present in a repository's `$GIT_DIR` when cloning from a malicious
+   repository.
+
+   Git will no longer dereference symbolic links via the `--local`
+   clone mechanism, and will instead refuse to clone repositories that
+   have symbolic links present in the `$GIT_DIR/objects` directory.
+
+   Additionally, the value of `protocol.file.allow` is changed to be
+   "user" by default.
+
+ * CVE-2022-39260:
+   An overly-long command string given to `git shell` can result in
+   overflow in `split_cmdline()`, leading to arbitrary heap writes and
+   remote code execution when `git shell` is exposed and the directory
+   `$HOME/git-shell-commands` exists.
+
+   `git shell` is taught to refuse interactive commands that are
+   longer than 4MiB in size. `split_cmdline()` is hardened to reject
+   inputs larger than 2GiB.
+
+Credit for finding CVE-2022-39253 goes to Cory Snider of Mirantis. The
+fix was authored by Taylor Blau, with help from Johannes Schindelin.
+
+Credit for finding CVE-2022-39260 goes to Kevin Backhouse of GitHub.
+The fix was authored by Kevin Backhouse, Jeff King, and Taylor Blau.
+
+
+Jeff King (2):
+      shell: add basic tests
+      shell: limit size of interactive commands
+
+Kevin Backhouse (1):
+      alias.c: reject too-long cmdline strings in split_cmdline()
+
+Taylor Blau (11):
+      builtin/clone.c: disallow `--local` clones with symlinks
+      t/lib-submodule-update.sh: allow local submodules
+      t/t1NNN: allow local submodules
+      t/2NNNN: allow local submodules
+      t/t3NNN: allow local submodules
+      t/t4NNN: allow local submodules
+      t/t5NNN: allow local submodules
+      t/t6NNN: allow local submodules
+      t/t7NNN: allow local submodules
+      t/t9NNN: allow local submodules
+      transport: make `protocol.file.allow` be "user" by default
diff --git a/Documentation/RelNotes/2.30.7.txt b/Documentation/RelNotes/2.30.7.txt
new file mode 100644
index 0000000000..285beed232
--- /dev/null
+++ b/Documentation/RelNotes/2.30.7.txt
@@ -0,0 +1,86 @@
+Git v2.30.7 Release Notes
+=========================
+
+This release addresses the security issues CVE-2022-41903 and
+CVE-2022-23521.
+
+
+Fixes since v2.30.6
+-------------------
+
+ * CVE-2022-41903:
+
+   git log has the ability to display commits using an arbitrary
+   format with its --format specifiers. This functionality is also
+   exposed to git archive via the export-subst gitattribute.
+
+   When processing the padding operators (e.g., %<(, %<|(, %>(,
+   %>>(, or %><( ), an integer overflow can occur in
+   pretty.c::format_and_pad_commit() where a size_t is improperly
+   stored as an int, and then added as an offset to a subsequent
+   memcpy() call.
+
+   This overflow can be triggered directly by a user running a
+   command which invokes the commit formatting machinery (e.g., git
+   log --format=...). It may also be triggered indirectly through
+   git archive via the export-subst mechanism, which expands format
+   specifiers inside of files within the repository during a git
+   archive.
+
+   This integer overflow can result in arbitrary heap writes, which
+   may result in remote code execution.
+
+* CVE-2022-23521:
+
+    gitattributes are a mechanism to allow defining attributes for
+    paths. These attributes can be defined by adding a `.gitattributes`
+    file to the repository, which contains a set of file patterns and
+    the attributes that should be set for paths matching this pattern.
+
+    When parsing gitattributes, multiple integer overflows can occur
+    when there is a huge number of path patterns, a huge number of
+    attributes for a single pattern, or when the declared attribute
+    names are huge.
+
+    These overflows can be triggered via a crafted `.gitattributes` file
+    that may be part of the commit history. Git silently splits lines
+    longer than 2KB when parsing gitattributes from a file, but not when
+    parsing them from the index. Consequentially, the failure mode
+    depends on whether the file exists in the working tree, the index or
+    both.
+
+    This integer overflow can result in arbitrary heap reads and writes,
+    which may result in remote code execution.
+
+Credit for finding CVE-2022-41903 goes to Joern Schneeweisz of GitLab.
+An initial fix was authored by Markus Vervier of X41 D-Sec. Credit for
+finding CVE-2022-23521 goes to Markus Vervier and Eric Sesterhenn of X41
+D-Sec. This work was sponsored by OSTIF.
+
+The proposed fixes have been polished and extended to cover additional
+findings by Patrick Steinhardt of GitLab, with help from others on the
+Git security mailing list.
+
+Patrick Steinhardt (21):
+      attr: fix overflow when upserting attribute with overly long name
+      attr: fix out-of-bounds read with huge attribute names
+      attr: fix integer overflow when parsing huge attribute names
+      attr: fix out-of-bounds write when parsing huge number of attributes
+      attr: fix out-of-bounds read with unreasonable amount of patterns
+      attr: fix integer overflow with more than INT_MAX macros
+      attr: harden allocation against integer overflows
+      attr: fix silently splitting up lines longer than 2048 bytes
+      attr: ignore attribute lines exceeding 2048 bytes
+      attr: ignore overly large gitattributes files
+      pretty: fix out-of-bounds write caused by integer overflow
+      pretty: fix out-of-bounds read when left-flushing with stealing
+      pretty: fix out-of-bounds read when parsing invalid padding format
+      pretty: fix adding linefeed when placeholder is not expanded
+      pretty: fix integer overflow in wrapping format
+      utf8: fix truncated string lengths in `utf8_strnwidth()`
+      utf8: fix returning negative string width
+      utf8: fix overflow when returning string width
+      utf8: fix checking for glyph width in `strbuf_utf8_replace()`
+      utf8: refactor `strbuf_utf8_replace` to not rely on preallocated buffer
+      pretty: restrict input lengths for padding and wrapping formats
+
diff --git a/Documentation/RelNotes/2.30.8.txt b/Documentation/RelNotes/2.30.8.txt
new file mode 100644
index 0000000000..5ed3efbd6a
--- /dev/null
+++ b/Documentation/RelNotes/2.30.8.txt
@@ -0,0 +1,51 @@
+Git v2.30.8 Release Notes
+=========================
+
+This release addresses the security issues CVE-2023-22490 and
+CVE-2023-23946.
+
+
+Fixes since v2.30.7
+-------------------
+
+ * CVE-2023-22490:
+
+   Using a specially-crafted repository, Git can be tricked into using
+   its local clone optimization even when using a non-local transport.
+   Though Git will abort local clones whose source $GIT_DIR/objects
+   directory contains symbolic links (c.f., CVE-2022-39253), the objects
+   directory itself may still be a symbolic link.
+
+   These two may be combined to include arbitrary files based on known
+   paths on the victim's filesystem within the malicious repository's
+   working copy, allowing for data exfiltration in a similar manner as
+   CVE-2022-39253.
+
+ * CVE-2023-23946:
+
+   By feeding a crafted input to "git apply", a path outside the
+   working tree can be overwritten as the user who is running "git
+   apply".
+
+ * A mismatched type in `attr.c::read_attr_from_index()` which could
+   cause Git to errantly reject attributes on Windows and 32-bit Linux
+   has been corrected.
+
+Credit for finding CVE-2023-22490 goes to yvvdwf, and the fix was
+developed by Taylor Blau, with additional help from others on the
+Git security mailing list.
+
+Credit for finding CVE-2023-23946 goes to Joern Schneeweisz, and the
+fix was developed by Patrick Steinhardt.
+
+
+Johannes Schindelin (1):
+      attr: adjust a mismatched data type
+
+Patrick Steinhardt (1):
+      apply: fix writing behind newly created symbolic links
+
+Taylor Blau (3):
+      t5619: demonstrate clone_local() with ambiguous transport
+      clone: delay picking a transport until after get_repo_path()
+      dir-iterator: prevent top-level symlinks without FOLLOW_SYMLINKS
diff --git a/Documentation/RelNotes/2.30.9.txt b/Documentation/RelNotes/2.30.9.txt
new file mode 100644
index 0000000000..708d626ce6
--- /dev/null
+++ b/Documentation/RelNotes/2.30.9.txt
@@ -0,0 +1,43 @@
+Git v2.30.9 Release Notes
+=========================
+
+This release addresses the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007.
+
+
+Fixes since v2.30.8
+-------------------
+
+ * CVE-2023-25652:
+
+   By feeding specially crafted input to `git apply --reject`, a
+   path outside the working tree can be overwritten with partially
+   controlled contents (corresponding to the rejected hunk(s) from
+   the given patch).
+
+ * CVE-2023-25815:
+
+   When Git is compiled with runtime prefix support and runs without
+   translated messages, it still used the gettext machinery to
+   display messages, which subsequently potentially looked for
+   translated messages in unexpected places. This allowed for
+   malicious placement of crafted messages.
+
+ * CVE-2023-29007:
+
+   When renaming or deleting a section from a configuration file,
+   certain malicious configuration values may be misinterpreted as
+   the beginning of a new configuration section, leading to arbitrary
+   configuration injection.
+
+Credit for finding CVE-2023-25652 goes to Ry0taK, and the fix was
+developed by Taylor Blau, Junio C Hamano and Johannes Schindelin,
+with the help of Linus Torvalds.
+
+Credit for finding CVE-2023-25815 goes to Maxime Escourbiac and
+Yassine BENGANA of Michelin, and the fix was developed by Johannes
+Schindelin.
+
+Credit for finding CVE-2023-29007 goes to André Baptista and Vítor Pinho
+of Ethiack, and the fix was developed by Taylor Blau, and Johannes
+Schindelin, with help from Jeff King, and Patrick Steinhardt.
diff --git a/Documentation/RelNotes/2.31.0.txt b/Documentation/RelNotes/2.31.0.txt
new file mode 100644
index 0000000000..cf0c7d8d40
--- /dev/null
+++ b/Documentation/RelNotes/2.31.0.txt
@@ -0,0 +1,365 @@
+Git 2.31 Release Notes
+======================
+
+Updates since v2.30
+-------------------
+
+Backward incompatible and other important changes
+
+ * The "pack-redundant" command, which has been left stale with almost
+   unusable performance issues, now warns loudly when it gets used, as
+   we no longer want to recommend its use (instead just "repack -d"
+   instead).
+
+ * The development community has adopted Contributor Covenant v2.0 to
+   update from v1.4 that we have been using.
+
+ * The support for deprecated PCRE1 library has been dropped.
+
+ * Fixes for CVE-2021-21300 in Git 2.30.2 (and earlier) is included.
+
+
+UI, Workflows & Features
+
+ * The "--format=%(trailers)" mechanism gets enhanced to make it
+   easier to design output for machine consumption.
+
+ * When a user does not tell "git pull" to use rebase or merge, the
+   command gives a loud message telling a user to choose between
+   rebase or merge but creates a merge anyway, forcing users who would
+   want to rebase to redo the operation.  Fix an early part of this
+   problem by tightening the condition to give the message---there is
+   no reason to stop or force the user to choose between rebase or
+   merge if the history fast-forwards.
+
+ * The configuration variable 'core.abbrev' can be set to 'no' to
+   force no abbreviation regardless of the hash algorithm.
+
+ * "git rev-parse" can be explicitly told to give output as absolute
+   or relative path with the `--path-format=(absolute|relative)` option.
+
+ * Bash completion (in contrib/) update to make it easier for
+   end-users to add completion for their custom "git" subcommands.
+
+ * "git maintenance" learned to drive scheduled maintenance on
+   platforms whose native scheduling methods are not 'cron'.
+
+ * After expiring a reflog and making a single commit, the reflog for
+   the branch would record a single entry that knows both @{0} and
+   @{1}, but we failed to answer "what commit were we on?", i.e. @{1}
+
+ * "git bundle" learns "--stdin" option to read its refs from the
+   standard input.  Also, it now does not lose refs whey they point
+   at the same object.
+
+ * "git log" learned a new "--diff-merges=<how>" option.
+
+ * "git ls-files" can and does show multiple entries when the index is
+   unmerged, which is a source for confusion unless -s/-u option is in
+   use.  A new option --deduplicate has been introduced.
+
+ * `git worktree list` now annotates worktrees as prunable, shows
+   locked and prunable attributes in --porcelain mode, and gained
+   a --verbose option.
+
+ * "git clone" tries to locally check out the branch pointed at by
+   HEAD of the remote repository after it is done, but the protocol
+   did not convey the information necessary to do so when copying an
+   empty repository.  The protocol v2 learned how to do so.
+
+ * There are other ways than ".." for a single token to denote a
+   "commit range", namely "<rev>^!" and "<rev>^-<n>", but "git
+   range-diff" did not understand them.
+
+ * The "git range-diff" command learned "--(left|right)-only" option
+   to show only one side of the compared range.
+
+ * "git mergetool" feeds three versions (base, local and remote) of
+   a conflicted path unmodified.  The command learned to optionally
+   prepare these files with unconflicted parts already resolved.
+
+ * The .mailmap is documented to be read only from the root level of a
+   working tree, but a stray file in a bare repository also was read
+   by accident, which has been corrected.
+
+ * "git maintenance" tool learned a new "pack-refs" maintenance task.
+
+ * The error message given when a configuration variable that is
+   expected to have a boolean value has been improved.
+
+ * Signed commits and tags now allow verification of objects, whose
+   two object names (one in SHA-1, the other in SHA-256) are both
+   signed.
+
+ * "git rev-list" command learned "--disk-usage" option.
+
+ * "git {diff,log} --{skip,rotate}-to=<path>" allows the user to
+   discard diff output for early paths or move them to the end of the
+   output.
+
+ * "git difftool" learned "--skip-to=<path>" option to restart an
+   interrupted session from an arbitrary path.
+
+ * "git grep" has been tweaked to be limited to the sparse checkout
+   paths.
+
+ * "git rebase --[no-]fork-point" gained a configuration variable
+   rebase.forkPoint so that users do not have to keep specifying a
+   non-default setting.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * A 3-year old test that was not testing anything useful has been
+   corrected.
+
+ * Retire more names with "sha1" in it.
+
+ * The topological walk codepath is covered by new trace2 stats.
+
+ * Update the Code-of-conduct to version 2.0 from the upstream (we've
+   been using version 1.4).
+
+ * "git mktag" validates its input using its own rules before writing
+   a tag object---it has been updated to share the logic with "git
+   fsck".
+
+ * Two new ways to feed configuration variable-value pairs via
+   environment variables have been introduced, and the way
+   GIT_CONFIG_PARAMETERS encodes variable/value pairs has been tweaked
+   to make it more robust.
+
+ * Tests have been updated so that they do not to get affected by the
+   name of the default branch "git init" creates.
+
+ * "git fetch" learns to treat ref updates atomically in all-or-none
+   fashion, just like "git push" does, with the new "--atomic" option.
+
+ * The peel_ref() API has been replaced with peel_iterated_oid().
+
+ * The .use_shell flag in struct child_process that is passed to
+   run_command() API has been clarified with a bit more documentation.
+
+ * Document, clean-up and optimize the code around the cache-tree
+   extension in the index.
+
+ * The ls-refs protocol operation has been optimized to narrow the
+   sub-hierarchy of refs/ it walks to produce response.
+
+ * When removing many branches and tags, the code used to do so one
+   ref at a time.  There is another API it can use to delete multiple
+   refs, and it makes quite a lot of performance difference when the
+   refs are packed.
+
+ * The "pack-objects" command needs to iterate over all the tags when
+   automatic tag following is enabled, but it actually iterated over
+   all refs and then discarded everything outside "refs/tags/"
+   hierarchy, which was quite wasteful.
+
+ * A perf script was made more portable.
+
+ * Our setting of GitHub CI test jobs were a bit too eager to give up
+   once there is even one failure found.  Tweak the knob to allow
+   other jobs keep running even when we see a failure, so that we can
+   find more failures in a single run.
+
+ * We've carried compatibility codepaths for compilers without
+   variadic macros for quite some time, but the world may be ready for
+   them to be removed.  Force compilation failure on exotic platforms
+   where variadic macros are not available to find out who screams in
+   such a way that we can easily revert if it turns out that the world
+   is not yet ready.
+
+ * Code clean-up to ensure our use of hashtables using object names as
+   keys use the "struct object_id" objects, not the raw hash values.
+
+ * Lose the debugging aid that may have been useful in the past, but
+   no longer is, in the "grep" codepaths.
+
+ * Some pretty-format specifiers do not need the data in commit object
+   (e.g. "%H"), but we were over-eager to load and parse it, which has
+   been made even lazier.
+
+ * Get rid of "GETTEXT_POISON" support altogether, which may or may
+   not be controversial.
+
+ * Introduce an on-disk file to record revindex for packdata, which
+   traditionally was always created on the fly and only in-core.
+
+ * The commit-graph learned to use corrected commit dates instead of
+   the generation number to help topological revision traversal.
+
+ * Piecemeal of rewrite of "git bisect" in C continues.
+
+ * When a pager spawned by us exited, the trace log did not record its
+   exit status correctly, which has been corrected.
+
+ * Removal of GIT_TEST_GETTEXT_POISON continues.
+
+ * The code to implement "git merge-base --independent" was poorly
+   done and was kept from the very beginning of the feature.
+
+ * Preliminary changes to fsmonitor integration.
+
+ * Performance improvements for rename detection.
+
+ * The common code to deal with "chunked file format" that is shared
+   by the multi-pack-index and commit-graph files have been factored
+   out, to help codepaths for both filetypes to become more robust.
+
+ * The approach to "fsck" the incoming objects in "index-pack" is
+   attractive for performance reasons (we have them already in core,
+   inflated and ready to be inspected), but fundamentally cannot be
+   applied fully when we receive more than one pack stream, as a tree
+   object in one pack may refer to a blob object in another pack as
+   ".gitmodules", when we want to inspect blobs that are used as
+   ".gitmodules" file, for example.  Teach "index-pack" to emit
+   objects that must be inspected later and check them in the calling
+   "fetch-pack" process.
+
+ * The logic to handle "trailer" related placeholders in the
+   "--format=" mechanisms in the "log" family and "for-each-ref"
+   family is getting unified.
+
+ * Raise the buffer size used when writing the index file out from
+   (obviously too small) 8kB to (clearly sufficiently large) 128kB.
+
+ * It is reported that open() on some platforms (e.g. macOS Big Sur)
+   can return EINTR even though our timers are set up with SA_RESTART.
+   A workaround has been implemented and enabled for macOS to rerun
+   open() transparently from the caller when this happens.
+
+
+Fixes since v2.30
+-----------------
+
+ * Diagnose command line error of "git rebase" early.
+
+ * Clean up option descriptions in "git cmd --help".
+
+ * "git stash" did not work well in a sparsely checked out working
+   tree.
+
+ * Some tests expect that "ls -l" output has either '-' or 'x' for
+   group executable bit, but setgid bit can be inherited from parent
+   directory and make these fields 'S' or 's' instead, causing test
+   failures.
+
+ * "git for-each-repo --config=<var> <cmd>" should not run <cmd> for
+   any repository when the configuration variable <var> is not defined
+   even once.
+
+ * Fix 2.29 regression where "git mergetool --tool-help" fails to list
+   all the available tools.
+
+ * Fix for procedure to building CI test environment for mac.
+
+ * The implementation of "git branch --sort" wrt the detached HEAD
+   display has always been hacky, which has been cleaned up.
+
+ * Newline characters in the host and path part of git:// URL are
+   now forbidden.
+
+ * "git diff" showed a submodule working tree with untracked cruft as
+   "Submodule commit <objectname>-dirty", but a natural expectation is
+   that the "-dirty" indicator would align with "git describe --dirty",
+   which does not consider having untracked files in the working tree
+   as source of dirtiness.  The inconsistency has been fixed.
+
+ * When more than one commit with the same patch ID appears on one
+   side, "git log --cherry-pick A...B" did not exclude them all when a
+   commit with the same patch ID appears on the other side.  Now it
+   does.
+
+ * Documentation for "git fsck" lost stale bits that has become
+   incorrect.
+
+ * Doc fix for packfile URI feature.
+
+ * When "git rebase -i" processes "fixup" insn, there is no reason to
+   clean up the commit log message, but we did the usual stripspace
+   processing.  This has been corrected.
+   (merge f7d42ceec5 js/rebase-i-commit-cleanup-fix later to maint).
+
+ * Fix in passing custom args from "git clone" to "upload-pack" on the
+   other side.
+   (merge ad6b5fefbd jv/upload-pack-filter-spec-quotefix later to maint).
+
+ * The command line completion (in contrib/) completed "git branch -d"
+   with branch names, but "git branch -D" offered tagnames in addition,
+   which has been corrected.  "git branch -M" had the same problem.
+   (merge 27dc071b9a jk/complete-branch-force-delete later to maint).
+
+ * When commands are started from a subdirectory, they may have to
+   compare the path to the subdirectory (called prefix and found out
+   from $(pwd)) with the tracked paths.  On macOS, $(pwd) and
+   readdir() yield decomposed path, while the tracked paths are
+   usually normalized to the precomposed form, causing mismatch.  This
+   has been fixed by taking the same approach used to normalize the
+   command line arguments.
+   (merge 5c327502db tb/precompose-prefix-too later to maint).
+
+ * Even though invocations of "die()" were logged to the trace2
+   system, "BUG()"s were not, which has been corrected.
+   (merge 0a9dde4a04 jt/trace2-BUG later to maint).
+
+ * "git grep --untracked" is meant to be "let's ALSO find in these
+   files on the filesystem" when looking for matches in the working
+   tree files, and does not make any sense if the primary search is
+   done against the index, or the tree objects.  The "--cached" and
+   "--untracked" options have been marked as mutually incompatible.
+   (merge 0c5d83b248 mt/grep-cached-untracked later to maint).
+
+ * Fix "git fsck --name-objects" which apparently has not been used by
+   anybody who is motivated enough to report breakage.
+   (merge e89f89361c js/fsck-name-objects-fix later to maint).
+
+ * Avoid individual tests in t5411 from getting affected by each other
+   by forcing them to use separate output files during the test.
+   (merge 822ee894f6 jx/t5411-unique-filenames later to maint).
+
+ * Test to make sure "git rev-parse one-thing one-thing" gives
+   the same thing twice (when one-thing is --since=X).
+   (merge a5cdca4520 ew/rev-parse-since-test later to maint).
+
+ * When certain features (e.g. grafts) used in the repository are
+   incompatible with the use of the commit-graph, we used to silently
+   turned commit-graph off; we now tell the user what we are doing.
+   (merge c85eec7fc3 js/commit-graph-warning later to maint).
+
+ * Objects that lost references can be pruned away, even when they
+   have notes attached to it (and these notes will become dangling,
+   which in turn can be pruned with "git notes prune").  This has been
+   clarified in the documentation.
+   (merge fa9ab027ba mz/doc-notes-are-not-anchors later to maint).
+
+ * The error codepath around the "--temp/--prefix" feature of "git
+   checkout-index" has been improved.
+   (merge 3f7ba60350 mt/checkout-index-corner-cases later to maint).
+
+ * The "git maintenance register" command had trouble registering bare
+   repositories, which had been corrected.
+
+ * A handful of multi-word configuration variable names in
+   documentation that are spelled in all lowercase have been corrected
+   to use the more canonical camelCase.
+   (merge 7dd0eaa39c dl/doc-config-camelcase later to maint).
+
+ * "git push $there --delete ''" should have been diagnosed as an
+   error, but instead turned into a matching push, which has been
+   corrected.
+   (merge 20e416409f jc/push-delete-nothing later to maint).
+
+ * Test script modernization.
+   (merge 488acf15df sv/t7001-modernize later to maint).
+
+ * An under-allocation for the untracked cache data has been corrected.
+   (merge 6347d649bc jh/untracked-cache-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge e3f5da7e60 sg/t7800-difftool-robustify later to maint).
+   (merge 9d336655ba js/doc-proto-v2-response-end later to maint).
+   (merge 1b5b8cf072 jc/maint-column-doc-typofix later to maint).
+   (merge 3a837b58e3 cw/pack-config-doc later to maint).
+   (merge 01168a9d89 ug/doc-commit-approxidate later to maint).
+   (merge b865734760 js/params-vs-args later to maint).
diff --git a/Documentation/RelNotes/2.31.1.txt b/Documentation/RelNotes/2.31.1.txt
new file mode 100644
index 0000000000..f9b06b8e1b
--- /dev/null
+++ b/Documentation/RelNotes/2.31.1.txt
@@ -0,0 +1,27 @@
+Git 2.31.1 Release Notes
+========================
+
+Fixes since v2.31
+-----------------
+
+ * The fsmonitor interface read from its input without making sure
+   there is something to read from.  This bug is new in 2.31
+   timeframe.
+
+ * The data structure used by fsmonitor interface was not properly
+   duplicated during an in-core merge, leading to use-after-free etc.
+
+ * "git bisect" reimplemented more in C during 2.30 timeframe did not
+   take an annotated tag as a good/bad endpoint well.  This regression
+   has been corrected.
+
+ * Fix macros that can silently inject unintended null-statements.
+
+ * CALLOC_ARRAY() macro replaces many uses of xcalloc().
+
+ * Update insn in Makefile comments to run fuzz-all target.
+
+ * Fix a corner case bug in "git mv" on case insensitive systems,
+   which was introduced in 2.29 timeframe.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.31.2.txt b/Documentation/RelNotes/2.31.2.txt
new file mode 100644
index 0000000000..aa13a5b022
--- /dev/null
+++ b/Documentation/RelNotes/2.31.2.txt
@@ -0,0 +1,6 @@
+Git v2.31.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3 to address
+the security issue CVE-2022-24765; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.31.3.txt b/Documentation/RelNotes/2.31.3.txt
new file mode 100644
index 0000000000..ca143abad0
--- /dev/null
+++ b/Documentation/RelNotes/2.31.3.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.31.3.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.31.3.
diff --git a/Documentation/RelNotes/2.31.4.txt b/Documentation/RelNotes/2.31.4.txt
new file mode 100644
index 0000000000..97a91fd07a
--- /dev/null
+++ b/Documentation/RelNotes/2.31.4.txt
@@ -0,0 +1,6 @@
+Git v2.31.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5 to address
+the security issue CVE-2022-29187; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.31.5.txt b/Documentation/RelNotes/2.31.5.txt
new file mode 100644
index 0000000000..0d87e6e03f
--- /dev/null
+++ b/Documentation/RelNotes/2.31.5.txt
@@ -0,0 +1,5 @@
+Git v2.31.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.6; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.31.6.txt b/Documentation/RelNotes/2.31.6.txt
new file mode 100644
index 0000000000..425a51875a
--- /dev/null
+++ b/Documentation/RelNotes/2.31.6.txt
@@ -0,0 +1,5 @@
+Git v2.31.6 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.31.7.txt b/Documentation/RelNotes/2.31.7.txt
new file mode 100644
index 0000000000..dd44d5bc62
--- /dev/null
+++ b/Documentation/RelNotes/2.31.7.txt
@@ -0,0 +1,6 @@
+Git v2.31.7 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8 to
+address the security issues CVE-2023-22490 and CVE-2023-23946;
+see the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.31.8.txt b/Documentation/RelNotes/2.31.8.txt
new file mode 100644
index 0000000000..0aa3080780
--- /dev/null
+++ b/Documentation/RelNotes/2.31.8.txt
@@ -0,0 +1,6 @@
+Git v2.31.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9 to address the
+security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007;
+see the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.32.0.txt b/Documentation/RelNotes/2.32.0.txt
new file mode 100644
index 0000000000..87d56fa1aa
--- /dev/null
+++ b/Documentation/RelNotes/2.32.0.txt
@@ -0,0 +1,416 @@
+Git 2.32 Release Notes
+======================
+
+Backward compatibility notes
+----------------------------
+
+ * ".gitattributes", ".gitignore", and ".mailmap" files that are
+   symbolic links are ignored.
+
+ * "git apply --3way" used to first attempt a straight application,
+   and only fell back to the 3-way merge algorithm when the stright
+   application failed.  Starting with this version, the command will
+   first try the 3-way merge algorithm and only when it fails (either
+   resulting with conflict or the base versions of blobs are missing),
+   falls back to the usual patch application.
+
+
+Updates since v2.31
+-------------------
+
+UI, Workflows & Features
+
+ * It does not make sense to make ".gitattributes", ".gitignore" and
+   ".mailmap" symlinks, as they are supposed to be usable from the
+   object store (think: bare repositories where HEAD:.mailmap etc. are
+   used).  When these files are symbolic links, we used to read the
+   contents of the files pointed by them by mistake, which has been
+   corrected.
+
+ * "git stash show" learned to optionally show untracked part of the
+   stash.
+
+ * "git log --format='...'" learned "%(describe)" placeholder.
+
+ * "git repack" so far has been only capable of repacking everything
+   under the sun into a single pack (or split by size).  A cleverer
+   strategy to reduce the cost of repacking a repository has been
+   introduced.
+
+ * The http codepath learned to let the credential layer to cache the
+   password used to unlock a certificate that has successfully been
+   used.
+
+ * "git commit --fixup=<commit>", which was to tweak the changes made
+   to the contents while keeping the original log message intact,
+   learned "--fixup=(amend|reword):<commit>", that can be used to
+   tweak both the message and the contents, and only the message,
+   respectively.
+
+ * "git send-email" learned to honor the core.hooksPath configuration.
+
+ * "git format-patch -v<n>" learned to allow a reroll count that is
+   not an integer.
+
+ * "git commit" learned "--trailer <key>[=<value>]" option; together
+   with the interpret-trailers command, this will make it easier to
+   support custom trailers.
+
+ * "git clone --reject-shallow" option fails the clone as soon as we
+   notice that we are cloning from a shallow repository.
+
+ * A configuration variable has been added to force tips of certain
+   refs to be given a reachability bitmap.
+
+ * "gitweb" learned "e-mail privacy" feature to redact strings that
+   look like e-mail addresses on various pages.
+
+ * "git apply --3way" has always been "to fall back to 3-way merge
+   only when straight application fails". Swap the order of falling
+   back so that 3-way is always attempted first (only when the option
+   is given, of course) and then straight patch application is used as
+   a fallback when it fails.
+
+ * "git apply" now takes "--3way" and "--cached" at the same time, and
+   work and record results only in the index.
+
+ * The command line completion (in contrib/) has learned that
+   CHERRY_PICK_HEAD is a possible pseudo-ref.
+
+ * Userdiff patterns for "Scheme" has been added.
+
+ * "git log" learned "--diff-merges=<style>" option, with an
+   associated configuration variable log.diffMerges.
+
+ * "git log --format=..." placeholders learned %ah/%ch placeholders to
+   request the --date=human output.
+
+ * Replace GIT_CONFIG_NOSYSTEM mechanism to decline from reading the
+   system-wide configuration file with GIT_CONFIG_SYSTEM that lets
+   users specify from which file to read the system-wide configuration
+   (setting it to an empty file would essentially be the same as
+   setting NOSYSTEM), and introduce GIT_CONFIG_GLOBAL to override the
+   per-user configuration in $HOME/.gitconfig.
+
+ * "git add" and "git rm" learned not to touch those paths that are
+   outside of sparse checkout.
+
+ * "git rev-list" learns the "--filter=object:type=<type>" option,
+   which can be used to exclude objects of the given kind from the
+   packfile generated by pack-objects.
+
+ * The command line completion (in contrib/) for "git stash" has been
+   updated.
+
+ * "git subtree" updates.
+
+ * It is now documented that "format-patch" skips merges.
+
+ * Options to "git pack-objects" that take numeric values like
+   --window and --depth should not accept negative values; the input
+   validation has been tightened.
+
+ * The way the command line specified by the trailer.<token>.command
+   configuration variable receives the end-user supplied value was
+   both error prone and misleading.  An alternative to achieve the
+   same goal in a safer and more intuitive way has been added, as
+   the trailer.<token>.cmd configuration variable, to replace it.
+
+ * "git add -i --dry-run" does not dry-run, which was surprising.  The
+   combination of options has taught to error out.
+
+ * "git push" learns to discover common ancestor with the receiving
+   end over protocol v2.  This will hopefully make "git push" as
+   efficient as "git fetch" in avoiding objects from getting
+   transferred unnecessarily.
+
+ * "git mailinfo" (hence "git am") learned the "--quoted-cr" option to
+   control how lines ending with CRLF wrapped in base64 or qp are
+   handled.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Rename detection rework continues.
+
+ * GIT_TEST_FAIL_PREREQS is a mechanism to skip test pieces with
+   prerequisites to catch broken tests that depend on the side effects
+   of optional pieces, but did not work at all when negative
+   prerequisites were involved.
+   (merge 27d578d904 jk/fail-prereq-testfix later to maint).
+
+ * "git diff-index" codepath has been taught to trust fsmonitor status
+   to reduce number of lstat() calls.
+   (merge 7e5aa13d2c nk/diff-index-fsmonitor later to maint).
+
+ * Reorganize Makefile to allow building git.o and other essential
+   objects without extra stuff needed only for testing.
+
+ * Preparatory API changes for parallel checkout.
+
+ * A simple IPC interface gets introduced to build services like
+   fsmonitor on top.
+
+ * Fsck API clean-up.
+
+ * SECURITY.md that is facing individual contributors and end users
+   has been introduced.  Also a procedure to follow when preparing
+   embargoed releases has been spelled out.
+   (merge 09420b7648 js/security-md later to maint).
+
+ * Optimize "rev-list --use-bitmap-index --objects" corner case that
+   uses negative tags as the stopping points.
+
+ * CMake update for vsbuild.
+
+ * An on-disk reverse-index to map the in-pack location of an object
+   back to its object name across multiple packfiles is introduced.
+
+ * Generate [ec]tags under $(QUIET_GEN).
+
+ * Clean-up codepaths that implements "git send-email --validate"
+   option and improves the message from it.
+
+ * The last remnant of gettext-poison has been removed.
+
+ * The test framework has been taught to optionally turn the default
+   merge strategy to "ort" throughout the system where we use
+   three-way merges internally, like cherry-pick, rebase etc.,
+   primarily to enhance its test coverage (the strategy has been
+   available as an explicit "-s ort" choice).
+
+ * A bit of code clean-up and a lot of test clean-up around userdiff
+   area.
+
+ * Handling of "promisor packs" that allows certain objects to be
+   missing and lazily retrievable has been optimized (a bit).
+
+ * When packet_write() fails, we gave an extra error message
+   unnecessarily, which has been corrected.
+
+ * The checkout machinery has been taught to perform the actual
+   write-out of the files in parallel when able.
+
+ * Show errno in the trace output in the error codepath that calls
+   read_raw_ref method.
+
+ * Effort to make the command line completion (in contrib/) safe with
+   "set -u" continues.
+
+ * Tweak a few tests for "log --format=..." that show timestamps in
+   various formats.
+
+ * The reflog expiry machinery has been taught to emit trace events.
+
+ * Over-the-wire protocol learns a new request type to ask for object
+   sizes given a list of object names.
+
+
+Fixes since v2.31
+-----------------
+
+ * The fsmonitor interface read from its input without making sure
+   there is something to read from.  This bug is new in 2.31
+   timeframe.
+
+ * The data structure used by fsmonitor interface was not properly
+   duplicated during an in-core merge, leading to use-after-free etc.
+
+ * "git bisect" reimplemented more in C during 2.30 timeframe did not
+   take an annotated tag as a good/bad endpoint well.  This regression
+   has been corrected.
+
+ * Fix macros that can silently inject unintended null-statements.
+
+ * CALLOC_ARRAY() macro replaces many uses of xcalloc().
+
+ * Update insn in Makefile comments to run fuzz-all target.
+
+ * Fix a corner case bug in "git mv" on case insensitive systems,
+   which was introduced in 2.29 timeframe.
+
+ * We had a code to diagnose and die cleanly when a required
+   clean/smudge filter is missing, but an assert before that
+   unnecessarily fired, hiding the end-user facing die() message.
+   (merge 6fab35f748 mt/cleanly-die-upon-missing-required-filter later to maint).
+
+ * Update C code that sets a few configuration variables when a remote
+   is configured so that it spells configuration variable names in the
+   canonical camelCase.
+   (merge 0f1da600e6 ab/remote-write-config-in-camel-case later to maint).
+
+ * A new configuration variable has been introduced to allow choosing
+   which version of the generation number gets used in the
+   commit-graph file.
+   (merge 702110aac6 ds/commit-graph-generation-config later to maint).
+
+ * Perf test update to work better in secondary worktrees.
+   (merge 36e834abc1 jk/perf-in-worktrees later to maint).
+
+ * Updates to memory allocation code around the use of pcre2 library.
+   (merge c1760352e0 ab/grep-pcre2-allocfix later to maint).
+
+ * "git -c core.bare=false clone --bare ..." would have segfaulted,
+   which has been corrected.
+   (merge 75555676ad bc/clone-bare-with-conflicting-config later to maint).
+
+ * When "git checkout" removes a path that does not exist in the
+   commit it is checking out, it wasn't careful enough not to follow
+   symbolic links, which has been corrected.
+   (merge fab78a0c3d mt/checkout-remove-nofollow later to maint).
+
+ * A few option description strings started with capital letters,
+   which were corrected.
+   (merge 5ee90326dc cc/downcase-opt-help later to maint).
+
+ * Plug or annotate remaining leaks that trigger while running the
+   very basic set of tests.
+   (merge 68ffe095a2 ah/plugleaks later to maint).
+
+ * The hashwrite() API uses a buffering mechanism to avoid calling
+   write(2) too frequently. This logic has been refactored to be
+   easier to understand.
+   (merge ddaf1f62e3 ds/clarify-hashwrite later to maint).
+
+ * "git cherry-pick/revert" with or without "--[no-]edit" did not spawn
+   the editor as expected (e.g. "revert --no-edit" after a conflict
+   still asked to edit the message), which has been corrected.
+   (merge 39edfd5cbc en/sequencer-edit-upon-conflict-fix later to maint).
+
+ * "git daemon" has been tightened against systems that take backslash
+   as directory separator.
+   (merge 9a7f1ce8b7 rs/daemon-sanitize-dir-sep later to maint).
+
+ * A NULL-dereference bug has been corrected in an error codepath in
+   "git for-each-ref", "git branch --list" etc.
+   (merge c685450880 jk/ref-filter-segfault-fix later to maint).
+
+ * Streamline the codepath to fix the UTF-8 encoding issues in the
+   argv[] and the prefix on macOS.
+   (merge c7d0e61016 tb/precompose-prefix-simplify later to maint).
+
+ * The command-line completion script (in contrib/) had a couple of
+   references that would have given a warning under the "-u" (nounset)
+   option.
+   (merge c5c0548d79 vs/completion-with-set-u later to maint).
+
+ * When "git pack-objects" makes a literal copy of a part of existing
+   packfile using the reachability bitmaps, its update to the progress
+   meter was broken.
+   (merge 8e118e8490 jk/pack-objects-bitmap-progress-fix later to maint).
+
+ * The dependencies for config-list.h and command-list.h were broken
+   when the former was split out of the latter, which has been
+   corrected.
+   (merge 56550ea718 sg/bugreport-fixes later to maint).
+
+ * "git push --quiet --set-upstream" was not quiet when setting the
+   upstream branch configuration, which has been corrected.
+   (merge f3cce896a8 ow/push-quiet-set-upstream later to maint).
+
+ * The prefetch task in "git maintenance" assumed that "git fetch"
+   from any remote would fetch all its local branches, which would
+   fetch too much if the user is interested in only a subset of
+   branches there.
+   (merge 32f67888d8 ds/maintenance-prefetch-fix later to maint).
+
+ * Clarify that pathnames recorded in Git trees are most often (but
+   not necessarily) encoded in UTF-8.
+   (merge 9364bf465d ab/pathname-encoding-doc later to maint).
+
+ * "git --config-env var=val cmd" weren't accepted (only
+   --config-env=var=val was).
+   (merge c331551ccf ps/config-env-option-with-separate-value later to maint).
+
+ * When the reachability bitmap is in effect, the "do not lose
+   recently created objects and those that are reachable from them"
+   safety to protect us from races were disabled by mistake, which has
+   been corrected.
+   (merge 2ba582ba4c jk/prune-with-bitmap-fix later to maint).
+
+ * Cygwin pathname handling fix.
+   (merge bccc37fdc7 ad/cygwin-no-backslashes-in-paths later to maint).
+
+ * "git rebase --[no-]reschedule-failed-exec" did not work well with
+   its configuration variable, which has been corrected.
+   (merge e5b32bffd1 ab/rebase-no-reschedule-failed-exec later to maint).
+
+ * Portability fix for command line completion script (in contrib/).
+   (merge f2acf763e2 si/zsh-complete-comment-fix later to maint).
+
+ * "git repack -A -d" in a partial clone unnecessarily loosened
+   objects in promisor pack.
+
+ * "git bisect skip" when custom words are used for new/old did not
+   work, which has been corrected.
+
+ * A few variants of informational message "Already up-to-date" has
+   been rephrased.
+   (merge ad9322da03 js/merge-already-up-to-date-message-reword later to maint).
+
+ * "git submodule update --quiet" did not propagate the quiet option
+   down to underlying "git fetch", which has been corrected.
+   (merge 62af4bdd42 nc/submodule-update-quiet later to maint).
+
+ * Document that our test can use "local" keyword.
+   (merge a84fd3bcc6 jc/test-allows-local later to maint).
+
+ * The word-diff mode has been taught to work better with a word
+   regexp that can match an empty string.
+   (merge 0324e8fc6b pw/word-diff-zero-width-matches later to maint).
+
+ * "git p4" learned to find branch points more efficiently.
+   (merge 6b79818bfb jk/p4-locate-branch-point-optim later to maint).
+
+ * When "git update-ref -d" removes a ref that is packed, it left
+   empty directories under $GIT_DIR/refs/ for
+   (merge 5f03e5126d wc/packed-ref-removal-cleanup later to maint).
+
+ * "git clean" and "git ls-files -i" had confusion around working on
+   or showing ignored paths inside an ignored directory, which has
+   been corrected.
+   (merge b548f0f156 en/dir-traversal later to maint).
+
+ * The handling of "%(push)" formatting element of "for-each-ref" and
+   friends was broken when the same codepath started handling
+   "%(push:<what>)", which has been corrected.
+   (merge 1e1c4c5eac zh/ref-filter-push-remote-fix later to maint).
+
+ * The bash prompt script (in contrib/) did not work under "set -u".
+   (merge 5c0cbdb107 en/prompt-under-set-u later to maint).
+
+ * The "chainlint" feature in the test framework is a handy way to
+   catch common mistakes in writing new tests, but tends to get
+   expensive.  An knob to selectively disable it has been introduced
+   to help running tests that the developer has not modified.
+   (merge 2d86a96220 jk/test-chainlint-softer later to maint).
+
+ * The "rev-parse" command did not diagnose the lack of argument to
+   "--path-format" option, which was introduced in v2.31 era, which
+   has been corrected.
+   (merge 99fc555188 wm/rev-parse-path-format-wo-arg later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge f451960708 dl/cat-file-doc-cleanup later to maint).
+   (merge 12604a8d0c sv/t9801-test-path-is-file-cleanup later to maint).
+   (merge ea7e63921c jr/doc-ignore-typofix later to maint).
+   (merge 23c781f173 ps/update-ref-trans-hook-doc later to maint).
+   (merge 42efa1231a jk/filter-branch-sha256 later to maint).
+   (merge 4c8e3dca6e tb/push-simple-uses-branch-merge-config later to maint).
+   (merge 6534d436a2 bs/asciidoctor-installation-hints later to maint).
+   (merge 47957485b3 ab/read-tree later to maint).
+   (merge 2be927f3d1 ab/diff-no-index-tests later to maint).
+   (merge 76593c09bb ab/detox-gettext-tests later to maint).
+   (merge 28e29ee38b jc/doc-format-patch-clarify later to maint).
+   (merge fc12b6fdde fm/user-manual-use-preface later to maint).
+   (merge dba94e3a85 cc/test-helper-bloom-usage-fix later to maint).
+   (merge 61a7660516 hn/reftable-tables-doc-update later to maint).
+   (merge 81ed96a9b2 jt/fetch-pack-request-fix later to maint).
+   (merge 151b6c2dd7 jc/doc-do-not-capitalize-clarification later to maint).
+   (merge 9160068ac6 js/access-nul-emulation-on-windows later to maint).
+   (merge 7a14acdbe6 po/diff-patch-doc later to maint).
+   (merge f91371b948 pw/patience-diff-clean-up later to maint).
+   (merge 3a7f0908b6 mt/clean-clean later to maint).
+   (merge d4e2d15a8b ab/streaming-simplify later to maint).
+   (merge 0e59f7ad67 ah/merge-ort-i18n later to maint).
+   (merge e6f68f62e0 ls/typofix later to maint).
diff --git a/Documentation/RelNotes/2.32.1.txt b/Documentation/RelNotes/2.32.1.txt
new file mode 100644
index 0000000000..7dcca13b92
--- /dev/null
+++ b/Documentation/RelNotes/2.32.1.txt
@@ -0,0 +1,6 @@
+Git v2.32.1 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3 and
+v2.31.2 to address the security issue CVE-2022-24765; see the
+release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.32.2.txt b/Documentation/RelNotes/2.32.2.txt
new file mode 100644
index 0000000000..cf49695f2f
--- /dev/null
+++ b/Documentation/RelNotes/2.32.2.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.32.2.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.32.2.
diff --git a/Documentation/RelNotes/2.32.3.txt b/Documentation/RelNotes/2.32.3.txt
new file mode 100644
index 0000000000..583fabe684
--- /dev/null
+++ b/Documentation/RelNotes/2.32.3.txt
@@ -0,0 +1,6 @@
+Git v2.32.3 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5 and
+v2.31.4 to address the security issue CVE-2022-29187; see the
+release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.32.4.txt b/Documentation/RelNotes/2.32.4.txt
new file mode 100644
index 0000000000..76c67b209e
--- /dev/null
+++ b/Documentation/RelNotes/2.32.4.txt
@@ -0,0 +1,5 @@
+Git v2.32.4 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.6; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.32.5.txt b/Documentation/RelNotes/2.32.5.txt
new file mode 100644
index 0000000000..a8cad1a05b
--- /dev/null
+++ b/Documentation/RelNotes/2.32.5.txt
@@ -0,0 +1,8 @@
+Git v2.32.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
+
+In addition, included are additional code for "git fsck" to check
+for questionable .gitattributes files.
diff --git a/Documentation/RelNotes/2.32.6.txt b/Documentation/RelNotes/2.32.6.txt
new file mode 100644
index 0000000000..fd659612e3
--- /dev/null
+++ b/Documentation/RelNotes/2.32.6.txt
@@ -0,0 +1,6 @@
+Git v2.32.6 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8 and v2.31.7
+to address the security issues CVE-2023-22490 and CVE-2023-23946;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.32.7.txt b/Documentation/RelNotes/2.32.7.txt
new file mode 100644
index 0000000000..7bb35388b5
--- /dev/null
+++ b/Documentation/RelNotes/2.32.7.txt
@@ -0,0 +1,7 @@
+Git v2.32.7 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9 and v2.31.8 to
+address the security issues CVE-2023-25652, CVE-2023-25815, and
+CVE-2023-29007; see the release notes for these versions for
+details.
diff --git a/Documentation/RelNotes/2.33.0.txt b/Documentation/RelNotes/2.33.0.txt
new file mode 100644
index 0000000000..893c18bfdd
--- /dev/null
+++ b/Documentation/RelNotes/2.33.0.txt
@@ -0,0 +1,279 @@
+Git 2.33 Release Notes
+======================
+
+Updates since Git 2.32
+----------------------
+
+UI, Workflows & Features
+
+ * "git send-email" learned the "--sendmail-cmd" command line option
+   and the "sendemail.sendmailCmd" configuration variable, which is a
+   more sensible approach than the current way of repurposing the
+   "smtp-server" that is meant to name the server to instead name the
+   command to talk to the server.
+
+ * The userdiff pattern for C# learned the token "record".
+
+ * "git rev-list" learns to omit the "commit <object-name>" header
+   lines from the output with the `--no-commit-header` option.
+
+ * "git worktree add --lock" learned to record why the worktree is
+   locked with a custom message.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The code to handle the "--format" option in "for-each-ref" and
+   friends made too many string comparisons on %(atom)s used in the
+   format string, which has been corrected by converting them into
+   enum when the format string is parsed.
+
+ * Use the hashfile API in the codepath that writes the index file to
+   reduce code duplication.
+
+ * Repeated rename detections in a sequence of mergy operations have
+   been optimized out for the 'ort' merge strategy.
+
+ * Preliminary clean-up of tests before the main reftable changes
+   hits the codebase.
+
+ * The backend for "diff -G/-S" has been updated to use pcre2 engine
+   when available.
+
+ * Use ".DELETE_ON_ERROR" pseudo target to simplify our Makefile.
+
+ * Code cleanup around struct_type_init() functions.
+
+ * "git send-email" optimization.
+
+ * GitHub Actions / CI update.
+   (merge 0dc787a9f2 js/ci-windows-update later to maint).
+
+ * Object accesses in repositories with many alternate object store
+   have been optimized.
+
+ * "git log" has been optimized not to waste cycles to load ref
+   decoration data that may not be needed.
+
+ * Many "printf"-like helper functions we have have been annotated
+   with __attribute__() to catch placeholder/parameter mismatches.
+
+ * Tests that cover protocol bits have been updated and helpers
+   used there have been consolidated.
+
+ * The CI gained a new job to run "make sparse" check.
+
+ * "git status" codepath learned to work with sparsely populated index
+   without hydrating it fully.
+
+ * A guideline for gender neutral documentation has been added.
+
+ * Documentation on "git diff -l<n>" and diff.renameLimit have been
+   updated, and the defaults for these limits have been raised.
+
+ * The completion support used to offer alternate spelling of options
+   that exist only for compatibility, which has been corrected.
+
+ * "TEST_OUTPUT_DIRECTORY=there make test" failed to work, which has
+   been corrected.
+
+ * "git bundle" gained more test coverage.
+
+ * "git read-tree" had a codepath where blobs are fetched one-by-one
+   from the promisor remote, which has been corrected to fetch in bulk.
+
+ * Rewrite of "git submodule" in C continues.
+
+ * "git checkout" and "git commit" learn to work without unnecessarily
+   expanding sparse indexes.
+
+
+Fixes since v2.32
+-----------------
+
+ * We historically rejected a very short string as an author name
+   while accepting a patch e-mail, which has been loosened.
+   (merge 72ee47ceeb ef/mailinfo-short-name later to maint).
+
+ * The parallel checkout codepath did not initialize object ID field
+   used to talk to the worker processes in a futureproof way.
+
+ * Rewrite code that triggers undefined behaviour warning.
+   (merge aafa5df0df jn/size-t-casted-to-off-t-fix later to maint).
+
+ * The description of "fast-forward" in the glossary has been updated.
+   (merge e22f2daed0 ry/clarify-fast-forward-in-glossary later to maint).
+
+ * Recent "git clone" left a temporary directory behind when the
+   transport layer returned an failure.
+   (merge 6aacb7d861 jk/clone-clean-upon-transport-error later to maint).
+
+ * "git fetch" over protocol v2 left its side of the socket open after
+   it finished speaking, which unnecessarily wasted the resource on
+   the other side.
+   (merge ae1a7eefff jk/fetch-pack-v2-half-close-early later to maint).
+
+ * The command line completion (in contrib/) learned that "git diff"
+   takes the "--anchored" option.
+   (merge d1e7c2cac9 tb/complete-diff-anchored later to maint).
+
+ * "git-svn" tests assumed that "locale -a", which is used to pick an
+   available UTF-8 locale, is available everywhere.  A knob has been
+   introduced to allow testers to specify a suitable locale to use.
+   (merge 482c962de4 dd/svn-test-wo-locale-a later to maint).
+
+ * Update "git subtree" to work better on Windows.
+   (merge 77f37de39f js/subtree-on-windows-fix later to maint).
+
+ * Remove multimail from contrib/
+   (merge f74d11471f js/no-more-multimail later to maint).
+
+ * Make the codebase MSAN clean.
+   (merge 4dbc55e87d ah/uninitialized-reads-fix later to maint).
+
+ * Work around inefficient glob substitution in older versions of bash
+   by rewriting parts of a test.
+   (merge eb87c6f559 jx/t6020-with-older-bash later to maint).
+
+ * Avoid duplicated work while building reachability bitmaps.
+   (merge aa9ad6fee5 jk/bitmap-tree-optim later to maint).
+
+ * We broke "GIT_SKIP_TESTS=t?000" to skip certain tests in recent
+   update, which got fixed.
+
+ * The side-band demultiplexer that is used to display progress output
+   from the remote end did not clear the line properly when the end of
+   line hits at a packet boundary, which has been corrected.
+
+ * Some test scripts assumed that readlink(1) was universally
+   installed and available, which is not the case.
+   (merge 7c0afdf23c jk/test-without-readlink-1 later to maint).
+
+ * Recent update to completion script (in contrib/) broke those who
+   use the __git_complete helper to define completion to their custom
+   command.
+   (merge cea232194d fw/complete-cmd-idx-fix later to maint).
+
+ * Output from some of our tests were affected by the width of the
+   terminal that they were run in, which has been corrected by
+   exporting a fixed value in the COLUMNS environment.
+   (merge c49a177bec ab/fix-columns-to-80-during-tests later to maint).
+
+ * On Windows, mergetool has been taught to find kdiff3.exe just like
+   it finds winmerge.exe.
+   (merge 47eb4c6890 ms/mergetools-kdiff3-on-windows later to maint).
+
+ * When we cannot figure out how wide the terminal is, we use a
+   fallback value of 80 ourselves (which cannot be avoided), but when
+   we run the pager, we export it in COLUMNS, which forces the pager
+   to use the hardcoded value, even when the pager is perfectly
+   capable to figure it out itself.  Stop exporting COLUMNS when we
+   fall back on the hardcoded default value for our own use.
+   (merge 9b6e2c8b98 js/stop-exporting-bogus-columns later to maint).
+
+ * "git cat-file --batch-all-objects"" misbehaved when "--batch" is in
+   use and did not ask for certain object traits.
+   (merge ee02ac6164 zh/cat-file-batch-fix later to maint).
+
+ * Some code and doc clarification around "git push".
+
+ * The "union" conflict resultion variant misbehaved when used with
+   binary merge driver.
+   (merge 382b601acd jk/union-merge-binary later to maint).
+
+ * Prevent "git p4" from failing to submit changes to binary file.
+   (merge 54662d5958 dc/p4-binary-submit-fix later to maint).
+
+ * "git grep --and -e foo" ought to have been diagnosed as an error
+   but instead segfaulted, which has been corrected.
+   (merge fe7fe62d8d rs/grep-parser-fix later to maint).
+
+ * The merge code had funny interactions between content based rename
+   detection and directory rename detection.
+   (merge 3585d0ea23 en/merge-dir-rename-corner-case-fix later to maint).
+
+ * When rebuilding the multi-pack index file reusing an existing one,
+   we used to blindly trust the existing file and ended up carrying
+   corrupted data into the updated file, which has been corrected.
+   (merge f89ecf7988 tb/midx-use-checksum later to maint).
+
+ * Update the location of system-side configuration file on Windows.
+   (merge e355307692 js/gfw-system-config-loc-fix later to maint).
+
+ * Code recently added to support common ancestry negotiation during
+   "git push" did not sanity check its arguments carefully enough.
+   (merge eff40457a4 ab/fetch-negotiate-segv-fix later to maint).
+
+ * Update the documentation not to assume users are of certain gender
+   and adds to guidelines to do so.
+   (merge 46a237f42f ds/gender-neutral-doc later to maint).
+
+ * "git commit --allow-empty-message" won't abort the operation upon
+   an empty message, but the hint shown in the editor said otherwise.
+   (merge 6f70f00b4f hj/commit-allow-empty-message later to maint).
+
+ * The code that gives an error message in "git multi-pack-index" when
+   no subcommand is given tried to print a NULL pointer as a strong,
+   which has been corrected.
+   (merge 88617d11f9 tb/reverse-midx later to maint).
+
+ * CI update.
+   (merge a066a90db6 js/ci-check-whitespace-updates later to maint).
+
+ * Documentation fix for "git pull --rebase=no".
+   (merge d3236becec fc/pull-no-rebase-merges-theirs-into-ours later to maint).
+
+ * A race between repacking and using pack bitmaps has been corrected.
+   (merge dc1daacdcc jk/check-pack-valid-before-opening-bitmap later to maint).
+
+ * The local changes stashed by "git merge --autostash" were lost when
+   the merge failed in certain ways, which has been corrected.
+
+ * Windows rmdir() equivalent behaves differently from POSIX ones in
+   that when used on a symbolic link that points at a directory, the
+   target directory gets removed, which has been corrected.
+   (merge 3e7d4888e5 tb/mingw-rmdir-symlink-to-directory later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge bfe35a6165 ah/doc-describe later to maint).
+   (merge f302c1e4aa jc/clarify-revision-range later to maint).
+   (merge 3127ff90ea tl/fix-packfile-uri-doc later to maint).
+   (merge a84216c684 jk/doc-color-pager later to maint).
+   (merge 4e0a64a713 ab/trace2-squelch-gcc-warning later to maint).
+   (merge 225f7fa847 ps/rev-list-object-type-filter later to maint).
+   (merge 5317dfeaed dd/honor-users-tar-in-tests later to maint).
+   (merge ace6d8e3d6 tk/partial-clone-repack-doc later to maint).
+   (merge 7ba68e0cf1 js/trace2-discard-event-docfix later to maint).
+   (merge 8603c419d3 fc/doc-default-to-upstream-config later to maint).
+   (merge 1d72b604ef jk/revision-squelch-gcc-warning later to maint).
+   (merge abcb66c614 ar/typofix later to maint).
+   (merge 9853830787 ah/graph-typofix later to maint).
+   (merge aac578492d ab/config-hooks-path-testfix later to maint).
+   (merge 98c7656a18 ar/more-typofix later to maint).
+   (merge 6fb9195f6c jk/doc-max-pack-size later to maint).
+   (merge 4184cbd635 ar/mailinfo-memcmp-to-skip-prefix later to maint).
+   (merge 91d2347033 ar/doc-libera-chat-in-my-first-contrib later to maint).
+   (merge 338abb0f04 ab/cmd-foo-should-return later to maint).
+   (merge 546096a5cb ab/xdiff-bug-cleanup later to maint).
+   (merge b7b793d1e7 ab/progress-cleanup later to maint).
+   (merge d94f9b8e90 ba/object-info later to maint).
+   (merge 52ff891c03 ar/test-code-cleanup later to maint).
+   (merge a0538e5c8b dd/document-log-decorate-default later to maint).
+   (merge ce24797d38 mr/cmake later to maint).
+   (merge 9eb542f2ee ab/pre-auto-gc-hook-test later to maint).
+   (merge 9fffc38583 bk/doc-commit-typofix later to maint).
+   (merge 1cf823d8f0 ks/submodule-cleanup later to maint).
+   (merge ebbf5d2b70 js/config-mak-windows-pcre-fix later to maint).
+   (merge 617480d75b hn/refs-iterator-peel-returns-boolean later to maint).
+   (merge 6a24cc71ed ar/submodule-helper-include-cleanup later to maint).
+   (merge 5632e838f8 rs/khash-alloc-cleanup later to maint).
+   (merge b1d87fbaf1 jk/typofix later to maint).
+   (merge e04170697a ab/gitignore-discovery-doc later to maint).
+   (merge 8232a0ff48 dl/packet-read-response-end-fix later to maint).
+   (merge eb448631fb dl/diff-merge-base later to maint).
+   (merge c510928a25 hn/refs-debug-empty-prefix later to maint).
+   (merge ddcb189d9d tb/bitmap-type-filter-comment-fix later to maint).
+   (merge 878b399734 pb/submodule-recurse-doc later to maint).
+   (merge 734283855f jk/config-env-doc later to maint).
+   (merge 482e1488a9 ab/getcwd-test later to maint).
+   (merge f0b922473e ar/doc-markup-fix later to maint).
diff --git a/Documentation/RelNotes/2.33.1.txt b/Documentation/RelNotes/2.33.1.txt
new file mode 100644
index 0000000000..b71738e654
--- /dev/null
+++ b/Documentation/RelNotes/2.33.1.txt
@@ -0,0 +1,138 @@
+Git 2.33.1 Release Notes
+========================
+
+This primarily is to backport various fixes accumulated during the
+development towards Git 2.34, the next feature release.
+
+
+Fixes since v2.33
+-----------------
+
+ * The unicode character width table (used for output alignment) has
+   been updated.
+
+ * Input validation of "git pack-objects --stdin-packs" has been
+   corrected.
+
+ * Bugfix for common ancestor negotiation recently introduced in "git
+   push" codepath.
+
+ * "git pull" had various corner cases that were not well thought out
+   around its --rebase backend, e.g. "git pull --ff-only" did not stop
+   but went ahead and rebased when the history on other side is not a
+   descendant of our history.  The series tries to fix them up.
+
+ * "git apply" miscounted the bytes and failed to read to the end of
+   binary hunks.
+
+ * "git range-diff" code clean-up.
+
+ * "git commit --fixup" now works with "--edit" again, after it was
+   broken in v2.32.
+
+ * Use upload-artifacts v1 (instead of v2) for 32-bit linux, as the
+   new version has a blocker bug for that architecture.
+
+ * Checking out all the paths from HEAD during the last conflicted
+   step in "git rebase" and continuing would cause the step to be
+   skipped (which is expected), but leaves MERGE_MSG file behind in
+   $GIT_DIR and confuses the next "git commit", which has been
+   corrected.
+
+ * Various bugs in "git rebase -r" have been fixed.
+
+ * mmap() imitation used to call xmalloc() that dies upon malloc()
+   failure, which has been corrected to just return an error to the
+   caller to be handled.
+
+ * "git diff --relative" segfaulted and/or produced incorrect result
+   when there are unmerged paths.
+
+ * The delayed checkout code path in "git checkout" etc. were chatty
+   even when --quiet and/or --no-progress options were given.
+
+ * "git branch -D <branch>" used to refuse to remove a broken branch
+   ref that points at a missing commit, which has been corrected.
+
+ * Build update for Apple clang.
+
+ * The parser for the "--nl" option of "git column" has been
+   corrected.
+
+ * "git upload-pack" which runs on the other side of "git fetch"
+   forgot to take the ref namespaces into account when handling
+   want-ref requests.
+
+ * The sparse-index support can corrupt the index structure by storing
+   a stale and/or uninitialized data, which has been corrected.
+
+ * Buggy tests could damage repositories outside the throw-away test
+   area we created.  We now by default export GIT_CEILING_DIRECTORIES
+   to limit the damage from such a stray test.
+
+ * Even when running "git send-email" without its own threaded
+   discussion support, a threading related header in one message is
+   carried over to the subsequent message to result in an unwanted
+   threading, which has been corrected.
+
+ * The output from "git fast-export", when its anonymization feature
+   is in use, showed an annotated tag incorrectly.
+
+ * Recent "diff -m" changes broke "gitk", which has been corrected.
+
+ * "git maintenance" scheduler fix for macOS.
+
+ * A pathname in an advice message has been made cut-and-paste ready.
+
+ * The "git apply -3" code path learned not to bother the lower level
+   merge machinery when the three-way merge can be trivially resolved
+   without the content level merge.
+
+ * The code that optionally creates the *.rev reverse index file has
+   been optimized to avoid needless computation when it is not writing
+   the file out.
+
+ * "git range-diff -I... <range> <range>" segfaulted, which has been
+   corrected.
+
+ * The order in which various files that make up a single (conceptual)
+   packfile has been reevaluated and straightened up.  This matters in
+   correctness, as an incomplete set of files must not be shown to a
+   running Git.
+
+ * The "mode" word is useless in a call to open(2) that does not
+   create a new file.  Such a call in the files backend of the ref
+   subsystem has been cleaned up.
+
+ * "git update-ref --stdin" failed to flush its output as needed,
+   which potentially led the conversation to a deadlock.
+
+ * When "git am --abort" fails to abort correctly, it still exited
+   with exit status of 0, which has been corrected.
+
+ * Correct nr and alloc members of strvec struct to be of type size_t.
+
+ * "git stash", where the tentative change involves changing a
+   directory to a file (or vice versa), was confused, which has been
+   corrected.
+
+ * "git clone" from a repository whose HEAD is unborn into a bare
+   repository didn't follow the branch name the other side used, which
+   is corrected.
+
+ * "git cvsserver" had a long-standing bug in its authentication code,
+   which has finally been corrected (it is unclear and is a separate
+   question if anybody is seriously using it, though).
+
+ * "git difftool --dir-diff" mishandled symbolic links.
+
+ * Sensitive data in the HTTP trace were supposed to be redacted, but
+   we failed to do so in HTTP/2 requests.
+
+ * "make clean" has been updated to remove leftover .depend/
+   directories, even when it is not told to use them to compute header
+   dependencies.
+
+ * Protocol v0 clients can get stuck parsing a malformed feature line.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.33.2.txt b/Documentation/RelNotes/2.33.2.txt
new file mode 100644
index 0000000000..e504489d61
--- /dev/null
+++ b/Documentation/RelNotes/2.33.2.txt
@@ -0,0 +1,15 @@
+Git v2.33.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3, v2.31.2
+and v2.32.1 to address the security issue CVE-2022-24765; see
+the release notes for these versions for details.
+
+In addition, it contains the following fixes:
+
+ * Squelch over-eager warning message added during this cycle.
+
+ * A bug in "git rebase -r" has been fixed.
+
+ * One CI task based on Fedora image noticed a not-quite-kosher
+   construct recently, which has been corrected.
diff --git a/Documentation/RelNotes/2.33.3.txt b/Documentation/RelNotes/2.33.3.txt
new file mode 100644
index 0000000000..e2bada12a1
--- /dev/null
+++ b/Documentation/RelNotes/2.33.3.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.33.3.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.33.3.
diff --git a/Documentation/RelNotes/2.33.4.txt b/Documentation/RelNotes/2.33.4.txt
new file mode 100644
index 0000000000..a145cc25de
--- /dev/null
+++ b/Documentation/RelNotes/2.33.4.txt
@@ -0,0 +1,6 @@
+Git v2.33.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5, v2.31.4
+and v2.32.3 to address the security issue CVE-2022-29187; see
+the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.33.5.txt b/Documentation/RelNotes/2.33.5.txt
new file mode 100644
index 0000000000..a63652602b
--- /dev/null
+++ b/Documentation/RelNotes/2.33.5.txt
@@ -0,0 +1,5 @@
+Git v2.33.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.6; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.33.6.txt b/Documentation/RelNotes/2.33.6.txt
new file mode 100644
index 0000000000..b63e4e6256
--- /dev/null
+++ b/Documentation/RelNotes/2.33.6.txt
@@ -0,0 +1,5 @@
+Git v2.33.6 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.33.7.txt b/Documentation/RelNotes/2.33.7.txt
new file mode 100644
index 0000000000..078a837cb4
--- /dev/null
+++ b/Documentation/RelNotes/2.33.7.txt
@@ -0,0 +1,7 @@
+Git v2.33.7 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8, v2.31.7
+and v2.32.6 to address the security issues CVE-2023-22490 and
+CVE-2023-23946; see the release notes for these versions for
+details.
diff --git a/Documentation/RelNotes/2.33.8.txt b/Documentation/RelNotes/2.33.8.txt
new file mode 100644
index 0000000000..d8cf4c7f3a
--- /dev/null
+++ b/Documentation/RelNotes/2.33.8.txt
@@ -0,0 +1,7 @@
+Git v2.33.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9, v2.31.8 and
+v2.32.7 to address the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.34.0.txt b/Documentation/RelNotes/2.34.0.txt
new file mode 100644
index 0000000000..75d4fdfde7
--- /dev/null
+++ b/Documentation/RelNotes/2.34.0.txt
@@ -0,0 +1,438 @@
+Git 2.34 Release Notes
+======================
+
+Updates since Git 2.33
+----------------------
+
+Backward compatibility notes
+
+ * The "--preserve-merges" option of "git rebase" has been removed.
+
+
+UI, Workflows & Features
+
+ * Pathname expansion (like "~username/") learned a way to specify a
+   location relative to Git installation (e.g. its $sharedir which is
+   $(prefix)/share), with "%(prefix)".
+
+ * The `ort` strategy is used instead of `recursive` as the default
+   merge strategy.
+
+ * The userdiff pattern for "java" language has been updated.
+
+ * "git rebase" by default skips changes that are equivalent to
+   commits that are already in the history the branch is rebased onto;
+   give messages when this happens to let the users be aware of
+   skipped commits, and also teach them how to tell "rebase" to keep
+   duplicated changes.
+
+ * The advice message that "git cherry-pick" gives when it asks
+   conflicted replay of a commit to be resolved by the end user has
+   been updated.
+
+ * After "git clone --recurse-submodules", all submodules are cloned
+   but they are not by default recursed into by other commands.  With
+   submodule.stickyRecursiveClone configuration set, submodule.recurse
+   configuration is set to true in a repository created by "clone"
+   with "--recurse-submodules" option.
+
+ * The logic for auto-correction of misspelt subcommands learned to go
+   interactive when the help.autocorrect configuration variable is set
+   to 'prompt'.
+
+ * "git maintenance" scheduler learned to use systemd timers as a
+   possible backend.
+
+ * "git diff --submodule=diff" showed failure from run_command() when
+   trying to run diff inside a submodule, when the user manually
+   removes the submodule directory.
+
+ * "git bundle unbundle" learned to show progress display.
+
+ * In cone mode, the sparse-index code path learned to remove ignored
+   files (like build artifacts) outside the sparse cone, allowing the
+   entire directory outside the sparse cone to be removed, which is
+   especially useful when the sparse patterns change.
+
+ * Taking advantage of the CGI interface, http-backend has been
+   updated to enable protocol v2 automatically when the other side
+   asks for it.
+
+ * The credential-cache helper has been adjusted to Windows.
+
+ * The error in "git help no-such-git-command" is handled better.
+
+ * The unicode character width table (used for output alignment) has
+   been updated.
+
+ * The ref iteration code used to optionally allow dangling refs to be
+   shown, which has been tightened up.
+
+ * "git add", "git mv", and "git rm" have been adjusted to avoid
+   updating paths outside of the sparse-checkout definition unless
+   the user specifies a "--sparse" option.
+
+ * "git repack" has been taught to generate multi-pack reachability
+   bitmaps.
+
+ * "git fsck" has been taught to report mismatch between expected and
+   actual types of an object better.
+
+ * In addition to GnuPG, ssh public crypto can be used for object and
+   push-cert signing.  Note that this feature cannot be used with
+   ssh-keygen from OpenSSH 8.7, whose support for it is broken.  Avoid
+   using it unless you update to OpenSSH 8.8.
+
+ * "git log --grep=string --author=name" learns to highlight hits just
+   like "git grep string" does.
+
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git bisect" spawned "git show-branch" only to pretty-print the
+   title of the commit after checking out the next version to be
+   tested; this has been rewritten in C.
+
+ * "git add" can work better with the sparse index.
+
+ * Support for ancient versions of cURL library (pre 7.19.4) has been
+   dropped.
+
+ * A handful of tests that assumed implementation details of files
+   backend for refs have been cleaned up.
+
+ * trace2 logs learned to show parent process name to see in what
+   context Git was invoked.
+
+ * Loading of ref tips to prepare for common ancestry negotiation in
+   "git fetch-pack" has been optimized by taking advantage of the
+   commit graph when available.
+
+ * Remind developers that the userdiff patterns should be kept simple
+   and permissive, assuming that the contents they apply are always
+   syntactically correct.
+
+ * The current implementation of GIT_TEST_FAIL_PREREQS is broken in
+   that checking for the lack of a prerequisite would not work.  Avoid
+   the use of "if ! test_have_prereq X" in a test script.
+
+ * The revision traversal API has been optimized by taking advantage
+   of the commit-graph, when available, to determine if a commit is
+   reachable from any of the existing refs.
+
+ * "git fetch --quiet" optimization to avoid useless computation of
+   info that will never be displayed.
+
+ * Callers from older advice_config[] based API has been updated to
+   use the newer advice_if_enabled() and advice_enabled() API.
+
+ * Teach "test_pause" and "debug" helpers to allow using the HOME and
+   TERM environment variables the user usually uses.
+
+ * "make INSTALL_STRIP=-s install" allows the installation step to use
+   "install -s" to strip the binaries as they get installed.
+
+ * Code that handles large number of refs in the "git fetch" code
+   path has been optimized.
+
+ * The reachability bitmap file used to be generated only for a single
+   pack, but now we've learned to generate bitmaps for history that
+   span across multiple packfiles.
+
+ * The code to make "git grep" recurse into submodules has been
+   updated to migrate away from the "add submodule's object store as
+   an alternate object store" mechanism (which is suboptimal).
+
+ * The tracing of process ancestry information has been enhanced.
+
+ * Reduce number of write(2) system calls while sending the
+   ref advertisement.
+
+ * Update the build procedure to use the "-pedantic" build when
+   DEVELOPER makefile macro is in effect.
+
+ * Large part of "git submodule add" gets rewritten in C.
+
+ * The run-command API has been updated so that the callers can easily
+   ask the file descriptors open for packfiles to be closed immediately
+   before spawning commands that may trigger auto-gc.
+
+ * An oddball OPTION_ARGUMENT feature has been removed from the
+   parse-options API.
+
+ * The mergesort implementation used to sort linked list has been
+   optimized.
+
+ * Remove external declaration of functions that no longer exist.
+
+ * "git multi-pack-index write --bitmap" learns to propagate the
+   hashcache from original bitmap to resulting bitmap.
+
+ * CI learns to run the leak sanitizer builds.
+
+ * "git grep --recurse-submodules" takes trees and blobs from the
+   submodule repository, but the textconv settings when processing a
+   blob from the submodule is not taken from the submodule repository.
+   A test is added to demonstrate the issue, without fixing it.
+
+ * Teach "git help -c" into helping the command line completion of
+   configuration variables.
+
+ * When "git cmd -h" shows more than one line of usage text (e.g.
+   the cmd subcommand may take sub-sub-command), parse-options API
+   learned to align these lines, even across i18n/l10n.
+
+ * Prevent "make sparse" from running for the source files that
+   haven't been modified.
+
+ * The code path to write a new version of .midx multi-pack index files
+   has learned to release the mmaped memory holding the current
+   version of .midx before removing them from the disk, as some
+   platforms do not allow removal of a file that still has mapping.
+
+ * A new feature has been added to abort early in the test framework.
+
+
+Fixes since v2.33
+-----------------
+
+ * Input validation of "git pack-objects --stdin-packs" has been
+   corrected.
+
+ * Bugfix for common ancestor negotiation recently introduced in "git
+   push" code path.
+
+ * "git pull" had various corner cases that were not well thought out
+   around its --rebase backend, e.g. "git pull --ff-only" did not stop
+   but went ahead and rebased when the history on other side is not a
+   descendant of our history.  The series tries to fix them up.
+
+ * "git apply" miscounted the bytes and failed to read to the end of
+   binary hunks.
+
+ * "git range-diff" code clean-up.
+
+ * "git commit --fixup" now works with "--edit" again, after it was
+   broken in v2.32.
+
+ * Use upload-artifacts v1 (instead of v2) for 32-bit linux, as the
+   new version has a blocker bug for that architecture.
+
+ * Checking out all the paths from HEAD during the last conflicted
+   step in "git rebase" and continuing would cause the step to be
+   skipped (which is expected), but leaves MERGE_MSG file behind in
+   $GIT_DIR and confuses the next "git commit", which has been
+   corrected.
+
+ * Various bugs in "git rebase -r" have been fixed.
+
+ * mmap() imitation used to call xmalloc() that dies upon malloc()
+   failure, which has been corrected to just return an error to the
+   caller to be handled.
+
+ * "git diff --relative" segfaulted and/or produced incorrect result
+   when there are unmerged paths.
+
+ * The delayed checkout code path in "git checkout" etc. were chatty
+   even when --quiet and/or --no-progress options were given.
+
+ * "git branch -D <branch>" used to refuse to remove a broken branch
+   ref that points at a missing commit, which has been corrected.
+
+ * Build update for Apple clang.
+
+ * The parser for the "--nl" option of "git column" has been
+   corrected.
+
+ * "git upload-pack" which runs on the other side of "git fetch"
+   forgot to take the ref namespaces into account when handling
+   want-ref requests.
+
+ * The sparse-index support can corrupt the index structure by storing
+   a stale and/or uninitialized data, which has been corrected.
+
+ * Buggy tests could damage repositories outside the throw-away test
+   area we created.  We now by default export GIT_CEILING_DIRECTORIES
+   to limit the damage from such a stray test.
+
+ * Even when running "git send-email" without its own threaded
+   discussion support, a threading related header in one message is
+   carried over to the subsequent message to result in an unwanted
+   threading, which has been corrected.
+
+ * The output from "git fast-export", when its anonymization feature
+   is in use, showed an annotated tag incorrectly.
+
+ * Recent "diff -m" changes broke "gitk", which has been corrected.
+
+ * The "git apply -3" code path learned not to bother the lower level
+   merge machinery when the three-way merge can be trivially resolved
+   without the content level merge.  This fixes a regression caused by
+   recent "-3way first and fall back to direct application" change.
+
+ * The code that optionally creates the *.rev reverse index file has
+   been optimized to avoid needless computation when it is not writing
+   the file out.
+
+ * "git range-diff -I... <range> <range>" segfaulted, which has been
+   corrected.
+
+ * The order in which various files that make up a single (conceptual)
+   packfile has been reevaluated and straightened up.  This matters in
+   correctness, as an incomplete set of files must not be shown to a
+   running Git.
+
+ * The "mode" word is useless in a call to open(2) that does not
+   create a new file.  Such a call in the files backend of the ref
+   subsystem has been cleaned up.
+
+ * "git update-ref --stdin" failed to flush its output as needed,
+   which potentially led the conversation to a deadlock.
+
+ * When "git am --abort" fails to abort correctly, it still exited
+   with exit status of 0, which has been corrected.
+
+ * Correct nr and alloc members of strvec struct to be of type size_t.
+
+ * "git stash", where the tentative change involves changing a
+   directory to a file (or vice versa), was confused, which has been
+   corrected.
+
+ * "git clone" from a repository whose HEAD is unborn into a bare
+   repository didn't follow the branch name the other side used, which
+   is corrected.
+
+ * "git cvsserver" had a long-standing bug in its authentication code,
+   which has finally been corrected (it is unclear and is a separate
+   question if anybody is seriously using it, though).
+
+ * "git difftool --dir-diff" mishandled symbolic links.
+
+ * Sensitive data in the HTTP trace were supposed to be redacted, but
+   we failed to do so in HTTP/2 requests.
+
+ * "make clean" has been updated to remove leftover .depend/
+   directories, even when it is not told to use them to compute header
+   dependencies.
+
+ * Protocol v0 clients can get stuck parsing a malformed feature line.
+
+ * A few kinds of changes "git status" can show were not documented.
+   (merge d2a534c515 ja/doc-status-types-and-copies later to maint).
+
+ * The mergesort implementation used to sort linked list has been
+   optimized.
+   (merge c90cfc225b rs/mergesort later to maint).
+
+ * An editor session launched during a Git operation (e.g. during 'git
+   commit') can leave the terminal in a funny state.  The code path
+   has updated to save the terminal state before, and restore it
+   after, it spawns an editor.
+   (merge 3d411afabc cm/save-restore-terminal later to maint).
+
+ * "git cat-file --batch" with the "--batch-all-objects" option is
+   supposed to iterate over all the objects found in a repository, but
+   it used to translate these object names using the replace mechanism,
+   which defeats the point of enumerating all objects in the repository.
+   This has been corrected.
+   (merge bf972896d7 jk/cat-file-batch-all-wo-replace later to maint).
+
+ * Recent sparse-index work broke safety against attempts to add paths
+   with trailing slashes to the index, which has been corrected.
+   (merge c8ad9d04c6 rs/make-verify-path-really-verify-again later to maint).
+
+ * The "--color-lines" and "--color-by-age" options of "git blame"
+   have been missing, which are now documented.
+   (merge 8c32856133 bs/doc-blame-color-lines later to maint).
+
+ * The PATH used in CI job may be too wide and let incompatible dlls
+   to be grabbed, which can cause the build&test to fail.  Tighten it.
+   (merge 7491ef6198 js/windows-ci-path-fix later to maint).
+
+ * Avoid performance measurements from getting ruined by gc and other
+   housekeeping pauses interfering in the middle.
+   (merge be79131a53 rs/disable-gc-during-perf-tests later to maint).
+
+ * Stop "git add --dry-run" from creating new blob and tree objects.
+   (merge e578d0311d rs/add-dry-run-without-objects later to maint).
+
+ * "git commit" gave duplicated error message when the object store
+   was unwritable, which has been corrected.
+   (merge 4ef91a2d79 ab/fix-commit-error-message-upon-unwritable-object-store later to maint).
+
+ * Recent sparse-index addition, namely any use of index_name_pos(),
+   can expand sparse index entries and breaks any code that walks
+   cache-tree or existing index entries.  One such instance of such a
+   breakage has been corrected.
+
+ * The xxdiff difftool backend can exit with status 128, which the
+   difftool-helper that launches the backend takes as a significant
+   failure, when it is not significant at all.  Work it around.
+   (merge 571f4348dd da/mergetools-special-case-xxdiff-exit-128 later to maint).
+
+ * Improve test framework around unwritable directories.
+   (merge 5d22e18965 ab/test-cleanly-recreate-trash-directory later to maint).
+
+ * "git push" client talking to an HTTP server did not diagnose the
+   lack of the final status report from the other side correctly,
+   which has been corrected.
+   (merge c5c3486f38 jk/http-push-status-fix later to maint).
+
+ * Update "git archive" documentation and give explicit mention on the
+   compression level for both zip and tar.gz format.
+   (merge c4b208c309 bs/archive-doc-compression-level later to maint).
+
+ * Drop "git sparse-checkout" from the list of common commands.
+   (merge 6a9a50a8af sg/sparse-index-not-that-common-a-command later to maint).
+
+ * "git branch -c/-m new old" was not described to copy config, which
+   has been corrected.
+   (merge 8252ec300e jc/branch-copy-doc later to maint).
+
+ * Squelch over-eager warning message added during this cycle.
+
+ * Fix long-standing shell syntax error in the completion script.
+   (merge 46b0585286 re/completion-fix-test-equality later to maint).
+
+ * Teach "git commit-graph" command not to allow using replace objects
+   at all, as we do not use the commit-graph at runtime when we see
+   object replacement.
+   (merge 095d112f8c ab/ignore-replace-while-working-on-commit-graph later to maint).
+
+ * "git pull --no-verify" did not affect the underlying "git merge".
+   (merge 47bfdfb3fd ar/fix-git-pull-no-verify later to maint).
+
+ * One CI task based on Fedora image noticed a not-quite-kosher
+   construct recently, which has been corrected.
+
+ * "git pull --ff-only" and "git pull --rebase --ff-only" should make
+   it a no-op to attempt pulling from a remote that is behind us, but
+   instead the command errored out by saying it was impossible to
+   fast-forward, which may technically be true, but not a useful thing
+   to diagnose as an error.  This has been corrected.
+   (merge 361cb52383 jc/fix-pull-ff-only-when-already-up-to-date later to maint).
+
+ * The way Cygwin emulates a unix-domain socket, on top of which the
+   simple-ipc mechanism is implemented, can race with the program on
+   the other side that wants to use the socket, and briefly make it
+   appear as a regular file before lstat(2) starts reporting it as a
+   socket.  We now have a workaround on the side that connects to a
+   unix domain socket.
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge f188160be9 ab/bundle-remove-verbose-option later to maint).
+   (merge 8c6b4332b4 rs/close-pack-leakfix later to maint).
+   (merge 51b04c05b7 bs/difftool-msg-tweak later to maint).
+   (merge dd20e4a6db ab/make-compdb-fix later to maint).
+   (merge 6ffb990dc4 os/status-docfix later to maint).
+   (merge 100c2da2d3 rs/p3400-lose-tac later to maint).
+   (merge 76f3b69896 tb/aggregate-ignore-leading-whitespaces later to maint).
+   (merge 6e4fd8bfcd tz/doc-link-to-bundle-format-fix later to maint).
+   (merge f6c013dfa1 jc/doc-commit-header-continuation-line later to maint).
+   (merge ec9a37d69b ab/pkt-line-cleanup later to maint).
+   (merge 8650c6298c ab/fix-make-lint-docs later to maint).
+   (merge 1c720357ce ab/test-lib-diff-cleanup later to maint).
+   (merge 6b615dbece ks/submodule-add-message-fix later to maint).
+   (merge 203eb8381a jc/doc-format-patch-clarify-auto-base later to maint).
+   (merge 559664c792 ab/test-lib later to maint).
diff --git a/Documentation/RelNotes/2.34.1.txt b/Documentation/RelNotes/2.34.1.txt
new file mode 100644
index 0000000000..ad404e9aa0
--- /dev/null
+++ b/Documentation/RelNotes/2.34.1.txt
@@ -0,0 +1,23 @@
+Git v2.34.1 Release Notes
+=========================
+
+This release is primarily to fix a handful of regressions in Git 2.34.
+
+Fixes since v2.34
+-----------------
+
+ * "git grep" looking in a blob that has non-UTF8 payload was
+   completely broken when linked with certain versions of PCREv2
+   library in the latest release.
+
+ * "git pull" with any strategy when the other side is behind us
+   should succeed as it is a no-op, but doesn't.
+
+ * An earlier change in 2.34.0 caused JGit application (that abused
+   GIT_EDITOR mechanism when invoking "git config") to get stuck with
+   a SIGTTOU signal; it has been reverted.
+
+ * An earlier change that broke .gitignore matching has been reverted.
+
+ * SubmittingPatches document gained a syntactically incorrect mark-up,
+   which has been corrected.
diff --git a/Documentation/RelNotes/2.34.2.txt b/Documentation/RelNotes/2.34.2.txt
new file mode 100644
index 0000000000..0c32cd844b
--- /dev/null
+++ b/Documentation/RelNotes/2.34.2.txt
@@ -0,0 +1,6 @@
+Git v2.34.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3, v2.31.2,
+v2.32.1 and v2.33.2 to address the security issue CVE-2022-24765;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.34.3.txt b/Documentation/RelNotes/2.34.3.txt
new file mode 100644
index 0000000000..10f6171ace
--- /dev/null
+++ b/Documentation/RelNotes/2.34.3.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.34.3.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.34.3.
diff --git a/Documentation/RelNotes/2.34.4.txt b/Documentation/RelNotes/2.34.4.txt
new file mode 100644
index 0000000000..2a6b223403
--- /dev/null
+++ b/Documentation/RelNotes/2.34.4.txt
@@ -0,0 +1,6 @@
+Git v2.34.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5, v2.31.4,
+v2.32.3 and v2.33.4 to address the security issue CVE-2022-29187;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.34.5.txt b/Documentation/RelNotes/2.34.5.txt
new file mode 100644
index 0000000000..0e8999204d
--- /dev/null
+++ b/Documentation/RelNotes/2.34.5.txt
@@ -0,0 +1,5 @@
+Git v2.34.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.6; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.34.6.txt b/Documentation/RelNotes/2.34.6.txt
new file mode 100644
index 0000000000..b32080dba8
--- /dev/null
+++ b/Documentation/RelNotes/2.34.6.txt
@@ -0,0 +1,5 @@
+Git v2.34.6 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.34.7.txt b/Documentation/RelNotes/2.34.7.txt
new file mode 100644
index 0000000000..88898adacc
--- /dev/null
+++ b/Documentation/RelNotes/2.34.7.txt
@@ -0,0 +1,7 @@
+Git v2.34.7 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8, v2.31.7,
+v2.32.6 and v2.33.7 to address the security issues CVE-2023-22490
+and CVE-2023-23946; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.34.8.txt b/Documentation/RelNotes/2.34.8.txt
new file mode 100644
index 0000000000..2b5bd7d9a3
--- /dev/null
+++ b/Documentation/RelNotes/2.34.8.txt
@@ -0,0 +1,7 @@
+Git v2.34.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9, v2.31.8,
+v2.32.7 and v2.33.8 to address the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.35.0.txt b/Documentation/RelNotes/2.35.0.txt
new file mode 100644
index 0000000000..d69b50d180
--- /dev/null
+++ b/Documentation/RelNotes/2.35.0.txt
@@ -0,0 +1,412 @@
+Git 2.35 Release Notes
+======================
+
+Updates since Git 2.34
+----------------------
+
+Backward compatibility warts
+
+ * "_" is now treated as any other URL-valid characters in an URL when
+   matching the per-URL configuration variable names.
+
+ * The color palette used by "git grep" has been updated to match that
+   of GNU grep.
+
+
+Note to those who build from the source
+
+ * You may need to define NO_UNCOMPRESS2 Makefile macro if you build
+   with zlib older than 1.2.9.
+
+ * If your compiler cannot grok C99, the build will fail.  See the
+   instruction at the beginning of git-compat-util.h if this happens
+   to you.
+
+
+UI, Workflows & Features
+
+ * "git status --porcelain=v2" now show the number of stash entries
+   with --show-stash like the normal output does.
+
+ * "git stash" learned the "--staged" option to stash away what has
+   been added to the index (and nothing else).
+
+ * "git var GIT_DEFAULT_BRANCH" is a way to see what name is used for
+   the newly created branch if "git init" is run.
+
+ * Various operating modes of "git reset" have been made to work
+   better with the sparse index.
+
+ * "git submodule deinit" for a submodule whose .git metadata
+   directory is embedded in its working tree refused to work, until
+   the submodule gets converted to use the "absorbed" form where the
+   metadata directory is stored in superproject, and a gitfile at the
+   top-level of the working tree of the submodule points at it.  The
+   command is taught to convert such submodules to the absorbed form
+   as needed.
+
+ * The completion script (in contrib/) learns that the "--date"
+   option of commands from the "git log" family takes "human" and
+   "auto" as valid values.
+
+ * "Zealous diff3" style of merge conflict presentation has been added.
+
+ * The "git log --format=%(describe)" placeholder has been extended to
+   allow passing selected command-line options to the underlying "git
+   describe" command.
+
+ * "default" and "reset" have been added to our color palette.
+
+ * The cryptographic signing using ssh keys can specify literal keys
+   for keytypes whose name do not begin with the "ssh-" prefix by
+   using the "key::" prefix mechanism (e.g. "key::ecdsa-sha2-nistp256").
+
+ * "git fetch" without the "--update-head-ok" option ought to protect
+   a checked out branch from getting updated, to prevent the working
+   tree that checks it out to go out of sync.  The code was written
+   before the use of "git worktree" got widespread, and only checked
+   the branch that was checked out in the current worktree, which has
+   been updated.
+
+ * "git name-rev" has been tweaked to give output that is shorter and
+   easier to understand.
+
+ * "git apply" has been taught to ignore a message without a patch
+   with the "--allow-empty" option.  It also learned to honor the
+   "--quiet" option given from the command line.
+
+ * The "init" and "set" subcommands in "git sparse-checkout" have been
+   unified for a better user experience and performance.
+
+ * Many git commands that deal with working tree files try to remove a
+   directory that becomes empty (i.e. "git switch" from a branch that
+   has the directory to another branch that does not would attempt
+   remove all files in the directory and the directory itself).  This
+   drops users into an unfamiliar situation if the command was run in
+   a subdirectory that becomes subject to removal due to the command.
+   The commands have been taught to keep an empty directory if it is
+   the directory they were started in to avoid surprising users.
+
+ * "git am" learns "--empty=(stop|drop|keep)" option to tweak what is
+   done to a piece of e-mail without a patch in it.
+
+ * The default merge message prepared by "git merge" records the name
+   of the current branch; the name can be overridden with a new option
+   to allow users to pretend a merge is made on a different branch.
+
+ * The way "git p4" shows file sizes in its output has been updated to
+   use human-readable units.
+
+ * "git -c branch.autosetupmerge=inherit branch new old" makes "new"
+   to have the same upstream as the "old" branch, instead of marking
+   "old" itself as its upstream.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The use of errno as a means to carry the nature of error in the ref
+   API implementation has been reworked and reduced.
+
+ * Teach and encourage first-time contributors to this project to
+   state the base commit when they submit their topic.
+
+ * The command line completion for "git send-email" options have been
+   tweaked to make it easier to keep it in sync with the command itself.
+
+ * Ensure that the sparseness of the in-core index matches the
+   index.sparse configuration specified by the repository immediately
+   after the on-disk index file is read.
+
+ * Code clean-up to eventually allow information on remotes defined
+   for an arbitrary repository to be read.
+
+ * Build optimization.
+
+ * Tighten code for testing pack-bitmap.
+
+ * Weather balloon to break people with compilers that do not support
+   C99.
+
+ * The "reftable" backend for the refs API, without integrating into
+   the refs subsystem, has been added.
+
+ * More tests are marked as leak-free.
+
+ * The test framework learns to list unsatisfied test prerequisites,
+   and optionally error out when prerequisites that are expected to be
+   satisfied are not.
+
+ * The default setting for trace2 event nesting was too low to cause
+   test failures, which is worked around by bumping it up in the test
+   framework.
+
+ * Drop support for TravisCI and update test workflows at GitHub.
+
+ * Many tests that used to need GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+   mechanism to force "git" to use 'master' as the default name for
+   the initial branch no longer need it; the use of the mechanism from
+   them have been removed.
+
+ * Allow running our tests while disabling fsync.
+
+ * Document the parameters given to the reflog entry iterator callback
+   functions.
+   (merge e6e94f34b2 jc/reflog-iterator-callback-doc later to maint).
+
+ * The test helper for refs subsystem learned to write bogus and/or
+   nonexistent object name to refs to simulate error situations we
+   want to test Git in.
+
+ * "diff --histogram" optimization.
+
+ * Weather balloon to find compilers that do not grok variable
+   declaration in the for() loop.
+
+ * diff and blame commands have been taught to work better with sparse
+   index.
+
+ * The chainlint test script linter in the test suite has been updated.
+
+ * The DEVELOPER=yes build uses -std=gnu99 now.
+
+ * "git format-patch" uses a single rev_info instance and then exits.
+   Mark the structure with UNLEAK() macro to squelch leak sanitizer.
+
+ * New interface into the tmp-objdir API to help in-core use of the
+   quarantine feature.
+
+ * Broken &&-chains in the test scripts have been corrected.
+
+ * The RCS keyword substitution in "git p4" used to be done assuming
+   that the contents are UTF-8 text, which can trigger decoding
+   errors.  We now treat the contents as a bytestring for robustness
+   and correctness.
+
+ * The conditions to choose different definitions of the FLEX_ARRAY
+   macro for vendor compilers has been simplified to make it easier to
+   maintain.
+
+ * Correctness and performance update to "diff --color-moved" feature.
+
+ * "git upload-pack" (the other side of "git fetch") used a 8kB buffer
+   but most of its payload came on 64kB "packets".  The buffer size
+   has been enlarged so that such a packet fits.
+
+ * "git fetch" and "git pull" are now declared sparse-index clean.
+   Also "git ls-files" learns the "--sparse" option to help debugging.
+
+ * Similar message templates have been consolidated so that
+   translators need to work on fewer number of messages.
+
+
+Fixes since v2.34
+-----------------
+
+ * "git grep" looking in a blob that has non-UTF8 payload was
+   completely broken when linked with certain versions of PCREv2
+   library in the latest release.
+
+ * Other code cleanup, docfix, build fix, etc.
+
+ * "git pull" with any strategy when the other side is behind us
+   should succeed as it is a no-op, but doesn't.
+
+ * An earlier change in 2.34.0 caused JGit application (that abused
+   GIT_EDITOR mechanism when invoking "git config") to get stuck with
+   a SIGTTOU signal; it has been reverted.
+
+ * An earlier change that broke .gitignore matching has been reverted.
+
+ * Things like "git -c branch.sort=bogus branch new HEAD", i.e. the
+   operation modes of the "git branch" command that do not need the
+   sort key information, no longer errors out by seeing a bogus sort
+   key.
+   (merge 98e7ab6d42 jc/fix-ref-sorting-parse later to maint).
+
+ * The compatibility implementation for unsetenv(3) were written to
+   mimic ancient, non-POSIX, variant seen in an old glibc; it has been
+   changed to return an integer to match the more modern era.
+   (merge a38989bd5b jc/unsetenv-returns-an-int later to maint).
+
+ * The clean/smudge conversion code path has been prepared to better
+   work on platforms where ulong is narrower than size_t.
+   (merge 596b5e77c9 mc/clean-smudge-with-llp64 later to maint).
+
+ * Redact the path part of packfile URI that appears in the trace output.
+   (merge 0ba558ffb1 if/redact-packfile-uri later to maint).
+
+ * CI has been taught to catch some Unicode directional formatting
+   sequence that can be used in certain mischief.
+   (merge 0e7696c64d js/ci-no-directional-formatting later to maint).
+
+ * The "--date=format:<strftime>" gained a workaround for the lack of
+   system support for a non-local timezone to handle "%s" placeholder.
+   (merge 9b591b9403 jk/strbuf-addftime-seconds-since-epoch later to maint).
+
+ * The "merge" subcommand of "git jump" (in contrib/) silently ignored
+   pathspec and other parameters.
+   (merge 67ba13e5a4 jk/jump-merge-with-pathspec later to maint).
+
+ * The code to decode the length of packed object size has been
+   corrected.
+   (merge 34de5b8eac jt/pack-header-lshift-overflow later to maint).
+
+ * The advice message given by "git pull" when the user hasn't made a
+   choice between merge and rebase still said that the merge is the
+   default, which no longer is the case.  This has been corrected.
+   (merge 71076d0edd ah/advice-pull-has-no-preference-between-rebase-and-merge later to maint).
+
+ * "git fetch", when received a bad packfile, can fail with SIGPIPE.
+   This wasn't wrong per-se, but we now detect the situation and fail
+   in a more predictable way.
+   (merge 2a4aed42ec jk/fetch-pack-avoid-sigpipe-to-index-pack later to maint).
+
+ * The function to cull a child process and determine the exit status
+   had two separate code paths for normal callers and callers in a
+   signal handler, and the latter did not yield correct value when the
+   child has caught a signal.  The handling of the exit status has
+   been unified for these two code paths.  An existing test with
+   flakiness has also been corrected.
+   (merge 5263e22cba jk/t7006-sigpipe-tests-fix later to maint).
+
+ * When a non-existent program is given as the pager, we tried to
+   reuse an uninitialized child_process structure and crashed, which
+   has been fixed.
+   (merge f917f57f40 em/missing-pager later to maint).
+
+ * The single-key-input mode in "git add -p" had some code to handle
+   keys that generate a sequence of input via ReadKey(), which did not
+   handle end-of-file correctly, which has been fixed.
+   (merge fc8a8126df cb/add-p-single-key-fix later to maint).
+
+ * "git rebase -x" added an unnecessary 'exec' instructions before
+   'noop', which has been corrected.
+   (merge cc9dcdee61 en/rebase-x-fix later to maint).
+
+ * When the "git push" command is killed while the receiving end is
+   trying to report what happened to the ref update proposals, the
+   latter used to die, due to SIGPIPE.  The code now ignores SIGPIPE
+   to increase our chances to run the post-receive hook after it
+   happens.
+   (merge d34182b9e3 rj/receive-pack-avoid-sigpipe-during-status-reporting later to maint).
+
+ * "git worktree add" showed "Preparing worktree" message to the
+   standard output stream, but when it failed, the message from die()
+   went to the standard error stream.  Depending on the order the
+   stdio streams are flushed at the program end, this resulted in
+   confusing output.  It has been corrected by sending all the chatty
+   messages to the standard error stream.
+   (merge b50252484f es/worktree-chatty-to-stderr later to maint).
+
+ * Coding guideline document has been updated to clarify what goes to
+   standard error in our system.
+   (merge e258eb4800 es/doc-stdout-vs-stderr later to maint).
+
+ * The sparse-index/sparse-checkout feature had a bug in its use of
+   the matching code to determine which path is in or outside the
+   sparse checkout patterns.
+   (merge 8c5de0d265 ds/sparse-deep-pattern-checkout-fix later to maint).
+
+ * "git rebase -x" by mistake started exporting the GIT_DIR and
+   GIT_WORK_TREE environment variables when the command was rewritten
+   in C, which has been corrected.
+   (merge 434e0636db en/rebase-x-wo-git-dir-env later to maint).
+
+ * When "git log" implicitly enabled the "decoration" processing
+   without being explicitly asked with "--decorate" option, it failed
+   to read and honor the settings given by the "--decorate-refs"
+   option.
+
+ * "git fetch --set-upstream" did not check if there is a current
+   branch, leading to a segfault when it is run on a detached HEAD,
+   which has been corrected.
+   (merge 17baeaf82d ab/fetch-set-upstream-while-detached later to maint).
+
+ * Among some code paths that ask an yes/no question, only one place
+   gave a prompt that looked different from the others, which has been
+   updated to match what the others create.
+   (merge 0fc8ed154c km/help-prompt-fix later to maint).
+
+ * "git log --invert-grep --author=<name>" used to exclude commits
+   written by the given author, but now "--invert-grep" only affects
+   the matches made by the "--grep=<pattern>" option.
+   (merge 794c000267 rs/log-invert-grep-with-headers later to maint).
+
+ * "git grep --perl-regexp" failed to match UTF-8 characters with
+   wildcard when the pattern consists only of ASCII letters, which has
+   been corrected.
+   (merge 32e3e8bc55 rs/pcre2-utf later to maint).
+
+ * Certain sparse-checkout patterns that are valid in non-cone mode
+   led to segfault in cone mode, which has been corrected.
+
+ * Use of certain "git rev-list" options with "git fast-export"
+   created nonsense results (the worst two of which being "--reverse"
+   and "--invert-grep --grep=<foo>").  The use of "--first-parent" is
+   made to behave a bit more sensible than before.
+   (merge 726a228dfb ws/fast-export-with-revision-options later to maint).
+
+ * Perf tests were run with end-user's shell, but it has been
+   corrected to use the shell specified by $TEST_SHELL_PATH.
+   (merge 9ccab75608 ja/perf-use-specified-shell later to maint).
+
+ * Fix dependency rules to generate hook-list.h header file.
+   (merge d3fd1a6667 ab/makefile-hook-list-dependency-fix later to maint).
+
+ * "git stash" by default triggers its "push" action, but its
+   implementation also made "git stash -h" to show short help only for
+   "git stash push", which has been corrected.
+   (merge ca7990cea5 ab/do-not-limit-stash-help-to-push later to maint).
+
+ * "git apply --3way" bypasses the attempt to do a three-way
+   application in more cases to address the regression caused by the
+   recent change to use direct application as a fallback.
+   (merge 34d607032c jz/apply-3-corner-cases later to maint).
+
+ * Fix performance-releated bug in "git subtree" (in contrib/).
+   (merge 3ce8888fb4 jl/subtree-check-parents-argument-passing-fix later to maint).
+
+ * Extend the guidance to choose the base commit to build your work
+   on, and hint/nudge contributors to read others' changes.
+   (merge fdfae830f8 jc/doc-submitting-patches-choice-of-base later to maint).
+
+ * A corner case bug in the ort merge strategy has been corrected.
+   (merge d30126c20d en/merge-ort-renorm-with-rename-delete-conflict-fix later to maint).
+
+ * "git stash apply" forgot to attempt restoring untracked files when
+   it failed to restore changes to tracked ones.
+   (merge 71cade5a0b en/stash-df-fix later to maint).
+
+ * Calling dynamically loaded functions on Windows has been corrected.
+   (merge 4a9b204920 ma/windows-dynload-fix later to maint).
+
+ * Some lockfile code called free() in signal-death code path, which
+   has been corrected.
+   (merge 58d4d7f1c5 ps/lockfile-cleanup-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 74db416c9c cw/protocol-v2-doc-fix later to maint).
+   (merge f9b2b6684d ja/doc-cleanup later to maint).
+   (merge 7d1b866778 jc/fix-first-object-walk later to maint).
+   (merge 538ac74604 js/trace2-avoid-recursive-errors later to maint).
+   (merge 152923b132 jk/t5319-midx-corruption-test-deflake later to maint).
+   (merge 9081a421a6 ab/checkout-branch-info-leakfix later to maint).
+   (merge 42c456ff81 rs/mergesort later to maint).
+   (merge ad506e6780 tl/midx-docfix later to maint).
+   (merge bf5b83fd8a hk/ci-checkwhitespace-commentfix later to maint).
+   (merge 49f1eb3b34 jk/refs-g11-workaround later to maint).
+   (merge 7d3fc7df70 jt/midx-doc-fix later to maint).
+   (merge 7b089120d9 hn/create-reflog-simplify later to maint).
+   (merge 9e12400da8 cb/mingw-gmtime-r later to maint).
+   (merge 0bf0de6cc7 tb/pack-revindex-on-disk-cleanup later to maint).
+   (merge 2c68f577fc ew/cbtree-remove-unused-and-broken-cb-unlink later to maint).
+   (merge eafd6e7e55 ab/die-with-bug later to maint).
+   (merge 91028f7659 jc/grep-patterntype-default-doc later to maint).
+   (merge 47ca93d071 ds/repack-fixlets later to maint).
+   (merge e6a9bc0c60 rs/t4202-invert-grep-test-fix later to maint).
+   (merge deb5407a42 gh/gpg-doc-markup-fix later to maint).
+   (merge 999bba3e0b rs/daemon-plug-leak later to maint).
+   (merge 786eb1ba39 js/l10n-mention-ngettext-early-in-readme later to maint).
+   (merge 2f12b31b74 ab/makefile-msgfmt-wo-stats later to maint).
+   (merge 0517f591ca fs/gpg-unknown-key-test-fix later to maint).
+   (merge 97d6fb5a1f ma/header-dup-cleanup later to maint).
diff --git a/Documentation/RelNotes/2.35.1.txt b/Documentation/RelNotes/2.35.1.txt
new file mode 100644
index 0000000000..726ba250ef
--- /dev/null
+++ b/Documentation/RelNotes/2.35.1.txt
@@ -0,0 +1,6 @@
+Git v2.35.1 Release Notes
+=========================
+
+Git 2.35 shipped with a regression that broke use of "rebase" and
+"stash" in a secondary worktree.  This maintenance release ought to
+fix it.
diff --git a/Documentation/RelNotes/2.35.2.txt b/Documentation/RelNotes/2.35.2.txt
new file mode 100644
index 0000000000..290bfa9ea4
--- /dev/null
+++ b/Documentation/RelNotes/2.35.2.txt
@@ -0,0 +1,7 @@
+Git v2.35.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.3,
+v2.31.2, v2.32.1, v2.33.2 and v2.34.2 to address the security
+issue CVE-2022-24765; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.35.3.txt b/Documentation/RelNotes/2.35.3.txt
new file mode 100644
index 0000000000..5458ba3441
--- /dev/null
+++ b/Documentation/RelNotes/2.35.3.txt
@@ -0,0 +1,4 @@
+Git Documentation/RelNotes/2.35.3.txt Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.35.3.
diff --git a/Documentation/RelNotes/2.35.4.txt b/Documentation/RelNotes/2.35.4.txt
new file mode 100644
index 0000000000..47abd5ad45
--- /dev/null
+++ b/Documentation/RelNotes/2.35.4.txt
@@ -0,0 +1,7 @@
+Git v2.35.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5,
+v2.31.4, v2.32.3, v2.33.4 and v2.34.4 to address the security
+issue CVE-2022-29187; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.35.5.txt b/Documentation/RelNotes/2.35.5.txt
new file mode 100644
index 0000000000..e19cc48b33
--- /dev/null
+++ b/Documentation/RelNotes/2.35.5.txt
@@ -0,0 +1,5 @@
+Git v2.35.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.6; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.35.6.txt b/Documentation/RelNotes/2.35.6.txt
new file mode 100644
index 0000000000..e7ca57bb41
--- /dev/null
+++ b/Documentation/RelNotes/2.35.6.txt
@@ -0,0 +1,5 @@
+Git v2.35.6 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.35.7.txt b/Documentation/RelNotes/2.35.7.txt
new file mode 100644
index 0000000000..42baabfc3b
--- /dev/null
+++ b/Documentation/RelNotes/2.35.7.txt
@@ -0,0 +1,7 @@
+Git v2.35.7 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8, v2.31.7,
+v2.32.6, v2.33.7 and v2.34.7 to address the security issues
+CVE-2023-22490 and CVE-2023-23946; see the release notes for
+these versions for details.
diff --git a/Documentation/RelNotes/2.35.8.txt b/Documentation/RelNotes/2.35.8.txt
new file mode 100644
index 0000000000..3c9c094c2b
--- /dev/null
+++ b/Documentation/RelNotes/2.35.8.txt
@@ -0,0 +1,7 @@
+Git v2.35.8 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8 and v2.34.8 to address the security issues
+CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.36.0.txt b/Documentation/RelNotes/2.36.0.txt
new file mode 100644
index 0000000000..e477fba12d
--- /dev/null
+++ b/Documentation/RelNotes/2.36.0.txt
@@ -0,0 +1,429 @@
+Git 2.36 Release Notes
+======================
+
+Updates since Git 2.35
+----------------------
+
+Backward compatibility warts
+
+ * "git name-rev --stdin" has been deprecated and issues a warning
+   when used; use "git name-rev --annotate-stdin" instead.
+
+ * "git clone --filter=... --recurse-submodules" only makes the
+   top-level a partial clone, while submodules are fully cloned.  This
+   behaviour is changed to pass the same filter down to the submodules.
+
+ * With the fixes for CVE-2022-24765 that are common with versions of
+   Git 2.30.4, 2.31.3, 2.32.2, 2.33.3, 2.34.3, and 2.35.3, Git has
+   been taught not to recognise repositories owned by other users, in
+   order to avoid getting affected by their config files and hooks.
+   You can list the path to the safe/trusted repositories that may be
+   owned by others on a multi-valued configuration variable
+   `safe.directory` to override this behaviour, or use '*' to declare
+   that you trust anything.
+
+
+Note to those who build from the source
+
+ * Since Git 2.31, our source assumed that the compiler you use to
+   build Git supports variadic macros, with an easy-to-use escape
+   hatch to allow compilation without variadic macros with an request
+   to report that you had to use the escape hatch to the list.
+   Because we haven't heard from anybody who actually needed to use
+   the escape hatch, it has been removed, making support of variadic
+   macros a hard requirement.
+
+
+UI, Workflows & Features
+
+ * Assorted updates to "git cat-file", especially "-h".
+
+ * The command line completion (in contrib/) learns to complete
+   arguments to give to "git sparse-checkout" command.
+
+ * "git log --remerge-diff" shows the difference from mechanical merge
+   result and the result that is actually recorded in a merge commit.
+
+ * "git log" and friends learned an option --exclude-first-parent-only
+   to propagate UNINTERESTING bit down only along the first-parent
+   chain, just like --first-parent option shows commits that lack the
+   UNINTERESTING bit only along the first-parent chain.
+
+ * The command line completion script (in contrib/) learned to
+   complete all Git subcommands, including the ones that are normally
+   hidden, when GIT_COMPLETION_SHOW_ALL_COMMANDS is used.
+
+ * "git branch" learned the "--recurse-submodules" option.
+
+ * A user can forget to make a script file executable before giving
+   it to "git bisect run".  In such a case, all tests will exit with
+   126 or 127 error codes, even on revisions that are marked as good.
+   Try to recognize this situation and stop iteration early.
+
+ * When "index-pack" dies due to incoming data exceeding the maximum
+   allowed input size, include the value of the limit in the error
+   message.
+
+ * The error message given by "git switch HEAD~4" has been clarified
+   to suggest the "--detach" option that is required.
+
+ * In sparse-checkouts, files mis-marked as missing from the working tree
+   could lead to later problems.  Such files were hard to discover, and
+   harder to correct.  Automatically detecting and correcting the marking
+   of such files has been added to avoid these problems.
+
+ * "git cat-file" learns "--batch-command" mode, which is a more
+   flexible interface than the existing "--batch" or "--batch-check"
+   modes, to allow different kinds of inquiries made.
+
+ * The level of verbose output from the ort backend during inner merge
+   has been aligned to that of the recursive backend.
+
+ * "git remote rename A B", depending on the number of remote-tracking
+   refs involved, takes long time renaming them.  The command has been
+   taught to show progress bar while making the user wait.
+
+ * Bundle file format gets extended to allow a partial bundle,
+   filtered by similar criteria you would give when making a
+   partial/lazy clone.
+
+ * A new built-in userdiff driver for kotlin has been added.
+
+ * "git repack" learned a new configuration to disable triggering of
+   age-old "update-server-info" command, which is rarely useful these
+   days.
+
+ * "git stash" does not allow subcommands it internally runs as its
+   implementation detail, except for "git reset", to emit messages;
+   now "git reset" part has also been squelched.
+
+ * "git ls-tree" learns "--oid-only" option, similar to "--name-only",
+   and more generalized "--format" option.
+
+ * "git fetch --refetch" learned to fetch everything without telling
+   the other side what we already have, which is useful when you
+   cannot trust what you have in the local object store.
+
+ * "git branch" gives hint when branch tracking cannot be established
+   because fetch refspecs from multiple remote repositories overlap.
+
+ * "git worktree list --porcelain" did not c-quote pathnames and lock
+   reasons with unsafe bytes correctly, which is worked around by
+   introducing NUL terminated output format with "-z".
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git apply" (ab)used the util pointer of the string-list to keep
+   track of how each symbolic link needs to be handled, which has been
+   simplified by using strset.
+
+ * Fix a hand-rolled alloca() imitation that may have violated
+   alignment requirement of data being sorted in compatibility
+   implementation of qsort_s() and stable qsort().
+
+ * Use the parse-options API in "git reflog" command.
+
+ * The conditional inclusion mechanism of configuration files using
+   "[includeIf <condition>]" learns to base its decision on the
+   URL of the remote repository the repository interacts with.
+   (merge 399b198489 jt/conditional-config-on-remote-url later to maint).
+
+ * "git name-rev --stdin" does not behave like usual "--stdin" at
+   all.  Start the process of renaming it to "--annotate-stdin".
+   (merge a2585719b3 jc/name-rev-stdin later to maint).
+
+ * "git update-index", "git checkout-index", and "git clean" are
+   taught to work better with the sparse checkout feature.
+
+ * Use an internal call to reset_head() helper function instead of
+   spawning "git checkout" in "rebase", and update code paths that are
+   involved in the change.
+
+ * Messages "ort" merge backend prepares while dealing with conflicted
+   paths were unnecessarily confusing since it did not differentiate
+   inner merges and outer merges.
+
+ * Small modernization of the rerere-train script (in contrib/).
+
+ * Use designated initializers we started using in mid 2017 in more
+   parts of the codebase that are relatively quiescent.
+
+ * Improve failure case behaviour of xdiff library when memory
+   allocation fails.
+
+ * General clean-up in reftable implementation, including
+   clarification of the API documentation, tightening the code to
+   honor documented length limit, etc.
+
+ * Remove the escape hatch we added when we introduced the weather
+   balloon to use variadic macros unconditionally, to make it official
+   that we now have a hard dependency on the feature.
+
+ * Makefile refactoring with a bit of suffixes rule stripping to
+   optimize the runtime overhead.
+
+ * "git stash drop" is reimplemented as an internal call to
+   reflog_delete() function, instead of invoking "git reflog delete"
+   via run_command() API.
+
+ * Count string_list items in size_t, not "unsigned int".
+
+ * The single-key interactive operation used by "git add -p" has been
+   made more robust.
+
+ * Remove unneeded <meta http-equiv=content-type...> from gitweb
+   output.
+
+ * "git name-rev" learned to use the generation numbers when setting
+   the lower bound of searching commits used to explain the revision,
+   when available, instead of committer time.
+
+ * Replace core.fsyncObjectFiles with two new configuration variables,
+   core.fsync and core.fsyncMethod.
+
+ * Updates to refs traditionally weren't fsync'ed, but we can
+   configure using core.fsync variable to do so.
+
+ * "git reflog" command now uses parse-options API to parse its
+   command line options.
+
+
+Fixes since v2.35
+-----------------
+
+ * "rebase" and "stash" in secondary worktrees are broken in
+   Git 2.35.0, which has been corrected.
+
+ * "git pull --rebase" ignored the rebase.autostash configuration
+   variable when the remote history is a descendant of our history,
+   which has been corrected.
+   (merge 3013d98d7a pb/pull-rebase-autostash-fix later to maint).
+
+ * "git update-index --refresh" has been taught to deal better with
+   racy timestamps (just like "git status" already does).
+   (merge 2ede073fd2 ms/update-index-racy later to maint).
+
+ * Avoid tests that are run under GIT_TRACE2 set from failing
+   unnecessarily.
+   (merge 944d808e42 js/test-unset-trace2-parents later to maint).
+
+ * The merge-ort misbehaved when merge.renameLimit configuration is
+   set too low and failed to find all renames.
+   (merge 9ae39fef7f en/merge-ort-restart-optim-fix later to maint).
+
+ * We explain that revs come first before the pathspec among command
+   line arguments, but did not spell out that dashed options come
+   before other args, which has been corrected.
+   (merge c11f95010c tl/doc-cli-options-first later to maint).
+
+ * "git add -p" rewritten in C regressed hunk splitting in some cases,
+   which has been corrected.
+   (merge 7008ddc645 pw/add-p-hunk-split-fix later to maint).
+
+ * "git fetch --negotiate-only" is an internal command used by "git
+   push" to figure out which part of our history is missing from the
+   other side.  It should never recurse into submodules even when
+   fetch.recursesubmodules configuration variable is set, nor it
+   should trigger "gc".  The code has been tightened up to ensure it
+   only does common ancestry discovery and nothing else.
+   (merge de4eaae63a gc/fetch-negotiate-only-early-return later to maint).
+
+ * The code path that verifies signatures made with ssh were made to
+   work better on a system with CRLF line endings.
+   (merge caeef01ea7 fs/ssh-signing-crlf later to maint).
+
+ * "git sparse-checkout init" failed to write into $GIT_DIR/info
+   directory when the repository was created without one, which has
+   been corrected to auto-create it.
+   (merge 7f44842ac1 jt/sparse-checkout-leading-dir-fix later to maint).
+
+ * Cloning from a repository that does not yet have any branches or
+   tags but has other refs resulted in a "remote transport reported
+   error", which has been corrected.
+   (merge dccea605b6 jt/clone-not-quite-empty later to maint).
+
+ * Mark in various places in the code that the sparse index and the
+   split index features are mutually incompatible.
+   (merge 451b66c533 js/sparse-vs-split-index later to maint).
+
+ * Update the logic to compute alignment requirement for our mem-pool.
+   (merge e38bcc66d8 jc/mem-pool-alignment later to maint).
+
+ * Pick a better random number generator and use it when we prepare
+   temporary filenames.
+   (merge 47efda967c bc/csprng-mktemps later to maint).
+
+ * Update the contributor-facing documents on proposed log messages.
+   (merge cdba0295b0 jc/doc-log-messages later to maint).
+
+ * When "git fetch --prune" failed to prune the refs it wanted to
+   prune, the command issued error messages but exited with exit
+   status 0, which has been corrected.
+   (merge c9e04d905e tg/fetch-prune-exit-code-fix later to maint).
+
+ * Problems identified by Coverity in the reftable code have been
+   corrected.
+   (merge 01033de49f hn/reftable-coverity-fixes later to maint).
+
+ * A bug that made multi-pack bitmap and the object order out-of-sync,
+   making the .midx data corrupt, has been fixed.
+   (merge f8b60cf99b tb/midx-bitmap-corruption-fix later to maint).
+
+ * The build procedure has been taught to notice older version of zlib
+   and enable our replacement uncompress2() automatically.
+   (merge 07564773c2 ab/auto-detect-zlib-compress2 later to maint).
+
+ * Interaction between fetch.negotiationAlgorithm and
+   feature.experimental configuration variables has been corrected.
+   (merge 714edc620c en/fetch-negotiation-default-fix later to maint).
+
+ * "git diff --diff-filter=aR" is now parsed correctly.
+   (merge 75408ca949 js/diff-filter-negation-fix later to maint).
+
+ * When "git subtree" wants to create a merge, it used "git merge" and
+   let it be affected by end-user's "merge.ff" configuration, which
+   has been corrected.
+   (merge 9158a3564a tk/subtree-merge-not-ff-only later to maint).
+
+ * Unlike "git apply", "git patch-id" did not handle patches with
+   hunks that has only 1 line in either preimage or postimage, which
+   has been corrected.
+   (merge 757e75c81e jz/patch-id-hunk-header-parsing-fix later to maint).
+
+ * "receive-pack" checks if it will do any ref updates (various
+   conditions could reject a push) before received objects are taken
+   out of the temporary directory used for quarantine purposes, so
+   that a push that is known-to-fail will not leave crufts that a
+   future "gc" needs to clean up.
+   (merge 5407764069 cb/clear-quarantine-early-on-all-ref-update-errors later to maint).
+
+ * When there is no object to write .bitmap file for, "git
+   multi-pack-index" triggered an error, instead of just skipping,
+   which has been corrected.
+   (merge eb57277ba3 tb/midx-no-bitmap-for-no-objects later to maint).
+
+ * "git cmd -h" outside a repository should error out cleanly for many
+   commands, but instead it hit a BUG(), which has been corrected.
+   (merge 87ad07d735 js/short-help-outside-repo-fix later to maint).
+
+ * "working tree" and "per-worktree ref" were in glossary, but
+   "worktree" itself wasn't, which has been corrected.
+   (merge 2df5387ed0 jc/glossary-worktree later to maint).
+
+ * L10n support for a few error messages.
+   (merge 3d3c23b3a7 bs/forbid-i18n-of-protocol-token-in-fetch-pack later to maint).
+
+ * Test modernization.
+   (merge d4fe066e4b sy/t0001-use-path-is-helper later to maint).
+
+ * "git log --graph --graph" used to leak a graph structure, and there
+   was no way to countermand "--graph" that appear earlier on the
+   command line.  A "--no-graph" option has been added and resource
+   leakage has been plugged.
+
+ * Error output given in response to an ambiguous object name has been
+   improved.
+   (merge 3a73c1dfaf ab/ambiguous-object-name later to maint).
+
+ * "git sparse-checkout" wants to work with per-worktree configuration,
+   but did not work well in a worktree attached to a bare repository.
+   (merge 3ce1138272 ds/sparse-checkout-requires-per-worktree-config later to maint).
+
+ * Setting core.untrackedCache to true failed to add the untracked
+   cache extension to the index.
+
+ * Workaround we have for versions of PCRE2 before their version 10.36
+   were in effect only for their versions newer than 10.36 by mistake,
+   which has been corrected.
+   (merge 97169fc361 rs/pcre-invalid-utf8-fix-fix later to maint).
+
+ * Document Taylor as a new member of Git PLC at SFC.  Welcome.
+   (merge e8d56ca863 tb/coc-plc-update later to maint).
+
+ * "git checkout -b branch/with/multi/level/name && git stash" only
+   recorded the last level component of the branch name, which has
+   been corrected.
+
+ * Check the return value from parse_tree_indirect() to turn segfaults
+   into calls to die().
+   (merge 8d2eaf649a gc/parse-tree-indirect-errors later to maint).
+
+ * Newer version of GPGSM changed its output in a backward
+   incompatible way to break our code that parses its output.  It also
+   added more processes our tests need to kill when cleaning up.
+   Adjustments have been made to accommodate these changes.
+   (merge b0b70d54c4 fs/gpgsm-update later to maint).
+
+ * The untracked cache newly computed weren't written back to the
+   on-disk index file when there is no other change to the index,
+   which has been corrected.
+
+ * "git config -h" did not describe the "--type" option correctly.
+   (merge 5445124fad mf/fix-type-in-config-h later to maint).
+
+ * The way generation number v2 in the commit-graph files are
+   (not) handled has been corrected.
+   (merge 6dbf4b8172 ds/commit-graph-gen-v2-fixes later to maint).
+
+ * The method to trigger malloc check used in our tests no longer work
+   with newer versions of glibc.
+   (merge baedc59543 ep/test-malloc-check-with-glibc-2.34 later to maint).
+
+ * When "git fetch --recurse-submodules" grabbed submodule commits
+   that would be needed to recursively check out newly fetched commits
+   in the superproject, it only paid attention to submodules that are
+   in the current checkout of the superproject.  We now do so for all
+   submodules that have been run "git submodule init" on.
+
+ * "git rebase $base $non_branch_commit", when $base is an ancestor or
+   the $non_branch_commit, modified the current branch, which has been
+   corrected.
+
+ * When "shallow" information is updated, we forgot to update the
+   in-core equivalent, which has been corrected.
+
+ * When creating a loose object file, we didn't report the exact
+   filename of the file we failed to fsync, even though the
+   information was readily available, which has been corrected.
+
+ * "git am" can read from the standard input when no mailbox is given
+   on the command line, but the end-user gets no indication when it
+   happens, making Git appear stuck.
+   (merge 7b20af6a06 jc/mailsplit-warn-on-tty later to maint).
+
+ * "git mv" failed to refresh the cached stat information for the
+   entry it moved.
+   (merge b7f9130a06 vd/mv-refresh-stat later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge cfc5cf428b jc/find-header later to maint).
+   (merge 40e7cfdd46 jh/p4-fix-use-of-process-error-exception later to maint).
+   (merge 727e6ea350 jh/p4-spawning-external-commands-cleanup later to maint).
+   (merge 0a6adc26e2 rs/grep-expr-cleanup later to maint).
+   (merge 4ed7dfa713 po/readme-mention-contributor-hints later to maint).
+   (merge 6046f7a91c en/plug-leaks-in-merge later to maint).
+   (merge 8c591dbfce bc/clarify-eol-attr later to maint).
+   (merge 518e15db74 rs/parse-options-lithelp-help later to maint).
+   (merge cbac0076ef gh/doc-typos later to maint).
+   (merge ce14de03db ab/no-errno-from-resolve-ref-unsafe later to maint).
+   (merge 2826ffad8c rc/negotiate-only-typofix later to maint).
+   (merge 0f03f04c5c en/sparse-checkout-leakfix later to maint).
+   (merge 74f3390dde sy/diff-usage-typofix later to maint).
+   (merge 45d0212a71 ll/doc-mktree-typofix later to maint).
+   (merge e9b272e4c1 js/no-more-legacy-stash later to maint).
+   (merge 6798b08e84 ab/do-not-hide-failures-in-git-dot-pm later to maint).
+   (merge 9325285df4 po/doc-check-ignore-markup-fix later to maint).
+   (merge cd26cd6c7c sy/modernize-t-lib-read-tree-m-3way later to maint).
+   (merge d17294a05e ab/hash-object-leakfix later to maint).
+   (merge b8403129d3 jd/t0015-modernize later to maint).
+   (merge 332acc248d ds/mailmap later to maint).
+   (merge 04bf052eef ab/grep-patterntype later to maint).
+   (merge 6ee36364eb ab/diff-free-more later to maint).
+   (merge 63a36017fe nj/read-tree-doc-reffix later to maint).
+   (merge eed36fce38 sm/no-git-in-upstream-of-pipe-in-tests later to maint).
+   (merge c614beb933 ep/t6423-modernize later to maint).
+   (merge 57be9c6dee ab/reflog-prep-fix later to maint).
+   (merge 5327d8982a js/in-place-reverse-in-sequencer later to maint).
+   (merge 2e2c0be51e dp/worktree-repair-in-usage later to maint).
+   (merge 6563706568 jc/coding-guidelines-decl-in-for-loop later to maint).
diff --git a/Documentation/RelNotes/2.36.1.txt b/Documentation/RelNotes/2.36.1.txt
new file mode 100644
index 0000000000..a9617095db
--- /dev/null
+++ b/Documentation/RelNotes/2.36.1.txt
@@ -0,0 +1,33 @@
+Git v2.36.1 Release Notes
+=========================
+
+Fixes since v2.36
+-----------------
+
+ * "git submodule update" without pathspec should silently skip an
+   uninitialized submodule, but it started to become noisy by mistake.
+
+ * "diff-tree --stdin" has been broken for about a year, but 2.36
+   release broke it even worse by breaking running the command with
+   <pathspec>, which in turn broke "gitk" and got noticed.  This has
+   been corrected by aligning its behaviour to that of "log".
+
+ * Regression fix for 2.36 where "git name-rev" started to sometimes
+   reference strings after they are freed.
+
+ * "git show <commit1> <commit2>... -- <pathspec>" lost the pathspec
+   when showing the second and subsequent commits, which has been
+   corrected.
+
+ * "git fast-export -- <pathspec>" lost the pathspec when showing the
+   second and subsequent commits, which has been corrected.
+
+ * "git format-patch <args> -- <pathspec>" lost the pathspec when
+   showing the second and subsequent commits, which has been
+   corrected.
+
+ * Get rid of a bogus and over-eager coccinelle rule.
+
+ * Correct choices of C compilers used in various CI jobs.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.36.2.txt b/Documentation/RelNotes/2.36.2.txt
new file mode 100644
index 0000000000..958f5b4102
--- /dev/null
+++ b/Documentation/RelNotes/2.36.2.txt
@@ -0,0 +1,56 @@
+Git v2.36.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.5, v2.31.4,
+v2.32.3, v2.33.4, v2.34.4 and v2.35.4 to address the security
+issue CVE-2022-29187; see the release notes for these versions
+for details.
+
+Apart from that, this maintenance release is primarily to merge down
+updates to the build and CI procedures from the 'master' front, in
+order to ensure that we can cut healthy maintenance releases in the
+future.  It also contains a handful of small and trivially-correct
+bugfixes.
+
+Fixes since v2.36.1
+-------------------
+
+ * Fixes real problems noticed by gcc 12 and works around false
+   positives.
+
+ * Update URL to the gitk repository.
+
+ * The "--current" option of "git show-branch" should have been made
+   incompatible with the "--reflog" mode, but this was not enforced,
+   which has been corrected.
+
+ * "git archive --add-file=<path>" picked up the raw permission bits
+   from the path and propagated to zip output in some cases, without
+   normalization, which has been corrected (tar output did not have
+   this issue).
+
+ * A bit of test framework fixes with a few fixes to issues found by
+   valgrind.
+
+ * macOS CI jobs have been occasionally flaky due to tentative version
+   skew between perforce and the homebrew packager.  Instead of
+   failing the whole CI job, just let it skip the p4 tests when this
+   happens.
+
+ * The commit summary shown after making a commit is matched to what
+   is given in "git status" not to use the break-rewrite heuristics.
+
+ * Avoid problems from interaction between malloc_check and address
+   sanitizer.
+
+ * "git rebase --keep-base <upstream> <branch-to-rebase>" computed the
+   commit to rebase onto incorrectly, which has been corrected.
+
+ * The path taken by "git multi-pack-index" command from the end user
+   was compared with path internally prepared by the tool withut first
+   normalizing, which lead to duplicated paths not being noticed,
+   which has been corrected.
+
+ * "git clone --origin X" leaked piece of memory that held value read
+   from the clone.defaultRemoteName configuration variable, which has
+   been plugged.
diff --git a/Documentation/RelNotes/2.36.3.txt b/Documentation/RelNotes/2.36.3.txt
new file mode 100644
index 0000000000..56db77b5bd
--- /dev/null
+++ b/Documentation/RelNotes/2.36.3.txt
@@ -0,0 +1,5 @@
+Git v2.36.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.6; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.36.4.txt b/Documentation/RelNotes/2.36.4.txt
new file mode 100644
index 0000000000..58fb93a35f
--- /dev/null
+++ b/Documentation/RelNotes/2.36.4.txt
@@ -0,0 +1,5 @@
+Git v2.36.4 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.36.5.txt b/Documentation/RelNotes/2.36.5.txt
new file mode 100644
index 0000000000..8a098c7916
--- /dev/null
+++ b/Documentation/RelNotes/2.36.5.txt
@@ -0,0 +1,7 @@
+Git v2.36.5 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8, v2.31.7,
+v2.32.6, v2.33.7, v2.34.7 and v2.35.7 to address the security
+issues CVE-2023-22490 and CVE-2023-23946; see the release notes
+for these versions for details.
diff --git a/Documentation/RelNotes/2.36.6.txt b/Documentation/RelNotes/2.36.6.txt
new file mode 100644
index 0000000000..e1edebcc43
--- /dev/null
+++ b/Documentation/RelNotes/2.36.6.txt
@@ -0,0 +1,7 @@
+Git v2.36.6 Release Notes
+=========================
+
+This release merges the fixes that appear in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8 and v2.35.8 to address the security issues
+CVE-2023-25652, CVS-2023-25815, and CVE-2023-29007; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.37.0.txt b/Documentation/RelNotes/2.37.0.txt
new file mode 100644
index 0000000000..99dc7e32f8
--- /dev/null
+++ b/Documentation/RelNotes/2.37.0.txt
@@ -0,0 +1,337 @@
+Git v2.37 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "vimdiff[123]" mergetool drivers have been reimplemented with a
+   more generic layout mechanism.
+
+ * "git -v" and "git -h" are now understood as "git --version" and
+   "git --help".
+
+ * The temporary files fed to external diff command are now generated
+   inside a new temporary directory under the same basename.
+
+ * "git log --since=X" will stop traversal upon seeing a commit that
+   is older than X, but there may be commits behind it that is younger
+   than X when the commit was created with a faulty clock.  A new
+   option is added to keep digging without stopping, and instead
+   filter out commits with timestamp older than X.
+
+ * "git -c branch.autosetupmerge=simple branch $A $B" will set the $B
+   as $A's upstream only when $A and $B shares the same name, and "git
+   -c push.default=simple" on branch $A would push to update the
+   branch $A at the remote $B came from.  Also more places use the
+   sole remote, if exists, before defaulting to 'origin'.
+
+ * A new doc has been added that lists tips for tools to work with
+   Git's codebase.
+
+ * "git remote -v" now shows the list-objects-filter used during
+   fetching from the remote, if available.
+
+ * With the new http.curloptResolve configuration, the CURLOPT_RESOLVE
+   mechanism that allows cURL based applications to use pre-resolved
+   IP addresses for the requests is exposed to the scripts.
+
+ * "git add -i" was rewritten in C some time ago and has been in
+   testing; the reimplementation is now exposed to general public by
+   default.
+
+ * Deprecate non-cone mode of the sparse-checkout feature.
+
+ * Introduce a filesystem-dependent mechanism to optimize the way the
+   bits for many loose object files are ensured to hit the disk
+   platter.
+
+ * The "do not remove the directory the user started Git in" logic,
+   when Git cannot tell where that directory is, is disabled.  Earlier
+   we refused to run in such a case.
+
+ * A mechanism to pack unreachable objects into a "cruft pack",
+   instead of ejecting them into loose form to be reclaimed later, has
+   been introduced.
+
+ * Update the doctype written in gitweb output to xhtml5.
+
+ * The "transfer.credentialsInURL" configuration variable controls what
+   happens when a URL with embedded login credential is used on either
+   "fetch" or "push". Credentials are currently only detected in
+   `remote.<name>.url` config, not `remote.<name>.pushurl`.
+
+ * "git revert" learns "--reference" option to use more human-readable
+   reference to the commit it reverts in the message template it
+   prepares for the user.
+
+ * Various error messages that talk about the removal of
+   "--preserve-merges" in "rebase" have been strengthened, and "rebase
+   --abort" learned to get out of a state that was left by an earlier
+   use of the option.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The performance of the "untracked cache" feature has been improved
+   when "--untracked-files=<mode>" and "status.showUntrackedFiles"
+   are combined.
+
+ * "git stash" works better with sparse index entries.
+
+ * "git show :<path>" learned to work better with the sparse-index
+   feature.
+
+ * Introduce and apply coccinelle rule to discourage an explicit
+   comparison between a pointer and NULL, and applies the clean-up to
+   the maintenance track.
+
+ * Preliminary code refactoring around transport and bundle code.
+
+ * "sparse-checkout" learns to work better with the sparse-index
+   feature.
+
+ * A workflow change for translators are being proposed.  git.pot is
+   no longer version controlled and it is local responsibility of
+   translators to generate it.
+
+ * Plug the memory leaks from the trickiest API of all, the revision
+   walker.
+
+ * Rename .env_array member to .env in the child_process structure.
+
+  * The fsmonitor--daemon handles even more corner cases when
+    watching filesystem events.
+
+ * A new bug() and BUG_if_bug() API is introduced to make it easier to
+   uniformly log "detect multiple bugs and abort in the end" pattern.
+
+
+Fixes since v2.36
+-----------------
+
+ * "git submodule update" without pathspec should silently skip an
+   uninitialized submodule, but it started to become noisy by mistake.
+   (merge 4f1ccef87c gc/submodule-update-part2 later to maint).
+
+ * "diff-tree --stdin" has been broken for about a year, but 2.36
+   release broke it even worse by breaking running the command with
+   <pathspec>, which in turn broke "gitk" and got noticed.  This has
+   been corrected by aligning its behaviour to that of "log".
+   (merge f8781bfda3 jc/diff-tree-stdin-fix later to maint).
+
+ * Regression fix for 2.36 where "git name-rev" started to sometimes
+   reference strings after they are freed.
+   (merge 45a14f578e rs/name-rev-fix-free-after-use later to maint).
+
+ * "git show <commit1> <commit2>... -- <pathspec>" lost the pathspec
+   when showing the second and subsequent commits, which has been
+   corrected.
+   (merge 5cdb38458e jc/show-pathspec-fix later to maint).
+
+ * "git fast-export -- <pathspec>" lost the pathspec when showing the
+   second and subsequent commits, which has been corrected.
+   (merge d1c25272f5 rs/fast-export-pathspec-fix later to maint).
+
+ * "git format-patch <args> -- <pathspec>" lost the pathspec when
+   showing the second and subsequent commits, which has been
+   corrected.
+   (merge 91f8f7e46f rs/format-patch-pathspec-fix later to maint).
+
+ * "git clone --origin X" leaked piece of memory that held value read
+   from the clone.defaultRemoteName configuration variable, which has
+   been plugged.
+   (merge 6dfadc8981 jc/clone-remote-name-leak-fix later to maint).
+
+ * Get rid of a bogus and over-eager coccinelle rule.
+   (merge 08bdd3a185 jc/cocci-xstrdup-or-null-fix later to maint).
+
+ * The path taken by "git multi-pack-index" command from the end user
+   was compared with path internally prepared by the tool without first
+   normalizing, which lead to duplicated paths not being noticed,
+   which has been corrected.
+   (merge 11f9e8de3d ds/midx-normalize-pathname-before-comparison later to maint).
+
+ * Correct choices of C compilers used in various CI jobs.
+   (merge 3506cae04f ab/cc-package-fixes later to maint).
+
+ * Various cleanups to "git p4".
+   (merge 4ff0108d9e jh/p4-various-fixups later to maint).
+
+ * The progress meter of "git blame" was showing incorrect numbers
+   when processing only parts of the file.
+   (merge e5f5d7d42e ea/progress-partial-blame later to maint).
+
+ * "git rebase --keep-base <upstream> <branch-to-rebase>" computed the
+   commit to rebase onto incorrectly, which has been corrected.
+   (merge 9e5ebe9668 ah/rebase-keep-base-fix later to maint).
+
+ * Fix a leak of FILE * in an error codepath.
+   (merge c0befa0c03 kt/commit-graph-plug-fp-leak-on-error later to maint).
+
+ * Avoid problems from interaction between malloc_check and address
+   sanitizer.
+   (merge 067109a5e7 pw/test-malloc-with-sanitize-address later to maint).
+
+ * The commit summary shown after making a commit is matched to what
+   is given in "git status" not to use the break-rewrite heuristics.
+   (merge 84792322ed rs/commit-summary-wo-break-rewrite later to maint).
+
+ * Update a few end-user facing messages around EOL conversion.
+   (merge c970d30c2c ah/convert-warning-message later to maint).
+
+ * Trace2 documentation updates.
+   (merge a6c80c313c js/trace2-doc-fixes later to maint).
+
+ * Build procedure fixup.
+   (merge 1fbfd96f50 mg/detect-compiler-in-c-locale later to maint).
+
+ * "git pull" without "--recurse-submodules=<arg>" made
+   submodule.recurse take precedence over fetch.recurseSubmodules by
+   mistake, which has been corrected.
+   (merge 5819417365 gc/pull-recurse-submodules later to maint).
+
+ * "git bisect" was too silent before it is ready to start computing
+   the actual bisection, which has been corrected.
+   (merge f11046e6de cd/bisect-messages-from-pre-flight-states later to maint).
+
+ * macOS CI jobs have been occasionally flaky due to tentative version
+   skew between perforce and the homebrew packager.  Instead of
+   failing the whole CI job, just let it skip the p4 tests when this
+   happens.
+   (merge f15e00b463 cb/ci-make-p4-optional later to maint).
+
+ * A bit of test framework fixes with a few fixes to issues found by
+   valgrind.
+   (merge 7c898554d7 ab/valgrind-fixes later to maint).
+
+ * "git archive --add-file=<path>" picked up the raw permission bits
+   from the path and propagated to zip output in some cases, without
+   normalization, which has been corrected (tar output did not have
+   this issue).
+   (merge 6a61661967 jc/archive-add-file-normalize-mode later to maint).
+
+ * "make coverage-report" without first running "make coverage" did
+   not produce any meaningful result, which has been corrected.
+   (merge 96ddfecc5b ep/coverage-report-wants-test-to-have-run later to maint).
+
+ * The "--current" option of "git show-branch" should have been made
+   incompatible with the "--reflog" mode, but this was not enforced,
+   which has been corrected.
+   (merge 41c64ae0e7 jc/show-branch-g-current later to maint).
+
+ * "git fetch" unnecessarily failed when an unexpected optional
+   section appeared in the output, which has been corrected.
+   (merge 7709acf7be jt/fetch-peek-optional-section later to maint).
+
+ * The way "git fetch" without "--update-head-ok" ensures that HEAD in
+   no worktree points at any ref being updated was too wasteful, which
+   has been optimized a bit.
+   (merge f7400da800 os/fetch-check-not-current-branch later to maint).
+
+ * "git fetch --recurse-submodules" from multiple remotes (either from
+   a remote group, or "--all") used to make one extra "git fetch" in
+   the submodules, which has been corrected.
+   (merge 0353c68818 jc/avoid-redundant-submodule-fetch later to maint).
+
+ * With a recent update to refuse access to repositories of other
+   people by default, "sudo make install" and "sudo git describe"
+   stopped working, which has been corrected.
+   (merge 6b11e3d52e cb/path-owner-check-with-sudo-plus later to maint).
+
+ * The tests that ensured merges stop when interfering local changes
+   are present did not make sure that local changes are preserved; now
+   they do.
+   (merge 4b317450ce jc/t6424-failing-merge-preserve-local-changes later to maint).
+
+ * Some real problems noticed by gcc 12 have been fixed, while false
+   positives have been worked around.
+
+ * Update the version of FreeBSD image used in Cirrus CI.
+   (merge c58bebd4c6 pb/use-freebsd-12.3-in-cirrus-ci later to maint).
+
+ * The multi-pack-index code did not protect the packfile it is going
+   to depend on from getting removed while in use, which has been
+   corrected.
+   (merge 4090511e40 tb/midx-race-in-pack-objects later to maint).
+
+ * Teach "git repack --geometric" work better with "--keep-pack" and
+   avoid corrupting the repository when packsize limit is used.
+   (merge 66731ff921 tb/geom-repack-with-keep-and-max later to maint).
+
+ * The documentation on the interaction between "--add-file" and
+   "--prefix" options of "git archive" has been improved.
+   (merge a75910602a rs/document-archive-prefix later to maint).
+
+ * A git subcommand like "git add -p" spawns a separate git process
+   while relaying its command line arguments.  A pathspec with only
+   negative elements was mistakenly passed with an empty string, which
+   has been corrected.
+   (merge b02fdbc80a jc/all-negative-pathspec later to maint).
+
+ * With a more targeted workaround in http.c in another topic, we may
+   be able to lift this blanket "GCC12 dangling-pointer warning is
+   broken and unsalvageable" workaround.
+   (merge 419141e495 cb/buggy-gcc-12-workaround later to maint).
+
+ * A misconfigured 'branch..remote' led to a bug in configuration
+   parsing.
+   (merge f1dfbd9ee0 gc/zero-length-branch-config-fix later to maint).
+
+ * "git -c diff.submodule=log range-diff" did not show anything for
+   submodules that changed in the ranges being compared, and
+   "git -c diff.submodule=diff range-diff" did not work correctly.
+   Fix this by including the "--submodule=short" output
+   unconditionally to be compared.
+
+ * In Git 2.36 we revamped the way how hooks are invoked.  One change
+   that is end-user visible is that the output of a hook is no longer
+   directly connected to the standard output of "git" that spawns the
+   hook, which was noticed post release.  This is getting corrected.
+   (merge a082345372 ab/hooks-regression-fix later to maint).
+
+ * Updating the graft information invalidates the list of parents of
+   in-core commit objects that used to be in the graft file.
+
+ * "git show-ref --heads" (and "--tags") still iterated over all the
+   refs only to discard refs outside the specified area, which has
+   been corrected.
+   (merge c0c9d35e27 tb/show-ref-optim later to maint).
+
+ * Remove redundant copying (with index v3 and older) or possible
+   over-reading beyond end of mmapped memory (with index v4) has been
+   corrected.
+   (merge 6d858341d2 zh/read-cache-copy-name-entry-fix later to maint).
+
+ * Sample watchman interface hook sometimes failed to produce
+   correctly formatted JSON message, which has been corrected.
+   (merge 134047b500 sn/fsmonitor-missing-clock later to maint).
+
+ * Use-after-free (with another forget-to-free) fix.
+   (merge 323822c72b ab/remote-free-fix later to maint).
+
+ * Remove a coccinelle rule that is no longer relevant.
+   (merge b1299de4a1 jc/cocci-cleanup later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge e6b2582da3 cm/reftable-0-length-memset later to maint).
+   (merge 0b75e5bf22 ab/misc-cleanup later to maint).
+   (merge 52e1ab8a76 ea/rebase-code-simplify later to maint).
+   (merge 756d15923b sg/safe-directory-tests-and-docs later to maint).
+   (merge d097a23bfa ds/do-not-call-bug-on-bad-refs later to maint).
+   (merge c36c27e75c rs/t7812-pcre2-ws-bug-test later to maint).
+   (merge 1da312742d gf/unused-includes later to maint).
+   (merge 465b30a92d pb/submodule-recurse-mode-enum later to maint).
+   (merge 82b28c4ed8 km/t3501-use-test-helpers later to maint).
+   (merge 72315e431b sa/t1011-use-helpers later to maint).
+   (merge 95b3002201 cg/vscode-with-gdb later to maint).
+   (merge fbe5f6b804 tk/p4-utf8-bom later to maint).
+   (merge 17f273ffba tk/p4-with-explicity-sync later to maint).
+   (merge 944db25c60 kf/p4-multiple-remotes later to maint).
+   (merge b014cee8de jc/update-ozlabs-url later to maint).
+   (merge 4ec5008062 pb/ggg-in-mfc-doc later to maint).
+   (merge af845a604d tb/receive-pack-code-cleanup later to maint).
+   (merge 2acf4cf001 js/ci-gcc-12-fixes later to maint).
+   (merge 05e280c0a6 jc/http-clear-finished-pointer later to maint).
+   (merge 8c49d704ef fh/transport-push-leakfix later to maint).
+   (merge 1d232d38bd tl/ls-tree-oid-only later to maint).
+   (merge db7961e6a6 gc/document-config-worktree-scope later to maint).
+   (merge ce18a30bb7 fs/ssh-default-key-command-doc later to maint).
diff --git a/Documentation/RelNotes/2.37.1.txt b/Documentation/RelNotes/2.37.1.txt
new file mode 100644
index 0000000000..84609327d1
--- /dev/null
+++ b/Documentation/RelNotes/2.37.1.txt
@@ -0,0 +1,17 @@
+Git 2.37.1 Release Notes
+========================
+
+This release merges up the fixes that appear in v2.30.5, v2.31.4,
+v2.32.3, v2.33.4, v2.34.4, v2.35.4, and v2.36.2 to address the
+security issue CVE-2022-29187; see the release notes for these
+versions for details.
+
+Fixes since Git 2.37
+--------------------
+
+ * Rewrite of "git add -i" in C that appeared in Git 2.25 didn't
+   correctly record a removed file to the index, which is an old
+   regression but has become widely known because the C version has
+   become the default in the latest release.
+
+ * Fix for CVS-2022-29187.
diff --git a/Documentation/RelNotes/2.37.2.txt b/Documentation/RelNotes/2.37.2.txt
new file mode 100644
index 0000000000..d82b29e014
--- /dev/null
+++ b/Documentation/RelNotes/2.37.2.txt
@@ -0,0 +1,88 @@
+Git 2.37.2 Release Notes
+========================
+
+This primarily is to backport various fixes accumulated on the 'master'
+front since 2.37.1.
+
+Fixes since v2.37.1
+-------------------
+
+ * "git shortlog -n" relied on the underlying qsort() to be stable,
+   which shouldn't have.  Fixed.
+
+ * Variable quoting fix in the vimdiff driver of "git mergetool".
+
+ * An earlier attempt to plug leaks placed a clean-up label to jump to
+   at a bogus place, which as been corrected.
+
+ * Fixes a long-standing corner case bug around directory renames in
+   the merge-ort strategy.
+
+ * Recent update to vimdiff layout code has been made more robust
+   against different end-user vim settings.
+
+ * In a non-bare repository, the behavior of Git when the
+   core.worktree configuration variable points at a directory that has
+   a repository as its subdirectory, regressed in Git 2.27 days.
+
+ * References to commands-to-be-typed-literally in "git rebase"
+   documentation mark-up have been corrected.
+
+ * Give _() markings to fatal/warning/usage: labels that are shown in
+   front of these messages.
+
+ * "git mktree --missing" lazily fetched objects that are missing from
+   the local object store, which was totally unnecessary for the purpose
+   of creating the tree object(s) from its input.
+
+ * Fixes for tests when the source directory has unusual characters in
+   its path, e.g. whitespaces, double-quotes, etc.
+
+ * Adjust technical/bitmap-format to be formatted by AsciiDoc, and
+   add some missing information to the documentation.
+
+ * Certain diff options are currently ignored when combined-diff is
+   shown; mark them as incompatible with the feature.
+
+ * "git clone" from a repository with some ref whose HEAD is unborn
+   did not set the HEAD in the resulting repository correctly, which
+   has been corrected.
+
+ * mkstemp() emulation on Windows has been improved.
+
+ * Add missing documentation for "include" and "includeIf" features in
+   "git config" file format, which incidentally teaches the command
+   line completion to include them in its offerings.
+
+ * Avoid "white/black-list" in documentation and code comments.
+
+ * Workaround for a compiler warning against use of die() in
+   osx-keychain (in contrib/).
+
+ * Workaround for a false positive compiler warning.
+
+ * The resolve-undo information in the index was not protected against
+   GC, which has been corrected.
+
+ * A corner case bug where lazily fetching objects from a promisor
+   remote resulted in infinite recursion has been corrected.
+
+ * "git p4" working on UTF-16 files on Windows did not implement
+   CRLF-to-LF conversion correctly, which has been corrected.
+
+ * "git p4" did not handle non-ASCII client name well, which has been
+   corrected.
+
+ * "rerere-train" script (in contrib/) used to honor commit.gpgSign
+   while recreating the throw-away merges.
+
+ * "git checkout" miscounted the paths it updated, which has been
+   corrected.
+
+ * Fix for a bug that makes write-tree to fail to write out a
+   non-existent index as a tree, introduced in 2.37.
+
+ * There was a bug in the codepath to upgrade generation information
+   in commit-graph from v1 to v2 format, which has been corrected.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.37.3.txt b/Documentation/RelNotes/2.37.3.txt
new file mode 100644
index 0000000000..d66689e598
--- /dev/null
+++ b/Documentation/RelNotes/2.37.3.txt
@@ -0,0 +1,46 @@
+Git 2.37.3 Release Notes
+========================
+
+This primarily is to backport various fixes accumulated on the 'master'
+front since 2.37.2.
+
+Fixes since v2.37.2
+-------------------
+
+ * The build procedure for Windows that uses CMake has been updated to
+   pick up the shell interpreter from local installation location.
+
+ * Conditionally allow building Python interpreter on Windows
+
+ * Fix to lstat() emulation on Windows.
+
+ * Older gcc with -Wall complains about the universal zero initializer
+   "struct s = { 0 };" idiom, which makes developers' lives
+   inconvenient (as -Werror is enabled by DEVELOPER=YesPlease).  The
+   build procedure has been tweaked to help these compilers.
+
+ * Plug memory leaks in the failure code path in the "merge-ort" merge
+   strategy backend.
+
+ * Avoid repeatedly running getconf to ask libc version in the test
+   suite, and instead just as it once per script.
+
+ * 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.
+
+ * "vimdiff3" regression has been corrected.
+
+ * "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.
+
+ * Fixes to sparse index compatibility work for "reset" and "checkout"
+   commands.
+
+ * Documentation for "git add --renormalize" has been improved.
+
+Also contains other minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.37.4.txt b/Documentation/RelNotes/2.37.4.txt
new file mode 100644
index 0000000000..e42a5c1620
--- /dev/null
+++ b/Documentation/RelNotes/2.37.4.txt
@@ -0,0 +1,65 @@
+Git 2.37.4 Release Notes
+========================
+
+This primarily is to backport various fixes accumulated on the 'master'
+front since 2.37.3, and also includes the same security fixes as in
+v2.30.6.
+
+Fixes since v2.37.3
+-------------------
+
+ * CVE-2022-39253:
+   When relying on the `--local` clone optimization, Git dereferences
+   symbolic links in the source repository before creating hardlinks
+   (or copies) of the dereferenced link in the destination repository.
+   This can lead to surprising behavior where arbitrary files are
+   present in a repository's `$GIT_DIR` when cloning from a malicious
+   repository.
+
+   Git will no longer dereference symbolic links via the `--local`
+   clone mechanism, and will instead refuse to clone repositories that
+   have symbolic links present in the `$GIT_DIR/objects` directory.
+
+   Additionally, the value of `protocol.file.allow` is changed to be
+   "user" by default.
+
+   Credit for finding CVE-2022-39253 goes to Cory Snider of Mirantis.
+   The fix was authored by Taylor Blau, with help from Johannes
+   Schindelin.
+
+ * CVE-2022-39260:
+   An overly-long command string given to `git shell` can result in
+   overflow in `split_cmdline()`, leading to arbitrary heap writes and
+   remote code execution when `git shell` is exposed and the directory
+   `$HOME/git-shell-commands` exists.
+
+   `git shell` is taught to refuse interactive commands that are
+   longer than 4MiB in size. `split_cmdline()` is hardened to reject
+   inputs larger than 2GiB.
+
+   Credit for finding CVE-2022-39260 goes to Kevin Backhouse of
+   GitHub. The fix was authored by Kevin Backhouse, Jeff King, and
+   Taylor Blau.
+
+ * An earlier optimization discarded a tree-object buffer that is
+   still in use, which has been corrected.
+
+ * Fix deadlocks between main Git process and subprocess spawned via
+   the pipe_command() API, that can kill "git add -p" that was
+   reimplemented in C recently.
+
+ * xcalloc(), imitating calloc(), takes "number of elements of the
+   array", and "size of a single element", in this order.  A call that
+   does not follow this ordering has been corrected.
+
+ * The preload-index codepath made copies of pathspec to give to
+   multiple threads, which were left leaked.
+
+ * Update the version of Ubuntu used for GitHub Actions CI from 18.04
+   to 22.04.
+
+ * The auto-stashed local changes created by "git merge --autostash"
+   was mixed into a conflicted state left in the working tree, which
+   has been corrected.
+
+Also contains other minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.37.5.txt b/Documentation/RelNotes/2.37.5.txt
new file mode 100644
index 0000000000..faa1447292
--- /dev/null
+++ b/Documentation/RelNotes/2.37.5.txt
@@ -0,0 +1,5 @@
+Git v2.37.5 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.37.6.txt b/Documentation/RelNotes/2.37.6.txt
new file mode 100644
index 0000000000..51dc149711
--- /dev/null
+++ b/Documentation/RelNotes/2.37.6.txt
@@ -0,0 +1,7 @@
+Git v2.37.6 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8, v2.31.7,
+v2.32.6, v2.33.7, v2.34.7, v2.35.7 and v2.36.5 to address the
+security issues CVE-2023-22490 and CVE-2023-23946; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.37.7.txt b/Documentation/RelNotes/2.37.7.txt
new file mode 100644
index 0000000000..4b8165f4b5
--- /dev/null
+++ b/Documentation/RelNotes/2.37.7.txt
@@ -0,0 +1,7 @@
+Git v2.37.7 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8 and v2.36.6 to address the
+security issues CVE-2023-25652, CVE-2023-25815, and CVE-2023-29007;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.38.0.txt b/Documentation/RelNotes/2.38.0.txt
new file mode 100644
index 0000000000..870581fc57
--- /dev/null
+++ b/Documentation/RelNotes/2.38.0.txt
@@ -0,0 +1,404 @@
+Git v2.38 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "git remote show [-n] frotz" now pays attention to negative
+   pathspec.
+
+ * "git push" sometimes performs poorly when reachability bitmaps are
+   used, even in a repository where other operations are helped by
+   bitmaps.  The push.useBitmaps configuration variable is introduced
+   to allow disabling use of reachability bitmaps only for "git push".
+
+ * "git grep -m<max-hits>" is a way to limit the hits shown per file.
+
+ * "git merge-tree" learned a new mode where it takes two commits and
+   computes a tree that would result in the merge commit, if the
+   histories leading to these two commits were to be merged.
+
+ * "git mv A B" in a sparsely populated working tree can be asked to
+   move a path between directories that are "in cone" (i.e. expected
+   to be materialized in the working tree) and "out of cone"
+   (i.e. expected to be hidden).  The handling of such cases has been
+   improved.
+
+ * Earlier, HTTP transport clients learned to tell the server side
+   what locale they are in by sending Accept-Language HTTP header, but
+   this was done only for some requests but not others.
+
+ * Introduce a safe.barerepository configuration variable that
+   allows users to forbid discovery of bare repositories.
+
+ * Various messages that come from the pack-bitmap codepaths have been
+   tweaked.
+
+ * "git rebase -i" learns to update branches whose tip appear in the
+   rebased range with "--update-refs" option.
+
+ * "git ls-files" learns the "--format" option to tweak its output.
+
+ * "git cat-file" learned an option to use the mailmap when showing
+   commit and tag objects.
+
+ * When "git merge" finds that it cannot perform a merge, it should
+   restore the working tree to the state before the command was
+   initiated, but in some corner cases it didn't.
+
+ * 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".
+
+ * The "diagnose" feature to create a zip archive for diagnostic
+   material has been lifted from "scalar" and made into a feature of
+   "git bugreport".
+
+ * The namespaces used by "log --decorate" from "refs/" hierarchy by
+   default has been tightened.
+
+ * "git rev-list --ancestry-path=C A..B" is a natural extension of
+   "git rev-list A..B"; instead of choosing a subset of A..B to those
+   that have ancestry relationship with A, it lets a subset with
+   ancestry relationship with C.
+
+ * "scalar" now enables built-in fsmonitor on enlisted repositories,
+   when able.
+
+ * The bash prompt (in contrib/) learned to optionally indicate when
+   the index is unmerged.
+
+ * "git clone" command learned the "--bundle-uri" option to coordinate
+   with hosting sites the use of pre-prepared bundle files.
+
+ * "git range-diff" learned to honor pathspec argument if given.
+
+ * "git format-patch --from=<ident>" can be told to add an in-body
+   "From:" line even for commits that are authored by the given
+   <ident> with "--force-in-body-from" option.
+
+ * The built-in fsmonitor refuses to work on a network mounted
+   repositories; a configuration knob for users to override this has
+   been introduced.
+
+ * The "scalar" addition from Microsoft is now part of the core Git
+   installation.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Collection of what is referenced by objects in promisor packs have
+   been optimized to inspect these objects in the in-pack order.
+
+ * Introduce a helper to see if a branch is already being worked on
+   (hence should not be newly checked out in a working tree), which
+   performs much better than the existing find_shared_symref() to
+   replace many uses of the latter.
+
+ * Teach "git archive" to (optionally and then by default) avoid
+   spawning an external "gzip" process when creating ".tar.gz" (and
+   ".tgz") archives.
+
+ * Allow large objects read from a packstream to be streamed into a
+   loose object file straight, without having to keep it in-core as a
+   whole.
+
+ * Further preparation to turn git-submodule.sh into a builtin
+   continues.
+
+ * Apply Coccinelle rule to turn raw memmove() into MOVE_ARRAY() cpp
+   macro, which would improve maintainability and readability.
+
+ * Teach "make all" to build gitweb as well.
+
+ * Tweak tests so that they still work when the "git init" template
+   did not create .git/info directory.
+
+ * Add Coccinelle rules to detect the pattern of initializing and then
+   finalizing a structure without using it in between at all, which
+   happens after code restructuring and the compilers fail to
+   recognize as an unused variable.
+
+ * The code to convert between GPG trust level strings and internal
+   constants we use to represent them have been cleaned up.
+
+ * Support for libnettle as SHA256 implementation has been added.
+
+ * The way "git multi-pack" uses parse-options API has been improved.
+
+ * A Coccinelle rule (in contrib/) to encourage use of COPY_ARRAY
+   macro has been improved.
+
+ * API tweak to make it easier to run fuzz testing on commit-graph parser.
+
+ * Omit fsync-related trace2 entries when their values are all zero.
+
+ * The codepath to write multi-pack index has been taught to release a
+   large chunk of memory that holds an array of objects in the packs,
+   as soon as it is done with the array, to reduce memory consumption.
+
+ * Add a level of redirection to array allocation API in xdiff part,
+   to make it easier to share with the libgit2 project.
+
+ * "git fetch" client logs the partial clone filter used in the trace2
+   output.
+
+ * The "bundle URI" design gets documented.
+
+ * The common ancestor negotiation exchange during a "git fetch"
+   session now leaves trace log.
+
+ * Test portability improvements.
+   (merge 4d1d843be7 mt/rot13-in-c later to maint).
+
+ * The "subcommand" mode is introduced to parse-options API and update
+   the command line parser of Git commands with subcommands.
+
+ * The pack bitmap file gained a bitmap-lookup table to speed up
+   locating the necessary bitmap for a given commit.
+
+ * The assembly version of SHA-1 implementation for PPC has been
+   removed.
+
+ * The server side that responds to "git fetch" and "git clone"
+   request has been optimized by allowing it to send objects in its
+   object store without recomputing and validating the object names.
+
+ * Annotate function parameters that are not used (but cannot be
+   removed for structural reasons), to prepare us to later compile
+   with -Wunused warning turned on.
+
+ * Share the text used to explain configuration variables used by "git
+   <subcmd>" in "git help <subcmd>" with the text from "git help config".
+
+ * "git mv A B" in a sparsely populated working tree can be asked to
+   move a path from a directory that is "in cone" to another directory
+   that is "out of cone".  Handling of such a case has been improved.
+
+ * The chainlint script for our tests has been revamped.
+
+
+Fixes since v2.37
+-----------------
+
+ * Rewrite of "git add -i" in C that appeared in Git 2.25 didn't
+   correctly record a removed file to the index, which was fixed.
+
+ * Certain diff options are currently ignored when combined-diff is
+   shown; mark them as incompatible with the feature.
+
+ * Adjust technical/bitmap-format to be formatted by AsciiDoc, and
+   add some missing information to the documentation.
+
+ * Fixes for tests when the source directory has unusual characters in
+   its path, e.g. whitespaces, double-quotes, etc.
+
+ * "git mktree --missing" lazily fetched objects that are missing from
+   the local object store, which was totally unnecessary for the purpose
+   of creating the tree object(s) from its input.
+
+ * Give _() markings to fatal/warning/usage: labels that are shown in
+   front of these messages.
+
+ * References to commands-to-be-typed-literally in "git rebase"
+   documentation mark-up have been corrected.
+
+ * In a non-bare repository, the behavior of Git when the
+   core.worktree configuration variable points at a directory that has
+   a repository as its subdirectory, regressed in Git 2.27 days.
+
+ * Recent update to vimdiff layout code has been made more robust
+   against different end-user vim settings.
+
+ * Plug various memory leaks, both in the main code and in test-tool
+   commands.
+
+ * Fixes a long-standing corner case bug around directory renames in
+   the merge-ort strategy.
+
+ * The resolve-undo information in the index was not protected against
+   GC, which has been corrected.
+
+ * A corner case bug where lazily fetching objects from a promisor
+   remote resulted in infinite recursion has been corrected.
+
+ * "git clone" from a repository with some ref whose HEAD is unborn
+   did not set the HEAD in the resulting repository correctly, which
+   has been corrected.
+
+ * An earlier attempt to plug leaks placed a clean-up label to jump to
+   at a bogus place, which as been corrected.
+
+ * Variable quoting fix in the vimdiff driver of "git mergetool"
+
+ * "git shortlog -n" relied on the underlying qsort() to be stable,
+   which shouldn't have.  Fixed.
+
+ * A fix for a regression in test framework.
+
+ * mkstemp() emulation on Windows has been improved.
+
+ * Add missing documentation for "include" and "includeIf" features in
+   "git config" file format, which incidentally teaches the command
+   line completion to include them in its offerings.
+
+ * Avoid "white/black-list" in documentation and code comments.
+
+ * Workaround for a compiler warning against use of die() in
+   osx-keychain (in contrib/).
+
+ * Workaround for a false positive compiler warning.
+
+ * "git p4" working on UTF-16 files on Windows did not implement
+   CRLF-to-LF conversion correctly, which has been corrected.
+
+ * "git p4" did not handle non-ASCII client name well, which has been
+   corrected.
+
+ * "rerere-train" script (in contrib/) used to honor commit.gpgSign
+   while recreating the throw-away merges.
+
+ * "git checkout" miscounted the paths it updated, which has been
+   corrected.
+
+ * Fix for a bug that makes write-tree to fail to write out a
+   non-existent index as a tree, introduced in 2.37.
+
+ * There was a bug in the codepath to upgrade generation information
+   in commit-graph from v1 to v2 format, which has been corrected.
+
+ * Gitweb had legacy URL shortener that is specific to the way
+   projects hosted on kernel.org used to (but no longer) work, which
+   has been removed.
+
+ * Fix build procedure for Windows that uses CMake so that it can pick
+   up the shell interpreter from local installation location.
+
+ * Conditionally allow building Python interpreter on Windows
+
+ * Fix to lstat() emulation on Windows.
+
+ * Older gcc with -Wall complains about the universal zero initializer
+   "struct s = { 0 };" idiom, which makes developers' lives
+   inconvenient (as -Werror is enabled by DEVELOPER=YesPlease).  The
+   build procedure has been tweaked to help these compilers.
+
+ * Plug memory leaks in the failure code path in the "merge-ort" merge
+   strategy backend.
+
+ * "git symbolic-ref symref non..sen..se" is now diagnosed as an error.
+
+ * A follow-up fix to a fix for a regression in 2.36 around hooks.
+
+ * Avoid repeatedly running getconf to ask libc version in the test
+   suite, and instead just as it once per script.
+
+ * 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.
+
+ * "vimdiff3" regression fix.
+
+ * "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 existing projects with broken tree objects
+   that they cannot fix retroactively, the severity of anomalies this
+   code detects has been demoted to "info" for now.
+
+ * Fixes to sparse index compatibility work for "reset" and "checkout"
+   commands.
+
+ * An earlier optimization discarded a tree-object buffer that is
+   still in use, which has been corrected.
+
+ * Fix deadlocks between main Git process and subprocess spawned via
+   the pipe_command() API, that can kill "git add -p" that was
+   reimplemented in C recently.
+
+ * The sequencer machinery translated messages left in the reflog by
+   mistake, which has been corrected.
+
+ * xcalloc(), imitating calloc(), takes "number of elements of the
+   array", and "size of a single element", in this order.  A call that
+   does not follow this ordering has been corrected.
+
+ * The preload-index codepath made copies of pathspec to give to
+   multiple threads, which were left leaked.
+
+ * Update the version of Ubuntu used for GitHub Actions CI from 18.04
+   to 22.04.
+
+ * The auto-stashed local changes created by "git merge --autostash"
+   was mixed into a conflicted state left in the working tree, which
+   has been corrected.
+
+ * Multi-pack index got corrupted when preferred pack changed from one
+   pack to another in a certain way, which has been corrected.
+   (merge 99e4d084ff tb/midx-with-changing-preferred-pack-fix later to maint).
+
+ * The clean-up of temporary files created via mks_tempfile_dt() was
+   racy and attempted to unlink() the leading directory when signals
+   are involved, which has been corrected.
+   (merge babe2e0559 rs/tempfile-cleanup-race-fix later to maint).
+
+ * FreeBSD portability fix for "git maintenance" that spawns "crontab"
+   to schedule tasks.
+   (merge ee69e7884e bc/gc-crontab-fix later to maint).
+
+ * Those who use diff-so-fancy as the diff-filter noticed a regression
+   or two in the code that parses the diff output in the built-in
+   version of "add -p", which has been corrected.
+   (merge 0a101676e5 js/add-p-diff-parsing-fix later to maint).
+
+ * Segfault fix-up to an earlier fix to the topic to teach "git reset"
+   and "git checkout" work better in a sparse checkout.
+   (merge 037f8ea6d9 vd/sparse-reset-checkout-fixes later to maint).
+
+ * "git diff --no-index A B" managed its the pathnames of its two
+   input files rather haphazardly, sometimes leaking them.  The
+   command line argument processing has been straightened out to clean
+   it up.
+   (merge 2b43dd0eb5 rs/diff-no-index-cleanup later to maint).
+
+ * "git rev-list --verify-objects" ought to inspect the contents of
+   objects and notice corrupted ones, but it didn't when the commit
+   graph is in use, which has been corrected.
+   (merge b27ccae34b jk/rev-list-verify-objects-fix later to maint).
+
+ * More fixes to "add -p"
+   (merge 64ec8efb83 js/builtin-add-p-portability-fix later to maint).
+
+ * The parser in the script interface to parse-options in "git
+   rev-parse" has been updated to diagnose a bogus input correctly.
+   (merge f20b9c36d0 ow/rev-parse-parseopt-fix later to maint).
+
+ * The code that manages list-object-filter structure, used in partial
+   clones, leaked the instances, which has been plugged.
+   (merge 66eede4a37 jk/plug-list-object-filter-leaks later to maint).
+
+ * Fix another UI regression in the reimplemented "add -p".
+   (merge f6f0ee247f rs/add-p-worktree-mode-prompt-fix later to maint).
+
+ * "git fetch" over protocol v2 sent an incorrect ref prefix request
+   to the server and made "git pull" with configured fetch refspec
+   that does not cover the remote branch to merge with fail, which has
+   been corrected.
+   (merge 49ca2fba39 jk/proto-v2-ref-prefix-fix later to maint).
+
+ * A result from opendir() was leaking in the commit-graph expiration
+   codepath, which has been plugged.
+   (merge 12f1ae5324 ml/commit-graph-expire-dir-leak-fix later to maint).
+
+ * Just like we have coding guidelines, we now have guidelines for
+   reviewers.
+   (merge e01b851923 vd/doc-reviewing-guidelines later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 77b9e85c0f vd/fix-perf-tests later to maint).
+   (merge 0682bc43f5 jk/test-crontab-fixes later to maint).
+   (merge b46dd1726c cc/doc-trailer-whitespace-rules later to maint).
diff --git a/Documentation/RelNotes/2.38.1.txt b/Documentation/RelNotes/2.38.1.txt
new file mode 100644
index 0000000000..b2b5854aac
--- /dev/null
+++ b/Documentation/RelNotes/2.38.1.txt
@@ -0,0 +1,5 @@
+Git v2.38.1 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.6; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.38.2.txt b/Documentation/RelNotes/2.38.2.txt
new file mode 100644
index 0000000000..92acb62bbb
--- /dev/null
+++ b/Documentation/RelNotes/2.38.2.txt
@@ -0,0 +1,67 @@
+Git 2.38.2 Release Notes
+========================
+
+This is to backport various fixes accumulated during the development
+towards Git 2.39, the next feature release.
+
+
+Fixes since v2.38.1
+-------------------
+
+ * Update CodingGuidelines to clarify what features to use and avoid
+   in C99.
+
+ * The codepath that reads from the index v4 had unaligned memory
+   accesses, which has been corrected.
+
+ * "git remote rename" failed to rename a remote without fetch
+   refspec, which has been corrected.
+
+ * "git clone" did not like to see the "--bare" and the "--origin"
+   options used together without a good reason.
+
+ * Fix messages incorrectly marked for translation.
+
+ * "git fsck" failed to release contents of tree objects already used
+   from the memory, which has been fixed.
+
+ * "git rebase -i" can mistakenly attempt to apply a fixup to a commit
+   itself, which has been corrected.
+
+ * In read-only repositories, "git merge-tree" tried to come up with a
+   merge result tree object, which it failed (which is not wrong) and
+   led to a segfault (which is bad), which has been corrected.
+
+ * Force C locale while running tests around httpd to make sure we can
+   find expected error messages in the log.
+
+ * Fix a logic in "mailinfo -b" that miscomputed the length of a
+   substring, which lead to an out-of-bounds access.
+
+ * The codepath to sign learned to report errors when it fails to read
+   from "ssh-keygen".
+
+ * "GIT_EDITOR=: git branch --edit-description" resulted in failure,
+   which has been corrected.
+
+ * Documentation on various Boolean GIT_* environment variables have
+   been clarified.
+
+ * "git multi-pack-index repack/expire" used to repack unreachable
+   cruft into a new pack, which have been corrected.
+
+ * The code to clean temporary object directories (used for
+   quarantine) tried to remove them inside its signal handler, which
+   was a no-no.
+
+ * "git branch --edit-description" on an unborh branch misleadingly
+   said that no such branch exists, which has been corrected.
+
+ * GitHub CI settings have been adjusted to recent reality, merging
+   and cherry-picking necessary topics that have been prepared for Git
+   2.39.
+
+ * `git rebase --update-refs` would delete references when all `update-ref`
+   commands in the sequencer were removed, which has been corrected.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.38.3.txt b/Documentation/RelNotes/2.38.3.txt
new file mode 100644
index 0000000000..4a46bb4300
--- /dev/null
+++ b/Documentation/RelNotes/2.38.3.txt
@@ -0,0 +1,5 @@
+Git v2.38.3 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.38.4.txt b/Documentation/RelNotes/2.38.4.txt
new file mode 100644
index 0000000000..fdfde22022
--- /dev/null
+++ b/Documentation/RelNotes/2.38.4.txt
@@ -0,0 +1,7 @@
+Git v2.38.4 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8, v2.31.7,
+v2.32.6, v2.33.7, v2.34.7, v2.35.7, v2.36.5 and v2.37.6 to
+address the security issues CVE-2023-22490 and CVE-2023-23946;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.38.5.txt b/Documentation/RelNotes/2.38.5.txt
new file mode 100644
index 0000000000..2d1f3b1249
--- /dev/null
+++ b/Documentation/RelNotes/2.38.5.txt
@@ -0,0 +1,8 @@
+Git v2.38.5 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6 and v2.37.7 to address
+the security issues CVE-2023-25652, CVE-2023-25815, and
+CVE-2023-29007; see the release notes for these versions for
+details.
diff --git a/Documentation/RelNotes/2.39.0.txt b/Documentation/RelNotes/2.39.0.txt
new file mode 100644
index 0000000000..9bf00ece53
--- /dev/null
+++ b/Documentation/RelNotes/2.39.0.txt
@@ -0,0 +1,346 @@
+Git v2.39 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * "git grep" learned to expand the sparse-index more lazily and on
+   demand in a sparse checkout.
+
+ * By default, use of fsmonitor on a repository on networked
+   filesystem is disabled. Add knobs to make it workable on macOS.
+
+ * After checking out a "branch" that is a symbolic-ref that points at
+   another branch, "git symbolic-ref HEAD" reports the underlying
+   branch, not the symbolic-ref the user gave checkout as argument.
+   The command learned the "--no-recurse" option to stop after
+   dereferencing a symbolic-ref only once.
+
+ * "git branch --edit-description @{-1}" is now a way to edit branch
+   description of the branch you were on before switching to the
+   current branch.
+
+ * "git merge-tree --stdin" is a new way to request a series of merges
+   and report the merge results.
+
+ * "git shortlog" learned to group by the "format" string.
+
+ * A new "--include-whitespace" option is added to "git patch-id", and
+   existing bugs in the internal patch-id logic that did not match
+   what "git patch-id" produces have been corrected.
+
+ * Enable gc.cruftpacks by default for those who opt into
+   feature.experimental setting.
+
+ * "git repack" learns to send cruft objects out of the way into
+   packfiles outside the repository.
+
+ * 'scalar reconfigure -a' is taught to automatically remove
+   scalar.repo entires which no longer exist.
+
+ * Redact headers from cURL's h2h3 module in GIT_CURL_VERBOSE and
+   others.
+
+ * 'git maintenance register' is taught to write configuration to an
+   arbitrary path, and 'git for-each-repo' is taught to expand tilde
+   characters in paths.
+
+ * When creating new notes, the template used to get a stray empty
+   newline, which has been removed.
+
+ * "git receive-pack" used to use all the local refs as the boundary for
+   checking connectivity of the data "git push" sent, but now it uses
+   only the refs that it advertised to the pusher. In a repository with
+   the .hideRefs configuration, this reduces the resources needed to
+   perform the check.
+
+ * With '--recurse-submodules=on-demand', all submodules are
+   recursively pushed.
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * With a bit of header twiddling, use the native regexp library on
+   macOS instead of the compat/ one.
+
+ * Prepare for GNU [ef]grep that throw warning of their uses.
+
+ * Sources related to fuzz testing have been moved down to their own
+   directory.
+
+ * Most credential helpers ignored unknown entries in a credential
+   description, but a few died upon seeing them.  The latter were
+   taught to ignore them, too
+
+ * "scalar unregister" in a repository that is already been
+   unregistered reported an error.
+
+ * Remove error detection from a function that fetches from promisor
+   remotes, and make it die when such a fetch fails to bring all the
+   requested objects, to give an early failure to various operations.
+
+ * Update CodingGuidelines to clarify what features to use and avoid
+   in C99.
+
+ * Avoid false-positive from LSan whose assumption may be broken with
+   higher optimization levels.
+
+ * Enable address and undefined sanitizer tasks at GitHub Actions CI.
+
+ * More UNUSED annotation to help using -Wunused option with the
+   compiler.
+   (merge 4b992f0a24 jk/unused-anno-more later to maint).
+
+ * Rewrite a deep recursion in the skipping negotiator to use a loop
+   with on-heap prio queue to avoid stack wastage.
+
+ * Add documentation for message IDs in fsck error messages.
+
+ * Define the logical elements of a "bundle list", data structure to
+   store them in-core, format to transfer them, and code to parse
+   them.
+
+ * The role the security mailing list plays in an embargoed release
+   has been documented.
+
+ * Two new facilities, "timer" and "counter", are introduced to the
+   trace2 API.
+
+ * Code simplification by using strvec_pushf() instead of building an
+   argument in a separate strbuf.
+
+ * Make sure generated dependency file is stably sorted to help
+   developers debugging their build issues.
+
+ * The glossary entries for "commit-graph file" and "reachability
+   bitmap" have been added.
+
+ * Various tests exercising the transfer.credentialsInUrl
+   configuration are taught to avoid making requests which require
+   resolving localhost to reduce CI-flakiness.
+
+ * A redundant diagnostic message is dropped from test_path_is_missing().
+
+ * Simplify the run-command API.
+
+ * Update the actions/github-script dependency in CI to avoid a
+   deprecation warning.
+
+ * Progress on being able to initialize a rev_info struct with a
+   macro.
+
+ * Add trace2 counters to the region to clear skip worktree bits in a
+   sparse checkout.
+
+ * Modernize test script to avoid "test -f" and friends.
+
+ * Avoid calling 'cache_tree_update()' when doing so would be
+   redundant.
+
+ * Update the credential-cache documentation to provide a more
+   realistic example.
+
+ * Makefile comments updates and reordering to clarify knobs used to
+   choose SHA implementations.
+
+ * A design document for sparse-checkout's future directions has been
+   added.
+
+ * Teach chainlint.pl to annotate the original test definition instead
+   of the token stream.
+
+ * "make coccicheck" is time consuming. It has been made to run more
+   incrementally.
+
+ * `parse_object()` has been hardened to check for the existence of a
+   suspected blob object.
+
+ * The build procedure has been adjusted to GNUmake version 4.4, which
+   made some changes to how pattern rule with multiple targets are
+   handled.
+
+
+Fixes since v2.38
+-----------------
+
+ * The codepath that reads from the index v4 had unaligned memory
+   accesses, which has been corrected.
+
+ * Fix messages incorrectly marked for translation.
+
+ * "git fsck" failed to release contents of tree objects already used
+   from the memory, which has been fixed.
+
+ * "git clone" did not like to see the "--bare" and the "--origin"
+   options used together without a good reason.
+
+ * "git remote rename" failed to rename a remote without fetch
+   refspec, which has been corrected.
+
+ * Documentation on various Boolean GIT_* environment variables have
+   been clarified.
+
+ * "git rebase -i" can mistakenly attempt to apply a fixup to a commit
+   itself, which has been corrected.
+
+ * "git multi-pack-index repack/expire" used to repack unreachable
+   cruft into a new pack, which have been corrected.
+
+ * In read-only repositories, "git merge-tree" tried to come up with a
+   merge result tree object, which it failed (which is not wrong) and
+   led to a segfault (which is bad), which has been corrected.
+
+ * Force C locale while running tests around httpd to make sure we can
+   find expected error messages in the log.
+
+ * Fix a logic in "mailinfo -b" that miscomputed the length of a
+   substring, which lead to an out-of-bounds access.
+
+ * The codepath to sign learned to report errors when it fails to read
+   from "ssh-keygen".
+
+ * Code clean-up that results in plugging a leak.
+
+ * "GIT_EDITOR=: git branch --edit-description" resulted in failure,
+   which has been corrected.
+
+ * The code to clean temporary object directories (used for
+   quarantine) tried to remove them inside its signal handler, which
+   was a no-no.
+
+ * Update comment in the Makefile about the RUNTIME_PREFIX config knob.
+
+ * Clarify that "the sentence after <area>: prefix does not begin with
+   a capital letter" rule applies only to the commit title.
+
+ * "git branch --edit-description" on an unborn branch misleadingly
+   said that no such branch exists, which has been corrected.
+
+ * Work around older clang that warns against C99 zero initialization
+   syntax for struct.
+
+ * Giving "--invert-grep" and "--all-match" without "--grep" to the
+   "git log" command resulted in an attempt to access grep pattern
+   expression structure that has not been allocated, which has been
+   corrected.
+   (merge db84376f98 ab/grep-simplify-extended-expression later to maint).
+
+ * "git diff rev^!" did not show combined diff to go to the rev from
+   its parents.
+   (merge a79c6b6081 rs/diff-caret-bang-with-parents later to maint).
+
+ * Allow configuration files in "protected" scopes to include other
+   configuration files.
+   (merge ecec57b3c9 gc/bare-repo-discovery later to maint).
+
+ * Give a bit more diversity to macOS CI by using sha1dc in one of the
+   jobs (the other one tests Apple Common Crypto).
+   (merge 1ad5c3df35 jc/ci-osx-with-sha1dc later to maint).
+
+ * A bugfix with tracing support in midx codepath
+   (merge e9c3839944 tb/midx-bitmap-selection-fix later to maint).
+
+ * When geometric repacking feature is in use together with the
+   --pack-kept-objects option, we lost packs marked with .keep files.
+   (merge 197443e80a tb/save-keep-pack-during-geometric-repack later to maint).
+
+ * Move a global variable added as a hack during regression fixes to
+   its proper place in the API.
+   (merge 0b0ab95f17 ab/run-hook-api-cleanup later to maint).
+
+ * Update to build procedure with VS using CMake/CTest.
+   (merge c858750b41 js/cmake-updates later to maint).
+
+ * The short-help text shown by "git cmd -h" and the synopsis text
+   shown at the beginning of "git help cmd" have been made more
+   consistent.
+
+ * When creating a multi-pack bitmap, remove per-pack bitmap files
+   unconditionally as they will never be consulted.
+   (merge 55d902cd61 tb/remove-unused-pack-bitmap later to maint).
+
+ * Fix a longstanding syntax error in Git.pm error codepath.
+
+ * "git diff --stat" etc. were invented back when everything was ASCII
+   and strlen() was a way to measure the display width of a string;
+   adjust them to compute the display width assuming UTF-8 pathnames.
+   (merge ce8529b2bb tb/diffstat-with-utf8-strwidth later to maint).
+
+ * "git branch --edit-description" can exit with status -1 which is
+   not a good practice; it learned to use 1 as everybody else instead.
+
+ * "git apply" limits its input to a bit less than 1 GiB.
+
+ * Merging a branch with directory renames into a branch that changes
+   the directory to a symlink was mishandled by the ort merge
+   strategy, which has been corrected.
+
+ * A bugfix to "git subtree" in its split and merge features.
+
+ * Fix some bugs in the reflog messages when rebasing and changes the
+   reflog messages of "rebase --apply" to match "rebase --merge" with
+   the aim of making the reflog easier to parse.
+
+ * "git rebase --keep-base" used to discard the commits that are
+   already cherry-picked to the upstream, even when "keep-base" meant
+   that the base, on top of which the history is being rebuilt, does
+   not yet include these cherry-picked commits.  The --keep-base
+   option now implies --reapply-cherry-picks and --no-fork-point
+   options.
+
+ * The way "git repack" created temporary files when it received a
+   signal was prone to deadlocking, which has been corrected.
+
+ * Various tests exercising the transfer.credentialsInUrl
+   configuration are taught to avoid making requests which require
+   resolving localhost to reduce CI-flakiness.
+
+ * The adjust_shared_perm() helper function learned to refrain from
+   setting the "g+s" bit on directories when it is not necessary.
+
+ * "git archive" mistakenly complained twice about a missing
+   executable, which has been corrected.
+
+ * Fix a bug where `git branch -d` did not work on an orphaned HEAD.
+
+ * `git rebase --update-refs` would delete references when all
+   `update-ref` commands in the sequencer were removed, which has been
+   corrected.
+
+ * Fix a regression in the bisect-helper which mistakenly treats
+   arguments to the command given to 'git bisect run' as arguments to
+   the helper.
+
+ * Correct an error where `git rebase` would mistakenly use a branch or
+   tag named "refs/rewritten/xyz" when missing a rebase label.
+
+ * Assorted fixes of parsing end-user input as integers.
+   (merge 14770cf0de pw/config-int-parse-fixes later to maint).
+
+ * "git prune" may try to iterate over .git/objects/pack for trash
+   files to remove in it, and loudly fail when the directory is
+   missing, which is not necessary.  The command has been taught to
+   ignore such a failure.
+   (merge 6974765352 ew/prune-with-missing-objects-pack later to maint).
+
+ * Add one more candidate directory that may house httpd modules while
+   running tests.
+   (merge 1c7dc23d41 es/locate-httpd-module-location-in-test later to maint).
+
+ * A handful of leaks in the line-log machinery have been plugged.
+
+ * The format of a line in /proc/cpuinfo that describes a CPU on s390x
+   looked different from everybody else, and the code in chainlint.pl
+   failed to parse it.
+   (merge 1f51b77f4f ah/chainlint-cpuinfo-parse-fix later to maint).
+
+ * Adjust the GitHub CI to newer ubuntu release.
+   (merge 0d3507f3e7 jx/ci-ubuntu-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 413bc6d20a ds/cmd-main-reorder later to maint).
+   (merge 8d2863e4ed nw/t1002-cleanup later to maint).
+   (merge 7c2dc122f9 rs/list-objects-filter-leakfix later to maint).
+   (merge 288fcb1c94 zk/push-use-bitmaps later to maint).
+   (merge 42db324c0f km/merge-recursive-typofix later to maint).
diff --git a/Documentation/RelNotes/2.39.1.txt b/Documentation/RelNotes/2.39.1.txt
new file mode 100644
index 0000000000..60c86f4122
--- /dev/null
+++ b/Documentation/RelNotes/2.39.1.txt
@@ -0,0 +1,5 @@
+Git v2.39.1 Release Notes
+=========================
+
+This release merges the security fix that appears in v2.30.7; see
+the release notes for that version for details.
diff --git a/Documentation/RelNotes/2.39.2.txt b/Documentation/RelNotes/2.39.2.txt
new file mode 100644
index 0000000000..ebb9900bc5
--- /dev/null
+++ b/Documentation/RelNotes/2.39.2.txt
@@ -0,0 +1,7 @@
+Git v2.39.2 Release Notes
+=========================
+
+This release merges up the fixes that appear in v2.30.8, v2.31.7,
+v2.32.6, v2.33.7, v2.34.7, v2.35.7, v2.36.5, v2.37.6 and v2.38.4
+to address the security issues CVE-2023-22490 and CVE-2023-23946;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.39.3.txt b/Documentation/RelNotes/2.39.3.txt
new file mode 100644
index 0000000000..66351b65c2
--- /dev/null
+++ b/Documentation/RelNotes/2.39.3.txt
@@ -0,0 +1,64 @@
+Git v2.39.3 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7 and v2.38.5 to
+address the security issues CVE-2023-25652, CVE-2023-25815, and
+CVE-2023-29007; see the release notes for these versions for
+details.
+
+This release also merges fixes that have accumulated on the 'master'
+front to prepare for the 2.40 release that are still relevant to
+2.39.x maintenance track.
+
+Fixes since v2.39.2
+-------------------
+
+ * Stop running win+VS build by default.
+
+ * CI updates.  We probably want a clean-up to move the long shell
+   script embedded in yaml file into a separate file, but that can
+   come later.
+
+ * Avoid unnecessary builds in CI, with settings configured in
+   ci-config.
+
+ * Redefining system functions for a few functions did not follow our
+   usual "implement git_foo() and #define foo(args) git_foo(args)"
+   pattern, which has broken build for some folks.
+
+ * Deal with a few deprecation warning from cURL library.
+
+ * Newer regex library macOS stopped enabling GNU-like enhanced BRE,
+   where '\(A\|B\)' works as alternation, unless explicitly asked with
+   the REG_ENHANCED flag.  "git grep" now can be compiled to do so, to
+   retain the old behaviour.
+
+ * When given a pattern that matches an empty string at the end of a
+   line, the code to parse the "git diff" line-ranges fell into an
+   infinite loop, which has been corrected.
+
+ * Fix the sequence to fsync $GIT_DIR/packed-refs file that forgot to
+   flush its output to the disk..
+
+ * "git diff --relative" did not mix well with "git diff --ext-diff",
+   which has been corrected.
+
+ * The logic to see if we are using the "cone" mode by checking the
+   sparsity patterns has been tightened to avoid mistaking a pattern
+   that names a single file as specifying a cone.
+
+ * Doc update for environment variables set when hooks are invoked.
+
+ * Document ORIG_HEAD a bit more.
+
+ * "git ls-tree --format='%(path) %(path)' $tree $path" showed the
+   path three times, which has been corrected.
+
+ * Document that "branch -f <branch>" disables only the safety to
+   avoid recreating an existing branch.
+
+ * Clarify how "checkout -b/-B" and "git branch [-f]" are similar but
+   different in the documentation.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.39.4.txt b/Documentation/RelNotes/2.39.4.txt
new file mode 100644
index 0000000000..7f54521fea
--- /dev/null
+++ b/Documentation/RelNotes/2.39.4.txt
@@ -0,0 +1,79 @@
+Git v2.39.4 Release Notes
+=========================
+
+This addresses the security issues CVE-2024-32002, CVE-2024-32004,
+CVE-2024-32020 and CVE-2024-32021.
+
+This release also backports fixes necessary to let the CI builds pass
+successfully.
+
+Fixes since v2.39.3
+-------------------
+
+ * CVE-2024-32002:
+
+   Recursive clones on case-insensitive filesystems that support symbolic
+   links are susceptible to case confusion that can be exploited to
+   execute just-cloned code during the clone operation.
+
+ * CVE-2024-32004:
+
+   Repositories can be configured to execute arbitrary code during local
+   clones. To address this, the ownership checks introduced in v2.30.3
+   are now extended to cover cloning local repositories.
+
+ * CVE-2024-32020:
+
+   Local clones may end up hardlinking files into the target repository's
+   object database when source and target repository reside on the same
+   disk. If the source repository is owned by a different user, then
+   those hardlinked files may be rewritten at any point in time by the
+   untrusted user.
+
+ * CVE-2024-32021:
+
+   When cloning a local source repository that contains symlinks via the
+   filesystem, Git may create hardlinks to arbitrary user-readable files
+   on the same filesystem as the target repository in the objects/
+   directory.
+
+ * CVE-2024-32465:
+
+   It is supposed to be safe to clone untrusted repositories, even those
+   unpacked from zip archives or tarballs originating from untrusted
+   sources, but Git can be tricked to run arbitrary code as part of the
+   clone.
+
+ * Defense-in-depth: submodule: require the submodule path to contain
+   directories only.
+
+ * Defense-in-depth: clone: when symbolic links collide with directories, keep
+   the latter.
+
+ * Defense-in-depth: clone: prevent hooks from running during a clone.
+
+ * Defense-in-depth: core.hooksPath: add some protection while cloning.
+
+ * Defense-in-depth: fsck: warn about symlink pointing inside a gitdir.
+
+ * Various fix-ups on HTTP tests.
+
+ * Test update.
+
+ * HTTP Header redaction code has been adjusted for a newer version of
+   cURL library that shows its traces differently from earlier
+   versions.
+
+ * Fix was added to work around a regression in libcURL 8.7.0 (which has
+   already been fixed in their tip of the tree).
+
+ * Replace macos-12 used at GitHub CI with macos-13.
+
+ * ci(linux-asan/linux-ubsan): let's save some time
+
+ * Tests with LSan from time to time seem to emit harmless message that makes
+   our tests unnecessarily flakey; we work it around by filtering the
+   uninteresting output.
+
+ * Update GitHub Actions jobs to avoid warnings against using deprecated
+   version of Node.js.
diff --git a/Documentation/RelNotes/2.39.5.txt b/Documentation/RelNotes/2.39.5.txt
new file mode 100644
index 0000000000..97c0185de4
--- /dev/null
+++ b/Documentation/RelNotes/2.39.5.txt
@@ -0,0 +1,26 @@
+Git v2.39.5 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.'  This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.39.4 and were not
+direct security fixes.
+
+Jeff King (5):
+      send-email: drop FakeTerm hack
+      send-email: avoid creating more than one Term::ReadLine object
+      ci: drop mention of BREW_INSTALL_PACKAGES variable
+      ci: avoid bare "gcc" for osx-gcc job
+      ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+      hook: plug a new memory leak
+      init: use the correct path of the templates directory again
+      Revert "core.hooksPath: add some protection while cloning"
+      tests: verify that `clone -c core.hooksPath=/dev/null` works again
+      clone: drop the protections where hooks aren't run
+      Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+      Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.4.0.txt b/Documentation/RelNotes/2.4.0.txt
new file mode 100644
index 0000000000..cde64be535
--- /dev/null
+++ b/Documentation/RelNotes/2.4.0.txt
@@ -0,0 +1,514 @@
+Git 2.4 Release Notes
+=====================
+
+Backward compatibility warning(s)
+---------------------------------
+
+This release has a few changes in the user-visible output from
+Porcelain commands. These are not meant to be parsed by scripts, but
+users still may want to be aware of the changes:
+
+ * The output from "git log --decorate" (and, more generally, the "%d"
+   format specifier used in the "--format=<string>" parameter to the
+   "git log" family of commands) has changed. It used to list "HEAD"
+   just like other branches; e.g.,
+
+     $ git log --decorate -1 master
+     commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD, master)
+     ...
+
+   This release changes the output slightly when HEAD refers to a
+   branch whose name is also shown in the output. The above is now
+   shown as:
+
+     $ git log --decorate -1 master
+     commit bdb0f6788fa5e3cacc4315e9ff318a27b2676ff4 (HEAD -> master)
+     ...
+
+ * The phrasing "git branch" uses to describe a detached HEAD has been
+   updated to agree with the phrasing used by "git status":
+
+    - When HEAD is at the same commit as when it was originally
+      detached, they now both show "detached at <commit object name>".
+
+    - When HEAD has moved since it was originally detached, they now
+      both show "detached from <commit object name>".
+
+   Previously, "git branch" always used "from".
+
+
+Updates since v2.3
+------------------
+
+Ports
+
+ * Our default I/O size (8 MiB) for large files was too large for some
+   platforms with smaller SSIZE_MAX, leading to read(2)/write(2)
+   failures.
+
+ * We did not check the curl library version before using the
+   CURLOPT_PROXYAUTH feature, which did not exist in older versions of
+   the library.
+
+ * We now detect number of CPUs on older BSD-derived systems.
+
+ * Portability fixes and workarounds for shell scripts have been added
+   to help BSD-derived systems.
+
+
+UI, Workflows & Features
+
+ * The command usage info strings given by "git cmd -h" and in
+   documentation have been tweaked for consistency.
+
+ * The "sync" subcommand of "git p4" now allows users to exclude
+   subdirectories like its "clone" subcommand does.
+
+ * "git log --invert-grep --grep=WIP" will show only commits that do
+   not have the string "WIP" in their messages.
+
+ * "git push" has been taught an "--atomic" option that makes a push
+   that updates more than one ref an "all-or-none" affair.
+
+ * Extending the "push to deploy" feature that was added in 2.3, the
+   behaviour of "git push" when updating the branch that is checked
+   out can now be tweaked by a "push-to-checkout" hook.
+
+ * HTTP-based transports now send Accept-Language when making
+   requests. The languages to accept are inferred from environment
+   variables on the client side (LANGUAGE, etc).
+
+ * "git send-email" used to accept a mistaken "y" (or "yes") as an
+   answer to "What encoding do you want to use [UTF-8]?" without
+   questioning. Now it asks for confirmation when the answer looks too
+   short to be a valid encoding name.
+
+ * When "git apply --whitespace=fix" fixed whitespace errors in the
+   common context lines, the command reports that it did so.
+
+ * "git status" now allows the "-v" option to be given twice, in which
+   case it also shows the differences in the working tree that are not
+   staged to be committed.
+
+ * "git cherry-pick" used to clean up the log message even when it is
+   merely replaying an existing commit. It now replays the message
+   verbatim unless you are editing the message of the resulting
+   commit.
+
+ * "git archive" can now be told to set the 'text' attribute in the
+   resulting zip archive.
+
+ * Output from "git log --decorate" now distinguishes between a
+   detached HEAD vs. a HEAD that points at a branch.
+
+   This is a potentially backward-incompatible change; see above for
+   more information.
+
+ * When HEAD was detached when at commit xyz and hasn't been moved
+   since it was detached, "git status" would report "detached at xyz"
+   whereas "git branch" would report "detached from xyz". Now the
+   output of "git branch" agrees with that of "git status".
+
+   This is a potentially backward-incompatible change; see above for
+   more information.
+
+ * "git -C '' subcmd" now works in the current directory (analogously
+   to "cd ''") rather than dying with an error message.
+   (merge 6a536e2 kn/git-cd-to-empty later to maint).
+
+ * The versionsort.prereleaseSuffix configuration variable can be used
+   to specify that, for example, v1.0-pre1 comes before v1.0.
+
+ * A new "push.followTags" configuration turns the "--follow-tags"
+   option on by default for the "git push" command.
+
+ * "git log --graph --no-walk A B..." is a nonsensical combination of
+   options: "--no-walk" requests discrete points in the history, while
+   "--graph" asks to draw connections between these discrete points.
+   Forbid the use of these options together.
+
+ * "git rev-list --bisect --first-parent" does not work (yet) and can
+   even cause SEGV; forbid it. "git log --bisect --first-parent" would
+   not be useful until "git bisect --first-parent" materializes, so
+   also forbid it for now.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Slightly change the implementation of the N_() macro to help us
+   detect mistakes.
+
+ * Restructure the implementation of "reflog expire" to fit better
+   with the recently updated reference API.
+
+ * The transport-helper did not pass transport options such as
+   verbosity, progress, cloning, etc. to import and export based
+   helpers, like it did for fetch and push based helpers, robbing them
+   of the chance to honor the wish of the end-users better.
+
+ * The tests that wanted to see that a file becomes unreadable after
+   running "chmod a-r file", and the tests that wanted to make sure
+   that they are not run as root, used "can we write into the /
+   directory?" as a cheap substitute. But on some platforms that is
+   not a good heuristic. The tests and their prerequisites have been
+   updated to check what they really require.
+   (merge f400e51 jk/sanity later to maint).
+
+ * Various issues around "reflog expire", e.g. using --updateref when
+   expiring a reflog for a symbolic reference, have been corrected
+   and/or made saner.
+
+ * The documentation for the strbuf API had been split between the API
+   documentation and the header file. Consolidate the documentation in
+   strbuf.h.
+
+ * The error handling functions and conventions are now documented in
+   the API manual (in api-error-handling.txt).
+
+ * Optimize gitattribute look-up, mostly useful in "git grep" on a
+   project that does not use many attributes, by avoiding it when we
+   (should) know that the attributes are not defined in the first
+   place.
+
+ * Typofix in comments.
+   (merge ef2956a ak/git-pm-typofix later to maint).
+
+ * Code clean-up.
+   (merge 0b868f0 sb/hex-object-name-is-at-most-41-bytes-long later to maint).
+   (merge 5d30851 dp/remove-duplicated-header-inclusion later to maint).
+
+ * Simplify the ref transaction API for verifying that "the ref should
+   be pointing at this object".
+
+ * Simplify the code in "git daemon" that parses out and holds
+   hostnames used in request interpolation.
+
+ * Restructure the "git push" codepath to make it easier to add new
+   configuration bits.
+
+ * The run-command interface made it easy to make a pipe for us to
+   read from a process, wait for the process to finish, and then
+   attempt to read its output. But this pattern can lead to deadlock.
+   So introduce a helper to do this correctly (i.e., first read, and
+   then wait the process to finish) and also add code to prevent such
+   abuse in the run-command helper.
+
+ * People often forget to chain the commands in their test together
+   with &&, letting a failure from an earlier command in the test go
+   unnoticed. The new GIT_TEST_CHAIN_LINT mechanism allows you to
+   catch such a mistake more easily.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.3
+----------------
+
+Unless otherwise noted, all the fixes since v2.3 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git blame HEAD -- missing" failed to correctly say "HEAD" when it
+   tried to say "No such path 'missing' in HEAD".
+   (merge a46442f jk/blame-commit-label later to maint).
+
+ * "git rerere" (invoked internally from many mergy operations) did
+   not correctly signal errors when it attempted to update the working
+   tree files but failed for whatever reason.
+   (merge 89ea903 jn/rerere-fail-on-auto-update-failure later to maint).
+
+ * Setting diff.submodule to 'log' made "git format-patch" produce
+   broken patches.
+   (merge 339de50 dk/format-patch-ignore-diff-submodule later to maint).
+
+ * After attempting and failing a password-less authentication (e.g.,
+   Kerberos), libcURL refuses to fall back to password-based Basic
+   authentication without a bit of help/encouragement.
+   (merge 4dbe664 bc/http-fallback-to-password-after-krb-fails later to maint).
+
+ * The "git push" documentation for the "--repo=<there>" option was
+   easily misunderstood.
+   (merge 57b92a7 mg/push-repo-option-doc later to maint).
+
+ * Code to read a branch name from various files in the .git/
+   directory would have overrun array limits if asked to read an empty
+   file.
+   (merge 66ec904 jk/status-read-branch-name-fix later to maint).
+
+ * Remove a superfluous conditional that is always true.
+   (merge 94ee8e2 jk/remote-curl-an-array-in-struct-cannot-be-null later to maint).
+
+ * The "git diff --raw" documentation incorrectly implied that C(opy)
+   and R(ename) are the only statuses that can be followed by a score
+   number.
+   (merge ac1c2d9 jc/diff-format-doc later to maint).
+
+ * A broken pack .idx file in the receiving repository prevented the
+   dumb http transport from fetching a good copy of it from the other
+   side.
+   (merge 8b9c2dd jk/dumb-http-idx-fetch-fix later to maint).
+
+ * The error message from "git commit", when a non-existing author
+   name was given as value to the "--author=" parameter, has been
+   reworded to avoid misunderstanding.
+   (merge 1044b1f mg/commit-author-no-match-malformed-message later to maint).
+
+ * "git log --help" used to show rev-list options that are irrelevant
+   to the "log" command.
+   (merge 3cab02d jc/doc-log-rev-list-options later to maint).
+
+ * "git apply --whitespace=fix" used to under-allocate memory when the
+   fix resulted in a longer text than the original patch.
+   (merge 407a792 jc/apply-ws-fix-expands later to maint).
+
+ * The interactive "show a list and let the user choose from it"
+   interface used by "git add -i" unnecessarily prompted the user even
+   when the candidate list was empty, against which the only "choice"
+   the user could have made was to choose nothing.
+   (merge a9c4641 ak/add-i-empty-candidates later to maint).
+
+ * The todo list created by "git rebase -i" did not fully honor
+   core.abbrev settings.
+   (merge edb72d5 ks/rebase-i-abbrev later to maint).
+
+ * "git fetch" over a remote-helper that cannot respond to the "list"
+   command could not fetch from a symbolic reference (e.g., HEAD).
+   (merge 33cae54 mh/deref-symref-over-helper-transport later to maint).
+
+ * "git push --signed" gave an incorrectly worded error message when
+   the other side did not support the capability.
+
+ * The "git push --signed" protocol extension did not limit what the
+   "nonce" (a server-chosen string) could contain nor how long it
+   could be, which was unnecessarily lax. Limit both the length and
+   the alphabet to a reasonably small space that can still have enough
+   entropy.
+   (merge afcb6ee jc/push-cert later to maint).
+
+ * The completion script (in contrib/) clobbered the shell variable $x
+   in the global shell namespace.
+   (merge 852ff1c ma/bash-completion-leaking-x later to maint).
+
+ * We incorrectly formatted a "uintmax_t" integer that doesn't fit in
+   "int".
+   (merge d306f3d jk/decimal-width-for-uintmax later to maint).
+
+ * The configuration parser used to be confused when reading
+   configuration from a blob object that ends with a lone CR.
+   (merge 1d0655c jk/config-no-ungetc-eof later to maint).
+
+ * The pack bitmap support did not build with older versions of GCC.
+   (merge bd4e882 jk/pack-bitmap later to maint).
+
+ * The documentation wasn't clear that "remote.<nick>.pushURL" and
+   "remote.<nick>.URL" are there to name the same repository accessed
+   via different transports, not two separate repositories.
+   (merge 697f652 jc/remote-set-url-doc later to maint).
+
+ * Older GnuPG implementations may not correctly import the keyring
+   material we prepare for the tests to use.
+   (merge 1f985d6 ch/new-gpg-drops-rfc-1991 later to maint).
+
+ * The credential helper for Windows (in contrib/) used to mishandle
+   user names that contain an at-sign.
+   (merge 13d261e av/wincred-with-at-in-username-fix later to maint).
+
+ * "diff-highlight" (in contrib/) used to show byte-by-byte
+   differences, which could cause multi-byte characters to be chopped
+   in the middle. It learned to pay attention to character boundaries
+   (assuming UTF-8).
+   (merge 8d00662 jk/colors later to maint).
+
+ * Document longstanding configuration variable naming rules in
+   CodingGuidelines.
+   (merge 35840a3 jc/conf-var-doc later to maint).
+
+ * An earlier workaround to squelch unhelpful deprecation warnings
+   from the compiler on OS X unnecessarily set a minimum required
+   version of the OS, which the user might want to raise (or lower)
+   for other reasons.
+   (merge 88c03eb es/squelch-openssl-warnings-on-macosx later to maint).
+
+ * Certain older vintages of cURL give irregular output from
+   "curl-config --vernum", which confused our build system.
+   (merge 3af6792 tc/curl-vernum-output-broken-in-7.11 later to maint).
+
+ * In v2.2.0, we broke "git prune" that runs in a repository that
+   borrows from an alternate object store.
+   (merge b0a4264 jk/prune-mtime later to maint).
+
+ * "git submodule add" failed to squash "path/to/././submodule" to
+   "path/to/submodule".
+   (merge 8196e72 ps/submodule-sanitize-path-upon-add later to maint).
+
+ * "git merge-file" did not work correctly when invoked in a
+   subdirectory.
+   (merge 204a8ff ab/merge-file-prefix later to maint).
+
+ * "git blame" could die trying to free an uninitialized piece of
+   memory.
+   (merge e600592 es/blame-commit-info-fix later to maint).
+
+ * "git fast-import" used to crash when it could not close and
+   finalize the resulting packfile cleanly.
+   (merge 5e915f3 jk/fast-import-die-nicely-fix later to maint).
+
+ * "update-index --refresh" used to leak memory when an entry could
+   not be refreshed for whatever reason.
+   (merge bc1c2ca sb/plug-leak-in-make-cache-entry later to maint).
+
+ * The "interpolated-path" option of "git daemon" inserted any string
+   the client declared on the "host=" capability request without
+   checking. Sanitize and limit %H and %CH to a saner and a valid DNS
+   name.
+   (merge b485373 jk/daemon-interpolate later to maint).
+
+ * "git daemon" unnecessarily looked up the hostname even when "%CH"
+   and "%IP" interpolations were not requested.
+   (merge dc8edc8 rs/daemon-interpolate later to maint).
+
+ * We relied on "--no-" prefix handling in Perl's Getopt::Long
+   package, even though that support didn't exist in Perl 5.8 (which
+   we still support). Manually add support to help people with older
+   Getopt::Long packages.
+   (merge f471494 km/send-email-getopt-long-workarounds later to maint).
+
+ * "git apply" was not very careful about reading from, removing,
+   updating and creating paths outside the working tree (under
+   --index/--cached) or the current directory (when used as a
+   replacement for GNU patch).
+   (merge e0d201b jc/apply-beyond-symlink later to maint).
+
+ * Correct a breakage in git-svn, introduced around the v2.2 era, that
+   can cause FileHandles to be closed prematurely.
+   (merge e426311 ew/svn-maint-fixes later to maint).
+
+ * We did not parse usernames followed by literal IPv6 addresses
+   correctly in SSH transport URLs; e.g.,
+   ssh://user@[2001:db8::1]:22/repo.git.
+   (merge 6b6c5f7 tb/connect-ipv6-parse-fix later to maint).
+
+ * The configuration variable 'mailinfo.scissors' was hard to
+   discover in the documentation.
+   (merge afb5de7 mm/am-c-doc later to maint).
+
+ * The interaction between "git submodule update" and the
+   submodule.*.update configuration was not clearly documented.
+   (merge 5c31acf ms/submodule-update-config-doc later to maint).
+
+ * "git diff --shortstat" used together with "--dirstat=changes" or
+   "--dirstat=files" incorrectly output dirstat information twice.
+   (merge ab27389 mk/diff-shortstat-dirstat-fix later to maint).
+
+ * The manpage for "git remote add" mentioned "--tags" and "--no-tags"
+   but did not explain what happens if neither option is provided.
+   (merge aaba0ab mg/doc-remote-tags-or-not later to maint).
+
+ * The description of "--exclude-standard option" in the output of
+   "git grep -h" was phrased poorly.
+   (merge 77fdb8a nd/grep-exclude-standard-help-fix later to maint).
+
+ * "git rebase -i" recently started to include the number of commits
+   in the todo list, but that output included extraneous whitespace on
+   a platform that prepends leading whitespaces to its "wc -l" output.
+   (merge 2185d3b es/rebase-i-count-todo later to maint).
+
+ * The borrowed code in the kwset API did not follow our usual
+   convention to use "unsigned char" to store values that range from
+   0-255.
+   (merge 189c860 bw/kwset-use-unsigned later to maint).
+
+ * A corrupt input to "git diff -M" used to cause it to segfault.
+   (merge 4d6be03 jk/diffcore-rename-duplicate later to maint).
+
+ * Certain builds of GPG triggered false breakages in a test.
+   (merge 3f88c1b mg/verify-commit later to maint).
+
+ * "git imap-send" learned to optionally talk with an IMAP server via
+   libcURL. Because there is no other option when Git is built with
+   the NO_OPENSSL option, use libcURL by default in that case.
+   (merge dcd01ea km/imap-send-libcurl-options later to maint).
+
+ * "git log --decorate" did not reset colors correctly around the
+   branch names.
+   (merge 5ee8758 jc/decorate-leaky-separator-color later to maint).
+
+ * The code that reads from the ctags file in the completion script
+   (in contrib/) did not spell ${param/pattern/string} substitution
+   correctly, which happened to work with bash but not with zsh.
+   (merge db8d750 js/completion-ctags-pattern-substitution-fix later to maint).
+
+ * The transfer.hiderefs support did not quite work for smart-http
+   transport.
+   (merge 8ddf3ca jk/smart-http-hide-refs later to maint).
+
+ * In the "git tag -h" output, move the documentation for the
+   "--column" and "--sort" options to the "Tag listing options"
+   section.
+   (merge dd059c6 jk/tag-h-column-is-a-listing-option later to maint).
+
+ * "git prune" used to largely ignore broken refs when deciding which
+   objects are still being used, which could cause reference
+   corruption to lead to object loss.
+   (merge ea56c4e jk/prune-with-corrupt-refs later to maint).
+
+ * The split-index mode introduced in v2.3.0-rc0~41 was broken in the
+   codepath to protect us against a broken reimplementation of Git
+   that writes an invalid index with duplicated index entries, etc.
+   (merge 03f15a7 tg/fix-check-order-with-split-index later to maint).
+
+ * "git fetch", when fetching a commit using the
+   allow-tip-sha1-in-want extension, could have failed to fetch all of
+   the requested refs.
+   (merge 32d0462 jk/fetch-pack later to maint).
+
+ * An failure early in the "git clone" that started creating the
+   working tree and repository could have resulted in the failure to
+   clean up some directories and files.
+   (merge 16eff6c jk/cleanup-failed-clone later to maint).
+
+ * Recommend format-patch and send-email for those who want to submit
+   patches to this project.
+   (merge b25c469 jc/submitting-patches-mention-send-email later to maint).
+
+ * Do not spawn the pager when "git grep" is run with "--quiet".
+   (merge c2048f0 ws/grep-quiet-no-pager later to maint).
+
+ * The prompt script (in contrib/) did not show the untracked sign
+   when working in a subdirectory without any untracked files.
+   (merge 9bdc517 ct/prompt-untracked-fix later to maint).
+
+ * An earlier update to the URL parser broke an address that contains
+   a colon but an empty string for the port number, like
+   ssh://example.com:/path/to/repo.
+   (merge 6b6c5f7 tb/connect-ipv6-parse-fix later to maint).
+
+ * Code cleanups and documentation updates.
+   (merge 2ce63e9 rs/simple-cleanups later to maint).
+   (merge 33baa69 rj/no-xopen-source-for-cygwin later to maint).
+   (merge 817d03e jc/diff-test-updates later to maint).
+   (merge eb32c66 ak/t5516-typofix later to maint).
+   (merge bcd57cb mr/doc-clean-f-f later to maint).
+   (merge 0d6accc mg/doc-status-color-slot later to maint).
+   (merge 53e53c7 sg/completion-remote later to maint).
+   (merge 8fa7975 ak/git-done-help-cleanup later to maint).
+   (merge 9a6f128 rs/deflate-init-cleanup later to maint).
+   (merge 6f75d45 rs/use-isxdigit later to maint).
+   (merge 376e4b3 jk/test-annoyances later to maint).
+   (merge 7032054 nd/doc-git-index-version later to maint).
+   (merge e869c5e tg/test-index-v4 later to maint).
+   (merge 599d223 jk/simplify-csum-file-sha1fd-check later to maint).
+   (merge 260d585 sg/completion-gitcomp-nl-for-refs later to maint).
+   (merge 777c55a jc/report-path-error-to-dir later to maint).
+   (merge fddfaf8 ph/push-doc-cas later to maint).
+   (merge d50d31e ss/pull-rebase-preserve later to maint).
+   (merge c8c3f1d pt/enter-repo-comment-fix later to maint).
+   (merge d7bfb9e jz/gitweb-conf-doc-fix later to maint).
+   (merge f907282 jk/cherry-pick-docfix later to maint).
+   (merge d3c0811 iu/fix-parse-options-h-comment later to maint).
+   (merge 6c3b2af jg/cguide-we-cannot-count later to maint).
+   (merge 2b8bd44 jk/pack-corruption-post-mortem later to maint).
+   (merge 9585cb8 jn/doc-fast-import-no-16-octopus-limit later to maint).
+   (merge 5dcd1b1 ps/grep-help-all-callback-arg later to maint).
+   (merge f1f4c84 va/fix-git-p4-tests later to maint).
diff --git a/Documentation/RelNotes/2.4.1.txt b/Documentation/RelNotes/2.4.1.txt
new file mode 100644
index 0000000000..a65a6c5829
--- /dev/null
+++ b/Documentation/RelNotes/2.4.1.txt
@@ -0,0 +1,40 @@
+Git v2.4.1 Release Notes
+========================
+
+Fixes since v2.4
+----------------
+
+ * The usual "git diff" when seeing a file turning into a directory
+   showed a patchset to remove the file and create all files in the
+   directory, but "git diff --no-index" simply refused to work.  Also,
+   when asked to compare a file and a directory, imitate POSIX "diff"
+   and compare the file with the file with the same name in the
+   directory, instead of refusing to run.
+
+ * The default $HOME/.gitconfig file created upon "git config --global"
+   that edits it had incorrectly spelled user.name and user.email
+   entries in it.
+
+ * "git commit --date=now" or anything that relies on approxidate lost
+   the daylight-saving-time offset.
+
+ * "git cat-file bl $blob" failed to barf even though there is no
+   object type that is "bl".
+
+ * Teach the codepaths that read .gitignore and .gitattributes files
+   that these files encoded in UTF-8 may have UTF-8 BOM marker at the
+   beginning; this makes it in line with what we do for configuration
+   files already.
+
+ * Access to objects in repositories that borrow from another one on a
+   slow NFS server unnecessarily got more expensive due to recent code
+   becoming more cautious in a naive way not to lose objects to pruning.
+
+ * We avoid setting core.worktree when the repository location is the
+   ".git" directory directly at the top level of the working tree, but
+   the code misdetected the case in which the working tree is at the
+   root level of the filesystem (which arguably is a silly thing to
+   do, but still valid).
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.10.txt b/Documentation/RelNotes/2.4.10.txt
new file mode 100644
index 0000000000..702d8d4e22
--- /dev/null
+++ b/Documentation/RelNotes/2.4.10.txt
@@ -0,0 +1,18 @@
+Git v2.4.10 Release Notes
+=========================
+
+Fixes since v2.4.9
+------------------
+
+ * xdiff code we use to generate diffs is not prepared to handle
+   extremely large files.  It uses "int" in many places, which can
+   overflow if we have a very large number of lines or even bytes in
+   our input files, for example.  Cap the input size to somewhere
+   around 1GB for now.
+
+ * Some protocols (like git-remote-ext) can execute arbitrary code
+   found in the URL.  The URLs that submodules use may come from
+   arbitrary sources (e.g., .gitmodules files in a remote
+   repository), and can hurt those who blindly enable recursive
+   fetch.  Restrict the allowed protocols to well known and safe
+   ones.
diff --git a/Documentation/RelNotes/2.4.11.txt b/Documentation/RelNotes/2.4.11.txt
new file mode 100644
index 0000000000..723360295c
--- /dev/null
+++ b/Documentation/RelNotes/2.4.11.txt
@@ -0,0 +1,11 @@
+Git v2.4.11 Release Notes
+=========================
+
+Fixes since v2.4.10
+-------------------
+
+ * Bugfix patches were backported from the 'master' front to plug heap
+   corruption holes, to catch integer overflow in the computation of
+   pathname lengths, and to get rid of the name_path API.  Both of
+   these would have resulted in writing over an under-allocated buffer
+   when formulating pathnames while tree traversal.
diff --git a/Documentation/RelNotes/2.4.12.txt b/Documentation/RelNotes/2.4.12.txt
new file mode 100644
index 0000000000..7d15f94725
--- /dev/null
+++ b/Documentation/RelNotes/2.4.12.txt
@@ -0,0 +1,12 @@
+Git v2.4.12 Release Notes
+=========================
+
+Fixes since v2.4.11
+-------------------
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
diff --git a/Documentation/RelNotes/2.4.2.txt b/Documentation/RelNotes/2.4.2.txt
new file mode 100644
index 0000000000..250cdc423c
--- /dev/null
+++ b/Documentation/RelNotes/2.4.2.txt
@@ -0,0 +1,45 @@
+Git v2.4.2 Release Notes
+========================
+
+Fixes since v2.4.1
+------------------
+
+ * "git rev-list --objects $old --not --all" to see if everything that
+   is reachable from $old is already connected to the existing refs
+   was very inefficient.
+
+ * "hash-object --literally" introduced in v2.2 was not prepared to
+   take a really long object type name.
+
+ * "git rebase --quiet" was not quite quiet when there is nothing to
+   do.
+
+ * The completion for "log --decorate=" parameter value was incorrect.
+
+ * "filter-branch" corrupted commit log message that ends with an
+   incomplete line on platforms with some "sed" implementations that
+   munge such a line.  Work it around by avoiding to use "sed".
+
+ * "git daemon" fails to build from the source under NO_IPV6
+   configuration (regression in 2.4).
+
+ * "git stash pop/apply" forgot to make sure that not just the working
+   tree is clean but also the index is clean. The latter is important
+   as a stash application can conflict and the index will be used for
+   conflict resolution.
+
+ * We have prepended $GIT_EXEC_PATH and the path "git" is installed in
+   (typically "/usr/bin") to $PATH when invoking subprograms and hooks
+   for almost eternity, but the original use case the latter tried to
+   support was semi-bogus (i.e. install git to /opt/foo/git and run it
+   without having /opt/foo on $PATH), and more importantly it has
+   become less and less relevant as Git grew more mainstream (i.e. the
+   users would _want_ to have it on their $PATH).  Stop prepending the
+   path in which "git" is installed to users' $PATH, as that would
+   interfere the command search order people depend on (e.g. they may
+   not like versions of programs that are unrelated to Git in /usr/bin
+   and want to override them by having different ones in /usr/local/bin
+   and have the latter directory earlier in their $PATH).
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.3.txt b/Documentation/RelNotes/2.4.3.txt
new file mode 100644
index 0000000000..422e930aa2
--- /dev/null
+++ b/Documentation/RelNotes/2.4.3.txt
@@ -0,0 +1,76 @@
+Git v2.4.3 Release Notes
+========================
+
+Fixes since v2.4.3
+------------------
+
+ * Error messages from "git branch" called remote-tracking branches as
+   "remote branches".
+
+ * "git rerere forget" in a repository without rerere enabled gave a
+   cryptic error message; it should be a silent no-op instead.
+
+ * "git pull --log" and "git pull --no-log" worked as expected, but
+   "git pull --log=20" did not.
+
+ * The pull.ff configuration was supposed to override the merge.ff
+   configuration, but it didn't.
+
+ * The code to read pack-bitmap wanted to allocate a few hundred
+   pointers to a structure, but by mistake allocated and leaked memory
+   enough to hold that many actual structures.  Correct the allocation
+   size and also have it on stack, as it is small enough.
+
+ * Various documentation mark-up fixes to make the output more
+   consistent in general and also make AsciiDoctor (an alternative
+   formatter) happier.
+
+ * "git bundle verify" did not diagnose extra parameters on the
+   command line.
+
+ * Multi-ref transaction support we merged a few releases ago
+   unnecessarily kept many file descriptors open, risking to fail with
+   resource exhaustion.
+
+ * The ref API did not handle cases where 'refs/heads/xyzzy/frotz' is
+   removed at the same time as 'refs/heads/xyzzy' is added (or vice
+   versa) very well.
+
+ * The "log --decorate" enhancement in Git 2.4 that shows the commit
+   at the tip of the current branch e.g. "HEAD -> master", did not
+   work with --decorate=full.
+
+ * There was a commented-out (instead of being marked to expect
+   failure) test that documented a breakage that was fixed since the
+   test was written; turn it into a proper test.
+
+ * core.excludesfile (defaulting to $XDG_HOME/git/ignore) is supposed
+   to be overridden by repository-specific .git/info/exclude file, but
+   the order was swapped from the beginning. This belatedly fixes it.
+
+ * The connection initiation code for "ssh" transport tried to absorb
+   differences between the stock "ssh" and Putty-supplied "plink" and
+   its derivatives, but the logic to tell that we are using "plink"
+   variants were too loose and falsely triggered when "plink" appeared
+   anywhere in the path (e.g. "/home/me/bin/uplink/ssh").
+
+ * "git rebase -i" moved the "current" command from "todo" to "done" a
+   bit too prematurely, losing a step when a "pick" did not even start.
+
+ * "git add -e" did not allow the user to abort the operation by
+   killing the editor.
+
+ * Git 2.4 broke setting verbosity and progress levels on "git clone"
+   with native transports.
+
+ * Some time ago, "git blame" (incorrectly) lost the convert_to_git()
+   call when synthesizing a fake "tip" commit that represents the
+   state in the working tree, which broke folks who record the history
+   with LF line ending to make their project portable across
+   platforms while terminating lines in their working tree files with
+   CRLF for their platform.
+
+ * Code clean-up for xdg configuration path support.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.4.txt b/Documentation/RelNotes/2.4.4.txt
new file mode 100644
index 0000000000..f1ccd001be
--- /dev/null
+++ b/Documentation/RelNotes/2.4.4.txt
@@ -0,0 +1,35 @@
+Git v2.4.4 Release Notes
+========================
+
+Fixes since v2.4.3
+------------------
+
+ * l10n updates for German.
+
+ * An earlier leakfix to bitmap testing code was incomplete.
+
+ * "git clean pathspec..." tried to lstat(2) and complain even for
+   paths outside the given pathspec.
+
+ * Communication between the HTTP server and http_backend process can
+   lead to a dead-lock when relaying a large ref negotiation request.
+   Diagnose the situation better, and mitigate it by reading such a
+   request first into core (to a reasonable limit).
+
+ * The clean/smudge interface did not work well when filtering an
+   empty contents (failed and then passed the empty input through).
+   It can be argued that a filter that produces anything but empty for
+   an empty input is nonsense, but if the user wants to do strange
+   things, then why not?
+
+ * Make "git stash something --help" error out, so that users can
+   safely say "git stash drop --help".
+
+ * Clarify that "log --raw" and "log --format=raw" are unrelated
+   concepts.
+
+ * Catch a programmer mistake to feed a pointer not an array to
+   ARRAY_SIZE() macro, by using a couple of GCC extensions.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.5.txt b/Documentation/RelNotes/2.4.5.txt
new file mode 100644
index 0000000000..568297ccb7
--- /dev/null
+++ b/Documentation/RelNotes/2.4.5.txt
@@ -0,0 +1,28 @@
+Git v2.4.5 Release Notes
+========================
+
+Fixes since v2.4.4
+------------------
+
+ * The setup code used to die when core.bare and core.worktree are set
+   inconsistently, even for commands that do not need working tree.
+
+ * There was a dead code that used to handle "git pull --tags" and
+   show special-cased error message, which was made irrelevant when
+   the semantics of the option changed back in Git 1.9 days.
+
+ * "color.diff.plain" was a misnomer; give it 'color.diff.context' as
+   a more logical synonym.
+
+ * The configuration reader/writer uses mmap(2) interface to access
+   the files; when we find a directory, it barfed with "Out of memory?".
+
+ * Recent "git prune" traverses young unreachable objects to safekeep
+   old objects in the reachability chain from them, which sometimes
+   showed unnecessary error messages that are alarming.
+
+ * "git rebase -i" fired post-rewrite hook when it shouldn't (namely,
+   when it was told to stop sequencing with 'exec' insn).
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.6.txt b/Documentation/RelNotes/2.4.6.txt
new file mode 100644
index 0000000000..b53f353939
--- /dev/null
+++ b/Documentation/RelNotes/2.4.6.txt
@@ -0,0 +1,23 @@
+Git v2.4.6 Release Notes
+========================
+
+Fixes since v2.4.5
+------------------
+
+ * "git fetch --depth=<depth>" and "git clone --depth=<depth>" issued
+   a shallow transfer request even to an upload-pack that does not
+   support the capability.
+
+ * "git fsck" used to ignore missing or invalid objects recorded in reflog.
+
+ * The tcsh completion writes a bash scriptlet but that would have
+   failed for users with noclobber set.
+
+ * Recent Mac OS X updates breaks the logic to detect that the machine
+   is on the AC power in the sample pre-auto-gc script.
+
+ * "git format-patch --ignore-if-upstream A..B" did not like to be fed
+   tags as boundary commits.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.7.txt b/Documentation/RelNotes/2.4.7.txt
new file mode 100644
index 0000000000..b3ac412b82
--- /dev/null
+++ b/Documentation/RelNotes/2.4.7.txt
@@ -0,0 +1,53 @@
+Git v2.4.7 Release Notes
+========================
+
+Fixes since v2.4.6
+------------------
+
+ * A minor regression to "git fsck" in v2.2 era was fixed; it
+   complained about a body-less tag object when it lacked a
+   separator empty line after its header to separate it with a
+   non-existent body.
+
+ * We used to ask libCURL to use the most secure authentication method
+   available when talking to an HTTP proxy only when we were told to
+   talk to one via configuration variables.  We now ask libCURL to
+   always use the most secure authentication method, because the user
+   can tell libCURL to use an HTTP proxy via an environment variable
+   without using configuration variables.
+
+ * When you say "!<ENTER>" while running say "git log", you'd confuse
+   yourself in the resulting shell, that may look as if you took
+   control back to the original shell you spawned "git log" from but
+   that isn't what is happening.  To that new shell, we leaked
+   GIT_PAGER_IN_USE environment variable that was meant as a local
+   communication between the original "Git" and subprocesses that was
+   spawned by it after we launched the pager, which caused many
+   "interesting" things to happen, e.g. "git diff | cat" still paints
+   its output in color by default.
+
+   Stop leaking that environment variable to the pager's half of the
+   fork; we only need it on "Git" side when we spawn the pager.
+
+ * Avoid possible ssize_t to int truncation.
+
+ * "git config" failed to update the configuration file when the
+   underlying filesystem is incapable of renaming a file that is still
+   open.
+
+ * A minor bugfix when pack bitmap is used with "rev-list --count".
+
+ * An ancient test framework enhancement to allow color was not
+   entirely correct; this makes it work even when tput needs to read
+   from the ~/.terminfo under the user's real HOME directory.
+
+ * Fix a small bug in our use of umask() return value.
+
+ * "git rebase" did not exit with failure when format-patch it invoked
+   failed for whatever reason.
+
+ * Disable "have we lost a race with competing repack?" check while
+   receiving a huge object transfer that runs index-pack.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.8.txt b/Documentation/RelNotes/2.4.8.txt
new file mode 100644
index 0000000000..ad946b2673
--- /dev/null
+++ b/Documentation/RelNotes/2.4.8.txt
@@ -0,0 +1,21 @@
+Git v2.4.8 Release Notes
+========================
+
+Fixes since v2.4.7
+------------------
+
+ * Abandoning an already applied change in "git rebase -i" with
+   "--continue" left CHERRY_PICK_HEAD and confused later steps.
+
+ * Various fixes around "git am" that applies a patch to a history
+   that is not there yet.
+
+ * "git for-each-ref" reported "missing object" for 0{40} when it
+   encounters a broken ref.  The lack of object whose name is 0{40} is
+   not the problem; the ref being broken is.
+
+ * "git commit --cleanup=scissors" was not careful enough to protect
+   against getting fooled by a line that looked like scissors.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.4.9.txt b/Documentation/RelNotes/2.4.9.txt
new file mode 100644
index 0000000000..09af9ddbc7
--- /dev/null
+++ b/Documentation/RelNotes/2.4.9.txt
@@ -0,0 +1,9 @@
+Git v2.4.9 Release Notes
+========================
+
+Fixes since v2.4.9
+------------------
+
+ * A handful of codepaths that used to use fixed-sized arrays to hold
+   pathnames have been corrected to use strbuf and other mechanisms to
+   allow longer pathnames without fearing overflows.
diff --git a/Documentation/RelNotes/2.40.0.txt b/Documentation/RelNotes/2.40.0.txt
new file mode 100644
index 0000000000..3ea445bf20
--- /dev/null
+++ b/Documentation/RelNotes/2.40.0.txt
@@ -0,0 +1,320 @@
+Git v2.40 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "merge-tree" learns a new `--merge-base` option.
+
+ * "git jump" (in contrib/) learned to present the "quickfix list" to
+   its standard output (instead of letting it consumed by the editor
+   it invokes), and learned to also drive emacs/emacsclient.
+
+ * "git var UNKNOWN_VARIABLE" and "git var VARIABLE" with the variable
+   given an empty value used to behave identically.  Now the latter
+   just gives an empty output, while the former still gives an error
+   message.
+
+ * Introduce a case insensitive mode to the Bash completion helpers.
+
+ * The advice message given by "git status" when it takes long time to
+   enumerate untracked paths has been updated.
+
+ * Just like "git var GIT_EDITOR" abstracts the complex logic to
+   choose which editor gets used behind it, "git var" now give support
+   to GIT_SEQUENCE_EDITOR.
+
+ * "git format-patch" learned to honor format.mboxrd even when sending
+   patches to the standard output stream,
+
+ * 'cat-file' gains mailmap support for its '--batch-check' and '-s'
+   options.
+
+ * Conditionally skip the pre-applypatch and applypatch-msg hooks when
+   applying patches with 'git am'.
+
+ * Introduce an optional configuration to allow the trailing hash that
+   protects the index file from bit flipping.
+
+ * "git check-attr" learned to take an optional tree-ish to read the
+   .gitattributes file from.
+
+ * "scalar" learned to give progress bar.
+
+ * "grep -P" learned to use Unicode Character Property to grok
+   character classes when processing \b and \w etc.
+
+ * "git rebase" often ignored incompatible options instead of
+   complaining, which has been corrected.
+
+ * "scalar" warns but continues when its periodic maintenance
+   feature cannot be enabled.
+
+ * The bundle-URI subsystem adds support for creation-token heuristics
+   to help incremental fetches.
+
+ * Userdiff regexp update for Java language.
+
+ * "git fetch --jobs=0" used to hit a BUG(), which has been corrected
+   to use the available CPUs.
+
+ * An invalid label or ref in the "rebase -i" todo file used to
+   trigger an runtime error. SUch an error is now diagnosed while the
+   todo file is parsed.
+
+ * The "diff" drivers specified by the "diff" attribute attached to
+   paths can now specify which algorithm (e.g. histogram) to use.
+
+ * "git range-diff" learned --abbrev=<num> option.
+
+ * "git archive HEAD^{tree}" records the paths with the current
+   timestamp in the archive, making it harder to obtain a stable
+   output.  The command learned the --mtime option to specify an
+   arbitrary timestamp (e.g. --mtime="@0 +0000" for the epoch).
+
+ * The credential subsystem learned that a password may have an
+   explicit expiration.
+
+ * The format.attach configuration variable lacked a way to override a
+   value defined in a lower-priority configuration file (e.g. the
+   system one) by redefining it in a higher-priority configuration
+   file.  Now, setting format.attach to an empty string means show the
+   patch inline in the e-mail message, without using MIME attachment.
+
+   This is a backward incompatible change.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * `git bisect` becomes a builtin.
+
+ * The pack-bitmap machinery is taught to log the paths of redundant
+   bitmap(s) to trace2 instead of stderr.
+
+ * Use the SHA1DC implementation on macOS, just like other platforms,
+   by default.
+
+ * Even in a repository with promisor remote, it is useless to
+   attempt to lazily attempt fetching an object that is expected to be
+   commit, because no "filter" mode omits commit objects.  Take
+   advantage of this assumption to fail fast on errors.
+
+ * Stop using "git --super-prefix" and narrow the scope of its use to
+   the submodule--helper.
+
+ * Stop running win+VS build by default.
+
+ * CI updates.  We probably want a clean-up to move the long shell
+   script embedded in yaml file into a separate file, but that can
+   come later.
+
+ * Use `git diff --no-index` as a test_cmp on Windows.
+
+   We'd probably need to revisit "do we really want to, and have to,
+   lose CRLF vs LF?" later, at which time we may be able to further
+   clean this up by replacing "git diff --no-index" with "diff -u".
+
+ * Avoid unnecessary builds in CI, with settings configured in
+   ci-config.
+
+ * Plug leaks in sequencer subsystem and its users.
+
+ * In-tree .gitattributes update to match the way we recommend our
+   users to mark a file as text.
+   (merge 1f34e0cd3d po/attributes-text later to maint).
+
+ * Finally retire the scripted "git add -p/-i" implementation and have
+   everybody use the one reimplemented in C.
+
+
+Fixes since v2.39
+-----------------
+
+ * Various leak fixes.
+
+ * Fix a bug where `pack-objects` would not respect multiple `--filter`
+   arguments when invoked directly.
+   (merge d4f7036887 rs/multi-filter-args later to maint).
+
+ * Make fsmonitor more robust to avoid the flakiness seen in t7527.
+   (merge 6692d45477 jh/t7527-unflake-by-forcing-cookie later to maint).
+
+ * Stop using deprecated macOS API in fsmonitor.
+   (merge b0226007f0 jh/fsmonitor-darwin-modernize later to maint).
+
+ * Redefining system functions for a few functions did not follow our
+   usual "implement git_foo() and #define foo(args) git_foo(args)"
+   pattern, which has broken build for some folks.
+
+ * The way the diff machinery prepares the options array for the
+   parse_options API has been refactored to avoid resource leaks.
+   (merge 189e97bc4b rs/diff-parseopts later to maint).
+
+ * Correct pthread API usage.
+   (merge 786e67611d sx/pthread-error-check-fix later to maint).
+
+ * The code to auto-correct a misspelt subcommand unnecessarily called
+   into git_default_config() from the early config codepath, which was
+   a no-no.  This has bee corrected.
+   (merge 0918d08887 sg/help-autocorrect-config-fix later to maint).
+
+ * "git http-fetch" (which is rarely used) forgot to identify itself
+   in the trace2 output.
+   (merge 7abb43cbc8 jt/http-fetch-trace2-report-name later to maint).
+
+ * The output from "git diff --stat" on an unmerged path lost the
+   terminating LF in Git 2.39, which has been corrected.
+   (merge 209d9cb011 pg/diff-stat-unmerged-regression-fix later to maint).
+
+ * "git pull -v --recurse-submodules" attempted to pass "-v" down to
+   underlying "git submodule update", which did not understand the
+   request and barfed, which has been corrected.
+   (merge 6f65f84766 ss/pull-v-recurse-fix later to maint).
+
+ * When given a pattern that matches an empty string at the end of a
+   line, the code to parse the "git diff" line-ranges fell into an
+   infinite loop, which has been corrected.
+
+ * Fix the sequence to fsync $GIT_DIR/packed-refs file that forgot to
+   flush its output to the disk..
+
+ * Fix to a small regression in 2.38 days.
+
+ * "git diff --relative" did not mix well with "git diff --ext-diff",
+   which has been corrected.
+
+ * The logic to see if we are using the "cone" mode by checking the
+   sparsity patterns has been tightened to avoid mistaking a pattern
+   that names a single file as specifying a cone.
+
+ * Deal with a few deprecation warning from cURL library.
+
+ * Doc update for environment variables set when hooks are invoked.
+
+ * Document ORIG_HEAD a bit more.
+
+ * "git ls-tree --format='%(path) %(path)' $tree $path" showed the
+   path three times, which has been corrected.
+
+ * Remove "git env--helper" and demote it to a test-tool subcommand.
+   (merge 4a1baacd46 ab/test-env-helper later to maint).
+
+ * Newer regex library macOS stopped enabling GNU-like enhanced BRE,
+   where '\(A\|B\)' works as alternation, unless explicitly asked with
+   the REG_ENHANCED flag.  "git grep" now can be compiled to do so, to
+   retain the old behaviour.
+
+ * Pthread emulation on Win32 leaked thread handle when a thread is
+   joined.
+   (merge 238a9dfe86 sk/win32-close-handle-upon-pthread-join later to maint).
+
+ * "git send-email -v 3" used to be expanded to "git send-email
+   --validate 3" when the user meant to pass them down to
+   "format-patch", which has been corrected.
+   (merge 8774aa56ad km/send-email-with-v-reroll-count later to maint).
+
+ * Document that "branch -f <branch>" disables only the safety to
+   avoid recreating an existing branch.
+
+ * "git fetch <group>", when "<group>" of remotes lists the same
+   remote twice, unnecessarily failed when parallel fetching was
+   enabled, which has been corrected.
+   (merge 06a668cb90 cw/fetch-remote-group-with-duplication later to maint).
+
+ * Clarify how "checkout -b/-B" and "git branch [-f]" are similar but
+   different in the documentation.
+
+ * "git hash-object" now checks that the resulting object is well
+   formed with the same code as "git fsck".
+   (merge 8e4309038f jk/hash-object-fsck later to maint).
+
+ * Improve the error message given when private key is not loaded in
+   the ssh agent in the codepath to sign with an ssh key.
+   (merge dce7b31126 as/ssh-signing-improve-key-missing-error later to maint).
+
+ * Adjust "git request-pull" to strip embedded signature from signed
+   tags to notice non-PGP signatures.
+   (merge a9cad02538 gm/request-pull-with-non-pgp-signed-tags later to maint).
+
+ * Remove support for MSys, which now lags way behind MSys2.
+   (merge 2987407f3c hj/remove-msys-support later to maint).
+
+ * Fix use of CreateThread() API call made early in the windows
+   start-up code.
+   (merge 592bcab61b sk/winansi-createthread-fix later to maint).
+
+ * "git pack-objects" learned to release delta-island bitmap data when
+   it is done using it, saving peak heap memory usage.
+   (merge 647982bb71 ew/free-island-marks later to maint).
+
+ * In an environment where dynamically generated code is prohibited to
+   run (e.g. SELinux), failure to JIT pcre patterns is expected.  Fall
+   back to interpreted execution in such a case.
+   (merge 50b6ad55b0 cb/grep-fallback-failing-jit later to maint).
+
+ * "git name-rev" heuristics update.
+   (merge b2182a8730 en/name-rev-make-taggerdate-much-less-important later to maint).
+
+ * Remove more remaining uses of macros that relies on the_index
+   singleton instance without explicitly spelling it out.
+
+ * Remove unnecessary explicit sizing of strbuf.
+   (merge 93ea118bed rs/cache-tree-strbuf-growth-fix later to maint).
+
+ * Doc update.
+   (merge d9ec3b0dc0 jk/doc-ls-remote-matching later to maint).
+
+ * Error messages given upon a signature verification failure used to
+   discard the errors from underlying gpg program, which has been
+   corrected.
+   (merge ad6b320756 js/gpg-errors later to maint).
+
+ * Update --date=default documentation.
+   (merge 9deef088ae rd/doc-default-date-format later to maint).
+
+ * A test helper had a single write(2) of 256kB, which was too big for
+   some platforms (e.g. NonStop), which has been corrected by using
+   xwrite() wrapper appropriately.
+   (merge 58eab6ff13 jc/genzeros-avoid-raw-write later to maint).
+
+ * sscanf(3) used in "git symbolic-ref --short" implementation found
+   to be not working reliably on macOS in UTF-8 locales.  Rewrite the
+   code to avoid sscanf() altogether to work it around.
+   (merge 613bef56b8 jk/shorten-unambiguous-ref-wo-sscanf later to maint).
+
+ * Various fix-ups on HTTP tests.
+   (merge 8f2146dbf1 jk/http-test-fixes later to maint).
+
+ * Fixes to code that parses the todo file used in "rebase -i".
+   (merge 666b6e1135 pw/rebase-i-parse-fix later to maint).
+
+ * Test library clean-up.
+   (merge c600a91c94 ar/test-lib-remove-stale-comment later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 4eb1ccecd4 dh/mingw-ownership-check-typofix later to maint).
+   (merge f95526419b ar/typofix-gitattributes-doc later to maint).
+   (merge 27875aeec9 km/doc-branch-start-point later to maint).
+   (merge 35c194dc57 es/t1509-root-fixes later to maint).
+   (merge 7b341645e3 pw/ci-print-failure-name-fix later to maint).
+   (merge bcb71d45bf jx/t1301-updates later to maint).
+   (merge ebdc46c242 jc/doc-diff-patch.txt later to maint).
+   (merge a87a20cbb4 ar/test-cleanup later to maint).
+   (merge f5156f1885 ar/bisect-doc-update later to maint).
+   (merge fca2d86c97 jk/interop-error later to maint).
+   (merge cf4936ed74 tl/ls-tree-code-clean-up later to maint).
+   (merge dcb47e52b0 en/t6426-todo-cleanup later to maint).
+   (merge 5b8db44bdd jc/format-patch-v-unleak later to maint).
+   (merge 590b636737 jk/hash-object-literally-fd-leak later to maint).
+   (merge 5458ba0a4d tb/t0003-invoke-dd-more-portably later to maint).
+   (merge 70661d288b ar/markup-em-dash later to maint).
+   (merge e750951e74 en/ls-files-doc-update later to maint).
+   (merge 4f542975d1 mh/doc-credential-cache-only-in-core later to maint).
+   (merge 3a2ebaebc7 gc/index-format-doc later to maint).
+   (merge b08edf709d jk/httpd-test-updates later to maint).
+   (merge d85e9448dd wl/new-command-doc later to maint).
+   (merge d912a603ed kf/t5000-modernise later to maint).
+   (merge e65b868d07 rs/size-t-fixes later to maint).
+   (merge 3eb1e1ca9a ab/config-h-remove-unused later to maint).
+   (merge d390e08076 cw/doc-pushurl-vs-url later to maint).
+   (merge 567342fc77 rs/ctype-test later to maint).
+   (merge d35d8f2e7a ap/t2015-style-update later to maint).
diff --git a/Documentation/RelNotes/2.40.1.txt b/Documentation/RelNotes/2.40.1.txt
new file mode 100644
index 0000000000..e72f6b1b25
--- /dev/null
+++ b/Documentation/RelNotes/2.40.1.txt
@@ -0,0 +1,8 @@
+Git v2.40.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.30.9, v2.31.8,
+v2.32.7, v2.33.8, v2.34.8, v2.35.8, v2.36.6, v2.37.7, v2.38.5
+and v2.39.3 to address the security issues CVE-2023-25652,
+CVE-2023-25815, and CVE-2023-29007; see the release notes for these
+versions for details.
diff --git a/Documentation/RelNotes/2.40.2.txt b/Documentation/RelNotes/2.40.2.txt
new file mode 100644
index 0000000000..646a2cc3eb
--- /dev/null
+++ b/Documentation/RelNotes/2.40.2.txt
@@ -0,0 +1,7 @@
+Git v2.40.2 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4 to address
+the security issues CVE-2024-32002, CVE-2024-32004, CVE-2024-32020,
+CVE-2024-32021 and CVE-2024-32465; see the release notes for that
+version for details.
diff --git a/Documentation/RelNotes/2.40.3.txt b/Documentation/RelNotes/2.40.3.txt
new file mode 100644
index 0000000000..6ca088ec86
--- /dev/null
+++ b/Documentation/RelNotes/2.40.3.txt
@@ -0,0 +1,26 @@
+Git v2.40.3 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.'  This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.40.2 and were not
+direct security fixes.
+
+Jeff King (5):
+      send-email: drop FakeTerm hack
+      send-email: avoid creating more than one Term::ReadLine object
+      ci: drop mention of BREW_INSTALL_PACKAGES variable
+      ci: avoid bare "gcc" for osx-gcc job
+      ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+      hook: plug a new memory leak
+      init: use the correct path of the templates directory again
+      Revert "core.hooksPath: add some protection while cloning"
+      tests: verify that `clone -c core.hooksPath=/dev/null` works again
+      clone: drop the protections where hooks aren't run
+      Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+      Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.40.4.txt b/Documentation/RelNotes/2.40.4.txt
new file mode 100644
index 0000000000..0ff29f3cfc
--- /dev/null
+++ b/Documentation/RelNotes/2.40.4.txt
@@ -0,0 +1,5 @@
+Git v2.40.4 Release Notes
+=========================
+
+This release lets Git refuse to accept URLs that contain control
+sequences.  This addresses CVE-2024-50349 and CVE-2024-52006.
diff --git a/Documentation/RelNotes/2.41.0.txt b/Documentation/RelNotes/2.41.0.txt
new file mode 100644
index 0000000000..8a9e17016e
--- /dev/null
+++ b/Documentation/RelNotes/2.41.0.txt
@@ -0,0 +1,399 @@
+Git v2.41 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * Allow information carried on the WWW-Authenticate header to be
+   passed to the credential helpers.
+
+ * A new "fetch.hideRefs" option can be used to exclude specified refs
+   from "rev-list --objects --stdin --not --all" traversal for
+   checking object connectivity, most useful when there are many
+   unrelated histories in a single repository.
+
+ * "git push" has been taught to allow deletion of refs with one-level
+   names to help repairing a repository who acquired such a ref by
+   mistake.  In general, we don't encourage use of such a ref, and
+   creation or update to such a ref is rejected as before.
+
+ * Allow "git bisect reset" to check out the original branch when the
+   branch is already checked out in a different worktree linked to the
+   same repository.
+
+ * A few subcommands have been taught to stop users from working on a
+   branch that is being used in another worktree linked to the same
+   repository.
+
+ * "git format-patch" learned to write a log-message only output file
+   for empty commits.
+
+ * "git format-patch" honors the src/dst prefixes set to nonstandard
+   values with configuration variables like "diff.noprefix", causing
+   receiving end of the patch that expects the standard -p1 format to
+   break.  "format-patch" has been taught to ignore end-user configuration
+   and always use the standard prefixes.
+
+   This is a backward compatibility breaking change.
+
+ * Lift the limitation that colored prompts can only be used with
+   PROMPT_COMMAND mode.
+
+ * "git blame --contents=<file> <rev> -- <path>" used to be forbidden,
+   but now it finds the origins of lines starting at <file> contents
+   through the history that leads to <rev>.
+
+ * "git pack-redundant" gave a warning when run, as the command has
+   outlived its usefulness long ago and is nominated for future
+   removal.  Now we escalate to give an error.
+
+ * "git clone" from an empty repository learned to propagate the
+   choice of the hash algorithm from the source repository to the
+   newly created repository over any one of the v0/v1/v2 protocol.
+
+ * "git mergetool" and "git difftool" learns a new configuration
+   guiDefault to optionally favor configured guitool over non-gui-tool
+   automatically when $DISPLAY is set.
+
+ * "git branch -d origin/master" would say "no such branch", but it is
+   likely a missed "-r" if refs/remotes/origin/master exists.  The
+   command has been taught to give such a hint in its error message.
+
+ * Clean-up of the code path that deals with merge strategy option
+   handling in "git rebase".
+
+ * "git clone --local" stops copying from an original repository that
+   has symbolic links inside its $GIT_DIR; an error message when that
+   happens has been updated.
+
+ * The "--format=..." option of "git for-each-ref", "git branch", and
+   "git tag" commands learn "--omit-empty" to hide refs whose
+   formatting results in an empty string from the output.
+
+ * The sendemail-validate validate hook learned to pass the total
+   number of input files and where in the sequence each invocation is
+   via environment variables.
+
+ * When "gc" needs to retain unreachable objects, packing them into
+   cruft packs (instead of exploding them into loose object files) has
+   been offered as a more efficient option for some time.  Now the use
+   of cruft packs has been made the default and no longer considered
+   an experimental feature.
+
+ * The output given by "git blame" that attributes a line to contents
+   taken from the file specified by the "--contents" option shows it
+   differently from a line attributed to the working tree file.
+
+ * "git send-email" learned to give the e-mail headers to the validate
+   hook by passing an extra argument from the command line.
+
+ * The credential subsystem learns to help OAuth framework.
+
+ * The titles of manual pages used to be chomped at an unreasonably
+   short limit, which has been removed.
+
+ * Error messages given when working on an unborn branch that is
+   checked out in another worktree have been improved.
+
+ * The documentation was misleading about the interaction between
+   GIT_DEFAULT_HASH and "git clone", which has been clarified to
+   stress that the variable is to be ignored by the command.
+
+ * "git send-email" learned "--header-cmd=<cmd>" that can inject
+   arbitrary e-mail header lines to the outgoing messages.
+
+ * "git fsck" learned to detect bit-flip breakages in the reachability
+   bitmap files.
+
+ * The "--stdin" option of "git name-rev" has been replaced with
+   the "--annotate-stdin" option more than a year ago.  We stop
+   advertising it in the "git name-rev -h" output.
+
+ * "git push --all" gained an alias "git push --branches".
+
+ * "git fetch" learned the "--porcelain" option that emits what it did
+   in a machine-parseable format.
+
+ * "git --attr-source=<tree> cmd $args" is a new way to have any
+   command to read attributes not from the working tree but from the
+   given tree object.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Code clean-up to clarify directory traversal API.
+
+ * Code clean-up to clarify the rule that "git-compat-util.h" must be
+   the first to be included.
+
+ * More work towards -Wunused.
+
+ * Instead of forcing each command to choose to honor GPG related
+   configuration variables, make the subsystem lazily initialize
+   itself.
+
+ * Remove workaround for ancient versions of DocBook to make it work
+   correctly with groff, which has not been necessary since docbook
+   1.76 from 2010.
+
+ * Code clean-up to include and/or uninclude parse-options.h file as
+   needed.
+
+ * The code path that reports what "git fetch" did to each ref has
+   been cleaned up.
+
+ * Assorted config API updates.
+
+ * A few configuration variables to tell the cURL library that
+   different types of ssl-cert and ssl-key are in use have been added.
+
+ * Split key function and data structure definitions out of cache.h to
+   new header files and adjust the users.
+
+ * "git fetch --all" does not have to download and handle the same
+   bundleURI over and over, which has been corrected.
+
+ * "git sparse-checkout" command learns a debugging aid for the sparse
+   rule definitions.
+
+ * "git write-tree" learns to work better with sparse-index.
+
+ * The on-disk reverse index that allows mapping from the pack offset
+   to the object name for the object stored at the offset has been
+   enabled by default.
+
+ * "git fsck" learned to validate the on-disk pack reverse index files.
+
+ * strtok() and strtok_r() are banned in this codebase.
+
+ * The detect-compilers script to help auto-tweaking the build system
+   had trouble working with compilers whose version number has extra
+   suffixes.  The script has been taught that certain suffixes (like
+   "-win32" in "gcc 10-win32") can be safely stripped as they share
+   the same features and bugs with the version without the suffix.
+
+ * ctype tests have been taught to test EOF, too.
+
+ * The implementation of credential helpers used fgets() over fixed
+   size buffers to read protocol messages, causing the remainder of
+   the folded long line to trigger unexpected behaviour, which has
+   been corrected.
+
+ * The implementation of the default "negotiator", used to find common
+   ancestor over the network for object tranfer, used to be recursive;
+   it was updated to be iterative to conserve stackspace usage.
+
+ * Our custom callout formatter is no longer used in the documentation
+   formatting toolchain, as the upstream default ones give better
+   output these days.
+
+ * The tracing mechanism learned to notice and report when
+   auto-discovered bare repositories are being used, as allowing so
+   without explicitly stating the user intends to do so (with setting
+   GIT_DIR for example) can be used with social engineering as an
+   attack vector.
+
+ * "git diff-files" learned not to expand sparse-index unless needed.
+
+
+Fixes since v2.40
+-----------------
+
+ * "git fsck" learned to check the index files in other worktrees,
+   just like "git gc" honors them as anchoring points.
+   (merge 8d3e7eac52 jk/fsck-indices-in-worktrees later to maint).
+
+ * Fix a segfaulting loop.  The function and its caller may need
+   further clean-up.
+   (merge c5773dc078 ew/commit-reach-clean-up-flags-fix later to maint).
+
+ * "git restore" supports options like "--ours" that are only
+   meaningful during a conflicted merge, but these options are only
+   meaningful when updating the working tree files.  These options are
+   marked to be incompatible when both "--staged" and "--worktree" are
+   in effect.
+   (merge ee8a88826a ak/restore-both-incompatible-with-conflicts later to maint).
+
+ * Simplify UI to control progress meter given by "git bundle" command.
+   (merge 8b95521edb jk/bundle-progress later to maint).
+
+ * "git bundle" learned that "-" is a common way to say that the input
+   comes from the standard input and/or the output goes to the
+   standard output.  It used to work only for output and only from the
+   root level of the working tree.
+   (merge 0bbe10313e jk/bundle-use-dash-for-stdfiles later to maint).
+
+ * Once we start running, we assumed that the list of alternate object
+   databases would never change.  Hook into the machinery used to
+   update the list of packfiles during runtime to update this list as
+   well.
+   (merge e2d003dbed ds/reprepare-alternates-when-repreparing-packfiles later to maint).
+
+ * The code to parse "git rebase -X<opt>" was not prepared to see an
+   unparsable option string, which has been corrected.
+   (merge 15a4cc912e ab/fix-strategy-opts-parsing later to maint).
+
+ * "git add -p" while the index is unmerged sometimes failed to parse
+   the diff output it internally produces and died, which has been
+   corrected.
+   (merge 28d1122f9c jk/add-p-unmerged-fix later to maint).
+
+ * Fix for a "ls-files --format="%(path)" that produced nonsense
+   output, which was a bug in 2.38.
+   (merge cfb62dd006 aj/ls-files-format-fix later to maint).
+
+ * "git receive-pack" that responds to "git push" requests failed to
+   clean a stale lockfile when killed in the middle, which has been
+   corrected.
+   (merge c55c30669c ps/receive-pack-unlock-before-die later to maint).
+
+ * "git rev-parse --quiet foo@{u}", or anything that asks @{u} to be
+   parsed with GET_OID_QUIETLY option, did not quietly fail, which has
+   been corrected.
+   (merge dfbfdc521d fc/oid-quietly-parse-upstream later to maint).
+
+ * Transports that do not support protocol v2 did not correctly fall
+   back to protocol v0 under certain conditions, which has been
+   corrected.
+   (merge eaa0fd6584 jk/fix-proto-downgrade-to-v0 later to maint).
+
+ * time(2) on glib 2.31+, especially on Linux, goes out of sync with
+   higher resolution timers used for gettimeofday(2) and by the
+   filesystem.  Replace all calls to it with a git_time() wrapper and
+   (merge 370ddcbc89 pe/time-use-gettimeofday later to maint).
+
+ * Code clean-up to use designated initializers in parse-options API.
+   (merge 353e6d4554 sg/parse-options-h-initializers later to maint).
+
+ * A recent-ish change to allow unicode character classes to be used
+   with "grep -P" triggered a JIT bug in older pcre2 libraries.
+   The problematic change in Git built with these older libraries has
+   been disabled to work around the bug.
+   (merge 14b9a04479 mk/workaround-pcre-jit-ucp-bug later to maint).
+
+ * The wildmatch library code unlearns exponential behaviour it
+   acquired some time ago since it was borrowed from rsync.
+   (merge 3dc0b7f0dc pw/wildmatch-fixes later to maint).
+
+ * The index files can become corrupt under certain conditions when
+   the split-index feature is in use, especially together with
+   fsmonitor, which have been corrected.
+   (merge 061dd722dc js/split-index-fixes later to maint).
+
+ * Document what the pathname-looking strings in "rev-list --object"
+   output are for and what they mean.
+   (merge 15364d2a3c jk/document-rev-list-object-name later to maint).
+
+ * Fix unnecessary truncation of generation numbers used in-core.
+   (merge d3af1c193d ps/ahead-behind-truncation-fix later to maint).
+
+ * Code clean-up around the use of the_repository.
+   (merge 4a93b899c1 ab/remove-implicit-use-of-the-repository later to maint).
+
+ * Consistently spell "Message-ID" as such, not "Message-Id".
+   (merge ba4324c4e1 jc/spell-id-in-both-caps-in-message-id later to maint).
+
+ * Correct use of an uninitialized structure member.
+   (merge dc12ee77ab jx/cap-object-info-uninitialized-fix later to maint).
+
+ * Tests had a few places where we ignored PERL_PATH and blindly used
+   /usr/bin/perl, which have been corrected.
+   (merge c1917156a0 jk/use-perl-path-consistently later to maint).
+
+ * Documentation mark-up fix.
+   (merge 78b6369e67 la/mfc-markup-fix later to maint).
+
+ * Doc toolchain update to remove old workaround for AsciiDoc.
+   (merge 8806120de6 fc/remove-header-workarounds-for-asciidoc later to maint).
+
+ * The userdiff regexp patterns for various filetypes that are built
+   into the system have been updated to avoid triggering regexp errors
+   from UTF-8 aware regex engines.
+   (merge be39144954 rs/userdiff-multibyte-regex later to maint).
+
+ * The approxidate() API has been simplified by losing an extra
+   function that did the same thing as another one.
+   (merge 8a7f0b666f rs/remove-approxidate-relative later to maint).
+
+ * Code clean-up to replace a hardcoded constant with a CPP macro.
+   (merge c870de6502 rs/get-tar-commit-id-use-defined-const later to maint).
+
+ * Doc build simplification.
+   (merge 9a09ed3229 fc/doc-stop-using-manversion later to maint).
+
+ * "git archive" run from a subdirectory mishandled attributes and
+   paths outside the current directory.
+   (merge 92b1dd1b9e rs/archive-from-subdirectory-fixes later to maint).
+
+ * The code to parse capability list for v0 on-wire protocol fell into
+   an infinite loop when a capability appears multiple times, which
+   has been corrected.
+
+ * Geometric repacking ("git repack --geometric=<n>") in a repository
+   that borrows from an alternate object database had various corner
+   case bugs, which have been corrected.
+   (merge d85cd18777 ps/fix-geom-repack-with-alternates later to maint).
+
+ * The "%GT" placeholder for the "--format" option of "git log" and
+   friends caused BUG() to trigger on a commit signed with an unknown
+   key, which has been corrected.
+   (merge 7891e46585 jk/gpg-trust-level-fix later to maint).
+
+ * The completion script used to use bare "read" without the "-r"
+   option to read the contents of various state files, which risked
+   getting confused with backslashes in them.  This has been
+   corrected.
+   (merge 197152098a ek/completion-use-read-r-to-read-literally later to maint).
+
+ * A small API fix to the ort merge strategy backend.
+   (merge 000c4ceca7 en/ort-finalize-after-0-merges-fix later to maint).
+
+ * The commit object parser has been taught to be a bit more lenient
+   to parse timestamps on the author/committer line with a malformed
+   author/committer ident.
+   (merge 90ef0f14eb jk/parse-commit-with-malformed-ident later to maint).
+
+ * Retitle a test script with an overly narrow name.
+   (merge 8bb19c14fb ob/t3501-retitle later to maint).
+
+ * Doc update to clarify how text and eol attributes interact to
+   specify the end-of-line conversion.
+   (merge 6696077ace ah/doc-attributes-text later to maint).
+
+ * Gitk updates from GfW project.
+   (merge 99e70f3077 js/gitk-fixes-from-gfw later to maint).
+
+ * "git diff --dirstat" leaked memory, which has been plugged.
+   (merge 83973981eb jc/dirstat-plug-leaks later to maint).
+
+ * "git merge-tree" reads the basic configuration, which can be used
+    by git forges to disable replace-refs feature.
+   (merge b6551feadf ds/merge-tree-use-config later to maint).
+
+ * A few bugs in the sequencer machinery that results in miscounting
+   the steps have been corrected.
+   (merge 170eea9750 js/rebase-count-fixes later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge f7111175df as/doc-markup-fix later to maint).
+   (merge 90ff7c9898 fc/test-aggregation-clean-up later to maint).
+   (merge 9b0c7f308a jc/am-doc-refer-to-format-patch later to maint).
+   (merge b10cbdac4c bb/unicode-width-table-15 later to maint).
+   (merge 3457b50e8c ab/retire-scripted-add-p later to maint).
+   (merge d52fcf493b ds/p2000-fix-grep-sparse later to maint).
+   (merge ec063d2591 ss/hashmap-typofix later to maint).
+   (merge 1aaed69d11 rs/archive-mtime later to maint).
+   (merge 2da2cc9b28 ob/rollback-after-commit-lock-failure later to maint).
+   (merge 54dbd0933b ob/sequencer-save-head-simplify later to maint).
+   (merge a93cbe8d78 ar/test-cleanup-unused-file-creation later to maint).
+   (merge cc48ddd937 jk/chainlint-fixes later to maint).
+   (merge 4833b08426 ow/ref-format-remove-unused-member later to maint).
+   (merge d0ea2ca1cf dw/doc-submittingpatches-grammofix later to maint).
+   (merge fd72637423 ar/t2024-checkout-output-fix later to maint).
+   (merge d45cbe3fe0 ob/sequencer-i18n-fix later to maint).
+   (merge b734fe49fd ob/messages-capitalize-exception later to maint).
+   (merge ad353d7e77 ma/gittutorial-fixes later to maint).
+   (merge a5855fd8d4 ar/test-cleanup-unused-file-creation-part2 later to maint).
+   (merge 0c5308af30 sd/doc-gitignore-and-rm-cached later to maint).
+   (merge cbb83daeaf kh/doc-interpret-trailers-updates later to maint).
+   (merge 3d77fbb664 ar/config-count-tests-updates later to maint).
+   (merge b7cf25c8f4 jc/t9800-fix-use-of-show-s-raw later to maint).
diff --git a/Documentation/RelNotes/2.41.1.txt b/Documentation/RelNotes/2.41.1.txt
new file mode 100644
index 0000000000..9fb4c218b2
--- /dev/null
+++ b/Documentation/RelNotes/2.41.1.txt
@@ -0,0 +1,7 @@
+Git v2.41.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4 and v2.40.2
+to address the security issues CVE-2024-32002, CVE-2024-32004,
+CVE-2024-32020, CVE-2024-32021 and CVE-2024-32465; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.41.2.txt b/Documentation/RelNotes/2.41.2.txt
new file mode 100644
index 0000000000..f94afde8c2
--- /dev/null
+++ b/Documentation/RelNotes/2.41.2.txt
@@ -0,0 +1,26 @@
+Git v2.41.2 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.'  This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.41.1 and were not
+direct security fixes.
+
+Jeff King (5):
+      send-email: drop FakeTerm hack
+      send-email: avoid creating more than one Term::ReadLine object
+      ci: drop mention of BREW_INSTALL_PACKAGES variable
+      ci: avoid bare "gcc" for osx-gcc job
+      ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+      hook: plug a new memory leak
+      init: use the correct path of the templates directory again
+      Revert "core.hooksPath: add some protection while cloning"
+      tests: verify that `clone -c core.hooksPath=/dev/null` works again
+      clone: drop the protections where hooks aren't run
+      Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+      Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.41.3.txt b/Documentation/RelNotes/2.41.3.txt
new file mode 100644
index 0000000000..b5aba88790
--- /dev/null
+++ b/Documentation/RelNotes/2.41.3.txt
@@ -0,0 +1,6 @@
+Git v2.41.3 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4 to address
+the security issues CVE-2024-50349 and CVE-2024-52006; see the
+release notes for that version for details.
diff --git a/Documentation/RelNotes/2.42.0.txt b/Documentation/RelNotes/2.42.0.txt
new file mode 100644
index 0000000000..0f1897ad5f
--- /dev/null
+++ b/Documentation/RelNotes/2.42.0.txt
@@ -0,0 +1,329 @@
+Git v2.42 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * "git pack-refs" learns "--include" and "--exclude" to tweak the ref
+   hierarchy to be packed using pattern matching.
+
+ * 'git worktree add' learned how to create a worktree based on an
+   orphaned branch with `--orphan`.
+
+ * "git pack-objects" learned to invoke a new hook program that
+   enumerates extra objects to be used as anchoring points to keep
+   otherwise unreachable objects in cruft packs.
+
+ * Add more "git var" for toolsmiths to learn various locations Git is
+   configured with either via the configuration or hard-coded defaults.
+
+ * 'git notes append' was taught '--separator' to specify string to insert
+   between paragraphs.
+
+ * The "git for-each-ref" family of commands learned placeholders
+   related to GPG signature verification.
+
+ * "git diff --no-index" learned to read from named pipes as if they
+   were regular files, to allow "git diff <(process) <(substitution)"
+   some shells support.
+
+ * Help newbies by suggesting that there are cases where force-pushing
+   is a valid and sensible thing to update a branch at a remote
+   repository, rather than reconciling with merge/rebase.
+
+ * "git blame --contents=file" has been taught to work in a bare
+   repository.
+
+ * "git branch -f X" to repoint the branch X said that X was "checked
+   out" in another worktree, even when branch X was not and instead
+   being bisected or rebased.  The message was reworded to say the
+   branch was "in use".
+
+ * Tone down the warning on SHA-256 repositories being an experimental
+   curiosity.  We do not have support for them to interoperate with
+   traditional SHA-1 repositories, but at this point, we do not plan
+   to make breaking changes to SHA-256 repositories and there is no
+   longer need for such a strongly phrased warning.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git diff-tree" has been taught to take advantage of the
+   sparse-index feature.
+
+ * Clang's sanitizer implementation seems to work better than GCC's.
+   (merge d88d727143 jk/ci-use-clang-for-sanitizer-jobs later to maint).
+
+ * The object traversal using reachability bitmap done by
+   "pack-object" has been tweaked to take advantage of the fact that
+   using "boundary" commits as representative of all the uninteresting
+   ones can save quite a lot of object enumeration.
+
+ * discover_git_directory() no longer touches the_repository.
+
+ * "git worktree" learned to work better with sparse index feature.
+
+ * When the external merge driver is killed by a signal, its output
+   should not be trusted as a resolution with conflicts that is
+   proposed by the driver, but the code did.
+
+ * The set-up code for the get_revision() API now allows feeding
+   options like --all and --not in the --stdin mode.
+
+ * Move functions that are not about pure string manipulation out of
+   strbuf.[ch]
+
+ * "imap-send" codepaths got cleaned up to get rid of unused
+   parameters.
+
+ * Enumerating refs in the packed-refs file, while excluding refs that
+   match certain patterns, has been optimized.
+
+ * Mark-up unused parameters in the code so that we can eventually
+   enable -Wunused-parameter by default.
+
+ * Instead of inventing a custom counter variables for debugging,
+   use existing trace2 facility in the fsync customization codepath.
+
+ * "git branch --list --format=<format>" and friends are taught
+   a new "%(describe)" placeholder.
+
+ * Clarify how to choose the starting point for a new topic in
+   developer guidance document.
+
+ * The implementation of "get_sha1_hex()" that reads a hexadecimal
+   string that spells a full object name has been extended to cope
+   with any hash function used in the repository, but the "sha1" in
+   its name survived.  Rename it to get_hash_hex(), a name that is
+   more consistent within its friends like get_hash_hex_algop().
+
+ * Command line parser fix, and a small parse-options API update.
+
+
+Fixes since v2.41
+-----------------
+
+ * "git tag" learned to leave the "$GIT_DIR/TAG_EDITMSG" file when the
+   command failed, so that the user can salvage what they typed.
+   (merge 08c12ec1d0 kh/keep-tag-editmsg-upon-failure later to maint).
+
+ * The "-s" (silent, squelch) option of the "diff" family of commands
+   did not interact with other options that specify the output format
+   well.  This has been cleaned up so that it will clear all the
+   formatting options given before.
+   (merge 9d484b92ed jc/diff-s-with-other-options later to maint).
+
+ * Update documentation regarding Coccinelle patches.
+   (merge 3bd0097cfc gc/doc-cocci-updates later to maint).
+
+ * Some atoms that can be used in "--format=<format>" for "git ls-tree"
+   were not supported by "git ls-files", even though they were relevant
+   in the context of the latter.
+   (merge 4d28c4f75f zh/ls-files-format-atoms later to maint).
+
+ * Document more pseudo-refs and teach the command line completion
+   machinery to complete AUTO_MERGE.
+   (merge 982ff3a649 pb/complete-and-document-auto-merge-and-friends later to maint).
+
+ * "git submodule" code trusted the data coming from the config (and
+   the in-tree .gitmodules file) too much without validating, leading
+   to NULL dereference if the user mucks with a repository (e.g.
+   submodule.<name>.url is removed).  This has been corrected.
+   (merge fbc806acd1 tb/submodule-null-deref-fix later to maint).
+
+ * The value of config.worktree is per-repository, but has been kept
+   in a singleton global variable per process. This has been OK as
+   most Git operations interacted with a single repository at a time,
+   but not right for operations like recursive "grep" that want to
+   access multiple repositories from a single process without forking.
+
+   The global variable has been eliminated and made into a member in
+   the per-repository data structure.
+   (merge 3867f6d650 vd/worktree-config-is-per-repository later to maint).
+
+ * "git [-c log.follow=true] log [--follow] ':(glob)f**'" used to barf.
+   (merge 8260bc5902 jk/log-follow-with-non-literal-pathspec later to maint).
+
+ * Introduce a mechanism to disable replace refs globally and per
+   repository.
+   (merge 9c7d1b057f ds/disable-replace-refs later to maint).
+
+ * "git cat-file --batch" and friends learned "-Z" that uses NUL
+   delimiter for both input and output.
+   (merge f79e18849b ps/cat-file-null-output later to maint).
+
+ * The reimplemented "git add -i" did not honor color.ui configuration.
+   (merge 6f74648cea ds/add-i-color-configuration-fix later to maint).
+
+ * Compilation fix for platforms without D_TYPE in struct dirent.
+   (merge 03bf92b9bf as/dtype-compilation-fix later to maint).
+
+ * Suggest to refrain from using hex literals that are non-portable
+   when writing printf(1) format strings.
+   (merge f0b68f0546 jt/doc-use-octal-with-printf later to maint).
+
+ * Simplify error message when run-command fails to start a command.
+   (merge 6d224ac286 rs/run-command-exec-error-on-noent later to maint).
+
+ * Gracefully deal with a stale MIDX file that lists a packfile that
+   no longer exists.
+   (merge 06f3867865 tb/open-midx-bitmap-fallback later to maint).
+
+ * Even when diff.ignoreSubmodules tells us to ignore submodule
+   changes, "git commit" with an index that already records changes to
+   submodules should include the submodule changes in the resulting
+   commit, but it did not.
+   (merge 5768478edc js/defeat-ignore-submodules-config-with-explicit-addition later to maint).
+
+ * When "git commit --trailer=..." invokes the interpret-trailers
+   machinery, it knows what it feeds to interpret-trailers is a full
+   log message without any patch, but failed to express that by
+   passing the "--no-divider" option, which has been corrected.
+   (merge be3d654343 jk/commit-use-no-divider-with-interpret-trailers later to maint).
+
+ * Avoid breakage of "git pack-objects --cruft" due to inconsistency
+   between the way the code enumerates packfiles in the repository.
+   (merge 73320e49ad tb/collect-pack-filenames-fix later to maint).
+
+ * We create .pack and then .idx, we consider only packfiles that have
+   .idx usable (those with only .pack are not ready yet), so we should
+   remove .idx before removing .pack for consistency.
+   (merge 0dd1324a73 ds/remove-idx-before-pack later to maint).
+
+ * Partially revert a sanity check that the rest of the config code
+   was not ready, to avoid triggering it in a corner case.
+   (merge a53f43f900 gc/config-partial-submodule-kvi-fix later to maint).
+
+ * "git apply" punts when it is fed too large a patch input; the error
+   message it gives when it happens has been clarified.
+   (merge 42612e18d2 pw/apply-too-large later to maint).
+
+ * During a cherry-pick or revert session that works on multiple
+   commits, "git status" did not give correct information, which has
+   been corrected.
+   (merge a096a889f4 jk/cherry-pick-revert-status later to maint).
+
+ * A few places failed to differentiate the case where the index is
+   truly empty (nothing added) and we haven't yet read from the
+   on-disk index file, which have been corrected.
+   (merge 2ee045eea1 js/empty-index-fixes later to maint).
+
+ * "git bugreport" tests did not test what it wanted to test, which
+   has been corrected.
+   (merge 1aa92b8500 ma/t0091-fixup later to maint).
+
+ * Code snippets in a tutorial document no longer compiled after
+   recent header shuffling, which have been corrected.
+   (merge bbd7c7b7c0 vd/adjust-mfow-doc-to-updated-headers later to maint).
+
+ * "git ls-files '(attr:X)D/'" that triggers the common prefix
+   optimization codepath failed to read from "D/.gitattributes",
+   which has been corrected.
+   (merge f4a8fde057 jc/pathspec-match-with-common-prefix later to maint).
+
+ * "git fsck --no-progress" still spewed noise from the commit-graph
+   subsystem, which has been corrected.
+   (merge 9281cd07f0 tb/fsck-no-progress later to maint).
+
+ * Various offset computation in the code that accesses the packfiles
+   and other data in the object layer has been hardened against
+   arithmetic overflow, especially on 32-bit systems.
+   (merge 9a25cad7e0 tb/object-access-overflow-protection later to maint).
+
+ * Names of MinGW header files are spelled in mixed case in some
+   source files, but the build host can be using case sensitive
+   filesystem with header files with their name spelled in all
+   lowercase.
+   (merge 4a53d0d0bc mh/mingw-case-sensitive-build later to maint).
+
+ * Update message mark-up for i18n in "git bundle".
+   (merge bbb6acd998 dk/bundle-i18n-more later to maint).
+
+ * "git tag --list --points-at X" showed tags that directly refers to
+   object X, but did not list a tag that points at such a tag, which
+   has been corrected.
+
+ * "./configure --with-expat=no" did not work as a way to refuse use
+   of the expat library on a system with the library installed, which
+   has been corrected.
+   (merge fb8f7269c2 ah/autoconf-fixes later to maint).
+
+ * When the user edits "rebase -i" todo file so that it starts with a
+   "fixup", which would make it invalid, the command truncated the
+   rest of the file before giving an error and returning the control
+   back to the user.  Stop truncating to make it easier to correct
+   such a malformed todo file.
+   (merge 9645a087c2 ah/sequencer-rewrite-todo-fix later to maint).
+
+ * Rewrite the description of giving a custom command to the
+   submodule.<name>.update configuration variable.
+   (merge 7cebc5bd78 pv/doc-submodule-update-settings later to maint).
+
+ * Adjust to OpenSSL 3+, which deprecates its SHA-1 functions based on
+   its traditional API, by using its EVP API instead.
+   (merge bda9c12073 ew/hash-with-openssl-evp later to maint).
+
+ * Exclude "." from the set of characters to be removed from the
+   beginning and the end of the human-readable name.
+   (merge 1c04cb0744 bc/ident-dot-is-no-longer-crud-letter later to maint).
+
+ * "git bisect visualize" stopped running "gitk" on Git for Windows
+   when the command was reimplemented in C around Git 2.34 timeframe.
+   This has been corrected.
+   (merge fff1594fa7 ma/locate-in-path-for-windows later to maint).
+
+ * "git rebase -i" with a series of squash/fixup, when one of the
+   steps stopped in conflicts and ended up getting skipped, did not
+   handle the accumulated commit log messages, which has been
+   corrected.
+   (merge 6ce7afe163 pw/rebase-skip-commit-message-fix later to maint).
+
+ * Adjust to newer Term::ReadLine to prevent it from breaking
+   the interactive prompt code in send-email.
+   (merge c016726c2d jk/send-email-with-new-readline later to maint).
+
+ * Windows updates.
+   (merge 0050f8e401 ds/maintenance-on-windows-fix later to maint).
+
+ * Correct use of lstat() that assumed a failing call would not
+   clobber the statbuf.
+   (merge 72695d8214 st/mv-lstat-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 51f9d2e563 sa/doc-ls-remote later to maint).
+   (merge c6d26a9dda jk/format-patch-message-id-unleak later to maint).
+   (merge f7e063f326 ps/fetch-cleanups later to maint).
+   (merge e4cf013468 tl/quote-problematic-arg-for-clarity later to maint).
+   (merge 20025fdfc7 tz/test-ssh-verifytime-fix later to maint).
+   (merge e48a21df65 tz/test-fix-pthreads-prereq later to maint).
+   (merge 68b51172e3 mh/commit-reach-get-reachable-plug-leak later to maint).
+   (merge aeee1408ce kh/use-default-notes-doc later to maint).
+   (merge 3b8724bce6 jc/test-modernization later to maint).
+   (merge 447a3b7331 jc/test-modernization-2 later to maint).
+   (merge d57fa7fc73 la/doc-interpret-trailers later to maint).
+   (merge 548afb0d9a la/docs-typofixes later to maint).
+   (merge 3744ffcbcd rs/doc-ls-tree-hex-literal later to maint).
+   (merge 6c26da8404 mh/credential-erase-improvements later to maint).
+   (merge 78e56cff69 tz/lib-gpg-prereq-fix later to maint).
+   (merge 80d32e84b5 rj/leakfixes later to maint).
+   (merge 0a868031ed pb/complete-diff-options later to maint).
+   (merge d4f28279ad jc/doc-hash-object-types later to maint).
+   (merge 1876a5ae15 ks/t4205-test-describe-with-abbrev-fix later to maint).
+   (merge 6e6a529b57 jk/fsck-indices-in-worktrees later to maint).
+   (merge 3e81b896f7 rs/packet-length-simplify later to maint).
+   (merge 4c9cb51fe7 mh/doc-credential-helpers later to maint).
+   (merge 3437f549dd jr/gitignore-doc-example-markup later to maint).
+   (merge 947ebd62a0 jc/am-parseopt-fix later to maint).
+   (merge e12cb98e1e jc/branch-parseopt-fix later to maint).
+   (merge d6f598e443 jc/gitignore-doc-pattern-markup later to maint).
+   (merge a2dad4868b jc/transport-parseopt-fix later to maint).
+   (merge 68cbb20e73 jc/parse-options-show-branch later to maint).
+   (merge 3821eb6c3d jc/parse-options-reset later to maint).
+   (merge c48af99a3e bb/trace2-comment-fix later to maint).
+   (merge c95ae3ff9c rs/describe-parseopt-fix later to maint).
+   (merge 36f76d2a25 rs/pack-objects-parseopt-fix later to maint).
+   (merge 30c8c55cbf jc/tree-walk-drop-base-offset later to maint).
+   (merge d089a06421 rs/bundle-parseopt-cleanup later to maint).
+   (merge 823839bda1 ew/sha256-gcrypt-leak-fixes later to maint).
+   (merge a5c01603b3 bc/ignore-clangd-cache later to maint).
+   (merge 12009a182b js/allow-t4000-to-be-indented-with-spaces later to maint).
+   (merge b3dcd24b8a jc/send-email-pre-process-fix later to maint).
diff --git a/Documentation/RelNotes/2.42.1.txt b/Documentation/RelNotes/2.42.1.txt
new file mode 100644
index 0000000000..3d391b7dcd
--- /dev/null
+++ b/Documentation/RelNotes/2.42.1.txt
@@ -0,0 +1,88 @@
+Git 2.42.1 Release Notes
+========================
+
+There is nothing exciting to see here.  Relative to Git 2.42, this
+release contains the fixes that have already been merged to the
+'master' branch of the development towards Git 2.43 that has been
+tagged as Git 2.43.0-rc0.
+
+Fixes since Git 2.42.0
+----------------------
+
+ * Tests that are known to pass with LSan are now marked as such.
+
+ * Flaky "git p4" tests, as well as "git svn" tests, are now skipped
+   in the (rather expensive) sanitizer CI job.
+
+ * Tests with LSan from time to time seem to emit harmless message
+   that makes our tests unnecessarily flaky; we work it around by
+   filtering the uninteresting output.
+
+ * GitHub CI workflow has learned to trigger Coverity check.
+
+ * Overly long label names used in the sequencer machinery are now
+   chopped to fit under filesystem limitation.
+
+ * Scalar updates.
+
+ * Tweak GitHub Actions CI so that pushing the same commit to multiple
+   branch tips at the same time will not waste building and testing
+   the same thing twice.
+
+ * The commit-graph verification code that detects mixture of zero and
+   non-zero generation numbers has been updated.
+
+ * "git diff -w --exit-code" with various options did not work
+   correctly, which is being addressed.
+
+ * transfer.unpackLimit ought to be used as a fallback, but overrode
+   fetch.unpackLimit and receive.unpackLimit instead.
+
+ * The use of API between two calls to require_clean_work_tree() from
+   the sequencer code has been cleaned up for consistency.
+
+ * "git diff --no-such-option" and other corner cases around the exit
+   status of the "diff" command has been corrected.
+
+ * "git for-each-ref --sort='contents:size'" sorts the refs according
+   to size numerically, giving a ref that points at a blob twelve-byte
+   (12) long before showing a blob hundred-byte (100) long.
+
+ * Various fixes to the behavior of "rebase -i" when the command got
+   interrupted by conflicting changes.
+
+ * References from description of the `--patch` option in various
+   manual pages have been simplified and improved.
+
+ * "git grep -e A --no-or -e B" is accepted, even though the negation
+   of "or" did not mean anything, which has been tightened.
+
+ * The completion script (in contrib/) has been taught to treat the
+   "-t" option to "git checkout" and "git switch" just like the
+   "--track" option, to complete remote-tracking branches.
+
+ * "git diff --no-index -R <(one) <(two)" did not work correctly,
+   which has been corrected.
+
+ * Update "git maintenance" timers' implementation based on systemd
+   timers to work with WSL.
+
+ * "git diff --cached" codepath did not fill the necessary stat
+   information for a file when fsmonitor knows it is clean and ended
+   up behaving as if it is not clean, which has been corrected.
+
+ * Clarify how "alias.foo = : git cmd ; aliased-command-string" should
+   be spelled with necessary whitespaces around punctuation marks to
+   work.
+
+ * HTTP Header redaction code has been adjusted for a newer version of
+   cURL library that shows its traces differently from earlier
+   versions.
+
+ * An error message given by "git send-email" when given a malformed
+   address did not give correct information, which has been corrected.
+
+ * UBSan options were not propagated through the test framework to git
+   run via the httpd, unlike ASan options, which has been corrected.
+
+Also contains various documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.42.2.txt b/Documentation/RelNotes/2.42.2.txt
new file mode 100644
index 0000000000..dbf761a01d
--- /dev/null
+++ b/Documentation/RelNotes/2.42.2.txt
@@ -0,0 +1,7 @@
+Git v2.42.2 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4, v2.40.2
+and v2.41.1 to address the security issues CVE-2024-32002,
+CVE-2024-32004, CVE-2024-32020, CVE-2024-32021 and CVE-2024-32465;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.42.3.txt b/Documentation/RelNotes/2.42.3.txt
new file mode 100644
index 0000000000..bfe3ba5629
--- /dev/null
+++ b/Documentation/RelNotes/2.42.3.txt
@@ -0,0 +1,26 @@
+Git v2.42.3 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.'  This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.42.2 and were not
+direct security fixes.
+
+Jeff King (5):
+      send-email: drop FakeTerm hack
+      send-email: avoid creating more than one Term::ReadLine object
+      ci: drop mention of BREW_INSTALL_PACKAGES variable
+      ci: avoid bare "gcc" for osx-gcc job
+      ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+      hook: plug a new memory leak
+      init: use the correct path of the templates directory again
+      Revert "core.hooksPath: add some protection while cloning"
+      tests: verify that `clone -c core.hooksPath=/dev/null` works again
+      clone: drop the protections where hooks aren't run
+      Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+      Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.42.4.txt b/Documentation/RelNotes/2.42.4.txt
new file mode 100644
index 0000000000..3129d76e75
--- /dev/null
+++ b/Documentation/RelNotes/2.42.4.txt
@@ -0,0 +1,6 @@
+Git v2.42.4 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4 and v2.41.3
+to address the security issues CVE-2024-50349 and CVE-2024-52006;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.43.0.txt b/Documentation/RelNotes/2.43.0.txt
new file mode 100644
index 0000000000..e0e5b535bb
--- /dev/null
+++ b/Documentation/RelNotes/2.43.0.txt
@@ -0,0 +1,323 @@
+Git v2.43 Release Notes
+=======================
+
+Backward Compatibility Notes
+
+ * The "--rfc" option of "git format-patch" used to be a valid way to
+   override an earlier "--subject-prefix=<something>" on the command
+   line and replace it with "[RFC PATCH]", but from this release, it
+   merely prefixes the string "RFC " in front of the given subject
+   prefix.  If you are negatively affected by this change, please use
+   "--subject-prefix=PATCH --rfc" as a replacement.
+
+ * In Git 2.42, "git rev-list --stdin" learned to take non-revisions
+   (like "--not") from the standard input, but the way such a "--not" was
+   handled was quite confusing, which has been rethought.  The updated
+   rule is that "--not" given from the command line only affects revs
+   given from the command line that comes but not revs read from the
+   standard input, and "--not" read from the standard input affects
+   revs given from the standard input and not revs given from the
+   command line.
+
+UI, Workflows & Features
+
+ * A message written in olden time prevented a branch from getting
+   checked out, saying it is already checked out elsewhere. But these
+   days, we treat a branch that is being bisected or rebased just like
+   a branch that is checked out and protect it from getting modified
+   with the same codepath.  The message has been rephrased to say that
+   the branch is "in use" to avoid confusion.
+
+ * Hourly and other schedules of "git maintenance" jobs are randomly
+   distributed now.
+
+ * "git cmd -h" learned to signal which options can be negated by
+   listing such options like "--[no-]opt".
+
+ * The way authentication related data other than passwords (e.g.,
+   oauth token and password expiration data) are stored in libsecret
+   keyrings has been rethought.
+
+ * Update the libsecret and wincred credential helpers to correctly
+   match which credential to erase; they erased the wrong entry in
+   some cases.
+
+ * Git GUI updates.
+
+ * "git format-patch" learned a new "--description-file" option that
+   lets cover letter description to be fed; this can be used on
+   detached HEAD where there is no branch description available, and
+   also can override the branch description if there is one.
+
+ * Use of the "--max-pack-size" option to allow multiple packfiles to
+   be created is now supported even when we are sending unreachable
+   objects to cruft packs.
+
+ * "git format-patch --rfc --subject-prefix=<foo>" used to ignore the
+   "--subject-prefix" option and used "[RFC PATCH]"; now we will add
+   "RFC" prefix to whatever subject prefix is specified.
+
+ * "git log --format" has been taught the %(decorate) placeholder for
+   further customization over what the "--decorate" option offers.
+
+ * The default log message created by "git revert", when reverting a
+   commit that records a revert, has been tweaked, to encourage people
+   to describe complex "revert of revert of revert" situations better in
+   their own words.
+
+ * The command-line completion support (in contrib/) learned to
+   complete "git commit --trailer=" for possible trailer keys.
+
+ * "git update-index" learned the "--show-index-version" option to
+   inspect the index format version used by the on-disk index file.
+
+ * "git diff" learned the "diff.statNameWidth" configuration variable,
+   to give the default width for the name part in the "--stat" output.
+
+ * "git range-diff --notes=foo" compared "log --notes=foo --notes" of
+   the two ranges, instead of using just the specified notes tree,
+   which has been corrected to use only the specified notes tree.
+
+ * The command line completion script (in contrib/) can be told to
+   complete aliases by including ": git <cmd> ;" in the alias to tell
+   it that the alias should be completed in a similar way to how "git
+   <cmd>" is completed.  The parsing code for the alias has been
+   loosened to allow ';' without an extra space before it.
+
+ * "git for-each-ref" and friends learned to apply mailmap to
+   authorname and other fields in a more flexible way than using
+   separate placeholder letters like %a[eElL] every time we want to
+   come up with small variants.
+
+ * "git repack" machinery learned to pay attention to the "--filter="
+   option.
+
+ * "git repack" learned the "--max-cruft-size" option to prevent cruft
+   packs from growing without bounds.
+
+ * "git merge-tree" learned to take strategy backend specific options
+   via the "-X" option, like "git merge" does.
+
+ * "git log" and friends learned the "--dd" option that is a
+   short-hand for "--diff-merges=first-parent -p".
+
+ * The attribute subsystem learned to honor the "attr.tree"
+   configuration variable that specifies which tree to read the
+   .gitattributes files from.
+
+ * "git merge-file" learns a mode to read three variants of the
+   contents to be merged from blob objects.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "git check-attr" has been taught to work better with sparse-index.
+
+ * It may be tempting to leave the help text NULL for a command line
+   option that is either hidden or too obvious, but "git subcmd -h"
+   and "git subcmd --help-all" would have segfaulted if done so.  Now
+   the help text is truly optional.
+
+ * Tests that are known to pass with LSan are now marked as such.
+
+ * Flaky "git p4" tests, as well as "git svn" tests, are now skipped
+   in the (rather expensive) sanitizer CI job.
+
+ * Tests with LSan from time to time seem to emit harmless messages
+   that make our tests unnecessarily flaky; we work around it by
+   filtering the uninteresting output.
+
+ * Unused parameters to functions are marked as such, and/or removed,
+   in order to bring us closer to "-Wunused-parameter" clean.
+
+ * The code to keep track of existing packs in the repository while
+   repacking has been refactored.
+
+ * The "streaming" interface used for bulk-checkin codepath has been
+   narrowed to take only blob objects for now, with no real loss of
+   functionality.
+
+ * GitHub CI workflow has learned to trigger Coverity check.
+
+ * Test coverage for trailers has been improved.
+
+ * The code to iterate over loose references has been optimized to
+   reduce the number of lstat() system calls.
+
+ * The codepaths that read "chunk" formatted files have been corrected
+   to pay attention to the chunk size and notice broken files.
+
+ * Replace macos-12 used at GitHub CI with macos-13.
+   (merge 682a868f67 js/ci-use-macos-13 later to maint).
+
+
+Fixes since v2.42
+-----------------
+
+ * Overly long label names used in the sequencer machinery are now
+   chopped to fit under filesystem limitation.
+
+ * Scalar updates.
+
+ * Tweak GitHub Actions CI so that pushing the same commit to multiple
+   branch tips at the same time will not waste building and testing
+   the same thing twice.
+
+ * The commit-graph verification code that detects a mixture of zero and
+   non-zero generation numbers has been updated.
+
+ * "git diff -w --exit-code" with various options did not work
+   correctly, which has been corrected.
+
+ * The "transfer.unpackLimit" configuration variable ought to be used
+   as a fallback, but overrode the more specific "fetch.unpackLimit"
+   and "receive.unpackLimit" configuration variables by mistake, which
+   has been corrected.
+
+ * The use of API between two calls to require_clean_work_tree() from
+   the sequencer code has been cleaned up for consistency.
+
+ * "git diff --no-such-option" and other corner cases around the exit
+   status of the "diff" command have been corrected.
+
+ * "git for-each-ref --sort='contents:size'" sorted the refs according
+   to size numerically, giving a ref that points at a blob twelve-byte
+   (12) long before showing a blob hundred-byte (100) long, which has
+   been corrected.
+
+ * We now limit the depth of the tree objects and maximum length of
+   pathnames recorded in tree objects.
+   (merge 4d5693ba05 jk/tree-name-and-depth-limit later to maint).
+
+ * Various fixes to the behavior of "rebase -i", when the command got
+   interrupted by conflicting changes, have been made.
+
+ * References from a description of the `--patch` option in various
+   manual pages have been simplified and improved.
+
+ * "git grep -e A --no-or -e B" is accepted, even though the negation
+   of the "--or" option did not mean anything, which has been tightened.
+
+ * The completion script (in contrib/) has been taught to treat the
+   "-t" option to "git checkout" and "git switch" just like the
+   "--track" option, to complete remote-tracking branches.
+
+ * "git diff --no-index -R <(one) <(two)" did not work correctly,
+   which has been corrected.
+
+ * "git maintenance" timers' implementation has been updated, based on
+   systemd timers, to work with WSL.
+
+ * "git diff --cached" codepath did not fill the necessary stat
+   information for a file when fsmonitor knows it is clean and ended
+   up behaving as if it were not clean, which has been corrected.
+
+ * How "alias.foo = : git cmd ; aliased-command-string" should be
+   spelled with necessary whitespace around punctuation marks to work
+   has been more clearly documented (but this will be moot with newer
+   versions of Git where the parsing rules have been improved).
+
+ * HTTP Header redaction code has been adjusted for a newer version of
+   cURL library that shows its traces differently from earlier
+   versions.
+
+ * An error message given by "git send-email", when given a malformed
+   address, did not show the offending address, which has been corrected.
+
+ * UBSan options were not propagated through the test framework to git
+   run via the httpd, unlike ASan options, which has been corrected.
+
+ * "checkout --merge -- path" and "update-index --unresolve path" did
+   not resurrect conflicted state that was resolved to remove path,
+   but now they do.
+   (merge 5bdedac3c7 jc/unresolve-removal later to maint).
+
+ * The display width table for unicode characters has been updated for
+   Unicode 15.1
+   (merge 872976c37e bb/unicode-width-table-15 later to maint).
+
+ * Update mailmap entry for Derrick.
+   (merge 6e5457d8c7 ds/mailmap-entry-update later to maint).
+
+ * In the ".gitmodules" files, submodules are keyed by their names,
+   and the path to the submodule whose name is $name is specified by
+   the submodule.$name.path variable.  There were a few codepaths that
+   mixed the name and path up when consulting the submodule database,
+   which have been corrected.  It took long for these bugs to be found
+   as the name of a submodule initially is the same as its path, and
+   the problem does not surface until it is moved to a different path,
+   which apparently happens very rarely.
+
+ * "git diff --merge-base X other args..." insisted that X must be a
+   commit and errored out when given an annotated tag that peels to a
+   commit, but we only need it to be a committish.  This has been
+   corrected.
+   (merge 4adceb5a29 ar/diff-index-merge-base-fix later to maint).
+
+ * "git merge-tree" used to segfault when the "--attr-source"
+   option is used, which has been corrected.
+   (merge e95bafc52f jc/merge-ort-attr-index-fix later to maint).
+
+ * Unlike "git log --pretty=%D", "git log --pretty="%(decorate)" did
+   not auto-initialize the decoration subsystem, which has been
+   corrected.
+
+ * Feeding "git stash store" with a random commit that was not created
+   by "git stash create" now errors out.
+   (merge d9b6634589 jc/fail-stash-to-store-non-stash later to maint).
+
+ * The index file has room only for the lower 32-bit of the file size in
+   the cached stat information, which means cached stat information
+   will have 0 in its sd_size member for a file whose size is a multiple
+   of 4GiB.  This is mistaken for a racily clean path.  Avoid it by
+   storing a bogus sd_size value instead for such files.
+   (merge 5143ac07b1 bc/racy-4gb-files later to maint).
+
+ * "git p4" tried to store symlinks to LFS when told, but has been
+   fixed not to do so, because it does not make sense.
+   (merge 10c89a02b0 mm/p4-symlink-with-lfs later to maint).
+
+ * The codepath to handle recipient addresses `git send-email
+   --compose` learns from the user was completely broken, which has
+   been corrected.
+   (merge 3ec6167567 jk/send-email-fix-addresses-from-composed-messages later to maint).
+
+ * "cd sub && git grep -f patterns" tried to read "patterns" file at
+   the top level of the working tree; it has been corrected to read
+   "sub/patterns" instead.
+
+ * "git reflog expire --single-worktree" has been broken for the past
+   20 months or so, which has been corrected.
+
+ * "git send-email" did not have certain pieces of data computed yet
+   when it tried to validate the outgoing messages and its recipient
+   addresses, which has been sorted out.
+
+ * "git bugreport" learned to complain when it received a command line
+   argument that it will not use.
+
+ * The codepath to traverse the commit-graph learned to notice that a
+   commit is missing (e.g., corrupt repository lost an object), even
+   though it knows something about the commit (like its parents) from
+   what is in commit-graph.
+   (merge 7a5d604443 ps/do-not-trust-commit-graph-blindly-for-existence later to maint).
+
+ * "git rev-list --missing" did not work for missing commit objects,
+   which has been corrected.
+
+ * "git rev-list --unpacked --objects" failed to exclude packed
+   non-commit objects, which has been corrected.
+   (merge 7b3c8e9f38 tb/rev-list-unpacked-fix later to maint).
+
+ * "To dereference" and "to peel" were sometimes used in in-code
+   comments and documentation but without description in the glossary.
+   (merge 893dce2ffb vd/glossary-dereference-peel later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge c2c349a15c xz/commit-title-soft-limit-doc later to maint).
+   (merge 1bd809938a tb/format-pack-doc-update later to maint).
+   (merge 8f81532599 an/clang-format-typofix later to maint).
+   (merge 3ca86adc2d la/strvec-header-fix later to maint).
+   (merge 6789275d37 jc/test-i18ngrep later to maint).
+   (merge 9972cd6004 ps/leakfixes later to maint).
+   (merge 46edab516b tz/send-email-helpfix later to maint).
diff --git a/Documentation/RelNotes/2.43.1.txt b/Documentation/RelNotes/2.43.1.txt
new file mode 100644
index 0000000000..20e96f2dfa
--- /dev/null
+++ b/Documentation/RelNotes/2.43.1.txt
@@ -0,0 +1,82 @@
+Git 2.43.1 Release Notes
+========================
+
+There is nothing exciting to see here.  Relative to Git 2.43, this
+release contains the fixes that have already been merged to the
+'master' branch of the development towards the next major release.
+
+Fixes since Git 2.43.0
+----------------------
+
+ * The way CI testing used "prove" could lead to running the test
+   suite twice needlessly, which has been corrected.
+
+ * Newer versions of Getopt::Long started giving warnings against our
+   (ab)use of it in "git send-email".  Bump the minimum version
+   requirement for Perl to 5.8.1 (from September 2002) to allow
+   simplifying our implementation.
+
+ * Earlier we stopped relying on commit-graph that (still) records
+   information about commits that are lost from the object store,
+   which has negative performance implications.  The default has been
+   flipped to disable this pessimization.
+
+ * Stale URLs have been updated to their current counterparts (or
+   archive.org) and HTTP links are replaced with working HTTPS links.
+
+ * trace2 streams used to record the URLs that potentially embed
+   authentication material, which has been corrected.
+
+ * The sample pre-commit hook that tries to catch introduction of new
+   paths that use potentially non-portable characters did not notice
+   an existing path getting renamed to such a problematic path, when
+   rename detection was enabled.
+
+ * The command line parser for the "log" family of commands was too
+   loose when parsing certain numbers, e.g., silently ignoring the
+   extra 'q' in "git log -n 1q" without complaining, which has been
+   tightened up.
+
+ * "git $cmd --end-of-options --rev -- --path" for some $cmd failed
+   to interpret "--rev" as a rev, and "--path" as a path.  This was
+   fixed for many programs like "reset" and "checkout".
+
+ * "git bisect reset" has been taught to clean up state files and refs
+   even when BISECT_START file is gone.
+
+ * Some codepaths did not correctly parse configuration variables
+   specified with valueless "true", which has been corrected.
+
+ * Code clean-up for sanity checking of command line options for "git
+   show-ref".
+
+ * The code to parse the From e-mail header has been updated to avoid
+   recursion.
+
+ * "git fetch --atomic" issued an unnecessary empty error message,
+   which has been corrected.
+
+ * Command line completion script (in contrib/) learned to work better
+   with the reftable backend.
+
+ * "git status" is taught to show both the branch being bisected and
+   being rebased when both are in effect at the same time.
+   cf. <xmqqil76kyov.fsf@gitster.g>
+
+ * "git archive --list extra garbage" silently ignored excess command
+   line parameters, which has been corrected.
+
+ * "git sparse-checkout set" added default patterns even when the
+   patterns are being fed from the standard input, which has been
+   corrected.
+
+ * Unlike other environment variables that took the usual
+   true/false/yes/no as well as 0/1, GIT_FLUSH only understood 0/1,
+   which has been corrected.
+
+ * Clearing in-core repository (happens during e.g., "git fetch
+   --recurse-submodules" with commit graph enabled) made in-core
+   commit object in an inconsistent state by discarding the necessary
+   data from commit-graph too early, which has been corrected.
+
+Also contains various documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.43.2.txt b/Documentation/RelNotes/2.43.2.txt
new file mode 100644
index 0000000000..5895e23a54
--- /dev/null
+++ b/Documentation/RelNotes/2.43.2.txt
@@ -0,0 +1,37 @@
+Git 2.43.2 Release Notes
+========================
+
+Relative to Git 2.43.1, this release has two important fixes to allow
+"git imap-send" to be built with NO_CURL defined, and to restore the
+forced flushing behaviour when GIT_FLUSH=1 is set.  It also contains
+other, unexciting, fixes that have already been merged to the 'master'
+branch of the development towards the next major release.
+
+Fixes since Git 2.43.1
+----------------------
+
+ * Update to a new feature recently added, "git show-ref --exists".
+
+ * Rename detection logic ignored the final line of a file if it is an
+   incomplete line.
+
+ * "git diff --no-rename A B" did not disable rename detection but did
+   not trigger an error from the command line parser.
+
+ * "git diff --no-index file1 file2" segfaulted while invoking the
+   external diff driver, which has been corrected.
+
+ * Rewrite //-comments to /* comments */ in files whose comments
+   prevalently use the latter.
+
+ * A failed "git tag -s" did not necessarily result in an error
+   depending on the crypto backend, which has been corrected.
+
+ * "git stash" sometimes was silent even when it failed due to
+   unwritable index file, which has been corrected.
+
+ * Recent conversion to allow more than 0/1 in GIT_FLUSH broke the
+   mechanism by flipping what yes/no means by mistake, which has been
+   corrected.
+
+Also contains documentation updates, code clean-ups and minor fixups.
diff --git a/Documentation/RelNotes/2.43.3.txt b/Documentation/RelNotes/2.43.3.txt
new file mode 100644
index 0000000000..924f20594f
--- /dev/null
+++ b/Documentation/RelNotes/2.43.3.txt
@@ -0,0 +1,12 @@
+Git 2.43.3 Release Notes
+========================
+
+Relative to Git 2.43.2, this release fixes one regression that
+manifests while running "git commit -v --trailer".
+
+Fixes since Git 2.43.2
+----------------------
+
+ * "git commit -v --trailer=..." was broken with recent update and
+   placed the trailer _after_ the divider line, which has been
+   corrected.
diff --git a/Documentation/RelNotes/2.43.4.txt b/Documentation/RelNotes/2.43.4.txt
new file mode 100644
index 0000000000..0a842515ff
--- /dev/null
+++ b/Documentation/RelNotes/2.43.4.txt
@@ -0,0 +1,7 @@
+Git v2.43.4 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4, v2.40.2,
+v2.41.1 and v2.42.2 to address the security issues CVE-2024-32002,
+CVE-2024-32004, CVE-2024-32020, CVE-2024-32021 and CVE-2024-32465;
+see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.43.5.txt b/Documentation/RelNotes/2.43.5.txt
new file mode 100644
index 0000000000..236b234b06
--- /dev/null
+++ b/Documentation/RelNotes/2.43.5.txt
@@ -0,0 +1,26 @@
+Git v2.43.5 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.'  This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.43.4 and were not
+direct security fixes.
+
+Jeff King (5):
+      send-email: drop FakeTerm hack
+      send-email: avoid creating more than one Term::ReadLine object
+      ci: drop mention of BREW_INSTALL_PACKAGES variable
+      ci: avoid bare "gcc" for osx-gcc job
+      ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+      hook: plug a new memory leak
+      init: use the correct path of the templates directory again
+      Revert "core.hooksPath: add some protection while cloning"
+      tests: verify that `clone -c core.hooksPath=/dev/null` works again
+      clone: drop the protections where hooks aren't run
+      Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+      Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.43.6.txt b/Documentation/RelNotes/2.43.6.txt
new file mode 100644
index 0000000000..2114b9f78d
--- /dev/null
+++ b/Documentation/RelNotes/2.43.6.txt
@@ -0,0 +1,7 @@
+Git v2.43.6 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4, v2.41.3
+and v2.42.4 to address the security issues CVE-2024-50349 and
+CVE-2024-52006; see the release notes for these versions for
+details.
diff --git a/Documentation/RelNotes/2.44.0.txt b/Documentation/RelNotes/2.44.0.txt
new file mode 100644
index 0000000000..14f9ce8226
--- /dev/null
+++ b/Documentation/RelNotes/2.44.0.txt
@@ -0,0 +1,334 @@
+Git v2.44 Release Notes
+=======================
+
+Backward Compatibility Notes
+
+ * "git checkout -B <branch>" used to allow switching to a branch that
+   is in use on another worktree, but this was by mistake.  The users
+   need to use "--ignore-other-worktrees" option.
+
+
+UI, Workflows & Features
+
+ * "git add" and "git stash" learned to support the ":(attr:...)"
+   magic pathspec.
+
+ * "git rebase --autosquash" is now enabled for non-interactive rebase,
+   but it is still incompatible with the apply backend.
+
+ * Introduce "git replay", a tool meant on the server side without
+   working tree to recreate a history.
+
+ * "git merge-file" learned to take the "--diff-algorithm" option to
+   use algorithm different from the default "myers" diff.
+
+ * Command line completion (in contrib/) learned to complete path
+   arguments to the "add/set" subcommands of "git sparse-checkout"
+   better.
+
+ * "git checkout -B <branch> [<start-point>]" allowed a branch that is
+   in use in another worktree to be updated and checked out, which
+   might be a bit unexpected.  The rule has been tightened, which is a
+   breaking change.  "--ignore-other-worktrees" option is required to
+   unbreak you, if you are used to the current behaviour that "-B"
+   overrides the safety.
+
+ * The builtin_objectmode attribute is populated for each path
+   without adding anything in .gitattributes files, which would be
+   useful in magic pathspec, e.g., ":(attr:builtin_objectmode=100755)"
+   to limit to executables.
+
+ * "git fetch" learned to pay attention to "fetch.all" configuration
+   variable, which pretends as if "--all" was passed from the command
+   line when no remote parameter was given.
+
+ * In addition to (rather cryptic) Security Identifiers, show username
+   and domain in the error message when we barf on mismatch between
+   the Git directory and the current user on Windows.
+
+ * The error message given when "git branch -d branch" fails due to
+   commits unique to the branch has been split into an error and a new
+   conditional advice message.
+
+ * When given an existing but unreadable file as a configuration file,
+   gitweb behaved as if the file did not exist at all, but now it
+   errors out.  This is a change that may break backward compatibility.
+
+ * When $HOME/.gitconfig is missing but XDG config file is available, we
+   should write into the latter, not former.  "git gc" and "git
+   maintenance" wrote into a wrong "global config" file, which have
+   been corrected.
+
+ * Define "special ref" as a very narrow set that consists of
+   FETCH_HEAD and MERGE_HEAD, and clarify everything else that used to
+   be classified as such are actually just pseudorefs.
+
+ * All conditional "advice" messages show how to turn them off, which
+   becomes repetitive.  Setting advice.* configuration explicitly on
+   now omits the instruction part.
+
+ * The "disable repository discovery of a bare repository" check,
+   triggered by setting safe.bareRepository configuration variable to
+   'explicit', has been loosened to exclude the ".git/" directory inside
+   a non-bare repository from the check.  So you can do "cd .git &&
+   git cmd" to run a Git command that works on a bare repository without
+   explicitly specifying $GIT_DIR now.
+
+ * The completion script (in contrib/) learned more options that can
+   be used with "git log".
+
+ * The labels on conflict markers for the common ancestor, our version,
+   and the other version are available to custom 3-way merge driver
+   via %S, %X, and %Y placeholders.
+
+ * The write codepath for the reftable data learned to honor
+   core.fsync configuration.
+
+ * The "--fsck-objects" option of "git index-pack" now can take the
+   optional parameter to tweak severity of different fsck errors.
+
+ * The wincred credential backend has been taught to support oauth
+   refresh token the same way as credential-cache and
+   credential-libsecret backends.
+
+ * Command line completion support (in contrib/) has been
+   updated for "git bisect".
+
+ * "git branch" and friends learned to use the formatted text as
+   sorting key, not the underlying timestamp value, when the --sort
+   option is used with author or committer timestamp with a format
+   specifier (e.g., "--sort=creatordate:format:%H:%M:%S").
+
+ * The command line completion script (in contrib/) learned to
+   complete configuration variable names better.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Process to add some form of low-level unit tests has started.
+
+ * Add support for GitLab CI.
+
+ * "git for-each-ref --no-sort" still sorted the refs alphabetically
+   which paid non-trivial cost.  It has been redefined to show output
+   in an unspecified order, to allow certain optimizations to take
+   advantage of.
+
+ * Simplify API implementation to delete references by eliminating
+   duplication.
+
+ * Subject approxidate() and show_date() machinery to OSS-Fuzz.
+
+ * A new helper to let us pretend that we called lstat() when we know
+   our cache_entry is up-to-date via fsmonitor.
+
+ * The optimization based on fsmonitor in the "diff --cached"
+   codepath is resurrected with the "fake-lstat" introduced earlier.
+
+ * Test balloon to use C99 "bool" type from <stdbool.h> has been
+   added.
+
+ * "git clone" has been prepared to allow cloning a repository with
+   non-default hash function into a repository that uses the reftable
+   backend.
+
+ * Streaming spans of packfile data used to be done only from a
+   single, primary, pack in a repository with multiple packfiles.  It
+   has been extended to allow reuse from other packfiles, too.
+
+ * Comment updates to help developers not to attempt to modify
+   messages from plumbing commands that must stay constant.
+
+   It might make sense to reassess the plumbing needs every few years,
+   but that should be done as a separate effort.
+
+ * Move test-ctype helper to the unit-test framework.
+
+ * Instead of manually creating refs/ hierarchy on disk upon a
+   creation of a secondary worktree, which is only usable via the
+   files backend, use the refs API to populate it.
+
+ * CI for GitLab learned to drive macOS jobs.
+
+ * A few tests to "git commit -o <pathspec>" and "git commit -i
+   <pathspec>" has been added.
+
+ * Tests on ref API are moved around to prepare for reftable.
+
+ * The Makefile often had to say "-L$(path) -R$(path)" that repeats
+   the path to the same library directory for link time and runtime.
+   A Makefile template is used to reduce such repetition.
+
+ * The priority queue test has been migrated to the unit testing
+   framework.
+
+ * Setting `feature.experimental` opts the user into multi-pack reuse
+   experiment
+
+ * Squelch node.js 16 deprecation warnings from GitHub Actions CI
+   by updating actions/github-script and actions/checkout that use
+   node.js 20.
+
+ * The mechanism to report the filename in the source code, used by
+   the unit-test machinery, assumed that the compiler expanded __FILE__
+   to the path to the source given to the $(CC), but some compilers
+   give full path, breaking the output.  This has been corrected.
+
+
+Fixes since v2.43
+-----------------
+
+ * The way CI testing used "prove" could lead to running the test
+   suite twice needlessly, which has been corrected.
+
+ * Update ref-related tests.
+
+ * "git format-patch --encode-email-headers" ignored the option when
+   preparing the cover letter, which has been corrected.
+
+ * Newer versions of Getopt::Long started giving warnings against our
+   (ab)use of it in "git send-email".  Bump the minimum version
+   requirement for Perl to 5.8.1 (from September 2002) to allow
+   simplifying our implementation.
+
+ * Earlier we stopped relying on commit-graph that (still) records
+   information about commits that are lost from the object store,
+   which has negative performance implications.  The default has been
+   flipped to disable this pessimization.
+
+ * Stale URLs have been updated to their current counterparts (or
+   archive.org) and HTTP links are replaced with working HTTPS links.
+
+ * trace2 streams used to record the URLs that potentially embed
+   authentication material, which has been corrected.
+
+ * The sample pre-commit hook that tries to catch introduction of new
+   paths that use potentially non-portable characters did not notice
+   an existing path getting renamed to such a problematic path, when
+   rename detection was enabled.
+
+ * The command line parser for the "log" family of commands was too
+   loose when parsing certain numbers, e.g., silently ignoring the
+   extra 'q' in "git log -n 1q" without complaining, which has been
+   tightened up.
+
+ * "git $cmd --end-of-options --rev -- --path" for some $cmd failed
+   to interpret "--rev" as a rev, and "--path" as a path.  This was
+   fixed for many programs like "reset" and "checkout".
+
+ * "git bisect reset" has been taught to clean up state files and refs
+   even when BISECT_START file is gone.
+
+ * Some codepaths did not correctly parse configuration variables
+   specified with valueless "true", which has been corrected.
+
+ * Code clean-up for sanity checking of command line options for "git
+   show-ref".
+
+ * The code to parse the From e-mail header has been updated to avoid
+   recursion.
+
+ * "git fetch --atomic" issued an unnecessary empty error message,
+   which has been corrected.
+
+ * Command line completion script (in contrib/) learned to work better
+   with the reftable backend.
+
+ * "git status" is taught to show both the branch being bisected and
+   being rebased when both are in effect at the same time.
+
+ * "git archive --list extra garbage" silently ignored excess command
+   line parameters, which has been corrected.
+
+ * "git sparse-checkout set" added default patterns even when the
+   patterns are being fed from the standard input, which has been
+   corrected.
+
+ * "git sparse-checkout (add|set) --[no-]cone --end-of-options" did
+   not handle "--end-of-options" correctly after a recent update.
+
+ * Unlike other environment variables that took the usual
+   true/false/yes/no as well as 0/1, GIT_FLUSH only understood 0/1,
+   which has been corrected.
+
+ * Clearing in-core repository (happens during e.g., "git fetch
+   --recurse-submodules" with commit graph enabled) made in-core
+   commit object in an inconsistent state by discarding the necessary
+   data from commit-graph too early, which has been corrected.
+
+ * Update to a new feature recently added, "git show-ref --exists".
+
+ * oss-fuzz tests are built and run in CI.
+   (merge c4a9cf1df3 js/oss-fuzz-build-in-ci later to maint).
+
+ * Rename detection logic ignored the final line of a file if it is an
+   incomplete line.
+
+ * GitHub CI update.
+   (merge 0188b2c8e0 pb/ci-github-skip-logs-for-broken-tests later to maint).
+
+ * "git diff --no-rename A B" did not disable rename detection but did
+   not trigger an error from the command line parser.
+
+ * "git archive --remote=<remote>" learned to talk over the smart
+   http (aka stateless) transport.
+   (merge 176cd68634 jx/remote-archive-over-smart-http later to maint).
+
+ * Fetching via protocol v0 over Smart HTTP transport sometimes failed
+   to correctly auto-follow tags.
+   (merge fba732c462 jk/fetch-auto-tag-following-fix later to maint).
+
+ * The documentation for the --exclude-per-directory option marked it
+   as deprecated, which confused readers into thinking there may be a
+   plan to remove it in the future, which was not our intention.
+   (merge 0009542cab jc/ls-files-doc-update later to maint).
+
+ * "git diff --no-index file1 file2" segfaulted while invoking the
+   external diff driver, which has been corrected.
+
+ * Rewrite //-comments to /* comments */ in files whose comments
+   prevalently use the latter.
+
+ * Cirrus CI jobs started breaking because we specified version of
+   FreeBSD that is no longer available, which has been corrected.
+   (merge 81fffb66d3 cb/use-freebsd-13-2-at-cirrus-ci later to maint).
+
+ * A caller called index_file_exists() that takes a string expressed
+   as <ptr, length> with a wrong length, which has been corrected.
+   (merge 156e28b36d jh/sparse-index-expand-to-path-fix later to maint).
+
+ * A failed "git tag -s" did not necessarily result in an error
+   depending on the crypto backend, which has been corrected.
+
+ * "git stash" sometimes was silent even when it failed due to
+   unwritable index file, which has been corrected.
+
+ * "git show-ref --verify" did not show things like "CHERRY_PICK_HEAD",
+   which has been corrected.
+
+ * Recent conversion to allow more than 0/1 in GIT_FLUSH broke the
+   mechanism by flipping what yes/no means by mistake, which has been
+   corrected.
+
+ * The sequencer machinery does not use the ref API and instead
+   records names of certain objects it needs for its correct operation
+   in temporary files, which makes these objects susceptible to loss
+   by garbage collection.  These temporary files have been added as
+   starting points for reachability analysis to fix this.
+   (merge bc7f5db896 pw/gc-during-rebase later to maint).
+
+ * "git cherry-pick" invoked during "git rebase -i" session lost
+   the authorship information, which has been corrected.
+   (merge e4301f73ff vn/rebase-with-cherry-pick-authorship later to maint).
+
+ * The code paths that call repo_read_object_file() have been
+   tightened to react to errors.
+   (merge 568459bf5e js/check-null-from-read-object-file later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 5aea3955bc rj/clarify-branch-doc-m later to maint).
+   (merge 9cce3be2df bk/bisect-doc-fix later to maint).
+   (merge 8430b438f6 vd/fsck-submodule-url-test later to maint).
+   (merge 3cb4384683 jc/t0091-with-unknown-git later to maint).
+   (merge 020456cb74 rs/receive-pack-remove-find-header later to maint).
+   (merge bc47139f4f la/trailer-cleanups later to maint).
diff --git a/Documentation/RelNotes/2.44.1.txt b/Documentation/RelNotes/2.44.1.txt
new file mode 100644
index 0000000000..b5135c3281
--- /dev/null
+++ b/Documentation/RelNotes/2.44.1.txt
@@ -0,0 +1,8 @@
+Git v2.44.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4, v2.40.2,
+v2.41.1, v2.42.2 and v2.43.4 to address the security issues
+CVE-2024-32002, CVE-2024-32004, CVE-2024-32020, CVE-2024-32021
+and CVE-2024-32465; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.44.2.txt b/Documentation/RelNotes/2.44.2.txt
new file mode 100644
index 0000000000..76700f0b73
--- /dev/null
+++ b/Documentation/RelNotes/2.44.2.txt
@@ -0,0 +1,26 @@
+Git v2.44.2 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.'  This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.44.1 and were not
+direct security fixes.
+
+Jeff King (5):
+      send-email: drop FakeTerm hack
+      send-email: avoid creating more than one Term::ReadLine object
+      ci: drop mention of BREW_INSTALL_PACKAGES variable
+      ci: avoid bare "gcc" for osx-gcc job
+      ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+      hook: plug a new memory leak
+      init: use the correct path of the templates directory again
+      Revert "core.hooksPath: add some protection while cloning"
+      tests: verify that `clone -c core.hooksPath=/dev/null` works again
+      clone: drop the protections where hooks aren't run
+      Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+      Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.44.3.txt b/Documentation/RelNotes/2.44.3.txt
new file mode 100644
index 0000000000..5862845458
--- /dev/null
+++ b/Documentation/RelNotes/2.44.3.txt
@@ -0,0 +1,7 @@
+Git v2.44.3 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4, v2.41.3,
+v2.42.4 and v2.43.6 to address the security issues CVE-2024-50349
+and CVE-2024-52006; see the release notes for these versions
+for details.
diff --git a/Documentation/RelNotes/2.45.0.txt b/Documentation/RelNotes/2.45.0.txt
new file mode 100644
index 0000000000..aa0315259b
--- /dev/null
+++ b/Documentation/RelNotes/2.45.0.txt
@@ -0,0 +1,476 @@
+Git v2.45 Release Notes
+=======================
+
+Backward Compatibility Notes
+
+UI, Workflows & Features
+
+ * Integrate the reftable code into the refs framework as a backend.
+   With "git init --ref-format=reftable", hopefully it would be a lot
+   more efficient to manage a repository with many references.
+
+ * "git checkout -p" and friends learned that "@" is a synonym
+   for "HEAD".
+
+ * Variants of vimdiff learned to honor mergetool.<variant>.layout
+   settings.
+
+ * "git reflog" learned a "list" subcommand that enumerates known reflogs.
+
+ * When a merge conflicted at a submodule, merge-ort backend used to
+   unconditionally give a lengthy message to suggest how to resolve
+   it.  Now the message can be squelched as an advice message.
+
+ * "git for-each-ref" learned "--include-root-refs" option to show
+   even the stuff outside the 'refs/' hierarchy.
+
+ * "git rev-list --missing=print" has learned to optionally take
+   "--allow-missing-tips", which allows the objects at the starting
+   points to be missing.
+
+ * "git merge-tree" has learned that the three trees involved in the
+   3-way merge only need to be trees, not necessarily commits.
+
+ * "git log --merge" learned to pay attention to CHERRY_PICK_HEAD and
+   other kinds of *_HEAD pseudorefs.
+
+ * Platform specific tweaks for OS/390 has been added to
+   config.mak.uname.
+
+ * Users with safe.bareRepository=explicit can still work from within
+   $GIT_DIR of a seconary worktree (which resides at .git/worktrees/$name/)
+   of the primary worktree without explicitly specifying the $GIT_DIR
+   environment variable or the --git-dir=<path> option.
+
+ * The output format for dates "iso-strict" has been tweaked to show
+   a time in the Zulu timezone with "Z" suffix, instead of "+00:00".
+
+ * "git diff" and friends learned two extra configuration variables,
+   diff.srcPrefix and diff.dstPrefix.
+
+ * The status.showUntrackedFiles configuration variable had a name
+   that tempts users to set a Boolean value expressed in our usual
+   "false", "off", and "0", but it only took "no".  This has been
+   corrected so "true" and its synonyms are taken as "normal", while
+   "false" and its synonyms are taken as "no".
+
+ * Remove an ancient and not well maintained Hg-to-git migration
+   script from contrib/.
+
+ * Hints that suggest what to do after resolving conflicts can now be
+   squelched by disabling advice.mergeConflict.
+
+ * Allow git-cherry-pick(1) to automatically drop redundant commits via
+   a new `--empty` option, similar to the `--empty` options for
+   git-rebase(1) and git-am(1). Includes a soft deprecation of
+   `--keep-redundant-commits` as well as some related docs changes and
+   sequencer code cleanup.
+
+ * "git config" learned "--comment=<message>" option to leave a
+   comment immediately after the "variable = value" on the same line
+   in the configuration file.
+
+ * core.commentChar used to be limited to a single byte, but has been
+   updated to allow an arbitrary multi-byte sequence.
+
+ * "git add -p" and other "interactive hunk selection" UI has learned to
+   skip showing the hunk immediately after it has already been shown, and
+   an additional action to explicitly ask to reshow the current hunk.
+
+ * "git pack-refs" learned the "--auto" option, which defers the decision of
+   whether and how to pack to the ref backend. This is used by the reftable
+   backend to avoid repacking of an already-optimal ref database. The new mode
+   is triggered from "git gc --auto".
+
+ * "git add -u <pathspec>" and "git commit [-i] <pathspec>" did not
+   diagnose a pathspec element that did not match any files in certain
+   situations, unlike "git add <pathspec>" did.
+
+ * The userdiff patterns for C# has been updated.
+
+ * Git writes a "waiting for your editor" message on an incomplete
+   line after launching an editor, and then append another error
+   message on the same line if the editor errors out.  It now clears
+   the "waiting for..." line before giving the error message.
+
+ * The filename used for rejected hunks "git apply --reject" creates
+   was limited to PATH_MAX, which has been lifted.
+
+ * When "git bisect" reports the commit it determined to be the
+   culprit, we used to show it in a format that does not honor common
+   UI tweaks, like log.date and log.decorate.  The code has been
+   taught to use "git show" to follow more customizations.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The code to iterate over refs with the reftable backend has seen
+   some optimization.
+
+ * More tests that are marked as "ref-files only" have been updated to
+   improve test coverage of reftable backend.
+
+ * Some parts of command line completion script (in contrib/) have
+   been micro-optimized.
+
+ * The way placeholders are to be marked-up in documentation have been
+   specified; use "_<placeholder>_" to typeset the word inside a pair
+   of <angle-brackets> emphasized.
+
+ * "git --no-lazy-fetch cmd" allows to run "cmd" while disabling lazy
+   fetching of objects from the promisor remote, which may be handy
+   for debugging.
+
+ * The implementation in "git clean" that makes "-n" and "-i" ignore
+   clean.requireForce has been simplified, together with the
+   documentation.
+
+ * Uses of xwrite() helper have been audited and updated for better
+   error checking and simpler code.
+
+ * Some trace2 events that lacked def_param have learned to show it,
+   enriching the output.
+
+ * The parse-options code that deals with abbreviated long option
+   names have been cleaned up.
+
+ * The code in reftable backend that creates new table files works
+   better with the tempfile framework to avoid leaving cruft after a
+   failure.
+
+ * The reftable code has its own custom binary search function whose
+   comparison callback has an unusual interface, which caused the
+   binary search to degenerate into a linear search, which has been
+   corrected.
+
+ * The code to iterate over reflogs in the reftable has been optimized
+   to reduce memory allocation and deallocation.
+
+ * Work to support a repository that work with both SHA-1 and SHA-256
+   hash algorithms has started.
+
+ * A new fuzz target that exercises config parsing code has been
+   added.
+
+ * Fix the way recently added tests interpolate variables defined
+   outside them, and document the best practice to help future
+   developers.
+
+ * Introduce an experimental protocol for contributors to propose the
+   topic description to be used in the "What's cooking" report, the
+   merge commit message for the topic, and in the release notes and
+   document it in the SubmittingPatches document.
+
+ * The t/README file now gives a hint on running individual tests in
+   the "t/" directory with "make t<num>-*.sh t<num>-*.sh".
+   (merge 8d383806fc pb/test-scripts-are-build-targets later to maint).
+
+ * The "hint:" messages given by the advice mechanism, when given a
+   message with a blank line, left a line with trailing whitespace,
+   which has been cleansed.
+
+ * Documentation rules has been explicitly described how to mark-up
+   literal parts and a few manual pages have been updated as examples.
+
+ * The .editorconfig file has been taught that a Makefile uses HT
+   indentation.
+
+ * t-prio-queue test has been cleaned up by using C99 compound
+   literals; this is meant to also serve as a weather-balloon to smoke
+   out folks with compilers who have trouble compiling code that uses
+   the feature.
+
+ * Windows binary used to decide the use of unix-domain socket at
+   build time, but it learned to make the decision at runtime instead.
+
+ * The "shared repository" test in the t0610 reftable test failed
+   under restrictive umask setting (e.g. 007), which has been
+   corrected.
+
+ * Document and apply workaround for a buggy version of dash that
+   mishandles "local var=val" construct.
+
+ * The codepaths that reach date_mode_from_type() have been updated to
+   pass "struct date_mode" by value to make them thread safe.
+
+ * The strategy to compact multiple tables of reftables after many
+   operations accumulate many entries has been improved to avoid
+   accumulating too many tables uncollected.
+
+ * The code to iterate over reftable blocks has seen some optimization
+   to reduce memory allocation and deallocation.
+
+ * The way "git fast-import" handles paths described in its input has
+   been tightened up and more clearly documented.
+
+ * The cvsimport tests required that the platform understands
+   traditional timezone notations like CST6CDT, which has been
+   updated to work on those systems as long as they understand
+   POSIX notation with explicit tz transition dates.
+
+ * The code to format trailers have been cleaned up.
+
+
+Fixes since v2.44
+-----------------
+
+ * "git apply" on a filesystem without filemode support have learned
+   to take a hint from what is in the index for the path, even when
+   not working with the "--index" or "--cached" option, when checking
+   the executable bit match what is required by the preimage in the
+   patch.
+   (merge 45b625142d cp/apply-core-filemode later to maint).
+
+ * "git column" has been taught to reject negative padding value, as
+   it would lead to nonsense behaviour including division by zero.
+   (merge 76fb807faa kh/column-reject-negative-padding later to maint).
+
+ * "git am --help" now tells readers what actions are available in
+   "git am --whitespace=<action>", in addition to saying that the
+   option is passed through to the underlying "git apply".
+   (merge a171dac734 jc/am-whitespace-doc later to maint).
+
+ * "git tag --column" failed to check the exit status of its "git
+   column" invocation, which has been corrected.
+   (merge 92e66478fc rj/tag-column-fix later to maint).
+
+ * Credential helper based on libsecret (in contrib/) has been updated
+   to handle an empty password correctly.
+   (merge 8f1f2023b7 mh/libsecret-empty-password-fix later to maint).
+
+ * "git difftool --dir-diff" learned to honor the "--trust-exit-code"
+   option; it used to always exit with 0 and signalled success.
+   (merge eb84c8b6ce ps/difftool-dir-diff-exit-code later to maint).
+
+ * The code incorrectly attempted to use textconv cache when asked,
+   even when we are not running in a repository, which has been
+   corrected.
+   (merge affe355fe7 jk/textconv-cache-outside-repo-fix later to maint).
+
+ * Remove an empty file that shouldn't have been added in the first
+   place.
+   (merge 4f66942215 js/remove-cruft-files later to maint).
+
+ * The logic to access reflog entries by date and number had ugly
+   corner cases at the boundaries, which have been cleaned up.
+   (merge 5edd126720 jk/reflog-special-cases-fix later to maint).
+
+ * An error message from "git upload-pack", which responds to "git
+   fetch" requests, had a trailing NUL in it, which has been
+   corrected.
+   (merge 3f4c7a0805 sg/upload-pack-error-message-fix later to maint).
+
+ * Clarify wording in the CodingGuidelines that requires <git-compat-util.h>
+   to be the first header file.
+   (merge 4e89f0e07c jc/doc-compat-util later to maint).
+
+ * "git commit -v --cleanup=scissors" used to add the scissors line
+   twice in the log message buffer, which has been corrected.
+   (merge e90cc075cc jt/commit-redundant-scissors-fix later to maint).
+
+ * A custom remote helper no longer cannot access the newly created
+   repository during "git clone", which is a regression in Git 2.44.
+   This has been corrected.
+   (merge 199f44cb2e ps/remote-helper-repo-initialization-fix later to maint).
+
+ * Various parts of upload-pack have been updated to bound the resource
+   consumption relative to the size of the repository to protect from
+   abusive clients.
+   (merge 6cd05e768b jk/upload-pack-bounded-resources later to maint).
+
+ * The upload-pack program, when talking over v2, accepted the
+   packfile-uris protocol extension from the client, even if it did
+   not advertise the capability, which has been corrected.
+   (merge a922bfa3b5 jk/upload-pack-v2-capability-cleanup later to maint).
+
+ * Make sure failure return from merge_bases_many() is properly caught.
+   (merge 25fd20eb44 js/merge-base-with-missing-commit later to maint).
+
+ * FSMonitor client code was confused when FSEvents were given in a
+   different case on a case-insensitive filesystem, which has been
+   corrected.
+   (merge 29c139ce78 jh/fsmonitor-icase-corner-case-fix later to maint).
+
+ * The "core.commentChar" configuration variable only allows an ASCII
+   character, which was not clearly documented, which has been
+   corrected.
+   (merge fb7c556f58 kh/doc-commentchar-is-a-byte later to maint).
+
+ * With release 2.44 we got rid of all uses of test_i18ngrep and there
+   is no in-flight topic that adds a new use of it.  Make a call to
+   test_i18ngrep a hard failure, so that we can remove it at the end
+   of this release cycle.
+   (merge 381a83dfa3 jc/test-i18ngrep later to maint).
+
+ * The command line completion script (in contrib/) learned to
+   complete "git reflog" better.
+   (merge 1284f9cc11 rj/complete-reflog later to maint).
+
+ * The logic to complete the command line arguments to "git worktree"
+   subcommand (in contrib/) has been updated to correctly honor things
+   like "git -C dir" etc.
+   (merge 3574816d98 rj/complete-worktree-paths-fix later to maint).
+
+ * When git refuses to create a branch because the proposed branch
+   name is not a valid refname, an advice message is given to refer
+   the user to exact naming rules.
+   (merge 8fbd903e58 kh/branch-ref-syntax-advice later to maint).
+
+ * Code simplification by getting rid of code that sets an environment
+   variable that is no longer used.
+   (merge 72a8d3f027 pw/rebase-i-ignore-cherry-pick-help-environment later to maint).
+
+ * The code to find the effective end of log messages can fall into an
+   endless loop, which has been corrected.
+   (merge 2541cba2d6 fs/find-end-of-log-message-fix later to maint).
+
+ * Mark-up used in the documentation has been improved for
+   consistency.
+   (merge 45d5ed3e50 ja/doc-markup-fixes later to maint).
+
+ * The status.showUntrackedFiles configuration variable was
+   incorrectly documented to accept "false", which has been corrected.
+
+ * Leaks from "git restore" have been plugged.
+   (merge 2f64da0790 rj/restore-plug-leaks later to maint).
+
+ * "git bugreport --no-suffix" was not supported and instead
+   segfaulted, which has been corrected.
+   (merge b3b57c69da js/bugreport-no-suffix-fix later to maint).
+
+ * The documentation for "%(trailers[:options])" placeholder in the
+   "--pretty" option of commands in the "git log" family has been
+   updated.
+   (merge bff85a338c bl/doc-key-val-sep-fix later to maint).
+
+ * "git checkout --conflict=bad" reported a bad conflictStyle as if it
+   were given to a configuration variable; it has been corrected to
+   report that the command line option is bad.
+   (merge 5a99c1ac1a pw/checkout-conflict-errorfix later to maint).
+
+ * Code clean-up in the "git log" machinery that implements custom log
+   message formatting.
+   (merge 1c10b8e5b0 jk/pretty-subject-cleanup later to maint).
+
+ * "git config" corrupted literal HT characters written in the
+   configuration file as part of a value, which has been corrected.
+   (merge e6895c3f97 ds/config-internal-whitespace-fix later to maint).
+
+ * A unit test for reftable code tried to enumerate all files in a
+   directory after reftable operations and expected to see nothing but
+   the files it wanted to leave there, but was fooled by .nfs* cruft
+   files left, which has been corrected.
+   (merge 0068aa7946 ps/reftable-unit-test-nfs-workaround later to maint).
+
+ * The implementation and documentation of "object-format" option
+   exchange between the Git itself and its remote helpers did not
+   quite match, which has been corrected.
+
+ * The "--pretty=<shortHand>" option of the commands in the "git log"
+   family, defined as "[pretty] shortHand = <expansion>" should have
+   been looked up case insensitively, but was not, which has been
+   corrected.
+   (merge f999d5188b bl/pretty-shorthand-config-fix later to maint).
+
+ * "git apply" failed to extract the filename the patch applied to,
+   when the change was about an empty file created in or deleted from
+   a directory whose name ends with a SP, which has been corrected.
+   (merge 776ffd1a30 jc/apply-parse-diff-git-header-names-fix later to maint).
+
+ * Update a more recent tutorial doc.
+   (merge 95ab557b4b dg/myfirstobjectwalk-updates later to maint).
+
+ * The test script had an incomplete and ineffective attempt to avoid
+   clobbering the testing user's real crontab (and its equivalents),
+   which has been completed.
+   (merge 73cb87773b es/test-cron-safety later to maint).
+
+ * Use advice_if_enabled() API to rewrite a simple pattern to
+   call advise() after checking advice_enabled().
+   (merge 6412d01527 rj/use-adv-if-enabled later to maint).
+
+ * Another "set -u" fix for the bash prompt (in contrib/) script.
+   (merge d7805bc743 vs/complete-with-set-u-fix later to maint).
+
+ * "git checkout/switch --detach foo", after switching to the detached
+   HEAD state, gave the tracking information for the 'foo' branch,
+   which was pointless.
+
+ * "git apply" has been updated to lift the hardcoded pathname length
+   limit, which in turn allowed a mksnpath() function that is no
+   longer used.
+   (merge 708f7e0590 rs/apply-lift-path-length-limit later to maint).
+
+ * A file descriptor leak in an error codepath, used when "git apply
+   --reject" fails to create the *.rej file, has been corrected.
+   (merge 2b1f456adf rs/apply-reject-fd-leakfix later to maint).
+
+ * A config parser callback function fell through instead of returning
+   after recognising and processing a variable, wasting cycles, which
+   has been corrected.
+   (merge a816ccd642 ds/fetch-config-parse-microfix later to maint).
+
+ * Fix was added to work around a regression in libcURL 8.7.0 (which has
+   already been fixed in their tip of the tree).
+   (merge 92a209bf24 jk/libcurl-8.7-regression-workaround later to maint).
+
+ * The variable that holds the value read from the core.excludefile
+   configuration variable used to leak, which has been corrected.
+   (merge 0e0fefb29f jc/unleak-core-excludesfile later to maint).
+
+ * vreportf(), which is used by error() and friends, has been taught
+   to give the error message printf-format string when its vsnprintf()
+   call fails, instead of showing nothing useful to identify the
+   nature of the error.
+   (merge c63adab961 rs/usage-fallback-to-show-message-format later to maint).
+
+ * Adjust to an upcoming changes to GNU make that breaks our Makefiles.
+   (merge 227b8fd902 tb/make-indent-conditional-with-non-spaces later to maint).
+
+ * Git 2.44 introduced a regression that makes the updated code to
+   barf in repositories with multi-pack index written by older
+   versions of Git, which has been corrected.
+
+ * When .git/rr-cache/ rerere database gets corrupted or rerere is fed to
+   work on a file with conflicted hunks resolved incompletely, the rerere
+   machinery got confused and segfaulted, which has been corrected.
+   (merge 167395bb47 mr/rerere-crash-fix later to maint).
+
+ * The "receive-pack" program (which responds to "git push") was not
+   converted to run "git maintenance --auto" when other codepaths that
+   used to run "git gc --auto" were updated, which has been corrected.
+   (merge 7bf3057d9c ps/run-auto-maintenance-in-receive-pack later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge f0e578c69c rs/use-xstrncmpz later to maint).
+   (merge 83e6eb7d7a ba/credential-test-clean-fix later to maint).
+   (merge 64562d784d jb/doc-interactive-singlekey-do-not-need-perl later to maint).
+   (merge c431a235e2 cp/t9146-use-test-path-helpers later to maint).
+   (merge 82d75402d5 ds/doc-send-email-capitalization later to maint).
+   (merge 41bff66e35 jc/doc-add-placeholder-fix later to maint).
+   (merge 6835f0efe9 jw/remote-doc-typofix later to maint).
+   (merge 244001aa20 hs/rebase-not-in-progress later to maint).
+   (merge 2ca6c07db2 jc/no-include-of-compat-util-from-headers later to maint).
+   (merge 87bd7fbb9c rs/fetch-simplify-with-starts-with later to maint).
+   (merge f39addd0d9 rs/name-rev-with-mempool later to maint).
+   (merge 9a97b43e03 rs/submodule-prefix-simplify later to maint).
+   (merge 40b8076462 ak/rebase-autosquash later to maint).
+   (merge 3223204456 eg/add-uflags later to maint).
+   (merge 5f78d52dce es/config-doc-sort-sections later to maint).
+   (merge 781fb7b4c2 as/option-names-in-messages later to maint).
+   (merge 51d41dc243 jk/doc-remote-helpers-markup-fix later to maint).
+   (merge e1aaf309db pb/ci-win-artifact-names-fix later to maint).
+   (merge ad538c61da jc/index-pack-fsck-levels later to maint).
+   (merge 67471bc704 ja/doc-formatting-fix later to maint).
+   (merge 86f9ce7dd6 bl/doc-config-fixes later to maint).
+   (merge 0d527842b7 az/grep-group-error-message-update later to maint).
+   (merge 7c43bdf07b rs/strbuf-expand-bad-format later to maint).
+   (merge 8b68b48d5c ds/typofix-core-config-doc later to maint).
+   (merge 39bb692152 rs/imap-send-use-xsnprintf later to maint).
+   (merge 8d320cec60 jc/t2104-style-fixes later to maint).
+   (merge b4454d5a7b pw/t3428-cleanup later to maint).
+   (merge 84a7c33a4b pf/commitish-committish later to maint).
+   (merge 8882ee9d68 la/mailmap-entry later to maint).
+   (merge 44bdba2fa6 rs/no-openssl-compilation-fix-on-macos later to maint).
+   (merge f412d72c19 yb/replay-doc-linkfix later to maint).
+   (merge 5da40be8d7 xx/rfc2822-date-format-in-doc later to maint).
diff --git a/Documentation/RelNotes/2.45.1.txt b/Documentation/RelNotes/2.45.1.txt
new file mode 100644
index 0000000000..3b0d60cfa3
--- /dev/null
+++ b/Documentation/RelNotes/2.45.1.txt
@@ -0,0 +1,8 @@
+Git v2.45.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.39.4,
+v2.40.2, v2.41.1, v2.42.2, v2.43.4 and v2.44.1 to address the
+security issues CVE-2024-32002, CVE-2024-32004, CVE-2024-32020,
+CVE-2024-32021 and CVE-2024-32465; see the release notes for
+these versions for details.
diff --git a/Documentation/RelNotes/2.45.2.txt b/Documentation/RelNotes/2.45.2.txt
new file mode 100644
index 0000000000..13429e6491
--- /dev/null
+++ b/Documentation/RelNotes/2.45.2.txt
@@ -0,0 +1,26 @@
+Git v2.45.2 Release Notes
+=========================
+
+In preparing security fixes for four CVEs, we made overly aggressive
+"defense in depth" changes that broke legitimate use cases like 'git
+lfs' and 'git annex.'  This release is to revert these misguided, if
+well-intentioned, changes that were shipped in 2.45.1 and were not
+direct security fixes.
+
+Jeff King (5):
+      send-email: drop FakeTerm hack
+      send-email: avoid creating more than one Term::ReadLine object
+      ci: drop mention of BREW_INSTALL_PACKAGES variable
+      ci: avoid bare "gcc" for osx-gcc job
+      ci: stop installing "gcc-13" for osx-gcc
+
+Johannes Schindelin (6):
+      hook: plug a new memory leak
+      init: use the correct path of the templates directory again
+      Revert "core.hooksPath: add some protection while cloning"
+      tests: verify that `clone -c core.hooksPath=/dev/null` works again
+      clone: drop the protections where hooks aren't run
+      Revert "Add a helper function to compare file contents"
+
+Junio C Hamano (1):
+      Revert "fsck: warn about symlink pointing inside a gitdir"
diff --git a/Documentation/RelNotes/2.45.3.txt b/Documentation/RelNotes/2.45.3.txt
new file mode 100644
index 0000000000..ddb3cb694b
--- /dev/null
+++ b/Documentation/RelNotes/2.45.3.txt
@@ -0,0 +1,112 @@
+Git v2.45.3 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4, v2.41.3,
+v2.42.4, v2.43.6 and v2.44.3 to address the security issues
+CVE-2024-50349 and CVE-2024-52006; see the release notes for
+these versions for details.
+
+This version also backports various small fixes accumulated on the
+'master' front during the development towards Git 2.46, the next
+feature release.
+
+
+Fixes since v2.45.2
+-------------------
+
+ * Git-GUI has a new maintainer, Johannes Sixt.
+
+ * Tests that try to corrupt in-repository files in chunked format did
+   not work well on macOS due to its broken "mv", which has been
+   worked around.
+
+ * The maximum size of attribute files is enforced more consistently.
+
+ * Unbreak CI jobs so that we do not attempt to use Python 2 that has
+   been removed from the platform.
+
+ * Git 2.43 started using the tree of HEAD as the source of attributes
+   in a bare repository, which has severe performance implications.
+   For now, revert the change, without ripping out a more explicit
+   support for the attr.tree configuration variable.
+
+ * Windows CI running in GitHub Actions started complaining about the
+   order of arguments given to calloc(); the imported regex code uses
+   the wrong order almost consistently, which has been corrected.
+
+ * The SubmittingPatches document now refers folks to manpages
+   translation project.
+
+ * "git rebase --signoff" used to forget that it needs to add a
+   sign-off to the resulting commit when told to continue after a
+   conflict stops its operation.
+
+ * The procedure to build multi-pack-index got confused by the
+   replace-refs mechanism, which has been corrected by disabling the
+   latter.
+
+ * "git stash -S" did not handle binary files correctly, which has
+   been corrected.
+
+ * A scheduled "git maintenance" job is expected to work on all
+   repositories it knows about, but it stopped at the first one that
+   errored out.  Now it keeps going.
+
+ * zsh can pretend to be a normal shell pretty well except for some
+   glitches that we tickle in some of our scripts. Work them around
+   so that "vimdiff" and our test suite works well enough with it.
+
+ * Command line completion support for zsh (in contrib/) has been
+   updated to stop exposing internal state to end-user shell
+   interaction.
+
+ * The documentation for "git diff --name-only" has been clarified
+   that it is about showing the names in the post-image tree.
+
+ * The chainlint script (invoked during "make test") did nothing when
+   it failed to detect the number of available CPUs.  It now falls
+   back to 1 CPU to avoid the problem.
+
+ * "git init" in an already created directory, when the user
+   configuration has includeif.onbranch, started to fail recently,
+   which has been corrected.
+
+ * The safe.directory configuration knob has been updated to
+   optionally allow leading path matches.
+
+ * An overly large ".gitignore" files are now rejected silently.
+
+ * Fix for an embarrassing typo that prevented Python2 tests from running
+   anywhere.
+
+ * Varargs functions that are unannotated as printf-like or execl-like
+   have been annotated as such.
+
+ * The "-k" and "--rfc" options of "format-patch" will now error out
+   when used together, as one tells us not to add anything to the
+   title of the commit, and the other one tells us to add "RFC" in
+   addition to "PATCH".
+
+ * When the user adds to "git rebase -i" instruction to "pick" a merge
+   commit, the error experience is not pleasant.  Such an error is now
+   caught earlier in the process that parses the todo list.
+
+ * We forgot to normalize the result of getcwd() to NFC on macOS where
+   all other paths are normalized, which has been corrected.  This still
+   does not address the case where core.precomposeUnicode configuration
+   is not defined globally.
+
+ * Earlier we stopped using the tree of HEAD as the default source of
+   attributes in a bare repository, but failed to document it.  This
+   has been corrected.
+
+ * An unused extern declaration for mingw has been removed to prevent
+   it from causing build failure.
+
+ * A helper function shared between two tests had a copy-paste bug,
+   which has been corrected.
+
+ * "git fetch-pack -k -k" without passing "--lock-pack" (which we
+   never do ourselves) did not work at all, which has been corrected.
+
+Also contains various documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.46.0.txt b/Documentation/RelNotes/2.46.0.txt
new file mode 100644
index 0000000000..c06a04a91b
--- /dev/null
+++ b/Documentation/RelNotes/2.46.0.txt
@@ -0,0 +1,461 @@
+Git v2.46 Release Notes
+=======================
+
+UI, Workflows & Features
+
+ * The "--rfc" option of "git format-patch" learned to take an
+   optional string value to be used in place of "RFC" to tweak the
+   "[PATCH]" on the subject header.
+
+ * The credential helper protocol, together with the HTTP layer, have
+   been enhanced to support authentication schemes different from
+   username & password pair, like Bearer and NTLM.
+
+ * Command line completion script (in contrib/) learned to complete
+   "git symbolic-ref" a bit better (you need to enable plumbing
+   commands to be completed with GIT_COMPLETION_SHOW_ALL_COMMANDS).
+
+ * When the user responds to a prompt given by "git add -p" with an
+   unsupported command, list of available commands were given, which
+   was too much if the user knew what they wanted to type but merely
+   made a typo.  Now the user gets a much shorter error message.
+
+ * The color parsing code learned to handle 12-bit RGB colors, spelled
+   as "#RGB" (in addition to "#RRGGBB" that is already supported).
+
+ * The operation mode options (like "--get") the "git config" command
+   uses have been deprecated and replaced with subcommands (like "git
+   config get").
+
+ * "git tag" learned the "--trailer" option to futz with the trailers
+   in the same way as "git commit" does.
+
+ * A new global "--no-advice" option can be used to disable all advice
+   messages, which is meant to be used only in scripts.
+
+ * Updates to symbolic refs can now be made as a part of ref
+   transaction.
+
+ * The trailer API has been reshuffled a bit.
+
+ * Terminology to call various ref-like things are getting
+   straightened out.
+
+ * The command line completion script (in contrib/) has been adjusted
+   to the recent update to "git config" that adopted subcommand based
+   UI.
+
+ * The knobs to tweak how reftable files are written have been made
+   available as configuration variables.
+
+ * When "git push" notices that the commit at the tip of the ref on
+   the other side it is about to overwrite does not exist locally, it
+   used to first try fetching it if the local repository is a partial
+   clone. The command has been taught not to do so and immediately
+   fail instead.
+
+ * The promisor.quiet configuration knob can be set to true to make
+   lazy fetching from promisor remotes silent.
+
+ * The inter/range-diff output has been moved to the end of the patch
+   when format-patch adds it to a single patch, instead of writing it
+   before the patch text, to be consistent with what is done for a
+   cover letter for a multi-patch series.
+
+ * A new command has been added to migrate a repository that uses the
+   files backend for its ref storage to use the reftable backend, with
+   limitations.
+
+ * "git diff --exit-code --ext-diff" learned to take the exit status
+   of the external diff driver into account when deciding the exit
+   status of the overall "git diff" invocation when configured to do
+   so.
+
+ * "git update-ref --stdin" learned to handle transactional updates of
+   symbolic-refs.
+
+ * "git format-patch --interdiff" for multi-patch series learned to
+   turn on cover letters automatically (unless told never to enable
+   cover letter with "--no-cover-letter" and such).
+
+ * The "--heads" option of "ls-remote" and "show-ref" has been
+   deprecated; "--branches" replaces "--heads".
+
+ * For over a year, setting add.interactive.useBuiltin configuration
+   variable did nothing but giving a "this does not do anything"
+   warning.  The warning has been removed.
+
+ * The http transport can now be told to send request with
+   authentication material without first getting a 401 response.
+
+ * A handful of entries are added to the GitFAQ document.
+
+ * "git var GIT_SHELL_PATH" should report the path to the shell used
+   to spawn external commands, but it didn't do so on Windows, which
+   has been corrected.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Advertise "git contacts", a tool for newcomers to find people to
+   ask review for their patches, a bit more in our developer
+   documentation.
+
+ * In addition to building the objects needed, try to link the objects
+   that are used in fuzzer tests, to make sure at least they build
+   without bitrot, in Linux CI runs.
+
+ * Code to write out reftable has seen some optimization and
+   simplification.
+
+ * Tests to ensure interoperability between reftable written by jgit
+   and our code have been added and enabled in CI.
+
+ * The singleton index_state instance "the_index" has been eliminated
+   by always instantiating "the_repository" and replacing references
+   to "the_index"  with references to its .index member.
+
+ * Git-GUI has a new maintainer, Johannes Sixt.
+
+ * The "test-tool" has been taught to run testsuite tests in parallel,
+   bypassing the need to use the "prove" tool.
+
+ * The "whitespace check" task that was enabled for GitHub Actions CI
+   has been ported to GitLab CI.
+
+ * The refs API lost functions that implicitly assumes to work on the
+   primary ref_store by forcing the callers to pass a ref_store as an
+   argument.
+
+ * Code clean-up to reduce inter-function communication inside
+   builtin/config.c done via the use of global variables.
+
+ * The pack bitmap code saw some clean-up to prepare for a follow-up topic.
+
+ * Preliminary code clean-up for "git send-email".
+
+ * The default "creation-factor" used by "git format-patch" has been
+   raised to make it more aggressively find matching commits.
+
+ * Before discovering the repository details, We used to assume SHA-1
+   as the "default" hash function, which has been corrected. Hopefully
+   this will smoke out codepaths that rely on such an unwarranted
+   assumptions.
+
+ * The project decision making policy has been documented.
+
+ * The strcmp-offset tests have been rewritten using the unit test
+   framework.
+
+ * "git add -p" learned to complain when an answer with more than one
+   letter is given to a prompt that expects a single letter answer.
+
+ * The alias-expanded command lines are logged to the trace output.
+
+ * A new test was added to ensure git commands that are designed to
+   run outside repositories do work.
+
+ * A few tests in reftable library have been rewritten using the
+   unit test framework.
+
+ * A pair of test helpers that essentially are unit tests on hash
+   algorithms have been rewritten using the unit-tests framework.
+
+ * A test helper that essentially is unit tests on the "decorate"
+   logic has been rewritten using the unit-tests framework.
+
+ * Many memory leaks in the sparse-checkout code paths have been
+   plugged.
+
+ * "make check-docs" noticed problems and reported to its output but
+   failed to signal its findings with its exit status, which has been
+   corrected.
+
+ * Building with "-Werror -Wwrite-strings" is now supported.
+
+ * To help developers, the build procedure now allows builders to use
+   CFLAGS_APPEND to specify additional CFLAGS.
+
+ * "oidtree" tests were rewritten to use the unit test framework.
+
+ * The structure of the document that records longer-term project
+   decisions to deprecate/remove/update various behaviour has been
+   outlined.
+
+ * The pseudo-merge reachability bitmap to help more efficient storage
+   of the reachability bitmap in a repository with too many refs has
+   been added.
+
+ * When "git merge" sees that the index cannot be refreshed (e.g. due
+   to another process doing the same in the background), it died but
+   after writing MERGE_HEAD etc. files, which was useless for the
+   purpose to recover from the failure.
+
+ * The output from "git cat-file --batch-check" and "--batch-command
+   (info)" should not be unbuffered, for which some tests have been
+   added.
+
+ * A CPP macro USE_THE_REPOSITORY_VARIABLE is introduced to help
+   transition the codebase to rely less on the availability of the
+   singleton the_repository instance.
+
+ * "git version --build-options" reports the version information of
+   OpenSSL and other libraries (if used) in the build.
+
+ * Memory ownership rules for the in-core representation of
+   remote.*.url configuration values have been straightened out, which
+   resulted in a few leak fixes and code clarification.
+
+ * When bundleURI interface fetches multiple bundles, Git failed to
+   take full advantage of all bundles and ended up slurping duplicated
+   objects, which has been corrected.
+
+ * The code to deal with modified paths that are out-of-cone in a
+   sparsely checked out working tree has been optimized.
+
+ * An existing test of oidmap API has been rewritten with the
+   unit-test framework.
+
+ * The "ort" merge backend saw one bugfix for a crash that happens
+   when inner merge gets killed, and assorted code clean-ups.
+
+ * A new warning message is issued when a command has to expand a
+   sparse index to handle working tree cruft that are outside of the
+   sparse checkout.
+
+ * The test framework learned to take the test body not as a single
+   string but as a here-document.
+
+ * "git push '' HEAD:there" used to hit a BUG(); it has been corrected
+   to die with "fatal: bad repository ''".
+
+ * What happens when http.cookieFile gets the special value "" has
+   been clarified in the documentation.
+
+
+Fixes since v2.45
+-----------------
+
+ * "git rebase --signoff" used to forget that it needs to add a
+   sign-off to the resulting commit when told to continue after a
+   conflict stops its operation.
+
+ * The procedure to build multi-pack-index got confused by the
+   replace-refs mechanism, which has been corrected by disabling the
+   latter.
+
+ * The "-k" and "--rfc" options of "format-patch" will now error out
+   when used together, as one tells us not to add anything to the
+   title of the commit, and the other one tells us to add "RFC" in
+   addition to "PATCH".
+
+ * "git stash -S" did not handle binary files correctly, which has
+   been corrected.
+
+ * A scheduled "git maintenance" job is expected to work on all
+   repositories it knows about, but it stopped at the first one that
+   errored out.  Now it keeps going.
+
+ * zsh can pretend to be a normal shell pretty well except for some
+   glitches that we tickle in some of our scripts. Work them around
+   so that "vimdiff" and our test suite works well enough with it.
+
+ * Command line completion support for zsh (in contrib/) has been
+   updated to stop exposing internal state to end-user shell
+   interaction.
+
+ * Tests that try to corrupt in-repository files in chunked format did
+   not work well on macOS due to its broken "mv", which has been
+   worked around.
+
+ * The maximum size of attribute files is enforced more consistently.
+
+ * Unbreak CI jobs so that we do not attempt to use Python 2 that has
+   been removed from the platform.
+
+ * Git 2.43 started using the tree of HEAD as the source of attributes
+   in a bare repository, which has severe performance implications.
+   For now, revert the change, without ripping out a more explicit
+   support for the attr.tree configuration variable.
+
+ * The "--exit-code" option of "git diff" command learned to work with
+   the "--ext-diff" option.
+
+ * Windows CI running in GitHub Actions started complaining about the
+   order of arguments given to calloc(); the imported regex code uses
+   the wrong order almost consistently, which has been corrected.
+
+ * Expose "name conflict" error when a ref creation fails due to D/F
+   conflict in the ref namespace, to improve an error message given by
+   "git fetch".
+   (merge 9339fca23e it/refs-name-conflict later to maint).
+
+ * The SubmittingPatches document now refers folks to manpages
+   translation project.
+
+ * The documentation for "git diff --name-only" has been clarified
+   that it is about showing the names in the post-image tree.
+
+ * The credential helper that talks with osx keychain learned to avoid
+   storing back the authentication material it just got received from
+   the keychain.
+   (merge e1ab45b2da kn/osxkeychain-skip-idempotent-store later to maint).
+
+ * The chainlint script (invoked during "make test") did nothing when
+   it failed to detect the number of available CPUs.  It now falls
+   back to 1 CPU to avoid the problem.
+
+ * Revert overly aggressive "layered defence" that went into 2.45.1
+   and friends, which broke "git-lfs", "git-annex", and other use
+   cases, so that we can rebuild necessary counterparts in the open.
+
+ * "git init" in an already created directory, when the user
+   configuration has includeif.onbranch, started to fail recently,
+   which has been corrected.
+
+ * Memory leaks in "git mv" has been plugged.
+
+ * The safe.directory configuration knob has been updated to
+   optionally allow leading path matches.
+
+ * An overly large ".gitignore" files are now rejected silently.
+
+ * Upon expiration event, the credential subsystem forgot to clear
+   in-core authentication material other than password (whose support
+   was added recently), which has been corrected.
+
+ * Fix for an embarrassing typo that prevented Python2 tests from running
+   anywhere.
+
+ * Varargs functions that are unannotated as printf-like or execl-like
+   have been annotated as such.
+
+ * "git am" has a safety feature to prevent it from starting a new
+   session when there already is a session going.  It reliably
+   triggers when a mbox is given on the command line, but it has to
+   rely on the tty-ness of the standard input.  Add an explicit way to
+   opt out of this safety with a command line option.
+   (merge 62c71ace44 jk/am-retry later to maint).
+
+ * A leak in "git imap-send" that somehow escapes LSan has been
+   plugged.
+
+ * Setting core.abbrev too early before the repository set-up
+   (typically in "git clone") caused segfault, which as been
+   corrected.
+
+ * When the user adds to "git rebase -i" instruction to "pick" a merge
+   commit, the error experience is not pleasant.  Such an error is now
+   caught earlier in the process that parses the todo list.
+
+ * We forgot to normalize the result of getcwd() to NFC on macOS where
+   all other paths are normalized, which has been corrected.  This still
+   does not address the case where core.precomposeUnicode configuration
+   is not defined globally.
+
+ * Earlier we stopped using the tree of HEAD as the default source of
+   attributes in a bare repository, but failed to document it.  This
+   has been corrected.
+
+ * "git update-server-info" and "git commit-graph --write" have been
+   updated to use the tempfile API to avoid leaving cruft after
+   failing.
+
+ * An unused extern declaration for mingw has been removed to prevent
+   it from causing build failure.
+
+ * A helper function shared between two tests had a copy-paste bug,
+   which has been corrected.
+
+ * "git fetch-pack -k -k" without passing "--lock-pack" (which we
+   never do ourselves) did not work at all, which has been corrected.
+
+ * CI job to build minimum fuzzers learned to pass NO_CURL=NoThanks to
+   the build procedure, as its build environment does not offer, or
+   the rest of the build needs, anything cURL.
+   (merge 4e66b5a990 jc/fuzz-sans-curl later to maint).
+
+ * "git diff --no-ext-diff" when diff.external is configured ignored
+   the "--color-moved" option.
+   (merge 0f4b0d4cf0 rs/diff-color-moved-w-no-ext-diff-fix later to maint).
+
+ * "git archive --add-virtual-file=<path>:<contents>" never paid
+   attention to the --prefix=<prefix> option but the documentation
+   said it would. The documentation has been corrected.
+   (merge 72c282098d jc/archive-prefix-with-add-virtual-file later to maint).
+
+ * When GIT_PAGER failed to spawn, depending on the code path taken,
+   we failed immediately (correct) or just spew the payload to the
+   standard output (incorrect).  The code now always fail immediately
+   when GIT_PAGER fails.
+   (merge 78f0a5d187 rj/pager-die-upon-exec-failure later to maint).
+
+ * date parser updates to be more careful about underflowing epoch
+   based timestamp.
+   (merge 9d69789770 db/date-underflow-fix later to maint).
+
+ * The Bloom filter used for path limited history traversal was broken
+   on systems whose "char" is unsigned; update the implementation and
+   bump the format version to 2.
+   (merge 9c8a9ec787 tb/path-filter-fix later to maint).
+
+ * Typofix.
+   (merge 231cf7370e as/pathspec-h-typofix later to maint).
+
+ * Code clean-up.
+   (merge 4b837f821e rs/simplify-submodule-helper-super-prefix-invocation later to maint).
+
+ * "git describe --dirty --broken" forgot to refresh the index before
+   seeing if there is any chang, ("git describe --dirty" correctly did
+   so), which has been corrected.
+   (merge b8ae42e292 as/describe-broken-refresh-index-fix later to maint).
+
+ * Test suite has been taught not to unnecessarily rely on DNS failing
+   a bogus external name.
+   (merge 407cdbd271 jk/tests-without-dns later to maint).
+
+ * GitWeb update to use committer date consistently in rss/atom feeds.
+   (merge cf6ead095b am/gitweb-feed-use-committer-date later to maint).
+
+ * Custom control structures we invented more recently have been
+   taught to the clang-format file.
+   (merge 1457dff9be rs/clang-format-updates later to maint).
+
+ * Developer build procedure fix.
+   (merge df32729866 tb/dev-build-pedantic-fix later to maint).
+
+ * "git push" that pushes only deletion gave an unnecessary and
+   harmless error message when push negotiation is configured, which
+   has been corrected.
+   (merge 4d8ee0317f jc/disable-push-nego-for-deletion later to maint).
+
+ * Address-looking strings found on the trailer are now placed on the
+   Cc: list after running through sanitize_address by "git send-email".
+   (merge c852531f45 cb/send-email-sanitize-trailer-addresses later to maint).
+
+ * Tests that use GIT_TEST_SANITIZE_LEAK_LOG feature got their exit
+   status inverted, which has been corrected.
+   (merge 8c1d6691bc rj/test-sanitize-leak-log-fix later to maint).
+
+ * The http.cookieFile and http.saveCookies configuration variables
+   have a few values that need to be avoided, which are now ignored
+   with warning messages.
+   (merge 4f5822076f jc/http-cookiefile later to maint).
+
+ * Repacking a repository with multi-pack index started making stupid
+   pack selections in Git 2.45, which has been corrected.
+   (merge 8fb6d11fad ds/midx-write-repack-fix later to maint).
+
+ * Fix documentation mark-up regression in 2.45.
+   (merge 6474da0aa4 ja/doc-markup-updates-fix later to maint).
+
+ * Work around asciidoctor's css that renders `monospace` material
+   in the SYNOPSIS section of manual pages as block elements.
+   (merge d44ce6ddd5 js/doc-markup-updates-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 493fdae046 ew/object-convert-leakfix later to maint).
+   (merge 00f3661a0a ss/doc-eol-attr-fix later to maint).
+   (merge 428c40da61 ri/doc-show-branch-fix later to maint).
+   (merge 58696bfcaa jc/where-is-bash-for-ci later to maint).
+   (merge 616e94ca24 tb/doc-max-tree-depth-fix later to maint).
diff --git a/Documentation/RelNotes/2.46.1.txt b/Documentation/RelNotes/2.46.1.txt
new file mode 100644
index 0000000000..e55c2c4a46
--- /dev/null
+++ b/Documentation/RelNotes/2.46.1.txt
@@ -0,0 +1,75 @@
+Git 2.46.1 Release Notes
+========================
+
+This release is primarily to merge fixes accumulated on the 'master'
+front to prepare for 2.47 release that are still relevant to 2.46.x
+maintenance track.
+
+Fixes since Git 2.46
+--------------------
+
+ * "git checkout --ours" (no other arguments) complained that the
+   option is incompatible with branch switching, which is technically
+   correct, but found confusing by some users.  It now says that the
+   user needs to give pathspec to specify what paths to checkout.
+
+ * It has been documented that we avoid "VAR=VAL shell_func" and why.
+
+ * "git add -p" by users with diff.suppressBlankEmpty set to true
+   failed to parse the patch that represents an unmodified empty line
+   with an empty line (not a line with a single space on it), which
+   has been corrected.
+
+ * "git rebase --help" referred to "offset" (the difference between
+   the location a change was taken from and the change gets replaced)
+   incorrectly and called it "fuzz", which has been corrected.
+
+ * "git notes add -m '' --allow-empty" and friends that take prepared
+   data to create notes should not invoke an editor, but it started
+   doing so since Git 2.42, which has been corrected.
+
+ * An expensive operation to prepare tracing was done in re-encoding
+   code path even when the tracing was not requested, which has been
+   corrected.
+
+ * Perforce tests have been updated.
+
+ * The credential helper to talk to OSX keychain sometimes sent
+   garbage bytes after the username, which has been corrected.
+
+ * A recent update broke "git ls-remote" used outside a repository,
+   which has been corrected.
+
+ * "git config --value=foo --fixed-value section.key newvalue" barfed
+   when the existing value in the configuration file used the
+   valueless true syntax, which has been corrected.
+
+ * "git reflog expire" failed to honor annotated tags when computing
+   reachable commits.
+
+ * A flakey test and incorrect calls to strtoX() functions have been
+   fixed.
+
+ * Follow-up on 2.45.1 regression fix.
+
+ * "git rev-list ... | git diff-tree -p --remerge-diff --stdin" should
+   behave more or less like "git log -p --remerge-diff" but instead it
+   crashed, forgetting to prepare a temporary object store needed.
+
+ * The patch parser in "git patch-id" has been tightened to avoid
+   getting confused by lines that look like a patch header in the log
+   message.
+
+ * "git bundle unbundle" outside a repository triggered a BUG()
+   unnecessarily, which has been corrected.
+
+ * The code forgot to discard unnecessary in-core commit buffer data
+   for commits that "git log --skip=<number>" traversed but omitted
+   from the output, which has been corrected.
+
+ * "git verify-pack" and "git index-pack" started dying outside a
+   repository, which has been corrected.
+
+ * A corner case bug in "git stash" was fixed.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.46.2.txt b/Documentation/RelNotes/2.46.2.txt
new file mode 100644
index 0000000000..613386878d
--- /dev/null
+++ b/Documentation/RelNotes/2.46.2.txt
@@ -0,0 +1,23 @@
+Git 2.46.2 Release Notes
+========================
+
+This release is primarily to merge changes to unbreak the 32-bit
+GitHub actions jobs we use for CI testing, so that we can release
+real fixes for the 2.46.x track after they pass CI.
+
+It also reverts the "git patch-id" change that went into 2.46.1,
+as it seems to have got a regression reported (I haven't verified,
+but it is better to keep a known breakage than adding an unintended
+regression).
+
+Other than that, a handful of minor bugfixes are included.
+
+ * In a few corner cases "git diff --exit-code" failed to report
+   "changes" (e.g., renamed without any content change), which has
+   been corrected.
+
+ * Cygwin does have /dev/tty support that is needed by things like
+   single-key input mode.
+
+ * The interpret-trailers command failed to recognise the end of the
+   message when the commit log ends in an incomplete line.
diff --git a/Documentation/RelNotes/2.46.3.txt b/Documentation/RelNotes/2.46.3.txt
new file mode 100644
index 0000000000..4af032b63c
--- /dev/null
+++ b/Documentation/RelNotes/2.46.3.txt
@@ -0,0 +1,6 @@
+Git v2.46.3 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4, v2.41.3, v2.42.4,
+v2.43.6, v2.44.3 and v2.45.3 to address the security issues CVE-2024-50349 and
+CVE-2024-52006; see the release notes for these versions for details.
diff --git a/Documentation/RelNotes/2.47.0.txt b/Documentation/RelNotes/2.47.0.txt
new file mode 100644
index 0000000000..b63c3364af
--- /dev/null
+++ b/Documentation/RelNotes/2.47.0.txt
@@ -0,0 +1,342 @@
+Git v2.47 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * Many Porcelain commands that internally use the merge machinery
+   were taught to consistently honor the diff.algorithm configuration.
+
+ * A few descriptions in "git show-ref -h" have been clarified.
+
+ * A 'P' command to "git add -p" that passes the patch hunk to the
+   pager has been added.
+
+ * "git grep -W" omits blank lines that follow the found function at
+   the end of the file, just like it omits blank lines before the next
+   function.
+
+ * The value of http.proxy can have "path" at the end for a socks
+   proxy that listens to a unix-domain socket, but we started to
+   discard it when we taught proxy auth code path to use the
+   credential helpers, which has been corrected.
+
+ * The code paths to compact multiple reftable files have been updated
+   to correctly deal with multiple compaction triggering at the same
+   time.
+
+ * Support to specify ref backend for submodules has been enhanced.
+
+ * "git svn" has been taught about svn:global-ignores property
+   recent versions of Subversion has.
+
+ * The default object hash and ref backend format used to be settable
+   only with explicit command line option to "git init" and
+   environment variables, but now they can be configured in the user's
+   global and system wide configuration.
+
+ * "git send-email" learned "--translate-aliases" option that reads
+   addresses from the standard input and emits the result of applying
+   aliases on them to the standard output.
+
+ * 'git for-each-ref' learned a new "--format" atom to find the branch
+   that the history leading to a given commit "%(is-base:<commit>)" is
+   likely based on.
+
+ * The command line prompt support used to be littered with bash-isms,
+   which has been corrected to work with more shells.
+
+ * Support for the RUNTIME_PREFIX feature has been added to z/OS port.
+
+ * "git send-email" learned "--mailmap" option to allow rewriting the
+   recipient addresses.
+
+ * "git mergetool" learned to use VSCode as a merge backend.
+
+ * "git pack-redundant" has been marked for removal in Git 3.0.
+
+ * One-line messages to "die" and other helper functions will get LF
+   added by these helper functions, but many existing messages had an
+   unnecessary LF at the end, which have been corrected.
+
+ * The "scalar clone" command learned the "--no-tags" option.
+
+ * The environment GIT_ADVICE has been intentionally kept undocumented
+   to discourage its use by interactive users.  Add documentation to
+   help tool writers.
+
+ * "git apply --3way" learned to take "--ours" and other options.
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * A build tweak knob has been simplified by not setting the value
+   that is already the default; another unused one has been removed.
+
+ * A CI job that use clang-format to check coding style issues in new
+   code has been added.
+
+ * The reviewing guidelines document now explicitly encourages people
+   to give positive reviews and how.
+
+ * Test script linter has been updated to catch an attempt to use
+   one-shot export construct "VAR=VAL func" for shell functions (which
+   does not work for some shells) better.
+
+ * Some project conventions have been added to CodingGuidelines.
+
+ * In the refs subsystem, implicit reliance of the_repository has been
+   eliminated; the repository associated with the ref store object is
+   used instead.
+
+ * Various tests in reftable library have been rewritten using the unit test
+   framework.
+
+ * A test that fails on an unusually slow machine was found, and made
+   less likely to cause trouble by lengthening the expiry value it
+   uses.
+
+ * An existing test of hashmap API has been rewritten with the
+   unit-test framework.
+
+ * A policy document that describes platform support levels and
+   expectation on platform stakeholders has been introduced.
+
+ * The refs API has been taught to give symref target information to
+   the users of ref iterators, allowing for-each-ref and friends to
+   avoid an extra ref_resolve_* API call per a symbolic ref.
+
+ * Unit-test framework has learned a simple control structure to allow
+   embedding test statements in-line instead of having to create a new
+   function to contain them.
+
+ * Incremental updates of multi-pack index files is getting worked on.
+
+ * Use of API functions that implicitly depend on the_repository
+   object in the config subsystem has been rewritten to pass a
+   repository object through the callchain.
+
+ * Unused parameters have been either marked as UNUSED to squelch
+   -Wunused warnings or dropped from many functions..
+
+ * The code in the reftable library has been cleaned up by discarding
+   unused "generic" interface.
+
+ * The underlying machinery for "git diff-index" has long been made to
+   expand the sparse index as needed, but the command fully expanded
+   the sparse index upfront, which now has been taught not to do.
+
+ * More trace2 events at key points on push and fetch code paths have
+   been added.
+
+ * Make our codebase compilable with the -Werror=unused-parameter
+   option.
+
+ * "git cat-file" works well with the sparse-index, and gets marked as
+   such.
+
+ * CI started failing completely for linux32 jobs, as the step to
+   upload failed test directory uses GitHub actions that is deprecated
+   and is now disabled.
+
+ * Import clar unit tests framework libgit2 folks invented for our
+   use.
+
+ * The error messages from the test script checker have been improved.
+
+ * The convention to calling into built-in command implementation has
+   been updated to pass the repository, if known, together with the
+   prefix value.
+
+ * "git apply" had custom buffer management code that predated before
+   use of strbuf got widespread, which has been updated to use strbuf,
+   which also plugged some memory leaks.
+
+ * The reftable backend learned to more efficiently handle exclude
+   patterns while enumerating the refs.
+
+ * CI updates.  FreeBSD image has been updated to 13.4.
+   (merge 2eeb29702e cb/ci-freebsd-13-4 later to maint).
+
+ * Give timeout to the locking code to write to reftable, instead of
+   failing on the first failure without retrying.
+
+ * The checksum at the tail of files are now computed without
+   collision detection protection.  This is safe as the consumer of
+   the information to protect itself from replay attacks checks for
+   hash collisions independently.
+
+
+Fixes since v2.46
+-----------------
+
+ * "git add -p" by users with diff.suppressBlankEmpty set to true
+   failed to parse the patch that represents an unmodified empty line
+   with an empty line (not a line with a single space on it), which
+   has been corrected.
+
+ * "git checkout --ours" (no other arguments) complained that the
+   option is incompatible with branch switching, which is technically
+   correct, but found confusing by some users.  It now says that the
+   user needs to give pathspec to specify what paths to checkout.
+
+ * It has been documented that we avoid "VAR=VAL shell_func" and why.
+
+ * "git rebase --help" referred to "offset" (the difference between
+   the location a change was taken from and the change gets replaced)
+   incorrectly and called it "fuzz", which has been corrected.
+
+ * "git notes add -m '' --allow-empty" and friends that take prepared
+   data to create notes should not invoke an editor, but it started
+   doing so since Git 2.42, which has been corrected.
+
+ * An expensive operation to prepare tracing was done in re-encoding
+   code path even when the tracing was not requested, which has been
+   corrected.
+
+ * More leakfixes.
+
+ * The credential helper to talk to OSX keychain sometimes sent
+   garbage bytes after the username, which has been corrected.
+
+ * A recent update broke "git ls-remote" used outside a repository,
+   which has been corrected.
+
+ * The patch parser in 'git apply' has been a bit more lenient against
+   unexpected mode bits, like 100664, recorded on extended header lines.
+
+ * "git config --value=foo --fixed-value section.key newvalue" barfed
+   when the existing value in the configuration file used the
+   valueless true syntax, which has been corrected.
+
+ * The patch parser in "git patch-id" has been tightened to avoid
+   getting confused by lines that look like a patch header in the log
+   message.
+
+ * "git reflog expire" failed to honor annotated tags when computing
+   reachable commits.
+
+ * A flakey test and incorrect calls to strtoX() functions have been
+   fixed.
+
+ * Follow-up on 2.45.1 regression fix.
+
+ * "git rev-list ... | git diff-tree -p --remerge-diff --stdin" should
+   behave more or less like "git log -p --remerge-diff" but instead it
+   crashed, forgetting to prepare a temporary object store needed.
+
+ * "git bundle unbundle" outside a repository triggered a BUG()
+   unnecessarily, which has been corrected.
+
+ * Maintenance tasks other than "gc" now properly go background when
+   "git maintenance" runs them.
+
+ * We created a useless pseudo-merge reachability bitmap that is about
+   0 commits, and attempted to include commits that are not in packs,
+   which made no sense.  These bugs have been corrected.
+   (merge a72dfab8b8 tb/pseudo-merge-bitmap-fixes later to maint).
+
+ * "git rebase -x --quiet" was not quiet, which was corrected.
+
+ * The code path for compacting reftable files saw some bugfixes
+   against concurrent operation.
+
+ * The code forgot to discard unnecessary in-core commit buffer data
+   for commits that "git log --skip=<number>" traversed but omitted
+   from the output, which has been corrected.
+
+ * "git verify-pack" and "git index-pack" started dying outside a
+   repository, which has been corrected.
+
+ * A data corruption bug when multi-pack-index is used and the same
+   objects are stored in multiple packfiles has been corrected.
+
+ * "git pack-refs --auto" for the files backend was too aggressive,
+   which has been a bit tamed.
+   (merge c3459ae9ef ps/pack-refs-auto-heuristics later to maint).
+
+ * A file descriptor left open is now properly closed when "git
+   sparse-checkout" updates the sparse patterns.
+
+ * In a few corner cases "git diff --exit-code" failed to report
+   "changes" (e.g., renamed without any content change), which has
+   been corrected.
+
+ * Cygwin does have /dev/tty support that is needed by things like
+   single-key input mode.
+
+ * The interpret-trailers command failed to recognise the end of the
+   message when the commit log ends in an incomplete line.
+
+ * "git rebase --autostash" failed to resurrect the autostashed
+   changes when the command gets aborted after giving back control
+   asking for hlep in conflict resolution.
+   (merge bf6ab087d1 pw/rebase-autostash-fix later to maint).
+
+ * The "imap-send" now allows to be compiled with NO_OPENSSL and
+   OPENSSL_SHA1 defined together.
+   (merge 997950a750 jk/no-openssl-with-openssl-sha1 later to maint).
+
+ * The support to customize build options to adjust for older versions
+   and/or older systems for the interop tests has been improved.
+   (merge 22ef5f02a8 jk/interop-test-build-options later to maint).
+
+ * Update the character width table for Unicode 16.
+   (merge 44dc651132 bb/unicode-width-table-16 later to maint).
+
+ * In Git 2.39, Git.pm stopped working in a bare repository, which has
+   been corrected.
+   (merge d3edb0bdde jk/git-pm-bare-repo-fix later to maint).
+
+ * When a remote-helper dies before Git writes to it, SIGPIPE killed
+   Git silently.  We now explain the situation a bit better to the end
+   user in our error message.
+   (merge 6e7fac9bca jk/diag-unexpected-remote-helper-death later to maint).
+
+ * A few usability fixes to "git jump" (in contrib/).
+   (merge 083b82544d jk/jump-quickfix-fixes later to maint).
+
+ * "git diff --exit-code" ignored modified binary files, which has
+   been corrected.
+   (merge 9a41735af6 rs/diff-exit-code-binary later to maint).
+
+ * When a subprocess to work in a submodule spawned by "git submodule"
+   fails with SIGPIPE, the parent Git process caught the death of it,
+   but gave a generic "failed to work in that submodule", which was
+   misleading.  We now behave as if the parent got SIGPIPE and die.
+   (merge 082caf527e pw/submodule-process-sigpipe later to maint).
+
+ * "git archive" with pathspec magic that uses the attribute
+   information did not work well, which has been corrected.
+   (merge 296743a7ca rs/archive-with-attr-pathspec-fix later to maint).
+
+ * Background tasks "git maintenance" runs may need to use credential
+   information when going over the network, but a credential helper
+   may work only in an interactive environment, and end up blocking a
+   scheduled task waiting for UI.  Credential helpers can now behave
+   differently when they are not running interactively.
+   (merge b9183b0a02 ds/background-maintenance-with-credential later to maint).
+
+ * "git --git-dir=nowhere cmd" failed to properly notice that it
+   wasn't in any repository while processing includeIf.onbranch
+   configuration and instead crashed.
+
+ * When "git sparse-checkout disable" turns a sparse checkout into a
+   regular checkout, the index is fully expanded.  This totally
+   expected behaviour however had an "oops, we are expanding the
+   index" advice message, which has been corrected.
+   (merge 537e516a39 ds/sparse-checkout-expansion-advice later to maint).
+
+ * macOS with fsmonitor daemon can hang forever when a submodule is
+   involved, which has been corrected.
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge be10ac7037 jc/mailinfo-header-cleanup later to maint).
+   (merge 4460e052e0 jc/range-diff-lazy-setup later to maint).
+   (merge 0627c58e7a ak/typofixes later to maint).
+   (merge 83799f1500 jk/t9001-deflake later to maint).
+   (merge e02cc08a88 ak/typofix-2.46-maint later to maint).
+   (merge 5c5d29e1c4 ps/ci-gitlab-upgrade later to maint).
+   (merge 9c4c840901 jc/doc-discarding-stalled-topics later to maint).
+   (merge 5e6f359f6b ds/read-cache-mempool-leakfix later to maint).
diff --git a/Documentation/RelNotes/2.47.1.txt b/Documentation/RelNotes/2.47.1.txt
new file mode 100644
index 0000000000..39206c09fd
--- /dev/null
+++ b/Documentation/RelNotes/2.47.1.txt
@@ -0,0 +1,31 @@
+Git 2.47.1 Release Notes
+========================
+
+This is to flush accumulated fixes since 2.47.0 on the 'master'
+front down to the maintenance track.
+
+
+Fixes since Git 2.47
+--------------------
+
+ * Use after free and double freeing at the end in "git log -L... -p"
+   had been identified and fixed.
+
+ * On macOS, fsmonitor can fall into a race condition that results in
+   a client waiting forever to be notified for an event that have
+   already happened.  This problem has been corrected.
+
+ * "git maintenance start" crashed due to an uninitialized variable
+   reference, which has been corrected.
+
+ * Fail gracefully instead of crashing when attempting to write the
+   contents of a corrupt in-core index as a tree object.
+
+ * A "git fetch" from the superproject going down to a submodule used
+   a wrong remote when the default remote names are set differently
+   between them.
+
+ * The "gitk" project tree has been synchronized again with its new
+   maintainer, Johannes Sixt.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.47.2.txt b/Documentation/RelNotes/2.47.2.txt
new file mode 100644
index 0000000000..7a52ad8cb4
--- /dev/null
+++ b/Documentation/RelNotes/2.47.2.txt
@@ -0,0 +1,7 @@
+Git v2.47.2 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4, v2.41.3,
+v2.42.4, v2.43.6, v2.44.3, v2.45.3 and v2.46.3 to address the
+security issues CVE-2024-50349 and CVE-2024-52006; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.48.0.txt b/Documentation/RelNotes/2.48.0.txt
new file mode 100644
index 0000000000..eff93be37a
--- /dev/null
+++ b/Documentation/RelNotes/2.48.0.txt
@@ -0,0 +1,330 @@
+Git v2.48 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * A new configuration variable remote.<name>.serverOption makes the
+   transport layer act as if the --serverOption=<value> option is
+   given from the command line.
+
+ * "git rebase --rebase-merges" now uses branch names as labels when
+   able.
+
+ * Describe the policy to introduce breaking changes.
+
+ * Teach 'git notes add' and 'git notes append' a new '-e' flag,
+   instructing them to open the note in $GIT_EDITOR before saving.
+
+ * Documentation for "git bundle" saw improvements to more prominently
+   call out the use of '--all' when creating bundles.
+
+ * Drop support for older libcURL and Perl.
+
+ * End-user experience of "git mergetool" when the command errors out
+   has been improved.
+
+ * "git bundle --unbundle" and "git clone" running on a bundle file
+   both learned to trigger fsck over the new objects with configurable
+   fck check levels.
+
+ * When "git fetch $remote" notices that refs/remotes/$remote/HEAD is
+   missing and discovers what branch the other side points with its
+   HEAD, refs/remotes/$remote/HEAD is updated to point to it.
+
+ * "git fetch" honors "remote.<remote>.followRemoteHEAD" settings to
+   tweak the remote-tracking HEAD in "refs/remotes/<remote>/HEAD".
+
+ * "git range-diff" learned to optionally show and compare merge
+   commits in the ranges being compared, with the --diff-merges
+   option.
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * Document "amlog" notes.
+
+ * The way AsciiDoc is used for SYNOPSIS part of the manual pages has
+   been revamped.  The sources, at least for the simple cases, got
+   vastly more pleasant to work with.
+
+ * The reftable library is now prepared to expect that the memory
+   allocation function given to it may fail to allocate and to deal
+   with such an error.
+
+ * An extra worktree attached to a repository points at each other to
+   allow finding the repository from the worktree (and vice versa)
+   possible.  Use relative paths for this linkage.
+
+ * Enable Windows-based CI in GitLab.
+
+ * Commands that can also work outside Git have learned to take the
+   repository instance "repo" when we know we are in a repository, and
+   NULL when we are not, in a parameter.  The uses of the_repository
+   variable in a few of them have been removed using the new calling
+   convention.
+
+ * The reftable sub-system grew a new reftable-specific strbuf
+   replacement to reduce its dependency on Git-specific data
+   structures.
+
+ * The ref-filter machinery learns to recognize and avoid cases where
+   sorting would be redundant.
+
+ * Various platform compatibility fixes split out of the larger effort
+   to use Meson as the primary build tool.
+
+ * Treat ECONNABORTED the same as ECONNRESET in 'git credential-cache'
+   to work around a possible Cygwin regression. This resolves a race
+   condition caused by changes in Cygwin's handling of socket
+   closures, allowing the client to exit cleanly when encountering
+   ECONNABORTED.
+
+ * Demonstrate an assertion failure in 'git mv'.
+
+ * Documentation update to clarify that 'uploadpack.allowAnySHA1InWant'
+   implies both 'allowTipSHA1InWant' and 'allowReachableSHA1InWant'.
+
+ * Replace various calls to atoi() with strtol_i() and strtoul_ui(),
+   and add improved error handling.
+
+ * Documentation updates to 'git-update-ref(1)'.
+
+ * Update the project's CodingGuidelines to discourage naming functions
+   with a "_1()" suffix.
+
+ * Update '.clang-format' to match project conventions.
+
+ * Centralize documentation for repository extensions into a single place.
+
+ * Buildfix and upgrade of Clar to a newer version.
+
+ * Documentation mark-up updates.
+
+ * Renaming a handful of variables and structure fields.
+
+ * Fix for clar unit tests to support CMake build.
+
+ * C23 compatibility updates.
+
+ * GCC 15 compatibility updates.
+
+ * We now ensure "index-pack" is used with the "--promisor" option
+   only during a "git fetch".
+
+ * The migration procedure between two ref backends has been optimized.
+
+ * "git fsck" learned to issue warnings on "curiously formatted" ref
+   contents that have always been treated as valid but that Git
+   wouldn't have written itself (e.g., missing terminating end-of-line
+   after the full object name).
+
+ * Work around Coverity warning that would not trigger in practice.
+
+ * Built-in Git subcommands are supplied the repository object to work
+   with; they learned to do the same when they invoke sub-subcommands.
+
+ * Drop support for ancient environments in various CI jobs.
+
+ * Isolate the reftable subsystem from the rest of Git's codebase by
+   using fewer pieces of Git's infrastructure.
+
+ * Optimize reading random references out of the reftable backend by
+   allowing reuse of iterator objects.
+
+ * Backport oss-fuzz tests to our codebase.
+
+ * Introduce a new repository extension to prevent older Git versions
+   from mis-interpreting worktrees created with relative paths.
+
+ * Yet another "pass the repository through the callchain" topic.
+
+ * "git describe" learned to stop digging the history needlessly
+   deeper.
+
+ * Build procedure update plus introduction of Meson based builds.
+
+ * Recent reftable updates mistook a NULL return from a request for
+   0-byte allocation as OOM and died unnecessarily, which has been
+   corrected.
+
+ * Reftable backend adds check for upper limit of log's update_index.
+
+ * Start working to make the codebase buildable with -Wsign-compare.
+
+ * Regression fix for 'show-index' when run outside of a repository.
+
+ * The meson-build procedure is integrated into CI to catch and
+   prevent bitrotting.
+
+ * "git refs migrate" learned to also migrate the reflog data across
+   backends.
+
+ * The developer documentation has been updated to give the latest
+   info on gitk and git-gui maintainer.
+
+
+ * CI jobs that run threaded programs under LSan has been giving false
+   positives from time to time, which has been worked around.
+
+
+Fixes since v2.47
+-----------------
+
+ * Doc update to clarify how periodical maintenance are scheduled,
+   spread across time to avoid thundering herds.
+
+ * Use after free and double freeing at the end in "git log -L... -p"
+   had been identified and fixed.
+
+ * On macOS, fsmonitor can fall into a race condition that results in
+   a client waiting forever to be notified about an event that has
+   already happened.  This problem has been corrected.
+
+ * "git maintenance start" crashed due to an uninitialized variable
+   reference, which has been corrected.
+
+ * Fail gracefully instead of crashing when attempting to write the
+   contents of a corrupt in-core index as a tree object.
+
+ * A "git fetch" from the superproject going down to a submodule used
+   a wrong remote when the default remote names are set differently
+   between them.
+
+ * Fixes compile time warnings with 64-bit MSVC.
+
+ * Teaches 'shortlog' to explicitly use SHA-1 when operating outside
+   of a repository.
+
+ * Fix 'git grep' regression on macOS by disabling lookahead when
+   encountering invalid UTF-8 byte sequences.
+
+ * The dumb-http code regressed when the result of re-indexing a pack
+   yielded an *.idx file that differs in content from the *.idx file
+   it downloaded from the remote. This has been corrected by no longer
+   relying on the *.idx file we got from the remote.
+
+ * When called with '--left-right' and '--use-bitmap-index', 'rev-list'
+   will produce output without any left/right markers, which has been
+   corrected.
+
+ * More leakfixes.
+
+ * Test modernization.
+
+ * The "--shallow-exclude=<ref>" option to various history transfer
+   commands takes a ref, not an arbitrary revision.
+
+ * A regression where commit objects missing from a commit-graph can
+   cause an infinite loop when doing a fetch in a partial clone has
+   been fixed.
+
+ * The MinGW compatibility layer has been taught to support POSIX
+   semantics for atomic renames when other process(es) have a file
+   opened at the destination path.
+
+ * "git gc" discards any objects that are outside promisor packs that
+   are referred to by an object in a promisor pack, and we do not
+   refetch them from the promisor at runtime, resulting an unusable
+   repository.  Work around it by including these objects in the
+   referring promisor pack at the receiving end of the fetch.
+
+ * Avoid build/test breakage on a system without working malloc debug
+   support dynamic library.
+   (merge 72ad6dc368 jk/test-malloc-debug-check later to maint).
+
+ * Double-free fix.
+   (merge fe17a25905 jk/fetch-prefetch-double-free-fix later to maint).
+
+ * Use of some uninitialized variables in "git difftool" has been
+   corrected.
+
+ * Object reuse code based on multi-pack-index sent an unwanted copy
+   of object.
+   (merge e199290592 tb/multi-pack-reuse-dupfix later to maint).
+
+ * "git fast-import" can be tricked into a replace ref that maps an
+   object to itself, which is a useless thing to do.
+   (merge 5e904f1a4a en/fast-import-avoid-self-replace later to maint).
+
+ * The ref-transaction hook triggered for reflog updates, which has
+   been corrected.
+   (merge b886db48c6 kn/ref-transaction-hook-with-reflog later to maint).
+
+ * Give a bit of advice/hint message when "git maintenance" stops finding a
+   lock file left by another instance that still is potentially running.
+   (merge ba874d1dac ps/gc-stale-lock-warning later to maint).
+
+ * Use the right helper program to measure file size in performance tests.
+   (merge 3f97f1bce6 tb/use-test-file-size-more later to maint).
+
+ * A double-free that may not trigger in practice by luck has been
+   corrected in the reference resolution code.
+   (merge b6318cf23a sj/refs-symref-referent-fix later to maint).
+
+ * The sequencer failed to honor core.commentString in some places.
+
+ * Describe a case where an option value needs to be spelled as a
+   separate argument, i.e. "--opt val", not "--opt=val".
+   (merge 1bc1e94091 jc/doc-opt-tilde-expand later to maint).
+
+ * Loosen overly strict ownership check introduced in the recent past,
+   to keep the promise "cloning a suspicious repository is a safe
+   first step to inspect it".
+   (merge 0ffb5a6bf1 bc/allow-upload-pack-from-other-people later to maint).
+
+ * "git fast-import" learned to reject paths with ".."  and "." as
+   their components to avoid creating invalid tree objects.
+   (merge 8cb4c6e62f en/fast-import-verify-path later to maint).
+
+ * The --ancestry-path option is designed to be given a commit that is
+   on the path, which was not documented, which has been corrected.
+   (merge bc1a980759 kk/doc-ancestry-path later to maint).
+
+ * "git tag" has been taught to refuse to create refs/tags/HEAD
+   since such a tag will be confusing in the context of the UI provided by
+   the Git Porcelain commands.
+   (merge bbd445d5ef jc/forbid-head-as-tagname later to maint).
+
+ * The advice messages now tell the newer 'git config set' command to
+   set the advice.token configuration variable to squelch a message.
+   (merge 6c397d0104 bf/explicit-config-set-in-advice-messages later to maint).
+
+ * The syntax ":/<text>" to name the latest commit with the matching
+   text was broken with a recent change, which has been corrected.
+   (merge 0ff919e87a ps/commit-with-message-syntax-fix later to maint).
+
+ * Fix performance regression of a recent "fatten promisor pack with
+   local objects" protection against an unwanted gc.
+
+ * "git log -p --remerge-diff --reverse" was completely broken.
+   (merge f94bfa1516 js/log-remerge-keep-ancestry later to maint).
+
+ * "git bundle create" with an annotated tag on the positive end of
+   the revision range had a workaround code for older limitation in
+   the revision walker, which has become unnecessary.
+   (merge dd1072dfa8 tc/bundle-with-tag-remove-workaround later to maint).
+
+ * GitLab CI updates.
+   (merge c6b43f663e ps/ci-gitlab-update later to maint).
+
+ * Code to reuse objects based on bitmap contents have been tightened
+   to avoid race condition even when multiple packs are involved.
+   (merge 62b3ec8a3f tb/bitmap-fix-pack-reuse later to maint).
+
+ * An earlier "csum-file checksum does not have to be computed with
+   sha1dc" topic had a few code paths that had initialized an
+   implementation of a hash function to be used by an unmatching hash
+   by mistake, which have been corrected.
+   (merge 599a63409b ps/weak-sha1-for-tail-sum-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge 77af53f56f aa/t7300-modernize later to maint).
+   (merge dcd590a39d bf/t-readme-mention-reftable later to maint).
+   (merge 68e3c69efa kh/trailer-in-glossary later to maint).
+   (merge 91f88f76e6 tb/boundary-traversal-fix later to maint).
+   (merge 168ebb7159 jc/doc-error-message-guidelines later to maint).
+   (merge 18693d7d65 kh/doc-bundle-typofix later to maint).
+   (merge e2f5d3b491 kh/doc-update-ref-grammofix later to maint).
+   (merge 8525e92886 mh/doc-windows-home-env later to maint).
diff --git a/Documentation/RelNotes/2.48.1.txt b/Documentation/RelNotes/2.48.1.txt
new file mode 100644
index 0000000000..26c59b6e3b
--- /dev/null
+++ b/Documentation/RelNotes/2.48.1.txt
@@ -0,0 +1,7 @@
+Git v2.48.1 Release Notes
+=========================
+
+This release merges up the fix that appears in v2.40.4, v2.41.3,
+v2.42.4, v2.43.6, v2.44.3, v2.45.3, v2.46.3, and v2.47.2 to address
+the security issues CVE-2024-50349 and CVE-2024-52006; see the release
+notes for these versions for details.
diff --git a/Documentation/RelNotes/2.49.0.txt b/Documentation/RelNotes/2.49.0.txt
new file mode 100644
index 0000000000..6c9e010b72
--- /dev/null
+++ b/Documentation/RelNotes/2.49.0.txt
@@ -0,0 +1,118 @@
+Git v2.49 Release Notes
+=======================
+
+UI, Workflows & Features
+------------------------
+
+ * Completion script updates for zsh
+
+
+Performance, Internal Implementation, Development Support etc.
+--------------------------------------------------------------
+
+ * More -Wsign-compare fixes.
+
+ * meson-based build now supports the unsafe-sha1 build knob.
+
+ * The code to check LSan results has been simplified and made more
+   robust.
+   (merge 164a2516eb jk/lsan-race-ignore-false-positive later to maint).
+
+ * More code paths have a repository passed through the callchain,
+   instead of assuming the primary the_repository object.
+
+ * Move a few more unit tests to the clar test framework.
+
+ * Introduce a new API to visit objects in batches based on a common
+   path, or by type.
+
+
+Fixes since v2.48
+-----------------
+
+ * "git submodule" learned various ways to spell the same option,
+   e.g. "--branch=B" can be spelled "--branch B" or "-bB".
+   (merge b86f0f9071 re/submodule-parse-opt later to maint).
+
+ * Tweak the help text used for the option value placeholders by
+   parse-options API so that translations can customize the "<>"
+   placeholder signal (e.g. "--option=<value>").
+   (merge 5b34dd08d0 as/long-option-help-i18n later to maint).
+
+ * CI jobs gave sporadic failures, which turns out that that the
+   object finalization code was giving an error when it did not have
+   to.
+   (merge d7fcbe2c56 ps/object-collision-check later to maint).
+
+ * The code to compute "unique" name used git_rand() which can fail or
+   get stuck; the callsite does not require cryptographic security.
+   Introduce the "insecure" mode and use it appropriately.
+   (merge 0b4f8afef6 ps/reftable-get-random-fix later to maint).
+
+ * A misconfigured "fsck.skiplist" configuration variable was not
+   diagnosed as an error, which has been corrected.
+   (merge ca7158076f jt/fsck-skiplist-parse-fix later to maint).
+
+ * Extended SHA-1 expression parser did not work well when a branch
+   with an unusual name (e.g. "foo{bar") is involved.
+   (merge 191f0c8db2 en/object-name-with-funny-refname-fix later to maint).
+
+ * The meson build procedure looked for the 'version-def.h' file in a
+   wrong directory, which has been corrected.
+   (merge 4771501c0a tc/meson-use-our-version-def-h later to maint).
+
+ * The meson build procedure for Documentation/technical/ hierarchy was
+   missing necessary dependencies, which has been corrected.
+   (merge 1dca492edd sj/meson-doc-technical-dependency-fix later to maint).
+
+ * The "instaweb" bound only to local IP address without "--local" and
+   to all addresses with "--local", which was the other way around, when
+   using Python's http.server class, which has been corrected.
+   (merge 76baf97fa1 ak/instaweb-python-port-binding-fix later to maint).
+
+ * Document that it is insecure to use Personal Access Tokens, which
+   some hosting providers take as username/password, embedded in URLs.
+   (merge a90ff409f0 mh/doc-credential-helpers-with-pat later to maint).
+
+ * The help text from "git $cmd -h" appear on the standard output for
+   some $cmd and the standard error for others.  The built-in commands
+   have been fixed to show them on the standard output consistently.
+   (merge f66d1423f5 jc/show-usage-help later to maint).
+
+ * The meson-driven build is now aware of "git-subtree" housed in
+   contrib/subtree hierarchy.
+   (merge 8454b42f94 ps/build-meson-subtree later to maint).
+
+ * It was possible for "git unpack-objects" and "git index-pack" to
+   make an unaligned access, which has been corrected.
+   (merge 98046591b9 jk/pack-header-parse-alignment-fix later to maint).
+
+ * The "cache" credential back-end did not handle authtype correctly,
+   which has been corrected.
+   (merge 0b43274850 mh/credential-cache-authtype-request-fix later to maint).
+
+ * "git branch --sort=..." and "git for-each-ref --format=... --sort=..."
+   did not work as expected with some atoms, which has been corrected.
+   (merge c5490ce9d1 rs/ref-fitler-used-atoms-value-fix later to maint).
+
+ * reflog entries for symbolic ref updates were broken, which has been
+   corrected.
+   (merge 3519492430 kn/reflog-symref-fix later to maint).
+
+ * The trace2 code was not prepared to show a configuration variable
+   that is set to true using the valueless true syntax, which has been
+   corrected.
+   (merge 2fd367cf63 am/trace2-with-valueless-true later to maint).
+
+ * The "git refs migrate" command did not migrate the reflog for
+   refs/stash, which is the contents of the stashes, which has been
+   corrected.
+   (merge a0bea0978f ps/reflog-migration-with-logall-fix later to maint).
+
+ * Other code cleanup, docfix, build fix, etc.
+   (merge ddb5287894 jk/t7407-use-test-grep later to maint).
+   (merge 21e1b44865 aj/difftool-config-doc-fix later to maint).
+   (merge 6a63995335 mh/gitattr-doc-markup-fix later to maint).
+   (merge 43850dcf9c sk/unit-test-hash later to maint).
+   (merge 4ad47d2de3 jc/cli-doc-option-and-config later to maint).
+   (merge 2d0ff147e5 jp/t8002-printf-fix later to maint).
diff --git a/Documentation/RelNotes/2.5.0.txt b/Documentation/RelNotes/2.5.0.txt
new file mode 100644
index 0000000000..84723f912a
--- /dev/null
+++ b/Documentation/RelNotes/2.5.0.txt
@@ -0,0 +1,564 @@
+Git 2.5 Release Notes
+=====================
+
+Updates since v2.4
+------------------
+
+UI, Workflows & Features
+
+ * The bash completion script (in contrib/) learned a few options that
+   "git revert" takes.
+
+ * Whitespace breakages in deleted and context lines can also be
+   painted in the output of "git diff" and friends with the new
+   --ws-error-highlight option.
+
+ * List of commands shown by "git help" are grouped along the workflow
+   elements to help early learners.
+
+ * "git p4" now detects the filetype (e.g. binary) correctly even when
+   the files are opened exclusively.
+
+ * git p4 attempts to better handle branches in Perforce.
+
+ * "git p4" learned "--changes-block-size <n>" to read the changes in
+   chunks from Perforce, instead of making one call to "p4 changes"
+   that may trigger "too many rows scanned" error from Perforce.
+
+ * More workaround for Perforce's row number limit in "git p4".
+
+ * Unlike "$EDITOR" and "$GIT_EDITOR" that can hold the path to the
+   command and initial options (e.g. "/path/to/emacs -nw"), 'git p4'
+   did not let the shell interpolate the contents of the environment
+   variable that name the editor "$P4EDITOR" (and "$EDITOR", too).
+   This release makes it in line with the rest of Git, as well as with
+   Perforce.
+
+ * A new short-hand <branch>@{push} denotes the remote-tracking branch
+   that tracks the branch at the remote the <branch> would be pushed
+   to.
+
+ * "git show-branch --topics HEAD" (with no other arguments) did not
+   do anything interesting.  Instead, contrast the given revision
+   against all the local branches by default.
+
+ * A replacement for contrib/workdir/git-new-workdir that does not
+   rely on symbolic links and make sharing of objects and refs safer
+   by making the borrowee and borrowers aware of each other.
+
+   Consider this as still an experimental feature; its UI is still
+   likely to change.
+
+ * Tweak the sample "store" backend of the credential helper to honor
+   XDG configuration file locations when specified.
+
+ * A heuristic we use to catch mistyped paths on the command line
+   "git <cmd> <revs> <pathspec>" is to make sure that all the non-rev
+   parameters in the later part of the command line are names of the
+   files in the working tree, but that means "git grep $str -- \*.c"
+   must always be disambiguated with "--", because nobody sane will
+   create a file whose name literally is asterisk-dot-see.  Loosen the
+   heuristic to declare that with a wildcard string the user likely
+   meant to give us a pathspec.
+
+ * "git merge FETCH_HEAD" learned that the previous "git fetch" could
+   be to create an Octopus merge, i.e. recording multiple branches
+   that are not marked as "not-for-merge"; this allows us to lose an
+   old style invocation "git merge <msg> HEAD $commits..." in the
+   implementation of "git pull" script; the old style syntax can now
+   be deprecated (but not removed yet).
+
+ * Filter scripts were run with SIGPIPE disabled on the Git side,
+   expecting that they may not read what Git feeds them to filter.
+   We however treated a filter that does not read its input fully
+   before exiting as an error.  We no longer do and ignore EPIPE
+   when writing to feed the filter scripts.
+
+   This changes semantics, but arguably in a good way.  If a filter
+   can produce its output without fully consuming its input using
+   whatever magic, we now let it do so, instead of diagnosing it
+   as a programming error.
+
+ * Instead of dying immediately upon failing to obtain a lock, the
+   locking (of refs etc) retries after a short while with backoff.
+
+ * Introduce http.<url>.SSLCipherList configuration variable to tweak
+   the list of cipher suite to be used with libcURL when talking with
+   https:// sites.
+
+ * "git subtree" script (in contrib/) used "echo -n" to produce
+   progress messages in a non-portable way.
+
+ * "git subtree" script (in contrib/) does not have --squash option
+   when pushing, but the documentation and help text pretended as if
+   it did.
+
+ * The Git subcommand completion (in contrib/) no longer lists credential
+   helpers among candidates; they are not something the end user would
+   invoke interactively.
+
+ * The index file can be taught with "update-index --untracked-cache"
+   to optionally remember already seen untracked files, in order to
+   speed up "git status" in a working tree with tons of cruft.
+
+ * "git mergetool" learned to drive WinMerge as a backend.
+
+ * "git upload-pack" that serves "git fetch" can be told to serve
+   commits that are not at the tip of any ref, as long as they are
+   reachable from a ref, with uploadpack.allowReachableSHA1InWant
+   configuration variable.
+
+ * "git cat-file --batch(-check)" learned the "--follow-symlinks"
+   option that follows an in-tree symbolic link when asked about an
+   object via extended SHA-1 syntax, e.g. HEAD:RelNotes that points at
+   Documentation/RelNotes/2.5.0.txt.  With the new option, the command
+   behaves as if HEAD:Documentation/RelNotes/2.5.0.txt was given as
+   input instead.
+
+   Consider this as still an experimental and incomplete feature:
+
+    - We may want to do the same for in-index objects, e.g.
+      asking for :RelNotes with this option should give
+      :Documentation/RelNotes/2.5.0.txt, too
+
+    - "git cat-file --follow-symlinks blob HEAD:RelNotes"
+      may also be something we want to allow in the future.
+
+ * "git send-email" learned the alias file format used by the sendmail
+   program (in a simplified form; we obviously do not feed pipes).
+
+ * Traditionally, external low-level 3-way merge drivers are expected
+   to produce their results based solely on the contents of the three
+   variants given in temporary files named by %O, %A and %B on their
+   command line.  Additionally allow them to look at the final path
+   (given by %P).
+
+ * "git blame" learned blame.showEmail configuration variable.
+
+ * "git apply" cannot diagnose a patch corruption when the breakage is
+   to mark the length of the hunk shorter than it really is on the
+   hunk header line "@@ -l,k +m,n @@"; one special case it could is
+   when the hunk becomes no-op (e.g. k == n == 2 for two-line context
+   patch output), and it learned to do so in this special case.
+
+ * Add the "--allow-unknown-type" option to "cat-file" to allow
+   inspecting loose objects of an experimental or a broken type.
+
+ * Many long-running operations show progress eye-candy, even when
+   they are later backgrounded.  Hide the eye-candy when the process
+   is sent to the background instead.
+   (merge a4fb76c lm/squelch-bg-progress later to maint).
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * "unsigned char [20]" used throughout the code to represent object
+   names are being converted into a semi-opaque "struct object_id".
+   This effort is expected to interfere with other topics in flight,
+   but hopefully will give us one extra level of abstraction in the
+   end, when completed.
+
+ * for_each_ref() callback functions were taught to name the objects
+   not with "unsigned char sha1[20]" but with "struct object_id".
+
+ * Catch a programmer mistake to feed a pointer not an array to
+   ARRAY_SIZE() macro, by using a couple of GCC extensions.
+
+ * Some error messages in "git config" were emitted without calling
+   the usual error() facility.
+
+ * When "add--interactive" splits a hunk into two overlapping hunks
+   and then let the user choose only one, it sometimes feeds an
+   incorrect patch text to "git apply".  Add tests to demonstrate
+   this.
+
+   I have a slight suspicion that this may be
+   cf. <7vtzf77wjp.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx> coming back
+   and biting us (I seem to have said "let's run with this and see
+   what happens" back then).
+
+ * More line-ending tests.
+
+ * An earlier rewrite to use strbuf_getwholeline() instead of fgets(3)
+   to read packed-refs file revealed that the former is unacceptably
+   inefficient.  It has been optimized by using getdelim(3) when
+   available.
+
+ * The refs API uses ref_lock struct which had its own "int fd", even
+   though the same file descriptor was in the lock struct it contains.
+   Clean-up the code to lose this redundant field.
+
+ * There was a dead code that used to handle "git pull --tags" and
+   show special-cased error message, which was made irrelevant when
+   the semantics of the option changed back in Git 1.9 days.
+   (merge 19d122b pt/pull-tags-error-diag later to maint).
+
+ * Help us to find broken test script that splits the body part of the
+   test by mistaken use of wrong kind of quotes.
+   (merge d93d5d5 jc/test-prereq-validate later to maint).
+
+ * Developer support to automatically detect broken &&-chain in the
+   test scripts is now turned on by default.
+   (merge 92b269f jk/test-chain-lint later to maint).
+
+ * Error reporting mechanism used in "refs" API has been made more
+   consistent.
+
+ * "git pull" has more test coverage now.
+
+ * "git pull" has become more aware of the options meant for
+   underlying "git fetch" and then learned to use parse-options
+   parser.
+
+ * Clarify in the Makefile a guideline to decide use of USE_NSEC.
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.4
+----------------
+
+Unless otherwise noted, all the fixes since v2.4 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * Git 2.4 broke setting verbosity and progress levels on "git clone"
+   with native transports.
+   (merge 822f0c4 mh/clone-verbosity-fix later to maint).
+
+ * "git add -e" did not allow the user to abort the operation by
+   killing the editor.
+   (merge cb64800 jk/add-e-kill-editor later to maint).
+
+ * Memory usage of "git index-pack" has been trimmed by tens of
+   per-cent.
+   (merge f0e7f11 nd/slim-index-pack-memory-usage later to maint).
+
+ * "git rev-list --objects $old --not --all" to see if everything that
+   is reachable from $old is already connected to the existing refs
+   was very inefficient.
+   (merge b6e8a3b jk/still-interesting later to maint).
+
+ * "hash-object --literally" introduced in v2.2 was not prepared to
+   take a really long object type name.
+   (merge 1427a7f jc/hash-object later to maint).
+
+ * "git rebase --quiet" was not quite quiet when there is nothing to
+   do.
+   (merge 22946a9 jk/rebase-quiet-noop later to maint).
+
+ * The completion for "log --decorate=" parameter value was incorrect.
+   (merge af16bda sg/complete-decorate-full-not-long later to maint).
+
+ * "filter-branch" corrupted commit log message that ends with an
+   incomplete line on platforms with some "sed" implementations that
+   munge such a line.  Work it around by avoiding to use "sed".
+   (merge df06201 jk/filter-branch-use-of-sed-on-incomplete-line later to maint).
+
+ * "git daemon" fails to build from the source under NO_IPV6
+   configuration (regression in 2.4).
+   (merge d358f77 jc/daemon-no-ipv6-for-2.4.1 later to maint).
+
+ * Some time ago, "git blame" (incorrectly) lost the convert_to_git()
+   call when synthesizing a fake "tip" commit that represents the
+   state in the working tree, which broke folks who record the history
+   with LF line ending to make their project portable across platforms
+   while terminating lines in their working tree files with CRLF for
+   their platform.
+   (merge 4bf256d tb/blame-resurrect-convert-to-git later to maint).
+
+ * We avoid setting core.worktree when the repository location is the
+   ".git" directory directly at the top level of the working tree, but
+   the code misdetected the case in which the working tree is at the
+   root level of the filesystem (which arguably is a silly thing to
+   do, but still valid).
+   (merge 84ccad8 jk/init-core-worktree-at-root later to maint).
+
+ * "git commit --date=now" or anything that relies on approxidate lost
+   the daylight-saving-time offset.
+   (merge f6e6362 jc/epochtime-wo-tz later to maint).
+
+ * Access to objects in repositories that borrow from another one on a
+   slow NFS server unnecessarily got more expensive due to recent code
+   becoming more cautious in a naive way not to lose objects to pruning.
+   (merge ee1c6c3 jk/prune-mtime later to maint).
+
+ * The codepaths that read .gitignore and .gitattributes files have been
+   taught that these files encoded in UTF-8 may have UTF-8 BOM marker at
+   the beginning; this makes it in line with what we do for configuration
+   files already.
+   (merge 27547e5 cn/bom-in-gitignore later to maint).
+
+ * a few helper scripts in the test suite did not report errors
+   correctly.
+   (merge de248e9 ep/fix-test-lib-functions-report later to maint).
+
+ * The default $HOME/.gitconfig file created upon "git config --global"
+   that edits it had incorrectly spelled user.name and user.email
+   entries in it.
+   (merge 7e11052 oh/fix-config-default-user-name-section later to maint).
+
+ * "git cat-file bl $blob" failed to barf even though there is no
+   object type that is "bl".
+   (merge b7994af jk/type-from-string-gently later to maint).
+
+ * The usual "git diff" when seeing a file turning into a directory
+   showed a patchset to remove the file and create all files in the
+   directory, but "git diff --no-index" simply refused to work.  Also,
+   when asked to compare a file and a directory, imitate POSIX "diff"
+   and compare the file with the file with the same name in the
+   directory, instead of refusing to run.
+   (merge 0615173 jc/diff-no-index-d-f later to maint).
+
+ * "git rebase -i" moved the "current" command from "todo" to "done" a
+   bit too prematurely, losing a step when a "pick" did not even start.
+   (merge 8cbc57c ph/rebase-i-redo later to maint).
+
+ * The connection initiation code for "ssh" transport tried to absorb
+   differences between the stock "ssh" and Putty-supplied "plink" and
+   its derivatives, but the logic to tell that we are using "plink"
+   variants were too loose and falsely triggered when "plink" appeared
+   anywhere in the path (e.g. "/home/me/bin/uplink/ssh").
+   (merge baaf233 bc/connect-plink later to maint).
+
+ * We have prepended $GIT_EXEC_PATH and the path "git" is installed in
+   (typically "/usr/bin") to $PATH when invoking subprograms and hooks
+   for almost eternity, but the original use case the latter tried to
+   support was semi-bogus (i.e. install git to /opt/foo/git and run it
+   without having /opt/foo on $PATH), and more importantly it has
+   become less and less relevant as Git grew more mainstream (i.e. the
+   users would _want_ to have it on their $PATH).  Stop prepending the
+   path in which "git" is installed to users' $PATH, as that would
+   interfere the command search order people depend on (e.g. they may
+   not like versions of programs that are unrelated to Git in /usr/bin
+   and want to override them by having different ones in /usr/local/bin
+   and have the latter directory earlier in their $PATH).
+   (merge a0b4507 jk/git-no-more-argv0-path-munging later to maint).
+
+ * core.excludesfile (defaulting to $XDG_HOME/git/ignore) is supposed
+   to be overridden by repository-specific .git/info/exclude file, but
+   the order was swapped from the beginning. This belatedly fixes it.
+   (merge 099d2d8 jc/gitignore-precedence later to maint).
+
+ * There was a commented-out (instead of being marked to expect
+   failure) test that documented a breakage that was fixed since the
+   test was written; turn it into a proper test.
+   (merge 66d2e04 sb/t1020-cleanup later to maint).
+
+ * The "log --decorate" enhancement in Git 2.4 that shows the commit
+   at the tip of the current branch e.g. "HEAD -> master", did not
+   work with --decorate=full.
+   (merge 429ad20 mg/log-decorate-HEAD later to maint).
+
+ * The ref API did not handle cases where 'refs/heads/xyzzy/frotz' is
+   removed at the same time as 'refs/heads/xyzzy' is added (or vice
+   versa) very well.
+   (merge c628edf mh/ref-directory-file later to maint).
+
+ * Multi-ref transaction support we merged a few releases ago
+   unnecessarily kept many file descriptors open, risking to fail with
+   resource exhaustion.  This is for 2.4.x track.
+   (merge 185ce3a mh/write-refs-sooner-2.4 later to maint).
+
+ * "git bundle verify" did not diagnose extra parameters on the
+   command line.
+   (merge 7886cfa ps/bundle-verify-arg later to maint).
+
+ * Various documentation mark-up fixes to make the output more
+   consistent in general and also make AsciiDoctor (an alternative
+   formatter) happier.
+   (merge d0258b9 jk/asciidoc-markup-fix later to maint).
+   (merge ad3967a jk/stripspace-asciidoctor-fix later to maint).
+   (merge 975e382 ja/tutorial-asciidoctor-fix later to maint).
+
+ * The code to read pack-bitmap wanted to allocate a few hundred
+   pointers to a structure, but by mistake allocated and leaked memory
+   enough to hold that many actual structures.  Correct the allocation
+   size and also have it on stack, as it is small enough.
+   (merge 599dc76 rs/plug-leak-in-pack-bitmaps later to maint).
+
+ * The pull.ff configuration was supposed to override the merge.ff
+   configuration, but it didn't.
+   (merge db9bb28 pt/pull-ff-vs-merge-ff later to maint).
+
+ * "git pull --log" and "git pull --no-log" worked as expected, but
+   "git pull --log=20" did not.
+   (merge 5061a44 pt/pull-log-n later to maint).
+
+ * "git rerere forget" in a repository without rerere enabled gave a
+   cryptic error message; it should be a silent no-op instead.
+   (merge 0544574 jk/rerere-forget-check-enabled later to maint).
+
+ * "git rebase -i" fired post-rewrite hook when it shouldn't (namely,
+   when it was told to stop sequencing with 'exec' insn).
+   (merge 141ff8f mm/rebase-i-post-rewrite-exec later to maint).
+
+ * Clarify that "log --raw" and "log --format=raw" are unrelated
+   concepts.
+   (merge 92de921 mm/log-format-raw-doc later to maint).
+
+ * Make "git stash something --help" error out, so that users can
+   safely say "git stash drop --help".
+   (merge 5ba2831 jk/stash-options later to maint).
+
+ * The clean/smudge interface did not work well when filtering an
+   empty contents (failed and then passed the empty input through).
+   It can be argued that a filter that produces anything but empty for
+   an empty input is nonsense, but if the user wants to do strange
+   things, then why not?
+   (merge f6a1e1e jh/filter-empty-contents later to maint).
+
+ * Communication between the HTTP server and http_backend process can
+   lead to a dead-lock when relaying a large ref negotiation request.
+   Diagnose the situation better, and mitigate it by reading such a
+   request first into core (to a reasonable limit).
+   (merge 636614f jk/http-backend-deadlock later to maint).
+
+ * "git clean pathspec..." tried to lstat(2) and complain even for
+   paths outside the given pathspec.
+   (merge 838d6a9 dt/clean-pathspec-filter-then-lstat later to maint).
+
+ * Recent "git prune" traverses young unreachable objects to safekeep
+   old objects in the reachability chain from them, which sometimes
+   caused error messages that are unnecessarily alarming.
+   (merge ce4e7b2 jk/squelch-missing-link-warning-for-unreachable later to maint).
+
+ * The configuration reader/writer uses mmap(2) interface to access
+   the files; when we find a directory, it barfed with "Out of memory?".
+   (merge 9ca0aaf jk/diagnose-config-mmap-failure later to maint).
+
+ * "color.diff.plain" was a misnomer; give it 'color.diff.context' as
+   a more logical synonym.
+   (merge 8dbf3eb jk/color-diff-plain-is-context later to maint).
+
+ * The setup code used to die when core.bare and core.worktree are set
+   inconsistently, even for commands that do not need working tree.
+   (merge fada767 jk/die-on-bogus-worktree-late later to maint).
+
+ * Recent Mac OS X updates breaks the logic to detect that the machine
+   is on the AC power in the sample pre-auto-gc script.
+   (merge c54c7b3 pa/auto-gc-mac-osx later to maint).
+
+ * "git commit --cleanup=scissors" was not careful enough to protect
+   against getting fooled by a line that looked like scissors.
+   (merge fbfa097 sg/commit-cleanup-scissors later to maint).
+
+ * "Have we lost a race with competing repack?" check was too
+   expensive, especially while receiving a huge object transfer
+   that runs index-pack (e.g. "clone" or "fetch").
+   (merge 0eeb077 jk/index-pack-reduce-recheck later to maint).
+
+ * The tcsh completion writes a bash scriptlet but that would have
+   failed for users with noclobber set.
+   (merge 0b1f688 af/tcsh-completion-noclobber later to maint).
+
+ * "git for-each-ref" reported "missing object" for 0{40} when it
+   encounters a broken ref.  The lack of object whose name is 0{40} is
+   not the problem; the ref being broken is.
+   (merge 501cf47 mh/reporting-broken-refs-from-for-each-ref later to maint).
+
+ * Various fixes around "git am" that applies a patch to a history
+   that is not there yet.
+   (merge 6ea3b67 pt/am-abort-fix later to maint).
+
+ * "git fsck" used to ignore missing or invalid objects recorded in reflog.
+   (merge 19bf6c9 mh/fsck-reflog-entries later to maint).
+
+ * "git format-patch --ignore-if-upstream A..B" did not like to be fed
+   tags as boundary commits.
+   (merge 9b7a61d jc/do-not-feed-tags-to-clear-commit-marks later to maint).
+
+ * "git fetch --depth=<depth>" and "git clone --depth=<depth>" issued
+   a shallow transfer request even to an upload-pack that does not
+   support the capability.
+   (merge eb86a50 me/fetch-into-shallow-safety later to maint).
+
+ * "git rebase" did not exit with failure when format-patch it invoked
+   failed for whatever reason.
+   (merge 60d708b cb/rebase-am-exit-code later to maint).
+
+ * Fix a small bug in our use of umask() return value.
+   (merge 3096b2e jk/fix-refresh-utime later to maint).
+
+ * An ancient test framework enhancement to allow color was not
+   entirely correct; this makes it work even when tput needs to read
+   from the ~/.terminfo under the user's real HOME directory.
+   (merge d5c1b7c rh/test-color-avoid-terminfo-in-original-home later to maint).
+
+ * A minor bugfix when pack bitmap is used with "rev-list --count".
+   (merge c8a70d3 jk/rev-list-no-bitmap-while-pruning later to maint).
+
+ * "git config" failed to update the configuration file when the
+   underlying filesystem is incapable of renaming a file that is still
+   open.
+   (merge 7a64592 kb/config-unmap-before-renaming later to maint).
+
+ * Avoid possible ssize_t to int truncation.
+   (merge 6c8afe4 mh/strbuf-read-file-returns-ssize-t later to maint).
+
+ * When you say "!<ENTER>" while running say "git log", you'd confuse
+   yourself in the resulting shell, that may look as if you took
+   control back to the original shell you spawned "git log" from but
+   that isn't what is happening.  To that new shell, we leaked
+   GIT_PAGER_IN_USE environment variable that was meant as a local
+   communication between the original "Git" and subprocesses that was
+   spawned by it after we launched the pager, which caused many
+   "interesting" things to happen, e.g. "git diff | cat" still paints
+   its output in color by default.
+
+   Stop leaking that environment variable to the pager's half of the
+   fork; we only need it on "Git" side when we spawn the pager.
+   (merge 124b519 jc/unexport-git-pager-in-use-in-pager later to maint).
+
+ * Abandoning an already applied change in "git rebase -i" with
+   "--continue" left CHERRY_PICK_HEAD and confused later steps.
+   (merge 0e0aff4 js/rebase-i-clean-up-upon-continue-to-skip later to maint).
+
+ * We used to ask libCURL to use the most secure authentication method
+   available when talking to an HTTP proxy only when we were told to
+   talk to one via configuration variables.  We now ask libCURL to
+   always use the most secure authentication method, because the user
+   can tell libCURL to use an HTTP proxy via an environment variable
+   without using configuration variables.
+   (merge 5841520 et/http-proxyauth later to maint).
+
+ * A fix to a minor regression to "git fsck" in v2.2 era that started
+   complaining about a body-less tag object when it lacks a separator
+   empty line after its header to separate it with a non-existent body.
+   (merge 84d18c0 jc/fsck-retire-require-eoh later to maint).
+
+ * Code cleanups and documentation updates.
+   (merge 0269f96 mm/usage-log-l-can-take-regex later to maint).
+   (merge 64f2589 nd/t1509-chroot-test later to maint).
+   (merge d201a1e sb/test-bitmap-free-at-end later to maint).
+   (merge 05bfc7d sb/line-log-plug-pairdiff-leak later to maint).
+   (merge 846e5df pt/xdg-config-path later to maint).
+   (merge 1154aa4 jc/plug-fmt-merge-msg-leak later to maint).
+   (merge 319b678 jk/sha1-file-reduce-useless-warnings later to maint).
+   (merge 9a35c14 fg/document-commit-message-stripping later to maint).
+   (merge bbf431c ps/doc-packfile-vs-pack-file later to maint).
+   (merge 309a9e3 jk/skip-http-tests-under-no-curl later to maint).
+   (merge ccd593c dl/branch-error-message later to maint).
+   (merge 22570b6 rs/janitorial later to maint).
+   (merge 5c2a581 mc/commit-doc-grammofix later to maint).
+   (merge ce41720 ah/usage-strings later to maint).
+   (merge e6a268c sb/glossary-submodule later to maint).
+   (merge ec48a76 sb/submodule-doc-intro later to maint).
+   (merge 14f8b9b jk/clone-dissociate later to maint).
+   (merge 055c7e9 sb/pack-protocol-mention-smart-http later to maint).
+   (merge 7c37a5d jk/make-fix-dependencies later to maint).
+   (merge fc0aa39 sg/merge-summary-config later to maint).
+   (merge 329af6c pt/t0302-needs-sanity later to maint).
+   (merge d614f07 fk/doc-format-patch-vn later to maint).
+   (merge 72dbb36 sg/completion-commit-cleanup later to maint).
+   (merge e654eb2 es/utf8-stupid-compiler-workaround later to maint).
+   (merge 34b935c es/osx-header-pollutes-mask-macro later to maint).
+   (merge ab7fade jc/prompt-document-ps1-state-separator later to maint).
+   (merge 25f600e mm/describe-doc later to maint).
+   (merge 83fe167 mm/branch-doc-updates later to maint).
+   (merge 75d2e5a ls/hint-rev-list-count later to maint).
+   (merge edc8f71 cb/subtree-tests-update later to maint).
+   (merge 5330e6e sb/p5310-and-chain later to maint).
+   (merge c4ac525 tb/checkout-doc later to maint).
+   (merge e479c5f jk/pretty-encoding-doc later to maint).
+   (merge 7e837c6 ss/clone-guess-dir-name-simplify later to maint).
diff --git a/Documentation/RelNotes/2.5.1.txt b/Documentation/RelNotes/2.5.1.txt
new file mode 100644
index 0000000000..b70553308a
--- /dev/null
+++ b/Documentation/RelNotes/2.5.1.txt
@@ -0,0 +1,65 @@
+Git v2.5.1 Release Notes
+========================
+
+Fixes since v2.5
+----------------
+
+ * Running an aliased command from a subdirectory when the .git thing
+   in the working tree is a gitfile pointing elsewhere did not work.
+
+ * Often a fast-import stream builds a new commit on top of the
+   previous commit it built, and it often unconditionally emits a
+   "from" command to specify the first parent, which can be omitted in
+   such a case.  This caused fast-import to forget the tree of the
+   previous commit and then re-read it from scratch, which was
+   inefficient.  Optimize for this common case.
+
+ * The "rev-parse --parseopt" mode parsed the option specification
+   and the argument hint in a strange way to allow '=' and other
+   special characters in the option name while forbidding them from
+   the argument hint.  This made it impossible to define an option
+   like "--pair <key>=<value>" with "pair=key=value" specification,
+   which instead would have defined a "--pair=key <value>" option.
+
+ * A "rebase" replays changes of the local branch on top of something
+   else, as such they are placed in stage #3 and referred to as
+   "theirs", while the changes in the new base, typically a foreign
+   work, are placed in stage #2 and referred to as "ours".  Clarify
+   the "checkout --ours/--theirs".
+
+ * An experimental "untracked cache" feature used uname(2) in a
+   slightly unportable way.
+
+ * "sparse checkout" misbehaved for a path that is excluded from the
+   checkout when switching between branches that differ at the path.
+
+ * The low-level "git send-pack" did not honor 'user.signingkey'
+   configuration variable when sending a signed-push.
+
+ * An attempt to delete a ref by pushing into a repository whose HEAD
+   symbolic reference points at an unborn branch that cannot be
+   created due to ref D/F conflict (e.g. refs/heads/a/b exists, HEAD
+   points at refs/heads/a) failed.
+
+ * "git subtree" (in contrib/) depended on "git log" output to be
+   stable, which was a no-no.  Apply a workaround to force a
+   particular date format.
+
+ * "git clone $URL" in recent releases of Git contains a regression in
+   the code that invents a new repository name incorrectly based on
+   the $URL.  This has been corrected.
+   (merge db2e220 jk/guess-repo-name-regression-fix later to maint).
+
+ * Running tests with the "-x" option to make them verbose had some
+   unpleasant interactions with other features of the test suite.
+   (merge 9b5fe78 jk/test-with-x later to maint).
+
+ * "git pull" in recent releases of Git has a regression in the code
+   that allows custom path to the --upload-pack=<program>.  This has
+   been corrected.
+
+ * pipe() emulation used in Git for Windows looked at a wrong variable
+   when checking for an error from an _open_osfhandle() call.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.5.2.txt b/Documentation/RelNotes/2.5.2.txt
new file mode 100644
index 0000000000..3f749398bb
--- /dev/null
+++ b/Documentation/RelNotes/2.5.2.txt
@@ -0,0 +1,63 @@
+Git v2.5.2 Release Notes
+========================
+
+Fixes since v2.5.1
+------------------
+
+ * "git init empty && git -C empty log" said "bad default revision 'HEAD'",
+   which was found to be a bit confusing to new users.
+
+ * The "interpret-trailers" helper mistook a multi-paragraph title of
+   a commit log message with a colon in it as the end of the trailer
+   block.
+
+ * When re-priming the cache-tree opportunistically while committing
+   the in-core index as-is, we mistakenly invalidated the in-core
+   index too aggressively, causing the experimental split-index code
+   to unnecessarily rewrite the on-disk index file(s).
+
+ * "git archive" did not use zip64 extension when creating an archive
+   with more than 64k entries, which nobody should need, right ;-)?
+
+ * The code in "multiple-worktree" support that attempted to recover
+   from an inconsistent state updated an incorrect file.
+
+ * "git rev-list" does not take "--notes" option, but did not complain
+   when one is given.
+
+ * Because the configuration system does not allow "alias.0foo" and
+   "pager.0foo" as the configuration key, the user cannot use '0foo'
+   as a custom command name anyway, but "git 0foo" tried to look these
+   keys up and emitted useless warnings before saying '0foo is not a
+   git command'.  These warning messages have been squelched.
+
+ * We recently rewrote one of the build scripts in Perl, which made it
+   necessary to have Perl to build Git.  Reduced Perl dependency by
+   rewriting it again using sed.
+
+ * t1509 test that requires a dedicated VM environment had some
+   bitrot, which has been corrected.
+
+ * strbuf_read() used to have one extra iteration (and an unnecessary
+   strbuf_grow() of 8kB), which was eliminated.
+
+ * The codepath to produce error messages had a hard-coded limit to
+   the size of the message, primarily to avoid memory allocation while
+   calling die().
+
+ * When trying to see that an object does not exist, a state errno
+   leaked from our "first try to open a packfile with O_NOATIME and
+   then if it fails retry without it" logic on a system that refuses
+   O_NOATIME.  This confused us and caused us to die, saying that the
+   packfile is unreadable, when we should have just reported that the
+   object does not exist in that packfile to the caller.
+
+ * An off-by-one error made "git remote" to mishandle a remote with a
+   single letter nickname.
+
+ * A handful of codepaths that used to use fixed-sized arrays to hold
+   pathnames have been corrected to use strbuf and other mechanisms to
+   allow longer pathnames without fearing overflows.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.5.3.txt b/Documentation/RelNotes/2.5.3.txt
new file mode 100644
index 0000000000..d1436857cb
--- /dev/null
+++ b/Documentation/RelNotes/2.5.3.txt
@@ -0,0 +1,17 @@
+Git v2.5.3 Release Notes
+========================
+
+Fixes since v2.5.2
+------------------
+
+ * The experimental untracked-cache feature were buggy when paths with
+   a few levels of subdirectories are involved.
+
+ * Recent versions of scripted "git am" has a performance regression
+   in "git am --skip" codepath, which no longer exists in the
+   built-in version on the 'master' front.  Fix the regression in
+   the last scripted version that appear in 2.5.x maintenance track
+   and older.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.5.4.txt b/Documentation/RelNotes/2.5.4.txt
new file mode 100644
index 0000000000..b8a2f93ee7
--- /dev/null
+++ b/Documentation/RelNotes/2.5.4.txt
@@ -0,0 +1,18 @@
+Git v2.5.4 Release Notes
+========================
+
+Fixes since v2.5.4
+------------------
+
+ * xdiff code we use to generate diffs is not prepared to handle
+   extremely large files.  It uses "int" in many places, which can
+   overflow if we have a very large number of lines or even bytes in
+   our input files, for example.  Cap the input size to somewhere
+   around 1GB for now.
+
+ * Some protocols (like git-remote-ext) can execute arbitrary code
+   found in the URL.  The URLs that submodules use may come from
+   arbitrary sources (e.g., .gitmodules files in a remote
+   repository), and can hurt those who blindly enable recursive
+   fetch.  Restrict the allowed protocols to well known and safe
+   ones.
diff --git a/Documentation/RelNotes/2.5.5.txt b/Documentation/RelNotes/2.5.5.txt
new file mode 100644
index 0000000000..37eae9a2d9
--- /dev/null
+++ b/Documentation/RelNotes/2.5.5.txt
@@ -0,0 +1,11 @@
+Git v2.5.5 Release Notes
+========================
+
+Fixes since v2.5.4
+------------------
+
+ * Bugfix patches were backported from the 'master' front to plug heap
+   corruption holes, to catch integer overflow in the computation of
+   pathname lengths, and to get rid of the name_path API.  Both of
+   these would have resulted in writing over an under-allocated buffer
+   when formulating pathnames while tree traversal.
diff --git a/Documentation/RelNotes/2.5.6.txt b/Documentation/RelNotes/2.5.6.txt
new file mode 100644
index 0000000000..9cd025bb1c
--- /dev/null
+++ b/Documentation/RelNotes/2.5.6.txt
@@ -0,0 +1,12 @@
+Git v2.5.6 Release Notes
+========================
+
+Fixes since v2.5.5
+------------------
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
diff --git a/Documentation/RelNotes/2.6.0.txt b/Documentation/RelNotes/2.6.0.txt
new file mode 100644
index 0000000000..7288aaf716
--- /dev/null
+++ b/Documentation/RelNotes/2.6.0.txt
@@ -0,0 +1,370 @@
+Git 2.6 Release Notes
+=====================
+
+Updates since v2.5
+------------------
+
+UI, Workflows & Features
+
+ * An asterisk as a substring (as opposed to the entirety) of a path
+   component for both side of a refspec, e.g.
+   "refs/heads/o*:refs/remotes/heads/i*", is now allowed.
+
+ * New userdiff pattern definition for fountain screenwriting markup
+   format has been added.
+
+ * "git log" and friends learned a new "--date=format:..." option to
+   format timestamps using system's strftime(3).
+
+ * "git fast-import" learned to respond to the get-mark command via
+   its cat-blob-fd interface.
+
+ * "git rebase -i" learned "drop commit-object-name subject" command
+   as another way to skip replaying of a commit.
+
+ * A new configuration variable can enable "--follow" automatically
+   when "git log" is run with one pathspec argument.
+
+ * "git status" learned to show a more detailed information regarding
+   the "rebase -i" session in progress.
+
+ * "git cat-file" learned "--batch-all-objects" option to enumerate all
+   available objects in the repository more quickly than "rev-list
+   --all --objects" (the output includes unreachable objects, though).
+
+ * "git fsck" learned to ignore errors on a set of known-to-be-bad
+   objects, and also allows the warning levels of various kinds of
+   non-critical breakages to be tweaked.
+
+ * "git rebase -i"'s list of todo is made configurable.
+
+ * "git send-email" now performs alias-expansion on names that are
+   given via --cccmd, etc.
+
+ * An environment variable GIT_REPLACE_REF_BASE tells Git to look into
+   refs hierarchy other than refs/replace/ for the object replacement
+   data.
+
+ * Allow untracked cache (experimental) to be used when sparse
+   checkout (experimental) is also in use.
+
+ * "git pull --rebase" has been taught to pay attention to
+   rebase.autostash configuration.
+
+ * The command-line completion script (in contrib/) has been updated.
+
+ * A negative !ref entry in multi-value transfer.hideRefs
+   configuration can be used to say "don't hide this one".
+
+ * After "git am" without "-3" stops, running "git am -3" pays attention
+   to "-3" only for the patch that caused the original invocation
+   to stop.
+
+ * When linked worktree is used, simultaneous "notes merge" instances
+   for the same ref in refs/notes/* are prevented from stomping on
+   each other.
+
+ * "git send-email" learned a new option --smtp-auth to limit the SMTP
+   AUTH mechanisms to be used to a subset of what the system library
+   supports.
+
+ * A new configuration variable http.sslVersion can be used to specify
+   what specific version of SSL/TLS to use to make a connection.
+
+ * "git notes merge" can be told with "--strategy=<how>" option how to
+   automatically handle conflicts; this can now be configured by
+   setting notes.mergeStrategy configuration variable.
+
+ * "git log --cc" did not show any patch, even though most of the time
+   the user meant "git log --cc -p -m" to see patch output for commits
+   with a single parent, and combined diff for merge commits.  The
+   command is taught to DWIM "--cc" (without "--raw" and other forms
+   of output specification) to "--cc -p -m".
+
+ * "git config --list" output was hard to parse when values consist of
+   multiple lines.  "--name-only" option is added to help this.
+
+ * A handful of usability & cosmetic fixes to gitk and l10n updates.
+
+ * A completely empty e-mail address <> is now allowed in the authors
+   file used by git-svn, to match the way it accepts the output from
+   authors-prog.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * In preparation for allowing different "backends" to store the refs
+   in a way different from the traditional "one ref per file in
+   $GIT_DIR or in a $GIT_DIR/packed-refs file" filesystem storage,
+   direct filesystem access to ref-like things like CHERRY_PICK_HEAD
+   from scripts and programs has been reduced.
+
+ * Computation of untracked status indicator by bash prompt
+   script (in contrib/) has been optimized.
+
+ * Memory use reduction when commit-slab facility is used to annotate
+   sparsely (which is not recommended in the first place).
+
+ * Clean up refs API and make "git clone" less intimate with the
+   implementation detail.
+
+ * "git pull" was reimplemented in C.
+
+ * The packet tracing machinery allows to capture an incoming pack
+   data to a file for debugging.
+
+ * Move machinery to parse human-readable scaled numbers like 1k, 4M,
+   and 2G as an option parameter's value from pack-objects to
+   parse-options API, to make it available to other codepaths.
+
+ * "git verify-tag" and "git verify-commit" have been taught to share
+   more code, and then learned to optionally show the verification
+   message from the underlying GPG implementation.
+
+ * Various enhancements around "git am" reading patches generated by
+   foreign SCM have been made.
+
+ * Ref listing by "git branch -l" and "git tag -l" commands has
+   started to be rebuilt, based on the for-each-ref machinery.
+
+ * The code to perform multi-tree merges has been taught to repopulate
+   the cache-tree upon a successful merge into the index, so that
+   subsequent "diff-index --cached" (hence "status") and "write-tree"
+   (hence "commit") will go faster.
+
+   The same logic in "git checkout" may now be removed, but that is a
+   separate issue.
+
+ * Tests that assume how reflogs are represented on the filesystem too
+   much have been corrected.
+
+ * "git am" has been rewritten in "C".
+
+ * git_path() and mkpath() are handy helper functions but it is easy
+   to misuse, as the callers need to be careful to keep the number of
+   active results below 4.  Their uses have been reduced.
+
+ * The "lockfile" API has been rebuilt on top of a new "tempfile" API.
+
+ * To prepare for allowing a different "ref" backend to be plugged in
+   to the system, update_ref()/delete_ref() have been taught about
+   ref-like things like MERGE_HEAD that are per-worktree (they will
+   always be written to the filesystem inside $GIT_DIR).
+
+ * The gitmodules API that is accessed from the C code learned to
+   cache stuff lazily.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.5
+----------------
+
+Unless otherwise noted, all the fixes since v2.5 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git subtree" (in contrib/) depended on "git log" output to be
+   stable, which was a no-no.  Apply a workaround to force a
+   particular date format.
+   (merge e7aac44 da/subtree-date-confusion later to maint).
+
+ * An attempt to delete a ref by pushing into a repository whose HEAD
+   symbolic reference points at an unborn branch that cannot be
+   created due to ref D/F conflict (e.g. refs/heads/a/b exists, HEAD
+   points at refs/heads/a) failed.
+   (merge b112b14 jx/do-not-crash-receive-pack-wo-head later to maint).
+
+ * The low-level "git send-pack" did not honor 'user.signingkey'
+   configuration variable when sending a signed-push.
+   (merge d830d39 db/send-pack-user-signingkey later to maint).
+
+ * "sparse checkout" misbehaved for a path that is excluded from the
+   checkout when switching between branches that differ at the path.
+   (merge 7d78241 as/sparse-checkout-removal later to maint).
+
+ * An experimental "untracked cache" feature used uname(2) in a
+   slightly unportable way.
+   (merge 100e433 cb/uname-in-untracked later to maint).
+
+ * A "rebase" replays changes of the local branch on top of something
+   else, as such they are placed in stage #3 and referred to as
+   "theirs", while the changes in the new base, typically a foreign
+   work, are placed in stage #2 and referred to as "ours".  Clarify
+   the "checkout --ours/--theirs".
+   (merge f303016 se/doc-checkout-ours-theirs later to maint).
+
+ * The "rev-parse --parseopt" mode parsed the option specification
+   and the argument hint in a strange way to allow '=' and other
+   special characters in the option name while forbidding them from
+   the argument hint.  This made it impossible to define an option
+   like "--pair <key>=<value>" with "pair=key=value" specification,
+   which instead would have defined a "--pair=key <value>" option.
+   (merge 2d893df ib/scripted-parse-opt-better-hint-string later to maint).
+
+ * Often a fast-import stream builds a new commit on top of the
+   previous commit it built, and it often unconditionally emits a
+   "from" command to specify the first parent, which can be omitted in
+   such a case.  This caused fast-import to forget the tree of the
+   previous commit and then re-read it from scratch, which was
+   inefficient.  Optimize for this common case.
+   (merge 0df3245 mh/fast-import-optimize-current-from later to maint).
+
+ * Running an aliased command from a subdirectory when the .git thing
+   in the working tree is a gitfile pointing elsewhere did not work.
+   (merge d95138e nd/export-worktree later to maint).
+
+ * "Is this subdirectory a separate repository that should not be
+   touched?" check "git clean" was inefficient.  This was replaced
+   with a more optimized check.
+   (merge fbf2fec ee/clean-remove-dirs later to maint).
+
+ * The "new-worktree-mode" hack in "checkout" that was added in
+   nd/multiple-work-trees topic has been removed by updating the
+   implementation of new "worktree add".
+   (merge 65f9b75 es/worktree-add-cleanup later to maint).
+
+ * Remove remaining cruft from  "git checkout --to", which
+   transitioned to "git worktree add".
+   (merge 114ff88 es/worktree-add later to maint).
+
+ * An off-by-one error made "git remote" to mishandle a remote with a
+   single letter nickname.
+   (merge bc598c3 mh/get-remote-group-fix later to maint).
+
+ * "git clone $URL", when cloning from a site whose sole purpose is to
+   host a single repository (hence, no path after <scheme>://<site>/),
+   tried to use the site name as the new repository name, but did not
+   remove username or password when <site> part was of the form
+   <user>@<pass>:<host>.  The code is taught to redact these.
+   (merge adef956 ps/guess-repo-name-at-root later to maint).
+
+ * Running tests with the "-x" option to make them verbose had some
+   unpleasant interactions with other features of the test suite.
+   (merge 9b5fe78 jk/test-with-x later to maint).
+
+ * t1509 test that requires a dedicated VM environment had some
+   bitrot, which has been corrected.
+   (merge faacc5a ps/t1509-chroot-test-fixup later to maint).
+
+ * "git pull" in recent releases of Git has a regression in the code
+   that allows custom path to the --upload-pack=<program>.  This has
+   been corrected.
+
+   Note that this is irrelevant for 'master' with "git pull" rewritten
+   in C.
+   (merge 13e0e28 mm/pull-upload-pack later to maint).
+
+ * When trying to see that an object does not exist, a state errno
+   leaked from our "first try to open a packfile with O_NOATIME and
+   then if it fails retry without it" logic on a system that refuses
+   O_NOATIME.  This confused us and caused us to die, saying that the
+   packfile is unreadable, when we should have just reported that the
+   object does not exist in that packfile to the caller.
+   (merge dff6f28 cb/open-noatime-clear-errno later to maint).
+
+ * The codepath to produce error messages had a hard-coded limit to
+   the size of the message, primarily to avoid memory allocation while
+   calling die().
+   (merge f4c3edc jk/long-error-messages later to maint).
+
+ * strbuf_read() used to have one extra iteration (and an unnecessary
+   strbuf_grow() of 8kB), which was eliminated.
+   (merge 3ebbd00 jh/strbuf-read-use-read-in-full later to maint).
+
+ * We rewrote one of the build scripts in Perl but this reimplements
+   in Bourne shell.
+   (merge 57cee8a sg/help-group later to maint).
+
+ * The experimental untracked-cache feature were buggy when paths with
+   a few levels of subdirectories are involved.
+   (merge 73f9145 dt/untracked-subdir later to maint).
+
+ * "interpret-trailers" helper mistook a single-liner log message that
+   has a colon as the end of existing trailer.
+
+ * The "interpret-trailers" helper mistook a multi-paragraph title of
+   a commit log message with a colon in it as the end of the trailer
+   block.
+   (merge 5c99995 cc/trailers-corner-case-fix later to maint).
+
+ * "git describe" without argument defaulted to describe the HEAD
+   commit, but "git describe --contains" didn't.  Arguably, in a
+   repository used for active development, such defaulting would not
+   be very useful as the tip of branch is typically not tagged, but it
+   is better to be consistent.
+   (merge 2bd0706 sg/describe-contains later to maint).
+
+ * The client side codepaths in "git push" have been cleaned up
+   and the user can request to perform an optional "signed push",
+   i.e. sign only when the other end accepts signed push.
+   (merge 68c757f db/push-sign-if-asked later to maint).
+
+ * Because the configuration system does not allow "alias.0foo" and
+   "pager.0foo" as the configuration key, the user cannot use '0foo'
+   as a custom command name anyway, but "git 0foo" tried to look these
+   keys up and emitted useless warnings before saying '0foo is not a
+   git command'.  These warning messages have been squelched.
+   (merge 9e9de18 jk/fix-alias-pager-config-key-warnings later to maint).
+
+ * "git rev-list" does not take "--notes" option, but did not complain
+   when one is given.
+   (merge 2aea7a5 jk/rev-list-has-no-notes later to maint).
+
+ * When re-priming the cache-tree opportunistically while committing
+   the in-core index as-is, we mistakenly invalidated the in-core
+   index too aggressively, causing the experimental split-index code
+   to unnecessarily rewrite the on-disk index file(s).
+   (merge 475a344 dt/commit-preserve-base-index-upon-opportunistic-cache-tree-update later to maint).
+
+ * "git archive" did not use zip64 extension when creating an archive
+   with more than 64k entries, which nobody should need, right ;-)?
+   (merge 88329ca rs/archive-zip-many later to maint).
+
+ * The code in "multiple-worktree" support that attempted to recover
+   from an inconsistent state updated an incorrect file.
+   (merge 82fde87 nd/fixup-linked-gitdir later to maint).
+
+ * On case insensitive systems, "git p4" did not work well with client
+   specs.
+
+ * "git init empty && git -C empty log" said "bad default revision 'HEAD'",
+   which was found to be a bit confusing to new users.
+   (merge ce11360 jk/log-missing-default-HEAD later to maint).
+
+ * Recent versions of scripted "git am" has a performance regression in
+   "git am --skip" codepath, which no longer exists in the built-in
+   version on the 'master' front.  Fix the regression in the last
+   scripted version that appear in 2.5.x maintenance track and older.
+   (merge b9d6689 js/maint-am-skip-performance-regression later to maint).
+
+ * The branch descriptions that are set with "git branch --edit-description"
+   option were used in many places but they weren't clearly documented.
+   (merge 561d2b7 po/doc-branch-desc later to maint).
+
+ * Code cleanups and documentation updates.
+   (merge 1c601af es/doc-clean-outdated-tools later to maint).
+   (merge 3581304 kn/tag-doc-fix later to maint).
+   (merge 3a59e59 kb/i18n-doc later to maint).
+   (merge 45abdee sb/remove-unused-var-from-builtin-add later to maint).
+   (merge 14691e3 sb/parse-options-codeformat later to maint).
+   (merge 4a6ada3 ad/bisect-cleanup later to maint).
+   (merge da4c5ad ta/docfix-index-format-tech later to maint).
+   (merge ae25fd3 sb/check-return-from-read-ref later to maint).
+   (merge b3325df nd/dwim-wildcards-as-pathspecs later to maint).
+   (merge 7aa9b9b sg/wt-status-header-inclusion later to maint).
+   (merge f04c690 as/docfix-reflog-expire-unreachable later to maint).
+   (merge 1269847 sg/t3020-typofix later to maint).
+   (merge 8b54c23 jc/calloc-pathspec later to maint).
+   (merge a6926b8 po/po-readme later to maint).
+   (merge 54d160e ss/fix-config-fd-leak later to maint).
+   (merge b80fa84 ah/submodule-typofix-in-error later to maint).
+   (merge 99885bc ah/reflog-typofix-in-error later to maint).
+   (merge 9476c2c ah/read-tree-usage-string later to maint).
+   (merge b8c1d27 ah/pack-objects-usage-strings later to maint).
+   (merge 486e1e1 br/svn-doc-include-paths-config later to maint).
+   (merge 1733ed3 ee/clean-test-fixes later to maint).
+   (merge 5fcadc3 gb/apply-comment-typofix later to maint).
+   (merge b894d3e mp/t7060-diff-index-test later to maint).
+   (merge d238710 as/config-doc-markup-fix later to maint).
diff --git a/Documentation/RelNotes/2.6.1.txt b/Documentation/RelNotes/2.6.1.txt
new file mode 100644
index 0000000000..f37ea89cda
--- /dev/null
+++ b/Documentation/RelNotes/2.6.1.txt
@@ -0,0 +1,18 @@
+Git v2.6.1 Release Notes
+========================
+
+Fixes since v2.6
+----------------
+
+ * xdiff code we use to generate diffs is not prepared to handle
+   extremely large files.  It uses "int" in many places, which can
+   overflow if we have a very large number of lines or even bytes in
+   our input files, for example.  Cap the input size to somewhere
+   around 1GB for now.
+
+ * Some protocols (like git-remote-ext) can execute arbitrary code
+   found in the URL.  The URLs that submodules use may come from
+   arbitrary sources (e.g., .gitmodules files in a remote
+   repository), and can hurt those who blindly enable recursive
+   fetch.  Restrict the allowed protocols to well known and safe
+   ones.
diff --git a/Documentation/RelNotes/2.6.2.txt b/Documentation/RelNotes/2.6.2.txt
new file mode 100644
index 0000000000..5b65e35245
--- /dev/null
+++ b/Documentation/RelNotes/2.6.2.txt
@@ -0,0 +1,65 @@
+Git v2.6.2 Release Notes
+========================
+
+Fixes since v2.6.1
+------------------
+
+ * There were some classes of errors that "git fsck" diagnosed to its
+   standard error that did not cause it to exit with non-zero status.
+
+ * A test script for the HTTP service had a timing dependent bug,
+   which was fixed.
+
+ * Performance-measurement tests did not work without an installed Git.
+
+ * On a case insensitive filesystems, setting GIT_WORK_TREE variable
+   using a random cases that does not agree with what the filesystem
+   thinks confused Git that it wasn't inside the working tree.
+
+ * When "git am" was rewritten as a built-in, it stopped paying
+   attention to user.signingkey, which was fixed.
+
+ * After "git checkout --detach", "git status" reported a fairly
+   useless "HEAD detached at HEAD", instead of saying at which exact
+   commit.
+
+ * "git rebase -i" had a minor regression recently, which stopped
+   considering a line that begins with an indented '#' in its insn
+   sheet not a comment, which is now fixed.
+
+ * Description of the "log.follow" configuration variable in "git log"
+   documentation is now also copied to "git config" documentation.
+
+ * Allocation related functions and stdio are unsafe things to call
+   inside a signal handler, and indeed killing the pager can cause
+   glibc to deadlock waiting on allocation mutex as our signal handler
+   tries to free() some data structures in wait_for_pager().  Reduce
+   these unsafe calls.
+
+ * The way how --ref/--notes to specify the notes tree reference are
+   DWIMmed was not clearly documented.
+
+ * Customization to change the behaviour with "make -w" and "make -s"
+   in our Makefile was broken when they were used together.
+
+ * The Makefile always runs the library archiver with hardcoded "crs"
+   options, which was inconvenient for exotic platforms on which
+   people want to use programs with totally different set of command
+   line options.
+
+ * The ssh transport, just like any other transport over the network,
+   did not clear GIT_* environment variables, but it is possible to
+   use SendEnv and AcceptEnv to leak them to the remote invocation of
+   Git, which is not a good idea at all.  Explicitly clear them just
+   like we do for the local transport.
+
+ * "git blame --first-parent v1.0..v2.0" was not rejected but did not
+   limit the blame to commits on the first parent chain.
+
+ * Very small number of options take a parameter that is optional
+   (which is not a great UI element as they can only appear at the end
+   of the command line).  Add notice to documentation of each and
+   every one of them.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.6.3.txt b/Documentation/RelNotes/2.6.3.txt
new file mode 100644
index 0000000000..fc6fe1711f
--- /dev/null
+++ b/Documentation/RelNotes/2.6.3.txt
@@ -0,0 +1,111 @@
+Git v2.6.3 Release Notes
+========================
+
+Fixes since v2.6.2
+------------------
+
+ * The error message from "git blame --contents --reverse" incorrectly
+   talked about "--contents --children".
+
+ * "git merge-file" tried to signal how many conflicts it found, which
+   obviously would not work well when there are too many of them.
+
+ * The name-hash subsystem that is used to cope with case insensitive
+   filesystems keeps track of directories and their on-filesystem
+   cases for all the paths in the index by holding a pointer to a
+   randomly chosen cache entry that is inside the directory (for its
+   ce->ce_name component).  This pointer was not updated even when the
+   cache entry was removed from the index, leading to use after free.
+   This was fixed by recording the path for each directory instead of
+   borrowing cache entries and restructuring the API somewhat.
+
+ * When the "git am" command was reimplemented in C, "git am -3" had a
+   small regression where it is aborted in its error handling codepath
+   when underlying merge-recursive failed in some ways.
+
+ * The synopsis text and the usage string of subcommands that read
+   list of things from the standard input are often shown as if they
+   only take input from a file on a filesystem, which was misleading.
+
+ * A couple of commands still showed "[options]" in their usage string
+   to note where options should come on their command line, but we
+   spell that "[<options>]" in most places these days.
+
+ * The submodule code has been taught to work better with separate
+   work trees created via "git worktree add".
+
+ * When "git gc --auto" is backgrounded, its diagnosis message is
+   lost.  It now is saved to a file in $GIT_DIR and is shown next time
+   the "gc --auto" is run.
+
+ * Work around "git p4" failing when the P4 depot records the contents
+   in UTF-16 without UTF-16 BOM.
+
+ * Recent update to "rebase -i" that tries to sanity check the edited
+   insn sheet before it uses it has become too picky on Windows where
+   CRLF left by the editor is turned into a trailing CR on the line
+   read via the "read" built-in command.
+
+ * "git clone --dissociate" runs a big "git repack" process at the
+   end, and it helps to close file descriptors that are open on the
+   packs and their idx files before doing so on filesystems that
+   cannot remove a file that is still open.
+
+ * Correct "git p4 --detect-labels" so that it does not fail to create
+   a tag that points at a commit that is also being imported.
+
+ * The internal stripspace() function has been moved to where it
+   logically belongs to, i.e. strbuf API, and the command line parser
+   of "git stripspace" has been updated to use the parse_options API.
+
+ * Prepare for Git on-disk repository representation to undergo
+   backward incompatible changes by introducing a new repository
+   format version "1", with an extension mechanism.
+
+ * "git gc" used to barf when a symbolic ref has gone dangling
+   (e.g. the branch that used to be your upstream's default when you
+   cloned from it is now gone, and you did "fetch --prune").
+
+ * The normalize_ceiling_entry() function does not muck with the end
+   of the path it accepts, and the real world callers do rely on that,
+   but a test insisted that the function drops a trailing slash.
+
+ * "git gc" is safe to run anytime only because it has the built-in
+   grace period to protect young objects.  In order to run with no
+   grace period, the user must make sure that the repository is
+   quiescent.
+
+ * A recent "filter-branch --msg-filter" broke skipping of the commit
+   object header, which is fixed.
+
+ * "git --literal-pathspecs add -u/-A" without any command line
+   argument misbehaved ever since Git 2.0.
+
+ * Merging a branch that removes a path and another that changes the
+   mode bits on the same path should have conflicted at the path, but
+   it didn't and silently favoured the removal.
+
+ * "git imap-send" did not compile well with older version of cURL library.
+
+ * The linkage order of libraries was wrong in places around libcurl.
+
+ * It was not possible to use a repository-lookalike created by "git
+   worktree add" as a local source of "git clone".
+
+ * When "git send-email" wanted to talk over Net::SMTP::SSL,
+   Net::Cmd::datasend() did not like to be fed too many bytes at the
+   same time and failed to send messages.  Send the payload one line
+   at a time to work around the problem.
+
+ * We peek objects from submodule's object store by linking it to the
+   list of alternate object databases, but the code to do so forgot to
+   correctly initialize the list.
+
+ * "git status --branch --short" accessed beyond the constant string
+   "HEAD", which has been corrected.
+
+ * "git daemon" uses "run_command()" without "finish_command()", so it
+   needs to release resources itself, which it forgot to do.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.6.4.txt b/Documentation/RelNotes/2.6.4.txt
new file mode 100644
index 0000000000..b0256a2dc9
--- /dev/null
+++ b/Documentation/RelNotes/2.6.4.txt
@@ -0,0 +1,63 @@
+Git v2.6.4 Release Notes
+========================
+
+Fixes since v2.6.3
+------------------
+
+ * The "configure" script did not test for -lpthread correctly, which
+   upset some linkers.
+
+ * Add support for talking http/https over socks proxy.
+
+ * Portability fix for Windows, which may rewrite $SHELL variable using
+   non-POSIX paths.
+
+ * We now consistently allow all hooks to ignore their standard input,
+   rather than having git complain of SIGPIPE.
+
+ * Fix shell quoting in contrib script.
+
+ * Test portability fix for a topic in v2.6.1.
+
+ * Allow tilde-expansion in some http config variables.
+
+ * Give a useful special case "diff/show --word-diff-regex=." as an
+   example in the documentation.
+
+ * Fix for a corner case in filter-branch.
+
+ * Make git-p4 work on a detached head.
+
+ * Documentation clarification for "check-ignore" without "--verbose".
+
+ * Just like the working tree is cleaned up when the user cancelled
+   submission in P4Submit.applyCommit(), clean up the mess if "p4
+   submit" fails.
+
+ * Having a leftover .idx file without corresponding .pack file in
+   the repository hurts performance; "git gc" learned to prune them.
+
+ * The code to prepare the working tree side of temporary directory
+   for the "dir-diff" feature forgot that symbolic links need not be
+   copied (or symlinked) to the temporary area, as the code already
+   special cases and overwrites them.  Besides, it was wrong to try
+   computing the object name of the target of symbolic link, which may
+   not even exist or may be a directory.
+
+ * There was no way to defeat a configured rebase.autostash variable
+   from the command line, as "git rebase --no-autostash" was missing.
+
+ * Allow "git interpret-trailers" to run outside of a Git repository.
+
+ * Produce correct "dirty" marker for shell prompts, even when we
+   are on an orphan or an unborn branch.
+
+ * Some corner cases have been fixed in string-matching done in "git
+   status".
+
+ * Apple's common crypto implementation of SHA1_Update() does not take
+   more than 4GB at a time, and we now have a compile-time workaround
+   for it.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.6.5.txt b/Documentation/RelNotes/2.6.5.txt
new file mode 100644
index 0000000000..f0924b62e0
--- /dev/null
+++ b/Documentation/RelNotes/2.6.5.txt
@@ -0,0 +1,58 @@
+Git v2.6.5 Release Notes
+========================
+
+Fixes since v2.6.4
+------------------
+
+ * Because "test_when_finished" in our test framework queues the
+   clean-up tasks to be done in a shell variable, it should not be
+   used inside a subshell.  Add a mechanism to allow 'bash' to catch
+   such uses, and fix the ones that were found.
+
+ * Update "git subtree" (in contrib/) so that it can take whitespaces
+   in the pathnames, not only in the in-tree pathname but the name of
+   the directory that the repository is in.
+
+ * Cosmetic improvement to lock-file error messages.
+
+ * mark_tree_uninteresting() has code to handle the case where it gets
+   passed a NULL pointer in its 'tree' parameter, but the function had
+   'object = &tree->object' assignment before checking if tree is
+   NULL.  This gives a compiler an excuse to declare that tree will
+   never be NULL and apply a wrong optimization.  Avoid it.
+
+ * The helper used to iterate over loose object directories to prune
+   stale objects did not closedir() immediately when it is done with a
+   directory--a callback such as the one used for "git prune" may want
+   to do rmdir(), but it would fail on open directory on platforms
+   such as WinXP.
+
+ * "git p4" used to import Perforce CLs that touch only paths outside
+   the client spec as empty commits.  It has been corrected to ignore
+   them instead, with a new configuration git-p4.keepEmptyCommits as a
+   backward compatibility knob.
+
+ * The exit code of git-fsck did not reflect some types of errors
+   found in packed objects, which has been corrected.
+
+ * The completion script (in contrib/) used to list "git column"
+   (which is not an end-user facing command) as one of the choices
+
+ * Improve error reporting when SMTP TLS fails.
+
+ * When getpwuid() on the system returned NULL (e.g. the user is not
+   in the /etc/passwd file or other uid-to-name mappings), the
+   codepath to find who the user is to record it in the reflog barfed
+   and died.  Loosen the check in this codepath, which already accepts
+   questionable ident string (e.g. host part of the e-mail address is
+   obviously bogus), and in general when we operate fmt_ident() function
+   in non-strict mode.
+
+ * "git symbolic-ref" forgot to report a failure with its exit status.
+
+ * History traversal with "git log --source" that starts with an
+   annotated tag failed to report the tag as "source", due to an
+   old regression in the command line parser back in v2.2 days.
+
+Also contains typofixes, documentation updates and trivial code
+clean-ups.
diff --git a/Documentation/RelNotes/2.6.6.txt b/Documentation/RelNotes/2.6.6.txt
new file mode 100644
index 0000000000..023ad85ec6
--- /dev/null
+++ b/Documentation/RelNotes/2.6.6.txt
@@ -0,0 +1,11 @@
+Git v2.6.6 Release Notes
+========================
+
+Fixes since v2.6.5
+------------------
+
+ * Bugfix patches were backported from the 'master' front to plug heap
+   corruption holes, to catch integer overflow in the computation of
+   pathname lengths, and to get rid of the name_path API.  Both of
+   these would have resulted in writing over an under-allocated buffer
+   when formulating pathnames while tree traversal.
diff --git a/Documentation/RelNotes/2.6.7.txt b/Documentation/RelNotes/2.6.7.txt
new file mode 100644
index 0000000000..1335de49a6
--- /dev/null
+++ b/Documentation/RelNotes/2.6.7.txt
@@ -0,0 +1,12 @@
+Git v2.6.7 Release Notes
+========================
+
+Fixes since v2.6.6
+------------------
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
diff --git a/Documentation/RelNotes/2.7.0.txt b/Documentation/RelNotes/2.7.0.txt
new file mode 100644
index 0000000000..e3cbf3a73c
--- /dev/null
+++ b/Documentation/RelNotes/2.7.0.txt
@@ -0,0 +1,414 @@
+Git 2.7 Release Notes
+=====================
+
+Updates since v2.6
+------------------
+
+UI, Workflows & Features
+
+ * The appearance of "gitk", particularly on high DPI monitors, have
+   been improved.  "gitk" also comes with an undated translation for
+   Swedish and Japanese.
+
+ * "git remote" learned "get-url" subcommand to show the URL for a
+   given remote name used for fetching and pushing.
+
+ * There was no way to defeat a configured rebase.autostash variable
+   from the command line, as "git rebase --no-autostash" was missing.
+
+ * "git log --date=local" used to only show the normal (default)
+   format in the local timezone.  The command learned to take 'local'
+   as an instruction to use the local timezone with other formats,
+
+ * The refs used during a "git bisect" session is now per-worktree so
+   that independent bisect sessions can be done in different worktrees
+   created with "git worktree add".
+
+ * Users who are too busy to type three extra keystrokes to ask for
+   "git stash show -p" can now set stash.showPatch configuration
+   variable to true to always see the actual patch, not just the list
+   of paths affected with feel for the extent of damage via diffstat.
+
+ * "quiltimport" allows to specify the series file by honoring the
+   $QUILT_SERIES environment and also --series command line option.
+
+ * The use of 'good/bad' in "git bisect" made it confusing to use when
+   hunting for a state change that is not a regression (e.g. bugfix).
+   The command learned 'old/new' and then allows the end user to
+   say e.g. "bisect start --term-old=fast --term-new=slow" to find a
+   performance regression.
+
+ * "git interpret-trailers" can now run outside of a Git repository.
+
+ * "git p4" learned to re-encode the pathname it uses to communicate
+   with the p4 depot with a new option.
+
+ * Give progress meter to "git filter-branch".
+
+ * Allow a later "!/abc/def" to override an earlier "/abc" that
+   appears in the same .gitignore file to make it easier to express
+   "everything in /abc directory is ignored, except for ...".
+
+ * Teach "git p4" to send large blobs outside the repository by
+   talking to Git LFS.
+
+ * Prepare for Git on-disk repository representation to undergo
+   backward incompatible changes by introducing a new repository
+   format version "1", with an extension mechanism.
+
+ * "git worktree" learned a "list" subcommand.
+
+ * "git clone --dissociate" learned that it can be used even when
+   "--reference" was not used at the same time.
+
+ * "git blame" learnt to take "--first-parent" and "--reverse" at the
+   same time when it makes sense.
+
+ * "git checkout" did not follow the usual "--[no-]progress"
+   convention and implemented only "--quiet" that is essentially
+   a superset of "--no-progress".  Extend the command to support the
+   usual "--[no-]progress".
+
+ * The semantics of transfer.hideRefs configuration variable have been
+   extended to work better with the ref "namespace" feature that lets
+   you throw unrelated bunches of repositories in a single physical
+   repository and virtually serve them as separate ones.
+
+ * send-email config variables whose values are pathnames now go
+   through the ~username/ expansion.
+
+ * bash completion learnt to TAB-complete recipient addresses given
+   to send-email.
+
+ * The credential-cache daemon can be told to ignore SIGHUP to work
+   around issue when running Git from inside emacs.
+
+ * "git push" learned new configuration for doing "--recurse-submodules"
+   on each push.
+
+ * "format-patch" has learned a new option to zero-out the commit
+   object name on the mbox "From " line.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The infrastructure to rewrite "git submodule" in C is being built
+   incrementally.  Let's polish these early parts well enough and make
+   them graduate to 'next' and 'master', so that the more involved
+   follow-up can start cooking on a solid ground.
+
+ * Some features from "git tag -l" and "git branch -l" have been made
+   available to "git for-each-ref" so that eventually the unified
+   implementation can be shared across all three.  The version merged
+   to the 'master' branch earlier had a performance regression in "tag
+   --contains", which has since been corrected.
+
+ * Because "test_when_finished" in our test framework queues the
+   clean-up tasks to be done in a shell variable, it should not be
+   used inside a subshell.  Add a mechanism to allow 'bash' to catch
+   such uses, and fix the ones that were found.
+
+ * The debugging infrastructure for pkt-line based communication has
+   been improved to mark the side-band communication specifically.
+
+ * Update "git branch" that list existing branches, using the
+   ref-filter API that is shared with "git tag" and "git
+   for-each-ref".
+
+ * The test for various line-ending conversions has been enhanced.
+
+ * A few test scripts around "git p4" have been improved for
+   portability.
+
+ * Many allocations that is manually counted (correctly) that are
+   followed by strcpy/sprintf have been replaced with a less error
+   prone constructs such as xstrfmt.
+
+ * The internal stripspace() function has been moved to where it
+   logically belongs to, i.e. strbuf API, and the command line parser
+   of "git stripspace" has been updated to use the parse_options API.
+
+ * "git am" used to spawn "git mailinfo" via run_command() API once
+   per each patch, but learned to make a direct call to mailinfo()
+   instead.
+
+ * The implementation of "git mailinfo" was refactored so that a
+   mailinfo() function can be directly called from inside a process.
+
+ * With a "debug" helper, debugging of a single "git" invocation in
+   our test scripts has become a lot easier.
+
+ * The "configure" script did not test for -lpthread correctly, which
+   upset some linkers.
+
+ * Cross completed task off of subtree project's todo list.
+
+ * Test cleanups for the subtree project.
+
+ * Clean up style in an ancient test t9300.
+
+ * Work around some test flakiness with p4d.
+
+ * Fsck did not correctly detect a NUL-truncated header in a tag.
+
+ * Use a safer behavior when we hit errors verifying remote certificates.
+
+ * Speed up filter-branch for cases where we only care about rewriting
+   commits, not tree data.
+
+ * The parse-options API has been updated to make "-h" command line
+   option work more consistently in all commands.
+
+ * "git svn rebase/mkdirs" got optimized by keeping track of empty
+   directories better.
+
+ * Fix some racy client/server tests by treating SIGPIPE the same as a
+   normal non-zero exit.
+
+ * The necessary infrastructure to build topics using the free Travis
+   CI has been added. Developers forking from this topic (and enabling
+   Travis) can do their own builds, and we can turn on auto-builds for
+   git/git (including build-status for pull requests that people
+   open).
+
+ * The write(2) emulation for Windows learned to set errno to EPIPE
+   when necessary.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.6
+----------------
+
+Unless otherwise noted, all the fixes since v2.6 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * Very small number of options take a parameter that is optional
+   (which is not a great UI element as they can only appear at the end
+   of the command line).  Add notice to documentation of each and
+   every one of them.
+
+ * "git blame --first-parent v1.0..v2.0" was not rejected but did not
+   limit the blame to commits on the first parent chain.
+
+ * "git subtree" (in contrib/) now can take whitespaces in the
+   pathnames, not only in the in-tree pathname but the name of the
+   directory that the repository is in.
+
+ * The ssh transport, just like any other transport over the network,
+   did not clear GIT_* environment variables, but it is possible to
+   use SendEnv and AcceptEnv to leak them to the remote invocation of
+   Git, which is not a good idea at all.  Explicitly clear them just
+   like we do for the local transport.
+
+ * Correct "git p4 --detect-labels" so that it does not fail to create
+   a tag that points at a commit that is also being imported.
+
+ * The Makefile always runs the library archiver with hardcoded "crs"
+   options, which was inconvenient for exotic platforms on which
+   people want to use programs with totally different set of command
+   line options.
+
+ * Customization to change the behaviour with "make -w" and "make -s"
+   in our Makefile was broken when they were used together.
+
+ * Allocation related functions and stdio are unsafe things to call
+   inside a signal handler, and indeed killing the pager can cause
+   glibc to deadlock waiting on allocation mutex as our signal handler
+   tries to free() some data structures in wait_for_pager().  Reduce
+   these unsafe calls.
+
+ * The way how --ref/--notes to specify the notes tree reference are
+   DWIMmed was not clearly documented.
+
+ * "git gc" used to barf when a symbolic ref has gone dangling
+   (e.g. the branch that used to be your upstream's default when you
+   cloned from it is now gone, and you did "fetch --prune").
+
+ * "git clone --dissociate" runs a big "git repack" process at the
+   end, and it helps to close file descriptors that are open on the
+   packs and their idx files before doing so on filesystems that
+   cannot remove a file that is still open.
+
+ * Description of the "log.follow" configuration variable in "git log"
+   documentation is now also copied to "git config" documentation.
+
+ * "git rebase -i" had a minor regression recently, which stopped
+   considering a line that begins with an indented '#' in its insn
+   sheet not a comment. Further, the code was still too picky on
+   Windows where CRLF left by the editor is turned into a trailing CR
+   on the line read via the "read" built-in command of bash.  Both of
+   these issues are now fixed.
+
+ * After "git checkout --detach", "git status" reported a fairly
+   useless "HEAD detached at HEAD", instead of saying at which exact
+   commit.
+
+ * When "git send-email" wanted to talk over Net::SMTP::SSL,
+   Net::Cmd::datasend() did not like to be fed too many bytes at the
+   same time and failed to send messages.  Send the payload one line
+   at a time to work around the problem.
+
+ * When "git am" was rewritten as a built-in, it stopped paying
+   attention to user.signingkey, which was fixed.
+
+ * It was not possible to use a repository-lookalike created by "git
+   worktree add" as a local source of "git clone".
+
+ * On a case insensitive filesystems, setting GIT_WORK_TREE variable
+   using a random cases that does not agree with what the filesystem
+   thinks confused Git that it wasn't inside the working tree.
+
+ * Performance-measurement tests did not work without an installed Git.
+
+ * A test script for the HTTP service had a timing dependent bug,
+   which was fixed.
+
+ * There were some classes of errors that "git fsck" diagnosed to its
+   standard error that did not cause it to exit with non-zero status.
+
+ * Work around "git p4" failing when the P4 depot records the contents
+   in UTF-16 without UTF-16 BOM.
+
+ * When "git gc --auto" is backgrounded, its diagnosis message is
+   lost.  Save it to a file in $GIT_DIR and show it next time the "gc
+   --auto" is run.
+
+ * The submodule code has been taught to work better with separate
+   work trees created via "git worktree add".
+
+ * "git gc" is safe to run anytime only because it has the built-in
+   grace period to protect young objects.  In order to run with no
+   grace period, the user must make sure that the repository is
+   quiescent.
+
+ * A recent "filter-branch --msg-filter" broke skipping of the commit
+   object header, which is fixed.
+
+ * The normalize_ceiling_entry() function does not muck with the end
+   of the path it accepts, and the real world callers do rely on that,
+   but a test insisted that the function drops a trailing slash.
+
+ * A test for interaction between untracked cache and sparse checkout
+   added in Git 2.5 days were flaky.
+
+ * A couple of commands still showed "[options]" in their usage string
+   to note where options should come on their command line, but we
+   spell that "[<options>]" in most places these days.
+
+ * The synopsis text and the usage string of subcommands that read
+   list of things from the standard input are often shown as if they
+   only take input from a file on a filesystem, which was misleading.
+
+ * "git am -3" had a small regression where it is aborted in its error
+   handling codepath when underlying merge-recursive failed in certain
+   ways, as it assumed that the internal call to merge-recursive will
+   never die, which is not the case (yet).
+
+ * The linkage order of libraries was wrong in places around libcurl.
+
+ * The name-hash subsystem that is used to cope with case insensitive
+   filesystems keeps track of directories and their on-filesystem
+   cases for all the paths in the index by holding a pointer to a
+   randomly chosen cache entry that is inside the directory (for its
+   ce->ce_name component).  This pointer was not updated even when the
+   cache entry was removed from the index, leading to use after free.
+   This was fixed by recording the path for each directory instead of
+   borrowing cache entries and restructuring the API somewhat.
+
+ * "git merge-file" tried to signal how many conflicts it found, which
+   obviously would not work well when there are too many of them.
+
+ * The error message from "git blame --contents --reverse" incorrectly
+   talked about "--contents --children".
+
+ * "git imap-send" did not compile well with older version of cURL library.
+
+ * Merging a branch that removes a path and another that changes the
+   mode bits on the same path should have conflicted at the path, but
+   it didn't and silently favoured the removal.
+
+ * "git --literal-pathspecs add -u/-A" without any command line
+   argument misbehaved ever since Git 2.0.
+
+ * "git daemon" uses "run_command()" without "finish_command()", so it
+   needs to release resources itself, which it forgot to do.
+
+ * "git status --branch --short" accessed beyond the constant string
+   "HEAD", which has been corrected.
+
+ * We peek objects from submodule's object store by linking it to the
+   list of alternate object databases, but the code to do so forgot to
+   correctly initialize the list.
+
+ * The code to prepare the working tree side of temporary directory
+   for the "dir-diff" feature forgot that symbolic links need not be
+   copied (or symlinked) to the temporary area, as the code already
+   special cases and overwrites them.  Besides, it was wrong to try
+   computing the object name of the target of symbolic link, which may
+   not even exist or may be a directory.
+
+ * A Range: request can be responded with a full response and when
+   asked properly libcurl knows how to strip the result down to the
+   requested range.  However, we were hand-crafting a range request
+   and it did not kick in.
+
+ * Having a leftover .idx file without corresponding .pack file in
+   the repository hurts performance; "git gc" learned to prune them.
+
+ * Apple's common crypto implementation of SHA1_Update() does not take
+   more than 4GB at a time, and we now have a compile-time workaround
+   for it.
+
+ * Produce correct "dirty" marker for shell prompts, even when we
+   are on an orphan or an unborn branch.
+
+ * A build without NO_IPv6 used to use gethostbyname() when guessing
+   user's hostname, instead of getaddrinfo() that is used in other
+   codepaths in such a build.
+
+ * The exit code of git-fsck did not reflect some types of errors
+   found in packed objects, which has been corrected.
+
+ * The helper used to iterate over loose object directories to prune
+   stale objects did not closedir() immediately when it is done with a
+   directory--a callback such as the one used for "git prune" may want
+   to do rmdir(), but it would fail on open directory on platforms
+   such as WinXP.
+
+ * "git p4" used to import Perforce CLs that touch only paths outside
+   the client spec as empty commits.  It has been corrected to ignore
+   them instead, with a new configuration git-p4.keepEmptyCommits as a
+   backward compatibility knob.
+
+ * The completion script (in contrib/) used to list "git column"
+   (which is not an end-user facing command) as one of the choices
+   (merge 160fcdb sg/completion-no-column later to maint).
+
+ * The error reporting from "git send-email", when SMTP TLS fails, has
+   been improved.
+   (merge 9d60524 jk/send-email-ssl-errors later to maint).
+
+ * When getpwuid() on the system returned NULL (e.g. the user is not
+   in the /etc/passwd file or other uid-to-name mappings), the
+   codepath to find who the user is to record it in the reflog barfed
+   and died.  Loosen the check in this codepath, which already accepts
+   questionable ident string (e.g. host part of the e-mail address is
+   obviously bogus), and in general when we operate fmt_ident() function
+   in non-strict mode.
+   (merge 92bcbb9 jk/ident-loosen-getpwuid later to maint).
+
+ * "git symbolic-ref" forgot to report a failure with its exit status.
+   (merge f91b273 jk/symbolic-ref-maint later to maint).
+
+ * History traversal with "git log --source" that starts with an
+   annotated tag failed to report the tag as "source", due to an
+   old regression in the command line parser back in v2.2 days.
+   (merge 728350b jk/pending-keep-tag-name later to maint).
+
+ * "git p4" when interacting with multiple depots at the same time
+   used to incorrectly drop changes.
+
+ * Code clean-up, minor fixes etc.
diff --git a/Documentation/RelNotes/2.7.1.txt b/Documentation/RelNotes/2.7.1.txt
new file mode 100644
index 0000000000..6323feaf64
--- /dev/null
+++ b/Documentation/RelNotes/2.7.1.txt
@@ -0,0 +1,87 @@
+Git v2.7.1 Release Notes
+========================
+
+Fixes since v2.7
+----------------
+
+ * An earlier change in 2.5.x-era broke users' hooks and aliases by
+   exporting GIT_WORK_TREE to point at the root of the working tree,
+   interfering when they tried to use a different working tree without
+   setting GIT_WORK_TREE environment themselves.
+
+ * The "exclude_list" structure has the usual "alloc, nr" pair of
+   fields to be used by ALLOC_GROW(), but clear_pattern_list() forgot
+   to reset 'alloc' to 0 when it cleared 'nr' to discard the managed
+   array.
+
+ * "git send-email" was confused by escaped quotes stored in the alias
+   files saved by "mutt", which has been corrected.
+
+ * A few unportable C construct have been spotted by clang compiler
+   and have been fixed.
+
+ * The documentation has been updated to hint the connection between
+   the '--signoff' option and DCO.
+
+ * "git reflog" incorrectly assumed that all objects that used to be
+   at the tip of a ref must be commits, which caused it to segfault.
+
+ * The ignore mechanism saw a few regressions around untracked file
+   listing and sparse checkout selection areas in 2.7.0; the change
+   that is responsible for the regression has been reverted.
+
+ * Some codepaths used fopen(3) when opening a fixed path in $GIT_DIR
+   (e.g. COMMIT_EDITMSG) that is meant to be left after the command is
+   done.  This however did not work well if the repository is set to
+   be shared with core.sharedRepository and the umask of the previous
+   user is tighter.  They have been made to work better by calling
+   unlink(2) and retrying after fopen(3) fails with EPERM.
+
+ * Asking gitweb for a nonexistent commit left a warning in the server
+   log.
+
+ * "git rebase", unlike all other callers of "gc --auto", did not
+   ignore the exit code from "gc --auto".
+
+ * Many codepaths that run "gc --auto" before exiting kept packfiles
+   mapped and left the file descriptors to them open, which was not
+   friendly to systems that cannot remove files that are open.  They
+   now close the packs before doing so.
+
+ * A recent optimization to filter-branch in v2.7.0 introduced a
+   regression when --prune-empty filter is used, which has been
+   corrected.
+
+ * The description for SANITY prerequisite the test suite uses has
+   been clarified both in the comment and in the implementation.
+
+ * "git tag" started listing a tag "foo" as "tags/foo" when a branch
+   named "foo" exists in the same repository; remove this unnecessary
+   disambiguation, which is a regression introduced in v2.7.0.
+
+ * The way "git svn" uses auth parameter was broken by Subversion
+   1.9.0 and later.
+
+ * The "split" subcommand of "git subtree" (in contrib/) incorrectly
+   skipped merges when it shouldn't, which was corrected.
+
+ * A few options of "git diff" did not work well when the command was
+   run from a subdirectory.
+
+ * dirname() emulation has been added, as Msys2 lacks it.
+
+ * The underlying machinery used by "ls-files -o" and other commands
+   have been taught not to create empty submodule ref cache for a
+   directory that is not a submodule.  This removes a ton of wasted
+   CPU cycles.
+
+ * Drop a few old "todo" items by deciding that the change one of them
+   suggests is not such a good idea, and doing the change the other
+   one suggested to do.
+
+ * Documentation for "git fetch --depth" has been updated for clarity.
+
+ * The command line completion learned a handful of additional options
+   and command specific syntax.
+
+Also includes a handful of documentation and test updates.
diff --git a/Documentation/RelNotes/2.7.2.txt b/Documentation/RelNotes/2.7.2.txt
new file mode 100644
index 0000000000..4feef76704
--- /dev/null
+++ b/Documentation/RelNotes/2.7.2.txt
@@ -0,0 +1,41 @@
+Git v2.7.2 Release Notes
+========================
+
+Fixes since v2.7.1
+------------------
+
+ * The low-level merge machinery has been taught to use CRLF line
+   termination when inserting conflict markers to merged contents that
+   are themselves CRLF line-terminated.
+
+ * "git worktree" had a broken code that attempted to auto-fix
+   possible inconsistency that results from end-users moving a
+   worktree to different places without telling Git (the original
+   repository needs to maintain backpointers to its worktrees, but
+   "mv" run by end-users who are not familiar with that fact will
+   obviously not adjust them), which actually made things worse
+   when triggered.
+
+ * "git push --force-with-lease" has been taught to report if the push
+   needed to force (or fast-forwarded).
+
+ * The emulated "yes" command used in our test scripts has been
+   tweaked not to spend too much time generating unnecessary output
+   that is not used, to help those who test on Windows where it would
+   not stop until it fills the pipe buffer due to lack of SIGPIPE.
+
+ * The vimdiff backend for "git mergetool" has been tweaked to arrange
+   and number buffers in the order that would match the expectation of
+   majority of people who read left to right, then top down and assign
+   buffers 1 2 3 4 "mentally" to local base remote merge windows based
+   on that order.
+
+ * The documentation for "git clean" has been corrected; it mentioned
+   that .git/modules/* are removed by giving two "-f", which has never
+   been the case.
+
+ * Paths that have been told the index about with "add -N" are not
+   quite yet in the index, but a few commands behaved as if they
+   already are in a harmful way.
+
+Also includes tiny documentation and test updates.
diff --git a/Documentation/RelNotes/2.7.3.txt b/Documentation/RelNotes/2.7.3.txt
new file mode 100644
index 0000000000..f618d71efd
--- /dev/null
+++ b/Documentation/RelNotes/2.7.3.txt
@@ -0,0 +1,62 @@
+Git v2.7.3 Release Notes
+========================
+
+Fixes since v2.7.2
+------------------
+
+ * Traditionally, the tests that try commands that work on the
+   contents in the working tree were named with "worktree" in their
+   filenames, but with the recent addition of "git worktree"
+   subcommand, whose tests are also named similarly, it has become
+   harder to tell them apart.  The traditional tests have been renamed
+   to use "work-tree" instead in an attempt to differentiate them.
+
+ * Many codepaths forget to check return value from git_config_set();
+   the function is made to die() to make sure we do not proceed when
+   setting a configuration variable failed.
+
+ * Handling of errors while writing into our internal asynchronous
+   process has been made more robust, which reduces flakiness in our
+   tests.
+
+ * "git show 'HEAD:Foo[BAR]Baz'" did not interpret the argument as a
+   rev, i.e. the object named by the pathname with wildcard
+   characters in a tree object.
+
+ * "git rev-parse --git-common-dir" used in the worktree feature
+   misbehaved when run from a subdirectory.
+
+ * The "v(iew)" subcommand of the interactive "git am -i" command was
+   broken in 2.6.0 timeframe when the command was rewritten in C.
+
+ * "git merge-tree" used to mishandle "both sides added" conflict with
+   its own "create a fake ancestor file that has the common parts of
+   what both sides have added and do a 3-way merge" logic; this has
+   been updated to use the usual "3-way merge with an empty blob as
+   the fake common ancestor file" approach used in the rest of the
+   system.
+
+ * The memory ownership rule of fill_textconv() API, which was a bit
+   tricky, has been documented a bit better.
+
+ * The documentation did not clearly state that the 'simple' mode is
+   now the default for "git push" when push.default configuration is
+   not set.
+
+ * Recent versions of GNU grep are pickier when their input contains
+   arbitrary binary data, which some of our tests uses.  Rewrite the
+   tests to sidestep the problem.
+
+ * A helper function "git submodule" uses since v2.7.0 to list the
+   modules that match the pathspec argument given to its subcommands
+   (e.g. "submodule add <repo> <path>") has been fixed.
+
+ * "git config section.var value" to set a value in per-repository
+   configuration file failed when it was run outside any repository,
+   but didn't say the reason correctly.
+
+ * The code to read the pack data using the offsets stored in the pack
+   idx file has been made more carefully check the validity of the
+   data in the idx.
+
+Also includes documentation and test updates.
diff --git a/Documentation/RelNotes/2.7.4.txt b/Documentation/RelNotes/2.7.4.txt
new file mode 100644
index 0000000000..883ae896fe
--- /dev/null
+++ b/Documentation/RelNotes/2.7.4.txt
@@ -0,0 +1,11 @@
+Git v2.7.4 Release Notes
+========================
+
+Fixes since v2.7.3
+------------------
+
+ * Bugfix patches were backported from the 'master' front to plug heap
+   corruption holes, to catch integer overflow in the computation of
+   pathname lengths, and to get rid of the name_path API.  Both of
+   these would have resulted in writing over an under-allocated buffer
+   when formulating pathnames while tree traversal.
diff --git a/Documentation/RelNotes/2.7.5.txt b/Documentation/RelNotes/2.7.5.txt
new file mode 100644
index 0000000000..83559ce3b2
--- /dev/null
+++ b/Documentation/RelNotes/2.7.5.txt
@@ -0,0 +1,14 @@
+Git v2.7.5 Release Notes
+========================
+
+Fixes since v2.7.4
+------------------
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
+
+Also contains a few fixes backported from later development tracks.
diff --git a/Documentation/RelNotes/2.7.6.txt b/Documentation/RelNotes/2.7.6.txt
new file mode 100644
index 0000000000..4c6d1dcd4a
--- /dev/null
+++ b/Documentation/RelNotes/2.7.6.txt
@@ -0,0 +1,25 @@
+Git v2.7.6 Release Notes
+========================
+
+Fixes since v2.7.5
+------------------
+
+ * A "ssh://..." URL can result in a "ssh" command line with a
+   hostname that begins with a dash "-", which would cause the "ssh"
+   command to instead (mis)treat it as an option.  This is now
+   prevented by forbidding such a hostname (which will not be
+   necessary in the real world).
+
+ * Similarly, when GIT_PROXY_COMMAND is configured, the command is
+   run with host and port that are parsed out from "ssh://..." URL;
+   a poorly written GIT_PROXY_COMMAND could be tricked into treating
+   a string that begins with a dash "-".  This is now prevented by
+   forbidding such a hostname and port number (again, which will not
+   be necessary in the real world).
+
+ * In the same spirit, a repository name that begins with a dash "-"
+   is also forbidden now.
+
+Credits go to Brian Neel at GitLab, Joern Schneeweisz of Recurity
+Labs and Jeff King at GitHub.
+
diff --git a/Documentation/RelNotes/2.8.0.txt b/Documentation/RelNotes/2.8.0.txt
new file mode 100644
index 0000000000..38453281b8
--- /dev/null
+++ b/Documentation/RelNotes/2.8.0.txt
@@ -0,0 +1,439 @@
+Git 2.8 Release Notes
+=====================
+
+Backward compatibility note
+---------------------------
+
+The rsync:// transport has been removed.
+
+
+Updates since v2.7
+------------------
+
+UI, Workflows & Features
+
+ * It turns out "git clone" over rsync transport has been broken when
+   the source repository has packed references for a long time, and
+   nobody noticed nor complained about it.
+
+ * "push" learned that its "--delete" option can be shortened to
+   "-d", just like "branch --delete" and "branch -d" are the same
+   thing.
+
+ * "git blame" learned to produce the progress eye-candy when it takes
+   too much time before emitting the first line of the result.
+
+ * "git grep" can now be configured (or told from the command line)
+   how many threads to use when searching in the working tree files.
+
+ * Some "git notes" operations, e.g. "git log --notes=<note>", should
+   be able to read notes from any tree-ish that is shaped like a notes
+   tree, but the notes infrastructure required that the argument must
+   be a ref under refs/notes/.  Loosen it to require a valid ref only
+   when the operation would update the notes (in which case we must
+   have a place to store the updated notes tree, iow, a ref).
+
+ * "git grep" by default does not fall back to its "--no-index"
+   behavior outside a directory under Git's control (otherwise the
+   user may by mistake end up running a huge recursive search); with a
+   new configuration (set in $HOME/.gitconfig--by definition this
+   cannot be set in the config file per project), this safety can be
+   disabled.
+
+ * "git pull --rebase" has been extended to allow invoking
+   "rebase -i".
+
+ * "git p4" learned to cope with the type of a file getting changed.
+
+ * "git format-patch" learned to notice format.outputDirectory
+   configuration variable.  This allows "-o <dir>" option to be
+   omitted on the command line if you always use the same directory in
+   your workflow.
+
+ * "interpret-trailers" has been taught to optionally update a file in
+   place, instead of always writing the result to the standard output.
+
+ * Many commands that read files that are expected to contain text
+   that is generated (or can be edited) by the end user to control
+   their behavior (e.g. "git grep -f <filename>") have been updated
+   to be more tolerant to lines that are terminated with CRLF (they
+   used to treat such a line to contain payload that ends with CR,
+   which is usually not what the users expect).
+
+ * "git notes merge" used to limit the source of the merged notes tree
+   to somewhere under refs/notes/ hierarchy, which was too limiting
+   when inventing a workflow to exchange notes with remote
+   repositories using remote-tracking notes trees (located in e.g.
+   refs/remote-notes/ or somesuch).
+
+ * "git ls-files" learned a new "--eol" option to help diagnose
+   end-of-line problems.
+
+ * "ls-remote" learned an option to show which branch the remote
+   repository advertises as its primary by pointing its HEAD at.
+
+ * New http.proxyAuthMethod configuration variable can be used to
+   specify what authentication method to use, as a way to work around
+   proxies that do not give error response expected by libcurl when
+   CURLAUTH_ANY is used.  Also, the codepath for proxy authentication
+   has been taught to use credential API to store the authentication
+   material in user's keyrings.
+
+ * Update the untracked cache subsystem and change its primary UI from
+   "git update-index" to "git config".
+
+ * There were a few "now I am doing this thing" progress messages in
+   the TCP connection code that can be triggered by setting a verbose
+   option internally in the code, but "git fetch -v" and friends never
+   passed the verbose option down to that codepath.
+
+ * Clean/smudge filters defined in a configuration file of lower
+   precedence can now be overridden to be a pass-through no-op by
+   setting the variable to an empty string.
+
+ * A new "<branch>^{/!-<pattern>}" notation can be used to name a
+   commit that is reachable from <branch> that does not match the
+   given <pattern>.
+
+ * The "user.useConfigOnly" configuration variable can be used to
+   force the user to always set user.email & user.name configuration
+   variables, serving as a reminder for those who work on multiple
+   projects and do not want to put these in their $HOME/.gitconfig.
+
+ * "git fetch" and friends that make network connections can now be
+   told to only use ipv4 (or ipv6).
+
+ * Some authentication methods do not need username or password, but
+   libcurl needs some hint that it needs to perform authentication.
+   Supplying an empty username and password string is a valid way to
+   do so, but you can set the http.[<url>.]emptyAuth configuration
+   variable to achieve the same, if you find it cleaner.
+
+ * You can now set http.[<url>.]pinnedpubkey to specify the pinned
+   public key when building with recent enough versions of libcURL.
+
+ * The configuration system has been taught to phrase where it found a
+   bad configuration variable in a better way in its error messages.
+   "git config" learnt a new "--show-origin" option to indicate where
+   the values come from.
+
+ * The "credential-cache" daemon process used to run in whatever
+   directory it happened to start in, but this made umount(2)ing the
+   filesystem that houses the repository harder; now the process
+   chdir()s to the directory that house its own socket on startup.
+
+ * When "git submodule update" did not result in fetching the commit
+   object in the submodule that is referenced by the superproject, the
+   command learned to retry another fetch, specifically asking for
+   that commit that may not be connected to the refs it usually
+   fetches.
+
+ * "git merge-recursive" learned "--no-renames" option to disable its
+   rename detection logic.
+
+ * Across the transition at around Git version 2.0, the user used to
+   get a pretty loud warning when running "git push" without setting
+   push.default configuration variable.  We no longer warn because the
+   transition was completed a long time ago.
+
+ * README has been renamed to README.md and its contents got tweaked
+   slightly to make it easier on the eyes.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * Add a framework to spawn a group of processes in parallel, and use
+   it to run "git fetch --recurse-submodules" in parallel.
+
+ * A slight update to the Makefile to mark ".PHONY" targets as such
+   correctly.
+
+ * In-core storage of the reverse index for .pack files (which lets
+   you go from a pack offset to an object name) has been streamlined.
+
+ * d95138e6 (setup: set env $GIT_WORK_TREE when work tree is set, like
+   $GIT_DIR, 2015-06-26) attempted to work around a glitch in alias
+   handling by overwriting GIT_WORK_TREE environment variable to
+   affect subprocesses when set_git_work_tree() gets called, which
+   resulted in a rather unpleasant regression to "clone" and "init".
+   Try to address the same issue by always restoring the environment
+   and respawning the real underlying command when handling alias.
+
+ * The low-level code that is used to create symbolic references has
+   been updated to share more code with the code that deals with
+   normal references.
+
+ * strbuf_getline() and friends have been redefined to make it easier
+   to identify which callsite of (new) strbuf_getline_lf() should
+   allow and silently ignore carriage-return at the end of the line to
+   help users on DOSsy systems.
+
+ * "git shortlog" used to accumulate various pieces of information
+   regardless of what was asked to be shown in the final output.  It
+   has been optimized by noticing what need not to be collected
+   (e.g. there is no need to collect the log messages when showing
+   only the number of changes).
+
+ * "git checkout $branch" (and other operations that share the same
+   underlying machinery) has been optimized.
+
+ * Automated tests in Travis CI environment has been optimized by
+   persisting runtime statistics of previous "prove" run, executing
+   tests that take longer before other ones; this reduces the total
+   wallclock time.
+
+ * Test scripts have been updated to remove assumptions that are not
+   portable between Git for POSIX and Git for Windows, or to skip ones
+   with expectations that are not satisfiable on Git for Windows.
+
+ * Some calls to strcpy(3) triggers a false warning from static
+   analyzers that are less intelligent than humans, and reducing the
+   number of these false hits helps us notice real issues.  A few
+   calls to strcpy(3) in a couple of programs that are already safe
+   has been rewritten to avoid false warnings.
+
+ * The "name_path" API was an attempt to reduce the need to construct
+   the full path out of a series of path components while walking a
+   tree hierarchy, but over time made less efficient because the path
+   needs to be flattened, e.g. to be compared with another path that
+   is already flat.  The API has been removed and its users have been
+   rewritten to simplify the overall code complexity.
+
+ * Help those who debug http(s) part of the system.
+   (merge 0054045 sp/remote-curl-ssl-strerror later to maint).
+
+ * The internal API to interact with "remote.*" configuration
+   variables has been streamlined.
+
+ * The ref-filter's format-parsing code has been refactored, in
+   preparation for "branch --format" and friends.
+
+ * Traditionally, the tests that try commands that work on the
+   contents in the working tree were named with "worktree" in their
+   filenames, but with the recent addition of "git worktree"
+   subcommand, whose tests are also named similarly, it has become
+   harder to tell them apart.  The traditional tests have been renamed
+   to use "work-tree" instead in an attempt to differentiate them.
+   (merge 5549029 mg/work-tree-tests later to maint).
+
+ * Many codepaths forget to check return value from git_config_set();
+   the function is made to die() to make sure we do not proceed when
+   setting a configuration variable failed.
+   (merge 3d18064 ps/config-error later to maint).
+
+ * Handling of errors while writing into our internal asynchronous
+   process has been made more robust, which reduces flakiness in our
+   tests.
+   (merge 43f3afc jk/epipe-in-async later to maint).
+
+ * There is a new DEVELOPER knob that enables many compiler warning
+   options in the Makefile.
+
+ * The way the test scripts configure the Apache web server has been
+   updated to work also for Apache 2.4 running on RedHat derived
+   distros.
+
+ * Out of maintenance gcc on OSX 10.6 fails to compile the code in
+   'master'; work it around by using clang by default on the platform.
+
+ * The "name_path" API was an attempt to reduce the need to construct
+   the full path out of a series of path components while walking a
+   tree hierarchy, but over time made less efficient because the path
+   needs to be flattened, e.g. to be compared with another path that
+   is already flat, in many cases.  The API has been removed and its
+   users have been rewritten to simplify the overall code complexity.
+   This incidentally also closes some heap-corruption holes.
+
+ * Recent versions of GNU grep is pickier than before to decide if a
+   file is "binary" and refuse to give line-oriented hits when we
+   expect it to, unless explicitly told with "-a" option.  As our
+   scripted Porcelains use sane_grep wrapper for line-oriented data,
+   even when the line may contain non-ASCII payload we took from
+   end-user data, use "grep -a" to implement sane_grep wrapper when
+   using an implementation of "grep" that takes the "-a" option.
+
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.7
+----------------
+
+Unless otherwise noted, all the fixes since v2.7 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * An earlier change in 2.5.x-era broke users' hooks and aliases by
+   exporting GIT_WORK_TREE to point at the root of the working tree,
+   interfering when they tried to use a different working tree without
+   setting GIT_WORK_TREE environment themselves.
+
+ * The "exclude_list" structure has the usual "alloc, nr" pair of
+   fields to be used by ALLOC_GROW(), but clear_pattern_list() forgot
+   to reset 'alloc' to 0 when it cleared 'nr' to discard the managed
+   array.
+
+ * Paths that have been told the index about with "add -N" are not
+   quite yet in the index, but a few commands behaved as if they
+   already are in a harmful way.
+
+ * "git send-email" was confused by escaped quotes stored in the alias
+   files saved by "mutt", which has been corrected.
+
+ * A few non-portable C construct have been spotted by clang compiler
+   and have been fixed.
+
+ * The documentation has been updated to hint the connection between
+   the '--signoff' option and DCO.
+
+ * "git reflog" incorrectly assumed that all objects that used to be
+   at the tip of a ref must be commits, which caused it to segfault.
+
+ * The ignore mechanism saw a few regressions around untracked file
+   listing and sparse checkout selection areas in 2.7.0; the change
+   that is responsible for the regression has been reverted.
+
+ * Some codepaths used fopen(3) when opening a fixed path in $GIT_DIR
+   (e.g. COMMIT_EDITMSG) that is meant to be left after the command is
+   done.  This however did not work well if the repository is set to
+   be shared with core.sharedRepository and the umask of the previous
+   user is tighter.  They have been made to work better by calling
+   unlink(2) and retrying after fopen(3) fails with EPERM.
+
+ * Asking gitweb for a nonexistent commit left a warning in the server
+   log.
+
+   Somebody may want to follow this up with an additional test, perhaps?
+   IIRC, we do test that no Perl warnings are given to the server log,
+   so this should have been caught if our test coverage were good.
+
+ * "git rebase", unlike all other callers of "gc --auto", did not
+   ignore the exit code from "gc --auto".
+
+ * Many codepaths that run "gc --auto" before exiting kept packfiles
+   mapped and left the file descriptors to them open, which was not
+   friendly to systems that cannot remove files that are open.  They
+   now close the packs before doing so.
+
+ * A recent optimization to filter-branch in v2.7.0 introduced a
+   regression when --prune-empty filter is used, which has been
+   corrected.
+
+ * The description for SANITY prerequisite the test suite uses has
+   been clarified both in the comment and in the implementation.
+
+ * "git tag" started listing a tag "foo" as "tags/foo" when a branch
+   named "foo" exists in the same repository; remove this unnecessary
+   disambiguation, which is a regression introduced in v2.7.0.
+
+ * The way "git svn" uses auth parameter was broken by Subversion
+   1.9.0 and later.
+
+ * The "split" subcommand of "git subtree" (in contrib/) incorrectly
+   skipped merges when it shouldn't, which was corrected.
+
+ * A few options of "git diff" did not work well when the command was
+   run from a subdirectory.
+
+ * The command line completion learned a handful of additional options
+   and command specific syntax.
+
+ * dirname() emulation has been added, as Msys2 lacks it.
+
+ * The underlying machinery used by "ls-files -o" and other commands
+   has been taught not to create empty submodule ref cache for a
+   directory that is not a submodule.  This removes a ton of wasted
+   CPU cycles.
+
+ * "git worktree" had a broken code that attempted to auto-fix
+   possible inconsistency that results from end-users moving a
+   worktree to different places without telling Git (the original
+   repository needs to maintain back-pointers to its worktrees,
+   but "mv" run by end-users who are not familiar with that fact
+   will obviously not adjust them), which actually made things
+   worse when triggered.
+
+ * The low-level merge machinery has been taught to use CRLF line
+   termination when inserting conflict markers to merged contents that
+   are themselves CRLF line-terminated.
+
+ * "git push --force-with-lease" has been taught to report if the push
+   needed to force (or fast-forwarded).
+
+ * The emulated "yes" command used in our test scripts has been
+   tweaked not to spend too much time generating unnecessary output
+   that is not used, to help those who test on Windows where it would
+   not stop until it fills the pipe buffer due to lack of SIGPIPE.
+
+ * The documentation for "git clean" has been corrected; it mentioned
+   that .git/modules/* are removed by giving two "-f", which has never
+   been the case.
+
+ * The vimdiff backend for "git mergetool" has been tweaked to arrange
+   and number buffers in the order that would match the expectation of
+   majority of people who read left to right, then top down and assign
+   buffers 1 2 3 4 "mentally" to local base remote merge windows based
+   on that order.
+
+ * "git show 'HEAD:Foo[BAR]Baz'" did not interpret the argument as a
+   rev, i.e. the object named by the pathname with wildcard
+   characters in a tree object.
+   (merge aac4fac nd/dwim-wildcards-as-pathspecs later to maint).
+
+ * "git rev-parse --git-common-dir" used in the worktree feature
+   misbehaved when run from a subdirectory.
+   (merge 17f1365 nd/git-common-dir-fix later to maint).
+
+ * "git worktree add -B <branchname>" did not work.
+
+ * The "v(iew)" subcommand of the interactive "git am -i" command was
+   broken in 2.6.0 timeframe when the command was rewritten in C.
+   (merge 708b8cc jc/am-i-v-fix later to maint).
+
+ * "git merge-tree" used to mishandle "both sides added" conflict with
+   its own "create a fake ancestor file that has the common parts of
+   what both sides have added and do a 3-way merge" logic; this has
+   been updated to use the usual "3-way merge with an empty blob as
+   the fake common ancestor file" approach used in the rest of the
+   system.
+   (merge 907681e jk/no-diff-emit-common later to maint).
+
+ * The memory ownership rule of fill_textconv() API, which was a bit
+   tricky, has been documented a bit better.
+   (merge a64e6a4 jk/more-comments-on-textconv later to maint).
+
+ * Update various codepaths to avoid manually-counted malloc().
+   (merge 08c95df jk/tighten-alloc later to maint).
+
+ * The documentation did not clearly state that the 'simple' mode is
+   now the default for "git push" when push.default configuration is
+   not set.
+   (merge f6b1fb3 mm/push-simple-doc later to maint).
+
+ * Recent versions of GNU grep are pickier when their input contains
+   arbitrary binary data, which some of our tests uses.  Rewrite the
+   tests to sidestep the problem.
+   (merge 3b1442d jk/grep-binary-workaround-in-test later to maint).
+
+ * A helper function "git submodule" uses since v2.7.0 to list the
+   modules that match the pathspec argument given to its subcommands
+   (e.g. "submodule add <repo> <path>") has been fixed.
+   (merge 2b56bb7 sb/submodule-module-list-fix later to maint).
+
+ * "git config section.var value" to set a value in per-repository
+   configuration file failed when it was run outside any repository,
+   but didn't say the reason correctly.
+   (merge 638fa62 js/config-set-in-non-repository later to maint).
+
+ * The code to read the pack data using the offsets stored in the pack
+   idx file has been made more carefully check the validity of the
+   data in the idx.
+   (merge 7465feb jk/pack-idx-corruption-safety later to maint).
+
+ * Other minor clean-ups and documentation updates
+   (merge f459823 ak/extract-argv0-last-dir-sep later to maint).
+   (merge 63ca1c0 ak/git-strip-extension-from-dashed-command later to maint).
+   (merge 4867f11 ps/plug-xdl-merge-leak later to maint).
+   (merge 4938686 dt/initial-ref-xn-commit-doc later to maint).
+   (merge 9537f21 ma/update-hooks-sample-typofix later to maint).
diff --git a/Documentation/RelNotes/2.8.1.txt b/Documentation/RelNotes/2.8.1.txt
new file mode 100644
index 0000000000..ef6d80b008
--- /dev/null
+++ b/Documentation/RelNotes/2.8.1.txt
@@ -0,0 +1,9 @@
+Git v2.8.1 Release Notes
+========================
+
+Fixes since v2.8
+----------------
+
+ * "make rpmbuild" target was broken as its input, git.spec.in, was
+   not updated to match a file it describes that has been renamed
+   recently.  This has been fixed.
diff --git a/Documentation/RelNotes/2.8.2.txt b/Documentation/RelNotes/2.8.2.txt
new file mode 100644
index 0000000000..447b1933a8
--- /dev/null
+++ b/Documentation/RelNotes/2.8.2.txt
@@ -0,0 +1,70 @@
+Git v2.8.2 Release Notes
+========================
+
+Fixes since v2.8.1
+------------------
+
+ * The embedded args argv-array in the child process is used to build
+   the command line to run pack-objects instead of using a separate
+   array of strings.
+
+ * Bunch of tests on "git clone" has been renumbered for better
+   organization.
+
+ * The tests that involve running httpd leaked the system-wide
+   configuration in /etc/gitconfig to the tested environment.
+
+ * "index-pack --keep=<msg>" was broken since v2.1.0 timeframe.
+
+ * "git config --get-urlmatch", unlike other variants of the "git
+   config --get" family, did not signal error with its exit status
+   when there was no matching configuration.
+
+ * The "--local-env-vars" and "--resolve-git-dir" options of "git
+   rev-parse" failed to work outside a repository when the command's
+   option parsing was rewritten in 1.8.5 era.
+
+ * Fetching of history by naming a commit object name directly didn't
+   work across remote-curl transport.
+
+ * A small memory leak in an error codepath has been plugged in xdiff
+   code.
+
+ * strbuf_getwholeline() did not NUL-terminate the buffer on certain
+   corner cases in its error codepath.
+
+ * The startup_info data, which records if we are working inside a
+   repository (among other things), are now uniformly available to Git
+   subcommand implementations, and Git avoids attempting to touch
+   references when we are not in a repository.
+
+ * "git mergetool" did not work well with conflicts that both sides
+   deleted.
+
+ * "git send-email" had trouble parsing alias file in mailrc format
+   when lines in it had trailing whitespaces on them.
+
+ * When "git merge --squash" stopped due to conflict, the concluding
+   "git commit" failed to read in the SQUASH_MSG that shows the log
+   messages from all the squashed commits.
+
+ * "git merge FETCH_HEAD" dereferenced NULL pointer when merging
+   nothing into an unborn history (which is arguably unusual usage,
+   which perhaps was the reason why nobody noticed it).
+
+ * Build updates for MSVC.
+
+ * "git diff -M" used to work better when two originally identical
+   files A and B got renamed to X/A and X/B by pairing A to X/A and B
+   to X/B, but this was broken in the 2.0 timeframe.
+
+ * "git send-pack --all <there>" was broken when its command line
+   option parsing was written in the 2.6 timeframe.
+
+ * When running "git blame $path" with unnormalized data in the index
+   for the path, the data in the working tree was blamed, even though
+   "git add" would not have changed what is already in the index, due
+   to "safe crlf" that disables the line-end conversion.  It has been
+   corrected.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.8.3.txt b/Documentation/RelNotes/2.8.3.txt
new file mode 100644
index 0000000000..a63825ed87
--- /dev/null
+++ b/Documentation/RelNotes/2.8.3.txt
@@ -0,0 +1,101 @@
+Git v2.8.3 Release Notes
+========================
+
+Fixes since v2.8.2
+------------------
+
+ * "git send-email" now uses a more readable timestamps when
+   formulating a message ID.
+
+ * The repository set-up sequence has been streamlined (the biggest
+   change is that there is no longer git_config_early()), so that we
+   do not attempt to look into refs/* when we know we do not have a
+   Git repository.
+
+ * When "git worktree" feature is in use, "git branch -d" allowed
+   deletion of a branch that is checked out in another worktree
+
+ * When "git worktree" feature is in use, "git branch -m" renamed a
+   branch that is checked out in another worktree without adjusting
+   the HEAD symbolic ref for the worktree.
+
+ * "git format-patch --help" showed `-s` and `--no-patch` as if these
+   are valid options to the command.  We already hide `--patch` option
+   from the documentation, because format-patch is about showing the
+   diff, and the documentation now hides these options as well.
+
+ * A change back in version 2.7 to "git branch" broke display of a
+   symbolic ref in a non-standard place in the refs/ hierarchy (we
+   expect symbolic refs to appear in refs/remotes/*/HEAD to point at
+   the primary branch the remote has, and as .git/HEAD to point at the
+   branch we locally checked out).
+
+ * A partial rewrite of "git submodule" in the 2.7 timeframe changed
+   the way the gitdir: pointer in the submodules point at the real
+   repository location to use absolute paths by accident.  This has
+   been corrected.
+
+ * "git commit" misbehaved in a few minor ways when an empty message
+   is given via -m '', all of which has been corrected.
+
+ * Support for CRAM-MD5 authentication method in "git imap-send" did
+   not work well.
+
+ * The socks5:// proxy support added back in 2.6.4 days was not aware
+   that socks5h:// proxies behave differently.
+
+ * "git config" had a codepath that tried to pass a NULL to
+   printf("%s"), which nobody seems to have noticed.
+
+ * On Cygwin, object creation uses the "create a temporary and then
+   rename it to the final name" pattern, not "create a temporary,
+   hardlink it to the final name and then unlink the temporary"
+   pattern.
+
+   This is necessary to use Git on Windows shared directories, and is
+   already enabled for the MinGW and plain Windows builds.  It also
+   has been used in Cygwin packaged versions of Git for quite a while.
+   See https://lore.kernel.org/git/20160419091055.GF2345@xxxxxxxxxxxxx/
+   and https://lore.kernel.org/git/20150811100527.GW14466@xxxxxxxxxxxxx/.
+
+ * "git replace -e" did not honour "core.editor" configuration.
+
+ * Upcoming OpenSSL 1.1.0 will break compilation b updating a few APIs
+   we use in imap-send, which has been adjusted for the change.
+
+ * "git submodule" reports the paths of submodules the command
+   recurses into, but this was incorrect when the command was not run
+   from the root level of the superproject.
+
+ * The test scripts for "git p4" (but not "git p4" implementation
+   itself) has been updated so that they would work even on a system
+   where the installed version of Python is python 3.
+
+ * The "user.useConfigOnly" configuration variable makes it an error
+   if users do not explicitly set user.name and user.email.  However,
+   its check was not done early enough and allowed another error to
+   trigger, reporting that the default value we guessed from the
+   system setting was unusable.  This was a suboptimal end-user
+   experience as we want the users to set user.name/user.email without
+   relying on the auto-detection at all.
+
+ * "git mv old new" did not adjust the path for a submodule that lives
+   as a subdirectory inside old/ directory correctly.
+
+ * "git push" from a corrupt repository that attempts to push a large
+   number of refs deadlocked; the thread to relay rejection notices
+   for these ref updates blocked on writing them to the main thread,
+   after the main thread at the receiving end notices that the push
+   failed and decides not to read these notices and return a failure.
+
+ * A question by "git send-email" to ask the identity of the sender
+   has been updated.
+
+ * Recent update to Git LFS broke "git p4" by changing the output from
+   its "lfs pointer" subcommand.
+
+ * Some multi-byte encoding can have a backslash byte as a later part
+   of one letter, which would confuse "highlight" filter used in
+   gitweb.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.8.4.txt b/Documentation/RelNotes/2.8.4.txt
new file mode 100644
index 0000000000..f4e2552836
--- /dev/null
+++ b/Documentation/RelNotes/2.8.4.txt
@@ -0,0 +1,69 @@
+Git v2.8.4 Release Notes
+========================
+
+Fixes since v2.8.3
+------------------
+
+ * Documentation for "git merge --verify-signatures" has been updated
+   to clarify that the signature of only the commit at the tip is
+   verified.  Also the phrasing used for signature and key validity is
+   adjusted to align with that used by OpenPGP.
+
+ * On Windows, .git and optionally any files whose name starts with a
+   dot are now marked as hidden, with a core.hideDotFiles knob to
+   customize this behaviour.
+
+ * Portability enhancement for "rebase -i" to help platforms whose
+   shell does not like "for i in <empty>" (which is not POSIX-kosher).
+
+ * "git fsck" learned to catch NUL byte in a commit object as
+   potential error and warn.
+
+ * CI test was taught to build documentation pages.
+
+ * Many 'linkgit:<git documentation page>' references were broken,
+   which are all fixed with this.
+
+ * "git describe --contains" often made a hard-to-justify choice of
+   tag to give name to a given commit, because it tried to come up
+   with a name with smallest number of hops from a tag, causing an old
+   commit whose close descendant that is recently tagged were not
+   described with respect to an old tag but with a newer tag.  It did
+   not help that its computation of "hop" count was further tweaked to
+   penalize being on a side branch of a merge.  The logic has been
+   updated to favor using the tag with the oldest tagger date, which
+   is a lot easier to explain to the end users: "We describe a commit
+   in terms of the (chronologically) oldest tag that contains the
+   commit."
+
+ * Running tests with '-x' option to trace the individual command
+   executions is a useful way to debug test scripts, but some tests
+   that capture the standard error stream and check what the command
+   said can be broken with the trace output mixed in.  When running
+   our tests under "bash", however, we can redirect the trace output
+   to another file descriptor to keep the standard error of programs
+   being tested intact.
+
+ * "http.cookieFile" configuration variable clearly wants a pathname,
+   but we forgot to treat it as such by e.g. applying tilde expansion.
+
+ * When de-initialising all submodules, "git submodule deinit" gave a
+   faulty recommendation to use "git submodule deinit .", which would
+   result in a strange error message in a pathological corner case.
+   This has been corrected to suggest "submodule deinit --all" instead.
+
+ * Many commands normalize command line arguments from NFD to NFC
+   variant of UTF-8 on OSX, but commands in the "diff" family did
+   not, causing "git diff $path" to complain that no such path is
+   known to Git.  They have been taught to do the normalization.
+
+ * A couple of bugs around core.autocrlf have been fixed.
+
+ * "git difftool" learned to handle unmerged paths correctly in
+   dir-diff mode.
+
+ * The "are we talking with TTY, doing an interactive session?"
+   detection has been updated to work better for "Git for Windows".
+
+
+Also contains other minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.8.5.txt b/Documentation/RelNotes/2.8.5.txt
new file mode 100644
index 0000000000..7bd179fa12
--- /dev/null
+++ b/Documentation/RelNotes/2.8.5.txt
@@ -0,0 +1,12 @@
+Git v2.8.5 Release Notes
+========================
+
+Fixes since v2.8.4
+------------------
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
diff --git a/Documentation/RelNotes/2.8.6.txt b/Documentation/RelNotes/2.8.6.txt
new file mode 100644
index 0000000000..d8db55d920
--- /dev/null
+++ b/Documentation/RelNotes/2.8.6.txt
@@ -0,0 +1,4 @@
+Git v2.8.6 Release Notes
+========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/RelNotes/2.9.0.txt b/Documentation/RelNotes/2.9.0.txt
new file mode 100644
index 0000000000..991640119a
--- /dev/null
+++ b/Documentation/RelNotes/2.9.0.txt
@@ -0,0 +1,512 @@
+Git 2.9 Release Notes
+=====================
+
+Backward compatibility notes
+----------------------------
+
+The end-user facing Porcelain level commands in the "git diff" and
+"git log" family by default enable the rename detection; you can still
+use "diff.renames" configuration variable to disable this.
+
+Merging two branches that have no common ancestor with "git merge" is
+by default forbidden now to prevent creating such an unusual merge by
+mistake.
+
+The output formats of "git log" that indents the commit log message by
+4 spaces now expands HT in the log message by default.  You can use
+the "--no-expand-tabs" option to disable this.
+
+"git commit-tree" plumbing command required the user to always sign
+its result when the user sets the commit.gpgsign configuration
+variable, which was an ancient mistake, which this release corrects.
+A script that drives commit-tree, if it relies on this mistake, now
+needs to read commit.gpgsign and pass the -S option as necessary.
+
+
+Updates since v2.8
+------------------
+
+UI, Workflows & Features
+
+ * Comes with git-multimail 1.3.1 (in contrib/).
+
+ * The end-user facing commands like "git diff" and "git log"
+   now enable the rename detection by default.
+
+ * The credential.helper configuration variable is cumulative and
+   there is no good way to override it from the command line.  As
+   a special case, giving an empty string as its value now serves
+   as the signal to clear the values specified in various files.
+
+ * A new "interactive.diffFilter" configuration can be used to
+   customize the diff shown in "git add -i" sessions.
+
+ * "git p4" now allows P4 author names to be mapped to Git author
+   names.
+
+ * "git rebase -x" can be used without passing "-i" option.
+
+ * "git -c credential.<var>=<value> submodule" can now be used to
+   propagate configuration variables related to credential helper
+   down to the submodules.
+
+ * "git tag" can create an annotated tag without explicitly given an
+   "-a" (or "-s") option (i.e. when a tag message is given).  A new
+   configuration variable, tag.forceSignAnnotated, can be used to tell
+   the command to create signed tag in such a situation.
+
+ * "git merge" used to allow merging two branches that have no common
+   base by default, which led to a brand new history of an existing
+   project created and then get pulled by an unsuspecting maintainer,
+   which allowed an unnecessary parallel history merged into the
+   existing project.  The command has been taught not to allow this by
+   default, with an escape hatch "--allow-unrelated-histories" option
+   to be used in a rare event that merges histories of two projects
+   that started their lives independently.
+
+ * "git pull" has been taught to pass the "--allow-unrelated-histories"
+   option to underlying "git merge".
+
+ * "git apply -v" learned to report paths in the patch that were
+   skipped via --include/--exclude mechanism or being outside the
+   current working directory.
+
+ * Shell completion (in contrib/) updates.
+
+ * The commit object name reported when "rebase -i" stops has been
+   shortened.
+
+ * "git worktree add" can be given "--no-checkout" option to only
+   create an empty worktree without checking out the files.
+
+ * "git mergetools" learned to drive ExamDiff.
+
+ * "git pull --rebase" learned "--[no-]autostash" option, so that
+   the rebase.autostash configuration variable set to true can be
+   overridden from the command line.
+
+ * When "git log" shows the log message indented by 4-spaces, the
+   remainder of a line after a HT does not align in the way the author
+   originally intended.  The command now expands tabs by default to help
+   such a case, and allows the users to override it with a new option,
+   "--no-expand-tabs".
+
+ * "git send-email" now uses a more readable timestamps when
+   formulating a message ID.
+
+ * "git rerere" can encounter two or more files with the same conflict
+   signature that have to be resolved in different ways, but there was
+   no way to record these separate resolutions.
+
+ * "git p4" learned to record P4 jobs in Git commit that imports from
+   the history in Perforce.
+
+ * "git describe --contains" often made a hard-to-justify choice of
+   tag to name a given commit, because it tried to come up
+   with a name with smallest number of hops from a tag, causing an old
+   commit whose close descendant that is recently tagged were not
+   described with respect to an old tag but with a newer tag.  It did
+   not help that its computation of "hop" count was further tweaked to
+   penalize being on a side branch of a merge.  The logic has been
+   updated to favor using the tag with the oldest tagger date, which
+   is a lot easier to explain to the end users: "We describe a commit
+   in terms of the (chronologically) oldest tag that contains the
+   commit."
+
+ * "git clone" learned the "--shallow-submodules" option.
+
+ * HTTP transport clients learned to throw extra HTTP headers at the
+   server, specified via http.extraHeader configuration variable.
+
+ * The "--compaction-heuristic" option to "git diff" family of
+   commands enables a heuristic to make the patch output more readable
+   by using a blank line as a strong hint that the contents before and
+   after it belong to logically separate units.  It is still
+   experimental.
+
+ * A new configuration variable core.hooksPath allows customizing
+   where the hook directory is.
+
+ * An earlier addition of "sanitize_submodule_env" with 14111fc4 (git:
+   submodule honor -c credential.* from command line, 2016-02-29)
+   turned out to be a convoluted no-op; implement what it wanted to do
+   correctly, and stop filtering settings given via "git -c var=val".
+
+ * "git commit --dry-run" reported "No, no, you cannot commit." in one
+   case where "git commit" would have allowed you to commit, and this
+   improves it a little bit ("git commit --dry-run --short" still does
+   not give you the correct answer, for example).  This is a stop-gap
+   measure in that "commit --short --dry-run" still gives an incorrect
+   result.
+
+ * The experimental "multiple worktree" feature gains more safety to
+   forbid operations on a branch that is checked out or being actively
+   worked on elsewhere, by noticing that e.g. it is being rebased.
+
+ * "git format-patch" learned a new "--base" option to record what
+   (public, well-known) commit the original series was built on in
+   its output.
+
+ * "git commit" learned to pay attention to the "commit.verbose"
+   configuration variable and act as if the "--verbose" option
+   was given from the command line.
+
+ * Updated documentation gives hints to GMail users with two-factor
+   auth enabled that they need app-specific-password when using
+   "git send-email".
+
+ * The manpage output of our documentation did not render well in
+   terminal; typeset literals in bold by default to make them stand
+   out more.
+
+ * The mark-up in the top-level README.md file has been updated to
+   typeset CLI command names differently from the body text.
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * The embedded args argv-array in the child process is used to build
+   the command line to run pack-objects instead of using a separate
+   array of strings.
+
+ * A test for tags has been restructured so that more parts of it can
+   easily be run on a platform without a working GnuPG.
+
+ * The startup_info data, which records if we are working inside a
+   repository (among other things), are now uniformly available to Git
+   subcommand implementations, and Git avoids attempting to touch
+   references when we are not in a repository.
+
+ * The command line argument parser for "receive-pack" has been
+   rewritten to use parse-options.
+
+ * A major part of "git submodule update" has been ported to C to take
+   advantage of the recently added framework to run download tasks in
+   parallel.  Other updates to "git submodule" that move pieces of
+   logic to C continues.
+
+ * Rename bunch of tests on "git clone" for better organization.
+
+ * The tests that involve running httpd leaked the system-wide
+   configuration in /etc/gitconfig to the tested environment.
+
+ * Build updates for MSVC.
+
+ * The repository set-up sequence has been streamlined (the biggest
+   change is that there is no longer git_config_early()), so that we
+   do not attempt to look into refs/* when we know we do not have a
+   Git repository.
+
+ * Code restructuring around the "refs" API to prepare for pluggable
+   refs backends.
+
+ * Sources to many test helper binaries and the generated helpers
+   have been moved to t/helper/ subdirectory to reduce clutter at the
+   top level of the tree.
+
+ * Unify internal logic between "git tag -v" and "git verify-tag"
+   commands by making one directly call into the other.
+
+ * "merge-recursive" strategy incorrectly checked if a path that is
+   involved in its internal merge exists in the working tree.
+
+ * The test scripts for "git p4" (but not "git p4" implementation
+   itself) has been updated so that they would work even on a system
+   where the installed version of Python is python 3.
+
+ * As nobody maintains our in-tree git.spec.in and distros use their
+   own spec file, we stopped pretending that we support "make rpm".
+
+ * Move from "unsigned char[20]" to "struct object_id" continues.
+
+ * The code for warning_errno/die_errno has been refactored and a new
+   error_errno() reporting helper is introduced.
+   (merge 1da045f nd/error-errno later to maint).
+
+ * Running tests with '-x' option to trace the individual command
+   executions is a useful way to debug test scripts, but some tests
+   that capture the standard error stream and check what the command
+   said can be broken with the trace output mixed in.  When running
+   our tests under "bash", however, we can redirect the trace output
+   to another file descriptor to keep the standard error of programs
+   being tested intact.
+
+ * t0040 had too many unnecessary repetitions in its test data.  Teach
+   test-parse-options program so that a caller can tell what it
+   expects in its output, so that these repetitions can be cleaned up.
+
+ * Add perf test for "rebase -i".
+
+ * Common mistakes when writing gitlink: in our documentation are
+   found by "make check-docs".
+
+ * t9xxx series has been updated primarily for readability, while
+   fixing small bugs in it.  A few scripted Porcelain commands have
+   also been updated to fix possible bugs around their use of
+   "test -z" and "test -n".
+
+ * CI test was taught to run git-svn tests.
+
+ * "git cat-file --batch-all" has been sped up, by taking advantage
+   of the fact that it does not have to read a list of objects, in two
+   ways.
+
+ * test updates to make it more readable and maintainable.
+   (merge e6273f4 es/t1500-modernize later to maint).
+
+ * "make DEVELOPER=1" worked as expected; setting DEVELOPER=1 in
+   config.mak didn't.
+   (merge 51dd3e8 mm/makefile-developer-can-be-in-config-mak later to maint).
+
+ * The way how "submodule--helper list" signals unmatch error to its
+   callers has been updated.
+
+ * A bash-ism "local" has been removed from "git submodule" scripted
+   Porcelain.
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.8
+----------------
+
+Unless otherwise noted, all the fixes since v2.8 in the maintenance
+track are contained in this release (see the maintenance releases'
+notes for details).
+
+ * "git config --get-urlmatch", unlike other variants of the "git
+   config --get" family, did not signal error with its exit status
+   when there was no matching configuration.
+
+ * The "--local-env-vars" and "--resolve-git-dir" options of "git
+   rev-parse" failed to work outside a repository when the command's
+   option parsing was rewritten in 1.8.5 era.
+
+ * "git index-pack --keep[=<msg>] pack-$name.pack" simply did not work.
+
+ * Fetching of history by naming a commit object name directly didn't
+   work across remote-curl transport.
+
+ * A small memory leak in an error codepath has been plugged in xdiff
+   code.
+
+ * strbuf_getwholeline() did not NUL-terminate the buffer on certain
+   corner cases in its error codepath.
+
+ * "git mergetool" did not work well with conflicts that both sides
+   deleted.
+
+ * "git send-email" had trouble parsing alias file in mailrc format
+   when lines in it had trailing whitespaces on them.
+
+ * When "git merge --squash" stopped due to conflict, the concluding
+   "git commit" failed to read in the SQUASH_MSG that shows the log
+   messages from all the squashed commits.
+
+ * "git merge FETCH_HEAD" dereferenced NULL pointer when merging
+   nothing into an unborn history (which is arguably unusual usage,
+   which perhaps was the reason why nobody noticed it).
+
+ * When "git worktree" feature is in use, "git branch -d" allowed
+   deletion of a branch that is checked out in another worktree,
+   which was wrong.
+
+ * When "git worktree" feature is in use, "git branch -m" renamed a
+   branch that is checked out in another worktree without adjusting
+   the HEAD symbolic ref for the worktree.
+
+ * "git diff -M" used to work better when two originally identical
+   files A and B got renamed to X/A and X/B by pairing A to X/A and B
+   to X/B, but this was broken in the 2.0 timeframe.
+
+ * "git send-pack --all <there>" was broken when its command line
+   option parsing was written in the 2.6 timeframe.
+
+ * "git format-patch --help" showed `-s` and `--no-patch` as if these
+   are valid options to the command.  We already hide `--patch` option
+   from the documentation, because format-patch is about showing the
+   diff, and the documentation now hides these options as well.
+
+ * When running "git blame $path" with unnormalized data in the index
+   for the path, the data in the working tree was blamed, even though
+   "git add" would not have changed what is already in the index, due
+   to "safe crlf" that disables the line-end conversion.  It has been
+   corrected.
+
+ * A change back in version 2.7 to "git branch" broke display of a
+   symbolic ref in a non-standard place in the refs/ hierarchy (we
+   expect symbolic refs to appear in refs/remotes/*/HEAD to point at
+   the primary branch the remote has, and as .git/HEAD to point at the
+   branch we locally checked out).
+
+ * A partial rewrite of "git submodule" in the 2.7 timeframe changed
+   the way the gitdir: pointer in the submodules point at the real
+   repository location to use absolute paths by accident.  This has
+   been corrected.
+
+ * "git commit" misbehaved in a few minor ways when an empty message
+   is given via -m '', all of which has been corrected.
+
+ * Support for CRAM-MD5 authentication method in "git imap-send" did
+   not work well.
+
+ * Upcoming OpenSSL 1.1.0 will break compilation by updating a few API
+   elements we use in imap-send, which has been adjusted for the change.
+
+ * The socks5:// proxy support added back in 2.6.4 days was not aware
+   that socks5h:// proxies behave differently from socks5:// proxies.
+
+ * "git config" had a codepath that tried to pass a NULL to
+   printf("%s"), which nobody seems to have noticed.
+
+ * On Cygwin, object creation uses the "create a temporary and then
+   rename it to the final name" pattern, not "create a temporary,
+   hardlink it to the final name and then unlink the temporary"
+   pattern.
+
+   This is necessary to use Git on Windows shared directories, and is
+   already enabled for the MinGW and plain Windows builds.  It also
+   has been used in Cygwin packaged versions of Git for quite a while.
+   See https://lore.kernel.org/git/20160419091055.GF2345@xxxxxxxxxxxxx/
+
+ * "merge-octopus" strategy did not ensure that the index is clean
+   when merge begins.
+
+ * When "git merge" notices that the merge can be resolved purely at
+   the tree level (without having to merge blobs) and the resulting
+   tree happens to already exist in the object store, it forgot to
+   update the index, which left an inconsistent state that would
+   break later operations.
+
+ * "git submodule" reports the paths of submodules the command
+   recurses into, but these paths were incorrectly reported when
+   the command was not run from the root level of the superproject.
+
+ * The "user.useConfigOnly" configuration variable makes it an error
+   if users do not explicitly set user.name and user.email.  However,
+   its check was not done early enough and allowed another error to
+   trigger, reporting that the default value we guessed from the
+   system setting was unusable.  This was a suboptimal end-user
+   experience as we want the users to set user.name/user.email without
+   relying on the auto-detection at all.
+
+ * "git mv old new" did not adjust the path for a submodule that lives
+   as a subdirectory inside old/ directory correctly.
+
+ * "git replace -e" did not honour "core.editor" configuration.
+
+ * "git push" from a corrupt repository that attempts to push a large
+   number of refs deadlocked; the thread to relay rejection notices
+   for these ref updates blocked on writing them to the main thread,
+   after the main thread at the receiving end notices that the push
+   failed and decides not to read these notices and return a failure.
+
+ * mmap emulation on Windows has been optimized and work better without
+   consuming paging store when not needed.
+
+ * A question by "git send-email" to ask the identity of the sender
+   has been updated.
+
+ * UI consistency improvements for "git mergetool".
+
+ * "git rebase -m" could be asked to rebase an entire branch starting
+   from the root, but failed by assuming that there always is a parent
+   commit to the first commit on the branch.
+
+ * Fix a broken "p4 lfs" test.
+
+ * Recent update to Git LFS broke "git p4" by changing the output from
+   its "lfs pointer" subcommand.
+
+ * "git fetch" test t5510 was flaky while running a (forced) automagic
+   garbage collection.
+
+ * Documentation updates to help contributors setting up Travis CI
+   test for their patches.
+
+ * Some multi-byte encoding can have a backslash byte as a later part
+   of one letter, which would confuse "highlight" filter used in
+   gitweb.
+
+ * "git commit-tree" plumbing command required the user to always sign
+   its result when the user sets the commit.gpgsign configuration
+   variable, which was an ancient mistake.  Rework "git rebase" that
+   relied on this mistake so that it reads commit.gpgsign and pass (or
+   not pass) the -S option to "git commit-tree" to keep the end-user
+   expectation the same, while teaching "git commit-tree" to ignore
+   the configuration variable.  This will stop requiring the users to
+   sign commit objects used internally as an implementation detail of
+   "git stash".
+
+ * "http.cookieFile" configuration variable clearly wants a pathname,
+   but we forgot to treat it as such by e.g. applying tilde expansion.
+
+ * Consolidate description of tilde-expansion that is done to
+   configuration variables that take pathname to a single place.
+
+ * Correct faulty recommendation to use "git submodule deinit ." when
+   de-initialising all submodules, which would result in a strange
+   error message in a pathological corner case.
+
+ * Many 'linkgit:<git documentation page>' references were broken,
+   which are all fixed with this.
+
+ * "git rerere" can get confused by conflict markers deliberately left
+   by the inner merge step, because they are indistinguishable from
+   the real conflict markers left by the outermost merge which are
+   what the end user and "rerere" need to look at.  This was fixed by
+   making the conflict markers left by the inner merges a bit longer.
+   (merge 0f9fd5c jc/ll-merge-internal later to maint).
+
+ * CI test was taught to build documentation pages.
+
+ * "git fsck" learned to catch NUL byte in a commit object as
+   potential error and warn.
+
+ * Portability enhancement for "rebase -i" to help platforms whose
+   shell does not like "for i in <empty>" (which is not POSIX-kosher).
+
+ * On Windows, .git and optionally any files whose name starts with a
+   dot are now marked as hidden, with a core.hideDotFiles knob to
+   customize this behaviour.
+
+ * Documentation for "git merge --verify-signatures" has been updated
+   to clarify that the signature of only the commit at the tip is
+   verified.  Also the phrasing used for signature and key validity is
+   adjusted to align with that used by OpenPGP.
+
+ * A couple of bugs around core.autocrlf have been fixed.
+
+ * Many commands normalize command line arguments from NFD to NFC
+   variant of UTF-8 on OSX, but commands in the "diff" family did
+   not, causing "git diff $path" to complain that no such path is
+   known to Git.  They have been taught to do the normalization.
+
+ * "git difftool" learned to handle unmerged paths correctly in
+   dir-diff mode.
+
+ * The "are we talking with TTY, doing an interactive session?"
+   detection has been updated to work better for "Git for Windows".
+
+ * We forgot to add "git log --decorate=auto" to documentation when we
+   added the feature back in v2.1.0 timeframe.
+   (merge 462cbb4 rj/log-decorate-auto later to maint).
+
+ * "git fast-import --export-marks" would overwrite the existing marks
+   file even when it makes a dump from its custom die routine.
+   Prevent it from doing so when we have an import-marks file but
+   haven't finished reading it.
+   (merge f4beed6 fc/fast-import-broken-marks-file later to maint).
+
+ * "git rebase -i", after it fails to auto-resolve the conflict, had
+   an unnecessary call to "git rerere" from its very early days, which
+   was spotted recently; the call has been removed.
+   (merge 7063693 js/rebase-i-dedup-call-to-rerere later to maint).
+
+ * Other minor clean-ups and documentation updates
+   (merge cd82b7a pa/cherry-pick-doc-typo later to maint).
+   (merge 2bb73ae rs/patch-id-use-skip-prefix later to maint).
+   (merge aa20cbc rs/apply-name-terminate later to maint).
+   (merge fe17fc0 jc/t2300-setup later to maint).
+   (merge e256eec jk/shell-portability later to maint).
diff --git a/Documentation/RelNotes/2.9.1.txt b/Documentation/RelNotes/2.9.1.txt
new file mode 100644
index 0000000000..338394097e
--- /dev/null
+++ b/Documentation/RelNotes/2.9.1.txt
@@ -0,0 +1,117 @@
+Git v2.9.1 Release Notes
+========================
+
+Fixes since v2.9
+----------------
+
+ * When "git daemon" is run without --[init-]timeout specified, a
+   connection from a client that silently goes offline can hang around
+   for a long time, wasting resources.  The socket-level KEEPALIVE has
+   been enabled to allow the OS to notice such failed connections.
+
+ * The commands in `git log` family take %C(auto) in a custom format
+   string.  This unconditionally turned the color on, ignoring
+   --no-color or with --color=auto when the output is not connected to
+   a tty; this was corrected to make the format truly behave as
+   "auto".
+
+ * "git rev-list --count" whose walk-length is limited with "-n"
+   option did not work well with the counting optimized to look at the
+   bitmap index.
+
+ * "git show -W" (extend hunks to cover the entire function, delimited
+   by lines that match the "funcname" pattern) used to show the entire
+   file when a change added an entire function at the end of the file,
+   which has been fixed.
+
+ * The documentation set has been updated so that literal commands,
+   configuration variables and environment variables are consistently
+   typeset in fixed-width font and bold in manpages.
+
+ * "git svn propset" subcommand that was added in 2.3 days is
+   documented now.
+
+ * The documentation tries to consistently spell "GPG"; when
+   referring to the specific program name, "gpg" is used.
+
+ * "git reflog" stopped upon seeing an entry that denotes a branch
+   creation event (aka "unborn"), which made it appear as if the
+   reflog was truncated.
+
+ * The git-prompt scriptlet (in contrib/) was not friendly with those
+   who uses "set -u", which has been fixed.
+
+ * A codepath that used alloca(3) to place an unbounded amount of data
+   on the stack has been updated to avoid doing so.
+
+ * "git update-index --add --chmod=+x file" may be usable as an escape
+   hatch, but not a friendly thing to force for people who do need to
+   use it regularly.  "git add --chmod=+x file" can be used instead.
+
+ * Build improvements for gnome-keyring (in contrib/)
+
+ * "git status" used to say "working directory" when it meant "working
+   tree".
+
+ * Comments about misbehaving FreeBSD shells have been clarified with
+   the version number (9.x and before are broken, newer ones are OK).
+
+ * "git cherry-pick A" worked on an unborn branch, but "git
+   cherry-pick A..B" didn't.
+
+ * "git add -i/-p" learned to honor diff.compactionHeuristic
+   experimental knob, so that the user can work on the same hunk split
+   as "git diff" output.
+
+ * "log --graph --format=" learned that "%>|(N)" specifies the width
+   relative to the terminal's left edge, not relative to the area to
+   draw text that is to the right of the ancestry-graph section.  It
+   also now accepts negative N that means the column limit is relative
+   to the right border.
+
+ * The ownership rule for the piece of memory that hold references to
+   be fetched in "git fetch" was screwy, which has been cleaned up.
+
+ * "git bisect" makes an internal call to "git diff-tree" when
+   bisection finds the culprit, but this call did not initialize the
+   data structure to pass to the diff-tree API correctly.
+
+ * Formats of the various data (and how to validate them) where we use
+   GPG signature have been documented.
+
+ * Fix an unintended regression in v2.9 that breaks "clone --depth"
+   that recurses down to submodules by forcing the submodules to also
+   be cloned shallowly, which many server instances that host upstream
+   of the submodules are not prepared for.
+
+ * Fix unnecessarily waste in the idiomatic use of ': ${VAR=default}'
+   to set the default value, without enclosing it in double quotes.
+
+ * Some platform-specific code had non-ANSI strict declarations of C
+   functions that do not take any parameters, which has been
+   corrected.
+
+ * The internal code used to show local timezone offset is not
+   prepared to handle timestamps beyond year 2100, and gave a
+   bogus offset value to the caller.  Use a more benign looking
+   +0000 instead and let "git log" going in such a case, instead
+   of aborting.
+
+ * One among four invocations of readlink(1) in our test suite has
+   been rewritten so that the test can run on systems without the
+   command (others are in valgrind test framework and t9802).
+
+ * t/perf needs /usr/bin/time with GNU extension; the invocation of it
+   is updated to "gtime" on Darwin.
+
+ * A bug, which caused "git p4" while running under verbose mode to
+   report paths that are omitted due to branch prefix incorrectly, has
+   been fixed; the command said "Ignoring file outside of prefix" for
+   paths that are _inside_.
+
+ * The top level documentation "git help git" still pointed at the
+   documentation set hosted at now-defunct google-code repository.
+   Update it to point to https://git.github.io/htmldocs/git.html
+   instead.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.9.2.txt b/Documentation/RelNotes/2.9.2.txt
new file mode 100644
index 0000000000..2620003dcf
--- /dev/null
+++ b/Documentation/RelNotes/2.9.2.txt
@@ -0,0 +1,13 @@
+Git v2.9.2 Release Notes
+========================
+
+Fixes since v2.9.1
+------------------
+
+ * A fix merged to v2.9.1 had a few tests that are not meant to be
+   run on platforms without 64-bit long, which caused unnecessary
+   test failures on them because we didn't detect the platform and
+   skip them.  These tests are now skipped on platforms that they
+   are not applicable to.
+
+No other change is included in this update.
diff --git a/Documentation/RelNotes/2.9.3.txt b/Documentation/RelNotes/2.9.3.txt
new file mode 100644
index 0000000000..305e08062b
--- /dev/null
+++ b/Documentation/RelNotes/2.9.3.txt
@@ -0,0 +1,170 @@
+Git v2.9.3 Release Notes
+========================
+
+Fixes since v2.9.2
+------------------
+
+ * A helper function that takes the contents of a commit object and
+   finds its subject line did not ignore leading blank lines, as is
+   commonly done by other codepaths.  Make it ignore leading blank
+   lines to match.
+
+ * Git does not know what the contents in the index should be for a
+   path added with "git add -N" yet, so "git grep --cached" should not
+   show hits (or show lack of hits, with -L) in such a path, but that
+   logic does not apply to "git grep", i.e. searching in the working
+   tree files.  But we did so by mistake, which has been corrected.
+
+ * "git rebase -i --autostash" did not restore the auto-stashed change
+   when the operation was aborted.
+
+ * "git commit --amend --allow-empty-message -S" for a commit without
+   any message body could have misidentified where the header of the
+   commit object ends.
+
+ * More mark-up updates to typeset strings that are expected to
+   literally typed by the end user in fixed-width font.
+
+ * For a long time, we carried an in-code comment that said our
+   colored output would work only when we use fprintf/fputs on
+   Windows, which no longer is the case for the past few years.
+
+ * "gc.autoPackLimit" when set to 1 should not trigger a repacking
+   when there is only one pack, but the code counted poorly and did
+   so.
+
+ * One part of "git am" had an oddball helper function that called
+   stuff from outside "his" as opposed to calling what we have "ours",
+   which was not gender-neutral and also inconsistent with the rest of
+   the system where outside stuff is usually called "theirs" in
+   contrast to "ours".
+
+ * The test framework learned a new helper test_match_signal to
+   check an exit code from getting killed by an expected signal.
+
+ * "git blame -M" missed a single line that was moved within the file.
+
+ * Fix recently introduced codepaths that are involved in parallel
+   submodule operations, which gave up on reading too early, and
+   could have wasted CPU while attempting to write under a corner
+   case condition.
+
+ * "git grep -i" has been taught to fold case in non-ascii locales
+   correctly.
+
+ * A test that unconditionally used "mktemp" learned that the command
+   is not necessarily available everywhere.
+
+ * "git blame file" allowed the lineage of lines in the uncommitted,
+   unadded contents of "file" to be inspected, but it refused when
+   "file" did not appear in the current commit.  When "file" was
+   created by renaming an existing file (but the change has not been
+   committed), this restriction was unnecessarily tight.
+
+ * "git add -N dir/file && git write-tree" produced an incorrect tree
+   when there are other paths in the same directory that sorts after
+   "file".
+
+ * "git fetch http://user:pass@host/repo..."; scrubbed the userinfo
+   part, but "git push" didn't.
+
+ * An age old bug that caused "git diff --ignore-space-at-eol"
+   misbehave has been fixed.
+
+ * "git notes merge" had a code to see if a path exists (and fails if
+   it does) and then open the path for writing (when it doesn't).
+   Replace it with open with O_EXCL.
+
+ * "git pack-objects" and "git index-pack" mostly operate with off_t
+   when talking about the offset of objects in a packfile, but there
+   were a handful of places that used "unsigned long" to hold that
+   value, leading to an unintended truncation.
+
+ * Recent update to "git daemon" tries to enable the socket-level
+   KEEPALIVE, but when it is spawned via inetd, the standard input
+   file descriptor may not necessarily be connected to a socket.
+   Suppress an ENOTSOCK error from setsockopt().
+
+ * Recent FreeBSD stopped making perl available at /usr/bin/perl;
+   switch the default the built-in path to /usr/local/bin/perl on not
+   too ancient FreeBSD releases.
+
+ * "git status" learned to suggest "merge --abort" during a conflicted
+   merge, just like it already suggests "rebase --abort" during a
+   conflicted rebase.
+
+ * The .c/.h sources are marked as such in our .gitattributes file so
+   that "git diff -W" and friends would work better.
+
+ * Existing autoconf generated test for the need to link with pthread
+   library did not check all the functions from pthread libraries;
+   recent FreeBSD has some functions in libc but not others, and we
+   mistakenly thought linking with libc is enough when it is not.
+
+ * Allow http daemon tests in Travis CI tests.
+
+ * Users of the parse_options_concat() API function need to allocate
+   extra slots in advance and fill them with OPT_END() when they want
+   to decide the set of supported options dynamically, which makes the
+   code error-prone and hard to read.  This has been corrected by tweaking
+   the API to allocate and return a new copy of "struct option" array.
+
+ * The use of strbuf in "git rm" to build filename to remove was a bit
+   suboptimal, which has been fixed.
+
+ * "git commit --help" said "--no-verify" is only about skipping the
+   pre-commit hook, and failed to say that it also skipped the
+   commit-msg hook.
+
+ * "git merge" in Git v2.9 was taught to forbid merging an unrelated
+   lines of history by default, but that is exactly the kind of thing
+   the "--rejoin" mode of "git subtree" (in contrib/) wants to do.
+   "git subtree" has been taught to use the "--allow-unrelated-histories"
+   option to override the default.
+
+ * The build procedure for "git persistent-https" helper (in contrib/)
+   has been updated so that it can be built with more recent versions
+   of Go.
+
+ * There is an optimization used in "git diff $treeA $treeB" to borrow
+   an already checked-out copy in the working tree when it is known to
+   be the same as the blob being compared, expecting that open/mmap of
+   such a file is faster than reading it from the object store, which
+   involves inflating and applying delta.  This however kicked in even
+   when the checked-out copy needs to go through the convert-to-git
+   conversion (including the clean filter), which defeats the whole
+   point of the optimization.  The optimization has been disabled when
+   the conversion is necessary.
+
+ * "git -c grep.patternType=extended log --basic-regexp" misbehaved
+   because the internal API to access the grep machinery was not
+   designed well.
+
+ * Windows port was failing some tests in t4130, due to the lack of
+   inum in the returned values by its lstat(2) emulation.
+
+ * The characters in the label shown for tags/refs for commits in
+   "gitweb" output are now properly escaped for proper HTML output.
+
+ * FreeBSD can lie when asked mtime of a directory, which made the
+   untracked cache code to fall back to a slow-path, which in turn
+   caused tests in t7063 to fail because it wanted to verify the
+   behaviour of the fast-path.
+
+ * Squelch compiler warnings for netmalloc (in compat/) library.
+
+ * The API documentation for hashmap was unclear if hashmap_entry
+   can be safely discarded without any other consideration.  State
+   that it is safe to do so.
+
+ * Not-so-recent rewrite of "git am" that started making internal
+   calls into the commit machinery had an unintended regression, in
+   that no matter how many seconds it took to apply many patches, the
+   resulting committer timestamp for the resulting commits were all
+   the same.
+
+ * "git difftool <paths>..." started in a subdirectory failed to
+   interpret the paths relative to that directory, which has been
+   fixed.
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.9.4.txt b/Documentation/RelNotes/2.9.4.txt
new file mode 100644
index 0000000000..9768293831
--- /dev/null
+++ b/Documentation/RelNotes/2.9.4.txt
@@ -0,0 +1,90 @@
+Git v2.9.4 Release Notes
+========================
+
+Fixes since v2.9.3
+------------------
+
+ * There are certain house-keeping tasks that need to be performed at
+   the very beginning of any Git program, and programs that are not
+   built-in commands had to do them exactly the same way as "git"
+   potty does.  It was easy to make mistakes in one-off standalone
+   programs (like test helpers).  A common "main()" function that
+   calls cmd_main() of individual program has been introduced to
+   make it harder to make mistakes.
+
+ * "git merge" with renormalization did not work well with
+   merge-recursive, due to "safer crlf" conversion kicking in when it
+   shouldn't.
+
+ * The reflog output format is documented better, and a new format
+   --date=unix to report the seconds-since-epoch (without timezone)
+   has been added.
+
+ * "git push --force-with-lease" already had enough logic to allow
+   ensuring that such a push results in creation of a ref (i.e. the
+   receiving end did not have another push from sideways that would be
+   discarded by our force-pushing), but didn't expose this possibility
+   to the users.  It does so now.
+
+ * "import-tars" fast-import script (in contrib/) used to ignore a
+   hardlink target and replaced it with an empty file, which has been
+   corrected to record the same blob as the other file the hardlink is
+   shared with.
+
+ * "git mv dir non-existing-dir/" did not work in some environments
+   the same way as existing mainstream platforms.  The code now moves
+   "dir" to "non-existing-dir", without relying on rename("A", "B/")
+   that strips the trailing slash of '/'.
+
+ * The "t/" hierarchy is prone to get an unusual pathname; "make test"
+   has been taught to make sure they do not contain paths that cannot
+   be checked out on Windows (and the mechanism can be reusable to
+   catch pathnames that are not portable to other platforms as need
+   arises).
+
+ * When "git merge-recursive" works on history with many criss-cross
+   merges in "verbose" mode, the names the command assigns to the
+   virtual merge bases could have overwritten each other by unintended
+   reuse of the same piece of memory.
+
+ * "git checkout --detach <branch>" used to give the same advice
+   message as that is issued when "git checkout <tag>" (or anything
+   that is not a branch name) is given, but asking with "--detach" is
+   an explicit enough sign that the user knows what is going on.  The
+   advice message has been squelched in this case.
+
+ * "git difftool" by default ignores the error exit from the backend
+   commands it spawns, because often they signal that they found
+   differences by exiting with a non-zero status code just like "diff"
+   does; the exit status codes 126 and above however are special in
+   that they are used to signal that the command is not executable,
+   does not exist, or killed by a signal.  "git difftool" has been
+   taught to notice these exit status codes.
+
+ * On Windows, help.browser configuration variable used to be ignored,
+   which has been corrected.
+
+ * The "git -c var[=val] cmd" facility to append a configuration
+   variable definition at the end of the search order was described in
+   git(1) manual page, but not in git-config(1), which was more likely
+   place for people to look for when they ask "can I make a one-shot
+   override, and if so how?"
+
+ * The tempfile (hence its user lockfile) API lets the caller to open
+   a file descriptor to a temporary file, write into it and then
+   finalize it by first closing the filehandle and then either
+   removing or renaming the temporary file.  When the process spawns a
+   subprocess after obtaining the file descriptor, and if the
+   subprocess has not exited when the attempt to remove or rename is
+   made, the last step fails on Windows, because the subprocess has
+   the file descriptor still open.  Open tempfile with O_CLOEXEC flag
+   to avoid this (on Windows, this is mapped to O_NOINHERIT).
+
+ * "git-shell" rejects a request to serve a repository whose name
+   begins with a dash, which makes it no longer possible to get it
+   confused into spawning service programs like "git-upload-pack" with
+   an option like "--help", which in turn would spawn an interactive
+   pager, instead of working with the repository user asked to access
+   (i.e. the one whose name is "--help").
+
+Also contains minor documentation updates and code clean-ups.
diff --git a/Documentation/RelNotes/2.9.5.txt b/Documentation/RelNotes/2.9.5.txt
new file mode 100644
index 0000000000..668313ae55
--- /dev/null
+++ b/Documentation/RelNotes/2.9.5.txt
@@ -0,0 +1,4 @@
+Git v2.9.5 Release Notes
+========================
+
+This release forward-ports the fix for "ssh://..." URL from Git v2.7.6
diff --git a/Documentation/ReviewingGuidelines.adoc b/Documentation/ReviewingGuidelines.adoc
new file mode 100644
index 0000000000..6534643cff
--- /dev/null
+++ b/Documentation/ReviewingGuidelines.adoc
@@ -0,0 +1,179 @@
+Reviewing Patches in the Git Project
+====================================
+
+Introduction
+------------
+The Git development community is a widely distributed, diverse, ever-changing
+group of individuals. Asynchronous communication via the Git mailing list poses
+unique challenges when reviewing or discussing patches. This document contains
+some guiding principles and helpful tools you can use to make your reviews both
+more efficient for yourself and more effective for other contributors.
+
+Note that none of the recommendations here are binding or in any way a
+requirement of participation in the Git community. They are provided as a
+resource to supplement your skills as a contributor.
+
+Principles
+----------
+
+Selecting patch(es) to review
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you are looking for a patch series in need of review, start by checking
+the latest "What's cooking in git.git" email
+(https://lore.kernel.org/git/xmqqilm1yp3m.fsf@gitster.g/[example]). The "What's
+cooking" emails & replies can be found using the query `s:"What's cooking"` on
+the https://lore.kernel.org/git/[`lore.kernel.org` mailing list archive];
+alternatively, you can find the contents of the "What's cooking" email tracked
+in `whats-cooking.txt` on the `todo` branch of Git. Topics tagged with "Needs
+review" and those in the "[New Topics]" section are typically those that would
+benefit the most from additional review.
+
+Patches can also be searched manually in the mailing list archive using a query
+like `s:"PATCH" -s:"Re:"`. You can browse these results for topics relevant to
+your expertise or interest.
+
+If you've already contributed to Git, you may also be CC'd in another
+contributor's patch series. These are topics where the author feels that your
+attention is warranted. This may be because their patch changes something you
+wrote previously (making you a good judge of whether the new approach does or
+doesn't work), or because you have the expertise to provide an exceptionally
+helpful review. There is no requirement to review these patches but, in the
+spirit of open source collaboration, you should strongly consider doing so.
+
+Reviewing patches
+~~~~~~~~~~~~~~~~~
+While every contributor takes their own approach to reviewing patches, here are
+some general pieces of advice to make your reviews as clear and helpful as
+possible. The advice is broken into two rough categories: high-level reviewing
+guidance, and concrete tips for interacting with patches on the mailing list.
+
+==== High-level guidance
+- Remember to review the content of commit messages for correctness and clarity,
+  in addition to the code change in the patch's diff. The commit message of a
+  patch should accurately and fully explain the code change being made in the
+  diff.
+
+- Reviewing test coverage is an important - but easy to overlook - component of
+  reviews. A patch's changes may be covered by existing tests, or new tests may
+  be introduced to exercise new behavior. Checking out a patch or series locally
+  allows you to manually mutate lines of new & existing tests to verify expected
+  pass/fail behavior. You can use this information to verify proper coverage or
+  to suggest additional tests the author could add.
+
+- When providing a recommendation, be as clear as possible about whether you
+  consider it "blocking" (the code would be broken or otherwise made worse if an
+  issue isn't fixed) or "non-blocking" (the patch could be made better by taking
+  the recommendation, but acceptance of the series does not require it).
+  Non-blocking recommendations can be particularly ambiguous when they are
+  related to - but outside the scope of - a series ("nice-to-have"s), or when
+  they represent only stylistic differences between the author and reviewer.
+
+- When commenting on an issue, try to include suggestions for how the author
+  could fix it. This not only helps the author to understand and fix the issue,
+  it also deepens and improves your understanding of the topic.
+
+- Reviews do not need to exclusively point out problems.  Positive
+  reviews indicate that it is not only the original author of the
+  patches who care about the issue the patches address, and are
+  highly encouraged.
+
+- Do not hesitate to give positive reviews on a series from your
+  work colleague.  If your positive review is written well, it will
+  not make you look as if you two are representing corporate
+  interest on a series that is otherwise uninteresting to other
+  community members and shoving it down their throat.
+
+- Write a positive review in such a way that others can understand
+  why you support the goal, the approach, and the implementation the
+  patches took.  Make sure to demonstrate that you did thoroughly read
+  the series and understood problem area well enough to be able to
+  say that the patches are written well.  Feel free to "think out
+  loud" in your review: describe how you read & understood a complex section of
+  a patch, ask a question about something that confused you, point out something
+  you found exceptionally well-written, etc.
+
+- In particular, uplifting feedback goes a long way towards
+  encouraging contributors to participate more actively in the Git
+  community.
+
+==== Performing your review
+- Provide your review comments per-patch in a plaintext "Reply-All" email to the
+  relevant patch. Comments should be made inline, immediately below the relevant
+  section(s).
+
+- You may find that the limited context provided in the patch diff is sometimes
+  insufficient for a thorough review. In such cases, you can review patches in
+  your local tree by either applying patches with linkgit:git-am[1] or checking
+  out the associated branch from https://github.com/gitster/git once the series
+  is tracked there.
+
+- Large, complicated patch diffs are sometimes unavoidable, such as when they
+  refactor existing code. If you find such a patch difficult to parse, try
+  reviewing the diff produced with the `--color-moved` and/or
+  `--ignore-space-change` options.
+
+- If a patch is long, you are encouraged to delete parts of it that are
+  unrelated to your review from the email reply. Make sure to leave enough
+  context for readers to understand your comments!
+
+- If you cannot complete a full review of a series all at once, consider letting
+  the author know (on- or off-list) if/when you plan to review the rest of the
+  series.
+
+Completing a review
+~~~~~~~~~~~~~~~~~~~
+Once each patch of a series is reviewed, the author (and/or other contributors)
+may discuss the review(s). This may result in no changes being applied, or the
+author will send a new version of their patch(es).
+
+After a series is rerolled in response to your or others' review, make sure to
+re-review the updates. If you are happy with the state of the patch series,
+explicitly indicate your approval (typically with a reply to the latest
+version's cover letter). Optionally, you can let the author know that they can
+add a "Reviewed-by: <you>" trailer if they resubmit the reviewed patch verbatim
+in a later iteration of the series.
+
+Finally, subsequent "What's cooking" emails may explicitly ask whether a
+reviewed topic is ready for merging to the `next` branch (typically phrased
+"Will merge to \'next\'?"). You can help the maintainer and author by responding
+with a short description of the state of your (and others', if applicable)
+review, including the links to the relevant thread(s).
+
+Terminology
+-----------
+nit: ::
+	Denotes a small issue that should be fixed, such as a typographical error
+	or misalignment of conditions in an `if()` statement.
+
+aside: ::
+optional: ::
+non-blocking: ::
+	Indicates to the reader that the following comment should not block the
+	acceptance of the patch or series. These are typically recommendations
+	related to code organization & style, or musings about topics related to
+	the patch in question, but beyond its scope.
+
+s/<before>/<after>/::
+	Shorthand for "you wrote <before>, but I think you meant <after>," usually
+	for misspellings or other typographical errors. The syntax is a reference
+	to "substitute" command commonly found in Unix tools such as `ed`, `sed`,
+	`vim`, and `perl`.
+
+cover letter::
+	The "Patch 0" of a multi-patch series. This email describes the
+	high-level intent and structure of the patch series to readers on the
+	Git mailing list. It is also where the changelog notes and range-diff of
+	subsequent versions are provided by the author.
++
+On single-patch submissions, cover letter content is typically not sent as a
+separate email. Instead, it is inserted between the end of the patch's commit
+message (after the `---`) and the beginning of the diff.
+
+#leftoverbits::
+  Used by either an author or a reviewer to describe features or suggested
+  changes that are out-of-scope of a given patch or series, but are relevant
+  to the topic for the sake of discussion.
+
+See Also
+--------
+link:MyFirstContribution.html[MyFirstContribution]
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
new file mode 100644
index 0000000000..958e3cc3d5
--- /dev/null
+++ b/Documentation/SubmittingPatches
@@ -0,0 +1,838 @@
+Submitting Patches
+==================
+
+== Guidelines
+
+Here are some guidelines for contributing back to this
+project. There is also a link:MyFirstContribution.html[step-by-step tutorial]
+available which covers many of these same guidelines.
+
+[[patch-flow]]
+=== A typical life cycle of a patch series
+
+To help us understand the reason behind various guidelines given later
+in the document, first let's understand how the life cycle of a
+typical patch series for this project goes.
+
+. You come up with an itch.  You code it up.  You do not need any
+  pre-authorization from the project to do so.
++
+Your patches will be reviewed by other contributors on the mailing
+list, and the reviews will be done to assess the merit of various
+things, like the general idea behind your patch (including "is it
+solving a problem worth solving in the first place?"), the reason
+behind the design of the solution, and the actual implementation.
+The guidelines given here are there to help your patches by making
+them easier to understand by the reviewers.
+
+. You send the patches to the list and cc people who may need to know
+  about the change.  Your goal is *not* necessarily to convince others
+  that what you are building is good.  Your goal is to get help in
+  coming up with a solution for the "itch" that is better than what
+  you can build alone.
++
+The people who may need to know are the ones who worked on the code
+you are touching.  These people happen to be the ones who are
+most likely to be knowledgeable enough to help you, but
+they have no obligation to help you (i.e. you ask them for help,
+you don't demand).  +git log -p {litdd} _$area_you_are_modifying_+ would
+help you find out who they are.
+
+. You get comments and suggestions for improvements.  You may even get
+  them in an "on top of your change" patch form.  You are expected to
+  respond to them with "Reply-All" on the mailing list, while taking
+  them into account while preparing an updated set of patches.
+
+. Polish, refine, and re-send your patches to the list and to the people
+  who spent their time to improve your patch.  Go back to step (2).
+
+. While the above iterations improve your patches, the maintainer may
+  pick the patches up from the list and queue them to the `seen`
+  branch, in order to make it easier for people to play with it
+  without having to pick up and apply the patches to their trees
+  themselves.  Being in `seen` has no other meaning.  Specifically, it
+  does not mean the patch was "accepted" in any way.
+
+. When the discussion reaches a consensus that the latest iteration of
+  the patches are in good enough shape, the maintainer includes the
+  topic in the "What's cooking" report that are sent out a few times a
+  week to the mailing list, marked as "Will merge to 'next'."  This
+  decision is primarily made by the maintainer with help from those
+  who participated in the review discussion.
+
+. After the patches are merged to the 'next' branch, the discussion
+  can still continue to further improve them by adding more patches on
+  top, but by the time a topic gets merged to 'next', it is expected
+  that everybody agrees that the scope and the basic direction of the
+  topic are appropriate, so such an incremental updates are limited to
+  small corrections and polishing.  After a topic cooks for some time
+  (like 7 calendar days) in 'next' without needing further tweaks on
+  top, it gets merged to the 'master' branch and wait to become part
+  of the next major release.
+
+In the following sections, many techniques and conventions are listed
+to help your patches get reviewed effectively in such a life cycle.
+
+
+[[choose-starting-point]]
+=== Choose a starting point.
+
+As a preliminary step, you must first choose a starting point for your
+work. Typically this means choosing a branch, although technically
+speaking it is actually a particular commit (typically the HEAD, or tip,
+of the branch).
+
+There are several important branches to be aware of. Namely, there are
+four integration branches as discussed in linkgit:gitworkflows[7]:
+
+* maint
+* master
+* next
+* seen
+
+The branches lower on the list are typically descendants of the ones
+that come before it. For example, `maint` is an "older" branch than
+`master` because `master` usually has patches (commits) on top of
+`maint`.
+
+There are also "topic" branches, which contain work from other
+contributors.  Topic branches are created by the Git maintainer (in
+their fork) to organize the current set of incoming contributions on
+the mailing list, and are itemized in the regular "What's cooking in
+git.git" announcements.  To find the tip of a topic branch, run `git log
+--first-parent master..seen` and look for the merge commit. The second
+parent of this commit is the tip of the topic branch.
+
+There is one guiding principle for choosing the right starting point: in
+general, always base your work on the oldest integration branch that
+your change is relevant to (see "Merge upwards" in
+linkgit:gitworkflows[7]).  What this principle means is that for the
+vast majority of cases, the starting point for new work should be the
+latest HEAD commit of `maint` or `master` based on the following cases:
+
+* If you are fixing bugs in the released version, use `maint` as the
+  starting point (which may mean you have to fix things without using
+  new API features on the cutting edge that recently appeared in
+  `master` but were not available in the released version).
+
+* Otherwise (such as if you are adding new features) use `master`.
+
+
+NOTE: In exceptional cases, a bug that was introduced in an old
+version may have to be fixed for users of releases that are much older
+than the recent releases.  `git describe --contains X` may describe
+`X` as `v2.30.0-rc2-gXXXXXX` for the commit `X` that introduced the
+bug, and the bug may be so high-impact that we may need to issue a new
+maintenance release for Git 2.30.x series, when "Git 2.41.0" is the
+current release.  In such a case, you may want to use the tip of the
+maintenance branch for the 2.30.x series, which may be available in the
+`maint-2.30` branch in https://github.com/gitster/git[the maintainer's
+"broken out" repo].
+
+This also means that `next` or `seen` are inappropriate starting points
+for your work, if you want your work to have a realistic chance of
+graduating to `master`.  They are simply not designed to be used as a
+base for new work; they are only there to make sure that topics in
+flight work well together. This is why both `next` and `seen` are
+frequently re-integrated with incoming patches on the mailing list and
+force-pushed to replace previous versions of themselves. A topic that is
+literally built on top of `next` cannot be merged to `master` without
+dragging in all the other topics in `next`, some of which may not be
+ready.
+
+For example, if you are making tree-wide changes, while somebody else is
+also making their own tree-wide changes, your work may have severe
+overlap with the other person's work.  This situation may tempt you to
+use `next` as your starting point (because it would have the other
+person's work included in it), but doing so would mean you'll not only
+depend on the other person's work, but all the other random things from
+other contributors that are already integrated into `next`.  And as soon
+as `next` is updated with a new version, all of your work will need to
+be rebased anyway in order for them to be cleanly applied by the
+maintainer.
+
+Under truly exceptional circumstances where you absolutely must depend
+on a select few topic branches that are already in `next` but not in
+`master`, you may want to create your own custom base-branch by forking
+`master` and merging the required topic branches into it. You could then
+work on top of this base-branch.  But keep in mind that this base-branch
+would only be known privately to you.  So when you are ready to send
+your patches to the list, be sure to communicate how you created it in
+your cover letter.  This critical piece of information would allow
+others to recreate your base-branch on their end in order for them to
+try out your work.
+
+Finally, note that some parts of the system have dedicated maintainers
+with their own separate source code repositories (see the section
+"Subsystems" below).
+
+[[separate-commits]]
+=== Make separate commits for logically separate changes.
+
+Unless your patch is really trivial, you should not be sending
+out a patch that was generated between your working tree and
+your commit head.  Instead, always make a commit with complete
+commit message and generate a series of patches from your
+repository.  It is a good discipline.
+
+Give an explanation for the change(s) that is detailed enough so
+that people can judge if it is good thing to do, without reading
+the actual patch text to determine how well the code does what
+the explanation promises to do.
+
+If your description starts to get too long, that's a sign that you
+probably need to split up your commit to finer grained pieces.
+That being said, patches which plainly describe the things that
+help reviewers check the patch, and future maintainers understand
+the code, are the most beautiful patches.  Descriptions that summarize
+the point in the subject well, and describe the motivation for the
+change, the approach taken by the change, and if relevant how this
+differs substantially from the prior version, are all good things
+to have.
+
+Make sure that you have tests for the bug you are fixing.  See
+`t/README` for guidance.
+
+[[tests]]
+When adding a new feature, make sure that you have new tests to show
+the feature triggers the new behavior when it should, and to show the
+feature does not trigger when it shouldn't.  After any code change,
+make sure that the entire test suite passes.  When fixing a bug, make
+sure you have new tests that break if somebody else breaks what you
+fixed by accident to avoid regression.  Also, try merging your work to
+'next' and 'seen' and make sure the tests still pass; topics by others
+that are still in flight may have unexpected interactions with what
+you are trying to do in your topic.
+
+Pushing to a fork of https://github.com/git/git will use their CI
+integration to test your changes on Linux, Mac and Windows. See the
+<<GHCI,GitHub CI>> section for details.
+
+Do not forget to update the documentation to describe the updated
+behavior and make sure that the resulting documentation set formats
+well (try the Documentation/doc-diff script).
+
+We currently have a liberal mixture of US and UK English norms for
+spelling and grammar, which is somewhat unfortunate.  A huge patch that
+touches the files all over the place only to correct the inconsistency
+is not welcome, though.  Potential clashes with other changes that can
+result from such a patch are not worth it.  We prefer to gradually
+reconcile the inconsistencies in favor of US English, with small and
+easily digestible patches, as a side effect of doing some other real
+work in the vicinity (e.g. rewriting a paragraph for clarity, while
+turning en_UK spelling to en_US).  Obvious typographical fixes are much
+more welcomed ("teh -> "the"), preferably submitted as independent
+patches separate from other documentation changes.
+
+[[whitespace-check]]
+Oh, another thing.  We are picky about whitespaces.  Make sure your
+changes do not trigger errors with the sample pre-commit hook shipped
+in `templates/hooks--pre-commit`.  To help ensure this does not happen,
+run `git diff --check` on your changes before you commit.
+
+[[describe-changes]]
+=== Describe your changes well.
+
+The log message that explains your changes is just as important as the
+changes themselves.  Your code may be clearly written with in-code
+comment to sufficiently explain how it works with the surrounding
+code, but those who need to fix or enhance your code in the future
+will need to know _why_ your code does what it does, for a few
+reasons:
+
+. Your code may be doing something differently from what you wanted it
+  to do.  Writing down what you actually wanted to achieve will help
+  them fix your code and make it do what it should have been doing
+  (also, you often discover your own bugs yourself, while writing the
+  log message to summarize the thought behind it).
+
+. Your code may be doing things that were only necessary for your
+  immediate needs (e.g. "do X to directories" without implementing or
+  even designing what is to be done on files).  Writing down why you
+  excluded what the code does not do will help guide future developers.
+  Writing down "we do X to directories, because directories have
+  characteristic Y" would help them infer "oh, files also have the same
+  characteristic Y, so perhaps doing X to them would also make sense?".
+  Saying "we don't do the same X to files, because ..." will help them
+  decide if the reasoning is sound (in which case they do not waste
+  time extending your code to cover files), or reason differently (in
+  which case, they can explain why they extend your code to cover
+  files, too).
+
+The goal of your log message is to convey the _why_ behind your change
+to help future developers.  The reviewers will also make sure that
+your proposed log message will serve this purpose well.
+
+The first line of the commit message should be a short description (50
+characters is the soft limit, see DISCUSSION in linkgit:git-commit[1]),
+and should skip the full stop.  It is also conventional in most cases to
+prefix the first line with "area: " where the area is a filename or
+identifier for the general area of the code being modified, e.g.
+
+* doc: clarify distinction between sign-off and pgp-signing
+* githooks.txt: improve the intro section
+
+If in doubt which identifier to use, run `git log --no-merges` on the
+files you are modifying to see the current conventions.
+
+[[summary-section]]
+The title sentence after the "area:" prefix omits the full stop at the
+end, and its first word is not capitalized (the omission
+of capitalization applies only to the word after the "area:"
+prefix of the title) unless there is a reason to
+capitalize it other than because it is the first word in the sentence.
+E.g. "doc: clarify...", not "doc: Clarify...", or "githooks.txt:
+improve...", not "githooks.txt: Improve...".  But "refs: HEAD is also
+treated as a ref" is correct, as we spell `HEAD` in all caps even when
+it appears in the middle of a sentence.
+
+[[meaningful-message]]
+The body should provide a meaningful commit message, which:
+
+. explains the problem the change tries to solve, i.e. what is wrong
+  with the current code without the change.
+
+. justifies the way the change solves the problem, i.e. why the
+  result with the change is better.
+
+. alternate solutions considered but discarded, if any.
+
+[[present-tense]]
+The problem statement that describes the status quo is written in the
+present tense.  Write "The code does X when it is given input Y",
+instead of "The code used to do Y when given input X".  You do not
+have to say "Currently"---the status quo in the problem statement is
+about the code _without_ your change, by project convention.
+
+[[imperative-mood]]
+Describe your changes in imperative mood, e.g. "make xyzzy do frotz"
+instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy
+to do frotz", as if you are giving orders to the codebase to change
+its behavior.  Try to make sure your explanation can be understood
+without external resources. Instead of giving a URL to a mailing list
+archive, summarize the relevant points of the discussion.
+
+[[commit-reference]]
+
+There are a few reasons why you may want to refer to another commit in
+the "more stable" part of the history (i.e. on branches like `maint`,
+`master`, and `next`):
+
+. A commit that introduced the root cause of a bug you are fixing.
+
+. A commit that introduced a feature that you are enhancing.
+
+. A commit that conflicts with your work when you made a trial merge
+  of your work into `next` and `seen` for testing.
+
+When you reference a commit on a more stable branch (like `master`,
+`maint` and `next`), use the format "abbreviated hash (subject,
+date)", like this:
+
+....
+	Commit f86a374 (pack-bitmap.c: fix a memleak, 2015-03-30)
+	noticed that ...
+....
+
+The "Copy commit reference" command of gitk can be used to obtain this
+format (with the subject enclosed in a pair of double-quotes), or this
+invocation of `git show`:
+
+....
+	git show -s --pretty=reference <commit>
+....
+
+or, on an older version of Git without support for --pretty=reference:
+
+....
+	git show -s --date=short --pretty='format:%h (%s, %ad)' <commit>
+....
+
+[[sign-off]]
+=== Certify your work by adding your `Signed-off-by` trailer
+
+To improve tracking of who did what, we ask you to certify that you
+wrote the patch or have the right to pass it on under the same license
+as ours, by "signing off" your patch.  Without sign-off, we cannot
+accept your patches.
+
+If (and only if) you certify the below D-C-O:
+
+[[dco]]
+.Developer's Certificate of Origin 1.1
+____
+By making a contribution to this project, I certify that:
+
+a. The contribution was created in whole or in part by me and I
+   have the right to submit it under the open source license
+   indicated in the file; or
+
+b. The contribution is based upon previous work that, to the best
+   of my knowledge, is covered under an appropriate open source
+   license and I have the right under that license to submit that
+   work with modifications, whether created in whole or in part
+   by me, under the same open source license (unless I am
+   permitted to submit under a different license), as indicated
+   in the file; or
+
+c. The contribution was provided directly to me by some other
+   person who certified (a), (b) or (c) and I have not modified
+   it.
+
+d. I understand and agree that this project and the contribution
+   are public and that a record of the contribution (including all
+   personal information I submit with it, including my sign-off) is
+   maintained indefinitely and may be redistributed consistent with
+   this project or the open source license(s) involved.
+____
+
+you add a "Signed-off-by" trailer to your commit, that looks like
+this:
+
+....
+	Signed-off-by: Random J Developer <random@xxxxxxxxxxxxxxxxxxxxx>
+....
+
+This line can be added by Git if you run the git-commit command with
+the -s option.
+
+Notice that you can place your own `Signed-off-by` trailer when
+forwarding somebody else's patch with the above rules for
+D-C-O.  Indeed you are encouraged to do so.  Do not forget to
+place an in-body "From: " line at the beginning to properly attribute
+the change to its true author (see (2) above).
+
+This procedure originally came from the Linux kernel project, so our
+rule is quite similar to theirs, but what exactly it means to sign-off
+your patch differs from project to project, so it may be different
+from that of the project you are accustomed to.
+
+[[real-name]]
+Also notice that a real name is used in the `Signed-off-by` trailer. Please
+don't hide your real name.
+
+[[commit-trailers]]
+If you like, you can put extra trailers at the end:
+
+. `Reported-by:` is used to credit someone who found the bug that
+  the patch attempts to fix.
+. `Acked-by:` says that the person who is more familiar with the area
+  the patch attempts to modify liked the patch.
+. `Reviewed-by:`, unlike the other trailers, can only be offered by the
+  reviewers themselves when they are completely satisfied with the
+  patch after a detailed analysis.
+. `Tested-by:` is used to indicate that the person applied the patch
+  and found it to have the desired effect.
+. `Co-authored-by:` is used to indicate that people exchanged drafts
+   of a patch before submitting it.
+. `Helped-by:` is used to credit someone who suggested ideas for
+  changes without providing the precise changes in patch form.
+. `Mentored-by:` is used to credit someone with helping develop a
+  patch as part of a mentorship program (e.g., GSoC or Outreachy).
+. `Suggested-by:` is used to credit someone with suggesting the idea
+  for a patch.
+
+While you can also create your own trailer if the situation warrants it, we
+encourage you to instead use one of the common trailers in this project
+highlighted above.
+
+Only capitalize the very first letter of the trailer, i.e. favor
+"Signed-off-by" over "Signed-Off-By" and "Acked-by:" over "Acked-By".
+
+[[git-tools]]
+=== Generate your patch using Git tools out of your commits.
+
+Git based diff tools generate unidiff which is the preferred format.
+
+You do not have to be afraid to use `-M` option to `git diff` or
+`git format-patch`, if your patch involves file renames.  The
+receiving end can handle them just fine.
+
+[[review-patch]]
+Please make sure your patch does not add commented out debugging code,
+or include any extra files which do not relate to what your patch
+is trying to achieve. Make sure to review
+your patch after generating it, to ensure accuracy.  Before
+sending out, please make sure it cleanly applies to the starting point you
+have chosen in the "Choose a starting point" section.
+
+NOTE: From the perspective of those reviewing your patch, the `master`
+branch is the default expected starting point.  So if you have chosen a
+different starting point, please communicate this choice in your cover
+letter.
+
+
+[[send-patches]]
+=== Sending your patches.
+
+==== Choosing your reviewers
+
+:security-ml: footnoteref:[security-ml,The Git Security mailing list: git-security@xxxxxxxxxxxxxxxx]
+
+NOTE: Patches that may be
+security relevant should be submitted privately to the Git Security
+mailing list{security-ml}, instead of the public mailing list.
+
+:contrib-scripts: footnoteref:[contrib-scripts,Scripts under `contrib/` are +
+not part of the core `git` binary and must be called directly. Clone the Git +
+codebase and run `perl contrib/contacts/git-contacts`.]
+
+Send your patch with "To:" set to the mailing list, with "cc:" listing
+people who are involved in the area you are touching (the `git-contacts`
+script in `contrib/contacts/`{contrib-scripts} can help to
+identify them), to solicit comments and reviews.  Also, when you made
+trial merges of your topic to `next` and `seen`, you may have noticed
+work by others conflicting with your changes.  There is a good possibility
+that these people may know the area you are touching well.
+
+If you are using `send-email`, you can feed it the output of `git-contacts` like
+this:
+
+....
+	git send-email --cc-cmd='perl contrib/contacts/git-contacts' feature/*.patch
+....
+
+:current-maintainer: footnote:[The current maintainer: gitster@xxxxxxxxx]
+:git-ml: footnote:[The mailing list: git@xxxxxxxxxxxxxxx]
+
+After the list reached a consensus that it is a good idea to apply the
+patch, re-send it with "To:" set to the maintainer{current-maintainer}
+and "cc:" the list{git-ml} for inclusion.  This is especially relevant
+when the maintainer did not heavily participate in the discussion and
+instead left the review to trusted others.
+
+Do not forget to add trailers such as `Acked-by:`, `Reviewed-by:` and
+`Tested-by:` lines as necessary to credit people who helped your
+patch, and "cc:" them when sending such a final version for inclusion.
+
+==== `format-patch` and `send-email`
+
+Learn to use `format-patch` and `send-email` if possible.  These commands
+are optimized for the workflow of sending patches, avoiding many ways
+your existing e-mail client (often optimized for "multipart/*" MIME
+type e-mails) might render your patches unusable.
+
+NOTE: Here we outline the procedure using `format-patch` and
+`send-email`, but you can instead use GitGitGadget to send in your
+patches (see link:MyFirstContribution.html[MyFirstContribution]).
+
+People on the Git mailing list need to be able to read and
+comment on the changes you are submitting.  It is important for
+a developer to be able to "quote" your changes, using standard
+e-mail tools, so that they may comment on specific portions of
+your code.  For this reason, each patch should be submitted
+"inline" in a separate message.
+
+All subsequent versions of a patch series and other related patches should be
+grouped into their own e-mail thread to help readers find all parts of the
+series.  To that end, send them as replies to either an additional "cover
+letter" message (see below), the first patch, or the respective preceding patch.
+Here is a link:MyFirstContribution.html#v2-git-send-email[step-by-step guide] on
+how to submit updated versions of a patch series.
+
+If your log message (including your name on the
+`Signed-off-by` trailer) is not writable in ASCII, make sure that
+you send off a message in the correct encoding.
+
+WARNING: Be wary of your MUAs word-wrap
+corrupting your patch.  Do not cut-n-paste your patch; you can
+lose tabs that way if you are not careful.
+
+It is a common convention to prefix your subject line with
+[PATCH].  This lets people easily distinguish patches from other
+e-mail discussions.  Use of markers in addition to PATCH within
+the brackets to describe the nature of the patch is also
+encouraged.  E.g. [RFC PATCH] (where RFC stands for "request for
+comments") is often used to indicate a patch needs further
+discussion before being accepted, [PATCH v2], [PATCH v3] etc.
+are often seen when you are sending an update to what you have
+previously sent.
+
+The `git format-patch` command follows the best current practice to
+format the body of an e-mail message.  At the beginning of the
+patch should come your commit message, ending with the
+`Signed-off-by` trailers, and a line that consists of three dashes,
+followed by the diffstat information and the patch itself.  If
+you are forwarding a patch from somebody else, optionally, at
+the beginning of the e-mail message just before the commit
+message starts, you can put a "From: " line to name that person.
+To change the default "[PATCH]" in the subject to "[<text>]", use
+`git format-patch --subject-prefix=<text>`.  As a shortcut, you
+can use `--rfc` instead of `--subject-prefix="RFC PATCH"`, or
+`-v <n>` instead of `--subject-prefix="PATCH v<n>"`.
+
+You often want to add additional explanation about the patch,
+other than the commit message itself.  Place such "cover letter"
+material between the three-dash line and the diffstat.  For
+patches requiring multiple iterations of review and discussion,
+an explanation of changes between each iteration can be kept in
+Git-notes and inserted automatically following the three-dash
+line via `git format-patch --notes`.
+
+[[the-topic-summary]]
+*This is EXPERIMENTAL*.
+
+When sending a topic, you can propose a one-paragraph summary that
+should appear in the "What's cooking" report when it is picked up to
+explain the topic.  If you choose to do so, please write a 2-5 line
+paragraph that will fit well in our release notes (see many bulleted
+entries in the Documentation/RelNotes/* files for examples), and make
+it the first paragraph of the cover letter.  For a single-patch
+series, use the space between the three-dash line and the diffstat, as
+described earlier.
+
+[[attachment]]
+Do not attach the patch as a MIME attachment, compressed or not.
+Do not let your e-mail client send quoted-printable.  Do not let
+your e-mail client send format=flowed which would destroy
+whitespaces in your patches. Many
+popular e-mail applications will not always transmit a MIME
+attachment as plain text, making it impossible to comment on
+your code.  A MIME attachment also takes a bit more time to
+process.  This does not decrease the likelihood of your
+MIME-attached change being accepted, but it makes it more likely
+that it will be postponed.
+
+Exception:  If your mailer is mangling patches then someone may ask
+you to re-send them using MIME, that is OK.
+
+[[pgp-signature]]
+Do not PGP sign your patch. Most likely, your maintainer or other people on the
+list would not have your PGP key and would not bother obtaining it anyway.
+Your patch is not judged by who you are; a good patch from an unknown origin
+has a far better chance of being accepted than a patch from a known, respected
+origin that is done poorly or does incorrect things.
+
+If you really really really really want to do a PGP signed
+patch, format it as "multipart/signed", not a text/plain message
+that starts with `-----BEGIN PGP SIGNED MESSAGE-----`.  That is
+not a text/plain, it's something else.
+
+=== Handling Conflicts and Iterating Patches
+
+When revising changes made to your patches, it's important to
+acknowledge the possibility of conflicts with other ongoing topics. To
+navigate these potential conflicts effectively, follow the recommended
+steps outlined below:
+
+. Build on a suitable base branch, see the <<choose-starting-point, section above>>,
+and format-patch the series. If you are doing "rebase -i" in-place to
+update from the previous round, this will reuse the previous base so
+(2) and (3) may become trivial.
+
+. Find the base of where the last round was queued
++
+    $ mine='kn/ref-transaction-symref'
+    $ git checkout "origin/seen^{/^Merge branch '$mine'}...master"
+
+. Apply your format-patch result.  There are two cases
+.. Things apply cleanly and tests fine.  Go to (4).
+.. Things apply cleanly but does not build or test fails, or things do
+not apply cleanly.
++
+In the latter case, you have textual or semantic conflicts coming from
+the difference between the old base and the base you used to build in
+(1).  Identify what caused the breakages (e.g., a topic or two may have
+merged since the base used by (2) until the base used by (1)).
++
+Check out the latest 'origin/master' (which may be newer than the base
+used by (2)), "merge --no-ff" the topics you newly depend on in there,
+and use the result of the merge(s) as the base, rebuild the series and
+test again.  Run format-patch from the last such merges to the tip of
+your topic.  If you did
++
+    $ git checkout origin/master
+    $ git merge --no-ff --into-name kn/ref-transaction-symref fo/obar
+    $ git merge --no-ff --into-name kn/ref-transaction-symref ba/zqux
+    ... rebuild the topic ...
++
+Then you'd just format your topic above these "preparing the ground"
+merges, e.g.
++
+    $ git format-patch "HEAD^{/^Merge branch 'ba/zqux'}"..HEAD
++
+Do not forget to write in the cover letter you did this, including the
+topics you have in your base on top of 'master'.  Then go to (4).
+
+. Make a trial merge of your topic into 'next' and 'seen', e.g.
++
+    $ git checkout --detach 'origin/seen'
+    $ git revert -m 1 <the merge of the previous iteration into seen>
+    $ git merge kn/ref-transaction-symref
++
+The "revert" is needed if the previous iteration of your topic is
+already in 'seen' (like in this case).  You could choose to rebuild
+master..origin/seen from scratch while excluding your previous
+iteration, which may emulate what happens on the maintainers end more
+closely.
++
+This trial merge may conflict.  It is primarily to see what conflicts
+_other_ topics may have with your topic.  In other words, you do not
+have to depend on it to make your topic work on 'master'.  It may
+become the job of the other topic owners to resolve conflicts if your
+topic goes to 'next' before theirs.
++
+Make a note on what conflict you saw in the cover letter.  You do not
+necessarily have to resolve them, but it would be a good opportunity to
+learn what others are doing in related areas.
++
+    $ git checkout --detach 'origin/next'
+    $ git merge kn/ref-transaction-symref
++
+This is to see what conflicts your topic has with other topics that are
+already cooking.  This should not conflict if (3)-2 prepared a base on
+top of updated master plus dependent topics taken from 'next'.  Unless
+the context is severe (one way to tell is try the same trial merge with
+your old iteration, which may conflict in a similar way), expect that it
+will be handled on maintainers end (if it gets unmanageable, I'll ask to
+rebase when I receive your patches).
+
+== Subsystems with dedicated maintainers
+
+Some parts of the system have dedicated maintainers with their own
+repositories.
+
+- `git-gui/` comes from the git-gui project, maintained by Johannes Sixt:
+
+        https://github.com/j6t/git-gui
+
+   Contibutions should go via the git mailing list.
+
+- `gitk-git/` comes from the gitk project, maintained by Johannes Sixt:
+
+	https://github.com/j6t/gitk
+
+   Contibutions should go via the git mailing list.
+
+- `po/` comes from the localization coordinator, Jiang Xin:
+
+	https://github.com/git-l10n/git-po/
+
+Patches to these parts should be based on their trees.
+
+- The "Git documentation translations" project, led by Jean-Noël
+  Avila, translates our documentation pages.  Their work products are
+  maintained separately from this project, not as part of our tree:
+
+	https://github.com/jnavila/git-manpages-l10n/
+
+
+== GitHub CI[[GHCI]]
+
+With an account at GitHub, you can use GitHub CI to test your changes
+on Linux, Mac and Windows. See
+https://github.com/git/git/actions/workflows/main.yml for examples of
+recent CI runs.
+
+Follow these steps for the initial setup:
+
+. Fork https://github.com/git/git to your GitHub account.
+  You can find detailed instructions how to fork here:
+  https://help.github.com/articles/fork-a-repo/
+
+After the initial setup, CI will run whenever you push new changes
+to your fork of Git on GitHub.  You can monitor the test state of all your
+branches here: `https://github.com/<Your GitHub handle>/git/actions/workflows/main.yml`
+
+If a branch does not pass all test cases then it will be marked with a
+red +x+, instead of a green check. In that case, you can click on the
+failing job and navigate to "ci/run-build-and-tests.sh" and/or
+"ci/print-test-failures.sh". You can also download "Artifacts" which
+are zip archives containing tarred (or zipped) archives with test data
+relevant for debugging.
+
+Then fix the problem and push your fix to your GitHub fork. This will
+trigger a new CI build to ensure all tests pass.
+
+[[mua]]
+== MUA specific hints
+
+Some of the patches I receive or pick up from the list share common
+patterns of breakage.  Please make sure your MUA is set up
+properly not to corrupt whitespaces.
+
+See the DISCUSSION section of linkgit:git-format-patch[1] for hints on
+checking your patch by mailing it to yourself and applying with
+linkgit:git-am[1].
+
+While you are at it, check the resulting commit log message from
+a trial run of applying the patch.  If what is in the resulting
+commit is not exactly what you would want to see, it is very
+likely that your maintainer would end up hand editing the log
+message when he applies your patch.  Things like "Hi, this is my
+first patch.\n", if you really want to put in the patch e-mail,
+should come after the three-dash line that signals the end of the
+commit message.
+
+
+=== Pine
+
+(Johannes Schindelin)
+
+....
+I don't know how many people still use pine, but for those poor
+souls it may be good to mention that the quell-flowed-text is
+needed for recent versions.
+
+... the "no-strip-whitespace-before-send" option, too. AFAIK it
+was introduced in 4.60.
+....
+
+(Linus Torvalds)
+
+....
+And 4.58 needs at least this.
+
+diff-tree 8326dd8350be64ac7fc805f6563a1d61ad10d32c (from e886a61f76edf5410573e92e38ce22974f9c40f1)
+Author: Linus Torvalds <torvalds@xxxxxxxxxxx>
+Date:   Mon Aug 15 17:23:51 2005 -0700
+
+    Fix pine whitespace-corruption bug
+
+    There's no excuse for unconditionally removing whitespace from
+    the pico buffers on close.
+
+diff --git a/pico/pico.c b/pico/pico.c
+--- a/pico/pico.c
++++ b/pico/pico.c
+@@ -219,7 +219,9 @@ PICO *pm;
+	    switch(pico_all_done){	/* prepare for/handle final events */
+	      case COMP_EXIT :		/* already confirmed */
+		packheader();
++#if 0
+		stripwhitespace();
++#endif
+		c |= COMP_EXIT;
+		break;
+....
+
+(Daniel Barkalow)
+
+....
+> A patch to SubmittingPatches, MUA specific help section for
+> users of Pine 4.63 would be very much appreciated.
+
+Ah, it looks like a recent version changed the default behavior to do the
+right thing, and inverted the sense of the configuration option. (Either
+that or Gentoo did it.) So you need to set the
+"no-strip-whitespace-before-send" option, unless the option you have is
+"strip-whitespace-before-send", in which case you should avoid checking
+it.
+....
+
+=== Thunderbird, KMail, GMail
+
+See the MUA-SPECIFIC HINTS section of linkgit:git-format-patch[1].
+
+=== Gnus
+
+"|" in the `*Summary*` buffer can be used to pipe the current
+message to an external program, and this is a handy way to drive
+`git am`.  However, if the message is MIME encoded, what is
+piped into the program is the representation you see in your
+`*Article*` buffer after unwrapping MIME.  This is often not what
+you would want for two reasons.  It tends to screw up non-ASCII
+characters (most notably in people's names), and also
+whitespaces (fatal in patches).  Running "C-u g" to display the
+message in raw form before using "|" to run the pipe can work
+this problem around.
diff --git a/Documentation/ToolsForGit.adoc b/Documentation/ToolsForGit.adoc
new file mode 100644
index 0000000000..ae7690b45d
--- /dev/null
+++ b/Documentation/ToolsForGit.adoc
@@ -0,0 +1,51 @@
+Tools for developing Git
+========================
+:sectanchors:
+
+[[summary]]
+== Summary
+
+This document gathers tips, scripts, and configuration files to help people
+working on Git's codebase use their favorite tools while following Git's
+coding style.
+
+[[author]]
+=== Author
+
+The Git community.
+
+[[table_of_contents]]
+== Table of contents
+
+- <<vscode>>
+- <<emacs>>
+
+[[vscode]]
+=== Visual Studio Code (VS Code)
+
+The contrib/vscode/init.sh script creates configuration files that enable
+several valuable VS Code features. See contrib/vscode/README.md for more
+information on using the script.
+
+[[emacs]]
+=== Emacs
+
+This is adapted from Linux's suggestion in its CodingStyle document:
+
+- To follow the rules in CodingGuidelines, it's useful to put the following in
+GIT_CHECKOUT/.dir-locals.el, assuming you use cperl-mode:
+----
+;; note the first part is useful for C editing, too
+((nil . ((indent-tabs-mode . t)
+	 (tab-width . 8)
+	 (fill-column . 80)))
+	 (cperl-mode . ((cperl-indent-level . 8)
+			(cperl-extra-newline-before-brace . nil)
+			(cperl-merge-trailing-else . t))))
+----
+
+For a more complete setup, since Git's codebase uses a coding style
+similar to the Linux kernel's style, tips given in Linux's CodingStyle
+document can be applied here too.
+
+==== https://www.kernel.org/doc/html/v4.10/process/coding-style.html#you-ve-made-a-mess-of-it
diff --git a/Documentation/asciidoc.conf.in b/Documentation/asciidoc.conf.in
new file mode 100644
index 0000000000..f2aef6cb79
--- /dev/null
+++ b/Documentation/asciidoc.conf.in
@@ -0,0 +1,92 @@
+## linkgit: macro
+#
+# Usage: linkgit:command[manpage-section]
+#
+# Note, {0} is the manpage section, while {target} is the command.
+#
+# Show Git link as: <command>(<section>); if section is defined, else just show
+# the command.
+
+[macros]
+(?su)[\\]?(?P<name>linkgit):(?P<target>\S*?)\[(?P<attrlist>.*?)\]=
+
+[attributes]
+asterisk=&#42;
+plus=&#43;
+caret=&#94;
+startsb=&#91;
+endsb=&#93;
+backslash=&#92;
+tilde=&#126;
+apostrophe=&#39;
+backtick=&#96;
+litdd=&#45;&#45;
+manmanual=Git Manual
+mansource=Git @GIT_VERSION@
+revdate=@GIT_DATE@
+
+ifdef::doctype-book[]
+[titles]
+	underlines="__","==","--","~~","^^"
+endif::doctype-book[]
+
+ifdef::backend-docbook[]
+[linkgit-inlinemacro]
+ifndef::doctype-book[]
+{0%{target}}
+{0#<citerefentry>}
+{0#<refentrytitle>{target}</refentrytitle><manvolnum>{0}</manvolnum>}
+{0#</citerefentry>}
+endif::doctype-book[]
+ifdef::doctype-book[]
+<ulink url="{target}.html">{target}{0?({0})}</ulink>
+endif::doctype-book[]
+
+[literal-inlinemacro]
+{eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<emphasis>\1</emphasis>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1<literal>\2</literal>', re.sub(r'(\.\.\.?)([^\]$.])', r'<literal>\1</literal>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))}
+
+endif::backend-docbook[]
+
+ifdef::backend-docbook[]
+ifdef::doctype-manpage[]
+# The following two small workarounds insert a simple paragraph after screen
+[listingblock]
+<example><title>{title}</title>
+<literallayout class="monospaced">
+|
+</literallayout><simpara></simpara>
+{title#}</example>
+
+[verseblock]
+<formalpara{id? id="{id}"}><title>{title}</title><para>
+{title%}<literallayout{id? id="{id}"}>
+{title#}<literallayout>
+|
+</literallayout>
+{title#}</para></formalpara>
+{title%}<simpara></simpara>
+endif::doctype-manpage[]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+[attributes]
+git-relative-html-prefix=
+[linkgit-inlinemacro]
+<a href="{git-relative-html-prefix}{target}.html">{target}{0?({0})}</a>
+
+[literal-inlinemacro]
+{eval:re.sub(r'(&lt;[-a-zA-Z0-9.]+&gt;)', r'<em>\1</em>', re.sub(r'([\[\s|()>]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,\/_^\$]+\.?)+)',r'\1<code>\2</code>', re.sub(r'(\.\.\.?)([^\]$.])', r'<code>\1</code>\2', macros.passthroughs[int(attrs['passtext'][1:-1])] if attrs['passtext'][1:-1].isnumeric() else attrs['passtext'][1:-1])))}
+
+endif::backend-xhtml11[]
+
+ifdef::backend-docbook[]
+ifdef::doctype-manpage[]
+[paradef-default]
+synopsis-style=template="verseparagraph",filter="sed 's!&#8230;\\(\\]\\|$\\)!<phrase>\\0</phrase>!g;s!\\([\\[ |()]\\|^\\|\\]\\|&gt;\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|&#8230;\\)!\\1<literal>\\2</literal>!g;s!&lt;[-a-zA-Z0-9.]\\+&gt;!<emphasis>\\0</emphasis>!g'"
+endif::doctype-manpage[]
+endif::backend-docbook[]
+
+ifdef::backend-xhtml11[]
+[paradef-default]
+synopsis-style=template="verseparagraph",filter="sed 's!&#8230;\\(\\]\\|$\\)!<span>\\0</span>!g;s!\\([\\[ |()]\\|^\\|\\]\\|&gt;\\)\\([-=a-zA-Z0-9:+@,\\/_^\\$.]\\+\\|&#8230;\\)!\\1<code>\\2</code>!g;s!&lt;[-a-zA-Z0-9.]\\+&gt;!<em>\\0</em>!g'"
+endif::backend-xhtml11[]
diff --git a/Documentation/asciidoctor-extensions.rb.in b/Documentation/asciidoctor-extensions.rb.in
new file mode 100644
index 0000000000..2494f17a51
--- /dev/null
+++ b/Documentation/asciidoctor-extensions.rb.in
@@ -0,0 +1,134 @@
+require 'asciidoctor'
+require 'asciidoctor/extensions'
+require 'asciidoctor/converter/docbook5'
+require 'asciidoctor/converter/html5'
+
+module Git
+  module Documentation
+    class LinkGitProcessor < Asciidoctor::Extensions::InlineMacroProcessor
+      use_dsl
+
+      named :chrome
+
+      def process(parent, target, attrs)
+        prefix = parent.document.attr('git-relative-html-prefix')
+        if parent.document.doctype == 'book'
+          "<ulink url=\"#{prefix}#{target}.html\">" \
+          "#{target}(#{attrs[1]})</ulink>"
+        elsif parent.document.basebackend? 'html'
+          %(<a href="#{prefix}#{target}.html">#{target}(#{attrs[1]})</a>)
+        elsif parent.document.basebackend? 'docbook'
+          "<citerefentry>\n" \
+            "<refentrytitle>#{target}</refentrytitle>" \
+            "<manvolnum>#{attrs[1]}</manvolnum>\n" \
+          "</citerefentry>"
+        end
+      end
+    end
+
+    class DocumentPostProcessor < Asciidoctor::Extensions::Postprocessor
+      def process document, output
+        if document.basebackend? 'docbook'
+          output = output.sub(/<refmiscinfo class="source">.*?<\/refmiscinfo>/, "")
+          output = output.sub(/<refmiscinfo class="manual">.*?<\/refmiscinfo>/, "")
+          output = output.sub(/<date>.*?<\/date>/, "<date>@GIT_DATE@</date>")
+          new_tags = "" \
+            "<refmiscinfo class=\"source\">Git @GIT_VERSION@</refmiscinfo>\n" \
+            "<refmiscinfo class=\"manual\">Git Manual</refmiscinfo>\n"
+          output = output.sub(/<\/refmeta>/, new_tags + "</refmeta>")
+        end
+        output
+      end
+    end
+
+    class SynopsisBlock < Asciidoctor::Extensions::BlockProcessor
+
+      use_dsl
+      named :synopsis
+      parse_content_as :simple
+
+      def process parent, reader, attrs
+        outlines = reader.lines.map do |l|
+          l.gsub(/(\.\.\.?)([^\]$.])/, '`\1`\2')
+           .gsub(%r{([\[\] |()>]|^)([-a-zA-Z0-9:+=~@,/_^\$]+)}, '\1{empty}`\2`{empty}')
+           .gsub(/(<[-a-zA-Z0-9.]+>)/, '__\\1__')
+           .gsub(']', ']{empty}')
+        end
+        create_block parent, :verse, outlines, attrs
+      end
+    end
+
+    class GitDBConverter < Asciidoctor::Converter::DocBook5Converter
+
+      extend Asciidoctor::Converter::Config
+      register_for 'docbook5'
+
+      def convert_inline_quoted node
+        if (type = node.type) == :asciimath
+          # NOTE fop requires jeuclid to process mathml markup
+          asciimath_available? ? %(<inlineequation>#{(::AsciiMath.parse node.text).to_mathml 'mml:', 'xmlns:mml' => 'http://www.w3.org/1998/Math/MathML'}</inlineequation>) : %(<inlineequation><mathphrase><![CDATA[#{node.text}]]></mathphrase></inlineequation>)
+        elsif type == :latexmath
+          # unhandled math; pass source to alt and required mathphrase element; dblatex will process alt as LaTeX math
+          %(<inlineequation><alt><![CDATA[#{equation = node.text}]]></alt><mathphrase><![CDATA[#{equation}]]></mathphrase></inlineequation>)
+        elsif type == :monospaced
+          node.text.gsub(/(\.\.\.?)([^\]$.])/, '<literal>\1</literal>\2')
+              .gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1<literal>\2</literal>')
+              .gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<emphasis>\1</emphasis>')
+        else
+          open, close, supports_phrase = QUOTE_TAGS[type]
+          text = node.text
+          if node.role
+            if supports_phrase
+              quoted_text = %(#{open}<phrase role="#{node.role}">#{text}</phrase>#{close})
+            else
+              quoted_text = %(#{open.chop} role="#{node.role}">#{text}#{close})
+            end
+          else
+            quoted_text = %(#{open}#{text}#{close})
+          end
+          node.id ? %(<anchor#{common_attributes node.id, nil, text}/>#{quoted_text}) : quoted_text
+        end
+      end
+    end
+
+    # register a html5 converter that takes in charge to convert monospaced text into Git style synopsis
+    class GitHTMLConverter < Asciidoctor::Converter::Html5Converter
+
+      extend Asciidoctor::Converter::Config
+      register_for 'html5'
+
+      def convert_inline_quoted node
+        if node.type == :monospaced
+          node.text.gsub(/(\.\.\.?)([^\]$.])/, '<code>\1</code>\2')
+              .gsub(%r{([\[\s|()>.]|^|\]|&gt;)(\.?([-a-zA-Z0-9:+=~@,/_^\$]+\.{0,2})+)}, '\1<code>\2</code>')
+              .gsub(/(&lt;[-a-zA-Z0-9.]+&gt;)/, '<em>\1</em>')
+
+        else
+          open, close, tag = QUOTE_TAGS[node.type]
+          if node.id
+            class_attr = node.role ? %( class="#{node.role}") : ''
+            if tag
+              %(#{open.chop} id="#{node.id}"#{class_attr}>#{node.text}#{close})
+            else
+              %(<span id="#{node.id}"#{class_attr}>#{open}#{node.text}#{close}</span>)
+            end
+          elsif node.role
+            if tag
+              %(#{open.chop} class="#{node.role}">#{node.text}#{close})
+            else
+              %(<span class="#{node.role}">#{open}#{node.text}#{close}</span>)
+            end
+          else
+            %(#{open}#{node.text}#{close})
+          end
+        end
+      end
+    end
+  end
+end
+
+Asciidoctor::Extensions.register do
+  inline_macro Git::Documentation::LinkGitProcessor, :linkgit
+  block Git::Documentation::SynopsisBlock
+  postprocessor Git::Documentation::DocumentPostProcessor
+end
diff --git a/Documentation/blame-options.adoc b/Documentation/blame-options.adoc
new file mode 100644
index 0000000000..aa77406d4e
--- /dev/null
+++ b/Documentation/blame-options.adoc
@@ -0,0 +1,149 @@
+-b::
+	Show blank SHA-1 for boundary commits.  This can also
+	be controlled via the `blame.blankBoundary` config option.
+
+--root::
+	Do not treat root commits as boundaries.  This can also be
+	controlled via the `blame.showRoot` config option.
+
+--show-stats::
+	Include additional statistics at the end of blame output.
+
+-L <start>,<end>::
+-L :<funcname>::
+	Annotate only the line range given by '<start>,<end>',
+	or by the function name regex '<funcname>'.
+	May be specified multiple times. Overlapping ranges are allowed.
++
+'<start>' and '<end>' are optional. `-L <start>` or `-L <start>,` spans from
+'<start>' to end of file. `-L ,<end>` spans from start of file to '<end>'.
++
+include::line-range-format.adoc[]
+
+-l::
+	Show long rev (Default: off).
+
+-t::
+	Show raw timestamp (Default: off).
+
+-S <revs-file>::
+	Use revisions from revs-file instead of calling linkgit:git-rev-list[1].
+
+--reverse <rev>..<rev>::
+	Walk history forward instead of backward. Instead of showing
+	the revision in which a line appeared, this shows the last
+	revision in which a line has existed. This requires a range of
+	revision like START..END where the path to blame exists in
+	START.  `git blame --reverse START` is taken as `git blame
+	--reverse START..HEAD` for convenience.
+
+--first-parent::
+	Follow only the first parent commit upon seeing a merge
+	commit. This option can be used to determine when a line
+	was introduced to a particular integration branch, rather
+	than when it was introduced to the history overall.
+
+-p::
+--porcelain::
+	Show in a format designed for machine consumption.
+
+--line-porcelain::
+	Show the porcelain format, but output commit information for
+	each line, not just the first time a commit is referenced.
+	Implies --porcelain.
+
+--incremental::
+	Show the result incrementally in a format designed for
+	machine consumption.
+
+--encoding=<encoding>::
+	Specifies the encoding used to output author names
+	and commit summaries. Setting it to `none` makes blame
+	output unconverted data. For more information see the
+	discussion about encoding in the linkgit:git-log[1]
+	manual page.
+
+--contents <file>::
+	Annotate using the contents from the named file, starting from <rev>
+	if it is specified, and HEAD otherwise. You may specify '-' to make
+	the command read from the standard input for the file contents.
+
+--date <format>::
+	Specifies the format used to output dates. If --date is not
+	provided, the value of the blame.date config variable is
+	used. If the blame.date config variable is also not set, the
+	iso format is used. For supported values, see the discussion
+	of the --date option at linkgit:git-log[1].
+
+--[no-]progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal. This flag
+	enables progress reporting even if not attached to a
+	terminal. Can't use `--progress` together with `--porcelain`
+	or `--incremental`.
+
+-M[<num>]::
+	Detect moved or copied lines within a file. When a commit
+	moves or copies a block of lines (e.g. the original file
+	has A and then B, and the commit changes it to B and then
+	A), the traditional 'blame' algorithm notices only half of
+	the movement and typically blames the lines that were moved
+	up (i.e. B) to the parent and assigns blame to the lines that
+	were moved down (i.e. A) to the child commit.  With this
+	option, both groups of lines are blamed on the parent by
+	running extra passes of inspection.
++
+<num> is optional but it is the lower bound on the number of
+alphanumeric characters that Git must detect as moving/copying
+within a file for it to associate those lines with the parent
+commit. The default value is 20.
+
+-C[<num>]::
+	In addition to `-M`, detect lines moved or copied from other
+	files that were modified in the same commit.  This is
+	useful when you reorganize your program and move code
+	around across files.  When this option is given twice,
+	the command additionally looks for copies from other
+	files in the commit that creates the file. When this
+	option is given three times, the command additionally
+	looks for copies from other files in any commit.
++
+<num> is optional but it is the lower bound on the number of
+alphanumeric characters that Git must detect as moving/copying
+between files for it to associate those lines with the parent
+commit. And the default value is 40. If there are more than one
+`-C` options given, the <num> argument of the last `-C` will
+take effect.
+
+--ignore-rev <rev>::
+	Ignore changes made by the revision when assigning blame, as if the
+	change never happened.  Lines that were changed or added by an ignored
+	commit will be blamed on the previous commit that changed that line or
+	nearby lines.  This option may be specified multiple times to ignore
+	more than one revision.  If the `blame.markIgnoredLines` config option
+	is set, then lines that were changed by an ignored commit and attributed to
+	another commit will be marked with a `?` in the blame output.  If the
+	`blame.markUnblamableLines` config option is set, then those lines touched
+	by an ignored commit that we could not attribute to another revision are
+	marked with a '*'.
+
+--ignore-revs-file <file>::
+	Ignore revisions listed in `file`, which must be in the same format as an
+	`fsck.skipList`.  This option may be repeated, and these files will be
+	processed after any files specified with the `blame.ignoreRevsFile` config
+	option.  An empty file name, `""`, will clear the list of revs from
+	previously processed files.
+
+--color-lines::
+	Color line annotations in the default format differently if they come from
+	the same commit as the preceding line. This makes it easier to distinguish
+	code blocks introduced by different commits. The color defaults to cyan and
+	can be adjusted using the `color.blame.repeatedLines` config option.
+
+--color-by-age::
+	Color line annotations depending on the age of the line in the default format.
+	The `color.blame.highlightRecent` config option controls what color is used for
+	each range of age.
+
+-h::
+	Show help message.
diff --git a/Documentation/build-docdep.perl b/Documentation/build-docdep.perl
new file mode 100755
index 0000000000..315efaa2fa
--- /dev/null
+++ b/Documentation/build-docdep.perl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+
+my ($build_dir) = @ARGV;
+my %include = ();
+my %included = ();
+
+for my $text (<*.txt>) {
+    open I, '<', $text || die "cannot read: $text";
+    while (<I>) {
+	if (/^include::/) {
+	    chomp;
+	    s/^include::\s*//;
+	    s/\[\]//;
+	    s/{build_dir}/${build_dir}/;
+	    $include{$text}{$_} = 1;
+	    $included{$_} = 1;
+	}
+    }
+    close I;
+}
+
+# Do we care about chained includes???
+my $changed = 1;
+while ($changed) {
+    $changed = 0;
+    while (my ($text, $included) = each %include) {
+	for my $i (keys %$included) {
+	    # $text has include::$i; if $i includes $j
+	    # $text indirectly includes $j.
+	    if (exists $include{$i}) {
+		for my $j (keys %{$include{$i}}) {
+		    if (!exists $include{$text}{$j}) {
+			$include{$text}{$j} = 1;
+			$included{$j} = 1;
+			$changed = 1;
+		    }
+		}
+	    }
+	}
+    }
+}
+
+foreach my $text (sort keys %include) {
+    my $included = $include{$text};
+    if (! exists $included{$text} &&
+	(my $base = $text) =~ s/\.txt$//) {
+	print "$base.html $base.xml : ", join(" ", sort keys %$included), "\n";
+    }
+}
diff --git a/Documentation/cat-texi.perl b/Documentation/cat-texi.perl
new file mode 100755
index 0000000000..14d2f83415
--- /dev/null
+++ b/Documentation/cat-texi.perl
@@ -0,0 +1,46 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+my @menu = ();
+my $output = $ARGV[0];
+
+open my $tmp, '>', "$output.tmp";
+
+while (<STDIN>) {
+	next if (/^\\input texinfo/../\@node Top/);
+	next if (/^\@bye/ || /^\.ft/);
+	if (s/^\@top (.*)/\@node $1,,,Top/) {
+		push @menu, $1;
+	}
+	s/\(\@pxref\{\[(URLS|REMOTES)\]}\)//;
+	s/\@anchor\{[^{}]*\}//g;
+	print $tmp $_;
+}
+close $tmp;
+
+print '\input texinfo
+@setfilename gitman.info
+@documentencoding UTF-8
+@dircategory Development
+@direntry
+* Git Man Pages: (gitman).  Manual pages for Git revision control system
+@end direntry
+@node Top,,, (dir)
+@top Git Manual Pages
+@documentlanguage en
+@menu
+';
+
+for (@menu) {
+	print "* ${_}::\n";
+}
+print "\@end menu\n";
+open $tmp, '<', "$output.tmp";
+while (<$tmp>) {
+	print;
+}
+close $tmp;
+print "\@bye\n";
+unlink "$output.tmp";
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
new file mode 100755
index 0000000000..0a0c1b3f61
--- /dev/null
+++ b/Documentation/cmd-list.perl
@@ -0,0 +1,80 @@
+#!/usr/bin/perl -w
+
+use File::Compare qw(compare);
+
+sub format_one {
+	my ($source_dir, $out, $nameattr) = @_;
+	my ($name, $attr) = @$nameattr;
+	my ($path) = "$source_dir/Documentation/$name.adoc";
+	my ($state, $description);
+	my $mansection;
+	$state = 0;
+	open I, '<', "$path" or die "No such file $path.adoc";
+	while (<I>) {
+		if (/^(?:git|scalar)[a-z0-9-]*\(([0-9])\)$/) {
+			$mansection = $1;
+			next;
+		}
+		if (/^NAME$/) {
+			$state = 1;
+			next;
+		}
+		if ($state == 1 && /^----$/) {
+			$state = 2;
+			next;
+		}
+		next if ($state != 2);
+		chomp;
+		$description = $_;
+		last;
+	}
+	close I;
+	if (!defined $description) {
+		die "No description found in $path.adoc";
+	}
+	if (my ($verify_name, $text) = ($description =~ /^($name) - (.*)/)) {
+		print $out "linkgit:$name\[$mansection\]::\n\t";
+		if ($attr =~ / deprecated /) {
+			print $out "(deprecated) ";
+		}
+		print $out "$text.\n\n";
+	}
+	else {
+		die "Description does not match $name: $description";
+	}
+}
+
+my ($source_dir, $build_dir, @categories) = @ARGV;
+
+open IN, "<$source_dir/command-list.txt";
+while (<IN>) {
+	last if /^### command list/;
+}
+
+my %cmds = ();
+for (sort <IN>) {
+	next if /^#/;
+
+	chomp;
+	my ($name, $cat, $attr) = /^(\S+)\s+(.*?)(?:\s+(.*))?$/;
+	$attr = '' unless defined $attr;
+	push @{$cmds{$cat}}, [$name, " $attr "];
+}
+close IN;
+
+for my $out (@categories) {
+	my ($cat) = $out =~ /^cmds-(.*)\.adoc$/;
+	my ($path) = "$build_dir/$out";
+	open O, '>', "$path+" or die "Cannot open output file $out+";
+	for (@{$cmds{$cat}}) {
+		format_one($source_dir, \*O, $_);
+	}
+	close O;
+
+	if (-f "$path" && compare("$path", "$path+") == 0) {
+		unlink "$path+";
+	}
+	else {
+		rename "$path+", "$path";
+	}
+}
diff --git a/Documentation/config.adoc b/Documentation/config.adoc
new file mode 100644
index 0000000000..812b43c43d
--- /dev/null
+++ b/Documentation/config.adoc
@@ -0,0 +1,557 @@
+CONFIGURATION FILE
+------------------
+
+The Git configuration file contains a number of variables that affect
+the Git commands' behavior. The files `.git/config` and optionally
+`config.worktree` (see the "CONFIGURATION FILE" section of
+linkgit:git-worktree[1]) in each repository are used to store the
+configuration for that repository, and `$HOME/.gitconfig` is used to
+store a per-user configuration as fallback values for the `.git/config`
+file. The file `/etc/gitconfig` can be used to store a system-wide
+default configuration.
+
+The configuration variables are used by both the Git plumbing
+and the porcelain commands. The variables are divided into sections, wherein
+the fully qualified variable name of the variable itself is the last
+dot-separated segment and the section name is everything before the last
+dot. The variable names are case-insensitive, allow only alphanumeric
+characters and `-`, and must start with an alphabetic character.  Some
+variables may appear multiple times; we say then that the variable is
+multivalued.
+
+Syntax
+~~~~~~
+
+The syntax is fairly flexible and permissive.  Whitespace characters,
+which in this context are the space character (SP) and the horizontal
+tabulation (HT), are mostly ignored.  The '#' and ';' characters begin
+comments to the end of line.  Blank lines are ignored.
+
+The file consists of sections and variables.  A section begins with
+the name of the section in square brackets and continues until the next
+section begins.  Section names are case-insensitive.  Only alphanumeric
+characters, `-` and `.` are allowed in section names.  Each variable
+must belong to some section, which means that there must be a section
+header before the first setting of a variable.
+
+Sections can be further divided into subsections.  To begin a subsection
+put its name in double quotes, separated by space from the section name,
+in the section header, like in the example below:
+
+--------
+	[section "subsection"]
+
+--------
+
+Subsection names are case sensitive and can contain any characters except
+newline and the null byte. Doublequote `"` and backslash can be included
+by escaping them as `\"` and `\\`, respectively. Backslashes preceding
+other characters are dropped when reading; for example, `\t` is read as
+`t` and `\0` is read as `0`. Section headers cannot span multiple lines.
+Variables may belong directly to a section or to a given subsection. You
+can have `[section]` if you have `[section "subsection"]`, but you don't
+need to.
+
+There is also a deprecated `[section.subsection]` syntax. With this
+syntax, the subsection name is converted to lower-case and is also
+compared case sensitively. These subsection names follow the same
+restrictions as section names.
+
+All the other lines (and the remainder of the line after the section
+header) are recognized as setting variables, in the form
+'name = value' (or just 'name', which is a short-hand to say that
+the variable is the boolean "true").
+The variable names are case-insensitive, allow only alphanumeric characters
+and `-`, and must start with an alphabetic character.
+
+Whitespace characters surrounding `name`, `=` and `value` are discarded.
+Internal whitespace characters within 'value' are retained verbatim.
+Comments starting with either `#` or `;` and extending to the end of line
+are discarded.  A line that defines a value can be continued to the next
+line by ending it with a backslash (`\`);  the backslash and the end-of-line
+characters are discarded.
+
+If `value` needs to contain leading or trailing whitespace characters,
+it must be enclosed in double quotation marks (`"`).  Inside double quotation
+marks, double quote (`"`) and backslash (`\`) characters must be escaped:
+use `\"` for `"` and `\\` for `\`.
+
+The following escape sequences (beside `\"` and `\\`) are recognized:
+`\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
+and `\b` for backspace (BS).  Other char escape sequences (including octal
+escape sequences) are invalid.
+
+
+Includes
+~~~~~~~~
+
+The `include` and `includeIf` sections allow you to include config
+directives from another source. These sections behave identically to
+each other with the exception that `includeIf` sections may be ignored
+if their condition does not evaluate to true; see "Conditional includes"
+below.
+
+You can include a config file from another by setting the special
+`include.path` (or `includeIf.*.path`) variable to the name of the file
+to be included. The variable takes a pathname as its value, and is
+subject to tilde expansion. These variables can be given multiple times.
+
+The contents of the included file are inserted immediately, as if they
+had been found at the location of the include directive. If the value of the
+variable is a relative path, the path is considered to
+be relative to the configuration file in which the include directive
+was found.  See below for examples.
+
+Conditional includes
+~~~~~~~~~~~~~~~~~~~~
+
+You can conditionally include a config file from another by setting an
+`includeIf.<condition>.path` variable to the name of the file to be
+included.
+
+The condition starts with a keyword followed by a colon and some data
+whose format and meaning depends on the keyword. Supported keywords
+are:
+
+`gitdir`::
+
+	The data that follows the keyword `gitdir:` is used as a glob
+	pattern. If the location of the .git directory matches the
+	pattern, the include condition is met.
++
+The .git location may be auto-discovered, or come from `$GIT_DIR`
+environment variable. If the repository is auto-discovered via a .git
+file (e.g. from submodules, or a linked worktree), the .git location
+would be the final location where the .git directory is, not where the
+.git file is.
++
+The pattern can contain standard globbing wildcards and two additional
+ones, `**/` and `/**`, that can match multiple path components. Please
+refer to linkgit:gitignore[5] for details. For convenience:
+
+ * If the pattern starts with `~/`, `~` will be substituted with the
+   content of the environment variable `HOME`.
+
+ * If the pattern starts with `./`, it is replaced with the directory
+   containing the current config file.
+
+ * If the pattern does not start with either `~/`, `./` or `/`, `**/`
+   will be automatically prepended. For example, the pattern `foo/bar`
+   becomes `**/foo/bar` and would match `/any/path/to/foo/bar`.
+
+ * If the pattern ends with `/`, `**` will be automatically added. For
+   example, the pattern `foo/` becomes `foo/**`. In other words, it
+   matches "foo" and everything inside, recursively.
+
+`gitdir/i`::
+	This is the same as `gitdir` except that matching is done
+	case-insensitively (e.g. on case-insensitive file systems)
+
+`onbranch`::
+	The data that follows the keyword `onbranch:` is taken to be a
+	pattern with standard globbing wildcards and two additional
+	ones, `**/` and `/**`, that can match multiple path components.
+	If we are in a worktree where the name of the branch that is
+	currently checked out matches the pattern, the include condition
+	is met.
++
+If the pattern ends with `/`, `**` will be automatically added. For
+example, the pattern `foo/` becomes `foo/**`. In other words, it matches
+all branches that begin with `foo/`. This is useful if your branches are
+organized hierarchically and you would like to apply a configuration to
+all the branches in that hierarchy.
+
+`hasconfig:remote.*.url:`::
+	The data that follows this keyword is taken to
+	be a pattern with standard globbing wildcards and two
+	additional ones, `**/` and `/**`, that can match multiple
+	components. The first time this keyword is seen, the rest of
+	the config files will be scanned for remote URLs (without
+	applying any values). If there exists at least one remote URL
+	that matches this pattern, the include condition is met.
++
+Files included by this option (directly or indirectly) are not allowed
+to contain remote URLs.
++
+Note that unlike other includeIf conditions, resolving this condition
+relies on information that is not yet known at the point of reading the
+condition. A typical use case is this option being present as a
+system-level or global-level config, and the remote URL being in a
+local-level config; hence the need to scan ahead when resolving this
+condition. In order to avoid the chicken-and-egg problem in which
+potentially-included files can affect whether such files are potentially
+included, Git breaks the cycle by prohibiting these files from affecting
+the resolution of these conditions (thus, prohibiting them from
+declaring remote URLs).
++
+As for the naming of this keyword, it is for forwards compatibility with
+a naming scheme that supports more variable-based include conditions,
+but currently Git only supports the exact keyword described above.
+
+A few more notes on matching via `gitdir` and `gitdir/i`:
+
+ * Symlinks in `$GIT_DIR` are not resolved before matching.
+
+ * Both the symlink & realpath versions of paths will be matched
+   outside of `$GIT_DIR`. E.g. if ~/git is a symlink to
+   /mnt/storage/git, both `gitdir:~/git` and `gitdir:/mnt/storage/git`
+   will match.
++
+This was not the case in the initial release of this feature in
+v2.13.0, which only matched the realpath version. Configuration that
+wants to be compatible with the initial release of this feature needs
+to either specify only the realpath version, or both versions.
+
+ * Note that "../" is not special and will match literally, which is
+   unlikely what you want.
+
+Example
+~~~~~~~
+
+----
+# Core variables
+[core]
+	; Don't trust file modes
+	filemode = false
+
+# Our diff algorithm
+[diff]
+	external = /usr/local/bin/diff-wrapper
+	renames = true
+
+[branch "devel"]
+	remote = origin
+	merge = refs/heads/devel
+
+# Proxy settings
+[core]
+	gitProxy="ssh" for "kernel.org"
+	gitProxy=default-proxy ; for the rest
+
+[include]
+	path = /path/to/foo.inc ; include by absolute path
+	path = foo.inc ; find "foo.inc" relative to the current file
+	path = ~/foo.inc ; find "foo.inc" in your `$HOME` directory
+
+; include if $GIT_DIR is /path/to/foo/.git
+[includeIf "gitdir:/path/to/foo/.git"]
+	path = /path/to/foo.inc
+
+; include for all repositories inside /path/to/group
+[includeIf "gitdir:/path/to/group/"]
+	path = /path/to/foo.inc
+
+; include for all repositories inside $HOME/to/group
+[includeIf "gitdir:~/to/group/"]
+	path = /path/to/foo.inc
+
+; relative paths are always relative to the including
+; file (if the condition is true); their location is not
+; affected by the condition
+[includeIf "gitdir:/path/to/group/"]
+	path = foo.inc
+
+; include only if we are in a worktree where foo-branch is
+; currently checked out
+[includeIf "onbranch:foo-branch"]
+	path = foo.inc
+
+; include only if a remote with the given URL exists (note
+; that such a URL may be provided later in a file or in a
+; file read after this file is read, as seen in this example)
+[includeIf "hasconfig:remote.*.url:https://example.com/**";]
+	path = foo.inc
+[remote "origin"]
+	url = https://example.com/git
+----
+
+Values
+~~~~~~
+
+Values of many variables are treated as a simple string, but there
+are variables that take values of specific types and there are rules
+as to how to spell them.
+
+boolean::
+
+       When a variable is said to take a boolean value, many
+       synonyms are accepted for 'true' and 'false'; these are all
+       case-insensitive.
+
+	true;; Boolean true literals are `yes`, `on`, `true`,
+		and `1`.  Also, a variable defined without `= <value>`
+		is taken as true.
+
+	false;; Boolean false literals are `no`, `off`, `false`,
+		`0` and the empty string.
++
+When converting a value to its canonical form using the `--type=bool` type
+specifier, 'git config' will ensure that the output is "true" or
+"false" (spelled in lowercase).
+
+integer::
+       The value for many variables that specify various sizes can
+       be suffixed with `k`, `M`,... to mean "scale the number by
+       1024", "by 1024x1024", etc.
+
+color::
+       The value for a variable that takes a color is a list of
+       colors (at most two, one for foreground and one for background)
+       and attributes (as many as you want), separated by spaces.
++
+The basic colors accepted are `normal`, `black`, `red`, `green`,
+`yellow`, `blue`, `magenta`, `cyan`, `white` and `default`.  The first
+color given is the foreground; the second is the background.  All the
+basic colors except `normal` and `default` have a bright variant that can
+be specified by prefixing the color with `bright`, like `brightred`.
++
+The color `normal` makes no change to the color. It is the same as an
+empty string, but can be used as the foreground color when specifying a
+background color alone (for example, "normal red").
++
+The color `default` explicitly resets the color to the terminal default,
+for example to specify a cleared background. Although it varies between
+terminals, this is usually not the same as setting to "white black".
++
+Colors may also be given as numbers between 0 and 255; these use ANSI
+256-color mode (but note that not all terminals may support this).  If
+your terminal supports it, you may also specify 24-bit RGB values as
+hex, like `#ff0ab3`, or 12-bit RGB values like `#f1b`, which is
+equivalent to the 24-bit color `#ff11bb`.
++
+The accepted attributes are `bold`, `dim`, `ul`, `blink`, `reverse`,
+`italic`, and `strike` (for crossed-out or "strikethrough" letters).
+The position of any attributes with respect to the colors
+(before, after, or in between), doesn't matter. Specific attributes may
+be turned off by prefixing them with `no` or `no-` (e.g., `noreverse`,
+`no-ul`, etc).
++
+The pseudo-attribute `reset` resets all colors and attributes before
+applying the specified coloring. For example, `reset green` will result
+in a green foreground and default background without any active
+attributes.
++
+An empty color string produces no color effect at all. This can be used
+to avoid coloring specific elements without disabling color entirely.
++
+For git's pre-defined color slots, the attributes are meant to be reset
+at the beginning of each item in the colored output. So setting
+`color.decorate.branch` to `black` will paint that branch name in a
+plain `black`, even if the previous thing on the same output line (e.g.
+opening parenthesis before the list of branch names in `log --decorate`
+output) is set to be painted with `bold` or some other attribute.
+However, custom log formats may do more complicated and layered
+coloring, and the negated forms may be useful there.
+
+pathname::
+	A variable that takes a pathname value can be given a
+	string that begins with "`~/`" or "`~user/`", and the usual
+	tilde expansion happens to such a string: `~/`
+	is expanded to the value of `$HOME`, and `~user/` to the
+	specified user's home directory.
++
+If a path starts with `%(prefix)/`, the remainder is interpreted as a
+path relative to Git's "runtime prefix", i.e. relative to the location
+where Git itself was installed. For example, `%(prefix)/bin/` refers to
+the directory in which the Git executable itself lives. If Git was
+compiled without runtime prefix support, the compiled-in prefix will be
+substituted instead. In the unlikely event that a literal path needs to
+be specified that should _not_ be expanded, it needs to be prefixed by
+`./`, like so: `./%(prefix)/bin`.
+
+
+Variables
+~~~~~~~~~
+
+Note that this list is non-comprehensive and not necessarily complete.
+For command-specific variables, you will find a more detailed description
+in the appropriate manual page.
+
+Other git-related tools may and do use their own variables.  When
+inventing new variables for use in your own tool, make sure their
+names do not conflict with those that are used by Git itself and
+other popular tools, and describe them in your documentation.
+
+include::config/add.adoc[]
+
+include::config/advice.adoc[]
+
+include::config/alias.adoc[]
+
+include::config/am.adoc[]
+
+include::config/apply.adoc[]
+
+include::config/attr.adoc[]
+
+include::config/bitmap-pseudo-merge.adoc[]
+
+include::config/blame.adoc[]
+
+include::config/branch.adoc[]
+
+include::config/browser.adoc[]
+
+include::config/bundle.adoc[]
+
+include::config/checkout.adoc[]
+
+include::config/clean.adoc[]
+
+include::config/clone.adoc[]
+
+include::config/color.adoc[]
+
+include::config/column.adoc[]
+
+include::config/commit.adoc[]
+
+include::config/commitgraph.adoc[]
+
+include::config/completion.adoc[]
+
+include::config/core.adoc[]
+
+include::config/credential.adoc[]
+
+include::config/diff.adoc[]
+
+include::config/difftool.adoc[]
+
+include::config/extensions.adoc[]
+
+include::config/fastimport.adoc[]
+
+include::config/feature.adoc[]
+
+include::config/fetch.adoc[]
+
+include::config/filter.adoc[]
+
+include::config/format.adoc[]
+
+include::config/fsck.adoc[]
+
+include::config/fsmonitor--daemon.adoc[]
+
+include::config/gc.adoc[]
+
+include::config/gitcvs.adoc[]
+
+include::config/gitweb.adoc[]
+
+include::config/gpg.adoc[]
+
+include::config/grep.adoc[]
+
+include::config/gui.adoc[]
+
+include::config/guitool.adoc[]
+
+include::config/help.adoc[]
+
+include::config/http.adoc[]
+
+include::config/i18n.adoc[]
+
+include::config/imap.adoc[]
+
+include::config/includeif.adoc[]
+
+include::config/index.adoc[]
+
+include::config/init.adoc[]
+
+include::config/instaweb.adoc[]
+
+include::config/interactive.adoc[]
+
+include::config/log.adoc[]
+
+include::config/lsrefs.adoc[]
+
+include::config/mailinfo.adoc[]
+
+include::config/mailmap.adoc[]
+
+include::config/maintenance.adoc[]
+
+include::config/man.adoc[]
+
+include::config/merge.adoc[]
+
+include::config/mergetool.adoc[]
+
+include::config/notes.adoc[]
+
+include::config/pack.adoc[]
+
+include::config/pager.adoc[]
+
+include::config/pretty.adoc[]
+
+include::config/promisor.adoc[]
+
+include::config/protocol.adoc[]
+
+include::config/pull.adoc[]
+
+include::config/push.adoc[]
+
+include::config/rebase.adoc[]
+
+include::config/receive.adoc[]
+
+include::config/reftable.adoc[]
+
+include::config/remote.adoc[]
+
+include::config/remotes.adoc[]
+
+include::config/repack.adoc[]
+
+include::config/rerere.adoc[]
+
+include::config/revert.adoc[]
+
+include::config/safe.adoc[]
+
+include::config/sendemail.adoc[]
+
+include::config/sequencer.adoc[]
+
+include::config/showbranch.adoc[]
+
+include::config/sparse.adoc[]
+
+include::config/splitindex.adoc[]
+
+include::config/ssh.adoc[]
+
+include::config/stash.adoc[]
+
+include::config/status.adoc[]
+
+include::config/submodule.adoc[]
+
+include::config/tag.adoc[]
+
+include::config/tar.adoc[]
+
+include::config/trace2.adoc[]
+
+include::config/transfer.adoc[]
+
+include::config/uploadarchive.adoc[]
+
+include::config/uploadpack.adoc[]
+
+include::config/url.adoc[]
+
+include::config/user.adoc[]
+
+include::config/versionsort.adoc[]
+
+include::config/web.adoc[]
+
+include::config/worktree.adoc[]
diff --git a/Documentation/config/add.adoc b/Documentation/config/add.adoc
new file mode 100644
index 0000000000..7497533cbc
--- /dev/null
+++ b/Documentation/config/add.adoc
@@ -0,0 +1,12 @@
+`add.ignoreErrors`::
+`add.ignore-errors` (deprecated)::
+	Tells `git add` to continue adding files when some files cannot be
+	added due to indexing errors.
+ifdef::git-add[]
+	Equivalent to the `--ignore-errors` option.
+endif::git-add[]
+ifndef::git-add[]
+	Equivalent to the `--ignore-errors` option of linkgit:git-add[1].
+endif::git-add[]
+	`add.ignore-errors` is deprecated, as it does not follow the usual
+	naming convention for configuration variables.
diff --git a/Documentation/config/advice.adoc b/Documentation/config/advice.adoc
new file mode 100644
index 0000000000..257db58918
--- /dev/null
+++ b/Documentation/config/advice.adoc
@@ -0,0 +1,169 @@
+advice.*::
+	These variables control various optional help messages designed to
+	aid new users.  When left unconfigured, Git will give the message
+	alongside instructions on how to squelch it.  You can tell Git
+	that you have understood the issue and no longer need a specific
+	help message by setting the corresponding variable to `false`.
++
+As they are intended to help human users, these messages are output to
+the standard error. When tools that run Git as a subprocess find them
+disruptive, they can set `GIT_ADVICE=0` in the environment to squelch
+all advice messages.
++
+--
+	addEmbeddedRepo::
+		Shown when the user accidentally adds one
+		git repo inside of another.
+	addEmptyPathspec::
+		Shown when the user runs `git add` without providing
+		the pathspec parameter.
+	addIgnoredFile::
+		Shown when the user attempts to add an ignored file to
+		the index.
+	amWorkDir::
+		Shown when linkgit:git-am[1] fails to apply a patch
+		file, to tell the user the location of the file.
+	ambiguousFetchRefspec::
+		Shown when a fetch refspec for multiple remotes maps to
+		the same remote-tracking branch namespace and causes branch
+		tracking set-up to fail.
+	checkoutAmbiguousRemoteBranchName::
+		Shown when the argument to
+		linkgit:git-checkout[1] and linkgit:git-switch[1]
+		ambiguously resolves to a
+		remote tracking branch on more than one remote in
+		situations where an unambiguous argument would have
+		otherwise caused a remote-tracking branch to be
+		checked out. See the `checkout.defaultRemote`
+		configuration variable for how to set a given remote
+		to be used by default in some situations where this
+		advice would be printed.
+	commitBeforeMerge::
+		Shown when linkgit:git-merge[1] refuses to
+		merge to avoid overwriting local changes.
+	detachedHead::
+		Shown when the user uses
+		linkgit:git-switch[1] or linkgit:git-checkout[1]
+		to move to the detached HEAD state, to tell the user how
+		to create a local branch after the fact.
+	diverging::
+		Shown when a fast-forward is not possible.
+	fetchShowForcedUpdates::
+		Shown when linkgit:git-fetch[1] takes a long time
+		to calculate forced updates after ref updates, or to warn
+		that the check is disabled.
+	forceDeleteBranch::
+		Shown when the user tries to delete a not fully merged
+		branch without the force option set.
+	ignoredHook::
+		Shown when a hook is ignored because the hook is not
+		set as executable.
+	implicitIdentity::
+		Shown when the user's information is guessed from the
+		system username and domain name, to tell the user how to
+		set their identity configuration.
+	mergeConflict::
+		Shown when various commands stop because of conflicts.
+	nestedTag::
+		Shown when a user attempts to recursively tag a tag object.
+	pushAlreadyExists::
+		Shown when linkgit:git-push[1] rejects an update that
+		does not qualify for fast-forwarding (e.g., a tag.)
+	pushFetchFirst::
+		Shown when linkgit:git-push[1] rejects an update that
+		tries to overwrite a remote ref that points at an
+		object we do not have.
+	pushNeedsForce::
+		Shown when linkgit:git-push[1] rejects an update that
+		tries to overwrite a remote ref that points at an
+		object that is not a commit-ish, or make the remote
+		ref point at an object that is not a commit-ish.
+	pushNonFFCurrent::
+		Shown when linkgit:git-push[1] fails due to a
+		non-fast-forward update to the current branch.
+	pushNonFFMatching::
+		Shown when the user ran linkgit:git-push[1] and pushed
+		"matching refs" explicitly (i.e. used `:`, or
+		specified a refspec that isn't the current branch) and
+		it resulted in a non-fast-forward error.
+	pushRefNeedsUpdate::
+		Shown when linkgit:git-push[1] rejects a forced update of
+		a branch when its remote-tracking ref has updates that we
+		do not have locally.
+	pushUnqualifiedRefname::
+		Shown when linkgit:git-push[1] gives up trying to
+		guess based on the source and destination refs what
+		remote ref namespace the source belongs in, but where
+		we can still suggest that the user push to either
+		`refs/heads/*` or `refs/tags/*` based on the type of the
+		source object.
+	pushUpdateRejected::
+		Set this variable to `false` if you want to disable
+		`pushNonFFCurrent`, `pushNonFFMatching`, `pushAlreadyExists`,
+		`pushFetchFirst`, `pushNeedsForce`, and `pushRefNeedsUpdate`
+		simultaneously.
+	rebaseTodoError::
+		Shown when there is an error after editing the rebase todo list.
+	refSyntax::
+		Shown when the user provides an illegal ref name, to
+		tell the user about the ref syntax documentation.
+	resetNoRefresh::
+		Shown when linkgit:git-reset[1] takes more than 2
+		seconds to refresh the index after reset, to tell the user
+		that they can use the `--no-refresh` option.
+	resolveConflict::
+		Shown by various commands when conflicts
+		prevent the operation from being performed.
+	rmHints::
+		Shown on failure in the output of linkgit:git-rm[1], to
+		give directions on how to proceed from the current state.
+	sequencerInUse::
+		Shown when a sequencer command is already in progress.
+	skippedCherryPicks::
+		Shown when linkgit:git-rebase[1] skips a commit that has already
+		been cherry-picked onto the upstream branch.
+	sparseIndexExpanded::
+		Shown when a sparse index is expanded to a full index, which is likely
+		due to an unexpected set of files existing outside of the
+		sparse-checkout.
+	statusAheadBehind::
+		Shown when linkgit:git-status[1] computes the ahead/behind
+		counts for a local ref compared to its remote tracking ref,
+		and that calculation takes longer than expected. Will not
+		appear if `status.aheadBehind` is false or the option
+		`--no-ahead-behind` is given.
+	statusHints::
+		Show directions on how to proceed from the current
+		state in the output of linkgit:git-status[1], in
+		the template shown when writing commit messages in
+		linkgit:git-commit[1], and in the help message shown
+		by linkgit:git-switch[1] or
+		linkgit:git-checkout[1] when switching branches.
+	statusUoption::
+		Shown when linkgit:git-status[1] takes more than 2
+		seconds to enumerate untracked files, to tell the user that
+		they can use the `-u` option.
+	submoduleAlternateErrorStrategyDie::
+		Shown when a submodule.alternateErrorStrategy option
+		configured to "die" causes a fatal error.
+	submoduleMergeConflict::
+		Advice shown when a non-trivial submodule merge conflict is
+		encountered.
+	submodulesNotUpdated::
+		Shown when a user runs a submodule command that fails
+		because `git submodule update --init` was not run.
+	suggestDetachingHead::
+		Shown when linkgit:git-switch[1] refuses to detach HEAD
+		without the explicit `--detach` option.
+	updateSparsePath::
+		Shown when either linkgit:git-add[1] or linkgit:git-rm[1]
+		is asked to update index entries outside the current sparse
+		checkout.
+	waitingForEditor::
+		Shown when Git is waiting for editor input. Relevant
+		when e.g. the editor is not launched inside the terminal.
+	worktreeAddOrphan::
+		Shown when the user tries to create a worktree from an
+		invalid reference, to tell the user how to create a new unborn
+		branch instead.
+--
diff --git a/Documentation/config/alias.adoc b/Documentation/config/alias.adoc
new file mode 100644
index 0000000000..2c5db0ad84
--- /dev/null
+++ b/Documentation/config/alias.adoc
@@ -0,0 +1,43 @@
+alias.*::
+	Command aliases for the linkgit:git[1] command wrapper - e.g.
+	after defining `alias.last = cat-file commit HEAD`, the invocation
+	`git last` is equivalent to `git cat-file commit HEAD`. To avoid
+	confusion and troubles with script usage, aliases that
+	hide existing Git commands are ignored. Arguments are split by
+	spaces, the usual shell quoting and escaping are supported.
+	A quote pair or a backslash can be used to quote them.
++
+Note that the first word of an alias does not necessarily have to be a
+command. It can be a command-line option that will be passed into the
+invocation of `git`. In particular, this is useful when used with `-c`
+to pass in one-time configurations or `-p` to force pagination. For example,
+`loud-rebase = -c commit.verbose=true rebase` can be defined such that
+running `git loud-rebase` would be equivalent to
+`git -c commit.verbose=true rebase`. Also, `ps = -p status` would be a
+helpful alias since `git ps` would paginate the output of `git status`
+where the original command does not.
++
+If the alias expansion is prefixed with an exclamation point,
+it will be treated as a shell command.  For example, defining
+`alias.new = !gitk --all --not ORIG_HEAD`, the invocation
+`git new` is equivalent to running the shell command
+`gitk --all --not ORIG_HEAD`.  Note:
++
+* Shell commands will be executed from the top-level directory of a
+  repository, which may not necessarily be the current directory.
+* `GIT_PREFIX` is set as returned by running `git rev-parse --show-prefix`
+  from the original current directory. See linkgit:git-rev-parse[1].
+* Shell command aliases always receive any extra arguments provided to
+  the Git command-line as positional arguments.
+** Care should be taken if your shell alias is a "one-liner" script
+   with multiple commands (e.g. in a pipeline), references multiple
+   arguments, or is otherwise not able to handle positional arguments
+   added at the end.  For example: `alias.cmd = "!echo $1 | grep $2"`
+   called as `git cmd 1 2` will be executed as 'echo $1 | grep $2
+   1 2', which is not what you want.
+** A convenient way to deal with this is to write your script
+   operations in an inline function that is then called with any
+   arguments from the command-line.  For example `alias.cmd = "!c() {
+   echo $1 | grep $2 ; }; c" will correctly execute the prior example.
+** Setting `GIT_TRACE=1` can help you debug the command being run for
+   your alias.
diff --git a/Documentation/config/am.adoc b/Documentation/config/am.adoc
new file mode 100644
index 0000000000..5bcad2efb1
--- /dev/null
+++ b/Documentation/config/am.adoc
@@ -0,0 +1,14 @@
+am.keepcr::
+	If true, git-am will call git-mailsplit for patches in mbox format
+	with parameter `--keep-cr`. In this case git-mailsplit will
+	not remove `\r` from lines ending with `\r\n`. Can be overridden
+	by giving `--no-keep-cr` from the command line.
+	See linkgit:git-am[1], linkgit:git-mailsplit[1].
+
+am.threeWay::
+	By default, `git am` will fail if the patch does not apply cleanly. When
+	set to true, this setting tells `git am` to fall back on 3-way merge if
+	the patch records the identity of blobs it is supposed to apply to and
+	we have those blobs available locally (equivalent to giving the `--3way`
+	option from the command line). Defaults to `false`.
+	See linkgit:git-am[1].
diff --git a/Documentation/config/apply.adoc b/Documentation/config/apply.adoc
new file mode 100644
index 0000000000..f9908e210a
--- /dev/null
+++ b/Documentation/config/apply.adoc
@@ -0,0 +1,11 @@
+apply.ignoreWhitespace::
+	When set to 'change', tells 'git apply' to ignore changes in
+	whitespace, in the same way as the `--ignore-space-change`
+	option.
+	When set to one of: no, none, never, false, it tells 'git apply' to
+	respect all whitespace differences.
+	See linkgit:git-apply[1].
+
+apply.whitespace::
+	Tells 'git apply' how to handle whitespace, in the same way
+	as the `--whitespace` option. See linkgit:git-apply[1].
diff --git a/Documentation/config/attr.adoc b/Documentation/config/attr.adoc
new file mode 100644
index 0000000000..c4a5857993
--- /dev/null
+++ b/Documentation/config/attr.adoc
@@ -0,0 +1,6 @@
+attr.tree::
+	A reference to a tree in the repository from which to read attributes,
+	instead of the `.gitattributes` file in the working tree. If the value
+	does not resolve to a valid tree object, an empty tree is used instead.
+	When the `GIT_ATTR_SOURCE` environment variable or `--attr-source`
+	command line option are used, this configuration variable has no effect.
diff --git a/Documentation/config/bitmap-pseudo-merge.adoc b/Documentation/config/bitmap-pseudo-merge.adoc
new file mode 100644
index 0000000000..1f264eca99
--- /dev/null
+++ b/Documentation/config/bitmap-pseudo-merge.adoc
@@ -0,0 +1,91 @@
+NOTE: The configuration options in `bitmapPseudoMerge.*` are considered
+EXPERIMENTAL and may be subject to change or be removed entirely in the
+future. For more information about the pseudo-merge bitmap feature, see
+the "Pseudo-merge bitmaps" section of linkgit:gitpacking[7].
+
+bitmapPseudoMerge.<name>.pattern::
+	Regular expression used to match reference names. Commits
+	pointed to by references matching this pattern (and meeting
+	the below criteria, like `bitmapPseudoMerge.<name>.sampleRate`
+	and `bitmapPseudoMerge.<name>.threshold`) will be considered
+	for inclusion in a pseudo-merge bitmap.
++
+Commits are grouped into pseudo-merge groups based on whether or not
+any reference(s) that point at a given commit match the pattern, which
+is an extended regular expression.
++
+Within a pseudo-merge group, commits may be further grouped into
+sub-groups based on the capture groups in the pattern. These
+sub-groupings are formed from the regular expressions by concatenating
+any capture groups from the regular expression, with a '-' dash in
+between.
++
+For example, if the pattern is `refs/tags/`, then all tags (provided
+they meet the below criteria) will be considered candidates for the
+same pseudo-merge group. However, if the pattern is instead
+`refs/remotes/([0-9])+/tags/`, then tags from different remotes will
+be grouped into separate pseudo-merge groups, based on the remote
+number.
+
+bitmapPseudoMerge.<name>.decay::
+	Determines the rate at which consecutive pseudo-merge bitmap
+	groups decrease in size. Must be non-negative. This parameter
+	can be thought of as `k` in the function `f(n) = C * n^-k`,
+	where `f(n)` is the size of the `n`th group.
++
+Setting the decay rate equal to `0` will cause all groups to be the
+same size. Setting the decay rate equal to `1` will cause the `n`th
+group to be `1/n` the size of the initial group.  Higher values of the
+decay rate cause consecutive groups to shrink at an increasing rate.
+The default is `1`.
++
+If all groups are the same size, it is possible that groups containing
+newer commits will be able to be used less often than earlier groups,
+since it is more likely that the references pointing at newer commits
+will be updated more often than a reference pointing at an old commit.
+
+bitmapPseudoMerge.<name>.sampleRate::
+	Determines the proportion of non-bitmapped commits (among
+	reference tips) which are selected for inclusion in an
+	unstable pseudo-merge bitmap. Must be between `0` and `1`
+	(inclusive). The default is `1`.
+
+bitmapPseudoMerge.<name>.threshold::
+	Determines the minimum age of non-bitmapped commits (among
+	reference tips, as above) which are candidates for inclusion
+	in an unstable pseudo-merge bitmap. The default is
+	`1.week.ago`.
+
+bitmapPseudoMerge.<name>.maxMerges::
+	Determines the maximum number of pseudo-merge commits among
+	which commits may be distributed.
++
+For pseudo-merge groups whose pattern does not contain any capture
+groups, this setting is applied for all commits matching the regular
+expression. For patterns that have one or more capture groups, this
+setting is applied for each distinct capture group.
++
+For example, if your capture group is `refs/tags/`, then this setting
+will distribute all tags into a maximum of `maxMerges` pseudo-merge
+commits. However, if your capture group is, say,
+`refs/remotes/([0-9]+)/tags/`, then this setting will be applied to
+each remote's set of tags individually.
++
+Must be non-negative. The default value is 64.
+
+bitmapPseudoMerge.<name>.stableThreshold::
+	Determines the minimum age of commits (among reference tips,
+	as above, however stable commits are still considered
+	candidates even when they have been covered by a bitmap) which
+	are candidates for a stable a pseudo-merge bitmap. The default
+	is `1.month.ago`.
++
+Setting this threshold to a smaller value (e.g., 1.week.ago) will cause
+more stable groups to be generated (which impose a one-time generation
+cost) but those groups will likely become stale over time. Using a
+larger value incurs the opposite penalty (fewer stable groups which are
+more useful).
+
+bitmapPseudoMerge.<name>.stableSize::
+	Determines the size (in number of commits) of a stable
+	psuedo-merge bitmap. The default is `512`.
diff --git a/Documentation/config/blame.adoc b/Documentation/config/blame.adoc
new file mode 100644
index 0000000000..4d047c1790
--- /dev/null
+++ b/Documentation/config/blame.adoc
@@ -0,0 +1,37 @@
+blame.blankBoundary::
+	Show blank commit object name for boundary commits in
+	linkgit:git-blame[1]. This option defaults to false.
+
+blame.coloring::
+	This determines the coloring scheme to be applied to blame
+	output. It can be 'repeatedLines', 'highlightRecent',
+	or 'none' which is the default.
+
+blame.date::
+	Specifies the format used to output dates in linkgit:git-blame[1].
+	If unset the iso format is used. For supported values,
+	see the discussion of the `--date` option at linkgit:git-log[1].
+
+blame.showEmail::
+	Show the author email instead of author name in linkgit:git-blame[1].
+	This option defaults to false.
+
+blame.showRoot::
+	Do not treat root commits as boundaries in linkgit:git-blame[1].
+	This option defaults to false.
+
+blame.ignoreRevsFile::
+	Ignore revisions listed in the file, one unabbreviated object name per
+	line, in linkgit:git-blame[1].  Whitespace and comments beginning with
+	`#` are ignored.  This option may be repeated multiple times.  Empty
+	file names will reset the list of ignored revisions.  This option will
+	be handled before the command line option `--ignore-revs-file`.
+
+blame.markUnblamableLines::
+	Mark lines that were changed by an ignored revision that we could not
+	attribute to another commit with a '*' in the output of
+	linkgit:git-blame[1].
+
+blame.markIgnoredLines::
+	Mark lines that were changed by an ignored revision that we attributed to
+	another commit with a '?' in the output of linkgit:git-blame[1].
diff --git a/Documentation/config/branch.adoc b/Documentation/config/branch.adoc
new file mode 100644
index 0000000000..432b9cd2c0
--- /dev/null
+++ b/Documentation/config/branch.adoc
@@ -0,0 +1,103 @@
+branch.autoSetupMerge::
+	Tells 'git branch', 'git switch' and 'git checkout' to set up new branches
+	so that linkgit:git-pull[1] will appropriately merge from the
+	starting point branch. Note that even if this option is not set,
+	this behavior can be chosen per-branch using the `--track`
+	and `--no-track` options. The valid settings are: `false` -- no
+	automatic setup is done; `true` -- automatic setup is done when the
+	starting point is a remote-tracking branch; `always` --
+	automatic setup is done when the starting point is either a
+	local branch or remote-tracking branch; `inherit` -- if the starting point
+	has a tracking configuration, it is copied to the new
+	branch; `simple` -- automatic setup is done only when the starting point
+	is a remote-tracking branch and the new branch has the same name as the
+	remote branch. This option defaults to true.
+
+branch.autoSetupRebase::
+	When a new branch is created with 'git branch', 'git switch' or 'git checkout'
+	that tracks another branch, this variable tells Git to set
+	up pull to rebase instead of merge (see "branch.<name>.rebase").
+	When `never`, rebase is never automatically set to true.
+	When `local`, rebase is set to true for tracked branches of
+	other local branches.
+	When `remote`, rebase is set to true for tracked branches of
+	remote-tracking branches.
+	When `always`, rebase will be set to true for all tracking
+	branches.
+	See "branch.autoSetupMerge" for details on how to set up a
+	branch to track another branch.
+	This option defaults to never.
+
+branch.sort::
+	This variable controls the sort ordering of branches when displayed by
+	linkgit:git-branch[1]. Without the "--sort=<value>" option provided, the
+	value of this variable will be used as the default.
+	See linkgit:git-for-each-ref[1] field names for valid values.
+
+branch.<name>.remote::
+	When on branch <name>, it tells 'git fetch' and 'git push'
+	which remote to fetch from or push to.  The remote to push to
+	may be overridden with `remote.pushDefault` (for all branches).
+	The remote to push to, for the current branch, may be further
+	overridden by `branch.<name>.pushRemote`.  If no remote is
+	configured, or if you are not on any branch and there is more than
+	one remote defined in the repository, it defaults to `origin` for
+	fetching and `remote.pushDefault` for pushing.
+	Additionally, `.` (a period) is the current local repository
+	(a dot-repository), see `branch.<name>.merge`'s final note below.
+
+branch.<name>.pushRemote::
+	When on branch <name>, it overrides `branch.<name>.remote` for
+	pushing.  It also overrides `remote.pushDefault` for pushing
+	from branch <name>.  When you pull from one place (e.g. your
+	upstream) and push to another place (e.g. your own publishing
+	repository), you would want to set `remote.pushDefault` to
+	specify the remote to push to for all branches, and use this
+	option to override it for a specific branch.
+
+branch.<name>.merge::
+	Defines, together with branch.<name>.remote, the upstream branch
+	for the given branch. It tells 'git fetch'/'git pull'/'git rebase' which
+	branch to merge and can also affect 'git push' (see push.default).
+	When in branch <name>, it tells 'git fetch' the default
+	refspec to be marked for merging in FETCH_HEAD. The value is
+	handled like the remote part of a refspec, and must match a
+	ref which is fetched from the remote given by
+	"branch.<name>.remote".
+	The merge information is used by 'git pull' (which first calls
+	'git fetch') to lookup the default branch for merging. Without
+	this option, 'git pull' defaults to merge the first refspec fetched.
+	Specify multiple values to get an octopus merge.
+	If you wish to setup 'git pull' so that it merges into <name> from
+	another branch in the local repository, you can point
+	branch.<name>.merge to the desired branch, and use the relative path
+	setting `.` (a period) for branch.<name>.remote.
+
+branch.<name>.mergeOptions::
+	Sets default options for merging into branch <name>. The syntax and
+	supported options are the same as those of linkgit:git-merge[1], but
+	option values containing whitespace characters are currently not
+	supported.
+
+branch.<name>.rebase::
+	When true, rebase the branch <name> on top of the fetched branch,
+	instead of merging the default branch from the default remote when
+	"git pull" is run. See "pull.rebase" for doing this in a non
+	branch-specific manner.
++
+When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'
+so that the local merge commits are included in the rebase (see
+linkgit:git-rebase[1] for details).
++
+When the value is `interactive` (or just 'i'), the rebase is run in interactive
+mode.
++
+*NOTE*: this is a possibly dangerous operation; do *not* use
+it unless you understand the implications (see linkgit:git-rebase[1]
+for details).
+
+branch.<name>.description::
+	Branch description, can be edited with
+	`git branch --edit-description`. Branch description is
+	automatically added to the format-patch cover letter or
+	request-pull summary.
diff --git a/Documentation/config/browser.adoc b/Documentation/config/browser.adoc
new file mode 100644
index 0000000000..195df207a6
--- /dev/null
+++ b/Documentation/config/browser.adoc
@@ -0,0 +1,9 @@
+browser.<tool>.cmd::
+	Specify the command to invoke the specified browser. The
+	specified command is evaluated in shell with the URLs passed
+	as arguments. (See linkgit:git-web{litdd}browse[1].)
+
+browser.<tool>.path::
+	Override the path for the given tool that may be used to
+	browse HTML help (see `-w` option in linkgit:git-help[1]) or a
+	working repository in gitweb (see linkgit:git-instaweb[1]).
diff --git a/Documentation/config/bundle.adoc b/Documentation/config/bundle.adoc
new file mode 100644
index 0000000000..3faae38685
--- /dev/null
+++ b/Documentation/config/bundle.adoc
@@ -0,0 +1,31 @@
+bundle.*::
+	The `bundle.*` keys may appear in a bundle list file found via the
+	`git clone --bundle-uri` option. These keys currently have no effect
+	if placed in a repository config file, though this will change in the
+	future. See link:technical/bundle-uri.html[the bundle URI design
+	document] for more details.
+
+bundle.version::
+	This integer value advertises the version of the bundle list format
+	used by the bundle list. Currently, the only accepted value is `1`.
+
+bundle.mode::
+	This string value should be either `all` or `any`. This value describes
+	whether all of the advertised bundles are required to unbundle a
+	complete understanding of the bundled information (`all`) or if any one
+	of the listed bundle URIs is sufficient (`any`).
+
+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 value currently understood is `creationToken`.
+
+bundle.<id>.*::
+	The `bundle.<id>.*` keys are used to describe a single item in the
+	bundle list, grouped under `<id>` for identification purposes.
+
+bundle.<id>.uri::
+	This string value defines the URI by which Git can reach the contents
+	of this `<id>`. This URI may be a bundle file or another bundle list.
diff --git a/Documentation/config/checkout.adoc b/Documentation/config/checkout.adoc
new file mode 100644
index 0000000000..a323022993
--- /dev/null
+++ b/Documentation/config/checkout.adoc
@@ -0,0 +1,44 @@
+checkout.defaultRemote::
+	When you run `git checkout <something>`
+	or `git switch <something>` and only have one
+	remote, it may implicitly fall back on checking out and
+	tracking e.g. `origin/<something>`. This stops working as soon
+	as you have more than one remote with a `<something>`
+	reference. This setting allows for setting the name of a
+	preferred remote that should always win when it comes to
+	disambiguation. The typical use-case is to set this to
+	`origin`.
++
+Currently this is used by linkgit:git-switch[1] and
+linkgit:git-checkout[1] when `git checkout <something>`
+or `git switch <something>`
+will checkout the `<something>` branch on another remote,
+and by linkgit:git-worktree[1] when `git worktree add` refers to a
+remote branch. This setting might be used for other checkout-like
+commands or functionality in the future.
+
+checkout.guess::
+	Provides the default value for the `--guess` or `--no-guess`
+	option in `git checkout` and `git switch`. See
+	linkgit:git-switch[1] and linkgit:git-checkout[1].
+
+checkout.workers::
+	The number of parallel workers to use when updating the working tree.
+	The default is one, i.e. sequential execution. If set to a value less
+	than one, Git will use as many workers as the number of logical cores
+	available. This setting and `checkout.thresholdForParallelism` affect
+	all commands that perform checkout. E.g. checkout, clone, reset,
+	sparse-checkout, etc.
++
+Note: Parallel checkout usually delivers better performance for repositories
+located on SSDs or over NFS. For repositories on spinning disks and/or machines
+with a small number of cores, the default sequential checkout often performs
+better. The size and compression level of a repository might also influence how
+well the parallel version performs.
+
+checkout.thresholdForParallelism::
+	When running parallel checkout with a small number of files, the cost
+	of subprocess spawning and inter-process communication might outweigh
+	the parallelization gains. This setting allows you to define the minimum
+	number of files for which parallel checkout should be attempted. The
+	default is 100.
diff --git a/Documentation/config/clean.adoc b/Documentation/config/clean.adoc
new file mode 100644
index 0000000000..c0188ead4e
--- /dev/null
+++ b/Documentation/config/clean.adoc
@@ -0,0 +1,3 @@
+clean.requireForce::
+	A boolean to make git-clean refuse to delete files unless -f
+	is given. Defaults to true.
diff --git a/Documentation/config/clone.adoc b/Documentation/config/clone.adoc
new file mode 100644
index 0000000000..0a10efd174
--- /dev/null
+++ b/Documentation/config/clone.adoc
@@ -0,0 +1,23 @@
+`clone.defaultRemoteName`::
+	The name of the remote to create when cloning a repository.  Defaults to
+	`origin`.
+ifdef::git-clone[]
+	It can be overridden by passing the `--origin` command-line
+	option.
+endif::[]
+ifndef::git-clone[]
+	It can be overridden by passing the `--origin` command-line
+	option to linkgit:git-clone[1].
+endif::[]
+
+`clone.rejectShallow`::
+	Reject cloning a repository if it is a shallow one; this can be overridden by
+	passing the `--reject-shallow` option on the command line.
+ifndef::git-clone[]
+	See linkgit:git-clone[1].
+endif::[]
+
+`clone.filterSubmodules`::
+	If a partial clone filter is provided (see `--filter` in
+	linkgit:git-rev-list[1]) and `--recurse-submodules` is used, also apply
+	the filter to submodules.
diff --git a/Documentation/config/color.adoc b/Documentation/config/color.adoc
new file mode 100644
index 0000000000..2f2275ac69
--- /dev/null
+++ b/Documentation/config/color.adoc
@@ -0,0 +1,206 @@
+color.advice::
+	A boolean to enable/disable color in hints (e.g. when a push
+	failed, see `advice.*` for a list).  May be set to `always`,
+	`false` (or `never`) or `auto` (or `true`), in which case colors
+	are used only when the error output goes to a terminal. If
+	unset, then the value of `color.ui` is used (`auto` by default).
+
+color.advice.hint::
+	Use customized color for hints.
+
+color.blame.highlightRecent::
+	Specify the line annotation color for `git blame --color-by-age`
+	depending upon the age of the line.
++
+This setting should be set to a comma-separated list of color and
+date settings, starting and ending with a color, the dates should be
+set from oldest to newest. The metadata will be colored with the
+specified colors if the line was introduced before the given
+timestamp, overwriting older timestamped colors.
++
+Instead of an absolute timestamp relative timestamps work as well,
+e.g. `2.weeks.ago` is valid to address anything older than 2 weeks.
++
+It defaults to `blue,12 month ago,white,1 month ago,red`, which
+colors everything older than one year blue, recent changes between
+one month and one year old are kept white, and lines introduced
+within the last month are colored red.
+
+color.blame.repeatedLines::
+	Use the specified color to colorize line annotations for
+	`git blame --color-lines`, if they come from the same commit as the
+	preceding line. Defaults to cyan.
+
+color.branch::
+	A boolean to enable/disable color in the output of
+	linkgit:git-branch[1]. May be set to `always`,
+	`false` (or `never`) or `auto` (or `true`), in which case colors are used
+	only when the output is to a terminal. If unset, then the
+	value of `color.ui` is used (`auto` by default).
+
+color.branch.<slot>::
+	Use customized color for branch coloration. `<slot>` is one of
+	`current` (the current branch), `local` (a local branch),
+	`remote` (a remote-tracking branch in refs/remotes/),
+	`upstream` (upstream tracking branch), `plain` (other
+	refs).
+
+color.diff::
+	Whether to use ANSI escape sequences to add color to patches.
+	If this is set to `always`, linkgit:git-diff[1],
+	linkgit:git-log[1], and linkgit:git-show[1] will use color
+	for all patches.  If it is set to `true` or `auto`, those
+	commands will only use color when output is to the terminal.
+	If unset, then the value of `color.ui` is used (`auto` by
+	default).
++
+This does not affect linkgit:git-format-patch[1] or the
+'git-diff-{asterisk}' plumbing commands.  Can be overridden on the
+command line with the `--color[=<when>]` option.
+
+color.diff.<slot>::
+	Use customized color for diff colorization.  `<slot>` specifies
+	which part of the patch to use the specified color, and is one
+	of `context` (context text - `plain` is a historical synonym),
+	`meta` (metainformation), `frag`
+	(hunk header), 'func' (function in hunk header), `old` (removed lines),
+	`new` (added lines), `commit` (commit headers), `whitespace`
+	(highlighting whitespace errors), `oldMoved` (deleted lines),
+	`newMoved` (added lines), `oldMovedDimmed`, `oldMovedAlternative`,
+	`oldMovedAlternativeDimmed`, `newMovedDimmed`, `newMovedAlternative`
+	`newMovedAlternativeDimmed` (See the '<mode>'
+	setting of '--color-moved' in linkgit:git-diff[1] for details),
+	`contextDimmed`, `oldDimmed`, `newDimmed`, `contextBold`,
+	`oldBold`, and `newBold` (see linkgit:git-range-diff[1] for details).
+
+color.decorate.<slot>::
+	Use customized color for 'git log --decorate' output.  `<slot>` is one
+	of `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local
+	branches, remote-tracking branches, tags, stash and HEAD, respectively
+	and `grafted` for grafted commits.
+
+color.grep::
+	When set to `always`, always highlight matches.  When `false` (or
+	`never`), never.  When set to `true` or `auto`, use color only
+	when the output is written to the terminal.  If unset, then the
+	value of `color.ui` is used (`auto` by default).
+
+color.grep.<slot>::
+	Use customized color for grep colorization.  `<slot>` specifies which
+	part of the line to use the specified color, and is one of
++
+--
+`context`;;
+	non-matching text in context lines (when using `-A`, `-B`, or `-C`)
+`filename`;;
+	filename prefix (when not using `-h`)
+`function`;;
+	function name lines (when using `-p`)
+`lineNumber`;;
+	line number prefix (when using `-n`)
+`column`;;
+	column number prefix (when using `--column`)
+`match`;;
+	matching text (same as setting `matchContext` and `matchSelected`)
+`matchContext`;;
+	matching text in context lines
+`matchSelected`;;
+	matching text in selected lines. Also, used to customize the following
+	linkgit:git-log[1] subcommands: `--grep`, `--author`, and `--committer`.
+`selected`;;
+	non-matching text in selected lines. Also, used to customize the
+	following linkgit:git-log[1] subcommands: `--grep`, `--author` and
+	`--committer`.
+`separator`;;
+	separators between fields on a line (`:`, `-`, and `=`)
+	and between hunks (`--`)
+--
+
+color.interactive::
+	When set to `always`, always use colors for interactive prompts
+	and displays (such as those used by "git-add --interactive" and
+	"git-clean --interactive"). When false (or `never`), never.
+	When set to `true` or `auto`, use colors only when the output is
+	to the terminal. If unset, then the value of `color.ui` is
+	used (`auto` by default).
+
+color.interactive.<slot>::
+	Use customized color for 'git add --interactive' and 'git clean
+	--interactive' output. `<slot>` may be `prompt`, `header`, `help`
+	or `error`, for four distinct types of normal output from
+	interactive commands.
+
+color.pager::
+	A boolean to specify whether `auto` color modes should colorize
+	output going to the pager. Defaults to true; set this to false
+	if your pager does not understand ANSI color codes.
+
+color.push::
+	A boolean to enable/disable color in push errors. May be set to
+	`always`, `false` (or `never`) or `auto` (or `true`), in which
+	case colors are used only when the error output goes to a terminal.
+	If unset, then the value of `color.ui` is used (`auto` by default).
+
+color.push.error::
+	Use customized color for push errors.
+
+color.remote::
+	If set, keywords at the start of the line are highlighted. The
+	keywords are "error", "warning", "hint" and "success", and are
+	matched case-insensitively. May be set to `always`, `false` (or
+	`never`) or `auto` (or `true`). If unset, then the value of
+	`color.ui` is used (`auto` by default).
+
+color.remote.<slot>::
+	Use customized color for each remote keyword. `<slot>` may be
+	`hint`, `warning`, `success` or `error` which match the
+	corresponding keyword.
+
+color.showBranch::
+	A boolean to enable/disable color in the output of
+	linkgit:git-show-branch[1]. May be set to `always`,
+	`false` (or `never`) or `auto` (or `true`), in which case colors are used
+	only when the output is to a terminal. If unset, then the
+	value of `color.ui` is used (`auto` by default).
+
+color.status::
+	A boolean to enable/disable color in the output of
+	linkgit:git-status[1]. May be set to `always`,
+	`false` (or `never`) or `auto` (or `true`), in which case colors are used
+	only when the output is to a terminal. If unset, then the
+	value of `color.ui` is used (`auto` by default).
+
+color.status.<slot>::
+	Use customized color for status colorization. `<slot>` is
+	one of `header` (the header text of the status message),
+	`added` or `updated` (files which are added but not committed),
+	`changed` (files which are changed but not added in the index),
+	`untracked` (files which are not tracked by Git),
+	`branch` (the current branch),
+	`nobranch` (the color the 'no branch' warning is shown in, defaulting
+	to red),
+	`localBranch` or `remoteBranch` (the local and remote branch names,
+	respectively, when branch and tracking information is displayed in the
+	status short-format), or
+	`unmerged` (files which have unmerged changes).
+
+color.transport::
+	A boolean to enable/disable color when pushes are rejected. May be
+	set to `always`, `false` (or `never`) or `auto` (or `true`), in which
+	case colors are used only when the error output goes to a terminal.
+	If unset, then the value of `color.ui` is used (`auto` by default).
+
+color.transport.rejected::
+	Use customized color when a push was rejected.
+
+color.ui::
+	This variable determines the default value for variables such
+	as `color.diff` and `color.grep` that control the use of color
+	per command family. Its scope will expand as more commands learn
+	configuration to set a default for the `--color` option.  Set it
+	to `false` or `never` if you prefer Git commands not to use
+	color unless enabled explicitly with some other configuration
+	or the `--color` option. Set it to `always` if you want all
+	output not intended for machine consumption to use color, to
+	`true` or `auto` (this is the default since Git 1.8.4) if you
+	want such output to use color when written to the terminal.
diff --git a/Documentation/config/column.adoc b/Documentation/config/column.adoc
new file mode 100644
index 0000000000..01e4198429
--- /dev/null
+++ b/Documentation/config/column.adoc
@@ -0,0 +1,55 @@
+column.ui::
+	Specify whether supported commands should output in columns.
+	This variable consists of a list of tokens separated by spaces
+	or commas:
++
+These options control when the feature should be enabled
+(defaults to 'never'):
++
+--
+`always`;;
+	always show in columns
+`never`;;
+	never show in columns
+`auto`;;
+	show in columns if the output is to the terminal
+--
++
+These options control layout (defaults to 'column').  Setting any
+of these implies 'always' if none of 'always', 'never', or 'auto' are
+specified.
++
+--
+`column`;;
+	fill columns before rows
+`row`;;
+	fill rows before columns
+`plain`;;
+	show in one column
+--
++
+Finally, these options can be combined with a layout option (defaults
+to 'nodense'):
++
+--
+`dense`;;
+	make unequal size columns to utilize more space
+`nodense`;;
+	make equal size columns
+--
+
+column.branch::
+	Specify whether to output branch listing in `git branch` in columns.
+	See `column.ui` for details.
+
+column.clean::
+	Specify the layout when listing items in `git clean -i`, which always
+	shows files and directories in columns. See `column.ui` for details.
+
+column.status::
+	Specify whether to output untracked files in `git status` in columns.
+	See `column.ui` for details.
+
+column.tag::
+	Specify whether to output tag listings in `git tag` in columns.
+	See `column.ui` for details.
diff --git a/Documentation/config/commit.adoc b/Documentation/config/commit.adoc
new file mode 100644
index 0000000000..d3f4624fd2
--- /dev/null
+++ b/Documentation/config/commit.adoc
@@ -0,0 +1,34 @@
+ifdef::git-commit[]
+:see-git-commit:
+endif::git-commit[]
+ifndef::git-commit[]
+:see-git-commit: See linkgit:git-commit[1] for details.
+endif::git-commit[]
+`commit.cleanup`::
+	This setting overrides the default of the `--cleanup` option in
+	`git commit`. {see-git-commit} Changing the default can be useful
+	when you always want to keep lines that begin
+	with the comment character `#` in your log message, in which case you
+	would do `git config commit.cleanup whitespace` (note that you will
+	have to remove the help lines that begin with `#` in the commit log
+	template yourself, if you do this).
+
+`commit.gpgSign`::
+	A boolean to specify whether all commits should be GPG signed.
+	Use of this option when doing operations such as rebase can
+	result in a large number of commits being signed. It may be
+	convenient to use an agent to avoid typing your GPG passphrase
+	several times.
+
+`commit.status`::
+	A boolean to enable/disable inclusion of status information in the
+	commit message template when using an editor to prepare the commit
+	message.  Defaults to `true`.
+
+`commit.template`::
+	Specify the pathname of a file to use as the template for
+	new commit messages.
+
+`commit.verbose`::
+	A boolean or int to specify the level of verbosity with `git commit`.
+	{see-git-commit}
diff --git a/Documentation/config/commitgraph.adoc b/Documentation/config/commitgraph.adoc
new file mode 100644
index 0000000000..7f8c9d6638
--- /dev/null
+++ b/Documentation/config/commitgraph.adoc
@@ -0,0 +1,37 @@
+commitGraph.generationVersion::
+	Specifies the type of generation number version to use when writing
+	or reading the commit-graph file. If version 1 is specified, then
+	the corrected commit dates will not be written or read. Defaults to
+	2.
+
+commitGraph.maxNewFilters::
+	Specifies the default value for the `--max-new-filters` option of `git
+	commit-graph write` (c.f., linkgit:git-commit-graph[1]).
+
+commitGraph.readChangedPaths::
+	Deprecated. Equivalent to commitGraph.changedPathsVersion=-1 if true, and
+	commitGraph.changedPathsVersion=0 if false. (If commitGraph.changedPathVersion
+	is also set, commitGraph.changedPathsVersion takes precedence.)
+
+commitGraph.changedPathsVersion::
+	Specifies the version of the changed-path Bloom filters that Git will read and
+	write. May be -1, 0, 1, or 2. Note that values greater than 1 may be
+	incompatible with older versions of Git which do not yet understand
+	those versions. Use caution when operating in a mixed-version
+	environment.
++
+Defaults to -1.
++
+If -1, Git will use the version of the changed-path Bloom filters in the
+repository, defaulting to 1 if there are none.
++
+If 0, Git will not read any Bloom filters, and will write version 1 Bloom
+filters when instructed to write.
++
+If 1, Git will only read version 1 Bloom filters, and will write version 1
+Bloom filters.
++
+If 2, Git will only read version 2 Bloom filters, and will write version 2
+Bloom filters.
++
+See linkgit:git-commit-graph[1] for more information.
diff --git a/Documentation/config/completion.adoc b/Documentation/config/completion.adoc
new file mode 100644
index 0000000000..4d99bf33c9
--- /dev/null
+++ b/Documentation/config/completion.adoc
@@ -0,0 +1,7 @@
+completion.commands::
+	This is only used by git-completion.bash to add or remove
+	commands from the list of completed commands. Normally only
+	porcelain commands and a few select others are completed. You
+	can add more commands, separated by space, in this
+	variable. Prefixing the command with '-' will remove it from
+	the existing list.
diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc
new file mode 100644
index 0000000000..8f6d8e7754
--- /dev/null
+++ b/Documentation/config/core.adoc
@@ -0,0 +1,760 @@
+core.fileMode::
+	Tells Git if the executable bit of files in the working tree
+	is to be honored.
++
+Some filesystems lose the executable bit when a file that is
+marked as executable is checked out, or checks out a
+non-executable file with executable bit on.
+linkgit:git-clone[1] or linkgit:git-init[1] probe the filesystem
+to see if it handles the executable bit correctly
+and this variable is automatically set as necessary.
++
+A repository, however, may be on a filesystem that handles
+the filemode correctly, and this variable is set to 'true'
+when created, but later may be made accessible from another
+environment that loses the filemode (e.g. exporting ext4 via
+CIFS mount, visiting a Cygwin created repository with
+Git for Windows or Eclipse).
+In such a case it may be necessary to set this variable to 'false'.
+See linkgit:git-update-index[1].
++
+The default is true (when core.filemode is not specified in the config file).
+
+core.hideDotFiles::
+	(Windows-only) If true, mark newly-created directories and files whose
+	name starts with a dot as hidden.  If 'dotGitOnly', only the `.git/`
+	directory is hidden, but no other files starting with a dot.  The
+	default mode is 'dotGitOnly'.
+
+core.ignoreCase::
+	Internal variable which enables various workarounds to enable
+	Git to work better on filesystems that are not case sensitive,
+	like APFS, HFS+, FAT, NTFS, etc. For example, if a directory listing
+	finds "makefile" when Git expects "Makefile", Git will assume
+	it is really the same file, and continue to remember it as
+	"Makefile".
++
+The default is false, except linkgit:git-clone[1] or linkgit:git-init[1]
+will probe and set core.ignoreCase true if appropriate when the repository
+is created.
++
+Git relies on the proper configuration of this variable for your operating
+and file system. Modifying this value may result in unexpected behavior.
+
+core.precomposeUnicode::
+	This option is only used by Mac OS implementation of Git.
+	When core.precomposeUnicode=true, Git reverts the unicode decomposition
+	of filenames done by Mac OS. This is useful when sharing a repository
+	between Mac OS and Linux or Windows.
+	(Git for Windows 1.7.10 or higher is needed, or Git under cygwin 1.7).
+	When false, file names are handled fully transparent by Git,
+	which is backward compatible with older versions of Git.
+
+core.protectHFS::
+	If set to true, do not allow checkout of paths that would
+	be considered equivalent to `.git` on an HFS+ filesystem.
+	Defaults to `true` on Mac OS, and `false` elsewhere.
+
+core.protectNTFS::
+	If set to true, do not allow checkout of paths that would
+	cause problems with the NTFS filesystem, e.g. conflict with
+	8.3 "short" names.
+	Defaults to `true` on Windows, and `false` elsewhere.
+
+core.fsmonitor::
+	If set to true, enable the built-in file system monitor
+	daemon for this working directory (linkgit:git-fsmonitor{litdd}daemon[1]).
++
+Like hook-based file system monitors, the built-in file system monitor
+can speed up Git commands that need to refresh the Git index
+(e.g. `git status`) in a working directory with many files.  The
+built-in monitor eliminates the need to install and maintain an
+external third-party tool.
++
+The built-in file system monitor is currently available only on a
+limited set of supported platforms.  Currently, this includes Windows
+and MacOS.
++
+	Otherwise, this variable contains the pathname of the "fsmonitor"
+	hook command.
++
+This hook command is used to identify all files that may have changed
+since the requested date/time. This information is used to speed up
+git by avoiding unnecessary scanning of files that have not changed.
++
+See the "fsmonitor-watchman" section of linkgit:githooks[5].
++
+Note that if you concurrently use multiple versions of Git, such
+as one version on the command line and another version in an IDE
+tool, that the definition of `core.fsmonitor` was extended to
+allow boolean values in addition to hook pathnames.  Git versions
+2.35.1 and prior will not understand the boolean values and will
+consider the "true" or "false" values as hook pathnames to be
+invoked.  Git versions 2.26 thru 2.35.1 default to hook protocol
+V2 and will fall back to no fsmonitor (full scan).  Git versions
+prior to 2.26 default to hook protocol V1 and will silently
+assume there were no changes to report (no scan), so status
+commands may report incomplete results.  For this reason, it is
+best to upgrade all of your Git versions before using the built-in
+file system monitor.
+
+core.fsmonitorHookVersion::
+	Sets the protocol version to be used when invoking the
+	"fsmonitor" hook.
++
+There are currently versions 1 and 2. When this is not set,
+version 2 will be tried first and if it fails then version 1
+will be tried. Version 1 uses a timestamp as input to determine
+which files have changes since that time but some monitors
+like Watchman have race conditions when used with a timestamp.
+Version 2 uses an opaque string so that the monitor can return
+something that can be used to determine what files have changed
+without race conditions.
+
+core.trustctime::
+	If false, the ctime differences between the index and the
+	working tree are ignored; useful when the inode change time
+	is regularly modified by something outside Git (file system
+	crawlers and some backup systems).
+	See linkgit:git-update-index[1]. True by default.
+
+core.splitIndex::
+	If true, the split-index feature of the index will be used.
+	See linkgit:git-update-index[1]. False by default.
+
+core.untrackedCache::
+	Determines what to do about the untracked cache feature of the
+	index. It will be kept, if this variable is unset or set to
+	`keep`. It will automatically be added if set to `true`. And
+	it will automatically be removed, if set to `false`. Before
+	setting it to `true`, you should check that mtime is working
+	properly on your system.
+	See linkgit:git-update-index[1]. `keep` by default, unless
+	`feature.manyFiles` is enabled which sets this setting to
+	`true` by default.
+
+core.checkStat::
+	When missing or is set to `default`, many fields in the stat
+	structure are checked to detect if a file has been modified
+	since Git looked at it.  When this configuration variable is
+	set to `minimal`, sub-second part of mtime and ctime, the
+	uid and gid of the owner of the file, the inode number (and
+	the device number, if Git was compiled to use it), are
+	excluded from the check among these fields, leaving only the
+	whole-second part of mtime (and ctime, if `core.trustCtime`
+	is set) and the filesize to be checked.
++
+There are implementations of Git that do not leave usable values in
+some fields (e.g. JGit); by excluding these fields from the
+comparison, the `minimal` mode may help interoperability when the
+same repository is used by these other systems at the same time.
+
+core.quotePath::
+	Commands that output paths (e.g. 'ls-files', 'diff'), will
+	quote "unusual" characters in the pathname by enclosing the
+	pathname in double-quotes and escaping those characters with
+	backslashes in the same way C escapes control characters (e.g.
+	`\t` for TAB, `\n` for LF, `\\` for backslash) or bytes with
+	values larger than 0x80 (e.g. octal `\302\265` for "micro" in
+	UTF-8).  If this variable is set to false, bytes higher than
+	0x80 are not considered "unusual" any more. Double-quotes,
+	backslash and control characters are always escaped regardless
+	of the setting of this variable.  A simple space character is
+	not considered "unusual".  Many commands can output pathnames
+	completely verbatim using the `-z` option. The default value
+	is true.
+
+core.eol::
+	Sets the line ending type to use in the working directory for
+	files that are marked as text (either by having the `text`
+	attribute set, or by having `text=auto` and Git auto-detecting
+	the contents as text).
+	Alternatives are 'lf', 'crlf' and 'native', which uses the platform's
+	native line ending.  The default value is `native`.  See
+	linkgit:gitattributes[5] for more information on end-of-line
+	conversion. Note that this value is ignored if `core.autocrlf`
+	is set to `true` or `input`.
+
+core.safecrlf::
+	If true, makes Git check if converting `CRLF` is reversible when
+	end-of-line conversion is active.  Git will verify if a command
+	modifies a file in the work tree either directly or indirectly.
+	For example, committing a file followed by checking out the
+	same file should yield the original file in the work tree.  If
+	this is not the case for the current setting of
+	`core.autocrlf`, Git will reject the file.  The variable can
+	be set to "warn", in which case Git will only warn about an
+	irreversible conversion but continue the operation.
++
+CRLF conversion bears a slight chance of corrupting data.
+When it is enabled, Git will convert CRLF to LF during commit and LF to
+CRLF during checkout.  A file that contains a mixture of LF and
+CRLF before the commit cannot be recreated by Git.  For text
+files this is the right thing to do: it corrects line endings
+such that we have only LF line endings in the repository.
+But for binary files that are accidentally classified as text the
+conversion can corrupt data.
++
+If you recognize such corruption early you can easily fix it by
+setting the conversion type explicitly in .gitattributes.  Right
+after committing you still have the original file in your work
+tree and this file is not yet corrupted.  You can explicitly tell
+Git that this file is binary and Git will handle the file
+appropriately.
++
+Unfortunately, the desired effect of cleaning up text files with
+mixed line endings and the undesired effect of corrupting binary
+files cannot be distinguished.  In both cases CRLFs are removed
+in an irreversible way.  For text files this is the right thing
+to do because CRLFs are line endings, while for binary files
+converting CRLFs corrupts data.
++
+Note, this safety check does not mean that a checkout will generate a
+file identical to the original file for a different setting of
+`core.eol` and `core.autocrlf`, but only for the current one.  For
+example, a text file with `LF` would be accepted with `core.eol=lf`
+and could later be checked out with `core.eol=crlf`, in which case the
+resulting file would contain `CRLF`, although the original file
+contained `LF`.  However, in both work trees the line endings would be
+consistent, that is either all `LF` or all `CRLF`, but never mixed.  A
+file with mixed line endings would be reported by the `core.safecrlf`
+mechanism.
+
+core.autocrlf::
+	Setting this variable to "true" is the same as setting
+	the `text` attribute to "auto" on all files and core.eol to "crlf".
+	Set to true if you want to have `CRLF` line endings in your
+	working directory and the repository has LF line endings.
+	This variable can be set to 'input',
+	in which case no output conversion is performed.
+
+core.checkRoundtripEncoding::
+	A comma and/or whitespace separated list of encodings that Git
+	performs UTF-8 round trip checks on if they are used in an
+	`working-tree-encoding` attribute (see linkgit:gitattributes[5]).
+	The default value is `SHIFT-JIS`.
+
+core.symlinks::
+	If false, symbolic links are checked out as small plain files that
+	contain the link text. linkgit:git-update-index[1] and
+	linkgit:git-add[1] will not change the recorded type to regular
+	file. Useful on filesystems like FAT that do not support
+	symbolic links.
++
+The default is true, except linkgit:git-clone[1] or linkgit:git-init[1]
+will probe and set core.symlinks false if appropriate when the repository
+is created.
+
+core.gitProxy::
+	A "proxy command" to execute (as 'command host port') instead
+	of establishing direct connection to the remote server when
+	using the Git protocol for fetching. If the variable value is
+	in the "COMMAND for DOMAIN" format, the command is applied only
+	on hostnames ending with the specified domain string. This variable
+	may be set multiple times and is matched in the given order;
+	the first match wins.
++
+Can be overridden by the `GIT_PROXY_COMMAND` environment variable
+(which always applies universally, without the special "for"
+handling).
++
+The special string `none` can be used as the proxy command to
+specify that no proxy be used for a given domain pattern.
+This is useful for excluding servers inside a firewall from
+proxy use, while defaulting to a common proxy for external domains.
+
+core.sshCommand::
+	If this variable is set, `git fetch` and `git push` will
+	use the specified command instead of `ssh` when they need to
+	connect to a remote system. The command is in the same form as
+	the `GIT_SSH_COMMAND` environment variable and is overridden
+	when the environment variable is set.
+
+core.ignoreStat::
+	If true, Git will avoid using lstat() calls to detect if files have
+	changed by setting the "assume-unchanged" bit for those tracked files
+	which it has updated identically in both the index and working tree.
++
+When files are modified outside of Git, the user will need to stage
+the modified files explicitly (e.g. see 'Examples' section in
+linkgit:git-update-index[1]).
+Git will not normally detect changes to those files.
++
+This is useful on systems where lstat() calls are very slow, such as
+CIFS/Microsoft Windows.
++
+False by default.
+
+core.preferSymlinkRefs::
+	Instead of the default "symref" format for HEAD
+	and other symbolic reference files, use symbolic links.
+	This is sometimes needed to work with old scripts that
+	expect HEAD to be a symbolic link.
+
+core.alternateRefsCommand::
+	When advertising tips of available history from an alternate, use the shell to
+	execute the specified command instead of linkgit:git-for-each-ref[1]. The
+	first argument is the absolute path of the alternate. Output must contain one
+	hex object id per line (i.e., the same as produced by `git for-each-ref
+	--format='%(objectname)'`).
++
+Note that you cannot generally put `git for-each-ref` directly into the config
+value, as it does not take a repository path as an argument (but you can wrap
+the command above in a shell script).
+
+core.alternateRefsPrefixes::
+	When listing references from an alternate, list only references that begin
+	with the given prefix. Prefixes match as if they were given as arguments to
+	linkgit:git-for-each-ref[1]. To list multiple prefixes, separate them with
+	whitespace. If `core.alternateRefsCommand` is set, setting
+	`core.alternateRefsPrefixes` has no effect.
+
+core.bare::
+	If true this repository is assumed to be 'bare' and has no
+	working directory associated with it.  If this is the case a
+	number of commands that require a working directory will be
+	disabled, such as linkgit:git-add[1] or linkgit:git-merge[1].
++
+This setting is automatically guessed by linkgit:git-clone[1] or
+linkgit:git-init[1] when the repository was created.  By default a
+repository that ends in "/.git" is assumed to be not bare (bare =
+false), while all other repositories are assumed to be bare (bare
+= true).
+
+core.worktree::
+	Set the path to the root of the working tree.
+	If `GIT_COMMON_DIR` environment variable is set, core.worktree
+	is ignored and not used for determining the root of working tree.
+	This can be overridden by the `GIT_WORK_TREE` environment
+	variable and the `--work-tree` command-line option.
+	The value can be an absolute path or relative to the path to
+	the .git directory, which is either specified by --git-dir
+	or GIT_DIR, or automatically discovered.
+	If --git-dir or GIT_DIR is specified but none of
+	--work-tree, GIT_WORK_TREE and core.worktree is specified,
+	the current working directory is regarded as the top level
+	of your working tree.
++
+Note that this variable is honored even when set in a configuration
+file in a ".git" subdirectory of a directory and its value differs
+from the latter directory (e.g. "/path/to/.git/config" has
+core.worktree set to "/different/path"), which is most likely a
+misconfiguration.  Running Git commands in the "/path/to" directory will
+still use "/different/path" as the root of the work tree and can cause
+confusion unless you know what you are doing (e.g. you are creating a
+read-only snapshot of the same index to a location different from the
+repository's usual working tree).
+
+core.logAllRefUpdates::
+	Enable the reflog. Updates to a ref <ref> is logged to the file
+	"`$GIT_DIR/logs/<ref>`", by appending the new and old
+	SHA-1, the date/time and the reason of the update, but
+	only when the file exists.  If this configuration
+	variable is set to `true`, missing "`$GIT_DIR/logs/<ref>`"
+	file is automatically created for branch heads (i.e. under
+	`refs/heads/`), remote refs (i.e. under `refs/remotes/`),
+	note refs (i.e. under `refs/notes/`), and the symbolic ref `HEAD`.
+	If it is set to `always`, then a missing reflog is automatically
+	created for any ref under `refs/`.
++
+This information can be used to determine what commit
+was the tip of a branch "2 days ago".
++
+This value is true by default in a repository that has
+a working directory associated with it, and false by
+default in a bare repository.
+
+core.repositoryFormatVersion::
+	Internal variable identifying the repository format and layout
+	version. See linkgit:gitrepository-layout[5].
+
+core.sharedRepository::
+	When 'group' (or 'true'), the repository is made shareable between
+	several users in a group (making sure all the files and objects are
+	group-writable). When 'all' (or 'world' or 'everybody'), the
+	repository will be readable by all users, additionally to being
+	group-shareable. When 'umask' (or 'false'), Git will use permissions
+	reported by umask(2). When '0xxx', where '0xxx' is an octal number,
+	files in the repository will have this mode value. '0xxx' will override
+	user's umask value (whereas the other options will only override
+	requested parts of the user's umask value). Examples: '0660' will make
+	the repo read/write-able for the owner and group, but inaccessible to
+	others (equivalent to 'group' unless umask is e.g. '0022'). '0640' is a
+	repository that is group-readable but not group-writable.
+	See linkgit:git-init[1]. False by default.
+
+core.warnAmbiguousRefs::
+	If true, Git will warn you if the ref name you passed it is ambiguous
+	and might match multiple refs in the repository. True by default.
+
+core.compression::
+	An integer -1..9, indicating a default compression level.
+	-1 is the zlib default. 0 means no compression,
+	and 1..9 are various speed/size tradeoffs, 9 being slowest.
+	If set, this provides a default to other compression variables,
+	such as `core.looseCompression` and `pack.compression`.
+
+core.looseCompression::
+	An integer -1..9, indicating the compression level for objects that
+	are not in a pack file. -1 is the zlib default. 0 means no
+	compression, and 1..9 are various speed/size tradeoffs, 9 being
+	slowest.  If not set,  defaults to core.compression.  If that is
+	not set,  defaults to 1 (best speed).
+
+core.packedGitWindowSize::
+	Number of bytes of a pack file to map into memory in a
+	single mapping operation.  Larger window sizes may allow
+	your system to process a smaller number of large pack files
+	more quickly.  Smaller window sizes will negatively affect
+	performance due to increased calls to the operating system's
+	memory manager, but may improve performance when accessing
+	a large number of large pack files.
++
+Default is 1 MiB if NO_MMAP was set at compile time, otherwise 32
+MiB on 32 bit platforms and 1 GiB on 64 bit platforms.  This should
+be reasonable for all users/operating systems.  You probably do
+not need to adjust this value.
++
+Common unit suffixes of 'k', 'm', or 'g' are supported.
+
+core.packedGitLimit::
+	Maximum number of bytes to map simultaneously into memory
+	from pack files.  If Git needs to access more than this many
+	bytes at once to complete an operation it will unmap existing
+	regions to reclaim virtual address space within the process.
++
+Default is 256 MiB on 32 bit platforms and 32 TiB (effectively
+unlimited) on 64 bit platforms.
+This should be reasonable for all users/operating systems, except on
+the largest projects.  You probably do not need to adjust this value.
++
+Common unit suffixes of 'k', 'm', or 'g' are supported.
+
+core.deltaBaseCacheLimit::
+	Maximum number of bytes per thread to reserve for caching base objects
+	that may be referenced by multiple deltified objects.  By storing the
+	entire decompressed base objects in a cache Git is able
+	to avoid unpacking and decompressing frequently used base
+	objects multiple times.
++
+Default is 96 MiB on all platforms.  This should be reasonable
+for all users/operating systems, except on the largest projects.
+You probably do not need to adjust this value.
++
+Common unit suffixes of 'k', 'm', or 'g' are supported.
+
+core.bigFileThreshold::
+	The size of files considered "big", which as discussed below
+	changes the behavior of numerous git commands, as well as how
+	such files are stored within the repository. The default is
+	512 MiB. Common unit suffixes of 'k', 'm', or 'g' are
+	supported.
++
+Files above the configured limit will be:
++
+* Stored deflated in packfiles, without attempting delta compression.
++
+The default limit is primarily set with this use-case in mind. With it,
+most projects will have their source code and other text files delta
+compressed, but not larger binary media files.
++
+Storing large files without delta compression avoids excessive memory
+usage, at the slight expense of increased disk usage.
++
+* Will be treated as if they were labeled "binary" (see
+  linkgit:gitattributes[5]). e.g. linkgit:git-log[1] and
+  linkgit:git-diff[1] will not compute diffs for files above this limit.
++
+* Will generally be streamed when written, which avoids excessive
+memory usage, at the cost of some fixed overhead. Commands that make
+use of this include linkgit:git-archive[1],
+linkgit:git-fast-import[1], linkgit:git-index-pack[1],
+linkgit:git-unpack-objects[1] and linkgit:git-fsck[1].
+
+core.excludesFile::
+	Specifies the pathname to the file that contains patterns to
+	describe paths that are not meant to be tracked, in addition
+	to `.gitignore` (per-directory) and `.git/info/exclude`.
+	Defaults to `$XDG_CONFIG_HOME/git/ignore`.
+	If `$XDG_CONFIG_HOME` is either not set or empty, `$HOME/.config/git/ignore`
+	is used instead. See linkgit:gitignore[5].
+
+core.askPass::
+	Some commands (e.g. svn and http interfaces) that interactively
+	ask for a password can be told to use an external program given
+	via the value of this variable. Can be overridden by the `GIT_ASKPASS`
+	environment variable. If not set, fall back to the value of the
+	`SSH_ASKPASS` environment variable or, failing that, a simple password
+	prompt. The external program shall be given a suitable prompt as
+	command-line argument and write the password on its STDOUT.
+
+core.attributesFile::
+	In addition to `.gitattributes` (per-directory) and
+	`.git/info/attributes`, Git looks into this file for attributes
+	(see linkgit:gitattributes[5]). Path expansions are made the same
+	way as for `core.excludesFile`. Its default value is
+	`$XDG_CONFIG_HOME/git/attributes`. If `$XDG_CONFIG_HOME` is either not
+	set or empty, `$HOME/.config/git/attributes` is used instead.
+
+core.hooksPath::
+	By default Git will look for your hooks in the
+	`$GIT_DIR/hooks` directory. Set this to different path,
+	e.g. `/etc/git/hooks`, and Git will try to find your hooks in
+	that directory, e.g. `/etc/git/hooks/pre-receive` instead of
+	in `$GIT_DIR/hooks/pre-receive`.
++
+The path can be either absolute or relative. A relative path is
+taken as relative to the directory where the hooks are run (see
+the "DESCRIPTION" section of linkgit:githooks[5]).
++
+This configuration variable is useful in cases where you'd like to
+centrally configure your Git hooks instead of configuring them on a
+per-repository basis, or as a more flexible and centralized
+alternative to having an `init.templateDir` where you've changed
+default hooks.
+
+core.editor::
+	Commands such as `commit` and `tag` that let you edit
+	messages by launching an editor use the value of this
+	variable when it is set, and the environment variable
+	`GIT_EDITOR` is not set.  See linkgit:git-var[1].
+
+core.commentChar::
+core.commentString::
+	Commands such as `commit` and `tag` that let you edit
+	messages consider a line that begins with this character
+	commented, and removes them after the editor returns
+	(default '#').
++
+If set to "auto", `git-commit` would select a character that is not
+the beginning character of any line in existing commit messages.
++
+Note that these two variables are aliases of each other, and in modern
+versions of Git you are free to use a string (e.g., `//` or `⁑⁕⁑`) with
+`commentChar`. Versions of Git prior to v2.45.0 will ignore
+`commentString` but will reject a value of `commentChar` that consists
+of more than a single ASCII byte. If you plan to use your config with
+older and newer versions of Git, you may want to specify both:
++
+    [core]
+    # single character for older versions
+    commentChar = "#"
+    # string for newer versions (which will override commentChar
+    # because it comes later in the file)
+    commentString = "//"
+
+core.filesRefLockTimeout::
+	The length of time, in milliseconds, to retry when trying to
+	lock an individual reference. Value 0 means not to retry at
+	all; -1 means to try indefinitely. Default is 100 (i.e.,
+	retry for 100ms).
+
+core.packedRefsTimeout::
+	The length of time, in milliseconds, to retry when trying to
+	lock the `packed-refs` file. Value 0 means not to retry at
+	all; -1 means to try indefinitely. Default is 1000 (i.e.,
+	retry for 1 second).
+
+core.pager::
+	Text viewer for use by Git commands (e.g., 'less').  The value
+	is meant to be interpreted by the shell.  The order of preference
+	is the `$GIT_PAGER` environment variable, then `core.pager`
+	configuration, then `$PAGER`, and then the default chosen at
+	compile time (usually 'less').
++
+When the `LESS` environment variable is unset, Git sets it to `FRX`
+(if `LESS` environment variable is set, Git does not change it at
+all).  If you want to selectively override Git's default setting
+for `LESS`, you can set `core.pager` to e.g. `less -S`.  This will
+be passed to the shell by Git, which will translate the final
+command to `LESS=FRX less -S`. The environment does not set the
+`S` option but the command line does, instructing less to truncate
+long lines. Similarly, setting `core.pager` to `less -+F` will
+deactivate the `F` option specified by the environment from the
+command-line, deactivating the "quit if one screen" behavior of
+`less`.  One can specifically activate some flags for particular
+commands: for example, setting `pager.blame` to `less -S` enables
+line truncation only for `git blame`.
++
+Likewise, when the `LV` environment variable is unset, Git sets it
+to `-c`.  You can override this setting by exporting `LV` with
+another value or setting `core.pager` to `lv +c`.
+
+core.whitespace::
+	A comma separated list of common whitespace problems to
+	notice.  'git diff' will use `color.diff.whitespace` to
+	highlight them, and 'git apply --whitespace=error' will
+	consider them as errors.  You can prefix `-` to disable
+	any of them (e.g. `-trailing-space`):
++
+* `blank-at-eol` treats trailing whitespaces at the end of the line
+  as an error (enabled by default).
+* `space-before-tab` treats a space character that appears immediately
+  before a tab character in the initial indent part of the line as an
+  error (enabled by default).
+* `indent-with-non-tab` treats a line that is indented with space
+  characters instead of the equivalent tabs as an error (not enabled by
+  default).
+* `tab-in-indent` treats a tab character in the initial indent part of
+  the line as an error (not enabled by default).
+* `blank-at-eof` treats blank lines added at the end of file as an error
+  (enabled by default).
+* `trailing-space` is a short-hand to cover both `blank-at-eol` and
+  `blank-at-eof`.
+* `cr-at-eol` treats a carriage-return at the end of line as
+  part of the line terminator, i.e. with it, `trailing-space`
+  does not trigger if the character before such a carriage-return
+  is not a whitespace (not enabled by default).
+* `tabwidth=<n>` tells how many character positions a tab occupies; this
+  is relevant for `indent-with-non-tab` and when Git fixes `tab-in-indent`
+  errors. The default tab width is 8. Allowed values are 1 to 63.
+
+core.fsync::
+	A comma-separated list of components of the repository that
+	should be hardened via the core.fsyncMethod when created or
+	modified.  You can disable hardening of any component by
+	prefixing it with a '-'.  Items that are not hardened may be
+	lost in the event of an unclean	system shutdown. Unless you
+	have special requirements, it is recommended that you leave
+	this option empty or pick one of `committed`, `added`,
+	or `all`.
++
+When this configuration is encountered, the set of components starts with
+the platform default value, disabled components are removed, and additional
+components are added. `none` resets the state so that the platform default
+is ignored.
++
+The empty string resets the fsync configuration to the platform
+default. The default on most platforms is equivalent to
+`core.fsync=committed,-loose-object`, which has good performance,
+but risks losing recent work in the event of an unclean system shutdown.
++
+* `none` clears the set of fsynced components.
+* `loose-object` hardens objects added to the repo in loose-object form.
+* `pack` hardens objects added to the repo in packfile form.
+* `pack-metadata` hardens packfile bitmaps and indexes.
+* `commit-graph` hardens the commit-graph file.
+* `index` hardens the index when it is modified.
+* `objects` is an aggregate option that is equivalent to
+  `loose-object,pack`.
+* `reference` hardens references modified in the repo.
+* `derived-metadata` is an aggregate option that is equivalent to
+  `pack-metadata,commit-graph`.
+* `committed` is an aggregate option that is currently equivalent to
+  `objects`. This mode sacrifices some performance to ensure that work
+  that is committed to the repository with `git commit` or similar commands
+  is hardened.
+* `added` is an aggregate option that is currently equivalent to
+  `committed,index`. This mode sacrifices additional performance to
+  ensure that the results of commands like `git add` and similar operations
+  are hardened.
+* `all` is an aggregate option that syncs all individual components above.
+
+core.fsyncMethod::
+	A value indicating the strategy Git will use to harden repository data
+	using fsync and related primitives.
++
+* `fsync` uses the fsync() system call or platform equivalents.
+* `writeout-only` issues pagecache writeback requests, but depending on the
+  filesystem and storage hardware, data added to the repository may not be
+  durable in the event of a system crash. This is the default mode on macOS.
+* `batch` enables a mode that uses writeout-only flushes to stage multiple
+  updates in the disk writeback cache and then does a single full fsync of
+  a dummy file to trigger the disk cache flush at the end of the operation.
++
+Currently `batch` mode only applies to loose-object files. Other repository
+data is made durable as if `fsync` was specified. This mode is expected to
+be as safe as `fsync` on macOS for repos stored on HFS+ or APFS filesystems
+and on Windows for repos stored on NTFS or ReFS filesystems.
+
+core.fsyncObjectFiles::
+	This boolean will enable 'fsync()' when writing object files.
+	This setting is deprecated. Use core.fsync instead.
++
+This setting affects data added to the Git repository in loose-object
+form. When set to true, Git will issue an fsync or similar system call
+to flush caches so that loose-objects remain consistent in the face
+of a unclean system shutdown.
+
+core.preloadIndex::
+	Enable parallel index preload for operations like 'git diff'
++
+This can speed up operations like 'git diff' and 'git status' especially
+on filesystems like NFS that have weak caching semantics and thus
+relatively high IO latencies.  When enabled, Git will do the
+index comparison to the filesystem data in parallel, allowing
+overlapping IO's.  Defaults to true.
+
+core.unsetenvvars::
+	Windows-only: comma-separated list of environment variables'
+	names that need to be unset before spawning any other process.
+	Defaults to `PERL5LIB` to account for the fact that Git for
+	Windows insists on using its own Perl interpreter.
+
+core.restrictinheritedhandles::
+	Windows-only: override whether spawned processes inherit only standard
+	file handles (`stdin`, `stdout` and `stderr`) or all handles. Can be
+	`auto`, `true` or `false`. Defaults to `auto`, which means `true` on
+	Windows 7 and later, and `false` on older Windows versions.
+
+core.createObject::
+	You can set this to 'link', in which case a hardlink followed by
+	a delete of the source are used to make sure that object creation
+	will not overwrite existing objects.
++
+On some file system/operating system combinations, this is unreliable.
+Set this config setting to 'rename' there; however, this will remove the
+check that makes sure that existing object files will not get overwritten.
+
+core.notesRef::
+	When showing commit messages, also show notes which are stored in
+	the given ref.  The ref must be fully qualified.  If the given
+	ref does not exist, it is not an error but means that no
+	notes should be printed.
++
+This setting defaults to "refs/notes/commits", and it can be overridden by
+the `GIT_NOTES_REF` environment variable.  See linkgit:git-notes[1].
+
+core.commitGraph::
+	If true, then git will read the commit-graph file (if it exists)
+	to parse the graph structure of commits. Defaults to true. See
+	linkgit:git-commit-graph[1] for more information.
+
+core.useReplaceRefs::
+	If set to `false`, behave as if the `--no-replace-objects`
+	option was given on the command line. See linkgit:git[1] and
+	linkgit:git-replace[1] for more information.
+
+core.multiPackIndex::
+	Use the multi-pack-index file to track multiple packfiles using a
+	single index. See linkgit:git-multi-pack-index[1] for more
+	information. Defaults to true.
+
+core.sparseCheckout::
+	Enable "sparse checkout" feature. See linkgit:git-sparse-checkout[1]
+	for more information.
+
+core.sparseCheckoutCone::
+	Enables the "cone mode" of the sparse checkout feature. When the
+	sparse-checkout file contains a limited set of patterns, this
+	mode provides significant performance advantages. The "non-cone
+	mode" can be requested to allow specifying more flexible
+	patterns by setting this variable to 'false'. See
+	linkgit:git-sparse-checkout[1] for more information.
+
+core.abbrev::
+	Set the length object names are abbreviated to.  If
+	unspecified or set to "auto", an appropriate value is
+	computed based on the approximate number of packed objects
+	in your repository, which hopefully is enough for
+	abbreviated object names to stay unique for some time.
+	If set to "no", no abbreviation is made and the object names
+	are shown in their full length.
+	The minimum length is 4.
+
+core.maxTreeDepth::
+	The maximum depth Git is willing to recurse while traversing a
+	tree (e.g., "a/b/cde/f" has a depth of 4). This is a fail-safe
+	to allow Git to abort cleanly, and should not generally need to
+	be adjusted. When Git is compiled with MSVC, the default is 512.
+	Otherwise, the default is 2048.
diff --git a/Documentation/config/credential.adoc b/Documentation/config/credential.adoc
new file mode 100644
index 0000000000..80a7c77772
--- /dev/null
+++ b/Documentation/config/credential.adoc
@@ -0,0 +1,55 @@
+credential.helper::
+	Specify an external helper to be called when a username or
+	password credential is needed; the helper may consult external
+	storage to avoid prompting the user for the credentials. This is
+	normally the name of a credential helper with possible
+	arguments, but may also be an absolute path with arguments or, if
+	preceded by `!`, shell commands.
++
+Note that multiple helpers may be defined. See linkgit:gitcredentials[7]
+for details and examples.
+
+credential.interactive::
+	By default, Git and any configured credential helpers will ask for
+	user input when new credentials are required. Many of these helpers
+	will succeed based on stored credentials if those credentials are
+	still valid. To avoid the possibility of user interactivity from
+	Git, set `credential.interactive=false`. Some credential helpers
+	respect this option as well.
+
+credential.useHttpPath::
+	When acquiring credentials, consider the "path" component of an http
+	or https URL to be important. Defaults to false. See
+	linkgit:gitcredentials[7] for more information.
+
+credential.sanitizePrompt::
+	By default, user names and hosts that are shown as part of the
+	password prompt are not allowed to contain control characters (they
+	will be URL-encoded by default). Configure this setting to `false` to
+	override that behavior.
+
+credential.protectProtocol::
+	By default, Carriage Return characters are not allowed in the protocol
+	that is used when Git talks to a credential helper. This setting allows
+	users to override this default.
+
+credential.username::
+	If no username is set for a network authentication, use this username
+	by default. See credential.<context>.* below, and
+	linkgit:gitcredentials[7].
+
+credential.<url>.*::
+	Any of the credential.* options above can be applied selectively to
+	some credentials. For example, "credential.https://example.com.username";
+	would set the default username only for https connections to
+	example.com. See linkgit:gitcredentials[7] for details on how URLs are
+	matched.
+
+credentialCache.ignoreSIGHUP::
+	Tell git-credential-cache--daemon to ignore SIGHUP, instead of quitting.
+
+credentialStore.lockTimeoutMS::
+	The length of time, in milliseconds, for git-credential-store to retry
+	when trying to lock the credentials file. A value of 0 means not to retry at
+	all; -1 means to try indefinitely. Default is 1000 (i.e., retry for
+	1s).
diff --git a/Documentation/config/diff.adoc b/Documentation/config/diff.adoc
new file mode 100644
index 0000000000..1135a62a0a
--- /dev/null
+++ b/Documentation/config/diff.adoc
@@ -0,0 +1,267 @@
+`diff.autoRefreshIndex`::
+	When using `git diff` to compare with work tree
+	files, do not consider stat-only changes as changed.
+	Instead, silently run `git update-index --refresh` to
+	update the cached stat information for paths whose
+	contents in the work tree match the contents in the
+	index.  This option defaults to `true`.  Note that this
+	affects only `git diff` Porcelain, and not lower level
+	`diff` commands such as `git diff-files`.
+
+`diff.dirstat`::
+ifdef::git-diff[]
+	A comma separated list of `--dirstat` parameters specifying the
+	default behavior of the `--dirstat` option to `git diff` and friends.
+endif::git-diff[]
+ifndef::git-diff[]
+	A comma separated list of `--dirstat` parameters specifying the
+	default behavior of the `--dirstat` option to linkgit:git-diff[1]
+	and friends.
+endif::git-diff[]
+	The defaults can be overridden on the command line
+	(using `--dirstat=<param>,...`). The fallback defaults
+	(when not changed by `diff.dirstat`) are `changes,noncumulative,3`.
+	The following parameters are available:
++
+--
+`changes`;;
+	Compute the dirstat numbers by counting the lines that have been
+	removed from the source, or added to the destination. This ignores
+	the amount of pure code movements within a file.  In other words,
+	rearranging lines in a file is not counted as much as other changes.
+	This is the default behavior when no parameter is given.
+`lines`;;
+	Compute the dirstat numbers by doing the regular line-based diff
+	analysis, and summing the removed/added line counts. (For binary
+	files, count 64-byte chunks instead, since binary files have no
+	natural concept of lines). This is a more expensive `--dirstat`
+	behavior than the `changes` behavior, but it does count rearranged
+	lines within a file as much as other changes. The resulting output
+	is consistent with what you get from the other `--*stat` options.
+`files`;;
+	Compute the dirstat numbers by counting the number of files changed.
+	Each changed file counts equally in the dirstat analysis. This is
+	the computationally cheapest `--dirstat` behavior, since it does
+	not have to look at the file contents at all.
+`cumulative`;;
+	Count changes in a child directory for the parent directory as well.
+	Note that when using `cumulative`, the sum of the percentages
+	reported may exceed 100%. The default (non-cumulative) behavior can
+	be specified with the `noncumulative` parameter.
+_<limit>_;;
+	An integer parameter specifies a cut-off percent (3% by default).
+	Directories contributing less than this percentage of the changes
+	are not shown in the output.
+--
++
+Example: The following will count changed files, while ignoring
+directories with less than 10% of the total amount of changed files,
+and accumulating child directory counts in the parent directories:
+`files,10,cumulative`.
+
+`diff.statNameWidth`::
+	Limit the width of the filename part in `--stat` output. If set, applies
+	to all commands generating `--stat` output except `format-patch`.
+
+`diff.statGraphWidth`::
+	Limit the width of the graph part in `--stat` output. If set, applies
+	to all commands generating `--stat` output except `format-patch`.
+
+`diff.context`::
+	Generate diffs with _<n>_ lines of context instead of the default
+	of 3. This value is overridden by the `-U` option.
+
+`diff.interHunkContext`::
+	Show the context between diff hunks, up to the specified number
+	of lines, thereby fusing the hunks that are close to each other.
+	This value serves as the default for the `--inter-hunk-context`
+	command line option.
+
+`diff.external`::
+	If this config variable is set, diff generation is not
+	performed using the internal diff machinery, but using the
+	given command.  Can be overridden with the `GIT_EXTERNAL_DIFF`
+	environment variable.  The command is called with parameters
+	as described under "git Diffs" in linkgit:git[1].  Note: if
+	you want to use an external diff program only on a subset of
+	your files, you might want to use linkgit:gitattributes[5] instead.
+
+`diff.trustExitCode`::
+	If this boolean value is set to `true` then the
+	`diff.external` command is expected to return exit code
+	0 if it considers the input files to be equal or 1 if it
+	considers them to be different, like `diff`(1).
+	If it is set to `false`, which is the default, then the command
+	is expected to return exit code `0` regardless of equality.
+	Any other exit code causes Git to report a fatal error.
+
+`diff.ignoreSubmodules`::
+	Sets the default value of `--ignore-submodules`. Note that this
+	affects only `git diff` Porcelain, and not lower level `diff`
+	commands such as `git diff-files`. `git checkout`
+	and `git switch` also honor
+	this setting when reporting uncommitted changes. Setting it to
+	`all` disables the submodule summary normally shown by `git commit`
+	and `git status` when `status.submoduleSummary` is set unless it is
+	overridden by using the `--ignore-submodules` command-line option.
+	The `git submodule` commands are not affected by this setting.
+	By default this is set to untracked so that any untracked
+	submodules are ignored.
+
+`diff.mnemonicPrefix`::
+	If set, `git diff` uses a prefix pair that is different from the
+	standard `a/` and `b/` depending on what is being compared.  When
+	this configuration is in effect, reverse diff output also swaps
+	the order of the prefixes:
+`git diff`;;
+	compares the (i)ndex and the (w)ork tree;
+`git diff HEAD`;;
+	 compares a (c)ommit and the (w)ork tree;
+`git diff --cached`;;
+	compares a (c)ommit and the (i)ndex;
+`git diff HEAD:<file1> <file2>`;;
+	compares an (o)bject and a (w)ork tree entity;
+`git diff --no-index <a> <b>`;;
+	compares two non-git things _<a>_ and _<b>_.
+
+`diff.noPrefix`::
+	If set, `git diff` does not show any source or destination prefix.
+
+`diff.srcPrefix`::
+	If set, `git diff` uses this source prefix. Defaults to `a/`.
+
+`diff.dstPrefix`::
+	If set, `git diff` uses this destination prefix. Defaults to `b/`.
+
+`diff.relative`::
+	If set to `true`, `git diff` does not show changes outside of the directory
+	and show pathnames relative to the current directory.
+
+`diff.orderFile`::
+	File indicating how to order files within a diff.
+ifdef::git-diff[]
+	See the `-O` option for details.
+endif::git-diff[]
+ifndef::git-diff[]
+	See the `-O` option to linkgit:git-diff[1] for details.
+endif::git-diff[]
+	If `diff.orderFile` is a relative pathname, it is treated as
+	relative to the top of the working tree.
+
+`diff.renameLimit`::
+	The number of files to consider in the exhaustive portion of
+	copy/rename detection; equivalent to the `git diff` option
+	`-l`.  If not set, the default value is currently 1000.  This
+	setting has no effect if rename detection is turned off.
+
+`diff.renames`::
+	Whether and how Git detects renames.  If set to `false`,
+	rename detection is disabled. If set to `true`, basic rename
+	detection is enabled.  If set to `copies` or `copy`, Git will
+	detect copies, as well.  Defaults to `true`.  Note that this
+	affects only `git diff` Porcelain like linkgit:git-diff[1] and
+	linkgit:git-log[1], and not lower level commands such as
+	linkgit:git-diff-files[1].
+
+`diff.suppressBlankEmpty`::
+	A boolean to inhibit the standard behavior of printing a space
+	before each empty output line. Defaults to `false`.
+
+`diff.submodule`::
+	Specify the format in which differences in submodules are
+	shown.  The `short` format just shows the names of the commits
+	at the beginning and end of the range. The `log` format lists
+	the commits in the range like linkgit:git-submodule[1] `summary`
+	does. The `diff` format shows an inline diff of the changed
+	contents of the submodule. Defaults to `short`.
+
+`diff.wordRegex`::
+	A POSIX Extended Regular Expression used to determine what is a "word"
+	when performing word-by-word difference calculations.  Character
+	sequences that match the regular expression are "words", all other
+	characters are *ignorable* whitespace.
+
+`diff.<driver>.command`::
+	The custom diff driver command.  See linkgit:gitattributes[5]
+	for details.
+
+`diff.<driver>.trustExitCode`::
+	If this boolean value is set to `true` then the
+	`diff.<driver>.command` command is expected to return exit code
+	0 if it considers the input files to be equal or 1 if it
+	considers them to be different, like `diff`(1).
+	If it is set to `false`, which is the default, then the command
+	is expected to return exit code 0 regardless of equality.
+	Any other exit code causes Git to report a fatal error.
+
+`diff.<driver>.xfuncname`::
+	The regular expression that the diff driver should use to
+	recognize the hunk header.  A built-in pattern may also be used.
+	See linkgit:gitattributes[5] for details.
+
+`diff.<driver>.binary`::
+	Set this option to `true` to make the diff driver treat files as
+	binary.  See linkgit:gitattributes[5] for details.
+
+`diff.<driver>.textconv`::
+	The command that the diff driver should call to generate the
+	text-converted version of a file.  The result of the
+	conversion is used to generate a human-readable diff.  See
+	linkgit:gitattributes[5] for details.
+
+`diff.<driver>.wordRegex`::
+	The regular expression that the diff driver should use to
+	split words in a line.  See linkgit:gitattributes[5] for
+	details.
+
+`diff.<driver>.cachetextconv`::
+	Set this option to `true` to make the diff driver cache the text
+	conversion outputs.  See linkgit:gitattributes[5] for details.
+
+`diff.indentHeuristic`::
+	Set this option to `false` to disable the default heuristics
+	that shift diff hunk boundaries to make patches easier to read.
+
+`diff.algorithm`::
+	Choose a diff algorithm.  The variants are as follows:
++
+--
+`default`;;
+`myers`;;
+	The basic greedy diff algorithm. Currently, this is the default.
+`minimal`;;
+	Spend extra time to make sure the smallest possible diff is
+	produced.
+`patience`;;
+	Use "patience diff" algorithm when generating patches.
+`histogram`;;
+	This algorithm extends the patience algorithm to "support
+	low-occurrence common elements".
+--
++
+
+`diff.wsErrorHighlight`::
+	Highlight whitespace errors in the `context`, `old` or `new`
+	lines of the diff.  Multiple values are separated by comma,
+	`none` resets previous values, `default` reset the list to
+	`new` and `all` is a shorthand for `old,new,context`.  The
+	whitespace errors are colored with `color.diff.whitespace`.
+	The command line option `--ws-error-highlight=<kind>`
+	overrides this setting.
+
+`diff.colorMoved`::
+	If set to either a valid _<mode>_ or a `true` value, moved lines
+	in a diff are colored differently.
+ifdef::git-diff[]
+	For details of valid modes see `--color-moved`.
+endif::git-diff[]
+ifndef::git-diff[]
+	For details of valid modes see `--color-moved` in linkgit:git-diff[1].
+endif::git-diff[]
+	If simply set to `true` the default color mode will be used. When
+	set to `false`, moved lines are not colored.
+
+`diff.colorMovedWS`::
+	When moved lines are colored using e.g. the `diff.colorMoved` setting,
+	this option controls the mode how spaces are treated.
+	For details of valid modes see `--color-moved-ws` in linkgit:git-diff[1].
diff --git a/Documentation/config/difftool.adoc b/Documentation/config/difftool.adoc
new file mode 100644
index 0000000000..4f7d40ce24
--- /dev/null
+++ b/Documentation/config/difftool.adoc
@@ -0,0 +1,45 @@
+diff.tool::
+	Controls which diff tool is used by linkgit:git-difftool[1].
+	This variable overrides the value configured in `merge.tool`.
+	The list below shows the valid built-in values.
+	Any other value is treated as a custom diff tool and requires
+	that a corresponding difftool.<tool>.cmd variable is defined.
+
+diff.guitool::
+	Controls which diff tool is used by linkgit:git-difftool[1] when
+	the -g/--gui flag is specified. This variable overrides the value
+	configured in `merge.guitool`. The list below shows the valid
+	built-in values. Any other value is treated as a custom diff tool
+	and requires that a corresponding difftool.<guitool>.cmd variable
+	is defined.
+
+include::{build_dir}/mergetools-diff.adoc[]
+
+difftool.<tool>.cmd::
+	Specify the command to invoke the specified diff tool.
+	The specified command is evaluated in shell with the following
+	variables available:  'LOCAL' is set to the name of the temporary
+	file containing the contents of the diff pre-image and 'REMOTE'
+	is set to the name of the temporary file containing the contents
+	of the diff post-image.
++
+See the `--tool=<tool>` option in linkgit:git-difftool[1] for more details.
+
+difftool.<tool>.path::
+	Override the path for the given tool.  This is useful in case
+	your tool is not in the PATH.
+
+difftool.trustExitCode::
+	Exit difftool if the invoked diff tool returns a non-zero exit status.
++
+See the `--trust-exit-code` option in linkgit:git-difftool[1] for more details.
+
+difftool.prompt::
+	Prompt before each invocation of the diff tool.
+
+difftool.guiDefault::
+	Set `true` to use the `diff.guitool` by default (equivalent to specifying
+	the `--gui` argument), or `auto` to select `diff.guitool` or `diff.tool`
+	depending on the presence of a `DISPLAY` environment variable value. The
+	default is `false`, where the `--gui` argument must be provided
+	explicitly for the `diff.guitool` to be used.
diff --git a/Documentation/config/extensions.adoc b/Documentation/config/extensions.adoc
new file mode 100644
index 0000000000..9e2f321a6d
--- /dev/null
+++ b/Documentation/config/extensions.adoc
@@ -0,0 +1,103 @@
+extensions.*::
+	Unless otherwise stated, is an error to specify an extension if
+	`core.repositoryFormatVersion` is not `1`. See
+	linkgit:gitrepository-layout[5].
++
+--
+compatObjectFormat::
+	Specify a compatibility hash algorithm to use.  The acceptable values
+	are `sha1` and `sha256`.  The value specified must be different from the
+	value of `extensions.objectFormat`.  This allows client level
+	interoperability between git repositories whose objectFormat matches
+	this compatObjectFormat.  In particular when fully implemented the
+	pushes and pulls from a repository in whose objectFormat matches
+	compatObjectFormat.  As well as being able to use oids encoded in
+	compatObjectFormat in addition to oids encoded with objectFormat to
+	locally specify objects.
+
+noop::
+	This extension does not change git's behavior at all. It is useful only
+	for testing format-1 compatibility.
++
+For historical reasons, this extension is respected regardless of the
+`core.repositoryFormatVersion` setting.
+
+noop-v1::
+	This extension does not change git's behavior at all. It is useful only
+	for testing format-1 compatibility.
+
+objectFormat::
+	Specify the hash algorithm to use.  The acceptable values are `sha1` and
+	`sha256`.  If not specified, `sha1` is assumed.
++
+Note that this setting should only be set by linkgit:git-init[1] or
+linkgit:git-clone[1].  Trying to change it after initialization will not
+work and will produce hard-to-diagnose issues.
+
+partialClone::
+	When enabled, indicates that the repo was created with a partial clone
+	(or later performed a partial fetch) and that the remote may have
+	omitted sending certain unwanted objects.  Such a remote is called a
+	"promisor remote" and it promises that all such omitted objects can
+	be fetched from it in the future.
++
+The value of this key is the name of the promisor remote.
++
+For historical reasons, this extension is respected regardless of the
+`core.repositoryFormatVersion` setting.
+
+preciousObjects::
+	If enabled, indicates that objects in the repository MUST NOT be deleted
+	(e.g., by `git-prune` or `git repack -d`).
++
+For historical reasons, this extension is respected regardless of the
+`core.repositoryFormatVersion` setting.
+
+refStorage::
+	Specify the ref storage format to use. The acceptable values are:
++
+include::../ref-storage-format.adoc[]
+
++
+Note that this setting should only be set by linkgit:git-init[1] or
+linkgit:git-clone[1]. Trying to change it after initialization will not
+work and will produce hard-to-diagnose issues.
+
+relativeWorktrees::
+	If enabled, indicates at least one worktree has been linked with
+	relative paths. Automatically set if a worktree has been created or
+	repaired with either the `--relative-paths` option or with the
+	`worktree.useRelativePaths` config set to `true`.
+
+worktreeConfig::
+	If enabled, then worktrees will load config settings from the
+	`$GIT_DIR/config.worktree` file in addition to the
+	`$GIT_COMMON_DIR/config` file. Note that `$GIT_COMMON_DIR` and
+	`$GIT_DIR` are the same for the main working tree, while other
+	working trees have `$GIT_DIR` equal to
+	`$GIT_COMMON_DIR/worktrees/<id>/`. The settings in the
+	`config.worktree` file will override settings from any other
+	config files.
++
+When enabling this extension, you must be careful to move
+certain values from the common config file to the main working tree's
+`config.worktree` file, if present:
++
+* `core.worktree` must be moved from `$GIT_COMMON_DIR/config` to
+  `$GIT_COMMON_DIR/config.worktree`.
+* If `core.bare` is true, then it must be moved from `$GIT_COMMON_DIR/config`
+  to `$GIT_COMMON_DIR/config.worktree`.
+
++
+It may also be beneficial to adjust the locations of `core.sparseCheckout`
+and `core.sparseCheckoutCone` depending on your desire for customizable
+sparse-checkout settings for each worktree. By default, the `git
+sparse-checkout` builtin enables this extension, assigns
+these config values on a per-worktree basis, and uses the
+`$GIT_DIR/info/sparse-checkout` file to specify the sparsity for each
+worktree independently. See linkgit:git-sparse-checkout[1] for more
+details.
++
+For historical reasons, this extension is respected regardless of the
+`core.repositoryFormatVersion` setting.
+--
diff --git a/Documentation/config/fastimport.adoc b/Documentation/config/fastimport.adoc
new file mode 100644
index 0000000000..903677d7ef
--- /dev/null
+++ b/Documentation/config/fastimport.adoc
@@ -0,0 +1,8 @@
+fastimport.unpackLimit::
+	If the number of objects imported by linkgit:git-fast-import[1]
+	is below this limit, then the objects will be unpacked into
+	loose object files.  However, if the number of imported objects
+	equals or exceeds this limit, then the pack will be stored as a
+	pack.  Storing the pack from a fast-import can make the import
+	operation complete faster, especially on slow filesystems.  If
+	not set, the value of `transfer.unpackLimit` is used instead.
diff --git a/Documentation/config/feature.adoc b/Documentation/config/feature.adoc
new file mode 100644
index 0000000000..f061b64b74
--- /dev/null
+++ b/Documentation/config/feature.adoc
@@ -0,0 +1,37 @@
+feature.*::
+	The config settings that start with `feature.` modify the defaults of
+	a group of other config settings. These groups are created by the Git
+	developer community as recommended defaults and are subject to change.
+	In particular, new config options may be added with different defaults.
+
+feature.experimental::
+	Enable config options that are new to Git, and are being considered for
+	future defaults. Config settings included here may be added or removed
+	with each release, including minor version updates. These settings may
+	have unintended interactions since they are so new. Please enable this
+	setting if you are interested in providing feedback on experimental
+	features. The new default values are:
++
+* `fetch.negotiationAlgorithm=skipping` may improve fetch negotiation times by
+skipping more commits at a time, reducing the number of round trips.
++
+* `pack.useBitmapBoundaryTraversal=true` may improve bitmap traversal times by
+walking fewer objects.
++
+* `pack.allowPackReuse=multi` may improve the time it takes to create a pack by
+reusing objects from multiple packs instead of just one.
+
+feature.manyFiles::
+	Enable config options that optimize for repos with many files in the
+	working directory. With many files, commands such as `git status` and
+	`git checkout` may be slow and these new defaults improve performance:
++
+* `index.skipHash=true` speeds up index writes by not computing a trailing
+  checksum. Note that this will cause Git versions earlier than 2.13.0 to
+  refuse to parse the index and Git versions earlier than 2.40.0 will report
+  a corrupted index during `git fsck`.
++
+* `index.version=4` enables path-prefix compression in the index.
++
+* `core.untrackedCache=true` enables the untracked cache. This setting assumes
+that mtime is working on your machine.
diff --git a/Documentation/config/fetch.adoc b/Documentation/config/fetch.adoc
new file mode 100644
index 0000000000..d7dc461bd1
--- /dev/null
+++ b/Documentation/config/fetch.adoc
@@ -0,0 +1,128 @@
+fetch.recurseSubmodules::
+	This option controls whether `git fetch` (and the underlying fetch
+	in `git pull`) will recursively fetch into populated submodules.
+	This option can be set either to a boolean value or to 'on-demand'.
+	Setting it to a boolean changes the behavior of fetch and pull to
+	recurse unconditionally into submodules when set to true or to not
+	recurse at all when set to false. When set to 'on-demand', fetch and
+	pull will only recurse into a populated submodule when its
+	superproject retrieves a commit that updates the submodule's
+	reference.
+	Defaults to 'on-demand', or to the value of 'submodule.recurse' if set.
+
+fetch.fsckObjects::
+	If it is set to true, git-fetch-pack will check all fetched
+	objects. See `transfer.fsckObjects` for what's
+	checked. Defaults to false. If not set, the value of
+	`transfer.fsckObjects` is used instead.
+
+fetch.fsck.<msg-id>::
+	Acts like `fsck.<msg-id>`, but is used by
+	linkgit:git-fetch-pack[1] instead of linkgit:git-fsck[1]. See
+	the `fsck.<msg-id>` documentation for details.
+
+fetch.fsck.skipList::
+	Acts like `fsck.skipList`, but is used by
+	linkgit:git-fetch-pack[1] instead of linkgit:git-fsck[1]. See
+	the `fsck.skipList` documentation for details.
+
+fetch.unpackLimit::
+	If the number of objects fetched over the Git native
+	transfer is below this
+	limit, then the objects will be unpacked into loose object
+	files. However if the number of received objects equals or
+	exceeds this limit then the received pack will be stored as
+	a pack, after adding any missing delta bases.  Storing the
+	pack from a push can make the push operation complete faster,
+	especially on slow filesystems.  If not set, the value of
+	`transfer.unpackLimit` is used instead.
+
+fetch.prune::
+	If true, fetch will automatically behave as if the `--prune`
+	option was given on the command line.  See also `remote.<name>.prune`
+	and the PRUNING section of linkgit:git-fetch[1].
+
+fetch.pruneTags::
+	If true, fetch will automatically behave as if the
+	`refs/tags/*:refs/tags/*` refspec was provided when pruning,
+	if not set already. This allows for setting both this option
+	and `fetch.prune` to maintain a 1=1 mapping to upstream
+	refs. See also `remote.<name>.pruneTags` and the PRUNING
+	section of linkgit:git-fetch[1].
+
+fetch.all::
+	If true, fetch will attempt to update all available remotes.
+	This behavior can be overridden by passing `--no-all` or by
+	explicitly specifying one or more remote(s) to fetch from.
+	Defaults to false.
+
+fetch.output::
+	Control how ref update status is printed. Valid values are
+	`full` and `compact`. Default value is `full`. See the
+	OUTPUT section in linkgit:git-fetch[1] for details.
+
+fetch.negotiationAlgorithm::
+	Control how information about the commits in the local repository
+	is sent when negotiating the contents of the packfile to be sent by
+	the server.  Set to "consecutive" to use an algorithm that walks
+	over consecutive commits checking each one.  Set to "skipping" to
+	use an algorithm that skips commits in an effort to converge
+	faster, but may result in a larger-than-necessary packfile; or set
+	to "noop" to not send any information at all, which will almost
+	certainly result in a larger-than-necessary packfile, but will skip
+	the negotiation step.  Set to "default" to override settings made
+	previously and use the default behaviour.  The default is normally
+	"consecutive", but if `feature.experimental` is true, then the
+	default is "skipping".  Unknown values will cause 'git fetch' to
+	error out.
++
+See also the `--negotiate-only` and `--negotiation-tip` options to
+linkgit:git-fetch[1].
+
+fetch.showForcedUpdates::
+	Set to false to enable `--no-show-forced-updates` in
+	linkgit:git-fetch[1] and linkgit:git-pull[1] commands.
+	Defaults to true.
+
+fetch.parallel::
+	Specifies the maximal number of fetch operations to be run in parallel
+	at a time (submodules, or remotes when the `--multiple` option of
+	linkgit:git-fetch[1] is in effect).
++
+A value of 0 will give some reasonable default. If unset, it defaults to 1.
++
+For submodules, this setting can be overridden using the `submodule.fetchJobs`
+config setting.
+
+fetch.writeCommitGraph::
+	Set to true to write a commit-graph after every `git fetch` command
+	that downloads a pack-file from a remote. Using the `--split` option,
+	most executions will create a very small commit-graph file on top of
+	the existing commit-graph file(s). Occasionally, these files will
+	merge and the write may take longer. Having an updated commit-graph
+	file helps performance of many Git commands, including `git merge-base`,
+	`git push -f`, and `git log --graph`. Defaults to false.
+
+fetch.bundleURI::
+	This value stores a URI for downloading Git object data from a bundle
+	URI before performing an incremental fetch from the origin Git server.
+	This is similar to how the `--bundle-uri` option behaves in
+	linkgit:git-clone[1]. `git clone --bundle-uri` will set the
+	`fetch.bundleURI` value if the supplied bundle URI contains a bundle
+	list that is organized for incremental fetches.
++
+If you modify this value and your repository has a `fetch.bundleCreationToken`
+value, then remove that `fetch.bundleCreationToken` value before fetching from
+the new bundle URI.
+
+fetch.bundleCreationToken::
+	When using `fetch.bundleURI` to fetch incrementally from a bundle
+	list that uses the "creationToken" heuristic, this config value
+	stores the maximum `creationToken` value of the downloaded bundles.
+	This value is used to prevent downloading bundles in the future
+	if the advertised `creationToken` is not strictly larger than this
+	value.
++
+The creation token values are chosen by the provider serving the specific
+bundle URI. If you modify the URI at `fetch.bundleURI`, then be sure to
+remove the value for the `fetch.bundleCreationToken` value before fetching.
diff --git a/Documentation/config/filter.adoc b/Documentation/config/filter.adoc
new file mode 100644
index 0000000000..90dfe0ba5a
--- /dev/null
+++ b/Documentation/config/filter.adoc
@@ -0,0 +1,9 @@
+filter.<driver>.clean::
+	The command which is used to convert the content of a worktree
+	file to a blob upon checkin.  See linkgit:gitattributes[5] for
+	details.
+
+filter.<driver>.smudge::
+	The command which is used to convert the content of a blob
+	object to a worktree file upon checkout.  See
+	linkgit:gitattributes[5] for details.
diff --git a/Documentation/config/fmt-merge-msg.adoc b/Documentation/config/fmt-merge-msg.adoc
new file mode 100644
index 0000000000..3fbf40e24f
--- /dev/null
+++ b/Documentation/config/fmt-merge-msg.adoc
@@ -0,0 +1,22 @@
+merge.branchdesc::
+	In addition to branch names, populate the log message with
+	the branch description text associated with them.  Defaults
+	to false.
+
+merge.log::
+	In addition to branch names, populate the log message with at
+	most the specified number of one-line descriptions from the
+	actual commits that are being merged.  Defaults to false, and
+	true is a synonym for 20.
+
+merge.suppressDest::
+	By adding a glob that matches the names of integration
+	branches to this multi-valued configuration variable, the
+	default merge message computed for merges into these
+	integration branches will omit "into <branch name>" from
+	its title.
++
+An element with an empty value can be used to clear the list
+of globs accumulated from previous configuration entries.
+When there is no `merge.suppressDest` variable defined, the
+default value of `master` is used for backward compatibility.
diff --git a/Documentation/config/format.adoc b/Documentation/config/format.adoc
new file mode 100644
index 0000000000..7410e930e5
--- /dev/null
+++ b/Documentation/config/format.adoc
@@ -0,0 +1,153 @@
+format.attach::
+	Enable multipart/mixed attachments as the default for
+	'format-patch'.  The value can also be a double quoted string
+	which will enable attachments as the default and set the
+	value as the boundary.  See the --attach option in
+	linkgit:git-format-patch[1].  To countermand an earlier
+	value, set it to an empty string.
+
+format.from::
+	Provides the default value for the `--from` option to format-patch.
+	Accepts a boolean value, or a name and email address.  If false,
+	format-patch defaults to `--no-from`, using commit authors directly in
+	the "From:" field of patch mails.  If true, format-patch defaults to
+	`--from`, using your committer identity in the "From:" field of patch
+	mails and including a "From:" field in the body of the patch mail if
+	different.  If set to a non-boolean value, format-patch uses that
+	value instead of your committer identity.  Defaults to false.
+
+format.forceInBodyFrom::
+	Provides the default value for the `--[no-]force-in-body-from`
+	option to format-patch.  Defaults to false.
+
+format.numbered::
+	A boolean which can enable or disable sequence numbers in patch
+	subjects.  It defaults to "auto" which enables it only if there
+	is more than one patch.  It can be enabled or disabled for all
+	messages by setting it to "true" or "false".  See --numbered
+	option in linkgit:git-format-patch[1].
+
+format.headers::
+	Additional email headers to include in a patch to be submitted
+	by mail.  See linkgit:git-format-patch[1].
+
+format.to::
+format.cc::
+	Additional recipients to include in a patch to be submitted
+	by mail.  See the --to and --cc options in
+	linkgit:git-format-patch[1].
+
+format.subjectPrefix::
+	The default for format-patch is to output files with the '[PATCH]'
+	subject prefix. Use this variable to change that prefix.
+
+format.coverFromDescription::
+	The default mode for format-patch to determine which parts of
+	the cover letter will be populated using the branch's
+	description. See the `--cover-from-description` option in
+	linkgit:git-format-patch[1].
+
+format.signature::
+	The default for format-patch is to output a signature containing
+	the Git version number. Use this variable to change that default.
+	Set this variable to the empty string ("") to suppress
+	signature generation.
+
+format.signatureFile::
+	Works just like format.signature except the contents of the
+	file specified by this variable will be used as the signature.
+
+format.suffix::
+	The default for format-patch is to output files with the suffix
+	`.patch`. Use this variable to change that suffix (make sure to
+	include the dot if you want it).
+
+format.encodeEmailHeaders::
+	Encode email headers that have non-ASCII characters with
+	"Q-encoding" (described in RFC 2047) for email transmission.
+	Defaults to true.
+
+format.pretty::
+	The default pretty format for log/show/whatchanged command.
+	See linkgit:git-log[1], linkgit:git-show[1],
+	linkgit:git-whatchanged[1].
+
+format.thread::
+	The default threading style for 'git format-patch'.  Can be
+	a boolean value, or `shallow` or `deep`.  `shallow` threading
+	makes every mail a reply to the head of the series,
+	where the head is chosen from the cover letter, the
+	`--in-reply-to`, and the first patch mail, in this order.
+	`deep` threading makes every mail a reply to the previous one.
+	A true boolean value is the same as `shallow`, and a false
+	value disables threading.
+
+format.signOff::
+	A boolean value which lets you enable the `-s/--signoff` option of
+	format-patch by default. *Note:* Adding the `Signed-off-by` trailer to a
+	patch should be a conscious act and means that you certify you have
+	the rights to submit this work under the same open source license.
+	Please see the 'SubmittingPatches' document for further discussion.
+
+format.coverLetter::
+	A boolean that controls whether to generate a cover-letter when
+	format-patch is invoked, but in addition can be set to "auto", to
+	generate a cover-letter only when there's more than one patch.
+	Default is false.
+
+format.outputDirectory::
+	Set a custom directory to store the resulting files instead of the
+	current working directory. All directory components will be created.
+
+format.filenameMaxLength::
+	The maximum length of the output filenames generated by the
+	`format-patch` command; defaults to 64.  Can be overridden
+	by the `--filename-max-length=<n>` command line option.
+
+format.useAutoBase::
+	A boolean value which lets you enable the `--base=auto` option of
+	format-patch by default. Can also be set to "whenAble" to allow
+	enabling `--base=auto` if a suitable base is available, but to skip
+	adding base info otherwise without the format dying.
+
+format.notes::
+	Provides the default value for the `--notes` option to
+	format-patch. Accepts a boolean value, or a ref which specifies
+	where to get notes. If false, format-patch defaults to
+	`--no-notes`. If true, format-patch defaults to `--notes`. If
+	set to a non-boolean value, format-patch defaults to
+	`--notes=<ref>`, where `ref` is the non-boolean value. Defaults
+	to false.
++
+If one wishes to use the ref `refs/notes/true`, please use that literal
+instead.
++
+This configuration can be specified multiple times in order to allow
+multiple notes refs to be included. In that case, it will behave
+similarly to multiple `--[no-]notes[=]` options passed in. That is, a
+value of `true` will show the default notes, a value of `<ref>` will
+also show notes from that notes ref and a value of `false` will negate
+previous configurations and not show notes.
++
+For example,
++
+------------
+[format]
+	notes = true
+	notes = foo
+	notes = false
+	notes = bar
+------------
++
+will only show notes from `refs/notes/bar`.
+
+format.mboxrd::
+	A boolean value which enables the robust "mboxrd" format when
+	`--stdout` is in use to escape "^>+From " lines.
+
+format.noprefix::
+	If set, do not show any source or destination prefix in patches.
+	This is equivalent to the `diff.noprefix` option used by `git
+	diff` (but which is not respected by `format-patch`). Note that
+	by setting this, the receiver of any patches you generate will
+	have to apply them using the `-p0` option.
diff --git a/Documentation/config/fsck.adoc b/Documentation/config/fsck.adoc
new file mode 100644
index 0000000000..8e9e508933
--- /dev/null
+++ b/Documentation/config/fsck.adoc
@@ -0,0 +1,71 @@
+fsck.<msg-id>::
+	During fsck git may find issues with legacy data which
+	wouldn't be generated by current versions of git, and which
+	wouldn't be sent over the wire if `transfer.fsckObjects` was
+	set. This feature is intended to support working with legacy
+	repositories containing such data.
++
+Setting `fsck.<msg-id>` will be picked up by linkgit:git-fsck[1], but
+to accept pushes of such data set `receive.fsck.<msg-id>` instead, or
+to clone or fetch it set `fetch.fsck.<msg-id>`.
++
+The rest of the documentation discusses `fsck.*` for brevity, but the
+same applies for the corresponding `receive.fsck.*` and
+`fetch.fsck.*`. variables.
++
+Unlike variables like `color.ui` and `core.editor`, the
+`receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>` variables will not
+fall back on the `fsck.<msg-id>` configuration if they aren't set. To
+uniformly configure the same fsck settings in different circumstances,
+all three of them must be set to the same values.
++
+When `fsck.<msg-id>` is set, errors can be switched to warnings and
+vice versa by configuring the `fsck.<msg-id>` setting where the
+`<msg-id>` is the fsck message ID and the value is one of `error`,
+`warn` or `ignore`. For convenience, fsck prefixes the error/warning
+with the message ID, e.g. "missingEmail: invalid author/committer
+line - missing email" means that setting `fsck.missingEmail = ignore`
+will hide that issue.
++
+In general, it is better to enumerate existing objects with problems
+with `fsck.skipList`, instead of listing the kind of breakages these
+problematic objects share to be ignored, as doing the latter will
+allow new instances of the same breakages go unnoticed.
++
+Setting an unknown `fsck.<msg-id>` value will cause fsck to die, but
+doing the same for `receive.fsck.<msg-id>` and `fetch.fsck.<msg-id>`
+will only cause git to warn.
++
+See the `Fsck Messages` section of linkgit:git-fsck[1] for supported
+values of `<msg-id>`.
+
+
+fsck.skipList::
+	The path to a list of object names (i.e. one unabbreviated SHA-1 per
+	line) that are known to be broken in a non-fatal way and should
+	be ignored. On versions of Git 2.20 and later, comments ('#'), empty
+	lines, and any leading and trailing whitespace are ignored. Everything
+	but a SHA-1 per line will error out on older versions.
++
+This feature is useful when an established project should be accepted
+despite early commits containing errors that can be safely ignored,
+such as invalid committer email addresses.  Note: corrupt objects
+cannot be skipped with this setting.
++
+Like `fsck.<msg-id>` this variable has corresponding
+`receive.fsck.skipList` and `fetch.fsck.skipList` variants.
++
+Unlike variables like `color.ui` and `core.editor` the
+`receive.fsck.skipList` and `fetch.fsck.skipList` variables will not
+fall back on the `fsck.skipList` configuration if they aren't set. To
+uniformly configure the same fsck settings in different circumstances,
+all three of them must be set to the same values.
++
+Older versions of Git (before 2.20) documented that the object names
+list should be sorted. This was never a requirement; the object names
+could appear in any order, but when reading the list we tracked whether
+the list was sorted for the purposes of an internal binary search
+implementation, which could save itself some work with an already sorted
+list. Unless you had a humongous list there was no reason to go out of
+your way to pre-sort the list. After Git version 2.20 a hash implementation
+is used instead, so there's now no reason to pre-sort the list.
diff --git a/Documentation/config/fsmonitor--daemon.adoc b/Documentation/config/fsmonitor--daemon.adoc
new file mode 100644
index 0000000000..671f9b9462
--- /dev/null
+++ b/Documentation/config/fsmonitor--daemon.adoc
@@ -0,0 +1,11 @@
+fsmonitor.allowRemote::
+    By default, the fsmonitor daemon refuses to work with network-mounted
+    repositories. Setting `fsmonitor.allowRemote` to `true` overrides this
+    behavior.  Only respected when `core.fsmonitor` is set to `true`.
+
+fsmonitor.socketDir::
+    This Mac OS-specific option, if set, specifies the directory in
+    which to create the Unix domain socket used for communication
+    between the fsmonitor daemon and various Git commands. The directory must
+    reside on a native Mac OS filesystem.  Only respected when `core.fsmonitor`
+    is set to `true`.
diff --git a/Documentation/config/gc.adoc b/Documentation/config/gc.adoc
new file mode 100644
index 0000000000..21d56db279
--- /dev/null
+++ b/Documentation/config/gc.adoc
@@ -0,0 +1,181 @@
+gc.aggressiveDepth::
+	The depth parameter used in the delta compression
+	algorithm used by 'git gc --aggressive'.  This defaults
+	to 50, which is the default for the `--depth` option when
+	`--aggressive` isn't in use.
++
+See the documentation for the `--depth` option in
+linkgit:git-repack[1] for more details.
+
+gc.aggressiveWindow::
+	The window size parameter used in the delta compression
+	algorithm used by 'git gc --aggressive'.  This defaults
+	to 250, which is a much more aggressive window size than
+	the default `--window` of 10.
++
+See the documentation for the `--window` option in
+linkgit:git-repack[1] for more details.
+
+gc.auto::
+	When there are approximately more than this many loose
+	objects in the repository, `git gc --auto` will pack them.
+	Some Porcelain commands use this command to perform a
+	light-weight garbage collection from time to time.  The
+	default value is 6700.
++
+Setting this to 0 disables not only automatic packing based on the
+number of loose objects, but also any other heuristic `git gc --auto` will
+otherwise use to determine if there's work to do, such as
+`gc.autoPackLimit`.
+
+gc.autoPackLimit::
+	When there are more than this many packs that are not
+	marked with `*.keep` file in the repository, `git gc
+	--auto` consolidates them into one larger pack.  The
+	default value is 50.  Setting this to 0 disables it.
+	Setting `gc.auto` to 0 will also disable this.
++
+See the `gc.bigPackThreshold` configuration variable below. When in
+use, it'll affect how the auto pack limit works.
+
+gc.autoDetach::
+	Make `git gc --auto` return immediately and run in the background
+	if the system supports it. Default is true. This config variable acts
+	as a fallback in case `maintenance.autoDetach` is not set.
+
+gc.bigPackThreshold::
+	If non-zero, all non-cruft packs larger than this limit are kept
+	when `git gc` is run. This is very similar to
+	`--keep-largest-pack` except that all non-cruft packs that meet
+	the threshold are kept, not just the largest pack. Defaults to
+	zero. Common unit suffixes of 'k', 'm', or 'g' are supported.
++
+Note that if the number of kept packs is more than gc.autoPackLimit,
+this configuration variable is ignored, all packs except the base pack
+will be repacked. After this the number of packs should go below
+gc.autoPackLimit and gc.bigPackThreshold should be respected again.
++
+If the amount of memory estimated for `git repack` to run smoothly is
+not available and `gc.bigPackThreshold` is not set, the largest pack
+will also be excluded (this is the equivalent of running `git gc` with
+`--keep-largest-pack`).
+
+gc.writeCommitGraph::
+	If true, then gc will rewrite the commit-graph file when
+	linkgit:git-gc[1] is run. When using `git gc --auto`
+	the commit-graph will be updated if housekeeping is
+	required. Default is true. See linkgit:git-commit-graph[1]
+	for details.
+
+gc.logExpiry::
+	If the file gc.log exists, then `git gc --auto` will print
+	its content and exit with status zero instead of running
+	unless that file is more than 'gc.logExpiry' old.  Default is
+	"1.day".  See `gc.pruneExpire` for more ways to specify its
+	value.
+
+gc.packRefs::
+	Running `git pack-refs` in a repository renders it
+	unclonable by Git versions prior to 1.5.1.2 over dumb
+	transports such as HTTP.  This variable determines whether
+	'git gc' runs `git pack-refs`. This can be set to `notbare`
+	to enable it within all non-bare repos or it can be set to a
+	boolean value.  The default is `true`.
+
+gc.cruftPacks::
+	Store unreachable objects in a cruft pack (see
+	linkgit:git-repack[1]) instead of as loose objects. The default
+	is `true`.
+
+gc.maxCruftSize::
+	Limit the size of new cruft packs when repacking. When
+	specified in addition to `--max-cruft-size`, the command line
+	option takes priority. See the `--max-cruft-size` option of
+	linkgit:git-repack[1].
+
+gc.pruneExpire::
+	When 'git gc' is run, it will call 'prune --expire 2.weeks.ago'
+	(and 'repack --cruft --cruft-expiration 2.weeks.ago' if using
+	cruft packs via `gc.cruftPacks` or `--cruft`).  Override the
+	grace period with this config variable.  The value "now" may be
+	used to disable this grace period and always prune unreachable
+	objects immediately, or "never" may be used to suppress pruning.
+	This feature helps prevent corruption when 'git gc' runs
+	concurrently with another process writing to the repository; see
+	the "NOTES" section of linkgit:git-gc[1].
+
+gc.worktreePruneExpire::
+	When 'git gc' is run, it calls
+	'git worktree prune --expire 3.months.ago'.
+	This config variable can be used to set a different grace
+	period. The value "now" may be used to disable the grace
+	period and prune `$GIT_DIR/worktrees` immediately, or "never"
+	may be used to suppress pruning.
+
+gc.reflogExpire::
+gc.<pattern>.reflogExpire::
+	'git reflog expire' removes reflog entries older than
+	this time; defaults to 90 days. The value "now" expires all
+	entries immediately, and "never" suppresses expiration
+	altogether. With "<pattern>" (e.g.
+	"refs/stash") in the middle the setting applies only to
+	the refs that match the <pattern>.
+
+gc.reflogExpireUnreachable::
+gc.<pattern>.reflogExpireUnreachable::
+	'git reflog expire' removes reflog entries older than
+	this time and are not reachable from the current tip;
+	defaults to 30 days. The value "now" expires all entries
+	immediately, and "never" suppresses expiration altogether.
+	With "<pattern>" (e.g. "refs/stash")
+	in the middle, the setting applies only to the refs that
+	match the <pattern>.
++
+These types of entries are generally created as a result of using `git
+commit --amend` or `git rebase` and are the commits prior to the amend
+or rebase occurring.  Since these changes are not part of the current
+project most users will want to expire them sooner, which is why the
+default is more aggressive than `gc.reflogExpire`.
+
+gc.recentObjectsHook::
+	When considering whether or not to remove an object (either when
+	generating a cruft pack or storing unreachable objects as
+	loose), use the shell to execute the specified command(s).
+	Interpret their output as object IDs which Git will consider as
+	"recent", regardless of their age. By treating their mtimes as
+	"now", any objects (and their descendants) mentioned in the
+	output will be kept regardless of their true age.
++
+Output must contain exactly one hex object ID per line, and nothing
+else. Objects which cannot be found in the repository are ignored.
+Multiple hooks are supported, but all must exit successfully, else the
+operation (either generating a cruft pack or unpacking unreachable
+objects) will be halted.
+
+gc.repackFilter::
+	When repacking, use the specified filter to move certain
+	objects into a separate packfile.  See the
+	`--filter=<filter-spec>` option of linkgit:git-repack[1].
+
+gc.repackFilterTo::
+	When repacking and using a filter, see `gc.repackFilter`, the
+	specified location will be used to create the packfile
+	containing the filtered out objects. **WARNING:** The
+	specified location should be accessible, using for example the
+	Git alternates mechanism, otherwise the repo could be
+	considered corrupt by Git as it might not be able to access the
+	objects in that packfile. See the `--filter-to=<dir>` option
+	of linkgit:git-repack[1] and the `objects/info/alternates`
+	section of linkgit:gitrepository-layout[5].
+
+gc.rerereResolved::
+	Records of conflicted merge you resolved earlier are
+	kept for this many days when 'git rerere gc' is run.
+	You can also use more human-readable "1.month.ago", etc.
+	The default is 60 days.  See linkgit:git-rerere[1].
+
+gc.rerereUnresolved::
+	Records of conflicted merge you have not resolved are
+	kept for this many days when 'git rerere gc' is run.
+	You can also use more human-readable "1.month.ago", etc.
+	The default is 15 days.  See linkgit:git-rerere[1].
diff --git a/Documentation/config/gitcvs.adoc b/Documentation/config/gitcvs.adoc
new file mode 100644
index 0000000000..02da427fd9
--- /dev/null
+++ b/Documentation/config/gitcvs.adoc
@@ -0,0 +1,67 @@
+gitcvs.commitMsgAnnotation::
+	Append this string to each commit message. Set to empty string
+	to disable this feature. Defaults to "via git-CVS emulator".
+
+gitcvs.enabled::
+	Whether the CVS server interface is enabled for this repository.
+	See linkgit:git-cvsserver[1].
+
+gitcvs.logFile::
+	Path to a log file where the CVS server interface well... logs
+	various stuff. See linkgit:git-cvsserver[1].
+
+gitcvs.usecrlfattr::
+	If true, the server will look up the end-of-line conversion
+	attributes for files to determine the `-k` modes to use. If
+	the attributes force Git to treat a file as text,
+	the `-k` mode will be left blank so CVS clients will
+	treat it as text. If they suppress text conversion, the file
+	will be set with '-kb' mode, which suppresses any newline munging
+	the client might otherwise do. If the attributes do not allow
+	the file type to be determined, then `gitcvs.allBinary` is
+	used. See linkgit:gitattributes[5].
+
+gitcvs.allBinary::
+	This is used if `gitcvs.usecrlfattr` does not resolve
+	the correct '-kb' mode to use. If true, all
+	unresolved files are sent to the client in
+	mode '-kb'. This causes the client to treat them
+	as binary files, which suppresses any newline munging it
+	otherwise might do. Alternatively, if it is set to "guess",
+	then the contents of the file are examined to decide if
+	it is binary, similar to `core.autocrlf`.
+
+gitcvs.dbName::
+	Database used by git-cvsserver to cache revision information
+	derived from the Git repository. The exact meaning depends on the
+	used database driver, for SQLite (which is the default driver) this
+	is a filename. Supports variable substitution (see
+	linkgit:git-cvsserver[1] for details). May not contain semicolons (`;`).
+	Default: '%Ggitcvs.%m.sqlite'
+
+gitcvs.dbDriver::
+	Used Perl DBI driver. You can specify any available driver
+	for this here, but it might not work. git-cvsserver is tested
+	with 'DBD::SQLite', reported to work with 'DBD::Pg', and
+	reported *not* to work with 'DBD::mysql'. Experimental feature.
+	May not contain double colons (`:`). Default: 'SQLite'.
+	See linkgit:git-cvsserver[1].
+
+gitcvs.dbUser, gitcvs.dbPass::
+	Database user and password. Only useful if setting `gitcvs.dbDriver`,
+	since SQLite has no concept of database users and/or passwords.
+	'gitcvs.dbUser' supports variable substitution (see
+	linkgit:git-cvsserver[1] for details).
+
+gitcvs.dbTableNamePrefix::
+	Database table name prefix.  Prepended to the names of any
+	database tables used, allowing a single database to be used
+	for several repositories.  Supports variable substitution (see
+	linkgit:git-cvsserver[1] for details).  Any non-alphabetic
+	characters will be replaced with underscores.
+
+All gitcvs variables except for `gitcvs.usecrlfattr` and
+`gitcvs.allBinary` can also be specified as
+'gitcvs.<access_method>.<varname>' (where 'access_method'
+is one of "ext" and "pserver") to make them apply only for the given
+access method.
diff --git a/Documentation/config/gitweb.adoc b/Documentation/config/gitweb.adoc
new file mode 100644
index 0000000000..1b51475108
--- /dev/null
+++ b/Documentation/config/gitweb.adoc
@@ -0,0 +1,16 @@
+gitweb.category::
+gitweb.description::
+gitweb.owner::
+gitweb.url::
+	See linkgit:gitweb[1] for description.
+
+gitweb.avatar::
+gitweb.blame::
+gitweb.grep::
+gitweb.highlight::
+gitweb.patches::
+gitweb.pickaxe::
+gitweb.remote_heads::
+gitweb.showSizes::
+gitweb.snapshot::
+	See linkgit:gitweb.conf[5] for description.
diff --git a/Documentation/config/gpg.adoc b/Documentation/config/gpg.adoc
new file mode 100644
index 0000000000..5cf32b179d
--- /dev/null
+++ b/Documentation/config/gpg.adoc
@@ -0,0 +1,85 @@
+gpg.program::
+	Use this custom program instead of "`gpg`" found on `$PATH` when
+	making or verifying a PGP signature. The program must support the
+	same command-line interface as GPG, namely, to verify a detached
+	signature, "`gpg --verify $signature - <$file`" is run, and the
+	program is expected to signal a good signature by exiting with
+	code 0.  To generate an ASCII-armored detached signature, the
+	standard input of "`gpg -bsau $key`" is fed with the contents to be
+	signed, and the program is expected to send the result to its
+	standard output.
+
+gpg.format::
+	Specifies which key format to use when signing with `--gpg-sign`.
+	Default is "openpgp". Other possible values are "x509", "ssh".
++
+See linkgit:gitformat-signature[5] for the signature format, which differs
+based on the selected `gpg.format`.
+
+gpg.<format>.program::
+	Use this to customize the program used for the signing format you
+	chose. (see `gpg.program` and `gpg.format`) `gpg.program` can still
+	be used as a legacy synonym for `gpg.openpgp.program`. The default
+	value for `gpg.x509.program` is "gpgsm" and `gpg.ssh.program` is "ssh-keygen".
+
+gpg.minTrustLevel::
+	Specifies a minimum trust level for signature verification.  If
+	this option is unset, then signature verification for merge
+	operations requires a key with at least `marginal` trust.  Other
+	operations that perform signature verification require a key
+	with at least `undefined` trust.  Setting this option overrides
+	the required trust-level for all operations.  Supported values,
+	in increasing order of significance:
++
+* `undefined`
+* `never`
+* `marginal`
+* `fully`
+* `ultimate`
+
+gpg.ssh.defaultKeyCommand::
+	This command will be run when user.signingkey is not set and a ssh
+	signature is requested. On successful exit a valid ssh public key
+	prefixed with `key::` is expected in the first line of its output.
+	This allows for a script doing a dynamic lookup of the correct public
+	key when it is impractical to statically configure `user.signingKey`.
+	For example when keys or SSH Certificates are rotated frequently or
+	selection of the right key depends on external factors unknown to git.
+
+gpg.ssh.allowedSignersFile::
+	A file containing ssh public keys which you are willing to trust.
+	The file consists of one or more lines of principals followed by an ssh
+	public key.
+	e.g.: `user1@xxxxxxxxxxx,user2@xxxxxxxxxxx ssh-rsa AAAAX1...`
+	See ssh-keygen(1) "ALLOWED SIGNERS" for details.
+	The principal is only used to identify the key and is available when
+	verifying a signature.
++
+SSH has no concept of trust levels like gpg does. To be able to differentiate
+between valid signatures and trusted signatures the trust level of a signature
+verification is set to `fully` when the public key is present in the allowedSignersFile.
+Otherwise the trust level is `undefined` and git verify-commit/tag will fail.
++
+This file can be set to a location outside of the repository and every developer
+maintains their own trust store. A central repository server could generate this
+file automatically from ssh keys with push access to verify the code against.
+In a corporate setting this file is probably generated at a global location
+from automation that already handles developer ssh keys.
++
+A repository that only allows signed commits can store the file
+in the repository itself using a path relative to the top-level of the working tree.
+This way only committers with an already valid key can add or change keys in the keyring.
++
+Since OpensSSH 8.8 this file allows specifying a key lifetime using valid-after &
+valid-before options. Git will mark signatures as valid if the signing key was
+valid at the time of the signature's creation. This allows users to change a
+signing key without invalidating all previously made signatures.
++
+Using a SSH CA key with the cert-authority option
+(see ssh-keygen(1) "CERTIFICATES") is also valid.
+
+gpg.ssh.revocationFile::
+	Either a SSH KRL or a list of revoked public keys (without the principal prefix).
+	See ssh-keygen(1) for details.
+	If a public key is found in this file then it will always be treated
+	as having trust level "never" and signatures will show as invalid.
diff --git a/Documentation/config/grep.adoc b/Documentation/config/grep.adoc
new file mode 100644
index 0000000000..10041f27b0
--- /dev/null
+++ b/Documentation/config/grep.adoc
@@ -0,0 +1,28 @@
+grep.lineNumber::
+	If set to true, enable `-n` option by default.
+
+grep.column::
+	If set to true, enable the `--column` option by default.
+
+grep.patternType::
+	Set the default matching behavior. Using a value of 'basic', 'extended',
+	'fixed', or 'perl' will enable the `--basic-regexp`, `--extended-regexp`,
+	`--fixed-strings`, or `--perl-regexp` option accordingly, while the
+	value 'default' will use the `grep.extendedRegexp` option to choose
+	between 'basic' and 'extended'.
+
+grep.extendedRegexp::
+	If set to true, enable `--extended-regexp` option by default. This
+	option is ignored when the `grep.patternType` option is set to a value
+	other than 'default'.
+
+grep.threads::
+	Number of grep worker threads to use. If unset (or set to 0), Git will
+	use as many threads as the number of logical cores available.
+
+grep.fullName::
+	If set to true, enable `--full-name` option by default.
+
+grep.fallbackToNoIndex::
+	If set to true, fall back to `git grep --no-index` if `git grep`
+	is executed outside of a git repository.  Defaults to false.
diff --git a/Documentation/config/gui.adoc b/Documentation/config/gui.adoc
new file mode 100644
index 0000000000..171be774d2
--- /dev/null
+++ b/Documentation/config/gui.adoc
@@ -0,0 +1,57 @@
+gui.commitMsgWidth::
+	Defines how wide the commit message window is in the
+	linkgit:git-gui[1]. "75" is the default.
+
+gui.diffContext::
+	Specifies how many context lines should be used in calls to diff
+	made by the linkgit:git-gui[1]. The default is "5".
+
+gui.displayUntracked::
+	Determines if linkgit:git-gui[1] shows untracked files
+	in the file list. The default is "true".
+
+gui.encoding::
+	Specifies the default character encoding to use for displaying of
+	file contents in linkgit:git-gui[1] and linkgit:gitk[1].
+	It can be overridden by setting the 'encoding' attribute
+	for relevant files (see linkgit:gitattributes[5]).
+	If this option is not set, the tools default to the
+	locale encoding.
+
+gui.matchTrackingBranch::
+	Determines if new branches created with linkgit:git-gui[1] should
+	default to tracking remote branches with matching names or
+	not. Default: "false".
+
+gui.newBranchTemplate::
+	Is used as a suggested name when creating new branches using the
+	linkgit:git-gui[1].
+
+gui.pruneDuringFetch::
+	"true" if linkgit:git-gui[1] should prune remote-tracking branches when
+	performing a fetch. The default value is "false".
+
+gui.trustmtime::
+	Determines if linkgit:git-gui[1] should trust the file modification
+	timestamp or not. By default the timestamps are not trusted.
+
+gui.spellingDictionary::
+	Specifies the dictionary used for spell checking commit messages in
+	the linkgit:git-gui[1]. When set to "none" spell checking is turned
+	off.
+
+gui.fastCopyBlame::
+	If true, 'git gui blame' uses `-C` instead of `-C -C` for original
+	location detection. It makes blame significantly faster on huge
+	repositories at the expense of less thorough copy detection.
+
+gui.copyBlameThreshold::
+	Specifies the threshold to use in 'git gui blame' original location
+	detection, measured in alphanumeric characters. See the
+	linkgit:git-blame[1] manual for more information on copy detection.
+
+gui.blamehistoryctx::
+	Specifies the radius of history context in days to show in
+	linkgit:gitk[1] for the selected commit, when the `Show History
+	Context` menu item is invoked from 'git gui blame'. If this
+	variable is set to zero, the whole history is shown.
diff --git a/Documentation/config/guitool.adoc b/Documentation/config/guitool.adoc
new file mode 100644
index 0000000000..43fb9466ff
--- /dev/null
+++ b/Documentation/config/guitool.adoc
@@ -0,0 +1,50 @@
+guitool.<name>.cmd::
+	Specifies the shell command line to execute when the corresponding item
+	of the linkgit:git-gui[1] `Tools` menu is invoked. This option is
+	mandatory for every tool. The command is executed from the root of
+	the working directory, and in the environment it receives the name of
+	the tool as `GIT_GUITOOL`, the name of the currently selected file as
+	'FILENAME', and the name of the current branch as 'CUR_BRANCH' (if
+	the head is detached, 'CUR_BRANCH' is empty).
+
+guitool.<name>.needsFile::
+	Run the tool only if a diff is selected in the GUI. It guarantees
+	that 'FILENAME' is not empty.
+
+guitool.<name>.noConsole::
+	Run the command silently, without creating a window to display its
+	output.
+
+guitool.<name>.noRescan::
+	Don't rescan the working directory for changes after the tool
+	finishes execution.
+
+guitool.<name>.confirm::
+	Show a confirmation dialog before actually running the tool.
+
+guitool.<name>.argPrompt::
+	Request a string argument from the user, and pass it to the tool
+	through the `ARGS` environment variable. Since requesting an
+	argument implies confirmation, the 'confirm' option has no effect
+	if this is enabled. If the option is set to 'true', 'yes', or '1',
+	the dialog uses a built-in generic prompt; otherwise the exact
+	value of the variable is used.
+
+guitool.<name>.revPrompt::
+	Request a single valid revision from the user, and set the
+	`REVISION` environment variable. In other aspects this option
+	is similar to 'argPrompt', and can be used together with it.
+
+guitool.<name>.revUnmerged::
+	Show only unmerged branches in the 'revPrompt' subdialog.
+	This is useful for tools similar to merge or rebase, but not
+	for things like checkout or reset.
+
+guitool.<name>.title::
+	Specifies the title to use for the prompt dialog. The default
+	is the tool name.
+
+guitool.<name>.prompt::
+	Specifies the general prompt string to display at the top of
+	the dialog, before subsections for 'argPrompt' and 'revPrompt'.
+	The default value includes the actual command.
diff --git a/Documentation/config/help.adoc b/Documentation/config/help.adoc
new file mode 100644
index 0000000000..610701f9a3
--- /dev/null
+++ b/Documentation/config/help.adoc
@@ -0,0 +1,26 @@
+help.browser::
+	Specify the browser that will be used to display help in the
+	'web' format. See linkgit:git-help[1].
+
+help.format::
+	Override the default help format used by linkgit:git-help[1].
+	Values 'man', 'info', 'web' and 'html' are supported. 'man' is
+	the default. 'web' and 'html' are the same.
+
+help.autoCorrect::
+	If git detects typos and can identify exactly one valid command similar
+	to the error, git will try to suggest the correct command or even
+	run the suggestion automatically. Possible config values are:
+	 - 0 (default): show the suggested command.
+	 - positive number: run the suggested command after specified
+deciseconds (0.1 sec).
+	 - "immediate": run the suggested command immediately.
+	 - "prompt": show the suggestion and prompt for confirmation to run
+the command.
+	 - "never": don't run or show any suggested command.
+
+help.htmlPath::
+	Specify the path where the HTML documentation resides. File system paths
+	and URLs are supported. HTML pages will be prefixed with this path when
+	help is displayed in the 'web' format. This defaults to the documentation
+	path of your Git installation.
diff --git a/Documentation/config/http.adoc b/Documentation/config/http.adoc
new file mode 100644
index 0000000000..a14371b5c9
--- /dev/null
+++ b/Documentation/config/http.adoc
@@ -0,0 +1,355 @@
+http.proxy::
+	Override the HTTP proxy, normally configured using the 'http_proxy',
+	'https_proxy', and 'all_proxy' environment variables (see `curl(1)`). In
+	addition to the syntax understood by curl, it is possible to specify a
+	proxy string with a user name but no password, in which case git will
+	attempt to acquire one in the same way it does for other credentials. See
+	linkgit:gitcredentials[7] for more information. The syntax thus is
+	'[protocol://][user[:password]@]proxyhost[:port][/path]'. This can be
+	overridden on a per-remote basis; see remote.<name>.proxy
++
+Any proxy, however configured, must be completely transparent and must not
+modify, transform, or buffer the request or response in any way.  Proxies which
+are not completely transparent are known to cause various forms of breakage
+with Git.
+
+http.proxyAuthMethod::
+	Set the method with which to authenticate against the HTTP proxy. This
+	only takes effect if the configured proxy string contains a user name part
+	(i.e. is of the form 'user@host' or 'user@host:port'). This can be
+	overridden on a per-remote basis; see `remote.<name>.proxyAuthMethod`.
+	Both can be overridden by the `GIT_HTTP_PROXY_AUTHMETHOD` environment
+	variable.  Possible values are:
++
+--
+* `anyauth` - Automatically pick a suitable authentication method. It is
+  assumed that the proxy answers an unauthenticated request with a 407
+  status code and one or more Proxy-authenticate headers with supported
+  authentication methods. This is the default.
+* `basic` - HTTP Basic authentication
+* `digest` - HTTP Digest authentication; this prevents the password from being
+  transmitted to the proxy in clear text
+* `negotiate` - GSS-Negotiate authentication (compare the --negotiate option
+  of `curl(1)`)
+* `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`)
+--
+
+http.proxySSLCert::
+	The pathname of a file that stores a client certificate to use to authenticate
+	with an HTTPS proxy. Can be overridden by the `GIT_PROXY_SSL_CERT` environment
+	variable.
+
+http.proxySSLKey::
+	The pathname of a file that stores a private key to use to authenticate with
+	an HTTPS proxy. Can be overridden by the `GIT_PROXY_SSL_KEY` environment
+	variable.
+
+http.proxySSLCertPasswordProtected::
+	Enable Git's password prompt for the proxy SSL certificate.  Otherwise OpenSSL
+	will prompt the user, possibly many times, if the certificate or private key
+	is encrypted. Can be overridden by the `GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED`
+	environment variable.
+
+http.proxySSLCAInfo::
+	Pathname to the file containing the certificate bundle that should be used to
+	verify the proxy with when using an HTTPS proxy. Can be overridden by the
+	`GIT_PROXY_SSL_CAINFO` environment variable.
+
+http.emptyAuth::
+	Attempt authentication without seeking a username or password.  This
+	can be used to attempt GSS-Negotiate authentication without specifying
+	a username in the URL, as libcurl normally requires a username for
+	authentication.
+
+http.proactiveAuth::
+	Attempt authentication without first making an unauthenticated attempt and
+	receiving a 401 response. This can be used to ensure that all requests are
+	authenticated. If `http.emptyAuth` is set to true, this value has no effect.
++
+If the credential helper used specifies an authentication scheme (i.e., via the
+`authtype` field), that value will be used; if a username and password is
+provided without a scheme, then Basic authentication is used.  The value of the
+option determines the scheme requested from the helper. Possible values are:
++
+--
+* `basic` - Request Basic authentication from the helper.
+* `auto` - Allow the helper to pick an appropriate scheme.
+* `none` - Disable proactive authentication.
+--
++
+Note that TLS should always be used with this configuration, since otherwise it
+is easy to accidentally expose plaintext credentials if Basic authentication
+is selected.
+
+http.delegation::
+	Control GSSAPI credential delegation. The delegation is disabled
+	by default in libcurl since version 7.21.7. Set parameter to tell
+	the server what it is allowed to delegate when it comes to user
+	credentials. Used with GSS/kerberos. Possible values are:
++
+--
+* `none` - Don't allow any delegation.
+* `policy` - Delegates if and only if the OK-AS-DELEGATE flag is set in the
+  Kerberos service ticket, which is a matter of realm policy.
+* `always` - Unconditionally allow the server to delegate.
+--
+
+
+http.extraHeader::
+	Pass an additional HTTP header when communicating with a server.  If
+	more than one such entry exists, all of them are added as extra
+	headers.  To allow overriding the settings inherited from the system
+	config, an empty value will reset the extra headers to the empty list.
+
+http.cookieFile::
+	The pathname of a file containing previously stored cookie lines,
+	which should be used
+	in the Git http session, if they match the server. The file format
+	of the file to read cookies from should be plain HTTP headers or
+	the Netscape/Mozilla cookie file format (see `curl(1)`).
+	Set it to an empty string, to accept only new cookies from
+	the server and send them back in successive requests within same
+	connection.
+	NOTE that the file specified with http.cookieFile is used only as
+	input unless http.saveCookies is set.
+
+http.saveCookies::
+	If set, store cookies received during requests to the file specified by
+	http.cookieFile. Has no effect if http.cookieFile is unset, or set to
+	an empty string.
+
+http.version::
+	Use the specified HTTP protocol version when communicating with a server.
+	If you want to force the default. The available and default version depend
+	on libcurl. Currently the possible values of
+	this option are:
+
+	- HTTP/2
+	- HTTP/1.1
+
+http.curloptResolve::
+	Hostname resolution information that will be used first by
+	libcurl when sending HTTP requests.  This information should
+	be in one of the following formats:
+
+	- [+]HOST:PORT:ADDRESS[,ADDRESS]
+	- -HOST:PORT
+
++
+The first format redirects all requests to the given `HOST:PORT`
+to the provided `ADDRESS`(s). The second format clears all
+previous config values for that `HOST:PORT` combination.  To
+allow easy overriding of all the settings inherited from the
+system config, an empty value will reset all resolution
+information to the empty list.
+
+http.sslVersion::
+	The SSL version to use when negotiating an SSL connection, if you
+	want to force the default.  The available and default version
+	depend on whether libcurl was built against NSS or OpenSSL and the
+	particular configuration of the crypto library in use. Internally
+	this sets the 'CURLOPT_SSL_VERSION' option; see the libcurl
+	documentation for more details on the format of this option and
+	for the ssl version supported. Currently the possible values of
+	this option are:
+
+	- sslv2
+	- sslv3
+	- tlsv1
+	- tlsv1.0
+	- tlsv1.1
+	- tlsv1.2
+	- tlsv1.3
+
++
+Can be overridden by the `GIT_SSL_VERSION` environment variable.
+To force git to use libcurl's default ssl version and ignore any
+explicit http.sslversion option, set `GIT_SSL_VERSION` to the
+empty string.
+
+http.sslCipherList::
+  A list of SSL ciphers to use when negotiating an SSL connection.
+  The available ciphers depend on whether libcurl was built against
+  NSS or OpenSSL and the particular configuration of the crypto
+  library in use.  Internally this sets the 'CURLOPT_SSL_CIPHER_LIST'
+  option; see the libcurl documentation for more details on the format
+  of this list.
++
+Can be overridden by the `GIT_SSL_CIPHER_LIST` environment variable.
+To force git to use libcurl's default cipher list and ignore any
+explicit http.sslCipherList option, set `GIT_SSL_CIPHER_LIST` to the
+empty string.
+
+http.sslVerify::
+	Whether to verify the SSL certificate when fetching or pushing
+	over HTTPS. Defaults to true. Can be overridden by the
+	`GIT_SSL_NO_VERIFY` environment variable.
+
+http.sslCert::
+	File containing the SSL certificate when fetching or pushing
+	over HTTPS. Can be overridden by the `GIT_SSL_CERT` environment
+	variable.
+
+http.sslKey::
+	File containing the SSL private key when fetching or pushing
+	over HTTPS. Can be overridden by the `GIT_SSL_KEY` environment
+	variable.
+
+http.sslCertPasswordProtected::
+	Enable Git's password prompt for the SSL certificate.  Otherwise
+	OpenSSL will prompt the user, possibly many times, if the
+	certificate or private key is encrypted.  Can be overridden by the
+	`GIT_SSL_CERT_PASSWORD_PROTECTED` environment variable.
+
+http.sslCAInfo::
+	File containing the certificates to verify the peer with when
+	fetching or pushing over HTTPS. Can be overridden by the
+	`GIT_SSL_CAINFO` environment variable.
+
+http.sslCAPath::
+	Path containing files with the CA certificates to verify the peer
+	with when fetching or pushing over HTTPS. Can be overridden
+	by the `GIT_SSL_CAPATH` environment variable.
+
+http.sslBackend::
+	Name of the SSL backend to use (e.g. "openssl" or "schannel").
+	This option is ignored if cURL lacks support for choosing the SSL
+	backend at runtime.
+
+http.schannelCheckRevoke::
+	Used to enforce or disable certificate revocation checks in cURL
+	when http.sslBackend is set to "schannel". Defaults to `true` if
+	unset. Only necessary to disable this if Git consistently errors
+	and the message is about checking the revocation status of a
+	certificate. This option is ignored if cURL lacks support for
+	setting the relevant SSL option at runtime.
+
+http.schannelUseSSLCAInfo::
+	As of cURL v7.60.0, the Secure Channel backend can use the
+	certificate bundle provided via `http.sslCAInfo`, but that would
+	override the Windows Certificate Store. Since this is not desirable
+	by default, Git will tell cURL not to use that bundle by default
+	when the `schannel` backend was configured via `http.sslBackend`,
+	unless `http.schannelUseSSLCAInfo` overrides this behavior.
+
+http.pinnedPubkey::
+	Public key of the https service. It may either be the filename of
+	a PEM or DER encoded public key file or a string starting with
+	'sha256//' followed by the base64 encoded sha256 hash of the
+	public key. See also libcurl 'CURLOPT_PINNEDPUBLICKEY'. git will
+	exit with an error if this option is set but not supported by
+	cURL.
+
+http.sslTry::
+	Attempt to use AUTH SSL/TLS and encrypted data transfers
+	when connecting via regular FTP protocol. This might be needed
+	if the FTP server requires it for security reasons or you wish
+	to connect securely whenever remote FTP server supports it.
+	Default is false since it might trigger certificate verification
+	errors on misconfigured servers.
+
+http.maxRequests::
+	How many HTTP requests to launch in parallel. Can be overridden
+	by the `GIT_HTTP_MAX_REQUESTS` environment variable. Default is 5.
+
+http.minSessions::
+	The number of curl sessions (counted across slots) to be kept across
+	requests. They will not be ended with curl_easy_cleanup() until
+	http_cleanup() is invoked. If USE_CURL_MULTI is not defined, this
+	value will be capped at 1. Defaults to 1.
+
+http.postBuffer::
+	Maximum size in bytes of the buffer used by smart HTTP
+	transports when POSTing data to the remote system.
+	For requests larger than this buffer size, HTTP/1.1 and
+	Transfer-Encoding: chunked is used to avoid creating a
+	massive pack file locally.  Default is 1 MiB, which is
+	sufficient for most requests.
++
+Note that raising this limit is only effective for disabling chunked
+transfer encoding and therefore should be used only where the remote
+server or a proxy only supports HTTP/1.0 or is noncompliant with the
+HTTP standard.  Raising this is not, in general, an effective solution
+for most push problems, but can increase memory consumption
+significantly since the entire buffer is allocated even for small
+pushes.
+
+http.lowSpeedLimit, http.lowSpeedTime::
+	If the HTTP transfer speed, in bytes per second, is less than
+	'http.lowSpeedLimit' for longer than 'http.lowSpeedTime' seconds,
+	the transfer is aborted.
+	Can be overridden by the `GIT_HTTP_LOW_SPEED_LIMIT` and
+	`GIT_HTTP_LOW_SPEED_TIME` environment variables.
+
+http.noEPSV::
+	A boolean which disables using of EPSV ftp command by curl.
+	This can be helpful with some "poor" ftp servers which don't
+	support EPSV mode. Can be overridden by the `GIT_CURL_FTP_NO_EPSV`
+	environment variable. Default is false (curl will use EPSV).
+
+http.userAgent::
+	The HTTP USER_AGENT string presented to an HTTP server.  The default
+	value represents the version of the Git client such as git/1.7.1.
+	This option allows you to override this value to a more common value
+	such as Mozilla/4.0.  This may be necessary, for instance, if
+	connecting through a firewall that restricts HTTP connections to a set
+	of common USER_AGENT strings (but not including those like git/1.7.1).
+	Can be overridden by the `GIT_HTTP_USER_AGENT` environment variable.
+
+http.followRedirects::
+	Whether git should follow HTTP redirects. If set to `true`, git
+	will transparently follow any redirect issued by a server it
+	encounters. If set to `false`, git will treat all redirects as
+	errors. If set to `initial`, git will follow redirects only for
+	the initial request to a remote, but not for subsequent
+	follow-up HTTP requests. Since git uses the redirected URL as
+	the base for the follow-up requests, this is generally
+	sufficient. The default is `initial`.
+
+http.<url>.*::
+	Any of the http.* options above can be applied selectively to some URLs.
+	For a config key to match a URL, each element of the config key is
+	compared to that of the URL, in the following order:
++
+--
+. Scheme (e.g., `https` in `https://example.com/`). This field
+  must match exactly between the config key and the URL.
+
+. Host/domain name (e.g., `example.com` in `https://example.com/`).
+  This field must match between the config key and the URL. It is
+  possible to specify a `*` as part of the host name to match all subdomains
+  at this level. `https://*.example.com/` for example would match
+  `https://foo.example.com/`, but not `https://foo.bar.example.com/`.
+
+. Port number (e.g., `8080` in `http://example.com:8080/`).
+  This field must match exactly between the config key and the URL.
+  Omitted port numbers are automatically converted to the correct
+  default for the scheme before matching.
+
+. Path (e.g., `repo.git` in `https://example.com/repo.git`). The
+  path field of the config key must match the path field of the URL
+  either exactly or as a prefix of slash-delimited path elements.  This means
+  a config key with path `foo/` matches URL path `foo/bar`.  A prefix can only
+  match on a slash (`/`) boundary.  Longer matches take precedence (so a config
+  key with path `foo/bar` is a better match to URL path `foo/bar` than a config
+  key with just path `foo/`).
+
+. User name (e.g., `user` in `https://user@xxxxxxxxxxx/repo.git`). If
+  the config key has a user name it must match the user name in the
+  URL exactly. If the config key does not have a user name, that
+  config key will match a URL with any user name (including none),
+  but at a lower precedence than a config key with a user name.
+--
++
+The list above is ordered by decreasing precedence; a URL that matches
+a config key's path is preferred to one that matches its user name. For example,
+if the URL is `https://user@xxxxxxxxxxx/foo/bar` a config key match of
+`https://example.com/foo` will be preferred over a config key match of
+`https://user@xxxxxxxxxxx`.
++
+All URLs are normalized before attempting any matching (the password part,
+if embedded in the URL, is always ignored for matching purposes) so that
+equivalent URLs that are simply spelled differently will match properly.
+Environment variable settings always override any matches.  The URLs that are
+matched against are those given directly to Git commands.  This means any URLs
+visited as a result of a redirection do not participate in matching.
diff --git a/Documentation/config/i18n.adoc b/Documentation/config/i18n.adoc
new file mode 100644
index 0000000000..6e72fdb45b
--- /dev/null
+++ b/Documentation/config/i18n.adoc
@@ -0,0 +1,10 @@
+i18n.commitEncoding::
+	Character encoding the commit messages are stored in; Git itself
+	does not care per se, but this information is necessary e.g. when
+	importing commits from emails or in the gitk graphical history
+	browser (and possibly in other places in the future or in other
+	porcelains). See e.g. linkgit:git-mailinfo[1]. Defaults to 'utf-8'.
+
+i18n.logOutputEncoding::
+	Character encoding the commit messages are converted to when
+	running 'git log' and friends.
diff --git a/Documentation/config/imap.adoc b/Documentation/config/imap.adoc
new file mode 100644
index 0000000000..3d28f72643
--- /dev/null
+++ b/Documentation/config/imap.adoc
@@ -0,0 +1,44 @@
+imap.folder::
+	The folder to drop the mails into, which is typically the Drafts
+	folder. For example: "INBOX.Drafts", "INBOX/Drafts" or
+	"[Gmail]/Drafts". Required.
+
+imap.tunnel::
+	Command used to set up a tunnel to the IMAP server through which
+	commands will be piped instead of using a direct network connection
+	to the server. Required when imap.host is not set.
+
+imap.host::
+	A URL identifying the server. Use an `imap://` prefix for non-secure
+	connections and an `imaps://` prefix for secure connections.
+	Ignored when imap.tunnel is set, but required otherwise.
+
+imap.user::
+	The username to use when logging in to the server.
+
+imap.pass::
+	The password to use when logging in to the server.
+
+imap.port::
+	An integer port number to connect to on the server.
+	Defaults to 143 for imap:// hosts and 993 for imaps:// hosts.
+	Ignored when imap.tunnel is set.
+
+imap.sslverify::
+	A boolean to enable/disable verification of the server certificate
+	used by the SSL/TLS connection. Default is `true`. Ignored when
+	imap.tunnel is set.
+
+imap.preformattedHTML::
+	A boolean to enable/disable the use of html encoding when sending
+	a patch.  An html encoded patch will be bracketed with <pre>
+	and have a content type of text/html.  Ironically, enabling this
+	option causes Thunderbird to send the patch as a plain/text,
+	format=fixed email.  Default is `false`.
+
+imap.authMethod::
+	Specify the authentication method for authenticating with the IMAP server.
+	If Git was built with the NO_CURL option, or if your curl version is older
+	than 7.34.0, or if you're running git-imap-send with the `--no-curl`
+	option, the only supported method is 'CRAM-MD5'. If this is not set
+	then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
diff --git a/Documentation/config/includeif.adoc b/Documentation/config/includeif.adoc
new file mode 100644
index 0000000000..82fe431c34
--- /dev/null
+++ b/Documentation/config/includeif.adoc
@@ -0,0 +1,6 @@
+include.path::
+includeIf.<condition>.path::
+	Special variables to include other configuration files. See
+	the "CONFIGURATION FILE" section in the main
+	linkgit:git-config[1] documentation,
+	specifically the "Includes" and "Conditional Includes" subsections.
diff --git a/Documentation/config/index.adoc b/Documentation/config/index.adoc
new file mode 100644
index 0000000000..3eff420360
--- /dev/null
+++ b/Documentation/config/index.adoc
@@ -0,0 +1,43 @@
+index.recordEndOfIndexEntries::
+	Specifies whether the index file should include an "End Of Index
+	Entry" section. This reduces index load time on multiprocessor
+	machines but produces a message "ignoring EOIE extension" when
+	reading the index using Git versions before 2.20. Defaults to
+	'true' if index.threads has been explicitly enabled, 'false'
+	otherwise.
+
+index.recordOffsetTable::
+	Specifies whether the index file should include an "Index Entry
+	Offset Table" section. This reduces index load time on
+	multiprocessor machines but produces a message "ignoring IEOT
+	extension" when reading the index using Git versions before 2.20.
+	Defaults to 'true' if index.threads has been explicitly enabled,
+	'false' otherwise.
+
+index.sparse::
+	When enabled, write the index using sparse-directory entries. This
+	has no effect unless `core.sparseCheckout` and
+	`core.sparseCheckoutCone` are both enabled. Defaults to 'false'.
+
+index.threads::
+	Specifies the number of threads to spawn when loading the index.
+	This is meant to reduce index load time on multiprocessor machines.
+	Specifying 0 or 'true' will cause Git to auto-detect the number of
+	CPUs and set the number of threads accordingly. Specifying 1 or
+	'false' will disable multithreading. Defaults to 'true'.
+
+index.version::
+	Specify the version with which new index files should be
+	initialized.  This does not affect existing repositories.
+	If `feature.manyFiles` is enabled, then the default is 4.
+
+index.skipHash::
+	When enabled, do not compute the trailing hash for the index file.
+	This accelerates Git commands that manipulate the index, such as
+	`git add`, `git commit`, or `git status`. Instead of storing the
+	checksum, write a trailing set of bytes with value zero, indicating
+	that the computation was skipped.
++
+If you enable `index.skipHash`, then Git clients older than 2.13.0 will
+refuse to parse the index and Git clients older than 2.40.0 will report an
+error during `git fsck`.
diff --git a/Documentation/config/init.adoc b/Documentation/config/init.adoc
new file mode 100644
index 0000000000..e45b2a8121
--- /dev/null
+++ b/Documentation/config/init.adoc
@@ -0,0 +1,20 @@
+:see-git-init:
+ifndef::git-init[]
+:see-git-init: (See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
+endif::[]
+
+`init.templateDir`::
+	Specify the directory from which templates will be copied. {see-git-init}
+`init.defaultBranch`::
+	Allows overriding the default branch name e.g. when initializing
+	a new repository.
+`init.defaultObjectFormat`::
+	Allows overriding the default object format for new repositories. See
+	`--object-format=` in linkgit:git-init[1]. Both the command line option
+	and the `GIT_DEFAULT_HASH` environment variable take precedence over
+	this config.
+`init.defaultRefFormat`::
+	Allows overriding the default ref storage format for new repositories.
+	See `--ref-format=` in linkgit:git-init[1]. Both the command line
+	option and the `GIT_DEFAULT_REF_FORMAT` environment variable take
+	precedence over this config.
diff --git a/Documentation/config/instaweb.adoc b/Documentation/config/instaweb.adoc
new file mode 100644
index 0000000000..50cb2f7d62
--- /dev/null
+++ b/Documentation/config/instaweb.adoc
@@ -0,0 +1,20 @@
+instaweb.browser::
+	Specify the program that will be used to browse your working
+	repository in gitweb. See linkgit:git-instaweb[1].
+
+instaweb.httpd::
+	The HTTP daemon command-line to start gitweb on your working
+	repository. See linkgit:git-instaweb[1].
+
+instaweb.local::
+	If true the web server started by linkgit:git-instaweb[1] will
+	be bound to the local IP (127.0.0.1).
+
+instaweb.modulePath::
+	The default module path for linkgit:git-instaweb[1] to use
+	instead of /usr/lib/apache2/modules.  Only used if httpd
+	is Apache.
+
+instaweb.port::
+	The port number to bind the gitweb httpd to. See
+	linkgit:git-instaweb[1].
diff --git a/Documentation/config/interactive.adoc b/Documentation/config/interactive.adoc
new file mode 100644
index 0000000000..8b876cb4eb
--- /dev/null
+++ b/Documentation/config/interactive.adoc
@@ -0,0 +1,15 @@
+interactive.singleKey::
+	When set to true, allow the user to provide one-letter input
+	with a single key (i.e., without hitting the Enter key) in
+	interactive commands.  This is currently used by the `--patch`
+	mode of linkgit:git-add[1], linkgit:git-checkout[1],
+	linkgit:git-restore[1], linkgit:git-commit[1],
+	linkgit:git-reset[1], and linkgit:git-stash[1].
+
+interactive.diffFilter::
+	When an interactive command (such as `git add --patch`) shows
+	a colorized diff, git will pipe the diff through the shell
+	command defined by this configuration variable. The command may
+	mark up the diff further for human consumption, provided that it
+	retains a one-to-one correspondence with the lines in the
+	original diff. Defaults to disabled (no filtering).
diff --git a/Documentation/config/log.adoc b/Documentation/config/log.adoc
new file mode 100644
index 0000000000..9003a82191
--- /dev/null
+++ b/Documentation/config/log.adoc
@@ -0,0 +1,64 @@
+log.abbrevCommit::
+	If true, makes linkgit:git-log[1], linkgit:git-show[1], and
+	linkgit:git-whatchanged[1] assume `--abbrev-commit`. You may
+	override this option with `--no-abbrev-commit`.
+
+log.date::
+	Set the default date-time mode for the 'log' command.
+	Setting a value for log.date is similar to using 'git log''s
+	`--date` option.  See linkgit:git-log[1] for details.
++
+If the format is set to "auto:foo" and the pager is in use, format
+"foo" will be used for the date format. Otherwise, "default" will
+be used.
+
+log.decorate::
+	Print out the ref names of any commits that are shown by the log
+	command. If 'short' is specified, the ref name prefixes 'refs/heads/',
+	'refs/tags/' and 'refs/remotes/' will not be printed. If 'full' is
+	specified, the full ref name (including prefix) will be printed.
+	If 'auto' is specified, then if the output is going to a terminal,
+	the ref names are shown as if 'short' were given, otherwise no ref
+	names are shown. This is the same as the `--decorate` option
+	of the `git log`.
+
+log.initialDecorationSet::
+	By default, `git log` only shows decorations for certain known ref
+	namespaces. If 'all' is specified, then show all refs as
+	decorations.
+
+log.excludeDecoration::
+	Exclude the specified patterns from the log decorations. This is
+	similar to the `--decorate-refs-exclude` command-line option, but
+	the config option can be overridden by the `--decorate-refs`
+	option.
+
+log.diffMerges::
+	Set diff format to be used when `--diff-merges=on` is
+	specified, see `--diff-merges` in linkgit:git-log[1] for
+	details. Defaults to `separate`.
+
+log.follow::
+	If `true`, `git log` will act as if the `--follow` option was used when
+	a single <path> is given.  This has the same limitations as `--follow`,
+	i.e. it cannot be used to follow multiple files and does not work well
+	on non-linear history.
+
+log.graphColors::
+	A list of colors, separated by commas, that can be used to draw
+	history lines in `git log --graph`.
+
+log.showRoot::
+	If true, the initial commit will be shown as a big creation event.
+	This is equivalent to a diff against an empty tree.
+	Tools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which
+	normally hide the root commit will now show it. True by default.
+
+log.showSignature::
+	If true, makes linkgit:git-log[1], linkgit:git-show[1], and
+	linkgit:git-whatchanged[1] assume `--show-signature`.
+
+log.mailmap::
+	If true, makes linkgit:git-log[1], linkgit:git-show[1], and
+	linkgit:git-whatchanged[1] assume `--use-mailmap`, otherwise
+	assume `--no-use-mailmap`. True by default.
diff --git a/Documentation/config/lsrefs.adoc b/Documentation/config/lsrefs.adoc
new file mode 100644
index 0000000000..3d88fb0bad
--- /dev/null
+++ b/Documentation/config/lsrefs.adoc
@@ -0,0 +1,9 @@
+lsrefs.unborn::
+	May be "advertise" (the default), "allow", or "ignore". If "advertise",
+	the server will respond to the client sending "unborn" (as described in
+	linkgit:gitprotocol-v2[5]) 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
+	updated atomically (for example), since the administrator could
+	configure "allow", then after a delay, configure "advertise".
diff --git a/Documentation/config/mailinfo.adoc b/Documentation/config/mailinfo.adoc
new file mode 100644
index 0000000000..ec3a5d81f7
--- /dev/null
+++ b/Documentation/config/mailinfo.adoc
@@ -0,0 +1,6 @@
+mailinfo.scissors::
+	If true, makes linkgit:git-mailinfo[1] (and therefore
+	linkgit:git-am[1]) act by default as if the --scissors option
+	was provided on the command-line. When active, this feature
+	removes everything from the message body before a scissors
+	line (i.e. consisting mainly of ">8", "8<" and "-").
diff --git a/Documentation/config/mailmap.adoc b/Documentation/config/mailmap.adoc
new file mode 100644
index 0000000000..48cbc30722
--- /dev/null
+++ b/Documentation/config/mailmap.adoc
@@ -0,0 +1,15 @@
+mailmap.file::
+	The location of an augmenting mailmap file. The default
+	mailmap, located in the root of the repository, is loaded
+	first, then the mailmap file pointed to by this variable.
+	The location of the mailmap file may be in a repository
+	subdirectory, or somewhere outside of the repository itself.
+	See linkgit:git-shortlog[1] and linkgit:git-blame[1].
+
+mailmap.blob::
+	Like `mailmap.file`, but consider the value as a reference to a
+	blob in the repository. If both `mailmap.file` and
+	`mailmap.blob` are given, both are parsed, with entries from
+	`mailmap.file` taking precedence. In a bare repository, this
+	defaults to `HEAD:.mailmap`. In a non-bare repository, it
+	defaults to empty.
diff --git a/Documentation/config/maintenance.adoc b/Documentation/config/maintenance.adoc
new file mode 100644
index 0000000000..72a9d6cf81
--- /dev/null
+++ b/Documentation/config/maintenance.adoc
@@ -0,0 +1,71 @@
+maintenance.auto::
+	This boolean config option controls whether some commands run
+	`git maintenance run --auto` after doing their normal work. Defaults
+	to true.
+
+maintenance.autoDetach::
+	Many Git commands trigger automatic maintenance after they have
+	written data into the repository. This boolean config option
+	controls whether this automatic maintenance shall happen in the
+	foreground or whether the maintenance process shall detach and
+	continue to run in the background.
++
+If unset, the value of `gc.autoDetach` is used as a fallback. Defaults
+to true if both are unset, meaning that the maintenance process will
+detach.
+
+maintenance.strategy::
+	This string config option provides a way to specify one of a few
+	recommended schedules for background maintenance. This only affects
+	which tasks are run during `git maintenance run --schedule=X`
+	commands, provided no `--task=<task>` arguments are provided.
+	Further, if a `maintenance.<task>.schedule` config value is set,
+	then that value is used instead of the one provided by
+	`maintenance.strategy`. The possible strategy strings are:
++
+* `none`: This default setting implies no tasks are run at any schedule.
+* `incremental`: This setting optimizes for performing small maintenance
+  activities that do not delete any data. This does not schedule the `gc`
+  task, but runs the `prefetch` and `commit-graph` tasks hourly, the
+  `loose-objects` and `incremental-repack` tasks daily, and the `pack-refs`
+  task weekly.
+
+maintenance.<task>.enabled::
+	This boolean config option controls whether the maintenance task
+	with name `<task>` is run when no `--task` option is specified to
+	`git maintenance run`. These config values are ignored if a
+	`--task` option exists. By default, only `maintenance.gc.enabled`
+	is true.
+
+maintenance.<task>.schedule::
+	This config option controls whether or not the given `<task>` runs
+	during a `git maintenance run --schedule=<frequency>` command. The
+	value must be one of "hourly", "daily", or "weekly".
+
+maintenance.commit-graph.auto::
+	This integer config option controls how often the `commit-graph` task
+	should be run as part of `git maintenance run --auto`. If zero, then
+	the `commit-graph` task will not run with the `--auto` option. A
+	negative value will force the task to run every time. Otherwise, a
+	positive value implies the command should run when the number of
+	reachable commits that are not in the commit-graph file is at least
+	the value of `maintenance.commit-graph.auto`. The default value is
+	100.
+
+maintenance.loose-objects.auto::
+	This integer config option controls how often the `loose-objects` task
+	should be run as part of `git maintenance run --auto`. If zero, then
+	the `loose-objects` task will not run with the `--auto` option. A
+	negative value will force the task to run every time. Otherwise, a
+	positive value implies the command should run when the number of
+	loose objects is at least the value of `maintenance.loose-objects.auto`.
+	The default value is 100.
+
+maintenance.incremental-repack.auto::
+	This integer config option controls how often the `incremental-repack`
+	task should be run as part of `git maintenance run --auto`. If zero,
+	then the `incremental-repack` task will not run with the `--auto`
+	option. A negative value will force the task to run every time.
+	Otherwise, a positive value implies the command should run when the
+	number of pack-files not in the multi-pack-index is at least the value
+	of `maintenance.incremental-repack.auto`. The default value is 10.
diff --git a/Documentation/config/man.adoc b/Documentation/config/man.adoc
new file mode 100644
index 0000000000..5a0f82cc23
--- /dev/null
+++ b/Documentation/config/man.adoc
@@ -0,0 +1,12 @@
+man.viewer::
+	Specify the programs that may be used to display help in the
+	'man' format. See linkgit:git-help[1].
+
+man.<tool>.cmd::
+	Specify the command to invoke the specified man viewer. The
+	specified command is evaluated in shell with the man page
+	passed as an argument. (See linkgit:git-help[1].)
+
+man.<tool>.path::
+	Override the path for the given tool that may be used to
+	display help in the 'man' format. See linkgit:git-help[1].
diff --git a/Documentation/config/merge.adoc b/Documentation/config/merge.adoc
new file mode 100644
index 0000000000..857de5b40b
--- /dev/null
+++ b/Documentation/config/merge.adoc
@@ -0,0 +1,125 @@
+merge.conflictStyle::
+	Specify the style in which conflicted hunks are written out to
+	working tree files upon merge.  The default is "merge", which
+	shows a `<<<<<<<` conflict marker, changes made by one side,
+	a `=======` marker, changes made by the other side, and then
+	a `>>>>>>>` marker.  An alternate style, "diff3", adds a `|||||||`
+	marker and the original text before the `=======` marker.  The
+	"merge" style tends to produce smaller conflict regions than diff3,
+	both because of the exclusion of the original text, and because
+	when a subset of lines match on the two sides, they are just pulled
+	out of the conflict region.  Another alternate style, "zdiff3", is
+	similar to diff3 but removes matching lines on the two sides from
+	the conflict region when those matching lines appear near either
+	the beginning or end of a conflict region.
+
+merge.defaultToUpstream::
+	If merge is called without any commit argument, merge the upstream
+	branches configured for the current branch by using their last
+	observed values stored in their remote-tracking branches.
+	The values of the `branch.<current branch>.merge` that name the
+	branches at the remote named by `branch.<current branch>.remote`
+	are consulted, and then they are mapped via `remote.<remote>.fetch`
+	to their corresponding remote-tracking branches, and the tips of
+	these tracking branches are merged. Defaults to true.
+
+merge.ff::
+	By default, Git does not create an extra merge commit when merging
+	a commit that is a descendant of the current commit. Instead, the
+	tip of the current branch is fast-forwarded. When set to `false`,
+	this variable tells Git to create an extra merge commit in such
+	a case (equivalent to giving the `--no-ff` option from the command
+	line). When set to `only`, only such fast-forward merges are
+	allowed (equivalent to giving the `--ff-only` option from the
+	command line).
+
+merge.verifySignatures::
+	If true, this is equivalent to the --verify-signatures command
+	line option. See linkgit:git-merge[1] for details.
+
+include::fmt-merge-msg.adoc[]
+
+merge.renameLimit::
+	The number of files to consider in the exhaustive portion of
+	rename detection during a merge.  If not specified, defaults
+	to the value of diff.renameLimit.  If neither
+	merge.renameLimit nor diff.renameLimit are specified,
+	currently defaults to 7000.  This setting has no effect if
+	rename detection is turned off.
+
+merge.renames::
+	Whether Git detects renames.  If set to "false", rename detection
+	is disabled. If set to "true", basic rename detection is enabled.
+	Defaults to the value of diff.renames.
+
+merge.directoryRenames::
+	Whether Git detects directory renames, affecting what happens at
+	merge time to new files added to a directory on one side of
+	history when that directory was renamed on the other side of
+	history.  If merge.directoryRenames is set to "false", directory
+	rename detection is disabled, meaning that such new files will be
+	left behind in the old directory.  If set to "true", directory
+	rename detection is enabled, meaning that such new files will be
+	moved into the new directory.  If set to "conflict", a conflict
+	will be reported for such paths.  If merge.renames is false,
+	merge.directoryRenames is ignored and treated as false.  Defaults
+	to "conflict".
+
+merge.renormalize::
+	Tell Git that canonical representation of files in the
+	repository has changed over time (e.g. earlier commits record
+	text files with CRLF line endings, but recent ones use LF line
+	endings).  In such a repository, Git can convert the data
+	recorded in commits to a canonical form before performing a
+	merge to reduce unnecessary conflicts.  For more information,
+	see section "Merging branches with differing checkin/checkout
+	attributes" in linkgit:gitattributes[5].
+
+merge.stat::
+	Whether to print the diffstat between ORIG_HEAD and the merge result
+	at the end of the merge.  True by default.
+
+merge.autoStash::
+	When set to true, automatically create a temporary stash entry
+	before the operation begins, and apply it after the operation
+	ends.  This means that you can run merge on a dirty worktree.
+	However, use with care: the final stash application after a
+	successful merge might result in non-trivial conflicts.
+	This option can be overridden by the `--no-autostash` and
+	`--autostash` options of linkgit:git-merge[1].
+	Defaults to false.
+
+merge.tool::
+	Controls which merge tool is used by linkgit:git-mergetool[1].
+	The list below shows the valid built-in values.
+	Any other value is treated as a custom merge tool and requires
+	that a corresponding mergetool.<tool>.cmd variable is defined.
+
+merge.guitool::
+	Controls which merge tool is used by linkgit:git-mergetool[1] when the
+	-g/--gui flag is specified. The list below shows the valid built-in values.
+	Any other value is treated as a custom merge tool and requires that a
+	corresponding mergetool.<guitool>.cmd variable is defined.
+
+include::{build_dir}/mergetools-merge.adoc[]
+
+merge.verbosity::
+	Controls the amount of output shown by the recursive merge
+	strategy.  Level 0 outputs nothing except a final error
+	message if conflicts were detected. Level 1 outputs only
+	conflicts, 2 outputs conflicts and file changes.  Level 5 and
+	above outputs debugging information.  The default is level 2.
+	Can be overridden by the `GIT_MERGE_VERBOSITY` environment variable.
+
+merge.<driver>.name::
+	Defines a human-readable name for a custom low-level
+	merge driver.  See linkgit:gitattributes[5] for details.
+
+merge.<driver>.driver::
+	Defines the command that implements a custom low-level
+	merge driver.  See linkgit:gitattributes[5] for details.
+
+merge.<driver>.recursive::
+	Names a low-level merge driver to be used when
+	performing an internal merge between common ancestors.
+	See linkgit:gitattributes[5] for details.
diff --git a/Documentation/config/mergetool.adoc b/Documentation/config/mergetool.adoc
new file mode 100644
index 0000000000..00bf665aa0
--- /dev/null
+++ b/Documentation/config/mergetool.adoc
@@ -0,0 +1,101 @@
+mergetool.<tool>.path::
+	Override the path for the given tool.  This is useful in case
+	your tool is not in the PATH.
+
+mergetool.<tool>.cmd::
+	Specify the command to invoke the specified merge tool.  The
+	specified command is evaluated in shell with the following
+	variables available: 'BASE' is the name of a temporary file
+	containing the common base of the files to be merged, if available;
+	'LOCAL' is the name of a temporary file containing the contents of
+	the file on the current branch; 'REMOTE' is the name of a temporary
+	file containing the contents of the file from the branch being
+	merged; 'MERGED' contains the name of the file to which the merge
+	tool should write the results of a successful merge.
+
+mergetool.<tool>.hideResolved::
+	Allows the user to override the global `mergetool.hideResolved` value
+	for a specific tool. See `mergetool.hideResolved` for the full
+	description.
+
+mergetool.<tool>.trustExitCode::
+	For a custom merge command, specify whether the exit code of
+	the merge command can be used to determine whether the merge was
+	successful.  If this is not set to true then the merge target file
+	timestamp is checked, and the merge is assumed to have been successful
+	if the file has been updated; otherwise, the user is prompted to
+	indicate the success of the merge.
+
+mergetool.meld.hasOutput::
+	Older versions of `meld` do not support the `--output` option.
+	Git will attempt to detect whether `meld` supports `--output`
+	by inspecting the output of `meld --help`.  Configuring
+	`mergetool.meld.hasOutput` will make Git skip these checks and
+	use the configured value instead.  Setting `mergetool.meld.hasOutput`
+	to `true` tells Git to unconditionally use the `--output` option,
+	and `false` avoids using `--output`.
+
+mergetool.meld.useAutoMerge::
+	When the `--auto-merge` is given, meld will merge all non-conflicting
+	parts automatically, highlight the conflicting parts, and wait for
+	user decision.  Setting `mergetool.meld.useAutoMerge` to `true` tells
+	Git to unconditionally use the `--auto-merge` option with `meld`.
+	Setting this value to `auto` makes git detect whether `--auto-merge`
+	is supported and will only use `--auto-merge` when available.  A
+	value of `false` avoids using `--auto-merge` altogether, and is the
+	default value.
+
+mergetool.<vimdiff variant>.layout::
+	Configure the split window layout for vimdiff's `<variant>`, which is any of `vimdiff`,
+	`nvimdiff`, `gvimdiff`.
+	Upon launching `git mergetool` with `--tool=<variant>` (or without `--tool`
+	if `merge.tool` is configured as `<variant>`), Git will consult
+	`mergetool.<variant>.layout` to determine the tool's layout. If the
+	variant-specific configuration is not available, `vimdiff`'s is used as
+	fallback.  If that too is not available, a default layout with 4 windows
+	will be used.  To configure the layout, see the `BACKEND SPECIFIC HINTS`
+ifdef::git-mergetool[]
+	section.
+endif::[]
+ifndef::git-mergetool[]
+	section in linkgit:git-mergetool[1].
+endif::[]
+
+mergetool.hideResolved::
+	During a merge, Git will automatically resolve as many conflicts as
+	possible and write the 'MERGED' file containing conflict markers around
+	any conflicts that it cannot resolve; 'LOCAL' and 'REMOTE' normally
+	represent the versions of the file from before Git's conflict
+	resolution. This flag causes 'LOCAL' and 'REMOTE' to be overwritten so
+	that only the unresolved conflicts are presented to the merge tool. Can
+	be configured per-tool via the `mergetool.<tool>.hideResolved`
+	configuration variable. Defaults to `false`.
+
+mergetool.keepBackup::
+	After performing a merge, the original file with conflict markers
+	can be saved as a file with a `.orig` extension.  If this variable
+	is set to `false` then this file is not preserved.  Defaults to
+	`true` (i.e. keep the backup files).
+
+mergetool.keepTemporaries::
+	When invoking a custom merge tool, Git uses a set of temporary
+	files to pass to the tool. If the tool returns an error and this
+	variable is set to `true`, then these temporary files will be
+	preserved; otherwise, they will be removed after the tool has
+	exited. Defaults to `false`.
+
+mergetool.writeToTemp::
+	Git writes temporary 'BASE', 'LOCAL', and 'REMOTE' versions of
+	conflicting files in the worktree by default.  Git will attempt
+	to use a temporary directory for these files when set `true`.
+	Defaults to `false`.
+
+mergetool.prompt::
+	Prompt before each invocation of the merge resolution program.
+
+mergetool.guiDefault::
+	Set `true` to use the `merge.guitool` by default (equivalent to
+	specifying the `--gui` argument), or `auto` to select `merge.guitool`
+	or `merge.tool` depending on the presence of a `DISPLAY` environment
+	variable value. The default is `false`, where the `--gui` argument
+	must be provided explicitly for the `merge.guitool` to be used.
diff --git a/Documentation/config/notes.adoc b/Documentation/config/notes.adoc
new file mode 100644
index 0000000000..43db8e808d
--- /dev/null
+++ b/Documentation/config/notes.adoc
@@ -0,0 +1,68 @@
+notes.mergeStrategy::
+	Which merge strategy to choose by default when resolving notes
+	conflicts.  Must be one of `manual`, `ours`, `theirs`, `union`, or
+	`cat_sort_uniq`.  Defaults to `manual`.  See the "NOTES MERGE STRATEGIES"
+	section of linkgit:git-notes[1] for more information on each strategy.
++
+This setting can be overridden by passing the `--strategy` option to
+linkgit:git-notes[1].
+
+notes.<name>.mergeStrategy::
+	Which merge strategy to choose when doing a notes merge into
+	refs/notes/<name>.  This overrides the more general
+	"notes.mergeStrategy".  See the "NOTES MERGE STRATEGIES" section in
+	linkgit:git-notes[1] for more information on the available strategies.
+
+notes.displayRef::
+	Which ref (or refs, if a glob or specified more than once), in
+	addition to the default set by `core.notesRef` or
+	`GIT_NOTES_REF`, to read notes from when showing commit
+	messages with the 'git log' family of commands.
++
+This setting can be overridden with the `GIT_NOTES_DISPLAY_REF`
+environment variable, which must be a colon separated list of refs or
+globs.
++
+A warning will be issued for refs that do not exist,
+but a glob that does not match any refs is silently ignored.
++
+This setting can be disabled by the `--no-notes` option to the 'git
+log' family of commands, or by the `--notes=<ref>` option accepted by
+those commands.
++
+The effective value of "core.notesRef" (possibly overridden by
+GIT_NOTES_REF) is also implicitly added to the list of refs to be
+displayed.
+
+notes.rewrite.<command>::
+	When rewriting commits with <command> (currently `amend` or
+	`rebase`), if this variable is `false`, git will not copy
+	notes from the original to the rewritten commit.  Defaults to
+	`true`.  See also "`notes.rewriteRef`" below.
++
+This setting can be overridden with the `GIT_NOTES_REWRITE_REF`
+environment variable, which must be a colon separated list of refs or
+globs.
+
+notes.rewriteMode::
+	When copying notes during a rewrite (see the
+	"notes.rewrite.<command>" option), determines what to do if
+	the target commit already has a note.  Must be one of
+	`overwrite`, `concatenate`, `cat_sort_uniq`, or `ignore`.
+	Defaults to `concatenate`.
++
+This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`
+environment variable.
+
+notes.rewriteRef::
+	When copying notes during a rewrite, specifies the (fully
+	qualified) ref whose notes should be copied.  May be a glob,
+	in which case notes in all matching refs will be copied.  You
+	may also specify this configuration several times.
++
+Does not have a default value; you must configure this variable to
+enable note rewriting.  Set it to `refs/notes/commits` to enable
+rewriting for the default commit notes.
++
+Can be overridden with the `GIT_NOTES_REWRITE_REF` environment variable.
+See `notes.rewrite.<command>` above for a further description of its format.
diff --git a/Documentation/config/pack.adoc b/Documentation/config/pack.adoc
new file mode 100644
index 0000000000..da527377fa
--- /dev/null
+++ b/Documentation/config/pack.adoc
@@ -0,0 +1,207 @@
+pack.window::
+	The size of the window used by linkgit:git-pack-objects[1] when no
+	window size is given on the command line. Defaults to 10.
+
+pack.depth::
+	The maximum delta depth used by linkgit:git-pack-objects[1] when no
+	maximum depth is given on the command line. Defaults to 50.
+	Maximum value is 4095.
+
+pack.windowMemory::
+	The maximum size of memory that is consumed by each thread
+	in linkgit:git-pack-objects[1] for pack window memory when
+	no limit is given on the command line.  The value can be
+	suffixed with "k", "m", or "g".  When left unconfigured (or
+	set explicitly to 0), there will be no limit.
+
+pack.compression::
+	An integer -1..9, indicating the compression level for objects
+	in a pack file. -1 is the zlib default. 0 means no
+	compression, and 1..9 are various speed/size tradeoffs, 9 being
+	slowest.  If not set,  defaults to core.compression.  If that is
+	not set,  defaults to -1, the zlib default, which is "a default
+	compromise between speed and compression (currently equivalent
+	to level 6)."
++
+Note that changing the compression level will not automatically recompress
+all existing objects. You can force recompression by passing the -F option
+to linkgit:git-repack[1].
+
+pack.allowPackReuse::
+	When true or "single", and when reachability bitmaps are
+	enabled, pack-objects will try to send parts of the bitmapped
+	packfile verbatim. When "multi", and when a multi-pack
+	reachability bitmap is available, pack-objects will try to send
+	parts of all packs in the MIDX.
++
+If only a single pack bitmap is available, and `pack.allowPackReuse`
+is set to "multi", reuse parts of just the bitmapped packfile. This
+can reduce memory and CPU usage to serve fetches, but might result in
+sending a slightly larger pack. Defaults to true.
+
+pack.island::
+	An extended regular expression configuring a set of delta
+	islands. See "DELTA ISLANDS" in linkgit:git-pack-objects[1]
+	for details.
+
+pack.islandCore::
+	Specify an island name which gets to have its objects be
+	packed first. This creates a kind of pseudo-pack at the front
+	of one pack, so that the objects from the specified island are
+	hopefully faster to copy into any pack that should be served
+	to a user requesting these objects. In practice this means
+	that the island specified should likely correspond to what is
+	the most commonly cloned in the repo. See also "DELTA ISLANDS"
+	in linkgit:git-pack-objects[1].
+
+pack.deltaCacheSize::
+	The maximum memory in bytes used for caching deltas in
+	linkgit:git-pack-objects[1] before writing them out to a pack.
+	This cache is used to speed up the writing object phase by not
+	having to recompute the final delta result once the best match
+	for all objects is found.  Repacking large repositories on machines
+	which are tight with memory might be badly impacted by this though,
+	especially if this cache pushes the system into swapping.
+	A value of 0 means no limit. The smallest size of 1 byte may be
+	used to virtually disable this cache. Defaults to 256 MiB.
+
+pack.deltaCacheLimit::
+	The maximum size of a delta, that is cached in
+	linkgit:git-pack-objects[1]. This cache is used to speed up the
+	writing object phase by not having to recompute the final delta
+	result once the best match for all objects is found.
+	Defaults to 1000. Maximum value is 65535.
+
+pack.threads::
+	Specifies the number of threads to spawn when searching for best
+	delta matches.  This requires that linkgit:git-pack-objects[1]
+	be compiled with pthreads otherwise this option is ignored with a
+	warning. This is meant to reduce packing time on multiprocessor
+	machines. The required amount of memory for the delta search window
+	is however multiplied by the number of threads.
+	Specifying 0 will cause Git to auto-detect the number of CPUs
+	and set the number of threads accordingly.
+
+pack.indexVersion::
+	Specify the default pack index version.  Valid values are 1 for
+	legacy pack index used by Git versions prior to 1.5.2, and 2 for
+	the new pack index with capabilities for packs larger than 4 GB
+	as well as proper protection against the repacking of corrupted
+	packs.  Version 2 is the default.  Note that version 2 is enforced
+	and this config option is ignored whenever the corresponding pack is
+	larger than 2 GB.
++
+If you have an old Git that does not understand the version 2 `*.idx` file,
+cloning or fetching over a non-native protocol (e.g. "http")
+that will copy both `*.pack` file and corresponding `*.idx` file from the
+other side may give you a repository that cannot be accessed with your
+older version of Git. If the `*.pack` file is smaller than 2 GB, however,
+you can use linkgit:git-index-pack[1] on the *.pack file to regenerate
+the `*.idx` file.
+
+pack.packSizeLimit::
+	The maximum size of a pack.  This setting only affects
+	packing to a file when repacking, i.e. the git:// protocol
+	is unaffected.  It can be overridden by the `--max-pack-size`
+	option of linkgit:git-repack[1].  Reaching this limit results
+	in the creation of multiple packfiles.
++
+Note that this option is rarely useful, and may result in a larger total
+on-disk size (because Git will not store deltas between packs) and
+worse runtime performance (object lookup within multiple packs is
+slower than a single pack, and optimizations like reachability bitmaps
+cannot cope with multiple packs).
++
+If you need to actively run Git using smaller packfiles (e.g., because your
+filesystem does not support large files), this option may help. But if
+your goal is to transmit a packfile over a medium that supports limited
+sizes (e.g., removable media that cannot store the whole repository),
+you are likely better off creating a single large packfile and splitting
+it using a generic multi-volume archive tool (e.g., Unix `split`).
++
+The minimum size allowed is limited to 1 MiB. The default is unlimited.
+Common unit suffixes of 'k', 'm', or 'g' are supported.
+
+pack.useBitmaps::
+	When true, git will use pack bitmaps (if available) when packing
+	to stdout (e.g., during the server side of a fetch). Defaults to
+	true. You should not generally need to turn this off unless
+	you are debugging pack bitmaps.
+
+pack.useBitmapBoundaryTraversal::
+	When true, Git will use an experimental algorithm for computing
+	reachability queries with bitmaps. Instead of building up
+	complete bitmaps for all of the negated tips and then OR-ing
+	them together, consider negated tips with existing bitmaps as
+	additive (i.e. OR-ing them into the result if they exist,
+	ignoring them otherwise), and build up a bitmap at the boundary
+	instead.
++
+When using this algorithm, Git may include too many objects as a result
+of not opening up trees belonging to certain UNINTERESTING commits. This
+inexactness matches the non-bitmap traversal algorithm.
++
+In many cases, this can provide a speed-up over the exact algorithm,
+particularly when there is poor bitmap coverage of the negated side of
+the query.
+
+pack.useSparse::
+	When true, git will default to using the '--sparse' option in
+	'git pack-objects' when the '--revs' option is present. This
+	algorithm only walks trees that appear in paths that introduce new
+	objects. This can have significant performance benefits when
+	computing a pack to send a small change. However, it is possible
+	that extra objects are added to the pack-file if the included
+	commits contain certain types of direct renames. Default is
+	`true`.
+
+pack.preferBitmapTips::
+	When selecting which commits will receive bitmaps, prefer a
+	commit at the tip of any reference that is a suffix of any value
+	of this configuration over any other commits in the "selection
+	window".
++
+Note that setting this configuration to `refs/foo` does not mean that
+the commits at the tips of `refs/foo/bar` and `refs/foo/baz` will
+necessarily be selected. This is because commits are selected for
+bitmaps from within a series of windows of variable length.
++
+If a commit at the tip of any reference which is a suffix of any value
+of this configuration is seen in a window, it is immediately given
+preference over any other commit in that window.
+
+pack.writeBitmaps (deprecated)::
+	This is a deprecated synonym for `repack.writeBitmaps`.
+
+pack.writeBitmapHashCache::
+	When true, git will include a "hash cache" section in the bitmap
+	index (if one is written). This cache can be used to feed git's
+	delta heuristics, potentially leading to better deltas between
+	bitmapped and non-bitmapped objects (e.g., when serving a fetch
+	between an older, bitmapped pack and objects that have been
+	pushed since the last gc). The downside is that it consumes 4
+	bytes per object of disk space. Defaults to true.
++
+When writing a multi-pack reachability bitmap, no new namehashes are
+computed; instead, any namehashes stored in an existing bitmap are
+permuted into their appropriate location when writing a new bitmap.
+
+pack.writeBitmapLookupTable::
+	When true, Git will include a "lookup table" section in the
+	bitmap index (if one is written). This table is used to defer
+	loading individual bitmaps as late as possible. This can be
+	beneficial in repositories that have relatively large bitmap
+	indexes. Defaults to false.
+
+pack.readReverseIndex::
+	When true, git will read any .rev file(s) that may be available
+	(see: linkgit:gitformat-pack[5]). When false, the reverse index
+	will be generated from scratch and stored in memory. Defaults to
+	true.
+
+pack.writeReverseIndex::
+	When true, git will write a corresponding .rev file (see:
+	linkgit:gitformat-pack[5])
+	for each new packfile that it writes in all places except for
+	linkgit:git-fast-import[1] and in the bulk checkin mechanism.
+	Defaults to true.
diff --git a/Documentation/config/pager.adoc b/Documentation/config/pager.adoc
new file mode 100644
index 0000000000..d3731cf66c
--- /dev/null
+++ b/Documentation/config/pager.adoc
@@ -0,0 +1,8 @@
+pager.<cmd>::
+	If the value is boolean, turns on or off pagination of the
+	output of a particular Git subcommand when writing to a tty.
+	Otherwise, turns on pagination for the subcommand using the
+	pager specified by the value of `pager.<cmd>`.  If `--paginate`
+	or `--no-pager` is specified on the command line, it takes
+	precedence over this option.  To disable pagination for all
+	commands, set `core.pager` or `GIT_PAGER` to `cat`.
diff --git a/Documentation/config/pretty.adoc b/Documentation/config/pretty.adoc
new file mode 100644
index 0000000000..063c6b63d9
--- /dev/null
+++ b/Documentation/config/pretty.adoc
@@ -0,0 +1,9 @@
+pretty.<name>::
+	Alias for a --pretty= format string, as specified in
+	linkgit:git-log[1]. Any aliases defined here can be used just
+	as the built-in pretty formats could. For example,
+	running `git config pretty.changelog "format:* %H %s"`
+	would cause the invocation `git log --pretty=changelog`
+	to be equivalent to running `git log "--pretty=format:* %H %s"`.
+	Note that an alias with the same name as a built-in format
+	will be silently ignored.
diff --git a/Documentation/config/promisor.adoc b/Documentation/config/promisor.adoc
new file mode 100644
index 0000000000..98c5cb2ec2
--- /dev/null
+++ b/Documentation/config/promisor.adoc
@@ -0,0 +1,3 @@
+promisor.quiet::
+	If set to "true" assume `--quiet` when fetching additional
+	objects for a partial clone.
diff --git a/Documentation/config/protocol.adoc b/Documentation/config/protocol.adoc
new file mode 100644
index 0000000000..a9bf187a93
--- /dev/null
+++ b/Documentation/config/protocol.adoc
@@ -0,0 +1,63 @@
+protocol.allow::
+	If set, provide a user defined default policy for all protocols which
+	don't explicitly have a policy (`protocol.<name>.allow`).  By default,
+	if unset, known-safe protocols (http, https, git, ssh) have a
+	default policy of `always`, known-dangerous protocols (ext) have a
+	default policy of `never`, and all other protocols (including file)
+	have a default policy of `user`.  Supported policies:
++
+--
+
+* `always` - protocol is always able to be used.
+
+* `never` - protocol is never able to be used.
+
+* `user` - protocol is only able to be used when `GIT_PROTOCOL_FROM_USER` is
+  either unset or has a value of 1.  This policy should be used when you want a
+  protocol to be directly usable by the user but don't want it used by commands which
+  execute clone/fetch/push commands without user input, e.g. recursive
+  submodule initialization.
+
+--
+
+protocol.<name>.allow::
+	Set a policy to be used by protocol `<name>` with clone/fetch/push
+	commands. See `protocol.allow` above for the available policies.
++
+The protocol names currently used by git are:
++
+--
+  - `file`: any local file-based path (including `file://` URLs,
+    or local paths)
+
+  - `git`: the anonymous git protocol over a direct TCP
+    connection (or proxy, if configured)
+
+  - `ssh`: git over ssh (including `host:path` syntax,
+    `ssh://`, etc).
+
+  - `http`: git over http, both "smart http" and "dumb http".
+    Note that this does _not_ include `https`; if you want to configure
+    both, you must do so individually.
+
+  - any external helpers are named by their protocol (e.g., use
+    `hg` to allow the `git-remote-hg` helper)
+--
+
+protocol.version::
+	If set, clients will attempt to communicate with a server
+	using the specified protocol version.  If the server does
+	not support it, communication falls back to version 0.
+	If unset, the default is `2`.
+	Supported versions:
++
+--
+
+* `0` - the original wire protocol.
+
+* `1` - the original wire protocol with the addition of a version string
+  in the initial response from the server.
+
+* `2` - Wire protocol version 2, see linkgit:gitprotocol-v2[5].
+
+--
diff --git a/Documentation/config/pull.adoc b/Documentation/config/pull.adoc
new file mode 100644
index 0000000000..9349e09261
--- /dev/null
+++ b/Documentation/config/pull.adoc
@@ -0,0 +1,33 @@
+pull.ff::
+	By default, Git does not create an extra merge commit when merging
+	a commit that is a descendant of the current commit. Instead, the
+	tip of the current branch is fast-forwarded. When set to `false`,
+	this variable tells Git to create an extra merge commit in such
+	a case (equivalent to giving the `--no-ff` option from the command
+	line). When set to `only`, only such fast-forward merges are
+	allowed (equivalent to giving the `--ff-only` option from the
+	command line). This setting overrides `merge.ff` when pulling.
+
+pull.rebase::
+	When true, rebase branches on top of the fetched branch, instead
+	of merging the default branch from the default remote when "git
+	pull" is run. See "branch.<name>.rebase" for setting this on a
+	per-branch basis.
++
+When `merges` (or just 'm'), pass the `--rebase-merges` option to 'git rebase'
+so that the local merge commits are included in the rebase (see
+linkgit:git-rebase[1] for details).
++
+When the value is `interactive` (or just 'i'), the rebase is run in interactive
+mode.
++
+*NOTE*: this is a possibly dangerous operation; do *not* use
+it unless you understand the implications (see linkgit:git-rebase[1]
+for details).
+
+pull.octopus::
+	The default merge strategy to use when pulling multiple branches
+	at once.
+
+pull.twohead::
+	The default merge strategy to use when pulling a single branch.
diff --git a/Documentation/config/push.adoc b/Documentation/config/push.adoc
new file mode 100644
index 0000000000..0acbbea18a
--- /dev/null
+++ b/Documentation/config/push.adoc
@@ -0,0 +1,134 @@
+push.autoSetupRemote::
+	If set to "true" assume `--set-upstream` on default push when no
+	upstream tracking exists for the current branch; this option
+	takes effect with push.default options 'simple', 'upstream',
+	and 'current'. It is useful if by default you want new branches
+	to be pushed to the default remote (like the behavior of
+	'push.default=current') and you also want the upstream tracking
+	to be set. Workflows most likely to benefit from this option are
+	'simple' central workflows where all branches are expected to
+	have the same name on the remote.
+
+push.default::
+	Defines the action `git push` should take if no refspec is
+	given (whether from the command-line, config, or elsewhere).
+	Different values are well-suited for
+	specific workflows; for instance, in a purely central workflow
+	(i.e. the fetch source is equal to the push destination),
+	`upstream` is probably what you want.  Possible values are:
++
+--
+
+* `nothing` - do not push anything (error out) unless a refspec is
+  given. This is primarily meant for people who want to
+  avoid mistakes by always being explicit.
+
+* `current` - push the current branch to update a branch with the same
+  name on the receiving end.  Works in both central and non-central
+  workflows.
+
+* `upstream` - push the current branch back to the branch whose
+  changes are usually integrated into the current branch (which is
+  called `@{upstream}`).  This mode only makes sense if you are
+  pushing to the same repository you would normally pull from
+  (i.e. central workflow).
+
+* `tracking` - This is a deprecated synonym for `upstream`.
+
+* `simple` - push the current branch with the same name on the remote.
++
+If you are working on a centralized workflow (pushing to the same repository you
+pull from, which is typically `origin`), then you need to configure an upstream
+branch with the same name.
++
+This mode is the default since Git 2.0, and is the safest option suited for
+beginners.
+
+* `matching` - push all branches having the same name on both ends.
+  This makes the repository you are pushing to remember the set of
+  branches that will be pushed out (e.g. if you always push 'maint'
+  and 'master' there and no other branches, the repository you push
+  to will have these two branches, and your local 'maint' and
+  'master' will be pushed there).
++
+To use this mode effectively, you have to make sure _all_ the
+branches you would push out are ready to be pushed out before
+running 'git push', as the whole point of this mode is to allow you
+to push all of the branches in one go.  If you usually finish work
+on only one branch and push out the result, while other branches are
+unfinished, this mode is not for you.  Also this mode is not
+suitable for pushing into a shared central repository, as other
+people may add new branches there, or update the tip of existing
+branches outside your control.
++
+This used to be the default, but not since Git 2.0 (`simple` is the
+new default).
+
+--
+
+push.followTags::
+	If set to true, enable `--follow-tags` option by default.  You
+	may override this configuration at time of push by specifying
+	`--no-follow-tags`.
+
+push.gpgSign::
+	May be set to a boolean value, or the string 'if-asked'. A true
+	value causes all pushes to be GPG signed, as if `--signed` is
+	passed to linkgit:git-push[1]. The string 'if-asked' causes
+	pushes to be signed if the server supports it, as if
+	`--signed=if-asked` is passed to 'git push'. A false value may
+	override a value from a lower-priority config file. An explicit
+	command-line flag always overrides this config option.
+
+push.pushOption::
+	When no `--push-option=<option>` argument is given from the
+	command line, `git push` behaves as if each <value> of
+	this variable is given as `--push-option=<value>`.
++
+This is a multi-valued variable, and an empty value can be used in a
+higher priority configuration file (e.g. `.git/config` in a
+repository) to clear the values inherited from a lower priority
+configuration files (e.g. `$HOME/.gitconfig`).
++
+----
+
+Example:
+
+/etc/gitconfig
+  push.pushoption = a
+  push.pushoption = b
+
+~/.gitconfig
+  push.pushoption = c
+
+repo/.git/config
+  push.pushoption =
+  push.pushoption = b
+
+This will result in only b (a and c are cleared).
+
+----
+
+push.recurseSubmodules::
+	May be "check", "on-demand", "only", or "no", with the same behavior
+	as that of "push --recurse-submodules".
+	If not set, 'no' is used by default, unless 'submodule.recurse' is
+	set (in which case a 'true' value means 'on-demand').
+
+push.useForceIfIncludes::
+	If set to "true", it is equivalent to specifying
+	`--force-if-includes` as an option to linkgit:git-push[1]
+	in the command line. Adding `--no-force-if-includes` at the
+	time of push overrides this configuration setting.
+
+push.negotiate::
+	If set to "true", attempt to reduce the size of the packfile
+	sent by rounds of negotiation in which the client and the
+	server attempt to find commits in common. If "false", Git will
+	rely solely on the server's ref advertisement to find commits
+	in common.
+
+push.useBitmaps::
+	If set to "false", disable use of bitmaps for "git push" even if
+	`pack.useBitmaps` is "true", without preventing other git operations
+	from using bitmaps. Default is true.
diff --git a/Documentation/config/rebase.adoc b/Documentation/config/rebase.adoc
new file mode 100644
index 0000000000..c6187ab28b
--- /dev/null
+++ b/Documentation/config/rebase.adoc
@@ -0,0 +1,87 @@
+rebase.backend::
+	Default backend to use for rebasing.  Possible choices are
+	'apply' or 'merge'.  In the future, if the merge backend gains
+	all remaining capabilities of the apply backend, this setting
+	may become unused.
+
+rebase.stat::
+	Whether to show a diffstat of what changed upstream since the last
+	rebase. False by default.
+
+rebase.autoSquash::
+	If set to true, enable the `--autosquash` option of
+	linkgit:git-rebase[1] by default for interactive mode.
+	This can be overridden with the `--no-autosquash` option.
+
+rebase.autoStash::
+	When set to true, automatically create a temporary stash entry
+	before the operation begins, and apply it after the operation
+	ends.  This means that you can run rebase on a dirty worktree.
+	However, use with care: the final stash application after a
+	successful rebase might result in non-trivial conflicts.
+	This option can be overridden by the `--no-autostash` and
+	`--autostash` options of linkgit:git-rebase[1].
+	Defaults to false.
+
+rebase.updateRefs::
+	If set to true enable `--update-refs` option by default.
+
+rebase.missingCommitsCheck::
+	If set to "warn", git rebase -i will print a warning if some
+	commits are removed (e.g. a line was deleted), however the
+	rebase will still proceed. If set to "error", it will print
+	the previous warning and stop the rebase, 'git rebase
+	--edit-todo' can then be used to correct the error. If set to
+	"ignore", no checking is done.
+	To drop a commit without warning or error, use the `drop`
+	command in the todo list.
+	Defaults to "ignore".
+
+rebase.instructionFormat::
+	A format string, as specified in linkgit:git-log[1], to be used for the
+	todo list during an interactive rebase.  The format will
+	automatically have the commit hash prepended to the format.
+
+rebase.abbreviateCommands::
+	If set to true, `git rebase` will use abbreviated command names in the
+	todo list resulting in something like this:
++
+-------------------------------------------
+	p deadbee The oneline of the commit
+	p fa1afe1 The oneline of the next commit
+	...
+-------------------------------------------
++
+instead of:
++
+-------------------------------------------
+	pick deadbee The oneline of the commit
+	pick fa1afe1 The oneline of the next commit
+	...
+-------------------------------------------
++
+Defaults to false.
+
+rebase.rescheduleFailedExec::
+	Automatically reschedule `exec` commands that failed. This only makes
+	sense in interactive mode (or when an `--exec` option was provided).
+	This is the same as specifying the `--reschedule-failed-exec` option.
+
+rebase.forkPoint::
+	If set to false set `--no-fork-point` option by default.
+
+rebase.rebaseMerges::
+	Whether and how to set the `--rebase-merges` option by default. Can
+	be `rebase-cousins`, `no-rebase-cousins`, or a boolean. Setting to
+	true or to `no-rebase-cousins` is equivalent to
+	`--rebase-merges=no-rebase-cousins`, setting to `rebase-cousins` is
+	equivalent to `--rebase-merges=rebase-cousins`, and setting to false is
+	equivalent to `--no-rebase-merges`. Passing `--rebase-merges` on the
+	command line, with or without an argument, overrides any
+	`rebase.rebaseMerges` configuration.
+
+rebase.maxLabelLength::
+	When generating label names from commit subjects, truncate the names to
+	this length. By default, the names are truncated to a little less than
+	`NAME_MAX` (to allow e.g. `.lock` files to be written for the
+	corresponding loose refs).
diff --git a/Documentation/config/receive.adoc b/Documentation/config/receive.adoc
new file mode 100644
index 0000000000..36a1e6f2d2
--- /dev/null
+++ b/Documentation/config/receive.adoc
@@ -0,0 +1,145 @@
+receive.advertiseAtomic::
+	By default, git-receive-pack will advertise the atomic push
+	capability to its clients. If you don't want to advertise this
+	capability, set this variable to false.
+
+receive.advertisePushOptions::
+	When set to true, git-receive-pack will advertise the push options
+	capability to its clients. False by default.
+
+receive.autogc::
+	By default, git-receive-pack will run "git maintenance run --auto" after
+	receiving data from git-push and updating refs.  You can stop
+	it by setting this variable to false.
+
+receive.certNonceSeed::
+	By setting this variable to a string, `git receive-pack`
+	will accept a `git push --signed` and verify it by using
+	a "nonce" protected by HMAC using this string as a secret
+	key.
+
+receive.certNonceSlop::
+	When a `git push --signed` sends a push certificate with a
+	"nonce" that was issued by a receive-pack serving the same
+	repository within this many seconds, export the "nonce"
+	found in the certificate to `GIT_PUSH_CERT_NONCE` to the
+	hooks (instead of what the receive-pack asked the sending
+	side to include).  This may allow writing checks in
+	`pre-receive` and `post-receive` a bit easier.  Instead of
+	checking `GIT_PUSH_CERT_NONCE_SLOP` environment variable
+	that records by how many seconds the nonce is stale to
+	decide if they want to accept the certificate, they only
+	can check `GIT_PUSH_CERT_NONCE_STATUS` is `OK`.
+
+receive.fsckObjects::
+	If it is set to true, git-receive-pack will check all received
+	objects. See `transfer.fsckObjects` for what's checked.
+	Defaults to false. If not set, the value of
+	`transfer.fsckObjects` is used instead.
+
+receive.fsck.<msg-id>::
+	Acts like `fsck.<msg-id>`, but is used by
+	linkgit:git-receive-pack[1] instead of
+	linkgit:git-fsck[1]. See the `fsck.<msg-id>` documentation for
+	details.
+
+receive.fsck.skipList::
+	Acts like `fsck.skipList`, but is used by
+	linkgit:git-receive-pack[1] instead of
+	linkgit:git-fsck[1]. See the `fsck.skipList` documentation for
+	details.
+
+receive.keepAlive::
+	After receiving the pack from the client, `receive-pack` may
+	produce no output (if `--quiet` was specified) while processing
+	the pack, causing some networks to drop the TCP connection.
+	With this option set, if `receive-pack` does not transmit
+	any data in this phase for `receive.keepAlive` seconds, it will
+	send a short keepalive packet.  The default is 5 seconds; set
+	to 0 to disable keepalives entirely.
+
+receive.unpackLimit::
+	If the number of objects received in a push is below this
+	limit then the objects will be unpacked into loose object
+	files. However if the number of received objects equals or
+	exceeds this limit then the received pack will be stored as
+	a pack, after adding any missing delta bases.  Storing the
+	pack from a push can make the push operation complete faster,
+	especially on slow filesystems.  If not set, the value of
+	`transfer.unpackLimit` is used instead.
+
+receive.maxInputSize::
+	If the size of the incoming pack stream is larger than this
+	limit, then git-receive-pack will error out, instead of
+	accepting the pack file. If not set or set to 0, then the size
+	is unlimited.
+
+receive.denyDeletes::
+	If set to true, git-receive-pack will deny a ref update that deletes
+	the ref. Use this to prevent such a ref deletion via a push.
+
+receive.denyDeleteCurrent::
+	If set to true, git-receive-pack will deny a ref update that
+	deletes the currently checked out branch of a non-bare repository.
+
+receive.denyCurrentBranch::
+	If set to true or "refuse", git-receive-pack will deny a ref update
+	to the currently checked out branch of a non-bare repository.
+	Such a push is potentially dangerous because it brings the HEAD
+	out of sync with the index and working tree. If set to "warn",
+	print a warning of such a push to stderr, but allow the push to
+	proceed. If set to false or "ignore", allow such pushes with no
+	message. Defaults to "refuse".
++
+Another option is "updateInstead" which will update the working
+tree if pushing into the current branch.  This option is
+intended for synchronizing working directories when one side is not easily
+accessible via interactive ssh (e.g. a live web site, hence the requirement
+that the working directory be clean). This mode also comes in handy when
+developing inside a VM to test and fix code on different Operating Systems.
++
+By default, "updateInstead" will refuse the push if the working tree or
+the index have any difference from the HEAD, but the `push-to-checkout`
+hook can be used to customize this.  See linkgit:githooks[5].
+
+receive.denyNonFastForwards::
+	If set to true, git-receive-pack will deny a ref update which is
+	not a fast-forward. Use this to prevent such an update via a push,
+	even if that push is forced. This configuration variable is
+	set when initializing a shared repository.
+
+receive.hideRefs::
+	This variable is the same as `transfer.hideRefs`, but applies
+	only to `receive-pack` (and so affects pushes, but not fetches).
+	An attempt to update or delete a hidden ref by `git push` is
+	rejected.
+
+receive.procReceiveRefs::
+	This is a multi-valued variable that defines reference prefixes
+	to match the commands in `receive-pack`.  Commands matching the
+	prefixes will be executed by an external hook "proc-receive",
+	instead of the internal `execute_commands` function.  If this
+	variable is not defined, the "proc-receive" hook will never be
+	used, and all commands will be executed by the internal
+	`execute_commands` function.
++
+For example, if this variable is set to "refs/for", pushing to reference
+such as "refs/for/master" will not create or update a reference named
+"refs/for/master", but may create or update a pull request directly by
+running the hook "proc-receive".
++
+Optional modifiers can be provided in the beginning of the value to filter
+commands for specific actions: create (a), modify (m), delete (d).
+A `!` can be included in the modifiers to negate the reference prefix entry.
+E.g.:
++
+	git config --system --add receive.procReceiveRefs ad:refs/heads
+	git config --system --add receive.procReceiveRefs !:refs/heads
+
+receive.updateServerInfo::
+	If set to true, git-receive-pack will run git-update-server-info
+	after receiving data from git-push and updating refs.
+
+receive.shallowUpdate::
+	If set to true, .git/shallow can be updated when new refs
+	require new shallow roots. Otherwise those refs are rejected.
diff --git a/Documentation/config/reftable.adoc b/Documentation/config/reftable.adoc
new file mode 100644
index 0000000000..57087803a5
--- /dev/null
+++ b/Documentation/config/reftable.adoc
@@ -0,0 +1,56 @@
+reftable.blockSize::
+	The size in bytes used by the reftable backend when writing blocks.
+	The block size is determined by the writer, and does not have to be a
+	power of 2. The block size must be larger than the longest reference
+	name or log entry used in the repository, as references cannot span
+	blocks.
++
+Powers of two that are friendly to the virtual memory system or
+filesystem (such as 4kB or 8kB) are recommended. Larger sizes (64kB) can
+yield better compression, with a possible increased cost incurred by
+readers during access.
++
+The largest block size is `16777215` bytes (15.99 MiB). The default value is
+`4096` bytes (4kB). A value of `0` will use the default value.
+
+reftable.restartInterval::
+	The interval at which to create restart points. The reftable backend
+	determines the restart points at file creation. Every 16 may be
+	more suitable for smaller block sizes (4k or 8k), every 64 for larger
+	block sizes (64k).
++
+More frequent restart points reduces prefix compression and increases
+space consumed by the restart table, both of which increase file size.
++
+Less frequent restart points makes prefix compression more effective,
+decreasing overall file size, with increased penalties for readers
+walking through more records after the binary search step.
++
+A maximum of `65535` restart points per block is supported.
++
+The default value is to create restart points every 16 records. A value of `0`
+will use the default value.
+
+reftable.indexObjects::
+	Whether the reftable backend shall write object blocks. Object blocks
+	are a reverse mapping of object ID to the references pointing to them.
++
+The default value is `true`.
+
+reftable.geometricFactor::
+	Whenever the reftable backend appends a new table to the stack, it
+	performs auto compaction to ensure that there is only a handful of
+	tables. The backend does this by ensuring that tables form a geometric
+	sequence regarding the respective sizes of each table.
++
+By default, the geometric sequence uses a factor of 2, meaning that for any
+table, the next-biggest table must at least be twice as big. A maximum factor
+of 256 is supported.
+
+reftable.lockTimeout::
+	Whenever the reftable backend appends a new table to the stack, it has
+	to lock the central "tables.list" file before updating it. This config
+	controls how long the process will wait to acquire the lock in case
+	another process has already acquired it. Value 0 means not to retry at
+	all; -1 means to try indefinitely. Default is 100 (i.e., retry for
+	100ms).
diff --git a/Documentation/config/remote.adoc b/Documentation/config/remote.adoc
new file mode 100644
index 0000000000..4118c219c1
--- /dev/null
+++ b/Documentation/config/remote.adoc
@@ -0,0 +1,121 @@
+remote.pushDefault::
+	The remote to push to by default.  Overrides
+	`branch.<name>.remote` for all branches, and is overridden by
+	`branch.<name>.pushRemote` for specific branches.
+
+remote.<name>.url::
+	The URL of a remote repository.  See linkgit:git-fetch[1] or
+	linkgit:git-push[1]. A configured remote can have multiple URLs;
+	in this case the first is used for fetching, and all are used
+	for pushing (assuming no `remote.<name>.pushurl` is defined).
+	Setting this key to the empty string clears the list of urls,
+	allowing you to override earlier config.
+
+remote.<name>.pushurl::
+	The push URL of a remote repository.  See linkgit:git-push[1].
+	If a `pushurl` option is present in a configured remote, it
+	is used for pushing instead of `remote.<name>.url`. A configured
+	remote can have multiple push URLs; in this case a push goes to
+	all of them. Setting this key to the empty string clears the
+	list of urls, allowing you to override earlier config.
+
+remote.<name>.proxy::
+	For remotes that require curl (http, https and ftp), the URL to
+	the proxy to use for that remote.  Set to the empty string to
+	disable proxying for that remote.
+
+remote.<name>.proxyAuthMethod::
+	For remotes that require curl (http, https and ftp), the method to use for
+	authenticating against the proxy in use (probably set in
+	`remote.<name>.proxy`). See `http.proxyAuthMethod`.
+
+remote.<name>.fetch::
+	The default set of "refspec" for linkgit:git-fetch[1]. See
+	linkgit:git-fetch[1].
+
+remote.<name>.push::
+	The default set of "refspec" for linkgit:git-push[1]. See
+	linkgit:git-push[1].
+
+remote.<name>.mirror::
+	If true, pushing to this remote will automatically behave
+	as if the `--mirror` option was given on the command line.
+
+remote.<name>.skipDefaultUpdate::
+	A deprecated synonym to `remote.<name>.skipFetchAll` (if
+	both are set in the configuration files with different
+	values, the value of the last occurrence will be used).
+
+remote.<name>.skipFetchAll::
+	If true, this remote will be skipped when updating
+	using linkgit:git-fetch[1], the `update` subcommand of
+	linkgit:git-remote[1], and ignored by the prefetch task
+	of `git maintenance`.
+
+remote.<name>.receivepack::
+	The default program to execute on the remote side when pushing.  See
+	option --receive-pack of linkgit:git-push[1].
+
+remote.<name>.uploadpack::
+	The default program to execute on the remote side when fetching.  See
+	option --upload-pack of linkgit:git-fetch-pack[1].
+
+remote.<name>.tagOpt::
+	Setting this value to --no-tags disables automatic tag following when
+	fetching from remote <name>. Setting it to --tags will fetch every
+	tag from remote <name>, even if they are not reachable from remote
+	branch heads. Passing these flags directly to linkgit:git-fetch[1] can
+	override this setting. See options --tags and --no-tags of
+	linkgit:git-fetch[1].
+
+remote.<name>.vcs::
+	Setting this to a value <vcs> will cause Git to interact with
+	the remote with the git-remote-<vcs> helper.
+
+remote.<name>.prune::
+	When set to true, fetching from this remote by default will also
+	remove any remote-tracking references that no longer exist on the
+	remote (as if the `--prune` option was given on the command line).
+	Overrides `fetch.prune` settings, if any.
+
+remote.<name>.pruneTags::
+	When set to true, fetching from this remote by default will also
+	remove any local tags that no longer exist on the remote if pruning
+	is activated in general via `remote.<name>.prune`, `fetch.prune` or
+	`--prune`. Overrides `fetch.pruneTags` settings, if any.
++
+See also `remote.<name>.prune` and the PRUNING section of
+linkgit:git-fetch[1].
+
+remote.<name>.promisor::
+	When set to true, this remote will be used to fetch promisor
+	objects.
+
+remote.<name>.partialclonefilter::
+	The filter that will be applied when fetching from this	promisor remote.
+	Changing or clearing this value will only affect fetches for new commits.
+	To fetch associated objects for commits already present in the local object
+	database, use the `--refetch` option of linkgit:git-fetch[1].
+
+remote.<name>.serverOption::
+	The default set of server options used when fetching from this remote.
+	These server options can be overridden by the `--server-option=` command
+	line arguments.
+
+remote.<name>.followRemoteHEAD::
+	How linkgit:git-fetch[1] should handle updates to `remotes/<name>/HEAD`.
+	The default value is "create", which will create `remotes/<name>/HEAD`
+	if it exists on the remote, but not locally, but will not touch an
+	already existing local reference. Setting to "warn" will print
+	a message if the remote has a different value, than the local one and
+	in case there is no local reference, it behaves like "create".
+	A variant on "warn" is "warn-if-not-$branch", which behaves like
+	"warn", but if `HEAD` on the remote is `$branch` it will be silent.
+	Setting to "always" will silently update it to the value on the remote.
+	Finally, setting it to "never" will never change or create the local
+	reference.
++
+This is a multi-valued variable, and an empty value can be used in a higher
+priority configuration file (e.g. `.git/config` in a repository) to clear
+the values inherited from a lower priority configuration files (e.g.
+`$HOME/.gitconfig`).
diff --git a/Documentation/config/remotes.adoc b/Documentation/config/remotes.adoc
new file mode 100644
index 0000000000..4cfe03221e
--- /dev/null
+++ b/Documentation/config/remotes.adoc
@@ -0,0 +1,3 @@
+remotes.<group>::
+	The list of remotes which are fetched by "git remote update
+	<group>".  See linkgit:git-remote[1].
diff --git a/Documentation/config/repack.adoc b/Documentation/config/repack.adoc
new file mode 100644
index 0000000000..c79af6d7b8
--- /dev/null
+++ b/Documentation/config/repack.adoc
@@ -0,0 +1,41 @@
+repack.useDeltaBaseOffset::
+	By default, linkgit:git-repack[1] creates packs that use
+	delta-base offset. If you need to share your repository with
+	Git older than version 1.4.4, either directly or via a dumb
+	protocol such as http, then you need to set this option to
+	"false" and repack. Access from old Git versions over the
+	native protocol are unaffected by this option.
+
+repack.packKeptObjects::
+	If set to true, makes `git repack` act as if
+	`--pack-kept-objects` was passed. See linkgit:git-repack[1] for
+	details. Defaults to `false` normally, but `true` if a bitmap
+	index is being written (either via `--write-bitmap-index` or
+	`repack.writeBitmaps`).
+
+repack.useDeltaIslands::
+	If set to true, makes `git repack` act as if `--delta-islands`
+	was passed. Defaults to `false`.
+
+repack.writeBitmaps::
+	When true, git will write a bitmap index when packing all
+	objects to disk (e.g., when `git repack -a` is run).  This
+	index can speed up the "counting objects" phase of subsequent
+	packs created for clones and fetches, at the cost of some disk
+	space and extra time spent on the initial repack.  This has
+	no effect if multiple packfiles are created.
+	Defaults to true on bare repos, false otherwise.
+
+repack.updateServerInfo::
+	If set to false, linkgit:git-repack[1] will not run
+	linkgit:git-update-server-info[1]. Defaults to true. Can be overridden
+	when true by the `-n` option of linkgit:git-repack[1].
+
+repack.cruftWindow::
+repack.cruftWindowMemory::
+repack.cruftDepth::
+repack.cruftThreads::
+	Parameters used by linkgit:git-pack-objects[1] when generating
+	a cruft pack and the respective parameters are not given over
+	the command line. See similarly named `pack.*` configuration
+	variables for defaults and meaning.
diff --git a/Documentation/config/rerere.adoc b/Documentation/config/rerere.adoc
new file mode 100644
index 0000000000..3a78b5ebb1
--- /dev/null
+++ b/Documentation/config/rerere.adoc
@@ -0,0 +1,12 @@
+rerere.autoUpdate::
+	When set to true, `git-rerere` updates the index with the
+	resulting contents after it cleanly resolves conflicts using
+	previously recorded resolutions.  Defaults to false.
+
+rerere.enabled::
+	Activate recording of resolved conflicts, so that identical
+	conflict hunks can be resolved automatically, should they be
+	encountered again.  By default, linkgit:git-rerere[1] is
+	enabled if there is an `rr-cache` directory under the
+	`$GIT_DIR`, e.g. if "rerere" was previously used in the
+	repository.
diff --git a/Documentation/config/revert.adoc b/Documentation/config/revert.adoc
new file mode 100644
index 0000000000..802d6faca2
--- /dev/null
+++ b/Documentation/config/revert.adoc
@@ -0,0 +1,3 @@
+revert.reference::
+	Setting this variable to true makes `git revert` behave
+	as if the `--reference` option is given.
diff --git a/Documentation/config/safe.adoc b/Documentation/config/safe.adoc
new file mode 100644
index 0000000000..2d45c98b12
--- /dev/null
+++ b/Documentation/config/safe.adoc
@@ -0,0 +1,62 @@
+safe.bareRepository::
+	Specifies which bare repositories Git will work with. The currently
+	supported values are:
++
+* `all`: Git works with all bare repositories. This is the default.
+* `explicit`: Git only works with bare repositories specified via
+  the top-level `--git-dir` command-line option, or the `GIT_DIR`
+  environment variable (see linkgit:git[1]).
++
+If you do not use bare repositories in your workflow, then it may be
+beneficial to set `safe.bareRepository` to `explicit` in your global
+config. This will protect you from attacks that involve cloning a
+repository that contains a bare repository and running a Git command
+within that directory.
++
+This config setting is only respected in protected configuration (see
+<<SCOPES>>). This prevents untrusted repositories from tampering with
+this value.
+
+safe.directory::
+	These config entries specify Git-tracked directories that are
+	considered safe even if they are owned by someone other than the
+	current user. By default, Git will refuse to even parse a Git
+	config of a repository owned by someone else, let alone run its
+	hooks, and this config setting allows users to specify exceptions,
+	e.g. for intentionally shared repositories (see the `--shared`
+	option in linkgit:git-init[1]).
++
+This is a multi-valued setting, i.e. you can add more than one directory
+via `git config --add`. To reset the list of safe directories (e.g. to
+override any such directories specified in the system config), add a
+`safe.directory` entry with an empty value.
++
+This config setting is only respected in protected configuration (see
+<<SCOPES>>). This prevents untrusted repositories from tampering with this
+value.
++
+The value of this setting is interpolated, i.e. `~/<path>` expands to a
+path relative to the home directory and `%(prefix)/<path>` expands to a
+path relative to Git's (runtime) prefix.
++
+To completely opt-out of this security check, set `safe.directory` to the
+string `*`. This will allow all repositories to be treated as if their
+directory was listed in the `safe.directory` list. If `safe.directory=*`
+is set in system config and you want to re-enable this protection, then
+initialize your list with an empty value before listing the repositories
+that you deem safe.  Giving a directory with `/*` appended to it will
+allow access to all repositories under the named directory.
++
+As explained, Git only allows you to access repositories owned by
+yourself, i.e. the user who is running Git, by default.  When Git
+is running as 'root' in a non Windows platform that provides sudo,
+however, git checks the SUDO_UID environment variable that sudo creates
+and will allow access to the uid recorded as its value in addition to
+the id from 'root'.
+This is to make it easy to perform a common sequence during installation
+"make && sudo make install".  A git process running under 'sudo' runs as
+'root' but the 'sudo' command exports the environment variable to record
+which id the original user has.
+If that is not what you would prefer and want git to only trust
+repositories that are owned by root instead, then you can remove
+the `SUDO_UID` variable from root's environment before invoking git.
diff --git a/Documentation/config/sendemail.adoc b/Documentation/config/sendemail.adoc
new file mode 100644
index 0000000000..5ffcfc9f2a
--- /dev/null
+++ b/Documentation/config/sendemail.adoc
@@ -0,0 +1,115 @@
+sendemail.identity::
+	A configuration identity. When given, causes values in the
+	'sendemail.<identity>' subsection to take precedence over
+	values in the 'sendemail' section. The default identity is
+	the value of `sendemail.identity`.
+
+sendemail.smtpEncryption::
+	See linkgit:git-send-email[1] for description.  Note that this
+	setting is not subject to the 'identity' mechanism.
+
+sendemail.smtpSSLCertPath::
+	Path to ca-certificates (either a directory or a single file).
+	Set it to an empty string to disable certificate verification.
+
+sendemail.<identity>.*::
+	Identity-specific versions of the 'sendemail.*' parameters
+	found below, taking precedence over those when this
+	identity is selected, through either the command-line or
+	`sendemail.identity`.
+
+sendemail.multiEdit::
+	If true (default), a single editor instance will be spawned to edit
+	files you have to edit (patches when `--annotate` is used, and the
+	summary when `--compose` is used). If false, files will be edited one
+	after the other, spawning a new editor each time.
+
+sendemail.confirm::
+	Sets the default for whether to confirm before sending. Must be
+	one of 'always', 'never', 'cc', 'compose', or 'auto'. See `--confirm`
+	in the linkgit:git-send-email[1] documentation for the meaning of these
+	values.
+
+sendemail.mailmap::
+	If true, makes linkgit:git-send-email[1] assume `--mailmap`,
+	otherwise assume `--no-mailmap`. False by default.
+
+sendemail.mailmap.file::
+	The location of a linkgit:git-send-email[1] specific augmenting
+	mailmap file. The default mailmap and `mailmap.file` are loaded
+	first. Thus, entries in this file take precedence over entries in
+	the default mailmap locations. See linkgit:gitmailmap[5].
+
+sendemail.mailmap.blob::
+	Like `sendemail.mailmap.file`, but consider the value as a reference
+	to a blob in the repository. Entries in `sendemail.mailmap.file`
+	take precedence over entries here. See linkgit:gitmailmap[5].
+
+sendemail.aliasesFile::
+	To avoid typing long email addresses, point this to one or more
+	email aliases files.  You must also supply `sendemail.aliasFileType`.
+
+sendemail.aliasFileType::
+	Format of the file(s) specified in sendemail.aliasesFile. Must be
+	one of 'mutt', 'mailrc', 'pine', 'elm', 'gnus', or 'sendmail'.
++
+What an alias file in each format looks like can be found in
+the documentation of the email program of the same name. The
+differences and limitations from the standard formats are
+described below:
++
+--
+sendmail;;
+*	Quoted aliases and quoted addresses are not supported: lines that
+	contain a `"` symbol are ignored.
+*	Redirection to a file (`/path/name`) or pipe (`|command`) is not
+	supported.
+*	File inclusion (`:include: /path/name`) is not supported.
+*	Warnings are printed on the standard error output for any
+	explicitly unsupported constructs, and any other lines that are not
+	recognized by the parser.
+--
+sendemail.annotate::
+sendemail.bcc::
+sendemail.cc::
+sendemail.ccCmd::
+sendemail.chainReplyTo::
+sendemail.envelopeSender::
+sendemail.from::
+sendemail.headerCmd::
+sendemail.signedOffByCc::
+sendemail.smtpPass::
+sendemail.suppressCc::
+sendemail.suppressFrom::
+sendemail.to::
+sendemail.toCmd::
+sendemail.smtpDomain::
+sendemail.smtpServer::
+sendemail.smtpServerPort::
+sendemail.smtpServerOption::
+sendemail.smtpUser::
+sendemail.thread::
+sendemail.transferEncoding::
+sendemail.validate::
+sendemail.xmailer::
+	These configuration variables all provide a default for
+	linkgit:git-send-email[1] command-line options. See its
+	documentation for details.
+
+sendemail.signedOffCc (deprecated)::
+	Deprecated alias for `sendemail.signedOffByCc`.
+
+sendemail.smtpBatchSize::
+	Number of messages to be sent per connection, after that a relogin
+	will happen.  If the value is 0 or undefined, send all messages in
+	one connection.
+	See also the `--batch-size` option of linkgit:git-send-email[1].
+
+sendemail.smtpReloginDelay::
+	Seconds to wait before reconnecting to the smtp server.
+	See also the `--relogin-delay` option of linkgit:git-send-email[1].
+
+sendemail.forbidSendmailVariables::
+	To avoid common misconfiguration mistakes, linkgit:git-send-email[1]
+	will abort with a warning if any configuration options for "sendmail"
+	exist. Set this variable to bypass the check.
diff --git a/Documentation/config/sequencer.adoc b/Documentation/config/sequencer.adoc
new file mode 100644
index 0000000000..e664eef01d
--- /dev/null
+++ b/Documentation/config/sequencer.adoc
@@ -0,0 +1,5 @@
+sequence.editor::
+	Text editor used by `git rebase -i` for editing the rebase instruction file.
+	The value is meant to be interpreted by the shell when it is used.
+	It can be overridden by the `GIT_SEQUENCE_EDITOR` environment variable.
+	When not configured, the default commit message editor is used instead.
diff --git a/Documentation/config/showbranch.adoc b/Documentation/config/showbranch.adoc
new file mode 100644
index 0000000000..e79ecd9ee9
--- /dev/null
+++ b/Documentation/config/showbranch.adoc
@@ -0,0 +1,3 @@
+showBranch.default::
+	The default set of branches for linkgit:git-show-branch[1].
+	See linkgit:git-show-branch[1].
diff --git a/Documentation/config/sparse.adoc b/Documentation/config/sparse.adoc
new file mode 100644
index 0000000000..aff49a8d3a
--- /dev/null
+++ b/Documentation/config/sparse.adoc
@@ -0,0 +1,27 @@
+sparse.expectFilesOutsideOfPatterns::
+	Typically with sparse checkouts, files not matching any
+	sparsity patterns are marked with a SKIP_WORKTREE bit in the
+	index and are missing from the working tree.  Accordingly, Git
+	will ordinarily check whether files with the SKIP_WORKTREE bit
+	are in fact present in the working tree contrary to
+	expectations.  If Git finds any, it marks those paths as
+	present by clearing the relevant SKIP_WORKTREE bits.  This
+	option can be used to tell Git that such
+	present-despite-skipped files are expected and to stop
+	checking for them.
++
+The default is `false`, which allows Git to automatically recover
+from the list of files in the index and working tree falling out of
+sync.
++
+Set this to `true` if you are in a setup where some external factor
+relieves Git of the responsibility for maintaining the consistency
+between the presence of working tree files and sparsity patterns.  For
+example, if you have a Git-aware virtual file system that has a robust
+mechanism for keeping the working tree and the sparsity patterns up to
+date based on access patterns.
++
+Regardless of this setting, Git does not check for
+present-despite-skipped files unless sparse checkout is enabled, so
+this config option has no effect unless `core.sparseCheckout` is
+`true`.
diff --git a/Documentation/config/splitindex.adoc b/Documentation/config/splitindex.adoc
new file mode 100644
index 0000000000..cfaa29610b
--- /dev/null
+++ b/Documentation/config/splitindex.adoc
@@ -0,0 +1,24 @@
+splitIndex.maxPercentChange::
+	When the split index feature is used, this specifies the
+	percent of entries the split index can contain compared to the
+	total number of entries in both the split index and the shared
+	index before a new shared index is written.
+	The value should be between 0 and 100. If the value is 0, then
+	a new shared index is always written; if it is 100, a new
+	shared index is never written.
+	By default, the value is 20, so a new shared index is written
+	if the number of entries in the split index would be greater
+	than 20 percent of the total number of entries.
+	See linkgit:git-update-index[1].
+
+splitIndex.sharedIndexExpire::
+	When the split index feature is used, shared index files that
+	were not modified since the time this variable specifies will
+	be removed when a new shared index file is created. The value
+	"now" expires all entries immediately, and "never" suppresses
+	expiration altogether.
+	The default value is "2.weeks.ago".
+	Note that a shared index file is considered modified (for the
+	purpose of expiration) each time a new split-index file is
+	either created based on it or read from it.
+	See linkgit:git-update-index[1].
diff --git a/Documentation/config/ssh.adoc b/Documentation/config/ssh.adoc
new file mode 100644
index 0000000000..2ca4bf93e1
--- /dev/null
+++ b/Documentation/config/ssh.adoc
@@ -0,0 +1,35 @@
+ssh.variant::
+	By default, Git determines the command line arguments to use
+	based on the basename of the configured SSH command (configured
+	using the environment variable `GIT_SSH` or `GIT_SSH_COMMAND` or
+	the config setting `core.sshCommand`). If the basename is
+	unrecognized, Git will attempt to detect support of OpenSSH
+	options by first invoking the configured SSH command with the
+	`-G` (print configuration) option and will subsequently use
+	OpenSSH options (if that is successful) or no options besides
+	the host and remote command (if it fails).
++
+The config variable `ssh.variant` can be set to override this detection.
+Valid values are `ssh` (to use OpenSSH options), `plink`, `putty`,
+`tortoiseplink`, `simple` (no options except the host and remote command).
+The default auto-detection can be explicitly requested using the value
+`auto`.  Any other value is treated as `ssh`.  This setting can also be
+overridden via the environment variable `GIT_SSH_VARIANT`.
++
+The current command-line parameters used for each variant are as
+follows:
++
+--
+
+* `ssh` - [-p port] [-4] [-6] [-o option] [username@]host command
+
+* `simple` - [username@]host command
+
+* `plink` or `putty` - [-P port] [-4] [-6] [username@]host command
+
+* `tortoiseplink` - [-P port] [-4] [-6] -batch [username@]host command
+
+--
++
+Except for the `simple` variant, command-line parameters are likely to
+change as git gains new features.
diff --git a/Documentation/config/stash.adoc b/Documentation/config/stash.adoc
new file mode 100644
index 0000000000..ec1edaeba6
--- /dev/null
+++ b/Documentation/config/stash.adoc
@@ -0,0 +1,14 @@
+stash.showIncludeUntracked::
+	If this is set to true, the `git stash show` command will show
+	the untracked files of a stash entry.  Defaults to false. See
+	the description of the 'show' command in linkgit:git-stash[1].
+
+stash.showPatch::
+	If this is set to true, the `git stash show` command without an
+	option will show the stash entry in patch form.  Defaults to false.
+	See the description of the 'show' command in linkgit:git-stash[1].
+
+stash.showStat::
+	If this is set to true, the `git stash show` command without an
+	option will show a diffstat of the stash entry.  Defaults to true.
+	See the description of the 'show' command in linkgit:git-stash[1].
diff --git a/Documentation/config/status.adoc b/Documentation/config/status.adoc
new file mode 100644
index 0000000000..8caf90f51c
--- /dev/null
+++ b/Documentation/config/status.adoc
@@ -0,0 +1,79 @@
+status.relativePaths::
+	By default, linkgit:git-status[1] shows paths relative to the
+	current directory. Setting this variable to `false` shows paths
+	relative to the repository root (this was the default for Git
+	prior to v1.5.4).
+
+status.short::
+	Set to true to enable --short by default in linkgit:git-status[1].
+	The option --no-short takes precedence over this variable.
+
+status.branch::
+	Set to true to enable --branch by default in linkgit:git-status[1].
+	The option --no-branch takes precedence over this variable.
+
+status.aheadBehind::
+	Set to true to enable `--ahead-behind` and false to enable
+	`--no-ahead-behind` by default in linkgit:git-status[1] for
+	non-porcelain status formats.  Defaults to true.
+
+status.displayCommentPrefix::
+	If set to true, linkgit:git-status[1] will insert a comment
+	prefix before each output line (starting with
+	`core.commentChar`, i.e. `#` by default). This was the
+	behavior of linkgit:git-status[1] in Git 1.8.4 and previous.
+	Defaults to false.
+
+status.renameLimit::
+	The number of files to consider when performing rename detection
+	in linkgit:git-status[1] and linkgit:git-commit[1]. Defaults to
+	the value of diff.renameLimit.
+
+status.renames::
+	Whether and how Git detects renames in linkgit:git-status[1] and
+	linkgit:git-commit[1] .  If set to "false", rename detection is
+	disabled. If set to "true", basic rename detection is enabled.
+	If set to "copies" or "copy", Git will detect copies, as well.
+	Defaults to the value of diff.renames.
+
+status.showStash::
+	If set to true, linkgit:git-status[1] will display the number of
+	entries currently stashed away.
+	Defaults to false.
+
+status.showUntrackedFiles::
+	By default, linkgit:git-status[1] and linkgit:git-commit[1] show
+	files which are not currently tracked by Git. Directories which
+	contain only untracked files, are shown with the directory name
+	only. Showing untracked files means that Git needs to lstat() all
+	the files in the whole repository, which might be slow on some
+	systems. So, this variable controls how the commands display
+	the untracked files. Possible values are:
++
+--
+* `no` - Show no untracked files.
+* `normal` - Show untracked files and directories.
+* `all` - Show also individual files in untracked directories.
+--
++
+If this variable is not specified, it defaults to 'normal'.
+All usual spellings for Boolean value `true` are taken as `normal`
+and `false` as `no`.
+This variable can be overridden with the -u|--untracked-files option
+of linkgit:git-status[1] and linkgit:git-commit[1].
+
+status.submoduleSummary::
+	Defaults to false.
+	If this is set to a non-zero number or true (identical to -1 or an
+	unlimited number), the submodule summary will be enabled and a
+	summary of commits for modified submodules will be shown (see
+	--summary-limit option of linkgit:git-submodule[1]). Please note
+	that the summary output command will be suppressed for all
+	submodules when `diff.ignoreSubmodules` is set to 'all' or only
+	for those submodules where `submodule.<name>.ignore=all`. The only
+	exception to that rule is that status and commit will show staged
+	submodule changes. To
+	also view the summary for ignored submodules you can either use
+	the --ignore-submodules=dirty command-line option or the 'git
+	submodule summary' command, which shows a similar output but does
+	not honor these settings.
diff --git a/Documentation/config/submodule.adoc b/Documentation/config/submodule.adoc
new file mode 100644
index 0000000000..0672d99117
--- /dev/null
+++ b/Documentation/config/submodule.adoc
@@ -0,0 +1,108 @@
+submodule.<name>.url::
+	The URL for a submodule. This variable is copied from the .gitmodules
+	file to the git config via 'git submodule init'. The user can change
+	the configured URL before obtaining the submodule via 'git submodule
+	update'. If neither submodule.<name>.active nor submodule.active are
+	set, the presence of this variable is used as a fallback to indicate
+	whether the submodule is of interest to git commands.
+	See linkgit:git-submodule[1] and linkgit:gitmodules[5] for details.
+
+submodule.<name>.update::
+	The method by which a submodule is updated by 'git submodule update',
+	which is the only affected command, others such as
+	'git checkout --recurse-submodules' are unaffected. It exists for
+	historical reasons, when 'git submodule' was the only command to
+	interact with submodules; settings like `submodule.active`
+	and `pull.rebase` are more specific. It is populated by
+	`git submodule init` from the linkgit:gitmodules[5] file.
+	See description of 'update' command in linkgit:git-submodule[1].
+
+submodule.<name>.branch::
+	The remote branch name for a submodule, used by `git submodule
+	update --remote`.  Set this option to override the value found in
+	the `.gitmodules` file.  See linkgit:git-submodule[1] and
+	linkgit:gitmodules[5] for details.
+
+submodule.<name>.fetchRecurseSubmodules::
+	This option can be used to control recursive fetching of this
+	submodule. It can be overridden by using the --[no-]recurse-submodules
+	command-line option to "git fetch" and "git pull".
+	This setting will override that from in the linkgit:gitmodules[5]
+	file.
+
+submodule.<name>.ignore::
+	Defines under what circumstances "git status" and the diff family show
+	a submodule as modified. When set to "all", it will never be considered
+	modified (but it will nonetheless show up in the output of status and
+	commit when it has been staged), "dirty" will ignore all changes
+	to the submodule's work tree and
+	takes only differences between the HEAD of the submodule and the commit
+	recorded in the superproject into account. "untracked" will additionally
+	let submodules with modified tracked files in their work tree show up.
+	Using "none" (the default when this option is not set) also shows
+	submodules that have untracked files in their work tree as changed.
+	This setting overrides any setting made in .gitmodules for this submodule,
+	both settings can be overridden on the command line by using the
+	"--ignore-submodules" option. The 'git submodule' commands are not
+	affected by this setting.
+
+submodule.<name>.active::
+	Boolean value indicating if the submodule is of interest to git
+	commands.  This config option takes precedence over the
+	submodule.active config option. See linkgit:gitsubmodules[7] for
+	details.
+
+submodule.active::
+	A repeated field which contains a pathspec used to match against a
+	submodule's path to determine if the submodule is of interest to git
+	commands. See linkgit:gitsubmodules[7] for details.
+
+submodule.recurse::
+	A boolean indicating if commands should enable the `--recurse-submodules`
+	option by default. Defaults to false.
++
+When set to true, it can be deactivated via the
+`--no-recurse-submodules` option. Note that some Git commands
+lacking this option may call some of the above commands affected by
+`submodule.recurse`; for instance `git remote update` will call
+`git fetch` but does not have a `--no-recurse-submodules` option.
+For these commands a workaround is to temporarily change the
+configuration value by using `git -c submodule.recurse=0`.
++
+The following list shows the commands that accept
+`--recurse-submodules` and whether they are supported by this
+setting.
+
+* `checkout`, `fetch`, `grep`, `pull`, `push`, `read-tree`,
+`reset`, `restore` and `switch` are always supported.
+* `clone` and `ls-files` are not supported.
+* `branch` is supported only if `submodule.propagateBranches` is
+enabled
+
+submodule.propagateBranches::
+	[EXPERIMENTAL] A boolean that enables branching support when
+	using `--recurse-submodules` or `submodule.recurse=true`.
+	Enabling this will allow certain commands to accept
+	`--recurse-submodules` and certain commands that already accept
+	`--recurse-submodules` will now consider branches.
+	Defaults to false.
+
+submodule.fetchJobs::
+	Specifies how many submodules are fetched/cloned at the same time.
+	A positive integer allows up to that number of submodules fetched
+	in parallel. A value of 0 will give some reasonable default.
+	If unset, it defaults to 1.
+
+submodule.alternateLocation::
+	Specifies how the submodules obtain alternates when submodules are
+	cloned. Possible values are `no`, `superproject`.
+	By default `no` is assumed, which doesn't add references. When the
+	value is set to `superproject` the submodule to be cloned computes
+	its alternates location relative to the superprojects alternate.
+
+submodule.alternateErrorStrategy::
+	Specifies how to treat errors with the alternates for a submodule
+	as computed via `submodule.alternateLocation`. Possible values are
+	`ignore`, `info`, `die`. Default is `die`. Note that if set to `ignore`
+	or `info`, and if there is an error with the computed alternate, the
+	clone proceeds as if no alternate was specified.
diff --git a/Documentation/config/tag.adoc b/Documentation/config/tag.adoc
new file mode 100644
index 0000000000..5062a057ff
--- /dev/null
+++ b/Documentation/config/tag.adoc
@@ -0,0 +1,17 @@
+tag.forceSignAnnotated::
+	A boolean to specify whether annotated tags created should be GPG signed.
+	If `--annotate` is specified on the command line, it takes
+	precedence over this option.
+
+tag.sort::
+	This variable controls the sort ordering of tags when displayed by
+	linkgit:git-tag[1]. Without the "--sort=<value>" option provided, the
+	value of this variable will be used as the default.
+
+tag.gpgSign::
+	A boolean to specify whether all tags should be GPG signed.
+	Use of this option when running in an automated script can
+	result in a large number of tags being signed. It is therefore
+	convenient to use an agent to avoid typing your gpg passphrase
+	several times. Note that this option doesn't affect tag signing
+	behavior enabled by "-u <keyid>" or "--local-user=<keyid>" options.
diff --git a/Documentation/config/tar.adoc b/Documentation/config/tar.adoc
new file mode 100644
index 0000000000..de8ff48ea9
--- /dev/null
+++ b/Documentation/config/tar.adoc
@@ -0,0 +1,6 @@
+tar.umask::
+	This variable can be used to restrict the permission bits of
+	tar archive entries.  The default is 0002, which turns off the
+	world write bit.  The special value "user" indicates that the
+	archiving user's umask will be used instead.  See umask(2) and
+	linkgit:git-archive[1].
diff --git a/Documentation/config/trace2.adoc b/Documentation/config/trace2.adoc
new file mode 100644
index 0000000000..05639ce33f
--- /dev/null
+++ b/Documentation/config/trace2.adoc
@@ -0,0 +1,71 @@
+Trace2 config settings are only read from the system and global
+config files; repository local and worktree config files and `-c`
+command line arguments are not respected.
+
+trace2.normalTarget::
+	This variable controls the normal target destination.
+	It may be overridden by the `GIT_TRACE2` environment variable.
+	The following table shows possible values.
+
+trace2.perfTarget::
+	This variable controls the performance target destination.
+	It may be overridden by the `GIT_TRACE2_PERF` environment variable.
+	The following table shows possible values.
+
+trace2.eventTarget::
+	This variable controls the event target destination.
+	It may be overridden by the `GIT_TRACE2_EVENT` environment variable.
+	The following table shows possible values.
++
+include::../trace2-target-values.adoc[]
+
+trace2.normalBrief::
+	Boolean.  When true `time`, `filename`, and `line` fields are
+	omitted from normal output.  May be overridden by the
+	`GIT_TRACE2_BRIEF` environment variable.  Defaults to false.
+
+trace2.perfBrief::
+	Boolean.  When true `time`, `filename`, and `line` fields are
+	omitted from PERF output.  May be overridden by the
+	`GIT_TRACE2_PERF_BRIEF` environment variable.  Defaults to false.
+
+trace2.eventBrief::
+	Boolean.  When true `time`, `filename`, and `line` fields are
+	omitted from event output.  May be overridden by the
+	`GIT_TRACE2_EVENT_BRIEF` environment variable.  Defaults to false.
+
+trace2.eventNesting::
+	Integer.  Specifies desired depth of nested regions in the
+	event output.  Regions deeper than this value will be
+	omitted.  May be overridden by the `GIT_TRACE2_EVENT_NESTING`
+	environment variable.  Defaults to 2.
+
+trace2.configParams::
+	A comma-separated list of patterns of "important" config
+	settings that should be recorded in the trace2 output.
+	For example, `core.*,remote.*.url` would cause the trace2
+	output to contain events listing each configured remote.
+	May be overridden by the `GIT_TRACE2_CONFIG_PARAMS` environment
+	variable.  Unset by default.
+
+trace2.envVars::
+	A comma-separated list of "important" environment variables that should
+	be recorded in the trace2 output.  For example,
+	`GIT_HTTP_USER_AGENT,GIT_CONFIG` would cause the trace2 output to
+	contain events listing the overrides for HTTP user agent and the
+	location of the Git configuration file (assuming any are set).  May be
+	overridden by the `GIT_TRACE2_ENV_VARS` environment variable.  Unset by
+	default.
+
+trace2.destinationDebug::
+	Boolean.  When true Git will print error messages when a
+	trace target destination cannot be opened for writing.
+	By default, these errors are suppressed and tracing is
+	silently disabled.  May be overridden by the
+	`GIT_TRACE2_DST_DEBUG` environment variable.
+
+trace2.maxFiles::
+	Integer.  When writing trace files to a target directory, do not
+	write additional traces if doing so would exceed this many files. Instead,
+	write a sentinel file that will block further tracing to this
+	directory. Defaults to 0, which disables this check.
diff --git a/Documentation/config/transfer.adoc b/Documentation/config/transfer.adoc
new file mode 100644
index 0000000000..f1ce50f4a6
--- /dev/null
+++ b/Documentation/config/transfer.adoc
@@ -0,0 +1,127 @@
+transfer.credentialsInUrl::
+	A configured URL can contain plaintext credentials in the form
+	`<protocol>://<user>:<password>@<domain>/<path>`. You may want
+	to warn or forbid the use of such configuration (in favor of
+	using linkgit:git-credential[1]). This will be used on
+	linkgit:git-clone[1], linkgit:git-fetch[1], linkgit:git-push[1],
+	and any other direct use of the configured URL.
++
+Note that this is currently limited to detecting credentials in
+`remote.<name>.url` configuration; it won't detect credentials in
+`remote.<name>.pushurl` configuration.
++
+You might want to enable this to prevent inadvertent credentials
+exposure, e.g. because:
++
+* The OS or system where you're running git may not provide a way or
+  otherwise allow you to configure the permissions of the
+  configuration file where the username and/or password are stored.
+* Even if it does, having such data stored "at rest" might expose you
+  in other ways, e.g. a backup process might copy the data to another
+  system.
+* The git programs will pass the full URL to one another as arguments
+  on the command-line, meaning the credentials will be exposed to other
+  unprivileged users on systems that allow them to see the full
+  process list of other users. On linux the "hidepid" setting
+  documented in procfs(5) allows for configuring this behavior.
++
+If such concerns don't apply to you then you probably don't need to be
+concerned about credentials exposure due to storing sensitive
+data in git's configuration files. If you do want to use this, set
+`transfer.credentialsInUrl` to one of these values:
++
+* `allow` (default): Git will proceed with its activity without warning.
+* `warn`: Git will write a warning message to `stderr` when parsing a URL
+  with a plaintext credential.
+* `die`: Git will write a failure message to `stderr` when parsing a URL
+  with a plaintext credential.
+
+transfer.fsckObjects::
+	When `fetch.fsckObjects` or `receive.fsckObjects` are
+	not set, the value of this variable is used instead.
+	Defaults to false.
++
+When set, the fetch or receive will abort in the case of a malformed
+object or a link to a nonexistent object. In addition, various other
+issues are checked for, including legacy issues (see `fsck.<msg-id>`),
+and potential security issues like the existence of a `.GIT` directory
+or a malicious `.gitmodules` file (see the release notes for v2.2.1
+and v2.17.1 for details). Other sanity and security checks may be
+added in future releases.
++
+On the receiving side, failing fsckObjects will make those objects
+unreachable, see "QUARANTINE ENVIRONMENT" in
+linkgit:git-receive-pack[1]. On the fetch side, malformed objects will
+instead be left unreferenced in the repository.
++
+Due to the non-quarantine nature of the `fetch.fsckObjects`
+implementation it cannot be relied upon to leave the object store
+clean like `receive.fsckObjects` can.
++
+As objects are unpacked they're written to the object store, so there
+can be cases where malicious objects get introduced even though the
+"fetch" failed, only to have a subsequent "fetch" succeed because only
+new incoming objects are checked, not those that have already been
+written to the object store. That difference in behavior should not be
+relied upon. In the future, such objects may be quarantined for
+"fetch" as well.
++
+For now, the paranoid need to find some way to emulate the quarantine
+environment if they'd like the same protection as "push". E.g. in the
+case of an internal mirror do the mirroring in two steps, one to fetch
+the untrusted objects, and then do a second "push" (which will use the
+quarantine) to another internal repo, and have internal clients
+consume this pushed-to repository, or embargo internal fetches and
+only allow them once a full "fsck" has run (and no new fetches have
+happened in the meantime).
+
+transfer.hideRefs::
+	String(s) `receive-pack` and `upload-pack` use to decide which
+	refs to omit from their initial advertisements.  Use more than
+	one definition to specify multiple prefix strings. A ref that is
+	under the hierarchies listed in the value of this variable is
+	excluded, and is hidden when responding to `git push` or `git
+	fetch`.  See `receive.hideRefs` and `uploadpack.hideRefs` for
+	program-specific versions of this config.
++
+You may also include a `!` in front of the ref name to negate the entry,
+explicitly exposing it, even if an earlier entry marked it as hidden.
+If you have multiple hideRefs values, later entries override earlier ones
+(and entries in more-specific config files override less-specific ones).
++
+If a namespace is in use, the namespace prefix is stripped from each
+reference before it is matched against `transfer.hiderefs` patterns. In
+order to match refs before stripping, add a `^` in front of the ref name. If
+you combine `!` and `^`, `!` must be specified first.
++
+For example, if `refs/heads/master` is specified in `transfer.hideRefs` and
+the current namespace is `foo`, then `refs/namespaces/foo/refs/heads/master`
+is omitted from the advertisements. If `uploadpack.allowRefInWant` is set,
+`upload-pack` will treat `want-ref refs/heads/master` in a protocol v2
+`fetch` command as if `refs/namespaces/foo/refs/heads/master` did not exist.
+`receive-pack`, on the other hand, will still advertise the object id the
+ref is pointing to without mentioning its name (a so-called ".have" line).
++
+Even if you hide refs, a client may still be able to steal the target
+objects via the techniques described in the "SECURITY" section of the
+linkgit:gitnamespaces[7] man page; it's best to keep private data in a
+separate repository.
+
+transfer.unpackLimit::
+	When `fetch.unpackLimit` or `receive.unpackLimit` are
+	not set, the value of this variable is used instead.
+	The default value is 100.
+
+transfer.advertiseSID::
+	Boolean. When true, client and server processes will advertise their
+	unique session IDs to their remote counterpart. Defaults to false.
+
+transfer.bundleURI::
+	When `true`, local `git clone` commands will request bundle
+	information from the remote server (if advertised) and download
+	bundles before continuing the clone through the Git protocol.
+	Defaults to `false`.
+
+transfer.advertiseObjectInfo::
+	When `true`, the `object-info` capability is advertised by
+	servers. Defaults to false.
diff --git a/Documentation/config/uploadarchive.adoc b/Documentation/config/uploadarchive.adoc
new file mode 100644
index 0000000000..e0698e8c1d
--- /dev/null
+++ b/Documentation/config/uploadarchive.adoc
@@ -0,0 +1,6 @@
+uploadarchive.allowUnreachable::
+	If true, allow clients to use `git archive --remote` to request
+	any tree, whether reachable from the ref tips or not. See the
+	discussion in the "SECURITY" section of
+	linkgit:git-upload-archive[1] for more details. Defaults to
+	`false`.
diff --git a/Documentation/config/uploadpack.adoc b/Documentation/config/uploadpack.adoc
new file mode 100644
index 0000000000..0e1dda944a
--- /dev/null
+++ b/Documentation/config/uploadpack.adoc
@@ -0,0 +1,88 @@
+uploadpack.hideRefs::
+	This variable is the same as `transfer.hideRefs`, but applies
+	only to `upload-pack` (and so affects only fetches, not pushes).
+	An attempt to fetch a hidden ref by `git fetch` will fail.  See
+	also `uploadpack.allowTipSHA1InWant`.
+
+uploadpack.allowTipSHA1InWant::
+	When `uploadpack.hideRefs` is in effect, allow `upload-pack`
+	to accept a fetch request that asks for an object at the tip
+	of a hidden ref (by default, such a request is rejected).
+	See also `uploadpack.hideRefs`.  Even if this is false, a client
+	may be able to steal objects via the techniques described in the
+	"SECURITY" section of the linkgit:gitnamespaces[7] man page; it's
+	best to keep private data in a separate repository.
+
+uploadpack.allowReachableSHA1InWant::
+	Allow `upload-pack` to accept a fetch request that asks for an
+	object that is reachable from any ref tip. However, note that
+	calculating object reachability is computationally expensive.
+	Defaults to `false`.  Even if this is false, a client may be able
+	to steal objects via the techniques described in the "SECURITY"
+	section of the linkgit:gitnamespaces[7] man page; it's best to
+	keep private data in a separate repository.
+
+uploadpack.allowAnySHA1InWant::
+	Allow `upload-pack` to accept a fetch request that asks for any
+	object at all.
+	It implies `uploadpack.allowTipSHA1InWant` and
+	`uploadpack.allowReachableSHA1InWant`. If set to `true` it will
+	enable both of them, it set to `false` it will disable both of
+	them.
+	By default not set.
+
+uploadpack.keepAlive::
+	When `upload-pack` has started `pack-objects`, there may be a
+	quiet period while `pack-objects` prepares the pack. Normally
+	it would output progress information, but if `--quiet` was used
+	for the fetch, `pack-objects` will output nothing at all until
+	the pack data begins. Some clients and networks may consider
+	the server to be hung and give up. Setting this option instructs
+	`upload-pack` to send an empty keepalive packet every
+	`uploadpack.keepAlive` seconds. Setting this option to 0
+	disables keepalive packets entirely. The default is 5 seconds.
+
+uploadpack.packObjectsHook::
+	If this option is set, when `upload-pack` would run
+	`git pack-objects` to create a packfile for a client, it will
+	run this shell command instead.  The `pack-objects` command and
+	arguments it _would_ have run (including the `git pack-objects`
+	at the beginning) are appended to the shell command. The stdin
+	and stdout of the hook are treated as if `pack-objects` itself
+	was run. I.e., `upload-pack` will feed input intended for
+	`pack-objects` to the hook, and expects a completed packfile on
+	stdout.
++
+Note that this configuration variable is only respected when it is specified
+in protected configuration (see <<SCOPES>>). This is a safety measure
+against fetching from untrusted repositories.
+
+uploadpack.allowFilter::
+	If this option is set, `upload-pack` will support partial
+	clone and partial fetch object filtering.
+
+uploadpackfilter.allow::
+	Provides a default value for unspecified object filters (see: the
+	below configuration variable). If set to `true`, this will also
+	enable all filters which get added in the future.
+	Defaults to `true`.
+
+uploadpackfilter.<filter>.allow::
+	Explicitly allow or ban the object filter corresponding to
+	`<filter>`, where `<filter>` may be one of: `blob:none`,
+	`blob:limit`, `object:type`, `tree`, `sparse:oid`, or `combine`.
+	If using combined filters, both `combine` and all of the nested
+	filter kinds must be allowed. Defaults to `uploadpackfilter.allow`.
+
+uploadpackfilter.tree.maxDepth::
+	Only allow `--filter=tree:<n>` when `<n>` is no more than the value of
+	`uploadpackfilter.tree.maxDepth`. If set, this also implies
+	`uploadpackfilter.tree.allow=true`, unless this configuration
+	variable had already been set. Has no effect if unset.
+
+uploadpack.allowRefInWant::
+	If this option is set, `upload-pack` will support the `ref-in-want`
+	feature of the protocol version 2 `fetch` command.  This feature
+	is intended for the benefit of load-balanced servers which may
+	not have the same view of what OIDs their refs point to due to
+	replication delay.
diff --git a/Documentation/config/url.adoc b/Documentation/config/url.adoc
new file mode 100644
index 0000000000..e5566c371d
--- /dev/null
+++ b/Documentation/config/url.adoc
@@ -0,0 +1,30 @@
+url.<base>.insteadOf::
+	Any URL that starts with this value will be rewritten to
+	start, instead, with <base>. In cases where some site serves a
+	large number of repositories, and serves them with multiple
+	access methods, and some users need to use different access
+	methods, this feature allows people to specify any of the
+	equivalent URLs and have Git automatically rewrite the URL to
+	the best alternative for the particular user, even for a
+	never-before-seen repository on the site.  When more than one
+	insteadOf strings match a given URL, the longest match is used.
++
+Note that any protocol restrictions will be applied to the rewritten
+URL. If the rewrite changes the URL to use a custom protocol or remote
+helper, you may need to adjust the `protocol.*.allow` config to permit
+the request.  In particular, protocols you expect to use for submodules
+must be set to `always` rather than the default of `user`. See the
+description of `protocol.allow` above.
+
+url.<base>.pushInsteadOf::
+	Any URL that starts with this value will not be pushed to;
+	instead, it will be rewritten to start with <base>, and the
+	resulting URL will be pushed to. In cases where some site serves
+	a large number of repositories, and serves them with multiple
+	access methods, some of which do not allow push, this feature
+	allows people to specify a pull-only URL and have Git
+	automatically use an appropriate URL to push, even for a
+	never-before-seen repository on the site.  When more than one
+	pushInsteadOf strings match a given URL, the longest match is
+	used.  If a remote has an explicit pushurl, Git will ignore this
+	setting for that remote.
diff --git a/Documentation/config/user.adoc b/Documentation/config/user.adoc
new file mode 100644
index 0000000000..2ffc38d164
--- /dev/null
+++ b/Documentation/config/user.adoc
@@ -0,0 +1,48 @@
+user.name::
+user.email::
+author.name::
+author.email::
+committer.name::
+committer.email::
+	The `user.name` and `user.email` variables determine what ends
+	up in the `author` and `committer` fields of commit
+	objects.
+	If you need the `author` or `committer` to be different, the
+	`author.name`, `author.email`, `committer.name`, or
+	`committer.email` variables can be set.
+	All of these can be overridden by the `GIT_AUTHOR_NAME`,
+	`GIT_AUTHOR_EMAIL`, `GIT_COMMITTER_NAME`,
+	`GIT_COMMITTER_EMAIL`, and `EMAIL` environment variables.
++
+Note that the `name` forms of these variables conventionally refer to
+some form of a personal name.  See linkgit:git-commit[1] and the
+environment variables section of linkgit:git[1] for more information on
+these settings and the `credential.username` option if you're looking
+for authentication credentials instead.
+
+user.useConfigOnly::
+	Instruct Git to avoid trying to guess defaults for `user.email`
+	and `user.name`, and instead retrieve the values only from the
+	configuration. For example, if you have multiple email addresses
+	and would like to use a different one for each repository, then
+	with this configuration option set to `true` in the global config
+	along with a name, Git will prompt you to set up an email before
+	making new commits in a newly cloned repository.
+	Defaults to `false`.
+
+user.signingKey::
+	If linkgit:git-tag[1] or linkgit:git-commit[1] is not selecting the
+	key you want it to automatically when creating a signed tag or
+	commit, you can override the default selection with this variable.
+	This option is passed unchanged to gpg's --local-user parameter,
+	so you may specify a key using any method that gpg supports.
+	If gpg.format is set to `ssh` this can contain the path to either
+	your private ssh key or the public key when ssh-agent is used.
+	Alternatively it can contain a public key prefixed with `key::`
+	directly (e.g.: "key::ssh-rsa XXXXXX identifier"). The private key
+	needs to be available via ssh-agent. If not set Git will call
+	gpg.ssh.defaultKeyCommand (e.g.: "ssh-add -L") and try to use the
+	first key available. For backward compatibility, a raw key which
+	begins with "ssh-", such as "ssh-rsa XXXXXX identifier", is treated
+	as "key::ssh-rsa XXXXXX identifier", but this form is deprecated;
+	use the `key::` form instead.
diff --git a/Documentation/config/versionsort.adoc b/Documentation/config/versionsort.adoc
new file mode 100644
index 0000000000..0cff090819
--- /dev/null
+++ b/Documentation/config/versionsort.adoc
@@ -0,0 +1,33 @@
+versionsort.prereleaseSuffix (deprecated)::
+	Deprecated alias for `versionsort.suffix`.  Ignored if
+	`versionsort.suffix` is set.
+
+versionsort.suffix::
+	Even when version sort is used in linkgit:git-tag[1], tagnames
+	with the same base version but different suffixes are still sorted
+	lexicographically, resulting e.g. in prerelease tags appearing
+	after the main release (e.g. "1.0-rc1" after "1.0").  This
+	variable can be specified to determine the sorting order of tags
+	with different suffixes.
++
+By specifying a single suffix in this variable, any tagname containing
+that suffix will appear before the corresponding main release.  E.g. if
+the variable is set to "-rc", then all "1.0-rcX" tags will appear before
+"1.0".  If specified multiple times, once per suffix, then the order of
+suffixes in the configuration will determine the sorting order of tagnames
+with those suffixes.  E.g. if "-pre" appears before "-rc" in the
+configuration, then all "1.0-preX" tags will be listed before any
+"1.0-rcX" tags.  The placement of the main release tag relative to tags
+with various suffixes can be determined by specifying the empty suffix
+among those other suffixes.  E.g. if the suffixes "-rc", "", "-ck", and
+"-bfs" appear in the configuration in this order, then all "v4.8-rcX" tags
+are listed first, followed by "v4.8", then "v4.8-ckX" and finally
+"v4.8-bfsX".
++
+If more than one suffix matches the same tagname, then that tagname will
+be sorted according to the suffix which starts at the earliest position in
+the tagname.  If more than one different matching suffix starts at
+that earliest position, then that tagname will be sorted according to the
+longest of those suffixes.
+The sorting order between different suffixes is undefined if they are
+in multiple config files.
diff --git a/Documentation/config/web.adoc b/Documentation/config/web.adoc
new file mode 100644
index 0000000000..beec8d1303
--- /dev/null
+++ b/Documentation/config/web.adoc
@@ -0,0 +1,4 @@
+web.browser::
+	Specify a web browser that may be used by some commands.
+	Currently only linkgit:git-instaweb[1] and linkgit:git-help[1]
+	may use it.
diff --git a/Documentation/config/worktree.adoc b/Documentation/config/worktree.adoc
new file mode 100644
index 0000000000..5e35c7d018
--- /dev/null
+++ b/Documentation/config/worktree.adoc
@@ -0,0 +1,19 @@
+worktree.guessRemote::
+	If no branch is specified and neither `-b` nor `-B` nor
+	`--detach` is used, then `git worktree add` defaults to
+	creating a new branch from HEAD.  If `worktree.guessRemote` is
+	set to true, `worktree add` tries to find a remote-tracking
+	branch whose name uniquely matches the new branch name.  If
+	such a branch exists, it is checked out and set as "upstream"
+	for the new branch.  If no such match can be found, it falls
+	back to creating a new branch from the current HEAD.
+
+worktree.useRelativePaths::
+	Link worktrees using relative paths (when "true") or absolute
+	paths (when "false"). This is particularly useful for setups
+	where the repository and worktrees may be moved between
+	different locations or environments. Defaults to "false".
++
+Note that setting `worktree.useRelativePaths` to "true" implies enabling the
+`extension.relativeWorktrees` config (see linkgit:git-config[1]),
+thus making it incompatible with older versions of Git.
diff --git a/Documentation/date-formats.adoc b/Documentation/date-formats.adoc
new file mode 100644
index 0000000000..e24517c496
--- /dev/null
+++ b/Documentation/date-formats.adoc
@@ -0,0 +1,31 @@
+DATE FORMATS
+------------
+
+The `GIT_AUTHOR_DATE` and `GIT_COMMITTER_DATE` environment variables
+support the following date formats:
+
+Git internal format::
+	It is `<unix-timestamp> <time-zone-offset>`, where
+	`<unix-timestamp>` is the number of seconds since the UNIX epoch.
+	`<time-zone-offset>` is a positive or negative offset from UTC.
+	For example CET (which is 1 hour ahead of UTC) is `+0100`.
+
+RFC 2822::
+	The standard date format as described by RFC 2822, for example
+	`Thu, 07 Apr 2005 22:13:13 +0200`.
+
+ISO 8601::
+	Time and date specified by the ISO 8601 standard, for example
+	`2005-04-07T22:13:13`. The parser accepts a space instead of the
+	`T` character as well. Fractional parts of a second will be ignored,
+	for example `2005-04-07T22:13:13.019` will be treated as
+	`2005-04-07T22:13:13`.
++
+NOTE: In addition, the date part is accepted in the following formats:
+`YYYY.MM.DD`, `MM/DD/YYYY` and `DD.MM.YYYY`.
+
+ifdef::git-commit[]
+In addition to recognizing all date formats above, the `--date` option
+will also try to make sense of other, more human-centric date formats,
+such as relative dates like "yesterday" or "last Friday at noon".
+endif::git-commit[]
diff --git a/Documentation/diff-format.adoc b/Documentation/diff-format.adoc
new file mode 100644
index 0000000000..80e36e153d
--- /dev/null
+++ b/Documentation/diff-format.adoc
@@ -0,0 +1,185 @@
+Raw output format
+-----------------
+
+The raw output format from `git-diff-index`, `git-diff-tree`,
+`git-diff-files` and `git diff --raw` are very similar.
+
+These commands all compare two sets of things; what is
+compared differs:
+
+`git-diff-index <tree-ish>`::
+	compares the _<tree-ish>_ and the files on the filesystem.
+
+`git-diff-index --cached <tree-ish>`::
+	compares the _<tree-ish>_ and the index.
+
+`git-diff-tree [-r] <tree-ish-1> <tree-ish-2> [<pattern>...]`::
+        compares the trees named by the two arguments.
+
+`git-diff-files [<pattern>...]`::
+        compares the index and the files on the filesystem.
+
+The `git-diff-tree` command begins its output by printing the hash of
+what is being compared. After that, all the commands print one output
+line per changed file.
+
+An output line is formatted this way:
+
+------------------------------------------------
+in-place edit  :100644 100644 bcd1234 0123456 M file0
+copy-edit      :100644 100644 abcd123 1234567 C68 file1 file2
+rename-edit    :100644 100644 abcd123 1234567 R86 file1 file3
+create         :000000 100644 0000000 1234567 A file4
+delete         :100644 000000 1234567 0000000 D file5
+unmerged       :000000 000000 0000000 0000000 U file6
+------------------------------------------------
+
+That is, from the left to the right:
+
+. a colon.
+. mode for "src"; 000000 if creation or unmerged.
+. a space.
+. mode for "dst"; 000000 if deletion or unmerged.
+. a space.
+. sha1 for "src"; 0\{40\} if creation or unmerged.
+. a space.
+. sha1 for "dst"; 0\{40\} if deletion, unmerged or "work tree out of sync with the index".
+. a space.
+. status, followed by optional "score" number.
+. a tab or a NUL when `-z` option is used.
+. path for "src"
+. a tab or a NUL when `-z` option is used; only exists for C or R.
+. path for "dst"; only exists for C or R.
+. an LF or a NUL when `-z` option is used, to terminate the record.
+
+Possible status letters are:
+
+- `A`: addition of a file
+- `C`: copy of a file into a new one
+- `D`: deletion of a file
+- `M`: modification of the contents or mode of a file
+- `R`: renaming of a file
+- `T`: change in the type of the file (regular file, symbolic link or submodule)
+- `U`: file is unmerged (you must complete the merge before it can
+  be committed)
+- `X`: "unknown" change type (most probably a bug, please report it)
+
+Status letters `C` and `R` are always followed by a score (denoting the
+percentage of similarity between the source and target of the move or
+copy).  Status letter `M` may be followed by a score (denoting the
+percentage of dissimilarity) for file rewrites.
+
+The sha1 for "dst" is shown as all 0's if a file on the filesystem
+is out of sync with the index.
+
+Example:
+
+------------------------------------------------
+:100644 100644 5be4a4a 0000000 M file.c
+------------------------------------------------
+
+Without the `-z` option, pathnames with "unusual" characters are
+quoted as explained for the configuration variable `core.quotePath`
+(see linkgit:git-config[1]).  Using `-z` the filename is output
+verbatim and the line is terminated by a NUL byte.
+
+diff format for merges
+----------------------
+
+`git-diff-tree`, `git-diff-files` and `git-diff --raw`
+can take `-c` or `--cc` option
+to generate diff output also for merge commits.  The output differs
+from the format described above in the following way:
+
+. there is a colon for each parent
+. there are more "src" modes and "src" sha1
+. status is concatenated status characters for each parent
+. no optional "score" number
+. tab-separated pathname(s) of the file
+
+For `-c` and `--cc`, only the destination or final path is shown even
+if the file was renamed on any side of history.  With
+`--combined-all-paths`, the name of the path in each parent is shown
+followed by the name of the path in the merge commit.
+
+Examples for `-c` and `--cc` without `--combined-all-paths`:
+------------------------------------------------
+::100644 100644 100644 fabadb8 cc95eb0 4866510 MM	desc.c
+::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM	bar.sh
+::100644 100644 100644 e07d6c5 9042e82 ee91881 RR	phooey.c
+------------------------------------------------
+
+Examples when `--combined-all-paths` added to either `-c` or `--cc`:
+
+------------------------------------------------
+::100644 100644 100644 fabadb8 cc95eb0 4866510 MM	desc.c	desc.c	desc.c
+::100755 100755 100755 52b7a2d 6d1ac04 d2ac7d7 RM	foo.sh	bar.sh	bar.sh
+::100644 100644 100644 e07d6c5 9042e82 ee91881 RR	fooey.c	fuey.c	phooey.c
+------------------------------------------------
+
+Note that 'combined diff' lists only files which were modified from
+all parents.
+
+
+include::diff-generate-patch.adoc[]
+
+
+other diff formats
+------------------
+
+The `--summary` option describes newly added, deleted, renamed and
+copied files.  The `--stat` option adds `diffstat`(1) graph to the
+output.  These options can be combined with other options, such as
+`-p`, and are meant for human consumption.
+
+When showing a change that involves a rename or a copy, `--stat` output
+formats the pathnames compactly by combining common prefix and suffix of
+the pathnames.  For example, a change that moves `arch/i386/Makefile` to
+`arch/x86/Makefile` while modifying 4 lines will be shown like this:
+
+------------------------------------
+arch/{i386 => x86}/Makefile    |   4 +--
+------------------------------------
+
+The `--numstat` option gives the diffstat(1) information but is designed
+for easier machine consumption.  An entry in `--numstat` output looks
+like this:
+
+----------------------------------------
+1	2	README
+3	1	arch/{i386 => x86}/Makefile
+----------------------------------------
+
+That is, from left to right:
+
+. the number of added lines;
+. a tab;
+. the number of deleted lines;
+. a tab;
+. pathname (possibly with rename/copy information);
+. a newline.
+
+When `-z` output option is in effect, the output is formatted this way:
+
+----------------------------------------
+1	2	README NUL
+3	1	NUL arch/i386/Makefile NUL arch/x86/Makefile NUL
+----------------------------------------
+
+That is:
+
+. the number of added lines;
+. a tab;
+. the number of deleted lines;
+. a tab;
+. a NUL (only exists if renamed/copied);
+. pathname in preimage;
+. a NUL (only exists if renamed/copied);
+. pathname in postimage (only exists if renamed/copied);
+. a NUL.
+
+The extra `NUL` before the preimage path in renamed case is to allow
+scripts that read the output to tell if the current record being read is
+a single-path record or a rename/copy record without reading ahead.
+After reading added and deleted lines, reading up to `NUL` would yield
+the pathname, but if that is `NUL`, the record will show two paths.
diff --git a/Documentation/diff-generate-patch.adoc b/Documentation/diff-generate-patch.adoc
new file mode 100644
index 0000000000..e5c813c96f
--- /dev/null
+++ b/Documentation/diff-generate-patch.adoc
@@ -0,0 +1,210 @@
+[[generate_patch_text_with_p]]
+Generating patch text with -p
+-----------------------------
+
+Running
+linkgit:git-diff[1],
+linkgit:git-log[1],
+linkgit:git-show[1],
+linkgit:git-diff-index[1],
+linkgit:git-diff-tree[1], or
+linkgit:git-diff-files[1]
+with the `-p` option produces patch text.
+You can customize the creation of patch text via the
+`GIT_EXTERNAL_DIFF` and the `GIT_DIFF_OPTS` environment variables
+(see linkgit:git[1]), and the `diff` attribute (see linkgit:gitattributes[5]).
+
+What the `-p` option produces is slightly different from the traditional
+diff format:
+
+1.   It is preceded by a "git diff" header that looks like this:
+
+       diff --git a/file1 b/file2
++
+The `a/` and `b/` filenames are the same unless rename/copy is
+involved.  Especially, even for a creation or a deletion,
+`/dev/null` is _not_ used in place of the `a/` or `b/` filenames.
++
+When a rename/copy is involved, `file1` and `file2` show the
+name of the source file of the rename/copy and the name of
+the file that the rename/copy produces, respectively.
+
+2.   It is followed by one or more extended header lines:
++
+[synopsis]
+old mode <mode>
+new mode <mode>
+deleted file mode <mode>
+new file mode <mode>
+copy from <path>
+copy to <path>
+rename from <path>
+rename to <path>
+similarity index <number>
+dissimilarity index <number>
+index <hash>..<hash> <mode>
++
+File modes _<mode>_ are printed as 6-digit octal numbers including the file type
+and file permission bits.
++
+Path names in extended headers do not include the `a/` and `b/` prefixes.
++
+The similarity index is the percentage of unchanged lines, and
+the dissimilarity index is the percentage of changed lines.  It
+is a rounded down integer, followed by a percent sign.  The
+similarity index value of 100% is thus reserved for two equal
+files, while 100% dissimilarity means that no line from the old
+file made it into the new one.
++
+The index line includes the blob object names before and after the change.
+The _<mode>_ is included if the file mode does not change; otherwise,
+separate lines indicate the old and the new mode.
+
+3.  Pathnames with "unusual" characters are quoted as explained for
+    the configuration variable `core.quotePath` (see
+    linkgit:git-config[1]).
+
+4.  All the `file1` files in the output refer to files before the
+    commit, and all the `file2` files refer to files after the commit.
+    It is incorrect to apply each change to each file sequentially.  For
+    example, this patch will swap a and b:
+
+      diff --git a/a b/b
+      rename from a
+      rename to b
+      diff --git a/b b/a
+      rename from b
+      rename to a
+
+5.  Hunk headers mention the name of the function to which the hunk
+    applies.  See "Defining a custom hunk-header" in
+    linkgit:gitattributes[5] for details of how to tailor this to
+    specific languages.
+
+
+Combined diff format
+--------------------
+
+Any diff-generating command can take the `-c` or `--cc` option to
+produce a 'combined diff' when showing a merge. This is the default
+format when showing merges with linkgit:git-diff[1] or
+linkgit:git-show[1]. Note also that you can give suitable
+`--diff-merges` option to any of these commands to force generation of
+diffs in a specific format.
+
+A "combined diff" format looks like this:
+
+------------
+diff --combined describe.c
+index fabadb8,cc95eb0..4866510
+--- a/describe.c
++++ b/describe.c
+@@@ -98,20 -98,12 +98,20 @@@
+	return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
+  }
+
+- static void describe(char *arg)
+ -static void describe(struct commit *cmit, int last_one)
+++static void describe(char *arg, int last_one)
+  {
+ +	unsigned char sha1[20];
+ +	struct commit *cmit;
+	struct commit_list *list;
+	static int initialized = 0;
+	struct commit_name *n;
+
+ +	if (get_sha1(arg, sha1) < 0)
+ +		usage(describe_usage);
+ +	cmit = lookup_commit_reference(sha1);
+ +	if (!cmit)
+ +		usage(describe_usage);
+ +
+	if (!initialized) {
+		initialized = 1;
+		for_each_ref(get_name);
+------------
+
+1.   It is preceded by a "git diff" header, that looks like
+     this (when the `-c` option is used):
+
+       diff --combined file
++
+or like this (when the `--cc` option is used):
+
+       diff --cc file
+
+2.   It is followed by one or more extended header lines
+     (this example shows a merge with two parents):
++
+[synopsis]
+index <hash>,<hash>..<hash>
+mode <mode>,<mode>`..`<mode>
+new file mode <mode>
+deleted file mode <mode>,<mode>
++
+The `mode <mode>,<mode>..<mode>` line appears only if at least one of
+the <mode> is different from the rest. Extended headers with
+information about detected content movement (renames and
+copying detection) are designed to work with the diff of two
+_<tree-ish>_ and are not used by combined diff format.
+
+3.   It is followed by a two-line from-file/to-file header:
+
+       --- a/file
+       +++ b/file
++
+Similar to the two-line header for the traditional 'unified' diff
+format, `/dev/null` is used to signal created or deleted
+files.
++
+However, if the --combined-all-paths option is provided, instead of a
+two-line from-file/to-file, you get an N+1 line from-file/to-file header,
+where N is the number of parents in the merge commit:
+
+       --- a/file
+       --- a/file
+       --- a/file
+       +++ b/file
++
+This extended format can be useful if rename or copy detection is
+active, to allow you to see the original name of the file in different
+parents.
+
+4.   Chunk header format is modified to prevent people from
+     accidentally feeding it to `patch -p1`. Combined diff format
+     was created for review of merge commit changes, and was not
+     meant to be applied. The change is similar to the change in the
+     extended 'index' header:
+
+       @@@ <from-file-range> <from-file-range> <to-file-range> @@@
++
+There are (number of parents + 1) `@` characters in the chunk
+header for combined diff format.
+
+Unlike the traditional 'unified' diff format, which shows two
+files A and B with a single column that has `-` (minus --
+appears in A but removed in B), `+` (plus -- missing in A but
+added to B), or `" "` (space -- unchanged) prefix, this format
+compares two or more files file1, file2,... with one file X, and
+shows how X differs from each of fileN.  One column for each of
+fileN is prepended to the output line to note how X's line is
+different from it.
+
+A `-` character in the column N means that the line appears in
+fileN but it does not appear in the result.  A `+` character
+in the column N means that the line appears in the result,
+and fileN does not have that line (in other words, the line was
+added, from the point of view of that parent).
+
+In the above example output, the function signature was changed
+from both files (hence two `-` removals from both file1 and
+file2, plus `++` to mean one line that was added does not appear
+in either file1 or file2).  Also, eight other lines are the same
+from file1 but do not appear in file2 (hence prefixed with `+`).
+
+When shown by `git diff-tree -c`, it compares the parents of a
+merge commit with the merge result (i.e. file1..fileN are the
+parents).  When shown by `git diff-files -c`, it compares the
+two unresolved merge parents with the working tree file
+(i.e. file1 is stage 2 aka "our version", file2 is stage 3 aka
+"their version").
diff --git a/Documentation/diff-options.adoc b/Documentation/diff-options.adoc
new file mode 100644
index 0000000000..640eb6e7db
--- /dev/null
+++ b/Documentation/diff-options.adoc
@@ -0,0 +1,891 @@
+// Please don't remove this comment as asciidoc behaves badly when
+// the first non-empty line is ifdef/ifndef. The symptom is that
+// without this comment the <git-diff-core> attribute conditionally
+// defined below ends up being defined unconditionally.
+// Last checked with asciidoc 7.0.2.
+
+ifndef::git-format-patch[]
+ifndef::git-diff[]
+ifndef::git-log[]
+:git-diff-core: 1
+endif::git-log[]
+endif::git-diff[]
+endif::git-format-patch[]
+
+ifdef::git-format-patch[]
+-p::
+--no-stat::
+	Generate plain patches without any diffstats.
+endif::git-format-patch[]
+
+ifndef::git-format-patch[]
+`-p`::
+`-u`::
+`--patch`::
+	Generate patch (see <<generate_patch_text_with_p>>).
+ifdef::git-diff[]
+	This is the default.
+endif::git-diff[]
+
+`-s`::
+`--no-patch`::
+	Suppress all output from the diff machinery.  Useful for
+	commands like `git show` that show the patch by default to
+	squelch their output, or to cancel the effect of options like
+	`--patch`, `--stat` earlier on the command line in an alias.
+
+endif::git-format-patch[]
+
+ifdef::git-log[]
+-m::
+	Show diffs for merge commits in the default format. This is
+	similar to `--diff-merges=on`, except `-m` will
+	produce no output unless `-p` is given as well.
+
+-c::
+	Produce combined diff output for merge commits.
+	Shortcut for `--diff-merges=combined -p`.
+
+--cc::
+	Produce dense combined diff output for merge commits.
+	Shortcut for `--diff-merges=dense-combined -p`.
+
+--dd::
+	Produce diff with respect to first parent for both merge and
+	regular commits.
+	Shortcut for `--diff-merges=first-parent -p`.
+
+--remerge-diff::
+	Produce remerge-diff output for merge commits.
+	Shortcut for `--diff-merges=remerge -p`.
+
+--no-diff-merges::
+	Synonym for `--diff-merges=off`.
+
+--diff-merges=<format>::
+	Specify diff format to be used for merge commits. Default is
+	{diff-merges-default} unless `--first-parent` is in use, in
+	which case `first-parent` is the default.
++
+The following formats are supported:
++
+--
+off, none::
+	Disable output of diffs for merge commits. Useful to override
+	implied value.
+
+on, m::
+	Make diff output for merge commits to be shown in the default
+	format. The default format can be changed using
+	`log.diffMerges` configuration variable, whose default value
+	is `separate`.
+
+first-parent, 1::
+	Show full diff with respect to first parent. This is the same
+	format as `--patch` produces for non-merge commits.
+
+separate::
+	Show full diff with respect to each of parents.
+	Separate log entry and diff is generated for each parent.
+
+combined, c::
+	Show differences from each of the parents to the merge
+	result simultaneously instead of showing pairwise diff between
+	a parent and the result one at a time. Furthermore, it lists
+	only files which were modified from all parents.
+
+dense-combined, cc::
+	Further compress output produced by `--diff-merges=combined`
+	by omitting uninteresting hunks whose contents in the parents
+	have only two variants and the merge result picks one of them
+	without modification.
+
+remerge, r::
+	Remerge two-parent merge commits to create a temporary tree
+	object--potentially containing files with conflict markers
+	and such.  A diff is then shown between that temporary tree
+	and the actual merge commit.
++
+The output emitted when this option is used is subject to change, and
+so is its interaction with other options (unless explicitly
+documented).
+--
+
+--combined-all-paths::
+	Cause combined diffs (used for merge commits) to
+	list the name of the file from all parents.  It thus only has
+	effect when `--diff-merges=[dense-]combined` is in use, and
+	is likely only useful if filename changes are detected (i.e.
+	when either rename or copy detection have been requested).
+endif::git-log[]
+
+`-U<n>`::
+`--unified=<n>`::
+	Generate diffs with _<n>_ lines of context instead of
+	the usual three.
+ifndef::git-format-patch[]
+	Implies `--patch`.
+endif::git-format-patch[]
+
+`--output=<file>`::
+	Output to a specific file instead of stdout.
+
+`--output-indicator-new=<char>`::
+`--output-indicator-old=<char>`::
+`--output-indicator-context=<char>`::
+	Specify the character used to indicate new, old or context
+	lines in the generated patch. Normally they are `+`, `-` and
+	' ' respectively.
+
+ifndef::git-format-patch[]
+`--raw`::
+ifndef::git-log[]
+	Generate the diff in raw format.
+ifdef::git-diff-core[]
+	This is the default.
+endif::git-diff-core[]
+endif::git-log[]
+ifdef::git-log[]
+	For each commit, show a summary of changes using the raw diff
+	format. See the "RAW OUTPUT FORMAT" section of
+	linkgit:git-diff[1]. This is different from showing the log
+	itself in raw format, which you can achieve with
+	`--format=raw`.
+endif::git-log[]
+endif::git-format-patch[]
+
+ifndef::git-format-patch[]
+`--patch-with-raw`::
+	Synonym for `-p --raw`.
+endif::git-format-patch[]
+
+ifdef::git-log[]
+`-t`::
+	Show the tree objects in the diff output.
+endif::git-log[]
+
+`--indent-heuristic`::
+	Enable the heuristic that shifts diff hunk boundaries to make patches
+	easier to read. This is the default.
+
+`--no-indent-heuristic`::
+	Disable the indent heuristic.
+
+`--minimal`::
+	Spend extra time to make sure the smallest possible
+	diff is produced.
+
+`--patience`::
+	Generate a diff using the "patience diff" algorithm.
+
+`--histogram`::
+	Generate a diff using the "histogram diff" algorithm.
+
+`--anchored=<text>`::
+	Generate a diff using the "anchored diff" algorithm.
++
+This option may be specified more than once.
++
+If a line exists in both the source and destination, exists only once,
+and starts with _<text>_, this algorithm attempts to prevent it from
+appearing as a deletion or addition in the output. It uses the "patience
+diff" algorithm internally.
+
+`--diff-algorithm=(patience|minimal|histogram|myers)`::
+	Choose a diff algorithm. The variants are as follows:
++
+--
+   `default`;;
+   `myers`;;
+	The basic greedy diff algorithm. Currently, this is the default.
+   `minimal`;;
+	Spend extra time to make sure the smallest possible diff is
+	produced.
+   `patience`;;
+	Use "patience diff" algorithm when generating patches.
+   `histogram`;;
+	This algorithm extends the patience algorithm to "support
+	low-occurrence common elements".
+--
++
+For instance, if you configured the `diff.algorithm` variable to a
+non-default value and want to use the default one, then you
+have to use `--diff-algorithm=default` option.
+
+`--stat[=<width>[,<name-width>[,<count>]]]`::
+	Generate a diffstat. By default, as much space as necessary
+	will be used for the filename part, and the rest for the graph
+	part. Maximum width defaults to terminal width, or 80 columns
+	if not connected to a terminal, and can be overridden by
+	_<width>_. The width of the filename part can be limited by
+	giving another width _<name-width>_ after a comma or by setting
+	`diff.statNameWidth=<name-width>`. The width of the graph part can be
+	limited by using `--stat-graph-width=<graph-width>` or by setting
+	`diff.statGraphWidth=<graph-width>`. Using `--stat` or
+	`--stat-graph-width` affects all commands generating a stat graph,
+	while setting `diff.statNameWidth` or `diff.statGraphWidth`
+	does not affect `git format-patch`.
+	By giving a third parameter _<count>_, you can limit the output to
+	the first _<count>_ lines, followed by `...` if there are more.
++
+These parameters can also be set individually with `--stat-width=<width>`,
+`--stat-name-width=<name-width>` and `--stat-count=<count>`.
+
+`--compact-summary`::
+	Output a condensed summary of extended header information such
+	as file creations or deletions ("new" or "gone", optionally `+l`
+	if it's a symlink) and mode changes (`+x` or `-x` for adding
+	or removing executable bit respectively) in diffstat. The
+	information is put between the filename part and the graph
+	part. Implies `--stat`.
+
+`--numstat`::
+	Similar to `--stat`, but shows number of added and
+	deleted lines in decimal notation and pathname without
+	abbreviation, to make it more machine friendly.  For
+	binary files, outputs two `-` instead of saying
+	`0 0`.
+
+`--shortstat`::
+	Output only the last line of the `--stat` format containing total
+	number of modified files, as well as number of added and deleted
+	lines.
+
+`-X [<param>,...]`::
+`--dirstat[=<param>,...]`::
+	Output the distribution of relative amount of changes for each
+	sub-directory. The behavior of `--dirstat` can be customized by
+	passing it a comma separated list of parameters.
+	The defaults are controlled by the `diff.dirstat` configuration
+	variable (see linkgit:git-config[1]).
+	The following parameters are available:
++
+--
+`changes`;;
+	Compute the dirstat numbers by counting the lines that have been
+	removed from the source, or added to the destination. This ignores
+	the amount of pure code movements within a file.  In other words,
+	rearranging lines in a file is not counted as much as other changes.
+	This is the default behavior when no parameter is given.
+`lines`;;
+	Compute the dirstat numbers by doing the regular line-based diff
+	analysis, and summing the removed/added line counts. (For binary
+	files, count 64-byte chunks instead, since binary files have no
+	natural concept of lines). This is a more expensive `--dirstat`
+	behavior than the `changes` behavior, but it does count rearranged
+	lines within a file as much as other changes. The resulting output
+	is consistent with what you get from the other `--*stat` options.
+`files`;;
+	Compute the dirstat numbers by counting the number of files changed.
+	Each changed file counts equally in the dirstat analysis. This is
+	the computationally cheapest `--dirstat` behavior, since it does
+	not have to look at the file contents at all.
+`cumulative`;;
+	Count changes in a child directory for the parent directory as well.
+	Note that when using `cumulative`, the sum of the percentages
+	reported may exceed 100%. The default (non-cumulative) behavior can
+	be specified with the `noncumulative` parameter.
+_<limit>_;;
+	An integer parameter specifies a cut-off percent (3% by default).
+	Directories contributing less than this percentage of the changes
+	are not shown in the output.
+--
++
+Example: The following will count changed files, while ignoring
+directories with less than 10% of the total amount of changed files,
+and accumulating child directory counts in the parent directories:
+`--dirstat=files,10,cumulative`.
+
+`--cumulative`::
+	Synonym for `--dirstat=cumulative`.
+
+`--dirstat-by-file[=<param>,...]`::
+	Synonym for `--dirstat=files,<param>,...`.
+
+`--summary`::
+	Output a condensed summary of extended header information
+	such as creations, renames and mode changes.
+
+ifndef::git-format-patch[]
+`--patch-with-stat`::
+	Synonym for `-p --stat`.
+endif::git-format-patch[]
+
+ifndef::git-format-patch[]
+
+`-z`::
+ifdef::git-log[]
+	Separate the commits with __NUL__s instead of newlines.
++
+Also, when `--raw` or `--numstat` has been given, do not munge
+pathnames and use __NUL__s as output field terminators.
+endif::git-log[]
+ifndef::git-log[]
+	When `--raw`, `--numstat`, `--name-only` or `--name-status` has been
+	given, do not munge pathnames and use NULs as output field terminators.
+endif::git-log[]
++
+Without this option, pathnames with "unusual" characters are quoted as
+explained for the configuration variable `core.quotePath` (see
+linkgit:git-config[1]).
+
+`--name-only`::
+	Show only the name of each changed file in the post-image tree.
+	The file names are often encoded in UTF-8.
+	For more information see the discussion about encoding in the linkgit:git-log[1]
+	manual page.
+
+`--name-status`::
+	Show only the name(s) and status of each changed file. See the description
+	of the `--diff-filter` option on what the status letters mean.
+	Just like `--name-only` the file names are often encoded in UTF-8.
+
+`--submodule[=<format>]`::
+	Specify how differences in submodules are shown.  When specifying
+	`--submodule=short` the `short` format is used.  This format just
+	shows the names of the commits at the beginning and end of the range.
+	When `--submodule` or `--submodule=log` is specified, the `log`
+	format is used.  This format lists the commits in the range like
+	linkgit:git-submodule[1] `summary` does.  When `--submodule=diff`
+	is specified, the `diff` format is used.  This format shows an
+	inline diff of the changes in the submodule contents between the
+	commit range.  Defaults to `diff.submodule` or the `short` format
+	if the config option is unset.
+
+`--color[=<when>]`::
+	Show colored diff.
+	`--color` (i.e. without `=<when>`) is the same as `--color=always`.
+	_<when>_ can be one of `always`, `never`, or `auto`.
+ifdef::git-diff[]
+	It can be changed by the `color.ui` and `color.diff`
+	configuration settings.
+endif::git-diff[]
+
+`--no-color`::
+	Turn off colored diff.
+ifdef::git-diff[]
+	This can be used to override configuration settings.
+endif::git-diff[]
+	It is the same as `--color=never`.
+
+`--color-moved[=<mode>]`::
+	Moved lines of code are colored differently.
+ifdef::git-diff[]
+	It can be changed by the `diff.colorMoved` configuration setting.
+endif::git-diff[]
+	The _<mode>_ defaults to `no` if the option is not given
+	and to `zebra` if the option with no mode is given.
+	The mode must be one of:
++
+--
+`no`::
+	Moved lines are not highlighted.
+`default`::
+	Is a synonym for `zebra`. This may change to a more sensible mode
+	in the future.
+`plain`::
+	Any line that is added in one location and was removed
+	in another location will be colored with `color.diff.newMoved`.
+	Similarly `color.diff.oldMoved` will be used for removed lines
+	that are added somewhere else in the diff. This mode picks up any
+	moved line, but it is not very useful in a review to determine
+	if a block of code was moved without permutation.
+`blocks`::
+	Blocks of moved text of at least 20 alphanumeric characters
+	are detected greedily. The detected blocks are
+	painted using either the `color.diff.(old|new)Moved` color.
+	Adjacent blocks cannot be told apart.
+`zebra`::
+	Blocks of moved text are detected as in `blocks` mode. The blocks
+	are painted using either the `color.diff.(old|new)Moved` color or
+	`color.diff.(old|new)MovedAlternative`. The change between
+	the two colors indicates that a new block was detected.
+`dimmed-zebra`::
+	Similar to `zebra`, but additional dimming of uninteresting parts
+	of moved code is performed. The bordering lines of two adjacent
+	blocks are considered interesting, the rest is uninteresting.
+	`dimmed_zebra` is a deprecated synonym.
+--
+
+`--no-color-moved`::
+	Turn off move detection. This can be used to override configuration
+	settings. It is the same as `--color-moved=no`.
+
+`--color-moved-ws=<mode>,...`::
+	This configures how whitespace is ignored when performing the
+	move detection for `--color-moved`.
+ifdef::git-diff[]
+	It can be set by the `diff.colorMovedWS` configuration setting.
+endif::git-diff[]
+	These modes can be given as a comma separated list:
++
+--
+`no`::
+	Do not ignore whitespace when performing move detection.
+`ignore-space-at-eol`::
+	Ignore changes in whitespace at EOL.
+`ignore-space-change`::
+	Ignore changes in amount of whitespace.  This ignores whitespace
+	at line end, and considers all other sequences of one or
+	more whitespace characters to be equivalent.
+`ignore-all-space`::
+	Ignore whitespace when comparing lines. This ignores differences
+	even if one line has whitespace where the other line has none.
+`allow-indentation-change`::
+	Initially ignore any whitespace in the move detection, then
+	group the moved code blocks only into a block if the change in
+	whitespace is the same per line. This is incompatible with the
+	other modes.
+--
+
+`--no-color-moved-ws`::
+	Do not ignore whitespace when performing move detection. This can be
+	used to override configuration settings. It is the same as
+	`--color-moved-ws=no`.
+
+`--word-diff[=<mode>]`::
+	By default, words are delimited by whitespace; see
+	`--word-diff-regex` below.  The _<mode>_ defaults to `plain`, and
+	must be one of:
++
+--
+`color`::
+	Highlight changed words using only colors.  Implies `--color`.
+`plain`::
+	Show words as ++[-removed-]++ and ++{+added+}++.  Makes no
+	attempts to escape the delimiters if they appear in the input,
+	so the output may be ambiguous.
+`porcelain`::
+	Use a special line-based format intended for script
+	consumption.  Added/removed/unchanged runs are printed in the
+	usual unified diff format, starting with a `+`/`-`/` `
+	character at the beginning of the line and extending to the
+	end of the line.  Newlines in the input are represented by a
+	tilde `~` on a line of its own.
+`none`::
+	Disable word diff again.
+--
++
+Note that despite the name of the first mode, color is used to
+highlight the changed parts in all modes if enabled.
+
+`--word-diff-regex=<regex>`::
+	Use _<regex>_ to decide what a word is, instead of considering
+	runs of non-whitespace to be a word.  Also implies
+	`--word-diff` unless it was already enabled.
++
+Every non-overlapping match of the
+_<regex>_ is considered a word.  Anything between these matches is
+considered whitespace and ignored(!) for the purposes of finding
+differences.  You may want to append `|[^[:space:]]` to your regular
+expression to make sure that it matches all non-whitespace characters.
+A match that contains a newline is silently truncated(!) at the
+newline.
++
+For example, `--word-diff-regex=.` will treat each character as a word
+and, correspondingly, show differences character by character.
++
+The regex can also be set via a diff driver or configuration option, see
+linkgit:gitattributes[5] or linkgit:git-config[1].  Giving it explicitly
+overrides any diff driver or configuration setting.  Diff drivers
+override configuration settings.
+
+`--color-words[=<regex>]`::
+	Equivalent to `--word-diff=color` plus (if a regex was
+	specified) `--word-diff-regex=<regex>`.
+endif::git-format-patch[]
+
+`--no-renames`::
+	Turn off rename detection, even when the configuration
+	file gives the default to do so.
+
+`--[no-]rename-empty`::
+	Whether to use empty blobs as rename source.
+
+ifndef::git-format-patch[]
+`--check`::
+	Warn if changes introduce conflict markers or whitespace errors.
+	What are considered whitespace errors is controlled by `core.whitespace`
+	configuration.  By default, trailing whitespaces (including
+	lines that consist solely of whitespaces) and a space character
+	that is immediately followed by a tab character inside the
+	initial indent of the line are considered whitespace errors.
+	Exits with non-zero status if problems are found. Not compatible
+	with `--exit-code`.
+
+`--ws-error-highlight=<kind>`::
+	Highlight whitespace errors in the `context`, `old` or `new`
+	lines of the diff.  Multiple values are separated by comma,
+	`none` resets previous values, `default` reset the list to
+	`new` and `all` is a shorthand for `old,new,context`.  When
+	this option is not given, and the configuration variable
+	`diff.wsErrorHighlight` is not set, only whitespace errors in
+	`new` lines are highlighted. The whitespace errors are colored
+	with `color.diff.whitespace`.
+
+endif::git-format-patch[]
+
+`--full-index`::
+	Instead of the first handful of characters, show the full
+	pre- and post-image blob object names on the "index"
+	line when generating patch format output.
+
+`--binary`::
+	In addition to `--full-index`, output a binary diff that
+	can be applied with `git-apply`.
+ifndef::git-format-patch[]
+	Implies `--patch`.
+endif::git-format-patch[]
+
+`--abbrev[=<n>]`::
+	Instead of showing the full 40-byte hexadecimal object
+	name in diff-raw format output and diff-tree header
+	lines, show the shortest prefix that is at least _<n>_
+	hexdigits long that uniquely refers the object.
+	In diff-patch output format, `--full-index` takes higher
+	precedence, i.e. if `--full-index` is specified, full blob
+	names will be shown regardless of `--abbrev`.
+	Non default number of digits can be specified with `--abbrev=<n>`.
+
+`-B[<n>][/<m>]`::
+`--break-rewrites[=[<n>][/<m>]]`::
+	Break complete rewrite changes into pairs of delete and
+	create. This serves two purposes:
++
+It affects the way a change that amounts to a total rewrite of a file
+not as a series of deletion and insertion mixed together with a very
+few lines that happen to match textually as the context, but as a
+single deletion of everything old followed by a single insertion of
+everything new, and the number _<m>_ controls this aspect of the `-B`
+option (defaults to 60%). `-B/70%` specifies that less than 30% of the
+original should remain in the result for Git to consider it a total
+rewrite (i.e. otherwise the resulting patch will be a series of
+deletion and insertion mixed together with context lines).
++
+When used with `-M`, a totally-rewritten file is also considered as the
+source of a rename (usually `-M` only considers a file that disappeared
+as the source of a rename), and the number _<n>_ controls this aspect of
+the `-B` option (defaults to 50%). `-B20%` specifies that a change with
+addition and deletion compared to 20% or more of the file's size are
+eligible for being picked up as a possible source of a rename to
+another file.
+
+`-M[<n>]`::
+`--find-renames[=<n>]`::
+ifndef::git-log[]
+	Detect renames.
+endif::git-log[]
+ifdef::git-log[]
+	If generating diffs, detect and report renames for each commit.
+	For following files across renames while traversing history, see
+	`--follow`.
+endif::git-log[]
+	If _<n>_ is specified, it is a threshold on the similarity
+	index (i.e. amount of addition/deletions compared to the
+	file's size). For example, `-M90%` means Git should consider a
+	delete/add pair to be a rename if more than 90% of the file
+	hasn't changed.  Without a `%` sign, the number is to be read as
+	a fraction, with a decimal point before it.  I.e., `-M5` becomes
+	0.5, and is thus the same as `-M50%`.  Similarly, `-M05` is
+	the same as `-M5%`.  To limit detection to exact renames, use
+	`-M100%`.  The default similarity index is 50%.
+
+`-C[<n>]`::
+`--find-copies[=<n>]`::
+	Detect copies as well as renames.  See also `--find-copies-harder`.
+	If _<n>_ is specified, it has the same meaning as for `-M<n>`.
+
+`--find-copies-harder`::
+	For performance reasons, by default, `-C` option finds copies only
+	if the original file of the copy was modified in the same
+	changeset.  This flag makes the command
+	inspect unmodified files as candidates for the source of
+	copy.  This is a very expensive operation for large
+	projects, so use it with caution.  Giving more than one
+	`-C` option has the same effect.
+
+`-D`::
+`--irreversible-delete`::
+	Omit the preimage for deletes, i.e. print only the header but not
+	the diff between the preimage and `/dev/null`. The resulting patch
+	is not meant to be applied with `patch` or `git apply`; this is
+	solely for people who want to just concentrate on reviewing the
+	text after the change. In addition, the output obviously lacks
+	enough information to apply such a patch in reverse, even manually,
+	hence the name of the option.
++
+When used together with `-B`, omit also the preimage in the deletion part
+of a delete/create pair.
+
+`-l<num>`::
+	The `-M` and `-C` options involve some preliminary steps that
+	can detect subsets of renames/copies cheaply, followed by an
+	exhaustive fallback portion that compares all remaining
+	unpaired destinations to all relevant sources.  (For renames,
+	only remaining unpaired sources are relevant; for copies, all
+	original sources are relevant.)  For N sources and
+	destinations, this exhaustive check is O(N^2).  This option
+	prevents the exhaustive portion of rename/copy detection from
+	running if the number of source/destination files involved
+	exceeds the specified number.  Defaults to `diff.renameLimit`.
+	Note that a value of 0 is treated as unlimited.
+
+ifndef::git-format-patch[]
+`--diff-filter=[(A|C|D|M|R|T|U|X|B)...[*]]`::
+	Select only files that are Added (`A`), Copied (`C`),
+	Deleted (`D`), Modified (`M`), Renamed (`R`), have their
+	type (i.e. regular file, symlink, submodule, ...) changed (`T`),
+	are Unmerged (`U`), are
+	Unknown (`X`), or have had their pairing Broken (`B`).
+	Any combination of the filter characters (including none) can be used.
+	When `*` (All-or-none) is added to the combination, all
+	paths are selected if there is any file that matches
+	other criteria in the comparison; if there is no file
+	that matches other criteria, nothing is selected.
++
+Also, these upper-case letters can be downcased to exclude.  E.g.
+`--diff-filter=ad` excludes added and deleted paths.
++
+Note that not all diffs can feature all types. For instance, copied and
+renamed entries cannot appear if detection for those types is disabled.
+
+`-S<string>`::
+	Look for differences that change the number of occurrences of
+	the specified _<string>_ (i.e. addition/deletion) in a file.
+	Intended for the scripter's use.
++
+It is useful when you're looking for an exact block of code (like a
+struct), and want to know the history of that block since it first
+came into being: use the feature iteratively to feed the interesting
+block in the preimage back into `-S`, and keep going until you get the
+very first version of the block.
++
+Binary files are searched as well.
+
+`-G<regex>`::
+	Look for differences whose patch text contains added/removed
+	lines that match _<regex>_.
++
+To illustrate the difference between `-S<regex>` `--pickaxe-regex` and
+`-G<regex>`, consider a commit with the following diff in the same
+file:
++
+----
++    return frotz(nitfol, two->ptr, 1, 0);
+...
+-    hit = frotz(nitfol, mf2.ptr, 1, 0);
+----
++
+While `git log -G"frotz\(nitfol"` will show this commit, `git log
+-S"frotz\(nitfol" --pickaxe-regex` will not (because the number of
+occurrences of that string did not change).
++
+Unless `--text` is supplied patches of binary files without a textconv
+filter will be ignored.
++
+See the 'pickaxe' entry in linkgit:gitdiffcore[7] for more
+information.
+
+`--find-object=<object-id>`::
+	Look for differences that change the number of occurrences of
+	the specified object. Similar to `-S`, just the argument is different
+	in that it doesn't search for a specific string but for a specific
+	object id.
++
+The object can be a blob or a submodule commit. It implies the `-t` option in
+`git-log` to also find trees.
+
+`--pickaxe-all`::
+	When `-S` or `-G` finds a change, show all the changes in that
+	changeset, not just the files that contain the change
+	in _<string>_.
+
+`--pickaxe-regex`::
+	Treat the _<string>_ given to `-S` as an extended POSIX regular
+	expression to match.
+
+endif::git-format-patch[]
+
+`-O<orderfile>`::
+	Control the order in which files appear in the output.
+	This overrides the `diff.orderFile` configuration variable
+	(see linkgit:git-config[1]).  To cancel `diff.orderFile`,
+	use `-O/dev/null`.
++
+The output order is determined by the order of glob patterns in
+_<orderfile>_.
+All files with pathnames that match the first pattern are output
+first, all files with pathnames that match the second pattern (but not
+the first) are output next, and so on.
+All files with pathnames that do not match any pattern are output
+last, as if there was an implicit match-all pattern at the end of the
+file.
+If multiple pathnames have the same rank (they match the same pattern
+but no earlier patterns), their output order relative to each other is
+the normal order.
++
+_<orderfile>_ is parsed as follows:
++
+--
+ - Blank lines are ignored, so they can be used as separators for
+   readability.
+
+ - Lines starting with a hash ("`#`") are ignored, so they can be used
+   for comments.  Add a backslash ("`\`") to the beginning of the
+   pattern if it starts with a hash.
+
+ - Each other line contains a single pattern.
+--
++
+Patterns have the same syntax and semantics as patterns used for
+`fnmatch`(3) without the `FNM_PATHNAME` flag, except a pathname also
+matches a pattern if removing any number of the final pathname
+components matches the pattern.  For example, the pattern "`foo*bar`"
+matches "`fooasdfbar`" and "`foo/bar/baz/asdf`" but not "`foobarx`".
+
+`--skip-to=<file>`::
+`--rotate-to=<file>`::
+	Discard the files before the named _<file>_ from the output
+	(i.e. 'skip to'), or move them to the end of the output
+	(i.e. 'rotate to').  These options were invented primarily for the use
+	of the `git difftool` command, and may not be very useful
+	otherwise.
+
+ifndef::git-format-patch[]
+`-R`::
+	Swap two inputs; that is, show differences from index or
+	on-disk file to tree contents.
+endif::git-format-patch[]
+
+`--relative[=<path>]`::
+`--no-relative`::
+	When run from a subdirectory of the project, it can be
+	told to exclude changes outside the directory and show
+	pathnames relative to it with this option.  When you are
+	not in a subdirectory (e.g. in a bare repository), you
+	can name which subdirectory to make the output relative
+	to by giving a _<path>_ as an argument.
+	`--no-relative` can be used to countermand both `diff.relative` config
+	option and previous `--relative`.
+
+`-a`::
+`--text`::
+	Treat all files as text.
+
+`--ignore-cr-at-eol`::
+	Ignore carriage-return at the end of line when doing a comparison.
+
+`--ignore-space-at-eol`::
+	Ignore changes in whitespace at EOL.
+
+`-b`::
+`--ignore-space-change`::
+	Ignore changes in amount of whitespace.  This ignores whitespace
+	at line end, and considers all other sequences of one or
+	more whitespace characters to be equivalent.
+
+`-w`::
+`--ignore-all-space`::
+	Ignore whitespace when comparing lines.  This ignores
+	differences even if one line has whitespace where the other
+	line has none.
+
+`--ignore-blank-lines`::
+	Ignore changes whose lines are all blank.
+
+
+`-I<regex>`::
+`--ignore-matching-lines=<regex>`::
+	Ignore changes whose all lines match _<regex>_.  This option may
+	be specified more than once.
+
+`--inter-hunk-context=<number>`::
+	Show the context between diff hunks, up to the specified _<number>_
+	of lines, thereby fusing hunks that are close to each other.
+	Defaults to `diff.interHunkContext` or 0 if the config option
+	is unset.
+
+`-W`::
+`--function-context`::
+	Show whole function as context lines for each change.
+	The function names are determined in the same way as
+	`git diff` works out patch hunk headers (see "Defining a
+	custom hunk-header" in linkgit:gitattributes[5]).
+
+ifndef::git-format-patch[]
+ifndef::git-log[]
+`--exit-code`::
+	Make the program exit with codes similar to `diff`(1).
+	That is, it exits with 1 if there were differences and
+	0 means no differences.
+
+`--quiet`::
+	Disable all output of the program. Implies `--exit-code`.
+	Disables execution of external diff helpers whose exit code
+	is not trusted, i.e. their respective configuration option
+	`diff.trustExitCode` or ++diff.++__<driver>__++.trustExitCode++ or
+	environment variable `GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE` is
+	false.
+endif::git-log[]
+endif::git-format-patch[]
+
+`--ext-diff`::
+	Allow an external diff helper to be executed. If you set an
+	external diff driver with linkgit:gitattributes[5], you need
+	to use this option with linkgit:git-log[1] and friends.
+
+`--no-ext-diff`::
+	Disallow external diff drivers.
+
+`--textconv`::
+`--no-textconv`::
+	Allow (or disallow) external text conversion filters to be run
+	when comparing binary files. See linkgit:gitattributes[5] for
+	details. Because textconv filters are typically a one-way
+	conversion, the resulting diff is suitable for human
+	consumption, but cannot be applied. For this reason, textconv
+	filters are enabled by default only for linkgit:git-diff[1] and
+	linkgit:git-log[1], but not for linkgit:git-format-patch[1] or
+	diff plumbing commands.
+
+
+`--ignore-submodules[=(none|untracked|dirty|all)]`::
+	Ignore changes to submodules in the diff generation. `all` is the default.
+	Using `none` will consider the submodule modified when it either contains
+	untracked or modified files or its `HEAD` differs from the commit recorded
+	in the superproject and can be used to override any settings of the
+	`ignore` option in linkgit:git-config[1] or linkgit:gitmodules[5]. When
+	`untracked` is used submodules are not considered dirty when they only
+	contain untracked content (but they are still scanned for modified
+	content). Using `dirty` ignores all changes to the work tree of submodules,
+	only changes to the commits stored in the superproject are shown (this was
+	the behavior until 1.7.0). Using `all` hides all changes to submodules.
+
+`--src-prefix=<prefix>`::
+	Show the given source _<prefix>_ instead of "a/".
+
+`--dst-prefix=<prefix>`::
+	Show the given destination _<prefix>_ instead of "b/".
+
+`--no-prefix`::
+	Do not show any source or destination prefix.
+
+`--default-prefix`::
+	Use the default source and destination prefixes ("a/" and "b/").
+	This overrides configuration variables such as `diff.noprefix`,
+	`diff.srcPrefix`, `diff.dstPrefix`, and `diff.mnemonicPrefix`
+	(see linkgit:git-config[1]).
+
+`--line-prefix=<prefix>`::
+	Prepend an additional _<prefix>_ to every line of output.
+
+`--ita-invisible-in-index`::
+	By default entries added by `git add -N` appear as an existing
+	empty file in `git diff` and a new file in `git diff --cached`.
+	This option makes the entry appear as a new file in `git diff`
+	and non-existent in `git diff --cached`. This option could be
+	reverted with `--ita-visible-in-index`. Both options are
+	experimental and could be removed in future.
+
+For more detailed explanation on these common options, see also
+linkgit:gitdiffcore[7].
diff --git a/Documentation/doc-diff b/Documentation/doc-diff
new file mode 100755
index 0000000000..fb09e0ac0e
--- /dev/null
+++ b/Documentation/doc-diff
@@ -0,0 +1,186 @@
+#!/bin/sh
+#
+# Build two documentation trees and diff the resulting formatted output.
+# Compared to a source diff, this can reveal mistakes in the formatting.
+# For example:
+#
+#   ./doc-diff origin/master HEAD
+#
+# would show the differences introduced by a branch based on master.
+
+OPTIONS_SPEC="\
+doc-diff [options] <from> <to> [-- <diff-options>]
+doc-diff (-c|--clean)
+--
+j=n			parallel argument to pass to make
+f			force rebuild; do not rely on cached results
+c,clean			cleanup temporary working files
+from-asciidoc		use asciidoc with the 'from'-commit
+from-asciidoctor	use asciidoctor with the 'from'-commit
+asciidoc		use asciidoc with both commits
+to-asciidoc		use asciidoc with the 'to'-commit
+to-asciidoctor		use asciidoctor with the 'to'-commit
+asciidoctor		use asciidoctor with both commits
+cut-footer		cut away footer
+"
+SUBDIRECTORY_OK=1
+. "$(git --exec-path)/git-sh-setup"
+
+parallel=
+force=
+clean=
+from_program=
+to_program=
+cut_footer=
+while test $# -gt 0
+do
+	case "$1" in
+	-j)
+		parallel=$2; shift ;;
+	-c|--clean)
+		clean=t ;;
+	-f)
+		force=t ;;
+	--from-asciidoctor)
+		from_program=-asciidoctor ;;
+	--to-asciidoctor)
+		to_program=-asciidoctor ;;
+	--asciidoctor)
+		from_program=-asciidoctor
+		to_program=-asciidoctor ;;
+	--from-asciidoc)
+		from_program=-asciidoc ;;
+	--to-asciidoc)
+		to_program=-asciidoc ;;
+	--asciidoc)
+		from_program=-asciidoc
+		to_program=-asciidoc ;;
+	--cut-footer)
+		cut_footer=-cut-footer ;;
+	--)
+		shift; break ;;
+	*)
+		usage ;;
+	esac
+	shift
+done
+
+tmp="$(git rev-parse --show-toplevel)/Documentation/tmp-doc-diff" || exit 1
+
+if test -n "$clean"
+then
+	test $# -eq 0 || usage
+	git worktree remove --force "$tmp/worktree" 2>/dev/null
+	rm -rf "$tmp"
+	exit 0
+fi
+
+if test -z "$parallel"
+then
+	parallel=$(getconf _NPROCESSORS_ONLN 2>/dev/null)
+	if test $? != 0 || test -z "$parallel"
+	then
+		parallel=1
+	fi
+fi
+
+test $# -gt 1 || usage
+from=$1; shift
+to=$1; shift
+
+from_oid=$(git rev-parse --verify "$from") || exit 1
+to_oid=$(git rev-parse --verify "$to") || exit 1
+
+if test -n "$force"
+then
+	rm -rf "$tmp"
+fi
+
+# We'll do both builds in a single worktree, which lets "make" reuse
+# results that don't differ between the two trees.
+if ! test -d "$tmp/worktree"
+then
+	git worktree add -f --detach "$tmp/worktree" "$from" &&
+	dots=$(echo "$tmp/worktree" | sed 's#[^/]*#..#g') &&
+	ln -s "$dots/config.mak" "$tmp/worktree/config.mak"
+fi
+
+construct_makemanflags () {
+	if test "$1" = "-asciidoc"
+	then
+		echo USE_ASCIIDOCTOR=
+	elif test "$1" = "-asciidoctor"
+	then
+		echo USE_ASCIIDOCTOR=YesPlease
+	fi
+}
+
+from_makemanflags=$(construct_makemanflags "$from_program") &&
+to_makemanflags=$(construct_makemanflags "$to_program") &&
+
+from_dir=$from_oid$from_program$cut_footer &&
+to_dir=$to_oid$to_program$cut_footer &&
+
+# generate_render_makefile <srcdir> <dstdir>
+generate_render_makefile () {
+	find "$1" -type f |
+	while read src
+	do
+		dst=$2/${src#$1/}
+		printf 'all: %s\n' "$dst"
+		printf '%s: %s\n' "$dst" "$src"
+		printf '\t@echo >&2 "  RENDER $(notdir $@)" && \\\n'
+		printf '\tmkdir -p $(dir $@) && \\\n'
+		printf '\tMANWIDTH=80 man $< >$@+ && \\\n'
+		printf '\tmv $@+ $@\n'
+	done
+}
+
+# render_tree <committish_oid> <directory_name> <makemanflags>
+render_tree () {
+	# Skip install-man entirely if we already have an installed directory.
+	# We can't rely on make here, since "install-man" unconditionally
+	# copies the files (spending effort, but also updating timestamps that
+	# we then can't rely on during the render step). We use "mv" to make
+	# sure we don't get confused by a previous run that failed partway
+	# through.
+	oid=$1 &&
+	dname=$2 &&
+	makemanflags=$3 &&
+	if ! test -d "$tmp/installed/$dname"
+	then
+		git -C "$tmp/worktree" checkout --detach "$oid" &&
+		make -j$parallel -C "$tmp/worktree" \
+			$makemanflags \
+			GIT_VERSION=omitted \
+			GIT_DATE=1970-01-01 \
+			DESTDIR="$tmp/installed/$dname+" \
+			install-man &&
+		mv "$tmp/installed/$dname+" "$tmp/installed/$dname"
+	fi &&
+
+	# As with "installed" above, we skip the render if it's already been
+	# done.  So using make here is primarily just about running in
+	# parallel.
+	if ! test -d "$tmp/rendered/$dname"
+	then
+		generate_render_makefile "$tmp/installed/$dname" \
+			"$tmp/rendered/$dname+" |
+		make -j$parallel -f - &&
+		mv "$tmp/rendered/$dname+" "$tmp/rendered/$dname"
+
+		if test "$cut_footer" = "-cut-footer"
+		then
+			for f in $(find "$tmp/rendered/$dname" -type f)
+			do
+				head -n -2 "$f" | sed -e '${/^$/d}' >"$f+" &&
+				mv "$f+" "$f" ||
+				return 1
+			done
+		fi
+	fi
+}
+
+render_tree $from_oid $from_dir $from_makemanflags &&
+render_tree $to_oid $to_dir $to_makemanflags &&
+git -C $tmp/rendered diff --no-index "$@" $from_dir $to_dir
diff --git a/Documentation/docbook-xsl.css b/Documentation/docbook-xsl.css
new file mode 100644
index 0000000000..e11c8f053a
--- /dev/null
+++ b/Documentation/docbook-xsl.css
@@ -0,0 +1,296 @@
+/*
+  CSS stylesheet for XHTML produced by DocBook XSL stylesheets.
+  Tested with XSL stylesheets 1.61.2, 1.67.2
+*/
+
+span.strong {
+  font-weight: bold;
+}
+
+body blockquote {
+  margin-top: .75em;
+  line-height: 1.5;
+  margin-bottom: .75em;
+}
+
+html body {
+  margin: 1em 5% 1em 5%;
+  line-height: 1.2;
+  font-family: sans-serif;
+}
+
+body div {
+  margin: 0;
+}
+
+h1, h2, h3, h4, h5, h6,
+div.toc p b,
+div.list-of-figures p b,
+div.list-of-tables p b,
+div.abstract p.title
+{
+  color: #527bbd;
+  font-family: tahoma, verdana, sans-serif;
+}
+
+div.toc p:first-child,
+div.list-of-figures p:first-child,
+div.list-of-tables p:first-child,
+div.example p.title
+{
+  margin-bottom: 0.2em;
+}
+
+body h1 {
+  margin: .0em 0 0 -4%;
+  line-height: 1.3;
+  border-bottom: 2px solid silver;
+}
+
+body h2 {
+  margin: 0.5em 0 0 -4%;
+  line-height: 1.3;
+  border-bottom: 2px solid silver;
+}
+
+body h3 {
+  margin: .8em 0 0 -3%;
+  line-height: 1.3;
+}
+
+body h4 {
+  margin: .8em 0 0 -3%;
+  line-height: 1.3;
+}
+
+body h5 {
+  margin: .8em 0 0 -2%;
+  line-height: 1.3;
+}
+
+body h6 {
+  margin: .8em 0 0 -1%;
+  line-height: 1.3;
+}
+
+body hr {
+  border: none; /* Broken on IE6 */
+}
+div.footnotes hr {
+  border: 1px solid silver;
+}
+
+div.navheader th, div.navheader td, div.navfooter td {
+  font-family: sans-serif;
+  font-size: 0.9em;
+  font-weight: bold;
+  color: #527bbd;
+}
+div.navheader img, div.navfooter img {
+  border-style: none;
+}
+div.navheader a, div.navfooter a {
+  font-weight: normal;
+}
+div.navfooter hr {
+  border: 1px solid silver;
+}
+
+body td {
+  line-height: 1.2
+}
+
+body th {
+  line-height: 1.2;
+}
+
+ol {
+  line-height: 1.2;
+}
+
+ul, body dir, body menu {
+  line-height: 1.2;
+}
+
+html {
+  margin: 0;
+  padding: 0;
+}
+
+body h1, body h2, body h3, body h4, body h5, body h6 {
+  margin-left: 0
+}
+
+body pre {
+  margin: 0.5em 10% 0.5em 1em;
+  line-height: 1.0;
+  color: navy;
+}
+
+tt.literal, code.literal {
+  color: navy;
+  font-family: sans-serif;
+}
+
+code.literal:before { content: "'"; }
+code.literal:after { content: "'"; }
+
+em {
+  font-style: italic;
+  color: #064;
+}
+
+div.literallayout p {
+  padding: 0em;
+  margin: 0em;
+}
+
+div.literallayout {
+  font-family: monospace;
+  margin: 0em;
+  color: navy;
+  border: 1px solid silver;
+  background: #f4f4f4;
+  padding: 0.5em;
+}
+
+.programlisting, .screen {
+  border: 1px solid silver;
+  background: #f4f4f4;
+  margin: 0.5em 10% 0.5em 0;
+  padding: 0.5em 1em;
+}
+
+div.sidebar {
+  background: #ffffee;
+  margin: 1.0em 10% 0.5em 0;
+  padding: 0.5em 1em;
+  border: 1px solid silver;
+}
+div.sidebar * { padding: 0; }
+div.sidebar div { margin: 0; }
+div.sidebar p.title {
+  font-family: sans-serif;
+  margin-top: 0.5em;
+  margin-bottom: 0.2em;
+}
+
+div.bibliomixed {
+  margin: 0.5em 5% 0.5em 1em;
+}
+
+div.glossary dt {
+  font-weight: bold;
+}
+div.glossary dd p {
+  margin-top: 0.2em;
+}
+
+dl {
+  margin: .8em 0;
+  line-height: 1.2;
+}
+
+dt {
+  margin-top: 0.5em;
+}
+
+dt span.term {
+  font-style: normal;
+  color: navy;
+}
+
+div.variablelist dd p {
+  margin-top: 0;
+}
+
+div.itemizedlist li, div.orderedlist li {
+  margin-left: -0.8em;
+  margin-top: 0.5em;
+}
+
+ul, ol {
+    list-style-position: outside;
+}
+
+div.sidebar ul, div.sidebar ol {
+    margin-left: 2.8em;
+}
+
+div.itemizedlist p.title,
+div.orderedlist p.title,
+div.variablelist p.title
+{
+  margin-bottom: -0.8em;
+}
+
+div.revhistory table {
+  border-collapse: collapse;
+  border: none;
+}
+div.revhistory th {
+  border: none;
+  color: #527bbd;
+  font-family: tahoma, verdana, sans-serif;
+}
+div.revhistory td {
+  border: 1px solid silver;
+}
+
+/* Keep TOC and index lines close together. */
+div.toc dl, div.toc dt,
+div.list-of-figures dl, div.list-of-figures dt,
+div.list-of-tables dl, div.list-of-tables dt,
+div.indexdiv dl, div.indexdiv dt
+{
+  line-height: normal;
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+/*
+  Table styling does not work because of overriding attributes in
+  generated HTML.
+*/
+div.table table,
+div.informaltable table
+{
+    margin-left: 0;
+    margin-right: 5%;
+    margin-bottom: 0.8em;
+}
+div.informaltable table
+{
+    margin-top: 0.4em
+}
+div.table thead,
+div.table tfoot,
+div.table tbody,
+div.informaltable thead,
+div.informaltable tfoot,
+div.informaltable tbody
+{
+    /* No effect in IE6. */
+    border-top: 2px solid #527bbd;
+    border-bottom: 2px solid #527bbd;
+}
+div.table thead, div.table tfoot,
+div.informaltable thead, div.informaltable tfoot
+{
+    font-weight: bold;
+}
+
+div.mediaobject img {
+    border: 1px solid silver;
+    margin-bottom: 0.8em;
+}
+div.figure p.title,
+div.table p.title
+{
+  margin-top: 1em;
+  margin-bottom: 0.4em;
+}
+
+@media print {
+  div.navheader, div.navfooter { display: none; }
+}
diff --git a/Documentation/docbook.xsl b/Documentation/docbook.xsl
new file mode 100644
index 0000000000..da8b05b922
--- /dev/null
+++ b/Documentation/docbook.xsl
@@ -0,0 +1,8 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+		version='1.0'>
+ <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/html/docbook.xsl"/>
+ <xsl:output method="html"
+     encoding="UTF-8" indent="no"
+     doctype-public="-//W3C//DTD HTML 4.01//EN"
+     doctype-system="http://www.w3.org/TR/html4/strict.dtd"; />
+</xsl:stylesheet>
diff --git a/Documentation/docinfo-html.in b/Documentation/docinfo-html.in
new file mode 100644
index 0000000000..fb3560eb92
--- /dev/null
+++ b/Documentation/docinfo-html.in
@@ -0,0 +1,5 @@
+<style>
+pre>code {
+   display: inline;
+}
+</style>
diff --git a/Documentation/everyday.txto b/Documentation/everyday.txto
new file mode 100644
index 0000000000..ae555bd47e
--- /dev/null
+++ b/Documentation/everyday.txto
@@ -0,0 +1,9 @@
+Everyday Git With 20 Commands Or So
+===================================
+
+This document has been moved to linkgit:giteveryday[7].
+
+Please let the owners of the referring site know so that they can update the
+link you clicked to get here.
+
+Thanks.
diff --git a/Documentation/fetch-options.adoc b/Documentation/fetch-options.adoc
new file mode 100644
index 0000000000..b01372e4b3
--- /dev/null
+++ b/Documentation/fetch-options.adoc
@@ -0,0 +1,331 @@
+--[no-]all::
+	Fetch all remotes, except for the ones that has the
+	`remote.<name>.skipFetchAll` configuration variable set.
+	This overrides the configuration variable fetch.all`.
+
+-a::
+--append::
+	Append ref names and object names of fetched refs to the
+	existing contents of `.git/FETCH_HEAD`.  Without this
+	option old data in `.git/FETCH_HEAD` will be overwritten.
+
+--atomic::
+	Use an atomic transaction to update local refs. Either all refs are
+	updated, or on error, no refs are updated.
+
+--depth=<depth>::
+	Limit fetching to the specified number of commits from the tip of
+	each remote branch history. If fetching to a 'shallow' repository
+	created by `git clone` with `--depth=<depth>` option (see
+	linkgit:git-clone[1]), deepen or shorten the history to the specified
+	number of commits. Tags for the deepened commits are not fetched.
+
+--deepen=<depth>::
+	Similar to --depth, except it specifies the number of commits
+	from the current shallow boundary instead of from the tip of
+	each remote branch history.
+
+--shallow-since=<date>::
+	Deepen or shorten the history of a shallow repository to
+	include all reachable commits after <date>.
+
+--shallow-exclude=<ref>::
+	Deepen or shorten the history of a shallow repository to
+	exclude commits reachable from a specified remote branch or tag.
+	This option can be specified multiple times.
+
+--unshallow::
+	If the source repository is complete, convert a shallow
+	repository to a complete one, removing all the limitations
+	imposed by shallow repositories.
++
+If the source repository is shallow, fetch as much as possible so that
+the current repository has the same history as the source repository.
+
+--update-shallow::
+	By default when fetching from a shallow repository,
+	`git fetch` refuses refs that require updating
+	.git/shallow. This option updates .git/shallow and accepts such
+	refs.
+
+--negotiation-tip=<commit|glob>::
+	By default, Git will report, to the server, commits reachable
+	from all local refs to find common commits in an attempt to
+	reduce the size of the to-be-received packfile. If specified,
+	Git will only report commits reachable from the given tips.
+	This is useful to speed up fetches when the user knows which
+	local ref is likely to have commits in common with the
+	upstream ref being fetched.
++
+This option may be specified more than once; if so, Git will report
+commits reachable from any of the given commits.
++
+The argument to this option may be a glob on ref names, a ref, or the (possibly
+abbreviated) SHA-1 of a commit. Specifying a glob is equivalent to specifying
+this option multiple times, one for each matching ref name.
++
+See also the `fetch.negotiationAlgorithm` and `push.negotiate`
+configuration variables documented in linkgit:git-config[1], and the
+`--negotiate-only` option below.
+
+--negotiate-only::
+	Do not fetch anything from the server, and instead print the
+	ancestors of the provided `--negotiation-tip=*` arguments,
+	which we have in common with the server.
++
+This is incompatible with `--recurse-submodules=[yes|on-demand]`.
+Internally this is used to implement the `push.negotiate` option, see
+linkgit:git-config[1].
+
+--dry-run::
+	Show what would be done, without making any changes.
+
+--porcelain::
+	Print the output to standard output in an easy-to-parse format for
+	scripts. See section OUTPUT in linkgit:git-fetch[1] for details.
++
+This is incompatible with `--recurse-submodules=[yes|on-demand]` and takes
+precedence over the `fetch.output` config option.
+
+ifndef::git-pull[]
+--[no-]write-fetch-head::
+	Write the list of remote refs fetched in the `FETCH_HEAD`
+	file directly under `$GIT_DIR`.  This is the default.
+	Passing `--no-write-fetch-head` from the command line tells
+	Git not to write the file.  Under `--dry-run` option, the
+	file is never written.
+endif::git-pull[]
+
+-f::
+--force::
+	When 'git fetch' is used with `<src>:<dst>` refspec, it may
+	refuse to update the local branch as discussed
+ifdef::git-pull[]
+	in the `<refspec>` part of the linkgit:git-fetch[1]
+	documentation.
+endif::git-pull[]
+ifndef::git-pull[]
+	in the `<refspec>` part below.
+endif::git-pull[]
+	This option overrides that check.
+
+-k::
+--keep::
+	Keep downloaded pack.
+
+ifndef::git-pull[]
+--multiple::
+	Allow several <repository> and <group> arguments to be
+	specified. No <refspec>s may be specified.
+
+--[no-]auto-maintenance::
+--[no-]auto-gc::
+	Run `git maintenance run --auto` at the end to perform automatic
+	repository maintenance if needed. (`--[no-]auto-gc` is a synonym.)
+	This is enabled by default.
+
+--[no-]write-commit-graph::
+	Write a commit-graph after fetching. This overrides the config
+	setting `fetch.writeCommitGraph`.
+endif::git-pull[]
+
+--prefetch::
+	Modify the configured refspec to place all refs into the
+	`refs/prefetch/` namespace. See the `prefetch` task in
+	linkgit:git-maintenance[1].
+
+-p::
+--prune::
+	Before fetching, remove any remote-tracking references that no
+	longer exist on the remote.  Tags are not subject to pruning
+	if they are fetched only because of the default tag
+	auto-following or due to a --tags option.  However, if tags
+	are fetched due to an explicit refspec (either on the command
+	line or in the remote configuration, for example if the remote
+	was cloned with the --mirror option), then they are also
+	subject to pruning. Supplying `--prune-tags` is a shorthand for
+	providing the tag refspec.
+ifndef::git-pull[]
++
+See the PRUNING section below for more details.
+
+-P::
+--prune-tags::
+	Before fetching, remove any local tags that no longer exist on
+	the remote if `--prune` is enabled. This option should be used
+	more carefully, unlike `--prune` it will remove any local
+	references (local tags) that have been created. This option is
+	a shorthand for providing the explicit tag refspec along with
+	`--prune`, see the discussion about that in its documentation.
++
+See the PRUNING section below for more details.
+
+endif::git-pull[]
+
+ifndef::git-pull[]
+-n::
+endif::git-pull[]
+--no-tags::
+	By default, tags that point at objects that are downloaded
+	from the remote repository are fetched and stored locally.
+	This option disables this automatic tag following. The default
+	behavior for a remote may be specified with the remote.<name>.tagOpt
+	setting. See linkgit:git-config[1].
+
+ifndef::git-pull[]
+--refetch::
+	Instead of negotiating with the server to avoid transferring commits and
+	associated objects that are already present locally, this option fetches
+	all objects as a fresh clone would. Use this to reapply a partial clone
+	filter from configuration or using `--filter=` when the filter
+	definition has changed. Automatic post-fetch maintenance will perform
+	object database pack consolidation to remove any duplicate objects.
+endif::git-pull[]
+
+--refmap=<refspec>::
+	When fetching refs listed on the command line, use the
+	specified refspec (can be given more than once) to map the
+	refs to remote-tracking branches, instead of the values of
+	`remote.*.fetch` configuration variables for the remote
+	repository.  Providing an empty `<refspec>` to the
+	`--refmap` option causes Git to ignore the configured
+	refspecs and rely entirely on the refspecs supplied as
+	command-line arguments. See section on "Configured Remote-tracking
+	Branches" for details.
+
+-t::
+--tags::
+	Fetch all tags from the remote (i.e., fetch remote tags
+	`refs/tags/*` into local tags with the same name), in addition
+	to whatever else would otherwise be fetched.  Using this
+	option alone does not subject tags to pruning, even if --prune
+	is used (though tags may be pruned anyway if they are also the
+	destination of an explicit refspec; see `--prune`).
+
+ifndef::git-pull[]
+--recurse-submodules[=(yes|on-demand|no)]::
+	This option controls if and under what conditions new commits of
+	submodules should be fetched too. When recursing through submodules,
+	`git fetch` always attempts to fetch "changed" submodules, that is, a
+	submodule that has commits that are referenced by a newly fetched
+	superproject commit but are missing in the local submodule clone. A
+	changed submodule can be fetched as long as it is present locally e.g.
+	in `$GIT_DIR/modules/` (see linkgit:gitsubmodules[7]); if the upstream
+	adds a new submodule, that submodule cannot be fetched until it is
+	cloned e.g. by `git submodule update`.
++
+When set to 'on-demand', only changed submodules are fetched. When set
+to 'yes', all populated submodules are fetched and submodules that are
+both unpopulated and changed are fetched. When set to 'no', submodules
+are never fetched.
++
+When unspecified, this uses the value of `fetch.recurseSubmodules` if it
+is set (see linkgit:git-config[1]), defaulting to 'on-demand' if unset.
+When this option is used without any value, it defaults to 'yes'.
+endif::git-pull[]
+
+-j::
+--jobs=<n>::
+	Number of parallel children to be used for all forms of fetching.
++
+If the `--multiple` option was specified, the different remotes will be fetched
+in parallel. If multiple submodules are fetched, they will be fetched in
+parallel. To control them independently, use the config settings
+`fetch.parallel` and `submodule.fetchJobs` (see linkgit:git-config[1]).
++
+Typically, parallel recursive and multi-remote fetches will be faster. By
+default fetches are performed sequentially, not in parallel.
+
+ifndef::git-pull[]
+--no-recurse-submodules::
+	Disable recursive fetching of submodules (this has the same effect as
+	using the `--recurse-submodules=no` option).
+endif::git-pull[]
+
+--set-upstream::
+	If the remote is fetched successfully, add upstream
+	(tracking) reference, used by argument-less
+	linkgit:git-pull[1] and other commands. For more information,
+	see `branch.<name>.merge` and `branch.<name>.remote` in
+	linkgit:git-config[1].
+
+ifndef::git-pull[]
+--submodule-prefix=<path>::
+	Prepend <path> to paths printed in informative messages
+	such as "Fetching submodule foo".  This option is used
+	internally when recursing over submodules.
+
+--recurse-submodules-default=[yes|on-demand]::
+	This option is used internally to temporarily provide a
+	non-negative default value for the --recurse-submodules
+	option.  All other methods of configuring fetch's submodule
+	recursion (such as settings in linkgit:gitmodules[5] and
+	linkgit:git-config[1]) override this option, as does
+	specifying --[no-]recurse-submodules directly.
+
+-u::
+--update-head-ok::
+	By default 'git fetch' refuses to update the head which
+	corresponds to the current branch.  This flag disables the
+	check.  This is purely for the internal use for 'git pull'
+	to communicate with 'git fetch', and unless you are
+	implementing your own Porcelain you are not supposed to
+	use it.
+endif::git-pull[]
+
+--upload-pack <upload-pack>::
+	When given, and the repository to fetch from is handled
+	by 'git fetch-pack', `--exec=<upload-pack>` is passed to
+	the command to specify non-default path for the command
+	run on the other end.
+
+ifndef::git-pull[]
+-q::
+--quiet::
+	Pass --quiet to git-fetch-pack and silence any other internally
+	used git commands. Progress is not reported to the standard error
+	stream.
+
+-v::
+--verbose::
+	Be verbose.
+endif::git-pull[]
+
+--progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless -q
+	is specified. This flag forces progress status even if the
+	standard error stream is not directed to a terminal.
+
+-o <option>::
+--server-option=<option>::
+	Transmit the given string to the server when communicating using
+	protocol version 2.  The given string must not contain a NUL or LF
+	character.  The server's handling of server options, including
+	unknown ones, is server-specific.
+	When multiple `--server-option=<option>` are given, they are all
+	sent to the other side in the order listed on the command line.
+	When no `--server-option=<option>` is given from the command line,
+	the values of configuration variable `remote.<name>.serverOption`
+	are used instead.
+
+--show-forced-updates::
+	By default, git checks if a branch is force-updated during
+	fetch. This can be disabled through fetch.showForcedUpdates, but
+	the --show-forced-updates option guarantees this check occurs.
+	See linkgit:git-config[1].
+
+--no-show-forced-updates::
+	By default, git checks if a branch is force-updated during
+	fetch. Pass --no-show-forced-updates or set fetch.showForcedUpdates
+	to false to skip this check for performance reasons. If used during
+	'git-pull' the --ff-only option will still check for forced updates
+	before attempting a fast-forward update. See linkgit:git-config[1].
+
+-4::
+--ipv4::
+	Use IPv4 addresses only, ignoring IPv6 addresses.
+
+-6::
+--ipv6::
+	Use IPv6 addresses only, ignoring IPv4 addresses.
diff --git a/Documentation/fix-texi.perl b/Documentation/fix-texi.perl
new file mode 100755
index 0000000000..ff7d78f620
--- /dev/null
+++ b/Documentation/fix-texi.perl
@@ -0,0 +1,15 @@
+#!/usr/bin/perl -w
+
+while (<>) {
+	if (/^\@setfilename/) {
+		$_ = "\@setfilename git.info\n";
+	} elsif (/^\@direntry/) {
+		print '@dircategory Development
+@direntry
+* Git: (git).           A fast distributed revision control system
+@end direntry
+';	}
+	unless (/^\@direntry/../^\@end direntry/) {
+		print;
+	}
+}
diff --git a/Documentation/fsck-msgids.adoc b/Documentation/fsck-msgids.adoc
new file mode 100644
index 0000000000..b14bc44ca4
--- /dev/null
+++ b/Documentation/fsck-msgids.adoc
@@ -0,0 +1,221 @@
+`badDate`::
+	(ERROR) Invalid date format in an author/committer line.
+
+`badDateOverflow`::
+	(ERROR) Invalid date value in an author/committer line.
+
+`badEmail`::
+	(ERROR) Invalid email format in an author/committer line.
+
+`badFilemode`::
+	(INFO) A tree contains a bad filemode entry.
+
+`badName`::
+	(ERROR) An author/committer name is empty.
+
+`badObjectSha1`::
+	(ERROR) An object has a bad sha1.
+
+`badParentSha1`::
+	(ERROR) A commit object has a bad parent sha1.
+
+`badRefContent`::
+	(ERROR) A ref has bad content.
+
+`badRefFiletype`::
+	(ERROR) A ref has a bad file type.
+
+`badRefName`::
+	(ERROR) A ref has an invalid format.
+
+`badReferentName`::
+	(ERROR) The referent name of a symref is invalid.
+
+`badTagName`::
+	(INFO) A tag has an invalid format.
+
+`badTimezone`::
+	(ERROR) Found an invalid time zone in an author/committer line.
+
+`badTree`::
+	(ERROR) A tree cannot be parsed.
+
+`badTreeSha1`::
+	(ERROR) A tree has an invalid format.
+
+`badType`::
+	(ERROR) Found an invalid object type.
+
+`duplicateEntries`::
+	(ERROR) A tree contains duplicate file entries.
+
+`emptyName`::
+	(WARN) A path contains an empty name.
+
+`extraHeaderEntry`::
+	(IGNORE) Extra headers found after `tagger`.
+
+`fullPathname`::
+	(WARN) A path contains the full path starting with "/".
+
+`gitattributesBlob`::
+	(ERROR) A non-blob found at `.gitattributes`.
+
+`gitattributesLarge`::
+	(ERROR) The `.gitattributes` blob is too large.
+
+`gitattributesLineLength`::
+	(ERROR) The `.gitattributes` blob contains too long lines.
+
+`gitattributesMissing`::
+	(ERROR) Unable to read `.gitattributes` blob.
+
+`gitattributesSymlink`::
+	(INFO) `.gitattributes` is a symlink.
+
+`gitignoreSymlink`::
+	(INFO) `.gitignore` is a symlink.
+
+`gitmodulesBlob`::
+	(ERROR) A non-blob found at `.gitmodules`.
+
+`gitmodulesLarge`::
+	(ERROR) The `.gitmodules` file is too large to parse.
+
+`gitmodulesMissing`::
+	(ERROR) Unable to read `.gitmodules` blob.
+
+`gitmodulesName`::
+	(ERROR) A submodule name is invalid.
+
+`gitmodulesParse`::
+	(INFO) Could not parse `.gitmodules` blob.
+
+`gitmodulesLarge`;
+	(ERROR) `.gitmodules` blob is too large to parse.
+
+`gitmodulesPath`::
+	(ERROR) `.gitmodules` path is invalid.
+
+`gitmodulesSymlink`::
+	(ERROR) `.gitmodules` is a symlink.
+
+`gitmodulesUpdate`::
+	(ERROR) Found an invalid submodule update setting.
+
+`gitmodulesUrl`::
+	(ERROR) Found an invalid submodule url.
+
+`hasDot`::
+	(WARN) A tree contains an entry named `.`.
+
+`hasDotdot`::
+	(WARN) A tree contains an entry named `..`.
+
+`hasDotgit`::
+	(WARN) A tree contains an entry named `.git`.
+
+`largePathname`::
+	(WARN) A tree contains an entry with a very long path name. If
+	the value of `fsck.largePathname` contains a colon, that value
+	is used as the maximum allowable length (e.g., "warn:10" would
+	complain about any path component of 11 or more bytes). The
+	default value is 4096.
+
+`mailmapSymlink`::
+	(INFO) `.mailmap` is a symlink.
+
+`missingAuthor`::
+	(ERROR) Author is missing.
+
+`missingCommitter`::
+	(ERROR) Committer is missing.
+
+`missingEmail`::
+	(ERROR) Email is missing in an author/committer line.
+
+`missingNameBeforeEmail`::
+	(ERROR) Missing name before an email in an author/committer line.
+
+`missingObject`::
+	(ERROR) Missing `object` line in tag object.
+
+`missingSpaceBeforeDate`::
+	(ERROR) Missing space before date in an author/committer line.
+
+`missingSpaceBeforeEmail`::
+	(ERROR) Missing space before the email in an author/committer line.
+
+`missingTag`::
+	(ERROR) Unexpected end after `type` line in a tag object.
+
+`missingTagEntry`::
+	(ERROR) Missing `tag` line in a tag object.
+
+`missingTaggerEntry`::
+	(INFO) Missing `tagger` line in a tag object.
+
+`missingTree`::
+	(ERROR) Missing `tree` line in a commit object.
+
+`missingType`::
+	(ERROR) Invalid type value on the `type` line in a tag object.
+
+`missingTypeEntry`::
+	(ERROR) Missing `type` line in a tag object.
+
+`multipleAuthors`::
+	(ERROR) Multiple author lines found in a commit.
+
+`nulInCommit`::
+	(WARN) Found a NUL byte in the commit object body.
+
+`nulInHeader`::
+	(FATAL) NUL byte exists in the object header.
+
+`nullSha1`::
+	(WARN) Tree contains entries pointing to a null sha1.
+
+`refMissingNewline`::
+	(INFO) A loose ref that does not end with newline(LF). As
+	valid implementations of Git never created such a loose ref
+	file, it may become an error in the future. Report to the
+	git@xxxxxxxxxxxxxxx mailing list if you see this error, as
+	we need to know what tools created such a file.
+
+`symlinkRef`::
+	(INFO) A symbolic link is used as a symref. Report to the
+	git@xxxxxxxxxxxxxxx mailing list if you see this error, as we
+	are assessing the feasibility of dropping the support to drop
+	creating symbolic links as symrefs.
+
+`symrefTargetIsNotARef`::
+	(INFO) The target of a symbolic reference points neither to
+	a root reference nor to a reference starting with "refs/".
+	Although we allow create a symref pointing to the referent which
+	is outside the "ref" by using `git symbolic-ref`, we may tighten
+	the rule in the future. Report to the git@xxxxxxxxxxxxxxx
+	mailing list if you see this error, as we need to know what tools
+	created such a file.
+
+`trailingRefContent`::
+	(INFO) A loose ref has trailing content. As valid implementations
+	of Git never created such a loose ref file, it may become an
+	error in the future. Report to the git@xxxxxxxxxxxxxxx mailing
+	list if you see this error, as we need to know what tools
+	created such a file.
+
+`treeNotSorted`::
+	(ERROR) A tree is not properly sorted.
+
+`unknownType`::
+	(ERROR) Found an unknown object type.
+
+`unterminatedHeader`::
+	(FATAL) Missing end-of-line in the object header.
+
+`zeroPaddedDate`::
+	(ERROR) Found a zero padded date in an author/committer line.
+
+`zeroPaddedFilemode`::
+	(WARN) Found a zero padded filemode in a tree.
diff --git a/Documentation/generate-mergetool-list.sh b/Documentation/generate-mergetool-list.sh
new file mode 100755
index 0000000000..6700498b93
--- /dev/null
+++ b/Documentation/generate-mergetool-list.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+if test "$#" -ne 3
+then
+	echo >&2 "USAGE: $0 <SOURCE_DIR> <MODE> <OUTPUT>"
+	exit 1
+fi
+
+SOURCE_DIR="$1"
+TOOL_MODE="$2"
+OUTPUT="$3"
+MERGE_TOOLS_DIR="$SOURCE_DIR/mergetools"
+
+(
+	. "$SOURCE_DIR"/git-mergetool--lib.sh &&
+	show_tool_names can_$TOOL_MODE
+) | sed -e "s/\([a-z0-9]*\)/\`\1\`;;/" >"$OUTPUT"
diff --git a/Documentation/git-add.adoc b/Documentation/git-add.adoc
new file mode 100644
index 0000000000..7527cbbcb6
--- /dev/null
+++ b/Documentation/git-add.adoc
@@ -0,0 +1,456 @@
+git-add(1)
+==========
+
+NAME
+----
+git-add - Add file contents to the index
+
+SYNOPSIS
+--------
+[synopsis]
+git add [--verbose | -v] [--dry-run | -n] [--force | -f] [--interactive | -i] [--patch | -p]
+	[--edit | -e] [--[no-]all | -A | --[no-]ignore-removal | [--update | -u]] [--sparse]
+	[--intent-to-add | -N] [--refresh] [--ignore-errors] [--ignore-missing] [--renormalize]
+	[--chmod=(+|-)x] [--pathspec-from-file=<file> [--pathspec-file-nul]]
+	[--] [<pathspec>...]
+
+DESCRIPTION
+-----------
+This command updates the index using the current content found in
+the working tree, to prepare the content staged for the next commit.
+It typically adds the current content of existing paths as a whole,
+but with some options it can also be used to add content with
+only part of the changes made to the working tree files applied, or
+remove paths that do not exist in the working tree anymore.
+
+The "index" holds a snapshot of the content of the working tree, and it
+is this snapshot that is taken as the contents of the next commit.  Thus
+after making any changes to the working tree, and before running
+the commit command, you must use the `add` command to add any new or
+modified files to the index.
+
+This command can be performed multiple times before a commit.  It only
+adds the content of the specified file(s) at the time the add command is
+run; if you want subsequent changes included in the next commit, then
+you must run `git add` again to add the new content to the index.
+
+The `git status` command can be used to obtain a summary of which
+files have changes that are staged for the next commit.
+
+The `git add` command will not add ignored files by default.  If any
+ignored files were explicitly specified on the command line, `git add`
+will fail with a list of ignored files.  Ignored files reached by
+directory recursion or filename globbing performed by Git (quote your
+globs before the shell) will be silently ignored.  The `git add` command can
+be used to add ignored files with the `-f` (force) option.
+
+Please see linkgit:git-commit[1] for alternative ways to add content to a
+commit.
+
+
+OPTIONS
+-------
+`<pathspec>...`::
+	Files to add content from.  Fileglobs (e.g. `*.c`) can
+	be given to add all matching files.  Also a
+	leading directory name (e.g. `dir` to add `dir/file1`
+	and `dir/file2`) can be given to update the index to
+	match the current state of the directory as a whole (e.g.
+	specifying `dir` will record not just a file `dir/file1`
+	modified in the working tree, a file `dir/file2` added to
+	the working tree, but also a file `dir/file3` removed from
+	the working tree). Note that older versions of Git used
+	to ignore removed files; use `--no-all` option if you want
+	to add modified or new files but ignore removed ones.
++
+For more details about the _<pathspec>_ syntax, see the 'pathspec' entry
+in linkgit:gitglossary[7].
+
+`-n`::
+`--dry-run`::
+	Don't actually add the file(s), just show if they exist and/or will
+	be ignored.
+
+`-v`::
+`--verbose`::
+        Be verbose.
+
+`-f`::
+`--force`::
+	Allow adding otherwise ignored files.
+
+`--sparse`::
+	Allow updating index entries outside of the sparse-checkout cone.
+	Normally, `git add` refuses to update index entries whose paths do
+	not fit within the sparse-checkout cone, since those files might
+	be removed from the working tree without warning. See
+	linkgit:git-sparse-checkout[1] for more details.
+
+`-i`::
+`--interactive`::
+	Add modified contents in the working tree interactively to
+	the index. Optional path arguments may be supplied to limit
+	operation to a subset of the working tree. See ``Interactive
+	mode'' for details.
+
+`-p`::
+`--patch`::
+	Interactively choose hunks of patch between the index and the
+	work tree and add them to the index. This gives the user a chance
+	to review the difference before adding modified contents to the
+	index.
++
+This effectively runs `add --interactive`, but bypasses the
+initial command menu and directly jumps to the `patch` subcommand.
+See ``Interactive mode'' for details.
+
+`-e`::
+`--edit`::
+	Open the diff vs. the index in an editor and let the user
+	edit it.  After the editor was closed, adjust the hunk headers
+	and apply the patch to the index.
++
+The intent of this option is to pick and choose lines of the patch to
+apply, or even to modify the contents of lines to be staged. This can be
+quicker and more flexible than using the interactive hunk selector.
+However, it is easy to confuse oneself and create a patch that does not
+apply to the index. See EDITING PATCHES below.
+
+`-u`::
+`--update`::
+	Update the index just where it already has an entry matching
+	_<pathspec>_.  This removes as well as modifies index entries to
+	match the working tree, but adds no new files.
++
+If no _<pathspec>_ is given when `-u` option is used, all
+tracked files in the entire working tree are updated (old versions
+of Git used to limit the update to the current directory and its
+subdirectories).
+
+`-A`::
+`--all`::
+`--no-ignore-removal`::
+	Update the index not only where the working tree has a file
+	matching _<pathspec>_ but also where the index already has an
+	entry. This adds, modifies, and removes index entries to
+	match the working tree.
++
+If no _<pathspec>_ is given when `-A` option is used, all
+files in the entire working tree are updated (old versions
+of Git used to limit the update to the current directory and its
+subdirectories).
+
+`--no-all`::
+`--ignore-removal`::
+	Update the index by adding new files that are unknown to the
+	index and files modified in the working tree, but ignore
+	files that have been removed from the working tree.  This
+	option is a no-op when no _<pathspec>_ is used.
++
+This option is primarily to help users who are used to older
+versions of Git, whose `git add <pathspec>...` was a synonym
+for `git add --no-all <pathspec>...`, i.e. ignored removed files.
+
+`-N`::
+`--intent-to-add`::
+	Record only the fact that the path will be added later. An entry
+	for the path is placed in the index with no content. This is
+	useful for, among other things, showing the unstaged content of
+	such files with `git diff` and committing them with `git commit
+	-a`.
+
+`--refresh`::
+	Don't add the file(s), but only refresh their stat()
+	information in the index.
+
+`--ignore-errors`::
+	If some files could not be added because of errors indexing
+	them, do not abort the operation, but continue adding the
+	others. The command shall still exit with non-zero status.
+	The configuration variable `add.ignoreErrors` can be set to
+	true to make this the default behaviour.
+
+`--ignore-missing`::
+	This option can only be used together with `--dry-run`. By using
+	this option the user can check if any of the given files would
+	be ignored, no matter if they are already present in the work
+	tree or not.
+
+`--no-warn-embedded-repo`::
+	By default, `git add` will warn when adding an embedded
+	repository to the index without using `git submodule add` to
+	create an entry in `.gitmodules`. This option will suppress the
+	warning (e.g., if you are manually performing operations on
+	submodules).
+
+`--renormalize`::
+	Apply the "clean" process freshly to all tracked files to
+	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`. 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
+	bit is only changed in the index, the files on disk are left
+	unchanged.
+
+`--pathspec-from-file=<file>`::
+	Pathspec is passed in _<file>_ instead of commandline args. If
+	_<file>_ is exactly `-` then standard input is used. Pathspec
+	elements are separated by _LF_ or _CR/LF_. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+`--pathspec-file-nul`::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with _NUL_ character and all other characters are taken
+	literally (including newlines and quotes).
+
+`--`::
+	This option can be used to separate command-line options from
+	the list of files, (useful when filenames might be mistaken
+	for command-line options).
+
+
+EXAMPLES
+--------
+
+* Adds content from all ++*.txt++ files under `Documentation` directory
+  and its subdirectories:
++
+------------
+$ git add Documentation/\*.txt
+------------
++
+Note that the asterisk ++*++ is quoted from the shell in this
+example; this lets the command include the files from
+subdirectories of `Documentation/` directory.
+
+* Considers adding content from all ++git-*.sh++ scripts:
++
+------------
+$ git add git-*.sh
+------------
++
+Because this example lets the shell expand the asterisk (i.e. you are
+listing the files explicitly), it does not consider
+`subdir/git-foo.sh`.
+
+INTERACTIVE MODE
+----------------
+When the command enters the interactive mode, it shows the
+output of the 'status' subcommand, and then goes into its
+interactive command loop.
+
+The command loop shows the list of subcommands available, and
+gives a prompt "What now> ".  In general, when the prompt ends
+with a single '>', you can pick only one of the choices given
+and type return, like this:
+
+------------
+    *** Commands ***
+      1: status       2: update       3: revert       4: add untracked
+      5: patch        6: diff         7: quit         8: help
+    What now> 1
+------------
+
+You also could say `s` or `sta` or `status` above as long as the
+choice is unique.
+
+The main command loop has 6 subcommands (plus help and quit).
+
+status::
+
+   This shows the change between `HEAD` and index (i.e. what will be
+   committed if you say `git commit`), and between index and
+   working tree files (i.e. what you could stage further before
+   `git commit` using `git add`) for each path.  A sample output
+   looks like this:
++
+------------
+              staged     unstaged path
+     1:       binary      nothing foo.png
+     2:     +403/-35        +1/-1 add-interactive.c
+------------
++
+It shows that `foo.png` has differences from `HEAD` (but that is
+binary so line count cannot be shown) and there is no
+difference between indexed copy and the working tree
+version (if the working tree version were also different,
+'binary' would have been shown in place of 'nothing').  The
+other file, `add-interactive.c`, has 403 lines added
+and 35 lines deleted if you commit what is in the index, but
+working tree file has further modifications (one addition and
+one deletion).
+
+update::
+
+   This shows the status information and issues an "Update>>"
+   prompt.  When the prompt ends with double '>>', you can
+   make more than one selection, concatenated with whitespace or
+   comma.  Also you can say ranges.  E.g. "2-5 7,9" to choose
+   2,3,4,5,7,9 from the list.  If the second number in a range is
+   omitted, all remaining patches are taken.  E.g. "7-" to choose
+   7,8,9 from the list.  You can say '*' to choose everything.
++
+What you chose are then highlighted with '*',
+like this:
++
+------------
+           staged     unstaged path
+  1:       binary      nothing foo.png
+* 2:     +403/-35        +1/-1 add-interactive.c
+------------
++
+To remove selection, prefix the input with `-`
+like this:
++
+------------
+Update>> -2
+------------
++
+After making the selection, answer with an empty line to stage the
+contents of working tree files for selected paths in the index.
+
+revert::
+
+  This has a very similar UI to 'update', and the staged
+  information for selected paths are reverted to that of the
+  HEAD version.  Reverting new paths makes them untracked.
+
+add untracked::
+
+  This has a very similar UI to 'update' and
+  'revert', and lets you add untracked paths to the index.
+
+patch::
+
+  This lets you choose one path out of a 'status' like selection.
+  After choosing the path, it presents the diff between the index
+  and the working tree file and asks you if you want to stage
+  the change of each hunk.  You can select one of the following
+  options and type return:
+
+       y - stage this hunk
+       n - do not stage this hunk
+       q - quit; do not stage this hunk or any of the remaining ones
+       a - stage this hunk and all later hunks in the file
+       d - do not stage this hunk or any of the later hunks in the file
+       g - select a hunk to go to
+       / - search for a hunk matching the given regex
+       j - leave this hunk undecided, see next undecided hunk
+       J - leave this hunk undecided, see next hunk
+       k - leave this hunk undecided, see previous undecided hunk
+       K - leave this hunk undecided, see previous hunk
+       s - split the current hunk into smaller hunks
+       e - manually edit the current hunk
+       p - print the current hunk
+       ? - print help
++
+After deciding the fate for all hunks, if there is any hunk
+that was chosen, the index is updated with the selected hunks.
++
+You can omit having to type return here, by setting the configuration
+variable `interactive.singleKey` to `true`.
+
+diff::
+
+  This lets you review what will be committed (i.e. between
+  `HEAD` and index).
+
+
+EDITING PATCHES
+---------------
+
+Invoking `git add -e` or selecting `e` from the interactive hunk
+selector will open a patch in your editor; after the editor exits, the
+result is applied to the index. You are free to make arbitrary changes
+to the patch, but note that some changes may have confusing results, or
+even result in a patch that cannot be applied.  If you want to abort the
+operation entirely (i.e., stage nothing new in the index), simply delete
+all lines of the patch. The list below describes some common things you
+may see in a patch, and which editing operations make sense on them.
+
+--
+added content::
+
+Added content is represented by lines beginning with "{plus}". You can
+prevent staging any addition lines by deleting them.
+
+removed content::
+
+Removed content is represented by lines beginning with "-". You can
+prevent staging their removal by converting the "-" to a " " (space).
+
+modified content::
+
+Modified content is represented by "-" lines (removing the old content)
+followed by "{plus}" lines (adding the replacement content). You can
+prevent staging the modification by converting "-" lines to " ", and
+removing "{plus}" lines. Beware that modifying only half of the pair is
+likely to introduce confusing changes to the index.
+--
+
+There are also more complex operations that can be performed. But beware
+that because the patch is applied only to the index and not the working
+tree, the working tree will appear to "undo" the change in the index.
+For example, introducing a new line into the index that is in neither
+the `HEAD` nor the working tree will stage the new line for commit, but
+the line will appear to be reverted in the working tree.
+
+Avoid using these constructs, or do so with extreme caution.
+
+--
+removing untouched content::
+
+Content which does not differ between the index and working tree may be
+shown on context lines, beginning with a " " (space).  You can stage
+context lines for removal by converting the space to a "-". The
+resulting working tree file will appear to re-add the content.
+
+modifying existing content::
+
+One can also modify context lines by staging them for removal (by
+converting " " to "-") and adding a "{plus}" line with the new content.
+Similarly, one can modify "{plus}" lines for existing additions or
+modifications. In all cases, the new modification will appear reverted
+in the working tree.
+
+new content::
+
+You may also add new content that does not exist in the patch; simply
+add new lines, each starting with "{plus}". The addition will appear
+reverted in the working tree.
+--
+
+There are also several operations which should be avoided entirely, as
+they will make the patch impossible to apply:
+
+* adding context (" ") or removal ("-") lines
+* deleting context or removal lines
+* modifying the contents of context or removal lines
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+:git-add: 1
+include::config/add.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-status[1]
+linkgit:git-rm[1]
+linkgit:git-reset[1]
+linkgit:git-mv[1]
+linkgit:git-commit[1]
+linkgit:git-update-index[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-am.adoc b/Documentation/git-am.adoc
new file mode 100644
index 0000000000..bd0d339f79
--- /dev/null
+++ b/Documentation/git-am.adoc
@@ -0,0 +1,298 @@
+git-am(1)
+=========
+
+NAME
+----
+git-am - Apply a series of patches from a mailbox
+
+
+SYNOPSIS
+--------
+[verse]
+'git am' [--signoff] [--keep] [--[no-]keep-cr] [--[no-]utf8] [--no-verify]
+	 [--[no-]3way] [--interactive] [--committer-date-is-author-date]
+	 [--ignore-date] [--ignore-space-change | --ignore-whitespace]
+	 [--whitespace=<action>] [-C<n>] [-p<n>] [--directory=<dir>]
+	 [--exclude=<path>] [--include=<path>] [--reject] [-q | --quiet]
+	 [--[no-]scissors] [-S[<keyid>]] [--patch-format=<format>]
+	 [--quoted-cr=<action>]
+	 [--empty=(stop|drop|keep)]
+	 [(<mbox> | <Maildir>)...]
+'git am' (--continue | --skip | --abort | --quit | --retry | --show-current-patch[=(diff|raw)] | --allow-empty)
+
+DESCRIPTION
+-----------
+Splits mail messages in a mailbox into commit log messages,
+authorship information, and patches, and applies them to the
+current branch. You could think of it as a reverse operation
+of linkgit:git-format-patch[1] run on a branch with a straight
+history without merges.
+
+OPTIONS
+-------
+(<mbox>|<Maildir>)...::
+	The list of mailbox files to read patches from. If you do not
+	supply this argument, the command reads from the standard input.
+	If you supply directories, they will be treated as Maildirs.
+
+-s::
+--signoff::
+	Add a `Signed-off-by` trailer to the commit message, using
+	the committer identity of yourself.
+	See the signoff option in linkgit:git-commit[1] for more information.
+
+-k::
+--keep::
+	Pass `-k` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+
+--keep-non-patch::
+	Pass `-b` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+
+--[no-]keep-cr::
+	With `--keep-cr`, call 'git mailsplit' (see linkgit:git-mailsplit[1])
+	with the same option, to prevent it from stripping CR at the end of
+	lines. `am.keepcr` configuration variable can be used to specify the
+	default behaviour.  `--no-keep-cr` is useful to override `am.keepcr`.
+
+-c::
+--scissors::
+	Remove everything in body before a scissors line (see
+	linkgit:git-mailinfo[1]). Can be activated by default using
+	the `mailinfo.scissors` configuration variable.
+
+--no-scissors::
+	Ignore scissors lines (see linkgit:git-mailinfo[1]).
+
+--quoted-cr=<action>::
+	This flag will be passed down to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+
+--empty=(drop|keep|stop)::
+	How to handle an e-mail message lacking a patch:
++
+--
+`drop`;;
+	The e-mail message will be skipped.
+`keep`;;
+	An empty commit will be created, with the contents of the e-mail
+	message as its log.
+`stop`;;
+	The command will fail, stopping in the middle of the current `am`
+	session. This is the default behavior.
+--
+
+-m::
+--message-id::
+	Pass the `-m` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]),
+	so that the Message-ID header is added to the commit message.
+	The `am.messageid` configuration variable can be used to specify
+	the default behaviour.
+
+--no-message-id::
+	Do not add the Message-ID header to the commit message.
+	`no-message-id` is useful to override `am.messageid`.
+
+-q::
+--quiet::
+	Be quiet. Only print error messages.
+
+-u::
+--utf8::
+	Pass `-u` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+	The proposed commit log message taken from the e-mail
+	is re-coded into UTF-8 encoding (configuration variable
+	`i18n.commitEncoding` can be used to specify the project's
+	preferred encoding if it is not UTF-8).
++
+This was optional in prior versions of git, but now it is the
+default.   You can use `--no-utf8` to override this.
+
+--no-utf8::
+	Pass `-n` flag to 'git mailinfo' (see
+	linkgit:git-mailinfo[1]).
+
+-3::
+--3way::
+--no-3way::
+	When the patch does not apply cleanly, fall back on
+	3-way merge if the patch records the identity of blobs
+	it is supposed to apply to and we have those blobs
+	available locally. `--no-3way` can be used to override
+	am.threeWay configuration variable. For more information,
+	see am.threeWay in linkgit:git-config[1].
+
+include::rerere-options.adoc[]
+
+--ignore-space-change::
+--ignore-whitespace::
+--whitespace=<action>::
+-C<n>::
+-p<n>::
+--directory=<dir>::
+--exclude=<path>::
+--include=<path>::
+--reject::
+	These flags are passed to the 'git apply' (see linkgit:git-apply[1])
+	program that applies
+	the patch.
++
+Valid <action> for the `--whitespace` option are:
+`nowarn`, `warn`, `fix`, `error`, and `error-all`.
+
+--patch-format::
+	By default the command will try to detect the patch format
+	automatically. This option allows the user to bypass the automatic
+	detection and specify the patch format that the patch(es) should be
+	interpreted as. Valid formats are mbox, mboxrd,
+	stgit, stgit-series, and hg.
+
+-i::
+--interactive::
+	Run interactively.
+
+-n::
+--no-verify::
+	By default, the pre-applypatch and applypatch-msg hooks are run.
+	When any of `--no-verify` or `-n` is given, these are bypassed.
+	See also linkgit:githooks[5].
+
+--committer-date-is-author-date::
+	By default the command records the date from the e-mail
+	message as the commit author date, and uses the time of
+	commit creation as the committer date. This allows the
+	user to lie about the committer date by using the same
+	value as the author date.
+
+--ignore-date::
+	By default the command records the date from the e-mail
+	message as the commit author date, and uses the time of
+	commit creation as the committer date. This allows the
+	user to lie about the author date by using the same
+	value as the committer date.
+
+--skip::
+	Skip the current patch.  This is only meaningful when
+	restarting an aborted patch.
+
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+--no-gpg-sign::
+	GPG-sign commits. The `keyid` argument is optional and
+	defaults to the committer identity; if specified, it must be
+	stuck to the option without a space. `--no-gpg-sign` is useful to
+	countermand both `commit.gpgSign` configuration variable, and
+	earlier `--gpg-sign`.
+
+--continue::
+-r::
+--resolved::
+	After a patch failure (e.g. attempting to apply
+	conflicting patch), the user has applied it by hand and
+	the index file stores the result of the application.
+	Make a commit using the authorship and commit log
+	extracted from the e-mail message and the current index
+	file, and continue.
+
+--resolvemsg=<msg>::
+	When a patch failure occurs, <msg> will be printed
+	to the screen before exiting.  This overrides the
+	standard message informing you to use `--continue`
+	or `--skip` to handle the failure.  This is solely
+	for internal use between 'git rebase' and 'git am'.
+
+--abort::
+	Restore the original branch and abort the patching operation.
+	Revert the contents of files involved in the am operation to their
+	pre-am state.
+
+--quit::
+	Abort the patching operation but keep HEAD and the index
+	untouched.
+
+--retry::
+	Try to apply the last conflicting patch again. This is generally
+	only useful for passing extra options to the retry attempt
+	(e.g., `--3way`), since otherwise you'll just see the same
+	failure again.
+
+--show-current-patch[=(diff|raw)]::
+	Show the message at which `git am` has stopped due to
+	conflicts.  If `raw` is specified, show the raw contents of
+	the e-mail message; if `diff`, show the diff portion only.
+	Defaults to `raw`.
+
+--allow-empty::
+	After a patch failure on an input e-mail message lacking a patch,
+	create an empty commit with the contents of the e-mail message
+	as its log message.
+
+DISCUSSION
+----------
+
+The commit author name is taken from the "From: " line of the
+message, and commit author date is taken from the "Date: " line
+of the message.  The "Subject: " line is used as the title of
+the commit, after stripping common prefix "[PATCH <anything>]".
+The "Subject: " line is supposed to concisely describe what the
+commit is about in one line of text.
+
+"From: ", "Date: ", and "Subject: " lines starting the body override the
+respective commit author name and title values taken from the headers.
+
+The commit message is formed by the title taken from the
+"Subject: ", a blank line and the body of the message up to
+where the patch begins.  Excess whitespace at the end of each
+line is automatically stripped.
+
+The patch is expected to be inline, directly following the
+message.  Any line that is of the form:
+
+* three-dashes and end-of-line, or
+* a line that begins with "diff -", or
+* a line that begins with "Index: "
+
+is taken as the beginning of a patch, and the commit log message
+is terminated before the first occurrence of such a line.
+
+When initially invoking `git am`, you give it the names of the mailboxes
+to process.  Upon seeing the first patch that does not apply, it
+aborts in the middle.  You can recover from this in one of two ways:
+
+. skip the current patch by re-running the command with the `--skip`
+  option.
+
+. hand resolve the conflict in the working directory, and update
+  the index file to bring it into a state that the patch should
+  have produced.  Then run the command with the `--continue` option.
+
+The command refuses to process new mailboxes until the current
+operation is finished, so if you decide to start over from scratch,
+run `git am --abort` before running the command with mailbox
+names.
+
+Before any patches are applied, ORIG_HEAD is set to the tip of the
+current branch.  This is useful if you have problems with multiple
+commits, like running 'git am' on the wrong branch or an error in the
+commits that is more easily fixed by changing the mailbox (e.g.
+errors in the "From:" lines).
+
+HOOKS
+-----
+This command can run `applypatch-msg`, `pre-applypatch`,
+and `post-applypatch` hooks.  See linkgit:githooks[5] for more
+information.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/am.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-apply[1],
+linkgit:git-format-patch[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-annotate.adoc b/Documentation/git-annotate.adoc
new file mode 100644
index 0000000000..965bc676af
--- /dev/null
+++ b/Documentation/git-annotate.adoc
@@ -0,0 +1,33 @@
+git-annotate(1)
+===============
+
+NAME
+----
+git-annotate - Annotate file lines with commit information
+
+SYNOPSIS
+--------
+[verse]
+'git annotate' [<options>] [<rev-opts>] [<rev>] [--] <file>
+
+DESCRIPTION
+-----------
+Annotates each line in the given file with information from the commit
+which introduced the line. Optionally annotates from a given revision.
+
+The only difference between this command and linkgit:git-blame[1] is that
+they use slightly different output formats, and this command exists only
+for backward compatibility to support existing scripts, and provide a more
+familiar command name for people coming from other SCM systems.
+
+OPTIONS
+-------
+include::blame-options.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-blame[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-apply.adoc b/Documentation/git-apply.adoc
new file mode 100644
index 0000000000..7e055d1307
--- /dev/null
+++ b/Documentation/git-apply.adoc
@@ -0,0 +1,298 @@
+git-apply(1)
+============
+
+NAME
+----
+git-apply - Apply a patch to files and/or to the index
+
+
+SYNOPSIS
+--------
+[verse]
+'git apply' [--stat] [--numstat] [--summary] [--check]
+	  [--index | --intent-to-add] [--3way] [--ours | --theirs | --union]
+	  [--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
+	  [--allow-binary-replacement | --binary] [--reject] [-z]
+	  [-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
+	  [--ignore-space-change | --ignore-whitespace]
+	  [--whitespace=(nowarn|warn|fix|error|error-all)]
+	  [--exclude=<path>] [--include=<path>] [--directory=<root>]
+	  [--verbose | --quiet] [--unsafe-paths] [--allow-empty] [<patch>...]
+
+DESCRIPTION
+-----------
+Reads the supplied diff output (i.e. "a patch") and applies it to files.
+When running from a subdirectory in a repository, patched paths
+outside the directory are ignored.
+With the `--index` option, the patch is also applied to the index, and
+with the `--cached` option, the patch is only applied to the index.
+Without these options, the command applies the patch only to files,
+and does not require them to be in a Git repository.
+
+This command applies the patch but does not create a commit.  Use
+linkgit:git-am[1] to create commits from patches generated by
+linkgit:git-format-patch[1] and/or received by email.
+
+OPTIONS
+-------
+<patch>...::
+	The files to read the patch from.  '-' can be used to read
+	from the standard input.
+
+--stat::
+	Instead of applying the patch, output diffstat for the
+	input.  Turns off "apply".
+
+--numstat::
+	Similar to `--stat`, but shows the number of added and
+	deleted lines in decimal notation and the pathname without
+	abbreviation, to make it more machine friendly.  For
+	binary files, outputs two `-` instead of saying
+	`0 0`.  Turns off "apply".
+
+--summary::
+	Instead of applying the patch, output a condensed
+	summary of information obtained from git diff extended
+	headers, such as creations, renames, and mode changes.
+	Turns off "apply".
+
+--check::
+	Instead of applying the patch, see if the patch is
+	applicable to the current working tree and/or the index
+	file and detects errors.  Turns off "apply".
+
+--index::
+	Apply the patch to both the index and the working tree (or
+	merely check that it would apply cleanly to both if `--check` is
+	in effect). Note that `--index` expects index entries and
+	working tree copies for relevant paths to be identical (their
+	contents and metadata such as file mode must match), and will
+	raise an error if they are not, even if the patch would apply
+	cleanly to both the index and the working tree in isolation.
+
+--cached::
+	Apply the patch to just the index, without touching the working
+	tree. If `--check` is in effect, merely check that it would
+	apply cleanly to the index entry.
+
+--intent-to-add::
+	When applying the patch only to the working tree, mark new
+	files to be added to the index later (see `--intent-to-add`
+	option in linkgit:git-add[1]). This option is ignored unless
+	running in a Git repository and `--index` is not specified.
+	Note that `--index` could be implied by other options such
+	as `--cached` or `--3way`.
+
+-3::
+--3way::
+	Attempt 3-way merge if the patch records the identity of blobs it is supposed
+	to apply to and we have those blobs available locally, possibly leaving the
+	conflict markers in the files in the working tree for the user to
+	resolve.  This option implies the `--index` option unless the
+	`--cached` option is used, and is incompatible with the `--reject` option.
+	When used with the `--cached` option, any conflicts are left at higher stages
+	in the cache.
+
+--ours::
+--theirs::
+--union::
+	Instead of leaving conflicts in the file, resolve conflicts favouring
+	our (or their or both) side of the lines. Requires --3way.
+
+--build-fake-ancestor=<file>::
+	Newer 'git diff' output has embedded 'index information'
+	for each blob to help identify the original version that
+	the patch applies to.  When this flag is given, and if
+	the original versions of the blobs are available locally,
+	builds a temporary index containing those blobs.
++
+When a pure mode change is encountered (which has no index information),
+the information is read from the current index instead.
+
+-R::
+--reverse::
+	Apply the patch in reverse.
+
+--reject::
+	For atomicity, 'git apply' by default fails the whole patch and
+	does not touch the working tree when some of the hunks
+	do not apply.  This option makes it apply
+	the parts of the patch that are applicable, and leave the
+	rejected hunks in corresponding *.rej files.
+
+-z::
+	When `--numstat` has been given, do not munge pathnames,
+	but use a NUL-terminated machine-readable format.
++
+Without this option, pathnames with "unusual" characters are quoted as
+explained for the configuration variable `core.quotePath` (see
+linkgit:git-config[1]).
+
+-p<n>::
+	Remove <n> leading path components (separated by slashes) from
+	traditional diff paths. E.g., with `-p2`, a patch against
+	`a/dir/file` will be applied directly to `file`. The default is
+	1.
+
+-C<n>::
+	Ensure at least <n> lines of surrounding context match before
+	and after each change.  When fewer lines of surrounding
+	context exist they all must match.  By default no context is
+	ever ignored.
+
+--unidiff-zero::
+	By default, 'git apply' expects that the patch being
+	applied is a unified diff with at least one line of context.
+	This provides good safety measures, but breaks down when
+	applying a diff generated with `--unified=0`. To bypass these
+	checks use `--unidiff-zero`.
++
+Note, for the reasons stated above, the usage of context-free patches is
+discouraged.
+
+--apply::
+	If you use any of the options marked "Turns off
+	'apply'" above, 'git apply' reads and outputs the
+	requested information without actually applying the
+	patch.  Give this flag after those flags to also apply
+	the patch.
+
+--no-add::
+	When applying a patch, ignore additions made by the
+	patch.  This can be used to extract the common part between
+	two files by first running 'diff' on them and applying
+	the result with this option, which would apply the
+	deletion part but not the addition part.
+
+--allow-binary-replacement::
+--binary::
+	Historically we did not allow binary patch application
+	without an explicit permission from the user, and this
+	flag was the way to do so.  Currently, we always allow binary
+	patch application, so this is a no-op.
+
+--exclude=<path-pattern>::
+	Don't apply changes to files matching the given path pattern. This can
+	be useful when importing patchsets, where you want to exclude certain
+	files or directories.
+
+--include=<path-pattern>::
+	Apply changes to files matching the given path pattern. This can
+	be useful when importing patchsets, where you want to include certain
+	files or directories.
++
+When `--exclude` and `--include` patterns are used, they are examined in the
+order they appear on the command line, and the first match determines if a
+patch to each path is used.  A patch to a path that does not match any
+include/exclude pattern is used by default if there is no include pattern
+on the command line, and ignored if there is any include pattern.
+
+--ignore-space-change::
+--ignore-whitespace::
+	When applying a patch, ignore changes in whitespace in context
+	lines if necessary.
+	Context lines will preserve their whitespace, and they will not
+	undergo whitespace fixing regardless of the value of the
+	`--whitespace` option. New lines will still be fixed, though.
+
+--whitespace=<action>::
+	When applying a patch, detect a new or modified line that has
+	whitespace errors.  What are considered whitespace errors is
+	controlled by `core.whitespace` configuration.  By default,
+	trailing whitespaces (including lines that solely consist of
+	whitespaces) and a space character that is immediately followed
+	by a tab character inside the initial indent of the line are
+	considered whitespace errors.
++
+By default, the command outputs warning messages but applies the patch.
+When `git-apply` is used for statistics and not applying a
+patch, it defaults to `nowarn`.
++
+You can use different `<action>` values to control this
+behavior:
++
+* `nowarn` turns off the trailing whitespace warning.
+* `warn` outputs warnings for a few such errors, but applies the
+  patch as-is (default).
+* `fix` outputs warnings for a few such errors, and applies the
+  patch after fixing them (`strip` is a synonym -- the tool
+  used to consider only trailing whitespace characters as errors, and the
+  fix involved 'stripping' them, but modern Gits do more).
+* `error` outputs warnings for a few such errors, and refuses
+  to apply the patch.
+* `error-all` is similar to `error` but shows all errors.
+
+--inaccurate-eof::
+	Under certain circumstances, some versions of 'diff' do not correctly
+	detect a missing new-line at the end of the file. As a result, patches
+	created by such 'diff' programs do not record incomplete lines
+	correctly. This option adds support for applying such patches by
+	working around this bug.
+
+-v::
+--verbose::
+	Report progress to stderr. By default, only a message about the
+	current patch being applied will be printed. This option will cause
+	additional information to be reported.
+
+-q::
+--quiet::
+	Suppress stderr output. Messages about patch status and progress
+	will not be printed.
+
+--recount::
+	Do not trust the line counts in the hunk headers, but infer them
+	by inspecting the patch (e.g. after editing the patch without
+	adjusting the hunk headers appropriately).
+
+--directory=<root>::
+	Prepend <root> to all filenames.  If a "-p" argument was also passed,
+	it is applied before prepending the new root.
++
+For example, a patch that talks about updating `a/git-gui.sh` to `b/git-gui.sh`
+can be applied to the file in the working tree `modules/git-gui/git-gui.sh` by
+running `git apply --directory=modules/git-gui`.
+
+--unsafe-paths::
+	By default, a patch that affects outside the working area
+	(either a Git controlled working tree, or the current working
+	directory when "git apply" is used as a replacement of GNU
+	patch) is rejected as a mistake (or a mischief).
++
+When `git apply` is used as a "better GNU patch", the user can pass
+the `--unsafe-paths` option to override this safety check.  This option
+has no effect when `--index` or `--cached` is in use.
+
+--allow-empty::
+	Don't return an error for patches containing no diff. This includes
+	empty patches and patches with commit text only.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/apply.adoc[]
+
+SUBMODULES
+----------
+If the patch contains any changes to submodules then 'git apply'
+treats these changes as follows.
+
+If `--index` is specified (explicitly or implicitly), then the submodule
+commits must match the index exactly for the patch to apply.  If any
+of the submodules are checked-out, then these check-outs are completely
+ignored, i.e., they are not required to be up to date or clean and they
+are not updated.
+
+If `--index` is not specified, then the submodule commits in the patch
+are ignored and only the absence or presence of the corresponding
+subdirectory is checked and (if possible) updated.
+
+SEE ALSO
+--------
+linkgit:git-am[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-archimport.adoc b/Documentation/git-archimport.adoc
new file mode 100644
index 0000000000..847777fd17
--- /dev/null
+++ b/Documentation/git-archimport.adoc
@@ -0,0 +1,113 @@
+git-archimport(1)
+=================
+
+NAME
+----
+git-archimport - Import a GNU Arch repository into Git
+
+
+SYNOPSIS
+--------
+[verse]
+'git archimport' [-h] [-v] [-o] [-a] [-f] [-T] [-D <depth>] [-t <tempdir>]
+	       <archive>/<branch>[:<git-branch>]...
+
+DESCRIPTION
+-----------
+Imports a project from one or more GNU Arch repositories.
+It will follow branches
+and repositories within the namespaces defined by the <archive>/<branch>
+parameters supplied. If it cannot find the remote branch a merge comes from
+it will just import it as a regular commit. If it can find it, it will mark it
+as a merge whenever possible (see discussion below).
+
+The script expects you to provide the key roots where it can start the import
+from an 'initial import' or 'tag' type of Arch commit. It will follow and
+import new branches within the provided roots.
+
+It expects to be dealing with one project only. If it sees
+branches that have different roots, it will refuse to run. In that case,
+edit your <archive>/<branch> parameters to define clearly the scope of the
+import.
+
+'git archimport' uses `tla` extensively in the background to access the
+Arch repository.
+Make sure you have a recent version of `tla` available in the path. `tla` must
+know about the repositories you pass to 'git archimport'.
+
+For the initial import, 'git archimport' expects to find itself in an empty
+directory. To follow the development of a project that uses Arch, rerun
+'git archimport' with the same parameters as the initial import to perform
+incremental imports.
+
+While 'git archimport' will try to create sensible branch names for the
+archives that it imports, it is also possible to specify Git branch names
+manually.  To do so, write a Git branch name after each <archive>/<branch>
+parameter, separated by a colon.  This way, you can shorten the Arch
+branch names and convert Arch jargon to Git jargon, for example mapping a
+"PROJECT{litdd}devo{litdd}VERSION" branch to "master".
+
+Associating multiple Arch branches to one Git branch is possible; the
+result will make the most sense only if no commits are made to the first
+branch, after the second branch is created.  Still, this is useful to
+convert Arch repositories that had been rotated periodically.
+
+
+MERGES
+------
+Patch merge data from Arch is used to mark merges in Git as well. Git
+does not care much about tracking patches, and only considers a merge when a
+branch incorporates all the commits since the point they forked. The end result
+is that Git will have a good idea of how far branches have diverged. So the
+import process does lose some patch-trading metadata.
+
+Fortunately, when you try and merge branches imported from Arch,
+Git will find a good merge base, and it has a good chance of identifying
+patches that have been traded out-of-sequence between the branches.
+
+OPTIONS
+-------
+
+-h::
+	Display usage.
+
+-v::
+	Verbose output.
+
+-T::
+	Many tags. Will create a tag for every commit, reflecting the commit
+	name in the Arch repository.
+
+-f::
+	Use the fast patchset import strategy.  This can be significantly
+	faster for large trees, but cannot handle directory renames or
+	permissions changes.  The default strategy is slow and safe.
+
+-o::
+	Use this for compatibility with old-style branch names used by
+	earlier versions of 'git archimport'.  Old-style branch names
+	were category{litdd}branch, whereas new-style branch names are
+	archive,category{litdd}branch{litdd}version.  In both cases, names given
+	on the command-line will override the automatically-generated
+	ones.
+
+-D <depth>::
+	Follow merge ancestry and attempt to import trees that have been
+	merged from.  Specify a depth greater than 1 if patch logs have been
+	pruned.
+
+-a::
+	Attempt to auto-register archives at `http://mirrors.sourcecontrol.net`
+	This is particularly useful with the -D option.
+
+-t <tmpdir>::
+	Override the default tempdir.
+
+
+<archive>/<branch>::
+	<archive>/<branch> identifier in a format that `tla log` understands.
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-archive.adoc b/Documentation/git-archive.adoc
new file mode 100644
index 0000000000..a0e3fe7996
--- /dev/null
+++ b/Documentation/git-archive.adoc
@@ -0,0 +1,243 @@
+git-archive(1)
+==============
+
+NAME
+----
+git-archive - Create an archive of files from a named tree
+
+
+SYNOPSIS
+--------
+[verse]
+'git archive' [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>]
+	      [-o <file> | --output=<file>] [--worktree-attributes]
+	      [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>
+	      [<path>...]
+
+DESCRIPTION
+-----------
+Creates an archive of the specified format containing the tree
+structure for the named tree, and writes it out to the standard
+output.  If <prefix> is specified it is
+prepended to the filenames in the archive.
+
+'git archive' behaves differently when given a tree ID as opposed to a
+commit ID or tag ID. When a tree ID is provided, the current time is
+used as the modification time of each file in the archive. On the
+other hand, when a commit ID or tag ID is provided, the commit time as
+recorded in the referenced commit object is used instead.
+Additionally the commit ID is stored in a global extended pax header
+if the tar format is used; it can be extracted using 'git
+get-tar-commit-id'. In ZIP files it is stored as a file comment.
+
+OPTIONS
+-------
+
+--format=<fmt>::
+	Format of the resulting archive. Possible values are `tar`,
+	`zip`, `tar.gz`, `tgz`, and any format defined using the
+	configuration option `tar.<format>.command`. If `--format`
+	is not given, and the output file is specified, the format is
+	inferred from the filename if possible (e.g. writing to `foo.zip`
+	makes the output to be in the `zip` format). Otherwise the output
+	format is `tar`.
+
+-l::
+--list::
+	Show all available formats.
+
+-v::
+--verbose::
+	Report progress to stderr.
+
+--prefix=<prefix>/::
+	Prepend <prefix>/ to paths in the archive.  Can be repeated; its
+	rightmost value is used for all tracked files.  See below which
+	value gets used by `--add-file`.
+
+-o <file>::
+--output=<file>::
+	Write the archive to <file> instead of stdout.
+
+--add-file=<file>::
+	Add a non-tracked file to the archive.  Can be repeated to add
+	multiple files.  The path of the file in the archive is built by
+	concatenating the value of the last `--prefix` option (if any)
+	before this `--add-file` and the basename of <file>.
+
+--add-virtual-file=<path>:<content>::
+	Add the specified contents to the archive.  Can be repeated to add
+	multiple files.
++
+The `<path>` argument can start and end with a literal double-quote
+character; the contained file name is interpreted as a C-style string,
+i.e. the backslash is interpreted as escape character. The path must
+be quoted if it contains a colon, to avoid the colon from being
+misinterpreted as the separator between the path and the contents, or
+if the path begins or ends with a double-quote character.
++
+The file mode is limited to a regular file, and the option may be
+subject to platform-dependent command-line limits. For non-trivial
+cases, write an untracked file and use `--add-file` instead.
++
+Note that unlike `--add-file` the path created in the archive is not
+affected by the `--prefix` option, as a full `<path>` can be given as
+the value of the option.
+
+--worktree-attributes::
+	Look for attributes in .gitattributes files in the working tree
+	as well (see <<ATTRIBUTES>>).
+
+--mtime=<time>::
+	Set modification time of archive entries.  Without this option
+	the committer time is used if `<tree-ish>` is a commit or tag,
+	and the current time if it is a tree.
+
+<extra>::
+	This can be any options that the archiver backend understands.
+	See next section.
+
+--remote=<repo>::
+	Instead of making a tar archive from the local repository,
+	retrieve a tar archive from a remote repository. Note that the
+	remote repository may place restrictions on which sha1
+	expressions may be allowed in `<tree-ish>`. See
+	linkgit:git-upload-archive[1] for details.
+
+--exec=<git-upload-archive>::
+	Used with --remote to specify the path to the
+	'git-upload-archive' on the remote side.
+
+<tree-ish>::
+	The tree or commit to produce an archive for.
+
+<path>::
+	Without an optional path parameter, all files and subdirectories
+	of the current working directory are included in the archive.
+	If one or more paths are specified, only these are included.
+
+BACKEND EXTRA OPTIONS
+---------------------
+
+zip
+~~~
+-<digit>::
+	Specify compression level.  Larger values allow the command
+	to spend more time to compress to smaller size.  Supported
+	values are from `-0` (store-only) to `-9` (best ratio).
+	Default is `-6` if not given.
+
+tar
+~~~
+-<number>::
+	Specify compression level. The value will be passed to the
+	compression command configured in `tar.<format>.command`. See
+	manual page of the configured command for the list of supported
+	levels and the default level if this option isn't specified.
+
+CONFIGURATION
+-------------
+
+tar.umask::
+	This variable can be used to restrict the permission bits of
+	tar archive entries.  The default is 0002, which turns off the
+	world write bit.  The special value "user" indicates that the
+	archiving user's umask will be used instead.  See umask(2) for
+	details.  If `--remote` is used then only the configuration of
+	the remote repository takes effect.
+
+tar.<format>.command::
+	This variable specifies a shell command through which the tar
+	output generated by `git archive` should be piped. The command
+	is executed using the shell with the generated tar file on its
+	standard input, and should produce the final output on its
+	standard output. Any compression-level options will be passed
+	to the command (e.g., `-9`).
++
+The `tar.gz` and `tgz` formats are defined automatically and use the
+magic command `git archive gzip` by default, which invokes an internal
+implementation of gzip.
+
+tar.<format>.remote::
+	If true, enable the format for use by remote clients via
+	linkgit:git-upload-archive[1]. Defaults to false for
+	user-defined formats, but true for the `tar.gz` and `tgz`
+	formats.
+
+[[ATTRIBUTES]]
+ATTRIBUTES
+----------
+
+export-ignore::
+	Files and directories with the attribute export-ignore won't be
+	added to archive files.  See linkgit:gitattributes[5] for details.
+
+export-subst::
+	If the attribute export-subst is set for a file then Git will
+	expand several placeholders when adding this file to an archive.
+	See linkgit:gitattributes[5] for details.
+
+Note that attributes are by default taken from the `.gitattributes` files
+in the tree that is being archived.  If you want to tweak the way the
+output is generated after the fact (e.g. you committed without adding an
+appropriate export-ignore in its `.gitattributes`), adjust the checked out
+`.gitattributes` file as necessary and use `--worktree-attributes`
+option.  Alternatively you can keep necessary attributes that should apply
+while archiving any tree in your `$GIT_DIR/info/attributes` file.
+
+EXAMPLES
+--------
+`git archive --format=tar --prefix=junk/ HEAD | (cd /var/tmp/ && tar xf -)`::
+
+	Create a tar archive that contains the contents of the
+	latest commit on the current branch, and extract it in the
+	`/var/tmp/junk` directory.
+
+`git archive --format=tar --prefix=git-1.4.0/ v1.4.0 | gzip >git-1.4.0.tar.gz`::
+
+	Create a compressed tarball for v1.4.0 release.
+
+`git archive --format=tar.gz --prefix=git-1.4.0/ v1.4.0 >git-1.4.0.tar.gz`::
+
+	Same as above, but using the builtin tar.gz handling.
+
+`git archive --prefix=git-1.4.0/ -o git-1.4.0.tar.gz v1.4.0`::
+
+	Same as above, but the format is inferred from the output file.
+
+`git archive --format=tar --prefix=git-1.4.0/ v1.4.0^{tree} | gzip >git-1.4.0.tar.gz`::
+
+	Create a compressed tarball for v1.4.0 release, but without a
+	global extended pax header.
+
+`git archive --format=zip --prefix=git-docs/ HEAD:Documentation/ > git-1.4.0-docs.zip`::
+
+	Put everything in the current head's Documentation/ directory
+	into 'git-1.4.0-docs.zip', with the prefix 'git-docs/'.
+
+`git archive -o latest.zip HEAD`::
+
+	Create a Zip archive that contains the contents of the latest
+	commit on the current branch. Note that the output format is
+	inferred by the extension of the output file.
+
+`git archive -o latest.tar --prefix=build/ --add-file=configure --prefix= HEAD`::
+
+	Creates a tar archive that contains the contents of the latest
+	commit on the current branch with no prefix and the untracked
+	file 'configure' with the prefix 'build/'.
+
+`git config tar.tar.xz.command "xz -c"`::
+
+	Configure a "tar.xz" format for making LZMA-compressed tarfiles.
+	You can use it specifying `--format=tar.xz`, or by creating an
+	output file like `-o foo.tar.xz`.
+
+
+SEE ALSO
+--------
+linkgit:gitattributes[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-bisect-lk2009.adoc b/Documentation/git-bisect-lk2009.adoc
new file mode 100644
index 0000000000..0bc165788e
--- /dev/null
+++ b/Documentation/git-bisect-lk2009.adoc
@@ -0,0 +1,1358 @@
+Fighting regressions with git bisect
+====================================
+:Author: Christian Couder
+:Email: chriscool@xxxxxxxxxxxxx
+:Date: 2009/11/08
+
+Abstract
+--------
+
+"git bisect" enables software users and developers to easily find the
+commit that introduced a regression. We show why it is important to
+have good tools to fight regressions. We describe how "git bisect"
+works from the outside and the algorithms it uses inside. Then we
+explain how to take advantage of "git bisect" to improve current
+practices. And we discuss how "git bisect" could improve in the
+future.
+
+
+Introduction to "git bisect"
+----------------------------
+
+Git is a Distributed Version Control system (DVCS) created by Linus
+Torvalds and maintained by Junio Hamano.
+
+In Git like in many other Version Control Systems (VCS), the different
+states of the data that is managed by the system are called
+commits. And, as VCS are mostly used to manage software source code,
+sometimes "interesting" changes of behavior in the software are
+introduced in some commits.
+
+In fact people are specially interested in commits that introduce a
+"bad" behavior, called a bug or a regression. They are interested in
+these commits because a commit (hopefully) contains a very small set
+of source code changes. And it's much easier to understand and
+properly fix a problem when you only need to check a very small set of
+changes, than when you don't know where look in the first place.
+
+So to help people find commits that introduce a "bad" behavior, the
+"git bisect" set of commands was invented. And it follows of course
+that in "git bisect" parlance, commits where the "interesting
+behavior" is present are called "bad" commits, while other commits are
+called "good" commits. And a commit that introduce the behavior we are
+interested in is called a "first bad commit". Note that there could be
+more than one "first bad commit" in the commit space we are searching.
+
+So "git bisect" is designed to help find a "first bad commit". And to
+be as efficient as possible, it tries to perform a binary search.
+
+
+Fighting regressions overview
+-----------------------------
+
+Regressions: a big problem
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Regressions are a big problem in the software industry. But it's
+difficult to put some real numbers behind that claim.
+
+There are some numbers about bugs in general, like a NIST study in
+2002 <<1>> that said:
+
+_____________
+Software bugs, or errors, are so prevalent and so detrimental that
+they cost the U.S. economy an estimated $59.5 billion annually, or
+about 0.6 percent of the gross domestic product, according to a newly
+released study commissioned by the Department of Commerce's National
+Institute of Standards and Technology (NIST). At the national level,
+over half of the costs are borne by software users and the remainder
+by software developers/vendors.  The study also found that, although
+all errors cannot be removed, more than a third of these costs, or an
+estimated $22.2 billion, could be eliminated by an improved testing
+infrastructure that enables earlier and more effective identification
+and removal of software defects. These are the savings associated with
+finding an increased percentage (but not 100 percent) of errors closer
+to the development stages in which they are introduced. Currently,
+over half of all errors are not found until "downstream" in the
+development process or during post-sale software use.
+_____________
+
+And then:
+
+_____________
+Software developers already spend approximately 80 percent of
+development costs on identifying and correcting defects, and yet few
+products of any type other than software are shipped with such high
+levels of errors.
+_____________
+
+Eventually the conclusion started with:
+
+_____________
+The path to higher software quality is significantly improved software
+testing.
+_____________
+
+There are other estimates saying that 80% of the cost related to
+software is about maintenance <<2>>.
+
+Though, according to Wikipedia <<3>>:
+
+_____________
+A common perception of maintenance is that it is merely fixing
+bugs. However, studies and surveys over the years have indicated that
+the majority, over 80%, of the maintenance effort is used for
+non-corrective actions (Pigosky 1997). This perception is perpetuated
+by users submitting problem reports that in reality are functionality
+enhancements to the system.
+_____________
+
+But we can guess that improving on existing software is very costly
+because you have to watch out for regressions. At least this would
+make the above studies consistent among themselves.
+
+Of course some kind of software is developed, then used during some
+time without being improved on much, and then finally thrown away. In
+this case, of course, regressions may not be a big problem. But on the
+other hand, there is a lot of big software that is continually
+developed and maintained during years or even tens of years by a lot
+of people. And as there are often many people who depend (sometimes
+critically) on such software, regressions are a really big problem.
+
+One such software is the Linux kernel. And if we look at the Linux
+kernel, we can see that a lot of time and effort is spent to fight
+regressions. The release cycle start with a 2 weeks long merge
+window. Then the first release candidate (rc) version is tagged. And
+after that about 7 or 8 more rc versions will appear with around one
+week between each of them, before the final release.
+
+The time between the first rc release and the final release is
+supposed to be used to test rc versions and fight bugs and especially
+regressions. And this time is more than 80% of the release cycle
+time. But this is not the end of the fight yet, as of course it
+continues after the release.
+
+And then this is what Ingo Molnar (a well known Linux kernel
+developer) says about his use of git bisect:
+
+_____________
+I most actively use it during the merge window (when a lot of trees
+get merged upstream and when the influx of bugs is the highest) - and
+yes, there have been cases that i used it multiple times a day. My
+average is roughly once a day.
+_____________
+
+So regressions are fought all the time by developers, and indeed it is
+well known that bugs should be fixed as soon as possible, so as soon
+as they are found. That's why it is interesting to have good tools for
+this purpose.
+
+Other tools to fight regressions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+So what are the tools used to fight regressions? They are nearly the
+same as those used to fight regular bugs. The only specific tools are
+test suites and tools similar as "git bisect".
+
+Test suites are very nice. But when they are used alone, they are
+supposed to be used so that all the tests are checked after each
+commit. This means that they are not very efficient, because many
+tests are run for no interesting result, and they suffer from
+combinatorial explosion.
+
+In fact the problem is that big software often has many different
+configuration options and that each test case should pass for each
+configuration after each commit. So if you have for each release: N
+configurations, M commits and T test cases, you should perform:
+
+-------------
+N * M * T tests
+-------------
+
+where N, M and T are all growing with the size your software.
+
+So very soon it will not be possible to completely test everything.
+
+And if some bugs slip through your test suite, then you can add a test
+to your test suite. But if you want to use your new improved test
+suite to find where the bug slipped in, then you will either have to
+emulate a bisection process or you will perhaps bluntly test each
+commit backward starting from the "bad" commit you have which may be
+very wasteful.
+
+"git bisect" overview
+---------------------
+
+Starting a bisection
+~~~~~~~~~~~~~~~~~~~~
+
+The first "git bisect" subcommand to use is "git bisect start" to
+start the search. Then bounds must be set to limit the commit
+space. This is done usually by giving one "bad" and at least one
+"good" commit. They can be passed in the initial call to "git bisect
+start" like this:
+
+-------------
+$ git bisect start [BAD [GOOD...]]
+-------------
+
+or they can be set using:
+
+-------------
+$ git bisect bad [COMMIT]
+-------------
+
+and:
+
+-------------
+$ git bisect good [COMMIT...]
+-------------
+
+where BAD, GOOD and COMMIT are all names that can be resolved to a
+commit.
+
+Then "git bisect" will checkout a commit of its choosing and ask the
+user to test it, like this:
+
+-------------
+$ git bisect start v2.6.27 v2.6.25
+Bisecting: 10928 revisions left to test after this (roughly 14 steps)
+[2ec65f8b89ea003c27ff7723525a2ee335a2b393] x86: clean up using max_low_pfn on 32-bit
+-------------
+
+Note that the example that we will use is really a toy example, we
+will be looking for the first commit that has a version like
+"2.6.26-something", that is the commit that has a "SUBLEVEL = 26" line
+in the top level Makefile. This is a toy example because there are
+better ways to find this commit with Git than using "git bisect" (for
+example "git blame" or "git log -S<string>").
+
+Driving a bisection manually
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+At this point there are basically 2 ways to drive the search. It can
+be driven manually by the user or it can be driven automatically by a
+script or a command.
+
+If the user is driving it, then at each step of the search, the user
+will have to test the current commit and say if it is "good" or "bad"
+using the "git bisect good" or "git bisect bad" commands respectively
+that have been described above. For example:
+
+-------------
+$ git bisect bad
+Bisecting: 5480 revisions left to test after this (roughly 13 steps)
+[66c0b394f08fd89236515c1c84485ea712a157be] KVM: kill file->f_count abuse in kvm
+-------------
+
+And after a few more steps like that, "git bisect" will eventually
+find a first bad commit:
+
+-------------
+$ git bisect bad
+2ddcca36c8bcfa251724fe342c8327451988be0d is the first bad commit
+commit 2ddcca36c8bcfa251724fe342c8327451988be0d
+Author: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
+Date:   Sat May 3 11:59:44 2008 -0700
+
+    Linux 2.6.26-rc1
+
+:100644 100644 5cf82581... 4492984e... M      Makefile
+-------------
+
+At this point we can see what the commit does, check it out (if it's
+not already checked out) or tinker with it, for example:
+
+-------------
+$ git show HEAD
+commit 2ddcca36c8bcfa251724fe342c8327451988be0d
+Author: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
+Date:   Sat May 3 11:59:44 2008 -0700
+
+    Linux 2.6.26-rc1
+
+diff --git a/Makefile b/Makefile
+index 5cf8258..4492984 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,7 +1,7 @@
+ VERSION = 2
+ PATCHLEVEL = 6
+-SUBLEVEL = 25
+-EXTRAVERSION =
++SUBLEVEL = 26
++EXTRAVERSION = -rc1
+ NAME = Funky Weasel is Jiggy wit it
+
+ # *DOCUMENTATION*
+-------------
+
+And when we are finished we can use "git bisect reset" to go back to
+the branch we were in before we started bisecting:
+
+-------------
+$ git bisect reset
+Checking out files: 100% (21549/21549), done.
+Previous HEAD position was 2ddcca3... Linux 2.6.26-rc1
+Switched to branch 'master'
+-------------
+
+Driving a bisection automatically
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The other way to drive the bisection process is to tell "git bisect"
+to launch a script or command at each bisection step to know if the
+current commit is "good" or "bad". To do that, we use the "git bisect
+run" command. For example:
+
+-------------
+$ git bisect start v2.6.27 v2.6.25
+Bisecting: 10928 revisions left to test after this (roughly 14 steps)
+[2ec65f8b89ea003c27ff7723525a2ee335a2b393] x86: clean up using max_low_pfn on 32-bit
+$
+$ git bisect run grep '^SUBLEVEL = 25' Makefile
+running grep ^SUBLEVEL = 25 Makefile
+Bisecting: 5480 revisions left to test after this (roughly 13 steps)
+[66c0b394f08fd89236515c1c84485ea712a157be] KVM: kill file->f_count abuse in kvm
+running grep ^SUBLEVEL = 25 Makefile
+SUBLEVEL = 25
+Bisecting: 2740 revisions left to test after this (roughly 12 steps)
+[671294719628f1671faefd4882764886f8ad08cb] V4L/DVB(7879): Adding cx18 Support for mxl5005s
+...
+...
+running grep ^SUBLEVEL = 25 Makefile
+Bisecting: 0 revisions left to test after this (roughly 0 steps)
+[2ddcca36c8bcfa251724fe342c8327451988be0d] Linux 2.6.26-rc1
+running grep ^SUBLEVEL = 25 Makefile
+2ddcca36c8bcfa251724fe342c8327451988be0d is the first bad commit
+commit 2ddcca36c8bcfa251724fe342c8327451988be0d
+Author: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
+Date:   Sat May 3 11:59:44 2008 -0700
+
+    Linux 2.6.26-rc1
+
+:100644 100644 5cf82581... 4492984e... M      Makefile
+bisect run success
+-------------
+
+In this example, we passed "grep '^SUBLEVEL = 25' Makefile" as
+parameter to "git bisect run". This means that at each step, the grep
+command we passed will be launched. And if it exits with code 0 (that
+means success) then git bisect will mark the current state as
+"good". If it exits with code 1 (or any code between 1 and 127
+included, except the special code 125), then the current state will be
+marked as "bad".
+
+Exit code between 128 and 255 are special to "git bisect run". They
+make it stop immediately the bisection process. This is useful for
+example if the command passed takes too long to complete, because you
+can kill it with a signal and it will stop the bisection process.
+
+It can also be useful in scripts passed to "git bisect run" to "exit
+255" if some very abnormal situation is detected.
+
+Avoiding untestable commits
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes it happens that the current state cannot be tested, for
+example if it does not compile because there was a bug preventing it
+at that time. This is what the special exit code 125 is for. It tells
+"git bisect run" that the current commit should be marked as
+untestable and that another one should be chosen and checked out.
+
+If the bisection process is driven manually, you can use "git bisect
+skip" to do the same thing. (In fact the special exit code 125 makes
+"git bisect run" use "git bisect skip" in the background.)
+
+Or if you want more control, you can inspect the current state using
+for example "git bisect visualize". It will launch gitk (or "git log"
+if the `DISPLAY` environment variable is not set) to help you find a
+better bisection point.
+
+Either way, if you have a string of untestable commits, it might
+happen that the regression you are looking for has been introduced by
+one of these untestable commits. In this case it's not possible to
+tell for sure which commit introduced the regression.
+
+So if you used "git bisect skip" (or the run script exited with
+special code 125) you could get a result like this:
+
+-------------
+There are only 'skip'ped commits left to test.
+The first bad commit could be any of:
+15722f2fa328eaba97022898a305ffc8172db6b1
+78e86cf3e850bd755bb71831f42e200626fbd1e0
+e15b73ad3db9b48d7d1ade32f8cd23a751fe0ace
+070eab2303024706f2924822bfec8b9847e4ac1b
+We cannot bisect more!
+-------------
+
+Saving a log and replaying it
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you want to show other people your bisection process, you can get a
+log using for example:
+
+-------------
+$ git bisect log > bisect_log.txt
+-------------
+
+And it is possible to replay it using:
+
+-------------
+$ git bisect replay bisect_log.txt
+-------------
+
+
+"git bisect" details
+--------------------
+
+Bisection algorithm
+~~~~~~~~~~~~~~~~~~~
+
+As the Git commits form a directed acyclic graph (DAG), finding the
+best bisection commit to test at each step is not so simple. Anyway
+Linus found and implemented a "truly stupid" algorithm, later improved
+by Junio Hamano, that works quite well.
+
+So the algorithm used by "git bisect" to find the best bisection
+commit when there are no skipped commits is the following:
+
+1) keep only the commits that:
+
+a) are ancestor of the "bad" commit (including the "bad" commit itself),
+b) are not ancestor of a "good" commit (excluding the "good" commits).
+
+This means that we get rid of the uninteresting commits in the DAG.
+
+For example if we start with a graph like this:
+
+-------------
+G-Y-G-W-W-W-X-X-X-X
+	   \ /
+	    W-W-B
+	   /
+Y---G-W---W
+ \ /   \
+Y-Y     X-X-X-X
+
+-> time goes this way ->
+-------------
+
+where B is the "bad" commit, "G" are "good" commits and W, X, and Y
+are other commits, we will get the following graph after this first
+step:
+
+-------------
+W-W-W
+     \
+      W-W-B
+     /
+W---W
+-------------
+
+So only the W and B commits will be kept. Because commits X and Y will
+have been removed by rules a) and b) respectively, and because commits
+G are removed by rule b) too.
+
+Note for Git users, that it is equivalent as keeping only the commit
+given by:
+
+-------------
+git rev-list BAD --not GOOD1 GOOD2...
+-------------
+
+Also note that we don't require the commits that are kept to be
+descendants of a "good" commit. So in the following example, commits W
+and Z will be kept:
+
+-------------
+G-W-W-W-B
+   /
+Z-Z
+-------------
+
+2) starting from the "good" ends of the graph, associate to each
+   commit the number of ancestors it has plus one
+
+For example with the following graph where H is the "bad" commit and A
+and D are some parents of some "good" commits:
+
+-------------
+A-B-C
+     \
+      F-G-H
+     /
+D---E
+-------------
+
+this will give:
+
+-------------
+1 2 3
+A-B-C
+     \6 7 8
+      F-G-H
+1   2/
+D---E
+-------------
+
+3) associate to each commit: min(X, N - X)
+
+where X is the value associated to the commit in step 2) and N is the
+total number of commits in the graph.
+
+In the above example we have N = 8, so this will give:
+
+-------------
+1 2 3
+A-B-C
+     \2 1 0
+      F-G-H
+1   2/
+D---E
+-------------
+
+4) the best bisection point is the commit with the highest associated
+   number
+
+So in the above example the best bisection point is commit C.
+
+5) note that some shortcuts are implemented to speed up the algorithm
+
+As we know N from the beginning, we know that min(X, N - X) can't be
+greater than N/2. So during steps 2) and 3), if we would associate N/2
+to a commit, then we know this is the best bisection point. So in this
+case we can just stop processing any other commit and return the
+current commit.
+
+Bisection algorithm debugging
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For any commit graph, you can see the number associated with each
+commit using "git rev-list --bisect-all".
+
+For example, for the above graph, a command like:
+
+-------------
+$ git rev-list --bisect-all BAD --not GOOD1 GOOD2
+-------------
+
+would output something like:
+
+-------------
+e15b73ad3db9b48d7d1ade32f8cd23a751fe0ace (dist=3)
+15722f2fa328eaba97022898a305ffc8172db6b1 (dist=2)
+78e86cf3e850bd755bb71831f42e200626fbd1e0 (dist=2)
+a1939d9a142de972094af4dde9a544e577ddef0e (dist=2)
+070eab2303024706f2924822bfec8b9847e4ac1b (dist=1)
+a3864d4f32a3bf5ed177ddef598490a08760b70d (dist=1)
+a41baa717dd74f1180abf55e9341bc7a0bb9d556 (dist=1)
+9e622a6dad403b71c40979743bb9d5be17b16bd6 (dist=0)
+-------------
+
+Bisection algorithm discussed
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+First let's define "best bisection point". We will say that a commit X
+is a best bisection point or a best bisection commit if knowing its
+state ("good" or "bad") gives as much information as possible whether
+the state of the commit happens to be "good" or "bad".
+
+This means that the best bisection commits are the commits where the
+following function is maximum:
+
+-------------
+f(X) = min(information_if_good(X), information_if_bad(X))
+-------------
+
+where information_if_good(X) is the information we get if X is good
+and information_if_bad(X) is the information we get if X is bad.
+
+Now we will suppose that there is only one "first bad commit". This
+means that all its descendants are "bad" and all the other commits are
+"good". And we will suppose that all commits have an equal probability
+of being good or bad, or of being the first bad commit, so knowing the
+state of c commits gives always the same amount of information
+wherever these c commits are on the graph and whatever c is. (So we
+suppose that these commits being for example on a branch or near a
+good or a bad commit does not give more or less information).
+
+Let's also suppose that we have a cleaned up graph like one after step
+1) in the bisection algorithm above. This means that we can measure
+   the information we get in terms of number of commit we can remove
+   from the graph..
+
+And let's take a commit X in the graph.
+
+If X is found to be "good", then we know that its ancestors are all
+"good", so we want to say that:
+
+-------------
+information_if_good(X) = number_of_ancestors(X)  (TRUE)
+-------------
+
+And this is true because at step 1) b) we remove the ancestors of the
+"good" commits.
+
+If X is found to be "bad", then we know that its descendants are all
+"bad", so we want to say that:
+
+-------------
+information_if_bad(X) = number_of_descendants(X)  (WRONG)
+-------------
+
+But this is wrong because at step 1) a) we keep only the ancestors of
+the bad commit. So we get more information when a commit is marked as
+"bad", because we also know that the ancestors of the previous "bad"
+commit that are not ancestors of the new "bad" commit are not the
+first bad commit. We don't know if they are good or bad, but we know
+that they are not the first bad commit because they are not ancestor
+of the new "bad" commit.
+
+So when a commit is marked as "bad" we know we can remove all the
+commits in the graph except those that are ancestors of the new "bad"
+commit. This means that:
+
+-------------
+information_if_bad(X) = N - number_of_ancestors(X)  (TRUE)
+-------------
+
+where N is the number of commits in the (cleaned up) graph.
+
+So in the end this means that to find the best bisection commits we
+should maximize the function:
+
+-------------
+f(X) = min(number_of_ancestors(X), N - number_of_ancestors(X))
+-------------
+
+And this is nice because at step 2) we compute number_of_ancestors(X)
+and so at step 3) we compute f(X).
+
+Let's take the following graph as an example:
+
+-------------
+            G-H-I-J
+           /       \
+A-B-C-D-E-F         O
+           \       /
+            K-L-M-N
+-------------
+
+If we compute the following non optimal function on it:
+
+-------------
+g(X) = min(number_of_ancestors(X), number_of_descendants(X))
+-------------
+
+we get:
+
+-------------
+            4 3 2 1
+            G-H-I-J
+1 2 3 4 5 6/       \0
+A-B-C-D-E-F         O
+           \       /
+            K-L-M-N
+            4 3 2 1
+-------------
+
+but with the algorithm used by git bisect we get:
+
+-------------
+            7 7 6 5
+            G-H-I-J
+1 2 3 4 5 6/       \0
+A-B-C-D-E-F         O
+           \       /
+            K-L-M-N
+            7 7 6 5
+-------------
+
+So we chose G, H, K or L as the best bisection point, which is better
+than F. Because if for example L is bad, then we will know not only
+that L, M and N are bad but also that G, H, I and J are not the first
+bad commit (since we suppose that there is only one first bad commit
+and it must be an ancestor of L).
+
+So the current algorithm seems to be the best possible given what we
+initially supposed.
+
+Skip algorithm
+~~~~~~~~~~~~~~
+
+When some commits have been skipped (using "git bisect skip"), then
+the bisection algorithm is the same for step 1) to 3). But then we use
+roughly the following steps:
+
+6) sort the commit by decreasing associated value
+
+7) if the first commit has not been skipped, we can return it and stop
+   here
+
+8) otherwise filter out all the skipped commits in the sorted list
+
+9) use a pseudo random number generator (PRNG) to generate a random
+   number between 0 and 1
+
+10) multiply this random number with its square root to bias it toward
+    0
+
+11) multiply the result by the number of commits in the filtered list
+    to get an index into this list
+
+12) return the commit at the computed index
+
+Skip algorithm discussed
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+After step 7) (in the skip algorithm), we could check if the second
+commit has been skipped and return it if it is not the case. And in
+fact that was the algorithm we used from when "git bisect skip" was
+developed in Git version 1.5.4 (released on February 1st 2008) until
+Git version 1.6.4 (released July 29th 2009).
+
+But Ingo Molnar and H. Peter Anvin (another well known linux kernel
+developer) both complained that sometimes the best bisection points
+all happened to be in an area where all the commits are
+untestable. And in this case the user was asked to test many
+untestable commits, which could be very inefficient.
+
+Indeed untestable commits are often untestable because a breakage was
+introduced at one time, and that breakage was fixed only after many
+other commits were introduced.
+
+This breakage is of course most of the time unrelated to the breakage
+we are trying to locate in the commit graph. But it prevents us to
+know if the interesting "bad behavior" is present or not.
+
+So it is a fact that commits near an untestable commit have a high
+probability of being untestable themselves. And the best bisection
+commits are often found together too (due to the bisection algorithm).
+
+This is why it is a bad idea to just chose the next best unskipped
+bisection commit when the first one has been skipped.
+
+We found that most commits on the graph may give quite a lot of
+information when they are tested. And the commits that will not on
+average give a lot of information are the one near the good and bad
+commits.
+
+So using a PRNG with a bias to favor commits away from the good and
+bad commits looked like a good choice.
+
+One obvious improvement to this algorithm would be to look for a
+commit that has an associated value near the one of the best bisection
+commit, and that is on another branch, before using the PRNG. Because
+if such a commit exists, then it is not very likely to be untestable
+too, so it will probably give more information than a nearly randomly
+chosen one.
+
+Checking merge bases
+~~~~~~~~~~~~~~~~~~~~
+
+There is another tweak in the bisection algorithm that has not been
+described in the "bisection algorithm" above.
+
+We supposed in the previous examples that the "good" commits were
+ancestors of the "bad" commit. But this is not a requirement of "git
+bisect".
+
+Of course the "bad" commit cannot be an ancestor of a "good" commit,
+because the ancestors of the good commits are supposed to be
+"good". And all the "good" commits must be related to the bad commit.
+They cannot be on a branch that has no link with the branch of the
+"bad" commit. But it is possible for a good commit to be related to a
+bad commit and yet not be neither one of its ancestor nor one of its
+descendants.
+
+For example, there can be a "main" branch, and a "dev" branch that was
+forked of the main branch at a commit named "D" like this:
+
+-------------
+A-B-C-D-E-F-G  <--main
+       \
+        H-I-J  <--dev
+-------------
+
+The commit "D" is called a "merge base" for branch "main" and "dev"
+because it's the best common ancestor for these branches for a merge.
+
+Now let's suppose that commit J is bad and commit G is good and that
+we apply the bisection algorithm like it has been previously
+described.
+
+As described in step 1) b) of the bisection algorithm, we remove all
+the ancestors of the good commits because they are supposed to be good
+too.
+
+So we would be left with only:
+
+-------------
+H-I-J
+-------------
+
+But what happens if the first bad commit is "B" and if it has been
+fixed in the "main" branch by commit "F"?
+
+The result of such a bisection would be that we would find that H is
+the first bad commit, when in fact it's B. So that would be wrong!
+
+And yes it can happen in practice that people working on one branch
+are not aware that people working on another branch fixed a bug! It
+could also happen that F fixed more than one bug or that it is a
+revert of some big development effort that was not ready to be
+released.
+
+In fact development teams often maintain both a development branch and
+a maintenance branch, and it would be quite easy for them if "git
+bisect" just worked when they want to bisect a regression on the
+development branch that is not on the maintenance branch. They should
+be able to start bisecting using:
+
+-------------
+$ git bisect start dev main
+-------------
+
+To enable that additional nice feature, when a bisection is started
+and when some good commits are not ancestors of the bad commit, we
+first compute the merge bases between the bad and the good commits and
+we chose these merge bases as the first commits that will be checked
+out and tested.
+
+If it happens that one merge base is bad, then the bisection process
+is stopped with a message like:
+
+-------------
+The merge base BBBBBB is bad.
+This means the bug has been fixed between BBBBBB and [GGGGGG,...].
+-------------
+
+where BBBBBB is the sha1 hash of the bad merge base and [GGGGGG,...]
+is a comma separated list of the sha1 of the good commits.
+
+If some of the merge bases are skipped, then the bisection process
+continues, but the following message is printed for each skipped merge
+base:
+
+-------------
+Warning: the merge base between BBBBBB and [GGGGGG,...] must be skipped.
+So we cannot be sure the first bad commit is between MMMMMM and BBBBBB.
+We continue anyway.
+-------------
+
+where BBBBBB is the sha1 hash of the bad commit, MMMMMM is the sha1
+hash of the merge base that is skipped and [GGGGGG,...]  is a comma
+separated list of the sha1 of the good commits.
+
+So if there is no bad merge base, the bisection process continues as
+usual after this step.
+
+Best bisecting practices
+------------------------
+
+Using test suites and git bisect together
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you both have a test suite and use git bisect, then it becomes less
+important to check that all tests pass after each commit. Though of
+course it is probably a good idea to have some checks to avoid
+breaking too many things because it could make bisecting other bugs
+more difficult.
+
+You can focus your efforts to check at a few points (for example rc
+and beta releases) that all the T test cases pass for all the N
+configurations. And when some tests don't pass you can use "git
+bisect" (or better "git bisect run"). So you should perform roughly:
+
+-------------
+c * N * T + b * M * log2(M) tests
+-------------
+
+where c is the number of rounds of test (so a small constant) and b is
+the ratio of bug per commit (hopefully a small constant too).
+
+So of course it's much better as it's O(N * T) vs O(N * T * M) if
+you would test everything after each commit.
+
+This means that test suites are good to prevent some bugs from being
+committed and they are also quite good to tell you that you have some
+bugs. But they are not so good to tell you where some bugs have been
+introduced. To tell you that efficiently, git bisect is needed.
+
+The other nice thing with test suites, is that when you have one, you
+already know how to test for bad behavior. So you can use this
+knowledge to create a new test case for "git bisect" when it appears
+that there is a regression. So it will be easier to bisect the bug and
+fix it. And then you can add the test case you just created to your
+test suite.
+
+So if you know how to create test cases and how to bisect, you will be
+subject to a virtuous circle:
+
+more tests => easier to create tests => easier to bisect => more tests
+
+So test suites and "git bisect" are complementary tools that are very
+powerful and efficient when used together.
+
+Bisecting build failures
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can very easily automatically bisect broken builds using something
+like:
+
+-------------
+$ git bisect start BAD GOOD
+$ git bisect run make
+-------------
+
+Passing sh -c "some commands" to "git bisect run"
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+For example:
+
+-------------
+$ git bisect run sh -c "make || exit 125; ./my_app | grep 'good output'"
+-------------
+
+On the other hand if you do this often, then it can be worth having
+scripts to avoid too much typing.
+
+Finding performance regressions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here is an example script that comes slightly modified from a real
+world script used by Junio Hamano <<4>>.
+
+This script can be passed to "git bisect run" to find the commit that
+introduced a performance regression:
+
+-------------
+#!/bin/sh
+
+# Build errors are not what I am interested in.
+make my_app || exit 255
+
+# We are checking if it stops in a reasonable amount of time, so
+# let it run in the background...
+
+./my_app >log 2>&1 &
+
+# ... and grab its process ID.
+pid=$!
+
+# ... and then wait for sufficiently long.
+sleep $NORMAL_TIME
+
+# ... and then see if the process is still there.
+if kill -0 $pid
+then
+	# It is still running -- that is bad.
+	kill $pid; sleep 1; kill $pid;
+	exit 1
+else
+	# It has already finished (the $pid process was no more),
+	# and we are happy.
+	exit 0
+fi
+-------------
+
+Following general best practices
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+It is obviously a good idea not to have commits with changes that
+knowingly break things, even if some other commits later fix the
+breakage.
+
+It is also a good idea when using any VCS to have only one small
+logical change in each commit.
+
+The smaller the changes in your commit, the most effective "git
+bisect" will be. And you will probably need "git bisect" less in the
+first place, as small changes are easier to review even if they are
+only reviewed by the committer.
+
+Another good idea is to have good commit messages. They can be very
+helpful to understand why some changes were made.
+
+These general best practices are very helpful if you bisect often.
+
+Avoiding bug prone merges
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+First merges by themselves can introduce some regressions even when
+the merge needs no source code conflict resolution. This is because a
+semantic change can happen in one branch while the other branch is not
+aware of it.
+
+For example one branch can change the semantic of a function while the
+other branch add more calls to the same function.
+
+This is made much worse if many files have to be fixed to resolve
+conflicts. That's why such merges are called "evil merges". They can
+make regressions very difficult to track down. It can even be
+misleading to know the first bad commit if it happens to be such a
+merge, because people might think that the bug comes from bad conflict
+resolution when it comes from a semantic change in one branch.
+
+Anyway "git rebase" can be used to linearize history. This can be used
+either to avoid merging in the first place. Or it can be used to
+bisect on a linear history instead of the non linear one, as this
+should give more information in case of a semantic change in one
+branch.
+
+Merges can be also made simpler by using smaller branches or by using
+many topic branches instead of only long version related branches.
+
+And testing can be done more often in special integration branches
+like linux-next for the linux kernel.
+
+Adapting your work-flow
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A special work-flow to process regressions can give great results.
+
+Here is an example of a work-flow used by Andreas Ericsson:
+
+* write, in the test suite, a test script that exposes the regression
+* use "git bisect run" to find the commit that introduced it
+* fix the bug that is often made obvious by the previous step
+* commit both the fix and the test script (and if needed more tests)
+
+And here is what Andreas said about this work-flow <<5>>:
+
+_____________
+To give some hard figures, we used to have an average report-to-fix
+cycle of 142.6 hours (according to our somewhat weird bug-tracker
+which just measures wall-clock time). Since we moved to Git, we've
+lowered that to 16.2 hours. Primarily because we can stay on top of
+the bug fixing now, and because everyone's jockeying to get to fix
+bugs (we're quite proud of how lazy we are to let Git find the bugs
+for us). Each new release results in ~40% fewer bugs (almost certainly
+due to how we now feel about writing tests).
+_____________
+
+Clearly this work-flow uses the virtuous circle between test suites
+and "git bisect". In fact it makes it the standard procedure to deal
+with regression.
+
+In other messages Andreas says that they also use the "best practices"
+described above: small logical commits, topic branches, no evil
+merge,... These practices all improve the bisectability of the commit
+graph, by making it easier and more useful to bisect.
+
+So a good work-flow should be designed around the above points. That
+is making bisecting easier, more useful and standard.
+
+Involving QA people and if possible end users
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+One nice about "git bisect" is that it is not only a developer
+tool. It can effectively be used by QA people or even end users (if
+they have access to the source code or if they can get access to all
+the builds).
+
+There was a discussion at one point on the linux kernel mailing list
+of whether it was ok to always ask end user to bisect, and very good
+points were made to support the point of view that it is ok.
+
+For example David Miller wrote <<6>>:
+
+_____________
+What people don't get is that this is a situation where the "end node
+principle" applies. When you have limited resources (here: developers)
+you don't push the bulk of the burden upon them. Instead you push
+things out to the resource you have a lot of, the end nodes (here:
+users), so that the situation actually scales.
+_____________
+
+This means that it is often "cheaper" if QA people or end users can do
+it.
+
+What is interesting too is that end users that are reporting bugs (or
+QA people that reproduced a bug) have access to the environment where
+the bug happens. So they can often more easily reproduce a
+regression. And if they can bisect, then more information will be
+extracted from the environment where the bug happens, which means that
+it will be easier to understand and then fix the bug.
+
+For open source projects it can be a good way to get more useful
+contributions from end users, and to introduce them to QA and
+development activities.
+
+Using complex scripts
+~~~~~~~~~~~~~~~~~~~~~
+
+In some cases like for kernel development it can be worth developing
+complex scripts to be able to fully automate bisecting.
+
+Here is what Ingo Molnar says about that <<7>>:
+
+_____________
+i have a fully automated bootup-hang bisection script. It is based on
+"git-bisect run". I run the script, it builds and boots kernels fully
+automatically, and when the bootup fails (the script notices that via
+the serial log, which it continuously watches - or via a timeout, if
+the system does not come up within 10 minutes it's a "bad" kernel),
+the script raises my attention via a beep and i power cycle the test
+box. (yeah, i should make use of a managed power outlet to 100%
+automate it)
+_____________
+
+Combining test suites, git bisect and other systems together
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We have seen that test suites and git bisect are very powerful when
+used together. It can be even more powerful if you can combine them
+with other systems.
+
+For example some test suites could be run automatically at night with
+some unusual (or even random) configurations. And if a regression is
+found by a test suite, then "git bisect" can be automatically
+launched, and its result can be emailed to the author of the first bad
+commit found by "git bisect", and perhaps other people too. And a new
+entry in the bug tracking system could be automatically created too.
+
+
+The future of bisecting
+-----------------------
+
+"git replace"
+~~~~~~~~~~~~~
+
+We saw earlier that "git bisect skip" is now using a PRNG to try to
+avoid areas in the commit graph where commits are untestable. The
+problem is that sometimes the first bad commit will be in an
+untestable area.
+
+To simplify the discussion we will suppose that the untestable area is
+a simple string of commits and that it was created by a breakage
+introduced by one commit (let's call it BBC for bisect breaking
+commit) and later fixed by another one (let's call it BFC for bisect
+fixing commit).
+
+For example:
+
+-------------
+...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z-...
+-------------
+
+where we know that Y is good and BFC is bad, and where BBC and X1 to
+X6 are untestable.
+
+In this case if you are bisecting manually, what you can do is create
+a special branch that starts just before the BBC. The first commit in
+this branch should be the BBC with the BFC squashed into it. And the
+other commits in the branch should be the commits between BBC and BFC
+rebased on the first commit of the branch and then the commit after
+BFC also rebased on.
+
+For example:
+
+-------------
+      (BBC+BFC)-X1'-X2'-X3'-X4'-X5'-X6'-Z'
+     /
+...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z-...
+-------------
+
+where commits quoted with ' have been rebased.
+
+You can easily create such a branch with Git using interactive rebase.
+
+For example using:
+
+-------------
+$ git rebase -i Y Z
+-------------
+
+and then moving BFC after BBC and squashing it.
+
+After that you can start bisecting as usual in the new branch and you
+should eventually find the first bad commit.
+
+For example:
+
+-------------
+$ git bisect start Z' Y
+-------------
+
+If you are using "git bisect run", you can use the same manual fix up
+as above, and then start another "git bisect run" in the special
+branch. Or as the "git bisect" man page says, the script passed to
+"git bisect run" can apply a patch before it compiles and test the
+software <<8>>. The patch should turn a current untestable commits
+into a testable one. So the testing will result in "good" or "bad" and
+"git bisect" will be able to find the first bad commit. And the script
+should not forget to remove the patch once the testing is done before
+exiting from the script.
+
+(Note that instead of a patch you can use "git cherry-pick BFC" to
+apply the fix, and in this case you should use "git reset --hard
+HEAD^" to revert the cherry-pick after testing and before returning
+from the script.)
+
+But the above ways to work around untestable areas are a little bit
+clunky. Using special branches is nice because these branches can be
+shared by developers like usual branches, but the risk is that people
+will get many such branches. And it disrupts the normal "git bisect"
+work-flow. So, if you want to use "git bisect run" completely
+automatically, you have to add special code in your script to restart
+bisection in the special branches.
+
+Anyway one can notice in the above special branch example that the Z'
+and Z commits should point to the same source code state (the same
+"tree" in git parlance). That's because Z' result from applying the
+same changes as Z just in a slightly different order.
+
+So if we could just "replace" Z by Z' when we bisect, then we would
+not need to add anything to a script. It would just work for anyone in
+the project sharing the special branches and the replacements.
+
+With the example above that would give:
+
+-------------
+      (BBC+BFC)-X1'-X2'-X3'-X4'-X5'-X6'-Z'-...
+     /
+...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z
+-------------
+
+That's why the "git replace" command was created. Technically it
+stores replacements "refs" in the "refs/replace/" hierarchy. These
+"refs" are like branches (that are stored in "refs/heads/") or tags
+(that are stored in "refs/tags"), and that means that they can
+automatically be shared like branches or tags among developers.
+
+"git replace" is a very powerful mechanism. It can be used to fix
+commits in already released history, for example to change the commit
+message or the author. And it can also be used instead of git "grafts"
+to link a repository with another old repository.
+
+In fact it's this last feature that "sold" it to the Git community, so
+it is now in the "master" branch of Git's Git repository and it should
+be released in Git 1.6.5 in October or November 2009.
+
+One problem with "git replace" is that currently it stores all the
+replacements refs in "refs/replace/", but it would be perhaps better
+if the replacement refs that are useful only for bisecting would be in
+"refs/replace/bisect/". This way the replacement refs could be used
+only for bisecting, while other refs directly in "refs/replace/" would
+be used nearly all the time.
+
+Bisecting sporadic bugs
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Another possible improvement to "git bisect" would be to optionally
+add some redundancy to the tests performed so that it would be more
+reliable when tracking sporadic bugs.
+
+This has been requested by some kernel developers because some bugs
+called sporadic bugs do not appear in all the kernel builds because
+they are very dependent on the compiler output.
+
+The idea is that every 3 test for example, "git bisect" could ask the
+user to test a commit that has already been found to be "good" or
+"bad" (because one of its descendants or one of its ancestors has been
+found to be "good" or "bad" respectively). If it happens that a commit
+has been previously incorrectly classified then the bisection can be
+aborted early, hopefully before too many mistakes have been made. Then
+the user will have to look at what happened and then restart the
+bisection using a fixed bisect log.
+
+There is already a project called BBChop created by Ealdwulf Wuffinga
+on Github that does something like that using Bayesian Search Theory
+<<9>>:
+
+_____________
+BBChop is like 'git bisect' (or equivalent), but works when your bug
+is intermittent. That is, it works in the presence of false negatives
+(when a version happens to work this time even though it contains the
+bug). It assumes that there are no false positives (in principle, the
+same approach would work, but adding it may be non-trivial).
+_____________
+
+But BBChop is independent of any VCS and it would be easier for Git
+users to have something integrated in Git.
+
+Conclusion
+----------
+
+We have seen that regressions are an important problem, and that "git
+bisect" has nice features that complement very well practices and
+other tools, especially test suites, that are generally used to fight
+regressions. But it might be needed to change some work-flows and
+(bad) habits to get the most out of it.
+
+Some improvements to the algorithms inside "git bisect" are possible
+and some new features could help in some cases, but overall "git
+bisect" works already very well, is used a lot, and is already very
+useful. To back up that last claim, let's give the final word to Ingo
+Molnar when he was asked by the author how much time does he think
+"git bisect" saves him when he uses it:
+
+_____________
+a _lot_.
+
+About ten years ago did i do my first 'bisection' of a Linux patch
+queue. That was prior the Git (and even prior the BitKeeper) days. I
+literally days spent sorting out patches, creating what in essence
+were standalone commits that i guessed to be related to that bug.
+
+It was a tool of absolute last resort. I'd rather spend days looking
+at printk output than do a manual 'patch bisection'.
+
+With Git bisect it's a breeze: in the best case i can get a ~15 step
+kernel bisection done in 20-30 minutes, in an automated way. Even with
+manual help or when bisecting multiple, overlapping bugs, it's rarely
+more than an hour.
+
+In fact it's invaluable because there are bugs i would never even
+_try_ to debug if it wasn't for git bisect. In the past there were bug
+patterns that were immediately hopeless for me to debug - at best i
+could send the crash/bug signature to lkml and hope that someone else
+can think of something.
+
+And even if a bisection fails today it tells us something valuable
+about the bug: that it's non-deterministic - timing or kernel image
+layout dependent.
+
+So git bisect is unconditional goodness - and feel free to quote that
+;-)
+_____________
+
+Acknowledgments
+---------------
+
+Many thanks to Junio Hamano for his help in reviewing this paper, for
+reviewing the patches I sent to the Git mailing list, for discussing
+some ideas and helping me improve them, for improving "git bisect" a
+lot and for his awesome work in maintaining and developing Git.
+
+Many thanks to Ingo Molnar for giving me very useful information that
+appears in this paper, for commenting on this paper, for his
+suggestions to improve "git bisect" and for evangelizing "git bisect"
+on the linux kernel mailing lists.
+
+Many thanks to Linus Torvalds for inventing, developing and
+evangelizing "git bisect", Git and Linux.
+
+Many thanks to the many other great people who helped one way or
+another when I worked on Git, especially to Andreas Ericsson, Johannes
+Schindelin, H. Peter Anvin, Daniel Barkalow, Bill Lear, John Hawley,
+Shawn O. Pierce, Jeff King, Sam Vilain, Jon Seymour.
+
+Many thanks to the Linux-Kongress program committee for choosing the
+author to given a talk and for publishing this paper.
+
+References
+----------
+
+- [[[1]]] https://web.archive.org/web/20091206032101/http://www.nist.gov/public_affairs/releases/n02-10.htm['Software Errors Cost U.S. Economy $59.5 Billion Annually'. Nist News Release.] See also https://www.nist.gov/system/files/documents/director/planning/report02-3.pdf['The Economic Impacts of Inadequate Infratructure for Software Testing'.  Nist Planning Report 02-3], Executive Summary and Chapter 8.
+- [[[2]]] https://www.oracle.com/java/technologies/javase/codeconventions-introduction.html['Code Conventions for the Java Programming Language: 1. Introduction'. Sun Microsystems.]
+- [[[3]]] https://en.wikipedia.org/wiki/Software_maintenance['Software maintenance'. Wikipedia.]
+- [[[4]]] https://lore.kernel.org/git/7vps5xsbwp.fsf_-_@xxxxxxxxxxxxxxxxxxxxxxxx/[Junio C Hamano. 'Automated bisect success story'.]
+- [[[5]]] https://lwn.net/Articles/317154/[Christian Couder. 'Fully automated bisecting with "git bisect run"'. LWN.net.]
+- [[[6]]] https://lwn.net/Articles/277872/[Jonathan Corbet. 'Bisection divides users and developers'. LWN.net.]
+- [[[7]]] https://lore.kernel.org/lkml/20071207113734.GA14598@xxxxxxx/[Ingo Molnar. 'Re: BUG 2.6.23-rc3 can't see sd partitions on Alpha'. Linux-kernel mailing list.]
+- [[[8]]] https://www.kernel.org/pub/software/scm/git/docs/git-bisect.html[Junio C Hamano and the git-list. 'git-bisect(1) Manual Page'. Linux Kernel Archives.]
+- [[[9]]] https://github.com/Ealdwulf/bbchop[Ealdwulf. 'bbchop'. GitHub.]
diff --git a/Documentation/git-bisect.adoc b/Documentation/git-bisect.adoc
new file mode 100644
index 0000000000..82f944dc03
--- /dev/null
+++ b/Documentation/git-bisect.adoc
@@ -0,0 +1,517 @@
+git-bisect(1)
+=============
+
+NAME
+----
+git-bisect - Use binary search to find the commit that introduced a bug
+
+
+SYNOPSIS
+--------
+[verse]
+'git bisect' <subcommand> <options>
+
+DESCRIPTION
+-----------
+The command takes various subcommands, and different options depending
+on the subcommand:
+
+ git bisect start [--term-(bad|new)=<term-new> --term-(good|old)=<term-old>]
+		  [--no-checkout] [--first-parent] [<bad> [<good>...]] [--] [<pathspec>...]
+ git bisect (bad|new|<term-new>) [<rev>]
+ git bisect (good|old|<term-old>) [<rev>...]
+ git bisect terms [--term-(good|old) | --term-(bad|new)]
+ git bisect skip [(<rev>|<range>)...]
+ git bisect reset [<commit>]
+ git bisect (visualize|view)
+ git bisect replay <logfile>
+ git bisect log
+ git bisect run <cmd> [<arg>...]
+ git bisect help
+
+This command uses a binary search algorithm to find which commit in
+your project's history introduced a bug. You use it by first telling
+it a "bad" commit that is known to contain the bug, and a "good"
+commit that is known to be before the bug was introduced. Then `git
+bisect` picks a commit between those two endpoints and asks you
+whether the selected commit is "good" or "bad". It continues narrowing
+down the range until it finds the exact commit that introduced the
+change.
+
+In fact, `git bisect` can be used to find the commit that changed
+*any* property of your project; e.g., the commit that fixed a bug, or
+the commit that caused a benchmark's performance to improve. To
+support this more general usage, the terms "old" and "new" can be used
+in place of "good" and "bad", or you can choose your own terms. See
+section "Alternate terms" below for more information.
+
+Basic bisect commands: start, bad, good
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+As an example, suppose you are trying to find the commit that broke a
+feature that was known to work in version `v2.6.13-rc2` of your
+project. You start a bisect session as follows:
+
+------------------------------------------------
+$ git bisect start
+$ git bisect bad                 # Current version is bad
+$ git bisect good v2.6.13-rc2    # v2.6.13-rc2 is known to be good
+------------------------------------------------
+
+Once you have specified at least one bad and one good commit, `git
+bisect` selects a commit in the middle of that range of history,
+checks it out, and outputs something similar to the following:
+
+------------------------------------------------
+Bisecting: 675 revisions left to test after this (roughly 10 steps)
+------------------------------------------------
+
+You should now compile the checked-out version and test it. If that
+version works correctly, type
+
+------------------------------------------------
+$ git bisect good
+------------------------------------------------
+
+If that version is broken, type
+
+------------------------------------------------
+$ git bisect bad
+------------------------------------------------
+
+Then `git bisect` will respond with something like
+
+------------------------------------------------
+Bisecting: 337 revisions left to test after this (roughly 9 steps)
+------------------------------------------------
+
+Keep repeating the process: compile the tree, test it, and depending
+on whether it is good or bad run `git bisect good` or `git bisect bad`
+to ask for the next commit that needs testing.
+
+Eventually there will be no more revisions left to inspect, and the
+command will print out a description of the first bad commit. The
+reference `refs/bisect/bad` will be left pointing at that commit.
+
+
+Bisect reset
+~~~~~~~~~~~~
+
+After a bisect session, to clean up the bisection state and return to
+the original HEAD, issue the following command:
+
+------------------------------------------------
+$ git bisect reset
+------------------------------------------------
+
+By default, this will return your tree to the commit that was checked
+out before `git bisect start`.  (A new `git bisect start` will also do
+that, as it cleans up the old bisection state.)
+
+With an optional argument, you can return to a different commit
+instead:
+
+------------------------------------------------
+$ git bisect reset <commit>
+------------------------------------------------
+
+For example, `git bisect reset bisect/bad` will check out the first
+bad revision, while `git bisect reset HEAD` will leave you on the
+current bisection commit and avoid switching commits at all.
+
+
+Alternate terms
+~~~~~~~~~~~~~~~
+
+Sometimes you are not looking for the commit that introduced a
+breakage, but rather for a commit that caused a change between some
+other "old" state and "new" state. For example, you might be looking
+for the commit that introduced a particular fix. Or you might be
+looking for the first commit in which the source-code filenames were
+finally all converted to your company's naming standard. Or whatever.
+
+In such cases it can be very confusing to use the terms "good" and
+"bad" to refer to "the state before the change" and "the state after
+the change". So instead, you can use the terms "old" and "new",
+respectively, in place of "good" and "bad". (But note that you cannot
+mix "good" and "bad" with "old" and "new" in a single session.)
+
+In this more general usage, you provide `git bisect` with a "new"
+commit that has some property and an "old" commit that doesn't have that
+property. Each time `git bisect` checks out a commit, you test if that
+commit has the property. If it does, mark the commit as "new";
+otherwise, mark it as "old". When the bisection is done, `git bisect`
+will report which commit introduced the property.
+
+To use "old" and "new" instead of "good" and bad, you must run `git
+bisect start` without commits as argument and then run the following
+commands to add the commits:
+
+------------------------------------------------
+git bisect old [<rev>]
+------------------------------------------------
+
+to indicate that a commit was before the sought change, or
+
+------------------------------------------------
+git bisect new [<rev>...]
+------------------------------------------------
+
+to indicate that it was after.
+
+To get a reminder of the currently used terms, use
+
+------------------------------------------------
+git bisect terms
+------------------------------------------------
+
+You can get just the old term with `git bisect terms --term-old`
+or `git bisect terms --term-good`; `git bisect terms --term-new`
+and `git bisect terms --term-bad` can be used to learn how to call
+the commits more recent than the sought change.
+
+If you would like to use your own terms instead of "bad"/"good" or
+"new"/"old", you can choose any names you like (except existing bisect
+subcommands like `reset`, `start`, ...) by starting the
+bisection using
+
+------------------------------------------------
+git bisect start --term-old <term-old> --term-new <term-new>
+------------------------------------------------
+
+For example, if you are looking for a commit that introduced a
+performance regression, you might use
+
+------------------------------------------------
+git bisect start --term-old fast --term-new slow
+------------------------------------------------
+
+Or if you are looking for the commit that fixed a bug, you might use
+
+------------------------------------------------
+git bisect start --term-new fixed --term-old broken
+------------------------------------------------
+
+Then, use `git bisect <term-old>` and `git bisect <term-new>` instead
+of `git bisect good` and `git bisect bad` to mark commits.
+
+Bisect visualize/view
+~~~~~~~~~~~~~~~~~~~~~
+
+To see the currently remaining suspects in 'gitk', issue the following
+command during the bisection process (the subcommand `view` can be used
+as an alternative to `visualize`):
+
+------------
+$ git bisect visualize
+------------
+
+Git detects a graphical environment through various environment variables:
+`DISPLAY`, which is set in X Window System environments on Unix systems.
+`SESSIONNAME`, which is set under Cygwin in interactive desktop sessions.
+`MSYSTEM`, which is set under Msys2 and Git for Windows.
+`SECURITYSESSIONID`, which may be set on macOS in interactive desktop sessions.
+
+If none of these environment variables is set, 'git log' is used instead.
+You can also give command-line options such as `-p` and `--stat`.
+
+------------
+$ git bisect visualize --stat
+------------
+
+Bisect log and bisect replay
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+After having marked revisions as good or bad, issue the following
+command to show what has been done so far:
+
+------------
+$ git bisect log
+------------
+
+If you discover that you made a mistake in specifying the status of a
+revision, you can save the output of this command to a file, edit it to
+remove the incorrect entries, and then issue the following commands to
+return to a corrected state:
+
+------------
+$ git bisect reset
+$ git bisect replay that-file
+------------
+
+Avoiding testing a commit
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If, in the middle of a bisect session, you know that the suggested
+revision is not a good one to test (e.g. it fails to build and you
+know that the failure does not have anything to do with the bug you
+are chasing), you can manually select a nearby commit and test that
+one instead.
+
+For example:
+
+------------
+$ git bisect good/bad			# previous round was good or bad.
+Bisecting: 337 revisions left to test after this (roughly 9 steps)
+$ git bisect visualize			# oops, that is uninteresting.
+$ git reset --hard HEAD~3		# try 3 revisions before what
+					# was suggested
+------------
+
+Then compile and test the chosen revision, and afterwards mark
+the revision as good or bad in the usual manner.
+
+Bisect skip
+~~~~~~~~~~~
+
+Instead of choosing a nearby commit by yourself, you can ask Git to do
+it for you by issuing the command:
+
+------------
+$ git bisect skip                 # Current version cannot be tested
+------------
+
+However, if you skip a commit adjacent to the one you are looking for,
+Git will be unable to tell exactly which of those commits was the
+first bad one.
+
+You can also skip a range of commits, instead of just one commit,
+using range notation. For example:
+
+------------
+$ git bisect skip v2.5..v2.6
+------------
+
+This tells the bisect process that no commit after `v2.5`, up to and
+including `v2.6`, should be tested.
+
+Note that if you also want to skip the first commit of the range you
+would issue the command:
+
+------------
+$ git bisect skip v2.5 v2.5..v2.6
+------------
+
+This tells the bisect process that the commits between `v2.5` and
+`v2.6` (inclusive) should be skipped.
+
+
+Cutting down bisection by giving more parameters to bisect start
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can further cut down the number of trials, if you know what part of
+the tree is involved in the problem you are tracking down, by specifying
+pathspec parameters when issuing the `bisect start` command:
+
+------------
+$ git bisect start -- arch/i386 include/asm-i386
+------------
+
+If you know beforehand more than one good commit, you can narrow the
+bisect space down by specifying all of the good commits immediately after
+the bad commit when issuing the `bisect start` command:
+
+------------
+$ git bisect start v2.6.20-rc6 v2.6.20-rc4 v2.6.20-rc1 --
+                   # v2.6.20-rc6 is bad
+                   # v2.6.20-rc4 and v2.6.20-rc1 are good
+------------
+
+Bisect run
+~~~~~~~~~~
+
+If you have a script that can tell if the current source code is good
+or bad, you can bisect by issuing the command:
+
+------------
+$ git bisect run my_script arguments
+------------
+
+Note that the script (`my_script` in the above example) should exit
+with code 0 if the current source code is good/old, and exit with a
+code between 1 and 127 (inclusive), except 125, if the current source
+code is bad/new.
+
+Any other exit code will abort the bisect process. It should be noted
+that a program that terminates via `exit(-1)` leaves $? = 255, (see the
+exit(3) manual page), as the value is chopped with `& 0377`.
+
+The special exit code 125 should be used when the current source code
+cannot be tested. If the script exits with this code, the current
+revision will be skipped (see `git bisect skip` above). 125 was chosen
+as the highest sensible value to use for this purpose, because 126 and 127
+are used by POSIX shells to signal specific error status (127 is for
+command not found, 126 is for command found but not executable--these
+details do not matter, as they are normal errors in the script, as far as
+`bisect run` is concerned).
+
+You may often find that during a bisect session you want to have
+temporary modifications (e.g. s/#define DEBUG 0/#define DEBUG 1/ in a
+header file, or "revision that does not have this commit needs this
+patch applied to work around another problem this bisection is not
+interested in") applied to the revision being tested.
+
+To cope with such a situation, after the inner 'git bisect' finds the
+next revision to test, the script can apply the patch
+before compiling, run the real test, and afterwards decide if the
+revision (possibly with the needed patch) passed the test and then
+rewind the tree to the pristine state.  Finally the script should exit
+with the status of the real test to let the `git bisect run` command loop
+determine the eventual outcome of the bisect session.
+
+OPTIONS
+-------
+--no-checkout::
++
+Do not checkout the new working tree at each iteration of the bisection
+process. Instead just update the reference named `BISECT_HEAD` to make
+it point to the commit that should be tested.
++
+This option may be useful when the test you would perform in each step
+does not require a checked out tree.
++
+If the repository is bare, `--no-checkout` is assumed.
+
+--first-parent::
++
+Follow only the first parent commit upon seeing a merge commit.
++
+In detecting regressions introduced through the merging of a branch, the merge
+commit will be identified as introduction of the bug and its ancestors will be
+ignored.
++
+This option is particularly useful in avoiding false positives when a merged
+branch contained broken or non-buildable commits, but the merge itself was OK.
+
+EXAMPLES
+--------
+
+* Automatically bisect a broken build between v1.2 and HEAD:
++
+------------
+$ git bisect start HEAD v1.2 --      # HEAD is bad, v1.2 is good
+$ git bisect run make                # "make" builds the app
+$ git bisect reset                   # quit the bisect session
+------------
+
+* Automatically bisect a test failure between origin and HEAD:
++
+------------
+$ git bisect start HEAD origin --    # HEAD is bad, origin is good
+$ git bisect run make test           # "make test" builds and tests
+$ git bisect reset                   # quit the bisect session
+------------
+
+* Automatically bisect a broken test case:
++
+------------
+$ cat ~/test.sh
+#!/bin/sh
+make || exit 125                     # this skips broken builds
+~/check_test_case.sh                 # does the test case pass?
+$ git bisect start HEAD HEAD~10 --   # culprit is among the last 10
+$ git bisect run ~/test.sh
+$ git bisect reset                   # quit the bisect session
+------------
++
+Here we use a `test.sh` custom script. In this script, if `make`
+fails, we skip the current commit.
+`check_test_case.sh` should `exit 0` if the test case passes,
+and `exit 1` otherwise.
++
+It is safer if both `test.sh` and `check_test_case.sh` are
+outside the repository to prevent interactions between the bisect,
+make and test processes and the scripts.
+
+* Automatically bisect with temporary modifications (hot-fix):
++
+------------
+$ cat ~/test.sh
+#!/bin/sh
+
+# tweak the working tree by merging the hot-fix branch
+# and then attempt a build
+if	git merge --no-commit --no-ff hot-fix &&
+	make
+then
+	# run project specific test and report its status
+	~/check_test_case.sh
+	status=$?
+else
+	# tell the caller this is untestable
+	status=125
+fi
+
+# undo the tweak to allow clean flipping to the next commit
+git reset --hard
+
+# return control
+exit $status
+------------
++
+This applies modifications from a hot-fix branch before each test run,
+e.g. in case your build or test environment changed so that older
+revisions may need a fix which newer ones have already. (Make sure the
+hot-fix branch is based off a commit which is contained in all revisions
+which you are bisecting, so that the merge does not pull in too much, or
+use `git cherry-pick` instead of `git merge`.)
+
+* Automatically bisect a broken test case:
++
+------------
+$ git bisect start HEAD HEAD~10 --   # culprit is among the last 10
+$ git bisect run sh -c "make || exit 125; ~/check_test_case.sh"
+$ git bisect reset                   # quit the bisect session
+------------
++
+This shows that you can do without a run script if you write the test
+on a single line.
+
+* Locate a good region of the object graph in a damaged repository
++
+------------
+$ git bisect start HEAD <known-good-commit> [ <boundary-commit> ... ] --no-checkout
+$ git bisect run sh -c '
+	GOOD=$(git for-each-ref "--format=%(objectname)" refs/bisect/good-*) &&
+	git rev-list --objects BISECT_HEAD --not $GOOD >tmp.$$ &&
+	git pack-objects --stdout >/dev/null <tmp.$$
+	rc=$?
+	rm -f tmp.$$
+	test $rc = 0'
+
+$ git bisect reset                   # quit the bisect session
+------------
++
+In this case, when 'git bisect run' finishes, bisect/bad will refer to a commit that
+has at least one parent whose reachable graph is fully traversable in the sense
+required by 'git pack objects'.
+
+* Look for a fix instead of a regression in the code
++
+------------
+$ git bisect start
+$ git bisect new HEAD    # current commit is marked as new
+$ git bisect old HEAD~10 # the tenth commit from now is marked as old
+------------
++
+or:
+------------
+$ git bisect start --term-old broken --term-new fixed
+$ git bisect fixed
+$ git bisect broken HEAD~10
+------------
+
+Getting help
+~~~~~~~~~~~~
+
+Use `git bisect` to get a short usage description, and `git bisect
+help` or `git bisect -h` to get a long usage description.
+
+SEE ALSO
+--------
+link:git-bisect-lk2009.html[Fighting regressions with git bisect],
+linkgit:git-blame[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-blame.adoc b/Documentation/git-blame.adoc
new file mode 100644
index 0000000000..0aee813b71
--- /dev/null
+++ b/Documentation/git-blame.adoc
@@ -0,0 +1,257 @@
+git-blame(1)
+============
+
+NAME
+----
+git-blame - Show what revision and author last modified each line of a file
+
+SYNOPSIS
+--------
+[verse]
+'git blame' [-c] [-b] [-l] [--root] [-t] [-f] [-n] [-s] [-e] [-p] [-w] [--incremental]
+	    [-L <range>] [-S <revs-file>] [-M] [-C] [-C] [-C] [--since=<date>]
+	    [--ignore-rev <rev>] [--ignore-revs-file <file>]
+	    [--color-lines] [--color-by-age] [--progress] [--abbrev=<n>]
+	    [ --contents <file> ] [<rev> | --reverse <rev>..<rev>] [--] <file>
+
+DESCRIPTION
+-----------
+
+Annotates each line in the given file with information from the revision which
+last modified the line. Optionally, start annotating from the given revision.
+
+When specified one or more times, `-L` restricts annotation to the requested
+lines.
+
+The origin of lines is automatically followed across whole-file
+renames (currently there is no option to turn the rename-following
+off). To follow lines moved from one file to another, or to follow
+lines that were copied and pasted from another file, etc., see the
+`-C` and `-M` options.
+
+The report does not tell you anything about lines which have been deleted or
+replaced; you need to use a tool such as 'git diff' or the "pickaxe"
+interface briefly mentioned in the following paragraph.
+
+Apart from supporting file annotation, Git also supports searching the
+development history for when a code snippet occurred in a change. This makes it
+possible to track when a code snippet was added to a file, moved or copied
+between files, and eventually deleted or replaced. It works by searching for
+a text string in the diff. A small example of the pickaxe interface
+that searches for `blame_usage`:
+
+-----------------------------------------------------------------------------
+$ git log --pretty=oneline -S'blame_usage'
+5040f17eba15504bad66b14a645bddd9b015ebb7 blame -S <ancestry-file>
+ea4c7f9bf69e781dd0cd88d2bccb2bf5cc15c9a7 git-blame: Make the output
+-----------------------------------------------------------------------------
+
+OPTIONS
+-------
+include::blame-options.adoc[]
+
+-c::
+	Use the same output mode as linkgit:git-annotate[1] (Default: off).
+
+--score-debug::
+	Include debugging information related to the movement of
+	lines between files (see `-C`) and lines moved within a
+	file (see `-M`).  The first number listed is the score.
+	This is the number of alphanumeric characters detected
+	as having been moved between or within files.  This must be above
+	a certain threshold for 'git blame' to consider those lines
+	of code to have been moved.
+
+-f::
+--show-name::
+	Show the filename in the original commit.  By default
+	the filename is shown if there is any line that came from a
+	file with a different name, due to rename detection.
+
+-n::
+--show-number::
+	Show the line number in the original commit (Default: off).
+
+-s::
+	Suppress the author name and timestamp from the output.
+
+-e::
+--show-email::
+	Show the author email instead of the author name (Default: off).
+	This can also be controlled via the `blame.showEmail` config
+	option.
+
+-w::
+	Ignore whitespace when comparing the parent's version and
+	the child's to find where the lines came from.
+
+--abbrev=<n>::
+	Instead of using the default 7+1 hexadecimal digits as the
+	abbreviated object name, use <m>+1 digits, where <m> is at
+	least <n> but ensures the commit object names are unique.
+	Note that 1 column
+	is used for a caret to mark the boundary commit.
+
+
+THE DEFAULT FORMAT
+------------------
+
+When neither `--porcelain` nor `--incremental` option is specified,
+`git blame` will output annotation for each line with:
+
+- abbreviated object name for the commit the line came from;
+- author ident (by default the author name and date, unless `-s` or `-e`
+  is specified); and
+- line number
+
+before the line contents.
+
+THE PORCELAIN FORMAT
+--------------------
+
+In this format, each line is output after a header; the
+header at the minimum has the first line which has:
+
+- 40-byte SHA-1 of the commit the line is attributed to;
+- the line number of the line in the original file;
+- the line number of the line in the final file;
+- on a line that starts a group of lines from a different
+  commit than the previous one, the number of lines in this
+  group.  On subsequent lines this field is absent.
+
+This header line is followed by the following information
+at least once for each commit:
+
+- the author name ("author"), email ("author-mail"), time
+  ("author-time"), and time zone ("author-tz"); similarly
+  for committer.
+- the filename in the commit that the line is attributed to.
+- the first line of the commit log message ("summary").
+
+The contents of the actual line are output after the above
+header, prefixed by a TAB. This is to allow adding more
+header elements later.
+
+The porcelain format generally suppresses commit information that has
+already been seen. For example, two lines that are blamed to the same
+commit will both be shown, but the details for that commit will be shown
+only once. This is more efficient, but may require more state be kept by
+the reader. The `--line-porcelain` option can be used to output full
+commit information for each line, allowing simpler (but less efficient)
+usage like:
+
+	# count the number of lines attributed to each author
+	git blame --line-porcelain file |
+	sed -n 's/^author //p' |
+	sort | uniq -c | sort -rn
+
+
+SPECIFYING RANGES
+-----------------
+
+Unlike 'git blame' and 'git annotate' in older versions of git, the extent
+of the annotation can be limited to both line ranges and revision
+ranges. The `-L` option, which limits annotation to a range of lines, may be
+specified multiple times.
+
+When you are interested in finding the origin for
+lines 40-60 for file `foo`, you can use the `-L` option like so
+(they mean the same thing -- both ask for 21 lines starting at
+line 40):
+
+	git blame -L 40,60 foo
+	git blame -L 40,+21 foo
+
+Also you can use a regular expression to specify the line range:
+
+	git blame -L '/^sub hello {/,/^}$/' foo
+
+which limits the annotation to the body of the `hello` subroutine.
+
+When you are not interested in changes older than version
+v2.6.18, or changes older than 3 weeks, you can use revision
+range specifiers similar to 'git rev-list':
+
+	git blame v2.6.18.. -- foo
+	git blame --since=3.weeks -- foo
+
+When revision range specifiers are used to limit the annotation,
+lines that have not changed since the range boundary (either the
+commit v2.6.18 or the most recent commit that is more than 3
+weeks old in the above example) are blamed for that range
+boundary commit.
+
+A particularly useful way is to see if an added file has lines
+created by copy-and-paste from existing files.  Sometimes this
+indicates that the developer was being sloppy and did not
+refactor the code properly.  You can first find the commit that
+introduced the file with:
+
+	git log --diff-filter=A --pretty=short -- foo
+
+and then annotate the change between the commit and its
+parents, using `commit^!` notation:
+
+	git blame -C -C -f $commit^! -- foo
+
+
+INCREMENTAL OUTPUT
+------------------
+
+When called with `--incremental` option, the command outputs the
+result as it is built.  The output generally will talk about
+lines touched by more recent commits first (i.e. the lines will
+be annotated out of order) and is meant to be used by
+interactive viewers.
+
+The output format is similar to the Porcelain format, but it
+does not contain the actual lines from the file that is being
+annotated.
+
+. Each blame entry always starts with a line of:
+
+	<40-byte-hex-sha1> <sourceline> <resultline> <num-lines>
++
+Line numbers count from 1.
+
+. The first time that a commit shows up in the stream, it has various
+  other information about it printed out with a one-word tag at the
+  beginning of each line describing the extra commit information (author,
+  email, committer, dates, summary, etc.).
+
+. Unlike the Porcelain format, the filename information is always
+  given and terminates the entry:
+
+	"filename" <whitespace-quoted-filename-goes-here>
++
+and thus it is really quite easy to parse for some line- and word-oriented
+parser (which should be quite natural for most scripting languages).
++
+[NOTE]
+For people who do parsing: to make it more robust, just ignore any
+lines between the first and last one ("<sha1>" and "filename" lines)
+where you do not recognize the tag words (or care about that particular
+one) at the beginning of the "extended information" lines. That way, if
+there is ever added information (like the commit encoding or extended
+commit commentary), a blame viewer will not care.
+
+
+MAPPING AUTHORS
+---------------
+
+See linkgit:gitmailmap[5].
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/blame.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-annotate[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-branch.adoc b/Documentation/git-branch.adoc
new file mode 100644
index 0000000000..9c329236b2
--- /dev/null
+++ b/Documentation/git-branch.adoc
@@ -0,0 +1,430 @@
+git-branch(1)
+=============
+
+NAME
+----
+git-branch - List, create, or delete branches
+
+SYNOPSIS
+--------
+[verse]
+'git branch' [--color[=<when>] | --no-color] [--show-current]
+	[-v [--abbrev=<n> | --no-abbrev]]
+	[--column[=<options>] | --no-column] [--sort=<key>]
+	[--merged [<commit>]] [--no-merged [<commit>]]
+	[--contains [<commit>]] [--no-contains [<commit>]]
+	[--points-at <object>] [--format=<format>]
+	[(-r | --remotes) | (-a | --all)]
+	[--list] [<pattern>...]
+'git branch' [--track[=(direct|inherit)] | --no-track] [-f]
+	[--recurse-submodules] <branchname> [<start-point>]
+'git branch' (--set-upstream-to=<upstream> | -u <upstream>) [<branchname>]
+'git branch' --unset-upstream [<branchname>]
+'git branch' (-m | -M) [<oldbranch>] <newbranch>
+'git branch' (-c | -C) [<oldbranch>] <newbranch>
+'git branch' (-d | -D) [-r] <branchname>...
+'git branch' --edit-description [<branchname>]
+
+DESCRIPTION
+-----------
+
+If `--list` is given, or if there are no non-option arguments, existing
+branches are listed; the current branch will be highlighted in green and
+marked with an asterisk.  Any branches checked out in linked worktrees will
+be highlighted in cyan and marked with a plus sign. Option `-r` causes the
+remote-tracking branches to be listed,
+and option `-a` shows both local and remote branches.
+
+If a `<pattern>`
+is given, it is used as a shell wildcard to restrict the output to
+matching branches. If multiple patterns are given, a branch is shown if
+it matches any of the patterns.
+
+Note that when providing a
+`<pattern>`, you must use `--list`; otherwise the command may be interpreted
+as branch creation.
+
+With `--contains`, shows only the branches that contain the named commit
+(in other words, the branches whose tip commits are descendants of the
+named commit), `--no-contains` inverts it. With `--merged`, only branches
+merged into the named commit (i.e. the branches whose tip commits are
+reachable from the named commit) will be listed.  With `--no-merged` only
+branches not merged into the named commit will be listed.  If the <commit>
+argument is missing it defaults to `HEAD` (i.e. the tip of the current
+branch).
+
+The command's second form creates a new branch head named <branchname>
+which points to the current `HEAD`, or <start-point> if given. As a
+special case, for <start-point>, you may use `"A...B"` as a shortcut for
+the merge base of `A` and `B` if there is exactly one merge base. You
+can leave out at most one of `A` and `B`, in which case it defaults to
+`HEAD`.
+
+Note that this will create the new branch, but it will not switch the
+working tree to it; use "git switch <newbranch>" to switch to the
+new branch.
+
+When a local branch is started off a remote-tracking branch, Git sets up the
+branch (specifically the `branch.<name>.remote` and `branch.<name>.merge`
+configuration entries) so that 'git pull' will appropriately merge from
+the remote-tracking branch. This behavior may be changed via the global
+`branch.autoSetupMerge` configuration flag. That setting can be
+overridden by using the `--track` and `--no-track` options, and
+changed later using `git branch --set-upstream-to`.
+
+With a `-m` or `-M` option, <oldbranch> will be renamed to <newbranch>.
+If <oldbranch> had a corresponding reflog, it is renamed to match
+<newbranch>, and a reflog entry is created to remember the branch
+renaming. If <newbranch> exists, -M must be used to force the rename
+to happen.
+
+The `-c` and `-C` options have the exact same semantics as `-m` and
+`-M`, except instead of the branch being renamed, it will be copied to a
+new name, along with its config and reflog.
+
+With a `-d` or `-D` option, `<branchname>` will be deleted.  You may
+specify more than one branch for deletion.  If the branch currently
+has a reflog then the reflog will also be deleted.
+
+Use `-r` together with `-d` to delete remote-tracking branches. Note, that it
+only makes sense to delete remote-tracking branches if they no longer exist
+in the remote repository or if 'git fetch' was configured not to fetch
+them again. See also the 'prune' subcommand of linkgit:git-remote[1] for a
+way to clean up all obsolete remote-tracking branches.
+
+
+OPTIONS
+-------
+-d::
+--delete::
+	Delete a branch. The branch must be fully merged in its
+	upstream branch, or in `HEAD` if no upstream was set with
+	`--track` or `--set-upstream-to`.
+
+-D::
+	Shortcut for `--delete --force`.
+
+--create-reflog::
+	Create the branch's reflog.  This activates recording of
+	all changes made to the branch ref, enabling use of date
+	based sha1 expressions such as "<branchname>@\{yesterday}".
+	Note that in non-bare repositories, reflogs are usually
+	enabled by default by the `core.logAllRefUpdates` config option.
+	The negated form `--no-create-reflog` only overrides an earlier
+	`--create-reflog`, but currently does not negate the setting of
+	`core.logAllRefUpdates`.
+
+-f::
+--force::
+	Reset <branchname> to <start-point>, even if <branchname> exists
+	already. Without `-f`, 'git branch' refuses to change an existing branch.
+	In combination with `-d` (or `--delete`), allow deleting the
+	branch irrespective of its merged status, or whether it even
+	points to a valid commit. In combination with
+	`-m` (or `--move`), allow renaming the branch even if the new
+	branch name already exists, the same applies for `-c` (or `--copy`).
++
+Note that 'git branch -f <branchname> [<start-point>]', even with '-f',
+refuses to change an existing branch `<branchname>` that is checked out
+in another worktree linked to the same repository.
+
+-m::
+--move::
+	Move/rename a branch, together with its config and reflog.
+
+-M::
+	Shortcut for `--move --force`.
+
+-c::
+--copy::
+	Copy a branch, together with its config and reflog.
+
+-C::
+	Shortcut for `--copy --force`.
+
+--color[=<when>]::
+	Color branches to highlight current, local, and
+	remote-tracking branches.
+	The value must be always (the default), never, or auto.
+
+--no-color::
+	Turn off branch colors, even when the configuration file gives the
+	default to color output.
+	Same as `--color=never`.
+
+-i::
+--ignore-case::
+	Sorting and filtering branches are case insensitive.
+
+--omit-empty::
+	Do not print a newline after formatted refs where the format expands
+	to the empty string.
+
+--column[=<options>]::
+--no-column::
+	Display branch listing in columns. See configuration variable
+	`column.branch` for option syntax. `--column` and `--no-column`
+	without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable in non-verbose mode.
+
+-r::
+--remotes::
+	List or delete (if used with -d) the remote-tracking branches.
+	Combine with `--list` to match the optional pattern(s).
+
+-a::
+--all::
+	List both remote-tracking branches and local branches.
+	Combine with `--list` to match optional pattern(s).
+
+-l::
+--list::
+	List branches.  With optional `<pattern>...`, e.g. `git
+	branch --list 'maint-*'`, list only the branches that match
+	the pattern(s).
+
+--show-current::
+	Print the name of the current branch. In detached HEAD state,
+	nothing is printed.
+
+-v::
+-vv::
+--verbose::
+	When in list mode,
+	show sha1 and commit subject line for each head, along with
+	relationship to upstream branch (if any). If given twice, print
+	the path of the linked worktree (if any) and the name of the upstream
+	branch, as well (see also `git remote show <remote>`).  Note that the
+	current worktree's HEAD will not have its path printed (it will always
+	be your current directory).
+
+-q::
+--quiet::
+	Be more quiet when creating or deleting a branch, suppressing
+	non-error messages.
+
+--abbrev=<n>::
+	In the verbose listing that show the commit object name,
+	show the shortest prefix that is at least '<n>' hexdigits
+	long that uniquely refers the object.
+	The default value is 7 and can be overridden by the `core.abbrev`
+	config option.
+
+--no-abbrev::
+	Display the full sha1s in the output listing rather than abbreviating them.
+
+-t::
+--track[=(direct|inherit)]::
+	When creating a new branch, set up `branch.<name>.remote` and
+	`branch.<name>.merge` configuration entries to set "upstream" tracking
+	configuration for the new branch. This
+	configuration will tell git to show the relationship between the
+	two branches in `git status` and `git branch -v`. Furthermore,
+	it directs `git pull` without arguments to pull from the
+	upstream when the new branch is checked out.
++
+The exact upstream branch is chosen depending on the optional argument:
+`-t`, `--track`, or `--track=direct` means to use the start-point branch
+itself as the upstream; `--track=inherit` means to copy the upstream
+configuration of the start-point branch.
++
+The branch.autoSetupMerge configuration variable specifies how `git switch`,
+`git checkout` and `git branch` should behave when neither `--track` nor
+`--no-track` are specified:
++
+The default option, `true`, behaves as though `--track=direct`
+were given whenever the start-point is a remote-tracking branch.
+`false` behaves as if `--no-track` were given. `always` behaves as though
+`--track=direct` were given. `inherit` behaves as though `--track=inherit`
+were given. `simple` behaves as though `--track=direct` were given only when
+the start-point is a remote-tracking branch and the new branch has the same
+name as the remote branch.
++
+See linkgit:git-pull[1] and linkgit:git-config[1] for additional discussion on
+how the `branch.<name>.remote` and `branch.<name>.merge` options are used.
+
+--no-track::
+	Do not set up "upstream" configuration, even if the
+	branch.autoSetupMerge configuration variable is set.
+
+--recurse-submodules::
+	THIS OPTION IS EXPERIMENTAL! Causes the current command to
+	recurse into submodules if `submodule.propagateBranches` is
+	enabled. See `submodule.propagateBranches` in
+	linkgit:git-config[1]. Currently, only branch creation is
+	supported.
++
+When used in branch creation, a new branch <branchname> will be created
+in the superproject and all of the submodules in the superproject's
+<start-point>. In submodules, the branch will point to the submodule
+commit in the superproject's <start-point> but the branch's tracking
+information will be set up based on the submodule's branches and remotes
+e.g. `git branch --recurse-submodules topic origin/main` will create the
+submodule branch "topic" that points to the submodule commit in the
+superproject's "origin/main", but tracks the submodule's "origin/main".
+
+--set-upstream::
+	As this option had confusing syntax, it is no longer supported.
+	Please use `--track` or `--set-upstream-to` instead.
+
+-u <upstream>::
+--set-upstream-to=<upstream>::
+	Set up <branchname>'s tracking information so <upstream> is
+	considered <branchname>'s upstream branch. If no <branchname>
+	is specified, then it defaults to the current branch.
+
+--unset-upstream::
+	Remove the upstream information for <branchname>. If no branch
+	is specified it defaults to the current branch.
+
+--edit-description::
+	Open an editor and edit the text to explain what the branch is
+	for, to be used by various other commands (e.g. `format-patch`,
+	`request-pull`, and `merge` (if enabled)). Multi-line explanations
+	may be used.
+
+--contains [<commit>]::
+	Only list branches which contain the specified commit (HEAD
+	if not specified). Implies `--list`.
+
+--no-contains [<commit>]::
+	Only list branches which don't contain the specified commit
+	(HEAD if not specified). Implies `--list`.
+
+--merged [<commit>]::
+	Only list branches whose tips are reachable from the
+	specified commit (HEAD if not specified). Implies `--list`.
+
+--no-merged [<commit>]::
+	Only list branches whose tips are not reachable from the
+	specified commit (HEAD if not specified). Implies `--list`.
+
+<branchname>::
+	The name of the branch to create or delete.
+	The new branch name must pass all checks defined by
+	linkgit:git-check-ref-format[1].  Some of these checks
+	may restrict the characters allowed in a branch name.
+
+<start-point>::
+	The new branch head will point to this commit.  It may be
+	given as a branch name, a commit-id, or a tag.  If this
+	option is omitted, the current HEAD will be used instead.
+
+<oldbranch>::
+	The name of an existing branch.  If this option is omitted,
+	the name of the current branch will be used instead.
+
+<newbranch>::
+	The new name for an existing branch. The same restrictions as for
+	<branchname> apply.
+
+--sort=<key>::
+	Sort based on the key given. Prefix `-` to sort in descending
+	order of the value. You may use the --sort=<key> option
+	multiple times, in which case the last key becomes the primary
+	key. The keys supported are the same as those in `git
+	for-each-ref`. Sort order defaults to the value configured for the
+	`branch.sort` variable if it exists, or to sorting based on the
+	full refname (including `refs/...` prefix). This lists
+	detached HEAD (if present) first, then local branches and
+	finally remote-tracking branches. See linkgit:git-config[1].
+
+
+--points-at <object>::
+	Only list branches of the given object.
+
+--format <format>::
+	A string that interpolates `%(fieldname)` from a branch ref being shown
+	and the object it points at.  The format is the same as
+	that of linkgit:git-for-each-ref[1].
+
+CONFIGURATION
+-------------
+`pager.branch` is only respected when listing branches, i.e., when
+`--list` is used or implied. The default is to use a pager.
+See linkgit:git-config[1].
+
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/branch.adoc[]
+
+EXAMPLES
+--------
+
+Start development from a known tag::
++
+------------
+$ git clone git://git.kernel.org/pub/scm/.../linux-2.6 my2.6
+$ cd my2.6
+$ git branch my2.6.14 v2.6.14   <1>
+$ git switch my2.6.14
+------------
++
+<1> This step and the next one could be combined into a single step with
+    "checkout -b my2.6.14 v2.6.14".
+
+Delete an unneeded branch::
++
+------------
+$ git clone git://git.kernel.org/.../git.git my.git
+$ cd my.git
+$ git branch -d -r origin/todo origin/html origin/man   <1>
+$ git branch -D test                                    <2>
+------------
++
+<1> Delete the remote-tracking branches "todo", "html" and "man". The next
+    'fetch' or 'pull' will create them again unless you configure them not to.
+    See linkgit:git-fetch[1].
+<2> Delete the "test" branch even if the "master" branch (or whichever branch
+    is currently checked out) does not have all commits from the test branch.
+
+Listing branches from a specific remote::
++
+------------
+$ git branch -r -l '<remote>/<pattern>'                 <1>
+$ git for-each-ref 'refs/remotes/<remote>/<pattern>'    <2>
+------------
++
+<1> Using `-a` would conflate <remote> with any local branches you happen to
+    have been prefixed with the same <remote> pattern.
+<2> `for-each-ref` can take a wide range of options. See linkgit:git-for-each-ref[1]
+
+Patterns will normally need quoting.
+
+NOTES
+-----
+
+If you are creating a branch that you want to switch to immediately,
+it is easier to use the "git switch" command with its `-c` option to
+do the same thing with a single command.
+
+The options `--contains`, `--no-contains`, `--merged` and `--no-merged`
+serve four related but different purposes:
+
+- `--contains <commit>` is used to find all branches which will need
+  special attention if <commit> were to be rebased or amended, since those
+  branches contain the specified <commit>.
+
+- `--no-contains <commit>` is the inverse of that, i.e. branches that don't
+  contain the specified <commit>.
+
+- `--merged` is used to find all branches which can be safely deleted,
+  since those branches are fully contained by HEAD.
+
+- `--no-merged` is used to find branches which are candidates for merging
+  into HEAD, since those branches are not fully contained by HEAD.
+
+include::ref-reachability-filters.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-check-ref-format[1],
+linkgit:git-fetch[1],
+linkgit:git-remote[1],
+link:user-manual.html#what-is-a-branch[``Understanding history: What is
+a branch?''] in the Git User's Manual.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-bugreport.adoc b/Documentation/git-bugreport.adoc
new file mode 100644
index 0000000000..112658b3c3
--- /dev/null
+++ b/Documentation/git-bugreport.adoc
@@ -0,0 +1,77 @@
+git-bugreport(1)
+================
+
+NAME
+----
+git-bugreport - Collect information for user to file a bug report
+
+SYNOPSIS
+--------
+[verse]
+'git bugreport' [(-o | --output-directory) <path>]
+		[(-s | --suffix) <format> | --no-suffix]
+		[--diagnose[=<mode>]]
+
+DESCRIPTION
+-----------
+Collects information about the user's machine, Git client, and repository
+state, in addition to a form requesting information about the behavior the
+user observed, and stores it in a single text file which the user can then
+share, for example to the Git mailing list, in order to report an observed
+bug.
+
+The following information is requested from the user:
+
+ - Reproduction steps
+ - Expected behavior
+ - Actual behavior
+
+The following information is captured automatically:
+
+ - 'git version --build-options'
+ - uname sysname, release, version, and machine strings
+ - Compiler-specific info string
+ - A list of enabled hooks
+ - $SHELL
+
+Additional information may be gathered into a separate zip archive using the
+`--diagnose` option, and can be attached alongside the bugreport document to
+provide additional context to readers.
+
+This tool is invoked via the typical Git setup process, which means that in some
+cases, it might not be able to launch - for example, if a relevant config file
+is unreadable. In this kind of scenario, it may be helpful to manually gather
+the kind of information listed above when manually asking for help.
+
+OPTIONS
+-------
+-o <path>::
+--output-directory <path>::
+	Place the resulting bug report file in `<path>` instead of the current
+	directory.
+
+-s <format>::
+--suffix <format>::
+--no-suffix::
+	Specify an alternate suffix for the bugreport name, to create a file
+	named 'git-bugreport-<formatted-suffix>'. This should take the form of a
+	strftime(3) format string; the current local time will be used.
+	`--no-suffix` disables the suffix and the file is just named
+	`git-bugreport` without any disambiguation measure.
+
+--no-diagnose::
+--diagnose[=<mode>]::
+	Create a zip archive of supplemental information about the user's
+	machine, Git client, and repository state. The archive is written to the
+	same output directory as the bug report and is named
+	'git-diagnostics-<formatted-suffix>'.
++
+Without `mode` specified, the diagnostic archive will contain the default set of
+statistics reported by `git diagnose`. An optional `mode` value may be specified
+to change which information is included in the archive. See
+linkgit:git-diagnose[1] for the list of valid values for `mode` and details
+about their usage.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-bundle.adoc b/Documentation/git-bundle.adoc
new file mode 100644
index 0000000000..03cd36fe8d
--- /dev/null
+++ b/Documentation/git-bundle.adoc
@@ -0,0 +1,372 @@
+git-bundle(1)
+=============
+
+NAME
+----
+git-bundle - Move objects and refs by archive
+
+
+SYNOPSIS
+--------
+[verse]
+'git bundle' create [-q | --quiet | --progress]
+		    [--version=<version>] <file> <git-rev-list-args>
+'git bundle' verify [-q | --quiet] <file>
+'git bundle' list-heads <file> [<refname>...]
+'git bundle' unbundle [--progress] <file> [<refname>...]
+
+DESCRIPTION
+-----------
+
+Create, unpack, and manipulate "bundle" files. Bundles are used for
+the "offline" transfer of Git objects without an active "server"
+sitting on the other side of the network connection.
+
+They can be used to create both incremental and full backups of a
+repository (see the "full backup" example in "EXAMPLES"), and to relay
+the state of the references in one repository to another (see the second
+example).
+
+Git commands that fetch or otherwise "read" via protocols such as
+`ssh://` and `https://` can also operate on bundle files. It is
+possible linkgit:git-clone[1] a new repository from a bundle, to use
+linkgit:git-fetch[1] to fetch from one, and to list the references
+contained within it with linkgit:git-ls-remote[1]. There's no
+corresponding "write" support, i.e. a 'git push' into a bundle is not
+supported.
+
+BUNDLE FORMAT
+-------------
+
+Bundles are `.pack` files (see linkgit:git-pack-objects[1]) with a
+header indicating what references are contained within the bundle.
+
+Like the packed archive format itself bundles can either be
+self-contained, or be created using exclusions.
+See the "OBJECT PREREQUISITES" section below.
+
+Bundles created using revision exclusions are "thin packs" created
+using the `--thin` option to linkgit:git-pack-objects[1], and
+unbundled using the `--fix-thin` option to linkgit:git-index-pack[1].
+
+There is no option to create a "thick pack" when using revision
+exclusions, and users should not be concerned about the difference. By
+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 linkgit:gitformat-bundle[5] for more details and the discussion of
+"thin pack" in linkgit:gitformat-pack[5] for further details.
+
+OPTIONS
+-------
+
+create [options] <file> <git-rev-list-args>::
+	Used to create a bundle named 'file'.  This requires the
+	'<git-rev-list-args>' arguments to define the bundle contents.
+	'options' contains the options specific to the 'git bundle create'
+	subcommand. If 'file' is `-`, the bundle is written to stdout.
+
+verify <file>::
+	Used to check that a bundle file is valid and will apply
+	cleanly to the current repository.  This includes checks on the
+	bundle format itself as well as checking that the prerequisite
+	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 linkgit:gitformat-bundle[5]
+	for more information. The exit code is zero for success, but will
+	be nonzero if the bundle file is invalid. If 'file' is `-`, the
+	bundle is read from stdin.
+
+list-heads <file>::
+	Lists the references defined in the bundle.  If followed by a
+	list of references, only references matching those given are
+	printed out. If 'file' is `-`, the bundle is read from stdin.
+
+unbundle <file>::
+	Passes the objects in the bundle to 'git index-pack'
+	for storage in the repository, then prints the names of all
+	defined references. If a list of references is given, only
+	references matching those in the list are printed. This command is
+	really plumbing, intended to be called only by 'git fetch'.
+	If 'file' is `-`, the bundle is read from stdin.
+
+<git-rev-list-args>::
+	A list of arguments, acceptable to 'git rev-parse' and
+	'git rev-list' (and containing a named ref, see SPECIFYING REFERENCES
+	below), that specifies the specific objects and references
+	to transport.  For example, `master~10..master` causes the
+	current master reference to be packaged along with all objects
+	added since its 10th ancestor commit.  There is no explicit
+	limit to the number of references and objects that may be
+	packaged.
+
+
+[<refname>...]::
+	A list of references used to limit the references reported as
+	available. This is principally of use to 'git fetch', which
+	expects to receive only those references asked for and not
+	necessarily everything in the pack (in this case, 'git bundle' acts
+	like 'git fetch-pack').
+
+--progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless -q
+	is specified. This flag forces progress status even if
+	the standard error stream is not directed to a terminal.
+
+--version=<version>::
+	Specify the bundle version.  Version 2 is the older format and can only be
+	used with SHA-1 repositories; the newer version 3 contains capabilities that
+	permit extensions. The default is the oldest supported format, based on the
+	hash algorithm in use.
+
+-q::
+--quiet::
+	This flag makes the command not to report its progress
+	on the standard error stream.
+
+SPECIFYING REFERENCES
+---------------------
+
+Revisions must be accompanied by reference names to be packaged in a
+bundle.  Alternatively `--all` can be used to package all refs.
+
+More than one reference may be packaged, and more than one set of prerequisite objects can
+be specified.  The objects packaged are those not contained in the
+union of the prerequisites.
+
+The 'git bundle create' command resolves the reference names for you
+using the same rules as `git rev-parse --abbrev-ref=loose`. Each
+prerequisite can be specified explicitly (e.g. `^master~10`), or implicitly
+(e.g. `master~10..master`, `--since=10.days.ago master`).
+
+All of these simple cases are OK (assuming we have a "master" and
+"next" branch):
+
+----------------
+$ git bundle create master.bundle master
+$ echo master | git bundle create master.bundle --stdin
+$ git bundle create master-and-next.bundle master next
+$ (echo master; echo next) | git bundle create master-and-next.bundle --stdin
+----------------
+
+And so are these (and the same but omitted `--stdin` examples):
+
+----------------
+$ git bundle create recent-master.bundle master~10..master
+$ git bundle create recent-updates.bundle master~10..master next~5..next
+----------------
+
+A revision name or a range whose right-hand-side cannot be resolved to
+a reference is not accepted:
+
+----------------
+$ git bundle create HEAD.bundle $(git rev-parse HEAD)
+fatal: Refusing to create empty bundle.
+$ git bundle create master-yesterday.bundle master~10..master~5
+fatal: Refusing to create empty bundle.
+----------------
+
+OBJECT PREREQUISITES
+--------------------
+
+When creating bundles it is possible to create a self-contained bundle
+that can be unbundled in a repository with no common history, as well
+as providing negative revisions to exclude objects needed in the
+earlier parts of the history.
+
+Feeding a revision such as `new` to `git bundle create` will create a
+bundle file that contains all the objects reachable from the revision
+`new`. That bundle can be unbundled in any repository to obtain a full
+history that leads to the revision `new`:
+
+----------------
+$ git bundle create full.bundle new
+----------------
+
+A revision range such as `old..new` will produce a bundle file that
+will require the revision `old` (and any objects reachable from it)
+to exist for the bundle to be "unbundle"-able:
+
+----------------
+$ git bundle create full.bundle old..new
+----------------
+
+A self-contained bundle without any prerequisites can be extracted
+into anywhere, even into an empty repository, or be cloned from
+(i.e., `new`, but not `old..new`).
+
+It is okay to err on the side of caution, causing the bundle file
+to contain objects already in the destination, as these are ignored
+when unpacking at the destination.
+
+If you want to provide the same set of refs that a clone directly
+from the source repository would get, use `--branches --tags` for
+the `<git-rev-list-args>`.
+
+The 'git bundle verify' command can be used to check whether your
+recipient repository has the required prerequisite commits for a
+bundle.
+
+EXAMPLES
+--------
+
+We'll discuss two cases:
+
+1. Taking a full backup of a repository
+2. Transferring the history of a repository to another machine when the
+   two machines have no direct connection
+
+First let's consider a full backup of the repository.  The following
+command will take a full backup of the repository in the sense that all
+refs are included in the bundle:
+
+----------------
+$ git bundle create backup.bundle --all
+----------------
+
+But note again that this is only for the refs, i.e. you will only
+include refs and commits reachable from those refs.  You will not
+include other local state, such as the contents of the index, working
+tree, the stash, per-repository configuration, hooks, etc.
+
+You can later recover that repository by using for example
+linkgit:git-clone[1]:
+
+----------------
+$ git clone backup.bundle <new directory>
+----------------
+
+For the next example, assume you want to transfer the history from a
+repository R1 on machine A to another repository R2 on machine B.
+For whatever reason, direct connection between A and B is not allowed,
+but we can move data from A to B via some mechanism (CD, email, etc.).
+We want to update R2 with development made on the branch master in R1.
+
+To bootstrap the process, you can first create a bundle that does not have
+any prerequisites. You can use a tag to remember up to what commit you last
+processed, in order to make it easy to later update the other repository
+with an incremental bundle:
+
+----------------
+machineA$ cd R1
+machineA$ git bundle create file.bundle master
+machineA$ git tag -f lastR2bundle master
+----------------
+
+Then you transfer file.bundle to the target machine B. Because this
+bundle does not require any existing object to be extracted, you can
+create a new repository on machine B by cloning from it:
+
+----------------
+machineB$ git clone -b master /home/me/tmp/file.bundle R2
+----------------
+
+This will define a remote called "origin" in the resulting repository that
+lets you fetch and pull from the bundle. The $GIT_DIR/config file in R2 will
+have an entry like this:
+
+------------------------
+[remote "origin"]
+    url = /home/me/tmp/file.bundle
+    fetch = refs/heads/*:refs/remotes/origin/*
+------------------------
+
+To update the resulting mine.git repository, you can fetch or pull after
+replacing the bundle stored at /home/me/tmp/file.bundle with incremental
+updates.
+
+After working some more in the original repository, you can create an
+incremental bundle to update the other repository:
+
+----------------
+machineA$ cd R1
+machineA$ git bundle create file.bundle lastR2bundle..master
+machineA$ git tag -f lastR2bundle master
+----------------
+
+You then transfer the bundle to the other machine to replace
+/home/me/tmp/file.bundle, and pull from it.
+
+----------------
+machineB$ cd R2
+machineB$ git pull
+----------------
+
+If you know up to what commit the intended recipient repository should
+have the necessary objects, you can use that knowledge to specify the
+prerequisites, giving a cut-off point to limit the revisions and objects that go
+in the resulting bundle. The previous example used the lastR2bundle tag
+for this purpose, but you can use any other options that you would give to
+the linkgit:git-log[1] command. Here are more examples:
+
+You can use a tag that is present in both:
+
+----------------
+$ git bundle create mybundle v1.0.0..master
+----------------
+
+You can use a prerequisite based on time:
+
+----------------
+$ git bundle create mybundle --since=10.days master
+----------------
+
+You can use the number of commits:
+
+----------------
+$ git bundle create mybundle -10 master
+----------------
+
+You can run `git-bundle verify` to see if you can extract from a bundle
+that was created with a prerequisite:
+
+----------------
+$ git bundle verify mybundle
+----------------
+
+This will list what commits you must have in order to extract from the
+bundle and will error out if you do not have them.
+
+A bundle from a recipient repository's point of view is just like a
+regular repository which it fetches or pulls from. You can, for example, map
+references when fetching:
+
+----------------
+$ git fetch mybundle master:localRef
+----------------
+
+You can also see what references it offers:
+
+----------------
+$ git ls-remote mybundle
+----------------
+
+DISCUSSION
+----------
+
+A naive way to make a full backup of a repository is to use something to
+the effect of `cp -r <repo> <destination>`.  This is discouraged since
+the repository could be written to during the copy operation.  In turn
+some files at `<destination>` could be corrupted.
+
+This is why it is recommended to use Git tooling for making repository
+backups, either with this command or with e.g. linkgit:git-clone[1].
+But keep in mind that these tools will not help you backup state other
+than refs and commits.  In other words they will not help you backup
+contents of the index, working tree, the stash, per-repository
+configuration, hooks, etc.
+
+See also linkgit:gitfaq[7], section "TRANSFERS" for a discussion of the
+problems associated with file syncing across systems.
+
+FILE FORMAT
+-----------
+
+See linkgit:gitformat-bundle[5].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cat-file.adoc b/Documentation/git-cat-file.adoc
new file mode 100644
index 0000000000..d5890ae368
--- /dev/null
+++ b/Documentation/git-cat-file.adoc
@@ -0,0 +1,412 @@
+git-cat-file(1)
+===============
+
+NAME
+----
+git-cat-file - Provide contents or details of repository objects
+
+SYNOPSIS
+--------
+[verse]
+'git cat-file' <type> <object>
+'git cat-file' (-e | -p) <object>
+'git cat-file' (-t | -s) [--allow-unknown-type] <object>
+'git cat-file' (--textconv | --filters)
+	     [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]
+'git cat-file' (--batch | --batch-check | --batch-command) [--batch-all-objects]
+	     [--buffer] [--follow-symlinks] [--unordered]
+	     [--textconv | --filters] [-Z]
+
+DESCRIPTION
+-----------
+Output the contents or other properties such as size, type or delta
+information of one or more objects.
+
+This command can operate in two modes, depending on whether an option
+from the `--batch` family is specified.
+
+In non-batch mode, the command provides information on an object
+named on the command line.
+
+In batch mode, arguments are read from standard input.
+
+OPTIONS
+-------
+<object>::
+	The name of the object to show.
+	For a more complete list of ways to spell object names, see
+	the "SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
+
+-t::
+	Instead of the content, show the object type identified by
+	`<object>`.
+
+-s::
+	Instead of the content, show the object size identified by
+	`<object>`. If used with `--use-mailmap` option, will show
+	the size of updated object after replacing idents using the
+	mailmap mechanism.
+
+-e::
+	Exit with zero status if `<object>` exists and is a valid
+	object. If `<object>` is of an invalid format, exit with non-zero
+	status and emit an error on stderr.
+
+-p::
+	Pretty-print the contents of `<object>` based on its type.
+
+<type>::
+	Typically this matches the real type of `<object>` but asking
+	for a type that can trivially be dereferenced from the given
+	`<object>` is also permitted.  An example is to ask for a
+	"tree" with `<object>` being a commit object that contains it,
+	or to ask for a "blob" with `<object>` being a tag object that
+	points at it.
+
+--[no-]mailmap::
+--[no-]use-mailmap::
+       Use mailmap file to map author, committer and tagger names
+       and email addresses to canonical real names and email addresses.
+       See linkgit:git-shortlog[1].
+
+--textconv::
+	Show the content as transformed by a textconv filter. In this case,
+	`<object>` has to be of the form `<tree-ish>:<path>`, or `:<path>` in
+	order to apply the filter to the content recorded in the index at
+	`<path>`.
+
+--filters::
+	Show the content as converted by the filters configured in
+	the current working tree for the given `<path>` (i.e. smudge filters,
+	end-of-line conversion, etc). In this case, `<object>` has to be of
+	the form `<tree-ish>:<path>`, or `:<path>`.
+
+--path=<path>::
+	For use with `--textconv` or `--filters`, to allow specifying an object
+	name and a path separately, e.g. when it is difficult to figure out
+	the revision from which the blob came.
+
+--batch::
+--batch=<format>::
+	Print object information and contents for each object provided
+	on stdin. May not be combined with any other options or arguments
+	except `--textconv`, `--filters`, or `--use-mailmap`.
++
+--
+	* When used with `--textconv` or `--filters`, the input lines
+	  must specify the path, separated by whitespace. See the section
+	  `BATCH OUTPUT` below for details.
+
+	* When used with `--use-mailmap`, for commit and tag objects, the
+	  contents part of the output shows the identities replaced using the
+	  mailmap mechanism, while the information part of the output shows
+	  the size of the object as if it actually recorded the replacement
+	  identities.
+--
+
+--batch-check::
+--batch-check=<format>::
+	Print object information for each object provided on stdin. May not be
+	combined with any other options or arguments except `--textconv`, `--filters`
+	or `--use-mailmap`.
++
+--
+	* When used with `--textconv` or `--filters`, the input lines must
+	 specify the path, separated by whitespace. See the section
+	 `BATCH OUTPUT` below for details.
+
+	* When used with `--use-mailmap`, for commit and tag objects, the
+	  printed object information shows the size of the object as if the
+	  identities recorded in it were replaced by the mailmap mechanism.
+--
+
+--batch-command::
+--batch-command=<format>::
+	Enter a command mode that reads commands and arguments from stdin. May
+	only be combined with `--buffer`, `--textconv`, `--use-mailmap` or
+	`--filters`.
++
+--
+	* When used with `--textconv` or `--filters`, the input lines must
+	  specify the path, separated by whitespace. See the section
+	  `BATCH OUTPUT` below for details.
+
+	* When used with `--use-mailmap`, for commit and tag objects, the
+	  `contents` command shows the identities replaced using the
+	  mailmap mechanism, while the `info` command shows the size
+	  of the object as if it actually recorded the replacement
+	  identities.
+--
++
+`--batch-command` recognizes the following commands:
++
+--
+contents <object>::
+	Print object contents for object reference `<object>`. This corresponds to
+	the output of `--batch`.
+
+info <object>::
+	Print object info for object reference `<object>`. This corresponds to the
+	output of `--batch-check`.
+
+flush::
+	Used with `--buffer` to execute all preceding commands that were issued
+	since the beginning or since the last flush was issued. When `--buffer`
+	is used, no output will come until a `flush` is issued. When `--buffer`
+	is not used, commands are flushed each time without issuing `flush`.
+--
++
+
+--batch-all-objects::
+	Instead of reading a list of objects on stdin, perform the
+	requested batch operation on all objects in the repository and
+	any alternate object stores (not just reachable objects).
+	Requires `--batch` or `--batch-check` be specified. By default,
+	the objects are visited in order sorted by their hashes; see
+	also `--unordered` below. Objects are presented as-is, without
+	respecting the "replace" mechanism of linkgit:git-replace[1].
+
+--buffer::
+	Normally batch output is flushed after each object is output, so
+	that a process can interactively read and write from
+	`cat-file`. With this option, the output uses normal stdio
+	buffering; this is much more efficient when invoking
+	`--batch-check` or `--batch-command` on a large number of objects.
+
+--unordered::
+	When `--batch-all-objects` is in use, visit objects in an
+	order which may be more efficient for accessing the object
+	contents than hash order. The exact details of the order are
+	unspecified, but if you do not require a specific order, this
+	should generally result in faster output, especially with
+	`--batch`.  Note that `cat-file` will still show each object
+	only once, even if it is stored multiple times in the
+	repository.
+
+--allow-unknown-type::
+	Allow `-s` or `-t` to query broken/corrupt objects of unknown type.
+
+--follow-symlinks::
+	With `--batch` or `--batch-check`, follow symlinks inside the
+	repository when requesting objects with extended SHA-1
+	expressions of the form tree-ish:path-in-tree.  Instead of
+	providing output about the link itself, provide output about
+	the linked-to object.  If a symlink points outside the
+	tree-ish (e.g. a link to `/foo` or a root-level link to `../foo`),
+	the portion of the link which is outside the tree will be
+	printed.
++
+This option does not (currently) work correctly when an object in the
+index is specified (e.g. `:link` instead of `HEAD:link`) rather than
+one in the tree.
++
+This option cannot (currently) be used unless `--batch` or
+`--batch-check` is used.
++
+For example, consider a git repository containing:
++
+--
+	f: a file containing "hello\n"
+	link: a symlink to f
+	dir/link: a symlink to ../f
+	plink: a symlink to ../f
+	alink: a symlink to /etc/passwd
+--
++
+For a regular file `f`, `echo HEAD:f | git cat-file --batch` would print
++
+--
+	ce013625030ba8dba906f756967f9e9ca394464a blob 6
+--
++
+And `echo HEAD:link | git cat-file --batch --follow-symlinks` would
+print the same thing, as would `HEAD:dir/link`, as they both point at
+`HEAD:f`.
++
+Without `--follow-symlinks`, these would print data about the symlink
+itself.  In the case of `HEAD:link`, you would see
++
+--
+	4d1ae35ba2c8ec712fa2a379db44ad639ca277bd blob 1
+--
++
+Both `plink` and `alink` point outside the tree, so they would
+respectively print:
++
+--
+	symlink 4
+	../f
+
+	symlink 11
+	/etc/passwd
+--
+
+-Z::
+	Only meaningful with `--batch`, `--batch-check`, or
+	`--batch-command`; input and output is NUL-delimited instead of
+	newline-delimited.
+
+-z::
+	Only meaningful with `--batch`, `--batch-check`, or
+	`--batch-command`; input is NUL-delimited instead of
+	newline-delimited. This option is deprecated in favor of
+	`-Z` as the output can otherwise be ambiguous.
+
+
+OUTPUT
+------
+If `-t` is specified, one of the `<type>`.
+
+If `-s` is specified, the size of the `<object>` in bytes.
+
+If `-e` is specified, no output, unless the `<object>` is malformed.
+
+If `-p` is specified, the contents of `<object>` are pretty-printed.
+
+If `<type>` is specified, the raw (though uncompressed) contents of the `<object>`
+will be returned.
+
+BATCH OUTPUT
+------------
+
+If `--batch` or `--batch-check` is given, `cat-file` will read objects
+from stdin, one per line, and print information about them in the same
+order as they have been read. By default, the whole line is
+considered as an object, as if it were fed to linkgit:git-rev-parse[1].
+
+When `--batch-command` is given, `cat-file` will read commands from stdin,
+one per line, and print information based on the command given. With
+`--batch-command`, the `info` command followed by an object will print
+information about the object the same way `--batch-check` would, and the
+`contents` command followed by an object prints contents in the same way
+`--batch` would.
+
+You can specify the information shown for each object by using a custom
+`<format>`. The `<format>` is copied literally to stdout for each
+object, with placeholders of the form `%(atom)` expanded, followed by a
+newline. The available atoms are:
+
+`objectname`::
+	The full hex representation of the object name.
+
+`objecttype`::
+	The type of the object (the same as `cat-file -t` reports).
+
+`objectsize`::
+	The size, in bytes, of the object (the same as `cat-file -s`
+	reports).
+
+`objectsize:disk`::
+	The size, in bytes, that the object takes up on disk. See the
+	note about on-disk sizes in the `CAVEATS` section below.
+
+`deltabase`::
+	If the object is stored as a delta on-disk, this expands to the
+	full hex representation of the delta base object name.
+	Otherwise, expands to the null OID (all zeroes). See `CAVEATS`
+	below.
+
+`rest`::
+	If this atom is used in the output string, input lines are split
+	at the first whitespace boundary. All characters before that
+	whitespace are considered to be the object name; characters
+	after that first run of whitespace (i.e., the "rest" of the
+	line) are output in place of the `%(rest)` atom.
+
+If no format is specified, the default format is `%(objectname)
+%(objecttype) %(objectsize)`.
+
+If `--batch` is specified, or if `--batch-command` is used with the `contents`
+command, the object information is followed by the object contents (consisting
+of `%(objectsize)` bytes), followed by a newline.
+
+For example, `--batch` without a custom format would produce:
+
+------------
+<oid> SP <type> SP <size> LF
+<contents> LF
+------------
+
+Whereas `--batch-check='%(objectname) %(objecttype)'` would produce:
+
+------------
+<oid> SP <type> LF
+------------
+
+If a name is specified on stdin that cannot be resolved to an object in
+the repository, then `cat-file` will ignore any custom format and print:
+
+------------
+<object> SP missing LF
+------------
+
+If a name is specified that might refer to more than one object (an ambiguous short sha), then `cat-file` will ignore any custom format and print:
+
+------------
+<object> SP ambiguous LF
+------------
+
+If `--follow-symlinks` is used, and a symlink in the repository points
+outside the repository, then `cat-file` will ignore any custom format
+and print:
+
+------------
+symlink SP <size> LF
+<symlink> LF
+------------
+
+The symlink will either be absolute (beginning with a `/`), or relative
+to the tree root.  For instance, if dir/link points to `../../foo`, then
+`<symlink>` will be `../foo`.  `<size>` is the size of the symlink in bytes.
+
+If `--follow-symlinks` is used, the following error messages will be
+displayed:
+
+------------
+<object> SP missing LF
+------------
+is printed when the initial symlink requested does not exist.
+
+------------
+dangling SP <size> LF
+<object> LF
+------------
+is printed when the initial symlink exists, but something that
+it (transitive-of) points to does not.
+
+------------
+loop SP <size> LF
+<object> LF
+------------
+is printed for symlink loops (or any symlinks that
+require more than 40 link resolutions to resolve).
+
+------------
+notdir SP <size> LF
+<object> LF
+------------
+is printed when, during symlink resolution, a file is used as a
+directory name.
+
+Alternatively, when `-Z` is passed, the line feeds in any of the above examples
+are replaced with NUL terminators. This ensures that output will be parsable if
+the output itself would contain a linefeed and is thus recommended for
+scripting purposes.
+
+CAVEATS
+-------
+
+Note that the sizes of objects on disk are reported accurately, but care
+should be taken in drawing conclusions about which refs or objects are
+responsible for disk usage. The size of a packed non-delta object may be
+much larger than the size of objects which delta against it, but the
+choice of which object is the base and which is the delta is arbitrary
+and is subject to change during a repack.
+
+Note also that multiple copies of an object may be present in the object
+database; in this case, it is undefined which copy's size or delta base
+will be reported.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-check-attr.adoc b/Documentation/git-check-attr.adoc
new file mode 100644
index 0000000000..cb5a6c8f33
--- /dev/null
+++ b/Documentation/git-check-attr.adoc
@@ -0,0 +1,125 @@
+git-check-attr(1)
+=================
+
+NAME
+----
+git-check-attr - Display gitattributes information
+
+
+SYNOPSIS
+--------
+[verse]
+'git check-attr' [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>...
+'git check-attr' --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]
+
+DESCRIPTION
+-----------
+For every pathname, this command will list if each attribute is 'unspecified',
+'set', or 'unset' as a gitattribute on that pathname.
+
+OPTIONS
+-------
+-a, --all::
+	List all attributes that are associated with the specified
+	paths.  If this option is used, then 'unspecified' attributes
+	will not be included in the output.
+
+--cached::
+	Consider `.gitattributes` in the index only, ignoring the working tree.
+
+--stdin::
+	Read pathnames from the standard input, one per line,
+	instead of from the command line.
+
+-z::
+	The output format is modified to be machine-parsable.
+	If `--stdin` is also given, input paths are separated
+	with a NUL character instead of a linefeed character.
+
+--source=<tree-ish>::
+	Check attributes against the specified tree-ish. It is common to
+	specify the source tree by naming a commit, branch, or tag associated
+	with it.
+
+\--::
+	Interpret all preceding arguments as attributes and all following
+	arguments as path names.
+
+If none of `--stdin`, `--all`, or `--` is used, the first argument
+will be treated as an attribute and the rest of the arguments as
+pathnames.
+
+OUTPUT
+------
+
+The output is of the form:
+<path> COLON SP <attribute> COLON SP <info> LF
+
+unless `-z` is in effect, in which case NUL is used as delimiter:
+<path> NUL <attribute> NUL <info> NUL
+
+
+<path> is the path of a file being queried, <attribute> is an attribute
+being queried, and <info> can be either:
+
+'unspecified';; when the attribute is not defined for the path.
+'unset';;	when the attribute is defined as false.
+'set';;		when the attribute is defined as true.
+<value>;;	when a value has been assigned to the attribute.
+
+Buffering happens as documented under the `GIT_FLUSH` option in
+linkgit:git[1].  The caller is responsible for avoiding deadlocks
+caused by overfilling an input buffer or reading from an empty output
+buffer.
+
+EXAMPLES
+--------
+
+In the examples, the following '.gitattributes' file is used:
+---------------
+*.java diff=java -crlf myAttr
+NoMyAttr.java !myAttr
+README caveat=unspecified
+---------------
+
+* Listing a single attribute:
+---------------
+$ git check-attr diff org/example/MyClass.java
+org/example/MyClass.java: diff: java
+---------------
+
+* Listing multiple attributes for a file:
+---------------
+$ git check-attr crlf diff myAttr -- org/example/MyClass.java
+org/example/MyClass.java: crlf: unset
+org/example/MyClass.java: diff: java
+org/example/MyClass.java: myAttr: set
+---------------
+
+* Listing all attributes for a file:
+---------------
+$ git check-attr --all -- org/example/MyClass.java
+org/example/MyClass.java: diff: java
+org/example/MyClass.java: myAttr: set
+---------------
+
+* Listing an attribute for multiple files:
+---------------
+$ git check-attr myAttr -- org/example/MyClass.java org/example/NoMyAttr.java
+org/example/MyClass.java: myAttr: set
+org/example/NoMyAttr.java: myAttr: unspecified
+---------------
+
+* Not all values are equally unambiguous:
+---------------
+$ git check-attr caveat README
+README: caveat: unspecified
+---------------
+
+SEE ALSO
+--------
+linkgit:gitattributes[5].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-check-ignore.adoc b/Documentation/git-check-ignore.adoc
new file mode 100644
index 0000000000..3e3b4e3446
--- /dev/null
+++ b/Documentation/git-check-ignore.adoc
@@ -0,0 +1,126 @@
+git-check-ignore(1)
+===================
+
+NAME
+----
+git-check-ignore - Debug gitignore / exclude files
+
+
+SYNOPSIS
+--------
+[verse]
+'git check-ignore' [<options>] <pathname>...
+'git check-ignore' [<options>] --stdin
+
+DESCRIPTION
+-----------
+
+For each pathname given via the command-line or from a file via
+`--stdin`, check whether the file is excluded by .gitignore (or other
+input files to the exclude mechanism) and output the path if it is
+excluded.
+
+By default, tracked files are not shown at all since they are not
+subject to exclude rules; but see `--no-index'.
+
+OPTIONS
+-------
+-q, --quiet::
+	Don't output anything, just set exit status.  This is only
+	valid with a single pathname.
+
+-v, --verbose::
+	Instead of printing the paths that are excluded, for each path
+	that matches an exclude pattern, print the exclude pattern
+	together with the path.  (Matching an exclude pattern usually
+	means the path is excluded, but if the pattern begins with "`!`"
+	then it is a negated pattern and matching it means the path is
+	NOT excluded.)
++
+For precedence rules within and between exclude sources, see
+linkgit:gitignore[5].
+
+--stdin::
+	Read pathnames from the standard input, one per line,
+	instead of from the command-line.
+
+-z::
+	The output format is modified to be machine-parsable (see
+	below).  If `--stdin` is also given, input paths are separated
+	with a NUL character instead of a linefeed character.
+
+-n, --non-matching::
+	Show given paths which don't match any pattern.  This only
+	makes sense when `--verbose` is enabled, otherwise it would
+	not be possible to distinguish between paths which match a
+	pattern and those which don't.
+
+--no-index::
+	Don't look in the index when undertaking the checks. This can
+	be used to debug why a path became tracked by e.g. `git add .`
+	and was not ignored by the rules as expected by the user or when
+	developing patterns including negation to match a path previously
+	added with `git add -f`.
+
+OUTPUT
+------
+
+By default, any of the given pathnames which match an ignore pattern
+will be output, one per line.  If no pattern matches a given path,
+nothing will be output for that path; this means that path will not be
+ignored.
+
+If `--verbose` is specified, the output is a series of lines of the form:
+
+<source> <COLON> <linenum> <COLON> <pattern> <HT> <pathname>
+
+<pathname> is the path of a file being queried, <pattern> is the
+matching pattern, <source> is the pattern's source file, and <linenum>
+is the line number of the pattern within that source.  If the pattern
+contained a "`!`" prefix or "`/`" suffix, it will be preserved in the
+output.  <source> will be an absolute path when referring to the file
+configured by `core.excludesFile`, or relative to the repository root
+when referring to `.git/info/exclude` or a per-directory exclude file.
+
+If `-z` is specified, the pathnames in the output are delimited by the
+null character; if `--verbose` is also specified then null characters
+are also used instead of colons and hard tabs:
+
+<source> <NULL> <linenum> <NULL> <pattern> <NULL> <pathname> <NULL>
+
+If `-n` or `--non-matching` are specified, non-matching pathnames will
+also be output, in which case all fields in each output record except
+for <pathname> will be empty.  This can be useful when running
+non-interactively, so that files can be incrementally streamed to
+STDIN of a long-running check-ignore process, and for each of these
+files, STDOUT will indicate whether that file matched a pattern or
+not.  (Without this option, it would be impossible to tell whether the
+absence of output for a given file meant that it didn't match any
+pattern, or that the output hadn't been generated yet.)
+
+Buffering happens as documented under the `GIT_FLUSH` option in
+linkgit:git[1].  The caller is responsible for avoiding deadlocks
+caused by overfilling an input buffer or reading from an empty output
+buffer.
+
+EXIT STATUS
+-----------
+
+0::
+	One or more of the provided paths is ignored.
+
+1::
+	None of the provided paths are ignored.
+
+128::
+	A fatal error was encountered.
+
+SEE ALSO
+--------
+linkgit:gitignore[5]
+linkgit:git-config[1]
+linkgit:git-ls-files[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-check-mailmap.adoc b/Documentation/git-check-mailmap.adoc
new file mode 100644
index 0000000000..966c91c46a
--- /dev/null
+++ b/Documentation/git-check-mailmap.adoc
@@ -0,0 +1,64 @@
+git-check-mailmap(1)
+====================
+
+NAME
+----
+git-check-mailmap - Show canonical names and email addresses of contacts
+
+
+SYNOPSIS
+--------
+[verse]
+'git check-mailmap' [<options>] <contact>...
+
+
+DESCRIPTION
+-----------
+
+For each ``Name $$<user@host>$$'', ``$$<user@host>$$'', or ``$$user@host$$''
+from the command-line or standard input (when using `--stdin`), look up the
+person's canonical name and email address (see "Mapping Authors" below). If
+found, print them; otherwise print the input as-is.
+
+
+OPTIONS
+-------
+--stdin::
+	Read contacts, one per line, from the standard input after exhausting
+	contacts provided on the command-line.
+
+--mailmap-file=<file>::
+	In addition to any configured mailmap files, read the specified
+	mailmap file. Entries in this file take precedence over entries in
+	either the default mailmap file or any configured mailmap file.
+
+--mailmap-blob=<blob>::
+	Like `--mailmap-file`, but consider the value as a reference to a
+	blob in the repository. If both `--mailmap-file` and
+	`--mailmap-blob` are specified, entries in `--mailmap-file` will
+	take precedence.
+
+OUTPUT
+------
+
+For each contact, a single line is output, terminated by a newline.  If the
+name is provided or known to the 'mailmap', ``Name $$<user@host>$$'' is
+printed; otherwise only ``$$<user@host>$$'' is printed.
+
+
+CONFIGURATION
+-------------
+
+See `mailmap.file` and `mailmap.blob` in linkgit:git-config[1] for how
+to specify a custom `.mailmap` target file or object.
+
+
+MAPPING AUTHORS
+---------------
+
+See linkgit:gitmailmap[5].
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-check-ref-format.adoc b/Documentation/git-check-ref-format.adoc
new file mode 100644
index 0000000000..2aacfd1808
--- /dev/null
+++ b/Documentation/git-check-ref-format.adoc
@@ -0,0 +1,140 @@
+git-check-ref-format(1)
+=======================
+
+NAME
+----
+git-check-ref-format - Ensures that a reference name is well formed
+
+SYNOPSIS
+--------
+[verse]
+'git check-ref-format' [--normalize]
+       [--[no-]allow-onelevel] [--refspec-pattern]
+       <refname>
+'git check-ref-format' --branch <branchname-shorthand>
+
+DESCRIPTION
+-----------
+Checks if a given 'refname' is acceptable, and exits with a non-zero
+status if it is not.
+
+A reference is used in Git to specify branches and tags.  A
+branch head is stored in the `refs/heads` hierarchy, while
+a tag is stored in the `refs/tags` hierarchy of the ref namespace
+(typically in `$GIT_DIR/refs/heads` and `$GIT_DIR/refs/tags`
+directories or, as entries in file `$GIT_DIR/packed-refs`
+if refs are packed by `git gc`).
+
+Git imposes the following rules on how references are named:
+
+. They can include slash `/` for hierarchical (directory)
+  grouping, but no slash-separated component can begin with a
+  dot `.` or end with the sequence `.lock`.
+
+. They must contain at least one `/`. This enforces the presence of a
+  category like `heads/`, `tags/` etc. but the actual names are not
+  restricted.  If the `--allow-onelevel` option is used, this rule
+  is waived.
+
+. They cannot have two consecutive dots `..` anywhere.
+
+. They cannot have ASCII control characters (i.e. bytes whose
+  values are lower than \040, or \177 `DEL`), space, tilde `~`,
+  caret `^`, or colon `:` anywhere.
+
+. They cannot have question-mark `?`, asterisk `*`, or open
+  bracket `[` anywhere.  See the `--refspec-pattern` option below for
+  an exception to this rule.
+
+. They cannot begin or end with a slash `/` or contain multiple
+  consecutive slashes (see the `--normalize` option below for an
+  exception to this rule).
+
+. They cannot end with a dot `.`.
+
+. They cannot contain a sequence `@{`.
+
+. They cannot be the single character `@`.
+
+. They cannot contain a `\`.
+
+These rules make it easy for shell script based tools to parse
+reference names, pathname expansion by the shell when a reference name is used
+unquoted (by mistake), and also avoid ambiguities in certain
+reference name expressions (see linkgit:gitrevisions[7]):
+
+. A double-dot `..` is often used as in `ref1..ref2`, and in some
+  contexts this notation means `^ref1 ref2` (i.e. not in
+  `ref1` and in `ref2`).
+
+. A tilde `~` and caret `^` are used to introduce the postfix
+  'nth parent' and 'peel onion' operation.
+
+. A colon `:` is used as in `srcref:dstref` to mean "use srcref\'s
+  value and store it in dstref" in fetch and push operations.
+  It may also be used to select a specific object such as with
+  'git cat-file': "git cat-file blob v1.3.3:refs.c".
+
+. at-open-brace `@{` is used as a notation to access a reflog entry.
+
+With the `--branch` option, the command takes a name and checks if
+it can be used as a valid branch name (e.g. when creating a new
+branch). But be cautious when using the
+previous checkout syntax that may refer to a detached HEAD state.
+The rule `git check-ref-format --branch $name` implements
+may be stricter than what `git check-ref-format refs/heads/$name`
+says (e.g. a dash may appear at the beginning of a ref component,
+but it is explicitly forbidden at the beginning of a branch name).
+When run with the `--branch` option in a repository, the input is first
+expanded for the ``previous checkout syntax''
+`@{-n}`.  For example, `@{-1}` is a way to refer the last thing that
+was checked out using "git switch" or "git checkout" operation.
+This option should be
+used by porcelains to accept this syntax anywhere a branch name is
+expected, so they can act as if you typed the branch name. As an
+exception note that, the ``previous checkout operation'' might result
+in a commit object name when the N-th last thing checked out was not
+a branch.
+
+OPTIONS
+-------
+--[no-]allow-onelevel::
+	Controls whether one-level refnames are accepted (i.e.,
+	refnames that do not contain multiple `/`-separated
+	components).  The default is `--no-allow-onelevel`.
+
+--refspec-pattern::
+	Interpret <refname> as a reference name pattern for a refspec
+	(as used with remote repositories).  If this option is
+	enabled, <refname> is allowed to contain a single `*`
+	in the refspec (e.g., `foo/bar*/baz` or `foo/bar*baz/`
+	but not `foo/bar*/baz*`).
+
+--normalize::
+	Normalize 'refname' by removing any leading slash (`/`)
+	characters and collapsing runs of adjacent slashes between
+	name components into a single slash.  If the normalized
+	refname is valid then print it to standard output and exit
+	with a status of 0, otherwise exit with a non-zero status.
+	(`--print` is a deprecated way to spell `--normalize`.)
+
+
+EXAMPLES
+--------
+
+* Print the name of the previous thing checked out:
++
+------------
+$ git check-ref-format --branch @{-1}
+------------
+
+* Determine the reference name to use for a new branch:
++
+------------
+$ ref=$(git check-ref-format --normalize "refs/heads/$newbranch")||
+{ echo "we do not like '$newbranch' as a branch name." >&2 ; exit 1 ; }
+------------
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-checkout-index.adoc b/Documentation/git-checkout-index.adoc
new file mode 100644
index 0000000000..faf8d6ca36
--- /dev/null
+++ b/Documentation/git-checkout-index.adoc
@@ -0,0 +1,183 @@
+git-checkout-index(1)
+=====================
+
+NAME
+----
+git-checkout-index - Copy files from the index to the working tree
+
+
+SYNOPSIS
+--------
+[verse]
+'git checkout-index' [-u] [-q] [-a] [-f] [-n] [--prefix=<string>]
+		   [--stage=<number>|all]
+		   [--temp]
+		   [--ignore-skip-worktree-bits]
+		   [-z] [--stdin]
+		   [--] [<file>...]
+
+DESCRIPTION
+-----------
+Copies all listed files from the index to the working directory
+(not overwriting existing files).
+
+OPTIONS
+-------
+-u::
+--index::
+	update stat information for the checked out entries in
+	the index file.
+
+-q::
+--quiet::
+	be quiet if files exist or are not in the index
+
+-f::
+--force::
+	forces overwrite of existing files
+
+-a::
+--all::
+	checks out all files in the index except for those with the
+	skip-worktree bit set (see `--ignore-skip-worktree-bits`).
+	Cannot be used together with explicit filenames.
+
+-n::
+--no-create::
+	Don't checkout new files, only refresh files already checked
+	out.
+
+--prefix=<string>::
+	When creating files, prepend <string> (usually a directory
+	including a trailing /)
+
+--stage=<number>|all::
+	Instead of checking out unmerged entries, copy out the
+	files from the named stage.  <number> must be between 1 and 3.
+	Note: --stage=all automatically implies --temp.
+
+--temp::
+	Instead of copying the files to the working directory,
+	write the content to temporary files.  The temporary name
+	associations will be written to stdout.
+
+--ignore-skip-worktree-bits::
+	Check out all files, including those with the skip-worktree bit
+	set.
+
+--stdin::
+	Instead of taking a list of paths from the command line,
+	read the list of paths from the standard input.  Paths are
+	separated by LF (i.e. one path per line) by default.
+
+-z::
+	Only meaningful with `--stdin`; paths are separated with
+	NUL character instead of LF.
+
+\--::
+	Do not interpret any more arguments as options.
+
+The order of the flags used to matter, but not anymore.
+
+Just doing `git checkout-index` does nothing. You probably meant
+`git checkout-index -a`. And if you want to force it, you want
+`git checkout-index -f -a`.
+
+Intuitiveness is not the goal here. Repeatability is. The reason for
+the "no arguments means no work" behavior is that from scripts you are
+supposed to be able to do:
+
+----------------
+$ find . -name '*.h' -print0 | xargs -0 git checkout-index -f --
+----------------
+
+which will force all existing `*.h` files to be replaced with their
+cached copies. If an empty command line implied "all", then this would
+force-refresh everything in the index, which was not the point.  But
+since 'git checkout-index' accepts --stdin it would be faster to use:
+
+----------------
+$ find . -name '*.h' -print0 | git checkout-index -f -z --stdin
+----------------
+
+The `--` is just a good idea when you know the rest will be filenames;
+it will prevent problems with a filename of, for example,  `-a`.
+Using `--` is probably a good policy in scripts.
+
+
+Using --temp or --stage=all
+---------------------------
+When `--temp` is used (or implied by `--stage=all`)
+'git checkout-index' will create a temporary file for each index
+entry being checked out.  The index will not be updated with stat
+information.  These options can be useful if the caller needs all
+stages of all unmerged entries so that the unmerged files can be
+processed by an external merge tool.
+
+A listing will be written to stdout providing the association of
+temporary file names to tracked path names.  The listing format
+has two variations:
+
+    . tempname TAB path RS
++
+The first format is what gets used when `--stage` is omitted or
+is not `--stage=all`. The field tempname is the temporary file
+name holding the file content and path is the tracked path name in
+the index.  Only the requested entries are output.
+
+    . stage1temp SP stage2temp SP stage3tmp TAB path RS
++
+The second format is what gets used when `--stage=all`.  The three
+stage temporary fields (stage1temp, stage2temp, stage3temp) list the
+name of the temporary file if there is a stage entry in the index
+or `.` if there is no stage entry.  Paths which only have a stage 0
+entry will always be omitted from the output.
+
+In both formats RS (the record separator) is newline by default
+but will be the null byte if -z was passed on the command line.
+The temporary file names are always safe strings; they will never
+contain directory separators or whitespace characters.  The path
+field is always relative to the current directory and the temporary
+file names are always relative to the top level directory.
+
+If the object being copied out to a temporary file is a symbolic
+link the content of the link will be written to a normal file.  It is
+up to the end-user or the Porcelain to make use of this information.
+
+
+EXAMPLES
+--------
+To update and refresh only the files already checked out::
++
+----------------
+$ git checkout-index -n -f -a && git update-index --ignore-missing --refresh
+----------------
+
+Using 'git checkout-index' to "export an entire tree"::
+	The prefix ability basically makes it trivial to use
+	'git checkout-index' as an "export as tree" function.
+	Just read the desired tree into the index, and do:
++
+----------------
+$ git checkout-index --prefix=git-export-dir/ -a
+----------------
++
+`git checkout-index` will "export" the index into the specified
+directory.
++
+The final "/" is important. The exported name is literally just
+prefixed with the specified string.  Contrast this with the
+following example.
+
+Export files with a prefix::
++
+----------------
+$ git checkout-index --prefix=.merged- Makefile
+----------------
++
+This will check out the currently cached copy of `Makefile`
+into the file `.merged-Makefile`.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-checkout.adoc b/Documentation/git-checkout.adoc
new file mode 100644
index 0000000000..2c4cc80179
--- /dev/null
+++ b/Documentation/git-checkout.adoc
@@ -0,0 +1,626 @@
+git-checkout(1)
+===============
+
+NAME
+----
+git-checkout - Switch branches or restore working tree files
+
+SYNOPSIS
+--------
+[verse]
+'git checkout' [-q] [-f] [-m] [<branch>]
+'git checkout' [-q] [-f] [-m] --detach [<branch>]
+'git checkout' [-q] [-f] [-m] [--detach] <commit>
+'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new-branch>] [<start-point>]
+'git checkout' [-f] <tree-ish> [--] <pathspec>...
+'git checkout' [-f] <tree-ish> --pathspec-from-file=<file> [--pathspec-file-nul]
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [--] <pathspec>...
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] --pathspec-from-file=<file> [--pathspec-file-nul]
+'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]
+
+DESCRIPTION
+-----------
+Updates files in the working tree to match the version in the index
+or the specified tree.  If no pathspec was given, 'git checkout' will
+also update `HEAD` to set the specified branch as the current
+branch.
+
+'git checkout' [<branch>]::
+	To prepare for working on `<branch>`, switch to it by updating
+	the index and the files in the working tree, and by pointing
+	`HEAD` at the branch. Local modifications to the files in the
+	working tree are kept, so that they can be committed to the
+	`<branch>`.
++
+If `<branch>` is not found but there does exist a tracking branch in
+exactly one remote (call it `<remote>`) with a matching name and
+`--no-guess` is not specified, treat as equivalent to
++
+------------
+$ git checkout -b <branch> --track <remote>/<branch>
+------------
++
+You could omit `<branch>`, in which case the command degenerates to
+"check out the current branch", which is a glorified no-op with
+rather expensive side-effects to show only the tracking information,
+if it exists, for the current branch.
+
+'git checkout' -b|-B <new-branch> [<start-point>]::
+
+	Specifying `-b` causes a new branch to be created as if
+	linkgit:git-branch[1] were called and then checked out.  In
+	this case you can use the `--track` or `--no-track` options,
+	which will be passed to 'git branch'.  As a convenience,
+	`--track` without `-b` implies branch creation; see the
+	description of `--track` below.
++
+If `-B` is given, `<new-branch>` is created if it doesn't exist; otherwise, it
+is reset. This is the transactional equivalent of
++
+------------
+$ git branch -f <branch> [<start-point>]
+$ git checkout <branch>
+------------
++
+that is to say, the branch is not reset/created unless "git checkout" is
+successful (e.g., when the branch is in use in another worktree, not
+just the current branch stays the same, but the branch is not reset to
+the start-point, either).
+
+'git checkout' --detach [<branch>]::
+'git checkout' [--detach] <commit>::
+
+	Prepare to work on top of `<commit>`, by detaching `HEAD` at it
+	(see "DETACHED HEAD" section), and updating the index and the
+	files in the working tree.  Local modifications to the files
+	in the working tree are kept, so that the resulting working
+	tree will be the state recorded in the commit plus the local
+	modifications.
++
+When the `<commit>` argument is a branch name, the `--detach` option can
+be used to detach `HEAD` at the tip of the branch (`git checkout
+<branch>` would check out that branch without detaching `HEAD`).
++
+Omitting `<branch>` detaches `HEAD` at the tip of the current branch.
+
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <pathspec>...::
+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] --pathspec-from-file=<file> [--pathspec-file-nul]::
+
+	Overwrite the contents of the files that match the pathspec.
+	When the `<tree-ish>` (most often a commit) is not given,
+	overwrite working tree with the contents in the index.
+	When the `<tree-ish>` is given, overwrite both the index and
+	the working tree with the contents at the `<tree-ish>`.
++
+The index may contain unmerged entries because of a previous failed merge.
+By default, if you try to check out such an entry from the index, the
+checkout operation will fail and nothing will be checked out.
+Using `-f` will ignore these unmerged entries.  The contents from a
+specific side of the merge can be checked out of the index by
+using `--ours` or `--theirs`.  With `-m`, changes made to the working tree
+file can be discarded to re-create the original conflicted merge result.
+
+'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]::
+	This is similar to the previous mode, but lets you use the
+	interactive interface to show the "diff" output and choose which
+	hunks to use in the result.  See below for the description of
+	`--patch` option.
+
+OPTIONS
+-------
+-q::
+--quiet::
+	Quiet, suppress feedback messages.
+
+--progress::
+--no-progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless `--quiet`
+	is specified. This flag enables progress reporting even if not
+	attached to a terminal, regardless of `--quiet`.
+
+-f::
+--force::
+	When switching branches, proceed even if the index or the
+	working tree differs from `HEAD`, and even if there are untracked
+	files in the way.  This is used to throw away local changes and
+	any untracked files or directories that are in the way.
++
+When checking out paths from the index, do not fail upon unmerged
+entries; instead, unmerged entries are ignored.
+
+--ours::
+--theirs::
+	When checking out paths from the index, check out stage #2
+	('ours') or #3 ('theirs') for unmerged paths.
++
+Note that during `git rebase` and `git pull --rebase`, 'ours' and
+'theirs' may appear swapped; `--ours` gives the version from the
+branch the changes are rebased onto, while `--theirs` gives the
+version from the branch that holds your work that is being rebased.
++
+This is because `rebase` is used in a workflow that treats the
+history at the remote as the shared canonical one, and treats the
+work done on the branch you are rebasing as the third-party work to
+be integrated, and you are temporarily assuming the role of the
+keeper of the canonical history during the rebase.  As the keeper of
+the canonical history, you need to view the history from the remote
+as `ours` (i.e. "our shared canonical history"), while what you did
+on your side branch as `theirs` (i.e. "one contributor's work on top
+of it").
+
+-b <new-branch>::
+	Create a new branch named `<new-branch>`, start it at
+	`<start-point>`, and check the resulting branch out;
+	see linkgit:git-branch[1] for details.
+
+-B <new-branch>::
+	Creates the branch `<new-branch>`, start it at `<start-point>`;
+	if it already exists, then reset it to `<start-point>`. And then
+	check the resulting branch out.  This is equivalent to running
+	"git branch" with "-f" followed by "git checkout" of that branch;
+	see linkgit:git-branch[1] for details.
+
+-t::
+--track[=(direct|inherit)]::
+	When creating a new branch, set up "upstream" configuration. See
+	"--track" in linkgit:git-branch[1] for details.
++
+If no `-b` option is given, the name of the new branch will be
+derived from the remote-tracking branch, by looking at the local part of
+the refspec configured for the corresponding remote, and then stripping
+the initial part up to the "*".
+This would tell us to use `hack` as the local branch when branching
+off of `origin/hack` (or `remotes/origin/hack`, or even
+`refs/remotes/origin/hack`).  If the given name has no slash, or the above
+guessing results in an empty name, the guessing is aborted.  You can
+explicitly give a name with `-b` in such a case.
+
+--no-track::
+	Do not set up "upstream" configuration, even if the
+	`branch.autoSetupMerge` configuration variable is true.
+
+--guess::
+--no-guess::
+	If `<branch>` is not found but there does exist a tracking
+	branch in exactly one remote (call it `<remote>`) with a
+	matching name, treat as equivalent to
++
+------------
+$ git checkout -b <branch> --track <remote>/<branch>
+------------
++
+If the branch exists in multiple remotes and one of them is named by
+the `checkout.defaultRemote` configuration variable, we'll use that
+one for the purposes of disambiguation, even if the `<branch>` isn't
+unique across all remotes. Set it to
+e.g. `checkout.defaultRemote=origin` to always checkout remote
+branches from there if `<branch>` is ambiguous but exists on the
+'origin' remote. See also `checkout.defaultRemote` in
+linkgit:git-config[1].
++
+`--guess` is the default behavior. Use `--no-guess` to disable it.
++
+The default behavior can be set via the `checkout.guess` configuration
+variable.
+
+-l::
+	Create the new branch's reflog; see linkgit:git-branch[1] for
+	details.
+
+-d::
+--detach::
+	Rather than checking out a branch to work on it, check out a
+	commit for inspection and discardable experiments.
+	This is the default behavior of `git checkout <commit>` when
+	`<commit>` is not a branch name.  See the "DETACHED HEAD" section
+	below for details.
+
+--orphan <new-branch>::
+	Create a new unborn branch, named `<new-branch>`, started from
+	`<start-point>` and switch to it.  The first commit made on this
+	new branch will have no parents and it will be the root of a new
+	history totally disconnected from all the other branches and
+	commits.
++
+The index and the working tree are adjusted as if you had previously run
+`git checkout <start-point>`.  This allows you to start a new history
+that records a set of paths similar to `<start-point>` by easily running
+`git commit -a` to make the root commit.
++
+This can be useful when you want to publish the tree from a commit
+without exposing its full history. You might want to do this to publish
+an open source branch of a project whose current tree is "clean", but
+whose full history contains proprietary or otherwise encumbered bits of
+code.
++
+If you want to start a disconnected history that records a set of paths
+that is totally different from the one of `<start-point>`, then you should
+clear the index and the working tree right after creating the orphan
+branch by running `git rm -rf .` from the top level of the working tree.
+Afterwards you will be ready to prepare your new files, repopulating the
+working tree, by copying them from elsewhere, extracting a tarball, etc.
+
+--ignore-skip-worktree-bits::
+	In sparse checkout mode, `git checkout -- <paths>` would
+	update only entries matched by `<paths>` and sparse patterns
+	in `$GIT_DIR/info/sparse-checkout`. This option ignores
+	the sparse patterns and adds back any files in `<paths>`.
+
+-m::
+--merge::
+	When switching branches,
+	if you have local modifications to one or more files that
+	are different between the current branch and the branch to
+	which you are switching, the command refuses to switch
+	branches in order to preserve your modifications in context.
+	However, with this option, a three-way merge between the current
+	branch, your working tree contents, and the new branch
+	is done, and you will be on the new branch.
++
+When a merge conflict happens, the index entries for conflicting
+paths are left unmerged, and you need to resolve the conflicts
+and mark the resolved paths with `git add` (or `git rm` if the merge
+should result in deletion of the path).
++
+When checking out paths from the index, this option lets you recreate
+the conflicted merge in the specified paths.  This option cannot be
+used when checking out paths from a tree-ish.
++
+When switching branches with `--merge`, staged changes may be lost.
+
+--conflict=<style>::
+	The same as `--merge` option above, but changes the way the
+	conflicting hunks are presented, overriding the
+	`merge.conflictStyle` configuration variable.  Possible values are
+	"merge" (default), "diff3", and "zdiff3".
+
+-p::
+--patch::
+	Interactively select hunks in the difference between the
+	`<tree-ish>` (or the index, if unspecified) and the working
+	tree.  The chosen hunks are then applied in reverse to the
+	working tree (and if a `<tree-ish>` was specified, the index).
++
+This means that you can use `git checkout -p` to selectively discard
+edits from your current working tree. See the ``Interactive Mode''
+section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
++
+Note that this option uses the no overlay mode by default (see also
+`--overlay`), and currently doesn't support overlay mode.
+
+--ignore-other-worktrees::
+	`git checkout` refuses when the wanted branch is already checked
+	out or otherwise in use by another worktree. This option makes
+	it check the branch out anyway. In other words, the branch can
+	be in use by more than one worktree.
+
+--overwrite-ignore::
+--no-overwrite-ignore::
+	Silently overwrite ignored files when switching branches. This
+	is the default behavior. Use `--no-overwrite-ignore` to abort
+	the operation when the new branch contains ignored files.
+
+--recurse-submodules::
+--no-recurse-submodules::
+	Using `--recurse-submodules` will update the content of all active
+	submodules according to the commit recorded in the superproject. If
+	local modifications in a submodule would be overwritten the checkout
+	will fail unless `-f` is used. If nothing (or `--no-recurse-submodules`)
+	is used, submodules working trees will not be updated.
+	Just like linkgit:git-submodule[1], this will detach `HEAD` of the
+	submodule.
+
+--overlay::
+--no-overlay::
+	In the default overlay mode, `git checkout` never
+	removes files from the index or the working tree.  When
+	specifying `--no-overlay`, files that appear in the index and
+	working tree, but not in `<tree-ish>` are removed, to make them
+	match `<tree-ish>` exactly.
+
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
+<branch>::
+	Branch to checkout; if it refers to a branch (i.e., a name that,
+	when prepended with "refs/heads/", is a valid ref), then that
+	branch is checked out. Otherwise, if it refers to a valid
+	commit, your `HEAD` becomes "detached" and you are no longer on
+	any branch (see below for details).
++
+You can use the `@{-N}` syntax to refer to the N-th last
+branch/commit checked out using "git checkout" operation. You may
+also specify `-` which is synonymous to `@{-1}`.
++
+As a special case, you may use `A...B` as a shortcut for the
+merge base of `A` and `B` if there is exactly one merge base. You can
+leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
+
+<new-branch>::
+	Name for the new branch.
+
+<start-point>::
+	The name of a commit at which to start the new branch; see
+	linkgit:git-branch[1] for details. Defaults to `HEAD`.
++
+As a special case, you may use `"A...B"` as a shortcut for the
+merge base of `A` and `B` if there is exactly one merge base. You can
+leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
+
+<tree-ish>::
+	Tree to checkout from (when paths are given). If not specified,
+	the index will be used.
++
+As a special case, you may use `"A...B"` as a shortcut for the
+merge base of `A` and `B` if there is exactly one merge base. You can
+leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
+
+\--::
+	Do not interpret any more arguments as options.
+
+<pathspec>...::
+	Limits the paths affected by the operation.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
+
+DETACHED HEAD
+-------------
+`HEAD` normally refers to a named branch (e.g. `master`). Meanwhile, each
+branch refers to a specific commit. Let's look at a repo with three
+commits, one of them tagged, and with branch `master` checked out:
+
+------------
+           HEAD (refers to branch 'master')
+            |
+            v
+a---b---c  branch 'master' (refers to commit 'c')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
+
+When a commit is created in this state, the branch is updated to refer to
+the new commit. Specifically, 'git commit' creates a new commit `d`, whose
+parent is commit `c`, and then updates branch `master` to refer to new
+commit `d`. `HEAD` still refers to branch `master` and so indirectly now refers
+to commit `d`:
+
+------------
+$ edit; git add; git commit
+
+               HEAD (refers to branch 'master')
+                |
+                v
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
+
+It is sometimes useful to be able to checkout a commit that is not at
+the tip of any named branch, or even to create a new commit that is not
+referenced by a named branch. Let's look at what happens when we
+checkout commit `b` (here we show two ways this may be done):
+
+------------
+$ git checkout v2.0  # or
+$ git checkout master^^
+
+   HEAD (refers to commit 'b')
+    |
+    v
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
+
+Notice that regardless of which checkout command we use, `HEAD` now refers
+directly to commit `b`. This is known as being in detached `HEAD` state.
+It means simply that `HEAD` refers to a specific commit, as opposed to
+referring to a named branch. Let's see what happens when we create a commit:
+
+------------
+$ edit; git add; git commit
+
+     HEAD (refers to commit 'e')
+      |
+      v
+      e
+     /
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
+
+There is now a new commit `e`, but it is referenced only by `HEAD`. We can
+of course add yet another commit in this state:
+
+------------
+$ edit; git add; git commit
+
+	 HEAD (refers to commit 'f')
+	  |
+	  v
+      e---f
+     /
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
+
+In fact, we can perform all the normal Git operations. But, let's look
+at what happens when we then checkout `master`:
+
+------------
+$ git checkout master
+
+               HEAD (refers to branch 'master')
+      e---f     |
+     /          v
+a---b---c---d  branch 'master' (refers to commit 'd')
+    ^
+    |
+  tag 'v2.0' (refers to commit 'b')
+------------
+
+It is important to realize that at this point nothing refers to commit
+`f`. Eventually commit `f` (and by extension commit `e`) will be deleted
+by the routine Git garbage collection process, unless we create a reference
+before that happens. If we have not yet moved away from commit `f`,
+any of these will create a reference to it:
+
+------------
+$ git checkout -b foo  # or "git switch -c foo"  <1>
+$ git branch foo                                 <2>
+$ git tag foo                                    <3>
+------------
+<1> creates a new branch `foo`, which refers to commit `f`, and then
+    updates `HEAD` to refer to branch `foo`. In other words, we'll no longer
+    be in detached `HEAD` state after this command.
+<2> similarly creates a new branch `foo`, which refers to commit `f`,
+    but leaves `HEAD` detached.
+<3> creates a new tag `foo`, which refers to commit `f`,
+    leaving `HEAD` detached.
+
+If we have moved away from commit `f`, then we must first recover its object
+name (typically by using git reflog), and then we can create a reference to
+it. For example, to see the last two commits to which `HEAD` referred, we
+can use either of these commands:
+
+------------
+$ git reflog -2 HEAD # or
+$ git log -g -2 HEAD
+------------
+
+ARGUMENT DISAMBIGUATION
+-----------------------
+
+When there is only one argument given and it is not `--` (e.g. `git
+checkout abc`), and when the argument is both a valid `<tree-ish>`
+(e.g. a branch `abc` exists) and a valid `<pathspec>` (e.g. a file
+or a directory whose name is "abc" exists), Git would usually ask
+you to disambiguate.  Because checking out a branch is so common an
+operation, however, `git checkout abc` takes "abc" as a `<tree-ish>`
+in such a situation.  Use `git checkout -- <pathspec>` if you want
+to checkout these paths out of the index.
+
+EXAMPLES
+--------
+
+=== 1. Paths
+
+The following sequence checks out the `master` branch, reverts
+the `Makefile` to two revisions back, deletes `hello.c` by
+mistake, and gets it back from the index.
+
+------------
+$ git checkout master             <1>
+$ git checkout master~2 Makefile  <2>
+$ rm -f hello.c
+$ git checkout hello.c            <3>
+------------
+<1> switch branch
+<2> take a file out of another commit
+<3> restore `hello.c` from the index
+
+If you want to check out _all_ C source files out of the index,
+you can say
+
+------------
+$ git checkout -- '*.c'
+------------
+
+Note the quotes around `*.c`.  The file `hello.c` will also be
+checked out, even though it is no longer in the working tree,
+because the file globbing is used to match entries in the index
+(not in the working tree by the shell).
+
+If you have an unfortunate branch that is named `hello.c`, this
+step would be confused as an instruction to switch to that branch.
+You should instead write:
+
+------------
+$ git checkout -- hello.c
+------------
+
+=== 2. Merge
+
+After working in the wrong branch, switching to the correct
+branch would be done using:
+
+------------
+$ git checkout mytopic
+------------
+
+However, your "wrong" branch and correct `mytopic` branch may
+differ in files that you have modified locally, in which case
+the above checkout would fail like this:
+
+------------
+$ git checkout mytopic
+error: You have local changes to 'frotz'; not switching branches.
+------------
+
+You can give the `-m` flag to the command, which would try a
+three-way merge:
+
+------------
+$ git checkout -m mytopic
+Auto-merging frotz
+------------
+
+After this three-way merge, the local modifications are _not_
+registered in your index file, so `git diff` would show you what
+changes you made since the tip of the new branch.
+
+=== 3. Merge conflict
+
+When a merge conflict happens during switching branches with
+the `-m` option, you would see something like this:
+
+------------
+$ git checkout -m mytopic
+Auto-merging frotz
+ERROR: Merge conflict in frotz
+fatal: merge program failed
+------------
+
+At this point, `git diff` shows the changes cleanly merged as in
+the previous example, as well as the changes in the conflicted
+files.  Edit and resolve the conflict and mark it resolved with
+`git add` as usual:
+
+------------
+$ edit frotz
+$ git add frotz
+------------
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/checkout.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-switch[1],
+linkgit:git-restore[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cherry-pick.adoc b/Documentation/git-cherry-pick.adoc
new file mode 100644
index 0000000000..42b41923d5
--- /dev/null
+++ b/Documentation/git-cherry-pick.adoc
@@ -0,0 +1,259 @@
+git-cherry-pick(1)
+==================
+
+NAME
+----
+git-cherry-pick - Apply the changes introduced by some existing commits
+
+SYNOPSIS
+--------
+[verse]
+'git cherry-pick' [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]
+		  [-S[<keyid>]] <commit>...
+'git cherry-pick' (--continue | --skip | --abort | --quit)
+
+DESCRIPTION
+-----------
+
+Given one or more existing commits, apply the change each one
+introduces, recording a new commit for each.  This requires your
+working tree to be clean (no modifications from the HEAD commit).
+
+When it is not obvious how to apply a change, the following
+happens:
+
+1. The current branch and `HEAD` pointer stay at the last commit
+   successfully made.
+2. The `CHERRY_PICK_HEAD` ref is set to point at the commit that
+   introduced the change that is difficult to apply.
+3. Paths in which the change applied cleanly are updated both
+   in the index file and in your working tree.
+4. For conflicting paths, the index file records up to three
+   versions, as described in the "TRUE MERGE" section of
+   linkgit:git-merge[1].  The working tree files will include
+   a description of the conflict bracketed by the usual
+   conflict markers `<<<<<<<` and `>>>>>>>`.
+5. No other modifications are made.
+
+See linkgit:git-merge[1] for some hints on resolving such
+conflicts.
+
+OPTIONS
+-------
+<commit>...::
+	Commits to cherry-pick.
+	For a more complete list of ways to spell commits, see
+	linkgit:gitrevisions[7].
+	Sets of commits can be passed but no traversal is done by
+	default, as if the `--no-walk` option was specified, see
+	linkgit:git-rev-list[1]. Note that specifying a range will
+	feed all <commit>... arguments to a single revision walk
+	(see a later example that uses 'maint master..next').
+
+-e::
+--edit::
+	With this option, 'git cherry-pick' will let you edit the commit
+	message prior to committing.
+
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on to the commit machinery. See linkgit:git-commit[1] for more
+	details. In particular, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on in the case
+	of a conflict.
+
+-x::
+	When recording the commit, append a line that says
+	"(cherry picked from commit ...)" to the original commit
+	message in order to indicate which commit this change was
+	cherry-picked from.  This is done only for cherry
+	picks without conflicts.  Do not use this option if
+	you are cherry-picking from your private branch because
+	the information is useless to the recipient.  If on the
+	other hand you are cherry-picking between two publicly
+	visible branches (e.g. backporting a fix to a
+	maintenance branch for an older release from a
+	development branch), adding this information can be
+	useful.
+
+-r::
+	It used to be that the command defaulted to do `-x`
+	described above, and `-r` was to disable it.  Now the
+	default is not to do `-x` so this option is a no-op.
+
+-m <parent-number>::
+--mainline <parent-number>::
+	Usually you cannot cherry-pick a merge because you do not know which
+	side of the merge should be considered the mainline.  This
+	option specifies the parent number (starting from 1) of
+	the mainline and allows cherry-pick to replay the change
+	relative to the specified parent.
+
+-n::
+--no-commit::
+	Usually the command automatically creates a sequence of commits.
+	This flag applies the changes necessary to cherry-pick
+	each named commit to your working tree and the index,
+	without making any commit.  In addition, when this
+	option is used, your index does not have to match the
+	HEAD commit.  The cherry-pick is done against the
+	beginning state of your index.
++
+This is useful when cherry-picking more than one commits'
+effect to your index in a row.
+
+-s::
+--signoff::
+	Add a `Signed-off-by` trailer at the end of the commit message.
+	See the signoff option in linkgit:git-commit[1] for more information.
+
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+--no-gpg-sign::
+	GPG-sign commits. The `keyid` argument is optional and
+	defaults to the committer identity; if specified, it must be
+	stuck to the option without a space. `--no-gpg-sign` is useful to
+	countermand both `commit.gpgSign` configuration variable, and
+	earlier `--gpg-sign`.
+
+--ff::
+	If the current HEAD is the same as the parent of the
+	cherry-pick'ed commit, then a fast forward to this commit will
+	be performed.
+
+--allow-empty::
+	By default, cherry-picking an empty commit will fail,
+	indicating that an explicit invocation of `git commit
+	--allow-empty` is required. This option overrides that
+	behavior, allowing empty commits to be preserved automatically
+	in a cherry-pick. Note that when "--ff" is in effect, empty
+	commits that meet the "fast-forward" requirement will be kept
+	even without this option.  Note also, that use of this option only
+	keeps commits that were initially empty (i.e. the commit recorded the
+	same tree as its parent).  Commits which are made empty due to a
+	previous commit will cause the cherry-pick to fail.  To force the
+	inclusion of those commits, use `--empty=keep`.
+
+--allow-empty-message::
+	By default, cherry-picking a commit with an empty message will fail.
+	This option overrides that behavior, allowing commits with empty
+	messages to be cherry picked.
+
+--empty=(drop|keep|stop)::
+	How to handle commits being cherry-picked that are redundant with
+	changes already in the current history.
++
+--
+`drop`;;
+	The commit will be dropped.
+`keep`;;
+	The commit will be kept. Implies `--allow-empty`.
+`stop`;;
+	The cherry-pick will stop when the commit is applied, allowing
+	you to examine the commit. This is the default behavior.
+--
++
+Note that `--empty=drop` and `--empty=stop` only specify how to handle a
+commit that was not initially empty, but rather became empty due to a previous
+commit. Commits that were initially empty will still cause the cherry-pick to
+fail unless one of `--empty=keep` or `--allow-empty` are specified.
++
+
+--keep-redundant-commits::
+	Deprecated synonym for `--empty=keep`.
+
+--strategy=<strategy>::
+	Use the given merge strategy.  Should only be used once.
+	See the MERGE STRATEGIES section in linkgit:git-merge[1]
+	for details.
+
+-X<option>::
+--strategy-option=<option>::
+	Pass the merge strategy-specific option through to the
+	merge strategy.  See linkgit:git-merge[1] for details.
+
+include::rerere-options.adoc[]
+
+SEQUENCER SUBCOMMANDS
+---------------------
+include::sequencer.adoc[]
+
+EXAMPLES
+--------
+`git cherry-pick master`::
+
+	Apply the change introduced by the commit at the tip of the
+	master branch and create a new commit with this change.
+
+`git cherry-pick ..master`::
+`git cherry-pick ^HEAD master`::
+
+	Apply the changes introduced by all commits that are ancestors
+	of master but not of HEAD to produce new commits.
+
+`git cherry-pick maint next ^master`::
+`git cherry-pick maint master..next`::
+
+	Apply the changes introduced by all commits that are
+	ancestors of maint or next, but not master or any of its
+	ancestors.  Note that the latter does not mean `maint` and
+	everything between `master` and `next`; specifically,
+	`maint` will not be used if it is included in `master`.
+
+`git cherry-pick master~4 master~2`::
+
+	Apply the changes introduced by the fifth and third last
+	commits pointed to by master and create 2 new commits with
+	these changes.
+
+`git cherry-pick -n master~1 next`::
+
+	Apply to the working tree and the index the changes introduced
+	by the second last commit pointed to by master and by the last
+	commit pointed to by next, but do not create any commit with
+	these changes.
+
+`git cherry-pick --ff ..next`::
+
+	If history is linear and HEAD is an ancestor of next, update
+	the working tree and advance the HEAD pointer to match next.
+	Otherwise, apply the changes introduced by those commits that
+	are in next but not HEAD to the current branch, creating a new
+	commit for each new change.
+
+`git rev-list --reverse master -- README | git cherry-pick -n --stdin`::
+
+	Apply the changes introduced by all commits on the master
+	branch that touched README to the working tree and index,
+	so the result can be inspected and made into a single new
+	commit if suitable.
+
+The following sequence attempts to backport a patch, bails out because
+the code the patch applies to has changed too much, and then tries
+again, this time exercising more care about matching up context lines.
+
+------------
+$ git cherry-pick topic^             <1>
+$ git diff                           <2>
+$ git cherry-pick --abort            <3>
+$ git cherry-pick -Xpatience topic^  <4>
+------------
+<1> apply the change that would be shown by `git show topic^`.
+    In this example, the patch does not apply cleanly, so
+    information about the conflict is written to the index and
+    working tree and no new commit results.
+<2> summarize changes to be reconciled
+<3> cancel the cherry-pick.  In other words, return to the
+    pre-cherry-pick state, preserving any local modifications
+    you had in the working tree.
+<4> try to apply the change introduced by `topic^` again,
+    spending extra time to avoid mistakes based on incorrectly
+    matching context lines.
+
+SEE ALSO
+--------
+linkgit:git-revert[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cherry.adoc b/Documentation/git-cherry.adoc
new file mode 100644
index 0000000000..0ea921a593
--- /dev/null
+++ b/Documentation/git-cherry.adoc
@@ -0,0 +1,145 @@
+git-cherry(1)
+=============
+
+NAME
+----
+git-cherry - Find commits yet to be applied to upstream
+
+SYNOPSIS
+--------
+[verse]
+'git cherry' [-v] [<upstream> [<head> [<limit>]]]
+
+DESCRIPTION
+-----------
+Determine whether there are commits in `<head>..<upstream>` that are
+equivalent to those in the range `<limit>..<head>`.
+
+The equivalence test is based on the diff, after removing whitespace
+and line numbers.  git-cherry therefore detects when commits have been
+"copied" by means of linkgit:git-cherry-pick[1], linkgit:git-am[1] or
+linkgit:git-rebase[1].
+
+Outputs the SHA1 of every commit in `<limit>..<head>`, prefixed with
+`-` for commits that have an equivalent in <upstream>, and `+` for
+commits that do not.
+
+OPTIONS
+-------
+-v::
+	Show the commit subjects next to the SHA1s.
+
+<upstream>::
+	Upstream branch to search for equivalent commits.
+	Defaults to the upstream branch of HEAD.
+
+<head>::
+	Working branch; defaults to HEAD.
+
+<limit>::
+	Do not report commits up to (and including) limit.
+
+EXAMPLES
+--------
+
+Patch workflows
+~~~~~~~~~~~~~~~
+
+git-cherry is frequently used in patch-based workflows (see
+linkgit:gitworkflows[7]) to determine if a series of patches has been
+applied by the upstream maintainer.  In such a workflow you might
+create and send a topic branch like this:
+
+------------
+$ git checkout -b topic origin/master
+# work and create some commits
+$ git format-patch origin/master
+$ git send-email ... 00*
+------------
+
+Later, you can see whether your changes have been applied by saying
+(still on `topic`):
+
+------------
+$ git fetch  # update your notion of origin/master
+$ git cherry -v
+------------
+
+Concrete example
+~~~~~~~~~~~~~~~~
+
+In a situation where topic consisted of three commits, and the
+maintainer applied two of them, the situation might look like:
+
+------------
+$ git log --graph --oneline --decorate --boundary origin/master...topic
+* 7654321 (origin/master) upstream tip commit
+[... snip some other commits ...]
+* cccc111 cherry-pick of C
+* aaaa111 cherry-pick of A
+[... snip a lot more that has happened ...]
+| * cccc000 (topic) commit C
+| * bbbb000 commit B
+| * aaaa000 commit A
+|/
+o 1234567 branch point
+------------
+
+In such cases, git-cherry shows a concise summary of what has yet to
+be applied:
+
+------------
+$ git cherry origin/master topic
+- cccc000... commit C
++ bbbb000... commit B
+- aaaa000... commit A
+------------
+
+Here, we see that the commits A and C (marked with `-`) can be
+dropped from your `topic` branch when you rebase it on top of
+`origin/master`, while the commit B (marked with `+`) still needs to
+be kept so that it will be sent to be applied to `origin/master`.
+
+
+Using a limit
+~~~~~~~~~~~~~
+
+The optional <limit> is useful in cases where your topic is based on
+other work that is not in upstream.  Expanding on the previous
+example, this might look like:
+
+------------
+$ git log --graph --oneline --decorate --boundary origin/master...topic
+* 7654321 (origin/master) upstream tip commit
+[... snip some other commits ...]
+* cccc111 cherry-pick of C
+* aaaa111 cherry-pick of A
+[... snip a lot more that has happened ...]
+| * cccc000 (topic) commit C
+| * bbbb000 commit B
+| * aaaa000 commit A
+| * 0000fff (base) unpublished stuff F
+[... snip ...]
+| * 0000aaa unpublished stuff A
+|/
+o 1234567 merge-base between upstream and topic
+------------
+
+By specifying `base` as the limit, you can avoid listing commits
+between `base` and `topic`:
+
+------------
+$ git cherry origin/master topic base
+- cccc000... commit C
++ bbbb000... commit B
+- aaaa000... commit A
+------------
+
+
+SEE ALSO
+--------
+linkgit:git-patch-id[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-citool.adoc b/Documentation/git-citool.adoc
new file mode 100644
index 0000000000..c7a11c36c1
--- /dev/null
+++ b/Documentation/git-citool.adoc
@@ -0,0 +1,25 @@
+git-citool(1)
+=============
+
+NAME
+----
+git-citool - Graphical alternative to git-commit
+
+SYNOPSIS
+--------
+[verse]
+'git citool'
+
+DESCRIPTION
+-----------
+A Tcl/Tk based graphical interface to review modified files, stage
+them into the index, enter a commit message and record the new
+commit onto the current branch.  This interface is an alternative
+to the less interactive 'git commit' program.
+
+'git citool' is actually a standard alias for `git gui citool`.
+See linkgit:git-gui[1] for more details.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-clean.adoc b/Documentation/git-clean.adoc
new file mode 100644
index 0000000000..686adeb088
--- /dev/null
+++ b/Documentation/git-clean.adoc
@@ -0,0 +1,153 @@
+git-clean(1)
+============
+
+NAME
+----
+git-clean - Remove untracked files from the working tree
+
+SYNOPSIS
+--------
+[verse]
+'git clean' [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] [<pathspec>...]
+
+DESCRIPTION
+-----------
+
+Cleans the working tree by recursively removing files that are not
+under version control, starting from the current directory.
+
+Normally, only files unknown to Git are removed, but if the `-x`
+option is specified, ignored files are also removed. This can, for
+example, be useful to remove all build products.
+
+If any optional `<pathspec>...` arguments are given, only those paths
+that match the pathspec are affected.
+
+OPTIONS
+-------
+-d::
+	Normally, when no <pathspec> is specified, git clean will not
+	recurse into untracked directories to avoid removing too much.
+	Specify -d to have it recurse into such directories as well.
+	If a <pathspec> is specified, -d is irrelevant; all untracked
+	files matching the specified paths (with exceptions for nested
+	git directories mentioned under `--force`) will be removed.
+
+-f::
+--force::
+	If the Git configuration variable clean.requireForce is not set
+	to false, 'git clean' will refuse to delete files or directories
+	unless given -f.  Git will refuse to modify untracked
+	nested git repositories (directories with a .git subdirectory)
+	unless a second -f is given.
+
+-i::
+--interactive::
+	Show what would be done and clean files interactively. See
+	``Interactive mode'' for details.
+	Configuration variable `clean.requireForce` is ignored, as
+	this mode gives its own safety protection by going interactive.
+
+-n::
+--dry-run::
+	Don't actually remove anything, just show what would be done.
+	Configuration variable `clean.requireForce` is ignored, as
+	nothing will be deleted anyway.
+
+-q::
+--quiet::
+	Be quiet, only report errors, but not the files that are
+	successfully removed.
+
+-e <pattern>::
+--exclude=<pattern>::
+	Use the given exclude pattern in addition to the standard ignore rules
+	(see linkgit:gitignore[5]).
+
+-x::
+	Don't use the standard ignore rules (see linkgit:gitignore[5]), but
+	still use the ignore rules given with `-e` options from the command
+	line.  This allows removing all untracked
+	files, including build products.  This can be used (possibly in
+	conjunction with 'git restore' or 'git reset') to create a pristine
+	working directory to test a clean build.
+
+-X::
+	Remove only files ignored by Git.  This may be useful to rebuild
+	everything from scratch, but keep manually created files.
+
+Interactive mode
+----------------
+When the command enters the interactive mode, it shows the
+files and directories to be cleaned, and goes into its
+interactive command loop.
+
+The command loop shows the list of subcommands available, and
+gives a prompt "What now> ".  In general, when the prompt ends
+with a single '>', you can pick only one of the choices given
+and type return, like this:
+
+------------
+    *** Commands ***
+	1: clean                2: filter by pattern    3: select by numbers
+	4: ask each             5: quit                 6: help
+    What now> 1
+------------
+
+You also could say `c` or `clean` above as long as the choice is unique.
+
+The main command loop has 6 subcommands.
+
+clean::
+
+   Start cleaning files and directories, and then quit.
+
+filter by pattern::
+
+   This shows the files and directories to be deleted and issues an
+   "Input ignore patterns>>" prompt. You can input space-separated
+   patterns to exclude files and directories from deletion.
+   E.g. "*.c *.h" will exclude files ending with ".c" and ".h" from
+   deletion. When you are satisfied with the filtered result, press
+   ENTER (empty) back to the main menu.
+
+select by numbers::
+
+   This shows the files and directories to be deleted and issues an
+   "Select items to delete>>" prompt. When the prompt ends with double
+   '>>' like this, you can make more than one selection, concatenated
+   with whitespace or comma.  Also you can say ranges.  E.g. "2-5 7,9"
+   to choose 2,3,4,5,7,9 from the list.  If the second number in a
+   range is omitted, all remaining items are selected.  E.g. "7-" to
+   choose 7,8,9 from the list.  You can say '*' to choose everything.
+   Also when you are satisfied with the filtered result, press ENTER
+   (empty) back to the main menu.
+
+ask each::
+
+  This will start to clean, and you must confirm one by one in order
+  to delete items. Please note that this action is not as efficient
+  as the above two actions.
+
+quit::
+
+  This lets you quit without doing any cleaning.
+
+help::
+
+  Show brief usage of interactive git-clean.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/clean.adoc[]
+
+SEE ALSO
+--------
+linkgit:gitignore[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-clone.adoc b/Documentation/git-clone.adoc
new file mode 100644
index 0000000000..ccd35f10c2
--- /dev/null
+++ b/Documentation/git-clone.adoc
@@ -0,0 +1,408 @@
+git-clone(1)
+============
+
+NAME
+----
+git-clone - Clone a repository into a new directory
+
+
+SYNOPSIS
+--------
+[synopsis]
+git clone [--template=<template-directory>]
+	  [-l] [-s] [--no-hardlinks] [-q] [-n] [--bare] [--mirror]
+	  [-o <name>] [-b <name>] [-u <upload-pack>] [--reference <repository>]
+	  [--dissociate] [--separate-git-dir <git-dir>]
+	  [--depth <depth>] [--[no-]single-branch] [--no-tags]
+	  [--recurse-submodules[=<pathspec>]] [--[no-]shallow-submodules]
+	  [--[no-]remote-submodules] [--jobs <n>] [--sparse] [--[no-]reject-shallow]
+	  [--filter=<filter-spec>] [--also-filter-submodules]] [--] <repository>
+	  [<directory>]
+
+DESCRIPTION
+-----------
+
+Clones a repository into a newly created directory, creates
+remote-tracking branches for each branch in the cloned repository
+(visible using `git branch --remotes`), and creates and checks out an
+initial branch that is forked from the cloned repository's
+currently active branch.
+
+After the clone, a plain `git fetch` without arguments will update
+all the remote-tracking branches, and a `git pull` without
+arguments will in addition merge the remote master branch into the
+current master branch, if any (this is untrue when `--single-branch`
+is given; see below).
+
+This default configuration is achieved by creating references to
+the remote branch heads under `refs/remotes/origin` and
+by initializing `remote.origin.url` and `remote.origin.fetch`
+configuration variables.
+
+
+OPTIONS
+-------
+`-l`::
+`--local`::
+	When the repository to clone from is on a local machine,
+	this flag bypasses the normal "Git aware" transport
+	mechanism and clones the repository by making a copy of
+	`HEAD` and everything under objects and refs directories.
+	The files under `.git/objects/` directory are hardlinked
+	to save space when possible.
++
+If the repository is specified as a local path (e.g., `/path/to/repo`),
+this is the default, and `--local` is essentially a no-op.  If the
+repository is specified as a URL, then this flag is ignored (and we
+never use the local optimizations).  Specifying `--no-local` will
+override the default when `/path/to/repo` is given, using the regular
+Git transport instead.
++
+If the repository's `$GIT_DIR/objects` has symbolic links or is a
+symbolic link, the clone will fail. This is a security measure to
+prevent the unintentional copying of files by dereferencing the symbolic
+links.
++
+This option does not work with repositories owned by other users for security
+reasons, and `--no-local` must be specified for the clone to succeed.
++
+*NOTE*: this operation can race with concurrent modification to the
+source repository, similar to running `cp -r <src> <dst>` while modifying
+_<src>_.
+
+`--no-hardlinks`::
+	Force the cloning process from a repository on a local
+	filesystem to copy the files under the `.git/objects`
+	directory instead of using hardlinks. This may be desirable
+	if you are trying to make a back-up of your repository.
+
+`-s`::
+`--shared`::
+	When the repository to clone is on the local machine,
+	instead of using hard links, automatically setup
+	`.git/objects/info/alternates` to share the objects
+	with the source repository.  The resulting repository
+	starts out without any object of its own.
++
+*NOTE*: this is a possibly dangerous operation; do *not* use
+it unless you understand what it does. If you clone your
+repository using this option and then delete branches (or use any
+other Git command that makes any existing commit unreferenced) in the
+source repository, some objects may become unreferenced (or dangling).
+These objects may be removed by normal Git operations (such as `git commit`)
+which automatically call `git maintenance run --auto`. (See
+linkgit:git-maintenance[1].) If these objects are removed and were referenced
+by the cloned repository, then the cloned repository will become corrupt.
++
+Note that running `git repack` without the `--local` option in a repository
+cloned with `--shared` will copy objects from the source repository into a pack
+in the cloned repository, removing the disk space savings of `clone --shared`.
+It is safe, however, to run `git gc`, which uses the `--local` option by
+default.
++
+If you want to break the dependency of a repository cloned with `--shared` on
+its source repository, you can simply run `git repack -a` to copy all
+objects from the source repository into a pack in the cloned repository.
+
+`--reference[-if-able] <repository>`::
+	If the reference _<repository>_ is on the local machine,
+	automatically setup `.git/objects/info/alternates` to
+	obtain objects from the reference _<repository>_.  Using
+	an already existing repository as an alternate will
+	require fewer objects to be copied from the repository
+	being cloned, reducing network and local storage costs.
+	When using the `--reference-if-able`, a non existing
+	directory is skipped with a warning instead of aborting
+	the clone.
++
+*NOTE*: see the NOTE for the `--shared` option, and also the
+`--dissociate` option.
+
+`--dissociate`::
+	Borrow the objects from reference repositories specified
+	with the `--reference` options only to reduce network
+	transfer, and stop borrowing from them after a clone is made
+	by making necessary local copies of borrowed objects.  This
+	option can also be used when cloning locally from a
+	repository that already borrows objects from another
+	repository--the new repository will borrow objects from the
+	same repository, and this option can be used to stop the
+	borrowing.
+
+`-q`::
+`--quiet`::
+	Operate quietly.  Progress is not reported to the standard
+	error stream.
+
+`-v`::
+`--verbose`::
+	Run verbosely. Does not affect the reporting of progress status
+	to the standard error stream.
+
+`--progress`::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless `--quiet`
+	is specified. This flag forces progress status even if the
+	standard error stream is not directed to a terminal.
+
+`--server-option=<option>`::
+	Transmit the given string to the server when communicating using
+	protocol version 2.  The given string must not contain a NUL or LF
+	character.  The server's handling of server options, including
+	unknown ones, is server-specific.
+	When multiple `--server-option=<option>` are given, they are all
+	sent to the other side in the order listed on the command line.
+	When no ++--server-option=++__<option>__ is given from the command
+	line, the values of configuration variable `remote.<name>.serverOption`
+	are used instead.
+
+`-n`::
+`--no-checkout`::
+	No checkout of `HEAD` is performed after the clone is complete.
+
+`--`[`no-`]`reject-shallow`::
+	Fail if the source repository is a shallow repository.
+	The `clone.rejectShallow` configuration variable can be used to
+	specify the default.
+
+`--bare`::
+	Make a 'bare' Git repository.  That is, instead of
+	creating _<directory>_ and placing the administrative
+	files in `<directory>/.git`, make the _<directory>_
+	itself the `$GIT_DIR`. This obviously implies the `--no-checkout`
+	because there is nowhere to check out the working tree.
+	Also the branch heads at the remote are copied directly
+	to corresponding local branch heads, without mapping
+	them to `refs/remotes/origin/`.  When this option is
+	used, neither remote-tracking branches nor the related
+	configuration variables are created.
+
+`--sparse`::
+	Employ a sparse-checkout, with only files in the toplevel
+	directory initially being present.  The
+	linkgit:git-sparse-checkout[1] command can be used to grow the
+	working directory as needed.
+
+`--filter=<filter-spec>`::
+	Use the partial clone feature and request that the server sends
+	a subset of reachable objects according to a given object filter.
+	When using `--filter`, the supplied _<filter-spec>_ is used for
+	the partial clone filter. For example, `--filter=blob:none` will
+	filter out all blobs (file contents) until needed by Git. Also,
+	`--filter=blob:limit=<size>` will filter out all blobs of size
+	at least _<size>_. For more details on filter specifications, see
+	the `--filter` option in linkgit:git-rev-list[1].
+
+`--also-filter-submodules`::
+	Also apply the partial clone filter to any submodules in the repository.
+	Requires `--filter` and `--recurse-submodules`. This can be turned on by
+	default by setting the `clone.filterSubmodules` config option.
+
+`--mirror`::
+	Set up a mirror of the source repository.  This implies `--bare`.
+	Compared to `--bare`, `--mirror` not only maps local branches of the
+	source to local branches of the target, it maps all refs (including
+	remote-tracking branches, notes etc.) and sets up a refspec configuration such
+	that all these refs are overwritten by a `git remote update` in the
+	target repository.
+
+`-o` _<name>_::
+`--origin` _<name>_::
+	Instead of using the remote name `origin` to keep track of the upstream
+	repository, use _<name>_.  Overrides `clone.defaultRemoteName` from the
+	config.
+
+`-b` _<name>_::
+`--branch` _<name>_::
+	Instead of pointing the newly created `HEAD` to the branch pointed
+	to by the cloned repository's `HEAD`, point to _<name>_ branch
+	instead. In a non-bare repository, this is the branch that will
+	be checked out.
+	`--branch` can also take tags and detaches the `HEAD` at that commit
+	in the resulting repository.
+
+`-u` _<upload-pack>_::
+`--upload-pack` _<upload-pack>_::
+	When given, and the repository to clone from is accessed
+	via ssh, this specifies a non-default path for the command
+	run on the other end.
+
+`--template=<template-directory>`::
+	Specify the directory from which templates will be used;
+	(See the "TEMPLATE DIRECTORY" section of linkgit:git-init[1].)
+
+`-c` `<key>=<value>`::
+`--config` `<key>=<value>`::
+	Set a configuration variable in the newly-created repository;
+	this takes effect immediately after the repository is
+	initialized, but before the remote history is fetched or any
+	files checked out.  The _<key>_ is in the same format as expected by
+	linkgit:git-config[1] (e.g., `core.eol=true`). If multiple
+	values are given for the same key, each value will be written to
+	the config file. This makes it safe, for example, to add
+	additional fetch refspecs to the origin remote.
++
+Due to limitations of the current implementation, some configuration
+variables do not take effect until after the initial fetch and checkout.
+Configuration variables known to not take effect are:
+`remote.<name>.mirror` and `remote.<name>.tagOpt`.  Use the
+corresponding `--mirror` and `--no-tags` options instead.
+
+`--depth <depth>`::
+	Create a 'shallow' clone with a history truncated to the
+	specified number of commits. Implies `--single-branch` unless
+	`--no-single-branch` is given to fetch the histories near the
+	tips of all branches. If you want to clone submodules shallowly,
+	also pass `--shallow-submodules`.
+
+`--shallow-since=<date>`::
+	Create a shallow clone with a history after the specified time.
+
+`--shallow-exclude=<ref>`::
+	Create a shallow clone with a history, excluding commits
+	reachable from a specified remote branch or tag.  This option
+	can be specified multiple times.
+
+`--[no-]single-branch`::
+	Clone only the history leading to the tip of a single branch,
+	either specified by the `--branch` option or the primary
+	branch remote's `HEAD` points at.
+	Further fetches into the resulting repository will only update the
+	remote-tracking branch for the branch this option was used for the
+	initial cloning.  If the `HEAD` at the remote did not point at any
+	branch when `--single-branch` clone was made, no remote-tracking
+	branch is created.
+
+`--no-tags`::
+	Don't clone any tags, and set
+	`remote.<remote>.tagOpt=--no-tags` in the config, ensuring
+	that future `git pull` and `git fetch` operations won't follow
+	any tags. Subsequent explicit tag fetches will still work,
+	(see linkgit:git-fetch[1]).
++
+Can be used in conjunction with `--single-branch` to clone and
+maintain a branch with no references other than a single cloned
+branch. This is useful e.g. to maintain minimal clones of the default
+branch of some repository for search indexing.
+
+`--recurse-submodules[=<pathspec>]`::
+	After the clone is created, initialize and clone submodules
+	within based on the provided _<pathspec>_.  If no `=<pathspec>` is
+	provided, all submodules are initialized and cloned.
+	This option can be given multiple times for pathspecs consisting
+	of multiple entries.  The resulting clone has `submodule.active` set to
+	the provided pathspec, or "`.`" (meaning all submodules) if no
+	pathspec is provided.
++
+Submodules are initialized and cloned using their default settings. This is
+equivalent to running
+`git submodule update --init --recursive <pathspec>` immediately after
+the clone is finished. This option is ignored if the cloned repository does
+not have a worktree/checkout (i.e. if any of `--no-checkout`/`-n`, `--bare`,
+or `--mirror` is given)
+
+`--[no-]shallow-submodules`::
+	All submodules which are cloned will be shallow with a depth of 1.
+
+`--[no-]remote-submodules`::
+	All submodules which are cloned will use the status of the submodule's
+	remote-tracking branch to update the submodule, rather than the
+	superproject's recorded SHA-1. Equivalent to passing `--remote` to
+	`git submodule update`.
+
+`--separate-git-dir=<git-dir>`::
+	Instead of placing the cloned repository where it is supposed
+	to be, place the cloned repository at the specified directory,
+	then make a filesystem-agnostic Git symbolic link to there.
+	The result is Git repository can be separated from working
+	tree.
+
+`--ref-format=<ref-format>`::
+
+Specify the given ref storage format for the repository. The valid values are:
++
+include::ref-storage-format.adoc[]
+
+`-j` _<n>_::
+`--jobs` _<n>_::
+	The number of submodules fetched at the same time.
+	Defaults to the `submodule.fetchJobs` option.
+
+_<repository>_::
+	The (possibly remote) _<repository>_ to clone from.  See the
+	<<URLS,GIT URLS>> section below for more information on specifying
+	repositories.
+
+_<directory>_::
+	The name of a new directory to clone into.  The "humanish"
+	part of the source repository is used if no _<directory>_ is
+	explicitly given (`repo` for `/path/to/repo.git` and `foo`
+	for `host.xz:foo/.git`).  Cloning into an existing directory
+	is only allowed if the directory is empty.
+
+`--bundle-uri=<uri>`::
+	Before fetching from the remote, fetch a bundle from the given
+	_<uri>_ and unbundle the data into the local repository. The refs
+	in the bundle will be stored under the hidden `refs/bundle/*`
+	namespace. This option is incompatible with `--depth`,
+	`--shallow-since`, and `--shallow-exclude`.
+
+:git-clone: 1
+include::urls.adoc[]
+
+EXAMPLES
+--------
+
+* Clone from upstream:
++
+------------
+$ git clone git://git.kernel.org/pub/scm/.../linux.git my-linux
+$ cd my-linux
+$ make
+------------
+
+
+* Make a local clone that borrows from the current directory, without checking things out:
++
+------------
+$ git clone -l -s -n . ../copy
+$ cd ../copy
+$ git show-branch
+------------
+
+
+* Clone from upstream while borrowing from an existing local directory:
++
+------------
+$ git clone --reference /git/linux.git \
+	git://git.kernel.org/pub/scm/.../linux.git \
+	my-linux
+$ cd my-linux
+------------
+
+
+* Create a bare repository to publish your changes to the public:
++
+------------
+$ git clone --bare -l /home/proj/.git /pub/scm/proj.git
+------------
+
+* Clone a local repository from a different user:
++
+------------
+$ git clone --no-local /home/otheruser/proj.git /pub/scm/proj.git
+------------
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/init.adoc[]
+
+include::config/clone.adoc[]
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-column.adoc b/Documentation/git-column.adoc
new file mode 100644
index 0000000000..3ecdb96d96
--- /dev/null
+++ b/Documentation/git-column.adoc
@@ -0,0 +1,86 @@
+git-column(1)
+=============
+
+NAME
+----
+git-column - Display data in columns
+
+SYNOPSIS
+--------
+[verse]
+'git column' [--command=<name>] [--[raw-]mode=<mode>] [--width=<width>]
+	     [--indent=<string>] [--nl=<string>] [--padding=<n>]
+
+DESCRIPTION
+-----------
+This command formats the lines of its standard input into a table with
+multiple columns. Each input line occupies one cell of the table. It
+is used internally by other git commands to format output into
+columns.
+
+OPTIONS
+-------
+--command=<name>::
+	Look up layout mode using configuration variable column.<name> and
+	column.ui.
+
+--mode=<mode>::
+	Specify layout mode. See configuration variable column.ui for option
+	syntax in linkgit:git-config[1].
+
+--raw-mode=<n>::
+	Same as --mode but take mode encoded as a number. This is mainly used
+	by other commands that have already parsed layout mode.
+
+--width=<width>::
+	Specify the terminal width. By default 'git column' will detect the
+	terminal width, or fall back to 80 if it is unable to do so.
+
+--indent=<string>::
+	String to be printed at the beginning of each line.
+
+--nl=<string>::
+	String to be printed at the end of each line,
+	including newline character.
+
+--padding=<N>::
+	The number of spaces between columns. One space by default.
+
+EXAMPLES
+--------
+
+Format data by columns:
+------------
+$ seq 1 24 | git column --mode=column --padding=5
+1      4      7      10     13     16     19     22
+2      5      8      11     14     17     20     23
+3      6      9      12     15     18     21     24
+------------
+
+Format data by rows:
+------------
+$ seq 1 21 | git column --mode=row --padding=5
+1      2      3      4      5      6      7
+8      9      10     11     12     13     14
+15     16     17     18     19     20     21
+------------
+
+List some tags in a table with unequal column widths:
+------------
+$ git tag --list 'v2.4.*' --column=row,dense
+v2.4.0  v2.4.0-rc0  v2.4.0-rc1  v2.4.0-rc2  v2.4.0-rc3
+v2.4.1  v2.4.10     v2.4.11     v2.4.12     v2.4.2
+v2.4.3  v2.4.4      v2.4.5      v2.4.6      v2.4.7
+v2.4.8  v2.4.9
+------------
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/column.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-commit-graph.adoc b/Documentation/git-commit-graph.adoc
new file mode 100644
index 0000000000..5921d6967b
--- /dev/null
+++ b/Documentation/git-commit-graph.adoc
@@ -0,0 +1,163 @@
+git-commit-graph(1)
+===================
+
+NAME
+----
+git-commit-graph - Write and verify Git commit-graph files
+
+
+SYNOPSIS
+--------
+[verse]
+'git commit-graph verify' [--object-dir <dir>] [--shallow] [--[no-]progress]
+'git commit-graph write' [--object-dir <dir>] [--append]
+			[--split[=<strategy>]] [--reachable | --stdin-packs | --stdin-commits]
+			[--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress]
+			<split-options>
+
+
+DESCRIPTION
+-----------
+
+Manage the serialized commit-graph file.
+
+
+OPTIONS
+-------
+--object-dir::
+	Use given directory for the location of packfiles and commit-graph
+	file. This parameter exists to specify the location of an alternate
+	that only has the objects directory, not a full `.git` directory. The
+	commit-graph file is expected to be in the `<dir>/info` directory and
+	the packfiles are expected to be in `<dir>/pack`. If the directory
+	could not be made into an absolute path, or does not match any known
+	object directory, `git commit-graph ...` will exit with non-zero
+	status.
+
+--[no-]progress::
+	Turn progress on/off explicitly. If neither is specified, progress is
+	shown if standard error is connected to a terminal.
+
+COMMANDS
+--------
+'write'::
+
+Write a commit-graph file based on the commits found in packfiles. If
+the config option `core.commitGraph` is disabled, then this command will
+output a warning, then return success without writing a commit-graph file.
++
+With the `--stdin-packs` option, generate the new commit graph by
+walking objects only in the specified pack-indexes. (Cannot be combined
+with `--stdin-commits` or `--reachable`.)
++
+With the `--stdin-commits` option, generate the new commit graph by
+walking commits starting at the commits specified in stdin as a list
+of OIDs in hex, one OID per line. OIDs that resolve to non-commits
+(either directly, or by peeling tags) are silently ignored. OIDs that
+are malformed, or do not exist generate an error. (Cannot be combined
+with `--stdin-packs` or `--reachable`.)
++
+With the `--reachable` option, generate the new commit graph by walking
+commits starting at all refs. (Cannot be combined with `--stdin-commits`
+or `--stdin-packs`.)
++
+With the `--append` option, include all commits that are present in the
+existing commit-graph file.
++
+With the `--changed-paths` option, compute and write information about the
+paths changed between a commit and its first parent. This operation can
+take a while on large repositories. It provides significant performance gains
+for getting history of a directory or a file with `git log -- <path>`. If
+this option is given, future commit-graph writes will automatically assume
+that this option was intended. Use `--no-changed-paths` to stop storing this
+data.
++
+With the `--max-new-filters=<n>` option, generate at most `n` new Bloom
+filters (if `--changed-paths` is specified). If `n` is `-1`, no limit is
+enforced. Only commits present in the new layer count against this
+limit. To retroactively compute Bloom filters over earlier layers, it is
+advised to use `--split=replace`.  Overrides the `commitGraph.maxNewFilters`
+configuration.
++
+With the `--split[=<strategy>]` option, write the commit-graph as a
+chain of multiple commit-graph files stored in
+`<dir>/info/commit-graphs`. Commit-graph layers are merged based on the
+strategy and other splitting options. The new commits not already in the
+commit-graph are added in a new "tip" file. This file is merged with the
+existing file if the following merge conditions are met:
++
+* If `--split=no-merge` is specified, a merge is never performed, and
+the remaining options are ignored. `--split=replace` overwrites the
+existing chain with a new one. A bare `--split` defers to the remaining
+options. (Note that merging a chain of commit graphs replaces the
+existing chain with a length-1 chain where the first and only
+incremental holds the entire graph).
++
+* If `--size-multiple=<X>` is not specified, let `X` equal 2. If the new
+tip file would have `N` commits and the previous tip has `M` commits and
+`X` times `N` is greater than  `M`, instead merge the two files into a
+single file.
++
+* If `--max-commits=<M>` is specified with `M` a positive integer, and the
+new tip file would have more than `M` commits, then instead merge the new
+tip with the previous tip.
++
+Finally, if `--expire-time=<datetime>` is not specified, let `datetime`
+be the current time. After writing the split commit-graph, delete all
+unused commit-graph whose modified times are older than `datetime`.
+
+'verify'::
+
+Read the commit-graph file and verify its contents against the object
+database. Used to check for corrupted data.
++
+With the `--shallow` option, only check the tip commit-graph file in
+a chain of split commit-graphs.
+
+
+EXAMPLES
+--------
+
+* Write a commit-graph file for the packed commits in your local `.git`
+  directory.
++
+------------------------------------------------
+$ git commit-graph write
+------------------------------------------------
+
+* Write a commit-graph file, extending the current commit-graph file
+  using commits in `<pack-index>`.
++
+------------------------------------------------
+$ echo <pack-index> | git commit-graph write --stdin-packs
+------------------------------------------------
+
+* Write a commit-graph file containing all reachable commits.
++
+------------------------------------------------
+$ git show-ref -s | git commit-graph write --stdin-commits
+------------------------------------------------
+
+* Write a commit-graph file containing all commits in the current
+  commit-graph file along with those reachable from `HEAD`.
++
+------------------------------------------------
+$ git rev-parse HEAD | git commit-graph write --stdin-commits --append
+------------------------------------------------
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/commitgraph.adoc[]
+
+
+FILE FORMAT
+-----------
+
+see linkgit:gitformat-commit-graph[5].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-commit-tree.adoc b/Documentation/git-commit-tree.adoc
new file mode 100644
index 0000000000..6472921e14
--- /dev/null
+++ b/Documentation/git-commit-tree.adoc
@@ -0,0 +1,101 @@
+git-commit-tree(1)
+==================
+
+NAME
+----
+git-commit-tree - Create a new commit object
+
+
+SYNOPSIS
+--------
+[verse]
+'git commit-tree' <tree> [(-p <parent>)...]
+'git commit-tree' [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]
+		  [(-F <file>)...] <tree>
+
+
+DESCRIPTION
+-----------
+This is usually not what an end user wants to run directly.  See
+linkgit:git-commit[1] instead.
+
+Creates a new commit object based on the provided tree object and
+emits the new commit object id on stdout. The log message is read
+from the standard input, unless `-m` or `-F` options are given.
+
+The `-m` and `-F` options can be given any number of times, in any
+order. The commit log message will be composed in the order in which
+the options are given.
+
+A commit object may have any number of parents. With exactly one
+parent, it is an ordinary commit. Having more than one parent makes
+the commit a merge between several lines of history. Initial (root)
+commits have no parents.
+
+While a tree represents a particular directory state of a working
+directory, a commit represents that state in "time", and explains how
+to get there.
+
+Normally a commit would identify a new "HEAD" state, and while Git
+doesn't care where you save the note about that state, in practice we
+tend to just write the result to the file that is pointed at by
+`.git/HEAD`, so that we can always see what the last committed
+state was.
+
+OPTIONS
+-------
+<tree>::
+	An existing tree object.
+
+-p <parent>::
+	Each `-p` indicates the id of a parent commit object.
+
+-m <message>::
+	A paragraph in the commit log message. This can be given more than
+	once and each <message> becomes its own paragraph.
+
+-F <file>::
+	Read the commit log message from the given file. Use `-` to read
+	from the standard input. This can be given more than once and the
+	content of each file becomes its own paragraph.
+
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+--no-gpg-sign::
+	GPG-sign commits. The `keyid` argument is optional and
+	defaults to the committer identity; if specified, it must be
+	stuck to the option without a space. `--no-gpg-sign` is useful to
+	countermand a `--gpg-sign` option given earlier on the command line.
+
+Commit Information
+------------------
+
+A commit encapsulates:
+
+- all parent object ids
+- author name, email and date
+- committer name and email and the commit time.
+
+A commit comment is read from stdin. If a changelog
+entry is not provided via "<" redirection, 'git commit-tree' will just wait
+for one to be entered and terminated with ^D.
+
+include::date-formats.adoc[]
+
+Discussion
+----------
+
+include::i18n.adoc[]
+
+FILES
+-----
+/etc/mailname
+
+SEE ALSO
+--------
+linkgit:git-write-tree[1]
+linkgit:git-commit[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-commit.adoc b/Documentation/git-commit.adoc
new file mode 100644
index 0000000000..8946b05041
--- /dev/null
+++ b/Documentation/git-commit.adoc
@@ -0,0 +1,589 @@
+git-commit(1)
+=============
+
+NAME
+----
+git-commit - Record changes to the repository
+
+SYNOPSIS
+--------
+[synopsis]
+git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]
+	   [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]
+	   [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
+	   [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
+	   [--date=<date>] [--cleanup=<mode>] [--[no-]status]
+	   [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]
+	   [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]
+	   [--] [<pathspec>...]
+
+DESCRIPTION
+-----------
+Create a new commit containing the current contents of the index and
+the given log message describing the changes. The new commit is a
+direct child of HEAD, usually the tip of the current branch, and the
+branch is updated to point to it (unless no branch is associated with
+the working tree, in which case `HEAD` is "detached" as described in
+linkgit:git-checkout[1]).
+
+The content to be committed can be specified in several ways:
+
+1. by using linkgit:git-add[1] to incrementally "add" changes to the
+   index before using the `commit` command (Note: even modified files
+   must be "added");
+
+2. by using linkgit:git-rm[1] to remove files from the working tree
+   and the index, again before using the `commit` command;
+
+3. by listing files as arguments to the `commit` command
+   (without `--interactive` or `--patch` switch), in which
+   case the commit will ignore changes staged in the index, and instead
+   record the current content of the listed files (which must already
+   be known to Git);
+
+4. by using the `-a` switch with the `commit` command to automatically
+   "add" changes from all known files (i.e. all files that are already
+   listed in the index) and to automatically "rm" files in the index
+   that have been removed from the working tree, and then perform the
+   actual commit;
+
+5. by using the `--interactive` or `--patch` switches with the `commit` command
+   to decide one by one which files or hunks should be part of the commit
+   in addition to contents in the index,
+   before finalizing the operation. See the ``Interactive Mode'' section of
+   linkgit:git-add[1] to learn how to operate these modes.
+
+The `--dry-run` option can be used to obtain a
+summary of what is included by any of the above for the next
+commit by giving the same set of parameters (options and paths).
+
+If you make a commit and then find a mistake immediately after
+that, you can recover from it with `git reset`.
+
+:git-commit: 1
+
+OPTIONS
+-------
+`-a`::
+`--all`::
+	Automatically stage files that have
+	been modified and deleted, but new files you have not
+	told Git about are not affected.
+
+`-p`::
+`--patch`::
+	Use the interactive patch selection interface to choose
+	which changes to commit. See linkgit:git-add[1] for
+	details.
+
+`-C <commit>`::
+`--reuse-message=<commit>`::
+	Take an existing _<commit>_ object, and reuse the log message
+	and the authorship information (including the timestamp)
+	when creating the commit.
+
+`-c <commit>`::
+`--reedit-message=<commit>`::
+	Like `-C`, but with `-c` the editor is invoked, so that
+	the user can further edit the commit message.
+
+`--fixup=[(amend|reword):]<commit>`::
+	Create a new commit which "fixes up" _<commit>_ when applied with
+	`git rebase --autosquash`. Plain `--fixup=<commit>` creates a
+	"fixup!" commit which changes the content of _<commit>_ but leaves
+	its log message untouched. `--fixup=amend:<commit>` is similar but
+	creates an "amend!" commit which also replaces the log message of
+	_<commit>_ with the log message of the "amend!" commit.
+	`--fixup=reword:<commit>` creates an "amend!" commit which
+	replaces the log message of _<commit>_ with its own log message
+	but makes no changes to the content of _<commit>_.
++
+The commit created by plain `--fixup=<commit>` has a subject
+composed of "fixup!" followed by the subject line from _<commit>_,
+and is recognized specially by `git rebase --autosquash`. The `-m`
+option may be used to supplement the log message of the created
+commit, but the additional commentary will be thrown away once the
+"fixup!" commit is squashed into _<commit>_ by
+`git rebase --autosquash`.
++
+The commit created by `--fixup=amend:<commit>` is similar but its
+subject is instead prefixed with "amend!". The log message of
+_<commit>_ is copied into the log message of the "amend!" commit and
+opened in an editor so it can be refined. When `git rebase
+--autosquash` squashes the "amend!" commit into _<commit>_, the
+log message of _<commit>_ is replaced by the refined log message
+from the "amend!" commit. It is an error for the "amend!" commit's
+log message to be empty unless `--allow-empty-message` is
+specified.
++
+`--fixup=reword:<commit>` is shorthand for `--fixup=amend:<commit>
+ --only`. It creates an "amend!" commit with only a log message
+(ignoring any changes staged in the index). When squashed by `git
+rebase --autosquash`, it replaces the log message of _<commit>_
+without making any other changes.
++
+Neither "fixup!" nor "amend!" commits change authorship of
+_<commit>_ when applied by `git rebase --autosquash`.
+See linkgit:git-rebase[1] for details.
+
+`--squash=<commit>`::
+	Construct a commit message for use with `git rebase --autosquash`.
+	The commit message subject line is taken from the specified
+	commit with a prefix of "squash! ".  Can be used with additional
+	commit message options (`-m`/`-c`/`-C`/`-F`). See
+	linkgit:git-rebase[1] for details.
+
+`--reset-author`::
+	When used with `-C`/`-c`/`--amend` options, or when committing after a
+	conflicting cherry-pick, declare that the authorship of the
+	resulting commit now belongs to the committer. This also renews
+	the author timestamp.
+
+`--short`::
+	When doing a dry-run, give the output in the short-format. See
+	linkgit:git-status[1] for details. Implies `--dry-run`.
+
+`--branch`::
+	Show the branch and tracking info even in short-format.
+
+`--porcelain`::
+	When doing a dry-run, give the output in a porcelain-ready
+	format. See linkgit:git-status[1] for details. Implies
+	`--dry-run`.
+
+`--long`::
+	When doing a dry-run, give the output in the long-format.
+	Implies `--dry-run`.
+
+`-z`::
+`--null`::
+	When showing `short` or `porcelain` status output, print the
+	filename verbatim and terminate the entries with _NUL_, instead of _LF_.
+	If no format is given, implies the `--porcelain` output format.
+	Without the `-z` option, filenames with "unusual" characters are
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]).
+
+`-F <file>`::
+`--file=<file>`::
+	Take the commit message from _<file>_.  Use '-' to
+	read the message from the standard input.
+
+`--author=<author>`::
+	Override the commit author. Specify an explicit author using the
+	standard `A U Thor <author@xxxxxxxxxxx>` format. Otherwise _<author>_
+	is assumed to be a pattern and is used to search for an existing
+	commit by that author (i.e. `git rev-list --all -i --author=<author>`);
+	the commit author is then copied from the first such commit found.
+
+`--date=<date>`::
+	Override the author date used in the commit.
+
+`-m <msg>`::
+`--message=<msg>`::
+	Use _<msg>_ as the commit message.
+	If multiple `-m` options are given, their values are
+	concatenated as separate paragraphs.
++
+The `-m` option is mutually exclusive with `-c`, `-C`, and `-F`.
+
+`-t <file>`::
+`--template=<file>`::
+	When editing the commit message, start the editor with the
+	contents in _<file>_.  The `commit.template` configuration
+	variable is often used to give this option implicitly to the
+	command.  This mechanism can be used by projects that want to
+	guide participants with some hints on what to write in the message
+	in what order.  If the user exits the editor without editing the
+	message, the commit is aborted.  This has no effect when a message
+	is given by other means, e.g. with the `-m` or `-F` options.
+
+include::signoff-option.adoc[]
+
+`--trailer <token>[(=|:)<value>]`::
+	Specify a (_<token>_, _<value>_) pair that should be applied as a
+	trailer. (e.g. `git commit --trailer "Signed-off-by:C O Mitter \
+	<committer@xxxxxxxxxxx>" --trailer "Helped-by:C O Mitter \
+	<committer@xxxxxxxxxxx>"` will add the `Signed-off-by` trailer
+	and the `Helped-by` trailer to the commit message.)
+	The `trailer.*` configuration variables
+	(linkgit:git-interpret-trailers[1]) can be used to define if
+	a duplicated trailer is omitted, where in the run of trailers
+	each trailer would appear, and other details.
+
+`-n`::
+`--[no-]verify`::
+	Bypass the `pre-commit` and `commit-msg` hooks.
+	See also linkgit:githooks[5].
+
+`--allow-empty`::
+	Usually recording a commit that has the exact same tree as its
+	sole parent commit is a mistake, and the command prevents you
+	from making such a commit.  This option bypasses the safety, and
+	is primarily for use by foreign SCM interface scripts.
+
+`--allow-empty-message`::
+	Create a commit with an empty commit message without using plumbing
+	commands like linkgit:git-commit-tree[1]. Like `--allow-empty`, this
+	command is primarily for use by foreign SCM interface scripts.
+
+`--cleanup=<mode>`::
+	Determine how the supplied commit message should be
+	cleaned up before committing.  The '<mode>' can be `strip`,
+	`whitespace`, `verbatim`, `scissors` or `default`.
++
+--
+`strip`::
+	Strip leading and trailing empty lines, trailing whitespace,
+	commentary and collapse consecutive empty lines.
+`whitespace`::
+	Same as `strip` except #commentary is not removed.
+`verbatim`::
+	Do not change the message at all.
+`scissors`::
+	Same as `whitespace` except that everything from (and including)
+	the line found below is truncated, if the message is to be edited.
+	"`#`" can be customized with `core.commentChar`.
+
+		# ------------------------ >8 ------------------------
+
+`default`::
+	Same as `strip` if the message is to be edited.
+	Otherwise `whitespace`.
+--
++
+The default can be changed by the `commit.cleanup` configuration
+variable (see linkgit:git-config[1]).
+
+`-e`::
+`--edit`::
+	Let the user further edit the message taken from _<file>_
+	with `-F <file>`, command line with `-m <message>`, and
+	from _<commit>_ with `-C <commit>`.
+
+`--no-edit`::
+	Use the selected commit message without launching an editor.
+	For example, `git commit --amend --no-edit` amends a commit
+	without changing its commit message.
+
+`--amend`::
+	Replace the tip of the current branch by creating a new
+	commit. The recorded tree is prepared as usual (including
+	the effect of the `-i` and `-o` options and explicit
+	pathspec), and the message from the original commit is used
+	as the starting point, instead of an empty message, when no
+	other message is specified from the command line via options
+	such as `-m`, `-F`, `-c`, etc.  The new commit has the same
+	parents and author as the current one (the `--reset-author`
+	option can countermand this).
++
+--
+It is a rough equivalent for:
+------
+	$ git reset --soft HEAD^
+	$ ... do something else to come up with the right tree ...
+	$ git commit -c ORIG_HEAD
+
+------
+but can be used to amend a merge commit.
+--
++
+You should understand the implications of rewriting history if you
+amend a commit that has already been published.  (See the "RECOVERING
+FROM UPSTREAM REBASE" section in linkgit:git-rebase[1].)
+
+`--no-post-rewrite`::
+	Bypass the `post-rewrite` hook.
+
+`-i`::
+`--include`::
+	Before making a commit out of staged contents so far,
+	stage the contents of paths given on the command line
+	as well.  This is usually not what you want unless you
+	are concluding a conflicted merge.
+
+`-o`::
+`--only`::
+	Make a commit by taking the updated working tree contents
+	of the paths specified on the
+	command line, disregarding any contents that have been
+	staged for other paths. This is the default mode of operation of
+	`git commit` if any paths are given on the command line,
+	in which case this option can be omitted.
+	If this option is specified together with `--amend`, then
+	no paths need to be specified, which can be used to amend
+	the last commit without committing changes that have
+	already been staged. If used together with `--allow-empty`
+	paths are also not required, and an empty commit will be created.
+
+`--pathspec-from-file=<file>`::
+	Pass pathspec in _<file>_ instead of commandline args. If
+	_<file>_ is exactly `-` then standard input is used. Pathspec
+	elements are separated by _LF_ or _CR_/_LF_. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+`--pathspec-file-nul`::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with _NUL_ character and all other characters are taken
+	literally (including newlines and quotes).
+
+`-u[<mode>]`::
+`--untracked-files[=<mode>]`::
+	Show untracked files.
++
+--
+The _<mode>_ parameter is optional (defaults to `all`), and is used to
+specify the handling of untracked files; when `-u` is not used, the
+default is `normal`, i.e. show untracked files and directories.
+
+The possible options are:
+
+`no`:: Show no untracked files
+`normal`:: Shows untracked files and directories
+`all`:: Also shows individual files in untracked directories.
+
+All usual spellings for Boolean value `true` are taken as `normal`
+and `false` as `no`.
+The default can be changed using the `status.showUntrackedFiles`
+configuration variable documented in linkgit:git-config[1].
+--
+
+`-v`::
+`--verbose`::
+	Show unified diff between the `HEAD` commit and what
+	would be committed at the bottom of the commit message
+	template to help the user describe the commit by reminding
+	what changes the commit has.
+	Note that this diff output doesn't have its
+	lines prefixed with `#`. This diff will not be a part
+	of the commit message. See the `commit.verbose` configuration
+	variable in linkgit:git-config[1].
++
+If specified twice, show in addition the unified diff between
+what would be committed and the worktree files, i.e. the unstaged
+changes to tracked files.
+
+`-q`::
+`--quiet`::
+	Suppress commit summary message.
+
+`--dry-run`::
+	Do not create a commit, but show a list of paths that are
+	to be committed, paths with local changes that will be left
+	uncommitted and paths that are untracked.
+
+`--status`::
+	Include the output of linkgit:git-status[1] in the commit
+	message template when using an editor to prepare the commit
+	message.  Defaults to on, but can be used to override
+	configuration variable `commit.status`.
+
+`--no-status`::
+	Do not include the output of linkgit:git-status[1] in the
+	commit message template when using an editor to prepare the
+	default commit message.
+
+`-S[<key-id>]`::
+`--gpg-sign[=<key-id>]`::
+`--no-gpg-sign`::
+	GPG-sign commits. The _<key-id>_ is optional and
+	defaults to the committer identity; if specified, it must be
+	stuck to the option without a space. `--no-gpg-sign` is useful to
+	countermand both `commit.gpgSign` configuration variable, and
+	earlier `--gpg-sign`.
+
+`--`::
+	Do not interpret any more arguments as options.
+
+`<pathspec>...`::
+	When _<pathspec>_ is given on the command line, commit the contents of
+	the files that match the pathspec without recording the changes
+	already added to the index. The contents of these files are also
+	staged for the next commit on top of what have been staged before.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
+
+EXAMPLES
+--------
+When recording your own work, the contents of modified files in
+your working tree are temporarily stored to a staging area
+called the "index" with `git add`.  A file can be
+reverted back, only in the index but not in the working tree,
+to that of the last commit with `git restore --staged <file>`,
+which effectively reverts `git add` and prevents the changes to
+this file from participating in the next commit.  After building
+the state to be committed incrementally with these commands,
+`git commit` (without any pathname parameter) is used to record what
+has been staged so far.  This is the most basic form of the
+command.  An example:
+
+------------
+$ edit hello.c
+$ git rm goodbye.c
+$ git add hello.c
+$ git commit
+------------
+
+Instead of staging files after each individual change, you can
+tell `git commit` to notice the changes to the files whose
+contents are tracked in
+your working tree and do corresponding `git add` and `git rm`
+for you.  That is, this example does the same as the earlier
+example if there is no other change in your working tree:
+
+------------
+$ edit hello.c
+$ rm goodbye.c
+$ git commit -a
+------------
+
+The command `git commit -a` first looks at your working tree,
+notices that you have modified `hello.c` and removed `goodbye.c`,
+and performs necessary `git add` and `git rm` for you.
+
+After staging changes to many files, you can alter the order the
+changes are recorded in, by giving pathnames to `git commit`.
+When pathnames are given, the command makes a commit that
+only records the changes made to the named paths:
+
+------------
+$ edit hello.c hello.h
+$ git add hello.c hello.h
+$ edit Makefile
+$ git commit Makefile
+------------
+
+This makes a commit that records the modification to `Makefile`.
+The changes staged for `hello.c` and `hello.h` are not included
+in the resulting commit.  However, their changes are not lost --
+they are still staged and merely held back.  After the above
+sequence, if you do:
+
+------------
+$ git commit
+------------
+
+this second commit would record the changes to `hello.c` and
+`hello.h` as expected.
+
+After a merge (initiated by `git merge` or `git pull`) stops
+because of conflicts, cleanly merged
+paths are already staged to be committed for you, and paths that
+conflicted are left in unmerged state.  You would have to first
+check which paths are conflicting with `git status`
+and after fixing them manually in your working tree, you would
+stage the result as usual with `git add`:
+
+------------
+$ git status | grep unmerged
+unmerged: hello.c
+$ edit hello.c
+$ git add hello.c
+------------
+
+After resolving conflicts and staging the result, `git ls-files -u`
+would stop mentioning the conflicted path.  When you are done,
+run `git commit` to finally record the merge:
+
+------------
+$ git commit
+------------
+
+As with the case to record your own changes, you can use `-a`
+option to save typing.  One difference is that during a merge
+resolution, you cannot use `git commit` with pathnames to
+alter the order the changes are committed, because the merge
+should be recorded as a single commit.  In fact, the command
+refuses to run when given pathnames (but see `-i` option).
+
+COMMIT INFORMATION
+------------------
+
+Author and committer information is taken from the following environment
+variables, if set:
+
+ * `GIT_AUTHOR_NAME`
+ * `GIT_AUTHOR_EMAIL`
+ * `GIT_AUTHOR_DATE`
+ * `GIT_COMMITTER_NAME`
+ * `GIT_COMMITTER_EMAIL`
+ * `GIT_COMMITTER_DATE`
+
+(nb "<", ">" and "\n"s are stripped)
+
+The author and committer names are by convention some form of a personal name
+(that is, the name by which other humans refer to you), although Git does not
+enforce or require any particular form. Arbitrary Unicode may be used, subject
+to the constraints listed above. This name has no effect on authentication; for
+that, see the `credential.username` variable in linkgit:git-config[1].
+
+In case (some of) these environment variables are not set, the information
+is taken from the configuration items `user.name` and `user.email`, or, if not
+present, the environment variable `EMAIL`, or, if that is not set,
+system user name and the hostname used for outgoing mail (taken
+from `/etc/mailname` and falling back to the fully qualified hostname when
+that file does not exist).
+
+The `author.name` and `committer.name` and their corresponding email options
+override `user.name` and `user.email` if set and are overridden themselves by
+the environment variables.
+
+The typical usage is to set just the `user.name` and `user.email` variables;
+the other options are provided for more complex use cases.
+
+:git-commit: 1
+include::date-formats.adoc[]
+
+DISCUSSION
+----------
+
+Though not required, it's a good idea to begin the commit message
+with a single short (no more than 50 characters) line summarizing the
+change, followed by a blank line and then a more thorough description.
+The text up to the first blank line in a commit message is treated
+as the commit title, and that title is used throughout Git.
+For example, linkgit:git-format-patch[1] turns a commit into email, and it uses
+the title on the Subject line and the rest of the commit in the body.
+
+include::i18n.adoc[]
+
+ENVIRONMENT AND CONFIGURATION VARIABLES
+---------------------------------------
+The editor used to edit the commit log message will be chosen from the
+`GIT_EDITOR` environment variable, the `core.editor` configuration variable, the
+`VISUAL` environment variable, or the `EDITOR` environment variable (in that
+order).  See linkgit:git-var[1] for details.
+
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/commit.adoc[]
+
+HOOKS
+-----
+This command can run `commit-msg`, `prepare-commit-msg`, `pre-commit`,
+`post-commit` and `post-rewrite` hooks.  See linkgit:githooks[5] for more
+information.
+
+FILES
+-----
+
+`$GIT_DIR/COMMIT_EDITMSG`::
+	This file contains the commit message of a commit in progress.
+	If `git commit` exits due to an error before creating a commit,
+	any commit message that has been provided by the user (e.g., in
+	an editor session) will be available in this file, but will be
+	overwritten by the next invocation of `git commit`.
+
+SEE ALSO
+--------
+linkgit:git-add[1],
+linkgit:git-rm[1],
+linkgit:git-mv[1],
+linkgit:git-merge[1],
+linkgit:git-commit-tree[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-config.adoc b/Documentation/git-config.adoc
new file mode 100644
index 0000000000..888f8ba54b
--- /dev/null
+++ b/Documentation/git-config.adoc
@@ -0,0 +1,638 @@
+git-config(1)
+=============
+
+NAME
+----
+git-config - Get and set repository or global options
+
+
+SYNOPSIS
+--------
+[verse]
+'git config list' [<file-option>] [<display-option>] [--includes]
+'git config get' [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>
+'git config set' [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>
+'git config unset' [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>
+'git config rename-section' [<file-option>] <old-name> <new-name>
+'git config remove-section' [<file-option>] <name>
+'git config edit' [<file-option>]
+'git config' [<file-option>] --get-colorbool <name> [<stdout-is-tty>]
+
+DESCRIPTION
+-----------
+You can query/set/replace/unset options with this command. The name is
+actually the section and the key separated by a dot, and the value will be
+escaped.
+
+Multiple lines can be added to an option by using the `--append` option.
+If you want to update or unset an option which can occur on multiple
+lines, a `value-pattern` (which is an extended regular expression,
+unless the `--fixed-value` option is given) needs to be given.  Only the
+existing values that match the pattern are updated or unset.  If
+you want to handle the lines that do *not* match the pattern, just
+prepend a single exclamation mark in front (see also <<EXAMPLES>>),
+but note that this only works when the `--fixed-value` option is not
+in use.
+
+The `--type=<type>` option instructs 'git config' to ensure that incoming and
+outgoing values are canonicalize-able under the given <type>.  If no
+`--type=<type>` is given, no canonicalization will be performed. Callers may
+unset an existing `--type` specifier with `--no-type`.
+
+When reading, the values are read from the system, global and
+repository local configuration files by default, and options
+`--system`, `--global`, `--local`, `--worktree` and
+`--file <filename>` can be used to tell the command to read from only
+that location (see <<FILES>>).
+
+When writing, the new value is written to the repository local
+configuration file by default, and options `--system`, `--global`,
+`--worktree`, `--file <filename>` can be used to tell the command to
+write to that location (you can say `--local` but that is the
+default).
+
+This command will fail with non-zero status upon error.  Some exit
+codes are:
+
+- The section or key is invalid (ret=1),
+- no section or name was provided (ret=2),
+- the config file is invalid (ret=3),
+- the config file cannot be written (ret=4),
+- you try to unset an option which does not exist (ret=5),
+- you try to unset/set an option for which multiple lines match (ret=5), or
+- you try to use an invalid regexp (ret=6).
+
+On success, the command returns the exit code 0.
+
+A list of all available configuration variables can be obtained using the
+`git help --config` command.
+
+COMMANDS
+--------
+
+list::
+	List all variables set in config file, along with their values.
+
+get::
+	Emits the value of the specified key. If key is present multiple times
+	in the configuration, emits the last value. If `--all` is specified,
+	emits all values associated with key. Returns error code 1 if key is
+	not present.
+
+set::
+	Set value for one or more config options. By default, this command
+	refuses to write multi-valued config options. Passing `--all` will
+	replace all multi-valued config options with the new value, whereas
+	`--value=` will replace all config options whose values match the given
+	pattern.
+
+unset::
+	Unset value for one or more config options. By default, this command
+	refuses to unset multi-valued keys. Passing `--all` will unset all
+	multi-valued config options, whereas `--value` will unset all config
+	options whose values match the given pattern.
+
+rename-section::
+	Rename the given section to a new name.
+
+remove-section::
+	Remove the given section from the configuration file.
+
+edit::
+	Opens an editor to modify the specified config file; either
+	`--system`, `--global`, `--local` (default), `--worktree`, or
+	`--file <config-file>`.
+
+[[OPTIONS]]
+OPTIONS
+-------
+
+--replace-all::
+	Default behavior is to replace at most one line. This replaces
+	all lines matching the key (and optionally the `value-pattern`).
+
+--append::
+	Adds a new line to the option without altering any existing
+	values. This is the same as providing '--value=^$' in `set`.
+
+--comment <message>::
+	Append a comment at the end of new or modified lines.
+
+	If _<message>_ begins with one or more whitespaces followed
+	by "#", it is used as-is.  If it begins with "#", a space is
+	prepended before it is used.  Otherwise, a string " # " (a
+	space followed by a hash followed by a space) is prepended
+	to it.  And the resulting string is placed immediately after
+	the value defined for the variable.  The _<message>_ must
+	not contain linefeed characters (no multi-line comments are
+	permitted).
+
+--all::
+	With `get`, return all values for a multi-valued key.
+
+--regexp::
+	With `get`, interpret the name as a regular expression. Regular
+	expression matching is currently case-sensitive and done against a
+	canonicalized version of the key in which section and variable names
+	are lowercased, but subsection names are not.
+
+--url=<URL>::
+	When given a two-part <name> as <section>.<key>, the value for
+	<section>.<URL>.<key> whose <URL> part matches the best to the
+	given URL is returned (if no such key exists, the value for
+	<section>.<key> is used as a fallback).  When given just the
+	<section> as name, do so for all the keys in the section and
+	list them.  Returns error code 1 if no value is found.
+
+--global::
+	For writing options: write to global `~/.gitconfig` file
+	rather than the repository `.git/config`, write to
+	`$XDG_CONFIG_HOME/git/config` file if this file exists and the
+	`~/.gitconfig` file doesn't.
++
+For reading options: read only from global `~/.gitconfig` and from
+`$XDG_CONFIG_HOME/git/config` rather than from all available files.
++
+See also <<FILES>>.
+
+--system::
+	For writing options: write to system-wide
+	`$(prefix)/etc/gitconfig` rather than the repository
+	`.git/config`.
++
+For reading options: read only from system-wide `$(prefix)/etc/gitconfig`
+rather than from all available files.
++
+See also <<FILES>>.
+
+--local::
+	For writing options: write to the repository `.git/config` file.
+	This is the default behavior.
++
+For reading options: read only from the repository `.git/config` rather than
+from all available files.
++
+See also <<FILES>>.
+
+--worktree::
+	Similar to `--local` except that `$GIT_DIR/config.worktree` is
+	read from or written to if `extensions.worktreeConfig` is
+	enabled. If not it's the same as `--local`. Note that `$GIT_DIR`
+	is equal to `$GIT_COMMON_DIR` for the main working tree, but is of
+	the form `$GIT_DIR/worktrees/<id>/` for other working trees. See
+	linkgit:git-worktree[1] to learn how to enable
+	`extensions.worktreeConfig`.
+
+-f <config-file>::
+--file <config-file>::
+	For writing options: write to the specified file rather than the
+	repository `.git/config`.
++
+For reading options: read only from the specified file rather than from all
+available files.
++
+See also <<FILES>>.
+
+--blob <blob>::
+	Similar to `--file` but use the given blob instead of a file. E.g.
+	you can use 'master:.gitmodules' to read values from the file
+	'.gitmodules' in the master branch. See "SPECIFYING REVISIONS"
+	section in linkgit:gitrevisions[7] for a more complete list of
+	ways to spell blob names.
+
+--fixed-value::
+	When used with the `value-pattern` argument, treat `value-pattern` as
+	an exact string instead of a regular expression. This will restrict
+	the name/value pairs that are matched to only those where the value
+	is exactly equal to the `value-pattern`.
+
+--type <type>::
+  'git config' will ensure that any input or output is valid under the given
+  type constraint(s), and will canonicalize outgoing values in `<type>`'s
+  canonical form.
++
+Valid `<type>`'s include:
++
+- 'bool': canonicalize values as either "true" or "false".
+- 'int': canonicalize values as simple decimal numbers. An optional suffix of
+  'k', 'm', or 'g' will cause the value to be multiplied by 1024, 1048576, or
+  1073741824 upon input.
+- 'bool-or-int': canonicalize according to either 'bool' or 'int', as described
+  above.
+- 'path': canonicalize by expanding a leading `~` to the value of `$HOME` and
+  `~user` to the home directory for the specified user. This specifier has no
+  effect when setting the value (but you can use `git config section.variable
+  ~/` from the command line to let your shell do the expansion.)
+- 'expiry-date': canonicalize by converting from a fixed or relative date-string
+  to a timestamp. This specifier has no effect when setting the value.
+- 'color': When getting a value, canonicalize by converting to an ANSI color
+  escape sequence. When setting a value, a sanity-check is performed to ensure
+  that the given value is canonicalize-able as an ANSI color, but it is written
+  as-is.
++
+
+--bool::
+--int::
+--bool-or-int::
+--path::
+--expiry-date::
+  Historical options for selecting a type specifier. Prefer instead `--type`
+  (see above).
+
+--no-type::
+  Un-sets the previously set type specifier (if one was previously set). This
+  option requests that 'git config' not canonicalize the retrieved variable.
+  `--no-type` has no effect without `--type=<type>` or `--<type>`.
+
+-z::
+--null::
+	For all options that output values and/or keys, always
+	end values with the null character (instead of a
+	newline). Use newline instead as a delimiter between
+	key and value. This allows for secure parsing of the
+	output without getting confused e.g. by values that
+	contain line breaks.
+
+--name-only::
+	Output only the names of config variables for `list` or
+	`get`.
+
+--show-origin::
+	Augment the output of all queried config options with the
+	origin type (file, standard input, blob, command line) and
+	the actual origin (config file path, ref, or blob id if
+	applicable).
+
+--show-scope::
+	Similar to `--show-origin` in that it augments the output of
+	all queried config options with the scope of that value
+	(worktree, local, global, system, command).
+
+--get-colorbool <name> [<stdout-is-tty>]::
+
+	Find the color setting for `<name>` (e.g. `color.diff`) and output
+	"true" or "false".  `<stdout-is-tty>` should be either "true" or
+	"false", and is taken into account when configuration says
+	"auto".  If `<stdout-is-tty>` is missing, then checks the standard
+	output of the command itself, and exits with status 0 if color
+	is to be used, or exits with status 1 otherwise.
+	When the color setting for `name` is undefined, the command uses
+	`color.ui` as fallback.
+
+--[no-]includes::
+	Respect `include.*` directives in config files when looking up
+	values. Defaults to `off` when a specific file is given (e.g.,
+	using `--file`, `--global`, etc) and `on` when searching all
+	config files.
+
+--default <value>::
+  When using `get`, and the requested variable is not found, behave as if
+  <value> were the value assigned to that variable.
+
+DEPRECATED MODES
+----------------
+
+The following modes have been deprecated in favor of subcommands. It is
+recommended to migrate to the new syntax.
+
+'git config <name>'::
+	Replaced by `git config get <name>`.
+
+'git config <name> <value> [<value-pattern>]'::
+	Replaced by `git config set [--value=<pattern>] <name> <value>`.
+
+-l::
+--list::
+	Replaced by `git config list`.
+
+--get <name> [<value-pattern>]::
+	Replaced by `git config get [--value=<pattern>] <name>`.
+
+--get-all <name> [<value-pattern>]::
+	Replaced by `git config get [--value=<pattern>] --all <name>`.
+
+--get-regexp <name-regexp>::
+	Replaced by `git config get --all --show-names --regexp <name-regexp>`.
+
+--get-urlmatch <name> <URL>::
+	Replaced by `git config get --all --show-names --url=<URL> <name>`.
+
+--get-color <name> [<default>]::
+	Replaced by `git config get --type=color [--default=<default>] <name>`.
+
+--add <name> <value>::
+	Replaced by `git config set --append <name> <value>`.
+
+--unset <name> [<value-pattern>]::
+	Replaced by `git config unset [--value=<pattern>] <name>`.
+
+--unset-all <name> [<value-pattern>]::
+	Replaced by `git config unset [--value=<pattern>] --all <name>`.
+
+--rename-section <old-name> <new-name>::
+	Replaced by `git config rename-section <old-name> <new-name>`.
+
+--remove-section <name>::
+	Replaced by `git config remove-section <name>`.
+
+-e::
+--edit::
+	Replaced by `git config edit`.
+
+CONFIGURATION
+-------------
+`pager.config` is only respected when listing configuration, i.e., when
+using `list` or `get` which may return multiple results. The default is to use
+a pager.
+
+[[FILES]]
+FILES
+-----
+
+By default, 'git config' will read configuration options from multiple
+files:
+
+$(prefix)/etc/gitconfig::
+	System-wide configuration file.
+
+$XDG_CONFIG_HOME/git/config::
+~/.gitconfig::
+	User-specific configuration files. When the XDG_CONFIG_HOME environment
+	variable is not set or empty, $HOME/.config/ is used as
+	$XDG_CONFIG_HOME.
++
+These are also called "global" configuration files. If both files exist, both
+files are read in the order given above.
+
+$GIT_DIR/config::
+	Repository specific configuration file.
+
+$GIT_DIR/config.worktree::
+	This is optional and is only searched when
+	`extensions.worktreeConfig` is present in $GIT_DIR/config.
+
+You may also provide additional configuration parameters when running any
+git command by using the `-c` option. See linkgit:git[1] for details.
+
+Options will be read from all of these files that are available. If the
+global or the system-wide configuration files are missing or unreadable they
+will be ignored. If the repository configuration file is missing or unreadable,
+'git config' will exit with a non-zero error code. An error message is produced
+if the file is unreadable, but not if it is missing.
+
+The files are read in the order given above, with last value found taking
+precedence over values read earlier.  When multiple values are taken then all
+values of a key from all files will be used.
+
+By default, options are only written to the repository specific
+configuration file. Note that this also affects options like `set`
+and `unset`. *'git config' will only ever change one file at a time*.
+
+You can limit which configuration sources are read from or written to by
+specifying the path of a file with the `--file` option, or by specifying a
+configuration scope with `--system`, `--global`, `--local`, or `--worktree`.
+For more, see <<OPTIONS>> above.
+
+[[SCOPES]]
+SCOPES
+------
+
+Each configuration source falls within a configuration scope. The scopes
+are:
+
+system::
+	$(prefix)/etc/gitconfig
+
+global::
+	$XDG_CONFIG_HOME/git/config
++
+~/.gitconfig
+
+local::
+	$GIT_DIR/config
+
+worktree::
+	$GIT_DIR/config.worktree
+
+command::
+	GIT_CONFIG_{COUNT,KEY,VALUE} environment variables (see <<ENVIRONMENT>>
+	below)
++
+the `-c` option
+
+With the exception of 'command', each scope corresponds to a command line
+option: `--system`, `--global`, `--local`, `--worktree`.
+
+When reading options, specifying a scope will only read options from the
+files within that scope. When writing options, specifying a scope will write
+to the files within that scope (instead of the repository specific
+configuration file). See <<OPTIONS>> above for a complete description.
+
+Most configuration options are respected regardless of the scope it is
+defined in, but some options are only respected in certain scopes. See the
+respective option's documentation for the full details.
+
+Protected configuration
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Protected configuration refers to the 'system', 'global', and 'command' scopes.
+For security reasons, certain options are only respected when they are
+specified in protected configuration, and ignored otherwise.
+
+Git treats these scopes as if they are controlled by the user or a trusted
+administrator. This is because an attacker who controls these scopes can do
+substantial harm without using Git, so it is assumed that the user's environment
+protects these scopes against attackers.
+
+[[ENVIRONMENT]]
+ENVIRONMENT
+-----------
+
+GIT_CONFIG_GLOBAL::
+GIT_CONFIG_SYSTEM::
+	Take the configuration from the given files instead from global or
+	system-level configuration. See linkgit:git[1] for details.
+
+GIT_CONFIG_NOSYSTEM::
+	Whether to skip reading settings from the system-wide
+	$(prefix)/etc/gitconfig file. See linkgit:git[1] for details.
+
+See also <<FILES>>.
+
+GIT_CONFIG_COUNT::
+GIT_CONFIG_KEY_<n>::
+GIT_CONFIG_VALUE_<n>::
+	If GIT_CONFIG_COUNT is set to a positive number, all environment pairs
+	GIT_CONFIG_KEY_<n> and GIT_CONFIG_VALUE_<n> up to that number will be
+	added to the process's runtime configuration. The config pairs are
+	zero-indexed. Any missing key or value is treated as an error. An empty
+	GIT_CONFIG_COUNT is treated the same as GIT_CONFIG_COUNT=0, namely no
+	pairs are processed. These environment variables will override values
+	in configuration files, but will be overridden by any explicit options
+	passed via `git -c`.
++
+This is useful for cases where you want to spawn multiple git commands
+with a common configuration but cannot depend on a configuration file,
+for example when writing scripts.
+
+GIT_CONFIG::
+	If no `--file` option is provided to `git config`, use the file
+	given by `GIT_CONFIG` as if it were provided via `--file`. This
+	variable has no effect on other Git commands, and is mostly for
+	historical compatibility; there is generally no reason to use it
+	instead of the `--file` option.
+
+[[EXAMPLES]]
+EXAMPLES
+--------
+
+Given a .git/config like this:
+
+------------
+#
+# This is the config file, and
+# a '#' or ';' character indicates
+# a comment
+#
+
+; core variables
+[core]
+	; Don't trust file modes
+	filemode = false
+
+; Our diff algorithm
+[diff]
+	external = /usr/local/bin/diff-wrapper
+	renames = true
+
+; Proxy settings
+[core]
+	gitproxy=proxy-command for kernel.org
+	gitproxy=default-proxy ; for all the rest
+
+; HTTP
+[http]
+	sslVerify
+[http "https://weak.example.com";]
+	sslVerify = false
+	cookieFile = /tmp/cookie.txt
+------------
+
+you can set the filemode to true with
+
+------------
+% git config set core.filemode true
+------------
+
+The hypothetical proxy command entries actually have a postfix to discern
+what URL they apply to. Here is how to change the entry for kernel.org
+to "ssh".
+
+------------
+% git config set --value='for kernel.org$' core.gitproxy '"ssh" for kernel.org'
+------------
+
+This makes sure that only the key/value pair for kernel.org is replaced.
+
+To delete the entry for renames, do
+
+------------
+% git config unset diff.renames
+------------
+
+If you want to delete an entry for a multivar (like core.gitproxy above),
+you have to provide a regex matching the value of exactly one line.
+
+To query the value for a given key, do
+
+------------
+% git config get core.filemode
+------------
+
+or, to query a multivar:
+
+------------
+% git config get --value="for kernel.org$" core.gitproxy
+------------
+
+If you want to know all the values for a multivar, do:
+
+------------
+% git config get --all --show-names core.gitproxy
+------------
+
+If you like to live dangerously, you can replace *all* core.gitproxy by a
+new one with
+
+------------
+% git config set --all core.gitproxy ssh
+------------
+
+However, if you really only want to replace the line for the default proxy,
+i.e. the one without a "for ..." postfix, do something like this:
+
+------------
+% git config set --value='! for ' core.gitproxy ssh
+------------
+
+To actually match only values with an exclamation mark, you have to
+
+------------
+% git config set --value='[!]' section.key value
+------------
+
+To add a new proxy, without altering any of the existing ones, use
+
+------------
+% git config set --append core.gitproxy '"proxy-command" for example.com'
+------------
+
+An example to use customized color from the configuration in your
+script:
+
+------------
+#!/bin/sh
+WS=$(git config get --type=color --default="blue reverse" color.diff.whitespace)
+RESET=$(git config get --type=color --default="reset" "")
+echo "${WS}your whitespace color or blue reverse${RESET}"
+------------
+
+For URLs in `https://weak.example.com`, `http.sslVerify` is set to
+false, while it is set to `true` for all others:
+
+------------
+% git config get --type=bool --url=https://good.example.com http.sslverify
+true
+% git config get --type=bool --url=https://weak.example.com http.sslverify
+false
+% git config get --url=https://weak.example.com http
+http.cookieFile /tmp/cookie.txt
+http.sslverify false
+------------
+
+include::config.adoc[]
+
+BUGS
+----
+When using the deprecated `[section.subsection]` syntax, changing a value
+will result in adding a multi-line key instead of a change, if the subsection
+is given with at least one uppercase character. For example when the config
+looks like
+
+--------
+  [section.subsection]
+    key = value1
+--------
+
+and running `git config section.Subsection.key value2` will result in
+
+--------
+  [section.subsection]
+    key = value1
+    key = value2
+--------
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-count-objects.adoc b/Documentation/git-count-objects.adoc
new file mode 100644
index 0000000000..97f9f12610
--- /dev/null
+++ b/Documentation/git-count-objects.adoc
@@ -0,0 +1,54 @@
+git-count-objects(1)
+====================
+
+NAME
+----
+git-count-objects - Count unpacked number of objects and their disk consumption
+
+SYNOPSIS
+--------
+[verse]
+'git count-objects' [-v] [-H | --human-readable]
+
+DESCRIPTION
+-----------
+Counts the number of unpacked object files and disk space consumed by
+them, to help you decide when it is a good time to repack.
+
+
+OPTIONS
+-------
+-v::
+--verbose::
+	Provide more detailed reports:
++
+count: the number of loose objects
++
+size: disk space consumed by loose objects, in KiB (unless -H is specified)
++
+in-pack: the number of in-pack objects
++
+size-pack: disk space consumed by the packs, in KiB (unless -H is specified)
++
+prune-packable: the number of loose objects that are also present in
+the packs. These objects could be pruned using `git prune-packed`.
++
+garbage: the number of files in the object database that are neither valid loose
+objects nor valid packs
++
+size-garbage: disk space consumed by garbage files, in KiB (unless -H is
+specified)
++
+alternate: absolute path of alternate object databases; may appear
+multiple times, one line per path. Note that if the path contains
+non-printable characters, it may be surrounded by double-quotes and
+contain C-style backslashed escape sequences.
+
+-H::
+--human-readable::
+
+Print sizes in human readable format
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-credential-cache--daemon.adoc b/Documentation/git-credential-cache--daemon.adoc
new file mode 100644
index 0000000000..650a15a7ed
--- /dev/null
+++ b/Documentation/git-credential-cache--daemon.adoc
@@ -0,0 +1,30 @@
+git-credential-cache{litdd}daemon(1)
+====================================
+
+NAME
+----
+git-credential-cache--daemon - Temporarily store user credentials in memory
+
+SYNOPSIS
+--------
+[verse]
+'git credential-cache{litdd}daemon' [--debug] <socket-path>
+
+DESCRIPTION
+-----------
+
+NOTE: You probably don't want to invoke this command yourself; it is
+started automatically when you use linkgit:git-credential-cache[1].
+
+This command listens on the Unix domain socket specified by `<socket-path>`
+for `git-credential-cache` clients. Clients may store and retrieve
+credentials. Each credential is held for a timeout specified by the
+client; once no credentials are held, the daemon exits.
+
+If the `--debug` option is specified, the daemon does not close its
+stderr stream, and may output extra diagnostics to it even after it has
+begun listening for clients.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-credential-cache.adoc b/Documentation/git-credential-cache.adoc
new file mode 100644
index 0000000000..54fa7a27e1
--- /dev/null
+++ b/Documentation/git-credential-cache.adoc
@@ -0,0 +1,100 @@
+git-credential-cache(1)
+=======================
+
+NAME
+----
+git-credential-cache - Helper to temporarily store passwords in memory
+
+SYNOPSIS
+--------
+-----------------------------
+git config credential.helper 'cache [<options>]'
+-----------------------------
+
+DESCRIPTION
+-----------
+
+This command caches credentials for use by future Git programs.
+The stored credentials are kept in memory of the cache-daemon
+process (instead of being written to a file) and are forgotten after a
+configurable timeout. Credentials are forgotten sooner if the
+cache-daemon dies, for example if the system restarts. The cache
+is accessible over a Unix domain socket, restricted to the current
+user by filesystem permissions.
+
+You probably don't want to invoke this command directly; it is meant to
+be used as a credential helper by other parts of Git. See
+linkgit:gitcredentials[7] or `EXAMPLES` below.
+
+OPTIONS
+-------
+
+--timeout <seconds>::
+
+	Number of seconds to cache credentials (default: 900).
+
+--socket <path>::
+
+	Use `<path>` to contact a running cache daemon (or start a new
+	cache daemon if one is not started).
+	Defaults to `$XDG_CACHE_HOME/git/credential/socket` unless
+	`~/.git-credential-cache/` exists in which case
+	`~/.git-credential-cache/socket` is used instead.
+	If your home directory is on a network-mounted filesystem, you
+	may need to change this to a local filesystem. You must specify
+	an absolute path.
+
+CONTROLLING THE DAEMON
+----------------------
+
+If you would like the daemon to exit early, forgetting all cached
+credentials before their timeout, you can issue an `exit` action:
+
+--------------------------------------
+git credential-cache exit
+--------------------------------------
+
+EXAMPLES
+--------
+
+The point of this helper is to reduce the number of times you must type
+your username or password. For example:
+
+------------------------------------
+$ git config credential.helper cache
+$ git push http://example.com/repo.git
+Username: <type your username>
+Password: <type your password>
+
+[work for 5 more minutes]
+$ git push http://example.com/repo.git
+[your credentials are used automatically]
+------------------------------------
+
+You can provide options via the credential.helper configuration
+variable (this example increases the cache time to 1 hour):
+
+-------------------------------------------------------
+$ git config credential.helper 'cache --timeout=3600'
+-------------------------------------------------------
+
+PERSONAL ACCESS TOKENS
+----------------------
+
+Some remotes accept personal access tokens, which are randomly
+generated and hard to memorise. They typically have a lifetime of weeks
+or months.
+
+git-credential-cache is inherently unsuitable for persistent storage of
+personal access tokens. The credential will be forgotten after the cache
+timeout. Even if you configure a long timeout, credentials will be
+forgotten if the daemon dies.
+
+To avoid frequently regenerating personal access tokens, configure a
+credential helper with persistent storage. Alternatively, configure an
+OAuth credential helper to generate credentials automatically. See
+linkgit:gitcredentials[7], sections "Available helpers" and "OAuth".
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-credential-store.adoc b/Documentation/git-credential-store.adoc
new file mode 100644
index 0000000000..71864a8726
--- /dev/null
+++ b/Documentation/git-credential-store.adoc
@@ -0,0 +1,110 @@
+git-credential-store(1)
+=======================
+
+NAME
+----
+git-credential-store - Helper to store credentials on disk
+
+SYNOPSIS
+--------
+-------------------
+git config credential.helper 'store [<options>]'
+-------------------
+
+DESCRIPTION
+-----------
+
+NOTE: Using this helper will store your passwords unencrypted on disk,
+protected only by filesystem permissions. If this is not an acceptable
+security tradeoff, try linkgit:git-credential-cache[1], or find a helper
+that integrates with secure storage provided by your operating system.
+
+This command stores credentials indefinitely on disk for use by future
+Git programs.
+
+You probably don't want to invoke this command directly; it is meant to
+be used as a credential helper by other parts of git. See
+linkgit:gitcredentials[7] or `EXAMPLES` below.
+
+OPTIONS
+-------
+
+--file=<path>::
+
+	Use `<path>` to lookup and store credentials. The file will have its
+	filesystem permissions set to prevent other users on the system
+	from reading it, but it will not be encrypted or otherwise
+	protected. If not specified, credentials will be searched for from
+	`~/.git-credentials` and `$XDG_CONFIG_HOME/git/credentials`, and
+	credentials will be written to `~/.git-credentials` if it exists, or
+	`$XDG_CONFIG_HOME/git/credentials` if it exists and the former does
+	not. See also <<FILES>>.
+
+[[FILES]]
+FILES
+-----
+
+If not set explicitly with `--file`, there are two files where
+git-credential-store will search for credentials in order of precedence:
+
+~/.git-credentials::
+	User-specific credentials file.
+
+$XDG_CONFIG_HOME/git/credentials::
+	Second user-specific credentials file. If '$XDG_CONFIG_HOME' is not set
+	or empty, `$HOME/.config/git/credentials` will be used. Any credentials
+	stored in this file will not be used if `~/.git-credentials` has a
+	matching credential as well. It is a good idea not to create this file
+	if you sometimes use older versions of Git that do not support it.
+
+For credential lookups, the files are read in the order given above, with the
+first matching credential found taking precedence over credentials found in
+files further down the list.
+
+Credential storage will by default write to the first existing file in the
+list. If none of these files exist, `~/.git-credentials` will be created and
+written to.
+
+When erasing credentials, matching credentials will be erased from all files.
+
+EXAMPLES
+--------
+
+The point of this helper is to reduce the number of times you must type
+your username or password. For example:
+
+------------------------------------------
+$ git config credential.helper store
+$ git push http://example.com/repo.git
+Username: <type your username>
+Password: <type your password>
+
+[several days later]
+$ git push http://example.com/repo.git
+[your credentials are used automatically]
+------------------------------------------
+
+STORAGE FORMAT
+--------------
+
+The `.git-credentials` file is stored in plaintext. Each credential is
+stored on its own line as a URL like:
+
+------------------------------
+https://user:pass@xxxxxxxxxxx
+------------------------------
+
+No other kinds of lines (e.g. empty lines or comment lines) are
+allowed in the file, even though some may be silently ignored. Do
+not view or edit the file with editors.
+
+When Git needs authentication for a particular URL context,
+credential-store will consider that context a pattern to match against
+each entry in the credentials file.  If the protocol, hostname, and
+username (if we already have one) match, then the password is returned
+to Git. See the discussion of configuration in linkgit:gitcredentials[7]
+for more information.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-credential.adoc b/Documentation/git-credential.adoc
new file mode 100644
index 0000000000..e41493292f
--- /dev/null
+++ b/Documentation/git-credential.adoc
@@ -0,0 +1,294 @@
+git-credential(1)
+=================
+
+NAME
+----
+git-credential - Retrieve and store user credentials
+
+SYNOPSIS
+--------
+------------------
+'git credential' (fill|approve|reject|capability)
+------------------
+
+DESCRIPTION
+-----------
+
+Git has an internal interface for storing and retrieving credentials
+from system-specific helpers, as well as prompting the user for
+usernames and passwords. The git-credential command exposes this
+interface to scripts which may want to retrieve, store, or prompt for
+credentials in the same manner as Git. The design of this scriptable
+interface models the internal C API; see credential.h for more
+background on the concepts.
+
+git-credential takes an "action" option on the command-line (one of
+`fill`, `approve`, or `reject`) and reads a credential description
+on stdin (see <<IOFMT,INPUT/OUTPUT FORMAT>>).
+
+If the action is `fill`, git-credential will attempt to add "username"
+and "password" attributes to the description by reading config files,
+by contacting any configured credential helpers, or by prompting the
+user. The username and password attributes of the credential
+description are then printed to stdout together with the attributes
+already provided.
+
+If the action is `approve`, git-credential will send the description
+to any configured credential helpers, which may store the credential
+for later use.
+
+If the action is `reject`, git-credential will send the description to
+any configured credential helpers, which may erase any stored
+credentials matching the description.
+
+If the action is `capability`, git-credential will announce any capabilities
+it supports to standard output.
+
+If the action is `approve` or `reject`, no output should be emitted.
+
+TYPICAL USE OF GIT CREDENTIAL
+-----------------------------
+
+An application using git-credential will typically use `git
+credential` following these steps:
+
+  1. Generate a credential description based on the context.
++
+For example, if we want a password for
+`https://example.com/foo.git`, we might generate the following
+credential description (don't forget the blank line at the end; it
+tells `git credential` that the application finished feeding all the
+information it has):
+
+	 protocol=https
+	 host=example.com
+	 path=foo.git
+
+  2. Ask git-credential to give us a username and password for this
+     description. This is done by running `git credential fill`,
+     feeding the description from step (1) to its standard input. The complete
+     credential description (including the credential per se, i.e. the
+     login and password) will be produced on standard output, like:
+
+	protocol=https
+	host=example.com
+	username=bob
+	password=secr3t
++
+In most cases, this means the attributes given in the input will be
+repeated in the output, but Git may also modify the credential
+description, for example by removing the `path` attribute when the
+protocol is HTTP(s) and `credential.useHttpPath` is false.
++
+If the `git credential` knew about the password, this step may
+not have involved the user actually typing this password (the
+user may have typed a password to unlock the keychain instead,
+or no user interaction was done if the keychain was already
+unlocked) before it returned `password=secr3t`.
+
+  3. Use the credential (e.g., access the URL with the username and
+     password from step (2)), and see if it's accepted.
+
+  4. Report on the success or failure of the password. If the
+     credential allowed the operation to complete successfully, then
+     it can be marked with an "approve" action to tell `git
+     credential` to reuse it in its next invocation. If the credential
+     was rejected during the operation, use the "reject" action so
+     that `git credential` will ask for a new password in its next
+     invocation. In either case, `git credential` should be fed with
+     the credential description obtained from step (2) (which also
+     contains the fields provided in step (1)).
+
+[[IOFMT]]
+INPUT/OUTPUT FORMAT
+-------------------
+
+`git credential` reads and/or writes (depending on the action used)
+credential information in its standard input/output. This information
+can correspond either to keys for which `git credential` will obtain
+the login information (e.g. host, protocol, path), or to the actual
+credential data to be obtained (username/password).
+
+The credential is split into a set of named attributes, with one
+attribute per line. Each attribute is specified by a key-value pair,
+separated by an `=` (equals) sign, followed by a newline.
+
+The key may contain any bytes except `=`, newline, or NUL. The value may
+contain any bytes except newline or NUL.  A line, including the trailing
+newline, may not exceed 65535 bytes in order to allow implementations to
+parse efficiently.
+
+Attributes with keys that end with C-style array brackets `[]` can have
+multiple values. Each instance of a multi-valued attribute forms an
+ordered list of values - the order of the repeated attributes defines
+the order of the values. An empty multi-valued attribute (`key[]=\n`)
+acts to clear any previous entries and reset the list.
+
+In all cases, all bytes are treated as-is (i.e., there is no quoting,
+and one cannot transmit a value with newline or NUL in it). The list of
+attributes is terminated by a blank line or end-of-file.
+
+Git understands the following attributes:
+
+`protocol`::
+
+	The protocol over which the credential will be used (e.g.,
+	`https`).
+
+`host`::
+
+	The remote hostname for a network credential.  This includes
+	the port number if one was specified (e.g., "example.com:8088").
+
+`path`::
+
+	The path with which the credential will be used. E.g., for
+	accessing a remote https repository, this will be the
+	repository's path on the server.
+
+`username`::
+
+	The credential's username, if we already have one (e.g., from a
+	URL, the configuration, the user, or from a previously run helper).
+
+`password`::
+
+	The credential's password, if we are asking it to be stored.
+
+`password_expiry_utc`::
+
+	Generated passwords such as an OAuth access token may have an expiry date.
+	When reading credentials from helpers, `git credential fill` ignores expired
+	passwords. Represented as Unix time UTC, seconds since 1970.
+
+`oauth_refresh_token`::
+
+	An OAuth refresh token may accompany a password that is an OAuth access
+	token. Helpers must treat this attribute as confidential like the password
+	attribute. Git itself has no special behaviour for this attribute.
+
+`url`::
+
+	When this special attribute is read by `git credential`, the
+	value is parsed as a URL and treated as if its constituent parts
+	were read (e.g., `url=https://example.com` would behave as if
+	`protocol=https` and `host=example.com` had been provided). This
+	can help callers avoid parsing URLs themselves.
++
+Note that specifying a protocol is mandatory and if the URL
+doesn't specify a hostname (e.g., "cert:///path/to/file") the
+credential will contain a hostname attribute whose value is an
+empty string.
++
+Components which are missing from the URL (e.g., there is no
+username in the example above) will be left unset.
+
+`authtype`::
+	This indicates that the authentication scheme in question should be used.
+	Common values for HTTP and HTTPS include `basic`, `bearer`, and `digest`,
+	although the latter is insecure and should not be used.  If `credential`
+	is used, this may be set to an arbitrary string suitable for the protocol in
+	question (usually HTTP).
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`credential`::
+	The pre-encoded credential, suitable for the protocol in question (usually
+	HTTP).  If this key is sent, `authtype` is mandatory, and `username` and
+	`password` are not used.  For HTTP, Git concatenates the `authtype` value and
+	this value with a single space to determine the `Authorization` header.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`ephemeral`::
+	This boolean value indicates, if true, that the value in the `credential`
+	field should not be saved by the credential helper because its usefulness is
+	limited in time.  For example, an HTTP Digest `credential` value is computed
+	using a nonce and reusing it will not result in successful authentication.
+	This may also be used for situations with short duration (e.g., 24-hour)
+	credentials.  The default value is false.
++
+The credential helper will still be invoked with `store` or `erase` so that it
+can determine whether the operation was successful.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`state[]`::
+	This value provides an opaque state that will be passed back to this helper
+	if it is called again.  Each different credential helper may specify this
+	once.  The value should include a prefix unique to the credential helper and
+	should ignore values that don't match its prefix.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.
+
+`continue`::
+	This is a boolean value, which, if enabled, indicates that this
+	authentication is a non-final part of a multistage authentication step. This
+	is common in protocols such as NTLM and Kerberos, where two rounds of client
+	authentication are required, and setting this flag allows the credential
+	helper to implement the multistage authentication step.  This flag should
+	only be sent if a further stage is required; that is, if another round of
+	authentication is expected.
++
+This value should not be sent unless the appropriate capability (see below) is
+provided on input.  This attribute is 'one-way' from a credential helper to
+pass information to Git (or other programs invoking `git credential`).
+
+`wwwauth[]`::
+
+	When an HTTP response is received by Git that includes one or more
+	'WWW-Authenticate' authentication headers, these will be passed by Git
+	to credential helpers.
++
+Each 'WWW-Authenticate' header value is passed as a multi-valued
+attribute 'wwwauth[]', where the order of the attributes is the same as
+they appear in the HTTP response. This attribute is 'one-way' from Git
+to pass additional information to credential helpers.
+
+`capability[]`::
+	This signals that Git, or the helper, as appropriate, supports the capability
+	in question.  This can be used to provide better, more specific data as part
+	of the protocol.  A `capability[]` directive must precede any value depending
+	on it and these directives _should_ be the first item announced in the
+	protocol.
++
+There are two currently supported capabilities.  The first is `authtype`, which
+indicates that the `authtype`, `credential`, and `ephemeral` values are
+understood.  The second is `state`, which indicates that the `state[]` and
+`continue` values are understood.
++
+It is not obligatory to use the additional features just because the capability
+is supported, but they should not be provided without the capability.
+
+Unrecognised attributes and capabilities are silently discarded.
+
+[[CAPA-IOFMT]]
+CAPABILITY INPUT/OUTPUT FORMAT
+------------------------------
+
+For `git credential capability`, the format is slightly different. First, a
+`version 0` announcement is made to indicate the current version of the
+protocol, and then each capability is announced with a line like `capability
+authtype`. Credential helpers may also implement this format, again with the
+`capability` argument. Additional lines may be added in the future; callers
+should ignore lines which they don't understand.
+
+Because this is a new part of the credential helper protocol, older versions of
+Git, as well as some credential helpers, may not support it.  If a non-zero
+exit status is received, or if the first line doesn't start with the word
+`version` and a space, callers should assume that no capabilities are supported.
+
+The intention of this format is to differentiate it from the credential output
+in an unambiguous way.  It is possible to use very simple credential helpers
+(e.g., inline shell scripts) which always produce identical output.  Using a
+distinct format allows users to continue to use this syntax without having to
+worry about correctly implementing capability advertisements or accidentally
+confusing callers querying for capabilities.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cvsexportcommit.adoc b/Documentation/git-cvsexportcommit.adoc
new file mode 100644
index 0000000000..41c8a8a05c
--- /dev/null
+++ b/Documentation/git-cvsexportcommit.adoc
@@ -0,0 +1,118 @@
+git-cvsexportcommit(1)
+======================
+
+NAME
+----
+git-cvsexportcommit - Export a single commit to a CVS checkout
+
+
+SYNOPSIS
+--------
+[verse]
+'git cvsexportcommit' [-h] [-u] [-v] [-c] [-P] [-p] [-a] [-d <cvsroot>]
+	[-w <cvs-workdir>] [-W] [-f] [-m <msgprefix>] [<parent-commit>] <commit-id>
+
+
+DESCRIPTION
+-----------
+Exports a commit from Git to a CVS checkout, making it easier
+to merge patches from a Git repository into a CVS repository.
+
+Specify the name of a CVS checkout using the -w switch or execute it
+from the root of the CVS working copy. In the latter case GIT_DIR must
+be defined. See examples below.
+
+It does its best to do the safe thing, it will check that the files are
+unchanged and up to date in the CVS checkout, and it will not autocommit
+by default.
+
+Supports file additions, removals, and commits that affect binary files.
+
+If the commit is a merge commit, you must tell 'git cvsexportcommit' what
+parent the changeset should be done against.
+
+OPTIONS
+-------
+
+-c::
+	Commit automatically if the patch applied cleanly. It will not
+	commit if any hunks fail to apply or there were other problems.
+
+-p::
+	Be pedantic (paranoid) when applying patches. Invokes patch with
+	--fuzz=0
+
+-a::
+	Add authorship information. Adds Author line, and Committer (if
+	different from Author) to the message.
+
+-d::
+	Set an alternative CVSROOT to use.  This corresponds to the CVS
+	-d parameter.  Usually users will not want to set this, except
+	if using CVS in an asymmetric fashion.
+
+-f::
+	Force the merge even if the files are not up to date.
+
+-P::
+	Force the parent commit, even if it is not a direct parent.
+
+-m::
+	Prepend the commit message with the provided prefix.
+	Useful for patch series and the like.
+
+-u::
+	Update affected files from CVS repository before attempting export.
+
+-k::
+	Reverse CVS keyword expansion (e.g. $Revision: 1.2.3.4$
+	becomes $Revision$) in working CVS checkout before applying patch.
+
+-w::
+	Specify the location of the CVS checkout to use for the export. This
+	option does not require GIT_DIR to be set before execution if the
+	current directory is within a Git repository.  The default is the
+	value of 'cvsexportcommit.cvsdir'.
+
+-W::
+	Tell cvsexportcommit that the current working directory is not only
+	a Git checkout, but also the CVS checkout.  Therefore, Git will
+	reset the working directory to the parent commit before proceeding.
+
+-v::
+	Verbose.
+
+CONFIGURATION
+-------------
+cvsexportcommit.cvsdir::
+	The default location of the CVS checkout to use for the export.
+
+EXAMPLES
+--------
+
+Merge one patch into CVS::
++
+------------
+$ export GIT_DIR=~/project/.git
+$ cd ~/project_cvs_checkout
+$ git cvsexportcommit -v <commit-sha1>
+$ cvs commit -F .msg <files>
+------------
+
+Merge one patch into CVS (-c and -w options). The working directory is within the Git Repo::
++
+------------
+	$ git cvsexportcommit -v -c -w ~/project_cvs_checkout <commit-sha1>
+------------
+
+Merge pending patches into CVS automatically -- only if you really know what you are doing::
++
+------------
+$ export GIT_DIR=~/project/.git
+$ cd ~/project_cvs_checkout
+$ git cherry cvshead myhead | sed -n 's/^+ //p' | xargs -l1 git cvsexportcommit -c -p -v
+------------
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cvsimport.adoc b/Documentation/git-cvsimport.adoc
new file mode 100644
index 0000000000..90fdc2551a
--- /dev/null
+++ b/Documentation/git-cvsimport.adoc
@@ -0,0 +1,228 @@
+git-cvsimport(1)
+================
+
+NAME
+----
+git-cvsimport - Salvage your data out of another SCM people love to hate
+
+
+SYNOPSIS
+--------
+[verse]
+'git cvsimport' [-o <branch-for-HEAD>] [-h] [-v] [-d <CVSROOT>]
+	      [-A <author-conv-file>] [-p <options-for-cvsps>] [-P <file>]
+	      [-C <git-repository>] [-z <fuzz>] [-i] [-k] [-u] [-s <subst>]
+	      [-a] [-m] [-M <regex>] [-S <regex>] [-L <commit-limit>]
+	      [-r <remote>] [-R] [<CVS-module>]
+
+
+DESCRIPTION
+-----------
+*WARNING:* `git cvsimport` uses cvsps version 2, which is considered
+deprecated; it does not work with cvsps version 3 and later.  If you are
+performing a one-shot import of a CVS repository consider using
+http://cvs2svn.tigris.org/cvs2git.html[cvs2git] or
+https://gitlab.com/esr/cvs-fast-export[cvs-fast-export].
+
+Imports a CVS repository into Git. It will either create a new
+repository, or incrementally import into an existing one.
+
+Splitting the CVS log into patch sets is done by 'cvsps'.
+At least version 2.1 is required.
+
+*WARNING:* for certain situations the import leads to incorrect results.
+Please see the section <<issues,ISSUES>> for further reference.
+
+You should *never* do any work of your own on the branches that are
+created by 'git cvsimport'.  By default initial import will create and populate a
+"master" branch from the CVS repository's main branch which you're free
+to work with; after that, you need to 'git merge' incremental imports, or
+any CVS branches, yourself.  It is advisable to specify a named remote via
+-r to separate and protect the incoming branches.
+
+If you intend to set up a shared public repository that all developers can
+read/write, or if you want to use linkgit:git-cvsserver[1], then you
+probably want to make a bare clone of the imported repository,
+and use the clone as the shared repository.
+See linkgit:gitcvs-migration[7].
+
+
+OPTIONS
+-------
+-v::
+	Verbosity: let 'cvsimport' report what it is doing.
+
+-d <CVSROOT>::
+	The root of the CVS archive. May be local (a simple path) or remote;
+	currently, only the :local:, :ext: and :pserver: access methods
+	are supported. If not given, 'git cvsimport' will try to read it
+	from `CVS/Root`. If no such file exists, it checks for the
+	`CVSROOT` environment variable.
+
+<CVS-module>::
+	The CVS module you want to import. Relative to <CVSROOT>.
+	If not given, 'git cvsimport' tries to read it from
+	`CVS/Repository`.
+
+-C <target-dir>::
+	The Git repository to import to.  If the directory doesn't
+        exist, it will be created.  Default is the current directory.
+
+-r <remote>::
+	The Git remote to import this CVS repository into.
+	Moves all CVS branches into remotes/<remote>/<branch>
+	akin to the way 'git clone' uses 'origin' by default.
+
+-o <branch-for-HEAD>::
+	When no remote is specified (via -r) the `HEAD` branch
+	from CVS is imported to the 'origin' branch within the Git
+	repository, as `HEAD` already has a special meaning for Git.
+	When a remote is specified the `HEAD` branch is named
+	remotes/<remote>/master mirroring 'git clone' behaviour.
+	Use this option if you want to import into a different
+	branch.
++
+Use '-o master' for continuing an import that was initially done by
+the old cvs2git tool.
+
+-i::
+	Import-only: don't perform a checkout after importing.  This option
+	ensures the working directory and index remain untouched and will
+	not create them if they do not exist.
+
+-k::
+	Kill keywords: will extract files with '-kk' from the CVS archive
+	to avoid noisy changesets. Highly recommended, but off by default
+	to preserve compatibility with early imported trees.
+
+-u::
+	Convert underscores in tag and branch names to dots.
+
+-s <subst>::
+	Substitute the character "/" in branch names with <subst>
+
+-p <options-for-cvsps>::
+	Additional options for cvsps.
+	The options `-u` and '-A' are implicit and should not be used here.
++
+If you need to pass multiple options, separate them with a comma.
+
+-z <fuzz>::
+	Pass the timestamp fuzz factor to cvsps, in seconds. If unset,
+	cvsps defaults to 300s.
+
+-P <cvsps-output-file>::
+	Instead of calling cvsps, read the provided cvsps output file. Useful
+	for debugging or when cvsps is being handled outside cvsimport.
+
+-m::
+	Attempt to detect merges based on the commit message. This option
+	will enable default regexes that try to capture the source
+	branch name from the commit message.
+
+-M <regex>::
+	Attempt to detect merges based on the commit message with a custom
+	regex. It can be used with `-m` to enable the default regexes
+	as well. You must escape forward slashes.
++
+The regex must capture the source branch name in $1.
++
+This option can be used several times to provide several detection regexes.
+
+-S <regex>::
+	Skip paths matching the regex.
+
+-a::
+	Import all commits, including recent ones. cvsimport by default
+	skips commits that have a timestamp less than 10 minutes ago.
+
+-L <limit>::
+	Limit the number of commits imported. Workaround for cases where
+	cvsimport leaks memory.
+
+-A <author-conv-file>::
+	CVS by default uses the Unix username when writing its
+	commit logs. Using this option and an author-conv-file
+	maps the name recorded in CVS to author name, e-mail and
+	optional time zone:
++
+---------
+	exon=Andreas Ericsson <ae@xxxxxx>
+	spawn=Simon Pawn <spawn@xxxxxxxxxxxxx> America/Chicago
+
+---------
++
+'git cvsimport' will make it appear as those authors had
+their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly
+all along.  If a time zone is specified, GIT_AUTHOR_DATE will
+have the corresponding offset applied.
++
+For convenience, this data is saved to `$GIT_DIR/cvs-authors`
+each time the '-A' option is provided and read from that same
+file each time 'git cvsimport' is run.
++
+It is not recommended to use this feature if you intend to
+export changes back to CVS again later with
+'git cvsexportcommit'.
+
+-R::
+	Generate a `$GIT_DIR/cvs-revisions` file containing a mapping from CVS
+	revision numbers to newly-created Git commit IDs.  The generated file
+	will contain one line for each (filename, revision) pair imported;
+	each line will look like
++
+---------
+src/widget.c 1.1 1d862f173cdc7325b6fa6d2ae1cfd61fd1b512b7
+---------
++
+The revision data is appended to the file if it already exists, for use when
+doing incremental imports.
++
+This option may be useful if you have CVS revision numbers stored in commit
+messages, bug-tracking systems, email archives, and the like.
+
+-h::
+	Print a short usage message and exit.
+
+OUTPUT
+------
+If `-v` is specified, the script reports what it is doing.
+
+Otherwise, success is indicated the Unix way, i.e. by simply exiting with
+a zero exit status.
+
+[[issues]]
+ISSUES
+------
+Problems related to timestamps:
+
+ * If timestamps of commits in the CVS repository are not stable enough
+   to be used for ordering commits changes may show up in the wrong
+   order.
+ * If any files were ever "cvs import"ed more than once (e.g., import of
+   more than one vendor release) the HEAD contains the wrong content.
+ * If the timestamp order of different files cross the revision order
+   within the commit matching time window the order of commits may be
+   wrong.
+
+Problems related to branches:
+
+ * Branches on which no commits have been made are not imported.
+ * All files from the branching point are added to a branch even if
+   never added in CVS.
+ * This applies to files added to the source branch *after* a daughter
+   branch was created: if previously no commit was made on the daughter
+   branch they will erroneously be added to the daughter branch in git.
+
+Problems related to tags:
+
+* Multiple tags on the same revision are not imported.
+
+If you suspect that any of these issues may apply to the repository you
+want to import, consider using cvs2git:
+
+* cvs2git (part of cvs2svn), `https://subversion.apache.org/`
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-cvsserver.adoc b/Documentation/git-cvsserver.adoc
new file mode 100644
index 0000000000..4c475efeab
--- /dev/null
+++ b/Documentation/git-cvsserver.adoc
@@ -0,0 +1,433 @@
+git-cvsserver(1)
+================
+
+NAME
+----
+git-cvsserver - A CVS server emulator for Git
+
+SYNOPSIS
+--------
+
+SSH:
+
+[verse]
+export CVS_SERVER="git cvsserver"
+'cvs' -d :ext:user@server/path/repo.git co <HEAD_name>
+
+pserver (/etc/inetd.conf):
+
+[verse]
+cvspserver stream tcp nowait nobody /usr/bin/git-cvsserver git-cvsserver pserver
+
+Usage:
+
+[verse]
+'git-cvsserver' [<options>] [pserver|server] [<directory> ...]
+
+DESCRIPTION
+-----------
+
+This application is a CVS emulation layer for Git.
+
+It is highly functional. However, not all methods are implemented,
+and for those methods that are implemented,
+not all switches are implemented.
+
+Testing has been done using both the CLI CVS client, and the Eclipse CVS
+plugin. Most functionality works fine with both of these clients.
+
+OPTIONS
+-------
+
+All these options obviously only make sense if enforced by the server side.
+They have been implemented to resemble the linkgit:git-daemon[1] options as
+closely as possible.
+
+--base-path <path>::
+Prepend 'path' to requested CVSROOT
+
+--strict-paths::
+Don't allow recursing into subdirectories
+
+--export-all::
+Don't check for `gitcvs.enabled` in config. You also have to specify a list
+of allowed directories (see below) if you want to use this option.
+
+-V::
+--version::
+Print version information and exit
+
+-h::
+-H::
+--help::
+Print usage information and exit
+
+<directory>::
+The remaining arguments provide a list of directories. If no directories
+are given, then all are allowed. Repositories within these directories
+still require the `gitcvs.enabled` config option, unless `--export-all`
+is specified.
+
+LIMITATIONS
+-----------
+
+CVS clients cannot tag, branch or perform Git merges.
+
+'git-cvsserver' maps Git branches to CVS modules. This is very different
+from what most CVS users would expect since in CVS modules usually represent
+one or more directories.
+
+INSTALLATION
+------------
+
+1. If you are going to offer CVS access via pserver, add a line in
+   /etc/inetd.conf like
++
+--
+------
+   cvspserver stream tcp nowait nobody git-cvsserver pserver
+
+------
+Note: Some inetd servers let you specify the name of the executable
+independently of the value of argv[0] (i.e. the name the program assumes
+it was executed with). In this case the correct line in /etc/inetd.conf
+looks like
+
+------
+   cvspserver stream tcp nowait nobody /usr/bin/git-cvsserver git-cvsserver pserver
+
+------
+
+Only anonymous access is provided by pserver by default. To commit you
+will have to create pserver accounts, simply add a gitcvs.authdb
+setting in the config file of the repositories you want the cvsserver
+to allow writes to, for example:
+
+------
+
+   [gitcvs]
+	authdb = /etc/cvsserver/passwd
+
+------
+The format of these files is username followed by the encrypted password,
+for example:
+
+------
+   myuser:sqkNi8zPf01HI
+   myuser:$1$9K7FzU28$VfF6EoPYCJEYcVQwATgOP/
+   myuser:$5$.NqmNH1vwfzGpV8B$znZIcumu1tNLATgV2l6e1/mY8RzhUDHMOaVOeL1cxV3
+------
+You can use the 'htpasswd' facility that comes with Apache to make these
+files, but only with the -d option (or -B if your system supports it).
+
+Preferably use the system specific utility that manages password hash
+creation in your platform (e.g. mkpasswd in Linux, encrypt in OpenBSD or
+pwhash in NetBSD) and paste it in the right location.
+
+Then provide your password via the pserver method, for example:
+------
+   cvs -d:pserver:someuser:somepassword@server:/path/repo.git co <HEAD_name>
+------
+No special setup is needed for SSH access, other than having Git tools
+in the PATH. If you have clients that do not accept the CVS_SERVER
+environment variable, you can rename 'git-cvsserver' to `cvs`.
+
+Note: Newer CVS versions (>= 1.12.11) also support specifying
+CVS_SERVER directly in CVSROOT like
+
+------
+   cvs -d ":ext;CVS_SERVER=git cvsserver:user@server/path/repo.git" co <HEAD_name>
+------
+This has the advantage that it will be saved in your 'CVS/Root' files and
+you don't need to worry about always setting the correct environment
+variable.  SSH users restricted to 'git-shell' don't need to override the default
+with CVS_SERVER (and shouldn't) as 'git-shell' understands `cvs` to mean
+'git-cvsserver' and pretends that the other end runs the real 'cvs' better.
+--
+2. For each repo that you want accessible from CVS you need to edit config in
+   the repo and add the following section.
++
+--
+------
+   [gitcvs]
+        enabled=1
+        # optional for debugging
+	logFile=/path/to/logfile
+
+------
+Note: you need to ensure each user that is going to invoke 'git-cvsserver' has
+write access to the log file and to the database (see
+<<dbbackend,Database Backend>>. If you want to offer write access over
+SSH, the users of course also need write access to the Git repository itself.
+
+You also need to ensure that each repository is "bare" (without a Git index
+file) for `cvs commit` to work. See linkgit:gitcvs-migration[7].
+
+[[configaccessmethod]]
+All configuration variables can also be overridden for a specific method of
+access. Valid method names are "ext" (for SSH access) and "pserver". The
+following example configuration would disable pserver access while still
+allowing access over SSH.
+------
+   [gitcvs]
+        enabled=0
+
+   [gitcvs "ext"]
+        enabled=1
+------
+--
+3. If you didn't specify the CVSROOT/CVS_SERVER directly in the checkout command,
+   automatically saving it in your 'CVS/Root' files, then you need to set them
+   explicitly in your environment.  CVSROOT should be set as per normal, but the
+   directory should point at the appropriate Git repo.  As above, for SSH clients
+   _not_ restricted to 'git-shell', CVS_SERVER should be set to 'git-cvsserver'.
++
+--
+------
+   export CVSROOT=:ext:user@server:/var/git/project.git
+   export CVS_SERVER="git cvsserver"
+------
+--
+4. For SSH clients that will make commits, make sure their server-side
+   .ssh/environment files (or .bashrc, etc., according to their specific shell)
+   export appropriate values for GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL,
+   GIT_COMMITTER_NAME, and GIT_COMMITTER_EMAIL.  For SSH clients whose login
+   shell is bash, .bashrc may be a reasonable alternative.
+
+5. Clients should now be able to check out the project. Use the CVS 'module'
+   name to indicate what Git 'head' you want to check out.  This also sets the
+   name of your newly checked-out directory, unless you tell it otherwise with
+   `-d <dir-name>`.  For example, this checks out 'master' branch to the
+   `project-master` directory:
++
+------
+   cvs co -d project-master master
+------
+
+[[dbbackend]]
+DATABASE BACKEND
+----------------
+
+'git-cvsserver' uses one database per Git head (i.e. CVS module) to
+store information about the repository to maintain consistent
+CVS revision numbers. The database needs to be
+updated (i.e. written to) after every commit.
+
+If the commit is done directly by using `git` (as opposed to
+using 'git-cvsserver') the update will need to happen on the
+next repository access by 'git-cvsserver', independent of
+access method and requested operation.
+
+That means that even if you offer only read access (e.g. by using
+the pserver method), 'git-cvsserver' should have write access to
+the database to work reliably (otherwise you need to make sure
+that the database is up to date any time 'git-cvsserver' is executed).
+
+By default it uses SQLite databases in the Git directory, named
+`gitcvs.<module-name>.sqlite`. Note that the SQLite backend creates
+temporary files in the same directory as the database file on
+write so it might not be enough to grant the users using
+'git-cvsserver' write access to the database file without granting
+them write access to the directory, too.
+
+The database cannot be reliably regenerated in a
+consistent form after the branch it is tracking has changed.
+Example: For merged branches, 'git-cvsserver' only tracks
+one branch of development, and after a 'git merge' an
+incrementally updated database may track a different branch
+than a database regenerated from scratch, causing inconsistent
+CVS revision numbers. `git-cvsserver` has no way of knowing which
+branch it would have picked if it had been run incrementally
+pre-merge. So if you have to fully or partially (from old
+backup) regenerate the database, you should be suspicious
+of pre-existing CVS sandboxes.
+
+You can configure the database backend with the following
+configuration variables:
+
+Configuring database backend
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+'git-cvsserver' uses the Perl DBI module. Please also read
+its documentation if changing these variables, especially
+about `DBI->connect()`.
+
+gitcvs.dbName::
+	Database name. The exact meaning depends on the
+	selected database driver, for SQLite this is a filename.
+	Supports variable substitution (see below). May
+	not contain semicolons (`;`).
+	Default: '%Ggitcvs.%m.sqlite'
+
+gitcvs.dbDriver::
+	Used DBI driver. You can specify any available driver
+	for this here, but it might not work. cvsserver is tested
+	with 'DBD::SQLite', reported to work with
+	'DBD::Pg', and reported *not* to work with 'DBD::mysql'.
+	Please regard this as an experimental feature. May not
+	contain colons (`:`).
+	Default: 'SQLite'
+
+gitcvs.dbuser::
+	Database user. Only useful if setting `dbDriver`, since
+	SQLite has no concept of database users. Supports variable
+	substitution (see below).
+
+gitcvs.dbPass::
+	Database password.  Only useful if setting `dbDriver`, since
+	SQLite has no concept of database passwords.
+
+gitcvs.dbTableNamePrefix::
+	Database table name prefix.  Supports variable substitution
+	(see below).  Any non-alphabetic characters will be replaced
+	with underscores.
+
+All variables can also be set per access method, see <<configaccessmethod,above>>.
+
+Variable substitution
+^^^^^^^^^^^^^^^^^^^^^
+In `dbDriver` and `dbUser` you can use the following variables:
+
+%G::
+	Git directory name
+%g::
+	Git directory name, where all characters except for
+	alphanumeric ones, `.`, and `-` are replaced with
+	`_` (this should make it easier to use the directory
+	name in a filename if wanted)
+%m::
+	CVS module/Git head name
+%a::
+	access method (one of "ext" or "pserver")
+%u::
+	Name of the user running 'git-cvsserver'.
+	If no name can be determined, the
+	numeric uid is used.
+
+ENVIRONMENT
+-----------
+
+These variables obviate the need for command-line options in some
+circumstances, allowing easier restricted usage through git-shell.
+
+GIT_CVSSERVER_BASE_PATH::
+	This variable replaces the argument to --base-path.
+
+GIT_CVSSERVER_ROOT::
+	This variable specifies a single directory, replacing the
+	`<directory>...` argument list. The repository still requires the
+	`gitcvs.enabled` config option, unless `--export-all` is specified.
+
+When these environment variables are set, the corresponding
+command-line arguments may not be used.
+
+ECLIPSE CVS CLIENT NOTES
+------------------------
+
+To get a checkout with the Eclipse CVS client:
+
+1. Select "Create a new project -> From CVS checkout"
+2. Create a new location. See the notes below for details on how to choose the
+   right protocol.
+3. Browse the 'modules' available. It will give you a list of the heads in
+   the repository. You will not be able to browse the tree from there. Only
+   the heads.
+4. Pick `HEAD` when it asks what branch/tag to check out. Untick the
+   "launch commit wizard" to avoid committing the .project file.
+
+Protocol notes: If you are using anonymous access via pserver, just select that.
+Those using SSH access should choose the 'ext' protocol, and configure 'ext'
+access on the Preferences->Team->CVS->ExtConnection pane. Set CVS_SERVER to
+"`git cvsserver`". Note that password support is not good when using 'ext',
+you will definitely want to have SSH keys setup.
+
+Alternatively, you can just use the non-standard extssh protocol that Eclipse
+offer. In that case CVS_SERVER is ignored, and you will have to replace
+the cvs utility on the server with 'git-cvsserver' or manipulate your `.bashrc`
+so that calling 'cvs' effectively calls 'git-cvsserver'.
+
+CLIENTS KNOWN TO WORK
+---------------------
+
+- CVS 1.12.9 on Debian
+- CVS 1.11.17 on MacOSX (from Fink package)
+- Eclipse 3.0, 3.1.2 on MacOSX (see Eclipse CVS Client Notes)
+- TortoiseCVS
+
+OPERATIONS SUPPORTED
+--------------------
+
+All the operations required for normal use are supported, including
+checkout, diff, status, update, log, add, remove, commit.
+
+Most CVS command arguments that read CVS tags or revision numbers
+(typically -r) work, and also support any git refspec
+(tag, branch, commit ID, etc).
+However, CVS revision numbers for non-default branches are not well
+emulated, and cvs log does not show tags or branches at
+all.  (Non-main-branch CVS revision numbers superficially resemble CVS
+revision numbers, but they actually encode a git commit ID directly,
+rather than represent the number of revisions since the branch point.)
+
+Note that there are two ways to checkout a particular branch.
+As described elsewhere on this page, the "module" parameter
+of cvs checkout is interpreted as a branch name, and it becomes
+the main branch.  It remains the main branch for a given sandbox
+even if you temporarily make another branch sticky with
+cvs update -r.  Alternatively, the -r argument can indicate
+some other branch to actually checkout, even though the module
+is still the "main" branch.  Tradeoffs (as currently
+implemented): Each new "module" creates a new database on disk with
+a history for the given module, and after the database is created,
+operations against that main branch are fast.  Or alternatively,
+-r doesn't take any extra disk space, but may be significantly slower for
+many operations, like cvs update.
+
+If you want to refer to a git refspec that has characters that are
+not allowed by CVS, you have two options.  First, it may just work
+to supply the git refspec directly to the appropriate CVS -r argument;
+some CVS clients don't seem to do much sanity checking of the argument.
+Second, if that fails, you can use a special character escape mechanism
+that only uses characters that are valid in CVS tags.  A sequence
+of 4 or 5 characters of the form (underscore (`"_"`), dash (`"-"`),
+one or two characters, and dash (`"-"`)) can encode various characters based
+on the one or two letters: `"s"` for slash (`"/"`), `"p"` for
+period (`"."`), `"u"` for underscore (`"_"`), or two hexadecimal digits
+for any byte value at all (typically an ASCII number, or perhaps a part
+of a UTF-8 encoded character).
+
+Legacy monitoring operations are not supported (edit, watch and related).
+Exports and tagging (tags and branches) are not supported at this stage.
+
+CRLF Line Ending Conversions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+By default the server leaves the `-k` mode blank for all files,
+which causes the CVS client to treat them as a text files, subject
+to end-of-line conversion on some platforms.
+
+You can make the server use the end-of-line conversion attributes to
+set the `-k` modes for files by setting the `gitcvs.usecrlfattr`
+config variable.  See linkgit:gitattributes[5] for more information
+about end-of-line conversion.
+
+Alternatively, if `gitcvs.usecrlfattr` config is not enabled
+or the attributes do not allow automatic detection for a filename, then
+the server uses the `gitcvs.allBinary` config for the default setting.
+If `gitcvs.allBinary` is set, then file not otherwise
+specified will default to '-kb' mode. Otherwise the `-k` mode
+is left blank. But if `gitcvs.allBinary` is set to "guess", then
+the correct `-k` mode will be guessed based on the contents of
+the file.
+
+For best consistency with 'cvs', it is probably best to override the
+defaults by setting `gitcvs.usecrlfattr` to true,
+and `gitcvs.allBinary` to "guess".
+
+DEPENDENCIES
+------------
+'git-cvsserver' depends on DBD::SQLite.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-daemon.adoc b/Documentation/git-daemon.adoc
new file mode 100644
index 0000000000..ede7b935d6
--- /dev/null
+++ b/Documentation/git-daemon.adoc
@@ -0,0 +1,341 @@
+git-daemon(1)
+=============
+
+NAME
+----
+git-daemon - A really simple server for Git repositories
+
+SYNOPSIS
+--------
+[verse]
+'git daemon' [--verbose] [--syslog] [--export-all]
+	     [--timeout=<n>] [--init-timeout=<n>] [--max-connections=<n>]
+	     [--strict-paths] [--base-path=<path>] [--base-path-relaxed]
+	     [--user-path | --user-path=<path>]
+	     [--interpolated-path=<pathtemplate>]
+	     [--reuseaddr] [--detach] [--pid-file=<file>]
+	     [--enable=<service>] [--disable=<service>]
+	     [--allow-override=<service>] [--forbid-override=<service>]
+	     [--access-hook=<path>] [--[no-]informative-errors]
+	     [--inetd |
+	      [--listen=<host-or-ipaddr>] [--port=<n>]
+	      [--user=<user> [--group=<group>]]]
+	     [--log-destination=(stderr|syslog|none)]
+	     [<directory>...]
+
+DESCRIPTION
+-----------
+A really simple TCP Git daemon that normally listens on port "DEFAULT_GIT_PORT"
+aka 9418.  It waits for a connection asking for a service, and will serve
+that service if it is enabled.
+
+It verifies that the directory has the magic file "git-daemon-export-ok", and
+it will refuse to export any Git directory that hasn't explicitly been marked
+for export this way (unless the `--export-all` parameter is specified). If you
+pass some directory paths as 'git daemon' arguments, the offers are limited to
+repositories within those directories.
+
+By default, only `upload-pack` service is enabled, which serves
+'git fetch-pack' and 'git ls-remote' clients, which are invoked
+from 'git fetch', 'git pull', and 'git clone'.
+
+This is ideally suited for read-only updates, i.e., pulling from
+Git repositories.
+
+An `upload-archive` also exists to serve 'git archive'.
+
+OPTIONS
+-------
+--strict-paths::
+	Match paths exactly (i.e. don't allow "/foo/repo" when the real path is
+	"/foo/repo.git" or "/foo/repo/.git") and don't do user-relative paths.
+	'git daemon' will refuse to start when this option is enabled and no
+	directory arguments are provided.
+
+--base-path=<path>::
+	Remap all the path requests as relative to the given path.
+	This is sort of "Git root" - if you run 'git daemon' with
+	'--base-path=/srv/git' on example.com, then if you later try to pull
+	'git://example.com/hello.git', 'git daemon' will interpret the path
+	as `/srv/git/hello.git`.
+
+--base-path-relaxed::
+	If --base-path is enabled and repo lookup fails, with this option
+	'git daemon' will attempt to lookup without prefixing the base path.
+	This is useful for switching to --base-path usage, while still
+	allowing the old paths.
+
+--interpolated-path=<pathtemplate>::
+	To support virtual hosting, an interpolated path template can be
+	used to dynamically construct alternate paths.  The template
+	supports %H for the target hostname as supplied by the client but
+	converted to all lowercase, %CH for the canonical hostname,
+	%IP for the server's IP address, %P for the port number,
+	and %D for the absolute path of the named repository.
+	After interpolation, the path is validated against the directory
+	list.
+
+--export-all::
+	Allow pulling from all directories that look like Git repositories
+	(have the 'objects' and 'refs' subdirectories), even if they
+	do not have the 'git-daemon-export-ok' file.
+
+--inetd::
+	Have the server run as an inetd service. Implies --syslog (may be
+	overridden with `--log-destination=`).
+	Incompatible with --detach, --port, --listen, --user and --group
+	options.
+
+--listen=<host-or-ipaddr>::
+	Listen on a specific IP address or hostname.  IP addresses can
+	be either an IPv4 address or an IPv6 address if supported.  If IPv6
+	is not supported, then --listen=<hostname> is also not supported and
+	--listen must be given an IPv4 address.
+	Can be given more than once.
+	Incompatible with `--inetd` option.
+
+--port=<n>::
+	Listen on an alternative port.  Incompatible with `--inetd` option.
+
+--init-timeout=<n>::
+	Timeout (in seconds) between the moment the connection is established
+	and the client request is received (typically a rather low value, since
+	that should be basically immediate).
+
+--timeout=<n>::
+	Timeout (in seconds) for specific client sub-requests. This includes
+	the time it takes for the server to process the sub-request and the
+	time spent waiting for the next client's request.
+
+--max-connections=<n>::
+	Maximum number of concurrent clients, defaults to 32.  Set it to
+	zero for no limit.
+
+--syslog::
+	Short for `--log-destination=syslog`.
+
+--log-destination=<destination>::
+	Send log messages to the specified destination.
+	Note that this option does not imply --verbose,
+	thus by default only error conditions will be logged.
+	The <destination> must be one of:
++
+--
+stderr::
+	Write to standard error.
+	Note that if `--detach` is specified,
+	the process disconnects from the real standard error,
+	making this destination effectively equivalent to `none`.
+syslog::
+	Write to syslog, using the `git-daemon` identifier.
+none::
+	Disable all logging.
+--
++
+The default destination is `syslog` if `--inetd` or `--detach` is specified,
+otherwise `stderr`.
+
+--user-path::
+--user-path=<path>::
+	Allow {tilde}user notation to be used in requests.  When
+	specified with no parameter, a request to
+	git://host/{tilde}alice/foo is taken as a request to access
+	'foo' repository in the home directory of user `alice`.
+	If `--user-path=<path>` is specified, the same request is
+	taken as a request to access `<path>/foo` repository in
+	the home directory of user `alice`.
+
+--verbose::
+	Log details about the incoming connections and requested files.
+
+--reuseaddr::
+	Use SO_REUSEADDR when binding the listening socket.
+	This allows the server to restart without waiting for
+	old connections to time out.
+
+--detach::
+	Detach from the shell. Implies --syslog.
+
+--pid-file=<file>::
+	Save the process id in 'file'.  Ignored when the daemon
+	is run under `--inetd`.
+
+--user=<user>::
+--group=<group>::
+	Change daemon's uid and gid before entering the service loop.
+	When only `--user` is given without `--group`, the
+	primary group ID for the user is used.  The values of
+	the option are given to `getpwnam(3)` and `getgrnam(3)`
+	and numeric IDs are not supported.
++
+Giving these options is an error when used with `--inetd`; use
+the facility of inet daemon to achieve the same before spawning
+'git daemon' if needed.
++
+Like many programs that switch user id, the daemon does not reset
+environment variables such as `$HOME` when it runs git programs,
+e.g. `upload-pack` and `receive-pack`. When using this option, you
+may also want to set and export `HOME` to point at the home
+directory of `<user>` before starting the daemon, and make sure any
+Git configuration files in that directory are readable by `<user>`.
+
+--enable=<service>::
+--disable=<service>::
+	Enable/disable the service site-wide per default.  Note
+	that a service disabled site-wide can still be enabled
+	per repository if it is marked overridable and the
+	repository enables the service with a configuration
+	item.
+
+--allow-override=<service>::
+--forbid-override=<service>::
+	Allow/forbid overriding the site-wide default with per
+	repository configuration.  By default, all the services
+	may be overridden.
+
+--[no-]informative-errors::
+	When informative errors are turned on, git-daemon will report
+	more verbose errors to the client, differentiating conditions
+	like "no such repository" from "repository not exported". This
+	is more convenient for clients, but may leak information about
+	the existence of unexported repositories.  When informative
+	errors are not enabled, all errors report "access denied" to the
+	client. The default is --no-informative-errors.
+
+--access-hook=<path>::
+	Every time a client connects, first run an external command
+	specified by the <path> with service name (e.g. "upload-pack"),
+	path to the repository, hostname (%H), canonical hostname
+	(%CH), IP address (%IP), and TCP port (%P) as its command-line
+	arguments. The external command can decide to decline the
+	service by exiting with a non-zero status (or to allow it by
+	exiting with a zero status).  It can also look at the $REMOTE_ADDR
+	and `$REMOTE_PORT` environment variables to learn about the
+	requestor when making this decision.
++
+The external command can optionally write a single line to its
+standard output to be sent to the requestor as an error message when
+it declines the service.
+
+<directory>::
+	The remaining arguments provide a list of directories. If any
+	directories are specified, then the `git-daemon` process will
+	serve a requested directory only if it is contained in one of
+	these directories. If `--strict-paths` is specified, then the
+	requested directory must match one of these directories exactly.
+
+SERVICES
+--------
+
+These services can be globally enabled/disabled using the
+command-line options of this command.  If finer-grained
+control is desired (e.g. to allow 'git archive' to be run
+against only in a few selected repositories the daemon serves),
+the per-repository configuration file can be used to enable or
+disable them.
+
+upload-pack::
+	This serves 'git fetch-pack' and 'git ls-remote'
+	clients.  It is enabled by default, but a repository can
+	disable it by setting `daemon.uploadpack` configuration
+	item to `false`.
+
+upload-archive::
+	This serves 'git archive --remote'.  It is disabled by
+	default, but a repository can enable it by setting
+	`daemon.uploadarch` configuration item to `true`.
+
+receive-pack::
+	This serves 'git send-pack' clients, allowing anonymous
+	push.  It is disabled by default, as there is _no_
+	authentication in the protocol (in other words, anybody
+	can push anything into the repository, including removal
+	of refs).  This is solely meant for a closed LAN setting
+	where everybody is friendly.  This service can be
+	enabled by setting `daemon.receivepack` configuration item to
+	`true`.
+
+EXAMPLES
+--------
+We assume the following in /etc/services::
++
+------------
+$ grep 9418 /etc/services
+git		9418/tcp		# Git Version Control System
+------------
+
+'git daemon' as inetd server::
+	To set up 'git daemon' as an inetd service that handles any
+	repository within `/pub/foo` or `/pub/bar`, place an entry like
+	the following into `/etc/inetd` all on one line:
++
+------------------------------------------------
+	git stream tcp nowait nobody  /usr/bin/git
+		git daemon --inetd --verbose --export-all
+		/pub/foo /pub/bar
+------------------------------------------------
+
+
+'git daemon' as inetd server for virtual hosts::
+	To set up 'git daemon' as an inetd service that handles
+	repositories for different virtual hosts, `www.example.com`
+	and `www.example.org`, place an entry like the following into
+	`/etc/inetd` all on one line:
++
+------------------------------------------------
+	git stream tcp nowait nobody /usr/bin/git
+		git daemon --inetd --verbose --export-all
+		--interpolated-path=/pub/%H%D
+		/pub/www.example.org/software
+		/pub/www.example.com/software
+		/software
+------------------------------------------------
++
+In this example, the root-level directory `/pub` will contain
+a subdirectory for each virtual host name supported.
+Further, both hosts advertise repositories simply as
+`git://www.example.com/software/repo.git`.  For pre-1.4.0
+clients, a symlink from `/software` into the appropriate
+default repository could be made as well.
+
+
+'git daemon' as regular daemon for virtual hosts::
+	To set up 'git daemon' as a regular, non-inetd service that
+	handles repositories for multiple virtual hosts based on
+	their IP addresses, start the daemon like this:
++
+------------------------------------------------
+	git daemon --verbose --export-all
+		--interpolated-path=/pub/%IP/%D
+		/pub/192.168.1.200/software
+		/pub/10.10.220.23/software
+------------------------------------------------
++
+In this example, the root-level directory `/pub` will contain
+a subdirectory for each virtual host IP address supported.
+Repositories can still be accessed by hostname though, assuming
+they correspond to these IP addresses.
+
+selectively enable/disable services per repository::
+	To enable 'git archive --remote' and disable 'git fetch' against
+	a repository, have the following in the configuration file in the
+	repository (that is the file 'config' next to `HEAD`, 'refs' and
+	'objects').
++
+----------------------------------------------------------------
+	[daemon]
+		uploadpack = false
+		uploadarch = true
+----------------------------------------------------------------
+
+
+ENVIRONMENT
+-----------
+'git daemon' will set REMOTE_ADDR to the IP address of the client
+that connected to it, if the IP address is available. REMOTE_ADDR will
+be available in the environment of hooks called when
+services are performed.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-describe.adoc b/Documentation/git-describe.adoc
new file mode 100644
index 0000000000..08ff715709
--- /dev/null
+++ b/Documentation/git-describe.adoc
@@ -0,0 +1,211 @@
+git-describe(1)
+===============
+
+NAME
+----
+git-describe - Give an object a human readable name based on an available ref
+
+SYNOPSIS
+--------
+[verse]
+'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]
+'git describe' [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]
+'git describe' <blob>
+
+DESCRIPTION
+-----------
+The command finds the most recent tag that is reachable from a
+commit.  If the tag points to the commit, then only the tag is
+shown.  Otherwise, it suffixes the tag name with the number of
+additional commits on top of the tagged object and the
+abbreviated object name of the most recent commit. The result
+is a "human-readable" object name which can also be used to
+identify the commit to other git commands.
+
+By default (without --all or --tags) `git describe` only shows
+annotated tags.  For more information about creating annotated tags
+see the -a and -s options to linkgit:git-tag[1].
+
+If the given object refers to a blob, it will be described
+as `<commit-ish>:<path>`, such that the blob can be found
+at `<path>` in the `<commit-ish>`, which itself describes the
+first commit in which this blob occurs in a reverse revision walk
+from HEAD.
+
+OPTIONS
+-------
+<commit-ish>...::
+	Commit-ish object names to describe.  Defaults to HEAD if omitted.
+
+--dirty[=<mark>]::
+--broken[=<mark>]::
+	Describe the state of the working tree.  When the working
+	tree matches HEAD, the output is the same as "git describe
+	HEAD".  If the working tree has local modification "-dirty"
+	is appended to it.  If a repository is corrupt and Git
+	cannot determine if there is local modification, Git will
+	error out, unless `--broken' is given, which appends
+	the suffix "-broken" instead.
+
+--all::
+	Instead of using only the annotated tags, use any ref
+	found in `refs/` namespace.  This option enables matching
+	any known branch, remote-tracking branch, or lightweight tag.
+
+--tags::
+	Instead of using only the annotated tags, use any tag
+	found in `refs/tags` namespace.  This option enables matching
+	a lightweight (non-annotated) tag.
+
+--contains::
+	Instead of finding the tag that predates the commit, find
+	the tag that comes after the commit, and thus contains it.
+	Automatically implies --tags.
+
+--abbrev=<n>::
+	Instead of using the default number of hexadecimal digits (which
+	will vary according to the number of objects in the repository with
+	a default of 7) of the abbreviated object name, use <n> digits, or
+	as many digits as needed to form a unique object name. An <n> of 0
+	will suppress long format, only showing the closest tag.
+
+--candidates=<n>::
+	Instead of considering only the 10 most recent tags as
+	candidates to describe the input commit-ish consider
+	up to <n> candidates.  Increasing <n> above 10 will take
+	slightly longer but may produce a more accurate result.
+	An <n> of 0 will cause only exact matches to be output.
+
+--exact-match::
+	Only output exact matches (a tag directly references the
+	supplied commit).  This is a synonym for --candidates=0.
+
+--debug::
+	Verbosely display information about the searching strategy
+	being employed to standard error.  The tag name will still
+	be printed to standard out.
+
+--long::
+	Always output the long format (the tag, the number of commits
+	and the abbreviated commit name) even when it matches a tag.
+	This is useful when you want to see parts of the commit object name
+	in "describe" output, even when the commit in question happens to be
+	a tagged version.  Instead of just emitting the tag name, it will
+	describe such a commit as v1.2-0-gdeadbee (0th commit since tag v1.2
+	that points at object deadbee....).
+
+--match <pattern>::
+	Only consider tags matching the given `glob(7)` pattern,
+	excluding the "refs/tags/" prefix. If used with `--all`, it also
+	considers local branches and remote-tracking references matching the
+	pattern, excluding respectively "refs/heads/" and "refs/remotes/"
+	prefix; references of other types are never considered. If given
+	multiple times, a list of patterns will be accumulated, and tags
+	matching any of the patterns will be considered.  Use `--no-match` to
+	clear and reset the list of patterns.
+
+--exclude <pattern>::
+	Do not consider tags matching the given `glob(7)` pattern, excluding
+	the "refs/tags/" prefix. If used with `--all`, it also does not consider
+	local branches and remote-tracking references matching the pattern,
+	excluding respectively "refs/heads/" and "refs/remotes/" prefix;
+	references of other types are never considered. If given multiple times,
+	a list of patterns will be accumulated and tags matching any of the
+	patterns will be excluded. When combined with --match a tag will be
+	considered when it matches at least one --match pattern and does not
+	match any of the --exclude patterns. Use `--no-exclude` to clear and
+	reset the list of patterns.
+
+--always::
+	Show uniquely abbreviated commit object as fallback.
+
+--first-parent::
+	Follow only the first parent commit upon seeing a merge commit.
+	This is useful when you wish to not match tags on branches merged
+	in the history of the target commit.
+
+EXAMPLES
+--------
+
+With something like git.git current tree, I get:
+
+	[torvalds@g5 git]$ git describe parent
+	v1.0.4-14-g2414721
+
+i.e. the current head of my "parent" branch is based on v1.0.4,
+but since it has a few commits on top of that,
+describe has added the number of additional commits ("14") and
+an abbreviated object name for the commit itself ("2414721")
+at the end.
+
+The number of additional commits is the number
+of commits which would be displayed by "git log v1.0.4..parent".
+The hash suffix is "-g" + an unambiguous abbreviation for the tip commit
+of parent (which was `2414721b194453f058079d897d13c4e377f92dc6`). The
+length of the abbreviation scales as the repository grows, using the
+approximate number of objects in the repository and a bit of math
+around the birthday paradox, and defaults to a minimum of 7.
+The "g" prefix stands for "git" and is used to allow describing the version of
+a software depending on the SCM the software is managed with. This is useful
+in an environment where people may use different SCMs.
+
+Doing a 'git describe' on a tag-name will just show the tag name:
+
+	[torvalds@g5 git]$ git describe v1.0.4
+	v1.0.4
+
+With --all, the command can use branch heads as references, so
+the output shows the reference path as well:
+
+	[torvalds@g5 git]$ git describe --all --abbrev=4 v1.0.5^2
+	tags/v1.0.0-21-g975b
+
+	[torvalds@g5 git]$ git describe --all --abbrev=4 HEAD^
+	heads/lt/describe-7-g975b
+
+With --abbrev set to 0, the command can be used to find the
+closest tagname without any suffix:
+
+	[torvalds@g5 git]$ git describe --abbrev=0 v1.0.5^2
+	tags/v1.0.0
+
+Note that the suffix you get if you type these commands today may be
+longer than what Linus saw above when he ran these commands, as your
+Git repository may have new commits whose object names begin with
+975b that did not exist back then, and "-g975b" suffix alone may not
+be sufficient to disambiguate these commits.
+
+
+SEARCH STRATEGY
+---------------
+
+For each commit-ish supplied, 'git describe' will first look for
+a tag which tags exactly that commit.  Annotated tags will always
+be preferred over lightweight tags, and tags with newer dates will
+always be preferred over tags with older dates.  If an exact match
+is found, its name will be output and searching will stop.
+
+If an exact match was not found, 'git describe' will walk back
+through the commit history to locate an ancestor commit which
+has been tagged.  The ancestor's tag will be output along with an
+abbreviation of the input commit-ish's SHA-1. If `--first-parent` was
+specified then the walk will only consider the first parent of each
+commit.
+
+If multiple tags were found during the walk then the tag which
+has the fewest commits different from the input commit-ish will be
+selected and output.  Here fewest commits different is defined as
+the number of commits which would be shown by `git log tag..input`
+will be the smallest number of commits possible.
+
+BUGS
+----
+
+Tree objects as well as tag objects not pointing at commits, cannot be described.
+When describing blobs, the lightweight tags pointing at blobs are ignored,
+but the blob is still described as <commit-ish>:<path> despite the lightweight
+tag being favorable.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diagnose.adoc b/Documentation/git-diagnose.adoc
new file mode 100644
index 0000000000..0711959e6f
--- /dev/null
+++ b/Documentation/git-diagnose.adoc
@@ -0,0 +1,65 @@
+git-diagnose(1)
+================
+
+NAME
+----
+git-diagnose - Generate a zip archive of diagnostic information
+
+SYNOPSIS
+--------
+[verse]
+'git diagnose' [(-o | --output-directory) <path>] [(-s | --suffix) <format>]
+	       [--mode=<mode>]
+
+DESCRIPTION
+-----------
+Collects detailed information about the user's machine, Git client, and
+repository state and packages that information into a zip archive. The
+generated archive can then, for example, be shared with the Git mailing list to
+help debug an issue or serve as a reference for independent debugging.
+
+By default, the following information is captured in the archive:
+
+  * 'git version --build-options'
+  * The path to the repository root
+  * The available disk space on the filesystem
+  * The name and size of each packfile, including those in alternate object
+    stores
+  * The total count of loose objects, as well as counts broken down by
+    `.git/objects` subdirectory
+
+Additional information can be collected by selecting a different diagnostic mode
+using the `--mode` option.
+
+This tool differs from linkgit:git-bugreport[1] in that it collects much more
+detailed information with a greater focus on reporting the size and data shape
+of repository contents.
+
+OPTIONS
+-------
+-o <path>::
+--output-directory <path>::
+	Place the resulting diagnostics archive in `<path>` instead of the
+	current directory.
+
+-s <format>::
+--suffix <format>::
+	Specify an alternate suffix for the diagnostics archive name, to create
+	a file named 'git-diagnostics-<formatted-suffix>'. This should take the
+	form of a strftime(3) format string; the current local time will be
+	used.
+
+--mode=(stats|all)::
+	Specify the type of diagnostics that should be collected. The default behavior
+	of 'git diagnose' is equivalent to `--mode=stats`.
++
+The `--mode=all` option collects everything included in `--mode=stats`, as well
+as copies of `.git`, `.git/hooks`, `.git/info`, `.git/logs`, and
+`.git/objects/info` directories. This additional information may be sensitive,
+as it can be used to reconstruct the full contents of the diagnosed repository.
+Users should exercise caution when sharing an archive generated with
+`--mode=all`.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diff-files.adoc b/Documentation/git-diff-files.adoc
new file mode 100644
index 0000000000..2b2358ca1c
--- /dev/null
+++ b/Documentation/git-diff-files.adoc
@@ -0,0 +1,52 @@
+git-diff-files(1)
+=================
+
+NAME
+----
+git-diff-files - Compares files in the working tree and the index
+
+
+SYNOPSIS
+--------
+[verse]
+'git diff-files' [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]
+
+DESCRIPTION
+-----------
+Compares the files in the working tree and the index.  When paths
+are specified, compares only those named paths.  Otherwise all
+entries in the index are compared.  The output format is the
+same as for 'git diff-index' and 'git diff-tree'.
+
+OPTIONS
+-------
+include::diff-options.adoc[]
+
+-1 --base::
+-2 --ours::
+-3 --theirs::
+-0::
+	Diff against the "base" version, "our branch", or "their
+	branch" respectively.  With these options, diffs for
+	merged entries are not shown.
++
+The default is to diff against our branch (-2) and the
+cleanly resolved paths.  The option -0 can be given to
+omit diff output for unmerged entries and just show "Unmerged".
+
+-c::
+--cc::
+	This compares stage 2 (our branch), stage 3 (their
+	branch), and the working tree file and outputs a combined
+	diff, similar to the way 'diff-tree' shows a merge
+	commit with these flags.
+
+-q::
+	Remain silent even for nonexistent files
+
+
+include::diff-format.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diff-index.adoc b/Documentation/git-diff-index.adoc
new file mode 100644
index 0000000000..911446a296
--- /dev/null
+++ b/Documentation/git-diff-index.adoc
@@ -0,0 +1,127 @@
+git-diff-index(1)
+=================
+
+NAME
+----
+git-diff-index - Compare a tree to the working tree or index
+
+
+SYNOPSIS
+--------
+[verse]
+'git diff-index' [-m] [--cached] [--merge-base] [<common-diff-options>] <tree-ish> [<path>...]
+
+DESCRIPTION
+-----------
+Compare the content and mode of the blobs found in a tree object
+with the corresponding tracked files in the working tree, or with the
+corresponding paths in the index.  When <path> arguments are present,
+compare only paths matching those patterns.  Otherwise all tracked
+files are compared.
+
+OPTIONS
+-------
+include::diff-options.adoc[]
+
+<tree-ish>::
+	The id of a tree object to diff against.
+
+--cached::
+	Do not consider the on-disk file at all.
+
+--merge-base::
+	Instead of comparing <tree-ish> directly, use the merge base
+	between <tree-ish> and HEAD instead.  <tree-ish> must be a
+	commit.
+
+-m::
+	By default, files recorded in the index but not checked
+	out are reported as deleted.  This flag makes
+	'git diff-index' say that all non-checked-out files are up
+	to date.
+
+include::diff-format.adoc[]
+
+OPERATING MODES
+---------------
+You can choose whether you want to trust the index file entirely
+(using the `--cached` flag) or ask the diff logic to show any files
+that don't match the stat state as being "tentatively changed".  Both
+of these operations are very useful indeed.
+
+CACHED MODE
+-----------
+If `--cached` is specified, it allows you to ask:
+
+	show me the differences between HEAD and the current index
+	contents (the ones I'd write using 'git write-tree')
+
+For example, let's say that you have worked on your working directory, updated
+some files in the index and are ready to commit. You want to see exactly
+*what* you are going to commit, without having to write a new tree
+object and compare it that way, and to do that, you just do
+
+	git diff-index --cached HEAD
+
+Example: let's say I had renamed `commit.c` to `git-commit.c`, and I had
+done an `update-index` to make that effective in the index file.
+`git diff-files` wouldn't show anything at all, since the index file
+matches my working directory. But doing a 'git diff-index' does:
+
+  torvalds@ppc970:~/git> git diff-index --cached HEAD
+  :100644 000000 4161aecc6700a2eb579e842af0b7f22b98443f74 0000000000000000000000000000000000000000 D	commit.c
+  :000000 100644 0000000000000000000000000000000000000000 4161aecc6700a2eb579e842af0b7f22b98443f74 A	git-commit.c
+
+You can see easily that the above is a rename.
+
+In fact, `git diff-index --cached` *should* always be entirely equivalent to
+actually doing a 'git write-tree' and comparing that. Except this one is much
+nicer for the case where you just want to check where you are.
+
+So doing a `git diff-index --cached` is basically very useful when you are
+asking yourself "what have I already marked for being committed, and
+what's the difference to a previous tree".
+
+NON-CACHED MODE
+---------------
+The "non-cached" mode takes a different approach, and is potentially
+the more useful of the two in that what it does can't be emulated with
+a 'git write-tree' + 'git diff-tree'. Thus that's the default mode.
+The non-cached version asks the question:
+
+  show me the differences between HEAD and the currently checked out
+  tree - index contents _and_ files that aren't up to date
+
+which is obviously a very useful question too, since that tells you what
+you *could* commit. Again, the output matches the 'git diff-tree -r'
+output to a tee, but with a twist.
+
+The twist is that if some file doesn't match the index, we don't have
+a backing store thing for it, and we use the magic "all-zero" sha1 to
+show that. So let's say that you have edited `kernel/sched.c`, but
+have not actually done a 'git update-index' on it yet - there is no
+"object" associated with the new state, and you get:
+
+  torvalds@ppc970:~/v2.6/linux> git diff-index --abbrev HEAD
+  :100644 100644 7476bb5ba 000000000 M	kernel/sched.c
+
+i.e., it shows that the tree has changed, and that `kernel/sched.c` is
+not up to date and may contain new stuff. The all-zero sha1 means that to
+get the real diff, you need to look at the object in the working directory
+directly rather than do an object-to-object diff.
+
+NOTE: As with other commands of this type, 'git diff-index' does not
+actually look at the contents of the file at all. So maybe
+`kernel/sched.c` hasn't actually changed, and it's just that you
+touched it. In either case, it's a note that you need to
+'git update-index' it to make the index be in sync.
+
+NOTE: You can have a mixture of files show up as "has been updated"
+and "is still dirty in the working directory" together. You can always
+tell which file is in which state, since the "has been updated" ones
+show a valid sha1, and the "not in sync with the index" ones will
+always have the special all-zero sha1.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diff-tree.adoc b/Documentation/git-diff-tree.adoc
new file mode 100644
index 0000000000..f1e3134bde
--- /dev/null
+++ b/Documentation/git-diff-tree.adoc
@@ -0,0 +1,131 @@
+git-diff-tree(1)
+================
+
+NAME
+----
+git-diff-tree - Compares the content and mode of blobs found via two tree objects
+
+
+SYNOPSIS
+--------
+[verse]
+'git diff-tree' [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty]
+	      [-t] [-r] [-c | --cc] [--combined-all-paths] [--root] [--merge-base]
+	      [<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]
+
+DESCRIPTION
+-----------
+Compare the content and mode of blobs found via two tree objects.
+
+If there is only one <tree-ish> given, the commit is compared with its parents
+(see --stdin below).
+
+Note that 'git diff-tree' can use the tree encapsulated in a commit object.
+
+OPTIONS
+-------
+include::diff-options.adoc[]
+
+<tree-ish>::
+	The id of a tree object.
+
+<path>...::
+	If provided, the results are limited to a subset of files
+	matching one of the provided pathspecs.
+
+-r::
+	Recurse into sub-trees.
+
+-t::
+	Show tree entry itself as well as subtrees.  Implies -r.
+
+--root::
+	When `--root` is specified the initial commit will be shown as a big
+	creation event. This is equivalent to a diff against the NULL tree.
+
+--merge-base::
+	Instead of comparing the <tree-ish>s directly, use the merge
+	base between the two <tree-ish>s as the "before" side.  There
+	must be two <tree-ish>s given and they must both be commits.
+
+--stdin::
+	When `--stdin` is specified, the command does not take
+	<tree-ish> arguments from the command line.  Instead, it
+	reads lines containing either two <tree>, one <commit>, or a
+	list of <commit> from its standard input.  (Use a single space
+	as separator.)
++
+When two trees are given, it compares the first tree with the second.
+When a single commit is given, it compares the commit with its
+parents.  The remaining commits, when given, are used as if they are
+parents of the first commit.
++
+When comparing two trees, the ID of both trees (separated by a space
+and terminated by a newline) is printed before the difference.  When
+comparing commits, the ID of the first (or only) commit, followed by a
+newline, is printed.
++
+The following flags further affect the behavior when comparing
+commits (but not trees).
+
+-m::
+	By default, 'git diff-tree --stdin' does not show
+	differences for merge commits.  With this flag, it shows
+	differences to that commit from all of its parents. See
+	also `-c`.
+
+-s::
+	By default, 'git diff-tree --stdin' shows differences,
+	either in machine-readable form (without `-p`) or in patch
+	form (with `-p`).  This output can be suppressed.  It is
+	only useful with the `-v` flag.
+
+-v::
+	This flag causes 'git diff-tree --stdin' to also show
+	the commit message before the differences.
+
+include::pretty-options.adoc[]
+
+--no-commit-id::
+	'git diff-tree' outputs a line with the commit ID when
+	applicable.  This flag suppresses the commit ID output.
+
+-c::
+	This flag changes the way a merge commit is displayed
+	(which means it is useful only when the command is given
+	one <tree-ish>, or `--stdin`).  It shows the differences
+	from each of the parents to the merge result simultaneously
+	instead of showing pairwise diff between a parent and the
+	result one at a time (which is what the `-m` option does).
+	Furthermore, it lists only files which were modified
+	from all parents.
+
+--cc::
+	This flag changes the way a merge commit patch is displayed,
+	in a similar way to the `-c` option. It implies the `-c`
+	and `-p` options and further compresses the patch output
+	by omitting uninteresting hunks whose contents in the parents
+	have only two variants and the merge result picks one of them
+	without modification.  When all hunks are uninteresting, the commit
+	itself and the commit log message are not shown, just like in any other
+	"empty diff" case.
+
+--combined-all-paths::
+	This flag causes combined diffs (used for merge commits) to
+	list the name of the file from all parents.  It thus only has
+	effect when -c or --cc are specified, and is likely only
+	useful if filename changes are detected (i.e. when either
+	rename or copy detection have been requested).
+
+--always::
+	Show the commit itself and the commit log message even
+	if the diff itself is empty.
+
+
+include::pretty-formats.adoc[]
+
+include::diff-format.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-diff.adoc b/Documentation/git-diff.adoc
new file mode 100644
index 0000000000..f597adb9e9
--- /dev/null
+++ b/Documentation/git-diff.adoc
@@ -0,0 +1,252 @@
+git-diff(1)
+===========
+
+NAME
+----
+git-diff - Show changes between commits, commit and working tree, etc
+
+
+SYNOPSIS
+--------
+[synopsis]
+git diff [<options>] [<commit>] [--] [<path>...]
+git diff [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]
+git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]
+git diff [<options>] <commit>...<commit> [--] [<path>...]
+git diff [<options>] <blob> <blob>
+git diff [<options>] --no-index [--] <path> <path>
+
+DESCRIPTION
+-----------
+Show changes between the working tree and the index or a tree, changes
+between the index and a tree, changes between two trees, changes resulting
+from a merge, changes between two blob objects, or changes between two
+files on disk.
+
+`git diff [<options>] [--] [<path>...]`::
+
+	This form is to view the changes you made relative to
+	the index (staging area for the next commit).  In other
+	words, the differences are what you _could_ tell Git to
+	further add to the index but you still haven't.  You can
+	stage these changes by using linkgit:git-add[1].
+
+`git diff [<options>] --no-index [--] <path> <path>`::
+
+	This form is to compare the given two paths on the
+	filesystem.  You can omit the `--no-index` option when
+	running the command in a working tree controlled by Git and
+	at least one of the paths points outside the working tree,
+	or when running the command outside a working tree
+	controlled by Git. This form implies `--exit-code`.
+
+`git diff [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]`::
+
+	This form is to view the changes you staged for the next
+	commit relative to the named _<commit>_.  Typically you
+	would want comparison with the latest commit, so if you
+	do not give _<commit>_, it defaults to `HEAD`.
+	If `HEAD` does not exist (e.g. unborn branches) and
+	_<commit>_ is not given, it shows all staged changes.
+	`--staged` is a synonym of `--cached`.
++
+If `--merge-base` is given, instead of using _<commit>_, use the merge base
+of _<commit>_ and `HEAD`.  `git diff --cached --merge-base A` is equivalent to
+`git diff --cached $(git merge-base A HEAD)`.
+
+`git diff [<options>] [--merge-base] <commit> [--] [<path>...]`::
+
+	This form is to view the changes you have in your
+	working tree relative to the named _<commit>_.  You can
+	use `HEAD` to compare it with the latest commit, or a
+	branch name to compare with the tip of a different
+	branch.
++
+If `--merge-base` is given, instead of using _<commit>_, use the merge base
+of _<commit>_ and `HEAD`.  `git diff --merge-base A` is equivalent to
+`git diff $(git merge-base A HEAD)`.
+
+`git diff [<options>] [--merge-base] <commit> <commit> [--] [<path>...]`::
+
+	This is to view the changes between two arbitrary
+	_<commit>_.
++
+If `--merge-base` is given, use the merge base of the two commits for the
+"before" side.  `git diff --merge-base A B` is equivalent to
+`git diff $(git merge-base A B) B`.
+
+`git diff [<options>] <commit> <commit>...<commit> [--] [<path>...]`::
+
+	This form is to view the results of a merge commit.  The first
+	listed _<commit>_ must be the merge itself; the remaining two or
+	more commits should be its parents.  Convenient ways to produce
+	the desired set of revisions are to use the suffixes `@` and
+	`^!`.  If `A` is a merge commit, then `git diff A A^@`,
+	`git diff A^!` and `git show A` all give the same combined diff.
+
+`git diff [<options>] <commit>..<commit> [--] [<path>...]`::
+
+	This is synonymous to the earlier form (without the `..`) for
+	viewing the changes between two arbitrary _<commit>_.  If _<commit>_ on
+	one side is omitted, it will have the same effect as
+	using `HEAD` instead.
+
+`git diff [<options>] <commit>...<commit> [--] [<path>...]`::
+
+	This form is to view the changes on the branch containing
+	and up to the second _<commit>_, starting at a common ancestor
+	of both _<commit>_.  `git diff A...B` is equivalent to
+	`git diff $(git merge-base A B) B`.  You can omit any one
+	of _<commit>_, which has the same effect as using `HEAD` instead.
+
+Just in case you are doing something exotic, it should be
+noted that all of the _<commit>_ in the above description, except
+in the `--merge-base` case and in the last two forms that use `..`
+notations, can be any _<tree>_. A tree of interest is the one pointed to
+by the ref named `AUTO_MERGE`, which is written by the `ort` merge
+strategy upon hitting merge conflicts (see linkgit:git-merge[1]).
+Comparing the working tree with `AUTO_MERGE` shows changes you've made
+so far to resolve textual conflicts (see the examples below).
+
+For a more complete list of ways to spell _<commit>_, see
+"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
+However, `diff` is about comparing two _endpoints_, not ranges,
+and the range notations (`<commit>..<commit>` and `<commit>...<commit>`)
+do not mean a range as defined in the
+"SPECIFYING RANGES" section in linkgit:gitrevisions[7].
+
+`git diff [<options>] <blob> <blob>`::
+
+	This form is to view the differences between the raw
+	contents of two blob objects.
+
+OPTIONS
+-------
+:git-diff: 1
+include::diff-options.adoc[]
+
+`-1`::
+`--base`::
+`-2`::
+`--ours`::
+`-3`::
+`--theirs`::
+	Compare the working tree with
++
+--
+ * the "base" version (stage #1) when using `-1` or `--base`,
+ * "our branch" (stage #2) when using `-2` or `--ours`, or
+ * "their branch" (stage #3) when using `-3` or `--theirs`.
+--
++
+The index contains these stages only for unmerged entries i.e.
+while resolving conflicts.  See linkgit:git-read-tree[1]
+section "3-Way Merge" for detailed information.
+
+`-0`::
+	Omit diff output for unmerged entries and just show
+	"Unmerged".  Can be used only when comparing the working tree
+	with the index.
+
+`<path>...`::
+	The _<path>_ parameters, when given, are used to limit
+	the diff to the named paths (you can give directory
+	names and get diff for all files under them).
+
+
+include::diff-format.adoc[]
+
+EXAMPLES
+--------
+
+Various ways to check your working tree::
++
+------------
+$ git diff            <1>
+$ git diff --cached   <2>
+$ git diff HEAD       <3>
+$ git diff AUTO_MERGE <4>
+------------
++
+<1> Changes in the working tree not yet staged for the next commit.
+<2> Changes between the index and your last commit; what you
+    would be committing if you run `git commit` without `-a` option.
+<3> Changes in the working tree since your last commit; what you
+    would be committing if you run `git commit -a`
+<4> Changes in the working tree you've made to resolve textual
+    conflicts so far.
+
+Comparing with arbitrary commits::
++
+------------
+$ git diff test            <1>
+$ git diff HEAD -- ./test  <2>
+$ git diff HEAD^ HEAD      <3>
+------------
++
+<1> Instead of using the tip of the current branch, compare with the
+    tip of "test" branch.
+<2> Instead of comparing with the tip of "test" branch, compare with
+    the tip of the current branch, but limit the comparison to the
+    file "test".
+<3> Compare the version before the last commit and the last commit.
+
+Comparing branches::
++
+------------
+$ git diff topic master    <1>
+$ git diff topic..master   <2>
+$ git diff topic...master  <3>
+------------
++
+<1> Changes between the tips of the topic and the master branches.
+<2> Same as above.
+<3> Changes that occurred on the master branch since when the topic
+    branch was started off it.
+
+Limiting the diff output::
++
+------------
+$ git diff --diff-filter=MRC            <1>
+$ git diff --name-status                <2>
+$ git diff arch/i386 include/asm-i386   <3>
+------------
++
+<1> Show only modification, rename, and copy, but not addition
+    or deletion.
+<2> Show only names and the nature of change, but not actual
+    diff output.
+<3> Limit diff output to named subtrees.
+
+Munging the diff output::
++
+------------
+$ git diff --find-copies-harder -B -C  <1>
+$ git diff -R                          <2>
+------------
++
+<1> Spend extra cycles to find renames, copies and complete
+    rewrites (very expensive).
+<2> Output diff in reverse.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+:git-diff: 1
+include::config/diff.adoc[]
+
+SEE ALSO
+--------
+`diff`(1),
+linkgit:git-difftool[1],
+linkgit:git-log[1],
+linkgit:gitdiffcore[7],
+linkgit:git-format-patch[1],
+linkgit:git-apply[1],
+linkgit:git-show[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-difftool.adoc b/Documentation/git-difftool.adoc
new file mode 100644
index 0000000000..718289ce54
--- /dev/null
+++ b/Documentation/git-difftool.adoc
@@ -0,0 +1,139 @@
+git-difftool(1)
+===============
+
+NAME
+----
+git-difftool - Show changes using common diff tools
+
+SYNOPSIS
+--------
+[verse]
+'git difftool' [<options>] [<commit> [<commit>]] [--] [<path>...]
+
+DESCRIPTION
+-----------
+'git difftool' is a Git command that allows you to compare and edit files
+between revisions using common diff tools.  'git difftool' is a frontend
+to 'git diff' and accepts the same options and arguments. See
+linkgit:git-diff[1].
+
+OPTIONS
+-------
+-d::
+--dir-diff::
+	Copy the modified files to a temporary location and perform
+	a directory diff on them. This mode never prompts before
+	launching the diff tool.
+
+-y::
+--no-prompt::
+	Do not prompt before launching a diff tool.
+
+--prompt::
+	Prompt before each invocation of the diff tool.
+	This is the default behaviour; the option is provided to
+	override any configuration settings.
+
+--rotate-to=<file>::
+	Start showing the diff for the given path,
+	the paths before it will move to the end and output.
+
+--skip-to=<file>::
+	Start showing the diff for the given path, skipping all
+	the paths before it.
+
+-t <tool>::
+--tool=<tool>::
+	Use the diff tool specified by <tool>.  Valid values include
+	emerge, kompare, meld, and vimdiff. Run `git difftool --tool-help`
+	for the list of valid <tool> settings.
++
+If a diff tool is not specified, 'git difftool'
+will use the configuration variable `diff.tool`.  If the
+configuration variable `diff.tool` is not set, 'git difftool'
+will pick a suitable default.
++
+You can explicitly provide a full path to the tool by setting the
+configuration variable `difftool.<tool>.path`. For example, you
+can configure the absolute path to kdiff3 by setting
+`difftool.kdiff3.path`. Otherwise, 'git difftool' assumes the
+tool is available in PATH.
++
+Instead of running one of the known diff tools,
+'git difftool' can be customized to run an alternative program
+by specifying the command line to invoke in a configuration
+variable `difftool.<tool>.cmd`.
++
+When 'git difftool' is invoked with this tool (either through the
+`-t` or `--tool` option or the `diff.tool` configuration variable)
+the configured command line will be invoked with the following
+variables available: `$LOCAL` is set to the name of the temporary
+file containing the contents of the diff pre-image and `$REMOTE`
+is set to the name of the temporary file containing the contents
+of the diff post-image.  `$MERGED` is the name of the file which is
+being compared. `$BASE` is provided for compatibility
+with custom merge tool commands and has the same value as `$MERGED`.
+
+--tool-help::
+	Print a list of diff tools that may be used with `--tool`.
+
+--[no-]symlinks::
+	'git difftool''s default behavior is to create symlinks to the
+	working tree when run in `--dir-diff` mode and the right-hand
+	side of the comparison yields the same content as the file in
+	the working tree.
++
+Specifying `--no-symlinks` instructs 'git difftool' to create copies
+instead.  `--no-symlinks` is the default on Windows.
+
+-x <command>::
+--extcmd=<command>::
+	Specify a custom command for viewing diffs.
+	'git-difftool' ignores the configured defaults and runs
+	`<command> $LOCAL $REMOTE` when this option is specified.
+	Additionally, `$BASE` is set in the environment.
+
+-g::
+--[no-]gui::
+	When 'git-difftool' is invoked with the `-g` or `--gui` option
+	the default diff tool will be read from the configured
+	`diff.guitool` variable instead of `diff.tool`. This may be
+	selected automatically using the configuration variable
+	`difftool.guiDefault`. The `--no-gui` option can be used to
+	override these settings. If `diff.guitool` is not set, we will
+	fallback in the order of `merge.guitool`, `diff.tool`,
+	`merge.tool` until a tool is found.
+
+--[no-]trust-exit-code::
+	Errors reported by the diff tool are ignored by default.
+	Use `--trust-exit-code` to make 'git-difftool' exit when an
+	invoked diff tool returns a non-zero exit code.
++
+'git-difftool' will forward the exit code of the invoked tool when
+`--trust-exit-code` is used.
+
+See linkgit:git-diff[1] for the full list of supported options.
+
+CONFIGURATION
+-------------
+'git difftool' falls back to 'git mergetool' config variables when the
+difftool equivalents have not been defined.
+
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/difftool.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-diff[1]::
+	 Show changes between commits, commit and working tree, etc
+
+linkgit:git-mergetool[1]::
+	Run merge conflict resolution tools to resolve merge conflicts
+
+linkgit:git-config[1]::
+	 Get and set repository or global options
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fast-export.adoc b/Documentation/git-fast-export.adoc
new file mode 100644
index 0000000000..752e4b9b01
--- /dev/null
+++ b/Documentation/git-fast-export.adoc
@@ -0,0 +1,284 @@
+git-fast-export(1)
+==================
+
+NAME
+----
+git-fast-export - Git data exporter
+
+
+SYNOPSIS
+--------
+[verse]
+'git fast-export' [<options>] | 'git fast-import'
+
+DESCRIPTION
+-----------
+This program dumps the given revisions in a form suitable to be piped
+into 'git fast-import'.
+
+You can use it as a human-readable bundle replacement (see
+linkgit:git-bundle[1]), or as a format that can be edited before being
+fed to 'git fast-import' in order to do history rewrites (an ability
+relied on by tools like 'git filter-repo').
+
+OPTIONS
+-------
+--progress=<n>::
+	Insert 'progress' statements every <n> objects, to be shown by
+	'git fast-import' during import.
+
+--signed-tags=(verbatim|warn|warn-strip|strip|abort)::
+	Specify how to handle signed tags.  Since any transformation
+	after the export can change the tag names (which can also happen
+	when excluding revisions) the signatures will not match.
++
+When asking to 'abort' (which is the default), this program will die
+when encountering a signed tag.  With 'strip', the tags will silently
+be made unsigned, with 'warn-strip' they will be made unsigned but a
+warning will be displayed, with 'verbatim', they will be silently
+exported and with 'warn', they will be exported, but you will see a
+warning.
+
+--tag-of-filtered-object=(abort|drop|rewrite)::
+	Specify how to handle tags whose tagged object is filtered out.
+	Since revisions and files to export can be limited by path,
+	tagged objects may be filtered completely.
++
+When asking to 'abort' (which is the default), this program will die
+when encountering such a tag.  With 'drop' it will omit such tags from
+the output.  With 'rewrite', if the tagged object is a commit, it will
+rewrite the tag to tag an ancestor commit (via parent rewriting; see
+linkgit:git-rev-list[1]).
+
+-M::
+-C::
+	Perform move and/or copy detection, as described in the
+	linkgit:git-diff[1] manual page, and use it to generate
+	rename and copy commands in the output dump.
++
+Note that earlier versions of this command did not complain and
+produced incorrect results if you gave these options.
+
+--export-marks=<file>::
+	Dumps the internal marks table to <file> when complete.
+	Marks are written one per line as `:markid SHA-1`. Only marks
+	for revisions are dumped; marks for blobs are ignored.
+	Backends can use this file to validate imports after they
+	have been completed, or to save the marks table across
+	incremental runs.  As <file> is only opened and truncated
+	at completion, the same path can also be safely given to
+	--import-marks.
+	The file will not be written if no new object has been
+	marked/exported.
+
+--import-marks=<file>::
+	Before processing any input, load the marks specified in
+	<file>.  The input file must exist, must be readable, and
+	must use the same format as produced by --export-marks.
+
+--mark-tags::
+	In addition to labelling blobs and commits with mark ids, also
+	label tags.  This is useful in conjunction with
+	`--export-marks` and `--import-marks`, and is also useful (and
+	necessary) for exporting of nested tags.  It does not hurt
+	other cases and would be the default, but many fast-import
+	frontends are not prepared to accept tags with mark
+	identifiers.
++
+Any commits (or tags) that have already been marked will not be
+exported again.  If the backend uses a similar --import-marks file,
+this allows for incremental bidirectional exporting of the repository
+by keeping the marks the same across runs.
+
+--fake-missing-tagger::
+	Some old repositories have tags without a tagger.  The
+	fast-import protocol was pretty strict about that, and did not
+	allow that.  So fake a tagger to be able to fast-import the
+	output.
+
+--use-done-feature::
+	Start the stream with a 'feature done' stanza, and terminate
+	it with a 'done' command.
+
+--no-data::
+	Skip output of blob objects and instead refer to blobs via
+	their original SHA-1 hash.  This is useful when rewriting the
+	directory structure or history of a repository without
+	touching the contents of individual files.  Note that the
+	resulting stream can only be used by a repository which
+	already contains the necessary objects.
+
+--full-tree::
+	This option will cause fast-export to issue a "deleteall"
+	directive for each commit followed by a full list of all files
+	in the commit (as opposed to just listing the files which are
+	different from the commit's first parent).
+
+--anonymize::
+	Anonymize the contents of the repository while still retaining
+	the shape of the history and stored tree.  See the section on
+	`ANONYMIZING` below.
+
+--anonymize-map=<from>[:<to>]::
+	Convert token `<from>` to `<to>` in the anonymized output. If
+	`<to>` is omitted, map `<from>` to itself (i.e., do not
+	anonymize it). See the section on `ANONYMIZING` below.
+
+--reference-excluded-parents::
+	By default, running a command such as `git fast-export
+	master~5..master` will not include the commit master{tilde}5
+	and will make master{tilde}4 no longer have master{tilde}5 as
+	a parent (though both the old master{tilde}4 and new
+	master{tilde}4 will have all the same files).  Use
+	--reference-excluded-parents to instead have the stream
+	refer to commits in the excluded range of history by their
+	sha1sum.  Note that the resulting stream can only be used by a
+	repository which already contains the necessary parent
+	commits.
+
+--show-original-ids::
+	Add an extra directive to the output for commits and blobs,
+	`original-oid <SHA1SUM>`.  While such directives will likely be
+	ignored by importers such as git-fast-import, it may be useful
+	for intermediary filters (e.g. for rewriting commit messages
+	which refer to older commits, or for stripping blobs by id).
+
+--reencode=(yes|no|abort)::
+	Specify how to handle `encoding` header in commit objects.  When
+	asking to 'abort' (which is the default), this program will die
+	when encountering such a commit object.  With 'yes', the commit
+	message will be re-encoded into UTF-8.  With 'no', the original
+	encoding will be preserved.
+
+--refspec::
+	Apply the specified refspec to each ref exported. Multiple of them can
+	be specified.
+
+[<git-rev-list-args>...]::
+	A list of arguments, acceptable to 'git rev-parse' and
+	'git rev-list', that specifies the specific objects and references
+	to export.  For example, `master~10..master` causes the
+	current master reference to be exported along with all objects
+	added since its 10th ancestor commit and (unless the
+	--reference-excluded-parents option is specified) all files
+	common to master{tilde}9 and master{tilde}10.
+
+EXAMPLES
+--------
+
+-------------------------------------------------------------------
+$ git fast-export --all | (cd /empty/repository && git fast-import)
+-------------------------------------------------------------------
+
+This will export the whole repository and import it into the existing
+empty repository.  Except for reencoding commits that are not in
+UTF-8, it would be a one-to-one mirror.
+
+-----------------------------------------------------
+$ git fast-export master~5..master |
+	sed "s|refs/heads/master|refs/heads/other|" |
+	git fast-import
+-----------------------------------------------------
+
+This makes a new branch called 'other' from 'master~5..master'
+(i.e. if 'master' has linear history, it will take the last 5 commits).
+
+Note that this assumes that none of the blobs and commit messages
+referenced by that revision range contains the string
+'refs/heads/master'.
+
+
+ANONYMIZING
+-----------
+
+If the `--anonymize` option is given, git will attempt to remove all
+identifying information from the repository while still retaining enough
+of the original tree and history patterns to reproduce some bugs. The
+goal is that a git bug which is found on a private repository will
+persist in the anonymized repository, and the latter can be shared with
+git developers to help solve the bug.
+
+With this option, git will replace all refnames, paths, blob contents,
+commit and tag messages, names, and email addresses in the output with
+anonymized data.  Two instances of the same string will be replaced
+equivalently (e.g., two commits with the same author will have the same
+anonymized author in the output, but bear no resemblance to the original
+author string). The relationship between commits, branches, and tags is
+retained, as well as the commit timestamps (but the commit messages and
+refnames bear no resemblance to the originals). The relative makeup of
+the tree is retained (e.g., if you have a root tree with 10 files and 3
+trees, so will the output), but their names and the contents of the
+files will be replaced.
+
+If you think you have found a git bug, you can start by exporting an
+anonymized stream of the whole repository:
+
+---------------------------------------------------
+$ git fast-export --anonymize --all >anon-stream
+---------------------------------------------------
+
+Then confirm that the bug persists in a repository created from that
+stream (many bugs will not, as they really do depend on the exact
+repository contents):
+
+---------------------------------------------------
+$ git init anon-repo
+$ cd anon-repo
+$ git fast-import <../anon-stream
+$ ... test your bug ...
+---------------------------------------------------
+
+If the anonymized repository shows the bug, it may be worth sharing
+`anon-stream` along with a regular bug report. Note that the anonymized
+stream compresses very well, so gzipping it is encouraged. If you want
+to examine the stream to see that it does not contain any private data,
+you can peruse it directly before sending. You may also want to try:
+
+---------------------------------------------------
+$ perl -pe 's/\d+/X/g' <anon-stream | sort -u | less
+---------------------------------------------------
+
+which shows all of the unique lines (with numbers converted to "X", to
+collapse "User 0", "User 1", etc into "User X"). This produces a much
+smaller output, and it is usually easy to quickly confirm that there is
+no private data in the stream.
+
+Reproducing some bugs may require referencing particular commits or
+paths, which becomes challenging after refnames and paths have been
+anonymized. You can ask for a particular token to be left as-is or
+mapped to a new value. For example, if you have a bug which reproduces
+with `git rev-list sensitive -- secret.c`, you can run:
+
+---------------------------------------------------
+$ git fast-export --anonymize --all \
+      --anonymize-map=sensitive:foo \
+      --anonymize-map=secret.c:bar.c \
+      >stream
+---------------------------------------------------
+
+After importing the stream, you can then run `git rev-list foo -- bar.c`
+in the anonymized repository.
+
+Note that paths and refnames are split into tokens at slash boundaries.
+The command above would anonymize `subdir/secret.c` as something like
+`path123/bar.c`; you could then search for `bar.c` in the anonymized
+repository to determine the final pathname.
+
+To make referencing the final pathname simpler, you can map each path
+component; so if you also anonymize `subdir` to `publicdir`, then the
+final pathname would be `publicdir/bar.c`.
+
+LIMITATIONS
+-----------
+
+Since 'git fast-import' cannot tag trees, you will not be
+able to export the linux.git repository completely, as it contains
+a tag referencing a tree instead of a commit.
+
+SEE ALSO
+--------
+linkgit:git-fast-import[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fast-import.adoc b/Documentation/git-fast-import.adoc
new file mode 100644
index 0000000000..9981c46e9f
--- /dev/null
+++ b/Documentation/git-fast-import.adoc
@@ -0,0 +1,1591 @@
+git-fast-import(1)
+==================
+
+NAME
+----
+git-fast-import - Backend for fast Git data importers
+
+
+SYNOPSIS
+--------
+[verse]
+frontend | 'git fast-import' [<options>]
+
+DESCRIPTION
+-----------
+This program is usually not what the end user wants to run directly.
+Most end users want to use one of the existing frontend programs,
+which parses a specific type of foreign source and feeds the contents
+stored there to 'git fast-import'.
+
+fast-import reads a mixed command/data stream from standard input and
+writes one or more packfiles directly into the current repository.
+When EOF is received on standard input, fast import writes out
+updated branch and tag refs, fully updating the current repository
+with the newly imported data.
+
+The fast-import backend itself can import into an empty repository (one that
+has already been initialized by 'git init') or incrementally
+update an existing populated repository.  Whether or not incremental
+imports are supported from a particular foreign source depends on
+the frontend program in use.
+
+
+OPTIONS
+-------
+
+--force::
+	Force updating modified existing branches, even if doing
+	so would cause commits to be lost (as the new commit does
+	not contain the old commit).
+
+--quiet::
+	Disable the output shown by --stats, making fast-import usually
+	be silent when it is successful.  However, if the import stream
+	has directives intended to show user output (e.g. `progress`
+	directives), the corresponding messages will still be shown.
+
+--stats::
+	Display some basic statistics about the objects fast-import has
+	created, the packfiles they were stored into, and the
+	memory used by fast-import during this run.  Showing this output
+	is currently the default, but can be disabled with --quiet.
+
+--allow-unsafe-features::
+	Many command-line options can be provided as part of the
+	fast-import stream itself by using the `feature` or `option`
+	commands. However, some of these options are unsafe (e.g.,
+	allowing fast-import to access the filesystem outside of the
+	repository). These options are disabled by default, but can be
+	allowed by providing this option on the command line.  This
+	currently impacts only the `export-marks`, `import-marks`, and
+	`import-marks-if-exists` feature commands.
++
+	Only enable this option if you trust the program generating the
+	fast-import stream! This option is enabled automatically for
+	remote-helpers that use the `import` capability, as they are
+	already trusted to run their own code.
+
+Options for Frontends
+~~~~~~~~~~~~~~~~~~~~~
+
+--cat-blob-fd=<fd>::
+	Write responses to `get-mark`, `cat-blob`, and `ls` queries to the
+	file descriptor <fd> instead of `stdout`.  Allows `progress`
+	output intended for the end-user to be separated from other
+	output.
+
+--date-format=<fmt>::
+	Specify the type of dates the frontend will supply to
+	fast-import within `author`, `committer` and `tagger` commands.
+	See ``Date Formats'' below for details about which formats
+	are supported, and their syntax.
+
+--done::
+	Terminate with error if there is no `done` command at the end of
+	the stream.  This option might be useful for detecting errors
+	that cause the frontend to terminate before it has started to
+	write a stream.
+
+Locations of Marks Files
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+--export-marks=<file>::
+	Dumps the internal marks table to <file> when complete.
+	Marks are written one per line as `:markid SHA-1`.
+	Frontends can use this file to validate imports after they
+	have been completed, or to save the marks table across
+	incremental runs.  As <file> is only opened and truncated
+	at checkpoint (or completion) the same path can also be
+	safely given to --import-marks.
+
+--import-marks=<file>::
+	Before processing any input, load the marks specified in
+	<file>.  The input file must exist, must be readable, and
+	must use the same format as produced by --export-marks.
+	Multiple options may be supplied to import more than one
+	set of marks.  If a mark is defined to different values,
+	the last file wins.
+
+--import-marks-if-exists=<file>::
+	Like --import-marks but instead of erroring out, silently
+	skips the file if it does not exist.
+
+--[no-]relative-marks::
+	After specifying --relative-marks the paths specified
+	with --import-marks= and --export-marks= are relative
+	to an internal directory in the current repository.
+	In git-fast-import this means that the paths are relative
+	to the .git/info/fast-import directory. However, other
+	importers may use a different location.
++
+Relative and non-relative marks may be combined by interweaving
+--(no-)-relative-marks with the --(import|export)-marks= options.
+
+Submodule Rewriting
+~~~~~~~~~~~~~~~~~~~
+
+--rewrite-submodules-from=<name>:<file>::
+--rewrite-submodules-to=<name>:<file>::
+  Rewrite the object IDs for the submodule specified by <name> from the values
+	used in the from <file> to those used in the to <file>. The from marks should
+	have been created by `git fast-export`, and the to marks should have been
+	created by `git fast-import` when importing that same submodule.
++
+<name> may be any arbitrary string not containing a colon character, but the
+same value must be used with both options when specifying corresponding marks.
+Multiple submodules may be specified with different values for <name>. It is an
+error not to use these options in corresponding pairs.
++
+These options are primarily useful when converting a repository from one hash
+algorithm to another; without them, fast-import will fail if it encounters a
+submodule because it has no way of writing the object ID into the new hash
+algorithm.
+
+Performance and Compression Tuning
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+--active-branches=<n>::
+	Maximum number of branches to maintain active at once.
+	See ``Memory Utilization'' below for details.  Default is 5.
+
+--big-file-threshold=<n>::
+	Maximum size of a blob that fast-import will attempt to
+	create a delta for, expressed in bytes.  The default is 512m
+	(512 MiB).  Some importers may wish to lower this on systems
+	with constrained memory.
+
+--depth=<n>::
+	Maximum delta depth, for blob and tree deltification.
+	Default is 50.
+
+--export-pack-edges=<file>::
+	After creating a packfile, print a line of data to
+	<file> listing the filename of the packfile and the last
+	commit on each branch that was written to that packfile.
+	This information may be useful after importing projects
+	whose total object set exceeds the 4 GiB packfile limit,
+	as these commits can be used as edge points during calls
+	to 'git pack-objects'.
+
+--max-pack-size=<n>::
+	Maximum size of each output packfile.
+	The default is unlimited.
+
+fastimport.unpackLimit::
+	See linkgit:git-config[1]
+
+PERFORMANCE
+-----------
+The design of fast-import allows it to import large projects in a minimum
+amount of memory usage and processing time.  Assuming the frontend
+is able to keep up with fast-import and feed it a constant stream of data,
+import times for projects holding 10+ years of history and containing
+100,000+ individual commits are generally completed in just 1-2
+hours on quite modest (~$2,000 USD) hardware.
+
+Most bottlenecks appear to be in foreign source data access (the
+source just cannot extract revisions fast enough) or disk IO (fast-import
+writes as fast as the disk will take the data).  Imports will run
+faster if the source data is stored on a different drive than the
+destination Git repository (due to less IO contention).
+
+
+DEVELOPMENT COST
+----------------
+A typical frontend for fast-import tends to weigh in at approximately 200
+lines of Perl/Python/Ruby code.  Most developers have been able to
+create working importers in just a couple of hours, even though it
+is their first exposure to fast-import, and sometimes even to Git.  This is
+an ideal situation, given that most conversion tools are throw-away
+(use once, and never look back).
+
+
+PARALLEL OPERATION
+------------------
+Like 'git push' or 'git fetch', imports handled by fast-import are safe to
+run alongside parallel `git repack -a -d` or `git gc` invocations,
+or any other Git operation (including 'git prune', as loose objects
+are never used by fast-import).
+
+fast-import does not lock the branch or tag refs it is actively importing.
+After the import, during its ref update phase, fast-import tests each
+existing branch ref to verify the update will be a fast-forward
+update (the commit stored in the ref is contained in the new
+history of the commit to be written).  If the update is not a
+fast-forward update, fast-import will skip updating that ref and instead
+prints a warning message.  fast-import will always attempt to update all
+branch refs, and does not stop on the first failure.
+
+Branch updates can be forced with --force, but it's recommended that
+this only be used on an otherwise quiet repository.  Using --force
+is not necessary for an initial import into an empty repository.
+
+
+TECHNICAL DISCUSSION
+--------------------
+fast-import tracks a set of branches in memory.  Any branch can be created
+or modified at any point during the import process by sending a
+`commit` command on the input stream.  This design allows a frontend
+program to process an unlimited number of branches simultaneously,
+generating commits in the order they are available from the source
+data.  It also simplifies the frontend programs considerably.
+
+fast-import does not use or alter the current working directory, or any
+file within it.  (It does however update the current Git repository,
+as referenced by `GIT_DIR`.)  Therefore an import frontend may use
+the working directory for its own purposes, such as extracting file
+revisions from the foreign source.  This ignorance of the working
+directory also allows fast-import to run very quickly, as it does not
+need to perform any costly file update operations when switching
+between branches.
+
+INPUT FORMAT
+------------
+With the exception of raw file data (which Git does not interpret)
+the fast-import input format is text (ASCII) based.  This text based
+format simplifies development and debugging of frontend programs,
+especially when a higher level language such as Perl, Python or
+Ruby is being used.
+
+fast-import is very strict about its input.  Where we say SP below we mean
+*exactly* one space.  Likewise LF means one (and only one) linefeed
+and HT one (and only one) horizontal tab.
+Supplying additional whitespace characters will cause unexpected
+results, such as branch names or file names with leading or trailing
+spaces in their name, or early termination of fast-import when it encounters
+unexpected input.
+
+Stream Comments
+~~~~~~~~~~~~~~~
+To aid in debugging frontends fast-import ignores any line that
+begins with `#` (ASCII pound/hash) up to and including the line
+ending `LF`.  A comment line may contain any sequence of bytes
+that does not contain an LF and therefore may be used to include
+any detailed debugging information that might be specific to the
+frontend and useful when inspecting a fast-import data stream.
+
+Date Formats
+~~~~~~~~~~~~
+The following date formats are supported.  A frontend should select
+the format it will use for this import by passing the format name
+in the --date-format=<fmt> command-line option.
+
+`raw`::
+	This is the Git native format and is `<time> SP <offutc>`.
+	It is also fast-import's default format, if --date-format was
+	not specified.
++
+The time of the event is specified by `<time>` as the number of
+seconds since the UNIX epoch (midnight, Jan 1, 1970, UTC) and is
+written as an ASCII decimal integer.
++
+The local offset is specified by `<offutc>` as a positive or negative
+offset from UTC.  For example EST (which is 5 hours behind UTC)
+would be expressed in `<tz>` by ``-0500'' while UTC is ``+0000''.
+The local offset does not affect `<time>`; it is used only as an
+advisement to help formatting routines display the timestamp.
++
+If the local offset is not available in the source material, use
+``+0000'', or the most common local offset.  For example many
+organizations have a CVS repository which has only ever been accessed
+by users who are located in the same location and time zone.  In this
+case a reasonable offset from UTC could be assumed.
++
+Unlike the `rfc2822` format, this format is very strict.  Any
+variation in formatting will cause fast-import to reject the value,
+and some sanity checks on the numeric values may also be performed.
+
+`raw-permissive`::
+	This is the same as `raw` except that no sanity checks on
+	the numeric epoch and local offset are performed.  This can
+	be useful when trying to filter or import an existing history
+	with e.g. bogus timezone values.
+
+`rfc2822`::
+	This is the standard date format as described by RFC 2822.
++
+An example value is ``Tue Feb 6 11:22:18 2007 -0500''.  The Git
+parser is accurate, but a little on the lenient side.  It is the
+same parser used by 'git am' when applying patches
+received from email.
++
+Some malformed strings may be accepted as valid dates.  In some of
+these cases Git will still be able to obtain the correct date from
+the malformed string.  There are also some types of malformed
+strings which Git will parse wrong, and yet consider valid.
+Seriously malformed strings will be rejected.
++
+Unlike the `raw` format above, the time zone/UTC offset information
+contained in an RFC 2822 date string is used to adjust the date
+value to UTC prior to storage.  Therefore it is important that
+this information be as accurate as possible.
++
+If the source material uses RFC 2822 style dates,
+the frontend should let fast-import handle the parsing and conversion
+(rather than attempting to do it itself) as the Git parser has
+been well tested in the wild.
++
+Frontends should prefer the `raw` format if the source material
+already uses UNIX-epoch format, can be coaxed to give dates in that
+format, or its format is easily convertible to it, as there is no
+ambiguity in parsing.
+
+`now`::
+	Always use the current time and time zone.  The literal
+	`now` must always be supplied for `<when>`.
++
+This is a toy format.  The current time and time zone of this system
+is always copied into the identity string at the time it is being
+created by fast-import.  There is no way to specify a different time or
+time zone.
++
+This particular format is supplied as it's short to implement and
+may be useful to a process that wants to create a new commit
+right now, without needing to use a working directory or
+'git update-index'.
++
+If separate `author` and `committer` commands are used in a `commit`
+the timestamps may not match, as the system clock will be polled
+twice (once for each command).  The only way to ensure that both
+author and committer identity information has the same timestamp
+is to omit `author` (thus copying from `committer`) or to use a
+date format other than `now`.
+
+Commands
+~~~~~~~~
+fast-import accepts several commands to update the current repository
+and control the current import process.  More detailed discussion
+(with examples) of each command follows later.
+
+`commit`::
+	Creates a new branch or updates an existing branch by
+	creating a new commit and updating the branch to point at
+	the newly created commit.
+
+`tag`::
+	Creates an annotated tag object from an existing commit or
+	branch.  Lightweight tags are not supported by this command,
+	as they are not recommended for recording meaningful points
+	in time.
+
+`reset`::
+	Reset an existing branch (or a new branch) to a specific
+	revision.  This command must be used to change a branch to
+	a specific revision without making a commit on it.
+
+`blob`::
+	Convert raw file data into a blob, for future use in a
+	`commit` command.  This command is optional and is not
+	needed to perform an import.
+
+`alias`::
+	Record that a mark refers to a given object without first
+	creating any new object.  Using --import-marks and referring
+	to missing marks will cause fast-import to fail, so aliases
+	can provide a way to set otherwise pruned commits to a valid
+	value (e.g. the nearest non-pruned ancestor).
+
+`checkpoint`::
+	Forces fast-import to close the current packfile, generate its
+	unique SHA-1 checksum and index, and start a new packfile.
+	This command is optional and is not needed to perform
+	an import.
+
+`progress`::
+	Causes fast-import to echo the entire line to its own
+	standard output.  This command is optional and is not needed
+	to perform an import.
+
+`done`::
+	Marks the end of the stream. This command is optional
+	unless the `done` feature was requested using the
+	`--done` command-line option or `feature done` command.
+
+`get-mark`::
+	Causes fast-import to print the SHA-1 corresponding to a mark
+	to the file descriptor set with `--cat-blob-fd`, or `stdout` if
+	unspecified.
+
+`cat-blob`::
+	Causes fast-import to print a blob in 'cat-file --batch'
+	format to the file descriptor set with `--cat-blob-fd` or
+	`stdout` if unspecified.
+
+`ls`::
+	Causes fast-import to print a line describing a directory
+	entry in 'ls-tree' format to the file descriptor set with
+	`--cat-blob-fd` or `stdout` if unspecified.
+
+`feature`::
+	Enable the specified feature. This requires that fast-import
+	supports the specified feature, and aborts if it does not.
+
+`option`::
+	Specify any of the options listed under OPTIONS that do not
+	change stream semantic to suit the frontend's needs. This
+	command is optional and is not needed to perform an import.
+
+`commit`
+~~~~~~~~
+Create or update a branch with a new commit, recording one logical
+change to the project.
+
+....
+	'commit' SP <ref> LF
+	mark?
+	original-oid?
+	('author' (SP <name>)? SP LT <email> GT SP <when> LF)?
+	'committer' (SP <name>)? SP LT <email> GT SP <when> LF
+	('encoding' SP <encoding>)?
+	data
+	('from' SP <commit-ish> LF)?
+	('merge' SP <commit-ish> LF)*
+	(filemodify | filedelete | filecopy | filerename | filedeleteall | notemodify)*
+	LF?
+....
+
+where `<ref>` is the name of the branch to make the commit on.
+Typically branch names are prefixed with `refs/heads/` in
+Git, so importing the CVS branch symbol `RELENG-1_0` would use
+`refs/heads/RELENG-1_0` for the value of `<ref>`.  The value of
+`<ref>` must be a valid refname in Git.  As `LF` is not valid in
+a Git refname, no quoting or escaping syntax is supported here.
+
+A `mark` command may optionally appear, requesting fast-import to save a
+reference to the newly created commit for future use by the frontend
+(see below for format).  It is very common for frontends to mark
+every commit they create, thereby allowing future branch creation
+from any imported commit.
+
+The `data` command following `committer` must supply the commit
+message (see below for `data` command syntax).  To import an empty
+commit message use a 0 length data.  Commit messages are free-form
+and are not interpreted by Git.  Currently they must be encoded in
+UTF-8, as fast-import does not permit other encodings to be specified.
+
+Zero or more `filemodify`, `filedelete`, `filecopy`, `filerename`,
+`filedeleteall` and `notemodify` commands
+may be included to update the contents of the branch prior to
+creating the commit.  These commands may be supplied in any order.
+However it is recommended that a `filedeleteall` command precede
+all `filemodify`, `filecopy`, `filerename` and `notemodify` commands in
+the same commit, as `filedeleteall` wipes the branch clean (see below).
+
+The `LF` after the command is optional (it used to be required).  Note
+that for reasons of backward compatibility, if the commit ends with a
+`data` command (i.e. it has no `from`, `merge`, `filemodify`,
+`filedelete`, `filecopy`, `filerename`, `filedeleteall` or
+`notemodify` commands) then two `LF` commands may appear at the end of
+the command instead of just one.
+
+`author`
+^^^^^^^^
+An `author` command may optionally appear, if the author information
+might differ from the committer information.  If `author` is omitted
+then fast-import will automatically use the committer's information for
+the author portion of the commit.  See below for a description of
+the fields in `author`, as they are identical to `committer`.
+
+`committer`
+^^^^^^^^^^^
+The `committer` command indicates who made this commit, and when
+they made it.
+
+Here `<name>` is the person's display name (for example
+``Com M Itter'') and `<email>` is the person's email address
+(``\cm@xxxxxxxxxxx'').  `LT` and `GT` are the literal less-than (\x3c)
+and greater-than (\x3e) symbols.  These are required to delimit
+the email address from the other fields in the line.  Note that
+`<name>` and `<email>` are free-form and may contain any sequence
+of bytes, except `LT`, `GT` and `LF`.  `<name>` is typically UTF-8 encoded.
+
+The time of the change is specified by `<when>` using the date format
+that was selected by the --date-format=<fmt> command-line option.
+See ``Date Formats'' above for the set of supported formats, and
+their syntax.
+
+`encoding`
+^^^^^^^^^^
+The optional `encoding` command indicates the encoding of the commit
+message.  Most commits are UTF-8 and the encoding is omitted, but this
+allows importing commit messages into git without first reencoding them.
+
+`from`
+^^^^^^
+The `from` command is used to specify the commit to initialize
+this branch from.  This revision will be the first ancestor of the
+new commit.  The state of the tree built at this commit will begin
+with the state at the `from` commit, and be altered by the content
+modifications in this commit.
+
+Omitting the `from` command in the first commit of a new branch
+will cause fast-import to create that commit with no ancestor. This
+tends to be desired only for the initial commit of a project.
+If the frontend creates all files from scratch when making a new
+branch, a `merge` command may be used instead of `from` to start
+the commit with an empty tree.
+Omitting the `from` command on existing branches is usually desired,
+as the current commit on that branch is automatically assumed to
+be the first ancestor of the new commit.
+
+As `LF` is not valid in a Git refname or SHA-1 expression, no
+quoting or escaping syntax is supported within `<commit-ish>`.
+
+Here `<commit-ish>` is any of the following:
+
+* The name of an existing branch already in fast-import's internal branch
+  table.  If fast-import doesn't know the name, it's treated as a SHA-1
+  expression.
+
+* A mark reference, `:<idnum>`, where `<idnum>` is the mark number.
++
+The reason fast-import uses `:` to denote a mark reference is this character
+is not legal in a Git branch name.  The leading `:` makes it easy
+to distinguish between the mark 42 (`:42`) and the branch 42 (`42`
+or `refs/heads/42`), or an abbreviated SHA-1 which happened to
+consist only of base-10 digits.
++
+Marks must be declared (via `mark`) before they can be used.
+
+* A complete 40 byte or abbreviated commit SHA-1 in hex.
+
+* Any valid Git SHA-1 expression that resolves to a commit.  See
+  ``SPECIFYING REVISIONS'' in linkgit:gitrevisions[7] for details.
+
+* The special null SHA-1 (40 zeros) specifies that the branch is to be
+  removed.
+
+The special case of restarting an incremental import from the
+current branch value should be written as:
+----
+	from refs/heads/branch^0
+----
+The `^0` suffix is necessary as fast-import does not permit a branch to
+start from itself, and the branch is created in memory before the
+`from` command is even read from the input.  Adding `^0` will force
+fast-import to resolve the commit through Git's revision parsing library,
+rather than its internal branch table, thereby loading in the
+existing value of the branch.
+
+`merge`
+^^^^^^^
+Includes one additional ancestor commit.  The additional ancestry
+link does not change the way the tree state is built at this commit.
+If the `from` command is
+omitted when creating a new branch, the first `merge` commit will be
+the first ancestor of the current commit, and the branch will start
+out with no files.  An unlimited number of `merge` commands per
+commit are permitted by fast-import, thereby establishing an n-way merge.
+
+Here `<commit-ish>` is any of the commit specification expressions
+also accepted by `from` (see above).
+
+`filemodify`
+^^^^^^^^^^^^
+Included in a `commit` command to add a new file or change the
+content of an existing file.  This command has two different means
+of specifying the content of the file.
+
+External data format::
+	The data content for the file was already supplied by a prior
+	`blob` command.  The frontend just needs to connect it.
++
+....
+	'M' SP <mode> SP <dataref> SP <path> LF
+....
++
+Here usually `<dataref>` must be either a mark reference (`:<idnum>`)
+set by a prior `blob` command, or a full 40-byte SHA-1 of an
+existing Git blob object.  If `<mode>` is `040000`` then
+`<dataref>` must be the full 40-byte SHA-1 of an existing
+Git tree object or a mark reference set with `--import-marks`.
+
+Inline data format::
+	The data content for the file has not been supplied yet.
+	The frontend wants to supply it as part of this modify
+	command.
++
+....
+	'M' SP <mode> SP 'inline' SP <path> LF
+	data
+....
++
+See below for a detailed description of the `data` command.
+
+In both formats `<mode>` is the type of file entry, specified
+in octal.  Git only supports the following modes:
+
+* `100644` or `644`: A normal (not-executable) file.  The majority
+  of files in most projects use this mode.  If in doubt, this is
+  what you want.
+* `100755` or `755`: A normal, but executable, file.
+* `120000`: A symlink, the content of the file will be the link target.
+* `160000`: A gitlink, SHA-1 of the object refers to a commit in
+  another repository. Git links can only be specified either by SHA or through
+  a commit mark. They are used to implement submodules.
+* `040000`: A subdirectory.  Subdirectories can only be specified by
+  SHA or through a tree mark set with `--import-marks`.
+
+In both formats `<path>` is the complete path of the file to be added
+(if not already existing) or modified (if already existing).
+
+A `<path>` can be written as unquoted bytes or a C-style quoted string.
+
+When a `<path>` does not start with a double quote (`"`), it is an
+unquoted string and is parsed as literal bytes without any escape
+sequences. However, if the filename contains `LF` or starts with double
+quote, it cannot be represented as an unquoted string and must be
+quoted. Additionally, the source `<path>` in `filecopy` or `filerename`
+must be quoted if it contains SP.
+
+When a `<path>` starts with a double quote (`"`), it is a C-style quoted
+string, where the complete filename is enclosed in a pair of double
+quotes and escape sequences are used. Certain characters must be escaped
+by preceding them with a backslash: `LF` is written as `\n`, backslash
+as `\\`, and double quote as `\"`. Some characters may optionally be
+written with escape sequences: `\a` for bell, `\b` for backspace, `\f`
+for form feed, `\n` for line feed, `\r` for carriage return, `\t` for
+horizontal tab, and `\v` for vertical tab. Any byte can be written with
+3-digit octal codes (e.g., `\033`). All filenames can be represented as
+quoted strings.
+
+A `<path>` must use UNIX-style directory separators (forward slash `/`)
+and its value must be in canonical form. That is it must not:
+
+* contain an empty directory component (e.g. `foo//bar` is invalid),
+* end with a directory separator (e.g. `foo/` is invalid),
+* start with a directory separator (e.g. `/foo` is invalid),
+* contain the special component `.` or `..` (e.g. `foo/./bar` and
+  `foo/../bar` are invalid).
+
+The root of the tree can be represented by an empty string as `<path>`.
+
+`<path>` cannot contain NUL, either literally or escaped as `\000`.
+It is recommended that `<path>` always be encoded using UTF-8.
+
+`filedelete`
+^^^^^^^^^^^^
+Included in a `commit` command to remove a file or recursively
+delete an entire directory from the branch.  If the file or directory
+removal makes its parent directory empty, the parent directory will
+be automatically removed too.  This cascades up the tree until the
+first non-empty directory or the root is reached.
+
+....
+	'D' SP <path> LF
+....
+
+here `<path>` is the complete path of the file or subdirectory to
+be removed from the branch.
+See `filemodify` above for a detailed description of `<path>`.
+
+`filecopy`
+^^^^^^^^^^
+Recursively copies an existing file or subdirectory to a different
+location within the branch.  The existing file or directory must
+exist.  If the destination exists it will be completely replaced
+by the content copied from the source.
+
+....
+	'C' SP <path> SP <path> LF
+....
+
+here the first `<path>` is the source location and the second
+`<path>` is the destination.  See `filemodify` above for a detailed
+description of what `<path>` may look like.  To use a source path
+that contains SP the path must be quoted.
+
+A `filecopy` command takes effect immediately.  Once the source
+location has been copied to the destination any future commands
+applied to the source location will not impact the destination of
+the copy.
+
+`filerename`
+^^^^^^^^^^^^
+Renames an existing file or subdirectory to a different location
+within the branch.  The existing file or directory must exist. If
+the destination exists it will be replaced by the source directory.
+
+....
+	'R' SP <path> SP <path> LF
+....
+
+here the first `<path>` is the source location and the second
+`<path>` is the destination.  See `filemodify` above for a detailed
+description of what `<path>` may look like.  To use a source path
+that contains SP the path must be quoted.
+
+A `filerename` command takes effect immediately.  Once the source
+location has been renamed to the destination any future commands
+applied to the source location will create new files there and not
+impact the destination of the rename.
+
+Note that a `filerename` is the same as a `filecopy` followed by a
+`filedelete` of the source location.  There is a slight performance
+advantage to using `filerename`, but the advantage is so small
+that it is never worth trying to convert a delete/add pair in
+source material into a rename for fast-import.  This `filerename`
+command is provided just to simplify frontends that already have
+rename information and don't want bother with decomposing it into a
+`filecopy` followed by a `filedelete`.
+
+`filedeleteall`
+^^^^^^^^^^^^^^^
+Included in a `commit` command to remove all files (and also all
+directories) from the branch.  This command resets the internal
+branch structure to have no files in it, allowing the frontend
+to subsequently add all interesting files from scratch.
+
+....
+	'deleteall' LF
+....
+
+This command is extremely useful if the frontend does not know
+(or does not care to know) what files are currently on the branch,
+and therefore cannot generate the proper `filedelete` commands to
+update the content.
+
+Issuing a `filedeleteall` followed by the needed `filemodify`
+commands to set the correct content will produce the same results
+as sending only the needed `filemodify` and `filedelete` commands.
+The `filedeleteall` approach may however require fast-import to use slightly
+more memory per active branch (less than 1 MiB for even most large
+projects); so frontends that can easily obtain only the affected
+paths for a commit are encouraged to do so.
+
+`notemodify`
+^^^^^^^^^^^^
+Included in a `commit` `<notes-ref>` command to add a new note
+annotating a `<commit-ish>` or change this annotation contents.
+Internally it is similar to filemodify 100644 on `<commit-ish>`
+path (maybe split into subdirectories). It's not advised to
+use any other commands to write to the `<notes-ref>` tree except
+`filedeleteall` to delete all existing notes in this tree.
+This command has two different means of specifying the content
+of the note.
+
+External data format::
+	The data content for the note was already supplied by a prior
+	`blob` command.  The frontend just needs to connect it to the
+	commit that is to be annotated.
++
+....
+	'N' SP <dataref> SP <commit-ish> LF
+....
++
+Here `<dataref>` can be either a mark reference (`:<idnum>`)
+set by a prior `blob` command, or a full 40-byte SHA-1 of an
+existing Git blob object.
+
+Inline data format::
+	The data content for the note has not been supplied yet.
+	The frontend wants to supply it as part of this modify
+	command.
++
+....
+	'N' SP 'inline' SP <commit-ish> LF
+	data
+....
++
+See below for a detailed description of the `data` command.
+
+In both formats `<commit-ish>` is any of the commit specification
+expressions also accepted by `from` (see above).
+
+`mark`
+~~~~~~
+Arranges for fast-import to save a reference to the current object, allowing
+the frontend to recall this object at a future point in time, without
+knowing its SHA-1.  Here the current object is the object creation
+command the `mark` command appears within.  This can be `commit`,
+`tag`, and `blob`, but `commit` is the most common usage.
+
+....
+	'mark' SP ':' <idnum> LF
+....
+
+where `<idnum>` is the number assigned by the frontend to this mark.
+The value of `<idnum>` is expressed as an ASCII decimal integer.
+The value 0 is reserved and cannot be used as
+a mark.  Only values greater than or equal to 1 may be used as marks.
+
+New marks are created automatically.  Existing marks can be moved
+to another object simply by reusing the same `<idnum>` in another
+`mark` command.
+
+`original-oid`
+~~~~~~~~~~~~~~
+Provides the name of the object in the original source control system.
+fast-import will simply ignore this directive, but filter processes
+which operate on and modify the stream before feeding to fast-import
+may have uses for this information
+
+....
+	'original-oid' SP <object-identifier> LF
+....
+
+where `<object-identifier>` is any string not containing LF.
+
+`tag`
+~~~~~
+Creates an annotated tag referring to a specific commit.  To create
+lightweight (non-annotated) tags see the `reset` command below.
+
+....
+	'tag' SP <name> LF
+	mark?
+	'from' SP <commit-ish> LF
+	original-oid?
+	'tagger' (SP <name>)? SP LT <email> GT SP <when> LF
+	data
+....
+
+where `<name>` is the name of the tag to create.
+
+Tag names are automatically prefixed with `refs/tags/` when stored
+in Git, so importing the CVS branch symbol `RELENG-1_0-FINAL` would
+use just `RELENG-1_0-FINAL` for `<name>`, and fast-import will write the
+corresponding ref as `refs/tags/RELENG-1_0-FINAL`.
+
+The value of `<name>` must be a valid refname in Git and therefore
+may contain forward slashes.  As `LF` is not valid in a Git refname,
+no quoting or escaping syntax is supported here.
+
+The `from` command is the same as in the `commit` command; see
+above for details.
+
+The `tagger` command uses the same format as `committer` within
+`commit`; again see above for details.
+
+The `data` command following `tagger` must supply the annotated tag
+message (see below for `data` command syntax).  To import an empty
+tag message use a 0 length data.  Tag messages are free-form and are
+not interpreted by Git.  Currently they must be encoded in UTF-8,
+as fast-import does not permit other encodings to be specified.
+
+Signing annotated tags during import from within fast-import is not
+supported.  Trying to include your own PGP/GPG signature is not
+recommended, as the frontend does not (easily) have access to the
+complete set of bytes which normally goes into such a signature.
+If signing is required, create lightweight tags from within fast-import with
+`reset`, then create the annotated versions of those tags offline
+with the standard 'git tag' process.
+
+`reset`
+~~~~~~~
+Creates (or recreates) the named branch, optionally starting from
+a specific revision.  The reset command allows a frontend to issue
+a new `from` command for an existing branch, or to create a new
+branch from an existing commit without creating a new commit.
+
+....
+	'reset' SP <ref> LF
+	('from' SP <commit-ish> LF)?
+	LF?
+....
+
+For a detailed description of `<ref>` and `<commit-ish>` see above
+under `commit` and `from`.
+
+The `LF` after the command is optional (it used to be required).
+
+The `reset` command can also be used to create lightweight
+(non-annotated) tags.  For example:
+
+====
+	reset refs/tags/938
+	from :938
+====
+
+would create the lightweight tag `refs/tags/938` referring to
+whatever commit mark `:938` references.
+
+`blob`
+~~~~~~
+Requests writing one file revision to the packfile.  The revision
+is not connected to any commit; this connection must be formed in
+a subsequent `commit` command by referencing the blob through an
+assigned mark.
+
+....
+	'blob' LF
+	mark?
+	original-oid?
+	data
+....
+
+The mark command is optional here as some frontends have chosen
+to generate the Git SHA-1 for the blob on their own, and feed that
+directly to `commit`.  This is typically more work than it's worth
+however, as marks are inexpensive to store and easy to use.
+
+`data`
+~~~~~~
+Supplies raw data (for use as blob/file content, commit messages, or
+annotated tag messages) to fast-import.  Data can be supplied using an exact
+byte count or delimited with a terminating line.  Real frontends
+intended for production-quality conversions should always use the
+exact byte count format, as it is more robust and performs better.
+The delimited format is intended primarily for testing fast-import.
+
+Comment lines appearing within the `<raw>` part of `data` commands
+are always taken to be part of the body of the data and are therefore
+never ignored by fast-import.  This makes it safe to import any
+file/message content whose lines might start with `#`.
+
+Exact byte count format::
+	The frontend must specify the number of bytes of data.
++
+....
+	'data' SP <count> LF
+	<raw> LF?
+....
++
+where `<count>` is the exact number of bytes appearing within
+`<raw>`.  The value of `<count>` is expressed as an ASCII decimal
+integer.  The `LF` on either side of `<raw>` is not
+included in `<count>` and will not be included in the imported data.
++
+The `LF` after `<raw>` is optional (it used to be required) but
+recommended.  Always including it makes debugging a fast-import
+stream easier as the next command always starts in column 0
+of the next line, even if `<raw>` did not end with an `LF`.
+
+Delimited format::
+	A delimiter string is used to mark the end of the data.
+	fast-import will compute the length by searching for the delimiter.
+	This format is primarily useful for testing and is not
+	recommended for real data.
++
+....
+	'data' SP '<<' <delim> LF
+	<raw> LF
+	<delim> LF
+	LF?
+....
++
+where `<delim>` is the chosen delimiter string.  The string `<delim>`
+must not appear on a line by itself within `<raw>`, as otherwise
+fast-import will think the data ends earlier than it really does.  The `LF`
+immediately trailing `<raw>` is part of `<raw>`.  This is one of
+the limitations of the delimited format, it is impossible to supply
+a data chunk which does not have an LF as its last byte.
++
+The `LF` after `<delim> LF` is optional (it used to be required).
+
+`alias`
+~~~~~~~
+Record that a mark refers to a given object without first creating any
+new object.
+
+....
+	'alias' LF
+	mark
+	'to' SP <commit-ish> LF
+	LF?
+....
+
+For a detailed description of `<commit-ish>` see above under `from`.
+
+
+`checkpoint`
+~~~~~~~~~~~~
+Forces fast-import to close the current packfile, start a new one, and to
+save out all current branch refs, tags and marks.
+
+....
+	'checkpoint' LF
+	LF?
+....
+
+Note that fast-import automatically switches packfiles when the current
+packfile reaches --max-pack-size, or 4 GiB, whichever limit is
+smaller.  During an automatic packfile switch fast-import does not update
+the branch refs, tags or marks.
+
+As a `checkpoint` can require a significant amount of CPU time and
+disk IO (to compute the overall pack SHA-1 checksum, generate the
+corresponding index file, and update the refs) it can easily take
+several minutes for a single `checkpoint` command to complete.
+
+Frontends may choose to issue checkpoints during extremely large
+and long running imports, or when they need to allow another Git
+process access to a branch.  However given that a 30 GiB Subversion
+repository can be loaded into Git through fast-import in about 3 hours,
+explicit checkpointing may not be necessary.
+
+The `LF` after the command is optional (it used to be required).
+
+`progress`
+~~~~~~~~~~
+Causes fast-import to print the entire `progress` line unmodified to
+its standard output channel (file descriptor 1) when the command is
+processed from the input stream.  The command otherwise has no impact
+on the current import, or on any of fast-import's internal state.
+
+....
+	'progress' SP <any> LF
+	LF?
+....
+
+The `<any>` part of the command may contain any sequence of bytes
+that does not contain `LF`.  The `LF` after the command is optional.
+Callers may wish to process the output through a tool such as sed to
+remove the leading part of the line, for example:
+
+====
+	frontend | git fast-import | sed 's/^progress //'
+====
+
+Placing a `progress` command immediately after a `checkpoint` will
+inform the reader when the `checkpoint` has been completed and it
+can safely access the refs that fast-import updated.
+
+`get-mark`
+~~~~~~~~~~
+Causes fast-import to print the SHA-1 corresponding to a mark to
+stdout or to the file descriptor previously arranged with the
+`--cat-blob-fd` argument. The command otherwise has no impact on the
+current import; its purpose is to retrieve SHA-1s that later commits
+might want to refer to in their commit messages.
+
+....
+	'get-mark' SP ':' <idnum> LF
+....
+
+See ``Responses To Commands'' below for details about how to read
+this output safely.
+
+`cat-blob`
+~~~~~~~~~~
+Causes fast-import to print a blob to a file descriptor previously
+arranged with the `--cat-blob-fd` argument.  The command otherwise
+has no impact on the current import; its main purpose is to
+retrieve blobs that may be in fast-import's memory but not
+accessible from the target repository.
+
+....
+	'cat-blob' SP <dataref> LF
+....
+
+The `<dataref>` can be either a mark reference (`:<idnum>`)
+set previously or a full 40-byte SHA-1 of a Git blob, preexisting or
+ready to be written.
+
+Output uses the same format as `git cat-file --batch`:
+
+====
+	<sha1> SP 'blob' SP <size> LF
+	<contents> LF
+====
+
+This command can be used where a `filemodify` directive can appear,
+allowing it to be used in the middle of a commit.  For a `filemodify`
+using an inline directive, it can also appear right before the `data`
+directive.
+
+See ``Responses To Commands'' below for details about how to read
+this output safely.
+
+`ls`
+~~~~
+Prints information about the object at a path to a file descriptor
+previously arranged with the `--cat-blob-fd` argument.  This allows
+printing a blob from the active commit (with `cat-blob`) or copying a
+blob or tree from a previous commit for use in the current one (with
+`filemodify`).
+
+The `ls` command can also be used where a `filemodify` directive can
+appear, allowing it to be used in the middle of a commit.
+
+Reading from the active commit::
+	This form can only be used in the middle of a `commit`.
+	The path names a directory entry within fast-import's
+	active commit.  The path must be quoted in this case.
++
+....
+	'ls' SP <path> LF
+....
+
+Reading from a named tree::
+	The `<dataref>` can be a mark reference (`:<idnum>`) or the
+	full 40-byte SHA-1 of a Git tag, commit, or tree object,
+	preexisting or waiting to be written.
+	The path is relative to the top level of the tree
+	named by `<dataref>`.
++
+....
+	'ls' SP <dataref> SP <path> LF
+....
+
+See `filemodify` above for a detailed description of `<path>`.
+
+Output uses the same format as `git ls-tree <tree> -- <path>`:
+
+====
+	<mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF
+====
+
+The <dataref> represents the blob, tree, or commit object at <path>
+and can be used in later 'get-mark', 'cat-blob', 'filemodify', or
+'ls' commands.
+
+If there is no file or subtree at that path, 'git fast-import' will
+instead report
+
+====
+	missing SP <path> LF
+====
+
+See ``Responses To Commands'' below for details about how to read
+this output safely.
+
+`feature`
+~~~~~~~~~
+Require that fast-import supports the specified feature, or abort if
+it does not.
+
+....
+	'feature' SP <feature> ('=' <argument>)? LF
+....
+
+The <feature> part of the command may be any one of the following:
+
+date-format::
+export-marks::
+relative-marks::
+no-relative-marks::
+force::
+	Act as though the corresponding command-line option with
+	a leading `--` was passed on the command line
+	(see OPTIONS, above).
+
+import-marks::
+import-marks-if-exists::
+	Like --import-marks except in two respects: first, only one
+	"feature import-marks" or "feature import-marks-if-exists"
+	command is allowed per stream; second, an --import-marks=
+	or --import-marks-if-exists command-line option overrides
+	any of these "feature" commands in the stream; third,
+	"feature import-marks-if-exists" like a corresponding
+	command-line option silently skips a nonexistent file.
+
+get-mark::
+cat-blob::
+ls::
+	Require that the backend support the 'get-mark', 'cat-blob',
+	or 'ls' command respectively.
+	Versions of fast-import not supporting the specified command
+	will exit with a message indicating so.
+	This lets the import error out early with a clear message,
+	rather than wasting time on the early part of an import
+	before the unsupported command is detected.
+
+notes::
+	Require that the backend support the 'notemodify' (N)
+	subcommand to the 'commit' command.
+	Versions of fast-import not supporting notes will exit
+	with a message indicating so.
+
+done::
+	Error out if the stream ends without a 'done' command.
+	Without this feature, errors causing the frontend to end
+	abruptly at a convenient point in the stream can go
+	undetected.  This may occur, for example, if an import
+	front end dies in mid-operation without emitting SIGTERM
+	or SIGKILL at its subordinate git fast-import instance.
+
+`option`
+~~~~~~~~
+Processes the specified option so that git fast-import behaves in a
+way that suits the frontend's needs.
+Note that options specified by the frontend are overridden by any
+options the user may specify to git fast-import itself.
+
+....
+    'option' SP <option> LF
+....
+
+The `<option>` part of the command may contain any of the options
+listed in the OPTIONS section that do not change import semantics,
+without the leading `--` and is treated in the same way.
+
+Option commands must be the first commands on the input (not counting
+feature commands), to give an option command after any non-option
+command is an error.
+
+The following command-line options change import semantics and may therefore
+not be passed as option:
+
+* date-format
+* import-marks
+* export-marks
+* cat-blob-fd
+* force
+
+`done`
+~~~~~~
+If the `done` feature is not in use, treated as if EOF was read.
+This can be used to tell fast-import to finish early.
+
+If the `--done` command-line option or `feature done` command is
+in use, the `done` command is mandatory and marks the end of the
+stream.
+
+RESPONSES TO COMMANDS
+---------------------
+New objects written by fast-import are not available immediately.
+Most fast-import commands have no visible effect until the next
+checkpoint (or completion).  The frontend can send commands to
+fill fast-import's input pipe without worrying about how quickly
+they will take effect, which improves performance by simplifying
+scheduling.
+
+For some frontends, though, it is useful to be able to read back
+data from the current repository as it is being updated (for
+example when the source material describes objects in terms of
+patches to be applied to previously imported objects).  This can
+be accomplished by connecting the frontend and fast-import via
+bidirectional pipes:
+
+====
+	mkfifo fast-import-output
+	frontend <fast-import-output |
+	git fast-import >fast-import-output
+====
+
+A frontend set up this way can use `progress`, `get-mark`, `ls`, and
+`cat-blob` commands to read information from the import in progress.
+
+To avoid deadlock, such frontends must completely consume any
+pending output from `progress`, `ls`, `get-mark`, and `cat-blob` before
+performing writes to fast-import that might block.
+
+CRASH REPORTS
+-------------
+If fast-import is supplied invalid input it will terminate with a
+non-zero exit status and create a crash report in the top level of
+the Git repository it was importing into.  Crash reports contain
+a snapshot of the internal fast-import state as well as the most
+recent commands that lead up to the crash.
+
+All recent commands (including stream comments, file changes and
+progress commands) are shown in the command history within the crash
+report, but raw file data and commit messages are excluded from the
+crash report.  This exclusion saves space within the report file
+and reduces the amount of buffering that fast-import must perform
+during execution.
+
+After writing a crash report fast-import will close the current
+packfile and export the marks table.  This allows the frontend
+developer to inspect the repository state and resume the import from
+the point where it crashed.  The modified branches and tags are not
+updated during a crash, as the import did not complete successfully.
+Branch and tag information can be found in the crash report and
+must be applied manually if the update is needed.
+
+An example crash:
+
+====
+	$ cat >in <<END_OF_INPUT
+	# my very first test commit
+	commit refs/heads/master
+	committer Shawn O. Pearce <spearce> 19283 -0400
+	# who is that guy anyway?
+	data <<EOF
+	this is my commit
+	EOF
+	M 644 inline .gitignore
+	data <<EOF
+	.gitignore
+	EOF
+	M 777 inline bob
+	END_OF_INPUT
+
+	$ git fast-import <in
+	fatal: Corrupt mode: M 777 inline bob
+	fast-import: dumping crash report to .git/fast_import_crash_8434
+
+	$ cat .git/fast_import_crash_8434
+	fast-import crash report:
+	    fast-import process: 8434
+	    parent process     : 1391
+	    at Sat Sep 1 00:58:12 2007
+
+	fatal: Corrupt mode: M 777 inline bob
+
+	Most Recent Commands Before Crash
+	---------------------------------
+	  # my very first test commit
+	  commit refs/heads/master
+	  committer Shawn O. Pearce <spearce> 19283 -0400
+	  # who is that guy anyway?
+	  data <<EOF
+	  M 644 inline .gitignore
+	  data <<EOF
+	* M 777 inline bob
+
+	Active Branch LRU
+	-----------------
+	    active_branches = 1 cur, 5 max
+
+	  pos  clock name
+	  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	   1)      0 refs/heads/master
+
+	Inactive Branches
+	-----------------
+	refs/heads/master:
+	  status      : active loaded dirty
+	  tip commit  : 0000000000000000000000000000000000000000
+	  old tree    : 0000000000000000000000000000000000000000
+	  cur tree    : 0000000000000000000000000000000000000000
+	  commit clock: 0
+	  last pack   :
+
+
+	-------------------
+	END OF CRASH REPORT
+====
+
+TIPS AND TRICKS
+---------------
+The following tips and tricks have been collected from various
+users of fast-import, and are offered here as suggestions.
+
+Use One Mark Per Commit
+~~~~~~~~~~~~~~~~~~~~~~~
+When doing a repository conversion, use a unique mark per commit
+(`mark :<n>`) and supply the --export-marks option on the command
+line.  fast-import will dump a file which lists every mark and the Git
+object SHA-1 that corresponds to it.  If the frontend can tie
+the marks back to the source repository, it is easy to verify the
+accuracy and completeness of the import by comparing each Git
+commit to the corresponding source revision.
+
+Coming from a system such as Perforce or Subversion, this should be
+quite simple, as the fast-import mark can also be the Perforce changeset
+number or the Subversion revision number.
+
+Freely Skip Around Branches
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Don't bother trying to optimize the frontend to stick to one branch
+at a time during an import.  Although doing so might be slightly
+faster for fast-import, it tends to increase the complexity of the frontend
+code considerably.
+
+The branch LRU builtin to fast-import tends to behave very well, and the
+cost of activating an inactive branch is so low that bouncing around
+between branches has virtually no impact on import performance.
+
+Handling Renames
+~~~~~~~~~~~~~~~~
+When importing a renamed file or directory, simply delete the old
+name(s) and modify the new name(s) during the corresponding commit.
+Git performs rename detection after-the-fact, rather than explicitly
+during a commit.
+
+Use Tag Fixup Branches
+~~~~~~~~~~~~~~~~~~~~~~
+Some other SCM systems let the user create a tag from multiple
+files which are not from the same commit/changeset.  Or to create
+tags which are a subset of the files available in the repository.
+
+Importing these tags as-is in Git is impossible without making at
+least one commit which ``fixes up'' the files to match the content
+of the tag.  Use fast-import's `reset` command to reset a dummy branch
+outside of your normal branch space to the base commit for the tag,
+then commit one or more file fixup commits, and finally tag the
+dummy branch.
+
+For example since all normal branches are stored under `refs/heads/`
+name the tag fixup branch `TAG_FIXUP`.  This way it is impossible for
+the fixup branch used by the importer to have namespace conflicts
+with real branches imported from the source (the name `TAG_FIXUP`
+is not `refs/heads/TAG_FIXUP`).
+
+When committing fixups, consider using `merge` to connect the
+commit(s) which are supplying file revisions to the fixup branch.
+Doing so will allow tools such as 'git blame' to track
+through the real commit history and properly annotate the source
+files.
+
+After fast-import terminates the frontend will need to do `rm .git/TAG_FIXUP`
+to remove the dummy branch.
+
+Import Now, Repack Later
+~~~~~~~~~~~~~~~~~~~~~~~~
+As soon as fast-import completes the Git repository is completely valid
+and ready for use.  Typically this takes only a very short time,
+even for considerably large projects (100,000+ commits).
+
+However repacking the repository is necessary to improve data
+locality and access performance.  It can also take hours on extremely
+large projects (especially if -f and a large --window parameter is
+used).  Since repacking is safe to run alongside readers and writers,
+run the repack in the background and let it finish when it finishes.
+There is no reason to wait to explore your new Git project!
+
+If you choose to wait for the repack, don't try to run benchmarks
+or performance tests until repacking is completed.  fast-import outputs
+suboptimal packfiles that are simply never seen in real use
+situations.
+
+Repacking Historical Data
+~~~~~~~~~~~~~~~~~~~~~~~~~
+If you are repacking very old imported data (e.g. older than the
+last year), consider expending some extra CPU time and supplying
+--window=50 (or higher) when you run 'git repack'.
+This will take longer, but will also produce a smaller packfile.
+You only need to expend the effort once, and everyone using your
+project will benefit from the smaller repository.
+
+Include Some Progress Messages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Every once in a while have your frontend emit a `progress` message
+to fast-import.  The contents of the messages are entirely free-form,
+so one suggestion would be to output the current month and year
+each time the current commit date moves into the next month.
+Your users will feel better knowing how much of the data stream
+has been processed.
+
+
+PACKFILE OPTIMIZATION
+---------------------
+When packing a blob fast-import always attempts to deltify against the last
+blob written.  Unless specifically arranged for by the frontend,
+this will probably not be a prior version of the same file, so the
+generated delta will not be the smallest possible.  The resulting
+packfile will be compressed, but will not be optimal.
+
+Frontends which have efficient access to all revisions of a
+single file (for example reading an RCS/CVS ,v file) can choose
+to supply all revisions of that file as a sequence of consecutive
+`blob` commands.  This allows fast-import to deltify the different file
+revisions against each other, saving space in the final packfile.
+Marks can be used to later identify individual file revisions during
+a sequence of `commit` commands.
+
+The packfile(s) created by fast-import do not encourage good disk access
+patterns.  This is caused by fast-import writing the data in the order
+it is received on standard input, while Git typically organizes
+data within packfiles to make the most recent (current tip) data
+appear before historical data.  Git also clusters commits together,
+speeding up revision traversal through better cache locality.
+
+For this reason it is strongly recommended that users repack the
+repository with `git repack -a -d` after fast-import completes, allowing
+Git to reorganize the packfiles for faster data access.  If blob
+deltas are suboptimal (see above) then also adding the `-f` option
+to force recomputation of all deltas can significantly reduce the
+final packfile size (30-50% smaller can be quite typical).
+
+Instead of running `git repack` you can also run `git gc
+--aggressive`, which will also optimize other things after an import
+(e.g. pack loose refs). As noted in the "AGGRESSIVE" section in
+linkgit:git-gc[1] the `--aggressive` option will find new deltas with
+the `-f` option to linkgit:git-repack[1]. For the reasons elaborated
+on above using `--aggressive` after a fast-import is one of the few
+cases where it's known to be worthwhile.
+
+MEMORY UTILIZATION
+------------------
+There are a number of factors which affect how much memory fast-import
+requires to perform an import.  Like critical sections of core
+Git, fast-import uses its own memory allocators to amortize any overheads
+associated with malloc.  In practice fast-import tends to amortize any
+malloc overheads to 0, due to its use of large block allocations.
+
+per object
+~~~~~~~~~~
+fast-import maintains an in-memory structure for every object written in
+this execution.  On a 32 bit system the structure is 32 bytes,
+on a 64 bit system the structure is 40 bytes (due to the larger
+pointer sizes).  Objects in the table are not deallocated until
+fast-import terminates.  Importing 2 million objects on a 32 bit system
+will require approximately 64 MiB of memory.
+
+The object table is actually a hashtable keyed on the object name
+(the unique SHA-1).  This storage configuration allows fast-import to reuse
+an existing or already written object and avoid writing duplicates
+to the output packfile.  Duplicate blobs are surprisingly common
+in an import, typically due to branch merges in the source.
+
+per mark
+~~~~~~~~
+Marks are stored in a sparse array, using 1 pointer (4 bytes or 8
+bytes, depending on pointer size) per mark.  Although the array
+is sparse, frontends are still strongly encouraged to use marks
+between 1 and n, where n is the total number of marks required for
+this import.
+
+per branch
+~~~~~~~~~~
+Branches are classified as active and inactive.  The memory usage
+of the two classes is significantly different.
+
+Inactive branches are stored in a structure which uses 96 or 120
+bytes (32 bit or 64 bit systems, respectively), plus the length of
+the branch name (typically under 200 bytes), per branch.  fast-import will
+easily handle as many as 10,000 inactive branches in under 2 MiB
+of memory.
+
+Active branches have the same overhead as inactive branches, but
+also contain copies of every tree that has been recently modified on
+that branch.  If subtree `include` has not been modified since the
+branch became active, its contents will not be loaded into memory,
+but if subtree `src` has been modified by a commit since the branch
+became active, then its contents will be loaded in memory.
+
+As active branches store metadata about the files contained on that
+branch, their in-memory storage size can grow to a considerable size
+(see below).
+
+fast-import automatically moves active branches to inactive status based on
+a simple least-recently-used algorithm.  The LRU chain is updated on
+each `commit` command.  The maximum number of active branches can be
+increased or decreased on the command line with --active-branches=.
+
+per active tree
+~~~~~~~~~~~~~~~
+Trees (aka directories) use just 12 bytes of memory on top of the
+memory required for their entries (see ``per active file'' below).
+The cost of a tree is virtually 0, as its overhead amortizes out
+over the individual file entries.
+
+per active file entry
+~~~~~~~~~~~~~~~~~~~~~
+Files (and pointers to subtrees) within active trees require 52 or 64
+bytes (32/64 bit platforms) per entry.  To conserve space, file and
+tree names are pooled in a common string table, allowing the filename
+``Makefile'' to use just 16 bytes (after including the string header
+overhead) no matter how many times it occurs within the project.
+
+The active branch LRU, when coupled with the filename string pool
+and lazy loading of subtrees, allows fast-import to efficiently import
+projects with 2,000+ branches and 45,114+ files in a very limited
+memory footprint (less than 2.7 MiB per active branch).
+
+SIGNALS
+-------
+Sending *SIGUSR1* to the 'git fast-import' process ends the current
+packfile early, simulating a `checkpoint` command.  The impatient
+operator can use this facility to peek at the objects and refs from an
+import in progress, at the cost of some added running time and worse
+compression.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fastimport.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-fast-export[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fetch-pack.adoc b/Documentation/git-fetch-pack.adoc
new file mode 100644
index 0000000000..b5223576a7
--- /dev/null
+++ b/Documentation/git-fetch-pack.adoc
@@ -0,0 +1,136 @@
+git-fetch-pack(1)
+=================
+
+NAME
+----
+git-fetch-pack - Receive missing objects from another repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git fetch-pack' [--all] [--quiet|-q] [--keep|-k] [--thin] [--include-tag]
+	[--upload-pack=<git-upload-pack>]
+	[--depth=<n>] [--no-progress]
+	[-v] <repository> [<refs>...]
+
+DESCRIPTION
+-----------
+Usually you would want to use 'git fetch', which is a
+higher level wrapper of this command, instead.
+
+Invokes 'git-upload-pack' on a possibly remote repository
+and asks it to send objects missing from this repository, to
+update the named heads.  The list of commits available locally
+is found out by scanning the local refs/ hierarchy and sent to
+'git-upload-pack' running on the other end.
+
+This command degenerates to download everything to complete the
+asked refs from the remote side when the local side does not
+have a common ancestor commit.
+
+
+OPTIONS
+-------
+--all::
+	Fetch all remote refs.
+
+--stdin::
+	Take the list of refs from stdin, one per line. If there
+	are refs specified on the command line in addition to this
+	option, then the refs from stdin are processed after those
+	on the command line.
++
+If `--stateless-rpc` is specified together with this option then
+the list of refs must be in packet format (pkt-line). Each ref must
+be in a separate packet, and the list must end with a flush packet.
+
+-q::
+--quiet::
+	Pass `-q` flag to 'git unpack-objects'; this makes the
+	cloning process less verbose.
+
+-k::
+--keep::
+	Do not invoke 'git unpack-objects' on received data, but
+	create a single packfile out of it instead, and store it
+	in the object database. If provided twice then the pack is
+	locked against repacking.
+
+--thin::
+	Fetch a "thin" pack, which records objects in deltified form based
+	on objects not included in the pack to reduce network traffic.
+
+--include-tag::
+	If the remote side supports it, annotated tags objects will
+	be downloaded on the same connection as the other objects if
+	the object the tag references is downloaded.  The caller must
+	otherwise determine the tags this option made available.
+
+--upload-pack=<git-upload-pack>::
+	Use this to specify the path to 'git-upload-pack' on the
+	remote side, if it is not found on your $PATH.
+	Installations of sshd ignores the user's environment
+	setup scripts for login shells (e.g. .bash_profile) and
+	your privately installed git may not be found on the system
+	default $PATH.  Another workaround suggested is to set
+	up your $PATH in ".bashrc", but this flag is for people
+	who do not want to pay the overhead for non-interactive
+	shells by having a lean .bashrc file (they set most of
+	the things up in .bash_profile).
+
+--exec=<git-upload-pack>::
+	Same as --upload-pack=<git-upload-pack>.
+
+--depth=<n>::
+	Limit fetching to ancestor-chains not longer than n.
+	'git-upload-pack' treats the special depth 2147483647 as
+	infinite even if there is an ancestor-chain that long.
+
+--shallow-since=<date>::
+	Deepen or shorten the history of a shallow repository to
+	include all reachable commits after <date>.
+
+--shallow-exclude=<ref>::
+	Deepen or shorten the history of a shallow repository to
+	exclude commits reachable from a specified remote branch or tag.
+	This option can be specified multiple times.
+
+--deepen-relative::
+	Argument --depth specifies the number of commits from the
+	current shallow boundary instead of from the tip of each
+	remote branch history.
+
+--refetch::
+	Skips negotiating commits with the server in order to fetch all matching
+	objects. Use to reapply a new partial clone blob/tree filter.
+
+--no-progress::
+	Do not show the progress.
+
+--check-self-contained-and-connected::
+	Output "connectivity-ok" if the received pack is
+	self-contained and connected.
+
+-v::
+	Run verbosely.
+
+<repository>::
+	The URL to the remote repository.
+
+<refs>...::
+	The remote heads to update from. This is relative to
+	$GIT_DIR (e.g. "HEAD", "refs/heads/master").  When
+	unspecified, update from all heads the remote side has.
++
+If the remote has enabled the options `uploadpack.allowTipSHA1InWant`,
+`uploadpack.allowReachableSHA1InWant`, or `uploadpack.allowAnySHA1InWant`,
+they may alternatively be 40-hex sha1s present on the remote.
+
+SEE ALSO
+--------
+linkgit:git-fetch[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fetch.adoc b/Documentation/git-fetch.adoc
new file mode 100644
index 0000000000..2e618df960
--- /dev/null
+++ b/Documentation/git-fetch.adoc
@@ -0,0 +1,317 @@
+git-fetch(1)
+============
+
+NAME
+----
+git-fetch - Download objects and refs from another repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git fetch' [<options>] [<repository> [<refspec>...]]
+'git fetch' [<options>] <group>
+'git fetch' --multiple [<options>] [(<repository> | <group>)...]
+'git fetch' --all [<options>]
+
+
+DESCRIPTION
+-----------
+Fetch branches and/or tags (collectively, "refs") from one or more
+other repositories, along with the objects necessary to complete their
+histories.  Remote-tracking branches are updated (see the description
+of <refspec> below for ways to control this behavior).
+
+By default, any tag that points into the histories being fetched is
+also fetched; the effect is to fetch tags that
+point at branches that you are interested in.  This default behavior
+can be changed by using the --tags or --no-tags options or by
+configuring remote.<name>.tagOpt.  By using a refspec that fetches tags
+explicitly, you can fetch tags that do not point into branches you
+are interested in as well.
+
+'git fetch' can fetch from either a single named repository or URL,
+or from several repositories at once if <group> is given and
+there is a remotes.<group> entry in the configuration file.
+(See linkgit:git-config[1]).
+
+When no remote is specified, by default the `origin` remote will be used,
+unless there's an upstream branch configured for the current branch.
+
+The names of refs that are fetched, together with the object names
+they point at, are written to `.git/FETCH_HEAD`.  This information
+may be used by scripts or other git commands, such as linkgit:git-pull[1].
+
+OPTIONS
+-------
+include::fetch-options.adoc[]
+
+include::pull-fetch-param.adoc[]
+
+--stdin::
+	Read refspecs, one per line, from stdin in addition to those provided
+	as arguments. The "tag <name>" format is not supported.
+
+include::urls-remotes.adoc[]
+
+
+CONFIGURED REMOTE-TRACKING BRANCHES[[CRTB]]
+-------------------------------------------
+
+You often interact with the same remote repository by
+regularly and repeatedly fetching from it.  In order to keep track
+of the progress of such a remote repository, `git fetch` allows you
+to configure `remote.<repository>.fetch` configuration variables.
+
+Typically such a variable may look like this:
+
+------------------------------------------------
+[remote "origin"]
+	fetch = +refs/heads/*:refs/remotes/origin/*
+------------------------------------------------
+
+This configuration is used in two ways:
+
+* When `git fetch` is run without specifying what branches
+  and/or tags to fetch on the command line, e.g. `git fetch origin`
+  or `git fetch`, `remote.<repository>.fetch` values are used as
+  the refspecs--they specify which refs to fetch and which local refs
+  to update.  The example above will fetch
+  all branches that exist in the `origin` (i.e. any ref that matches
+  the left-hand side of the value, `refs/heads/*`) and update the
+  corresponding remote-tracking branches in the `refs/remotes/origin/*`
+  hierarchy.
+
+* When `git fetch` is run with explicit branches and/or tags
+  to fetch on the command line, e.g. `git fetch origin master`, the
+  <refspec>s given on the command line determine what are to be
+  fetched (e.g. `master` in the example,
+  which is a short-hand for `master:`, which in turn means
+  "fetch the 'master' branch but I do not explicitly say what
+  remote-tracking branch to update with it from the command line"),
+  and the example command will
+  fetch _only_ the 'master' branch.  The `remote.<repository>.fetch`
+  values determine which
+  remote-tracking branch, if any, is updated.  When used in this
+  way, the `remote.<repository>.fetch` values do not have any
+  effect in deciding _what_ gets fetched (i.e. the values are not
+  used as refspecs when the command-line lists refspecs); they are
+  only used to decide _where_ the refs that are fetched are stored
+  by acting as a mapping.
+
+The latter use of the `remote.<repository>.fetch` values can be
+overridden by giving the `--refmap=<refspec>` parameter(s) on the
+command line.
+
+PRUNING
+-------
+
+Git has a default disposition of keeping data unless it's explicitly
+thrown away; this extends to holding onto local references to branches
+on remotes that have themselves deleted those branches.
+
+If left to accumulate, these stale references might make performance
+worse on big and busy repos that have a lot of branch churn, and
+e.g. make the output of commands like `git branch -a --contains
+<commit>` needlessly verbose, as well as impacting anything else
+that'll work with the complete set of known references.
+
+These remote-tracking references can be deleted as a one-off with
+either of:
+
+------------------------------------------------
+# While fetching
+$ git fetch --prune <name>
+
+# Only prune, don't fetch
+$ git remote prune <name>
+------------------------------------------------
+
+To prune references as part of your normal workflow without needing to
+remember to run that, set `fetch.prune` globally, or
+`remote.<name>.prune` per-remote in the config. See
+linkgit:git-config[1].
+
+Here's where things get tricky and more specific. The pruning feature
+doesn't actually care about branches, instead it'll prune local <-->
+remote-references as a function of the refspec of the remote (see
+`<refspec>` and <<CRTB,CONFIGURED REMOTE-TRACKING BRANCHES>> above).
+
+Therefore if the refspec for the remote includes
+e.g. `refs/tags/*:refs/tags/*`, or you manually run e.g. `git fetch
+--prune <name> "refs/tags/*:refs/tags/*"` it won't be stale remote
+tracking branches that are deleted, but any local tag that doesn't
+exist on the remote.
+
+This might not be what you expect, i.e. you want to prune remote
+`<name>`, but also explicitly fetch tags from it, so when you fetch
+from it you delete all your local tags, most of which may not have
+come from the `<name>` remote in the first place.
+
+So be careful when using this with a refspec like
+`refs/tags/*:refs/tags/*`, or any other refspec which might map
+references from multiple remotes to the same local namespace.
+
+Since keeping up-to-date with both branches and tags on the remote is
+a common use-case the `--prune-tags` option can be supplied along with
+`--prune` to prune local tags that don't exist on the remote, and
+force-update those tags that differ. Tag pruning can also be enabled
+with `fetch.pruneTags` or `remote.<name>.pruneTags` in the config. See
+linkgit:git-config[1].
+
+The `--prune-tags` option is equivalent to having
+`refs/tags/*:refs/tags/*` declared in the refspecs of the remote. This
+can lead to some seemingly strange interactions:
+
+------------------------------------------------
+# These both fetch tags
+$ git fetch --no-tags origin 'refs/tags/*:refs/tags/*'
+$ git fetch --no-tags --prune-tags origin
+------------------------------------------------
+
+The reason it doesn't error out when provided without `--prune` or its
+config versions is for flexibility of the configured versions, and to
+maintain a 1=1 mapping between what the command line flags do, and
+what the configuration versions do.
+
+It's reasonable to e.g. configure `fetch.pruneTags=true` in
+`~/.gitconfig` to have tags pruned whenever `git fetch --prune` is
+run, without making every invocation of `git fetch` without `--prune`
+an error.
+
+Pruning tags with `--prune-tags` also works when fetching a URL
+instead of a named remote. These will all prune tags not found on
+origin:
+
+------------------------------------------------
+$ git fetch origin --prune --prune-tags
+$ git fetch origin --prune 'refs/tags/*:refs/tags/*'
+$ git fetch <url-of-origin> --prune --prune-tags
+$ git fetch <url-of-origin> --prune 'refs/tags/*:refs/tags/*'
+------------------------------------------------
+
+OUTPUT
+------
+
+The output of "git fetch" depends on the transport method used; this
+section describes the output when fetching over the Git protocol
+(either locally or via ssh) and Smart HTTP protocol.
+
+The status of the fetch is output in tabular form, with each line
+representing the status of a single ref. Each line is of the form:
+
+-------------------------------
+ <flag> <summary> <from> -> <to> [<reason>]
+-------------------------------
+
+When using `--porcelain`, the output format is intended to be
+machine-parseable. In contrast to the human-readable output formats it
+thus prints to standard output instead of standard error. Each line is
+of the form:
+
+-------------------------------
+<flag> <old-object-id> <new-object-id> <local-reference>
+-------------------------------
+
+The status of up-to-date refs is shown only if the --verbose option is
+used.
+
+In compact output mode, specified with configuration variable
+fetch.output, if either entire `<from>` or `<to>` is found in the
+other string, it will be substituted with `*` in the other string. For
+example, `master -> origin/master` becomes `master -> origin/*`.
+
+flag::
+	A single character indicating the status of the ref:
+(space);; for a successfully fetched fast-forward;
+`+`;; for a successful forced update;
+`-`;; for a successfully pruned ref;
+`t`;; for a successful tag update;
+`*`;; for a successfully fetched new ref;
+`!`;; for a ref that was rejected or failed to update; and
+`=`;; for a ref that was up to date and did not need fetching.
+
+summary::
+	For a successfully fetched ref, the summary shows the old and new
+	values of the ref in a form suitable for using as an argument to
+	`git log` (this is `<old>..<new>` in most cases, and
+	`<old>...<new>` for forced non-fast-forward updates).
+
+from::
+	The name of the remote ref being fetched from, minus its
+	`refs/<type>/` prefix. In the case of deletion, the name of
+	the remote ref is "(none)".
+
+to::
+	The name of the local ref being updated, minus its
+	`refs/<type>/` prefix.
+
+reason::
+	A human-readable explanation. In the case of successfully fetched
+	refs, no explanation is needed. For a failed ref, the reason for
+	failure is described.
+
+EXAMPLES
+--------
+
+* Update the remote-tracking branches:
++
+------------------------------------------------
+$ git fetch origin
+------------------------------------------------
++
+The above command copies all branches from the remote `refs/heads/`
+namespace and stores them to the local `refs/remotes/origin/` namespace,
+unless the `remote.<repository>.fetch` option is used to specify a
+non-default refspec.
+
+* Using refspecs explicitly:
++
+------------------------------------------------
+$ git fetch origin +seen:seen maint:tmp
+------------------------------------------------
++
+This updates (or creates, as necessary) branches `seen` and `tmp` in
+the local repository by fetching from the branches (respectively)
+`seen` and `maint` from the remote repository.
++
+The `seen` branch will be updated even if it does not fast-forward,
+because it is prefixed with a plus sign; `tmp` will not be.
+
+* Peek at a remote's branch, without configuring the remote in your local
+  repository:
++
+------------------------------------------------
+$ git fetch git://git.kernel.org/pub/scm/git/git.git maint
+$ git log FETCH_HEAD
+------------------------------------------------
++
+The first command fetches the `maint` branch from the repository at
+`git://git.kernel.org/pub/scm/git/git.git` and the second command uses
+`FETCH_HEAD` to examine the branch with linkgit:git-log[1].  The fetched
+objects will eventually be removed by git's built-in housekeeping (see
+linkgit:git-gc[1]).
+
+include::transfer-data-leaks.adoc[]
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fetch.adoc[]
+
+BUGS
+----
+Using --recurse-submodules can only fetch new commits in submodules that are
+present locally e.g. in `$GIT_DIR/modules/`. If the upstream adds a new
+submodule, that submodule cannot be fetched until it is cloned e.g. by `git
+submodule update`. This is expected to be fixed in a future Git version.
+
+SEE ALSO
+--------
+linkgit:git-pull[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-filter-branch.adoc b/Documentation/git-filter-branch.adoc
new file mode 100644
index 0000000000..5a4f853785
--- /dev/null
+++ b/Documentation/git-filter-branch.adoc
@@ -0,0 +1,703 @@
+git-filter-branch(1)
+====================
+
+NAME
+----
+git-filter-branch - Rewrite branches
+
+SYNOPSIS
+--------
+[verse]
+'git filter-branch' [--setup <command>] [--subdirectory-filter <directory>]
+	[--env-filter <command>] [--tree-filter <command>]
+	[--index-filter <command>] [--parent-filter <command>]
+	[--msg-filter <command>] [--commit-filter <command>]
+	[--tag-name-filter <command>] [--prune-empty]
+	[--original <namespace>] [-d <directory>] [-f | --force]
+	[--state-branch <branch>] [--] [<rev-list-options>...]
+
+WARNING
+-------
+'git filter-branch' has a plethora of pitfalls that can produce non-obvious
+manglings of the intended history rewrite (and can leave you with little
+time to investigate such problems since it has such abysmal performance).
+These safety and performance issues cannot be backward compatibly fixed and
+as such, its use is not recommended.  Please use an alternative history
+filtering tool such as https://github.com/newren/git-filter-repo/[git
+filter-repo].  If you still need to use 'git filter-branch', please
+carefully read <<SAFETY>> (and <<PERFORMANCE>>) to learn about the land
+mines of filter-branch, and then vigilantly avoid as many of the hazards
+listed there as reasonably possible.
+
+DESCRIPTION
+-----------
+Lets you rewrite Git revision history by rewriting the branches mentioned
+in the <rev-list-options>, applying custom filters on each revision.
+Those filters can modify each tree (e.g. removing a file or running
+a perl rewrite on all files) or information about each commit.
+Otherwise, all information (including original commit times or merge
+information) will be preserved.
+
+The command will only rewrite the _positive_ refs mentioned in the
+command line (e.g. if you pass 'a..b', only 'b' will be rewritten).
+If you specify no filters, the commits will be recommitted without any
+changes, which would normally have no effect.  Nevertheless, this may be
+useful in the future for compensating for some Git bugs or such,
+therefore such a usage is permitted.
+
+*NOTE*: This command honors `.git/info/grafts` file and refs in
+the `refs/replace/` namespace.
+If you have any grafts or replacement refs defined, running this command
+will make them permanent.
+
+*WARNING*! The rewritten history will have different object names for all
+the objects and will not converge with the original branch.  You will not
+be able to easily push and distribute the rewritten branch on top of the
+original branch.  Please do not use this command if you do not know the
+full implications, and avoid using it anyway, if a simple single commit
+would suffice to fix your problem.  (See the "RECOVERING FROM UPSTREAM
+REBASE" section in linkgit:git-rebase[1] for further information about
+rewriting published history.)
+
+Always verify that the rewritten version is correct: The original refs,
+if different from the rewritten ones, will be stored in the namespace
+'refs/original/'.
+
+Note that since this operation is very I/O expensive, it might
+be a good idea to redirect the temporary directory off-disk with the
+`-d` option, e.g. on tmpfs.  Reportedly the speedup is very noticeable.
+
+
+Filters
+~~~~~~~
+
+The filters are applied in the order as listed below.  The <command>
+argument is always evaluated in the shell context using the 'eval' command
+(with the notable exception of the commit filter, for technical reasons).
+Prior to that, the `$GIT_COMMIT` environment variable will be set to contain
+the id of the commit being rewritten.  Also, GIT_AUTHOR_NAME,
+GIT_AUTHOR_EMAIL, GIT_AUTHOR_DATE, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL,
+and GIT_COMMITTER_DATE are taken from the current commit and exported to
+the environment, in order to affect the author and committer identities of
+the replacement commit created by linkgit:git-commit-tree[1] after the
+filters have run.
+
+If any evaluation of <command> returns a non-zero exit status, the whole
+operation will be aborted.
+
+A 'map' function is available that takes an "original sha1 id" argument
+and outputs a "rewritten sha1 id" if the commit has been already
+rewritten, and "original sha1 id" otherwise; the 'map' function can
+return several ids on separate lines if your commit filter emitted
+multiple commits.
+
+
+OPTIONS
+-------
+
+--setup <command>::
+	This is not a real filter executed for each commit but a one
+	time setup just before the loop. Therefore no commit-specific
+	variables are defined yet.  Functions or variables defined here
+	can be used or modified in the following filter steps except
+	the commit filter, for technical reasons.
+
+--subdirectory-filter <directory>::
+	Only look at the history which touches the given subdirectory.
+	The result will contain that directory (and only that) as its
+	project root. Implies <<Remap_to_ancestor>>.
+
+--env-filter <command>::
+	This filter may be used if you only need to modify the environment
+	in which the commit will be performed.  Specifically, you might
+	want to rewrite the author/committer name/email/time environment
+	variables (see linkgit:git-commit-tree[1] for details).
+
+--tree-filter <command>::
+	This is the filter for rewriting the tree and its contents.
+	The argument is evaluated in shell with the working
+	directory set to the root of the checked out tree.  The new tree
+	is then used as-is (new files are auto-added, disappeared files
+	are auto-removed - neither .gitignore files nor any other ignore
+	rules *HAVE ANY EFFECT*!).
+
+--index-filter <command>::
+	This is the filter for rewriting the index.  It is similar to the
+	tree filter but does not check out the tree, which makes it much
+	faster.  Frequently used with `git rm --cached
+	--ignore-unmatch ...`, see EXAMPLES below.  For hairy
+	cases, see linkgit:git-update-index[1].
+
+--parent-filter <command>::
+	This is the filter for rewriting the commit's parent list.
+	It will receive the parent string on stdin and shall output
+	the new parent string on stdout.  The parent string is in
+	the format described in linkgit:git-commit-tree[1]: empty for
+	the initial commit, "-p parent" for a normal commit and
+	"-p parent1 -p parent2 -p parent3 ..." for a merge commit.
+
+--msg-filter <command>::
+	This is the filter for rewriting the commit messages.
+	The argument is evaluated in the shell with the original
+	commit message on standard input; its standard output is
+	used as the new commit message.
+
+--commit-filter <command>::
+	This is the filter for performing the commit.
+	If this filter is specified, it will be called instead of the
+	'git commit-tree' command, with arguments of the form
+	"<TREE_ID> [(-p <PARENT_COMMIT_ID>)...]" and the log message on
+	stdin.  The commit id is expected on stdout.
++
+As a special extension, the commit filter may emit multiple
+commit ids; in that case, the rewritten children of the original commit will
+have all of them as parents.
++
+You can use the 'map' convenience function in this filter, and other
+convenience functions, too.  For example, calling 'skip_commit "$@"'
+will leave out the current commit (but not its changes! If you want
+that, use 'git rebase' instead).
++
+You can also use the `git_commit_non_empty_tree "$@"` instead of
+`git commit-tree "$@"` if you don't wish to keep commits with a single parent
+and that makes no change to the tree.
+
+--tag-name-filter <command>::
+	This is the filter for rewriting tag names. When passed,
+	it will be called for every tag ref that points to a rewritten
+	object (or to a tag object which points to a rewritten object).
+	The original tag name is passed via standard input, and the new
+	tag name is expected on standard output.
++
+The original tags are not deleted, but can be overwritten;
+use "--tag-name-filter cat" to simply update the tags.  In this
+case, be very careful and make sure you have the old tags
+backed up in case the conversion has run afoul.
++
+Nearly proper rewriting of tag objects is supported. If the tag has
+a message attached, a new tag object will be created with the same message,
+author, and timestamp. If the tag has a signature attached, the
+signature will be stripped. It is by definition impossible to preserve
+signatures. The reason this is "nearly" proper, is because ideally if
+the tag did not change (points to the same object, has the same name, etc.)
+it should retain any signature. That is not the case, signatures will always
+be removed, buyer beware. There is also no support for changing the
+author or timestamp (or the tag message for that matter). Tags which point
+to other tags will be rewritten to point to the underlying commit.
+
+--prune-empty::
+	Some filters will generate empty commits that leave the tree untouched.
+	This option instructs git-filter-branch to remove such commits if they
+	have exactly one or zero non-pruned parents; merge commits will
+	therefore remain intact.  This option cannot be used together with
+	`--commit-filter`, though the same effect can be achieved by using the
+	provided `git_commit_non_empty_tree` function in a commit filter.
+
+--original <namespace>::
+	Use this option to set the namespace where the original commits
+	will be stored. The default value is 'refs/original'.
+
+-d <directory>::
+	Use this option to set the path to the temporary directory used for
+	rewriting.  When applying a tree filter, the command needs to
+	temporarily check out the tree to some directory, which may consume
+	considerable space in case of large projects.  By default it
+	does this in the `.git-rewrite/` directory but you can override
+	that choice by this parameter.
+
+-f::
+--force::
+	'git filter-branch' refuses to start with an existing temporary
+	directory or when there are already refs starting with
+	'refs/original/', unless forced.
+
+--state-branch <branch>::
+	This option will cause the mapping from old to new objects to
+	be loaded from named branch upon startup and saved as a new
+	commit to that branch upon exit, enabling incremental of large
+	trees. If '<branch>' does not exist it will be created.
+
+<rev-list options>...::
+	Arguments for 'git rev-list'.  All positive refs included by
+	these options are rewritten.  You may also specify options
+	such as `--all`, but you must use `--` to separate them from
+	the 'git filter-branch' options. Implies <<Remap_to_ancestor>>.
+
+
+[[Remap_to_ancestor]]
+Remap to ancestor
+~~~~~~~~~~~~~~~~~
+
+By using linkgit:git-rev-list[1] arguments, e.g., path limiters, you can limit the
+set of revisions which get rewritten. However, positive refs on the command
+line are distinguished: we don't let them be excluded by such limiters. For
+this purpose, they are instead rewritten to point at the nearest ancestor that
+was not excluded.
+
+
+EXIT STATUS
+-----------
+
+On success, the exit status is `0`.  If the filter can't find any commits to
+rewrite, the exit status is `2`.  On any other error, the exit status may be
+any other non-zero value.
+
+
+EXAMPLES
+--------
+
+Suppose you want to remove a file (containing confidential information
+or copyright violation) from all commits:
+
+-------------------------------------------------------
+git filter-branch --tree-filter 'rm filename' HEAD
+-------------------------------------------------------
+
+However, if the file is absent from the tree of some commit,
+a simple `rm filename` will fail for that tree and commit.
+Thus you may instead want to use `rm -f filename` as the script.
+
+Using `--index-filter` with 'git rm' yields a significantly faster
+version.  Like with using `rm filename`, `git rm --cached filename`
+will fail if the file is absent from the tree of a commit.  If you
+want to "completely forget" a file, it does not matter when it entered
+history, so we also add `--ignore-unmatch`:
+
+--------------------------------------------------------------------------
+git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD
+--------------------------------------------------------------------------
+
+Now, you will get the rewritten history saved in HEAD.
+
+To rewrite the repository to look as if `foodir/` had been its project
+root, and discard all other history:
+
+-------------------------------------------------------
+git filter-branch --subdirectory-filter foodir -- --all
+-------------------------------------------------------
+
+Thus you can, e.g., turn a library subdirectory into a repository of
+its own.  Note the `--` that separates 'filter-branch' options from
+revision options, and the `--all` to rewrite all branches and tags.
+
+To set a commit (which typically is at the tip of another
+history) to be the parent of the current initial commit, in
+order to paste the other history behind the current history:
+
+-------------------------------------------------------------------
+git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD
+-------------------------------------------------------------------
+
+(if the parent string is empty - which happens when we are dealing with
+the initial commit - add graftcommit as a parent).  Note that this assumes
+history with a single root (that is, no merge without common ancestors
+happened).  If this is not the case, use:
+
+--------------------------------------------------------------------------
+git filter-branch --parent-filter \
+	'test $GIT_COMMIT = <commit-id> && echo "-p <graft-id>" || cat' HEAD
+--------------------------------------------------------------------------
+
+or even simpler:
+
+-----------------------------------------------
+git replace --graft $commit-id $graft-id
+git filter-branch $graft-id..HEAD
+-----------------------------------------------
+
+To remove commits authored by "Darl McBribe" from the history:
+
+------------------------------------------------------------------------------
+git filter-branch --commit-filter '
+	if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ];
+	then
+		skip_commit "$@";
+	else
+		git commit-tree "$@";
+	fi' HEAD
+------------------------------------------------------------------------------
+
+The function 'skip_commit' is defined as follows:
+
+--------------------------
+skip_commit()
+{
+	shift;
+	while [ -n "$1" ];
+	do
+		shift;
+		map "$1";
+		shift;
+	done;
+}
+--------------------------
+
+The shift magic first throws away the tree id and then the -p
+parameters.  Note that this handles merges properly! In case Darl
+committed a merge between P1 and P2, it will be propagated properly
+and all children of the merge will become merge commits with P1,P2
+as their parents instead of the merge commit.
+
+*NOTE* the changes introduced by the commits, and which are not reverted
+by subsequent commits, will still be in the rewritten branch. If you want
+to throw out _changes_ together with the commits, you should use the
+interactive mode of 'git rebase'.
+
+You can rewrite the commit log messages using `--msg-filter`.  For
+example, 'git svn-id' strings in a repository created by 'git svn' can
+be removed this way:
+
+-------------------------------------------------------
+git filter-branch --msg-filter '
+	sed -e "/^git-svn-id:/d"
+'
+-------------------------------------------------------
+
+If you need to add 'Acked-by' lines to, say, the last 10 commits (none
+of which is a merge), use this command:
+
+--------------------------------------------------------
+git filter-branch --msg-filter '
+	cat &&
+	echo "Acked-by: Bugs Bunny <bunny@xxxxxxxxxxxx>"
+' HEAD~10..HEAD
+--------------------------------------------------------
+
+The `--env-filter` option can be used to modify committer and/or author
+identity.  For example, if you found out that your commits have the wrong
+identity due to a misconfigured user.email, you can make a correction,
+before publishing the project, like this:
+
+--------------------------------------------------------
+git filter-branch --env-filter '
+	if test "$GIT_AUTHOR_EMAIL" = "root@localhost"
+	then
+		GIT_AUTHOR_EMAIL=john@xxxxxxxxxxx
+	fi
+	if test "$GIT_COMMITTER_EMAIL" = "root@localhost"
+	then
+		GIT_COMMITTER_EMAIL=john@xxxxxxxxxxx
+	fi
+' -- --all
+--------------------------------------------------------
+
+To restrict rewriting to only part of the history, specify a revision
+range in addition to the new branch name.  The new branch name will
+point to the top-most revision that a 'git rev-list' of this range
+will print.
+
+Consider this history:
+
+------------------
+     D--E--F--G--H
+    /     /
+A--B-----C
+------------------
+
+To rewrite only commits D,E,F,G,H, but leave A, B and C alone, use:
+
+--------------------------------
+git filter-branch ... C..H
+--------------------------------
+
+To rewrite commits E,F,G,H, use one of these:
+
+----------------------------------------
+git filter-branch ... C..H --not D
+git filter-branch ... D..H --not C
+----------------------------------------
+
+To move the whole tree into a subdirectory, or remove it from there:
+
+---------------------------------------------------------------
+git filter-branch --index-filter \
+	'git ls-files -s | sed "s-\t\"*-&newsubdir/-" |
+		GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
+			git update-index --index-info &&
+	 mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD
+---------------------------------------------------------------
+
+
+
+CHECKLIST FOR SHRINKING A REPOSITORY
+------------------------------------
+
+git-filter-branch can be used to get rid of a subset of files,
+usually with some combination of `--index-filter` and
+`--subdirectory-filter`.  People expect the resulting repository to
+be smaller than the original, but you need a few more steps to
+actually make it smaller, because Git tries hard not to lose your
+objects until you tell it to.  First make sure that:
+
+* You really removed all variants of a filename, if a blob was moved
+  over its lifetime.  `git log --name-only --follow --all -- filename`
+  can help you find renames.
+
+* You really filtered all refs: use `--tag-name-filter cat -- --all`
+  when calling git-filter-branch.
+
+Then there are two ways to get a smaller repository.  A safer way is
+to clone, that keeps your original intact.
+
+* Clone it with `git clone file:///path/to/repo`.  The clone
+  will not have the removed objects.  See linkgit:git-clone[1].  (Note
+  that cloning with a plain path just hardlinks everything!)
+
+If you really don't want to clone it, for whatever reasons, check the
+following points instead (in this order).  This is a very destructive
+approach, so *make a backup* or go back to cloning it.  You have been
+warned.
+
+* Remove the original refs backed up by git-filter-branch: say `git
+  for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git
+  update-ref -d`.
+
+* Expire all reflogs with `git reflog expire --expire=now --all`.
+
+* Garbage collect all unreferenced objects with `git gc --prune=now`
+  (or if your git-gc is not new enough to support arguments to
+  `--prune`, use `git repack -ad; git prune` instead).
+
+[[PERFORMANCE]]
+PERFORMANCE
+-----------
+
+The performance of git-filter-branch is glacially slow; its design makes it
+impossible for a backward-compatible implementation to ever be fast:
+
+* In editing files, git-filter-branch by design checks out each and
+  every commit as it existed in the original repo.  If your repo has
+  `10^5` files and `10^5` commits, but each commit only modifies five
+  files, then git-filter-branch will make you do `10^10` modifications,
+  despite only having (at most) `5*10^5` unique blobs.
+
+* If you try and cheat and try to make git-filter-branch only work on
+  files modified in a commit, then two things happen
+
+  ** you run into problems with deletions whenever the user is simply
+     trying to rename files (because attempting to delete files that
+     don't exist looks like a no-op; it takes some chicanery to remap
+     deletes across file renames when the renames happen via arbitrary
+     user-provided shell)
+
+  ** even if you succeed at the map-deletes-for-renames chicanery, you
+     still technically violate backward compatibility because users
+     are allowed to filter files in ways that depend upon topology of
+     commits instead of filtering solely based on file contents or
+     names (though this has not been observed in the wild).
+
+* Even if you don't need to edit files but only want to e.g. rename or
+  remove some and thus can avoid checking out each file (i.e. you can
+  use --index-filter), you still are passing shell snippets for your
+  filters.  This means that for every commit, you have to have a
+  prepared git repo where those filters can be run.  That's a
+  significant setup.
+
+* Further, several additional files are created or updated per commit
+  by git-filter-branch.  Some of these are for supporting the
+  convenience functions provided by git-filter-branch (such as map()),
+  while others are for keeping track of internal state (but could have
+  also been accessed by user filters; one of git-filter-branch's
+  regression tests does so).  This essentially amounts to using the
+  filesystem as an IPC mechanism between git-filter-branch and the
+  user-provided filters.  Disks tend to be a slow IPC mechanism, and
+  writing these files also effectively represents a forced
+  synchronization point between separate processes that we hit with
+  every commit.
+
+* The user-provided shell commands will likely involve a pipeline of
+  commands, resulting in the creation of many processes per commit.
+  Creating and running another process takes a widely varying amount
+  of time between operating systems, but on any platform it is very
+  slow relative to invoking a function.
+
+* git-filter-branch itself is written in shell, which is kind of slow.
+  This is the one performance issue that could be backward-compatibly
+  fixed, but compared to the above problems that are intrinsic to the
+  design of git-filter-branch, the language of the tool itself is a
+  relatively minor issue.
+
+  ** Side note: Unfortunately, people tend to fixate on the
+     written-in-shell aspect and periodically ask if git-filter-branch
+     could be rewritten in another language to fix the performance
+     issues.  Not only does that ignore the bigger intrinsic problems
+     with the design, it'd help less than you'd expect: if
+     git-filter-branch itself were not shell, then the convenience
+     functions (map(), skip_commit(), etc) and the `--setup` argument
+     could no longer be executed once at the beginning of the program
+     but would instead need to be prepended to every user filter (and
+     thus re-executed with every commit).
+
+The https://github.com/newren/git-filter-repo/[git filter-repo] tool is
+an alternative to git-filter-branch which does not suffer from these
+performance problems or the safety problems (mentioned below). For those
+with existing tooling which relies upon git-filter-branch, 'git
+filter-repo' also provides
+https://github.com/newren/git-filter-repo/blob/master/contrib/filter-repo-demos/filter-lamely[filter-lamely],
+a drop-in git-filter-branch replacement (with a few caveats).  While
+filter-lamely suffers from all the same safety issues as
+git-filter-branch, it at least ameliorates the performance issues a
+little.
+
+[[SAFETY]]
+SAFETY
+------
+
+git-filter-branch is riddled with gotchas resulting in various ways to
+easily corrupt repos or end up with a mess worse than what you started
+with:
+
+* Someone can have a set of "working and tested filters" which they
+  document or provide to a coworker, who then runs them on a different
+  OS where the same commands are not working/tested (some examples in
+  the git-filter-branch manpage are also affected by this).
+  BSD vs. GNU userland differences can really bite.  If lucky, error
+  messages are spewed.  But just as likely, the commands either don't
+  do the filtering requested, or silently corrupt by making some
+  unwanted change.  The unwanted change may only affect a few commits,
+  so it's not necessarily obvious either.  (The fact that problems
+  won't necessarily be obvious means they are likely to go unnoticed
+  until the rewritten history is in use for quite a while, at which
+  point it's really hard to justify another flag-day for another
+  rewrite.)
+
+* Filenames with spaces are often mishandled by shell snippets since
+  they cause problems for shell pipelines.  Not everyone is familiar
+  with find -print0, xargs -0, git-ls-files -z, etc.  Even people who
+  are familiar with these may assume such flags are not relevant
+  because someone else renamed any such files in their repo back
+  before the person doing the filtering joined the project.  And
+  often, even those familiar with handling arguments with spaces may
+  not do so just because they aren't in the mindset of thinking about
+  everything that could possibly go wrong.
+
+* Non-ascii filenames can be silently removed despite being in a
+  desired directory.  Keeping only wanted paths is often done using
+  pipelines like `git ls-files | grep -v ^WANTED_DIR/ | xargs git rm`.
+  ls-files will only quote filenames if needed, so folks may not
+  notice that one of the files didn't match the regex (at least not
+  until it's much too late).  Yes, someone who knows about
+  core.quotePath can avoid this (unless they have other special
+  characters like \t, \n, or "), and people who use ls-files -z with
+  something other than grep can avoid this, but that doesn't mean they
+  will.
+
+* Similarly, when moving files around, one can find that filenames
+  with non-ascii or special characters end up in a different
+  directory, one that includes a double quote character.  (This is
+  technically the same issue as above with quoting, but perhaps an
+  interesting different way that it can and has manifested as a
+  problem.)
+
+* It's far too easy to accidentally mix up old and new history.  It's
+  still possible with any tool, but git-filter-branch almost
+  invites it.  If lucky, the only downside is users getting frustrated
+  that they don't know how to shrink their repo and remove the old
+  stuff.  If unlucky, they merge old and new history and end up with
+  multiple "copies" of each commit, some of which have unwanted or
+  sensitive files and others which don't.  This comes about in
+  multiple different ways:
+
+  ** the default to only doing a partial history rewrite ('--all' is not
+     the default and few examples show it)
+
+  ** the fact that there's no automatic post-run cleanup
+
+  ** the fact that --tag-name-filter (when used to rename tags) doesn't
+     remove the old tags but just adds new ones with the new name
+
+  ** the fact that little educational information is provided to inform
+     users of the ramifications of a rewrite and how to avoid mixing old
+     and new history.  For example, this man page discusses how users
+     need to understand that they need to rebase their changes for all
+     their branches on top of new history (or delete and reclone), but
+     that's only one of multiple concerns to consider.  See the
+     "DISCUSSION" section of the git filter-repo manual page for more
+     details.
+
+* Annotated tags can be accidentally converted to lightweight tags,
+  due to either of two issues:
+
+  ** Someone can do a history rewrite, realize they messed up, restore
+     from the backups in refs/original/, and then redo their
+     git-filter-branch command.  (The backup in refs/original/ is not a
+     real backup; it dereferences tags first.)
+
+  ** Running git-filter-branch with either --tags or --all in your
+     <rev-list-options>.  In order to retain annotated tags as
+     annotated, you must use --tag-name-filter (and must not have
+     restored from refs/original/ in a previously botched rewrite).
+
+* Any commit messages that specify an encoding will become corrupted
+  by the rewrite; git-filter-branch ignores the encoding, takes the
+  original bytes, and feeds it to commit-tree without telling it the
+  proper encoding.  (This happens whether or not --msg-filter is
+  used.)
+
+* Commit messages (even if they are all UTF-8) by default become
+  corrupted due to not being updated -- any references to other commit
+  hashes in commit messages will now refer to no-longer-extant
+  commits.
+
+* There are no facilities for helping users find what unwanted crud
+  they should delete, which means they are much more likely to have
+  incomplete or partial cleanups that sometimes result in confusion
+  and people wasting time trying to understand.  (For example, folks
+  tend to just look for big files to delete instead of big directories
+  or extensions, and once they do so, then sometime later folks using
+  the new repository who are going through history will notice a build
+  artifact directory that has some files but not others, or a cache of
+  dependencies (node_modules or similar) which couldn't have ever been
+  functional since it's missing some files.)
+
+* If --prune-empty isn't specified, then the filtering process can
+  create hoards of confusing empty commits
+
+* If --prune-empty is specified, then intentionally placed empty
+  commits from before the filtering operation are also pruned instead
+  of just pruning commits that became empty due to filtering rules.
+
+* If --prune-empty is specified, sometimes empty commits are missed
+  and left around anyway (a somewhat rare bug, but it happens...)
+
+* A minor issue, but users who have a goal to update all names and
+  emails in a repository may be led to --env-filter which will only
+  update authors and committers, missing taggers.
+
+* If the user provides a --tag-name-filter that maps multiple tags to
+  the same name, no warning or error is provided; git-filter-branch
+  simply overwrites each tag in some undocumented pre-defined order
+  resulting in only one tag at the end.  (A git-filter-branch
+  regression test requires this surprising behavior.)
+
+Also, the poor performance of git-filter-branch often leads to safety
+issues:
+
+* Coming up with the correct shell snippet to do the filtering you
+  want is sometimes difficult unless you're just doing a trivial
+  modification such as deleting a couple files.  Unfortunately, people
+  often learn if the snippet is right or wrong by trying it out, but
+  the rightness or wrongness can vary depending on special
+  circumstances (spaces in filenames, non-ascii filenames, funny
+  author names or emails, invalid timezones, presence of grafts or
+  replace objects, etc.), meaning they may have to wait a long time,
+  hit an error, then restart.  The performance of git-filter-branch is
+  so bad that this cycle is painful, reducing the time available to
+  carefully re-check (to say nothing about what it does to the
+  patience of the person doing the rewrite even if they do technically
+  have more time available).  This problem is extra compounded because
+  errors from broken filters may not be shown for a long time and/or
+  get lost in a sea of output.  Even worse, broken filters often just
+  result in silent incorrect rewrites.
+
+* To top it all off, even when users finally find working commands,
+  they naturally want to share them.  But they may be unaware that
+  their repo didn't have some special cases that someone else's does.
+  So, when someone else with a different repository runs the same
+  commands, they get hit by the problems above.  Or, the user just
+  runs commands that really were vetted for special cases, but they
+  run it on a different OS where it doesn't work, as noted above.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fmt-merge-msg.adoc b/Documentation/git-fmt-merge-msg.adoc
new file mode 100644
index 0000000000..0f3328956d
--- /dev/null
+++ b/Documentation/git-fmt-merge-msg.adoc
@@ -0,0 +1,82 @@
+git-fmt-merge-msg(1)
+====================
+
+NAME
+----
+git-fmt-merge-msg - Produce a merge commit message
+
+
+SYNOPSIS
+--------
+[verse]
+'git fmt-merge-msg' [-m <message>] [--into-name <branch>] [--log[=<n>] | --no-log]
+'git fmt-merge-msg' [-m <message>] [--log[=<n>] | --no-log] -F <file>
+
+DESCRIPTION
+-----------
+Takes the list of merged objects on stdin and produces a suitable
+commit message to be used for the merge commit, usually to be
+passed as the '<merge-message>' argument of 'git merge'.
+
+This command is intended mostly for internal use by scripts
+automatically invoking 'git merge'.
+
+OPTIONS
+-------
+
+--log[=<n>]::
+	In addition to branch names, populate the log message with
+	one-line descriptions from the actual commits that are being
+	merged.  At most <n> commits from each merge parent will be
+	used (20 if <n> is omitted).  This overrides the `merge.log`
+	configuration variable.
+
+--no-log::
+	Do not list one-line descriptions from the actual commits being
+	merged.
+
+--[no-]summary::
+	Synonyms to --log and --no-log; these are deprecated and will be
+	removed in the future.
+
+-m <message>::
+--message <message>::
+	Use <message> instead of the branch names for the first line
+	of the log message.  For use with `--log`.
+
+--into-name <branch>::
+	Prepare the merge message as if merging to the branch `<branch>`,
+	instead of the name of the real branch to which the merge is made.
+
+-F <file>::
+--file <file>::
+	Take the list of merged objects from <file> instead of
+	stdin.
+
+CONFIGURATION
+-------------
+include::config/fmt-merge-msg.adoc[]
+
+merge.summary::
+	Synonym to `merge.log`; this is deprecated and will be removed in
+	the future.
+
+EXAMPLES
+--------
+
+---------
+$ git fetch origin master
+$ git fmt-merge-msg --log <$GIT_DIR/FETCH_HEAD
+---------
+
+Print a log message describing a merge of the "master" branch from
+the "origin" remote.
+
+
+SEE ALSO
+--------
+linkgit:git-merge[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-for-each-ref.adoc b/Documentation/git-for-each-ref.adoc
new file mode 100644
index 0000000000..ffb97e62c2
--- /dev/null
+++ b/Documentation/git-for-each-ref.adoc
@@ -0,0 +1,549 @@
+git-for-each-ref(1)
+===================
+
+NAME
+----
+git-for-each-ref - Output information on each ref
+
+SYNOPSIS
+--------
+[verse]
+'git for-each-ref' [--count=<count>] [--shell|--perl|--python|--tcl]
+		   [(--sort=<key>)...] [--format=<format>]
+		   [--include-root-refs] [ --stdin | <pattern>... ]
+		   [--points-at=<object>]
+		   [--merged[=<object>]] [--no-merged[=<object>]]
+		   [--contains[=<object>]] [--no-contains[=<object>]]
+		   [--exclude=<pattern> ...]
+
+DESCRIPTION
+-----------
+
+Iterate over all refs that match `<pattern>` and show them
+according to the given `<format>`, after sorting them according
+to the given set of `<key>`.  If `<count>` is given, stop after
+showing that many refs.  The interpolated values in `<format>`
+can optionally be quoted as string literals in the specified
+host language allowing their direct evaluation in that language.
+
+OPTIONS
+-------
+<pattern>...::
+	If one or more patterns are given, only refs are shown that
+	match against at least one pattern, either using fnmatch(3) or
+	literally, in the latter case matching completely or from the
+	beginning up to a slash.
+
+--stdin::
+	If `--stdin` is supplied, then the list of patterns is read from
+	standard input instead of from the argument list.
+
+--count=<count>::
+	By default the command shows all refs that match
+	`<pattern>`.  This option makes it stop after showing
+	that many refs.
+
+--sort=<key>::
+	A field name to sort on.  Prefix `-` to sort in
+	descending order of the value.  When unspecified,
+	`refname` is used.  You may use the --sort=<key> option
+	multiple times, in which case the last key becomes the primary
+	key.
+
+--format=<format>::
+	A string that interpolates `%(fieldname)` from a ref being shown and
+	the object it points at. In addition, the string literal `%%`
+	renders as `%` and `%xx` - where `xx` are hex digits - renders as
+	the character with hex code `xx`. For example, `%00` interpolates to
+	`\0` (NUL), `%09` to `\t` (TAB), and `%0a` to `\n` (LF).
++
+When unspecified, `<format>` defaults to `%(objectname) SPC %(objecttype)
+TAB %(refname)`.
+
+--color[=<when>]::
+	Respect any colors specified in the `--format` option. The
+	`<when>` field must be one of `always`, `never`, or `auto` (if
+	`<when>` is absent, behave as if `always` was given).
+
+--shell::
+--perl::
+--python::
+--tcl::
+	If given, strings that substitute `%(fieldname)`
+	placeholders are quoted as string literals suitable for
+	the specified host language.  This is meant to produce
+	a scriptlet that can directly be `eval`ed.
+
+--points-at=<object>::
+	Only list refs which points at the given object.
+
+--merged[=<object>]::
+	Only list refs whose tips are reachable from the
+	specified commit (HEAD if not specified).
+
+--no-merged[=<object>]::
+	Only list refs whose tips are not reachable from the
+	specified commit (HEAD if not specified).
+
+--contains[=<object>]::
+	Only list refs which contain the specified commit (HEAD if not
+	specified).
+
+--no-contains[=<object>]::
+	Only list refs which don't contain the specified commit (HEAD
+	if not specified).
+
+--ignore-case::
+	Sorting and filtering refs are case insensitive.
+
+--omit-empty::
+	Do not print a newline after formatted refs where the format expands
+	to the empty string.
+
+--exclude=<pattern>::
+	If one or more patterns are given, only refs which do not match
+	any excluded pattern(s) are shown. Matching is done using the
+	same rules as `<pattern>` above.
+
+--include-root-refs::
+	List root refs (HEAD and pseudorefs) apart from regular refs.
+
+FIELD NAMES
+-----------
+
+Various values from structured fields in referenced objects can
+be used to interpolate into the resulting output, or as sort
+keys.
+
+For all objects, the following names can be used:
+
+refname::
+	The name of the ref (the part after $GIT_DIR/).
+	For a non-ambiguous short name of the ref append `:short`.
+	The option core.warnAmbiguousRefs is used to select the strict
+	abbreviation mode. If `lstrip=<N>` (`rstrip=<N>`) is appended, strips `<N>`
+	slash-separated path components from the front (back) of the refname
+	(e.g. `%(refname:lstrip=2)` turns `refs/tags/foo` into `foo` and
+	`%(refname:rstrip=2)` turns `refs/tags/foo` into `refs`).
+	If `<N>` is a negative number, strip as many path components as
+	necessary from the specified end to leave `-<N>` path components
+	(e.g. `%(refname:lstrip=-2)` turns
+	`refs/tags/foo` into `tags/foo` and `%(refname:rstrip=-1)`
+	turns `refs/tags/foo` into `refs`). When the ref does not have
+	enough components, the result becomes an empty string if
+	stripping with positive <N>, or it becomes the full refname if
+	stripping with negative <N>.  Neither is an error.
++
+`strip` can be used as a synonym to `lstrip`.
+
+objecttype::
+	The type of the object (`blob`, `tree`, `commit`, `tag`).
+
+objectsize::
+	The size of the object (the same as 'git cat-file -s' reports).
+	Append `:disk` to get the size, in bytes, that the object takes up on
+	disk. See the note about on-disk sizes in the `CAVEATS` section below.
+objectname::
+	The object name (aka SHA-1).
+	For a non-ambiguous abbreviation of the object name append `:short`.
+	For an abbreviation of the object name with desired length append
+	`:short=<length>`, where the minimum length is MINIMUM_ABBREV. The
+	length may be exceeded to ensure unique object names.
+deltabase::
+	This expands to the object name of the delta base for the
+	given object, if it is stored as a delta.  Otherwise it
+	expands to the null object name (all zeroes).
+
+upstream::
+	The name of a local ref which can be considered ``upstream''
+	from the displayed ref. Respects `:short`, `:lstrip` and
+	`:rstrip` in the same way as `refname` above.  Additionally
+	respects `:track` to show "[ahead N, behind M]" and
+	`:trackshort` to show the terse version: ">" (ahead), "<"
+	(behind), "<>" (ahead and behind), or "=" (in sync). `:track`
+	also prints "[gone]" whenever unknown upstream ref is
+	encountered. Append `:track,nobracket` to show tracking
+	information without brackets (i.e "ahead N, behind M").
++
+For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)`
+and `%(upstream:remoteref)` refer to the name of the remote and the
+name of the tracked remote ref, respectively. In other words, the
+remote-tracking branch can be updated explicitly and individually by
+using the refspec `%(upstream:remoteref):%(upstream)` to fetch from
+`%(upstream:remotename)`.
++
+Has no effect if the ref does not have tracking information associated
+with it.  All the options apart from `nobracket` are mutually exclusive,
+but if used together the last option is selected.
+
+push::
+	The name of a local ref which represents the `@{push}`
+	location for the displayed ref. Respects `:short`, `:lstrip`,
+	`:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref`
+	options as `upstream` does. Produces an empty string if no `@{push}`
+	ref is configured.
+
+HEAD::
+	'*' if HEAD matches current ref (the checked out branch), ' '
+	otherwise.
+
+color::
+	Change output color. Followed by `:<colorname>`, where color
+	names are described under Values in the "CONFIGURATION FILE"
+	section of linkgit:git-config[1].  For example,
+	`%(color:bold red)`.
+
+align::
+	Left-, middle-, or right-align the content between
+	%(align:...) and %(end). The "align:" is followed by
+	`width=<width>` and `position=<position>` in any order
+	separated by a comma, where the `<position>` is either left,
+	right or middle, default being left and `<width>` is the total
+	length of the content with alignment. For brevity, the
+	"width=" and/or "position=" prefixes may be omitted, and bare
+	<width> and <position> used instead.  For instance,
+	`%(align:<width>,<position>)`. If the contents length is more
+	than the width then no alignment is performed. If used with
+	`--quote` everything in between %(align:...) and %(end) is
+	quoted, but if nested then only the topmost level performs
+	quoting.
+
+if::
+	Used as %(if)...%(then)...%(end) or
+	%(if)...%(then)...%(else)...%(end).  If there is an atom with
+	value or string literal after the %(if) then everything after
+	the %(then) is printed, else if the %(else) atom is used, then
+	everything after %(else) is printed. We ignore space when
+	evaluating the string before %(then), this is useful when we
+	use the %(HEAD) atom which prints either "*" or " " and we
+	want to apply the 'if' condition only on the 'HEAD' ref.
+	Append ":equals=<string>" or ":notequals=<string>" to compare
+	the value between the %(if:...) and %(then) atoms with the
+	given string.
+
+symref::
+	The ref which the given symbolic ref refers to. If not a
+	symbolic ref, nothing is printed. Respects the `:short`,
+	`:lstrip` and `:rstrip` options in the same way as `refname`
+	above.
+
+signature::
+	The GPG signature of a commit.
+
+signature:grade::
+	Show "G" for a good (valid) signature, "B" for a bad
+	signature, "U" for a good signature with unknown validity, "X"
+	for a good signature that has expired, "Y" for a good
+	signature made by an expired key, "R" for a good signature
+	made by a revoked key, "E" if the signature cannot be
+	checked (e.g. missing key) and "N" for no signature.
+
+signature:signer::
+	The signer of the GPG signature of a commit.
+
+signature:key::
+	The key of the GPG signature of a commit.
+
+signature:fingerprint::
+	The fingerprint of the GPG signature of a commit.
+
+signature:primarykeyfingerprint::
+	The primary key fingerprint of the GPG signature of a commit.
+
+signature:trustlevel::
+	The trust level of the GPG signature of a commit. Possible
+	outputs are `ultimate`, `fully`, `marginal`, `never` and `undefined`.
+
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. Empty string
+	otherwise.
+
+ahead-behind:<committish>::
+	Two integers, separated by a space, demonstrating the number of
+	commits ahead and behind, respectively, when comparing the output
+	ref to the `<committish>` specified in the format.
+
+is-base:<committish>::
+	In at most one row, `(<committish>)` will appear to indicate the ref
+	that is most likely the ref used as a starting point for the branch
+	that produced `<committish>`. This choice is made using a heuristic:
+	choose the ref that minimizes the number of commits in the
+	first-parent history of `<committish>` and not in the first-parent
+	history of the ref.
++
+For example, consider the following figure of first-parent histories of
+several refs:
++
+----
+*--*--*--*--*--* refs/heads/A
+\
+ \
+  *--*--*--* refs/heads/B
+   \     \
+    \     \
+     *     * refs/heads/C
+      \
+       \
+	*--* refs/heads/D
+----
++
+Here, if `A`, `B`, and `C` are the filtered references, and the format
+string is `%(refname):%(is-base:D)`, then the output would be
++
+----
+refs/heads/A:
+refs/heads/B:(D)
+refs/heads/C:
+----
++
+This is because the first-parent history of `D` has its earliest
+intersection with the first-parent histories of the filtered refs at a
+common first-parent ancestor of `B` and `C` and ties are broken by the
+earliest ref in the sorted order.
++
+Note that this token will not appear if the first-parent history of
+`<committish>` does not intersect the first-parent histories of the
+filtered refs.
+
+describe[:options]::
+	A human-readable name, like linkgit:git-describe[1];
+	empty string for undescribable commits. The `describe` string may
+	be followed by a colon and one or more comma-separated options.
++
+--
+tags=<bool-value>;;
+	Instead of only considering annotated tags, consider
+	lightweight tags as well; see the corresponding option in
+	linkgit:git-describe[1] for details.
+abbrev=<number>;;
+	Use at least <number> hexadecimal digits; see the corresponding
+	option in linkgit:git-describe[1] for details.
+match=<pattern>;;
+	Only consider tags matching the given `glob(7)` pattern,
+	excluding the "refs/tags/" prefix; see the corresponding option
+	in linkgit:git-describe[1] for details.
+exclude=<pattern>;;
+	Do not consider tags matching the given `glob(7)` pattern,
+	excluding the "refs/tags/" prefix; see the corresponding option
+	in linkgit:git-describe[1] for details.
+--
+
+In addition to the above, for commit and tag objects, the header
+field names (`tree`, `parent`, `object`, `type`, and `tag`) can
+be used to specify the value in the header field.
+Fields `tree` and `parent` can also be used with modifier `:short` and
+`:short=<length>` just like `objectname`.
+
+For commit and tag objects, the special `creatordate` and `creator`
+fields will correspond to the appropriate date or name-email-date tuple
+from the `committer` or `tagger` fields depending on the object type.
+These are intended for working on a mix of annotated and lightweight tags.
+
+For tag objects, a `fieldname` prefixed with an asterisk (`*`) expands to
+the `fieldname` value of the peeled object, rather than that of the tag
+object itself.
+
+Fields that have name-email-date tuple as its value (`author`,
+`committer`, and `tagger`) can be suffixed with `name`, `email`,
+and `date` to extract the named component.  For email fields (`authoremail`,
+`committeremail` and `taggeremail`), `:trim` can be appended to get the email
+without angle brackets, and `:localpart` to get the part before the `@` symbol
+out of the trimmed email. In addition to these, the `:mailmap` option and the
+corresponding `:mailmap,trim` and `:mailmap,localpart` can be used (order does
+not matter) to get values of the name and email according to the .mailmap file
+or according to the file set in the mailmap.file or mailmap.blob configuration
+variable (see linkgit:gitmailmap[5]).
+
+The raw data in an object is `raw`.
+
+raw:size::
+	The raw data size of the object.
+
+Note that `--format=%(raw)` can not be used with `--python`, `--shell`, `--tcl`,
+because such language may not support arbitrary binary data in their string
+variable type.
+
+The message in a commit or a tag object is `contents`, from which
+`contents:<part>` can be used to extract various parts out of:
+
+contents:size::
+	The size in bytes of the commit or tag message.
+
+contents:subject::
+	The first paragraph of the message, which typically is a
+	single line, is taken as the "subject" of the commit or the
+	tag message.
+	Instead of `contents:subject`, field `subject` can also be used to
+	obtain same results. `:sanitize` can be appended to `subject` for
+	subject line suitable for filename.
+
+contents:body::
+	The remainder of the commit or the tag message that follows
+	the "subject".
+
+contents:signature::
+	The optional GPG signature of the tag.
+
+contents:lines=N::
+	The first `N` lines of the message.
+
+Additionally, the trailers as interpreted by linkgit:git-interpret-trailers[1]
+are obtained as `trailers[:options]` (or by using the historical alias
+`contents:trailers[:options]`). For valid [:option] values see `trailers`
+section of linkgit:git-log[1].
+
+For sorting purposes, fields with numeric values sort in numeric order
+(`objectsize`, `authordate`, `committerdate`, `creatordate`, `taggerdate`).
+All other fields are used to sort in their byte-value order.
+
+There is also an option to sort by versions, this can be done by using
+the fieldname `version:refname` or its alias `v:refname`.
+
+In any case, a field name that refers to a field inapplicable to
+the object referred by the ref does not cause an error.  It
+returns an empty string instead.
+
+As a special case for the date-type fields, you may specify a format for the
+date by adding `:` followed by date format name (see the values the `--date`
+option to linkgit:git-rev-list[1] takes). If this formatting is provided in
+a `--sort` key, references will be sorted according to the byte-value of the
+formatted string rather than the numeric value of the underlying timestamp.
+
+Some atoms like %(align) and %(if) always require a matching %(end).
+We call them "opening atoms" and sometimes denote them as %($open).
+
+When a scripting language specific quoting is in effect, everything
+between a top-level opening atom and its matching %(end) is evaluated
+according to the semantics of the opening atom and only its result
+from the top-level is quoted.
+
+
+EXAMPLES
+--------
+
+An example directly producing formatted text.  Show the most recent
+3 tagged commits:
+
+------------
+#!/bin/sh
+
+git for-each-ref --count=3 --sort='-*authordate' \
+--format='From: %(*authorname) %(*authoremail)
+Subject: %(*subject)
+Date: %(*authordate)
+Ref: %(*refname)
+
+%(*body)
+' 'refs/tags'
+------------
+
+
+A simple example showing the use of shell eval on the output,
+demonstrating the use of --shell.  List the prefixes of all heads:
+------------
+#!/bin/sh
+
+git for-each-ref --shell --format="ref=%(refname)" refs/heads | \
+while read entry
+do
+	eval "$entry"
+	echo `dirname $ref`
+done
+------------
+
+
+A bit more elaborate report on tags, demonstrating that the format
+may be an entire script:
+------------
+#!/bin/sh
+
+fmt='
+	r=%(refname)
+	t=%(*objecttype)
+	T=${r#refs/tags/}
+
+	o=%(*objectname)
+	n=%(*authorname)
+	e=%(*authoremail)
+	s=%(*subject)
+	d=%(*authordate)
+	b=%(*body)
+
+	kind=Tag
+	if test "z$t" = z
+	then
+		# could be a lightweight tag
+		t=%(objecttype)
+		kind="Lightweight tag"
+		o=%(objectname)
+		n=%(authorname)
+		e=%(authoremail)
+		s=%(subject)
+		d=%(authordate)
+		b=%(body)
+	fi
+	echo "$kind $T points at a $t object $o"
+	if test "z$t" = zcommit
+	then
+		echo "The commit was authored by $n $e
+at $d, and titled
+
+    $s
+
+Its message reads as:
+"
+		echo "$b" | sed -e "s/^/    /"
+		echo
+	fi
+'
+
+eval=`git for-each-ref --shell --format="$fmt" \
+	--sort='*objecttype' \
+	--sort=-taggerdate \
+	refs/tags`
+eval "$eval"
+------------
+
+
+An example to show the usage of %(if)...%(then)...%(else)...%(end).
+This prefixes the current branch with a star.
+
+------------
+git for-each-ref --format="%(if)%(HEAD)%(then)* %(else)  %(end)%(refname:short)" refs/heads/
+------------
+
+
+An example to show the usage of %(if)...%(then)...%(end).
+This prints the authorname, if present.
+
+------------
+git for-each-ref --format="%(refname)%(if)%(authorname)%(then) Authored by: %(authorname)%(end)"
+------------
+
+CAVEATS
+-------
+
+Note that the sizes of objects on disk are reported accurately, but care
+should be taken in drawing conclusions about which refs or objects are
+responsible for disk usage. The size of a packed non-delta object may be
+much larger than the size of objects which delta against it, but the
+choice of which object is the base and which is the delta is arbitrary
+and is subject to change during a repack.
+
+Note also that multiple copies of an object may be present in the object
+database; in this case, it is undefined which copy's size or delta base
+will be reported.
+
+NOTES
+-----
+
+include::ref-reachability-filters.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-show-ref[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-for-each-repo.adoc b/Documentation/git-for-each-repo.adoc
new file mode 100644
index 0000000000..abe3527aac
--- /dev/null
+++ b/Documentation/git-for-each-repo.adoc
@@ -0,0 +1,68 @@
+git-for-each-repo(1)
+====================
+
+NAME
+----
+git-for-each-repo - Run a Git command on a list of repositories
+
+
+SYNOPSIS
+--------
+[verse]
+'git for-each-repo' --config=<config> [--] <arguments>
+
+
+DESCRIPTION
+-----------
+Run a Git command on a list of repositories. The arguments after the
+known options or `--` indicator are used as the arguments for the Git
+subprocess.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+For example, we could run maintenance on each of a list of repositories
+stored in a `maintenance.repo` config variable using
+
+-------------
+git for-each-repo --config=maintenance.repo maintenance run
+-------------
+
+This will run `git -C <repo> maintenance run` for each value `<repo>`
+in the multi-valued config variable `maintenance.repo`.
+
+
+OPTIONS
+-------
+--config=<config>::
+	Use the given config variable as a multi-valued list storing
+	absolute path names. Iterate on that list of paths to run
+	the given arguments.
++
+These config values are loaded from system, global, and local Git config,
+as available. If `git for-each-repo` is run in a directory that is not a
+Git repository, then only the system and global config is used.
+
+--keep-going::
+	Continue with the remaining repositories if the command failed
+	on a repository. The exit code will still indicate that the
+	overall operation was not successful.
++
+Note that the exact exit code of the failing command is not passed
+through as the exit code of the `for-each-repo` command: If the command
+failed in any of the specified repositories, the overall exit code will
+be 1.
+
+SUBPROCESS BEHAVIOR
+-------------------
+
+If any `git -C <repo> <arguments>` subprocess returns a non-zero exit code,
+then the `git for-each-repo` process returns that exit code without running
+more subprocesses.
+
+Each `git -C <repo> <arguments>` subprocess inherits the standard file
+descriptors `stdin`, `stdout`, and `stderr`.
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc
new file mode 100644
index 0000000000..a8b53db9a6
--- /dev/null
+++ b/Documentation/git-format-patch.adoc
@@ -0,0 +1,797 @@
+git-format-patch(1)
+===================
+
+NAME
+----
+git-format-patch - Prepare patches for e-mail submission
+
+
+SYNOPSIS
+--------
+[verse]
+'git format-patch' [-k] [(-o|--output-directory) <dir> | --stdout]
+		   [--no-thread | --thread[=<style>]]
+		   [(--attach|--inline)[=<boundary>] | --no-attach]
+		   [-s | --signoff]
+		   [--signature=<signature> | --no-signature]
+		   [--signature-file=<file>]
+		   [-n | --numbered | -N | --no-numbered]
+		   [--start-number <n>] [--numbered-files]
+		   [--in-reply-to=<message-id>] [--suffix=.<sfx>]
+		   [--ignore-if-in-upstream] [--always]
+		   [--cover-from-description=<mode>]
+		   [--rfc[=<rfc>]] [--subject-prefix=<subject-prefix>]
+		   [(--reroll-count|-v) <n>]
+		   [--to=<email>] [--cc=<email>]
+		   [--[no-]cover-letter] [--quiet]
+		   [--[no-]encode-email-headers]
+		   [--no-notes | --notes[=<ref>]]
+		   [--interdiff=<previous>]
+		   [--range-diff=<previous> [--creation-factor=<percent>]]
+		   [--filename-max-length=<n>]
+		   [--progress]
+		   [<common-diff-options>]
+		   [ <since> | <revision-range> ]
+
+DESCRIPTION
+-----------
+
+Prepare each non-merge commit with its "patch" in
+one "message" per commit, formatted to resemble a UNIX mailbox.
+The output of this command is convenient for e-mail submission or
+for use with 'git am'.
+
+A "message" generated by the command consists of three parts:
+
+* A brief metadata header that begins with `From <commit>`
+  with a fixed `Mon Sep 17 00:00:00 2001` datestamp to help programs
+  like "file(1)" to recognize that the file is an output from this
+  command, fields that record the author identity, the author date,
+  and the title of the change (taken from the first paragraph of the
+  commit log message).
+
+* The second and subsequent paragraphs of the commit log message.
+
+* The "patch", which is the "diff -p --stat" output (see
+  linkgit:git-diff[1]) between the commit and its parent.
+
+The log message and the patch are separated by a line with a
+three-dash line.
+
+There are two ways to specify which commits to operate on.
+
+1. A single commit, <since>, specifies that the commits leading
+   to the tip of the current branch that are not in the history
+   that leads to the <since> to be output.
+
+2. Generic <revision-range> expression (see "SPECIFYING
+   REVISIONS" section in linkgit:gitrevisions[7]) means the
+   commits in the specified range.
+
+The first rule takes precedence in the case of a single <commit>.  To
+apply the second rule, i.e., format everything since the beginning of
+history up until <commit>, use the `--root` option: `git format-patch
+--root <commit>`.  If you want to format only <commit> itself, you
+can do this with `git format-patch -1 <commit>`.
+
+By default, each output file is numbered sequentially from 1, and uses the
+first line of the commit message (massaged for pathname safety) as
+the filename. With the `--numbered-files` option, the output file names
+will only be numbers, without the first line of the commit appended.
+The names of the output files are printed to standard
+output, unless the `--stdout` option is specified.
+
+If `-o` is specified, output files are created in <dir>.  Otherwise
+they are created in the current working directory. The default path
+can be set with the `format.outputDirectory` configuration option.
+The `-o` option takes precedence over `format.outputDirectory`.
+To store patches in the current working directory even when
+`format.outputDirectory` points elsewhere, use `-o .`. All directory
+components will be created.
+
+By default, the subject of a single patch is "[PATCH] " followed by
+the concatenation of lines from the commit message up to the first blank
+line (see the DISCUSSION section of linkgit:git-commit[1]).
+
+When multiple patches are output, the subject prefix will instead be
+"[PATCH n/m] ".  To force 1/1 to be added for a single patch, use `-n`.
+To omit patch numbers from the subject, use `-N`.
+
+If given `--thread`, `git-format-patch` will generate `In-Reply-To` and
+`References` headers to make the second and subsequent patch mails appear
+as replies to the first mail; this also generates a `Message-ID` header to
+reference.
+
+OPTIONS
+-------
+:git-format-patch: 1
+include::diff-options.adoc[]
+
+-<n>::
+	Prepare patches from the topmost <n> commits.
+
+-o <dir>::
+--output-directory <dir>::
+	Use <dir> to store the resulting files, instead of the
+	current working directory.
+
+-n::
+--numbered::
+	Name output in '[PATCH n/m]' format, even with a single patch.
+
+-N::
+--no-numbered::
+	Name output in '[PATCH]' format.
+
+--start-number <n>::
+	Start numbering the patches at <n> instead of 1.
+
+--numbered-files::
+	Output file names will be a simple number sequence
+	without the default first line of the commit appended.
+
+-k::
+--keep-subject::
+	Do not strip/add '[PATCH]' from the first line of the
+	commit log message.
+
+-s::
+--signoff::
+	Add a `Signed-off-by` trailer to the commit message, using
+	the committer identity of yourself.
+	See the signoff option in linkgit:git-commit[1] for more information.
+
+--stdout::
+	Print all commits to the standard output in mbox format,
+	instead of creating a file for each one.
+
+--attach[=<boundary>]::
+	Create multipart/mixed attachment, the first part of
+	which is the commit message and the patch itself in the
+	second part, with `Content-Disposition: attachment`.
+
+--no-attach::
+	Disable the creation of an attachment, overriding the
+	configuration setting.
+
+--inline[=<boundary>]::
+	Create multipart/mixed attachment, the first part of
+	which is the commit message and the patch itself in the
+	second part, with `Content-Disposition: inline`.
+
+--thread[=<style>]::
+--no-thread::
+	Controls addition of `In-Reply-To` and `References` headers to
+	make the second and subsequent mails appear as replies to the
+	first.  Also controls generation of the `Message-ID` header to
+	reference.
++
+The optional <style> argument can be either `shallow` or `deep`.
+'shallow' threading makes every mail a reply to the head of the
+series, where the head is chosen from the cover letter, the
+`--in-reply-to`, and the first patch mail, in this order.  'deep'
+threading makes every mail a reply to the previous one.
++
+The default is `--no-thread`, unless the `format.thread` configuration
+is set.  `--thread` without an argument is equivalent to `--thread=shallow`.
++
+Beware that the default for 'git send-email' is to thread emails
+itself.  If you want `git format-patch` to take care of threading, you
+will want to ensure that threading is disabled for `git send-email`.
+
+--in-reply-to=<message-id>::
+	Make the first mail (or all the mails with `--no-thread`) appear as a
+	reply to the given <message-id>, which avoids breaking threads to
+	provide a new patch series.
+
+--ignore-if-in-upstream::
+	Do not include a patch that matches a commit in
+	<until>..<since>.  This will examine all patches reachable
+	from <since> but not from <until> and compare them with the
+	patches being generated, and any patch that matches is
+	ignored.
+
+--always::
+	Include patches for commits that do not introduce any change,
+	which are omitted by default.
+
+--cover-from-description=<mode>::
+	Controls which parts of the cover letter will be automatically
+	populated using the branch's description.
++
+If `<mode>` is `message` or `default`, the cover letter subject will be
+populated with placeholder text. The body of the cover letter will be
+populated with the branch's description. This is the default mode when
+no configuration nor command line option is specified.
++
+If `<mode>` is `subject`, the first paragraph of the branch description will
+populate the cover letter subject. The remainder of the description will
+populate the body of the cover letter.
++
+If `<mode>` is `auto`, if the first paragraph of the branch description
+is greater than 100 bytes, then the mode will be `message`, otherwise
+`subject` will be used.
++
+If `<mode>` is `none`, both the cover letter subject and body will be
+populated with placeholder text.
+
+--description-file=<file>::
+	Use the contents of <file> instead of the branch's description
+	for generating the cover letter.
+
+--subject-prefix=<subject-prefix>::
+	Instead of the standard '[PATCH]' prefix in the subject
+	line, instead use '[<subject-prefix>]'. This can be used
+	to name a patch series, and can be combined with the
+	`--numbered` option.
++
+The configuration variable `format.subjectPrefix` may also be used
+to configure a subject prefix to apply to a given repository for
+all patches. This is often useful on mailing lists which receive
+patches for several repositories and can be used to disambiguate
+the patches (with a value of e.g. "PATCH my-project").
+
+--filename-max-length=<n>::
+	Instead of the standard 64 bytes, chomp the generated output
+	filenames at around '<n>' bytes (too short a value will be
+	silently raised to a reasonable length).  Defaults to the
+	value of the `format.filenameMaxLength` configuration
+	variable, or 64 if unconfigured.
+
+--rfc[=<rfc>]::
+	Prepends the string _<rfc>_ (defaults to "RFC") to
+	the subject prefix.  As the subject prefix defaults to
+	"PATCH", you'll get "RFC PATCH" by default.
++
+RFC means "Request For Comments"; use this when sending
+an experimental patch for discussion rather than application.
+"--rfc=WIP" may also be a useful way to indicate that a patch
+is not complete yet ("WIP" stands for "Work In Progress").
++
+If the convention of the receiving community for a particular extra
+string is to have it _after_ the subject prefix, the string _<rfc>_
+can be prefixed with a dash ("`-`") to signal that the rest of
+the _<rfc>_ string should be appended to the subject prefix instead,
+e.g., `--rfc='-(WIP)'` results in "PATCH (WIP)".
+
+-v <n>::
+--reroll-count=<n>::
+	Mark the series as the <n>-th iteration of the topic. The
+	output filenames have `v<n>` prepended to them, and the
+	subject prefix ("PATCH" by default, but configurable via the
+	`--subject-prefix` option) has ` v<n>` appended to it.  E.g.
+	`--reroll-count=4` may produce `v4-0001-add-makefile.patch`
+	file that has "Subject: [PATCH v4 1/20] Add makefile" in it.
+	`<n>` does not have to be an integer (e.g. "--reroll-count=4.4",
+	or "--reroll-count=4rev2" are allowed), but the downside of
+	using such a reroll-count is that the range-diff/interdiff
+	with the previous version does not state exactly which
+	version the new iteration is compared against.
+
+--to=<email>::
+	Add a `To:` header to the email headers. This is in addition
+	to any configured headers, and may be used multiple times.
+	The negated form `--no-to` discards all `To:` headers added so
+	far (from config or command line).
+
+--cc=<email>::
+	Add a `Cc:` header to the email headers. This is in addition
+	to any configured headers, and may be used multiple times.
+	The negated form `--no-cc` discards all `Cc:` headers added so
+	far (from config or command line).
+
+--from::
+--from=<ident>::
+	Use `ident` in the `From:` header of each commit email. If the
+	author ident of the commit is not textually identical to the
+	provided `ident`, place a `From:` header in the body of the
+	message with the original author. If no `ident` is given, use
+	the committer ident.
++
+Note that this option is only useful if you are actually sending the
+emails and want to identify yourself as the sender, but retain the
+original author (and `git am` will correctly pick up the in-body
+header). Note also that `git send-email` already handles this
+transformation for you, and this option should not be used if you are
+feeding the result to `git send-email`.
+
+--[no-]force-in-body-from::
+	With the e-mail sender specified via the `--from` option, by
+	default, an in-body "From:" to identify the real author of
+	the commit is added at the top of the commit log message if
+	the sender is different from the author.  With this option,
+	the in-body "From:" is added even when the sender and the
+	author have the same name and address, which may help if the
+	mailing list software mangles the sender's identity.
+	Defaults to the value of the `format.forceInBodyFrom`
+	configuration variable.
+
+--add-header=<header>::
+	Add an arbitrary header to the email headers.  This is in addition
+	to any configured headers, and may be used multiple times.
+	For example, `--add-header="Organization: git-foo"`.
+	The negated form `--no-add-header` discards *all* (`To:`,
+	`Cc:`, and custom) headers added so far from config or command
+	line.
+
+--[no-]cover-letter::
+	In addition to the patches, generate a cover letter file
+	containing the branch description, shortlog and the overall diffstat.  You can
+	fill in a description in the file before sending it out.
+
+--encode-email-headers::
+--no-encode-email-headers::
+	Encode email headers that have non-ASCII characters with
+	"Q-encoding" (described in RFC 2047), instead of outputting the
+	headers verbatim. Defaults to the value of the
+	`format.encodeEmailHeaders` configuration variable.
+
+--interdiff=<previous>::
+	As a reviewer aid, insert an interdiff into the cover letter,
+	or as commentary of the lone patch of a 1-patch series, showing
+	the differences between the previous version of the patch series and
+	the series currently being formatted. `previous` is a single revision
+	naming the tip of the previous series which shares a common base with
+	the series being formatted (for example `git format-patch
+	--cover-letter --interdiff=feature/v1 -3 feature/v2`).
+
+--range-diff=<previous>::
+	As a reviewer aid, insert a range-diff (see linkgit:git-range-diff[1])
+	into the cover letter, or as commentary of the lone patch of a
+	1-patch series, showing the differences between the previous
+	version of the patch series and the series currently being formatted.
+	`previous` can be a single revision naming the tip of the previous
+	series if it shares a common base with the series being formatted (for
+	example `git format-patch --cover-letter --range-diff=feature/v1 -3
+	feature/v2`), or a revision range if the two versions of the series are
+	disjoint (for example `git format-patch --cover-letter
+	--range-diff=feature/v1~3..feature/v1 -3 feature/v2`).
++
+Note that diff options passed to the command affect how the primary
+product of `format-patch` is generated, and they are not passed to
+the underlying `range-diff` machinery used to generate the cover-letter
+material (this may change in the future).
+
+--creation-factor=<percent>::
+	Used with `--range-diff`, tweak the heuristic which matches up commits
+	between the previous and current series of patches by adjusting the
+	creation/deletion cost fudge factor. See linkgit:git-range-diff[1])
+	for details.
++
+Defaults to 999 (the linkgit:git-range-diff[1] uses 60), as the use
+case is to show comparison with an older iteration of the same
+topic and the tool should find more correspondence between the two
+sets of patches.
+
+--notes[=<ref>]::
+--no-notes::
+	Append the notes (see linkgit:git-notes[1]) for the commit
+	after the three-dash line.
++
+The expected use case of this is to write supporting explanation for
+the commit that does not belong to the commit log message proper,
+and include it with the patch submission. While one can simply write
+these explanations after `format-patch` has run but before sending,
+keeping them as Git notes allows them to be maintained between versions
+of the patch series (but see the discussion of the `notes.rewrite`
+configuration options in linkgit:git-notes[1] to use this workflow).
++
+The default is `--no-notes`, unless the `format.notes` configuration is
+set.
+
+--[no-]signature=<signature>::
+	Add a signature to each message produced. Per RFC 3676 the signature
+	is separated from the body by a line with '-- ' on it. If the
+	signature option is omitted the signature defaults to the Git version
+	number.
+
+--signature-file=<file>::
+	Works just like --signature except the signature is read from a file.
+
+--suffix=.<sfx>::
+	Instead of using `.patch` as the suffix for generated
+	filenames, use specified suffix.  A common alternative is
+	`--suffix=.txt`.  Leaving this empty will remove the `.patch`
+	suffix.
++
+Note that the leading character does not have to be a dot; for example,
+you can use `--suffix=-patch` to get `0001-description-of-my-change-patch`.
+
+-q::
+--quiet::
+	Do not print the names of the generated files to standard output.
+
+--no-binary::
+	Do not output contents of changes in binary files, instead
+	display a notice that those files changed.  Patches generated
+	using this option cannot be applied properly, but they are
+	still useful for code review.
+
+--zero-commit::
+  Output an all-zero hash in each patch's From header instead
+  of the hash of the commit.
+
+--[no-]base[=<commit>]::
+	Record the base tree information to identify the state the
+	patch series applies to.  See the BASE TREE INFORMATION section
+	below for details. If <commit> is "auto", a base commit is
+	automatically chosen. The `--no-base` option overrides a
+	`format.useAutoBase` configuration.
+
+--root::
+	Treat the revision argument as a <revision-range>, even if it
+	is just a single commit (that would normally be treated as a
+	<since>).  Note that root commits included in the specified
+	range are always formatted as creation patches, independently
+	of this flag.
+
+--progress::
+	Show progress reports on stderr as patches are generated.
+
+CONFIGURATION
+-------------
+You can specify extra mail header lines to be added to each message,
+defaults for the subject prefix and file suffix, number patches when
+outputting more than one patch, add "To:" or "Cc:" headers, configure
+attachments, change the patch output directory, and sign off patches
+with configuration variables.
+
+------------
+[format]
+	headers = "Organization: git-foo\n"
+	subjectPrefix = CHANGE
+	suffix = .txt
+	numbered = auto
+	to = <email>
+	cc = <email>
+	attach [ = mime-boundary-string ]
+	signOff = true
+	outputDirectory = <directory>
+	coverLetter = auto
+	coverFromDescription = auto
+------------
+
+
+DISCUSSION
+----------
+
+The patch produced by 'git format-patch' is in UNIX mailbox format,
+with a fixed "magic" time stamp to indicate that the file is output
+from format-patch rather than a real mailbox, like so:
+
+------------
+From 8f72bad1baf19a53459661343e21d6491c3908d3 Mon Sep 17 00:00:00 2001
+From: Tony Luck <tony.luck@xxxxxxxxx>
+Date: Tue, 13 Jul 2010 11:42:54 -0700
+Subject: [PATCH] =?UTF-8?q?[IA64]=20Put=20ia64=20config=20files=20on=20the=20?=
+ =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig=20diet?=
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+arch/arm config files were slimmed down using a python script
+(See commit c2330e286f68f1c408b4aa6515ba49d57f05beae comment)
+
+Do the same for ia64 so we can have sleek & trim looking
+...
+------------
+
+Typically it will be placed in a MUA's drafts folder, edited to add
+timely commentary that should not go in the changelog after the three
+dashes, and then sent as a message whose body, in our example, starts
+with "arch/arm config files were...".  On the receiving end, readers
+can save interesting patches in a UNIX mailbox and apply them with
+linkgit:git-am[1].
+
+When a patch is part of an ongoing discussion, the patch generated by
+'git format-patch' can be tweaked to take advantage of the 'git am
+--scissors' feature.  After your response to the discussion comes a
+line that consists solely of "`-- >8 --`" (scissors and perforation),
+followed by the patch with unnecessary header fields removed:
+
+------------
+...
+> So we should do such-and-such.
+
+Makes sense to me.  How about this patch?
+
+-- >8 --
+Subject: [IA64] Put ia64 config files on the Uwe Kleine-König diet
+
+arch/arm config files were slimmed down using a python script
+...
+------------
+
+When sending a patch this way, most often you are sending your own
+patch, so in addition to the "`From $SHA1 $magic_timestamp`" marker you
+should omit `From:` and `Date:` lines from the patch file.  The patch
+title is likely to be different from the subject of the discussion the
+patch is in response to, so it is likely that you would want to keep
+the Subject: line, like the example above.
+
+Checking for patch corruption
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Many mailers if not set up properly will corrupt whitespace.  Here are
+two common types of corruption:
+
+* Empty context lines that do not have _any_ whitespace.
+
+* Non-empty context lines that have one extra whitespace at the
+  beginning.
+
+One way to test if your MUA is set up correctly is:
+
+* Send the patch to yourself, exactly the way you would, except
+  with To: and Cc: lines that do not contain the list and
+  maintainer address.
+
+* Save that patch to a file in UNIX mailbox format.  Call it a.patch,
+  say.
+
+* Apply it:
+
+    $ git fetch <project> master:test-apply
+    $ git switch test-apply
+    $ git restore --source=HEAD --staged --worktree :/
+    $ git am a.patch
+
+If it does not apply correctly, there can be various reasons.
+
+* The patch itself does not apply cleanly.  That is _bad_ but
+  does not have much to do with your MUA.  You might want to rebase
+  the patch with linkgit:git-rebase[1] before regenerating it in
+  this case.
+
+* The MUA corrupted your patch; "am" would complain that
+  the patch does not apply.  Look in the .git/rebase-apply/ subdirectory and
+  see what 'patch' file contains and check for the common
+  corruption patterns mentioned above.
+
+* While at it, check the 'info' and 'final-commit' files as well.
+  If what is in 'final-commit' is not exactly what you would want to
+  see in the commit log message, it is very likely that the
+  receiver would end up hand editing the log message when applying
+  your patch.  Things like "Hi, this is my first patch.\n" in the
+  patch e-mail should come after the three-dash line that signals
+  the end of the commit message.
+
+MUA-SPECIFIC HINTS
+------------------
+Here are some hints on how to successfully submit patches inline using
+various mailers.
+
+GMail
+~~~~~
+GMail does not have any way to turn off line wrapping in the web
+interface, so it will mangle any emails that you send.  You can however
+use "git send-email" and send your patches through the GMail SMTP server, or
+use any IMAP email client to connect to the google IMAP server and forward
+the emails through that.
+
+For hints on using 'git send-email' to send your patches through the
+GMail SMTP server, see the EXAMPLE section of linkgit:git-send-email[1].
+
+For hints on submission using the IMAP interface, see the EXAMPLE
+section of linkgit:git-imap-send[1].
+
+Thunderbird
+~~~~~~~~~~~
+By default, Thunderbird will both wrap emails as well as flag
+them as being 'format=flowed', both of which will make the
+resulting email unusable by Git.
+
+There are three different approaches: use an add-on to turn off line wraps,
+configure Thunderbird to not mangle patches, or use
+an external editor to keep Thunderbird from mangling the patches.
+
+Approach #1 (add-on)
+^^^^^^^^^^^^^^^^^^^^
+
+Install the Toggle Word Wrap add-on that is available from
+https://addons.mozilla.org/thunderbird/addon/toggle-word-wrap/
+It adds a menu entry "Enable Word Wrap" in the composer's "Options" menu
+that you can tick off. Now you can compose the message as you otherwise do
+(cut + paste, 'git format-patch' | 'git imap-send', etc), but you have to
+insert line breaks manually in any text that you type.
+
+Approach #2 (configuration)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Three steps:
+
+1. Configure your mail server composition as plain text:
+   Edit...Account Settings...Composition & Addressing,
+   uncheck "Compose Messages in HTML".
+
+2. Configure your general composition window to not wrap.
++
+In Thunderbird 2:
+Edit..Preferences..Composition, wrap plain text messages at 0
++
+In Thunderbird 3:
+Edit..Preferences..Advanced..Config Editor.  Search for
+"mail.wrap_long_lines".
+Toggle it to make sure it is set to `false`. Also, search for
+"mailnews.wraplength" and set the value to 0.
+
+3. Disable the use of format=flowed:
+   Edit..Preferences..Advanced..Config Editor.  Search for
+   "mailnews.send_plaintext_flowed".
+   Toggle it to make sure it is set to `false`.
+
+After that is done, you should be able to compose email as you
+otherwise would (cut + paste, 'git format-patch' | 'git imap-send', etc),
+and the patches will not be mangled.
+
+Approach #3 (external editor)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following Thunderbird extensions are needed:
+AboutConfig from https://mjg.github.io/AboutConfig/ and
+External Editor from https://globs.org/articles.php?lng=en&pg=8
+
+1. Prepare the patch as a text file using your method of choice.
+
+2. Before opening a compose window, use Edit->Account Settings to
+   uncheck the "Compose messages in HTML format" setting in the
+   "Composition & Addressing" panel of the account to be used to
+   send the patch.
+
+3. In the main Thunderbird window, 'before' you open the compose
+   window for the patch, use Tools->about:config to set the
+   following to the indicated values:
++
+----------
+	mailnews.send_plaintext_flowed  => false
+	mailnews.wraplength             => 0
+----------
+
+4. Open a compose window and click the external editor icon.
+
+5. In the external editor window, read in the patch file and exit
+   the editor normally.
+
+Side note: it may be possible to do step 2 with
+about:config and the following settings but no one's tried yet.
+
+----------
+	mail.html_compose                       => false
+	mail.identity.default.compose_html      => false
+	mail.identity.id?.compose_html          => false
+----------
+
+There is a script in contrib/thunderbird-patch-inline which can help
+you include patches with Thunderbird in an easy way. To use it, do the
+steps above and then use the script as the external editor.
+
+KMail
+~~~~~
+This should help you to submit patches inline using KMail.
+
+1. Prepare the patch as a text file.
+
+2. Click on New Mail.
+
+3. Go under "Options" in the Composer window and be sure that
+   "Word wrap" is not set.
+
+4. Use Message -> Insert file... and insert the patch.
+
+5. Back in the compose window: add whatever other text you wish to the
+   message, complete the addressing and subject fields, and press send.
+
+BASE TREE INFORMATION
+---------------------
+
+The base tree information block is used for maintainers or third party
+testers to know the exact state the patch series applies to. It consists
+of the 'base commit', which is a well-known commit that is part of the
+stable part of the project history everybody else works off of, and zero
+or more 'prerequisite patches', which are well-known patches in flight
+that is not yet part of the 'base commit' that need to be applied on top
+of 'base commit' in topological order before the patches can be applied.
+
+The 'base commit' is shown as "base-commit: " followed by the 40-hex of
+the commit object name.  A 'prerequisite patch' is shown as
+"prerequisite-patch-id: " followed by the 40-hex 'patch id', which can
+be obtained by passing the patch through the `git patch-id --stable`
+command.
+
+Imagine that on top of the public commit P, you applied well-known
+patches X, Y and Z from somebody else, and then built your three-patch
+series A, B, C, the history would be like:
+
+................................................
+---P---X---Y---Z---A---B---C
+................................................
+
+With `git format-patch --base=P -3 C` (or variants thereof, e.g. with
+`--cover-letter` or using `Z..C` instead of `-3 C` to specify the
+range), the base tree information block is shown at the end of the
+first message the command outputs (either the first patch, or the
+cover letter), like this:
+
+------------
+base-commit: P
+prerequisite-patch-id: X
+prerequisite-patch-id: Y
+prerequisite-patch-id: Z
+------------
+
+For non-linear topology, such as
+
+................................................
+---P---X---A---M---C
+    \         /
+     Y---Z---B
+................................................
+
+You can also use `git format-patch --base=P -3 C` to generate patches
+for A, B and C, and the identifiers for P, X, Y, Z are appended at the
+end of the first message.
+
+If set `--base=auto` in cmdline, it will automatically compute
+the base commit as the merge base of tip commit of the remote-tracking
+branch and revision-range specified in cmdline.
+For a local branch, you need to make it to track a remote branch by `git branch
+--set-upstream-to` before using this option.
+
+EXAMPLES
+--------
+
+* Extract commits between revisions R1 and R2, and apply them on top of
+  the current branch using 'git am' to cherry-pick them:
++
+------------
+$ git format-patch -k --stdout R1..R2 | git am -3 -k
+------------
+
+* Extract all commits which are in the current branch but not in the
+  origin branch:
++
+------------
+$ git format-patch origin
+------------
++
+For each commit a separate file is created in the current directory.
+
+* Extract all commits that lead to 'origin' since the inception of the
+  project:
++
+------------
+$ git format-patch --root origin
+------------
+
+* The same as the previous one:
++
+------------
+$ git format-patch -M -B origin
+------------
++
+Additionally, it detects and handles renames and complete rewrites
+intelligently to produce a renaming patch.  A renaming patch reduces
+the amount of text output, and generally makes it easier to review.
+Note that non-Git "patch" programs won't understand renaming patches, so
+use it only when you know the recipient uses Git to apply your patch.
+
+* Extract three topmost commits from the current branch and format them
+  as e-mailable patches:
++
+------------
+$ git format-patch -3
+------------
+
+CAVEATS
+-------
+
+Note that `format-patch` will omit merge commits from the output, even
+if they are part of the requested range. A simple "patch" does not
+include enough information for the receiving end to reproduce the same
+merge commit.
+
+SEE ALSO
+--------
+linkgit:git-am[1], linkgit:git-send-email[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fsck-objects.adoc b/Documentation/git-fsck-objects.adoc
new file mode 100644
index 0000000000..eec4bdb600
--- /dev/null
+++ b/Documentation/git-fsck-objects.adoc
@@ -0,0 +1,22 @@
+git-fsck-objects(1)
+===================
+
+NAME
+----
+git-fsck-objects - Verifies the connectivity and validity of the objects in the database
+
+
+SYNOPSIS
+--------
+[verse]
+'git fsck-objects' ...
+
+DESCRIPTION
+-----------
+
+This is a synonym for linkgit:git-fsck[1].  Please refer to the
+documentation of that command.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fsck.adoc b/Documentation/git-fsck.adoc
new file mode 100644
index 0000000000..fc164e32da
--- /dev/null
+++ b/Documentation/git-fsck.adoc
@@ -0,0 +1,181 @@
+git-fsck(1)
+===========
+
+NAME
+----
+git-fsck - Verifies the connectivity and validity of the objects in the database
+
+
+SYNOPSIS
+--------
+[verse]
+'git fsck' [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]
+	 [--[no-]full] [--strict] [--verbose] [--lost-found]
+	 [--[no-]dangling] [--[no-]progress] [--connectivity-only]
+	 [--[no-]name-objects] [<object>...]
+
+DESCRIPTION
+-----------
+Verifies the connectivity and validity of the objects in the database.
+
+OPTIONS
+-------
+<object>::
+	An object to treat as the head of an unreachability trace.
++
+If no objects are given, 'git fsck' defaults to using the
+index file, all SHA-1 references in the `refs` namespace, and all reflogs
+(unless --no-reflogs is given) as heads.
+
+--unreachable::
+	Print out objects that exist but that aren't reachable from any
+	of the reference nodes.
+
+--[no-]dangling::
+	Print objects that exist but that are never 'directly' used (default).
+	`--no-dangling` can be used to omit this information from the output.
+
+--root::
+	Report root nodes.
+
+--tags::
+	Report tags.
+
+--cache::
+	Consider any object recorded in the index also as a head node for
+	an unreachability trace.
+
+--no-reflogs::
+	Do not consider commits that are referenced only by an
+	entry in a reflog to be reachable.  This option is meant
+	only to search for commits that used to be in a ref, but
+	now aren't, but are still in that corresponding reflog.
+
+--full::
+	Check not just objects in GIT_OBJECT_DIRECTORY
+	($GIT_DIR/objects), but also the ones found in alternate
+	object pools listed in GIT_ALTERNATE_OBJECT_DIRECTORIES
+	or $GIT_DIR/objects/info/alternates,
+	and in packed Git archives found in $GIT_DIR/objects/pack
+	and corresponding pack subdirectories in alternate
+	object pools.  This is now default; you can turn it off
+	with --no-full.
+
+--connectivity-only::
+	Check only the connectivity of reachable objects, making sure
+	that any objects referenced by a reachable tag, commit, or tree
+	are present. This speeds up the operation by avoiding reading
+	blobs entirely (though it does still check that referenced blobs
+	exist). This will detect corruption in commits and trees, but
+	not do any semantic checks (e.g., for format errors). Corruption
+	in blob objects will not be detected at all.
++
+Unreachable tags, commits, and trees will also be accessed to find the
+tips of dangling segments of history. Use `--no-dangling` if you don't
+care about this output and want to speed it up further.
+
+--strict::
+	Enable more strict checking, namely to catch a file mode
+	recorded with g+w bit set, which was created by older
+	versions of Git.  Existing repositories, including the
+	Linux kernel, Git itself, and sparse repository have old
+	objects that trigger this check, but it is recommended
+	to check new projects with this flag.
+
+--verbose::
+	Be chatty.
+
+--lost-found::
+	Write dangling objects into .git/lost-found/commit/ or
+	.git/lost-found/other/, depending on type.  If the object is
+	a blob, the contents are written into the file, rather than
+	its object name.
+
+--name-objects::
+	When displaying names of reachable objects, in addition to the
+	SHA-1 also display a name that describes *how* they are reachable,
+	compatible with linkgit:git-rev-parse[1], e.g.
+	`HEAD@{1234567890}~25^2:src/`.
+
+--[no-]progress::
+	Progress status is reported on the standard error stream by
+	default when it is attached to a terminal, unless
+	--no-progress or --verbose is specified. --progress forces
+	progress status even if the standard error stream is not
+	directed to a terminal.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fsck.adoc[]
+
+DISCUSSION
+----------
+
+git-fsck tests SHA-1 and general object sanity, and it does full tracking
+of the resulting reachability and everything else. It prints out any
+corruption it finds (missing or bad objects), and if you use the
+`--unreachable` flag it will also print out objects that exist but that
+aren't reachable from any of the specified head nodes (or the default
+set, as mentioned above).
+
+Any corrupt objects you will have to find in backups or other archives
+(i.e., you can just remove them and do an 'rsync' with some other site in
+the hopes that somebody else has the object you have corrupted).
+
+If core.commitGraph is true, the commit-graph file will also be inspected
+using 'git commit-graph verify'. See linkgit:git-commit-graph[1].
+
+Extracted Diagnostics
+---------------------
+
+unreachable <type> <object>::
+	The <type> object <object>, isn't actually referred to directly
+	or indirectly in any of the trees or commits seen. This can
+	mean that there's another root node that you're not specifying
+	or that the tree is corrupt. If you haven't missed a root node
+	then you might as well delete unreachable nodes since they
+	can't be used.
+
+missing <type> <object>::
+	The <type> object <object>, is referred to but isn't present in
+	the database.
+
+dangling <type> <object>::
+	The <type> object <object>, is present in the database but never
+	'directly' used. A dangling commit could be a root node.
+
+hash mismatch <object>::
+	The database has an object whose hash doesn't match the
+	object database value.
+	This indicates a serious data integrity problem.
+
+
+FSCK MESSAGES
+-------------
+
+The following lists the types of errors `git fsck` detects and what
+each error means, with their default severity.  The severity of the
+error, other than those that are marked as "(FATAL)", can be tweaked
+by setting the corresponding `fsck.<msg-id>` configuration variable.
+
+include::fsck-msgids.adoc[]
+
+
+Environment Variables
+---------------------
+
+GIT_OBJECT_DIRECTORY::
+	used to specify the object database root (usually $GIT_DIR/objects)
+
+GIT_INDEX_FILE::
+	used to specify the index file of the index
+
+GIT_ALTERNATE_OBJECT_DIRECTORIES::
+	used to specify additional object database roots (usually unset)
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-fsmonitor--daemon.adoc b/Documentation/git-fsmonitor--daemon.adoc
new file mode 100644
index 0000000000..b480d73049
--- /dev/null
+++ b/Documentation/git-fsmonitor--daemon.adoc
@@ -0,0 +1,106 @@
+git-fsmonitor{litdd}daemon(1)
+=============================
+
+NAME
+----
+git-fsmonitor--daemon - A Built-in Filesystem Monitor
+
+SYNOPSIS
+--------
+[verse]
+'git fsmonitor{litdd}daemon' start
+'git fsmonitor{litdd}daemon' run
+'git fsmonitor{litdd}daemon' stop
+'git fsmonitor{litdd}daemon' status
+
+DESCRIPTION
+-----------
+
+A daemon to watch the working directory for file and directory
+changes using platform-specific filesystem notification facilities.
+
+This daemon communicates directly with commands like `git status`
+using the link:technical/api-simple-ipc.html[simple IPC] interface
+instead of the slower linkgit:githooks[5] interface.
+
+This daemon is built into Git so that no third-party tools are
+required.
+
+OPTIONS
+-------
+
+start::
+	Starts a daemon in the background.
+
+run::
+	Runs a daemon in the foreground.
+
+stop::
+	Stops the daemon running in the current working
+	directory, if present.
+
+status::
+	Exits with zero status if a daemon is watching the
+	current working directory.
+
+REMARKS
+-------
+
+This daemon is a long running process used to watch a single working
+directory and maintain a list of the recently changed files and
+directories.  Performance of commands such as `git status` can be
+increased if they just ask for a summary of changes to the working
+directory and can avoid scanning the disk.
+
+When `core.fsmonitor` is set to `true` (see linkgit:git-config[1])
+commands, such as `git status`, will ask the daemon for changes and
+automatically start it (if necessary).
+
+For more information see the "File System Monitor" section in
+linkgit:git-update-index[1].
+
+CAVEATS
+-------
+
+The fsmonitor daemon does not currently know about submodules and does
+not know to filter out filesystem events that happen within a
+submodule.  If fsmonitor daemon is watching a super repo and a file is
+modified within the working directory of a submodule, it will report
+the change (as happening against the super repo).  However, the client
+will properly ignore these extra events, so performance may be affected
+but it will not cause an incorrect result.
+
+By default, the fsmonitor daemon refuses to work with network-mounted
+repositories; this may be overridden by setting `fsmonitor.allowRemote` to
+`true`. Note, however, that the fsmonitor daemon is not guaranteed to work
+correctly with all network-mounted repositories, so such use is considered
+experimental.
+
+On Mac OS, the inter-process communication (IPC) between various Git
+commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a
+special type of file -- which is supported by native Mac OS filesystems,
+but not on network-mounted filesystems, NTFS, or FAT32.  Other filesystems
+may or may not have the needed support; the fsmonitor daemon is not guaranteed
+to work with these filesystems and such use is considered experimental.
+
+By default, the socket is created in the `.git` directory.  However, if the
+`.git` directory is on a network-mounted filesystem, it will instead be
+created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a
+network-mounted filesystem, in which case you must set the configuration
+variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native
+filesystem in which to create the socket file.
+
+If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`)
+is on a native Mac OS file filesystem the fsmonitor daemon will report an
+error that will cause the daemon and the currently running command to exit.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/fsmonitor--daemon.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-gc.adoc b/Documentation/git-gc.adoc
new file mode 100644
index 0000000000..ff25c74125
--- /dev/null
+++ b/Documentation/git-gc.adoc
@@ -0,0 +1,178 @@
+git-gc(1)
+=========
+
+NAME
+----
+git-gc - Cleanup unnecessary files and optimize the local repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git gc' [--aggressive] [--auto] [--[no-]detach] [--quiet] [--prune=<date> | --no-prune] [--force] [--keep-largest-pack]
+
+DESCRIPTION
+-----------
+Runs a number of housekeeping tasks within the current repository,
+such as compressing file revisions (to reduce disk space and increase
+performance), removing unreachable objects which may have been
+created from prior invocations of 'git add', packing refs, pruning
+reflog, rerere metadata or stale working trees. May also update ancillary
+indexes such as the commit-graph.
+
+When common porcelain operations that create objects are run, they
+will check whether the repository has grown substantially since the
+last maintenance, and if so run `git gc` automatically. See `gc.auto`
+below for how to disable this behavior.
+
+Running `git gc` manually should only be needed when adding objects to
+a repository without regularly running such porcelain commands, to do
+a one-off repository optimization, or e.g. to clean up a suboptimal
+mass-import. See the "PACKFILE OPTIMIZATION" section in
+linkgit:git-fast-import[1] for more details on the import case.
+
+OPTIONS
+-------
+
+--aggressive::
+	Usually 'git gc' runs very quickly while providing good disk
+	space utilization and performance.  This option will cause
+	'git gc' to more aggressively optimize the repository at the expense
+	of taking much more time.  The effects of this optimization are
+	mostly persistent. See the "AGGRESSIVE" section below for details.
+
+--auto::
+	With this option, 'git gc' checks whether any housekeeping is
+	required; if not, it exits without performing any work.
++
+See the `gc.auto` option in the "CONFIGURATION" section below for how
+this heuristic works.
++
+Once housekeeping is triggered by exceeding the limits of
+configuration options such as `gc.auto` and `gc.autoPackLimit`, all
+other housekeeping tasks (e.g. rerere, working trees, reflog...) will
+be performed as well.
+
+--[no-]detach::
+	Run in the background if the system supports it. This option overrides
+	the `gc.autoDetach` config.
+
+--[no-]cruft::
+	When expiring unreachable objects, pack them separately into a
+	cruft pack instead of storing them as loose objects. `--cruft`
+	is on by default.
+
+--max-cruft-size=<n>::
+	When packing unreachable objects into a cruft pack, limit the
+	size of new cruft packs to be at most `<n>` bytes. Overrides any
+	value specified via the `gc.maxCruftSize` configuration. See
+	the `--max-cruft-size` option of linkgit:git-repack[1] for
+	more.
+
+--prune=<date>::
+	Prune loose objects older than date (default is 2 weeks ago,
+	overridable by the config variable `gc.pruneExpire`).
+	--prune=now prunes loose objects regardless of their age and
+	increases the risk of corruption if another process is writing to
+	the repository concurrently; see "NOTES" below. --prune is on by
+	default.
+
+--no-prune::
+	Do not prune any loose objects.
+
+--quiet::
+	Suppress all progress reports.
+
+--force::
+	Force `git gc` to run even if there may be another `git gc`
+	instance running on this repository.
+
+--keep-largest-pack::
+	All packs except the largest non-cruft pack, any packs marked
+	with a `.keep` file, and any cruft pack(s) are consolidated into
+	a single pack. When this option is used, `gc.bigPackThreshold`
+	is ignored.
+
+AGGRESSIVE
+----------
+
+When the `--aggressive` option is supplied, linkgit:git-repack[1] will
+be invoked with the `-f` flag, which in turn will pass
+`--no-reuse-delta` to linkgit:git-pack-objects[1]. This will throw
+away any existing deltas and re-compute them, at the expense of
+spending much more time on the repacking.
+
+The effects of this are mostly persistent, e.g. when packs and loose
+objects are coalesced into one another pack the existing deltas in
+that pack might get re-used, but there are also various cases where we
+might pick a sub-optimal delta from a newer pack instead.
+
+Furthermore, supplying `--aggressive` will tweak the `--depth` and
+`--window` options passed to linkgit:git-repack[1]. See the
+`gc.aggressiveDepth` and `gc.aggressiveWindow` settings below. By
+using a larger window size we're more likely to find more optimal
+deltas.
+
+It's probably not worth it to use this option on a given repository
+without running tailored performance benchmarks on it. It takes a lot
+more time, and the resulting space/delta optimization may or may not
+be worth it. Not using this at all is the right trade-off for most
+users and their repositories.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/gc.adoc[]
+
+NOTES
+-----
+
+'git gc' tries very hard not to delete objects that are referenced
+anywhere in your repository. In particular, it will keep not only
+objects referenced by your current set of branches and tags, but also
+objects referenced by the index, remote-tracking branches, reflogs
+(which may reference commits in branches that were later amended or
+rewound), and anything else in the refs/* namespace. Note that a note
+(of the kind created by 'git notes') attached to an object does not
+contribute in keeping the object alive. If you are expecting some
+objects to be deleted and they aren't, check all of those locations
+and decide whether it makes sense in your case to remove those
+references.
+
+On the other hand, when 'git gc' runs concurrently with another process,
+there is a risk of it deleting an object that the other process is using
+but hasn't created a reference to. This may just cause the other process
+to fail or may corrupt the repository if the other process later adds a
+reference to the deleted object. Git has two features that significantly
+mitigate this problem:
+
+. Any object with modification time newer than the `--prune` date is kept,
+  along with everything reachable from it.
+
+. Most operations that add an object to the database update the
+  modification time of the object if it is already present so that #1
+  applies.
+
+However, these features fall short of a complete solution, so users who
+run commands concurrently have to live with some risk of corruption (which
+seems to be low in practice).
+
+HOOKS
+-----
+
+The 'git gc --auto' command will run the 'pre-auto-gc' hook.  See
+linkgit:githooks[5] for more information.
+
+
+SEE ALSO
+--------
+linkgit:git-prune[1]
+linkgit:git-reflog[1]
+linkgit:git-repack[1]
+linkgit:git-rerere[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-get-tar-commit-id.adoc b/Documentation/git-get-tar-commit-id.adoc
new file mode 100644
index 0000000000..b537bb45b1
--- /dev/null
+++ b/Documentation/git-get-tar-commit-id.adoc
@@ -0,0 +1,30 @@
+git-get-tar-commit-id(1)
+========================
+
+NAME
+----
+git-get-tar-commit-id - Extract commit ID from an archive created using git-archive
+
+
+SYNOPSIS
+--------
+[verse]
+'git get-tar-commit-id'
+
+
+DESCRIPTION
+-----------
+
+Read a tar archive created by 'git archive' from the standard input
+and extract the commit ID stored in it.  It reads only the first
+1024 bytes of input, thus its runtime is not influenced by the size
+of the tar archive very much.
+
+If no commit ID is found, 'git get-tar-commit-id' quietly exits with a
+return code of 1.  This can happen if the archive had not been created
+using 'git archive' or if the first parameter of 'git archive' had been
+a tree ID instead of a commit ID or tag.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-grep.adoc b/Documentation/git-grep.adoc
new file mode 100644
index 0000000000..718a02f46d
--- /dev/null
+++ b/Documentation/git-grep.adoc
@@ -0,0 +1,360 @@
+git-grep(1)
+===========
+
+NAME
+----
+git-grep - Print lines matching a pattern
+
+
+SYNOPSIS
+--------
+[verse]
+'git grep' [-a | --text] [-I] [--textconv] [-i | --ignore-case] [-w | --word-regexp]
+	   [-v | --invert-match] [-h|-H] [--full-name]
+	   [-E | --extended-regexp] [-G | --basic-regexp]
+	   [-P | --perl-regexp]
+	   [-F | --fixed-strings] [-n | --line-number] [--column]
+	   [-l | --files-with-matches] [-L | --files-without-match]
+	   [(-O | --open-files-in-pager) [<pager>]]
+	   [-z | --null]
+	   [ -o | --only-matching ] [-c | --count] [--all-match] [-q | --quiet]
+	   [--max-depth <depth>] [--[no-]recursive]
+	   [--color[=<when>] | --no-color]
+	   [--break] [--heading] [-p | --show-function]
+	   [-A <post-context>] [-B <pre-context>] [-C <context>]
+	   [-W | --function-context]
+	   [(-m | --max-count) <num>]
+	   [--threads <num>]
+	   [-f <file>] [-e] <pattern>
+	   [--and|--or|--not|(|)|-e <pattern>...]
+	   [--recurse-submodules] [--parent-basename <basename>]
+	   [ [--[no-]exclude-standard] [--cached | --untracked | --no-index] | <tree>...]
+	   [--] [<pathspec>...]
+
+DESCRIPTION
+-----------
+Look for specified patterns in the tracked files in the work tree, blobs
+registered in the index file, or blobs in given tree objects.  Patterns
+are lists of one or more search expressions separated by newline
+characters.  An empty string as search expression matches all lines.
+
+
+OPTIONS
+-------
+--cached::
+	Instead of searching tracked files in the working tree, search
+	blobs registered in the index file.
+
+--untracked::
+	In addition to searching in the tracked files in the working
+	tree, search also in untracked files.
+
+--no-index::
+	Search files in the current directory that is not managed by Git,
+	or by ignoring that the current directory is managed by Git.  This
+	is rather similar to running the regular `grep(1)` utility with its
+	`-r` option specified, but with some additional benefits, such as
+	using pathspec patterns to limit paths;  see the 'pathspec' entry
+	in linkgit:gitglossary[7] for more information.
++
+This option cannot be used together with `--cached` or `--untracked`.
+See also `grep.fallbackToNoIndex` in 'CONFIGURATION' below.
+
+--no-exclude-standard::
+	Also search in ignored files by not honoring the `.gitignore`
+	mechanism. Only useful with `--untracked`.
+
+--exclude-standard::
+	Do not pay attention to ignored files specified via the `.gitignore`
+	mechanism.  Only useful when searching files in the current directory
+	with `--no-index`.
+
+--recurse-submodules::
+	Recursively search in each submodule that is active and
+	checked out in the repository.  When used in combination with the
+	_<tree>_ option the prefix of all submodule output will be the name of
+	the parent project's _<tree>_ object.  This option cannot be used together
+	with `--untracked`, and it has no effect if `--no-index` is specified.
+
+-a::
+--text::
+	Process binary files as if they were text.
+
+--textconv::
+	Honor textconv filter settings.
+
+--no-textconv::
+	Do not honor textconv filter settings.
+	This is the default.
+
+-i::
+--ignore-case::
+	Ignore case differences between the patterns and the
+	files.
+
+-I::
+	Don't match the pattern in binary files.
+
+--max-depth <depth>::
+	For each <pathspec> given on command line, descend at most <depth>
+	levels of directories. A value of -1 means no limit.
+	This option is ignored if <pathspec> contains active wildcards.
+	In other words if "a*" matches a directory named "a*",
+	"*" is matched literally so --max-depth is still effective.
+
+-r::
+--recursive::
+	Same as `--max-depth=-1`; this is the default.
+
+--no-recursive::
+	Same as `--max-depth=0`.
+
+-w::
+--word-regexp::
+	Match the pattern only at word boundary (either begin at the
+	beginning of a line, or preceded by a non-word character; end at
+	the end of a line or followed by a non-word character).
+
+-v::
+--invert-match::
+	Select non-matching lines.
+
+-h::
+-H::
+	By default, the command shows the filename for each
+	match.  `-h` option is used to suppress this output.
+	`-H` is there for completeness and does not do anything
+	except it overrides `-h` given earlier on the command
+	line.
+
+--full-name::
+	When run from a subdirectory, the command usually
+	outputs paths relative to the current directory.  This
+	option forces paths to be output relative to the project
+	top directory.
+
+-E::
+--extended-regexp::
+-G::
+--basic-regexp::
+	Use POSIX extended/basic regexp for patterns.  Default
+	is to use basic regexp.
+
+-P::
+--perl-regexp::
+	Use Perl-compatible regular expressions for patterns.
++
+Support for these types of regular expressions is an optional
+compile-time dependency. If Git wasn't compiled with support for them
+providing this option will cause it to die.
+
+-F::
+--fixed-strings::
+	Use fixed strings for patterns (don't interpret pattern
+	as a regex).
+
+-n::
+--line-number::
+	Prefix the line number to matching lines.
+
+--column::
+	Prefix the 1-indexed byte-offset of the first match from the start of the
+	matching line.
+
+-l::
+--files-with-matches::
+--name-only::
+-L::
+--files-without-match::
+	Instead of showing every matched line, show only the
+	names of files that contain (or do not contain) matches.
+	For better compatibility with 'git diff', `--name-only` is a
+	synonym for `--files-with-matches`.
+
+-O[<pager>]::
+--open-files-in-pager[=<pager>]::
+	Open the matching files in the pager (not the output of 'grep').
+	If the pager happens to be "less" or "vi", and the user
+	specified only one pattern, the first file is positioned at
+	the first match automatically. The `pager` argument is
+	optional; if specified, it must be stuck to the option
+	without a space. If `pager` is unspecified, the default pager
+	will be used (see `core.pager` in linkgit:git-config[1]).
+
+-z::
+--null::
+	Use \0 as the delimiter for pathnames in the output, and print
+	them verbatim. Without this option, pathnames with "unusual"
+	characters are quoted as explained for the configuration
+	variable `core.quotePath` (see linkgit:git-config[1]).
+
+-o::
+--only-matching::
+	Print only the matched (non-empty) parts of a matching line, with each such
+	part on a separate output line.
+
+-c::
+--count::
+	Instead of showing every matched line, show the number of
+	lines that match.
+
+--color[=<when>]::
+	Show colored matches.
+	The value must be always (the default), never, or auto.
+
+--no-color::
+	Turn off match highlighting, even when the configuration file
+	gives the default to color output.
+	Same as `--color=never`.
+
+--break::
+	Print an empty line between matches from different files.
+
+--heading::
+	Show the filename above the matches in that file instead of
+	at the start of each shown line.
+
+-p::
+--show-function::
+	Show the preceding line that contains the function name of
+	the match, unless the matching line is a function name itself.
+	The name is determined in the same way as `git diff` works out
+	patch hunk headers (see 'Defining a custom hunk-header' in
+	linkgit:gitattributes[5]).
+
+-<num>::
+-C <num>::
+--context <num>::
+	Show <num> leading and trailing lines, and place a line
+	containing `--` between contiguous groups of matches.
+
+-A <num>::
+--after-context <num>::
+	Show <num> trailing lines, and place a line containing
+	`--` between contiguous groups of matches.
+
+-B <num>::
+--before-context <num>::
+	Show <num> leading lines, and place a line containing
+	`--` between contiguous groups of matches.
+
+-W::
+--function-context::
+	Show the surrounding text from the previous line containing a
+	function name up to the one before the next function name,
+	effectively showing the whole function in which the match was
+	found. The function names are determined in the same way as
+	`git diff` works out patch hunk headers (see 'Defining a
+	custom hunk-header' in linkgit:gitattributes[5]).
+
+-m <num>::
+--max-count <num>::
+	Limit the amount of matches per file. When using the `-v` or
+	`--invert-match` option, the search stops after the specified
+	number of non-matches. A value of -1 will return unlimited
+	results (the default). A value of 0 will exit immediately with
+	a non-zero status.
+
+--threads <num>::
+	Number of `grep` worker threads to use.  See 'NOTES ON THREADS'
+	and `grep.threads` in 'CONFIGURATION' for more information.
+
+-f <file>::
+	Read patterns from <file>, one per line.
++
+Passing the pattern via <file> allows for providing a search pattern
+containing a \0.
++
+Not all pattern types support patterns containing \0. Git will error
+out if a given pattern type can't support such a pattern. The
+`--perl-regexp` pattern type when compiled against the PCRE v2 backend
+has the widest support for these types of patterns.
++
+In versions of Git before 2.23.0 patterns containing \0 would be
+silently considered fixed. This was never documented, there were also
+odd and undocumented interactions between e.g. non-ASCII patterns
+containing \0 and `--ignore-case`.
++
+In future versions we may learn to support patterns containing \0 for
+more search backends, until then we'll die when the pattern type in
+question doesn't support them.
+
+-e::
+	The next parameter is the pattern. This option has to be
+	used for patterns starting with `-` and should be used in
+	scripts passing user input to grep.  Multiple patterns are
+	combined by 'or'.
+
+--and::
+--or::
+--not::
+( ... )::
+	Specify how multiple patterns are combined using Boolean
+	expressions.  `--or` is the default operator.  `--and` has
+	higher precedence than `--or`.  `-e` has to be used for all
+	patterns.
+
+--all-match::
+	When giving multiple pattern expressions combined with `--or`,
+	this flag is specified to limit the match to files that
+	have lines to match all of them.
+
+-q::
+--quiet::
+	Do not output matched lines; instead, exit with status 0 when
+	there is a match and with non-zero status when there isn't.
+
+<tree>...::
+	Instead of searching tracked files in the working tree, search
+	blobs in the given trees.
+
+\--::
+	Signals the end of options; the rest of the parameters
+	are <pathspec> limiters.
+
+<pathspec>...::
+	If given, limit the search to paths matching at least one pattern.
+	Both leading paths match and glob(7) patterns are supported.
++
+For more details about the <pathspec> syntax, see the 'pathspec' entry
+in linkgit:gitglossary[7].
+
+EXAMPLES
+--------
+
+`git grep 'time_t' -- '*.[ch]'`::
+	Looks for `time_t` in all tracked .c and .h files in the working
+	directory and its subdirectories.
+
+`git grep -e '#define' --and \( -e MAX_PATH -e PATH_MAX \)`::
+	Looks for a line that has `#define` and either `MAX_PATH` or
+	`PATH_MAX`.
+
+`git grep --all-match -e NODE -e Unexpected`::
+	Looks for a line that has `NODE` or `Unexpected` in
+	files that have lines that match both.
+
+`git grep solution -- :^Documentation`::
+	Looks for `solution`, excluding files in `Documentation`.
+
+NOTES ON THREADS
+----------------
+
+The `--threads` option (and the `grep.threads` configuration) will be ignored when
+`--open-files-in-pager` is used, forcing a single-threaded execution.
+
+When grepping the object store (with `--cached` or giving tree objects), running
+with multiple threads might perform slower than single-threaded if `--textconv`
+is given and there are too many text conversions.  Thus, if low performance is
+experienced in this case, it might be desirable to use `--threads=1`.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/grep.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-gui.adoc b/Documentation/git-gui.adoc
new file mode 100644
index 0000000000..f5b02ef114
--- /dev/null
+++ b/Documentation/git-gui.adoc
@@ -0,0 +1,121 @@
+git-gui(1)
+==========
+
+NAME
+----
+git-gui - A portable graphical interface to Git
+
+SYNOPSIS
+--------
+[verse]
+'git gui' [<command>] [<arguments>]
+
+DESCRIPTION
+-----------
+A Tcl/Tk based graphical user interface to Git.  'git gui' focuses
+on allowing users to make changes to their repository by making
+new commits, amending existing ones, creating branches, performing
+local merges, and fetching/pushing to remote repositories.
+
+Unlike 'gitk', 'git gui' focuses on commit generation
+and single file annotation and does not show project history.
+It does however supply menu actions to start a 'gitk' session from
+within 'git gui'.
+
+'git gui' is known to work on all popular UNIX systems, Mac OS X,
+and Windows (under both Cygwin and MSYS).  To the extent possible
+OS specific user interface guidelines are followed, making 'git gui'
+a fairly native interface for users.
+
+COMMANDS
+--------
+blame::
+	Start a blame viewer on the specified file on the given
+	version (or working directory if not specified).
+
+browser::
+	Start a tree browser showing all files in the specified
+	commit.  Files selected through the
+	browser are opened in the blame viewer.
+
+citool::
+	Start 'git gui' and arrange to make exactly one commit before
+	exiting and returning to the shell.  The interface is limited
+	to only commit actions, slightly reducing the application's
+	startup time and simplifying the menubar.
+
+version::
+	Display the currently running version of 'git gui'.
+
+
+Examples
+--------
+`git gui blame Makefile`::
+
+	Show the contents of the file 'Makefile' in the current
+	working directory, and provide annotations for both the
+	original author of each line, and who moved the line to its
+	current location.  The uncommitted file is annotated, and
+	uncommitted changes (if any) are explicitly attributed to
+	'Not Yet Committed'.
+
+`git gui blame v0.99.8 Makefile`::
+
+	Show the contents of 'Makefile' in revision 'v0.99.8'
+	and provide annotations for each line.  Unlike the above
+	example the file is read from the object database and not
+	the working directory.
+
+`git gui blame --line=100 Makefile`::
+
+	Loads annotations as described above and automatically
+	scrolls the view to center on line '100'.
+
+`git gui citool`::
+
+	Make one commit and return to the shell when it is complete.
+	This command returns a non-zero exit code if the window was
+	closed in any way other than by making a commit.
+
+`git gui citool --amend`::
+
+	Automatically enter the 'Amend Last Commit' mode of
+	the interface.
+
+`git gui citool --nocommit`::
+
+	Behave as normal citool, but instead of making a commit
+	simply terminate with a zero exit code. It still checks
+	that the index does not contain any unmerged entries, so
+	you can use it as a GUI version of linkgit:git-mergetool[1]
+
+`git citool`::
+
+	Same as `git gui citool` (above).
+
+`git gui browser maint`::
+
+	Show a browser for the tree of the 'maint' branch.  Files
+	selected in the browser can be viewed with the internal
+	blame viewer.
+
+SEE ALSO
+--------
+linkgit:gitk[1]::
+	The Git repository browser.  Shows branches, commit history
+	and file differences.  gitk is the utility started by
+	'git gui''s Repository Visualize actions.
+
+Other
+-----
+'git gui' is actually maintained as an independent project, but stable
+versions are distributed as part of the Git suite for the convenience
+of end users.
+
+The official repository of the 'git gui' project can be found at:
+
+  https://github.com/j6t/git-gui
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-hash-object.adoc b/Documentation/git-hash-object.adoc
new file mode 100644
index 0000000000..ef4719ae41
--- /dev/null
+++ b/Documentation/git-hash-object.adoc
@@ -0,0 +1,65 @@
+git-hash-object(1)
+==================
+
+NAME
+----
+git-hash-object - Compute object ID and optionally create an object from a file
+
+
+SYNOPSIS
+--------
+[verse]
+'git hash-object' [-t <type>] [-w] [--path=<file> | --no-filters]
+		[--stdin [--literally]] [--] <file>...
+'git hash-object' [-t <type>] [-w] --stdin-paths [--no-filters]
+
+DESCRIPTION
+-----------
+Computes the object ID value for an object with specified type
+with the contents of the named file (which can be outside of the
+work tree), and optionally writes the resulting object into the
+object database.  Reports its object ID to its standard output.
+When <type> is not specified, it defaults to "blob".
+
+OPTIONS
+-------
+
+-t <type>::
+	Specify the type of object to be created (default: "blob"). Possible
+	values are `commit`, `tree`, `blob`, and `tag`.
+
+-w::
+	Actually write the object into the object database.
+
+--stdin::
+	Read the object from standard input instead of from a file.
+
+--stdin-paths::
+	Read file names from the standard input, one per line, instead
+	of from the command-line.
+
+--path::
+	Hash object as if it were located at the given path. The location of
+	the file does not directly influence the hash value, but the path is
+	used to determine which Git filters should be applied to the object
+	before it can be placed in the object database.  As a result of
+	applying filters, the actual blob put into the object database may
+	differ from the given file. This option is mainly useful for hashing
+	temporary files located outside of the working directory or files
+	read from stdin.
+
+--no-filters::
+	Hash the contents as is, ignoring any input filter that would
+	have been chosen by the attributes mechanism, including the end-of-line
+	conversion. If the file is read from standard input then this
+	is always implied, unless the `--path` option is given.
+
+--literally::
+	Allow `--stdin` to hash any garbage into a loose object which might not
+	otherwise pass standard object parsing or git-fsck checks. Useful for
+	stress-testing Git itself or reproducing characteristics of corrupt or
+	bogus objects encountered in the wild.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-help.adoc b/Documentation/git-help.adoc
new file mode 100644
index 0000000000..f0bedc1f96
--- /dev/null
+++ b/Documentation/git-help.adoc
@@ -0,0 +1,231 @@
+git-help(1)
+===========
+
+NAME
+----
+git-help - Display help information about Git
+
+SYNOPSIS
+--------
+[verse]
+'git help' [-a|--all] [--[no-]verbose] [--[no-]external-commands] [--[no-]aliases]
+'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 '<doc>' given, the synopsis of the 'git'
+command and a list of the most commonly used Git commands are printed
+on the standard output.
+
+If the option `--all` or `-a` is given, all available commands are
+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 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.
+
+If an alias is given, git shows the definition of the alias on
+standard output. To get the manual page for the aliased command, use
+`git <command> --help`.
+
+Note that `git --help ...` is identical to `git help ...` because the
+former is internally converted into the latter.
+
+To display the linkgit:git[1] man page, use `git help git`.
+
+This page can be displayed with 'git help help' or `git help --help`.
+
+OPTIONS
+-------
+-a::
+--all::
+	Print all the available commands on the standard output.
+
+--no-external-commands::
+	When used with `--all`, exclude the listing of external "git-*"
+	commands found in the `$PATH`.
+
+--no-aliases::
+	When used with `--all`, exclude the listing of configured
+	aliases.
+
+--verbose::
+	When used with `--all`, print description for all recognized
+	commands. This is the default.
+
+-c::
+--config::
+	List all available configuration variables. This is a short
+	summary of the list in linkgit:git-config[1].
+
+-g::
+--guides::
+	Print a list of the Git concept guides on the standard output.
+
+--user-interfaces::
+	Print 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 a 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
+	'info' program will be used for that purpose.
+
+-m::
+--man::
+	Display manual page for the command in the 'man' format. This
+	option may be used to override a value set in the
+	`help.format` configuration variable.
++
+By default the 'man' program will be used to display the manual page,
+but the `man.viewer` configuration variable may be used to choose
+other display programs (see below).
+
+-w::
+--web::
+	Display manual page for the command in the 'web' (HTML)
+	format. A web browser will be used for that purpose.
++
+The web browser can be specified using the configuration variable
+`help.browser`, or `web.browser` if the former is not set. If neither of
+these config variables is set, the 'git web{litdd}browse' helper script
+(called by 'git help') will pick a suitable default. See
+linkgit:git-web{litdd}browse[1] for more information about this.
+
+CONFIGURATION VARIABLES
+-----------------------
+
+help.format
+~~~~~~~~~~~
+
+If no command-line option is passed, the `help.format` configuration
+variable will be checked. The following values are supported for this
+variable; they make 'git help' behave as their corresponding command-
+line option:
+
+* "man" corresponds to '-m|--man',
+* "info" corresponds to '-i|--info',
+* "web" or "html" correspond to '-w|--web'.
+
+help.browser, web.browser, and browser.<tool>.path
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The `help.browser`, `web.browser` and `browser.<tool>.path` will also
+be checked if the 'web' format is chosen (either by command-line
+option or configuration variable). See '-w|--web' in the OPTIONS
+section above and linkgit:git-web{litdd}browse[1].
+
+man.viewer
+~~~~~~~~~~
+
+The `man.viewer` configuration variable will be checked if the 'man'
+format is chosen. The following values are currently supported:
+
+* "man": use the 'man' program as usual,
+* "woman": use 'emacsclient' to launch the "woman" mode in emacs
+  (this only works starting with emacsclient versions 22),
+* "konqueror": use 'kfmclient' to open the man page in a new konqueror
+  tab (see 'Note about konqueror' below).
+
+Values for other tools can be used if there is a corresponding
+`man.<tool>.cmd` configuration entry (see below).
+
+Multiple values may be given to the `man.viewer` configuration
+variable. Their corresponding programs will be tried in the order
+listed in the configuration file.
+
+For example, this configuration:
+
+------------------------------------------------
+	[man]
+		viewer = konqueror
+		viewer = woman
+------------------------------------------------
+
+will try to use konqueror first. But this may fail (for example, if
+DISPLAY is not set) and in that case emacs' woman mode will be tried.
+
+If everything fails, or if no viewer is configured, the viewer specified
+in the `GIT_MAN_VIEWER` environment variable will be tried.  If that
+fails too, the 'man' program will be tried anyway.
+
+man.<tool>.path
+~~~~~~~~~~~~~~~
+
+You can explicitly provide a full path to your preferred man viewer by
+setting the configuration variable `man.<tool>.path`. For example, you
+can configure the absolute path to konqueror by setting
+'man.konqueror.path'. Otherwise, 'git help' assumes the tool is
+available in PATH.
+
+man.<tool>.cmd
+~~~~~~~~~~~~~~
+
+When the man viewer, specified by the `man.viewer` configuration
+variables, is not among the supported ones, then the corresponding
+`man.<tool>.cmd` configuration variable will be looked up. If this
+variable exists then the specified tool will be treated as a custom
+command and a shell eval will be used to run the command with the man
+page passed as arguments.
+
+Note about konqueror
+~~~~~~~~~~~~~~~~~~~~
+
+When 'konqueror' is specified in the `man.viewer` configuration
+variable, we launch 'kfmclient' to try to open the man page on an
+already opened konqueror in a new tab if possible.
+
+For consistency, we also try such a trick if 'man.konqueror.path' is
+set to something like `A_PATH_TO/konqueror`. That means we will try to
+launch `A_PATH_TO/kfmclient` instead.
+
+If you really want to use 'konqueror', then you can use something like
+the following:
+
+------------------------------------------------
+	[man]
+		viewer = konq
+
+	[man "konq"]
+		cmd = A_PATH_TO/konqueror
+------------------------------------------------
+
+Note about git config --global
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Note that all these configuration variables should probably be set
+using the `--global` flag, for example like this:
+
+------------------------------------------------
+$ git config --global help.format web
+$ git config --global web.browser firefox
+------------------------------------------------
+
+as they are probably more user specific than repository specific.
+See linkgit:git-config[1] for more information about this.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-hook.adoc b/Documentation/git-hook.adoc
new file mode 100644
index 0000000000..f6cc72d2ca
--- /dev/null
+++ b/Documentation/git-hook.adoc
@@ -0,0 +1,50 @@
+git-hook(1)
+===========
+
+NAME
+----
+git-hook - Run git hooks
+
+SYNOPSIS
+--------
+[verse]
+'git hook' run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]
+
+DESCRIPTION
+-----------
+
+A command interface for running git hooks (see linkgit:githooks[5]),
+for use by other scripted git commands.
+
+SUBCOMMANDS
+-----------
+
+run::
+	Run the `<hook-name>` hook. See linkgit:githooks[5] for
+	supported hook names.
++
+
+Any positional arguments to the hook should be passed after a
+mandatory `--` (or `--end-of-options`, see linkgit:gitcli[7]). See
+linkgit:githooks[5] for arguments hooks might expect (if any).
+
+OPTIONS
+-------
+
+--to-stdin::
+	For "run"; specify a file which will be streamed into the
+	hook's stdin. The hook will receive the entire file from
+	beginning to EOF.
+
+--ignore-missing::
+	Ignore any missing hook by quietly returning zero. Used for
+	tools that want to do a blind one-shot run of a hook that may
+	or may not be present.
+
+SEE ALSO
+--------
+linkgit:githooks[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-http-backend.adoc b/Documentation/git-http-backend.adoc
new file mode 100644
index 0000000000..f37ddaded8
--- /dev/null
+++ b/Documentation/git-http-backend.adoc
@@ -0,0 +1,301 @@
+git-http-backend(1)
+===================
+
+NAME
+----
+git-http-backend - Server side implementation of Git over HTTP
+
+SYNOPSIS
+--------
+[verse]
+'git http-backend'
+
+DESCRIPTION
+-----------
+A simple CGI program to serve the contents of a Git repository to Git
+clients accessing the repository over http:// and https:// protocols.
+The program supports clients fetching using both the smart HTTP protocol
+and the backwards-compatible dumb HTTP protocol, as well as clients
+pushing using the smart HTTP protocol. It also supports Git's
+more-efficient "v2" protocol if properly configured; see the
+discussion of `GIT_PROTOCOL` in the ENVIRONMENT section below.
+
+It verifies that the directory has the magic file
+"git-daemon-export-ok", and it will refuse to export any Git directory
+that hasn't explicitly been marked for export this way (unless the
+`GIT_HTTP_EXPORT_ALL` environment variable is set).
+
+By default, only the `upload-pack` service is enabled, which serves
+'git fetch-pack' and 'git ls-remote' clients, which are invoked from
+'git fetch', 'git pull', and 'git clone'.  If the client is authenticated,
+the `receive-pack` service is enabled, which serves 'git send-pack'
+clients, which is invoked from 'git push'.
+
+SERVICES
+--------
+These services can be enabled/disabled using the per-repository
+configuration file:
+
+http.getanyfile::
+	This serves Git clients older than version 1.6.6 that are unable to use the
+	upload pack service.  When enabled, clients are able to read
+	any file within the repository, including objects that are
+	no longer reachable from a branch but are still present.
+	It is enabled by default, but a repository can disable it
+	by setting this configuration value to `false`.
+
+http.uploadpack::
+	This serves 'git fetch-pack' and 'git ls-remote' clients.
+	It is enabled by default, but a repository can disable it
+	by setting this configuration value to `false`.
+
+http.receivepack::
+	This serves 'git send-pack' clients, allowing push.  It is
+	disabled by default for anonymous users, and enabled by
+	default for users authenticated by the web server.  It can be
+	disabled by setting this item to `false`, or enabled for all
+	users, including anonymous users, by setting it to `true`.
+
+URL TRANSLATION
+---------------
+To determine the location of the repository on disk, 'git http-backend'
+concatenates the environment variables PATH_INFO, which is set
+automatically by the web server, and GIT_PROJECT_ROOT, which must be set
+manually in the web server configuration.  If GIT_PROJECT_ROOT is not
+set, 'git http-backend' reads PATH_TRANSLATED, which is also set
+automatically by the web server.
+
+EXAMPLES
+--------
+All of the following examples map `http://$hostname/git/foo/bar.git`
+to `/var/www/git/foo/bar.git`.
+
+Apache 2.x::
+	Ensure mod_cgi, mod_alias, and mod_env are enabled, set
+	GIT_PROJECT_ROOT (or DocumentRoot) appropriately, and
+	create a ScriptAlias to the CGI:
++
+----------------------------------------------------------------
+SetEnv GIT_PROJECT_ROOT /var/www/git
+SetEnv GIT_HTTP_EXPORT_ALL
+ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
+
+# This is not strictly necessary using Apache and a modern version of
+# git-http-backend, as the webserver will pass along the header in the
+# environment as HTTP_GIT_PROTOCOL, and http-backend will copy that into
+# GIT_PROTOCOL. But you may need this line (or something similar if you
+# are using a different webserver), or if you want to support older Git
+# versions that did not do that copying.
+#
+# Having the webserver set up GIT_PROTOCOL is perfectly fine even with
+# modern versions (and will take precedence over HTTP_GIT_PROTOCOL,
+# which means it can be used to override the client's request).
+SetEnvIf Git-Protocol ".*" GIT_PROTOCOL=$0
+----------------------------------------------------------------
++
+To enable anonymous read access but authenticated write access,
+require authorization for both the initial ref advertisement (which we
+detect as a push via the service parameter in the query string), and the
+receive-pack invocation itself:
++
+----------------------------------------------------------------
+RewriteCond %{QUERY_STRING} service=git-receive-pack [OR]
+RewriteCond %{REQUEST_URI} /git-receive-pack$
+RewriteRule ^/git/ - [E=AUTHREQUIRED:yes]
+
+<LocationMatch "^/git/">
+	Order Deny,Allow
+	Deny from env=AUTHREQUIRED
+
+	AuthType Basic
+	AuthName "Git Access"
+	Require group committers
+	Satisfy Any
+	...
+</LocationMatch>
+----------------------------------------------------------------
++
+If you do not have `mod_rewrite` available to match against the query
+string, it is sufficient to just protect `git-receive-pack` itself,
+like:
++
+----------------------------------------------------------------
+<LocationMatch "^/git/.*/git-receive-pack$">
+	AuthType Basic
+	AuthName "Git Access"
+	Require group committers
+	...
+</LocationMatch>
+----------------------------------------------------------------
++
+In this mode, the server will not request authentication until the
+client actually starts the object negotiation phase of the push, rather
+than during the initial contact.  For this reason, you must also enable
+the `http.receivepack` config option in any repositories that should
+accept a push. The default behavior, if `http.receivepack` is not set,
+is to reject any pushes by unauthenticated users; the initial request
+will therefore report `403 Forbidden` to the client, without even giving
+an opportunity for authentication.
++
+To require authentication for both reads and writes, use a Location
+directive around the repository, or one of its parent directories:
++
+----------------------------------------------------------------
+<Location /git/private>
+	AuthType Basic
+	AuthName "Private Git Access"
+	Require group committers
+	...
+</Location>
+----------------------------------------------------------------
++
+To serve gitweb at the same url, use a ScriptAliasMatch to only
+those URLs that 'git http-backend' can handle, and forward the
+rest to gitweb:
++
+----------------------------------------------------------------
+ScriptAliasMatch \
+	"(?x)^/git/(.*/(HEAD | \
+			info/refs | \
+			objects/(info/[^/]+ | \
+				 [0-9a-f]{2}/[0-9a-f]{38} | \
+				 pack/pack-[0-9a-f]{40}\.(pack|idx)) | \
+			git-(upload|receive)-pack))$" \
+	/usr/libexec/git-core/git-http-backend/$1
+
+ScriptAlias /git/ /var/www/cgi-bin/gitweb.cgi/
+----------------------------------------------------------------
++
+To serve multiple repositories from different linkgit:gitnamespaces[7] in a
+single repository:
++
+----------------------------------------------------------------
+SetEnvIf Request_URI "^/git/([^/]*)" GIT_NAMESPACE=$1
+ScriptAliasMatch ^/git/[^/]*(.*) /usr/libexec/git-core/git-http-backend/storage.git$1
+----------------------------------------------------------------
+
+Accelerated static Apache 2.x::
+	Similar to the above, but Apache can be used to return static
+	files that are stored on disk.  On many systems this may
+	be more efficient as Apache can ask the kernel to copy the
+	file contents from the file system directly to the network:
++
+----------------------------------------------------------------
+SetEnv GIT_PROJECT_ROOT /var/www/git
+
+AliasMatch ^/git/(.*/objects/[0-9a-f]{2}/[0-9a-f]{38})$          /var/www/git/$1
+AliasMatch ^/git/(.*/objects/pack/pack-[0-9a-f]{40}.(pack|idx))$ /var/www/git/$1
+ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
+----------------------------------------------------------------
++
+This can be combined with the gitweb configuration:
++
+----------------------------------------------------------------
+SetEnv GIT_PROJECT_ROOT /var/www/git
+
+AliasMatch ^/git/(.*/objects/[0-9a-f]{2}/[0-9a-f]{38})$          /var/www/git/$1
+AliasMatch ^/git/(.*/objects/pack/pack-[0-9a-f]{40}.(pack|idx))$ /var/www/git/$1
+ScriptAliasMatch \
+	"(?x)^/git/(.*/(HEAD | \
+			info/refs | \
+			objects/info/[^/]+ | \
+			git-(upload|receive)-pack))$" \
+	/usr/libexec/git-core/git-http-backend/$1
+ScriptAlias /git/ /var/www/cgi-bin/gitweb.cgi/
+----------------------------------------------------------------
+
+Lighttpd::
+	Ensure that `mod_cgi`, `mod_alias`, `mod_auth`, `mod_setenv` are
+	loaded, then set `GIT_PROJECT_ROOT` appropriately and redirect
+	all requests to the CGI:
++
+----------------------------------------------------------------
+alias.url += ( "/git" => "/usr/lib/git-core/git-http-backend" )
+$HTTP["url"] =~ "^/git" {
+	cgi.assign = ("" => "")
+	setenv.add-environment = (
+		"GIT_PROJECT_ROOT" => "/var/www/git",
+		"GIT_HTTP_EXPORT_ALL" => ""
+	)
+}
+----------------------------------------------------------------
++
+To enable anonymous read access but authenticated write access:
++
+----------------------------------------------------------------
+$HTTP["querystring"] =~ "service=git-receive-pack" {
+	include "git-auth.conf"
+}
+$HTTP["url"] =~ "^/git/.*/git-receive-pack$" {
+	include "git-auth.conf"
+}
+----------------------------------------------------------------
++
+where `git-auth.conf` looks something like:
++
+----------------------------------------------------------------
+auth.require = (
+	"/" => (
+		"method" => "basic",
+		"realm" => "Git Access",
+		"require" => "valid-user"
+	       )
+)
+# ...and set up auth.backend here
+----------------------------------------------------------------
++
+To require authentication for both reads and writes:
++
+----------------------------------------------------------------
+$HTTP["url"] =~ "^/git/private" {
+	include "git-auth.conf"
+}
+----------------------------------------------------------------
+
+
+ENVIRONMENT
+-----------
+'git http-backend' relies upon the `CGI` environment variables set
+by the invoking web server, including:
+
+* PATH_INFO (if GIT_PROJECT_ROOT is set, otherwise PATH_TRANSLATED)
+* REMOTE_USER
+* REMOTE_ADDR
+* CONTENT_TYPE
+* QUERY_STRING
+* REQUEST_METHOD
+
+The `GIT_HTTP_EXPORT_ALL` environment variable may be passed to
+'git-http-backend' to bypass the check for the "git-daemon-export-ok"
+file in each repository before allowing export of that repository.
+
+The `GIT_HTTP_MAX_REQUEST_BUFFER` environment variable (or the
+`http.maxRequestBuffer` config option) may be set to change the
+largest ref negotiation request that git will handle during a fetch; any
+fetch requiring a larger buffer will not succeed.  This value should not
+normally need to be changed, but may be helpful if you are fetching from
+a repository with an extremely large number of refs.  The value can be
+specified with a unit (e.g., `100M` for 100 megabytes). The default is
+10 megabytes.
+
+Clients may probe for optional protocol capabilities (like the v2
+protocol) using the `Git-Protocol` HTTP header. In order to support
+these, the contents of that header must appear in the `GIT_PROTOCOL`
+environment variable. Most webservers will pass this header to the CGI
+via the `HTTP_GIT_PROTOCOL` variable, and `git-http-backend` will
+automatically copy that to `GIT_PROTOCOL`. However, some webservers may
+be more selective about which headers they'll pass, in which case they
+need to be configured explicitly (see the mention of `Git-Protocol` in
+the Apache config from the earlier EXAMPLES section).
+
+The backend process sets GIT_COMMITTER_NAME to '$REMOTE_USER' and
+GIT_COMMITTER_EMAIL to '$\{REMOTE_USER}@http.$\{REMOTE_ADDR\}',
+ensuring that any reflogs created by 'git-receive-pack' contain some
+identifying information of the remote user who performed the push.
+
+All `CGI` environment variables are available to each of the hooks
+invoked by the 'git-receive-pack'.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-http-fetch.adoc b/Documentation/git-http-fetch.adoc
new file mode 100644
index 0000000000..4ec7c68d3b
--- /dev/null
+++ b/Documentation/git-http-fetch.adoc
@@ -0,0 +1,62 @@
+git-http-fetch(1)
+=================
+
+NAME
+----
+git-http-fetch - Download from a remote Git repository via HTTP
+
+
+SYNOPSIS
+--------
+[verse]
+'git http-fetch' [-c] [-t] [-a] [-d] [-v] [-w <filename>] [--recover] [--stdin | --packfile=<hash> | <commit>] <URL>
+
+DESCRIPTION
+-----------
+Downloads a remote Git repository via HTTP.
+
+This command always gets all objects. Historically, there were three options
+`-a`, `-c` and `-t` for choosing which objects to download. They are now
+silently ignored.
+
+OPTIONS
+-------
+commit-id::
+        Either the hash or the filename under [URL]/refs/ to
+        pull.
+
+-a, -c, -t::
+	These options are ignored for historical reasons.
+-v::
+	Report what is downloaded.
+
+-w <filename>::
+	Writes the commit-id into the specified filename under $GIT_DIR/refs/<filename> on
+        the local end after the transfer is complete.
+
+--stdin::
+	Instead of a commit id on the command line (which is not expected in this
+	case), 'git http-fetch' expects lines on stdin in the format
+
+		<commit-id>['\t'<filename-as-in--w>]
+
+--packfile=<hash>::
+	For internal use only. Instead of a commit id on the command
+	line (which is not expected in
+	this case), 'git http-fetch' fetches the packfile directly at the given
+	URL and uses index-pack to generate corresponding .idx and .keep files.
+	The hash is used to determine the name of the temporary file and is
+	arbitrary. The output of index-pack is printed to stdout. Requires
+	--index-pack-args.
+
+--index-pack-args=<args>::
+	For internal use only. The command to run on the contents of the
+	downloaded pack. Arguments are URL-encoded separated by spaces.
+
+--recover::
+	Verify that everything reachable from target is fetched.  Used after
+	an earlier fetch is interrupted.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-http-push.adoc b/Documentation/git-http-push.adoc
new file mode 100644
index 0000000000..ce0d808212
--- /dev/null
+++ b/Documentation/git-http-push.adoc
@@ -0,0 +1,96 @@
+git-http-push(1)
+================
+
+NAME
+----
+git-http-push - Push objects over HTTP/DAV to another repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git http-push' [--all] [--dry-run] [--force] [--verbose] <URL> <ref> [<ref>...]
+
+DESCRIPTION
+-----------
+Sends missing objects to the remote repository, and updates the
+remote branch.
+
+*NOTE*: This command is temporarily disabled if your libcurl
+is older than 7.16, as the combination has been reported
+not to work and sometimes corrupts the repository.
+
+OPTIONS
+-------
+--all::
+	Do not assume that the remote repository is complete in its
+	current state, and verify all objects in the entire local
+	ref's history exist in the remote repository.
+
+--force::
+	Usually, the command refuses to update a remote ref that
+	is not an ancestor of the local ref used to overwrite it.
+	This flag disables the check.  What this means is that
+	the remote repository can lose commits; use it with
+	care.
+
+--dry-run::
+	Do everything except actually send the updates.
+
+--verbose::
+	Report the list of objects being walked locally and the
+	list of objects successfully sent to the remote repository.
+
+-d::
+-D::
+	Remove <ref> from remote repository.  The specified branch
+	cannot be the remote HEAD.  If -d is specified, the following
+	other conditions must also be met:
+
+	- Remote HEAD must resolve to an object that exists locally
+	- Specified branch resolves to an object that exists locally
+	- Specified branch is an ancestor of the remote HEAD
+
+<ref>...::
+	The remote refs to update.
+
+
+SPECIFYING THE REFS
+-------------------
+
+A '<ref>' specification can be either a single pattern, or a pair
+of such patterns separated by a colon ":" (this means that a ref name
+cannot have a colon in it).  A single pattern '<name>' is just a
+shorthand for '<name>:<name>'.
+
+Each pattern pair '<src>:<dst>' consists of the source side (before
+the colon) and the destination side (after the colon).  The ref to be
+pushed is determined by finding a match that matches the source side,
+and where it is pushed is determined by using the destination side.
+
+ - It is an error if '<src>' does not match exactly one of the
+   local refs.
+
+ - If '<dst>' does not match any remote ref, either
+
+   * it has to start with "refs/"; <dst> is used as the
+     destination literally in this case.
+
+   * <src> == <dst> and the ref that matched the <src> must not
+     exist in the set of remote refs; the ref matched <src>
+     locally is used as the name of the destination.
+
+Without `--force`, the <src> ref is stored at the remote only if
+<dst> does not exist, or <dst> is a proper subset (i.e. an
+ancestor) of <src>.  This check, known as "fast-forward check",
+is performed to avoid accidentally overwriting the
+remote ref and losing other peoples' commits from there.
+
+With `--force`, the fast-forward check is disabled for all refs.
+
+Optionally, a <ref> parameter can be prefixed with a plus '+' sign
+to disable the fast-forward check only on that ref.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-imap-send.adoc b/Documentation/git-imap-send.adoc
new file mode 100644
index 0000000000..9ab4d071d3
--- /dev/null
+++ b/Documentation/git-imap-send.adoc
@@ -0,0 +1,146 @@
+git-imap-send(1)
+================
+
+NAME
+----
+git-imap-send - Send a collection of patches from stdin to an IMAP folder
+
+
+SYNOPSIS
+--------
+[verse]
+'git imap-send' [-v] [-q] [--[no-]curl]
+
+
+DESCRIPTION
+-----------
+This command uploads a mailbox generated with 'git format-patch'
+into an IMAP drafts folder.  This allows patches to be sent as
+other email is when using mail clients that cannot read mailbox
+files directly. The command also works with any general mailbox
+in which emails have the fields "From", "Date", and "Subject" in
+that order.
+
+Typical usage is something like:
+
+git format-patch --signoff --stdout --attach origin | git imap-send
+
+
+OPTIONS
+-------
+
+-v::
+--verbose::
+	Be verbose.
+
+-q::
+--quiet::
+	Be quiet.
+
+--curl::
+	Use libcurl to communicate with the IMAP server, unless tunneling
+	into it.  Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
+	option set.
+
+--no-curl::
+	Talk to the IMAP server using git's own IMAP routines instead of
+	using libcurl.  Ignored if Git was built with the NO_OPENSSL option
+	set.
+
+
+CONFIGURATION
+-------------
+
+To use the tool, `imap.folder` and either `imap.tunnel` or `imap.host` must be set
+to appropriate values.
+
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/imap.adoc[]
+
+EXAMPLES
+--------
+Using tunnel mode:
+
+..........................
+[imap]
+    folder = "INBOX.Drafts"
+    tunnel = "ssh -q -C user@xxxxxxxxxxx /usr/bin/imapd ./Maildir 2> /dev/null"
+..........................
+
+Using direct mode:
+
+.........................
+[imap]
+    folder = "INBOX.Drafts"
+    host = imap://imap.example.com
+    user = bob
+    pass = p4ssw0rd
+.........................
+
+Using direct mode with SSL:
+
+.........................
+[imap]
+    folder = "INBOX.Drafts"
+    host = imaps://imap.example.com
+    user = bob
+    pass = p4ssw0rd
+    port = 123
+    ; sslVerify = false
+.........................
+
+
+[NOTE]
+You may want to use `sslVerify=false`
+while troubleshooting, if you suspect that the reason you are
+having trouble connecting is because the certificate you use at
+the private server `example.com` you are trying to set up (or
+have set up) may not be verified correctly.
+
+Using Gmail's IMAP interface:
+
+---------
+[imap]
+	folder = "[Gmail]/Drafts"
+	host = imaps://imap.gmail.com
+	user = user@xxxxxxxxx
+	port = 993
+---------
+
+[NOTE]
+You might need to instead use: `folder = "[Google Mail]/Drafts"` if you get an error
+that the "Folder doesn't exist".
+
+[NOTE]
+If your Gmail account is set to another language than English, the name of the "Drafts"
+folder will be localized.
+
+Once the commits are ready to be sent, run the following command:
+
+  $ git format-patch --cover-letter -M --stdout origin/master | git imap-send
+
+Just make sure to disable line wrapping in the email client (Gmail's web
+interface will wrap lines no matter what, so you need to use a real
+IMAP client).
+
+CAUTION
+-------
+It is still your responsibility to make sure that the email message
+sent by your email program meets the standards of your project.
+Many projects do not like patches to be attached.  Some mail
+agents will transform patches (e.g. wrap lines, send them as
+format=flowed) in ways that make them fail.  You will get angry
+flames ridiculing you if you don't check this.
+
+Thunderbird in particular is known to be problematic.  Thunderbird
+users may wish to visit this web page for more information:
+  https://kb.mozillazine.org/Plain_text_e-mail_-_Thunderbird#Completely_plain_email
+
+SEE ALSO
+--------
+linkgit:git-format-patch[1], linkgit:git-send-email[1], mbox(5)
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-index-pack.adoc b/Documentation/git-index-pack.adoc
new file mode 100644
index 0000000000..270056cf63
--- /dev/null
+++ b/Documentation/git-index-pack.adoc
@@ -0,0 +1,162 @@
+git-index-pack(1)
+=================
+
+NAME
+----
+git-index-pack - Build pack index file for an existing packed archive
+
+
+SYNOPSIS
+--------
+[verse]
+'git index-pack' [-v] [-o <index-file>] [--[no-]rev-index] <pack-file>
+'git index-pack' --stdin [--fix-thin] [--keep] [-v] [-o <index-file>]
+		  [--[no-]rev-index] [<pack-file>]
+
+
+DESCRIPTION
+-----------
+Reads a packed archive (.pack) from the specified file,
+builds a pack index file (.idx) for it, and optionally writes a
+reverse-index (.rev) for the specified pack. The packed
+archive, together with the pack index, can then be placed in
+the objects/pack/ directory of a Git repository.
+
+
+OPTIONS
+-------
+-v::
+	Be verbose about what is going on, including progress status.
+
+-o <index-file>::
+	Write the generated pack index into the specified
+	file.  Without this option the name of pack index
+	file is constructed from the name of packed archive
+	file by replacing .pack with .idx (and the program
+	fails if the name of packed archive does not end
+	with .pack).
+
+--[no-]rev-index::
+	When this flag is provided, generate a reverse index
+	(a `.rev` file) corresponding to the given pack. If
+	`--verify` is given, ensure that the existing
+	reverse index is correct. Takes precedence over
+	`pack.writeReverseIndex`.
+
+--stdin::
+	When this flag is provided, the pack is read from stdin
+	instead and a copy is then written to <pack-file>. If
+	<pack-file> is not specified, the pack is written to
+	objects/pack/ directory of the current Git repository with
+	a default name determined from the pack content.  If
+	<pack-file> is not specified consider using --keep to
+	prevent a race condition between this process and
+	'git repack'.
+
+--fix-thin::
+	Fix a "thin" pack produced by `git pack-objects --thin` (see
+	linkgit:git-pack-objects[1] for details) by adding the
+	excluded objects the deltified objects are based on to the
+	pack. This option only makes sense in conjunction with --stdin.
+
+--keep::
+	Before moving the index into its final destination
+	create an empty .keep file for the associated pack file.
+	This option is usually necessary with --stdin to prevent a
+	simultaneous 'git repack' process from deleting
+	the newly constructed pack and index before refs can be
+	updated to use objects contained in the pack.
+
+--keep=<msg>::
+	Like --keep, create a .keep file before moving the index into
+	its final destination.  However, instead of creating an empty file
+	place '<msg>' followed by an LF into the .keep file.  The '<msg>'
+	message can later be searched for within all .keep files to
+	locate any which have outlived their usefulness.
+
+--index-version=<version>[,<offset>]::
+	This is intended to be used by the test suite only. It allows
+	to force the version for the generated pack index, and to force
+	64-bit index entries on objects located above the given offset.
+
+--strict[=<msg-id>=<severity>...]::
+	Die, if the pack contains broken objects or links. An optional
+	comma-separated list of `<msg-id>=<severity>` can be passed to change
+	the severity of some possible issues, e.g.,
+	 `--strict="missingEmail=ignore,badTagName=error"`. See the entry for the
+	`fsck.<msg-id>` configuration options in linkgit:git-fsck[1] for more
+	information on the possible values of `<msg-id>` and `<severity>`.
+
+--progress-title::
+	For internal use only.
++
+Set the title of the progress bar. The title is "Receiving objects" by
+default and "Indexing objects" when `--stdin` is specified.
+
+--check-self-contained-and-connected::
+	Die if the pack contains broken links. For internal use only.
+
+--fsck-objects[=<msg-id>=<severity>...]::
+	Die if the pack contains broken objects, but unlike `--strict`, don't
+	choke on broken links. If the pack contains a tree pointing to a
+	.gitmodules blob that does not exist, prints the hash of that blob
+	(for the caller to check) after the hash that goes into the name of the
+	pack/idx file (see "Notes").
++
+An optional comma-separated list of `<msg-id>=<severity>` can be passed to
+change the severity of some possible issues, e.g.,
+`--fsck-objects="missingEmail=ignore,badTagName=ignore"`. See the entry for the
+`fsck.<msg-id>` configuration options in linkgit:git-fsck[1] for more
+information on the possible values of `<msg-id>` and `<severity>`.
+
+--threads=<n>::
+	Specifies the number of threads to spawn when resolving
+	deltas. This requires that index-pack be compiled with
+	pthreads otherwise this option is ignored with a warning.
+	This is meant to reduce packing time on multiprocessor
+	machines. The required amount of memory for the delta search
+	window is however multiplied by the number of threads.
+	Specifying 0 will cause Git to auto-detect the number of CPU's
+	and use maximum 3 threads.
+
+--max-input-size=<size>::
+	Die, if the pack is larger than <size>.
+
+--object-format=<hash-algorithm>::
+	Specify the given object format (hash algorithm) for the pack.  The valid
+	values are 'sha1' and (if enabled) 'sha256'.  The default is the algorithm for
+	the current repository (set by `extensions.objectFormat`), or 'sha1' if no
+	value is set or outside a repository.
++
+This option cannot be used with --stdin.
++
+include::object-format-disclaimer.adoc[]
+
+--promisor[=<message>]::
+	Before committing the pack-index, create a .promisor file for this
+	pack. Particularly helpful when writing a promisor pack with --fix-thin
+	since the name of the pack is not final until the pack has been fully
+	written. If a `<message>` is provided, then that content will be
+	written to the .promisor file for future reference. See
+	link:technical/partial-clone.html[partial clone] for more information.
++
+Also, if there are objects in the given pack that references non-promisor
+objects (in the repo), repacks those non-promisor objects into a promisor
+pack. This avoids a situation in which a repo has non-promisor objects that are
+accessible through promisor objects.
++
+Requires <pack-file> to not be specified.
+
+NOTES
+-----
+
+Once the index has been created, the hash that goes into the name of
+the pack/idx file is printed to stdout. If --stdin was
+also used then this is prefixed by either "pack\t", or "keep\t" if a
+new .keep file was successfully created. This is useful to remove a
+.keep file used as a lock to prevent the race with 'git repack'
+mentioned above.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-init-db.adoc b/Documentation/git-init-db.adoc
new file mode 100644
index 0000000000..18bf1a3c8c
--- /dev/null
+++ b/Documentation/git-init-db.adoc
@@ -0,0 +1,23 @@
+git-init-db(1)
+==============
+
+NAME
+----
+git-init-db - Creates an empty Git repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git init-db' [-q | --quiet] [--bare] [--template=<template-directory>] [--separate-git-dir <git-dir>] [--shared[=<permissions>]]
+
+
+DESCRIPTION
+-----------
+
+This is a synonym for linkgit:git-init[1].  Please refer to the
+documentation of that command.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-init.adoc b/Documentation/git-init.adoc
new file mode 100644
index 0000000000..943aa7ecd7
--- /dev/null
+++ b/Documentation/git-init.adoc
@@ -0,0 +1,189 @@
+git-init(1)
+===========
+
+NAME
+----
+git-init - Create an empty Git repository or reinitialize an existing one
+
+
+SYNOPSIS
+--------
+[synopsis]
+git init [-q | --quiet] [--bare] [--template=<template-directory>]
+	 [--separate-git-dir <git-dir>] [--object-format=<format>]
+	 [--ref-format=<format>]
+	 [-b <branch-name> | --initial-branch=<branch-name>]
+	 [--shared[=<permissions>]] [<directory>]
+
+
+DESCRIPTION
+-----------
+
+This command creates an empty Git repository - basically a `.git`
+directory with subdirectories for `objects`, `refs/heads`,
+`refs/tags`, and template files.  An initial branch without any
+commits will be created (see the `--initial-branch` option below
+for its name).
+
+If the `GIT_DIR` environment variable is set then it specifies a path
+to use instead of `./.git` for the base of the repository.
+
+If the object storage directory is specified via the
+`GIT_OBJECT_DIRECTORY` environment variable then the sha1 directories
+are created underneath; otherwise, the default `$GIT_DIR/objects`
+directory is used.
+
+Running `git init` in an existing repository is safe. It will not
+overwrite things that are already there. The primary reason for
+rerunning `git init` is to pick up newly added templates (or to move
+the repository to another place if `--separate-git-dir` is given).
+
+OPTIONS
+-------
+
+`-q`::
+`--quiet`::
+
+Only print error and warning messages; all other output will be suppressed.
+
+`--bare`::
+
+Create a bare repository. If `GIT_DIR` environment is not set, it is set to the
+current working directory.
+
+`--object-format=<format>`::
+Specify the given object _<format>_ (hash algorithm) for the repository.  The valid
+values are `sha1` and (if enabled) `sha256`.  `sha1` is the default.
++
+include::object-format-disclaimer.adoc[]
+
+`--ref-format=<format>`::
+Specify the given ref storage _<format>_ for the repository. The valid values are:
++
+include::ref-storage-format.adoc[]
+
+`--template=<template-directory>`::
+Specify the directory from which templates will be used.  (See the "TEMPLATE
+DIRECTORY" section below.)
+
+`--separate-git-dir=<git-dir>`::
+Instead of initializing the repository as a directory to either `$GIT_DIR` or
+`./.git/`, create a text file there containing the path to the actual
+repository.  This file acts as a filesystem-agnostic Git symbolic link to the
+repository.
++
+If this is a reinitialization, the repository will be moved to the specified path.
+
+`-b <branch-name>`::
+`--initial-branch=<branch-name>`::
+Use _<branch-name>_ for the initial branch in the newly created
+repository.  If not specified, fall back to the default name (currently
+`master`, but this is subject to change in the future; the name can be
+customized via the `init.defaultBranch` configuration variable).
+
+`--shared[=(false|true|umask|group|all|world|everybody|<perm>)]`::
+
+Specify that the Git repository is to be shared amongst several users.  This
+allows users belonging to the same group to push into that
+repository.  When specified, the config variable `core.sharedRepository` is
+set so that files and directories under `$GIT_DIR` are created with the
+requested permissions.  When not specified, Git will use permissions reported
+by `umask`(2).
++
+The option can have the following values, defaulting to `group` if no value
+is given:
++
+--
+`umask`::
+`false`::
+
+Use permissions reported by `umask`(2). The default, when `--shared` is not
+specified.
+
+`group`::
+`true`::
+
+Make the repository group-writable, (and `g+sx`, since the git group may not be
+the primary group of all users). This is used to loosen the permissions of an
+otherwise safe `umask`(2) value. Note that the umask still applies to the other
+permission bits (e.g. if umask is `0022`, using `group` will not remove read
+privileges from other (non-group) users). See `0xxx` for how to exactly specify
+the repository permissions.
+
+`all`::
+`world`::
+`everybody`::
+
+Same as `group`, but make the repository readable by all users.
+
+_<perm>_::
+
+_<perm>_ is a 3-digit octal number prefixed with `0` and each file
+will have mode _<perm>_. _<perm>_ will override users' `umask`(2)
+value (and not only loosen permissions as `group` and `all`
+do). `0640` will create a repository which is group-readable, but
+not group-writable or accessible to others. `0660` will create a repo
+that is readable and writable to the current user and group, but
+inaccessible to others (directories and executable files get their
+`x` bit from the `r` bit for corresponding classes of users).
+--
+
+By default, the configuration flag `receive.denyNonFastForwards` is enabled
+in shared repositories, so that you cannot force a non fast-forwarding push
+into it.
+
+If you provide a _<directory>_, the command is run inside it. If this directory
+does not exist, it will be created.
+
+TEMPLATE DIRECTORY
+------------------
+
+Files and directories in the template directory whose name do not start with a
+dot will be copied to the `$GIT_DIR` after it is created.
+
+The template directory will be one of the following (in order):
+
+ - the argument given with the `--template` option;
+
+ - the contents of the `$GIT_TEMPLATE_DIR` environment variable;
+
+ - the `init.templateDir` configuration variable; or
+
+ - the default template directory: `/usr/share/git-core/templates`.
+
+The default template directory includes some directory structure, suggested
+"exclude patterns" (see linkgit:gitignore[5]), and sample hook files.
+
+The sample hooks are all disabled by default. To enable one of the
+sample hooks rename it by removing its `.sample` suffix.
+
+See linkgit:githooks[5] for more general info on hook execution.
+
+EXAMPLES
+--------
+
+Start a new Git repository for an existing code base::
++
+----------------
+$ cd /path/to/my/codebase
+$ git init      <1>
+$ git add .     <2>
+$ git commit    <3>
+----------------
++
+<1> Create a `/path/to/my/codebase/.git` directory.
+<2> Add all existing files to the index.
+<3> Record the pristine state as the first commit in the history.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+:git-init:
+
+include::config/init.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-instaweb.adoc b/Documentation/git-instaweb.adoc
new file mode 100644
index 0000000000..a54fe4401b
--- /dev/null
+++ b/Documentation/git-instaweb.adoc
@@ -0,0 +1,94 @@
+git-instaweb(1)
+===============
+
+NAME
+----
+git-instaweb - Instantly browse your working repository in gitweb
+
+SYNOPSIS
+--------
+[verse]
+'git instaweb' [--local] [--httpd=<httpd>] [--port=<port>]
+               [--browser=<browser>]
+'git instaweb' [--start] [--stop] [--restart]
+
+DESCRIPTION
+-----------
+A simple script to set up `gitweb` and a web server for browsing the local
+repository.
+
+OPTIONS
+-------
+
+-l::
+--local::
+	Only bind the web server to the local IP (127.0.0.1).
+
+-d::
+--httpd::
+	The HTTP daemon command-line that will be executed.
+	Command-line options may be specified here, and the
+	configuration file will be added at the end of the command-line.
+	Currently apache2, lighttpd, mongoose, plackup, python and
+	webrick are supported.
+	(Default: lighttpd)
+
+-m::
+--module-path::
+	The module path (only needed if httpd is Apache).
+	(Default: /usr/lib/apache2/modules)
+
+-p::
+--port::
+	The port number to bind the httpd to.  (Default: 1234)
+
+-b::
+--browser::
+	The web browser that should be used to view the gitweb
+	page. This will be passed to the 'git web{litdd}browse' helper
+	script along with the URL of the gitweb instance. See
+	linkgit:git-web{litdd}browse[1] for more information about this. If
+	the script fails, the URL will be printed to stdout.
+
+start::
+--start::
+	Start the httpd instance and exit.  Regenerate configuration files
+	as necessary for spawning a new instance.
+
+stop::
+--stop::
+	Stop the httpd instance and exit.  This does not generate
+	any of the configuration files for spawning a new instance,
+	nor does it close the browser.
+
+restart::
+--restart::
+	Restart the httpd instance and exit.  Regenerate configuration files
+	as necessary for spawning a new instance.
+
+CONFIGURATION
+-------------
+
+You may specify configuration in your .git/config
+
+-----------------------------------------------------------------------
+[instaweb]
+	local = true
+	httpd = apache2 -f
+	port = 4321
+	browser = konqueror
+	modulePath = /usr/lib/apache2/modules
+
+-----------------------------------------------------------------------
+
+If the configuration variable `instaweb.browser` is not set,
+`web.browser` will be used instead if it is defined. See
+linkgit:git-web{litdd}browse[1] for more information about this.
+
+SEE ALSO
+--------
+linkgit:gitweb[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-interpret-trailers.adoc b/Documentation/git-interpret-trailers.adoc
new file mode 100644
index 0000000000..d9dfb75fef
--- /dev/null
+++ b/Documentation/git-interpret-trailers.adoc
@@ -0,0 +1,523 @@
+git-interpret-trailers(1)
+=========================
+
+NAME
+----
+git-interpret-trailers - Add or parse structured information in commit messages
+
+SYNOPSIS
+--------
+[verse]
+'git interpret-trailers' [--in-place] [--trim-empty]
+			[(--trailer (<key>|<key-alias>)[(=|:)<value>])...]
+			[--parse] [<file>...]
+
+DESCRIPTION
+-----------
+Add or parse 'trailer' lines that look similar to RFC 822 e-mail
+headers, at the end of the otherwise free-form part of a commit
+message. For example, in the following commit message
+
+------------------------------------------------
+subject
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
+Signed-off-by: Alice <alice@xxxxxxxxxxx>
+Signed-off-by: Bob <bob@xxxxxxxxxxx>
+------------------------------------------------
+
+the last two lines starting with "Signed-off-by" are trailers.
+
+This command reads commit messages from either the
+<file> arguments or the standard input if no <file> is specified.
+If `--parse` is specified, the output consists of the parsed trailers
+coming from the input, without influencing them with any command line
+options or configuration variables.
+
+Otherwise, this command applies `trailer.*` configuration variables
+(which could potentially add new trailers, as well as reposition them),
+as well as any command line arguments that can override configuration
+variables (such as `--trailer=...` which could also add new trailers),
+to each input file. The result is emitted on the standard output.
+
+This command can also operate on the output of linkgit:git-format-patch[1],
+which is more elaborate than a plain commit message. Namely, such output
+includes a commit message (as above), a "---" divider line, and a patch part.
+For these inputs, the divider and patch parts are not modified by
+this command and are emitted as is on the output, unless
+`--no-divider` is specified.
+
+Some configuration variables control the way the `--trailer` arguments
+are applied to each input and the way any existing trailer in
+the input is changed. They also make it possible to
+automatically add some trailers.
+
+By default, a '<key>=<value>' or '<key>:<value>' argument given
+using `--trailer` will be appended after the existing trailers only if
+the last trailer has a different (<key>, <value>) pair (or if there
+is no existing trailer). The <key> and <value> parts will be trimmed
+to remove starting and trailing whitespace, and the resulting trimmed
+<key> and <value> will appear in the output like this:
+
+------------------------------------------------
+key: value
+------------------------------------------------
+
+This means that the trimmed <key> and <value> will be separated by
+`': '` (one colon followed by one space).
+
+For convenience, a <key-alias> can be configured to make using `--trailer`
+shorter to type on the command line. This can be configured using the
+'trailer.<key-alias>.key' configuration variable. The <keyAlias> must be a prefix
+of the full <key> string, although case sensitivity does not matter. For
+example, if you have
+
+------------------------------------------------
+trailer.sign.key "Signed-off-by: "
+------------------------------------------------
+
+in your configuration, you only need to specify `--trailer="sign: foo"`
+on the command line instead of `--trailer="Signed-off-by: foo"`.
+
+By default the new trailer will appear at the end of all the existing
+trailers. If there is no existing trailer, the new trailer will appear
+at the end of the input. A blank line will be added before the new
+trailer if there isn't one already.
+
+Existing trailers are extracted from the input by looking for
+a group of one or more lines that (i) is all trailers, or (ii) contains at
+least one Git-generated or user-configured trailer and consists of at
+least 25% trailers.
+The group must be preceded by one or more empty (or whitespace-only) lines.
+The group must either be at the end of the input or be the last
+non-whitespace lines before a line that starts with '---' (followed by a
+space or the end of the line).
+
+When reading trailers, there can be no whitespace before or inside the
+<key>, but any number of regular space and tab characters are allowed
+between the <key> and the separator. There can be whitespaces before,
+inside or after the <value>. The <value> may be split over multiple lines
+with each subsequent line starting with at least one whitespace, like
+the "folding" in RFC 822. Example:
+
+------------------------------------------------
+key: This is a very long value, with spaces and
+  newlines in it.
+------------------------------------------------
+
+Note that trailers do not follow (nor are they intended to follow) many of the
+rules for RFC 822 headers. For example they do not follow the encoding rule.
+
+OPTIONS
+-------
+--in-place::
+	Edit the files in place.
+
+--trim-empty::
+	If the <value> part of any trailer contains only whitespace,
+	the whole trailer will be removed from the output.
+	This applies to existing trailers as well as new trailers.
+
+--trailer <key>[(=|:)<value>]::
+	Specify a (<key>, <value>) pair that should be applied as a
+	trailer to the inputs. See the description of this
+	command.
+
+--where <placement>::
+--no-where::
+	Specify where all new trailers will be added.  A setting
+	provided with '--where' overrides the `trailer.where` and any
+	applicable `trailer.<keyAlias>.where` configuration variables
+	and applies to all '--trailer' options until the next occurrence of
+	'--where' or '--no-where'. Upon encountering '--no-where', clear the
+	effect of any previous use of '--where', such that the relevant configuration
+	variables are no longer overridden. Possible placements are `after`,
+	`before`, `end` or `start`.
+
+--if-exists <action>::
+--no-if-exists::
+	Specify what action will be performed when there is already at
+	least one trailer with the same <key> in the input.  A setting
+	provided with '--if-exists' overrides the `trailer.ifExists` and any
+	applicable `trailer.<keyAlias>.ifExists` configuration variables
+	and applies to all '--trailer' options until the next occurrence of
+	'--if-exists' or '--no-if-exists'. Upon encountering '--no-if-exists, clear the
+	effect of any previous use of '--if-exists, such that the relevant configuration
+	variables are no longer overridden. Possible actions are `addIfDifferent`,
+	`addIfDifferentNeighbor`, `add`, `replace` and `doNothing`.
+
+--if-missing <action>::
+--no-if-missing::
+	Specify what action will be performed when there is no other
+	trailer with the same <key> in the input.  A setting
+	provided with '--if-missing' overrides the `trailer.ifMissing` and any
+	applicable `trailer.<keyAlias>.ifMissing` configuration variables
+	and applies to all '--trailer' options until the next occurrence of
+	'--if-missing' or '--no-if-missing'. Upon encountering '--no-if-missing,
+	clear the effect of any previous use of '--if-missing, such that the relevant
+	configuration variables are no longer overridden. Possible actions are `doNothing`
+	or `add`.
+
+--only-trailers::
+	Output only the trailers, not any other parts of the input.
+
+--only-input::
+	Output only trailers that exist in the input; do not add any
+	from the command-line or by applying `trailer.*` configuration
+	variables.
+
+--unfold::
+	If a trailer has a value that runs over multiple lines (aka "folded"),
+	reformat the value into a single line.
+
+--parse::
+	A convenience alias for `--only-trailers --only-input
+	--unfold`. This makes it easier to only see the trailers coming from the
+	input without influencing them with any command line options or
+	configuration variables, while also making the output machine-friendly with
+	--unfold.
+
+--no-divider::
+	Do not treat `---` as the end of the commit message. Use this
+	when you know your input contains just the commit message itself
+	(and not an email or the output of `git format-patch`).
+
+CONFIGURATION VARIABLES
+-----------------------
+
+trailer.separators::
+	This option tells which characters are recognized as trailer
+	separators. By default only ':' is recognized as a trailer
+	separator, except that '=' is always accepted on the command
+	line for compatibility with other git commands.
++
+The first character given by this option will be the default character
+used when another separator is not specified in the config for this
+trailer.
++
+For example, if the value for this option is "%=$", then only lines
+using the format '<key><sep><value>' with <sep> containing '%', '='
+or '$' and then spaces will be considered trailers. And '%' will be
+the default separator used, so by default trailers will appear like:
+'<key>% <value>' (one percent sign and one space will appear between
+the key and the value).
+
+trailer.where::
+	This option tells where a new trailer will be added.
++
+This can be `end`, which is the default, `start`, `after` or `before`.
++
+If it is `end`, then each new trailer will appear at the end of the
+existing trailers.
++
+If it is `start`, then each new trailer will appear at the start,
+instead of the end, of the existing trailers.
++
+If it is `after`, then each new trailer will appear just after the
+last trailer with the same <key>.
++
+If it is `before`, then each new trailer will appear just before the
+first trailer with the same <key>.
+
+trailer.ifexists::
+	This option makes it possible to choose what action will be
+	performed when there is already at least one trailer with the
+	same <key> in the input.
++
+The valid values for this option are: `addIfDifferentNeighbor` (this
+is the default), `addIfDifferent`, `add`, `replace` or `doNothing`.
++
+With `addIfDifferentNeighbor`, a new trailer will be added only if no
+trailer with the same (<key>, <value>) pair is above or below the line
+where the new trailer will be added.
++
+With `addIfDifferent`, a new trailer will be added only if no trailer
+with the same (<key>, <value>) pair is already in the input.
++
+With `add`, a new trailer will be added, even if some trailers with
+the same (<key>, <value>) pair are already in the input.
++
+With `replace`, an existing trailer with the same <key> will be
+deleted and the new trailer will be added. The deleted trailer will be
+the closest one (with the same <key>) to the place where the new one
+will be added.
++
+With `doNothing`, nothing will be done; that is no new trailer will be
+added if there is already one with the same <key> in the input.
+
+trailer.ifmissing::
+	This option makes it possible to choose what action will be
+	performed when there is not yet any trailer with the same
+	<key> in the input.
++
+The valid values for this option are: `add` (this is the default) and
+`doNothing`.
++
+With `add`, a new trailer will be added.
++
+With `doNothing`, nothing will be done.
+
+trailer.<keyAlias>.key::
+	Defines a <keyAlias> for the <key>. The <keyAlias> must be a
+	prefix (case does not matter) of the <key>. For example, in `git
+	config trailer.ack.key "Acked-by"` the "Acked-by" is the <key> and
+	the "ack" is the <keyAlias>. This configuration allows the shorter
+	`--trailer "ack:..."` invocation on the command line using the "ack"
+	<keyAlias> instead of the longer `--trailer "Acked-by:..."`.
++
+At the end of the <key>, a separator can appear and then some
+space characters. By default the only valid separator is ':',
+but this can be changed using the `trailer.separators` config
+variable.
++
+If there is a separator in the key, then it overrides the default
+separator when adding the trailer.
+
+trailer.<keyAlias>.where::
+	This option takes the same values as the 'trailer.where'
+	configuration variable and it overrides what is specified by
+	that option for trailers with the specified <keyAlias>.
+
+trailer.<keyAlias>.ifexists::
+	This option takes the same values as the 'trailer.ifexists'
+	configuration variable and it overrides what is specified by
+	that option for trailers with the specified <keyAlias>.
+
+trailer.<keyAlias>.ifmissing::
+	This option takes the same values as the 'trailer.ifmissing'
+	configuration variable and it overrides what is specified by
+	that option for trailers with the specified <keyAlias>.
+
+trailer.<keyAlias>.command::
+	Deprecated in favor of 'trailer.<keyAlias>.cmd'.
+	This option behaves in the same way as 'trailer.<keyAlias>.cmd', except
+	that it doesn't pass anything as argument to the specified command.
+	Instead the first occurrence of substring $ARG is replaced by the
+	<value> that would be passed as argument.
++
+Note that $ARG in the user's command is
+only replaced once and that the original way of replacing $ARG is not safe.
++
+When both 'trailer.<keyAlias>.cmd' and 'trailer.<keyAlias>.command' are given
+for the same <keyAlias>, 'trailer.<keyAlias>.cmd' is used and
+'trailer.<keyAlias>.command' is ignored.
+
+trailer.<keyAlias>.cmd::
+	This option can be used to specify a shell command that will be called
+	once to automatically add a trailer with the specified <keyAlias>, and then
+	called each time a '--trailer <keyAlias>=<value>' argument is specified to
+	modify the <value> of the trailer that this option would produce.
++
+When the specified command is first called to add a trailer
+with the specified <keyAlias>, the behavior is as if a special
+'--trailer <keyAlias>=<value>' argument was added at the beginning
+of the "git interpret-trailers" command, where <value>
+is taken to be the standard output of the command with any
+leading and trailing whitespace trimmed off.
++
+If some '--trailer <keyAlias>=<value>' arguments are also passed
+on the command line, the command is called again once for each
+of these arguments with the same <keyAlias>. And the <value> part
+of these arguments, if any, will be passed to the command as its
+first argument. This way the command can produce a <value> computed
+from the <value> passed in the '--trailer <keyAlias>=<value>' argument.
+
+EXAMPLES
+--------
+
+* Configure a 'sign' trailer with a 'Signed-off-by' key, and then
+  add two of these trailers to a commit message file:
++
+------------
+$ git config trailer.sign.key "Signed-off-by"
+$ cat msg.txt
+subject
+
+body text
+$ git interpret-trailers --trailer 'sign: Alice <alice@xxxxxxxxxxx>' --trailer 'sign: Bob <bob@xxxxxxxxxxx>' <msg.txt
+subject
+
+body text
+
+Signed-off-by: Alice <alice@xxxxxxxxxxx>
+Signed-off-by: Bob <bob@xxxxxxxxxxx>
+------------
+
+* Use the `--in-place` option to edit a commit message file in place:
++
+------------
+$ cat msg.txt
+subject
+
+body text
+
+Signed-off-by: Bob <bob@xxxxxxxxxxx>
+$ git interpret-trailers --trailer 'Acked-by: Alice <alice@xxxxxxxxxxx>' --in-place msg.txt
+$ cat msg.txt
+subject
+
+body text
+
+Signed-off-by: Bob <bob@xxxxxxxxxxx>
+Acked-by: Alice <alice@xxxxxxxxxxx>
+------------
+
+* Extract the last commit as a patch, and add a 'Cc' and a
+  'Reviewed-by' trailer to it:
++
+------------
+$ git format-patch -1
+0001-foo.patch
+$ git interpret-trailers --trailer 'Cc: Alice <alice@xxxxxxxxxxx>' --trailer 'Reviewed-by: Bob <bob@xxxxxxxxxxx>' 0001-foo.patch >0001-bar.patch
+------------
+
+* Configure a 'sign' trailer with a command to automatically add a
+  'Signed-off-by: ' with the author information only if there is no
+  'Signed-off-by: ' already, and show how it works:
++
+------------
+$ cat msg1.txt
+subject
+
+body text
+$ git config trailer.sign.key "Signed-off-by: "
+$ git config trailer.sign.ifmissing add
+$ git config trailer.sign.ifexists doNothing
+$ git config trailer.sign.cmd 'echo "$(git config user.name) <$(git config user.email)>"'
+$ git interpret-trailers --trailer sign <msg1.txt
+subject
+
+body text
+
+Signed-off-by: Bob <bob@xxxxxxxxxxx>
+$ cat msg2.txt
+subject
+
+body text
+
+Signed-off-by: Alice <alice@xxxxxxxxxxx>
+$ git interpret-trailers --trailer sign <msg2.txt
+subject
+
+body text
+
+Signed-off-by: Alice <alice@xxxxxxxxxxx>
+------------
+
+* Configure a 'fix' trailer with a key that contains a '#' and no
+  space after this character, and show how it works:
++
+------------
+$ git config trailer.separators ":#"
+$ git config trailer.fix.key "Fix #"
+$ echo "subject" | git interpret-trailers --trailer fix=42
+subject
+
+Fix #42
+------------
+
+* Configure a 'help' trailer with a cmd use a script `glog-find-author`
+  which search specified author identity from git log in git repository
+  and show how it works:
++
+------------
+$ cat ~/bin/glog-find-author
+#!/bin/sh
+test -n "$1" && git log --author="$1" --pretty="%an <%ae>" -1 || true
+$ cat msg.txt
+subject
+
+body text
+$ git config trailer.help.key "Helped-by: "
+$ git config trailer.help.ifExists "addIfDifferentNeighbor"
+$ git config trailer.help.cmd "~/bin/glog-find-author"
+$ git interpret-trailers --trailer="help:Junio" --trailer="help:Couder" <msg.txt
+subject
+
+body text
+
+Helped-by: Junio C Hamano <gitster@xxxxxxxxx>
+Helped-by: Christian Couder <christian.couder@xxxxxxxxx>
+------------
+
+* Configure a 'ref' trailer with a cmd use a script `glog-grep`
+  to grep last relevant commit from git log in the git repository
+  and show how it works:
++
+------------
+$ cat ~/bin/glog-grep
+#!/bin/sh
+test -n "$1" && git log --grep "$1" --pretty=reference -1 || true
+$ cat msg.txt
+subject
+
+body text
+$ git config trailer.ref.key "Reference-to: "
+$ git config trailer.ref.ifExists "replace"
+$ git config trailer.ref.cmd "~/bin/glog-grep"
+$ git interpret-trailers --trailer="ref:Add copyright notices." <msg.txt
+subject
+
+body text
+
+Reference-to: 8bc9a0c769 (Add copyright notices., 2005-04-07)
+------------
+
+* Configure a 'see' trailer with a command to show the subject of a
+  commit that is related, and show how it works:
++
+------------
+$ cat msg.txt
+subject
+
+body text
+
+see: HEAD~2
+$ cat ~/bin/glog-ref
+#!/bin/sh
+git log -1 --oneline --format="%h (%s)" --abbrev-commit --abbrev=14
+$ git config trailer.see.key "See-also: "
+$ git config trailer.see.ifExists "replace"
+$ git config trailer.see.ifMissing "doNothing"
+$ git config trailer.see.cmd "glog-ref"
+$ git interpret-trailers --trailer=see <msg.txt
+subject
+
+body text
+
+See-also: fe3187489d69c4 (subject of related commit)
+------------
+
+* Configure a commit template with some trailers with empty values
+  (using sed to show and keep the trailing spaces at the end of the
+  trailers), then configure a commit-msg hook that uses
+  'git interpret-trailers' to remove trailers with empty values and
+  to add a 'git-version' trailer:
++
+------------
+$ cat temp.txt
+***subject***
+
+***message***
+
+Fixes: Z
+Cc: Z
+Reviewed-by: Z
+Signed-off-by: Z
+$ sed -e 's/ Z$/ /' temp.txt > commit_template.txt
+$ git config commit.template commit_template.txt
+$ cat .git/hooks/commit-msg
+#!/bin/sh
+git interpret-trailers --trim-empty --trailer "git-version: \$(git describe)" "\$1" > "\$1.new"
+mv "\$1.new" "\$1"
+$ chmod +x .git/hooks/commit-msg
+------------
+
+SEE ALSO
+--------
+linkgit:git-commit[1], linkgit:git-format-patch[1], linkgit:git-config[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-log.adoc b/Documentation/git-log.adoc
new file mode 100644
index 0000000000..0d0ed328a4
--- /dev/null
+++ b/Documentation/git-log.adoc
@@ -0,0 +1,220 @@
+git-log(1)
+==========
+
+NAME
+----
+git-log - Show commit logs
+
+
+SYNOPSIS
+--------
+[verse]
+'git log' [<options>] [<revision-range>] [[--] <path>...]
+
+DESCRIPTION
+-----------
+Shows the commit logs.
+
+:git-log: 1
+include::rev-list-description.adoc[]
+
+The command takes options applicable to the linkgit:git-rev-list[1]
+command to control what is shown and how, and options applicable to
+the linkgit:git-diff[1] command to control how the changes
+each commit introduces are shown.
+
+
+OPTIONS
+-------
+
+--follow::
+	Continue listing the history of a file beyond renames
+	(works only for a single file).
+
+--no-decorate::
+--decorate[=short|full|auto|no]::
+	Print out the ref names of any commits that are shown. If 'short' is
+	specified, the ref name prefixes 'refs/heads/', 'refs/tags/' and
+	'refs/remotes/' will not be printed. If 'full' is specified, the
+	full ref name (including prefix) will be printed. If 'auto' is
+	specified, then if the output is going to a terminal, the ref names
+	are shown as if 'short' were given, otherwise no ref names are
+	shown. The option `--decorate` is short-hand for `--decorate=short`.
+	Default to configuration value of `log.decorate` if configured,
+	otherwise, `auto`.
+
+--decorate-refs=<pattern>::
+--decorate-refs-exclude=<pattern>::
+	For each candidate reference, do not use it for decoration if it
+	matches any patterns given to `--decorate-refs-exclude` or if it
+	doesn't match any of the patterns given to `--decorate-refs`. The
+	`log.excludeDecoration` config option allows excluding refs from
+	the decorations, but an explicit `--decorate-refs` pattern will
+	override a match in `log.excludeDecoration`.
++
+If none of these options or config settings are given, then references are
+used as decoration if they match `HEAD`, `refs/heads/`, `refs/remotes/`,
+`refs/stash/`, or `refs/tags/`.
+
+--clear-decorations::
+	When specified, this option clears all previous `--decorate-refs`
+	or `--decorate-refs-exclude` options and relaxes the default
+	decoration filter to include all references. This option is
+	assumed if the config value `log.initialDecorationSet` is set to
+	`all`.
+
+--source::
+	Print out the ref name given on the command line by which each
+	commit was reached.
+
+--[no-]mailmap::
+--[no-]use-mailmap::
+	Use mailmap file to map author and committer names and email
+	addresses to canonical real names and email addresses. See
+	linkgit:git-shortlog[1].
+
+--full-diff::
+	Without this flag, `git log -p <path>...` shows commits that
+	touch the specified paths, and diffs about the same specified
+	paths.  With this, the full diff is shown for commits that touch
+	the specified paths; this means that "<path>..." limits only
+	commits, and doesn't limit diff for those commits.
++
+Note that this affects all diff-based output types, e.g. those
+produced by `--stat`, etc.
+
+--log-size::
+	Include a line ``log size <number>'' in the output for each commit,
+	where <number> is the length of that commit's message in bytes.
+	Intended to speed up tools that read log messages from `git log`
+	output by allowing them to allocate space in advance.
+
+include::line-range-options.adoc[]
+
+<revision-range>::
+	Show only commits in the specified revision range.  When no
+	<revision-range> is specified, it defaults to `HEAD` (i.e. the
+	whole history leading to the current commit).  `origin..HEAD`
+	specifies all the commits reachable from the current commit
+	(i.e. `HEAD`), but not from `origin`. For a complete list of
+	ways to spell <revision-range>, see the 'Specifying Ranges'
+	section of linkgit:gitrevisions[7].
+
+[--] <path>...::
+	Show only commits that are enough to explain how the files
+	that match the specified paths came to be.  See 'History
+	Simplification' below for details and other simplification
+	modes.
++
+Paths may need to be prefixed with `--` to separate them from
+options or the revision range, when confusion arises.
+
+include::rev-list-options.adoc[]
+
+include::pretty-formats.adoc[]
+
+DIFF FORMATTING
+---------------
+
+By default, `git log` does not generate any diff output. The options
+below can be used to show the changes made by each commit.
+
+Note that unless one of `--diff-merges` variants (including short
+`-m`, `-c`, `--cc`, and `--dd` options) is explicitly given, merge commits
+will not show a diff, even if a diff format like `--patch` is
+selected, nor will they match search options like `-S`. The exception
+is when `--first-parent` is in use, in which case `first-parent` is
+the default format for merge commits.
+
+:git-log: 1
+:diff-merges-default: `off`
+include::diff-options.adoc[]
+
+include::diff-generate-patch.adoc[]
+
+EXAMPLES
+--------
+`git log --no-merges`::
+
+	Show the whole commit history, but skip any merges
+
+`git log v2.6.12.. include/scsi drivers/scsi`::
+
+	Show all commits since version 'v2.6.12' that changed any file
+	in the `include/scsi` or `drivers/scsi` subdirectories
+
+`git log --since="2 weeks ago" -- gitk`::
+
+	Show the changes during the last two weeks to the file 'gitk'.
+	The `--` is necessary to avoid confusion with the *branch* named
+	'gitk'
+
+`git log --name-status release..test`::
+
+	Show the commits that are in the "test" branch but not yet
+	in the "release" branch, along with the list of paths
+	each commit modifies.
+
+`git log --follow builtin/rev-list.c`::
+
+	Shows the commits that changed `builtin/rev-list.c`, including
+	those commits that occurred before the file was given its
+	present name.
+
+`git log --branches --not --remotes=origin`::
+
+	Shows all commits that are in any of local branches but not in
+	any of remote-tracking branches for 'origin' (what you have that
+	origin doesn't).
+
+`git log master --not --remotes=*/master`::
+
+	Shows all commits that are in local master but not in any remote
+	repository master branches.
+
+`git log -p -m --first-parent`::
+
+	Shows the history including change diffs, but only from the
+	``main branch'' perspective, skipping commits that come from merged
+	branches, and showing full diffs of changes introduced by the merges.
+	This makes sense only when following a strict policy of merging all
+	topic branches when staying on a single integration branch.
+
+`git log -L '/int main/',/^}/:main.c`::
+
+	Shows how the function `main()` in the file `main.c` evolved
+	over time.
+
+`git log -3`::
+
+	Limits the number of commits to show to 3.
+
+DISCUSSION
+----------
+
+include::i18n.adoc[]
+
+CONFIGURATION
+-------------
+
+See linkgit:git-config[1] for core variables and linkgit:git-diff[1]
+for settings related to diff generation.
+
+format.pretty::
+	Default for the `--format` option.  (See 'Pretty Formats' above.)
+	Defaults to `medium`.
+
+i18n.logOutputEncoding::
+	Encoding to use when displaying logs.  (See 'Discussion' above.)
+	Defaults to the value of `i18n.commitEncoding` if set, and UTF-8
+	otherwise.
+
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/log.adoc[]
+
+include::config/notes.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-ls-files.adoc b/Documentation/git-ls-files.adoc
new file mode 100644
index 0000000000..58c529afbe
--- /dev/null
+++ b/Documentation/git-ls-files.adoc
@@ -0,0 +1,344 @@
+git-ls-files(1)
+===============
+
+NAME
+----
+git-ls-files - Show information about files in the index and the working tree
+
+
+SYNOPSIS
+--------
+[verse]
+'git ls-files' [-z] [-t] [-v] [-f]
+		[-c|--cached] [-d|--deleted] [-o|--others] [-i|--ignored]
+		[-s|--stage] [-u|--unmerged] [-k|--killed] [-m|--modified]
+		[--resolve-undo]
+		[--directory [--no-empty-directory]] [--eol]
+		[--deduplicate]
+		[-x <pattern>|--exclude=<pattern>]
+		[-X <file>|--exclude-from=<file>]
+		[--exclude-per-directory=<file>]
+		[--exclude-standard]
+		[--error-unmatch] [--with-tree=<tree-ish>]
+		[--full-name] [--recurse-submodules]
+		[--abbrev[=<n>]] [--format=<format>] [--] [<file>...]
+
+DESCRIPTION
+-----------
+This command merges the file listing in the index with the actual working
+directory list, and shows different combinations of the two.
+
+Several flags can be used to determine which files are
+shown, and each file may be printed multiple times if there are
+multiple entries in the index or if multiple statuses are applicable for
+the relevant file selection options.
+
+OPTIONS
+-------
+-c::
+--cached::
+	Show all files cached in Git's index, i.e. all tracked files.
+	(This is the default if no -c/-s/-d/-o/-u/-k/-m/--resolve-undo
+	options are specified.)
+
+-d::
+--deleted::
+	Show files with an unstaged deletion
+
+-m::
+--modified::
+	Show files with an unstaged modification (note that an unstaged
+	deletion also counts as an unstaged modification)
+
+-o::
+--others::
+	Show other (i.e. untracked) files in the output
+
+-i::
+--ignored::
+	Show only ignored files in the output.  Must be used with
+	either an explicit '-c' or '-o'.  When showing files in the
+	index (i.e. when used with '-c'), print only those files
+	matching an exclude pattern.  When showing "other" files
+	(i.e. when used with '-o'), show only those matched by an
+	exclude pattern.  Standard ignore rules are not automatically
+	activated; therefore, at least one of the `--exclude*` options
+	is required.
+
+-s::
+--stage::
+	Show staged contents' mode bits, object name and stage number in the output.
+
+--directory::
+	If a whole directory is classified as "other", show just its
+	name (with a trailing slash) and not its whole contents.
+	Has no effect without -o/--others.
+
+--no-empty-directory::
+	Do not list empty directories. Has no effect without --directory.
+
+-u::
+--unmerged::
+	Show information about unmerged files in the output, but do
+	not show any other tracked files (forces --stage, overrides
+	--cached).
+
+-k::
+--killed::
+	Show untracked files on the filesystem that need to be removed
+	due to file/directory conflicts for tracked files to be able to
+	be written to the filesystem.
+
+--resolve-undo::
+	Show files having resolve-undo information in the index
+	together with their resolve-undo information.  (resolve-undo
+	information is what is used to implement "git checkout -m
+	$PATH", i.e. to recreate merge conflicts that were
+	accidentally resolved)
+
+-z::
+	\0 line termination on output and do not quote filenames.
+	See OUTPUT below for more information.
+
+--deduplicate::
+	When only filenames are shown, suppress duplicates that may
+	come from having multiple stages during a merge, or giving
+	`--deleted` and `--modified` option at the same time.
+	When any of the `-t`, `--unmerged`, or `--stage` option is
+	in use, this option has no effect.
+
+-x <pattern>::
+--exclude=<pattern>::
+	Skip untracked files matching pattern.
+	Note that pattern is a shell wildcard pattern. See EXCLUDE PATTERNS
+	below for more information.
+
+-X <file>::
+--exclude-from=<file>::
+	Read exclude patterns from <file>; 1 per line.
+
+--exclude-per-directory=<file>::
+	Read additional exclude patterns that apply only to the
+	directory and its subdirectories in <file>.  If you are
+	trying to emulate the way Porcelain commands work, using
+	the `--exclude-standard` option instead is easier and more
+	thorough.
+
+--exclude-standard::
+	Add the standard Git exclusions: .git/info/exclude, .gitignore
+	in each directory, and the user's global exclusion file.
+
+--error-unmatch::
+	If any <file> does not appear in the index, treat this as an
+	error (return 1).
+
+--with-tree=<tree-ish>::
+	When using --error-unmatch to expand the user supplied
+	<file> (i.e. path pattern) arguments to paths, pretend
+	that paths which were removed in the index since the
+	named <tree-ish> are still present.  Using this option
+	with `-s` or `-u` options does not make any sense.
+
+-t::
+	Show status tags together with filenames.  Note that for
+	scripting purposes, linkgit:git-status[1] `--porcelain` and
+	linkgit:git-diff-files[1] `--name-status` are almost always
+	superior alternatives; users should look at
+	linkgit:git-status[1] `--short` or linkgit:git-diff[1]
+	`--name-status` for more user-friendly alternatives.
++
+--
+This option provides a reason for showing each filename, in the form
+of a status tag (which is followed by a space and then the filename).
+The status tags are all single characters from the following list:
+
+	H::	tracked file that is not either unmerged or skip-worktree
+	S::	tracked file that is skip-worktree
+	M::	tracked file that is unmerged
+	R::	tracked file with unstaged removal/deletion
+	C::	tracked file with unstaged modification/change
+	K::	untracked paths which are part of file/directory conflicts
+		which prevent checking out tracked files
+	?::	untracked file
+	U::     file with resolve-undo information
+--
+
+-v::
+	Similar to `-t`, but use lowercase letters for files
+	that are marked as 'assume unchanged' (see
+	linkgit:git-update-index[1]).
+
+-f::
+	Similar to `-t`, but use lowercase letters for files
+	that are marked as 'fsmonitor valid' (see
+	linkgit:git-update-index[1]).
+
+--full-name::
+	When run from a subdirectory, the command usually
+	outputs paths relative to the current directory.  This
+	option forces paths to be output relative to the project
+	top directory.
+
+--recurse-submodules::
+	Recursively calls ls-files on each active submodule in the repository.
+	Currently there is only support for the --cached and --stage modes.
+
+--abbrev[=<n>]::
+	Instead of showing the full 40-byte hexadecimal object
+	lines, show the shortest prefix that is at least '<n>'
+	hexdigits long that uniquely refers the object.
+	Non default number of digits can be specified with --abbrev=<n>.
+
+--debug::
+	After each line that describes a file, add more data about its
+	cache entry.  This is intended to show as much information as
+	possible for manual inspection; the exact format may change at
+	any time.
+
+--eol::
+	Show <eolinfo> and <eolattr> of files.
+	<eolinfo> is the file content identification used by Git when
+	the "text" attribute is "auto" (or not set and core.autocrlf is not false).
+	<eolinfo> is either "-text", "none", "lf", "crlf", "mixed" or "".
++
+"" means the file is not a regular file, it is not in the index or
+not accessible in the working tree.
++
+<eolattr> is the attribute that is used when checking out or committing,
+it is either "", "-text", "text", "text=auto", "text eol=lf", "text eol=crlf".
+Since Git 2.10 "text=auto eol=lf" and "text=auto eol=crlf" are supported.
++
+Both the <eolinfo> in the index ("i/<eolinfo>")
+and in the working tree ("w/<eolinfo>") are shown for regular files,
+followed by the  ("attr/<eolattr>").
+
+--sparse::
+	If the index is sparse, show the sparse directories without expanding
+	to the contained files. Sparse directories will be shown with a
+	trailing slash, such as "x/" for a sparse directory "x".
+
+--format=<format>::
+	A string that interpolates `%(fieldname)` from the result being shown.
+	It also interpolates `%%` to `%`, and `%xXX` where `XX` are hex digits
+	interpolates to character with hex code `XX`; for example `%x00`
+	interpolates to `\0` (NUL), `%x09` to `\t` (TAB) and %x0a to `\n` (LF).
+	--format cannot be combined with `-s`, `-o`, `-k`, `-t`, `--resolve-undo`
+	and `--eol`.
+\--::
+	Do not interpret any more arguments as options.
+
+<file>::
+	Files to show. If no files are given all files which match the other
+	specified criteria are shown.
+
+OUTPUT
+------
+'git ls-files' just outputs the filenames unless `--stage` is specified in
+which case it outputs:
+
+        [<tag> ]<mode> <object> <stage> <file>
+
+'git ls-files --eol' will show
+	i/<eolinfo><SPACES>w/<eolinfo><SPACES>attr/<eolattr><SPACE*><TAB><file>
+
+'git ls-files --unmerged' and 'git ls-files --stage' can be used to examine
+detailed information on unmerged paths.
+
+For an unmerged path, instead of recording a single mode/SHA-1 pair,
+the index records up to three such pairs; one from tree O in stage
+1, A in stage 2, and B in stage 3.  This information can be used by
+the user (or the porcelain) to see what should eventually be recorded at the
+path. (see linkgit:git-read-tree[1] for more information on state)
+
+Without the `-z` option, pathnames with "unusual" characters are
+quoted as explained for the configuration variable `core.quotePath`
+(see linkgit:git-config[1]).  Using `-z` the filename is output
+verbatim and the line is terminated by a NUL byte.
+
+It is possible to print in a custom format by using the `--format`
+option, which is able to interpolate different fields using
+a `%(fieldname)` notation. For example, if you only care about the
+"objectname" and "path" fields, you can execute with a specific
+"--format" like
+
+	git ls-files --format='%(objectname) %(path)'
+
+FIELD NAMES
+-----------
+The way each path is shown can be customized by using the
+`--format=<format>` option, where the %(fieldname) in the
+<format> string for various aspects of the index entry are
+interpolated.  The following "fieldname" are understood:
+
+objectmode::
+	The mode of the file which is recorded in the index.
+objecttype::
+	The object type of the file which is recorded in the index.
+objectname::
+	The name of the file which is recorded in the index.
+objectsize[:padded]::
+	The object size of the file which is recorded in the index
+	("-" if the object is a `commit` or `tree`).
+	It also supports a padded format of size with "%(objectsize:padded)".
+stage::
+	The stage of the file which is recorded in the index.
+eolinfo:index::
+eolinfo:worktree::
+	The <eolinfo> (see the description of the `--eol` option) of
+	the contents in the index or in the worktree for the path.
+eolattr::
+	The <eolattr> (see the description of the `--eol` option)
+	that applies to the path.
+path::
+	The pathname of the file which is recorded in the index.
+
+EXCLUDE PATTERNS
+----------------
+
+'git ls-files' can use a list of "exclude patterns" when
+traversing the directory tree and finding files to show when the
+flags --others or --ignored are specified.  linkgit:gitignore[5]
+specifies the format of exclude patterns.
+
+These exclude patterns can be specified from the following places,
+in order:
+
+  1. The command-line flag --exclude=<pattern> specifies a
+     single pattern.  Patterns are ordered in the same order
+     they appear in the command line.
+
+  2. The command-line flag --exclude-from=<file> specifies a
+     file containing a list of patterns.  Patterns are ordered
+     in the same order they appear in the file.
+
+  3. The command-line flag --exclude-per-directory=<name> specifies
+     a name of the file in each directory 'git ls-files'
+     examines, normally `.gitignore`.  Files in deeper
+     directories take precedence.  Patterns are ordered in the
+     same order they appear in the files.
+
+A pattern specified on the command line with --exclude or read
+from the file specified with --exclude-from is relative to the
+top of the directory tree.  A pattern read from a file specified
+by --exclude-per-directory is relative to the directory that the
+pattern file appears in.
+
+Generally, you should be able to use `--exclude-standard` when you
+want the exclude rules applied the same way as what Porcelain
+commands do.  To emulate what `--exclude-standard` specifies, you
+can give `--exclude-per-directory=.gitignore`, and then specify:
+
+  1. The file specified by the `core.excludesfile` configuration
+     variable, if exists, or the `$XDG_CONFIG_HOME/git/ignore` file.
+
+  2. The `$GIT_DIR/info/exclude` file.
+
+via the `--exclude-from=` option.
+
+SEE ALSO
+--------
+linkgit:git-read-tree[1], linkgit:gitignore[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-ls-remote.adoc b/Documentation/git-ls-remote.adoc
new file mode 100644
index 0000000000..d71c4ab3e2
--- /dev/null
+++ b/Documentation/git-ls-remote.adoc
@@ -0,0 +1,157 @@
+git-ls-remote(1)
+================
+
+NAME
+----
+git-ls-remote - List references in a remote repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git ls-remote' [--branches] [--tags] [--refs] [--upload-pack=<exec>]
+	      [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]
+	      [--symref] [<repository> [<patterns>...]]
+
+DESCRIPTION
+-----------
+Displays references available in a remote repository along with the associated
+commit IDs.
+
+
+OPTIONS
+-------
+-b::
+--branches::
+-t::
+--tags::
+	Limit to only local branches and local tags, respectively.
+	These options are _not_ mutually exclusive; when given
+	both, references stored in refs/heads and refs/tags are
+	displayed.  Note that `--heads` and `-h` are deprecated
+	synonyms for `--branches` and `-b` and may be removed in
+	the future.  Also note that `git ls-remote -h` used without
+	anything else on the command line gives help, consistent
+	with other git subcommands.
+
+--refs::
+	Do not show peeled tags or pseudorefs like `HEAD` in the output.
+
+-q::
+--quiet::
+	Do not print remote URL to stderr.
+
+--upload-pack=<exec>::
+	Specify the full path of 'git-upload-pack' on the remote
+	host. This allows listing references from repositories accessed via
+	SSH and where the SSH daemon does not use the PATH configured by the
+	user.
+
+--exit-code::
+	Exit with status "2" when no matching refs are found in the remote
+	repository. Usually the command exits with status "0" to indicate
+	it successfully talked with the remote repository, whether it
+	found any matching refs.
+
+--get-url::
+	Expand the URL of the given remote repository taking into account any
+	"url.<base>.insteadOf" config setting (See linkgit:git-config[1]) and
+	exit without talking to the remote.
+
+--symref::
+	In addition to the object pointed by it, show the underlying
+	ref pointed by it when showing a symbolic ref.  Currently,
+	upload-pack only shows the symref HEAD, so it will be the only
+	one shown by ls-remote.
+
+--sort=<key>::
+	Sort based on the key given. Prefix `-` to sort in descending order
+	of the value. Supports "version:refname" or "v:refname" (tag names
+	are treated as versions). The "version:refname" sort order can also
+	be affected by the "versionsort.suffix" configuration variable.
+	See linkgit:git-for-each-ref[1] for more sort options, but be aware
+	keys like `committerdate` that require access to the objects
+	themselves will not work for refs whose objects have not yet been
+	fetched from the remote, and will give a `missing object` error.
+
+-o <option>::
+--server-option=<option>::
+	Transmit the given string to the server when communicating using
+	protocol version 2.  The given string must not contain a NUL or LF
+	character.
+	When multiple `--server-option=<option>` are given, they are all
+	sent to the other side in the order listed on the command line.
+	When no `--server-option=<option>` is given from the command line,
+	the values of configuration variable `remote.<name>.serverOption`
+	are used instead.
+
+<repository>::
+	The "remote" repository to query.  This parameter can be
+	either a URL or the name of a remote (see the GIT URLS and
+	REMOTES sections of linkgit:git-fetch[1]).
+
+<patterns>...::
+	When unspecified, all references, after filtering done
+	with --heads and --tags, are shown.  When <patterns>... are
+	specified, only references matching one or more of the given
+	patterns are displayed. Each pattern is interpreted as a glob
+	(see `glob` in linkgit:gitglossary[7]) which is matched against
+	the "tail" of a ref, starting either from the start of the ref
+	(so a full name like `refs/heads/foo` matches) or from a slash
+	separator (so `bar` matches `refs/heads/bar` but not
+	`refs/heads/foobar`).
+
+OUTPUT
+------
+
+The output is in the format:
+
+------------
+<oid> TAB <ref> LF
+------------
+
+When showing an annotated tag, unless `--refs` is given, two such
+lines are shown: one with the refname for the tag itself as `<ref>`,
+and another with `<ref>` followed by `^{}`. The `<oid>` on the latter
+line shows the name of the object the tag points at.
+
+EXAMPLES
+--------
+
+* List all references (including symbolics and pseudorefs), peeling
+  tags:
++
+----
+$ git ls-remote
+27d43aaaf50ef0ae014b88bba294f93658016a2e	HEAD
+950264636c68591989456e3ba0a5442f93152c1a	refs/heads/main
+d9ab777d41f92a8c1684c91cfb02053d7dd1046b	refs/heads/next
+d4ca2e3147b409459955613c152220f4db848ee1	refs/tags/v2.40.0
+73876f4861cd3d187a4682290ab75c9dccadbc56	refs/tags/v2.40.0^{}
+----
+
+* List all references matching given patterns:
++
+----
+$ git ls-remote http://www.kernel.org/pub/scm/git/git.git master seen rc
+5fe978a5381f1fbad26a80e682ddd2a401966740	refs/heads/master
+c781a84b5204fb294c9ccc79f8b3baceeb32c061	refs/heads/seen
+----
+
+* List only tags matching a given wildcard pattern:
++
+----
+$ git ls-remote --tags http://www.kernel.org/pub/scm/git/git.git v\*
+485a869c64a68cc5795dd99689797c5900f4716d	refs/tags/v2.39.2
+cbf04937d5b9fcf0a76c28f69e6294e9e3ecd7e6	refs/tags/v2.39.2^{}
+d4ca2e3147b409459955613c152220f4db848ee1	refs/tags/v2.40.0
+73876f4861cd3d187a4682290ab75c9dccadbc56	refs/tags/v2.40.0^{}
+----
+
+SEE ALSO
+--------
+linkgit:git-check-ref-format[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-ls-tree.adoc b/Documentation/git-ls-tree.adoc
new file mode 100644
index 0000000000..6572095d8d
--- /dev/null
+++ b/Documentation/git-ls-tree.adoc
@@ -0,0 +1,165 @@
+git-ls-tree(1)
+==============
+
+NAME
+----
+git-ls-tree - List the contents of a tree object
+
+
+SYNOPSIS
+--------
+[verse]
+'git ls-tree' [-d] [-r] [-t] [-l] [-z]
+	    [--name-only] [--name-status] [--object-only] [--full-name] [--full-tree] [--abbrev[=<n>]] [--format=<format>]
+	    <tree-ish> [<path>...]
+
+DESCRIPTION
+-----------
+Lists the contents of a given tree object, like what "/bin/ls -a" does
+in the current working directory.  Note that:
+
+ - the behaviour is slightly different from that of "/bin/ls" in that the
+   '<path>' denotes just a list of patterns to match, e.g. so specifying
+   directory name (without `-r`) will behave differently, and order of the
+   arguments does not matter.
+
+ - the behaviour is similar to that of "/bin/ls" in that the '<path>' is
+   taken as relative to the current working directory.  E.g. when you are
+   in a directory 'sub' that has a directory 'dir', you can run 'git
+   ls-tree -r HEAD dir' to list the contents of the tree (that is
+   `sub/dir` in `HEAD`).  You don't want to give a tree that is not at the
+   root level (e.g. `git ls-tree -r HEAD:sub dir`) in this case, as that
+   would result in asking for `sub/sub/dir` in the `HEAD` commit.
+   However, the current working directory can be ignored by passing
+   --full-tree option.
+
+OPTIONS
+-------
+<tree-ish>::
+	Id of a tree-ish.
+
+-d::
+	Show only the named tree entry itself, not its children.
+
+-r::
+	Recurse into sub-trees.
+
+-t::
+	Show tree entries even when going to recurse them. Has no effect
+	if `-r` was not passed. `-d` implies `-t`.
+
+-l::
+--long::
+	Show object size of blob (file) entries.
+
+-z::
+	\0 line termination on output and do not quote filenames.
+	See OUTPUT FORMAT below for more information.
+
+--name-only::
+--name-status::
+	List only filenames (instead of the "long" output), one per line.
+	Cannot be combined with `--object-only`.
+
+--object-only::
+	List only names of the objects, one per line. Cannot be combined
+	with `--name-only` or `--name-status`.
+	This is equivalent to specifying `--format='%(objectname)'`, but
+	for both this option and that exact format the command takes a
+	hand-optimized codepath instead of going through the generic
+	formatting mechanism.
+
+--abbrev[=<n>]::
+	Instead of showing the full 40-byte hexadecimal object
+	lines, show the shortest prefix that is at least '<n>'
+	hexdigits long that uniquely refers the object.
+	Non default number of digits can be specified with --abbrev=<n>.
+
+--full-name::
+	Instead of showing the path names relative to the current working
+	directory, show the full path names.
+
+--full-tree::
+	Do not limit the listing to the current working directory.
+	Implies --full-name.
+
+--format=<format>::
+	A string that interpolates `%(fieldname)` from the result
+	being shown. It also interpolates `%%` to `%`, and
+	`%xNN` where `NN` are hex digits interpolates to character
+	with hex code `NN`; for example `%x00` interpolates to
+	`\0` (NUL), `%x09` to `\t` (TAB) and `%x0a` to `\n` (LF).
+	When specified, `--format` cannot be combined with other
+	format-altering options, including `--long`, `--name-only`
+	and `--object-only`.
+
+[<path>...]::
+	When paths are given, show them (note that this isn't really raw
+	pathnames, but rather a list of patterns to match).  Otherwise
+	implicitly uses the root level of the tree as the sole path argument.
+
+
+Output Format
+-------------
+
+The output format of `ls-tree` is determined by either the `--format`
+option, or other format-altering options such as `--name-only` etc.
+(see `--format` above).
+
+The use of certain `--format` directives is equivalent to using those
+options, but invoking the full formatting machinery can be slower than
+using an appropriate formatting option.
+
+In cases where the `--format` would exactly map to an existing option
+`ls-tree` will use the appropriate faster path. Thus the default format
+is equivalent to:
+
+	%(objectmode) %(objecttype) %(objectname)%x09%(path)
+
+This output format is compatible with what `--index-info --stdin` of
+'git update-index' expects.
+
+When the `-l` option is used, format changes to
+
+	%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)
+
+Object size identified by <objectname> is given in bytes, and right-justified
+with minimum width of 7 characters.  Object size is given only for blobs
+(file) entries; for other entries `-` character is used in place of size.
+
+Without the `-z` option, pathnames with "unusual" characters are
+quoted as explained for the configuration variable `core.quotePath`
+(see linkgit:git-config[1]).  Using `-z` the filename is output
+verbatim and the line is terminated by a NUL byte.
+
+Customized format:
+
+It is possible to print in a custom format by using the `--format` option,
+which is able to interpolate different fields using a `%(fieldname)` notation.
+For example, if you only care about the "objectname" and "path" fields, you
+can execute with a specific "--format" like
+
+	git ls-tree --format='%(objectname) %(path)' <tree-ish>
+
+FIELD NAMES
+-----------
+
+Various values from structured fields can be used to interpolate
+into the resulting output. For each outputting line, the following
+names can be used:
+
+objectmode::
+	The mode of the object.
+objecttype::
+	The type of the object (`commit`, `blob` or `tree`).
+objectname::
+	The name of the object.
+objectsize[:padded]::
+	The size of a `blob` object ("-" if it's a `commit` or `tree`).
+	It also supports a padded format of size with "%(objectsize:padded)".
+path::
+	The pathname of the object.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mailinfo.adoc b/Documentation/git-mailinfo.adoc
new file mode 100644
index 0000000000..87c9e1cffa
--- /dev/null
+++ b/Documentation/git-mailinfo.adoc
@@ -0,0 +1,127 @@
+git-mailinfo(1)
+===============
+
+NAME
+----
+git-mailinfo - Extracts patch and authorship from a single e-mail message
+
+
+SYNOPSIS
+--------
+[verse]
+'git mailinfo' [-k|-b] [-u | --encoding=<encoding> | -n]
+	       [--[no-]scissors] [--quoted-cr=<action>]
+	       <msg> <patch>
+
+
+DESCRIPTION
+-----------
+Reads a single e-mail message from the standard input, and
+writes the commit log message in <msg> file, and the patches in
+<patch> file.  The author name, e-mail and e-mail subject are
+written out to the standard output to be used by 'git am'
+to create a commit.  It is usually not necessary to use this
+command directly.  See linkgit:git-am[1] instead.
+
+
+OPTIONS
+-------
+-k::
+	Usually the program removes email cruft from the Subject:
+	header line to extract the title line for the commit log
+	message.  This option prevents this munging, and is most
+	useful when used to read back 'git format-patch -k' output.
++
+Specifically, the following are removed until none of them remain:
++
+--
+*	Leading and trailing whitespace.
+
+*	Leading `Re:`, `re:`, and `:`.
+
+*	Leading bracketed strings (between `[` and `]`, usually
+	`[PATCH]`).
+--
++
+Finally, runs of whitespace are normalized to a single ASCII space
+character.
+
+-b::
+	When -k is not in effect, all leading strings bracketed with '['
+	and ']' pairs are stripped.  This option limits the stripping to
+	only the pairs whose bracketed string contains the word "PATCH".
+
+-u::
+	The commit log message, author name and author email are
+	taken from the e-mail, and after minimally decoding MIME
+	transfer encoding, re-coded in the charset specified by
+	`i18n.commitEncoding` (defaulting to UTF-8) by transliterating
+	them.  This used to be optional but now it is the default.
++
+Note that the patch is always used as-is without charset
+conversion, even with this flag.
+
+--encoding=<encoding>::
+	Similar to -u.  But when re-coding, the charset specified here is
+	used instead of the one specified by `i18n.commitEncoding` or UTF-8.
+
+-n::
+	Disable all charset re-coding of the metadata.
+
+-m::
+--message-id::
+	Copy the Message-ID header at the end of the commit message.  This
+	is useful in order to associate commits with mailing list discussions.
+
+--scissors::
+	Remove everything in body before a scissors line (e.g. "-- >8 --").
+	The line represents scissors and perforation marks, and is used to
+	request the reader to cut the message at that line.  If that line
+	appears in the body of the message before the patch, everything
+	before it (including the scissors line itself) is ignored when
+	this option is used.
++
+This is useful if you want to begin your message in a discussion thread
+with comments and suggestions on the message you are responding to, and to
+conclude it with a patch submission, separating the discussion and the
+beginning of the proposed commit log message with a scissors line.
++
+This can be enabled by default with the configuration option mailinfo.scissors.
+
+--no-scissors::
+	Ignore scissors lines. Useful for overriding mailinfo.scissors settings.
+
+--quoted-cr=<action>::
+	Action when processes email messages sent with base64 or
+	quoted-printable encoding, and the decoded lines end with a CRLF
+	instead of a simple LF.
++
+The valid actions are:
++
+--
+*	`nowarn`: Git will do nothing when such a CRLF is found.
+*	`warn`: Git will issue a warning for each message if such a CRLF is
+	found.
+*	`strip`: Git will convert those CRLF to LF.
+--
++
+The default action could be set by configuration option `mailinfo.quotedCR`.
+If no such configuration option has been set, `warn` will be used.
+
+<msg>::
+	The commit log message extracted from e-mail, usually
+	except the title line which comes from e-mail Subject.
+
+<patch>::
+	The patch extracted from e-mail.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/mailinfo.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mailsplit.adoc b/Documentation/git-mailsplit.adoc
new file mode 100644
index 0000000000..3f0a6662c8
--- /dev/null
+++ b/Documentation/git-mailsplit.adoc
@@ -0,0 +1,57 @@
+git-mailsplit(1)
+================
+
+NAME
+----
+git-mailsplit - Simple UNIX mbox splitter program
+
+SYNOPSIS
+--------
+[verse]
+'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] [--mboxrd]
+		-o<directory> [--] [(<mbox>|<Maildir>)...]
+
+DESCRIPTION
+-----------
+Splits a mbox file or a Maildir into a list of files: "0001" "0002" ..  in the
+specified directory so you can process them further from there.
+
+IMPORTANT: Maildir splitting relies upon filenames being sorted to output
+patches in the correct order.
+
+OPTIONS
+-------
+<mbox>::
+	Mbox file to split.  If not given, the mbox is read from
+	the standard input.
+
+<Maildir>::
+	Root of the Maildir to split. This directory should contain the cur, tmp
+	and new subdirectories.
+
+-o<directory>::
+	Directory in which to place the individual messages.
+
+-b::
+	If any file doesn't begin with a From line, assume it is a
+	single mail message instead of signaling an error.
+
+-d<prec>::
+	Instead of the default 4 digits with leading zeros,
+	different precision can be specified for the generated
+	filenames.
+
+-f<nn>::
+	Skip the first <nn> numbers, for example if -f3 is specified,
+	start the numbering with 0004.
+
+--keep-cr::
+	Do not remove `\r` from lines ending with `\r\n`.
+
+--mboxrd::
+	Input is of the "mboxrd" format and "^>+From " line escaping is
+	reversed.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-maintenance.adoc b/Documentation/git-maintenance.adoc
new file mode 100644
index 0000000000..f4aff5d990
--- /dev/null
+++ b/Documentation/git-maintenance.adoc
@@ -0,0 +1,419 @@
+git-maintenance(1)
+==================
+
+NAME
+----
+git-maintenance - Run tasks to optimize Git repository data
+
+
+SYNOPSIS
+--------
+[verse]
+'git maintenance' run [<options>]
+'git maintenance' start [--scheduler=<scheduler>]
+'git maintenance' (stop|register|unregister) [<options>]
+
+
+DESCRIPTION
+-----------
+Run tasks to optimize Git repository data, speeding up other Git commands
+and reducing storage requirements for the repository.
+
+Git commands that add repository data, such as `git add` or `git fetch`,
+are optimized for a responsive user experience. These commands do not take
+time to optimize the Git data, since such optimizations scale with the full
+size of the repository while these user commands each perform a relatively
+small action.
+
+The `git maintenance` command provides flexibility for how to optimize the
+Git repository.
+
+SUBCOMMANDS
+-----------
+
+run::
+	Run one or more maintenance tasks. If one or more `--task` options
+	are specified, then those tasks are run in that order. Otherwise,
+	the tasks are determined by which `maintenance.<task>.enabled`
+	config options are true. By default, only `maintenance.gc.enabled`
+	is true.
+
+start::
+	Start running maintenance on the current repository. This performs
+	the same config updates as the `register` subcommand, then updates
+	the background scheduler to run `git maintenance run --scheduled`
+	on an hourly basis.
+
+stop::
+	Halt the background maintenance schedule. The current repository
+	is not removed from the list of maintained repositories, in case
+	the background maintenance is restarted later.
+
+register::
+	Initialize Git config values so any scheduled maintenance will start
+	running on this repository. This adds the repository to the
+	`maintenance.repo` config variable in the current user's global config,
+	or the config specified by --config-file option, and enables some
+	recommended configuration values for `maintenance.<task>.schedule`. The
+	tasks that are enabled are safe for running in the background without
+	disrupting foreground processes.
++
+The `register` subcommand will also set the `maintenance.strategy` config
+value to `incremental`, if this value is not previously set. The
+`incremental` strategy uses the following schedule for each maintenance
+task:
++
+--
+* `gc`: disabled.
+* `commit-graph`: hourly.
+* `prefetch`: hourly.
+* `loose-objects`: daily.
+* `incremental-repack`: daily.
+--
++
+`git maintenance register` will also disable foreground maintenance by
+setting `maintenance.auto = false` in the current repository. This config
+setting will remain after a `git maintenance unregister` command.
+
+unregister::
+	Remove the current repository from background maintenance. This
+	only removes the repository from the configured list. It does not
+	stop the background maintenance processes from running.
++
+The `unregister` subcommand will report an error if the current repository
+is not already registered. Use the `--force` option to return success even
+when the current repository is not registered.
+
+TASKS
+-----
+
+commit-graph::
+	The `commit-graph` job updates the `commit-graph` files incrementally,
+	then verifies that the written data is correct. The incremental
+	write is safe to run alongside concurrent Git processes since it
+	will not expire `.graph` files that were in the previous
+	`commit-graph-chain` file. They will be deleted by a later run based
+	on the expiration delay.
+
+prefetch::
+	The `prefetch` task updates the object directory with the latest
+	objects from all registered remotes. For each remote, a `git fetch`
+	command is run. The configured refspec is modified to place all
+	requested refs within `refs/prefetch/`. Also, tags are not updated.
++
+This is done to avoid disrupting the remote-tracking branches. The end users
+expect these refs to stay unmoved unless they initiate a fetch.  However,
+with the prefetch task, the objects necessary to complete a later real fetch
+would already be obtained, making the real fetch faster.  In the ideal case,
+it will just become an update to a bunch of remote-tracking branches without
+any object transfer.
++
+The `remote.<name>.skipFetchAll` configuration can be used to
+exclude a particular remote from getting prefetched.
+
+gc::
+	Clean up unnecessary files and optimize the local repository. "GC"
+	stands for "garbage collection," but this task performs many
+	smaller tasks. This task can be expensive for large repositories,
+	as it repacks all Git objects into a single pack-file. It can also
+	be disruptive in some situations, as it deletes stale data. See
+	linkgit:git-gc[1] for more details on garbage collection in Git.
+
+loose-objects::
+	The `loose-objects` job cleans up loose objects and places them into
+	pack-files. In order to prevent race conditions with concurrent Git
+	commands, it follows a two-step process. First, it deletes any loose
+	objects that already exist in a pack-file; concurrent Git processes
+	will examine the pack-file for the object data instead of the loose
+	object. Second, it creates a new pack-file (starting with "loose-")
+	containing a batch of loose objects. The batch size is limited to 50
+	thousand objects to prevent the job from taking too long on a
+	repository with many loose objects. The `gc` task writes unreachable
+	objects as loose objects to be cleaned up by a later step only if
+	they are not re-added to a pack-file; for this reason it is not
+	advisable to enable both the `loose-objects` and `gc` tasks at the
+	same time.
+
+incremental-repack::
+	The `incremental-repack` job repacks the object directory
+	using the `multi-pack-index` feature. In order to prevent race
+	conditions with concurrent Git commands, it follows a two-step
+	process. First, it calls `git multi-pack-index expire` to delete
+	pack-files unreferenced by the `multi-pack-index` file. Second, it
+	calls `git multi-pack-index repack` to select several small
+	pack-files and repack them into a bigger one, and then update the
+	`multi-pack-index` entries that refer to the small pack-files to
+	refer to the new pack-file. This prepares those small pack-files
+	for deletion upon the next run of `git multi-pack-index expire`.
+	The selection of the small pack-files is such that the expected
+	size of the big pack-file is at least the batch size; see the
+	`--batch-size` option for the `repack` subcommand in
+	linkgit:git-multi-pack-index[1]. The default batch-size is zero,
+	which is a special case that attempts to repack all pack-files
+	into a single pack-file.
+
+pack-refs::
+	The `pack-refs` task collects the loose reference files and
+	collects them into a single file. This speeds up operations that
+	need to iterate across many references. See linkgit:git-pack-refs[1]
+	for more information.
+
+OPTIONS
+-------
+--auto::
+	When combined with the `run` subcommand, run maintenance tasks
+	only if certain thresholds are met. For example, the `gc` task
+	runs when the number of loose objects exceeds the number stored
+	in the `gc.auto` config setting, or when the number of pack-files
+	exceeds the `gc.autoPackLimit` config setting. Not compatible with
+	the `--schedule` option.
+
+--schedule::
+	When combined with the `run` subcommand, run maintenance tasks
+	only if certain time conditions are met, as specified by the
+	`maintenance.<task>.schedule` config value for each `<task>`.
+	This config value specifies a number of seconds since the last
+	time that task ran, according to the `maintenance.<task>.lastRun`
+	config value. The tasks that are tested are those provided by
+	the `--task=<task>` option(s) or those with
+	`maintenance.<task>.enabled` set to true.
+
+--quiet::
+	Do not report progress or other information over `stderr`.
+
+--task=<task>::
+	If this option is specified one or more times, then only run the
+	specified tasks in the specified order. If no `--task=<task>`
+	arguments are specified, then only the tasks with
+	`maintenance.<task>.enabled` configured as `true` are considered.
+	See the 'TASKS' section for the list of accepted `<task>` values.
+
+--scheduler=auto|crontab|systemd-timer|launchctl|schtasks::
+	When combined with the `start` subcommand, specify the scheduler
+	for running the hourly, daily and weekly executions of
+	`git maintenance run`.
+	Possible values for `<scheduler>` are `auto`, `crontab`
+	(POSIX), `systemd-timer` (Linux), `launchctl` (macOS), and
+	`schtasks` (Windows). When `auto` is specified, the
+	appropriate platform-specific scheduler is used; on Linux,
+	`systemd-timer` is used if available, otherwise
+	`crontab`. Default is `auto`.
+
+
+TROUBLESHOOTING
+---------------
+The `git maintenance` command is designed to simplify the repository
+maintenance patterns while minimizing user wait time during Git commands.
+A variety of configuration options are available to allow customizing this
+process. The default maintenance options focus on operations that complete
+quickly, even on large repositories.
+
+Users may find some cases where scheduled maintenance tasks do not run as
+frequently as intended. Each `git maintenance run` command takes a lock on
+the repository's object database, and this prevents other concurrent
+`git maintenance run` commands from running on the same repository. Without
+this safeguard, competing processes could leave the repository in an
+unpredictable state.
+
+The background maintenance schedule runs `git maintenance run` processes
+on an hourly basis. Each run executes the "hourly" tasks. At midnight,
+that process also executes the "daily" tasks. At midnight on the first day
+of the week, that process also executes the "weekly" tasks. A single
+process iterates over each registered repository, performing the scheduled
+tasks for that frequency. The processes are scheduled to a random minute of
+the hour per client to spread out the load that multiple clients might
+generate (e.g. from prefetching). Depending on the number of registered
+repositories and their sizes, this process may take longer than an hour.
+In this case, multiple `git maintenance run` commands may run on the same
+repository at the same time, colliding on the object database lock. This
+results in one of the two tasks not running.
+
+If you find that some maintenance windows are taking longer than one hour
+to complete, then consider reducing the complexity of your maintenance
+tasks. For example, the `gc` task is much slower than the
+`incremental-repack` task. However, this comes at a cost of a slightly
+larger object database. Consider moving more expensive tasks to be run
+less frequently.
+
+Expert users may consider scheduling their own maintenance tasks using a
+different schedule than is available through `git maintenance start` and
+Git configuration options. These users should be aware of the object
+database lock and how concurrent `git maintenance run` commands behave.
+Further, the `git gc` command should not be combined with
+`git maintenance run` commands. `git gc` modifies the object database
+but does not take the lock in the same way as `git maintenance run`. If
+possible, use `git maintenance run --task=gc` instead of `git gc`.
+
+The following sections describe the mechanisms put in place to run
+background maintenance by `git maintenance start` and how to customize
+them.
+
+BACKGROUND MAINTENANCE ON POSIX SYSTEMS
+---------------------------------------
+
+The standard mechanism for scheduling background tasks on POSIX systems
+is cron(8). This tool executes commands based on a given schedule. The
+current list of user-scheduled tasks can be found by running `crontab -l`.
+The schedule written by `git maintenance start` is similar to this:
+
+-----------------------------------------------------------------------
+# BEGIN GIT MAINTENANCE SCHEDULE
+# The following schedule was created by Git
+# Any edits made in this region might be
+# replaced in the future by a Git command.
+
+0 1-23 * * * "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=hourly
+0 0 * * 1-6 "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=daily
+0 0 * * 0 "/<path>/git" --exec-path="/<path>" for-each-repo --config=maintenance.repo maintenance run --schedule=weekly
+
+# END GIT MAINTENANCE SCHEDULE
+-----------------------------------------------------------------------
+
+The comments are used as a region to mark the schedule as written by Git.
+Any modifications within this region will be completely deleted by
+`git maintenance stop` or overwritten by `git maintenance start`.
+
+The `crontab` entry specifies the full path of the `git` executable to
+ensure that the executed `git` command is the same one with which
+`git maintenance start` was issued independent of `PATH`. If the same user
+runs `git maintenance start` with multiple Git executables, then only the
+latest executable is used.
+
+These commands use `git for-each-repo --config=maintenance.repo` to run
+`git maintenance run --schedule=<frequency>` on each repository listed in
+the multi-valued `maintenance.repo` config option. These are typically
+loaded from the user-specific global config. The `git maintenance` process
+then determines which maintenance tasks are configured to run on each
+repository with each `<frequency>` using the `maintenance.<task>.schedule`
+config options. These values are loaded from the global or repository
+config values.
+
+If the config values are insufficient to achieve your desired background
+maintenance schedule, then you can create your own schedule. If you run
+`crontab -e`, then an editor will load with your user-specific `cron`
+schedule. In that editor, you can add your own schedule lines. You could
+start by adapting the default schedule listed earlier, or you could read
+the crontab(5) documentation for advanced scheduling techniques. Please
+do use the full path and `--exec-path` techniques from the default
+schedule to ensure you are executing the correct binaries in your
+schedule.
+
+
+BACKGROUND MAINTENANCE ON LINUX SYSTEMD SYSTEMS
+-----------------------------------------------
+
+While Linux supports `cron`, depending on the distribution, `cron` may
+be an optional package not necessarily installed. On modern Linux
+distributions, systemd timers are superseding it.
+
+If user systemd timers are available, they will be used as a replacement
+of `cron`.
+
+In this case, `git maintenance start` will create user systemd timer units
+and start the timers. The current list of user-scheduled tasks can be found
+by running `systemctl --user list-timers`. The timers written by `git
+maintenance start` are similar to this:
+
+-----------------------------------------------------------------------
+$ systemctl --user list-timers
+NEXT                         LEFT          LAST                         PASSED     UNIT                         ACTIVATES
+Thu 2021-04-29 19:00:00 CEST 42min left    Thu 2021-04-29 18:00:11 CEST 17min ago  git-maintenance@hourly.timer git-maintenance@hourly.service
+Fri 2021-04-30 00:00:00 CEST 5h 42min left Thu 2021-04-29 00:00:11 CEST 18h ago    git-maintenance@daily.timer  git-maintenance@daily.service
+Mon 2021-05-03 00:00:00 CEST 3 days left   Mon 2021-04-26 00:00:11 CEST 3 days ago git-maintenance@weekly.timer git-maintenance@weekly.service
+-----------------------------------------------------------------------
+
+One timer is registered for each `--schedule=<frequency>` option.
+
+The definition of the systemd units can be inspected in the following files:
+
+-----------------------------------------------------------------------
+~/.config/systemd/user/git-maintenance@.timer
+~/.config/systemd/user/git-maintenance@.service
+~/.config/systemd/user/timers.target.wants/git-maintenance@hourly.timer
+~/.config/systemd/user/timers.target.wants/git-maintenance@daily.timer
+~/.config/systemd/user/timers.target.wants/git-maintenance@weekly.timer
+-----------------------------------------------------------------------
+
+`git maintenance start` will overwrite these files and start the timer
+again with `systemctl --user`, so any customization should be done by
+creating a drop-in file, i.e. a `.conf` suffixed file in the
+`~/.config/systemd/user/git-maintenance@.service.d` directory.
+
+`git maintenance stop` will stop the user systemd timers and delete
+the above mentioned files.
+
+For more details, see `systemd.timer(5)`.
+
+
+BACKGROUND MAINTENANCE ON MACOS SYSTEMS
+---------------------------------------
+
+While macOS technically supports `cron`, using `crontab -e` requires
+elevated privileges and the executed process does not have a full user
+context. Without a full user context, Git and its credential helpers
+cannot access stored credentials, so some maintenance tasks are not
+functional.
+
+Instead, `git maintenance start` interacts with the `launchctl` tool,
+which is the recommended way to schedule timed jobs in macOS. Scheduling
+maintenance through `git maintenance (start|stop)` requires some
+`launchctl` features available only in macOS 10.11 or later.
+
+Your user-specific scheduled tasks are stored as XML-formatted `.plist`
+files in `~/Library/LaunchAgents/`. You can see the currently-registered
+tasks using the following command:
+
+-----------------------------------------------------------------------
+$ ls ~/Library/LaunchAgents/org.git-scm.git*
+org.git-scm.git.daily.plist
+org.git-scm.git.hourly.plist
+org.git-scm.git.weekly.plist
+-----------------------------------------------------------------------
+
+One task is registered for each `--schedule=<frequency>` option. To
+inspect how the XML format describes each schedule, open one of these
+`.plist` files in an editor and inspect the `<array>` element following
+the `<key>StartCalendarInterval</key>` element.
+
+`git maintenance start` will overwrite these files and register the
+tasks again with `launchctl`, so any customizations should be done by
+creating your own `.plist` files with distinct names. Similarly, the
+`git maintenance stop` command will unregister the tasks with `launchctl`
+and delete the `.plist` files.
+
+To create more advanced customizations to your background tasks, see
+launchctl.plist(5) for more information.
+
+
+BACKGROUND MAINTENANCE ON WINDOWS SYSTEMS
+-----------------------------------------
+
+Windows does not support `cron` and instead has its own system for
+scheduling background tasks. The `git maintenance start` command uses
+the `schtasks` command to submit tasks to this system. You can inspect
+all background tasks using the Task Scheduler application. The tasks
+added by Git have names of the form `Git Maintenance (<frequency>)`.
+The Task Scheduler GUI has ways to inspect these tasks, but you can also
+export the tasks to XML files and view the details there.
+
+Note that since Git is a console application, these background tasks
+create a console window visible to the current user. This can be changed
+manually by selecting the "Run whether user is logged in or not" option
+in Task Scheduler. This change requires a password input, which is why
+`git maintenance start` does not select it by default.
+
+If you want to customize the background tasks, please rename the tasks
+so future calls to `git maintenance (start|stop)` do not overwrite your
+custom tasks.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/maintenance.adoc[]
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-base.adoc b/Documentation/git-merge-base.adoc
new file mode 100644
index 0000000000..5ab957cfbc
--- /dev/null
+++ b/Documentation/git-merge-base.adoc
@@ -0,0 +1,247 @@
+git-merge-base(1)
+=================
+
+NAME
+----
+git-merge-base - Find as good common ancestors as possible for a merge
+
+
+SYNOPSIS
+--------
+[verse]
+'git merge-base' [-a | --all] <commit> <commit>...
+'git merge-base' [-a | --all] --octopus <commit>...
+'git merge-base' --is-ancestor <commit> <commit>
+'git merge-base' --independent <commit>...
+'git merge-base' --fork-point <ref> [<commit>]
+
+DESCRIPTION
+-----------
+
+'git merge-base' finds the best common ancestor(s) between two commits to use
+in a three-way merge.  One common ancestor is 'better' than another common
+ancestor if the latter is an ancestor of the former.  A common ancestor
+that does not have any better common ancestor is a 'best common
+ancestor', i.e. a 'merge base'.  Note that there can be more than one
+merge base for a pair of commits.
+
+OPERATION MODES
+---------------
+
+In the most common special case, specifying only two commits on the
+command line means computing the merge base between the given two commits.
+
+More generally, among the two commits to compute the merge base from,
+one is specified by the first commit argument on the command line;
+the other commit is a (possibly hypothetical) commit that is a merge
+across all the remaining commits on the command line.
+
+As a consequence, the 'merge base' is not necessarily contained in each of the
+commit arguments if more than two commits are specified. This is different
+from linkgit:git-show-branch[1] when used with the `--merge-base` option.
+
+--octopus::
+	Compute the best common ancestors of all supplied commits,
+	in preparation for an n-way merge.  This mimics the behavior
+	of 'git show-branch --merge-base'.
+
+--independent::
+	Instead of printing merge bases, print a minimal subset of
+	the supplied commits with the same ancestors.  In other words,
+	among the commits given, list those which cannot be reached
+	from any other.  This mimics the behavior of 'git show-branch
+	--independent'.
+
+--is-ancestor::
+	Check if the first <commit> is an ancestor of the second <commit>,
+	and exit with status 0 if true, or with status 1 if not.
+	Errors are signaled by a non-zero status that is not 1.
+
+--fork-point::
+	Find the point at which a branch (or any history that leads
+	to <commit>) forked from another branch (or any reference)
+	<ref>. This does not just look for the common ancestor of
+	the two commits, but also takes into account the reflog of
+	<ref> to see if the history leading to <commit> forked from
+	an earlier incarnation of the branch <ref> (see discussion
+	of this mode below).
+
+OPTIONS
+-------
+-a::
+--all::
+	Output all merge bases for the commits, instead of just one.
+
+DISCUSSION
+----------
+
+Given two commits 'A' and 'B', `git merge-base A B` will output a commit
+which is reachable from both 'A' and 'B' through the parent relationship.
+
+For example, with this topology:
+
+....
+	 o---o---o---B
+	/
+---o---1---o---o---o---A
+....
+
+the merge base between 'A' and 'B' is '1'.
+
+Given three commits 'A', 'B', and 'C', `git merge-base A B C` will compute the
+merge base between 'A' and a hypothetical commit 'M', which is a merge
+between 'B' and 'C'.  For example, with this topology:
+
+....
+       o---o---o---o---C
+      /
+     /   o---o---o---B
+    /   /
+---2---1---o---o---o---A
+....
+
+the result of `git merge-base A B C` is '1'.  This is because the
+equivalent topology with a merge commit 'M' between 'B' and 'C' is:
+
+
+....
+       o---o---o---o---o
+      /                 \
+     /   o---o---o---o---M
+    /   /
+---2---1---o---o---o---A
+....
+
+and the result of `git merge-base A M` is '1'.  Commit '2' is also a
+common ancestor between 'A' and 'M', but '1' is a better common ancestor,
+because '2' is an ancestor of '1'.  Hence, '2' is not a merge base.
+
+The result of `git merge-base --octopus A B C` is '2', because '2' is
+the best common ancestor of all commits.
+
+When the history involves criss-cross merges, there can be more than one
+'best' common ancestor for two commits.  For example, with this topology:
+
+....
+---1---o---A
+    \ /
+     X
+    / \
+---2---o---o---B
+....
+
+both '1' and '2' are merge bases of A and B.  Neither one is better than
+the other (both are 'best' merge bases).  When the `--all` option is not given,
+it is unspecified which best one is output.
+
+A common idiom to check "fast-forward-ness" between two commits A
+and B is (or at least used to be) to compute the merge base between
+A and B, and check if it is the same as A, in which case, A is an
+ancestor of B.  You will see this idiom used often in older scripts.
+
+....
+A=$(git rev-parse --verify A)
+if test "$A" = "$(git merge-base A B)"
+then
+	... A is an ancestor of B ...
+fi
+....
+
+In modern git, you can say this in a more direct way:
+
+....
+if git merge-base --is-ancestor A B
+then
+	... A is an ancestor of B ...
+fi
+....
+
+instead.
+
+Discussion on fork-point mode
+-----------------------------
+
+After working on the `topic` branch created with `git switch -c
+topic origin/master`, the history of remote-tracking branch
+`origin/master` may have been rewound and rebuilt, leading to a
+history of this shape:
+
+....
+		 o---B2
+		/
+---o---o---B1--o---o---o---B (origin/master)
+	\
+	 B0
+	  \
+	   D0---D1---D (topic)
+....
+
+where `origin/master` used to point at commits B0, B1, B2 and now it
+points at B, and your `topic` branch was started on top of it back
+when `origin/master` was at B0, and you built three commits, D0, D1,
+and D, on top of it.  Imagine that you now want to rebase the work
+you did on the topic on top of the updated origin/master.
+
+In such a case, `git merge-base origin/master topic` would return the
+parent of B0 in the above picture, but B0^..D is *not* the range of
+commits you would want to replay on top of B (it includes B0, which
+is not what you wrote; it is a commit the other side discarded when
+it moved its tip from B0 to B1).
+
+`git merge-base --fork-point origin/master topic` is designed to
+help in such a case.  It takes not only B but also B0, B1, and B2
+(i.e. old tips of the remote-tracking branches your repository's
+reflog knows about) into account to see on which commit your topic
+branch was built and finds B0, allowing you to replay only the
+commits on your topic, excluding the commits the other side later
+discarded.
+
+Hence
+
+    $ fork_point=$(git merge-base --fork-point origin/master topic)
+
+will find B0, and
+
+    $ git rebase --onto origin/master $fork_point topic
+
+will replay D0, D1, and D on top of B to create a new history of this
+shape:
+
+....
+		 o---B2
+		/
+---o---o---B1--o---o---o---B (origin/master)
+	\                   \
+	 B0                  D0'--D1'--D' (topic - updated)
+	  \
+	   D0---D1---D (topic - old)
+....
+
+A caveat is that older reflog entries in your repository may be
+expired by `git gc`.  If B0 no longer appears in the reflog of the
+remote-tracking branch `origin/master`, the `--fork-point` mode
+obviously cannot find it and fails, avoiding to give a random and
+useless result (such as the parent of B0, like the same command
+without the `--fork-point` option gives).
+
+Also, the remote-tracking branch you use the `--fork-point` mode
+with must be the one your topic forked from its tip.  If you forked
+from an older commit than the tip, this mode would not find the fork
+point (imagine in the above sample history B0 did not exist,
+origin/master started at B1, moved to B2 and then B, and you forked
+your topic at origin/master^ when origin/master was B1; the shape of
+the history would be the same as above, without B0, and the parent
+of B1 is what `git merge-base origin/master topic` correctly finds,
+but the `--fork-point` mode will not, because it is not one of the
+commits that used to be at the tip of origin/master).
+
+
+See also
+--------
+linkgit:git-rev-list[1],
+linkgit:git-show-branch[1],
+linkgit:git-merge[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-file.adoc b/Documentation/git-merge-file.adoc
new file mode 100644
index 0000000000..71915a00fa
--- /dev/null
+++ b/Documentation/git-merge-file.adoc
@@ -0,0 +1,122 @@
+git-merge-file(1)
+=================
+
+NAME
+----
+git-merge-file - Run a three-way file merge
+
+
+SYNOPSIS
+--------
+[verse]
+'git merge-file' [-L <current-name> [-L <base-name> [-L <other-name>]]]
+	[--ours|--theirs|--union] [-p|--stdout] [-q|--quiet] [--marker-size=<n>]
+	[--[no-]diff3] [--object-id] <current> <base> <other>
+
+
+DESCRIPTION
+-----------
+Given three files `<current>`, `<base>` and `<other>`,
+'git merge-file' incorporates all changes that lead from `<base>`
+to `<other>` into `<current>`. The result ordinarily goes into
+`<current>`. 'git merge-file' is useful for combining separate changes
+to an original. Suppose `<base>` is the original, and both
+`<current>` and `<other>` are modifications of `<base>`,
+then 'git merge-file' combines both changes.
+
+A conflict occurs if both `<current>` and `<other>` have changes
+in a common segment of lines. If a conflict is found, 'git merge-file'
+normally outputs a warning and brackets the conflict with lines containing
+<<<<<<< and >>>>>>> markers. A typical conflict will look like this:
+
+	<<<<<<< A
+	lines in file A
+	=======
+	lines in file B
+	>>>>>>> B
+
+If there are conflicts, the user should edit the result and delete one of
+the alternatives.  When `--ours`, `--theirs`, or `--union` option is in effect,
+however, these conflicts are resolved favouring lines from `<current>`,
+lines from `<other>`, or lines from both respectively.  The length of the
+conflict markers can be given with the `--marker-size` option.
+
+If `--object-id` is specified, exactly the same behavior occurs, except that
+instead of specifying what to merge as files, it is specified as a list of
+object IDs referring to blobs.
+
+The exit value of this program is negative on error, and the number of
+conflicts otherwise (truncated to 127 if there are more than that many
+conflicts). If the merge was clean, the exit value is 0.
+
+'git merge-file' is designed to be a minimal clone of RCS 'merge'; that is, it
+implements all of RCS 'merge''s functionality which is needed by
+linkgit:git[1].
+
+
+OPTIONS
+-------
+
+--object-id::
+	Specify the contents to merge as blobs in the current repository instead of
+	files.  In this case, the operation must take place within a valid repository.
++
+If the `-p` option is specified, the merged file (including conflicts, if any)
+goes to standard output as normal; otherwise, the merged file is written to the
+object store and the object ID of its blob is written to standard output.
+
+-L <label>::
+	This option may be given up to three times, and
+	specifies labels to be used in place of the
+	corresponding file names in conflict reports. That is,
+	`git merge-file -L x -L y -L z a b c` generates output that
+	looks like it came from files x, y and z instead of
+	from files a, b and c.
+
+-p::
+	Send results to standard output instead of overwriting
+	`<current>`.
+
+-q::
+	Quiet; do not warn about conflicts.
+
+--diff3::
+	Show conflicts in "diff3" style.
+
+--zdiff3::
+	Show conflicts in "zdiff3" style.
+
+--ours::
+--theirs::
+--union::
+	Instead of leaving conflicts in the file, resolve conflicts
+	favouring our (or their or both) side of the lines.
+
+--diff-algorithm={patience|minimal|histogram|myers}::
+	Use a different diff algorithm while merging. The current default is "myers",
+	but selecting more recent algorithm such as "histogram" can help
+	avoid mismerges that occur due to unimportant matching lines
+	(such as braces from distinct functions). See also
+	linkgit:git-diff[1] `--diff-algorithm`.
+
+EXAMPLES
+--------
+
+`git merge-file README.my README README.upstream`::
+
+	combines the changes of README.my and README.upstream since README,
+	tries to merge them and writes the result into README.my.
+
+`git merge-file -L a -L b -L c tmp/a123 tmp/b234 tmp/c345`::
+
+	merges tmp/a123 and tmp/c345 with the base tmp/b234, but uses labels
+	`a` and `c` instead of `tmp/a123` and `tmp/c345`.
+
+`git merge-file -p --object-id abc1234 def567 890abcd`::
+
+	combines the changes of the blob abc1234 and 890abcd since def567,
+	tries to merge them and writes the result to standard output
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-index.adoc b/Documentation/git-merge-index.adoc
new file mode 100644
index 0000000000..eea56b3154
--- /dev/null
+++ b/Documentation/git-merge-index.adoc
@@ -0,0 +1,83 @@
+git-merge-index(1)
+==================
+
+NAME
+----
+git-merge-index - Run a merge for files needing merging
+
+
+SYNOPSIS
+--------
+[verse]
+'git merge-index' [-o] [-q] <merge-program> (-a | ( [--] <file>...) )
+
+DESCRIPTION
+-----------
+This looks up the <file>(s) in the index and, if there are any merge
+entries, passes the SHA-1 hash for those files as arguments 1, 2, 3 (empty
+argument if no file), and <file> as argument 4.  File modes for the three
+files are passed as arguments 5, 6 and 7.
+
+OPTIONS
+-------
+\--::
+	Do not interpret any more arguments as options.
+
+-a::
+	Run merge against all files in the index that need merging.
+
+-o::
+	Instead of stopping at the first failed merge, do all of them
+	in one shot - continue with merging even when previous merges
+	returned errors, and only return the error code after all the
+	merges.
+
+-q::
+	Do not complain about a failed merge program (a merge program
+	failure usually indicates conflicts during the merge). This is for
+	porcelains which might want to emit custom messages.
+
+If 'git merge-index' is called with multiple <file>s (or -a) then it
+processes them in turn only stopping if merge returns a non-zero exit
+code.
+
+Typically this is run with a script calling Git's imitation of
+the 'merge' command from the RCS package.
+
+A sample script called 'git merge-one-file' is included in the
+distribution.
+
+ALERT ALERT ALERT! The Git "merge object order" is different from the
+RCS 'merge' program merge object order. In the above ordering, the
+original is first. But the argument order to the 3-way merge program
+'merge' is to have the original in the middle. Don't ask me why.
+
+Examples:
+
+----
+torvalds@ppc970:~/merge-test> git merge-index cat MM
+This is MM from the original tree.		# original
+This is modified MM in the branch A.		# merge1
+This is modified MM in the branch B.		# merge2
+This is modified MM in the branch B.		# current contents
+----
+
+or
+
+----
+torvalds@ppc970:~/merge-test> git merge-index cat AA MM
+cat: : No such file or directory
+This is added AA in the branch A.
+This is added AA in the branch B.
+This is added AA in the branch B.
+fatal: merge program failed
+----
+
+where the latter example shows how 'git merge-index' will stop trying to
+merge once anything has returned an error (i.e., `cat` returned an error
+for the AA file, because it didn't exist in the original, and thus
+'git merge-index' didn't even try to merge the MM thing).
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-one-file.adoc b/Documentation/git-merge-one-file.adoc
new file mode 100644
index 0000000000..04e803d5d3
--- /dev/null
+++ b/Documentation/git-merge-one-file.adoc
@@ -0,0 +1,21 @@
+git-merge-one-file(1)
+=====================
+
+NAME
+----
+git-merge-one-file - The standard helper program to use with git-merge-index
+
+
+SYNOPSIS
+--------
+[verse]
+'git merge-one-file'
+
+DESCRIPTION
+-----------
+This is the standard helper program to use with 'git merge-index'
+to resolve a merge after the trivial merge done with 'git read-tree -m'.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge-tree.adoc b/Documentation/git-merge-tree.adoc
new file mode 100644
index 0000000000..0b6a8a19b1
--- /dev/null
+++ b/Documentation/git-merge-tree.adoc
@@ -0,0 +1,330 @@
+git-merge-tree(1)
+=================
+
+NAME
+----
+git-merge-tree - Perform merge without touching index or working tree
+
+
+SYNOPSIS
+--------
+[verse]
+'git merge-tree' [--write-tree] [<options>] <branch1> <branch2>
+'git merge-tree' [--trivial-merge] <base-tree> <branch1> <branch2> (deprecated)
+
+[[NEWMERGE]]
+DESCRIPTION
+-----------
+
+This command has a modern `--write-tree` mode and a deprecated
+`--trivial-merge` mode.  With the exception of the
+<<DEPMERGE,DEPRECATED DESCRIPTION>> section at the end, the rest of
+this documentation describes the modern `--write-tree` mode.
+
+Performs a merge, but does not make any new commits and does not read
+from or write to either the working tree or index.
+
+The performed merge will use the same features as the "real"
+linkgit:git-merge[1], including:
+
+  * three way content merges of individual files
+  * rename detection
+  * proper directory/file conflict handling
+  * recursive ancestor consolidation (i.e. when there is more than one
+    merge base, creating a virtual merge base by merging the merge bases)
+  * etc.
+
+After the merge completes, a new toplevel tree object is created.  See
+`OUTPUT` below for details.
+
+OPTIONS
+-------
+
+-z::
+	Do not quote filenames in the <Conflicted file info> section,
+	and end each filename with a NUL character rather than
+	newline.  Also begin the messages section with a NUL character
+	instead of a newline.  See <<OUTPUT>> below for more information.
+
+--name-only::
+	In the Conflicted file info section, instead of writing a list
+	of (mode, oid, stage, path) tuples to output for conflicted
+	files, just provide a list of filenames with conflicts (and
+	do not list filenames multiple times if they have multiple
+	conflicting stages).
+
+--[no-]messages::
+	Write any informational messages such as "Auto-merging <path>"
+	or CONFLICT notices to the end of stdout.  If unspecified, the
+	default is to include these messages if there are merge
+	conflicts, and to omit them otherwise.
+
+--allow-unrelated-histories::
+	merge-tree will by default error out if the two branches specified
+	share no common history.  This flag can be given to override that
+	check and make the merge proceed anyway.
+
+--merge-base=<tree-ish>::
+	Instead of finding the merge-bases for <branch1> and <branch2>,
+	specify a merge-base for the merge, and specifying multiple bases is
+	currently not supported. This option is incompatible with `--stdin`.
++
+As the merge-base is provided directly, <branch1> and <branch2> do not need
+to specify commits; trees are enough.
+
+-X<option>::
+--strategy-option=<option>::
+	Pass the merge strategy-specific option through to the merge strategy.
+	See linkgit:git-merge[1] for details.
+
+[[OUTPUT]]
+OUTPUT
+------
+
+For a successful merge, the output from git-merge-tree is simply one
+line:
+
+	<OID of toplevel tree>
+
+Whereas for a conflicted merge, the output is by default of the form:
+
+	<OID of toplevel tree>
+	<Conflicted file info>
+	<Informational messages>
+
+These are discussed individually below.
+
+However, there is an exception.  If `--stdin` is passed, then there is
+an extra section at the beginning, a NUL character at the end, and then
+all the sections repeat for each line of input.  Thus, if the first merge
+is conflicted and the second is clean, the output would be of the form:
+
+	<Merge status>
+	<OID of toplevel tree>
+	<Conflicted file info>
+	<Informational messages>
+	NUL
+	<Merge status>
+	<OID of toplevel tree>
+	NUL
+
+[[MS]]
+Merge status
+~~~~~~~~~~~~
+
+This is an integer status followed by a NUL character.  The integer status is:
+
+     0: merge had conflicts
+     1: merge was clean
+     <0: something prevented the merge from running (e.g. access to repository
+	 objects denied by filesystem)
+
+[[OIDTLT]]
+OID of toplevel tree
+~~~~~~~~~~~~~~~~~~~~
+
+This is a tree object that represents what would be checked out in the
+working tree at the end of `git merge`.  If there were conflicts, then
+files within this tree may have embedded conflict markers.  This section
+is always followed by a newline (or NUL if `-z` is passed).
+
+[[CFI]]
+Conflicted file info
+~~~~~~~~~~~~~~~~~~~~
+
+This is a sequence of lines with the format
+
+	<mode> <object> <stage> <filename>
+
+The filename will be quoted as explained for the configuration
+variable `core.quotePath` (see linkgit:git-config[1]).  However, if
+the `--name-only` option is passed, the mode, object, and stage will
+be omitted.  If `-z` is passed, the "lines" are terminated by a NUL
+character instead of a newline character.
+
+[[IM]]
+Informational messages
+~~~~~~~~~~~~~~~~~~~~~~
+
+This section provides informational messages, typically about
+conflicts.  The format of the section varies significantly depending
+on whether `-z` is passed.
+
+If `-z` is passed:
+
+The output format is zero or more conflict informational records, each
+of the form:
+
+	<list-of-paths><conflict-type>NUL<conflict-message>NUL
+
+where <list-of-paths> is of the form
+
+	<number-of-paths>NUL<path1>NUL<path2>NUL...<pathN>NUL
+
+and includes paths (or branch names) affected by the conflict or
+informational message in <conflict-message>.  Also, <conflict-type> is a
+stable string explaining the type of conflict, such as
+
+  * "Auto-merging"
+  * "CONFLICT (rename/delete)"
+  * "CONFLICT (submodule lacks merge base)"
+  * "CONFLICT (binary)"
+
+and <conflict-message> is a more detailed message about the conflict which often
+(but not always) embeds the <stable-short-type-description> within it.  These
+strings may change in future Git versions.  Some examples:
+
+  * "Auto-merging <file>"
+  * "CONFLICT (rename/delete): <oldfile> renamed...but deleted in..."
+  * "Failed to merge submodule <submodule> (no merge base)"
+  * "Warning: cannot merge binary files: <filename>"
+
+If `-z` is NOT passed:
+
+This section starts with a blank line to separate it from the previous
+sections, and then only contains the <conflict-message> information
+from the previous section (separated by newlines).  These are
+non-stable strings that should not be parsed by scripts, and are just
+meant for human consumption.  Also, note that while <conflict-message>
+strings usually do not contain embedded newlines, they sometimes do.
+(However, the free-form messages will never have an embedded NUL
+character).  So, the entire block of information is meant for human
+readers as an agglomeration of all conflict messages.
+
+EXIT STATUS
+-----------
+
+For a successful, non-conflicted merge, the exit status is 0.  When the
+merge has conflicts, the exit status is 1.  If the merge is not able to
+complete (or start) due to some kind of error, the exit status is
+something other than 0 or 1 (and the output is unspecified).  When
+--stdin is passed, the return status is 0 for both successful and
+conflicted merges, and something other than 0 or 1 if it cannot complete
+all the requested merges.
+
+USAGE NOTES
+-----------
+
+This command is intended as low-level plumbing, similar to
+linkgit:git-hash-object[1], linkgit:git-mktree[1],
+linkgit:git-commit-tree[1], linkgit:git-write-tree[1],
+linkgit:git-update-ref[1], and linkgit:git-mktag[1].  Thus, it can be
+used as a part of a series of steps such as:
+
+       vi message.txt
+       BRANCH1=refs/heads/test
+       BRANCH2=main
+       NEWTREE=$(git merge-tree --write-tree $BRANCH1 $BRANCH2) || {
+           echo "There were conflicts..." 1>&2
+           exit 1
+       }
+       NEWCOMMIT=$(git commit-tree $NEWTREE -F message.txt \
+           -p $BRANCH1 -p $BRANCH2)
+       git update-ref $BRANCH1 $NEWCOMMIT
+
+Note that when the exit status is non-zero, `NEWTREE` in this sequence
+will contain a lot more output than just a tree.
+
+For conflicts, the output includes the same information that you'd get
+with linkgit:git-merge[1]:
+
+  * what would be written to the working tree (the
+    <<OIDTLT,OID of toplevel tree>>)
+  * the higher order stages that would be written to the index (the
+    <<CFI,Conflicted file info>>)
+  * any messages that would have been printed to stdout (the
+    <<IM,Informational messages>>)
+
+INPUT FORMAT
+------------
+'git merge-tree --stdin' input format is fully text based. Each line
+has this format:
+
+	[<base-commit> -- ]<branch1> <branch2>
+
+If one line is separated by `--`, the string before the separator is
+used for specifying a merge-base for the merge and the string after
+the separator describes the branches to be merged.
+
+MISTAKES TO AVOID
+-----------------
+
+Do NOT look through the resulting toplevel tree to try to find which
+files conflict; parse the <<CFI,Conflicted file info>> section instead.
+Not only would parsing an entire tree be horrendously slow in large
+repositories, there are numerous types of conflicts not representable by
+conflict markers (modify/delete, mode conflict, binary file changed on
+both sides, file/directory conflicts, various rename conflict
+permutations, etc.)
+
+Do NOT interpret an empty <<CFI,Conflicted file info>> list as a clean
+merge; check the exit status.  A merge can have conflicts without having
+individual files conflict (there are a few types of directory rename
+conflicts that fall into this category, and others might also be added
+in the future).
+
+Do NOT attempt to guess or make the user guess the conflict types from
+the <<CFI,Conflicted file info>> list.  The information there is
+insufficient to do so.  For example: Rename/rename(1to2) conflicts (both
+sides renamed the same file differently) will result in three different
+files having higher order stages (but each only has one higher order
+stage), with no way (short of the <<IM,Informational messages>> section)
+to determine which three files are related.  File/directory conflicts
+also result in a file with exactly one higher order stage.
+Possibly-involved-in-directory-rename conflicts (when
+"merge.directoryRenames" is unset or set to "conflicts") also result in
+a file with exactly one higher order stage.  In all cases, the
+<<IM,Informational messages>> section has the necessary info, though it
+is not designed to be machine parseable.
+
+Do NOT assume that each path from <<CFI,Conflicted file info>>, and
+the logical conflicts in the <<IM,Informational messages>> have a
+one-to-one mapping, nor that there is a one-to-many mapping, nor a
+many-to-one mapping.  Many-to-many mappings exist, meaning that each
+path can have many logical conflict types in a single merge, and each
+logical conflict type can affect many paths.
+
+Do NOT assume all filenames listed in the <<IM,Informational messages>>
+section had conflicts.  Messages can be included for files that have no
+conflicts, such as "Auto-merging <file>".
+
+AVOID taking the OIDS from the <<CFI,Conflicted file info>> and
+re-merging them to present the conflicts to the user.  This will lose
+information.  Instead, look up the version of the file found within the
+<<OIDTLT,OID of toplevel tree>> and show that instead.  In particular,
+the latter will have conflict markers annotated with the original
+branch/commit being merged and, if renames were involved, the original
+filename.  While you could include the original branch/commit in the
+conflict marker annotations when re-merging, the original filename is
+not available from the <<CFI,Conflicted file info>> and thus you would
+be losing information that might help the user resolve the conflict.
+
+[[DEPMERGE]]
+DEPRECATED DESCRIPTION
+----------------------
+
+Per the <<NEWMERGE,DESCRIPTION>> and unlike the rest of this
+documentation, this section describes the deprecated `--trivial-merge`
+mode.
+
+Other than the optional `--trivial-merge`, this mode accepts no
+options.
+
+This mode reads three tree-ish, and outputs trivial merge results and
+conflicting stages to the standard output in a semi-diff format.
+Since this was designed for higher level scripts to consume and merge
+the results back into the index, it omits entries that match
+<branch1>.  The result of this second form is similar to what
+three-way 'git read-tree -m' does, but instead of storing the results
+in the index, the command outputs the entries to the standard output.
+
+This form not only has limited applicability (a trivial merge cannot
+handle content merges of individual files, rename detection, proper
+directory/file conflict handling, etc.), the output format is also
+difficult to work with, and it will generally be less performant than
+the first form even on successful merges (especially if working in
+large repositories).
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-merge.adoc b/Documentation/git-merge.adoc
new file mode 100644
index 0000000000..a5e8e013af
--- /dev/null
+++ b/Documentation/git-merge.adoc
@@ -0,0 +1,413 @@
+git-merge(1)
+============
+
+NAME
+----
+git-merge - Join two or more development histories together
+
+
+SYNOPSIS
+--------
+[verse]
+'git merge' [-n] [--stat] [--no-commit] [--squash] [--[no-]edit]
+	[--no-verify] [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
+	[--[no-]allow-unrelated-histories]
+	[--[no-]rerere-autoupdate] [-m <msg>] [-F <file>]
+	[--into-name <branch>] [<commit>...]
+'git merge' (--continue | --abort | --quit)
+
+DESCRIPTION
+-----------
+Incorporates changes from the named commits (since the time their
+histories diverged from the current branch) into the current
+branch.  This command is used by `git pull` to incorporate changes
+from another repository and can be used by hand to merge changes
+from one branch into another.
+
+Assume the following history exists and the current branch is
+`master`:
+
+------------
+	  A---B---C topic
+	 /
+    D---E---F---G master
+------------
+
+Then `git merge topic` will replay the changes made on the
+`topic` branch since it diverged from `master` (i.e., `E`) until
+its current commit (`C`) on top of `master`, and record the result
+in a new commit along with the names of the two parent commits and
+a log message from the user describing the changes. Before the operation,
+`ORIG_HEAD` is set to the tip of the current branch (`C`).
+
+------------
+	  A---B---C topic
+	 /         \
+    D---E---F---G---H master
+------------
+
+A merge stops if there's a conflict that cannot be resolved
+automatically or if `--no-commit` was provided when initiating the
+merge. At that point you can run `git merge --abort` or `git merge
+--continue`.
+
+`git merge --abort` will abort the merge process and try to reconstruct
+the pre-merge state. However, if there were uncommitted changes when the
+merge started (and especially if those changes were further modified
+after the merge was started), `git merge --abort` will in some cases be
+unable to reconstruct the original (pre-merge) changes. Therefore:
+
+*Warning*: Running `git merge` with non-trivial uncommitted changes is
+discouraged: while possible, it may leave you in a state that is hard to
+back out of in the case of a conflict.
+
+OPTIONS
+-------
+:git-merge: 1
+
+include::merge-options.adoc[]
+
+-m <msg>::
+	Set the commit message to be used for the merge commit (in
+	case one is created).
++
+If `--log` is specified, a shortlog of the commits being merged
+will be appended to the specified message.
++
+The `git fmt-merge-msg` command can be
+used to give a good default for automated `git merge`
+invocations. The automated message can include the branch description.
+
+--into-name <branch>::
+	Prepare the default merge message as if merging to the branch
+	`<branch>`, instead of the name of the real branch to which
+	the merge is made.
+
+-F <file>::
+--file=<file>::
+	Read the commit message to be used for the merge commit (in
+	case one is created).
++
+If `--log` is specified, a shortlog of the commits being merged
+will be appended to the specified message.
+
+include::rerere-options.adoc[]
+
+--overwrite-ignore::
+--no-overwrite-ignore::
+	Silently overwrite ignored files from the merge result. This
+	is the default behavior. Use `--no-overwrite-ignore` to abort.
+
+--abort::
+	Abort the current conflict resolution process, and
+	try to reconstruct the pre-merge state. If an autostash entry is
+	present, apply it to the worktree.
++
+If there were uncommitted worktree changes present when the merge
+started, `git merge --abort` will in some cases be unable to
+reconstruct these changes. It is therefore recommended to always
+commit or stash your changes before running `git merge`.
++
+`git merge --abort` is equivalent to `git reset --merge` when
+`MERGE_HEAD` is present unless `MERGE_AUTOSTASH` is also present in
+which case `git merge --abort` applies the stash entry to the worktree
+whereas `git reset --merge` will save the stashed changes in the stash
+list.
+
+--quit::
+	Forget about the current merge in progress. Leave the index
+	and the working tree as-is. If `MERGE_AUTOSTASH` is present, the
+	stash entry will be saved to the stash list.
+
+--continue::
+	After a `git merge` stops due to conflicts you can conclude the
+	merge by running `git merge --continue` (see "HOW TO RESOLVE
+	CONFLICTS" section below).
+
+<commit>...::
+	Commits, usually other branch heads, to merge into our branch.
+	Specifying more than one commit will create a merge with
+	more than two parents (affectionately called an Octopus merge).
++
+If no commit is given from the command line, merge the remote-tracking
+branches that the current branch is configured to use as its upstream.
+See also the configuration section of this manual page.
++
+When `FETCH_HEAD` (and no other commit) is specified, the branches
+recorded in the `.git/FETCH_HEAD` file by the previous invocation
+of `git fetch` for merging are merged to the current branch.
+
+
+PRE-MERGE CHECKS
+----------------
+
+Before applying outside changes, you should get your own work in
+good shape and committed locally, so it will not be clobbered if
+there are conflicts.  See also linkgit:git-stash[1].
+`git pull` and `git merge` will stop without doing anything when
+local uncommitted changes overlap with files that `git pull`/`git
+merge` may need to update.
+
+To avoid recording unrelated changes in the merge commit,
+`git pull` and `git merge` will also abort if there are any changes
+registered in the index relative to the `HEAD` commit.  (Special
+narrow exceptions to this rule may exist depending on which merge
+strategy is in use, but generally, the index must match HEAD.)
+
+If all named commits are already ancestors of `HEAD`, `git merge`
+will exit early with the message "Already up to date."
+
+FAST-FORWARD MERGE
+------------------
+
+Often the current branch head is an ancestor of the named commit.
+This is the most common case especially when invoked from `git
+pull`: you are tracking an upstream repository, you have committed
+no local changes, and now you want to update to a newer upstream
+revision.  In this case, a new commit is not needed to store the
+combined history; instead, the `HEAD` (along with the index) is
+updated to point at the named commit, without creating an extra
+merge commit.
+
+This behavior can be suppressed with the `--no-ff` option.
+
+TRUE MERGE
+----------
+
+Except in a fast-forward merge (see above), the branches to be
+merged must be tied together by a merge commit that has both of them
+as its parents.
+
+A merged version reconciling the changes from all branches to be
+merged is committed, and your `HEAD`, index, and working tree are
+updated to it.  It is possible to have modifications in the working
+tree as long as they do not overlap; the update will preserve them.
+
+When it is not obvious how to reconcile the changes, the following
+happens:
+
+1. The `HEAD` pointer stays the same.
+2. The `MERGE_HEAD` ref is set to point to the other branch head.
+3. Paths that merged cleanly are updated both in the index file and
+   in your working tree.
+4. For conflicting paths, the index file records up to three
+   versions: stage 1 stores the version from the common ancestor,
+   stage 2 from `HEAD`, and stage 3 from `MERGE_HEAD` (you
+   can inspect the stages with `git ls-files -u`).  The working
+   tree files contain the result of the merge operation; i.e. 3-way
+   merge results with familiar conflict markers `<<<` `===` `>>>`.
+5. A ref named `AUTO_MERGE` is written, pointing to a tree
+   corresponding to the current content of the working tree (including
+   conflict markers for textual conflicts).  Note that this ref is only
+   written when the 'ort' merge strategy is used (the default).
+6. No other changes are made.  In particular, the local
+   modifications you had before you started merge will stay the
+   same and the index entries for them stay as they were,
+   i.e. matching `HEAD`.
+
+If you tried a merge which resulted in complex conflicts and
+want to start over, you can recover with `git merge --abort`.
+
+MERGING TAG
+-----------
+
+When merging an annotated (and possibly signed) tag, Git always
+creates a merge commit even if a fast-forward merge is possible, and
+the commit message template is prepared with the tag message.
+Additionally, if the tag is signed, the signature check is reported
+as a comment in the message template. See also linkgit:git-tag[1].
+
+When you want to just integrate with the work leading to the commit
+that happens to be tagged, e.g. synchronizing with an upstream
+release point, you may not want to make an unnecessary merge commit.
+
+In such a case, you can "unwrap" the tag yourself before feeding it
+to `git merge`, or pass `--ff-only` when you do not have any work on
+your own. e.g.
+
+----
+git fetch origin
+git merge v1.2.3^0
+git merge --ff-only v1.2.3
+----
+
+
+HOW CONFLICTS ARE PRESENTED
+---------------------------
+
+During a merge, the working tree files are updated to reflect the result
+of the merge.  Among the changes made to the common ancestor's version,
+non-overlapping ones (that is, you changed an area of the file while the
+other side left that area intact, or vice versa) are incorporated in the
+final result verbatim.  When both sides made changes to the same area,
+however, Git cannot randomly pick one side over the other, and asks you to
+resolve it by leaving what both sides did to that area.
+
+By default, Git uses the same style as the one used by the "merge" program
+from the RCS suite to present such a conflicted hunk, like this:
+
+------------
+Here are lines that are either unchanged from the common
+ancestor, or cleanly resolved because only one side changed,
+or cleanly resolved because both sides changed the same way.
+<<<<<<< yours:sample.txt
+Conflict resolution is hard;
+let's go shopping.
+=======
+Git makes conflict resolution easy.
+>>>>>>> theirs:sample.txt
+And here is another line that is cleanly resolved or unmodified.
+------------
+
+The area where a pair of conflicting changes happened is marked with markers
+`<<<<<<<`, `=======`, and `>>>>>>>`.  The part before the `=======`
+is typically your side, and the part afterwards is typically their side.
+
+The default format does not show what the original said in the conflicting
+area.  You cannot tell how many lines are deleted and replaced with
+Barbie's remark on your side.  The only thing you can tell is that your
+side wants to say it is hard and you'd prefer to go shopping, while the
+other side wants to claim it is easy.
+
+An alternative style can be used by setting the `merge.conflictStyle`
+configuration variable to either "diff3" or "zdiff3".  In "diff3"
+style, the above conflict may look like this:
+
+------------
+Here are lines that are either unchanged from the common
+ancestor, or cleanly resolved because only one side changed,
+<<<<<<< yours:sample.txt
+or cleanly resolved because both sides changed the same way.
+Conflict resolution is hard;
+let's go shopping.
+||||||| base:sample.txt
+or cleanly resolved because both sides changed identically.
+Conflict resolution is hard.
+=======
+or cleanly resolved because both sides changed the same way.
+Git makes conflict resolution easy.
+>>>>>>> theirs:sample.txt
+And here is another line that is cleanly resolved or unmodified.
+------------
+
+while in "zdiff3" style, it may look like this:
+
+------------
+Here are lines that are either unchanged from the common
+ancestor, or cleanly resolved because only one side changed,
+or cleanly resolved because both sides changed the same way.
+<<<<<<< yours:sample.txt
+Conflict resolution is hard;
+let's go shopping.
+||||||| base:sample.txt
+or cleanly resolved because both sides changed identically.
+Conflict resolution is hard.
+=======
+Git makes conflict resolution easy.
+>>>>>>> theirs:sample.txt
+And here is another line that is cleanly resolved or unmodified.
+------------
+
+In addition to the `<<<<<<<`, `=======`, and `>>>>>>>` markers, it uses
+another `|||||||` marker that is followed by the original text.  You can
+tell that the original just stated a fact, and your side simply gave in to
+that statement and gave up, while the other side tried to have a more
+positive attitude.  You can sometimes come up with a better resolution by
+viewing the original.
+
+
+HOW TO RESOLVE CONFLICTS
+------------------------
+
+After seeing a conflict, you can do two things:
+
+ * Decide not to merge.  The only clean-ups you need are to reset
+   the index file to the `HEAD` commit to reverse 2. and to clean
+   up working tree changes made by 2. and 3.; `git merge --abort`
+   can be used for this.
+
+ * Resolve the conflicts.  Git will mark the conflicts in
+   the working tree.  Edit the files into shape and
+   `git add` them to the index.  Use `git commit` or
+   `git merge --continue` to seal the deal. The latter command
+   checks whether there is a (interrupted) merge in progress
+   before calling `git commit`.
+
+You can work through the conflict with a number of tools:
+
+ * Use a mergetool.  `git mergetool` to launch a graphical
+   mergetool which will work through the merge with you.
+
+ * Look at the diffs.  `git diff` will show a three-way diff,
+   highlighting changes from both the `HEAD` and `MERGE_HEAD`
+   versions. `git diff AUTO_MERGE` will show what changes you've
+   made so far to resolve textual conflicts.
+
+ * Look at the diffs from each branch. `git log --merge -p <path>`
+   will show diffs first for the `HEAD` version and then the
+   `MERGE_HEAD` version.
+
+ * Look at the originals.  `git show :1:filename` shows the
+   common ancestor, `git show :2:filename` shows the `HEAD`
+   version, and `git show :3:filename` shows the `MERGE_HEAD`
+   version.
+
+
+EXAMPLES
+--------
+
+* Merge branches `fixes` and `enhancements` on top of
+  the current branch, making an octopus merge:
++
+------------------------------------------------
+$ git merge fixes enhancements
+------------------------------------------------
+
+* Merge branch `obsolete` into the current branch, using `ours`
+  merge strategy:
++
+------------------------------------------------
+$ git merge -s ours obsolete
+------------------------------------------------
+
+* Merge branch `maint` into the current branch, but do not make
+  a new commit automatically:
++
+------------------------------------------------
+$ git merge --no-commit maint
+------------------------------------------------
++
+This can be used when you want to include further changes to the
+merge, or want to write your own merge commit message.
++
+You should refrain from abusing this option to sneak substantial
+changes into a merge commit.  Small fixups like bumping
+release/version name would be acceptable.
+
+
+include::merge-strategies.adoc[]
+
+CONFIGURATION
+-------------
+
+branch.<name>.mergeOptions::
+	Sets default options for merging into branch <name>. The syntax and
+	supported options are the same as those of `git merge`, but option
+	values containing whitespace characters are currently not supported.
+
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/merge.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-fmt-merge-msg[1], linkgit:git-pull[1],
+linkgit:gitattributes[5],
+linkgit:git-reset[1],
+linkgit:git-diff[1], linkgit:git-ls-files[1],
+linkgit:git-add[1], linkgit:git-rm[1],
+linkgit:git-mergetool[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mergetool--lib.adoc b/Documentation/git-mergetool--lib.adoc
new file mode 100644
index 0000000000..0726b560d4
--- /dev/null
+++ b/Documentation/git-mergetool--lib.adoc
@@ -0,0 +1,53 @@
+git-mergetool{litdd}lib(1)
+==========================
+
+NAME
+----
+git-mergetool--lib - Common Git merge tool shell scriptlets
+
+SYNOPSIS
+--------
+[verse]
+'TOOL_MODE=(diff|merge) . "$(git --exec-path)/git-mergetool{litdd}lib"'
+
+DESCRIPTION
+-----------
+
+This is not a command the end user would want to run.  Ever.
+This documentation is meant for people who are studying the
+Porcelain-ish scripts and/or are writing new ones.
+
+The 'git-mergetool{litdd}lib' scriptlet is designed to be sourced (using
+`.`) by other shell scripts to set up functions for working
+with Git merge tools.
+
+Before sourcing 'git-mergetool{litdd}lib', your script must set `TOOL_MODE`
+to define the operation mode for the functions listed below.
+'diff' and 'merge' are valid values.
+
+FUNCTIONS
+---------
+get_merge_tool::
+	Returns a merge tool. The return code is 1 if we returned a guessed
+	merge tool, else 0. '$GIT_MERGETOOL_GUI' may be set to 'true' to
+	search for the appropriate guitool.
+
+get_merge_tool_cmd::
+	Returns the custom command for a merge tool.
+
+get_merge_tool_path::
+	Returns the custom path for a merge tool.
+
+initialize_merge_tool::
+	Brings merge tool specific functions into scope so they can be used or
+	overridden.
+
+run_merge_tool::
+	Launches a merge tool given the tool name and a true/false
+	flag to indicate whether a merge base is present.
+	'$MERGED', '$LOCAL', '$REMOTE', and '$BASE' must be defined
+	for use by the merge tool.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mergetool.adoc b/Documentation/git-mergetool.adoc
new file mode 100644
index 0000000000..964bc9742e
--- /dev/null
+++ b/Documentation/git-mergetool.adoc
@@ -0,0 +1,130 @@
+git-mergetool(1)
+================
+
+NAME
+----
+git-mergetool - Run merge conflict resolution tools to resolve merge conflicts
+
+SYNOPSIS
+--------
+[verse]
+'git mergetool' [--tool=<tool>] [-y | --[no-]prompt] [<file>...]
+
+DESCRIPTION
+-----------
+
+Use `git mergetool` to run one of several merge utilities to resolve
+merge conflicts.  It is typically run after 'git merge'.
+
+If one or more <file> parameters are given, the merge tool program will
+be run to resolve differences in each file (skipping those without
+conflicts).  Specifying a directory will include all unresolved files in
+that path.  If no <file> names are specified, 'git mergetool' will run
+the merge tool program on every file with merge conflicts.
+
+OPTIONS
+-------
+-t <tool>::
+--tool=<tool>::
+	Use the merge resolution program specified by <tool>.
+	Valid values include emerge, gvimdiff, kdiff3,
+	meld, vimdiff, and tortoisemerge. Run `git mergetool --tool-help`
+	for the list of valid <tool> settings.
++
+If a merge resolution program is not specified, 'git mergetool'
+will use the configuration variable `merge.tool`.  If the
+configuration variable `merge.tool` is not set, 'git mergetool'
+will pick a suitable default.
++
+You can explicitly provide a full path to the tool by setting the
+configuration variable `mergetool.<tool>.path`. For example, you
+can configure the absolute path to kdiff3 by setting
+`mergetool.kdiff3.path`. Otherwise, 'git mergetool' assumes the
+tool is available in PATH.
++
+Instead of running one of the known merge tool programs,
+'git mergetool' can be customized to run an alternative program
+by specifying the command line to invoke in a configuration
+variable `mergetool.<tool>.cmd`.
++
+When 'git mergetool' is invoked with this tool (either through the
+`-t` or `--tool` option or the `merge.tool` configuration
+variable), the configured command line will be invoked with `$BASE`
+set to the name of a temporary file containing the common base for
+the merge, if available; `$LOCAL` set to the name of a temporary
+file containing the contents of the file on the current branch;
+`$REMOTE` set to the name of a temporary file containing the
+contents of the file to be merged, and `$MERGED` set to the name
+of the file to which the merge tool should write the result of the
+merge resolution.
++
+If the custom merge tool correctly indicates the success of a
+merge resolution with its exit code, then the configuration
+variable `mergetool.<tool>.trustExitCode` can be set to `true`.
+Otherwise, 'git mergetool' will prompt the user to indicate the
+success of the resolution after the custom tool has exited.
+
+--tool-help::
+	Print a list of merge tools that may be used with `--tool`.
+
+-y::
+--no-prompt::
+	Don't prompt before each invocation of the merge resolution
+	program.
+	This is the default if the merge resolution program is
+	explicitly specified with the `--tool` option or with the
+	`merge.tool` configuration variable.
+
+--prompt::
+	Prompt before each invocation of the merge resolution program
+	to give the user a chance to skip the path.
+
+-g::
+--gui::
+	When 'git-mergetool' is invoked with the `-g` or `--gui` option,
+	the default merge tool will be read from the configured
+	`merge.guitool` variable instead of `merge.tool`. If
+	`merge.guitool` is not set, we will fallback to the tool
+	configured under `merge.tool`. This may be autoselected using
+	the configuration variable `mergetool.guiDefault`.
+
+--no-gui::
+	This overrides a previous `-g` or `--gui` setting or
+	`mergetool.guiDefault` configuration and reads the default merge
+	tool from the configured `merge.tool` variable.
+
+-O<orderfile>::
+	Process files in the order specified in the
+	<orderfile>, which has one shell glob pattern per line.
+	This overrides the `diff.orderFile` configuration variable
+	(see linkgit:git-config[1]).  To cancel `diff.orderFile`,
+	use `-O/dev/null`.
+
+CONFIGURATION
+-------------
+:git-mergetool: 1
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/mergetool.adoc[]
+
+TEMPORARY FILES
+---------------
+`git mergetool` creates `*.orig` backup files while resolving merges.
+These are safe to remove once a file has been merged and its
+`git mergetool` session has completed.
+
+Setting the `mergetool.keepBackup` configuration variable to `false`
+causes `git mergetool` to automatically remove the backup files as files
+are successfully merged.
+
+BACKEND SPECIFIC HINTS
+----------------------
+
+vimdiff
+~~~~~~~
+include::mergetools/vimdiff.txt[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mktag.adoc b/Documentation/git-mktag.adoc
new file mode 100644
index 0000000000..006d759962
--- /dev/null
+++ b/Documentation/git-mktag.adoc
@@ -0,0 +1,66 @@
+git-mktag(1)
+============
+
+NAME
+----
+git-mktag - Creates a tag object with extra validation
+
+
+SYNOPSIS
+--------
+[verse]
+'git mktag'
+
+DESCRIPTION
+-----------
+
+Reads a tag's contents on standard input and creates a tag object. The
+output is the new tag's <object> identifier.
+
+This command is mostly equivalent to linkgit:git-hash-object[1]
+invoked with `-t tag -w --stdin`. I.e. both of these will create and
+write a tag found in `my-tag`:
+
+    git mktag <my-tag
+    git hash-object -t tag -w --stdin <my-tag
+
+The difference is that mktag will die before writing the tag if the
+tag doesn't pass a linkgit:git-fsck[1] check.
+
+The "fsck" check done by mktag is stricter than what linkgit:git-fsck[1]
+would run by default in that all `fsck.<msg-id>` messages are promoted
+from warnings to errors (so e.g. a missing "tagger" line is an error).
+
+Extra headers in the object are also an error under mktag, but ignored
+by linkgit:git-fsck[1]. This extra check can be turned off by setting
+the appropriate `fsck.<msg-id>` variable:
+
+    git -c fsck.extraHeaderEntry=ignore mktag <my-tag-with-headers
+
+OPTIONS
+-------
+
+--strict::
+	By default mktag turns on the equivalent of
+	linkgit:git-fsck[1] `--strict` mode. Use `--no-strict` to
+	disable it.
+
+Tag Format
+----------
+A tag signature file, to be fed to this command's standard input,
+has a very simple fixed format: four lines of
+
+  object <hash>
+  type <typename>
+  tag <tagname>
+  tagger <tagger>
+
+followed by some 'optional' free-form message (some tags created
+by older Git may not have a `tagger` line).  The message, when it
+exists, is separated by a blank line from the header.  The
+message part may contain a signature that Git itself doesn't
+care about, but that can be verified with gpg.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mktree.adoc b/Documentation/git-mktree.adoc
new file mode 100644
index 0000000000..383f09dd33
--- /dev/null
+++ b/Documentation/git-mktree.adoc
@@ -0,0 +1,40 @@
+git-mktree(1)
+=============
+
+NAME
+----
+git-mktree - Build a tree-object from ls-tree formatted text
+
+
+SYNOPSIS
+--------
+[verse]
+'git mktree' [-z] [--missing] [--batch]
+
+DESCRIPTION
+-----------
+Reads standard input in non-recursive `ls-tree` output format, and creates
+a tree object.  The order of the tree entries is normalized by mktree so
+pre-sorting the input is not required.  The object name of the tree object
+built is written to the standard output.
+
+OPTIONS
+-------
+-z::
+	Read the NUL-terminated `ls-tree -z` output instead.
+
+--missing::
+	Allow missing objects.  The default behaviour (without this option)
+	is to verify that each tree entry's hash identifies an existing
+	object.  This option has no effect on the treatment of gitlink entries
+	(aka "submodules") which are always allowed to be missing.
+
+--batch::
+	Allow building of more than one tree object before exiting.  Each
+	tree is separated by a single blank line. The final newline is
+	optional.  Note - if the `-z` option is used, lines are terminated
+	with NUL.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-multi-pack-index.adoc b/Documentation/git-multi-pack-index.adoc
new file mode 100644
index 0000000000..631d5c7d15
--- /dev/null
+++ b/Documentation/git-multi-pack-index.adoc
@@ -0,0 +1,147 @@
+git-multi-pack-index(1)
+=======================
+
+NAME
+----
+git-multi-pack-index - Write and verify multi-pack-indexes
+
+
+SYNOPSIS
+--------
+[verse]
+'git multi-pack-index' [--object-dir=<dir>] [--[no-]bitmap] <sub-command>
+
+DESCRIPTION
+-----------
+Write or verify a multi-pack-index (MIDX) file.
+
+OPTIONS
+-------
+
+--object-dir=<dir>::
+	Use given directory for the location of Git objects. We check
+	`<dir>/packs/multi-pack-index` for the current MIDX file, and
+	`<dir>/packs` for the pack-files to index.
++
+`<dir>` must be an alternate of the current repository.
+
+--[no-]progress::
+	Turn progress on/off explicitly. If neither is specified, progress is
+	shown if standard error is connected to a terminal. Supported by
+	sub-commands `write`, `verify`, `expire`, and `repack.
+
+The following subcommands are available:
+
+write::
+	Write a new MIDX file. The following options are available for
+	the `write` sub-command:
++
+--
+	--preferred-pack=<pack>::
+		Optionally specify the tie-breaking pack used when
+		multiple packs contain the same object. `<pack>` must
+		contain at least one object. If not given, ties are
+		broken in favor of the pack with the lowest mtime.
+
+	--[no-]bitmap::
+		Control whether or not a multi-pack bitmap is written.
+
+	--stdin-packs::
+		Write a multi-pack index containing only the set of
+		line-delimited pack index basenames provided over stdin.
+
+	--refs-snapshot=<path>::
+		With `--bitmap`, optionally specify a file which
+		contains a "refs snapshot" taken prior to repacking.
++
+A reference snapshot is composed of line-delimited OIDs corresponding to
+the reference tips, usually taken by `git repack` prior to generating a
+new pack. A line may optionally start with a `+` character to indicate
+that the reference which corresponds to that OID is "preferred" (see
+linkgit:git-config[1]'s `pack.preferBitmapTips`.)
++
+The file given at `<path>` is expected to be readable, and can contain
+duplicates. (If a given OID is given more than once, it is marked as
+preferred if at least one instance of it begins with the special `+`
+marker).
+
+	--incremental::
+		Write an incremental MIDX file containing only objects
+		and packs not present in an existing MIDX layer.
+		Migrates non-incremental MIDXs to incremental ones when
+		necessary. Incompatible with `--bitmap`.
+--
+
+verify::
+	Verify the contents of the MIDX file.
+
+expire::
+	Delete the pack-files that are tracked by the MIDX file, but
+	have no objects referenced by the MIDX (with the exception of
+	`.keep` packs and cruft packs). Rewrite the MIDX file afterward
+	to remove all references to these pack-files.
++
+NOTE: this mode is incompatible with incremental MIDX files.
+
+repack::
+	Create a new pack-file containing objects in small pack-files
+	referenced by the multi-pack-index. If the size given by the
+	`--batch-size=<size>` argument is zero, then create a pack
+	containing all objects referenced by the multi-pack-index. For
+	a non-zero batch size, Select the pack-files by examining packs
+	from oldest-to-newest, computing the "expected size" by counting
+	the number of objects in the pack referenced by the
+	multi-pack-index, then divide by the total number of objects in
+	the pack and multiply by the pack size. We select packs with
+	expected size below the batch size until the set of packs have
+	total expected size at least the batch size, or all pack-files
+	are considered. If only one pack-file is selected, then do
+	nothing. If a new pack-file is created, rewrite the
+	multi-pack-index to reference the new pack-file. A later run of
+	'git multi-pack-index expire' will delete the pack-files that
+	were part of this batch.
++
+If `repack.packKeptObjects` is `false`, then any pack-files with an
+associated `.keep` file will not be selected for the batch to repack.
++
+NOTE: this mode is incompatible with incremental MIDX files.
+
+EXAMPLES
+--------
+
+* Write a MIDX file for the packfiles in the current `.git` directory.
++
+-----------------------------------------------
+$ git multi-pack-index write
+-----------------------------------------------
+
+* Write a MIDX file for the packfiles in the current `.git` directory with a
+corresponding bitmap.
++
+-------------------------------------------------------------
+$ git multi-pack-index write --preferred-pack=<pack> --bitmap
+-------------------------------------------------------------
+
+* Write a MIDX file for the packfiles in an alternate object store.
++
+-----------------------------------------------
+$ git multi-pack-index --object-dir <alt> write
+-----------------------------------------------
+
+* Verify the MIDX file for the packfiles in the current `.git` directory.
++
+-----------------------------------------------
+$ git multi-pack-index verify
+-----------------------------------------------
+
+
+SEE ALSO
+--------
+See link:technical/multi-pack-index.html[The Multi-Pack-Index Design
+Document] and linkgit:gitformat-pack[5] for more information on the
+multi-pack-index feature and its file format.
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-mv.adoc b/Documentation/git-mv.adoc
new file mode 100644
index 0000000000..dc1bf61534
--- /dev/null
+++ b/Documentation/git-mv.adoc
@@ -0,0 +1,69 @@
+git-mv(1)
+=========
+
+NAME
+----
+git-mv - Move or rename a file, a directory, or a symlink
+
+
+SYNOPSIS
+--------
+[verse]
+'git mv' [<options>] <source>... <destination>
+
+DESCRIPTION
+-----------
+Move or rename a file, directory, or symlink.
+
+ git mv [-v] [-f] [-n] [-k] <source> <destination>
+ git mv [-v] [-f] [-n] [-k] <source> ... <destination-directory>
+
+In the first form, it renames <source>, which must exist and be either
+a file, symlink or directory, to <destination>.
+In the second form, the last argument has to be an existing
+directory; the given sources will be moved into this directory.
+
+The index is updated after successful completion, but the change must still be
+committed.
+
+OPTIONS
+-------
+-f::
+--force::
+	Force renaming or moving of a file even if the <destination> exists.
+-k::
+	Skip move or rename actions which would lead to an error
+	condition. An error happens when a source is neither existing nor
+	controlled by Git, or when it would overwrite an existing
+	file unless `-f` is given.
+-n::
+--dry-run::
+	Do nothing; only show what would happen
+
+-v::
+--verbose::
+	Report the names of files as they are moved.
+
+SUBMODULES
+----------
+Moving a submodule using a gitfile (which means they were cloned
+with a Git version 1.7.8 or newer) will update the gitfile and
+core.worktree setting to make the submodule work in the new location.
+It also will attempt to update the submodule.<name>.path setting in
+the linkgit:gitmodules[5] file and stage that file (unless -n is used).
+
+BUGS
+----
+Each time a superproject update moves a populated submodule (e.g. when
+switching between commits before and after the move) a stale submodule
+checkout will remain in the old location and an empty directory will
+appear in the new location. To populate the submodule again in the new
+location the user will have to run "git submodule update"
+afterwards. Removing the old directory is only safe when it uses a
+gitfile, as otherwise the history of the submodule will be deleted
+too. Both steps will be obsolete when recursive submodule update has
+been implemented.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-name-rev.adoc b/Documentation/git-name-rev.adoc
new file mode 100644
index 0000000000..d4f1c4d594
--- /dev/null
+++ b/Documentation/git-name-rev.adoc
@@ -0,0 +1,112 @@
+git-name-rev(1)
+===============
+
+NAME
+----
+git-name-rev - Find symbolic names for given revs
+
+
+SYNOPSIS
+--------
+[verse]
+'git name-rev' [--tags] [--refs=<pattern>]
+	       ( --all | --annotate-stdin | <commit-ish>... )
+
+DESCRIPTION
+-----------
+Finds symbolic names suitable for human digestion for revisions given in any
+format parsable by 'git rev-parse'.
+
+
+OPTIONS
+-------
+
+--tags::
+	Do not use branch names, but only tags to name the commits
+
+--refs=<pattern>::
+	Only use refs whose names match a given shell pattern.  The pattern
+	can be a branch name, a tag name, or a fully qualified ref name. If
+	given multiple times, use refs whose names match any of the given shell
+	patterns. Use `--no-refs` to clear any previous ref patterns given.
+
+--exclude=<pattern>::
+	Do not use any ref whose name matches a given shell pattern. The
+	pattern can be one of branch name, tag name or fully qualified ref
+	name. If given multiple times, a ref will be excluded when it matches
+	any of the given patterns. When used together with --refs, a ref will
+	be used as a match only when it matches at least one --refs pattern and
+	does not match any --exclude patterns. Use `--no-exclude` to clear the
+	list of exclude patterns.
+
+--all::
+	List all commits reachable from all refs
+
+--annotate-stdin::
+	Transform stdin by substituting all the 40-character SHA-1
+	hexes (say $hex) with "$hex ($rev_name)".  When used with
+	--name-only, substitute with "$rev_name", omitting $hex
+	altogether. This option was called `--stdin` in older versions
+	of Git.
++
+For example:
++
+-----------
+$ cat sample.txt
+
+An abbreviated revision 2ae0a9cb82 will not be substituted.
+The full name after substitution is 2ae0a9cb8298185a94e5998086f380a355dd8907,
+while its tree object is 70d105cc79e63b81cfdcb08a15297c23e60b07ad
+
+$ git name-rev --annotate-stdin <sample.txt
+
+An abbreviated revision 2ae0a9cb82 will not be substituted.
+The full name after substitution is 2ae0a9cb8298185a94e5998086f380a355dd8907 (master),
+while its tree object is 70d105cc79e63b81cfdcb08a15297c23e60b07ad
+
+$ git name-rev --name-only --annotate-stdin <sample.txt
+
+An abbreviated revision 2ae0a9cb82 will not be substituted.
+The full name after substitution is master,
+while its tree object is 70d105cc79e63b81cfdcb08a15297c23e60b07ad
+-----------
+
+--name-only::
+	Instead of printing both the SHA-1 and the name, print only
+	the name.  If given with --tags the usual tag prefix of
+	"tags/" is also omitted from the name, matching the output
+	of `git-describe` more closely.
+
+--no-undefined::
+	Die with error code != 0 when a reference is undefined,
+	instead of printing `undefined`.
+
+--always::
+	Show uniquely abbreviated commit object as fallback.
+
+EXAMPLES
+--------
+
+Given a commit, find out where it is relative to the local refs. Say somebody
+wrote you about that fantastic commit 33db5f4d9027a10e477ccf054b2c1ab94f74c85a.
+Of course, you look into the commit, but that only tells you what happened, but
+not the context.
+
+Enter 'git name-rev':
+
+------------
+% git name-rev 33db5f4d9027a10e477ccf054b2c1ab94f74c85a
+33db5f4d9027a10e477ccf054b2c1ab94f74c85a tags/v0.99~940
+------------
+
+Now you are wiser, because you know that it happened 940 revisions before v0.99.
+
+Another nice thing you can do is:
+
+------------
+% git log | git name-rev --annotate-stdin
+------------
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-notes.adoc b/Documentation/git-notes.adoc
new file mode 100644
index 0000000000..d04989805a
--- /dev/null
+++ b/Documentation/git-notes.adoc
@@ -0,0 +1,386 @@
+git-notes(1)
+============
+
+NAME
+----
+git-notes - Add or inspect object notes
+
+SYNOPSIS
+--------
+[verse]
+'git notes' [list [<object>]]
+'git notes' add [-f] [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [-e] [<object>]
+'git notes' copy [-f] ( --stdin | <from-object> [<to-object>] )
+'git notes' append [--allow-empty] [--[no-]separator | --separator=<paragraph-break>] [--[no-]stripspace] [-F <file> | -m <msg> | (-c | -C) <object>] [-e] [<object>]
+'git notes' edit [--allow-empty] [<object>] [--[no-]stripspace]
+'git notes' show [<object>]
+'git notes' merge [-v | -q] [-s <strategy> ] <notes-ref>
+'git notes' merge --commit [-v | -q]
+'git notes' merge --abort [-v | -q]
+'git notes' remove [--ignore-missing] [--stdin] [<object>...]
+'git notes' prune [-n] [-v]
+'git notes' get-ref
+
+
+DESCRIPTION
+-----------
+Adds, removes, or reads notes attached to objects, without touching
+the objects themselves.
+
+By default, notes are saved to and read from `refs/notes/commits`, but
+this default can be overridden.  See the OPTIONS, CONFIGURATION, and
+ENVIRONMENT sections below.  If this ref does not exist, it will be
+quietly created when it is first needed to store a note.
+
+A typical use of notes is to supplement a commit message without
+changing the commit itself. Notes can be shown by 'git log' along with
+the original commit message. To distinguish these notes from the
+message stored in the commit object, the notes are indented like the
+message, after an unindented line saying "Notes (<refname>):" (or
+"Notes:" for `refs/notes/commits`).
+
+Notes can also be added to patches prepared with `git format-patch` by
+using the `--notes` option. Such notes are added as a patch commentary
+after a three dash separator line.
+
+To change which notes are shown by 'git log', see the
+"notes.displayRef" discussion in <<CONFIGURATION>>.
+
+See the "notes.rewrite.<command>" configuration for a way to carry
+notes across commands that rewrite commits.
+
+
+SUBCOMMANDS
+-----------
+
+list::
+	List the notes object for a given object. If no object is
+	given, show a list of all note objects and the objects they
+	annotate (in the format "<note-object> <annotated-object>").
+	This is the default subcommand if no subcommand is given.
+
+add::
+	Add notes for a given object (defaults to HEAD). Abort if the
+	object already has notes (use `-f` to overwrite existing notes).
+	However, if you're using `add` interactively (using an editor
+	to supply the notes contents), then - instead of aborting -
+	the existing notes will be opened in the editor (like the `edit`
+	subcommand). If you specify multiple `-m` and `-F`, a blank
+	line will be inserted between the messages. Use the `--separator`
+	option to insert other delimiters. You can use `-e` to edit and
+	fine-tune the message(s) supplied from `-m` and `-F` options
+	interactively (using an editor) before adding the note.
+
+copy::
+	Copy the notes for the first object onto the second object (defaults to
+	HEAD). Abort if the second object already has notes, or if the first
+	object has none (use -f to overwrite existing notes to the
+	second object). This subcommand is equivalent to:
+	`git notes add [-f] -C $(git notes list <from-object>) <to-object>`
++
+In `--stdin` mode, take lines in the format
++
+----------
+<from-object> SP <to-object> [ SP <rest> ] LF
+----------
++
+on standard input, and copy the notes from each <from-object> to its
+corresponding <to-object>.  (The optional `<rest>` is ignored so that
+the command can read the input given to the `post-rewrite` hook.)
+
+append::
+	Append new message(s) given by `-m` or `-F` options to an
+	existing note, or add them as a new note if one does not
+	exist, for the object (defaults to HEAD).  When appending to
+	an existing note, a blank line is added before each new
+	message as an inter-paragraph separator.  The separator can
+	be customized with the `--separator` option.
+	Edit the notes to be appended given by `-m` and `-F` options with
+	`-e` interactively (using an editor) before appending the note.
+
+edit::
+	Edit the notes for a given object (defaults to HEAD).
+
+show::
+	Show the notes for a given object (defaults to HEAD).
+
+merge::
+	Merge the given notes ref into the current notes ref.
+	This will try to merge the changes made by the given
+	notes ref (called "remote") since the merge-base (if
+	any) into the current notes ref (called "local").
++
+If conflicts arise and a strategy for automatically resolving
+conflicting notes (see the "NOTES MERGE STRATEGIES" section) is not given,
+the "manual" resolver is used. This resolver checks out the
+conflicting notes in a special worktree (`.git/NOTES_MERGE_WORKTREE`),
+and instructs the user to manually resolve the conflicts there.
+When done, the user can either finalize the merge with
+'git notes merge --commit', or abort the merge with
+'git notes merge --abort'.
+
+remove::
+	Remove the notes for given objects (defaults to HEAD). When
+	giving zero or one object from the command line, this is
+	equivalent to specifying an empty note message to
+	the `edit` subcommand.
+
+prune::
+	Remove all notes for non-existing/unreachable objects.
+
+get-ref::
+	Print the current notes ref. This provides an easy way to
+	retrieve the current notes ref (e.g. from scripts).
+
+OPTIONS
+-------
+-f::
+--force::
+	When adding notes to an object that already has notes,
+	overwrite the existing notes (instead of aborting).
+
+-m <msg>::
+--message=<msg>::
+	Use the given note message (instead of prompting).
+	If multiple `-m` options are given, their values
+	are concatenated as separate paragraphs.
+	Lines starting with `#` and empty lines other than a
+	single line between paragraphs will be stripped out.
+	If you wish to keep them verbatim, use `--no-stripspace`.
+
+-F <file>::
+--file=<file>::
+	Take the note message from the given file.  Use '-' to
+	read the note message from the standard input.
+	Lines starting with `#` and empty lines other than a
+	single line between paragraphs will be stripped out.
+	If you wish to keep them verbatim, use `--no-stripspace`.
+
+-C <object>::
+--reuse-message=<object>::
+	Take the given blob object (for example, another note) as the
+	note message. (Use `git notes copy <object>` instead to
+	copy notes between objects.).  By default, message will be
+	copied verbatim, but if you wish to strip out the lines
+	starting with `#` and empty lines other than a single line
+	between paragraphs, use with`--stripspace` option.
+
+-c <object>::
+--reedit-message=<object>::
+	Like '-C', but with `-c` the editor is invoked, so that
+	the user can further edit the note message.
+
+--allow-empty::
+	Allow an empty note object to be stored. The default behavior is
+	to automatically remove empty notes.
+
+--[no-]separator, --separator=<paragraph-break>::
+	Specify a string used as a custom inter-paragraph separator
+	(a newline is added at the end as needed). If `--no-separator`, no
+	separators will be added between paragraphs.  Defaults to a blank
+	line.
+
+--[no-]stripspace::
+	Strip leading and trailing whitespace from the note message.
+	Also strip out empty lines other than a single line between
+	paragraphs. Lines starting with `#` will be stripped out
+	in non-editor cases like `-m`, `-F` and `-C`, but not in
+	editor case like `git notes edit`, `-c`, etc.
+
+--ref <ref>::
+	Manipulate the notes tree in <ref>.  This overrides
+	`GIT_NOTES_REF` and the "core.notesRef" configuration.  The ref
+	specifies the full refname when it begins with `refs/notes/`; when it
+	begins with `notes/`, `refs/` and otherwise `refs/notes/` is prefixed
+	to form a full name of the ref.
+
+--ignore-missing::
+	Do not consider it an error to request removing notes from an
+	object that does not have notes attached to it.
+
+--stdin::
+	Also read the object names to remove notes from the standard
+	input (there is no reason you cannot combine this with object
+	names from the command line).
+
+-n::
+--dry-run::
+	Do not remove anything; just report the object names whose notes
+	would be removed.
+
+-s <strategy>::
+--strategy=<strategy>::
+	When merging notes, resolve notes conflicts using the given
+	strategy. The following strategies are recognized: "manual"
+	(default), "ours", "theirs", "union" and "cat_sort_uniq".
+	This option overrides the "notes.mergeStrategy" configuration setting.
+	See the "NOTES MERGE STRATEGIES" section below for more
+	information on each notes merge strategy.
+
+--commit::
+	Finalize an in-progress 'git notes merge'. Use this option
+	when you have resolved the conflicts that 'git notes merge'
+	stored in .git/NOTES_MERGE_WORKTREE. This amends the partial
+	merge commit created by 'git notes merge' (stored in
+	.git/NOTES_MERGE_PARTIAL) by adding the notes in
+	.git/NOTES_MERGE_WORKTREE. The notes ref stored in the
+	.git/NOTES_MERGE_REF symref is updated to the resulting commit.
+
+--abort::
+	Abort/reset an in-progress 'git notes merge', i.e. a notes merge
+	with conflicts. This simply removes all files related to the
+	notes merge.
+
+-q::
+--quiet::
+	When merging notes, operate quietly.
+
+-v::
+--verbose::
+	When merging notes, be more verbose.
+	When pruning notes, report all object names whose notes are
+	removed.
+
+
+DISCUSSION
+----------
+
+Commit notes are blobs containing extra information about an object
+(usually information to supplement a commit's message).  These blobs
+are taken from notes refs.  A notes ref is usually a branch which
+contains "files" whose paths are the object names for the objects
+they describe, with some directory separators included for performance
+reasons footnote:[Permitted pathnames have the form
+'bf'`/`'fe'`/`'30'`/`'...'`/`'680d5a...': a sequence of directory
+names of two hexadecimal digits each followed by a filename with the
+rest of the object ID.].
+
+Every notes change creates a new commit at the specified notes ref.
+You can therefore inspect the history of the notes by invoking, e.g.,
+`git log -p notes/commits`.  Currently the commit message only records
+which operation triggered the update, and the commit authorship is
+determined according to the usual rules (see linkgit:git-commit[1]).
+These details may change in the future.
+
+It is also permitted for a notes ref to point directly to a tree
+object, in which case the history of the notes can be read with
+`git log -p -g <refname>`.
+
+
+NOTES MERGE STRATEGIES
+----------------------
+
+The default notes merge strategy is "manual", which checks out
+conflicting notes in a special work tree for resolving notes conflicts
+(`.git/NOTES_MERGE_WORKTREE`), and instructs the user to resolve the
+conflicts in that work tree.
+When done, the user can either finalize the merge with
+'git notes merge --commit', or abort the merge with
+'git notes merge --abort'.
+
+Users may select an automated merge strategy from among the following using
+either -s/--strategy option or configuring notes.mergeStrategy accordingly:
+
+"ours" automatically resolves conflicting notes in favor of the local
+version (i.e. the current notes ref).
+
+"theirs" automatically resolves notes conflicts in favor of the remote
+version (i.e. the given notes ref being merged into the current notes
+ref).
+
+"union" automatically resolves notes conflicts by concatenating the
+local and remote versions.
+
+"cat_sort_uniq" is similar to "union", but in addition to concatenating
+the local and remote versions, this strategy also sorts the resulting
+lines, and removes duplicate lines from the result. This is equivalent
+to applying the "cat | sort | uniq" shell pipeline to the local and
+remote versions. This strategy is useful if the notes follow a line-based
+format where one wants to avoid duplicated lines in the merge result.
+Note that if either the local or remote version contain duplicate lines
+prior to the merge, these will also be removed by this notes merge
+strategy.
+
+
+EXAMPLES
+--------
+
+You can use notes to add annotations with information that was not
+available at the time a commit was written.
+
+------------
+$ git notes add -m 'Tested-by: Johannes Sixt <j6t@xxxxxxxx>' 72a144e2
+$ git show -s 72a144e
+[...]
+    Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx>
+
+Notes:
+    Tested-by: Johannes Sixt <j6t@xxxxxxxx>
+------------
+
+In principle, a note is a regular Git blob, and any kind of
+(non-)format is accepted.  You can binary-safely create notes from
+arbitrary files using 'git hash-object':
+
+------------
+$ cc *.c
+$ blob=$(git hash-object -w a.out)
+$ git notes --ref=built add --allow-empty -C "$blob" HEAD
+------------
+
+(You cannot simply use `git notes --ref=built add -F a.out HEAD`
+because that is not binary-safe.)
+Of course, it doesn't make much sense to display non-text-format notes
+with 'git log', so if you use such notes, you'll probably need to write
+some special-purpose tools to do something useful with them.
+
+
+[[CONFIGURATION]]
+CONFIGURATION
+-------------
+
+core.notesRef::
+	Notes ref to read and manipulate instead of
+	`refs/notes/commits`.  Must be an unabbreviated ref name.
+	This setting can be overridden through the environment and
+	command line.
+
+include::includes/cmd-config-section-rest.txt[]
+
+include::config/notes.adoc[]
+
+
+ENVIRONMENT
+-----------
+
+`GIT_NOTES_REF`::
+	Which ref to manipulate notes from, instead of `refs/notes/commits`.
+	This overrides the `core.notesRef` setting.
+
+`GIT_NOTES_DISPLAY_REF`::
+	Colon-delimited list of refs or globs indicating which refs,
+	in addition to the default from `core.notesRef` or
+	`GIT_NOTES_REF`, to read notes from when showing commit
+	messages.
+	This overrides the `notes.displayRef` setting.
++
+A warning will be issued for refs that do not exist, but a glob that
+does not match any refs is silently ignored.
+
+`GIT_NOTES_REWRITE_MODE`::
+	When copying notes during a rewrite, what to do if the target
+	commit already has a note.
+	Must be one of `overwrite`, `concatenate`, `cat_sort_uniq`, or `ignore`.
+	This overrides the `core.rewriteMode` setting.
+
+`GIT_NOTES_REWRITE_REF`::
+	When rewriting commits, which notes to copy from the original
+	to the rewritten commit.  Must be a colon-delimited list of
+	refs or globs.
++
+If not set in the environment, the list of notes to copy depends
+on the `notes.rewrite.<command>` and `notes.rewriteRef` settings.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-p4.adoc b/Documentation/git-p4.adoc
new file mode 100644
index 0000000000..de5ee6748e
--- /dev/null
+++ b/Documentation/git-p4.adoc
@@ -0,0 +1,803 @@
+git-p4(1)
+=========
+
+NAME
+----
+git-p4 - Import from and submit to Perforce repositories
+
+
+SYNOPSIS
+--------
+[verse]
+'git p4 clone' [<sync-options>] [<clone-options>] <p4-depot-path>...
+'git p4 sync' [<sync-options>] [<p4-depot-path>...]
+'git p4 rebase'
+'git p4 submit' [<submit-options>] [<master-branch-name>]
+
+
+DESCRIPTION
+-----------
+This command provides a way to interact with p4 repositories
+using Git.
+
+Create a new Git repository from an existing p4 repository using
+'git p4 clone', giving it one or more p4 depot paths.  Incorporate
+new commits from p4 changes with 'git p4 sync'.  The 'sync' command
+is also used to include new branches from other p4 depot paths.
+Submit Git changes back to p4 using 'git p4 submit'.  The command
+'git p4 rebase' does a sync plus rebases the current branch onto
+the updated p4 remote branch.
+
+
+EXAMPLES
+--------
+* Clone a repository:
++
+------------
+$ git p4 clone //depot/path/project
+------------
+
+* Do some work in the newly created Git repository:
++
+------------
+$ cd project
+$ vi foo.h
+$ git commit -a -m "edited foo.h"
+------------
+
+* Update the Git repository with recent changes from p4, rebasing your
+  work on top:
++
+------------
+$ git p4 rebase
+------------
+
+* Submit your commits back to p4:
++
+------------
+$ git p4 submit
+------------
+
+
+COMMANDS
+--------
+
+Clone
+~~~~~
+Generally, 'git p4 clone' is used to create a new Git directory
+from an existing p4 repository:
+------------
+$ git p4 clone //depot/path/project
+------------
+This:
+
+1. Creates an empty Git repository in a subdirectory called 'project'.
++
+2. Imports the full contents of the head revision from the given p4
+   depot path into a single commit in the Git branch 'refs/remotes/p4/master'.
++
+3. Creates a local branch, 'master' from this remote and checks it out.
+
+To reproduce the entire p4 history in Git, use the '@all' modifier on
+the depot path:
+------------
+$ git p4 clone //depot/path/project@all
+------------
+
+
+Sync
+~~~~
+As development continues in the p4 repository, those changes can
+be included in the Git repository using:
+------------
+$ git p4 sync
+------------
+This command finds new changes in p4 and imports them as Git commits.
+
+P4 repositories can be added to an existing Git repository using
+'git p4 sync' too:
+------------
+$ mkdir repo-git
+$ cd repo-git
+$ git init
+$ git p4 sync //path/in/your/perforce/depot
+------------
+This imports the specified depot into
+'refs/remotes/p4/master' in an existing Git repository.  The
+`--branch` option can be used to specify a different branch to
+be used for the p4 content.
+
+If a Git repository includes branches 'refs/remotes/origin/p4', these
+will be fetched and consulted first during a 'git p4 sync'.  Since
+importing directly from p4 is considerably slower than pulling changes
+from a Git remote, this can be useful in a multi-developer environment.
+
+If there are multiple branches, doing 'git p4 sync' will automatically
+use the "BRANCH DETECTION" algorithm to try to partition new changes
+into the right branch.  This can be overridden with the `--branch`
+option to specify just a single branch to update.
+
+
+Rebase
+~~~~~~
+A common working pattern is to fetch the latest changes from the p4 depot
+and merge them with local uncommitted changes.  Often, the p4 repository
+is the ultimate location for all code, thus a rebase workflow makes
+sense.  This command does 'git p4 sync' followed by 'git rebase' to move
+local commits on top of updated p4 changes.
+------------
+$ git p4 rebase
+------------
+
+
+Submit
+~~~~~~
+Submitting changes from a Git repository back to the p4 repository
+requires a separate p4 client workspace.  This should be specified
+using the `P4CLIENT` environment variable or the Git configuration
+variable 'git-p4.client'.  The p4 client must exist, but the client root
+will be created and populated if it does not already exist.
+
+To submit all changes that are in the current Git branch but not in
+the 'p4/master' branch, use:
+------------
+$ git p4 submit
+------------
+
+To specify a branch other than the current one, use:
+------------
+$ git p4 submit topicbranch
+------------
+
+To specify a single commit or a range of commits, use:
+------------
+$ git p4 submit --commit <sha1>
+$ git p4 submit --commit <sha1..sha1>
+------------
+
+The upstream reference is generally 'refs/remotes/p4/master', but can
+be overridden using the `--origin=` command-line option.
+
+The p4 changes will be created as the user invoking 'git p4 submit'. The
+`--preserve-user` option will cause ownership to be modified
+according to the author of the Git commit.  This option requires admin
+privileges in p4, which can be granted using 'p4 protect'.
+
+To shelve changes instead of submitting, use `--shelve` and `--update-shelve`:
+
+----
+$ git p4 submit --shelve
+$ git p4 submit --update-shelve 1234 --update-shelve 2345
+----
+
+
+Unshelve
+~~~~~~~~
+Unshelving will take a shelved P4 changelist, and produce the equivalent git commit
+in the branch refs/remotes/p4-unshelved/<changelist>.
+
+The git commit is created relative to the current origin revision (HEAD by default).
+A parent commit is created based on the origin, and then the unshelve commit is
+created based on that.
+
+The origin revision can be changed with the "--origin" option.
+
+If the target branch in refs/remotes/p4-unshelved already exists, the old one will
+be renamed.
+
+----
+$ git p4 sync
+$ git p4 unshelve 12345
+$ git show p4-unshelved/12345
+<submit more changes via p4 to the same files>
+$ git p4 unshelve 12345
+<refuses to unshelve until git is in sync with p4 again>
+
+----
+
+OPTIONS
+-------
+
+General options
+~~~~~~~~~~~~~~~
+All commands except clone accept these options.
+
+--git-dir <dir>::
+	Set the `GIT_DIR` environment variable.  See linkgit:git[1].
+
+-v::
+--verbose::
+	Provide more progress information.
+
+Sync options
+~~~~~~~~~~~~
+These options can be used in the initial 'clone' as well as in
+subsequent 'sync' operations.
+
+--branch <ref>::
+	Import changes into <ref> instead of refs/remotes/p4/master.
+	If <ref> starts with refs/, it is used as is.  Otherwise, if
+	it does not start with p4/, that prefix is added.
++
+By default a <ref> not starting with refs/ is treated as the
+name of a remote-tracking branch (under refs/remotes/).  This
+behavior can be modified using the --import-local option.
++
+The default <ref> is "master".
++
+This example imports a new remote "p4/proj2" into an existing
+Git repository:
++
+----
+    $ git init
+    $ git p4 sync --branch=refs/remotes/p4/proj2 //depot/proj2
+----
+
+--detect-branches::
+	Use the branch detection algorithm to find new paths in p4.  It is
+	documented below in "BRANCH DETECTION".
+
+--changesfile <file>::
+	Import exactly the p4 change numbers listed in 'file', one per
+	line.  Normally, 'git p4' inspects the current p4 repository
+	state and detects the changes it should import.
+
+--silent::
+	Do not print any progress information.
+
+--detect-labels::
+	Query p4 for labels associated with the depot paths, and add
+	them as tags in Git. Limited usefulness as only imports labels
+	associated with new changelists. Deprecated.
+
+--import-labels::
+	Import labels from p4 into Git.
+
+--import-local::
+	By default, p4 branches are stored in 'refs/remotes/p4/',
+	where they will be treated as remote-tracking branches by
+	linkgit:git-branch[1] and other commands.  This option instead
+	puts p4 branches in 'refs/heads/p4/'.  Note that future
+	sync operations must specify `--import-local` as well so that
+	they can find the p4 branches in refs/heads.
+
+--max-changes <n>::
+	Import at most 'n' changes, rather than the entire range of
+	changes included in the given revision specifier. A typical
+	usage would be use '@all' as the revision specifier, but then
+	to use '--max-changes 1000' to import only the last 1000
+	revisions rather than the entire revision history.
+
+--changes-block-size <n>::
+	The internal block size to use when converting a revision
+	specifier such as '@all' into a list of specific change
+	numbers. Instead of using a single call to 'p4 changes' to
+	find the full list of changes for the conversion, there are a
+	sequence of calls to 'p4 changes -m', each of which requests
+	one block of changes of the given size. The default block size
+	is 500, which should usually be suitable.
+
+--keep-path::
+	The mapping of file names from the p4 depot path to Git, by
+	default, involves removing the entire depot path.  With this
+	option, the full p4 depot path is retained in Git.  For example,
+	path '//depot/main/foo/bar.c', when imported from
+	'//depot/main/', becomes 'foo/bar.c'.  With `--keep-path`, the
+	Git path is instead 'depot/main/foo/bar.c'.
+
+--use-client-spec::
+	Use a client spec to find the list of interesting files in p4.
+	See the "CLIENT SPEC" section below.
+
+-/ <path>::
+	Exclude selected depot paths when cloning or syncing.
+
+Clone options
+~~~~~~~~~~~~~
+These options can be used in an initial 'clone', along with the 'sync'
+options described above.
+
+--destination <directory>::
+	Where to create the Git repository.  If not provided, the last
+	component in the p4 depot path is used to create a new
+	directory.
+
+--bare::
+	Perform a bare clone.  See linkgit:git-clone[1].
+
+Submit options
+~~~~~~~~~~~~~~
+These options can be used to modify 'git p4 submit' behavior.
+
+--origin <commit>::
+	Upstream location from which commits are identified to submit to
+	p4.  By default, this is the most recent p4 commit reachable
+	from `HEAD`.
+
+-M::
+	Detect renames.  See linkgit:git-diff[1].  Renames will be
+	represented in p4 using explicit 'move' operations.  There
+	is no corresponding option to detect copies, but there are
+	variables for both moves and copies.
+
+--preserve-user::
+	Re-author p4 changes before submitting to p4.  This option
+	requires p4 admin privileges.
+
+--export-labels::
+	Export tags from Git as p4 labels. Tags found in Git are applied
+	to the perforce working directory.
+
+-n::
+--dry-run::
+	Show just what commits would be submitted to p4; do not change
+	state in Git or p4.
+
+--prepare-p4-only::
+	Apply a commit to the p4 workspace, opening, adding and deleting
+	files in p4 as for a normal submit operation.  Do not issue the
+	final "p4 submit", but instead print a message about how to
+	submit manually or revert.  This option always stops after the
+	first (oldest) commit.  Git tags are not exported to p4.
+
+--shelve::
+	Instead of submitting create a series of shelved changelists.
+	After creating each shelve, the relevant files are reverted/deleted.
+	If you have multiple commits pending multiple shelves will be created.
+
+--update-shelve CHANGELIST::
+	Update an existing shelved changelist with this commit. Implies
+	--shelve. Repeat for multiple shelved changelists.
+
+--conflict=(ask|skip|quit)::
+	Conflicts can occur when applying a commit to p4.  When this
+	happens, the default behavior ("ask") is to prompt whether to
+	skip this commit and continue, or quit.  This option can be used
+	to bypass the prompt, causing conflicting commits to be automatically
+	skipped, or to quit trying to apply commits, without prompting.
+
+--branch <branch>::
+	After submitting, sync this named branch instead of the default
+	p4/master.  See the "Sync options" section above for more
+	information.
+
+--commit (<sha1>|<sha1>..<sha1>)::
+    Submit only the specified commit or range of commits, instead of the full
+    list of changes that are in the current Git branch.
+
+--disable-rebase::
+    Disable the automatic rebase after all commits have been successfully
+    submitted. Can also be set with git-p4.disableRebase.
+
+--disable-p4sync::
+    Disable the automatic sync of p4/master from Perforce after commits have
+    been submitted. Implies --disable-rebase. Can also be set with
+    git-p4.disableP4Sync. Sync with origin/master still goes ahead if possible.
+
+Hooks for submit
+----------------
+
+p4-pre-submit
+~~~~~~~~~~~~~
+
+The `p4-pre-submit` hook is executed if it exists and is executable.
+The hook takes no parameters and nothing from standard input. Exiting with
+non-zero status from this script prevents `git-p4 submit` from launching.
+It can be bypassed with the `--no-verify` command line option.
+
+One usage scenario is to run unit tests in the hook.
+
+p4-prepare-changelist
+~~~~~~~~~~~~~~~~~~~~~
+
+The `p4-prepare-changelist` hook is executed right after preparing
+the default changelist message and before the editor is started.
+It takes one parameter, the name of the file that contains the
+changelist text. Exiting with a non-zero status from the script
+will abort the process.
+
+The purpose of the hook is to edit the message file in place,
+and it is not suppressed by the `--no-verify` option. This hook
+is called even if `--prepare-p4-only` is set.
+
+p4-changelist
+~~~~~~~~~~~~~
+
+The `p4-changelist` hook is executed after the changelist
+message has been edited by the user. It can be bypassed with the
+`--no-verify` option. It takes a single parameter, the name
+of the file that holds the proposed changelist text. Exiting
+with a non-zero status causes the command to abort.
+
+The hook is allowed to edit the changelist file and can be used
+to normalize the text into some project standard format. It can
+also be used to refuse the Submit after inspect the message file.
+
+p4-post-changelist
+~~~~~~~~~~~~~~~~~~
+
+The `p4-post-changelist` hook is invoked after the submit has
+successfully occurred in P4. It takes no parameters and is meant
+primarily for notification and cannot affect the outcome of the
+git p4 submit action.
+
+
+
+Rebase options
+~~~~~~~~~~~~~~
+These options can be used to modify 'git p4 rebase' behavior.
+
+--import-labels::
+	Import p4 labels.
+
+Unshelve options
+~~~~~~~~~~~~~~~~
+
+--origin::
+    Sets the git refspec against which the shelved P4 changelist is compared.
+    Defaults to p4/master.
+
+DEPOT PATH SYNTAX
+-----------------
+The p4 depot path argument to 'git p4 sync' and 'git p4 clone' can
+be one or more space-separated p4 depot paths, with an optional
+p4 revision specifier on the end:
+
+"//depot/my/project"::
+    Import one commit with all files in the '#head' change under that tree.
+
+"//depot/my/project@all"::
+    Import one commit for each change in the history of that depot path.
+
+"//depot/my/project@1,6"::
+    Import only changes 1 through 6.
+
+"//depot/proj1@all //depot/proj2@all"::
+    Import all changes from both named depot paths into a single
+    repository.  Only files below these directories are included.
+    There is not a subdirectory in Git for each "proj1" and "proj2".
+    You must use the `--destination` option when specifying more
+    than one depot path.  The revision specifier must be specified
+    identically on each depot path.  If there are files in the
+    depot paths with the same name, the path with the most recently
+    updated version of the file is the one that appears in Git.
+
+See 'p4 help revisions' for the full syntax of p4 revision specifiers.
+
+
+CLIENT SPEC
+-----------
+The p4 client specification is maintained with the 'p4 client' command
+and contains among other fields, a View that specifies how the depot
+is mapped into the client repository.  The 'clone' and 'sync' commands
+can consult the client spec when given the `--use-client-spec` option or
+when the useClientSpec variable is true.  After 'git p4 clone', the
+useClientSpec variable is automatically set in the repository
+configuration file.  This allows future 'git p4 submit' commands to
+work properly; the submit command looks only at the variable and does
+not have a command-line option.
+
+The full syntax for a p4 view is documented in 'p4 help views'.  'git p4'
+knows only a subset of the view syntax.  It understands multi-line
+mappings, overlays with '+', exclusions with '-' and double-quotes
+around whitespace.  Of the possible wildcards, 'git p4' only handles
+'...', and only when it is at the end of the path.  'git p4' will complain
+if it encounters an unhandled wildcard.
+
+Bugs in the implementation of overlap mappings exist.  If multiple depot
+paths map through overlays to the same location in the repository,
+'git p4' can choose the wrong one.  This is hard to solve without
+dedicating a client spec just for 'git p4'.
+
+The name of the client can be given to 'git p4' in multiple ways.  The
+variable 'git-p4.client' takes precedence if it exists.  Otherwise,
+normal p4 mechanisms of determining the client are used:  environment
+variable `P4CLIENT`, a file referenced by `P4CONFIG`, or the local host name.
+
+
+BRANCH DETECTION
+----------------
+P4 does not have the same concept of a branch as Git.  Instead,
+p4 organizes its content as a directory tree, where by convention
+different logical branches are in different locations in the tree.
+The 'p4 branch' command is used to maintain mappings between
+different areas in the tree, and indicate related content.  'git p4'
+can use these mappings to determine branch relationships.
+
+If you have a repository where all the branches of interest exist as
+subdirectories of a single depot path, you can use `--detect-branches`
+when cloning or syncing to have 'git p4' automatically find
+subdirectories in p4, and to generate these as branches in Git.
+
+For example, if the P4 repository structure is:
+----
+//depot/main/...
+//depot/branch1/...
+----
+
+And "p4 branch -o branch1" shows a View line that looks like:
+----
+//depot/main/... //depot/branch1/...
+----
+
+Then this 'git p4 clone' command:
+----
+git p4 clone --detect-branches //depot@all
+----
+produces a separate branch in 'refs/remotes/p4/' for //depot/main,
+called 'master', and one for //depot/branch1 called 'depot/branch1'.
+
+However, it is not necessary to create branches in p4 to be able to use
+them like branches.  Because it is difficult to infer branch
+relationships automatically, a Git configuration setting
+'git-p4.branchList' can be used to explicitly identify branch
+relationships.  It is a list of "source:destination" pairs, like a
+simple p4 branch specification, where the "source" and "destination" are
+the path elements in the p4 repository.  The example above relied on the
+presence of the p4 branch.  Without p4 branches, the same result will
+occur with:
+----
+git init depot
+cd depot
+git config git-p4.branchList main:branch1
+git p4 clone --detect-branches //depot@all .
+----
+
+
+PERFORMANCE
+-----------
+The fast-import mechanism used by 'git p4' creates one pack file for
+each invocation of 'git p4 sync'.  Normally, Git garbage compression
+(linkgit:git-gc[1]) automatically compresses these to fewer pack files,
+but explicit invocation of 'git repack -adf' may improve performance.
+
+
+CONFIGURATION VARIABLES
+-----------------------
+The following config settings can be used to modify 'git p4' behavior.
+They all are in the 'git-p4' section.
+
+General variables
+~~~~~~~~~~~~~~~~~
+git-p4.user::
+	User specified as an option to all p4 commands, with '-u <user>'.
+	The environment variable `P4USER` can be used instead.
+
+git-p4.password::
+	Password specified as an option to all p4 commands, with
+	'-P <password>'.
+	The environment variable `P4PASS` can be used instead.
+
+git-p4.port::
+	Port specified as an option to all p4 commands, with
+	'-p <port>'.
+	The environment variable `P4PORT` can be used instead.
+
+git-p4.host::
+	Host specified as an option to all p4 commands, with
+	'-h <host>'.
+	The environment variable `P4HOST` can be used instead.
+
+git-p4.client::
+	Client specified as an option to all p4 commands, with
+	'-c <client>', including the client spec.
+
+git-p4.retries::
+	Specifies the number of times to retry a p4 command (notably,
+	'p4 sync') if the network times out. The default value is 3.
+	Set the value to 0 to disable retries or if your p4 version
+	does not support retries (pre 2012.2).
+
+Clone and sync variables
+~~~~~~~~~~~~~~~~~~~~~~~~
+git-p4.syncFromOrigin::
+	Because importing commits from other Git repositories is much faster
+	than importing them from p4, a mechanism exists to find p4 changes
+	first in Git remotes.  If branches exist under 'refs/remote/origin/p4',
+	those will be fetched and used when syncing from p4.  This
+	variable can be set to 'false' to disable this behavior.
+
+git-p4.branchUser::
+	One phase in branch detection involves looking at p4 branches
+	to find new ones to import.  By default, all branches are
+	inspected.  This option limits the search to just those owned
+	by the single user named in the variable.
+
+git-p4.branchList::
+	List of branches to be imported when branch detection is
+	enabled.  Each entry should be a pair of branch names separated
+	by a colon (:).  This example declares that both branchA and
+	branchB were created from main:
++
+-------------
+git config       git-p4.branchList main:branchA
+git config --add git-p4.branchList main:branchB
+-------------
+
+git-p4.ignoredP4Labels::
+	List of p4 labels to ignore. This is built automatically as
+	unimportable labels are discovered.
+
+git-p4.importLabels::
+	Import p4 labels into git, as per --import-labels.
+
+git-p4.labelImportRegexp::
+	Only p4 labels matching this regular expression will be imported. The
+	default value is '[a-zA-Z0-9_\-.]+$'.
+
+git-p4.useClientSpec::
+	Specify that the p4 client spec should be used to identify p4
+	depot paths of interest.  This is equivalent to specifying the
+	option `--use-client-spec`.  See the "CLIENT SPEC" section above.
+	This variable is a boolean, not the name of a p4 client.
+
+git-p4.pathEncoding::
+	Perforce keeps the encoding of a path as given by the originating OS.
+	Git expects paths encoded as UTF-8. Use this config to tell git-p4
+	what encoding Perforce had used for the paths. This encoding is used
+	to transcode the paths to UTF-8. As an example, Perforce on Windows
+	often uses "cp1252" to encode path names. If this option is passed
+	into a p4 clone request, it is persisted in the resulting new git
+	repo.
+
+git-p4.metadataDecodingStrategy::
+	Perforce keeps the encoding of a changelist descriptions and user
+	full names as stored by the client on a given OS. The p4v client
+	uses the OS-local encoding, and so different users can end up storing
+	different changelist descriptions or user full names in different
+	encodings, in the same depot.
+	Git tolerates inconsistent/incorrect encodings in commit messages
+	and author names, but expects them to be specified in utf-8.
+	git-p4 can use three different decoding strategies in handling the
+	encoding uncertainty in Perforce: 'passthrough' simply passes the
+	original bytes through from Perforce to git, creating usable but
+	incorrectly-encoded data when the Perforce data is encoded as
+	anything other than utf-8. 'strict' expects the Perforce data to be
+	encoded as utf-8, and fails to import when this is not true.
+	'fallback' attempts to interpret the data as utf-8, and otherwise
+	falls back to using a secondary encoding - by default the common
+	windows encoding 'cp-1252' - with upper-range bytes escaped if
+	decoding with the fallback encoding also fails.
+	Under python2 the default strategy is 'passthrough' for historical
+	reasons, and under python3 the default is 'fallback'.
+	When 'strict' is selected and decoding fails, the error message will
+	propose changing this config parameter as a workaround. If this
+	option is passed into a p4 clone request, it is persisted into the
+	resulting new git repo.
+
+git-p4.metadataFallbackEncoding::
+	Specify the fallback encoding to use when decoding Perforce author
+	names and changelists descriptions using the 'fallback' strategy
+	(see git-p4.metadataDecodingStrategy). The fallback encoding will
+	only be used when decoding as utf-8 fails. This option defaults to
+	cp1252, a common windows encoding. If this option is passed into a
+	p4 clone request, it is persisted into the resulting new git repo.
+
+git-p4.largeFileSystem::
+	Specify the system that is used for large (binary) files. Please note
+	that large file systems do not support the 'git p4 submit' command.
+	Only Git LFS is implemented right now (see https://git-lfs.github.com/
+	for more information). Download and install the Git LFS command line
+	extension to use this option and configure it like this:
++
+-------------
+git config       git-p4.largeFileSystem GitLFS
+-------------
+
+git-p4.largeFileExtensions::
+	All files matching a file extension in the list will be processed
+	by the large file system. Do not prefix the extensions with '.'.
+
+git-p4.largeFileThreshold::
+	All files with an uncompressed size exceeding the threshold will be
+	processed by the large file system. By default the threshold is
+	defined in bytes. Add the suffix k, m, or g to change the unit.
+
+git-p4.largeFileCompressedThreshold::
+	All files with a compressed size exceeding the threshold will be
+	processed by the large file system. This option might slow down
+	your clone/sync process. By default the threshold is defined in
+	bytes. Add the suffix k, m, or g to change the unit.
+
+git-p4.largeFilePush::
+	Boolean variable which defines if large files are automatically
+	pushed to a server.
+
+git-p4.keepEmptyCommits::
+	A changelist that contains only excluded files will be imported
+	as an empty commit if this boolean option is set to true.
+
+git-p4.mapUser::
+	Map a P4 user to a name and email address in Git. Use a string
+	with the following format to create a mapping:
++
+-------------
+git config --add git-p4.mapUser "p4user = First Last <mail@xxxxxxxxxxx>"
+-------------
++
+A mapping will override any user information from P4. Mappings for
+multiple P4 user can be defined.
+
+Submit variables
+~~~~~~~~~~~~~~~~
+git-p4.detectRenames::
+	Detect renames.  See linkgit:git-diff[1].  This can be true,
+	false, or a score as expected by 'git diff -M'.
+
+git-p4.detectCopies::
+	Detect copies.  See linkgit:git-diff[1].  This can be true,
+	false, or a score as expected by 'git diff -C'.
+
+git-p4.detectCopiesHarder::
+	Detect copies harder.  See linkgit:git-diff[1].  A boolean.
+
+git-p4.preserveUser::
+	On submit, re-author changes to reflect the Git author,
+	regardless of who invokes 'git p4 submit'.
+
+git-p4.allowMissingP4Users::
+	When 'preserveUser' is true, 'git p4' normally dies if it
+	cannot find an author in the p4 user map.  This setting
+	submits the change regardless.
+
+git-p4.skipSubmitEdit::
+	The submit process invokes the editor before each p4 change
+	is submitted.  If this setting is true, though, the editing
+	step is skipped.
+
+git-p4.skipSubmitEditCheck::
+	After editing the p4 change message, 'git p4' makes sure that
+	the description really was changed by looking at the file
+	modification time.  This option disables that test.
+
+git-p4.allowSubmit::
+	By default, any branch can be used as the source for a 'git p4
+	submit' operation.  This configuration variable, if set, permits only
+	the named branches to be used as submit sources.  Branch names
+	must be the short names (no "refs/heads/"), and should be
+	separated by commas (","), with no spaces.
+
+git-p4.skipUserNameCheck::
+	If the user running 'git p4 submit' does not exist in the p4
+	user map, 'git p4' exits.  This option can be used to force
+	submission regardless.
+
+git-p4.attemptRCSCleanup::
+	If enabled, 'git p4 submit' will attempt to cleanup RCS keywords
+	($Header$, etc). These would otherwise cause merge conflicts and prevent
+	the submit going ahead. This option should be considered experimental at
+	present.
+
+git-p4.exportLabels::
+	Export Git tags to p4 labels, as per --export-labels.
+
+git-p4.labelExportRegexp::
+	Only p4 labels matching this regular expression will be exported. The
+	default value is '[a-zA-Z0-9_\-.]+$'.
+
+git-p4.conflict::
+	Specify submit behavior when a conflict with p4 is found, as per
+	--conflict.  The default behavior is 'ask'.
+
+git-p4.disableRebase::
+    Do not rebase the tree against p4/master following a submit.
+
+git-p4.disableP4Sync::
+    Do not sync p4/master with Perforce following a submit. Implies git-p4.disableRebase.
+
+IMPLEMENTATION DETAILS
+----------------------
+* Changesets from p4 are imported using Git fast-import.
+* Cloning or syncing does not require a p4 client; file contents are
+  collected using 'p4 print'.
+* Submitting requires a p4 client, which is not in the same location
+  as the Git repository.  Patches are applied, one at a time, to
+  this p4 client and submitted from there.
+* Each commit imported by 'git p4' has a line at the end of the log
+  message indicating the p4 depot location and change number.  This
+  line is used by later 'git p4 sync' operations to know which p4
+  changes are new.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pack-objects.adoc b/Documentation/git-pack-objects.adoc
new file mode 100644
index 0000000000..e32404c6aa
--- /dev/null
+++ b/Documentation/git-pack-objects.adoc
@@ -0,0 +1,460 @@
+git-pack-objects(1)
+===================
+
+NAME
+----
+git-pack-objects - Create a packed archive of objects
+
+
+SYNOPSIS
+--------
+[verse]
+'git pack-objects' [-q | --progress | --all-progress] [--all-progress-implied]
+	[--no-reuse-delta] [--delta-base-offset] [--non-empty]
+	[--local] [--incremental] [--window=<n>] [--depth=<n>]
+	[--revs [--unpacked | --all]] [--keep-pack=<pack-name>]
+	[--cruft] [--cruft-expiration=<time>]
+	[--stdout [--filter=<filter-spec>] | <base-name>]
+	[--shallow] [--keep-true-parents] [--[no-]sparse] < <object-list>
+
+
+DESCRIPTION
+-----------
+Reads list of objects from the standard input, and writes either one or
+more packed archives with the specified base-name to disk, or a packed
+archive to the standard output.
+
+A packed archive is an efficient way to transfer a set of objects
+between two repositories as well as an access efficient archival
+format.  In a packed archive, an object is either stored as a
+compressed whole or as a difference from some other object.
+The latter is often called a delta.
+
+The packed archive format (.pack) is designed to be self-contained
+so that it can be unpacked without any further information. Therefore,
+each object that a delta depends upon must be present within the pack.
+
+A pack index file (.idx) is generated for fast, random access to the
+objects in the pack. Placing both the index file (.idx) and the packed
+archive (.pack) in the pack/ subdirectory of $GIT_OBJECT_DIRECTORY (or
+any of the directories on $GIT_ALTERNATE_OBJECT_DIRECTORIES)
+enables Git to read from the pack archive.
+
+The 'git unpack-objects' command can read the packed archive and
+expand the objects contained in the pack into "one-file
+one-object" format; this is typically done by the smart-pull
+commands when a pack is created on-the-fly for efficient network
+transport by their peers.
+
+
+OPTIONS
+-------
+base-name::
+	Write into pairs of files (.pack and .idx), using
+	<base-name> to determine the name of the created file.
+	When this option is used, the two files in a pair are written in
+	<base-name>-<SHA-1>.{pack,idx} files.  <SHA-1> is a hash
+	based on the pack content and is written to the standard
+	output of the command.
+
+--stdout::
+	Write the pack contents (what would have been written to
+	.pack file) out to the standard output.
+
+--revs::
+	Read the revision arguments from the standard input, instead of
+	individual object names.  The revision arguments are processed
+	the same way as 'git rev-list' with the `--objects` flag
+	uses its `commit` arguments to build the list of objects it
+	outputs.  The objects on the resulting list are packed.
+	Besides revisions, `--not` or `--shallow <SHA-1>` lines are
+	also accepted.
+
+--unpacked::
+	This implies `--revs`.  When processing the list of
+	revision arguments read from the standard input, limit
+	the objects packed to those that are not already packed.
+
+--all::
+	This implies `--revs`.  In addition to the list of
+	revision arguments read from the standard input, pretend
+	as if all refs under `refs/` are specified to be
+	included.
+
+--include-tag::
+	Include unasked-for annotated tags if the object they
+	reference was included in the resulting packfile.  This
+	can be useful to send new tags to native Git clients.
+
+--stdin-packs::
+	Read the basenames of packfiles (e.g., `pack-1234abcd.pack`)
+	from the standard input, instead of object names or revision
+	arguments. The resulting pack contains all objects listed in the
+	included packs (those not beginning with `^`), excluding any
+	objects listed in the excluded packs (beginning with `^`).
++
+Incompatible with `--revs`, or options that imply `--revs` (such as
+`--all`), with the exception of `--unpacked`, which is compatible.
+
+--cruft::
+	Packs unreachable objects into a separate "cruft" pack, denoted
+	by the existence of a `.mtimes` file. Typically used by `git
+	repack --cruft`. Callers provide a list of pack names and
+	indicate which packs will remain in the repository, along with
+	which packs will be deleted (indicated by the `-` prefix). The
+	contents of the cruft pack are all objects not contained in the
+	surviving packs which have not exceeded the grace period (see
+	`--cruft-expiration` below), or which have exceeded the grace
+	period, but are reachable from an other object which hasn't.
++
+When the input lists a pack containing all reachable objects (and lists
+all other packs as pending deletion), the corresponding cruft pack will
+contain all unreachable objects (with mtime newer than the
+`--cruft-expiration`) along with any unreachable objects whose mtime is
+older than the `--cruft-expiration`, but are reachable from an
+unreachable object whose mtime is newer than the `--cruft-expiration`).
++
+Incompatible with `--unpack-unreachable`, `--keep-unreachable`,
+`--pack-loose-unreachable`, `--stdin-packs`, as well as any other
+options which imply `--revs`.
+
+--cruft-expiration=<approxidate>::
+	If specified, objects are eliminated from the cruft pack if they
+	have an mtime older than `<approxidate>`. If unspecified (and
+	given `--cruft`), then no objects are eliminated.
+
+--window=<n>::
+--depth=<n>::
+	These two options affect how the objects contained in
+	the pack are stored using delta compression.  The
+	objects are first internally sorted by type, size and
+	optionally names and compared against the other objects
+	within --window to see if using delta compression saves
+	space.  --depth limits the maximum delta depth; making
+	it too deep affects the performance on the unpacker
+	side, because delta data needs to be applied that many
+	times to get to the necessary object.
++
+The default value for --window is 10 and --depth is 50. The maximum
+depth is 4095.
+
+--window-memory=<n>::
+	This option provides an additional limit on top of `--window`;
+	the window size will dynamically scale down so as to not take
+	up more than '<n>' bytes in memory.  This is useful in
+	repositories with a mix of large and small objects to not run
+	out of memory with a large window, but still be able to take
+	advantage of the large window for the smaller objects.  The
+	size can be suffixed with "k", "m", or "g".
+	`--window-memory=0` makes memory usage unlimited.  The default
+	is taken from the `pack.windowMemory` configuration variable.
+
+--max-pack-size=<n>::
+	In unusual scenarios, you may not be able to create files
+	larger than a certain size on your filesystem, and this option
+	can be used to tell the command to split the output packfile
+	into multiple independent packfiles, each not larger than the
+	given size. The size can be suffixed with
+	"k", "m", or "g". The minimum size allowed is limited to 1 MiB.
+	The default is unlimited, unless the config variable
+	`pack.packSizeLimit` is set. Note that this option may result in
+	a larger and slower repository; see the discussion in
+	`pack.packSizeLimit`.
+
+--honor-pack-keep::
+	This flag causes an object already in a local pack that
+	has a .keep file to be ignored, even if it would have
+	otherwise been packed.
+
+--keep-pack=<pack-name>::
+	This flag causes an object already in the given pack to be
+	ignored, even if it would have otherwise been
+	packed. `<pack-name>` is the pack file name without
+	leading directory (e.g. `pack-123.pack`). The option could be
+	specified multiple times to keep multiple packs.
+
+--incremental::
+	This flag causes an object already in a pack to be ignored
+	even if it would have otherwise been packed.
+
+--local::
+	This flag causes an object that is borrowed from an alternate
+	object store to be ignored even if it would have otherwise been
+	packed.
+
+--non-empty::
+        Only create a packed archive if it would contain at
+        least one object.
+
+--progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless -q
+	is specified. This flag forces progress status even if
+	the standard error stream is not directed to a terminal.
+
+--all-progress::
+	When --stdout is specified then progress report is
+	displayed during the object count and compression phases
+	but inhibited during the write-out phase. The reason is
+	that in some cases the output stream is directly linked
+	to another command which may wish to display progress
+	status of its own as it processes incoming pack data.
+	This flag is like --progress except that it forces progress
+	report for the write-out phase as well even if --stdout is
+	used.
+
+--all-progress-implied::
+	This is used to imply --all-progress whenever progress display
+	is activated.  Unlike --all-progress this flag doesn't actually
+	force any progress display by itself.
+
+-q::
+	This flag makes the command not to report its progress
+	on the standard error stream.
+
+--no-reuse-delta::
+	When creating a packed archive in a repository that
+	has existing packs, the command reuses existing deltas.
+	This sometimes results in a slightly suboptimal pack.
+	This flag tells the command not to reuse existing deltas
+	but compute them from scratch.
+
+--no-reuse-object::
+	This flag tells the command not to reuse existing object data at all,
+	including non deltified object, forcing recompression of everything.
+	This implies --no-reuse-delta. Useful only in the obscure case where
+	wholesale enforcement of a different compression level on the
+	packed data is desired.
+
+--compression=<n>::
+	Specifies compression level for newly-compressed data in the
+	generated pack.  If not specified,  pack compression level is
+	determined first by pack.compression,  then by core.compression,
+	and defaults to -1,  the zlib default,  if neither is set.
+	Add --no-reuse-object if you want to force a uniform compression
+	level on all data no matter the source.
+
+--[no-]sparse::
+	Toggle the "sparse" algorithm to determine which objects to include in
+	the pack, when combined with the "--revs" option. This algorithm
+	only walks trees that appear in paths that introduce new objects.
+	This can have significant performance benefits when computing
+	a pack to send a small change. However, it is possible that extra
+	objects are added to the pack-file if the included commits contain
+	certain types of direct renames. If this option is not included,
+	it defaults to the value of `pack.useSparse`, which is true unless
+	otherwise specified.
+
+--thin::
+	Create a "thin" pack by omitting the common objects between a
+	sender and a receiver in order to reduce network transfer. This
+	option only makes sense in conjunction with --stdout.
++
+Note: A thin pack violates the packed archive format by omitting
+required objects and is thus unusable by Git without making it
+self-contained. Use `git index-pack --fix-thin`
+(see linkgit:git-index-pack[1]) to restore the self-contained property.
+
+--shallow::
+	Optimize a pack that will be provided to a client with a shallow
+	repository.  This option, combined with --thin, can result in a
+	smaller pack at the cost of speed.
+
+--delta-base-offset::
+	A packed archive can express the base object of a delta as
+	either a 20-byte object name or as an offset in the
+	stream, but ancient versions of Git don't understand the
+	latter.  By default, 'git pack-objects' only uses the
+	former format for better compatibility.  This option
+	allows the command to use the latter format for
+	compactness.  Depending on the average delta chain
+	length, this option typically shrinks the resulting
+	packfile by 3-5 per-cent.
++
+Note: Porcelain commands such as `git gc` (see linkgit:git-gc[1]),
+`git repack` (see linkgit:git-repack[1]) pass this option by default
+in modern Git when they put objects in your repository into pack files.
+So does `git bundle` (see linkgit:git-bundle[1]) when it creates a bundle.
+
+--threads=<n>::
+	Specifies the number of threads to spawn when searching for best
+	delta matches.  This requires that pack-objects be compiled with
+	pthreads otherwise this option is ignored with a warning.
+	This is meant to reduce packing time on multiprocessor machines.
+	The required amount of memory for the delta search window is
+	however multiplied by the number of threads.
+	Specifying 0 will cause Git to auto-detect the number of CPU's
+	and set the number of threads accordingly.
+
+--index-version=<version>[,<offset>]::
+	This is intended to be used by the test suite only. It allows
+	to force the version for the generated pack index, and to force
+	64-bit index entries on objects located above the given offset.
+
+--keep-true-parents::
+	With this option, parents that are hidden by grafts are packed
+	nevertheless.
+
+--filter=<filter-spec>::
+	Omits certain objects (usually blobs) from the resulting
+	packfile.  See linkgit:git-rev-list[1] for valid
+	`<filter-spec>` forms.
+
+--no-filter::
+	Turns off any previous `--filter=` argument.
+
+--missing=<missing-action>::
+	A debug option to help with future "partial clone" development.
+	This option specifies how missing objects are handled.
++
+The form '--missing=error' requests that pack-objects stop with an error if
+a missing object is encountered.  If the repository is a partial clone, an
+attempt to fetch missing objects will be made before declaring them missing.
+This is the default action.
++
+The form '--missing=allow-any' will allow object traversal to continue
+if a missing object is encountered.  No fetch of a missing object will occur.
+Missing objects will silently be omitted from the results.
++
+The form '--missing=allow-promisor' is like 'allow-any', but will only
+allow object traversal to continue for EXPECTED promisor missing objects.
+No fetch of a missing object will occur.  An unexpected missing object will
+raise an error.
+
+--exclude-promisor-objects::
+	Omit objects that are known to be in the promisor remote.  (This
+	option has the purpose of operating only on locally created objects,
+	so that when we repack, we still maintain a distinction between
+	locally created objects [without .promisor] and objects from the
+	promisor remote [with .promisor].)  This is used with partial clone.
+
+--keep-unreachable::
+	Objects unreachable from the refs in packs named with
+	--unpacked= option are added to the resulting pack, in
+	addition to the reachable objects that are not in packs marked
+	with *.keep files. This implies `--revs`.
+
+--pack-loose-unreachable::
+	Pack unreachable loose objects (and their loose counterparts
+	removed). This implies `--revs`.
+
+--unpack-unreachable::
+	Keep unreachable objects in loose form. This implies `--revs`.
+
+--delta-islands::
+	Restrict delta matches based on "islands". See DELTA ISLANDS
+	below.
+
+
+DELTA ISLANDS
+-------------
+
+When possible, `pack-objects` tries to reuse existing on-disk deltas to
+avoid having to search for new ones on the fly. This is an important
+optimization for serving fetches, because it means the server can avoid
+inflating most objects at all and just send the bytes directly from
+disk. This optimization can't work when an object is stored as a delta
+against a base which the receiver does not have (and which we are not
+already sending). In that case the server "breaks" the delta and has to
+find a new one, which has a high CPU cost. Therefore it's important for
+performance that the set of objects in on-disk delta relationships match
+what a client would fetch.
+
+In a normal repository, this tends to work automatically. The objects
+are mostly reachable from the branches and tags, and that's what clients
+fetch. Any deltas we find on the server are likely to be between objects
+the client has or will have.
+
+But in some repository setups, you may have several related but separate
+groups of ref tips, with clients tending to fetch those groups
+independently. For example, imagine that you are hosting several "forks"
+of a repository in a single shared object store, and letting clients
+view them as separate repositories through `GIT_NAMESPACE` or separate
+repos using the alternates mechanism. A naive repack may find that the
+optimal delta for an object is against a base that is only found in
+another fork. But when a client fetches, they will not have the base
+object, and we'll have to find a new delta on the fly.
+
+A similar situation may exist if you have many refs outside of
+`refs/heads/` and `refs/tags/` that point to related objects (e.g.,
+`refs/pull` or `refs/changes` used by some hosting providers). By
+default, clients fetch only heads and tags, and deltas against objects
+found only in those other groups cannot be sent as-is.
+
+Delta islands solve this problem by allowing you to group your refs into
+distinct "islands". Pack-objects computes which objects are reachable
+from which islands, and refuses to make a delta from an object `A`
+against a base which is not present in all of `A`'s islands. This
+results in slightly larger packs (because we miss some delta
+opportunities), but guarantees that a fetch of one island will not have
+to recompute deltas on the fly due to crossing island boundaries.
+
+When repacking with delta islands the delta window tends to get
+clogged with candidates that are forbidden by the config. Repacking
+with a big --window helps (and doesn't take as long as it otherwise
+might because we can reject some object pairs based on islands before
+doing any computation on the content).
+
+Islands are configured via the `pack.island` option, which can be
+specified multiple times. Each value is a left-anchored regular
+expressions matching refnames. For example:
+
+-------------------------------------------
+[pack]
+island = refs/heads/
+island = refs/tags/
+-------------------------------------------
+
+puts heads and tags into an island (whose name is the empty string; see
+below for more on naming). Any refs which do not match those regular
+expressions (e.g., `refs/pull/123`) is not in any island. Any object
+which is reachable only from `refs/pull/` (but not heads or tags) is
+therefore not a candidate to be used as a base for `refs/heads/`.
+
+Refs are grouped into islands based on their "names", and two regexes
+that produce the same name are considered to be in the same
+island. The names are computed from the regexes by concatenating any
+capture groups from the regex, with a '-' dash in between. (And if
+there are no capture groups, then the name is the empty string, as in
+the above example.) This allows you to create arbitrary numbers of
+islands. Only up to 14 such capture groups are supported though.
+
+For example, imagine you store the refs for each fork in
+`refs/virtual/ID`, where `ID` is a numeric identifier. You might then
+configure:
+
+-------------------------------------------
+[pack]
+island = refs/virtual/([0-9]+)/heads/
+island = refs/virtual/([0-9]+)/tags/
+island = refs/virtual/([0-9]+)/(pull)/
+-------------------------------------------
+
+That puts the heads and tags for each fork in their own island (named
+"1234" or similar), and the pull refs for each go into their own
+"1234-pull".
+
+Note that we pick a single island for each regex to go into, using "last
+one wins" ordering (which allows repo-specific config to take precedence
+over user-wide config, and so forth).
+
+
+CONFIGURATION
+-------------
+
+Various configuration variables affect packing, see
+linkgit:git-config[1] (search for "pack" and "delta").
+
+Notably, delta compression is not used on objects larger than the
+`core.bigFileThreshold` configuration variable and on files with the
+attribute `delta` set to false.
+
+SEE ALSO
+--------
+linkgit:git-rev-list[1]
+linkgit:git-repack[1]
+linkgit:git-prune-packed[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pack-redundant.adoc b/Documentation/git-pack-redundant.adoc
new file mode 100644
index 0000000000..13c3eb5ec9
--- /dev/null
+++ b/Documentation/git-pack-redundant.adoc
@@ -0,0 +1,64 @@
+git-pack-redundant(1)
+=====================
+
+NAME
+----
+git-pack-redundant - Find redundant pack files
+
+
+SYNOPSIS
+--------
+[verse]
+'git pack-redundant' [--verbose] [--alt-odb] (--all | <pack-filename>...)
+
+WARNING
+-------
+`git pack-redundant` has been deprecated and is scheduled for removal in
+a future version of Git. Because it can only remove entire duplicate
+packs and not individual duplicate objects, it is generally not a useful
+tool for reducing repository size. You are better off using `git gc` to
+do so, which will put objects into a new pack, removing duplicates.
+
+Running `pack-redundant` without the `--i-still-use-this` flag will fail
+in this release. If you believe you have a use case for which
+`pack-redundant` is better suited and oppose this removal, please
+contact the Git mailing list at git@xxxxxxxxxxxxxxx. More information
+about the list is available at https://git-scm.com/community.
+
+DESCRIPTION
+-----------
+This program computes which packs in your repository
+are redundant. The output is suitable for piping to
+`xargs rm` if you are in the root of the repository.
+
+'git pack-redundant' accepts a list of objects on standard input. Any objects
+given will be ignored when checking which packs are required. This makes the
+following command useful when wanting to remove packs which contain unreachable
+objects.
+
+git fsck --full --unreachable | cut -d ' ' -f3 | \
+git pack-redundant --all | xargs rm
+
+OPTIONS
+-------
+
+
+--all::
+	Processes all packs. Any filenames on the command line are ignored.
+
+--alt-odb::
+	Don't require objects present in packs from alternate object
+	database (odb) directories to be present in local packs.
+
+--verbose::
+	Outputs some statistics to stderr. Has a small performance penalty.
+
+SEE ALSO
+--------
+linkgit:git-pack-objects[1]
+linkgit:git-repack[1]
+linkgit:git-prune-packed[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pack-refs.adoc b/Documentation/git-pack-refs.adoc
new file mode 100644
index 0000000000..2dcabaf74c
--- /dev/null
+++ b/Documentation/git-pack-refs.adoc
@@ -0,0 +1,109 @@
+git-pack-refs(1)
+================
+
+NAME
+----
+git-pack-refs - Pack heads and tags for efficient repository access
+
+SYNOPSIS
+--------
+[verse]
+'git pack-refs' [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]
+
+DESCRIPTION
+-----------
+
+Traditionally, tips of branches and tags (collectively known as
+'refs') were stored one file per ref in a (sub)directory
+under `$GIT_DIR/refs`
+directory.  While many branch tips tend to be updated often,
+most tags and some branch tips are never updated.  When a
+repository has hundreds or thousands of tags, this
+one-file-per-ref format both wastes storage and hurts
+performance.
+
+This command is used to solve the storage and performance
+problem by storing the refs in a single file,
+`$GIT_DIR/packed-refs`.  When a ref is missing from the
+traditional `$GIT_DIR/refs` directory hierarchy, it is looked
+up in this
+file and used if found.
+
+Subsequent updates to branches always create new files under
+`$GIT_DIR/refs` directory hierarchy.
+
+A recommended practice to deal with a repository with too many
+refs is to pack its refs with `--all` once, and
+occasionally run `git pack-refs`.  Tags are by
+definition stationary and are not expected to change.  Branch
+heads will be packed with the initial `pack-refs --all`, but
+only the currently active branch heads will become unpacked,
+and the next `pack-refs` (without `--all`) will leave them
+unpacked.
+
+
+OPTIONS
+-------
+
+--all::
+
+The command by default packs all tags and refs that are already
+packed, and leaves other refs
+alone.  This is because branches are expected to be actively
+developed and packing their tips does not help performance.
+This option causes all refs to be packed as well, with the exception
+of hidden refs, broken refs, and symbolic refs. Useful for a repository
+with many branches of historical interests.
+
+--no-prune::
+
+The command usually removes loose refs under `$GIT_DIR/refs`
+hierarchy after packing them.  This option tells it not to.
+
+--auto::
+
+Pack refs as needed depending on the current state of the ref database. The
+behavior depends on the ref format used by the repository and may change in the
+future.
++
+	- "files": No special handling for `--auto` has been implemented.
++
+	- "reftable": Tables are compacted such that they form a geometric
+	  sequence. For two tables N and N+1, where N+1 is newer, this
+	  maintains the property that N is at least twice as big as N+1. Only
+	  tables that violate this property are compacted.
+
+--include <pattern>::
+
+Pack refs based on a `glob(7)` pattern. Repetitions of this option
+accumulate inclusion patterns. If a ref is both included in `--include` and
+`--exclude`, `--exclude` takes precedence. Using `--include` will preclude all
+tags from being included by default. Symbolic refs and broken refs will never
+be packed. When used with `--all`, it will be a noop. Use `--no-include` to clear
+and reset the list of patterns.
+
+--exclude <pattern>::
+
+Do not pack refs matching the given `glob(7)` pattern. Repetitions of this option
+accumulate exclusion patterns. Use `--no-exclude` to clear and reset the list of
+patterns. If a ref is already packed, including it with `--exclude` will not
+unpack it.
+
+When used with `--all`, pack only loose refs which do not match any of
+the provided `--exclude` patterns.
+
+When used with `--include`, refs provided to `--include`, minus refs that are
+provided to `--exclude` will be packed.
+
+
+BUGS
+----
+
+Older documentation written before the packed-refs mechanism was
+introduced may still say things like ".git/refs/heads/<branch> file
+exists" when it means "branch <branch> exists".
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-patch-id.adoc b/Documentation/git-patch-id.adoc
new file mode 100644
index 0000000000..1d15fa45d5
--- /dev/null
+++ b/Documentation/git-patch-id.adoc
@@ -0,0 +1,69 @@
+git-patch-id(1)
+===============
+
+NAME
+----
+git-patch-id - Compute unique ID for a patch
+
+SYNOPSIS
+--------
+[verse]
+'git patch-id' [--stable | --unstable | --verbatim]
+
+DESCRIPTION
+-----------
+Read a patch from the standard input and compute the patch ID for it.
+
+A "patch ID" is nothing but a sum of SHA-1 of the file diffs associated with a
+patch, with line numbers ignored.  As such, it's "reasonably stable", but at
+the same time also reasonably unique, i.e., two patches that have the same
+"patch ID" are almost guaranteed to be the same thing.
+
+The main usecase for this command is to look for likely duplicate commits.
+
+When dealing with 'git diff-tree' output, it takes advantage of
+the fact that the patch is prefixed with the object name of the
+commit, and outputs two 40-byte hexadecimal strings.  The first
+string is the patch ID, and the second string is the commit ID.
+This can be used to make a mapping from patch ID to commit ID.
+
+OPTIONS
+-------
+
+--verbatim::
+	Calculate the patch-id of the input as it is given, do not strip
+	any whitespace.
+
+	This is the default if patchid.verbatim is true.
+
+--stable::
+	Use a "stable" sum of hashes as the patch ID. With this option:
+	 - Reordering file diffs that make up a patch does not affect the ID.
+	   In particular, two patches produced by comparing the same two trees
+	   with two different settings for "-O<orderfile>" result in the same
+	   patch ID signature, thereby allowing the computed result to be used
+	   as a key to index some meta-information about the change between
+	   the two trees;
+
+	 - Result is different from the value produced by git 1.9 and older
+	   or produced when an "unstable" hash (see --unstable below) is
+	   configured - even when used on a diff output taken without any use
+	   of "-O<orderfile>", thereby making existing databases storing such
+	   "unstable" or historical patch-ids unusable.
+
+	 - All whitespace within the patch is ignored and does not affect the id.
+
+	This is the default if patchid.stable is set to true.
+
+--unstable::
+	Use an "unstable" hash as the patch ID. With this option,
+	the result produced is compatible with the patch-id value produced
+	by git 1.9 and older and whitespace is ignored.  Users with pre-existing
+	databases storing patch-ids produced by git 1.9 and older (who do not deal
+	with reordered patches) may want to use this option.
+
+	This is the default.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-prune-packed.adoc b/Documentation/git-prune-packed.adoc
new file mode 100644
index 0000000000..db742dcfee
--- /dev/null
+++ b/Documentation/git-prune-packed.adoc
@@ -0,0 +1,47 @@
+git-prune-packed(1)
+===================
+
+NAME
+----
+git-prune-packed - Remove extra objects that are already in pack files
+
+
+SYNOPSIS
+--------
+[verse]
+'git prune-packed' [-n | --dry-run] [-q | --quiet]
+
+
+DESCRIPTION
+-----------
+This program searches the `$GIT_OBJECT_DIRECTORY` for all objects that currently
+exist in a pack file as well as in the independent object directories.
+
+All such extra objects are removed.
+
+A pack is a collection of objects, individually compressed, with delta
+compression applied, stored in a single file, with an associated index file.
+
+Packs are used to reduce the load on mirror systems, backup engines,
+disk storage, etc.
+
+
+OPTIONS
+-------
+-n::
+--dry-run::
+        Don't actually remove any objects, only show those that would have been
+        removed.
+
+-q::
+--quiet::
+	Squelch the progress indicator.
+
+SEE ALSO
+--------
+linkgit:git-pack-objects[1]
+linkgit:git-repack[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-prune.adoc b/Documentation/git-prune.adoc
new file mode 100644
index 0000000000..9a45571b90
--- /dev/null
+++ b/Documentation/git-prune.adoc
@@ -0,0 +1,89 @@
+git-prune(1)
+============
+
+NAME
+----
+git-prune - Prune all unreachable objects from the object database
+
+
+SYNOPSIS
+--------
+[verse]
+'git prune' [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]
+
+DESCRIPTION
+-----------
+
+NOTE: In most cases, users should run 'git gc', which calls
+'git prune'. See the section "NOTES", below.
+
+This runs 'git fsck --unreachable' using all the refs
+available in `refs/`, optionally with an additional set of
+objects specified on the command line, and prunes all unpacked
+objects unreachable from any of these head objects from the object database.
+In addition, it
+prunes the unpacked objects that are also found in packs by
+running 'git prune-packed'.
+It also removes entries from .git/shallow that are not reachable by
+any ref.
+
+Note that unreachable, packed objects will remain.  If this is
+not desired, see linkgit:git-repack[1].
+
+OPTIONS
+-------
+
+-n::
+--dry-run::
+	Do not remove anything; just report what it would
+	remove.
+
+-v::
+--verbose::
+	Report all removed objects.
+
+--progress::
+	Show progress.
+
+--expire <time>::
+	Only expire loose objects older than <time>.
+
+\--::
+	Do not interpret any more arguments as options.
+
+<head>...::
+	In addition to objects
+	reachable from any of our references, keep objects
+	reachable from listed <head>s.
+
+EXAMPLES
+--------
+
+To prune objects not used by your repository or another that
+borrows from your repository via its
+`.git/objects/info/alternates`:
+
+------------
+$ git prune $(cd ../another && git rev-parse --all)
+------------
+
+NOTES
+-----
+
+In most cases, users will not need to call 'git prune' directly, but
+should instead call 'git gc', which handles pruning along with
+many other housekeeping tasks.
+
+For a description of which objects are considered for pruning, see
+'git fsck''s --unreachable option.
+
+SEE ALSO
+--------
+
+linkgit:git-fsck[1],
+linkgit:git-gc[1],
+linkgit:git-reflog[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-pull.adoc b/Documentation/git-pull.adoc
new file mode 100644
index 0000000000..3f4ecc4730
--- /dev/null
+++ b/Documentation/git-pull.adoc
@@ -0,0 +1,254 @@
+git-pull(1)
+===========
+
+NAME
+----
+git-pull - Fetch from and integrate with another repository or a local branch
+
+
+SYNOPSIS
+--------
+[verse]
+'git pull' [<options>] [<repository> [<refspec>...]]
+
+
+DESCRIPTION
+-----------
+
+Incorporates changes from a remote repository into the current branch.
+If the current branch is behind the remote, then by default it will
+fast-forward the current branch to match the remote.  If the current
+branch and the remote have diverged, the user needs to specify how to
+reconcile the divergent branches with `--rebase` or `--no-rebase` (or
+the corresponding configuration option in `pull.rebase`).
+
+More precisely, `git pull` runs `git fetch` with the given parameters
+and then depending on configuration options or command line flags,
+will call either `git rebase` or `git merge` to reconcile diverging
+branches.
+
+<repository> should be the name of a remote repository as
+passed to linkgit:git-fetch[1].  <refspec> can name an
+arbitrary remote ref (for example, the name of a tag) or even
+a collection of refs with corresponding remote-tracking branches
+(e.g., refs/heads/{asterisk}:refs/remotes/origin/{asterisk}),
+but usually it is the name of a branch in the remote repository.
+
+Default values for <repository> and <branch> are read from the
+"remote" and "merge" configuration for the current branch
+as set by linkgit:git-branch[1] `--track`.
+
+Assume the following history exists and the current branch is
+"`master`":
+
+------------
+	  A---B---C master on origin
+	 /
+    D---E---F---G master
+	^
+	origin/master in your repository
+------------
+
+Then "`git pull`" will fetch and replay the changes from the remote
+`master` branch since it diverged from the local `master` (i.e., `E`)
+until its current commit (`C`) on top of `master` and record the
+result in a new commit along with the names of the two parent commits
+and a log message from the user describing the changes.
+
+------------
+	  A---B---C origin/master
+	 /         \
+    D---E---F---G---H master
+------------
+
+See linkgit:git-merge[1] for details, including how conflicts
+are presented and handled.
+
+In Git 1.7.0 or later, to cancel a conflicting merge, use
+`git reset --merge`.  *Warning*: In older versions of Git, running 'git pull'
+with uncommitted changes is discouraged: while possible, it leaves you
+in a state that may be hard to back out of in the case of a conflict.
+
+If any of the remote changes overlap with local uncommitted changes,
+the merge will be automatically canceled and the work tree untouched.
+It is generally best to get any local changes in working order before
+pulling or stash them away with linkgit:git-stash[1].
+
+OPTIONS
+-------
+
+-q::
+--quiet::
+	This is passed to both underlying git-fetch to squelch reporting of
+	during transfer, and underlying git-merge to squelch output during
+	merging.
+
+-v::
+--verbose::
+	Pass --verbose to git-fetch and git-merge.
+
+--[no-]recurse-submodules[=(yes|on-demand|no)]::
+	This option controls if new commits of populated submodules should
+	be fetched, and if the working trees of active submodules should be
+	updated, too (see linkgit:git-fetch[1], linkgit:git-config[1] and
+	linkgit:gitmodules[5]).
++
+If the checkout is done via rebase, local submodule commits are rebased as well.
++
+If the update is done via merge, the submodule conflicts are resolved and checked out.
+
+Options related to merging
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:git-pull: 1
+
+include::merge-options.adoc[]
+
+-r::
+--rebase[=(false|true|merges|interactive)]::
+	When true, rebase the current branch on top of the upstream
+	branch after fetching. If there is a remote-tracking branch
+	corresponding to the upstream branch and the upstream branch
+	was rebased since last fetched, the rebase uses that information
+	to avoid rebasing non-local changes.
++
+When set to `merges`, rebase using `git rebase --rebase-merges` so that
+the local merge commits are included in the rebase (see
+linkgit:git-rebase[1] for details).
++
+When false, merge the upstream branch into the current branch.
++
+When `interactive`, enable the interactive mode of rebase.
++
+See `pull.rebase`, `branch.<name>.rebase` and `branch.autoSetupRebase` in
+linkgit:git-config[1] if you want to make `git pull` always use
+`--rebase` instead of merging.
++
+[NOTE]
+This is a potentially _dangerous_ mode of operation.
+It rewrites history, which does not bode well when you
+published that history already.  Do *not* use this option
+unless you have read linkgit:git-rebase[1] carefully.
+
+--no-rebase::
+	This is shorthand for --rebase=false.
+
+Options related to fetching
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+include::fetch-options.adoc[]
+
+include::pull-fetch-param.adoc[]
+
+include::urls-remotes.adoc[]
+
+include::merge-strategies.adoc[]
+
+DEFAULT BEHAVIOUR
+-----------------
+
+Often people use `git pull` without giving any parameter.
+Traditionally, this has been equivalent to saying `git pull
+origin`.  However, when configuration `branch.<name>.remote` is
+present while on branch `<name>`, that value is used instead of
+`origin`.
+
+In order to determine what URL to use to fetch from, the value
+of the configuration `remote.<origin>.url` is consulted
+and if there is not any such variable, the value on the `URL:` line
+in `$GIT_DIR/remotes/<origin>` is used.
+
+In order to determine what remote branches to fetch (and
+optionally store in the remote-tracking branches) when the command is
+run without any refspec parameters on the command line, values
+of the configuration variable `remote.<origin>.fetch` are
+consulted, and if there aren't any, `$GIT_DIR/remotes/<origin>`
+is consulted and its `Pull:` lines are used.
+In addition to the refspec formats described in the OPTIONS
+section, you can have a globbing refspec that looks like this:
+
+------------
+refs/heads/*:refs/remotes/origin/*
+------------
+
+A globbing refspec must have a non-empty RHS (i.e. must store
+what were fetched in remote-tracking branches), and its LHS and RHS
+must end with `/*`.  The above specifies that all remote
+branches are tracked using remote-tracking branches in
+`refs/remotes/origin/` hierarchy under the same name.
+
+The rule to determine which remote branch to merge after
+fetching is a bit involved, in order not to break backward
+compatibility.
+
+If explicit refspecs were given on the command
+line of `git pull`, they are all merged.
+
+When no refspec was given on the command line, then `git pull`
+uses the refspec from the configuration or
+`$GIT_DIR/remotes/<origin>`.  In such cases, the following
+rules apply:
+
+. If `branch.<name>.merge` configuration for the current
+  branch `<name>` exists, that is the name of the branch at the
+  remote site that is merged.
+
+. If the refspec is a globbing one, nothing is merged.
+
+. Otherwise the remote branch of the first refspec is merged.
+
+
+EXAMPLES
+--------
+
+* Update the remote-tracking branches for the repository
+  you cloned from, then merge one of them into your
+  current branch:
++
+------------------------------------------------
+$ git pull
+$ git pull origin
+------------------------------------------------
++
+Normally the branch merged in is the HEAD of the remote repository,
+but the choice is determined by the branch.<name>.remote and
+branch.<name>.merge options; see linkgit:git-config[1] for details.
+
+* Merge into the current branch the remote branch `next`:
++
+------------------------------------------------
+$ git pull origin next
+------------------------------------------------
++
+This leaves a copy of `next` temporarily in FETCH_HEAD, and
+updates the remote-tracking branch `origin/next`.
+The same can be done by invoking fetch and merge:
++
+------------------------------------------------
+$ git fetch origin
+$ git merge origin/next
+------------------------------------------------
+
+
+If you tried a pull which resulted in complex conflicts and
+would want to start over, you can recover with 'git reset'.
+
+
+include::transfer-data-leaks.adoc[]
+
+BUGS
+----
+Using --recurse-submodules can only fetch new commits in already checked
+out submodules right now. When e.g. upstream added a new submodule in the
+just fetched commits of the superproject the submodule itself cannot be
+fetched, making it impossible to check out that submodule later without
+having to do a fetch again. This is expected to be fixed in a future Git
+version.
+
+SEE ALSO
+--------
+linkgit:git-fetch[1], linkgit:git-merge[1], linkgit:git-config[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-push.adoc b/Documentation/git-push.adoc
new file mode 100644
index 0000000000..ab1e83c2c4
--- /dev/null
+++ b/Documentation/git-push.adoc
@@ -0,0 +1,709 @@
+git-push(1)
+===========
+
+NAME
+----
+git-push - Update remote refs along with associated objects
+
+
+SYNOPSIS
+--------
+[verse]
+'git push' [--all | --branches | --mirror | --tags] [--follow-tags] [--atomic] [-n | --dry-run] [--receive-pack=<git-receive-pack>]
+	   [--repo=<repository>] [-f | --force] [-d | --delete] [--prune] [-q | --quiet] [-v | --verbose]
+	   [-u | --set-upstream] [-o <string> | --push-option=<string>]
+	   [--[no-]signed|--signed=(true|false|if-asked)]
+	   [--force-with-lease[=<refname>[:<expect>]] [--force-if-includes]]
+	   [--no-verify] [<repository> [<refspec>...]]
+
+DESCRIPTION
+-----------
+
+Updates remote refs using local refs, while sending objects
+necessary to complete the given refs.
+
+You can make interesting things happen to a repository
+every time you push into it, by setting up 'hooks' there.  See
+documentation for linkgit:git-receive-pack[1].
+
+When the command line does not specify where to push with the
+`<repository>` argument, `branch.*.remote` configuration for the
+current branch is consulted to determine where to push.  If the
+configuration is missing, it defaults to 'origin'.
+
+When the command line does not specify what to push with `<refspec>...`
+arguments or `--all`, `--mirror`, `--tags` options, the command finds
+the default `<refspec>` by consulting `remote.*.push` configuration,
+and if it is not found, honors `push.default` configuration to decide
+what to push (See linkgit:git-config[1] for the meaning of `push.default`).
+
+When neither the command-line nor the configuration specifies what to
+push, the default behavior is used, which corresponds to the `simple`
+value for `push.default`: the current branch is pushed to the
+corresponding upstream branch, but as a safety measure, the push is
+aborted if the upstream branch does not have the same name as the
+local one.
+
+
+OPTIONS[[OPTIONS]]
+------------------
+<repository>::
+	The "remote" repository that is the destination of a push
+	operation.  This parameter can be either a URL
+	(see the section <<URLS,GIT URLS>> below) or the name
+	of a remote (see the section <<REMOTES,REMOTES>> below).
+
+<refspec>...::
+	Specify what destination ref to update with what source object.
+	The format of a <refspec> parameter is an optional plus
+	`+`, followed by the source object <src>, followed
+	by a colon `:`, followed by the destination ref <dst>.
++
+The <src> is often the name of the branch you would want to push, but
+it can be any arbitrary "SHA-1 expression", such as `master~4` or
+`HEAD` (see linkgit:gitrevisions[7]).
++
+The <dst> tells which ref on the remote side is updated with this
+push. Arbitrary expressions cannot be used here, an actual ref must
+be named.
+If `git push [<repository>]` without any `<refspec>` argument is set to
+update some ref at the destination with `<src>` with
+`remote.<repository>.push` configuration variable, `:<dst>` part can
+be omitted--such a push will update a ref that `<src>` normally updates
+without any `<refspec>` on the command line.  Otherwise, missing
+`:<dst>` means to update the same ref as the `<src>`.
++
+If <dst> doesn't start with `refs/` (e.g. `refs/heads/master`) we will
+try to infer where in `refs/*` on the destination <repository> it
+belongs based on the type of <src> being pushed and whether <dst>
+is ambiguous.
++
+--
+* If <dst> unambiguously refers to a ref on the <repository> remote,
+  then push to that ref.
+
+* If <src> resolves to a ref starting with refs/heads/ or refs/tags/,
+  then prepend that to <dst>.
+
+* Other ambiguity resolutions might be added in the future, but for
+  now any other cases will error out with an error indicating what we
+  tried, and depending on the `advice.pushUnqualifiedRefname`
+  configuration (see linkgit:git-config[1]) suggest what refs/
+  namespace you may have wanted to push to.
+
+--
++
+The object referenced by <src> is used to update the <dst> reference
+on the remote side. Whether this is allowed depends on where in
+`refs/*` the <dst> reference lives as described in detail below, in
+those sections "update" means any modifications except deletes, which
+as noted after the next few sections are treated differently.
++
+The `refs/heads/*` namespace will only accept commit objects, and
+updates only if they can be fast-forwarded.
++
+The `refs/tags/*` namespace will accept any kind of object (as
+commits, trees and blobs can be tagged), and any updates to them will
+be rejected.
++
+It's possible to push any type of object to any namespace outside of
+`refs/{tags,heads}/*`. In the case of tags and commits, these will be
+treated as if they were the commits inside `refs/heads/*` for the
+purposes of whether the update is allowed.
++
+I.e. a fast-forward of commits and tags outside `refs/{tags,heads}/*`
+is allowed, even in cases where what's being fast-forwarded is not a
+commit, but a tag object which happens to point to a new commit which
+is a fast-forward of the commit the last tag (or commit) it's
+replacing. Replacing a tag with an entirely different tag is also
+allowed, if it points to the same commit, as well as pushing a peeled
+tag, i.e. pushing the commit that existing tag object points to, or a
+new tag object which an existing commit points to.
++
+Tree and blob objects outside of `refs/{tags,heads}/*` will be treated
+the same way as if they were inside `refs/tags/*`, any update of them
+will be rejected.
++
+All of the rules described above about what's not allowed as an update
+can be overridden by adding an the optional leading `+` to a refspec
+(or using `--force` command line option). The only exception to this
+is that no amount of forcing will make the `refs/heads/*` namespace
+accept a non-commit object. Hooks and configuration can also override
+or amend these rules, see e.g. `receive.denyNonFastForwards` in
+linkgit:git-config[1] and `pre-receive` and `update` in
+linkgit:githooks[5].
++
+Pushing an empty <src> allows you to delete the <dst> ref from the
+remote repository. Deletions are always accepted without a leading `+`
+in the refspec (or `--force`), except when forbidden by configuration
+or hooks. See `receive.denyDeletes` in linkgit:git-config[1] and
+`pre-receive` and `update` in linkgit:githooks[5].
++
+The special refspec `:` (or `+:` to allow non-fast-forward updates)
+directs Git to push "matching" branches: for every branch that exists on
+the local side, the remote side is updated if a branch of the same name
+already exists on the remote side.
++
+`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.
+
+--all::
+--branches::
+	Push all branches (i.e. refs under `refs/heads/`); cannot be
+	used with other <refspec>.
+
+--prune::
+	Remove remote branches that don't have a local counterpart. For example
+	a remote branch `tmp` will be removed if a local branch with the same
+	name doesn't exist any more. This also respects refspecs, e.g.
+	`git push --prune remote refs/heads/*:refs/tmp/*` would
+	make sure that remote `refs/tmp/foo` will be removed if `refs/heads/foo`
+	doesn't exist.
+
+--mirror::
+	Instead of naming each ref to push, specifies that all
+	refs under `refs/` (which includes but is not
+	limited to `refs/heads/`, `refs/remotes/`, and `refs/tags/`)
+	be mirrored to the remote repository.  Newly created local
+	refs will be pushed to the remote end, locally updated refs
+	will be force updated on the remote end, and deleted refs
+	will be removed from the remote end.  This is the default
+	if the configuration option `remote.<remote>.mirror` is
+	set.
+
+-n::
+--dry-run::
+	Do everything except actually send the updates.
+
+--porcelain::
+	Produce machine-readable output.  The output status line for each ref
+	will be tab-separated and sent to stdout instead of stderr.  The full
+	symbolic names of the refs will be given.
+
+-d::
+--delete::
+	All listed refs are deleted from the remote repository. This is
+	the same as prefixing all refs with a colon.
+
+--tags::
+	All refs under `refs/tags` are pushed, in
+	addition to refspecs explicitly listed on the command
+	line.
+
+--follow-tags::
+	Push all the refs that would be pushed without this option,
+	and also push annotated tags in `refs/tags` that are missing
+	from the remote but are pointing at commit-ish that are
+	reachable from the refs being pushed.  This can also be specified
+	with configuration variable `push.followTags`.  For more
+	information, see `push.followTags` in linkgit:git-config[1].
+
+--[no-]signed::
+--signed=(true|false|if-asked)::
+	GPG-sign the push request to update refs on the receiving
+	side, to allow it to be checked by the hooks and/or be
+	logged.  If `false` or `--no-signed`, no signing will be
+	attempted.  If `true` or `--signed`, the push will fail if the
+	server does not support signed pushes.  If set to `if-asked`,
+	sign if and only if the server supports signed pushes.  The push
+	will also fail if the actual call to `gpg --sign` fails.  See
+	linkgit:git-receive-pack[1] for the details on the receiving end.
+
+--[no-]atomic::
+	Use an atomic transaction on the remote side if available.
+	Either all refs are updated, or on error, no refs are updated.
+	If the server does not support atomic pushes the push will fail.
+
+-o <option>::
+--push-option=<option>::
+	Transmit the given string to the server, which passes them to
+	the pre-receive as well as the post-receive hook. The given string
+	must not contain a NUL or LF character.
+	When multiple `--push-option=<option>` are given, they are
+	all sent to the other side in the order listed on the
+	command line.
+	When no `--push-option=<option>` is given from the command
+	line, the values of configuration variable `push.pushOption`
+	are used instead.
+
+--receive-pack=<git-receive-pack>::
+--exec=<git-receive-pack>::
+	Path to the 'git-receive-pack' program on the remote
+	end.  Sometimes useful when pushing to a remote
+	repository over ssh, and you do not have the program in
+	a directory on the default $PATH.
+
+--[no-]force-with-lease::
+--force-with-lease=<refname>::
+--force-with-lease=<refname>:<expect>::
+	Usually, "git push" refuses to update a remote ref that is
+	not an ancestor of the local ref used to overwrite it.
++
+This option overrides this restriction if the current value of the
+remote ref is the expected value.  "git push" fails otherwise.
++
+Imagine that you have to rebase what you have already published.
+You will have to bypass the "must fast-forward" rule in order to
+replace the history you originally published with the rebased history.
+If somebody else built on top of your original history while you are
+rebasing, the tip of the branch at the remote may advance with their
+commit, and blindly pushing with `--force` will lose their work.
++
+This option allows you to say that you expect the history you are
+updating is what you rebased and want to replace. If the remote ref
+still points at the commit you specified, you can be sure that no
+other people did anything to the ref. It is like taking a "lease" on
+the ref without explicitly locking it, and the remote ref is updated
+only if the "lease" is still valid.
++
+`--force-with-lease` alone, without specifying the details, will protect
+all remote refs that are going to be updated by requiring their
+current value to be the same as the remote-tracking branch we have
+for them.
++
+`--force-with-lease=<refname>`, without specifying the expected value, will
+protect the named ref (alone), if it is going to be updated, by
+requiring its current value to be the same as the remote-tracking
+branch we have for it.
++
+`--force-with-lease=<refname>:<expect>` will protect the named ref (alone),
+if it is going to be updated, by requiring its current value to be
+the same as the specified value `<expect>` (which is allowed to be
+different from the remote-tracking branch we have for the refname,
+or we do not even have to have such a remote-tracking branch when
+this form is used).  If `<expect>` is the empty string, then the named ref
+must not already exist.
++
+Note that all forms other than `--force-with-lease=<refname>:<expect>`
+that specifies the expected current value of the ref explicitly are
+still experimental and their semantics may change as we gain experience
+with this feature.
++
+"--no-force-with-lease" will cancel all the previous --force-with-lease on the
+command line.
++
+A general note on safety: supplying this option without an expected
+value, i.e. as `--force-with-lease` or `--force-with-lease=<refname>`
+interacts very badly with anything that implicitly runs `git fetch` on
+the remote to be pushed to in the background, e.g. `git fetch origin`
+on your repository in a cronjob.
++
+The protection it offers over `--force` is ensuring that subsequent
+changes your work wasn't based on aren't clobbered, but this is
+trivially defeated if some background process is updating refs in the
+background. We don't have anything except the remote tracking info to
+go by as a heuristic for refs you're expected to have seen & are
+willing to clobber.
++
+If your editor or some other system is running `git fetch` in the
+background for you a way to mitigate this is to simply set up another
+remote:
++
+	git remote add origin-push $(git config remote.origin.url)
+	git fetch origin-push
++
+Now when the background process runs `git fetch origin` the references
+on `origin-push` won't be updated, and thus commands like:
++
+	git push --force-with-lease origin-push
++
+Will fail unless you manually run `git fetch origin-push`. This method
+is of course entirely defeated by something that runs `git fetch
+--all`, in that case you'd need to either disable it or do something
+more tedious like:
++
+	git fetch              # update 'master' from remote
+	git tag base master    # mark our base point
+	git rebase -i master   # rewrite some commits
+	git push --force-with-lease=master:base master:master
++
+I.e. create a `base` tag for versions of the upstream code that you've
+seen and are willing to overwrite, then rewrite history, and finally
+force push changes to `master` if the remote version is still at
+`base`, regardless of what your local `remotes/origin/master` has been
+updated to in the background.
++
+Alternatively, specifying `--force-if-includes` as an ancillary option
+along with `--force-with-lease[=<refname>]` (i.e., without saying what
+exact commit the ref on the remote side must be pointing at, or which
+refs on the remote side are being protected) at the time of "push" will
+verify if updates from the remote-tracking refs that may have been
+implicitly updated in the background are integrated locally before
+allowing a forced update.
+
+-f::
+--force::
+	Usually, the command refuses to update a remote ref that is
+	not an ancestor of the local ref used to overwrite it.
+	Also, when `--force-with-lease` option is used, the command refuses
+	to update a remote ref whose current value does not match
+	what is expected.
++
+This flag disables these checks, and can cause the remote repository
+to lose commits; use it with care.
++
+Note that `--force` applies to all the refs that are pushed, hence
+using it with `push.default` set to `matching` or with multiple push
+destinations configured with `remote.*.push` may overwrite refs
+other than the current branch (including local refs that are
+strictly behind their remote counterpart).  To force a push to only
+one branch, use a `+` in front of the refspec to push (e.g `git push
+origin +master` to force a push to the `master` branch). See the
+`<refspec>...` section above for details.
+
+--[no-]force-if-includes::
+	Force an update only if the tip of the remote-tracking ref
+	has been integrated locally.
++
+This option enables a check that verifies if the tip of the
+remote-tracking ref is reachable from one of the "reflog" entries of
+the local branch based in it for a rewrite. The check ensures that any
+updates from the remote have been incorporated locally by rejecting the
+forced update if that is not the case.
++
+If the option is passed without specifying `--force-with-lease`, or
+specified along with `--force-with-lease=<refname>:<expect>`, it is
+a "no-op".
++
+Specifying `--no-force-if-includes` disables this behavior.
+
+--repo=<repository>::
+	This option is equivalent to the <repository> argument. If both
+	are specified, the command-line argument takes precedence.
+
+-u::
+--set-upstream::
+	For every branch that is up to date or successfully pushed, add
+	upstream (tracking) reference, used by argument-less
+	linkgit:git-pull[1] and other commands. For more information,
+	see `branch.<name>.merge` in linkgit:git-config[1].
+
+--[no-]thin::
+	These options are passed to linkgit:git-send-pack[1]. A thin transfer
+	significantly reduces the amount of sent data when the sender and
+	receiver share many of the same objects in common. The default is
+	`--thin`.
+
+-q::
+--quiet::
+	Suppress all output, including the listing of updated refs,
+	unless an error occurs. Progress is not reported to the standard
+	error stream.
+
+-v::
+--verbose::
+	Run verbosely.
+
+--progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless -q
+	is specified. This flag forces progress status even if the
+	standard error stream is not directed to a terminal.
+
+--no-recurse-submodules::
+--recurse-submodules=check|on-demand|only|no::
+	May be used to make sure all submodule commits used by the
+	revisions to be pushed are available on a remote-tracking branch.
+	If 'check' is used Git will verify that all submodule commits that
+	changed in the revisions to be pushed are available on at least one
+	remote of the submodule. If any commits are missing the push will
+	be aborted and exit with non-zero status. If 'on-demand' is used
+	all submodules that changed in the revisions to be pushed will be
+	pushed. If on-demand was not able to push all necessary revisions it will
+	also be aborted and exit with non-zero status. If 'only' is used all
+	submodules will be pushed while the superproject is left
+	unpushed. A value of 'no' or using `--no-recurse-submodules` can be used
+	to override the push.recurseSubmodules configuration variable when no
+	submodule recursion is required.
++
+When using 'on-demand' or 'only', if a submodule has a
+"push.recurseSubmodules={on-demand,only}" or "submodule.recurse" configuration,
+further recursion will occur. In this case, "only" is treated as "on-demand".
+
+--[no-]verify::
+	Toggle the pre-push hook (see linkgit:githooks[5]).  The
+	default is --verify, giving the hook a chance to prevent the
+	push.  With --no-verify, the hook is bypassed completely.
+
+-4::
+--ipv4::
+	Use IPv4 addresses only, ignoring IPv6 addresses.
+
+-6::
+--ipv6::
+	Use IPv6 addresses only, ignoring IPv4 addresses.
+
+include::urls-remotes.adoc[]
+
+OUTPUT
+------
+
+The output of "git push" depends on the transport method used; this
+section describes the output when pushing over the Git protocol (either
+locally or via ssh).
+
+The status of the push is output in tabular form, with each line
+representing the status of a single ref. Each line is of the form:
+
+-------------------------------
+ <flag> <summary> <from> -> <to> (<reason>)
+-------------------------------
+
+If --porcelain is used, then each line of the output is of the form:
+
+-------------------------------
+ <flag> \t <from>:<to> \t <summary> (<reason>)
+-------------------------------
+
+The status of up-to-date refs is shown only if --porcelain or --verbose
+option is used.
+
+flag::
+	A single character indicating the status of the ref:
+(space);; for a successfully pushed fast-forward;
+`+`;; for a successful forced update;
+`-`;; for a successfully deleted ref;
+`*`;; for a successfully pushed new ref;
+`!`;; for a ref that was rejected or failed to push; and
+`=`;; for a ref that was up to date and did not need pushing.
+
+summary::
+	For a successfully pushed ref, the summary shows the old and new
+	values of the ref in a form suitable for using as an argument to
+	`git log` (this is `<old>..<new>` in most cases, and
+	`<old>...<new>` for forced non-fast-forward updates).
++
+For a failed update, more details are given:
++
+--
+rejected::
+	Git did not try to send the ref at all, typically because it
+	is not a fast-forward and you did not force the update.
+
+remote rejected::
+	The remote end refused the update.  Usually caused by a hook
+	on the remote side, or because the remote repository has one
+	of the following safety options in effect:
+	`receive.denyCurrentBranch` (for pushes to the checked out
+	branch), `receive.denyNonFastForwards` (for forced
+	non-fast-forward updates), `receive.denyDeletes` or
+	`receive.denyDeleteCurrent`.  See linkgit:git-config[1].
+
+remote failure::
+	The remote end did not report the successful update of the ref,
+	perhaps because of a temporary error on the remote side, a
+	break in the network connection, or other transient error.
+--
+
+from::
+	The name of the local ref being pushed, minus its
+	`refs/<type>/` prefix. In the case of deletion, the
+	name of the local ref is omitted.
+
+to::
+	The name of the remote ref being updated, minus its
+	`refs/<type>/` prefix.
+
+reason::
+	A human-readable explanation. In the case of successfully pushed
+	refs, no explanation is needed. For a failed ref, the reason for
+	failure is described.
+
+NOTE ABOUT FAST-FORWARDS
+------------------------
+
+When an update changes a branch (or more in general, a ref) that used to
+point at commit A to point at another commit B, it is called a
+fast-forward update if and only if B is a descendant of A.
+
+In a fast-forward update from A to B, the set of commits that the original
+commit A built on top of is a subset of the commits the new commit B
+builds on top of.  Hence, it does not lose any history.
+
+In contrast, a non-fast-forward update will lose history.  For example,
+suppose you and somebody else started at the same commit X, and you built
+a history leading to commit B while the other person built a history
+leading to commit A.  The history looks like this:
+
+----------------
+
+      B
+     /
+ ---X---A
+
+----------------
+
+Further suppose that the other person already pushed changes leading to A
+back to the original repository from which you two obtained the original
+commit X.
+
+The push done by the other person updated the branch that used to point at
+commit X to point at commit A.  It is a fast-forward.
+
+But if you try to push, you will attempt to update the branch (that
+now points at A) with commit B.  This does _not_ fast-forward.  If you did
+so, the changes introduced by commit A will be lost, because everybody
+will now start building on top of B.
+
+The command by default does not allow an update that is not a fast-forward
+to prevent such loss of history.
+
+If you do not want to lose your work (history from X to B) or the work by
+the other person (history from X to A), you would need to first fetch the
+history from the repository, create a history that contains changes done
+by both parties, and push the result back.
+
+You can perform "git pull", resolve potential conflicts, and "git push"
+the result.  A "git pull" will create a merge commit C between commits A
+and B.
+
+----------------
+
+      B---C
+     /   /
+ ---X---A
+
+----------------
+
+Updating A with the resulting merge commit will fast-forward and your
+push will be accepted.
+
+Alternatively, you can rebase your change between X and B on top of A,
+with "git pull --rebase", and push the result back.  The rebase will
+create a new commit D that builds the change between X and B on top of
+A.
+
+----------------
+
+      B   D
+     /   /
+ ---X---A
+
+----------------
+
+Again, updating A with this commit will fast-forward and your push will be
+accepted.
+
+There is another common situation where you may encounter non-fast-forward
+rejection when you try to push, and it is possible even when you are
+pushing into a repository nobody else pushes into. After you push commit
+A yourself (in the first picture in this section), replace it with "git
+commit --amend" to produce commit B, and you try to push it out, because
+forgot that you have pushed A out already. In such a case, and only if
+you are certain that nobody in the meantime fetched your earlier commit A
+(and started building on top of it), you can run "git push --force" to
+overwrite it. In other words, "git push --force" is a method reserved for
+a case where you do mean to lose history.
+
+
+EXAMPLES
+--------
+
+`git push`::
+	Works like `git push <remote>`, where <remote> is the
+	current branch's remote (or `origin`, if no remote is
+	configured for the current branch).
+
+`git push origin`::
+	Without additional configuration, pushes the current branch to
+	the configured upstream (`branch.<name>.merge` configuration
+	variable) if it has the same name as the current branch, and
+	errors out without pushing otherwise.
++
+The default behavior of this command when no <refspec> is given can be
+configured by setting the `push` option of the remote, or the `push.default`
+configuration variable.
++
+For example, to default to pushing only the current branch to `origin`
+use `git config remote.origin.push HEAD`.  Any valid <refspec> (like
+the ones in the examples below) can be configured as the default for
+`git push origin`.
+
+`git push origin :`::
+	Push "matching" branches to `origin`. See
+	<refspec> in the <<OPTIONS,OPTIONS>> section above for a
+	description of "matching" branches.
+
+`git push origin master`::
+	Find a ref that matches `master` in the source repository
+	(most likely, it would find `refs/heads/master`), and update
+	the same ref (e.g. `refs/heads/master`) in `origin` repository
+	with it.  If `master` did not exist remotely, it would be
+	created.
+
+`git push origin HEAD`::
+	A handy way to push the current branch to the same name on the
+	remote.
+
+`git push mothership master:satellite/master dev:satellite/dev`::
+	Use the source ref that matches `master` (e.g. `refs/heads/master`)
+	to update the ref that matches `satellite/master` (most probably
+	`refs/remotes/satellite/master`) in the `mothership` repository;
+	do the same for `dev` and `satellite/dev`.
++
+See the section describing `<refspec>...` above for a discussion of
+the matching semantics.
++
+This is to emulate `git fetch` run on the `mothership` using `git
+push` that is run in the opposite direction in order to integrate
+the work done on `satellite`, and is often necessary when you can
+only make connection in one way (i.e. satellite can ssh into
+mothership but mothership cannot initiate connection to satellite
+because the latter is behind a firewall or does not run sshd).
++
+After running this `git push` on the `satellite` machine, you would
+ssh into the `mothership` and run `git merge` there to complete the
+emulation of `git pull` that were run on `mothership` to pull changes
+made on `satellite`.
+
+`git push origin HEAD:master`::
+	Push the current branch to the remote ref matching `master` in the
+	`origin` repository. This form is convenient to push the current
+	branch without thinking about its local name.
+
+`git push origin master:refs/heads/experimental`::
+	Create the branch `experimental` in the `origin` repository
+	by copying the current `master` branch.  This form is only
+	needed to create a new branch or tag in the remote repository when
+	the local name and the remote name are different; otherwise,
+	the ref name on its own will work.
+
+`git push origin :experimental`::
+	Find a ref that matches `experimental` in the `origin` repository
+	(e.g. `refs/heads/experimental`), and delete it.
+
+`git push origin +dev:master`::
+	Update the origin repository's master branch with the dev branch,
+	allowing non-fast-forward updates.  *This can leave unreferenced
+	commits dangling in the origin repository.*  Consider the
+	following situation, where a fast-forward is not possible:
++
+----
+	    o---o---o---A---B  origin/master
+		     \
+		      X---Y---Z  dev
+----
++
+The above command would change the origin repository to
++
+----
+		      A---B  (unnamed branch)
+		     /
+	    o---o---o---X---Y---Z  master
+----
++
+Commits A and B would no longer belong to a branch with a symbolic name,
+and so would be unreachable.  As such, these commits would be removed by
+a `git gc` command on the origin repository.
+
+include::transfer-data-leaks.adoc[]
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/push.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-quiltimport.adoc b/Documentation/git-quiltimport.adoc
new file mode 100644
index 0000000000..40e02d92eb
--- /dev/null
+++ b/Documentation/git-quiltimport.adoc
@@ -0,0 +1,64 @@
+git-quiltimport(1)
+==================
+
+NAME
+----
+git-quiltimport - Applies a quilt patchset onto the current branch
+
+
+SYNOPSIS
+--------
+[verse]
+'git quiltimport' [--dry-run | -n] [--author <author>] [--patches <dir>]
+		[--series <file>] [--keep-non-patch]
+
+
+DESCRIPTION
+-----------
+Applies a quilt patchset onto the current Git branch, preserving
+the patch boundaries, patch order, and patch descriptions present
+in the quilt patchset.
+
+For each patch the code attempts to extract the author from the
+patch description.  If that fails it falls back to the author
+specified with --author.  If the --author flag was not given
+the patch description is displayed and the user is asked to
+interactively enter the author of the patch.
+
+If a subject is not found in the patch description the patch name is
+preserved as the 1 line subject in the Git description.
+
+OPTIONS
+-------
+
+-n::
+--dry-run::
+	Walk through the patches in the series and warn
+	if we cannot find all of the necessary information to commit
+	a patch.  At the time of this writing only missing author
+	information is warned about.
+
+--author 'Author Name <Author Email>'::
+	The author name and email address to use when no author
+	information can be found in the patch description.
+
+--patches <dir>::
+	The directory to find the quilt patches.
++
+The default for the patch directory is 'patches'
+or the value of the `$QUILT_PATCHES` environment
+variable.
+
+--series <file>::
+	The quilt series file.
++
+The default for the series file is <patches>/series
+or the value of the `$QUILT_SERIES` environment
+variable.
+
+--keep-non-patch::
+	Pass `-b` flag to 'git mailinfo' (see linkgit:git-mailinfo[1]).
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-range-diff.adoc b/Documentation/git-range-diff.adoc
new file mode 100644
index 0000000000..db0e4279b5
--- /dev/null
+++ b/Documentation/git-range-diff.adoc
@@ -0,0 +1,312 @@
+git-range-diff(1)
+=================
+
+NAME
+----
+git-range-diff - Compare two commit ranges (e.g. two versions of a branch)
+
+SYNOPSIS
+--------
+[verse]
+'git range-diff' [--color=[<when>]] [--no-color] [<diff-options>]
+	[--no-dual-color] [--creation-factor=<factor>]
+	[--left-only | --right-only] [--diff-merges=<format>]
+	[--remerge-diff]
+	( <range1> <range2> | <rev1>...<rev2> | <base> <rev1> <rev2> )
+	[[--] <path>...]
+
+DESCRIPTION
+-----------
+
+This command shows the differences between two versions of a patch
+series, or more generally, two commit ranges (ignoring merge commits).
+
+In the presence of `<path>` arguments, these commit ranges are limited
+accordingly.
+
+To that end, it first finds pairs of commits from both commit ranges
+that correspond with each other. Two commits are said to correspond when
+the diff between their patches (i.e. the author information, the commit
+message and the commit diff) is reasonably small compared to the
+patches' size. See ``Algorithm`` below for details.
+
+Finally, the list of matching commits is shown in the order of the
+second commit range, with unmatched commits being inserted just after
+all of their ancestors have been shown.
+
+There are three ways to specify the commit ranges:
+
+- `<range1> <range2>`: Either commit range can be of the form
+  `<base>..<rev>`, `<rev>^!` or `<rev>^-<n>`. See `SPECIFYING RANGES`
+  in linkgit:gitrevisions[7] for more details.
+
+- `<rev1>...<rev2>`. This is equivalent to
+  `<rev2>..<rev1> <rev1>..<rev2>`.
+
+- `<base> <rev1> <rev2>`: This is equivalent to `<base>..<rev1>
+  <base>..<rev2>`.
+
+OPTIONS
+-------
+--no-dual-color::
+	When the commit diffs differ, `git range-diff` recreates the
+	original diffs' coloring, and adds outer -/+ diff markers with
+	the *background* being red/green to make it easier to see e.g.
+	when there was a change in what exact lines were added.
++
+Additionally, the commit diff lines that are only present in the first commit
+range are shown "dimmed" (this can be overridden using the `color.diff.<slot>`
+config setting where `<slot>` is one of `contextDimmed`, `oldDimmed` and
+`newDimmed`), and the commit diff lines that are only present in the second
+commit range are shown in bold (which can be overridden using the config
+settings `color.diff.<slot>` with `<slot>` being one of `contextBold`,
+`oldBold` or `newBold`).
++
+This is known to `range-diff` as "dual coloring". Use `--no-dual-color`
+to revert to color all lines according to the outer diff markers
+(and completely ignore the inner diff when it comes to color).
+
+--creation-factor=<percent>::
+	Set the creation/deletion cost fudge factor to `<percent>`.
+	Defaults to 60. Try a larger value if `git range-diff` erroneously
+	considers a large change a total rewrite (deletion of one commit
+	and addition of another), and a smaller one in the reverse case.
+	See the ``Algorithm`` section below for an explanation of why this is
+	needed.
+
+--left-only::
+	Suppress commits that are missing from the first specified range
+	(or the "left range" when using the `<rev1>...<rev2>` format).
+
+--right-only::
+	Suppress commits that are missing from the second specified range
+	(or the "right range" when using the `<rev1>...<rev2>` format).
+
+--diff-merges=<format>::
+	Instead of ignoring merge commits, generate diffs for them using the
+	corresponding `--diff-merges=<format>` option of linkgit:git-log[1],
+	and include them in the comparison.
++
+Note: In the common case, the `remerge` mode will be the most natural one
+to use, as it shows only the diff on top of what Git's merge machinery would
+have produced. In other words, if a merge commit is the result of a
+non-conflicting `git merge`, the `remerge` mode will represent it with an empty
+diff.
+
+--remerge-diff::
+	Convenience option, equivalent to `--diff-merges=remerge`.
+
+--[no-]notes[=<ref>]::
+	This flag is passed to the `git log` program
+	(see linkgit:git-log[1]) that generates the patches.
+
+<range1> <range2>::
+	Compare the commits specified by the two ranges, where
+	`<range1>` is considered an older version of `<range2>`.
+
+<rev1>...<rev2>::
+	Equivalent to passing `<rev2>..<rev1>` and `<rev1>..<rev2>`.
+
+<base> <rev1> <rev2>::
+	Equivalent to passing `<base>..<rev1>` and `<base>..<rev2>`.
+	Note that `<base>` does not need to be the exact branch point
+	of the branches. Example: after rebasing a branch `my-topic`,
+	`git range-diff my-topic@{u} my-topic@{1} my-topic` would
+	show the differences introduced by the rebase.
+
+`git range-diff` also accepts the regular diff options (see
+linkgit:git-diff[1]), most notably the `--color=[<when>]` and
+`--no-color` options. These options are used when generating the "diff
+between patches", i.e. to compare the author, commit message and diff of
+corresponding old/new commits. There is currently no means to tweak most of the
+diff options passed to `git log` when generating those patches.
+
+OUTPUT STABILITY
+----------------
+
+The output of the `range-diff` command is subject to change. It is
+intended to be human-readable porcelain output, not something that can
+be used across versions of Git to get a textually stable `range-diff`
+(as opposed to something like the `--stable` option to
+linkgit:git-patch-id[1]). There's also no equivalent of
+linkgit:git-apply[1] for `range-diff`, the output is not intended to
+be machine-readable.
+
+This is particularly true when passing in diff options. Currently some
+options like `--stat` can, as an emergent effect, produce output
+that's quite useless in the context of `range-diff`. Future versions
+of `range-diff` may learn to interpret such options in a manner
+specific to `range-diff` (e.g. for `--stat` producing human-readable
+output which summarizes how the diffstat changed).
+
+CONFIGURATION
+-------------
+This command uses the `diff.color.*` and `pager.range-diff` settings
+(the latter is on by default).
+See linkgit:git-config[1].
+
+
+EXAMPLES
+--------
+
+When a rebase required merge conflicts to be resolved, compare the changes
+introduced by the rebase directly afterwards using:
+
+------------
+$ git range-diff @{u} @{1} @
+------------
+
+
+A typical output of `git range-diff` would look like this:
+
+------------
+-:  ------- > 1:  0ddba11 Prepare for the inevitable!
+1:  c0debee = 2:  cab005e Add a helpful message at the start
+2:  f00dbal ! 3:  decafe1 Describe a bug
+    @@ -1,3 +1,3 @@
+     Author: A U Thor <author@xxxxxxxxxxx>
+
+    -TODO: Describe a bug
+    +Describe a bug
+    @@ -324,5 +324,6
+      This is expected.
+
+    -+What is unexpected is that it will also crash.
+    ++Unexpectedly, it also crashes. This is a bug, and the jury is
+    ++still out there how to fix it best. See ticket #314 for details.
+
+      Contact
+3:  bedead < -:  ------- TO-UNDO
+------------
+
+In this example, there are 3 old and 3 new commits, where the developer
+removed the 3rd, added a new one before the first two, and modified the
+commit message of the 2nd commit as well as its diff.
+
+When the output goes to a terminal, it is color-coded by default, just
+like regular `git diff`'s output. In addition, the first line (adding a
+commit) is green, the last line (deleting a commit) is red, the second
+line (with a perfect match) is yellow like the commit header of `git
+show`'s output, and the third line colors the old commit red, the new
+one green and the rest like `git show`'s commit header.
+
+A naive color-coded diff of diffs is actually a bit hard to read,
+though, as it colors the entire lines red or green. The line that added
+"What is unexpected" in the old commit, for example, is completely red,
+even if the intent of the old commit was to add something.
+
+To help with that, `range` uses the `--dual-color` mode by default. In
+this mode, the diff of diffs will retain the original diff colors, and
+prefix the lines with -/+ markers that have their *background* red or
+green, to make it more obvious that they describe how the diff itself
+changed.
+
+
+Algorithm
+---------
+
+The general idea is this: we generate a cost matrix between the commits
+in both commit ranges, then solve the least-cost assignment.
+
+The cost matrix is populated thusly: for each pair of commits, both
+diffs are generated and the "diff of diffs" is generated, with 3 context
+lines, then the number of lines in that diff is used as cost.
+
+To avoid false positives (e.g. when a patch has been removed, and an
+unrelated patch has been added between two iterations of the same patch
+series), the cost matrix is extended to allow for that, by adding
+fixed-cost entries for wholesale deletes/adds.
+
+Example: Let commits `1--2` be the first iteration of a patch series and
+`A--C` the second iteration. Let's assume that `A` is a cherry-pick of
+`2,` and `C` is a cherry-pick of `1` but with a small modification (say,
+a fixed typo). Visualize the commits as a bipartite graph:
+
+------------
+    1            A
+
+    2            B
+
+		 C
+------------
+
+We are looking for a "best" explanation of the new series in terms of
+the old one. We can represent an "explanation" as an edge in the graph:
+
+
+------------
+    1            A
+	       /
+    2 --------'  B
+
+		 C
+------------
+
+This explanation comes for "free" because there was no change. Similarly
+`C` could be explained using `1`, but that comes at some cost c>0
+because of the modification:
+
+------------
+    1 ----.      A
+	  |    /
+    2 ----+---'  B
+	  |
+	  `----- C
+	  c>0
+------------
+
+In mathematical terms, what we are looking for is some sort of a minimum
+cost bipartite matching; `1` is matched to `C` at some cost, etc. The
+underlying graph is in fact a complete bipartite graph; the cost we
+associate with every edge is the size of the diff between the two
+commits' patches. To explain also new commits, we introduce dummy nodes
+on both sides:
+
+------------
+    1 ----.      A
+	  |    /
+    2 ----+---'  B
+	  |
+    o     `----- C
+	  c>0
+    o            o
+
+    o            o
+------------
+
+The cost of an edge `o--C` is the size of `C`'s diff, modified by a
+fudge factor that should be smaller than 100%. The cost of an edge
+`o--o` is free. The fudge factor is necessary because even if `1` and
+`C` have nothing in common, they may still share a few empty lines and
+such, possibly making the assignment `1--C`, `o--o` slightly cheaper
+than `1--o`, `o--C` even if `1` and `C` have nothing in common. With the
+fudge factor we require a much larger common part to consider patches as
+corresponding.
+
+The overall time needed to compute this algorithm is the time needed to
+compute n+m commit diffs and then n*m diffs of patches, plus the time
+needed to compute the least-cost assignment between n and m diffs. Git
+uses an implementation of the Jonker-Volgenant algorithm to solve the
+assignment problem, which has cubic runtime complexity. The matching
+found in this case will look like this:
+
+------------
+    1 ----.      A
+	  |    /
+    2 ----+---'  B
+       .--+-----'
+    o -'  `----- C
+	  c>0
+    o ---------- o
+
+    o ---------- o
+------------
+
+
+SEE ALSO
+--------
+linkgit:git-log[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-read-tree.adoc b/Documentation/git-read-tree.adoc
new file mode 100644
index 0000000000..1c48c28996
--- /dev/null
+++ b/Documentation/git-read-tree.adoc
@@ -0,0 +1,437 @@
+git-read-tree(1)
+================
+
+NAME
+----
+git-read-tree - Reads tree information into the index
+
+
+SYNOPSIS
+--------
+[verse]
+'git read-tree' [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>)
+		[-u | -i]] [--index-output=<file>] [--no-sparse-checkout]
+		(--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])
+
+
+DESCRIPTION
+-----------
+Reads the tree information given by <tree-ish> into the index,
+but does not actually *update* any of the files it "caches". (see:
+linkgit:git-checkout-index[1])
+
+Optionally, it can merge a tree into the index, perform a
+fast-forward (i.e. 2-way) merge, or a 3-way merge, with the `-m`
+flag.  When used with `-m`, the `-u` flag causes it to also update
+the files in the work tree with the result of the merge.
+
+Only trivial merges are done by 'git read-tree' itself.  Only conflicting paths
+will be in an unmerged state when 'git read-tree' returns.
+
+OPTIONS
+-------
+-m::
+	Perform a merge, not just a read.  The command will
+	refuse to run if your index file has unmerged entries,
+	indicating that you have not finished a previous merge you
+	started.
+
+--reset::
+	Same as -m, except that unmerged entries are discarded instead
+	of failing.  When used with `-u`, updates leading to loss of
+	working tree changes or untracked files or directories will not
+	abort the operation.
+
+-u::
+	After a successful merge, update the files in the work
+	tree with the result of the merge.
+
+-i::
+	Usually a merge requires the index file as well as the
+	files in the working tree to be up to date with the
+	current head commit, in order not to lose local
+	changes.  This flag disables the check with the working
+	tree and is meant to be used when creating a merge of
+	trees that are not directly related to the current
+	working tree status into a temporary index file.
+
+-n::
+--dry-run::
+	Check if the command would error out, without updating the index
+	or the files in the working tree for real.
+
+-v::
+	Show the progress of checking files out.
+
+--trivial::
+	Restrict three-way merge by 'git read-tree' to happen
+	only if there is no file-level merging required, instead
+	of resolving merge for trivial cases and leaving
+	conflicting files unresolved in the index.
+
+--aggressive::
+	Usually a three-way merge by 'git read-tree' resolves
+	the merge for really trivial cases and leaves other
+	cases unresolved in the index, so that porcelains can
+	implement different merge policies.  This flag makes the
+	command resolve a few more cases internally:
++
+* when one side removes a path and the other side leaves the path
+  unmodified.  The resolution is to remove that path.
+* when both sides remove a path.  The resolution is to remove that path.
+* when both sides add a path identically.  The resolution
+  is to add that path.
+
+--prefix=<prefix>::
+	Keep the current index contents, and read the contents
+	of the named tree-ish under the directory at `<prefix>`.
+	The command will refuse to overwrite entries that already
+	existed in the original index file.
+
+--index-output=<file>::
+	Instead of writing the results out to `$GIT_INDEX_FILE`,
+	write the resulting index in the named file.  While the
+	command is operating, the original index file is locked
+	with the same mechanism as usual.  The file must allow
+	to be rename(2)ed into from a temporary file that is
+	created next to the usual index file; typically this
+	means it needs to be on the same filesystem as the index
+	file itself, and you need write permission to the
+	directories the index file and index output file are
+	located in.
+
+--[no-]recurse-submodules::
+	Using --recurse-submodules will update the content of all active
+	submodules according to the commit recorded in the superproject by
+	calling read-tree recursively, also setting the submodules' HEAD to be
+	detached at that commit.
+
+--no-sparse-checkout::
+	Disable sparse checkout support even if `core.sparseCheckout`
+	is true.
+
+--empty::
+	Instead of reading tree object(s) into the index, just empty
+	it.
+
+-q::
+--quiet::
+	Quiet, suppress feedback messages.
+
+<tree-ish#>::
+	The id of the tree object(s) to be read/merged.
+
+
+MERGING
+-------
+If `-m` is specified, 'git read-tree' can perform 3 kinds of
+merge, a single tree merge if only 1 tree is given, a
+fast-forward merge with 2 trees, or a 3-way merge if 3 or more trees are
+provided.
+
+
+Single Tree Merge
+~~~~~~~~~~~~~~~~~
+If only 1 tree is specified, 'git read-tree' operates as if the user did not
+specify `-m`, except that if the original index has an entry for a
+given pathname, and the contents of the path match with the tree
+being read, the stat info from the index is used. (In other words, the
+index's stat()s take precedence over the merged tree's).
+
+That means that if you do a `git read-tree -m <newtree>` followed by a
+`git checkout-index -f -u -a`, the 'git checkout-index' only checks out
+the stuff that really changed.
+
+This is used to avoid unnecessary false hits when 'git diff-files' is
+run after 'git read-tree'.
+
+
+Two Tree Merge
+~~~~~~~~~~~~~~
+
+Typically, this is invoked as `git read-tree -m $H $M`, where $H
+is the head commit of the current repository, and $M is the head
+of a foreign tree, which is simply ahead of $H (i.e. we are in a
+fast-forward situation).
+
+When two trees are specified, the user is telling 'git read-tree'
+the following:
+
+     1. The current index and work tree is derived from $H, but
+	the user may have local changes in them since $H.
+
+     2. The user wants to fast-forward to $M.
+
+In this case, the `git read-tree -m $H $M` command makes sure
+that no local change is lost as the result of this "merge".
+Here are the "carry forward" rules, where "I" denotes the index,
+"clean" means that index and work tree coincide, and "exists"/"nothing"
+refer to the presence of a path in the specified commit:
+
+....
+	I                   H        M        Result
+       -------------------------------------------------------
+     0  nothing             nothing  nothing  (does not happen)
+     1  nothing             nothing  exists   use M
+     2  nothing             exists   nothing  remove path from index
+     3  nothing             exists   exists,  use M if "initial checkout",
+				     H == M   keep index otherwise
+				     exists,  fail
+				     H != M
+
+        clean I==H  I==M
+       ------------------
+     4  yes   N/A   N/A     nothing  nothing  keep index
+     5  no    N/A   N/A     nothing  nothing  keep index
+
+     6  yes   N/A   yes     nothing  exists   keep index
+     7  no    N/A   yes     nothing  exists   keep index
+     8  yes   N/A   no      nothing  exists   fail
+     9  no    N/A   no      nothing  exists   fail
+
+     10 yes   yes   N/A     exists   nothing  remove path from index
+     11 no    yes   N/A     exists   nothing  fail
+     12 yes   no    N/A     exists   nothing  fail
+     13 no    no    N/A     exists   nothing  fail
+
+	clean (H==M)
+       ------
+     14 yes                 exists   exists   keep index
+     15 no                  exists   exists   keep index
+
+        clean I==H  I==M (H!=M)
+       ------------------
+     16 yes   no    no      exists   exists   fail
+     17 no    no    no      exists   exists   fail
+     18 yes   no    yes     exists   exists   keep index
+     19 no    no    yes     exists   exists   keep index
+     20 yes   yes   no      exists   exists   use M
+     21 no    yes   no      exists   exists   fail
+....
+
+In all "keep index" cases, the index entry stays as in the
+original index file.  If the entry is not up to date,
+'git read-tree' keeps the copy in the work tree intact when
+operating under the -u flag.
+
+When this form of 'git read-tree' returns successfully, you can
+see which of the "local changes" that you made were carried forward by running
+`git diff-index --cached $M`.  Note that this does not
+necessarily match what `git diff-index --cached $H` would have
+produced before such a two tree merge.  This is because of cases
+18 and 19 -- if you already had the changes in $M (e.g. maybe
+you picked it up via e-mail in a patch form), `git diff-index
+--cached $H` would have told you about the change before this
+merge, but it would not show in `git diff-index --cached $M`
+output after the two-tree merge.
+
+Case 3 is slightly tricky and needs explanation.  The result from this
+rule logically should be to remove the path if the user staged the removal
+of the path and then switching to a new branch.  That however will prevent
+the initial checkout from happening, so the rule is modified to use M (new
+tree) only when the content of the index is empty.  Otherwise the removal
+of the path is kept as long as $H and $M are the same.
+
+3-Way Merge
+~~~~~~~~~~~
+Each "index" entry has two bits worth of "stage" state. stage 0 is the
+normal one, and is the only one you'd see in any kind of normal use.
+
+However, when you do 'git read-tree' with three trees, the "stage"
+starts out at 1.
+
+This means that you can do
+
+----------------
+$ git read-tree -m <tree1> <tree2> <tree3>
+----------------
+
+and you will end up with an index with all of the <tree1> entries in
+"stage1", all of the <tree2> entries in "stage2" and all of the
+<tree3> entries in "stage3".  When performing a merge of another
+branch into the current branch, we use the common ancestor tree
+as <tree1>, the current branch head as <tree2>, and the other
+branch head as <tree3>.
+
+Furthermore, 'git read-tree' has special-case logic that says: if you see
+a file that matches in all respects in the following states, it
+"collapses" back to "stage0":
+
+   - stage 2 and 3 are the same; take one or the other (it makes no
+     difference - the same work has been done on our branch in
+     stage 2 and their branch in stage 3)
+
+   - stage 1 and stage 2 are the same and stage 3 is different; take
+     stage 3 (our branch in stage 2 did not do anything since the
+     ancestor in stage 1 while their branch in stage 3 worked on
+     it)
+
+   - stage 1 and stage 3 are the same and stage 2 is different take
+     stage 2 (we did something while they did nothing)
+
+The 'git write-tree' command refuses to write a nonsensical tree, and it
+will complain about unmerged entries if it sees a single entry that is not
+stage 0.
+
+OK, this all sounds like a collection of totally nonsensical rules,
+but it's actually exactly what you want in order to do a fast
+merge. The different stages represent the "result tree" (stage 0, aka
+"merged"), the original tree (stage 1, aka "orig"), and the two trees
+you are trying to merge (stage 2 and 3 respectively).
+
+The order of stages 1, 2 and 3 (hence the order of three
+<tree-ish> command-line arguments) are significant when you
+start a 3-way merge with an index file that is already
+populated.  Here is an outline of how the algorithm works:
+
+- if a file exists in identical format in all three trees, it will
+  automatically collapse to "merged" state by 'git read-tree'.
+
+- a file that has _any_ difference what-so-ever in the three trees
+  will stay as separate entries in the index. It's up to "porcelain
+  policy" to determine how to remove the non-0 stages, and insert a
+  merged version.
+
+- the index file saves and restores with all this information, so you
+  can merge things incrementally, but as long as it has entries in
+  stages 1/2/3 (i.e., "unmerged entries") you can't write the result. So
+  now the merge algorithm ends up being really simple:
+
+  * you walk the index in order, and ignore all entries of stage 0,
+    since they've already been done.
+
+  * if you find a "stage1", but no matching "stage2" or "stage3", you
+    know it's been removed from both trees (it only existed in the
+    original tree), and you remove that entry.
+
+  * if you find a matching "stage2" and "stage3" tree, you remove one
+    of them, and turn the other into a "stage0" entry. Remove any
+    matching "stage1" entry if it exists too.  .. all the normal
+    trivial rules ..
+
+You would normally use 'git merge-index' with supplied
+'git merge-one-file' to do this last step.  The script updates
+the files in the working tree as it merges each path and at the
+end of a successful merge.
+
+When you start a 3-way merge with an index file that is already
+populated, it is assumed that it represents the state of the
+files in your work tree, and you can even have files with
+changes unrecorded in the index file.  It is further assumed
+that this state is "derived" from the stage 2 tree.  The 3-way
+merge refuses to run if it finds an entry in the original index
+file that does not match stage 2.
+
+This is done to prevent you from losing your work-in-progress
+changes, and mixing your random changes in an unrelated merge
+commit.  To illustrate, suppose you start from what has been
+committed last to your repository:
+
+----------------
+$ JC=`git rev-parse --verify "HEAD^0"`
+$ git checkout-index -f -u -a $JC
+----------------
+
+You do random edits, without running 'git update-index'.  And then
+you notice that the tip of your "upstream" tree has advanced
+since you pulled from him:
+
+----------------
+$ git fetch git://.... linus
+$ LT=`git rev-parse FETCH_HEAD`
+----------------
+
+Your work tree is still based on your HEAD ($JC), but you have
+some edits since.  Three-way merge makes sure that you have not
+added or modified index entries since $JC, and if you haven't,
+then does the right thing.  So with the following sequence:
+
+----------------
+$ git read-tree -m -u `git merge-base $JC $LT` $JC $LT
+$ git merge-index git-merge-one-file -a
+$ echo "Merge with Linus" | \
+  git commit-tree `git write-tree` -p $JC -p $LT
+----------------
+
+what you would commit is a pure merge between $JC and $LT without
+your work-in-progress changes, and your work tree would be
+updated to the result of the merge.
+
+However, if you have local changes in the working tree that
+would be overwritten by this merge, 'git read-tree' will refuse
+to run to prevent your changes from being lost.
+
+In other words, there is no need to worry about what exists only
+in the working tree.  When you have local changes in a part of
+the project that is not involved in the merge, your changes do
+not interfere with the merge, and are kept intact.  When they
+*do* interfere, the merge does not even start ('git read-tree'
+complains loudly and fails without modifying anything).  In such
+a case, you can simply continue doing what you were in the
+middle of doing, and when your working tree is ready (i.e. you
+have finished your work-in-progress), attempt the merge again.
+
+
+SPARSE CHECKOUT
+---------------
+
+Note: The skip-worktree capabilities in linkgit:git-update-index[1]
+and `read-tree` predated the introduction of
+linkgit:git-sparse-checkout[1].  Users are encouraged to use the
+`sparse-checkout` command in preference to these plumbing commands for
+sparse-checkout/skip-worktree related needs.  However, the information
+below might be useful to users trying to understand the pattern style
+used in non-cone mode of the `sparse-checkout` command.
+
+"Sparse checkout" allows populating the working directory sparsely.
+It uses the skip-worktree bit (see linkgit:git-update-index[1]) to
+tell Git whether a file in the working directory is worth looking at.
+
+'git read-tree' and other merge-based commands ('git merge', 'git
+checkout'...) can help maintaining the skip-worktree bitmap and working
+directory update. `$GIT_DIR/info/sparse-checkout` is used to
+define the skip-worktree reference bitmap. When 'git read-tree' needs
+to update the working directory, it resets the skip-worktree bit in the index
+based on this file, which uses the same syntax as .gitignore files.
+If an entry matches a pattern in this file, or the entry corresponds to
+a file present in the working tree, then skip-worktree will not be
+set on that entry. Otherwise, skip-worktree will be set.
+
+Then it compares the new skip-worktree value with the previous one. If
+skip-worktree turns from set to unset, it will add the corresponding
+file back. If it turns from unset to set, that file will be removed.
+
+While `$GIT_DIR/info/sparse-checkout` is usually used to specify what
+files are in, you can also specify what files are _not_ in, using
+negate patterns. For example, to remove the file `unwanted`:
+
+----------------
+/*
+!unwanted
+----------------
+
+Another tricky thing is fully repopulating the working directory when you
+no longer want sparse checkout. You cannot just disable "sparse
+checkout" because skip-worktree bits are still in the index and your working
+directory is still sparsely populated. You should re-populate the working
+directory with the `$GIT_DIR/info/sparse-checkout` file content as
+follows:
+
+----------------
+/*
+----------------
+
+Then you can disable sparse checkout. Sparse checkout support in 'git
+read-tree' and similar commands is disabled by default. You need to
+turn `core.sparseCheckout` on in order to have sparse checkout
+support.
+
+
+SEE ALSO
+--------
+linkgit:git-write-tree[1], linkgit:git-ls-files[1],
+linkgit:gitignore[5], linkgit:git-sparse-checkout[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
new file mode 100644
index 0000000000..f0d2a5c8b0
--- /dev/null
+++ b/Documentation/git-rebase.adoc
@@ -0,0 +1,1304 @@
+git-rebase(1)
+=============
+
+NAME
+----
+git-rebase - Reapply commits on top of another base tip
+
+SYNOPSIS
+--------
+[verse]
+'git rebase' [-i | --interactive] [<options>] [--exec <cmd>]
+	[--onto <newbase> | --keep-base] [<upstream> [<branch>]]
+'git rebase' [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
+	--root [<branch>]
+'git rebase' (--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)
+
+DESCRIPTION
+-----------
+If `<branch>` is specified, `git rebase` will perform an automatic
+`git switch <branch>` before doing anything else.  Otherwise
+it remains on the current branch.
+
+If `<upstream>` is not specified, the upstream configured in
+`branch.<name>.remote` and `branch.<name>.merge` options will be used (see
+linkgit:git-config[1] for details) and the `--fork-point` option is
+assumed.  If you are currently not on any branch or if the current
+branch does not have a configured upstream, the rebase will abort.
+
+All changes made by commits in the current branch but that are not
+in `<upstream>` are saved to a temporary area.  This is the same set
+of commits that would be shown by `git log <upstream>..HEAD`; or by
+`git log 'fork_point'..HEAD`, if `--fork-point` is active (see the
+description on `--fork-point` below); or by `git log HEAD`, if the
+`--root` option is specified.
+
+The current branch is reset to `<upstream>` or `<newbase>` if the
+`--onto` option was supplied.  This has the exact same effect as
+`git reset --hard <upstream>` (or `<newbase>`). `ORIG_HEAD` is set
+to point at the tip of the branch before the reset.
+
+[NOTE]
+`ORIG_HEAD` is not guaranteed to still point to the previous branch tip
+at the end of the rebase if other commands that write that pseudo-ref
+(e.g. `git reset`) are used during the rebase. The previous branch tip,
+however, is accessible using the reflog of the current branch
+(i.e. `@{1}`, see linkgit:gitrevisions[7]).
+
+The commits that were previously saved into the temporary area are
+then reapplied to the current branch, one by one, in order. Note that
+any commits in `HEAD` which introduce the same textual changes as a commit
+in `HEAD..<upstream>` are omitted (i.e., a patch already accepted upstream
+with a different commit message or timestamp will be skipped).
+
+It is possible that a merge failure will prevent this process from being
+completely automatic.  You will have to resolve any such merge failure
+and run `git rebase --continue`.  Another option is to bypass the commit
+that caused the merge failure with `git rebase --skip`.  To check out the
+original `<branch>` and remove the `.git/rebase-apply` working files, use
+the command `git rebase --abort` instead.
+
+Assume the following history exists and the current branch is "topic":
+
+------------
+          A---B---C topic
+         /
+    D---E---F---G master
+------------
+
+From this point, the result of either of the following commands:
+
+
+    git rebase master
+    git rebase master topic
+
+would be:
+
+------------
+                  A'--B'--C' topic
+                 /
+    D---E---F---G master
+------------
+
+*NOTE:* The latter form is just a short-hand of `git checkout topic`
+followed by `git rebase master`. When rebase exits `topic` will
+remain the checked-out branch.
+
+If the upstream branch already contains a change you have made (e.g.,
+because you mailed a patch which was applied upstream), then that commit
+will be skipped and warnings will be issued (if the 'merge' backend is
+used).  For example, running `git rebase master` on the following
+history (in which `A'` and `A` introduce the same set of changes, but
+have different committer information):
+
+------------
+          A---B---C topic
+         /
+    D---E---A'---F master
+------------
+
+will result in:
+
+------------
+                   B'---C' topic
+                  /
+    D---E---A'---F master
+------------
+
+Here is how you would transplant a topic branch based on one
+branch to another, to pretend that you forked the topic branch
+from the latter branch, using `rebase --onto`.
+
+First let's assume your 'topic' is based on branch 'next'.
+For example, a feature developed in 'topic' depends on some
+functionality which is found in 'next'.
+
+------------
+    o---o---o---o---o  master
+         \
+          o---o---o---o---o  next
+                           \
+                            o---o---o  topic
+------------
+
+We want to make 'topic' forked from branch 'master'; for example,
+because the functionality on which 'topic' depends was merged into the
+more stable 'master' branch. We want our tree to look like this:
+
+------------
+    o---o---o---o---o  master
+        |            \
+        |             o'--o'--o'  topic
+         \
+          o---o---o---o---o  next
+------------
+
+We can get this using the following command:
+
+    git rebase --onto master next topic
+
+
+Another example of --onto option is to rebase part of a
+branch.  If we have the following situation:
+
+------------
+                            H---I---J topicB
+                           /
+                  E---F---G  topicA
+                 /
+    A---B---C---D  master
+------------
+
+then the command
+
+    git rebase --onto master topicA topicB
+
+would result in:
+
+------------
+                 H'--I'--J'  topicB
+                /
+                | E---F---G  topicA
+                |/
+    A---B---C---D  master
+------------
+
+This is useful when topicB does not depend on topicA.
+
+A range of commits could also be removed with rebase.  If we have
+the following situation:
+
+------------
+    E---F---G---H---I---J  topicA
+------------
+
+then the command
+
+    git rebase --onto topicA~5 topicA~3 topicA
+
+would result in the removal of commits F and G:
+
+------------
+    E---H'---I'---J'  topicA
+------------
+
+This is useful if F and G were flawed in some way, or should not be
+part of topicA.  Note that the argument to `--onto` and the `<upstream>`
+parameter can be any valid commit-ish.
+
+In case of conflict, `git rebase` will stop at the first problematic commit
+and leave conflict markers in the tree.  You can use `git diff` to locate
+the markers (<<<<<<) and make edits to resolve the conflict.  For each
+file you edit, you need to tell Git that the conflict has been resolved,
+typically this would be done with
+
+
+    git add <filename>
+
+
+After resolving the conflict manually and updating the index with the
+desired resolution, you can continue the rebasing process with
+
+
+    git rebase --continue
+
+
+Alternatively, you can undo the 'git rebase' with
+
+
+    git rebase --abort
+
+MODE OPTIONS
+------------
+
+The options in this section cannot be used with any other option,
+including not with each other:
+
+--continue::
+	Restart the rebasing process after having resolved a merge conflict.
+
+--skip::
+	Restart the rebasing process by skipping the current patch.
+
+--abort::
+	Abort the rebase operation and reset HEAD to the original
+	branch. If `<branch>` was provided when the rebase operation was
+	started, then `HEAD` will be reset to `<branch>`. Otherwise `HEAD`
+	will be reset to where it was when the rebase operation was
+	started.
+
+--quit::
+	Abort the rebase operation but `HEAD` is not reset back to the
+	original branch. The index and working tree are also left
+	unchanged as a result. If a temporary stash entry was created
+	using `--autostash`, it will be saved to the stash list.
+
+--edit-todo::
+	Edit the todo list during an interactive rebase.
+
+--show-current-patch::
+	Show the current patch in an interactive rebase or when rebase
+	is stopped because of conflicts. This is the equivalent of
+	`git show REBASE_HEAD`.
+
+OPTIONS
+-------
+--onto <newbase>::
+	Starting point at which to create the new commits. If the
+	`--onto` option is not specified, the starting point is
+	`<upstream>`.  May be any valid commit, and not just an
+	existing branch name.
++
+As a special case, you may use "A\...B" as a shortcut for the
+merge base of A and B if there is exactly one merge base. You can
+leave out at most one of A and B, in which case it defaults to HEAD.
+
+--keep-base::
+	Set the starting point at which to create the new commits to the
+	merge base of `<upstream>` and `<branch>`. Running
+	`git rebase --keep-base <upstream> <branch>` is equivalent to
+	running
+	`git rebase --reapply-cherry-picks --no-fork-point --onto <upstream>...<branch> <upstream> <branch>`.
++
+This option is useful in the case where one is developing a feature on
+top of an upstream branch. While the feature is being worked on, the
+upstream branch may advance and it may not be the best idea to keep
+rebasing on top of the upstream but to keep the base commit as-is. As
+the base commit is unchanged this option implies `--reapply-cherry-picks`
+to avoid losing commits.
++
+Although both this option and `--fork-point` find the merge base between
+`<upstream>` and `<branch>`, this option uses the merge base as the _starting
+point_ on which new commits will be created, whereas `--fork-point` uses
+the merge base to determine the _set of commits_ which will be rebased.
++
+See also INCOMPATIBLE OPTIONS below.
+
+<upstream>::
+	Upstream branch to compare against.  May be any valid commit,
+	not just an existing branch name. Defaults to the configured
+	upstream for the current branch.
+
+<branch>::
+	Working branch; defaults to `HEAD`.
+
+--apply::
+	Use applying strategies to rebase (calling `git-am`
+	internally).  This option may become a no-op in the future
+	once the merge backend handles everything the apply one does.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--empty=(drop|keep|stop)::
+	How to handle commits that are not empty to start and are not
+	clean cherry-picks of any upstream commit, but which become
+	empty after rebasing (because they contain a subset of already
+	upstream changes):
++
+--
+`drop`;;
+	The commit will be dropped. This is the default behavior.
+`keep`;;
+	The commit will be kept. This option is implied when `--exec` is
+	specified unless `-i`/`--interactive` is also specified.
+`stop`;;
+`ask`;;
+	The rebase will halt when the commit is applied, allowing you to
+	choose whether to drop it, edit files more, or just commit the empty
+	changes. This option is implied when `-i`/`--interactive` is
+	specified. `ask` is a deprecated synonym of `stop`.
+--
++
+Note that commits which start empty are kept (unless `--no-keep-empty`
+is specified), and commits which are clean cherry-picks (as determined
+by `git log --cherry-mark ...`) are detected and dropped as a
+preliminary step (unless `--reapply-cherry-picks` or `--keep-base` is
+passed).
++
+See also INCOMPATIBLE OPTIONS below.
+
+--no-keep-empty::
+--keep-empty::
+	Do not keep commits that start empty before the rebase
+	(i.e. that do not change anything from its parent) in the
+	result.  The default is to keep commits which start empty,
+	since creating such commits requires passing the `--allow-empty`
+	override flag to `git commit`, signifying that a user is very
+	intentionally creating such a commit and thus wants to keep
+	it.
++
+Usage of this flag will probably be rare, since you can get rid of
+commits that start empty by just firing up an interactive rebase and
+removing the lines corresponding to the commits you don't want.  This
+flag exists as a convenient shortcut, such as for cases where external
+tools generate many empty commits and you want them all removed.
++
+For commits which do not start empty but become empty after rebasing,
+see the `--empty` flag.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--reapply-cherry-picks::
+--no-reapply-cherry-picks::
+	Reapply all clean cherry-picks of any upstream commit instead
+	of preemptively dropping them. (If these commits then become
+	empty after rebasing, because they contain a subset of already
+	upstream changes, the behavior towards them is controlled by
+	the `--empty` flag.)
++
+In the absence of `--keep-base` (or if `--no-reapply-cherry-picks` is
+given), these commits will be automatically dropped.  Because this
+necessitates reading all upstream commits, this can be expensive in
+repositories with a large number of upstream commits that need to be
+read. When using the 'merge' backend, warnings will be issued for each
+dropped commit (unless `--quiet` is given). Advice will also be issued
+unless `advice.skippedCherryPicks` is set to false (see
+linkgit:git-config[1]).
++
+`--reapply-cherry-picks` allows rebase to forgo reading all upstream
+commits, potentially improving performance.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--allow-empty-message::
+	No-op.  Rebasing commits with an empty message used to fail
+	and this option would override that behavior, allowing commits
+	with empty messages to be rebased.  Now commits with an empty
+	message do not cause rebasing to halt.
++
+See also INCOMPATIBLE OPTIONS below.
+
+-m::
+--merge::
+	Using merging strategies to rebase (default).
++
+Note that a rebase merge works by replaying each commit from the working
+branch on top of the `<upstream>` branch.  Because of this, when a merge
+conflict happens, the side reported as 'ours' is the so-far rebased
+series, starting with `<upstream>`, and 'theirs' is the working branch.
+In other words, the sides are swapped.
++
+See also INCOMPATIBLE OPTIONS below.
+
+-s <strategy>::
+--strategy=<strategy>::
+	Use the given merge strategy, instead of the default `ort`.
+	This implies `--merge`.
++
+Because `git rebase` replays each commit from the working branch
+on top of the `<upstream>` branch using the given strategy, using
+the `ours` strategy simply empties all patches from the `<branch>`,
+which makes little sense.
++
+See also INCOMPATIBLE OPTIONS below.
+
+-X <strategy-option>::
+--strategy-option=<strategy-option>::
+	Pass the <strategy-option> through to the merge strategy.
+	This implies `--merge` and, if no strategy has been
+	specified, `-s ort`.  Note the reversal of 'ours' and
+	'theirs' as noted above for the `-m` option.
++
+See also INCOMPATIBLE OPTIONS below.
+
+include::rerere-options.adoc[]
+
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+--no-gpg-sign::
+	GPG-sign commits. The `keyid` argument is optional and
+	defaults to the committer identity; if specified, it must be
+	stuck to the option without a space. `--no-gpg-sign` is useful to
+	countermand both `commit.gpgSign` configuration variable, and
+	earlier `--gpg-sign`.
+
+-q::
+--quiet::
+	Be quiet. Implies `--no-stat`.
+
+-v::
+--verbose::
+	Be verbose. Implies `--stat`.
+
+--stat::
+	Show a diffstat of what changed upstream since the last rebase. The
+	diffstat is also controlled by the configuration option rebase.stat.
+
+-n::
+--no-stat::
+	Do not show a diffstat as part of the rebase process.
+
+--no-verify::
+	This option bypasses the pre-rebase hook.  See also linkgit:githooks[5].
+
+--verify::
+	Allows the pre-rebase hook to run, which is the default.  This option can
+	be used to override `--no-verify`.  See also linkgit:githooks[5].
+
+-C<n>::
+	Ensure at least `<n>` lines of surrounding context match before
+	and after each change.  When fewer lines of surrounding
+	context exist they all must match.  By default no context is
+	ever ignored.  Implies `--apply`.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--no-ff::
+--force-rebase::
+-f::
+	Individually replay all rebased commits instead of fast-forwarding
+	over the unchanged ones.  This ensures that the entire history of
+	the rebased branch is composed of new commits.
++
+You may find this helpful after reverting a topic branch merge, as this option
+recreates the topic branch with fresh commits so it can be remerged
+successfully without needing to "revert the reversion" (see the
+link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for
+details).
+
+--fork-point::
+--no-fork-point::
+	Use reflog to find a better common ancestor between `<upstream>`
+	and `<branch>` when calculating which commits have been
+	introduced by `<branch>`.
++
+When `--fork-point` is active, 'fork_point' will be used instead of
+`<upstream>` to calculate the set of commits to rebase, where
+'fork_point' is the result of `git merge-base --fork-point <upstream>
+<branch>` command (see linkgit:git-merge-base[1]).  If 'fork_point'
+ends up being empty, the `<upstream>` will be used as a fallback.
++
+If `<upstream>` or `--keep-base` is given on the command line, then
+the default is `--no-fork-point`, otherwise the default is
+`--fork-point`. See also `rebase.forkpoint` in linkgit:git-config[1].
++
+If your branch was based on `<upstream>` but `<upstream>` was rewound and
+your branch contains commits which were dropped, this option can be used
+with `--keep-base` in order to drop those commits from your branch.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--ignore-whitespace::
+	Ignore whitespace differences when trying to reconcile
+	differences. Currently, each backend implements an approximation of
+	this behavior:
++
+apply backend;;
+	When applying a patch, ignore changes in whitespace in context
+	lines. Unfortunately, this means that if the "old" lines being
+	replaced by the patch differ only in whitespace from the existing
+	file, you will get a merge conflict instead of a successful patch
+	application.
++
+merge backend;;
+	Treat lines with only whitespace changes as unchanged when merging.
+	Unfortunately, this means that any patch hunks that were intended
+	to modify whitespace and nothing else will be dropped, even if the
+	other side had no changes that conflicted.
+
+--whitespace=<option>::
+	This flag is passed to the `git apply` program
+	(see linkgit:git-apply[1]) that applies the patch.
+	Implies `--apply`.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--committer-date-is-author-date::
+	Instead of using the current time as the committer date, use
+	the author date of the commit being rebased as the committer
+	date. This option implies `--force-rebase`.
+
+--ignore-date::
+--reset-author-date::
+	Instead of using the author date of the original commit, use
+	the current time as the	author date of the rebased commit.  This
+	option implies `--force-rebase`.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--signoff::
+	Add a `Signed-off-by` trailer to all the rebased commits. Note
+	that if `--interactive` is given then only commits marked to be
+	picked, edited or reworded will have the trailer added.
++
+See also INCOMPATIBLE OPTIONS below.
+
+-i::
+--interactive::
+	Make a list of the commits which are about to be rebased.  Let the
+	user edit that list before rebasing.  This mode can also be used to
+	split commits (see SPLITTING COMMITS below).
++
+The commit list format can be changed by setting the configuration option
+rebase.instructionFormat.  A customized instruction format will automatically
+have the commit hash prepended to the format.
++
+See also INCOMPATIBLE OPTIONS below.
+
+-r::
+--rebase-merges[=(rebase-cousins|no-rebase-cousins)]::
+--no-rebase-merges::
+	By default, a rebase will simply drop merge commits from the todo
+	list, and put the rebased commits into a single, linear branch.
+	With `--rebase-merges`, the rebase will instead try to preserve
+	the branching structure within the commits that are to be rebased,
+	by recreating the merge commits. Any resolved merge conflicts or
+	manual amendments in these merge commits will have to be
+	resolved/re-applied manually. `--no-rebase-merges` can be used to
+	countermand both the `rebase.rebaseMerges` config option and a previous
+	`--rebase-merges`.
++
+When rebasing merges, there are two modes: `rebase-cousins` and
+`no-rebase-cousins`. If the mode is not specified, it defaults to
+`no-rebase-cousins`. In `no-rebase-cousins` mode, commits which do not have
+`<upstream>` as direct ancestor will keep their original branch point, i.e.
+commits that would be excluded by linkgit:git-log[1]'s `--ancestry-path`
+option will keep their original ancestry by default. In `rebase-cousins` mode,
+such commits are instead rebased onto `<upstream>` (or `<onto>`, if
+specified).
++
+It is currently only possible to recreate the merge commits using the
+`ort` merge strategy; different merge strategies can be used only via
+explicit `exec git merge -s <strategy> [...]` commands.
++
+See also REBASING MERGES and INCOMPATIBLE OPTIONS below.
+
+-x <cmd>::
+--exec <cmd>::
+	Append "exec <cmd>" after each line creating a commit in the
+	final history. `<cmd>` will be interpreted as one or more shell
+	commands. Any command that fails will interrupt the rebase,
+	with exit code 1.
++
+You may execute several commands by either using one instance of `--exec`
+with several commands:
++
+	git rebase -i --exec "cmd1 && cmd2 && ..."
++
+or by giving more than one `--exec`:
++
+	git rebase -i --exec "cmd1" --exec "cmd2" --exec ...
++
+If `--autosquash` is used, `exec` lines will not be appended for
+the intermediate commits, and will only appear at the end of each
+squash/fixup series.
++
+This uses the `--interactive` machinery internally, but it can be run
+without an explicit `--interactive`.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--root::
+	Rebase all commits reachable from `<branch>`, instead of
+	limiting them with an `<upstream>`.  This allows you to rebase
+	the root commit(s) on a branch.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--autosquash::
+--no-autosquash::
+	Automatically squash commits with specially formatted messages into
+	previous commits being rebased.  If a commit message starts with
+	"squash! ", "fixup! " or "amend! ", the remainder of the subject line
+	is taken as a commit specifier, which matches a previous commit if it
+	matches the subject line or the hash of that commit.  If no commit
+	matches fully, matches of the specifier with the start of commit
+	subjects are considered.
++
+In the rebase todo list, the actions of squash, fixup and amend commits are
+changed from `pick` to `squash`, `fixup` or `fixup -C`, respectively, and they
+are moved right after the commit they modify.  The `--interactive` option can
+be used to review and edit the todo list before proceeding.
++
+The recommended way to create commits with squash markers is by using the
+`--squash`, `--fixup`, `--fixup=amend:` or `--fixup=reword:` options of
+linkgit:git-commit[1], which take the target commit as an argument and
+automatically fill in the subject line of the new commit from that.
++
+Setting configuration variable `rebase.autoSquash` to true enables
+auto-squashing by default for interactive rebase.  The `--no-autosquash`
+option can be used to override that setting.
++
+See also INCOMPATIBLE OPTIONS below.
+
+--autostash::
+--no-autostash::
+	Automatically create a temporary stash entry before the operation
+	begins, and apply it after the operation ends.  This means
+	that you can run rebase on a dirty worktree.  However, use
+	with care: the final stash application after a successful
+	rebase might result in non-trivial conflicts.
+
+--reschedule-failed-exec::
+--no-reschedule-failed-exec::
+	Automatically reschedule `exec` commands that failed. This only makes
+	sense in interactive mode (or when an `--exec` option was provided).
++
+This option applies once a rebase is started. It is preserved for the whole
+rebase based on, in order, the command line option provided to the initial `git
+rebase`, the `rebase.rescheduleFailedExec` configuration (see
+linkgit:git-config[1] or "CONFIGURATION" below), or it defaults to false.
++
+Recording this option for the whole rebase is a convenience feature. Otherwise
+an explicit `--no-reschedule-failed-exec` at the start would be overridden by
+the presence of a `rebase.rescheduleFailedExec=true` configuration when `git
+rebase --continue` is invoked. Currently, you cannot pass
+`--[no-]reschedule-failed-exec` to `git rebase --continue`.
+
+--update-refs::
+--no-update-refs::
+	Automatically force-update any branches that point to commits that
+	are being rebased. Any branches that are checked out in a worktree
+	are not updated in this way.
++
+If the configuration variable `rebase.updateRefs` is set, then this option
+can be used to override and disable this setting.
++
+See also INCOMPATIBLE OPTIONS below.
+
+INCOMPATIBLE OPTIONS
+--------------------
+
+The following options:
+
+ * --apply
+ * --whitespace
+ * -C
+
+are incompatible with the following options:
+
+ * --merge
+ * --strategy
+ * --strategy-option
+ * --autosquash
+ * --rebase-merges
+ * --interactive
+ * --exec
+ * --no-keep-empty
+ * --empty=
+ * --[no-]reapply-cherry-picks when used without --keep-base
+ * --update-refs
+ * --root when used without --onto
+
+In addition, the following pairs of options are incompatible:
+
+ * --keep-base and --onto
+ * --keep-base and --root
+ * --fork-point and --root
+
+BEHAVIORAL DIFFERENCES
+-----------------------
+
+`git rebase` has two primary backends: 'apply' and 'merge'.  (The 'apply'
+backend used to be known as the 'am' backend, but the name led to
+confusion as it looks like a verb instead of a noun.  Also, the 'merge'
+backend used to be known as the interactive backend, but it is now
+used for non-interactive cases as well.  Both were renamed based on
+lower-level functionality that underpinned each.) There are some
+subtle differences in how these two backends behave:
+
+Empty commits
+~~~~~~~~~~~~~
+
+The 'apply' backend unfortunately drops intentionally empty commits, i.e.
+commits that started empty, though these are rare in practice.  It
+also drops commits that become empty and has no option for controlling
+this behavior.
+
+The 'merge' backend keeps intentionally empty commits by default (though
+with `-i` they are marked as empty in the todo list editor, or they can
+be dropped automatically with `--no-keep-empty`).
+
+Similar to the apply backend, by default the merge backend drops
+commits that become empty unless `-i`/`--interactive` is specified (in
+which case it stops and asks the user what to do).  The merge backend
+also has an `--empty=(drop|keep|stop)` option for changing the behavior
+of handling commits that become empty.
+
+Directory rename detection
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Due to the lack of accurate tree information (arising from
+constructing fake ancestors with the limited information available in
+patches), directory rename detection is disabled in the 'apply' backend.
+Disabled directory rename detection means that if one side of history
+renames a directory and the other adds new files to the old directory,
+then the new files will be left behind in the old directory without
+any warning at the time of rebasing that you may want to move these
+files into the new directory.
+
+Directory rename detection works with the 'merge' backend to provide you
+warnings in such cases.
+
+Context
+~~~~~~~
+
+The 'apply' backend works by creating a sequence of patches (by calling
+`format-patch` internally), and then applying the patches in sequence
+(calling `am` internally).  Patches are composed of multiple hunks,
+each with line numbers, a context region, and the actual changes.  The
+line numbers have to be taken with some offset, since the other side
+will likely have inserted or deleted lines earlier in the file.  The
+context region is meant to help find how to adjust the line numbers in
+order to apply the changes to the right lines.  However, if multiple
+areas of the code have the same surrounding lines of context, the
+wrong one can be picked.  There are real-world cases where this has
+caused commits to be reapplied incorrectly with no conflicts reported.
+Setting `diff.context` to a larger value may prevent such types of
+problems, but increases the chance of spurious conflicts (since it
+will require more lines of matching context to apply).
+
+The 'merge' backend works with a full copy of each relevant file,
+insulating it from these types of problems.
+
+Labelling of conflicts markers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When there are content conflicts, the merge machinery tries to
+annotate each side's conflict markers with the commits where the
+content came from.  Since the 'apply' backend drops the original
+information about the rebased commits and their parents (and instead
+generates new fake commits based off limited information in the
+generated patches), those commits cannot be identified; instead it has
+to fall back to a commit summary.  Also, when `merge.conflictStyle` is
+set to `diff3` or `zdiff3`, the 'apply' backend will use "constructed merge
+base" to label the content from the merge base, and thus provide no
+information about the merge base commit whatsoever.
+
+The 'merge' backend works with the full commits on both sides of history
+and thus has no such limitations.
+
+Hooks
+~~~~~
+
+The 'apply' backend has not traditionally called the post-commit hook,
+while the 'merge' backend has.  Both have called the post-checkout hook,
+though the 'merge' backend has squelched its output.  Further, both
+backends only call the post-checkout hook with the starting point
+commit of the rebase, not the intermediate commits nor the final
+commit.  In each case, the calling of these hooks was by accident of
+implementation rather than by design (both backends were originally
+implemented as shell scripts and happened to invoke other commands
+like `git checkout` or `git commit` that would call the hooks).  Both
+backends should have the same behavior, though it is not entirely
+clear which, if any, is correct.  We will likely make rebase stop
+calling either of these hooks in the future.
+
+Interruptability
+~~~~~~~~~~~~~~~~
+
+The 'apply' backend has safety problems with an ill-timed interrupt; if
+the user presses Ctrl-C at the wrong time to try to abort the rebase,
+the rebase can enter a state where it cannot be aborted with a
+subsequent `git rebase --abort`.  The 'merge' backend does not appear to
+suffer from the same shortcoming.  (See
+https://lore.kernel.org/git/20200207132152.GC2868@xxxxxxxxxx/ for
+details.)
+
+Commit Rewording
+~~~~~~~~~~~~~~~~
+
+When a conflict occurs while rebasing, rebase stops and asks the user
+to resolve.  Since the user may need to make notable changes while
+resolving conflicts, after conflicts are resolved and the user has run
+`git rebase --continue`, the rebase should open an editor and ask the
+user to update the commit message.  The 'merge' backend does this, while
+the 'apply' backend blindly applies the original commit message.
+
+Miscellaneous differences
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are a few more behavioral differences that most folks would
+probably consider inconsequential but which are mentioned for
+completeness:
+
+* Reflog: The two backends will use different wording when describing
+  the changes made in the reflog, though both will make use of the
+  word "rebase".
+
+* Progress, informational, and error messages: The two backends
+  provide slightly different progress and informational messages.
+  Also, the apply backend writes error messages (such as "Your files
+  would be overwritten...") to stdout, while the merge backend writes
+  them to stderr.
+
+* State directories: The two backends keep their state in different
+  directories under `.git/`
+
+include::merge-strategies.adoc[]
+
+NOTES
+-----
+
+You should understand the implications of using `git rebase` on a
+repository that you share.  See also RECOVERING FROM UPSTREAM REBASE
+below.
+
+When the rebase is run, it will first execute a `pre-rebase` hook if one
+exists.  You can use this hook to do sanity checks and reject the rebase
+if it isn't appropriate.  Please see the template `pre-rebase` hook script
+for an example.
+
+Upon completion, `<branch>` will be the current branch.
+
+INTERACTIVE MODE
+----------------
+
+Rebasing interactively means that you have a chance to edit the commits
+which are rebased.  You can reorder the commits, and you can
+remove them (weeding out bad or otherwise unwanted patches).
+
+The interactive mode is meant for this type of workflow:
+
+1. have a wonderful idea
+2. hack on the code
+3. prepare a series for submission
+4. submit
+
+where point 2. consists of several instances of
+
+a) regular use
+
+ 1. finish something worthy of a commit
+ 2. commit
+
+b) independent fixup
+
+ 1. realize that something does not work
+ 2. fix that
+ 3. commit it
+
+Sometimes the thing fixed in b.2. cannot be amended to the not-quite
+perfect commit it fixes, because that commit is buried deeply in a
+patch series.  That is exactly what interactive rebase is for: use it
+after plenty of "a"s and "b"s, by rearranging and editing
+commits, and squashing multiple commits into one.
+
+Start it with the last commit you want to retain as-is:
+
+	git rebase -i <after-this-commit>
+
+An editor will be fired up with all the commits in your current branch
+(ignoring merge commits), which come after the given commit.  You can
+reorder the commits in this list to your heart's content, and you can
+remove them.  The list looks more or less like this:
+
+-------------------------------------------
+pick deadbee The oneline of this commit
+pick fa1afe1 The oneline of the next commit
+...
+-------------------------------------------
+
+The oneline descriptions are purely for your pleasure; 'git rebase' will
+not look at them but at the commit names ("deadbee" and "fa1afe1" in this
+example), so do not delete or edit the names.
+
+By replacing the command "pick" with the command "edit", you can tell
+`git rebase` to stop after applying that commit, so that you can edit
+the files and/or the commit message, amend the commit, and continue
+rebasing.
+
+To interrupt the rebase (just like an "edit" command would do, but without
+cherry-picking any commit first), use the "break" command.
+
+If you just want to edit the commit message for a commit, replace the
+command "pick" with the command "reword".
+
+To drop a commit, replace the command "pick" with "drop", or just
+delete the matching line.
+
+If you want to fold two or more commits into one, replace the command
+"pick" for the second and subsequent commits with "squash" or "fixup".
+If the commits had different authors, the folded commit will be
+attributed to the author of the first commit.  The suggested commit
+message for the folded commit is the concatenation of the first
+commit's message with those identified by "squash" commands, omitting the
+messages of commits identified by "fixup" commands, unless "fixup -c"
+is used.  In that case the suggested commit message is only the message
+of the "fixup -c" commit, and an editor is opened allowing you to edit
+the message.  The contents (patch) of the "fixup -c" commit are still
+incorporated into the folded commit. If there is more than one "fixup -c"
+commit, the message from the final one is used.  You can also use
+"fixup -C" to get the same behavior as "fixup -c" except without opening
+an editor.
+
+`git rebase` will stop when "pick" has been replaced with "edit" or
+when a command fails due to merge errors. When you are done editing
+and/or resolving conflicts you can continue with `git rebase --continue`.
+
+For example, if you want to reorder the last 5 commits, such that what
+was `HEAD~4` becomes the new `HEAD`. To achieve that, you would call
+`git rebase` like this:
+
+----------------------
+$ git rebase -i HEAD~5
+----------------------
+
+And move the first patch to the end of the list.
+
+You might want to recreate merge commits, e.g. if you have a history
+like this:
+
+------------------
+           X
+            \
+         A---M---B
+        /
+---o---O---P---Q
+------------------
+
+Suppose you want to rebase the side branch starting at "A" to "Q". Make
+sure that the current `HEAD` is "B", and call
+
+-----------------------------
+$ git rebase -i -r --onto Q O
+-----------------------------
+
+Reordering and editing commits usually creates untested intermediate
+steps.  You may want to check that your history editing did not break
+anything by running a test, or at least recompiling at intermediate
+points in history by using the "exec" command (shortcut "x").  You may
+do so by creating a todo list like this one:
+
+-------------------------------------------
+pick deadbee Implement feature XXX
+fixup f1a5c00 Fix to feature XXX
+exec make
+pick c0ffeee The oneline of the next commit
+edit deadbab The oneline of the commit after
+exec cd subdir; make test
+...
+-------------------------------------------
+
+The interactive rebase will stop when a command fails (i.e. exits with
+non-0 status) to give you an opportunity to fix the problem. You can
+continue with `git rebase --continue`.
+
+The "exec" command launches the command in a shell (the default one, usually
+/bin/sh), so you can use shell features (like "cd", ">", ";" ...). The command
+is run from the root of the working tree.
+
+----------------------------------
+$ git rebase -i --exec "make test"
+----------------------------------
+
+This command lets you check that intermediate commits are compilable.
+The todo list becomes like that:
+
+--------------------
+pick 5928aea one
+exec make test
+pick 04d0fda two
+exec make test
+pick ba46169 three
+exec make test
+pick f4593f9 four
+exec make test
+--------------------
+
+SPLITTING COMMITS
+-----------------
+
+In interactive mode, you can mark commits with the action "edit".  However,
+this does not necessarily mean that `git rebase` expects the result of this
+edit to be exactly one commit.  Indeed, you can undo the commit, or you can
+add other commits.  This can be used to split a commit into two:
+
+- Start an interactive rebase with `git rebase -i <commit>^`, where
+  `<commit>` is the commit you want to split.  In fact, any commit range
+  will do, as long as it contains that commit.
+
+- Mark the commit you want to split with the action "edit".
+
+- When it comes to editing that commit, execute `git reset HEAD^`.  The
+  effect is that the `HEAD` is rewound by one, and the index follows suit.
+  However, the working tree stays the same.
+
+- Now add the changes to the index that you want to have in the first
+  commit.  You can use `git add` (possibly interactively) or
+  `git gui` (or both) to do that.
+
+- Commit the now-current index with whatever commit message is appropriate
+  now.
+
+- Repeat the last two steps until your working tree is clean.
+
+- Continue the rebase with `git rebase --continue`.
+
+If you are not absolutely sure that the intermediate revisions are
+consistent (they compile, pass the testsuite, etc.) you should use
+`git stash` to stash away the not-yet-committed changes
+after each commit, test, and amend the commit if fixes are necessary.
+
+
+RECOVERING FROM UPSTREAM REBASE
+-------------------------------
+
+Rebasing (or any other form of rewriting) a branch that others have
+based work on is a bad idea: anyone downstream of it is forced to
+manually fix their history.  This section explains how to do the fix
+from the downstream's point of view.  The real fix, however, would be
+to avoid rebasing the upstream in the first place.
+
+To illustrate, suppose you are in a situation where someone develops a
+'subsystem' branch, and you are working on a 'topic' that is dependent
+on this 'subsystem'.  You might end up with a history like the
+following:
+
+------------
+    o---o---o---o---o---o---o---o  master
+	 \
+	  o---o---o---o---o  subsystem
+			   \
+			    *---*---*  topic
+------------
+
+If 'subsystem' is rebased against 'master', the following happens:
+
+------------
+    o---o---o---o---o---o---o---o  master
+	 \			 \
+	  o---o---o---o---o	  o'--o'--o'--o'--o'  subsystem
+			   \
+			    *---*---*  topic
+------------
+
+If you now continue development as usual, and eventually merge 'topic'
+to 'subsystem', the commits from 'subsystem' will remain duplicated forever:
+
+------------
+    o---o---o---o---o---o---o---o  master
+	 \			 \
+	  o---o---o---o---o	  o'--o'--o'--o'--o'--M	 subsystem
+			   \			     /
+			    *---*---*-..........-*--*  topic
+------------
+
+Such duplicates are generally frowned upon because they clutter up
+history, making it harder to follow.  To clean things up, you need to
+transplant the commits on 'topic' to the new 'subsystem' tip, i.e.,
+rebase 'topic'.  This becomes a ripple effect: anyone downstream from
+'topic' is forced to rebase too, and so on!
+
+There are two kinds of fixes, discussed in the following subsections:
+
+Easy case: The changes are literally the same.::
+
+	This happens if the 'subsystem' rebase was a simple rebase and
+	had no conflicts.
+
+Hard case: The changes are not the same.::
+
+	This happens if the 'subsystem' rebase had conflicts, or used
+	`--interactive` to omit, edit, squash, or fixup commits; or
+	if the upstream used one of `commit --amend`, `reset`, or
+	a full history rewriting command like
+	https://github.com/newren/git-filter-repo[`filter-repo`].
+
+
+The easy case
+~~~~~~~~~~~~~
+
+Only works if the changes (patch IDs based on the diff contents) on
+'subsystem' are literally the same before and after the rebase
+'subsystem' did.
+
+In that case, the fix is easy because 'git rebase' knows to skip
+changes that are already present in the new upstream (unless
+`--reapply-cherry-picks` is given). So if you say
+(assuming you're on 'topic')
+------------
+    $ git rebase subsystem
+------------
+you will end up with the fixed history
+------------
+    o---o---o---o---o---o---o---o  master
+				 \
+				  o'--o'--o'--o'--o'  subsystem
+						   \
+						    *---*---*  topic
+------------
+
+
+The hard case
+~~~~~~~~~~~~~
+
+Things get more complicated if the 'subsystem' changes do not exactly
+correspond to the ones before the rebase.
+
+NOTE: While an "easy case recovery" sometimes appears to be successful
+      even in the hard case, it may have unintended consequences.  For
+      example, a commit that was removed via `git rebase
+      --interactive` will be **resurrected**!
+
+The idea is to manually tell `git rebase` "where the old 'subsystem'
+ended and your 'topic' began", that is, what the old merge base
+between them was.  You will have to find a way to name the last commit
+of the old 'subsystem', for example:
+
+* With the 'subsystem' reflog: after `git fetch`, the old tip of
+  'subsystem' is at `subsystem@{1}`.  Subsequent fetches will
+  increase the number.  (See linkgit:git-reflog[1].)
+
+* Relative to the tip of 'topic': knowing that your 'topic' has three
+  commits, the old tip of 'subsystem' must be `topic~3`.
+
+You can then transplant the old `subsystem..topic` to the new tip by
+saying (for the reflog case, and assuming you are on 'topic' already):
+------------
+    $ git rebase --onto subsystem subsystem@{1}
+------------
+
+The ripple effect of a "hard case" recovery is especially bad:
+'everyone' downstream from 'topic' will now have to perform a "hard
+case" recovery too!
+
+REBASING MERGES
+---------------
+
+The interactive rebase command was originally designed to handle
+individual patch series. As such, it makes sense to exclude merge
+commits from the todo list, as the developer may have merged the
+then-current `master` while working on the branch, only to rebase
+all the commits onto `master` eventually (skipping the merge
+commits).
+
+However, there are legitimate reasons why a developer may want to
+recreate merge commits: to keep the branch structure (or "commit
+topology") when working on multiple, inter-related branches.
+
+In the following example, the developer works on a topic branch that
+refactors the way buttons are defined, and on another topic branch
+that uses that refactoring to implement a "Report a bug" button. The
+output of `git log --graph --format=%s -5` may look like this:
+
+------------
+*   Merge branch 'report-a-bug'
+|\
+| * Add the feedback button
+* | Merge branch 'refactor-button'
+|\ \
+| |/
+| * Use the Button class for all buttons
+| * Extract a generic Button class from the DownloadButton one
+------------
+
+The developer might want to rebase those commits to a newer `master`
+while keeping the branch topology, for example when the first topic
+branch is expected to be integrated into `master` much earlier than the
+second one, say, to resolve merge conflicts with changes to the
+DownloadButton class that made it into `master`.
+
+This rebase can be performed using the `--rebase-merges` option.
+It will generate a todo list looking like this:
+
+------------
+label onto
+
+# Branch: refactor-button
+reset onto
+pick 123456 Extract a generic Button class from the DownloadButton one
+pick 654321 Use the Button class for all buttons
+label refactor-button
+
+# Branch: report-a-bug
+reset refactor-button # Use the Button class for all buttons
+pick abcdef Add the feedback button
+label report-a-bug
+
+reset onto
+merge -C a1b2c3 refactor-button # Merge 'refactor-button'
+merge -C 6f5e4d report-a-bug # Merge 'report-a-bug'
+------------
+
+In contrast to a regular interactive rebase, there are `label`, `reset`
+and `merge` commands in addition to `pick` ones.
+
+The `label` command associates a label with the current HEAD when that
+command is executed. These labels are created as worktree-local refs
+(`refs/rewritten/<label>`) that will be deleted when the rebase
+finishes. That way, rebase operations in multiple worktrees linked to
+the same repository do not interfere with one another. If the `label`
+command fails, it is rescheduled immediately, with a helpful message how
+to proceed.
+
+The `reset` command resets the HEAD, index and worktree to the specified
+revision. It is similar to an `exec git reset --hard <label>`, but
+refuses to overwrite untracked files. If the `reset` command fails, it is
+rescheduled immediately, with a helpful message how to edit the todo list
+(this typically happens when a `reset` command was inserted into the todo
+list manually and contains a typo).
+
+The `merge` command will merge the specified revision(s) into whatever
+is HEAD at that time. With `-C <original-commit>`, the commit message of
+the specified merge commit will be used. When the `-C` is changed to
+a lower-case `-c`, the message will be opened in an editor after a
+successful merge so that the user can edit the message.
+
+If a `merge` command fails for any reason other than merge conflicts (i.e.
+when the merge operation did not even start), it is rescheduled immediately.
+
+By default, the `merge` command will use the `ort` merge strategy for
+regular merges, and `octopus` for octopus merges.  One can specify a
+default strategy for all merges using the `--strategy` argument when
+invoking rebase, or can override specific merges in the interactive
+list of commands by using an `exec` command to call `git merge`
+explicitly with a `--strategy` argument.  Note that when calling `git
+merge` explicitly like this, you can make use of the fact that the
+labels are worktree-local refs (the ref `refs/rewritten/onto` would
+correspond to the label `onto`, for example) in order to refer to the
+branches you want to merge.
+
+Note: the first command (`label onto`) labels the revision onto which
+the commits are rebased; The name `onto` is just a convention, as a nod
+to the `--onto` option.
+
+It is also possible to introduce completely new merge commits from scratch
+by adding a command of the form `merge <merge-head>`. This form will
+generate a tentative commit message and always open an editor to let the
+user edit it. This can be useful e.g. when a topic branch turns out to
+address more than a single concern and wants to be split into two or
+even more topic branches. Consider this todo list:
+
+------------
+pick 192837 Switch from GNU Makefiles to CMake
+pick 5a6c7e Document the switch to CMake
+pick 918273 Fix detection of OpenSSL in CMake
+pick afbecd http: add support for TLS v1.3
+pick fdbaec Fix detection of cURL in CMake on Windows
+------------
+
+The one commit in this list that is not related to CMake may very well
+have been motivated by working on fixing all those bugs introduced by
+switching to CMake, but it addresses a different concern. To split this
+branch into two topic branches, the todo list could be edited like this:
+
+------------
+label onto
+
+pick afbecd http: add support for TLS v1.3
+label tlsv1.3
+
+reset onto
+pick 192837 Switch from GNU Makefiles to CMake
+pick 918273 Fix detection of OpenSSL in CMake
+pick fdbaec Fix detection of cURL in CMake on Windows
+pick 5a6c7e Document the switch to CMake
+label cmake
+
+reset onto
+merge tlsv1.3
+merge cmake
+------------
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/rebase.adoc[]
+include::config/sequencer.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-receive-pack.adoc b/Documentation/git-receive-pack.adoc
new file mode 100644
index 0000000000..20aca92073
--- /dev/null
+++ b/Documentation/git-receive-pack.adoc
@@ -0,0 +1,261 @@
+git-receive-pack(1)
+===================
+
+NAME
+----
+git-receive-pack - Receive what is pushed into the repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git receive-pack' <git-dir>
+
+DESCRIPTION
+-----------
+Invoked by 'git send-pack' and updates the repository with the
+information fed from the remote end.
+
+This command is usually not invoked directly by the end user.
+The UI for the protocol is on the 'git send-pack' side, and the
+program pair is meant to be used to push updates to a remote
+repository.  For pull operations, see linkgit:git-fetch-pack[1].
+
+The command allows for the creation and fast-forwarding of sha1 refs
+(heads/tags) on the remote end (strictly speaking, it is the
+local end 'git-receive-pack' runs, but to the user who is sitting at
+the send-pack end, it is updating the remote.  Confused?)
+
+There are other real-world examples of using update and
+post-update hooks found in the Documentation/howto directory.
+
+'git-receive-pack' honours the receive.denyNonFastForwards config
+option, which tells it if updates to a ref should be denied if they
+are not fast-forwards.
+
+A number of other receive.* config options are available to tweak
+its behavior, see linkgit:git-config[1].
+
+OPTIONS
+-------
+<git-dir>::
+	The repository to sync into.
+
+--http-backend-info-refs::
+	Used by linkgit:git-http-backend[1] to serve up
+	`$GIT_URL/info/refs?service=git-receive-pack` requests. See
+	`--http-backend-info-refs` in linkgit:git-upload-pack[1].
+
+PRE-RECEIVE HOOK
+----------------
+Before any ref is updated, if $GIT_DIR/hooks/pre-receive file exists
+and is executable, it will be invoked once with no parameters.  The
+standard input of the hook will be one line per ref to be updated:
+
+       sha1-old SP sha1-new SP refname LF
+
+The refname value is relative to $GIT_DIR; e.g. for the master
+head this is "refs/heads/master".  The two sha1 values before
+each refname are the object names for the refname before and after
+the update.  Refs to be created will have sha1-old equal to 0\{40},
+while refs to be deleted will have sha1-new equal to 0\{40}, otherwise
+sha1-old and sha1-new should be valid objects in the repository.
+
+When accepting a signed push (see linkgit:git-push[1]), the signed
+push certificate is stored in a blob and an environment variable
+`GIT_PUSH_CERT` can be consulted for its object name.  See the
+description of `post-receive` hook for an example.  In addition, the
+certificate is verified using GPG and the result is exported with
+the following environment variables:
+
+`GIT_PUSH_CERT_SIGNER`::
+	The name and the e-mail address of the owner of the key that
+	signed the push certificate.
+
+`GIT_PUSH_CERT_KEY`::
+	The GPG key ID of the key that signed the push certificate.
+
+`GIT_PUSH_CERT_STATUS`::
+	The status of GPG verification of the push certificate,
+	using the same mnemonic as used in `%G?` format of `git log`
+	family of commands (see linkgit:git-log[1]).
+
+`GIT_PUSH_CERT_NONCE`::
+	The nonce string the process asked the signer to include
+	in the push certificate.  If this does not match the value
+	recorded on the "nonce" header in the push certificate, it
+	may indicate that the certificate is a valid one that is
+	being replayed from a separate "git push" session.
+
+`GIT_PUSH_CERT_NONCE_STATUS`::
+`UNSOLICITED`;;
+	"git push --signed" sent a nonce when we did not ask it to
+	send one.
+`MISSING`;;
+	"git push --signed" did not send any nonce header.
+`BAD`;;
+	"git push --signed" sent a bogus nonce.
+`OK`;;
+	"git push --signed" sent the nonce we asked it to send.
+`SLOP`;;
+	"git push --signed" sent a nonce different from what we
+	asked it to send now, but in a previous session.  See
+	`GIT_PUSH_CERT_NONCE_SLOP` environment variable.
+
+`GIT_PUSH_CERT_NONCE_SLOP`::
+	"git push --signed" sent a nonce different from what we
+	asked it to send now, but in a different session whose
+	starting time is different by this many seconds from the
+	current session.  Only meaningful when
+	`GIT_PUSH_CERT_NONCE_STATUS` says `SLOP`.
+	Also read about `receive.certNonceSlop` variable in
+	linkgit:git-config[1].
+
+This hook is called before any refname is updated and before any
+fast-forward checks are performed.
+
+If the pre-receive hook exits with a non-zero exit status no updates
+will be performed, and the update, post-receive and post-update
+hooks will not be invoked either.  This can be useful to quickly
+bail out if the update is not to be supported.
+
+See the notes on the quarantine environment below.
+
+UPDATE HOOK
+-----------
+Before each ref is updated, if $GIT_DIR/hooks/update file exists
+and is executable, it is invoked once per ref, with three parameters:
+
+       $GIT_DIR/hooks/update refname sha1-old sha1-new
+
+The refname parameter is relative to $GIT_DIR; e.g. for the master
+head this is "refs/heads/master".  The two sha1 arguments are
+the object names for the refname before and after the update.
+Note that the hook is called before the refname is updated,
+so either sha1-old is 0\{40} (meaning there is no such ref yet),
+or it should match what is recorded in refname.
+
+The hook should exit with non-zero status if it wants to disallow
+updating the named ref.  Otherwise it should exit with zero.
+
+Successful execution (a zero exit status) of this hook does not
+ensure the ref will actually be updated, it is only a prerequisite.
+As such it is not a good idea to send notices (e.g. email) from
+this hook.  Consider using the post-receive hook instead.
+
+POST-RECEIVE HOOK
+-----------------
+After all refs were updated (or attempted to be updated), if any
+ref update was successful, and if $GIT_DIR/hooks/post-receive
+file exists and is executable, it will be invoked once with no
+parameters.  The standard input of the hook will be one line
+for each successfully updated ref:
+
+       sha1-old SP sha1-new SP refname LF
+
+The refname value is relative to $GIT_DIR; e.g. for the master
+head this is "refs/heads/master".  The two sha1 values before
+each refname are the object names for the refname before and after
+the update.  Refs that were created will have sha1-old equal to
+0\{40}, while refs that were deleted will have sha1-new equal to
+0\{40}, otherwise sha1-old and sha1-new should be valid objects in
+the repository.
+
+The `GIT_PUSH_CERT*` environment variables can be inspected, just as
+in `pre-receive` hook, after accepting a signed push.
+
+Using this hook, it is easy to generate mails describing the updates
+to the repository.  This example script sends one mail message per
+ref listing the commits pushed to the repository, and logs the push
+certificates of signed pushes with good signatures to a logger
+service:
+
+----
+#!/bin/sh
+# mail out commit update information.
+while read oval nval ref
+do
+	if expr "$oval" : '0*$' >/dev/null
+	then
+		echo "Created a new ref, with the following commits:"
+		git rev-list --pretty "$nval"
+	else
+		echo "New commits:"
+		git rev-list --pretty "$nval" "^$oval"
+	fi |
+	mail -s "Changes to ref $ref" commit-list@mydomain
+done
+# log signed push certificate, if any
+if test -n "${GIT_PUSH_CERT-}" && test ${GIT_PUSH_CERT_STATUS} = G
+then
+	(
+		echo expected nonce is ${GIT_PUSH_NONCE}
+		git cat-file blob ${GIT_PUSH_CERT}
+	) | mail -s "push certificate from $GIT_PUSH_CERT_SIGNER" push-log@mydomain
+fi
+exit 0
+----
+
+The exit code from this hook invocation is ignored, however a
+non-zero exit code will generate an error message.
+
+Note that it is possible for refname to not have sha1-new when this
+hook runs.  This can easily occur if another user modifies the ref
+after it was updated by 'git-receive-pack', but before the hook was able
+to evaluate it.  It is recommended that hooks rely on sha1-new
+rather than the current value of refname.
+
+POST-UPDATE HOOK
+----------------
+After all other processing, if at least one ref was updated, and
+if $GIT_DIR/hooks/post-update file exists and is executable, then
+post-update will be called with the list of refs that have been updated.
+This can be used to implement any repository wide cleanup tasks.
+
+The exit code from this hook invocation is ignored; the only thing
+left for 'git-receive-pack' to do at that point is to exit itself
+anyway.
+
+This hook can be used, for example, to run `git update-server-info`
+if the repository is packed and is served via a dumb transport.
+
+----
+#!/bin/sh
+exec git update-server-info
+----
+
+
+QUARANTINE ENVIRONMENT
+----------------------
+
+When `receive-pack` takes in objects, they are placed into a temporary
+"quarantine" directory within the `$GIT_DIR/objects` directory and
+migrated into the main object store only after the `pre-receive` hook
+has completed. If the push fails before then, the temporary directory is
+removed entirely.
+
+This has a few user-visible effects and caveats:
+
+  1. Pushes which fail due to problems with the incoming pack, missing
+     objects, or due to the `pre-receive` hook will not leave any
+     on-disk data. This is usually helpful to prevent repeated failed
+     pushes from filling up your disk, but can make debugging more
+     challenging.
+
+  2. Any objects created by the `pre-receive` hook will be created in
+     the quarantine directory (and migrated only if it succeeds).
+
+  3. The `pre-receive` hook MUST NOT update any refs to point to
+     quarantined objects. Other programs accessing the repository will
+     not be able to see the objects (and if the pre-receive hook fails,
+     those refs would become corrupted). For safety, any ref updates
+     from within `pre-receive` are automatically rejected.
+
+
+SEE ALSO
+--------
+linkgit:git-send-pack[1], linkgit:gitnamespaces[7]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-reflog.adoc b/Documentation/git-reflog.adoc
new file mode 100644
index 0000000000..a929c52982
--- /dev/null
+++ b/Documentation/git-reflog.adoc
@@ -0,0 +1,138 @@
+git-reflog(1)
+=============
+
+NAME
+----
+git-reflog - Manage reflog information
+
+
+SYNOPSIS
+--------
+[verse]
+'git reflog' [show] [<log-options>] [<ref>]
+'git reflog list'
+'git reflog expire' [--expire=<time>] [--expire-unreachable=<time>]
+	[--rewrite] [--updateref] [--stale-fix]
+	[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]
+'git reflog delete' [--rewrite] [--updateref]
+	[--dry-run | -n] [--verbose] <ref>@{<specifier>}...
+'git reflog exists' <ref>
+
+DESCRIPTION
+-----------
+This command manages the information recorded in the reflogs.
+
+Reference logs, or "reflogs", record when the tips of branches and
+other references were updated in the local repository. Reflogs are
+useful in various Git commands, to specify the old value of a
+reference. For example, `HEAD@{2}` means "where HEAD used to be two
+moves ago", `master@{one.week.ago}` means "where master used to point
+to one week ago in this local repository", and so on. See
+linkgit:gitrevisions[7] for more details.
+
+The command takes various subcommands, and different options
+depending on the subcommand:
+
+The "show" subcommand (which is also the default, in the absence of
+any subcommands) shows the log of the reference provided in the
+command-line (or `HEAD`, by default). The reflog covers all recent
+actions, and in addition the `HEAD` reflog records branch switching.
+`git reflog show` is an alias for `git log -g --abbrev-commit
+--pretty=oneline`; see linkgit:git-log[1] for more information.
+
+The "list" subcommand lists all refs which have a corresponding reflog.
+
+The "expire" subcommand prunes older reflog entries. Entries older
+than `expire` time, or entries older than `expire-unreachable` time
+and not reachable from the current tip, are removed from the reflog.
+This is typically not used directly by end users -- instead, see
+linkgit:git-gc[1].
+
+The "delete" subcommand deletes single entries from the reflog. Its
+argument must be an _exact_ entry (e.g. "`git reflog delete
+master@{2}`"). This subcommand is also typically not used directly by
+end users.
+
+The "exists" subcommand checks whether a ref has a reflog.  It exits
+with zero status if the reflog exists, and non-zero status if it does
+not.
+
+OPTIONS
+-------
+
+Options for `show`
+~~~~~~~~~~~~~~~~~~
+
+`git reflog show` accepts any of the options accepted by `git log`.
+
+
+Options for `expire`
+~~~~~~~~~~~~~~~~~~~~
+
+--all::
+	Process the reflogs of all references.
+
+--single-worktree::
+	By default when `--all` is specified, reflogs from all working
+	trees are processed. This option limits the processing to reflogs
+	from the current working tree only.
+
+--expire=<time>::
+	Prune entries older than the specified time. If this option is
+	not specified, the expiration time is taken from the
+	configuration setting `gc.reflogExpire`, which in turn
+	defaults to 90 days. `--expire=all` prunes entries regardless
+	of their age; `--expire=never` turns off pruning of reachable
+	entries (but see `--expire-unreachable`).
+
+--expire-unreachable=<time>::
+	Prune entries older than `<time>` that are not reachable from
+	the current tip of the branch. If this option is not
+	specified, the expiration time is taken from the configuration
+	setting `gc.reflogExpireUnreachable`, which in turn defaults
+	to 30 days. `--expire-unreachable=all` prunes unreachable
+	entries regardless of their age; `--expire-unreachable=never`
+	turns off early pruning of unreachable entries (but see
+	`--expire`).
+
+--updateref::
+	Update the reference to the value of the top reflog entry (i.e.
+	<ref>@\{0\}) if the previous top entry was pruned.  (This
+	option is ignored for symbolic references.)
+
+--rewrite::
+	If a reflog entry's predecessor is pruned, adjust its "old"
+	SHA-1 to be equal to the "new" SHA-1 field of the entry that
+	now precedes it.
+
+--stale-fix::
+	Prune any reflog entries that point to "broken commits". A
+	broken commit is a commit that is not reachable from any of
+	the reference tips and that refers, directly or indirectly, to
+	a missing commit, tree, or blob object.
++
+This computation involves traversing all the reachable objects, i.e. it
+has the same cost as 'git prune'.  It is primarily intended to fix
+corruption caused by garbage collecting using older versions of Git,
+which didn't protect objects referred to by reflogs.
+
+-n::
+--dry-run::
+	Do not actually prune any entries; just show what would have
+	been pruned.
+
+--verbose::
+	Print extra information on screen.
+
+
+Options for `delete`
+~~~~~~~~~~~~~~~~~~~~
+
+`git reflog delete` accepts options `--updateref`, `--rewrite`, `-n`,
+`--dry-run`, and `--verbose`, with the same meanings as when they are
+used with `expire`.
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc
new file mode 100644
index 0000000000..95f25776aa
--- /dev/null
+++ b/Documentation/git-refs.adoc
@@ -0,0 +1,72 @@
+git-refs(1)
+===========
+
+NAME
+----
+git-refs - Low-level access to refs
+
+
+SYNOPSIS
+--------
+[verse]
+'git refs migrate' --ref-format=<format> [--dry-run]
+'git refs verify' [--strict] [--verbose]
+
+DESCRIPTION
+-----------
+
+This command provides low-level access to refs.
+
+COMMANDS
+--------
+
+migrate::
+	Migrate ref store between different formats.
+
+verify::
+	Verify reference database consistency.
+
+OPTIONS
+-------
+
+The following options are specific to 'git refs migrate':
+
+--ref-format=<format>::
+	The ref format to migrate the ref store to. Can be one of:
++
+include::ref-storage-format.adoc[]
+
+--dry-run::
+	Perform the migration, but do not modify the repository. The migrated
+	refs will be written into a separate directory that can be inspected
+	separately. The name of the directory will be reported on stdout. This
+	can be used to double check that the migration works as expected before
+	performing the actual migration.
+
+The following options are specific to 'git refs verify':
+
+--strict::
+	Enable stricter error checking. This will cause warnings to be
+	reported as errors. See linkgit:git-fsck[1].
+
+--verbose::
+	When verifying the reference database consistency, be chatty.
+
+KNOWN LIMITATIONS
+-----------------
+
+The ref format migration has several known limitations in its current form:
+
+* It is not possible to migrate repositories that have worktrees.
+
+* There is no way to block concurrent writes to the repository during an
+  ongoing migration. Concurrent writes can lead to an inconsistent migrated
+  state. Users are expected to block writes on a higher level. If your
+  repository is registered for scheduled maintenance, it is recommended to
+  unregister it first with git-maintenance(1).
+
+These limitations may eventually be lifted.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-remote-ext.adoc b/Documentation/git-remote-ext.adoc
new file mode 100644
index 0000000000..b33ee3c9e8
--- /dev/null
+++ b/Documentation/git-remote-ext.adoc
@@ -0,0 +1,125 @@
+git-remote-ext(1)
+=================
+
+NAME
+----
+git-remote-ext - Bridge smart transport to external command.
+
+SYNOPSIS
+--------
+[verse]
+git remote add <nick> "ext::<command>[ <arguments>...]"
+
+DESCRIPTION
+-----------
+This remote helper uses the specified '<command>' to connect
+to a remote Git server.
+
+Data written to stdin of the specified '<command>' is assumed
+to be sent to a git:// server, git-upload-pack, git-receive-pack
+or git-upload-archive (depending on situation), and data read
+from stdout of <command> is assumed to be received from
+the same service.
+
+Command and arguments are separated by an unescaped space.
+
+The following sequences have a special meaning:
+
+'% '::
+	Literal space in command or argument.
+
+'%%'::
+	Literal percent sign.
+
+'%s'::
+	Replaced with name (receive-pack, upload-pack, or
+	upload-archive) of the service Git wants to invoke.
+
+'%S'::
+	Replaced with long name (git-receive-pack,
+	git-upload-pack, or git-upload-archive) of the service
+	Git wants to invoke.
+
+'%G' (must be the first characters in an argument)::
+	This argument will not be passed to '<command>'. Instead, it
+	will cause the helper to start by sending git:// service requests to
+	the remote side with the service field set to an appropriate value and
+	the repository field set to the rest of the argument. Default is not to send
+	such a request.
++
+This is useful if the remote side is git:// server accessed over
+some tunnel.
+
+'%V' (must be first characters in argument)::
+	This argument will not be passed to '<command>'. Instead it sets
+	the vhost field in the git:// service request (to the rest of the argument).
+	Default is not to send vhost in such request (if sent).
+
+ENVIRONMENT VARIABLES
+---------------------
+
+GIT_TRANSLOOP_DEBUG::
+	If set, prints debugging information about various reads/writes.
+
+ENVIRONMENT VARIABLES PASSED TO COMMAND
+---------------------------------------
+
+GIT_EXT_SERVICE::
+	Set to long name (git-upload-pack, etc...) of service helper needs
+	to invoke.
+
+GIT_EXT_SERVICE_NOPREFIX::
+	Set to long name (upload-pack, etc...) of service helper needs
+	to invoke.
+
+
+EXAMPLES
+--------
+This remote helper is transparently used by Git when
+you use commands such as "git fetch <URL>", "git clone <URL>",
+, "git push <URL>" or "git remote add <nick> <URL>", where <URL>
+begins with `ext::`.  Examples:
+
+"ext::ssh -i /home/foo/.ssh/somekey user&#64;host.example %S 'foo/repo'"::
+	Like host.example:foo/repo, but use /home/foo/.ssh/somekey as
+	keypair and user as the user on the remote side. This avoids the need to
+	edit .ssh/config.
+
+"ext::socat -t3600 - ABSTRACT-CONNECT:/git-server %G/somerepo"::
+	Represents repository with path /somerepo accessible over
+	git protocol at the abstract namespace address /git-server.
+
+"ext::git-server-alias foo %G/repo"::
+	Represents a repository with path /repo accessed using the
+	helper program "git-server-alias foo".  The path to the
+	repository and type of request are not passed on the command
+	line but as part of the protocol stream, as usual with git://
+	protocol.
+
+"ext::git-server-alias foo %G/repo %Vfoo"::
+	Represents a repository with path /repo accessed using the
+	helper program "git-server-alias foo".  The hostname for the
+	remote server passed in the protocol stream will be "foo"
+	(this allows multiple virtual Git servers to share a
+	link-level address).
+
+"ext::git-server-alias foo %G/repo% with% spaces %Vfoo"::
+	Represents a repository with path `/repo with spaces` accessed
+	using the helper program "git-server-alias foo".  The hostname for
+	the remote server passed in the protocol stream will be "foo"
+	(this allows multiple virtual Git servers to share a
+	link-level address).
+
+"ext::git-ssl foo.example /bar"::
+	Represents a repository accessed using the helper program
+	"git-ssl foo.example /bar".  The type of request can be
+	determined by the helper using environment variables (see
+	above).
+
+SEE ALSO
+--------
+linkgit:gitremote-helpers[7]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-remote-fd.adoc b/Documentation/git-remote-fd.adoc
new file mode 100644
index 0000000000..1dd2648a79
--- /dev/null
+++ b/Documentation/git-remote-fd.adoc
@@ -0,0 +1,59 @@
+git-remote-fd(1)
+================
+
+NAME
+----
+git-remote-fd - Reflect smart transport stream back to caller
+
+SYNOPSIS
+--------
+"fd::<infd>[,<outfd>][/<anything>]" (as URL)
+
+DESCRIPTION
+-----------
+This helper uses specified file descriptors to connect to a remote Git server.
+This is not meant for end users but for programs and scripts calling git
+fetch, push, or archive.
+
+If only <infd> is given, it is assumed to be a bidirectional socket connected
+to a remote Git server (git-upload-pack, git-receive-pack, or
+git-upload-archive). If both <infd> and <outfd> are given, they are assumed
+to be pipes connected to a remote Git server (<infd> being the inbound pipe
+and <outfd> being the outbound pipe).
+
+It is assumed that any handshaking procedures have already been completed
+(such as sending service request for git://) before this helper is started.
+
+<anything> can be any string. It is ignored. It is meant for providing
+information to the user in the URL in case that URL is displayed in some
+context.
+
+ENVIRONMENT VARIABLES
+---------------------
+GIT_TRANSLOOP_DEBUG::
+	If set, prints debugging information about various reads/writes.
+
+EXAMPLES
+--------
+`git fetch fd::17 master`::
+	Fetch master, using file descriptor #17 to communicate with
+	git-upload-pack.
+
+`git fetch fd::17/foo master`::
+	Same as above.
+
+`git push fd::7,8 master (as URL)`::
+	Push master, using file descriptor #7 to read data from
+	git-receive-pack and file descriptor #8 to write data to
+	the same service.
+
+`git push fd::7,8/bar master`::
+	Same as above.
+
+SEE ALSO
+--------
+linkgit:gitremote-helpers[7]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-remote-helpers.txto b/Documentation/git-remote-helpers.txto
new file mode 100644
index 0000000000..6f353ebfd3
--- /dev/null
+++ b/Documentation/git-remote-helpers.txto
@@ -0,0 +1,9 @@
+git-remote-helpers
+==================
+
+This document has been moved to linkgit:gitremote-helpers[7].
+
+Please let the owners of the referring site know so that they can update the
+link you clicked to get here.
+
+Thanks.
diff --git a/Documentation/git-remote.adoc b/Documentation/git-remote.adoc
new file mode 100644
index 0000000000..932a5c3ea4
--- /dev/null
+++ b/Documentation/git-remote.adoc
@@ -0,0 +1,269 @@
+git-remote(1)
+=============
+
+NAME
+----
+git-remote - Manage set of tracked repositories
+
+
+SYNOPSIS
+--------
+[verse]
+'git remote' [-v | --verbose]
+'git remote add' [-t <branch>] [-m <master>] [-f] [--[no-]tags] [--mirror=(fetch|push)] <name> <URL>
+'git remote rename' [--[no-]progress] <old> <new>
+'git remote remove' <name>
+'git remote set-head' <name> (-a | --auto | -d | --delete | <branch>)
+'git remote set-branches' [--add] <name> <branch>...
+'git remote get-url' [--push] [--all] <name>
+'git remote set-url' [--push] <name> <newurl> [<oldurl>]
+'git remote set-url --add' [--push] <name> <newurl>
+'git remote set-url --delete' [--push] <name> <URL>
+'git remote' [-v | --verbose] 'show' [-n] <name>...
+'git remote prune' [-n | --dry-run] <name>...
+'git remote' [-v | --verbose] 'update' [-p | --prune] [(<group> | <remote>)...]
+
+DESCRIPTION
+-----------
+
+Manage the set of repositories ("remotes") whose branches you track.
+
+
+OPTIONS
+-------
+
+-v::
+--verbose::
+	Be a little more verbose and show remote url after name.
+	For promisor remotes, also show which filters (`blob:none` etc.)
+	are configured.
+	NOTE: This must be placed between `remote` and subcommand.
+
+
+COMMANDS
+--------
+
+With no arguments, shows a list of existing remotes.  Several
+subcommands are available to perform operations on the remotes.
+
+'add'::
+
+Add a remote named <name> for the repository at
+<URL>.  The command `git fetch <name>` can then be used to create and
+update remote-tracking branches <name>/<branch>.
++
+With `-f` option, `git fetch <name>` is run immediately after
+the remote information is set up.
++
+With `--tags` option, `git fetch <name>` imports every tag from the
+remote repository.
++
+With `--no-tags` option, `git fetch <name>` does not import tags from
+the remote repository.
++
+By default, only tags on fetched branches are imported
+(see linkgit:git-fetch[1]).
++
+With `-t <branch>` option, instead of the default glob
+refspec for the remote to track all branches under
+the `refs/remotes/<name>/` namespace, a refspec to track only `<branch>`
+is created.  You can give more than one `-t <branch>` to track
+multiple branches without grabbing all branches.
++
+With `-m <master>` option, a symbolic-ref `refs/remotes/<name>/HEAD` is set
+up to point at remote's `<master>` branch. See also the set-head command.
++
+When a fetch mirror is created with `--mirror=fetch`, the refs will not
+be stored in the 'refs/remotes/' namespace, but rather everything in
+'refs/' on the remote will be directly mirrored into 'refs/' in the
+local repository. This option only makes sense in bare repositories,
+because a fetch would overwrite any local commits.
++
+When a push mirror is created with `--mirror=push`, then `git push`
+will always behave as if `--mirror` was passed.
+
+'rename'::
+
+Rename the remote named <old> to <new>. All remote-tracking branches and
+configuration settings for the remote are updated.
++
+In case <old> and <new> are the same, and <old> is a file under
+`$GIT_DIR/remotes` or `$GIT_DIR/branches`, the remote is converted to
+the configuration file format.
+
+'remove'::
+'rm'::
+
+Remove the remote named <name>. All remote-tracking branches and
+configuration settings for the remote are removed.
+
+'set-head'::
+
+Sets or deletes the default branch (i.e. the target of the
+symbolic-ref `refs/remotes/<name>/HEAD`) for
+the named remote. Having a default branch for a remote is not required,
+but allows the name of the remote to be specified in lieu of a specific
+branch. For example, if the default branch for `origin` is set to
+`master`, then `origin` may be specified wherever you would normally
+specify `origin/master`.
++
+With `-d` or `--delete`, the symbolic ref `refs/remotes/<name>/HEAD` is deleted.
++
+With `-a` or `--auto`, the remote is queried to determine its `HEAD`, then the
+symbolic-ref `refs/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote
+`HEAD` is pointed at `next`, `git remote set-head origin -a` will set
+the symbolic-ref `refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will
+only work if `refs/remotes/origin/next` already exists; if not it must be
+fetched first.
++
+Use `<branch>` to set the symbolic-ref `refs/remotes/<name>/HEAD` explicitly. e.g., `git
+remote set-head origin master` will set the symbolic-ref `refs/remotes/origin/HEAD` to
+`refs/remotes/origin/master`. This will only work if
+`refs/remotes/origin/master` already exists; if not it must be fetched first.
++
+
+'set-branches'::
+
+Changes the list of branches tracked by the named remote.
+This can be used to track a subset of the available remote branches
+after the initial setup for a remote.
++
+The named branches will be interpreted as if specified with the
+`-t` option on the `git remote add` command line.
++
+With `--add`, instead of replacing the list of currently tracked
+branches, adds to that list.
+
+'get-url'::
+
+Retrieves the URLs for a remote. Configurations for `insteadOf` and
+`pushInsteadOf` are expanded here. By default, only the first URL is listed.
++
+With `--push`, push URLs are queried rather than fetch URLs.
++
+With `--all`, all URLs for the remote will be listed.
+
+'set-url'::
+
+Changes URLs for the remote. Sets first URL for remote <name> that matches
+regex <oldurl> (first URL if no <oldurl> is given) to <newurl>. If
+<oldurl> doesn't match any URL, an error occurs and nothing is changed.
++
+With `--push`, push URLs are manipulated instead of fetch URLs.
++
+With `--add`, instead of changing existing URLs, new URL is added.
++
+With `--delete`, instead of changing existing URLs, all URLs matching
+regex <URL> are deleted for remote <name>.  Trying to delete all
+non-push URLs is an error.
++
+Note that the push URL and the fetch URL, even though they can
+be set differently, must still refer to the same place.  What you
+pushed to the push URL should be what you would see if you
+immediately fetched from the fetch URL.  If you are trying to
+fetch from one place (e.g. your upstream) and push to another (e.g.
+your publishing repository), use two separate remotes.
+
+
+'show'::
+
+Gives some information about the remote <name>.
++
+With `-n` option, the remote heads are not queried first with
+`git ls-remote <name>`; cached information is used instead.
+
+'prune'::
+
+Deletes stale references associated with <name>. By default, stale
+remote-tracking branches under <name> are deleted, but depending on
+global configuration and the configuration of the remote we might even
+prune local tags that haven't been pushed there. Equivalent to `git
+fetch --prune <name>`, except that no new references will be fetched.
++
+See the PRUNING section of linkgit:git-fetch[1] for what it'll prune
+depending on various configuration.
++
+With `--dry-run` option, report what branches would be pruned, but do not
+actually prune them.
+
+'update'::
+
+Fetch updates for remotes or remote groups in the repository as defined by
+`remotes.<group>`. If neither group nor remote is specified on the command line,
+the configuration parameter remotes.default will be used; if
+remotes.default is not defined, all remotes which do not have the
+configuration parameter `remote.<name>.skipDefaultUpdate` set to true will
+be updated.  (See linkgit:git-config[1]).
++
+With `--prune` option, run pruning against all the remotes that are updated.
+
+
+DISCUSSION
+----------
+
+The remote configuration is achieved using the `remote.origin.url` and
+`remote.origin.fetch` configuration variables.  (See
+linkgit:git-config[1]).
+
+EXIT STATUS
+-----------
+
+On success, the exit status is `0`.
+
+When subcommands such as 'add', 'rename', and 'remove' can't find the
+remote in question, the exit status is `2`. When the remote already
+exists, the exit status is `3`.
+
+On any other error, the exit status may be any other non-zero value.
+
+EXAMPLES
+--------
+
+* Add a new remote, fetch, and check out a branch from it
++
+------------
+$ git remote
+origin
+$ git branch -r
+  origin/HEAD -> origin/master
+  origin/master
+$ git remote add staging git://git.kernel.org/.../gregkh/staging.git
+$ git remote
+origin
+staging
+$ git fetch staging
+...
+From git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
+ * [new branch]      master     -> staging/master
+ * [new branch]      staging-linus -> staging/staging-linus
+ * [new branch]      staging-next -> staging/staging-next
+$ git branch -r
+  origin/HEAD -> origin/master
+  origin/master
+  staging/master
+  staging/staging-linus
+  staging/staging-next
+$ git switch -c staging staging/master
+...
+------------
+
+* Imitate 'git clone' but track only selected branches
++
+------------
+$ mkdir project.git
+$ cd project.git
+$ git init
+$ git remote add -f -t master -m master origin git://example.com/git.git/
+$ git merge origin
+------------
+
+
+SEE ALSO
+--------
+linkgit:git-fetch[1]
+linkgit:git-branch[1]
+linkgit:git-config[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-repack.adoc b/Documentation/git-repack.adoc
new file mode 100644
index 0000000000..c902512a9e
--- /dev/null
+++ b/Documentation/git-repack.adoc
@@ -0,0 +1,279 @@
+git-repack(1)
+=============
+
+NAME
+----
+git-repack - Pack unpacked objects in a repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git repack' [-a] [-A] [-d] [-f] [-F] [-l] [-n] [-q] [-b] [-m] [--window=<n>] [--depth=<n>] [--threads=<n>] [--keep-pack=<pack-name>] [--write-midx]
+
+DESCRIPTION
+-----------
+
+This command is used to combine all objects that do not currently
+reside in a "pack", into a pack.  It can also be used to re-organize
+existing packs into a single, more efficient pack.
+
+A pack is a collection of objects, individually compressed, with
+delta compression applied, stored in a single file, with an
+associated index file.
+
+Packs are used to reduce the load on mirror systems, backup
+engines, disk storage, etc.
+
+OPTIONS
+-------
+
+-a::
+	Instead of incrementally packing the unpacked objects,
+	pack everything referenced into a single pack.
+	Especially useful when packing a repository that is used
+	for private development. Use
+	with `-d`.  This will clean up the objects that `git prune`
+	leaves behind, but `git fsck --full --dangling` shows as
+	dangling.
++
+Note that users fetching over dumb protocols will have to fetch the
+whole new pack in order to get any contained object, no matter how many
+other objects in that pack they already have locally.
++
+Promisor packfiles are repacked separately: if there are packfiles that
+have an associated ".promisor" file, these packfiles will be repacked
+into another separate pack, and an empty ".promisor" file corresponding
+to the new separate pack will be written.
+
+-A::
+	Same as `-a`, unless `-d` is used.  Then any unreachable
+	objects in a previous pack become loose, unpacked objects,
+	instead of being left in the old pack.  Unreachable objects
+	are never intentionally added to a pack, even when repacking.
+	This option prevents unreachable objects from being immediately
+	deleted by way of being left in the old pack and then
+	removed.  Instead, the loose unreachable objects
+	will be pruned according to normal expiry rules
+	with the next 'git gc' invocation. See linkgit:git-gc[1].
+
+-d::
+	After packing, if the newly created packs make some
+	existing packs redundant, remove the redundant packs.
+	Also run  'git prune-packed' to remove redundant
+	loose object files.
+
+--cruft::
+	Same as `-a`, unless `-d` is used. Then any unreachable objects
+	are packed into a separate cruft pack. Unreachable objects can
+	be pruned using the normal expiry rules with the next `git gc`
+	invocation (see linkgit:git-gc[1]). Incompatible with `-k`.
+
+--cruft-expiration=<approxidate>::
+	Expire unreachable objects older than `<approxidate>`
+	immediately instead of waiting for the next `git gc` invocation.
+	Only useful with `--cruft -d`.
+
+--max-cruft-size=<n>::
+	Repack cruft objects into packs as large as `<n>` bytes before
+	creating new packs. As long as there are enough cruft packs
+	smaller than `<n>`, repacking will cause a new cruft pack to
+	be created containing objects from any combined cruft packs,
+	along with any new unreachable objects. Cruft packs larger than
+	`<n>` will not be modified. When the new cruft pack is larger
+	than `<n>` bytes, it will be split into multiple packs, all of
+	which are guaranteed to be at most `<n>` bytes in size. Only
+	useful with `--cruft -d`.
+
+--expire-to=<dir>::
+	Write a cruft pack containing pruned objects (if any) to the
+	directory `<dir>`. This option is useful for keeping a copy of
+	any pruned objects in a separate directory as a backup. Only
+	useful with `--cruft -d`.
+
+-l::
+	Pass the `--local` option to 'git pack-objects'. See
+	linkgit:git-pack-objects[1].
+
+-f::
+	Pass the `--no-reuse-delta` option to `git-pack-objects`, see
+	linkgit:git-pack-objects[1].
+
+-F::
+	Pass the `--no-reuse-object` option to `git-pack-objects`, see
+	linkgit:git-pack-objects[1].
+
+-q::
+--quiet::
+	Show no progress over the standard error stream and pass the `-q`
+	option to 'git pack-objects'. See linkgit:git-pack-objects[1].
+
+-n::
+	Do not update the server information with
+	'git update-server-info'.  This option skips
+	updating local catalog files needed to publish
+	this repository (or a direct copy of it)
+	over HTTP or FTP.  See linkgit:git-update-server-info[1].
+
+--window=<n>::
+--depth=<n>::
+	These two options affect how the objects contained in the pack are
+	stored using delta compression. The objects are first internally
+	sorted by type, size and optionally names and compared against the
+	other objects within `--window` to see if using delta compression saves
+	space. `--depth` limits the maximum delta depth; making it too deep
+	affects the performance on the unpacker side, because delta data needs
+	to be applied that many times to get to the necessary object.
++
+The default value for --window is 10 and --depth is 50. The maximum
+depth is 4095.
+
+--threads=<n>::
+	This option is passed through to `git pack-objects`.
+
+--window-memory=<n>::
+	This option provides an additional limit on top of `--window`;
+	the window size will dynamically scale down so as to not take
+	up more than '<n>' bytes in memory.  This is useful in
+	repositories with a mix of large and small objects to not run
+	out of memory with a large window, but still be able to take
+	advantage of the large window for the smaller objects.  The
+	size can be suffixed with "k", "m", or "g".
+	`--window-memory=0` makes memory usage unlimited.  The default
+	is taken from the `pack.windowMemory` configuration variable.
+	Note that the actual memory usage will be the limit multiplied
+	by the number of threads used by linkgit:git-pack-objects[1].
+
+--max-pack-size=<n>::
+	Maximum size of each output pack file. The size can be suffixed with
+	"k", "m", or "g". The minimum size allowed is limited to 1 MiB.
+	If specified, multiple packfiles may be created, which also
+	prevents the creation of a bitmap index.
+	The default is unlimited, unless the config variable
+	`pack.packSizeLimit` is set. Note that this option may result in
+	a larger and slower repository; see the discussion in
+	`pack.packSizeLimit`.
+
+--filter=<filter-spec>::
+	Remove objects matching the filter specification from the
+	resulting packfile and put them into a separate packfile. Note
+	that objects used in the working directory are not filtered
+	out. So for the split to fully work, it's best to perform it
+	in a bare repo and to use the `-a` and `-d` options along with
+	this option.  Also `--no-write-bitmap-index` (or the
+	`repack.writebitmaps` config option set to `false`) should be
+	used otherwise writing bitmap index will fail, as it supposes
+	a single packfile containing all the objects. See
+	linkgit:git-rev-list[1] for valid `<filter-spec>` forms.
+
+--filter-to=<dir>::
+	Write the pack containing filtered out objects to the
+	directory `<dir>`. Only useful with `--filter`. This can be
+	used for putting the pack on a separate object directory that
+	is accessed through the Git alternates mechanism. **WARNING:**
+	If the packfile containing the filtered out objects is not
+	accessible, the repo can become corrupt as it might not be
+	possible to access the objects in that packfile. See the
+	`objects` and `objects/info/alternates` sections of
+	linkgit:gitrepository-layout[5].
+
+-b::
+--write-bitmap-index::
+	Write a reachability bitmap index as part of the repack. This
+	only makes sense when used with `-a`, `-A` or `-m`, as the bitmaps
+	must be able to refer to all reachable objects. This option
+	overrides the setting of `repack.writeBitmaps`. This option
+	has no effect if multiple packfiles are created, unless writing a
+	MIDX (in which case a multi-pack bitmap is created).
+
+--pack-kept-objects::
+	Include objects in `.keep` files when repacking.  Note that we
+	still do not delete `.keep` packs after `pack-objects` finishes.
+	This means that we may duplicate objects, but this makes the
+	option safe to use when there are concurrent pushes or fetches.
+	This option is generally only useful if you are writing bitmaps
+	with `-b` or `repack.writeBitmaps`, as it ensures that the
+	bitmapped packfile has the necessary objects.
+
+--keep-pack=<pack-name>::
+	Exclude the given pack from repacking. This is the equivalent
+	of having `.keep` file on the pack. `<pack-name>` is the
+	pack file name without leading directory (e.g. `pack-123.pack`).
+	The option can be specified multiple times to keep multiple
+	packs.
+
+--unpack-unreachable=<when>::
+	When loosening unreachable objects, do not bother loosening any
+	objects older than `<when>`. This can be used to optimize out
+	the write of any objects that would be immediately pruned by
+	a follow-up `git prune`.
+
+-k::
+--keep-unreachable::
+	When used with `-ad`, any unreachable objects from existing
+	packs will be appended to the end of the packfile instead of
+	being removed. In addition, any unreachable loose objects will
+	be packed (and their loose counterparts removed).
+
+-i::
+--delta-islands::
+	Pass the `--delta-islands` option to `git-pack-objects`, see
+	linkgit:git-pack-objects[1].
+
+-g<factor>::
+--geometric=<factor>::
+	Arrange resulting pack structure so that each successive pack
+	contains at least `<factor>` times the number of objects as the
+	next-largest pack.
++
+`git repack` ensures this by determining a "cut" of packfiles that need
+to be repacked into one in order to ensure a geometric progression. It
+picks the smallest set of packfiles such that as many of the larger
+packfiles (by count of objects contained in that pack) may be left
+intact.
++
+Unlike other repack modes, the set of objects to pack is determined
+uniquely by the set of packs being "rolled-up"; in other words, the
+packs determined to need to be combined in order to restore a geometric
+progression.
++
+Loose objects are implicitly included in this "roll-up", without respect to
+their reachability. This is subject to change in the future.
++
+When writing a multi-pack bitmap, `git repack` selects the largest resulting
+pack as the preferred pack for object selection by the MIDX (see
+linkgit:git-multi-pack-index[1]).
+
+-m::
+--write-midx::
+	Write a multi-pack index (see linkgit:git-multi-pack-index[1])
+	containing the non-redundant packs.
+
+CONFIGURATION
+-------------
+
+Various configuration variables affect packing, see
+linkgit:git-config[1] (search for "pack" and "delta").
+
+By default, the command passes `--delta-base-offset` option to
+'git pack-objects'; this typically results in slightly smaller packs,
+but the generated packs are incompatible with versions of Git older than
+version 1.4.4. If you need to share your repository with such ancient Git
+versions, either directly or via the dumb http protocol, then you
+need to set the configuration variable `repack.UseDeltaBaseOffset` to
+"false" and repack. Access from old Git versions over the native protocol
+is unaffected by this option as the conversion is performed on the fly
+as needed in that case.
+
+Delta compression is not used on objects larger than the
+`core.bigFileThreshold` configuration variable and on files with the
+attribute `delta` set to false.
+
+SEE ALSO
+--------
+linkgit:git-pack-objects[1]
+linkgit:git-prune-packed[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-replace.adoc b/Documentation/git-replace.adoc
new file mode 100644
index 0000000000..0a65460adb
--- /dev/null
+++ b/Documentation/git-replace.adoc
@@ -0,0 +1,161 @@
+git-replace(1)
+==============
+
+NAME
+----
+git-replace - Create, list, delete refs to replace objects
+
+SYNOPSIS
+--------
+[verse]
+'git replace' [-f] <object> <replacement>
+'git replace' [-f] --edit <object>
+'git replace' [-f] --graft <commit> [<parent>...]
+'git replace' [-f] --convert-graft-file
+'git replace' -d <object>...
+'git replace' [--format=<format>] [-l [<pattern>]]
+
+DESCRIPTION
+-----------
+Adds a 'replace' reference in `refs/replace/` namespace.
+
+The name of the 'replace' reference is the SHA-1 of the object that is
+replaced. The content of the 'replace' reference is the SHA-1 of the
+replacement object.
+
+The replaced object and the replacement object must be of the same type.
+This restriction can be bypassed using `-f`.
+
+Unless `-f` is given, the 'replace' reference must not yet exist.
+
+There is no other restriction on the replaced and replacement objects.
+Merge commits can be replaced by non-merge commits and vice versa.
+
+Replacement references will be used by default by all Git commands
+except those doing reachability traversal (prune, pack transfer and
+fsck).
+
+It is possible to disable the use of replacement references for any
+command using the `--no-replace-objects` option just after 'git'.
+
+For example if commit 'foo' has been replaced by commit 'bar':
+
+------------------------------------------------
+$ git --no-replace-objects cat-file commit foo
+------------------------------------------------
+
+shows information about commit 'foo', while:
+
+------------------------------------------------
+$ git cat-file commit foo
+------------------------------------------------
+
+shows information about commit 'bar'.
+
+The `GIT_NO_REPLACE_OBJECTS` environment variable can be set to
+achieve the same effect as the `--no-replace-objects` option.
+
+OPTIONS
+-------
+-f::
+--force::
+	If an existing replace ref for the same object exists, it will
+	be overwritten (instead of failing).
+
+-d::
+--delete::
+	Delete existing replace refs for the given objects.
+
+--edit <object>::
+	Edit an object's content interactively. The existing content
+	for <object> is pretty-printed into a temporary file, an
+	editor is launched on the file, and the result is parsed to
+	create a new object of the same type as <object>. A
+	replacement ref is then created to replace <object> with the
+	newly created object. See linkgit:git-var[1] for details about
+	how the editor will be chosen.
+
+--raw::
+	When editing, provide the raw object contents rather than
+	pretty-printed ones. Currently this only affects trees, which
+	will be shown in their binary form. This is harder to work with,
+	but can help when repairing a tree that is so corrupted it
+	cannot be pretty-printed. Note that you may need to configure
+	your editor to cleanly read and write binary data.
+
+--graft <commit> [<parent>...]::
+	Create a graft commit. A new commit is created with the same
+	content as <commit> except that its parents will be
+	[<parent>...] instead of <commit>'s parents. A replacement ref
+	is then created to replace <commit> with the newly created
+	commit. Use `--convert-graft-file` to convert a
+	`$GIT_DIR/info/grafts` file and use replace refs instead.
+
+--convert-graft-file::
+	Creates graft commits for all entries in `$GIT_DIR/info/grafts`
+	and deletes that file upon success. The purpose is to help users
+	with transitioning off of the now-deprecated graft file.
+
+-l <pattern>::
+--list <pattern>::
+	List replace refs for objects that match the given pattern (or
+	all if no pattern is given).
+	Typing "git replace" without arguments, also lists all replace
+	refs.
+
+--format=<format>::
+	When listing, use the specified <format>, which can be one of
+	'short', 'medium' and 'long'. When omitted, the format
+	defaults to 'short'.
+
+FORMATS
+-------
+
+The following formats are available:
+
+* 'short':
+	<replaced-sha1>
+* 'medium':
+	<replaced-sha1> -> <replacement-sha1>
+* 'long':
+	<replaced-sha1> (<replaced-type>) -> <replacement-sha1> (<replacement-type>)
+
+CREATING REPLACEMENT OBJECTS
+----------------------------
+
+linkgit:git-hash-object[1], linkgit:git-rebase[1], and
+https://github.com/newren/git-filter-repo[git-filter-repo], among other git commands, can be used to
+create replacement objects from existing objects. The `--edit` option
+can also be used with 'git replace' to create a replacement object by
+editing an existing object.
+
+If you want to replace many blobs, trees or commits that are part of a
+string of commits, you may just want to create a replacement string of
+commits and then only replace the commit at the tip of the target
+string of commits with the commit at the tip of the replacement string
+of commits.
+
+BUGS
+----
+Comparing blobs or trees that have been replaced with those that
+replace them will not work properly. And using `git reset --hard` to
+go back to a replaced commit will move the branch to the replacement
+commit instead of the replaced commit.
+
+There may be other problems when using 'git rev-list' related to
+pending objects.
+
+SEE ALSO
+--------
+linkgit:git-hash-object[1]
+linkgit:git-rebase[1]
+linkgit:git-tag[1]
+linkgit:git-branch[1]
+linkgit:git-commit[1]
+linkgit:git-var[1]
+linkgit:git[1]
+https://github.com/newren/git-filter-repo[git-filter-repo]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-replay.adoc b/Documentation/git-replay.adoc
new file mode 100644
index 0000000000..0b12bf8aa4
--- /dev/null
+++ b/Documentation/git-replay.adoc
@@ -0,0 +1,127 @@
+git-replay(1)
+=============
+
+NAME
+----
+git-replay - EXPERIMENTAL: Replay commits on a new base, works with bare repos too
+
+
+SYNOPSIS
+--------
+[verse]
+(EXPERIMENTAL!) 'git replay' ([--contained] --onto <newbase> | --advance <branch>) <revision-range>...
+
+DESCRIPTION
+-----------
+
+Takes ranges of commits and replays them onto a new location. Leaves
+the working tree and the index untouched, and updates no references.
+The output of this command is meant to be used as input to
+`git update-ref --stdin`, which would update the relevant branches
+(see the OUTPUT section below).
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+OPTIONS
+-------
+
+--onto <newbase>::
+	Starting point at which to create the new commits.  May be any
+	valid commit, and not just an existing branch name.
++
+When `--onto` is specified, the update-ref command(s) in the output will
+update the branch(es) in the revision range to point at the new
+commits, similar to the way how `git rebase --update-refs` updates
+multiple branches in the affected range.
+
+--advance <branch>::
+	Starting point at which to create the new commits; must be a
+	branch name.
++
+When `--advance` is specified, the update-ref command(s) in the output
+will update the branch passed as an argument to `--advance` to point at
+the new commits (in other words, this mimics a cherry-pick operation).
+
+<revision-range>::
+	Range of commits to replay. More than one <revision-range> can
+	be passed, but in `--advance <branch>` mode, they should have
+	a single tip, so that it's clear where <branch> should point
+	to. See "Specifying Ranges" in linkgit:git-rev-parse[1] and the
+	"Commit Limiting" options below.
+
+include::rev-list-options.adoc[]
+
+OUTPUT
+------
+
+When there are no conflicts, the output of this command is usable as
+input to `git update-ref --stdin`.  It is of the form:
+
+	update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
+	update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
+	update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}
+
+where the number of refs updated depends on the arguments passed and
+the shape of the history being replayed.  When using `--advance`, the
+number of refs updated is always one, but for `--onto`, it can be one
+or more (rebasing multiple branches simultaneously is supported).
+
+EXIT STATUS
+-----------
+
+For a successful, non-conflicted replay, the exit status is 0.  When
+the replay has conflicts, the exit status is 1.  If the replay is not
+able to complete (or start) due to some kind of error, the exit status
+is something other than 0 or 1.
+
+EXAMPLES
+--------
+
+To simply rebase `mybranch` onto `target`:
+
+------------
+$ git replay --onto target origin/main..mybranch
+update refs/heads/mybranch ${NEW_mybranch_HASH} ${OLD_mybranch_HASH}
+------------
+
+To cherry-pick the commits from mybranch onto target:
+
+------------
+$ git replay --advance target origin/main..mybranch
+update refs/heads/target ${NEW_target_HASH} ${OLD_target_HASH}
+------------
+
+Note that the first two examples replay the exact same commits and on
+top of the exact same new base, they only differ in that the first
+provides instructions to make mybranch point at the new commits and
+the second provides instructions to make target point at them.
+
+What if you have a stack of branches, one depending upon another, and
+you'd really like to rebase the whole set?
+
+------------
+$ git replay --contained --onto origin/main origin/main..tipbranch
+update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
+update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
+update refs/heads/tipbranch ${NEW_tipbranch_HASH} ${OLD_tipbranch_HASH}
+------------
+
+When calling `git replay`, one does not need to specify a range of
+commits to replay using the syntax `A..B`; any range expression will
+do:
+
+------------
+$ git replay --onto origin/main ^base branch1 branch2 branch3
+update refs/heads/branch1 ${NEW_branch1_HASH} ${OLD_branch1_HASH}
+update refs/heads/branch2 ${NEW_branch2_HASH} ${OLD_branch2_HASH}
+update refs/heads/branch3 ${NEW_branch3_HASH} ${OLD_branch3_HASH}
+------------
+
+This will simultaneously rebase `branch1`, `branch2`, and `branch3`,
+all commits they have since `base`, playing them on top of
+`origin/main`. These three branches may have commits on top of `base`
+that they have in common, but that does not need to be the case.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-request-pull.adoc b/Documentation/git-request-pull.adoc
new file mode 100644
index 0000000000..15dcbb6d91
--- /dev/null
+++ b/Documentation/git-request-pull.adoc
@@ -0,0 +1,79 @@
+git-request-pull(1)
+===================
+
+NAME
+----
+git-request-pull - Generates a summary of pending changes
+
+SYNOPSIS
+--------
+[verse]
+'git request-pull' [-p] <start> <URL> [<end>]
+
+DESCRIPTION
+-----------
+
+Generate a request asking your upstream project to pull changes into
+their tree.  The request, printed to the standard output,
+begins with the branch description, summarizes
+the changes, and indicates from where they can be pulled.
+
+The upstream project is expected to have the commit named by
+`<start>` and the output asks it to integrate the changes you made
+since that commit, up to the commit named by `<end>`, by visiting
+the repository named by `<URL>`.
+
+
+OPTIONS
+-------
+-p::
+	Include patch text in the output.
+
+<start>::
+	Commit to start at.  This names a commit that is already in
+	the upstream history.
+
+<URL>::
+	The repository URL to be pulled from.
+
+<end>::
+	Commit to end at (defaults to HEAD).  This names the commit
+	at the tip of the history you are asking to be pulled.
++
+When the repository named by `<URL>` has the commit at a tip of a
+ref that is different from the ref you have locally, you can use the
+`<local>:<remote>` syntax, to have its local name, a colon `:`, and
+its remote name.
+
+
+EXAMPLES
+--------
+
+Imagine that you built your work on your `master` branch on top of
+the `v1.0` release, and want it to be integrated into the project.
+First you push that change to your public repository for others to
+see:
+
+	git push https://git.ko.xz/project master
+
+Then, you run this command:
+
+	git request-pull v1.0 https://git.ko.xz/project master
+
+which will produce a request to the upstream, summarizing the
+changes between the `v1.0` release and your `master`, to pull it
+from your public repository.
+
+If you pushed your change to a branch whose name is different from
+the one you have locally, e.g.
+
+	git push https://git.ko.xz/project master:for-linus
+
+then you can ask that to be pulled with
+
+	git request-pull v1.0 https://git.ko.xz/project master:for-linus
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rerere.adoc b/Documentation/git-rerere.adoc
new file mode 100644
index 0000000000..992b469270
--- /dev/null
+++ b/Documentation/git-rerere.adoc
@@ -0,0 +1,222 @@
+git-rerere(1)
+=============
+
+NAME
+----
+git-rerere - Reuse recorded resolution of conflicted merges
+
+SYNOPSIS
+--------
+[verse]
+'git rerere' [clear | forget <pathspec>... | diff | status | remaining | gc]
+
+DESCRIPTION
+-----------
+
+In a workflow employing relatively long lived topic branches,
+the developer sometimes needs to resolve the same conflicts over
+and over again until the topic branches are done (either merged
+to the "release" branch, or sent out and accepted upstream).
+
+This command assists the developer in this process by recording
+conflicted automerge results and corresponding hand resolve results
+on the initial manual merge, and applying previously recorded
+hand resolutions to their corresponding automerge results.
+
+[NOTE]
+You need to set the configuration variable `rerere.enabled` in order to
+enable this command.
+
+
+COMMANDS
+--------
+
+Normally, 'git rerere' is run without arguments or user-intervention.
+However, it has several commands that allow it to interact with
+its working state.
+
+'clear'::
+
+Reset the metadata used by rerere if a merge resolution is to be
+aborted.  Calling 'git am [--skip|--abort]' or 'git rebase [--skip|--abort]'
+will automatically invoke this command.
+
+'forget' <pathspec>::
+
+Reset the conflict resolutions which rerere has recorded for the current
+conflict in <pathspec>.
+
+'diff'::
+
+Display diffs for the current state of the resolution.  It is
+useful for tracking what has changed while the user is resolving
+conflicts.  Additional arguments are passed directly to the system
+'diff' command installed in PATH.
+
+'status'::
+
+Print paths with conflicts whose merge resolution rerere will record.
+
+'remaining'::
+
+Print paths with conflicts that have not been autoresolved by rerere.
+This includes paths whose resolutions cannot be tracked by rerere,
+such as conflicting submodules.
+
+'gc'::
+
+Prune records of conflicted merges that
+occurred a long time ago.  By default, unresolved conflicts older
+than 15 days and resolved conflicts older than 60
+days are pruned.  These defaults are controlled via the
+`gc.rerereUnresolved` and `gc.rerereResolved` configuration
+variables respectively.
+
+
+DISCUSSION
+----------
+
+When your topic branch modifies an overlapping area that your
+master branch (or upstream) touched since your topic branch
+forked from it, you may want to test it with the latest master,
+even before your topic branch is ready to be pushed upstream:
+
+------------
+              o---*---o topic
+             /
+    o---o---o---*---o---o master
+------------
+
+For such a test, you need to merge master and topic somehow.
+One way to do it is to pull master into the topic branch:
+
+------------
+	$ git switch topic
+	$ git merge master
+
+              o---*---o---+ topic
+             /           /
+    o---o---o---*---o---o master
+------------
+
+The commits marked with `*` touch the same area in the same
+file; you need to resolve the conflicts when creating the commit
+marked with `+`.  Then you can test the result to make sure your
+work-in-progress still works with what is in the latest master.
+
+After this test merge, there are two ways to continue your work
+on the topic.  The easiest is to build on top of the test merge
+commit `+`, and when your work in the topic branch is finally
+ready, pull the topic branch into master, and/or ask the
+upstream to pull from you.  By that time, however, the master or
+the upstream might have been advanced since the test merge `+`,
+in which case the final commit graph would look like this:
+
+------------
+	$ git switch topic
+	$ git merge master
+	$ ... work on both topic and master branches
+	$ git switch master
+	$ git merge topic
+
+              o---*---o---+---o---o topic
+             /           /         \
+    o---o---o---*---o---o---o---o---+ master
+------------
+
+When your topic branch is long-lived, however, your topic branch
+would end up having many such "Merge from master" commits on it,
+which would unnecessarily clutter the development history.
+Readers of the Linux kernel mailing list may remember that Linus
+complained about such too frequent test merges when a subsystem
+maintainer asked to pull from a branch full of "useless merges".
+
+As an alternative, to keep the topic branch clean of test
+merges, you could blow away the test merge, and keep building on
+top of the tip before the test merge:
+
+------------
+	$ git switch topic
+	$ git merge master
+	$ git reset --hard HEAD^ ;# rewind the test merge
+	$ ... work on both topic and master branches
+	$ git switch master
+	$ git merge topic
+
+              o---*---o-------o---o topic
+             /                     \
+    o---o---o---*---o---o---o---o---+ master
+------------
+
+This would leave only one merge commit when your topic branch is
+finally ready and merged into the master branch.  This merge
+would require you to resolve the conflict, introduced by the
+commits marked with `*`.  However, this conflict is often the
+same conflict you resolved when you created the test merge you
+blew away.  'git rerere' helps you resolve this final
+conflicted merge using the information from your earlier hand
+resolve.
+
+Running the 'git rerere' command immediately after a conflicted
+automerge records the conflicted working tree files, with the
+usual conflict markers `<<<<<<<`, `=======`, and `>>>>>>>` in
+them.  Later, after you are done resolving the conflicts,
+running 'git rerere' again will record the resolved state of these
+files.  Suppose you did this when you created the test merge of
+master into the topic branch.
+
+Next time, after seeing the same conflicted automerge,
+running 'git rerere' will perform a three-way merge between the
+earlier conflicted automerge, the earlier manual resolution, and
+the current conflicted automerge.
+If this three-way merge resolves cleanly, the result is written
+out to your working tree file, so you do not have to manually
+resolve it.  Note that 'git rerere' leaves the index file alone,
+so you still need to do the final sanity checks with `git diff`
+(or `git diff -c`) and 'git add' when you are satisfied.
+
+As a convenience measure, 'git merge' automatically invokes
+'git rerere' upon exiting with a failed automerge and 'git rerere'
+records the hand resolve when it is a new conflict, or reuses the earlier hand
+resolve when it is not.  'git commit' also invokes 'git rerere'
+when committing a merge result.  What this means is that you do
+not have to do anything special yourself (besides enabling
+the rerere.enabled config variable).
+
+In our example, when you do the test merge, the manual
+resolution is recorded, and it will be reused when you do the
+actual merge later with the updated master and topic branch, as long
+as the recorded resolution is still applicable.
+
+The information 'git rerere' records is also used when running
+'git rebase'.  After blowing away the test merge and continuing
+development on the topic branch:
+
+------------
+              o---*---o-------o---o topic
+             /
+    o---o---o---*---o---o---o---o   master
+
+	$ git rebase master topic
+
+				  o---*---o-------o---o topic
+				 /
+    o---o---o---*---o---o---o---o   master
+------------
+
+you could run `git rebase master topic`, to bring yourself
+up to date before your topic is ready to be sent upstream.
+This would result in falling back to a three-way merge, and it
+would conflict the same way as the test merge you resolved earlier.
+'git rerere' will be run by 'git rebase' to help you resolve this
+conflict.
+
+[NOTE] 'git rerere' relies on the conflict markers in the file to
+detect the conflict.  If the file already contains lines that look the
+same as lines with conflict markers, 'git rerere' may fail to record a
+conflict resolution.  To work around this, the `conflict-marker-size`
+setting in linkgit:gitattributes[5] can be used.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-reset.adoc b/Documentation/git-reset.adoc
new file mode 100644
index 0000000000..79ad5643ee
--- /dev/null
+++ b/Documentation/git-reset.adoc
@@ -0,0 +1,506 @@
+git-reset(1)
+============
+
+NAME
+----
+git-reset - Reset current HEAD to the specified state
+
+SYNOPSIS
+--------
+[verse]
+'git reset' [-q] [<tree-ish>] [--] <pathspec>...
+'git reset' [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]
+'git reset' (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
+'git reset' [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]
+
+DESCRIPTION
+-----------
+In the first three forms, copy entries from `<tree-ish>` to the index.
+In the last form, set the current branch head (`HEAD`) to `<commit>`,
+optionally modifying index and working tree to match.
+The `<tree-ish>`/`<commit>` defaults to `HEAD` in all forms.
+
+'git reset' [-q] [<tree-ish>] [--] <pathspec>...::
+'git reset' [-q] [--pathspec-from-file=<file> [--pathspec-file-nul]] [<tree-ish>]::
+	These forms reset the index entries for all paths that match the
+	`<pathspec>` to their state at `<tree-ish>`.  (It does not affect
+	the working tree or the current branch.)
++
+This means that `git reset <pathspec>` is the opposite of `git add
+<pathspec>`. This command is equivalent to
+`git restore [--source=<tree-ish>] --staged <pathspec>...`.
++
+After running `git reset <pathspec>` to update the index entry, you can
+use linkgit:git-restore[1] to check the contents out of the index to
+the working tree. Alternatively, using linkgit:git-restore[1]
+and specifying a commit with `--source`, you
+can copy the contents of a path out of a commit to the index and to the
+working tree in one go.
+
+'git reset' (--patch | -p) [<tree-ish>] [--] [<pathspec>...]::
+	Interactively select hunks in the difference between the index
+	and `<tree-ish>` (defaults to `HEAD`).  The chosen hunks are applied
+	in reverse to the index.
++
+This means that `git reset -p` is the opposite of `git add -p`, i.e.
+you can use it to selectively reset hunks. See the ``Interactive Mode''
+section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
+
+'git reset' [<mode>] [<commit>]::
+	This form resets the current branch head to `<commit>` and
+	possibly updates the index (resetting it to the tree of `<commit>`) and
+	the working tree depending on `<mode>`. Before the operation, `ORIG_HEAD`
+	is set to the tip of the current branch. If `<mode>` is omitted,
+	defaults to `--mixed`. The `<mode>` must be one of the following:
++
+--
+--soft::
+	Does not touch the index file or the working tree at all (but
+	resets the head to `<commit>`, just like all modes do). This leaves
+	all your changed files "Changes to be committed", as `git status`
+	would put it.
+
+--mixed::
+	Resets the index but not the working tree (i.e., the changed files
+	are preserved but not marked for commit) and reports what has not
+	been updated. This is the default action.
++
+If `-N` is specified, removed paths are marked as intent-to-add (see
+linkgit:git-add[1]).
+
+--hard::
+	Resets the index and working tree. Any changes to tracked files in the
+	working tree since `<commit>` are discarded.  Any untracked files or
+	directories in the way of writing any tracked files are simply deleted.
+
+--merge::
+	Resets the index and updates the files in the working tree that are
+	different between `<commit>` and `HEAD`, but keeps those which are
+	different between the index and working tree (i.e. which have changes
+	which have not been added).
+	If a file that is different between `<commit>` and the index has
+	unstaged changes, reset is aborted.
++
+In other words, `--merge` does something like a `git read-tree -u -m <commit>`,
+but carries forward unmerged index entries.
+
+--keep::
+	Resets index entries and updates files in the working tree that are
+	different between `<commit>` and `HEAD`.
+	If a file that is different between `<commit>` and `HEAD` has local
+	changes, reset is aborted.
+
+--[no-]recurse-submodules::
+	When the working tree is updated, using --recurse-submodules will
+	also recursively reset the working tree of all active submodules
+	according to the commit recorded in the superproject, also setting
+	the submodules' HEAD to be detached at that commit.
+--
+
+See "Reset, restore and revert" in linkgit:git[1] for the differences
+between the three commands.
+
+
+OPTIONS
+-------
+
+-q::
+--quiet::
+	Be quiet, only report errors.
+
+--refresh::
+--no-refresh::
+	Refresh the index after a mixed reset. Enabled by default.
+
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
+\--::
+	Do not interpret any more arguments as options.
+
+<pathspec>...::
+	Limits the paths affected by the operation.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
+
+EXAMPLES
+--------
+
+Undo add::
++
+------------
+$ edit                                     <1>
+$ git add frotz.c filfre.c
+$ mailx                                    <2>
+$ git reset                                <3>
+$ git pull git://info.example.com/ nitfol  <4>
+------------
++
+<1> You are happily working on something, and find the changes
+    in these files are in good order.  You do not want to see them
+    when you run `git diff`, because you plan to work on other files
+    and changes with these files are distracting.
+<2> Somebody asks you to pull, and the changes sound worthy of merging.
+<3> However, you already dirtied the index (i.e. your index does
+    not match the `HEAD` commit).  But you know the pull you are going
+    to make does not affect `frotz.c` or `filfre.c`, so you revert the
+    index changes for these two files.  Your changes in working tree
+    remain there.
+<4> Then you can pull and merge, leaving `frotz.c` and `filfre.c`
+    changes still in the working tree.
+
+Undo a commit and redo::
++
+------------
+$ git commit ...
+$ git reset --soft HEAD^      <1>
+$ edit                        <2>
+$ git commit -a -c ORIG_HEAD  <3>
+------------
++
+<1> This is most often done when you remembered what you
+    just committed is incomplete, or you misspelled your commit
+    message, or both.  Leaves working tree as it was before "reset".
+<2> Make corrections to working tree files.
+<3> "reset" copies the old head to `.git/ORIG_HEAD`; redo the
+    commit by starting with its log message.  If you do not need to
+    edit the message further, you can give `-C` option instead.
++
+See also the `--amend` option to linkgit:git-commit[1].
+
+Undo a commit, making it a topic branch::
++
+------------
+$ git branch topic/wip          <1>
+$ git reset --hard HEAD~3       <2>
+$ git switch topic/wip          <3>
+------------
++
+<1> You have made some commits, but realize they were premature
+    to be in the `master` branch.  You want to continue polishing
+    them in a topic branch, so create `topic/wip` branch off of the
+    current `HEAD`.
+<2> Rewind the master branch to get rid of those three commits.
+<3> Switch to `topic/wip` branch and keep working.
+
+Undo commits permanently::
++
+------------
+$ git commit ...
+$ git reset --hard HEAD~3   <1>
+------------
++
+<1> The last three commits (`HEAD`, `HEAD^`, and `HEAD~2`) were bad
+    and you do not want to ever see them again.  Do *not* do this if
+    you have already given these commits to somebody else.  (See the
+    "RECOVERING FROM UPSTREAM REBASE" section in linkgit:git-rebase[1]
+    for the implications of doing so.)
+
+Undo a merge or pull::
++
+------------
+$ git pull                         <1>
+Auto-merging nitfol
+CONFLICT (content): Merge conflict in nitfol
+Automatic merge failed; fix conflicts and then commit the result.
+$ git reset --hard                 <2>
+$ git pull . topic/branch          <3>
+Updating from 41223... to 13134...
+Fast-forward
+$ git reset --hard ORIG_HEAD       <4>
+------------
++
+<1> Try to update from the upstream resulted in a lot of
+    conflicts; you were not ready to spend a lot of time merging
+    right now, so you decide to do that later.
+<2> "pull" has not made merge commit, so `git reset --hard`
+    which is a synonym for `git reset --hard HEAD` clears the mess
+    from the index file and the working tree.
+<3> Merge a topic branch into the current branch, which resulted
+    in a fast-forward.
+<4> But you decided that the topic branch is not ready for public
+    consumption yet.  "pull" or "merge" always leaves the original
+    tip of the current branch in `ORIG_HEAD`, so resetting hard to it
+    brings your index file and the working tree back to that state,
+    and resets the tip of the branch to that commit.
+
+Undo a merge or pull inside a dirty working tree::
++
+------------
+$ git pull                         <1>
+Auto-merging nitfol
+Merge made by recursive.
+ nitfol                |   20 +++++----
+ ...
+$ git reset --merge ORIG_HEAD      <2>
+------------
++
+<1> Even if you may have local modifications in your
+    working tree, you can safely say `git pull` when you know
+    that the change in the other branch does not overlap with
+    them.
+<2> After inspecting the result of the merge, you may find
+    that the change in the other branch is unsatisfactory.  Running
+    `git reset --hard ORIG_HEAD` will let you go back to where you
+    were, but it will discard your local changes, which you do not
+    want.  `git reset --merge` keeps your local changes.
+
+
+Interrupted workflow::
++
+Suppose you are interrupted by an urgent fix request while you
+are in the middle of a large change.  The files in your
+working tree are not in any shape to be committed yet, but you
+need to get to the other branch for a quick bugfix.
++
+------------
+$ git switch feature  ;# you were working in "feature" branch and
+$ work work work      ;# got interrupted
+$ git commit -a -m "snapshot WIP"                 <1>
+$ git switch master
+$ fix fix fix
+$ git commit ;# commit with real log
+$ git switch feature
+$ git reset --soft HEAD^ ;# go back to WIP state  <2>
+$ git reset                                       <3>
+------------
++
+<1> This commit will get blown away so a throw-away log message is OK.
+<2> This removes the 'WIP' commit from the commit history, and sets
+    your working tree to the state just before you made that snapshot.
+<3> At this point the index file still has all the WIP changes you
+    committed as 'snapshot WIP'.  This updates the index to show your
+    WIP files as uncommitted.
++
+See also linkgit:git-stash[1].
+
+Reset a single file in the index::
++
+Suppose you have added a file to your index, but later decide you do not
+want to add it to your commit. You can remove the file from the index
+while keeping your changes with git reset.
++
+------------
+$ git reset -- frotz.c                      <1>
+$ git commit -m "Commit files in index"     <2>
+$ git add frotz.c                           <3>
+------------
++
+<1> This removes the file from the index while keeping it in the working
+    directory.
+<2> This commits all other changes in the index.
+<3> Adds the file to the index again.
+
+Keep changes in working tree while discarding some previous commits::
++
+Suppose you are working on something and you commit it, and then you
+continue working a bit more, but now you think that what you have in
+your working tree should be in another branch that has nothing to do
+with what you committed previously. You can start a new branch and
+reset it while keeping the changes in your working tree.
++
+------------
+$ git tag start
+$ git switch -c branch1
+$ edit
+$ git commit ...                            <1>
+$ edit
+$ git switch -c branch2                     <2>
+$ git reset --keep start                    <3>
+------------
++
+<1> This commits your first edits in `branch1`.
+<2> In the ideal world, you could have realized that the earlier
+    commit did not belong to the new topic when you created and switched
+    to `branch2` (i.e. `git switch -c branch2 start`), but nobody is
+    perfect.
+<3> But you can use `reset --keep` to remove the unwanted commit after
+    you switched to `branch2`.
+
+Split a commit apart into a sequence of commits::
++
+Suppose that you have created lots of logically separate changes and committed
+them together. Then, later you decide that it might be better to have each
+logical chunk associated with its own commit. You can use git reset to rewind
+history without changing the contents of your local files, and then successively
+use `git add -p` to interactively select which hunks to include into each commit,
+using `git commit -c` to pre-populate the commit message.
++
+------------
+$ git reset -N HEAD^                        <1>
+$ git add -p                                <2>
+$ git diff --cached                         <3>
+$ git commit -c HEAD@{1}                    <4>
+...                                         <5>
+$ git add ...                               <6>
+$ git diff --cached                         <7>
+$ git commit ...                            <8>
+------------
++
+<1> First, reset the history back one commit so that we remove the original
+    commit, but leave the working tree with all the changes. The -N ensures
+    that any new files added with `HEAD` are still marked so that `git add -p`
+    will find them.
+<2> Next, we interactively select diff hunks to add using the `git add -p`
+    facility. This will ask you about each diff hunk in sequence and you can
+    use simple commands such as "yes, include this", "No don't include this"
+    or even the very powerful "edit" facility.
+<3> Once satisfied with the hunks you want to include, you should verify what
+    has been prepared for the first commit by using `git diff --cached`. This
+    shows all the changes that have been moved into the index and are about
+    to be committed.
+<4> Next, commit the changes stored in the index. The `-c` option specifies to
+    pre-populate the commit message from the original message that you started
+    with in the first commit. This is helpful to avoid retyping it. The
+    `HEAD@{1}` is a special notation for the commit that `HEAD` used to be at
+    prior to the original reset commit (1 change ago).
+    See linkgit:git-reflog[1] for more details. You may also use any other
+    valid commit reference.
+<5> You can repeat steps 2-4 multiple times to break the original code into
+    any number of commits.
+<6> Now you've split out many of the changes into their own commits, and might
+    no longer use the patch mode of `git add`, in order to select all remaining
+    uncommitted changes.
+<7> Once again, check to verify that you've included what you want to. You may
+    also wish to verify that git diff doesn't show any remaining changes to be
+    committed later.
+<8> And finally create the final commit.
+
+
+DISCUSSION
+----------
+
+The tables below show what happens when running:
+
+----------
+git reset --option target
+----------
+
+to reset the `HEAD` to another commit (`target`) with the different
+reset options depending on the state of the files.
+
+In these tables, `A`, `B`, `C` and `D` are some different states of a
+file. For example, the first line of the first table means that if a
+file is in state `A` in the working tree, in state `B` in the index, in
+state `C` in `HEAD` and in state `D` in the target, then `git reset --soft
+target` will leave the file in the working tree in state `A` and in the
+index in state `B`.  It resets (i.e. moves) the `HEAD` (i.e. the tip of
+the current branch, if you are on one) to `target` (which has the file
+in state `D`).
+
+....
+working index HEAD target         working index HEAD
+----------------------------------------------------
+ A       B     C    D     --soft   A       B     D
+			  --mixed  A       D     D
+			  --hard   D       D     D
+			  --merge (disallowed)
+			  --keep  (disallowed)
+....
+
+....
+working index HEAD target         working index HEAD
+----------------------------------------------------
+ A       B     C    C     --soft   A       B     C
+			  --mixed  A       C     C
+			  --hard   C       C     C
+			  --merge (disallowed)
+			  --keep   A       C     C
+....
+
+....
+working index HEAD target         working index HEAD
+----------------------------------------------------
+ B       B     C    D     --soft   B       B     D
+			  --mixed  B       D     D
+			  --hard   D       D     D
+			  --merge  D       D     D
+			  --keep  (disallowed)
+....
+
+....
+working index HEAD target         working index HEAD
+----------------------------------------------------
+ B       B     C    C     --soft   B       B     C
+			  --mixed  B       C     C
+			  --hard   C       C     C
+			  --merge  C       C     C
+			  --keep   B       C     C
+....
+
+....
+working index HEAD target         working index HEAD
+----------------------------------------------------
+ B       C     C    D     --soft   B       C     D
+			  --mixed  B       D     D
+			  --hard   D       D     D
+			  --merge (disallowed)
+			  --keep  (disallowed)
+....
+
+....
+working index HEAD target         working index HEAD
+----------------------------------------------------
+ B       C     C    C     --soft   B       C     C
+			  --mixed  B       C     C
+			  --hard   C       C     C
+			  --merge  B       C     C
+			  --keep   B       C     C
+....
+
+`reset --merge` is meant to be used when resetting out of a conflicted
+merge. Any mergy operation guarantees that the working tree file that is
+involved in the merge does not have a local change with respect to the index
+before it starts, and that it writes the result out to the working tree. So if
+we see some difference between the index and the target and also
+between the index and the working tree, then it means that we are not
+resetting out from a state that a mergy operation left after failing
+with a conflict. That is why we disallow `--merge` option in this case.
+
+`reset --keep` is meant to be used when removing some of the last
+commits in the current branch while keeping changes in the working
+tree. If there could be conflicts between the changes in the commit we
+want to remove and the changes in the working tree we want to keep,
+the reset is disallowed. That's why it is disallowed if there are both
+changes between the working tree and `HEAD`, and between `HEAD` and the
+target. To be safe, it is also disallowed when there are unmerged
+entries.
+
+The following tables show what happens when there are unmerged
+entries:
+
+....
+working index HEAD target         working index HEAD
+----------------------------------------------------
+ X       U     A    B     --soft  (disallowed)
+			  --mixed  X       B     B
+			  --hard   B       B     B
+			  --merge  B       B     B
+			  --keep  (disallowed)
+....
+
+....
+working index HEAD target         working index HEAD
+----------------------------------------------------
+ X       U     A    A     --soft  (disallowed)
+			  --mixed  X       A     A
+			  --hard   A       A     A
+			  --merge  A       A     A
+			  --keep  (disallowed)
+....
+
+`X` means any state and `U` means an unmerged index.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-restore.adoc b/Documentation/git-restore.adoc
new file mode 100644
index 0000000000..975825b44a
--- /dev/null
+++ b/Documentation/git-restore.adoc
@@ -0,0 +1,222 @@
+git-restore(1)
+==============
+
+NAME
+----
+git-restore - Restore working tree files
+
+SYNOPSIS
+--------
+[verse]
+'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] [--] <pathspec>...
+'git restore' [<options>] [--source=<tree>] [--staged] [--worktree] --pathspec-from-file=<file> [--pathspec-file-nul]
+'git restore' (-p|--patch) [<options>] [--source=<tree>] [--staged] [--worktree] [--] [<pathspec>...]
+
+DESCRIPTION
+-----------
+Restore specified paths in the working tree with some contents from a
+restore source. If a path is tracked but does not exist in the restore
+source, it will be removed to match the source.
+
+The command can also be used to restore the content in the index with
+`--staged`, or restore both the working tree and the index with
+`--staged --worktree`.
+
+By default, if `--staged` is given, the contents are restored from `HEAD`,
+otherwise from the index. Use `--source` to restore from a different commit.
+
+See "Reset, restore and revert" in linkgit:git[1] for the differences
+between the three commands.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+OPTIONS
+-------
+-s <tree>::
+--source=<tree>::
+	Restore the working tree files with the content from the given
+	tree. It is common to specify the source tree by naming a
+	commit, branch or tag associated with it.
++
+If not specified, the contents are restored from `HEAD` if `--staged` is
+given, otherwise from the index.
++
+As a special case, you may use `"A...B"` as a shortcut for the
+merge base of `A` and `B` if there is exactly one merge base. You can
+leave out at most one of `A` and `B`, in which case it defaults to `HEAD`.
+
+-p::
+--patch::
+	Interactively select hunks in the difference between the
+	restore source and the restore location. See the ``Interactive
+	Mode'' section of linkgit:git-add[1] to learn how to operate
+	the `--patch` mode.
++
+Note that `--patch` can accept no pathspec and will prompt to restore
+all modified paths.
+
+-W::
+--worktree::
+-S::
+--staged::
+	Specify the restore location. If neither option is specified,
+	by default the working tree is restored. Specifying `--staged`
+	will only restore the index. Specifying both restores both.
+
+-q::
+--quiet::
+	Quiet, suppress feedback messages. Implies `--no-progress`.
+
+--progress::
+--no-progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless `--quiet`
+	is specified. This flag enables progress reporting even if not
+	attached to a terminal, regardless of `--quiet`.
+
+--ours::
+--theirs::
+	When restoring files in the working tree from the index, use
+	stage #2 ('ours') or #3 ('theirs') for unmerged paths.
+	This option cannot be used when checking out paths from a
+	tree-ish (i.e. with the `--source` option).
++
+Note that during `git rebase` and `git pull --rebase`, 'ours' and
+'theirs' may appear swapped. See the explanation of the same options
+in linkgit:git-checkout[1] for details.
+
+-m::
+--merge::
+	When restoring files on the working tree from the index,
+	recreate the conflicted merge in the unmerged paths.
+	This option cannot be used when checking out paths from a
+	tree-ish (i.e. with the `--source` option).
+
+--conflict=<style>::
+	The same as `--merge` option above, but changes the way the
+	conflicting hunks are presented, overriding the
+	`merge.conflictStyle` configuration variable.  Possible values
+	are "merge" (default), "diff3", and "zdiff3".
+
+--ignore-unmerged::
+	When restoring files on the working tree from the index, do
+	not abort the operation if there are unmerged entries and
+	neither `--ours`, `--theirs`, `--merge` or `--conflict` is
+	specified. Unmerged paths on the working tree are left alone.
+
+--ignore-skip-worktree-bits::
+	In sparse checkout mode, the default is to only update entries
+	matched by `<pathspec>` and sparse patterns in
+	$GIT_DIR/info/sparse-checkout. This option ignores the sparse
+	patterns and unconditionally restores any files in
+	`<pathspec>`.
+
+--recurse-submodules::
+--no-recurse-submodules::
+	If `<pathspec>` names an active submodule and the restore location
+	includes the working tree, the submodule will only be updated if
+	this option is given, in which case its working tree will be
+	restored to the commit recorded in the superproject, and any local
+	modifications overwritten. If nothing (or
+	`--no-recurse-submodules`) is used, submodules working trees will
+	not be updated. Just like linkgit:git-checkout[1], this will detach
+	`HEAD` of the submodule.
+
+--overlay::
+--no-overlay::
+	In overlay mode, the command never removes files when
+	restoring. In no-overlay mode, tracked files that do not
+	appear in the `--source` tree are removed, to make them match
+	`<tree>` exactly. The default is no-overlay mode.
+
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
+\--::
+	Do not interpret any more arguments as options.
+
+<pathspec>...::
+	Limits the paths affected by the operation.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
+
+EXAMPLES
+--------
+
+The following sequence switches to the `master` branch, reverts the
+`Makefile` to two revisions back, deletes hello.c by mistake, and gets
+it back from the index.
+
+------------
+$ git switch master
+$ git restore --source master~2 Makefile  <1>
+$ rm -f hello.c
+$ git restore hello.c                     <2>
+------------
+
+<1> take a file out of another commit
+<2> restore hello.c from the index
+
+If you want to restore _all_ C source files to match the version in
+the index, you can say
+
+------------
+$ git restore '*.c'
+------------
+
+Note the quotes around `*.c`.  The file `hello.c` will also be
+restored, even though it is no longer in the working tree, because the
+file globbing is used to match entries in the index (not in the
+working tree by the shell).
+
+To restore all files in the current directory
+
+------------
+$ git restore .
+------------
+
+or to restore all working tree files with 'top' pathspec magic (see
+linkgit:gitglossary[7])
+
+------------
+$ git restore :/
+------------
+
+To restore a file in the index to match the version in `HEAD` (this is
+the same as using linkgit:git-reset[1])
+
+------------
+$ git restore --staged hello.c
+------------
+
+or you can restore both the index and the working tree (this is the same
+as using linkgit:git-checkout[1])
+
+------------
+$ git restore --source=HEAD --staged --worktree hello.c
+------------
+
+or the short form which is more practical but less readable:
+
+------------
+$ git restore -s@ -SW hello.c
+------------
+
+SEE ALSO
+--------
+linkgit:git-checkout[1],
+linkgit:git-reset[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rev-list.adoc b/Documentation/git-rev-list.adoc
new file mode 100644
index 0000000000..f582491dd4
--- /dev/null
+++ b/Documentation/git-rev-list.adoc
@@ -0,0 +1,129 @@
+git-rev-list(1)
+===============
+
+NAME
+----
+git-rev-list - Lists commit objects in reverse chronological order
+
+
+SYNOPSIS
+--------
+[verse]
+'git rev-list' [<options>] <commit>... [--] [<path>...]
+
+DESCRIPTION
+-----------
+
+:git-rev-list: 1
+include::rev-list-description.adoc[]
+
+'rev-list' is an essential Git command, since it
+provides the ability to build and traverse commit ancestry graphs. For
+this reason, it has a lot of different options that enable it to be
+used by commands as different as 'git bisect' and
+'git repack'.
+
+OPTIONS
+-------
+
+:git-rev-list: 1
+include::rev-list-options.adoc[]
+
+include::pretty-formats.adoc[]
+
+EXAMPLES
+--------
+
+* Print the list of commits reachable from the current branch.
++
+----------
+git rev-list HEAD
+----------
+
+* Print the list of commits on this branch, but not present in the
+  upstream branch.
++
+----------
+git rev-list @{upstream}..HEAD
+----------
+
+* Format commits with their author and commit message (see also the
+  porcelain linkgit:git-log[1]).
++
+----------
+git rev-list --format=medium HEAD
+----------
+
+* Format commits along with their diffs (see also the porcelain
+  linkgit:git-log[1], which can do this in a single process).
++
+----------
+git rev-list HEAD |
+git diff-tree --stdin --format=medium -p
+----------
+
+* Print the list of commits on the current branch that touched any
+  file in the `Documentation` directory.
++
+----------
+git rev-list HEAD -- Documentation/
+----------
+
+* Print the list of commits authored by you in the past year, on
+  any branch, tag, or other ref.
++
+----------
+git rev-list --author=you@xxxxxxxxxxx --since=1.year.ago --all
+----------
+
+* Print the list of objects reachable from the current branch (i.e., all
+  commits and the blobs and trees they contain).
++
+----------
+git rev-list --objects HEAD
+----------
+
+* Compare the disk size of all reachable objects, versus those
+  reachable from reflogs, versus the total packed size. This can tell
+  you whether running `git repack -ad` might reduce the repository size
+  (by dropping unreachable objects), and whether expiring reflogs might
+  help.
++
+----------
+# reachable objects
+git rev-list --disk-usage --objects --all
+# plus reflogs
+git rev-list --disk-usage --objects --all --reflog
+# total disk size used
+du -c .git/objects/pack/*.pack .git/objects/??/*
+# alternative to du: add up "size" and "size-pack" fields
+git count-objects -v
+----------
+
+* Report the disk size of each branch, not including objects used by the
+  current branch. This can find outliers that are contributing to a
+  bloated repository size (e.g., because somebody accidentally committed
+  large build artifacts).
++
+----------
+git for-each-ref --format='%(refname)' |
+while read branch
+do
+	size=$(git rev-list --disk-usage --objects HEAD..$branch)
+	echo "$size $branch"
+done |
+sort -n
+----------
+
+* Compare the on-disk size of branches in one group of refs, excluding
+  another. If you co-mingle objects from multiple remotes in a single
+  repository, this can show which remotes are contributing to the
+  repository size (taking the size of `origin` as a baseline).
++
+----------
+git rev-list --disk-usage --objects --remotes=$suspect --not --remotes=origin
+----------
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rev-parse.adoc b/Documentation/git-rev-parse.adoc
new file mode 100644
index 0000000000..cc32b4b4f0
--- /dev/null
+++ b/Documentation/git-rev-parse.adoc
@@ -0,0 +1,516 @@
+git-rev-parse(1)
+================
+
+NAME
+----
+git-rev-parse - Pick out and massage parameters
+
+
+SYNOPSIS
+--------
+[verse]
+'git rev-parse' [<options>] <arg>...
+
+DESCRIPTION
+-----------
+
+Many Git porcelainish commands take a mixture of flags
+(i.e. parameters that begin with a dash '-') and parameters
+meant for the underlying 'git rev-list' command they use internally
+and flags and parameters for the other commands they use
+downstream of 'git rev-list'.  The primary purpose of this command
+is to allow calling programs to distinguish between them.  There are
+a few other operation modes that have nothing to do with the above
+"help parse command line options".
+
+Unless otherwise specified, most of the options and operation modes
+require you to run this command inside a git repository or a working
+tree that is under the control of a git repository, and will give you
+a fatal error otherwise.
+
+
+OPTIONS
+-------
+
+Operation Modes
+~~~~~~~~~~~~~~~
+
+Each of these options must appear first on the command line.
+
+--parseopt::
+	Use 'git rev-parse' in option parsing mode (see PARSEOPT section below).
+	The command in this mode can be used outside a repository or
+	a working tree controlled by a repository.
+
+--sq-quote::
+	Use 'git rev-parse' in shell quoting mode (see SQ-QUOTE
+	section below). In contrast to the `--sq` option below, this
+	mode only does quoting. Nothing else is done to command input.
+	The command in this mode can be used outside a repository or
+	a working tree controlled by a repository.
+
+Options for --parseopt
+~~~~~~~~~~~~~~~~~~~~~~
+
+--keep-dashdash::
+	Only meaningful in `--parseopt` mode. Tells the option parser to echo
+	out the first `--` met instead of skipping it.
+
+--stop-at-non-option::
+	Only meaningful in `--parseopt` mode.  Lets the option parser stop at
+	the first non-option argument.  This can be used to parse sub-commands
+	that take options themselves.
+
+--stuck-long::
+	Only meaningful in `--parseopt` mode. Output the options in their
+	long form if available, and with their arguments stuck.
+
+Options for Filtering
+~~~~~~~~~~~~~~~~~~~~~
+
+--revs-only::
+	Do not output flags and parameters not meant for
+	'git rev-list' command.
+
+--no-revs::
+	Do not output flags and parameters meant for
+	'git rev-list' command.
+
+--flags::
+	Do not output non-flag parameters.
+
+--no-flags::
+	Do not output flag parameters.
+
+Options for Output
+~~~~~~~~~~~~~~~~~~
+
+--default <arg>::
+	If there is no parameter given by the user, use `<arg>`
+	instead.
+
+--prefix <arg>::
+	Behave as if 'git rev-parse' was invoked from the `<arg>`
+	subdirectory of the working tree.  Any relative filenames are
+	resolved as if they are prefixed by `<arg>` and will be printed
+	in that form.
++
+This can be used to convert arguments to a command run in a subdirectory
+so that they can still be used after moving to the top-level of the
+repository.  For example:
++
+----
+prefix=$(git rev-parse --show-prefix)
+cd "$(git rev-parse --show-toplevel)"
+# rev-parse provides the -- needed for 'set'
+eval "set $(git rev-parse --sq --prefix "$prefix" -- "$@")"
+----
+
+--verify::
+	Verify that exactly one parameter is provided, and that it
+	can be turned into a raw 20-byte SHA-1 that can be used to
+	access the object database. If so, emit it to the standard
+	output; otherwise, error out.
++
+If you want to make sure that the output actually names an object in
+your object database and/or can be used as a specific type of object
+you require, you can add the `^{type}` peeling operator to the parameter.
+For example, `git rev-parse "$VAR^{commit}"` will make sure `$VAR`
+names an existing object that is a commit-ish (i.e. a commit, or an
+annotated tag that points at a commit).  To make sure that `$VAR`
+names an existing object of any type, `git rev-parse "$VAR^{object}"`
+can be used.
++
+Note that if you are verifying a name from an untrusted source, it is
+wise to use `--end-of-options` so that the name argument is not mistaken
+for another option.
+
+-q::
+--quiet::
+	Only meaningful in `--verify` mode. Do not output an error
+	message if the first argument is not a valid object name;
+	instead exit with non-zero status silently.
+	SHA-1s for valid object names are printed to stdout on success.
+
+--sq::
+	Usually the output is made one line per flag and
+	parameter.  This option makes output a single line,
+	properly quoted for consumption by shell.  Useful when
+	you expect your parameter to contain whitespaces and
+	newlines (e.g. when using pickaxe `-S` with
+	'git diff-{asterisk}'). In contrast to the `--sq-quote` option,
+	the command input is still interpreted as usual.
+
+--short[=<length>]::
+	Same as `--verify` but shortens the object name to a unique
+	prefix with at least `length` characters. The minimum length
+	is 4, the default is the effective value of the `core.abbrev`
+	configuration variable (see linkgit:git-config[1]).
+
+--not::
+	When showing object names, prefix them with '{caret}' and
+	strip '{caret}' prefix from the object names that already have
+	one.
+
+--abbrev-ref[=(strict|loose)]::
+	A non-ambiguous short name of the objects name.
+	The option core.warnAmbiguousRefs is used to select the strict
+	abbreviation mode.
+
+--symbolic::
+	Usually the object names are output in SHA-1 form (with
+	possible '{caret}' prefix); this option makes them output in a
+	form as close to the original input as possible.
+
+--symbolic-full-name::
+	This is similar to --symbolic, but it omits input that
+	are not refs (i.e. branch or tag names; or more
+	explicitly disambiguating "heads/master" form, when you
+	want to name the "master" branch when there is an
+	unfortunately named tag "master"), and shows them as full
+	refnames (e.g. "refs/heads/master").
+
+--output-object-format=(sha1|sha256|storage)::
+
+	Allow oids to be input from any object format that the current
+	repository supports.
+
+	Specifying "sha1" translates if necessary and returns a sha1 oid.
+
+	Specifying "sha256" translates if necessary and returns a sha256 oid.
+
+	Specifying "storage" translates if necessary and returns an oid in
+	encoded in the storage hash algorithm.
+
+Options for Objects
+~~~~~~~~~~~~~~~~~~~
+
+--all::
+	Show all refs found in `refs/`.
+
+--branches[=<pattern>]::
+--tags[=<pattern>]::
+--remotes[=<pattern>]::
+	Show all branches, tags, or remote-tracking branches,
+	respectively (i.e., refs found in `refs/heads`,
+	`refs/tags`, or `refs/remotes`, respectively).
++
+If a `pattern` is given, only refs matching the given shell glob are
+shown.  If the pattern does not contain a globbing character (`?`,
+`*`, or `[`), it is turned into a prefix match by appending `/*`.
+
+--glob=<pattern>::
+	Show all refs matching the shell glob pattern `pattern`. If
+	the pattern does not start with `refs/`, this is automatically
+	prepended.  If the pattern does not contain a globbing
+	character (`?`, `*`, or `[`), it is turned into a prefix
+	match by appending `/*`.
+
+--exclude=<glob-pattern>::
+	Do not include refs matching '<glob-pattern>' that the next `--all`,
+	`--branches`, `--tags`, `--remotes`, or `--glob` would otherwise
+	consider. Repetitions of this option accumulate exclusion patterns
+	up to the next `--all`, `--branches`, `--tags`, `--remotes`, or
+	`--glob` option (other options or arguments do not clear
+	accumulated patterns).
++
+The patterns given should not begin with `refs/heads`, `refs/tags`, or
+`refs/remotes` when applied to `--branches`, `--tags`, or `--remotes`,
+respectively, and they must begin with `refs/` when applied to `--glob`
+or `--all`. If a trailing '/{asterisk}' is intended, it must be given
+explicitly.
+
+--exclude-hidden=(fetch|receive|uploadpack)::
+	Do not include refs that would be hidden by `git-fetch`,
+	`git-receive-pack` or `git-upload-pack` by consulting the appropriate
+	`fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs`
+	configuration along with `transfer.hideRefs` (see
+	linkgit:git-config[1]). This option affects the next pseudo-ref option
+	`--all` or `--glob` and is cleared after processing them.
+
+--disambiguate=<prefix>::
+	Show every object whose name begins with the given prefix.
+	The <prefix> must be at least 4 hexadecimal digits long to
+	avoid listing each and every object in the repository by
+	mistake.
+
+Options for Files
+~~~~~~~~~~~~~~~~~
+
+--local-env-vars::
+	List the GIT_* environment variables that are local to the
+	repository (e.g. GIT_DIR or GIT_WORK_TREE, but not GIT_EDITOR).
+	Only the names of the variables are listed, not their value,
+	even if they are set.
+
+--path-format=(absolute|relative)::
+	Controls the behavior of certain other options. If specified as absolute, the
+	paths printed by those options will be absolute and canonical. If specified as
+	relative, the paths will be relative to the current working directory if that
+	is possible.  The default is option specific.
++
+This option may be specified multiple times and affects only the arguments that
+follow it on the command line, either to the end of the command line or the next
+instance of this option.
+
+The following options are modified by `--path-format`:
+
+--git-dir::
+	Show `$GIT_DIR` if defined. Otherwise show the path to
+	the .git directory. The path shown, when relative, is
+	relative to the current working directory.
++
+If `$GIT_DIR` is not defined and the current directory
+is not detected to lie in a Git repository or work tree
+print a message to stderr and exit with nonzero status.
+
+--git-common-dir::
+	Show `$GIT_COMMON_DIR` if defined, else `$GIT_DIR`.
+
+--resolve-git-dir <path>::
+	Check if <path> is a valid repository or a gitfile that
+	points at a valid repository, and print the location of the
+	repository.  If <path> is a gitfile then the resolved path
+	to the real repository is printed.
+
+--git-path <path>::
+	Resolve "$GIT_DIR/<path>" and takes other path relocation
+	variables such as $GIT_OBJECT_DIRECTORY,
+	$GIT_INDEX_FILE... into account. For example, if
+	$GIT_OBJECT_DIRECTORY is set to /foo/bar then "git rev-parse
+	--git-path objects/abc" returns /foo/bar/abc.
+
+--show-toplevel::
+	Show the (by default, absolute) path of the top-level directory
+	of the working tree. If there is no working tree, report an error.
+
+--show-superproject-working-tree::
+	Show the absolute path of the root of the superproject's
+	working tree (if exists) that uses the current repository as
+	its submodule.  Outputs nothing if the current repository is
+	not used as a submodule by any project.
+
+--shared-index-path::
+	Show the path to the shared index file in split index mode, or
+	empty if not in split-index mode.
+
+The following options are unaffected by `--path-format`:
+
+--absolute-git-dir::
+	Like `--git-dir`, but its output is always the canonicalized
+	absolute path.
+
+--is-inside-git-dir::
+	When the current working directory is below the repository
+	directory print "true", otherwise "false".
+
+--is-inside-work-tree::
+	When the current working directory is inside the work tree of the
+	repository print "true", otherwise "false".
+
+--is-bare-repository::
+	When the repository is bare print "true", otherwise "false".
+
+--is-shallow-repository::
+	When the repository is shallow print "true", otherwise "false".
+
+--show-cdup::
+	When the command is invoked from a subdirectory, show the
+	path of the top-level directory relative to the current
+	directory (typically a sequence of "../", or an empty string).
+
+--show-prefix::
+	When the command is invoked from a subdirectory, show the
+	path of the current directory relative to the top-level
+	directory.
+
+--show-object-format[=(storage|input|output)]::
+	Show the object format (hash algorithm) used for the repository
+	for storage inside the `.git` directory, input, or output. For
+	input, multiple algorithms may be printed, space-separated.
+	If not specified, the default is "storage".
+
+--show-ref-format::
+	Show the reference storage format used for the repository.
+
+
+Other Options
+~~~~~~~~~~~~~
+
+--since=<datestring>::
+--after=<datestring>::
+	Parse the date string, and output the corresponding
+	--max-age= parameter for 'git rev-list'.
+
+--until=<datestring>::
+--before=<datestring>::
+	Parse the date string, and output the corresponding
+	--min-age= parameter for 'git rev-list'.
+
+<arg>...::
+	Flags and parameters to be parsed.
+
+
+include::revisions.adoc[]
+
+PARSEOPT
+--------
+
+In `--parseopt` mode, 'git rev-parse' helps massaging options to bring to shell
+scripts the same facilities C builtins have. It works as an option normalizer
+(e.g. splits single switches aggregate values), a bit like `getopt(1)` does.
+
+It takes on the standard input the specification of the options to parse and
+understand, and echoes on the standard output a string suitable for `sh(1)` `eval`
+to replace the arguments with normalized ones.  In case of error, it outputs
+usage on the standard error stream, and exits with code 129.
+
+Note: Make sure you quote the result when passing it to `eval`.  See
+below for an example.
+
+Input Format
+~~~~~~~~~~~~
+
+'git rev-parse --parseopt' input format is fully text based. It has two parts,
+separated by a line that contains only `--`. The lines before the separator
+(should be one or more) are used for the usage.
+The lines after the separator describe the options.
+
+Each line of options has this format:
+
+------------
+<opt-spec><flags>*<arg-hint>? SP+ help LF
+------------
+
+`<opt-spec>`::
+	its format is the short option character, then the long option name
+	separated by a comma. Both parts are not required, though at least one
+	is necessary. May not contain any of the `<flags>` characters.
+	`h,help`, `dry-run` and `f` are examples of correct `<opt-spec>`.
+
+`<flags>`::
+	`<flags>` are of `*`, `=`, `?` or `!`.
+	* Use `=` if the option takes an argument.
+
+	* Use `?` to mean that the option takes an optional argument. You
+	  probably want to use the `--stuck-long` mode to be able to
+	  unambiguously parse the optional argument.
+
+	* Use `*` to mean that this option should not be listed in the usage
+	  generated for the `-h` argument. It's shown for `--help-all` as
+	  documented in linkgit:gitcli[7].
+
+	* Use `!` to not make the corresponding negated long option available.
+
+`<arg-hint>`::
+	`<arg-hint>`, if specified, is used as a name of the argument in the
+	help output, for options that take arguments. `<arg-hint>` is
+	terminated by the first whitespace.  It is customary to use a
+	dash to separate words in a multi-word argument hint.
+
+The remainder of the line, after stripping the spaces, is used
+as the help associated with the option.
+
+Blank lines are ignored, and lines that don't match this specification are used
+as option group headers (start the line with a space to create such
+lines on purpose).
+
+Example
+~~~~~~~
+
+------------
+OPTS_SPEC="\
+some-command [<options>] <args>...
+
+some-command does foo and bar!
+--
+h,help!   show the help
+
+foo       some nifty option --foo
+bar=      some cool option --bar with an argument
+baz=arg   another cool option --baz with a named argument
+qux?path  qux may take a path argument but has meaning by itself
+
+  An option group Header
+C?        option C with an optional argument"
+
+eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"
+------------
+
+
+Usage text
+~~~~~~~~~~
+
+When `"$@"` is `-h` or `--help` in the above example, the following
+usage text would be shown:
+
+------------
+usage: some-command [<options>] <args>...
+
+    some-command does foo and bar!
+
+    -h, --help            show the help
+    --[no-]foo            some nifty option --foo
+    --[no-]bar ...        some cool option --bar with an argument
+    --[no-]baz <arg>      another cool option --baz with a named argument
+    --[no-]qux[=<path>]   qux may take a path argument but has meaning by itself
+
+An option group Header
+    -C[...]               option C with an optional argument
+------------
+
+SQ-QUOTE
+--------
+
+In `--sq-quote` mode, 'git rev-parse' echoes on the standard output a
+single line suitable for `sh(1)` `eval`. This line is made by
+normalizing the arguments following `--sq-quote`. Nothing other than
+quoting the arguments is done.
+
+If you want command input to still be interpreted as usual by
+'git rev-parse' before the output is shell quoted, see the `--sq`
+option.
+
+Example
+~~~~~~~
+
+------------
+$ cat >your-git-script.sh <<\EOF
+#!/bin/sh
+args=$(git rev-parse --sq-quote "$@")   # quote user-supplied arguments
+command="git frotz -n24 $args"          # and use it inside a handcrafted
+					# command line
+eval "$command"
+EOF
+
+$ sh your-git-script.sh "a b'c"
+------------
+
+EXAMPLES
+--------
+
+* Print the object name of the current commit:
++
+------------
+$ git rev-parse --verify HEAD
+------------
+
+* Print the commit object name from the revision in the $REV shell variable:
++
+------------
+$ git rev-parse --verify --end-of-options $REV^{commit}
+------------
++
+This will error out if $REV is empty or not a valid revision.
+
+* Similar to above:
++
+------------
+$ git rev-parse --default master --verify --end-of-options $REV
+------------
++
+but if $REV is empty, the commit object name from master will be printed.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-revert.adoc b/Documentation/git-revert.adoc
new file mode 100644
index 0000000000..98f6aa62d1
--- /dev/null
+++ b/Documentation/git-revert.adoc
@@ -0,0 +1,168 @@
+git-revert(1)
+=============
+
+NAME
+----
+git-revert - Revert some existing commits
+
+SYNOPSIS
+--------
+[verse]
+'git revert' [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>...
+'git revert' (--continue | --skip | --abort | --quit)
+
+DESCRIPTION
+-----------
+
+Given one or more existing commits, revert the changes that the
+related patches introduce, and record some new commits that record
+them.  This requires your working tree to be clean (no modifications
+from the HEAD commit).
+
+Note: 'git revert' is used to record some new commits to reverse the
+effect of some earlier commits (often only a faulty one).  If you want to
+throw away all uncommitted changes in your working directory, you
+should see linkgit:git-reset[1], particularly the `--hard` option.  If
+you want to extract specific files as they were in another commit, you
+should see linkgit:git-restore[1], specifically the `--source`
+option. Take care with these alternatives as
+both will discard uncommitted changes in your working directory.
+
+See "Reset, restore and revert" in linkgit:git[1] for the differences
+between the three commands.
+
+OPTIONS
+-------
+<commit>...::
+	Commits to revert.
+	For a more complete list of ways to spell commit names, see
+	linkgit:gitrevisions[7].
+	Sets of commits can also be given but no traversal is done by
+	default, see linkgit:git-rev-list[1] and its `--no-walk`
+	option.
+
+-e::
+--edit::
+	With this option, 'git revert' will let you edit the commit
+	message prior to committing the revert. This is the default if
+	you run the command from a terminal.
+
+-m parent-number::
+--mainline parent-number::
+	Usually you cannot revert a merge because you do not know which
+	side of the merge should be considered the mainline.  This
+	option specifies the parent number (starting from 1) of
+	the mainline and allows revert to reverse the change
+	relative to the specified parent.
++
+Reverting a merge commit declares that you will never want the tree changes
+brought in by the merge.  As a result, later merges will only bring in tree
+changes introduced by commits that are not ancestors of the previously
+reverted merge.  This may or may not be what you want.
++
+See the link:howto/revert-a-faulty-merge.html[revert-a-faulty-merge How-To] for
+more details.
+
+--no-edit::
+	With this option, 'git revert' will not start the commit
+	message editor.
+
+--cleanup=<mode>::
+	This option determines how the commit message will be cleaned up before
+	being passed on to the commit machinery. See linkgit:git-commit[1] for more
+	details. In particular, if the '<mode>' is given a value of `scissors`,
+	scissors will be appended to `MERGE_MSG` before being passed on in the case
+	of a conflict.
+
+-n::
+--no-commit::
+	Usually the command automatically creates some commits with
+	commit log messages stating which commits were
+	reverted.  This flag applies the changes necessary
+	to revert the named commits to your working tree
+	and the index, but does not make the commits.  In addition,
+	when this option is used, your index does not have to match
+	the HEAD commit.  The revert is done against the
+	beginning state of your index.
++
+This is useful when reverting more than one commits'
+effect to your index in a row.
+
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+--no-gpg-sign::
+	GPG-sign commits. The `keyid` argument is optional and
+	defaults to the committer identity; if specified, it must be
+	stuck to the option without a space. `--no-gpg-sign` is useful to
+	countermand both `commit.gpgSign` configuration variable, and
+	earlier `--gpg-sign`.
+
+-s::
+--signoff::
+	Add a `Signed-off-by` trailer at the end of the commit message.
+	See the signoff option in linkgit:git-commit[1] for more information.
+
+--strategy=<strategy>::
+	Use the given merge strategy.  Should only be used once.
+	See the MERGE STRATEGIES section in linkgit:git-merge[1]
+	for details.
+
+-X<option>::
+--strategy-option=<option>::
+	Pass the merge strategy-specific option through to the
+	merge strategy.  See linkgit:git-merge[1] for details.
+
+include::rerere-options.adoc[]
+
+--reference::
+	Instead of starting the body of the log message with "This
+	reverts <full-object-name-of-the-commit-being-reverted>.",
+	refer to the commit using "--pretty=reference" format
+	(cf. linkgit:git-log[1]).  The `revert.reference`
+	configuration variable can be used to enable this option by
+	default.
+
+
+SEQUENCER SUBCOMMANDS
+---------------------
+include::sequencer.adoc[]
+
+EXAMPLES
+--------
+`git revert HEAD~3`::
+
+	Revert the changes specified by the fourth last commit in HEAD
+	and create a new commit with the reverted changes.
+
+`git revert -n master~5..master~2`::
+
+	Revert the changes done by commits from the fifth last commit
+	in master (included) to the third last commit in master
+	(included), but do not create any commit with the reverted
+	changes. The revert only modifies the working tree and the
+	index.
+
+DISCUSSION
+----------
+
+While git creates a basic commit message automatically, it is
+_strongly_ recommended to explain why the original commit is being
+reverted.
+In addition, repeatedly reverting reverts will result in increasingly
+unwieldy subject lines, for example 'Reapply "Reapply "<original-subject>""'.
+Please consider rewording these to be shorter and more unique.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/revert.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-cherry-pick[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-rm.adoc b/Documentation/git-rm.adoc
new file mode 100644
index 0000000000..363a26934f
--- /dev/null
+++ b/Documentation/git-rm.adoc
@@ -0,0 +1,204 @@
+git-rm(1)
+=========
+
+NAME
+----
+git-rm - Remove files from the working tree and from the index
+
+SYNOPSIS
+--------
+[verse]
+'git rm' [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]
+	  [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]
+	  [--] [<pathspec>...]
+
+DESCRIPTION
+-----------
+Remove files matching pathspec from the index, or from the working tree
+and the index. `git rm` will not remove a file from just your working
+directory. (There is no option to remove a file only from the working
+tree and yet keep it in the index; use `/bin/rm` if you want to do
+that.) The files being removed have to be identical to the tip of the
+branch, and no updates to their contents can be staged in the index,
+though that default behavior can be overridden with the `-f` option.
+When `--cached` is given, the staged content has to
+match either the tip of the branch or the file on disk,
+allowing the file to be removed from just the index. When
+sparse-checkouts are in use (see linkgit:git-sparse-checkout[1]),
+`git rm` will only remove paths within the sparse-checkout patterns.
+
+
+OPTIONS
+-------
+<pathspec>...::
+	Files to remove.  A leading directory name (e.g. `dir` to remove
+	`dir/file1` and `dir/file2`) can be given to remove all files in
+	the directory, and recursively all sub-directories, but this
+	requires the `-r` option to be explicitly given.
++
+The command removes only the paths that are known to Git.
++
+File globbing matches across directory boundaries.  Thus, given two
+directories `d` and `d2`, there is a difference between using
+`git rm 'd*'` and `git rm 'd/*'`, as the former will also remove all
+of directory `d2`.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
+
+-f::
+--force::
+	Override the up-to-date check.
+
+-n::
+--dry-run::
+	Don't actually remove any file(s).  Instead, just show
+	if they exist in the index and would otherwise be removed
+	by the command.
+
+-r::
+        Allow recursive removal when a leading directory name is
+        given.
+
+\--::
+	This option can be used to separate command-line options from
+	the list of files, (useful when filenames might be mistaken
+	for command-line options).
+
+--cached::
+	Use this option to unstage and remove paths only from the index.
+	Working tree files, whether modified or not, will be
+	left alone.
+
+--ignore-unmatch::
+	Exit with a zero status even if no files matched.
+
+--sparse::
+	Allow updating index entries outside of the sparse-checkout cone.
+	Normally, `git rm` refuses to update index entries whose paths do
+	not fit within the sparse-checkout cone. See
+	linkgit:git-sparse-checkout[1] for more.
+
+-q::
+--quiet::
+	`git rm` normally outputs one line (in the form of an `rm` command)
+	for each file removed. This option suppresses that output.
+
+--pathspec-from-file=<file>::
+	Pathspec is passed in `<file>` instead of commandline args. If
+	`<file>` is exactly `-` then standard input is used. Pathspec
+	elements are separated by LF or CR/LF. Pathspec elements can be
+	quoted as explained for the configuration variable `core.quotePath`
+	(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+	global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	Only meaningful with `--pathspec-from-file`. Pathspec elements are
+	separated with NUL character and all other characters are taken
+	literally (including newlines and quotes).
+
+
+REMOVING FILES THAT HAVE DISAPPEARED FROM THE FILESYSTEM
+--------------------------------------------------------
+There is no option for `git rm` to remove from the index only
+the paths that have disappeared from the filesystem. However,
+depending on the use case, there are several ways that can be
+done.
+
+Using ``git commit -a''
+~~~~~~~~~~~~~~~~~~~~~~~
+If you intend that your next commit should record all modifications
+of tracked files in the working tree and record all removals of
+files that have been removed from the working tree with `rm`
+(as opposed to `git rm`), use `git commit -a`, as it will
+automatically notice and record all removals.  You can also have a
+similar effect without committing by using `git add -u`.
+
+Using ``git add -A''
+~~~~~~~~~~~~~~~~~~~~
+When accepting a new code drop for a vendor branch, you probably
+want to record both the removal of paths and additions of new paths
+as well as modifications of existing paths.
+
+Typically you would first remove all tracked files from the working
+tree using this command:
+
+----------------
+git ls-files -z | xargs -0 rm -f
+----------------
+
+and then untar the new code in the working tree. Alternately
+you could 'rsync' the changes into the working tree.
+
+After that, the easiest way to record all removals, additions, and
+modifications in the working tree is:
+
+----------------
+git add -A
+----------------
+
+See linkgit:git-add[1].
+
+Other ways
+~~~~~~~~~~
+If all you really want to do is to remove from the index the files
+that are no longer present in the working tree (perhaps because
+your working tree is dirty so that you cannot use `git commit -a`),
+use the following command:
+
+----------------
+git diff --name-only --diff-filter=D -z | xargs -0 git rm --cached
+----------------
+
+SUBMODULES
+----------
+Only submodules using a gitfile (which means they were cloned
+with a Git version 1.7.8 or newer) will be removed from the work
+tree, as their repository lives inside the .git directory of the
+superproject. If a submodule (or one of those nested inside it)
+still uses a .git directory, `git rm` will move the submodules
+git directory into the superprojects git directory to protect
+the submodule's history. If it exists the submodule.<name> section
+in the linkgit:gitmodules[5] file will also be removed and that file
+will be staged (unless --cached or -n are used).
+
+A submodule is considered up to date when the HEAD is the same as
+recorded in the index, no tracked files are modified and no untracked
+files that aren't ignored are present in the submodule's work tree.
+Ignored files are deemed expendable and won't stop a submodule's work
+tree from being removed.
+
+If you only want to remove the local checkout of a submodule from your
+work tree without committing the removal, use linkgit:git-submodule[1] `deinit`
+instead. Also see linkgit:gitsubmodules[7] for details on submodule removal.
+
+EXAMPLES
+--------
+`git rm Documentation/\*.txt`::
+	Removes all `*.txt` files from the index that are under the
+	`Documentation` directory and any of its subdirectories.
++
+Note that the asterisk `*` is quoted from the shell in this
+example; this lets Git, and not the shell, expand the pathnames
+of files and subdirectories under the `Documentation/` directory.
+
+`git rm -f git-*.sh`::
+	Because this example lets the shell expand the asterisk
+	(i.e. you are listing the files explicitly), it
+	does not remove `subdir/git-foo.sh`.
+
+BUGS
+----
+Each time a superproject update removes a populated submodule
+(e.g. when switching between commits before and after the removal) a
+stale submodule checkout will remain in the old location. Removing the
+old directory is only safe when it uses a gitfile, as otherwise the
+history of the submodule will be deleted too. This step will be
+obsolete when recursive submodule update has been implemented.
+
+SEE ALSO
+--------
+linkgit:git-add[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-send-email.adoc b/Documentation/git-send-email.adoc
new file mode 100644
index 0000000000..94bffa25d4
--- /dev/null
+++ b/Documentation/git-send-email.adoc
@@ -0,0 +1,543 @@
+git-send-email(1)
+=================
+
+NAME
+----
+git-send-email - Send a collection of patches as emails
+
+
+SYNOPSIS
+--------
+[verse]
+'git send-email' [<options>] (<file>|<directory>)...
+'git send-email' [<options>] <format-patch-options>
+'git send-email' --dump-aliases
+'git send-email' --translate-aliases
+
+
+DESCRIPTION
+-----------
+Takes the patches given on the command line and emails them out.
+Patches can be specified as files, directories (which will send all
+files in the directory), or directly as a revision list.  In the
+last case, any format accepted by linkgit:git-format-patch[1] can
+be passed to git send-email, as well as options understood by
+linkgit:git-format-patch[1].
+
+The header of the email is configurable via command-line options.  If not
+specified on the command line, the user will be prompted with a ReadLine
+enabled interface to provide the necessary information.
+
+There are two formats accepted for patch files:
+
+1. mbox format files
++
+This is what linkgit:git-format-patch[1] generates.  Most headers and MIME
+formatting are ignored.
+
+2. The original format used by Greg Kroah-Hartman's 'send_lots_of_email.pl'
+   script
++
+This format expects the first line of the file to contain the "Cc:" value
+and the "Subject:" of the message as the second line.
+
+
+OPTIONS
+-------
+
+Composing
+~~~~~~~~~
+
+--annotate::
+	Review and edit each patch you're about to send. Default is the value
+	of `sendemail.annotate`. See the CONFIGURATION section for
+	`sendemail.multiEdit`.
+
+--bcc=<address>,...::
+	Specify a "Bcc:" value for each email. Default is the value of
+	`sendemail.bcc`.
++
+This option may be specified multiple times.
+
+--cc=<address>,...::
+	Specify a starting "Cc:" value for each email.
+	Default is the value of `sendemail.cc`.
++
+This option may be specified multiple times.
+
+--compose::
+	Invoke a text editor (see GIT_EDITOR in linkgit:git-var[1])
+	to edit an introductory message for the patch series.
++
+When `--compose` is used, git send-email will use the From, To, Cc, Bcc,
+Subject, Reply-To, and In-Reply-To headers specified in the message. If
+the body of the message (what you type after the headers and a blank
+line) only contains blank (or Git: prefixed) lines, the summary won't be
+sent, but the headers mentioned above will be used unless they are
+removed.
++
+Missing From or In-Reply-To headers will be prompted for.
++
+See the CONFIGURATION section for `sendemail.multiEdit`.
+
+--from=<address>::
+	Specify the sender of the emails.  If not specified on the command line,
+	the value of the `sendemail.from` configuration option is used.  If
+	neither the command-line option nor `sendemail.from` are set, then the
+	user will be prompted for the value.  The default for the prompt will be
+	the value of GIT_AUTHOR_IDENT, or GIT_COMMITTER_IDENT if that is not
+	set, as returned by "git var -l".
+
+--reply-to=<address>::
+	Specify the address where replies from recipients should go to.
+	Use this if replies to messages should go to another address than what
+	is specified with the --from parameter.
+
+--in-reply-to=<identifier>::
+	Make the first mail (or all the mails with `--no-thread`) appear as a
+	reply to the given Message-ID, which avoids breaking threads to
+	provide a new patch series.
+	The second and subsequent emails will be sent as replies according to
+	the `--[no-]chain-reply-to` setting.
++
+So for example when `--thread` and `--no-chain-reply-to` are specified, the
+second and subsequent patches will be replies to the first one like in the
+illustration below where `[PATCH v2 0/3]` is in reply to `[PATCH 0/2]`:
++
+  [PATCH 0/2] Here is what I did...
+    [PATCH 1/2] Clean up and tests
+    [PATCH 2/2] Implementation
+    [PATCH v2 0/3] Here is a reroll
+      [PATCH v2 1/3] Clean up
+      [PATCH v2 2/3] New tests
+      [PATCH v2 3/3] Implementation
++
+Only necessary if --compose is also set.  If --compose
+is not set, this will be prompted for.
+
+--subject=<string>::
+	Specify the initial subject of the email thread.
+	Only necessary if --compose is also set.  If --compose
+	is not set, this will be prompted for.
+
+--to=<address>,...::
+	Specify the primary recipient of the emails generated. Generally, this
+	will be the upstream maintainer of the project involved. Default is the
+	value of the `sendemail.to` configuration value; if that is unspecified,
+	and --to-cmd is not specified, this will be prompted for.
++
+This option may be specified multiple times.
+
+--8bit-encoding=<encoding>::
+	When encountering a non-ASCII message or subject that does not
+	declare its encoding, add headers/quoting to indicate it is
+	encoded in <encoding>.  Default is the value of the
+	'sendemail.assume8bitEncoding'; if that is unspecified, this
+	will be prompted for if any non-ASCII files are encountered.
++
+Note that no attempts whatsoever are made to validate the encoding.
+
+--compose-encoding=<encoding>::
+	Specify encoding of compose message. Default is the value of the
+	'sendemail.composeEncoding'; if that is unspecified, UTF-8 is assumed.
+
+--transfer-encoding=(7bit|8bit|quoted-printable|base64|auto)::
+	Specify the transfer encoding to be used to send the message over SMTP.
+	7bit will fail upon encountering a non-ASCII message.  quoted-printable
+	can be useful when the repository contains files that contain carriage
+	returns, but makes the raw patch email file (as saved from a MUA) much
+	harder to inspect manually.  base64 is even more fool proof, but also
+	even more opaque.  auto will use 8bit when possible, and quoted-printable
+	otherwise.
++
+Default is the value of the `sendemail.transferEncoding` configuration
+value; if that is unspecified, default to `auto`.
+
+--xmailer::
+--no-xmailer::
+	Add (or prevent adding) the "X-Mailer:" header.  By default,
+	the header is added, but it can be turned off by setting the
+	`sendemail.xmailer` configuration variable to `false`.
+
+Sending
+~~~~~~~
+
+--envelope-sender=<address>::
+	Specify the envelope sender used to send the emails.
+	This is useful if your default address is not the address that is
+	subscribed to a list. In order to use the 'From' address, set the
+	value to "auto". If you use the sendmail binary, you must have
+	suitable privileges for the -f parameter.  Default is the value of the
+	`sendemail.envelopeSender` configuration variable; if that is
+	unspecified, choosing the envelope sender is left to your MTA.
+
+--sendmail-cmd=<command>::
+	Specify a command to run to send the email. The command should
+	be sendmail-like; specifically, it must support the `-i` option.
+	The command will be executed in the shell if necessary.  Default
+	is the value of `sendemail.sendmailCmd`.  If unspecified, and if
+	--smtp-server is also unspecified, git-send-email will search
+	for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH.
+
+--smtp-encryption=<encryption>::
+	Specify in what way encrypting begins for the SMTP connection.
+	Valid values are 'ssl' and 'tls'. Any other value reverts to plain
+	(unencrypted) SMTP, which defaults to port 25.
+	Despite the names, both values will use the same newer version of TLS,
+	but for historic reasons have these names. 'ssl' refers to "implicit"
+	encryption (sometimes called SMTPS), that uses port 465 by default.
+	'tls' refers to "explicit" encryption (often known as STARTTLS),
+	that uses port 25 by default. Other ports might be used by the SMTP
+	server, which are not the default. Commonly found alternative port for
+	'tls' and unencrypted is 587. You need to check your provider's
+	documentation or your server configuration to make sure
+	for your own case. Default is the value of `sendemail.smtpEncryption`.
+
+--smtp-domain=<FQDN>::
+	Specifies the Fully Qualified Domain Name (FQDN) used in the
+	HELO/EHLO command to the SMTP server.  Some servers require the
+	FQDN to match your IP address.  If not set, git send-email attempts
+	to determine your FQDN automatically.  Default is the value of
+	`sendemail.smtpDomain`.
+
+--smtp-auth=<mechanisms>::
+	Whitespace-separated list of allowed SMTP-AUTH mechanisms. This setting
+	forces using only the listed mechanisms. Example:
++
+------
+$ git send-email --smtp-auth="PLAIN LOGIN GSSAPI" ...
+------
++
+If at least one of the specified mechanisms matches the ones advertised by the
+SMTP server and if it is supported by the utilized SASL library, the mechanism
+is used for authentication. If neither 'sendemail.smtpAuth' nor `--smtp-auth`
+is specified, all mechanisms supported by the SASL library can be used. The
+special value 'none' maybe specified to completely disable authentication
+independently of `--smtp-user`
+
+--smtp-pass[=<password>]::
+	Password for SMTP-AUTH. The argument is optional: If no
+	argument is specified, then the empty string is used as
+	the password. Default is the value of `sendemail.smtpPass`,
+	however `--smtp-pass` always overrides this value.
++
+Furthermore, passwords need not be specified in configuration files
+or on the command line. If a username has been specified (with
+`--smtp-user` or a `sendemail.smtpUser`), but no password has been
+specified (with `--smtp-pass` or `sendemail.smtpPass`), then
+a password is obtained using 'git-credential'.
+
+--no-smtp-auth::
+	Disable SMTP authentication. Short hand for `--smtp-auth=none`
+
+--smtp-server=<host>::
+	If set, specifies the outgoing SMTP server to use (e.g.
+	`smtp.example.com` or a raw IP address).  If unspecified, and if
+	`--sendmail-cmd` is also unspecified, the default is to search
+	for `sendmail` in `/usr/sbin`, `/usr/lib` and $PATH if such a
+	program is available, falling back to `localhost` otherwise.
++
+For backward compatibility, this option can also specify a full pathname
+of a sendmail-like program instead; the program must support the `-i`
+option.  This method does not support passing arguments or using plain
+command names.  For those use cases, consider using `--sendmail-cmd`
+instead.
+
+--smtp-server-port=<port>::
+	Specifies a port different from the default port (SMTP
+	servers typically listen to smtp port 25, but may also listen to
+	submission port 587, or the common SSL smtp port 465);
+	symbolic port names (e.g. "submission" instead of 587)
+	are also accepted. The port can also be set with the
+	`sendemail.smtpServerPort` configuration variable.
+
+--smtp-server-option=<option>::
+	If set, specifies the outgoing SMTP server option to use.
+	Default value can be specified by the `sendemail.smtpServerOption`
+	configuration option.
++
+The --smtp-server-option option must be repeated for each option you want
+to pass to the server. Likewise, different lines in the configuration files
+must be used for each option.
+
+--smtp-ssl::
+	Legacy alias for '--smtp-encryption ssl'.
+
+--smtp-ssl-cert-path::
+	Path to a store of trusted CA certificates for SMTP SSL/TLS
+	certificate validation (either a directory that has been processed
+	by 'c_rehash', or a single file containing one or more PEM format
+	certificates concatenated together: see verify(1) -CAfile and
+	-CApath for more information on these). Set it to an empty string
+	to disable certificate verification. Defaults to the value of the
+	`sendemail.smtpSSLCertPath` configuration variable, if set, or the
+	backing SSL library's compiled-in default otherwise (which should
+	be the best choice on most platforms).
+
+--smtp-user=<user>::
+	Username for SMTP-AUTH. Default is the value of `sendemail.smtpUser`;
+	if a username is not specified (with `--smtp-user` or `sendemail.smtpUser`),
+	then authentication is not attempted.
+
+--smtp-debug=(0|1)::
+	Enable (1) or disable (0) debug output. If enabled, SMTP
+	commands and replies will be printed. Useful to debug TLS
+	connection and authentication problems.
+
+--batch-size=<num>::
+	Some email servers (e.g. smtp.163.com) limit the number emails to be
+	sent per session (connection) and this will lead to a failure when
+	sending many messages.  With this option, send-email will disconnect after
+	sending $<num> messages and wait for a few seconds (see --relogin-delay)
+	and reconnect, to work around such a limit.  You may want to
+	use some form of credential helper to avoid having to retype
+	your password every time this happens.  Defaults to the
+	`sendemail.smtpBatchSize` configuration variable.
+
+--relogin-delay=<int>::
+	Waiting $<int> seconds before reconnecting to SMTP server. Used together
+	with --batch-size option.  Defaults to the `sendemail.smtpReloginDelay`
+	configuration variable.
+
+Automating
+~~~~~~~~~~
+
+--no-to::
+--no-cc::
+--no-bcc::
+	Clears any list of "To:", "Cc:", "Bcc:" addresses previously
+	set via config.
+
+--no-identity::
+	Clears the previously read value of `sendemail.identity` set
+	via config, if any.
+
+--to-cmd=<command>::
+	Specify a command to execute once per patch file which
+	should generate patch file specific "To:" entries.
+	Output of this command must be single email address per line.
+	Default is the value of 'sendemail.toCmd' configuration value.
+
+--cc-cmd=<command>::
+	Specify a command to execute once per patch file which
+	should generate patch file specific "Cc:" entries.
+	Output of this command must be single email address per line.
+	Default is the value of `sendemail.ccCmd` configuration value.
+
+--header-cmd=<command>::
+	Specify a command that is executed once per outgoing message
+	and output RFC 2822 style header lines to be inserted into
+	them. When the `sendemail.headerCmd` configuration variable is
+	set, its value is always used. When --header-cmd is provided
+	at the command line, its value takes precedence over the
+	`sendemail.headerCmd` configuration variable.
+
+--no-header-cmd::
+	Disable any header command in use.
+
+--[no-]chain-reply-to::
+	If this is set, each email will be sent as a reply to the previous
+	email sent.  If disabled with "--no-chain-reply-to", all emails after
+	the first will be sent as replies to the first email sent.  When using
+	this, it is recommended that the first file given be an overview of the
+	entire patch series. Disabled by default, but the `sendemail.chainReplyTo`
+	configuration variable can be used to enable it.
+
+--identity=<identity>::
+	A configuration identity. When given, causes values in the
+	'sendemail.<identity>' subsection to take precedence over
+	values in the 'sendemail' section. The default identity is
+	the value of `sendemail.identity`.
+
+--[no-]signed-off-by-cc::
+	If this is set, add emails found in the `Signed-off-by` trailer or Cc: lines to the
+	cc list. Default is the value of `sendemail.signedOffByCc` configuration
+	value; if that is unspecified, default to --signed-off-by-cc.
+
+--[no-]cc-cover::
+	If this is set, emails found in Cc: headers in the first patch of
+	the series (typically the cover letter) are added to the cc list
+	for each email set. Default is the value of 'sendemail.ccCover'
+	configuration value; if that is unspecified, default to --no-cc-cover.
+
+--[no-]to-cover::
+	If this is set, emails found in To: headers in the first patch of
+	the series (typically the cover letter) are added to the to list
+	for each email set. Default is the value of 'sendemail.toCover'
+	configuration value; if that is unspecified, default to --no-to-cover.
+
+--suppress-cc=<category>::
+	Specify an additional category of recipients to suppress the
+	auto-cc of:
++
+--
+- 'author' will avoid including the patch author.
+- 'self' will avoid including the sender.
+- 'cc' will avoid including anyone mentioned in Cc lines in the patch header
+  except for self (use 'self' for that).
+- 'bodycc' will avoid including anyone mentioned in Cc lines in the
+  patch body (commit message) except for self (use 'self' for that).
+- 'sob' will avoid including anyone mentioned in the Signed-off-by trailers except
+  for self (use 'self' for that).
+- 'misc-by' will avoid including anyone mentioned in Acked-by,
+  Reviewed-by, Tested-by and other "-by" lines in the patch body,
+  except Signed-off-by (use 'sob' for that).
+- 'cccmd' will avoid running the --cc-cmd.
+- 'body' is equivalent to 'sob' + 'bodycc' + 'misc-by'.
+- 'all' will suppress all auto cc values.
+--
++
+Default is the value of `sendemail.suppressCc` configuration value; if
+that is unspecified, default to 'self' if --suppress-from is
+specified, as well as 'body' if --no-signed-off-cc is specified.
+
+--[no-]suppress-from::
+	If this is set, do not add the From: address to the cc: list.
+	Default is the value of `sendemail.suppressFrom` configuration
+	value; if that is unspecified, default to --no-suppress-from.
+
+--[no-]thread::
+	If this is set, the In-Reply-To and References headers will be
+	added to each email sent.  Whether each mail refers to the
+	previous email (`deep` threading per 'git format-patch'
+	wording) or to the first email (`shallow` threading) is
+	governed by "--[no-]chain-reply-to".
++
+If disabled with "--no-thread", those headers will not be added
+(unless specified with --in-reply-to).  Default is the value of the
+`sendemail.thread` configuration value; if that is unspecified,
+default to --thread.
++
+It is up to the user to ensure that no In-Reply-To header already
+exists when 'git send-email' is asked to add it (especially note that
+'git format-patch' can be configured to do the threading itself).
+Failure to do so may not produce the expected result in the
+recipient's MUA.
+
+--[no-]mailmap::
+	Use the mailmap file (see linkgit:gitmailmap[5]) to map all
+	addresses to their canonical real name and email address. Additional
+	mailmap data specific to git-send-email may be provided using the
+	`sendemail.mailmap.file` or `sendemail.mailmap.blob` configuration
+	values. Defaults to `sendemail.mailmap`.
+
+Administering
+~~~~~~~~~~~~~
+
+--confirm=<mode>::
+	Confirm just before sending:
++
+--
+- 'always' will always confirm before sending
+- 'never' will never confirm before sending
+- 'cc' will confirm before sending when send-email has automatically
+  added addresses from the patch to the Cc list
+- 'compose' will confirm before sending the first message when using --compose.
+- 'auto' is equivalent to 'cc' + 'compose'
+--
++
+Default is the value of `sendemail.confirm` configuration value; if that
+is unspecified, default to 'auto' unless any of the suppress options
+have been specified, in which case default to 'compose'.
+
+--dry-run::
+	Do everything except actually send the emails.
+
+--[no-]format-patch::
+	When an argument may be understood either as a reference or as a file name,
+	choose to understand it as a format-patch argument (`--format-patch`)
+	or as a file name (`--no-format-patch`). By default, when such a conflict
+	occurs, git send-email will fail.
+
+--quiet::
+	Make git-send-email less verbose.  One line per email should be
+	all that is output.
+
+--[no-]validate::
+	Perform sanity checks on patches.
+	Currently, validation means the following:
++
+--
+		*	Invoke the sendemail-validate hook if present (see linkgit:githooks[5]).
+		*	Warn of patches that contain lines longer than
+			998 characters unless a suitable transfer encoding
+			('auto', 'base64', or 'quoted-printable') is used;
+			this is due to SMTP limits as described by
+			https://www.ietf.org/rfc/rfc5322.txt.
+--
++
+Default is the value of `sendemail.validate`; if this is not set,
+default to `--validate`.
+
+--force::
+	Send emails even if safety checks would prevent it.
+
+
+Information
+~~~~~~~~~~~
+
+--dump-aliases::
+	Instead of the normal operation, dump the shorthand alias names from
+	the configured alias file(s), one per line in alphabetical order. Note
+	that this only includes the alias name and not its expanded email addresses.
+	See 'sendemail.aliasesFile' for more information about aliases.
+
+--translate-aliases::
+	Instead of the normal operation, read from standard input and
+	interpret each line as an email alias. Translate it according to the
+	configured alias file(s). Output each translated name and email
+	address to standard output, one per line. See 'sendemail.aliasFile'
+	for more information about aliases.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/sendemail.adoc[]
+
+EXAMPLES
+--------
+Use gmail as the smtp server
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+To use 'git send-email' to send your patches through the GMail SMTP server,
+edit ~/.gitconfig to specify your account settings:
+
+----
+[sendemail]
+	smtpEncryption = tls
+	smtpServer = smtp.gmail.com
+	smtpUser = yourname@xxxxxxxxx
+	smtpServerPort = 587
+----
+
+If you have multi-factor authentication set up on your Gmail account, you can
+generate an app-specific password for use with 'git send-email'. Visit
+https://security.google.com/settings/security/apppasswords to create it.
+
+Once your commits are ready to be sent to the mailing list, run the
+following commands:
+
+	$ git format-patch --cover-letter -M origin/master -o outgoing/
+	$ edit outgoing/0000-*
+	$ git send-email outgoing/*
+
+The first time you run it, you will be prompted for your credentials.  Enter the
+app-specific or your regular password as appropriate.  If you have credential
+helper configured (see linkgit:git-credential[1]), the password will be saved in
+the credential store so you won't have to type it the next time.
+
+Note: the following core Perl modules that may be installed with your
+distribution of Perl are required:
+MIME::Base64, MIME::QuotedPrint, Net::Domain and Net::SMTP.
+These additional Perl modules are also required:
+Authen::SASL and Mail::Address.
+
+
+SEE ALSO
+--------
+linkgit:git-format-patch[1], linkgit:git-imap-send[1], mbox(5)
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-send-pack.adoc b/Documentation/git-send-pack.adoc
new file mode 100644
index 0000000000..b9e73f2e77
--- /dev/null
+++ b/Documentation/git-send-pack.adoc
@@ -0,0 +1,157 @@
+git-send-pack(1)
+================
+
+NAME
+----
+git-send-pack - Push objects over Git protocol to another repository
+
+
+SYNOPSIS
+--------
+[verse]
+'git send-pack' [--mirror] [--dry-run] [--force]
+		[--receive-pack=<git-receive-pack>]
+		[--verbose] [--thin] [--atomic]
+		[--[no-]signed | --signed=(true|false|if-asked)]
+		[<host>:]<directory> (--all | <ref>...)
+
+DESCRIPTION
+-----------
+Usually you would want to use 'git push', which is a
+higher-level wrapper of this command, instead. See linkgit:git-push[1].
+
+Invokes 'git-receive-pack' on a possibly remote repository, and
+updates it from the current repository, sending named refs.
+
+
+OPTIONS
+-------
+--receive-pack=<git-receive-pack>::
+	Path to the 'git-receive-pack' program on the remote
+	end.  Sometimes useful when pushing to a remote
+	repository over ssh, and you do not have the program in
+	a directory on the default $PATH.
+
+--exec=<git-receive-pack>::
+	Same as --receive-pack=<git-receive-pack>.
+
+--all::
+	Instead of explicitly specifying which refs to update,
+	update all heads that locally exist.
+
+--stdin::
+	Take the list of refs from stdin, one per line. If there
+	are refs specified on the command line in addition to this
+	option, then the refs from stdin are processed after those
+	on the command line.
++
+If `--stateless-rpc` is specified together with this option then
+the list of refs must be in packet format (pkt-line). Each ref must
+be in a separate packet, and the list must end with a flush packet.
+
+--dry-run::
+	Do everything except actually send the updates.
+
+--force::
+	Usually, the command refuses to update a remote ref that
+	is not an ancestor of the local ref used to overwrite it.
+	This flag disables the check.  This means that
+	the remote repository can lose commits; use it with
+	care.
+
+--verbose::
+	Run verbosely.
+
+--thin::
+	Send a "thin" pack, which records objects in deltified form based
+	on objects not included in the pack to reduce network traffic.
+
+--atomic::
+	Use an atomic transaction for updating the refs. If any of the refs
+	fails to update then the entire push will fail without changing any
+	refs.
+
+--[no-]signed::
+--signed=(true|false|if-asked)::
+	GPG-sign the push request to update refs on the receiving
+	side, to allow it to be checked by the hooks and/or be
+	logged.  If `false` or `--no-signed`, no signing will be
+	attempted.  If `true` or `--signed`, the push will fail if the
+	server does not support signed pushes.  If set to `if-asked`,
+	sign if and only if the server supports signed pushes.  The push
+	will also fail if the actual call to `gpg --sign` fails.  See
+	linkgit:git-receive-pack[1] for the details on the receiving end.
+
+--push-option=<string>::
+	Pass the specified string as a push option for consumption by
+	hooks on the server side.  If the server doesn't support push
+	options, error out.  See linkgit:git-push[1] and
+	linkgit:githooks[5] for details.
+
+<host>::
+	A remote host to house the repository.  When this
+	part is specified, 'git-receive-pack' is invoked via
+	ssh.
+
+<directory>::
+	The repository to update.
+
+<ref>...::
+	The remote refs to update.
+
+
+SPECIFYING THE REFS
+-------------------
+
+There are three ways to specify which refs to update on the
+remote end.
+
+With the `--all` flag, all refs that exist locally are transferred to
+the remote side.  You cannot specify any '<ref>' if you use
+this flag.
+
+Without `--all` and without any '<ref>', the heads that exist
+both on the local side and on the remote side are updated.
+
+When one or more '<ref>' are specified explicitly (whether on the
+command line or via `--stdin`), it can be either a
+single pattern, or a pair of such patterns separated by a colon
+":" (this means that a ref name cannot have a colon in it).  A
+single pattern '<name>' is just shorthand for '<name>:<name>'.
+
+Each pattern pair consists of the source side (before the colon)
+and the destination side (after the colon).  The ref to be
+pushed is determined by finding a match that matches the source
+side, and where it is pushed is determined by using the
+destination side. The rules used to match a ref are the same
+rules used by 'git rev-parse' to resolve a symbolic ref
+name. See linkgit:git-rev-parse[1].
+
+ - It is an error if <src> does not match exactly one of the
+   local refs.
+
+ - It is an error if <dst> matches more than one remote ref.
+
+ - If <dst> does not match any remote ref, either
+
+   * it has to start with "refs/"; <dst> is used as the
+     destination literally in this case.
+
+   * <src> == <dst> and the ref that matched the <src> must not
+     exist in the set of remote refs; the ref matched <src>
+     locally is used as the name of the destination.
+
+Without `--force`, the <src> ref is stored at the remote only if
+<dst> does not exist, or <dst> is a proper subset (i.e. an
+ancestor) of <src>.  This check, known as the "fast-forward check",
+is performed to avoid accidentally overwriting the
+remote ref and losing other people's commits from there.
+
+With `--force`, the fast-forward check is disabled for all refs.
+
+Optionally, a <ref> parameter can be prefixed with a plus '+' sign
+to disable the fast-forward check only on that ref.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-sh-i18n--envsubst.adoc b/Documentation/git-sh-i18n--envsubst.adoc
new file mode 100644
index 0000000000..2ffaf9392e
--- /dev/null
+++ b/Documentation/git-sh-i18n--envsubst.adoc
@@ -0,0 +1,36 @@
+git-sh-i18n{litdd}envsubst(1)
+=============================
+
+NAME
+----
+git-sh-i18n--envsubst - Git's own envsubst(1) for i18n fallbacks
+
+SYNOPSIS
+--------
+[verse]
+eval_gettext () {
+	printf "%s" "$1" | (
+		export PATH $('git sh-i18n{litdd}envsubst' --variables "$1");
+		'git sh-i18n{litdd}envsubst' "$1"
+	)
+}
+
+DESCRIPTION
+-----------
+
+This is not a command the end user would want to run.  Ever.
+This documentation is meant for people who are studying the
+plumbing scripts and/or are writing new ones.
+
+'git sh-i18n{litdd}envsubst' is Git's stripped-down copy of the GNU
+`envsubst(1)` program that comes with the GNU gettext package. It's
+used internally by linkgit:git-sh-i18n[1] to interpolate the variables
+passed to the `eval_gettext` function.
+
+No promises are made about the interface, or that this
+program won't disappear without warning in the next version
+of Git. Don't use it.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-sh-i18n.adoc b/Documentation/git-sh-i18n.adoc
new file mode 100644
index 0000000000..60cf49cb2a
--- /dev/null
+++ b/Documentation/git-sh-i18n.adoc
@@ -0,0 +1,43 @@
+git-sh-i18n(1)
+==============
+
+NAME
+----
+git-sh-i18n - Git's i18n setup code for shell scripts
+
+SYNOPSIS
+--------
+[verse]
+'. "$(git --exec-path)/git-sh-i18n"'
+
+DESCRIPTION
+-----------
+
+This is not a command the end user would want to run.  Ever.
+This documentation is meant for people who are studying the
+Porcelain-ish scripts and/or are writing new ones.
+
+The 'git sh-i18n scriptlet is designed to be sourced (using
+`.`) by Git's porcelain programs implemented in shell
+script. It provides wrappers for the GNU `gettext` and
+`eval_gettext` functions accessible through the `gettext.sh`
+script, and provides pass-through fallbacks on systems
+without GNU gettext.
+
+FUNCTIONS
+---------
+
+gettext::
+	Currently a dummy fall-through function implemented as a wrapper
+	around `printf(1)`. Will be replaced by a real gettext
+	implementation in a later version.
+
+eval_gettext::
+	Currently a dummy fall-through function implemented as a wrapper
+	around `printf(1)` with variables expanded by the
+	linkgit:git-sh-i18n{litdd}envsubst[1] helper. Will be replaced by a
+	real gettext implementation in a later version.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-sh-setup.adoc b/Documentation/git-sh-setup.adoc
new file mode 100644
index 0000000000..bdaf6e5fc4
--- /dev/null
+++ b/Documentation/git-sh-setup.adoc
@@ -0,0 +1,95 @@
+git-sh-setup(1)
+===============
+
+NAME
+----
+git-sh-setup - Common Git shell script setup code
+
+SYNOPSIS
+--------
+[verse]
+'. "$(git --exec-path)/git-sh-setup"'
+
+DESCRIPTION
+-----------
+
+This is not a command the end user would want to run.  Ever.
+This documentation is meant for people who are studying the
+Porcelain-ish scripts and/or are writing new ones.
+
+The 'git sh-setup' scriptlet is designed to be sourced (using
+`.`) by other shell scripts to set up some variables pointing at
+the normal Git directories and a few helper shell functions.
+
+Before sourcing it, your script should set up a few variables;
+`USAGE` (and `LONG_USAGE`, if any) is used to define the message
+given by `usage()` shell function.  `SUBDIRECTORY_OK` can be set
+if the script can run from a subdirectory of the working tree
+(some commands do not).
+
+The scriptlet sets `GIT_DIR` and `GIT_OBJECT_DIRECTORY` shell
+variables, but does *not* export them to the environment.
+
+FUNCTIONS
+---------
+
+die::
+	exit after emitting the supplied error message to the
+	standard error stream.
+
+usage::
+	die with the usage message.
+
+set_reflog_action::
+	Set `GIT_REFLOG_ACTION` environment to a given string (typically
+	the name of the program) unless it is already set.  Whenever
+	the script runs a `git` command that updates refs, a reflog
+	entry is created using the value of this string to leave the
+	record of what command updated the ref.
+
+git_editor::
+	runs an editor of user's choice (GIT_EDITOR, core.editor, VISUAL or
+	EDITOR) on a given file, but error out if no editor is specified
+	and the terminal is dumb.
+
+is_bare_repository::
+	outputs `true` or `false` to the standard output stream
+	to indicate if the repository is a bare repository
+	(i.e. without an associated working tree).
+
+cd_to_toplevel::
+	runs chdir to the toplevel of the working tree.
+
+require_work_tree::
+	checks if the current directory is within the working tree
+	of the repository, and otherwise dies.
+
+require_work_tree_exists::
+	checks if the working tree associated with the repository
+	exists, and otherwise dies.  Often done before calling
+	cd_to_toplevel, which is impossible to do if there is no
+	working tree.
+
+require_clean_work_tree <action> [<hint>]::
+	checks that the working tree and index associated with the
+	repository have no uncommitted changes to tracked files.
+	Otherwise it emits an error message of the form `Cannot
+	<action>: <reason>. <hint>`, and dies.  Example:
++
+----------------
+require_clean_work_tree rebase "Please commit or stash them."
+----------------
+
+get_author_ident_from_commit::
+	outputs code for use with eval to set the GIT_AUTHOR_NAME,
+	GIT_AUTHOR_EMAIL and GIT_AUTHOR_DATE variables for a given commit.
+
+create_virtual_base::
+	modifies the first file so only lines in common with the
+	second file remain. If there is insufficient common material,
+	then the first file is left empty. The result is suitable
+	as a virtual base input for a 3-way merge.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-shell.adoc b/Documentation/git-shell.adoc
new file mode 100644
index 0000000000..11361f33e9
--- /dev/null
+++ b/Documentation/git-shell.adoc
@@ -0,0 +1,106 @@
+git-shell(1)
+============
+
+NAME
+----
+git-shell - Restricted login shell for Git-only SSH access
+
+
+SYNOPSIS
+--------
+[verse]
+'chsh' -s $(command -v git-shell) <user>
+'git clone' <user>`@localhost:/path/to/repo.git`
+'ssh' <user>`@localhost`
+
+DESCRIPTION
+-----------
+
+This is a login shell for SSH accounts to provide restricted Git access.
+It permits execution only of server-side Git commands implementing the
+pull/push functionality, plus custom commands present in a subdirectory
+named `git-shell-commands` in the user's home directory.
+
+COMMANDS
+--------
+
+'git shell' accepts the following commands after the `-c` option:
+
+'git receive-pack <argument>'::
+'git upload-pack <argument>'::
+'git upload-archive <argument>'::
+	Call the corresponding server-side command to support
+	the client's 'git push', 'git fetch', or 'git archive --remote'
+	request.
+'cvs server'::
+	Imitate a CVS server.  See linkgit:git-cvsserver[1].
+
+If a `~/git-shell-commands` directory is present, 'git shell' will
+also handle other, custom commands by running
+"`git-shell-commands/<command> <arguments>`" from the user's home
+directory.
+
+INTERACTIVE USE
+---------------
+
+By default, the commands above can be executed only with the `-c`
+option; the shell is not interactive.
+
+If a `~/git-shell-commands` directory is present, 'git shell'
+can also be run interactively (with no arguments).  If a `help`
+command is present in the `git-shell-commands` directory, it is
+run to provide the user with an overview of allowed actions.  Then a
+"git> " prompt is presented at which one can enter any of the
+commands from the `git-shell-commands` directory, or `exit` to close
+the connection.
+
+Generally this mode is used as an administrative interface to allow
+users to list repositories they have access to, create, delete, or
+rename repositories, or change repository descriptions and
+permissions.
+
+If a `no-interactive-login` command exists, then it is run and the
+interactive shell is aborted.
+
+EXAMPLES
+--------
+
+To disable interactive logins, displaying a greeting instead:
+
+----------------
+$ chsh -s /usr/bin/git-shell
+$ mkdir $HOME/git-shell-commands
+$ cat >$HOME/git-shell-commands/no-interactive-login <<\EOF
+#!/bin/sh
+printf '%s\n' "Hi $USER! You've successfully authenticated, but I do not"
+printf '%s\n' "provide interactive shell access."
+exit 128
+EOF
+$ chmod +x $HOME/git-shell-commands/no-interactive-login
+----------------
+
+To enable git-cvsserver access (which should generally have the
+`no-interactive-login` example above as a prerequisite, as creating
+the git-shell-commands directory allows interactive logins):
+
+----------------
+$ cat >$HOME/git-shell-commands/cvs <<\EOF
+if ! test $# = 1 && test "$1" = "server"
+then
+	echo >&2 "git-cvsserver only handles \"server\""
+	exit 1
+fi
+exec git cvsserver server
+EOF
+$ chmod +x $HOME/git-shell-commands/cvs
+----------------
+
+SEE ALSO
+--------
+ssh(1),
+linkgit:git-daemon[1],
+contrib/git-shell-commands/README
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-shortlog.adoc b/Documentation/git-shortlog.adoc
new file mode 100644
index 0000000000..d8ab38dcc1
--- /dev/null
+++ b/Documentation/git-shortlog.adoc
@@ -0,0 +1,130 @@
+git-shortlog(1)
+===============
+
+NAME
+----
+git-shortlog - Summarize 'git log' output
+
+SYNOPSIS
+--------
+[verse]
+'git shortlog' [<options>] [<revision-range>] [[--] <path>...]
+git log --pretty=short | 'git shortlog' [<options>]
+
+DESCRIPTION
+-----------
+Summarizes 'git log' output in a format suitable for inclusion
+in release announcements. Each commit will be grouped by author and title.
+
+Additionally, "[PATCH]" will be stripped from the commit description.
+
+If no revisions are passed on the command line and either standard input
+is not a terminal or there is no current branch, 'git shortlog' will
+output a summary of the log read from standard input, without
+reference to the current repository.
+
+OPTIONS
+-------
+
+-n::
+--numbered::
+	Sort output according to the number of commits per author instead
+	of author alphabetic order.
+
+-s::
+--summary::
+	Suppress commit description and provide a commit count summary only.
+
+-e::
+--email::
+	Show the email address of each author.
+
+--format[=<format>]::
+	Instead of the commit subject, use some other information to
+	describe each commit.  '<format>' can be any string accepted
+	by the `--format` option of 'git log', such as '* [%h] %s'.
+	(See the "PRETTY FORMATS" section of linkgit:git-log[1].)
+
+	Each pretty-printed commit will be rewrapped before it is shown.
+
+--date=<format>::
+	Show dates formatted according to the given date string. (See
+	the `--date` option in the "Commit Formatting" section of
+	linkgit:git-log[1]). Useful with `--group=format:<format>`.
+
+--group=<type>::
+	Group commits based on `<type>`. If no `--group` option is
+	specified, the default is `author`. `<type>` is one of:
++
+--
+ - `author`, commits are grouped by author
+ - `committer`, commits are grouped by committer (the same as `-c`)
+ - `trailer:<field>`, the `<field>` is interpreted as a case-insensitive
+   commit message trailer (see linkgit:git-interpret-trailers[1]). For
+   example, if your project uses `Reviewed-by` trailers, you might want
+   to see who has been reviewing with
+   `git shortlog -ns --group=trailer:reviewed-by`.
+ - `format:<format>`, any string accepted by the `--format` option of
+   'git log'. (See the "PRETTY FORMATS" section of
+   linkgit:git-log[1].)
++
+Note that commits that do not include the trailer will not be counted.
+Likewise, commits with multiple trailers (e.g., multiple signoffs) may
+be counted more than once (but only once per unique trailer value in
+that commit).
++
+Shortlog will attempt to parse each trailer value as a `name <email>`
+identity. If successful, the mailmap is applied and the email is omitted
+unless the `--email` option is specified. If the value cannot be parsed
+as an identity, it will be taken literally and completely.
+--
++
+If `--group` is specified multiple times, commits are counted under each
+value (but again, only once per unique value in that commit). For
+example, `git shortlog --group=author --group=trailer:co-authored-by`
+counts both authors and co-authors.
+
+-c::
+--committer::
+	This is an alias for `--group=committer`.
+
+-w[<width>[,<indent1>[,<indent2>]]]::
+	Linewrap the output by wrapping each line at `width`.  The first
+	line of each entry is indented by `indent1` spaces, and the second
+	and subsequent lines are indented by `indent2` spaces. `width`,
+	`indent1`, and `indent2` default to 76, 6 and 9 respectively.
++
+If width is `0` (zero) then indent the lines of the output without wrapping
+them.
+
+<revision-range>::
+	Show only commits in the specified revision range.  When no
+	<revision-range> is specified, it defaults to `HEAD` (i.e. the
+	whole history leading to the current commit).  `origin..HEAD`
+	specifies all the commits reachable from the current commit
+	(i.e. `HEAD`), but not from `origin`. For a complete list of
+	ways to spell <revision-range>, see the "Specifying Ranges"
+	section of linkgit:gitrevisions[7].
+
+[--] <path>...::
+	Consider only commits that are enough to explain how the files
+	that match the specified paths came to be.
++
+Paths may need to be prefixed with `--` to separate them from
+options or the revision range, when confusion arises.
+
+:git-shortlog: 1
+include::rev-list-options.adoc[]
+
+MAPPING AUTHORS
+---------------
+
+See linkgit:gitmailmap[5].
+
+Note that if `git shortlog` is run outside of a repository (to process
+log contents on standard input), it will look for a `.mailmap` file in
+the current directory.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-show-branch.adoc b/Documentation/git-show-branch.adoc
new file mode 100644
index 0000000000..7cb6620345
--- /dev/null
+++ b/Documentation/git-show-branch.adoc
@@ -0,0 +1,211 @@
+git-show-branch(1)
+==================
+
+NAME
+----
+git-show-branch - Show branches and their commits
+
+SYNOPSIS
+--------
+[verse]
+'git show-branch' [-a | --all] [-r | --remotes] [--topo-order | --date-order]
+		[--current] [--color[=<when>] | --no-color] [--sparse]
+		[--more=<n> | --list | --independent | --merge-base]
+		[--no-name | --sha1-name] [--topics]
+		[(<rev> | <glob>)...]
+'git show-branch' (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]
+
+DESCRIPTION
+-----------
+
+Shows the commit ancestry graph starting from the commits named
+with <rev>s or <glob>s (or all refs under refs/heads
+and/or refs/tags) semi-visually.
+
+It cannot show more than 26 branches and commits at a time.
+
+It uses `showbranch.default` multi-valued configuration items if
+no <rev> or <glob> is given on the command line.
+
+
+OPTIONS
+-------
+<rev>::
+	Arbitrary extended SHA-1 expression (see linkgit:gitrevisions[7])
+	that typically names a branch head or a tag.
+
+<glob>::
+	A glob pattern that matches branch or tag names under
+	refs/.  For example, if you have many topic
+	branches under refs/heads/topic, giving
+	`topic/*` would show all of them.
+
+-r::
+--remotes::
+	Show the remote-tracking branches.
+
+-a::
+--all::
+	Show both remote-tracking branches and local branches.
+
+--current::
+	With this option, the command includes the current
+	branch in the list of revs to be shown when it is not
+	given on the command line.
+
+--topo-order::
+        By default, the branches and their commits are shown in
+        reverse chronological order.  This option makes them
+        appear in topological order (i.e., descendant commits
+        are shown before their parents).
+
+--date-order::
+	This option is similar to `--topo-order` in the sense that no
+	parent comes before all of its children, but otherwise commits
+	are ordered according to their commit date.
+
+--sparse::
+	By default, the output omits merges that are reachable
+	from only one tip being shown.  This option makes them
+	visible.
+
+--more=<n>::
+	Usually the command stops output upon showing the commit
+	that is the common ancestor of all the branches.  This
+	flag tells the command to go <n> more common commits
+	beyond that.  When <n> is negative, display only the
+	<ref>s given, without showing the commit ancestry tree.
+
+--list::
+	Synonym to `--more=-1`
+
+--merge-base::
+	Instead of showing the commit list, determine possible
+	merge bases for the specified commits. All merge bases
+	will be contained in all specified commits. This is
+	different from how linkgit:git-merge-base[1] handles
+	the case of three or more commits.
+
+--independent::
+	Among the <ref>s given, display only the ones that cannot be
+	reached from any other <ref>.
+
+--no-name::
+	Do not show naming strings for each commit.
+
+--sha1-name::
+	Instead of naming the commits using the path to reach
+	them from heads (e.g. "master~2" to mean the grandparent
+	of "master"), name them with the unique prefix of their
+	object names.
+
+--topics::
+	Shows only commits that are NOT on the first branch given.
+	This helps track topic branches by hiding any commit that
+	is already in the main line of development.  When given
+	"git show-branch --topics master topic1 topic2", this
+	will show the revisions given by "git rev-list {caret}master
+	topic1 topic2"
+
+-g::
+--reflog[=<n>[,<base>]] [<ref>]::
+	Shows <n> most recent ref-log entries for the given
+	ref.  If <base> is given, <n> entries going back from
+	that entry.  <base> can be specified as count or date.
+	When no explicit <ref> parameter is given, it defaults to the
+	current branch (or `HEAD` if it is detached).
+
+--color[=<when>]::
+	Color the status sign (one of these: `*` `!` `+` `-`) of each commit
+	corresponding to the branch it's in.
+	The value must be always (the default), never, or auto.
+
+--no-color::
+	Turn off colored output, even when the configuration file gives the
+	default to color output.
+	Same as `--color=never`.
+
+Note that --more, --list, --independent, and --merge-base options
+are mutually exclusive.
+
+
+OUTPUT
+------
+
+Given N <ref>s, the first N lines are the one-line description from
+their commit message. The branch head that is pointed at by
+$GIT_DIR/HEAD is prefixed with an asterisk `*` character while other
+heads are prefixed with a `!` character.
+
+Following these N lines, a one-line log for each commit is
+displayed, indented N places.  If a commit is on the I-th
+branch, the I-th indentation character shows a `+` sign;
+otherwise it shows a space.  Merge commits are denoted by
+a `-` sign.  Each commit shows a short name that
+can be used as an extended SHA-1 to name that commit.
+
+The following example shows three branches, "master", "fixes",
+and "mhf":
+
+------------------------------------------------
+$ git show-branch master fixes mhf
+* [master] Add 'git show-branch'.
+ ! [fixes] Introduce "reset type" flag to "git reset"
+  ! [mhf] Allow "+remote:local" refspec to cause --force when fetching.
+---
+  + [mhf] Allow "+remote:local" refspec to cause --force when fetching.
+  + [mhf~1] Use git-octopus when pulling more than one head.
+ +  [fixes] Introduce "reset type" flag to "git reset"
+  + [mhf~2] "git fetch --force".
+  + [mhf~3] Use .git/remote/origin, not .git/branches/origin.
+  + [mhf~4] Make "git pull" and "git fetch" default to origin
+  + [mhf~5] Infamous 'octopus merge'
+  + [mhf~6] Retire git-parse-remote.
+  + [mhf~7] Multi-head fetch.
+  + [mhf~8] Start adding the $GIT_DIR/remotes/ support.
+*++ [master] Add 'git show-branch'.
+------------------------------------------------
+
+These three branches all forked from a common commit, [master],
+whose commit message is "Add \'git show-branch'".
+The "fixes" branch adds one commit "Introduce "reset type" flag to
+"git reset"". The "mhf" branch adds many other commits.
+The current branch is "master".
+
+
+EXAMPLES
+--------
+
+If you keep your primary branches immediately under
+`refs/heads`, and topic branches in subdirectories of
+it, having the following in the configuration file may help:
+
+------------
+[showbranch]
+	default = --topo-order
+	default = heads/*
+
+------------
+
+With this, `git show-branch` without extra parameters would show
+only the primary branches.  In addition, if you happen to be on
+your topic branch, it is shown as well.
+
+------------
+$ git show-branch --reflog="10,1 hour ago" --list master
+------------
+
+shows 10 reflog entries going back from the tip as of 1 hour ago.
+Without `--list`, the output also shows how these tips are
+topologically related to each other.
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/showbranch.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-show-index.adoc b/Documentation/git-show-index.adoc
new file mode 100644
index 0000000000..f0e40e6164
--- /dev/null
+++ b/Documentation/git-show-index.adoc
@@ -0,0 +1,52 @@
+git-show-index(1)
+=================
+
+NAME
+----
+git-show-index - Show packed archive index
+
+
+SYNOPSIS
+--------
+[verse]
+'git show-index' [--object-format=<hash-algorithm>]
+
+
+DESCRIPTION
+-----------
+Read the `.idx` file for a Git packfile (created with
+linkgit:git-pack-objects[1] or linkgit:git-index-pack[1]) from the
+standard input, and dump its contents. The output consists of one object
+per line, with each line containing two or three space-separated
+columns:
+
+  - the first column is the offset in bytes of the object within the
+    corresponding packfile
+
+  - the second column is the object id of the object
+
+  - if the index version is 2 or higher, the third column contains the
+    CRC32 of the object data
+
+The objects are output in the order in which they are found in the index
+file, which should be (in a correctly constructed file) sorted by object
+id.
+
+Note that you can get more information on a packfile by calling
+linkgit:git-verify-pack[1]. However, as this command considers only the
+index file itself, it's both faster and more flexible.
+
+OPTIONS
+-------
+
+--object-format=<hash-algorithm>::
+	Specify the given object format (hash algorithm) for the index file.  The
+	valid values are 'sha1' and (if enabled) 'sha256'.  The default is the
+	algorithm for the current repository (set by `extensions.objectFormat`), or
+	'sha1' if no value is set or outside a repository..
++
+include::object-format-disclaimer.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-show-ref.adoc b/Documentation/git-show-ref.adoc
new file mode 100644
index 0000000000..616d919655
--- /dev/null
+++ b/Documentation/git-show-ref.adoc
@@ -0,0 +1,214 @@
+git-show-ref(1)
+===============
+
+NAME
+----
+git-show-ref - List references in a local repository
+
+SYNOPSIS
+--------
+[verse]
+'git show-ref' [--head] [-d | --dereference]
+	     [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]
+	     [--] [<pattern>...]
+'git show-ref' --verify [-q | --quiet] [-d | --dereference]
+	     [-s | --hash[=<n>]] [--abbrev[=<n>]]
+	     [--] [<ref>...]
+'git show-ref' --exclude-existing[=<pattern>]
+'git show-ref' --exists <ref>
+
+DESCRIPTION
+-----------
+
+Displays references available in a local repository along with the associated
+commit IDs. Results can be filtered using a pattern and tags can be
+dereferenced into object IDs. Additionally, it can be used to test whether a
+particular ref exists.
+
+By default, shows the tags, heads, and remote refs.
+
+The `--exclude-existing` form is a filter that does the inverse. It reads
+refs from stdin, one ref per line, and shows those that don't exist in
+the local repository.
+
+The `--exists` form can be used to check for the existence of a single
+references. This form does not verify whether the reference resolves to an
+actual object.
+
+Use of this utility is encouraged in favor of directly accessing files under
+the `.git` directory.
+
+OPTIONS
+-------
+
+--head::
+
+	Show the HEAD reference, even if it would normally be filtered out.
+
+--branches::
+--tags::
+
+	Limit to local branches and local tags, respectively.  These options
+	are not mutually exclusive; when given both, references stored in
+	"refs/heads" and "refs/tags" are displayed.  Note that `--heads`
+	is a deprecated synonym for `--branches` and may be removed
+	in the future.
+
+-d::
+--dereference::
+
+	Dereference tags into object IDs as well. They will be shown with `^{}`
+	appended.
+
+-s::
+--hash[=<n>]::
+
+	Only show the OID, not the reference name. When combined with
+	`--dereference`, the dereferenced tag will still be shown after the OID.
+
+--verify::
+
+	Enable stricter reference checking by requiring an exact ref path.
+	Aside from returning an error code of 1, it will also print an error
+	message if `--quiet` was not specified.
+
+--exists::
+
+	Check whether the given reference exists. Returns an exit code of 0 if
+	it does, 2 if it is missing, and 1 in case looking up the reference
+	failed with an error other than the reference being missing.
+
+--abbrev[=<n>]::
+
+	Abbreviate the object name.  When using `--hash`, you do
+	not have to say `--hash --abbrev`; `--hash=n` would do.
+
+-q::
+--quiet::
+
+	Do not print any results to stdout. Can be used with `--verify` to
+	silently check if a reference exists.
+
+--exclude-existing[=<pattern>]::
+
+	Make `git show-ref` act as a filter that reads refs from stdin of the
+	form `^(?:<anything>\s)?<refname>(?:\^{})?$`
+	and performs the following actions on each:
+	(1) strip `^{}` at the end of line if any;
+	(2) ignore if pattern is provided and does not head-match refname;
+	(3) warn if refname is not a well-formed refname and skip;
+	(4) ignore if refname is a ref that exists in the local repository;
+	(5) otherwise output the line.
+
+
+<pattern>...::
+
+	Show references matching one or more patterns. Patterns are matched from
+	the end of the full name, and only complete parts are matched, e.g.
+	'master' matches 'refs/heads/master', 'refs/remotes/origin/master',
+	'refs/tags/jedi/master' but not 'refs/heads/mymaster' or
+	'refs/remotes/master/jedi'.
+
+OUTPUT
+------
+
+The output is in the format:
+
+------------
+<oid> SP <ref> LF
+------------
+
+For example,
+
+-----------------------------------------------------------------------------
+$ git show-ref --head --dereference
+832e76a9899f560a90ffd62ae2ce83bbeff58f54 HEAD
+832e76a9899f560a90ffd62ae2ce83bbeff58f54 refs/heads/master
+832e76a9899f560a90ffd62ae2ce83bbeff58f54 refs/heads/origin
+3521017556c5de4159da4615a39fa4d5d2c279b5 refs/tags/v0.99.9c
+6ddc0964034342519a87fe013781abf31c6db6ad refs/tags/v0.99.9c^{}
+055e4ae3ae6eb344cbabf2a5256a49ea66040131 refs/tags/v1.0rc4
+423325a2d24638ddcc82ce47be5e40be550f4507 refs/tags/v1.0rc4^{}
+...
+-----------------------------------------------------------------------------
+
+When using `--hash` (and not `--dereference`), the output is in the format:
+
+------------
+<oid> LF
+------------
+
+For example,
+
+-----------------------------------------------------------------------------
+$ git show-ref --branches --hash
+2e3ba0114a1f52b47df29743d6915d056be13278
+185008ae97960c8d551adcd9e23565194651b5d1
+03adf42c988195b50e1a1935ba5fcbc39b2b029b
+...
+-----------------------------------------------------------------------------
+
+EXAMPLES
+--------
+
+To show all references called "master", whether tags or heads or anything
+else, and regardless of how deep in the reference naming hierarchy they are,
+use:
+
+-----------------------------------------------------------------------------
+	git show-ref master
+-----------------------------------------------------------------------------
+
+This will show "refs/heads/master" but also "refs/remote/other-repo/master",
+if such references exist.
+
+When using the `--verify` flag, the command requires an exact path:
+
+-----------------------------------------------------------------------------
+	git show-ref --verify refs/heads/master
+-----------------------------------------------------------------------------
+
+will only match the exact branch called "master".
+
+If nothing matches, `git show-ref` will return an error code of 1,
+and in the case of verification, it will show an error message.
+
+For scripting, you can ask it to be quiet with the `--quiet` flag, which
+allows you to do things like
+
+-----------------------------------------------------------------------------
+	git show-ref --quiet --verify -- "refs/heads/$headname" ||
+		echo "$headname is not a valid branch"
+-----------------------------------------------------------------------------
+
+to check whether a particular branch exists or not (notice how we don't
+actually want to show any results, and we want to use the full refname for it
+in order to not trigger the problem with ambiguous partial matches).
+
+To show only tags, or only proper branch heads, use `--tags` and/or `--branches`
+respectively (using both means that it shows tags and branches, but not other
+random references under the refs/ subdirectory).
+
+To do automatic tag object dereferencing, use the `-d` or `--dereference`
+flag, so you can do
+
+-----------------------------------------------------------------------------
+	git show-ref --tags --dereference
+-----------------------------------------------------------------------------
+
+to get a listing of all tags together with what they dereference.
+
+FILES
+-----
+`.git/refs/*`, `.git/packed-refs`
+
+SEE ALSO
+--------
+linkgit:git-for-each-ref[1],
+linkgit:git-ls-remote[1],
+linkgit:git-update-ref[1],
+linkgit:gitrepository-layout[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-show.adoc b/Documentation/git-show.adoc
new file mode 100644
index 0000000000..51044c814f
--- /dev/null
+++ b/Documentation/git-show.adoc
@@ -0,0 +1,90 @@
+git-show(1)
+===========
+
+NAME
+----
+git-show - Show various types of objects
+
+
+SYNOPSIS
+--------
+[verse]
+'git show' [<options>] [<object>...]
+
+DESCRIPTION
+-----------
+Shows one or more objects (blobs, trees, tags and commits).
+
+For commits it shows the log message and textual diff. It also
+presents the merge commit in a special format as produced by
+'git diff-tree --cc'.
+
+For tags, it shows the tag message and the referenced objects.
+
+For trees, it shows the names (equivalent to 'git ls-tree'
+with --name-only).
+
+For plain blobs, it shows the plain contents.
+
+Some options that 'git log' command understands can be used to
+control how the changes the commit introduces are shown.
+
+This manual page describes only the most frequently used options.
+
+
+OPTIONS
+-------
+<object>...::
+	The names of objects to show (defaults to 'HEAD').
+	For a more complete list of ways to spell object names, see
+	"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
+
+include::pretty-options.adoc[]
+
+
+include::pretty-formats.adoc[]
+
+
+DIFF FORMATTING
+---------------
+The options below can be used to change the way `git show` generates
+diff output.
+
+:git-log: 1
+:diff-merges-default: `dense-combined`
+include::diff-options.adoc[]
+
+include::diff-generate-patch.adoc[]
+
+
+EXAMPLES
+--------
+
+`git show v1.0.0`::
+	Shows the tag `v1.0.0`, along with the object the tag
+	points at.
+
+`git show v1.0.0^{tree}`::
+	Shows the tree pointed to by the tag `v1.0.0`.
+
+`git show -s --format=%s v1.0.0^{commit}`::
+	Shows the subject of the commit pointed to by the
+	tag `v1.0.0`.
+
+`git show next~10:Documentation/README`::
+	Shows the contents of the file `Documentation/README` as
+	they were current in the 10th last commit of the branch
+	`next`.
+
+`git show master:Makefile master:t/Makefile`::
+	Concatenates the contents of said Makefiles in the head
+	of the branch `master`.
+
+DISCUSSION
+----------
+
+include::i18n.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-sparse-checkout.adoc b/Documentation/git-sparse-checkout.adoc
new file mode 100644
index 0000000000..529a8edd9c
--- /dev/null
+++ b/Documentation/git-sparse-checkout.adoc
@@ -0,0 +1,483 @@
+git-sparse-checkout(1)
+======================
+
+NAME
+----
+git-sparse-checkout - Reduce your working tree to a subset of tracked files
+
+
+SYNOPSIS
+--------
+[verse]
+'git sparse-checkout' (init | list | set | add | reapply | disable | check-rules) [<options>]
+
+
+DESCRIPTION
+-----------
+
+This command is used to create sparse checkouts, which change the
+working tree from having all tracked files present to only having a
+subset of those files.  It can also switch which subset of files are
+present, or undo and go back to having all tracked files present in
+the working copy.
+
+The subset of files is chosen by providing a list of directories in
+cone mode (the default), or by providing a list of patterns in
+non-cone mode.
+
+When in a sparse-checkout, other Git commands behave a bit differently.
+For example, switching branches will not update paths outside the
+sparse-checkout directories/patterns, and `git commit -a` will not record
+paths outside the sparse-checkout directories/patterns as deleted.
+
+THIS COMMAND IS EXPERIMENTAL. ITS BEHAVIOR, AND THE BEHAVIOR OF OTHER
+COMMANDS IN THE PRESENCE OF SPARSE-CHECKOUTS, WILL LIKELY CHANGE IN
+THE FUTURE.
+
+
+COMMANDS
+--------
+'list'::
+	Describe the directories or patterns in the sparse-checkout file.
+
+'set'::
+	Enable the necessary sparse-checkout config settings
+	(`core.sparseCheckout`, `core.sparseCheckoutCone`, and
+	`index.sparse`) if they are not already set to the desired values,
+	populate the sparse-checkout file from the list of arguments
+	following the 'set' subcommand, and update the working directory to
+	match.
++
+To ensure that adjusting the sparse-checkout settings within a worktree
+does not alter the sparse-checkout settings in other worktrees, the 'set'
+subcommand will upgrade your repository config to use worktree-specific
+config if not already present. The sparsity defined by the arguments to
+the 'set' subcommand are stored in the worktree-specific sparse-checkout
+file. See linkgit:git-worktree[1] and the documentation of
+`extensions.worktreeConfig` in linkgit:git-config[1] for more details.
++
+When the `--stdin` option is provided, the directories or patterns are
+read from standard in as a newline-delimited list instead of from the
+arguments.
++
+By default, the input list is considered a list of directories, matching
+the output of `git ls-tree -d --name-only`.  This includes interpreting
+pathnames that begin with a double quote (") as C-style quoted strings.
+Note that all files under the specified directories (at any depth) will
+be included in the sparse checkout, as well as files that are siblings
+of either the given directory or any of its ancestors (see 'CONE PATTERN
+SET' below for more details).  In the past, this was not the default,
+and `--cone` needed to be specified or `core.sparseCheckoutCone` needed
+to be enabled.
++
+When `--no-cone` is passed, the input list is considered a list of
+patterns.  This mode has a number of drawbacks, including not working
+with some options like `--sparse-index`.  As explained in the
+"Non-cone Problems" section below, we do not recommend using it.
++
+Use the `--[no-]sparse-index` option to use a sparse index (the
+default is to not use it).  A sparse index reduces the size of the
+index to be more closely aligned with your sparse-checkout
+definition. This can have significant performance advantages for
+commands such as `git status` or `git add`.  This feature is still
+experimental. Some commands might be slower with a sparse index until
+they are properly integrated with the feature.
++
+**WARNING:** Using a sparse index requires modifying the index in a way
+that is not completely understood by external tools. If you have trouble
+with this compatibility, then run `git sparse-checkout init --no-sparse-index`
+to rewrite your index to not be sparse. Older versions of Git will not
+understand the sparse directory entries index extension and may fail to
+interact with your repository until it is disabled.
+
+'add'::
+	Update the sparse-checkout file to include additional directories
+	(in cone mode) or patterns (in non-cone mode).  By default, these
+	directories or patterns are read from the command-line arguments,
+	but they can be read from stdin using the `--stdin` option.
+
+'reapply'::
+	Reapply the sparsity pattern rules to paths in the working tree.
+	Commands like merge or rebase can materialize paths to do their
+	work (e.g. in order to show you a conflict), and other
+	sparse-checkout commands might fail to sparsify an individual file
+	(e.g. because it has unstaged changes or conflicts).  In such
+	cases, it can make sense to run `git sparse-checkout reapply` later
+	after cleaning up affected paths (e.g. resolving conflicts, undoing
+	or committing changes, etc.).
++
+The `reapply` command can also take `--[no-]cone` and `--[no-]sparse-index`
+flags, with the same meaning as the flags from the `set` command, in order
+to change which sparsity mode you are using without needing to also respecify
+all sparsity paths.
+
+'disable'::
+	Disable the `core.sparseCheckout` config setting, and restore the
+	working directory to include all files.
+
+'init'::
+	Deprecated command that behaves like `set` with no specified paths.
+	May be removed in the future.
++
+Historically, `set` did not handle all the necessary config settings,
+which meant that both `init` and `set` had to be called.  Invoking
+both meant the `init` step would first remove nearly all tracked files
+(and in cone mode, ignored files too), then the `set` step would add
+many of the tracked files (but not ignored files) back.  In addition
+to the lost files, the performance and UI of this combination was
+poor.
++
+Also, historically, `init` would not actually initialize the
+sparse-checkout file if it already existed.  This meant it was
+possible to return to a sparse-checkout without remembering which
+paths to pass to a subsequent 'set' or 'add' command.  However,
+`--cone` and `--sparse-index` options would not be remembered across
+the disable command, so the easy restore of calling a plain `init`
+decreased in utility.
+
+'check-rules'::
+	Check whether sparsity rules match one or more paths.
++
+By default `check-rules` reads a list of paths from stdin and outputs only
+the ones that match the current sparsity rules. The input is expected to consist
+of one path per line, matching the output of `git ls-tree --name-only` including
+that pathnames that begin with a double quote (") are interpreted as C-style
+quoted strings.
++
+When called with the `--rules-file <file>` flag the input files are matched
+against the sparse checkout rules found in `<file>` instead of the current ones.
+The rules in the files are expected to be in the same form as accepted by `git
+sparse-checkout set --stdin` (in particular, they must be newline-delimited).
++
+By default, the rules passed to the `--rules-file` option are interpreted as
+cone mode directories. To pass non-cone mode patterns with `--rules-file`,
+combine the option with the `--no-cone` option.
++
+When called with the `-z` flag, the format of the paths input on stdin as well
+as the output paths are \0 terminated and not quoted. Note that this does not
+apply to the format of the rules passed with the `--rules-file` option.
+
+
+EXAMPLES
+--------
+`git sparse-checkout set MY/DIR1 SUB/DIR2`::
+
+	Change to a sparse checkout with all files (at any depth) under
+	MY/DIR1/ and SUB/DIR2/ present in the working copy (plus all
+	files immediately under MY/ and SUB/ and the toplevel
+	directory).  If already in a sparse checkout, change which files
+	are present in the working copy to this new selection.  Note
+	that this command will also delete all ignored files in any
+	directory that no longer has either tracked or
+	non-ignored-untracked files present.
+
+`git sparse-checkout disable`::
+
+	Repopulate the working directory with all files, disabling sparse
+	checkouts.
+
+`git sparse-checkout add SOME/DIR/ECTORY`::
+
+	Add all files under SOME/DIR/ECTORY/ (at any depth) to the
+	sparse checkout, as well as all files immediately under
+	SOME/DIR/ and immediately under SOME/.  Must already be in a
+	sparse checkout before using this command.
+
+`git sparse-checkout reapply`::
+
+	It is possible for commands to update the working tree in a
+	way that does not respect the selected sparsity directories.
+	This can come from tools external to Git writing files, or
+	even affect Git commands because of either special cases (such
+	as hitting conflicts when merging/rebasing), or because some
+	commands didn't fully support sparse checkouts (e.g. the old
+	`recursive` merge backend had only limited support).  This
+	command reapplies the existing sparse directory specifications
+	to make the working directory match.
+
+INTERNALS -- SPARSE CHECKOUT
+----------------------------
+
+"Sparse checkout" allows populating the working directory sparsely.  It
+uses the skip-worktree bit (see linkgit:git-update-index[1]) to tell Git
+whether a file in the working directory is worth looking at. If the
+skip-worktree bit is set, and the file is not present in the working tree,
+then its absence is ignored. Git will avoid populating the contents of
+those files, which makes a sparse checkout helpful when working in a
+repository with many files, but only a few are important to the current
+user.
+
+The `$GIT_DIR/info/sparse-checkout` file is used to define the
+skip-worktree reference bitmap. When Git updates the working
+directory, it updates the skip-worktree bits in the index based
+on this file. The files matching the patterns in the file will
+appear in the working directory, and the rest will not.
+
+INTERNALS -- NON-CONE PROBLEMS
+------------------------------
+
+The `$GIT_DIR/info/sparse-checkout` file populated by the `set` and
+`add` subcommands is defined to be a bunch of patterns (one per line)
+using the same syntax as `.gitignore` files.  In cone mode, these
+patterns are restricted to matching directories (and users only ever
+need supply or see directory names), while in non-cone mode any
+gitignore-style pattern is permitted.  Using the full gitignore-style
+patterns in non-cone mode has a number of shortcomings:
+
+  * Fundamentally, it makes various worktree-updating processes (pull,
+    merge, rebase, switch, reset, checkout, etc.) require O(N*M) pattern
+    matches, where N is the number of patterns and M is the number of
+    paths in the index.  This scales poorly.
+
+  * Avoiding the scaling issue has to be done via limiting the number
+    of patterns via specifying leading directory name or glob.
+
+  * Passing globs on the command line is error-prone as users may
+    forget to quote the glob, causing the shell to expand it into all
+    matching files and pass them all individually along to
+    sparse-checkout set/add.  While this could also be a problem with
+    e.g. "git grep -- *.c", mistakes with grep/log/status appear in
+    the immediate output.  With sparse-checkout, the mistake gets
+    recorded at the time the sparse-checkout command is run and might
+    not be problematic until the user later switches branches or rebases
+    or merges, thus putting a delay between the user's error and when
+    they have a chance to catch/notice it.
+
+  * Related to the previous item, sparse-checkout has an 'add'
+    subcommand but no 'remove' subcommand.  Even if a 'remove'
+    subcommand were added, undoing an accidental unquoted glob runs
+    the risk of "removing too much", as it may remove entries that had
+    been included before the accidental add.
+
+  * Non-cone mode uses gitignore-style patterns to select what to
+    *include* (with the exception of negated patterns), while
+    .gitignore files use gitignore-style patterns to select what to
+    *exclude* (with the exception of negated patterns).  The
+    documentation on gitignore-style patterns usually does not talk in
+    terms of matching or non-matching, but on what the user wants to
+    "exclude".  This can cause confusion for users trying to learn how
+    to specify sparse-checkout patterns to get their desired behavior.
+
+  * Every other git subcommand that wants to provide "special path
+    pattern matching" of some sort uses pathspecs, but non-cone mode
+    for sparse-checkout uses gitignore patterns, which feels
+    inconsistent.
+
+  * It has edge cases where the "right" behavior is unclear.  Two examples:
+
+    First, two users are in a subdirectory, and the first runs
+       git sparse-checkout set '/toplevel-dir/*.c'
+    while the second runs
+       git sparse-checkout set relative-dir
+    Should those arguments be transliterated into
+       current/subdirectory/toplevel-dir/*.c
+    and
+       current/subdirectory/relative-dir
+    before inserting into the sparse-checkout file?  The user who typed
+    the first command is probably aware that arguments to set/add are
+    supposed to be patterns in non-cone mode, and probably would not be
+    happy with such a transliteration.  However, many gitignore-style
+    patterns are just paths, which might be what the user who typed the
+    second command was thinking, and they'd be upset if their argument
+    wasn't transliterated.
+
+    Second, what should bash-completion complete on for set/add commands
+    for non-cone users?  If it suggests paths, is it exacerbating the
+    problem above?  Also, if it suggests paths, what if the user has a
+    file or directory that begins with either a '!' or '#' or has a '*',
+    '\', '?', '[', or ']' in its name?  And if it suggests paths, will
+    it complete "/pro" to "/proc" (in the root filesystem) rather than to
+    "/progress.txt" in the current directory?  (Note that users are
+    likely to want to start paths with a leading '/' in non-cone mode,
+    for the same reason that .gitignore files often have one.)
+    Completing on files or directories might give nasty surprises in
+    all these cases.
+
+  * The excessive flexibility made other extensions essentially
+    impractical.  `--sparse-index` is likely impossible in non-cone
+    mode; even if it is somehow feasible, it would have been far more
+    work to implement and may have been too slow in practice.  Some
+    ideas for adding coupling between partial clones and sparse
+    checkouts are only practical with a more restricted set of paths
+    as well.
+
+For all these reasons, non-cone mode is deprecated.  Please switch to
+using cone mode.
+
+
+INTERNALS -- CONE MODE HANDLING
+-------------------------------
+
+The "cone mode", which is the default, lets you specify only what
+directories to include.  For any directory specified, all paths below
+that directory will be included, and any paths immediately under
+leading directories (including the toplevel directory) will also be
+included.  Thus, if you specified the directory
+    Documentation/technical/
+then your sparse checkout would contain:
+
+  * all files in the toplevel-directory
+  * all files immediately under Documentation/
+  * all files at any depth under Documentation/technical/
+
+Also, in cone mode, even if no directories are specified, then the
+files in the toplevel directory will be included.
+
+When changing the sparse-checkout patterns in cone mode, Git will inspect each
+tracked directory that is not within the sparse-checkout cone to see if it
+contains any untracked files. If all of those files are ignored due to the
+`.gitignore` patterns, then the directory will be deleted. If any of the
+untracked files within that directory is not ignored, then no deletions will
+occur within that directory and a warning message will appear. If these files
+are important, then reset your sparse-checkout definition so they are included,
+use `git add` and `git commit` to store them, then remove any remaining files
+manually to ensure Git can behave optimally.
+
+See also the "Internals -- Cone Pattern Set" section to learn how the
+directories are transformed under the hood into a subset of the
+Full Pattern Set of sparse-checkout.
+
+
+INTERNALS -- FULL PATTERN SET
+-----------------------------
+
+The full pattern set allows for arbitrary pattern matches and complicated
+inclusion/exclusion rules. These can result in O(N*M) pattern matches when
+updating the index, where N is the number of patterns and M is the number
+of paths in the index. To combat this performance issue, a more restricted
+pattern set is allowed when `core.sparseCheckoutCone` is enabled.
+
+The sparse-checkout file uses the same syntax as `.gitignore` files;
+see linkgit:gitignore[5] for details.  Here, though, the patterns are
+usually being used to select which files to include rather than which
+files to exclude.  (However, it can get a bit confusing since
+gitignore-style patterns have negations defined by patterns which
+begin with a '!', so you can also select files to _not_ include.)
+
+For example, to select everything, and then to remove the file
+`unwanted` (so that every file will appear in your working tree except
+the file named `unwanted`):
+
+    git sparse-checkout set --no-cone '/*' '!unwanted'
+
+These patterns are just placed into the
+`$GIT_DIR/info/sparse-checkout` as-is, so the contents of that file
+at this point would be
+
+----------------
+/*
+!unwanted
+----------------
+
+See also the "Sparse Checkout" section of linkgit:git-read-tree[1] to
+learn more about the gitignore-style patterns used in sparse
+checkouts.
+
+
+INTERNALS -- CONE PATTERN SET
+-----------------------------
+
+In cone mode, only directories are accepted, but they are translated into
+the same gitignore-style patterns used in the full pattern set.  We refer
+to the particular patterns used in those mode as being of one of two types:
+
+1. *Recursive:* All paths inside a directory are included.
+
+2. *Parent:* All files immediately inside a directory are included.
+
+Since cone mode always includes files at the toplevel, when running
+`git sparse-checkout set` with no directories specified, the toplevel
+directory is added as a parent pattern.  At this point, the
+sparse-checkout file contains the following patterns:
+
+----------------
+/*
+!/*/
+----------------
+
+This says "include everything immediately under the toplevel
+directory, but nothing at any level below that."
+
+When in cone mode, the `git sparse-checkout set` subcommand takes a
+list of directories.  The command `git sparse-checkout set A/B/C` sets
+the directory `A/B/C` as a recursive pattern, the directories `A` and
+`A/B` are added as parent patterns. The resulting sparse-checkout file
+is now
+
+----------------
+/*
+!/*/
+/A/
+!/A/*/
+/A/B/
+!/A/B/*/
+/A/B/C/
+----------------
+
+Here, order matters, so the negative patterns are overridden by the positive
+patterns that appear lower in the file.
+
+Unless `core.sparseCheckoutCone` is explicitly set to `false`, Git will
+parse the sparse-checkout file expecting patterns of these types. Git will
+warn if the patterns do not match.  If the patterns do match the expected
+format, then Git will use faster hash-based algorithms to compute inclusion
+in the sparse-checkout.  If they do not match, git will behave as though
+`core.sparseCheckoutCone` was false, regardless of its setting.
+
+In the cone mode case, despite the fact that full patterns are written
+to the $GIT_DIR/info/sparse-checkout file, the `git sparse-checkout
+list` subcommand will list the directories that define the recursive
+patterns. For the example sparse-checkout file above, the output is as
+follows:
+
+--------------------------
+$ git sparse-checkout list
+A/B/C
+--------------------------
+
+If `core.ignoreCase=true`, then the pattern-matching algorithm will use a
+case-insensitive check. This corrects for case mismatched filenames in the
+'git sparse-checkout set' command to reflect the expected cone in the working
+directory.
+
+
+INTERNALS -- SUBMODULES
+-----------------------
+
+If your repository contains one or more submodules, then submodules
+are populated based on interactions with the `git submodule` command.
+Specifically, `git submodule init -- <path>` will ensure the submodule
+at `<path>` is present, while `git submodule deinit [-f] -- <path>`
+will remove the files for the submodule at `<path>` (including any
+untracked files, uncommitted changes, and unpushed history).  Similar
+to how sparse-checkout removes files from the working tree but still
+leaves entries in the index, deinitialized submodules are removed from
+the working directory but still have an entry in the index.
+
+Since submodules may have unpushed changes or untracked files,
+removing them could result in data loss.  Thus, changing sparse
+inclusion/exclusion rules will not cause an already checked out
+submodule to be removed from the working copy.  Said another way, just
+as `checkout` will not cause submodules to be automatically removed or
+initialized even when switching between branches that remove or add
+submodules, using `sparse-checkout` to reduce or expand the scope of
+"interesting" files will not cause submodules to be automatically
+deinitialized or initialized either.
+
+Further, the above facts mean that there are multiple reasons that
+"tracked" files might not be present in the working copy: sparsity
+pattern application from sparse-checkout, and submodule initialization
+state.  Thus, commands like `git grep` that work on tracked files in
+the working copy may return results that are limited by either or both
+of these restrictions.
+
+
+SEE ALSO
+--------
+
+linkgit:git-read-tree[1]
+linkgit:gitignore[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-stage.adoc b/Documentation/git-stage.adoc
new file mode 100644
index 0000000000..2f6aaa75b9
--- /dev/null
+++ b/Documentation/git-stage.adoc
@@ -0,0 +1,23 @@
+git-stage(1)
+============
+
+NAME
+----
+git-stage - Add file contents to the staging area
+
+
+SYNOPSIS
+--------
+[verse]
+'git stage' <arg>...
+
+
+DESCRIPTION
+-----------
+
+This is a synonym for linkgit:git-add[1].  Please refer to the
+documentation of that command.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-stash.adoc b/Documentation/git-stash.adoc
new file mode 100644
index 0000000000..8667a8ca47
--- /dev/null
+++ b/Documentation/git-stash.adoc
@@ -0,0 +1,406 @@
+git-stash(1)
+============
+
+NAME
+----
+git-stash - Stash the changes in a dirty working directory away
+
+SYNOPSIS
+--------
+[verse]
+'git stash' list [<log-options>]
+'git stash' show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]
+'git stash' drop [-q | --quiet] [<stash>]
+'git stash' pop [--index] [-q | --quiet] [<stash>]
+'git stash' apply [--index] [-q | --quiet] [<stash>]
+'git stash' branch <branchname> [<stash>]
+'git stash' [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
+	     [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]
+	     [--pathspec-from-file=<file> [--pathspec-file-nul]]
+	     [--] [<pathspec>...]]
+'git stash' save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]
+	     [-u | --include-untracked] [-a | --all] [<message>]
+'git stash' clear
+'git stash' create [<message>]
+'git stash' store [(-m | --message) <message>] [-q | --quiet] <commit>
+
+DESCRIPTION
+-----------
+
+Use `git stash` when you want to record the current state of the
+working directory and the index, but want to go back to a clean
+working directory.  The command saves your local modifications away
+and reverts the working directory to match the `HEAD` commit.
+
+The modifications stashed away by this command can be listed with
+`git stash list`, inspected with `git stash show`, and restored
+(potentially on top of a different commit) with `git stash apply`.
+Calling `git stash` without any arguments is equivalent to `git stash push`.
+A stash is by default listed as "WIP on 'branchname' ...", but
+you can give a more descriptive message on the command line when
+you create one.
+
+The latest stash you created is stored in `refs/stash`; older
+stashes are found in the reflog of this reference and can be named using
+the usual reflog syntax (e.g. `stash@{0}` is the most recently
+created stash, `stash@{1}` is the one before it, `stash@{2.hours.ago}`
+is also possible). Stashes may also be referenced by specifying just the
+stash index (e.g. the integer `n` is equivalent to `stash@{n}`).
+
+COMMANDS
+--------
+
+push [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [(-m|--message) <message>] [--pathspec-from-file=<file> [--pathspec-file-nul]] [--] [<pathspec>...]::
+
+	Save your local modifications to a new 'stash entry' and roll them
+	back to HEAD (in the working tree and in the index).
+	The <message> part is optional and gives
+	the description along with the stashed state.
++
+For quickly making a snapshot, you can omit "push".  In this mode,
+non-option arguments are not allowed to prevent a misspelled
+subcommand from making an unwanted stash entry.  The two exceptions to this
+are `stash -p` which acts as alias for `stash push -p` and pathspec elements,
+which are allowed after a double hyphen `--` for disambiguation.
+
+save [-p|--patch] [-S|--staged] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
+
+	This option is deprecated in favour of 'git stash push'.  It
+	differs from "stash push" in that it cannot take pathspec.
+	Instead, all non-option arguments are concatenated to form the stash
+	message.
+
+list [<log-options>]::
+
+	List the stash entries that you currently have.  Each 'stash entry' is
+	listed with its name (e.g. `stash@{0}` is the latest entry, `stash@{1}` is
+	the one before, etc.), the name of the branch that was current when the
+	entry was made, and a short description of the commit the entry was
+	based on.
++
+----------------------------------------------------------------
+stash@{0}: WIP on submit: 6ebd0e2... Update git-stash documentation
+stash@{1}: On master: 9cc0589... Add git-stash
+----------------------------------------------------------------
++
+The command takes options applicable to the 'git log'
+command to control what is shown and how. See linkgit:git-log[1].
+
+show [-u|--include-untracked|--only-untracked] [<diff-options>] [<stash>]::
+
+	Show the changes recorded in the stash entry as a diff between the
+	stashed contents and the commit back when the stash entry was first
+	created.
+	By default, the command shows the diffstat, but it will accept any
+	format known to 'git diff' (e.g., `git stash show -p stash@{1}`
+	to view the second most recent entry in patch form).
+	If no `<diff-option>` is provided, the default behavior will be given
+	by the `stash.showStat`, and `stash.showPatch` config variables. You
+	can also use `stash.showIncludeUntracked` to set whether
+	`--include-untracked` is enabled by default.
+
+pop [--index] [-q|--quiet] [<stash>]::
+
+	Remove a single stashed state from the stash list and apply it
+	on top of the current working tree state, i.e., do the inverse
+	operation of `git stash push`. The working directory must
+	match the index.
++
+Applying the state can fail with conflicts; in this case, it is not
+removed from the stash list. You need to resolve the conflicts by hand
+and call `git stash drop` manually afterwards.
+
+apply [--index] [-q|--quiet] [<stash>]::
+
+	Like `pop`, but do not remove the state from the stash list. Unlike `pop`,
+	`<stash>` may be any commit that looks like a commit created by
+	`stash push` or `stash create`.
+
+branch <branchname> [<stash>]::
+
+	Creates and checks out a new branch named `<branchname>` starting from
+	the commit at which the `<stash>` was originally created, applies the
+	changes recorded in `<stash>` to the new working tree and index.
+	If that succeeds, and `<stash>` is a reference of the form
+	`stash@{<revision>}`, it then drops the `<stash>`.
++
+This is useful if the branch on which you ran `git stash push` has
+changed enough that `git stash apply` fails due to conflicts. Since
+the stash entry is applied on top of the commit that was HEAD at the
+time `git stash` was run, it restores the originally stashed state
+with no conflicts.
+
+clear::
+	Remove all the stash entries. Note that those entries will then
+	be subject to pruning, and may be impossible to recover (see
+	'Examples' below for a possible strategy).
+
+drop [-q|--quiet] [<stash>]::
+
+	Remove a single stash entry from the list of stash entries.
+
+create::
+
+	Create a stash entry (which is a regular commit object) and
+	return its object name, without storing it anywhere in the ref
+	namespace.
+	This is intended to be useful for scripts.  It is probably not
+	the command you want to use; see "push" above.
+
+store::
+
+	Store a given stash created via 'git stash create' (which is a
+	dangling merge commit) in the stash ref, updating the stash
+	reflog.  This is intended to be useful for scripts.  It is
+	probably not the command you want to use; see "push" above.
+
+OPTIONS
+-------
+-a::
+--all::
+	This option is only valid for `push` and `save` commands.
++
+All ignored and untracked files are also stashed and then cleaned
+up with `git clean`.
+
+-u::
+--include-untracked::
+--no-include-untracked::
+	When used with the `push` and `save` commands,
+	all untracked files are also stashed and then cleaned up with
+	`git clean`.
++
+When used with the `show` command, show the untracked files in the stash
+entry as part of the diff.
+
+--only-untracked::
+	This option is only valid for the `show` command.
++
+Show only the untracked files in the stash entry as part of the diff.
+
+--index::
+	This option is only valid for `pop` and `apply` commands.
++
+Tries to reinstate not only the working tree's changes, but also
+the index's ones. However, this can fail, when you have conflicts
+(which are stored in the index, where you therefore can no longer
+apply the changes as they were originally).
+
+-k::
+--keep-index::
+--no-keep-index::
+	This option is only valid for `push` and `save` commands.
++
+All changes already added to the index are left intact.
+
+-p::
+--patch::
+	This option is only valid for `push` and `save` commands.
++
+Interactively select hunks from the diff between HEAD and the
+working tree to be stashed.  The stash entry is constructed such
+that its index state is the same as the index state of your
+repository, and its worktree contains only the changes you selected
+interactively.  The selected changes are then rolled back from your
+worktree. See the ``Interactive Mode'' section of linkgit:git-add[1]
+to learn how to operate the `--patch` mode.
++
+The `--patch` option implies `--keep-index`.  You can use
+`--no-keep-index` to override this.
+
+-S::
+--staged::
+	This option is only valid for `push` and `save` commands.
++
+Stash only the changes that are currently staged. This is similar to
+basic `git commit` except the state is committed to the stash instead
+of current branch.
++
+The `--patch` option has priority over this one.
+
+--pathspec-from-file=<file>::
+	This option is only valid for `push` command.
++
+Pathspec is passed in `<file>` instead of commandline args. If
+`<file>` is exactly `-` then standard input is used. Pathspec
+elements are separated by LF or CR/LF. Pathspec elements can be
+quoted as explained for the configuration variable `core.quotePath`
+(see linkgit:git-config[1]). See also `--pathspec-file-nul` and
+global `--literal-pathspecs`.
+
+--pathspec-file-nul::
+	This option is only valid for `push` command.
++
+Only meaningful with `--pathspec-from-file`. Pathspec elements are
+separated with NUL character and all other characters are taken
+literally (including newlines and quotes).
+
+-q::
+--quiet::
+	This option is only valid for `apply`, `drop`, `pop`, `push`,
+	`save`, `store` commands.
++
+Quiet, suppress feedback messages.
+
+\--::
+	This option is only valid for `push` command.
++
+Separates pathspec from options for disambiguation purposes.
+
+<pathspec>...::
+	This option is only valid for `push` command.
++
+The new stash entry records the modified states only for the files
+that match the pathspec.  The index entries and working tree files
+are then rolled back to the state in HEAD only for these files,
+too, leaving files that do not match the pathspec intact.
++
+For more details, see the 'pathspec' entry in linkgit:gitglossary[7].
+
+<stash>::
+	This option is only valid for `apply`, `branch`, `drop`, `pop`,
+	`show` commands.
++
+A reference of the form `stash@{<revision>}`. When no `<stash>` is
+given, the latest stash is assumed (that is, `stash@{0}`).
+
+DISCUSSION
+----------
+
+A stash entry is represented as a commit whose tree records the state
+of the working directory, and its first parent is the commit at `HEAD`
+when the entry was created.  The tree of the second parent records the
+state of the index when the entry is made, and it is made a child of
+the `HEAD` commit.  The ancestry graph looks like this:
+
+            .----W
+           /    /
+     -----H----I
+
+where `H` is the `HEAD` commit, `I` is a commit that records the state
+of the index, and `W` is a commit that records the state of the working
+tree.
+
+
+EXAMPLES
+--------
+
+Pulling into a dirty tree::
+
+When you are in the middle of something, you learn that there are
+upstream changes that are possibly relevant to what you are
+doing.  When your local changes do not conflict with the changes in
+the upstream, a simple `git pull` will let you move forward.
++
+However, there are cases in which your local changes do conflict with
+the upstream changes, and `git pull` refuses to overwrite your
+changes.  In such a case, you can stash your changes away,
+perform a pull, and then unstash, like this:
++
+----------------------------------------------------------------
+$ git pull
+ ...
+file foobar not up to date, cannot merge.
+$ git stash
+$ git pull
+$ git stash pop
+----------------------------------------------------------------
+
+Interrupted workflow::
+
+When you are in the middle of something, your boss comes in and
+demands that you fix something immediately.  Traditionally, you would
+make a commit to a temporary branch to store your changes away, and
+return to your original branch to make the emergency fix, like this:
++
+----------------------------------------------------------------
+# ... hack hack hack ...
+$ git switch -c my_wip
+$ git commit -a -m "WIP"
+$ git switch master
+$ edit emergency fix
+$ git commit -a -m "Fix in a hurry"
+$ git switch my_wip
+$ git reset --soft HEAD^
+# ... continue hacking ...
+----------------------------------------------------------------
++
+You can use 'git stash' to simplify the above, like this:
++
+----------------------------------------------------------------
+# ... hack hack hack ...
+$ git stash
+$ edit emergency fix
+$ git commit -a -m "Fix in a hurry"
+$ git stash pop
+# ... continue hacking ...
+----------------------------------------------------------------
+
+Testing partial commits::
+
+You can use `git stash push --keep-index` when you want to make two or
+more commits out of the changes in the work tree, and you want to test
+each change before committing:
++
+----------------------------------------------------------------
+# ... hack hack hack ...
+$ git add --patch foo            # add just first part to the index
+$ git stash push --keep-index    # save all other changes to the stash
+$ edit/build/test first part
+$ git commit -m 'First part'     # commit fully tested change
+$ git stash pop                  # prepare to work on all other changes
+# ... repeat above five steps until one commit remains ...
+$ edit/build/test remaining parts
+$ git commit foo -m 'Remaining parts'
+----------------------------------------------------------------
+
+Saving unrelated changes for future use::
+
+When you are in the middle of massive changes and you find some
+unrelated issue that you don't want to forget to fix, you can do the
+change(s), stage them, and use `git stash push --staged` to stash them
+out for future use. This is similar to committing the staged changes,
+only the commit ends-up being in the stash and not on the current branch.
++
+----------------------------------------------------------------
+# ... hack hack hack ...
+$ git add --patch foo           # add unrelated changes to the index
+$ git stash push --staged       # save these changes to the stash
+# ... hack hack hack, finish current changes ...
+$ git commit -m 'Massive'       # commit fully tested changes
+$ git switch fixup-branch       # switch to another branch
+$ git stash pop                 # to finish work on the saved changes
+----------------------------------------------------------------
+
+Recovering stash entries that were cleared/dropped erroneously::
+
+If you mistakenly drop or clear stash entries, they cannot be recovered
+through the normal safety mechanisms.  However, you can try the
+following incantation to get a list of stash entries that are still in
+your repository, but not reachable any more:
++
+----------------------------------------------------------------
+git fsck --unreachable |
+grep commit | cut -d\  -f3 |
+xargs git log --merges --no-walk --grep=WIP
+----------------------------------------------------------------
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/stash.adoc[]
+
+
+SEE ALSO
+--------
+linkgit:git-checkout[1],
+linkgit:git-commit[1],
+linkgit:git-reflog[1],
+linkgit:git-reset[1],
+linkgit:git-switch[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-status.adoc b/Documentation/git-status.adoc
new file mode 100644
index 0000000000..9a376886a5
--- /dev/null
+++ b/Documentation/git-status.adoc
@@ -0,0 +1,529 @@
+git-status(1)
+=============
+
+NAME
+----
+git-status - Show the working tree status
+
+
+SYNOPSIS
+--------
+[verse]
+'git status' [<options>] [--] [<pathspec>...]
+
+DESCRIPTION
+-----------
+Displays paths that have differences between the index file and the
+current HEAD commit, paths that have differences between the working
+tree and the index file, and paths in the working tree that are not
+tracked by Git (and are not ignored by linkgit:gitignore[5]). The first
+are what you _would_ commit by running `git commit`; the second and
+third are what you _could_ commit by running 'git add' before running
+`git commit`.
+
+OPTIONS
+-------
+
+-s::
+--short::
+	Give the output in the short-format.
+
+-b::
+--branch::
+	Show the branch and tracking info even in short-format.
+
+--show-stash::
+	Show the number of entries currently stashed away.
+
+--porcelain[=<version>]::
+	Give the output in an easy-to-parse format for scripts.
+	This is similar to the short output, but will remain stable
+	across Git versions and regardless of user configuration. See
+	below for details.
++
+The version parameter is used to specify the format version.
+This is optional and defaults to the original version 'v1' format.
+
+--long::
+	Give the output in the long-format. This is the default.
+
+-v::
+--verbose::
+	In addition to the names of files that have been changed, also
+	show the textual changes that are staged to be committed
+	(i.e., like the output of `git diff --cached`). If `-v` is specified
+	twice, then also show the changes in the working tree that
+	have not yet been staged (i.e., like the output of `git diff`).
+
+-u[<mode>]::
+--untracked-files[=<mode>]::
+	Show untracked files.
++
+--
+The mode parameter is used to specify the handling of untracked files.
+It is optional: it defaults to 'all', and if specified, it must be
+stuck to the option (e.g. `-uno`, but not `-u no`).
+
+The possible options are:
+
+	- 'no'     - Show no untracked files.
+	- 'normal' - Shows untracked files and directories.
+	- 'all'    - Also shows individual files in untracked directories.
+
+When `-u` option is not used, untracked files and directories are
+shown (i.e. the same as specifying `normal`), to help you avoid
+forgetting to add newly created files.  Because it takes extra work
+to find untracked files in the filesystem, this mode may take some
+time in a large working tree.
+Consider enabling untracked cache and split index if supported (see
+`git update-index --untracked-cache` and `git update-index
+--split-index`), Otherwise you can use `no` to have `git status`
+return more quickly without showing untracked files.
+All usual spellings for Boolean value `true` are taken as `normal`
+and `false` as `no`.
+
+The default can be changed using the status.showUntrackedFiles
+configuration variable documented in linkgit:git-config[1].
+--
+
+--ignore-submodules[=<when>]::
+	Ignore changes to submodules when looking for changes. <when> can be
+	either "none", "untracked", "dirty" or "all", which is the default.
+	Using "none" will consider the submodule modified when it either contains
+	untracked or modified files or its HEAD differs from the commit recorded
+	in the superproject and can be used to override any settings of the
+	'ignore' option in linkgit:git-config[1] or linkgit:gitmodules[5]. When
+	"untracked" is used submodules are not considered dirty when they only
+	contain untracked content (but they are still scanned for modified
+	content). Using "dirty" ignores all changes to the work tree of submodules,
+	only changes to the commits stored in the superproject are shown (this was
+	the behavior before 1.7.0). Using "all" hides all changes to submodules
+	(and suppresses the output of submodule summaries when the config option
+	`status.submoduleSummary` is set).
+
+--ignored[=<mode>]::
+	Show ignored files as well.
++
+--
+The mode parameter is used to specify the handling of ignored files.
+It is optional: it defaults to 'traditional'.
+
+The possible options are:
+
+	- 'traditional' - Shows ignored files and directories, unless
+			  --untracked-files=all is specified, in which case
+			  individual files in ignored directories are
+			  displayed.
+	- 'no'	        - Show no ignored files.
+	- 'matching'    - Shows ignored files and directories matching an
+			  ignore pattern.
+
+When 'matching' mode is specified, paths that explicitly match an
+ignored pattern are shown. If a directory matches an ignore pattern,
+then it is shown, but not paths contained in the ignored directory. If
+a directory does not match an ignore pattern, but all contents are
+ignored, then the directory is not shown, but all contents are shown.
+--
+
+-z::
+	Terminate entries with NUL, instead of LF.  This implies
+	the `--porcelain=v1` output format if no other format is given.
+
+--column[=<options>]::
+--no-column::
+	Display untracked files in columns. See configuration variable
+	`column.status` for option syntax. `--column` and `--no-column`
+	without options are equivalent to 'always' and 'never'
+	respectively.
+
+--ahead-behind::
+--no-ahead-behind::
+	Display or do not display detailed ahead/behind counts for the
+	branch relative to its upstream branch.  Defaults to true.
+
+--renames::
+--no-renames::
+	Turn on/off rename detection regardless of user configuration.
+	See also linkgit:git-diff[1] `--no-renames`.
+
+--find-renames[=<n>]::
+	Turn on rename detection, optionally setting the similarity
+	threshold.
+	See also linkgit:git-diff[1] `--find-renames`.
+
+<pathspec>...::
+	See the 'pathspec' entry in linkgit:gitglossary[7].
+
+OUTPUT
+------
+The output from this command is designed to be used as a commit
+template comment.
+The default, long format, is designed to be human readable,
+verbose and descriptive.  Its contents and format are subject to change
+at any time.
+
+The paths mentioned in the output, unlike many other Git commands, are
+made relative to the current directory if you are working in a
+subdirectory (this is on purpose, to help cutting and pasting). See
+the status.relativePaths config option below.
+
+Short Format
+~~~~~~~~~~~~
+
+In the short-format, the status of each path is shown as one of these
+forms
+
+	XY PATH
+	XY ORIG_PATH -> PATH
+
+where `ORIG_PATH` is where the renamed/copied contents came
+from. `ORIG_PATH` is only shown when the entry is renamed or
+copied. The `XY` is a two-letter status code.
+
+The fields (including the `->`) are separated from each other by a
+single space. If a filename contains whitespace or other nonprintable
+characters, that field will be quoted in the manner of a C string
+literal: surrounded by ASCII double quote (34) characters, and with
+interior special characters backslash-escaped.
+
+There are three different types of states that are shown using this format, and
+each one uses the `XY` syntax differently:
+
+* When a merge is occurring and the merge was successful, or outside of a merge
+	situation, `X` shows the status of the index and `Y` shows the status of the
+	working tree.
+* When a merge conflict has occurred and has not yet been resolved, `X` and `Y`
+	show the state introduced by each head of the merge, relative to the common
+	ancestor. These paths are said to be _unmerged_.
+* When a path is untracked, `X` and `Y` are always the same, since they are
+	unknown to the index. `??` is used for untracked paths. Ignored files are
+	not listed unless `--ignored` is used; if it is, ignored files are indicated
+	by `!!`.
+
+Note that the term _merge_ here also includes rebases using the default
+`--merge` strategy, cherry-picks, and anything else using the merge machinery.
+
+In the following table, these three classes are shown in separate sections, and
+these characters are used for `X` and `Y` fields for the first two sections that
+show tracked paths:
+
+* ' ' = unmodified
+* 'M' = modified
+* 'T' = file type changed (regular file, symbolic link or submodule)
+* 'A' = added
+* 'D' = deleted
+* 'R' = renamed
+* 'C' = copied (if config option status.renames is set to "copies")
+* 'U' = updated but unmerged
+
+....
+X          Y     Meaning
+-------------------------------------------------
+	 [AMD]   not updated
+M        [ MTD]  updated in index
+T        [ MTD]  type changed in index
+A        [ MTD]  added to index
+D                deleted from index
+R        [ MTD]  renamed in index
+C        [ MTD]  copied in index
+[MTARC]          index and work tree matches
+[ MTARC]    M    work tree changed since index
+[ MTARC]    T    type changed in work tree since index
+[ MTARC]    D    deleted in work tree
+	    R    renamed in work tree
+	    C    copied in work tree
+-------------------------------------------------
+D           D    unmerged, both deleted
+A           U    unmerged, added by us
+U           D    unmerged, deleted by them
+U           A    unmerged, added by them
+D           U    unmerged, deleted by us
+A           A    unmerged, both added
+U           U    unmerged, both modified
+-------------------------------------------------
+?           ?    untracked
+!           !    ignored
+-------------------------------------------------
+....
+
+Submodules have more state and instead report
+
+* 'M' = the submodule has a different HEAD than recorded in the index
+* 'm' = the submodule has modified content
+* '?' = the submodule has untracked files
+
+This is since modified content or untracked files in a submodule cannot be added
+via `git add` in the superproject to prepare a commit.
+
+'m' and '?' are applied recursively. For example if a nested submodule
+in a submodule contains an untracked file, this is reported as '?' as well.
+
+If -b is used the short-format status is preceded by a line
+
+    ## branchname tracking info
+
+Porcelain Format Version 1
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Version 1 porcelain format is similar to the short format, but is guaranteed
+not to change in a backwards-incompatible way between Git versions or
+based on user configuration. This makes it ideal for parsing by scripts.
+The description of the short format above also describes the porcelain
+format, with a few exceptions:
+
+1. The user's color.status configuration is not respected; color will
+   always be off.
+
+2. The user's status.relativePaths configuration is not respected; paths
+   shown will always be relative to the repository root.
+
+There is also an alternate -z format recommended for machine parsing. In
+that format, the status field is the same, but some other things
+change.  First, the '\->' is omitted from rename entries and the field
+order is reversed (e.g 'from \-> to' becomes 'to from'). Second, a NUL
+(ASCII 0) follows each filename, replacing space as a field separator
+and the terminating newline (but a space still separates the status
+field from the first filename).  Third, filenames containing special
+characters are not specially formatted; no quoting or
+backslash-escaping is performed.
+
+Any submodule changes are reported as modified `M` instead of `m` or single `?`.
+
+Porcelain Format Version 2
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Version 2 format adds more detailed information about the state of
+the worktree and changed items.  Version 2 also defines an extensible
+set of easy to parse optional headers.
+
+Header lines start with "#" and are added in response to specific
+command line arguments.  Parsers should ignore headers they
+don't recognize.
+
+Branch Headers
+^^^^^^^^^^^^^^
+
+If `--branch` is given, a series of header lines are printed with
+information about the current branch.
+
+....
+Line                                     Notes
+------------------------------------------------------------
+# branch.oid <commit> | (initial)        Current commit.
+# branch.head <branch> | (detached)      Current branch.
+# branch.upstream <upstream-branch>      If upstream is set.
+# branch.ab +<ahead> -<behind>           If upstream is set and
+					 the commit is present.
+------------------------------------------------------------
+....
+
+Stash Information
+^^^^^^^^^^^^^^^^^
+
+If `--show-stash` is given, one line is printed showing the number of stash
+entries if non-zero:
+
+    # stash <N>
+
+Changed Tracked Entries
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Following the headers, a series of lines are printed for tracked
+entries.  One of three different line formats may be used to describe
+an entry depending on the type of change.  Tracked entries are printed
+in an undefined order; parsers should allow for a mixture of the 3
+line types in any order.
+
+Ordinary changed entries have the following format:
+
+    1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>
+
+Renamed or copied entries have the following format:
+
+    2 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <X><score> <path><sep><origPath>
+
+....
+Field       Meaning
+--------------------------------------------------------
+<XY>        A 2 character field containing the staged and
+	    unstaged XY values described in the short format,
+	    with unchanged indicated by a "." rather than
+	    a space.
+<sub>       A 4 character field describing the submodule state.
+	    "N..." when the entry is not a submodule.
+	    "S<c><m><u>" when the entry is a submodule.
+	    <c> is "C" if the commit changed; otherwise ".".
+	    <m> is "M" if it has tracked changes; otherwise ".".
+	    <u> is "U" if there are untracked changes; otherwise ".".
+<mH>        The octal file mode in HEAD.
+<mI>        The octal file mode in the index.
+<mW>        The octal file mode in the worktree.
+<hH>        The object name in HEAD.
+<hI>        The object name in the index.
+<X><score>  The rename or copy score (denoting the percentage
+	    of similarity between the source and target of the
+	    move or copy). For example "R100" or "C75".
+<path>      The pathname.  In a renamed/copied entry, this
+	    is the target path.
+<sep>       When the `-z` option is used, the 2 pathnames are separated
+	    with a NUL (ASCII 0x00) byte; otherwise, a tab (ASCII 0x09)
+	    byte separates them.
+<origPath>  The pathname in the commit at HEAD or in the index.
+	    This is only present in a renamed/copied entry, and
+	    tells where the renamed/copied contents came from.
+--------------------------------------------------------
+....
+
+Unmerged entries have the following format; the first character is
+a "u" to distinguish from ordinary changed entries.
+
+    u <XY> <sub> <m1> <m2> <m3> <mW> <h1> <h2> <h3> <path>
+
+....
+Field       Meaning
+--------------------------------------------------------
+<XY>        A 2 character field describing the conflict type
+	    as described in the short format.
+<sub>       A 4 character field describing the submodule state
+	    as described above.
+<m1>        The octal file mode in stage 1.
+<m2>        The octal file mode in stage 2.
+<m3>        The octal file mode in stage 3.
+<mW>        The octal file mode in the worktree.
+<h1>        The object name in stage 1.
+<h2>        The object name in stage 2.
+<h3>        The object name in stage 3.
+<path>      The pathname.
+--------------------------------------------------------
+....
+
+Other Items
+^^^^^^^^^^^
+
+Following the tracked entries (and if requested), a series of
+lines will be printed for untracked and then ignored items
+found in the worktree.
+
+Untracked items have the following format:
+
+    ? <path>
+
+Ignored items have the following format:
+
+    ! <path>
+
+Pathname Format Notes and -z
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When the `-z` option is given, pathnames are printed as is and
+without any quoting and lines are terminated with a NUL (ASCII 0x00)
+byte.
+
+Without the `-z` option, pathnames with "unusual" characters are
+quoted as explained for the configuration variable `core.quotePath`
+(see linkgit:git-config[1]).
+
+
+CONFIGURATION
+-------------
+
+The command honors `color.status` (or `status.color` -- they
+mean the same thing and the latter is kept for backward
+compatibility) and `color.status.<slot>` configuration variables
+to colorize its output.
+
+If the config variable `status.relativePaths` is set to false, then all
+paths shown are relative to the repository root, not to the current
+directory.
+
+If `status.submoduleSummary` is set to a non zero number or true (identical
+to -1 or an unlimited number), the submodule summary will be enabled for
+the long format and a summary of commits for modified submodules will be
+shown (see --summary-limit option of linkgit:git-submodule[1]). Please note
+that the summary output from the status command will be suppressed for all
+submodules when `diff.ignoreSubmodules` is set to 'all' or only for those
+submodules where `submodule.<name>.ignore=all`. To also view the summary for
+ignored submodules you can either use the --ignore-submodules=dirty command
+line option or the 'git submodule summary' command, which shows a similar
+output but does not honor these settings.
+
+BACKGROUND REFRESH
+------------------
+
+By default, `git status` will automatically refresh the index, updating
+the cached stat information from the working tree and writing out the
+result. Writing out the updated index is an optimization that isn't
+strictly necessary (`status` computes the values for itself, but writing
+them out is just to save subsequent programs from repeating our
+computation). When `status` is run in the background, the lock held
+during the write may conflict with other simultaneous processes, causing
+them to fail. Scripts running `status` in the background should consider
+using `git --no-optional-locks status` (see linkgit:git[1] for details).
+
+UNTRACKED FILES AND PERFORMANCE
+-------------------------------
+
+`git status` can be very slow in large worktrees if/when it
+needs to search for untracked files and directories. There are
+many configuration options available to speed this up by either
+avoiding the work or making use of cached results from previous
+Git commands. There is no single optimum set of settings right
+for everyone. We'll list a summary of the relevant options to help
+you, but before going into the list, you may want to run `git status`
+again, because your configuration may already be caching `git status`
+results, so it could be faster on subsequent runs.
+
+* The `--untracked-files=no` flag or the
+	`status.showUntrackedFiles=no` config (see above for both):
+	indicate that `git status` should not report untracked
+	files. This is the fastest option. `git status` will not list
+	the untracked files, so you need to be careful to remember if
+	you create any new files and manually `git add` them.
+
+* `advice.statusUoption=false` (see linkgit:git-config[1]):
+	setting this variable to `false` disables the warning message
+	given when enumerating untracked files takes more than 2
+	seconds.  In a large project, it may take longer and the user
+	may have already accepted the trade off (e.g. using "-uno" may
+	not be an acceptable option for the user), in which case, there
+	is no point issuing the warning message, and in such a case,
+	disabling the warning may be the best.
+
+* `core.untrackedCache=true` (see linkgit:git-update-index[1]):
+	enable the untracked cache feature and only search directories
+	that have been modified since the previous `git status` command.
+	Git remembers the set of untracked files within each directory
+	and assumes that if a directory has not been modified, then
+	the set of untracked files within has not changed.  This is much
+	faster than enumerating the contents of every directory, but still
+	not without cost, because Git still has to search for the set of
+	modified directories. The untracked cache is stored in the
+	`.git/index` file. The reduced cost of searching for untracked
+	files is offset slightly by the increased size of the index and
+	the cost of keeping it up-to-date. That reduced search time is
+	usually worth the additional size.
+
+* `core.untrackedCache=true` and `core.fsmonitor=true` or
+	`core.fsmonitor=<hook-command-pathname>` (see
+	linkgit:git-update-index[1]): enable both the untracked cache
+	and FSMonitor features and only search directories that have
+	been modified since the previous `git status` command.  This
+	is faster than using just the untracked cache alone because
+	Git can also avoid searching for modified directories.  Git
+	only has to enumerate the exact set of directories that have
+	changed recently. While the FSMonitor feature can be enabled
+	without the untracked cache, the benefits are greatly reduced
+	in that case.
+
+Note that after you turn on the untracked cache and/or FSMonitor
+features it may take a few `git status` commands for the various
+caches to warm up before you see improved command times.  This is
+normal.
+
+SEE ALSO
+--------
+linkgit:gitignore[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-stripspace.adoc b/Documentation/git-stripspace.adoc
new file mode 100644
index 0000000000..a293327581
--- /dev/null
+++ b/Documentation/git-stripspace.adoc
@@ -0,0 +1,94 @@
+git-stripspace(1)
+=================
+
+NAME
+----
+git-stripspace - Remove unnecessary whitespace
+
+
+SYNOPSIS
+--------
+[verse]
+'git stripspace' [-s | --strip-comments]
+'git stripspace' [-c | --comment-lines]
+
+DESCRIPTION
+-----------
+
+Read text, such as commit messages, notes, tags and branch
+descriptions, from the standard input and clean it in the manner
+used by Git.
+
+With no arguments, this will:
+
+- remove trailing whitespace from all lines
+- collapse multiple consecutive empty lines into one empty line
+- remove empty lines from the beginning and end of the input
+- add a missing '\n' to the last line if necessary.
+
+In the case where the input consists entirely of whitespace characters, no
+output will be produced.
+
+*NOTE*: This is intended for cleaning metadata. Prefer the `--whitespace=fix`
+mode of linkgit:git-apply[1] for correcting whitespace of patches or files in
+the repository.
+
+OPTIONS
+-------
+-s::
+--strip-comments::
+	Skip and remove all lines starting with a comment character (default '#').
+
+-c::
+--comment-lines::
+	Prepend the comment character and a blank space to each line. Lines will automatically
+	be terminated with a newline. On empty lines, only the comment character
+	will be prepended.
+
+EXAMPLES
+--------
+
+Given the following noisy input with '$' indicating the end of a line:
+
+---------
+|A brief introduction   $
+|   $
+|$
+|A new paragraph$
+|# with a commented-out line    $
+|explaining lots of stuff.$
+|$
+|# An old paragraph, also commented-out. $
+|      $
+|The end.$
+|  $
+---------
+
+Use 'git stripspace' with no arguments to obtain:
+
+---------
+|A brief introduction$
+|$
+|A new paragraph$
+|# with a commented-out line$
+|explaining lots of stuff.$
+|$
+|# An old paragraph, also commented-out.$
+|$
+|The end.$
+---------
+
+Use 'git stripspace --strip-comments' to obtain:
+
+---------
+|A brief introduction$
+|$
+|A new paragraph$
+|explaining lots of stuff.$
+|$
+|The end.$
+---------
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-submodule.adoc b/Documentation/git-submodule.adoc
new file mode 100644
index 0000000000..87d8e0f0c5
--- /dev/null
+++ b/Documentation/git-submodule.adoc
@@ -0,0 +1,473 @@
+git-submodule(1)
+================
+
+NAME
+----
+git-submodule - Initialize, update or inspect submodules
+
+
+SYNOPSIS
+--------
+[verse]
+'git submodule' [--quiet] [--cached]
+'git submodule' [--quiet] add [<options>] [--] <repository> [<path>]
+'git submodule' [--quiet] status [--cached] [--recursive] [--] [<path>...]
+'git submodule' [--quiet] init [--] [<path>...]
+'git submodule' [--quiet] deinit [-f|--force] (--all|[--] <path>...)
+'git submodule' [--quiet] update [<options>] [--] [<path>...]
+'git submodule' [--quiet] set-branch [<options>] [--] <path>
+'git submodule' [--quiet] set-url [--] <path> <newurl>
+'git submodule' [--quiet] summary [<options>] [--] [<path>...]
+'git submodule' [--quiet] foreach [--recursive] <command>
+'git submodule' [--quiet] sync [--recursive] [--] [<path>...]
+'git submodule' [--quiet] absorbgitdirs [--] [<path>...]
+
+
+DESCRIPTION
+-----------
+Inspects, updates and manages submodules.
+
+For more information about submodules, see linkgit:gitsubmodules[7].
+
+COMMANDS
+--------
+With no arguments, shows the status of existing submodules.  Several
+subcommands are available to perform operations on the submodules.
+
+add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--] <repository> [<path>]::
+	Add the given repository as a submodule at the given path
+	to the changeset to be committed next to the current
+	project: the current project is termed the "superproject".
++
+<repository> is the URL of the new submodule's origin repository.
+This may be either an absolute URL, or (if it begins with ./
+or ../), the location relative to the superproject's default remote
+repository (Please note that to specify a repository 'foo.git'
+which is located right next to a superproject 'bar.git', you'll
+have to use `../foo.git` instead of `./foo.git` - as one might expect
+when following the rules for relative URLs - because the evaluation
+of relative URLs in Git is identical to that of relative directories).
++
+The default remote is the remote of the remote-tracking branch
+of the current branch. If no such remote-tracking branch exists or
+the HEAD is detached, "origin" is assumed to be the default remote.
+If the superproject doesn't have a default remote configured
+the superproject is its own authoritative upstream and the current
+working directory is used instead.
++
+The optional argument <path> is the relative location for the cloned
+submodule to exist in the superproject. If <path> is not given, the
+canonical part of the source repository is used ("repo" for
+"/path/to/repo.git" and "foo" for "host.xz:foo/.git"). If <path>
+exists and is already a valid Git repository, then it is staged
+for commit without cloning. The <path> is also used as the submodule's
+logical name in its configuration entries unless `--name` is used
+to specify a logical name.
++
+The given URL is recorded into `.gitmodules` for use by subsequent users
+cloning the superproject. If the URL is given relative to the
+superproject's repository, the presumption is the superproject and
+submodule repositories will be kept together in the same relative
+location, and only the superproject's URL needs to be provided.
+git-submodule will correctly locate the submodule using the relative
+URL in `.gitmodules`.
++
+If `--ref-format <format>`  is specified, the ref storage format of newly
+cloned submodules will be set accordingly.
+
+status [--cached] [--recursive] [--] [<path>...]::
+	Show the status of the submodules. This will print the SHA-1 of the
+	currently checked out commit for each submodule, along with the
+	submodule path and the output of 'git describe' for the
+	SHA-1. Each SHA-1 will possibly be prefixed with `-` if the submodule is
+	not initialized, `+` if the currently checked out submodule commit
+	does not match the SHA-1 found in the index of the containing
+	repository and `U` if the submodule has merge conflicts.
++
+If `--cached` is specified, this command will instead print the SHA-1
+recorded in the superproject for each submodule.
++
+If `--recursive` is specified, this command will recurse into nested
+submodules, and show their status as well.
++
+If you are only interested in changes of the currently initialized
+submodules with respect to the commit recorded in the index or the HEAD,
+linkgit:git-status[1] and linkgit:git-diff[1] will provide that information
+too (and can also report changes to a submodule's work tree).
+
+init [--] [<path>...]::
+	Initialize the submodules recorded in the index (which were
+	added and committed elsewhere) by setting `submodule.$name.url`
+	in `.git/config`, using the same setting from `.gitmodules` as
+	a template. If the URL is relative, it will be resolved using
+	the default remote. If there is no default remote, the current
+	repository will be assumed to be upstream.
++
+Optional <path> arguments limit which submodules will be initialized.
+If no path is specified and submodule.active has been configured, submodules
+configured to be active will be initialized, otherwise all submodules are
+initialized.
++
+It will also copy the value of `submodule.$name.update`, if present in
+the `.gitmodules` file, to `.git/config`, but (1) this command does not
+alter existing information in `.git/config`, and (2) `submodule.$name.update`
+that is set to a custom command is *not* copied for security reasons.
++
+You can then customize the submodule clone URLs in `.git/config`
+for your local setup and proceed to `git submodule update`;
+you can also just use `git submodule update --init` without
+the explicit 'init' step if you do not intend to customize
+any submodule locations.
++
+See the add subcommand for the definition of default remote.
+
+deinit [-f|--force] (--all|[--] <path>...)::
+	Unregister the given submodules, i.e. remove the whole
+	`submodule.$name` section from .git/config together with their work
+	tree. Further calls to `git submodule update`, `git submodule foreach`
+	and `git submodule sync` will skip any unregistered submodules until
+	they are initialized again, so use this command if you don't want to
+	have a local checkout of the submodule in your working tree anymore.
++
+When the command is run without pathspec, it errors out,
+instead of deinit-ing everything, to prevent mistakes.
++
+If `--force` is specified, the submodule's working tree will
+be removed even if it contains local modifications.
++
+If you really want to remove a submodule from the repository and commit
+that use linkgit:git-rm[1] instead. See linkgit:gitsubmodules[7] for removal
+options.
+
+update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter-spec>] [--] [<path>...]::
++
+--
+Update the registered submodules to match what the superproject
+expects by cloning missing submodules, fetching missing commits
+in submodules and updating the working tree of
+the submodules. The "updating" can be done in several ways depending
+on command line options and the value of `submodule.<name>.update`
+configuration variable. The command line option takes precedence over
+the configuration variable. If neither is given, a 'checkout' is performed.
+(note: what is in `.gitmodules` file is irrelevant at this point;
+see `git submodule init` above for how `.gitmodules` is used).
+The 'update' procedures supported both from the command line as well as
+through the `submodule.<name>.update` configuration are:
+
+	checkout;; the commit recorded in the superproject will be
+	    checked out in the submodule on a detached HEAD.
++
+If `--force` is specified, the submodule will be checked out (using
+`git checkout --force`), even if the commit specified
+in the index of the containing repository already matches the commit
+checked out in the submodule.
+
+	rebase;; the current branch of the submodule will be rebased
+	    onto the commit recorded in the superproject.
+
+	merge;; the commit recorded in the superproject will be merged
+	    into the current branch in the submodule.
+
+The following update procedures have additional limitations:
+
+	custom command;; mechanism for running arbitrary commands with the
+	    commit ID as an argument. Specifically, if the
+	    `submodule.<name>.update` configuration variable is set to
+	    `!custom command`, the object name of the commit recorded in the
+	    superproject for the submodule is appended to the `custom command`
+	    string and executed. Note that this mechanism is not supported in
+	    the `.gitmodules` file or on the command line.
+
+	none;; the submodule is not updated. This update procedure is not
+	    allowed on the command line.
+
+If the submodule is not yet initialized, and you just want to use the
+setting as stored in `.gitmodules`, you can automatically initialize the
+submodule with the `--init` option.
+
+If `--recursive` is specified, this command will recurse into the
+registered submodules, and update any nested submodules within.
+
+If `--ref-format <format>`  is specified, the ref storage format of newly
+cloned submodules will be set accordingly.
+
+If `--filter <filter-spec>` is specified, the given partial clone filter will be
+applied to the submodule. See linkgit:git-rev-list[1] for details on filter
+specifications.
+--
+set-branch (-b|--branch) <branch> [--] <path>::
+set-branch (-d|--default) [--] <path>::
+	Sets the default remote tracking branch for the submodule. The
+	`--branch` option allows the remote branch to be specified. The
+	`--default` option removes the submodule.<name>.branch configuration
+	key, which causes the tracking branch to default to the remote 'HEAD'.
+
+set-url [--] <path> <newurl>::
+	Sets the URL of the specified submodule to <newurl>. Then, it will
+	automatically synchronize the submodule's new remote URL
+	configuration.
+
+summary [--cached|--files] [(-n|--summary-limit) <n>] [commit] [--] [<path>...]::
+	Show commit summary between the given commit (defaults to HEAD) and
+	working tree/index. For a submodule in question, a series of commits
+	in the submodule between the given super project commit and the
+	index or working tree (switched by `--cached`) are shown. If the option
+	`--files` is given, show the series of commits in the submodule between
+	the index of the super project and the working tree of the submodule
+	(this option doesn't allow to use the `--cached` option or to provide an
+	explicit commit).
++
+Using the `--submodule=log` option with linkgit:git-diff[1] will provide that
+information too.
+
+foreach [--recursive] <command>::
+	Evaluates an arbitrary shell command in each checked out submodule.
+	The command has access to the variables $name, $sm_path, $displaypath,
+	$sha1 and $toplevel:
+	$name is the name of the relevant submodule section in `.gitmodules`,
+	$sm_path is the path of the submodule as recorded in the immediate
+	superproject, $displaypath contains the relative path from the
+	current working directory to the submodules root directory,
+	$sha1 is the commit as recorded in the immediate
+	superproject, and $toplevel is the absolute path to the top-level
+	of the immediate superproject.
+	Note that to avoid conflicts with '$PATH' on Windows, the '$path'
+	variable is now a deprecated synonym of '$sm_path' variable.
+	Any submodules defined in the superproject but not checked out are
+	ignored by this command. Unless given `--quiet`, foreach prints the name
+	of each submodule before evaluating the command.
+	If `--recursive` is given, submodules are traversed recursively (i.e.
+	the given shell command is evaluated in nested submodules as well).
+	A non-zero return from the command in any submodule causes
+	the processing to terminate. This can be overridden by adding '|| :'
+	to the end of the command.
++
+As an example, the command below will show the path and currently
+checked out commit for each submodule:
++
+--------------
+git submodule foreach 'echo $sm_path `git rev-parse HEAD`'
+--------------
+
+sync [--recursive] [--] [<path>...]::
+	Synchronizes submodules' remote URL configuration setting
+	to the value specified in `.gitmodules`. It will only affect those
+	submodules which already have a URL entry in .git/config (that is the
+	case when they are initialized or freshly added). This is useful when
+	submodule URLs change upstream and you need to update your local
+	repositories accordingly.
++
+`git submodule sync` synchronizes all submodules while
+`git submodule sync -- A` synchronizes submodule "A" only.
++
+If `--recursive` is specified, this command will recurse into the
+registered submodules, and sync any nested submodules within.
+
+absorbgitdirs::
+	If a git directory of a submodule is inside the submodule,
+	move the git directory of the submodule into its superproject's
+	`$GIT_DIR/modules` path and then connect the git directory and
+	its working directory by setting the `core.worktree` and adding
+	a .git file pointing to the git directory embedded in the
+	superprojects git directory.
++
+A repository that was cloned independently and later added as a submodule or
+old setups have the submodules git directory inside the submodule instead of
+embedded into the superprojects git directory.
++
+This command is recursive by default.
+
+OPTIONS
+-------
+-q::
+--quiet::
+	Only print error messages.
+
+--progress::
+	This option is only valid for add and update commands.
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless -q
+	is specified. This flag forces progress status even if the
+	standard error stream is not directed to a terminal.
+
+--all::
+	This option is only valid for the deinit command. Unregister all
+	submodules in the working tree.
+
+-b <branch>::
+--branch <branch>::
+	Branch of repository to add as submodule.
+	The name of the branch is recorded as `submodule.<name>.branch` in
+	`.gitmodules` for `update --remote`.  A special value of `.` is used to
+	indicate that the name of the branch in the submodule should be the
+	same name as the current branch in the current repository.  If the
+	option is not specified, it defaults to the remote 'HEAD'.
+
+-f::
+--force::
+	This option is only valid for add, deinit and update commands.
+	When running add, allow adding an otherwise ignored submodule path.
+	When running deinit the submodule working trees will be removed even
+	if they contain local changes.
+	When running update (only effective with the checkout procedure),
+	throw away local changes in submodules when switching to a
+	different commit; and always run a checkout operation in the
+	submodule, even if the commit listed in the index of the
+	containing repository matches the commit checked out in the
+	submodule.
+
+--cached::
+	This option is only valid for status and summary commands.  These
+	commands typically use the commit found in the submodule HEAD, but
+	with this option, the commit stored in the index is used instead.
+
+--files::
+	This option is only valid for the summary command. This command
+	compares the commit in the index with that in the submodule HEAD
+	when this option is used.
+
+-n::
+--summary-limit::
+	This option is only valid for the summary command.
+	Limit the summary size (number of commits shown in total).
+	Giving 0 will disable the summary; a negative number means unlimited
+	(the default). This limit only applies to modified submodules. The
+	size is always limited to 1 for added/deleted/typechanged submodules.
+
+--remote::
+	This option is only valid for the update command.  Instead of using
+	the superproject's recorded SHA-1 to update the submodule, use the
+	status of the submodule's remote-tracking branch.  The remote used
+	is branch's remote (`branch.<name>.remote`), defaulting to `origin`.
+	The remote branch used defaults to the remote `HEAD`, but the branch
+	name may be overridden by setting the `submodule.<name>.branch`
+	option in either `.gitmodules` or `.git/config` (with `.git/config`
+	taking precedence).
++
+This works for any of the supported update procedures (`--checkout`,
+`--rebase`, etc.).  The only change is the source of the target SHA-1.
+For example, `submodule update --remote --merge` will merge upstream
+submodule changes into the submodules, while `submodule update
+--merge` will merge superproject gitlink changes into the submodules.
++
+In order to ensure a current tracking branch state, `update --remote`
+fetches the submodule's remote repository before calculating the
+SHA-1.  If you don't want to fetch, you should use `submodule update
+--remote --no-fetch`.
++
+Use this option to integrate changes from the upstream subproject with
+your submodule's current HEAD.  Alternatively, you can run `git pull`
+from the submodule, which is equivalent except for the remote branch
+name: `update --remote` uses the default upstream repository and
+`submodule.<name>.branch`, while `git pull` uses the submodule's
+`branch.<name>.merge`.  Prefer `submodule.<name>.branch` if you want
+to distribute the default upstream branch with the superproject and
+`branch.<name>.merge` if you want a more native feel while working in
+the submodule itself.
+
+-N::
+--no-fetch::
+	This option is only valid for the update command.
+	Don't fetch new objects from the remote site.
+
+--checkout::
+	This option is only valid for the update command.
+	Checkout the commit recorded in the superproject on a detached HEAD
+	in the submodule. This is the default behavior, the main use of
+	this option is to override `submodule.$name.update` when set to
+	a value other than `checkout`.
+	If the key `submodule.$name.update` is either not explicitly set or
+	set to `checkout`, this option is implicit.
+
+--merge::
+	This option is only valid for the update command.
+	Merge the commit recorded in the superproject into the current branch
+	of the submodule. If this option is given, the submodule's HEAD will
+	not be detached. If a merge failure prevents this process, you will
+	have to resolve the resulting conflicts within the submodule with the
+	usual conflict resolution tools.
+	If the key `submodule.$name.update` is set to `merge`, this option is
+	implicit.
+
+--rebase::
+	This option is only valid for the update command.
+	Rebase the current branch onto the commit recorded in the
+	superproject. If this option is given, the submodule's HEAD will not
+	be detached. If a merge failure prevents this process, you will have
+	to resolve these failures with linkgit:git-rebase[1].
+	If the key `submodule.$name.update` is set to `rebase`, this option is
+	implicit.
+
+--init::
+	This option is only valid for the update command.
+	Initialize all submodules for which "git submodule init" has not been
+	called so far before updating.
+
+--name::
+	This option is only valid for the add command. It sets the submodule's
+	name to the given string instead of defaulting to its path. The name
+	must be valid as a directory name and may not end with a '/'.
+
+--reference <repository>::
+	This option is only valid for add and update commands.  These
+	commands sometimes need to clone a remote repository. In this case,
+	this option will be passed to the linkgit:git-clone[1] command.
++
+*NOTE*: Do *not* use this option unless you have read the note
+for linkgit:git-clone[1]'s `--reference`, `--shared`, and `--dissociate`
+options carefully.
+
+--dissociate::
+	This option is only valid for add and update commands.  These
+	commands sometimes need to clone a remote repository. In this case,
+	this option will be passed to the linkgit:git-clone[1] command.
++
+*NOTE*: see the NOTE for the `--reference` option.
+
+--recursive::
+	This option is only valid for foreach, update, status and sync commands.
+	Traverse submodules recursively. The operation is performed not
+	only in the submodules of the current repo, but also
+	in any nested submodules inside those submodules (and so on).
+
+--depth::
+	This option is valid for add and update commands. Create a 'shallow'
+	clone with a history truncated to the specified number of revisions.
+	See linkgit:git-clone[1]
+
+--[no-]recommend-shallow::
+	This option is only valid for the update command.
+	The initial clone of a submodule will use the recommended
+	`submodule.<name>.shallow` as provided by the `.gitmodules` file
+	by default. To ignore the suggestions use `--no-recommend-shallow`.
+
+-j <n>::
+--jobs <n>::
+	This option is only valid for the update command.
+	Clone new submodules in parallel with as many jobs.
+	Defaults to the `submodule.fetchJobs` option.
+
+--[no-]single-branch::
+	This option is only valid for the update command.
+	Clone only one branch during update: HEAD or one specified by --branch.
+
+<path>...::
+	Paths to submodule(s). When specified this will restrict the command
+	to only operate on the submodules found at the specified paths.
+	(This argument is required with add).
+
+FILES
+-----
+When initializing submodules, a `.gitmodules` file in the top-level directory
+of the containing repository is used to find the url of each submodule.
+This file should be formatted in the same way as `$GIT_DIR/config`. The key
+to each submodule url is "submodule.$name.url".  See linkgit:gitmodules[5]
+for details.
+
+SEE ALSO
+--------
+linkgit:gitsubmodules[7], linkgit:gitmodules[5].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-svn.adoc b/Documentation/git-svn.adoc
new file mode 100644
index 0000000000..bcf7d84a87
--- /dev/null
+++ b/Documentation/git-svn.adoc
@@ -0,0 +1,1174 @@
+git-svn(1)
+==========
+
+NAME
+----
+git-svn - Bidirectional operation between a Subversion repository and Git
+
+SYNOPSIS
+--------
+[verse]
+'git svn' <command> [<options>] [<arguments>]
+
+DESCRIPTION
+-----------
+'git svn' is a simple conduit for changesets between Subversion and Git.
+It provides a bidirectional flow of changes between a Subversion and a Git
+repository.
+
+'git svn' can track a standard Subversion repository,
+following the common "trunk/branches/tags" layout, with the --stdlayout option.
+It can also follow branches and tags in any layout with the -T/-t/-b options
+(see options to 'init' below, and also the 'clone' command).
+
+Once tracking a Subversion repository (with any of the above methods), the Git
+repository can be updated from Subversion by the 'fetch' command and
+Subversion updated from Git by the 'dcommit' command.
+
+COMMANDS
+--------
+
+'init'::
+	Initializes an empty Git repository with additional
+	metadata directories for 'git svn'.  The Subversion URL
+	may be specified as a command-line argument, or as full
+	URL arguments to -T/-t/-b.  Optionally, the target
+	directory to operate on can be specified as a second
+	argument.  Normally this command initializes the current
+	directory.
+
+-T<trunk-subdir>;;
+--trunk=<trunk-subdir>;;
+-t<tags-subdir>;;
+--tags=<tags-subdir>;;
+-b<branches-subdir>;;
+--branches=<branches-subdir>;;
+-s;;
+--stdlayout;;
+	These are optional command-line options for init.  Each of
+	these flags can point to a relative repository path
+	(--tags=project/tags) or a full url
+	(--tags=https://foo.org/project/tags).
+	You can specify more than one --tags and/or --branches options, in case
+	your Subversion repository places tags or branches under multiple paths.
+	The option --stdlayout is
+	a shorthand way of setting trunk,tags,branches as the relative paths,
+	which is the Subversion default. If any of the other options are given
+	as well, they take precedence.
+--no-metadata;;
+	Set the 'noMetadata' option in the [svn-remote] config.
+	This option is not recommended, please read the 'svn.noMetadata'
+	section of this manpage before using this option.
+--use-svm-props;;
+	Set the 'useSvmProps' option in the [svn-remote] config.
+--use-svnsync-props;;
+	Set the 'useSvnsyncProps' option in the [svn-remote] config.
+--rewrite-root=<URL>;;
+	Set the 'rewriteRoot' option in the [svn-remote] config.
+--rewrite-uuid=<UUID>;;
+	Set the 'rewriteUUID' option in the [svn-remote] config.
+--username=<user>;;
+	For transports that SVN handles authentication for (http,
+	https, and plain svn), specify the username.  For other
+	transports (e.g. `svn+ssh://`), you must include the username in
+	the URL, e.g. `svn+ssh://foo@xxxxxxxxxxx/project`
+--prefix=<prefix>;;
+	This allows one to specify a prefix which is prepended
+	to the names of remotes if trunk/branches/tags are
+	specified.  The prefix does not automatically include a
+	trailing slash, so be sure you include one in the
+	argument if that is what you want.  If --branches/-b is
+	specified, the prefix must include a trailing slash.
+	Setting a prefix (with a trailing slash) is strongly
+	encouraged in any case, as your SVN-tracking refs will
+	then be located at "refs/remotes/$prefix/*", which is
+	compatible with Git's own remote-tracking ref layout
+	(refs/remotes/$remote/*). Setting a prefix is also useful
+	if you wish to track multiple projects that share a common
+	repository.
+	By default, the prefix is set to 'origin/'.
++
+NOTE: Before Git v2.0, the default prefix was "" (no prefix). This
+meant that SVN-tracking refs were put at "refs/remotes/*", which is
+incompatible with how Git's own remote-tracking refs are organized.
+If you still want the old default, you can get it by passing
+`--prefix ""` on the command line (`--prefix=""` may not work if
+your Perl's Getopt::Long is < v2.37).
+
+--ignore-refs=<regex>;;
+	When passed to 'init' or 'clone' this regular expression will
+	be preserved as a config key.  See 'fetch' for a description
+	of `--ignore-refs`.
+--ignore-paths=<regex>;;
+	When passed to 'init' or 'clone' this regular expression will
+	be preserved as a config key.  See 'fetch' for a description
+	of `--ignore-paths`.
+--include-paths=<regex>;;
+	When passed to 'init' or 'clone' this regular expression will
+	be preserved as a config key.  See 'fetch' for a description
+	of `--include-paths`.
+--no-minimize-url;;
+	When tracking multiple directories (using --stdlayout,
+	--branches, or --tags options), git svn will attempt to connect
+	to the root (or highest allowed level) of the Subversion
+	repository.  This default allows better tracking of history if
+	entire projects are moved within a repository, but may cause
+	issues on repositories where read access restrictions are in
+	place.  Passing `--no-minimize-url` will allow git svn to
+	accept URLs as-is without attempting to connect to a higher
+	level directory.  This option is off by default when only
+	one URL/branch is tracked (it would do little good).
+
+'fetch'::
+	Fetch unfetched revisions from the Subversion remote we are
+	tracking.  The name of the [svn-remote "..."] section in the
+	$GIT_DIR/config file may be specified as an optional
+	command-line argument.
++
+This automatically updates the rev_map if needed (see
+'$GIT_DIR/svn/\**/.rev_map.*' in the FILES section below for details).
+
+--localtime;;
+	Store Git commit times in the local time zone instead of UTC.  This
+	makes 'git log' (even without --date=local) show the same times
+	that `svn log` would in the local time zone.
++
+This doesn't interfere with interoperating with the Subversion
+repository you cloned from, but if you wish for your local Git
+repository to be able to interoperate with someone else's local Git
+repository, either don't use this option or you should both use it in
+the same local time zone.
+
+--parent;;
+	Fetch only from the SVN parent of the current HEAD.
+
+--ignore-refs=<regex>;;
+	Ignore refs for branches or tags matching the Perl regular
+	expression. A "negative look-ahead assertion" like
+	`^refs/remotes/origin/(?!tags/wanted-tag|wanted-branch).*$`
+	can be used to allow only certain refs.
++
+[verse]
+config key: svn-remote.<name>.ignore-refs
++
+If the ignore-refs configuration key is set, and the command-line
+option is also given, both regular expressions will be used.
+
+--ignore-paths=<regex>;;
+	This allows one to specify a Perl regular expression that will
+	cause skipping of all matching paths from checkout from SVN.
+	The `--ignore-paths` option should match for every 'fetch'
+	(including automatic fetches due to 'clone', 'dcommit',
+	'rebase', etc) on a given repository.
++
+[verse]
+config key: svn-remote.<name>.ignore-paths
++
+If the ignore-paths configuration key is set, and the command-line
+option is also given, both regular expressions will be used.
++
+Examples:
++
+--
+Skip "doc*" directory for every fetch;;
++
+------------------------------------------------------------------------
+--ignore-paths="^doc"
+------------------------------------------------------------------------
+
+Skip "branches" and "tags" of first level directories;;
++
+------------------------------------------------------------------------
+--ignore-paths="^[^/]+/(?:branches|tags)"
+------------------------------------------------------------------------
+--
+
+--include-paths=<regex>;;
+	This allows one to specify a Perl regular expression that will
+	cause the inclusion of only matching paths from checkout from SVN.
+	The `--include-paths` option should match for every 'fetch'
+	(including automatic fetches due to 'clone', 'dcommit',
+	'rebase', etc) on a given repository. `--ignore-paths` takes
+	precedence over `--include-paths`.
++
+[verse]
+config key: svn-remote.<name>.include-paths
+
+--log-window-size=<n>;;
+	Fetch <n> log entries per request when scanning Subversion history.
+	The default is 100. For very large Subversion repositories, larger
+	values may be needed for 'clone'/'fetch' to complete in reasonable
+	time. But overly large values may lead to higher memory usage and
+	request timeouts.
+
+'clone'::
+	Runs 'init' and 'fetch'.  It will automatically create a
+	directory based on the basename of the URL passed to it;
+	or if a second argument is passed; it will create a directory
+	and work within that.  It accepts all arguments that the
+	'init' and 'fetch' commands accept; with the exception of
+	`--fetch-all` and `--parent`.  After a repository is cloned,
+	the 'fetch' command will be able to update revisions without
+	affecting the working tree; and the 'rebase' command will be
+	able to update the working tree with the latest changes.
+
+--preserve-empty-dirs;;
+	Create a placeholder file in the local Git repository for each
+	empty directory fetched from Subversion.  This includes directories
+	that become empty by removing all entries in the Subversion
+	repository (but not the directory itself).  The placeholder files
+	are also tracked and removed when no longer necessary.
+
+--placeholder-filename=<filename>;;
+	Set the name of placeholder files created by --preserve-empty-dirs.
+	Default: ".gitignore"
+
+'rebase'::
+	This fetches revisions from the SVN parent of the current HEAD
+	and rebases the current (uncommitted to SVN) work against it.
++
+This works similarly to `svn update` or 'git pull' except that
+it preserves linear history with 'git rebase' instead of
+'git merge' for ease of dcommitting with 'git svn'.
++
+This accepts all options that 'git svn fetch' and 'git rebase'
+accept.  However, `--fetch-all` only fetches from the current
+[svn-remote], and not all [svn-remote] definitions.
++
+Like 'git rebase'; this requires that the working tree be clean
+and have no uncommitted changes.
++
+This automatically updates the rev_map if needed (see
+'$GIT_DIR/svn/\**/.rev_map.*' in the FILES section below for details).
+
+-l;;
+--local;;
+	Do not fetch remotely; only run 'git rebase' against the
+	last fetched commit from the upstream SVN.
+
+'dcommit'::
+	Commit each diff from the current branch directly to the SVN
+	repository, and then rebase or reset (depending on whether or
+	not there is a diff between SVN and head).  This will create
+	a revision in SVN for each commit in Git.
++
+When an optional Git branch name (or a Git commit object name)
+is specified as an argument, the subcommand works on the specified
+branch, not on the current branch.
++
+Use of 'dcommit' is preferred to 'set-tree' (below).
++
+--no-rebase;;
+	After committing, do not rebase or reset.
+--commit-url <URL>;;
+	Commit to this SVN URL (the full path).  This is intended to
+	allow existing 'git svn' repositories created with one transport
+	method (e.g. `svn://` or `http://` for anonymous read) to be
+	reused if a user is later given access to an alternate transport
+	method (e.g. `svn+ssh://` or `https://`) for commit.
++
+[verse]
+config key: svn-remote.<name>.commiturl
+config key: svn.commiturl (overwrites all svn-remote.<name>.commiturl options)
++
+Note that the SVN URL of the commiturl config key includes the SVN branch.
+If you rather want to set the commit URL for an entire SVN repository use
+svn-remote.<name>.pushurl instead.
++
+Using this option for any other purpose (don't ask) is very strongly
+discouraged.
+
+--mergeinfo=<mergeinfo>;;
+	Add the given merge information during the dcommit
+	(e.g. `--mergeinfo="/branches/foo:1-10"`). All svn server versions can
+	store this information (as a property), and svn clients starting from
+	version 1.5 can make use of it. To specify merge information from multiple
+	branches, use a single space character between the branches
+	(`--mergeinfo="/branches/foo:1-10 /branches/bar:3,5-6,8"`)
++
+[verse]
+config key: svn.pushmergeinfo
++
+This option will cause git-svn to attempt to automatically populate the
+svn:mergeinfo property in the SVN repository when possible. Currently, this can
+only be done when dcommitting non-fast-forward merges where all parents but the
+first have already been pushed into SVN.
+
+--interactive;;
+	Ask the user to confirm that a patch set should actually be sent to SVN.
+	For each patch, one may answer "yes" (accept this patch), "no" (discard this
+	patch), "all" (accept all patches), or "quit".
++
+'git svn dcommit' returns immediately if answer is "no" or "quit", without
+committing anything to SVN.
+
+'branch'::
+	Create a branch in the SVN repository.
+
+-m;;
+--message;;
+	Allows to specify the commit message.
+
+-t;;
+--tag;;
+	Create a tag by using the tags_subdir instead of the branches_subdir
+	specified during git svn init.
+
+-d<path>;;
+--destination=<path>;;
+
+	If more than one --branches (or --tags) option was given to the 'init'
+	or 'clone' command, you must provide the location of the branch (or
+	tag) you wish to create in the SVN repository.  <path> specifies which
+	path to use to create the branch or tag and should match the pattern
+	on the left-hand side of one of the configured branches or tags
+	refspecs.  You can see these refspecs with the commands
++
+	git config --get-all svn-remote.<name>.branches
+	git config --get-all svn-remote.<name>.tags
++
+where <name> is the name of the SVN repository as specified by the -R option to
+'init' (or "svn" by default).
+
+--username;;
+	Specify the SVN username to perform the commit as.  This option overrides
+	the 'username' configuration property.
+
+--commit-url;;
+	Use the specified URL to connect to the destination Subversion
+	repository.  This is useful in cases where the source SVN
+	repository is read-only.  This option overrides configuration
+	property 'commiturl'.
++
+	git config --get-all svn-remote.<name>.commiturl
++
+
+--parents;;
+	Create parent folders. This parameter is equivalent to the parameter
+	--parents on svn cp commands and is useful for non-standard repository
+	layouts.
+
+'tag'::
+	Create a tag in the SVN repository. This is a shorthand for
+	'branch -t'.
+
+'log'::
+	This should make it easy to look up svn log messages when svn
+	users refer to -r/--revision numbers.
++
+The following features from `svn log' are supported:
++
+--
+-r <n>[:<n>];;
+--revision=<n>[:<n>];;
+	is supported, non-numeric args are not:
+	HEAD, NEXT, BASE, PREV, etc ...
+-v;;
+--verbose;;
+	it's not completely compatible with the --verbose
+	output in svn log, but reasonably close.
+--limit=<n>;;
+	is NOT the same as --max-count, doesn't count
+	merged/excluded commits
+--incremental;;
+	supported
+--
++
+New features:
++
+--
+--show-commit;;
+	shows the Git commit sha1, as well
+--oneline;;
+	our version of --pretty=oneline
+--
++
+NOTE: SVN itself only stores times in UTC and nothing else. The regular svn
+client converts the UTC time to the local time (or based on the TZ=
+environment). This command has the same behaviour.
++
+Any other arguments are passed directly to 'git log'
+
+'blame'::
+	Show what revision and author last modified each line of a file. The
+	output of this mode is format-compatible with the output of
+	`svn blame' by default. Like the SVN blame command,
+	local uncommitted changes in the working tree are ignored;
+	the version of the file in the HEAD revision is annotated. Unknown
+	arguments are passed directly to 'git blame'.
++
+--git-format;;
+	Produce output in the same format as 'git blame', but with
+	SVN revision numbers instead of Git commit hashes. In this mode,
+	changes that haven't been committed to SVN (including local
+	working-copy edits) are shown as revision 0.
+
+'find-rev'::
+	When given an SVN revision number of the form 'rN', returns the
+	corresponding Git commit hash (this can optionally be followed by a
+	tree-ish to specify which branch should be searched).  When given a
+	tree-ish, returns the corresponding SVN revision number.
++
+-B;;
+--before;;
+	Don't require an exact match if given an SVN revision, instead find
+	the commit corresponding to the state of the SVN repository (on the
+	current branch) at the specified revision.
++
+-A;;
+--after;;
+	Don't require an exact match if given an SVN revision; if there is
+	not an exact match return the closest match searching forward in the
+	history.
+
+'set-tree'::
+	You should consider using 'dcommit' instead of this command.
+	Commit specified commit or tree objects to SVN.  This relies on
+	your imported fetch data being up to date.  This makes
+	absolutely no attempts to do patching when committing to SVN, it
+	simply overwrites files with those specified in the tree or
+	commit.  All merging is assumed to have taken place
+	independently of 'git svn' functions.
+
+'create-ignore'::
+	Recursively finds the svn:ignore and svn:global-ignores properties
+	on directories and creates matching .gitignore files. The resulting
+	files are staged to be committed, but are not committed. Use
+	-r/--revision to refer to a specific revision.
+
+'show-ignore'::
+	Recursively finds and lists the svn:ignore and svn:global-ignores
+	properties on directories. The output is suitable for appending to
+	the $GIT_DIR/info/exclude file.
+
+'mkdirs'::
+	Attempts to recreate empty directories that core Git cannot track
+	based on information in $GIT_DIR/svn/<refname>/unhandled.log files.
+	Empty directories are automatically recreated when using
+	"git svn clone" and "git svn rebase", so "mkdirs" is intended
+	for use after commands like "git checkout" or "git reset".
+	(See the svn-remote.<name>.automkdirs config file option for
+	more information.)
+
+'commit-diff'::
+	Commits the diff of two tree-ish arguments from the
+	command-line.  This command does not rely on being inside a `git svn
+	init`-ed repository.  This command takes three arguments, (a) the
+	original tree to diff against, (b) the new tree result, (c) the
+	URL of the target Subversion repository.  The final argument
+	(URL) may be omitted if you are working from a 'git svn'-aware
+	repository (that has been `init`-ed with 'git svn').
+	The -r<revision> option is required for this.
++
+The commit message is supplied either directly with the `-m` or `-F`
+option, or indirectly from the tag or commit when the second tree-ish
+denotes such an object, or it is requested by invoking an editor (see
+`--edit` option below).
+
+-m <msg>;;
+--message=<msg>;;
+	Use the given `msg` as the commit message. This option
+	disables the `--edit` option.
+
+-F <filename>;;
+--file=<filename>;;
+	Take the commit message from the given file. This option
+	disables the `--edit` option.
+
+'info'::
+	Shows information about a file or directory similar to what
+	`svn info' provides.  Does not currently support a -r/--revision
+	argument.  Use the --url option to output only the value of the
+	'URL:' field.
+
+'proplist'::
+	Lists the properties stored in the Subversion repository about a
+	given file or directory.  Use -r/--revision to refer to a specific
+	Subversion revision.
+
+'propget'::
+	Gets the Subversion property given as the first argument, for a
+	file.  A specific revision can be specified with -r/--revision.
+
+'propset'::
+	Sets the Subversion property given as the first argument, to the
+	value given as the second argument for the file given as the
+	third argument.
++
+Example:
++
+------------------------------------------------------------------------
+git svn propset svn:keywords "FreeBSD=%H" devel/py-tipper/Makefile
+------------------------------------------------------------------------
++
+This will set the property 'svn:keywords' to 'FreeBSD=%H' for the file
+'devel/py-tipper/Makefile'.
+
+'show-externals'::
+	Shows the Subversion externals.  Use -r/--revision to specify a
+	specific revision.
+
+'gc'::
+	Compress $GIT_DIR/svn/<refname>/unhandled.log files and remove
+	$GIT_DIR/svn/<refname>/index files.
+
+'reset'::
+	Undoes the effects of 'fetch' back to the specified revision.
+	This allows you to re-'fetch' an SVN revision.  Normally the
+	contents of an SVN revision should never change and 'reset'
+	should not be necessary.  However, if SVN permissions change,
+	or if you alter your --ignore-paths option, a 'fetch' may fail
+	with "not found in commit" (file not previously visible) or
+	"checksum mismatch" (missed a modification).  If the problem
+	file cannot be ignored forever (with --ignore-paths) the only
+	way to repair the repo is to use 'reset'.
++
+Only the rev_map and refs/remotes/git-svn are changed (see
+'$GIT_DIR/svn/\**/.rev_map.*' in the FILES section below for details).
+Follow 'reset' with a 'fetch' and then 'git reset' or 'git rebase' to
+move local branches onto the new tree.
+
+-r <n>;;
+--revision=<n>;;
+	Specify the most recent revision to keep.  All later revisions
+	are discarded.
+-p;;
+--parent;;
+	Discard the specified revision as well, keeping the nearest
+	parent instead.
+Example:;;
+Assume you have local changes in "master", but you need to refetch "r2".
++
+------------
+    r1---r2---r3 remotes/git-svn
+                \
+                 A---B master
+------------
++
+Fix the ignore-paths or SVN permissions problem that caused "r2" to
+be incomplete in the first place.  Then:
++
+[verse]
+git svn reset -r2 -p
+git svn fetch
++
+------------
+    r1---r2'--r3' remotes/git-svn
+      \
+       r2---r3---A---B master
+------------
++
+Then fixup "master" with 'git rebase'.
+Do NOT use 'git merge' or your history will not be compatible with a
+future 'dcommit'!
++
+[verse]
+git rebase --onto remotes/git-svn A^ master
++
+------------
+    r1---r2'--r3' remotes/git-svn
+                \
+                 A'--B' master
+------------
+
+OPTIONS
+-------
+
+--shared[=(false|true|umask|group|all|world|everybody)]::
+--template=<template-directory>::
+	Only used with the 'init' command.
+	These are passed directly to 'git init'.
+
+-r <arg>::
+--revision <arg>::
+	   Used with the 'fetch' command.
++
+This allows revision ranges for partial/cauterized history
+to be supported.  $NUMBER, $NUMBER1:$NUMBER2 (numeric ranges),
+$NUMBER:HEAD, and BASE:$NUMBER are all supported.
++
+This can allow you to make partial mirrors when running fetch;
+but is generally not recommended because history will be skipped
+and lost.
+
+-::
+--stdin::
+	Only used with the 'set-tree' command.
++
+Read a list of commits from stdin and commit them in reverse
+order.  Only the leading sha1 is read from each line, so
+'git rev-list --pretty=oneline' output can be used.
+
+--rmdir::
+	Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
++
+Remove directories from the SVN tree if there are no files left
+behind.  SVN can version empty directories, and they are not
+removed by default if there are no files left in them.  Git
+cannot version empty directories.  Enabling this flag will make
+the commit to SVN act like Git.
++
+[verse]
+config key: svn.rmdir
+
+-e::
+--edit::
+	Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
++
+Edit the commit message before committing to SVN.  This is off by
+default for objects that are commits, and forced on when committing
+tree objects.
++
+[verse]
+config key: svn.edit
+
+-l<num>::
+--find-copies-harder::
+	Only used with the 'dcommit', 'set-tree' and 'commit-diff' commands.
++
+They are both passed directly to 'git diff-tree'; see
+linkgit:git-diff-tree[1] for more information.
++
+[verse]
+config key: svn.l
+config key: svn.findcopiesharder
+
+-A<filename>::
+--authors-file=<filename>::
+	Syntax is compatible with the file used by 'git cvsimport' but
+	an empty email address can be supplied with '<>':
++
+------------------------------------------------------------------------
+	loginname = Joe User <user@xxxxxxxxxxx>
+------------------------------------------------------------------------
++
+If this option is specified and 'git svn' encounters an SVN
+committer name that does not exist in the authors-file, 'git svn'
+will abort operation. The user will then have to add the
+appropriate entry.  Re-running the previous 'git svn' command
+after the authors-file is modified should continue operation.
++
+[verse]
+config key: svn.authorsfile
+
+--authors-prog=<filename>::
+	If this option is specified, for each SVN committer name that
+	does not exist in the authors file, the given file is executed
+	with the committer name as the first argument.  The program is
+	expected to return a single line of the form "Name <email>" or
+	"Name <>", which will be treated as if included in the authors
+	file.
++
+Due to historical reasons a relative 'filename' is first searched
+relative to the current directory for 'init' and 'clone' and relative
+to the root of the working tree for 'fetch'. If 'filename' is
+not found, it is searched like any other command in '$PATH'.
++
+[verse]
+config key: svn.authorsProg
+
+-q::
+--quiet::
+	Make 'git svn' less verbose. Specify a second time to make it
+	even less verbose.
+
+-m::
+--merge::
+-s<strategy>::
+--strategy=<strategy>::
+-p::
+--rebase-merges::
+	These are only used with the 'dcommit' and 'rebase' commands.
++
+Passed directly to 'git rebase' when using 'dcommit' if a
+'git reset' cannot be used (see 'dcommit').
+
+-n::
+--dry-run::
+	This can be used with the 'dcommit', 'rebase', 'branch' and
+	'tag' commands.
++
+For 'dcommit', print out the series of Git arguments that would show
+which diffs would be committed to SVN.
++
+For 'rebase', display the local branch associated with the upstream svn
+repository associated with the current branch and the URL of svn
+repository that will be fetched from.
++
+For 'branch' and 'tag', display the urls that will be used for copying when
+creating the branch or tag.
+
+--use-log-author::
+	When retrieving svn commits into Git (as part of 'fetch', 'rebase', or
+	'dcommit' operations), look for the first `From:` line or `Signed-off-by` trailer
+	in the log message and use that as the author string.
++
+[verse]
+config key: svn.useLogAuthor
+
+--add-author-from::
+	When committing to svn from Git (as part of 'set-tree' or 'dcommit'
+	operations), if the existing log message doesn't already have a
+	`From:` or `Signed-off-by` trailer, append a `From:` line based on the
+	Git commit's author string.  If you use this, then `--use-log-author`
+	will retrieve a valid author string for all commits.
++
+[verse]
+config key: svn.addAuthorFrom
+
+ADVANCED OPTIONS
+----------------
+
+-i<GIT_SVN_ID>::
+--id <GIT_SVN_ID>::
+	This sets GIT_SVN_ID (instead of using the environment).  This
+	allows the user to override the default refname to fetch from
+	when tracking a single URL.  The 'log' and 'dcommit' commands
+	no longer require this switch as an argument.
+
+-R<remote-name>::
+--svn-remote <remote-name>::
+	Specify the [svn-remote "<remote-name>"] section to use,
+	this allows SVN multiple repositories to be tracked.
+	Default: "svn"
+
+--follow-parent::
+	This option is only relevant if we are tracking branches (using
+	one of the repository layout options --trunk, --tags,
+	--branches, --stdlayout). For each tracked branch, try to find
+	out where its revision was copied from, and set
+	a suitable parent in the first Git commit for the branch.
+	This is especially helpful when we're tracking a directory
+	that has been moved around within the repository.  If this
+	feature is disabled, the branches created by 'git svn' will all
+	be linear and not share any history, meaning that there will be
+	no information on where branches were branched off or merged.
+	However, following long/convoluted histories can take a long
+	time, so disabling this feature may speed up the cloning
+	process. This feature is enabled by default, use
+	--no-follow-parent to disable it.
++
+[verse]
+config key: svn.followparent
+
+CONFIG FILE-ONLY OPTIONS
+------------------------
+
+svn.noMetadata::
+svn-remote.<name>.noMetadata::
+	This gets rid of the 'git-svn-id:' lines at the end of every commit.
++
+This option can only be used for one-shot imports as 'git svn'
+will not be able to fetch again without metadata. Additionally,
+if you lose your '$GIT_DIR/svn/\**/.rev_map.*' files, 'git svn' will not
+be able to rebuild them.
++
+The 'git svn log' command will not work on repositories using
+this, either.  Using this conflicts with the 'useSvmProps'
+option for (hopefully) obvious reasons.
++
+This option is NOT recommended as it makes it difficult to track down
+old references to SVN revision numbers in existing documentation, bug
+reports, and archives.  If you plan to eventually migrate from SVN to
+Git and are certain about dropping SVN history, consider
+https://github.com/newren/git-filter-repo[git-filter-repo] instead.
+filter-repo also allows reformatting of metadata for ease-of-reading
+and rewriting authorship info for non-"svn.authorsFile" users.
+
+svn.useSvmProps::
+svn-remote.<name>.useSvmProps::
+	This allows 'git svn' to re-map repository URLs and UUIDs from
+	mirrors created using SVN::Mirror (or svk) for metadata.
++
+If an SVN revision has a property, "svm:headrev", it is likely
+that the revision was created by SVN::Mirror (also used by SVK).
+The property contains a repository UUID and a revision.  We want
+to make it look like we are mirroring the original URL, so
+introduce a helper function that returns the original identity
+URL and UUID, and use it when generating metadata in commit
+messages.
+
+svn.useSvnsyncProps::
+svn-remote.<name>.useSvnsyncprops::
+	Similar to the useSvmProps option; this is for users
+	of the svnsync(1) command distributed with SVN 1.4.x and
+	later.
+
+svn-remote.<name>.rewriteRoot::
+	This allows users to create repositories from alternate
+	URLs.  For example, an administrator could run 'git svn' on the
+	server locally (accessing via file://) but wish to distribute
+	the repository with a public http:// or svn:// URL in the
+	metadata so users of it will see the public URL.
+
+svn-remote.<name>.rewriteUUID::
+	Similar to the useSvmProps option; this is for users who need
+	to remap the UUID manually. This may be useful in situations
+	where the original UUID is not available via either useSvmProps
+	or useSvnsyncProps.
+
+svn-remote.<name>.pushurl::
+
+	Similar to Git's `remote.<name>.pushurl`, this key is designed
+	to be used in cases where 'url' points to an SVN repository
+	via a read-only transport, to provide an alternate read/write
+	transport. It is assumed that both keys point to the same
+	repository. Unlike 'commiturl', 'pushurl' is a base path. If
+	either 'commiturl' or 'pushurl' could be used, 'commiturl'
+	takes precedence.
+
+svn.brokenSymlinkWorkaround::
+	This disables potentially expensive checks to workaround
+	broken symlinks checked into SVN by broken clients.  Set this
+	option to "false" if you track a SVN repository with many
+	empty blobs that are not symlinks.  This option may be changed
+	while 'git svn' is running and take effect on the next
+	revision fetched.  If unset, 'git svn' assumes this option to
+	be "true".
+
+svn.pathnameencoding::
+	This instructs git svn to recode pathnames to a given encoding.
+	It can be used by windows users and by those who work in non-utf8
+	locales to avoid corrupted file names with non-ASCII characters.
+	Valid encodings are the ones supported by Perl's Encode module.
+
+svn-remote.<name>.automkdirs::
+	Normally, the "git svn clone" and "git svn rebase" commands
+	attempt to recreate empty directories that are in the
+	Subversion repository.  If this option is set to "false", then
+	empty directories will only be created if the "git svn mkdirs"
+	command is run explicitly.  If unset, 'git svn' assumes this
+	option to be "true".
+
+Since the noMetadata, rewriteRoot, rewriteUUID, useSvnsyncProps and useSvmProps
+options all affect the metadata generated and used by 'git svn'; they
+*must* be set in the configuration file before any history is imported
+and these settings should never be changed once they are set.
+
+Additionally, only one of these options can be used per svn-remote
+section because they affect the 'git-svn-id:' metadata line, except
+for rewriteRoot and rewriteUUID which can be used together.
+
+
+BASIC EXAMPLES
+--------------
+
+Tracking and contributing to the trunk of a Subversion-managed project
+(ignoring tags and branches):
+
+------------------------------------------------------------------------
+# Clone a repo (like git clone):
+	git svn clone http://svn.example.com/project/trunk
+# Enter the newly cloned directory:
+	cd trunk
+# You should be on master branch, double-check with 'git branch'
+	git branch
+# Do some work and commit locally to Git:
+	git commit ...
+# Something is committed to SVN, rebase your local changes against the
+# latest changes in SVN:
+	git svn rebase
+# Now commit your changes (that were committed previously using Git) to SVN,
+# as well as automatically updating your working HEAD:
+	git svn dcommit
+# Append svn:ignore and svn:global-ignores settings to the default Git exclude file:
+	git svn show-ignore >> .git/info/exclude
+------------------------------------------------------------------------
+
+Tracking and contributing to an entire Subversion-managed project
+(complete with a trunk, tags and branches):
+
+------------------------------------------------------------------------
+# Clone a repo with standard SVN directory layout (like git clone):
+	git svn clone http://svn.example.com/project --stdlayout --prefix svn/
+# Or, if the repo uses a non-standard directory layout:
+	git svn clone http://svn.example.com/project -T tr -b branch -t tag --prefix svn/
+# View all branches and tags you have cloned:
+	git branch -r
+# Create a new branch in SVN
+	git svn branch waldo
+# Reset your master to trunk (or any other branch, replacing 'trunk'
+# with the appropriate name):
+	git reset --hard svn/trunk
+# You may only dcommit to one branch/tag/trunk at a time.  The usage
+# of dcommit/rebase/show-ignore should be the same as above.
+------------------------------------------------------------------------
+
+The initial 'git svn clone' can be quite time-consuming
+(especially for large Subversion repositories). If multiple
+people (or one person with multiple machines) want to use
+'git svn' to interact with the same Subversion repository, you can
+do the initial 'git svn clone' to a repository on a server and
+have each person clone that repository with 'git clone':
+
+------------------------------------------------------------------------
+# Do the initial import on a server
+	ssh server "cd /pub && git svn clone http://svn.example.com/project [options...]"
+# Clone locally - make sure the refs/remotes/ space matches the server
+	mkdir project
+	cd project
+	git init
+	git remote add origin server:/pub/project
+	git config --replace-all remote.origin.fetch '+refs/remotes/*:refs/remotes/*'
+	git fetch
+# Prevent fetch/pull from remote Git server in the future,
+# we only want to use git svn for future updates
+	git config --remove-section remote.origin
+# Create a local branch from one of the branches just fetched
+	git checkout -b master FETCH_HEAD
+# Initialize 'git svn' locally (be sure to use the same URL and
+# --stdlayout/-T/-b/-t/--prefix options as were used on server)
+	git svn init http://svn.example.com/project [options...]
+# Pull the latest changes from Subversion
+	git svn rebase
+------------------------------------------------------------------------
+
+REBASE VS. PULL/MERGE
+---------------------
+Prefer to use 'git svn rebase' or 'git rebase', rather than
+'git pull' or 'git merge' to synchronize unintegrated commits with a 'git svn'
+branch. Doing so will keep the history of unintegrated commits linear with
+respect to the upstream SVN repository and allow the use of the preferred
+'git svn dcommit' subcommand to push unintegrated commits back into SVN.
+
+Originally, 'git svn' recommended that developers pulled or merged from
+the 'git svn' branch.  This was because the author favored
+`git svn set-tree B` to commit a single head rather than the
+`git svn set-tree A..B` notation to commit multiple commits. Use of
+'git pull' or 'git merge' with `git svn set-tree A..B` will cause non-linear
+history to be flattened when committing into SVN and this can lead to merge
+commits unexpectedly reversing previous commits in SVN.
+
+MERGE TRACKING
+--------------
+While 'git svn' can track
+copy history (including branches and tags) for repositories adopting a
+standard layout, it cannot yet represent merge history that happened
+inside git back upstream to SVN users.  Therefore it is advised that
+users keep history as linear as possible inside Git to ease
+compatibility with SVN (see the CAVEATS section below).
+
+HANDLING OF SVN BRANCHES
+------------------------
+If 'git svn' is configured to fetch branches (and --follow-branches
+is in effect), it sometimes creates multiple Git branches for one
+SVN branch, where the additional branches have names of the form
+'branchname@nnn' (with nnn an SVN revision number).  These additional
+branches are created if 'git svn' cannot find a parent commit for the
+first commit in an SVN branch, to connect the branch to the history of
+the other branches.
+
+Normally, the first commit in an SVN branch consists
+of a copy operation. 'git svn' will read this commit to get the SVN
+revision the branch was created from. It will then try to find the
+Git commit that corresponds to this SVN revision, and use that as the
+parent of the branch. However, it is possible that there is no suitable
+Git commit to serve as parent.  This will happen, among other reasons,
+if the SVN branch is a copy of a revision that was not fetched by 'git
+svn' (e.g. because it is an old revision that was skipped with
+`--revision`), or if in SVN a directory was copied that is not tracked
+by 'git svn' (such as a branch that is not tracked at all, or a
+subdirectory of a tracked branch). In these cases, 'git svn' will still
+create a Git branch, but instead of using an existing Git commit as the
+parent of the branch, it will read the SVN history of the directory the
+branch was copied from and create appropriate Git commits.  This is
+indicated by the message "Initializing parent: <branchname>".
+
+Additionally, it will create a special branch named
+'<branchname>@<SVN-Revision>', where <SVN-Revision> is the SVN revision
+number the branch was copied from.  This branch will point to the newly
+created parent commit of the branch.  If in SVN the branch was deleted
+and later recreated from a different version, there will be multiple
+such branches with an '@'.
+
+Note that this may mean that multiple Git commits are created for a
+single SVN revision.
+
+An example: in an SVN repository with a standard
+trunk/tags/branches layout, a directory trunk/sub is created in r.100.
+In r.200, trunk/sub is branched by copying it to branches/. 'git svn
+clone -s' will then create a branch 'sub'. It will also create new Git
+commits for r.100 through r.199 and use these as the history of branch
+'sub'. Thus there will be two Git commits for each revision from r.100
+to r.199 (one containing trunk/, one containing trunk/sub/). Finally,
+it will create a branch 'sub@200' pointing to the new parent commit of
+branch 'sub' (i.e. the commit for r.200 and trunk/sub/).
+
+CAVEATS
+-------
+
+For the sake of simplicity and interoperating with Subversion,
+it is recommended that all 'git svn' users clone, fetch and dcommit
+directly from the SVN server, and avoid all 'git clone'/'pull'/'merge'/'push'
+operations between Git repositories and branches.  The recommended
+method of exchanging code between Git branches and users is
+'git format-patch' and 'git am', or just 'dcommit'ing to the SVN repository.
+
+Running 'git merge' or 'git pull' is NOT recommended on a branch you
+plan to 'dcommit' from because Subversion users cannot see any
+merges you've made.  Furthermore, if you merge or pull from a Git branch
+that is a mirror of an SVN branch, 'dcommit' may commit to the wrong
+branch.
+
+If you do merge, note the following rule: 'git svn dcommit' will
+attempt to commit on top of the SVN commit named in
+------------------------------------------------------------------------
+git log --grep=^git-svn-id: --first-parent -1
+------------------------------------------------------------------------
+You 'must' therefore ensure that the most recent commit of the branch
+you want to dcommit to is the 'first' parent of the merge.  Chaos will
+ensue otherwise, especially if the first parent is an older commit on
+the same SVN branch.
+
+'git clone' does not clone branches under the refs/remotes/ hierarchy or
+any 'git svn' metadata, or config.  So repositories created and managed with
+using 'git svn' should use 'rsync' for cloning, if cloning is to be done
+at all.
+
+Since 'dcommit' uses rebase internally, any Git branches you 'git push' to
+before 'dcommit' on will require forcing an overwrite of the existing ref
+on the remote repository.  This is generally considered bad practice,
+see the linkgit:git-push[1] documentation for details.
+
+Do not use the --amend option of linkgit:git-commit[1] on a change you've
+already dcommitted.  It is considered bad practice to --amend commits
+you've already pushed to a remote repository for other users, and
+dcommit with SVN is analogous to that.
+
+When cloning an SVN repository, if none of the options for describing
+the repository layout is used (--trunk, --tags, --branches,
+--stdlayout), 'git svn clone' will create a Git repository with
+completely linear history, where branches and tags appear as separate
+directories in the working copy.  While this is the easiest way to get a
+copy of a complete repository, for projects with many branches it will
+lead to a working copy many times larger than just the trunk. Thus for
+projects using the standard directory structure (trunk/branches/tags),
+it is recommended to clone with option `--stdlayout`. If the project
+uses a non-standard structure, and/or if branches and tags are not
+required, it is easiest to only clone one directory (typically trunk),
+without giving any repository layout options.  If the full history with
+branches and tags is required, the options `--trunk` / `--branches` /
+`--tags` must be used.
+
+When using multiple --branches or --tags, 'git svn' does not automatically
+handle name collisions (for example, if two branches from different paths have
+the same name, or if a branch and a tag have the same name).  In these cases,
+use 'init' to set up your Git repository then, before your first 'fetch', edit
+the $GIT_DIR/config file so that the branches and tags are associated
+with different name spaces.  For example:
+
+	branches = stable/*:refs/remotes/svn/stable/*
+	branches = debug/*:refs/remotes/svn/debug/*
+
+CONFIGURATION
+-------------
+
+'git svn' stores [svn-remote] configuration information in the
+repository $GIT_DIR/config file.  It is similar the core Git
+[remote] sections except 'fetch' keys do not accept glob
+arguments; but they are instead handled by the 'branches'
+and 'tags' keys.  Since some SVN repositories are oddly
+configured with multiple projects glob expansions such those
+listed below are allowed:
+
+------------------------------------------------------------------------
+[svn-remote "project-a"]
+	url = http://server.org/svn
+	fetch = trunk/project-a:refs/remotes/project-a/trunk
+	branches = branches/*/project-a:refs/remotes/project-a/branches/*
+	branches = branches/release_*:refs/remotes/project-a/branches/release_*
+	branches = branches/re*se:refs/remotes/project-a/branches/*
+	tags = tags/*/project-a:refs/remotes/project-a/tags/*
+------------------------------------------------------------------------
+
+Keep in mind that the `*` (asterisk) wildcard of the local ref
+(right of the `:`) *must* be the farthest right path component;
+however the remote wildcard may be anywhere as long as it's an
+independent path component (surrounded by `/` or EOL).   This
+type of configuration is not automatically created by 'init' and
+should be manually entered with a text-editor or using 'git config'.
+
+Also note that only one asterisk is allowed per word. For example:
+
+	branches = branches/re*se:refs/remotes/project-a/branches/*
+
+will match branches 'release', 'rese', 're123se', however
+
+	branches = branches/re*s*e:refs/remotes/project-a/branches/*
+
+will produce an error.
+
+It is also possible to fetch a subset of branches or tags by using a
+comma-separated list of names within braces. For example:
+
+------------------------------------------------------------------------
+[svn-remote "huge-project"]
+	url = http://server.org/svn
+	fetch = trunk/src:refs/remotes/trunk
+	branches = branches/{red,green}/src:refs/remotes/project-a/branches/*
+	tags = tags/{1.0,2.0}/src:refs/remotes/project-a/tags/*
+------------------------------------------------------------------------
+
+Multiple fetch, branches, and tags keys are supported:
+
+------------------------------------------------------------------------
+[svn-remote "messy-repo"]
+	url = http://server.org/svn
+	fetch = trunk/project-a:refs/remotes/project-a/trunk
+	fetch = branches/demos/june-project-a-demo:refs/remotes/project-a/demos/june-demo
+	branches = branches/server/*:refs/remotes/project-a/branches/*
+	branches = branches/demos/2011/*:refs/remotes/project-a/2011-demos/*
+	tags = tags/server/*:refs/remotes/project-a/tags/*
+------------------------------------------------------------------------
+
+Creating a branch in such a configuration requires disambiguating which
+location to use using the -d or --destination flag:
+
+------------------------------------------------------------------------
+$ git svn branch -d branches/server release-2-3-0
+------------------------------------------------------------------------
+
+Note that git-svn keeps track of the highest revision in which a branch
+or tag has appeared. If the subset of branches or tags is changed after
+fetching, then $GIT_DIR/svn/.metadata must be manually edited to remove
+(or reset) branches-maxRev and/or tags-maxRev as appropriate.
+
+FILES
+-----
+$GIT_DIR/svn/\**/.rev_map.*::
+	Mapping between Subversion revision numbers and Git commit
+	names.  In a repository where the noMetadata option is not set,
+	this can be rebuilt from the git-svn-id: lines that are at the
+	end of every commit (see the 'svn.noMetadata' section above for
+	details).
++
+'git svn fetch' and 'git svn rebase' automatically update the rev_map
+if it is missing or not up to date.  'git svn reset' automatically
+rewinds it.
+
+BUGS
+----
+
+We ignore all SVN properties except svn:executable.  Any unhandled
+properties are logged to $GIT_DIR/svn/<refname>/unhandled.log
+
+Renamed and copied directories are not detected by Git and hence not
+tracked when committing to SVN.  I do not plan on adding support for
+this as it's quite difficult and time-consuming to get working for all
+the possible corner cases (Git doesn't do it, either).  Committing
+renamed and copied files is fully supported if they're similar enough
+for Git to detect them.
+
+In SVN, it is possible (though discouraged) to commit changes to a tag
+(because a tag is just a directory copy, thus technically the same as a
+branch). When cloning an SVN repository, 'git svn' cannot know if such a
+commit to a tag will happen in the future. Thus it acts conservatively
+and imports all SVN tags as branches, prefixing the tag name with 'tags/'.
+
+SEE ALSO
+--------
+linkgit:git-rebase[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-switch.adoc b/Documentation/git-switch.adoc
new file mode 100644
index 0000000000..8c33ffb0ab
--- /dev/null
+++ b/Documentation/git-switch.adoc
@@ -0,0 +1,287 @@
+git-switch(1)
+=============
+
+NAME
+----
+git-switch - Switch branches
+
+SYNOPSIS
+--------
+[verse]
+'git switch' [<options>] [--no-guess] <branch>
+'git switch' [<options>] --detach [<start-point>]
+'git switch' [<options>] (-c|-C) <new-branch> [<start-point>]
+'git switch' [<options>] --orphan <new-branch>
+
+DESCRIPTION
+-----------
+Switch to a specified branch. The working tree and the index are
+updated to match the branch. All new commits will be added to the tip
+of this branch.
+
+Optionally a new branch could be created with either `-c`, `-C`,
+automatically from a remote branch of same name (see `--guess`), or
+detach the working tree from any branch with `--detach`, along with
+switching.
+
+Switching branches does not require a clean index and working tree
+(i.e. no differences compared to `HEAD`). The operation is aborted
+however if the operation leads to loss of local changes, unless told
+otherwise with `--discard-changes` or `--merge`.
+
+THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.
+
+OPTIONS
+-------
+<branch>::
+	Branch to switch to.
+
+<new-branch>::
+	Name for the new branch.
+
+<start-point>::
+	The starting point for the new branch. Specifying a
+	`<start-point>` allows you to create a branch based on some
+	other point in history than where HEAD currently points. (Or,
+	in the case of `--detach`, allows you to inspect and detach
+	from some other point.)
++
+You can use the `@{-N}` syntax to refer to the N-th last
+branch/commit switched to using "git switch" or "git checkout"
+operation. You may also specify `-` which is synonymous to `@{-1}`.
+This is often used to switch quickly between two branches, or to undo
+a branch switch by mistake.
++
+As a special case, you may use `A...B` as a shortcut for the merge
+base of `A` and `B` if there is exactly one merge base. You can leave
+out at most one of `A` and `B`, in which case it defaults to `HEAD`.
+
+-c <new-branch>::
+--create <new-branch>::
+	Create a new branch named `<new-branch>` starting at
+	`<start-point>` before switching to the branch. This is the
+	transactional equivalent of
++
+------------
+$ git branch <new-branch>
+$ git switch <new-branch>
+------------
++
+that is to say, the branch is not reset/created unless "git switch" is
+successful (e.g., when the branch is in use in another worktree, not
+just the current branch stays the same, but the branch is not reset to
+the start-point, either).
+
+-C <new-branch>::
+--force-create <new-branch>::
+	Similar to `--create` except that if `<new-branch>` already
+	exists, it will be reset to `<start-point>`. This is a
+	convenient shortcut for:
++
+------------
+$ git branch -f <new-branch>
+$ git switch <new-branch>
+------------
+
+-d::
+--detach::
+	Switch to a commit for inspection and discardable
+	experiments. See the "DETACHED HEAD" section in
+	linkgit:git-checkout[1] for details.
+
+--guess::
+--no-guess::
+	If `<branch>` is not found but there does exist a tracking
+	branch in exactly one remote (call it `<remote>`) with a
+	matching name, treat as equivalent to
++
+------------
+$ git switch -c <branch> --track <remote>/<branch>
+------------
++
+If the branch exists in multiple remotes and one of them is named by
+the `checkout.defaultRemote` configuration variable, we'll use that
+one for the purposes of disambiguation, even if the `<branch>` isn't
+unique across all remotes. Set it to e.g. `checkout.defaultRemote=origin`
+to always checkout remote branches from there if `<branch>` is
+ambiguous but exists on the 'origin' remote. See also
+`checkout.defaultRemote` in linkgit:git-config[1].
++
+`--guess` is the default behavior. Use `--no-guess` to disable it.
++
+The default behavior can be set via the `checkout.guess` configuration
+variable.
+
+-f::
+--force::
+	An alias for `--discard-changes`.
+
+--discard-changes::
+	Proceed even if the index or the working tree differs from
+	`HEAD`. Both the index and working tree are restored to match
+	the switching target. If `--recurse-submodules` is specified,
+	submodule content is also restored to match the switching
+	target. This is used to throw away local changes.
+
+-m::
+--merge::
+	If you have local modifications to one or more files that are
+	different between the current branch and the branch to which
+	you are switching, the command refuses to switch branches in
+	order to preserve your modifications in context.  However,
+	with this option, a three-way merge between the current
+	branch, your working tree contents, and the new branch is
+	done, and you will be on the new branch.
++
+When a merge conflict happens, the index entries for conflicting
+paths are left unmerged, and you need to resolve the conflicts
+and mark the resolved paths with `git add` (or `git rm` if the merge
+should result in deletion of the path).
+
+--conflict=<style>::
+	The same as `--merge` option above, but changes the way the
+	conflicting hunks are presented, overriding the
+	`merge.conflictStyle` configuration variable.  Possible values are
+	"merge" (default), "diff3", and "zdiff3".
+
+-q::
+--quiet::
+	Quiet, suppress feedback messages.
+
+--progress::
+--no-progress::
+	Progress status is reported on the standard error stream
+	by default when it is attached to a terminal, unless `--quiet`
+	is specified. This flag enables progress reporting even if not
+	attached to a terminal, regardless of `--quiet`.
+
+-t::
+--track [direct|inherit]::
+	When creating a new branch, set up "upstream" configuration.
+	`-c` is implied. See `--track` in linkgit:git-branch[1] for
+	details.
++
+If no `-c` option is given, the name of the new branch will be derived
+from the remote-tracking branch, by looking at the local part of the
+refspec configured for the corresponding remote, and then stripping
+the initial part up to the "*".  This would tell us to use `hack` as
+the local branch when branching off of `origin/hack` (or
+`remotes/origin/hack`, or even `refs/remotes/origin/hack`).  If the
+given name has no slash, or the above guessing results in an empty
+name, the guessing is aborted.  You can explicitly give a name with
+`-c` in such a case.
+
+--no-track::
+	Do not set up "upstream" configuration, even if the
+	`branch.autoSetupMerge` configuration variable is true.
+
+--orphan <new-branch>::
+	Create a new unborn branch, named `<new-branch>`. All
+	tracked files are removed.
+
+--ignore-other-worktrees::
+	`git switch` refuses when the wanted ref is already
+	checked out by another worktree. This option makes it check
+	the ref out anyway. In other words, the ref can be held by
+	more than one worktree.
+
+--recurse-submodules::
+--no-recurse-submodules::
+	Using `--recurse-submodules` will update the content of all
+	active submodules according to the commit recorded in the
+	superproject. If nothing (or `--no-recurse-submodules`) is
+	used, submodules working trees will not be updated. Just
+	like linkgit:git-submodule[1], this will detach `HEAD` of the
+	submodules.
+
+EXAMPLES
+--------
+
+The following command switches to the "master" branch:
+
+------------
+$ git switch master
+------------
+
+After working in the wrong branch, switching to the correct branch
+would be done using:
+
+------------
+$ git switch mytopic
+------------
+
+However, your "wrong" branch and correct "mytopic" branch may differ
+in files that you have modified locally, in which case the above
+switch would fail like this:
+
+------------
+$ git switch mytopic
+error: You have local changes to 'frotz'; not switching branches.
+------------
+
+You can give the `-m` flag to the command, which would try a three-way
+merge:
+
+------------
+$ git switch -m mytopic
+Auto-merging frotz
+------------
+
+After this three-way merge, the local modifications are _not_
+registered in your index file, so `git diff` would show you what
+changes you made since the tip of the new branch.
+
+To switch back to the previous branch before we switched to mytopic
+(i.e. "master" branch):
+
+------------
+$ git switch -
+------------
+
+You can grow a new branch from any commit. For example, switch to
+"HEAD~3" and create branch "fixup":
+
+------------
+$ git switch -c fixup HEAD~3
+Switched to a new branch 'fixup'
+------------
+
+If you want to start a new branch from a remote branch of the same
+name:
+
+------------
+$ git switch new-topic
+Branch 'new-topic' set up to track remote branch 'new-topic' from 'origin'
+Switched to a new branch 'new-topic'
+------------
+
+To check out commit `HEAD~3` for temporary inspection or experiment
+without creating a new branch:
+
+------------
+$ git switch --detach HEAD~3
+HEAD is now at 9fc9555312 Merge branch 'cc/shared-index-permbits'
+------------
+
+If it turns out whatever you have done is worth keeping, you can
+always create a new name for it (without switching away):
+
+------------
+$ git switch -c good-surprises
+------------
+
+CONFIGURATION
+-------------
+
+include::includes/cmd-config-section-all.txt[]
+
+include::config/checkout.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-checkout[1],
+linkgit:git-branch[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-symbolic-ref.adoc b/Documentation/git-symbolic-ref.adoc
new file mode 100644
index 0000000000..33ca381fde
--- /dev/null
+++ b/Documentation/git-symbolic-ref.adoc
@@ -0,0 +1,82 @@
+git-symbolic-ref(1)
+===================
+
+NAME
+----
+git-symbolic-ref - Read, modify and delete symbolic refs
+
+SYNOPSIS
+--------
+[verse]
+'git symbolic-ref' [-m <reason>] <name> <ref>
+'git symbolic-ref' [-q] [--short] [--no-recurse] <name>
+'git symbolic-ref' --delete [-q] <name>
+
+DESCRIPTION
+-----------
+Given one argument, reads which branch head the given symbolic
+ref refers to and outputs its path, relative to the `.git/`
+directory.  Typically you would give `HEAD` as the <name>
+argument to see which branch your working tree is on.
+
+Given two arguments, creates or updates a symbolic ref <name> to
+point at the given branch <ref>.
+
+Given `--delete` and an additional argument, deletes the given
+symbolic ref.
+
+A symbolic ref is a regular file that stores a string that
+begins with `ref: refs/`.  For example, your `.git/HEAD` is
+a regular file whose content is `ref: refs/heads/master`.
+
+OPTIONS
+-------
+
+-d::
+--delete::
+	Delete the symbolic ref <name>.
+
+-q::
+--quiet::
+	Do not issue an error message if the <name> is not a
+	symbolic ref but a detached HEAD; instead exit with
+	non-zero status silently.
+
+--short::
+	When showing the value of <name> as a symbolic ref, try to shorten the
+	value, e.g. from `refs/heads/master` to `master`.
+
+--recurse::
+--no-recurse::
+	When showing the value of <name> as a symbolic ref, if
+	<name> refers to another symbolic ref, follow such a chain
+	of symbolic refs until the result no longer points at a
+	symbolic ref (`--recurse`, which is the default).
+	`--no-recurse` stops after dereferencing only a single level
+	of symbolic ref.
+
+-m::
+	Update the reflog for <name> with <reason>.  This is valid only
+	when creating or updating a symbolic ref.
+
+NOTES
+-----
+In the past, `.git/HEAD` was a symbolic link pointing at
+`refs/heads/master`.  When we wanted to switch to another branch,
+we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we wanted
+to find out which branch we are on, we did `readlink .git/HEAD`.
+But symbolic links are not entirely portable, so they are now
+deprecated and symbolic refs (as described above) are used by
+default.
+
+'git symbolic-ref' will exit with status 0 if the contents of the
+symbolic ref were printed correctly, with status 1 if the requested
+name is not a symbolic ref, or 128 if another error occurs.
+
+SEE ALSO
+--------
+linkgit:git-update-ref[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-tag.adoc b/Documentation/git-tag.adoc
new file mode 100644
index 0000000000..a4b1c0ec05
--- /dev/null
+++ b/Documentation/git-tag.adoc
@@ -0,0 +1,418 @@
+git-tag(1)
+==========
+
+NAME
+----
+git-tag - Create, list, delete or verify a tag object signed with GPG
+
+
+SYNOPSIS
+--------
+[verse]
+'git tag' [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]
+	[(--trailer <token>[(=|:)<value>])...]
+	<tagname> [<commit> | <object>]
+'git tag' -d <tagname>...
+'git tag' [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]
+	[--points-at <object>] [--column[=<options>] | --no-column]
+	[--create-reflog] [--sort=<key>] [--format=<format>]
+	[--merged <commit>] [--no-merged <commit>] [<pattern>...]
+'git tag' -v [--format=<format>] <tagname>...
+
+DESCRIPTION
+-----------
+
+Add a tag reference in `refs/tags/`, unless `-d/-l/-v` is given
+to delete, list or verify tags.
+
+Unless `-f` is given, the named tag must not yet exist.
+
+If one of `-a`, `-s`, or `-u <key-id>` is passed, the command
+creates a 'tag' object, and requires a tag message.  Unless
+`-m <msg>` or `-F <file>` is given, an editor is started for the user to type
+in the tag message.
+
+If `-m <msg>` or `-F <file>` or `--trailer <token>[=<value>]` is given
+and `-a`, `-s`, and `-u <key-id>` are absent, `-a` is implied.
+
+Otherwise, a tag reference that points directly at the given object
+(i.e., a lightweight tag) is created.
+
+A GnuPG signed tag object will be created when `-s` or `-u
+<key-id>` is used.  When `-u <key-id>` is not used, the
+committer identity for the current user is used to find the
+GnuPG key for signing. 	The configuration variable `gpg.program`
+is used to specify custom GnuPG binary.
+
+Tag objects (created with `-a`, `-s`, or `-u`) are called "annotated"
+tags; they contain a creation date, the tagger name and e-mail, a
+tagging message, and an optional GnuPG signature. Whereas a
+"lightweight" tag is simply a name for an object (usually a commit
+object).
+
+Annotated tags are meant for release while lightweight tags are meant
+for private or temporary object labels. For this reason, some git
+commands for naming objects (like `git describe`) will ignore
+lightweight tags by default.
+
+
+OPTIONS
+-------
+-a::
+--annotate::
+	Make an unsigned, annotated tag object
+
+-s::
+--sign::
+	Make a GPG-signed tag, using the default e-mail address's key.
+	The default behavior of tag GPG-signing is controlled by `tag.gpgSign`
+	configuration variable if it exists, or disabled otherwise.
+	See linkgit:git-config[1].
+
+--no-sign::
+	Override `tag.gpgSign` configuration variable that is
+	set to force each and every tag to be signed.
+
+-u <key-id>::
+--local-user=<key-id>::
+	Make a GPG-signed tag, using the given key.
+
+-f::
+--force::
+	Replace an existing tag with the given name (instead of failing)
+
+-d::
+--delete::
+	Delete existing tags with the given names.
+
+-v::
+--verify::
+	Verify the GPG signature of the given tag names.
+
+-n<num>::
+	<num> specifies how many lines from the annotation, if any,
+	are printed when using -l. Implies `--list`.
++
+The default is not to print any annotation lines.
+If no number is given to `-n`, only the first line is printed.
+If the tag is not annotated, the commit message is displayed instead.
+
+-l::
+--list::
+	List tags. With optional `<pattern>...`, e.g. `git tag --list
+	'v-*'`, list only the tags that match the pattern(s).
++
+Running "git tag" without arguments also lists all tags. The pattern
+is a shell wildcard (i.e., matched using fnmatch(3)). Multiple
+patterns may be given; if any of them matches, the tag is shown.
++
+This option is implicitly supplied if any other list-like option such
+as `--contains` is provided. See the documentation for each of those
+options for details.
+
+--sort=<key>::
+	Sort based on the key given.  Prefix `-` to sort in
+	descending order of the value. You may use the --sort=<key> option
+	multiple times, in which case the last key becomes the primary
+	key. Also supports "version:refname" or "v:refname" (tag
+	names are treated as versions). The "version:refname" sort
+	order can also be affected by the "versionsort.suffix"
+	configuration variable.
+	The keys supported are the same as those in `git for-each-ref`.
+	Sort order defaults to the value configured for the `tag.sort`
+	variable if it exists, or lexicographic order otherwise. See
+	linkgit:git-config[1].
+
+--color[=<when>]::
+	Respect any colors specified in the `--format` option. The
+	`<when>` field must be one of `always`, `never`, or `auto` (if
+	`<when>` is absent, behave as if `always` was given).
+
+-i::
+--ignore-case::
+	Sorting and filtering tags are case insensitive.
+
+--omit-empty::
+	Do not print a newline after formatted refs where the format expands
+	to the empty string.
+
+--column[=<options>]::
+--no-column::
+	Display tag listing in columns. See configuration variable
+	`column.tag` for option syntax. `--column` and `--no-column`
+	without options are equivalent to 'always' and 'never' respectively.
++
+This option is only applicable when listing tags without annotation lines.
+
+--contains [<commit>]::
+	Only list tags which contain the specified commit (HEAD if not
+	specified). Implies `--list`.
+
+--no-contains [<commit>]::
+	Only list tags which don't contain the specified commit (HEAD if
+	not specified). Implies `--list`.
+
+--merged [<commit>]::
+	Only list tags whose commits are reachable from the specified
+	commit (`HEAD` if not specified).
+
+--no-merged [<commit>]::
+	Only list tags whose commits are not reachable from the specified
+	commit (`HEAD` if not specified).
+
+--points-at <object>::
+	Only list tags of the given object (HEAD if not
+	specified). Implies `--list`.
+
+-m <msg>::
+--message=<msg>::
+	Use the given tag message (instead of prompting).
+	If multiple `-m` options are given, their values are
+	concatenated as separate paragraphs.
+	Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`
+	is given.
+
+-F <file>::
+--file=<file>::
+	Take the tag message from the given file.  Use '-' to
+	read the message from the standard input.
+	Implies `-a` if none of `-a`, `-s`, or `-u <key-id>`
+	is given.
+
+--trailer <token>[(=|:)<value>]::
+	Specify a (<token>, <value>) pair that should be applied as a
+	trailer. (e.g. `git tag --trailer "Custom-Key: value"`
+	will add a "Custom-Key" trailer to the tag message.)
+	The `trailer.*` configuration variables
+	(linkgit:git-interpret-trailers[1]) can be used to define if
+	a duplicated trailer is omitted, where in the run of trailers
+	each trailer would appear, and other details.
+	The trailers can be extracted in `git tag --list`, using
+	`--format="%(trailers)"` placeholder.
+
+-e::
+--edit::
+	The message taken from file with `-F` and command line with
+	`-m` are usually used as the tag message unmodified.
+	This option lets you further edit the message taken from these sources.
+
+--cleanup=<mode>::
+	This option sets how the tag message is cleaned up.
+	The  '<mode>' can be one of 'verbatim', 'whitespace' and 'strip'.  The
+	'strip' mode is default. The 'verbatim' mode does not change message at
+	all, 'whitespace' removes just leading/trailing whitespace lines and
+	'strip' removes both whitespace and commentary.
+
+--create-reflog::
+	Create a reflog for the tag. To globally enable reflogs for tags, see
+	`core.logAllRefUpdates` in linkgit:git-config[1].
+	The negated form `--no-create-reflog` only overrides an earlier
+	`--create-reflog`, but currently does not negate the setting of
+	`core.logAllRefUpdates`.
+
+--format=<format>::
+	A string that interpolates `%(fieldname)` from a tag ref being shown
+	and the object it points at.  The format is the same as
+	that of linkgit:git-for-each-ref[1].  When unspecified,
+	defaults to `%(refname:strip=2)`.
+
+<tagname>::
+	The name of the tag to create, delete, or describe.
+	The new tag name must pass all checks defined by
+	linkgit:git-check-ref-format[1].  Some of these checks
+	may restrict the characters allowed in a tag name.
+
+<commit>::
+<object>::
+	The object that the new tag will refer to, usually a commit.
+	Defaults to HEAD.
+
+CONFIGURATION
+-------------
+By default, 'git tag' in sign-with-default mode (-s) will use your
+committer identity (of the form `Your Name <your@email.address>`) to
+find a key.  If you want to use a different default key, you can specify
+it in the repository configuration as follows:
+
+-------------------------------------
+[user]
+    signingKey = <gpg-key-id>
+-------------------------------------
+
+`pager.tag` is only respected when listing tags, i.e., when `-l` is
+used or implied. The default is to use a pager.
+See linkgit:git-config[1].
+
+DISCUSSION
+----------
+
+On Re-tagging
+~~~~~~~~~~~~~
+
+What should you do when you tag a wrong commit and you would
+want to re-tag?
+
+If you never pushed anything out, just re-tag it. Use "-f" to
+replace the old one. And you're done.
+
+But if you have pushed things out (or others could just read
+your repository directly), then others will have already seen
+the old tag. In that case you can do one of two things:
+
+. The sane thing.
+  Just admit you screwed up, and use a different name. Others have
+  already seen one tag-name, and if you keep the same name, you
+  may be in the situation that two people both have "version X",
+  but they actually have 'different' "X"'s.  So just call it "X.1"
+  and be done with it.
+
+. The insane thing.
+  You really want to call the new version "X" too, 'even though'
+  others have already seen the old one. So just use 'git tag -f'
+  again, as if you hadn't already published the old one.
+
+However, Git does *not* (and it should not) change tags behind
+users back. So if somebody already got the old tag, doing a
+'git pull' on your tree shouldn't just make them overwrite the old
+one.
+
+If somebody got a release tag from you, you cannot just change
+the tag for them by updating your own one. This is a big
+security issue, in that people MUST be able to trust their
+tag-names.  If you really want to do the insane thing, you need
+to just fess up to it, and tell people that you messed up. You
+can do that by making a very public announcement saying:
+
+------------
+Ok, I messed up, and I pushed out an earlier version tagged as X. I
+then fixed something, and retagged the *fixed* tree as X again.
+
+If you got the wrong tag, and want the new one, please delete
+the old one and fetch the new one by doing:
+
+	git tag -d X
+	git fetch origin tag X
+
+to get my updated tag.
+
+You can test which tag you have by doing
+
+	git rev-parse X
+
+which should return 0123456789abcdef.. if you have the new version.
+
+Sorry for the inconvenience.
+------------
+
+Does this seem a bit complicated?  It *should* be. There is no
+way that it would be correct to just "fix" it automatically.
+People need to know that their tags might have been changed.
+
+
+On Automatic following
+~~~~~~~~~~~~~~~~~~~~~~
+
+If you are following somebody else's tree, you are most likely
+using remote-tracking branches (eg. `refs/remotes/origin/master`).
+You usually want the tags from the other end.
+
+On the other hand, if you are fetching because you would want a
+one-shot merge from somebody else, you typically do not want to
+get tags from there.  This happens more often for people near
+the toplevel but not limited to them.  Mere mortals when pulling
+from each other do not necessarily want to automatically get
+private anchor point tags from the other person.
+
+Often, "please pull" messages on the mailing list just provide
+two pieces of information: a repo URL and a branch name; this
+is designed to be easily cut&pasted at the end of a 'git fetch'
+command line:
+
+------------
+Linus, please pull from
+
+	git://git..../proj.git master
+
+to get the following updates...
+------------
+
+becomes:
+
+------------
+$ git pull git://git..../proj.git master
+------------
+
+In such a case, you do not want to automatically follow the other
+person's tags.
+
+One important aspect of Git is its distributed nature, which
+largely means there is no inherent "upstream" or
+"downstream" in the system.  On the face of it, the above
+example might seem to indicate that the tag namespace is owned
+by the upper echelon of people and that tags only flow downwards, but
+that is not the case.  It only shows that the usage pattern
+determines who are interested in whose tags.
+
+A one-shot pull is a sign that a commit history is now crossing
+the boundary between one circle of people (e.g. "people who are
+primarily interested in the networking part of the kernel") who may
+have their own set of tags (e.g. "this is the third release
+candidate from the networking group to be proposed for general
+consumption with 2.6.21 release") to another circle of people
+(e.g. "people who integrate various subsystem improvements").
+The latter are usually not interested in the detailed tags used
+internally in the former group (that is what "internal" means).
+That is why it is desirable not to follow tags automatically in
+this case.
+
+It may well be that among networking people, they may want to
+exchange the tags internal to their group, but in that workflow
+they are most likely tracking each other's progress by
+having remote-tracking branches.  Again, the heuristic to automatically
+follow such tags is a good thing.
+
+
+On Backdating Tags
+~~~~~~~~~~~~~~~~~~
+
+If you have imported some changes from another VCS and would like
+to add tags for major releases of your work, it is useful to be able
+to specify the date to embed inside of the tag object; such data in
+the tag object affects, for example, the ordering of tags in the
+gitweb interface.
+
+To set the date used in future tag objects, set the environment
+variable GIT_COMMITTER_DATE (see the later discussion of possible
+values; the most common form is "YYYY-MM-DD HH:MM").
+
+For example:
+
+------------
+$ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
+------------
+
+include::date-formats.adoc[]
+
+FILES
+-----
+
+`$GIT_DIR/TAG_EDITMSG`::
+	This file contains the message of an in-progress annotated
+	tag. If `git tag` exits due to an error before creating an
+	annotated tag then the tag message that has been provided by the
+	user in an editor session will be available in this file, but
+	may be overwritten by the next invocation of `git tag`.
+
+NOTES
+-----
+
+include::ref-reachability-filters.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-check-ref-format[1].
+linkgit:git-config[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-tools.adoc b/Documentation/git-tools.adoc
new file mode 100644
index 0000000000..d0fec4cddd
--- /dev/null
+++ b/Documentation/git-tools.adoc
@@ -0,0 +1,10 @@
+Git Tools
+=========
+
+When Git was young, people looking for third-party Git-related tools came
+to the Git project itself to find them, thus a list of such tools was
+maintained here. These days, however, search engines fill that role much
+more efficiently, so this manually-maintained list has been retired.
+
+See also the `contrib/` area, and the Git wiki:
+https://git.wiki.kernel.org/index.php/InterfacesFrontendsAndTools
diff --git a/Documentation/git-unpack-file.adoc b/Documentation/git-unpack-file.adoc
new file mode 100644
index 0000000000..e9f148a00d
--- /dev/null
+++ b/Documentation/git-unpack-file.adoc
@@ -0,0 +1,28 @@
+git-unpack-file(1)
+==================
+
+NAME
+----
+git-unpack-file - Creates a temporary file with a blob's contents
+
+
+
+SYNOPSIS
+--------
+[verse]
+'git unpack-file' <blob>
+
+DESCRIPTION
+-----------
+Creates a file holding the contents of the blob specified by sha1. It
+returns the name of the temporary file in the following format:
+	.merge_file_XXXXX
+
+OPTIONS
+-------
+<blob>::
+	Must be a blob id
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-unpack-objects.adoc b/Documentation/git-unpack-objects.adoc
new file mode 100644
index 0000000000..b3de50d710
--- /dev/null
+++ b/Documentation/git-unpack-objects.adoc
@@ -0,0 +1,52 @@
+git-unpack-objects(1)
+=====================
+
+NAME
+----
+git-unpack-objects - Unpack objects from a packed archive
+
+
+SYNOPSIS
+--------
+[verse]
+'git unpack-objects' [-n] [-q] [-r] [--strict]
+
+
+DESCRIPTION
+-----------
+Read a packed archive (.pack) from the standard input, expanding
+the objects contained within and writing them into the repository in
+"loose" (one object per file) format.
+
+Objects that already exist in the repository will *not* be unpacked
+from the packfile.  Therefore, nothing will be unpacked if you use
+this command on a packfile that exists within the target repository.
+
+See linkgit:git-repack[1] for options to generate
+new packs and replace existing ones.
+
+OPTIONS
+-------
+-n::
+        Dry run.  Check the pack file without actually unpacking
+	the objects.
+
+-q::
+	The command usually shows percentage progress.  This
+	flag suppresses it.
+
+-r::
+	When unpacking a corrupt packfile, the command dies at
+	the first corruption.  This flag tells it to keep going
+	and make the best effort to recover as many objects as
+	possible.
+
+--strict::
+	Don't write objects with broken content or links.
+
+--max-input-size=<size>::
+	Die, if the pack is larger than <size>.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-update-index.adoc b/Documentation/git-update-index.adoc
new file mode 100644
index 0000000000..7128aed540
--- /dev/null
+++ b/Documentation/git-update-index.adoc
@@ -0,0 +1,613 @@
+git-update-index(1)
+===================
+
+NAME
+----
+git-update-index - Register file contents in the working tree to the index
+
+
+SYNOPSIS
+--------
+[verse]
+'git update-index'
+	     [--add] [--remove | --force-remove] [--replace]
+	     [--refresh] [-q] [--unmerged] [--ignore-missing]
+	     [(--cacheinfo <mode>,<object>,<file>)...]
+	     [--chmod=(+|-)x]
+	     [--[no-]assume-unchanged]
+	     [--[no-]skip-worktree]
+	     [--[no-]ignore-skip-worktree-entries]
+	     [--[no-]fsmonitor-valid]
+	     [--ignore-submodules]
+	     [--[no-]split-index]
+	     [--[no-|test-|force-]untracked-cache]
+	     [--[no-]fsmonitor]
+	     [--really-refresh] [--unresolve] [--again | -g]
+	     [--info-only] [--index-info]
+	     [-z] [--stdin] [--index-version <n>]
+	     [--show-index-version]
+	     [--verbose]
+	     [--] [<file>...]
+
+DESCRIPTION
+-----------
+Modifies the index. Each file mentioned is updated into the index and
+any 'unmerged' or 'needs updating' state is cleared.
+
+See also linkgit:git-add[1] for a more user-friendly way to do some of
+the most common operations on the index.
+
+The way 'git update-index' handles files it is told about can be modified
+using the various options:
+
+OPTIONS
+-------
+--add::
+	If a specified file isn't in the index already then it's
+	added.
+	Default behaviour is to ignore new files.
+
+--remove::
+	If a specified file is in the index but is missing then it's
+	removed.
+	Default behavior is to ignore removed files.
+
+--refresh::
+	Looks at the current index and checks to see if merges or
+	updates are needed by checking stat() information.
+
+-q::
+        Quiet.  If --refresh finds that the index needs an update, the
+        default behavior is to error out.  This option makes
+	'git update-index' continue anyway.
+
+--ignore-submodules::
+	Do not try to update submodules.  This option is only respected
+	when passed before --refresh.
+
+--unmerged::
+        If --refresh finds unmerged changes in the index, the default
+	behavior is to error out.  This option makes 'git update-index'
+        continue anyway.
+
+--ignore-missing::
+	Ignores missing files during a --refresh
+
+--cacheinfo <mode>,<object>,<path>::
+--cacheinfo <mode> <object> <path>::
+	Directly insert the specified info into the index.  For
+	backward compatibility, you can also give these three
+	arguments as three separate parameters, but new users are
+	encouraged to use a single-parameter form.
+
+--index-info::
+        Read index information from stdin.
+
+--chmod=(+|-)x::
+        Set the execute permissions on the updated files.
+
+--[no-]assume-unchanged::
+	When this flag is specified, the object names recorded
+	for the paths are not updated.  Instead, this option
+	sets/unsets the "assume unchanged" bit for the
+	paths.  When the "assume unchanged" bit is on, the user
+	promises not to change the file and allows Git to assume
+	that the working tree file matches what is recorded in
+	the index.  If you want to change the working tree file,
+	you need to unset the bit to tell Git.  This is
+	sometimes helpful when working with a big project on a
+	filesystem that has a very slow lstat(2) system call
+	(e.g. cifs).
++
+Git will fail (gracefully) in case it needs to modify this file
+in the index e.g. when merging in a commit;
+thus, in case the assumed-untracked file is changed upstream,
+you will need to handle the situation manually.
+
+--really-refresh::
+	Like `--refresh`, but checks stat information unconditionally,
+	without regard to the "assume unchanged" setting.
+
+--[no-]skip-worktree::
+	When one of these flags is specified, the object names recorded
+	for the paths are not updated. Instead, these options
+	set and unset the "skip-worktree" bit for the paths. See
+	section "Skip-worktree bit" below for more information.
+
+
+--[no-]ignore-skip-worktree-entries::
+	Do not remove skip-worktree (AKA "index-only") entries even when
+	the `--remove` option was specified.
+
+--[no-]fsmonitor-valid::
+	When one of these flags is specified, the object names recorded
+	for the paths are not updated. Instead, these options
+	set and unset the "fsmonitor valid" bit for the paths. See
+	section "File System Monitor" below for more information.
+
+-g::
+--again::
+	Runs 'git update-index' itself on the paths whose index
+	entries are different from those of the `HEAD` commit.
+
+--unresolve::
+	Restores the 'unmerged' or 'needs updating' state of a
+	file during a merge if it was cleared by accident.
+
+--info-only::
+	Do not create objects in the object database for all
+	<file> arguments that follow this flag; just insert
+	their object IDs into the index.
+
+--force-remove::
+	Remove the file from the index even when the working directory
+	still has such a file. (Implies --remove.)
+
+--replace::
+	By default, when a file `path` exists in the index,
+	'git update-index' refuses an attempt to add `path/file`.
+	Similarly if a file `path/file` exists, a file `path`
+	cannot be added.  With --replace flag, existing entries
+	that conflict with the entry being added are
+	automatically removed with warning messages.
+
+--stdin::
+	Instead of taking a list of paths from the command line,
+	read a list of paths from the standard input.  Paths are
+	separated by LF (i.e. one path per line) by default.
+
+--verbose::
+	Report what is being added and removed from the index.
+
+--index-version <n>::
+	Write the resulting index out in the named on-disk format version.
+	Supported versions are 2, 3, and 4. The current default version is 2
+	or 3, depending on whether extra features are used, such as
+	`git add -N`.  With `--verbose`, also report the version the index
+	file uses before and after this command.
++
+Version 4 performs a simple pathname compression that reduces index
+size by 30%-50% on large repositories, which results in faster load
+time.  Git supports it since version 1.8.0, released in October 2012,
+and support for it was added to libgit2 in 2016 and to JGit in 2020.
+Older versions of this manual page called it "relatively young", but
+it should be considered mature technology these days.
+
+--show-index-version::
+	Report the index format version used by the on-disk index file.
+	See `--index-version` above.
+
+-z::
+	Only meaningful with `--stdin` or `--index-info`; paths are
+	separated with NUL character instead of LF.
+
+--split-index::
+--no-split-index::
+	Enable or disable split index mode. If split-index mode is
+	already enabled and `--split-index` is given again, all
+	changes in $GIT_DIR/index are pushed back to the shared index
+	file.
++
+These options take effect whatever the value of the `core.splitIndex`
+configuration variable (see linkgit:git-config[1]). But a warning is
+emitted when the change goes against the configured value, as the
+configured value will take effect next time the index is read and this
+will remove the intended effect of the option.
+
+--untracked-cache::
+--no-untracked-cache::
+	Enable or disable untracked cache feature. Please use
+	`--test-untracked-cache` before enabling it.
++
+These options take effect whatever the value of the `core.untrackedCache`
+configuration variable (see linkgit:git-config[1]). But a warning is
+emitted when the change goes against the configured value, as the
+configured value will take effect next time the index is read and this
+will remove the intended effect of the option.
+
+--test-untracked-cache::
+	Only perform tests on the working directory to make sure
+	untracked cache can be used. You have to manually enable
+	untracked cache using `--untracked-cache` or
+	`--force-untracked-cache` or the `core.untrackedCache`
+	configuration variable afterwards if you really want to use
+	it. If a test fails the exit code is 1 and a message
+	explains what is not working as needed, otherwise the exit
+	code is 0 and OK is printed.
+
+--force-untracked-cache::
+	Same as `--untracked-cache`. Provided for backwards
+	compatibility with older versions of Git where
+	`--untracked-cache` used to imply `--test-untracked-cache` but
+	this option would enable the extension unconditionally.
+
+--fsmonitor::
+--no-fsmonitor::
+	Enable or disable files system monitor feature. These options
+	take effect whatever the value of the `core.fsmonitor`
+	configuration variable (see linkgit:git-config[1]). But a warning
+	is emitted when the change goes against the configured value, as
+	the configured value will take effect next time the index is
+	read and this will remove the intended effect of the option.
+
+\--::
+	Do not interpret any more arguments as options.
+
+<file>::
+	Files to act on.
+	Note that files beginning with '.' are discarded. This includes
+	`./file` and `dir/./file`. If you don't want this, then use
+	cleaner names.
+	The same applies to directories ending '/' and paths with '//'
+
+USING --REFRESH
+---------------
+`--refresh` does not calculate a new sha1 file or bring the index
+up to date for mode/content changes. But what it *does* do is to
+"re-match" the stat information of a file with the index, so that you
+can refresh the index for a file that hasn't been changed but where
+the stat entry is out of date.
+
+For example, you'd want to do this after doing a 'git read-tree', to link
+up the stat index details with the proper files.
+
+USING --CACHEINFO OR --INFO-ONLY
+--------------------------------
+`--cacheinfo` is used to register a file that is not in the
+current working directory.  This is useful for minimum-checkout
+merging.
+
+To pretend you have a file at path with mode and sha1, say:
+
+----------------
+$ git update-index --add --cacheinfo <mode>,<sha1>,<path>
+----------------
+
+`--info-only` is used to register files without placing them in the object
+database.  This is useful for status-only repositories.
+
+Both `--cacheinfo` and `--info-only` behave similarly: the index is updated
+but the object database isn't.  `--cacheinfo` is useful when the object is
+in the database but the file isn't available locally.  `--info-only` is
+useful when the file is available, but you do not wish to update the
+object database.
+
+
+USING --INDEX-INFO
+------------------
+
+`--index-info` is a more powerful mechanism that lets you feed
+multiple entry definitions from the standard input, and designed
+specifically for scripts.  It can take inputs of three formats:
+
+    . mode SP type SP sha1          TAB path
++
+This format is to stuff `git ls-tree` output into the index.
+
+    . mode         SP sha1 SP stage TAB path
++
+This format is to put higher order stages into the
+index file and matches 'git ls-files --stage' output.
+
+    . mode         SP sha1          TAB path
++
+This format is no longer produced by any Git command, but is
+and will continue to be supported by `update-index --index-info`.
+
+To place a higher stage entry to the index, the path should
+first be removed by feeding a mode=0 entry for the path, and
+then feeding necessary input lines in the third format.
+
+For example, starting with this index:
+
+------------
+$ git ls-files -s
+100644 8a1218a1024a212bb3db30becd860315f9f3ac52 0       frotz
+------------
+
+you can feed the following input to `--index-info`:
+
+------------
+$ git update-index --index-info
+0 0000000000000000000000000000000000000000	frotz
+100644 8a1218a1024a212bb3db30becd860315f9f3ac52 1	frotz
+100755 8a1218a1024a212bb3db30becd860315f9f3ac52 2	frotz
+------------
+
+The first line of the input feeds 0 as the mode to remove the
+path; the SHA-1 does not matter as long as it is well formatted.
+Then the second and third line feeds stage 1 and stage 2 entries
+for that path.  After the above, we would end up with this:
+
+------------
+$ git ls-files -s
+100644 8a1218a1024a212bb3db30becd860315f9f3ac52 1	frotz
+100755 8a1218a1024a212bb3db30becd860315f9f3ac52 2	frotz
+------------
+
+
+USING ``ASSUME UNCHANGED'' BIT
+------------------------------
+
+Many operations in Git depend on your filesystem to have an
+efficient `lstat(2)` implementation, so that `st_mtime`
+information for working tree files can be cheaply checked to see
+if the file contents have changed from the version recorded in
+the index file.  Unfortunately, some filesystems have
+inefficient `lstat(2)`.  If your filesystem is one of them, you
+can set "assume unchanged" bit to paths you have not changed to
+cause Git not to do this check.  Note that setting this bit on a
+path does not mean Git will check the contents of the file to
+see if it has changed -- it makes Git to omit any checking and
+assume it has *not* changed.  When you make changes to working
+tree files, you have to explicitly tell Git about it by dropping
+"assume unchanged" bit, either before or after you modify them.
+
+In order to set "assume unchanged" bit, use `--assume-unchanged`
+option.  To unset, use `--no-assume-unchanged`. To see which files
+have the "assume unchanged" bit set, use `git ls-files -v`
+(see linkgit:git-ls-files[1]).
+
+The command looks at `core.ignorestat` configuration variable.  When
+this is true, paths updated with `git update-index paths...` and
+paths updated with other Git commands that update both index and
+working tree (e.g. 'git apply --index', 'git checkout-index -u',
+and 'git read-tree -u') are automatically marked as "assume
+unchanged".  Note that "assume unchanged" bit is *not* set if
+`git update-index --refresh` finds the working tree file matches
+the index (use `git update-index --really-refresh` if you want
+to mark them as "assume unchanged").
+
+Sometimes users confuse the assume-unchanged bit with the
+skip-worktree bit.  See the final paragraph in the "Skip-worktree bit"
+section below for an explanation of the differences.
+
+
+EXAMPLES
+--------
+To update and refresh only the files already checked out:
+
+----------------
+$ git checkout-index -n -f -a && git update-index --ignore-missing --refresh
+----------------
+
+On an inefficient filesystem with `core.ignorestat` set::
++
+------------
+$ git update-index --really-refresh              <1>
+$ git update-index --no-assume-unchanged foo.c   <2>
+$ git diff --name-only                           <3>
+$ edit foo.c
+$ git diff --name-only                           <4>
+M foo.c
+$ git update-index foo.c                         <5>
+$ git diff --name-only                           <6>
+$ edit foo.c
+$ git diff --name-only                           <7>
+$ git update-index --no-assume-unchanged foo.c   <8>
+$ git diff --name-only                           <9>
+M foo.c
+------------
++
+<1> forces lstat(2) to set "assume unchanged" bits for paths that match index.
+<2> mark the path to be edited.
+<3> this does lstat(2) and finds index matches the path.
+<4> this does lstat(2) and finds index does *not* match the path.
+<5> registering the new version to index sets "assume unchanged" bit.
+<6> and it is assumed unchanged.
+<7> even after you edit it.
+<8> you can tell about the change after the fact.
+<9> now it checks with lstat(2) and finds it has been changed.
+
+
+SKIP-WORKTREE BIT
+-----------------
+
+Skip-worktree bit can be defined in one (long) sentence: Tell git to
+avoid writing the file to the working directory when reasonably
+possible, and treat the file as unchanged when it is not
+present in the working directory.
+
+Note that not all git commands will pay attention to this bit, and
+some only partially support it.
+
+The update-index flags and the read-tree capabilities relating to the
+skip-worktree bit predated the introduction of the
+linkgit:git-sparse-checkout[1] command, which provides a much easier
+way to configure and handle the skip-worktree bits.  If you want to
+reduce your working tree to only deal with a subset of the files in
+the repository, we strongly encourage the use of
+linkgit:git-sparse-checkout[1] in preference to the low-level
+update-index and read-tree primitives.
+
+The primary purpose of the skip-worktree bit is to enable sparse
+checkouts, i.e. to have working directories with only a subset of
+paths present.  When the skip-worktree bit is set, Git commands (such
+as `switch`, `pull`, `merge`) will avoid writing these files.
+However, these commands will sometimes write these files anyway in
+important cases such as conflicts during a merge or rebase.  Git
+commands will also avoid treating the lack of such files as an
+intentional deletion; for example `git add -u` will not stage a
+deletion for these files and `git commit -a` will not make a commit
+deleting them either.
+
+Although this bit looks similar to assume-unchanged bit, its goal is
+different.  The assume-unchanged bit is for leaving the file in the
+working tree but having Git omit checking it for changes and presuming
+that the file has not been changed (though if it can determine without
+stat'ing the file that it has changed, it is free to record the
+changes).  skip-worktree tells Git to ignore the absence of the file,
+avoid updating it when possible with commands that normally update
+much of the working directory (e.g. `checkout`, `switch`, `pull`,
+etc.), and not have its absence be recorded in commits.  Note that in
+sparse checkouts (setup by `git sparse-checkout` or by configuring
+core.sparseCheckout to true), if a file is marked as skip-worktree in
+the index but is found in the working tree, Git will clear the
+skip-worktree bit for that file.
+
+SPLIT INDEX
+-----------
+
+This mode is designed for repositories with very large indexes, and
+aims at reducing the time it takes to repeatedly write these indexes.
+
+In this mode, the index is split into two files, $GIT_DIR/index and
+$GIT_DIR/sharedindex.<SHA-1>. Changes are accumulated in
+$GIT_DIR/index, the split index, while the shared index file contains
+all index entries and stays unchanged.
+
+All changes in the split index are pushed back to the shared index
+file when the number of entries in the split index reaches a level
+specified by the splitIndex.maxPercentChange config variable (see
+linkgit:git-config[1]).
+
+Each time a new shared index file is created, the old shared index
+files are deleted if their modification time is older than what is
+specified by the splitIndex.sharedIndexExpire config variable (see
+linkgit:git-config[1]).
+
+To avoid deleting a shared index file that is still used, its
+modification time is updated to the current time every time a new split
+index based on the shared index file is either created or read from.
+
+UNTRACKED CACHE
+---------------
+
+This cache is meant to speed up commands that involve determining
+untracked files such as `git status`.
+
+This feature works by recording the mtime of the working tree
+directories and then omitting reading directories and stat calls
+against files in those directories whose mtime hasn't changed. For
+this to work the underlying operating system and file system must
+change the `st_mtime` field of directories if files in the directory
+are added, modified or deleted.
+
+You can test whether the filesystem supports that with the
+`--test-untracked-cache` option. The `--untracked-cache` option used
+to implicitly perform that test in older versions of Git, but that's
+no longer the case.
+
+If you want to enable (or disable) this feature, it is easier to use
+the `core.untrackedCache` configuration variable (see
+linkgit:git-config[1]) than using the `--untracked-cache` option to
+`git update-index` in each repository, especially if you want to do so
+across all repositories you use, because you can set the configuration
+variable to `true` (or `false`) in your `$HOME/.gitconfig` just once
+and have it affect all repositories you touch.
+
+When the `core.untrackedCache` configuration variable is changed, the
+untracked cache is added to or removed from the index the next time a
+command reads the index; while when `--[no-|force-]untracked-cache`
+are used, the untracked cache is immediately added to or removed from
+the index.
+
+Before 2.17, the untracked cache had a bug where replacing a directory
+with a symlink to another directory could cause it to incorrectly show
+files tracked by git as untracked. See the "status: add a failing test
+showing a core.untrackedCache bug" commit to git.git. A workaround for
+that is (and this might work for other undiscovered bugs in the
+future):
+
+----------------
+$ git -c core.untrackedCache=false status
+----------------
+
+This bug has also been shown to affect non-symlink cases of replacing
+a directory with a file when it comes to the internal structures of
+the untracked cache, but no case has been reported where this resulted in
+wrong "git status" output.
+
+There are also cases where existing indexes written by git versions
+before 2.17 will reference directories that don't exist anymore,
+potentially causing many "could not open directory" warnings to be
+printed on "git status". These are new warnings for existing issues
+that were previously silently discarded.
+
+As with the bug described above the solution is to one-off do a "git
+status" run with `core.untrackedCache=false` to flush out the leftover
+bad data.
+
+FILE SYSTEM MONITOR
+-------------------
+
+This feature is intended to speed up git operations for repos that have
+large working directories.
+
+It enables git to work together with a file system monitor (see
+linkgit:git-fsmonitor{litdd}daemon[1]
+and the
+"fsmonitor-watchman" section of linkgit:githooks[5]) that can
+inform it as to what files have been modified. This enables git to avoid
+having to lstat() every file to find modified files.
+
+When used in conjunction with the untracked cache, it can further improve
+performance by avoiding the cost of scanning the entire working directory
+looking for new files.
+
+If you want to enable (or disable) this feature, it is easier to use
+the `core.fsmonitor` configuration variable (see
+linkgit:git-config[1]) than using the `--fsmonitor` option to `git
+update-index` in each repository, especially if you want to do so
+across all repositories you use, because you can set the configuration
+variable in your `$HOME/.gitconfig` just once and have it affect all
+repositories you touch.
+
+When the `core.fsmonitor` configuration variable is changed, the
+file system monitor is added to or removed from the index the next time
+a command reads the index. When `--[no-]fsmonitor` are used, the file
+system monitor is immediately added to or removed from the index.
+
+CONFIGURATION
+-------------
+
+The command honors `core.filemode` configuration variable.  If
+your repository is on a filesystem whose executable bits are
+unreliable, this should be set to 'false' (see linkgit:git-config[1]).
+This causes the command to ignore differences in file modes recorded
+in the index and the file mode on the filesystem if they differ only on
+executable bit.   On such an unfortunate filesystem, you may
+need to use 'git update-index --chmod='.
+
+Quite similarly, if `core.symlinks` configuration variable is set
+to 'false' (see linkgit:git-config[1]), symbolic links are checked out
+as plain files, and this command does not modify a recorded file mode
+from symbolic link to regular file.
+
+The command looks at `core.ignorestat` configuration variable.  See
+'Using "assume unchanged" bit' section above.
+
+The command also looks at `core.trustctime` configuration variable.
+It can be useful when the inode change time is regularly modified by
+something outside Git (file system crawlers and backup systems use
+ctime for marking files processed) (see linkgit:git-config[1]).
+
+The untracked cache extension can be enabled by the
+`core.untrackedCache` configuration variable (see
+linkgit:git-config[1]).
+
+NOTES
+-----
+
+Users often try to use the assume-unchanged and skip-worktree bits
+to tell Git to ignore changes to files that are tracked.  This does not
+work as expected, since Git may still check working tree files against
+the index when performing certain operations.  In general, Git does not
+provide a way to ignore changes to tracked files, so alternate solutions
+are recommended.
+
+For example, if the file you want to change is some sort of config file,
+the repository can include a sample config file that can then be copied
+into the ignored name and modified.  The repository can even include a
+script to treat the sample file as a template, modifying and copying it
+automatically.
+
+SEE ALSO
+--------
+linkgit:git-config[1],
+linkgit:git-add[1],
+linkgit:git-ls-files[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-update-ref.adoc b/Documentation/git-update-ref.adoc
new file mode 100644
index 0000000000..9e6935d38d
--- /dev/null
+++ b/Documentation/git-update-ref.adoc
@@ -0,0 +1,199 @@
+git-update-ref(1)
+=================
+
+NAME
+----
+git-update-ref - Update the object name stored in a ref safely
+
+SYNOPSIS
+--------
+[verse]
+'git update-ref' [-m <reason>] [--no-deref] (-d <ref> [<old-oid>] | [--create-reflog] <ref> <new-oid> [<old-oid>] | --stdin [-z])
+
+DESCRIPTION
+-----------
+Given two arguments, stores the <new-oid> in the <ref>, possibly
+dereferencing the symbolic refs.  E.g. `git update-ref HEAD
+<new-oid>` updates the current branch head to the new object.
+
+Given three arguments, stores the <new-oid> in the <ref>,
+possibly dereferencing the symbolic refs, after verifying that
+the current value of the <ref> matches <old-oid>.
+E.g. `git update-ref refs/heads/master <new-oid> <old-oid>`
+updates the master branch head to <new-oid> only if its current
+value is <old-oid>.  You can specify 40 "0" or an empty string
+as <old-oid> to make sure that the ref you are creating does
+not exist.
+
+The final arguments are object names; this command without any options
+does not support updating a symbolic ref to point to another ref (see
+linkgit:git-symbolic-ref[1]).  But `git update-ref --stdin` does have
+the `symref-*` commands so that regular refs and symbolic refs can be
+committed in the same transaction.
+
+If --no-deref is given, <ref> itself is overwritten, rather than
+the result of following the symbolic pointers.
+
+With `-d`, it deletes the named <ref> after verifying that it
+still contains <old-oid>.
+
+With `--stdin`, update-ref reads instructions from standard input and
+performs all modifications together.  Specify commands of the form:
+
+	update SP <ref> SP <new-oid> [SP <old-oid>] LF
+	create SP <ref> SP <new-oid> LF
+	delete SP <ref> [SP <old-oid>] LF
+	verify SP <ref> [SP <old-oid>] LF
+	symref-update SP <ref> SP <new-target> [SP (ref SP <old-target> | oid SP <old-oid>)] LF
+	symref-create SP <ref> SP <new-target> LF
+	symref-delete SP <ref> [SP <old-target>] LF
+	symref-verify SP <ref> [SP <old-target>] LF
+	option SP <opt> LF
+	start LF
+	prepare LF
+	commit LF
+	abort LF
+
+With `--create-reflog`, update-ref will create a reflog for each ref
+even if one would not ordinarily be created.
+
+Quote fields containing whitespace as if they were strings in C source
+code; i.e., surrounded by double-quotes and with backslash escapes.
+Use 40 "0" characters or the empty string to specify a zero value.  To
+specify a missing value, omit the value and its preceding SP entirely.
+
+Alternatively, use `-z` to specify in NUL-terminated format, without
+quoting:
+
+	update SP <ref> NUL <new-oid> NUL [<old-oid>] NUL
+	create SP <ref> NUL <new-oid> NUL
+	delete SP <ref> NUL [<old-oid>] NUL
+	verify SP <ref> NUL [<old-oid>] NUL
+	symref-update SP <ref> NUL <new-target> [NUL (ref NUL <old-target> | oid NUL <old-oid>)] NUL
+	symref-create SP <ref> NUL <new-target> NUL
+	symref-delete SP <ref> [NUL <old-target>] NUL
+	symref-verify SP <ref> [NUL <old-target>] NUL
+	option SP <opt> NUL
+	start NUL
+	prepare NUL
+	commit NUL
+	abort NUL
+
+In this format, use 40 "0" to specify a zero value, and use the empty
+string to specify a missing value.
+
+In either format, values can be specified in any form that Git
+recognizes as an object name.  Commands in any other format or a
+repeated <ref> produce an error.  Command meanings are:
+
+update::
+	Set <ref> to <new-oid> after verifying <old-oid>, if given.
+	Specify a zero <new-oid> to ensure the ref does not exist
+	after the update and/or a zero <old-oid> to make sure the
+	ref does not exist before the update.
+
+create::
+	Create <ref> with <new-oid> after verifying that it does not
+	exist.  The given <new-oid> may not be zero.
+
+delete::
+	Delete <ref> after verifying that it exists with <old-oid>, if
+	given.  If given, <old-oid> may not be zero.
+
+symref-update::
+	Set <ref> to <new-target> after verifying <old-target> or <old-oid>,
+	if given. Specify a zero <old-oid> to ensure that the ref does not
+	exist before the update.
+
+verify::
+	Verify <ref> against <old-oid> but do not change it.  If
+	<old-oid> is zero or missing, the ref must not exist.
+
+symref-create:
+	Create symbolic ref <ref> with <new-target> after verifying that
+	it does not exist.
+
+symref-delete::
+	Delete <ref> after verifying that it exists with <old-target>, if given.
+
+symref-verify::
+	Verify symbolic <ref> against <old-target> but do not change it.
+	If <old-target> is missing, the ref must not exist.  Can only be
+	used in `no-deref` mode.
+
+option::
+	Modify the behavior of the next command naming a <ref>.
+	The only valid option is `no-deref` to avoid dereferencing
+	a symbolic ref.
+
+start::
+	Start a transaction. In contrast to a non-transactional session, a
+	transaction will automatically abort if the session ends without an
+	explicit commit. This command may create a new empty transaction when
+	the current one has been committed or aborted already.
+
+prepare::
+	Prepare to commit the transaction. This will create lock files for all
+	queued reference updates. If one reference could not be locked, the
+	transaction will be aborted.
+
+commit::
+	Commit all reference updates queued for the transaction, ending the
+	transaction.
+
+abort::
+	Abort the transaction, releasing all locks if the transaction is in
+	prepared state.
+
+If all <ref>s can be locked with matching <old-oid>s
+simultaneously, all modifications are performed.  Otherwise, no
+modifications are performed.  Note that while each individual
+<ref> is updated or deleted atomically, a concurrent reader may
+still see a subset of the modifications.
+
+LOGGING UPDATES
+---------------
+If config parameter "core.logAllRefUpdates" is true and the ref is one
+under "refs/heads/", "refs/remotes/", "refs/notes/", or a pseudoref
+like HEAD or ORIG_HEAD; or the file "$GIT_DIR/logs/<ref>" exists then
+`git update-ref` will append a line to the log file
+"$GIT_DIR/logs/<ref>" (dereferencing all symbolic refs before creating
+the log name) describing the change in ref value.  Log lines are
+formatted as:
+
+    oldsha1 SP newsha1 SP committer LF
+
+Where "oldsha1" is the 40 character hexadecimal value previously
+stored in <ref>, "newsha1" is the 40 character hexadecimal value of
+<new-oid> and "committer" is the committer's name, email address
+and date in the standard Git committer ident format.
+
+Optionally with -m:
+
+    oldsha1 SP newsha1 SP committer TAB message LF
+
+Where all fields are as described above and "message" is the
+value supplied to the -m option.
+
+An update will fail (without changing <ref>) if the current user is
+unable to create a new log file, append to the existing log file
+or does not have committer information available.
+
+NOTES
+-----
+
+Symbolic refs were initially implemented using symbolic links.  This is
+now deprecated since not all filesystems support symbolic links.
+
+This command follows *real* symlinks only if they start with "refs/":
+otherwise it will just try to read them and update them as a regular
+file (i.e. it will allow the filesystem to follow them, but will
+overwrite such a symlink to somewhere else with a regular filename).
+
+SEE ALSO
+--------
+linkgit:git-symbolic-ref[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-update-server-info.adoc b/Documentation/git-update-server-info.adoc
new file mode 100644
index 0000000000..6bc9b50d89
--- /dev/null
+++ b/Documentation/git-update-server-info.adoc
@@ -0,0 +1,41 @@
+git-update-server-info(1)
+=========================
+
+NAME
+----
+git-update-server-info - Update auxiliary info file to help dumb servers
+
+
+SYNOPSIS
+--------
+[verse]
+'git update-server-info' [-f | --force]
+
+DESCRIPTION
+-----------
+A dumb server that does not do on-the-fly pack generations must
+have some auxiliary information files in $GIT_DIR/info and
+$GIT_OBJECT_DIRECTORY/info directories to help clients discover
+what references and packs the server has.  This command
+generates such auxiliary files.
+
+OPTIONS
+-------
+-f::
+--force::
+	Update the info files from scratch.
+
+OUTPUT
+------
+
+Currently the command updates the following files.  Please see
+linkgit:gitrepository-layout[5] for a description of
+what they are for:
+
+* objects/info/packs
+
+* info/refs
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-upload-archive.adoc b/Documentation/git-upload-archive.adoc
new file mode 100644
index 0000000000..e8eb10baad
--- /dev/null
+++ b/Documentation/git-upload-archive.adoc
@@ -0,0 +1,62 @@
+git-upload-archive(1)
+=====================
+
+NAME
+----
+git-upload-archive - Send archive back to git-archive
+
+
+SYNOPSIS
+--------
+[verse]
+'git upload-archive' <repository>
+
+DESCRIPTION
+-----------
+Invoked by 'git archive --remote' and sends a generated archive to the
+other end over the Git protocol.
+
+This command is usually not invoked directly by the end user.  The UI
+for the protocol is on the 'git archive' side, and the program pair
+is meant to be used to get an archive from a remote repository.
+
+SECURITY
+--------
+
+In order to protect the privacy of objects that have been removed from
+history but may not yet have been pruned, `git-upload-archive` avoids
+serving archives for commits and trees that are not reachable from the
+repository's refs.  However, because calculating object reachability is
+computationally expensive, `git-upload-archive` implements a stricter
+but easier-to-check set of rules:
+
+  1. Clients may request a commit or tree that is pointed to directly by
+     a ref. E.g., `git archive --remote=origin v1.0`.
+
+  2. Clients may request a sub-tree within a commit or tree using the
+     `ref:path` syntax. E.g., `git archive --remote=origin v1.0:Documentation`.
+
+  3. Clients may _not_ use other sha1 expressions, even if the end
+     result is reachable. E.g., neither a relative commit like `master^`
+     nor a literal sha1 like `abcd1234` is allowed, even if the result
+     is reachable from the refs.
+
+Note that rule 3 disallows many cases that do not have any privacy
+implications. These rules are subject to change in future versions of
+git, and the server accessed by `git archive --remote` may or may not
+follow these exact rules.
+
+If the config option `uploadArchive.allowUnreachable` is true, these
+rules are ignored, and clients may use arbitrary sha1 expressions.
+This is useful if you do not care about the privacy of unreachable
+objects, or if your object database is already publicly available for
+access via non-smart-http.
+
+OPTIONS
+-------
+<repository>::
+	The repository to get a tar archive from.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-upload-pack.adoc b/Documentation/git-upload-pack.adoc
new file mode 100644
index 0000000000..516d1639d9
--- /dev/null
+++ b/Documentation/git-upload-pack.adoc
@@ -0,0 +1,95 @@
+git-upload-pack(1)
+==================
+
+NAME
+----
+git-upload-pack - Send objects packed back to git-fetch-pack
+
+
+SYNOPSIS
+--------
+[verse]
+'git-upload-pack' [--[no-]strict] [--timeout=<n>] [--stateless-rpc]
+		  [--advertise-refs] <directory>
+
+DESCRIPTION
+-----------
+Invoked by 'git fetch-pack', learns what
+objects the other side is missing, and sends them after packing.
+
+This command is usually not invoked directly by the end user.
+The UI for the protocol is on the 'git fetch-pack' side, and the
+program pair is meant to be used to pull updates from a remote
+repository.  For push operations, see 'git send-pack'.
+
+OPTIONS
+-------
+
+--[no-]strict::
+	Do not try <directory>/.git/ if <directory> is not a Git directory.
+
+--timeout=<n>::
+	Interrupt transfer after <n> seconds of inactivity.
+
+--stateless-rpc::
+	Perform only a single read-write cycle with stdin and stdout.
+	This fits with the HTTP POST request processing model where
+	a program may read the request, write a response, and must exit.
+
+--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 linkgit:gitprotocol-http[5] and "HTTP
+	Transport" in the linkgit:gitprotocol-v2[5]
+	documentation. Also understood by
+	linkgit:git-receive-pack[1].
+
+<directory>::
+	The repository to sync from.
+
+ENVIRONMENT
+-----------
+
+`GIT_PROTOCOL`::
+	Internal variable used for handshaking the wire protocol. Server
+	admins may need to configure some transports to allow this
+	variable to be passed. See the discussion in linkgit:git[1].
+
+`GIT_NO_LAZY_FETCH`::
+	When cloning or fetching from a partial repository (i.e., one
+	itself cloned with `--filter`), the server-side `upload-pack`
+	may need to fetch extra objects from its upstream in order to
+	complete the request. By default, `upload-pack` will refuse to
+	perform such a lazy fetch, because `git fetch` may run arbitrary
+	commands specified in configuration and hooks of the source
+	repository (and `upload-pack` tries to be safe to run even in
+	untrusted `.git` directories).
++
+This is implemented by having `upload-pack` internally set the
+`GIT_NO_LAZY_FETCH` variable to `1`. If you want to override it
+(because you are fetching from a partial clone, and you are sure
+you trust it), you can explicitly set `GIT_NO_LAZY_FETCH` to
+`0`.
+
+SECURITY
+--------
+
+Most Git commands should not be run in an untrusted `.git` directory
+(see the section `SECURITY` in linkgit:git[1]). `upload-pack` tries to
+avoid any dangerous configuration options or hooks from the repository
+it's serving, making it safe to clone an untrusted directory and run
+commands on the resulting clone.
+
+For an extra level of safety, you may be able to run `upload-pack` as an
+alternate user. The details will be platform dependent, but on many
+systems you can run:
+
+    git clone --no-local --upload-pack='sudo -u nobody git-upload-pack' ...
+
+SEE ALSO
+--------
+linkgit:gitnamespaces[7]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-var.adoc b/Documentation/git-var.adoc
new file mode 100644
index 0000000000..0680568dfd
--- /dev/null
+++ b/Documentation/git-var.adoc
@@ -0,0 +1,105 @@
+git-var(1)
+==========
+
+NAME
+----
+git-var - Show a Git logical variable
+
+
+SYNOPSIS
+--------
+[verse]
+'git var' (-l | <variable>)
+
+DESCRIPTION
+-----------
+Prints a Git logical variable. Exits with code 1 if the variable has
+no value.
+
+OPTIONS
+-------
+-l::
+	Display the logical variables. In addition, all the
+	variables of the Git configuration file .git/config are listed
+	as well. (However, the configuration variables listing functionality
+	is deprecated in favor of `git config -l`.)
+
+EXAMPLES
+--------
+	$ git var GIT_AUTHOR_IDENT
+	Eric W. Biederman <ebiederm@xxxxxxxx> 1121223278 -0600
+
+
+VARIABLES
+---------
+GIT_AUTHOR_IDENT::
+    The author of a piece of code.
+
+GIT_COMMITTER_IDENT::
+    The person who put a piece of code into Git.
+
+GIT_EDITOR::
+    Text editor for use by Git commands.  The value is meant to be
+    interpreted by the shell when it is used.  Examples: `~/bin/vi`,
+    `$SOME_ENVIRONMENT_VARIABLE`, `"C:\Program Files\Vim\gvim.exe"
+    --nofork`.  The order of preference is the `$GIT_EDITOR`
+    environment variable, then `core.editor` configuration, then
+    `$VISUAL`, then `$EDITOR`, and then the default chosen at compile
+    time, which is usually 'vi'.
+ifdef::git-default-editor[]
+    The build you are using chose '{git-default-editor}' as the default.
+endif::git-default-editor[]
+
+GIT_SEQUENCE_EDITOR::
+    Text editor used to edit the 'todo' file while running `git rebase
+    -i`. Like `GIT_EDITOR`, the value is meant to be interpreted by
+    the shell when it is used. The order of preference is the
+    `$GIT_SEQUENCE_EDITOR` environment variable, then
+    `sequence.editor` configuration, and then the value of `git var
+    GIT_EDITOR`.
+
+GIT_PAGER::
+    Text viewer for use by Git commands (e.g., 'less').  The value
+    is meant to be interpreted by the shell.  The order of preference
+    is the `$GIT_PAGER` environment variable, then `core.pager`
+    configuration, then `$PAGER`, and then the default chosen at
+    compile time (usually 'less').
+ifdef::git-default-pager[]
+    The build you are using chose '{git-default-pager}' as the default.
+endif::git-default-pager[]
+
+GIT_DEFAULT_BRANCH::
+    The name of the first branch created in newly initialized repositories.
+
+GIT_SHELL_PATH::
+    The path of the binary providing the POSIX shell for commands which use the shell.
+
+GIT_ATTR_SYSTEM::
+    The path to the system linkgit:gitattributes[5] file, if one is enabled.
+
+GIT_ATTR_GLOBAL::
+    The path to the global (per-user) linkgit:gitattributes[5] file.
+
+GIT_CONFIG_SYSTEM::
+    The path to the system configuration file, if one is enabled.
+
+GIT_CONFIG_GLOBAL::
+    The path to the global (per-user) configuration files, if any.
+
+Most path values contain only one value. However, some can contain multiple
+values, which are separated by newlines, and are listed in order from highest to
+lowest priority.  Callers should be prepared for any such path value to contain
+multiple items.
+
+Note that paths are printed even if they do not exist, but not if they are
+disabled by other environment variables.
+
+SEE ALSO
+--------
+linkgit:git-commit-tree[1]
+linkgit:git-tag[1]
+linkgit:git-config[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-verify-commit.adoc b/Documentation/git-verify-commit.adoc
new file mode 100644
index 0000000000..aee4c40eac
--- /dev/null
+++ b/Documentation/git-verify-commit.adoc
@@ -0,0 +1,32 @@
+git-verify-commit(1)
+====================
+
+NAME
+----
+git-verify-commit - Check the GPG signature of commits
+
+SYNOPSIS
+--------
+[verse]
+'git verify-commit' [-v | --verbose] [--raw] <commit>...
+
+DESCRIPTION
+-----------
+Validates the GPG signature created by 'git commit -S'.
+
+OPTIONS
+-------
+--raw::
+	Print the raw gpg status output to standard error instead of the normal
+	human-readable output.
+
+-v::
+--verbose::
+	Print the contents of the commit object before validating it.
+
+<commit>...::
+	SHA-1 identifiers of Git commit objects.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-verify-pack.adoc b/Documentation/git-verify-pack.adoc
new file mode 100644
index 0000000000..d7e886918a
--- /dev/null
+++ b/Documentation/git-verify-pack.adoc
@@ -0,0 +1,53 @@
+git-verify-pack(1)
+==================
+
+NAME
+----
+git-verify-pack - Validate packed Git archive files
+
+
+SYNOPSIS
+--------
+[verse]
+'git verify-pack' [-v | --verbose] [-s | --stat-only] [--] <pack>.idx...
+
+
+DESCRIPTION
+-----------
+Reads given idx file for packed Git archive created with the
+'git pack-objects' command and verifies the idx file and the
+corresponding pack file.
+
+OPTIONS
+-------
+<pack>.idx ...::
+	The idx files to verify.
+
+-v::
+--verbose::
+	After verifying the pack, show the list of objects contained
+	in the pack and a histogram of delta chain length.
+
+-s::
+--stat-only::
+	Do not verify the pack contents; only show the histogram of delta
+	chain length.  With `--verbose`, the list of objects is also shown.
+
+\--::
+	Do not interpret any more arguments as options.
+
+OUTPUT FORMAT
+-------------
+When specifying the -v option the format used is:
+
+	SHA-1 type size size-in-packfile offset-in-packfile
+
+for objects that are not deltified in the pack, and
+
+	SHA-1 type size size-in-packfile offset-in-packfile depth base-SHA-1
+
+for objects that are deltified.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-verify-tag.adoc b/Documentation/git-verify-tag.adoc
new file mode 100644
index 0000000000..81d50ecc4c
--- /dev/null
+++ b/Documentation/git-verify-tag.adoc
@@ -0,0 +1,32 @@
+git-verify-tag(1)
+=================
+
+NAME
+----
+git-verify-tag - Check the GPG signature of tags
+
+SYNOPSIS
+--------
+[verse]
+'git verify-tag' [-v | --verbose] [--format=<format>] [--raw] <tag>...
+
+DESCRIPTION
+-----------
+Validates the gpg signature created by 'git tag'.
+
+OPTIONS
+-------
+--raw::
+	Print the raw gpg status output to standard error instead of the normal
+	human-readable output.
+
+-v::
+--verbose::
+	Print the contents of the tag object before validating it.
+
+<tag>...::
+	SHA-1 identifiers of Git tag objects.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-version.adoc b/Documentation/git-version.adoc
new file mode 100644
index 0000000000..80fa7754a6
--- /dev/null
+++ b/Documentation/git-version.adoc
@@ -0,0 +1,28 @@
+git-version(1)
+==============
+
+NAME
+----
+git-version - Display version information about Git
+
+SYNOPSIS
+--------
+[verse]
+'git version' [--build-options]
+
+DESCRIPTION
+-----------
+With no options given, the version of 'git' is printed on the standard output.
+
+Note that `git --version` is identical to `git version` because the
+former is internally converted into the latter.
+
+OPTIONS
+-------
+--build-options::
+	Include additional information about how git was built for diagnostic
+	purposes.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-web--browse.adoc b/Documentation/git-web--browse.adoc
new file mode 100644
index 0000000000..f2f996cbe1
--- /dev/null
+++ b/Documentation/git-web--browse.adoc
@@ -0,0 +1,124 @@
+git-web{litdd}browse(1)
+=======================
+
+NAME
+----
+git-web--browse - Git helper script to launch a web browser
+
+SYNOPSIS
+--------
+[verse]
+'git web{litdd}browse' [<options>] (<URL>|<file>)...
+
+DESCRIPTION
+-----------
+
+This script tries, as much as possible, to display the URLs and FILEs
+that are passed as arguments, as HTML pages in new tabs on an already
+opened web browser.
+
+The following browsers (or commands) are currently supported:
+
+* firefox (this is the default under X Window when not using KDE)
+* iceweasel
+* seamonkey
+* iceape
+* chromium (also supported as chromium-browser)
+* google-chrome (also supported as chrome)
+* konqueror (this is the default under KDE, see 'Note about konqueror' below)
+* opera
+* w3m (this is the default outside graphical environments)
+* elinks
+* links
+* lynx
+* dillo
+* open (this is the default under Mac OS X GUI)
+* start (this is the default under MinGW)
+* cygstart (this is the default under Cygwin)
+* xdg-open
+
+Custom commands may also be specified.
+
+OPTIONS
+-------
+-b <browser>::
+--browser=<browser>::
+	Use the specified browser. It must be in the list of supported
+	browsers.
+
+-t <browser>::
+--tool=<browser>::
+	Same as above.
+
+-c <conf.var>::
+--config=<conf.var>::
+	CONF.VAR is looked up in the Git config files. If it's set,
+	then its value specifies the browser that should be used.
+
+CONFIGURATION VARIABLES
+-----------------------
+
+CONF.VAR (from -c option) and web.browser
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The web browser can be specified using a configuration variable passed
+with the -c (or --config) command-line option, or the `web.browser`
+configuration variable if the former is not used.
+
+browser.<tool>.path
+~~~~~~~~~~~~~~~~~~~
+
+You can explicitly provide a full path to your preferred browser by
+setting the configuration variable `browser.<tool>.path`. For example,
+you can configure the absolute path to firefox by setting
+'browser.firefox.path'. Otherwise, 'git web{litdd}browse' assumes the tool
+is available in PATH.
+
+browser.<tool>.cmd
+~~~~~~~~~~~~~~~~~~
+
+When the browser, specified by options or configuration variables, is
+not among the supported ones, then the corresponding
+`browser.<tool>.cmd` configuration variable will be looked up. If this
+variable exists then 'git web{litdd}browse' will treat the specified tool
+as a custom command and will use a shell eval to run the command with
+the URLs passed as arguments.
+
+NOTE ABOUT KONQUEROR
+--------------------
+
+When 'konqueror' is specified by a command-line option or a
+configuration variable, we launch 'kfmclient' to try to open the HTML
+man page on an already opened konqueror in a new tab if possible.
+
+For consistency, we also try such a trick if 'browser.konqueror.path' is
+set to something like `A_PATH_TO/konqueror`. That means we will try to
+launch `A_PATH_TO/kfmclient` instead.
+
+If you really want to use 'konqueror', then you can use something like
+the following:
+
+------------------------------------------------
+	[web]
+		browser = konq
+
+	[browser "konq"]
+		cmd = A_PATH_TO/konqueror
+------------------------------------------------
+
+Note about git-config --global
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Note that these configuration variables should probably be set using
+the `--global` flag, for example like this:
+
+------------------------------------------------
+$ git config --global web.browser firefox
+------------------------------------------------
+
+as they are probably more user specific than repository specific.
+See linkgit:git-config[1] for more information about this.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-whatchanged.adoc b/Documentation/git-whatchanged.adoc
new file mode 100644
index 0000000000..8e55e0bb1e
--- /dev/null
+++ b/Documentation/git-whatchanged.adoc
@@ -0,0 +1,43 @@
+git-whatchanged(1)
+==================
+
+NAME
+----
+git-whatchanged - Show logs with differences each commit introduces
+
+
+SYNOPSIS
+--------
+[verse]
+'git whatchanged' <option>...
+
+DESCRIPTION
+-----------
+
+Shows commit logs and diff output each commit introduces.
+
+New users are encouraged to use linkgit:git-log[1] instead.  The
+`whatchanged` command is essentially the same as linkgit:git-log[1]
+but defaults to showing the raw format diff output and skipping merges.
+
+The command is primarily kept for historical reasons; fingers of
+many people who learned Git long before `git log` was invented by
+reading the Linux kernel mailing list are trained to type it.
+
+
+Examples
+--------
+`git whatchanged -p v2.6.12.. include/scsi drivers/scsi`::
+
+	Show as patches the commits since version 'v2.6.12' that changed
+	any file in the include/scsi or drivers/scsi subdirectories
+
+`git whatchanged --since="2 weeks ago" -- gitk`::
+
+	Show the changes during the last two weeks to the file 'gitk'.
+	The "--" is necessary to avoid confusion with the *branch* named
+	'gitk'
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-worktree.adoc b/Documentation/git-worktree.adoc
new file mode 100644
index 0000000000..8340b7f028
--- /dev/null
+++ b/Documentation/git-worktree.adoc
@@ -0,0 +1,529 @@
+git-worktree(1)
+===============
+
+NAME
+----
+git-worktree - Manage multiple working trees
+
+
+SYNOPSIS
+--------
+[verse]
+'git worktree add' [-f] [--detach] [--checkout] [--lock [--reason <string>]]
+		   [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]
+'git worktree list' [-v | --porcelain [-z]]
+'git worktree lock' [--reason <string>] <worktree>
+'git worktree move' <worktree> <new-path>
+'git worktree prune' [-n] [-v] [--expire <expire>]
+'git worktree remove' [-f] <worktree>
+'git worktree repair' [<path>...]
+'git worktree unlock' <worktree>
+
+DESCRIPTION
+-----------
+
+Manage multiple working trees attached to the same repository.
+
+A git repository can support multiple working trees, allowing you to check
+out more than one branch at a time.  With `git worktree add` a new working
+tree is associated with the repository, along with additional metadata
+that differentiates that working tree from others in the same repository.
+The working tree, along with this metadata, is called a "worktree".
+
+This new worktree is called a "linked worktree" as opposed to the "main
+worktree" prepared by linkgit:git-init[1] or linkgit:git-clone[1].
+A repository has one main worktree (if it's not a bare repository) and
+zero or more linked worktrees. When you are done with a linked worktree,
+remove it with `git worktree remove`.
+
+In its simplest form, `git worktree add <path>` automatically creates a
+new branch whose name is the final component of `<path>`, which is
+convenient if you plan to work on a new topic. For instance, `git
+worktree add ../hotfix` creates new branch `hotfix` and checks it out at
+path `../hotfix`. To instead work on an existing branch in a new worktree,
+use `git worktree add <path> <branch>`. On the other hand, if you just
+plan to make some experimental changes or do testing without disturbing
+existing development, it is often convenient to create a 'throwaway'
+worktree not associated with any branch. For instance,
+`git worktree add -d <path>` creates a new worktree with a detached `HEAD`
+at the same commit as the current branch.
+
+If a working tree is deleted without using `git worktree remove`, then
+its associated administrative files, which reside in the repository
+(see "DETAILS" below), will eventually be removed automatically (see
+`gc.worktreePruneExpire` in linkgit:git-config[1]), or you can run
+`git worktree prune` in the main or any linked worktree to clean up any
+stale administrative files.
+
+If the working tree for a linked worktree is stored on a portable device
+or network share which is not always mounted, you can prevent its
+administrative files from being pruned by issuing the `git worktree lock`
+command, optionally specifying `--reason` to explain why the worktree is
+locked.
+
+COMMANDS
+--------
+add <path> [<commit-ish>]::
+
+Create a worktree at `<path>` and checkout `<commit-ish>` into it. The new worktree
+is linked to the current repository, sharing everything except per-worktree
+files such as `HEAD`, `index`, etc. As a convenience, `<commit-ish>` may
+be a bare "`-`", which is synonymous with `@{-1}`.
++
+If `<commit-ish>` is a branch name (call it `<branch>`) and is not found,
+and neither `-b` nor `-B` nor `--detach` are used, but there does
+exist a tracking branch in exactly one remote (call it `<remote>`)
+with a matching name, treat as equivalent to:
++
+------------
+$ git worktree add --track -b <branch> <path> <remote>/<branch>
+------------
++
+If the branch exists in multiple remotes and one of them is named by
+the `checkout.defaultRemote` configuration variable, we'll use that
+one for the purposes of disambiguation, even if the `<branch>` isn't
+unique across all remotes. Set it to
+e.g. `checkout.defaultRemote=origin` to always checkout remote
+branches from there if `<branch>` is ambiguous but exists on the
+`origin` remote. See also `checkout.defaultRemote` in
+linkgit:git-config[1].
++
+If `<commit-ish>` is omitted and neither `-b` nor `-B` nor `--detach` used,
+then, as a convenience, the new worktree is associated with a branch (call
+it `<branch>`) named after `$(basename <path>)`.  If `<branch>` doesn't
+exist, a new branch based on `HEAD` is automatically created as if
+`-b <branch>` was given.  If `<branch>` does exist, it will be checked out
+in the new worktree, if it's not checked out anywhere else, otherwise the
+command will refuse to create the worktree (unless `--force` is used).
++
+If `<commit-ish>` is omitted, neither `--detach`, or `--orphan` is
+used, and there are no valid local branches (or remote branches if
+`--guess-remote` is specified) then, as a convenience, the new worktree is
+associated with a new unborn branch named `<branch>` (after
+`$(basename <path>)` if neither `-b` or `-B` is used) as if `--orphan` was
+passed to the command. In the event the repository has a remote and
+`--guess-remote` is used, but no remote or local branches exist, then the
+command fails with a warning reminding the user to fetch from their remote
+first (or override by using `-f/--force`).
+
+list::
+
+List details of each worktree.  The main worktree is listed first,
+followed by each of the linked worktrees.  The output details include
+whether the worktree is bare, the revision currently checked out, the
+branch currently checked out (or "detached HEAD" if none), "locked" if
+the worktree is locked, "prunable" if the worktree can be pruned by the
+`prune` command.
+
+lock::
+
+If a worktree is on a portable device or network share which is not always
+mounted, lock it to prevent its administrative files from being pruned
+automatically. This also prevents it from being moved or deleted.
+Optionally, specify a reason for the lock with `--reason`.
+
+move::
+
+Move a worktree to a new location. Note that the main worktree or linked
+worktrees containing submodules cannot be moved with this command. (The
+`git worktree repair` command, however, can reestablish the connection
+with linked worktrees if you move the main worktree manually.)
+
+prune::
+
+Prune worktree information in `$GIT_DIR/worktrees`.
+
+remove::
+
+Remove a worktree. Only clean worktrees (no untracked files and no
+modification in tracked files) can be removed. Unclean worktrees or ones
+with submodules can be removed with `--force`. The main worktree cannot be
+removed.
+
+repair [<path>...]::
+
+Repair worktree administrative files, if possible, if they have become
+corrupted or outdated due to external factors.
++
+For instance, if the main worktree (or bare repository) is moved, linked
+worktrees will be unable to locate it. Running `repair` in the main
+worktree will reestablish the connection from linked worktrees back to the
+main worktree.
++
+Similarly, if the working tree for a linked worktree is moved without
+using `git worktree move`, the main worktree (or bare repository) will be
+unable to locate it. Running `repair` within the recently-moved worktree
+will reestablish the connection. If multiple linked worktrees are moved,
+running `repair` from any worktree with each tree's new `<path>` as an
+argument, will reestablish the connection to all the specified paths.
++
+If both the main worktree and linked worktrees have been moved or copied manually,
+then running `repair` in the main worktree and specifying the new `<path>`
+of each linked worktree will reestablish all connections in both
+directions.
+
+unlock::
+
+Unlock a worktree, allowing it to be pruned, moved or deleted.
+
+OPTIONS
+-------
+
+-f::
+--force::
+	By default, `add` refuses to create a new worktree when
+	`<commit-ish>` is a branch name and is already checked out by
+	another worktree, or if `<path>` is already assigned to some
+	worktree but is missing (for instance, if `<path>` was deleted
+	manually). This option overrides these safeguards. To add a missing but
+	locked worktree path, specify `--force` twice.
++
+`move` refuses to move a locked worktree unless `--force` is specified
+twice. If the destination is already assigned to some other worktree but is
+missing (for instance, if `<new-path>` was deleted manually), then `--force`
+allows the move to proceed; use `--force` twice if the destination is locked.
++
+`remove` refuses to remove an unclean worktree unless `--force` is used.
+To remove a locked worktree, specify `--force` twice.
+
+-b <new-branch>::
+-B <new-branch>::
+	With `add`, create a new branch named `<new-branch>` starting at
+	`<commit-ish>`, and check out `<new-branch>` into the new worktree.
+	If `<commit-ish>` is omitted, it defaults to `HEAD`.
+	By default, `-b` refuses to create a new branch if it already
+	exists. `-B` overrides this safeguard, resetting `<new-branch>` to
+	`<commit-ish>`.
+
+-d::
+--detach::
+	With `add`, detach `HEAD` in the new worktree. See "DETACHED HEAD"
+	in linkgit:git-checkout[1].
+
+--[no-]checkout::
+	By default, `add` checks out `<commit-ish>`, however, `--no-checkout` can
+	be used to suppress checkout in order to make customizations,
+	such as configuring sparse-checkout. See "Sparse checkout"
+	in linkgit:git-read-tree[1].
+
+--[no-]guess-remote::
+	With `worktree add <path>`, without `<commit-ish>`, instead
+	of creating a new branch from `HEAD`, if there exists a tracking
+	branch in exactly one remote matching the basename of `<path>`,
+	base the new branch on the remote-tracking branch, and mark
+	the remote-tracking branch as "upstream" from the new branch.
++
+This can also be set up as the default behaviour by using the
+`worktree.guessRemote` config option.
+
+--[no-]relative-paths::
+	Link worktrees using relative paths or absolute paths (default).
+	Overrides the `worktree.useRelativePaths` config option, see
+	linkgit:git-config[1].
++
+With `repair`, the linking files will be updated if there's an absolute/relative
+mismatch, even if the links are correct.
+
+--[no-]track::
+	When creating a new branch, if `<commit-ish>` is a branch,
+	mark it as "upstream" from the new branch.  This is the
+	default if `<commit-ish>` is a remote-tracking branch.  See
+	`--track` in linkgit:git-branch[1] for details.
+
+--lock::
+	Keep the worktree locked after creation. This is the
+	equivalent of `git worktree lock` after `git worktree add`,
+	but without a race condition.
+
+-n::
+--dry-run::
+	With `prune`, do not remove anything; just report what it would
+	remove.
+
+--orphan::
+	With `add`, make the new worktree and index empty, associating
+	the worktree with a new unborn branch named `<new-branch>`.
+
+--porcelain::
+	With `list`, output in an easy-to-parse format for scripts.
+	This format will remain stable across Git versions and regardless of user
+	configuration.  It is recommended to combine this with `-z`.
+	See below for details.
+
+-z::
+	Terminate each line with a NUL rather than a newline when
+	`--porcelain` is specified with `list`. This makes it possible
+	to parse the output when a worktree path contains a newline
+	character.
+
+-q::
+--quiet::
+	With `add`, suppress feedback messages.
+
+-v::
+--verbose::
+	With `prune`, report all removals.
++
+With `list`, output additional information about worktrees (see below).
+
+--expire <time>::
+	With `prune`, only expire unused worktrees older than `<time>`.
++
+With `list`, annotate missing worktrees as prunable if they are older than
+`<time>`.
+
+--reason <string>::
+	With `lock` or with `add --lock`, an explanation why the worktree
+	is locked.
+
+<worktree>::
+	Worktrees can be identified by path, either relative or absolute.
++
+If the last path components in the worktree's path is unique among
+worktrees, it can be used to identify a worktree. For example if you only
+have two worktrees, at `/abc/def/ghi` and `/abc/def/ggg`, then `ghi` or
+`def/ghi` is enough to point to the former worktree.
+
+REFS
+----
+When using multiple worktrees, some refs are shared between all worktrees,
+but others are specific to an individual worktree. One example is `HEAD`,
+which is different for each worktree. This section is about the sharing
+rules and how to access refs of one worktree from another.
+
+In general, all pseudo refs are per-worktree and all refs starting with
+`refs/` are shared. Pseudo refs are ones like `HEAD` which are directly
+under `$GIT_DIR` instead of inside `$GIT_DIR/refs`. There are exceptions,
+however: refs inside `refs/bisect`, `refs/worktree` and `refs/rewritten` are
+not shared.
+
+Refs that are per-worktree can still be accessed from another worktree via
+two special paths, `main-worktree` and `worktrees`. The former gives
+access to per-worktree refs of the main worktree, while the latter to all
+linked worktrees.
+
+For example, `main-worktree/HEAD` or `main-worktree/refs/bisect/good`
+resolve to the same value as the main worktree's `HEAD` and
+`refs/bisect/good` respectively. Similarly, `worktrees/foo/HEAD` or
+`worktrees/bar/refs/bisect/bad` are the same as
+`$GIT_COMMON_DIR/worktrees/foo/HEAD` and
+`$GIT_COMMON_DIR/worktrees/bar/refs/bisect/bad`.
+
+To access refs, it's best not to look inside `$GIT_DIR` directly. Instead
+use commands such as linkgit:git-rev-parse[1] or linkgit:git-update-ref[1]
+which will handle refs correctly.
+
+CONFIGURATION FILE
+------------------
+By default, the repository `config` file is shared across all worktrees.
+If the config variables `core.bare` or `core.worktree` are present in the
+common config file and `extensions.worktreeConfig` is disabled, then they
+will be applied to the main worktree only.
+
+In order to have worktree-specific configuration, you can turn on the
+`worktreeConfig` extension, e.g.:
+
+------------
+$ git config extensions.worktreeConfig true
+------------
+
+In this mode, specific configuration stays in the path pointed by `git
+rev-parse --git-path config.worktree`. You can add or update
+configuration in this file with `git config --worktree`. Older Git
+versions will refuse to access repositories with this extension.
+
+Note that in this file, the exception for `core.bare` and `core.worktree`
+is gone. If they exist in `$GIT_DIR/config`, you must move
+them to the `config.worktree` of the main worktree. You may also take this
+opportunity to review and move other configuration that you do not want to
+share to all worktrees:
+
+ - `core.worktree` should never be shared.
+
+ - `core.bare` should not be shared if the value is `core.bare=true`.
+
+ - `core.sparseCheckout` should not be shared, unless you are sure you
+   always use sparse checkout for all worktrees.
+
+See the documentation of `extensions.worktreeConfig` in
+linkgit:git-config[1] for more details.
+
+DETAILS
+-------
+Each linked worktree has a private sub-directory in the repository's
+`$GIT_DIR/worktrees` directory.  The private sub-directory's name is usually
+the base name of the linked worktree's path, possibly appended with a
+number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the
+command `git worktree add /path/other/test-next next` creates the linked
+worktree in `/path/other/test-next` and also creates a
+`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`
+if `test-next` is already taken).
+
+Within a linked worktree, `$GIT_DIR` is set to point to this private
+directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and
+`$GIT_COMMON_DIR` is set to point back to the main worktree's `$GIT_DIR`
+(e.g. `/path/main/.git`). These settings are made in a `.git` file located at
+the top directory of the linked worktree.
+
+Path resolution via `git rev-parse --git-path` uses either
+`$GIT_DIR` or `$GIT_COMMON_DIR` depending on the path. For example, in the
+linked worktree `git rev-parse --git-path HEAD` returns
+`/path/main/.git/worktrees/test-next/HEAD` (not
+`/path/other/test-next/.git/HEAD` or `/path/main/.git/HEAD`) while `git
+rev-parse --git-path refs/heads/master` uses
+`$GIT_COMMON_DIR` and returns `/path/main/.git/refs/heads/master`,
+since refs are shared across all worktrees, except `refs/bisect`,
+`refs/worktree` and `refs/rewritten`.
+
+See linkgit:gitrepository-layout[5] for more information. The rule of
+thumb is do not make any assumption about whether a path belongs to
+`$GIT_DIR` or `$GIT_COMMON_DIR` when you need to directly access something
+inside `$GIT_DIR`. Use `git rev-parse --git-path` to get the final path.
+
+If you manually move a linked worktree, you need to update the `gitdir` file
+in the entry's directory. For example, if a linked worktree is moved
+to `/newpath/test-next` and its `.git` file points to
+`/path/main/.git/worktrees/test-next`, then update
+`/path/main/.git/worktrees/test-next/gitdir` to reference `/newpath/test-next`
+instead. Better yet, run `git worktree repair` to reestablish the connection
+automatically.
+
+To prevent a `$GIT_DIR/worktrees` entry from being pruned (which
+can be useful in some situations, such as when the
+entry's worktree is stored on a portable device), use the
+`git worktree lock` command, which adds a file named
+`locked` to the entry's directory. The file contains the reason in
+plain text. For example, if a linked worktree's `.git` file points
+to `/path/main/.git/worktrees/test-next` then a file named
+`/path/main/.git/worktrees/test-next/locked` will prevent the
+`test-next` entry from being pruned.  See
+linkgit:gitrepository-layout[5] for details.
+
+When `extensions.worktreeConfig` is enabled, the config file
+`.git/worktrees/<id>/config.worktree` is read after `.git/config` is.
+
+LIST OUTPUT FORMAT
+------------------
+The `worktree list` command has two output formats. The default format shows the
+details on a single line with columns.  For example:
+
+------------
+$ git worktree list
+/path/to/bare-source            (bare)
+/path/to/linked-worktree        abcd1234 [master]
+/path/to/other-linked-worktree  1234abc  (detached HEAD)
+------------
+
+The command also shows annotations for each worktree, according to its state.
+These annotations are:
+
+ * `locked`, if the worktree is locked.
+ * `prunable`, if the worktree can be pruned via `git worktree prune`.
+
+------------
+$ git worktree list
+/path/to/linked-worktree    abcd1234 [master]
+/path/to/locked-worktree    acbd5678 (brancha) locked
+/path/to/prunable-worktree  5678abc  (detached HEAD) prunable
+------------
+
+For these annotations, a reason might also be available and this can be
+seen using the verbose mode. The annotation is then moved to the next line
+indented followed by the additional information.
+
+------------
+$ git worktree list --verbose
+/path/to/linked-worktree              abcd1234 [master]
+/path/to/locked-worktree-no-reason    abcd5678 (detached HEAD) locked
+/path/to/locked-worktree-with-reason  1234abcd (brancha)
+	locked: worktree path is mounted on a portable device
+/path/to/prunable-worktree            5678abc1 (detached HEAD)
+	prunable: gitdir file points to non-existent location
+------------
+
+Note that the annotation is moved to the next line if the additional
+information is available, otherwise it stays on the same line as the
+worktree itself.
+
+Porcelain Format
+~~~~~~~~~~~~~~~~
+The porcelain format has a line per attribute.  If `-z` is given then the lines
+are terminated with NUL rather than a newline.  Attributes are listed with a
+label and value separated by a single space.  Boolean attributes (like `bare`
+and `detached`) are listed as a label only, and are present only
+if the value is true.  Some attributes (like `locked`) can be listed as a label
+only or with a value depending upon whether a reason is available.  The first
+attribute of a worktree is always `worktree`, an empty line indicates the
+end of the record.  For example:
+
+------------
+$ git worktree list --porcelain
+worktree /path/to/bare-source
+bare
+
+worktree /path/to/linked-worktree
+HEAD abcd1234abcd1234abcd1234abcd1234abcd1234
+branch refs/heads/master
+
+worktree /path/to/other-linked-worktree
+HEAD 1234abc1234abc1234abc1234abc1234abc1234a
+detached
+
+worktree /path/to/linked-worktree-locked-no-reason
+HEAD 5678abc5678abc5678abc5678abc5678abc5678c
+branch refs/heads/locked-no-reason
+locked
+
+worktree /path/to/linked-worktree-locked-with-reason
+HEAD 3456def3456def3456def3456def3456def3456b
+branch refs/heads/locked-with-reason
+locked reason why is locked
+
+worktree /path/to/linked-worktree-prunable
+HEAD 1233def1234def1234def1234def1234def1234b
+detached
+prunable gitdir file points to non-existent location
+
+------------
+
+Unless `-z` is used any "unusual" characters in the lock reason such as newlines
+are escaped and the entire reason is quoted as explained for the
+configuration variable `core.quotePath` (see linkgit:git-config[1]).
+For Example:
+
+------------
+$ git worktree list --porcelain
+...
+locked "reason\nwhy is locked"
+...
+------------
+
+EXAMPLES
+--------
+You are in the middle of a refactoring session and your boss comes in and
+demands that you fix something immediately. You might typically use
+linkgit:git-stash[1] to store your changes away temporarily, however, your
+working tree is in such a state of disarray (with new, moved, and removed
+files, and other bits and pieces strewn around) that you don't want to risk
+disturbing any of it. Instead, you create a temporary linked worktree to
+make the emergency fix, remove it when done, and then resume your earlier
+refactoring session.
+
+------------
+$ git worktree add -b emergency-fix ../temp master
+$ pushd ../temp
+# ... hack hack hack ...
+$ git commit -a -m 'emergency fix for boss'
+$ popd
+$ git worktree remove ../temp
+------------
+
+BUGS
+----
+Multiple checkout in general is still experimental, and the support
+for submodules is incomplete. It is NOT recommended to make multiple
+checkouts of a superproject.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git-write-tree.adoc b/Documentation/git-write-tree.adoc
new file mode 100644
index 0000000000..f22041a9dc
--- /dev/null
+++ b/Documentation/git-write-tree.adoc
@@ -0,0 +1,42 @@
+git-write-tree(1)
+=================
+
+NAME
+----
+git-write-tree - Create a tree object from the current index
+
+
+SYNOPSIS
+--------
+[verse]
+'git write-tree' [--missing-ok] [--prefix=<prefix>/]
+
+DESCRIPTION
+-----------
+Creates a tree object using the current index. The name of the new
+tree object is printed to standard output.
+
+The index must be in a fully merged state.
+
+Conceptually, 'git write-tree' sync()s the current index contents
+into a set of tree files.
+In order to have that match what is actually in your directory right
+now, you need to have done a 'git update-index' phase before you did the
+'git write-tree'.
+
+
+OPTIONS
+-------
+--missing-ok::
+	Normally 'git write-tree' ensures that the objects referenced by the
+	directory exist in the object database.  This option disables this
+	check.
+
+--prefix=<prefix>/::
+	Writes a tree object that represents a subdirectory
+	`<prefix>`.  This can be used to write the tree object
+	for a subproject that is in the named subdirectory.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/git.adoc b/Documentation/git.adoc
new file mode 100644
index 0000000000..a9c1183318
--- /dev/null
+++ b/Documentation/git.adoc
@@ -0,0 +1,1190 @@
+git(1)
+======
+
+NAME
+----
+git - the stupid content tracker
+
+
+SYNOPSIS
+--------
+[verse]
+'git' [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
+    [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
+    [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]
+    [--no-optional-locks] [--no-advice] [--bare] [--git-dir=<path>]
+    [--work-tree=<path>] [--namespace=<name>] [--config-env=<name>=<envvar>]
+    <command> [<args>]
+
+DESCRIPTION
+-----------
+Git is a fast, scalable, distributed revision control system with an
+unusually rich command set that provides both high-level operations
+and full access to internals.
+
+See linkgit:gittutorial[7] to get started, then see
+linkgit:giteveryday[7] for a useful minimum set of
+commands.  The link:user-manual.html[Git User's Manual] has a more
+in-depth introduction.
+
+After you mastered the basic concepts, you can come back to this
+page to learn what commands Git offers.  You can learn more about
+individual Git commands with "git help command".  linkgit:gitcli[7]
+manual page gives you an overview of the command-line command syntax.
+
+A formatted and hyperlinked copy of the latest Git documentation
+can be viewed at https://git.github.io/htmldocs/git.html
+or https://git-scm.com/docs.
+
+
+OPTIONS
+-------
+-v::
+--version::
+	Prints the Git suite version that the 'git' program came from.
++
+This option is internally converted to `git version ...` and accepts
+the same options as the linkgit:git-version[1] command. If `--help` is
+also given, it takes precedence over `--version`.
+
+-h::
+--help::
+	Prints the synopsis and a list of the most commonly used
+	commands. If the option `--all` or `-a` is given then all
+	available commands are printed. If a Git command is named this
+	option will bring up the manual page for that command.
++
+Other options are available to control how the manual page is
+displayed. See linkgit:git-help[1] for more information,
+because `git --help ...` is converted internally into `git
+help ...`.
+
+-C <path>::
+	Run as if git was started in '<path>' instead of the current working
+	directory.  When multiple `-C` options are given, each subsequent
+	non-absolute `-C <path>` is interpreted relative to the preceding `-C
+	<path>`.  If '<path>' is present but empty, e.g. `-C ""`, then the
+	current working directory is left unchanged.
++
+This option affects options that expect path name like `--git-dir` and
+`--work-tree` in that their interpretations of the path names would be
+made relative to the working directory caused by the `-C` option. For
+example the following invocations are equivalent:
+
+    git --git-dir=a.git --work-tree=b -C c status
+    git --git-dir=c/a.git --work-tree=c/b status
+
+-c <name>=<value>::
+	Pass a configuration parameter to the command. The value
+	given will override values from configuration files.
+	The <name> is expected in the same format as listed by
+	'git config' (subkeys separated by dots).
++
+Note that omitting the `=` in `git -c foo.bar ...` is allowed and sets
+`foo.bar` to the boolean true value (just like `[foo]bar` would in a
+config file). Including the equals but with an empty value (like `git -c
+foo.bar= ...`) sets `foo.bar` to the empty string which `git config
+--type=bool` will convert to `false`.
+
+--config-env=<name>=<envvar>::
+	Like `-c <name>=<value>`, give configuration variable
+	'<name>' a value, where <envvar> is the name of an
+	environment variable from which to retrieve the value. Unlike
+	`-c` there is no shortcut for directly setting the value to an
+	empty string, instead the environment variable itself must be
+	set to the empty string.  It is an error if the `<envvar>` does not exist
+	in the environment. `<envvar>` may not contain an equals sign
+	to avoid ambiguity with `<name>` containing one.
++
+This is useful for cases where you want to pass transitory
+configuration options to git, but are doing so on operating systems
+where other processes might be able to read your command line
+(e.g. `/proc/self/cmdline`), but not your environment
+(e.g. `/proc/self/environ`). That behavior is the default on
+Linux, but may not be on your system.
++
+Note that this might add security for variables such as
+`http.extraHeader` where the sensitive information is part of
+the value, but not e.g. `url.<base>.insteadOf` where the
+sensitive information can be part of the key.
+
+--exec-path[=<path>]::
+	Path to wherever your core Git programs are installed.
+	This can also be controlled by setting the GIT_EXEC_PATH
+	environment variable. If no path is given, 'git' will print
+	the current setting and then exit.
+
+--html-path::
+	Print the path, without trailing slash, where Git's HTML
+	documentation is installed and exit.
+
+--man-path::
+	Print the manpath (see `man(1)`) for the man pages for
+	this version of Git and exit.
+
+--info-path::
+	Print the path where the Info files documenting this
+	version of Git are installed and exit.
+
+-p::
+--paginate::
+	Pipe all output into 'less' (or if set, $PAGER) if standard
+	output is a terminal.  This overrides the `pager.<cmd>`
+	configuration options (see the "Configuration Mechanism" section
+	below).
+
+-P::
+--no-pager::
+	Do not pipe Git output into a pager.
+
+--git-dir=<path>::
+	Set the path to the repository (".git" directory). This can also be
+	controlled by setting the `GIT_DIR` environment variable. It can be
+	an absolute path or relative path to current working directory.
++
+Specifying the location of the ".git" directory using this
+option (or `GIT_DIR` environment variable) turns off the
+repository discovery that tries to find a directory with
+".git" subdirectory (which is how the repository and the
+top-level of the working tree are discovered), and tells Git
+that you are at the top level of the working tree.  If you
+are not at the top-level directory of the working tree, you
+should tell Git where the top-level of the working tree is,
+with the `--work-tree=<path>` option (or `GIT_WORK_TREE`
+environment variable)
++
+If you just want to run git as if it was started in `<path>` then use
+`git -C <path>`.
+
+--work-tree=<path>::
+	Set the path to the working tree. It can be an absolute path
+	or a path relative to the current working directory.
+	This can also be controlled by setting the GIT_WORK_TREE
+	environment variable and the core.worktree configuration
+	variable (see core.worktree in linkgit:git-config[1] for a
+	more detailed discussion).
+
+--namespace=<path>::
+	Set the Git namespace.  See linkgit:gitnamespaces[7] for more
+	details.  Equivalent to setting the `GIT_NAMESPACE` environment
+	variable.
+
+--bare::
+	Treat the repository as a bare repository.  If GIT_DIR
+	environment is not set, it is set to the current working
+	directory.
+
+--no-replace-objects::
+	Do not use replacement refs to replace Git objects.
+	This is equivalent to exporting the `GIT_NO_REPLACE_OBJECTS`
+	environment variable with any value.
+	See linkgit:git-replace[1] for more information.
+
+--no-lazy-fetch::
+	Do not fetch missing objects from the promisor remote on
+	demand.  Useful together with `git cat-file -e <object>` to
+	see if the object is locally available.
+	This is equivalent to setting the `GIT_NO_LAZY_FETCH`
+	environment variable to `1`.
+
+--no-optional-locks::
+	Do not perform optional operations that require locks. This is
+	equivalent to setting the `GIT_OPTIONAL_LOCKS` to `0`.
+
+--no-advice::
+	Disable all advice hints from being printed.
+
+--literal-pathspecs::
+	Treat pathspecs literally (i.e. no globbing, no pathspec magic).
+	This is equivalent to setting the `GIT_LITERAL_PATHSPECS` environment
+	variable to `1`.
+
+--glob-pathspecs::
+	Add "glob" magic to all pathspec. This is equivalent to setting
+	the `GIT_GLOB_PATHSPECS` environment variable to `1`. Disabling
+	globbing on individual pathspecs can be done using pathspec
+	magic ":(literal)"
+
+--noglob-pathspecs::
+	Add "literal" magic to all pathspec. This is equivalent to setting
+	the `GIT_NOGLOB_PATHSPECS` environment variable to `1`. Enabling
+	globbing on individual pathspecs can be done using pathspec
+	magic ":(glob)"
+
+--icase-pathspecs::
+	Add "icase" magic to all pathspec. This is equivalent to setting
+	the `GIT_ICASE_PATHSPECS` environment variable to `1`.
+
+--list-cmds=<group>[,<group>...]::
+	List commands by group. This is an internal/experimental
+	option and may change or be removed in the future. Supported
+	groups are: builtins, parseopt (builtin commands that use
+	parse-options), main (all commands in libexec directory),
+	others (all other commands in `$PATH` that have git- prefix),
+	list-<category> (see categories in command-list.txt),
+	nohelpers (exclude helper commands), alias and config
+	(retrieve command list from config variable completion.commands)
+
+--attr-source=<tree-ish>::
+	Read gitattributes from <tree-ish> instead of the worktree. See
+	linkgit:gitattributes[5]. This is equivalent to setting the
+	`GIT_ATTR_SOURCE` environment variable.
+
+GIT COMMANDS
+------------
+
+We divide Git into high level ("porcelain") commands and low level
+("plumbing") commands.
+
+High-level commands (porcelain)
+-------------------------------
+
+We separate the porcelain commands into the main commands and some
+ancillary user utilities.
+
+Main porcelain commands
+~~~~~~~~~~~~~~~~~~~~~~~
+
+include::{build_dir}/cmds-mainporcelain.adoc[]
+
+Ancillary Commands
+~~~~~~~~~~~~~~~~~~
+Manipulators:
+
+include::{build_dir}/cmds-ancillarymanipulators.adoc[]
+
+Interrogators:
+
+include::{build_dir}/cmds-ancillaryinterrogators.adoc[]
+
+
+Interacting with Others
+~~~~~~~~~~~~~~~~~~~~~~~
+
+These commands are to interact with foreign SCM and with other
+people via patch over e-mail.
+
+include::{build_dir}/cmds-foreignscminterface.adoc[]
+
+Reset, restore and revert
+~~~~~~~~~~~~~~~~~~~~~~~~~
+There are three commands with similar names: `git reset`,
+`git restore` and `git revert`.
+
+* linkgit:git-revert[1] is about making a new commit that reverts the
+  changes made by other commits.
+
+* linkgit:git-restore[1] is about restoring files in the working tree
+  from either the index or another commit. This command does not
+  update your branch. The command can also be used to restore files in
+  the index from another commit.
+
+* linkgit:git-reset[1] is about updating your branch, moving the tip
+  in order to add or remove commits from the branch. This operation
+  changes the commit history.
++
+`git reset` can also be used to restore the index, overlapping with
+`git restore`.
+
+
+Low-level commands (plumbing)
+-----------------------------
+
+Although Git includes its
+own porcelain layer, its low-level commands are sufficient to support
+development of alternative porcelains.  Developers of such porcelains
+might start by reading about linkgit:git-update-index[1] and
+linkgit:git-read-tree[1].
+
+The interface (input, output, set of options and the semantics)
+to these low-level commands are meant to be a lot more stable
+than Porcelain level commands, because these commands are
+primarily for scripted use.  The interface to Porcelain commands
+on the other hand are subject to change in order to improve the
+end user experience.
+
+The following description divides
+the low-level commands into commands that manipulate objects (in
+the repository, index, and working tree), commands that interrogate and
+compare objects, and commands that move objects and references between
+repositories.
+
+
+Manipulation commands
+~~~~~~~~~~~~~~~~~~~~~
+
+include::{build_dir}/cmds-plumbingmanipulators.adoc[]
+
+
+Interrogation commands
+~~~~~~~~~~~~~~~~~~~~~~
+
+include::{build_dir}/cmds-plumbinginterrogators.adoc[]
+
+In general, the interrogate commands do not touch the files in
+the working tree.
+
+
+Syncing repositories
+~~~~~~~~~~~~~~~~~~~~
+
+include::{build_dir}/cmds-synchingrepositories.adoc[]
+
+The following are helper commands used by the above; end users
+typically do not use them directly.
+
+include::{build_dir}/cmds-synchelpers.adoc[]
+
+
+Internal helper commands
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+These are internal helper commands used by other commands; end
+users typically do not use them directly.
+
+include::{build_dir}/cmds-purehelpers.adoc[]
+
+Guides
+------
+
+The following documentation pages are guides about Git concepts.
+
+include::{build_dir}/cmds-guide.adoc[]
+
+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 criteria.
+
+include::{build_dir}/cmds-userinterfaces.adoc[]
+
+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::{build_dir}/cmds-developerinterfaces.adoc[]
+
+Configuration Mechanism
+-----------------------
+
+Git uses a simple text format to store customizations that are per
+repository and are per user.  Such a configuration file may look
+like this:
+
+------------
+#
+# A '#' or ';' character indicates a comment.
+#
+
+; core variables
+[core]
+	; Don't trust file modes
+	filemode = false
+
+; user identity
+[user]
+	name = "Junio C Hamano"
+	email = "gitster@xxxxxxxxx"
+
+------------
+
+Various commands read from the configuration file and adjust
+their operation accordingly.  See linkgit:git-config[1] for a
+list and more details about the configuration mechanism.
+
+
+Identifier Terminology
+----------------------
+<object>::
+	Indicates the object name for any type of object.
+
+<blob>::
+	Indicates a blob object name.
+
+<tree>::
+	Indicates a tree object name.
+
+<commit>::
+	Indicates a commit object name.
+
+<tree-ish>::
+	Indicates a tree, commit or tag object name.  A
+	command that takes a <tree-ish> argument ultimately wants to
+	operate on a <tree> object but automatically dereferences
+	<commit> and <tag> objects that point at a <tree>.
+
+<commit-ish>::
+	Indicates a commit or tag object name.  A
+	command that takes a <commit-ish> argument ultimately wants to
+	operate on a <commit> object but automatically dereferences
+	<tag> objects that point at a <commit>.
+
+<type>::
+	Indicates that an object type is required.
+	Currently one of: `blob`, `tree`, `commit`, or `tag`.
+
+<file>::
+	Indicates a filename - almost always relative to the
+	root of the tree structure `GIT_INDEX_FILE` describes.
+
+Symbolic Identifiers
+--------------------
+Any Git command accepting any <object> can also use the following
+symbolic notation:
+
+HEAD::
+	indicates the head of the current branch.
+
+<tag>::
+	a valid tag 'name'
+	(i.e. a `refs/tags/<tag>` reference).
+
+<head>::
+	a valid head 'name'
+	(i.e. a `refs/heads/<head>` reference).
+
+For a more complete list of ways to spell object names, see
+"SPECIFYING REVISIONS" section in linkgit:gitrevisions[7].
+
+
+File/Directory Structure
+------------------------
+
+Please see the linkgit:gitrepository-layout[5] document.
+
+Read linkgit:githooks[5] for more details about each hook.
+
+Higher level SCMs may provide and manage additional information in the
+`$GIT_DIR`.
+
+
+Terminology
+-----------
+Please see linkgit:gitglossary[7].
+
+
+Environment Variables
+---------------------
+Various Git commands pay attention to environment variables and change
+their behavior.  The environment variables marked as "Boolean" take
+their values the same way as Boolean valued configuration variables, e.g.
+"true", "yes", "on" and positive numbers are taken as "yes".
+
+Here are the variables:
+
+System
+~~~~~~
+`HOME`::
+	Specifies the path to the user's home directory. On Windows, if
+	unset, Git will set a process environment variable equal to:
+	`$HOMEDRIVE$HOMEPATH` if both `$HOMEDRIVE` and `$HOMEPATH` exist;
+	otherwise `$USERPROFILE` if `$USERPROFILE` exists.
+
+The Git Repository
+~~~~~~~~~~~~~~~~~~
+These environment variables apply to 'all' core Git commands. Nb: it
+is worth noting that they may be used/overridden by SCMS sitting above
+Git so take care if using a foreign front-end.
+
+`GIT_INDEX_FILE`::
+	This environment variable specifies an alternate
+	index file. If not specified, the default of `$GIT_DIR/index`
+	is used.
+
+`GIT_INDEX_VERSION`::
+	This environment variable specifies what index version is used
+	when writing the index file out.  It won't affect existing index
+	files.  By default index file version 2 or 3 is used. See
+	linkgit:git-update-index[1] for more information.
+
+`GIT_OBJECT_DIRECTORY`::
+	If the object storage directory is specified via this
+	environment variable then the sha1 directories are created
+	underneath - otherwise the default `$GIT_DIR/objects`
+	directory is used.
+
+`GIT_ALTERNATE_OBJECT_DIRECTORIES`::
+	Due to the immutable nature of Git objects, old objects can be
+	archived into shared, read-only directories. This variable
+	specifies a ":" separated (on Windows ";" separated) list
+	of Git object directories which can be used to search for Git
+	objects. New objects will not be written to these directories.
++
+Entries that begin with `"` (double-quote) will be interpreted
+as C-style quoted paths, removing leading and trailing
+double-quotes and respecting backslash escapes. E.g., the value
+`"path-with-\"-and-:-in-it":vanilla-path` has two paths:
+`path-with-"-and-:-in-it` and `vanilla-path`.
+
+`GIT_DIR`::
+	If the `GIT_DIR` environment variable is set then it
+	specifies a path to use instead of the default `.git`
+	for the base of the repository.
+	The `--git-dir` command-line option also sets this value.
+
+`GIT_WORK_TREE`::
+	Set the path to the root of the working tree.
+	This can also be controlled by the `--work-tree` command-line
+	option and the core.worktree configuration variable.
+
+`GIT_NAMESPACE`::
+	Set the Git namespace; see linkgit:gitnamespaces[7] for details.
+	The `--namespace` command-line option also sets this value.
+
+`GIT_CEILING_DIRECTORIES`::
+	This should be a colon-separated list of absolute paths.  If
+	set, it is a list of directories that Git should not chdir up
+	into while looking for a repository directory (useful for
+	excluding slow-loading network directories).  It will not
+	exclude the current working directory or a GIT_DIR set on the
+	command line or in the environment.  Normally, Git has to read
+	the entries in this list and resolve any symlink that
+	might be present in order to compare them with the current
+	directory.  However, if even this access is slow, you
+	can add an empty entry to the list to tell Git that the
+	subsequent entries are not symlinks and needn't be resolved;
+	e.g.,
+	`GIT_CEILING_DIRECTORIES=/maybe/symlink::/very/slow/non/symlink`.
+
+`GIT_DISCOVERY_ACROSS_FILESYSTEM`::
+	When run in a directory that does not have ".git" repository
+	directory, Git tries to find such a directory in the parent
+	directories to find the top of the working tree, but by default it
+	does not cross filesystem boundaries.  This Boolean environment variable
+	can be set to true to tell Git not to stop at filesystem
+	boundaries.  Like `GIT_CEILING_DIRECTORIES`, this will not affect
+	an explicit repository directory set via `GIT_DIR` or on the
+	command line.
+
+`GIT_COMMON_DIR`::
+	If this variable is set to a path, non-worktree files that are
+	normally in $GIT_DIR will be taken from this path
+	instead. Worktree-specific files such as HEAD or index are
+	taken from $GIT_DIR. See linkgit:gitrepository-layout[5] and
+	linkgit:git-worktree[1] for
+	details. This variable has lower precedence than other path
+	variables such as GIT_INDEX_FILE, GIT_OBJECT_DIRECTORY...
+
+`GIT_DEFAULT_HASH`::
+	If this variable is set, the default hash algorithm for new
+	repositories will be set to this value. This value is
+	ignored when cloning and the setting of the remote repository
+	is always used. The default is "sha1".
+	See `--object-format` in linkgit:git-init[1].
+
+`GIT_DEFAULT_REF_FORMAT`::
+	If this variable is set, the default reference backend format for new
+	repositories will be set to this value. The default is "files".
+	See `--ref-format` in linkgit:git-init[1].
+
+Git Commits
+~~~~~~~~~~~
+`GIT_AUTHOR_NAME`::
+	The human-readable name used in the author identity when creating commit or
+	tag objects, or when writing reflogs. Overrides the `user.name` and
+	`author.name` configuration settings.
+
+`GIT_AUTHOR_EMAIL`::
+	The email address used in the author identity when creating commit or
+	tag objects, or when writing reflogs. Overrides the `user.email` and
+	`author.email` configuration settings.
+
+`GIT_AUTHOR_DATE`::
+	The date used for the author identity when creating commit or tag objects, or
+	when writing reflogs. See linkgit:git-commit[1] for valid formats.
+
+`GIT_COMMITTER_NAME`::
+	The human-readable name used in the committer identity when creating commit or
+	tag objects, or when writing reflogs. Overrides the `user.name` and
+	`committer.name` configuration settings.
+
+`GIT_COMMITTER_EMAIL`::
+	The email address used in the author identity when creating commit or
+	tag objects, or when writing reflogs. Overrides the `user.email` and
+	`committer.email` configuration settings.
+
+`GIT_COMMITTER_DATE`::
+	The date used for the committer identity when creating commit or tag objects, or
+	when writing reflogs. See linkgit:git-commit[1] for valid formats.
+
+`EMAIL`::
+	The email address used in the author and committer identities if no other
+	relevant environment variable or configuration setting has been set.
+
+Git Diffs
+~~~~~~~~~
+`GIT_DIFF_OPTS`::
+	Only valid setting is "--unified=??" or "-u??" to set the
+	number of context lines shown when a unified diff is created.
+	This takes precedence over any "-U" or "--unified" option
+	value passed on the Git diff command line.
+
+`GIT_EXTERNAL_DIFF`::
+	When the environment variable `GIT_EXTERNAL_DIFF` is set, the
+	program named by it is called to generate diffs, and Git
+	does not use its builtin diff machinery.
+	For a path that is added, removed, or modified,
+	`GIT_EXTERNAL_DIFF` is called with 7 parameters:
+
+	path old-file old-hex old-mode new-file new-hex new-mode
++
+where:
+
+	<old|new>-file:: are files GIT_EXTERNAL_DIFF can use to read the
+                         contents of <old|new>,
+	<old|new>-hex:: are the 40-hexdigit SHA-1 hashes,
+	<old|new>-mode:: are the octal representation of the file modes.
++
+The file parameters can point at the user's working file
+(e.g. `new-file` in "git-diff-files"), `/dev/null` (e.g. `old-file`
+when a new file is added), or a temporary file (e.g. `old-file` in the
+index).  `GIT_EXTERNAL_DIFF` should not worry about unlinking the
+temporary file -- it is removed when `GIT_EXTERNAL_DIFF` exits.
++
+For a path that is unmerged, `GIT_EXTERNAL_DIFF` is called with 1
+parameter, <path>.
++
+For each path `GIT_EXTERNAL_DIFF` is called, two environment variables,
+`GIT_DIFF_PATH_COUNTER` and `GIT_DIFF_PATH_TOTAL` are set.
+
+`GIT_EXTERNAL_DIFF_TRUST_EXIT_CODE`::
+	If this Boolean environment variable is set to true then the
+	`GIT_EXTERNAL_DIFF` command is expected to return exit code
+	0 if it considers the input files to be equal or 1 if it
+	considers them to be different, like `diff(1)`.
+	If it is set to false, which is the default, then the command
+	is expected to return exit code 0 regardless of equality.
+	Any other exit code causes Git to report a fatal error.
+
+
+`GIT_DIFF_PATH_COUNTER`::
+	A 1-based counter incremented by one for every path.
+
+`GIT_DIFF_PATH_TOTAL`::
+	The total number of paths.
+
+other
+~~~~~
+`GIT_MERGE_VERBOSITY`::
+	A number controlling the amount of output shown by
+	the recursive merge strategy.  Overrides merge.verbosity.
+	See linkgit:git-merge[1]
+
+`GIT_PAGER`::
+	This environment variable overrides `$PAGER`. If it is set
+	to an empty string or to the value "cat", Git will not launch
+	a pager.  See also the `core.pager` option in
+	linkgit:git-config[1].
+
+`GIT_PROGRESS_DELAY`::
+	A number controlling how many seconds to delay before showing
+	optional progress indicators. Defaults to 2.
+
+`GIT_EDITOR`::
+	This environment variable overrides `$EDITOR` and `$VISUAL`.
+	It is used by several Git commands when, on interactive mode,
+	an editor is to be launched. See also linkgit:git-var[1]
+	and the `core.editor` option in linkgit:git-config[1].
+
+`GIT_SEQUENCE_EDITOR`::
+	This environment variable overrides the configured Git editor
+	when editing the todo list of an interactive rebase. See also
+	linkgit:git-rebase[1] and the `sequence.editor` option in
+	linkgit:git-config[1].
+
+`GIT_SSH`::
+`GIT_SSH_COMMAND`::
+	If either of these environment variables is set then 'git fetch'
+	and 'git push' will use the specified command instead of 'ssh'
+	when they need to connect to a remote system.
+	The command-line parameters passed to the configured command are
+	determined by the ssh variant.  See `ssh.variant` option in
+	linkgit:git-config[1] for details.
++
+`$GIT_SSH_COMMAND` takes precedence over `$GIT_SSH`, and is interpreted
+by the shell, which allows additional arguments to be included.
+`$GIT_SSH` on the other hand must be just the path to a program
+(which can be a wrapper shell script, if additional arguments are
+needed).
++
+Usually it is easier to configure any desired options through your
+personal `.ssh/config` file.  Please consult your ssh documentation
+for further details.
+
+`GIT_SSH_VARIANT`::
+	If this environment variable is set, it overrides Git's autodetection
+	whether `GIT_SSH`/`GIT_SSH_COMMAND`/`core.sshCommand` refer to OpenSSH,
+	plink or tortoiseplink. This variable overrides the config setting
+	`ssh.variant` that serves the same purpose.
+
+`GIT_SSL_NO_VERIFY`::
+	Setting and exporting this environment variable to any value
+	tells Git not to verify the SSL certificate when fetching or
+	pushing over HTTPS.
+
+`GIT_ATTR_SOURCE`::
+	Sets the treeish that gitattributes will be read from.
+
+`GIT_ASKPASS`::
+	If this environment variable is set, then Git commands which need to
+	acquire passwords or passphrases (e.g. for HTTP or IMAP authentication)
+	will call this program with a suitable prompt as command-line argument
+	and read the password from its STDOUT. See also the `core.askPass`
+	option in linkgit:git-config[1].
+
+`GIT_TERMINAL_PROMPT`::
+	If this Boolean environment variable is set to false, git will not prompt
+	on the terminal (e.g., when asking for HTTP authentication).
+
+`GIT_CONFIG_GLOBAL`::
+`GIT_CONFIG_SYSTEM`::
+	Take the configuration from the given files instead from global or
+	system-level configuration files. If `GIT_CONFIG_SYSTEM` is set, the
+	system config file defined at build time (usually `/etc/gitconfig`)
+	will not be read. Likewise, if `GIT_CONFIG_GLOBAL` is set, neither
+	`$HOME/.gitconfig` nor `$XDG_CONFIG_HOME/git/config` will be read. Can
+	be set to `/dev/null` to skip reading configuration files of the
+	respective level.
+
+`GIT_CONFIG_NOSYSTEM`::
+	Whether to skip reading settings from the system-wide
+	`$(prefix)/etc/gitconfig` file.  This Boolean environment variable can
+	be used along with `$HOME` and `$XDG_CONFIG_HOME` to create a
+	predictable environment for a picky script, or you can set it
+	to true to temporarily avoid using a buggy `/etc/gitconfig` file while
+	waiting for someone with sufficient permissions to fix it.
+
+`GIT_FLUSH`::
+	If this Boolean environment variable is set to true, then commands such
+	as 'git blame' (in incremental mode), 'git rev-list', 'git log',
+	'git check-attr' and 'git check-ignore' will
+	force a flush of the output stream after each record have been
+	flushed. If this
+	variable is set to false, the output of these commands will be done
+	using completely buffered I/O.   If this environment variable is
+	not set, Git will choose buffered or record-oriented flushing
+	based on whether stdout appears to be redirected to a file or not.
+
+`GIT_TRACE`::
+	Enables general trace messages, e.g. alias expansion, built-in
+	command execution and external command execution.
++
+If this variable is set to "1", "2" or "true" (comparison
+is case insensitive), trace messages will be printed to
+stderr.
++
+If the variable is set to an integer value greater than 2
+and lower than 10 (strictly) then Git will interpret this
+value as an open file descriptor and will try to write the
+trace messages into this file descriptor.
++
+Alternatively, if the variable is set to an absolute path
+(starting with a '/' character), Git will interpret this
+as a file path and will try to append the trace messages
+to it.
++
+Unsetting the variable, or setting it to empty, "0" or
+"false" (case insensitive) disables trace messages.
+
+`GIT_TRACE_FSMONITOR`::
+	Enables trace messages for the filesystem monitor extension.
+	See `GIT_TRACE` for available trace output options.
+
+`GIT_TRACE_PACK_ACCESS`::
+	Enables trace messages for all accesses to any packs. For each
+	access, the pack file name and an offset in the pack is
+	recorded. This may be helpful for troubleshooting some
+	pack-related performance problems.
+	See `GIT_TRACE` for available trace output options.
+
+`GIT_TRACE_PACKET`::
+	Enables trace messages for all packets coming in or out of a
+	given program. This can help with debugging object negotiation
+	or other protocol issues. Tracing is turned off at a packet
+	starting with "PACK" (but see `GIT_TRACE_PACKFILE` below).
+	See `GIT_TRACE` for available trace output options.
+
+`GIT_TRACE_PACKFILE`::
+	Enables tracing of packfiles sent or received by a
+	given program. Unlike other trace output, this trace is
+	verbatim: no headers, and no quoting of binary data. You almost
+	certainly want to direct into a file (e.g.,
+	`GIT_TRACE_PACKFILE=/tmp/my.pack`) rather than displaying it on
+	the terminal or mixing it with other trace output.
++
+Note that this is currently only implemented for the client side
+of clones and fetches.
+
+`GIT_TRACE_PERFORMANCE`::
+	Enables performance related trace messages, e.g. total execution
+	time of each Git command.
+	See `GIT_TRACE` for available trace output options.
+
+`GIT_TRACE_REFS`::
+	Enables trace messages for operations on the ref database.
+	See `GIT_TRACE` for available trace output options.
+
+`GIT_TRACE_SETUP`::
+	Enables trace messages printing the .git, working tree and current
+	working directory after Git has completed its setup phase.
+	See `GIT_TRACE` for available trace output options.
+
+`GIT_TRACE_SHALLOW`::
+	Enables trace messages that can help debugging fetching /
+	cloning of shallow repositories.
+	See `GIT_TRACE` for available trace output options.
+
+`GIT_TRACE_CURL`::
+	Enables a curl full trace dump of all incoming and outgoing data,
+	including descriptive information, of the git transport protocol.
+	This is similar to doing curl `--trace-ascii` on the command line.
+	See `GIT_TRACE` for available trace output options.
+
+`GIT_TRACE_CURL_NO_DATA`::
+	When a curl trace is enabled (see `GIT_TRACE_CURL` above), do not dump
+	data (that is, only dump info lines and headers).
+
+`GIT_TRACE2`::
+	Enables more detailed trace messages from the "trace2" library.
+	Output from `GIT_TRACE2` is a simple text-based format for human
+	readability.
++
+If this variable is set to "1", "2" or "true" (comparison
+is case insensitive), trace messages will be printed to
+stderr.
++
+If the variable is set to an integer value greater than 2
+and lower than 10 (strictly) then Git will interpret this
+value as an open file descriptor and will try to write the
+trace messages into this file descriptor.
++
+Alternatively, if the variable is set to an absolute path
+(starting with a '/' character), Git will interpret this
+as a file path and will try to append the trace messages
+to it.  If the path already exists and is a directory, the
+trace messages will be written to files (one per process)
+in that directory, named according to the last component
+of the SID and an optional counter (to avoid filename
+collisions).
++
+In addition, if the variable is set to
+`af_unix:[<socket-type>:]<absolute-pathname>`, Git will try
+to open the path as a Unix Domain Socket.  The socket type
+can be either `stream` or `dgram`.
++
+Unsetting the variable, or setting it to empty, "0" or
+"false" (case insensitive) disables trace messages.
++
+See link:technical/api-trace2.html[Trace2 documentation]
+for full details.
+
+
+`GIT_TRACE2_EVENT`::
+	This setting writes a JSON-based format that is suited for machine
+	interpretation.
+	See `GIT_TRACE2` for available trace output options and
+	link:technical/api-trace2.html[Trace2 documentation] for full details.
+
+`GIT_TRACE2_PERF`::
+	In addition to the text-based messages available in `GIT_TRACE2`, this
+	setting writes a column-based format for understanding nesting
+	regions.
+	See `GIT_TRACE2` for available trace output options and
+	link:technical/api-trace2.html[Trace2 documentation] for full details.
+
+`GIT_TRACE_REDACT`::
+	By default, when tracing is activated, Git redacts the values of
+	cookies, the "Authorization:" header, the "Proxy-Authorization:"
+	header and packfile URIs. Set this Boolean environment variable to false to prevent this
+	redaction.
+
+`GIT_NO_REPLACE_OBJECTS`::
+	Setting and exporting this environment variable tells Git to
+	ignore replacement refs and do not replace Git objects.
+
+`GIT_LITERAL_PATHSPECS`::
+	Setting this Boolean environment variable to true will cause Git to treat all
+	pathspecs literally, rather than as glob patterns. For example,
+	running `GIT_LITERAL_PATHSPECS=1 git log -- '*.c'` will search
+	for commits that touch the path `*.c`, not any paths that the
+	glob `*.c` matches. You might want this if you are feeding
+	literal paths to Git (e.g., paths previously given to you by
+	`git ls-tree`, `--raw` diff output, etc).
+
+`GIT_GLOB_PATHSPECS`::
+	Setting this Boolean environment variable to true will cause Git to treat all
+	pathspecs as glob patterns (aka "glob" magic).
+
+`GIT_NOGLOB_PATHSPECS`::
+	Setting this Boolean environment variable to true will cause Git to treat all
+	pathspecs as literal (aka "literal" magic).
+
+`GIT_ICASE_PATHSPECS`::
+	Setting this Boolean environment variable to true will cause Git to treat all
+	pathspecs as case-insensitive.
+
+`GIT_NO_LAZY_FETCH`::
+	Setting this Boolean environment variable to true tells Git
+	not to lazily fetch missing objects from the promisor remote
+	on demand.
+
+`GIT_REFLOG_ACTION`::
+	When a ref is updated, reflog entries are created to keep
+	track of the reason why the ref was updated (which is
+	typically the name of the high-level command that updated
+	the ref), in addition to the old and new values of the ref.
+	A scripted Porcelain command can use set_reflog_action
+	helper function in `git-sh-setup` to set its name to this
+	variable when it is invoked as the top level command by the
+	end user, to be recorded in the body of the reflog.
+
+`GIT_REF_PARANOIA`::
+	If this Boolean environment variable is set to false, ignore broken or badly named refs when iterating
+	over lists of refs. Normally Git will try to include any such
+	refs, which may cause some operations to fail. This is usually
+	preferable, as potentially destructive operations (e.g.,
+	linkgit:git-prune[1]) are better off aborting rather than
+	ignoring broken refs (and thus considering the history they
+	point to as not worth saving). The default value is `1` (i.e.,
+	be paranoid about detecting and aborting all operations). You
+	should not normally need to set this to `0`, but it may be
+	useful when trying to salvage data from a corrupted repository.
+
+`GIT_COMMIT_GRAPH_PARANOIA`::
+	When loading a commit object from the commit-graph, Git performs an
+	existence check on the object in the object database. This is done to
+	avoid issues with stale commit-graphs that contain references to
+	already-deleted commits, but comes with a performance penalty.
++
+The default is "false", which disables the aforementioned behavior.
+Setting this to "true" enables the existence check so that stale commits
+will never be returned from the commit-graph at the cost of performance.
+
+`GIT_ALLOW_PROTOCOL`::
+	If set to a colon-separated list of protocols, behave as if
+	`protocol.allow` is set to `never`, and each of the listed
+	protocols has `protocol.<name>.allow` set to `always`
+	(overriding any existing configuration). See the description of
+	`protocol.allow` in linkgit:git-config[1] for more details.
+
+`GIT_PROTOCOL_FROM_USER`::
+	Set this Boolean environment variable to false to prevent protocols used by fetch/push/clone which are
+	configured to the `user` state.  This is useful to restrict recursive
+	submodule initialization from an untrusted repository or for programs
+	which feed potentially-untrusted URLS to git commands.  See
+	linkgit:git-config[1] for more details.
+
+`GIT_PROTOCOL`::
+	For internal use only.  Used in handshaking the wire protocol.
+	Contains a colon ':' separated list of keys with optional values
+	'<key>[=<value>]'.  Presence of unknown keys and values must be
+	ignored.
++
+Note that servers may need to be configured to allow this variable to
+pass over some transports. It will be propagated automatically when
+accessing local repositories (i.e., `file://` or a filesystem path), as
+well as over the `git://` protocol. For git-over-http, it should work
+automatically in most configurations, but see the discussion in
+linkgit:git-http-backend[1]. For git-over-ssh, the ssh server may need
+to be configured to allow clients to pass this variable (e.g., by using
+`AcceptEnv GIT_PROTOCOL` with OpenSSH).
++
+This configuration is optional. If the variable is not propagated, then
+clients will fall back to the original "v0" protocol (but may miss out
+on some performance improvements or features). This variable currently
+only affects clones and fetches; it is not yet used for pushes (but may
+be in the future).
+
+`GIT_OPTIONAL_LOCKS`::
+	If this Boolean environment variable is set to false, Git will complete any requested operation without
+	performing any optional sub-operations that require taking a lock.
+	For example, this will prevent `git status` from refreshing the
+	index as a side effect. This is useful for processes running in
+	the background which do not want to cause lock contention with
+	other operations on the repository.  Defaults to `1`.
+
+`GIT_REDIRECT_STDIN`::
+`GIT_REDIRECT_STDOUT`::
+`GIT_REDIRECT_STDERR`::
+	Windows-only: allow redirecting the standard input/output/error
+	handles to paths specified by the environment variables. This is
+	particularly useful in multi-threaded applications where the
+	canonical way to pass standard handles via `CreateProcess()` is
+	not an option because it would require the handles to be marked
+	inheritable (and consequently *every* spawned process would
+	inherit them, possibly blocking regular Git operations). The
+	primary intended use case is to use named pipes for communication
+	(e.g. `\\.\pipe\my-git-stdin-123`).
++
+Two special values are supported: `off` will simply close the
+corresponding standard handle, and if `GIT_REDIRECT_STDERR` is
+`2>&1`, standard error will be redirected to the same handle as
+standard output.
+
+`GIT_PRINT_SHA1_ELLIPSIS` (deprecated)::
+	If set to `yes`, print an ellipsis following an
+	(abbreviated) SHA-1 value.  This affects indications of
+	detached HEADs (linkgit:git-checkout[1]) and the raw
+	diff output (linkgit:git-diff[1]).  Printing an
+	ellipsis in the cases mentioned is no longer considered
+	adequate and support for it is likely to be removed in the
+	foreseeable future (along with the variable).
+
+`GIT_ADVICE`::
+	If set to `0`, then disable all advice messages. These messages are
+	intended to provide hints to human users that may help them get out of
+	problematic situations or take advantage of new features. Users can
+	disable individual messages using the `advice.*` config keys. These
+	messages may be disruptive to tools that execute Git processes, so this
+	variable is available to disable the messages. (The `--no-advice`
+	global option is also available, but old Git versions may fail when
+	this option is not understood. The environment variable will be ignored
+	by Git versions that do not understand it.)
+
+Discussion[[Discussion]]
+------------------------
+
+More detail on the following is available from the
+link:user-manual.html#git-concepts[Git concepts chapter of the
+user-manual] and linkgit:gitcore-tutorial[7].
+
+A Git project normally consists of a working directory with a ".git"
+subdirectory at the top level.  The .git directory contains, among other
+things, a compressed object database representing the complete history
+of the project, an "index" file which links that history to the current
+contents of the working tree, and named pointers into that history such
+as tags and branch heads.
+
+The object database contains objects of three main types: blobs, which
+hold file data; trees, which point to blobs and other trees to build up
+directory hierarchies; and commits, which each reference a single tree
+and some number of parent commits.
+
+The commit, equivalent to what other systems call a "changeset" or
+"version", represents a step in the project's history, and each parent
+represents an immediately preceding step.  Commits with more than one
+parent represent merges of independent lines of development.
+
+All objects are named by the SHA-1 hash of their contents, normally
+written as a string of 40 hex digits.  Such names are globally unique.
+The entire history leading up to a commit can be vouched for by signing
+just that commit.  A fourth object type, the tag, is provided for this
+purpose.
+
+When first created, objects are stored in individual files, but for
+efficiency may later be compressed together into "pack files".
+
+Named pointers called refs mark interesting points in history.  A ref
+may contain the SHA-1 name of an object or the name of another ref (the
+latter is called a "symbolic ref").
+Refs with names beginning `refs/head/` contain the SHA-1 name of the most
+recent commit (or "head") of a branch under development.  SHA-1 names of
+tags of interest are stored under `refs/tags/`.  A symbolic ref named
+`HEAD` contains the name of the currently checked-out branch.
+
+The index file is initialized with a list of all paths and, for each
+path, a blob object and a set of attributes.  The blob object represents
+the contents of the file as of the head of the current branch.  The
+attributes (last modified time, size, etc.) are taken from the
+corresponding file in the working tree.  Subsequent changes to the
+working tree can be found by comparing these attributes.  The index may
+be updated with new content, and new commits may be created from the
+content stored in the index.
+
+The index is also capable of storing multiple entries (called "stages")
+for a given pathname.  These stages are used to hold the various
+unmerged version of a file when a merge is in progress.
+
+SECURITY
+--------
+
+Some configuration options and hook files may cause Git to run arbitrary
+shell commands. Because configuration and hooks are not copied using
+`git clone`, it is generally safe to clone remote repositories with
+untrusted content, inspect them with `git log`, and so on.
+
+However, it is not safe to run Git commands in a `.git` directory (or
+the working tree that surrounds it) when that `.git` directory itself
+comes from an untrusted source. The commands in its config and hooks
+are executed in the usual way.
+
+By default, Git will refuse to run when the repository is owned by
+someone other than the user running the command. See the entry for
+`safe.directory` in linkgit:git-config[1]. While this can help protect
+you in a multi-user environment, note that you can also acquire
+untrusted repositories that are owned by you (for example, if you
+extract a zip file or tarball from an untrusted source). In such cases,
+you'd need to "sanitize" the untrusted repository first.
+
+If you have an untrusted `.git` directory, you should first clone it
+with `git clone --no-local` to obtain a clean copy. Git does restrict
+the set of options and hooks that will be run by `upload-pack`, which
+handles the server side of a clone or fetch, but beware that the
+surface area for attack against `upload-pack` is large, so this does
+carry some risk. The safest thing is to serve the repository as an
+unprivileged user (either via linkgit:git-daemon[1], ssh, or using
+other tools to change user ids). See the discussion in the `SECURITY`
+section of linkgit:git-upload-pack[1].
+
+FURTHER DOCUMENTATION
+---------------------
+
+See the references in the "description" section to get started
+using Git.  The following is probably more detail than necessary
+for a first-time user.
+
+The link:user-manual.html#git-concepts[Git concepts chapter of the
+user-manual] and linkgit:gitcore-tutorial[7] both provide
+introductions to the underlying Git architecture.
+
+See linkgit:gitworkflows[7] for an overview of recommended workflows.
+
+See also the link:howto-index.html[howto] documents for some useful
+examples.
+
+The internals are documented in the
+link:technical/api-index.html[Git API documentation].
+
+Users migrating from CVS may also want to
+read linkgit:gitcvs-migration[7].
+
+
+Authors
+-------
+Git was started by Linus Torvalds, and is currently maintained by Junio
+C Hamano. Numerous contributions have come from the Git mailing list
+<git@xxxxxxxxxxxxxxx>.  https://openhub.net/p/git/contributors/summary
+gives you a more complete list of contributors.
+
+If you have a clone of git.git itself, the
+output of linkgit:git-shortlog[1] and linkgit:git-blame[1] can show you
+the authors for specific parts of the project.
+
+Reporting Bugs
+--------------
+
+Report bugs to the Git mailing list <git@xxxxxxxxxxxxxxx> where the
+development and maintenance is primarily done.  You do not have to be
+subscribed to the list to send a message there.  See the list archive
+at https://lore.kernel.org/git for previous bug reports and other
+discussions.
+
+Issues which are security relevant should be disclosed privately to
+the Git Security mailing list <git-security@xxxxxxxxxxxxxxxx>.
+
+SEE ALSO
+--------
+linkgit:gittutorial[7], linkgit:gittutorial-2[7],
+linkgit:giteveryday[7], linkgit:gitcvs-migration[7],
+linkgit:gitglossary[7], linkgit:gitcore-tutorial[7],
+linkgit:gitcli[7], link:user-manual.html[The Git User's Manual],
+linkgit:gitworkflows[7]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitattributes.adoc b/Documentation/gitattributes.adoc
new file mode 100644
index 0000000000..5d12b78549
--- /dev/null
+++ b/Documentation/gitattributes.adoc
@@ -0,0 +1,1374 @@
+gitattributes(5)
+================
+
+NAME
+----
+gitattributes - Defining attributes per path
+
+SYNOPSIS
+--------
+$GIT_DIR/info/attributes, .gitattributes
+
+
+DESCRIPTION
+-----------
+
+A `gitattributes` file is a simple text file that gives
+`attributes` to pathnames.
+
+Each line in `gitattributes` file is of form:
+
+	pattern attr1 attr2 ...
+
+That is, a pattern followed by an attributes list,
+separated by whitespaces. Leading and trailing whitespaces are
+ignored. Lines that begin with '#' are ignored. Patterns
+that begin with a double quote are quoted in C style.
+When the pattern matches the path in question, the attributes
+listed on the line are given to the path.
+
+Each attribute can be in one of these states for a given path:
+
+Set::
+
+	The path has the attribute with special value "true";
+	this is specified by listing only the name of the
+	attribute in the attribute list.
+
+Unset::
+
+	The path has the attribute with special value "false";
+	this is specified by listing the name of the attribute
+	prefixed with a dash `-` in the attribute list.
+
+Set to a value::
+
+	The path has the attribute with specified string value;
+	this is specified by listing the name of the attribute
+	followed by an equal sign `=` and its value in the
+	attribute list.
+
+Unspecified::
+
+	No pattern matches the path, and nothing says if
+	the path has or does not have the attribute, the
+	attribute for the path is said to be Unspecified.
+
+When more than one pattern matches the path, a later line
+overrides an earlier line.  This overriding is done per
+attribute.
+
+The rules by which the pattern matches paths are the same as in
+`.gitignore` files (see linkgit:gitignore[5]), with a few exceptions:
+
+  - negative patterns are forbidden
+
+  - patterns that match a directory do not recursively match paths
+    inside that directory (so using the trailing-slash `path/` syntax is
+    pointless in an attributes file; use `path/**` instead)
+
+When deciding what attributes are assigned to a path, Git
+consults `$GIT_DIR/info/attributes` file (which has the highest
+precedence), `.gitattributes` file in the same directory as the
+path in question, and its parent directories up to the toplevel of the
+work tree (the further the directory that contains `.gitattributes`
+is from the path in question, the lower its precedence). Finally
+global and system-wide files are considered (they have the lowest
+precedence).
+
+When the `.gitattributes` file is missing from the work tree, the
+path in the index is used as a fall-back.  During checkout process,
+`.gitattributes` in the index is used and then the file in the
+working tree is used as a fall-back.
+
+If you wish to affect only a single repository (i.e., to assign
+attributes to files that are particular to
+one user's workflow for that repository), then
+attributes should be placed in the `$GIT_DIR/info/attributes` file.
+Attributes which should be version-controlled and distributed to other
+repositories (i.e., attributes of interest to all users) should go into
+`.gitattributes` files. Attributes that should affect all repositories
+for a single user should be placed in a file specified by the
+`core.attributesFile` configuration option (see linkgit:git-config[1]).
+Its default value is $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME
+is either not set or empty, $HOME/.config/git/attributes is used instead.
+Attributes for all users on a system should be placed in the
+`$(prefix)/etc/gitattributes` file.
+
+Sometimes you would need to override a setting of an attribute
+for a path to `Unspecified` state.  This can be done by listing
+the name of the attribute prefixed with an exclamation point `!`.
+
+
+RESERVED BUILTIN_* ATTRIBUTES
+-----------------------------
+
+builtin_* is a reserved namespace for builtin attribute values. Any
+user defined attributes under this namespace will be ignored and
+trigger a warning.
+
+`builtin_objectmode`
+~~~~~~~~~~~~~~~~~~~~
+This attribute is for filtering files by their file bit modes (40000,
+120000, 160000, 100755, 100644). e.g. ':(attr:builtin_objectmode=160000)'.
+You may also check these values with `git check-attr builtin_objectmode -- <file>`.
+If the object is not in the index `git check-attr --cached` will return unspecified.
+
+
+EFFECTS
+-------
+
+Certain operations by Git can be influenced by assigning
+particular attributes to a path.  Currently, the following
+operations are attributes-aware.
+
+Checking-out and checking-in
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These attributes affect how the contents stored in the
+repository are copied to the working tree files when commands
+such as 'git switch', 'git checkout'  and 'git merge' run.
+They also affect how
+Git stores the contents you prepare in the working tree in the
+repository upon 'git add' and 'git commit'.
+
+`text`
+^^^^^^
+
+This attribute marks the path as a text file, which enables end-of-line
+conversion: When a matching file is added to the index, the file's line
+endings are normalized to LF in the index.  Conversely, when the file is
+copied from the index to the working directory, its line endings may be
+converted from LF to CRLF depending on the `eol` attribute, the Git
+config, and the platform (see explanation of `eol` below).
+
+Set::
+
+	Setting the `text` attribute on a path enables end-of-line
+	conversion on checkin and checkout as described above.  Line endings
+	are normalized to LF in the index every time the file is checked in,
+	even if the file was previously added to Git with CRLF line endings.
+
+Unset::
+
+	Unsetting the `text` attribute on a path tells Git not to
+	attempt any end-of-line conversion upon checkin or checkout.
+
+Set to string value "auto"::
+
+	When `text` is set to "auto", Git decides by itself whether the file
+	is text or binary.  If it is text and the file was not already in
+	Git with CRLF endings, line endings are converted on checkin and
+	checkout as described above.  Otherwise, no conversion is done on
+	checkin or checkout.
+
+Unspecified::
+
+	If the `text` attribute is unspecified, Git uses the
+	`core.autocrlf` configuration variable to determine if the
+	file should be converted.
+
+Any other value causes Git to act as if `text` has been left
+unspecified.
+
+`eol`
+^^^^^
+
+This attribute marks a path to use a specific line-ending style in the
+working tree when it is checked out.  It has effect only if `text` or
+`text=auto` is set (see above), but specifying `eol` automatically sets
+`text` if `text` was left unspecified.
+
+Set to string value "crlf"::
+
+	This setting converts the file's line endings in the working
+	directory to CRLF when the file is checked out.
+
+Set to string value "lf"::
+
+	This setting uses the same line endings in the working directory as
+	in the index when the file is checked out.
+
+Unspecified::
+
+	If the `eol` attribute is unspecified for a file, its line endings
+	in the working directory are determined by the `core.autocrlf` or
+	`core.eol` configuration variable (see the definitions of those
+	options in linkgit:git-config[1]).  If `text` is set but neither of
+	those variables is, the default is `eol=crlf` on Windows and
+	`eol=lf` on all other platforms.
+
+Backwards compatibility with `crlf` attribute
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For backwards compatibility, the `crlf` attribute is interpreted as
+follows:
+
+------------------------
+crlf		text
+-crlf		-text
+crlf=input	eol=lf
+------------------------
+
+End-of-line conversion
+^^^^^^^^^^^^^^^^^^^^^^
+
+While Git normally leaves file contents alone, it can be configured to
+normalize line endings to LF in the repository and, optionally, to
+convert them to CRLF when files are checked out.
+
+If you simply want to have CRLF line endings in your working directory
+regardless of the repository you are working with, you can set the
+config variable "core.autocrlf" without using any attributes.
+
+------------------------
+[core]
+	autocrlf = true
+------------------------
+
+This does not force normalization of text files, but does ensure
+that text files that you introduce to the repository have their line
+endings normalized to LF when they are added, and that files that are
+already normalized in the repository stay normalized.
+
+If you want to ensure that text files that any contributor introduces to
+the repository have their line endings normalized, you can set the
+`text` attribute to "auto" for _all_ files.
+
+------------------------
+*	text=auto
+------------------------
+
+The attributes allow a fine-grained control, how the line endings
+are converted.
+Here is an example that will make Git normalize .txt, .vcproj and .sh
+files, ensure that .vcproj files have CRLF and .sh files have LF in
+the working directory, and prevent .jpg files from being normalized
+regardless of their content.
+
+------------------------
+*               text=auto
+*.txt		text
+*.vcproj	text eol=crlf
+*.sh		text eol=lf
+*.jpg		-text
+------------------------
+
+NOTE: When `text=auto` conversion is enabled in a cross-platform
+project using push and pull to a central repository the text files
+containing CRLFs should be normalized.
+
+From a clean working directory:
+
+-------------------------------------------------
+$ echo "* text=auto" >.gitattributes
+$ git add --renormalize .
+$ git status        # Show files that will be normalized
+$ git commit -m "Introduce end-of-line normalization"
+-------------------------------------------------
+
+If any files that should not be normalized show up in 'git status',
+unset their `text` attribute before running 'git add -u'.
+
+------------------------
+manual.pdf	-text
+------------------------
+
+Conversely, text files that Git does not detect can have normalization
+enabled manually.
+
+------------------------
+weirdchars.txt	text
+------------------------
+
+If `core.safecrlf` is set to "true" or "warn", Git verifies if
+the conversion is reversible for the current setting of
+`core.autocrlf`.  For "true", Git rejects irreversible
+conversions; for "warn", Git only prints a warning but accepts
+an irreversible conversion.  The safety triggers to prevent such
+a conversion done to the files in the work tree, but there are a
+few exceptions.  Even though...
+
+- 'git add' itself does not touch the files in the work tree, the
+  next checkout would, so the safety triggers;
+
+- 'git apply' to update a text file with a patch does touch the files
+  in the work tree, but the operation is about text files and CRLF
+  conversion is about fixing the line ending inconsistencies, so the
+  safety does not trigger;
+
+- 'git diff' itself does not touch the files in the work tree, it is
+  often run to inspect the changes you intend to next 'git add'.  To
+  catch potential problems early, safety triggers.
+
+
+`working-tree-encoding`
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Git recognizes files encoded in ASCII or one of its supersets (e.g.
+UTF-8, ISO-8859-1, ...) as text files. Files encoded in certain other
+encodings (e.g. UTF-16) are interpreted as binary and consequently
+built-in Git text processing tools (e.g. 'git diff') as well as most Git
+web front ends do not visualize the contents of these files by default.
+
+In these cases you can tell Git the encoding of a file in the working
+directory with the `working-tree-encoding` attribute. If a file with this
+attribute is added to Git, then Git re-encodes the content from the
+specified encoding to UTF-8. Finally, Git stores the UTF-8 encoded
+content in its internal data structure (called "the index"). On checkout
+the content is re-encoded back to the specified encoding.
+
+Please note that using the `working-tree-encoding` attribute may have a
+number of pitfalls:
+
+- Alternative Git implementations (e.g. JGit or libgit2) and older Git
+  versions (as of March 2018) do not support the `working-tree-encoding`
+  attribute. If you decide to use the `working-tree-encoding` attribute
+  in your repository, then it is strongly recommended to ensure that all
+  clients working with the repository support it.
++
+For example, Microsoft Visual Studio resources files (`*.rc`) or
+PowerShell script files (`*.ps1`) are sometimes encoded in UTF-16.
+If you declare `*.ps1` as files as UTF-16 and you add `foo.ps1` with
+a `working-tree-encoding` enabled Git client, then `foo.ps1` will be
+stored as UTF-8 internally. A client without `working-tree-encoding`
+support will checkout `foo.ps1` as UTF-8 encoded file. This will
+typically cause trouble for the users of this file.
++
+If a Git client that does not support the `working-tree-encoding`
+attribute adds a new file `bar.ps1`, then `bar.ps1` will be
+stored "as-is" internally (in this example probably as UTF-16).
+A client with `working-tree-encoding` support will interpret the
+internal contents as UTF-8 and try to convert it to UTF-16 on checkout.
+That operation will fail and cause an error.
+
+- Reencoding content to non-UTF encodings can cause errors as the
+  conversion might not be UTF-8 round trip safe. If you suspect your
+  encoding to not be round trip safe, then add it to
+  `core.checkRoundtripEncoding` to make Git check the round trip
+  encoding (see linkgit:git-config[1]). SHIFT-JIS (Japanese character
+  set) is known to have round trip issues with UTF-8 and is checked by
+  default.
+
+- Reencoding content requires resources that might slow down certain
+  Git operations (e.g 'git checkout' or 'git add').
+
+Use the `working-tree-encoding` attribute only if you cannot store a file
+in UTF-8 encoding and if you want Git to be able to process the content
+as text.
+
+As an example, use the following attributes if your '*.ps1' files are
+UTF-16 encoded with byte order mark (BOM) and you want Git to perform
+automatic line ending conversion based on your platform.
+
+------------------------
+*.ps1		text working-tree-encoding=UTF-16
+------------------------
+
+Use the following attributes if your '*.ps1' files are UTF-16 little
+endian encoded without BOM and you want Git to use Windows line endings
+in the working directory (use `UTF-16LE-BOM` instead of `UTF-16LE` if
+you want UTF-16 little endian with BOM).
+Please note, it is highly recommended to
+explicitly define the line endings with `eol` if the `working-tree-encoding`
+attribute is used to avoid ambiguity.
+
+------------------------
+*.ps1		text working-tree-encoding=UTF-16LE eol=crlf
+------------------------
+
+You can get a list of all available encodings on your platform with the
+following command:
+
+------------------------
+iconv --list
+------------------------
+
+If you do not know the encoding of a file, then you can use the `file`
+command to guess the encoding:
+
+------------------------
+file foo.ps1
+------------------------
+
+
+`ident`
+^^^^^^^
+
+When the attribute `ident` is set for a path, Git replaces
+`$Id$` in the blob object with `$Id:`, followed by the
+40-character hexadecimal blob object name, followed by a dollar
+sign `$` upon checkout.  Any byte sequence that begins with
+`$Id:` and ends with `$` in the worktree file is replaced
+with `$Id$` upon check-in.
+
+
+`filter`
+^^^^^^^^
+
+A `filter` attribute can be set to a string value that names a
+filter driver specified in the configuration.
+
+A filter driver consists of a `clean` command and a `smudge`
+command, either of which can be left unspecified.  Upon
+checkout, when the `smudge` command is specified, the command is
+fed the blob object from its standard input, and its standard
+output is used to update the worktree file.  Similarly, the
+`clean` command is used to convert the contents of worktree file
+upon checkin. By default these commands process only a single
+blob and terminate. If a long running `process` filter is used
+in place of `clean` and/or `smudge` filters, then Git can process
+all blobs with a single filter command invocation for the entire
+life of a single Git command, for example `git add --all`. If a
+long running `process` filter is configured then it always takes
+precedence over a configured single blob filter. See section
+below for the description of the protocol used to communicate with
+a `process` filter.
+
+One use of the content filtering is to massage the content into a shape
+that is more convenient for the platform, filesystem, and the user to use.
+For this mode of operation, the key phrase here is "more convenient" and
+not "turning something unusable into usable".  In other words, the intent
+is that if someone unsets the filter driver definition, or does not have
+the appropriate filter program, the project should still be usable.
+
+Another use of the content filtering is to store the content that cannot
+be directly used in the repository (e.g. a UUID that refers to the true
+content stored outside Git, or an encrypted content) and turn it into a
+usable form upon checkout (e.g. download the external content, or decrypt
+the encrypted content).
+
+These two filters behave differently, and by default, a filter is taken as
+the former, massaging the contents into more convenient shape.  A missing
+filter driver definition in the config, or a filter driver that exits with
+a non-zero status, is not an error but makes the filter a no-op passthru.
+
+You can declare that a filter turns a content that by itself is unusable
+into a usable content by setting the filter.<driver>.required configuration
+variable to `true`.
+
+Note: Whenever the clean filter is changed, the repo should be renormalized:
+$ git add --renormalize .
+
+For example, in .gitattributes, you would assign the `filter`
+attribute for paths.
+
+------------------------
+*.c	filter=indent
+------------------------
+
+Then you would define a "filter.indent.clean" and "filter.indent.smudge"
+configuration in your .git/config to specify a pair of commands to
+modify the contents of C programs when the source files are checked
+in ("clean" is run) and checked out (no change is made because the
+command is "cat").
+
+------------------------
+[filter "indent"]
+	clean = indent
+	smudge = cat
+------------------------
+
+For best results, `clean` should not alter its output further if it is
+run twice ("clean->clean" should be equivalent to "clean"), and
+multiple `smudge` commands should not alter `clean`'s output
+("smudge->smudge->clean" should be equivalent to "clean").  See the
+section on merging below.
+
+The "indent" filter is well-behaved in this regard: it will not modify
+input that is already correctly indented.  In this case, the lack of a
+smudge filter means that the clean filter _must_ accept its own output
+without modifying it.
+
+If a filter _must_ succeed in order to make the stored contents usable,
+you can declare that the filter is `required`, in the configuration:
+
+------------------------
+[filter "crypt"]
+	clean = openssl enc ...
+	smudge = openssl enc -d ...
+	required
+------------------------
+
+Sequence "%f" on the filter command line is replaced with the name of
+the file the filter is working on.  A filter might use this in keyword
+substitution.  For example:
+
+------------------------
+[filter "p4"]
+	clean = git-p4-filter --clean %f
+	smudge = git-p4-filter --smudge %f
+------------------------
+
+Note that "%f" is the name of the path that is being worked on. Depending
+on the version that is being filtered, the corresponding file on disk may
+not exist, or may have different contents. So, smudge and clean commands
+should not try to access the file on disk, but only act as filters on the
+content provided to them on standard input.
+
+Long Running Filter Process
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If the filter command (a string value) is defined via
+`filter.<driver>.process` then Git can process all blobs with a
+single filter invocation for the entire life of a single Git
+command. This is achieved by using the long-running process protocol
+(described in technical/long-running-process-protocol.txt).
+
+When Git encounters the first file that needs to be cleaned or smudged,
+it starts the filter and performs the handshake. In the handshake, the
+welcome message sent by Git is "git-filter-client", only version 2 is
+supported, and the supported capabilities are "clean", "smudge", and
+"delay".
+
+Afterwards Git sends a list of "key=value" pairs terminated with
+a flush packet. The list will contain at least the filter command
+(based on the supported capabilities) and the pathname of the file
+to filter relative to the repository root. Right after the flush packet
+Git sends the content split in zero or more pkt-line packets and a
+flush packet to terminate content. Please note, that the filter
+must not send any response before it received the content and the
+final flush packet. Also note that the "value" of a "key=value" pair
+can contain the "=" character whereas the key would never contain
+that character.
+------------------------
+packet:          git> command=smudge
+packet:          git> pathname=path/testfile.dat
+packet:          git> 0000
+packet:          git> CONTENT
+packet:          git> 0000
+------------------------
+
+The filter is expected to respond with a list of "key=value" pairs
+terminated with a flush packet. If the filter does not experience
+problems then the list must contain a "success" status. Right after
+these packets the filter is expected to send the content in zero
+or more pkt-line packets and a flush packet at the end. Finally, a
+second list of "key=value" pairs terminated with a flush packet
+is expected. The filter can change the status in the second list
+or keep the status as is with an empty list. Please note that the
+empty list must be terminated with a flush packet regardless.
+
+------------------------
+packet:          git< status=success
+packet:          git< 0000
+packet:          git< SMUDGED_CONTENT
+packet:          git< 0000
+packet:          git< 0000  # empty list, keep "status=success" unchanged!
+------------------------
+
+If the result content is empty then the filter is expected to respond
+with a "success" status and a flush packet to signal the empty content.
+------------------------
+packet:          git< status=success
+packet:          git< 0000
+packet:          git< 0000  # empty content!
+packet:          git< 0000  # empty list, keep "status=success" unchanged!
+------------------------
+
+In case the filter cannot or does not want to process the content,
+it is expected to respond with an "error" status.
+------------------------
+packet:          git< status=error
+packet:          git< 0000
+------------------------
+
+If the filter experiences an error during processing, then it can
+send the status "error" after the content was (partially or
+completely) sent.
+------------------------
+packet:          git< status=success
+packet:          git< 0000
+packet:          git< HALF_WRITTEN_ERRONEOUS_CONTENT
+packet:          git< 0000
+packet:          git< status=error
+packet:          git< 0000
+------------------------
+
+In case the filter cannot or does not want to process the content
+as well as any future content for the lifetime of the Git process,
+then it is expected to respond with an "abort" status at any point
+in the protocol.
+------------------------
+packet:          git< status=abort
+packet:          git< 0000
+------------------------
+
+Git neither stops nor restarts the filter process in case the
+"error"/"abort" status is set. However, Git sets its exit code
+according to the `filter.<driver>.required` flag, mimicking the
+behavior of the `filter.<driver>.clean` / `filter.<driver>.smudge`
+mechanism.
+
+If the filter dies during the communication or does not adhere to
+the protocol then Git will stop the filter process and restart it
+with the next file that needs to be processed. Depending on the
+`filter.<driver>.required` flag Git will interpret that as error.
+
+Delay
+^^^^^
+
+If the filter supports the "delay" capability, then Git can send the
+flag "can-delay" after the filter command and pathname. This flag
+denotes that the filter can delay filtering the current blob (e.g. to
+compensate network latencies) by responding with no content but with
+the status "delayed" and a flush packet.
+------------------------
+packet:          git> command=smudge
+packet:          git> pathname=path/testfile.dat
+packet:          git> can-delay=1
+packet:          git> 0000
+packet:          git> CONTENT
+packet:          git> 0000
+packet:          git< status=delayed
+packet:          git< 0000
+------------------------
+
+If the filter supports the "delay" capability then it must support the
+"list_available_blobs" command. If Git sends this command, then the
+filter is expected to return a list of pathnames representing blobs
+that have been delayed earlier and are now available.
+The list must be terminated with a flush packet followed
+by a "success" status that is also terminated with a flush packet. If
+no blobs for the delayed paths are available, yet, then the filter is
+expected to block the response until at least one blob becomes
+available. The filter can tell Git that it has no more delayed blobs
+by sending an empty list. As soon as the filter responds with an empty
+list, Git stops asking. All blobs that Git has not received at this
+point are considered missing and will result in an error.
+
+------------------------
+packet:          git> command=list_available_blobs
+packet:          git> 0000
+packet:          git< pathname=path/testfile.dat
+packet:          git< pathname=path/otherfile.dat
+packet:          git< 0000
+packet:          git< status=success
+packet:          git< 0000
+------------------------
+
+After Git received the pathnames, it will request the corresponding
+blobs again. These requests contain a pathname and an empty content
+section. The filter is expected to respond with the smudged content
+in the usual way as explained above.
+------------------------
+packet:          git> command=smudge
+packet:          git> pathname=path/testfile.dat
+packet:          git> 0000
+packet:          git> 0000  # empty content!
+packet:          git< status=success
+packet:          git< 0000
+packet:          git< SMUDGED_CONTENT
+packet:          git< 0000
+packet:          git< 0000  # empty list, keep "status=success" unchanged!
+------------------------
+
+Example
+^^^^^^^
+
+A long running filter demo implementation can be found in
+`contrib/long-running-filter/example.pl` located in the Git
+core repository. If you develop your own long running filter
+process then the `GIT_TRACE_PACKET` environment variables can be
+very helpful for debugging (see linkgit:git[1]).
+
+Please note that you cannot use an existing `filter.<driver>.clean`
+or `filter.<driver>.smudge` command with `filter.<driver>.process`
+because the former two use a different inter process communication
+protocol than the latter one.
+
+
+Interaction between checkin/checkout attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the check-in codepath, the worktree file is first converted
+with `filter` driver (if specified and corresponding driver
+defined), then the result is processed with `ident` (if
+specified), and then finally with `text` (again, if specified
+and applicable).
+
+In the check-out codepath, the blob content is first converted
+with `text`, and then `ident` and fed to `filter`.
+
+
+Merging branches with differing checkin/checkout attributes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you have added attributes to a file that cause the canonical
+repository format for that file to change, such as adding a
+clean/smudge filter or text/eol/ident attributes, merging anything
+where the attribute is not in place would normally cause merge
+conflicts.
+
+To prevent these unnecessary merge conflicts, Git can be told to run a
+virtual check-out and check-in of all three stages of a file when
+resolving a three-way merge by setting the `merge.renormalize`
+configuration variable.  This prevents changes caused by check-in
+conversion from causing spurious merge conflicts when a converted file
+is merged with an unconverted file.
+
+As long as a "smudge->clean" results in the same output as a "clean"
+even on files that are already smudged, this strategy will
+automatically resolve all filter-related conflicts.  Filters that do
+not act in this way may cause additional merge conflicts that must be
+resolved manually.
+
+
+Generating diff text
+~~~~~~~~~~~~~~~~~~~~
+
+`diff`
+^^^^^^
+
+The attribute `diff` affects how Git generates diffs for particular
+files. It can tell Git whether to generate a textual patch for the path
+or to treat the path as a binary file.  It can also affect what line is
+shown on the hunk header `@@ -k,l +n,m @@` line, tell Git to use an
+external command to generate the diff, or ask Git to convert binary
+files to a text format before generating the diff.
+
+Set::
+
+	A path to which the `diff` attribute is set is treated
+	as text, even when they contain byte values that
+	normally never appear in text files, such as NUL.
+
+Unset::
+
+	A path to which the `diff` attribute is unset will
+	generate `Binary files differ` (or a binary patch, if
+	binary patches are enabled).
+
+Unspecified::
+
+	A path to which the `diff` attribute is unspecified
+	first gets its contents inspected, and if it looks like
+	text and is smaller than core.bigFileThreshold, it is treated
+	as text. Otherwise it would generate `Binary files differ`.
+
+String::
+
+	Diff is shown using the specified diff driver.  Each driver may
+	specify one or more options, as described in the following
+	section. The options for the diff driver "foo" are defined
+	by the configuration variables in the "diff.foo" section of the
+	Git config file.
+
+
+Defining an external diff driver
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The definition of a diff driver is done in `gitconfig`, not
+`gitattributes` file, so strictly speaking this manual page is a
+wrong place to talk about it.  However...
+
+To define an external diff driver `jcdiff`, add a section to your
+`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
+
+----------------------------------------------------------------
+[diff "jcdiff"]
+	command = j-c-diff
+----------------------------------------------------------------
+
+When Git needs to show you a diff for the path with `diff`
+attribute set to `jcdiff`, it calls the command you specified
+with the above configuration, i.e. `j-c-diff`, with 7
+parameters, just like `GIT_EXTERNAL_DIFF` program is called.
+See linkgit:git[1] for details.
+
+If the program is able to ignore certain changes (similar to
+`git diff --ignore-space-change`), then also set the option
+`trustExitCode` to true.  It is then expected to return exit code 1 if
+it finds significant changes and 0 if it doesn't.
+
+Setting the internal diff algorithm
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The diff algorithm can be set through the `diff.algorithm` config key, but
+sometimes it may be helpful to set the diff algorithm per path. For example,
+one may want to use the `minimal` diff algorithm for .json files, and the
+`histogram` for .c files, and so on without having to pass in the algorithm
+through the command line each time.
+
+First, in `.gitattributes`, assign the `diff` attribute for paths.
+
+------------------------
+*.json diff=<name>
+------------------------
+
+Then, define a "diff.<name>.algorithm" configuration to specify the diff
+algorithm, choosing from `myers`, `patience`, `minimal`, or `histogram`.
+
+----------------------------------------------------------------
+[diff "<name>"]
+  algorithm = histogram
+----------------------------------------------------------------
+
+This diff algorithm applies to user facing diff output like git-diff(1),
+git-show(1) and is used for the `--stat` output as well. The merge machinery
+will not use the diff algorithm set through this method.
+
+NOTE: If `diff.<name>.command` is defined for path with the
+`diff=<name>` attribute, it is executed as an external diff driver
+(see above), and adding `diff.<name>.algorithm` has no effect, as the
+algorithm is not passed to the external diff driver.
+
+Defining a custom hunk-header
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Each group of changes (called a "hunk") in the textual diff output
+is prefixed with a line of the form:
+
+	@@ -k,l +n,m @@ TEXT
+
+This is called a 'hunk header'.  The "TEXT" portion is by default a line
+that begins with an alphabet, an underscore or a dollar sign; this
+matches what GNU 'diff -p' output uses.  This default selection however
+is not suited for some contents, and you can use a customized pattern
+to make a selection.
+
+First, in .gitattributes, you would assign the `diff` attribute
+for paths.
+
+------------------------
+*.tex	diff=tex
+------------------------
+
+Then, you would define a "diff.tex.xfuncname" configuration to
+specify a regular expression that matches a line that you would
+want to appear as the hunk header "TEXT". Add a section to your
+`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
+
+------------------------
+[diff "tex"]
+	xfuncname = "^(\\\\(sub)*section\\{.*)$"
+------------------------
+
+Note.  A single level of backslashes are eaten by the
+configuration file parser, so you would need to double the
+backslashes; the pattern above picks a line that begins with a
+backslash, and zero or more occurrences of `sub` followed by
+`section` followed by open brace, to the end of line.
+
+There are a few built-in patterns to make this easier, and `tex`
+is one of them, so you do not have to write the above in your
+configuration file (you still need to enable this with the
+attribute mechanism, via `.gitattributes`).  The following built in
+patterns are available:
+
+- `ada` suitable for source code in the Ada language.
+
+- `bash` suitable for source code in the Bourne-Again SHell language.
+  Covers a superset of POSIX shell function definitions.
+
+- `bibtex` suitable for files with BibTeX coded references.
+
+- `cpp` suitable for source code in the C and C++ languages.
+
+- `csharp` suitable for source code in the C# language.
+
+- `css` suitable for cascading style sheets.
+
+- `dts` suitable for devicetree (DTS) files.
+
+- `elixir` suitable for source code in the Elixir language.
+
+- `fortran` suitable for source code in the Fortran language.
+
+- `fountain` suitable for Fountain documents.
+
+- `golang` suitable for source code in the Go language.
+
+- `html` suitable for HTML/XHTML documents.
+
+- `java` suitable for source code in the Java language.
+
+- `kotlin` suitable for source code in the Kotlin language.
+
+- `markdown` suitable for Markdown documents.
+
+- `matlab` suitable for source code in the MATLAB and Octave languages.
+
+- `objc` suitable for source code in the Objective-C language.
+
+- `pascal` suitable for source code in the Pascal/Delphi language.
+
+- `perl` suitable for source code in the Perl language.
+
+- `php` suitable for source code in the PHP language.
+
+- `python` suitable for source code in the Python language.
+
+- `ruby` suitable for source code in the Ruby language.
+
+- `rust` suitable for source code in the Rust language.
+
+- `scheme` suitable for source code in the Scheme language.
+
+- `tex` suitable for source code for LaTeX documents.
+
+
+Customizing word diff
+^^^^^^^^^^^^^^^^^^^^^
+
+You can customize the rules that `git diff --word-diff` uses to
+split words in a line, by specifying an appropriate regular expression
+in the "diff.*.wordRegex" configuration variable.  For example, in TeX
+a backslash followed by a sequence of letters forms a command, but
+several such commands can be run together without intervening
+whitespace.  To separate them, use a regular expression in your
+`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
+
+------------------------
+[diff "tex"]
+	wordRegex = "\\\\[a-zA-Z]+|[{}]|\\\\.|[^\\{}[:space:]]+"
+------------------------
+
+A built-in pattern is provided for all languages listed in the
+previous section.
+
+
+Performing text diffs of binary files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Sometimes it is desirable to see the diff of a text-converted
+version of some binary files. For example, a word processor
+document can be converted to an ASCII text representation, and
+the diff of the text shown. Even though this conversion loses
+some information, the resulting diff is useful for human
+viewing (but cannot be applied directly).
+
+The `textconv` config option is used to define a program for
+performing such a conversion. The program should take a single
+argument, the name of a file to convert, and produce the
+resulting text on stdout.
+
+For example, to show the diff of the exif information of a
+file instead of the binary information (assuming you have the
+exif tool installed), add the following section to your
+`$GIT_DIR/config` file (or `$HOME/.gitconfig` file):
+
+------------------------
+[diff "jpg"]
+	textconv = exif
+------------------------
+
+NOTE: The text conversion is generally a one-way conversion;
+in this example, we lose the actual image contents and focus
+just on the text data. This means that diffs generated by
+textconv are _not_ suitable for applying. For this reason,
+only `git diff` and the `git log` family of commands (i.e.,
+log, whatchanged, show) will perform text conversion. `git
+format-patch` will never generate this output. If you want to
+send somebody a text-converted diff of a binary file (e.g.,
+because it quickly conveys the changes you have made), you
+should generate it separately and send it as a comment _in
+addition to_ the usual binary diff that you might send.
+
+Because text conversion can be slow, especially when doing a
+large number of them with `git log -p`, Git provides a mechanism
+to cache the output and use it in future diffs.  To enable
+caching, set the "cachetextconv" variable in your diff driver's
+config. For example:
+
+------------------------
+[diff "jpg"]
+	textconv = exif
+	cachetextconv = true
+------------------------
+
+This will cache the result of running "exif" on each blob
+indefinitely. If you change the textconv config variable for a
+diff driver, Git will automatically invalidate the cache entries
+and re-run the textconv filter. If you want to invalidate the
+cache manually (e.g., because your version of "exif" was updated
+and now produces better output), you can remove the cache
+manually with `git update-ref -d refs/notes/textconv/jpg` (where
+"jpg" is the name of the diff driver, as in the example above).
+
+Choosing textconv versus external diff
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you want to show differences between binary or specially-formatted
+blobs in your repository, you can choose to use either an external diff
+command, or to use textconv to convert them to a diff-able text format.
+Which method you choose depends on your exact situation.
+
+The advantage of using an external diff command is flexibility. You are
+not bound to find line-oriented changes, nor is it necessary for the
+output to resemble unified diff. You are free to locate and report
+changes in the most appropriate way for your data format.
+
+A textconv, by comparison, is much more limiting. You provide a
+transformation of the data into a line-oriented text format, and Git
+uses its regular diff tools to generate the output. There are several
+advantages to choosing this method:
+
+1. Ease of use. It is often much simpler to write a binary to text
+   transformation than it is to perform your own diff. In many cases,
+   existing programs can be used as textconv filters (e.g., exif,
+   odt2txt).
+
+2. Git diff features. By performing only the transformation step
+   yourself, you can still utilize many of Git's diff features,
+   including colorization, word-diff, and combined diffs for merges.
+
+3. Caching. Textconv caching can speed up repeated diffs, such as those
+   you might trigger by running `git log -p`.
+
+
+Marking files as binary
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Git usually guesses correctly whether a blob contains text or binary
+data by examining the beginning of the contents. However, sometimes you
+may want to override its decision, either because a blob contains binary
+data later in the file, or because the content, while technically
+composed of text characters, is opaque to a human reader. For example,
+many postscript files contain only ASCII characters, but produce noisy
+and meaningless diffs.
+
+The simplest way to mark a file as binary is to unset the diff
+attribute in the `.gitattributes` file:
+
+------------------------
+*.ps -diff
+------------------------
+
+This will cause Git to generate `Binary files differ` (or a binary
+patch, if binary patches are enabled) instead of a regular diff.
+
+However, one may also want to specify other diff driver attributes. For
+example, you might want to use `textconv` to convert postscript files to
+an ASCII representation for human viewing, but otherwise treat them as
+binary files. You cannot specify both `-diff` and `diff=ps` attributes.
+The solution is to use the `diff.*.binary` config option:
+
+------------------------
+[diff "ps"]
+  textconv = ps2ascii
+  binary = true
+------------------------
+
+Performing a three-way merge
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`merge`
+^^^^^^^
+
+The attribute `merge` affects how three versions of a file are
+merged when a file-level merge is necessary during `git merge`,
+and other commands such as `git revert` and `git cherry-pick`.
+
+Set::
+
+	Built-in 3-way merge driver is used to merge the
+	contents in a way similar to 'merge' command of `RCS`
+	suite.  This is suitable for ordinary text files.
+
+Unset::
+
+	Take the version from the current branch as the
+	tentative merge result, and declare that the merge has
+	conflicts.  This is suitable for binary files that do
+	not have a well-defined merge semantics.
+
+Unspecified::
+
+	By default, this uses the same built-in 3-way merge
+	driver as is the case when the `merge` attribute is set.
+	However, the `merge.default` configuration variable can name
+	different merge driver to be used with paths for which the
+	`merge` attribute is unspecified.
+
+String::
+
+	3-way merge is performed using the specified custom
+	merge driver.  The built-in 3-way merge driver can be
+	explicitly specified by asking for "text" driver; the
+	built-in "take the current branch" driver can be
+	requested with "binary".
+
+
+Built-in merge drivers
+^^^^^^^^^^^^^^^^^^^^^^
+
+There are a few built-in low-level merge drivers defined that
+can be asked for via the `merge` attribute.
+
+text::
+
+	Usual 3-way file level merge for text files.  Conflicted
+	regions are marked with conflict markers `<<<<<<<`,
+	`=======` and `>>>>>>>`.  The version from your branch
+	appears before the `=======` marker, and the version
+	from the merged branch appears after the `=======`
+	marker.
+
+binary::
+
+	Keep the version from your branch in the work tree, but
+	leave the path in the conflicted state for the user to
+	sort out.
+
+union::
+
+	Run 3-way file level merge for text files, but take
+	lines from both versions, instead of leaving conflict
+	markers.  This tends to leave the added lines in the
+	resulting file in random order and the user should
+	verify the result. Do not use this if you do not
+	understand the implications.
+
+
+Defining a custom merge driver
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The definition of a merge driver is done in the `.git/config`
+file, not in the `gitattributes` file, so strictly speaking this
+manual page is a wrong place to talk about it.  However...
+
+To define a custom merge driver `filfre`, add a section to your
+`$GIT_DIR/config` file (or `$HOME/.gitconfig` file) like this:
+
+----------------------------------------------------------------
+[merge "filfre"]
+	name = feel-free merge driver
+	driver = filfre %O %A %B %L %P
+	recursive = binary
+----------------------------------------------------------------
+
+The `merge.*.name` variable gives the driver a human-readable
+name.
+
+The `merge.*.driver` variable's value is used to construct a
+command to run to common ancestor's version (`%O`), current
+version (`%A`) and the other branches' version (`%B`).  These
+three tokens are replaced with the names of temporary files that
+hold the contents of these versions when the command line is
+built. Additionally, `%L` will be replaced with the conflict marker
+size (see below).
+
+The merge driver is expected to leave the result of the merge in
+the file named with `%A` by overwriting it, and exit with zero
+status if it managed to merge them cleanly, or non-zero if there
+were conflicts.  When the driver crashes (e.g. killed by SEGV),
+it is expected to exit with non-zero status that are higher than
+128, and in such a case, the merge results in a failure (which is
+different from producing a conflict).
+
+The `merge.*.recursive` variable specifies what other merge
+driver to use when the merge driver is called for an internal
+merge between common ancestors, when there are more than one.
+When left unspecified, the driver itself is used for both
+internal merge and the final merge.
+
+The merge driver can learn the pathname in which the merged result
+will be stored via placeholder `%P`. The conflict labels to be used
+for the common ancestor, local head and other head can be passed by
+using `%S`, `%X` and `%Y` respectively.
+
+`conflict-marker-size`
+^^^^^^^^^^^^^^^^^^^^^^
+
+This attribute controls the length of conflict markers left in
+the work tree file during a conflicted merge.  Only a positive
+integer has a meaningful effect.
+
+For example, this line in `.gitattributes` can be used to tell the merge
+machinery to leave much longer (instead of the usual 7-character-long)
+conflict markers when merging the file `Documentation/git-merge.txt`
+results in a conflict.
+
+------------------------
+Documentation/git-merge.txt	conflict-marker-size=32
+------------------------
+
+
+Checking whitespace errors
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`whitespace`
+^^^^^^^^^^^^
+
+The `core.whitespace` configuration variable allows you to define what
+'diff' and 'apply' should consider whitespace errors for all paths in
+the project (See linkgit:git-config[1]).  This attribute gives you finer
+control per path.
+
+Set::
+
+	Notice all types of potential whitespace errors known to Git.
+	The tab width is taken from the value of the `core.whitespace`
+	configuration variable.
+
+Unset::
+
+	Do not notice anything as error.
+
+Unspecified::
+
+	Use the value of the `core.whitespace` configuration variable to
+	decide what to notice as error.
+
+String::
+
+	Specify a comma separated list of common whitespace problems to
+	notice in the same format as the `core.whitespace` configuration
+	variable.
+
+
+Creating an archive
+~~~~~~~~~~~~~~~~~~~
+
+`export-ignore`
+^^^^^^^^^^^^^^^
+
+Files and directories with the attribute `export-ignore` won't be added to
+archive files.
+
+`export-subst`
+^^^^^^^^^^^^^^
+
+If the attribute `export-subst` is set for a file then Git will expand
+several placeholders when adding this file to an archive.  The
+expansion depends on the availability of a commit ID, i.e., if
+linkgit:git-archive[1] has been given a tree instead of a commit or a
+tag then no replacement will be done.  The placeholders are the same
+as those for the option `--pretty=format:` of linkgit:git-log[1],
+except that they need to be wrapped like this: `$Format:PLACEHOLDERS$`
+in the file.  E.g. the string `$Format:%H$` will be replaced by the
+commit hash.  However, only one `%(describe)` placeholder is expanded
+per archive to avoid denial-of-service attacks.
+
+
+Packing objects
+~~~~~~~~~~~~~~~
+
+`delta`
+^^^^^^^
+
+Delta compression will not be attempted for blobs for paths with the
+attribute `delta` set to false.
+
+
+Viewing files in GUI tools
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`encoding`
+^^^^^^^^^^
+
+The value of this attribute specifies the character encoding that should
+be used by GUI tools (e.g. linkgit:gitk[1] and linkgit:git-gui[1]) to
+display the contents of the relevant file. Note that due to performance
+considerations linkgit:gitk[1] does not use this attribute unless you
+manually enable per-file encodings in its options.
+
+If this attribute is not set or has an invalid value, the value of the
+`gui.encoding` configuration variable is used instead
+(See linkgit:git-config[1]).
+
+
+USING MACRO ATTRIBUTES
+----------------------
+
+You do not want any end-of-line conversions applied to, nor textual diffs
+produced for, any binary file you track.  You would need to specify e.g.
+
+------------
+*.jpg -text -diff
+------------
+
+but that may become cumbersome, when you have many attributes.  Using
+macro attributes, you can define an attribute that, when set, also
+sets or unsets a number of other attributes at the same time.  The
+system knows a built-in macro attribute, `binary`:
+
+------------
+*.jpg binary
+------------
+
+Setting the "binary" attribute also unsets the "text" and "diff"
+attributes as above.  Note that macro attributes can only be "Set",
+though setting one might have the effect of setting or unsetting other
+attributes or even returning other attributes to the "Unspecified"
+state.
+
+
+DEFINING MACRO ATTRIBUTES
+-------------------------
+
+Custom macro attributes can be defined only in top-level gitattributes
+files (`$GIT_DIR/info/attributes`, the `.gitattributes` file at the
+top level of the working tree, or the global or system-wide
+gitattributes files), not in `.gitattributes` files in working tree
+subdirectories.  The built-in macro attribute "binary" is equivalent
+to:
+
+------------
+[attr]binary -diff -merge -text
+------------
+
+NOTES
+-----
+
+Git does not follow symbolic links when accessing a `.gitattributes`
+file in the working tree. This keeps behavior consistent when the file
+is accessed from the index or a tree versus from the filesystem.
+
+EXAMPLES
+--------
+
+If you have these three `gitattributes` file:
+
+----------------------------------------------------------------
+(in $GIT_DIR/info/attributes)
+
+a*	foo !bar -baz
+
+(in .gitattributes)
+abc	foo bar baz
+
+(in t/.gitattributes)
+ab*	merge=filfre
+abc	-foo -bar
+*.c	frotz
+----------------------------------------------------------------
+
+the attributes given to path `t/abc` are computed as follows:
+
+1. By examining `t/.gitattributes` (which is in the same
+   directory as the path in question), Git finds that the first
+   line matches.  `merge` attribute is set.  It also finds that
+   the second line matches, and attributes `foo` and `bar`
+   are unset.
+
+2. Then it examines `.gitattributes` (which is in the parent
+   directory), and finds that the first line matches, but
+   `t/.gitattributes` file already decided how `merge`, `foo`
+   and `bar` attributes should be given to this path, so it
+   leaves `foo` and `bar` unset.  Attribute `baz` is set.
+
+3. Finally it examines `$GIT_DIR/info/attributes`.  This file
+   is used to override the in-tree settings.  The first line is
+   a match, and `foo` is set, `bar` is reverted to unspecified
+   state, and `baz` is unset.
+
+As the result, the attributes assignment to `t/abc` becomes:
+
+----------------------------------------------------------------
+foo	set to true
+bar	unspecified
+baz	set to false
+merge	set to string value "filfre"
+frotz	unspecified
+----------------------------------------------------------------
+
+
+SEE ALSO
+--------
+linkgit:git-check-attr[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitcli.adoc b/Documentation/gitcli.adoc
new file mode 100644
index 0000000000..04193ec907
--- /dev/null
+++ b/Documentation/gitcli.adoc
@@ -0,0 +1,269 @@
+gitcli(7)
+=========
+
+NAME
+----
+gitcli - Git command-line interface and conventions
+
+SYNOPSIS
+--------
+gitcli
+
+
+DESCRIPTION
+-----------
+
+This manual describes the convention used throughout Git CLI.
+
+Many commands take revisions (most often "commits", but sometimes
+"tree-ish", depending on the context and command) and paths as their
+arguments.  Here are the rules:
+
+ * Options come first and then args.
+    A subcommand may take dashed options (which may take their own
+    arguments, e.g. "--max-parents 2") and arguments.  You SHOULD
+    give dashed options first and then arguments.  Some commands may
+    accept dashed options after you have already given non-option
+    arguments (which may make the command ambiguous), but you should
+    not rely on it (because eventually we may find a way to fix
+    these ambiguities by enforcing the "options then args" rule).
+
+ * Revisions come first and then paths.
+   E.g. in `git diff v1.0 v2.0 arch/x86 include/asm-x86`,
+   `v1.0` and `v2.0` are revisions and `arch/x86` and `include/asm-x86`
+   are paths.
+
+ * When an argument can be misunderstood as either a revision or a path,
+   they can be disambiguated by placing `--` between them.
+   E.g. `git diff -- HEAD` is, "I have a file called HEAD in my work
+   tree.  Please show changes between the version I staged in the index
+   and what I have in the work tree for that file", not "show the difference
+   between the HEAD commit and the work tree as a whole".  You can say
+   `git diff HEAD --` to ask for the latter.
+
+ * Without disambiguating `--`, Git makes a reasonable guess, but errors
+   out and asks you to disambiguate when ambiguous.  E.g. if you have a
+   file called HEAD in your work tree, `git diff HEAD` is ambiguous, and
+   you have to say either `git diff HEAD --` or `git diff -- HEAD` to
+   disambiguate.
+
+ * Because `--` disambiguates revisions and paths in some commands, it
+   cannot be used for those commands to separate options and revisions.
+   You can use `--end-of-options` for this (it also works for commands
+   that do not distinguish between revisions in paths, in which case it
+   is simply an alias for `--`).
++
+When writing a script that is expected to handle random user-input, it is
+a good practice to make it explicit which arguments are which by placing
+disambiguating `--` at appropriate places.
+
+ * Many commands allow wildcards in paths, but you need to protect
+   them from getting globbed by the shell.  These two mean different
+   things:
++
+--------------------------------
+$ git restore *.c
+$ git restore \*.c
+--------------------------------
++
+The former lets your shell expand the fileglob, and you are asking
+the dot-C files in your working tree to be overwritten with the version
+in the index.  The latter passes the `*.c` to Git, and you are asking
+the paths in the index that match the pattern to be checked out to your
+working tree.  After running `git add hello.c; rm hello.c`, you will _not_
+see `hello.c` in your working tree with the former, but with the latter
+you will.
+
+ * Just as the filesystem '.' (period) refers to the current directory,
+   using a '.' as a repository name in Git (a dot-repository) is a relative
+   path and means your current repository.
+
+Here are the rules regarding the "flags" that you should follow when you are
+scripting Git:
+
+ * Splitting short options to separate words (prefer `git foo -a -b`
+   to `git foo -ab`, the latter may not even work).
+
+ * When a command-line option takes an argument, use the 'stuck' form.  In
+   other words, write `git foo -oArg` instead of `git foo -o Arg` for short
+   options, and `git foo --long-opt=Arg` instead of `git foo --long-opt Arg`
+   for long options.  An option that takes optional option-argument must be
+   written in the 'stuck' form.
+
+ * Despite the above suggestion, when Arg is a path relative to the
+   home directory of a user, e.g. `~/directory/file` or `~u/d/f`, you
+   may want to use the separate form, e.g. `git foo --file ~/mine`,
+   not `git foo --file=~/mine`.  The shell will expand `~/` in the
+   former to your home directory, but most shells keep the tilde in
+   the latter.  Some of our commands know how to tilde-expand the
+   option value even when given in the stuck form, but not all of
+   them do.
+
+ * When you give a revision parameter to a command, make sure the parameter is
+   not ambiguous with a name of a file in the work tree.  E.g. do not write
+   `git log -1 HEAD` but write `git log -1 HEAD --`; the former will not work
+   if you happen to have a file called `HEAD` in the work tree.
+
+ * Many commands allow a long option `--option` to be abbreviated
+   only to their unique prefix (e.g. if there is no other option
+   whose name begins with `opt`, you may be able to spell `--opt` to
+   invoke the `--option` flag), but you should fully spell them out
+   when writing your scripts; later versions of Git may introduce a
+   new option whose name shares the same prefix, e.g. `--optimize`,
+   to make a short prefix that used to be unique no longer unique.
+
+
+ENHANCED OPTION PARSER
+----------------------
+From the Git 1.5.4 series and further, many Git commands (not all of them at the
+time of the writing though) come with an enhanced option parser.
+
+Here is a list of the facilities provided by this option parser.
+
+
+Magic Options
+~~~~~~~~~~~~~
+Commands which have the enhanced option parser activated all understand a
+couple of magic command-line options:
+
+-h::
+	gives a pretty printed usage of the command.
++
+---------------------------------------------
+$ git describe -h
+usage: git describe [<options>] <commit-ish>*
+   or: git describe [<options>] --dirty
+
+    --contains            find the tag that comes after the commit
+    --debug               debug search strategy on stderr
+    --all                 use any ref
+    --tags                use any tag, even unannotated
+    --long                always use long format
+    --abbrev[=<n>]        use <n> digits to display SHA-1s
+---------------------------------------------
++
+Note that some subcommand (e.g. `git grep`) may behave differently
+when there are things on the command line other than `-h`, but `git
+subcmd -h` without anything else on the command line is meant to
+consistently give the usage.
+
+--help-all::
+	Some Git commands take options that are only used for plumbing or that
+	are deprecated, and such options are hidden from the default usage. This
+	option gives the full list of options.
+
+
+Negating options
+~~~~~~~~~~~~~~~~
+Options with long option names can be negated by prefixing `--no-`. For
+example, `git branch` has the option `--track` which is 'on' by default. You
+can use `--no-track` to override that behaviour. The same goes for `--color`
+and `--no-color`.
+
+
+Options trump configuration and environment
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When there is a configuration variable or an environment variable
+that tweak the behaviour of an aspect of a Git command, and also a
+command line option that tweaks the same, the command line option
+overrides what the configuration and/or environment variable say.
+
+For example, the `user.name` configuration variable is used to
+specify the human-readable name used by the `git commit` command to
+record the author and the committer name in a newly created commit.
+The `GIT_AUTHOR_NAME` environment variable, if set, takes precedence
+when deciding what author name to record.  The `--author=<author>`
+command line option of the `git commit` command, when given, takes
+precedence over these two sources of information.
+
+
+Aggregating short options
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Commands that support the enhanced option parser allow you to aggregate short
+options. This means that you can for example use `git rm -rf` or
+`git clean -fdx`.
+
+
+Abbreviating long options
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Commands that support the enhanced option parser accepts unique
+prefix of a long option as if it is fully spelled out, but use this
+with a caution.  For example, `git commit --amen` behaves as if you
+typed `git commit --amend`, but that is true only until a later version
+of Git introduces another option that shares the same prefix,
+e.g. `git commit --amenity` option.
+
+
+Separating argument from the option
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can write the mandatory option parameter to an option as a separate
+word on the command line.  That means that all the following uses work:
+
+----------------------------
+$ git foo --long-opt=Arg
+$ git foo --long-opt Arg
+$ git foo -oArg
+$ git foo -o Arg
+----------------------------
+
+However, this is *NOT* allowed for switches with an optional value, where the
+'stuck' form must be used:
+----------------------------
+$ git describe --abbrev HEAD     # correct
+$ git describe --abbrev=10 HEAD  # correct
+$ git describe --abbrev 10 HEAD  # NOT WHAT YOU MEANT
+----------------------------
+
+
+NOTES ON FREQUENTLY CONFUSED OPTIONS
+------------------------------------
+
+Many commands that can work on files in the working tree
+and/or in the index can take `--cached` and/or `--index`
+options.  Sometimes people incorrectly think that, because
+the index was originally called cache, these two are
+synonyms.  They are *not* -- these two options mean very
+different things.
+
+ * The `--cached` option is used to ask a command that
+   usually works on files in the working tree to *only* work
+   with the index.  For example, `git grep`, when used
+   without a commit to specify from which commit to look for
+   strings in, usually works on files in the working tree,
+   but with the `--cached` option, it looks for strings in
+   the index.
+
+ * The `--index` option is used to ask a command that
+   usually works on files in the working tree to *also*
+   affect the index.  For example, `git stash apply` usually
+   merges changes recorded in a stash entry to the working tree,
+   but with the `--index` option, it also merges changes to
+   the index as well.
+
+`git apply` command can be used with `--cached` and
+`--index` (but not at the same time).  Usually the command
+only affects the files in the working tree, but with
+`--index`, it patches both the files and their index
+entries, and with `--cached`, it modifies only the index
+entries.
+
+See also https://lore.kernel.org/git/7v64clg5u9.fsf@xxxxxxxxxxxxxxxxxxxxxxxx/ and
+https://lore.kernel.org/git/7vy7ej9g38.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx/ for further
+information.
+
+Some other commands that also work on files in the working tree and/or
+in the index can take `--staged` and/or `--worktree`.
+
+* `--staged` is exactly like `--cached`, which is used to ask a
+  command to only work on the index, not the working tree.
+
+* `--worktree` is the opposite, to ask a command to work on the
+  working tree only, not the index.
+
+* The two options can be specified together to ask a command to work
+  on both the index and the working tree.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitcore-tutorial.adoc b/Documentation/gitcore-tutorial.adoc
new file mode 100644
index 0000000000..2122aeb976
--- /dev/null
+++ b/Documentation/gitcore-tutorial.adoc
@@ -0,0 +1,1660 @@
+gitcore-tutorial(7)
+===================
+
+NAME
+----
+gitcore-tutorial - A Git core tutorial for developers
+
+SYNOPSIS
+--------
+git *
+
+DESCRIPTION
+-----------
+
+This tutorial explains how to use the "core" Git commands to set up and
+work with a Git repository.
+
+If you just need to use Git as a revision control system you may prefer
+to start with "A Tutorial Introduction to Git" (linkgit:gittutorial[7]) or
+link:user-manual.html[the Git User Manual].
+
+However, an understanding of these low-level tools can be helpful if
+you want to understand Git's internals.
+
+The core Git is often called "plumbing", with the prettier user
+interfaces on top of it called "porcelain". You may not want to use the
+plumbing directly very often, but it can be good to know what the
+plumbing does when the porcelain isn't flushing.
+
+Back when this document was originally written, many porcelain
+commands were shell scripts. For simplicity, it still uses them as
+examples to illustrate how plumbing is fit together to form the
+porcelain commands. The source tree includes some of these scripts in
+contrib/examples/ for reference. Although these are not implemented as
+shell scripts anymore, the description of what the plumbing layer
+commands do is still valid.
+
+[NOTE]
+Deeper technical details are often marked as Notes, which you can
+skip on your first reading.
+
+
+Creating a Git repository
+-------------------------
+
+Creating a new Git repository couldn't be easier: all Git repositories start
+out empty, and the only thing you need to do is find yourself a
+subdirectory that you want to use as a working tree - either an empty
+one for a totally new project, or an existing working tree that you want
+to import into Git.
+
+For our first example, we're going to start a totally new repository from
+scratch, with no pre-existing files, and we'll call it 'git-tutorial'.
+To start up, create a subdirectory for it, change into that
+subdirectory, and initialize the Git infrastructure with 'git init':
+
+------------------------------------------------
+$ mkdir git-tutorial
+$ cd git-tutorial
+$ git init
+------------------------------------------------
+
+to which Git will reply
+
+----------------
+Initialized empty Git repository in .git/
+----------------
+
+which is just Git's way of saying that you haven't been doing anything
+strange, and that it will have created a local `.git` directory setup for
+your new project. You will now have a `.git` directory, and you can
+inspect that with 'ls'. For your new empty project, it should show you
+three entries, among other things:
+
+ - a file called `HEAD`, that has `ref: refs/heads/master` in it.
+   This is similar to a symbolic link and points at
+   `refs/heads/master` relative to the `HEAD` file.
++
+Don't worry about the fact that the file that the `HEAD` link points to
+doesn't even exist yet -- you haven't created the commit that will
+start your `HEAD` development branch yet.
+
+ - a subdirectory called `objects`, which will contain all the
+   objects of your project. You should never have any real reason to
+   look at the objects directly, but you might want to know that these
+   objects are what contains all the real 'data' in your repository.
+
+ - a subdirectory called `refs`, which contains references to objects.
+
+In particular, the `refs` subdirectory will contain two other
+subdirectories, named `heads` and `tags` respectively. They do
+exactly what their names imply: they contain references to any number
+of different 'heads' of development (aka 'branches'), and to any
+'tags' that you have created to name specific versions in your
+repository.
+
+One note: the special `master` head is the default branch, which is
+why the `.git/HEAD` file was created points to it even if it
+doesn't yet exist. Basically, the `HEAD` link is supposed to always
+point to the branch you are working on right now, and you always
+start out expecting to work on the `master` branch.
+
+However, this is only a convention, and you can name your branches
+anything you want, and don't have to ever even 'have' a `master`
+branch. A number of the Git tools will assume that `.git/HEAD` is
+valid, though.
+
+[NOTE]
+An 'object' is identified by its 160-bit SHA-1 hash, aka 'object name',
+and a reference to an object is always the 40-byte hex
+representation of that SHA-1 name. The files in the `refs`
+subdirectory are expected to contain these hex references
+(usually with a final `\n` at the end), and you should thus
+expect to see a number of 41-byte files containing these
+references in these `refs` subdirectories when you actually start
+populating your tree.
+
+[NOTE]
+An advanced user may want to take a look at linkgit:gitrepository-layout[5]
+after finishing this tutorial.
+
+You have now created your first Git repository. Of course, since it's
+empty, that's not very useful, so let's start populating it with data.
+
+
+Populating a Git repository
+---------------------------
+
+We'll keep this simple and stupid, so we'll start off with populating a
+few trivial files just to get a feel for it.
+
+Start off with just creating any random files that you want to maintain
+in your Git repository. We'll start off with a few bad examples, just to
+get a feel for how this works:
+
+------------------------------------------------
+$ echo "Hello World" >hello
+$ echo "Silly example" >example
+------------------------------------------------
+
+you have now created two files in your working tree (aka 'working directory'),
+but to actually check in your hard work, you will have to go through two steps:
+
+ - fill in the 'index' file (aka 'cache') with the information about your
+   working tree state.
+
+ - commit that index file as an object.
+
+The first step is trivial: when you want to tell Git about any changes
+to your working tree, you use the 'git update-index' program. That
+program normally just takes a list of filenames you want to update, but
+to avoid trivial mistakes, it refuses to add new entries to the index
+(or remove existing ones) unless you explicitly tell it that you're
+adding a new entry with the `--add` flag (or removing an entry with the
+`--remove`) flag.
+
+So to populate the index with the two files you just created, you can do
+
+------------------------------------------------
+$ git update-index --add hello example
+------------------------------------------------
+
+and you have now told Git to track those two files.
+
+In fact, as you did that, if you now look into your object directory,
+you'll notice that Git will have added two new objects to the object
+database. If you did exactly the steps above, you should now be able to do
+
+
+----------------
+$ ls .git/objects/??/*
+----------------
+
+and see two files:
+
+----------------
+.git/objects/55/7db03de997c86a4a028e1ebd3a1ceb225be238
+.git/objects/f2/4c74a2e500f5ee1332c86b94199f52b1d1d962
+----------------
+
+which correspond with the objects with names of `557db...` and
+`f24c7...` respectively.
+
+If you want to, you can use 'git cat-file' to look at those objects, but
+you'll have to use the object name, not the filename of the object:
+
+----------------
+$ git cat-file -t 557db03de997c86a4a028e1ebd3a1ceb225be238
+----------------
+
+where the `-t` tells 'git cat-file' to tell you what the "type" of the
+object is. Git will tell you that you have a "blob" object (i.e., just a
+regular file), and you can see the contents with
+
+----------------
+$ git cat-file blob 557db03
+----------------
+
+which will print out "Hello World". The object `557db03` is nothing
+more than the contents of your file `hello`.
+
+[NOTE]
+Don't confuse that object with the file `hello` itself. The
+object is literally just those specific *contents* of the file, and
+however much you later change the contents in file `hello`, the object
+we just looked at will never change. Objects are immutable.
+
+[NOTE]
+The second example demonstrates that you can
+abbreviate the object name to only the first several
+hexadecimal digits in most places.
+
+Anyway, as we mentioned previously, you normally never actually take a
+look at the objects themselves, and typing long 40-character hex
+names is not something you'd normally want to do. The above digression
+was just to show that 'git update-index' did something magical, and
+actually saved away the contents of your files into the Git object
+database.
+
+Updating the index did something else too: it created a `.git/index`
+file. This is the index that describes your current working tree, and
+something you should be very aware of. Again, you normally never worry
+about the index file itself, but you should be aware of the fact that
+you have not actually really "checked in" your files into Git so far,
+you've only *told* Git about them.
+
+However, since Git knows about them, you can now start using some of the
+most basic Git commands to manipulate the files or look at their status.
+
+In particular, let's not even check in the two files into Git yet, we'll
+start off by adding another line to `hello` first:
+
+------------------------------------------------
+$ echo "It's a new day for git" >>hello
+------------------------------------------------
+
+and you can now, since you told Git about the previous state of `hello`, ask
+Git what has changed in the tree compared to your old index, using the
+'git diff-files' command:
+
+------------
+$ git diff-files
+------------
+
+Oops. That wasn't very readable. It just spit out its own internal
+version of a 'diff', but that internal version really just tells you
+that it has noticed that "hello" has been modified, and that the old object
+contents it had have been replaced with something else.
+
+To make it readable, we can tell 'git diff-files' to output the
+differences as a patch, using the `-p` flag:
+
+------------
+$ git diff-files -p
+diff --git a/hello b/hello
+index 557db03..263414f 100644
+--- a/hello
++++ b/hello
+@@ -1 +1,2 @@
+ Hello World
++It's a new day for git
+------------
+
+i.e. the diff of the change we caused by adding another line to `hello`.
+
+In other words, 'git diff-files' always shows us the difference between
+what is recorded in the index, and what is currently in the working
+tree. That's very useful.
+
+A common shorthand for `git diff-files -p` is to just write `git
+diff`, which will do the same thing.
+
+------------
+$ git diff
+diff --git a/hello b/hello
+index 557db03..263414f 100644
+--- a/hello
++++ b/hello
+@@ -1 +1,2 @@
+ Hello World
++It's a new day for git
+------------
+
+
+Committing Git state
+--------------------
+
+Now, we want to go to the next stage in Git, which is to take the files
+that Git knows about in the index, and commit them as a real tree. We do
+that in two phases: creating a 'tree' object, and committing that 'tree'
+object as a 'commit' object together with an explanation of what the
+tree was all about, along with information of how we came to that state.
+
+Creating a tree object is trivial, and is done with 'git write-tree'.
+There are no options or other input: `git write-tree` will take the
+current index state, and write an object that describes that whole
+index. In other words, we're now tying together all the different
+filenames with their contents (and their permissions), and we're
+creating the equivalent of a Git "directory" object:
+
+------------------------------------------------
+$ git write-tree
+------------------------------------------------
+
+and this will just output the name of the resulting tree, in this case
+(if you have done exactly as I've described) it should be
+
+----------------
+8988da15d077d4829fc51d8544c097def6644dbb
+----------------
+
+which is another incomprehensible object name. Again, if you want to,
+you can use `git cat-file -t 8988d...` to see that this time the object
+is not a "blob" object, but a "tree" object (you can also use
+`git cat-file` to actually output the raw object contents, but you'll see
+mainly a binary mess, so that's less interesting).
+
+However -- normally you'd never use 'git write-tree' on its own, because
+normally you always commit a tree into a commit object using the
+'git commit-tree' command. In fact, it's easier to not actually use
+'git write-tree' on its own at all, but to just pass its result in as an
+argument to 'git commit-tree'.
+
+'git commit-tree' normally takes several arguments -- it wants to know
+what the 'parent' of a commit was, but since this is the first commit
+ever in this new repository, and it has no parents, we only need to pass in
+the object name of the tree. However, 'git commit-tree' also wants to get a
+commit message on its standard input, and it will write out the resulting
+object name for the commit to its standard output.
+
+And this is where we create the `.git/refs/heads/master` file
+which is pointed at by `HEAD`. This file is supposed to contain
+the reference to the top-of-tree of the master branch, and since
+that's exactly what 'git commit-tree' spits out, we can do this
+all with a sequence of simple shell commands:
+
+------------------------------------------------
+$ tree=$(git write-tree)
+$ commit=$(echo 'Initial commit' | git commit-tree $tree)
+$ git update-ref HEAD $commit
+------------------------------------------------
+
+In this case this creates a totally new commit that is not related to
+anything else. Normally you do this only *once* for a project ever, and
+all later commits will be parented on top of an earlier commit.
+
+Again, normally you'd never actually do this by hand. There is a
+helpful script called `git commit` that will do all of this for you. So
+you could have just written `git commit`
+instead, and it would have done the above magic scripting for you.
+
+
+Making a change
+---------------
+
+Remember how we did the 'git update-index' on file `hello` and then we
+changed `hello` afterward, and could compare the new state of `hello` with the
+state we saved in the index file?
+
+Further, remember how I said that 'git write-tree' writes the contents
+of the *index* file to the tree, and thus what we just committed was in
+fact the *original* contents of the file `hello`, not the new ones. We did
+that on purpose, to show the difference between the index state, and the
+state in the working tree, and how they don't have to match, even
+when we commit things.
+
+As before, if we do `git diff-files -p` in our git-tutorial project,
+we'll still see the same difference we saw last time: the index file
+hasn't changed by the act of committing anything. However, now that we
+have committed something, we can also learn to use a new command:
+'git diff-index'.
+
+Unlike 'git diff-files', which showed the difference between the index
+file and the working tree, 'git diff-index' shows the differences
+between a committed *tree* and either the index file or the working
+tree. In other words, 'git diff-index' wants a tree to be diffed
+against, and before we did the commit, we couldn't do that, because we
+didn't have anything to diff against.
+
+But now we can do
+
+----------------
+$ git diff-index -p HEAD
+----------------
+
+(where `-p` has the same meaning as it did in 'git diff-files'), and it
+will show us the same difference, but for a totally different reason.
+Now we're comparing the working tree not against the index file,
+but against the tree we just wrote. It just so happens that those two
+are obviously the same, so we get the same result.
+
+Again, because this is a common operation, you can also just shorthand
+it with
+
+----------------
+$ git diff HEAD
+----------------
+
+which ends up doing the above for you.
+
+In other words, 'git diff-index' normally compares a tree against the
+working tree, but when given the `--cached` flag, it is told to
+instead compare against just the index cache contents, and ignore the
+current working tree state entirely. Since we just wrote the index
+file to HEAD, doing `git diff-index --cached -p HEAD` should thus return
+an empty set of differences, and that's exactly what it does.
+
+[NOTE]
+================
+'git diff-index' really always uses the index for its
+comparisons, and saying that it compares a tree against the working
+tree is thus not strictly accurate. In particular, the list of
+files to compare (the "meta-data") *always* comes from the index file,
+regardless of whether the `--cached` flag is used or not. The `--cached`
+flag really only determines whether the file *contents* to be compared
+come from the working tree or not.
+
+This is not hard to understand, as soon as you realize that Git simply
+never knows (or cares) about files that it is not told about
+explicitly. Git will never go *looking* for files to compare, it
+expects you to tell it what the files are, and that's what the index
+is there for.
+================
+
+However, our next step is to commit the *change* we did, and again, to
+understand what's going on, keep in mind the difference between "working
+tree contents", "index file" and "committed tree". We have changes
+in the working tree that we want to commit, and we always have to
+work through the index file, so the first thing we need to do is to
+update the index cache:
+
+------------------------------------------------
+$ git update-index hello
+------------------------------------------------
+
+(note how we didn't need the `--add` flag this time, since Git knew
+about the file already).
+
+Note what happens to the different 'git diff-{asterisk}' versions here.
+After we've updated `hello` in the index, `git diff-files -p` now shows no
+differences, but `git diff-index -p HEAD` still *does* show that the
+current state is different from the state we committed. In fact, now
+'git diff-index' shows the same difference whether we use the `--cached`
+flag or not, since now the index is coherent with the working tree.
+
+Now, since we've updated `hello` in the index, we can commit the new
+version. We could do it by writing the tree by hand again, and
+committing the tree (this time we'd have to use the `-p HEAD` flag to
+tell commit that the HEAD was the *parent* of the new commit, and that
+this wasn't an initial commit any more), but you've done that once
+already, so let's just use the helpful script this time:
+
+------------------------------------------------
+$ git commit
+------------------------------------------------
+
+which starts an editor for you to write the commit message and tells you
+a bit about what you have done.
+
+Write whatever message you want, and all the lines that start with '#'
+will be pruned out, and the rest will be used as the commit message for
+the change. If you decide you don't want to commit anything after all at
+this point (you can continue to edit things and update the index), you
+can just leave an empty message. Otherwise `git commit` will commit
+the change for you.
+
+You've now made your first real Git commit. And if you're interested in
+looking at what `git commit` really does, feel free to investigate:
+it's a few very simple shell scripts to generate the helpful (?) commit
+message headers, and a few one-liners that actually do the
+commit itself ('git commit').
+
+
+Inspecting Changes
+------------------
+
+While creating changes is useful, it's even more useful if you can tell
+later what changed. The most useful command for this is another of the
+'diff' family, namely 'git diff-tree'.
+
+'git diff-tree' can be given two arbitrary trees, and it will tell you the
+differences between them. Perhaps even more commonly, though, you can
+give it just a single commit object, and it will figure out the parent
+of that commit itself, and show the difference directly. Thus, to get
+the same diff that we've already seen several times, we can now do
+
+----------------
+$ git diff-tree -p HEAD
+----------------
+
+(again, `-p` means to show the difference as a human-readable patch),
+and it will show what the last commit (in `HEAD`) actually changed.
+
+[NOTE]
+============
+Here is an ASCII art by Jon Loeliger that illustrates how
+various 'diff-{asterisk}' commands compare things.
+
+                      diff-tree
+                       +----+
+                       |    |
+                       |    |
+                       V    V
+                    +-----------+
+                    | Object DB |
+                    |  Backing  |
+                    |   Store   |
+                    +-----------+
+                      ^    ^
+                      |    |
+                      |    |  diff-index --cached
+                      |    |
+          diff-index  |    V
+                      |  +-----------+
+                      |  |   Index   |
+                      |  |  "cache"  |
+                      |  +-----------+
+                      |    ^
+                      |    |
+                      |    |  diff-files
+                      |    |
+                      V    V
+                    +-----------+
+                    |  Working  |
+                    | Directory |
+                    +-----------+
+============
+
+More interestingly, you can also give 'git diff-tree' the `--pretty` flag,
+which tells it to also show the commit message and author and date of the
+commit, and you can tell it to show a whole series of diffs.
+Alternatively, you can tell it to be "silent", and not show the diffs at
+all, but just show the actual commit message.
+
+In fact, together with the 'git rev-list' program (which generates a
+list of revisions), 'git diff-tree' ends up being a veritable fount of
+changes.  You can emulate `git log`, `git log -p`, etc. with a trivial
+script that pipes the output of `git rev-list` to `git diff-tree --stdin`,
+which was exactly how early versions of `git log` were implemented.
+
+
+Tagging a version
+-----------------
+
+In Git, there are two kinds of tags, a "light" one, and an "annotated tag".
+
+A "light" tag is technically nothing more than a branch, except we put
+it in the `.git/refs/tags/` subdirectory instead of calling it a `head`.
+So the simplest form of tag involves nothing more than
+
+------------------------------------------------
+$ git tag my-first-tag
+------------------------------------------------
+
+which just writes the current `HEAD` into the `.git/refs/tags/my-first-tag`
+file, after which point you can then use this symbolic name for that
+particular state. You can, for example, do
+
+----------------
+$ git diff my-first-tag
+----------------
+
+to diff your current state against that tag which at this point will
+obviously be an empty diff, but if you continue to develop and commit
+stuff, you can use your tag as an "anchor-point" to see what has changed
+since you tagged it.
+
+An "annotated tag" is actually a real Git object, and contains not only a
+pointer to the state you want to tag, but also a small tag name and
+message, along with optionally a PGP signature that says that yes,
+you really did
+that tag. You create these annotated tags with either the `-a` or
+`-s` flag to 'git tag':
+
+----------------
+$ git tag -s <tagname>
+----------------
+
+which will sign the current `HEAD` (but you can also give it another
+argument that specifies the thing to tag, e.g., you could have tagged the
+current `mybranch` point by using `git tag <tagname> mybranch`).
+
+You normally only do signed tags for major releases or things
+like that, while the light-weight tags are useful for any marking you
+want to do -- any time you decide that you want to remember a certain
+point, just create a private tag for it, and you have a nice symbolic
+name for the state at that point.
+
+
+Copying repositories
+--------------------
+
+Git repositories are normally totally self-sufficient and relocatable.
+Unlike CVS, for example, there is no separate notion of
+"repository" and "working tree". A Git repository normally *is* the
+working tree, with the local Git information hidden in the `.git`
+subdirectory. There is nothing else. What you see is what you got.
+
+[NOTE]
+You can tell Git to split the Git internal information from
+the directory that it tracks, but we'll ignore that for now: it's not
+how normal projects work, and it's really only meant for special uses.
+So the mental model of "the Git information is always tied directly to
+the working tree that it describes" may not be technically 100%
+accurate, but it's a good model for all normal use.
+
+This has two implications:
+
+ - if you grow bored with the tutorial repository you created (or you've
+   made a mistake and want to start all over), you can just do simple
++
+----------------
+$ rm -rf git-tutorial
+----------------
++
+and it will be gone. There's no external repository, and there's no
+history outside the project you created.
+
+ - if you want to move or duplicate a Git repository, you can do so. There
+   is 'git clone' command, but if all you want to do is just to
+   create a copy of your repository (with all the full history that
+   went along with it), you can do so with a regular
+   `cp -a git-tutorial new-git-tutorial`.
++
+Note that when you've moved or copied a Git repository, your Git index
+file (which caches various information, notably some of the "stat"
+information for the files involved) will likely need to be refreshed.
+So after you do a `cp -a` to create a new copy, you'll want to do
++
+----------------
+$ git update-index --refresh
+----------------
++
+in the new repository to make sure that the index file is up to date.
+
+Note that the second point is true even across machines. You can
+duplicate a remote Git repository with *any* regular copy mechanism, be it
+'scp', 'rsync' or 'wget'.
+
+When copying a remote repository, you'll want to at a minimum update the
+index cache when you do this, and especially with other peoples'
+repositories you often want to make sure that the index cache is in some
+known state (you don't know *what* they've done and not yet checked in),
+so usually you'll precede the 'git update-index' with a
+
+----------------
+$ git read-tree --reset HEAD
+$ git update-index --refresh
+----------------
+
+which will force a total index re-build from the tree pointed to by `HEAD`.
+It resets the index contents to `HEAD`, and then the 'git update-index'
+makes sure to match up all index entries with the checked-out files.
+If the original repository had uncommitted changes in its
+working tree, `git update-index --refresh` notices them and
+tells you they need to be updated.
+
+The above can also be written as simply
+
+----------------
+$ git reset
+----------------
+
+and in fact a lot of the common Git command combinations can be scripted
+with the `git xyz` interfaces.  You can learn things by just looking
+at what the various git scripts do.  For example, `git reset` used to be
+the above two lines implemented in 'git reset', but some things like
+'git status' and 'git commit' are slightly more complex scripts around
+the basic Git commands.
+
+Many (most?) public remote repositories will not contain any of
+the checked out files or even an index file, and will *only* contain the
+actual core Git files. Such a repository usually doesn't even have the
+`.git` subdirectory, but has all the Git files directly in the
+repository.
+
+To create your own local live copy of such a "raw" Git repository, you'd
+first create your own subdirectory for the project, and then copy the
+raw repository contents into the `.git` directory. For example, to
+create your own copy of the Git repository, you'd do the following
+
+----------------
+$ mkdir my-git
+$ cd my-git
+$ rsync -rL rsync://rsync.kernel.org/pub/scm/git/git.git/ .git
+----------------
+
+followed by
+
+----------------
+$ git read-tree HEAD
+----------------
+
+to populate the index. However, now you have populated the index, and
+you have all the Git internal files, but you will notice that you don't
+actually have any of the working tree files to work on. To get
+those, you'd check them out with
+
+----------------
+$ git checkout-index -u -a
+----------------
+
+where the `-u` flag means that you want the checkout to keep the index
+up to date (so that you don't have to refresh it afterward), and the
+`-a` flag means "check out all files" (if you have a stale copy or an
+older version of a checked out tree you may also need to add the `-f`
+flag first, to tell 'git checkout-index' to *force* overwriting of any old
+files).
+
+Again, this can all be simplified with
+
+----------------
+$ git clone git://git.kernel.org/pub/scm/git/git.git/ my-git
+$ cd my-git
+$ git checkout
+----------------
+
+which will end up doing all of the above for you.
+
+You have now successfully copied somebody else's (mine) remote
+repository, and checked it out.
+
+
+Creating a new branch
+---------------------
+
+Branches in Git are really nothing more than pointers into the Git
+object database from within the `.git/refs/` subdirectory, and as we
+already discussed, the `HEAD` branch is nothing but a symlink to one of
+these object pointers.
+
+You can at any time create a new branch by just picking an arbitrary
+point in the project history, and just writing the SHA-1 name of that
+object into a file under `.git/refs/heads/`. You can use any filename you
+want (and indeed, subdirectories), but the convention is that the
+"normal" branch is called `master`. That's just a convention, though,
+and nothing enforces it.
+
+To show that as an example, let's go back to the git-tutorial repository we
+used earlier, and create a branch in it. You do that by simply just
+saying that you want to check out a new branch:
+
+------------
+$ git switch -c mybranch
+------------
+
+will create a new branch based at the current `HEAD` position, and switch
+to it.
+
+[NOTE]
+================================================
+If you make the decision to start your new branch at some
+other point in the history than the current `HEAD`, you can do so by
+just telling 'git switch' what the base of the checkout would be.
+In other words, if you have an earlier tag or branch, you'd just do
+
+------------
+$ git switch -c mybranch earlier-commit
+------------
+
+and it would create the new branch `mybranch` at the earlier commit,
+and check out the state at that time.
+================================================
+
+You can always just jump back to your original `master` branch by doing
+
+------------
+$ git switch master
+------------
+
+(or any other branch-name, for that matter) and if you forget which
+branch you happen to be on, a simple
+
+------------
+$ cat .git/HEAD
+------------
+
+will tell you where it's pointing.  To get the list of branches
+you have, you can say
+
+------------
+$ git branch
+------------
+
+which used to be nothing more than a simple script around `ls .git/refs/heads`.
+There will be an asterisk in front of the branch you are currently on.
+
+Sometimes you may wish to create a new branch _without_ actually
+checking it out and switching to it. If so, just use the command
+
+------------
+$ git branch <branchname> [startingpoint]
+------------
+
+which will simply _create_ the branch, but will not do anything further.
+You can then later -- once you decide that you want to actually develop
+on that branch -- switch to that branch with a regular 'git switch'
+with the branchname as the argument.
+
+
+Merging two branches
+--------------------
+
+One of the ideas of having a branch is that you do some (possibly
+experimental) work in it, and eventually merge it back to the main
+branch. So assuming you created the above `mybranch` that started out
+being the same as the original `master` branch, let's make sure we're in
+that branch, and do some work there.
+
+------------------------------------------------
+$ git switch mybranch
+$ echo "Work, work, work" >>hello
+$ git commit -m "Some work." -i hello
+------------------------------------------------
+
+Here, we just added another line to `hello`, and we used a shorthand for
+doing both `git update-index hello` and `git commit` by just giving the
+filename directly to `git commit`, with an `-i` flag (it tells
+Git to 'include' that file in addition to what you have done to
+the index file so far when making the commit).  The `-m` flag is to give the
+commit log message from the command line.
+
+Now, to make it a bit more interesting, let's assume that somebody else
+does some work in the original branch, and simulate that by going back
+to the master branch, and editing the same file differently there:
+
+------------
+$ git switch master
+------------
+
+Here, take a moment to look at the contents of `hello`, and notice how they
+don't contain the work we just did in `mybranch` -- because that work
+hasn't happened in the `master` branch at all. Then do
+
+------------
+$ echo "Play, play, play" >>hello
+$ echo "Lots of fun" >>example
+$ git commit -m "Some fun." -i hello example
+------------
+
+since the master branch is obviously in a much better mood.
+
+Now, you've got two branches, and you decide that you want to merge the
+work done. Before we do that, let's introduce a cool graphical tool that
+helps you view what's going on:
+
+----------------
+$ gitk --all
+----------------
+
+will show you graphically both of your branches (that's what the `--all`
+means: normally it will just show you your current `HEAD`) and their
+histories. You can also see exactly how they came to be from a common
+source.
+
+Anyway, let's exit 'gitk' (`^Q` or the File menu), and decide that we want
+to merge the work we did on the `mybranch` branch into the `master`
+branch (which is currently our `HEAD` too). To do that, there's a nice
+script called 'git merge', which wants to know which branches you want
+to resolve and what the merge is all about:
+
+------------
+$ git merge -m "Merge work in mybranch" mybranch
+------------
+
+where the first argument is going to be used as the commit message if
+the merge can be resolved automatically.
+
+Now, in this case we've intentionally created a situation where the
+merge will need to be fixed up by hand, though, so Git will do as much
+of it as it can automatically (which in this case is just merge the `example`
+file, which had no differences in the `mybranch` branch), and say:
+
+----------------
+	Auto-merging hello
+	CONFLICT (content): Merge conflict in hello
+	Automatic merge failed; fix conflicts and then commit the result.
+----------------
+
+It tells you that it did an "Automatic merge", which
+failed due to conflicts in `hello`.
+
+Not to worry. It left the (trivial) conflict in `hello` in the same form you
+should already be well used to if you've ever used CVS, so let's just
+open `hello` in our editor (whatever that may be), and fix it up somehow.
+I'd suggest just making it so that `hello` contains all four lines:
+
+------------
+Hello World
+It's a new day for git
+Play, play, play
+Work, work, work
+------------
+
+and once you're happy with your manual merge, just do a
+
+------------
+$ git commit -i hello
+------------
+
+which will very loudly warn you that you're now committing a merge
+(which is correct, so never mind), and you can write a small merge
+message about your adventures in 'git merge'-land.
+
+After you're done, start up `gitk --all` to see graphically what the
+history looks like. Notice that `mybranch` still exists, and you can
+switch to it, and continue to work with it if you want to. The
+`mybranch` branch will not contain the merge, but next time you merge it
+from the `master` branch, Git will know how you merged it, so you'll not
+have to do _that_ merge again.
+
+Another useful tool, especially if you do not always work in X-Window
+environment, is `git show-branch`.
+
+------------------------------------------------
+$ git show-branch --topo-order --more=1 master mybranch
+* [master] Merge work in mybranch
+ ! [mybranch] Some work.
+--
+-  [master] Merge work in mybranch
+*+ [mybranch] Some work.
+*  [master^] Some fun.
+------------------------------------------------
+
+The first two lines indicate that it is showing the two branches
+with the titles of their top-of-the-tree commits, you are currently on
+`master` branch (notice the asterisk `*` character), and the first
+column for the later output lines is used to show commits contained in the
+`master` branch, and the second column for the `mybranch`
+branch. Three commits are shown along with their titles.
+All of them have non blank characters in the first column (`*`
+shows an ordinary commit on the current branch, `-` is a merge commit), which
+means they are now part of the `master` branch. Only the "Some
+work" commit has the plus `+` character in the second column,
+because `mybranch` has not been merged to incorporate these
+commits from the master branch.  The string inside brackets
+before the commit log message is a short name you can use to
+name the commit.  In the above example, 'master' and 'mybranch'
+are branch heads.  'master^' is the first parent of 'master'
+branch head.  Please see linkgit:gitrevisions[7] if you want to
+see more complex cases.
+
+[NOTE]
+Without the '--more=1' option, 'git show-branch' would not output the
+'[master^]' commit, as '[mybranch]' commit is a common ancestor of
+both 'master' and 'mybranch' tips.  Please see linkgit:git-show-branch[1]
+for details.
+
+[NOTE]
+If there were more commits on the 'master' branch after the merge, the
+merge commit itself would not be shown by 'git show-branch' by
+default.  You would need to provide `--sparse` option to make the
+merge commit visible in this case.
+
+Now, let's pretend you are the one who did all the work in
+`mybranch`, and the fruit of your hard work has finally been merged
+to the `master` branch. Let's go back to `mybranch`, and run
+'git merge' to get the "upstream changes" back to your branch.
+
+------------
+$ git switch mybranch
+$ git merge -m "Merge upstream changes." master
+------------
+
+This outputs something like this (the actual commit object names
+would be different)
+
+----------------
+Updating from ae3a2da... to a80b4aa....
+Fast-forward (no commit created; -m option ignored)
+ example | 1 +
+ hello   | 1 +
+ 2 files changed, 2 insertions(+)
+----------------
+
+Because your branch did not contain anything more than what had
+already been merged into the `master` branch, the merge operation did
+not actually do a merge. Instead, it just updated the top of
+the tree of your branch to that of the `master` branch. This is
+often called 'fast-forward' merge.
+
+You can run `gitk --all` again to see how the commit ancestry
+looks like, or run 'show-branch', which tells you this.
+
+------------------------------------------------
+$ git show-branch master mybranch
+! [master] Merge work in mybranch
+ * [mybranch] Merge work in mybranch
+--
+-- [master] Merge work in mybranch
+------------------------------------------------
+
+
+Merging external work
+---------------------
+
+It's usually much more common that you merge with somebody else than
+merging with your own branches, so it's worth pointing out that Git
+makes that very easy too, and in fact, it's not that different from
+doing a 'git merge'. In fact, a remote merge ends up being nothing
+more than "fetch the work from a remote repository into a temporary tag"
+followed by a 'git merge'.
+
+Fetching from a remote repository is done by, unsurprisingly,
+'git fetch':
+
+----------------
+$ git fetch <remote-repository>
+----------------
+
+One of the following transports can be used to name the
+repository to download from:
+
+SSH::
+	`remote.machine:/path/to/repo.git/` or
++
+`ssh://remote.machine/path/to/repo.git/`
++
+This transport can be used for both uploading and downloading,
+and requires you to have a log-in privilege over `ssh` to the
+remote machine.  It finds out the set of objects the other side
+lacks by exchanging the head commits both ends have and
+transfers (close to) minimum set of objects.  It is by far the
+most efficient way to exchange Git objects between repositories.
+
+Local directory::
+	`/path/to/repo.git/`
++
+This transport is the same as SSH transport but uses 'sh' to run
+both ends on the local machine instead of running other end on
+the remote machine via 'ssh'.
+
+Git Native::
+	`git://remote.machine/path/to/repo.git/`
++
+This transport was designed for anonymous downloading.  Like SSH
+transport, it finds out the set of objects the downstream side
+lacks and transfers (close to) minimum set of objects.
+
+HTTP(S)::
+	`http://remote.machine/path/to/repo.git/`
++
+Downloader from http and https URL
+first obtains the topmost commit object name from the remote site
+by looking at the specified refname under `repo.git/refs/` directory,
+and then tries to obtain the
+commit object by downloading from `repo.git/objects/xx/xxx...`
+using the object name of that commit object.  Then it reads the
+commit object to find out its parent commits and the associate
+tree object; it repeats this process until it gets all the
+necessary objects.  Because of this behavior, they are
+sometimes also called 'commit walkers'.
++
+The 'commit walkers' are sometimes also called 'dumb
+transports', because they do not require any Git aware smart
+server like Git Native transport does.  Any stock HTTP server
+that does not even support directory index would suffice.  But
+you must prepare your repository with 'git update-server-info'
+to help dumb transport downloaders.
+
+Once you fetch from the remote repository, you `merge` that
+with your current branch.
+
+However -- it's such a common thing to `fetch` and then
+immediately `merge`, that it's called `git pull`, and you can
+simply do
+
+----------------
+$ git pull <remote-repository>
+----------------
+
+and optionally give a branch-name for the remote end as a second
+argument.
+
+[NOTE]
+You could do without using any branches at all, by
+keeping as many local repositories as you would like to have
+branches, and merging between them with 'git pull', just like
+you merge between branches. The advantage of this approach is
+that it lets you keep a set of files for each `branch` checked
+out and you may find it easier to switch back and forth if you
+juggle multiple lines of development simultaneously. Of
+course, you will pay the price of more disk usage to hold
+multiple working trees, but disk space is cheap these days.
+
+It is likely that you will be pulling from the same remote
+repository from time to time. As a short hand, you can store
+the remote repository URL in the local repository's config file
+like this:
+
+------------------------------------------------
+$ git config remote.linus.url https://git.kernel.org/pub/scm/git/git.git/
+------------------------------------------------
+
+and use the "linus" keyword with 'git pull' instead of the full URL.
+
+Examples.
+
+. `git pull linus`
+. `git pull linus tag v0.99.1`
+
+the above are equivalent to:
+
+. `git pull http://www.kernel.org/pub/scm/git/git.git/ HEAD`
+. `git pull http://www.kernel.org/pub/scm/git/git.git/ tag v0.99.1`
+
+
+How does the merge work?
+------------------------
+
+We said this tutorial shows what plumbing does to help you cope
+with the porcelain that isn't flushing, but we so far did not
+talk about how the merge really works.  If you are following
+this tutorial the first time, I'd suggest to skip to "Publishing
+your work" section and come back here later.
+
+OK, still with me?  To give us an example to look at, let's go
+back to the earlier repository with "hello" and "example" file,
+and bring ourselves back to the pre-merge state:
+
+------------
+$ git show-branch --more=2 master mybranch
+! [master] Merge work in mybranch
+ * [mybranch] Merge work in mybranch
+--
+-- [master] Merge work in mybranch
++* [master^2] Some work.
++* [master^] Some fun.
+------------
+
+Remember, before running 'git merge', our `master` head was at
+"Some fun." commit, while our `mybranch` head was at "Some
+work." commit.
+
+------------
+$ git switch -C mybranch master^2
+$ git switch master
+$ git reset --hard master^
+------------
+
+After rewinding, the commit structure should look like this:
+
+------------
+$ git show-branch
+* [master] Some fun.
+ ! [mybranch] Some work.
+--
+*  [master] Some fun.
+ + [mybranch] Some work.
+*+ [master^] Initial commit
+------------
+
+Now we are ready to experiment with the merge by hand.
+
+`git merge` command, when merging two branches, uses 3-way merge
+algorithm.  First, it finds the common ancestor between them.
+The command it uses is 'git merge-base':
+
+------------
+$ mb=$(git merge-base HEAD mybranch)
+------------
+
+The command writes the commit object name of the common ancestor
+to the standard output, so we captured its output to a variable,
+because we will be using it in the next step.  By the way, the common
+ancestor commit is the "Initial commit" commit in this case.  You can
+tell it by:
+
+------------
+$ git name-rev --name-only --tags $mb
+my-first-tag
+------------
+
+After finding out a common ancestor commit, the second step is
+this:
+
+------------
+$ git read-tree -m -u $mb HEAD mybranch
+------------
+
+This is the same 'git read-tree' command we have already seen,
+but it takes three trees, unlike previous examples.  This reads
+the contents of each tree into different 'stage' in the index
+file (the first tree goes to stage 1, the second to stage 2,
+etc.).  After reading three trees into three stages, the paths
+that are the same in all three stages are 'collapsed' into stage
+0.  Also paths that are the same in two of three stages are
+collapsed into stage 0, taking the SHA-1 from either stage 2 or
+stage 3, whichever is different from stage 1 (i.e. only one side
+changed from the common ancestor).
+
+After 'collapsing' operation, paths that are different in three
+trees are left in non-zero stages.  At this point, you can
+inspect the index file with this command:
+
+------------
+$ git ls-files --stage
+100644 7f8b141b65fdcee47321e399a2598a235a032422 0	example
+100644 557db03de997c86a4a028e1ebd3a1ceb225be238 1	hello
+100644 ba42a2a96e3027f3333e13ede4ccf4498c3ae942 2	hello
+100644 cc44c73eb783565da5831b4d820c962954019b69 3	hello
+------------
+
+In our example of only two files, we did not have unchanged
+files so only 'example' resulted in collapsing.  But in real-life
+large projects, when only a small number of files change in one commit,
+this 'collapsing' tends to trivially merge most of the paths
+fairly quickly, leaving only a handful of real changes in non-zero
+stages.
+
+To look at only non-zero stages, use `--unmerged` flag:
+
+------------
+$ git ls-files --unmerged
+100644 557db03de997c86a4a028e1ebd3a1ceb225be238 1	hello
+100644 ba42a2a96e3027f3333e13ede4ccf4498c3ae942 2	hello
+100644 cc44c73eb783565da5831b4d820c962954019b69 3	hello
+------------
+
+The next step of merging is to merge these three versions of the
+file, using 3-way merge.  This is done by giving
+'git merge-one-file' command as one of the arguments to
+'git merge-index' command:
+
+------------
+$ git merge-index git-merge-one-file hello
+Auto-merging hello
+ERROR: Merge conflict in hello
+fatal: merge program failed
+------------
+
+'git merge-one-file' script is called with parameters to
+describe those three versions, and is responsible to leave the
+merge results in the working tree.
+It is a fairly straightforward shell script, and
+eventually calls 'merge' program from RCS suite to perform a
+file-level 3-way merge.  In this case, 'merge' detects
+conflicts, and the merge result with conflict marks is left in
+the working tree..  This can be seen if you run `ls-files
+--stage` again at this point:
+
+------------
+$ git ls-files --stage
+100644 7f8b141b65fdcee47321e399a2598a235a032422 0	example
+100644 557db03de997c86a4a028e1ebd3a1ceb225be238 1	hello
+100644 ba42a2a96e3027f3333e13ede4ccf4498c3ae942 2	hello
+100644 cc44c73eb783565da5831b4d820c962954019b69 3	hello
+------------
+
+This is the state of the index file and the working file after
+'git merge' returns control back to you, leaving the conflicting
+merge for you to resolve.  Notice that the path `hello` is still
+unmerged, and what you see with 'git diff' at this point is
+differences since stage 2 (i.e. your version).
+
+
+Publishing your work
+--------------------
+
+So, we can use somebody else's work from a remote repository, but
+how can *you* prepare a repository to let other people pull from
+it?
+
+You do your real work in your working tree that has your
+primary repository hanging under it as its `.git` subdirectory.
+You *could* make that repository accessible remotely and ask
+people to pull from it, but in practice that is not the way
+things are usually done. A recommended way is to have a public
+repository, make it reachable by other people, and when the
+changes you made in your primary working tree are in good shape,
+update the public repository from it. This is often called
+'pushing'.
+
+[NOTE]
+This public repository could further be mirrored, and that is
+how Git repositories at `kernel.org` are managed.
+
+Publishing the changes from your local (private) repository to
+your remote (public) repository requires a write privilege on
+the remote machine. You need to have an SSH account there to
+run a single command, 'git-receive-pack'.
+
+First, you need to create an empty repository on the remote
+machine that will house your public repository. This empty
+repository will be populated and be kept up to date by pushing
+into it later. Obviously, this repository creation needs to be
+done only once.
+
+[NOTE]
+'git push' uses a pair of commands,
+'git send-pack' on your local machine, and 'git-receive-pack'
+on the remote machine. The communication between the two over
+the network internally uses an SSH connection.
+
+Your private repository's Git directory is usually `.git`, but
+your public repository is often named after the project name,
+i.e. `<project>.git`. Let's create such a public repository for
+project `my-git`. After logging into the remote machine, create
+an empty directory:
+
+------------
+$ mkdir my-git.git
+------------
+
+Then, make that directory into a Git repository by running
+'git init', but this time, since its name is not the usual
+`.git`, we do things slightly differently:
+
+------------
+$ GIT_DIR=my-git.git git init
+------------
+
+Make sure this directory is available for others you want your
+changes to be pulled via the transport of your choice. Also
+you need to make sure that you have the 'git-receive-pack'
+program on the `$PATH`.
+
+[NOTE]
+Many installations of sshd do not invoke your shell as the login
+shell when you directly run programs; what this means is that if
+your login shell is 'bash', only `.bashrc` is read and not
+`.bash_profile`. As a workaround, make sure `.bashrc` sets up
+`$PATH` so that you can run 'git-receive-pack' program.
+
+[NOTE]
+If you plan to publish this repository to be accessed over http,
+you should do `mv my-git.git/hooks/post-update.sample
+my-git.git/hooks/post-update` at this point.
+This makes sure that every time you push into this
+repository, `git update-server-info` is run.
+
+Your "public repository" is now ready to accept your changes.
+Come back to the machine you have your private repository. From
+there, run this command:
+
+------------
+$ git push <public-host>:/path/to/my-git.git master
+------------
+
+This synchronizes your public repository to match the named
+branch head (i.e. `master` in this case) and objects reachable
+from them in your current repository.
+
+As a real example, this is how I update my public Git
+repository. Kernel.org mirror network takes care of the
+propagation to other publicly visible machines:
+
+------------
+$ git push master.kernel.org:/pub/scm/git/git.git/
+------------
+
+
+Packing your repository
+-----------------------
+
+Earlier, we saw that one file under `.git/objects/??/` directory
+is stored for each Git object you create. This representation
+is efficient to create atomically and safely, but
+not so convenient to transport over the network. Since Git objects are
+immutable once they are created, there is a way to optimize the
+storage by "packing them together". The command
+
+------------
+$ git repack
+------------
+
+will do it for you. If you followed the tutorial examples, you
+would have accumulated about 17 objects in `.git/objects/??/`
+directories by now. 'git repack' tells you how many objects it
+packed, and stores the packed file in the `.git/objects/pack`
+directory.
+
+[NOTE]
+You will see two files, `pack-*.pack` and `pack-*.idx`,
+in `.git/objects/pack` directory. They are closely related to
+each other, and if you ever copy them by hand to a different
+repository for whatever reason, you should make sure you copy
+them together. The former holds all the data from the objects
+in the pack, and the latter holds the index for random
+access.
+
+If you are paranoid, running 'git verify-pack' command would
+detect if you have a corrupt pack, but do not worry too much.
+Our programs are always perfect ;-).
+
+Once you have packed objects, you do not need to leave the
+unpacked objects that are contained in the pack file anymore.
+
+------------
+$ git prune-packed
+------------
+
+would remove them for you.
+
+You can try running `find .git/objects -type f` before and after
+you run `git prune-packed` if you are curious.  Also `git
+count-objects` would tell you how many unpacked objects are in
+your repository and how much space they are consuming.
+
+[NOTE]
+`git pull` is slightly cumbersome for HTTP transport, as a
+packed repository may contain relatively few objects in a
+relatively large pack. If you expect many HTTP pulls from your
+public repository you might want to repack & prune often, or
+never.
+
+If you run `git repack` again at this point, it will say
+"Nothing new to pack.". Once you continue your development and
+accumulate the changes, running `git repack` again will create a
+new pack, that contains objects created since you packed your
+repository the last time. We recommend that you pack your project
+soon after the initial import (unless you are starting your
+project from scratch), and then run `git repack` every once in a
+while, depending on how active your project is.
+
+When a repository is synchronized via `git push` and `git pull`
+objects packed in the source repository are usually stored
+unpacked in the destination.
+While this allows you to use different packing strategies on
+both ends, it also means you may need to repack both
+repositories every once in a while.
+
+
+Working with Others
+-------------------
+
+Although Git is a truly distributed system, it is often
+convenient to organize your project with an informal hierarchy
+of developers. Linux kernel development is run this way. There
+is a nice illustration (page 17, "Merges to Mainline") in
+https://web.archive.org/web/20120915203609/http://www.xenotime.net/linux/mentor/linux-mentoring-2006.pdf[Randy Dunlap's presentation].
+
+It should be stressed that this hierarchy is purely *informal*.
+There is nothing fundamental in Git that enforces the "chain of
+patch flow" this hierarchy implies. You do not have to pull
+from only one remote repository.
+
+A recommended workflow for a "project lead" goes like this:
+
+1. Prepare your primary repository on your local machine. Your
+   work is done there.
+
+2. Prepare a public repository accessible to others.
++
+If other people are pulling from your repository over dumb
+transport protocols (HTTP), you need to keep this repository
+'dumb transport friendly'.  After `git init`,
+`$GIT_DIR/hooks/post-update.sample` copied from the standard templates
+would contain a call to 'git update-server-info'
+but you need to manually enable the hook with
+`mv post-update.sample post-update`.  This makes sure
+'git update-server-info' keeps the necessary files up to date.
+
+3. Push into the public repository from your primary
+   repository.
+
+4. 'git repack' the public repository. This establishes a big
+   pack that contains the initial set of objects as the
+   baseline, and possibly 'git prune' if the transport
+   used for pulling from your repository supports packed
+   repositories.
+
+5. Keep working in your primary repository. Your changes
+   include modifications of your own, patches you receive via
+   e-mails, and merges resulting from pulling the "public"
+   repositories of your "subsystem maintainers".
++
+You can repack this private repository whenever you feel like.
+
+6. Push your changes to the public repository, and announce it
+   to the public.
+
+7. Every once in a while, 'git repack' the public repository.
+   Go back to step 5. and continue working.
+
+
+A recommended work cycle for a "subsystem maintainer" who works
+on that project and has an own "public repository" goes like this:
+
+1. Prepare your work repository, by running 'git clone' on the public
+   repository of the "project lead". The URL used for the
+   initial cloning is stored in the remote.origin.url
+   configuration variable.
+
+2. Prepare a public repository accessible to others, just like
+   the "project lead" person does.
+
+3. Copy over the packed files from "project lead" public
+   repository to your public repository, unless the "project
+   lead" repository lives on the same machine as yours.  In the
+   latter case, you can use `objects/info/alternates` file to
+   point at the repository you are borrowing from.
+
+4. Push into the public repository from your primary
+   repository. Run 'git repack', and possibly 'git prune' if the
+   transport used for pulling from your repository supports
+   packed repositories.
+
+5. Keep working in your primary repository. Your changes
+   include modifications of your own, patches you receive via
+   e-mails, and merges resulting from pulling the "public"
+   repositories of your "project lead" and possibly your
+   "sub-subsystem maintainers".
++
+You can repack this private repository whenever you feel
+like.
+
+6. Push your changes to your public repository, and ask your
+   "project lead" and possibly your "sub-subsystem
+   maintainers" to pull from it.
+
+7. Every once in a while, 'git repack' the public repository.
+   Go back to step 5. and continue working.
+
+
+A recommended work cycle for an "individual developer" who does
+not have a "public" repository is somewhat different. It goes
+like this:
+
+1. Prepare your work repository, by 'git clone' the public
+   repository of the "project lead" (or a "subsystem
+   maintainer", if you work on a subsystem). The URL used for
+   the initial cloning is stored in the remote.origin.url
+   configuration variable.
+
+2. Do your work in your repository on 'master' branch.
+
+3. Run `git fetch origin` from the public repository of your
+   upstream every once in a while. This does only the first
+   half of `git pull` but does not merge. The head of the
+   public repository is stored in `.git/refs/remotes/origin/master`.
+
+4. Use `git cherry origin` to see which ones of your patches
+   were accepted, and/or use `git rebase origin` to port your
+   unmerged changes forward to the updated upstream.
+
+5. Use `git format-patch origin` to prepare patches for e-mail
+   submission to your upstream and send it out. Go back to
+   step 2. and continue.
+
+
+Working with Others, Shared Repository Style
+--------------------------------------------
+
+If you are coming from a CVS background, the style of cooperation
+suggested in the previous section may be new to you. You do not
+have to worry. Git supports the "shared public repository" style of
+cooperation you are probably more familiar with as well.
+
+See linkgit:gitcvs-migration[7] for the details.
+
+Bundling your work together
+---------------------------
+
+It is likely that you will be working on more than one thing at
+a time.  It is easy to manage those more-or-less independent tasks
+using branches with Git.
+
+We have already seen how branches work previously,
+with "fun and work" example using two branches.  The idea is the
+same if there are more than two branches.  Let's say you started
+out from "master" head, and have some new code in the "master"
+branch, and two independent fixes in the "commit-fix" and
+"diff-fix" branches:
+
+------------
+$ git show-branch
+! [commit-fix] Fix commit message normalization.
+ ! [diff-fix] Fix rename detection.
+  * [master] Release candidate #1
+---
+ +  [diff-fix] Fix rename detection.
+ +  [diff-fix~1] Better common substring algorithm.
++   [commit-fix] Fix commit message normalization.
+  * [master] Release candidate #1
+++* [diff-fix~2] Pretty-print messages.
+------------
+
+Both fixes are tested well, and at this point, you want to merge
+in both of them.  You could merge in 'diff-fix' first and then
+'commit-fix' next, like this:
+
+------------
+$ git merge -m "Merge fix in diff-fix" diff-fix
+$ git merge -m "Merge fix in commit-fix" commit-fix
+------------
+
+Which would result in:
+
+------------
+$ git show-branch
+! [commit-fix] Fix commit message normalization.
+ ! [diff-fix] Fix rename detection.
+  * [master] Merge fix in commit-fix
+---
+  - [master] Merge fix in commit-fix
++ * [commit-fix] Fix commit message normalization.
+  - [master~1] Merge fix in diff-fix
+ +* [diff-fix] Fix rename detection.
+ +* [diff-fix~1] Better common substring algorithm.
+  * [master~2] Release candidate #1
+++* [master~3] Pretty-print messages.
+------------
+
+However, there is no particular reason to merge in one branch
+first and the other next, when what you have are a set of truly
+independent changes (if the order mattered, then they are not
+independent by definition).  You could instead merge those two
+branches into the current branch at once.  First let's undo what
+we just did and start over.  We would want to get the master
+branch before these two merges by resetting it to 'master~2':
+
+------------
+$ git reset --hard master~2
+------------
+
+You can make sure `git show-branch` matches the state before
+those two 'git merge' you just did.  Then, instead of running
+two 'git merge' commands in a row, you would merge these two
+branch heads (this is known as 'making an Octopus'):
+
+------------
+$ git merge commit-fix diff-fix
+$ git show-branch
+! [commit-fix] Fix commit message normalization.
+ ! [diff-fix] Fix rename detection.
+  * [master] Octopus merge of branches 'diff-fix' and 'commit-fix'
+---
+  - [master] Octopus merge of branches 'diff-fix' and 'commit-fix'
++ * [commit-fix] Fix commit message normalization.
+ +* [diff-fix] Fix rename detection.
+ +* [diff-fix~1] Better common substring algorithm.
+  * [master~1] Release candidate #1
+++* [master~2] Pretty-print messages.
+------------
+
+Note that you should not do Octopus just because you can.  An octopus
+is a valid thing to do and often makes it easier to view the
+commit history if you are merging more than two independent
+changes at the same time.  However, if you have merge conflicts
+with any of the branches you are merging in and need to hand
+resolve, that is an indication that the development happened in
+those branches were not independent after all, and you should
+merge two at a time, documenting how you resolved the conflicts,
+and the reason why you preferred changes made in one side over
+the other.  Otherwise it would make the project history harder
+to follow, not easier.
+
+SEE ALSO
+--------
+linkgit:gittutorial[7],
+linkgit:gittutorial-2[7],
+linkgit:gitcvs-migration[7],
+linkgit:git-help[1],
+linkgit:giteveryday[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitcredentials.adoc b/Documentation/gitcredentials.adoc
new file mode 100644
index 0000000000..3337bb475d
--- /dev/null
+++ b/Documentation/gitcredentials.adoc
@@ -0,0 +1,336 @@
+gitcredentials(7)
+=================
+
+NAME
+----
+gitcredentials - Providing usernames and passwords to Git
+
+SYNOPSIS
+--------
+------------------
+git config credential.https://example.com.username myusername
+git config credential.helper "$helper $options"
+------------------
+
+DESCRIPTION
+-----------
+
+Git will sometimes need credentials from the user in order to perform
+operations; for example, it may need to ask for a username and password
+in order to access a remote repository over HTTP. Some remotes accept
+a personal access token or OAuth access token as a password. This
+manual describes the mechanisms Git uses to request these credentials,
+as well as some features to avoid inputting these credentials repeatedly.
+
+REQUESTING CREDENTIALS
+----------------------
+
+Without any credential helpers defined, Git will try the following
+strategies to ask the user for usernames and passwords:
+
+1. If the `GIT_ASKPASS` environment variable is set, the program
+   specified by the variable is invoked. A suitable prompt is provided
+   to the program on the command line, and the user's input is read
+   from its standard output.
+
+2. Otherwise, if the `core.askPass` configuration variable is set, its
+   value is used as above.
+
+3. Otherwise, if the `SSH_ASKPASS` environment variable is set, its
+   value is used as above.
+
+4. Otherwise, the user is prompted on the terminal.
+
+AVOIDING REPETITION
+-------------------
+
+It can be cumbersome to input the same credentials over and over.  Git
+provides two methods to reduce this annoyance:
+
+1. Static configuration of usernames for a given authentication context.
+
+2. Credential helpers to cache or store passwords, or to interact with
+   a system password wallet or keychain.
+
+The first is simple and appropriate if you do not have secure storage available
+for a password. It is generally configured by adding this to your config:
+
+---------------------------------------
+[credential "https://example.com";]
+	username = me
+---------------------------------------
+
+Credential helpers, on the other hand, are external programs from which Git can
+request both usernames and passwords; they typically interface with secure
+storage provided by the OS or other programs. Alternatively, a
+credential-generating helper might generate credentials for certain servers via
+some API.
+
+To use a helper, you must first select one to use (see below for a list).
+
+You may also have third-party helpers installed; search for
+`credential-*` in the output of `git help -a`, and consult the
+documentation of individual helpers.  Once you have selected a helper,
+you can tell Git to use it by putting its name into the
+credential.helper variable.
+
+1. Find a helper.
++
+-------------------------------------------
+$ git help -a | grep credential-
+credential-foo
+-------------------------------------------
+
+2. Read its description.
++
+-------------------------------------------
+$ git help credential-foo
+-------------------------------------------
+
+3. Tell Git to use it.
++
+-------------------------------------------
+$ git config --global credential.helper foo
+-------------------------------------------
+
+=== Available helpers
+
+Git currently includes the following helpers:
+
+cache::
+
+    Cache credentials in memory for a short period of time. See
+    linkgit:git-credential-cache[1] for details.
+
+store::
+
+    Store credentials indefinitely on disk. See
+    linkgit:git-credential-store[1] for details.
+
+Popular helpers with secure persistent storage include:
+
+    - git-credential-libsecret (Linux)
+
+    - git-credential-osxkeychain (macOS)
+
+    - git-credential-wincred (Windows)
+
+    - https://github.com/git-ecosystem/git-credential-manager[Git Credential Manager] (cross platform, included in Git for Windows)
+
+The community maintains a comprehensive list of Git credential helpers at
+https://git-scm.com/doc/credential-helpers.
+
+=== OAuth
+
+An alternative to inputting passwords or personal access tokens is to use an
+OAuth credential helper. Initial authentication opens a browser window to the
+host. Subsequent authentication happens in the background. Many popular Git
+hosts support OAuth.
+
+Popular helpers with OAuth support include:
+
+    - https://github.com/git-ecosystem/git-credential-manager[Git Credential Manager] (cross platform, included in Git for Windows)
+
+    - https://github.com/hickford/git-credential-oauth[git-credential-oauth] (cross platform, included in many Linux distributions)
+
+CREDENTIAL CONTEXTS
+-------------------
+
+Git considers each credential to have a context defined by a URL. This context
+is used to look up context-specific configuration, and is passed to any
+helpers, which may use it as an index into secure storage.
+
+For instance, imagine we are accessing `https://example.com/foo.git`. When Git
+looks into a config file to see if a section matches this context, it will
+consider the two a match if the context is a more-specific subset of the
+pattern in the config file. For example, if you have this in your config file:
+
+--------------------------------------
+[credential "https://example.com";]
+	username = foo
+--------------------------------------
+
+then we will match: both protocols are the same, both hosts are the same, and
+the "pattern" URL does not care about the path component at all. However, this
+context would not match:
+
+--------------------------------------
+[credential "https://kernel.org";]
+	username = foo
+--------------------------------------
+
+because the hostnames differ. Nor would it match `foo.example.com`; Git
+compares hostnames exactly, without considering whether two hosts are part of
+the same domain. Likewise, a config entry for `http://example.com` would not
+match: Git compares the protocols exactly.  However, you may use wildcards in
+the domain name and other pattern matching techniques as with the `http.<URL>.*`
+options.
+
+If the "pattern" URL does include a path component, then this too must match
+exactly: the context `https://example.com/bar/baz.git` will match a config
+entry for `https://example.com/bar/baz.git` (in addition to matching the config
+entry for `https://example.com`) but will not match a config entry for
+`https://example.com/bar`.
+
+
+CONFIGURATION OPTIONS
+---------------------
+
+Options for a credential context can be configured either in
+`credential.*` (which applies to all credentials), or
+`credential.<URL>.*`, where <URL> matches the context as described
+above.
+
+The following options are available in either location:
+
+helper::
+
+	The name of an external credential helper, and any associated options.
+	If the helper name is not an absolute path, then the string `git
+	credential-` is prepended. The resulting string is executed by the
+	shell (so, for example, setting this to `foo --option=bar` will execute
+	`git credential-foo --option=bar` via the shell. See the manual of
+	specific helpers for examples of their use.
++
+If there are multiple instances of the `credential.helper` configuration
+variable, each helper will be tried in turn, and may provide a username,
+password, or nothing. Once Git has acquired both a username and a
+non-expired password, no more helpers will be tried.
++
+If `credential.helper` is configured to the empty string, this resets
+the helper list to empty (so you may override a helper set by a
+lower-priority config file by configuring the empty-string helper,
+followed by whatever set of helpers you would like).
+
+username::
+
+	A default username, if one is not provided in the URL.
+
+useHttpPath::
+
+	By default, Git does not consider the "path" component of an http URL
+	to be worth matching via external helpers. This means that a credential
+	stored for `https://example.com/foo.git` will also be used for
+	`https://example.com/bar.git`. If you do want to distinguish these
+	cases, set this option to `true`.
+
+
+CUSTOM HELPERS
+--------------
+
+You can write your own custom helpers to interface with any system in
+which you keep credentials.
+
+Credential helpers are programs executed by Git to fetch or save
+credentials from and to long-term storage (where "long-term" is simply
+longer than a single Git process; e.g., credentials may be stored
+in-memory for a few minutes, or indefinitely on disk).
+
+Each helper is specified by a single string in the configuration
+variable `credential.helper` (and others, see linkgit:git-config[1]).
+The string is transformed by Git into a command to be executed using
+these rules:
+
+  1. If the helper string begins with "!", it is considered a shell
+     snippet, and everything after the "!" becomes the command.
+
+  2. Otherwise, if the helper string begins with an absolute path, the
+     verbatim helper string becomes the command.
+
+  3. Otherwise, the string "git credential-" is prepended to the helper
+     string, and the result becomes the command.
+
+The resulting command then has an "operation" argument appended to it
+(see below for details), and the result is executed by the shell.
+
+Here are some example specifications:
+
+----------------------------------------------------
+# run "git credential-foo"
+[credential]
+	helper = foo
+
+# same as above, but pass an argument to the helper
+[credential]
+	helper = "foo --bar=baz"
+
+# the arguments are parsed by the shell, so use shell
+# quoting if necessary
+[credential]
+	helper = "foo --bar='whitespace arg'"
+
+# store helper (discouraged) with custom location for the db file;
+# use `--file ~/.git-secret.txt`, rather than `--file=~/.git-secret.txt`,
+# to allow the shell to expand tilde to the home directory.
+[credential]
+	helper = "store --file ~/.git-secret.txt"
+
+# you can also use an absolute path, which will not use the git wrapper
+[credential]
+	helper = "/path/to/my/helper --with-arguments"
+
+# or you can specify your own shell snippet
+[credential "https://example.com";]
+	username = your_user
+	helper = "!f() { test \"$1\" = get && echo \"password=$(cat $HOME/.secret)\"; }; f"
+----------------------------------------------------
+
+Generally speaking, rule (3) above is the simplest for users to specify.
+Authors of credential helpers should make an effort to assist their
+users by naming their program "git-credential-$NAME", and putting it in
+the `$PATH` or `$GIT_EXEC_PATH` during installation, which will allow a
+user to enable it with `git config credential.helper $NAME`.
+
+When a helper is executed, it will have one "operation" argument
+appended to its command line, which is one of:
+
+`get`::
+
+	Return a matching credential, if any exists.
+
+`store`::
+
+	Store the credential, if applicable to the helper.
+
+`erase`::
+
+	Remove matching credentials, if any, from the helper's storage.
+
+The details of the credential will be provided on the helper's stdin
+stream. The exact format is the same as the input/output format of the
+`git credential` plumbing command (see the section `INPUT/OUTPUT
+FORMAT` in linkgit:git-credential[1] for a detailed specification).
+
+For a `get` operation, the helper should produce a list of attributes on
+stdout in the same format (see linkgit:git-credential[1] for common
+attributes). A helper is free to produce a subset, or even no values at
+all if it has nothing useful to provide. Any provided attributes will
+overwrite those already known about by Git's credential subsystem.
+Unrecognised attributes are silently discarded.
+
+While it is possible to override all attributes, well behaving helpers
+should refrain from doing so for any attribute other than username and
+password.
+
+If a helper outputs a `quit` attribute with a value of `true` or `1`,
+no further helpers will be consulted, nor will the user be prompted
+(if no credential has been provided, the operation will then fail).
+
+Similarly, no more helpers will be consulted once both username and
+password had been provided.
+
+For a `store` or `erase` operation, the helper's output is ignored.
+
+If a helper fails to perform the requested operation or needs to notify
+the user of a potential issue, it may write to stderr.
+
+If it does not support the requested operation (e.g., a read-only store
+or generator), it should silently ignore the request.
+
+If a helper receives any other operation, it should silently ignore the
+request. This leaves room for future operations to be added (older
+helpers will just ignore the new requests).
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitcvs-migration.adoc b/Documentation/gitcvs-migration.adoc
new file mode 100644
index 0000000000..1cd1283d0f
--- /dev/null
+++ b/Documentation/gitcvs-migration.adoc
@@ -0,0 +1,206 @@
+gitcvs-migration(7)
+===================
+
+NAME
+----
+gitcvs-migration - Git for CVS users
+
+SYNOPSIS
+--------
+[verse]
+'git cvsimport' *
+
+DESCRIPTION
+-----------
+
+Git differs from CVS in that every working tree contains a repository with
+a full copy of the project history, and no repository is inherently more
+important than any other.  However, you can emulate the CVS model by
+designating a single shared repository which people can synchronize with;
+this document explains how to do that.
+
+Some basic familiarity with Git is required. Having gone through
+linkgit:gittutorial[7] and
+linkgit:gitglossary[7] should be sufficient.
+
+Developing against a shared repository
+--------------------------------------
+
+Suppose a shared repository is set up in /pub/repo.git on the host
+foo.com.  Then as an individual committer you can clone the shared
+repository over ssh with:
+
+------------------------------------------------
+$ git clone foo.com:/pub/repo.git/ my-project
+$ cd my-project
+------------------------------------------------
+
+and hack away.  The equivalent of 'cvs update' is
+
+------------------------------------------------
+$ git pull origin
+------------------------------------------------
+
+which merges in any work that others might have done since the clone
+operation.  If there are uncommitted changes in your working tree, commit
+them first before running git pull.
+
+[NOTE]
+================================
+The 'pull' command knows where to get updates from because of certain
+configuration variables that were set by the first 'git clone'
+command; see `git config -l` and the linkgit:git-config[1] man
+page for details.
+================================
+
+You can update the shared repository with your changes by first committing
+your changes, and then using the 'git push' command:
+
+------------------------------------------------
+$ git push origin master
+------------------------------------------------
+
+to "push" those commits to the shared repository.  If someone else has
+updated the repository more recently, 'git push', like 'cvs commit', will
+complain, in which case you must pull any changes before attempting the
+push again.
+
+In the 'git push' command above we specify the name of the remote branch
+to update (`master`).  If we leave that out, 'git push' tries to update
+any branches in the remote repository that have the same name as a branch
+in the local repository.  So the last 'push' can be done with either of:
+
+------------
+$ git push origin
+$ git push foo.com:/pub/project.git/
+------------
+
+as long as the shared repository does not have any branches
+other than `master`.
+
+Setting Up a Shared Repository
+------------------------------
+
+We assume you have already created a Git repository for your project,
+possibly created from scratch or from a tarball (see
+linkgit:gittutorial[7]), or imported from an already existing CVS
+repository (see the next section).
+
+Assume your existing repo is at /home/alice/myproject.  Create a new "bare"
+repository (a repository without a working tree) and fetch your project into
+it:
+
+------------------------------------------------
+$ mkdir /pub/my-repo.git
+$ cd /pub/my-repo.git
+$ git --bare init --shared
+$ git --bare fetch /home/alice/myproject master:master
+------------------------------------------------
+
+Next, give every team member read/write access to this repository.  One
+easy way to do this is to give all the team members ssh access to the
+machine where the repository is hosted.  If you don't want to give them a
+full shell on the machine, there is a restricted shell which only allows
+users to do Git pushes and pulls; see linkgit:git-shell[1].
+
+Put all the committers in the same group, and make the repository
+writable by that group:
+
+------------------------------------------------
+$ chgrp -R $group /pub/my-repo.git
+------------------------------------------------
+
+Make sure committers have a umask of at most 027, so that the directories
+they create are writable and searchable by other group members.
+
+Importing a CVS archive
+-----------------------
+
+NOTE: These instructions use the `git-cvsimport` script which ships with
+git, but other importers may provide better results. See the note in
+linkgit:git-cvsimport[1] for other options.
+
+First, install version 2.1 or higher of cvsps from
+https://github.com/andreyvit/cvsps[https://github.com/andreyvit/cvsps] and make
+sure it is in your path.  Then cd to a checked out CVS working directory
+of the project you are interested in and run linkgit:git-cvsimport[1]:
+
+-------------------------------------------
+$ git cvsimport -C <destination> <module>
+-------------------------------------------
+
+This puts a Git archive of the named CVS module in the directory
+<destination>, which will be created if necessary.
+
+The import checks out from CVS every revision of every file.  Reportedly
+cvsimport can average some twenty revisions per second, so for a
+medium-sized project this should not take more than a couple of minutes.
+Larger projects or remote repositories may take longer.
+
+The main trunk is stored in the Git branch named `origin`, and additional
+CVS branches are stored in Git branches with the same names.  The most
+recent version of the main trunk is also left checked out on the `master`
+branch, so you can start adding your own changes right away.
+
+The import is incremental, so if you call it again next month it will
+fetch any CVS updates that have been made in the meantime.  For this to
+work, you must not modify the imported branches; instead, create new
+branches for your own changes, and merge in the imported branches as
+necessary.
+
+If you want a shared repository, you will need to make a bare clone
+of the imported directory, as described above. Then treat the imported
+directory as another development clone for purposes of merging
+incremental imports.
+
+Advanced Shared Repository Management
+-------------------------------------
+
+Git allows you to specify scripts called "hooks" to be run at certain
+points.  You can use these, for example, to send all commits to the shared
+repository to a mailing list.  See linkgit:githooks[5].
+
+You can enforce finer grained permissions using update hooks.  See
+link:howto/update-hook-example.html[Controlling access to branches using
+update hooks].
+
+Providing CVS Access to a Git Repository
+----------------------------------------
+
+It is also possible to provide true CVS access to a Git repository, so
+that developers can still use CVS; see linkgit:git-cvsserver[1] for
+details.
+
+Alternative Development Models
+------------------------------
+
+CVS users are accustomed to giving a group of developers commit access to
+a common repository.  As we've seen, this is also possible with Git.
+However, the distributed nature of Git allows other development models,
+and you may want to first consider whether one of them might be a better
+fit for your project.
+
+For example, you can choose a single person to maintain the project's
+primary public repository.  Other developers then clone this repository
+and each work in their own clone.  When they have a series of changes that
+they're happy with, they ask the maintainer to pull from the branch
+containing the changes.  The maintainer reviews their changes and pulls
+them into the primary repository, which other developers pull from as
+necessary to stay coordinated.  The Linux kernel and other projects use
+variants of this model.
+
+With a small group, developers may just pull changes from each other's
+repositories without the need for a central maintainer.
+
+SEE ALSO
+--------
+linkgit:gittutorial[7],
+linkgit:gittutorial-2[7],
+linkgit:gitcore-tutorial[7],
+linkgit:gitglossary[7],
+linkgit:giteveryday[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitdiffcore.adoc b/Documentation/gitdiffcore.adoc
new file mode 100644
index 0000000000..642c51227b
--- /dev/null
+++ b/Documentation/gitdiffcore.adoc
@@ -0,0 +1,333 @@
+gitdiffcore(7)
+==============
+
+NAME
+----
+gitdiffcore - Tweaking diff output
+
+SYNOPSIS
+--------
+[verse]
+'git diff' *
+
+DESCRIPTION
+-----------
+
+The diff commands 'git diff-index', 'git diff-files', and 'git diff-tree'
+can be told to manipulate differences they find in
+unconventional ways before showing 'diff' output.  The manipulation
+is collectively called "diffcore transformation".  This short note
+describes what they are and how to use them to produce 'diff' output
+that is easier to understand than the conventional kind.
+
+
+The chain of operation
+----------------------
+
+The 'git diff-{asterisk}' family works by first comparing two sets of
+files:
+
+ - 'git diff-index' compares contents of a "tree" object and the
+   working directory (when `--cached` flag is not used) or a
+   "tree" object and the index file (when `--cached` flag is
+   used);
+
+ - 'git diff-files' compares contents of the index file and the
+   working directory;
+
+ - 'git diff-tree' compares contents of two "tree" objects;
+
+In all of these cases, the commands themselves first optionally limit
+the two sets of files by any pathspecs given on their command-lines,
+and compare corresponding paths in the two resulting sets of files.
+
+The pathspecs are used to limit the world diff operates in.  They remove
+the filepairs outside the specified sets of pathnames.  E.g. If the
+input set of filepairs included:
+
+------------------------------------------------
+:100644 100644 bcd1234... 0123456... M junkfile
+------------------------------------------------
+
+but the command invocation was `git diff-files myfile`, then the
+junkfile entry would be removed from the list because only "myfile"
+is under consideration.
+
+The result of comparison is passed from these commands to what is
+internally called "diffcore", in a format similar to what is output
+when the -p option is not used.  E.g.
+
+------------------------------------------------
+in-place edit  :100644 100644 bcd1234... 0123456... M file0
+create         :000000 100644 0000000... 1234567... A file4
+delete         :100644 000000 1234567... 0000000... D file5
+unmerged       :000000 000000 0000000... 0000000... U file6
+------------------------------------------------
+
+The diffcore mechanism is fed a list of such comparison results
+(each of which is called "filepair", although at this point each
+of them talks about a single file), and transforms such a list
+into another list.  There are currently 5 such transformations:
+
+- diffcore-break
+- diffcore-rename
+- diffcore-merge-broken
+- diffcore-pickaxe
+- diffcore-order
+- diffcore-rotate
+
+These are applied in sequence.  The set of filepairs 'git diff-{asterisk}'
+commands find are used as the input to diffcore-break, and
+the output from diffcore-break is used as the input to the
+next transformation.  The final result is then passed to the
+output routine and generates either diff-raw format (see Output
+format sections of the manual for 'git diff-{asterisk}' commands) or
+diff-patch format.
+
+
+diffcore-break: For Splitting Up Complete Rewrites
+--------------------------------------------------
+
+The second transformation in the chain is diffcore-break, and is
+controlled by the -B option to the 'git diff-{asterisk}' commands.  This is
+used to detect a filepair that represents "complete rewrite" and
+break such filepair into two filepairs that represent delete and
+create.  E.g.  If the input contained this filepair:
+
+------------------------------------------------
+:100644 100644 bcd1234... 0123456... M file0
+------------------------------------------------
+
+and if it detects that the file "file0" is completely rewritten,
+it changes it to:
+
+------------------------------------------------
+:100644 000000 bcd1234... 0000000... D file0
+:000000 100644 0000000... 0123456... A file0
+------------------------------------------------
+
+For the purpose of breaking a filepair, diffcore-break examines
+the extent of changes between the contents of the files before
+and after modification (i.e. the contents that have "bcd1234..."
+and "0123456..." as their SHA-1 content ID, in the above
+example).  The amount of deletion of original contents and
+insertion of new material are added together, and if it exceeds
+the "break score", the filepair is broken into two.  The break
+score defaults to 50% of the size of the smaller of the original
+and the result (i.e. if the edit shrinks the file, the size of
+the result is used; if the edit lengthens the file, the size of
+the original is used), and can be customized by giving a number
+after "-B" option (e.g. "-B75" to tell it to use 75%).
+
+
+diffcore-rename: For Detecting Renames and Copies
+-------------------------------------------------
+
+This transformation is used to detect renames and copies, and is
+controlled by the -M option (to detect renames) and the -C option
+(to detect copies as well) to the 'git diff-{asterisk}' commands.  If the
+input contained these filepairs:
+
+------------------------------------------------
+:100644 000000 0123456... 0000000... D fileX
+:000000 100644 0000000... 0123456... A file0
+------------------------------------------------
+
+and the contents of the deleted file fileX is similar enough to
+the contents of the created file file0, then rename detection
+merges these filepairs and creates:
+
+------------------------------------------------
+:100644 100644 0123456... 0123456... R100 fileX file0
+------------------------------------------------
+
+When the "-C" option is used, the original contents of modified files,
+and deleted files (and also unmodified files, if the
+"--find-copies-harder" option is used) are considered as candidates
+of the source files in rename/copy operation.  If the input were like
+these filepairs, that talk about a modified file fileY and a newly
+created file file0:
+
+------------------------------------------------
+:100644 100644 0123456... 1234567... M fileY
+:000000 100644 0000000... bcd3456... A file0
+------------------------------------------------
+
+the original contents of fileY and the resulting contents of
+file0 are compared, and if they are similar enough, they are
+changed to:
+
+------------------------------------------------
+:100644 100644 0123456... 1234567... M fileY
+:100644 100644 0123456... bcd3456... C100 fileY file0
+------------------------------------------------
+
+In both rename and copy detection, the same "extent of changes"
+algorithm used in diffcore-break is used to determine if two
+files are "similar enough", and can be customized to use
+a similarity score different from the default of 50% by giving a
+number after the "-M" or "-C" option (e.g. "-M8" to tell it to use
+8/10 = 80%).
+
+Note that when rename detection is on but both copy and break
+detection are off, rename detection adds a preliminary step that first
+checks if files are moved across directories while keeping their
+filename the same.  If there is a file added to a directory whose
+contents are sufficiently similar to a file with the same name that got
+deleted from a different directory, it will mark them as renames and
+exclude them from the later quadratic step (the one that pairwise
+compares all unmatched files to find the "best" matches, determined by
+the highest content similarity).  So, for example, if a deleted
+docs/ext.txt and an added docs/config/ext.txt are similar enough, they
+will be marked as a rename and prevent an added docs/ext.md that may
+be even more similar to the deleted docs/ext.txt from being considered
+as the rename destination in the later step.  For this reason, the
+preliminary "match same filename" step uses a bit higher threshold to
+mark a file pair as a rename and stop considering other candidates for
+better matches.  At most, one comparison is done per file in this
+preliminary pass; so if there are several remaining ext.txt files
+throughout the directory hierarchy after exact rename detection, this
+preliminary step may be skipped for those files.
+
+Note.  When the "-C" option is used with `--find-copies-harder`
+option, 'git diff-{asterisk}' commands feed unmodified filepairs to
+diffcore mechanism as well as modified ones.  This lets the copy
+detector consider unmodified files as copy source candidates at
+the expense of making it slower.  Without `--find-copies-harder`,
+'git diff-{asterisk}' commands can detect copies only if the file that was
+copied happened to have been modified in the same changeset.
+
+
+diffcore-merge-broken: For Putting Complete Rewrites Back Together
+------------------------------------------------------------------
+
+This transformation is used to merge filepairs broken by
+diffcore-break, and not transformed into rename/copy by
+diffcore-rename, back into a single modification.  This always
+runs when diffcore-break is used.
+
+For the purpose of merging broken filepairs back, it uses a
+different "extent of changes" computation from the ones used by
+diffcore-break and diffcore-rename.  It counts only the deletion
+from the original, and does not count insertion.  If you removed
+only 10 lines from a 100-line document, even if you added 910
+new lines to make a new 1000-line document, you did not do a
+complete rewrite.  diffcore-break breaks such a case in order to
+help diffcore-rename to consider such filepairs as a candidate of
+rename/copy detection, but if filepairs broken that way were not
+matched with other filepairs to create rename/copy, then this
+transformation merges them back into the original
+"modification".
+
+The "extent of changes" parameter can be tweaked from the
+default 80% (that is, unless more than 80% of the original
+material is deleted, the broken pairs are merged back into a
+single modification) by giving a second number to -B option,
+like these:
+
+* -B50/60 (give 50% "break score" to diffcore-break, use 60%
+  for diffcore-merge-broken).
+
+* -B/60 (the same as above, since diffcore-break defaults to 50%).
+
+Note that earlier implementation left a broken pair as separate
+creation and deletion patches.  This was an unnecessary hack, and
+the latest implementation always merges all the broken pairs
+back into modifications, but the resulting patch output is
+formatted differently for easier review in case of such
+a complete rewrite by showing the entire contents of the old version
+prefixed with '-', followed by the entire contents of the new
+version prefixed with '+'.
+
+
+diffcore-pickaxe: For Detecting Addition/Deletion of Specified String
+---------------------------------------------------------------------
+
+This transformation limits the set of filepairs to those that change
+specified strings between the preimage and the postimage in a certain
+way.  -S<block-of-text> and -G<regular-expression> options are used to
+specify different ways these strings are sought.
+
+"-S<block-of-text>" detects filepairs whose preimage and postimage
+have different number of occurrences of the specified block of text.
+By definition, it will not detect in-file moves.  Also, when a
+changeset moves a file wholesale without affecting the interesting
+string, diffcore-rename kicks in as usual, and `-S` omits the filepair
+(since the number of occurrences of that string didn't change in that
+rename-detected filepair).  When used with `--pickaxe-regex`, treat
+the <block-of-text> as an extended POSIX regular expression to match,
+instead of a literal string.
+
+"-G<regular-expression>" (mnemonic: grep) detects filepairs whose
+textual diff has an added or a deleted line that matches the given
+regular expression.  This means that it will detect in-file (or what
+rename-detection considers the same file) moves, which is noise.  The
+implementation runs diff twice and greps, and this can be quite
+expensive.  To speed things up, binary files without textconv filters
+will be ignored.
+
+When `-S` or `-G` are used without `--pickaxe-all`, only filepairs
+that match their respective criterion are kept in the output.  When
+`--pickaxe-all` is used, if even one filepair matches their respective
+criterion in a changeset, the entire changeset is kept.  This behavior
+is designed to make reviewing changes in the context of the whole
+changeset easier.
+
+diffcore-order: For Sorting the Output Based on Filenames
+---------------------------------------------------------
+
+This is used to reorder the filepairs according to the user's
+(or project's) taste, and is controlled by the -O option to the
+'git diff-{asterisk}' commands.
+
+This takes a text file each of whose lines is a shell glob
+pattern.  Filepairs that match a glob pattern on an earlier line
+in the file are output before ones that match a later line, and
+filepairs that do not match any glob pattern are output last.
+
+As an example, a typical orderfile for the core Git probably
+would look like this:
+
+------------------------------------------------
+README
+Makefile
+Documentation
+*.h
+*.c
+t
+------------------------------------------------
+
+diffcore-rotate: For Changing At Which Path Output Starts
+---------------------------------------------------------
+
+This transformation takes one pathname, and rotates the set of
+filepairs so that the filepair for the given pathname comes first,
+optionally discarding the paths that come before it.  This is used
+to implement the `--skip-to` and the `--rotate-to` options.  It is
+an error when the specified pathname is not in the set of filepairs,
+but it is not useful to error out when used with "git log" family of
+commands, because it is unreasonable to expect that a given path
+would be modified by each and every commit shown by the "git log"
+command.  For this reason, when used with "git log", the filepair
+that sorts the same as, or the first one that sorts after, the given
+pathname is where the output starts.
+
+Use of this transformation combined with diffcore-order will produce
+unexpected results, as the input to this transformation is likely
+not sorted when diffcore-order is in effect.
+
+
+SEE ALSO
+--------
+linkgit:git-diff[1],
+linkgit:git-diff-files[1],
+linkgit:git-diff-index[1],
+linkgit:git-diff-tree[1],
+linkgit:git-format-patch[1],
+linkgit:git-log[1],
+linkgit:gitglossary[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/giteveryday.adoc b/Documentation/giteveryday.adoc
new file mode 100644
index 0000000000..6cfdd0e07b
--- /dev/null
+++ b/Documentation/giteveryday.adoc
@@ -0,0 +1,455 @@
+giteveryday(7)
+==============
+
+NAME
+----
+giteveryday - A useful minimum set of commands for Everyday Git
+
+SYNOPSIS
+--------
+
+Everyday Git With 20 Commands Or So
+
+DESCRIPTION
+-----------
+
+Git users can broadly be grouped into four categories for the purposes of
+describing here a small set of useful commands for everyday Git.
+
+*	<<STANDALONE,Individual Developer (Standalone)>> commands are essential
+	for anybody who makes a commit, even for somebody who works alone.
+
+*	If you work with other people, you will need commands listed in
+	the <<PARTICIPANT,Individual Developer (Participant)>> section as well.
+
+*	People who play the <<INTEGRATOR,Integrator>> role need to learn some
+	more commands in addition to the above.
+
+*	<<ADMINISTRATION,Repository Administration>> commands are for system
+	administrators who are responsible for the care and feeding
+	of Git repositories.
+
+
+Individual Developer (Standalone)[[STANDALONE]]
+-----------------------------------------------
+
+A standalone individual developer does not exchange patches with
+other people, and works alone in a single repository, using the
+following commands.
+
+  * linkgit:git-init[1] to create a new repository.
+
+  * linkgit:git-log[1] to see what happened.
+
+  * linkgit:git-switch[1] and linkgit:git-branch[1] to switch
+    branches.
+
+  * linkgit:git-add[1] to manage the index file.
+
+  * linkgit:git-diff[1] and linkgit:git-status[1] to see what
+    you are in the middle of doing.
+
+  * linkgit:git-commit[1] to advance the current branch.
+
+  * linkgit:git-restore[1] to undo changes.
+
+  * linkgit:git-merge[1] to merge between local branches.
+
+  * linkgit:git-rebase[1] to maintain topic branches.
+
+  * linkgit:git-tag[1] to mark a known point.
+
+Examples
+~~~~~~~~
+
+Use a tarball as a starting point for a new repository.::
++
+------------
+$ tar zxf frotz.tar.gz
+$ cd frotz
+$ git init
+$ git add . <1>
+$ git commit -m "import of frotz source tree."
+$ git tag v2.43 <2>
+------------
++
+<1> add everything under the current directory.
+<2> make a lightweight, unannotated tag.
+
+Create a topic branch and develop.::
++
+------------
+$ git switch -c alsa-audio <1>
+$ edit/compile/test
+$ git restore curses/ux_audio_oss.c <2>
+$ git add curses/ux_audio_alsa.c <3>
+$ edit/compile/test
+$ git diff HEAD <4>
+$ git commit -a -s <5>
+$ edit/compile/test
+$ git diff HEAD^ <6>
+$ git commit -a --amend <7>
+$ git switch master <8>
+$ git merge alsa-audio <9>
+$ git log --since='3 days ago' <10>
+$ git log v2.43.. curses/ <11>
+------------
++
+<1> create a new topic branch.
+<2> revert your botched changes in `curses/ux_audio_oss.c`.
+<3> you need to tell Git if you added a new file; removal and
+modification will be caught if you do `git commit -a` later.
+<4> to see what changes you are committing.
+<5> commit everything, as you have tested, with your sign-off.
+<6> look at all your changes including the previous commit.
+<7> amend the previous commit, adding all your new changes,
+using your original message.
+<8> switch to the master branch.
+<9> merge a topic branch into your master branch.
+<10> review commit logs; other forms to limit output can be
+combined and include `-10` (to show up to 10 commits),
+`--until=2005-12-10`, etc.
+<11> view only the changes that touch what's in `curses/`
+directory, since `v2.43` tag.
+
+
+Individual Developer (Participant)[[PARTICIPANT]]
+-------------------------------------------------
+
+A developer working as a participant in a group project needs to
+learn how to communicate with others, and uses these commands in
+addition to the ones needed by a standalone developer.
+
+  * linkgit:git-clone[1] from the upstream to prime your local
+    repository.
+
+  * linkgit:git-pull[1] and linkgit:git-fetch[1] from "origin"
+    to keep up-to-date with the upstream.
+
+  * linkgit:git-push[1] to shared repository, if you adopt CVS
+    style shared repository workflow.
+
+  * linkgit:git-format-patch[1] to prepare e-mail submission, if
+    you adopt Linux kernel-style public forum workflow.
+
+  * linkgit:git-send-email[1] to send your e-mail submission without
+    corruption by your MUA.
+
+  * linkgit:git-request-pull[1] to create a summary of changes
+    for your upstream to pull.
+
+
+Examples
+~~~~~~~~
+
+Clone the upstream and work on it.  Feed changes to upstream.::
++
+------------
+$ git clone git://git.kernel.org/pub/scm/.../torvalds/linux-2.6 my2.6
+$ cd my2.6
+$ git switch -c mine master <1>
+$ edit/compile/test; git commit -a -s <2>
+$ git format-patch master <3>
+$ git send-email --to="person <email@xxxxxxxxxxx>" 00*.patch <4>
+$ git switch master <5>
+$ git pull <6>
+$ git log -p ORIG_HEAD.. arch/i386 include/asm-i386 <7>
+$ git ls-remote --heads http://git.kernel.org/.../jgarzik/libata-dev.git <8>
+$ git pull git://git.kernel.org/pub/.../jgarzik/libata-dev.git ALL <9>
+$ git reset --hard ORIG_HEAD <10>
+$ git gc <11>
+------------
++
+<1> checkout a new branch `mine` from master.
+<2> repeat as needed.
+<3> extract patches from your branch, relative to master,
+<4> and email them.
+<5> return to `master`, ready to see what's new
+<6> `git pull` fetches from `origin` by default and merges into the
+current branch.
+<7> immediately after pulling, look at the changes done upstream
+since last time we checked, only in the
+area we are interested in.
+<8> check the branch names in an external repository (if not known).
+<9> fetch from a specific branch `ALL` from a specific repository
+and merge it.
+<10> revert the pull.
+<11> garbage collect leftover objects from reverted pull.
+
+
+Push into another repository.::
++
+------------
+satellite$ git clone mothership:frotz frotz <1>
+satellite$ cd frotz
+satellite$ git config --get-regexp '^(remote|branch)\.' <2>
+remote.origin.url mothership:frotz
+remote.origin.fetch refs/heads/*:refs/remotes/origin/*
+branch.master.remote origin
+branch.master.merge refs/heads/master
+satellite$ git config remote.origin.push \
+	   +refs/heads/*:refs/remotes/satellite/* <3>
+satellite$ edit/compile/test/commit
+satellite$ git push origin <4>
+
+mothership$ cd frotz
+mothership$ git switch master
+mothership$ git merge satellite/master <5>
+------------
++
+<1> mothership machine has a frotz repository under your home
+directory; clone from it to start a repository on the satellite
+machine.
+<2> clone sets these configuration variables by default.
+It arranges `git pull` to fetch and store the branches of mothership
+machine to local `remotes/origin/*` remote-tracking branches.
+<3> arrange `git push` to push all local branches to
+their corresponding branch of the mothership machine.
+<4> push will stash all our work away on `remotes/satellite/*`
+remote-tracking branches on the mothership machine.  You could use this
+as a back-up method. Likewise, you can pretend that mothership
+"fetched" from you (useful when access is one sided).
+<5> on mothership machine, merge the work done on the satellite
+machine into the master branch.
+
+Branch off of a specific tag.::
++
+------------
+$ git switch -c private2.6.14 v2.6.14 <1>
+$ edit/compile/test; git commit -a
+$ git checkout master
+$ git cherry-pick v2.6.14..private2.6.14 <2>
+------------
++
+<1> create a private branch based on a well known (but somewhat behind)
+tag.
+<2> forward port all changes in `private2.6.14` branch to `master` branch
+without a formal "merging". Or longhand +
+`git format-patch -k -m --stdout v2.6.14..private2.6.14 |
+  git am -3 -k`
+
+An alternate participant submission mechanism is using the
+`git request-pull` or pull-request mechanisms (e.g. as used on
+GitHub (www.github.com) to notify your upstream of your
+contribution.
+
+Integrator[[INTEGRATOR]]
+------------------------
+
+A fairly central person acting as the integrator in a group
+project receives changes made by others, reviews and integrates
+them and publishes the result for others to use, using these
+commands in addition to the ones needed by participants.
+
+This section can also be used by those who respond to `git
+request-pull` or pull-request on GitHub (www.github.com) to
+integrate the work of others into their history. A sub-area
+lieutenant for a repository will act both as a participant and
+as an integrator.
+
+
+  * linkgit:git-am[1] to apply patches e-mailed in from your
+    contributors.
+
+  * linkgit:git-pull[1] to merge from your trusted lieutenants.
+
+  * linkgit:git-format-patch[1] to prepare and send suggested
+    alternative to contributors.
+
+  * linkgit:git-revert[1] to undo botched commits.
+
+  * linkgit:git-push[1] to publish the bleeding edge.
+
+
+Examples
+~~~~~~~~
+
+A typical integrator's Git day.::
++
+------------
+$ git status <1>
+$ git branch --no-merged master <2>
+$ mailx <3>
+& s 2 3 4 5 ./+to-apply
+& s 7 8 ./+hold-linus
+& q
+$ git switch -c topic/one master
+$ git am -3 -i -s ./+to-apply <4>
+$ compile/test
+$ git switch -c hold/linus && git am -3 -i -s ./+hold-linus <5>
+$ git switch topic/one && git rebase master <6>
+$ git switch -C seen next <7>
+$ git merge topic/one topic/two && git merge hold/linus <8>
+$ git switch maint
+$ git cherry-pick master~4 <9>
+$ compile/test
+$ git tag -s -m "GIT 0.99.9x" v0.99.9x <10>
+$ git fetch ko && for branch in master maint next seen <11>
+    do
+	git show-branch ko/$branch $branch <12>
+    done
+$ git push --follow-tags ko <13>
+------------
++
+<1> see what you were in the middle of doing, if anything.
+<2> see which branches haven't been merged into `master` yet.
+Likewise for any other integration branches e.g. `maint`, `next`
+and `seen`.
+<3> read mails, save ones that are applicable, and save others
+that are not quite ready (other mail readers are available).
+<4> apply them, interactively, with your sign-offs.
+<5> create topic branch as needed and apply, again with sign-offs.
+<6> rebase internal topic branch that has not been merged to the
+master or exposed as a part of a stable branch.
+<7> restart `seen` every time from the next.
+<8> and bundle topic branches still cooking.
+<9> backport a critical fix.
+<10> create a signed tag.
+<11> make sure master was not accidentally rewound beyond that
+already pushed out.
+<12> In the output from `git show-branch`, `master` should have
+everything `ko/master` has, and `next` should have
+everything `ko/next` has, etc.
+<13> push out the bleeding edge, together with new tags that point
+into the pushed history.
+
+In this example, the `ko` shorthand points at the Git maintainer's
+repository at kernel.org, and looks like this:
+
+------------
+(in .git/config)
+[remote "ko"]
+	url = kernel.org:/pub/scm/git/git.git
+	fetch = refs/heads/*:refs/remotes/ko/*
+	push = refs/heads/master
+	push = refs/heads/next
+	push = +refs/heads/seen
+	push = refs/heads/maint
+------------
+
+
+Repository Administration[[ADMINISTRATION]]
+-------------------------------------------
+
+A repository administrator uses the following tools to set up
+and maintain access to the repository by developers.
+
+  * linkgit:git-daemon[1] to allow anonymous download from
+    repository.
+
+  * linkgit:git-shell[1] can be used as a 'restricted login shell'
+    for shared central repository users.
+
+  * linkgit:git-http-backend[1] provides a server side implementation
+    of Git-over-HTTP ("Smart http") allowing both fetch and push services.
+
+  * linkgit:gitweb[1] provides a web front-end to Git repositories,
+    which can be set-up using the linkgit:git-instaweb[1] script.
+
+link:howto/update-hook-example.html[update hook howto] has a good
+example of managing a shared central repository.
+
+In addition there are a number of other widely deployed hosting, browsing
+and reviewing solutions such as:
+
+  * gitolite, gerrit code review, cgit and others.
+
+Examples
+~~~~~~~~
+We assume the following in /etc/services::
++
+------------
+$ grep 9418 /etc/services
+git		9418/tcp		# Git Version Control System
+------------
+
+Run git-daemon to serve /pub/scm from inetd.::
++
+------------
+$ grep git /etc/inetd.conf
+git	stream	tcp	nowait	nobody \
+  /usr/bin/git-daemon git-daemon --inetd --export-all /pub/scm
+------------
++
+The actual configuration line should be on one line.
+
+Run git-daemon to serve /pub/scm from xinetd.::
++
+------------
+$ cat /etc/xinetd.d/git-daemon
+# default: off
+# description: The Git server offers access to Git repositories
+service git
+{
+	disable = no
+	type            = UNLISTED
+	port            = 9418
+	socket_type     = stream
+	wait            = no
+	user            = nobody
+	server          = /usr/bin/git-daemon
+	server_args     = --inetd --export-all --base-path=/pub/scm
+	log_on_failure  += USERID
+}
+------------
++
+Check your xinetd(8) documentation and setup, this is from a Fedora system.
+Others might be different.
+
+Give push/pull only access to developers using git-over-ssh.::
+
+e.g. those using:
+`$ git push/pull ssh://host.xz/pub/scm/project`
++
+------------
+$ grep git /etc/passwd <1>
+alice:x:1000:1000::/home/alice:/usr/bin/git-shell
+bob:x:1001:1001::/home/bob:/usr/bin/git-shell
+cindy:x:1002:1002::/home/cindy:/usr/bin/git-shell
+david:x:1003:1003::/home/david:/usr/bin/git-shell
+$ grep git /etc/shells <2>
+/usr/bin/git-shell
+------------
++
+<1> log-in shell is set to /usr/bin/git-shell, which does not
+allow anything but `git push` and `git pull`.  The users require
+ssh access to the machine.
+<2> in many distributions /etc/shells needs to list what is used
+as the login shell.
+
+CVS-style shared repository.::
++
+------------
+$ grep git /etc/group <1>
+git:x:9418:alice,bob,cindy,david
+$ cd /home/devo.git
+$ ls -l <2>
+  lrwxrwxrwx   1 david git    17 Dec  4 22:40 HEAD -> refs/heads/master
+  drwxrwsr-x   2 david git  4096 Dec  4 22:40 branches
+  -rw-rw-r--   1 david git    84 Dec  4 22:40 config
+  -rw-rw-r--   1 david git    58 Dec  4 22:40 description
+  drwxrwsr-x   2 david git  4096 Dec  4 22:40 hooks
+  -rw-rw-r--   1 david git 37504 Dec  4 22:40 index
+  drwxrwsr-x   2 david git  4096 Dec  4 22:40 info
+  drwxrwsr-x   4 david git  4096 Dec  4 22:40 objects
+  drwxrwsr-x   4 david git  4096 Nov  7 14:58 refs
+  drwxrwsr-x   2 david git  4096 Dec  4 22:40 remotes
+$ ls -l hooks/update <3>
+  -r-xr-xr-x   1 david git  3536 Dec  4 22:40 update
+$ cat info/allowed-users <4>
+refs/heads/master	alice\|cindy
+refs/heads/doc-update	bob
+refs/tags/v[0-9]*	david
+------------
++
+<1> place the developers into the same git group.
+<2> and make the shared repository writable by the group.
+<3> use update-hook example by Carl from Documentation/howto/
+for branch policy control.
+<4> alice and cindy can push into master, only bob can push into doc-update.
+david is the release manager and is the only person who can
+create and push version tags.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitfaq.adoc b/Documentation/gitfaq.adoc
new file mode 100644
index 0000000000..f2917d142c
--- /dev/null
+++ b/Documentation/gitfaq.adoc
@@ -0,0 +1,542 @@
+gitfaq(7)
+=========
+
+NAME
+----
+gitfaq - Frequently asked questions about using Git
+
+SYNOPSIS
+--------
+gitfaq
+
+DESCRIPTION
+-----------
+
+The examples in this FAQ assume a standard POSIX shell, like `bash` or `dash`,
+and a user, A U Thor, who has the account `author` on the hosting provider
+`git.example.org`.
+
+Configuration
+-------------
+
+[[user-name]]
+What should I put in `user.name`?::
+	You should put your personal name, generally a form using a given name
+	and family name.  For example, the current maintainer of Git uses "Junio
+	C Hamano".  This will be the name portion that is stored in every commit
+	you make.
++
+This configuration doesn't have any effect on authenticating to remote services;
+for that, see `credential.username` in linkgit:git-config[1].
+
+[[http-postbuffer]]
+What does `http.postBuffer` really do?::
+	This option changes the size of the buffer that Git uses when pushing
+	data to a remote over HTTP or HTTPS.  If the data is larger than this
+	size, libcurl, which handles the HTTP support for Git, will use chunked
+	transfer encoding since it isn't known ahead of time what the size of
+	the pushed data will be.
++
+Leaving this value at the default size is fine unless you know that either the
+remote server or a proxy in the middle doesn't support HTTP/1.1 (which
+introduced the chunked transfer encoding) or is known to be broken with chunked
+data.  This is often (erroneously) suggested as a solution for generic push
+problems, but since almost every server and proxy supports at least HTTP/1.1,
+raising this value usually doesn't solve most push problems.  A server or proxy
+that didn't correctly support HTTP/1.1 and chunked transfer encoding wouldn't be
+that useful on the Internet today, since it would break lots of traffic.
++
+Note that increasing this value will increase the memory used on every relevant
+push that Git does over HTTP or HTTPS, since the entire buffer is allocated
+regardless of whether or not it is all used.  Thus, it's best to leave it at the
+default unless you are sure you need a different value.
+
+[[configure-editor]]
+How do I configure a different editor?::
+	If you haven't specified an editor specifically for Git, it will by default
+	use the editor you've configured using the `VISUAL` or `EDITOR` environment
+	variables, or if neither is specified, the system default (which is usually
+	`vi`).  Since some people find `vi` difficult to use or prefer a different
+	editor, it may be desirable to change the editor used.
++
+If you want to configure a general editor for most programs which need one, you
+can edit your shell configuration (e.g., `~/.bashrc` or `~/.zshenv`) to contain
+a line setting the `EDITOR` or `VISUAL` environment variable to an appropriate
+value.  For example, if you prefer the editor `nano`, then you could write the
+following:
++
+----
+export VISUAL=nano
+----
++
+If you want to configure an editor specifically for Git, you can either set the
+`core.editor` configuration value or the `GIT_EDITOR` environment variable.  You
+can see linkgit:git-var[1] for details on the order in which these options are
+consulted.
++
+Note that in all cases, the editor value will be passed to the shell, so any
+arguments containing spaces should be appropriately quoted.  Additionally, if
+your editor normally detaches from the terminal when invoked, you should specify
+it with an argument that makes it not do that, or else Git will not see any
+changes.  An example of a configuration addressing both of these issues on
+Windows would be the configuration `"C:\Program Files\Vim\gvim.exe" --nofork`,
+which quotes the filename with spaces and specifies the `--nofork` option to
+avoid backgrounding the process.
+
+Credentials
+-----------
+
+[[http-credentials]]
+How do I specify my credentials when pushing over HTTP?::
+	The easiest way to do this is to use a credential helper via the
+	`credential.helper` configuration.  Most systems provide a standard
+	choice to integrate with the system credential manager.  For example,
+	Git for Windows provides the `wincred` credential manager, macOS has the
+	`osxkeychain` credential manager, and Unix systems with a standard
+	desktop environment can use the `libsecret` credential manager.  All of
+	these store credentials in an encrypted store to keep your passwords or
+	tokens secure.
++
+In addition, you can use the `store` credential manager which stores in a file
+in your home directory, or the `cache` credential manager, which does not
+permanently store your credentials, but does prevent you from being prompted for
+them for a certain period of time.
++
+You can also just enter your password when prompted.  While it is possible to
+place the password (which must be percent-encoded) in the URL, this is not
+particularly secure and can lead to accidental exposure of credentials, so it is
+not recommended.
+
+[[http-credentials-environment]]
+How do I read a password or token from an environment variable?::
+	The `credential.helper` configuration option can also take an arbitrary
+	shell command that produces the credential protocol on standard output.
+	This is useful when passing credentials into a container, for example.
++
+Such a shell command can be specified by starting the option value with an
+exclamation point.  If your password or token were stored in the `GIT_TOKEN`,
+you could run the following command to set your credential helper:
++
+----
+$ git config credential.helper \
+	'!f() { echo username=author; echo "password=$GIT_TOKEN"; };f'
+----
+
+[[http-reset-credentials]]
+How do I change the password or token I've saved in my credential manager?::
+	Usually, if the password or token is invalid, Git will erase it and
+	prompt for a new one.  However, there are times when this doesn't always
+	happen.  To change the password or token, you can erase the existing
+	credentials and then Git will prompt for new ones.  To erase
+	credentials, use a syntax like the following (substituting your username
+	and the hostname):
++
+----
+$ echo url=https://author@xxxxxxxxxxxxxxx | git credential reject
+----
+
+[[multiple-accounts-http]]
+How do I use multiple accounts with the same hosting provider using HTTP?::
+	Usually the easiest way to distinguish between these accounts is to use
+	the username in the URL.  For example, if you have the accounts `author`
+	and `committer` on `git.example.org`, you can use the URLs
+	https://author@xxxxxxxxxxxxxxx/org1/project1.git and
+	https://committer@xxxxxxxxxxxxxxx/org2/project2.git.  This way, when you
+	use a credential helper, it will automatically try to look up the
+	correct credentials for your account.  If you already have a remote set
+	up, you can change the URL with something like `git remote set-url
+	origin https://author@xxxxxxxxxxxxxxx/org1/project1.git` (see
+	linkgit:git-remote[1] for details).
+
+[[multiple-accounts-ssh]]
+How do I use multiple accounts with the same hosting provider using SSH?::
+	With most hosting providers that support SSH, a single key pair uniquely
+	identifies a user.  Therefore, to use multiple accounts, it's necessary
+	to create a key pair for each account.  If you're using a reasonably
+	modern OpenSSH version, you can create a new key pair with something
+	like `ssh-keygen -t ed25519 -f ~/.ssh/id_committer`.  You can then
+	register the public key (in this case, `~/.ssh/id_committer.pub`; note
+	the `.pub`) with the hosting provider.
++
+Most hosting providers use a single SSH account for pushing; that is, all users
+push to the `git` account (e.g., `git@xxxxxxxxxxxxxxx`).  If that's the case for
+your provider, you can set up multiple aliases in SSH to make it clear which key
+pair to use.  For example, you could write something like the following in
+`~/.ssh/config`, substituting the proper private key file:
++
+----
+# This is the account for author on git.example.org.
+Host example_author
+	HostName git.example.org
+	User git
+	# This is the key pair registered for author with git.example.org.
+	IdentityFile ~/.ssh/id_author
+	IdentitiesOnly yes
+# This is the account for committer on git.example.org.
+Host example_committer
+	HostName git.example.org
+	User git
+	# This is the key pair registered for committer with git.example.org.
+	IdentityFile ~/.ssh/id_committer
+	IdentitiesOnly yes
+----
++
+Then, you can adjust your push URL to use `git@example_author` or
+`git@example_committer` instead of `git@xxxxxxxxxxx` (e.g., `git remote set-url
+git@example_author:org1/project1.git`).
+
+Transfers
+---------
+
+[[sync-working-tree]]
+How do I sync a working tree across systems?::
+	First, decide whether you want to do this at all.  Git works best when you
+	push or pull your work using the typical `git push` and `git fetch` commands
+	and isn't designed to share a working tree across systems.  This is
+	potentially risky and in some cases can cause repository corruption or data
+	loss.
++
+Usually, doing so will cause `git status` to need to re-read every file in the
+working tree.  Additionally, Git's security model does not permit sharing a
+working tree across untrusted users, so it is only safe to sync a working tree
+if it will only be used by a single user across all machines.
++
+It is important not to use a cloud syncing service to sync any portion of a Git
+repository, since this can cause corruption, such as missing objects, changed
+or added files, broken refs, and a wide variety of other problems.  These
+services tend to sync file by file on a continuous basis and don't understand
+the structure of a Git repository.  This is especially bad if they sync the
+repository in the middle of it being updated, since that is very likely to
+cause incomplete or partial updates and therefore data loss.
++
+An example of the kind of corruption that can occur is conflicts over the state
+of refs, such that both sides end up with different commits on a branch that
+the other doesn't have.  This can result in important objects becoming
+unreferenced and possibly pruned by `git gc`, causing data loss.
++
+Therefore, it's better to push your work to either the other system or a central
+server using the normal push and pull mechanism.  However, this doesn't always
+preserve important data, like stashes, so some people prefer to share a working
+tree across systems.
++
+If you do this, the recommended approach is to use `rsync -a --delete-after`
+(ideally with an encrypted connection such as with `ssh`) on the root of
+repository.  You should ensure several things when you do this:
++
+* If you have additional worktrees or a separate Git directory, they must be
+  synced at the same time as the main working tree and repository.
+* You are comfortable with the destination directory being an exact copy of the
+  source directory, _deleting any data that is already there_.
+* The repository (including all worktrees and the Git directory) is in a
+  quiescent state for the duration of the transfer (that is, no operations of
+  any sort are taking place on it, including background operations like `git
+  gc` and operations invoked by your editor).
++
+Be aware that even with these recommendations, syncing in this way has some risk
+since it bypasses Git's normal integrity checking for repositories, so having
+backups is advised.  You may also wish to do a `git fsck` to verify the
+integrity of your data on the destination system after syncing.
+
+Common Issues
+-------------
+
+[[last-commit-amend]]
+I've made a mistake in the last commit.  How do I change it?::
+	You can make the appropriate change to your working tree, run `git add
+	<file>` or `git rm <file>`, as appropriate, to stage it, and then `git
+	commit --amend`.  Your change will be included in the commit, and you'll
+	be prompted to edit the commit message again; if you wish to use the
+	original message verbatim, you can use the `--no-edit` option to `git
+	commit` in addition, or just save and quit when your editor opens.
+
+[[undo-previous-change]]
+I've made a change with a bug and it's been included in the main branch.  How should I undo it?::
+	The usual way to deal with this is to use `git revert`.  This preserves
+	the history that the original change was made and was a valuable
+	contribution, but also introduces a new commit that undoes those changes
+	because the original had a problem.  The commit message of the revert
+	indicates the commit which was reverted and is usually edited to include
+	an explanation as to why the revert was made.
+
+[[ignore-tracked-files]]
+How do I ignore changes to a tracked file?::
+	Git doesn't provide a way to do this.  The reason is that if Git needs
+	to overwrite this file, such as during a checkout, it doesn't know
+	whether the changes to the file are precious and should be kept, or
+	whether they are irrelevant and can safely be destroyed.  Therefore, it
+	has to take the safe route and always preserve them.
++
+It's tempting to try to use certain features of `git update-index`, namely the
+assume-unchanged and skip-worktree bits, but these don't work properly for this
+purpose and shouldn't be used this way.
++
+If your goal is to modify a configuration file, it can often be helpful to have
+a file checked into the repository which is a template or set of defaults which
+can then be copied alongside and modified as appropriate.  This second, modified
+file is usually ignored to prevent accidentally committing it.
+
+[[files-in-gitignore-are-tracked]]
+I asked Git to ignore various files, yet they are still tracked::
+	A `gitignore` file ensures that certain file(s) which are not
+	tracked by Git remain untracked.  However, sometimes particular
+	file(s) may have been tracked before adding them into the
+	`.gitignore`, hence they still remain tracked.  To untrack and
+	ignore files/patterns, use `git rm --cached <file/pattern>`
+	and add a pattern to `.gitignore` that matches the <file>.
+	See linkgit:gitignore[5] for details.
+
+[[fetching-and-pulling]]
+How do I know if I want to do a fetch or a pull?::
+	A fetch stores a copy of the latest changes from the remote
+	repository, without modifying the working tree or current branch.
+	You can then at your leisure inspect, merge, rebase on top of, or
+	ignore the upstream changes.  A pull consists of a fetch followed
+	immediately by either a merge or rebase.  See linkgit:git-pull[1].
+
+[[proxy]]
+Can I use a proxy with Git?::
+	Yes, Git supports the use of proxies.  Git honors the standard `http_proxy`,
+	`https_proxy`, and `no_proxy` environment variables commonly used on Unix, and
+	it also can be configured with `http.proxy` and similar options for HTTPS (see
+	linkgit:git-config[1]).  The `http.proxy` and related options can be
+	customized on a per-URL pattern basis.  In addition, Git can in theory
+	function normally with transparent proxies that exist on the network.
++
+For SSH, Git can support a proxy using OpenSSH's `ProxyCommand`. Commonly used
+tools include `netcat` and `socat`.  However, they must be configured not to
+exit when seeing EOF on standard input, which usually means that `netcat` will
+require `-q` and `socat` will require a timeout with something like `-t 10`.
+This is required because the way the Git SSH server knows that no more requests
+will be made is an EOF on standard input, but when that happens, the server may
+not have yet processed the final request, so dropping the connection at that
+point would interrupt that request.
++
+An example configuration entry in `~/.ssh/config` with an HTTP proxy might look
+like this:
++
+----
+Host git.example.org
+    User git
+    ProxyCommand socat -t 10 - PROXY:proxy.example.org:%h:%p,proxyport=8080
+----
++
+Note that in all cases, for Git to work properly, the proxy must be completely
+transparent.  The proxy cannot modify, tamper with, or buffer the connection in
+any way, or Git will almost certainly fail to work.  Note that many proxies,
+including many TLS middleboxes, Windows antivirus and firewall programs other
+than Windows Defender and Windows Firewall, and filtering proxies fail to meet
+this standard, and as a result end up breaking Git.  Because of the many
+reports of problems and their poor security history, we recommend against the
+use of these classes of software and devices.
+
+Merging and Rebasing
+--------------------
+
+[[long-running-squash-merge]]
+What kinds of problems can occur when merging long-lived branches with squash merges?::
+	In general, there are a variety of problems that can occur when using squash
+	merges to merge two branches multiple times.  These can include seeing extra
+	commits in `git log` output, with a GUI, or when using the `...` notation to
+	express a range, as well as the possibility of needing to re-resolve conflicts
+	again and again.
++
+When Git does a normal merge between two branches, it considers exactly three
+points: the two branches and a third commit, called the _merge base_, which is
+usually the common ancestor of the commits.  The result of the merge is the sum
+of the changes between the merge base and each head.  When you merge two
+branches with a regular merge commit, this results in a new commit which will
+end up as a merge base when they're merged again, because there is now a new
+common ancestor.  Git doesn't have to consider changes that occurred before the
+merge base, so you don't have to re-resolve any conflicts you resolved before.
++
+When you perform a squash merge, a merge commit isn't created; instead, the
+changes from one side are applied as a regular commit to the other side.  This
+means that the merge base for these branches won't have changed, and so when Git
+goes to perform its next merge, it considers all of the changes that it
+considered the last time plus the new changes.  That means any conflicts may
+need to be re-resolved.  Similarly, anything using the `...` notation in `git
+diff`, `git log`, or a GUI will result in showing all of the changes since the
+original merge base.
++
+As a consequence, if you want to merge two long-lived branches repeatedly, it's
+best to always use a regular merge commit.
+
+[[merge-two-revert-one]]
+If I make a change on two branches but revert it on one, why does the merge of those branches include the change?::
+	By default, when Git does a merge, it uses a strategy called the `ort`
+	strategy, which does a fancy three-way merge.  In such a case, when Git
+	performs the merge, it considers exactly three points: the two heads and a
+	third point, called the _merge base_, which is usually the common ancestor of
+	those commits.  Git does not consider the history or the individual commits
+	that have happened on those branches at all.
++
+As a result, if both sides have a change and one side has reverted that change,
+the result is to include the change.  This is because the code has changed on
+one side and there is no net change on the other, and in this scenario, Git
+adopts the change.
++
+If this is a problem for you, you can do a rebase instead, rebasing the branch
+with the revert onto the other branch.  A rebase in this scenario will revert
+the change, because a rebase applies each individual commit, including the
+revert.  Note that rebases rewrite history, so you should avoid rebasing
+published branches unless you're sure you're comfortable with that.  See the
+NOTES section in linkgit:git-rebase[1] for more details.
+
+Hooks
+-----
+
+[[restrict-with-hooks]]
+How do I use hooks to prevent users from making certain changes?::
+	The only safe place to make these changes is on the remote repository
+	(i.e., the Git server), usually in the `pre-receive` hook or in a
+	continuous integration (CI) system.  These are the locations in which
+	policy can be enforced effectively.
++
+It's common to try to use `pre-commit` hooks (or, for commit messages,
+`commit-msg` hooks) to check these things, which is great if you're working as a
+solo developer and want the tooling to help you.  However, using hooks on a
+developer machine is not effective as a policy control because a user can bypass
+these hooks with `--no-verify` without being noticed (among various other ways).
+Git assumes that the user is in control of their local repositories and doesn't
+try to prevent this or tattle on the user.
++
+In addition, some advanced users find `pre-commit` hooks to be an impediment to
+workflows that use temporary commits to stage work in progress or that create
+fixup commits, so it's better to push these kinds of checks to the server
+anyway.
+
+Cross-Platform Issues
+---------------------
+
+[[windows-text-binary]]
+I'm on Windows and my text files are detected as binary.::
+	Git works best when you store text files as UTF-8.  Many programs on
+	Windows support UTF-8, but some do not and only use the little-endian
+	UTF-16 format, which Git detects as binary.  If you can't use UTF-8 with
+	your programs, you can specify a working tree encoding that indicates
+	which encoding your files should be checked out with, while still
+	storing these files as UTF-8 in the repository.  This allows tools like
+	linkgit:git-diff[1] to work as expected, while still allowing your tools
+	to work.
++
+To do so, you can specify a linkgit:gitattributes[5] pattern with the
+`working-tree-encoding` attribute.  For example, the following pattern sets all
+C files to use UTF-16LE-BOM, which is a common encoding on Windows:
++
+----
+*.c	working-tree-encoding=UTF-16LE-BOM
+----
++
+You will need to run `git add --renormalize` to have this take effect.  Note
+that if you are making these changes on a project that is used across platforms,
+you'll probably want to make it in a per-user configuration file or in the one
+in `$GIT_DIR/info/attributes`, since making it in a `.gitattributes` file in the
+repository will apply to all users of the repository.
++
+See the following entry for information about normalizing line endings as well,
+and see linkgit:gitattributes[5] for more information about attribute files.
+
+[[windows-diff-control-m]]
+I'm on Windows and git diff shows my files as having a `^M` at the end.::
+	By default, Git expects files to be stored with Unix line endings.  As such,
+	the carriage return (`^M`) that is part of a Windows line ending is shown
+	because it is considered to be trailing whitespace.  Git defaults to showing
+	trailing whitespace only on new lines, not existing ones.
++
+You can store the files in the repository with Unix line endings and convert
+them automatically to your platform's line endings.  To do that, set the
+configuration option `core.eol` to `native` and see
+<<recommended-storage-settings,the question on recommended storage settings>>
+for information about how to configure files as text or binary.
++
+You can also control this behavior with the `core.whitespace` setting if you
+don't wish to remove the carriage returns from your line endings.
+
+[[always-modified-files-case]]
+Why do I have a file that's always modified?::
+	Internally, Git always stores file names as sequences of bytes and doesn't
+	perform any encoding or case folding.  However, Windows and macOS by default
+	both perform case folding on file names.  As a result, it's possible to end up
+	with multiple files or directories whose names differ only in case.  Git can
+	handle this just fine, but the file system can store only one of these files,
+	so when Git reads the other file to see its contents, it looks modified.
++
+It's best to remove one of the files such that you only have one file.  You can
+do this with commands like the following (assuming two files `AFile.txt` and
+`afile.txt`) on an otherwise clean working tree:
++
+----
+$ git rm --cached AFile.txt
+$ git commit -m 'Remove files conflicting in case'
+$ git checkout .
+----
++
+This avoids touching the disk, but removes the additional file.  Your project
+may prefer to adopt a naming convention, such as all-lowercase names, to avoid
+this problem from occurring again; such a convention can be checked using a
+`pre-receive` hook or as part of a continuous integration (CI) system.
++
+It is also possible for perpetually modified files to occur on any platform if a
+smudge or clean filter is in use on your system but a file was previously
+committed without running the smudge or clean filter.  To fix this, run the
+following on an otherwise clean working tree:
++
+----
+$ git add --renormalize .
+----
+
+[[recommended-storage-settings]]
+What's the recommended way to store files in Git?::
+	While Git can store and handle any file of any type, there are some
+	settings that work better than others.  In general, we recommend that
+	text files be stored in UTF-8 without a byte-order mark (BOM) with LF
+	(Unix-style) endings.  We also recommend the use of UTF-8 (again,
+	without BOM) in commit messages.  These are the settings that work best
+	across platforms and with tools such as `git diff` and `git merge`.
++
+Additionally, if you have a choice between storage formats that are text based
+or non-text based, we recommend storing files in the text format and, if
+necessary, transforming them into the other format.  For example, a text-based
+SQL dump with one record per line will work much better for diffing and merging
+than an actual database file.  Similarly, text-based formats such as Markdown
+and AsciiDoc will work better than binary formats such as Microsoft Word and
+PDF.
++
+Similarly, storing binary dependencies (e.g., shared libraries or JAR files) or
+build products in the repository is generally not recommended.  Dependencies and
+build products are best stored on an artifact or package server with only
+references, URLs, and hashes stored in the repository.
++
+We also recommend setting a linkgit:gitattributes[5] file to explicitly mark
+which files are text and which are binary.  If you want Git to guess, you can
+set the attribute `text=auto`.
++
+With text files, Git will generally ensure that LF endings are used in the
+repository.  The `core.autocrlf` and `core.eol` configuration variables specify
+what line-ending convention is followed when any text file is checked out.  You
+can also use the `eol` attribute (e.g., `eol=crlf`) to override which files get
+what line-ending treatment.
++
+For example, generally shell files must have LF endings and batch files must
+have CRLF endings, so the following might be appropriate in some projects:
++
+----
+# By default, guess.
+*	text=auto
+# Mark all C files as text.
+*.c	text
+# Ensure all shell files have LF endings and all batch files have CRLF
+# endings in the working tree and both have LF in the repo.
+*.sh text eol=lf
+*.bat text eol=crlf
+# Mark all JPEG files as binary.
+*.jpg	binary
+----
++
+These settings help tools pick the right format for output such as patches and
+result in files being checked out in the appropriate line ending for the
+platform.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitformat-bundle.adoc b/Documentation/gitformat-bundle.adoc
new file mode 100644
index 0000000000..1b75cf71ce
--- /dev/null
+++ b/Documentation/gitformat-bundle.adoc
@@ -0,0 +1,111 @@
+gitformat-bundle(5)
+===================
+
+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.
+
+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
+linkgit:gitprotocol-common[5] for the details.
+
+A v2 bundle looks like this:
+
+----
+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
+----
+
+A v3 bundle looks like this:
+
+----
+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
+----
+
+
+SEMANTICS
+---------
+
+A Git bundle consists of several parts.
+
+* "Capabilities", which are only in the v3 format, indicate functionality that
+	the bundle requires to be read properly.
+
+* "Prerequisites" list 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.
+
+* "References" record the tips of the history graph, iow, what the reader of the
+  bundle CAN "git fetch" from it.
+
+* "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.
+
+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 shallow clones and Git bundles
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Note that the prerequisites do 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
+------------
+
+Because there is no opportunity for negotiation, unknown capabilities cause 'git
+bundle' to abort.
+
+* `object-format` specifies the hash algorithm in use, and can take the same
+  values as the `extensions.objectFormat` configuration value.
+
+* `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/Documentation/gitformat-chunk.adoc b/Documentation/gitformat-chunk.adoc
new file mode 100644
index 0000000000..3315df6201
--- /dev/null
+++ b/Documentation/gitformat-chunk.adoc
@@ -0,0 +1,133 @@
+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
+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
+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.
+
+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:
+
+  | Chunk ID (4 bytes) | Chunk Offset (8 bytes) |
+  |--------------------|------------------------|
+  | ID[0]              | OFFSET[0]              |
+  | ...                | ...                    |
+  | ID[C]              | OFFSET[C]              |
+  | 0x0000             | OFFSET[C+1]            |
+
+Each row consists of a 4-byte chunk identifier (ID) and an 8-byte offset.
+Each integer is stored in network-byte order.
+
+The chunk identifier `ID[i]` is a label for the data stored within this
+file from `OFFSET[i]` (inclusive) to `OFFSET[i+1]` (exclusive). Thus, the
+size of the `i`th chunk is equal to the difference between `OFFSET[i+1]`
+and `OFFSET[i]`. This requires that the chunk data appears contiguously
+in the same order as the table of contents.
+
+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.
+
+Note: The chunk-based format expects that the file contains _at least_ a
+trailing hash after `OFFSET[C+1]`.
+
+Functions for working with chunk-based file formats are declared in
+`chunk-format.h`. Using these methods provide extra checks that assist
+developers when creating new file formats.
+
+Writing chunk-based file formats
+--------------------------------
+
+To write a chunk-based file format, create a `struct chunkfile` by
+calling `init_chunkfile()` and pass a `struct hashfile` pointer. The
+caller is responsible for opening the `hashfile` and writing header
+information so the file format is identifiable before the chunk-based
+format begins.
+
+Then, call `add_chunk()` for each chunk that is intended for writing. This
+populates the `chunkfile` with information about the order and size of
+each chunk to write. Provide a `chunk_write_fn` function pointer to
+perform the write of the chunk data upon request.
+
+Call `write_chunkfile()` to write the table of contents to the `hashfile`
+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.
+
+Finally, call `free_chunkfile()` to clear the `struct chunkfile` data. The
+caller is responsible for finalizing the `hashfile` by writing the trailing
+hash and closing the file.
+
+Reading chunk-based file formats
+--------------------------------
+
+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.
+
+Initialize a `struct chunkfile` pointer with `init_chunkfile(NULL)`.
+
+After reading the header information from the beginning of the file,
+including the chunk count, call `read_table_of_contents()` to populate
+the `struct chunkfile` with the list of chunks, their offsets, and their
+sizes.
+
+Extract the data information for each chunk using `pair_chunk()` or
+`read_chunk()`:
+
+* `pair_chunk()` assigns a given pointer with the location inside the
+  memory-mapped file corresponding to that chunk's offset. If the chunk
+  does not exist, then the pointer is not modified.
+
+* `read_chunk()` takes a `chunk_read_fn` 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.
+
+After calling these methods, call `free_chunkfile()` to clear the
+`struct chunkfile` 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.
+
+Examples
+--------
+
+These file formats use the chunk-format API, and can be used as examples
+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
+  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
+  the multi-pack-index file format section of linkgit:gitformat-pack[5].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitformat-commit-graph.adoc b/Documentation/gitformat-commit-graph.adoc
new file mode 100644
index 0000000000..14d1631234
--- /dev/null
+++ b/Documentation/gitformat-commit-graph.adoc
@@ -0,0 +1,186 @@
+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:
+
+- The generation number of the commit.
+
+- The root tree OID.
+
+- The commit date.
+
+- The parents of the commit, stored using positional references within
+  the graph file.
+
+- The Bloom filter of the commit carrying the paths that were changed between
+  the commit and its first parent, if requested.
+
+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 << 30) + (1 << 29) + (1 << 28) - 1 (around 1.8 billion) commits.
+
+== Commit-graph files have the following format:
+
+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.
+
+All multi-byte numbers are in network byte order.
+
+=== HEADER:
+
+  4-byte signature:
+      The signature is: {'C', 'G', 'P', 'H'}
+
+  1-byte version number:
+      Currently, the only valid version is 1.
+
+  1-byte Hash Version
+      We infer the hash length (H) from this value:
+	1 => SHA-1
+	2 => 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.
+
+  1-byte number (C) of "chunks"
+
+  1-byte number (B) of base commit-graphs
+      We infer the length (H*B) of the Base Graphs chunk
+      from this value.
+
+=== 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.
+      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.
+
+  The CHUNK LOOKUP matches the table of contents from
+  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:
+
+==== 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)
+      The OIDs for all commits in the graph, sorted in ascending order.
+
+====  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
+      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.
+    * 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.
+
+==== 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,
+      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.
+    * 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.
+
+==== 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.
+    * Generation Data Overflow chunk is present only when Generation Data
+      chunk is present and at least one corrected commit date offset cannot
+      be stored within 31 bits.
+
+==== 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
+      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.
+
+==== 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]
+    * It starts with header consisting of three unsigned 32-bit integers:
+      - Version of the hash algorithm being used. We currently support
+	value 2 which corresponds to the 32-bit version of the murmur3 hash
+	implemented exactly as described in
+	https://en.wikipedia.org/wiki/MurmurHash#Algorithm and the double
+	hashing technique using seed values 0x293ae76f and 0x7e646e2 as
+	described in https://doi.org/10.1007/978-3-540-30494-4_26 "Bloom Filters
+	in Probabilistic Verification". Version 1 Bloom filters have a bug that appears
+	when char is signed and the repository has path names that have characters >=
+	0x80; Git supports reading and writing them, but this ability will be removed
+	in a future version of Git.
+      - 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.
+      - The minimum number of bits 'b' per entry in the Bloom filter. If the filter
+	      contains 'n' entries, then the filter size is the minimum number of 64-bit
+	      words that contain n*b bits.
+    * The rest of the chunk is the concatenation of all the computed Bloom
+      filters for the commits in lexicographic order.
+    * 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.
+    * The BDAT chunk is present if and only if BIDX is present.
+
+==== 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:
+
+	H-byte HASH-checksum of all of the above.
+
+== Historical Notes:
+
+The Generation Data (GDA2) and Generation Data Overflow (GDO2) chunks have
+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/Documentation/gitformat-index.adoc b/Documentation/gitformat-index.adoc
new file mode 100644
index 0000000000..145cace1fe
--- /dev/null
+++ b/Documentation/gitformat-index.adoc
@@ -0,0 +1,424 @@
+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
+
+  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.
+
+   - A 12-byte header consisting of
+
+     4-byte signature:
+       The signature is { 'D', 'I', 'R', 'C' } (stands for "dircache")
+
+     4-byte version number:
+       The current supported versions are 2, 3 and 4.
+
+     32-bit number of index entries.
+
+   - A number of sorted index entries (see below).
+
+   - Extensions
+
+     Extensions are identified by signature. Optional extensions can
+     be ignored if Git does not understand them.
+
+     4-byte extension signature. If the first byte is 'A'..'Z' the
+     extension is optional and can be ignored.
+
+     32-bit size of the extension
+
+     Extension data
+
+   - Hash checksum over the content of the index file before this checksum.
+
+== Index entry
+
+  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.
+
+  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.
+
+  32-bit ctime seconds, the last time a file's metadata changed
+    this is stat(2) data
+
+  32-bit ctime nanosecond fractions
+    this is stat(2) data
+
+  32-bit mtime seconds, the last time a file's data changed
+    this is stat(2) data
+
+  32-bit mtime nanosecond fractions
+    this is stat(2) data
+
+  32-bit dev
+    this is stat(2) data
+
+  32-bit ino
+    this is stat(2) data
+
+  32-bit mode, split into (high to low bits)
+
+    16-bit unused, must be zero
+
+    4-bit object type
+      valid values in binary are 1000 (regular file), 1010 (symbolic link)
+      and 1110 (gitlink)
+
+    3-bit unused, must be zero
+
+    9-bit unix permission. Only 0755 and 0644 are valid for regular files.
+    Symbolic links and gitlinks have value 0 in this field.
+
+  32-bit uid
+    this is stat(2) data
+
+  32-bit gid
+    this is stat(2) data
+
+  32-bit file size
+    This is the on-disk size from stat(2), truncated to 32-bit.
+
+  Object name for the represented object
+
+  A 16-bit 'flags' field split into (high to low bits)
+
+    1-bit assume-valid flag
+
+    1-bit extended flag (must be zero in version 2)
+
+    2-bit stage (during merge)
+
+    12-bit name length if the length is less than 0xFFF; otherwise 0xFFF
+    is stored in this field.
+
+  (Version 3 or later) A 16-bit field, only applicable if the
+  "extended flag" above is 1, split into (high to low bits).
+
+    1-bit reserved for future
+
+    1-bit skip-worktree flag (used by sparse checkout)
+
+    1-bit intent-to-add flag (used by "git add -N")
+
+    13-bit unused, must be zero
+
+  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.
+
+    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).
+
+  (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.
+
+  1-8 nul bytes as necessary to pad the entry to a multiple of eight bytes
+  while keeping the name NUL-terminated.
+
+  (Version 4) In version 4, the padding after the pathname does not
+  exist.
+
+  Interpretation of index entries in split index mode is completely
+  different. See below for details.
+
+== Extensions
+
+=== Cache tree
+
+  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.
+
+  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.
+
+  The extension tracks the full directory structure in the cache tree
+  extension, but this is generally smaller than the full cache entry list.
+
+  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.
+
+  The signature for this extension is { 'T', 'R', 'E', 'E' }.
+
+  A series of entries fill the entire extension; each of which
+  consists of:
+
+  - NUL-terminated path component (relative to its parent directory);
+
+  - ASCII decimal number of entries in the index that is covered by the
+    tree this entry represents (entry_count);
+
+  - A space (ASCII 32);
+
+  - ASCII decimal number that represents the number of subtrees this
+    tree has;
+
+  - A newline (ASCII 10); and
+
+  - Object name for the object that would result from writing this span
+    of index as a tree.
+
+  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.
+
+  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.
+
+=== Resolve undo
+
+  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.
+
+  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.
+
+  The signature for this extension is { 'R', 'E', 'U', 'C' }.
+
+  A series of entries fill the entire extension; each of which
+  consists of:
+
+  - NUL-terminated pathname the entry describes (relative to the root of
+    the repository, i.e. full pathname);
+
+  - 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
+
+  - At most three object names of the entry in stages from 1 to 3
+    (nothing is written for a missing stage).
+
+=== Split index
+
+  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.
+
+  The signature for this extension is { 'l', 'i', 'n', 'k' }.
+
+  The extension consists of:
+
+  - Hash of the shared index file. The shared index file path
+    is $GIT_DIR/sharedindex.<hash>. If all bits are zero, the
+    index does not require a shared index file.
+
+  - 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's best to just mark
+    entries for removal, then do a mass deletion after replacement.
+
+  - 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.
+
+  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.
+
+== Untracked cache
+
+  Untracked cache saves the untracked file list and necessary data to
+  verify the cache. The signature for this extension is { 'U', 'N',
+  'T', 'R' }.
+
+  The extension starts with
+
+  - 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.
+
+  - Stat data of $GIT_DIR/info/exclude. See "Index entry" section from
+    ctime field until "file size".
+
+  - Stat data of core.excludesFile
+
+  - 32-bit dir_flags (see struct dir_struct)
+
+  - Hash of $GIT_DIR/info/exclude. A null hash means the file
+    does not exist.
+
+  - Hash of core.excludesFile. A null hash means the file does
+    not exist.
+
+  - NUL-terminated string of per-dir exclude file name. This usually
+    is ".gitignore".
+
+  - The number of following directory blocks, variable width
+    encoding. If this number is zero, the extension ends here with a
+    following NUL.
+
+  - A number of directory blocks in depth-first-search order, each
+    consists of
+
+    - The number of untracked entries, variable width encoding.
+
+    - The number of sub-directory blocks, variable width encoding.
+
+    - The directory name terminated by NUL.
+
+    - A number of untracked file/dir names terminated by NUL.
+
+The remaining data of each directory block is grouped by type:
+
+  - An ewah bitmap, the n-th bit marks whether the n-th directory has
+    valid untracked cache entries.
+
+  - An ewah bitmap, the n-th bit records "check-only" bit of
+    read_directory_recursive() for the n-th directory.
+
+  - 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.
+
+  - An array of stat data. The n-th data corresponds with the n-th
+    "one" bit in the previous ewah bitmap.
+
+  - An array of hashes. The n-th hash corresponds with the n-th "one" bit
+    in the previous ewah bitmap.
+
+  - One NUL.
+
+== File System Monitor cache
+
+  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' }.
+
+  The extension starts with
+
+  - 32-bit version number: the current supported versions are 1 and 2.
+
+  - (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.
+
+  - (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.
+
+  - 32-bit bitmap size: the size of the CE_FSMONITOR_VALID bitmap.
+
+  - An ewah bitmap, the n-th bit indicates whether the n-th index entry
+    is not CE_FSMONITOR_VALID.
+
+== End of Index Entry
+
+  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.
+
+  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' }.
+
+  The extension consists of:
+
+  - 32-bit offset to the end of the index entries
+
+  - 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:
+
+	Hash("TREE" + <binary-representation-of-N> +
+		"REUC" + <binary-representation-of-M>)
+
+== Index Entry Offset Table
+
+  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' }.
+
+  The extension consists of:
+
+  - 32-bit version (currently 1)
+
+  - A number of index offset entries each consisting of:
+
+    - 32-bit offset from the beginning of the file to the first cache entry
+	in this block of entries.
+
+    - 32-bit count of cache entries in this block
+
+== Sparse Directory Entries
+
+  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.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitformat-pack.adoc b/Documentation/gitformat-pack.adoc
new file mode 100644
index 0000000000..d6ae229be5
--- /dev/null
+++ b/Documentation/gitformat-pack.adoc
@@ -0,0 +1,681 @@
+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 how Git stores most of its primary repository
+data. Over the lifetime of 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
+
+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.
+
+== pack-*.pack files have the following format:
+
+   - A header appears at the beginning and consists of the following:
+
+     4-byte signature:
+         The signature is: {'P', 'A', 'C', 'K'}
+
+     4-byte version number (network byte order):
+	 Git currently accepts version number 2 or 3 but
+         generates version 2 only.
+
+     4-byte number of objects contained in the pack (network byte order)
+
+     Observation: we cannot have more than 4G versions ;-) and
+     more than 4G objects in a pack.
+
+   - The header is followed by a number of object entries, each of
+     which looks like this:
+
+     (undeltified representation)
+     n-byte type and length (3-bit type, (n-1)*7+4-bit length)
+     compressed data
+
+     (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
+
+     Observation: the length of each object is encoded in a variable
+     length format and is not constrained to 32-bit or anything.
+
+  - The trailer records a pack checksum of all of the above.
+
+=== Object types
+
+Valid object types are:
+
+- OBJ_COMMIT (1)
+- OBJ_TREE (2)
+- OBJ_BLOB (3)
+- OBJ_TAG (4)
+- OBJ_OFS_DELTA (6)
+- OBJ_REF_DELTA (7)
+
+Type 5 is reserved for future expansion. Type 0 is invalid.
+
+=== Size encoding
+
+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.
+
+This size encoding should not be confused with the "offset encoding",
+which is also used in this document.
+
+=== Deltified representation
+
+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.
+
+Both ofs-delta and ref-delta store the "delta" to be applied to
+another object (called 'base object') 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.
+
+The base object could also be deltified if it'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.
+
+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's complete. There are two
+supported instructions so far: one for copying a byte range from the
+source object and one for inserting new data embedded in the
+instruction itself.
+
+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).
+
+==== Instruction to copy from base object
+
+  +----------+---------+---------+---------+---------+-------+-------+-------+
+  | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |
+  +----------+---------+---------+---------+---------+-------+-------+-------+
+
+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.
+
+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 determine 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.
+
+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's right next to offset1.
+
+  +----------+---------+---------+
+  | 10000101 | offset1 | offset3 |
+  +----------+---------+---------+
+
+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.
+
+==== Instruction to add new data
+
+  +----------+============+
+  | 0xxxxxxx |    data    |
+  +----------+============+
+
+This is the instruction to construct the target object without the base
+object. The following data is appended to the target object. The first
+seven bits of the first octet determine the size of data in
+bytes. The size must be non-zero.
+
+==== Reserved instruction
+
+  +----------+============
+  | 00000000 |
+  +----------+============
+
+This is the instruction reserved for future expansion.
+
+== Original (version 1) pack-*.idx files have the following format:
+
+  - 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
+    'first-level fan-out' table.
+
+  - The header is followed by sorted 24-byte entries, one entry
+    per object in the pack.  Each entry is:
+
+    4-byte network byte order integer, recording where the
+    object is stored in the packfile as the offset from the
+    beginning.
+
+    one object name of the appropriate size.
+
+  - The file is concluded with a trailer:
+
+    A copy of the pack checksum at the end of the corresponding
+    packfile.
+
+    Index checksum of all of the above.
+
+Pack Idx file:
+
+	--  +--------------------------------+
+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 | | |
+	    +--------------------------------+<+ |
+	  .-| offset                         |   |
+	  | | object name 01XXXXXXXXXXXXXXXX |   |
+	  | +--------------------------------+   |
+	  | | offset                         |   |
+	  | | object name 01XXXXXXXXXXXXXXXX |   |
+	  | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   |
+	  | | offset                         |   |
+	  | | object name FFXXXXXXXXXXXXXXXX |   |
+	--| +--------------------------------+<--+
+trailer	  | | packfile checksum              |
+	  | +--------------------------------+
+	  | | idxfile checksum               |
+	  | +--------------------------------+
+          .-------.
+                  |
+Pack file entry: <+
+
+     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.
+
+     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 >= 2 adding 2^7 + 2^14 + ... + 2^(7*(n-1))
+	  to the result.
+
+
+
+== Version 2 pack-*.idx files support packs larger than 4 GiB, and
+   have some other reorganizations.  They have the format:
+
+  - A 4-byte magic number '\377tOc' which is an unreasonable
+    fanout[0] value.
+
+  - A 4-byte version number (= 2)
+
+  - A 256-entry fan-out table just like v1.
+
+  - 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.
+
+  - 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.
+
+  - 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.
+
+  - 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.
+
+  - The same trailer as a v1 pack file:
+
+    A copy of the pack checksum at the end of the
+    corresponding packfile.
+
+    Index checksum of all of the above.
+
+== pack-*.rev files have the format:
+
+  - A 4-byte magic number '0x52494458' ('RIDX').
+
+  - A 4-byte version identifier (= 1).
+
+  - A 4-byte hash function identifier (= 1 for SHA-1, 2 for SHA-256).
+
+  - 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.
+
+  - A trailer, containing a:
+
+    checksum of the corresponding packfile, and
+
+    a checksum of all of the above.
+
+All 4-byte numbers are in network order.
+
+== pack-*.mtimes files have the format:
+
+All 4-byte numbers are in network byte order.
+
+  - A 4-byte magic number '0x4d544d45' ('MTME').
+
+  - A 4-byte version identifier (= 1).
+
+  - A 4-byte hash function identifier (= 1 for SHA-1, 2 for SHA-256).
+
+  - 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.
+
+  - 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).
+
+== multi-pack-index (MIDX) files have the following format:
+
+The multi-pack-index files refer to multiple pack-files and loose objects.
+
+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.
+
+All 4-byte numbers are in network order.
+
+HEADER:
+
+	4-byte signature:
+	    The signature is: {'M', 'I', 'D', 'X'}
+
+	1-byte version number:
+	    Git only writes or recognizes version 1.
+
+	1-byte Object Id Version
+	    We infer the length of object IDs (OIDs) from this value:
+		1 => SHA-1
+		2 => 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.
+
+	1-byte number of "chunks"
+
+	1-byte number of base multi-pack-index files:
+	    This value is currently always zero.
+
+	4-byte number of pack files
+
+CHUNK LOOKUP:
+
+	(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.)
+
+	The CHUNK LOOKUP matches the table of contents from
+	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:
+
+	Packfile Names (ID: {'P', 'N', 'A', 'M'})
+	    Store the names of packfiles as a sequence of NUL-terminated
+	    strings. There is no extra padding between the filenames,
+	    and they are listed in lexicographic order. The chunk itself
+	    is padded at the end with between 0 and 3 NUL bytes to make the
+	    chunk size a multiple of 4 bytes.
+
+	Bitmapped Packfiles (ID: {'B', 'T', 'M', 'P'})
+	    Stores a table of two 4-byte unsigned integers in network order.
+	    Each table entry corresponds to a single pack (in the order that
+	    they appear above in the `PNAM` chunk). The values for each table
+	    entry are as follows:
+	    - The first bit position (in pseudo-pack order, see below) to
+	      contain an object from that pack.
+	    - The number of bits whose objects are selected from that pack.
+
+	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.
+
+	OID Lookup (ID: {'O', 'I', 'D', 'L'})
+	    The OIDs for all objects in the MIDX are stored in lexicographic
+	    order in this chunk.
+
+	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.
+
+	[Optional] Object Large Offsets (ID: {'L', 'O', 'F', 'F'})
+	    8-byte offsets into large packfiles.
+
+	[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.
+
+TRAILER:
+
+	Index checksum of the above contents.
+
+== multi-pack-index reverse indexes
+
+Similar to the pack-based reverse index, the multi-pack index can also
+be used to generate a reverse index.
+
+Instead of mapping between offset, pack-, and index position, this
+reverse index maps between an object's position within the MIDX, and
+that object'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).
+
+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.
+
+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.)
+
+So we'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:
+
+    |a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
+
+where the ordering of the packs is defined by the MIDX's pack list,
+and then the ordering of objects within each pack is the same as the
+order in the actual packfile.
+
+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's a catch. Objects may be duplicated between packs, in
+which case the MIDX only stores one pointer to the object (and thus we'd
+want only one slot in the bitmap).
+
+Callers could handle duplicates themselves by reading objects in order
+of their bit-position, but that'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's reuse it for the MIDX's pseudo-pack,
+too.
+
+Objects from the MIDX are ordered as follows to string together the
+pseudo-pack. Let `pack(o)` return the pack from which `o` was selected
+by the MIDX, and define an ordering of packs based on their numeric ID
+(as stored by the MIDX). Let `offset(o)` return the object offset of `o`
+within `pack(o)`. Then, compare `o1` and `o2` as follows:
+
+  - If one of `pack(o1)` and `pack(o2)` is preferred and the other
+    is not, then the preferred one sorts first.
++
+(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).
+
+  - If `pack(o1) ≠ pack(o2)`, then sort the two objects in descending
+    order based on the pack ID.
+
+  - Otherwise, `pack(o1) = pack(o2)`, and the objects are sorted in
+    pack-order (i.e., `o1` sorts ahead of `o2` exactly when `offset(o1)
+    < offset(o2)`).
+
+In short, a MIDX'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).
+
+The MIDX's reverse index is stored in the optional 'RIDX' chunk within
+the MIDX itself.
+
+=== `BTMP` chunk
+
+The Bitmapped Packfiles (`BTMP`) chunk encodes additional information
+about the objects in the multi-pack index's reachability bitmap. Recall
+that objects from the MIDX are arranged in "pseudo-pack" order (see
+above) for reachability bitmaps.
+
+From the example above, suppose we have packs "a", "b", and "c", with
+10, 15, and 20 objects, respectively. In pseudo-pack order, those would
+be arranged as follows:
+
+    |a,0|a,1|...|a,9|b,0|b,1|...|b,14|c,0|c,1|...|c,19|
+
+When working with single-pack bitmaps (or, equivalently, multi-pack
+reachability bitmaps with a preferred pack), linkgit:git-pack-objects[1]
+performs ``verbatim'' reuse, attempting to reuse chunks of the bitmapped
+or preferred packfile instead of adding objects to the packing list.
+
+When a chunk of bytes is reused from an existing pack, any objects
+contained therein do not need to be added to the packing list, saving
+memory and CPU time. But a chunk from an existing packfile can only be
+reused when the following conditions are met:
+
+  - The chunk contains only objects which were requested by the caller
+    (i.e. does not contain any objects which the caller didn't ask for
+    explicitly or implicitly).
+
+  - All objects stored in non-thin packs as offset- or reference-deltas
+    also include their base object in the resulting pack.
+
+The `BTMP` chunk encodes the necessary information in order to implement
+multi-pack reuse over a set of packfiles as described above.
+Specifically, the `BTMP` chunk encodes three pieces of information (all
+32-bit unsigned integers in network byte-order) for each packfile `p`
+that is stored in the MIDX, as follows:
+
+`bitmap_pos`:: The first bit position (in pseudo-pack order) in the
+  multi-pack index's reachability bitmap occupied by an object from `p`.
+
+`bitmap_nr`:: The number of bit positions (including the one at
+  `bitmap_pos`) that encode objects from that pack `p`.
+
+For example, the `BTMP` chunk corresponding to the above example (with
+packs ``a'', ``b'', and ``c'') would look like:
+
+[cols="1,2,2"]
+|===
+| |`bitmap_pos` |`bitmap_nr`
+
+|packfile ``a''
+|`0`
+|`10`
+
+|packfile ``b''
+|`10`
+|`15`
+
+|packfile ``c''
+|`25`
+|`20`
+|===
+
+With this information in place, we can treat each packfile as
+individually reusable in the same fashion as verbatim pack reuse is
+performed on individual packs prior to the implementation of the `BTMP`
+chunk.
+
+== 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.
+
+=== Alternatives
+
+Notable alternatives to this design include:
+
+  - The location of the per-object mtime data.
+
+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.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitformat-signature.adoc b/Documentation/gitformat-signature.adoc
new file mode 100644
index 0000000000..d4d3a31f03
--- /dev/null
+++ b/Documentation/gitformat-signature.adoc
@@ -0,0 +1,229 @@
+gitformat-signature(5)
+======================
+
+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
+is about to create an object or transaction determines a payload from that,
+calls an external program to obtain a detached signature for the payload
+(`gpg -bsa` in the case of PGP signatures), and embeds the signature into the
+object or transaction.
+
+Signatures begin with an "ASCII Armor" header line and end with a tail line,
+which differ depending on signature type (as selected by `gpg.format`, see
+linkgit:git-config[1]). These are, for `gpg.format` values:
+
+`gpg` (PGP)::
+	`-----BEGIN PGP SIGNATURE-----` and `-----END PGP SIGNATURE-----`.
+	Or, if gpg is told to produce RFC1991 signatures,
+	`-----BEGIN PGP MESSAGE-----` and `-----END PGP MESSAGE-----`
+
+`ssh` (SSH)::
+	`-----BEGIN SSH SIGNATURE-----` and `-----END SSH SIGNATURE-----`
+
+`x509` (X.509)::
+	`-----BEGIN SIGNED MESSAGE-----` and `-----END SIGNED MESSAGE-----`
+
+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.
+
+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 `$` 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.
+
+The signed payload and the way the signature is embedded depends
+on the type of the object resp. transaction.
+
+== Tag signatures
+
+- created by: `git tag -s`
+- payload: annotated tag object
+- embedding: append the signature to the unsigned tag object
+- example: tag `signedtag` with subject `signed tag`
+
+----
+object 04b871796dc0420f8e7561a895b52484b701d51a
+type commit
+tag signedtag
+tagger C O Mitter <committer@xxxxxxxxxxx> 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-----
+----
+
+- verify with: `git verify-tag [-v]` or `git tag -v`
+
+----
+gpg: Signature made Wed Jun 15 10:56:46 2016 CEST using RSA key ID B7227189
+gpg: Good signature from "Eris Discordia <discord@xxxxxxxxxxx>"
+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 <committer@xxxxxxxxxxx> 1465981006 +0000
+
+signed tag
+
+signed tag message body
+----
+
+== Commit signatures
+
+- created by: `git commit -S`
+- payload: commit object
+- embedding: header entry `gpgsig`
+  (content is preceded by a space)
+- example: commit with subject `signed commit`
+
+----
+tree eebfed94e75e7760540d1485c740902590a00332
+parent 04b871796dc0420f8e7561a895b52484b701d51a
+author A U Thor <author@xxxxxxxxxxx> 1465981137 +0000
+committer C O Mitter <committer@xxxxxxxxxxx> 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
+----
+
+- verify with: `git verify-commit [-v]` (or `git show --show-signature`)
+
+----
+gpg: Signature made Wed Jun 15 10:58:57 2016 CEST using RSA key ID B7227189
+gpg: Good signature from "Eris Discordia <discord@xxxxxxxxxxx>"
+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 <author@xxxxxxxxxxx> 1465981137 +0000
+committer C O Mitter <committer@xxxxxxxxxxx> 1465981137 +0000
+
+signed commit
+
+signed commit message body
+----
+
+== Mergetag signatures
+
+- created by: `git merge` on signed tag
+- payload/embedding: the whole signed tag object is embedded into
+  the (merge) commit object as header entry `mergetag`
+- example: merge of the signed tag `signedtag` as above
+
+----
+tree c7b1cff039a93f3600a1d18b82d26688668c7dea
+parent c33429be94b5f2d3ee9b0adad223f877f174b05d
+parent 04b871796dc0420f8e7561a895b52484b701d51a
+author A U Thor <author@xxxxxxxxxxx> 1465982009 +0000
+committer C O Mitter <committer@xxxxxxxxxxx> 1465982009 +0000
+mergetag object 04b871796dc0420f8e7561a895b52484b701d51a
+ type commit
+ tag signedtag
+ tagger C O Mitter <committer@xxxxxxxxxxx> 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 <discord@xxxxxxxxxxx>"
+# 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
+----
+
+- verify with: verification is embedded in merge commit message by default,
+  alternatively with `git show --show-signature`:
+
+----
+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 <discord@xxxxxxxxxxx>"
+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 <author@xxxxxxxxxxx>
+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 <discord@xxxxxxxxxxx>"
+    # 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
+----
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitglossary.adoc b/Documentation/gitglossary.adoc
new file mode 100644
index 0000000000..0e85be4847
--- /dev/null
+++ b/Documentation/gitglossary.adoc
@@ -0,0 +1,27 @@
+gitglossary(7)
+==============
+
+NAME
+----
+gitglossary - A Git Glossary
+
+SYNOPSIS
+--------
+*
+
+DESCRIPTION
+-----------
+
+include::glossary-content.adoc[]
+
+SEE ALSO
+--------
+linkgit:gittutorial[7],
+linkgit:gittutorial-2[7],
+linkgit:gitcvs-migration[7],
+linkgit:giteveryday[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/githooks.adoc b/Documentation/githooks.adoc
new file mode 100644
index 0000000000..0397dec64d
--- /dev/null
+++ b/Documentation/githooks.adoc
@@ -0,0 +1,767 @@
+githooks(5)
+===========
+
+NAME
+----
+githooks - Hooks used by Git
+
+SYNOPSIS
+--------
+$GIT_DIR/hooks/* (or \`git config core.hooksPath`/*)
+
+
+DESCRIPTION
+-----------
+
+Hooks are programs you can place in a hooks directory to trigger
+actions at certain points in git's execution. Hooks that don't have
+the executable bit set are ignored.
+
+By default the hooks directory is `$GIT_DIR/hooks`, but that can be
+changed via the `core.hooksPath` configuration variable (see
+linkgit:git-config[1]).
+
+Before Git invokes a hook, it changes its working directory to either
+$GIT_DIR in a bare repository or the root of the working tree in a non-bare
+repository. An exception are hooks triggered during a push ('pre-receive',
+'update', 'post-receive', 'post-update', 'push-to-checkout') which are always
+executed in $GIT_DIR.
+
+Environment variables, such as `GIT_DIR`, `GIT_WORK_TREE`, etc., are exported
+so that Git commands run by the hook can correctly locate the repository.  If
+your hook needs to invoke Git commands in a foreign repository or in a
+different working tree of the same repository, then it should clear these
+environment variables so they do not interfere with Git operations at the
+foreign location.  For example:
+
+------------
+local_desc=$(git describe)
+foreign_desc=$(unset $(git rev-parse --local-env-vars); git -C ../foreign-repo describe)
+------------
+
+Hooks can get their arguments via the environment, command-line
+arguments, and stdin. See the documentation for each hook below for
+details.
+
+`git init` may copy hooks to the new repository, depending on its
+configuration. See the "TEMPLATE DIRECTORY" section in
+linkgit:git-init[1] for details. When the rest of this document refers
+to "default hooks" it's talking about the default template shipped
+with Git.
+
+The currently supported hooks are described below.
+
+HOOKS
+-----
+
+applypatch-msg
+~~~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-am[1].  It takes a single
+parameter, the name of the file that holds the proposed commit
+log message.  Exiting with a non-zero status causes `git am` to abort
+before applying the patch.
+
+The hook is allowed to edit the message file in place, and can
+be used to normalize the message into some project standard
+format. It can also be used to refuse the commit after inspecting
+the message file.
+
+The default 'applypatch-msg' hook, when enabled, runs the
+'commit-msg' hook, if the latter is enabled.
+
+pre-applypatch
+~~~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-am[1].  It takes no parameter, and is
+invoked after the patch is applied, but before a commit is made.
+
+If it exits with non-zero status, then the working tree will not be
+committed after applying the patch.
+
+It can be used to inspect the current working tree and refuse to
+make a commit if it does not pass certain tests.
+
+The default 'pre-applypatch' hook, when enabled, runs the
+'pre-commit' hook, if the latter is enabled.
+
+post-applypatch
+~~~~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-am[1].  It takes no parameter,
+and is invoked after the patch is applied and a commit is made.
+
+This hook is meant primarily for notification, and cannot affect
+the outcome of `git am`.
+
+pre-commit
+~~~~~~~~~~
+
+This hook is invoked by linkgit:git-commit[1], and can be bypassed
+with the `--no-verify` option.  It takes no parameters, and is
+invoked before obtaining the proposed commit log message and
+making a commit.  Exiting with a non-zero status from this script
+causes the `git commit` command to abort before creating a commit.
+
+The default 'pre-commit' hook, when enabled, catches introduction
+of lines with trailing whitespaces and aborts the commit when
+such a line is found.
+
+All the `git commit` hooks are invoked with the environment
+variable `GIT_EDITOR=:` if the command will not bring up an editor
+to modify the commit message.
+
+The default 'pre-commit' hook, when enabled--and with the
+`hooks.allownonascii` config option unset or set to false--prevents
+the use of non-ASCII filenames.
+
+pre-merge-commit
+~~~~~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-merge[1], and can be bypassed
+with the `--no-verify` option.  It takes no parameters, and is
+invoked after the merge has been carried out successfully and before
+obtaining the proposed commit log message to
+make a commit.  Exiting with a non-zero status from this script
+causes the `git merge` command to abort before creating a commit.
+
+The default 'pre-merge-commit' hook, when enabled, runs the
+'pre-commit' hook, if the latter is enabled.
+
+This hook is invoked with the environment variable
+`GIT_EDITOR=:` if the command will not bring up an editor
+to modify the commit message.
+
+If the merge cannot be carried out automatically, the conflicts
+need to be resolved and the result committed separately (see
+linkgit:git-merge[1]). At that point, this hook will not be executed,
+but the 'pre-commit' hook will, if it is enabled.
+
+prepare-commit-msg
+~~~~~~~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-commit[1] right after preparing the
+default log message, and before the editor is started.
+
+It takes one to three parameters.  The first is the name of the file
+that contains the commit log message.  The second is the source of the commit
+message, and can be: `message` (if a `-m` or `-F` option was
+given); `template` (if a `-t` option was given or the
+configuration option `commit.template` is set); `merge` (if the
+commit is a merge or a `.git/MERGE_MSG` file exists); `squash`
+(if a `.git/SQUASH_MSG` file exists); or `commit`, followed by
+a commit object name (if a `-c`, `-C` or `--amend` option was given).
+
+If the exit status is non-zero, `git commit` will abort.
+
+The purpose of the hook is to edit the message file in place, and
+it is not suppressed by the `--no-verify` option.  A non-zero exit
+means a failure of the hook and aborts the commit.  It should not
+be used as a replacement for the pre-commit hook.
+
+The sample `prepare-commit-msg` hook that comes with Git removes the
+help message found in the commented portion of the commit template.
+
+commit-msg
+~~~~~~~~~~
+
+This hook is invoked by linkgit:git-commit[1] and linkgit:git-merge[1], and can be
+bypassed with the `--no-verify` option.  It takes a single parameter,
+the name of the file that holds the proposed commit log message.
+Exiting with a non-zero status causes the command to abort.
+
+The hook is allowed to edit the message file in place, and can be used
+to normalize the message into some project standard format. It
+can also be used to refuse the commit after inspecting the message
+file.
+
+The default 'commit-msg' hook, when enabled, detects duplicate
+`Signed-off-by` trailers, and aborts the commit if one is found.
+
+post-commit
+~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-commit[1]. It takes no parameters, and is
+invoked after a commit is made.
+
+This hook is meant primarily for notification, and cannot affect
+the outcome of `git commit`.
+
+pre-rebase
+~~~~~~~~~~
+
+This hook is called by linkgit:git-rebase[1] and can be used to prevent a
+branch from getting rebased.  The hook may be called with one or
+two parameters.  The first parameter is the upstream from which
+the series was forked.  The second parameter is the branch being
+rebased, and is not set when rebasing the current branch.
+
+post-checkout
+~~~~~~~~~~~~~
+
+This hook is invoked when a linkgit:git-checkout[1] or
+linkgit:git-switch[1] is run after having updated the
+worktree.  The hook is given three parameters: the ref of the previous HEAD,
+the ref of the new HEAD (which may or may not have changed), and a flag
+indicating whether the checkout was a branch checkout (changing branches,
+flag=1) or a file checkout (retrieving a file from the index, flag=0).
+This hook cannot affect the outcome of `git switch` or `git checkout`,
+other than that the hook's exit status becomes the exit status of
+these two commands.
+
+It is also run after linkgit:git-clone[1], unless the `--no-checkout` (`-n`) option is
+used. The first parameter given to the hook is the null-ref, the second the
+ref of the new HEAD and the flag is always 1. Likewise for `git worktree add`
+unless `--no-checkout` is used.
+
+This hook can be used to perform repository validity checks, auto-display
+differences from the previous HEAD if different, or set working dir metadata
+properties.
+
+post-merge
+~~~~~~~~~~
+
+This hook is invoked by linkgit:git-merge[1], which happens when a `git pull`
+is done on a local repository.  The hook takes a single parameter, a status
+flag specifying whether or not the merge being done was a squash merge.
+This hook cannot affect the outcome of `git merge` and is not executed,
+if the merge failed due to conflicts.
+
+This hook can be used in conjunction with a corresponding pre-commit hook to
+save and restore any form of metadata associated with the working tree
+(e.g.: permissions/ownership, ACLS, etc).  See contrib/hooks/setgitperms.perl
+for an example of how to do this.
+
+pre-push
+~~~~~~~~
+
+This hook is called by linkgit:git-push[1] and can be used to prevent
+a push from taking place.  The hook is called with two parameters
+which provide the name and location of the destination remote, if a
+named remote is not being used both values will be the same.
+
+Information about what is to be pushed is provided on the hook's standard
+input with lines of the form:
+
+  <local-ref> SP <local-object-name> SP <remote-ref> SP <remote-object-name> LF
+
+For instance, if the command +git push origin master:foreign+ were run the
+hook would receive a line like the following:
+
+  refs/heads/master 67890 refs/heads/foreign 12345
+
+although the full object name would be supplied.  If the foreign ref does not
+yet exist the `<remote-object-name>` will be the all-zeroes object name.  If a
+ref is to be deleted, the `<local-ref>` will be supplied as `(delete)` and the
+`<local-object-name>` will be the all-zeroes object name.  If the local commit
+was specified by something other than a name which could be expanded (such as
+`HEAD~`, or an object name) it will be supplied as it was originally given.
+
+If this hook exits with a non-zero status, `git push` will abort without
+pushing anything.  Information about why the push is rejected may be sent
+to the user by writing to standard error.
+
+[[pre-receive]]
+pre-receive
+~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository.
+Just before starting to update refs on the remote repository, the
+pre-receive hook is invoked.  Its exit status determines the success
+or failure of the update.
+
+This hook executes once for the receive operation. It takes no
+arguments, but for each ref to be updated it receives on standard
+input a line of the format:
+
+  <old-oid> SP <new-oid> SP <ref-name> LF
+
+where `<old-oid>` is the old object name stored in the ref,
+`<new-oid>` is the new object name to be stored in the ref and
+`<ref-name>` is the full name of the ref.
+When creating a new ref, `<old-oid>` is the all-zeroes object name.
+
+If the hook exits with non-zero status, none of the refs will be
+updated. If the hook exits with zero, updating of individual refs can
+still be prevented by the <<update,'update'>> hook.
+
+Both standard output and standard error output are forwarded to
+`git send-pack` on the other end, so you can simply `echo` messages
+for the user.
+
+The number of push options given on the command line of
+`git push --push-option=...` can be read from the environment
+variable `GIT_PUSH_OPTION_COUNT`, and the options themselves are
+found in `GIT_PUSH_OPTION_0`, `GIT_PUSH_OPTION_1`,...
+If it is negotiated to not use the push options phase, the
+environment variables will not be set. If the client selects
+to use push options, but doesn't transmit any, the count variable
+will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
+
+See the section on "Quarantine Environment" in
+linkgit:git-receive-pack[1] for some caveats.
+
+[[update]]
+update
+~~~~~~
+
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository.
+Just before updating the ref on the remote repository, the update hook
+is invoked.  Its exit status determines the success or failure of
+the ref update.
+
+The hook executes once for each ref to be updated, and takes
+three parameters:
+
+ - the name of the ref being updated,
+ - the old object name stored in the ref,
+ - and the new object name to be stored in the ref.
+
+A zero exit from the update hook allows the ref to be updated.
+Exiting with a non-zero status prevents `git receive-pack`
+from updating that ref.
+
+This hook can be used to prevent 'forced' update on certain refs by
+making sure that the object name is a commit object that is a
+descendant of the commit object named by the old object name.
+That is, to enforce a "fast-forward only" policy.
+
+It could also be used to log the old..new status.  However, it
+does not know the entire set of branches, so it would end up
+firing one e-mail per ref when used naively, though.  The
+<<post-receive,'post-receive'>> hook is more suited to that.
+
+In an environment that restricts the users' access only to git
+commands over the wire, this hook can be used to implement access
+control without relying on filesystem ownership and group
+membership. See linkgit:git-shell[1] for how you might use the login
+shell to restrict the user's access to only git commands.
+
+Both standard output and standard error output are forwarded to
+`git send-pack` on the other end, so you can simply `echo` messages
+for the user.
+
+The default 'update' hook, when enabled--and with
+`hooks.allowunannotated` config option unset or set to false--prevents
+unannotated tags from being pushed.
+
+[[proc-receive]]
+proc-receive
+~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-receive-pack[1].  If the server has
+set the multi-valued config variable `receive.procReceiveRefs`, and the
+commands sent to 'receive-pack' have matching reference names, these
+commands will be executed by this hook, instead of by the internal
+`execute_commands()` function.  This hook is responsible for updating
+the relevant references and reporting the results back to 'receive-pack'.
+
+This hook executes once for the receive operation.  It takes no
+arguments, but uses a pkt-line format protocol to communicate with
+'receive-pack' to read commands, push-options and send results.  In the
+following example for the protocol, the letter 'S' stands for
+'receive-pack' and the letter 'H' stands for this hook.
+
+    # Version and features negotiation.
+    S: PKT-LINE(version=1\0push-options atomic...)
+    S: flush-pkt
+    H: PKT-LINE(version=1\0push-options...)
+    H: flush-pkt
+
+    # Send commands from server to the hook.
+    S: PKT-LINE(<old-oid> <new-oid> <ref>)
+    S: ... ...
+    S: flush-pkt
+    # Send push-options only if the 'push-options' feature is enabled.
+    S: PKT-LINE(push-option)
+    S: ... ...
+    S: flush-pkt
+
+    # Receive results from the hook.
+    # OK, run this command successfully.
+    H: PKT-LINE(ok <ref>)
+    # NO, I reject it.
+    H: PKT-LINE(ng <ref> <reason>)
+    # Fall through, let 'receive-pack' execute it.
+    H: PKT-LINE(ok <ref>)
+    H: PKT-LINE(option fall-through)
+    # OK, but has an alternate reference.  The alternate reference name
+    # and other status can be given in option directives.
+    H: PKT-LINE(ok <ref>)
+    H: PKT-LINE(option refname <refname>)
+    H: PKT-LINE(option old-oid <old-oid>)
+    H: PKT-LINE(option new-oid <new-oid>)
+    H: PKT-LINE(option forced-update)
+    H: ... ...
+    H: flush-pkt
+
+Each command for the 'proc-receive' hook may point to a pseudo-reference
+and always has a zero-old as its old-oid, while the 'proc-receive' hook
+may update an alternate reference and the alternate reference may exist
+already with a non-zero old-oid.  For this case, this hook will use
+"option" directives to report extended attributes for the reference given
+by the leading "ok" directive.
+
+The report of the commands of this hook should have the same order as
+the input.  The exit status of the 'proc-receive' hook only determines
+the success or failure of the group of commands sent to it, unless
+atomic push is in use.
+
+[[post-receive]]
+post-receive
+~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository.
+The hook executes on the remote repository once after all the proposed
+ref updates are processed and if at least one ref is updated as the
+result.
+
+The hook takes no arguments.  It receives one line on standard input for
+each ref that is successfully updated following the same format as the
+<<pre-receive,'pre-receive'>> hook.
+
+This hook does not affect the outcome of `git receive-pack`, as it
+is called after the real work is done.
+
+This supersedes the <<post-update,'post-update'>> hook in that it gets
+both old and new values of all the refs in addition to their
+names.
+
+Both standard output and standard error output are forwarded to
+`git send-pack` on the other end, so you can simply `echo` messages
+for the user.
+
+The default 'post-receive' hook is empty, but there is
+a sample script `post-receive-email` provided in the `contrib/hooks`
+directory in Git distribution, which implements sending commit
+emails.
+
+The number of push options given on the command line of
+`git push --push-option=...` can be read from the environment
+variable `GIT_PUSH_OPTION_COUNT`, and the options themselves are
+found in `GIT_PUSH_OPTION_0`, `GIT_PUSH_OPTION_1`,...
+If it is negotiated to not use the push options phase, the
+environment variables will not be set. If the client selects
+to use push options, but doesn't transmit any, the count variable
+will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
+
+See the "post-receive" section in linkgit:git-receive-pack[1] for
+additional details.
+
+[[post-update]]
+post-update
+~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository.
+It executes on the remote repository once after all the refs have
+been updated.
+
+It takes a variable number of parameters, each of which is the
+name of ref that was actually updated.
+
+This hook is meant primarily for notification, and cannot affect
+the outcome of `git receive-pack`.
+
+The 'post-update' hook can tell what are the heads that were pushed,
+but it does not know what their original and updated values are,
+so it is a poor place to do log old..new. The
+<<post-receive,'post-receive'>> hook does get both original and
+updated values of the refs. You might consider it instead if you need
+them.
+
+When enabled, the default 'post-update' hook runs
+`git update-server-info` to keep the information used by dumb
+transports (e.g., HTTP) up to date.  If you are publishing
+a Git repository that is accessible via HTTP, you should
+probably enable this hook.
+
+Both standard output and standard error output are forwarded to
+`git send-pack` on the other end, so you can simply `echo` messages
+for the user.
+
+reference-transaction
+~~~~~~~~~~~~~~~~~~~~~
+
+This hook is invoked by any Git command that performs reference
+updates. It executes whenever a reference transaction is prepared,
+committed or aborted and may thus get called multiple times. The hook
+also supports symbolic reference updates.
+
+The hook takes exactly one argument, which is the current state the
+given reference transaction is in:
+
+    - "prepared": All reference updates have been queued to the
+      transaction and references were locked on disk.
+
+    - "committed": The reference transaction was committed and all
+      references now have their respective new value.
+
+    - "aborted": The reference transaction was aborted, no changes
+      were performed and the locks have been released.
+
+For each reference update that was added to the transaction, the hook
+receives on standard input a line of the format:
+
+  <old-value> SP <new-value> SP <ref-name> LF
+
+where `<old-value>` is the old object name passed into the reference
+transaction, `<new-value>` is the new object name to be stored in the
+ref and `<ref-name>` is the full name of the ref. When force updating
+the reference regardless of its current value or when the reference is
+to be created anew, `<old-value>` is the all-zeroes object name. To
+distinguish these cases, you can inspect the current value of
+`<ref-name>` via `git rev-parse`.
+
+For symbolic reference updates the `<old_value>` and `<new-value>`
+fields could denote references instead of objects. A reference will be
+denoted with a 'ref:' prefix, like `ref:<ref-target>`.
+
+The exit status of the hook is ignored for any state except for the
+"prepared" state. In the "prepared" state, a non-zero exit status will
+cause the transaction to be aborted. The hook will not be called with
+"aborted" state in that case.
+
+push-to-checkout
+~~~~~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-receive-pack[1] when it reacts to
+`git push` and updates reference(s) in its repository, and when
+the push tries to update the branch that is currently checked out
+and the `receive.denyCurrentBranch` configuration variable is set to
+`updateInstead`.  Such a push by default is refused if the working
+tree and the index of the remote repository has any difference from
+the currently checked out commit; when both the working tree and the
+index match the current commit, they are updated to match the newly
+pushed tip of the branch.  This hook is to be used to override the
+default behaviour.
+
+The hook receives the commit with which the tip of the current
+branch is going to be updated.  It can exit with a non-zero status
+to refuse the push (when it does so, it must not modify the index or
+the working tree).  Or it can make any necessary changes to the
+working tree and to the index to bring them to the desired state
+when the tip of the current branch is updated to the new commit, and
+exit with a zero status.
+
+For example, the hook can simply run `git read-tree -u -m HEAD "$1"`
+in order to emulate `git fetch` that is run in the reverse direction
+with `git push`, as the two-tree form of `git read-tree -u -m` is
+essentially the same as `git switch` or `git checkout`
+that switches branches while
+keeping the local changes in the working tree that do not interfere
+with the difference between the branches.
+
+
+pre-auto-gc
+~~~~~~~~~~~
+
+This hook is invoked by `git gc --auto` (see linkgit:git-gc[1]). It
+takes no parameter, and exiting with non-zero status from this script
+causes the `git gc --auto` to abort.
+
+post-rewrite
+~~~~~~~~~~~~
+
+This hook is invoked by commands that rewrite commits
+(linkgit:git-commit[1] when called with `--amend` and
+linkgit:git-rebase[1]; however, full-history (re)writing tools like
+linkgit:git-fast-import[1] or
+https://github.com/newren/git-filter-repo[git-filter-repo] typically
+do not call it!).  Its first argument denotes the command it was
+invoked by: currently one of `amend` or `rebase`.  Further
+command-dependent arguments may be passed in the future.
+
+The hook receives a list of the rewritten commits on stdin, in the
+format
+
+  <old-object-name> SP <new-object-name> [ SP <extra-info> ] LF
+
+The 'extra-info' is again command-dependent.  If it is empty, the
+preceding SP is also omitted.  Currently, no commands pass any
+'extra-info'.
+
+The hook always runs after the automatic note copying (see
+"notes.rewrite.<command>" in linkgit:git-config[1]) has happened, and
+thus has access to these notes.
+
+The following command-specific comments apply:
+
+rebase::
+	For the 'squash' and 'fixup' operation, all commits that were
+	squashed are listed as being rewritten to the squashed commit.
+	This means that there will be several lines sharing the same
+	'new-object-name'.
++
+The commits are guaranteed to be listed in the order that they were
+processed by rebase.
+
+sendemail-validate
+~~~~~~~~~~~~~~~~~~
+
+This hook is invoked by linkgit:git-send-email[1].
+
+It takes these command line arguments. They are,
+1. the name of the file which holds the contents of the email to be sent.
+2. The name of the file which holds the SMTP headers of the email.
+
+The SMTP headers are passed in the exact same way as they are passed to the
+user's Mail Transport Agent (MTA). In effect, the email given to the user's
+MTA, is the contents of $2 followed by the contents of $1.
+
+An example of a few common headers is shown below. Take notice of the
+capitalization and multi-line tab structure.
+
+  From: Example <from@xxxxxxxxxxx>
+  To: to@xxxxxxxxxxx
+  Cc: cc@xxxxxxxxxxx,
+	  A <author@xxxxxxxxxxx>,
+	  One <one@xxxxxxxxxxx>,
+	  two@xxxxxxxxxxx
+  Subject: PATCH-STRING
+
+Exiting with a non-zero status causes `git send-email` to abort
+before sending any e-mails.
+
+The following environment variables are set when executing the hook.
+
+`GIT_SENDEMAIL_FILE_COUNTER`::
+	A 1-based counter incremented by one for every file holding an e-mail
+	to be sent (excluding any FIFOs). This counter does not follow the
+	patch series counter scheme. It will always start at 1 and will end at
+	GIT_SENDEMAIL_FILE_TOTAL.
+
+`GIT_SENDEMAIL_FILE_TOTAL`::
+	The total number of files that will be sent (excluding any FIFOs). This
+	counter does not follow the patch series counter scheme. It will always
+	be equal to the number of files being sent, whether there is a cover
+	letter or not.
+
+These variables may for instance be used to validate patch series.
+
+The sample `sendemail-validate` hook that comes with Git checks that all sent
+patches (excluding the cover letter) can be applied on top of the upstream
+repository default branch without conflicts. Some placeholders are left for
+additional validation steps to be performed after all patches of a given series
+have been applied.
+
+fsmonitor-watchman
+~~~~~~~~~~~~~~~~~~
+
+This hook is invoked when the configuration option `core.fsmonitor` is
+set to `.git/hooks/fsmonitor-watchman` or `.git/hooks/fsmonitor-watchmanv2`
+depending on the version of the hook to use.
+
+Version 1 takes two arguments, a version (1) and the time in elapsed
+nanoseconds since midnight, January 1, 1970.
+
+Version 2 takes two arguments, a version (2) and a token that is used
+for identifying changes since the token. For watchman this would be
+a clock id. This version must output to stdout the new token followed
+by a NUL before the list of files.
+
+The hook should output to stdout the list of all files in the working
+directory that may have changed since the requested time.  The logic
+should be inclusive so that it does not miss any potential changes.
+The paths should be relative to the root of the working directory
+and be separated by a single NUL.
+
+It is OK to include files which have not actually changed.  All changes
+including newly-created and deleted files should be included. When
+files are renamed, both the old and the new name should be included.
+
+Git will limit what files it checks for changes as well as which
+directories are checked for untracked files based on the path names
+given.
+
+An optimized way to tell git "all files have changed" is to return
+the filename `/`.
+
+The exit status determines whether git will use the data from the
+hook to limit its search.  On error, it will fall back to verifying
+all files and folders.
+
+p4-changelist
+~~~~~~~~~~~~~
+
+This hook is invoked by `git-p4 submit`.
+
+The `p4-changelist` hook is executed after the changelist
+message has been edited by the user. It can be bypassed with the
+`--no-verify` option. It takes a single parameter, the name
+of the file that holds the proposed changelist text. Exiting
+with a non-zero status causes the command to abort.
+
+The hook is allowed to edit the changelist file and can be used
+to normalize the text into some project standard format. It can
+also be used to refuse the Submit after inspect the message file.
+
+Run `git-p4 submit --help` for details.
+
+p4-prepare-changelist
+~~~~~~~~~~~~~~~~~~~~~
+
+This hook is invoked by `git-p4 submit`.
+
+The `p4-prepare-changelist` hook is executed right after preparing
+the default changelist message and before the editor is started.
+It takes one parameter, the name of the file that contains the
+changelist text. Exiting with a non-zero status from the script
+will abort the process.
+
+The purpose of the hook is to edit the message file in place,
+and it is not suppressed by the `--no-verify` option. This hook
+is called even if `--prepare-p4-only` is set.
+
+Run `git-p4 submit --help` for details.
+
+p4-post-changelist
+~~~~~~~~~~~~~~~~~~
+
+This hook is invoked by `git-p4 submit`.
+
+The `p4-post-changelist` hook is invoked after the submit has
+successfully occurred in P4. It takes no parameters and is meant
+primarily for notification and cannot affect the outcome of the
+git p4 submit action.
+
+Run `git-p4 submit --help` for details.
+
+p4-pre-submit
+~~~~~~~~~~~~~
+
+This hook is invoked by `git-p4 submit`. It takes no parameters and nothing
+from standard input. Exiting with non-zero status from this script prevent
+`git-p4 submit` from launching. It can be bypassed with the `--no-verify`
+command line option. Run `git-p4 submit --help` for details.
+
+
+
+post-index-change
+~~~~~~~~~~~~~~~~~
+
+This hook is invoked when the index is written in read-cache.c
+do_write_locked_index.
+
+The first parameter passed to the hook is the indicator for the
+working directory being updated.  "1" meaning working directory
+was updated or "0" when the working directory was not updated.
+
+The second parameter passed to the hook is the indicator for whether
+or not the index was updated and the skip-worktree bit could have
+changed.  "1" meaning skip-worktree bits could have been updated
+and "0" meaning they were not.
+
+Only one parameter should be set to "1" when the hook runs.  The hook
+running passing "1", "1" should not be possible.
+
+SEE ALSO
+--------
+linkgit:git-hook[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitignore.adoc b/Documentation/gitignore.adoc
new file mode 100644
index 0000000000..5e0964ef41
--- /dev/null
+++ b/Documentation/gitignore.adoc
@@ -0,0 +1,243 @@
+gitignore(5)
+============
+
+NAME
+----
+gitignore - Specifies intentionally untracked files to ignore
+
+SYNOPSIS
+--------
+$XDG_CONFIG_HOME/git/ignore, $GIT_DIR/info/exclude, .gitignore
+
+DESCRIPTION
+-----------
+
+A `gitignore` file specifies intentionally untracked files that
+Git should ignore.
+Files already tracked by Git are not affected; see the NOTES
+below for details.
+
+Each line in a `gitignore` file specifies a pattern.
+When deciding whether to ignore a path, Git normally checks
+`gitignore` patterns from multiple sources, with the following
+order of precedence, from highest to lowest (within one level of
+precedence, the last matching pattern decides the outcome):
+
+ * Patterns read from the command line for those commands that support
+   them.
+
+ * Patterns read from a `.gitignore` file in the same directory
+   as the path, or in any parent directory (up to the top-level of the working
+   tree), with patterns in the higher level files being overridden by those in
+   lower level files down to the directory containing the file. These patterns
+   match relative to the location of the `.gitignore` file.  A project normally
+   includes such `.gitignore` files in its repository, containing patterns for
+   files generated as part of the project build.
+
+ * Patterns read from `$GIT_DIR/info/exclude`.
+
+ * Patterns read from the file specified by the configuration
+   variable `core.excludesFile`.
+
+Which file to place a pattern in depends on how the pattern is meant to
+be used.
+
+ * Patterns which should be version-controlled and distributed to
+   other repositories via clone (i.e., files that all developers will want
+   to ignore) should go into a `.gitignore` file.
+
+ * Patterns which are
+   specific to a particular repository but which do not need to be shared
+   with other related repositories (e.g., auxiliary files that live inside
+   the repository but are specific to one user's workflow) should go into
+   the `$GIT_DIR/info/exclude` file.
+
+ * Patterns which a user wants Git to
+   ignore in all situations (e.g., backup or temporary files generated by
+   the user's editor of choice) generally go into a file specified by
+   `core.excludesFile` in the user's `~/.gitconfig`. Its default value is
+   $XDG_CONFIG_HOME/git/ignore. If $XDG_CONFIG_HOME is either not set or
+   empty, $HOME/.config/git/ignore is used instead.
+
+The underlying Git plumbing tools, such as
+'git ls-files' and 'git read-tree', read
+`gitignore` patterns specified by command-line options, or from
+files specified by command-line options.  Higher-level Git
+tools, such as 'git status' and 'git add',
+use patterns from the sources specified above.
+
+PATTERN FORMAT
+--------------
+
+ - A blank line matches no files, so it can serve as a separator
+   for readability.
+
+ - A line starting with # serves as a comment.
+   Put a backslash ("`\`") in front of the first hash for patterns
+   that begin with a hash.
+
+ - Trailing spaces are ignored unless they are quoted with backslash
+   ("`\`").
+
+ - An optional prefix "`!`" which negates the pattern; any
+   matching file excluded by a previous pattern will become
+   included again. It is not possible to re-include a file if a parent
+   directory of that file is excluded. Git doesn't list excluded
+   directories for performance reasons, so any patterns on contained
+   files have no effect, no matter where they are defined.
+   Put a backslash ("`\`") in front of the first "`!`" for patterns
+   that begin with a literal "`!`", for example, "`\!important!.txt`".
+
+ - The slash "`/`" is used as the directory separator. Separators may
+   occur at the beginning, middle or end of the `.gitignore` search pattern.
+
+ - If there is a separator at the beginning or middle (or both) of the
+   pattern, then the pattern is relative to the directory level of the
+   particular `.gitignore` file itself. Otherwise the pattern may also
+   match at any level below the `.gitignore` level.
+
+ - If there is a separator at the end of the pattern then the pattern
+   will only match directories, otherwise the pattern can match both
+   files and directories.
+
+ - For example, a pattern `doc/frotz/` matches `doc/frotz` directory,
+   but not `a/doc/frotz` directory; however `frotz/` matches `frotz`
+   and `a/frotz` that is a directory (all paths are relative from
+   the `.gitignore` file).
+
+ - An asterisk "`*`" matches anything except a slash.
+   The character "`?`" matches any one character except "`/`".
+   The range notation, e.g. `[a-zA-Z]`, can be used to match
+   one of the characters in a range. See fnmatch(3) and the
+   FNM_PATHNAME flag for a more detailed description.
+
+Two consecutive asterisks ("`**`") in patterns matched against
+full pathname may have special meaning:
+
+ - A leading "`**`" followed by a slash means match in all
+   directories. For example, "`**/foo`" matches file or directory
+   "`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`"
+   matches file or directory "`bar`" anywhere that is directly
+   under directory "`foo`".
+
+ - A trailing "`/**`" matches everything inside. For example,
+   "`abc/**`" matches all files inside directory "`abc`", relative
+   to the location of the `.gitignore` file, with infinite depth.
+
+ - A slash followed by two consecutive asterisks then a slash
+   matches zero or more directories. For example, "`a/**/b`"
+   matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
+
+ - Other consecutive asterisks are considered regular asterisks and
+   will match according to the previous rules.
+
+CONFIGURATION
+-------------
+
+The optional configuration variable `core.excludesFile` indicates a path to a
+file containing patterns of file names to exclude, similar to
+`$GIT_DIR/info/exclude`.  Patterns in the exclude file are used in addition to
+those in `$GIT_DIR/info/exclude`.
+
+NOTES
+-----
+
+The purpose of gitignore files is to ensure that certain files
+not tracked by Git remain untracked.
+
+To stop tracking a file that is currently tracked, use
+'git rm --cached' to remove the file from the index. The filename
+can then be added to the `.gitignore` file to stop the file from
+being reintroduced in later commits.
+
+Git does not follow symbolic links when accessing a `.gitignore` file in
+the working tree. This keeps behavior consistent when the file is
+accessed from the index or a tree versus from the filesystem.
+
+EXAMPLES
+--------
+
+ - The pattern `hello.*` matches any file or directory
+   whose name begins with `hello.`. If one wants to restrict
+   this only to the directory and not in its subdirectories,
+   one can prepend the pattern with a slash, i.e. `/hello.*`;
+   the pattern now matches `hello.txt`, `hello.c` but not
+   `a/hello.java`.
+
+ - The pattern `foo/` will match a directory `foo` and
+   paths underneath it, but will not match a regular file
+   or a symbolic link `foo` (this is consistent with the
+   way how pathspec works in general in Git)
+
+ - The pattern `doc/frotz` and `/doc/frotz` have the same effect
+   in any `.gitignore` file. In other words, a leading slash
+   is not relevant  if there is already a middle slash in
+   the pattern.
+
+ - The pattern `foo/*`, matches `foo/test.json`
+   (a regular file), `foo/bar` (a directory), but it does not match
+   `foo/bar/hello.c` (a regular file), as the asterisk in the
+   pattern does not match `bar/hello.c` which has a slash in it.
+
+--------------------------------------------------------------
+    $ git status
+    [...]
+    # Untracked files:
+    [...]
+    #       Documentation/foo.html
+    #       Documentation/gitignore.html
+    #       file.o
+    #       lib.a
+    #       src/internal.o
+    [...]
+    $ cat .git/info/exclude
+    # ignore objects and archives, anywhere in the tree.
+    *.[oa]
+    $ cat Documentation/.gitignore
+    # ignore generated html files,
+    *.html
+    # except foo.html which is maintained by hand
+    !foo.html
+    $ git status
+    [...]
+    # Untracked files:
+    [...]
+    #       Documentation/foo.html
+    [...]
+--------------------------------------------------------------
+
+Another example:
+
+--------------------------------------------------------------
+    $ cat .gitignore
+    vmlinux*
+    $ ls arch/foo/kernel/vm*
+    arch/foo/kernel/vmlinux.lds.S
+    $ echo '!/vmlinux*' >arch/foo/kernel/.gitignore
+--------------------------------------------------------------
+
+The second .gitignore prevents Git from ignoring
+`arch/foo/kernel/vmlinux.lds.S`.
+
+Example to exclude everything except a specific directory `foo/bar`
+(note the `/*` - without the slash, the wildcard would also exclude
+everything within `foo/bar`):
+
+--------------------------------------------------------------
+    $ cat .gitignore
+    # exclude everything except directory foo/bar
+    /*
+    !/foo
+    /foo/*
+    !/foo/bar
+--------------------------------------------------------------
+
+SEE ALSO
+--------
+linkgit:git-rm[1],
+linkgit:gitrepository-layout[5],
+linkgit:git-check-ignore[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitk.adoc b/Documentation/gitk.adoc
new file mode 100644
index 0000000000..58ce40ddb1
--- /dev/null
+++ b/Documentation/gitk.adoc
@@ -0,0 +1,188 @@
+gitk(1)
+=======
+
+NAME
+----
+gitk - The Git repository browser
+
+SYNOPSIS
+--------
+[verse]
+'gitk' [<options>] [<revision-range>] [--] [<path>...]
+
+DESCRIPTION
+-----------
+Displays changes in a repository or a selected set of commits. This includes
+visualizing the commit graph, showing information related to each commit, and
+the files in the trees of each revision.
+
+OPTIONS
+-------
+
+To control which revisions to show, gitk supports most options
+applicable to the 'git rev-list' command.  It also supports a few
+options applicable to the 'git diff-*' commands to control how the
+changes each commit introduces are shown.  Finally, it supports some
+gitk-specific options.
+
+gitk generally only understands options with arguments in the
+'stuck' form (see linkgit:gitcli[7]) due to limitations in the
+command-line parser.
+
+rev-list options and arguments
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This manual page describes only the most frequently used options.  See
+linkgit:git-rev-list[1] for a complete list.
+
+--all::
+
+	Show all refs (branches, tags, etc.).
+
+--branches[=<pattern>]::
+--tags[=<pattern>]::
+--remotes[=<pattern>]::
+
+	Pretend as if all the branches (tags, remote branches, resp.)
+	are listed on the command line as '<commit>'. If '<pattern>'
+	is given, limit refs to ones matching given shell glob. If
+	pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the
+	end is implied.
+
+--since=<date>::
+
+	Show commits more recent than a specific date.
+
+--until=<date>::
+
+	Show commits older than a specific date.
+
+--date-order::
+
+	Sort commits by date when possible.
+
+--merge::
+
+	After an attempt to merge stops with conflicts, show the commits on
+	the history between two branches (i.e. the HEAD and the MERGE_HEAD)
+	that modify the conflicted files and do not exist on all the heads
+	being merged.
+
+--left-right::
+
+	Mark which side of a symmetric difference a commit is reachable
+	from.  Commits from the left side are prefixed with a `<`
+	symbol and those from the right with a `>` symbol.
+
+--full-history::
+
+	When filtering history with '<path>...', does not prune some
+	history.  (See "History simplification" in linkgit:git-log[1]
+	for a more detailed explanation.)
+
+--simplify-merges::
+
+	Additional option to `--full-history` to remove some needless
+	merges from the resulting history, as there are no selected
+	commits contributing to this merge.  (See "History
+	simplification" in linkgit:git-log[1] for a more detailed
+	explanation.)
+
+--ancestry-path::
+
+	When given a range of commits to display
+	(e.g. 'commit1..commit2' or 'commit2 {caret}commit1'), only
+	display commits that exist directly on the ancestry chain
+	between the 'commit1' and 'commit2', i.e. commits that are
+	both descendants of 'commit1', and ancestors of 'commit2'.
+	(See "History simplification" in linkgit:git-log[1] for a more
+	detailed explanation.)
+
+include::line-range-options.adoc[]
+
+<revision range>::
+
+	Limit the revisions to show. This can be either a single revision
+	meaning show from the given revision and back, or it can be a range in
+	the form "'<from>'..'<to>'" to show all revisions between '<from>' and
+	back to '<to>'. Note, more advanced revision selection can be applied.
+	For a more complete list of ways to spell object names, see
+	linkgit:gitrevisions[7].
+
+<path>...::
+
+	Limit commits to the ones touching files in the given paths. Note, to
+	avoid ambiguity with respect to revision names use "--" to separate the paths
+	from any preceding options.
+
+gitk-specific options
+~~~~~~~~~~~~~~~~~~~~~
+
+--argscmd=<command>::
+
+	Command to be run each time gitk has to determine the revision
+	range to show.  The command is expected to print on its
+	standard output a list of additional revisions to be shown,
+	one per line.  Use this instead of explicitly specifying a
+	'<revision-range>' if the set of commits to show may vary
+	between refreshes.
+
+--select-commit=<ref>::
+
+	Select the specified commit after loading the graph.
+	Default behavior is equivalent to specifying '--select-commit=HEAD'.
+
+Examples
+--------
+gitk v2.6.12.. include/scsi drivers/scsi::
+
+	Show the changes since version 'v2.6.12' that changed any
+	file in the include/scsi or drivers/scsi subdirectories
+
+gitk --since="2 weeks ago" \-- gitk::
+
+	Show the changes during the last two weeks to the file 'gitk'.
+	The "--" is necessary to avoid confusion with the *branch* named
+	'gitk'
+
+gitk --max-count=100 --all \-- Makefile::
+
+	Show at most 100 changes made to the file 'Makefile'. Instead of only
+	looking for changes in the current branch look in all branches.
+
+Files
+-----
+User configuration and preferences are stored at:
+
+* `$XDG_CONFIG_HOME/git/gitk` if it exists, otherwise
+* `$HOME/.gitk` if it exists
+
+If neither of the above exist then `$XDG_CONFIG_HOME/git/gitk` is created and
+used by default. If '$XDG_CONFIG_HOME' is not set it defaults to
+`$HOME/.config` in all cases.
+
+History
+-------
+Gitk was the first graphical repository browser. It's written in
+tcl/tk.
+
+'gitk' is actually maintained as an independent project, but stable
+versions are distributed as part of the Git suite for the convenience
+of end users.
+
+gitk-git/ comes from Paul Mackerras's gitk project:
+
+	git://ozlabs.org/~paulus/gitk
+
+SEE ALSO
+--------
+'qgit(1)'::
+	A repository browser written in C++ using Qt.
+
+'tig(1)'::
+	A minimal repository browser and Git tool output highlighter written
+	in C using Ncurses.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitmailmap.adoc b/Documentation/gitmailmap.adoc
new file mode 100644
index 0000000000..06f4af93fe
--- /dev/null
+++ b/Documentation/gitmailmap.adoc
@@ -0,0 +1,130 @@
+gitmailmap(5)
+=============
+
+NAME
+----
+gitmailmap - Map author/committer names and/or E-Mail addresses
+
+SYNOPSIS
+--------
+$GIT_WORK_TREE/.mailmap
+
+
+DESCRIPTION
+-----------
+
+If the file `.mailmap` exists at the toplevel of the repository, or at
+the location pointed to by the `mailmap.file` or `mailmap.blob`
+configuration options (see linkgit:git-config[1]), it
+is used to map author and committer names and email addresses to
+canonical real names and email addresses.
+
+
+SYNTAX
+------
+
+The '#' character begins a comment to the end of line, blank lines
+are ignored.
+
+In the simple form, each line in the file consists of the canonical
+real name of an author, whitespace, and an email address used in the
+commit (enclosed by '<' and '>') to map to the name. For example:
+--
+	Proper Name <commit@xxxxxxxx>
+--
+
+The more complex forms are:
+--
+	<proper@xxxxxxxx> <commit@xxxxxxxx>
+--
+which allows mailmap to replace only the email part of a commit, and:
+--
+	Proper Name <proper@xxxxxxxx> <commit@xxxxxxxx>
+--
+which allows mailmap to replace both the name and the email of a
+commit matching the specified commit email address, and:
+--
+	Proper Name <proper@xxxxxxxx> Commit Name <commit@xxxxxxxx>
+--
+which allows mailmap to replace both the name and the email of a
+commit matching both the specified commit name and email address.
+
+Both E-Mails and names are matched case-insensitively. For example
+this would also match the 'Commit Name <commit&#64;email.xx>' above:
+--
+	Proper Name <proper@xxxxxxxx> CoMmIt NaMe <CoMmIt@xxxxxxxx>
+--
+
+NOTES
+-----
+
+Git does not follow symbolic links when accessing a `.mailmap` file in
+the working tree. This keeps behavior consistent when the file is
+accessed from the index or a tree versus from the filesystem.
+
+EXAMPLES
+--------
+
+Your history contains commits by two authors, Jane
+and Joe, whose names appear in the repository under several forms:
+
+------------
+Joe Developer <joe@xxxxxxxxxxx>
+Joe R. Developer <joe@xxxxxxxxxxx>
+Jane Doe <jane@xxxxxxxxxxx>
+Jane Doe <jane@laptop.(none)>
+Jane D. <jane@desktop.(none)>
+------------
+
+Now suppose that Joe wants his middle name initial used, and Jane
+prefers her family name fully spelled out. A `.mailmap` file to
+correct the names would look like:
+
+------------
+Joe R. Developer <joe@xxxxxxxxxxx>
+Jane Doe <jane@xxxxxxxxxxx>
+Jane Doe <jane@desktop.(none)>
+------------
+
+Note that there's no need to map the name for '<jane&#64;laptop.(none)>' to
+only correct the names. However, leaving the obviously broken
+'<jane&#64;laptop.(none)>' and '<jane&#64;desktop.(none)>' E-Mails as-is is
+usually not what you want. A `.mailmap` file which also corrects those
+is:
+
+------------
+Joe R. Developer <joe@xxxxxxxxxxx>
+Jane Doe <jane@xxxxxxxxxxx> <jane@laptop.(none)>
+Jane Doe <jane@xxxxxxxxxxx> <jane@desktop.(none)>
+------------
+
+Finally, let's say that Joe and Jane shared an E-Mail address, but not
+a name, e.g. by having these two commits in the history generated by a
+bug reporting system. I.e. names appearing in history as:
+
+------------
+Joe <bugs@xxxxxxxxxxx>
+Jane <bugs@xxxxxxxxxxx>
+------------
+
+A full `.mailmap` file which also handles those cases (an addition of
+two lines to the above example) would be:
+
+------------
+Joe R. Developer <joe@xxxxxxxxxxx>
+Jane Doe <jane@xxxxxxxxxxx> <jane@laptop.(none)>
+Jane Doe <jane@xxxxxxxxxxx> <jane@desktop.(none)>
+Joe R. Developer <joe@xxxxxxxxxxx> Joe <bugs@xxxxxxxxxxx>
+Jane Doe <jane@xxxxxxxxxxx> Jane <bugs@xxxxxxxxxxx>
+------------
+
+
+
+SEE ALSO
+--------
+linkgit:git-check-mailmap[1]
+
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitmodules.adoc b/Documentation/gitmodules.adoc
new file mode 100644
index 0000000000..d9bec8b187
--- /dev/null
+++ b/Documentation/gitmodules.adoc
@@ -0,0 +1,135 @@
+gitmodules(5)
+=============
+
+NAME
+----
+gitmodules - Defining submodule properties
+
+SYNOPSIS
+--------
+$GIT_WORK_TREE/.gitmodules
+
+
+DESCRIPTION
+-----------
+
+The `.gitmodules` file, located in the top-level directory of a Git
+working tree, is a text file with a syntax matching the requirements
+of linkgit:git-config[1].
+
+The file contains one subsection per submodule, and the subsection value
+is the name of the submodule. The name is set to the path where the
+submodule has been added unless it was customized with the `--name`
+option of 'git submodule add'. Each submodule section also contains the
+following required keys:
+
+submodule.<name>.path::
+	Defines the path, relative to the top-level directory of the Git
+	working tree, where the submodule is expected to be checked out.
+	The path name must not end with a `/`. All submodule paths must
+	be unique within the `.gitmodules` file.
+
+submodule.<name>.url::
+	Defines a URL from which the submodule repository can be cloned.
+	This may be either an absolute URL ready to be passed to
+	linkgit:git-clone[1] or (if it begins with `./` or `../`) a location
+	relative to the superproject's origin repository.
+
+In addition, there are a number of optional keys:
+
+submodule.<name>.update::
+	Defines the default update procedure for the named submodule,
+	i.e. how the submodule is updated by the `git submodule update`
+	command in the superproject. This is only used by `git
+	submodule init` to initialize the configuration variable of
+	the same name. Allowed values here are 'checkout', 'rebase',
+	'merge' or 'none', but not '!command' (for security reasons).
+	See the description of the 'update' command in
+	linkgit:git-submodule[1] for more details.
+
+submodule.<name>.branch::
+	A remote branch name for tracking updates in the upstream submodule.
+	If the option is not specified, it defaults to the remote `HEAD`.
+	A special value of `.` is used to indicate that the name of the branch
+	in the submodule should be the same name as the current branch in the
+	current repository.  See the `--remote` documentation in
+	linkgit:git-submodule[1] for details.
+
+submodule.<name>.fetchRecurseSubmodules::
+	This option can be used to control recursive fetching of this
+	submodule. If this option is also present in the submodule's entry in
+	`.git/config` of the superproject, the setting there will override the
+	one found in `.gitmodules`.
+	Both settings can be overridden on the command line by using the
+	`--[no-]recurse-submodules` option to `git fetch` and `git pull`.
+
+submodule.<name>.ignore::
+	Defines under what circumstances `git status` and the diff family show
+	a submodule as modified. The following values are supported:
++
+--
+	all;; The submodule will never be considered modified (but will
+	    nonetheless show up in the output of status and commit when it has
+	    been staged).
+
+	dirty;; All changes to the submodule's work tree will be ignored, only
+	    committed differences between the `HEAD` of the submodule and its
+	    recorded state in the superproject are taken into account.
+
+	untracked;; Only untracked files in submodules will be ignored.
+	    Committed differences and modifications to tracked files will show
+	    up.
+
+	none;; No modifications to submodules are ignored, all of committed
+	    differences, and modifications to tracked and untracked files are
+	    shown. This is the default option.
+
+If this option is also present in the submodule's entry in `.git/config`
+of the superproject, the setting there will override the one found in
+`.gitmodules`.
+
+Both settings can be overridden on the command line by using the
+`--ignore-submodules` option. The `git submodule` commands are not
+affected by this setting.
+--
+
+submodule.<name>.shallow::
+	When set to true, a clone of this submodule will be performed as a
+	shallow clone (with a history depth of 1) unless the user explicitly
+	asks for a non-shallow clone.
+
+NOTES
+-----
+
+Git does not allow the `.gitmodules` file within a working tree to be a
+symbolic link, and will refuse to check out such a tree entry. This
+keeps behavior consistent when the file is accessed from the index or a
+tree versus from the filesystem, and helps Git reliably enforce security
+checks of the file contents.
+
+EXAMPLES
+--------
+
+Consider the following `.gitmodules` file:
+
+----
+[submodule "libfoo"]
+	path = include/foo
+	url = git://foo.com/git/lib.git
+
+[submodule "libbar"]
+	path = include/bar
+	url = git://bar.com/git/lib.git
+----
+
+This defines two submodules, `libfoo` and `libbar`. These are expected to
+be checked out in the paths `include/foo` and `include/bar`, and for both
+submodules a URL is specified which can be used for cloning the submodules.
+
+SEE ALSO
+--------
+linkgit:git-submodule[1], linkgit:gitsubmodules[7], linkgit:git-config[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitnamespaces.adoc b/Documentation/gitnamespaces.adoc
new file mode 100644
index 0000000000..06f4d37efa
--- /dev/null
+++ b/Documentation/gitnamespaces.adoc
@@ -0,0 +1,68 @@
+gitnamespaces(7)
+================
+
+NAME
+----
+gitnamespaces - Git namespaces
+
+SYNOPSIS
+--------
+[verse]
+GIT_NAMESPACE=<namespace> 'git upload-pack'
+GIT_NAMESPACE=<namespace> 'git receive-pack'
+
+
+DESCRIPTION
+-----------
+
+Git supports dividing the refs of a single repository into multiple
+namespaces, each of which has its own branches, tags, and HEAD.  Git can
+expose each namespace as an independent repository to pull from and push
+to, while sharing the object store, and exposing all the refs to
+operations such as linkgit:git-gc[1].
+
+Storing multiple repositories as namespaces of a single repository
+avoids storing duplicate copies of the same objects, such as when
+storing multiple branches of the same source.  The alternates mechanism
+provides similar support for avoiding duplicates, but alternates do not
+prevent duplication between new objects added to the repositories
+without ongoing maintenance, while namespaces do.
+
+To specify a namespace, set the `GIT_NAMESPACE` environment variable to
+the namespace.  For each ref namespace, Git stores the corresponding
+refs in a directory under `refs/namespaces/`.  For example,
+`GIT_NAMESPACE=foo` will store refs under `refs/namespaces/foo/`.  You
+can also specify namespaces via the `--namespace` option to
+linkgit:git[1].
+
+Note that namespaces which include a `/` will expand to a hierarchy of
+namespaces; for example, `GIT_NAMESPACE=foo/bar` will store refs under
+`refs/namespaces/foo/refs/namespaces/bar/`.  This makes paths in
+`GIT_NAMESPACE` behave hierarchically, so that cloning with
+`GIT_NAMESPACE=foo/bar` produces the same result as cloning with
+`GIT_NAMESPACE=foo` and cloning from that repo with `GIT_NAMESPACE=bar`.  It
+also avoids ambiguity with strange namespace paths such as `foo/refs/heads/`,
+which could otherwise generate directory/file conflicts within the `refs`
+directory.
+
+linkgit:git-upload-pack[1] and linkgit:git-receive-pack[1] rewrite the
+names of refs as specified by `GIT_NAMESPACE`.  git-upload-pack and
+git-receive-pack will ignore all references outside the specified
+namespace.
+
+The smart HTTP server, linkgit:git-http-backend[1], will pass
+GIT_NAMESPACE through to the backend programs; see
+linkgit:git-http-backend[1] for sample configuration to expose
+repository namespaces as repositories.
+
+For a simple local test, you can use linkgit:git-remote-ext[1]:
+
+----------
+git clone ext::'git --namespace=foo %s /tmp/prefixed.git'
+----------
+
+include::transfer-data-leaks.adoc[]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitpacking.adoc b/Documentation/gitpacking.adoc
new file mode 100644
index 0000000000..a56596e2d1
--- /dev/null
+++ b/Documentation/gitpacking.adoc
@@ -0,0 +1,195 @@
+gitpacking(7)
+=============
+
+NAME
+----
+gitpacking - Advanced concepts related to packing in Git
+
+SYNOPSIS
+--------
+gitpacking
+
+DESCRIPTION
+-----------
+
+This document aims to describe some advanced concepts related to packing
+in Git.
+
+Many concepts are currently described scattered between manual pages of
+various Git commands, including linkgit:git-pack-objects[1],
+linkgit:git-repack[1], and others, as well as linkgit:gitformat-pack[5],
+and parts of the `Documentation/technical` tree.
+
+There are many aspects of packing in Git that are not covered in this
+document that instead live in the aforementioned areas. Over time, those
+scattered bits may coalesce into this document.
+
+== Pseudo-merge bitmaps
+
+NOTE: Pseudo-merge bitmaps are considered an experimental feature, so
+the configuration and many of the ideas are subject to change.
+
+=== Background
+
+Reachability bitmaps are most efficient when we have on-disk stored
+bitmaps for one or more of the starting points of a traversal. For this
+reason, Git prefers storing bitmaps for commits at the tips of refs,
+because traversals tend to start with those points.
+
+But if you have a large number of refs, it's not feasible to store a
+bitmap for _every_ ref tip. It takes up space, and just OR-ing all of
+those bitmaps together is expensive.
+
+One way we can deal with that is to create bitmaps that represent
+_groups_ of refs. When a traversal asks about the entire group, then we
+can use this single bitmap instead of considering each ref individually.
+Because these bitmaps represent the set of objects which would be
+reachable in a hypothetical merge of all of the commits, we call them
+pseudo-merge bitmaps.
+
+=== Overview
+
+A "pseudo-merge bitmap" is used to refer to a pair of bitmaps, as
+follows:
+
+Commit bitmap::
+
+  A bitmap whose set bits describe the set of commits included in the
+  pseudo-merge's "merge" bitmap (as below).
+
+Merge bitmap::
+
+  A bitmap whose set bits describe the reachability closure over the set
+  of commits in the pseudo-merge's "commits" bitmap (as above). An
+  identical bitmap would be generated for an octopus merge with the same
+  set of parents as described in the commits bitmap.
+
+Pseudo-merge bitmaps can accelerate bitmap traversals when all commits
+for a given pseudo-merge are listed on either side of the traversal,
+either directly (by explicitly asking for them as part of the `HAVES`
+or `WANTS`) or indirectly (by encountering them during a fill-in
+traversal).
+
+=== Use-cases
+
+For example, suppose there exists a pseudo-merge bitmap with a large
+number of commits, all of which are listed in the `WANTS` section of
+some bitmap traversal query. When pseudo-merge bitmaps are enabled, the
+bitmap machinery can quickly determine there is a pseudo-merge which
+satisfies some subset of the wanted objects on either side of the query.
+Then, we can inflate the EWAH-compressed bitmap, and `OR` it in to the
+resulting bitmap. By contrast, without pseudo-merge bitmaps, we would
+have to repeat the decompression and `OR`-ing step over a potentially
+large number of individual bitmaps, which can take proportionally more
+time.
+
+Another benefit of pseudo-merges arises when there is some combination
+of (a) a large number of references, with (b) poor bitmap coverage, and
+(c) deep, nested trees, making fill-in traversal relatively expensive.
+For example, suppose that there are a large enough number of tags where
+bitmapping each of the tags individually is infeasible. Without
+pseudo-merge bitmaps, computing the result of, say, `git rev-list
+--use-bitmap-index --count --objects --tags` would likely require a
+large amount of fill-in traversal. But when a large quantity of those
+tags are stored together in a pseudo-merge bitmap, the bitmap machinery
+can take advantage of the fact that we only care about the union of
+objects reachable from all of those tags, and answer the query much
+faster.
+
+=== Configuration
+
+Reference tips are grouped into different pseudo-merge groups according
+to two criteria. A reference name matches one or more of the defined
+pseudo-merge patterns, and optionally one or more capture groups within
+that pattern which further partition the group.
+
+Within a group, commits may be considered "stable", or "unstable"
+depending on their age. These are adjusted by setting the
+`bitmapPseudoMerge.<name>.stableThreshold` and
+`bitmapPseudoMerge.<name>.threshold` configuration values, respectively.
+
+All stable commits are grouped into pseudo-merges of equal size
+(`bitmapPseudoMerge.<name>.stableSize`). If the `stableSize`
+configuration is set to, say, 100, then the first 100 commits (ordered
+by committer date) which are older than the `stableThreshold` value will
+form one group, the next 100 commits will form another group, and so on.
+
+Among unstable commits, the pseudo-merge machinery will attempt to
+combine older commits into large groups as opposed to newer commits
+which will appear in smaller groups. This is based on the heuristic that
+references whose tip commit is older are less likely to be modified to
+point at a different commit than a reference whose tip commit is newer.
+
+The size of groups is determined by a power-law decay function, and the
+decay parameter roughly corresponds to "k" in `f(n) = C*n^(-k/100)`,
+where `f(n)` describes the size of the `n`-th pseudo-merge group. The
+sample rate controls what percentage of eligible commits are considered
+as candidates. The threshold parameter indicates the minimum age (so as
+to avoid including too-recent commits in a pseudo-merge group, making it
+less likely to be valid). The "maxMerges" parameter sets an upper-bound
+on the number of pseudo-merge commits an individual group
+
+The "stable"-related parameters control "stable" pseudo-merge groups,
+comprised of a fixed number of commits which are older than the
+configured "stable threshold" value and may be grouped together in
+chunks of "stableSize" in order of age.
+
+The exact configuration for pseudo-merges is as follows:
+
+include::config/bitmap-pseudo-merge.adoc[]
+
+=== Examples
+
+Suppose that you have a repository with a large number of references,
+and you want a bare-bones configuration of pseudo-merge bitmaps that
+will enhance bitmap coverage of the `refs/` namespace. You may start
+with a configuration like so:
+
+----
+[bitmapPseudoMerge "all"]
+	pattern = "refs/"
+	threshold = now
+	stableThreshold = never
+	sampleRate = 100
+	maxMerges = 64
+----
+
+This will create pseudo-merge bitmaps for all references, regardless of
+their age, and group them into 64 pseudo-merge commits.
+
+If you wanted to separate tags from branches when generating
+pseudo-merge commits, you would instead define the pattern with a
+capture group, like so:
+
+----
+[bitmapPseudoMerge "all"]
+	pattern = "refs/(heads/tags)/"
+----
+
+Suppose instead that you are working in a fork-network repository, with
+each fork specified by some numeric ID, and whose refs reside in
+`refs/virtual/NNN/` (where `NNN` is the numeric ID corresponding to some
+fork) in the network. In this instance, you may instead write something
+like:
+
+----
+[bitmapPseudoMerge "all"]
+	pattern = "refs/virtual/([0-9]+)/(heads|tags)/"
+	threshold = now
+	stableThreshold = never
+	sampleRate = 100
+	maxMerges = 64
+----
+
+Which would generate pseudo-merge group identifiers like "1234-heads",
+and "5678-tags" (for branches in fork "1234", and tags in remote "5678",
+respectively).
+
+SEE ALSO
+--------
+linkgit:git-pack-objects[1]
+linkgit:git-repack[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitprotocol-capabilities.adoc b/Documentation/gitprotocol-capabilities.adoc
new file mode 100644
index 0000000000..2cf7735be4
--- /dev/null
+++ b/Documentation/gitprotocol-capabilities.adoc
@@ -0,0 +1,396 @@
+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 linkgit:gitprotocol-v2[5]
+doc.
+
+Servers SHOULD support all capabilities defined in this document.
+
+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.
+
+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.
+
+Server MUST diagnose and abort if capabilities it does not understand
+were 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.
+
+The 'atomic', 'report-status', 'report-status-v2', 'delete-refs', 'quiet',
+and 'push-cert' capabilities are sent and recognized by the receive-pack
+(push to server) process.
+
+The 'ofs-delta' and 'side-band-64k' capabilities are sent and recognized
+by both upload-pack and receive-pack protocols.  The 'agent' and 'session-id'
+capabilities may optionally be sent in both protocols.
+
+All other capabilities are only recognized by the upload-pack (fetch
+from server) process.
+
+multi_ack
+---------
+
+The 'multi_ack' 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's wants and the client's have set.
+
+By sending this early, the server can potentially head off the client
+from walking any further down that particular branch of the client'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".
+
+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 on which the server hasn't found
+a common base yet.
+
+For example suppose the client has commits in caps that the server
+doesn't and the server has commits in lower case that the client
+doesn't, as in the following diagram:
+
+       +---- u ---------------------- x
+      /              +----- y
+     /              /
+    a -- b -- c -- d -- E -- F
+       \
+	+--- Q -- R -- S
+
+If the client wants x,y and starts out by saying have F,S, the server
+doesn'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't send c-b-a), but it'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.
+
+Without multi_ack the client would have sent that c-b-a chain anyway,
+interleaved with S-R-Q.
+
+multi_ack_detailed
+------------------
+This is an extension of multi_ack that permits the client to better
+understand the server's in-memory state. See linkgit:gitprotocol-pack[5],
+section "Packfile Negotiation" for more information.
+
+no-done
+-------
+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.
+
+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.
+
+thin-pack
+---------
+
+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.
+
+The upload-pack server advertises 'thin-pack' when it can generate
+and send a thin pack. A client requests the 'thin-pack' capability
+when it understands how to "thicken" it, notifying the server that
+it can receive such a pack. A client MUST NOT request the
+'thin-pack' capability if it cannot turn a thin pack into a
+self-contained pack.
+
+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 'no-thin' capability. A client MUST NOT send a thin
+pack if the server advertises the 'no-thin' capability.
+
+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 'no-thin' later allowed receive-pack
+to disable the feature in a backwards-compatible manner.
+
+
+side-band, side-band-64k
+------------------------
+
+This capability means that the server can send, and the client can understand, multiplexed
+progress reports and error info interleaved with the packfile itself.
+
+These two options are mutually exclusive. A modern client always
+favors 'side-band-64k'.
+
+Either mode indicates that the packfile data will be streamed broken
+up into packets of up to either 1000 bytes in the case of 'side_band',
+or 65520 bytes in the case of 'side_band_64k'. 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.
+
+The stream code can be one of:
+
+ 1 - pack data
+ 2 - progress messages
+ 3 - fatal error message just before stream aborts
+
+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.
+
+Further, with side-band and its up to 1000-byte messages, it'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.
+
+The client MUST send only one of "side-band" and "side-
+band-64k".  The server MUST diagnose it as an error if client requests
+both.
+
+ofs-delta
+---------
+
+The server can send, and the client can 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.
+
+agent
+-----
+
+The server may optionally send a capability of the form `agent=X` to
+notify the client that the server is running version `X`. The client may
+optionally return its own agent string by responding with an `agent=Y`
+capability (but it MUST NOT do so if the server did not mention the
+agent capability). The `X` and `Y` strings may contain any printable
+ASCII characters except space (i.e., the byte range 32 < x < 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.
+
+object-format
+-------------
+
+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.
+
+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.
+
+If this capability is not provided, it is assumed that the only
+supported algorithm is SHA-1.
+
+symref
+------
+
+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.
+
+Servers SHOULD include this capability for the HEAD symref if it is one of the
+refs being sent.
+
+Clients MAY use the parameters from this capability to select the proper initial
+branch when cloning a repository.
+
+shallow
+-------
+
+This capability adds "deepen", "shallow" and "unshallow" commands to
+the  fetch-pack/upload-pack protocol so clients can request shallow
+clones.
+
+deepen-since
+------------
+
+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's equivalent of doing
+"rev-list --max-age=<timestamp>" on the server side. "deepen-since"
+cannot be used with "deepen".
+
+deepen-not
+----------
+
+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's equivalent of
+doing "rev-list --not <rev>" on the server side. "deepen-not"
+cannot be used with "deepen", but can be used with "deepen-since".
+
+deepen-relative
+---------------
+
+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.
+
+no-progress
+-----------
+
+The client was started with "git clone -q" or something similar, and doesn'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.
+
+include-tag
+-----------
+
+The 'include-tag' 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.
+
+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's desires for tag
+data, whether or not a server had advertised objects in the
+refs/tags/* namespace.
+
+Servers MUST pack the tags if their referent is packed and the client
+has requested include-tags.
+
+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.
+
+The server SHOULD send include-tag, if it supports it, regardless
+of whether or not there are tags available.
+
+report-status
+-------------
+
+The receive-pack process can receive a 'report-status' 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 linkgit:gitprotocol-pack[5]
+for example messages.
+
+report-status-v2
+----------------
+
+Capability 'report-status-v2' extends capability 'report-status' 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
+'report-status' cannot report for such case.  See linkgit:gitprotocol-pack[5]
+for details.
+
+delete-refs
+-----------
+
+If the server sends back the 'delete-refs' 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.
+
+quiet
+-----
+
+If the receive-pack server advertises the 'quiet' 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 'quiet' capability to suppress server-side progress
+reporting if the local progress reporting is also being suppressed
+(e.g., via `push -q`, or if stderr does not go to a tty).
+
+atomic
+------
+
+If the server sends the 'atomic' 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.
+
+push-options
+------------
+
+If the server sends the 'push-options' 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.
+
+allow-tip-sha1-in-want
+----------------------
+
+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 'object-format' capability.
+
+allow-reachable-sha1-in-want
+----------------------------
+
+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 'object-format' capability.
+
+push-cert=<nonce>
+-----------------
+
+The receive-pack server that advertises this capability is willing
+to accept a signed push certificate, and asks the <nonce> 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.
+
+filter
+------
+
+If the upload-pack server advertises the 'filter' 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.
+
+session-id=<session-id>
+-----------------------
+
+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.
+
+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
+link:technical/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/Documentation/gitprotocol-common.adoc b/Documentation/gitprotocol-common.adoc
new file mode 100644
index 0000000000..cdc9d6e707
--- /dev/null
+++ b/Documentation/gitprotocol-common.adoc
@@ -0,0 +1,118 @@
+gitprotocol-common(5)
+=====================
+
+NAME
+----
+gitprotocol-common - Things common to various protocols
+
+SYNOPSIS
+--------
+[verse]
+<over-the-wire-protocol>
+
+DESCRIPTION
+-----------
+
+This document defines things common to various over-the-wire
+protocols and file formats used in Git.
+
+ABNF Notation
+-------------
+
+ABNF notation as described by RFC 5234 is used within the protocol documents,
+except the following replacement core rules are used:
+----
+  HEXDIG    =  DIGIT / "a" / "b" / "c" / "d" / "e" / "f"
+----
+
+We also define the following common rules:
+----
+  NUL       =  %x00
+  zero-id   =  40*"0"
+  obj-id    =  40*(HEXDIGIT)
+
+  refname  =  "HEAD"
+  refname /=  "refs/" <see discussion below>
+----
+
+A refname is a hierarchical octet string beginning with "refs/" and
+not violating the 'git-check-ref-format' command's validation rules.
+More specifically, they:
+
+. They can include slash `/` for hierarchical (directory)
+  grouping, but no slash-separated component can begin with a
+  dot `.`.
+
+. They must contain at least one `/`. This enforces the presence of a
+  category like `heads/`, `tags/` etc. but the actual names are not
+  restricted.
+
+. They cannot have two consecutive dots `..` anywhere.
+
+. They cannot have ASCII control characters (i.e. bytes whose
+  values are lower than \040, or \177 `DEL`), space, tilde `~`,
+  caret `^`, colon `:`, question-mark `?`, asterisk `*`,
+  or open bracket `[` anywhere.
+
+. They cannot end with a slash `/` or a dot `.`.
+
+. They cannot end with the sequence `.lock`.
+
+. They cannot contain a sequence `@{`.
+
+. They cannot contain a `\\`.
+
+
+pkt-line Format
+---------------
+
+Much (but not all) of the payload is described around pkt-lines.
+
+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's hexadecimal representation.
+
+A pkt-line MAY contain binary data, so implementors MUST ensure
+pkt-line parsing/formatting routines are 8-bit clean.
+
+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).
+
+The maximum length of a pkt-line'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).
+
+Implementations SHOULD NOT send an empty pkt-line ("0004").
+
+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").
+
+----
+  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"
+----
+
+Examples (as C-style strings):
+
+----
+  pkt-line          actual value
+  ---------------------------------
+  "0006a\n"         "a\n"
+  "0005a"           "a"
+  "000bfoobar\n"    "foobar\n"
+  "0004"            ""
+----
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitprotocol-http.adoc b/Documentation/gitprotocol-http.adoc
new file mode 100644
index 0000000000..ec40a550cc
--- /dev/null
+++ b/Documentation/gitprotocol-http.adoc
@@ -0,0 +1,543 @@
+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
+connection, and a "smart" protocol which requires a Git aware CGI
+(or server module).  This document describes both protocols.
+
+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.
+
+
+URL Format
+----------
+
+URLs for Git repositories accessed by HTTP use the standard HTTP
+URL syntax documented by RFC 1738, so they are of the form:
+
+  http://<host>:<port>/<path>?<searchpart>
+
+Within this documentation the placeholder `$GIT_URL` will stand for
+the http:// repository URL entered by the end-user.
+
+Servers SHOULD handle all requests to locations matching `$GIT_URL`, as
+both the "smart" and "dumb" HTTP protocols used by Git operate
+by appending additional path components onto the end of the user
+supplied `$GIT_URL` string.
+
+An example of a dumb client requesting a loose object:
+
+  $GIT_URL:     http://example.com:8080/git/repo.git
+  URL request:  http://example.com:8080/git/repo.git/objects/d0/49f6c27a2244e12041955e262a404c7faba355
+
+An example of a smart request to a catch-all gateway:
+
+  $GIT_URL:     http://example.com/daemon.cgi?svc=git&q=
+  URL request:  http://example.com/daemon.cgi?svc=git&q=/info/refs&service=git-receive-pack
+
+An example of a request to a submodule:
+
+  $GIT_URL:     http://example.com/git/repo.git/path/submodule.git
+  URL request:  http://example.com/git/repo.git/path/submodule.git/info/refs
+
+Clients MUST strip a trailing `/`, if present, from the user supplied
+`$GIT_URL` string to prevent empty path tokens (`//`) from appearing
+in any URL sent to a server.  Compatible clients MUST expand
+`$GIT_URL/info/refs` as `foo/info/refs` and not `foo//info/refs`.
+
+
+Authentication
+--------------
+
+Standard HTTP authentication is used if authentication is required
+to access a repository, and MAY be configured and enforced by the
+HTTP server software.
+
+Because Git repositories are accessed by standard path components
+server administrators MAY use directory based permissions within
+their HTTP server to control repository access.
+
+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.
+
+Servers SHOULD NOT require HTTP cookies for the purposes of
+authentication or access control.
+
+Clients and servers MAY support other common forms of HTTP based
+authentication, such as Digest authentication.
+
+
+SSL
+---
+
+Clients and servers SHOULD support SSL, particularly to protect
+passwords when relying on Basic HTTP authentication.
+
+
+Session State
+-------------
+
+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.
+
+Clients MUST NOT require state management on the server side in
+order to function correctly.
+
+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.
+
+
+General Request Processing
+--------------------------
+
+Except where noted, all standard HTTP behavior SHOULD be assumed
+by both client and server.  This includes (but is not necessarily
+limited to):
+
+If there is no repository at `$GIT_URL`, or the resource pointed to by a
+location matching `$GIT_URL` does not exist, the server MUST NOT respond
+with `200 OK` response.  A server SHOULD respond with
+`404 Not Found`, `410 Gone`, or any other suitable HTTP status code
+which does not imply the resource exists as requested.
+
+If there is a repository at `$GIT_URL`, but access is not currently
+permitted, the server MUST respond with the `403 Forbidden` HTTP
+status code.
+
+Servers SHOULD support both HTTP 1.0 and HTTP 1.1.
+Servers SHOULD support chunked encoding for both request and response
+bodies.
+
+Clients SHOULD support both HTTP 1.0 and HTTP 1.1.
+Clients SHOULD support chunked encoding for both request and response
+bodies.
+
+Servers MAY return ETag and/or Last-Modified headers.
+
+Clients MAY revalidate cached entities by including If-Modified-Since
+and/or If-None-Match request headers.
+
+Servers MAY return `304 Not Modified` if the relevant headers appear
+in the request and the entity has not changed.  Clients MUST treat
+`304 Not Modified` identical to `200 OK` by reusing the cached entity.
+
+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.
+
+
+Discovering References
+----------------------
+
+All HTTP clients MUST begin either a fetch or a push exchange by
+discovering the references available on the remote repository.
+
+Dumb Clients
+~~~~~~~~~~~~
+
+HTTP clients that only support the "dumb" protocol MUST discover
+references by making a request for the special info/refs file of
+the repository.
+
+Dumb HTTP clients MUST make a `GET` request to `$GIT_URL/info/refs`,
+without any search/query parameters.
+
+   C: GET $GIT_URL/info/refs HTTP/1.0
+
+   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^{}
+
+The Content-Type of the returned info/refs entity SHOULD be
+`text/plain; charset=utf-8`, 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
+`application/x-git-`.
+
+Cache-Control headers MAY be returned to disable caching of the
+returned entity.
+
+When examining the response clients SHOULD only examine the HTTP
+status code.  Valid responses are `200 OK`, or `304 Not Modified`.
+
+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 `HEAD`.
+
+  info_refs   =  *( ref_record )
+  ref_record  =  any_ref / peeled_ref
+
+  any_ref     =  obj-id HTAB refname LF
+  peeled_ref  =  obj-id HTAB refname LF
+		 obj-id HTAB refname "^{}" LF
+
+Smart Clients
+~~~~~~~~~~~~~
+
+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.
+
+The request MUST contain exactly one query parameter,
+`service=$servicename`, where `$servicename` MUST be the service
+name the client wishes to contact to complete the operation.
+The request MUST NOT contain additional query parameters.
+
+   C: GET $GIT_URL/info/refs?service=git-upload-pack HTTP/1.0
+
+dumb server reply:
+
+   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^{}
+
+smart server reply:
+
+   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
+
+The client may send Extra Parameters (see
+linkgit:gitprotocol-pack[5]) as a colon-separated string
+in the Git-Protocol HTTP header.
+
+Uses the `--http-backend-info-refs` option to
+linkgit:git-upload-pack[1].
+
+Dumb Server Response
+^^^^^^^^^^^^^^^^^^^^
+Dumb servers MUST respond with the dumb server reply format.
+
+See the prior section under dumb clients for a more detailed
+description of the dumb server response.
+
+Smart Server Response
+^^^^^^^^^^^^^^^^^^^^^
+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 `403 Forbidden` HTTP status code.
+
+Otherwise, smart servers MUST respond with the smart server reply
+format for the requested service name.
+
+Cache-Control headers SHOULD be used to disable caching of the
+returned entity.
+
+The Content-Type MUST be `application/x-$servicename-advertisement`.
+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 `$GIT_URL/info/refs`, but
+instead SHOULD use the response already in hand.  Clients MUST NOT
+continue if they do not support the dumb protocol.
+
+Clients MUST validate the status code is either `200 OK` or
+`304 Not Modified`.
+
+Clients MUST validate the first five bytes of the response entity
+matches the regex `^[0-9a-f]{4}#`.  If this test fails, clients
+MUST NOT continue.
+
+Clients MUST parse the entire response as a sequence of pkt-line
+records.
+
+Clients MUST verify the first pkt-line is `# service=$servicename`.
+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.
+
+Servers MUST terminate the response with the magic `0000` end
+pkt-line marker.
+
+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 `HEAD` as the first ref.  The stream MUST include capability
+declarations behind a NUL on the first ref.
+
+The returned response contains "version 1" if "version=1" was sent as an
+Extra Parameter.
+
+  smart_reply     =  PKT-LINE("# service=$servicename" LF)
+		     "0000"
+		     *1("version 1")
+		     ref_list
+		     "0000"
+  ref_list        =  empty_list / non_empty_list
+
+  empty_list      =  PKT-LINE(zero-id SP "capabilities^{}" NUL cap-list LF)
+
+  non_empty_list  =  PKT-LINE(obj-id SP name NUL cap_list LF)
+		     *ref_record
+
+  cap-list        =  capability *(SP capability)
+  capability      =  1*(LC_ALPHA / DIGIT / "-" / "_")
+  LC_ALPHA        =  %x61-7A
+
+  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
+
+
+Smart Service git-upload-pack
+------------------------------
+This service reads from the repository pointed to by `$GIT_URL`.
+
+Clients MUST first perform ref discovery with
+`$GIT_URL/info/refs?service=git-upload-pack`.
+
+   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
+
+   S: 200 OK
+   S: Content-Type: application/x-git-upload-pack-result
+   S: Cache-Control: no-cache
+   S:
+   S: ....ACK %s, continue
+   S: ....NAK
+
+Clients MUST NOT reuse or revalidate a cached response.
+Servers MUST include sufficient Cache-Control headers
+to prevent caching of the response.
+
+Servers SHOULD support all capabilities defined here.
+
+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 `allow-tip-sha1-in-want` or
+`allow-reachable-sha1-in-want`.
+
+  compute_request   =  want_list
+		       have_list
+		       request_end
+  request_end       =  "0000" / "done"
+
+  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)
+
+  have_list         =  *PKT-LINE("have" SP id LF)
+
+TODO: Document this further.
+
+The Negotiation Algorithm
+~~~~~~~~~~~~~~~~~~~~~~~~~
+The computation to select the minimal pack proceeds as follows
+(C = client, S = server):
+
+'init step:'
+
+C: Use ref discovery to obtain the advertised refs.
+
+C: Place any object seen into set `advertised`.
+
+C: Build an empty set, `common`, to hold the objects that are later
+   determined to be on both ends.
+
+C: Build a set, `want`, of the objects from `advertised` that the client
+   wants to fetch, based on what it saw during ref discovery.
+
+C: Start a queue, `c_pending`, 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.
+
+'one compute step:'
+
+C: Send one `$GIT_URL/git-upload-pack` request:
+
+   C: 0032want <want-#1>...............................
+   C: 0032want <want-#2>...............................
+   ....
+   C: 0032have <common-#1>.............................
+   C: 0032have <common-#2>.............................
+   ....
+   C: 0032have <have-#1>...............................
+   C: 0032have <have-#2>...............................
+   ....
+   C: 0000
+
+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.
+
+Commands MUST appear in the following order, if they appear
+at all in the request stream:
+
+* "want"
+* "have"
+
+The stream is terminated by a pkt-line flush (`0000`).
+
+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 `object-format` capability (default SHA-1).
+
+The `have` list is created by popping the first 32 commits
+from `c_pending`.  Fewer can be supplied if `c_pending` empties.
+
+If the client has sent 256 "have" commits and has not yet
+received one of those back from `s_common`, or the client has
+emptied `c_pending` it SHOULD include a "done" command to let
+the server know it won't proceed:
+
+   C: 0009done
+
+S: Parse the git-upload-pack request:
+
+Verify all objects in `want` are directly reachable from refs.
+
+The server MAY walk backwards through history or through
+the reflog to permit slightly stale requests.
+
+If no "want" objects are received, send an error:
+TODO: Define error if no "want" lines are requested.
+
+If any "want" object is not reachable, send an error:
+TODO: Define error if an invalid "want" is requested.
+
+Create an empty list, `s_common`.
+
+If "have" was sent:
+
+Loop through the objects in the order supplied by the client.
+
+For each object, if the server has the object reachable from
+a ref, add it to `s_common`.  If a commit is added to `s_common`,
+do not add any ancestors, even if they also appear in `have`.
+
+S: Send the git-upload-pack response:
+
+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
+
+   S: PACK...
+
+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.
+
+Here a "closed set of objects" is defined to have at least
+one path from every "want" to at least one "common" object.
+
+If the server needs more information, it replies with a
+status continue response:
+TODO: Document the non-pack response
+
+C: Parse the upload-pack response:
+   TODO: Document parsing response
+
+'Do another compute step.'
+
+
+Smart Service git-receive-pack
+------------------------------
+This service reads from the repository pointed to by `$GIT_URL`.
+
+Clients MUST first perform ref discovery with
+`$GIT_URL/info/refs?service=git-receive-pack`.
+
+   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....
+
+   S: 200 OK
+   S: Content-Type: application/x-git-receive-pack-result
+   S: Cache-Control: no-cache
+   S:
+   S: ....
+
+Clients MUST NOT reuse or revalidate a cached response.
+Servers MUST include sufficient Cache-Control headers
+to prevent caching of the response.
+
+Servers SHOULD support all capabilities defined here.
+
+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.
+
+  update_request  =  command_list
+		     "PACK" <binary-data>
+
+  command_list    =  PKT-LINE(command NUL cap_list LF)
+		     *(command_pkt)
+  command_pkt     =  PKT-LINE(command LF)
+  cap_list        =  *(SP capability) SP
+
+  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
+
+TODO: Document this further.
+
+REFERENCES
+----------
+
+https://www.ietf.org/rfc/rfc1738.txt[RFC 1738: Uniform Resource Locators (URL)]
+https://www.ietf.org/rfc/rfc2616.txt[RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1]
+
+SEE ALSO
+--------
+
+linkgit:gitprotocol-pack[5]
+linkgit:gitprotocol-capabilities[5]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitprotocol-pack.adoc b/Documentation/gitprotocol-pack.adoc
new file mode 100644
index 0000000000..837b691c89
--- /dev/null
+++ b/Documentation/gitprotocol-pack.adoc
@@ -0,0 +1,725 @@
+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 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;
+then 'receive-pack' on the server and 'send-pack' 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.
+
+pkt-line Format
+---------------
+
+The descriptions below build on the pkt-line format described in
+linkgit:gitprotocol-common[5]. When the grammar indicates `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.
+
+An error packet is a special pkt-line that contains an error string.
+
+----
+  error-line     =  PKT-LINE("ERR" SP explanation-text)
+----
+
+Throughout the protocol, where `PKT-LINE(...)` 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.
+
+Transports
+----------
+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 'upload-pack', though Git
+servers can be configured to be globally writable, in which 'receive-
+pack' initiation is also allowed) with which the client wishes to
+communicate and executes it and connects it to the requesting
+process.
+
+In the SSH transport, the client just runs the 'upload-pack'
+or 'receive-pack' process on the server over the SSH protocol and then
+communicates with that invoked process over the SSH connection.
+
+The file:// transport runs the 'upload-pack' or 'receive-pack'
+process locally and communicates with it over a pipe.
+
+Extra Parameters
+----------------
+
+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.
+
+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 linkgit:gitprotocol-v2[5] for more
+information on protocol version 2.
+
+Git Transport
+-------------
+
+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.
+
+   0033git-upload-pack /project.git\0host=myserver.com\0
+
+The transport may send Extra Parameters by adding an additional NUL
+byte, and then adding one or more NUL-terminated strings:
+
+   003egit-upload-pack /project.git\0host=myserver.com\0\0version=1\0
+
+--
+   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
+--
+
+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.
+
+Basically what the Git client is doing to connect to an 'upload-pack'
+process on the server side over the Git protocol is this:
+
+   $ echo -e -n \
+     "003agit-upload-pack /schacon/gitbook.git\0host=example.com\0" |
+     nc -v example.com 9418
+
+
+SSH Transport
+-------------
+
+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:
+
+   $ ssh git.example.com "git-upload-pack '/project.git'"
+
+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.
+
+In an ssh:// format URI, it's absolute in the URI, so the '/' 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's effectively
+an absolute path in the remote filesystem.
+
+       git clone ssh://user@xxxxxxxxxxx/project.git
+		    |
+		    v
+    ssh user@xxxxxxxxxxx "git-upload-pack '/project.git'"
+
+In a "user@host:path" format URI, it's relative to the user's home
+directory, because the Git client will run:
+
+     git clone user@xxxxxxxxxxx:project.git
+		    |
+		    v
+  ssh user@xxxxxxxxxxx "git-upload-pack 'project.git'"
+
+The exception is if a '~' is used, in which case
+we execute it without the leading '/'.
+
+      ssh://user@xxxxxxxxxxx/~alice/project.git,
+		     |
+		     v
+   ssh user@xxxxxxxxxxx "git-upload-pack '~alice/project.git'"
+
+Depending on the value of the `protocol.version` 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 `ssh.variant` configuration variable indicates that the ssh command
+supports passing environment variables as an argument.
+
+A few things to remember here:
+
+- The "command name" is spelled with dash (e.g. git-upload-pack), but
+  this can be overridden by the client;
+
+- The repository path is always quoted with single quotes.
+
+Fetching Data From a Server
+---------------------------
+
+When one Git repository wants to get data that a second repository
+has, the first can 'fetch' 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.
+
+
+Reference Discovery
+-------------------
+
+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.
+
+   $ 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
+
+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.
+
+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.
+
+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's an annotated tag.
+
+----
+  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
+----
+
+Server and client MUST use lowercase for obj-id, both MUST treat obj-id
+as case-insensitive.
+
+See protocol-capabilities.txt for a list of allowed server capabilities
+and descriptions.
+
+Packfile Negotiation
+--------------------
+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.
+
+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 'want' line.
+
+----
+  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)
+----
+
+Clients MUST send all the obj-ids it wants from the reference
+discovery phase as 'want' lines. Clients MUST send at least one
+'want' command in the request body. Clients MUST NOT mention an
+obj-id in a 'want' command which did not appear in the response
+obtained through ref discovery.
+
+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
+'shallow' lines so that the server is aware of the limitations of
+the client's history.
+
+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 'deepen' 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.
+
+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 'want' line. See `rev-list`
+for possible filter-spec values.
+
+Once all the 'want's and 'shallow's (and optional 'deepen') are
+transferred, clients MUST send a flush-pkt, to tell the server side
+that it is done sending the list.
+
+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.
+
+----
+  shallow-update   =  *shallow-line
+		      *unshallow-line
+		      flush-pkt
+
+  shallow-line     =  PKT-LINE("shallow" SP obj-id)
+
+  unshallow-line   =  PKT-LINE("unshallow" SP obj-id)
+----
+
+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 starts at the client's wants.
+
+The server writes 'shallow' lines for each
+commit whose parents will not be sent as a result. The server writes
+an 'unshallow' 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.
+
+Now the client will send a list of the obj-ids it has using 'have'
+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.
+
+----
+  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")
+----
+
+If the server reads 'have' 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.
+
+In multi_ack mode:
+
+  * the server will respond with 'ACK obj-id continue' for any common
+    commits.
+
+  * once the server has found an acceptable common base commit and is
+    ready to make a packfile, it will blindly ACK all 'have' obj-ids
+    back to the client.
+
+  * the server will then send a 'NAK' and then wait for another response
+    from the client - either a 'done' or another list of 'have' lines.
+
+In multi_ack_detailed mode:
+
+  * the server will differentiate the ACKs where it is signaling
+    that it is ready to send data with 'ACK obj-id ready' lines, and
+    signals the identified common commits with 'ACK obj-id common' lines.
+
+Without either multi_ack or multi_ack_detailed:
+
+ * 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".
+
+ * 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's silent on the flush-pkt.
+
+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 'have' 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 'done' command.  The 'done' command signals to the server that the client
+is ready to receive its packfile data.
+
+However, the 256 limit *only* 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.
+
+Once the 'done' line is read from the client, the server will either
+send a final 'ACK obj-id' or it will send a 'NAK'. 'obj-id' is the object
+name of the last commit determined to be common. The server only sends
+ACK after 'done' if there is at least one common base and multi_ack or
+multi_ack_detailed is enabled. The server always sends NAK after 'done'
+if there is no common base found.
+
+Instead of 'ACK' or 'NAK', the server may send an error message (for
+example, if it does not recognize an object in a 'want' line received
+from the client).
+
+Then the server will start sending its packfile data.
+
+----
+  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")
+----
+
+A simple clone may look like this (with no 'have' lines):
+
+----
+   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]
+----
+
+An incremental update (fetch) response might look like this:
+
+----
+   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]
+----
+
+
+Packfile Data
+-------------
+
+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 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.
+
+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.
+
+In 'side-band' 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 'side-band-64k'
+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.
+
+The sideband byte will be a '1', '2' or a '3'. Sideband '1' will contain
+packfile data, sideband '2' will be used for progress information that the
+client will generally print to stderr and sideband '3' is used for error
+information.
+
+If no 'side-band' capability was specified, the server will stream the
+entire packfile without multiplexing.
+
+
+Pushing Data To a Server
+------------------------
+
+Pushing data to a server will invoke the 'receive-pack' 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.
+
+Authentication
+--------------
+
+The protocol itself contains no authentication mechanisms.  That is to be
+handled by the transport, such as SSH, before the 'receive-pack' process is
+invoked.  If 'receive-pack' is configured over the Git transport, those
+repositories will be writable by anyone who can access that port (9418) as
+that transport is unauthenticated.
+
+Reference Discovery
+-------------------
+
+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 'report-status', 'report-status-v2', 'delete-refs',
+'ofs-delta', 'atomic' and 'push-options'.
+
+Reference Update Request and Packfile Transfer
+----------------------------------------------
+
+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.
+
+This list is followed by a flush-pkt.
+
+----
+  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 )
+----
+
+If the server has advertised the 'push-options' capability and the client has
+specified 'push-options' as part of the capability list above, the client then
+sends its push options followed by a flush-pkt.
+
+----
+  push-options      =  *PKT-LINE(push-option) flush-pkt
+----
+
+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.
+
+After that the packfile that
+should contain all the objects that the server will need to complete the new
+references will be sent.
+
+----
+  packfile          =  "PACK" 28*(OCTET)
+----
+
+If the receiving end does not support delete-refs, the sending end MUST
+NOT ask for delete command.
+
+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.
+
+The packfile MUST NOT be sent if the only command used is 'delete'.
+
+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.
+
+The server will receive the packfile, unpack it, then validate each
+reference that is being updated that it hasn'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.
+
+Push Certificate
+----------------
+
+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 _not_
+optional; it must be present.
+
+Currently, the following header fields are defined:
+
+`pusher` ident::
+	Identify the GPG key in "Human Readable Name <email@address>"
+	format.
+
+`pushee` url::
+	The repository URL (anonymized, if the URL contains
+	authentication material) the user who ran `git push`
+	intended to push into.
+
+`nonce` nonce::
+	The 'nonce' string the receiving repository asked the
+	pushing user to include in the certificate, to prevent
+	replay attacks.
+
+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.
+
+Report Status
+-------------
+
+After receiving the pack data from the sender, the receiver sends a
+report if 'report-status' or 'report-status-v2' 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 'unpack ok' or
+'unpack [error]'.  Then it will list the status for each of the references
+that it tried to update.  Each line is either 'ok [refname]' if the
+update was successful, or 'ng [refname] [error]' if the update was not.
+
+----
+  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"
+----
+
+The 'report-status-v2' capability extends the protocol by adding new option
+lines in order to support reporting of reference rewritten by the
+'proc-receive' hook.  The 'proc-receive' 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.
+
+----
+  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")
+
+----
+
+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.
+
+An example client/server communication might look like this:
+
+----
+   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
+----
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitprotocol-v2.adoc b/Documentation/gitprotocol-v2.adoc
new file mode 100644
index 0000000000..1652fef3ae
--- /dev/null
+++ b/Documentation/gitprotocol-v2.adoc
@@ -0,0 +1,786 @@
+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:
+
+  * Instead of multiple service names, multiple commands will be
+    supported by a single service
+  * 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
+  * Separate out other information hidden behind NUL bytes (e.g. agent
+    string as a capability and symrefs can be requested using 'ls-refs')
+  * Reference advertisement will be omitted unless explicitly requested
+  * ls-refs command to explicitly request some refs
+  * Designed with http and stateless-rpc in mind.  With clear flush
+    semantics the http remote helper can simply act as a proxy
+
+In protocol v2 communication is command oriented.  When first contacting a
+server a list of capabilities will be 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.
+
+Packet-Line Framing
+-------------------
+
+All communication is done using packet-line framing, just as in v1.  See
+linkgit:gitprotocol-pack[5] and linkgit:gitprotocol-common[5] for more information.
+
+In protocol v2 these special packets will have the following semantics:
+
+  * '0000' Flush Packet (flush-pkt) - indicates the end of a message
+  * '0001' Delimiter Packet (delim-pkt) - separates sections of a message
+  * '0002' Response End Packet (response-end-pkt) - indicates the end of a
+    response for stateless connections
+
+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 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.
+
+Git Transport
+~~~~~~~~~~~~~
+
+When using the git:// transport, you can request to use protocol v2 by
+sending "version=2" as an extra parameter:
+
+   003egit-upload-pack /project.git\0host=myserver.com\0\0version=2\0
+
+SSH and File Transport
+~~~~~~~~~~~~~~~~~~~~~~
+
+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.
+
+HTTP Transport
+~~~~~~~~~~~~~~
+
+When using the http:// or https:// transport a client makes a "smart"
+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
+   C: Git-Protocol: version=2
+
+A v2 server would reply:
+
+   S: 200 OK
+   S: <Some headers>
+   S: ...
+   S:
+   S: 000eversion 2\n
+   S: <capability-advertisement>
+
+Subsequent requests are then made directly to the service
+`$GIT_URL/git-upload-pack`. (This works the same for git-receive-pack).
+
+Uses the `--http-backend-info-refs` option to
+linkgit:git-upload-pack[1].
+
+The server may need to be configured to pass this header's contents via
+the `GIT_PROTOCOL` variable. See the discussion in `git-http-backend.txt`.
+
+Capability Advertisement
+------------------------
+
+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.
+
+    capability-advertisement = protocol-version
+			       capability-list
+			       flush-pkt
+
+    protocol-version = PKT-LINE("version 2" LF)
+    capability-list = *capability
+    capability = PKT-LINE(key[=value] LF)
+
+    key = 1*(ALPHA | DIGIT | "-_")
+    value = 1*(ALPHA | DIGIT | " -_.,?\/{}[]()<>!@#$%^&*+=:;")
+
+Command Request
+---------------
+
+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.
+
+    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
+
+    command-specific-args are packet line framed arguments defined by
+    each individual command.
+
+The server will then check to ensure that the client'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'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.
+
+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.
+
+Capabilities
+------------
+
+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).
+
+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.
+
+agent
+~~~~~
+
+The server can advertise the `agent` capability with a value `X` (in the
+form `agent=X`) to notify the client that the server is running version
+`X`.  The client may optionally send its own agent string by including
+the `agent` capability with a value `Y` (in the form `agent=Y`) in its
+request to the server (but it MUST NOT do so if the server did not
+advertise the agent capability). The `X` and `Y` strings may contain any
+printable ASCII characters except space (i.e., the byte range 32 < x <
+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.
+
+ls-refs
+~~~~~~~
+
+`ls-refs` 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.
+
+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: "<command>=<feature-1> <feature-2>"
+
+ls-refs takes in the following arguments:
+
+    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 <prefix>
+	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.
+
+If the 'unborn' feature is advertised the following argument can be
+included in the client's request.
+
+    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:<target>".
+
+The output of ls-refs is as follows:
+
+    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
+
+fetch
+~~~~~
+
+`fetch` 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 `ls-refs` command fills that role) and the
+message format is tweaked to eliminate redundancies and permit easy
+addition of future extensions.
+
+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: "<command>=<feature-1> <feature-2>"
+
+A `fetch` request can take the following arguments:
+
+    want <oid>
+	Indicates to the server an object which the client wants to
+	retrieve.  Wants can be anything and are not limited to
+	advertised objects.
+
+    have <oid>
+	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.
+
+    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.
+
+    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.
+
+    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.
+
+    include-tag
+	Request that annotated tags should be sent if the objects they
+	point to are being sent.
+
+    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.
+
+If the 'shallow' feature is advertised the following arguments can be
+included in the clients request as well as the potential addition of the
+'shallow-info' section in the server's response as explained below.
+
+    shallow <oid>
+	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 <oid>' 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.
+
+    deepen <depth>
+	Requests that the fetch/clone should be shallow having a commit
+	depth of <depth> relative to the remote side.
+
+    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.
+
+    deepen-since <timestamp>
+	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=<timestamp>". Cannot be used with
+	"deepen".
+
+    deepen-not <rev>
+	Requests that the shallow clone/fetch should be cut at a
+	specific revision specified by '<rev>', instead of a depth.
+	Internally it's equivalent of doing "git rev-list --not <rev>".
+	Cannot be used with "deepen", but can be used with
+	"deepen-since".
+
+If the 'filter' feature is advertised, the following argument can be
+included in the client's request:
+
+    filter <filter-spec>
+	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.
+
+If the 'ref-in-want' feature is advertised, the following argument can
+be included in the client's request as well as the potential addition of
+the 'wanted-refs' section in the server's response as explained below.
+
+    want-ref <ref>
+	Indicates to the server that the client wants to retrieve a
+	particular ref, where <ref> is the full name of a ref on the
+	server.  It is a protocol error to send want-ref for the
+	same ref more than once.
+
+If the 'sideband-all' feature is advertised, the following argument can be
+included in the client's request:
+
+    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.
+
+If the 'packfile-uris' feature is advertised, the following argument
+can be included in the client's request as well as the potential
+addition of the 'packfile-uris' section in the server's response as
+explained below. Note that at most one `packfile-uris` line can be sent
+to the server.
+
+    packfile-uris <comma-separated-list-of-protocols>
+	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".
+
+If the 'wait-for-done' feature is advertised, the following argument
+can be included in the client's request.
+
+    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.
+
+The response of `fetch` 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.
+
+    output = acknowledgements flush-pkt |
+	     [acknowledgments delim-pkt] [shallow-info delim-pkt]
+	     [wanted-refs delim-pkt] [packfile-uris delim-pkt]
+	     packfile flush-pkt
+
+    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)
+
+    shallow-info = PKT-LINE("shallow-info" LF)
+		   *PKT-LINE((shallow | unshallow) LF)
+    shallow = "shallow" SP obj-id
+    unshallow = "unshallow" SP obj-id
+
+    wanted-refs = PKT-LINE("wanted-refs" LF)
+		  *PKT-LINE(wanted-ref LF)
+    wanted-ref = obj-id SP refname
+
+    packfile-uris = PKT-LINE("packfile-uris" LF) *packfile-uri
+    packfile-uri = PKT-LINE(40*(HEXDIGIT) SP *%x20-ff LF)
+
+    packfile = PKT-LINE("packfile" LF)
+	       *PKT-LINE(%x01-03 *%x00-ff)
+
+    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.
+
+	* Always begins with the section header "acknowledgments"
+
+	* The server will respond with "NAK" if none of the object ids sent
+	  as have lines were common.
+
+	* The server will respond with "ACK obj-id" for all of the
+	  object ids sent as have lines which are common.
+
+	* A response cannot have both "ACK" lines as well as a "NAK"
+	  line.
+
+	* 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)
+
+	* 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.
+
+    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.
+
+	* Always begins with the section header "shallow-info"
+
+	* If a positive depth is requested, the server will compute the
+	  set of commits which are no deeper than the desired depth.
+
+	* The server sends a "shallow obj-id" line for each commit whose
+	  parents will not be sent in the following packfile.
+
+	* 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).
+
+	* The server MUST NOT send any "unshallow" lines for anything
+	  which the client has not indicated was shallow as a part of
+	  its request.
+
+    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.
+
+	* Always begins with the section header "wanted-refs".
+
+	* The server will send a ref listing ("<oid> <refname>") for
+	  each reference requested using 'want-ref' lines.
+
+	* The server MUST NOT send any refs which were not requested
+	  using 'want-ref' lines.
+
+    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.
+
+	* Always begins with the section header "packfile-uris".
+
+	* For each URI the server sends, it sends a hash of the pack's
+	  contents (as output by git index-pack) followed by the URI.
+
+	* 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".
+
+    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.
+
+	* Always begins with the section header "packfile"
+
+	* The transmission of the packfile begins immediately after the
+	  section header
+
+	* The data transfer of the packfile is always multiplexed, using
+	  the same semantics of the 'side-band-64k' 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.
+
+	  The stream code can be one of:
+		1 - pack data
+		2 - progress messages
+		3 - fatal error message just before stream aborts
+
+server-option
+~~~~~~~~~~~~~
+
+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=<option>" capability line in the capability-list section of
+a request.
+
+The provided options must not contain a NUL or LF character.
+
+object-format
+~~~~~~~~~~~~~
+
+The server can advertise the `object-format` capability with a value `X` (in the
+form `object-format=X`) 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.
+
+session-id=<session-id>
+~~~~~~~~~~~~~~~~~~~~~~~
+
+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.
+
+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
+link:technical/api-trace2.html[api-trace2] for details), but this may change
+and users of the session ID should not rely on this fact.
+
+object-info
+~~~~~~~~~~~
+
+`object-info` 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.
+
+An `object-info` request takes the following arguments:
+
+	size
+	Requests size information to be returned for each listed object id.
+
+	oid <oid>
+	Indicates to the server an object which the client wants to obtain
+	information for.
+
+The response of `object-info` is a list of the requested object ids
+and associated requested information, each separated by a single space.
+
+	output = info flush-pkt
+
+	info = PKT-LINE(attrs) LF)
+		*PKT-LINE(obj-info LF)
+
+	attrs = attr | attrs SP attrs
+
+	attr = "size"
+
+	obj-info = obj-id SP obj-size
+
+bundle-uri
+~~~~~~~~~~
+
+If the 'bundle-uri' capability is advertised, the server supports the
+`bundle-uri' command.
+
+The capability is currently advertised with no value (i.e. not
+"bundle-uri=somevalue"), a value may be added in the future for
+supporting command-wide extensions. Clients MUST ignore any unknown
+capability values and proceed with the 'bundle-uri` dialog they
+support.
+
+The 'bundle-uri' command is intended to be issued before `fetch` to
+get URIs to bundle files (see linkgit:git-bundle[1]) to "seed" and
+inform the subsequent `fetch` command.
+
+The client CAN issue `bundle-uri` before or after any other valid
+command. To be useful to clients it's expected that it'll be issued
+after an `ls-refs` and before `fetch`, but CAN be issued at any time
+in the dialog.
+
+DISCUSSION of bundle-uri
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The intent of the feature is optimize for server resource consumption
+in the common case by changing the common case of fetching a very
+large PACK during linkgit:git-clone[1] into a smaller incremental
+fetch.
+
+It also allows servers to achieve better caching in combination with
+an `uploadpack.packObjectsHook` (see linkgit:git-config[1]).
+
+By having new clones or fetches be a more predictable and common
+negotiation against the tips of recently produces *.bundle file(s).
+Servers might even pre-generate the results of such negotiations for
+the `uploadpack.packObjectsHook` as new pushes come in.
+
+One way that servers could take advantage of these bundles is that the
+server would anticipate that fresh clones will download a known bundle,
+followed by catching up to the current state of the repository using ref
+tips found in that bundle (or bundles).
+
+PROTOCOL for bundle-uri
+^^^^^^^^^^^^^^^^^^^^^^^
+
+A `bundle-uri` request takes no arguments, and as noted above does not
+currently advertise a capability value. Both may be added in the
+future.
+
+When the client issues a `command=bundle-uri` request, the response is a
+list of key-value pairs provided as packet lines with value
+`<key>=<value>`. Each `<key>` should be interpreted as a config key from
+the `bundle.*` namespace to construct a list of bundles. These keys are
+grouped by a `bundle.<id>.` subsection, where each key corresponding to a
+given `<id>` contributes attributes to the bundle defined by that `<id>`.
+See linkgit:git-config[1] for the specific details of these keys and how
+the Git client will interpret their values.
+
+Clients MUST parse the line according to the above format, lines that do
+not conform to the format SHOULD be discarded. The user MAY be warned in
+such a case.
+
+bundle-uri CLIENT AND SERVER EXPECTATIONS
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+URI CONTENTS::
+The content at the advertised URIs MUST be one of two types.
++
+The advertised URI may contain a bundle file that `git bundle verify`
+would accept. I.e. they MUST contain one or more reference tips for
+use by the client, MUST indicate prerequisites (in any) with standard
+"-" prefixes, and MUST indicate their "object-format", if
+applicable.
++
+The advertised URI may alternatively contain a plaintext file that `git
+config --list` would accept (with the `--file` option). The key-value
+pairs in this list are in the `bundle.*` namespace (see
+linkgit:git-config[1]).
+
+bundle-uri CLIENT ERROR RECOVERY::
+A client MUST above all gracefully degrade on errors, whether that
+error is because of bad missing/data in the bundle URI(s), because
+that client is too dumb to e.g. understand and fully parse out bundle
+headers and their prerequisite relationships, or something else.
++
+Server operators should feel confident in turning on "bundle-uri" and
+not worry if e.g. their CDN goes down that clones or fetches will run
+into hard failures. Even if the server bundle(s) are
+incomplete, or bad in some way the client should still end up with a
+functioning repository, just as if it had chosen not to use this
+protocol extension.
++
+All subsequent discussion on client and server interaction MUST keep
+this in mind.
+
+bundle-uri SERVER TO CLIENT::
+The ordering of the returned bundle uris is not significant. Clients
+MUST parse their headers to discover their contained OIDS and
+prerequisites. A client MUST consider the content of the bundle(s)
+themselves and their header as the ultimate source of truth.
++
+A server MAY even return bundle(s) that don't have any direct
+relationship to the repository being cloned (either through accident,
+or intentional "clever" configuration), and expect a client to sort
+out what data they'd like from the bundle(s), if any.
+
+bundle-uri CLIENT TO SERVER::
+The client SHOULD provide reference tips found in the bundle header(s)
+as 'have' lines in any subsequent `fetch` request. A client MAY also
+ignore the bundle(s) entirely if doing so is deemed worse for some
+reason, e.g. if the bundles can't be downloaded, it doesn't like the
+tips it finds etc.
+
+WHEN ADVERTISED BUNDLE(S) REQUIRE NO FURTHER NEGOTIATION::
+If after issuing `bundle-uri` and `ls-refs`, and getting the header(s)
+of the bundle(s) the client finds that the ref tips it wants can be
+retrieved entirely from advertised bundle(s), the client MAY disconnect
+from the Git server. The results of such a 'clone' or 'fetch' should be
+indistinguishable from the state attained without using bundle-uri.
+
+EARLY CLIENT DISCONNECTIONS AND ERROR RECOVERY::
+A client MAY perform an early disconnect while still downloading the
+bundle(s) (having streamed and parsed their headers). In such a case
+the client MUST gracefully recover from any errors related to
+finishing the download and validation of the bundle(s).
++
+I.e. a client might need to re-connect and issue a 'fetch' command,
+and possibly fall back to not making use of 'bundle-uri' at all.
++
+This "MAY" behavior is specified as such (and not a "SHOULD") on the
+assumption that a server advertising bundle uris is more likely than
+not to be serving up a relatively large repository, and to be pointing
+to URIs that have a good chance of being in working order. A client
+MAY e.g. look at the payload size of the bundles as a heuristic to see
+if an early disconnect is worth it, should falling back on a full
+"fetch" dialog be necessary.
+
+WHEN ADVERTISED BUNDLE(S) REQUIRE FURTHER NEGOTIATION::
+A client SHOULD commence a negotiation of a PACK from the server via
+the "fetch" command using the OID tips found in advertised bundles,
+even if's still in the process of downloading those bundle(s).
++
+This allows for aggressive early disconnects from any interactive
+server dialog. The client blindly trusts that the advertised OID tips
+are relevant, and issues them as 'have' lines, it then requests any
+tips it would like (usually from the "ls-refs" advertisement) via
+'want' lines. The server will then compute a (hopefully small) PACK
+with the expected difference between the tips from the bundle(s) and
+the data requested.
++
+The only connection the client then needs to keep active is to the
+concurrently downloading static bundle(s), when those and the
+incremental PACK are retrieved they should be inflated and
+validated. Any errors at this point should be gracefully recovered
+from, see above.
+
+bundle-uri PROTOCOL FEATURES
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The client constructs a bundle list from the `<key>=<value>` pairs
+provided by the server. These pairs are part of the `bundle.*` namespace
+as documented in linkgit:git-config[1]. In this section, we discuss some
+of these keys and describe the actions the client will do in response to
+this information.
+
+In particular, the `bundle.version` key specifies an integer value. The
+only accepted value at the moment is `1`, but if the client sees an
+unexpected value here then the client MUST ignore the bundle list.
+
+As long as `bundle.version` is understood, all other unknown keys MAY be
+ignored by the client. The server will guarantee compatibility with older
+clients, though newer clients may be better able to use the extra keys to
+minimize downloads.
+
+Any backwards-incompatible addition of pre-URI key-value will be
+guarded by a new `bundle.version` value or values in 'bundle-uri'
+capability advertisement itself, and/or by new future `bundle-uri`
+request arguments.
+
+Some example key-value pairs that are not currently implemented but could
+be implemented in the future include:
+
+ * Add a "hash=<val>" or "size=<bytes>" advertise the expected hash or
+   size of the bundle file.
+
+ * Advertise that one or more bundle files are the same (to e.g. have
+   clients round-robin or otherwise choose one of N possible files).
+
+ * A "oid=<OID>" shortcut and "prerequisite=<OID>" shortcut. For
+   expressing the common case of a bundle with one tip and no
+   prerequisites, or one tip and one prerequisite.
++
+This would allow for optimizing the common case of servers who'd like
+to provide one "big bundle" containing only their "main" branch,
+and/or incremental updates thereof.
++
+A client receiving such a response MAY assume that they can skip
+retrieving the header from a bundle at the indicated URI, and thus
+save themselves and the server(s) the request(s) needed to inspect the
+headers of that bundle or bundles.
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitremote-helpers.adoc b/Documentation/gitremote-helpers.adoc
new file mode 100644
index 0000000000..d0be008e5e
--- /dev/null
+++ b/Documentation/gitremote-helpers.adoc
@@ -0,0 +1,562 @@
+gitremote-helpers(7)
+====================
+
+NAME
+----
+gitremote-helpers - Helper programs to interact with remote repositories
+
+SYNOPSIS
+--------
+[verse]
+'git remote-<transport>' <repository> [<URL>]
+
+DESCRIPTION
+-----------
+
+Remote helper programs are normally not used directly by end users,
+but they are invoked by Git when it needs to interact with remote
+repositories Git does not support natively.  A given helper will
+implement a subset of the capabilities documented here. When Git
+needs to interact with a repository using a remote helper, it spawns
+the helper as an independent process, sends commands to the helper's
+standard input, and expects results from the helper's standard
+output. Because a remote helper runs as an independent process from
+Git, there is no need to re-link Git to add a new helper, nor any
+need to link the helper with the implementation of Git.
+
+Every helper must support the "capabilities" command, which Git
+uses to determine what other commands the helper will accept.  Those
+other commands can be used to discover and update remote refs,
+transport objects between the object database and the remote repository,
+and update the local object store.
+
+Git comes with a "curl" family of remote helpers, that handle various
+transport protocols, such as 'git-remote-http', 'git-remote-https',
+'git-remote-ftp' and 'git-remote-ftps'. They implement the capabilities
+'fetch', 'option', and 'push'.
+
+INVOCATION
+----------
+
+Remote helper programs are invoked with one or (optionally) two
+arguments. The first argument specifies a remote repository as in Git;
+it is either the name of a configured remote or a URL. The second
+argument specifies a URL; it is usually of the form
+'<transport>://<address>', but any arbitrary string is possible.
+The `GIT_DIR` environment variable is set up for the remote helper
+and can be used to determine where to store additional data or from
+which directory to invoke auxiliary Git commands.
+
+When Git encounters a URL of the form '<transport>://<address>', where
+'<transport>' is a protocol that it cannot handle natively, it
+automatically invokes 'git remote-<transport>' with the full URL as
+the second argument. If such a URL is encountered directly on the
+command line, the first argument is the same as the second, and if it
+is encountered in a configured remote, the first argument is the name
+of that remote.
+
+A URL of the form '<transport>::<address>' explicitly instructs Git to
+invoke 'git remote-<transport>' with '<address>' as the second
+argument. If such a URL is encountered directly on the command line,
+the first argument is '<address>', and if it is encountered in a
+configured remote, the first argument is the name of that remote.
+
+Additionally, when a configured remote has `remote.<name>.vcs` set to
+'<transport>', Git explicitly invokes 'git remote-<transport>' with
+'<name>' as the first argument. If set, the second argument is
+`remote.<name>.url`; otherwise, the second argument is omitted.
+
+INPUT FORMAT
+------------
+
+Git sends the remote helper a list of commands on standard input, one
+per line.  The first command is always the 'capabilities' command, in
+response to which the remote helper must print a list of the
+capabilities it supports (see below) followed by a blank line.  The
+response to the capabilities command determines what commands Git uses
+in the remainder of the command stream.
+
+The command stream is terminated by a blank line.  In some cases
+(indicated in the documentation of the relevant commands), this blank
+line is followed by a payload in some other protocol (e.g., the pack
+protocol), while in others it indicates the end of input.
+
+Capabilities
+~~~~~~~~~~~~
+
+Each remote helper is expected to support only a subset of commands.
+The operations a helper supports are declared to Git in the response
+to the `capabilities` command (see COMMANDS, below).
+
+In the following, we list all defined capabilities and for
+each we list which commands a helper with that capability
+must provide.
+
+Capabilities for Pushing
+^^^^^^^^^^^^^^^^^^^^^^^^
+'connect'::
+	Can attempt to connect to 'git receive-pack' (for pushing),
+	'git upload-pack', etc for communication using
+	git's native packfile protocol. This
+	requires a bidirectional, full-duplex connection.
++
+Supported commands: 'connect'.
+
+'stateless-connect'::
+	Experimental; for internal use only.
+	Can attempt to connect to a remote server for communication
+	using git's wire-protocol version 2.  See the documentation
+	for the stateless-connect command for more information.
++
+Supported commands: 'stateless-connect'.
+
+'push'::
+	Can discover remote refs and push local commits and the
+	history leading up to them to new or existing remote refs.
++
+Supported commands: 'list for-push', 'push'.
+
+'export'::
+	Can discover remote refs and push specified objects from a
+	fast-import stream to remote refs.
++
+Supported commands: 'list for-push', 'export'.
+
+If a helper advertises 'connect', Git will use it if possible and
+fall back to another capability if the helper requests so when
+connecting (see the 'connect' command under COMMANDS).
+When choosing between 'push' and 'export', Git prefers 'push'.
+Other frontends may have some other order of preference.
+
+'no-private-update'::
+	When using the 'refspec' capability, git normally updates the
+	private ref on successful push. This update is disabled when
+	the remote-helper declares the capability 'no-private-update'.
+
+
+Capabilities for Fetching
+^^^^^^^^^^^^^^^^^^^^^^^^^
+'connect'::
+	Can try to connect to 'git upload-pack' (for fetching),
+	'git receive-pack', etc for communication using the
+	Git's native packfile protocol. This
+	requires a bidirectional, full-duplex connection.
++
+Supported commands: 'connect'.
+
+'stateless-connect'::
+	Experimental; for internal use only.
+	Can attempt to connect to a remote server for communication
+	using git's wire-protocol version 2.  See the documentation
+	for the stateless-connect command for more information.
++
+Supported commands: 'stateless-connect'.
+
+'fetch'::
+	Can discover remote refs and transfer objects reachable from
+	them to the local object store.
++
+Supported commands: 'list', 'fetch'.
+
+'import'::
+	Can discover remote refs and output objects reachable from
+	them as a stream in fast-import format.
++
+Supported commands: 'list', 'import'.
+
+'check-connectivity'::
+	Can guarantee that when a clone is requested, the received
+	pack is self contained and is connected.
+
+'get'::
+	Can use the 'get' command to download a file from a given URI.
+
+If a helper advertises 'connect', Git will use it if possible and
+fall back to another capability if the helper requests so when
+connecting (see the 'connect' command under COMMANDS).
+When choosing between 'fetch' and 'import', Git prefers 'fetch'.
+Other frontends may have some other order of preference.
+
+Miscellaneous capabilities
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+'option'::
+	For specifying settings like `verbosity` (how much output to
+	write to stderr) and `depth` (how much history is wanted in the
+	case of a shallow clone) that affect how other commands are
+	carried out.
+
+'refspec' <refspec>::
+	For remote helpers that implement 'import' or 'export', this capability
+	allows the refs to be constrained to a private namespace, instead of
+	writing to refs/heads or refs/remotes directly.
+	It is recommended that all importers providing the 'import'
+	capability use this. It's mandatory for 'export'.
++
+A helper advertising the capability
+`refspec refs/heads/*:refs/svn/origin/branches/*`
+is saying that, when it is asked to `import refs/heads/topic`, the
+stream it outputs will update the `refs/svn/origin/branches/topic`
+ref.
++
+This capability can be advertised multiple times.  The first
+applicable refspec takes precedence.  The left-hand of refspecs
+advertised with this capability must cover all refs reported by
+the list command.  If no 'refspec' capability is advertised,
+there is an implied `refspec *:*`.
++
+When writing remote-helpers for decentralized version control
+systems, it is advised to keep a local copy of the repository to
+interact with, and to let the private namespace refs point to this
+local repository, while the refs/remotes namespace is used to track
+the remote repository.
+
+'bidi-import'::
+	This modifies the 'import' capability.
+	The fast-import commands 'cat-blob' and 'ls' can be used by remote-helpers
+	to retrieve information about blobs and trees that already exist in
+	fast-import's memory. This requires a channel from fast-import to the
+	remote-helper.
+	If it is advertised in addition to "import", Git establishes a pipe from
+	fast-import to the remote-helper's stdin.
+	It follows that Git and fast-import are both connected to the
+	remote-helper's stdin. Because Git can send multiple commands to
+	the remote-helper it is required that helpers that use 'bidi-import'
+	buffer all 'import' commands of a batch before sending data to fast-import.
+	This is to prevent mixing commands and fast-import responses on the
+	helper's stdin.
+
+'export-marks' <file>::
+	This modifies the 'export' capability, instructing Git to dump the
+	internal marks table to <file> when complete. For details,
+	read up on `--export-marks=<file>` in linkgit:git-fast-export[1].
+
+'import-marks' <file>::
+	This modifies the 'export' capability, instructing Git to load the
+	marks specified in <file> before processing any input. For details,
+	read up on `--import-marks=<file>` in linkgit:git-fast-export[1].
+
+'signed-tags'::
+	This modifies the 'export' capability, instructing Git to pass
+	`--signed-tags=verbatim` to linkgit:git-fast-export[1].  In the
+	absence of this capability, Git will use `--signed-tags=warn-strip`.
+
+'object-format'::
+	This indicates that the helper is able to interact with the remote
+	side using an explicit hash algorithm extension.
+
+
+COMMANDS
+--------
+
+Commands are given by the caller on the helper's standard input, one per line.
+
+'capabilities'::
+	Lists the capabilities of the helper, one per line, ending
+	with a blank line. Each capability may be preceded with '*',
+	which marks them mandatory for Git versions using the remote
+	helper to understand. Any unknown mandatory capability is a
+	fatal error.
++
+Support for this command is mandatory.
+
+'list'::
+	Lists the refs, one per line, in the format "<value> <name>
+	[<attr> ...]". The value may be a hex sha1 hash, "@<dest>" for
+	a symref, ":<keyword> <value>" for a key-value pair, or
+	"?" to indicate that the helper could not get the value of the
+	ref. A space-separated list of attributes follows the name;
+	unrecognized attributes are ignored. The list ends with a
+	blank line.
++
+See REF LIST ATTRIBUTES for a list of currently defined attributes.
+See REF LIST KEYWORDS for a list of currently defined keywords.
++
+Supported if the helper has the "fetch" or "import" capability.
+
+'list for-push'::
+	Similar to 'list', except that it is used if and only if
+	the caller wants to the resulting ref list to prepare
+	push commands.
+	A helper supporting both push and fetch can use this
+	to distinguish for which operation the output of 'list'
+	is going to be used, possibly reducing the amount
+	of work that needs to be performed.
++
+Supported if the helper has the "push" or "export" capability.
+
+'option' <name> <value>::
+	Sets the transport helper option <name> to <value>.  Outputs a
+	single line containing one of 'ok' (option successfully set),
+	'unsupported' (option not recognized) or 'error <msg>'
+	(option <name> is supported but <value> is not valid
+	for it).  Options should be set before other commands,
+	and may influence the behavior of those commands.
++
+See OPTIONS for a list of currently defined options.
++
+Supported if the helper has the "option" capability.
+
+'fetch' <sha1> <name>::
+	Fetches the given object, writing the necessary objects
+	to the database.  Fetch commands are sent in a batch, one
+	per line, terminated with a blank line.
+	Outputs a single blank line when all fetch commands in the
+	same batch are complete. Only objects which were reported
+	in the output of 'list' with a sha1 may be fetched this way.
++
+Optionally may output a 'lock <file>' line indicating the full path of
+a file under `$GIT_DIR/objects/pack` which is keeping a pack until
+refs can be suitably updated.  The path must end with `.keep`. This is
+a mechanism to name a <pack,idx,keep> tuple by giving only the keep
+component.  The kept pack will not be deleted by a concurrent repack,
+even though its objects may not be referenced until the fetch completes.
+The `.keep` file will be deleted at the conclusion of the fetch.
++
+If option 'check-connectivity' is requested, the helper must output
+'connectivity-ok' if the clone is self-contained and connected.
++
+Supported if the helper has the "fetch" capability.
+
+'push' +<src>:<dst>::
+	Pushes the given local <src> commit or branch to the
+	remote branch described by <dst>.  A batch sequence of
+	one or more 'push' commands is terminated with a blank line
+	(if there is only one reference to push, a single 'push' command
+	is followed by a blank line). For example, the following would
+	be two batches of 'push', the first asking the remote-helper
+	to push the local ref 'master' to the remote ref 'master' and
+	the local `HEAD` to the remote 'branch', and the second
+	asking to push ref 'foo' to ref 'bar' (forced update requested
+	by the '+').
++
+------------
+push refs/heads/master:refs/heads/master
+push HEAD:refs/heads/branch
+\n
+push +refs/heads/foo:refs/heads/bar
+\n
+------------
++
+Zero or more protocol options may be entered after the last 'push'
+command, before the batch's terminating blank line.
++
+When the push is complete, outputs one or more 'ok <dst>' or
+'error <dst> <why>?' lines to indicate success or failure of
+each pushed ref.  The status report output is terminated by
+a blank line.  The option field <why> may be quoted in a C
+style string if it contains an LF.
++
+Supported if the helper has the "push" capability.
+
+'import' <name>::
+	Produces a fast-import stream which imports the current value
+	of the named ref. It may additionally import other refs as
+	needed to construct the history efficiently. The script writes
+	to a helper-specific private namespace. The value of the named
+	ref should be written to a location in this namespace derived
+	by applying the refspecs from the "refspec" capability to the
+	name of the ref.
++
+Especially useful for interoperability with a foreign versioning
+system.
++
+Just like 'push', a batch sequence of one or more 'import' is
+terminated with a blank line. For each batch of 'import', the remote
+helper should produce a fast-import stream terminated by a 'done'
+command.
++
+Note that if the 'bidi-import' capability is used the complete batch
+sequence has to be buffered before starting to send data to fast-import
+to prevent mixing of commands and fast-import responses on the helper's
+stdin.
++
+Supported if the helper has the "import" capability.
+
+'export'::
+	Instructs the remote helper that any subsequent input is
+	part of a fast-import stream (generated by 'git fast-export')
+	containing objects which should be pushed to the remote.
++
+Especially useful for interoperability with a foreign versioning
+system.
++
+The 'export-marks' and 'import-marks' capabilities, if specified,
+affect this command in so far as they are passed on to 'git
+fast-export', which then will load/store a table of marks for
+local objects. This can be used to implement for incremental
+operations.
++
+Supported if the helper has the "export" capability.
+
+'connect' <service>::
+	Connects to given service. Standard input and standard output
+	of helper are connected to specified service (git prefix is
+	included in service name so e.g. fetching uses 'git-upload-pack'
+	as service) on remote side. Valid replies to this command are
+	empty line (connection established), 'fallback' (no smart
+	transport support, fall back to dumb transports) and just
+	exiting with error message printed (can't connect, don't
+	bother trying to fall back). After line feed terminating the
+	positive (empty) response, the output of service starts. After
+	the connection ends, the remote helper exits.
++
+Supported if the helper has the "connect" capability.
+
+'stateless-connect' <service>::
+	Experimental; for internal use only.
+	Connects to the given remote service for communication using
+	git's wire-protocol version 2.  Valid replies to this command
+	are empty line (connection established), 'fallback' (no smart
+	transport support, fall back to dumb transports) and just
+	exiting with error message printed (can't connect, don't bother
+	trying to fall back).  After line feed terminating the positive
+	(empty) response, the output of the service starts.  Messages
+	(both request and response) must consist of zero or more
+	PKT-LINEs, terminating in a flush packet. Response messages will
+	then have a response end packet after the flush packet to
+	indicate the end of a response.  The client must not
+	expect the server to store any state in between request-response
+	pairs.  After the connection ends, the remote helper exits.
++
+Supported if the helper has the "stateless-connect" capability.
+
+'get' <uri> <path>::
+	Downloads the file from the given `<uri>` to the given `<path>`. If
+	`<path>.temp` exists, then Git assumes that the `.temp` file is a
+	partial download from a previous attempt and will resume the
+	download from that position.
+
+If a fatal error occurs, the program writes the error message to
+stderr and exits. The caller should expect that a suitable error
+message has been printed if the child closes the connection without
+completing a valid response for the current command.
+
+Additional commands may be supported, as may be determined from
+capabilities reported by the helper.
+
+REF LIST ATTRIBUTES
+-------------------
+
+The 'list' command produces a list of refs in which each ref
+may be followed by a list of attributes. The following ref list
+attributes are defined.
+
+'unchanged'::
+	This ref is unchanged since the last import or fetch, although
+	the helper cannot necessarily determine what value that produced.
+
+REF LIST KEYWORDS
+-----------------
+
+The 'list' command may produce a list of key-value pairs.
+The following keys are defined.
+
+'object-format'::
+	The refs are using the given hash algorithm.  This keyword is only
+	used if the server and client both support the object-format
+	extension.
+
+
+OPTIONS
+-------
+
+The following options are defined and (under suitable circumstances)
+set by Git if the remote helper has the 'option' capability.
+
+'option verbosity' <n>::
+	Changes the verbosity of messages displayed by the helper.
+	A value of 0 for <n> means that processes operate
+	quietly, and the helper produces only error output.
+	1 is the default level of verbosity, and higher values
+	of <n> correspond to the number of -v flags passed on the
+	command line.
+
+'option progress' {'true'|'false'}::
+	Enables (or disables) progress messages displayed by the
+	transport helper during a command.
+
+'option depth' <depth>::
+	Deepens the history of a shallow repository.
+
+'option deepen-since' <timestamp>::
+	Deepens the history of a shallow repository based on time.
+
+'option deepen-not' <ref>::
+	Deepens the history of a shallow repository excluding ref.
+	Multiple options add up.
+
+'option deepen-relative' {'true'|'false'}::
+	Deepens the history of a shallow repository relative to
+	current boundary. Only valid when used with "option depth".
+
+'option followtags' {'true'|'false'}::
+	If enabled the helper should automatically fetch annotated
+	tag objects if the object the tag points at was transferred
+	during the fetch command.  If the tag is not fetched by
+	the helper a second fetch command will usually be sent to
+	ask for the tag specifically.  Some helpers may be able to
+	use this option to avoid a second network connection.
+
+'option dry-run' {'true'|'false'}:
+	If true, pretend the operation completed successfully,
+	but don't actually change any repository data.  For most
+	helpers this only applies to the 'push', if supported.
+
+'option servpath <c-style-quoted-path>'::
+	Sets service path (--upload-pack, --receive-pack etc.) for
+	next connect. Remote helper may support this option, but
+	must not rely on this option being set before
+	connect request occurs.
+
+'option check-connectivity' {'true'|'false'}::
+	Request the helper to check connectivity of a clone.
+
+'option force' {'true'|'false'}::
+	Request the helper to perform a force update.  Defaults to
+	'false'.
+
+'option cloning' {'true'|'false'}::
+	Notify the helper this is a clone request (i.e. the current
+	repository is guaranteed empty).
+
+'option update-shallow' {'true'|'false'}::
+	Allow to extend .git/shallow if the new refs require it.
+
+'option pushcert' {'true'|'false'}::
+	GPG sign pushes.
+
+'option push-option' <string>::
+	Transmit <string> as a push option. As the push option
+	must not contain LF or NUL characters, the string is not encoded.
+
+'option from-promisor' {'true'|'false'}::
+	Indicate that these objects are being fetched from a promisor.
+
+'option no-dependents' {'true'|'false'}::
+	Indicate that only the objects wanted need to be fetched, not
+	their dependents.
+
+'option atomic' {'true'|'false'}::
+	When pushing, request the remote server to update refs in a single atomic
+	transaction.  If successful, all refs will be updated, or none will.  If the
+	remote side does not support this capability, the push will fail.
+
+'option object-format true'::
+	Indicate that the caller wants hash algorithm information
+	to be passed back from the remote.  This mode is used when fetching
+	refs.
+
+SEE ALSO
+--------
+linkgit:git-remote[1]
+
+linkgit:git-remote-ext[1]
+
+linkgit:git-remote-fd[1]
+
+linkgit:git-fast-import[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitrepository-layout.adoc b/Documentation/gitrepository-layout.adoc
new file mode 100644
index 0000000000..c77f474311
--- /dev/null
+++ b/Documentation/gitrepository-layout.adoc
@@ -0,0 +1,311 @@
+gitrepository-layout(5)
+=======================
+
+NAME
+----
+gitrepository-layout - Git Repository Layout
+
+SYNOPSIS
+--------
+$GIT_DIR/*
+
+DESCRIPTION
+-----------
+
+A Git repository comes in two different flavours:
+
+ * a `.git` directory at the root of the working tree;
+
+ * a `<project>.git` directory that is a 'bare' repository
+   (i.e. without its own working tree), that is typically used for
+   exchanging histories with others by pushing into it and fetching
+   from it.
+
+*Note*: Also you can have a plain text file `.git` at the root of
+your working tree, containing `gitdir: <path>` to point at the real
+directory that has the repository.
+This mechanism is called a 'gitfile' and is usually managed via the
+`git submodule` and `git worktree` commands. It is often used for
+a working tree of a submodule checkout, to allow you in the
+containing superproject to `git checkout` a branch that does not
+have the submodule.  The `checkout` has to remove the entire
+submodule working tree, without losing the submodule repository.
+
+These things may exist in a Git repository.
+
+objects::
+	Object store associated with this repository.  Usually
+	an object store is self sufficient (i.e. all the objects
+	that are referred to by an object found in it are also
+	found in it), but there are a few ways to violate it.
++
+. You could have an incomplete but locally usable repository
+by creating a shallow clone.  See linkgit:git-clone[1].
+. You could be using the `objects/info/alternates` or
+`$GIT_ALTERNATE_OBJECT_DIRECTORIES` mechanisms to 'borrow'
+objects from other object stores.  A repository with this kind
+of incomplete object store is not suitable to be published for
+use with dumb transports but otherwise is OK as long as
+`objects/info/alternates` points at the object stores it
+borrows from.
++
+This directory is ignored if $GIT_COMMON_DIR is set and
+"$GIT_COMMON_DIR/objects" will be used instead.
+
+objects/[0-9a-f][0-9a-f]::
+	A newly created object is stored in its own file.
+	The objects are splayed over 256 subdirectories using
+	the first two characters of the sha1 object name to
+	keep the number of directory entries in `objects`
+	itself to a manageable number. Objects found
+	here are often called 'unpacked' (or 'loose') objects.
+
+objects/pack::
+	Packs (files that store many objects in compressed form,
+	along with index files to allow them to be randomly
+	accessed) are found in this directory.
+
+objects/info::
+	Additional information about the object store is
+	recorded in this directory.
+
+objects/info/packs::
+	This file is to help dumb transports discover what packs
+	are available in this object store.  Whenever a pack is
+	added or removed, `git update-server-info` should be run
+	to keep this file up to date if the repository is
+	published for dumb transports.  'git repack' does this
+	by default.
+
+objects/info/alternates::
+	This file records paths to alternate object stores that
+	this object store borrows objects from, one pathname per
+	line. Note that not only native Git tools use it locally,
+	but the HTTP fetcher also tries to use it remotely; this
+	will usually work if you have relative paths (relative
+	to the object database, not to the repository!) in your
+	alternates file, but it will not work if you use absolute
+	paths unless the absolute path in filesystem and web URL
+	is the same. See also `objects/info/http-alternates`.
+
+objects/info/http-alternates::
+	This file records URLs to alternate object stores that
+	this object store borrows objects from, to be used when
+	the repository is fetched over HTTP.
+
+refs::
+	References are stored in subdirectories of this
+	directory.  The 'git prune' command knows to preserve
+	objects reachable from refs found in this directory and
+	its subdirectories.
+	This directory is ignored (except refs/bisect,
+	refs/rewritten and refs/worktree) if $GIT_COMMON_DIR is
+	set and "$GIT_COMMON_DIR/refs" will be used instead.
+
+refs/heads/`name`::
+	records tip-of-the-tree commit objects of branch `name`
+
+refs/tags/`name`::
+	records any object name (not necessarily a commit
+	object, or a tag object that points at a commit object).
+
+refs/remotes/`name`::
+	records tip-of-the-tree commit objects of branches copied
+	from a remote repository.
+
+refs/replace/`<obj-sha1>`::
+	records the SHA-1 of the object that replaces `<obj-sha1>`.
+	This is similar to info/grafts and is internally used and
+	maintained by linkgit:git-replace[1]. Such refs can be exchanged
+	between repositories while grafts are not.
+
+packed-refs::
+	records the same information as refs/heads/, refs/tags/,
+	and friends record in a more efficient way.  See
+	linkgit:git-pack-refs[1]. This file is ignored if $GIT_COMMON_DIR
+	is set and "$GIT_COMMON_DIR/packed-refs" will be used instead.
+
+HEAD::
+	A symref (see glossary) to the `refs/heads/` namespace
+	describing the currently active branch.  It does not mean
+	much if the repository is not associated with any working tree
+	(i.e. a 'bare' repository), but a valid Git repository
+	*must* have the HEAD file; some porcelains may use it to
+	guess the designated "default" branch of the repository
+	(usually 'master').  It is legal if the named branch
+	'name' does not (yet) exist.  In some legacy setups, it is
+	a symbolic link instead of a symref that points at the current
+	branch.
++
+HEAD can also record a specific commit directly, instead of
+being a symref to point at the current branch.  Such a state
+is often called 'detached HEAD.'  See linkgit:git-checkout[1]
+for details.
+
+config::
+	Repository specific configuration file. This file is ignored
+	if $GIT_COMMON_DIR is set and "$GIT_COMMON_DIR/config" will be
+	used instead.
+
+config.worktree::
+	Working directory specific configuration file for the main
+	working directory in multiple working directory setup (see
+	linkgit:git-worktree[1]).
+
+branches::
+	A slightly deprecated way to store shorthands to be used
+	to specify a URL to 'git fetch', 'git pull' and 'git push'.
+	A file can be stored as `branches/<name>` and then
+	'name' can be given to these commands in place of
+	'repository' argument.  See the REMOTES section in
+	linkgit:git-fetch[1] for details.  This mechanism is legacy
+	and not likely to be found in modern repositories. This
+	directory is ignored if $GIT_COMMON_DIR is set and
+	"$GIT_COMMON_DIR/branches" will be used instead.
+
+
+hooks::
+	Hooks are customization scripts used by various Git
+	commands.  A handful of sample hooks are installed when
+	'git init' is run, but all of them are disabled by
+	default.  To enable, the `.sample` suffix has to be
+	removed from the filename by renaming.
+	Read linkgit:githooks[5] for more details about
+	each hook. This directory is ignored if $GIT_COMMON_DIR is set
+	and "$GIT_COMMON_DIR/hooks" will be used instead.
+
+common::
+	When multiple working trees are used, most of files in
+	$GIT_DIR are per-worktree with a few known exceptions. All
+	files under 'common' however will be shared between all
+	working trees.
+
+index::
+	The current index file for the repository.  It is
+	usually not found in a bare repository.
+
+sharedindex.<SHA-1>::
+	The shared index part, to be referenced by $GIT_DIR/index and
+	other temporary index files. Only valid in split index mode.
+
+info::
+	Additional information about the repository is recorded
+	in this directory. This directory is ignored if $GIT_COMMON_DIR
+	is set and "$GIT_COMMON_DIR/info" will be used instead.
+
+info/refs::
+	This file helps dumb transports discover what refs are
+	available in this repository.  If the repository is
+	published for dumb transports, this file should be
+	regenerated by 'git update-server-info' every time a tag
+	or branch is created or modified.  This is normally done
+	from the `hooks/update` hook, which is run by the
+	'git-receive-pack' command when you 'git push' into the
+	repository.
+
+info/grafts::
+	This file records fake commit ancestry information, to
+	pretend the set of parents a commit has is different
+	from how the commit was actually created.  One record
+	per line describes a commit and its fake parents by
+	listing their 40-byte hexadecimal object names separated
+	by a space and terminated by a newline.
++
+Note that the grafts mechanism is outdated and can lead to problems
+transferring objects between repositories; see linkgit:git-replace[1]
+for a more flexible and robust system to do the same thing.
+
+info/exclude::
+	This file, by convention among Porcelains, stores the
+	exclude pattern list. `.gitignore` is the per-directory
+	ignore file.  'git status', 'git add', 'git rm' and
+	'git clean' look at it but the core Git commands do not look
+	at it.  See also: linkgit:gitignore[5].
+
+info/attributes::
+	Defines which attributes to assign to a path, similar to per-directory
+	`.gitattributes` files.   See also: linkgit:gitattributes[5].
+
+info/sparse-checkout::
+	This file stores sparse checkout patterns.
+	See also: linkgit:git-read-tree[1].
+
+remotes::
+	Stores shorthands for URL and default refnames for use
+	when interacting with remote repositories via 'git fetch',
+	'git pull' and 'git push' commands.  See the REMOTES section
+	in linkgit:git-fetch[1] for details.  This mechanism is legacy
+	and not likely to be found in modern repositories. This
+	directory is ignored if $GIT_COMMON_DIR is set and
+	"$GIT_COMMON_DIR/remotes" will be used instead.
+
+logs::
+	Records of changes made to refs are stored in this directory.
+	See linkgit:git-update-ref[1] for more information. This
+	directory is ignored (except logs/HEAD) if $GIT_COMMON_DIR is
+	set and "$GIT_COMMON_DIR/logs" will be used instead.
+
+logs/refs/heads/`name`::
+	Records all changes made to the branch tip named `name`.
+
+logs/refs/tags/`name`::
+	Records all changes made to the tag named `name`.
+
+shallow::
+	This is similar to `info/grafts` but is internally used
+	and maintained by shallow clone mechanism.  See `--depth`
+	option to linkgit:git-clone[1] and linkgit:git-fetch[1]. This
+	file is ignored if $GIT_COMMON_DIR is set and
+	"$GIT_COMMON_DIR/shallow" will be used instead.
+
+commondir::
+	If this file exists, $GIT_COMMON_DIR (see linkgit:git[1]) will
+	be set to the path specified in this file if it is not
+	explicitly set. If the specified path is relative, it is
+	relative to $GIT_DIR. The repository with commondir is
+	incomplete without the repository pointed by "commondir".
+
+modules::
+	Contains the git-repositories of the submodules.
+
+worktrees::
+	Contains administrative data for linked
+	working trees. Each subdirectory contains the working tree-related
+	part of a linked working tree. This directory is ignored if
+	$GIT_COMMON_DIR is set, in which case
+	"$GIT_COMMON_DIR/worktrees" will be used instead.
+
+worktrees/<id>/gitdir::
+	A text file containing the absolute path back to the .git file
+	that points to here. This is used to check if the linked
+	repository has been manually removed and there is no need to
+	keep this directory any more. The mtime of this file should be
+	updated every time the linked repository is accessed.
+
+worktrees/<id>/locked::
+	If this file exists, the linked working tree may be on a
+	portable device and not available. The presence of this file
+	prevents `worktrees/<id>` from being pruned either automatically
+	or manually by `git worktree prune`. The file may contain a string
+	explaining why the repository is locked.
+
+worktrees/<id>/config.worktree::
+	Working directory specific configuration file.
+
+include::technical/repository-version.adoc[]
+
+SEE ALSO
+--------
+linkgit:git-init[1],
+linkgit:git-clone[1],
+linkgit:git-config[1],
+linkgit:git-fetch[1],
+linkgit:git-pack-refs[1],
+linkgit:git-gc[1],
+linkgit:git-checkout[1],
+linkgit:gitglossary[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitrevisions.adoc b/Documentation/gitrevisions.adoc
new file mode 100644
index 0000000000..7146117de5
--- /dev/null
+++ b/Documentation/gitrevisions.adoc
@@ -0,0 +1,36 @@
+gitrevisions(7)
+===============
+
+NAME
+----
+gitrevisions - Specifying revisions and ranges for Git
+
+SYNOPSIS
+--------
+gitrevisions
+
+
+DESCRIPTION
+-----------
+
+Many Git commands take revision parameters as arguments. Depending on
+the command, they denote a specific commit or, for commands which
+walk the revision graph (such as linkgit:git-log[1]), all commits which are
+reachable from that commit. For commands that walk the revision graph one can
+also specify a range of revisions explicitly.
+
+In addition, some Git commands (such as linkgit:git-show[1] and
+linkgit:git-push[1]) can also take revision parameters which denote
+other objects than commits, e.g. blobs ("files") or trees
+("directories of files").
+
+include::revisions.adoc[]
+
+
+SEE ALSO
+--------
+linkgit:git-rev-parse[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitsubmodules.adoc b/Documentation/gitsubmodules.adoc
new file mode 100644
index 0000000000..f7b5a25a0c
--- /dev/null
+++ b/Documentation/gitsubmodules.adoc
@@ -0,0 +1,287 @@
+gitsubmodules(7)
+================
+
+NAME
+----
+gitsubmodules - Mounting one repository inside another
+
+SYNOPSIS
+--------
+ .gitmodules, $GIT_DIR/config
+------------------
+git submodule
+git <command> --recurse-submodules
+------------------
+
+DESCRIPTION
+-----------
+
+A submodule is a repository embedded inside another repository.
+The submodule has its own history; the repository it is embedded
+in is called a superproject.
+
+On the filesystem, a submodule usually (but not always - see FORMS below)
+consists of (i) a Git directory located under the `$GIT_DIR/modules/`
+directory of its superproject, (ii) a working directory inside the
+superproject's working directory, and a `.git` file at the root of
+the submodule's working directory pointing to (i).
+
+Assuming the submodule has a Git directory at `$GIT_DIR/modules/foo/`
+and a working directory at `path/to/bar/`, the superproject tracks the
+submodule via a `gitlink` entry in the tree at `path/to/bar` and an entry
+in its `.gitmodules` file (see linkgit:gitmodules[5]) of the form
+`submodule.foo.path = path/to/bar`.
+
+The `gitlink` entry contains the object name of the commit that the
+superproject expects the submodule's working directory to be at.
+
+The section `submodule.foo.*` in the `.gitmodules` file gives additional
+hints to Git's porcelain layer. For example, the `submodule.foo.url`
+setting specifies where to obtain the submodule.
+
+Submodules can be used for at least two different use cases:
+
+1. Using another project while maintaining independent history.
+  Submodules allow you to contain the working tree of another project
+  within your own working tree while keeping the history of both
+  projects separate. Also, since submodules are fixed to an arbitrary
+  version, the other project can be independently developed without
+  affecting the superproject, allowing the superproject project to
+  fix itself to new versions only when desired.
+
+2. Splitting a (logically single) project into multiple
+   repositories and tying them back together. This can be used to
+   overcome current limitations of Git's implementation to have
+   finer grained access:
+
+    * Size of the Git repository:
+      In its current form Git scales up poorly for large repositories containing
+      content that is not compressed by delta computation between trees.
+      For example, you can use submodules to hold large binary assets
+      and these repositories can be shallowly cloned such that you do not
+      have a large history locally.
+    * Transfer size:
+      In its current form Git requires the whole working tree present. It
+      does not allow partial trees to be transferred in fetch or clone.
+      If the project you work on consists of multiple repositories tied
+      together as submodules in a superproject, you can avoid fetching the
+      working trees of the repositories you are not interested in.
+    * Access control:
+      By restricting user access to submodules, this can be used to implement
+      read/write policies for different users.
+
+The configuration of submodules
+-------------------------------
+
+Submodule operations can be configured using the following mechanisms
+(from highest to lowest precedence):
+
+ * The command line for those commands that support taking submodules
+   as part of their pathspecs. Most commands have a boolean flag
+   `--recurse-submodules` which specifies whether to recurse into submodules.
+   Examples are `grep` and `checkout`.
+   Some commands take enums, such as `fetch` and `push`, where you can
+   specify how submodules are affected.
+
+ * The configuration inside the submodule. This includes `$GIT_DIR/config`
+   in the submodule, but also settings in the tree such as a `.gitattributes`
+   or `.gitignore` files that specify behavior of commands inside the
+   submodule.
++
+For example an effect from the submodule's `.gitignore` file
+would be observed when you run `git status --ignore-submodules=none` in
+the superproject. This collects information from the submodule's working
+directory by running `status` in the submodule while paying attention
+to the `.gitignore` file of the submodule.
++
+The submodule's `$GIT_DIR/config` file would come into play when running
+`git push --recurse-submodules=check` in the superproject, as this would
+check if the submodule has any changes not published to any remote. The
+remotes are configured in the submodule as usual in the `$GIT_DIR/config`
+file.
+
+ * The configuration file `$GIT_DIR/config` in the superproject.
+   Git only recurses into active submodules (see "ACTIVE SUBMODULES"
+   section below).
++
+If the submodule is not yet initialized, then the configuration
+inside the submodule does not exist yet, so where to
+obtain the submodule from is configured here for example.
+
+ * The `.gitmodules` file inside the superproject. A project usually
+   uses this file to suggest defaults for the upstream collection
+   of repositories for the mapping that is required between a
+   submodule's name and its path.
++
+This file mainly serves as the mapping between the name and path of submodules
+in the superproject, such that the submodule's Git directory can be
+located.
++
+If the submodule has never been initialized, this is the only place
+where submodule configuration is found. It serves as the last fallback
+to specify where to obtain the submodule from.
+
+FORMS
+-----
+
+Submodules can take the following forms:
+
+ * The basic form described in DESCRIPTION with a Git directory,
+a working directory, a `gitlink`, and a `.gitmodules` entry.
+
+ * "Old-form" submodule: A working directory with an embedded
+`.git` directory, and the tracking `gitlink` and `.gitmodules` entry in
+the superproject. This is typically found in repositories generated
+using older versions of Git.
++
+It is possible to construct these old form repositories manually.
++
+When deinitialized or deleted (see below), the submodule's Git
+directory is automatically moved to `$GIT_DIR/modules/<name>/`
+of the superproject.
+
+ * Deinitialized submodule: A `gitlink`, and a `.gitmodules` entry,
+but no submodule working directory. The submodule's Git directory
+may be there as after deinitializing the Git directory is kept around.
+The directory which is supposed to be the working directory is empty instead.
++
+A submodule can be deinitialized by running `git submodule deinit`.
+Besides emptying the working directory, this command only modifies
+the superproject's `$GIT_DIR/config` file, so the superproject's history
+is not affected. This can be undone using `git submodule init`.
+
+ * Deleted submodule: A submodule can be deleted by running
+`git rm <submodule-path> && git commit`. This can be undone
+using `git revert`.
++
+The deletion removes the superproject's tracking data, which are
+both the `gitlink` entry and the section in the `.gitmodules` file.
+The submodule's working directory is removed from the file
+system, but the Git directory is kept around as it to make it
+possible to checkout past commits without requiring fetching
+from another repository.
++
+To completely remove a submodule, manually delete
+`$GIT_DIR/modules/<name>/`.
+
+ACTIVE SUBMODULES
+-----------------
+
+A submodule is considered active,
+
+  1. if `submodule.<name>.active` is set to `true`
++
+or
+
+  2. if the submodule's path matches the pathspec in `submodule.active`
++
+or
+
+  3. if `submodule.<name>.url` is set.
+
+and these are evaluated in this order.
+
+For example:
+
+  [submodule "foo"]
+    active = false
+    url = https://example.org/foo
+  [submodule "bar"]
+    active = true
+    url = https://example.org/bar
+  [submodule "baz"]
+    url = https://example.org/baz
+
+In the above config only the submodules 'bar' and 'baz' are active,
+'bar' due to (1) and 'baz' due to (3). 'foo' is inactive because
+(1) takes precedence over (3)
+
+Note that (3) is a historical artefact and will be ignored if the
+(1) and (2) specify that the submodule is not active. In other words,
+if we have a `submodule.<name>.active` set to `false` or if the
+submodule's path is excluded in the pathspec in `submodule.active`, the
+url doesn't matter whether it is present or not. This is illustrated in
+the example that follows.
+
+  [submodule "foo"]
+    active = true
+    url = https://example.org/foo
+  [submodule "bar"]
+    url = https://example.org/bar
+  [submodule "baz"]
+    url = https://example.org/baz
+  [submodule "bob"]
+    ignore = true
+  [submodule]
+    active = b*
+    active = :(exclude) baz
+
+In here all submodules except 'baz' (foo, bar, bob) are active.
+'foo' due to its own active flag and all the others due to the
+submodule active pathspec, which specifies that any submodule
+starting with 'b' except 'baz' are also active, regardless of the
+presence of the .url field.
+
+Workflow for a third party library
+----------------------------------
+
+  # Add a submodule
+  git submodule add <URL> <path>
+
+  # Occasionally update the submodule to a new version:
+  git -C <path> checkout <new-version>
+  git add <path>
+  git commit -m "update submodule to new version"
+
+  # See the list of submodules in a superproject
+  git submodule status
+
+  # See FORMS on removing submodules
+
+
+Workflow for an artificially split repo
+--------------------------------------
+
+  # Enable recursion for relevant commands, such that
+  # regular commands recurse into submodules by default
+  git config --global submodule.recurse true
+
+  # Unlike most other commands below, clone still needs
+  # its own recurse flag:
+  git clone --recurse <URL> <directory>
+  cd <directory>
+
+  # Get to know the code:
+  git grep foo
+  git ls-files --recurse-submodules
+
+[NOTE]
+`git ls-files` also requires its own `--recurse-submodules` flag.
+
+  # Get new code
+  git fetch
+  git pull --rebase
+
+  # Change worktree
+  git checkout
+  git reset
+
+Implementation details
+----------------------
+
+When cloning or pulling a repository containing submodules the submodules
+will not be checked out by default; you can instruct `clone` to recurse
+into submodules. The `init` and `update` subcommands of `git submodule`
+will maintain submodules checked out and at an appropriate revision in
+your working tree. Alternatively you can set `submodule.recurse` to have
+`checkout` recurse into submodules (note that `submodule.recurse` also
+affects other Git commands, see linkgit:git-config[1] for a complete list).
+
+
+SEE ALSO
+--------
+linkgit:git-submodule[1], linkgit:gitmodules[5].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gittutorial-2.adoc b/Documentation/gittutorial-2.adoc
new file mode 100644
index 0000000000..8bdb7d0bd3
--- /dev/null
+++ b/Documentation/gittutorial-2.adoc
@@ -0,0 +1,436 @@
+gittutorial-2(7)
+================
+
+NAME
+----
+gittutorial-2 - A tutorial introduction to Git: part two
+
+SYNOPSIS
+--------
+[verse]
+git *
+
+DESCRIPTION
+-----------
+
+You should work through linkgit:gittutorial[7] before reading this tutorial.
+
+The goal of this tutorial is to introduce two fundamental pieces of
+Git's architecture--the object database and the index file--and to
+provide the reader with everything necessary to understand the rest
+of the Git documentation.
+
+The Git object database
+-----------------------
+
+Let's start a new project and create a small amount of history:
+
+------------------------------------------------
+$ mkdir test-project
+$ cd test-project
+$ git init
+Initialized empty Git repository in .git/
+$ echo 'hello world' > file.txt
+$ git add .
+$ git commit -a -m "initial commit"
+[master (root-commit) 54196cc] initial commit
+ 1 file changed, 1 insertion(+)
+ create mode 100644 file.txt
+$ echo 'hello world!' >file.txt
+$ git commit -a -m "add emphasis"
+[master c4d59f3] add emphasis
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+------------------------------------------------
+
+What are the 7 digits of hex that Git responded to the commit with?
+
+We saw in part one of the tutorial that commits have names like this.
+It turns out that every object in the Git history is stored under
+a 40-digit hex name.  That name is the SHA-1 hash of the object's
+contents; among other things, this ensures that Git will never store
+the same data twice (since identical data is given an identical SHA-1
+name), and that the contents of a Git object will never change (since
+that would change the object's name as well). The 7 char hex strings
+here are simply the abbreviation of such 40 character long strings.
+Abbreviations can be used everywhere where the 40 character strings
+can be used, so long as they are unambiguous.
+
+It is expected that the content of the commit object you created while
+following the example above generates a different SHA-1 hash than
+the one shown above because the commit object records the time when
+it was created and the name of the person performing the commit.
+
+We can ask Git about this particular object with the `cat-file`
+command. Don't copy the 40 hex digits from this example but use those
+from your own version. Note that you can shorten it to only a few
+characters to save yourself typing all 40 hex digits:
+
+------------------------------------------------
+$ git cat-file -t 54196cc2
+commit
+$ git cat-file commit 54196cc2
+tree 92b8b694ffb1675e5975148e1121810081dbdffe
+author J. Bruce Fields <bfields@xxxxxxxxxxxxxxxxxxx> 1143414668 -0500
+committer J. Bruce Fields <bfields@xxxxxxxxxxxxxxxxxxx> 1143414668 -0500
+
+initial commit
+------------------------------------------------
+
+A tree can refer to one or more "blob" objects, each corresponding to
+a file.  In addition, a tree can also refer to other tree objects,
+thus creating a directory hierarchy.  You can examine the contents of
+any tree using ls-tree (remember that a long enough initial portion
+of the SHA-1 will also work):
+
+------------------------------------------------
+$ git ls-tree 92b8b694
+100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    file.txt
+------------------------------------------------
+
+Thus we see that this tree has one file in it.  The SHA-1 hash is a
+reference to that file's data:
+
+------------------------------------------------
+$ git cat-file -t 3b18e512
+blob
+------------------------------------------------
+
+A "blob" is just file data, which we can also examine with cat-file:
+
+------------------------------------------------
+$ git cat-file blob 3b18e512
+hello world
+------------------------------------------------
+
+Note that this is the old file data; so the object that Git named in
+its response to the initial tree was a tree with a snapshot of the
+directory state that was recorded by the first commit.
+
+All of these objects are stored under their SHA-1 names inside the Git
+directory:
+
+------------------------------------------------
+$ find .git/objects/
+.git/objects/
+.git/objects/pack
+.git/objects/info
+.git/objects/3b
+.git/objects/3b/18e512dba79e4c8300dd08aeb37f8e728b8dad
+.git/objects/92
+.git/objects/92/b8b694ffb1675e5975148e1121810081dbdffe
+.git/objects/54
+.git/objects/54/196cc2703dc165cbd373a65a4dcf22d50ae7f7
+.git/objects/a0
+.git/objects/a0/423896973644771497bdc03eb99d5281615b51
+.git/objects/d0
+.git/objects/d0/492b368b66bdabf2ac1fd8c92b39d3db916e59
+.git/objects/c4
+.git/objects/c4/d59f390b9cfd4318117afde11d601c1085f241
+------------------------------------------------
+
+and the contents of these files is just the compressed data plus a
+header identifying their length and their type.  The type is either a
+blob, a tree, a commit, or a tag.
+
+The simplest commit to find is the HEAD commit, which we can find
+from .git/HEAD:
+
+------------------------------------------------
+$ cat .git/HEAD
+ref: refs/heads/master
+------------------------------------------------
+
+As you can see, this tells us which branch we're currently on, and it
+tells us this by naming a file under the .git directory, which itself
+contains a SHA-1 name referring to a commit object, which we can
+examine with cat-file:
+
+------------------------------------------------
+$ cat .git/refs/heads/master
+c4d59f390b9cfd4318117afde11d601c1085f241
+$ git cat-file -t c4d59f39
+commit
+$ git cat-file commit c4d59f39
+tree d0492b368b66bdabf2ac1fd8c92b39d3db916e59
+parent 54196cc2703dc165cbd373a65a4dcf22d50ae7f7
+author J. Bruce Fields <bfields@xxxxxxxxxxxxxxxxxxx> 1143418702 -0500
+committer J. Bruce Fields <bfields@xxxxxxxxxxxxxxxxxxx> 1143418702 -0500
+
+add emphasis
+------------------------------------------------
+
+The "tree" object here refers to the new state of the tree:
+
+------------------------------------------------
+$ git ls-tree d0492b36
+100644 blob a0423896973644771497bdc03eb99d5281615b51    file.txt
+$ git cat-file blob a0423896
+hello world!
+------------------------------------------------
+
+and the "parent" object refers to the previous commit:
+
+------------------------------------------------
+$ git cat-file commit 54196cc2
+tree 92b8b694ffb1675e5975148e1121810081dbdffe
+author J. Bruce Fields <bfields@xxxxxxxxxxxxxxxxxxx> 1143414668 -0500
+committer J. Bruce Fields <bfields@xxxxxxxxxxxxxxxxxxx> 1143414668 -0500
+
+initial commit
+------------------------------------------------
+
+The tree object is the tree we examined first, and this commit is
+unusual in that it lacks any parent.
+
+Most commits have only one parent, but it is also common for a commit
+to have multiple parents.   In that case the commit represents a
+merge, with the parent references pointing to the heads of the merged
+branches.
+
+Besides blobs, trees, and commits, the only remaining type of object
+is a "tag", which we won't discuss here; refer to linkgit:git-tag[1]
+for details.
+
+So now we know how Git uses the object database to represent a
+project's history:
+
+  * "commit" objects refer to "tree" objects representing the
+    snapshot of a directory tree at a particular point in the
+    history, and refer to "parent" commits to show how they're
+    connected into the project history.
+  * "tree" objects represent the state of a single directory,
+    associating directory names to "blob" objects containing file
+    data and "tree" objects containing subdirectory information.
+  * "blob" objects contain file data without any other structure.
+  * References to commit objects at the head of each branch are
+    stored in files under .git/refs/heads/.
+  * The name of the current branch is stored in .git/HEAD.
+
+Note, by the way, that lots of commands take a tree as an argument.
+But as we can see above, a tree can be referred to in many different
+ways--by the SHA-1 name for that tree, by the name of a commit that
+refers to the tree, by the name of a branch whose head refers to that
+tree, etc.--and most such commands can accept any of these names.
+
+In command synopses, the word "tree-ish" is sometimes used to
+designate such an argument.
+
+The index file
+--------------
+
+The primary tool we've been using to create commits is `git-commit
+-a`, which creates a commit including every change you've made to
+your working tree.  But what if you want to commit changes only to
+certain files?  Or only certain changes to certain files?
+
+If we look at the way commits are created under the cover, we'll see
+that there are more flexible ways creating commits.
+
+Continuing with our test-project, let's modify file.txt again:
+
+------------------------------------------------
+$ echo "hello world, again" >>file.txt
+------------------------------------------------
+
+but this time instead of immediately making the commit, let's take an
+intermediate step, and ask for diffs along the way to keep track of
+what's happening:
+
+------------------------------------------------
+$ git diff
+--- a/file.txt
++++ b/file.txt
+@@ -1 +1,2 @@
+ hello world!
++hello world, again
+$ git add file.txt
+$ git diff
+------------------------------------------------
+
+The last diff is empty, but no new commits have been made, and the
+head still doesn't contain the new line:
+
+------------------------------------------------
+$ git diff HEAD
+diff --git a/file.txt b/file.txt
+index a042389..513feba 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1 +1,2 @@
+ hello world!
++hello world, again
+------------------------------------------------
+
+So 'git diff' is comparing against something other than the head.
+The thing that it's comparing against is actually the index file,
+which is stored in .git/index in a binary format, but whose contents
+we can examine with ls-files:
+
+------------------------------------------------
+$ git ls-files --stage
+100644 513feba2e53ebbd2532419ded848ba19de88ba00 0       file.txt
+$ git cat-file -t 513feba2
+blob
+$ git cat-file blob 513feba2
+hello world!
+hello world, again
+------------------------------------------------
+
+So what our 'git add' did was store a new blob and then put
+a reference to it in the index file.  If we modify the file again,
+we'll see that the new modifications are reflected in the 'git diff'
+output:
+
+------------------------------------------------
+$ echo 'again?' >>file.txt
+$ git diff
+index 513feba..ba3da7b 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,2 +1,3 @@
+ hello world!
+ hello world, again
++again?
+------------------------------------------------
+
+With the right arguments, 'git diff' can also show us the difference
+between the working directory and the last commit, or between the
+index and the last commit:
+
+------------------------------------------------
+$ git diff HEAD
+diff --git a/file.txt b/file.txt
+index a042389..ba3da7b 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1 +1,3 @@
+ hello world!
++hello world, again
++again?
+$ git diff --cached
+diff --git a/file.txt b/file.txt
+index a042389..513feba 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1 +1,2 @@
+ hello world!
++hello world, again
+------------------------------------------------
+
+At any time, we can create a new commit using 'git commit' (without
+the "-a" option), and verify that the state committed only includes the
+changes stored in the index file, not the additional change that is
+still only in our working tree:
+
+------------------------------------------------
+$ git commit -m "repeat"
+$ git diff HEAD
+diff --git a/file.txt b/file.txt
+index 513feba..ba3da7b 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,2 +1,3 @@
+ hello world!
+ hello world, again
++again?
+------------------------------------------------
+
+So by default 'git commit' uses the index to create the commit, not
+the working tree; the "-a" option to commit tells it to first update
+the index with all changes in the working tree.
+
+Finally, it's worth looking at the effect of 'git add' on the index
+file:
+
+------------------------------------------------
+$ echo "goodbye, world" >closing.txt
+$ git add closing.txt
+------------------------------------------------
+
+The effect of the 'git add' was to add one entry to the index file:
+
+------------------------------------------------
+$ git ls-files --stage
+100644 8b9743b20d4b15be3955fc8d5cd2b09cd2336138 0       closing.txt
+100644 513feba2e53ebbd2532419ded848ba19de88ba00 0       file.txt
+------------------------------------------------
+
+And, as you can see with cat-file, this new entry refers to the
+current contents of the file:
+
+------------------------------------------------
+$ git cat-file blob 8b9743b2
+goodbye, world
+------------------------------------------------
+
+The "status" command is a useful way to get a quick summary of the
+situation:
+
+------------------------------------------------
+$ git status
+On branch master
+Changes to be committed:
+  (use "git restore --staged <file>..." to unstage)
+
+	new file:   closing.txt
+
+Changes not staged for commit:
+  (use "git add <file>..." to update what will be committed)
+  (use "git restore <file>..." to discard changes in working directory)
+
+	modified:   file.txt
+
+------------------------------------------------
+
+Since the current state of closing.txt is cached in the index file,
+it is listed as "Changes to be committed".  Since file.txt has
+changes in the working directory that aren't reflected in the index,
+it is marked "changed but not updated".  At this point, running "git
+commit" would create a commit that added closing.txt (with its new
+contents), but that didn't modify file.txt.
+
+Also, note that a bare `git diff` shows the changes to file.txt, but
+not the addition of closing.txt, because the version of closing.txt
+in the index file is identical to the one in the working directory.
+
+In addition to being the staging area for new commits, the index file
+is also populated from the object database when checking out a
+branch, and is used to hold the trees involved in a merge operation.
+See linkgit:gitcore-tutorial[7] and the relevant man
+pages for details.
+
+What next?
+----------
+
+At this point you should know everything necessary to read the man
+pages for any of the git commands; one good place to start would be
+with the commands mentioned in linkgit:giteveryday[7].  You
+should be able to find any unknown jargon in linkgit:gitglossary[7].
+
+The link:user-manual.html[Git User's Manual] provides a more
+comprehensive introduction to Git.
+
+linkgit:gitcvs-migration[7] explains how to
+import a CVS repository into Git, and shows how to use Git in a
+CVS-like way.
+
+For some interesting examples of Git use, see the
+link:howto-index.html[howtos].
+
+For Git developers, linkgit:gitcore-tutorial[7] goes
+into detail on the lower-level Git mechanisms involved in, for
+example, creating a new commit.
+
+SEE ALSO
+--------
+linkgit:gittutorial[7],
+linkgit:gitcvs-migration[7],
+linkgit:gitcore-tutorial[7],
+linkgit:gitglossary[7],
+linkgit:git-help[1],
+linkgit:giteveryday[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gittutorial.adoc b/Documentation/gittutorial.adoc
new file mode 100644
index 0000000000..f89ad30cf6
--- /dev/null
+++ b/Documentation/gittutorial.adoc
@@ -0,0 +1,676 @@
+gittutorial(7)
+==============
+
+NAME
+----
+gittutorial - A tutorial introduction to Git
+
+SYNOPSIS
+--------
+[verse]
+git *
+
+DESCRIPTION
+-----------
+
+This tutorial explains how to import a new project into Git, make
+changes to it, and share changes with other developers.
+
+If you are instead primarily interested in using Git to fetch a project,
+for example, to test the latest version, you may prefer to start with
+the first two chapters of link:user-manual.html[The Git User's Manual].
+
+First, note that you can get documentation for a command such as
+`git log --graph` with:
+
+------------------------------------------------
+$ man git-log
+------------------------------------------------
+
+or:
+
+------------------------------------------------
+$ git help log
+------------------------------------------------
+
+With the latter, you can use the manual viewer of your choice; see
+linkgit:git-help[1] for more information.
+
+It is a good idea to introduce yourself to Git with your name and
+public email address before doing any operation.  The easiest
+way to do so is:
+
+------------------------------------------------
+$ git config --global user.name "Your Name Comes Here"
+$ git config --global user.email you@xxxxxxxxxxxxxxxxxxxxxx
+------------------------------------------------
+
+
+Importing a new project
+-----------------------
+
+Assume you have a tarball `project.tar.gz` with your initial work.  You
+can place it under Git revision control as follows.
+
+------------------------------------------------
+$ tar xzf project.tar.gz
+$ cd project
+$ git init
+------------------------------------------------
+
+Git will reply
+
+------------------------------------------------
+Initialized empty Git repository in .git/
+------------------------------------------------
+
+You've now initialized the working directory--you may notice a new
+directory created, named `.git`.
+
+Next, tell Git to take a snapshot of the contents of all files under the
+current directory (note the `.`), with `git add`:
+
+------------------------------------------------
+$ git add .
+------------------------------------------------
+
+This snapshot is now stored in a temporary staging area which Git calls
+the "index".  You can permanently store the contents of the index in the
+repository with `git commit`:
+
+------------------------------------------------
+$ git commit
+------------------------------------------------
+
+This will prompt you for a commit message.  You've now stored the first
+version of your project in Git.
+
+Making changes
+--------------
+
+Modify some files, then add their updated contents to the index:
+
+------------------------------------------------
+$ git add file1 file2 file3
+------------------------------------------------
+
+You are now ready to commit.  You can see what is about to be committed
+using `git diff` with the `--cached` option:
+
+------------------------------------------------
+$ git diff --cached
+------------------------------------------------
+
+(Without `--cached`, `git diff` will show you any changes that
+you've made but not yet added to the index.)  You can also get a brief
+summary of the situation with `git status`:
+
+------------------------------------------------
+$ git status
+On branch master
+Changes to be committed:
+  (use "git restore --staged <file>..." to unstage)
+
+	modified:   file1
+	modified:   file2
+	modified:   file3
+
+------------------------------------------------
+
+If you need to make any further adjustments, do so now, and then add any
+newly modified content to the index.  Finally, commit your changes with:
+
+------------------------------------------------
+$ git commit
+------------------------------------------------
+
+This will again prompt you for a message describing the change, and then
+record a new version of the project.
+
+Alternatively, instead of running `git add` beforehand, you can use
+
+------------------------------------------------
+$ git commit -a
+------------------------------------------------
+
+which will automatically notice any modified (but not new) files, add
+them to the index, and commit, all in one step.
+
+A note on commit messages: Though not required, it's a good idea to
+begin the commit message with a single short (no more than 50
+characters) line summarizing the change, followed by a blank line and
+then a more thorough description. The text up to the first blank line in
+a commit message is treated as the commit title, and that title is used
+throughout Git.  For example, linkgit:git-format-patch[1] turns a
+commit into email, and it uses the title on the Subject line and the
+rest of the commit in the body.
+
+Git tracks content not files
+----------------------------
+
+Many revision control systems provide an `add` command that tells the
+system to start tracking changes to a new file.  Git's `add` command
+does something simpler and more powerful: `git add` is used both for new
+and newly modified files, and in both cases it takes a snapshot of the
+given files and stages that content in the index, ready for inclusion in
+the next commit.
+
+Viewing project history
+-----------------------
+
+At any point you can view the history of your changes using
+
+------------------------------------------------
+$ git log
+------------------------------------------------
+
+If you also want to see complete diffs at each step, use
+
+------------------------------------------------
+$ git log -p
+------------------------------------------------
+
+Often the overview of the change is useful to get a feel of
+each step
+
+------------------------------------------------
+$ git log --stat --summary
+------------------------------------------------
+
+Managing branches
+-----------------
+
+A single Git repository can maintain multiple branches of
+development.  To create a new branch named `experimental`, use
+
+------------------------------------------------
+$ git branch experimental
+------------------------------------------------
+
+If you now run
+
+------------------------------------------------
+$ git branch
+------------------------------------------------
+
+you'll get a list of all existing branches:
+
+------------------------------------------------
+  experimental
+* master
+------------------------------------------------
+
+The `experimental` branch is the one you just created, and the
+`master` branch is a default branch that was created for you
+automatically.  The asterisk marks the branch you are currently on;
+type
+
+------------------------------------------------
+$ git switch experimental
+------------------------------------------------
+
+to switch to the `experimental` branch.  Now edit a file, commit the
+change, and switch back to the `master` branch:
+
+------------------------------------------------
+(edit file)
+$ git commit -a
+$ git switch master
+------------------------------------------------
+
+Check that the change you made is no longer visible, since it was
+made on the `experimental` branch and you're back on the `master` branch.
+
+You can make a different change on the `master` branch:
+
+------------------------------------------------
+(edit file)
+$ git commit -a
+------------------------------------------------
+
+at this point the two branches have diverged, with different changes
+made in each.  To merge the changes made in `experimental` into `master`, run
+
+------------------------------------------------
+$ git merge experimental
+------------------------------------------------
+
+If the changes don't conflict, you're done.  If there are conflicts,
+markers will be left in the problematic files showing the conflict;
+
+------------------------------------------------
+$ git diff
+------------------------------------------------
+
+will show this.  Once you've edited the files to resolve the
+conflicts,
+
+------------------------------------------------
+$ git commit -a
+------------------------------------------------
+
+will commit the result of the merge. Finally,
+
+------------------------------------------------
+$ gitk
+------------------------------------------------
+
+will show a nice graphical representation of the resulting history.
+
+At this point you could delete the `experimental` branch with
+
+------------------------------------------------
+$ git branch -d experimental
+------------------------------------------------
+
+This command ensures that the changes in the `experimental` branch are
+already in the current branch.
+
+If you develop on a branch `crazy-idea`, then regret it, you can always
+delete the branch with
+
+-------------------------------------
+$ git branch -D crazy-idea
+-------------------------------------
+
+Branches are cheap and easy, so this is a good way to try something
+out.
+
+Using Git for collaboration
+---------------------------
+
+Suppose that Alice has started a new project with a Git repository in
+`/home/alice/project`, and that Bob, who has a home directory on the
+same machine, wants to contribute.
+
+Bob begins with:
+
+------------------------------------------------
+bob$ git clone /home/alice/project myrepo
+------------------------------------------------
+
+This creates a new directory `myrepo` containing a clone of Alice's
+repository.  The clone is on an equal footing with the original
+project, possessing its own copy of the original project's history.
+
+Bob then makes some changes and commits them:
+
+------------------------------------------------
+(edit files)
+bob$ git commit -a
+(repeat as necessary)
+------------------------------------------------
+
+When he's ready, he tells Alice to pull changes from the repository
+at `/home/bob/myrepo`.  She does this with:
+
+------------------------------------------------
+alice$ cd /home/alice/project
+alice$ git pull /home/bob/myrepo master
+------------------------------------------------
+
+This merges the changes from Bob's `master` branch into Alice's
+current branch.  If Alice has made her own changes in the meantime,
+then she may need to manually fix any conflicts.
+
+The `pull` command thus performs two operations: it fetches changes
+from a remote branch, then merges them into the current branch.
+
+Note that in general, Alice would want her local changes committed before
+initiating this `pull`.  If Bob's work conflicts with what Alice did since
+their histories forked, Alice will use her working tree and the index to
+resolve conflicts, and existing local changes will interfere with the
+conflict resolution process (Git will still perform the fetch but will
+refuse to merge -- Alice will have to get rid of her local changes in
+some way and pull again when this happens).
+
+Alice can peek at what Bob did without merging first, using the `fetch`
+command; this allows Alice to inspect what Bob did, using a special
+symbol `FETCH_HEAD`, in order to determine if he has anything worth
+pulling, like this:
+
+------------------------------------------------
+alice$ git fetch /home/bob/myrepo master
+alice$ git log -p HEAD..FETCH_HEAD
+------------------------------------------------
+
+This operation is safe even if Alice has uncommitted local changes.
+The range notation `HEAD..FETCH_HEAD` means "show everything that is reachable
+from the `FETCH_HEAD` but exclude anything that is reachable from `HEAD`".
+Alice already knows everything that leads to her current state (`HEAD`),
+and reviews what Bob has in his state (`FETCH_HEAD`) that she has not
+seen with this command.
+
+If Alice wants to visualize what Bob did since their histories forked
+she can issue the following command:
+
+------------------------------------------------
+$ gitk HEAD..FETCH_HEAD
+------------------------------------------------
+
+This uses the same two-dot range notation we saw earlier with `git log`.
+
+Alice may want to view what both of them did since they forked.
+She can use three-dot form instead of the two-dot form:
+
+------------------------------------------------
+$ gitk HEAD...FETCH_HEAD
+------------------------------------------------
+
+This means "show everything that is reachable from either one, but
+exclude anything that is reachable from both of them".
+
+Please note that these range notations can be used with both `gitk`
+and `git log`.
+
+After inspecting what Bob did, if there is nothing urgent, Alice may
+decide to continue working without pulling from Bob.  If Bob's history
+does have something Alice would immediately need, Alice may choose to
+stash her work-in-progress first, do a `pull`, and then finally unstash
+her work-in-progress on top of the resulting history.
+
+When you are working in a small closely knit group, it is not
+unusual to interact with the same repository over and over
+again.  By defining 'remote' repository shorthand, you can make
+it easier:
+
+------------------------------------------------
+alice$ git remote add bob /home/bob/myrepo
+------------------------------------------------
+
+With this, Alice can perform the first part of the `pull` operation
+alone using the `git fetch` command without merging them with her own
+branch, using:
+
+-------------------------------------
+alice$ git fetch bob
+-------------------------------------
+
+Unlike the longhand form, when Alice fetches from Bob using a
+remote repository shorthand set up with `git remote`, what was
+fetched is stored in a remote-tracking branch, in this case
+`bob/master`.  So after this:
+
+-------------------------------------
+alice$ git log -p master..bob/master
+-------------------------------------
+
+shows a list of all the changes that Bob made since he branched from
+Alice's `master` branch.
+
+After examining those changes, Alice
+could merge the changes into her `master` branch:
+
+-------------------------------------
+alice$ git merge bob/master
+-------------------------------------
+
+This `merge` can also be done by 'pulling from her own remote-tracking
+branch', like this:
+
+-------------------------------------
+alice$ git pull . remotes/bob/master
+-------------------------------------
+
+Note that git pull always merges into the current branch,
+regardless of what else is given on the command line.
+
+Later, Bob can update his repo with Alice's latest changes using
+
+-------------------------------------
+bob$ git pull
+-------------------------------------
+
+Note that he doesn't need to give the path to Alice's repository;
+when Bob cloned Alice's repository, Git stored the location of her
+repository in the repository configuration, and that location is
+used for pulls:
+
+-------------------------------------
+bob$ git config --get remote.origin.url
+/home/alice/project
+-------------------------------------
+
+(The complete configuration created by `git clone` is visible using
+`git config -l`, and the linkgit:git-config[1] man page
+explains the meaning of each option.)
+
+Git also keeps a pristine copy of Alice's `master` branch under the
+name `origin/master`:
+
+-------------------------------------
+bob$ git branch -r
+  origin/master
+-------------------------------------
+
+If Bob later decides to work from a different host, he can still
+perform clones and pulls using the ssh protocol:
+
+-------------------------------------
+bob$ git clone alice.org:/home/alice/project myrepo
+-------------------------------------
+
+Alternatively, Git has a native protocol, or can use http;
+see linkgit:git-pull[1] for details.
+
+Git can also be used in a CVS-like mode, with a central repository
+that various users push changes to; see linkgit:git-push[1] and
+linkgit:gitcvs-migration[7].
+
+Exploring history
+-----------------
+
+Git history is represented as a series of interrelated commits.  We
+have already seen that the `git log` command can list those commits.
+Note that first line of each `git log` entry also gives a name for the
+commit:
+
+-------------------------------------
+$ git log
+commit c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
+Author: Junio C Hamano <junkio@xxxxxxx>
+Date:   Tue May 16 17:18:22 2006 -0700
+
+    merge-base: Clarify the comments on post processing.
+-------------------------------------
+
+We can give this name to `git show` to see the details about this
+commit.
+
+-------------------------------------
+$ git show c82a22c39cbc32576f64f5c6b3f24b99ea8149c7
+-------------------------------------
+
+But there are other ways to refer to commits.  You can use any initial
+part of the name that is long enough to uniquely identify the commit:
+
+-------------------------------------
+$ git show c82a22c39c	# the first few characters of the name are
+			# usually enough
+$ git show HEAD		# the tip of the current branch
+$ git show experimental	# the tip of the "experimental" branch
+-------------------------------------
+
+Every commit usually has one "parent" commit
+which points to the previous state of the project:
+
+-------------------------------------
+$ git show HEAD^  # to see the parent of HEAD
+$ git show HEAD^^ # to see the grandparent of HEAD
+$ git show HEAD~4 # to see the great-great grandparent of HEAD
+-------------------------------------
+
+Note that merge commits may have more than one parent:
+
+-------------------------------------
+$ git show HEAD^1 # show the first parent of HEAD (same as HEAD^)
+$ git show HEAD^2 # show the second parent of HEAD
+-------------------------------------
+
+You can also give commits names of your own; after running
+
+-------------------------------------
+$ git tag v2.5 1b2e1d63ff
+-------------------------------------
+
+you can refer to `1b2e1d63ff` by the name `v2.5`.  If you intend to
+share this name with other people (for example, to identify a release
+version), you should create a "tag" object, and perhaps sign it; see
+linkgit:git-tag[1] for details.
+
+Any Git command that needs to know a commit can take any of these
+names.  For example:
+
+-------------------------------------
+$ git diff v2.5 HEAD	 # compare the current HEAD to v2.5
+$ git branch stable v2.5 # start a new branch named "stable" based
+			 # at v2.5
+$ git reset --hard HEAD^ # reset your current branch and working
+			 # directory to its state at HEAD^
+-------------------------------------
+
+Be careful with that last command: in addition to losing any changes
+in the working directory, it will also remove all later commits from
+this branch.  If this branch is the only branch containing those
+commits, they will be lost.  Also, don't use `git reset` on a
+publicly-visible branch that other developers pull from, as it will
+force needless merges on other developers to clean up the history.
+If you need to undo changes that you have pushed, use `git revert`
+instead.
+
+The `git grep` command can search for strings in any version of your
+project, so
+
+-------------------------------------
+$ git grep "hello" v2.5
+-------------------------------------
+
+searches for all occurrences of "hello" in `v2.5`.
+
+If you leave out the commit name, `git grep` will search any of the
+files it manages in your current directory.  So
+
+-------------------------------------
+$ git grep "hello"
+-------------------------------------
+
+is a quick way to search just the files that are tracked by Git.
+
+Many Git commands also take sets of commits, which can be specified
+in a number of ways.  Here are some examples with `git log`:
+
+-------------------------------------
+$ git log v2.5..v2.6            # commits between v2.5 and v2.6
+$ git log v2.5..                # commits since v2.5
+$ git log --since="2 weeks ago" # commits from the last 2 weeks
+$ git log v2.5.. Makefile       # commits since v2.5 which modify
+				# Makefile
+-------------------------------------
+
+You can also give `git log` a "range" of commits where the first is not
+necessarily an ancestor of the second; for example, if the tips of
+the branches `stable` and `master` diverged from a common
+commit some time ago, then
+
+-------------------------------------
+$ git log stable..master
+-------------------------------------
+
+will list commits made in the `master` branch but not in the
+stable branch, while
+
+-------------------------------------
+$ git log master..stable
+-------------------------------------
+
+will show the list of commits made on the stable branch but not
+the `master` branch.
+
+The `git log` command has a weakness: it must present commits in a
+list.  When the history has lines of development that diverged and
+then merged back together, the order in which `git log` presents
+those commits is meaningless.
+
+Most projects with multiple contributors (such as the Linux kernel,
+or Git itself) have frequent merges, and `gitk` does a better job of
+visualizing their history.  For example,
+
+-------------------------------------
+$ gitk --since="2 weeks ago" drivers/
+-------------------------------------
+
+allows you to browse any commits from the last 2 weeks of commits
+that modified files under the `drivers` directory.  (Note: you can
+adjust gitk's fonts by holding down the control key while pressing
+"-" or "+".)
+
+Finally, most commands that take filenames will optionally allow you
+to precede any filename by a commit, to specify a particular version
+of the file:
+
+-------------------------------------
+$ git diff v2.5:Makefile HEAD:Makefile.in
+-------------------------------------
+
+You can also use `git show` to see any such file:
+
+-------------------------------------
+$ git show v2.5:Makefile
+-------------------------------------
+
+Next Steps
+----------
+
+This tutorial should be enough to perform basic distributed revision
+control for your projects.  However, to fully understand the depth
+and power of Git you need to understand two simple ideas on which it
+is based:
+
+  * The object database is the rather elegant system used to
+    store the history of your project--files, directories, and
+    commits.
+
+  * The index file is a cache of the state of a directory tree,
+    used to create commits, check out working directories, and
+    hold the various trees involved in a merge.
+
+Part two of this tutorial explains the object
+database, the index file, and a few other odds and ends that you'll
+need to make the most of Git. You can find it at linkgit:gittutorial-2[7].
+
+If you don't want to continue with that right away, a few other
+digressions that may be interesting at this point are:
+
+  * linkgit:git-format-patch[1], linkgit:git-am[1]: These convert
+    series of git commits into emailed patches, and vice versa,
+    useful for projects such as the Linux kernel which rely heavily
+    on emailed patches.
+
+  * linkgit:git-bisect[1]: When there is a regression in your
+    project, one way to track down the bug is by searching through
+    the history to find the exact commit that's to blame.  `git bisect`
+    can help you perform a binary search for that commit.  It is
+    smart enough to perform a close-to-optimal search even in the
+    case of complex non-linear history with lots of merged branches.
+
+  * linkgit:gitworkflows[7]: Gives an overview of recommended
+    workflows.
+
+  * linkgit:giteveryday[7]: Everyday Git with 20 Commands Or So.
+
+  * linkgit:gitcvs-migration[7]: Git for CVS users.
+
+SEE ALSO
+--------
+linkgit:gittutorial-2[7],
+linkgit:gitcvs-migration[7],
+linkgit:gitcore-tutorial[7],
+linkgit:gitglossary[7],
+linkgit:git-help[1],
+linkgit:gitworkflows[7],
+linkgit:giteveryday[7],
+link:user-manual.html[The Git User's Manual]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitweb.adoc b/Documentation/gitweb.adoc
new file mode 100644
index 0000000000..5e2b491ec2
--- /dev/null
+++ b/Documentation/gitweb.adoc
@@ -0,0 +1,703 @@
+gitweb(1)
+=========
+
+NAME
+----
+gitweb - Git web interface (web frontend to Git repositories)
+
+SYNOPSIS
+--------
+To get started with gitweb, run linkgit:git-instaweb[1] from a Git repository.
+This will configure and start your web server, and run a web browser pointing to
+gitweb.
+
+
+DESCRIPTION
+-----------
+Gitweb provides a web interface to Git repositories.  Its features include:
+
+* Viewing multiple Git repositories with common root.
+* Browsing every revision of the repository.
+* Viewing the contents of files in the repository at any revision.
+* Viewing the revision log of branches, history of files and directories,
+  seeing what was changed, when, and by whom.
+* Viewing the blame/annotation details of any file (if enabled).
+* Generating RSS and Atom feeds of commits, for any branch.
+  The feeds are auto-discoverable in modern web browsers.
+* Viewing everything that was changed in a revision, and stepping through
+  revisions one at a time, viewing the history of the repository.
+* Finding commits whose commit messages match a given search term.
+
+See https://repo.or.cz/w/git.git/tree/HEAD:/gitweb/[] for gitweb source code,
+browsed using gitweb itself.
+
+
+CONFIGURATION
+-------------
+Various aspects of gitweb's behavior can be controlled through the configuration
+file `gitweb_config.perl` or `/etc/gitweb.conf`.  See the linkgit:gitweb.conf[5]
+for details.
+
+Repositories
+~~~~~~~~~~~~
+Gitweb can show information from one or more Git repositories.  These
+repositories have to be all on local filesystem, and have to share a common
+repository root, i.e. be all under a single parent repository (but see also
+the "Advanced web server setup" section, "Webserver configuration with multiple
+projects' root" subsection).
+
+-----------------------------------------------------------------------
+our $projectroot = '/path/to/parent/directory';
+-----------------------------------------------------------------------
+
+The default value for `$projectroot` is `/pub/git`.  You can change it during
+building gitweb via the `GITWEB_PROJECTROOT` build configuration variable.
+
+By default all Git repositories under `$projectroot` are visible and available
+to gitweb.  The list of projects is generated by default by scanning the
+`$projectroot` directory for Git repositories (for object databases to be
+more exact; gitweb is not interested in a working area, and is best suited
+to showing "bare" repositories).
+
+The name of the repository in gitweb is the path to its `$GIT_DIR` (its object
+database) relative to `$projectroot`.  Therefore the repository $repo can be
+found at "$projectroot/$repo".
+
+
+Projects list file format
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Instead of having gitweb find repositories by scanning the filesystem
+starting from $projectroot, you can provide a pre-generated list of
+visible projects by setting `$projects_list` to point to a plain text
+file with a list of projects (with some additional info).
+
+This file uses the following format:
+
+* One record (for project / repository) per line; does not support line
+continuation (newline escaping).
+
+* Leading and trailing whitespace are ignored.
+
+* Whitespace separated fields; any run of whitespace can be used as field
+separator (rules for Perl's "`split(" ", $line)`").
+
+* Fields use modified URI encoding, defined in RFC 3986, section 2.1
+(Percent-Encoding), or rather "Query string encoding" (see
+https://en.wikipedia.org/wiki/Query_string#URL_encoding[]), the difference
+being that SP (" ") can be encoded as "{plus}" (and therefore "{plus}" has to be
+also percent-encoded).
++
+Reserved characters are: "%" (used for encoding), "{plus}" (can be used to
+encode SPACE), all whitespace characters as defined in Perl, including SP,
+TAB and LF, (used to separate fields in a record).
+
+* Currently recognized fields are:
+<repository path>::
+	path to repository GIT_DIR, relative to `$projectroot`
+<repository owner>::
+	displayed as repository owner, preferably full name, or email,
+	or both
+
+You can generate the projects list index file using the project_index action
+(the 'TXT' link on projects list page) directly from gitweb; see also
+"Generating projects list using gitweb" section below.
+
+Example contents:
+-----------------------------------------------------------------------
+foo.git       Joe+R+Hacker+<joe@xxxxxxxxxxx>
+foo/bar.git   O+W+Ner+<owner@xxxxxxxxxxx>
+-----------------------------------------------------------------------
+
+
+By default this file controls only which projects are *visible* on projects
+list page (note that entries that do not point to correctly recognized Git
+repositories won't be displayed by gitweb).  Even if a project is not
+visible on projects list page, you can view it nevertheless by hand-crafting
+a gitweb URL.  By setting `$strict_export` configuration variable (see
+linkgit:gitweb.conf[5]) to true value you can allow viewing only of
+repositories also shown on the overview page (i.e. only projects explicitly
+listed in projects list file will be accessible).
+
+
+Generating projects list using gitweb
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+We assume that GITWEB_CONFIG has its default Makefile value, namely
+'gitweb_config.perl'. Put the following in 'gitweb_make_index.perl' file:
+----------------------------------------------------------------------------
+read_config_file("gitweb_config.perl");
+$projects_list = $projectroot;
+----------------------------------------------------------------------------
+
+Then create the following script to get list of project in the format
+suitable for GITWEB_LIST build configuration variable (or
+`$projects_list` variable in gitweb config):
+
+----------------------------------------------------------------------------
+#!/bin/sh
+
+export GITWEB_CONFIG="gitweb_make_index.perl"
+export GATEWAY_INTERFACE="CGI/1.1"
+export HTTP_ACCEPT="*/*"
+export REQUEST_METHOD="GET"
+export QUERY_STRING="a=project_index"
+
+perl -- /var/www/cgi-bin/gitweb.cgi
+----------------------------------------------------------------------------
+
+Run this script and save its output to a file.  This file could then be used
+as projects list file, which means that you can set `$projects_list` to its
+filename.
+
+
+Controlling access to Git repositories
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+By default all Git repositories under `$projectroot` are visible and
+available to gitweb.  You can however configure how gitweb controls access
+to repositories.
+
+* As described in "Projects list file format" section, you can control which
+projects are *visible* by selectively including repositories in projects
+list file, and setting `$projects_list` gitweb configuration variable to
+point to it.  With `$strict_export` set, projects list file can be used to
+control which repositories are *available* as well.
+
+* You can configure gitweb to only list and allow viewing of the explicitly
+exported repositories, via `$export_ok` variable in gitweb config file; see
+linkgit:gitweb.conf[5] manpage.  If it evaluates to true, gitweb shows
+repositories only if this file named by `$export_ok` exists in its object
+database (if directory has the magic file named `$export_ok`).
++
+For example linkgit:git-daemon[1] by default (unless `--export-all` option
+is used) allows pulling only for those repositories that have
+'git-daemon-export-ok' file.  Adding
++
+--------------------------------------------------------------------------
+our $export_ok = "git-daemon-export-ok";
+--------------------------------------------------------------------------
++
+makes gitweb show and allow access only to those repositories that can be
+fetched from via `git://` protocol.
+
+* Finally, it is possible to specify an arbitrary perl subroutine that will
+be called for each repository to determine if it can be exported.  The
+subroutine receives an absolute path to the project (repository) as its only
+parameter (i.e. "$projectroot/$project").
++
+For example, if you use mod_perl to run the script, and have dumb
+HTTP protocol authentication configured for your repositories, you
+can use the following hook to allow access only if the user is
+authorized to read the files:
++
+--------------------------------------------------------------------------
+$export_auth_hook = sub {
+	use Apache2::SubRequest ();
+	use Apache2::Const -compile => qw(HTTP_OK);
+	my $path = "$_[0]/HEAD";
+	my $r    = Apache2::RequestUtil->request;
+	my $sub  = $r->lookup_file($path);
+	return $sub->filename eq $path
+	    && $sub->status == Apache2::Const::HTTP_OK;
+};
+--------------------------------------------------------------------------
+
+
+Per-repository gitweb configuration
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can configure individual repositories shown in gitweb by creating file
+in the `GIT_DIR` of Git repository, or by setting some repo configuration
+variable (in `GIT_DIR/config`, see linkgit:git-config[1]).
+
+You can use the following files in repository:
+
+README.html::
+	A html file (HTML fragment) which is included on the gitweb project
+	"summary" page inside `<div>` block element. You can use it for longer
+	description of a project, to provide links (for example to project's
+	homepage), etc. This is recognized only if XSS prevention is off
+	(`$prevent_xss` is false, see linkgit:gitweb.conf[5]); a way to include
+	a README safely when XSS prevention is on may be worked out in the
+	future.
+
+description (or `gitweb.description`)::
+	Short (shortened to `$projects_list_description_width` in the projects
+	list page, which is 25 characters by default; see
+	linkgit:gitweb.conf[5]) single line description of a project (of a
+	repository).  Plain text file; HTML will be escaped.  By default set to
++
+-------------------------------------------------------------------------------
+Unnamed repository; edit this file to name it for gitweb.
+-------------------------------------------------------------------------------
++
+from the template during repository creation, usually installed in
+`/usr/share/git-core/templates/`.  You can use the `gitweb.description` repo
+configuration variable, but the file takes precedence.
+
+category (or `gitweb.category`)::
+	Single line category of a project, used to group projects if
+	`$projects_list_group_categories` is enabled.  By default (file and
+	configuration variable absent), uncategorized projects are put in the
+	`$project_list_default_category` category.  You can use the
+	`gitweb.category` repo configuration variable, but the file takes
+	precedence.
++
+The configuration variables `$projects_list_group_categories` and
+`$project_list_default_category` are described in linkgit:gitweb.conf[5]
+
+cloneurl (or multiple-valued `gitweb.url`)::
+	File with repository URL (used for clone and fetch), one per line.
+	Displayed in the project summary page. You can use multiple-valued
+	`gitweb.url` repository configuration variable for that, but the file
+	takes precedence.
++
+This is per-repository enhancement / version of global prefix-based
+`@git_base_url_list` gitweb configuration variable (see
+linkgit:gitweb.conf[5]).
+
+gitweb.owner::
+	You can use the `gitweb.owner` repository configuration variable to set
+	repository's owner.  It is displayed in the project list and summary
+	page.
++
+If it's not set, filesystem directory's owner is used (via GECOS field,
+i.e. real name field from *getpwuid*(3)) if `$projects_list` is unset
+(gitweb scans `$projectroot` for repositories); if `$projects_list`
+points to file with list of repositories, then project owner defaults to
+value from this file for given repository.
+
+various `gitweb.*` config variables (in config)::
+	Read description of `%feature` hash for detailed list, and descriptions.
+	See also "Configuring gitweb features" section in linkgit:gitweb.conf[5]
+
+
+ACTIONS, AND URLS
+-----------------
+Gitweb can use path_info (component) based URLs, or it can pass all necessary
+information via query parameters.  The typical gitweb URLs are broken down in to
+five components:
+
+-----------------------------------------------------------------------
+.../gitweb.cgi/<repo>/<action>/<revision>:/<path>?<arguments>
+-----------------------------------------------------------------------
+
+repo::
+	The repository the action will be performed on.
++
+All actions except for those that list all available projects,
+in whatever form, require this parameter.
+
+action::
+	The action that will be run.  Defaults to 'projects_list' if repo
+	is not set, and to 'summary' otherwise.
+
+revision::
+	Revision shown.  Defaults to HEAD.
+
+path::
+	The path within the <repository> that the action is performed on,
+	for those actions that require it.
+
+arguments::
+	Any arguments that control the behaviour of the action.
+
+Some actions require or allow to specify two revisions, and sometimes even two
+pathnames.  In most general form such path_info (component) based gitweb URL
+looks like this:
+
+-----------------------------------------------------------------------
+.../gitweb.cgi/<repo>/<action>/<revision-from>:/<path-from>..<revision-to>:/<path-to>?<arguments>
+-----------------------------------------------------------------------
+
+
+Each action is implemented as a subroutine, and must be present in %actions
+hash.  Some actions are disabled by default, and must be turned on via feature
+mechanism.  For example to enable 'blame' view add the following to gitweb
+configuration file:
+
+-----------------------------------------------------------------------
+$feature{'blame'}{'default'} = [1];
+-----------------------------------------------------------------------
+
+
+Actions:
+~~~~~~~~
+The standard actions are:
+
+project_list::
+	Lists the available Git repositories.  This is the default command if no
+	repository is specified in the URL.
+
+summary::
+	Displays summary about given repository.  This is the default command if
+	no action is specified in URL, and only repository is specified.
+
+heads::
+remotes::
+	Lists all local or all remote-tracking branches in given repository.
++
+The latter is not available by default, unless configured.
+
+tags::
+	List all tags (lightweight and annotated) in given repository.
+
+blob::
+tree::
+	Shows the files and directories in a given repository path, at given
+	revision.  This is default command if no action is specified in the URL,
+	and path is given.
+
+blob_plain::
+	Returns the raw data for the file in given repository, at given path and
+	revision.  Links to this action are marked 'raw'.
+
+blobdiff::
+	Shows the difference between two revisions of the same file.
+
+blame::
+blame_incremental::
+	Shows the blame (also called annotation) information for a file. On a
+	per line basis it shows the revision in which that line was last changed
+	and the user that committed the change.  The incremental version (which
+	if configured is used automatically when JavaScript is enabled) uses
+	Ajax to incrementally add blame info to the contents of given file.
++
+This action is disabled by default for performance reasons.
+
+commit::
+commitdiff::
+	Shows information about a specific commit in a repository.  The 'commit'
+	view shows information about commit in more detail, the 'commitdiff'
+	action shows changeset for given commit.
+
+patch::
+	Returns the commit in plain text mail format, suitable for applying with
+	linkgit:git-am[1].
+
+tag::
+	Display specific annotated tag (tag object).
+
+log::
+shortlog::
+	Shows log information (commit message or just commit subject) for a
+	given branch (starting from given revision).
++
+The 'shortlog' view is more compact; it shows one commit per line.
+
+history::
+	Shows history of the file or directory in a given repository path,
+	starting from given revision (defaults to HEAD, i.e. default branch).
++
+This view is similar to 'shortlog' view.
+
+rss::
+atom::
+	Generates an RSS (or Atom) feed of changes to repository.
+
+
+WEBSERVER CONFIGURATION
+-----------------------
+This section explains how to configure some common webservers to run gitweb. In
+all cases, `/path/to/gitweb` in the examples is the directory you ran installed
+gitweb in, and contains `gitweb_config.perl`.
+
+If you've configured a web server that isn't listed here for gitweb, please send
+in the instructions so they can be included in a future release.
+
+Apache as CGI
+~~~~~~~~~~~~~
+Apache must be configured to support CGI scripts in the directory in
+which gitweb is installed.  Let's assume that it is `/var/www/cgi-bin`
+directory.
+
+-----------------------------------------------------------------------
+ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
+
+<Directory "/var/www/cgi-bin">
+    Options Indexes FollowSymlinks ExecCGI
+    AllowOverride None
+    Order allow,deny
+    Allow from all
+</Directory>
+-----------------------------------------------------------------------
+
+With that configuration the full path to browse repositories would be:
+
+  http://server/cgi-bin/gitweb.cgi
+
+Apache with mod_perl, via ModPerl::Registry
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+You can use mod_perl with gitweb.  You must install Apache::Registry
+(for mod_perl 1.x) or ModPerl::Registry (for mod_perl 2.x) to enable
+this support.
+
+Assuming that gitweb is installed to `/var/www/perl`, the following
+Apache configuration (for mod_perl 2.x) is suitable.
+
+-----------------------------------------------------------------------
+Alias /perl "/var/www/perl"
+
+<Directory "/var/www/perl">
+    SetHandler perl-script
+    PerlResponseHandler ModPerl::Registry
+    PerlOptions +ParseHeaders
+    Options Indexes FollowSymlinks +ExecCGI
+    AllowOverride None
+    Order allow,deny
+    Allow from all
+</Directory>
+-----------------------------------------------------------------------
+
+With that configuration the full path to browse repositories would be:
+
+  http://server/perl/gitweb.cgi
+
+Apache with FastCGI
+~~~~~~~~~~~~~~~~~~~
+Gitweb works with Apache and FastCGI.  First you need to rename, copy
+or symlink gitweb.cgi to gitweb.fcgi.  Let's assume that gitweb is
+installed in `/usr/share/gitweb` directory.  The following Apache
+configuration is suitable (UNTESTED!)
+
+-----------------------------------------------------------------------
+FastCgiServer /usr/share/gitweb/gitweb.cgi
+ScriptAlias /gitweb /usr/share/gitweb/gitweb.cgi
+
+Alias /gitweb/static /usr/share/gitweb/static
+<Directory /usr/share/gitweb/static>
+    SetHandler default-handler
+</Directory>
+-----------------------------------------------------------------------
+
+With that configuration the full path to browse repositories would be:
+
+  http://server/gitweb
+
+
+ADVANCED WEB SERVER SETUP
+-------------------------
+All of those examples use request rewriting, and need `mod_rewrite`
+(or equivalent; examples below are written for Apache).
+
+Single URL for gitweb and for fetching
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you want to have one URL for both gitweb and your `http://`
+repositories, you can configure Apache like this:
+
+-----------------------------------------------------------------------
+<VirtualHost *:80>
+    ServerName    git.example.org
+    DocumentRoot  /pub/git
+    SetEnv        GITWEB_CONFIG   /etc/gitweb.conf
+
+    # turning on mod rewrite
+    RewriteEngine on
+
+    # make the front page an internal rewrite to the gitweb script
+    RewriteRule ^/$  /cgi-bin/gitweb.cgi
+
+    # make access for "dumb clients" work
+    RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ \
+		/cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
+</VirtualHost>
+-----------------------------------------------------------------------
+
+The above configuration expects your public repositories to live under
+`/pub/git` and will serve them as `http://git.domain.org/dir-under-pub-git`,
+both as clonable Git URL and as browsable gitweb interface.  If you then
+start your linkgit:git-daemon[1] with `--base-path=/pub/git --export-all`
+then you can even use the `git://` URL with exactly the same path.
+
+Setting the environment variable `GITWEB_CONFIG` will tell gitweb to use the
+named file (i.e. in this example `/etc/gitweb.conf`) as a configuration for
+gitweb.  You don't really need it in above example; it is required only if
+your configuration file is in different place than built-in (during
+compiling gitweb) 'gitweb_config.perl' or `/etc/gitweb.conf`.  See
+linkgit:gitweb.conf[5] for details, especially information about precedence
+rules.
+
+If you use the rewrite rules from the example you *might* also need
+something like the following in your gitweb configuration file
+(`/etc/gitweb.conf` following example):
+----------------------------------------------------------------------------
+@stylesheets = ("/some/absolute/path/gitweb.css");
+$my_uri    = "/";
+$home_link = "/";
+$per_request_config = 1;
+----------------------------------------------------------------------------
+Nowadays though gitweb should create HTML base tag when needed (to set base
+URI for relative links), so it should work automatically.
+
+
+Webserver configuration with multiple projects' root
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If you want to use gitweb with several project roots you can edit your
+Apache virtual host and gitweb configuration files in the following way.
+
+The virtual host configuration (in Apache configuration file) should look
+like this:
+--------------------------------------------------------------------------
+<VirtualHost *:80>
+    ServerName    git.example.org
+    DocumentRoot  /pub/git
+    SetEnv        GITWEB_CONFIG  /etc/gitweb.conf
+
+    # turning on mod rewrite
+    RewriteEngine on
+
+    # make the front page an internal rewrite to the gitweb script
+    RewriteRule ^/$  /cgi-bin/gitweb.cgi  [QSA,L,PT]
+
+    # look for a public_git directory in unix users' home
+    # http://git.example.org/~<user>/
+    RewriteRule ^/\~([^\/]+)(/|/gitweb.cgi)?$	/cgi-bin/gitweb.cgi \
+		[QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+    # http://git.example.org/+<user>/
+    #RewriteRule ^/\+([^\/]+)(/|/gitweb.cgi)?$	/cgi-bin/gitweb.cgi \
+		 [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+    # http://git.example.org/user/<user>/
+    #RewriteRule ^/user/([^\/]+)/(gitweb.cgi)?$	/cgi-bin/gitweb.cgi \
+		 [QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
+
+    # defined list of project roots
+    RewriteRule ^/scm(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
+		[QSA,E=GITWEB_PROJECTROOT:/pub/scm/,L,PT]
+    RewriteRule ^/var(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
+		[QSA,E=GITWEB_PROJECTROOT:/var/git/,L,PT]
+
+    # make access for "dumb clients" work
+    RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ \
+		/cgi-bin/gitweb.cgi%{REQUEST_URI}  [L,PT]
+</VirtualHost>
+--------------------------------------------------------------------------
+
+Here actual project root is passed to gitweb via `GITWEB_PROJECT_ROOT`
+environment variable from a web server, so you need to put the following
+line in gitweb configuration file (`/etc/gitweb.conf` in above example):
+--------------------------------------------------------------------------
+$projectroot = $ENV{'GITWEB_PROJECTROOT'} || "/pub/git";
+--------------------------------------------------------------------------
+*Note* that this requires to be set for each request, so either
+`$per_request_config` must be false, or the above must be put in code
+referenced by `$per_request_config`;
+
+These configurations enable two things. First, each unix user (`<user>`) of
+the server will be able to browse through gitweb Git repositories found in
+`~/public_git/` with the following url:
+
+  http://git.example.org/~<user>/
+
+If you do not want this feature on your server just remove the second
+rewrite rule.
+
+If you already use `mod_userdir` in your virtual host or you don't want to
+use the \'~' as first character, just comment or remove the second rewrite
+rule, and uncomment one of the following according to what you want.
+
+Second, repositories found in `/pub/scm/` and `/var/git/` will be accessible
+through `http://git.example.org/scm/` and `http://git.example.org/var/`.
+You can add as many project roots as you want by adding rewrite rules like
+the third and the fourth.
+
+
+PATH_INFO usage
+~~~~~~~~~~~~~~~
+If you enable PATH_INFO usage in gitweb by putting
+----------------------------------------------------------------------------
+$feature{'pathinfo'}{'default'} = [1];
+----------------------------------------------------------------------------
+in your gitweb configuration file, it is possible to set up your server so
+that it consumes and produces URLs in the form
+
+  http://git.example.com/project.git/shortlog/sometag
+
+i.e. without 'gitweb.cgi' part, by using a configuration such as the
+following.  This configuration assumes that `/var/www/gitweb` is the
+DocumentRoot of your webserver, contains the gitweb.cgi script and
+complementary static files (stylesheet, favicon, JavaScript):
+
+----------------------------------------------------------------------------
+<VirtualHost *:80>
+	ServerAlias git.example.com
+
+	DocumentRoot /var/www/gitweb
+
+	<Directory /var/www/gitweb>
+		Options ExecCGI
+		AddHandler cgi-script cgi
+
+		DirectoryIndex gitweb.cgi
+
+		RewriteEngine On
+		RewriteCond %{REQUEST_FILENAME} !-f
+		RewriteCond %{REQUEST_FILENAME} !-d
+		RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
+	</Directory>
+</VirtualHost>
+----------------------------------------------------------------------------
+The rewrite rule guarantees that existing static files will be properly
+served, whereas any other URL will be passed to gitweb as PATH_INFO
+parameter.
+
+*Notice* that in this case you don't need special settings for
+`@stylesheets`, `$my_uri` and `$home_link`, but you lose "dumb client"
+access to your project .git dirs (described in "Single URL for gitweb and
+for fetching" section).  A possible workaround for the latter is the
+following: in your project root dir (e.g. `/pub/git`) have the projects
+named *without* a .git extension (e.g. `/pub/git/project` instead of
+`/pub/git/project.git`) and configure Apache as follows:
+----------------------------------------------------------------------------
+<VirtualHost *:80>
+	ServerAlias git.example.com
+
+	DocumentRoot /var/www/gitweb
+
+	AliasMatch ^(/.*?)(\.git)(/.*)?$ /pub/git$1$3
+	<Directory /var/www/gitweb>
+		Options ExecCGI
+		AddHandler cgi-script cgi
+
+		DirectoryIndex gitweb.cgi
+
+		RewriteEngine On
+		RewriteCond %{REQUEST_FILENAME} !-f
+		RewriteCond %{REQUEST_FILENAME} !-d
+		RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
+	</Directory>
+</VirtualHost>
+----------------------------------------------------------------------------
+
+The additional AliasMatch makes it so that
+
+  http://git.example.com/project.git
+
+will give raw access to the project's Git dir (so that the project can be
+cloned), while
+
+  http://git.example.com/project
+
+will provide human-friendly gitweb access.
+
+This solution is not 100% bulletproof, in the sense that if some project has
+a named ref (branch, tag) starting with `git/`, then paths such as
+
+  http://git.example.com/project/command/abranch..git/abranch
+
+will fail with a 404 error.
+
+
+BUGS
+----
+Please report any bugs or feature requests to git@xxxxxxxxxxxxxxx,
+putting "gitweb" in the subject of email.
+
+SEE ALSO
+--------
+linkgit:gitweb.conf[5], linkgit:git-instaweb[1]
+
+`gitweb/README`, `gitweb/INSTALL`
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitweb.conf.adoc b/Documentation/gitweb.conf.adoc
new file mode 100644
index 0000000000..85983587fc
--- /dev/null
+++ b/Documentation/gitweb.conf.adoc
@@ -0,0 +1,981 @@
+gitweb.conf(5)
+==============
+
+NAME
+----
+gitweb.conf - Gitweb (Git web interface) configuration file
+
+SYNOPSIS
+--------
+/etc/gitweb.conf, /etc/gitweb-common.conf, $GITWEBDIR/gitweb_config.perl
+
+DESCRIPTION
+-----------
+
+The gitweb CGI script for viewing Git repositories over the web uses a
+perl script fragment as its configuration file.  You can set variables
+using "`our $variable = value`"; text from a "#" character until the
+end of a line is ignored.  See *perlsyn*(1) for details.
+
+An example:
+
+------------------------------------------------
+# gitweb configuration file for http://git.example.org
+#
+our $projectroot = "/srv/git"; # FHS recommendation
+our $site_name = 'Example.org >> Repos';
+------------------------------------------------
+
+
+The configuration file is used to override the default settings that
+were built into gitweb at the time the 'gitweb.cgi' script was generated.
+
+While one could just alter the configuration settings in the gitweb
+CGI itself, those changes would be lost upon upgrade.  Configuration
+settings might also be placed into a file in the same directory as the
+CGI script with the default name 'gitweb_config.perl' -- allowing
+one to have multiple gitweb instances with different configurations by
+the use of symlinks.
+
+Note that some configuration can be controlled on per-repository rather than
+gitweb-wide basis: see "Per-repository gitweb configuration" subsection on
+linkgit:gitweb[1] manpage.
+
+
+DISCUSSION
+----------
+Gitweb reads configuration data from the following sources in the
+following order:
+
+ * built-in values (some set during build stage),
+
+ * common system-wide configuration file (defaults to
+   `/etc/gitweb-common.conf`),
+
+ * either per-instance configuration file (defaults to 'gitweb_config.perl'
+   in the same directory as the installed gitweb), or if it does not exist
+   then fallback system-wide configuration file (defaults to `/etc/gitweb.conf`).
+
+Values obtained in later configuration files override values obtained earlier
+in the above sequence.
+
+Locations of the common system-wide configuration file, the fallback
+system-wide configuration file and the per-instance configuration file
+are defined at compile time using build-time Makefile configuration
+variables, respectively `GITWEB_CONFIG_COMMON`, `GITWEB_CONFIG_SYSTEM`
+and `GITWEB_CONFIG`.
+
+You can also override locations of gitweb configuration files during
+runtime by setting the following environment variables:
+`GITWEB_CONFIG_COMMON`, `GITWEB_CONFIG_SYSTEM` and `GITWEB_CONFIG`
+to a non-empty value.
+
+
+The syntax of the configuration files is that of Perl, since these files are
+handled by sourcing them as fragments of Perl code (the language that
+gitweb itself is written in). Variables are typically set using the
+`our` qualifier (as in "`our $variable = <value>;`") to avoid syntax
+errors if a new version of gitweb no longer uses a variable and therefore
+stops declaring it.
+
+You can include other configuration file using read_config_file()
+subroutine.  For example, one might want to put gitweb configuration
+related to access control for viewing repositories via Gitolite (one
+of Git repository management tools) in a separate file, e.g. in
+`/etc/gitweb-gitolite.conf`.  To include it, put
+
+--------------------------------------------------
+read_config_file("/etc/gitweb-gitolite.conf");
+--------------------------------------------------
+
+somewhere in gitweb configuration file used, e.g. in per-installation
+gitweb configuration file.  Note that read_config_file() checks itself
+that the file it reads exists, and does nothing if it is not found.
+It also handles errors in included file.
+
+
+The default configuration with no configuration file at all may work
+perfectly well for some installations.  Still, a configuration file is
+useful for customizing or tweaking the behavior of gitweb in many ways, and
+some optional features will not be present unless explicitly enabled using
+the configurable `%features` variable (see also "Configuring gitweb
+features" section below).
+
+
+CONFIGURATION VARIABLES
+-----------------------
+Some configuration variables have their default values (embedded in the CGI
+script) set during building gitweb -- if that is the case, this fact is put
+in their description.  See gitweb's 'INSTALL' file for instructions on building
+and installing gitweb.
+
+
+Location of repositories
+~~~~~~~~~~~~~~~~~~~~~~~~
+The configuration variables described below control how gitweb finds
+Git repositories, and how repositories are displayed and accessed.
+
+See also "Repositories" and later subsections in linkgit:gitweb[1] manpage.
+
+$projectroot::
+	Absolute filesystem path which will be prepended to project path;
+	the path to repository is `$projectroot/$project`.  Set to
+	`$GITWEB_PROJECTROOT` during installation.  This variable has to be
+	set correctly for gitweb to find repositories.
++
+For example, if `$projectroot` is set to "/srv/git" by putting the following
+in gitweb config file:
++
+----------------------------------------------------------------------------
+our $projectroot = "/srv/git";
+----------------------------------------------------------------------------
++
+then
++
+------------------------------------------------
+http://git.example.com/gitweb.cgi?p=foo/bar.git
+------------------------------------------------
++
+and its path_info based equivalent
++
+------------------------------------------------
+http://git.example.com/gitweb.cgi/foo/bar.git
+------------------------------------------------
++
+will map to the path `/srv/git/foo/bar.git` on the filesystem.
+
+$projects_list::
+	Name of a plain text file listing projects, or a name of directory
+	to be scanned for projects.
++
+Project list files should list one project per line, with each line
+having the following format
++
+-----------------------------------------------------------------------------
+<URI-encoded filesystem path to repository> SP <URI-encoded repository owner>
+-----------------------------------------------------------------------------
++
+The default value of this variable is determined by the `GITWEB_LIST`
+makefile variable at installation time.  If this variable is empty, gitweb
+will fall back to scanning the `$projectroot` directory for repositories.
+
+$project_maxdepth::
+	If `$projects_list` variable is unset, gitweb will recursively
+	scan filesystem for Git repositories.  The `$project_maxdepth`
+	is used to limit traversing depth, relative to `$projectroot`
+	(starting point); it means that directories which are further
+	from `$projectroot` than `$project_maxdepth` will be skipped.
++
+It is purely performance optimization, originally intended for MacOS X,
+where recursive directory traversal is slow.  Gitweb follows symbolic
+links, but it detects cycles, ignoring any duplicate files and directories.
++
+The default value of this variable is determined by the build-time
+configuration variable `GITWEB_PROJECT_MAXDEPTH`, which defaults to
+2007.
+
+$export_ok::
+	Show repository only if this file exists (in repository).  Only
+	effective if this variable evaluates to true.  Can be set when
+	building gitweb by setting `GITWEB_EXPORT_OK`.  This path is
+	relative to `GIT_DIR`.  git-daemon[1] uses 'git-daemon-export-ok',
+	unless started with `--export-all`.  By default this variable is
+	not set, which means that this feature is turned off.
+
+$export_auth_hook::
+	Function used to determine which repositories should be shown.
+	This subroutine should take one parameter, the full path to
+	a project, and if it returns true, that project will be included
+	in the projects list and can be accessed through gitweb as long
+	as it fulfills the other requirements described by $export_ok,
+	$projects_list, and $projects_maxdepth.  Example:
++
+----------------------------------------------------------------------------
+our $export_auth_hook = sub { return -e "$_[0]/git-daemon-export-ok"; };
+----------------------------------------------------------------------------
++
+though the above might be done by using `$export_ok` instead
++
+----------------------------------------------------------------------------
+our $export_ok = "git-daemon-export-ok";
+----------------------------------------------------------------------------
++
+If not set (default), it means that this feature is disabled.
++
+See also more involved example in "Controlling access to Git repositories"
+subsection on linkgit:gitweb[1] manpage.
+
+$strict_export::
+	Only allow viewing of repositories also shown on the overview page.
+	This for example makes `$export_ok` file decide if repository is
+	available and not only if it is shown.  If `$projects_list` points to
+	file with list of project, only those repositories listed would be
+	available for gitweb.  Can be set during building gitweb via
+	`GITWEB_STRICT_EXPORT`.  By default this variable is not set, which
+	means that you can directly access those repositories that are hidden
+	from projects list page (e.g. the are not listed in the $projects_list
+	file).
+
+
+Finding files
+~~~~~~~~~~~~~
+The following configuration variables tell gitweb where to find files.
+The values of these variables are paths on the filesystem.
+
+$GIT::
+	Core git executable to use.  By default set to `$GIT_BINDIR/git`, which
+	in turn is by default set to `$(bindir)/git`.  If you use Git installed
+	from a binary package, you should usually set this to "/usr/bin/git".
+	This can just be "git" if your web server has a sensible PATH; from
+	security point of view it is better to use absolute path to git binary.
+	If you have multiple Git versions installed it can be used to choose
+	which one to use.  Must be (correctly) set for gitweb to be able to
+	work.
+
+$mimetypes_file::
+	File to use for (filename extension based) guessing of MIME types before
+	trying `/etc/mime.types`.  *NOTE* that this path, if relative, is taken
+	as relative to the current Git repository, not to CGI script.  If unset,
+	only `/etc/mime.types` is used (if present on filesystem).  If no mimetypes
+	file is found, mimetype guessing based on extension of file is disabled.
+	Unset by default.
+
+$highlight_bin::
+	Path to the highlight executable to use (it must be the one from
+	http://andre-simon.de/zip/download.php[] due to assumptions about parameters and output).
+	By default set to 'highlight'; set it to full path to highlight
+	executable if it is not installed on your web server's PATH.
+	Note that 'highlight' feature must be set for gitweb to actually
+	use syntax highlighting.
++
+*NOTE*: for a file to be highlighted, its syntax type must be detected
+and that syntax must be supported by "highlight".  The default syntax
+detection is minimal, and there are many supported syntax types with no
+detection by default.  There are three options for adding syntax
+detection.  The first and second priority are `%highlight_basename` and
+`%highlight_ext`, which detect based on basename (the full filename, for
+example "Makefile") and extension (for example "sh").  The keys of these
+hashes are the basename and extension, respectively, and the value for a
+given key is the name of the syntax to be passed via `--syntax <syntax>`
+to "highlight".  The last priority is the "highlight" configuration of
+`Shebang` regular expressions to detect the language based on the first
+line in the file, (for example, matching the line "#!/bin/bash").  See
+the highlight documentation and the default config at
+/etc/highlight/filetypes.conf for more details.
++
+For example if repositories you are hosting use "phtml" extension for
+PHP files, and you want to have correct syntax-highlighting for those
+files, you can add the following to gitweb configuration:
++
+---------------------------------------------------------
+our %highlight_ext;
+$highlight_ext{'phtml'} = 'php';
+---------------------------------------------------------
+
+
+Links and their targets
+~~~~~~~~~~~~~~~~~~~~~~~
+The configuration variables described below configure some of gitweb links:
+their target and their look (text or image), and where to find page
+prerequisites (stylesheet, favicon, images, scripts).  Usually they are left
+at their default values, with the possible exception of `@stylesheets`
+variable.
+
+@stylesheets::
+	List of URIs of stylesheets (relative to the base URI of a page). You
+	might specify more than one stylesheet, for example to use "gitweb.css"
+	as base with site specific modifications in a separate stylesheet
+	to make it easier to upgrade gitweb.  For example, you can add
+	a `site` stylesheet by putting
++
+----------------------------------------------------------------------------
+push @stylesheets, "gitweb-site.css";
+----------------------------------------------------------------------------
++
+in the gitweb config file.  Those values that are relative paths are
+relative to base URI of gitweb.
++
+This list should contain the URI of gitweb's standard stylesheet.  The default
+URI of gitweb stylesheet can be set at build time using the `GITWEB_CSS`
+makefile variable.  Its default value is `static/gitweb.css`
+(or `static/gitweb.min.css` if the `CSSMIN` variable is defined,
+i.e. if CSS minifier is used during build).
++
+*Note*: there is also a legacy `$stylesheet` configuration variable, which was
+used by older gitweb.  If `$stylesheet` variable is defined, only CSS stylesheet
+given by this variable is used by gitweb.
+
+$logo::
+	Points to the location where you put 'git-logo.png' on your web
+	server, or to be more the generic URI of logo, 72x27 size).  This image
+	is displayed in the top right corner of each gitweb page and used as
+	a logo for the Atom feed.  Relative to the base URI of gitweb (as a path).
+	Can be adjusted when building gitweb using `GITWEB_LOGO` variable
+	By default set to `static/git-logo.png`.
+
+$favicon::
+	Points to the location where you put 'git-favicon.png' on your web
+	server, or to be more the generic URI of favicon, which will be served
+	as "image/png" type.  Web browsers that support favicons (website icons)
+	may display them in the browser's URL bar and next to the site name in
+	bookmarks.  Relative to the base URI of gitweb.  Can be adjusted at
+	build time using `GITWEB_FAVICON` variable.
+	By default set to `static/git-favicon.png`.
+
+$javascript::
+	Points to the location where you put 'gitweb.js' on your web server,
+	or to be more generic the URI of JavaScript code used by gitweb.
+	Relative to the base URI of gitweb.  Can be set at build time using
+	the `GITWEB_JS` build-time configuration variable.
++
+The default value is either `static/gitweb.js`, or `static/gitweb.min.js` if
+the `JSMIN` build variable was defined, i.e. if JavaScript minifier was used
+at build time.  *Note* that this single file is generated from multiple
+individual JavaScript "modules".
+
+$home_link::
+	Target of the home link on the top of all pages (the first part of view
+	"breadcrumbs").  By default it is set to the absolute URI of a current page
+	(to the value of `$my_uri` variable, or to "/" if `$my_uri` is undefined
+	or is an empty string).
+
+$home_link_str::
+	Label for the "home link" at the top of all pages, leading to `$home_link`
+	(usually the main gitweb page, which contains the projects list).  It is
+	used as the first component of gitweb's "breadcrumb trail":
+	`<home-link> / <project> / <action>`.  Can be set at build time using
+	the `GITWEB_HOME_LINK_STR` variable.  By default it is set to "projects",
+	as this link leads to the list of projects.  Another popular choice is to
+	set it to the name of site.  Note that it is treated as raw HTML so it
+	should not be set from untrusted sources.
+
+@extra_breadcrumbs::
+	Additional links to be added to the start of the breadcrumb trail before
+	the home link, to pages that are logically "above" the gitweb projects
+	list, such as the organization and department which host the gitweb
+	server. Each element of the list is a reference to an array, in which
+	element 0 is the link text (equivalent to `$home_link_str`) and element
+	1 is the target URL (equivalent to `$home_link`).
++
+For example, the following setting produces a breadcrumb trail like
+"home / dev / projects / ..." where "projects" is the home link.
++
+----------------------------------------------------------------------------
+    our @extra_breadcrumbs = (
+      [ 'home' => 'https://www.example.org/' ],
+      [ 'dev'  => 'https://dev.example.org/' ],
+    );
+----------------------------------------------------------------------------
+
+$logo_url::
+$logo_label::
+	URI and label (title) for the Git logo link (or your site logo,
+	if you chose to use different logo image). By default, these both
+	refer to Git homepage, https://git-scm.com[]; in the past, they pointed
+	to Git documentation at https://www.kernel.org[].
+
+
+Changing gitweb's look
+~~~~~~~~~~~~~~~~~~~~~~
+You can adjust how pages generated by gitweb look using the variables described
+below.  You can change the site name, add common headers and footers for all
+pages, and add a description of this gitweb installation on its main page
+(which is the projects list page), etc.
+
+$site_name::
+	Name of your site or organization, to appear in page titles.  Set it
+	to something descriptive for clearer bookmarks etc.  If this variable
+	is not set or is, then gitweb uses the value of the `SERVER_NAME`
+	`CGI` environment variable, setting site name to "$SERVER_NAME Git",
+	or "Untitled Git" if this variable is not set (e.g. if running gitweb
+	as standalone script).
++
+Can be set using the `GITWEB_SITENAME` at build time.  Unset by default.
+
+$site_html_head_string::
+	HTML snippet to be included in the <head> section of each page.
+	Can be set using `GITWEB_SITE_HTML_HEAD_STRING` at build time.
+	No default value.
+
+$site_header::
+	Name of a file with HTML to be included at the top of each page.
+	Relative to the directory containing the 'gitweb.cgi' script.
+	Can be set using `GITWEB_SITE_HEADER` at build time.  No default
+	value.
+
+$site_footer::
+	Name of a file with HTML to be included at the bottom of each page.
+	Relative to the directory containing the 'gitweb.cgi' script.
+	Can be set using `GITWEB_SITE_FOOTER` at build time.  No default
+	value.
+
+$home_text::
+	Name of a HTML file which, if it exists, is included on the
+	gitweb projects overview page ("projects_list" view).  Relative to
+	the directory containing the gitweb.cgi script.  Default value
+	can be adjusted during build time using `GITWEB_HOMETEXT` variable.
+	By default set to 'indextext.html'.
+
+$projects_list_description_width::
+	The width (in characters) of the "Description" column of the projects list.
+	Longer descriptions will be truncated (trying to cut at word boundary);
+	the full description is available in the 'title' attribute (usually shown on
+	mouseover).  The default is 25, which might be too small if you
+	use long project descriptions.
+
+$default_projects_order::
+	Default value of ordering of projects on projects list page, which
+	means the ordering used if you don't explicitly sort projects list
+	(if there is no "o" CGI query parameter in the URL).  Valid values
+	are "none" (unsorted), "project" (projects are by project name,
+	i.e. path to repository relative to `$projectroot`), "descr"
+	(project description), "owner", and "age" (by date of most current
+	commit).
++
+Default value is "project".  Unknown value means unsorted.
+
+
+Changing gitweb's behavior
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+These configuration variables control _internal_ gitweb behavior.
+
+$default_blob_plain_mimetype::
+	Default mimetype for the blob_plain (raw) view, if mimetype checking
+	doesn't result in some other type; by default "text/plain".
+	Gitweb guesses mimetype of a file to display based on extension
+	of its filename, using `$mimetypes_file` (if set and file exists)
+	and `/etc/mime.types` files (see *mime.types*(5) manpage; only
+	filename extension rules are supported by gitweb).
+
+$default_text_plain_charset::
+	Default charset for text files. If this is not set, the web server
+	configuration will be used.  Unset by default.
+
+$fallback_encoding::
+	Gitweb assumes this charset when a line contains non-UTF-8 characters.
+	The fallback decoding is used without error checking, so it can be even
+	"utf-8". The value must be a valid encoding; see the *Encoding::Supported*(3pm)
+	man page for a list. The default is "latin1", aka. "iso-8859-1".
+
+@diff_opts::
+	Rename detection options for git-diff and git-diff-tree. The default is
+	(\'-M'); set it to (\'-C') or (\'-C', \'-C') to also detect copies,
+	or set it to () i.e. empty list if you don't want to have renames
+	detection.
++
+*Note* that rename and especially copy detection can be quite
+CPU-intensive.  Note also that non Git tools can have problems with
+patches generated with options mentioned above, especially when they
+involve file copies (\'-C') or criss-cross renames (\'-B').
+
+
+Some optional features and policies
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Most of features are configured via `%feature` hash; however some of extra
+gitweb features can be turned on and configured using variables described
+below.  This list beside configuration variables that control how gitweb
+looks does contain variables configuring administrative side of gitweb
+(e.g. cross-site scripting prevention; admittedly this as side effect
+affects how "summary" pages look like, or load limiting).
+
+@git_base_url_list::
+	List of Git base URLs.  These URLs are used to generate URLs
+	describing from where to fetch a project, which are shown on
+	project summary page.  The full fetch URL is "`$git_base_url/$project`",
+	for each element of this list. You can set up multiple base URLs
+	(for example one for `git://` protocol, and one for `http://`
+	protocol).
++
+Note that per repository configuration can be set in `$GIT_DIR/cloneurl`
+file, or as values of multi-value `gitweb.url` configuration variable in
+project config.  Per-repository configuration takes precedence over value
+composed from `@git_base_url_list` elements and project name.
++
+You can setup one single value (single entry/item in this list) at build
+time by setting the `GITWEB_BASE_URL` build-time configuration variable.
+By default it is set to (), i.e. an empty list.  This means that gitweb
+would not try to create project URL (to fetch) from project name.
+
+$projects_list_group_categories::
+	Whether to enable the grouping of projects by category on the project
+	list page. The category of a project is determined by the
+	`$GIT_DIR/category` file or the `gitweb.category` variable in each
+	repository's configuration.  Disabled by default (set to 0).
+
+$project_list_default_category::
+	Default category for projects for which none is specified.  If this is
+	set to the empty string, such projects will remain uncategorized and
+	listed at the top, above categorized projects.  Used only if project
+	categories are enabled, which means if `$projects_list_group_categories`
+	is true.  By default set to "" (empty string).
+
+$prevent_xss::
+	If true, some gitweb features are disabled to prevent content in
+	repositories from launching cross-site scripting (XSS) attacks.  Set this
+	to true if you don't trust the content of your repositories.
+	False by default (set to 0).
+
+$maxload::
+	Used to set the maximum load that we will still respond to gitweb queries.
+	If the server load exceeds this value then gitweb will return
+	"503 Service Unavailable" error.  The server load is taken to be 0
+	if gitweb cannot determine its value.  Currently it works only on Linux,
+	where it uses `/proc/loadavg`; the load there is the number of active
+	tasks on the system -- processes that are actually running -- averaged
+	over the last minute.
++
+Set `$maxload` to undefined value (`undef`) to turn this feature off.
+The default value is 300.
+
+$omit_age_column::
+	If true, omit the column with date of the most current commit on the
+	projects list page. It can save a bit of I/O and a fork per repository.
+
+$omit_owner::
+	If true prevents displaying information about repository owner.
+
+$per_request_config::
+	If this is set to code reference, it will be run once for each request.
+	You can set parts of configuration that change per session this way.
+	For example, one might use the following code in a gitweb configuration
+	file
++
+--------------------------------------------------------------------------------
+our $per_request_config = sub {
+	$ENV{GL_USER} = $cgi->remote_user || "gitweb";
+};
+--------------------------------------------------------------------------------
++
+If `$per_request_config` is not a code reference, it is interpreted as boolean
+value.  If it is true gitweb will process config files once per request,
+and if it is false gitweb will process config files only once, each time it
+is executed.  True by default (set to 1).
++
+*NOTE*: `$my_url`, `$my_uri`, and `$base_url` are overwritten with their default
+values before every request, so if you want to change them, be sure to set
+this variable to true or a code reference effecting the desired changes.
++
+This variable matters only when using persistent web environments that
+serve multiple requests using single gitweb instance, like mod_perl,
+FastCGI or Plackup.
+
+
+Other variables
+~~~~~~~~~~~~~~~
+Usually you should not need to change (adjust) any of configuration
+variables described below; they should be automatically set by gitweb to
+correct value.
+
+
+$version::
+	Gitweb version, set automatically when creating gitweb.cgi from
+	gitweb.perl. You might want to modify it if you are running modified
+	gitweb, for example
++
+---------------------------------------------------
+our $version .= " with caching";
+---------------------------------------------------
++
+if you run modified version of gitweb with caching support.  This variable
+is purely informational, used e.g. in the "generator" meta header in HTML
+header.
+
+$my_url::
+$my_uri::
+	Full URL and absolute URL of the gitweb script;
+	in earlier versions of gitweb you might have need to set those
+	variables, but now there should be no need to do it.  See
+	`$per_request_config` if you need to set them still.
+
+$base_url::
+	Base URL for relative URLs in pages generated by gitweb,
+	(e.g. `$logo`, `$favicon`, `@stylesheets` if they are relative URLs),
+	needed and used '<base href="$base_url">' only for URLs with nonempty
+	PATH_INFO.  Usually gitweb sets its value correctly,
+	and there is no need to set this variable, e.g. to $my_uri or "/".
+	See `$per_request_config` if you need to override it anyway.
+
+
+CONFIGURING GITWEB FEATURES
+---------------------------
+Many gitweb features can be enabled (or disabled) and configured using the
+`%feature` hash.  Names of gitweb features are keys of this hash.
+
+Each `%feature` hash element is a hash reference and has the following
+structure:
+----------------------------------------------------------------------
+"<feature-name>" => {
+	"sub" => <feature-sub-(subroutine)>,
+	"override" => <allow-override-(boolean)>,
+	"default" => [ <options>... ]
+},
+----------------------------------------------------------------------
+Some features cannot be overridden per project.  For those
+features the structure of appropriate `%feature` hash element has a simpler
+form:
+----------------------------------------------------------------------
+"<feature-name>" => {
+	"override" => 0,
+	"default" => [ <options>... ]
+},
+----------------------------------------------------------------------
+As one can see it lacks the \'sub' element.
+
+The meaning of each part of feature configuration is described
+below:
+
+default::
+	List (array reference) of feature parameters (if there are any),
+	used also to toggle (enable or disable) given feature.
++
+Note that it is currently *always* an array reference, even if
+feature doesn't accept any configuration parameters, and \'default'
+is used only to turn it on or off.  In such case you turn feature on
+by setting this element to `[1]`, and torn it off by setting it to
+`[0]`.  See also the passage about the "blame" feature in the "Examples"
+section.
++
+To disable features that accept parameters (are configurable), you
+need to set this element to empty list i.e. `[]`.
+
+override::
+	If this field has a true value then the given feature is
+	overridable, which means that it can be configured
+	(or enabled/disabled) on a per-repository basis.
++
+Usually given "<feature>" is configurable via the `gitweb.<feature>`
+config variable in the per-repository Git configuration file.
++
+*Note* that no feature is overridable by default.
+
+sub::
+	Internal detail of implementation.  What is important is that
+	if this field is not present then per-repository override for
+	given feature is not supported.
++
+You wouldn't need to ever change it in gitweb config file.
+
+
+Features in `%feature`
+~~~~~~~~~~~~~~~~~~~~~~
+The gitweb features that are configurable via `%feature` hash are listed
+below.  This should be a complete list, but ultimately the authoritative
+and complete list is in gitweb.cgi source code, with features described
+in the comments.
+
+blame::
+	Enable the "blame" and "blame_incremental" blob views, showing for
+	each line the last commit that modified it; see linkgit:git-blame[1].
+	This can be very CPU-intensive and is therefore disabled by default.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.blame` configuration variable (boolean).
+
+snapshot::
+	Enable and configure the "snapshot" action, which allows user to
+	download a compressed archive of any tree or commit, as produced
+	by linkgit:git-archive[1] and possibly additionally compressed.
+	This can potentially generate high traffic if you have large project.
++
+The value of \'default' is a list of names of snapshot formats,
+defined in `%known_snapshot_formats` hash, that you wish to offer.
+Supported formats include "tgz", "tbz2", "txz" (gzip/bzip2/xz
+compressed tar archive) and "zip"; please consult gitweb sources for
+a definitive list.  By default only "tgz" is offered.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.snapshot` configuration variable, which contains
+a comma separated list of formats or "none" to disable snapshots.
+Unknown values are ignored.
+
+grep::
+	Enable grep search, which lists the files in currently selected
+	tree (directory) containing the given string; see linkgit:git-grep[1].
+	This can be potentially CPU-intensive, of course.  Enabled by default.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.grep` configuration variable (boolean).
+
+pickaxe::
+	Enable the so called pickaxe search, which will list the commits
+	that introduced or removed a given string in a file.  This can be
+	practical and quite faster alternative to "blame" action, but it is
+	still potentially CPU-intensive.  Enabled by default.
++
+The pickaxe search is described in linkgit:git-log[1] (the
+description of `-S<string>` option, which refers to pickaxe entry in
+linkgit:gitdiffcore[7] for more details).
++
+This feature can be configured on a per-repository basis by setting
+repository's `gitweb.pickaxe` configuration variable (boolean).
+
+show-sizes::
+	Enable showing size of blobs (ordinary files) in a "tree" view, in a
+	separate column, similar to what `ls -l` does; see description of
+	`-l` option in linkgit:git-ls-tree[1] manpage.  This costs a bit of
+	I/O.  Enabled by default.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.showSizes` configuration variable (boolean).
+
+patches::
+	Enable and configure "patches" view, which displays list of commits in email
+	(plain text) output format; see also linkgit:git-format-patch[1].
+	The value is the maximum number of patches in a patchset generated
+	in "patches" view.  Set the 'default' field to a list containing single
+	item of or to an empty list to disable patch view, or to a list
+	containing a single negative number to remove any limit.
+	Default value is 16.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.patches` configuration variable (integer).
+
+avatar::
+	Avatar support.  When this feature is enabled, views such as
+	"shortlog" or "commit" will display an avatar associated with
+	the email of each committer and author.
++
+Currently available providers are *"gravatar"* and *"picon"*.
+Only one provider at a time can be selected ('default' is one element list).
+If an unknown provider is specified, the feature is disabled.
+*Note* that some providers might require extra Perl packages to be
+installed; see `gitweb/INSTALL` for more details.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.avatar` configuration variable.
++
+See also `%avatar_size` with pixel sizes for icons and avatars
+("default" is used for one-line like "log" and "shortlog", "double"
+is used for two-line like "commit", "commitdiff" or "tag").  If the
+default font sizes or lineheights are changed (e.g. via adding extra
+CSS stylesheet in `@stylesheets`), it may be appropriate to change
+these values.
+
+email-privacy::
+	Redact e-mail addresses from the generated HTML, etc. content.
+	This obscures e-mail addresses retrieved from the author/committer
+	and comment sections of the Git log.
+	It is meant to hinder web crawlers that harvest and abuse addresses.
+	Such crawlers may not respect robots.txt.
+	Note that users and user tools also see the addresses as redacted.
+	If Gitweb is not the final step in a workflow then subsequent steps
+	may misbehave because of the redacted information they receive.
+	Disabled by default.
+
+highlight::
+	Server-side syntax highlight support in "blob" view.  It requires
+	`$highlight_bin` program to be available (see the description of
+	this variable in the "Configuration variables" section above),
+	and therefore is disabled by default.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.highlight` configuration variable (boolean).
+
+remote_heads::
+	Enable displaying remote heads (remote-tracking branches) in the "heads"
+	list.  In most cases the list of remote-tracking branches is an
+	unnecessary internal private detail, and this feature is therefore
+	disabled by default.  linkgit:git-instaweb[1], which is usually used
+	to browse local repositories, enables and uses this feature.
++
+This feature can be configured on a per-repository basis via
+repository's `gitweb.remote_heads` configuration variable (boolean).
+
+
+The remaining features cannot be overridden on a per project basis.
+
+search::
+	Enable text search, which will list the commits which match author,
+	committer or commit text to a given string; see the description of
+	`--author`, `--committer` and `--grep` options in linkgit:git-log[1]
+	manpage.  Enabled by default.
++
+Project specific override is not supported.
+
+forks::
+	If this feature is enabled, gitweb considers projects in
+	subdirectories of project root (basename) to be forks of existing
+	projects.  For each project +$projname.git+, projects in the
+	+$projname/+ directory and its subdirectories will not be
+	shown in the main projects list.  Instead, a \'+' mark is shown
+	next to `$projname`, which links to a "forks" view that lists all
+	the forks (all projects in `$projname/` subdirectory).  Additionally
+	a "forks" view for a project is linked from project summary page.
++
+If the project list is taken from a file (+$projects_list+ points to a
+file), forks are only recognized if they are listed after the main project
+in that file.
++
+Project specific override is not supported.
+
+actions::
+	Insert custom links to the action bar of all project pages.  This
+	allows you to link to third-party scripts integrating into gitweb.
++
+The "default" value consists of a list of triplets in the form
+`("<label>", "<link>", "<position>")` where "position" is the label
+after which to insert the link, "link" is a format string where `%n`
+expands to the project name, `%f` to the project path within the
+filesystem (i.e. "$projectroot/$project"), `%h` to the current hash
+(\'h' gitweb parameter) and `%b` to the current hash base
+(\'hb' gitweb parameter); `%%` expands to \'%'.
++
+For example, at the time this page was written, the https://repo.or.cz[]
+Git hosting site set it to the following to enable graphical log
+(using the third party tool *git-browser*):
++
+----------------------------------------------------------------------
+$feature{'actions'}{'default'} =
+	[ ('graphiclog', '/git-browser/by-commit.html?r=%n', 'summary')];
+----------------------------------------------------------------------
++
+This adds a link titled "graphiclog" after the "summary" link, leading to
+`git-browser` script, passing `r=<project>` as a query parameter.
++
+Project specific override is not supported.
+
+timed::
+	Enable displaying how much time and how many Git commands it took to
+	generate and display each page in the page footer (at the bottom of
+	page).  For example the footer might contain: "This page took 6.53325
+	seconds and 13 Git commands to generate."  Disabled by default.
++
+Project specific override is not supported.
+
+javascript-timezone::
+	Enable and configure the ability to change a common time zone for dates
+	in gitweb output via JavaScript.  Dates in gitweb output include
+	authordate and committerdate in "commit", "commitdiff" and "log"
+	views, and taggerdate in "tag" view.  Enabled by default.
++
+The value is a list of three values: a default time zone (for if the client
+hasn't selected some other time zone and saved it in a cookie), a name of cookie
+where to store selected time zone, and a CSS class used to mark up
+dates for manipulation.  If you want to turn this feature off, set "default"
+to empty list: `[]`.
++
+Typical gitweb config files will only change starting (default) time zone,
+and leave other elements at their default values:
++
+---------------------------------------------------------------------------
+$feature{'javascript-timezone'}{'default'}[0] = "utc";
+---------------------------------------------------------------------------
++
+The example configuration presented here is guaranteed to be backwards
+and forward compatible.
++
+Time zone values can be "local" (for local time zone that browser uses), "utc"
+(what gitweb uses when JavaScript or this feature is disabled), or numerical
+time zones in the form of "+/-HHMM", such as "+0200".
++
+Project specific override is not supported.
+
+extra-branch-refs::
+	List of additional directories under "refs" which are going to
+	be used as branch refs. For example if you have a gerrit setup
+	where all branches under refs/heads/ are official,
+	push-after-review ones and branches under refs/sandbox/,
+	refs/wip and refs/other are user ones where permissions are
+	much wider, then you might want to set this variable as
+	follows:
++
+--------------------------------------------------------------------------------
+$feature{'extra-branch-refs'}{'default'} =
+	['sandbox', 'wip', 'other'];
+--------------------------------------------------------------------------------
++
+This feature can be configured on per-repository basis after setting
+$feature{'extra-branch-refs'}{'override'} to true, via repository's
+`gitweb.extraBranchRefs` configuration variable, which contains a
+space separated list of refs. An example:
++
+--------------------------------------------------------------------------------
+[gitweb]
+	extraBranchRefs = sandbox wip other
+--------------------------------------------------------------------------------
++
+The gitweb.extraBranchRefs is actually a multi-valued configuration
+variable, so following example is also correct and the result is the
+same as of the snippet above:
++
+--------------------------------------------------------------------------------
+[gitweb]
+	extraBranchRefs = sandbox
+	extraBranchRefs = wip other
+--------------------------------------------------------------------------------
++
+It is an error to specify a ref that does not pass "git check-ref-format"
+scrutiny. Duplicated values are filtered.
+
+
+EXAMPLES
+--------
+
+To enable blame, pickaxe search, and snapshot support (allowing "tar.gz" and
+"zip" snapshots), while allowing individual projects to turn them off, put
+the following in your GITWEB_CONFIG file:
+
+--------------------------------------------------------------------------------
+$feature{'blame'}{'default'} = [1];
+$feature{'blame'}{'override'} = 1;
+
+$feature{'pickaxe'}{'default'} = [1];
+$feature{'pickaxe'}{'override'} = 1;
+
+$feature{'snapshot'}{'default'} = ['zip', 'tgz'];
+$feature{'snapshot'}{'override'} = 1;
+--------------------------------------------------------------------------------
+
+If you allow overriding for the snapshot feature, you can specify which
+snapshot formats are globally disabled. You can also add any command-line
+options you want (such as setting the compression level). For instance, you
+can disable Zip compressed snapshots and set *gzip*(1) to run at level 6 by
+adding the following lines to your gitweb configuration file:
+
+	$known_snapshot_formats{'zip'}{'disabled'} = 1;
+	$known_snapshot_formats{'tgz'}{'compressor'} = ['gzip','-6'];
+
+BUGS
+----
+Debugging would be easier if the fallback configuration file
+(`/etc/gitweb.conf`) and environment variable to override its location
+('GITWEB_CONFIG_SYSTEM') had names reflecting their "fallback" role.
+The current names are kept to avoid breaking working setups.
+
+ENVIRONMENT
+-----------
+The location of per-instance and system-wide configuration files can be
+overridden using the following environment variables:
+
+GITWEB_CONFIG::
+	Sets location of per-instance configuration file.
+GITWEB_CONFIG_SYSTEM::
+	Sets location of fallback system-wide configuration file.
+	This file is read only if per-instance one does not exist.
+GITWEB_CONFIG_COMMON::
+	Sets location of common system-wide configuration file.
+
+
+FILES
+-----
+gitweb_config.perl::
+	This is default name of per-instance configuration file.  The
+	format of this file is described above.
+/etc/gitweb.conf::
+	This is default name of fallback system-wide configuration
+	file.  This file is used only if per-instance configuration
+	variable is not found.
+/etc/gitweb-common.conf::
+	This is default name of common system-wide configuration
+	file.
+
+
+SEE ALSO
+--------
+linkgit:gitweb[1], linkgit:git-instaweb[1]
+
+'gitweb/README', 'gitweb/INSTALL'
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/gitworkflows.adoc b/Documentation/gitworkflows.adoc
new file mode 100644
index 0000000000..59305265c5
--- /dev/null
+++ b/Documentation/gitworkflows.adoc
@@ -0,0 +1,479 @@
+gitworkflows(7)
+===============
+
+NAME
+----
+gitworkflows - An overview of recommended workflows with Git
+
+SYNOPSIS
+--------
+[verse]
+git *
+
+
+DESCRIPTION
+-----------
+
+This document attempts to write down and motivate some of the workflow
+elements used for `git.git` itself.  Many ideas apply in general,
+though the full workflow is rarely required for smaller projects with
+fewer people involved.
+
+We formulate a set of 'rules' for quick reference, while the prose
+tries to motivate each of them.  Do not always take them literally;
+you should value good reasons for your actions higher than manpages
+such as this one.
+
+
+SEPARATE CHANGES
+----------------
+
+As a general rule, you should try to split your changes into small
+logical steps, and commit each of them.  They should be consistent,
+working independently of any later commits, pass the test suite, etc.
+This makes the review process much easier, and the history much more
+useful for later inspection and analysis, for example with
+linkgit:git-blame[1] and linkgit:git-bisect[1].
+
+To achieve this, try to split your work into small steps from the very
+beginning. It is always easier to squash a few commits together than
+to split one big commit into several.  Don't be afraid of making too
+small or imperfect steps along the way. You can always go back later
+and edit the commits with `git rebase --interactive` before you
+publish them.  You can use `git stash push --keep-index` to run the
+test suite independent of other uncommitted changes; see the EXAMPLES
+section of linkgit:git-stash[1].
+
+
+MANAGING BRANCHES
+-----------------
+
+There are two main tools that can be used to include changes from one
+branch on another: linkgit:git-merge[1] and
+linkgit:git-cherry-pick[1].
+
+Merges have many advantages, so we try to solve as many problems as
+possible with merges alone.  Cherry-picking is still occasionally
+useful; see "Merging upwards" below for an example.
+
+Most importantly, merging works at the branch level, while
+cherry-picking works at the commit level.  This means that a merge can
+carry over the changes from 1, 10, or 1000 commits with equal ease,
+which in turn means the workflow scales much better to a large number
+of contributors (and contributions).  Merges are also easier to
+understand because a merge commit is a "promise" that all changes from
+all its parents are now included.
+
+There is a tradeoff of course: merges require a more careful branch
+management.  The following subsections discuss the important points.
+
+
+Graduation
+~~~~~~~~~~
+
+As a given feature goes from experimental to stable, it also
+"graduates" between the corresponding branches of the software.
+`git.git` uses the following 'integration branches':
+
+* 'maint' tracks the commits that should go into the next "maintenance
+  release", i.e., update of the last released stable version;
+
+* 'master' tracks the commits that should go into the next release;
+
+* 'next' is intended as a testing branch for topics being tested for
+  stability for master.
+
+There is a fourth official branch that is used slightly differently:
+
+* 'seen' (patches seen by the maintainer) is an integration branch for
+  things that are not quite ready for inclusion yet (see "Integration
+  Branches" below).
+
+Each of the four branches is usually a direct descendant of the one
+above it.
+
+Conceptually, the feature enters at an unstable branch (usually 'next'
+or 'seen'), and "graduates" to 'master' for the next release once it is
+considered stable enough.
+
+
+Merging upwards
+~~~~~~~~~~~~~~~
+
+The "downwards graduation" discussed above cannot be done by actually
+merging downwards, however, since that would merge 'all' changes on
+the unstable branch into the stable one.  Hence the following:
+
+.Merge upwards
+[caption="Rule: "]
+=====================================
+Always commit your fixes to the oldest supported branch that requires
+them.  Then (periodically) merge the integration branches upwards into each
+other.
+=====================================
+
+This gives a very controlled flow of fixes.  If you notice that you
+have applied a fix to e.g. 'master' that is also required in 'maint',
+you will need to cherry-pick it (using linkgit:git-cherry-pick[1])
+downwards.  This will happen a few times and is nothing to worry about
+unless you do it very frequently.
+
+
+Topic branches
+~~~~~~~~~~~~~~
+
+Any nontrivial feature will require several patches to implement, and
+may get extra bugfixes or improvements during its lifetime.
+
+Committing everything directly on the integration branches leads to many
+problems: Bad commits cannot be undone, so they must be reverted one
+by one, which creates confusing histories and further error potential
+when you forget to revert part of a group of changes.  Working in
+parallel mixes up the changes, creating further confusion.
+
+Use of "topic branches" solves these problems.  The name is pretty
+self explanatory, with a caveat that comes from the "merge upwards"
+rule above:
+
+.Topic branches
+[caption="Rule: "]
+=====================================
+Make a side branch for every topic (feature, bugfix, ...). Fork it off
+at the oldest integration branch that you will eventually want to merge it
+into.
+=====================================
+
+Many things can then be done very naturally:
+
+* To get the feature/bugfix into an integration branch, simply merge
+  it.  If the topic has evolved further in the meantime, merge again.
+  (Note that you do not necessarily have to merge it to the oldest
+  integration branch first.  For example, you can first merge a bugfix
+  to 'next', give it some testing time, and merge to 'maint' when you
+  know it is stable.)
+
+* If you find you need new features from the branch 'other' to continue
+  working on your topic, merge 'other' to 'topic'.  (However, do not
+  do this "just habitually", see below.)
+
+* If you find you forked off the wrong branch and want to move it
+  "back in time", use linkgit:git-rebase[1].
+
+Note that the last point clashes with the other two: a topic that has
+been merged elsewhere should not be rebased.  See the section on
+RECOVERING FROM UPSTREAM REBASE in linkgit:git-rebase[1].
+
+We should point out that "habitually" (regularly for no real reason)
+merging an integration branch into your topics -- and by extension,
+merging anything upstream into anything downstream on a regular basis
+-- is frowned upon:
+
+.Merge to downstream only at well-defined points
+[caption="Rule: "]
+=====================================
+Do not merge to downstream except with a good reason: upstream API
+changes affect your branch; your branch no longer merges to upstream
+cleanly; etc.
+=====================================
+
+Otherwise, the topic that was merged to suddenly contains more than a
+single (well-separated) change.  The many resulting small merges will
+greatly clutter up history.  Anyone who later investigates the history
+of a file will have to find out whether that merge affected the topic
+in development.  An upstream might even inadvertently be merged into a
+"more stable" branch.  And so on.
+
+
+Throw-away integration
+~~~~~~~~~~~~~~~~~~~~~~
+
+If you followed the last paragraph, you will now have many small topic
+branches, and occasionally wonder how they interact.  Perhaps the
+result of merging them does not even work?  But on the other hand, we
+want to avoid merging them anywhere "stable" because such merges
+cannot easily be undone.
+
+The solution, of course, is to make a merge that we can undo: merge
+into a throw-away branch.
+
+.Throw-away integration branches
+[caption="Rule: "]
+=====================================
+To test the interaction of several topics, merge them into a
+throw-away branch.  You must never base any work on such a branch!
+=====================================
+
+If you make it (very) clear that this branch is going to be deleted
+right after the testing, you can even publish this branch, for example
+to give the testers a chance to work with it, or other developers a
+chance to see if their in-progress work will be compatible.  `git.git`
+has such an official throw-away integration branch called 'seen'.
+
+
+Branch management for a release
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Assuming you are using the merge approach discussed above, when you
+are releasing your project you will need to do some additional branch
+management work.
+
+A feature release is created from the 'master' branch, since 'master'
+tracks the commits that should go into the next feature release.
+
+The 'master' branch is supposed to be a superset of 'maint'. If this
+condition does not hold, then 'maint' contains some commits that
+are not included on 'master'. The fixes represented by those commits
+will therefore not be included in your feature release.
+
+To verify that 'master' is indeed a superset of 'maint', use git log:
+
+.Verify 'master' is a superset of 'maint'
+[caption="Recipe: "]
+=====================================
+`git log master..maint`
+=====================================
+
+This command should not list any commits.  Otherwise, check out
+'master' and merge 'maint' into it.
+
+Now you can proceed with the creation of the feature release. Apply a
+tag to the tip of 'master' indicating the release version:
+
+.Release tagging
+[caption="Recipe: "]
+=====================================
+`git tag -s -m "Git X.Y.Z" vX.Y.Z master`
+=====================================
+
+You need to push the new tag to a public Git server (see
+"DISTRIBUTED WORKFLOWS" below). This makes the tag available to
+others tracking your project. The push could also trigger a
+post-update hook to perform release-related items such as building
+release tarballs and preformatted documentation pages.
+
+Similarly, for a maintenance release, 'maint' is tracking the commits
+to be released. Therefore, in the steps above simply tag and push
+'maint' rather than 'master'.
+
+
+Maintenance branch management after a feature release
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+After a feature release, you need to manage your maintenance branches.
+
+First, if you wish to continue to release maintenance fixes for the
+feature release made before the recent one, then you must create
+another branch to track commits for that previous release.
+
+To do this, the current maintenance branch is copied to another branch
+named with the previous release version number (e.g. maint-X.Y.(Z-1)
+where X.Y.Z is the current release).
+
+.Copy maint
+[caption="Recipe: "]
+=====================================
+`git branch maint-X.Y.(Z-1) maint`
+=====================================
+
+The 'maint' branch should now be fast-forwarded to the newly released
+code so that maintenance fixes can be tracked for the current release:
+
+.Update maint to new release
+[caption="Recipe: "]
+=====================================
+* `git checkout maint`
+* `git merge --ff-only master`
+=====================================
+
+If the merge fails because it is not a fast-forward, then it is
+possible some fixes on 'maint' were missed in the feature release.
+This will not happen if the content of the branches was verified as
+described in the previous section.
+
+
+Branch management for next and seen after a feature release
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+After a feature release, the integration branch 'next' may optionally be
+rewound and rebuilt from the tip of 'master' using the surviving
+topics on 'next':
+
+.Rewind and rebuild next
+[caption="Recipe: "]
+=====================================
+* `git switch -C next master`
+* `git merge ai/topic_in_next1`
+* `git merge ai/topic_in_next2`
+* ...
+=====================================
+
+The advantage of doing this is that the history of 'next' will be
+clean. For example, some topics merged into 'next' may have initially
+looked promising, but were later found to be undesirable or premature.
+In such a case, the topic is reverted out of 'next' but the fact
+remains in the history that it was once merged and reverted. By
+recreating 'next', you give another incarnation of such topics a clean
+slate to retry, and a feature release is a good point in history to do
+so.
+
+If you do this, then you should make a public announcement indicating
+that 'next' was rewound and rebuilt.
+
+The same rewind and rebuild process may be followed for 'seen'. A public
+announcement is not necessary since 'seen' is a throw-away branch, as
+described above.
+
+
+DISTRIBUTED WORKFLOWS
+---------------------
+
+After the last section, you should know how to manage topics.  In
+general, you will not be the only person working on the project, so
+you will have to share your work.
+
+Roughly speaking, there are two important workflows: merge and patch.
+The important difference is that the merge workflow can propagate full
+history, including merges, while patches cannot.  Both workflows can
+be used in parallel: in `git.git`, only subsystem maintainers use
+the merge workflow, while everyone else sends patches.
+
+Note that the maintainer(s) may impose restrictions, such as
+"Signed-off-by" requirements, that all commits/patches submitted for
+inclusion must adhere to.  Consult your project's documentation for
+more information.
+
+
+Merge workflow
+~~~~~~~~~~~~~~
+
+The merge workflow works by copying branches between upstream and
+downstream.  Upstream can merge contributions into the official
+history; downstream base their work on the official history.
+
+There are three main tools that can be used for this:
+
+* linkgit:git-push[1] copies your branches to a remote repository,
+  usually to one that can be read by all involved parties;
+
+* linkgit:git-fetch[1] that copies remote branches to your repository;
+  and
+
+* linkgit:git-pull[1] that does fetch and merge in one go.
+
+Note the last point.  Do 'not' use 'git pull' unless you actually want
+to merge the remote branch.
+
+Getting changes out is easy:
+
+.Push/pull: Publishing branches/topics
+[caption="Recipe: "]
+=====================================
+`git push <remote> <branch>` and tell everyone where they can fetch
+from.
+=====================================
+
+You will still have to tell people by other means, such as mail.  (Git
+provides the linkgit:git-request-pull[1] to send preformatted pull
+requests to upstream maintainers to simplify this task.)
+
+If you just want to get the newest copies of the integration branches,
+staying up to date is easy too:
+
+.Push/pull: Staying up to date
+[caption="Recipe: "]
+=====================================
+Use `git fetch <remote>` or `git remote update` to stay up to date.
+=====================================
+
+Then simply fork your topic branches from the stable remotes as
+explained earlier.
+
+If you are a maintainer and would like to merge other people's topic
+branches to the integration branches, they will typically send a
+request to do so by mail.  Such a request looks like
+
+-------------------------------------
+Please pull from
+    <URL> <branch>
+-------------------------------------
+
+In that case, 'git pull' can do the fetch and merge in one go, as
+follows.
+
+.Push/pull: Merging remote topics
+[caption="Recipe: "]
+=====================================
+`git pull <URL> <branch>`
+=====================================
+
+Occasionally, the maintainer may get merge conflicts when they try to
+pull changes from downstream.  In this case, they can ask downstream to
+do the merge and resolve the conflicts themselves (perhaps they will
+know better how to resolve them).  It is one of the rare cases where
+downstream 'should' merge from upstream.
+
+
+Patch workflow
+~~~~~~~~~~~~~~
+
+If you are a contributor that sends changes upstream in the form of
+emails, you should use topic branches as usual (see above).  Then use
+linkgit:git-format-patch[1] to generate the corresponding emails
+(highly recommended over manually formatting them because it makes the
+maintainer's life easier).
+
+.format-patch/am: Publishing branches/topics
+[caption="Recipe: "]
+=====================================
+* `git format-patch -M upstream..topic` to turn them into preformatted
+  patch files
+* `git send-email --to=<recipient> <patches>`
+=====================================
+
+See the linkgit:git-format-patch[1] and linkgit:git-send-email[1]
+manpages for further usage notes.
+
+If the maintainer tells you that your patch no longer applies to the
+current upstream, you will have to rebase your topic (you cannot use a
+merge because you cannot format-patch merges):
+
+.format-patch/am: Keeping topics up to date
+[caption="Recipe: "]
+=====================================
+`git pull --rebase <URL> <branch>`
+=====================================
+
+You can then fix the conflicts during the rebase.  Presumably you have
+not published your topic other than by mail, so rebasing it is not a
+problem.
+
+If you receive such a patch series (as maintainer, or perhaps as a
+reader of the mailing list it was sent to), save the mails to files,
+create a new topic branch and use 'git am' to import the commits:
+
+.format-patch/am: Importing patches
+[caption="Recipe: "]
+=====================================
+`git am < patch`
+=====================================
+
+One feature worth pointing out is the three-way merge, which can help
+if you get conflicts: `git am -3` will use index information contained
+in patches to figure out the merge base.  See linkgit:git-am[1] for
+other options.
+
+
+SEE ALSO
+--------
+linkgit:gittutorial[7],
+linkgit:git-push[1],
+linkgit:git-pull[1],
+linkgit:git-merge[1],
+linkgit:git-rebase[1],
+linkgit:git-format-patch[1],
+linkgit:git-send-email[1],
+linkgit:git-am[1]
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/glossary-content.adoc b/Documentation/glossary-content.adoc
new file mode 100644
index 0000000000..575c18f776
--- /dev/null
+++ b/Documentation/glossary-content.adoc
@@ -0,0 +1,766 @@
+[[def_alternate_object_database]]alternate object database::
+	Via the alternates mechanism, a <<def_repository,repository>>
+	can inherit part of its <<def_object_database,object database>>
+	from another object database, which is called an "alternate".
+
+[[def_bare_repository]]bare repository::
+	A bare repository is normally an appropriately
+	named <<def_directory,directory>> with a `.git` suffix that does not
+	have a locally checked-out copy of any of the files under
+	revision control. That is, all of the Git
+	administrative and control files that would normally be present in the
+	hidden `.git` sub-directory are directly present in the
+	`repository.git` directory instead,
+	and no other files are present and checked out. Usually publishers of
+	public repositories make bare repositories available.
+
+[[def_blob_object]]blob object::
+	Untyped <<def_object,object>>, e.g. the contents of a file.
+
+[[def_branch]]branch::
+	A "branch" is a line of development.  The most recent
+	<<def_commit,commit>> on a branch is referred to as the tip of
+	that branch.  The tip of the branch is <<def_ref,referenced>> by a branch
+	<<def_head,head>>, which moves forward as additional development
+	is done on the branch.  A single Git
+	<<def_repository,repository>> can track an arbitrary number of
+	branches, but your <<def_working_tree,working tree>> is
+	associated with just one of them (the "current" or "checked out"
+	branch), and <<def_HEAD,HEAD>> points to that branch.
+
+[[def_cache]]cache::
+	Obsolete for: <<def_index,index>>.
+
+[[def_chain]]chain::
+	A list of objects, where each <<def_object,object>> in the list contains
+	a reference to its successor (for example, the successor of a
+	<<def_commit,commit>> could be one of its <<def_parent,parents>>).
+
+[[def_changeset]]changeset::
+	BitKeeper/cvsps speak for "<<def_commit,commit>>". Since Git does not
+	store changes, but states, it really does not make sense to use the term
+	"changesets" with Git.
+
+[[def_checkout]]checkout::
+	The action of updating all or part of the
+	<<def_working_tree,working tree>> with a <<def_tree_object,tree object>>
+	or <<def_blob_object,blob>> from the
+	<<def_object_database,object database>>, and updating the
+	<<def_index,index>> and <<def_HEAD,HEAD>> if the whole working tree has
+	been pointed at a new <<def_branch,branch>>.
+
+[[def_cherry-picking]]cherry-picking::
+	In <<def_SCM,SCM>> jargon, "cherry pick" means to choose a subset of
+	changes out of a series of changes (typically commits) and record them
+	as a new series of changes on top of a different codebase. In Git, this is
+	performed by the "git cherry-pick" command to extract the change introduced
+	by an existing <<def_commit,commit>> and to record it based on the tip
+	of the current <<def_branch,branch>> as a new commit.
+
+[[def_clean]]clean::
+	A <<def_working_tree,working tree>> is clean, if it
+	corresponds to the <<def_revision,revision>> referenced by the current
+	<<def_head,head>>. Also see "<<def_dirty,dirty>>".
+
+[[def_commit]]commit::
+	As a noun: A single point in the
+	Git history; the entire history of a project is represented as a
+	set of interrelated commits.  The word "commit" is often
+	used by Git in the same places other revision control systems
+	use the words "revision" or "version".  Also used as a short
+	hand for <<def_commit_object,commit object>>.
++
+As a verb: The action of storing a new snapshot of the project's
+state in the Git history, by creating a new commit representing the current
+state of the <<def_index,index>> and advancing <<def_HEAD,HEAD>>
+to point at the new commit.
+
+[[def_commit_graph_general]]commit graph concept, representations and usage::
+	A synonym for the <<def_DAG,DAG>> structure formed by the commits
+	in the object database, <<def_ref,referenced>> by branch tips,
+	using their <<def_chain,chain>> of linked commits.
+	This structure is the definitive commit graph. The
+	graph can be represented in other ways, e.g. the
+	<<def_commit_graph_file,"commit-graph" file>>.
+
+[[def_commit_graph_file]]commit-graph file::
+	The "commit-graph" (normally hyphenated) file is a supplemental
+	representation of the <<def_commit_graph_general,commit graph>>
+	which accelerates commit graph walks. The "commit-graph" file is
+	stored either in the .git/objects/info directory or in the info
+	directory of an alternate object database.
+
+[[def_commit_object]]commit object::
+	An <<def_object,object>> which contains the information about a
+	particular <<def_revision,revision>>, such as <<def_parent,parents>>, committer,
+	author, date and the <<def_tree_object,tree object>> which corresponds
+	to the top <<def_directory,directory>> of the stored
+	revision.
+
+[[def_commit-ish]]commit-ish (also committish)::
+	A <<def_commit_object,commit object>> or an <<def_object,object>> that
+	can be recursively <<def_dereference,dereferenced>> to a commit object.
+	The following are all commit-ishes:
+	a commit object,
+	a <<def_tag_object,tag object>> that points to a commit
+	object,
+	a tag object that points to a tag object that points to a
+	commit object,
+	etc.
+
+[[def_core_git]]core Git::
+	Fundamental data structures and utilities of Git. Exposes only limited
+	source code management tools.
+
+[[def_DAG]]DAG::
+	Directed acyclic graph. The <<def_commit_object,commit objects>> form a
+	directed acyclic graph, because they have parents (directed), and the
+	graph of commit objects is acyclic (there is no <<def_chain,chain>>
+	which begins and ends with the same <<def_object,object>>).
+
+[[def_dangling_object]]dangling object::
+	An <<def_unreachable_object,unreachable object>> which is not
+	<<def_reachable,reachable>> even from other unreachable objects; a
+	dangling object has no references to it from any
+	reference or <<def_object,object>> in the <<def_repository,repository>>.
+
+[[def_dereference]]dereference::
+	Referring to a <<def_symref,symbolic ref>>: the action of accessing the
+	<<def_ref,reference>> pointed at by a symbolic ref. Recursive
+	dereferencing involves repeating the aforementioned process on the
+	resulting ref until a non-symbolic reference is found.
++
+Referring to a <<def_tag_object,tag object>>: the action of accessing the
+<<def_object,object>> a tag points at. Tags are recursively dereferenced by
+repeating the operation on the result object until the result has either a
+specified <<def_object_type,object type>> (where applicable) or any non-"tag"
+object type. A synonym for "recursive dereference" in the context of tags is
+"<<def_peel,peel>>".
++
+Referring to a <<def_commit_object,commit object>>: the action of accessing
+the commit's tree object. Commits cannot be dereferenced recursively.
++
+Unless otherwise specified, "dereferencing" as it used in the context of Git
+commands or protocols is implicitly recursive.
+
+[[def_detached_HEAD]]detached HEAD::
+	Normally the <<def_HEAD,HEAD>> stores the name of a
+	<<def_branch,branch>>, and commands that operate on the
+	history HEAD represents operate on the history leading to the
+	tip of the branch the HEAD points at.  However, Git also
+	allows you to <<def_checkout,check out>> an arbitrary
+	<<def_commit,commit>> that isn't necessarily the tip of any
+	particular branch.  The HEAD in such a state is called
+	"detached".
++
+Note that commands that operate on the history of the current branch
+(e.g. `git commit` to build a new history on top of it) still work
+while the HEAD is detached. They update the HEAD to point at the tip
+of the updated history without affecting any branch.  Commands that
+update or inquire information _about_ the current branch (e.g. `git
+branch --set-upstream-to` that sets what remote-tracking branch the
+current branch integrates with) obviously do not work, as there is no
+(real) current branch to ask about in this state.
+
+[[def_directory]]directory::
+	The list you get with "ls" :-)
+
+[[def_dirty]]dirty::
+	A <<def_working_tree,working tree>> is said to be "dirty" if
+	it contains modifications which have not been <<def_commit,committed>> to the current
+	<<def_branch,branch>>.
+
+[[def_evil_merge]]evil merge::
+	An evil merge is a <<def_merge,merge>> that introduces changes that
+	do not appear in any <<def_parent,parent>>.
+
+[[def_fast_forward]]fast-forward::
+	A fast-forward is a special type of <<def_merge,merge>> where you have a
+	<<def_revision,revision>> and you are "merging" another
+	<<def_branch,branch>>'s changes that happen to be a descendant of what
+	you have. In such a case, you do not make a new <<def_merge,merge>>
+	<<def_commit,commit>> but instead just update your branch to point at the same
+	revision as the branch you are merging. This will happen frequently on a
+	<<def_remote_tracking_branch,remote-tracking branch>> of a remote
+	<<def_repository,repository>>.
+
+[[def_fetch]]fetch::
+	Fetching a <<def_branch,branch>> means to get the
+	branch's <<def_head_ref,head ref>> from a remote
+	<<def_repository,repository>>, to find out which objects are
+	missing from the local <<def_object_database,object database>>,
+	and to get them, too.  See also linkgit:git-fetch[1].
+
+[[def_file_system]]file system::
+	Linus Torvalds originally designed Git to be a user space file system,
+	i.e. the infrastructure to hold files and directories. That ensured the
+	efficiency and speed of Git.
+
+[[def_git_archive]]Git archive::
+	Synonym for <<def_repository,repository>> (for arch people).
+
+[[def_gitfile]]gitfile::
+	A plain file `.git` at the root of a working tree that
+	points at the directory that is the real repository.
+	For proper use see linkgit:git-worktree[1] or linkgit:git-submodule[1].
+	For syntax see linkgit:gitrepository-layout[5].
+
+[[def_grafts]]grafts::
+	Grafts enable two otherwise different lines of development to be joined
+	together by recording fake ancestry information for commits. This way
+	you can make Git pretend the set of <<def_parent,parents>> a <<def_commit,commit>> has
+	is different from what was recorded when the commit was
+	created. Configured via the `.git/info/grafts` file.
++
+Note that the grafts mechanism is outdated and can lead to problems
+transferring objects between repositories; see linkgit:git-replace[1]
+for a more flexible and robust system to do the same thing.
+
+[[def_hash]]hash::
+	In Git's context, synonym for <<def_object_name,object name>>.
+
+[[def_head]]head::
+	A <<def_ref,named reference>> to the <<def_commit,commit>> at the tip of a
+	<<def_branch,branch>>.  Heads are stored in a file in
+	`$GIT_DIR/refs/heads/` directory, except when using packed refs. (See
+	linkgit:git-pack-refs[1].)
+
+[[def_HEAD]]HEAD::
+	The current <<def_branch,branch>>.  In more detail: Your <<def_working_tree,
+	working tree>> is normally derived from the state of the tree
+	referred to by HEAD.  HEAD is a reference to one of the
+	<<def_head,heads>> in your repository, except when using a
+	<<def_detached_HEAD,detached HEAD>>, in which case it directly
+	references an arbitrary commit.
+
+[[def_head_ref]]head ref::
+	A synonym for <<def_head,head>>.
+
+[[def_hook]]hook::
+	During the normal execution of several Git commands, call-outs are made
+	to optional scripts that allow a developer to add functionality or
+	checking. Typically, the hooks allow for a command to be pre-verified
+	and potentially aborted, and allow for a post-notification after the
+	operation is done. The hook scripts are found in the
+	`$GIT_DIR/hooks/` directory, and are enabled by simply
+	removing the `.sample` suffix from the filename. In earlier versions
+	of Git you had to make them executable.
+
+[[def_index]]index::
+	A collection of files with stat information, whose contents are stored
+	as objects. The index is a stored version of your
+	<<def_working_tree,working tree>>. Truth be told, it can also contain a second, and even
+	a third version of a working tree, which are used
+	when <<def_merge,merging>>.
+
+[[def_index_entry]]index entry::
+	The information regarding a particular file, stored in the
+	<<def_index,index>>. An index entry can be unmerged, if a
+	<<def_merge,merge>> was started, but not yet finished (i.e. if
+	the index contains multiple versions of that file).
+
+[[def_master]]master::
+	The default development <<def_branch,branch>>. Whenever you
+	create a Git <<def_repository,repository>>, a branch named
+	"master" is created, and becomes the active branch. In most
+	cases, this contains the local development, though that is
+	purely by convention and is not required.
+
+[[def_merge]]merge::
+	As a verb: To bring the contents of another
+	<<def_branch,branch>> (possibly from an external
+	<<def_repository,repository>>) into the current branch.  In the
+	case where the merged-in branch is from a different repository,
+	this is done by first <<def_fetch,fetching>> the remote branch
+	and then merging the result into the current branch.  This
+	combination of fetch and merge operations is called a
+	<<def_pull,pull>>.  Merging is performed by an automatic process
+	that identifies changes made since the branches diverged, and
+	then applies all those changes together.  In cases where changes
+	conflict, manual intervention may be required to complete the
+	merge.
++
+As a noun: unless it is a <<def_fast_forward,fast-forward>>, a
+successful merge results in the creation of a new <<def_commit,commit>>
+representing the result of the merge, and having as
+<<def_parent,parents>> the tips of the merged <<def_branch,branches>>.
+This commit is referred to as a "merge commit", or sometimes just a
+"merge".
+
+[[def_object]]object::
+	The unit of storage in Git. It is uniquely identified by the
+	<<def_SHA1,SHA-1>> of its contents. Consequently, an
+	object cannot be changed.
+
+[[def_object_database]]object database::
+	Stores a set of "objects", and an individual <<def_object,object>> is
+	identified by its <<def_object_name,object name>>. The objects usually
+	live in `$GIT_DIR/objects/`.
+
+[[def_object_identifier]]object identifier (oid)::
+	Synonym for <<def_object_name,object name>>.
+
+[[def_object_name]]object name::
+	The unique identifier of an <<def_object,object>>.  The
+	object name is usually represented by a 40 character
+	hexadecimal string.  Also colloquially called <<def_SHA1,SHA-1>>.
+
+[[def_object_type]]object type::
+	One of the identifiers "<<def_commit_object,commit>>",
+	"<<def_tree_object,tree>>", "<<def_tag_object,tag>>" or
+	"<<def_blob_object,blob>>" describing the type of an
+	<<def_object,object>>.
+
+[[def_octopus]]octopus::
+	To <<def_merge,merge>> more than two <<def_branch,branches>>.
+
+[[def_orphan]]orphan::
+	The act of getting on a <<def_branch,branch>> that does not
+	exist yet (i.e., an <<def_unborn,unborn>> branch).  After
+	such an operation, the commit first created becomes a commit
+	without a parent, starting a new history.
+
+[[def_origin]]origin::
+	The default upstream <<def_repository,repository>>. Most projects have
+	at least one upstream project which they track. By default
+	'origin' is used for that purpose. New upstream updates
+	will be fetched into <<def_remote_tracking_branch,remote-tracking branches>> named
+	origin/name-of-upstream-branch, which you can see using
+	`git branch -r`.
+
+[[def_overlay]]overlay::
+	Only update and add files to the working directory, but don't
+	delete them, similar to how 'cp -R' would update the contents
+	in the destination directory.  This is the default mode in a
+	<<def_checkout,checkout>> when checking out files from the
+	<<def_index,index>> or a <<def_tree-ish,tree-ish>>.  In
+	contrast, no-overlay mode also deletes tracked files not
+	present in the source, similar to 'rsync --delete'.
+
+[[def_pack]]pack::
+	A set of objects which have been compressed into one file (to save space
+	or to transmit them efficiently).
+
+[[def_pack_index]]pack index::
+	The list of identifiers, and other information, of the objects in a
+	<<def_pack,pack>>, to assist in efficiently accessing the contents of a
+	pack.
+
+[[def_pathspec]]pathspec::
+	Pattern used to limit paths in Git commands.
++
+Pathspecs are used on the command line of "git ls-files", "git
+ls-tree", "git add", "git grep", "git diff", "git checkout",
+and many other commands to
+limit the scope of operations to some subset of the tree or
+working tree.  See the documentation of each command for whether
+paths are relative to the current directory or toplevel.  The
+pathspec syntax is as follows:
++
+--
+
+* any path matches itself
+* the pathspec up to the last slash represents a
+  directory prefix.  The scope of that pathspec is
+  limited to that subtree.
+* the rest of the pathspec is a pattern for the remainder
+  of the pathname.  Paths relative to the directory
+  prefix will be matched against that pattern using fnmatch(3);
+  in particular, '*' and '?' _can_ match directory separators.
+
+--
++
+For example, Documentation/*.jpg will match all .jpg files
+in the Documentation subtree,
+including Documentation/chapter_1/figure_1.jpg.
++
+A pathspec that begins with a colon `:` has special meaning.  In the
+short form, the leading colon `:` is followed by zero or more "magic
+signature" letters (which optionally is terminated by another colon `:`),
+and the remainder is the pattern to match against the path.
+The "magic signature" consists of ASCII symbols that are neither
+alphanumeric, glob, regex special characters nor colon.
+The optional colon that terminates the "magic signature" can be
+omitted if the pattern begins with a character that does not belong to
+"magic signature" symbol set and is not a colon.
++
+In the long form, the leading colon `:` is followed by an open
+parenthesis `(`, a comma-separated list of zero or more "magic words",
+and a close parentheses `)`, and the remainder is the pattern to match
+against the path.
++
+A pathspec with only a colon means "there is no pathspec". This form
+should not be combined with other pathspec.
++
+--
+top;;
+	The magic word `top` (magic signature: `/`) makes the pattern
+	match from the root of the working tree, even when you are
+	running the command from inside a subdirectory.
+
+literal;;
+	Wildcards in the pattern such as `*` or `?` are treated
+	as literal characters.
+
+icase;;
+	Case insensitive match.
+
+glob;;
+	Git treats the pattern as a shell glob suitable for
+	consumption by fnmatch(3) with the FNM_PATHNAME flag:
+	wildcards in the pattern will not match a / in the pathname.
+	For example, "Documentation/{asterisk}.html" matches
+	"Documentation/git.html" but not "Documentation/ppc/ppc.html"
+	or "tools/perf/Documentation/perf.html".
++
+Two consecutive asterisks ("`**`") in patterns matched against
+full pathname may have special meaning:
+
+ - A leading "`**`" followed by a slash means match in all
+   directories. For example, "`**/foo`" matches file or directory
+   "`foo`" anywhere, the same as pattern "`foo`". "`**/foo/bar`"
+   matches file or directory "`bar`" anywhere that is directly
+   under directory "`foo`".
+
+ - A trailing "`/**`" matches everything inside. For example,
+   "`abc/**`" matches all files inside directory "abc", relative
+   to the location of the `.gitignore` file, with infinite depth.
+
+ - A slash followed by two consecutive asterisks then a slash
+   matches zero or more directories. For example, "`a/**/b`"
+   matches "`a/b`", "`a/x/b`", "`a/x/y/b`" and so on.
+
+ - Other consecutive asterisks are considered invalid.
++
+Glob magic is incompatible with literal magic.
+
+attr;;
+After `attr:` comes a space separated list of "attribute
+requirements", all of which must be met in order for the
+path to be considered a match; this is in addition to the
+usual non-magic pathspec pattern matching.
+See linkgit:gitattributes[5].
++
+Each of the attribute requirements for the path takes one of
+these forms:
+
+- "`ATTR`" requires that the attribute `ATTR` be set.
+
+- "`-ATTR`" requires that the attribute `ATTR` be unset.
+
+- "`ATTR=VALUE`" requires that the attribute `ATTR` be
+  set to the string `VALUE`.
+
+- "`!ATTR`" requires that the attribute `ATTR` be
+  unspecified.
++
+Note that when matching against a tree object, attributes are still
+obtained from working tree, not from the given tree object.
+
+exclude;;
+	After a path matches any non-exclude pathspec, it will be run
+	through all exclude pathspecs (magic signature: `!` or its
+	synonym `^`). If it matches, the path is ignored.  When there
+	is no non-exclude pathspec, the exclusion is applied to the
+	result set as if invoked without any pathspec.
+--
+
+[[def_parent]]parent::
+	A <<def_commit_object,commit object>> contains a (possibly empty) list
+	of the logical predecessor(s) in the line of development, i.e. its
+	parents.
+
+[[def_peel]]peel::
+	The action of recursively <<def_dereference,dereferencing>> a
+	<<def_tag_object,tag object>>.
+
+[[def_pickaxe]]pickaxe::
+	The term <<def_pickaxe,pickaxe>> refers to an option to the diffcore
+	routines that help select changes that add or delete a given text
+	string. With the `--pickaxe-all` option, it can be used to view the full
+	<<def_changeset,changeset>> that introduced or removed, say, a
+	particular line of text. See linkgit:git-diff[1].
+
+[[def_plumbing]]plumbing::
+	Cute name for <<def_core_git,core Git>>.
+
+[[def_porcelain]]porcelain::
+	Cute name for programs and program suites depending on
+	<<def_core_git,core Git>>, presenting a high level access to
+	core Git. Porcelains expose more of a <<def_SCM,SCM>>
+	interface than the <<def_plumbing,plumbing>>.
+
+[[def_per_worktree_ref]]per-worktree ref::
+	Refs that are per-<<def_worktree,worktree>>, rather than
+	global.  This is presently only <<def_HEAD,HEAD>> and any refs
+	that start with `refs/bisect/`, but might later include other
+	unusual refs.
+
+[[def_pseudoref]]pseudoref::
+	A ref that has different semantics than normal refs. These refs can be
+	read via normal Git commands, but cannot be written to by commands like
+	linkgit:git-update-ref[1].
++
+The following pseudorefs are known to Git:
+
+ - `FETCH_HEAD` is written by linkgit:git-fetch[1] or linkgit:git-pull[1]. It
+   may refer to multiple object IDs. Each object ID is annotated with metadata
+   indicating where it was fetched from and its fetch status.
+
+ - `MERGE_HEAD` is written by linkgit:git-merge[1] when resolving merge
+   conflicts. It contains all commit IDs which are being merged.
+
+[[def_pull]]pull::
+	Pulling a <<def_branch,branch>> means to <<def_fetch,fetch>> it and
+	<<def_merge,merge>> it.  See also linkgit:git-pull[1].
+
+[[def_push]]push::
+	Pushing a <<def_branch,branch>> means to get the branch's
+	<<def_head_ref,head ref>> from a remote <<def_repository,repository>>,
+	find out if it is an ancestor to the branch's local
+	head ref, and in that case, putting all
+	objects, which are <<def_reachable,reachable>> from the local
+	head ref, and which are missing from the remote
+	repository, into the remote
+	<<def_object_database,object database>>, and updating the remote
+	head ref. If the remote <<def_head,head>> is not an
+	ancestor to the local head, the push fails.
+
+[[def_reachable]]reachable::
+	All of the ancestors of a given <<def_commit,commit>> are said to be
+	"reachable" from that commit. More
+	generally, one <<def_object,object>> is reachable from
+	another if we can reach the one from the other by a <<def_chain,chain>>
+	that follows <<def_tag,tags>> to whatever they tag,
+	<<def_commit_object,commits>> to their parents or trees, and
+	<<def_tree_object,trees>> to the trees or <<def_blob_object,blobs>>
+	that they contain.
+
+[[def_reachability_bitmap]]reachability bitmaps::
+	Reachability bitmaps store information about the
+	<<def_reachable,reachability>> of a selected set of commits in
+	a packfile, or a multi-pack index (MIDX), to speed up object search.
+	The bitmaps are stored in a ".bitmap" file. A repository may have at
+	most one bitmap file in use. The bitmap file may belong to either one
+	pack, or the repository's multi-pack index (if it exists).
+
+[[def_rebase]]rebase::
+	To reapply a series of changes from a <<def_branch,branch>> to a
+	different base, and reset the <<def_head,head>> of that branch
+	to the result.
+
+[[def_ref]]ref::
+	A name that points to an <<def_object_name,object name>> or
+	another ref (the latter is called a <<def_symref,symbolic ref>>).
+	For convenience, a ref can sometimes be abbreviated when used
+	as an argument to a Git command; see linkgit:gitrevisions[7]
+	for details.
+	Refs are stored in the <<def_repository,repository>>.
++
+The ref namespace is hierarchical.
+Ref names must either start with `refs/` or be located in the root of
+the hierarchy. For the latter, their name must follow these rules:
++
+ - The name consists of only upper-case characters or underscores.
+
+ - The name ends with "`_HEAD`" or is equal to "`HEAD`".
++
+There are some irregular refs in the root of the hierarchy that do not
+match these rules. The following list is exhaustive and shall not be
+extended in the future:
++
+ - `AUTO_MERGE`
+
+ - `BISECT_EXPECTED_REV`
+
+ - `NOTES_MERGE_PARTIAL`
+
+ - `NOTES_MERGE_REF`
+
+ - `MERGE_AUTOSTASH`
++
+Different subhierarchies are used for different purposes. For example,
+the `refs/heads/` hierarchy is used to represent local branches whereas
+the `refs/tags/` hierarchy is used to represent local tags..
+
+[[def_reflog]]reflog::
+	A reflog shows the local "history" of a ref.  In other words,
+	it can tell you what the 3rd last revision in _this_ repository
+	was, and what was the current state in _this_ repository,
+	yesterday 9:14pm.  See linkgit:git-reflog[1] for details.
+
+[[def_refspec]]refspec::
+	A "refspec" is used by <<def_fetch,fetch>> and
+	<<def_push,push>> to describe the mapping between remote
+	<<def_ref,ref>> and local ref. See linkgit:git-fetch[1] or
+	linkgit:git-push[1] for details.
+
+[[def_remote]]remote repository::
+	A <<def_repository,repository>> which is used to track the same
+	project but resides somewhere else. To communicate with remotes,
+	see <<def_fetch,fetch>> or <<def_push,push>>.
+
+[[def_remote_tracking_branch]]remote-tracking branch::
+	A <<def_ref,ref>> that is used to follow changes from another
+	<<def_repository,repository>>. It typically looks like
+	'refs/remotes/foo/bar' (indicating that it tracks a branch named
+	'bar' in a remote named 'foo'), and matches the right-hand-side of
+	a configured fetch <<def_refspec,refspec>>. A remote-tracking
+	branch should not contain direct modifications or have local
+	commits made to it.
+
+[[def_repository]]repository::
+	A collection of <<def_ref,refs>> together with an
+	<<def_object_database,object database>> containing all objects
+	which are <<def_reachable,reachable>> from the refs, possibly
+	accompanied by meta data from one or more <<def_porcelain,porcelains>>. A
+	repository can share an object database with other repositories
+	via <<def_alternate_object_database,alternates mechanism>>.
+
+[[def_resolve]]resolve::
+	The action of fixing up manually what a failed automatic
+	<<def_merge,merge>> left behind.
+
+[[def_revision]]revision::
+	Synonym for <<def_commit,commit>> (the noun).
+
+[[def_rewind]]rewind::
+	To throw away part of the development, i.e. to assign the
+	<<def_head,head>> to an earlier <<def_revision,revision>>.
+
+[[def_SCM]]SCM::
+	Source code management (tool).
+
+[[def_SHA1]]SHA-1::
+	"Secure Hash Algorithm 1"; a cryptographic hash function.
+	In the context of Git used as a synonym for <<def_object_name,object name>>.
+
+[[def_shallow_clone]]shallow clone::
+	Mostly a synonym to <<def_shallow_repository,shallow repository>>
+	but the phrase makes it more explicit that it was created by
+	running `git clone --depth=...` command.
+
+[[def_shallow_repository]]shallow repository::
+	A shallow <<def_repository,repository>> has an incomplete
+	history some of whose <<def_commit,commits>> have <<def_parent,parents>> cauterized away (in other
+	words, Git is told to pretend that these commits do not have the
+	parents, even though they are recorded in the <<def_commit_object,commit
+	object>>). This is sometimes useful when you are interested only in the
+	recent history of a project even though the real history recorded in the
+	upstream is much larger. A shallow repository
+	is created by giving the `--depth` option to linkgit:git-clone[1], and
+	its history can be later deepened with linkgit:git-fetch[1].
+
+[[def_stash]]stash entry::
+	An <<def_object,object>> used to temporarily store the contents of a
+	<<def_dirty,dirty>> working directory and the index for future reuse.
+
+[[def_submodule]]submodule::
+	A <<def_repository,repository>> that holds the history of a
+	separate project inside another repository (the latter of
+	which is called <<def_superproject, superproject>>).
+
+[[def_superproject]]superproject::
+	A <<def_repository,repository>> that references repositories
+	of other projects in its working tree as <<def_submodule,submodules>>.
+	The superproject knows about the names of (but does not hold
+	copies of) commit objects of the contained submodules.
+
+[[def_symref]]symref::
+	Symbolic reference: instead of containing the <<def_SHA1,SHA-1>> id
+	itself, it is of the format 'ref: refs/some/thing' and when referenced,
+	it recursively <<def_dereference,dereferences>> to this reference.
+	'<<def_HEAD,HEAD>>' is a prime example of a symref. Symbolic references
+	are manipulated with the linkgit:git-symbolic-ref[1] command.
+
+[[def_tag]]tag::
+	A <<def_ref,ref>> under `refs/tags/` namespace that points to an
+	object of an arbitrary type (typically a tag points to either a
+	<<def_tag_object,tag>> or a <<def_commit_object,commit object>>).
+	In contrast to a <<def_head,head>>, a tag is not updated by
+	the `commit` command. A Git tag has nothing to do with a Lisp
+	tag (which would be called an <<def_object_type,object type>>
+	in Git's context). A tag is most typically used to mark a particular
+	point in the commit ancestry <<def_chain,chain>>.
+
+[[def_tag_object]]tag object::
+	An <<def_object,object>> containing a <<def_ref,ref>> pointing to
+	another object, which can contain a message just like a
+	<<def_commit_object,commit object>>. It can also contain a (PGP)
+	signature, in which case it is called a "signed tag object".
+
+[[def_topic_branch]]topic branch::
+	A regular Git <<def_branch,branch>> that is used by a developer to
+	identify a conceptual line of development. Since branches are very easy
+	and inexpensive, it is often desirable to have several small branches
+	that each contain very well defined concepts or small incremental yet
+	related changes.
+
+[[def_trailer]]trailer::
+	Key-value metadata.  Trailers are optionally found at the end of
+	a commit message.  Might be called "footers" or "tags" in other
+	communities.  See linkgit:git-interpret-trailers[1].
+
+[[def_tree]]tree::
+	Either a <<def_working_tree,working tree>>, or a <<def_tree_object,tree
+	object>> together with the dependent <<def_blob_object,blob>> and tree objects
+	(i.e. a stored representation of a working tree).
+
+[[def_tree_object]]tree object::
+	An <<def_object,object>> containing a list of file names and modes along
+	with refs to the associated blob and/or tree objects. A
+	<<def_tree,tree>> is equivalent to a <<def_directory,directory>>.
+
+[[def_tree-ish]]tree-ish (also treeish)::
+	A <<def_tree_object,tree object>> or an <<def_object,object>> that can
+	be recursively <<def_dereference,dereferenced>> to a tree object.
+	Dereferencing a <<def_commit_object,commit object>> yields the tree
+	object corresponding to the <<def_revision,revision>>'s top
+	<<def_directory,directory>>.
+	The following are all tree-ishes:
+	a <<def_commit-ish,commit-ish>>,
+	a tree object,
+	a <<def_tag_object,tag object>> that points to a tree object,
+	a tag object that points to a tag object that points to a tree
+	object,
+	etc.
+
+[[def_unborn]]unborn::
+	The <<def_HEAD,HEAD>> can point at a <<def_branch,branch>>
+	that does not yet exist and that does not have any commit on
+	it yet, and such a branch is called an unborn branch.  The
+	most typical way users encounter an unborn branch is by
+	creating a repository anew without cloning from elsewhere.
+	The HEAD would point at the 'main' (or 'master', depending
+	on your configuration) branch that is yet to be born.  Also
+	some operations can get you on an unborn branch with their
+	<<def_orphan,orphan>> option.
+
+
+[[def_unmerged_index]]unmerged index::
+	An <<def_index,index>> which contains unmerged
+	<<def_index_entry,index entries>>.
+
+[[def_unreachable_object]]unreachable object::
+	An <<def_object,object>> which is not <<def_reachable,reachable>> from a
+	<<def_branch,branch>>, <<def_tag,tag>>, or any other reference.
+
+[[def_upstream_branch]]upstream branch::
+	The default <<def_branch,branch>> that is merged into the branch in
+	question (or the branch in question is rebased onto). It is configured
+	via branch.<name>.remote and branch.<name>.merge. If the upstream branch
+	of 'A' is 'origin/B' sometimes we say "'A' is tracking 'origin/B'".
+
+[[def_working_tree]]working tree::
+	The tree of actual checked out files.  The working tree normally
+	contains the contents of the <<def_HEAD,HEAD>> commit's tree,
+	plus any local changes that you have made but not yet committed.
+
+[[def_worktree]]worktree::
+	A repository can have zero (i.e. bare repository) or one or
+	more worktrees attached to it. One "worktree" consists of a
+	"working tree" and repository metadata, most of which are
+	shared among other worktrees of a single repository, and
+	some of which are maintained separately per worktree
+	(e.g. the index, HEAD and pseudorefs like MERGE_HEAD,
+	per-worktree refs and per-worktree configuration file).
diff --git a/Documentation/howto-index.adoc b/Documentation/howto-index.adoc
new file mode 100644
index 0000000000..7f74654621
--- /dev/null
+++ b/Documentation/howto-index.adoc
@@ -0,0 +1,6 @@
+Git Howto Index
+===============
+
+Here is a collection of mailing list postings made by various
+people describing how they use Git in their workflow.
+
diff --git a/Documentation/howto/coordinate-embargoed-releases.adoc b/Documentation/howto/coordinate-embargoed-releases.adoc
new file mode 100644
index 0000000000..b9cb95e82f
--- /dev/null
+++ b/Documentation/howto/coordinate-embargoed-releases.adoc
@@ -0,0 +1,246 @@
+Content-type: text/asciidoc
+Abstract: When a vulnerability is reported, we follow these guidelines to
+ assess the vulnerability, create and review a fix, and coordinate embargoed
+ security releases.
+
+How we coordinate embargoed releases
+------------------------------------
+
+To protect Git users from critical vulnerabilities, we do not just release
+fixed versions like regular maintenance releases. Instead, we coordinate
+releases with packagers, keeping the fixes under an embargo until the release
+date. That way, users will have a chance to upgrade on that date, no matter
+what Operating System or distribution they run.
+
+The `git-security` mailing list
+-------------------------------
+
+Responsible disclosures of vulnerabilities, analysis, proposed fixes as
+well as the orchestration of coordinated embargoed releases all happen on the
+`git-security` mailing list at <git-security@xxxxxxxxxxxxxxxx>.
+
+In this context, the term "embargo" refers to the time period that information
+about a vulnerability is kept under wraps and only shared on a need-to-know
+basis. This is necessary to protect Git's users from bad actors who would
+otherwise be made aware of attack vectors that could be exploited. "Lifting the
+embargo" refers to publishing the version that fixes the vulnerabilities.
+
+Audience of the `git-security` mailing list
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Anybody may contact the `git-security` mailing list by sending an email
+to <git-security@xxxxxxxxxxxxxxxx>, though the archive is closed to the
+public and only accessible to subscribed members.
+
+There are a few dozen subscribed members: core Git developers who are trusted
+with addressing vulnerabilities, and stakeholders (i.e. owners of products
+affected by security vulnerabilities in Git).
+
+Most of the discussions revolve around assessing the severity of the reported
+issue (including the decision whether the report is security-relevant or can be
+redirected to the public mailing list), how to remediate the issue, determining
+the timeline of the disclosure as well as aligning priorities and
+requirements.
+
+Communications
+~~~~~~~~~~~~~~
+
+If you are a stakeholder, it is a good idea to pay close attention to the
+discussions, as pertinent information may be buried in the middle of a lively
+conversation that might not look relevant to your interests. For example, the
+tentative timeline might be agreed upon in the middle of discussing code
+comment formatting in one of the patches and whether or not to combine fixes
+for multiple, separate vulnerabilities into the same embargoed release. Most
+mail threads are not usually structured specifically to communicate
+agreements, assessments or timelines.
+
+Typical timeline
+----------------
+
+- A potential vulnerability is reported to the `git-security` mailing list.
+
+- The members of the git-security list start a discussion to give an initial
+  assessment of the severity of the reported potential vulnerability.
+  We aspire to do so within a few days.
+
+- After discussion, if consensus is reached that it is not critical enough
+  to warrant any embargo, the reporter is redirected to the public Git mailing
+  list. This ends the reporter's interaction with the `git-security` list.
+
+- If it is deemed critical enough for an embargo, ideas are presented on how to
+  address the vulnerability.
+
+- Usually around that time, the Git maintainer or their delegate(s) open a draft
+  security advisory in the `git/git` repository on GitHub (see below for more
+  details).
+
+- Code review can take place in a variety of different locations,
+  depending on context. These are: patches sent inline on the git-security list,
+  a private fork on GitHub associated with the draft security advisory, or the
+  git/cabal repository.
+
+- Contributors working on a fix should consider beginning by sending
+  patches to the git-security list (inline with the original thread), since they
+  are accessible to all subscribers, along with the original reporter.
+
+- Once the review has settled and everyone involved in the review agrees that
+  the patches are nearing the finish line, the Git maintainer, and others
+  determine a release date as well as the release trains that are serviced. The
+  decision regarding which versions need a backported fix is based on input from
+  the reporter, the contributor who worked on the patches, and from
+  stakeholders. Operators of hosting sites who may want to analyze whether the
+  given issue is exploited via any of the repositories they host, and binary
+  packagers who want to make sure their product gets patched adequately against
+  the vulnerability, for example, may want to give their input at this stage.
+
+- While the Git community does its best to accommodate the specific timeline
+  requests of the various binary packagers, the nature of the issue may preclude
+  a prolonged release schedule. For fixes deemed urgent, it may be in the best
+  interest of the Git users community to shorten the disclosure and release
+  timeline, and packagers may need to adapt accordingly.
+
+- Subsequently, branches with the fixes are pushed to the git/cabal repository.
+
+- The tags are created by the Git maintainer and pushed to the same repository.
+
+- The Git for Windows, Git for macOS, BSD, Debian, etc. maintainers prepare the
+  corresponding release artifacts, based on the tags created that have been
+  prepared by the Git maintainer.
+
+- The release artifacts prepared by various binary packagers can be
+  made available to stakeholders under embargo via a mail to the
+  `git-security` list.
+
+- Less than a week before the release, a mail with the relevant information is
+  sent to <distros@xxxxxxxxxxxxxxx> (see below), a list used to pre-announce
+  embargoed releases of open source projects to the stakeholders of all major
+  distributions of Linux as well as other OSes.
+
+- Public communication is then prepared in advance of the release date. This
+  includes blog posts and mails to the Git and Git for Windows mailing lists.
+
+- On the day of the release, at around 10am Pacific Time, the Git maintainer
+  pushes the tag and the `master` branch to the public repository, then sends
+  out an announcement mail.
+
+- Once the tag is pushed, the Git for Windows maintainer publishes the
+  corresponding tag and creates a GitHub Release with the associated release
+  artifacts (Git for Windows installer, Portable Git, MinGit, etc).
+
+- Git for Windows release is then announced via a mail to the public Git and
+  Git for Windows mailing lists as well as via a tweet.
+
+- Ditto for distribution packagers for Linux and other platforms:
+  their releases are announced via their preferred channels.
+
+- A mail to <oss-security@xxxxxxxxxxxxxxxxxx> (see below for details) is sent
+  as a follow-up to the <distros@xxxxxxxxxxxxxxx> one, describing the
+  vulnerability in detail, often including a proof of concept of an exploit.
+
+Note: The Git project makes no guarantees about timelines, but aims to keep
+embargoes reasonably short in the interest of keeping Git's users safe.
+
+Opening a Security Advisory draft
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The first step is to https://github.com/git/git/security/advisories/new[open
+an advisory]. Technically, this is not necessary. However, it is the most
+convenient way to obtain the CVE number and it gives us a private repository
+associated with it that can be used to collaborate on a fix.
+
+Notifying the Linux distributions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+At most two weeks before release date, we need to send a notification to
+<distros@xxxxxxxxxxxxxxx>, preferably less than 7 days before the release date.
+This will reach most (all?) Linux distributions. See an example below, and the
+guidelines for this mailing list at
+https://oss-security.openwall.org/wiki/mailing-lists/distros#how-to-use-the-lists[here].
+
+Once the version has been published, we send a note about that to oss-security.
+As an example, see https://www.openwall.com/lists/oss-security/2019/12/13/1[the
+v2.24.1 mail];
+https://oss-security.openwall.org/wiki/mailing-lists/oss-security[Here] are
+their guidelines.
+
+The mail to oss-security should also describe the exploit, and give credit to
+the reporter(s): security researchers still receive too little respect for the
+invaluable service they provide, and public credit goes a long way to keep them
+paid by their respective organizations.
+
+Technically, describing any exploit can be delayed up to 7 days, but we usually
+refrain from doing that, including it right away.
+
+As a courtesy we typically attach a Git bundle (as `.tar.xz` because the list
+will drop `.bundle` attachments) in the mail to distros@ so that the involved
+parties can take care of integrating/backporting them. This bundle is typically
+created using a command like this:
+
+	git bundle create cve-xxx.bundle ^origin/master vA.B.C vD.E.F
+	tar cJvf cve-xxx.bundle.tar.xz cve-xxx.bundle
+
+Example mail to distros@xxxxxxxxxxxxxxx
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+....
+To: distros@xxxxxxxxxxxxxxx
+Cc: git-security@xxxxxxxxxxxxxxxx, <other people involved in the report/fix>
+Subject: [vs] Upcoming Git security fix release
+
+Team,
+
+The Git project will release new versions on <date> at 10am Pacific Time or
+soon thereafter. I have attached a Git bundle (embedded in a `.tar.xz` to avoid
+it being dropped) which you can fetch into a clone of
+https://github.com/git/git via `git fetch --tags /path/to/cve-xxx.bundle`,
+containing the tags for versions <versions>.
+
+You can verify with `git tag -v <tag>` that the versions were signed by
+the Git maintainer, using the same GPG key as e.g. v2.24.0.
+
+Please use these tags to prepare `git` packages for your various
+distributions, using the appropriate tagged versions. The added test cases
+help verify the correctness.
+
+The addressed issues are:
+
+<list of CVEs with a short description, typically copy/pasted from Git's
+release notes, usually demo exploit(s), too>
+
+Credit for finding the vulnerability goes to <reporter>, credit for fixing
+it goes to <developer>.
+
+Thanks,
+<name>
+
+....
+
+Example mail to oss-security@xxxxxxxxxxxxxxxxxx
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+....
+To: oss-security@xxxxxxxxxxxxxxxxxx
+Cc: git-security@xxxxxxxxxxxxxxxx, <other people involved in the report/fix>
+Subject: git: <copy from security advisory>
+
+Team,
+
+The Git project released new versions on <date>, addressing <CVE>.
+
+All supported platforms are affected in one way or another, and all Git
+versions all the way back to <version> are affected. The fixed versions are:
+<versions>.
+
+Link to the announcement: <link to lore.kernel.org/git>
+
+We highly recommend to upgrade.
+
+The addressed issues are:
+* <list of CVEs and their explanations, along with demo exploits>
+
+Credit for finding the vulnerability goes to <reporter>, credit for fixing
+it goes to <developer>.
+
+Thanks,
+<name>
+....
\ No newline at end of file
diff --git a/Documentation/howto/howto-index.sh b/Documentation/howto/howto-index.sh
new file mode 100755
index 0000000000..a5634e7347
--- /dev/null
+++ b/Documentation/howto/howto-index.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+cat <<\EOF
+Git Howto Index
+===============
+
+Here is a collection of mailing list postings made by various
+people describing how they use Git in their workflow.
+
+EOF
+
+for txt
+do
+	title=$(expr "$txt" : '.*/\(.*\)\.adoc$')
+	from=$(sed -ne '
+	/^$/q
+	/^From:[ 	]/{
+		s///
+		s/^[ 	]*//
+		s/[ 	]*$//
+		s/^/by /
+		p
+	}
+	' "$txt")
+
+	abstract=$(sed -ne '
+	/^Abstract:[ 	]/{
+		s/^[^ 	]*//
+		x
+		s/.*//
+		x
+		: again
+		/^[ 	]/{
+			s/^[ 	]*//
+			H
+			n
+			b again
+		}
+		x
+		p
+		q
+	}' "$txt")
+
+	if grep 'Content-type: text/asciidoc' >/dev/null $txt
+	then
+		file=$(expr "$adoc" : '\(.*\)\.adoc$').html
+	else
+		file="$txt"
+	fi
+
+	echo "* link:howto/$(basename "$file")[$title] $from
+$abstract
+
+"
+
+done
diff --git a/Documentation/howto/keep-canonical-history-correct.adoc b/Documentation/howto/keep-canonical-history-correct.adoc
new file mode 100644
index 0000000000..e98f03275e
--- /dev/null
+++ b/Documentation/howto/keep-canonical-history-correct.adoc
@@ -0,0 +1,216 @@
+From: Junio C Hamano <gitster@xxxxxxxxx>
+Date: Wed, 07 May 2014 13:15:39 -0700
+Subject: Beginner question on "Pull is mostly evil"
+Abstract: This how-to explains a method for keeping a
+ project's history correct when using git pull.
+Content-type: text/asciidoc
+
+Keep authoritative canonical history correct with git pull
+==========================================================
+
+Sometimes a new project integrator will end up with project history
+that appears to be "backwards" from what other project developers
+expect. This howto presents a suggested integration workflow for
+maintaining a central repository.
+
+Suppose that the central repository has this history:
+
+------------
+    ---o---o---A
+------------
+
+which ends at commit `A` (time flows from left to right and each node
+in the graph is a commit, lines between them indicating parent-child
+relationship).
+
+Then you clone it and work on your own commits, which leads you to
+have this history in *your* repository:
+
+------------
+    ---o---o---A---B---C
+------------
+
+Imagine your coworker did the same and built on top of `A` in *his*
+repository in the meantime, and then pushed it to the
+central repository:
+
+------------
+    ---o---o---A---X---Y---Z
+------------
+
+Now, if you `git push` at this point, because your history that leads
+to `C` lacks `X`, `Y` and `Z`, it will fail.  You need to somehow make
+the tip of your history a descendant of `Z`.
+
+One suggested way to solve the problem is "fetch and then merge", aka
+`git pull`. When you fetch, your repository will have a history like
+this:
+
+------------
+    ---o---o---A---B---C
+		\
+		 X---Y---Z
+------------
+
+Once you run merge after that, while still on *your* branch, i.e. `C`,
+you will create a merge `M` and make the history look like this:
+
+------------
+    ---o---o---A---B---C---M
+		\         /
+		 X---Y---Z
+------------
+
+`M` is a descendant of `Z`, so you can push to update the central
+repository.  Such a merge `M` does not lose any commit in both
+histories, so in that sense it may not be wrong, but when people want
+to talk about "the authoritative canonical history that is shared
+among the project participants", i.e. "the trunk", they often view
+it as "commits you see by following the first-parent chain", and use
+this command to view it:
+
+------------
+    $ git log --first-parent
+------------
+
+For all other people who observed the central repository after your
+coworker pushed `Z` but before you pushed `M`, the commit on the trunk
+used to be `o-o-A-X-Y-Z`.  But because you made `M` while you were on
+`C`, `M`'s first parent is `C`, so by pushing `M` to advance the
+central repository, you made `X-Y-Z` a side branch, not on the trunk.
+
+You would rather want to have a history of this shape:
+
+------------
+    ---o---o---A---X---Y---Z---M'
+		\             /
+		 B-----------C
+------------
+
+so that in the first-parent chain, it is clear that the project first
+did `X` and then `Y` and then `Z` and merged a change that consists of
+two commits `B` and `C` that achieves a single goal.  You may have
+worked on fixing the bug #12345 with these two patches, and the merge
+`M'` with swapped parents can say in its log message "Merge
+fix-bug-12345". Having a way to tell `git pull` to create a merge
+but record the parents in reverse order may be a way to do so.
+
+Note that I said "achieves a single goal" above, because this is
+important.  "Swapping the merge order" only covers a special case
+where the project does not care too much about having unrelated
+things done on a single merge but cares a lot about first-parent
+chain.
+
+There are multiple schools of thought about the "trunk" management.
+
+ 1. Some projects want to keep a completely linear history without any
+    merges.  Obviously, swapping the merge order would not match their
+    taste.  You would need to flatten your history on top of the
+    updated upstream to result in a history of this shape instead:
++
+------------
+    ---o---o---A---X---Y---Z---B---C
+------------
++
+with `git pull --rebase` or something.
+
+ 2. Some projects tolerate merges in their history, but do not worry
+    too much about the first-parent order, and allow fast-forward
+    merges.  To them, swapping the merge order does not hurt, but
+    it is unnecessary.
+
+ 3. Some projects want each commit on the "trunk" to do one single
+    thing.  The output of `git log --first-parent` in such a project
+    would show either a merge of a side branch that completes a single
+    theme, or a single commit that completes a single theme by itself.
+    If your two commits `B` and `C` (or they may even be two groups of
+    commits) were solving two independent issues, then the merge `M'`
+    we made in the earlier example by swapping the merge order is
+    still not up to the project standard.  It merges two unrelated
+    efforts `B` and `C` at the same time.
+
+For projects in the last category (Git itself is one of them),
+individual developers would want to prepare a history more like
+this:
+
+------------
+		 C0--C1--C2     topic-c
+		/
+    ---o---o---A                master
+		\
+		 B0--B1--B2     topic-b
+------------
+
+That is, keeping separate topics on separate branches, perhaps like
+so:
+
+------------
+    $ git clone $URL work && cd work
+    $ git checkout -b topic-b master
+    $ ... work to create B0, B1 and B2 to complete one theme
+    $ git checkout -b topic-c master
+    $ ... same for the theme of topic-c
+------------
+
+And then
+
+------------
+    $ git checkout master
+    $ git pull --ff-only
+------------
+
+would grab `X`, `Y` and `Z` from the upstream and advance your master
+branch:
+
+------------
+		 C0--C1--C2     topic-c
+		/
+    ---o---o---A---X---Y---Z    master
+		\
+		 B0--B1--B2     topic-b
+------------
+
+And then you would merge these two branches separately:
+
+------------
+    $ git merge topic-b
+    $ git merge topic-c
+------------
+
+to result in
+
+------------
+		 C0--C1---------C2
+		/                 \
+    ---o---o---A---X---Y---Z---M---N
+		\             /
+		 B0--B1-----B2
+------------
+
+and push it back to the central repository.
+
+It is very much possible that while you are merging topic-b and
+topic-c, somebody again advanced the history in the central repository
+to put `W` on top of `Z`, and make your `git push` fail.
+
+In such a case, you would rewind to discard `M` and `N`, update the
+tip of your 'master' again and redo the two merges:
+
+------------
+    $ git reset --hard origin/master
+    $ git pull --ff-only
+    $ git merge topic-b
+    $ git merge topic-c
+------------
+
+The procedure will result in a history that looks like this:
+
+------------
+		 C0--C1--------------C2
+		/                     \
+    ---o---o---A---X---Y---Z---W---M'--N'
+		\                 /
+		 B0--B1---------B2
+------------
+
+See also https://git-blame.blogspot.com/2013/09/fun-with-first-parent-history.html
diff --git a/Documentation/howto/maintain-git.adoc b/Documentation/howto/maintain-git.adoc
new file mode 100644
index 0000000000..45e2599c5d
--- /dev/null
+++ b/Documentation/howto/maintain-git.adoc
@@ -0,0 +1,595 @@
+From: Junio C Hamano <gitster@xxxxxxxxx>
+Date: Wed, 21 Nov 2007 16:32:55 -0800
+Subject: Addendum to "MaintNotes"
+Abstract: Imagine that Git development is racing along as usual, when our friendly
+ neighborhood maintainer is struck down by a wayward bus. Out of the
+ hordes of suckers (loyal developers), you have been tricked (chosen) to
+ step up as the new maintainer. This howto will show you "how to" do it.
+Content-type: text/asciidoc
+
+How to maintain Git
+===================
+
+Activities
+----------
+
+The maintainer's Git time is spent on three activities.
+
+ - Communication (45%)
+
+   Mailing list discussions on general design, fielding user
+   questions, diagnosing bug reports; reviewing, commenting on,
+   suggesting alternatives to, and rejecting patches.
+
+ - Integration (50%)
+
+   Applying new patches from the contributors while spotting and
+   correcting minor mistakes, shuffling the integration and
+   testing branches, pushing the results out, cutting the
+   releases, and making announcements.
+
+ - Own development (5%)
+
+   Scratching my own itch and sending proposed patch series out.
+
+The Policy
+----------
+
+The policy on Integration is informally mentioned in "A Note
+from the maintainer" message, which is periodically posted to
+the mailing list after each feature release is made:
+
+ - Feature releases are numbered as vX.Y.0 and are meant to
+   contain bugfixes and enhancements in any area, including
+   functionality, performance and usability, without regression.
+
+ - Maintenance releases are numbered as vX.Y.Z (0 < Z) and are meant
+   to contain only bugfixes for the corresponding vX.Y.0 feature
+   release and earlier maintenance releases vX.Y.W (W < Z).
+
+ - The 'master' branch is used to prepare for the next feature
+   release. In other words, at some point, the tip of 'master'
+   branch is tagged as vX.(Y+1).0, when vX.Y.0 is the latest
+   feature release.
+
+ - 'maint' branch is used to prepare for the next maintenance
+   release.  After the feature release vX.Y.0 is made, the tip
+   of 'maint' branch is set to that release, and bugfixes will
+   accumulate on the branch, and at some point, the tip of the
+   branch is tagged with vX.Y.1, vX.Y.2, and so on.
+
+ - 'next' branch is used to publish changes (both enhancements
+   and fixes) that (1) have worthwhile goal, (2) are in a fairly
+   good shape suitable for everyday use, (3) but have not yet
+   demonstrated to be regression free.  Reviews from contributors on
+   the mailing list help to make the determination.  After a topic
+   is merged to 'next', it is tested for at least 7 calendar days
+   before getting merged to 'master'.
+
+ - 'seen' branch is used to publish other proposed changes that do
+   not yet pass the criteria set for 'next' (see above), but there
+   is no promise that 'seen' will contain everything.  A topic that
+   had no reviewer reaction may not be picked up.
+
+   - A new topic will first get merged to 'seen', unless it is
+     trivially correct and clearly urgent, in which case it may be
+     directly merged to 'next' or even to 'master'.
+
+   - If a topic that was picked up to 'seen' becomes and stays
+     inactive for 3 calendar weeks without having seen a clear
+     consensus that it is good enough to be moved to 'next', the
+     topic may be discarded from 'seen'.  Interested parties are
+     still free to revive the topic.  For the purpose of this
+     guideline, the definition of being "inactive" is that nobody
+     has discussed the topic, no new iteration of the topic was
+     posted, and no responses to the review comments were given.
+
+ - The tips of 'master' and 'maint' branches will not be rewound to
+   allow people to build their own customization on top of them.
+   Early in a new development cycle, 'next' is rewound to the tip of
+   'master' once, but otherwise it will not be rewound until the end
+   of the cycle.
+
+ - Usually 'master' contains all of 'maint' and 'next' contains all
+   of 'master'.  'seen' contains all the topics merged to 'next', but
+   is rebuilt directly on 'master'.
+
+ - The tip of 'master' is meant to be more stable than any
+   tagged releases, and the users are encouraged to follow it.
+
+ - The 'next' branch is where new action takes place, and the
+   users are encouraged to test it so that regressions and bugs
+   are found before new topics are merged to 'master'.
+
+ - When a problem is found in a topic in 'next', the topic is marked
+   not to be merged to 'master'.  Follow-up patches are discussed on
+   the mailing list and applied to the topic after being reviewed and
+   then the topic is merged (again) to 'next'.  After going through
+   the usual testing in 'next', the entire (fixed) topic is merged
+   to 'master'.
+
+ - One release cycle for a feature release is expected to last for
+   eight to ten weeks.  A few "release candidate" releases are
+   expected to be tagged about a week apart before the final
+   release, and a "preview" release is tagged about a week before
+   the first release candidate gets tagged.
+
+ - After the preview release is tagged, topics that were well
+   reviewed may be merged to 'master' before spending the usual 7
+   calendar days in 'next', with the expectation that any bugs in
+   them can be caught and fixed in the release candidates before
+   the final release.
+
+ - After the first release candidate is tagged, the contributors are
+   strongly encouraged to focus on finding and fixing new regressions
+   introduced during the cycle, over addressing old bugs and any new
+   features.  Topics stop getting merged down from 'next' to 'master',
+   and new topics stop getting merged to 'next'. Unless they are fixes
+   to new regressions in the cycle, that is.
+
+ - Soon after a feature release is made, the tip of 'maint' gets
+   fast-forwarded to point at the release.  Topics that have been
+   kept in 'next' are merged down to 'master' and a new development
+   cycle starts.
+
+
+Note that before v1.9.0 release, the version numbers used to be
+structured slightly differently.  vX.Y.Z were feature releases while
+vX.Y.Z.W were maintenance releases for vX.Y.Z.
+
+Because most of the lines of code in Git are written by individual
+contributors, and contributions come in the form of e-mailed patches
+published on the mailing list, the project maintains a mapping from
+individual commits to the Message-Id of the e-mail that resulted in
+the commit, to help tracking the origin of the changes. The notes
+in "refs/notes/amlog" are used for this purpose, and are published
+along with the broken-out branches to the maintainer's repository.
+
+A Typical Git Day
+-----------------
+
+A typical Git day for the maintainer implements the above policy
+by doing the following:
+
+ - Scan mailing list.  Respond with review comments, suggestions
+   etc.  Kibitz.  Collect potentially usable patches from the
+   mailing list.  Patches about a single topic go to one mailbox (I
+   read my mail in Gnus, and type \C-o to save/append messages in
+   files in mbox format).
+
+ - Write his own patches to address issues raised on the list but
+   nobody has stepped up to solve.  Send it out just like other
+   contributors do, and pick them up just like patches from other
+   contributors (see above).
+
+ - Review the patches in the saved mailboxes.  Edit proposed log
+   message for typofixes and clarifications, and add Acks
+   collected from the list.  Edit patch to incorporate "Oops,
+   that should have been like this" fixes from the discussion.
+
+ - Classify the collected patches and handle 'master' and
+   'maint' updates:
+
+   - Obviously correct fixes that pertain to the tip of 'maint'
+     are directly applied to 'maint'.
+
+   - Obviously correct fixes that pertain to the tip of 'master'
+     are directly applied to 'master'.
+
+   - Other topics are not handled in this step.
+
+   This step is done with "git am".
+
+     $ git checkout master    ;# or "git checkout maint"
+     $ git am -sc3 mailbox
+     $ make test
+
+   In practice, almost no patch directly goes to 'master' or
+   'maint'.
+
+   Applying the e-mailed patches using "git am" automatically records
+   the mappings from 'Message-Id' to the applied commit in the "amlog"
+   notes. Periodically check that this is working with "git show -s
+   --notes=amlog $commit".
+
+   This mapping is maintained with the aid of the "post-applypatch"
+   hook found in the 'todo' branch. That hook should be installed
+   before applying patches. It is also helpful to carry forward any
+   relevant amlog entries when rebasing, so the following config may
+   be useful:
+
+      [notes]
+	rewriteRef = refs/notes/amlog
+
+   Avoid "cherry-pick", as it does not propagate notes by design. Use
+   either "git commit --amend" or "git rebase" to make corrections to
+   an existing commit, even for a single-patch topic.
+
+   Make sure that a push refspec for 'refs/notes/amlog' is in the
+   remote configuration for publishing repositories. A few sample
+   configurations look like the following:
+
+      [remote "github"]
+	url = https://github.com/gitster/git
+	pushurl = github.com:gitster/git.git
+	mirror
+
+      [remote "github2"]
+	url = https://github.com/git/git
+	fetch = +refs/heads/*:refs/remotes/github2/*
+	pushurl = github.com:git/git.git
+	push = refs/heads/maint:refs/heads/maint
+	push = refs/heads/master:refs/heads/master
+	push = refs/heads/next:refs/heads/next
+	push = +refs/heads/seen:refs/heads/seen
+	push = +refs/notes/amlog
+
+ - Review the last issue of "What's cooking" message, review the
+   topics ready for merging (topic->master and topic->maint).  Use
+   "Meta/cook -w" script (where Meta/ contains a checkout of the
+   'todo' branch) to aid this step.
+
+   And perform the merge.  Use "Meta/Reintegrate -e" script (see
+   later) to aid this step.
+
+     $ Meta/cook -w last-issue-of-whats-cooking.mbox
+
+     $ git checkout master    ;# or "git checkout maint"
+     $ echo ai/topic | Meta/Reintegrate -e ;# "git merge ai/topic"
+     $ git log -p ORIG_HEAD.. ;# final review
+     $ git diff ORIG_HEAD..   ;# final review
+     $ make test              ;# final review
+
+   If the tip of 'master' is updated, also generate the preformatted
+   documentation and push the out result to git-htmldocs and
+   git-manpages repositories.
+
+ - Handle the remaining patches:
+
+   - Anything unobvious that is applicable to 'master' (in other
+     words, does not depend on anything that is still in 'next'
+     and not in 'master') is applied to a new topic branch that
+     is forked from the tip of 'master' (or the last feature release,
+     which is a bit older than 'master').  This includes both
+     enhancements and unobvious fixes to 'master'.  A topic
+     branch is named as ai/topic where "ai" is two-letter string
+     named after author's initial and "topic" is a descriptive name
+     of the topic (in other words, "what's the series is about").
+
+   - An unobvious fix meant for 'maint' is applied to a new
+     topic branch that is forked from the tip of 'maint' (or the
+     oldest and still relevant maintenance branch).  The
+     topic may be named as ai/maint-topic.
+
+   - Changes that pertain to an existing topic are applied to
+     the branch, but:
+
+     - obviously correct ones are applied first;
+
+     - questionable ones are discarded or applied to near the tip;
+
+   - Replacement patches to an existing topic are accepted only
+     for commits not in 'next'.
+
+   The initial round is done with:
+
+     $ git checkout ai/topic ;# or "git checkout -b ai/topic master"
+     $ git am -sc3 --whitespace=warn mailbox
+
+   and replacing an existing topic with subsequent round is done with:
+
+     $ git checkout master...ai/topic ;# try to reapply to the same base
+     $ git am -sc3 --whitespace=warn mailbox
+
+   to prepare the new round on a detached HEAD, and then
+
+     $ git range-diff @{-1}...
+     $ git diff @{-1}
+
+   to double check what changed since the last round, and finally
+
+     $ git checkout -B @{-1}
+
+   to conclude (the last step is why a topic already in 'next' is
+   not replaced but updated incrementally).
+
+   Whether it is the initial round or a subsequent round, the topic
+   may not build even in isolation, or may break the build when
+   merged to integration branches due to bugs.  There may already
+   be obvious and trivial improvements suggested on the list.  The
+   maintainer often adds an extra commit, with "SQUASH???" in its
+   title, to fix things up, before publishing the integration
+   branches to make it usable by other developers for testing.
+   These changes are what the maintainer is not 100% committed to
+   (trivial typofixes etc. are often squashed directly into the
+   patches that need fixing, without being applied as a separate
+   "SQUASH???" commit), so that they can be removed easily as needed.
+   The expectation is that the original author will make corrections
+   in a reroll.
+
+ - By now, new topic branches are created and existing topic
+   branches are updated.  The integration branches 'next', 'jch',
+   and 'seen' need to be updated to contain them.
+
+ - If there are topics that have been merged to 'master' and should
+   be merged to 'maint', merge them to 'maint', and update the
+   release notes to the next maintenance release.
+
+ - Review the latest issue of "What's cooking" again.  Are topics
+   that have been sufficiently long in 'next' ready to be merged to
+   'master'?  Are topics we saw earlier and are in 'seen' now got
+   positive reviews and are ready to be merged to 'next'?
+
+ - If there are topics that have been cooking in 'next' long enough
+   and should be merged to 'master', merge them to 'master', and
+   update the release notes to the next feature release.
+
+ - If there were patches directly made on 'maint', merge 'maint' to
+   'master'; make sure that the result is what you want.
+
+     $ git checkout master
+     $ git merge -m "Sync with 'maint'" --no-log maint
+     $ git log -p --first-parent ORIG_HEAD..
+     $ make test
+
+ - Prepare to update the 'jch' branch, which is used to represent
+   somewhere between 'master' and 'seen' and often is slightly ahead
+   of 'next', and the 'seen' branch, which is used to hold the rest.
+
+     $ Meta/Reintegrate master..jch >Meta/redo-jch.sh
+
+   The result is a script that lists topics to be merged in order to
+   rebuild the current 'jch'.  Do the same for 'seen'.
+
+ - Review the Meta/redo-jch.sh and Meta/redo-seen.sh scripts.  The
+   former should have a line '### match next'---the idea is that
+   merging the topics listed before the line on top of 'master'
+   should result in a tree identical to that of 'next'.
+
+ - As newly created topics are usually merged near the tip of
+   'seen', add them to the end of the Meta/redo-seen.sh script.
+   Among the topics that were in 'seen', there may be ones that
+   are not quite ready for 'next' but are getting there.  Move
+   them from Meta/redo-seen.sh to the end of Meta/redo-jch.sh.
+   The expectation is that you'd use 'jch' as your daily driver
+   as the first guinea pig, so you should choose carefully.
+
+ - Now we are ready to start rebuilding 'jch' and merging topics to
+   'next'.  For each branch whose tip is not merged to 'next', one
+   of three things can happen:
+
+   - The commits are all next-worthy; merge the topic to next;
+   - The new parts are of mixed quality, but earlier ones are
+     next-worthy; merge the early parts to next;
+   - Nothing is next-worthy; do not do anything.
+
+   This step is aided with Meta/redo-jch.sh script created earlier.
+   If a topic that was already in 'next' gained a patch, the script
+   would list it as "ai/topic~1".  To include the new patch to the
+   updated 'next', drop the "~1" part; to keep it excluded, do not
+   touch the line.
+
+   If a topic that was not in 'next' should be merged to 'next', add
+   it before the '### match next' line.  Then:
+
+     $ git checkout --detach master
+     $ sh Meta/redo-jch.sh -c1
+
+   to rebuild the 'jch' branch from scratch.  "-c1" tells the script
+   to stop merging at the first line that begins with '###'
+   (i.e. the "### match next" line you added earlier).
+
+   At this point, build-test the result.  It may reveal semantic
+   conflicts (e.g. a topic renamed a variable, another added a new
+   reference to the variable under its old name), in which case
+   prepare an appropriate merge-fix first (see appendix), and
+   rebuild the 'jch' branch from scratch, starting at the tip of
+   'master', this time without using "-c1" to merge all topics.
+
+   Then do the same to 'next'.
+
+     $ git checkout next
+     $ sh Meta/redo-jch.sh -c1 -e
+
+   The "-e" option allows the merge message that comes from the
+   history of the topic and the comments in the "What's cooking" to
+   be edited.  The resulting tree should match 'jch^{/^### match next'}'
+   as the same set of topics are merged on 'master'; otherwise there
+   is a mismerge. Investigate why and do not proceed until the mismerge
+   is found and rectified.
+
+   If 'master' was updated before you started redoing 'next', then
+
+     $ git diff 'jch^{/^### match next}' next
+
+   would show differences that went into 'master' (which 'jch' has,
+   but 'next' does not yet---often it is updates to the release
+   notes).  Merge 'master' back to 'next' if that is the case.
+
+     $ git merge -m "Sync with 'master'" --no-log master
+
+   When all is well, clean up the redo-jch.sh script with
+
+     $ sh Meta/redo-jch.sh -u
+
+   This removes topics listed in the script that have already been
+   merged to 'master'.  This may lose '### match next' marker;
+   add it again to the appropriate place when it happens.
+
+ - Rebuild 'seen' on top of 'jch'.
+
+     $ git checkout -B seen jch
+     $ sh Meta/redo-seen.sh
+
+   When all is well, clean up the redo-seen.sh script with
+
+     $ sh Meta/redo-seen.sh -u
+
+   Double check by running
+
+     $ git branch --no-merged seen '??/*'
+
+   to see there is no unexpected leftover topics.
+
+   At this point, build-test the result for semantic conflicts, and
+   if there are, prepare an appropriate merge-fix first (see
+   appendix), and rebuild the 'seen' branch from scratch, starting at
+   the tip of 'jch'.
+
+ - Update "What's cooking" message to review the updates to
+   existing topics, newly added topics and graduated topics.
+
+   This step is helped with Meta/cook script.
+
+     $ Meta/cook
+
+   This script inspects the history between master..seen, finds tips
+   of topic branches, compares what it found with the current
+   contents in Meta/whats-cooking.txt, and updates that file.
+   Topics not listed in the file but are found in master..seen are
+   added to the "New topics" section, topics listed in the file that
+   are no longer found in master..seen are moved to the "Graduated to
+   master" section, and topics whose commits changed their states
+   (e.g. used to be only in 'seen', now merged to 'next') are updated
+   with change markers "<<" and ">>".
+
+   Look for lines enclosed in "<<" and ">>"; they hold contents from
+   old file that are replaced by this integration round.  After
+   verifying them, remove the old part.  Review the description for
+   each topic and update its doneness and plan as needed.  To review
+   the updated plan, run
+
+     $ Meta/cook -w
+
+   which will pick up comments given to the topics, such as "Will
+   merge to 'next'", etc. (see Meta/cook script to learn what kind
+   of phrases are supported).
+
+ - Compile, test and install all four (five) integration branches;
+   Meta/Dothem script may aid this step.
+
+ - Format documentation if the 'master' branch was updated;
+   Meta/dodoc.sh script may aid this step.
+
+ - Push the integration branches out to public places; Meta/pushall
+   script may aid this step.
+
+Observations
+------------
+
+Some observations to be made.
+
+ * Each topic is tested individually, and also together with other
+   topics cooking first in 'seen', then in 'jch' and then in 'next'.
+   Until it matures, no part of it is merged to 'master'.
+
+ * A topic already in 'next' can get fixes while still in
+   'next'.  Such a topic will have many merges to 'next' (in
+   other words, "git log --first-parent next" will show many
+   "Merge branch 'ai/topic' to next" for the same topic.
+
+ * An unobvious fix for 'maint' is cooked in 'next' and then
+   merged to 'master' to make extra sure it is Ok and then
+   merged to 'maint'.
+
+ * Even when 'next' becomes empty (in other words, all topics
+   prove stable and are merged to 'master' and "git diff master
+   next" shows empty), it has tons of merge commits that will
+   never be in 'master'.
+
+ * In principle, "git log --first-parent master..next" should
+   show nothing but merges (in practice, there are fixup commits
+   and reverts that are not merges).
+
+ * Commits near the tip of a topic branch that are not in 'next'
+   are fair game to be discarded, replaced or rewritten.
+   Commits already merged to 'next' will not be.
+
+ * Being in the 'next' branch is not a guarantee for a topic to
+   be included in the next feature release.  Being in the
+   'master' branch typically is.
+
+ * Due to the nature of "SQUASH???" fix-ups, if the original author
+   agrees with the suggested changes, it is OK to squash them to
+   appropriate patches in the next round (when the suggested change
+   is small enough, the author should not even bother with
+   "Helped-by").  It is also OK to drop them from the next round
+   when the original author does not agree with the suggestion, but
+   the author is expected to say why somewhere in the discussion.
+
+
+Appendix
+--------
+
+Preparing a "merge-fix"
+~~~~~~~~~~~~~~~~~~~~~~~
+
+A merge of two topics may not textually conflict but still have
+conflict at the semantic level. A classic example is for one topic
+to rename a variable and all its uses, while another topic adds a
+new use of the variable under its old name. When these two topics
+are merged together, the reference to the variable newly added by
+the latter topic will still use the old name in the result.
+
+The Meta/Reintegrate script that is used by redo-jch and redo-seen
+scripts implements a crude but usable way to work around this issue.
+When the script merges branch $X, it checks if "refs/merge-fix/$X"
+exists, and if so, the effect of it is squashed into the result of
+the mechanical merge.  In other words,
+
+     $ echo $X | Meta/Reintegrate
+
+is roughly equivalent to this sequence:
+
+     $ git merge --rerere-autoupdate $X
+     $ git commit
+     $ git cherry-pick -n refs/merge-fix/$X
+     $ git commit --amend
+
+The goal of this "prepare a merge-fix" step is to come up with a
+commit that can be squashed into a result of mechanical merge to
+correct semantic conflicts.
+
+After finding that the result of merging branch "ai/topic" to an
+integration branch had such a semantic conflict, say seen~4, check the
+problematic merge out on a detached HEAD, edit the working tree to
+fix the semantic conflict, and make a separate commit to record the
+fix-up:
+
+     $ git checkout seen~4
+     $ git show -s --pretty=%s ;# double check
+     Merge branch 'ai/topic' to seen
+     $ edit
+     $ git commit -m 'merge-fix/ai/topic' -a
+
+Then make a reference "refs/merge-fix/ai/topic" to point at this
+result:
+
+     $ git update-ref refs/merge-fix/ai/topic HEAD
+
+Then double check the result by asking Meta/Reintegrate to redo the
+merge:
+
+     $ git checkout seen~5 ;# the parent of the problem merge
+     $ echo ai/topic | Meta/Reintegrate
+     $ git diff seen~4
+
+This time, because you prepared refs/merge-fix/ai/topic, the
+resulting merge should have been tweaked to include the fix for the
+semantic conflict.
+
+Note that this assumes that the order in which conflicting branches
+are merged does not change.  If the reason why merging ai/topic
+branch needs this merge-fix is because another branch merged earlier
+to the integration branch changed the underlying assumption ai/topic
+branch made (e.g. ai/topic branch added a site to refer to a
+variable, while the other branch renamed that variable and adjusted
+existing use sites), and if you changed redo-jch (or redo-seen) script
+to merge ai/topic branch before the other branch, then the above
+merge-fix should not be applied while merging ai/topic, but should
+instead be applied while merging the other branch.  You would need
+to move the fix to apply to the other branch, perhaps like this:
+
+      $ mf=refs/merge-fix
+      $ git update-ref $mf/$the_other_branch $mf/ai/topic
+      $ git update-ref -d $mf/ai/topic
diff --git a/Documentation/howto/meson.build b/Documentation/howto/meson.build
new file mode 100644
index 0000000000..961e053362
--- /dev/null
+++ b/Documentation/howto/meson.build
@@ -0,0 +1,62 @@
+howto_sources = [
+  'coordinate-embargoed-releases.adoc',
+  'keep-canonical-history-correct.adoc',
+  'maintain-git.adoc',
+  'new-command.adoc',
+  'rebase-from-internal-branch.adoc',
+  'rebuild-from-update-hook.adoc',
+  'recover-corrupted-blob-object.adoc',
+  'recover-corrupted-object-harder.adoc',
+  'revert-a-faulty-merge.adoc',
+  'revert-branch-rebase.adoc',
+  'separating-topic-branches.adoc',
+  'setup-git-server-over-http.adoc',
+  'update-hook-example.adoc',
+  'use-git-daemon.adoc',
+  'using-merge-subtree.adoc',
+  'using-signed-tag-in-pull-request.adoc',
+]
+
+howto_index = custom_target(
+  command: [
+    shell,
+    meson.current_source_dir() / 'howto-index.sh',
+    '@INPUT@',
+  ],
+  env: script_environment,
+  capture: true,
+  input: howto_sources,
+  output: 'howto-index.adoc',
+)
+
+custom_target(
+  command: asciidoc_html_options,
+  input: howto_index,
+  output: 'howto-index.html',
+  depends: documentation_deps,
+  install: true,
+  install_dir: get_option('datadir') / 'doc/git-doc',
+)
+
+foreach howto : howto_sources
+  howto_stripped = custom_target(
+    command: [
+      find_program('sed'),
+      '-e',
+      '1,/^$/d',
+      '@INPUT@',
+    ],
+    input: howto,
+    output: fs.stem(howto) + '.stripped',
+    capture: true,
+  )
+
+  custom_target(
+    command: asciidoc_html_options,
+    input: howto_stripped,
+    output: fs.stem(howto_stripped.full_path()) + '.html',
+    depends: documentation_deps,
+    install: true,
+    install_dir: get_option('datadir') / 'doc/git-doc/howto',
+  )
+endforeach
diff --git a/Documentation/howto/new-command.adoc b/Documentation/howto/new-command.adoc
new file mode 100644
index 0000000000..880c51112b
--- /dev/null
+++ b/Documentation/howto/new-command.adoc
@@ -0,0 +1,106 @@
+From: Eric S. Raymond <esr@xxxxxxxxxxx>
+Abstract: This is how-to documentation for people who want to add extension
+ commands to Git.  It should be read alongside builtin.h.
+Content-type: text/asciidoc
+
+How to integrate new subcommands
+================================
+
+This is how-to documentation for people who want to add extension
+commands to Git.  It should be read alongside builtin.h.
+
+Runtime environment
+-------------------
+
+Git subcommands are standalone executables that live in the Git exec
+path, normally /usr/lib/git-core.  The git executable itself is a
+thin wrapper that knows where the subcommands live, and runs them by
+passing command-line arguments to them.
+
+(If "git foo" is not found in the Git exec path, the wrapper
+will look in the rest of your $PATH for it.  Thus, it's possible
+to write local Git extensions that don't live in system space.)
+
+Implementation languages
+------------------------
+
+Most subcommands are written in C or shell.  A few are written in
+Perl.
+
+While we strongly encourage coding in portable C for portability,
+these specific scripting languages are also acceptable.  We won't
+accept more without a very strong technical case, as we don't want
+to broaden the Git suite's required dependencies.  Import utilities,
+surgical tools, remote helpers and other code at the edges of the
+Git suite are more lenient and we allow Python (and even Tcl/tk),
+but they should not be used for core functions.
+
+This may change in the future.  Especially Python is not allowed in
+core because we need better Python integration in the Git Windows
+installer before we can be confident people in that environment
+won't experience an unacceptably large loss of capability.
+
+C commands are normally written as single modules, named after the
+command, that link a collection of functions called libgit.  Thus,
+your command 'git-foo' would normally be implemented as a single
+"git-foo.c" (or "builtin/foo.c" if it is to be linked to the main
+binary); this organization makes it easy for people reading the code
+to find things.
+
+See the CodingGuidelines document for other guidance on what we consider
+good practice in C and shell, and api-builtin.txt for the support
+functions available to built-in commands written in C.
+
+What every extension command needs
+----------------------------------
+
+You must have a man page, written in asciidoc (this is what Git help
+followed by your subcommand name will display).  Be aware that there is
+a local asciidoc configuration and macros which you should use.  It's
+often helpful to start by cloning an existing page and replacing the
+text content.
+
+You must have a test, written to report in TAP (Test Anything Protocol).
+Tests are executables (usually shell scripts) that live in the 't'
+subdirectory of the tree.  Each test name begins with 't' and a sequence
+number that controls where in the test sequence it will be executed;
+conventionally the rest of the name stem is that of the command
+being tested.
+
+Read the file t/README to learn more about the conventions to be used
+in writing tests, and the test support library.
+
+Integrating a command
+---------------------
+
+Here are the things you need to do when you want to merge a new
+subcommand into the Git tree.
+
+1. Don't forget to sign off your patch!
+
+2. Append your command name to one of the variables BUILTIN_OBJS,
+EXTRA_PROGRAMS, SCRIPT_SH, SCRIPT_PERL or SCRIPT_PYTHON.
+
+3. Drop its test in the t directory.
+
+4. If your command is implemented in an interpreted language with a
+p-code intermediate form, make sure .gitignore in the main directory
+includes a pattern entry that ignores such files.  Python .pyc and
+.pyo files will already be covered.
+
+5. If your command has any dependency on a particular version of
+your language, document it in the INSTALL file.
+
+6. There is a file command-list.txt in the distribution main directory
+that categorizes commands by type, so they can be listed in appropriate
+subsections in the documentation's summary command list.  Add an entry
+for yours.  To understand the categories, look at command-list.txt
+in the main directory.  If the new command is part of the typical Git
+workflow and you believe it common enough to be mentioned in 'git help',
+map this command to a common group in the column [common].
+
+7. Give the maintainer one paragraph to include in the RelNotes file
+to describe the new feature; a good place to do so is in the cover
+letter [PATCH 0/n].
+
+That's all there is to it.
diff --git a/Documentation/howto/rebase-from-internal-branch.adoc b/Documentation/howto/rebase-from-internal-branch.adoc
new file mode 100644
index 0000000000..f2e10a7ec8
--- /dev/null
+++ b/Documentation/howto/rebase-from-internal-branch.adoc
@@ -0,0 +1,164 @@
+From:	Junio C Hamano <gitster@xxxxxxxxx>
+To:	git@xxxxxxxxxxxxxxx
+Cc:	Petr Baudis <pasky@xxxxxxx>, Linus Torvalds <torvalds@xxxxxxxx>
+Subject: Re: sending changesets from the middle of a git tree
+Date:	Sun, 14 Aug 2005 18:37:39 -0700
+Abstract: In this article, JC talks about how he rebases the
+ public "seen" branch using the core Git tools when he updates
+ the "master" branch, and how "rebase" works.  Also discussed
+ is how this applies to individual developers who sends patches
+ upstream.
+Content-type: text/asciidoc
+
+How to rebase from an internal branch
+=====================================
+
+--------------------------------------
+Petr Baudis <pasky@xxxxxxx> writes:
+
+> Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter
+> where Junio C Hamano <junkio@xxxxxxx> told me that...
+>> Linus Torvalds <torvalds@xxxxxxxx> writes:
+>>
+>> > Junio, maybe you want to talk about how you move patches from your
+>> > "seen" branch to the real branches.
+>>
+> Actually, wouldn't this be also precisely for what StGIT is intended to?
+--------------------------------------
+
+Exactly my feeling.  I was sort of waiting for Catalin to speak
+up.  With its basing philosophical ancestry on quilt, this is
+the kind of task StGIT is designed to do.
+
+I just have done a simpler one, this time using only the core
+Git tools.
+
+I had a handful of commits that were ahead of master in 'seen', and I
+wanted to add some documentation bypassing my usual habit of
+placing new things in 'seen' first.  At the beginning, the commit
+ancestry graph looked like this:
+
+			     *"seen" head
+    master --> #1 --> #2 --> #3
+
+So I started from master, made a bunch of edits, and committed:
+
+    $ git checkout master
+    $ cd Documentation; ed git.txt ...
+    $ cd ..; git add Documentation/*.txt
+    $ git commit -s
+
+After the commit, the ancestry graph would look like this:
+
+			      *"seen" head
+    master^ --> #1 --> #2 --> #3
+          \
+            \---> master
+
+The old master is now master^ (the first parent of the master).
+The new master commit holds my documentation updates.
+
+Now I have to deal with "seen" branch.
+
+This is the kind of situation I used to have all the time when
+Linus was the maintainer and I was a contributor, when you look
+at "master" branch being the "maintainer" branch, and "seen"
+branch being the "contributor" branch.  Your work started at the
+tip of the "maintainer" branch some time ago, you made a lot of
+progress in the meantime, and now the maintainer branch has some
+other commits you do not have yet.  And "git rebase" was written
+with the explicit purpose of helping to maintain branches like
+"seen".  You _could_ merge master to 'seen' and keep going, but if you
+eventually want to cherrypick and merge some but not necessarily
+all changes back to the master branch, it often makes later
+operations for _you_ easier if you rebase (i.e. carry forward
+your changes) "seen" rather than merge.  So I ran "git rebase":
+
+    $ git checkout seen
+    $ git rebase master seen
+
+What this does is to pick all the commits since the current
+branch (note that I now am on "seen" branch) forked from the
+master branch, and forward port these changes.
+
+    master^ --> #1 --> #2 --> #3
+	  \                                  *"seen" head
+            \---> master --> #1' --> #2' --> #3'
+
+The diff between master^ and #1 is applied to master and
+committed to create #1' commit with the commit information (log,
+author and date) taken from commit #1.  On top of that #2' and #3'
+commits are made similarly out of #2 and #3 commits.
+
+Old #3 is not recorded in any of the .git/refs/heads/ file
+anymore, so after doing this you will have dangling commit if
+you ran fsck-cache, which is normal.  After testing "seen", you
+can run "git prune" to get rid of those original three commits.
+
+While I am talking about "git rebase", I should talk about how
+to do cherrypicking using only the core Git tools.
+
+Let's go back to the earlier picture, with different labels.
+
+You, as an individual developer, cloned upstream repository and
+made a couple of commits on top of it.
+
+                              *your "master" head
+   upstream --> #1 --> #2 --> #3
+
+You would want changes #2 and #3 incorporated in the upstream,
+while you feel that #1 may need further improvements.  So you
+prepare #2 and #3 for e-mail submission.
+
+    $ git format-patch master^^ master
+
+This creates two files, 0001-XXXX.patch and 0002-XXXX.patch.  Send
+them out "To: " your project maintainer and "Cc: " your mailing
+list.  You could use contributed script git-send-email if
+your host has necessary perl modules for this, but your usual
+MUA would do as long as it does not corrupt whitespaces in the
+patch.
+
+Then you would wait, and you find out that the upstream picked
+up your changes, along with other changes.
+
+   where                      *your "master" head
+  upstream --> #1 --> #2 --> #3
+    used   \
+   to be     \--> #A --> #2' --> #3' --> #B --> #C
+                                                *upstream head
+
+The two commits #2' and #3' in the above picture record the same
+changes your e-mail submission for #2 and #3 contained, but
+probably with the new sign-off line added by the upstream
+maintainer and definitely with different committer and ancestry
+information, they are different objects from #2 and #3 commits.
+
+You fetch from upstream, but not merge.
+
+    $ git fetch upstream
+
+This leaves the updated upstream head in .git/FETCH_HEAD but
+does not touch your .git/HEAD or .git/refs/heads/master.
+You run "git rebase" now.
+
+    $ git rebase FETCH_HEAD master
+
+Earlier, I said that rebase applies all the commits from your
+branch on top of the upstream head.  Well, I lied.  "git rebase"
+is a bit smarter than that and notices that #2 and #3 need not
+be applied, so it only applies #1.  The commit ancestry graph
+becomes something like this:
+
+   where                     *your old "master" head
+  upstream --> #1 --> #2 --> #3
+    used   \                      your new "master" head*
+   to be     \--> #A --> #2' --> #3' --> #B --> #C --> #1'
+                                                *upstream
+                                                head
+
+Again, "git prune" would discard the disused commits #1-#3 and
+you continue on starting from the new "master" head, which is
+the #1' commit.
+
+-jc
diff --git a/Documentation/howto/rebuild-from-update-hook.adoc b/Documentation/howto/rebuild-from-update-hook.adoc
new file mode 100644
index 0000000000..db219f5c07
--- /dev/null
+++ b/Documentation/howto/rebuild-from-update-hook.adoc
@@ -0,0 +1,90 @@
+Subject: [HOWTO] Using post-update hook
+Message-ID: <7vy86o6usx.fsf@xxxxxxxxxxxxxxxxxxxxxxxx>
+From: Junio C Hamano <gitster@xxxxxxxxx>
+Date: Fri, 26 Aug 2005 18:19:10 -0700
+Abstract: In this how-to article, JC talks about how he
+ uses the post-update hook to automate Git documentation page
+ shown at https://www.kernel.org/pub/software/scm/git/docs/.
+Content-type: text/asciidoc
+
+How to rebuild from update hook
+===============================
+
+The pages under https://www.kernel.org/pub/software/scm/git/docs/
+are built from Documentation/ directory of the git.git project
+and needed to be kept up-to-date.  The www.kernel.org/ servers
+are mirrored and I was told that the origin of the mirror is on
+the machine $some.kernel.org, on which I was given an account
+when I took over Git maintainership from Linus.
+
+The directories relevant to this how-to are these two:
+
+    /pub/scm/git/git.git/	The public Git repository.
+    /pub/software/scm/git/docs/	The HTML documentation page.
+
+So I made a repository to generate the documentation under my
+home directory over there.
+
+    $ cd
+    $ mkdir doc-git && cd doc-git
+    $ git clone /pub/scm/git/git.git/ docgen
+
+What needs to happen is to update the $HOME/doc-git/docgen/
+working tree, build HTML docs there and install the result in
+/pub/software/scm/git/docs/ directory.  So I wrote a little
+script:
+
+    $ cat >dododoc.sh <<\EOF
+    #!/bin/sh
+    cd $HOME/doc-git/docgen || exit
+
+    unset GIT_DIR
+
+    git pull /pub/scm/git/git.git/ master &&
+    cd Documentation &&
+    make install-webdoc
+    EOF
+
+Initially I used to run this by hand whenever I push into the
+public Git repository.  Then I did a cron job that ran twice a
+day.  The current round uses the post-update hook mechanism,
+like this:
+
+    $ cat >/pub/scm/git/git.git/hooks/post-update <<\EOF
+    #!/bin/sh
+    #
+    # An example hook script to prepare a packed repository for use over
+    # dumb transports.
+    #
+    # To enable this hook, make this file executable by "chmod +x post-update".
+
+    case " $* " in
+    *' refs/heads/master '*)
+            echo $HOME/doc-git/dododoc.sh | at now
+            ;;
+    esac
+    exec git-update-server-info
+    EOF
+    $ chmod +x /pub/scm/git/git.git/hooks/post-update
+
+There are four things worth mentioning:
+
+ - The update-hook is run after the repository accepts a "git
+   push", under my user privilege.  It is given the full names
+   of refs that have been updated as arguments.  My post-update
+   runs the dododoc.sh script only when the master head is
+   updated.
+
+ - When update-hook is run, GIT_DIR is set to '.' by the calling
+   receive-pack.  This is inherited by the dododoc.sh run via
+   the "at" command, and needs to be unset; otherwise, "git
+   pull" it does into $HOME/doc-git/docgen/ repository would not
+   work correctly.
+
+ - The stdout of update hook script is not connected to git
+   push; I run the heavy part of the command inside "at", to
+   receive the execution report via e-mail.
+
+ - This is still crude and does not protect against simultaneous
+   make invocations stomping on each other.  I would need to add
+   some locking mechanism for this.
diff --git a/Documentation/howto/recover-corrupted-blob-object.adoc b/Documentation/howto/recover-corrupted-blob-object.adoc
new file mode 100644
index 0000000000..1b3b188d3c
--- /dev/null
+++ b/Documentation/howto/recover-corrupted-blob-object.adoc
@@ -0,0 +1,144 @@
+Date: Fri, 9 Nov 2007 08:28:38 -0800 (PST)
+From: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>
+Subject: corrupt object on git-gc
+Abstract: Some tricks to reconstruct blob objects in order to fix
+ a corrupted repository.
+Content-type: text/asciidoc
+
+How to recover a corrupted blob object
+======================================
+
+-----------------------------------------------------------
+On Fri, 9 Nov 2007, Yossi Leybovich wrote:
+>
+> Did not help still the repository look for this object?
+> Any one know how can I track this object and understand which file is it
+-----------------------------------------------------------
+
+So exactly *because* the SHA-1 hash is cryptographically secure, the hash
+itself doesn't actually tell you anything, in order to fix a corrupt
+object you basically have to find the "original source" for it.
+
+The easiest way to do that is almost always to have backups, and find the
+same object somewhere else. Backups really are a good idea, and Git makes
+it pretty easy (if nothing else, just clone the repository somewhere else,
+and make sure that you do *not* use a hard-linked clone, and preferably
+not the same disk/machine).
+
+But since you don't seem to have backups right now, the good news is that
+especially with a single blob being corrupt, these things *are* somewhat
+debuggable.
+
+First off, move the corrupt object away, and *save* it. The most common
+cause of corruption so far has been memory corruption, but even so, there
+are people who would be interested in seeing the corruption - but it's
+basically impossible to judge the corruption until we can also see the
+original object, so right now the corrupt object is useless, but it's very
+interesting for the future, in the hope that you can re-create a
+non-corrupt version.
+
+-----------------------------------------------------------
+So:
+
+> ib]$ mv .git/objects/4b/9458b3786228369c63936db65827de3cc06200 ../
+-----------------------------------------------------------
+
+This is the right thing to do, although it's usually best to save it under
+it's full SHA-1 name (you just dropped the "4b" from the result ;).
+
+Let's see what that tells us:
+
+-----------------------------------------------------------
+> ib]$ git-fsck --full
+> broken link from    tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
+>              to    blob 4b9458b3786228369c63936db65827de3cc06200
+> missing blob 4b9458b3786228369c63936db65827de3cc06200
+-----------------------------------------------------------
+
+Ok, I removed the "dangling commit" messages, because they are just
+messages about the fact that you probably have rebased etc, so they're not
+at all interesting. But what remains is still very useful. In particular,
+we now know which tree points to it!
+
+Now you can do
+
+	git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
+
+which will show something like
+
+	100644 blob 8d14531846b95bfa3564b58ccfb7913a034323b8    .gitignore
+	100644 blob ebf9bf84da0aab5ed944264a5db2a65fe3a3e883    .mailmap
+	100644 blob ca442d313d86dc67e0a2e5d584b465bd382cbf5c    COPYING
+	100644 blob ee909f2cc49e54f0799a4739d24c4cb9151ae453    CREDITS
+	040000 tree 0f5f709c17ad89e72bdbbef6ea221c69807009f6    Documentation
+	100644 blob 1570d248ad9237e4fa6e4d079336b9da62d9ba32    Kbuild
+	100644 blob 1c7c229a092665b11cd46a25dbd40feeb31661d9    MAINTAINERS
+	...
+
+and you should now have a line that looks like
+
+	10064 blob 4b9458b3786228369c63936db65827de3cc06200	my-magic-file
+
+in the output. This already tells you a *lot* it tells you what file the
+corrupt blob came from!
+
+Now, it doesn't tell you quite enough, though: it doesn't tell what
+*version* of the file didn't get correctly written! You might be really
+lucky, and it may be the version that you already have checked out in your
+working tree, in which case fixing this problem is really simple, just do
+
+	git hash-object -w my-magic-file
+
+again, and if it outputs the missing SHA-1 (4b945..) you're now all done!
+
+But that's the really lucky case, so let's assume that it was some older
+version that was broken. How do you tell which version it was?
+
+The easiest way to do it is to do
+
+	git log --raw --all --full-history -- subdirectory/my-magic-file
+
+and that will show you the whole log for that file (please realize that
+the tree you had may not be the top-level tree, so you need to figure out
+which subdirectory it was in on your own), and because you're asking for
+raw output, you'll now get something like
+
+	commit abc
+	Author:
+	Date:
+	  ..
+	:100644 100644 4b9458b... newsha... M  somedirectory/my-magic-file
+
+
+	commit xyz
+	Author:
+	Date:
+
+	  ..
+	:100644 100644 oldsha... 4b9458b... M	somedirectory/my-magic-file
+
+and this actually tells you what the *previous* and *subsequent* versions
+of that file were! So now you can look at those ("oldsha" and "newsha"
+respectively), and hopefully you have done commits often, and can
+re-create the missing my-magic-file version by looking at those older and
+newer versions!
+
+If you can do that, you can now recreate the missing object with
+
+	git hash-object -w <recreated-file>
+
+and your repository is good again!
+
+(Btw, you could have ignored the fsck, and started with doing a
+
+	git log --raw --all
+
+and just looked for the sha of the missing object (4b9458b..) in that
+whole thing. It's up to you - Git does *have* a lot of information, it is
+just missing one particular blob version.
+
+Trying to recreate trees and especially commits is *much* harder. So you
+were lucky that it's a blob. It's quite possible that you can recreate the
+thing.
+
+			Linus
diff --git a/Documentation/howto/recover-corrupted-object-harder.adoc b/Documentation/howto/recover-corrupted-object-harder.adoc
new file mode 100644
index 0000000000..5efb4fe81f
--- /dev/null
+++ b/Documentation/howto/recover-corrupted-object-harder.adoc
@@ -0,0 +1,479 @@
+Date: Wed, 16 Oct 2013 04:34:01 -0400
+From: Jeff King <peff@xxxxxxxx>
+Subject: pack corruption post-mortem
+Abstract: Recovering a corrupted object when no good copy is available.
+Content-type: text/asciidoc
+
+How to recover an object from scratch
+=====================================
+
+I was recently presented with a repository with a corrupted packfile,
+and was asked if the data was recoverable. This post-mortem describes
+the steps I took to investigate and fix the problem. I thought others
+might find the process interesting, and it might help somebody in the
+same situation.
+
+********************************
+Note: In this case, no good copy of the repository was available. For
+the much easier case where you can get the corrupted object from
+elsewhere, see link:recover-corrupted-blob-object.html[this howto].
+********************************
+
+I started with an fsck, which found a problem with exactly one object
+(I've used $pack and $obj below to keep the output readable, and also
+because I'll refer to them later):
+
+-----------
+    $ git fsck
+    error: $pack SHA1 checksum mismatch
+    error: index CRC mismatch for object $obj from $pack at offset 51653873
+    error: inflate: data stream error (incorrect data check)
+    error: cannot unpack $obj from $pack at offset 51653873
+-----------
+
+The pack checksum failing means a byte is munged somewhere, and it is
+presumably in the object mentioned (since both the index checksum and
+zlib were failing).
+
+Reading the zlib source code, I found that "incorrect data check" means
+that the adler-32 checksum at the end of the zlib data did not match the
+inflated data. So stepping the data through zlib would not help, as it
+did not fail until the very end, when we realize the CRC does not match.
+The problematic bytes could be anywhere in the object data.
+
+The first thing I did was pull the broken data out of the packfile. I
+needed to know how big the object was, which I found out with:
+
+------------
+    $ git show-index <$idx | cut -d' ' -f1 | sort -n | grep -A1 51653873
+    51653873
+    51664736
+------------
+
+Show-index gives us the list of objects and their offsets. We throw away
+everything but the offsets, and then sort them so that our interesting
+offset (which we got from the fsck output above) is followed immediately
+by the offset of the next object. Now we know that the object data is
+10863 bytes long, and we can grab it with:
+
+------------
+  dd if=$pack of=object bs=1 skip=51653873 count=10863
+------------
+
+I inspected a hexdump of the data, looking for any obvious bogosity
+(e.g., a 4K run of zeroes would be a good sign of filesystem
+corruption). But everything looked pretty reasonable.
+
+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
+linkgit:gitformat-pack[5]),
+or you can walk through it in a debugger. I did the latter, creating a
+valid pack like:
+
+------------
+    # pack magic and version
+    printf 'PACK\0\0\0\2' >tmp.pack
+    # pack has one object
+    printf '\0\0\0\1' >>tmp.pack
+    # now add our object data
+    cat object >>tmp.pack
+    # and then append the pack trailer
+    /path/to/git.git/t/helper/test-tool sha1 -b <tmp.pack >trailer
+    cat trailer >>tmp.pack
+------------
+
+and then running "git index-pack tmp.pack" in the debugger (stop at
+unpack_raw_entry). Doing this, I found that there were 3 bytes of header
+(and the header itself had a sane type and size). So I stripped those
+off with:
+
+------------
+    dd if=object of=zlib bs=1 skip=3
+------------
+
+I ran the result through zlib's inflate using a custom C program. And
+while it did report the error, I did get the right number of output
+bytes (i.e., it matched git's size header that we decoded above). But
+feeding the result back to "git hash-object" didn't produce the same
+sha1. So there were some wrong bytes, but I didn't know which. The file
+happened to be C source code, so I hoped I could notice something
+obviously wrong with it, but I didn't. I even got it to compile!
+
+I also tried comparing it to other versions of the same path in the
+repository, hoping that there would be some part of the diff that didn't
+make sense. Unfortunately, this happened to be the only revision of this
+particular file in the repository, so I had nothing to compare against.
+
+So I took a different approach. Working under the guess that the
+corruption was limited to a single byte, I wrote a program to munge each
+byte individually, and try inflating the result. Since the object was
+only 10K compressed, that worked out to about 2.5M attempts, which took
+a few minutes.
+
+The program I used is here:
+
+----------------------------------------------
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <zlib.h>
+
+static int try_zlib(unsigned char *buf, int len)
+{
+	/* make this absurdly large so we don't have to loop */
+	static unsigned char out[1024*1024];
+	z_stream z;
+	int ret;
+
+	memset(&z, 0, sizeof(z));
+	inflateInit(&z);
+
+	z.next_in = buf;
+	z.avail_in = len;
+	z.next_out = out;
+	z.avail_out = sizeof(out);
+
+	ret = inflate(&z, 0);
+	inflateEnd(&z);
+	return ret >= 0;
+}
+
+/* eye candy */
+static int counter = 0;
+static void progress(int sig)
+{
+	fprintf(stderr, "\r%d", counter);
+	alarm(1);
+}
+
+int main(void)
+{
+	/* oversized so we can read the whole buffer in */
+	unsigned char buf[1024*1024];
+	int len;
+	unsigned i, j;
+
+	signal(SIGALRM, progress);
+	alarm(1);
+
+	len = read(0, buf, sizeof(buf));
+	for (i = 0; i < len; i++) {
+		unsigned char c = buf[i];
+		for (j = 0; j <= 0xff; j++) {
+			buf[i] = j;
+
+			counter++;
+			if (try_zlib(buf, len))
+				printf("i=%d, j=%x\n", i, j);
+		}
+		buf[i] = c;
+	}
+
+	alarm(0);
+	fprintf(stderr, "\n");
+	return 0;
+}
+----------------------------------------------
+
+I compiled and ran with:
+
+-------
+  gcc -Wall -Werror -O3 munge.c -o munge -lz
+  ./munge <zlib
+-------
+
+
+There were a few false positives early on (if you write "no data" in the
+zlib header, zlib thinks it's just fine :) ). But I got a hit about
+halfway through:
+
+-------
+  i=5642, j=c7
+-------
+
+I let it run to completion, and got a few more hits at the end (where it
+was munging the CRC to match our broken data). So there was a good
+chance this middle hit was the source of the problem.
+
+I confirmed by tweaking the byte in a hex editor, zlib inflating the
+result (no errors!), and then piping the output into "git hash-object",
+which reported the sha1 of the broken object. Success!
+
+I fixed the packfile itself with:
+
+-------
+  chmod +w $pack
+  printf '\xc7' | dd of=$pack bs=1 seek=51659518 conv=notrunc
+  chmod -w $pack
+-------
+
+The `\xc7` comes from the replacement byte our "munge" program found.
+The offset 51659518 is derived by taking the original object offset
+(51653873), adding the replacement offset found by "munge" (5642), and
+then adding back in the 3 bytes of git header we stripped.
+
+After that, "git fsck" ran clean.
+
+As for the corruption itself, I was lucky that it was indeed a single
+byte. In fact, it turned out to be a single bit. The byte 0xc7 was
+corrupted to 0xc5. So presumably it was caused by faulty hardware, or a
+cosmic ray.
+
+And the aborted attempt to look at the inflated output to see what was
+wrong? I could have looked forever and never found it. Here's the diff
+between what the corrupted data inflates to, versus the real data:
+
+--------------
+  -       cp = strtok (arg, "+");
+  +       cp = strtok (arg, ".");
+--------------
+
+It tweaked one byte and still ended up as valid, readable C that just
+happened to do something totally different! One takeaway is that on a
+less unlucky day, looking at the zlib output might have actually been
+helpful, as most random changes would actually break the C code.
+
+But more importantly, git's hashing and checksumming noticed a problem
+that easily could have gone undetected in another system. The result
+still compiled, but would have caused an interesting bug (that would
+have been blamed on some random commit).
+
+
+The adventure continues...
+--------------------------
+
+I ended up doing this again! Same entity, new hardware. The assumption
+at this point is that the old disk corrupted the packfile, and then the
+corruption was migrated to the new hardware (because it was done by
+rsync or similar, and no fsck was done at the time of migration).
+
+This time, the affected blob was over 20 megabytes, which was far too
+large to do a brute-force on. I followed the instructions above to
+create the `zlib` file. I then used the `inflate` program below to pull
+the corrupted data from that. Examining that output gave me a hint about
+where in the file the corruption was. But now I was working with the
+file itself, not the zlib contents. So knowing the sha1 of the object
+and the approximate area of the corruption, I used the `sha1-munge`
+program below to brute-force the correct byte.
+
+Here's the inflate program (it's essentially `gunzip` but without the
+`.gz` header processing):
+
+--------------------------
+#include <stdio.h>
+#include <string.h>
+#include <zlib.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+	/*
+	 * oversized so we can read the whole buffer in;
+	 * this could actually be switched to streaming
+	 * to avoid any memory limitations
+	 */
+	static unsigned char buf[25 * 1024 * 1024];
+	static unsigned char out[25 * 1024 * 1024];
+	int len;
+	z_stream z;
+	int ret;
+
+	len = read(0, buf, sizeof(buf));
+	memset(&z, 0, sizeof(z));
+	inflateInit(&z);
+
+	z.next_in = buf;
+	z.avail_in = len;
+	z.next_out = out;
+	z.avail_out = sizeof(out);
+
+	ret = inflate(&z, 0);
+	if (ret != Z_OK && ret != Z_STREAM_END)
+		fprintf(stderr, "initial inflate failed (%d)\n", ret);
+
+	fprintf(stderr, "outputting %lu bytes", z.total_out);
+	fwrite(out, 1, z.total_out, stdout);
+	return 0;
+}
+--------------------------
+
+And here is the `sha1-munge` program:
+
+--------------------------
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <openssl/sha.h>
+#include <stdlib.h>
+
+/* eye candy */
+static int counter = 0;
+static void progress(int sig)
+{
+	fprintf(stderr, "\r%d", counter);
+	alarm(1);
+}
+
+static const signed char hexval_table[256] = {
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 00-07 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 08-0f */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 10-17 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 18-1f */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 20-27 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 28-2f */
+	  0,  1,  2,  3,  4,  5,  6,  7,		/* 30-37 */
+	  8,  9, -1, -1, -1, -1, -1, -1,		/* 38-3f */
+	 -1, 10, 11, 12, 13, 14, 15, -1,		/* 40-47 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 48-4f */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 50-57 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 58-5f */
+	 -1, 10, 11, 12, 13, 14, 15, -1,		/* 60-67 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 68-67 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 70-77 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 78-7f */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 80-87 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 88-8f */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 90-97 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* 98-9f */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* a0-a7 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* a8-af */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* b0-b7 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* b8-bf */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* c0-c7 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* c8-cf */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* d0-d7 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* d8-df */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* e0-e7 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* e8-ef */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* f0-f7 */
+	 -1, -1, -1, -1, -1, -1, -1, -1,		/* f8-ff */
+};
+
+static inline unsigned int hexval(unsigned char c)
+{
+return hexval_table[c];
+}
+
+static int get_sha1_hex(const char *hex, unsigned char *sha1)
+{
+	int i;
+	for (i = 0; i < 20; i++) {
+		unsigned int val;
+		/*
+		 * hex[1]=='\0' is caught when val is checked below,
+		 * but if hex[0] is NUL we have to avoid reading
+		 * past the end of the string:
+		 */
+		if (!hex[0])
+			return -1;
+		val = (hexval(hex[0]) << 4) | hexval(hex[1]);
+		if (val & ~0xff)
+			return -1;
+		*sha1++ = val;
+		hex += 2;
+	}
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	/* oversized so we can read the whole buffer in */
+	static unsigned char buf[25 * 1024 * 1024];
+	char header[32];
+	int header_len;
+	unsigned char have[20], want[20];
+	int start, len;
+	SHA_CTX orig;
+	unsigned i, j;
+
+	if (!argv[1] || get_sha1_hex(argv[1], want)) {
+		fprintf(stderr, "usage: sha1-munge <sha1> [start] <file.in\n");
+		return 1;
+	}
+
+	if (argv[2])
+		start = atoi(argv[2]);
+	else
+		start = 0;
+
+	len = read(0, buf, sizeof(buf));
+	header_len = sprintf(header, "blob %d", len) + 1;
+	fprintf(stderr, "using header: %s\n", header);
+
+	/*
+	 * We keep a running sha1 so that if you are munging
+	 * near the end of the file, we do not have to re-sha1
+	 * the unchanged earlier bytes
+	 */
+	SHA1_Init(&orig);
+	SHA1_Update(&orig, header, header_len);
+	if (start)
+		SHA1_Update(&orig, buf, start);
+
+	signal(SIGALRM, progress);
+	alarm(1);
+
+	for (i = start; i < len; i++) {
+		unsigned char c;
+		SHA_CTX x;
+
+#if 0
+		/*
+		 * deletion -- this would not actually work in practice,
+		 * I think, because we've already committed to a
+		 * particular size in the header. Ditto for addition
+		 * below. In those cases, you'd have to do the whole
+		 * sha1 from scratch, or possibly keep three running
+		 * "orig" sha1 computations going.
+		 */
+		memcpy(&x, &orig, sizeof(x));
+		SHA1_Update(&x, buf + i + 1, len - i - 1);
+		SHA1_Final(have, &x);
+		if (!memcmp(have, want, 20))
+			printf("i=%d, deletion\n", i);
+#endif
+
+		/*
+		 * replacement -- note that this tries each of the 256
+		 * possible bytes. If you suspect a single-bit flip,
+		 * it would be much shorter to just try the 8
+		 * bit-flipped variants.
+		 */
+		c = buf[i];
+		for (j = 0; j <= 0xff; j++) {
+			buf[i] = j;
+
+			memcpy(&x, &orig, sizeof(x));
+			SHA1_Update(&x, buf + i, len - i);
+			SHA1_Final(have, &x);
+			if (!memcmp(have, want, 20))
+				printf("i=%d, j=%02x\n", i, j);
+		}
+		buf[i] = c;
+
+#if 0
+		/* addition */
+		for (j = 0; j <= 0xff; j++) {
+			unsigned char extra = j;
+			memcpy(&x, &orig, sizeof(x));
+			SHA1_Update(&x, &extra, 1);
+			SHA1_Update(&x, buf + i, len - i);
+			SHA1_Final(have, &x);
+			if (!memcmp(have, want, 20))
+				printf("i=%d, addition=%02x", i, j);
+		}
+#endif
+
+		SHA1_Update(&orig, buf + i, 1);
+		counter++;
+	}
+
+	alarm(0);
+	fprintf(stderr, "\r%d\n", counter);
+	return 0;
+}
+--------------------------
diff --git a/Documentation/howto/revert-a-faulty-merge.adoc b/Documentation/howto/revert-a-faulty-merge.adoc
new file mode 100644
index 0000000000..19f59cc888
--- /dev/null
+++ b/Documentation/howto/revert-a-faulty-merge.adoc
@@ -0,0 +1,273 @@
+Date: Fri, 19 Dec 2008 00:45:19 -0800
+From: Linus Torvalds <torvalds@xxxxxxxxxxxxxxxxxxxx>, Junio C Hamano <gitster@xxxxxxxxx>
+Subject: Re: Odd merge behaviour involving reverts
+Abstract: Sometimes a branch that was already merged to the mainline
+ is later found to be faulty.  Linus and Junio give guidance on
+ recovering from such a premature merge and continuing development
+ after the offending branch is fixed.
+Message-ID: <7vocz8a6zk.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxx>
+References: <alpine.LFD.2.00.0812181949450.14014@localhost.localdomain>
+Content-type: text/asciidoc
+
+How to revert a faulty merge
+============================
+
+Alan <alan@xxxxxxxxxxxxxx> said:
+
+    I have a master branch.  We have a branch off of that that some
+    developers are doing work on.  They claim it is ready. We merge it
+    into the master branch.  It breaks something so we revert the merge.
+    They make changes to the code.  they get it to a point where they say
+    it is ok and we merge again.
+
+    When examined, we find that code changes made before the revert are
+    not in the master branch, but code changes after are in the master
+    branch.
+
+and asked for help recovering from this situation.
+
+The history immediately after the "revert of the merge" would look like
+this:
+
+ ---o---o---o---M---x---x---W
+               /
+       ---A---B
+
+where A and B are on the side development that was not so good, M is the
+merge that brings these premature changes into the mainline, x are changes
+unrelated to what the side branch did and already made on the mainline,
+and W is the "revert of the merge M" (doesn't W look M upside down?).
+IOW, `"diff W^..W"` is similar to `"diff -R M^..M"`.
+
+Such a "revert" of a merge can be made with:
+
+    $ git revert -m 1 M
+
+After the developers of the side branch fix their mistakes, the history
+may look like this:
+
+ ---o---o---o---M---x---x---W---x
+               /
+       ---A---B-------------------C---D
+
+where C and D are to fix what was broken in A and B, and you may already
+have some other changes on the mainline after W.
+
+If you merge the updated side branch (with D at its tip), none of the
+changes made in A or B will be in the result, because they were reverted
+by W.  That is what Alan saw.
+
+Linus explains the situation:
+
+    Reverting a regular commit just effectively undoes what that commit
+    did, and is fairly straightforward. But reverting a merge commit also
+    undoes the _data_ that the commit changed, but it does absolutely
+    nothing to the effects on _history_ that the merge had.
+
+    So the merge will still exist, and it will still be seen as joining
+    the two branches together, and future merges will see that merge as
+    the last shared state - and the revert that reverted the merge brought
+    in will not affect that at all.
+
+    So a "revert" undoes the data changes, but it's very much _not_ an
+    "undo" in the sense that it doesn't undo the effects of a commit on
+    the repository history.
+
+    So if you think of "revert" as "undo", then you're going to always
+    miss this part of reverts. Yes, it undoes the data, but no, it doesn't
+    undo history.
+
+In such a situation, you would want to first revert the previous revert,
+which would make the history look like this:
+
+ ---o---o---o---M---x---x---W---x---Y
+               /
+       ---A---B-------------------C---D
+
+where Y is the revert of W.  Such a "revert of the revert" can be done
+with:
+
+    $ git revert W
+
+This history would (ignoring possible conflicts between what W and W..Y
+changed) be equivalent to not having W or Y at all in the history:
+
+ ---o---o---o---M---x---x-------x----
+               /
+       ---A---B-------------------C---D
+
+and merging the side branch again will not have conflict arising from an
+earlier revert and revert of the revert.
+
+ ---o---o---o---M---x---x-------x-------*
+               /                       /
+       ---A---B-------------------C---D
+
+Of course the changes made in C and D still can conflict with what was
+done by any of the x, but that is just a normal merge conflict.
+
+On the other hand, if the developers of the side branch discarded their
+faulty A and B, and redone the changes on top of the updated mainline
+after the revert, the history would have looked like this:
+
+ ---o---o---o---M---x---x---W---x---x
+               /                 \
+       ---A---B                   A'--B'--C'
+
+If you reverted the revert in such a case as in the previous example:
+
+ ---o---o---o---M---x---x---W---x---x---Y---*
+               /                 \         /
+       ---A---B                   A'--B'--C'
+
+where Y is the revert of W, A' and B' are rerolled A and B, and there may
+also be a further fix-up C' on the side branch.  `"diff Y^..Y"` is similar
+to `"diff -R W^..W"` (which in turn means it is similar to `"diff M^..M"`),
+and `"diff A'^..C'"` by definition would be similar but different from that,
+because it is a rerolled series of the earlier change.  There will be a
+lot of overlapping changes that result in conflicts.  So do not do "revert
+of revert" blindly without thinking..
+
+ ---o---o---o---M---x---x---W---x---x
+               /                 \
+       ---A---B                   A'--B'--C'
+
+In the history with rebased side branch, W (and M) are behind the merge
+base of the updated branch and the tip of the mainline, and they should
+merge without the past faulty merge and its revert getting in the way.
+
+To recap, these are two very different scenarios, and they want two very
+different resolution strategies:
+
+ - If the faulty side branch was fixed by adding corrections on top, then
+   doing a revert of the previous revert would be the right thing to do.
+
+ - If the faulty side branch whose effects were discarded by an earlier
+   revert of a merge was rebuilt from scratch (i.e. rebasing and fixing,
+   as you seem to have interpreted), then re-merging the result without
+   doing anything else fancy would be the right thing to do.
+   (See the ADDENDUM below for how to rebuild a branch from scratch
+   without changing its original branching-off point.)
+
+However, there are things to keep in mind when reverting a merge (and
+reverting such a revert).
+
+For example, think about what reverting a merge (and then reverting the
+revert) does to bisectability. Ignore the fact that the revert of a revert
+is undoing it - just think of it as a "single commit that does a lot".
+Because that is what it does.
+
+When you have a problem you are chasing down, and you hit a "revert this
+merge", what you're hitting is essentially a single commit that contains
+all the changes (but obviously in reverse) of all the commits that got
+merged. So it's debugging hell, because now you don't have lots of small
+changes that you can try to pinpoint which _part_ of it changes.
+
+But does it all work? Sure it does. You can revert a merge, and from a
+purely technical angle, Git did it very naturally and had no real
+troubles. It just considered it a change from "state before merge" to
+"state after merge", and that was it. Nothing complicated, nothing odd,
+nothing really dangerous. Git will do it without even thinking about it.
+
+So from a technical angle, there's nothing wrong with reverting a merge,
+but from a workflow angle it's something that you generally should try to
+avoid.
+
+If at all possible, for example, if you find a problem that got merged
+into the main tree, rather than revert the merge, try _really_ hard to
+bisect the problem down into the branch you merged, and just fix it, or
+try to revert the individual commit that caused it.
+
+Yes, it's more complex, and no, it's not always going to work (sometimes
+the answer is: "oops, I really shouldn't have merged it, because it wasn't
+ready yet, and I really need to undo _all_ of the merge"). So then you
+really should revert the merge, but when you want to re-do the merge, you
+now need to do it by reverting the revert.
+
+ADDENDUM
+
+Sometimes you have to rewrite one of a topic branch's commits *and* you can't
+change the topic's branching-off point.  Consider the following situation:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C
+
+where commit W reverted commit M because it turned out that commit B was wrong
+and needs to be rewritten, but you need the rewritten topic to still branch
+from commit P (perhaps P is a branching-off point for yet another branch, and
+you want be able to merge the topic into both branches).
+
+The natural thing to do in this case is to checkout the A-B-C branch and use
+"rebase -i P" to change commit B.  However this does not rewrite commit A,
+because "rebase -i" by default fast-forwards over any initial commits selected
+with the "pick" command.  So you end up with this:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C   <-- old branch
+    \
+     B'---C'   <-- naively rewritten branch
+
+To merge A-B'-C' into the mainline branch you would still have to first revert
+commit W in order to pick up the changes in A, but then it's likely that the
+changes in B' will conflict with the original B changes re-introduced by the
+reversion of W.
+
+However, you can avoid these problems if you recreate the entire branch,
+including commit A:
+
+   A'---B'---C'  <-- completely rewritten branch
+  /
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C
+
+You can merge A'-B'-C' into the mainline branch without worrying about first
+reverting W.  Mainline's history would look like this:
+
+   A'---B'---C'------------------
+  /                              \
+ P---o---o---M---x---x---W---x---M2
+  \         /
+   A---B---C
+
+But if you don't actually need to change commit A, then you need some way to
+recreate it as a new commit with the same changes in it.  The rebase command's
+--no-ff option provides a way to do this:
+
+    $ git rebase [-i] --no-ff P
+
+The --no-ff option creates a new branch A'-B'-C' with all-new commits (all the
+SHA IDs will be different) even if in the interactive case you only actually
+modify commit B.  You can then merge this new branch directly into the mainline
+branch and be sure you'll get all of the branch's changes.
+
+You can also use --no-ff in cases where you just add extra commits to the topic
+to fix it up.  Let's revisit the situation discussed at the start of this howto:
+
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C----------------D---E   <-- fixed-up topic branch
+
+At this point, you can use --no-ff to recreate the topic branch:
+
+    $ git checkout E
+    $ git rebase --no-ff P
+
+yielding
+
+   A'---B'---C'------------D'---E'  <-- recreated topic branch
+  /
+ P---o---o---M---x---x---W---x
+  \         /
+   A---B---C----------------D---E
+
+You can merge the recreated branch into the mainline without reverting commit W,
+and mainline's history will look like this:
+
+   A'---B'---C'------------D'---E'
+  /                              \
+ P---o---o---M---x---x---W---x---M2
+  \         /
+   A---B---C
diff --git a/Documentation/howto/revert-branch-rebase.adoc b/Documentation/howto/revert-branch-rebase.adoc
new file mode 100644
index 0000000000..a3e5595a56
--- /dev/null
+++ b/Documentation/howto/revert-branch-rebase.adoc
@@ -0,0 +1,187 @@
+From: Junio C Hamano <gitster@xxxxxxxxx>
+To: git@xxxxxxxxxxxxxxx
+Subject: [HOWTO] Reverting an existing commit
+Abstract: In this article, JC gives a small real-life example of using
+ 'git revert' command, and using a temporary branch and tag for safety
+ and easier sanity checking.
+Date: Mon, 29 Aug 2005 21:39:02 -0700
+Content-type: text/asciidoc
+Message-ID: <7voe7g3uop.fsf@xxxxxxxxxxxxxxxxxxxxxxxx>
+
+How to revert an existing commit
+================================
+
+One of the changes I pulled into the 'master' branch turns out to
+break building Git with GCC 2.95.  While they were well-intentioned
+portability fixes, keeping things working with gcc-2.95 was also
+important.  Here is what I did to revert the change in the 'master'
+branch and to adjust the 'seen' branch, using core Git tools and
+barebone Porcelain.
+
+First, prepare a throw-away branch in case I screw things up.
+
+------------------------------------------------
+$ git checkout -b revert-c99 master
+------------------------------------------------
+
+Now I am on the 'revert-c99' branch.  Let's figure out which commit to
+revert.  I happen to know that the top of the 'master' branch is a
+merge, and its second parent (i.e. foreign commit I merged from) has
+the change I would want to undo.  Further I happen to know that that
+merge introduced 5 commits or so:
+
+------------------------------------------------
+$ git show-branch --more=4 master master^2 | head
+* [master] Merge refs/heads/portable from http://www.cs.berkeley....
+ ! [master^2] Replace C99 array initializers with code.
+--
+-  [master] Merge refs/heads/portable from http://www.cs.berkeley....
+*+ [master^2] Replace C99 array initializers with code.
+*+ [master^2~1] Replace unsetenv() and setenv() with older putenv().
+*+ [master^2~2] Include sys/time.h in daemon.c.
+*+ [master^2~3] Fix ?: statements.
+*+ [master^2~4] Replace zero-length array decls with [].
+*  [master~1] tutorial note about git branch
+------------------------------------------------
+
+The '--more=4' above means "after we reach the merge base of refs,
+show until we display four more common commits".  That last commit
+would have been where the "portable" branch was forked from the main
+git.git repository, so this would show everything on both branches
+since then.  I just limited the output to the first handful using
+'head'.
+
+Now I know 'master^2~4' (pronounce it as "find the second parent of
+the 'master', and then go four generations back following the first
+parent") is the one I would want to revert.  Since I also want to say
+why I am reverting it, the '-n' flag is given to 'git revert'.  This
+prevents it from actually making a commit, and instead 'git revert'
+leaves the commit log message it wanted to use in '.msg' file:
+
+------------------------------------------------
+$ git revert -n master^2~4
+$ cat .msg
+Revert "Replace zero-length array decls with []."
+
+This reverts 6c5f9baa3bc0d63e141e0afc23110205379905a4 commit.
+$ git diff HEAD ;# to make sure what we are reverting makes sense.
+$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.
+$ make clean test ;# make sure it did not cause other breakage.
+------------------------------------------------
+
+The reverted change makes sense (from reading the 'diff' output), does
+fix the problem (from 'make CC=gcc-2.95' test), and does not cause new
+breakage (from the last 'make test').  I'm ready to commit:
+
+------------------------------------------------
+$ git commit -a -s ;# read .msg into the log,
+                    # and explain why I am reverting.
+------------------------------------------------
+
+I could have screwed up in any of the above steps, but in the worst
+case I could just have done 'git checkout master' to start over.
+Fortunately I did not have to; what I have in the current branch
+'revert-c99' is what I want.  So merge that back into 'master':
+
+------------------------------------------------
+$ git checkout master
+$ git merge revert-c99 ;# this should be a fast-forward
+Updating from 10d781b9caa4f71495c7b34963bef137216f86a8 to e3a693c...
+ cache.h        |    8 ++++----
+ commit.c       |    2 +-
+ ls-files.c     |    2 +-
+ receive-pack.c |    2 +-
+ server-info.c  |    2 +-
+ 5 files changed, 8 insertions(+), 8 deletions(-)
+------------------------------------------------
+
+There is no need to redo the test at this point.  We fast-forwarded
+and we know 'master' matches 'revert-c99' exactly.  In fact:
+
+------------------------------------------------
+$ git diff master..revert-c99
+------------------------------------------------
+
+says nothing.
+
+Then we rebase the 'seen' branch as usual.
+
+------------------------------------------------
+$ git checkout seen
+$ git tag seen-anchor seen
+$ git rebase master
+* Applying: Redo "revert" using three-way merge machinery.
+First trying simple merge strategy to cherry-pick.
+* Applying: Remove git-apply-patch-script.
+First trying simple merge strategy to cherry-pick.
+Simple cherry-pick fails; trying Automatic cherry-pick.
+Removing Documentation/git-apply-patch-script.txt
+Removing git-apply-patch-script
+* Applying: Document "git cherry-pick" and "git revert"
+First trying simple merge strategy to cherry-pick.
+* Applying: mailinfo and applymbox updates
+First trying simple merge strategy to cherry-pick.
+* Applying: Show commits in topo order and name all commits.
+First trying simple merge strategy to cherry-pick.
+* Applying: More documentation updates.
+First trying simple merge strategy to cherry-pick.
+------------------------------------------------
+
+The temporary tag 'seen-anchor' is me just being careful, in case 'git
+rebase' screws up.  After this, I can do these for sanity check:
+
+------------------------------------------------
+$ git diff seen-anchor..seen ;# make sure we got the master fix.
+$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.
+$ make clean test ;# make sure it did not cause other breakage.
+------------------------------------------------
+
+Everything is in the good order.  I do not need the temporary branch
+or tag anymore, so remove them:
+
+------------------------------------------------
+$ rm -f .git/refs/tags/seen-anchor
+$ git branch -d revert-c99
+------------------------------------------------
+
+It was an emergency fix, so we might as well merge it into the
+'release candidate' branch, although I expect the next release would
+be some days off:
+
+------------------------------------------------
+$ git checkout rc
+$ git pull . master
+Packing 0 objects
+Unpacking 0 objects
+
+* commit-ish: e3a693c...	refs/heads/master from .
+Trying to merge e3a693c... into 8c1f5f0... using 10d781b...
+Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f
+ cache.h        |    8 ++++----
+ commit.c       |    2 +-
+ ls-files.c     |    2 +-
+ receive-pack.c |    2 +-
+ server-info.c  |    2 +-
+ 5 files changed, 8 insertions(+), 8 deletions(-)
+------------------------------------------------
+
+And the final repository status looks like this:
+
+------------------------------------------------
+$ git show-branch --more=1 master seen rc
+! [master] Revert "Replace zero-length array decls with []."
+ ! [seen] git-repack: Add option to repack all objects.
+  * [rc] Merge refs/heads/master from .
+---
+ +  [seen] git-repack: Add option to repack all objects.
+ +  [seen~1] More documentation updates.
+ +  [seen~2] Show commits in topo order and name all commits.
+ +  [seen~3] mailinfo and applymbox updates
+ +  [seen~4] Document "git cherry-pick" and "git revert"
+ +  [seen~5] Remove git-apply-patch-script.
+ +  [seen~6] Redo "revert" using three-way merge machinery.
+  - [rc] Merge refs/heads/master from .
+++* [master] Revert "Replace zero-length array decls with []."
+  - [rc~1] Merge refs/heads/master from .
+... [master~1] Merge refs/heads/portable from http://www.cs.berkeley....
+------------------------------------------------
diff --git a/Documentation/howto/separating-topic-branches.adoc b/Documentation/howto/separating-topic-branches.adoc
new file mode 100644
index 0000000000..81be0d6115
--- /dev/null
+++ b/Documentation/howto/separating-topic-branches.adoc
@@ -0,0 +1,94 @@
+From: Junio C Hamano <gitster@xxxxxxxxx>
+Subject: Separating topic branches
+Abstract: In this article, JC describes how to separate topic branches.
+Content-type: text/asciidoc
+
+How to separate topic branches
+==============================
+
+This text was originally a footnote to a discussion about the
+behaviour of the git diff commands.
+
+Often I find myself doing that [running diff against something other
+than HEAD] while rewriting messy development history.  For example, I
+start doing some work without knowing exactly where it leads, and end
+up with a history like this:
+
+            "master"
+        o---o
+             \                    "topic"
+              o---o---o---o---o---o
+
+At this point, "topic" contains something I know I want, but it
+contains two concepts that turned out to be completely independent.
+And often, one topic component is larger than the other.  It may
+contain more than two topics.
+
+In order to rewrite this mess to be more manageable, I would first do
+"diff master..topic", to extract the changes into a single patch, start
+picking pieces from it to get logically self-contained units, and
+start building on top of "master":
+
+        $ git diff master..topic >P.diff
+        $ git checkout -b topicA master
+        ... pick and apply pieces from P.diff to build
+        ... commits on topicA branch.
+
+              o---o---o
+             /        "topicA"
+        o---o"master"
+             \                    "topic"
+              o---o---o---o---o---o
+
+Before doing each commit on "topicA" HEAD, I run "diff HEAD"
+before update-index the affected paths, or "diff --cached HEAD"
+after.  Also I would run "diff --cached master" to make sure
+that the changes are only the ones related to "topicA".  Usually
+I do this for smaller topics first.
+
+After that, I'd do the remainder of the original "topic", but
+for that, I do not start from the patchfile I extracted by
+comparing "master" and "topic" I used initially.  Still on
+"topicA", I extract "diff topic", and use it to rebuild the
+other topic:
+
+        $ git diff -R topic >P.diff ;# --cached also would work fine
+        $ git checkout -b topicB master
+        ... pick and apply pieces from P.diff to build
+        ... commits on topicB branch.
+
+                                "topicB"
+               o---o---o---o---o
+              /
+             /o---o---o
+            |/        "topicA"
+        o---o"master"
+             \                    "topic"
+              o---o---o---o---o---o
+
+After I am done, I'd try a pretend-merge between "topicA" and
+"topicB" in order to make sure I have not missed anything:
+
+        $ git pull . topicA ;# merge it into current "topicB"
+        $ git diff topic
+                                "topicB"
+               o---o---o---o---o---* (pretend merge)
+              /                   /
+             /o---o---o----------'
+            |/        "topicA"
+        o---o"master"
+             \                    "topic"
+              o---o---o---o---o---o
+
+The last diff better not to show anything other than cleanups
+for cruft.  Then I can finally clean things up:
+
+        $ git branch -D topic
+        $ git reset --hard HEAD^ ;# nuke pretend merge
+
+                                "topicB"
+               o---o---o---o---o
+              /
+             /o---o---o
+            |/        "topicA"
+        o---o"master"
diff --git a/Documentation/howto/setup-git-server-over-http.adoc b/Documentation/howto/setup-git-server-over-http.adoc
new file mode 100644
index 0000000000..bfe6f9b500
--- /dev/null
+++ b/Documentation/howto/setup-git-server-over-http.adoc
@@ -0,0 +1,285 @@
+From: Rutger Nijlunsing <rutger@xxxxxxxxxx>
+Subject: Setting up a Git repository which can be pushed into and pulled from over HTTP(S).
+Date: Thu, 10 Aug 2006 22:00:26 +0200
+Content-type: text/asciidoc
+
+How to setup Git server over http
+=================================
+
+NOTE: This document is from 2006.  A lot has happened since then, and this
+document is now relevant mainly if your web host is not CGI capable.
+Almost everyone else should instead look at linkgit:git-http-backend[1].
+
+Since Apache is one of those packages people like to compile
+themselves while others prefer the bureaucrat's dream Debian, it is
+impossible to give guidelines which will work for everyone. Just send
+some feedback to the mailing list at git@xxxxxxxxxxxxxxx to get this
+document tailored to your favorite distro.
+
+
+What's needed:
+
+- Have an Apache web-server
+
+  On Debian:
+    $ apt-get install apache2
+    To get apache2 by default started,
+    edit /etc/default/apache2 and set NO_START=0
+
+- can edit the configuration of it.
+
+  This could be found under /etc/httpd, or refer to your Apache documentation.
+
+  On Debian: this means being able to edit files under /etc/apache2
+
+- can restart it.
+
+  'apachectl --graceful' might do. If it doesn't, just stop and
+  restart apache. Be warning that active connections to your server
+  might be aborted by this.
+
+  On Debian:
+    $ /etc/init.d/apache2 restart
+  or
+    $ /etc/init.d/apache2 force-reload
+    (which seems to do the same)
+  This adds symlinks from the /etc/apache2/mods-enabled to
+  /etc/apache2/mods-available.
+
+- have permissions to chown a directory
+
+- have Git installed on the client, and
+
+- either have Git installed on the server or have a webdav client on
+  the client.
+
+In effect, this means you're going to be root, or that you're using a
+preconfigured WebDAV server.
+
+
+Step 1: setup a bare Git repository
+-----------------------------------
+
+At the time of writing, git-http-push cannot remotely create a Git
+repository. So we have to do that at the server side with Git. Another
+option is to generate an empty bare repository at the client and copy
+it to the server with a WebDAV client (which is the only option if Git
+is not installed on the server).
+
+Create the directory under the DocumentRoot of the directories served
+by Apache. As an example we take /usr/local/apache2, but try "grep
+DocumentRoot /where/ever/httpd.conf" to find your root:
+
+    $ cd /usr/local/apache/htdocs
+    $ mkdir my-new-repo.git
+
+  On Debian:
+
+    $ cd /var/www
+    $ mkdir my-new-repo.git
+
+
+Initialize a bare repository
+
+    $ cd my-new-repo.git
+    $ git --bare init
+
+
+Change the ownership to your web-server's credentials. Use `"grep ^User
+httpd.conf"` and `"grep ^Group httpd.conf"` to find out:
+
+    $ chown -R www.www .
+
+  On Debian:
+
+    $ chown -R www-data.www-data .
+
+
+If you do not know which user Apache runs as, you can alternatively do
+a "chmod -R a+w .", inspect the files which are created later on, and
+set the permissions appropriately.
+
+Restart apache2, and check whether http://server/my-new-repo.git gives
+a directory listing. If not, check whether apache started up
+successfully.
+
+
+Step 2: enable DAV on this repository
+-------------------------------------
+
+First make sure the dav_module is loaded. For this, insert in httpd.conf:
+
+    LoadModule dav_module libexec/httpd/libdav.so
+    AddModule mod_dav.c
+
+Also make sure that this line exists which is the file used for
+locking DAV operations:
+
+  DAVLockDB "/usr/local/apache2/temp/DAV.lock"
+
+  On Debian these steps can be performed with:
+
+    Enable the dav and dav_fs modules of apache:
+    $ a2enmod dav_fs
+    (just to be sure. dav_fs might be unneeded, I don't know)
+    $ a2enmod dav
+    The DAV lock is located in /etc/apache2/mods-available/dav_fs.conf:
+      DAVLockDB /var/lock/apache2/DAVLock
+
+Of course, it can point somewhere else, but the string is actually just a
+prefix in some Apache configurations, and therefore the _directory_ has to
+be writable by the user Apache runs as.
+
+Then, add something like this to your httpd.conf
+
+  <Location /my-new-repo.git>
+     DAV on
+     AuthType Basic
+     AuthName "Git"
+     AuthUserFile /usr/local/apache2/conf/passwd.git
+     Require valid-user
+  </Location>
+
+  On Debian:
+    Create (or add to) /etc/apache2/conf.d/git.conf :
+
+    <Location /my-new-repo.git>
+       DAV on
+       AuthType Basic
+       AuthName "Git"
+       AuthUserFile /etc/apache2/passwd.git
+       Require valid-user
+    </Location>
+
+    Debian automatically reads all files under /etc/apache2/conf.d.
+
+The password file can be somewhere else, but it has to be readable by
+Apache and preferably not readable by the world.
+
+Create this file by
+    $ htpasswd -c /usr/local/apache2/conf/passwd.git <user>
+
+    On Debian:
+      $ htpasswd -c /etc/apache2/passwd.git <user>
+
+You will be asked a password, and the file is created. Subsequent calls
+to htpasswd should omit the '-c' option, since you want to append to the
+existing file.
+
+You need to restart Apache.
+
+Now go to http://<username>@<servername>/my-new-repo.git in your
+browser to check whether it asks for a password and accepts the right
+password.
+
+On Debian:
+
+   To test the WebDAV part, do:
+
+   $ apt-get install litmus
+   $ litmus http://<servername>/my-new-repo.git <username> <password>
+
+   Most tests should pass.
+
+A command-line tool to test WebDAV is cadaver. If you prefer GUIs, for
+example, konqueror can open WebDAV URLs as "webdav://..." or
+"webdavs://...".
+
+If you're into Windows, from XP onwards Internet Explorer supports
+WebDAV. For this, do Internet Explorer -> Open Location ->
+http://<servername>/my-new-repo.git [x] Open as webfolder -> login .
+
+
+Step 3: setup the client
+------------------------
+
+Make sure that you have HTTP support, i.e. your Git was built with
+libcurl (version more recent than 7.10). The command 'git http-push' with
+no argument should display a usage message.
+
+Then, add the following to your $HOME/.netrc (you can do without, but will be
+asked to input your password a _lot_ of times):
+
+    machine <servername>
+    login <username>
+    password <password>
+
+...and set permissions:
+     chmod 600 ~/.netrc
+
+If you want to access the web-server by its IP, you have to type that in,
+instead of the server name.
+
+To check whether all is OK, do:
+
+   curl --netrc --location -v http://<username>@<servername>/my-new-repo.git/HEAD
+
+...this should give something like 'ref: refs/heads/master', which is
+the content of the file HEAD on the server.
+
+Now, add the remote in your existing repository which contains the project
+you want to export:
+
+   $ git-config remote.upload.url \
+       http://<username>@<servername>/my-new-repo.git/
+
+It is important to put the last '/'; Without it, the server will send
+a redirect which git-http-push does not (yet) understand, and git-http-push
+will repeat the request infinitely.
+
+
+Step 4: make the initial push
+-----------------------------
+
+From your client repository, do
+
+   $ git push upload master
+
+This pushes branch 'master' (which is assumed to be the branch you
+want to export) to repository called 'upload', which we previously
+defined with git-config.
+
+
+Using a proxy:
+--------------
+
+If you have to access the WebDAV server from behind an HTTP(S) proxy,
+set the variable 'all_proxy' to `http://proxy-host.com:port`, or
+`http://login-on-proxy:passwd-on-proxy@xxxxxxxxxxxxxx:port`. See 'man
+curl' for details.
+
+
+Troubleshooting:
+----------------
+
+If git-http-push says
+
+   Error: no DAV locking support on remote repo http://...
+
+then it means the web-server did not accept your authentication. Make sure
+that the user name and password matches in httpd.conf, .netrc and the URL
+you are uploading to.
+
+If git-http-push shows you an error (22/502) when trying to MOVE a blob,
+it means that your web-server somehow does not recognize its name in the
+request; This can happen when you start Apache, but then disable the
+network interface. A simple restart of Apache helps.
+
+Errors like (22/502) are of format (curl error code/http error
+code). So (22/404) means something like 'not found' at the server.
+
+Reading /usr/local/apache2/logs/error_log is often helpful.
+
+  On Debian: Read /var/log/apache2/error.log instead.
+
+If you access HTTPS locations, Git may fail verifying the SSL
+certificate (this is return code 60). Setting http.sslVerify=false can
+help diagnosing the problem, but removes security checks.
+
+
+Debian References: http://www.debian-administration.org/articles/285
+
+Authors
+  Johannes Schindelin <Johannes.Schindelin@xxxxxx>
+  Rutger Nijlunsing <git@xxxxxxxxxxxxxxxxx>
+  Matthieu Moy <Matthieu.Moy@xxxxxxx>
diff --git a/Documentation/howto/update-hook-example.adoc b/Documentation/howto/update-hook-example.adoc
new file mode 100644
index 0000000000..4e727deedd
--- /dev/null
+++ b/Documentation/howto/update-hook-example.adoc
@@ -0,0 +1,192 @@
+From: Junio C Hamano <gitster@xxxxxxxxx> and Carl Baldwin <cnb@xxxxxxxxx>
+Subject: control access to branches.
+Date: Thu, 17 Nov 2005 23:55:32 -0800
+Message-ID: <7vfypumlu3.fsf@xxxxxxxxxxxxxxxxxxxxxxxx>
+Abstract: An example hooks/update script is presented to
+ implement repository maintenance policies, such as who can push
+ into which branch and who can make a tag.
+Content-type: text/asciidoc
+
+How to use the update hook
+==========================
+
+When your developer runs git-push into the repository,
+git-receive-pack is run (either locally or over ssh) as that
+developer, so is hooks/update script.  Quoting from the relevant
+section of the documentation:
+
+    Before each ref is updated, if $GIT_DIR/hooks/update file exists
+    and executable, it is called with three parameters:
+
+           $GIT_DIR/hooks/update refname sha1-old sha1-new
+
+    The refname parameter is relative to $GIT_DIR; e.g. for the
+    master head this is "refs/heads/master".  Two sha1 are the
+    object names for the refname before and after the update.  Note
+    that the hook is called before the refname is updated, so either
+    sha1-old is 0{40} (meaning there is no such ref yet), or it
+    should match what is recorded in refname.
+
+So if your policy is (1) always require fast-forward push
+(i.e. never allow "git-push repo +branch:branch"), (2) you
+have a list of users allowed to update each branch, and (3) you
+do not let tags to be overwritten, then you can use something
+like this as your hooks/update script.
+
+[jc: editorial note.  This is a much improved version by Carl
+since I posted the original outline]
+
+----------------------------------------------------
+#!/bin/bash
+
+umask 002
+
+# If you are having trouble with this access control hook script
+# you can try setting this to true.  It will tell you exactly
+# why a user is being allowed/denied access.
+
+verbose=false
+
+# Default shell globbing messes things up downstream
+GLOBIGNORE=*
+
+function grant {
+  $verbose && echo >&2 "-Grant-		$1"
+  echo grant
+  exit 0
+}
+
+function deny {
+  $verbose && echo >&2 "-Deny-		$1"
+  echo deny
+  exit 1
+}
+
+function info {
+  $verbose && echo >&2 "-Info-		$1"
+}
+
+# Implement generic branch and tag policies.
+# - Tags should not be updated once created.
+# - Branches should only be fast-forwarded unless their pattern starts with '+'
+case "$1" in
+  refs/tags/*)
+    git rev-parse --verify -q "$1" &&
+    deny >/dev/null "You can't overwrite an existing tag"
+    ;;
+  refs/heads/*)
+    # No rebasing or rewinding
+    if expr "$2" : '0*$' >/dev/null; then
+      info "The branch '$1' is new..."
+    else
+      # updating -- make sure it is a fast-forward
+      mb=$(git merge-base "$2" "$3")
+      case "$mb,$2" in
+        "$2,$mb") info "Update is fast-forward" ;;
+	*)	  noff=y; info "This is not a fast-forward update.";;
+      esac
+    fi
+    ;;
+  *)
+    deny >/dev/null \
+    "Branch is not under refs/heads or refs/tags.  What are you trying to do?"
+    ;;
+esac
+
+# Implement per-branch controls based on username
+allowed_users_file=$GIT_DIR/info/allowed-users
+username=$(id -u -n)
+info "The user is: '$username'"
+
+if test -f "$allowed_users_file"
+then
+  rc=$(grep -Ev '^(#|$)' $allowed_users_file |
+    while read heads user_patterns
+    do
+      # does this rule apply to us?
+      head_pattern=${heads#+}
+      matchlen=$(expr "$1" : "${head_pattern#+}")
+      test "$matchlen" = ${#1} || continue
+
+      # if non-ff, $heads must be with the '+' prefix
+      test -n "$noff" &&
+      test "$head_pattern" = "$heads" && continue
+
+      info "Found matching head pattern: '$head_pattern'"
+      for user_pattern in $user_patterns; do
+        info "Checking user: '$username' against pattern: '$user_pattern'"
+        matchlen=$(expr "$username" : "$user_pattern")
+        if test "$matchlen" = "${#username}"
+        then
+          grant "Allowing user: '$username' with pattern: '$user_pattern'"
+        fi
+      done
+      deny "The user is not in the access list for this branch"
+    done
+  )
+  case "$rc" in
+    grant) grant >/dev/null "Granting access based on $allowed_users_file" ;;
+    deny)  deny  >/dev/null "Denying  access based on $allowed_users_file" ;;
+    *) ;;
+  esac
+fi
+
+allowed_groups_file=$GIT_DIR/info/allowed-groups
+groups=$(id -G -n)
+info "The user belongs to the following groups:"
+info "'$groups'"
+
+if test -f "$allowed_groups_file"
+then
+  rc=$(grep -Ev '^(#|$)' $allowed_groups_file |
+    while read heads group_patterns
+    do
+      # does this rule apply to us?
+      head_pattern=${heads#+}
+      matchlen=$(expr "$1" : "${head_pattern#+}")
+      test "$matchlen" = ${#1} || continue
+
+      # if non-ff, $heads must be with the '+' prefix
+      test -n "$noff" &&
+      test "$head_pattern" = "$heads" && continue
+
+      info "Found matching head pattern: '$head_pattern'"
+      for group_pattern in $group_patterns; do
+        for groupname in $groups; do
+          info "Checking group: '$groupname' against pattern: '$group_pattern'"
+          matchlen=$(expr "$groupname" : "$group_pattern")
+          if test "$matchlen" = "${#groupname}"
+          then
+            grant "Allowing group: '$groupname' with pattern: '$group_pattern'"
+          fi
+        done
+      done
+      deny "None of the user's groups are in the access list for this branch"
+    done
+  )
+  case "$rc" in
+    grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;;
+    deny)  deny  >/dev/null "Denying  access based on $allowed_groups_file" ;;
+    *) ;;
+  esac
+fi
+
+deny >/dev/null "There are no more rules to check.  Denying access"
+----------------------------------------------------
+
+This uses two files, $GIT_DIR/info/allowed-users and
+allowed-groups, to describe which heads can be pushed into by
+whom.  The format of each file would look like this:
+
+    refs/heads/master   junio
+    +refs/heads/seen    junio
+    refs/heads/cogito$  pasky
+    refs/heads/bw/.*    linus
+    refs/heads/tmp/.*   .*
+    refs/tags/v[0-9].*  junio
+
+With this, Linus can push or create "bw/penguin" or "bw/zebra"
+or "bw/panda" branches, Pasky can do only "cogito", and JC can
+do master and "seen" branches and make versioned tags.  And anybody
+can do tmp/blah branches. The '+' sign at the "seen" record means
+that JC can make non-fast-forward pushes on it.
diff --git a/Documentation/howto/use-git-daemon.adoc b/Documentation/howto/use-git-daemon.adoc
new file mode 100644
index 0000000000..2cad9b3ca5
--- /dev/null
+++ b/Documentation/howto/use-git-daemon.adoc
@@ -0,0 +1,54 @@
+Content-type: text/asciidoc
+
+How to use git-daemon
+=====================
+
+Git can be run in inetd mode and in stand alone mode. But all you want is
+to let a coworker pull from you, and therefore need to set up a Git server
+real quick, right?
+
+Note that git-daemon is not really chatty at the moment, especially when
+things do not go according to plan (e.g. a socket could not be bound).
+
+Another word of warning: if you run
+
+	$ git ls-remote git://127.0.0.1/rule-the-world.git
+
+and you see a message like
+
+	fatal: The remote end hung up unexpectedly
+
+it only means that _something_ went wrong. To find out _what_ went wrong,
+you have to ask the server. (Git refuses to be more precise for your
+security only. Take off your shoes now. You have any coins in your pockets?
+Sorry, not allowed -- who knows what you planned to do with them?)
+
+With these two caveats, let's see an example:
+
+	$ git daemon --reuseaddr --verbose --base-path=/home/gitte/git \
+	  --export-all -- /home/gitte/git/rule-the-world.git
+
+(Of course, unless your user name is `gitte` _and_ your repository is in
+~/rule-the-world.git, you have to adjust the paths. If your repository is
+not bare, be aware that you have to type the path to the .git directory!)
+
+This invocation tries to reuse the address if it is already taken
+(this can save you some debugging, because otherwise killing and restarting
+git-daemon could just silently fail to bind to a socket).
+
+Also, it is (relatively) verbose when somebody actually connects to it.
+It also sets the base path, which means that all the projects which can be
+accessed using this daemon have to reside in or under that path.
+
+The option `--export-all` just means that you _don't_ have to create a
+file named `git-daemon-export-ok` in each exported repository. (Otherwise,
+git-daemon would complain loudly, and refuse to cooperate.)
+
+Last of all, the repository which should be exported is specified. It is
+a good practice to put the paths after a "--" separator.
+
+Now, test your daemon with
+
+	$ git ls-remote git://127.0.0.1/rule-the-world.git
+
+If this does not work, find out why, and submit a patch to this document.
diff --git a/Documentation/howto/using-merge-subtree.adoc b/Documentation/howto/using-merge-subtree.adoc
new file mode 100644
index 0000000000..3bd581ac35
--- /dev/null
+++ b/Documentation/howto/using-merge-subtree.adoc
@@ -0,0 +1,75 @@
+Date: Sat, 5 Jan 2008 20:17:40 -0500
+From: Sean <seanlkml@xxxxxxxxxxxx>
+To: Miklos Vajna <vmiklos@xxxxxxxxxxxxxx>
+Cc: git@xxxxxxxxxxxxxxx
+Subject: how to use git merge -s subtree?
+Abstract: In this article, Sean demonstrates how one can use the subtree merge
+ strategy.
+Content-type: text/asciidoc
+Message-ID: <BAYC1-PASMTP12374B54BA370A1E1C6E78AE4E0@xxxxxxx>
+
+How to use the subtree merge strategy
+=====================================
+
+There are situations where you want to include content in your project
+from an independently developed project. You can just pull from the
+other project as long as there are no conflicting paths.
+
+The problematic case is when there are conflicting files. Potential
+candidates are Makefiles and other standard filenames. You could merge
+these files but probably you do not want to.  A better solution for this
+problem can be to merge the project as its own subdirectory. This is not
+supported by the 'recursive' merge strategy, so just pulling won't work.
+
+What you want is the 'subtree' merge strategy, which helps you in such a
+situation.
+
+In this example, let's say you have the repository at `/path/to/B` (but
+it can be a URL as well, if you want). You want to merge the 'master'
+branch of that repository to the `dir-B` subdirectory in your current
+branch.
+
+Here is the command sequence you need:
+
+----------------
+$ git remote add -f Bproject /path/to/B <1>
+$ git merge -s ours --no-commit --allow-unrelated-histories Bproject/master <2>
+$ git read-tree --prefix=dir-B/ -u Bproject/master <3>
+$ git commit -m "Merge B project as our subdirectory" <4>
+
+$ git pull -s subtree Bproject master <5>
+----------------
+<1> name the other project "Bproject", and fetch.
+<2> prepare for the later step to record the result as a merge.
+<3> read "master" branch of Bproject to the subdirectory "dir-B".
+<4> record the merge result.
+<5> maintain the result with subsequent merges using "subtree"
+
+The first four commands are used for the initial merge, while the last
+one is to merge updates from 'B project'.
+
+Comparing 'subtree' merge with submodules
+-----------------------------------------
+
+- The benefit of using subtree merge is that it requires less
+  administrative burden from the users of your repository. It works with
+  older (before Git v1.5.2) clients and you have the code right after
+  clone.
+
+- However if you use submodules then you can choose not to transfer the
+  submodule objects. This may be a problem with the subtree merge.
+
+- Also, in case you make changes to the other project, it is easier to
+  submit changes if you just use submodules.
+
+Additional tips
+---------------
+
+- If you made changes to the other project in your repository, they may
+  want to merge from your project. This is possible using subtree -- it
+  can shift up the paths in your tree and then they can merge only the
+  relevant parts of your tree.
+
+- Please note that if the other project merges from you, then it will
+  connect its history to yours, which can be something they don't want
+  to.
diff --git a/Documentation/howto/using-signed-tag-in-pull-request.adoc b/Documentation/howto/using-signed-tag-in-pull-request.adoc
new file mode 100644
index 0000000000..bbf040eda8
--- /dev/null
+++ b/Documentation/howto/using-signed-tag-in-pull-request.adoc
@@ -0,0 +1,217 @@
+From: Junio C Hamano <gitster@xxxxxxxxx>
+Date: Tue, 17 Jan 2011 13:00:00 -0800
+Subject: Using signed tag in pull requests
+Abstract: Beginning v1.7.9, a contributor can push a signed tag to her
+ publishing repository and ask her integrator to pull it. This assures the
+ integrator that the pulled history is authentic and allows others to
+ later validate it.
+Content-type: text/asciidoc
+
+How to use a signed tag in pull requests
+========================================
+
+A typical distributed workflow using Git is for a contributor to fork a
+project, build on it, publish the result to her public repository, and ask
+the "upstream" person (often the owner of the project where she forked
+from) to pull from her public repository. Requesting such a "pull" is made
+easy by the `git request-pull` command.
+
+Earlier, a typical pull request may have started like this:
+
+------------
+ The following changes since commit 406da78032179...:
+
+   Froboz 3.2 (2011-09-30 14:20:57 -0700)
+
+ are available in the Git repository at:
+
+   example.com:/git/froboz.git for-xyzzy
+------------
+
+followed by a shortlog of the changes and a diffstat.
+
+The request was for a branch name (e.g. `for-xyzzy`) in the public
+repository of the contributor, and even though it stated where the
+contributor forked her work from, the message did not say anything about
+the commit to expect at the tip of the for-xyzzy branch. If the site that
+hosts the public repository of the contributor cannot be fully trusted, it
+was unnecessarily hard to make sure what was pulled by the integrator was
+genuinely what the contributor had produced for the project. Also there
+was no easy way for third-party auditors to later verify the resulting
+history.
+
+Starting from Git release v1.7.9, a contributor can add a signed tag to
+the commit at the tip of the history and ask the integrator to pull that
+signed tag. When the integrator runs `git pull`, the signed tag is
+automatically verified to assure that the history is not tampered with.
+In addition, the resulting merge commit records the content of the signed
+tag, so that other people can verify that the branch merged by the
+integrator was signed by the contributor, without fetching the signed tag
+used to validate the pull request separately and keeping it in the refs
+namespace.
+
+This document describes the workflow between the contributor and the
+integrator, using Git v1.7.9 or later.
+
+
+A contributor or a lieutenant
+-----------------------------
+
+After preparing her work to be pulled, the contributor uses `git tag -s`
+to create a signed tag:
+
+------------
+ $ git checkout work
+ $ ... "git pull" from sublieutenants, "git commit" your own work ...
+ $ git tag -s -m "Completed frotz feature" frotz-for-xyzzy work
+------------
+
+Note that this example uses the `-m` option to create a signed tag with
+just a one-liner message, but this is for illustration purposes only. It
+is advisable to compose a well-written explanation of what the topic does
+to justify why it is worthwhile for the integrator to pull it, as this
+message will eventually become part of the final history after the
+integrator responds to the pull request (as we will see later).
+
+Then she pushes the tag out to her public repository:
+
+------------
+ $ git push example.com:/git/froboz.git/ +frotz-for-xyzzy
+------------
+
+There is no need to push the `work` branch or anything else.
+
+Note that the above command line used a plus sign at the beginning of
+`+frotz-for-xyzzy` to allow forcing the update of a tag, as the same
+contributor may want to reuse a signed tag with the same name after the
+previous pull request has already been responded to.
+
+The contributor then prepares a message to request a "pull":
+
+------------
+ $ git request-pull v3.2 example.com:/git/froboz.git/ frotz-for-xyzzy >msg.txt
+------------
+
+The arguments are:
+
+. the version of the integrator's commit the contributor based her work on;
+. the URL of the repository, to which the contributor has pushed what she
+  wants to get pulled; and
+. the name of the tag the contributor wants to get pulled (earlier, she could
+  write only a branch name here).
+
+The resulting msg.txt file begins like so:
+
+------------
+ The following changes since commit 406da78032179...:
+
+   Froboz 3.2 (2011-09-30 14:20:57 -0700)
+
+ are available in the Git repository at:
+
+   example.com:/git/froboz.git tags/frotz-for-xyzzy
+
+ for you to fetch changes up to 703f05ad5835c...:
+
+   Add tests and documentation for frotz (2011-12-02 10:02:52 -0800)
+
+ -----------------------------------------------
+ Completed frotz feature
+ -----------------------------------------------
+------------
+
+followed by a shortlog of the changes and a diffstat.  Comparing this with
+the earlier illustration of the output from the traditional `git request-pull`
+command, the reader should notice that:
+
+. The tip commit to expect is shown to the integrator; and
+. The signed tag message is shown prominently between the dashed lines
+  before the shortlog.
+
+The latter is why the contributor would want to justify why pulling her
+work is worthwhile when creating the signed tag.  The contributor then
+opens her favorite MUA, reads msg.txt, edits and sends it to her upstream
+integrator.
+
+
+Integrator
+----------
+
+After receiving such a pull request message, the integrator fetches and
+integrates the tag named in the request, with:
+
+------------
+ $ git pull example.com:/git/froboz.git/ tags/frotz-for-xyzzy
+------------
+
+This operation will always open an editor to allow the integrator to fine
+tune the commit log message when merging a signed tag.  Also, pulling a
+signed tag will always create a merge commit even when the integrator does
+not have any new commit since the contributor's work forked (i.e. 'fast
+forward'), so that the integrator can properly explain what the merge is
+about and why it was made.
+
+In the editor, the integrator will see something like this:
+
+------------
+ Merge tag 'frotz-for-xyzzy' of example.com:/git/froboz.git/
+
+ Completed frotz feature
+ # gpg: Signature made Fri 02 Dec 2011 10:03:01 AM PST using RSA key ID 96AFE6CB
+ # gpg: Good signature from "Con Tributor <nitfol@xxxxxxxxxxx>"
+------------
+
+Notice that the message recorded in the signed tag "Completed frotz
+feature" appears here, and again that is why it is important for the
+contributor to explain her work well when creating the signed tag.
+
+As usual, the lines commented with `#` are stripped out. The resulting
+commit records the signed tag used for this validation in a hidden field
+so that it can later be used by others to audit the history. There is no
+need for the integrator to keep a separate copy of the tag in his
+repository (i.e. `git tag -l` won't list the `frotz-for-xyzzy` tag in the
+above example), and there is no need to publish the tag to his public
+repository, either.
+
+After the integrator responds to the pull request and her work becomes
+part of the permanent history, the contributor can remove the tag from
+her public repository, if she chooses, in order to keep the tag namespace
+of her public repository clean, with:
+
+------------
+ $ git push example.com:/git/froboz.git :frotz-for-xyzzy
+------------
+
+
+Auditors
+--------
+
+The `--show-signature` option can be given to `git log` or `git show` and
+shows the verification status of the embedded signed tag in merge commits
+created when the integrator responded to a pull request of a signed tag.
+
+A typical output from `git show --show-signature` may look like this:
+
+------------
+ $ git show --show-signature
+ commit 02306ef6a3498a39118aef9df7975bdb50091585
+ merged tag 'frotz-for-xyzzy'
+ gpg: Signature made Fri 06 Jan 2012 12:41:49 PM PST using RSA key ID 96AFE6CB
+ gpg: Good signature from "Con Tributor <nitfol@xxxxxxxxxxx>"
+ Merge: 406da78 703f05a
+ Author: Inte Grator <xyzzy@xxxxxxxxxxx>
+ Date:   Tue Jan 17 13:49:41 2012 -0800
+
+     Merge tag 'frotz-for-xyzzy' of example.com:/git/froboz.git/
+
+     Completed frotz feature
+
+     * tag 'frotz-for-xyzzy' (100 commits)
+       Add tests and documentation for frotz
+       ...
+------------
+
+There is no need for the auditor to explicitly fetch the contributor's
+signature, or to even be aware of what tag(s) the contributor and integrator
+used to communicate the signature.  All the required information is recorded
+as part of the merge commit.
diff --git a/Documentation/i18n.adoc b/Documentation/i18n.adoc
new file mode 100644
index 0000000000..baff780a7e
--- /dev/null
+++ b/Documentation/i18n.adoc
@@ -0,0 +1,70 @@
+Git is to some extent character encoding agnostic.
+
+ - The contents of the blob objects are uninterpreted sequences
+   of bytes.  There is no encoding translation at the core
+   level.
+
+ - Path names are encoded in UTF-8 normalization form C. This
+   applies to tree objects, the index file, ref names, as well as
+   path names in command line arguments, environment variables
+   and config files (`.git/config` (see linkgit:git-config[1]),
+   linkgit:gitignore[5], linkgit:gitattributes[5] and
+   linkgit:gitmodules[5]).
++
+Note that Git at the core level treats path names simply as
+sequences of non-NUL bytes, there are no path name encoding
+conversions (except on Mac and Windows). Therefore, using
+non-ASCII path names will mostly work even on platforms and file
+systems that use legacy extended ASCII encodings. However,
+repositories created on such systems will not work properly on
+UTF-8-based systems (e.g. Linux, Mac, Windows) and vice versa.
+Additionally, many Git-based tools simply assume path names to
+be UTF-8 and will fail to display other encodings correctly.
+
+ - Commit log messages are typically encoded in UTF-8, but other
+   extended ASCII encodings are also supported. This includes
+   ISO-8859-x, CP125x and many others, but _not_ UTF-16/32,
+   EBCDIC and CJK multi-byte encodings (GBK, Shift-JIS, Big5,
+   EUC-x, CP9xx etc.).
+
+Although we encourage that the commit log messages are encoded
+in UTF-8, both the core and Git Porcelain are designed not to
+force UTF-8 on projects.  If all participants of a particular
+project find it more convenient to use legacy encodings, Git
+does not forbid it.  However, there are a few things to keep in
+mind.
+
+. `git commit` and `git commit-tree` issue
+  a warning if the commit log message given to it does not look
+  like a valid UTF-8 string, unless you explicitly say your
+  project uses a legacy encoding.  The way to say this is to
+  have `i18n.commitEncoding` in `.git/config` file, like this:
++
+------------
+[i18n]
+	commitEncoding = ISO-8859-1
+------------
++
+Commit objects created with the above setting record the value
+of `i18n.commitEncoding` in their `encoding` header.  This is to
+help other people who look at them later.  Lack of this header
+implies that the commit log message is encoded in UTF-8.
+
+. `git log`, `git show`, `git blame` and friends look at the
+  `encoding` header of a commit object, and try to re-code the
+  log message into UTF-8 unless otherwise specified.  You can
+  specify the desired output encoding with
+  `i18n.logOutputEncoding` in `.git/config` file, like this:
++
+------------
+[i18n]
+	logOutputEncoding = ISO-8859-1
+------------
++
+If you do not have this configuration variable, the value of
+`i18n.commitEncoding` is used instead.
+
+Note that we deliberately chose not to re-code the commit log
+message when a commit is made to force UTF-8 at the commit
+object level, because re-coding to UTF-8 is not necessarily a
+reversible operation.
diff --git a/Documentation/includes/cmd-config-section-all.txt b/Documentation/includes/cmd-config-section-all.txt
new file mode 100644
index 0000000000..296a239f2a
--- /dev/null
+++ b/Documentation/includes/cmd-config-section-all.txt
@@ -0,0 +1,3 @@
+Everything below this line in this section is selectively included
+from the linkgit:git-config[1] documentation. The content is the same
+as what's found there:
diff --git a/Documentation/includes/cmd-config-section-rest.txt b/Documentation/includes/cmd-config-section-rest.txt
new file mode 100644
index 0000000000..b1e7682c1d
--- /dev/null
+++ b/Documentation/includes/cmd-config-section-rest.txt
@@ -0,0 +1,3 @@
+Everything above this line in this section isn't included from the
+linkgit:git-config[1] documentation. The content that follows is the
+same as what's found there:
diff --git a/Documentation/install-doc-quick.sh b/Documentation/install-doc-quick.sh
new file mode 100755
index 0000000000..17231d8e59
--- /dev/null
+++ b/Documentation/install-doc-quick.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# This requires git-manpages and/or git-htmldocs repositories
+
+repository=${1?repository}
+destdir=${2?destination}
+GIT_MAN_REF=${3?master}
+
+GIT_DIR=
+for d in "$repository/.git" "$repository"
+do
+	if GIT_DIR="$d" git rev-parse "$GIT_MAN_REF" >/dev/null 2>&1
+	then
+		GIT_DIR="$d"
+		export GIT_DIR
+		break
+	fi
+done
+
+if test -z "$GIT_DIR"
+then
+	echo >&2 "Neither $repository nor $repository/.git is a repository"
+	exit 1
+fi
+
+GIT_WORK_TREE=$(pwd)
+GIT_INDEX_FILE=$(pwd)/.quick-doc.$$
+export GIT_INDEX_FILE GIT_WORK_TREE
+rm -f "$GIT_INDEX_FILE"
+trap 'rm -f "$GIT_INDEX_FILE"' 0
+
+git read-tree "$GIT_MAN_REF"
+git checkout-index -a -f --prefix="$destdir"/
+
+if test -n "$GZ"
+then
+	git ls-tree -r --name-only "$GIT_MAN_REF" |
+	xargs printf "$destdir/%s\n" |
+	xargs gzip -f
+fi
+rm -f "$GIT_INDEX_FILE"
diff --git a/Documentation/install-webdoc.sh b/Documentation/install-webdoc.sh
new file mode 100755
index 0000000000..ed8b4ff3e5
--- /dev/null
+++ b/Documentation/install-webdoc.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+T="$1"
+
+for h in \
+	*.txt *.html \
+	howto/*.txt howto/*.html \
+	technical/*.txt technical/*.html \
+	RelNotes/*.txt *.css
+do
+	if test ! -f "$h"
+	then
+		: did not match
+	elif test -f "$T/$h" &&
+		$DIFF -u -I'^Last updated ' "$T/$h" "$h"
+	then
+		:; # up to date
+	else
+		echo >&2 "# install $h $T/$h"
+		rm -f "$T/$h"
+		mkdir -p $(dirname "$T/$h")
+		cp "$h" "$T/$h"
+	fi
+done
+strip_leading=$(echo "$T/" | sed -e 's|.|.|g')
+for th in \
+	"$T"/*.html "$T"/*.txt \
+	"$T"/howto/*.txt "$T"/howto/*.html \
+	"$T"/technical/*.txt "$T"/technical/*.html
+do
+	h=$(expr "$th" : "$strip_leading"'\(.*\)')
+	case "$h" in
+	RelNotes-*.txt | index.html) continue ;;
+	esac
+	test -f "$h" && continue
+	echo >&2 "# rm -f $th"
+	rm -f "$th"
+done
+ln -sf git.html "$T/index.html"
diff --git a/Documentation/line-range-format.adoc b/Documentation/line-range-format.adoc
new file mode 100644
index 0000000000..9b51e9fb66
--- /dev/null
+++ b/Documentation/line-range-format.adoc
@@ -0,0 +1,32 @@
+'<start>' and '<end>' can take one of these forms:
+
+- number
++
+If '<start>' or '<end>' is a number, it specifies an
+absolute line number (lines count from 1).
++
+
+- `/regex/`
++
+This form will use the first line matching the given
+POSIX regex. If '<start>' is a regex, it will search from the end of
+the previous `-L` range, if any, otherwise from the start of file.
+If '<start>' is `^/regex/`, it will search from the start of file.
+If '<end>' is a regex, it will search
+starting at the line given by '<start>'.
++
+
+- +offset or -offset
++
+This is only valid for '<end>' and will specify a number
+of lines before or after the line given by '<start>'.
+
++
+If `:<funcname>` is given in place of '<start>' and '<end>', it is a
+regular expression that denotes the range from the first funcname line
+that matches '<funcname>', up to the next funcname line. `:<funcname>`
+searches from the end of the previous `-L` range, if any, otherwise
+from the start of file. `^:<funcname>` searches from the start of
+file. The function names are determined in the same way as `git diff`
+works out patch hunk headers (see 'Defining a custom hunk-header'
+in linkgit:gitattributes[5]).
diff --git a/Documentation/line-range-options.adoc b/Documentation/line-range-options.adoc
new file mode 100644
index 0000000000..f275df3b69
--- /dev/null
+++ b/Documentation/line-range-options.adoc
@@ -0,0 +1,15 @@
+-L<start>,<end>:<file>::
+-L:<funcname>:<file>::
+
+	Trace the evolution of the line range given by '<start>,<end>',
+	or by the function name regex '<funcname>', within the '<file>'. You may
+	not give any pathspec limiters.  This is currently limited to
+	a walk starting from a single revision, i.e., you may only
+	give zero or one positive revision arguments, and
+	'<start>' and '<end>' (or '<funcname>') must exist in the starting revision.
+	You can specify this option more than once. Implies `--patch`.
+	Patch output can be suppressed using `--no-patch`, but other diff formats
+	(namely `--raw`, `--numstat`, `--shortstat`, `--dirstat`, `--summary`,
+	`--name-only`, `--name-status`, `--check`) are not currently implemented.
++
+include::line-range-format.adoc[]
diff --git a/Documentation/lint-fsck-msgids.perl b/Documentation/lint-fsck-msgids.perl
new file mode 100755
index 0000000000..1233ffe815
--- /dev/null
+++ b/Documentation/lint-fsck-msgids.perl
@@ -0,0 +1,70 @@
+#!/usr/bin/perl
+
+my ($fsck_h, $fsck_msgids_txt, $okfile) = @ARGV;
+
+my (%in_fsck_h, $fh, $bad);
+
+open($fh, "<", "$fsck_h") or die;
+while (<$fh>) {
+	if (/^\s+FUNC\(([0-9A-Z_]+), ([A-Z]+)\)/) {
+		my ($name, $severity) = ($1, $2);
+		my ($first) = 1;
+		$name = join('',
+			     map {
+				     y/A-Z/a-z/;
+				     if (!$first) {
+					     s/^(.)/uc($1)/e;
+				     } else {
+					     $first = 0;
+				     }
+				     $_;
+			     }
+			     split(/_/, $name));
+		$in_fsck_h{$name} = $severity;
+	}
+}
+close($fh);
+
+open($fh, "<", "$fsck_msgids_txt") or die;
+my ($previous, $current);
+while (<$fh>) {
+	if (!defined $current) {
+		if (/^\`([a-zA-Z0-9]*)\`::/) {
+			$current = $1;
+			if ((defined $previous) &&
+			    ($current le $previous)) {
+				print STDERR "$previous >= $current in doc\n";
+				$bad = 1;
+			}
+		}
+	} elsif (/^\s+\(([A-Z]+)\) /) {
+		my ($level) = $1;
+		if (!exists $in_fsck_h{$current}) {
+			print STDERR "$current does not exist in fsck.h\n";
+			$bad = 1;
+		} elsif ($in_fsck_h{$current} eq "") {
+			print STDERR "$current defined twice\n";
+			$bad = 1;
+		} elsif ($in_fsck_h{$current} ne $level) {
+			print STDERR "$current severity $level != $in_fsck_h{$current}\n";
+			$bad = 1;
+		}
+		$previous = $current;
+		$in_fsck_h{$current} = ""; # mark as seen.
+		undef $current;
+	}
+}
+close($fh);
+
+for my $key (keys %in_fsck_h) {
+	if ($in_fsck_h{$key} ne "") {
+		print STDERR "$key not explained in doc.\n";
+		$bad = 1;
+	}
+}
+
+die if ($bad);
+
+open($fh, ">", "$okfile");
+print $fh "good\n";
+close($fh);
diff --git a/Documentation/lint-gitlink.perl b/Documentation/lint-gitlink.perl
new file mode 100755
index 0000000000..1c61dd9512
--- /dev/null
+++ b/Documentation/lint-gitlink.perl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+# Parse arguments, a simple state machine for input like:
+#
+# <file-to-check.txt> <valid-files-to-link-to> --section=1 git.txt git-add.txt [...] --to-lint git-add.txt a-file.txt [...]
+my %TXT;
+my %SECTION;
+my $section;
+my $lint_these = 0;
+my $to_check = shift @ARGV;
+for my $arg (@ARGV) {
+	if (my ($sec) = $arg =~ /^--section=(\d+)$/s) {
+		$section = $sec;
+		next;
+	}
+
+	my ($name) = $arg =~ /^(.*?)\.txt$/s;
+	unless (defined $section) {
+		$TXT{$name} = $arg;
+		next;
+	}
+
+	$SECTION{$name} = $section;
+}
+
+my $exit_code = 0;
+sub report {
+	my ($pos, $line, $target, $msg) = @_;
+	substr($line, $pos) = "' <-- HERE";
+	$line =~ s/^\s+//;
+	print STDERR "$ARGV:$.: error: $target: $msg, shown with 'HERE' below:\n";
+	print STDERR "$ARGV:$.:\t'$line\n";
+	$exit_code = 1;
+}
+
+@ARGV = sort values %TXT;
+die "BUG: No list of valid linkgit:* files given" unless @ARGV;
+@ARGV = $to_check;
+while (<>) {
+	my $line = $_;
+	while ($line =~ m/linkgit:((.*?)\[(\d)\])/g) {
+		my $pos = pos $line;
+		my ($target, $page, $section) = ($1, $2, $3);
+
+		# De-AsciiDoc
+		$page =~ s/{litdd}/--/g;
+
+		if (!exists $TXT{$page}) {
+			report($pos, $line, $target, "link outside of our own docs");
+			next;
+		}
+		if (!exists $SECTION{$page}) {
+			report($pos, $line, $target, "link outside of our sectioned docs");
+			next;
+		}
+		my $real_section = $SECTION{$page};
+		if ($section != $SECTION{$page}) {
+			report($pos, $line, $target, "wrong section (should be $real_section)");
+			next;
+		}
+	}
+	# this resets our $. for each file
+	close ARGV if eof;
+}
+
+exit $exit_code;
diff --git a/Documentation/lint-man-end-blurb.perl b/Documentation/lint-man-end-blurb.perl
new file mode 100755
index 0000000000..6bdb13ad9f
--- /dev/null
+++ b/Documentation/lint-man-end-blurb.perl
@@ -0,0 +1,24 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my $exit_code = 0;
+sub report {
+	my ($target, $msg) = @_;
+	print STDERR "error: $target: $msg\n";
+	$exit_code = 1;
+}
+
+local $/;
+while (my $slurp = <>) {
+	report($ARGV, "has no 'Part of the linkgit:git[1] suite' end blurb")
+		unless $slurp =~ m[
+		^GIT\n
+		 ---\n
+		\QPart of the linkgit:git[1] suite\E \n
+		\z
+	]mx;
+}
+
+exit $exit_code;
diff --git a/Documentation/lint-man-section-order.perl b/Documentation/lint-man-section-order.perl
new file mode 100755
index 0000000000..02408a0062
--- /dev/null
+++ b/Documentation/lint-man-section-order.perl
@@ -0,0 +1,108 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+my %SECTIONS;
+{
+	my $order = 0;
+	%SECTIONS = (
+		'NAME' => {
+			required => 1,
+			order => $order++,
+		},
+		'SYNOPSIS' => {
+			required => 1,
+			order => $order++,
+		},
+		'DESCRIPTION' => {
+			required => 1,
+			order => $order++,
+		},
+		'OPTIONS' => {
+			order => $order++,
+			required => 0,
+		},
+		'CONFIGURATION' => {
+			order => $order++,
+		},
+		'BUGS' => {
+			order => $order++,
+		},
+		'SEE ALSO' => {
+			order => $order++,
+		},
+		'FILE FORMAT' => {
+			order => $order++,
+		},
+		'GIT' => {
+			required => 1,
+			order => $order++,
+		},
+	);
+}
+my $SECTION_RX = do {
+	my ($names) = join "|", keys %SECTIONS;
+	qr/^($names)$/s;
+};
+
+my $exit_code = 0;
+sub report {
+	my ($msg) = @_;
+	print STDERR "$ARGV:$.: $msg\n";
+	$exit_code = 1;
+}
+
+my $last_was_section;
+my @actual_order;
+while (my $line = <>) {
+	chomp $line;
+	if ($line =~ $SECTION_RX) {
+		push @actual_order => $line;
+		$last_was_section = 1;
+		# Have no "last" section yet, processing NAME
+		next if @actual_order == 1;
+
+		my @expected_order = sort {
+			$SECTIONS{$a}->{order} <=> $SECTIONS{$b}->{order}
+		} @actual_order;
+
+		my $expected_last = $expected_order[-2];
+		my $actual_last = $actual_order[-2];
+		if ($actual_last ne $expected_last) {
+			report("section '$line' incorrectly ordered, comes after '$actual_last'");
+		}
+		next;
+	}
+	if ($last_was_section) {
+		my $last_section = $actual_order[-1];
+		if (length $last_section ne length $line) {
+			report("dashes under '$last_section' should match its length!");
+		}
+		if ($line !~ /^-+$/) {
+			report("dashes under '$last_section' should be '-' dashes!");
+		}
+		$last_was_section = 0;
+	}
+
+	if (eof) {
+		# We have both a hash and an array to consider, for
+		# convenience
+		my %actual_sections;
+		@actual_sections{@actual_order} = ();
+
+		for my $section (sort keys %SECTIONS) {
+			next if !$SECTIONS{$section}->{required} or exists $actual_sections{$section};
+			report("has no required '$section' section!");
+		}
+
+		# Reset per-file state
+		{
+			@actual_order = ();
+			# this resets our $. for each file
+			close ARGV;
+		}
+	}
+}
+
+exit $exit_code;
diff --git a/Documentation/lint-manpages.sh b/Documentation/lint-manpages.sh
new file mode 100755
index 0000000000..92cfc0a15a
--- /dev/null
+++ b/Documentation/lint-manpages.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+
+extract_variable () {
+	(
+		cat ../Makefile
+		cat <<EOF
+print_variable:
+	@\$(foreach b,\$($1),echo XXX \$(b:\$X=) YYY;)
+EOF
+	) |
+	make -C .. -f - print_variable 2>/dev/null |
+	sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p'
+}
+
+check_missing_docs () (
+	ret=0
+
+	for v in $ALL_COMMANDS
+	do
+		case "$v" in
+		git-merge-octopus) continue;;
+		git-merge-ours) continue;;
+		git-merge-recursive) continue;;
+		git-merge-resolve) continue;;
+		git-merge-subtree) continue;;
+		git-fsck-objects) continue;;
+		git-init-db) continue;;
+		git-remote-*) continue;;
+		git-stage) continue;;
+		git-legacy-*) continue;;
+		git-?*--?* ) continue ;;
+		esac
+
+		if ! test -f "$v.txt"
+		then
+			echo "no doc: $v"
+			ret=1
+		fi
+
+		if ! sed -e '1,/^### command list/d' -e '/^#/d' ../command-list.txt |
+			grep -q "^$v[ 	]"
+		then
+			case "$v" in
+			git)
+				;;
+			*)
+				echo "no link: $v"
+				ret=1
+				;;
+			esac
+		fi
+	done
+
+	exit $ret
+)
+
+check_extraneous_docs () {
+	(
+		sed -e '1,/^### command list/d' \
+		    -e '/^#/d' \
+		    -e '/guide$/d' \
+		    -e '/interfaces$/d' \
+		    -e 's/[ 	].*//' \
+		    -e 's/^/listed /' ../command-list.txt
+		make print-man1 |
+		grep '\.txt$' |
+		sed -e 's|^|documented |' \
+		    -e 's/\.txt//'
+	) | (
+		all_commands="$(printf "%s " "$ALL_COMMANDS" "$BUILT_INS" "$EXCLUDED_PROGRAMS" | tr '\n' ' ')"
+		ret=0
+
+		while read how cmd
+		do
+			case " $all_commands " in
+			*" $cmd "*) ;;
+			*)
+				echo "removed but $how: $cmd"
+				ret=1;;
+			esac
+		done
+
+		exit $ret
+	)
+}
+
+BUILT_INS="$(extract_variable BUILT_INS)"
+ALL_COMMANDS="$(extract_variable ALL_COMMANDS)"
+EXCLUDED_PROGRAMS="$(extract_variable EXCLUDED_PROGRAMS)"
+
+findings=$(
+	if ! check_missing_docs
+	then
+		ret=1
+	fi
+
+	if ! check_extraneous_docs
+	then
+		ret=1
+	fi
+
+	exit $ret
+)
+ret=$?
+
+printf "%s" "$findings" | sort
+
+exit $ret
diff --git a/Documentation/manpage-bold-literal.xsl b/Documentation/manpage-bold-literal.xsl
new file mode 100644
index 0000000000..e13db85693
--- /dev/null
+++ b/Documentation/manpage-bold-literal.xsl
@@ -0,0 +1,16 @@
+<!-- manpage-bold-literal.xsl:
+     special formatting for manpages rendered from asciidoc+docbook -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+		xmlns:d="http://docbook.org/ns/docbook";
+		version="1.0">
+
+<!-- render literal text as bold (instead of plain or monospace);
+     this makes literal text easier to distinguish in manpages
+     viewed on a tty -->
+<xsl:template match="literal|d:literal">
+	<xsl:text>\fB</xsl:text>
+	<xsl:apply-templates/>
+	<xsl:text>\fR</xsl:text>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/Documentation/manpage-normal.xsl b/Documentation/manpage-normal.xsl
new file mode 100644
index 0000000000..beb5ff8ec2
--- /dev/null
+++ b/Documentation/manpage-normal.xsl
@@ -0,0 +1,14 @@
+<!-- manpage-normal.xsl:
+     special settings for manpages rendered from asciidoc+docbook -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+		version="1.0">
+
+
+<!-- these params silence some output from xmlto -->
+<xsl:param name="man.output.quietly" select="1"/>
+<xsl:param name="refentry.meta.get.quietly" select="1"/>
+
+<!-- unset maximum length of title -->
+<xsl:param name="man.th.title.max.length"/>
+
+</xsl:stylesheet>
diff --git a/Documentation/manpage.xsl b/Documentation/manpage.xsl
new file mode 100644
index 0000000000..ef64bab17a
--- /dev/null
+++ b/Documentation/manpage.xsl
@@ -0,0 +1,3 @@
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
+	<xsl:import href="http://docbook.sourceforge.net/release/xsl-ns/current/manpages/docbook.xsl"; />
+</xsl:stylesheet>
diff --git a/Documentation/merge-options.adoc b/Documentation/merge-options.adoc
new file mode 100644
index 0000000000..0022185201
--- /dev/null
+++ b/Documentation/merge-options.adoc
@@ -0,0 +1,210 @@
+--commit::
+--no-commit::
+	Perform the merge and commit the result. This option can
+	be used to override --no-commit.
+ifdef::git-pull[]
+	Only useful when merging.
+endif::git-pull[]
++
+With --no-commit perform the merge and stop just before creating
+a merge commit, to give the user a chance to inspect and further
+tweak the merge result before committing.
++
+Note that fast-forward updates do not create a merge commit and
+therefore there is no way to stop those merges with --no-commit.
+Thus, if you want to ensure your branch is not changed or updated
+by the merge command, use --no-ff with --no-commit.
+
+--edit::
+-e::
+--no-edit::
+	Invoke an editor before committing successful mechanical merge to
+	further edit the auto-generated merge message, so that the user
+	can explain and justify the merge. The `--no-edit` option can be
+	used to accept the auto-generated message (this is generally
+	discouraged).
+ifndef::git-pull[]
+The `--edit` (or `-e`) option is still useful if you are
+giving a draft message with the `-m` option from the command line
+and want to edit it in the editor.
+endif::git-pull[]
++
+Older scripts may depend on the historical behaviour of not allowing the
+user to edit the merge log message. They will see an editor opened when
+they run `git merge`. To make it easier to adjust such scripts to the
+updated behaviour, the environment variable `GIT_MERGE_AUTOEDIT` can be
+set to `no` at the beginning of them.
+
+--cleanup=<mode>::
+	This option determines how the merge message will be cleaned up before
+	committing. See linkgit:git-commit[1] for more details. In addition, if
+	the '<mode>' is given a value of `scissors`, scissors will be appended
+	to `MERGE_MSG` before being passed on to the commit machinery in the
+	case of a merge conflict.
+
+ifdef::git-merge[]
+--ff::
+--no-ff::
+--ff-only::
+	Specifies how a merge is handled when the merged-in history is
+	already a descendant of the current history.  `--ff` is the
+	default unless merging an annotated (and possibly signed) tag
+	that is not stored in its natural place in the `refs/tags/`
+	hierarchy, in which case `--no-ff` is assumed.
+endif::git-merge[]
+ifdef::git-pull[]
+--ff-only::
+	Only update to the new history if there is no divergent local
+	history.  This is the default when no method for reconciling
+	divergent histories is provided (via the --rebase=* flags).
+
+--ff::
+--no-ff::
+	When merging rather than rebasing, specifies how a merge is
+	handled when the merged-in history is already a descendant of
+	the current history.  If merging is requested, `--ff` is the
+	default unless merging an annotated (and possibly signed) tag
+	that is not stored in its natural place in the `refs/tags/`
+	hierarchy, in which case `--no-ff` is assumed.
+endif::git-pull[]
++
+With `--ff`, when possible resolve the merge as a fast-forward (only
+update the branch pointer to match the merged branch; do not create a
+merge commit).  When not possible (when the merged-in history is not a
+descendant of the current history), create a merge commit.
++
+With `--no-ff`, create a merge commit in all cases, even when the merge
+could instead be resolved as a fast-forward.
+ifdef::git-merge[]
++
+With `--ff-only`, resolve the merge as a fast-forward when possible.
+When not possible, refuse to merge and exit with a non-zero status.
+endif::git-merge[]
+
+-S[<keyid>]::
+--gpg-sign[=<keyid>]::
+--no-gpg-sign::
+	GPG-sign the resulting merge commit. The `keyid` argument is
+	optional and defaults to the committer identity; if specified,
+	it must be stuck to the option without a space. `--no-gpg-sign`
+	is useful to countermand both `commit.gpgSign` configuration variable,
+	and earlier `--gpg-sign`.
+
+--log[=<n>]::
+--no-log::
+	In addition to branch names, populate the log message with
+	one-line descriptions from at most <n> actual commits that are being
+	merged. See also linkgit:git-fmt-merge-msg[1].
+ifdef::git-pull[]
+	Only useful when merging.
+endif::git-pull[]
++
+With --no-log do not list one-line descriptions from the
+actual commits being merged.
+
+include::signoff-option.adoc[]
+
+--stat::
+-n::
+--no-stat::
+	Show a diffstat at the end of the merge. The diffstat is also
+	controlled by the configuration option merge.stat.
++
+With -n or --no-stat do not show a diffstat at the end of the
+merge.
+
+--squash::
+--no-squash::
+	Produce the working tree and index state as if a real merge
+	happened (except for the merge information), but do not actually
+	make a commit, move the `HEAD`, or record `$GIT_DIR/MERGE_HEAD`
+	(to cause the next `git commit` command to create a merge
+	commit).  This allows you to create a single commit on top of
+	the current branch whose effect is the same as merging another
+	branch (or more in case of an octopus).
++
+With --no-squash perform the merge and commit the result. This
+option can be used to override --squash.
++
+With --squash, --commit is not allowed, and will fail.
+ifdef::git-pull[]
++
+Only useful when merging.
+endif::git-pull[]
+
+--[no-]verify::
+	By default, the pre-merge and commit-msg hooks are run.
+	When `--no-verify` is given, these are bypassed.
+	See also linkgit:githooks[5].
+ifdef::git-pull[]
+	Only useful when merging.
+endif::git-pull[]
+
+-s <strategy>::
+--strategy=<strategy>::
+	Use the given merge strategy; can be supplied more than
+	once to specify them in the order they should be tried.
+	If there is no `-s` option, a built-in list of strategies
+	is used instead (`ort` when merging a single head,
+	`octopus` otherwise).
+
+-X <option>::
+--strategy-option=<option>::
+	Pass merge strategy specific option through to the merge
+	strategy.
+
+--verify-signatures::
+--no-verify-signatures::
+	Verify that the tip commit of the side branch being merged is
+	signed with a valid key, i.e. a key that has a valid uid: in the
+	default trust model, this means the signing key has been signed by
+	a trusted key.  If the tip commit of the side branch is not signed
+	with a valid key, the merge is aborted.
+ifdef::git-pull[]
++
+Only useful when merging.
+endif::git-pull[]
+
+--summary::
+--no-summary::
+	Synonyms to --stat and --no-stat; these are deprecated and will be
+	removed in the future.
+
+ifndef::git-pull[]
+-q::
+--quiet::
+	Operate quietly. Implies --no-progress.
+
+-v::
+--verbose::
+	Be verbose.
+
+--progress::
+--no-progress::
+	Turn progress on/off explicitly. If neither is specified,
+	progress is shown if standard error is connected to a terminal.
+	Note that not all merge strategies may support progress
+	reporting.
+
+endif::git-pull[]
+
+--autostash::
+--no-autostash::
+	Automatically create a temporary stash entry before the operation
+	begins, record it in the ref `MERGE_AUTOSTASH`
+	and apply it after the operation ends.  This means
+	that you can run the operation on a dirty worktree.  However, use
+	with care: the final stash application after a successful
+	merge might result in non-trivial conflicts.
+
+--allow-unrelated-histories::
+	By default, `git merge` command refuses to merge histories
+	that do not share a common ancestor.  This option can be
+	used to override this safety when merging histories of two
+	projects that started their lives independently. As that is
+	a very rare occasion, no configuration variable to enable
+	this by default exists and will not be added.
+ifdef::git-pull[]
++
+Only useful when merging.
+endif::git-pull[]
diff --git a/Documentation/merge-strategies.adoc b/Documentation/merge-strategies.adoc
new file mode 100644
index 0000000000..5fc54ec060
--- /dev/null
+++ b/Documentation/merge-strategies.adoc
@@ -0,0 +1,153 @@
+MERGE STRATEGIES
+----------------
+
+The merge mechanism (`git merge` and `git pull` commands) allows the
+backend 'merge strategies' to be chosen with `-s` option.  Some strategies
+can also take their own options, which can be passed by giving `-X<option>`
+arguments to `git merge` and/or `git pull`.
+
+ort::
+	This is the default merge strategy when pulling or merging one
+	branch.  This strategy can only resolve two heads using a
+	3-way merge algorithm.  When there is more than one common
+	ancestor that can be used for 3-way merge, it creates a merged
+	tree of the common ancestors and uses that as the reference
+	tree for the 3-way merge.  This has been reported to result in
+	fewer merge conflicts without causing mismerges by tests done
+	on actual merge commits taken from Linux 2.6 kernel
+	development history.  Additionally this strategy can detect
+	and handle merges involving renames.  It does not make use of
+	detected copies.  The name for this algorithm is an acronym
+	("Ostensibly Recursive's Twin") and came from the fact that it
+	was written as a replacement for the previous default
+	algorithm, `recursive`.
++
+The 'ort' strategy can take the following options:
+
+ours;;
+	This option forces conflicting hunks to be auto-resolved cleanly by
+	favoring 'our' version.  Changes from the other tree that do not
+	conflict with our side are reflected in the merge result.
+	For a binary file, the entire contents are taken from our side.
++
+This should not be confused with the 'ours' merge strategy, which does not
+even look at what the other tree contains at all.  It discards everything
+the other tree did, declaring 'our' history contains all that happened in it.
+
+theirs;;
+	This is the opposite of 'ours'; note that, unlike 'ours', there is
+	no 'theirs' merge strategy to confuse this merge option with.
+
+ignore-space-change;;
+ignore-all-space;;
+ignore-space-at-eol;;
+ignore-cr-at-eol;;
+	Treats lines with the indicated type of whitespace change as
+	unchanged for the sake of a three-way merge.  Whitespace
+	changes mixed with other changes to a line are not ignored.
+	See also linkgit:git-diff[1] `-b`, `-w`,
+	`--ignore-space-at-eol`, and `--ignore-cr-at-eol`.
++
+* If 'their' version only introduces whitespace changes to a line,
+  'our' version is used;
+* If 'our' version introduces whitespace changes but 'their'
+  version includes a substantial change, 'their' version is used;
+* Otherwise, the merge proceeds in the usual way.
+
+renormalize;;
+	This runs a virtual check-out and check-in of all three stages
+	of a file when resolving a three-way merge.  This option is
+	meant to be used when merging branches with different clean
+	filters or end-of-line normalization rules.  See "Merging
+	branches with differing checkin/checkout attributes" in
+	linkgit:gitattributes[5] for details.
+
+no-renormalize;;
+	Disables the `renormalize` option.  This overrides the
+	`merge.renormalize` configuration variable.
+
+find-renames[=<n>];;
+	Turn on rename detection, optionally setting the similarity
+	threshold.  This is the default. This overrides the
+	'merge.renames' configuration variable.
+	See also linkgit:git-diff[1] `--find-renames`.
+
+rename-threshold=<n>;;
+	Deprecated synonym for `find-renames=<n>`.
+
+subtree[=<path>];;
+	This option is a more advanced form of 'subtree' strategy, where
+	the strategy makes a guess on how two trees must be shifted to
+	match with each other when merging.  Instead, the specified path
+	is prefixed (or stripped from the beginning) to make the shape of
+	two trees to match.
+
+recursive::
+	This can only resolve two heads using a 3-way merge
+	algorithm.  When there is more than one common
+	ancestor that can be used for 3-way merge, it creates a
+	merged tree of the common ancestors and uses that as
+	the reference tree for the 3-way merge.  This has been
+	reported to result in fewer merge conflicts without
+	causing mismerges by tests done on actual merge commits
+	taken from Linux 2.6 kernel development history.
+	Additionally this can detect and handle merges involving
+	renames.  It does not make use of detected copies.  This was
+	the default strategy for resolving two heads from Git v0.99.9k
+	until v2.33.0.
++
+The 'recursive' strategy takes the same options as 'ort'.  However,
+there are three additional options that 'ort' ignores (not documented
+above) that are potentially useful with the 'recursive' strategy:
+
+patience;;
+	Deprecated synonym for `diff-algorithm=patience`.
+
+diff-algorithm=[patience|minimal|histogram|myers];;
+	Use a different diff algorithm while merging, which can help
+	avoid mismerges that occur due to unimportant matching lines
+	(such as braces from distinct functions).  See also
+	linkgit:git-diff[1] `--diff-algorithm`.  Note that `ort`
+	specifically uses `diff-algorithm=histogram`, while `recursive`
+	defaults to the `diff.algorithm` config setting.
+
+no-renames;;
+	Turn off rename detection. This overrides the `merge.renames`
+	configuration variable.
+	See also linkgit:git-diff[1] `--no-renames`.
+
+resolve::
+	This can only resolve two heads (i.e. the current branch
+	and another branch you pulled from) using a 3-way merge
+	algorithm.  It tries to carefully detect criss-cross
+	merge ambiguities.  It does not handle renames.
+
+octopus::
+	This resolves cases with more than two heads, but refuses to do
+	a complex merge that needs manual resolution.  It is
+	primarily meant to be used for bundling topic branch
+	heads together.  This is the default merge strategy when
+	pulling or merging more than one branch.
+
+ours::
+	This resolves any number of heads, but the resulting tree of the
+	merge is always that of the current branch head, effectively
+	ignoring all changes from all other branches.  It is meant to
+	be used to supersede old development history of side
+	branches.  Note that this is different from the -Xours option to
+	the 'recursive' merge strategy.
+
+subtree::
+	This is a modified `ort` strategy. When merging trees A and
+	B, if B corresponds to a subtree of A, B is first adjusted to
+	match the tree structure of A, instead of reading the trees at
+	the same level. This adjustment is also done to the common
+	ancestor tree.
+
+With the strategies that use 3-way merge (including the default, 'ort'),
+if a change is made on both branches, but later reverted on one of the
+branches, that change will be present in the merged result; some people find
+this behavior confusing.  It occurs because only the heads and the merge base
+are considered when performing a merge, not the individual commits.  The merge
+algorithm therefore considers the reverted change as no change at all, and
+substitutes the changed version instead.
diff --git a/Documentation/mergetools/vimdiff.txt b/Documentation/mergetools/vimdiff.txt
new file mode 100644
index 0000000000..befa86d692
--- /dev/null
+++ b/Documentation/mergetools/vimdiff.txt
@@ -0,0 +1,195 @@
+Description
+^^^^^^^^^^^
+
+When specifying `--tool=vimdiff` in `git mergetool` Git will open Vim with a 4
+windows layout distributed in the following way:
+....
+------------------------------------------
+|             |           |              |
+|   LOCAL     |   BASE    |   REMOTE     |
+|             |           |              |
+------------------------------------------
+|                                        |
+|                MERGED                  |
+|                                        |
+------------------------------------------
+....
+`LOCAL`, `BASE` and `REMOTE` are read-only buffers showing the contents of the
+conflicting file in specific commits ("commit you are merging into", "common
+ancestor commit" and "commit you are merging from" respectively)
+
+`MERGED` is a writable buffer where you have to resolve the conflicts (using the
+other read-only buffers as a reference). Once you are done, save and exit Vim as
+usual (`:wq`) or, if you want to abort, exit using `:cq`.
+
+Layout configuration
+^^^^^^^^^^^^^^^^^^^^
+
+You can change the windows layout used by Vim by setting configuration variable
+`mergetool.vimdiff.layout` which accepts a string where the following separators
+have special meaning:
+
+  - `+` is used to "open a new tab"
+  - `,` is used to "open a new vertical split"
+  - `/` is used to "open a new horizontal split"
+  - `@` is used to indicate the file containing the final version after
+    solving the conflicts. If not present, `MERGED` will be used by default.
+
+The precedence of the operators is as follows (you can use parentheses to change
+it):
+
+    `@` > `+` > `/` > `,`
+
+Let's see some examples to understand how it works:
+
+* `layout = "(LOCAL,BASE,REMOTE)/MERGED"`
++
+--
+This is exactly the same as the default layout we have already seen.
+
+Note that `/` has precedence over `,` and thus the parenthesis are not
+needed in this case. The next layout definition is equivalent:
+
+    layout = "LOCAL,BASE,REMOTE / MERGED"
+--
+* `layout = "LOCAL,MERGED,REMOTE"`
++
+--
+If, for some reason, we are not interested in the `BASE` buffer.
+....
+------------------------------------------
+|             |           |              |
+|             |           |              |
+|   LOCAL     |   MERGED  |   REMOTE     |
+|             |           |              |
+|             |           |              |
+------------------------------------------
+....
+--
+* `layout = "MERGED"`
++
+--
+Only the `MERGED` buffer will be shown. Note, however, that all the other
+ones are still loaded in vim, and you can access them with the "buffers"
+command.
+....
+------------------------------------------
+|                                        |
+|                                        |
+|                 MERGED                 |
+|                                        |
+|                                        |
+------------------------------------------
+....
+--
+* `layout = "@LOCAL,REMOTE"`
++
+--
+When `MERGED` is not present in the layout, you must "mark" one of the
+buffers with an asterisk. That will become the buffer you need to edit and
+save after resolving the conflicts.
+....
+------------------------------------------
+|                   |                    |
+|                   |                    |
+|                   |                    |
+|     LOCAL         |    REMOTE          |
+|                   |                    |
+|                   |                    |
+|                   |                    |
+------------------------------------------
+....
+--
+* `layout = "LOCAL,BASE,REMOTE / MERGED + BASE,LOCAL + BASE,REMOTE"`
++
+--
+Three tabs will open: the first one is a copy of the default layout, while
+the other two only show the differences between (`BASE` and `LOCAL`) and
+(`BASE` and `REMOTE`) respectively.
+....
+------------------------------------------
+| <TAB #1> |  TAB #2  |  TAB #3  |       |
+------------------------------------------
+|             |           |              |
+|   LOCAL     |   BASE    |   REMOTE     |
+|             |           |              |
+------------------------------------------
+|                                        |
+|                MERGED                  |
+|                                        |
+------------------------------------------
+....
+....
+------------------------------------------
+|  TAB #1  | <TAB #2> |  TAB #3  |       |
+------------------------------------------
+|                   |                    |
+|                   |                    |
+|                   |                    |
+|     BASE          |    LOCAL           |
+|                   |                    |
+|                   |                    |
+|                   |                    |
+------------------------------------------
+....
+....
+------------------------------------------
+|  TAB #1  |  TAB #2  | <TAB #3> |       |
+------------------------------------------
+|                   |                    |
+|                   |                    |
+|                   |                    |
+|     BASE          |    REMOTE          |
+|                   |                    |
+|                   |                    |
+|                   |                    |
+------------------------------------------
+....
+--
+* `layout = "LOCAL,BASE,REMOTE / MERGED + BASE,LOCAL + BASE,REMOTE + (LOCAL/BASE/REMOTE),MERGED"`
++
+--
+Same as the previous example, but adds a fourth tab with the same
+information as the first tab, with a different layout.
+....
+---------------------------------------------
+|  TAB #1  |  TAB #2  |  TAB #3  | <TAB #4> |
+---------------------------------------------
+|       LOCAL         |                     |
+|---------------------|                     |
+|       BASE          |        MERGED       |
+|---------------------|                     |
+|       REMOTE        |                     |
+---------------------------------------------
+....
+Note how in the third tab definition we need to use parentheses to make `,`
+have precedence over `/`.
+--
+
+Variants
+^^^^^^^^
+
+Instead of `--tool=vimdiff`, you can also use one of these other variants:
+
+  * `--tool=gvimdiff`, to open gVim instead of Vim.
+
+  * `--tool=nvimdiff`, to open Neovim instead of Vim.
+
+When using these variants, in order to specify a custom layout you will have to
+set configuration variables `mergetool.gvimdiff.layout` and
+`mergetool.nvimdiff.layout` instead of `mergetool.vimdiff.layout` (though the
+latter will be used as fallback if the variant-specific one is not set).
+
+In addition, for backwards compatibility with previous Git versions, you can
+also append `1`, `2` or `3` to either `vimdiff` or any of the variants (ex:
+`vimdiff3`, `nvimdiff1`, etc...) to use a predefined layout.
+In other words, using `--tool=[g,n,]vimdiffx` is the same as using
+`--tool=[g,n,]vimdiff` and setting configuration variable
+`mergetool.[g,n,]vimdiff.layout` to...
+
+  * `x=1`: `"@LOCAL, REMOTE"`
+  * `x=2`: `"LOCAL, MERGED, REMOTE"`
+  * `x=3`: `"MERGED"`
+
+Example: using `--tool=gvimdiff2` will open `gvim` with three columns (LOCAL,
+MERGED and REMOTE).
diff --git a/Documentation/meson.build b/Documentation/meson.build
new file mode 100644
index 0000000000..a479094ae6
--- /dev/null
+++ b/Documentation/meson.build
@@ -0,0 +1,504 @@
+manpages = {
+  # Category 1.
+  'git-add.adoc' : 1,
+  'git-am.adoc' : 1,
+  'git-annotate.adoc' : 1,
+  'git-apply.adoc' : 1,
+  'git-archimport.adoc' : 1,
+  'git-archive.adoc' : 1,
+  'git-bisect.adoc' : 1,
+  'git-blame.adoc' : 1,
+  'git-branch.adoc' : 1,
+  'git-bugreport.adoc' : 1,
+  'git-bundle.adoc' : 1,
+  'git-cat-file.adoc' : 1,
+  'git-check-attr.adoc' : 1,
+  'git-check-ignore.adoc' : 1,
+  'git-check-mailmap.adoc' : 1,
+  'git-checkout-index.adoc' : 1,
+  'git-checkout.adoc' : 1,
+  'git-check-ref-format.adoc' : 1,
+  'git-cherry-pick.adoc' : 1,
+  'git-cherry.adoc' : 1,
+  'git-citool.adoc' : 1,
+  'git-clean.adoc' : 1,
+  'git-clone.adoc' : 1,
+  'git-column.adoc' : 1,
+  'git-commit-graph.adoc' : 1,
+  'git-commit-tree.adoc' : 1,
+  'git-commit.adoc' : 1,
+  'git-config.adoc' : 1,
+  'git-count-objects.adoc' : 1,
+  'git-credential-cache--daemon.adoc' : 1,
+  'git-credential-cache.adoc' : 1,
+  'git-credential-store.adoc' : 1,
+  'git-credential.adoc' : 1,
+  'git-cvsexportcommit.adoc' : 1,
+  'git-cvsimport.adoc' : 1,
+  'git-cvsserver.adoc' : 1,
+  'git-daemon.adoc' : 1,
+  'git-describe.adoc' : 1,
+  'git-diagnose.adoc' : 1,
+  'git-diff-files.adoc' : 1,
+  'git-diff-index.adoc' : 1,
+  'git-difftool.adoc' : 1,
+  'git-diff-tree.adoc' : 1,
+  'git-diff.adoc' : 1,
+  'git-fast-export.adoc' : 1,
+  'git-fast-import.adoc' : 1,
+  'git-fetch-pack.adoc' : 1,
+  'git-fetch.adoc' : 1,
+  'git-filter-branch.adoc' : 1,
+  'git-fmt-merge-msg.adoc' : 1,
+  'git-for-each-ref.adoc' : 1,
+  'git-for-each-repo.adoc' : 1,
+  'git-format-patch.adoc' : 1,
+  'git-fsck-objects.adoc' : 1,
+  'git-fsck.adoc' : 1,
+  'git-fsmonitor--daemon.adoc' : 1,
+  'git-gc.adoc' : 1,
+  'git-get-tar-commit-id.adoc' : 1,
+  'git-grep.adoc' : 1,
+  'git-gui.adoc' : 1,
+  'git-hash-object.adoc' : 1,
+  'git-help.adoc' : 1,
+  'git-hook.adoc' : 1,
+  'git-http-backend.adoc' : 1,
+  'git-http-fetch.adoc' : 1,
+  'git-http-push.adoc' : 1,
+  'git-imap-send.adoc' : 1,
+  'git-index-pack.adoc' : 1,
+  'git-init-db.adoc' : 1,
+  'git-init.adoc' : 1,
+  'git-instaweb.adoc' : 1,
+  'git-interpret-trailers.adoc' : 1,
+  'git-log.adoc' : 1,
+  'git-ls-files.adoc' : 1,
+  'git-ls-remote.adoc' : 1,
+  'git-ls-tree.adoc' : 1,
+  'git-mailinfo.adoc' : 1,
+  'git-mailsplit.adoc' : 1,
+  'git-maintenance.adoc' : 1,
+  'git-merge-base.adoc' : 1,
+  'git-merge-file.adoc' : 1,
+  'git-merge-index.adoc' : 1,
+  'git-merge-one-file.adoc' : 1,
+  'git-mergetool--lib.adoc' : 1,
+  'git-mergetool.adoc' : 1,
+  'git-merge-tree.adoc' : 1,
+  'git-merge.adoc' : 1,
+  'git-mktag.adoc' : 1,
+  'git-mktree.adoc' : 1,
+  'git-multi-pack-index.adoc' : 1,
+  'git-mv.adoc' : 1,
+  'git-name-rev.adoc' : 1,
+  'git-notes.adoc' : 1,
+  'git-p4.adoc' : 1,
+  'git-pack-objects.adoc' : 1,
+  'git-pack-redundant.adoc' : 1,
+  'git-pack-refs.adoc' : 1,
+  'git-patch-id.adoc' : 1,
+  'git-prune-packed.adoc' : 1,
+  'git-prune.adoc' : 1,
+  'git-pull.adoc' : 1,
+  'git-push.adoc' : 1,
+  'git-quiltimport.adoc' : 1,
+  'git-range-diff.adoc' : 1,
+  'git-read-tree.adoc' : 1,
+  'git-rebase.adoc' : 1,
+  'git-receive-pack.adoc' : 1,
+  'git-reflog.adoc' : 1,
+  'git-refs.adoc' : 1,
+  'git-remote-ext.adoc' : 1,
+  'git-remote-fd.adoc' : 1,
+  'git-remote.adoc' : 1,
+  'git-repack.adoc' : 1,
+  'git-replace.adoc' : 1,
+  'git-replay.adoc' : 1,
+  'git-request-pull.adoc' : 1,
+  'git-rerere.adoc' : 1,
+  'git-reset.adoc' : 1,
+  'git-restore.adoc' : 1,
+  'git-revert.adoc' : 1,
+  'git-rev-list.adoc' : 1,
+  'git-rev-parse.adoc' : 1,
+  'git-rm.adoc' : 1,
+  'git-send-email.adoc' : 1,
+  'git-send-pack.adoc' : 1,
+  'git-shell.adoc' : 1,
+  'git-sh-i18n--envsubst.adoc' : 1,
+  'git-sh-i18n.adoc' : 1,
+  'git-shortlog.adoc' : 1,
+  'git-show-branch.adoc' : 1,
+  'git-show-index.adoc' : 1,
+  'git-show-ref.adoc' : 1,
+  'git-show.adoc' : 1,
+  'git-sh-setup.adoc' : 1,
+  'git-sparse-checkout.adoc' : 1,
+  'git-stage.adoc' : 1,
+  'git-stash.adoc' : 1,
+  'git-status.adoc' : 1,
+  'git-stripspace.adoc' : 1,
+  'git-submodule.adoc' : 1,
+  'git-svn.adoc' : 1,
+  'git-switch.adoc' : 1,
+  'git-symbolic-ref.adoc' : 1,
+  'git-tag.adoc' : 1,
+  'git-unpack-file.adoc' : 1,
+  'git-unpack-objects.adoc' : 1,
+  'git-update-index.adoc' : 1,
+  'git-update-ref.adoc' : 1,
+  'git-update-server-info.adoc' : 1,
+  'git-upload-archive.adoc' : 1,
+  'git-upload-pack.adoc' : 1,
+  'git-var.adoc' : 1,
+  'git-verify-commit.adoc' : 1,
+  'git-verify-pack.adoc' : 1,
+  'git-verify-tag.adoc' : 1,
+  'git-version.adoc' : 1,
+  'git-web--browse.adoc' : 1,
+  'git-whatchanged.adoc' : 1,
+  'git-worktree.adoc' : 1,
+  'git-write-tree.adoc' : 1,
+  'git.adoc' : 1,
+  'gitk.adoc' : 1,
+  'gitweb.adoc' : 1,
+  'scalar.adoc' : 1,
+
+  # Category 5.
+  'gitattributes.adoc' : 5,
+  'gitformat-bundle.adoc' : 5,
+  'gitformat-chunk.adoc' : 5,
+  'gitformat-commit-graph.adoc' : 5,
+  'gitformat-index.adoc' : 5,
+  'gitformat-pack.adoc' : 5,
+  'gitformat-signature.adoc' : 5,
+  'githooks.adoc' : 5,
+  'gitignore.adoc' : 5,
+  'gitmailmap.adoc' : 5,
+  'gitmodules.adoc' : 5,
+  'gitprotocol-capabilities.adoc' : 5,
+  'gitprotocol-common.adoc' : 5,
+  'gitprotocol-http.adoc' : 5,
+  'gitprotocol-pack.adoc' : 5,
+  'gitprotocol-v2.adoc' : 5,
+  'gitrepository-layout.adoc' : 5,
+  'gitweb.conf.adoc' : 5,
+
+  # Category 7.
+  'gitcli.adoc' : 7,
+  'gitcore-tutorial.adoc' : 7,
+  'gitcredentials.adoc' : 7,
+  'gitcvs-migration.adoc' : 7,
+  'gitdiffcore.adoc' : 7,
+  'giteveryday.adoc' : 7,
+  'gitfaq.adoc' : 7,
+  'gitglossary.adoc' : 7,
+  'gitpacking.adoc' : 7,
+  'gitnamespaces.adoc' : 7,
+  'gitremote-helpers.adoc' : 7,
+  'gitrevisions.adoc' : 7,
+  'gitsubmodules.adoc' : 7,
+  'gittutorial-2.adoc' : 7,
+  'gittutorial.adoc' : 7,
+  'gitworkflows.adoc' : 7,
+}
+
+docs_backend = get_option('docs_backend')
+if docs_backend == 'auto'
+  if find_program('asciidoc', required: false).found()
+    docs_backend = 'asciidoc'
+  elif find_program('asciidoctor', required: false).found()
+    docs_backend = 'asciidoctor'
+  else
+    error('Neither asciidoc nor asciidoctor were found.')
+  endif
+endif
+
+if docs_backend == 'asciidoc'
+  asciidoc = find_program('asciidoc', required: true)
+  asciidoc_html = 'xhtml11'
+  asciidoc_docbook = 'docbook'
+  xmlto_extra = [ ]
+
+  asciidoc_conf = custom_target(
+    command: [
+      shell,
+      meson.project_source_root() / 'GIT-VERSION-GEN',
+      meson.project_source_root(),
+      '@INPUT@',
+      '@OUTPUT@',
+    ],
+    input: 'asciidoc.conf.in',
+    output: 'asciidoc.conf',
+    depends: [git_version_file],
+    env: version_gen_environment,
+  )
+
+  asciidoc_common_options = [
+    asciidoc,
+    '--conf-file=' + asciidoc_conf.full_path(),
+    '--attribute=build_dir=' + meson.current_build_dir(),
+  ]
+
+  documentation_deps = [
+    asciidoc_conf,
+  ]
+elif docs_backend == 'asciidoctor'
+  asciidoctor = find_program('asciidoctor', required: true)
+  asciidoc_html = 'xhtml5'
+  asciidoc_docbook = 'docbook5'
+  xmlto_extra = [
+    '--skip-validation',
+    '-x', meson.current_source_dir() / 'manpage.xsl',
+  ]
+
+  asciidoctor_extensions = custom_target(
+    command: [
+      shell,
+      meson.project_source_root() / 'GIT-VERSION-GEN',
+      meson.project_source_root(),
+      '@INPUT@',
+      '@OUTPUT@',
+    ],
+    input: 'asciidoctor-extensions.rb.in',
+    output: 'asciidoctor-extensions.rb',
+    depends: [git_version_file],
+    env: version_gen_environment,
+  )
+
+  asciidoc_common_options = [
+    asciidoctor,
+    '--attribute', 'compat-mode',
+    '--attribute', 'tabsize=8',
+    '--attribute', 'litdd=&#x2d;&#x2d;',
+    '--attribute', 'docinfo=shared',
+    '--attribute', 'build_dir=' + meson.current_build_dir(),
+    '--load-path', meson.current_build_dir(),
+    '--require', 'asciidoctor-extensions',
+  ]
+
+  documentation_deps = [
+    asciidoctor_extensions,
+  ]
+endif
+
+git = find_program('git', required: false)
+xmlto = find_program('xmlto')
+
+cmd_lists = [
+  'cmds-ancillaryinterrogators.adoc',
+  'cmds-ancillarymanipulators.adoc',
+  'cmds-mainporcelain.adoc',
+  'cmds-plumbinginterrogators.adoc',
+  'cmds-plumbingmanipulators.adoc',
+  'cmds-synchingrepositories.adoc',
+  'cmds-synchelpers.adoc',
+  'cmds-guide.adoc',
+  'cmds-developerinterfaces.adoc',
+  'cmds-userinterfaces.adoc',
+  'cmds-purehelpers.adoc',
+  'cmds-foreignscminterface.adoc',
+]
+
+documentation_deps += custom_target(
+  command: [
+    perl,
+    '@INPUT@',
+    meson.project_source_root(),
+    meson.current_build_dir(),
+  ] + cmd_lists,
+  input: 'cmd-list.perl',
+  output: cmd_lists
+)
+
+foreach mode : [ 'diff', 'merge' ]
+  documentation_deps += custom_target(
+    command: [
+      shell,
+      '@INPUT@',
+      '..',
+      mode,
+      '@OUTPUT@'
+    ],
+    env: [
+      'MERGE_TOOLS_DIR=' + meson.project_source_root() / 'mergetools',
+    ],
+    input: 'generate-mergetool-list.sh',
+    output: 'mergetools-' + mode + '.adoc',
+  )
+endforeach
+
+foreach manpage, category : manpages
+  if get_option('docs').contains('man')
+    manpage_xml_target = custom_target(
+      command: asciidoc_common_options + [
+        '--backend=' + asciidoc_docbook,
+        '--doctype=manpage',
+        '--out-file=@OUTPUT@',
+        '@INPUT@',
+      ],
+      depends: documentation_deps,
+      input: manpage,
+      output: fs.stem(manpage) + '.xml',
+    )
+
+    manpage_path = fs.stem(manpage) + '.' + category.to_string()
+    manpage_target = custom_target(
+      command: [
+        xmlto,
+        '-m', '@INPUT0@',
+        '-m', '@INPUT1@',
+        '--stringparam',
+        'man.base.url.for.relative.links=' + get_option('prefix') / get_option('mandir'),
+        'man',
+        manpage_xml_target,
+        '-o',
+        meson.current_build_dir(),
+      ] + xmlto_extra,
+      input: [
+        'manpage-normal.xsl',
+        'manpage-bold-literal.xsl',
+      ],
+      output: manpage_path,
+      install: true,
+      install_dir: get_option('mandir') / 'man' + category.to_string(),
+    )
+  endif
+
+  if get_option('docs').contains('html')
+    custom_target(
+      command: asciidoc_common_options + [
+        '--backend=' + asciidoc_html,
+        '--doctype=manpage',
+        '--out-file=@OUTPUT@',
+        '@INPUT@',
+      ],
+      depends: documentation_deps,
+      input: manpage,
+      output: fs.stem(manpage) + '.html',
+      install: true,
+      install_dir: get_option('datadir') / 'doc/git-doc',
+    )
+  endif
+endforeach
+
+if get_option('docs').contains('html')
+  configure_file(
+    input: 'docinfo-html.in',
+    output: 'docinfo.html',
+    copy: true,
+    install: true,
+    install_dir: get_option('datadir') / 'doc/git-doc',
+  )
+
+  configure_file(
+    input: 'docbook-xsl.css',
+    output: 'docbook-xsl.css',
+    copy: true,
+    install: true,
+    install_dir: get_option('datadir') / 'doc/git-doc',
+  )
+
+  install_symlink('index.html',
+    install_dir: get_option('datadir') / 'doc/git-doc',
+    pointing_to: 'git.html',
+  )
+
+  xsltproc = find_program('xsltproc')
+
+  user_manual_xml = custom_target(
+    command: asciidoc_common_options + [
+      '--backend=' + asciidoc_docbook,
+      '--doctype=book',
+      '--out-file=@OUTPUT@',
+      '@INPUT@',
+    ],
+    input: 'user-manual.txt',
+    output: 'user-manual.xml',
+    depends: documentation_deps,
+  )
+
+  custom_target(
+    command: [
+      xsltproc,
+      '--xinclude',
+      '--stringparam', 'html.stylesheet', 'docbook-xsl.css',
+      '--param', 'generate.consistent.ids', '1',
+      '--output', '@OUTPUT@',
+      '@INPUT@',
+      user_manual_xml,
+    ],
+    input: 'docbook.xsl',
+    output: 'user-manual.html',
+    install: true,
+    install_dir: get_option('datadir') / 'doc/git-doc',
+  )
+
+  articles = [
+    'DecisionMaking.adoc',
+    'MyFirstContribution.adoc',
+    'MyFirstObjectWalk.adoc',
+    'ReviewingGuidelines.adoc',
+    'SubmittingPatches',
+    'ToolsForGit.adoc',
+    'git-bisect-lk2009.adoc',
+    'git-tools.adoc',
+  ]
+
+  foreach article : articles
+    custom_target(
+      command: asciidoc_common_options + [
+        '--backend=' + asciidoc_html,
+        '--out-file=@OUTPUT@',
+        '@INPUT@',
+      ],
+      input: article,
+      output: fs.stem(article) + '.html',
+      depends: documentation_deps,
+      install: true,
+      install_dir: get_option('datadir') / 'doc/git-doc',
+    )
+  endforeach
+
+  asciidoc_html_options = asciidoc_common_options + [
+    '--backend=' + asciidoc_html,
+    '--out-file=@OUTPUT@',
+    '--attribute', 'git-relative-html-prefix=../',
+    '@INPUT@',
+  ]
+
+  subdir('howto')
+  subdir('technical')
+endif
+
+# Sanity check that we are not missing any tests present in 't/'. This check
+# only runs once at configure time and is thus best-effort, only. Furthermore,
+# it only verifies man pages for the sake of simplicity.
+configured_manpages = manpages.keys() + [ 'git-bisect-lk2009.txt', 'git-tools.txt' ]
+actual_manpages = run_command(shell, '-c', 'ls git*.txt scalar.txt',
+  check: true,
+  env: script_environment,
+).stdout().strip().split('\n')
+
+if configured_manpages != actual_manpages
+  missing_manpage = [ ]
+  foreach actual_manpage : actual_manpages
+    if actual_manpage not in configured_manpages
+      missing_manpage += actual_manpage
+    endif
+  endforeach
+  if missing_manpage.length() > 0
+    error('Man page found, but not configured:\n\n - ' + '\n - '.join(missing_manpage))
+  endif
+
+  superfluous_manpage = [ ]
+  foreach configured_manpage : configured_manpages
+    if configured_manpage not in actual_manpages
+      superfluous_manpage += configured_manpage
+    endif
+  endforeach
+  if superfluous_manpage.length() > 0
+    error('Man page configured, but not found:\n\n - ' + '\n - '.join(superfluous_manpage))
+  endif
+endif
diff --git a/Documentation/object-format-disclaimer.adoc b/Documentation/object-format-disclaimer.adoc
new file mode 100644
index 0000000000..e561e6668c
--- /dev/null
+++ b/Documentation/object-format-disclaimer.adoc
@@ -0,0 +1,9 @@
+Note: At present, there is no interoperability between SHA-256
+repositories and SHA-1 repositories.
+
+Historically, we warned that SHA-256 repositories may later need
+backward incompatible changes when we introduce such interoperability
+features. Today, we only expect compatible changes. Furthermore, if such
+changes prove to be necessary, it can be expected that SHA-256 repositories
+created with today's Git will be usable by future versions of Git
+without data loss.
diff --git a/Documentation/pretty-formats.adoc b/Documentation/pretty-formats.adoc
new file mode 100644
index 0000000000..8ee940b6a4
--- /dev/null
+++ b/Documentation/pretty-formats.adoc
@@ -0,0 +1,388 @@
+PRETTY FORMATS
+--------------
+
+If the commit is a merge, and if the pretty-format
+is not 'oneline', 'email' or 'raw', an additional line is
+inserted before the 'Author:' line.  This line begins with
+"Merge: " and the hashes of ancestral commits are printed,
+separated by spaces.  Note that the listed commits may not
+necessarily be the list of the *direct* parent commits if you
+have limited your view of history: for example, if you are
+only interested in changes related to a certain directory or
+file.
+
+There are several built-in formats, and you can define
+additional formats by setting a pretty.<name>
+config option to either another format name, or a
+'format:' string, as described below (see
+linkgit:git-config[1]). Here are the details of the
+built-in formats:
+
+* 'oneline'
+
+	  <hash> <title-line>
++
+This is designed to be as compact as possible.
+
+* 'short'
+
+	  commit <hash>
+	  Author: <author>
+
+	      <title-line>
+
+* 'medium'
+
+	  commit <hash>
+	  Author: <author>
+	  Date:   <author-date>
+
+	      <title-line>
+
+	      <full-commit-message>
+
+* 'full'
+
+	  commit <hash>
+	  Author: <author>
+	  Commit: <committer>
+
+	      <title-line>
+
+	      <full-commit-message>
+
+* 'fuller'
+
+	  commit <hash>
+	  Author:     <author>
+	  AuthorDate: <author-date>
+	  Commit:     <committer>
+	  CommitDate: <committer-date>
+
+	       <title-line>
+
+	       <full-commit-message>
+
+* 'reference'
+
+	  <abbrev-hash> (<title-line>, <short-author-date>)
++
+This format is used to refer to another commit in a commit message and
+is the same as `--pretty='format:%C(auto)%h (%s, %ad)'`.  By default,
+the date is formatted with `--date=short` unless another `--date` option
+is explicitly specified.  As with any `format:` with format
+placeholders, its output is not affected by other options like
+`--decorate` and `--walk-reflogs`.
+
+* 'email'
+
+	  From <hash> <date>
+	  From: <author>
+	  Date: <author-date>
+	  Subject: [PATCH] <title-line>
+
+	  <full-commit-message>
+
+* 'mboxrd'
++
+Like 'email', but lines in the commit message starting with "From "
+(preceded by zero or more ">") are quoted with ">" so they aren't
+confused as starting a new commit.
+
+* 'raw'
++
+The 'raw' format shows the entire commit exactly as
+stored in the commit object.  Notably, the hashes are
+displayed in full, regardless of whether --abbrev or
+--no-abbrev are used, and 'parents' information show the
+true parent commits, without taking grafts or history
+simplification into account. Note that this format affects the way
+commits are displayed, but not the way the diff is shown e.g. with
+`git log --raw`. To get full object names in a raw diff format,
+use `--no-abbrev`.
+
+* 'format:<format-string>'
++
+The 'format:<format-string>' format allows you to specify which information
+you want to show. It works a little bit like printf format,
+with the notable exception that you get a newline with '%n'
+instead of '\n'.
++
+E.g, 'format:"The author of %h was %an, %ar%nThe title was >>%s<<%n"'
+would show something like this:
++
+-------
+The author of fe6e0ee was Junio C Hamano, 23 hours ago
+The title was >>t4119: test autocomputing -p<n> for traditional diff input.<<
+
+-------
++
+The placeholders are:
+
+- Placeholders that expand to a single literal character:
+'%n':: newline
+'%%':: a raw '%'
+'%x00':: '%x' followed by two hexadecimal digits is replaced with a
+	 byte with the hexadecimal digits' value (we will call this
+	 "literal formatting code" in the rest of this document).
+
+- Placeholders that affect formatting of later placeholders:
+'%Cred':: switch color to red
+'%Cgreen':: switch color to green
+'%Cblue':: switch color to blue
+'%Creset':: reset color
+'%C(...)':: color specification, as described under Values in the
+	    "CONFIGURATION FILE" section of linkgit:git-config[1].  By
+	    default, colors are shown only when enabled for log output
+	    (by `color.diff`, `color.ui`, or `--color`, and respecting
+	    the `auto` settings of the former if we are going to a
+	    terminal). `%C(auto,...)` is accepted as a historical
+	    synonym for the default (e.g., `%C(auto,red)`). Specifying
+	    `%C(always,...)` will show the colors even when color is
+	    not otherwise enabled (though consider just using
+	    `--color=always` to enable color for the whole output,
+	    including this format and anything else git might color).
+	    `auto` alone (i.e. `%C(auto)`) will turn on auto coloring
+	    on the next placeholders until the color is switched
+	    again.
+'%m':: left (`<`), right (`>`) or boundary (`-`) mark
+'%w([<w>[,<i1>[,<i2>]]])':: switch line wrapping, like the -w option of
+			    linkgit:git-shortlog[1].
+'%<( <N> [,trunc|ltrunc|mtrunc])':: make the next placeholder take at
+				  least N column widths, padding spaces on
+				  the right if necessary.  Optionally
+				  truncate (with ellipsis '..') at the left (ltrunc) `..ft`,
+				  the middle (mtrunc) `mi..le`, or the end
+				  (trunc) `rig..`, if the output is longer than
+				  N columns.
+				  Note 1: that truncating
+				  only works correctly with N >= 2.
+				  Note 2: spaces around the N and M (see below)
+				  values are optional.
+				  Note 3: Emojis and other wide characters
+				  will take two display columns, which may
+				  over-run column boundaries.
+				  Note 4: decomposed character combining marks
+				  may be misplaced at padding boundaries.
+'%<|( <M> )':: make the next placeholder take at least until Mth
+	     display column, padding spaces on the right if necessary.
+	     Use negative M values for column positions measured
+	     from the right hand edge of the terminal window.
+'%>( <N> )', '%>|( <M> )':: similar to '%<( <N> )', '%<|( <M> )' respectively,
+			but padding spaces on the left
+'%>>( <N> )', '%>>|( <M> )':: similar to '%>( <N> )', '%>|( <M> )'
+			  respectively, except that if the next
+			  placeholder takes more spaces than given and
+			  there are spaces on its left, use those
+			  spaces
+'%><( <N> )', '%><|( <M> )':: similar to '%<( <N> )', '%<|( <M> )'
+			  respectively, but padding both sides
+			  (i.e. the text is centered)
+
+- Placeholders that expand to information extracted from the commit:
+'%H':: commit hash
+'%h':: abbreviated commit hash
+'%T':: tree hash
+'%t':: abbreviated tree hash
+'%P':: parent hashes
+'%p':: abbreviated parent hashes
+'%an':: author name
+'%aN':: author name (respecting .mailmap, see linkgit:git-shortlog[1]
+	or linkgit:git-blame[1])
+'%ae':: author email
+'%aE':: author email (respecting .mailmap, see linkgit:git-shortlog[1]
+	or linkgit:git-blame[1])
+'%al':: author email local-part (the part before the '@' sign)
+'%aL':: author local-part (see '%al') respecting .mailmap, see
+	linkgit:git-shortlog[1] or linkgit:git-blame[1])
+'%ad':: author date (format respects --date= option)
+'%aD':: author date, RFC2822 style
+'%ar':: author date, relative
+'%at':: author date, UNIX timestamp
+'%ai':: author date, ISO 8601-like format
+'%aI':: author date, strict ISO 8601 format
+'%as':: author date, short format (`YYYY-MM-DD`)
+'%ah':: author date, human style (like the `--date=human` option of
+	linkgit:git-rev-list[1])
+'%cn':: committer name
+'%cN':: committer name (respecting .mailmap, see
+	linkgit:git-shortlog[1] or linkgit:git-blame[1])
+'%ce':: committer email
+'%cE':: committer email (respecting .mailmap, see
+	linkgit:git-shortlog[1] or linkgit:git-blame[1])
+'%cl':: committer email local-part (the part before the '@' sign)
+'%cL':: committer local-part (see '%cl') respecting .mailmap, see
+	linkgit:git-shortlog[1] or linkgit:git-blame[1])
+'%cd':: committer date (format respects --date= option)
+'%cD':: committer date, RFC2822 style
+'%cr':: committer date, relative
+'%ct':: committer date, UNIX timestamp
+'%ci':: committer date, ISO 8601-like format
+'%cI':: committer date, strict ISO 8601 format
+'%cs':: committer date, short format (`YYYY-MM-DD`)
+'%ch':: committer date, human style (like the `--date=human` option of
+	linkgit:git-rev-list[1])
+'%d':: ref names, like the --decorate option of linkgit:git-log[1]
+'%D':: ref names without the " (", ")" wrapping.
+'%(decorate[:<options>])'::
+ref names with custom decorations. The `decorate` string may be followed by a
+colon and zero or more comma-separated options. Option values may contain
+literal formatting codes. These must be used for commas (`%x2C`) and closing
+parentheses (`%x29`), due to their role in the option syntax.
++
+** 'prefix=<value>': Shown before the list of ref names.  Defaults to "{nbsp}`(`".
+** 'suffix=<value>': Shown after the list of ref names.  Defaults to "`)`".
+** 'separator=<value>': Shown between ref names.  Defaults to "`,`{nbsp}".
+** 'pointer=<value>': Shown between HEAD and the branch it points to, if any.
+		      Defaults to "{nbsp}`->`{nbsp}".
+** 'tag=<value>': Shown before tag names. Defaults to "`tag:`{nbsp}".
+
++
+For example, to produce decorations with no wrapping
+or tag annotations, and spaces as separators:
++
+`%(decorate:prefix=,suffix=,tag=,separator= )`
+
+'%(describe[:<options>])'::
+human-readable name, like linkgit:git-describe[1]; empty string for
+undescribable commits.  The `describe` string may be followed by a colon and
+zero or more comma-separated options.  Descriptions can be inconsistent when
+tags are added or removed at the same time.
++
+** 'tags[=<bool-value>]': Instead of only considering annotated tags,
+   consider lightweight tags as well.
+** 'abbrev=<number>': Instead of using the default number of hexadecimal digits
+   (which will vary according to the number of objects in the repository with a
+   default of 7) of the abbreviated object name, use <number> digits, or as many
+   digits as needed to form a unique object name.
+** 'match=<pattern>': Only consider tags matching the given
+   `glob(7)` pattern, excluding the "refs/tags/" prefix.
+** 'exclude=<pattern>': Do not consider tags matching the given
+   `glob(7)` pattern, excluding the "refs/tags/" prefix.
+
+'%S':: ref name given on the command line by which the commit was reached
+       (like `git log --source`), only works with `git log`
+'%e':: encoding
+'%s':: subject
+'%f':: sanitized subject line, suitable for a filename
+'%b':: body
+'%B':: raw body (unwrapped subject and body)
+ifndef::git-rev-list[]
+'%N':: commit notes
+endif::git-rev-list[]
+'%GG':: raw verification message from GPG for a signed commit
+'%G?':: show "G" for a good (valid) signature,
+	"B" for a bad signature,
+	"U" for a good signature with unknown validity,
+	"X" for a good signature that has expired,
+	"Y" for a good signature made by an expired key,
+	"R" for a good signature made by a revoked key,
+	"E" if the signature cannot be checked (e.g. missing key)
+	and "N" for no signature
+'%GS':: show the name of the signer for a signed commit
+'%GK':: show the key used to sign a signed commit
+'%GF':: show the fingerprint of the key used to sign a signed commit
+'%GP':: show the fingerprint of the primary key whose subkey was used
+	to sign a signed commit
+'%GT':: show the trust level for the key used to sign a signed commit
+'%gD':: reflog selector, e.g., `refs/stash@{1}` or `refs/stash@{2
+	minutes ago}`; the format follows the rules described for the
+	`-g` option. The portion before the `@` is the refname as
+	given on the command line (so `git log -g refs/heads/master`
+	would yield `refs/heads/master@{0}`).
+'%gd':: shortened reflog selector; same as `%gD`, but the refname
+	portion is shortened for human readability (so
+	`refs/heads/master` becomes just `master`).
+'%gn':: reflog identity name
+'%gN':: reflog identity name (respecting .mailmap, see
+	linkgit:git-shortlog[1] or linkgit:git-blame[1])
+'%ge':: reflog identity email
+'%gE':: reflog identity email (respecting .mailmap, see
+	linkgit:git-shortlog[1] or linkgit:git-blame[1])
+'%gs':: reflog subject
+'%(trailers[:<options>])'::
+display the trailers of the body as interpreted by
+linkgit:git-interpret-trailers[1]. The `trailers` string may be followed by
+a colon and zero or more comma-separated options. If any option is provided
+multiple times, the last occurrence wins.
++
+** 'key=<key>': only show trailers with specified <key>. Matching is done
+   case-insensitively and trailing colon is optional. If option is
+   given multiple times trailer lines matching any of the keys are
+   shown. This option automatically enables the `only` option so that
+   non-trailer lines in the trailer block are hidden. If that is not
+   desired it can be disabled with `only=false`.  E.g.,
+   `%(trailers:key=Reviewed-by)` shows trailer lines with key
+   `Reviewed-by`.
+** 'only[=<bool>]': select whether non-trailer lines from the trailer
+   block should be included.
+** 'separator=<sep>': specify the separator inserted between trailer
+   lines. Defaults to a line feed character. The string <sep> may contain
+   the literal formatting codes described above. To use comma as
+   separator one must use `%x2C` as it would otherwise be parsed as
+   next option. E.g., `%(trailers:key=Ticket,separator=%x2C )`
+   shows all trailer lines whose key is "Ticket" separated by a comma
+   and a space.
+** 'unfold[=<bool>]': make it behave as if interpret-trailer's `--unfold`
+   option was given. E.g.,
+   `%(trailers:only,unfold=true)` unfolds and shows all trailer lines.
+** 'keyonly[=<bool>]': only show the key part of the trailer.
+** 'valueonly[=<bool>]': only show the value part of the trailer.
+** 'key_value_separator=<sep>': specify the separator inserted between
+   the key and value of each trailer. Defaults to ": ". Otherwise it
+   shares the same semantics as 'separator=<sep>' above.
+
+NOTE: Some placeholders may depend on other options given to the
+revision traversal engine. For example, the `%g*` reflog options will
+insert an empty string unless we are traversing reflog entries (e.g., by
+`git log -g`). The `%d` and `%D` placeholders will use the "short"
+decoration format if `--decorate` was not already provided on the command
+line.
+
+The boolean options accept an optional value `[=<bool-value>]`. The values
+`true`, `false`, `on`, `off` etc. are all accepted. See the "boolean"
+sub-section in "EXAMPLES" in linkgit:git-config[1]. If a boolean
+option is given with no value, it's enabled.
+
+If you add a `+` (plus sign) after '%' of a placeholder, a line-feed
+is inserted immediately before the expansion if and only if the
+placeholder expands to a non-empty string.
+
+If you add a `-` (minus sign) after '%' of a placeholder, all consecutive
+line-feeds immediately preceding the expansion are deleted if and only if the
+placeholder expands to an empty string.
+
+If you add a ` ` (space) after '%' of a placeholder, a space
+is inserted immediately before the expansion if and only if the
+placeholder expands to a non-empty string.
+
+* 'tformat:'
++
+The 'tformat:' format works exactly like 'format:', except that it
+provides "terminator" semantics instead of "separator" semantics. In
+other words, each commit has the message terminator character (usually a
+newline) appended, rather than a separator placed between entries.
+This means that the final entry of a single-line format will be properly
+terminated with a new line, just as the "oneline" format does.
+For example:
++
+---------------------
+$ git log -2 --pretty=format:%h 4da45bef \
+  | perl -pe '$_ .= " -- NO NEWLINE\n" unless /\n/'
+4da45be
+7134973 -- NO NEWLINE
+
+$ git log -2 --pretty=tformat:%h 4da45bef \
+  | perl -pe '$_ .= " -- NO NEWLINE\n" unless /\n/'
+4da45be
+7134973
+---------------------
++
+In addition, any unrecognized string that has a `%` in it is interpreted
+as if it has `tformat:` in front of it.  For example, these two are
+equivalent:
++
+---------------------
+$ git log -2 --pretty=tformat:%h 4da45bef
+$ git log -2 --pretty=%h 4da45bef
+---------------------
diff --git a/Documentation/pretty-options.adoc b/Documentation/pretty-options.adoc
new file mode 100644
index 0000000000..23888cd612
--- /dev/null
+++ b/Documentation/pretty-options.adoc
@@ -0,0 +1,102 @@
+--pretty[=<format>]::
+--format=<format>::
+
+	Pretty-print the contents of the commit logs in a given format,
+	where '<format>' can be one of 'oneline', 'short', 'medium',
+	'full', 'fuller', 'reference', 'email', 'raw', 'format:<string>'
+	and 'tformat:<string>'.  When '<format>' is none of the above,
+	and has '%placeholder' in it, it acts as if
+	'--pretty=tformat:<format>' were given.
++
+See the "PRETTY FORMATS" section for some additional details for each
+format.  When '=<format>' part is omitted, it defaults to 'medium'.
++
+Note: you can specify the default pretty format in the repository
+configuration (see linkgit:git-config[1]).
+
+--abbrev-commit::
+	Instead of showing the full 40-byte hexadecimal commit object
+	name, show a prefix that names the object uniquely.
+	"--abbrev=<n>" (which also modifies diff output, if it is displayed)
+	option can be used to specify the minimum length of the prefix.
++
+This should make "--pretty=oneline" a whole lot more readable for
+people using 80-column terminals.
+
+--no-abbrev-commit::
+	Show the full 40-byte hexadecimal commit object name. This negates
+	`--abbrev-commit`, either explicit or implied by other options such
+	as "--oneline". It also overrides the `log.abbrevCommit` variable.
+
+--oneline::
+	This is a shorthand for "--pretty=oneline --abbrev-commit"
+	used together.
+
+--encoding=<encoding>::
+	Commit objects record the character encoding used for the log message
+	in their encoding header; this option can be used to tell the
+	command to re-code the commit log message in the encoding
+	preferred by the user.  For non plumbing commands this
+	defaults to UTF-8. Note that if an object claims to be encoded
+	in `X` and we are outputting in `X`, we will output the object
+	verbatim; this means that invalid sequences in the original
+	commit may be copied to the output. Likewise, if iconv(3) fails
+	to convert the commit, we will quietly output the original
+	object verbatim.
+
+--expand-tabs=<n>::
+--expand-tabs::
+--no-expand-tabs::
+	Perform a tab expansion (replace each tab with enough spaces
+	to fill to the next display column that is a multiple of '<n>')
+	in the log message before showing it in the output.
+	`--expand-tabs` is a short-hand for `--expand-tabs=8`, and
+	`--no-expand-tabs` is a short-hand for `--expand-tabs=0`,
+	which disables tab expansion.
++
+By default, tabs are expanded in pretty formats that indent the log
+message by 4 spaces (i.e.  'medium', which is the default, 'full',
+and 'fuller').
+
+ifndef::git-rev-list[]
+--notes[=<ref>]::
+	Show the notes (see linkgit:git-notes[1]) that annotate the
+	commit, when showing the commit log message.  This is the default
+	for `git log`, `git show` and `git whatchanged` commands when
+	there is no `--pretty`, `--format`, or `--oneline` option given
+	on the command line.
++
+By default, the notes shown are from the notes refs listed in the
+`core.notesRef` and `notes.displayRef` variables (or corresponding
+environment overrides). See linkgit:git-config[1] for more details.
++
+With an optional '<ref>' argument, use the ref to find the notes
+to display.  The ref can specify the full refname when it begins
+with `refs/notes/`; when it begins with `notes/`, `refs/` and otherwise
+`refs/notes/` is prefixed to form the full name of the ref.
++
+Multiple --notes options can be combined to control which notes are
+being displayed. Examples: "--notes=foo" will show only notes from
+"refs/notes/foo"; "--notes=foo --notes" will show both notes from
+"refs/notes/foo" and from the default notes ref(s).
+
+--no-notes::
+	Do not show notes. This negates the above `--notes` option, by
+	resetting the list of notes refs from which notes are shown.
+	Options are parsed in the order given on the command line, so e.g.
+	"--notes --notes=foo --no-notes --notes=bar" will only show notes
+	from "refs/notes/bar".
+
+--show-notes-by-default::
+	Show the default notes unless options for displaying specific
+	notes are given.
+
+--show-notes[=<ref>]::
+--[no-]standard-notes::
+	These options are deprecated. Use the above --notes/--no-notes
+	options instead.
+endif::git-rev-list[]
+
+--show-signature::
+	Check the validity of a signed commit object by passing the signature
+	to `gpg --verify` and show the output.
diff --git a/Documentation/pull-fetch-param.adoc b/Documentation/pull-fetch-param.adoc
new file mode 100644
index 0000000000..d79d2f6065
--- /dev/null
+++ b/Documentation/pull-fetch-param.adoc
@@ -0,0 +1,120 @@
+<repository>::
+	The "remote" repository that is the source of a fetch
+	or pull operation.  This parameter can be either a URL
+	(see the section <<URLS,GIT URLS>> below) or the name
+	of a remote (see the section <<REMOTES,REMOTES>> below).
+
+ifndef::git-pull[]
+<group>::
+	A name referring to a list of repositories as the value
+	of remotes.<group> in the configuration file.
+	(See linkgit:git-config[1]).
+endif::git-pull[]
+
+<refspec>::
+	Specifies which refs to fetch and which local refs to update.
+	When no <refspec>s appear on the command line, the refs to fetch
+	are read from `remote.<repository>.fetch` variables instead
+ifndef::git-pull[]
+	(see <<CRTB,CONFIGURED REMOTE-TRACKING BRANCHES>> below).
+endif::git-pull[]
+ifdef::git-pull[]
+	(see the section "CONFIGURED REMOTE-TRACKING BRANCHES"
+	in linkgit:git-fetch[1]).
+endif::git-pull[]
++
+The format of a <refspec> parameter is an optional plus
+`+`, followed by the source <src>, followed
+by a colon `:`, followed by the destination <dst>.
+The colon can be omitted when <dst> is empty.  <src> is
+typically a ref, or a glob pattern with a single `*` that is used
+to match a set of refs, but it can also be a fully spelled hex object
+name.
++
+A <refspec> may contain a `*` in its <src> to indicate a simple pattern
+match. Such a refspec functions like a glob that matches any ref with the
+pattern. A pattern <refspec> must have one and only one `*` in both the <src> and
+<dst>. It will map refs to the destination by replacing the `*` with the
+contents matched from the source.
++
+If a refspec is prefixed by `^`, it will be interpreted as a negative
+refspec. Rather than specifying which refs to fetch or which local refs to
+update, such a refspec will instead specify refs to exclude. A ref will be
+considered to match if it matches at least one positive refspec, and does
+not match any negative refspec. Negative refspecs can be useful to restrict
+the scope of a pattern refspec so that it will not include specific refs.
+Negative refspecs can themselves be pattern refspecs. However, they may only
+contain a <src> and do not specify a <dst>. Fully spelled out hex object
+names are also not supported.
++
+`tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`;
+it requests fetching everything up to the given tag.
++
+The remote ref that matches <src>
+is fetched, and if <dst> is not an empty string, an attempt
+is made to update the local ref that matches it.
++
+Whether that update is allowed without `--force` depends on the ref
+namespace it's being fetched to, the type of object being fetched, and
+whether the update is considered to be a fast-forward. Generally, the
+same rules apply for fetching as when pushing, see the `<refspec>...`
+section of linkgit:git-push[1] for what those are. Exceptions to those
+rules particular to 'git fetch' are noted below.
++
+Until Git version 2.20, and unlike when pushing with
+linkgit:git-push[1], any updates to `refs/tags/*` would be accepted
+without `+` in the refspec (or `--force`). When fetching, we promiscuously
+considered all tag updates from a remote to be forced fetches.  Since
+Git version 2.20, fetching to update `refs/tags/*` works the same way
+as when pushing. I.e. any updates will be rejected without `+` in the
+refspec (or `--force`).
++
+Unlike when pushing with linkgit:git-push[1], any updates outside of
+`refs/{tags,heads}/*` will be accepted without `+` in the refspec (or
+`--force`), whether that's swapping e.g. a tree object for a blob, or
+a commit for another commit that doesn't have the previous commit as
+an ancestor etc.
++
+Unlike when pushing with linkgit:git-push[1], there is no
+configuration which'll amend these rules, and nothing like a
+`pre-fetch` hook analogous to the `pre-receive` hook.
++
+As with pushing with linkgit:git-push[1], all of the rules described
+above about what's not allowed as an update can be overridden by
+adding an optional leading `+` to a refspec (or using the `--force`
+command line option). The only exception to this is that no amount of
+forcing will make the `refs/heads/*` namespace accept a non-commit
+object.
++
+[NOTE]
+When the remote branch you want to fetch is known to
+be rewound and rebased regularly, it is expected that
+its new tip will not be a descendant of its previous tip
+(as stored in your remote-tracking branch the last time
+you fetched).  You would want
+to use the `+` sign to indicate non-fast-forward updates
+will be needed for such branches.  There is no way to
+determine or declare that a branch will be made available
+in a repository with this behavior; the pulling user simply
+must know this is the expected usage pattern for a branch.
+ifdef::git-pull[]
++
+[NOTE]
+There is a difference between listing multiple <refspec>
+directly on 'git pull' command line and having multiple
+`remote.<repository>.fetch` entries in your configuration
+for a <repository> and running a
+'git pull' command without any explicit <refspec> parameters.
+<refspec>s listed explicitly on the command line are always
+merged into the current branch after fetching.  In other words,
+if you list more than one remote ref, 'git pull' will create
+an Octopus merge.  On the other hand, if you do not list any
+explicit <refspec> parameter on the command line, 'git pull'
+will fetch all the <refspec>s it finds in the
+`remote.<repository>.fetch` configuration and merge
+only the first <refspec> found into the current branch.
+This is because making an
+Octopus from remote refs is rarely done, while keeping track
+of multiple remote heads in one-go by fetching more than one
+is often useful.
+endif::git-pull[]
diff --git a/Documentation/ref-reachability-filters.adoc b/Documentation/ref-reachability-filters.adoc
new file mode 100644
index 0000000000..9bae46d84c
--- /dev/null
+++ b/Documentation/ref-reachability-filters.adoc
@@ -0,0 +1,7 @@
+When combining multiple `--contains` and `--no-contains` filters, only
+references that contain at least one of the `--contains` commits and
+contain none of the `--no-contains` commits are shown.
+
+When combining multiple `--merged` and `--no-merged` filters, only
+references that are reachable from at least one of the `--merged`
+commits and from none of the `--no-merged` commits are shown.
diff --git a/Documentation/ref-storage-format.adoc b/Documentation/ref-storage-format.adoc
new file mode 100644
index 0000000000..14fff8a9c6
--- /dev/null
+++ b/Documentation/ref-storage-format.adoc
@@ -0,0 +1,3 @@
+* `files` for loose files with packed-refs. This is the default.
+* `reftable` for the reftable format. This format is experimental and its
+  internals are subject to change.
diff --git a/Documentation/rerere-options.adoc b/Documentation/rerere-options.adoc
new file mode 100644
index 0000000000..c3321ddea2
--- /dev/null
+++ b/Documentation/rerere-options.adoc
@@ -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/Documentation/rev-list-description.adoc b/Documentation/rev-list-description.adoc
new file mode 100644
index 0000000000..a9efa7fa27
--- /dev/null
+++ b/Documentation/rev-list-description.adoc
@@ -0,0 +1,61 @@
+List commits that are reachable by following the `parent` links from the
+given commit(s), but exclude commits that are reachable from the one(s)
+given with a '{caret}' in front of them.  The output is given in reverse
+chronological order by default.
+
+You can think of this as a set operation. Commits reachable from any of
+the commits given on the command line form a set, and then commits reachable
+from any of the ones given with '{caret}' in front are subtracted from that
+set.  The remaining commits are what comes out in the command's output.
+Various other options and paths parameters can be used to further limit the
+result.
+
+Thus, the following command:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list foo bar ^baz
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log foo bar ^baz
+-----------------------------------------------------------------------
+endif::git-log[]
+
+means "list all the commits which are reachable from 'foo' or 'bar', but
+not from 'baz'".
+
+A special notation "'<commit1>'..'<commit2>'" can be used as a
+short-hand for "^'<commit1>' '<commit2>'". For example, either of
+the following may be used interchangeably:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list origin..HEAD
+$ git rev-list HEAD ^origin
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log origin..HEAD
+$ git log HEAD ^origin
+-----------------------------------------------------------------------
+endif::git-log[]
+
+Another special notation is "'<commit1>'...'<commit2>'" which is useful
+for merges.  The resulting set of commits is the symmetric difference
+between the two operands.  The following two commands are equivalent:
+
+ifdef::git-rev-list[]
+-----------------------------------------------------------------------
+$ git rev-list A B --not $(git merge-base --all A B)
+$ git rev-list A...B
+-----------------------------------------------------------------------
+endif::git-rev-list[]
+ifdef::git-log[]
+-----------------------------------------------------------------------
+$ git log A B --not $(git merge-base --all A B)
+$ git log A...B
+-----------------------------------------------------------------------
+endif::git-log[]
diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc
new file mode 100644
index 0000000000..196b2781cc
--- /dev/null
+++ b/Documentation/rev-list-options.adoc
@@ -0,0 +1,1216 @@
+Commit Limiting
+~~~~~~~~~~~~~~~
+
+Besides specifying a range of commits that should be listed using the
+special notations explained in the description, additional commit
+limiting may be applied.
+
+Using more options generally further limits the output (e.g.
+`--since=<date1>` limits to commits newer than `<date1>`, and using it
+with `--grep=<pattern>` further limits to commits whose log message
+has a line that matches `<pattern>`), unless otherwise noted.
+
+Note that these are applied before commit
+ordering and formatting options, such as `--reverse`.
+
+-<number>::
+-n <number>::
+--max-count=<number>::
+	Limit the number of commits to output.
+
+--skip=<number>::
+	Skip 'number' commits before starting to show the commit output.
+
+--since=<date>::
+--after=<date>::
+	Show commits more recent than a specific date.
+
+--since-as-filter=<date>::
+	Show all commits more recent than a specific date. This visits
+	all commits in the range, rather than stopping at the first commit which
+	is older than a specific date.
+
+--until=<date>::
+--before=<date>::
+	Show commits older than a specific date.
+
+ifdef::git-rev-list[]
+--max-age=<timestamp>::
+--min-age=<timestamp>::
+	Limit the commits output to specified time range.
+endif::git-rev-list[]
+
+--author=<pattern>::
+--committer=<pattern>::
+	Limit the commits output to ones with author/committer
+	header lines that match the specified pattern (regular
+	expression).  With more than one `--author=<pattern>`,
+	commits whose author matches any of the given patterns are
+	chosen (similarly for multiple `--committer=<pattern>`).
+
+--grep-reflog=<pattern>::
+	Limit the commits output to ones with reflog entries that
+	match the specified pattern (regular expression). With
+	more than one `--grep-reflog`, commits whose reflog message
+	matches any of the given patterns are chosen.  It is an
+	error to use this option unless `--walk-reflogs` is in use.
+
+--grep=<pattern>::
+	Limit the commits output to ones with a log message that
+	matches the specified pattern (regular expression).  With
+	more than one `--grep=<pattern>`, commits whose message
+	matches any of the given patterns are chosen (but see
+	`--all-match`).
+ifndef::git-rev-list[]
++
+When `--notes` is in effect, the message from the notes is
+matched as if it were part of the log message.
+endif::git-rev-list[]
+
+--all-match::
+	Limit the commits output to ones that match all given `--grep`,
+	instead of ones that match at least one.
+
+--invert-grep::
+	Limit the commits output to ones with a log message that do not
+	match the pattern specified with `--grep=<pattern>`.
+
+-i::
+--regexp-ignore-case::
+	Match the regular expression limiting patterns without regard to letter
+	case.
+
+--basic-regexp::
+	Consider the limiting patterns to be basic regular expressions;
+	this is the default.
+
+-E::
+--extended-regexp::
+	Consider the limiting patterns to be extended regular expressions
+	instead of the default basic regular expressions.
+
+-F::
+--fixed-strings::
+	Consider the limiting patterns to be fixed strings (don't interpret
+	pattern as a regular expression).
+
+-P::
+--perl-regexp::
+	Consider the limiting patterns to be Perl-compatible regular
+	expressions.
++
+Support for these types of regular expressions is an optional
+compile-time dependency. If Git wasn't compiled with support for them
+providing this option will cause it to die.
+
+--remove-empty::
+	Stop when a given path disappears from the tree.
+
+--merges::
+	Print only merge commits. This is exactly the same as `--min-parents=2`.
+
+--no-merges::
+	Do not print commits with more than one parent. This is
+	exactly the same as `--max-parents=1`.
+
+--min-parents=<number>::
+--max-parents=<number>::
+--no-min-parents::
+--no-max-parents::
+	Show only commits which have at least (or at most) that many parent
+	commits. In particular, `--max-parents=1` is the same as `--no-merges`,
+	`--min-parents=2` is the same as `--merges`.  `--max-parents=0`
+	gives all root commits and `--min-parents=3` all octopus merges.
++
+`--no-min-parents` and `--no-max-parents` reset these limits (to no limit)
+again.  Equivalent forms are `--min-parents=0` (any commit has 0 or more
+parents) and `--max-parents=-1` (negative numbers denote no upper limit).
+
+--first-parent::
+	When finding commits to include, follow only the first
+	parent commit upon seeing a merge commit.  This option
+	can give a better overview when viewing the evolution of
+	a particular topic branch, because merges into a topic
+	branch tend to be only about adjusting to updated upstream
+	from time to time, and this option allows you to ignore
+	the individual commits brought in to your history by such
+	a merge.
+ifdef::git-log[]
++
+This option also changes default diff format for merge commits
+to `first-parent`, see `--diff-merges=first-parent` for details.
+endif::git-log[]
+
+--exclude-first-parent-only::
+	When finding commits to exclude (with a '{caret}'), follow only
+	the first parent commit upon seeing a merge commit.
+	This can be used to find the set of changes in a topic branch
+	from the point where it diverged from the remote branch, given
+	that arbitrary merges can be valid topic branch changes.
+
+--not::
+	Reverses the meaning of the '{caret}' prefix (or lack thereof)
+	for all following revision specifiers, up to the next `--not`.
+	When used on the command line before --stdin, the revisions passed
+	through stdin will not be affected by it. Conversely, when passed
+	via standard input, the revisions passed on the command line will
+	not be affected by it.
+
+--all::
+	Pretend as if all the refs in `refs/`, along with `HEAD`, are
+	listed on the command line as '<commit>'.
+
+--branches[=<pattern>]::
+	Pretend as if all the refs in `refs/heads` are listed
+	on the command line as '<commit>'. If '<pattern>' is given, limit
+	branches to ones matching given shell glob. If pattern lacks '?',
+	'{asterisk}', or '[', '/{asterisk}' at the end is implied.
+
+--tags[=<pattern>]::
+	Pretend as if all the refs in `refs/tags` are listed
+	on the command line as '<commit>'. If '<pattern>' is given, limit
+	tags to ones matching given shell glob. If pattern lacks '?', '{asterisk}',
+	or '[', '/{asterisk}' at the end is implied.
+
+--remotes[=<pattern>]::
+	Pretend as if all the refs in `refs/remotes` are listed
+	on the command line as '<commit>'. If '<pattern>' is given, limit
+	remote-tracking branches to ones matching given shell glob.
+	If pattern lacks '?', '{asterisk}', or '[', '/{asterisk}' at the end is implied.
+
+--glob=<glob-pattern>::
+	Pretend as if all the refs matching shell glob '<glob-pattern>'
+	are listed on the command line as '<commit>'. Leading 'refs/',
+	is automatically prepended if missing. If pattern lacks '?', '{asterisk}',
+	or '[', '/{asterisk}' at the end is implied.
+
+--exclude=<glob-pattern>::
+
+	Do not include refs matching '<glob-pattern>' that the next `--all`,
+	`--branches`, `--tags`, `--remotes`, or `--glob` would otherwise
+	consider. Repetitions of this option accumulate exclusion patterns
+	up to the next `--all`, `--branches`, `--tags`, `--remotes`, or
+	`--glob` option (other options or arguments do not clear
+	accumulated patterns).
++
+The patterns given should not begin with `refs/heads`, `refs/tags`, or
+`refs/remotes` when applied to `--branches`, `--tags`, or `--remotes`,
+respectively, and they must begin with `refs/` when applied to `--glob`
+or `--all`. If a trailing '/{asterisk}' is intended, it must be given
+explicitly.
+
+--exclude-hidden=[fetch|receive|uploadpack]::
+	Do not include refs that would be hidden by `git-fetch`,
+	`git-receive-pack` or `git-upload-pack` by consulting the appropriate
+	`fetch.hideRefs`, `receive.hideRefs` or `uploadpack.hideRefs`
+	configuration along with `transfer.hideRefs` (see
+	linkgit:git-config[1]). This option affects the next pseudo-ref option
+	`--all` or `--glob` and is cleared after processing them.
+
+--reflog::
+	Pretend as if all objects mentioned by reflogs are listed on the
+	command line as `<commit>`.
+
+--alternate-refs::
+	Pretend as if all objects mentioned as ref tips of alternate
+	repositories were listed on the command line. An alternate
+	repository is any repository whose object directory is specified
+	in `objects/info/alternates`.  The set of included objects may
+	be modified by `core.alternateRefsCommand`, etc. See
+	linkgit:git-config[1].
+
+--single-worktree::
+	By default, all working trees will be examined by the
+	following options when there are more than one (see
+	linkgit:git-worktree[1]): `--all`, `--reflog` and
+	`--indexed-objects`.
+	This option forces them to examine the current working tree
+	only.
+
+--ignore-missing::
+	Upon seeing an invalid object name in the input, pretend as if
+	the bad input was not given.
+
+ifndef::git-rev-list[]
+--bisect::
+	Pretend as if the bad bisection ref `refs/bisect/bad`
+	was listed and as if it was followed by `--not` and the good
+	bisection refs `refs/bisect/good-*` on the command
+	line.
+endif::git-rev-list[]
+
+--stdin::
+	In addition to getting arguments from the command line, read
+	them from standard input as well. This accepts commits and
+	pseudo-options like `--all` and `--glob=`. When a `--` separator
+	is seen, the following input is treated as paths and used to
+	limit the result. Flags like `--not` which are read via standard input
+	are only respected for arguments passed in the same way and will not
+	influence any subsequent command line arguments.
+
+ifdef::git-rev-list[]
+--quiet::
+	Don't print anything to standard output.  This form
+	is primarily meant to allow the caller to
+	test the exit status to see if a range of objects is fully
+	connected (or not).  It is faster than redirecting stdout
+	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
+	--batch-check='%(objectsize:disk)'`, except that it runs much
+	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::
+	Like `--cherry-pick` (see below) but mark equivalent commits
+	with `=` rather than omitting them, and inequivalent ones with `+`.
+
+--cherry-pick::
+	Omit any commit that introduces the same change as
+	another commit on the ``other side'' when the set of
+	commits are limited with symmetric difference.
++
+For example, if you have two branches, `A` and `B`, a usual way
+to list all commits on only one side of them is with
+`--left-right` (see the example below in the description of
+the `--left-right` option). However, it shows the commits that were
+cherry-picked from the other branch (for example, ``3rd on b'' may be
+cherry-picked from branch A). With this option, such pairs of commits are
+excluded from the output.
+
+--left-only::
+--right-only::
+	List only commits on the respective side of a symmetric difference,
+	i.e. only those which would be marked `<` resp. `>` by
+	`--left-right`.
++
+For example, `--cherry-pick --right-only A...B` omits those
+commits from `B` which are in `A` or are patch-equivalent to a commit in
+`A`. In other words, this lists the `+` commits from `git cherry A B`.
+More precisely, `--cherry-pick --right-only --no-merges` gives the exact
+list.
+
+--cherry::
+	A synonym for `--right-only --cherry-mark --no-merges`; useful to
+	limit the output to the commits on our side and mark those that
+	have been applied to the other side of a forked history with
+	`git log --cherry upstream...mybranch`, similar to
+	`git cherry upstream mybranch`.
+
+-g::
+--walk-reflogs::
+	Instead of walking the commit ancestry chain, walk
+	reflog entries from the most recent one to older ones.
+	When this option is used you cannot specify commits to
+	exclude (that is, '{caret}commit', 'commit1..commit2',
+	and 'commit1\...commit2' notations cannot be used).
++
+With `--pretty` format other than `oneline` and `reference` (for obvious reasons),
+this causes the output to have two extra lines of information
+taken from the reflog.  The reflog designator in the output may be shown
+as `ref@{<Nth>}` (where _<Nth>_ is the reverse-chronological index in the
+reflog) or as `ref@{<timestamp>}` (with the _<timestamp>_ for that entry),
+depending on a few rules:
++
+--
+1. If the starting point is specified as `ref@{<Nth>}`, show the index
+   format.
++
+2. If the starting point was specified as `ref@{now}`, show the
+   timestamp format.
++
+3. If neither was used, but `--date` was given on the command line, show
+   the timestamp in the format requested by `--date`.
++
+4. Otherwise, show the index format.
+--
++
+Under `--pretty=oneline`, the commit message is
+prefixed with this information on the same line.
+This option cannot be combined with `--reverse`.
+See also linkgit:git-reflog[1].
++
+Under `--pretty=reference`, this information will not be shown at all.
+
+--merge::
+	Show commits touching conflicted paths in the range `HEAD...<other>`,
+	where `<other>` is the first existing pseudoref in `MERGE_HEAD`,
+	`CHERRY_PICK_HEAD`, `REVERT_HEAD` or `REBASE_HEAD`. Only works
+	when the index has unmerged entries. This option can be used to show
+	relevant commits when resolving conflicts from a 3-way merge.
+
+--boundary::
+	Output excluded boundary commits. Boundary commits are
+	prefixed with `-`.
+
+ifdef::git-rev-list[]
+--use-bitmap-index::
+
+	Try to speed up the traversal using the pack bitmap index (if
+	one is available). Note that when traversing with `--objects`,
+	trees and blobs will not have their associated path printed.
+
+--progress=<header>::
+	Show progress reports on stderr as objects are considered. The
+	`<header>` text will be printed with each progress update.
+endif::git-rev-list[]
+
+History Simplification
+~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes you are only interested in parts of the history, for example the
+commits modifying a particular <path>. But there are two parts of
+'History Simplification', one part is selecting the commits and the other
+is how to do it, as there are various strategies to simplify the history.
+
+The following options select the commits to be shown:
+
+<paths>::
+	Commits modifying the given <paths> are selected.
+
+--simplify-by-decoration::
+	Commits that are referred by some branch or tag are selected.
+
+Note that extra commits can be shown to give a meaningful history.
+
+The following options affect the way the simplification is performed:
+
+Default mode::
+	Simplifies the history to the simplest history explaining the
+	final state of the tree. Simplest because it prunes some side
+	branches if the end result is the same (i.e. merging branches
+	with the same content)
+
+--show-pulls::
+	Include all commits from the default mode, but also any merge
+	commits that are not TREESAME to the first parent but are
+	TREESAME to a later parent. This mode is helpful for showing
+	the merge commits that "first introduced" a change to a branch.
+
+--full-history::
+	Same as the default mode, but does not prune some history.
+
+--dense::
+	Only the selected commits are shown, plus some to have a
+	meaningful history.
+
+--sparse::
+	All commits in the simplified history are shown.
+
+--simplify-merges::
+	Additional option to `--full-history` to remove some needless
+	merges from the resulting history, as there are no selected
+	commits contributing to this merge.
+
+--ancestry-path[=<commit>]::
+	When given a range of commits to display (e.g. 'commit1..commit2'
+	or 'commit2 {caret}commit1'), and a commit <commit> in that range,
+	only display commits in that range
+	that are ancestors of <commit>, descendants of <commit>, or
+	<commit> itself.  If no commit is specified, use 'commit1' (the
+	excluded part of the range) as <commit>.  Can be passed multiple
+	times; if so, a commit is included if it is any of the commits
+	given or if it is an ancestor or descendant of one of them.
+
+A more detailed explanation follows.
+
+Suppose you specified `foo` as the <paths>.  We shall call commits
+that modify `foo` !TREESAME, and the rest TREESAME.  (In a diff
+filtered for `foo`, they look different and equal, respectively.)
+
+In the following, we will always refer to the same example history to
+illustrate the differences between simplification settings.  We assume
+that you are filtering for a file `foo` in this commit graph:
+-----------------------------------------------------------------------
+	  .-A---M---N---O---P---Q
+	 /     /   /   /   /   /
+	I     B   C   D   E   Y
+	 \   /   /   /   /   /
+	  `-------------'   X
+-----------------------------------------------------------------------
+The horizontal line of history A---Q is taken to be the first parent of
+each merge.  The commits are:
+
+* `I` is the initial commit, in which `foo` exists with contents
+  ``asdf'', and a file `quux` exists with contents ``quux''. Initial
+  commits are compared to an empty tree, so `I` is !TREESAME.
+
+* In `A`, `foo` contains just ``foo''.
+
+* `B` contains the same change as `A`.  Its merge `M` is trivial and
+  hence TREESAME to all parents.
+
+* `C` does not change `foo`, but its merge `N` changes it to ``foobar'',
+  so it is not TREESAME to any parent.
+
+* `D` sets `foo` to ``baz''. Its merge `O` combines the strings from
+  `N` and `D` to ``foobarbaz''; i.e., it is not TREESAME to any parent.
+
+* `E` changes `quux` to ``xyzzy'', and its merge `P` combines the
+  strings to ``quux xyzzy''. `P` is TREESAME to `O`, but not to `E`.
+
+* `X` is an independent root commit that added a new file `side`, and `Y`
+  modified it. `Y` is TREESAME to `X`. Its merge `Q` added `side` to `P`, and
+  `Q` is TREESAME to `P`, but not to `Y`.
+
+`rev-list` walks backwards through history, including or excluding
+commits based on whether `--full-history` and/or parent rewriting
+(via `--parents` or `--children`) are used. The following settings
+are available.
+
+Default mode::
+	Commits are included if they are not TREESAME to any parent
+	(though this can be changed, see `--sparse` below).  If the
+	commit was a merge, and it was TREESAME to one parent, follow
+	only that parent.  (Even if there are several TREESAME
+	parents, follow only one of them.)  Otherwise, follow all
+	parents.
++
+This results in:
++
+-----------------------------------------------------------------------
+	  .-A---N---O
+	 /     /   /
+	I---------D
+-----------------------------------------------------------------------
++
+Note how the rule to only follow the TREESAME parent, if one is
+available, removed `B` from consideration entirely.  `C` was
+considered via `N`, but is TREESAME.  Root commits are compared to an
+empty tree, so `I` is !TREESAME.
++
+Parent/child relations are only visible with `--parents`, but that does
+not affect the commits selected in default mode, so we have shown the
+parent lines.
+
+--full-history without parent rewriting::
+	This mode differs from the default in one point: always follow
+	all parents of a merge, even if it is TREESAME to one of them.
+	Even if more than one side of the merge has commits that are
+	included, this does not imply that the merge itself is!  In
+	the example, we get
++
+-----------------------------------------------------------------------
+	I  A  B  N  D  O  P  Q
+-----------------------------------------------------------------------
++
+`M` was excluded because it is TREESAME to both parents.  `E`,
+`C` and `B` were all walked, but only `B` was !TREESAME, so the others
+do not appear.
++
+Note that without parent rewriting, it is not really possible to talk
+about the parent/child relationships between the commits, so we show
+them disconnected.
+
+--full-history with parent rewriting::
+	Ordinary commits are only included if they are !TREESAME
+	(though this can be changed, see `--sparse` below).
++
+Merges are always included.  However, their parent list is rewritten:
+Along each parent, prune away commits that are not included
+themselves.  This results in
++
+-----------------------------------------------------------------------
+	  .-A---M---N---O---P---Q
+	 /     /   /   /   /
+	I     B   /   D   /
+	 \   /   /   /   /
+	  `-------------'
+-----------------------------------------------------------------------
++
+Compare to `--full-history` without rewriting above.  Note that `E`
+was pruned away because it is TREESAME, but the parent list of P was
+rewritten to contain `E`'s parent `I`.  The same happened for `C` and
+`N`, and `X`, `Y` and `Q`.
+
+In addition to the above settings, you can change whether TREESAME
+affects inclusion:
+
+--dense::
+	Commits that are walked are included if they are not TREESAME
+	to any parent.
+
+--sparse::
+	All commits that are walked are included.
++
+Note that without `--full-history`, this still simplifies merges: if
+one of the parents is TREESAME, we follow only that one, so the other
+sides of the merge are never walked.
+
+--simplify-merges::
+	First, build a history graph in the same way that
+	`--full-history` with parent rewriting does (see above).
++
+Then simplify each commit `C` to its replacement `C'` in the final
+history according to the following rules:
++
+--
+* Set `C'` to `C`.
++
+* Replace each parent `P` of `C'` with its simplification `P'`.  In
+  the process, drop parents that are ancestors of other parents or that are
+  root commits TREESAME to an empty tree, and remove duplicates, but take care
+  to never drop all parents that we are TREESAME to.
++
+* If after this parent rewriting, `C'` is a root or merge commit (has
+  zero or >1 parents), a boundary commit, or !TREESAME, it remains.
+  Otherwise, it is replaced with its only parent.
+--
++
+The effect of this is best shown by way of comparing to
+`--full-history` with parent rewriting.  The example turns into:
++
+-----------------------------------------------------------------------
+	  .-A---M---N---O
+	 /     /       /
+	I     B       D
+	 \   /       /
+	  `---------'
+-----------------------------------------------------------------------
++
+Note the major differences in `N`, `P`, and `Q` over `--full-history`:
++
+--
+* `N`'s parent list had `I` removed, because it is an ancestor of the
+  other parent `M`.  Still, `N` remained because it is !TREESAME.
++
+* `P`'s parent list similarly had `I` removed.  `P` was then
+  removed completely, because it had one parent and is TREESAME.
++
+* `Q`'s parent list had `Y` simplified to `X`. `X` was then removed, because it
+  was a TREESAME root. `Q` was then removed completely, because it had one
+  parent and is TREESAME.
+--
+
+There is another simplification mode available:
+
+--ancestry-path[=<commit>]::
+	Limit the displayed commits to those which are an ancestor of
+	<commit>, or which are a descendant of <commit>, or are <commit>
+	itself.
++
+As an example use case, consider the following commit history:
++
+-----------------------------------------------------------------------
+	    D---E-------F
+	   /     \       \
+	  B---C---G---H---I---J
+	 /                     \
+	A-------K---------------L--M
+-----------------------------------------------------------------------
++
+A regular 'D..M' computes the set of commits that are ancestors of `M`,
+but excludes the ones that are ancestors of `D`. This is useful to see
+what happened to the history leading to `M` since `D`, in the sense
+that ``what does `M` have that did not exist in `D`''. The result in this
+example would be all the commits, except `A` and `B` (and `D` itself,
+of course).
++
+When we want to find out what commits in `M` are contaminated with the
+bug introduced by `D` and need fixing, however, we might want to view
+only the subset of 'D..M' that are actually descendants of `D`, i.e.
+excluding `C` and `K`. This is exactly what the `--ancestry-path`
+option does. Applied to the 'D..M' range, it results in:
++
+-----------------------------------------------------------------------
+		E-------F
+		 \       \
+		  G---H---I---J
+			       \
+				L--M
+-----------------------------------------------------------------------
++
+We can also use `--ancestry-path=D` instead of `--ancestry-path` which
+means the same thing when applied to the 'D..M' range but is just more
+explicit.
++
+If we instead are interested in a given topic within this range, and all
+commits affected by that topic, we may only want to view the subset of
+`D..M` which contain that topic in their ancestry path.  So, using
+`--ancestry-path=H D..M` for example would result in:
++
+-----------------------------------------------------------------------
+		E
+		 \
+		  G---H---I---J
+			       \
+				L--M
+-----------------------------------------------------------------------
++
+Whereas `--ancestry-path=K D..M` would result in
++
+-----------------------------------------------------------------------
+		K---------------L--M
+-----------------------------------------------------------------------
+
+Before discussing another option, `--show-pulls`, we need to
+create a new example history.
+
+A common problem users face when looking at simplified history is that a
+commit they know changed a file somehow does not appear in the file's
+simplified history. Let's demonstrate a new example and show how options
+such as `--full-history` and `--simplify-merges` works in that case:
+
+-----------------------------------------------------------------------
+	  .-A---M-----C--N---O---P
+	 /     / \  \  \/   /   /
+	I     B   \  R-'`-Z'   /
+	 \   /     \/         /
+	  \ /      /\        /
+	   `---X--'  `---Y--'
+-----------------------------------------------------------------------
+
+For this example, suppose `I` created `file.txt` which was modified by
+`A`, `B`, and `X` in different ways. The single-parent commits `C`, `Z`,
+and `Y` do not change `file.txt`. The merge commit `M` was created by
+resolving the merge conflict to include both changes from `A` and `B`
+and hence is not TREESAME to either. The merge commit `R`, however, was
+created by ignoring the contents of `file.txt` at `M` and taking only
+the contents of `file.txt` at `X`. Hence, `R` is TREESAME to `X` but not
+`M`. Finally, the natural merge resolution to create `N` is to take the
+contents of `file.txt` at `R`, so `N` is TREESAME to `R` but not `C`.
+The merge commits `O` and `P` are TREESAME to their first parents, but
+not to their second parents, `Z` and `Y` respectively.
+
+When using the default mode, `N` and `R` both have a TREESAME parent, so
+those edges are walked and the others are ignored. The resulting history
+graph is:
+
+-----------------------------------------------------------------------
+	I---X
+-----------------------------------------------------------------------
+
+When using `--full-history`, Git walks every edge. This will discover
+the commits `A` and `B` and the merge `M`, but also will reveal the
+merge commits `O` and `P`. With parent rewriting, the resulting graph is:
+
+-----------------------------------------------------------------------
+	  .-A---M--------N---O---P
+	 /     / \  \  \/   /   /
+	I     B   \  R-'`--'   /
+	 \   /     \/         /
+	  \ /      /\        /
+	   `---X--'  `------'
+-----------------------------------------------------------------------
+
+Here, the merge commits `O` and `P` contribute extra noise, as they did
+not actually contribute a change to `file.txt`. They only merged a topic
+that was based on an older version of `file.txt`. This is a common
+issue in repositories using a workflow where many contributors work in
+parallel and merge their topic branches along a single trunk: many
+unrelated merges appear in the `--full-history` results.
+
+When using the `--simplify-merges` option, the commits `O` and `P`
+disappear from the results. This is because the rewritten second parents
+of `O` and `P` are reachable from their first parents. Those edges are
+removed and then the commits look like single-parent commits that are
+TREESAME to their parent. This also happens to the commit `N`, resulting
+in a history view as follows:
+
+-----------------------------------------------------------------------
+	  .-A---M--.
+	 /     /    \
+	I     B      R
+	 \   /      /
+	  \ /      /
+	   `---X--'
+-----------------------------------------------------------------------
+
+In this view, we see all of the important single-parent changes from
+`A`, `B`, and `X`. We also see the carefully-resolved merge `M` and the
+not-so-carefully-resolved merge `R`. This is usually enough information
+to determine why the commits `A` and `B` "disappeared" from history in
+the default view. However, there are a few issues with this approach.
+
+The first issue is performance. Unlike any previous option, the
+`--simplify-merges` option requires walking the entire commit history
+before returning a single result. This can make the option difficult to
+use for very large repositories.
+
+The second issue is one of auditing. When many contributors are working
+on the same repository, it is important which merge commits introduced
+a change into an important branch. The problematic merge `R` above is
+not likely to be the merge commit that was used to merge into an
+important branch. Instead, the merge `N` was used to merge `R` and `X`
+into the important branch. This commit may have information about why
+the change `X` came to override the changes from `A` and `B` in its
+commit message.
+
+--show-pulls::
+	In addition to the commits shown in the default history, show
+	each merge commit that is not TREESAME to its first parent but
+	is TREESAME to a later parent.
++
+When a merge commit is included by `--show-pulls`, the merge is
+treated as if it "pulled" the change from another branch. When using
+`--show-pulls` on this example (and no other options) the resulting
+graph is:
++
+-----------------------------------------------------------------------
+	I---X---R---N
+-----------------------------------------------------------------------
++
+Here, the merge commits `R` and `N` are included because they pulled
+the commits `X` and `R` into the base branch, respectively. These
+merges are the reason the commits `A` and `B` do not appear in the
+default history.
++
+When `--show-pulls` is paired with `--simplify-merges`, the
+graph includes all of the necessary information:
++
+-----------------------------------------------------------------------
+	  .-A---M--.   N
+	 /     /    \ /
+	I     B      R
+	 \   /      /
+	  \ /      /
+	   `---X--'
+-----------------------------------------------------------------------
++
+Notice that since `M` is reachable from `R`, the edge from `N` to `M`
+was simplified away. However, `N` still appears in the history as an
+important commit because it "pulled" the change `R` into the main
+branch.
+
+The `--simplify-by-decoration` option allows you to view only the
+big picture of the topology of the history, by omitting commits
+that are not referenced by tags.  Commits are marked as !TREESAME
+(in other words, kept after history simplification rules described
+above) if (1) they are referenced by tags, or (2) they change the
+contents of the paths given on the command line.  All other
+commits are marked as TREESAME (subject to be simplified away).
+
+ifndef::git-shortlog[]
+ifdef::git-rev-list[]
+Bisection Helpers
+~~~~~~~~~~~~~~~~~
+
+--bisect::
+	Limit output to the one commit object which is roughly halfway between
+	included and excluded commits. Note that the bad bisection ref
+	`refs/bisect/bad` is added to the included commits (if it
+	exists) and the good bisection refs `refs/bisect/good-*` are
+	added to the excluded commits (if they exist). Thus, supposing there
+	are no refs in `refs/bisect/`, if
++
+-----------------------------------------------------------------------
+	$ git rev-list --bisect foo ^bar ^baz
+-----------------------------------------------------------------------
++
+outputs 'midpoint', the output of the two commands
++
+-----------------------------------------------------------------------
+	$ git rev-list foo ^midpoint
+	$ git rev-list midpoint ^bar ^baz
+-----------------------------------------------------------------------
++
+would be of roughly the same length.  Finding the change which
+introduces a regression is thus reduced to a binary search: repeatedly
+generate and test new 'midpoint's until the commit chain is of length
+one.
+
+--bisect-vars::
+	This calculates the same as `--bisect`, except that refs in
+	`refs/bisect/` are not used, and except that this outputs
+	text ready to be eval'ed by the shell. These lines will assign the
+	name of the midpoint revision to the variable `bisect_rev`, and the
+	expected number of commits to be tested after `bisect_rev` is tested
+	to `bisect_nr`, the expected number of commits to be tested if
+	`bisect_rev` turns out to be good to `bisect_good`, the expected
+	number of commits to be tested if `bisect_rev` turns out to be bad to
+	`bisect_bad`, and the number of commits we are bisecting right now to
+	`bisect_all`.
+
+--bisect-all::
+	This outputs all the commit objects between the included and excluded
+	commits, ordered by their distance to the included and excluded
+	commits. Refs in `refs/bisect/` are not used. The farthest
+	from them is displayed first. (This is the only one displayed by
+	`--bisect`.)
++
+This is useful because it makes it easy to choose a good commit to
+test when you want to avoid to test some of them for some reason (they
+may not compile for example).
++
+This option can be used along with `--bisect-vars`, in this case,
+after all the sorted commit objects, there will be the same text as if
+`--bisect-vars` had been used alone.
+endif::git-rev-list[]
+endif::git-shortlog[]
+
+ifndef::git-shortlog[]
+Commit Ordering
+~~~~~~~~~~~~~~~
+
+By default, the commits are shown in reverse chronological order.
+
+--date-order::
+	Show no parents before all of its children are shown, but
+	otherwise show commits in the commit timestamp order.
+
+--author-date-order::
+	Show no parents before all of its children are shown, but
+	otherwise show commits in the author timestamp order.
+
+--topo-order::
+	Show no parents before all of its children are shown, and
+	avoid showing commits on multiple lines of history
+	intermixed.
++
+For example, in a commit history like this:
++
+----------------------------------------------------------------
+
+    ---1----2----4----7
+	\	       \
+	 3----5----6----8---
+
+----------------------------------------------------------------
++
+where the numbers denote the order of commit timestamps, `git
+rev-list` and friends with `--date-order` show the commits in the
+timestamp order: 8 7 6 5 4 3 2 1.
++
+With `--topo-order`, they would show 8 6 5 3 7 4 2 1 (or 8 7 4 2 6 5
+3 1); some older commits are shown before newer ones in order to
+avoid showing the commits from two parallel development track mixed
+together.
+
+--reverse::
+	Output the commits chosen to be shown (see Commit Limiting
+	section above) in reverse order. Cannot be combined with
+	`--walk-reflogs`.
+endif::git-shortlog[]
+
+ifndef::git-shortlog[]
+Object Traversal
+~~~~~~~~~~~~~~~~
+
+These options are mostly targeted for packing of Git repositories.
+
+ifdef::git-rev-list[]
+--objects::
+	Print the object IDs of any object referenced by the listed
+	commits.  `--objects foo ^bar` thus means ``send me
+	all object IDs which I need to download if I have the commit
+	object _bar_ but not _foo_''. See also `--object-names` below.
+
+--in-commit-order::
+	Print tree and blob ids in order of the commits. The tree
+	and blob ids are printed after they are first referenced
+	by a commit.
+
+--objects-edge::
+	Similar to `--objects`, but also print the IDs of excluded
+	commits prefixed with a ``-'' character.  This is used by
+	linkgit:git-pack-objects[1] to build a ``thin'' pack, which records
+	objects in deltified form based on objects contained in these
+	excluded commits to reduce network traffic.
+
+--objects-edge-aggressive::
+	Similar to `--objects-edge`, but it tries harder to find excluded
+	commits at the cost of increased time.  This is used instead of
+	`--objects-edge` to build ``thin'' packs for shallow repositories.
+
+--indexed-objects::
+	Pretend as if all trees and blobs used by the index are listed
+	on the command line.  Note that you probably want to use
+	`--objects`, too.
+
+--unpacked::
+	Only useful with `--objects`; print the object IDs that are not
+	in packs.
+
+--object-names::
+	Only useful with `--objects`; print the names of the object IDs
+	that are found. This is the default behavior. Note that the
+	"name" of each object is ambiguous, and mostly intended as a
+	hint for packing objects. In particular: no distinction is made between
+	the names of tags, trees, and blobs; path names may be modified
+	to remove newlines; and if an object would appear multiple times
+	with different names, only one name is shown.
+
+--no-object-names::
+	Only useful with `--objects`; does not print the names of the object
+	IDs that are found. This inverts `--object-names`. This flag allows
+	the output to be more easily parsed by commands such as
+	linkgit:git-cat-file[1].
+
+--filter=<filter-spec>::
+	Only useful with one of the `--objects*`; omits objects (usually
+	blobs) from the list of printed objects.  The '<filter-spec>'
+	may be one of the following:
++
+The form '--filter=blob:none' omits all blobs.
++
+The form '--filter=blob:limit=<n>[kmg]' omits blobs of size at least n
+bytes or units.  n may be zero.  The suffixes k, m, and g can be used
+to name units in KiB, MiB, or GiB.  For example, 'blob:limit=1k'
+is the same as 'blob:limit=1024'.
++
+The form '--filter=object:type=(tag|commit|tree|blob)' omits all objects
+which are not of the requested type.
++
+The form '--filter=sparse:oid=<blob-ish>' uses a sparse-checkout
+specification contained in the blob (or blob-expression) '<blob-ish>'
+to omit blobs that would not be required for a sparse checkout on
+the requested refs.
++
+The form '--filter=tree:<depth>' omits all blobs and trees whose depth
+from the root tree is >= <depth> (minimum depth if an object is located
+at multiple depths in the commits traversed). <depth>=0 will not include
+any trees or blobs unless included explicitly in the command-line (or
+standard input when --stdin is used). <depth>=1 will include only the
+tree and blobs which are referenced directly by a commit reachable from
+<commit> or an explicitly-given object. <depth>=2 is like <depth>=1
+while also including trees and blobs one more level removed from an
+explicitly-given commit or tree.
++
+Note that the form '--filter=sparse:path=<path>' that wants to read
+from an arbitrary path on the filesystem has been dropped for security
+reasons.
++
+Multiple '--filter=' flags can be specified to combine filters. Only
+objects which are accepted by every filter are included.
++
+The form '--filter=combine:<filter1>+<filter2>+...<filterN>' can also be
+used to combined several filters, but this is harder than just repeating
+the '--filter' flag and is usually not necessary. Filters are joined by
+'{plus}' and individual filters are %-encoded (i.e. URL-encoded).
+Besides the '{plus}' and '%' characters, the following characters are
+reserved and also must be encoded: `~!@#$^&*()[]{}\;",<>?`+&#39;&#96;+
+as well as all characters with ASCII code &lt;= `0x20`, which includes
+space and newline.
++
+Other arbitrary characters can also be encoded. For instance,
+'combine:tree:3+blob:none' and 'combine:tree%3A3+blob%3Anone' are
+equivalent.
+
+--no-filter::
+	Turn off any previous `--filter=` argument.
+
+--filter-provided-objects::
+	Filter the list of explicitly provided objects, which would otherwise
+	always be printed even if they did not match any of the filters. Only
+	useful with `--filter=`.
+
+--filter-print-omitted::
+	Only useful with `--filter=`; prints a list of the objects omitted
+	by the filter.  Object IDs are prefixed with a ``~'' character.
+
+--missing=<missing-action>::
+	A debug option to help with future "partial clone" development.
+	This option specifies how missing objects are handled.
++
+The form '--missing=error' requests that rev-list stop with an error if
+a missing object is encountered.  This is the default action.
++
+The form '--missing=allow-any' will allow object traversal to continue
+if a missing object is encountered.  Missing objects will silently be
+omitted from the results.
++
+The form '--missing=allow-promisor' is like 'allow-any', but will only
+allow object traversal to continue for EXPECTED promisor missing objects.
+Unexpected missing objects will raise an error.
++
+The form '--missing=print' is like 'allow-any', but will also print a
+list of the missing objects.  Object IDs are prefixed with a ``?'' character.
++
+If some tips passed to the traversal are missing, they will be
+considered as missing too, and the traversal will ignore them. In case
+we cannot get their Object ID though, an error will be raised.
+
+--exclude-promisor-objects::
+	(For internal use only.)  Prefilter object traversal at
+	promisor boundary.  This is used with partial clone.  This is
+	stronger than `--missing=allow-promisor` because it limits the
+	traversal, rather than just silencing errors about missing
+	objects.
+endif::git-rev-list[]
+
+--no-walk[=(sorted|unsorted)]::
+	Only show the given commits, but do not traverse their ancestors.
+	This has no effect if a range is specified. If the argument
+	`unsorted` is given, the commits are shown in the order they were
+	given on the command line. Otherwise (if `sorted` or no argument
+	was given), the commits are shown in reverse chronological order
+	by commit time.
+	Cannot be combined with `--graph`.
+
+--do-walk::
+	Overrides a previous `--no-walk`.
+endif::git-shortlog[]
+
+ifndef::git-shortlog[]
+Commit Formatting
+~~~~~~~~~~~~~~~~~
+
+ifdef::git-rev-list[]
+Using these options, linkgit:git-rev-list[1] will act similar to the
+more specialized family of commit log tools: linkgit:git-log[1],
+linkgit:git-show[1], and linkgit:git-whatchanged[1]
+endif::git-rev-list[]
+
+include::pretty-options.adoc[]
+
+--relative-date::
+	Synonym for `--date=relative`.
+
+--date=<format>::
+	Only takes effect for dates shown in human-readable format, such
+	as when using `--pretty`. `log.date` config variable sets a default
+	value for the log command's `--date` option. By default, dates
+	are shown in the original time zone (either committer's or
+	author's). If `-local` is appended to the format (e.g.,
+	`iso-local`), the user's local time zone is used instead.
++
+--
+`--date=relative` shows dates relative to the current time,
+e.g. ``2 hours ago''. The `-local` option has no effect for
+`--date=relative`.
+
+`--date=local` is an alias for `--date=default-local`.
+
+`--date=iso` (or `--date=iso8601`) shows timestamps in a ISO 8601-like format.
+The differences to the strict ISO 8601 format are:
+
+	- a space instead of the `T` date/time delimiter
+	- a space between time and time zone
+	- no colon between hours and minutes of the time zone
+
+`--date=iso-strict` (or `--date=iso8601-strict`) shows timestamps in strict
+ISO 8601 format.
+
+`--date=rfc` (or `--date=rfc2822`) shows timestamps in RFC 2822
+format, often found in email messages.
+
+`--date=short` shows only the date, but not the time, in `YYYY-MM-DD` format.
+
+`--date=raw` shows the date as seconds since the epoch (1970-01-01
+00:00:00 UTC), followed by a space, and then the timezone as an offset
+from UTC (a `+` or `-` with four digits; the first two are hours, and
+the second two are minutes). I.e., as if the timestamp were formatted
+with `strftime("%s %z")`).
+Note that the `-local` option does not affect the seconds-since-epoch
+value (which is always measured in UTC), but does switch the accompanying
+timezone value.
+
+`--date=human` shows the timezone if the timezone does not match the
+current time-zone, and doesn't print the whole date if that matches
+(ie skip printing year for dates that are "this year", but also skip
+the whole date itself if it's in the last few days and we can just say
+what weekday it was).  For older dates the hour and minute is also
+omitted.
+
+`--date=unix` shows the date as a Unix epoch timestamp (seconds since
+1970).  As with `--raw`, this is always in UTC and therefore `-local`
+has no effect.
+
+`--date=format:...` feeds the format `...` to your system `strftime`,
+except for %s, %z, and %Z, which are handled internally.
+Use `--date=format:%c` to show the date in your system locale's
+preferred format.  See the `strftime` manual for a complete list of
+format placeholders. When using `-local`, the correct syntax is
+`--date=format-local:...`.
+
+`--date=default` is the default format, and is based on ctime(3)
+output.  It shows a single line with three-letter day of the week,
+three-letter month, day-of-month, hour-minute-seconds in "HH:MM:SS"
+format, followed by 4-digit year, plus timezone information, unless
+the local time zone is used, e.g. `Thu Jan 1 00:00:00 1970 +0000`.
+--
+
+ifdef::git-rev-list[]
+--header::
+	Print the contents of the commit in raw-format; each record is
+	separated with a NUL character.
+
+--no-commit-header::
+	Suppress the header line containing "commit" and the object ID printed before
+	the specified format.  This has no effect on the built-in formats; only custom
+	formats are affected.
+
+--commit-header::
+	Overrides a previous `--no-commit-header`.
+endif::git-rev-list[]
+
+--parents::
+	Print also the parents of the commit (in the form "commit parent...").
+	Also enables parent rewriting, see 'History Simplification' above.
+
+--children::
+	Print also the children of the commit (in the form "commit child...").
+	Also enables parent rewriting, see 'History Simplification' above.
+
+ifdef::git-rev-list[]
+--timestamp::
+	Print the raw commit timestamp.
+endif::git-rev-list[]
+
+--left-right::
+	Mark which side of a symmetric difference a commit is reachable from.
+	Commits from the left side are prefixed with `<` and those from
+	the right with `>`.  If combined with `--boundary`, those
+	commits are prefixed with `-`.
++
+For example, if you have this topology:
++
+-----------------------------------------------------------------------
+	     y---b---b  branch B
+	    / \ /
+	   /   .
+	  /   / \
+	 o---x---a---a  branch A
+-----------------------------------------------------------------------
++
+you would get an output like this:
++
+-----------------------------------------------------------------------
+	$ git rev-list --left-right --boundary --pretty=oneline A...B
+
+	>bbbbbbb... 3rd on b
+	>bbbbbbb... 2nd on b
+	<aaaaaaa... 3rd on a
+	<aaaaaaa... 2nd on a
+	-yyyyyyy... 1st on b
+	-xxxxxxx... 1st on a
+-----------------------------------------------------------------------
+
+--graph::
+	Draw a text-based graphical representation of the commit history
+	on the left hand side of the output.  This may cause extra lines
+	to be printed in between commits, in order for the graph history
+	to be drawn properly.
+	Cannot be combined with `--no-walk`.
++
+This enables parent rewriting, see 'History Simplification' above.
++
+This implies the `--topo-order` option by default, but the
+`--date-order` option may also be specified.
+
+--show-linear-break[=<barrier>]::
+	When --graph is not used, all history branches are flattened
+	which can make it hard to see that the two consecutive commits
+	do not belong to a linear branch. This option puts a barrier
+	in between them in that case. If `<barrier>` is specified, it
+	is the string that will be shown instead of the default one.
+
+ifdef::git-rev-list[]
+--count::
+	Print a number stating how many commits would have been
+	listed, and suppress all other output.  When used together
+	with `--left-right`, instead print the counts for left and
+	right commits, separated by a tab. When used together with
+	`--cherry-mark`, omit patch equivalent commits from these
+	counts and print the count for equivalent commits separated
+	by a tab.
+endif::git-rev-list[]
+endif::git-shortlog[]
diff --git a/Documentation/revisions.adoc b/Documentation/revisions.adoc
new file mode 100644
index 0000000000..6ea6c7cead
--- /dev/null
+++ b/Documentation/revisions.adoc
@@ -0,0 +1,421 @@
+SPECIFYING REVISIONS
+--------------------
+
+A revision parameter '<rev>' typically, but not necessarily, names a
+commit object.  It uses what is called an 'extended SHA-1'
+syntax.  Here are various ways to spell object names.  The
+ones listed near the end of this list name trees and
+blobs contained in a commit.
+
+NOTE: This document shows the "raw" syntax as seen by git. The shell
+and other UIs might require additional quoting to protect special
+characters and to avoid word splitting.
+
+'<sha1>', e.g. 'dae86e1950b1277e545cee180551750029cfe735', 'dae86e'::
+  The full SHA-1 object name (40-byte hexadecimal string), or
+  a leading substring that is unique within the repository.
+  E.g. dae86e1950b1277e545cee180551750029cfe735 and dae86e both
+  name the same commit object if there is no other object in
+  your repository whose object name starts with dae86e.
+
+'<describeOutput>', e.g. 'v1.7.4.2-679-g3bee7fb'::
+  Output from `git describe`; i.e. a closest tag, optionally
+  followed by a dash and a number of commits, followed by a dash, a
+  'g', and an abbreviated object name.
+
+'<refname>', e.g. 'master', 'heads/master', 'refs/heads/master'::
+  A symbolic ref name.  E.g. 'master' typically means the commit
+  object referenced by 'refs/heads/master'.  If you
+  happen to have both 'heads/master' and 'tags/master', you can
+  explicitly say 'heads/master' to tell Git which one you mean.
+  When ambiguous, a '<refname>' is disambiguated by taking the
+  first match in the following rules:
++
+  . If '$GIT_DIR/<refname>' exists, that is what you mean (this is usually
+    useful only for `HEAD`, `FETCH_HEAD`, `ORIG_HEAD`, `MERGE_HEAD`,
+    `REBASE_HEAD`, `REVERT_HEAD`, `CHERRY_PICK_HEAD`, `BISECT_HEAD`
+    and `AUTO_MERGE`);
+
+  . otherwise, 'refs/<refname>' if it exists;
+
+  . otherwise, 'refs/tags/<refname>' if it exists;
+
+  . otherwise, 'refs/heads/<refname>' if it exists;
+
+  . otherwise, 'refs/remotes/<refname>' if it exists;
+
+  . otherwise, 'refs/remotes/<refname>/HEAD' if it exists.
+
++
+  `HEAD`:::
+    names the commit on which you based the changes in the working tree.
+  `FETCH_HEAD`:::
+    records the branch which you fetched from a remote repository with
+    your last `git fetch` invocation.
+  `ORIG_HEAD`:::
+    is created by commands that move your `HEAD` in a drastic way (`git
+    am`, `git merge`, `git rebase`, `git reset`), to record the position
+    of the `HEAD` before their operation, so that you can easily change
+    the tip of the branch back to the state before you ran them.
+  `MERGE_HEAD`:::
+    records the commit(s) which you are merging into your branch when you
+    run `git merge`.
+  `REBASE_HEAD`:::
+    during a rebase, records the commit at which the operation is
+    currently stopped, either because of conflicts or an `edit` command in
+    an interactive rebase.
+  `REVERT_HEAD`:::
+    records the commit which you are reverting when you run `git revert`.
+  `CHERRY_PICK_HEAD`:::
+    records the commit which you are cherry-picking when you run `git
+    cherry-pick`.
+  `BISECT_HEAD`:::
+    records the current commit to be tested when you run `git bisect
+    --no-checkout`.
+  `AUTO_MERGE`:::
+    records a tree object corresponding to the state the
+    'ort' merge strategy wrote to the working tree when a merge operation
+    resulted in conflicts.
+
++
+Note that any of the 'refs/*' cases above may come either from
+the `$GIT_DIR/refs` directory or from the `$GIT_DIR/packed-refs` file.
+While the ref name encoding is unspecified, UTF-8 is preferred as
+some output processing may assume ref names in UTF-8.
+
+'@'::
+  '@' alone is a shortcut for `HEAD`.
+
+'[<refname>]@{<date>}', e.g. 'master@\{yesterday\}', 'HEAD@{5 minutes ago}'::
+  A ref followed by the suffix '@' with a date specification
+  enclosed in a brace
+  pair (e.g. '\{yesterday\}', '{1 month 2 weeks 3 days 1 hour 1
+  second ago}' or '{1979-02-26 18:30:00}') specifies the value
+  of the ref at a prior point in time.  This suffix may only be
+  used immediately following a ref name and the ref must have an
+  existing log ('$GIT_DIR/logs/<ref>'). Note that this looks up the state
+  of your *local* ref at a given time; e.g., what was in your local
+  'master' branch last week. If you want to look at commits made during
+  certain times, see `--since` and `--until`.
+
+'<refname>@{<n>}', e.g. 'master@\{1\}'::
+  A ref followed by the suffix '@' with an ordinal specification
+  enclosed in a brace pair (e.g. '\{1\}', '\{15\}') specifies
+  the n-th prior value of that ref.  For example 'master@\{1\}'
+  is the immediate prior value of 'master' while 'master@\{5\}'
+  is the 5th prior value of 'master'. This suffix may only be used
+  immediately following a ref name and the ref must have an existing
+  log ('$GIT_DIR/logs/<refname>').
+
+'@{<n>}', e.g. '@\{1\}'::
+  You can use the '@' construct with an empty ref part to get at a
+  reflog entry of the current branch. For example, if you are on
+  branch 'blabla' then '@\{1\}' means the same as 'blabla@\{1\}'.
+
+'@{-<n>}', e.g. '@{-1}'::
+  The construct '@{-<n>}' means the <n>th branch/commit checked out
+  before the current one.
+
+'[<branchname>]@\{upstream\}', e.g. 'master@\{upstream\}', '@\{u\}'::
+  A branch B may be set up to build on top of a branch X (configured with
+  `branch.<name>.merge`) at a remote R (configured with
+  `branch.<name>.remote`). B@{u} refers to the remote-tracking branch for
+  the branch X taken from remote R, typically found at `refs/remotes/R/X`.
+
+'[<branchname>]@\{push\}', e.g. 'master@\{push\}', '@\{push\}'::
+  The suffix '@\{push}' reports the branch "where we would push to" if
+  `git push` were run while `branchname` was checked out (or the current
+  `HEAD` if no branchname is specified). Like for '@\{upstream\}', we report
+  the remote-tracking branch that corresponds to that branch at the remote.
++
+Here's an example to make it more clear:
++
+------------------------------
+$ git config push.default current
+$ git config remote.pushdefault myfork
+$ git switch -c mybranch origin/master
+
+$ git rev-parse --symbolic-full-name @{upstream}
+refs/remotes/origin/master
+
+$ git rev-parse --symbolic-full-name @{push}
+refs/remotes/myfork/mybranch
+------------------------------
++
+Note in the example that we set up a triangular workflow, where we pull
+from one location and push to another. In a non-triangular workflow,
+'@\{push}' is the same as '@\{upstream}', and there is no need for it.
++
+This suffix is also accepted when spelled in uppercase, and means the same
+thing no matter the case.
+
+'<rev>{caret}[<n>]', e.g. 'HEAD{caret}, v1.5.1{caret}0'::
+  A suffix '{caret}' to a revision parameter means the first parent of
+  that commit object.  '{caret}<n>' means the <n>th parent (i.e.
+  '<rev>{caret}'
+  is equivalent to '<rev>{caret}1').  As a special rule,
+  '<rev>{caret}0' means the commit itself and is used when '<rev>' is the
+  object name of a tag object that refers to a commit object.
+
+'<rev>{tilde}[<n>]', e.g. 'HEAD{tilde}, master{tilde}3'::
+  A suffix '{tilde}' to a revision parameter means the first parent of
+  that commit object.
+  A suffix '{tilde}<n>' to a revision parameter means the commit
+  object that is the <n>th generation ancestor of the named
+  commit object, following only the first parents.  I.e. '<rev>{tilde}3' is
+  equivalent to '<rev>{caret}{caret}{caret}' which is equivalent to
+  '<rev>{caret}1{caret}1{caret}1'.  See below for an illustration of
+  the usage of this form.
+
+'<rev>{caret}{<type>}', e.g. 'v0.99.8{caret}\{commit\}'::
+  A suffix '{caret}' followed by an object type name enclosed in
+  brace pair means dereference the object at '<rev>' recursively until
+  an object of type '<type>' is found or the object cannot be
+  dereferenced anymore (in which case, barf).
+  For example, if '<rev>' is a commit-ish, '<rev>{caret}\{commit\}'
+  describes the corresponding commit object.
+  Similarly, if '<rev>' is a tree-ish, '<rev>{caret}\{tree\}'
+  describes the corresponding tree object.
+  '<rev>{caret}0'
+  is a short-hand for '<rev>{caret}\{commit\}'.
++
+'<rev>{caret}\{object\}' can be used to make sure '<rev>' names an
+object that exists, without requiring '<rev>' to be a tag, and
+without dereferencing '<rev>'; because a tag is already an object,
+it does not have to be dereferenced even once to get to an object.
++
+'<rev>{caret}\{tag\}' can be used to ensure that '<rev>' identifies an
+existing tag object.
+
+'<rev>{caret}{}', e.g. 'v0.99.8{caret}{}'::
+  A suffix '{caret}' followed by an empty brace pair
+  means the object could be a tag,
+  and dereference the tag recursively until a non-tag object is
+  found.
+
+'<rev>{caret}{/<text>}', e.g. 'HEAD^{/fix nasty bug}'::
+  A suffix '{caret}' to a revision parameter, followed by a brace
+  pair that contains a text led by a slash,
+  is the same as the ':/fix nasty bug' syntax below except that
+  it returns the youngest matching commit which is reachable from
+  the '<rev>' before '{caret}'.
+
+':/<text>', e.g. ':/fix nasty bug'::
+  A colon, followed by a slash, followed by a text, names
+  a commit whose commit message matches the specified regular expression.
+  This name returns the youngest matching commit which is
+  reachable from any ref, including HEAD.
+  The regular expression can match any part of the
+  commit message. To match messages starting with a string, one can use
+  e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what
+  is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a
+  literal '!' character, followed by 'foo'. Any other sequence beginning with
+  ':/!' is reserved for now.
+  Depending on the given text, the shell's word splitting rules might
+  require additional quoting.
+
+'<rev>:<path>', e.g. 'HEAD:README', 'master:./README'::
+  A suffix ':' followed by a path names the blob or tree
+  at the given path in the tree-ish object named by the part
+  before the colon.
+  A path starting with './' or '../' is relative to the current working directory.
+  The given path will be converted to be relative to the working tree's root directory.
+  This is most useful to address a blob or tree from a commit or tree that has
+  the same tree structure as the working tree.
+
+':[<n>:]<path>', e.g. ':0:README', ':README'::
+  A colon, optionally followed by a stage number (0 to 3) and a
+  colon, followed by a path, names a blob object in the
+  index at the given path. A missing stage number (and the colon
+  that follows it) names a stage 0 entry. During a merge, stage
+  1 is the common ancestor, stage 2 is the target branch's version
+  (typically the current branch), and stage 3 is the version from
+  the branch which is being merged.
+
+Here is an illustration, by Jon Loeliger.  Both commit nodes B
+and C are parents of commit node A.  Parent commits are ordered
+left-to-right.
+
+........................................
+G   H   I   J
+ \ /     \ /
+  D   E   F
+   \  |  / \
+    \ | /   |
+     \|/    |
+      B     C
+       \   /
+        \ /
+         A
+........................................
+
+    A =      = A^0
+    B = A^   = A^1     = A~1
+    C =      = A^2
+    D = A^^  = A^1^1   = A~2
+    E = B^2  = A^^2
+    F = B^3  = A^^3
+    G = A^^^ = A^1^1^1 = A~3
+    H = D^2  = B^^2    = A^^^2  = A~2^2
+    I = F^   = B^3^    = A^^3^
+    J = F^2  = B^3^2   = A^^3^2
+
+
+SPECIFYING RANGES
+-----------------
+
+History traversing commands such as `git log` operate on a set
+of commits, not just a single commit.
+
+For these commands,
+specifying a single revision, using the notation described in the
+previous section, means the set of commits `reachable` from the given
+commit.
+
+Specifying several revisions means the set of commits reachable from
+any of the given commits.
+
+A commit's reachable set is the commit itself and the commits in
+its ancestry chain.
+
+There are several notations to specify a set of connected commits
+(called a "revision range"), illustrated below.
+
+
+Commit Exclusions
+~~~~~~~~~~~~~~~~~
+
+'{caret}<rev>' (caret) Notation::
+ To exclude commits reachable from a commit, a prefix '{caret}'
+ notation is used.  E.g. '{caret}r1 r2' means commits reachable
+ from 'r2' but exclude the ones reachable from 'r1' (i.e. 'r1' and
+ its ancestors).
+
+Dotted Range Notations
+~~~~~~~~~~~~~~~~~~~~~~
+
+The '..' (two-dot) Range Notation::
+ The '{caret}r1 r2' set operation appears so often that there is a shorthand
+ for it.  When you have two commits 'r1' and 'r2' (named according
+ to the syntax explained in SPECIFYING REVISIONS above), you can ask
+ for commits that are reachable from r2 excluding those that are reachable
+ from r1 by '{caret}r1 r2' and it can be written as 'r1..r2'.
+
+The '\...' (three-dot) Symmetric Difference Notation::
+ A similar notation 'r1\...r2' is called symmetric difference
+ of 'r1' and 'r2' and is defined as
+ 'r1 r2 --not $(git merge-base --all r1 r2)'.
+ It is the set of commits that are reachable from either one of
+ 'r1' (left side) or 'r2' (right side) but not from both.
+
+In these two shorthand notations, you can omit one end and let it default to HEAD.
+For example, 'origin..' is a shorthand for 'origin..HEAD' and asks "What
+did I do since I forked from the origin branch?"  Similarly, '..origin'
+is a shorthand for 'HEAD..origin' and asks "What did the origin do since
+I forked from them?"  Note that '..' would mean 'HEAD..HEAD' which is an
+empty range that is both reachable and unreachable from HEAD.
+
+Commands that are specifically designed to take two distinct ranges
+(e.g. "git range-diff R1 R2" to compare two ranges) do exist, but
+they are exceptions.  Unless otherwise noted, all "git" commands
+that operate on a set of commits work on a single revision range.
+In other words, writing two "two-dot range notation" next to each
+other, e.g.
+
+    $ git log A..B C..D
+
+does *not* specify two revision ranges for most commands.  Instead
+it will name a single connected set of commits, i.e. those that are
+reachable from either B or D but are reachable from neither A or C.
+In a linear history like this:
+
+    ---A---B---o---o---C---D
+
+because A and B are reachable from C, the revision range specified
+by these two dotted ranges is a single commit D.
+
+
+Other <rev>{caret} Parent Shorthand Notations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Three other shorthands exist, particularly useful for merge commits,
+for naming a set that is formed by a commit and its parent commits.
+
+The 'r1{caret}@' notation means all parents of 'r1'.
+
+The 'r1{caret}!' notation includes commit 'r1' but excludes all of its parents.
+By itself, this notation denotes the single commit 'r1'.
+
+The '<rev>{caret}-[<n>]' notation includes '<rev>' but excludes the <n>th
+parent (i.e. a shorthand for '<rev>{caret}<n>..<rev>'), with '<n>' = 1 if
+not given. This is typically useful for merge commits where you
+can just pass '<commit>{caret}-' to get all the commits in the branch
+that was merged in merge commit '<commit>' (including '<commit>'
+itself).
+
+While '<rev>{caret}<n>' was about specifying a single commit parent, these
+three notations also consider its parents. For example you can say
+'HEAD{caret}2{caret}@', however you cannot say 'HEAD{caret}@{caret}2'.
+
+Revision Range Summary
+----------------------
+
+'<rev>'::
+	Include commits that are reachable from <rev> (i.e. <rev> and its
+	ancestors).
+
+'{caret}<rev>'::
+	Exclude commits that are reachable from <rev> (i.e. <rev> and its
+	ancestors).
+
+'<rev1>..<rev2>'::
+	Include commits that are reachable from <rev2> but exclude
+	those that are reachable from <rev1>.  When either <rev1> or
+	<rev2> is omitted, it defaults to `HEAD`.
+
+'<rev1>\...<rev2>'::
+	Include commits that are reachable from either <rev1> or
+	<rev2> but exclude those that are reachable from both.  When
+	either <rev1> or <rev2> is omitted, it defaults to `HEAD`.
+
+'<rev>{caret}@', e.g. 'HEAD{caret}@'::
+  A suffix '{caret}' followed by an at sign is the same as listing
+  all parents of '<rev>' (meaning, include anything reachable from
+  its parents, but not the commit itself).
+
+'<rev>{caret}!', e.g. 'HEAD{caret}!'::
+  A suffix '{caret}' followed by an exclamation mark is the same
+  as giving commit '<rev>' and all its parents prefixed with
+  '{caret}' to exclude them (and their ancestors).
+
+'<rev>{caret}-<n>', e.g. 'HEAD{caret}-, HEAD{caret}-2'::
+	Equivalent to '<rev>{caret}<n>..<rev>', with '<n>' = 1 if not
+	given.
+
+Here are a handful of examples using the Loeliger illustration above,
+with each step in the notation's expansion and selection carefully
+spelt out:
+
+....
+   Args   Expanded arguments    Selected commits
+   D                            G H D
+   D F                          G H I J D F
+   ^G D                         H D
+   ^D B                         E I J F B
+   ^D B C                       E I J F B C
+   C                            I J F C
+   B..C   = ^B C                C
+   B...C  = B ^F C              G H D E B C
+   B^-    = B^..B
+	  = ^B^1 B              E I J F B
+   C^@    = C^1
+	  = F                   I J F
+   B^@    = B^1 B^2 B^3
+	  = D E F               D G H E F I J
+   C^!    = C ^C^@
+	  = C ^C^1
+	  = C ^F                C
+   B^!    = B ^B^@
+	  = B ^B^1 ^B^2 ^B^3
+	  = B ^D ^E ^F          B
+   F^! D  = F ^I ^J D           G H D F
+....
diff --git a/Documentation/scalar.adoc b/Documentation/scalar.adoc
new file mode 100644
index 0000000000..7e4259c674
--- /dev/null
+++ b/Documentation/scalar.adoc
@@ -0,0 +1,179 @@
+scalar(1)
+=========
+
+NAME
+----
+scalar - A tool for managing large Git repositories
+
+SYNOPSIS
+--------
+[verse]
+scalar clone [--single-branch] [--branch <main-branch>] [--full-clone]
+	[--[no-]src] <url> [<enlistment>]
+scalar list
+scalar register [<enlistment>]
+scalar unregister [<enlistment>]
+scalar run ( all | config | commit-graph | fetch | loose-objects | pack-files ) [<enlistment>]
+scalar reconfigure [ --all | <enlistment> ]
+scalar diagnose [<enlistment>]
+scalar delete <enlistment>
+
+DESCRIPTION
+-----------
+
+Scalar is a repository management tool that optimizes Git for use in large
+repositories. Scalar improves performance by configuring advanced Git settings,
+maintaining repositories in the background, and helping to reduce data sent
+across the network.
+
+An important Scalar concept is the enlistment: this is the top-level directory
+of the project. It usually contains the subdirectory `src/` which is a Git
+worktree. This encourages the separation between tracked files (inside `src/`)
+and untracked files, such as build artifacts (outside `src/`). When registering
+an existing Git worktree with Scalar whose name is not `src`, the enlistment
+will be identical to the worktree.
+
+The `scalar` command implements various subcommands, and different options
+depending on the subcommand. With the exception of `clone`, `list` and
+`reconfigure --all`, all subcommands expect to be run in an enlistment.
+
+The following options can be specified _before_ the subcommand:
+
+-C <directory>::
+	Before running the subcommand, change the working directory. This
+	option imitates the same option of linkgit:git[1].
+
+-c <key>=<value>::
+	For the duration of running the specified subcommand, configure this
+	setting. This option imitates the same option of linkgit:git[1].
+
+COMMANDS
+--------
+
+Clone
+~~~~~
+
+clone [<options>] <url> [<enlistment>]::
+	Clones the specified repository, similar to linkgit:git-clone[1]. By
+	default, only commit and tree objects are cloned. Once finished, the
+	worktree is located at `<enlistment>/src`.
++
+The sparse-checkout feature is enabled (except when run with `--full-clone`)
+and the only files present are those in the top-level directory. Use
+`git sparse-checkout set` to expand the set of directories you want to see,
+or `git sparse-checkout disable` to expand to all files (see
+linkgit:git-sparse-checkout[1] for more details). You can explore the
+subdirectories outside your sparse-checkout by using `git ls-tree
+HEAD[:<directory>]`.
+
+-b <name>::
+--branch <name>::
+	Instead of checking out the branch pointed to by the cloned
+	repository's HEAD, check out the `<name>` branch instead.
+
+--[no-]single-branch::
+	Clone only the history leading to the tip of a single branch, either
+	specified by the `--branch` option or the primary branch remote's
+	`HEAD` points at.
++
+Further fetches into the resulting repository will only update the
+remote-tracking branch for the branch this option was used for the initial
+cloning. If the HEAD at the remote did not point at any branch when
+`--single-branch` clone was made, no remote-tracking branch is created.
+
+--[no-]src::
+	By default, `scalar clone` places the cloned repository within a
+	`<entlistment>/src` directory. Use `--no-src` to place the cloned
+	repository directly in the `<enlistment>` directory.
+
+--[no-]tags::
+	By default, `scalar clone` will fetch the tag objects advertised by
+	the remote and future `git fetch` commands will do the same. Use
+	`--no-tags` to avoid fetching tags in `scalar clone` and to configure
+	the repository to avoid fetching tags in the future. To fetch tags after
+	cloning with `--no-tags`, run `git fetch --tags`.
+
+--[no-]full-clone::
+	A sparse-checkout is initialized by default. This behavior can be
+	turned off via `--full-clone`.
+
+List
+~~~~
+
+list::
+	List enlistments that are currently registered by Scalar. This
+	subcommand does not need to be run inside an enlistment.
+
+Register
+~~~~~~~~
+
+register [<enlistment>]::
+	Adds the enlistment's repository to the list of registered repositories
+	and starts background maintenance. If `<enlistment>` is not provided,
+	then the enlistment associated with the current working directory is
+	registered.
++
+Note: when this subcommand is called in a worktree that is called `src/`, its
+parent directory is considered to be the Scalar enlistment. If the worktree is
+_not_ called `src/`, it itself will be considered to be the Scalar enlistment.
+
+Unregister
+~~~~~~~~~~
+
+unregister [<enlistment>]::
+	Remove the specified repository from the list of repositories
+	registered with Scalar and stop the scheduled background maintenance.
+
+Run
+~~~
+
+scalar run ( all | config | commit-graph | fetch | loose-objects | pack-files ) [<enlistment>]::
+	Run the given maintenance task (or all tasks, if `all` was specified).
+	Except for `all` and `config`, this subcommand simply hands off to
+	linkgit:git-maintenance[1] (mapping `fetch` to `prefetch` and
+	`pack-files` to `incremental-repack`).
++
+These tasks are run automatically as part of the scheduled maintenance,
+as soon as the repository is registered with Scalar. It should therefore
+not be necessary to run this subcommand manually.
++
+The `config` task is specific to Scalar and configures all those
+opinionated default settings that make Git work more efficiently with
+large repositories. As this task is run as part of `scalar clone`
+automatically, explicit invocations of this task are rarely needed.
+
+Reconfigure
+~~~~~~~~~~~
+
+After a Scalar upgrade, or when the configuration of a Scalar enlistment
+was somehow corrupted or changed by mistake, this subcommand allows to
+reconfigure the enlistment.
+
+With the `--all` option, all enlistments currently registered with Scalar
+will be reconfigured. Use this option after each Scalar upgrade.
+
+Diagnose
+~~~~~~~~
+
+diagnose [<enlistment>]::
+    When reporting issues with Scalar, it is often helpful to provide the
+    information gathered by this command, including logs and certain
+    statistics describing the data shape of the current enlistment.
++
+The output of this command is a `.zip` file that is written into
+a directory adjacent to the worktree in the `src` directory.
+
+Delete
+~~~~~~
+
+delete <enlistment>::
+	This subcommand lets you delete an existing Scalar enlistment from your
+	local file system, unregistering the repository.
+
+SEE ALSO
+--------
+linkgit:git-clone[1], linkgit:git-maintenance[1].
+
+GIT
+---
+Part of the linkgit:git[1] suite
diff --git a/Documentation/sequencer.adoc b/Documentation/sequencer.adoc
new file mode 100644
index 0000000000..3bceb56474
--- /dev/null
+++ b/Documentation/sequencer.adoc
@@ -0,0 +1,16 @@
+--continue::
+	Continue the operation in progress using the information in
+	`.git/sequencer`.  Can be used to continue after resolving
+	conflicts in a failed cherry-pick or revert.
+
+--skip::
+	Skip the current commit and continue with the rest of the
+	sequence.
+
+--quit::
+	Forget about the current operation in progress.  Can be used
+	to clear the sequencer state after a failed cherry-pick or
+	revert.
+
+--abort::
+	Cancel the operation and return to the pre-sequence state.
diff --git a/Documentation/signoff-option.adoc b/Documentation/signoff-option.adoc
new file mode 100644
index 0000000000..cddfb225d1
--- /dev/null
+++ b/Documentation/signoff-option.adoc
@@ -0,0 +1,18 @@
+ifdef::git-commit[]
+`-s`::
+endif::git-commit[]
+`--signoff`::
+`--no-signoff`::
+	Add a `Signed-off-by` trailer by the committer at the end of the commit
+	log message.  The meaning of a signoff depends on the project
+	to which you're committing.  For example, it may certify that
+	the committer has the rights to submit the work under the
+	project's license or agrees to some contributor representation,
+	such as a Developer Certificate of Origin.
+	(See https://developercertificate.org for the one used by the
+	Linux kernel and Git projects.)  Consult the documentation or
+	leadership of the project to which you're contributing to
+	understand how the signoffs are used in that project.
++
+The `--no-signoff` option can be used to countermand an earlier `--signoff`
+option on the command line.
diff --git a/Documentation/technical/.gitignore b/Documentation/technical/.gitignore
new file mode 100644
index 0000000000..8aa891daee
--- /dev/null
+++ b/Documentation/technical/.gitignore
@@ -0,0 +1 @@
+api-index.txt
diff --git a/Documentation/technical/api-error-handling.adoc b/Documentation/technical/api-error-handling.adoc
new file mode 100644
index 0000000000..665c4960b4
--- /dev/null
+++ b/Documentation/technical/api-error-handling.adoc
@@ -0,0 +1,103 @@
+Error reporting in git
+======================
+
+`BUG`, `bug`, `die`, `usage`, `error`, and `warning` report errors of
+various kinds.
+
+- `BUG` is for failed internal assertions that should never happen,
+  i.e. a bug in git itself.
+
+- `bug` (lower-case, not `BUG`) is supposed to be used like `BUG` but
+  prints a "BUG" message instead of calling `abort()`.
++
+A call to `bug()` will then result in a "real" call to the `BUG()`
+function, either explicitly by invoking `BUG_if_bug()` after call(s)
+to `bug()`, or implicitly at `exit()` time where we'll check if we
+encountered any outstanding `bug()` invocations.
++
+If there were no prior calls to `bug()` before invoking `BUG_if_bug()`
+the latter is a NOOP. The `BUG_if_bug()` function takes the same
+arguments as `BUG()` itself. Calling `BUG_if_bug()` explicitly isn't
+necessary, but ensures that we die as soon as possible.
++
+If you know you had prior calls to `bug()` then calling `BUG()` itself
+is equivalent to calling `BUG_if_bug()`, the latter being a wrapper
+calling `BUG()` if we've set a flag indicating that we've called
+`bug()`.
++
+This is for the convenience of APIs who'd like to potentially report
+more than one "bug", such as the optbug() validation in
+parse-options.c.
+
+- `die` is for fatal application errors.  It prints a message to
+  the user and exits with status 128.
+
+- `usage` is for errors in command line usage.  After printing its
+  message, it exits with status 129.  (See also `usage_with_options`
+  in the link:api-parse-options.html[parse-options API].)
+
+- `error` is for non-fatal library errors.  It prints a message
+  to the user and returns -1 for convenience in signaling the error
+  to the caller.
+
+- `warning` is for reporting situations that probably should not
+  occur but which the user (and Git) can continue to work around
+  without running into too many problems.  Like `error`, it
+  returns -1 after reporting the situation to the caller.
+
+These reports will be logged via the trace2 facility. See the "error"
+event in link:api-trace2.html[trace2 API].
+
+Customizable error handlers
+---------------------------
+
+The default behavior of `die` and `error` is to write a message to
+stderr and then exit or return as appropriate.  This behavior can be
+overridden using `set_die_routine` and `set_error_routine`.  For
+example, "git daemon" uses set_die_routine to write the reason `die`
+was called to syslog before exiting.
+
+Library errors
+--------------
+
+Functions return a negative integer on error.  Details beyond that
+vary from function to function:
+
+- Some functions return -1 for all errors.  Others return a more
+  specific value depending on how the caller might want to react
+  to the error.
+
+- Some functions report the error to stderr with `error`,
+  while others leave that for the caller to do.
+
+- errno is not meaningful on return from most functions (except
+  for thin wrappers for system calls).
+
+Check the function's API documentation to be sure.
+
+Caller-handled errors
+---------------------
+
+An increasing number of functions take a parameter 'struct strbuf *err'.
+On error, such functions append a message about what went wrong to the
+'err' strbuf.  The message is meant to be complete enough to be passed
+to `die` or `error` as-is.  For example:
+
+	if (ref_transaction_commit(transaction, &err))
+		die("%s", err.buf);
+
+The 'err' parameter will be untouched if no error occurred, so multiple
+function calls can be chained:
+
+	t = ref_transaction_begin(&err);
+	if (!t ||
+	    ref_transaction_update(t, "HEAD", ..., &err) ||
+	    ret_transaction_commit(t, &err))
+		die("%s", err.buf);
+
+The 'err' parameter must be a pointer to a valid strbuf.  To silence
+a message, pass a strbuf that is explicitly ignored:
+
+	if (thing_that_can_fail_in_an_ignorable_way(..., &err))
+		/* This failure is okay. */
+		strbuf_reset(&err);
diff --git a/Documentation/technical/api-index-skel.adoc b/Documentation/technical/api-index-skel.adoc
new file mode 100644
index 0000000000..7780a76b08
--- /dev/null
+++ b/Documentation/technical/api-index-skel.adoc
@@ -0,0 +1,13 @@
+Git API Documents
+=================
+
+Git has grown a set of internal APIs over time.  This collection
+documents them.
+
+////////////////////////////////////////////////////////////////
+// table of contents begin
+////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////
+// table of contents end
+////////////////////////////////////////////////////////////////
diff --git a/Documentation/technical/api-index.sh b/Documentation/technical/api-index.sh
new file mode 100755
index 0000000000..13478e2a4d
--- /dev/null
+++ b/Documentation/technical/api-index.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+if test $# -ne 2
+then
+	echo >&2 "USAGE: $0 <SOURCE_DIR> <OUTPUT>"
+	exit 1
+fi
+
+SOURCE_DIR="$1"
+OUTPUT="$2"
+
+(
+	cd "$SOURCE_DIR"
+
+	c=////////////////////////////////////////////////////////////////
+	skel=api-index-skel.adoc
+	sed -e '/^\/\/ table of contents begin/q' "$skel"
+	echo "$c"
+
+	ls api-*.adoc |
+	while read filename
+	do
+		case "$filename" in
+		api-index-skel.adoc | api-index.adoc) continue ;;
+		esac
+		title=$(sed -e 1q "$filename")
+		html=${filename%.txt}.html
+		echo "* link:$html[$title]"
+	done
+	echo "$c"
+	sed -n -e '/^\/\/ table of contents end/,$p' "$skel"
+) >"$OUTPUT"+
+
+if test -f "$OUTPUT" && cmp "$OUTPUT" "$OUTPUT"+ >/dev/null
+then
+	rm -f "$OUTPUT"+
+else
+	mv "$OUTPUT"+ "$OUTPUT"
+fi
diff --git a/Documentation/technical/api-merge.adoc b/Documentation/technical/api-merge.adoc
new file mode 100644
index 0000000000..c2ba01828c
--- /dev/null
+++ b/Documentation/technical/api-merge.adoc
@@ -0,0 +1,36 @@
+merge API
+=========
+
+The merge API helps a program to reconcile two competing sets of
+improvements to some files (e.g., unregistered changes from the work
+tree versus changes involved in switching to a new branch), reporting
+conflicts if found.  The library called through this API is
+responsible for a few things.
+
+ * determining which trees to merge (recursive ancestor consolidation);
+
+ * lining up corresponding files in the trees to be merged (rename
+   detection, subtree shifting), reporting edge cases like add/add
+   and rename/rename conflicts to the user;
+
+ * performing a three-way merge of corresponding files, taking
+   path-specific merge drivers (specified in `.gitattributes`)
+   into account.
+
+Data structures
+---------------
+
+* `mmbuffer_t`, `mmfile_t`
+
+These store data usable for use by the xdiff backend, for writing and
+for reading, respectively.  See `xdiff/xdiff.h` for the definitions
+and `diff.c` for examples.
+
+* `struct ll_merge_options`
+
+Check merge-ll.h for details.
+
+Low-level (single file) merge
+-----------------------------
+
+Check merge-ll.h for details.
diff --git a/Documentation/technical/api-parse-options.adoc b/Documentation/technical/api-parse-options.adoc
new file mode 100644
index 0000000000..61fa6ee167
--- /dev/null
+++ b/Documentation/technical/api-parse-options.adoc
@@ -0,0 +1,349 @@
+parse-options API
+=================
+
+The parse-options API is used to parse and massage options in Git
+and to provide a usage help with consistent look.
+
+Basics
+------
+
+The argument vector `argv[]` may usually contain mandatory or optional
+'non-option arguments', e.g. a filename or a branch, 'options', and
+'subcommands'.
+Options are optional arguments that start with a dash and
+that allow to change the behavior of a command.
+
+* There are basically three types of options:
+  'boolean' options,
+  options with (mandatory) 'arguments' and
+  options with 'optional arguments'
+  (i.e. a boolean option that can be adjusted).
+
+* There are basically two forms of options:
+  'Short options' consist of one dash (`-`) and one alphanumeric
+  character.
+  'Long options' begin with two dashes (`--`) and some
+  alphanumeric characters.
+
+* Options are case-sensitive.
+  Please define 'lower-case long options' only.
+
+The parse-options API allows:
+
+* 'stuck' and 'separate form' of options with arguments.
+  `-oArg` is stuck, `-o Arg` is separate form.
+  `--option=Arg` is stuck, `--option Arg` is separate form.
+
+* Long options may be 'abbreviated', as long as the abbreviation
+  is unambiguous.
+
+* Short options may be bundled, e.g. `-a -b` can be specified as `-ab`.
+
+* Boolean long options can be 'negated' (or 'unset') by prepending
+  `no-`, e.g. `--no-abbrev` instead of `--abbrev`. Conversely,
+  options that begin with `no-` can be 'negated' by removing it.
+  Other long options can be unset (e.g., set string to NULL, set
+  integer to 0) by prepending `no-`.
+
+* Options and non-option arguments can clearly be separated using the `--`
+  option, e.g. `-a -b --option -- --this-is-a-file` indicates that
+  `--this-is-a-file` must not be processed as an option.
+
+Subcommands are special in a couple of ways:
+
+* Subcommands only have long form, and they have no double dash prefix, no
+  negated form, and no description, and they don't take any arguments, and
+  can't be abbreviated.
+
+* There must be exactly one subcommand among the arguments, or zero if the
+  command has a default operation mode.
+
+* All arguments following the subcommand are considered to be arguments of
+  the subcommand, and, conversely, arguments meant for the subcommand may
+  not precede the subcommand.
+
+Therefore, if the options array contains at least one subcommand and
+`parse_options()` encounters the first dashless argument, it will either:
+
+* stop and return, if that dashless argument is a known subcommand, setting
+  `value` to the function pointer associated with that subcommand, storing
+  the name of the subcommand in argv[0], and leaving the rest of the
+  arguments unprocessed, or
+
+* stop and return, if it was invoked with the `PARSE_OPT_SUBCOMMAND_OPTIONAL`
+  flag and that dashless argument doesn't match any subcommands, leaving
+  `value` unchanged and the rest of the arguments unprocessed, or
+
+* show error and usage, and abort.
+
+Steps to parse options
+----------------------
+
+. `#include "parse-options.h"`
+
+. define a NULL-terminated
+  `static const char * const builtin_foo_usage[]` array
+  containing alternative usage strings
+
+. define `builtin_foo_options` array as described below
+  in section 'Data Structure'.
+
+. in `cmd_foo(int argc, const char **argv, const char *prefix)`
+  call
+
+	argc = parse_options(argc, argv, prefix, builtin_foo_options, builtin_foo_usage, flags);
++
+`parse_options()` will filter out the processed options of `argv[]` and leave the
+non-option arguments in `argv[]`.
+`argc` is updated appropriately because of the assignment.
++
+You can also pass NULL instead of a usage array as the fifth parameter of
+parse_options(), to avoid displaying a help screen with usage info and
+option list.  This should only be done if necessary, e.g. to implement
+a limited parser for only a subset of the options that needs to be run
+before the full parser, which in turn shows the full help message.
++
+Flags are the bitwise-or of:
+
+`PARSE_OPT_KEEP_DASHDASH`::
+	Keep the `--` that usually separates options from
+	non-option arguments.
+
+`PARSE_OPT_STOP_AT_NON_OPTION`::
+	Usually the whole argument vector is massaged and reordered.
+	Using this flag, processing is stopped at the first non-option
+	argument.
+
+`PARSE_OPT_KEEP_ARGV0`::
+	Keep the first argument, which contains the program name.  It's
+	removed from argv[] by default.
+
+`PARSE_OPT_KEEP_UNKNOWN_OPT`::
+	Keep unknown options instead of erroring out.  This doesn't
+	work for all combinations of arguments as users might expect
+	it to do.  E.g. if the first argument in `--unknown --known`
+	takes a value (which we can't know), the second one is
+	mistakenly interpreted as a known option.  Similarly, if
+	`PARSE_OPT_STOP_AT_NON_OPTION` is set, the second argument in
+	`--unknown value` will be mistakenly interpreted as a
+	non-option, not as a value belonging to the unknown option,
+	the parser early.  That's why parse_options() errors out if
+	both options are set.
+	Note that non-option arguments are always kept, even without
+	this flag.
+
+`PARSE_OPT_NO_INTERNAL_HELP`::
+	By default, parse_options() handles `-h`, `--help` and
+	`--help-all` internally, by showing a help screen.  This option
+	turns it off and allows one to add custom handlers for these
+	options, or to just leave them unknown.
+
+`PARSE_OPT_SUBCOMMAND_OPTIONAL`::
+	Don't error out when no subcommand is specified.
+
+Note that `PARSE_OPT_STOP_AT_NON_OPTION` is incompatible with subcommands;
+while `PARSE_OPT_KEEP_DASHDASH` and `PARSE_OPT_KEEP_UNKNOWN_OPT` can only be
+used with subcommands when combined with `PARSE_OPT_SUBCOMMAND_OPTIONAL`.
+
+Data Structure
+--------------
+
+The main data structure is an array of the `option` struct,
+say `static struct option builtin_add_options[]`.
+There are some macros to easily define options:
+
+`OPT__ABBREV(&int_var)`::
+	Add `--abbrev[=<n>]`.
+
+`OPT__COLOR(&int_var, description)`::
+	Add `--color[=<when>]` and `--no-color`.
+
+`OPT__DRY_RUN(&int_var, description)`::
+	Add `-n, --dry-run`.
+
+`OPT__FORCE(&int_var, description)`::
+	Add `-f, --force`.
+
+`OPT__QUIET(&int_var, description)`::
+	Add `-q, --quiet`.
+
+`OPT__VERBOSE(&int_var, description)`::
+	Add `-v, --verbose`.
+
+`OPT_GROUP(description)`::
+	Start an option group. `description` is a short string that
+	describes the group or an empty string.
+	Start the description with an upper-case letter.
+
+`OPT_BOOL(short, long, &int_var, description)`::
+	Introduce a boolean option. `int_var` is set to one with
+	`--option` and set to zero with `--no-option`.
+
+`OPT_COUNTUP(short, long, &int_var, description)`::
+	Introduce a count-up option.
+	Each use of `--option` increments `int_var`, starting from zero
+	(even if initially negative), and `--no-option` resets it to
+	zero. To determine if `--option` or `--no-option` was encountered at
+	all, initialize `int_var` to a negative value, and if it is still
+	negative after parse_options(), then neither `--option` nor
+	`--no-option` was seen.
+
+`OPT_BIT(short, long, &int_var, description, mask)`::
+	Introduce a boolean option.
+	If used, `int_var` is bitwise-ored with `mask`.
+
+`OPT_NEGBIT(short, long, &int_var, description, mask)`::
+	Introduce a boolean option.
+	If used, `int_var` is bitwise-anded with the inverted `mask`.
+
+`OPT_SET_INT(short, long, &int_var, description, integer)`::
+	Introduce an integer option.
+	`int_var` is set to `integer` with `--option`, and
+	reset to zero with `--no-option`.
+
+`OPT_STRING(short, long, &str_var, arg_str, description)`::
+	Introduce an option with string argument.
+	The string argument is put into `str_var`.
+
+`OPT_STRING_LIST(short, long, &struct string_list, arg_str, description)`::
+	Introduce an option with string argument.
+	The string argument is stored as an element in `string_list`.
+	Use of `--no-option` will clear the list of preceding values.
+
+`OPT_INTEGER(short, long, &int_var, description)`::
+	Introduce an option with integer argument.
+	The integer is put into `int_var`.
+
+`OPT_MAGNITUDE(short, long, &unsigned_long_var, description)`::
+	Introduce an option with a size argument. The argument must be a
+	non-negative integer and may include a suffix of 'k', 'm' or 'g' to
+	scale the provided value by 1024, 1024^2 or 1024^3 respectively.
+	The scaled value is put into `unsigned_long_var`.
+
+`OPT_EXPIRY_DATE(short, long, &timestamp_t_var, description)`::
+	Introduce an option with expiry date argument, see `parse_expiry_date()`.
+	The timestamp is put into `timestamp_t_var`.
+
+`OPT_CALLBACK(short, long, &var, arg_str, description, func_ptr)`::
+	Introduce an option with argument.
+	The argument will be fed into the function given by `func_ptr`
+	and the result will be put into `var`.
+	See 'Option Callbacks' below for a more elaborate description.
+
+`OPT_FILENAME(short, long, &var, description)`::
+	Introduce an option with a filename argument.
+	The filename will be prefixed by passing the filename along with
+	the prefix argument of `parse_options()` to `prefix_filename()`.
+
+`OPT_NUMBER_CALLBACK(&var, description, func_ptr)`::
+	Recognize numerical options like -123 and feed the integer as
+	if it was an argument to the function given by `func_ptr`.
+	The result will be put into `var`.  There can be only one such
+	option definition.  It cannot be negated and it takes no
+	arguments.  Short options that happen to be digits take
+	precedence over it.
+
+`OPT_COLOR_FLAG(short, long, &int_var, description)`::
+	Introduce an option that takes an optional argument that can
+	have one of three values: "always", "never", or "auto".  If the
+	argument is not given, it defaults to "always".  The `--no-` form
+	works like `--long=never`; it cannot take an argument.  If
+	"always", set `int_var` to 1; if "never", set `int_var` to 0; if
+	"auto", set `int_var` to 1 if stdout is a tty or a pager,
+	0 otherwise.
+
+`OPT_NOOP_NOARG(short, long)`::
+	Introduce an option that has no effect and takes no arguments.
+	Use it to hide deprecated options that are still to be recognized
+	and ignored silently.
+
+`OPT_PASSTHRU(short, long, &char_var, arg_str, description, flags)`::
+	Introduce an option that will be reconstructed into a char* string,
+	which must be initialized to NULL. This is useful when you need to
+	pass the command-line option to another command. Any previous value
+	will be overwritten, so this should only be used for options where
+	the last one specified on the command line wins.
+
+`OPT_PASSTHRU_ARGV(short, long, &strvec_var, arg_str, description, flags)`::
+	Introduce an option where all instances of it on the command-line will
+	be reconstructed into a strvec. This is useful when you need to
+	pass the command-line option, which can be specified multiple times,
+	to another command.
+
+`OPT_CMDMODE(short, long, &int_var, description, enum_val)`::
+	Define an "operation mode" option, only one of which in the same
+	group of "operating mode" options that share the same `int_var`
+	can be given by the user. `int_var` is set to `enum_val` when the
+	option is used, but an error is reported if other "operating mode"
+	option has already set its value to the same `int_var`.
+	In new commands consider using subcommands instead.
+
+`OPT_SUBCOMMAND(long, &fn_ptr, subcommand_fn)`::
+	Define a subcommand.  `subcommand_fn` is put into `fn_ptr` when
+	this subcommand is used.
+
+The last element of the array must be `OPT_END()`.
+
+If not stated otherwise, interpret the arguments as follows:
+
+* `short` is a character for the short option
+  (e.g. `'e'` for `-e`, use `0` to omit),
+
+* `long` is a string for the long option
+  (e.g. `"example"` for `--example`, use `NULL` to omit),
+
+* `int_var` is an integer variable,
+
+* `str_var` is a string variable (`char *`),
+
+* `arg_str` is the string that is shown as argument
+  (e.g. `"branch"` will result in `<branch>`).
+  If set to `NULL`, three dots (`...`) will be displayed.
+
+* `description` is a short string to describe the effect of the option.
+  It shall begin with a lower-case letter and a full stop (`.`) shall be
+  omitted at the end.
+
+Option Callbacks
+----------------
+
+The function must be defined in this form:
+
+	int func(const struct option *opt, const char *arg, int unset)
+
+The callback mechanism is as follows:
+
+* Inside `func`, the only interesting member of the structure
+  given by `opt` is the void pointer `opt->value`.
+  `*opt->value` will be the value that is saved into `var`, if you
+  use `OPT_CALLBACK()`.
+  For example, do `*(unsigned long *)opt->value = 42;` to get 42
+  into an `unsigned long` variable.
+
+* Return value `0` indicates success and non-zero return
+  value will invoke `usage_with_options()` and, thus, die.
+
+* If the user negates the option, `arg` is `NULL` and `unset` is 1.
+
+Sophisticated option parsing
+----------------------------
+
+If you need, for example, option callbacks with optional arguments
+or without arguments at all, or if you need other special cases,
+that are not handled by the macros above, you need to specify the
+members of the `option` structure manually.
+
+This is not covered in this document, but well documented
+in `parse-options.h` itself.
+
+Examples
+--------
+
+See `test-parse-options.c` and
+`builtin/add.c`,
+`builtin/clone.c`,
+`builtin/commit.c`,
+`builtin/fetch.c`,
+`builtin/fsck.c`,
+`builtin/rm.c`
+for real-world examples.
diff --git a/Documentation/technical/api-path-walk.adoc b/Documentation/technical/api-path-walk.adoc
new file mode 100644
index 0000000000..7075d0d5ab
--- /dev/null
+++ b/Documentation/technical/api-path-walk.adoc
@@ -0,0 +1,63 @@
+Path-Walk API
+=============
+
+The path-walk API is used to walk reachable objects, but to visit objects
+in batches based on a common path they appear in, or by type.
+
+For example, all reachable commits are visited in a group. All tags are
+visited in a group. Then, all root trees are visited. At some point, all
+blobs reachable via a path `my/dir/to/A` are visited. When there are
+multiple paths possible to reach the same object, then only one of those
+paths is used to visit the object.
+
+Basics
+------
+
+To use the path-walk API, include `path-walk.h` and call
+`walk_objects_by_path()` with a customized `path_walk_info` struct. The
+struct is used to set all of the options for how the walk should proceed.
+Let's dig into the different options and their use.
+
+`path_fn` and `path_fn_data`::
+	The most important option is the `path_fn` option, which is a
+	function pointer to the callback that can execute logic on the
+	object IDs for objects grouped by type and path. This function
+	also receives a `data` value that corresponds to the
+	`path_fn_data` member, for providing custom data structures to
+	this callback function.
+
+`revs`::
+	To configure the exact details of the reachable set of objects,
+	use the `revs` member and initialize it using the revision
+	machinery in `revision.h`. Initialize `revs` using calls such as
+	`setup_revisions()` or `parse_revision_opt()`. Do not call
+	`prepare_revision_walk()`, as that will be called within
+	`walk_objects_by_path()`.
++
+It is also important that you do not specify the `--objects` flag for the
+`revs` struct. The revision walk should only be used to walk commits, and
+the objects will be walked in a separate way based on those starting
+commits.
+
+`commits`, `blobs`, `trees`, `tags`::
+	By default, these members are enabled and signal that the path-walk
+	API should call the `path_fn` on objects of these types. Specialized
+	applications could disable some options to make it simpler to walk
+	the objects or to have fewer calls to `path_fn`.
++
+While it is possible to walk only commits in this way, consumers would be
+better off using the revision walk API instead.
+
+`prune_all_uninteresting`::
+	By default, all reachable paths are emitted by the path-walk API.
+	This option allows consumers to declare that they are not
+	interested in paths where all included objects are marked with the
+	`UNINTERESTING` flag. This requires using the `boundary` option in
+	the revision walk so that the walk emits commits marked with the
+	`UNINTERESTING` flag.
+
+Examples
+--------
+
+See example usages in:
+	`t/helper/test-path-walk.c`
diff --git a/Documentation/technical/api-simple-ipc.adoc b/Documentation/technical/api-simple-ipc.adoc
new file mode 100644
index 0000000000..c4fb152b23
--- /dev/null
+++ b/Documentation/technical/api-simple-ipc.adoc
@@ -0,0 +1,105 @@
+Simple-IPC API
+==============
+
+The Simple-IPC API is a collection of `ipc_` prefixed library routines
+and a basic communication protocol that allows an IPC-client process to
+send an application-specific IPC-request message to an IPC-server
+process and receive an application-specific IPC-response message.
+
+Communication occurs over a named pipe on Windows and a Unix domain
+socket on other platforms.  IPC-clients and IPC-servers rendezvous at
+a previously agreed-to application-specific pathname (which is outside
+the scope of this design) that is local to the computer system.
+
+The IPC-server routines within the server application process create a
+thread pool to listen for connections and receive request messages
+from multiple concurrent IPC-clients.  When received, these messages
+are dispatched up to the server application callbacks for handling.
+IPC-server routines then incrementally relay responses back to the
+IPC-client.
+
+The IPC-client routines within a client application process connect
+to the IPC-server and send a request message and wait for a response.
+When received, the response is returned back to the caller.
+
+For example, the `fsmonitor--daemon` feature will be built as a server
+application on top of the IPC-server library routines.  It will have
+threads watching for file system events and a thread pool waiting for
+client connections.  Clients, such as `git status`, will request a list
+of file system events since a point in time and the server will
+respond with a list of changed files and directories.  The formats of
+the request and response are application-specific; the IPC-client and
+IPC-server routines treat them as opaque byte streams.
+
+
+Comparison with sub-process model
+---------------------------------
+
+The Simple-IPC mechanism differs from the existing `sub-process.c`
+model (Documentation/technical/long-running-process-protocol.txt) and
+used by applications like Git-LFS.  In the LFS-style sub-process model,
+the helper is started by the foreground process, communication happens
+via a pair of file descriptors bound to the stdin/stdout of the
+sub-process, the sub-process only serves the current foreground
+process, and the sub-process exits when the foreground process
+terminates.
+
+In the Simple-IPC model the server is a very long-running service.  It
+can service many clients at the same time and has a private socket or
+named pipe connection to each active client.  It might be started
+(on-demand) by the current client process or it might have been
+started by a previous client or by the OS at boot time.  The server
+process is not associated with a terminal and it persists after
+clients terminate.  Clients do not have access to the stdin/stdout of
+the server process and therefore must communicate over sockets or
+named pipes.
+
+
+Server startup and shutdown
+---------------------------
+
+How an application server based upon IPC-server is started is also
+outside the scope of the Simple-IPC design and is a property of the
+application using it.  For example, the server might be started or
+restarted during routine maintenance operations, or it might be
+started as a system service during the system boot-up sequence, or it
+might be started on-demand by a foreground Git command when needed.
+
+Similarly, server shutdown is a property of the application using
+the simple-ipc routines.  For example, the server might decide to
+shutdown when idle or only upon explicit request.
+
+
+Simple-IPC protocol
+-------------------
+
+The Simple-IPC protocol consists of a single request message from the
+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 (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
+transmit the message.  It allows the receiver to incrementally receive
+the message in chunks and to know when they have received the entire
+message.
+
+The actual byte format of the client request and server response
+messages are application specific.  The IPC layer transmits and
+receives them as opaque byte buffers without any concern for the
+content within.  It is the job of the calling application layer to
+understand the contents of the request and response messages.
+
+
+Summary
+-------
+
+Conceptually, the Simple-IPC protocol is similar to an HTTP REST
+request.  Clients connect, make an application-specific and
+stateless request, receive an application-specific
+response, and disconnect.  It is a one round trip facility for
+querying the server.  The Simple-IPC routines hide the socket,
+named pipe, and thread pool details and allow the application
+layer to focus on the task at hand.
diff --git a/Documentation/technical/api-trace2.adoc b/Documentation/technical/api-trace2.adoc
new file mode 100644
index 0000000000..cf493dae03
--- /dev/null
+++ b/Documentation/technical/api-trace2.adoc
@@ -0,0 +1,1352 @@
+= Trace2 API
+
+The Trace2 API can be used to print debug, performance, and telemetry
+information to stderr or a file.  The Trace2 feature is inactive unless
+explicitly enabled by enabling one or more Trace2 Targets.
+
+The Trace2 API is intended to replace the existing (Trace1)
+`printf()`-style tracing provided by the existing `GIT_TRACE` and
+`GIT_TRACE_PERFORMANCE` facilities.  During initial implementation,
+Trace2 and Trace1 may operate in parallel.
+
+The Trace2 API defines a set of high-level messages with known fields,
+such as (`start`: `argv`) and (`exit`: {`exit-code`, `elapsed-time`}).
+
+Trace2 instrumentation throughout the Git code base sends Trace2
+messages to the enabled Trace2 Targets.  Targets transform these
+messages content into purpose-specific formats and write events to
+their data streams.  In this manner, the Trace2 API can drive
+many different types of analysis.
+
+Targets are defined using a VTable allowing easy extension to other
+formats in the future.  This might be used to define a binary format,
+for example.
+
+Trace2 is controlled using `trace2.*` config values in the system and
+global config files and `GIT_TRACE2*` environment variables.  Trace2 does
+not read from repo local or worktree config files, nor does it respect
+`-c` command line config settings.
+
+== Trace2 Targets
+
+Trace2 defines the following set of Trace2 Targets.
+Format details are given in a later section.
+
+=== The Normal Format Target
+
+The normal format target is a traditional `printf()` format and similar
+to the `GIT_TRACE` format.  This format is enabled with the `GIT_TRACE2`
+environment variable or the `trace2.normalTarget` system or global
+config setting.
+
+For example
+
+------------
+$ export GIT_TRACE2=~/log.normal
+$ git version
+git version 2.20.1.155.g426c96fcdb
+------------
+
+or
+
+------------
+$ git config --global trace2.normalTarget ~/log.normal
+$ git version
+git version 2.20.1.155.g426c96fcdb
+------------
+
+yields
+
+------------
+$ cat ~/log.normal
+12:28:42.620009 common-main.c:38                  version 2.20.1.155.g426c96fcdb
+12:28:42.620989 common-main.c:39                  start git version
+12:28:42.621101 git.c:432                         cmd_name version (version)
+12:28:42.621215 git.c:662                         exit elapsed:0.001227 code:0
+12:28:42.621250 trace2/tr2_tgt_normal.c:124       atexit elapsed:0.001265 code:0
+------------
+
+=== The Performance Format Target
+
+The performance format target (PERF) is a column-based format to
+replace `GIT_TRACE_PERFORMANCE` and is suitable for development and
+testing, possibly to complement tools like `gprof`.  This format is
+enabled with the `GIT_TRACE2_PERF` environment variable or the
+`trace2.perfTarget` system or global config setting.
+
+For example
+
+------------
+$ export GIT_TRACE2_PERF=~/log.perf
+$ git version
+git version 2.20.1.155.g426c96fcdb
+------------
+
+or
+
+------------
+$ git config --global trace2.perfTarget ~/log.perf
+$ git version
+git version 2.20.1.155.g426c96fcdb
+------------
+
+yields
+
+------------
+$ cat ~/log.perf
+12:28:42.620675 common-main.c:38                  | d0 | main                     | version      |     |           |           |            | 2.20.1.155.g426c96fcdb
+12:28:42.621001 common-main.c:39                  | d0 | main                     | start        |     |  0.001173 |           |            | git version
+12:28:42.621111 git.c:432                         | d0 | main                     | cmd_name     |     |           |           |            | version (version)
+12:28:42.621225 git.c:662                         | d0 | main                     | exit         |     |  0.001227 |           |            | code:0
+12:28:42.621259 trace2/tr2_tgt_perf.c:211         | d0 | main                     | atexit       |     |  0.001265 |           |            | code:0
+------------
+
+=== The Event Format Target
+
+The event format target is a JSON-based format of event data suitable
+for telemetry analysis.  This format is enabled with the `GIT_TRACE2_EVENT`
+environment variable or the `trace2.eventTarget` system or global config
+setting.
+
+For example
+
+------------
+$ export GIT_TRACE2_EVENT=~/log.event
+$ git version
+git version 2.20.1.155.g426c96fcdb
+------------
+
+or
+
+------------
+$ git config --global trace2.eventTarget ~/log.event
+$ git version
+git version 2.20.1.155.g426c96fcdb
+------------
+
+yields
+
+------------
+$ cat ~/log.event
+{"event":"version","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.620713Z","file":"common-main.c","line":38,"evt":"4","exe":"2.20.1.155.g426c96fcdb"}
+{"event":"start","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621027Z","file":"common-main.c","line":39,"t_abs":0.001173,"argv":["git","version"]}
+{"event":"cmd_name","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621122Z","file":"git.c","line":432,"name":"version","hierarchy":"version"}
+{"event":"exit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621236Z","file":"git.c","line":662,"t_abs":0.001227,"code":0}
+{"event":"atexit","sid":"20190408T191610.507018Z-H9b68c35f-P000059a8","thread":"main","time":"2019-01-16T17:28:42.621268Z","file":"trace2/tr2_tgt_event.c","line":163,"t_abs":0.001265,"code":0}
+------------
+
+=== Enabling a Target
+
+To enable a target, set the corresponding environment variable or
+system or global config value to one of the following:
+
+include::../trace2-target-values.adoc[]
+
+When trace files are written to a target directory, they will be named according
+to the last component of the SID (optionally followed by a counter to avoid
+filename collisions).
+
+== Trace2 API
+
+The Trace2 public API is defined and documented in `trace2.h`; refer to it for
+more information.  All public functions and macros are prefixed
+with `trace2_` and are implemented in `trace2.c`.
+
+There are no public Trace2 data structures.
+
+The Trace2 code also defines a set of private functions and data types
+in the `trace2/` directory.  These symbols are prefixed with `tr2_`
+and should only be used by functions in `trace2.c` (or other private
+source files in `trace2/`).
+
+=== Conventions for Public Functions and Macros
+
+Some functions have a `_fl()` suffix to indicate that they take `file`
+and `line-number` arguments.
+
+Some functions have a `_va_fl()` suffix to indicate that they also
+take a `va_list` argument.
+
+Some functions have a `_printf_fl()` suffix to indicate that they also
+take a `printf()` style format with a variable number of arguments.
+
+CPP wrapper macros are defined to hide most of these details.
+
+== Trace2 Target Formats
+
+=== NORMAL Format
+
+Events are written as lines of the form:
+
+------------
+[<time> SP <filename>:<line> SP+] <event-name> [[SP] <event-message>] LF
+------------
+
+`<event-name>`::
+
+	is the event name.
+
+`<event-message>`::
+	is a free-form `printf()` message intended for human consumption.
++
+Note that this may contain embedded LF or CRLF characters that are
+not escaped, so the event may spill across multiple lines.
+
+If `GIT_TRACE2_BRIEF` or `trace2.normalBrief` is true, the `time`, `filename`,
+and `line` fields are omitted.
+
+This target is intended to be more of a summary (like GIT_TRACE) and
+less detailed than the other targets.  It ignores thread, region, and
+data messages, for example.
+
+=== PERF Format
+
+Events are written as lines of the form:
+
+------------
+[<time> SP <filename>:<line> SP+
+    BAR SP] d<depth> SP
+    BAR SP <thread-name> SP+
+    BAR SP <event-name> SP+
+    BAR SP [r<repo-id>] SP+
+    BAR SP [<t_abs>] SP+
+    BAR SP [<t_rel>] SP+
+    BAR SP [<category>] SP+
+    BAR SP DOTS* <perf-event-message>
+    LF
+------------
+
+`<depth>`::
+	is the git process depth.  This is the number of parent
+	git processes.  A top-level git command has depth value "d0".
+	A child of it has depth value "d1".  A second level child
+	has depth value "d2" and so on.
+
+`<thread-name>`::
+	is a unique name for the thread.  The primary thread
+	is called "main".  Other thread names are of the form "th%d:%s"
+	and include a unique number and the name of the thread-proc.
+
+`<event-name>`::
+	is the event name.
+
+`<repo-id>`::
+	when present, is a number indicating the repository
+	in use.  A `def_repo` event is emitted when a repository is
+	opened.  This defines the repo-id and associated worktree.
+	Subsequent repo-specific events will reference this repo-id.
++
+Currently, this is always "r1" for the main repository.
+This field is in anticipation of in-proc submodules in the future.
+
+`<t_abs>`::
+	when present, is the absolute time in seconds since the
+	program started.
+
+`<t_rel>`::
+	when present, is time in seconds relative to the start of
+	the current region.  For a thread-exit event, it is the elapsed
+	time of the thread.
+
+`<category>`::
+	is present on region and data events and is used to
+	indicate a broad category, such as "index" or "status".
+
+`<perf-event-message>`::
+	is a free-form `printf()` message intended for human consumption.
+
+------------
+15:33:33.532712 wt-status.c:2310                  | d0 | main                     | region_enter | r1  |  0.126064 |           | status     | label:print
+15:33:33.532712 wt-status.c:2331                  | d0 | main                     | region_leave | r1  |  0.127568 |  0.001504 | status     | label:print
+------------
+
+If `GIT_TRACE2_PERF_BRIEF` or `trace2.perfBrief` is true, the `time`, `file`,
+and `line` fields are omitted.
+
+------------
+d0 | main                     | region_leave | r1  |  0.011717 |  0.009122 | index      | label:preload
+------------
+
+The PERF target is intended for interactive performance analysis
+during development and is quite noisy.
+
+=== EVENT Format
+
+Each event is a JSON-object containing multiple key/value pairs
+written as a single line and followed by a LF.
+
+------------
+'{' <key> ':' <value> [',' <key> ':' <value>]* '}' LF
+------------
+
+Some key/value pairs are common to all events and some are
+event-specific.
+
+==== Common Key/Value Pairs
+
+The following key/value pairs are common to all events:
+
+------------
+{
+	"event":"version",
+	"sid":"20190408T191827.272759Z-H9b68c35f-P00003510",
+	"thread":"main",
+	"time":"2019-04-08T19:18:27.282761Z",
+	"file":"common-main.c",
+	"line":42,
+	...
+}
+------------
+
+`"event":<event>`::
+	is the event name.
+
+`"sid":<sid>`::
+	is the session-id.  This is a unique string to identify the
+	process instance to allow all events emitted by a process to
+	be identified.  A session-id is used instead of a PID because
+	PIDs are recycled by the OS.  For child git processes, the
+	session-id is prepended with the session-id of the parent git
+	process to allow parent-child relationships to be identified
+	during post-processing.
+
+`"thread":<thread>`::
+	is the thread name.
+
+`"time":<time>`::
+	is the UTC time of the event.
+
+`"file":<filename>`::
+	is source file generating the event.
+
+`"line":<line-number>`::
+	is the integer source line number generating the event.
+
+`"repo":<repo-id>`::
+	when present, is the integer repo-id as described previously.
+
+If `GIT_TRACE2_EVENT_BRIEF` or `trace2.eventBrief` is true, the `file`
+and `line` fields are omitted from all events and the `time` field is
+only present on the "start" and "atexit" events.
+
+==== Event-Specific Key/Value Pairs
+
+`"version"`::
+	This event gives the version of the executable and the EVENT format. It
+	should always be the first event in a trace session. The EVENT format
+	version will be incremented if new event types are added, if existing
+	fields are removed, or if there are significant changes in
+	interpretation of existing events or fields. Smaller changes, such as
+	adding a new field to an existing event, will not require an increment
+	to the EVENT format version.
++
+------------
+{
+	"event":"version",
+	...
+	"evt":"4",		       # EVENT format version
+	"exe":"2.20.1.155.g426c96fcdb" # git version
+}
+------------
+
+`"too_many_files"`::
+	This event is written to the git-trace2-discard sentinel file if there
+	are too many files in the target trace directory (see the
+	trace2.maxFiles config option).
++
+------------
+{
+	"event":"too_many_files",
+	...
+}
+------------
+
+`"start"`::
+	This event contains the complete argv received by main().
++
+------------
+{
+	"event":"start",
+	...
+	"t_abs":0.001227, # elapsed time in seconds
+	"argv":["git","version"]
+}
+------------
+
+`"exit"`::
+	This event is emitted when git calls `exit()`.
++
+------------
+{
+	"event":"exit",
+	...
+	"t_abs":0.001227, # elapsed time in seconds
+	"code":0	  # exit code
+}
+------------
+
+`"atexit"`::
+	This event is emitted by the Trace2 `atexit` routine during
+	final shutdown.  It should be the last event emitted by the
+	process.
++
+(The elapsed time reported here is greater than the time reported in
+the "exit" event because it runs after all other atexit tasks have
+completed.)
++
+------------
+{
+	"event":"atexit",
+	...
+	"t_abs":0.001227, # elapsed time in seconds
+	"code":0          # exit code
+}
+------------
+
+`"signal"`::
+	This event is emitted when the program is terminated by a user
+	signal.  Depending on the platform, the signal event may
+	prevent the "atexit" event from being generated.
++
+------------
+{
+	"event":"signal",
+	...
+	"t_abs":0.001227,  # elapsed time in seconds
+	"signo":13         # SIGTERM, SIGINT, etc.
+}
+------------
+
+`"error"`::
+	This event is emitted when one of the `BUG()`, `bug()`, `error()`,
+	`die()`, `warning()`, or `usage()` functions are called.
++
+------------
+{
+	"event":"error",
+	...
+	"msg":"invalid option: --cahced", # formatted error message
+	"fmt":"invalid option: %s"	  # error format string
+}
+------------
++
+The error event may be emitted more than once.  The format string
+allows post-processors to group errors by type without worrying
+about specific error arguments.
+
+`"cmd_path"`::
+	This event contains the discovered full path of the git
+	executable (on platforms that are configured to resolve it).
++
+------------
+{
+	"event":"cmd_path",
+	...
+	"path":"C:/work/gfw/git.exe"
+}
+------------
+
+`"cmd_ancestry"`::
+	This event contains the text command name for the parent (and earlier
+	generations of parents) of the current process, in an array ordered from
+	nearest parent to furthest great-grandparent. It may not be implemented
+	on all platforms.
++
+------------
+{
+	"event":"cmd_ancestry",
+	...
+	"ancestry":["bash","tmux: server","systemd"]
+}
+------------
+
+`"cmd_name"`::
+	This event contains the command name for this git process
+	and the hierarchy of commands from parent git processes.
++
+------------
+{
+	"event":"cmd_name",
+	...
+	"name":"pack-objects",
+	"hierarchy":"push/pack-objects"
+}
+------------
++
+Normally, the "name" field contains the canonical name of the
+command.  When a canonical name is not available, one of
+these special values are used:
++
+------------
+"_query_"            # "git --html-path"
+"_run_dashed_"       # when "git foo" tries to run "git-foo"
+"_run_shell_alias_"  # alias expansion to a shell command
+"_run_git_alias_"    # alias expansion to a git command
+"_usage_"            # usage error
+------------
+
+`"cmd_mode"`::
+	This event, when present, describes the command variant. This
+	event may be emitted more than once.
++
+------------
+{
+	"event":"cmd_mode",
+	...
+	"name":"branch"
+}
+------------
++
+The "name" field is an arbitrary string to describe the command mode.
+For example, checkout can checkout a branch or an individual file.
+And these variations typically have different performance
+characteristics that are not comparable.
+
+`"alias"`::
+	This event is present when an alias is expanded.
++
+------------
+{
+	"event":"alias",
+	...
+	"alias":"l",		 # registered alias
+	"argv":["log","--graph"] # alias expansion
+}
+------------
+
+`"child_start"`::
+	This event describes a child process that is about to be
+	spawned.
++
+------------
+{
+	"event":"child_start",
+	...
+	"child_id":2,
+	"child_class":"?",
+	"use_shell":false,
+	"argv":["git","rev-list","--objects","--stdin","--not","--all","--quiet"]
+
+	"hook_name":"<hook_name>"  # present when child_class is "hook"
+	"cd":"<path>"		   # present when cd is required
+}
+------------
++
+The "child_id" field can be used to match this child_start with the
+corresponding child_exit event.
++
+The "child_class" field is a rough classification, such as "editor",
+"pager", "transport/*", and "hook".  Unclassified children are classified
+with "?".
+
+`"child_exit"`::
+	This event is generated after the current process has returned
+	from the `waitpid()` and collected the exit information from the
+	child.
++
+------------
+{
+	"event":"child_exit",
+	...
+	"child_id":2,
+	"pid":14708,	 # child PID
+	"code":0,	 # child exit-code
+	"t_rel":0.110605 # observed run-time of child process
+}
+------------
++
+Note that the session-id of the child process is not available to
+the current/spawning process, so the child's PID is reported here as
+a hint for post-processing.  (But it is only a hint because the child
+process may be a shell script which doesn't have a session-id.)
++
+Note that the `t_rel` field contains the observed run time in seconds
+for the child process (starting before the fork/exec/spawn and
+stopping after the `waitpid()` and includes OS process creation overhead).
+So this time will be slightly larger than the atexit time reported by
+the child process itself.
+
+`"child_ready"`::
+	This event is generated after the current process has started
+	a background process and released all handles to it.
++
+------------
+{
+	"event":"child_ready",
+	...
+	"child_id":2,
+	"pid":14708,	 # child PID
+	"ready":"ready", # child ready state
+	"t_rel":0.110605 # observed run-time of child process
+}
+------------
++
+Note that the session-id of the child process is not available to
+the current/spawning process, so the child's PID is reported here as
+a hint for post-processing.  (But it is only a hint because the child
+process may be a shell script which doesn't have a session-id.)
++
+This event is generated after the child is started in the background
+and given a little time to boot up and start working.  If the child
+starts up normally while the parent is still waiting, the "ready"
+field will have the value "ready".
+If the child is too slow to start and the parent times out, the field
+will have the value "timeout".
+If the child starts but the parent is unable to probe it, the field
+will have the value "error".
++
+After the parent process emits this event, it will release all of its
+handles to the child process and treat the child as a background
+daemon.  So even if the child does eventually finish booting up,
+the parent will not emit an updated event.
++
+Note that the `t_rel` field contains the observed run time in seconds
+when the parent released the child process into the background.
+The child is assumed to be a long-running daemon process and may
+outlive the parent process.  So the parent's child event times should
+not be compared to the child's atexit times.
+
+`"exec"`::
+	This event is generated before git attempts to `exec()`
+	another command rather than starting a child process.
++
+------------
+{
+	"event":"exec",
+	...
+	"exec_id":0,
+	"exe":"git",
+	"argv":["foo", "bar"]
+}
+------------
++
+The "exec_id" field is a command-unique id and is only useful if the
+`exec()` fails and a corresponding exec_result event is generated.
+
+`"exec_result"`::
+	This event is generated if the `exec()` fails and control
+	returns to the current git command.
++
+------------
+{
+	"event":"exec_result",
+	...
+	"exec_id":0,
+	"code":1      # error code (errno) from exec()
+}
+------------
+
+`"thread_start"`::
+	This event is generated when a thread is started.  It is
+	generated from *within* the new thread's thread-proc (because
+	it needs to access data in the thread's thread-local storage).
++
+------------
+{
+	"event":"thread_start",
+	...
+	"thread":"th02:preload_thread" # thread name
+}
+------------
+
+`"thread_exit"`::
+	This event is generated when a thread exits.  It is generated
+	from *within* the thread's thread-proc.
++
+------------
+{
+	"event":"thread_exit",
+	...
+	"thread":"th02:preload_thread", # thread name
+	"t_rel":0.007328                # thread elapsed time
+}
+------------
+
+`"def_param"`::
+	This event is generated to log a global parameter, such as a config
+	setting, command-line flag, or environment variable.
++
+------------
+{
+	"event":"def_param",
+	...
+	"scope":"global",
+	"param":"core.abbrev",
+	"value":"7"
+}
+------------
+
+`"def_repo"`::
+	This event defines a repo-id and associates it with the root
+	of the worktree.
++
+------------
+{
+	"event":"def_repo",
+	...
+	"repo":1,
+	"worktree":"/Users/jeffhost/work/gfw"
+}
+------------
++
+As stated earlier, the repo-id is currently always 1, so there will
+only be one def_repo event.  Later, if in-proc submodules are
+supported, a def_repo event should be emitted for each submodule
+visited.
+
+`"region_enter"`::
+	This event is generated when entering a region.
++
+------------
+{
+	"event":"region_enter",
+	...
+	"repo":1,                # optional
+	"nesting":1,             # current region stack depth
+	"category":"index",      # optional
+	"label":"do_read_index", # optional
+	"msg":".git/index"       # optional
+}
+------------
++
+The `category` field may be used in a future enhancement to
+do category-based filtering.
++
+`GIT_TRACE2_EVENT_NESTING` or `trace2.eventNesting` can be used to
+filter deeply nested regions and data events.  It defaults to "2".
+
+`"region_leave"`::
+	This event is generated when leaving a region.
++
+------------
+{
+	"event":"region_leave",
+	...
+	"repo":1,                # optional
+	"t_rel":0.002876,        # time spent in region in seconds
+	"nesting":1,             # region stack depth
+	"category":"index",      # optional
+	"label":"do_read_index", # optional
+	"msg":".git/index"       # optional
+}
+------------
+
+`"data"`::
+	This event is generated to log a thread- and region-local
+	key/value pair.
++
+------------
+{
+	"event":"data",
+	...
+	"repo":1,              # optional
+	"t_abs":0.024107,      # absolute elapsed time
+	"t_rel":0.001031,      # elapsed time in region/thread
+	"nesting":2,           # region stack depth
+	"category":"index",
+	"key":"read/cache_nr",
+	"value":"3552"
+}
+------------
++
+The "value" field may be an integer or a string.
+
+`"data-json"`::
+	This event is generated to log a pre-formatted JSON string
+	containing structured data.
++
+------------
+{
+	"event":"data_json",
+	...
+	"repo":1,              # optional
+	"t_abs":0.015905,
+	"t_rel":0.015905,
+	"nesting":1,
+	"category":"process",
+	"key":"windows/ancestry",
+	"value":["bash.exe","bash.exe"]
+}
+------------
+
+`"th_timer"`::
+	This event logs the amount of time that a stopwatch timer was
+	running in the thread.  This event is generated when a thread
+	exits for timers that requested per-thread events.
++
+------------
+{
+	"event":"th_timer",
+	...
+	"category":"my_category",
+	"name":"my_timer",
+	"intervals":5,         # number of time it was started/stopped
+	"t_total":0.052741,    # total time in seconds it was running
+	"t_min":0.010061,      # shortest interval
+	"t_max":0.011648       # longest interval
+}
+------------
+
+`"timer"`::
+	This event logs the amount of time that a stopwatch timer was
+	running aggregated across all threads.  This event is generated
+	when the process exits.
++
+------------
+{
+	"event":"timer",
+	...
+	"category":"my_category",
+	"name":"my_timer",
+	"intervals":5,         # number of time it was started/stopped
+	"t_total":0.052741,    # total time in seconds it was running
+	"t_min":0.010061,      # shortest interval
+	"t_max":0.011648       # longest interval
+}
+------------
+
+`"th_counter"`::
+	This event logs the value of a counter variable in a thread.
+	This event is generated when a thread exits for counters that
+	requested per-thread events.
++
+------------
+{
+	"event":"th_counter",
+	...
+	"category":"my_category",
+	"name":"my_counter",
+	"count":23
+}
+------------
+
+`"counter"`::
+	This event logs the value of a counter variable across all threads.
+	This event is generated when the process exits.  The total value
+	reported here is the sum across all threads.
++
+------------
+{
+	"event":"counter",
+	...
+	"category":"my_category",
+	"name":"my_counter",
+	"count":23
+}
+------------
+
+`"printf"`::
+	This event logs a human-readable message with no particular formatting
+	guidelines.
++
+------------
+{
+	"event":"printf",
+	...
+	"t_abs":0.015905,      # elapsed time in seconds
+	"msg":"Hello world"    # optional
+}
+------------
+
+
+== Example Trace2 API Usage
+
+Here is a hypothetical usage of the Trace2 API showing the intended
+usage (without worrying about the actual Git details).
+
+Initialization::
+
+	Initialization happens in `main()`.  Behind the scenes, an
+	`atexit` and `signal` handler are registered.
++
+----------------
+int main(int argc, const char **argv)
+{
+	int exit_code;
+
+	trace2_initialize();
+	trace2_cmd_start(argv);
+
+	exit_code = cmd_main(argc, argv);
+
+	trace2_cmd_exit(exit_code);
+
+	return exit_code;
+}
+----------------
+
+Command Details::
+
+	After the basics are established, additional command
+	information can be sent to Trace2 as it is discovered.
++
+----------------
+int cmd_checkout(int argc, const char **argv)
+{
+	trace2_cmd_name("checkout");
+	trace2_cmd_mode("branch");
+	trace2_def_repo(the_repository);
+
+	// emit "def_param" messages for "interesting" config settings.
+	trace2_cmd_list_config();
+
+	if (do_something())
+	    trace2_cmd_error("Path '%s': cannot do something", path);
+
+	return 0;
+}
+----------------
+
+Child Processes::
+
+	Wrap code spawning child processes.
++
+----------------
+void run_child(...)
+{
+	int child_exit_code;
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	...
+	cmd.trace2_child_class = "editor";
+
+	trace2_child_start(&cmd);
+	child_exit_code = spawn_child_and_wait_for_it();
+	trace2_child_exit(&cmd, child_exit_code);
+}
+----------------
++
+For example, the following fetch command spawned ssh, index-pack,
+rev-list, and gc.  This example also shows that fetch took
+5.199 seconds and of that 4.932 was in ssh.
++
+----------------
+$ export GIT_TRACE2_BRIEF=1
+$ export GIT_TRACE2=~/log.normal
+$ git fetch origin
+...
+----------------
++
+----------------
+$ cat ~/log.normal
+version 2.20.1.vfs.1.1.47.g534dbe1ad1
+start git fetch origin
+worktree /Users/jeffhost/work/gfw
+cmd_name fetch (fetch)
+child_start[0] ssh git@xxxxxxxxxx ...
+child_start[1] git index-pack ...
+... (Trace2 events from child processes omitted)
+child_exit[1] pid:14707 code:0 elapsed:0.076353
+child_exit[0] pid:14706 code:0 elapsed:4.931869
+child_start[2] git rev-list ...
+... (Trace2 events from child process omitted)
+child_exit[2] pid:14708 code:0 elapsed:0.110605
+child_start[3] git gc --auto
+... (Trace2 events from child process omitted)
+child_exit[3] pid:14709 code:0 elapsed:0.006240
+exit elapsed:5.198503 code:0
+atexit elapsed:5.198541 code:0
+----------------
++
+When a git process is a (direct or indirect) child of another
+git process, it inherits Trace2 context information.  This
+allows the child to print the command hierarchy.  This example
+shows gc as child[3] of fetch.  When the gc process reports
+its name as "gc", it also reports the hierarchy as "fetch/gc".
+(In this example, trace2 messages from the child process is
+indented for clarity.)
++
+----------------
+$ export GIT_TRACE2_BRIEF=1
+$ export GIT_TRACE2=~/log.normal
+$ git fetch origin
+...
+----------------
++
+----------------
+$ cat ~/log.normal
+version 2.20.1.160.g5676107ecd.dirty
+start git fetch official
+worktree /Users/jeffhost/work/gfw
+cmd_name fetch (fetch)
+...
+child_start[3] git gc --auto
+    version 2.20.1.160.g5676107ecd.dirty
+    start /Users/jeffhost/work/gfw/git gc --auto
+    worktree /Users/jeffhost/work/gfw
+    cmd_name gc (fetch/gc)
+    exit elapsed:0.001959 code:0
+    atexit elapsed:0.001997 code:0
+child_exit[3] pid:20303 code:0 elapsed:0.007564
+exit elapsed:3.868938 code:0
+atexit elapsed:3.868970 code:0
+----------------
+
+Regions::
+
+	Regions can be used to time an interesting section of code.
++
+----------------
+void wt_status_collect(struct wt_status *s)
+{
+	trace2_region_enter("status", "worktrees", s->repo);
+	wt_status_collect_changes_worktree(s);
+	trace2_region_leave("status", "worktrees", s->repo);
+
+	trace2_region_enter("status", "index", s->repo);
+	wt_status_collect_changes_index(s);
+	trace2_region_leave("status", "index", s->repo);
+
+	trace2_region_enter("status", "untracked", s->repo);
+	wt_status_collect_untracked(s);
+	trace2_region_leave("status", "untracked", s->repo);
+}
+
+void wt_status_print(struct wt_status *s)
+{
+	trace2_region_enter("status", "print", s->repo);
+	switch (s->status_format) {
+	    ...
+	}
+	trace2_region_leave("status", "print", s->repo);
+}
+----------------
++
+In this example, scanning for untracked files ran from +0.012568 to
++0.027149 (since the process started) and took 0.014581 seconds.
++
+----------------
+$ export GIT_TRACE2_PERF_BRIEF=1
+$ export GIT_TRACE2_PERF=~/log.perf
+$ git status
+...
+
+$ cat ~/log.perf
+d0 | main                     | version      |     |           |           |            | 2.20.1.160.g5676107ecd.dirty
+d0 | main                     | start        |     |  0.001173 |           |            | git status
+d0 | main                     | def_repo     | r1  |           |           |            | worktree:/Users/jeffhost/work/gfw
+d0 | main                     | cmd_name     |     |           |           |            | status (status)
+...
+d0 | main                     | region_enter | r1  |  0.010988 |           | status     | label:worktrees
+d0 | main                     | region_leave | r1  |  0.011236 |  0.000248 | status     | label:worktrees
+d0 | main                     | region_enter | r1  |  0.011260 |           | status     | label:index
+d0 | main                     | region_leave | r1  |  0.012542 |  0.001282 | status     | label:index
+d0 | main                     | region_enter | r1  |  0.012568 |           | status     | label:untracked
+d0 | main                     | region_leave | r1  |  0.027149 |  0.014581 | status     | label:untracked
+d0 | main                     | region_enter | r1  |  0.027411 |           | status     | label:print
+d0 | main                     | region_leave | r1  |  0.028741 |  0.001330 | status     | label:print
+d0 | main                     | exit         |     |  0.028778 |           |            | code:0
+d0 | main                     | atexit       |     |  0.028809 |           |            | code:0
+----------------
++
+Regions may be nested.  This causes messages to be indented in the
+PERF target, for example.
+Elapsed times are relative to the start of the corresponding nesting
+level as expected.  For example, if we add region message to:
++
+----------------
+static enum path_treatment read_directory_recursive(struct dir_struct *dir,
+	struct index_state *istate, const char *base, int baselen,
+	struct untracked_cache_dir *untracked, int check_only,
+	int stop_at_first_file, const struct pathspec *pathspec)
+{
+	enum path_treatment state, subdir_state, dir_state = path_none;
+
+	trace2_region_enter_printf("dir", "read_recursive", NULL, "%.*s", baselen, base);
+	...
+	trace2_region_leave_printf("dir", "read_recursive", NULL, "%.*s", baselen, base);
+	return dir_state;
+}
+----------------
++
+We can further investigate the time spent scanning for untracked files.
++
+----------------
+$ export GIT_TRACE2_PERF_BRIEF=1
+$ export GIT_TRACE2_PERF=~/log.perf
+$ git status
+...
+$ cat ~/log.perf
+d0 | main                     | version      |     |           |           |            | 2.20.1.162.gb4ccea44db.dirty
+d0 | main                     | start        |     |  0.001173 |           |            | git status
+d0 | main                     | def_repo     | r1  |           |           |            | worktree:/Users/jeffhost/work/gfw
+d0 | main                     | cmd_name     |     |           |           |            | status (status)
+...
+d0 | main                     | region_enter | r1  |  0.015047 |           | status     | label:untracked
+d0 | main                     | region_enter |     |  0.015132 |           | dir        | ..label:read_recursive
+d0 | main                     | region_enter |     |  0.016341 |           | dir        | ....label:read_recursive vcs-svn/
+d0 | main                     | region_leave |     |  0.016422 |  0.000081 | dir        | ....label:read_recursive vcs-svn/
+d0 | main                     | region_enter |     |  0.016446 |           | dir        | ....label:read_recursive xdiff/
+d0 | main                     | region_leave |     |  0.016522 |  0.000076 | dir        | ....label:read_recursive xdiff/
+d0 | main                     | region_enter |     |  0.016612 |           | dir        | ....label:read_recursive git-gui/
+d0 | main                     | region_enter |     |  0.016698 |           | dir        | ......label:read_recursive git-gui/po/
+d0 | main                     | region_enter |     |  0.016810 |           | dir        | ........label:read_recursive git-gui/po/glossary/
+d0 | main                     | region_leave |     |  0.016863 |  0.000053 | dir        | ........label:read_recursive git-gui/po/glossary/
+...
+d0 | main                     | region_enter |     |  0.031876 |           | dir        | ....label:read_recursive builtin/
+d0 | main                     | region_leave |     |  0.032270 |  0.000394 | dir        | ....label:read_recursive builtin/
+d0 | main                     | region_leave |     |  0.032414 |  0.017282 | dir        | ..label:read_recursive
+d0 | main                     | region_leave | r1  |  0.032454 |  0.017407 | status     | label:untracked
+...
+d0 | main                     | exit         |     |  0.034279 |           |            | code:0
+d0 | main                     | atexit       |     |  0.034322 |           |            | code:0
+----------------
++
+Trace2 regions are similar to the existing trace_performance_enter()
+and trace_performance_leave() routines, but are thread safe and
+maintain per-thread stacks of timers.
+
+Data Messages::
+
+	Data messages added to a region.
++
+----------------
+int read_index_from(struct index_state *istate, const char *path,
+	const char *gitdir)
+{
+	trace2_region_enter_printf("index", "do_read_index", the_repository, "%s", path);
+
+	...
+
+	trace2_data_intmax("index", the_repository, "read/version", istate->version);
+	trace2_data_intmax("index", the_repository, "read/cache_nr", istate->cache_nr);
+
+	trace2_region_leave_printf("index", "do_read_index", the_repository, "%s", path);
+}
+----------------
++
+This example shows that the index contained 3552 entries.
++
+----------------
+$ export GIT_TRACE2_PERF_BRIEF=1
+$ export GIT_TRACE2_PERF=~/log.perf
+$ git status
+...
+$ cat ~/log.perf
+d0 | main                     | version      |     |           |           |            | 2.20.1.156.gf9916ae094.dirty
+d0 | main                     | start        |     |  0.001173 |           |            | git status
+d0 | main                     | def_repo     | r1  |           |           |            | worktree:/Users/jeffhost/work/gfw
+d0 | main                     | cmd_name     |     |           |           |            | status (status)
+d0 | main                     | region_enter | r1  |  0.001791 |           | index      | label:do_read_index .git/index
+d0 | main                     | data         | r1  |  0.002494 |  0.000703 | index      | ..read/version:2
+d0 | main                     | data         | r1  |  0.002520 |  0.000729 | index      | ..read/cache_nr:3552
+d0 | main                     | region_leave | r1  |  0.002539 |  0.000748 | index      | label:do_read_index .git/index
+...
+----------------
+
+Thread Events::
+
+	Thread messages added to a thread-proc.
++
+For example, the multi-threaded preload-index code can be
+instrumented with a region around the thread pool and then
+per-thread start and exit events within the thread-proc.
++
+----------------
+static void *preload_thread(void *_data)
+{
+	// start the per-thread clock and emit a message.
+	trace2_thread_start("preload_thread");
+
+	// report which chunk of the array this thread was assigned.
+	trace2_data_intmax("index", the_repository, "offset", p->offset);
+	trace2_data_intmax("index", the_repository, "count", nr);
+
+	do {
+	    ...
+	} while (--nr > 0);
+	...
+
+	// report elapsed time taken by this thread.
+	trace2_thread_exit();
+	return NULL;
+}
+
+void preload_index(struct index_state *index,
+	const struct pathspec *pathspec,
+	unsigned int refresh_flags)
+{
+	trace2_region_enter("index", "preload", the_repository);
+
+	for (i = 0; i < threads; i++) {
+	    ... /* create thread */
+	}
+
+	for (i = 0; i < threads; i++) {
+	    ... /* join thread */
+	}
+
+	trace2_region_leave("index", "preload", the_repository);
+}
+----------------
++
+In this example preload_index() was executed by the `main` thread
+and started the `preload` region.  Seven threads, named
+`th01:preload_thread` through `th07:preload_thread`, were started.
+Events from each thread are atomically appended to the shared target
+stream as they occur so they may appear in random order with respect
+other threads. Finally, the main thread waits for the threads to
+finish and leaves the region.
++
+Data events are tagged with the active thread name.  They are used
+to report the per-thread parameters.
++
+----------------
+$ export GIT_TRACE2_PERF_BRIEF=1
+$ export GIT_TRACE2_PERF=~/log.perf
+$ git status
+...
+$ cat ~/log.perf
+...
+d0 | main                     | region_enter | r1  |  0.002595 |           | index      | label:preload
+d0 | th01:preload_thread      | thread_start |     |  0.002699 |           |            |
+d0 | th02:preload_thread      | thread_start |     |  0.002721 |           |            |
+d0 | th01:preload_thread      | data         | r1  |  0.002736 |  0.000037 | index      | offset:0
+d0 | th02:preload_thread      | data         | r1  |  0.002751 |  0.000030 | index      | offset:2032
+d0 | th03:preload_thread      | thread_start |     |  0.002711 |           |            |
+d0 | th06:preload_thread      | thread_start |     |  0.002739 |           |            |
+d0 | th01:preload_thread      | data         | r1  |  0.002766 |  0.000067 | index      | count:508
+d0 | th06:preload_thread      | data         | r1  |  0.002856 |  0.000117 | index      | offset:2540
+d0 | th03:preload_thread      | data         | r1  |  0.002824 |  0.000113 | index      | offset:1016
+d0 | th04:preload_thread      | thread_start |     |  0.002710 |           |            |
+d0 | th02:preload_thread      | data         | r1  |  0.002779 |  0.000058 | index      | count:508
+d0 | th06:preload_thread      | data         | r1  |  0.002966 |  0.000227 | index      | count:508
+d0 | th07:preload_thread      | thread_start |     |  0.002741 |           |            |
+d0 | th07:preload_thread      | data         | r1  |  0.003017 |  0.000276 | index      | offset:3048
+d0 | th05:preload_thread      | thread_start |     |  0.002712 |           |            |
+d0 | th05:preload_thread      | data         | r1  |  0.003067 |  0.000355 | index      | offset:1524
+d0 | th05:preload_thread      | data         | r1  |  0.003090 |  0.000378 | index      | count:508
+d0 | th07:preload_thread      | data         | r1  |  0.003037 |  0.000296 | index      | count:504
+d0 | th03:preload_thread      | data         | r1  |  0.002971 |  0.000260 | index      | count:508
+d0 | th04:preload_thread      | data         | r1  |  0.002983 |  0.000273 | index      | offset:508
+d0 | th04:preload_thread      | data         | r1  |  0.007311 |  0.004601 | index      | count:508
+d0 | th05:preload_thread      | thread_exit  |     |  0.008781 |  0.006069 |            |
+d0 | th01:preload_thread      | thread_exit  |     |  0.009561 |  0.006862 |            |
+d0 | th03:preload_thread      | thread_exit  |     |  0.009742 |  0.007031 |            |
+d0 | th06:preload_thread      | thread_exit  |     |  0.009820 |  0.007081 |            |
+d0 | th02:preload_thread      | thread_exit  |     |  0.010274 |  0.007553 |            |
+d0 | th07:preload_thread      | thread_exit  |     |  0.010477 |  0.007736 |            |
+d0 | th04:preload_thread      | thread_exit  |     |  0.011657 |  0.008947 |            |
+d0 | main                     | region_leave | r1  |  0.011717 |  0.009122 | index      | label:preload
+...
+d0 | main                     | exit         |     |  0.029996 |           |            | code:0
+d0 | main                     | atexit       |     |  0.030027 |           |            | code:0
+----------------
++
+In this example, the preload region took 0.009122 seconds.  The 7 threads
+took between 0.006069 and 0.008947 seconds to work on their portion of
+the index.  Thread "th01" worked on 508 items at offset 0.  Thread "th02"
+worked on 508 items at offset 2032.  Thread "th04" worked on 508 items
+at offset 508.
++
+This example also shows that thread names are assigned in a racy manner
+as each thread starts.
+
+Config (def param) Events::
+
+	  Dump "interesting" config values to trace2 log.
++
+We can optionally emit configuration events, see
+`trace2.configparams` in linkgit:git-config[1] for how to enable
+it.
++
+----------------
+$ git config --system color.ui never
+$ git config --global color.ui always
+$ git config --local color.ui auto
+$ git config --list --show-scope | grep 'color.ui'
+system  color.ui=never
+global  color.ui=always
+local   color.ui=auto
+----------------
++
+Then, mark the config `color.ui` as "interesting" config with
+`GIT_TRACE2_CONFIG_PARAMS`:
++
+----------------
+$ export GIT_TRACE2_PERF_BRIEF=1
+$ export GIT_TRACE2_PERF=~/log.perf
+$ export GIT_TRACE2_CONFIG_PARAMS=color.ui
+$ git version
+...
+$ cat ~/log.perf
+d0 | main                     | version      |     |           |           |              | ...
+d0 | main                     | start        |     |  0.001642 |           |              | /usr/local/bin/git version
+d0 | main                     | cmd_name     |     |           |           |              | version (version)
+d0 | main                     | def_param    |     |           |           | scope:system | color.ui:never
+d0 | main                     | def_param    |     |           |           | scope:global | color.ui:always
+d0 | main                     | def_param    |     |           |           | scope:local  | color.ui:auto
+d0 | main                     | data         | r0  |  0.002100 |  0.002100 | fsync        | fsync/writeout-only:0
+d0 | main                     | data         | r0  |  0.002126 |  0.002126 | fsync        | fsync/hardware-flush:0
+d0 | main                     | exit         |     |  0.000470 |           |              | code:0
+d0 | main                     | atexit       |     |  0.000477 |           |              | code:0
+----------------
+
+Stopwatch Timer Events::
+
+	Measure the time spent in a function call or span of code
+	that might be called from many places within the code
+	throughout the life of the process.
++
+----------------
+static void expensive_function(void)
+{
+	trace2_timer_start(TRACE2_TIMER_ID_TEST1);
+	...
+	sleep_millisec(1000); // Do something expensive
+	...
+	trace2_timer_stop(TRACE2_TIMER_ID_TEST1);
+}
+
+static int ut_100timer(int argc, const char **argv)
+{
+	...
+
+	expensive_function();
+
+	// Do something else 1...
+
+	expensive_function();
+
+	// Do something else 2...
+
+	expensive_function();
+
+	return 0;
+}
+----------------
++
+In this example, we measure the total time spent in
+`expensive_function()` regardless of when it is called
+in the overall flow of the program.
++
+----------------
+$ export GIT_TRACE2_PERF_BRIEF=1
+$ export GIT_TRACE2_PERF=~/log.perf
+$ t/helper/test-tool trace2 100timer 3 1000
+...
+$ cat ~/log.perf
+d0 | main                     | version      |     |           |           |              | ...
+d0 | main                     | start        |     |  0.001453 |           |              | t/helper/test-tool trace2 100timer 3 1000
+d0 | main                     | cmd_name     |     |           |           |              | trace2 (trace2)
+d0 | main                     | exit         |     |  3.003667 |           |              | code:0
+d0 | main                     | timer        |     |           |           | test         | name:test1 intervals:3 total:3.001686 min:1.000254 max:1.000929
+d0 | main                     | atexit       |     |  3.003796 |           |              | code:0
+----------------
+
+
+== Future Work
+
+=== Relationship to the Existing Trace Api (api-trace.txt)
+
+There are a few issues to resolve before we can completely
+switch to Trace2.
+
+* Updating existing tests that assume `GIT_TRACE` format messages.
+
+* How to best handle custom `GIT_TRACE_<key>` messages?
+
+** The `GIT_TRACE_<key>` mechanism allows each <key> to write to a
+different file (in addition to just stderr).
+
+** Do we want to maintain that ability or simply write to the existing
+Trace2 targets (and convert <key> to a "category").
diff --git a/Documentation/technical/bitmap-format.adoc b/Documentation/technical/bitmap-format.adoc
new file mode 100644
index 0000000000..bfb0ec7beb
--- /dev/null
+++ b/Documentation/technical/bitmap-format.adoc
@@ -0,0 +1,398 @@
+GIT bitmap v1 format
+====================
+
+== Pack and multi-pack bitmaps
+
+Bitmaps store reachability information about the set of objects in a packfile,
+or a multi-pack index (MIDX). The former is defined obviously, and the latter is
+defined as the union of objects in packs contained in the MIDX.
+
+A bitmap may belong to either one pack, or the repository's multi-pack index (if
+it exists). A repository may have at most one bitmap.
+
+An object is uniquely described by its bit position within a bitmap:
+
+	- If the bitmap belongs to a packfile, the __n__th bit corresponds to
+	the __n__th object in pack order. For a function `offset` which maps
+	objects to their byte offset within a pack, pack order is defined as
+	follows:
+
+		o1 <= o2 <==> offset(o1) <= offset(o2)
+
+	- If the bitmap belongs to a MIDX, the __n__th bit corresponds to the
+	__n__th object in MIDX order. With an additional function `pack` which
+	maps objects to the pack they were selected from by the MIDX, MIDX order
+	is defined as follows:
+
+		o1 <= o2 <==> pack(o1) <= pack(o2) /\ offset(o1) <= offset(o2)
++
+The ordering between packs is done according to the MIDX's .rev file.
+Notably, the preferred pack sorts ahead of all other packs.
+
+The on-disk representation (described below) of a bitmap is the same regardless
+of whether or not that bitmap belongs to a packfile or a MIDX. The only
+difference is the interpretation of the bits, which is described above.
+
+Certain bitmap extensions are supported (see: Appendix B). No extensions are
+required for bitmaps corresponding to packfiles. For bitmaps that correspond to
+MIDXs, both the bit-cache and rev-cache extensions are required.
+
+== On-disk format
+
+    * A header appears at the beginning:
+
+	4-byte signature: :: {'B', 'I', 'T', 'M'}
+
+	2-byte version number (network byte order): ::
+
+	    The current implementation only supports version 1
+	    of the bitmap index (the same one as JGit).
+
+	2-byte flags (network byte order): ::
+
+	    The following flags are supported:
+
+	    ** {empty}
+	    BITMAP_OPT_FULL_DAG (0x1) REQUIRED: :::
+
+	    This flag must always be present. It implies that the
+	    bitmap index has been generated for a packfile or
+	    multi-pack index (MIDX) with full closure (i.e. where
+	    every single object in the packfile/MIDX can find its
+	    parent links inside the same packfile/MIDX). This is a
+	    requirement for the bitmap index format, also present in
+	    JGit, that greatly reduces the complexity of the
+	    implementation.
+
+	    ** {empty}
+	    BITMAP_OPT_HASH_CACHE (0x4): :::
+
+	    If present, the end of the bitmap file contains
+	    `N` 32-bit name-hash values, one per object in the
+	    pack/MIDX. The format and meaning of the name-hash is
+	    described below.
+
+		** {empty}
+		BITMAP_OPT_LOOKUP_TABLE (0x10): :::
+		If present, the end of the bitmap file contains a table
+		containing a list of `N` <commit_pos, offset, xor_row>
+		triplets. The format and meaning of the table is described
+		below.
++
+NOTE: Unlike the xor_offset used to compress an individual bitmap,
+`xor_row` stores an *absolute* index into the lookup table, not a location
+relative to the current entry.
+
+	4-byte entry count (network byte order): ::
+	    The total count of entries (bitmapped commits) in this bitmap index.
+
+	20-byte checksum: ::
+	    The SHA1 checksum of the pack/MIDX this bitmap index
+	    belongs to.
+
+    * 4 EWAH bitmaps that act as type indexes
++
+Type indexes are serialized after the hash cache in the shape
+of four EWAH bitmaps stored consecutively (see Appendix A for
+the serialization format of an EWAH bitmap).
++
+There is a bitmap for each Git object type, stored in the following
+order:
++
+    - Commits
+    - Trees
+    - Blobs
+    - Tags
+
++
+In each bitmap, the `n`th bit is set to true if the `n`th object
+in the packfile or multi-pack index is of that type.
++
+The obvious consequence is that the OR of all 4 bitmaps will result
+in a full set (all bits set), and the AND of all 4 bitmaps will
+result in an empty bitmap (no bits set).
+
+    * N entries with compressed bitmaps, one for each indexed commit
++
+Where `N` is the total number of entries in this bitmap index.
+Each entry contains the following:
+
+	** {empty}
+	4-byte object position (network byte order): ::
+	    The position **in the index for the packfile or
+	    multi-pack index** where the bitmap for this commit is
+	    found.
+
+	** {empty}
+	1-byte XOR-offset: ::
+	    The xor offset used to compress this bitmap. For an entry
+	    in position `x`, an XOR offset of `y` means that the actual
+	    bitmap representing this commit is composed by XORing the
+	    bitmap for this entry with the bitmap in entry `x-y` (i.e.
+	    the bitmap `y` entries before this one).
++
+NOTE: This compression can be recursive. In order to
+XOR this entry with a previous one, the previous entry needs
+to be decompressed first, and so on.
++
+The hard-limit for this offset is 160 (an entry can only be
+xor'ed against one of the 160 entries preceding it). This
+number is always positive, and hence entries are always xor'ed
+with **previous** bitmaps, not bitmaps that will come afterwards
+in the index.
+
+	** {empty}
+	1-byte flags for this bitmap: ::
+	    At the moment the only available flag is `0x1`, which hints
+	    that this bitmap can be re-used when rebuilding bitmap indexes
+	    for the repository.
+
+	** The compressed bitmap itself, see Appendix A.
+
+	* {empty}
+	TRAILER: ::
+		Trailing checksum of the preceding contents.
+
+== Appendix A: Serialization format for an EWAH bitmap
+
+Ewah bitmaps are serialized in the same protocol as the JAVAEWAH
+library, making them backwards compatible with the JGit
+implementation:
+
+	- 4-byte number of bits of the resulting UNCOMPRESSED bitmap
+
+	- 4-byte number of words of the COMPRESSED bitmap, when stored
+
+	- N x 8-byte words, as specified by the previous field
++
+This is the actual content of the compressed bitmap.
+
+	- 4-byte position of the current RLW for the compressed
+		bitmap
+
+All words are stored in network byte order for their corresponding
+sizes.
+
+The compressed bitmap is stored in a form of run-length encoding, as
+follows.  It consists of a concatenation of an arbitrary number of
+chunks.  Each chunk consists of one or more 64-bit words
+
+     H  L_1  L_2  L_3 .... L_M
+
+H is called RLW (run length word).  It consists of (from lower to higher
+order bits):
+
+     - 1 bit: the repeated bit B
+
+     - 32 bits: repetition count K (unsigned)
+
+     - 31 bits: literal word count M (unsigned)
+
+The bitstream represented by the above chunk is then:
+
+     - K repetitions of B
+
+     - The bits stored in `L_1` through `L_M`.  Within a word, bits at
+       lower order come earlier in the stream than those at higher
+       order.
+
+The next word after `L_M` (if any) must again be a RLW, for the next
+chunk.  For efficient appending to the bitstream, the EWAH stores a
+pointer to the last RLW in the stream.
+
+
+== Appendix B: Optional Bitmap Sections
+
+These sections may or may not be present in the `.bitmap` file; their
+presence is indicated by the header flags section described above.
+
+Name-hash cache
+---------------
+
+If the BITMAP_OPT_HASH_CACHE flag is set, the end of the bitmap contains
+a cache of 32-bit values, one per object in the pack/MIDX. The value at
+position `i` is the hash of the pathname at which the `i`th object
+(counting in index or multi-pack index order) in the pack/MIDX can be found.
+This can be fed into the delta heuristics to compare objects with similar
+pathnames.
+
+The hash algorithm used is:
+
+    hash = 0;
+    while ((c = *name++))
+	    if (!isspace(c))
+		    hash = (hash >> 2) + (c << 24);
+
+Note that this hashing scheme is tied to the BITMAP_OPT_HASH_CACHE flag.
+If implementations want to choose a different hashing scheme, they are
+free to do so, but MUST allocate a new header flag (because comparing
+hashes made under two different schemes would be pointless).
+
+Commit lookup table
+-------------------
+
+If the BITMAP_OPT_LOOKUP_TABLE flag is set, the last `N * (4 + 8 + 4)`
+bytes (preceding the name-hash cache and trailing hash) of the `.bitmap`
+file contains a lookup table specifying the information needed to get
+the desired bitmap from the entries without parsing previous unnecessary
+bitmaps.
+
+For a `.bitmap` containing `nr_entries` reachability bitmaps, the table
+contains a list of `nr_entries` <commit_pos, offset, xor_row> triplets
+(sorted in the ascending order of `commit_pos`). The content of the i'th
+triplet is -
+
+	* {empty}
+	commit_pos (4 byte integer, network byte order): ::
+	It stores the object position of a commit (in the midx or pack
+	index).
+
+	* {empty}
+	offset (8 byte integer, network byte order): ::
+	The offset from which that commit's bitmap can be read.
+
+	* {empty}
+	xor_row (4 byte integer, network byte order): ::
+	The position of the triplet whose bitmap is used to compress
+	this one, or `0xffffffff` if no such bitmap exists.
+
+Pseudo-merge bitmaps
+--------------------
+
+If the `BITMAP_OPT_PSEUDO_MERGES` flag is set, a variable number of
+bytes (preceding the name-hash cache, commit lookup table, and trailing
+checksum) of the `.bitmap` file is used to store pseudo-merge bitmaps.
+
+For more information on what pseudo-merges are, why they are useful, and
+how to configure them, see the information in linkgit:gitpacking[7].
+
+=== File format
+
+If enabled, pseudo-merge bitmaps are stored in an optional section at
+the end of a `.bitmap` file. The format is as follows:
+
+....
++-------------------------------------------+
+|               .bitmap File                |
++-------------------------------------------+
+|                                           |
+|  Pseudo-merge bitmaps (Variable Length)   |
+|  +---------------------------+            |
+|  | commits_bitmap (EWAH)     |            |
+|  +---------------------------+            |
+|  | merge_bitmap (EWAH)       |            |
+|  +---------------------------+            |
+|                                           |
++-------------------------------------------+
+|                                           |
+|  Lookup Table                             |
+|  +---------------------------+            |
+|  | commit_pos (4 bytes)      |            |
+|  +---------------------------+            |
+|  | offset (8 bytes)          |            |
+|  +------------+--------------+            |
+|                                           |
+|  Offset Cases:                            |
+|  -------------                            |
+|                                           |
+|  1. MSB Unset: single pseudo-merge bitmap |
+|     + offset to pseudo-merge bitmap       |
+|                                           |
+|  2. MSB Set: multiple pseudo-merges       |
+|     + offset to extended lookup table     |
+|                                           |
++-------------------------------------------+
+|                                           |
+|  Extended Lookup Table (Optional)         |
+|  +----+----------+----------+----------+  |
+|  | N  | Offset 1 |   ....   | Offset N |  |
+|  +----+----------+----------+----------+  |
+|  |    |  8 bytes |   ....   |  8 bytes |  |
+|  +----+----------+----------+----------+  |
+|                                           |
++-------------------------------------------+
+|                                           |
+|  Pseudo-merge position table              |
+|  +----+----------+----------+----------+  |
+|  | N  | Offset 1 |   ....   | Offset N |  |
+|  +----+----------+----------+----------+  |
+|  |    |  8 bytes |   ....   |  8 bytes |  |
+|  +----+----------+----------+----------+  |
+|                                           |
++-------------------------------------------+
+|                                           |
+|  Pseudo-merge Metadata                    |
+|  +-----------------------------------+    |
+|  | # pseudo-merges (4 bytes)         |    |
+|  +-----------------------------------+    |
+|  | # commits (4 bytes)               |    |
+|  +-----------------------------------+    |
+|  | Lookup offset (8 bytes)           |    |
+|  +-----------------------------------+    |
+|  | Extension size (8 bytes)          |    |
+|  +-----------------------------------+    |
+|                                           |
++-------------------------------------------+
+....
+
+* One or more pseudo-merge bitmaps, each containing:
+
+  ** `commits_bitmap`, an EWAH-compressed bitmap describing the set of
+     commits included in the this psuedo-merge.
+
+  ** `merge_bitmap`, an EWAH-compressed bitmap describing the union of
+     the set of objects reachable from all commits listed in the
+     `commits_bitmap`.
+
+* A lookup table, mapping pseudo-merged commits to the pseudo-merges
+  they belong to. Entries appear in increasing order of each commit's
+  bit position. Each entry is 12 bytes wide, and is comprised of the
+  following:
+
+  ** `commit_pos`, a 4-byte unsigned value (in network byte-order)
+     containing the bit position for this commit.
+
+  ** `offset`, an 8-byte unsigned value (also in network byte-order)
+  containing either one of two possible offsets, depending on whether or
+  not the most-significant bit is set.
+
+    *** If unset (i.e. `offset & ((uint64_t)1<<63) == 0`), the offset
+	(relative to the beginning of the `.bitmap` file) at which the
+	pseudo-merge bitmap for this commit can be read. This indicates
+	only a single pseudo-merge bitmap contains this commit.
+
+    *** If set (i.e. `offset & ((uint64_t)1<<63) != 0`), the offset
+	(again relative to the beginning of the `.bitmap` file) at which
+	the extended offset table can be located describing the set of
+	pseudo-merge bitmaps which contain this commit. This indicates
+	that multiple pseudo-merge bitmaps contain this commit.
+
+* An (optional) extended lookup table (written if and only if there is
+  at least one commit which appears in more than one pseudo-merge).
+  There are as many entries as commits which appear in multiple
+  pseudo-merges. Each entry contains the following:
+
+  ** `N`, a 4-byte unsigned value equal to the number of pseudo-merges
+     which contain a given commit.
+
+  ** An array of `N` 8-byte unsigned values, each of which is
+     interpreted as an offset (relative to the beginning of the
+     `.bitmap` file) at which a pseudo-merge bitmap for this commit can
+     be read. These values occur in no particular order.
+
+* Positions for all pseudo-merges, each stored as an 8-byte unsigned
+  value (in network byte-order) containing the offset (relative to the
+  beginning of the `.bitmap` file) of each consecutive pseudo-merge.
+
+* A 4-byte unsigned value (in network byte-order) equal to the number of
+  pseudo-merges.
+
+* A 4-byte unsigned value (in network byte-order) equal to the number of
+  unique commits which appear in any pseudo-merge.
+
+* An 8-byte unsigned value (in network byte-order) equal to the number
+  of bytes between the start of the pseudo-merge section and the
+  beginning of the lookup table.
+
+* An 8-byte unsigned value (in network byte-order) equal to the number
+  of bytes in the pseudo-merge section (including this field).
diff --git a/Documentation/technical/build-systems.adoc b/Documentation/technical/build-systems.adoc
new file mode 100644
index 0000000000..d9dafb407c
--- /dev/null
+++ b/Documentation/technical/build-systems.adoc
@@ -0,0 +1,224 @@
+= Build Systems
+
+The build system is the primary way for both developers and system integrators
+to interact with the Git project. As such, being easy to use and extend for
+those who are not directly developing Git itself is just as important as other
+requirements we have on any potential build system.
+
+This document outlines the different requirements that we have for the build
+system and then compares available build systems using these criteria.
+
+== Requirements
+
+The following subsections present a list of requirements that we have for any
+potential build system. Sections are sorted by decreasing priority.
+
+=== Platform support
+
+The build system must have support for all of our platforms that we continually
+test against as outlined by our platform support policy. These platforms are:
+
+  - Linux
+  - Windows
+  - macOS
+
+Furthermore, the build system should have support for the following platforms
+that generally have somebody running test pipelines against regularly:
+
+  - AIX
+  - FreeBSD
+  - NetBSD
+  - NonStop
+  - OpenBSD
+
+The platforms which must be supported by the tool should be aligned with our
+[platform support policy](platform-support.txt).
+
+=== Auto-detection of supported features
+
+The build system must support auto-detection of features which are or aren't
+available on the current platform. Platform maintainers should not be required
+to manually configure the complete build.
+
+Auto-detection of the following items is considered to be important:
+
+  - Check for the existence of headers.
+  - Check for the existence of libraries.
+  - Check for the existence of exectuables.
+  - Check for the runtime behavior of specific functions.
+  - Check for specific link order requirements when multiple libraries are
+    involved.
+
+=== Ease of use
+
+The build system should be both easy to use and easy to extend. While this is
+naturally a subjective metric it is likely not controversial to say that some
+build systems are considerably harder to use than others.
+
+=== IDE support
+
+The build system should integrate with well-known IDEs. Well-known IDEs include:
+
+  - Microsoft Visual Studio
+  - Visual Studio Code
+  - Xcode
+
+There are four levels of support:
+
+  - Native integration into the IDE.
+  - Integration into the IDE via a plugin.
+  - Integration into the IDE via generating a project description with the build
+    system.
+  - No integration.
+
+Native integration is preferable, but integration via either a plugin or by
+generating a project description via the build system are considered feasible
+alternatives.
+
+Another important distinction is the level of integration. There are two
+features that one generally wants to have:
+
+  - Integration of build targets.
+  - Automatic setup of features like code completion with detected build
+    dependencies.
+
+The first bullet point is the bare minimum, but is not sufficient to be
+considered proper integration.
+
+=== Out-of-tree builds
+
+The build system should support out-of-tree builds. Out-of-tree builds allow a
+developer to configure multiple different build directories with different
+configuration, e.g. one "debug" build and one "release" build.
+
+=== Cross-platform builds
+
+The build system should support cross-platform builds, e.g. building for arm on
+an x86-64 host.
+
+=== Language support
+
+The following languages and toolchains are of relevance and should be supported
+by the build system:
+
+  - C: the primary compiled language used by Git, must be supported. Relevant
+    toolchains are GCC, Clang and MSVC.
+  - Rust: candidate as a second compiled lanugage, should be supported. Relevant
+    toolchains is the LLVM-based rustc.
+
+Built-in support for the respective languages is preferred over support that
+needs to be wired up manually to avoid unnecessary complexity. Native support
+includes the following features:
+
+  - Compiling objects.
+  - Dependency tracking.
+  - Detection of available features.
+  - Discovery of relevant toolchains.
+  - Linking libraries and executables.
+  - Templating placeholders in scripts.
+
+=== Test integration
+
+It should be possible to integrate tests into the build system such that it is
+possible to build and test Git within the build system. Features which are nice
+to have:
+
+  - Track build-time dependencies for respective tests. Unit tests have
+    different requirements than integration tests.
+  - Allow filtering of which tests to run.
+  - Allow running tests such that utilities like `test_pause` or `debug` work.
+
+== Comparison
+
+The following list of build systems are considered:
+
+- GNU Make
+- autoconf
+- CMake
+- Meson
+
+=== GNU Make
+
+- Platform support: ubitquitous on all platforms, but not well-integrated into Windows.
+- Auto-detection: no built-in support for auto-detection of features.
+- Ease of use: easy to use, but discovering available options is hard. Makefile
+  rules can quickly get out of hand once reaching a certain scope.
+- IDE support: execution of Makefile targets is supported by many IDEs
+- Out-of-tree builds: supported in theory, not wired up in practice.
+- Cross-platform builds: supported in theory, not wired up in practice.
+- Language support:
+  - C: Limited built-in support, many parts need to be wired up manually.
+  - Rust: No built-in support, needs to be wired up manually.
+- Test integration: partially supported, many parts need to be wired up
+  manually.
+
+=== autoconf
+
+- Platform support: ubiquitous on all platforms, but not well-integrated into Windows.
+- Auto-detection: supported.
+- Ease of use: easy to use, discovering available options is comparatively
+  easy. The autoconf syntax is prohibitively hard to extend though due to its
+  complex set of interacting files and the hard-to-understand M4 language.
+- IDE support: no integration into IDEs at generation time. The generated
+  Makefiles have the same level of support as GNU Make.
+- Out-of-tree builds: supported in theory, not wired up in practice.
+- Cross-platform builds: supported.
+- Language support:
+  - C: Limited built-in support, many parts need to be wired up manually.
+  - Rust: No built-in support, needs to be wired up manually.
+- Test integration: partially supported, many parts need to be wired up
+  manually.
+
+=== CMake
+
+- Platform support: not as extensive as GNU Make or autoconf, but all major
+  platforms are supported.
+  - AIX
+  - Cygwin
+  - FreeBSD
+  - Linux
+  - OpenBSD
+  - Solaris
+  - Windows
+  - macOS
+- Ease of use: easy to use, discovering available options is not always
+  trivial. The scripting language used by CMake is somewhat cumbersome to use,
+  but extending CMake build instructions is doable.
+- IDE support: natively integrated into Microsoft Visual Studio. Can generate
+  project descriptions for Xcode. An extension is available for Visual Studio
+  Code. Many other IDEs have plugins for CMake.
+- Out-of-tree builds: supported.
+- Cross-platform builds: supported.
+- Language support:
+  - C: Supported for GCC, Clang, MSVC and other toolchains.
+  - Rust: No built-in support, needs to be wired up manually.
+- Test integration: supported, even though test dependencies are a bit
+  cumbersome to use via "test fixtures". Interactive test runs are not
+  supported.
+
+=== Meson
+
+- Platform: not as extensive as GNU Make or autoconf, but all major platforms
+  and some smaller ones are supported.
+  - AIX
+  - Cygwin
+  - DragonflyBSD
+  - FreeBSD
+  - Haiku
+  - Linux
+  - NetBSD
+  - OpenBSD
+  - Solaris
+  - Windows
+  - macOS
+- Ease of use: easy to use, discovering available options is easy. The
+  scripting language is straight-forward to use.
+- IDE support: Supports generating build instructions for Xcode and Microsoft
+  Visual Studio, a plugin exists for Visual Studio Code.
+- Out-of-tree builds: supported.
+- Cross-platform builds: supported.
+- Language support:
+  - C: Supported for GCC, Clang, MSVC and other toolchains.
+  - Rust: Supported for rustc.
+- Test integration: supported. Interactive tests are supported starting with
+  Meson 1.5.0 via the `--interactive` flag.
diff --git a/Documentation/technical/bundle-uri.adoc b/Documentation/technical/bundle-uri.adoc
new file mode 100644
index 0000000000..91d3a13e32
--- /dev/null
+++ b/Documentation/technical/bundle-uri.adoc
@@ -0,0 +1,572 @@
+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 linkgit:gitformat-bundle[5] 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
+	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 each
+   bundled ref as a `have`, 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 tokens 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 response.
+
+* 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 recommended 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.heuristic` configuration key
+   and the `bundle.<id>.creationToken` heuristic. When `git clone`
+   discovers a bundle URI with `bundle.heuristic`, 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.heuristic` is set.
+
+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@xxxxxxxxx/
+    An earlier RFC for a bundle URI feature.
+
+[2] https://github.com/microsoft/VFSForGit/blob/master/Protocol.md
+    The GVFS Protocol
diff --git a/Documentation/technical/commit-graph.adoc b/Documentation/technical/commit-graph.adoc
new file mode 100644
index 0000000000..2c26e95e51
--- /dev/null
+++ b/Documentation/technical/commit-graph.adoc
@@ -0,0 +1,401 @@
+Git Commit-Graph Design Notes
+=============================
+
+Git walks the commit graph for many reasons, including:
+
+1. Listing and filtering commit history.
+2. Computing merge bases.
+
+These operations can become slow as the commit count grows. The merge
+base calculation shows up in many user-facing commands, such as 'merge-base'
+or 'status' and can take minutes to compute depending on history shape.
+
+There are two main costs here:
+
+1. Decompressing and parsing commits.
+2. Walking the entire graph to satisfy topological order constraints.
+
+The commit-graph file is a supplemental data structure that accelerates
+commit graph walks. If a user downgrades or disables the 'core.commitGraph'
+config setting, then the existing object database is sufficient. The file is stored
+as "commit-graph" either in the .git/objects/info directory or in the info
+directory of an alternate.
+
+The commit-graph file stores the commit graph structure along with some
+extra metadata to speed up graph walks. By listing commit OIDs in
+lexicographic order, we can identify an integer position for each commit
+and refer to the parents of a commit using those integer positions. We
+use binary search to find initial commits and then use the integer
+positions for fast lookups during the walk.
+
+A consumer may load the following info for a commit from the graph:
+
+1. The commit OID.
+2. The list of parents, along with their integer position.
+3. The commit date.
+4. The root tree OID.
+5. The generation number (see definition below).
+
+Values 1-4 satisfy the requirements of parse_commit_gently().
+
+There are two definitions of generation number:
+1. Corrected committer dates (generation number v2)
+2. Topological levels (generation number v1)
+
+Define "corrected committer date" of a commit recursively as follows:
+
+ * A commit with no parents (a root commit) has corrected committer date
+    equal to its committer date.
+
+ * A commit with at least one parent has corrected committer date equal to
+    the maximum of its committer date and one more than the largest corrected
+    committer date among its parents.
+
+ * As a special case, a root commit with timestamp zero has corrected commit
+    date of 1, to be able to distinguish it from GENERATION_NUMBER_ZERO
+    (that is, an uncomputed corrected commit date).
+
+Define the "topological level" of a commit recursively as follows:
+
+ * A commit with no parents (a root commit) has topological level of one.
+
+ * A commit with at least one parent has topological level one more than
+   the largest topological level among its parents.
+
+Equivalently, the topological level of a commit A is one more than the
+length of a longest path from A to a root commit. The recursive definition
+is easier to use for computation and observing the following property:
+
+    If A and B are commits with generation numbers N and M, respectively,
+    and N <= M, then A cannot reach B. That is, we know without searching
+    that B is not an ancestor of A because it is further from a root commit
+    than A.
+
+    Conversely, when checking if A is an ancestor of B, then we only need
+    to walk commits until all commits on the walk boundary have generation
+    number at most N. If we walk commits using a priority queue seeded by
+    generation numbers, then we always expand the boundary commit with highest
+    generation number and can easily detect the stopping condition.
+
+The property applies to both versions of generation number, that is both
+corrected committer dates and topological levels.
+
+This property can be used to significantly reduce the time it takes to
+walk commits and determine topological relationships. Without generation
+numbers, the general heuristic is the following:
+
+    If A and B are commits with commit time X and Y, respectively, and
+    X < Y, then A _probably_ cannot reach B.
+
+In absence of corrected commit dates (for example, old versions of Git or
+mixed generation graph chains),
+this heuristic is currently used whenever the computation is allowed to
+violate topological relationships due to clock skew (such as "git log"
+with default order), but is not used when the topological order is
+required (such as merge base calculations, "git log --graph").
+
+In practice, we expect some commits to be created recently and not stored
+in the commit-graph. We can treat these commits as having "infinite"
+generation number and walk until reaching commits with known generation
+number.
+
+We use the macro GENERATION_NUMBER_INFINITY to mark commits not
+in the commit-graph file. If a commit-graph file was written by a version
+of Git that did not compute generation numbers, then those commits will
+have generation number represented by the macro GENERATION_NUMBER_ZERO = 0.
+
+Since the commit-graph file is closed under reachability, we can guarantee
+the following weaker condition on all commits:
+
+    If A and B are commits with generation numbers N and M, respectively,
+    and N < M, then A cannot reach B.
+
+Note how the strict inequality differs from the inequality when we have
+fully-computed generation numbers. Using strict inequality may result in
+walking a few extra commits, but the simplicity in dealing with commits
+with generation number *_INFINITY or *_ZERO is valuable.
+
+We use the macro GENERATION_NUMBER_V1_MAX = 0x3FFFFFFF for commits whose
+topological levels (generation number v1) are computed to be at least
+this value. We limit at this value since it is the largest value that
+can be stored in the commit-graph file using the 30 bits available
+to topological levels. This presents another case where a commit can
+have generation number equal to that of a parent.
+
+Design Details
+--------------
+
+- The commit-graph file is stored in a file named 'commit-graph' in the
+  .git/objects/info directory. This could be stored in the info directory
+  of an alternate.
+
+- The core.commitGraph config setting must be on to consume graph files.
+
+- The file format includes parameters for the object ID hash function,
+  so a future change of hash algorithm does not require a change in format.
+
+- Commit grafts and replace objects can change the shape of the commit
+  history. The latter can also be enabled/disabled on the fly using
+  `--no-replace-objects`. This leads to difficulty storing both possible
+  interpretations of a commit id, especially when computing generation
+  numbers. The commit-graph will not be read or written when
+  replace-objects or grafts are present.
+
+- Shallow clones create grafts of commits by dropping their parents. This
+  leads the commit-graph to think those commits have generation number 1.
+  If and when those commits are made unshallow, those generation numbers
+  become invalid. Since shallow clones are intended to restrict the commit
+  history to a very small set of commits, the commit-graph feature is less
+  helpful for these clones, anyway. The commit-graph will not be read or
+  written when shallow commits are present.
+
+Commit-Graphs Chains
+--------------------
+
+Typically, repos grow with near-constant velocity (commits per day). Over time,
+the number of commits added by a fetch operation is much smaller than the
+number of commits in the full history. By creating a "chain" of commit-graphs,
+we enable fast writes of new commit data without rewriting the entire commit
+history -- at least, most of the time.
+
+## File Layout
+
+A commit-graph chain uses multiple files, and we use a fixed naming convention
+to organize these files. Each commit-graph file has a name
+`$OBJDIR/info/commit-graphs/graph-{hash}.graph` where `{hash}` is the hex-
+valued hash stored in the footer of that file (which is a hash of the file's
+contents before that hash). For a chain of commit-graph files, a plain-text
+file at `$OBJDIR/info/commit-graphs/commit-graph-chain` contains the
+hashes for the files in order from "lowest" to "highest".
+
+For example, if the `commit-graph-chain` file contains the lines
+
+```
+	{hash0}
+	{hash1}
+	{hash2}
+```
+
+then the commit-graph chain looks like the following diagram:
+
+ +-----------------------+
+ |  graph-{hash2}.graph  |
+ +-----------------------+
+	  |
+ +-----------------------+
+ |                       |
+ |  graph-{hash1}.graph  |
+ |                       |
+ +-----------------------+
+	  |
+ +-----------------------+
+ |                       |
+ |                       |
+ |                       |
+ |  graph-{hash0}.graph  |
+ |                       |
+ |                       |
+ |                       |
+ +-----------------------+
+
+Let X0 be the number of commits in `graph-{hash0}.graph`, X1 be the number of
+commits in `graph-{hash1}.graph`, and X2 be the number of commits in
+`graph-{hash2}.graph`. If a commit appears in position i in `graph-{hash2}.graph`,
+then we interpret this as being the commit in position (X0 + X1 + i), and that
+will be used as its "graph position". The commits in `graph-{hash2}.graph` use these
+positions to refer to their parents, which may be in `graph-{hash1}.graph` or
+`graph-{hash0}.graph`. We can navigate to an arbitrary commit in position j by checking
+its containment in the intervals [0, X0), [X0, X0 + X1), [X0 + X1, X0 + X1 +
+X2).
+
+Each commit-graph file (except the base, `graph-{hash0}.graph`) contains data
+specifying the hashes of all files in the lower layers. In the above example,
+`graph-{hash1}.graph` contains `{hash0}` while `graph-{hash2}.graph` contains
+`{hash0}` and `{hash1}`.
+
+## Merging commit-graph files
+
+If we only added a new commit-graph file on every write, we would run into a
+linear search problem through many commit-graph files.  Instead, we use a merge
+strategy to decide when the stack should collapse some number of levels.
+
+The diagram below shows such a collapse. As a set of new commits are added, it
+is determined by the merge strategy that the files should collapse to
+`graph-{hash1}`. Thus, the new commits, the commits in `graph-{hash2}` and
+the commits in `graph-{hash1}` should be combined into a new `graph-{hash3}`
+file.
+
+			    +---------------------+
+			    |                     |
+			    |    (new commits)    |
+			    |                     |
+			    +---------------------+
+			    |                     |
+ +-----------------------+  +---------------------+
+ |  graph-{hash2}        |->|                     |
+ +-----------------------+  +---------------------+
+	  |                 |                     |
+ +-----------------------+  +---------------------+
+ |                       |  |                     |
+ |  graph-{hash1}        |->|                     |
+ |                       |  |                     |
+ +-----------------------+  +---------------------+
+	  |                  tmp_graphXXX
+ +-----------------------+
+ |                       |
+ |                       |
+ |                       |
+ |  graph-{hash0}        |
+ |                       |
+ |                       |
+ |                       |
+ +-----------------------+
+
+During this process, the commits to write are combined, sorted and we write the
+contents to a temporary file, all while holding a `commit-graph-chain.lock`
+lock-file.  When the file is flushed, we rename it to `graph-{hash3}`
+according to the computed `{hash3}`. Finally, we write the new chain data to
+`commit-graph-chain.lock`:
+
+```
+	{hash3}
+	{hash0}
+```
+
+We then close the lock-file.
+
+## Merge Strategy
+
+When writing a set of commits that do not exist in the commit-graph stack of
+height N, we default to creating a new file at level N + 1. We then decide to
+merge with the Nth level if one of two conditions hold:
+
+  1. `--size-multiple=<X>` is specified or X = 2, and the number of commits in
+     level N is less than X times the number of commits in level N + 1.
+
+  2. `--max-commits=<C>` is specified with non-zero C and the number of commits
+     in level N + 1 is more than C commits.
+
+This decision cascades down the levels: when we merge a level we create a new
+set of commits that then compares to the next level.
+
+The first condition bounds the number of levels to be logarithmic in the total
+number of commits.  The second condition bounds the total number of commits in
+a `graph-{hashN}` file and not in the `commit-graph` file, preventing
+significant performance issues when the stack merges and another process only
+partially reads the previous stack.
+
+The merge strategy values (2 for the size multiple, 64,000 for the maximum
+number of commits) could be extracted into config settings for full
+flexibility.
+
+## Handling Mixed Generation Number Chains
+
+With the introduction of generation number v2 and generation data chunk, the
+following scenario is possible:
+
+1. "New" Git writes a commit-graph with the corrected commit dates.
+2. "Old" Git writes a split commit-graph on top without corrected commit dates.
+
+A naive approach of using the newest available generation number from
+each layer would lead to violated expectations: the lower layer would
+use corrected commit dates which are much larger than the topological
+levels of the higher layer. For this reason, Git inspects the topmost
+layer to see if the layer is missing corrected commit dates. In such a case
+Git only uses topological level for generation numbers.
+
+When writing a new layer in split commit-graph, we write corrected commit
+dates if the topmost layer has corrected commit dates written. This
+guarantees that if a layer has corrected commit dates, all lower layers
+must have corrected commit dates as well.
+
+When merging layers, we do not consider whether the merged layers had corrected
+commit dates. Instead, the new layer will have corrected commit dates if the
+layer below the new layer has corrected commit dates.
+
+While writing or merging layers, if the new layer is the only layer, it will
+have corrected commit dates when written by compatible versions of Git. Thus,
+rewriting split commit-graph as a single file (`--split=replace`) creates a
+single layer with corrected commit dates.
+
+## Deleting graph-{hash} files
+
+After a new tip file is written, some `graph-{hash}` files may no longer
+be part of a chain. It is important to remove these files from disk, eventually.
+The main reason to delay removal is that another process could read the
+`commit-graph-chain` file before it is rewritten, but then look for the
+`graph-{hash}` files after they are deleted.
+
+To allow holding old split commit-graphs for a while after they are unreferenced,
+we update the modified times of the files when they become unreferenced. Then,
+we scan the `$OBJDIR/info/commit-graphs/` directory for `graph-{hash}`
+files whose modified times are older than a given expiry window. This window
+defaults to zero, but can be changed using command-line arguments or a config
+setting.
+
+## Chains across multiple object directories
+
+In a repo with alternates, we look for the `commit-graph-chain` file starting
+in the local object directory and then in each alternate. The first file that
+exists defines our chain. As we look for the `graph-{hash}` files for
+each `{hash}` in the chain file, we follow the same pattern for the host
+directories.
+
+This allows commit-graphs to be split across multiple forks in a fork network.
+The typical case is a large "base" repo with many smaller forks.
+
+As the base repo advances, it will likely update and merge its commit-graph
+chain more frequently than the forks. If a fork updates their commit-graph after
+the base repo, then it should "reparent" the commit-graph chain onto the new
+chain in the base repo. When reading each `graph-{hash}` file, we track
+the object directory containing it. During a write of a new commit-graph file,
+we check for any changes in the source object directory and read the
+`commit-graph-chain` file for that source and create a new file based on those
+files. During this "reparent" operation, we necessarily need to collapse all
+levels in the fork, as all of the files are invalid against the new base file.
+
+It is crucial to be careful when cleaning up "unreferenced" `graph-{hash}.graph`
+files in this scenario. It falls to the user to define the proper settings for
+their custom environment:
+
+ 1. When merging levels in the base repo, the unreferenced files may still be
+    referenced by chains from fork repos.
+
+ 2. The expiry time should be set to a length of time such that every fork has
+    time to recompute their commit-graph chain to "reparent" onto the new base
+    file(s).
+
+ 3. If the commit-graph chain is updated in the base, the fork will not have
+    access to the new chain until its chain is updated to reference those files.
+    (This may change in the future [5].)
+
+Related Links
+-------------
+[0] https://bugs.chromium.org/p/git/issues/detail?id=8
+    Chromium work item for: Serialized Commit Graph
+
+[1] https://lore.kernel.org/git/20110713070517.GC18566@xxxxxxxxxxxxxxxxxxxxx/
+    An abandoned patch that introduced generation numbers.
+
+[2] https://lore.kernel.org/git/20170908033403.q7e6dj7benasrjes@xxxxxxxxxxxxxxxxxxxxx/
+    Discussion about generation numbers on commits and how they interact
+    with fsck.
+
+[3] https://lore.kernel.org/git/20170908034739.4op3w4f2ma5s65ku@xxxxxxxxxxxxxxxxxxxxx/
+    More discussion about generation numbers and not storing them inside
+    commit objects. A valuable quote:
+
+    "I think we should be moving more in the direction of keeping
+     repo-local caches for optimizations. Reachability bitmaps have been
+     a big performance win. I think we should be doing the same with our
+     properties of commits. Not just generation numbers, but making it
+     cheap to access the graph structure without zlib-inflating whole
+     commit objects (i.e., packv4 or something like the "metapacks" I
+     proposed a few years ago)."
+
+[4] https://lore.kernel.org/git/20180108154822.54829-1-git@xxxxxxxxxxxxxxxxx/T/#u
+    A patch to remove the ahead-behind calculation from 'status'.
+
+[5] https://lore.kernel.org/git/f27db281-abad-5043-6d71-cbb083b1c877@xxxxxxxxx/
+    A discussion of a "two-dimensional graph position" that can allow reading
+    multiple commit-graph chains at the same time.
diff --git a/Documentation/technical/directory-rename-detection.adoc b/Documentation/technical/directory-rename-detection.adoc
new file mode 100644
index 0000000000..029ee2cedc
--- /dev/null
+++ b/Documentation/technical/directory-rename-detection.adoc
@@ -0,0 +1,118 @@
+Directory rename detection
+==========================
+
+Rename detection logic in diffcore-rename that checks for renames of
+individual files is also aggregated there and then analyzed in either
+merge-ort or merge-recursive for cases where combinations of renames
+indicate that a full directory has been renamed.
+
+Scope of abilities
+------------------
+
+It is perhaps easiest to start with an example:
+
+  * When all of x/a, x/b and x/c have moved to z/a, z/b and z/c, it is
+    likely that x/d added in the meantime would also want to move to z/d by
+    taking the hint that the entire directory 'x' moved to 'z'.
+
+More interesting possibilities exist, though, such as:
+
+  * one side of history renames x -> z, and the other renames some file to
+    x/e, causing the need for the merge to do a transitive rename so that
+    the rename ends up at z/e.
+
+  * one side of history renames x -> z, but also renames all files within x.
+    For example, x/a -> z/alpha, x/b -> z/bravo, etc.
+
+  * both 'x' and 'y' being merged into a single directory 'z', with a
+    directory rename being detected for both x->z and y->z.
+
+  * not all files in a directory being renamed to the same location;
+    i.e. perhaps most the files in 'x' are now found under 'z', but a few
+    are found under 'w'.
+
+  * a directory being renamed, which also contained a subdirectory that was
+    renamed to some entirely different location.  (And perhaps the inner
+    directory itself contained inner directories that were renamed to yet
+    other locations).
+
+  * combinations of the above; see t/t6423-merge-rename-directories.sh for
+    various interesting cases.
+
+Limitations -- applicability of directory renames
+-------------------------------------------------
+
+In order to prevent edge and corner cases resulting in either conflicts
+that cannot be represented in the index or which might be too complex for
+users to try to understand and resolve, a couple basic rules limit when
+directory rename detection applies:
+
+  1) If a given directory still exists on both sides of a merge, we do
+     not consider it to have been renamed.
+
+  2) If a subset of to-be-renamed files have a file or directory in the
+     way (or would be in the way of each other), "turn off" the directory
+     rename for those specific sub-paths and report the conflict to the
+     user.
+
+  3) If the other side of history did a directory rename to a path that
+     your side of history renamed away, then ignore that particular
+     rename from the other side of history for any implicit directory
+     renames (but warn the user).
+
+Limitations -- detailed rules and testcases
+-------------------------------------------
+
+t/t6423-merge-rename-directories.sh contains extensive tests and commentary
+which generate and explore the rules listed above.  It also lists a few
+additional rules:
+
+  a) If renames split a directory into two or more others, the directory
+     with the most renames, "wins".
+
+  b) Only apply implicit directory renames to directories if the other side
+     of history is the one doing the renaming.
+
+  c) Do not perform directory rename detection for directories which had no
+     new paths added to them.
+
+Limitations -- support in different commands
+--------------------------------------------
+
+Directory rename detection is supported by 'merge' and 'cherry-pick'.
+Other git commands which users might be surprised to see limited or no
+directory rename detection support in:
+
+  * diff
+
+    Folks have requested in the past that `git diff` detect directory
+    renames and somehow simplify its output.  It is not clear whether this
+    would be desirable or how the output should be simplified, so this was
+    simply not implemented.  Also, while diffcore-rename has most of the
+    logic for detecting directory renames, some of the logic is still found
+    within merge-ort and merge-recursive.  Fully supporting directory
+    rename detection in diffs would require copying or moving the remaining
+    bits of logic to the diff machinery.
+
+  * am
+
+    git-am tries to avoid a full three way merge, instead calling
+    git-apply.  That prevents us from detecting renames at all, which may
+    defeat the directory rename detection.  There is a fallback, though; if
+    the initial git-apply fails and the user has specified the -3 option,
+    git-am will fall back to a three way merge.  However, git-am lacks the
+    necessary information to do a "real" three way merge.  Instead, it has
+    to use build_fake_ancestor() to get a merge base that is missing files
+    whose rename may have been important to detect for directory rename
+    detection to function.
+
+  * rebase
+
+    Since am-based rebases work by first generating a bunch of patches
+    (which no longer record what the original commits were and thus don't
+    have the necessary info from which we can find a real merge-base), and
+    then calling git-am, this implies that am-based rebases will not always
+    successfully detect directory renames either (see the 'am' section
+    above).  merged-based rebases (rebase -m) and cherry-pick-based rebases
+    (rebase -i) are not affected by this shortcoming, and fully support
+    directory rename detection.
diff --git a/Documentation/technical/hash-function-transition.adoc b/Documentation/technical/hash-function-transition.adoc
new file mode 100644
index 0000000000..7102c7c8f5
--- /dev/null
+++ b/Documentation/technical/hash-function-transition.adoc
@@ -0,0 +1,830 @@
+Git hash function transition
+============================
+
+Objective
+---------
+Migrate Git from SHA-1 to a stronger hash function.
+
+Background
+----------
+At its core, the Git version control system is a content addressable
+filesystem. It uses the SHA-1 hash function to name content. For
+example, files, directories, and revisions are referred to by hash
+values unlike in other traditional version control systems where files
+or versions are referred to via sequential numbers. The use of a hash
+function to address its content delivers a few advantages:
+
+* Integrity checking is easy. Bit flips, for example, are easily
+  detected, as the hash of corrupted content does not match its name.
+* Lookup of objects is fast.
+
+Using a cryptographically secure hash function brings additional
+advantages:
+
+* Object names can be signed and third parties can trust the hash to
+  address the signed object and all objects it references.
+* Communication using Git protocol and out of band communication
+  methods have a short reliable string that can be used to reliably
+  address stored content.
+
+Over time some flaws in SHA-1 have been discovered by security
+researchers. On 23 February 2017 the SHAttered attack
+(https://shattered.io) demonstrated a practical SHA-1 hash collision.
+
+Git v2.13.0 and later subsequently moved to a hardened SHA-1
+implementation by default, which isn't vulnerable to the SHAttered
+attack, but SHA-1 is still weak.
+
+Thus it's considered prudent to move past any variant of SHA-1
+to a new hash. There's no guarantee that future attacks on SHA-1 won't
+be published in the future, and those attacks may not have viable
+mitigations.
+
+If SHA-1 and its variants were to be truly broken, Git's hash function
+could not be considered cryptographically secure any more. This would
+impact the communication of hash values because we could not trust
+that a given hash value represented the known good version of content
+that the speaker intended.
+
+SHA-1 still possesses the other properties such as fast object lookup
+and safe error checking, but other hash functions are equally suitable
+that are believed to be cryptographically secure.
+
+Choice of Hash
+--------------
+The hash to replace the hardened SHA-1 should be stronger than SHA-1
+was: we would like it to be trustworthy and useful in practice for at
+least 10 years.
+
+Some other relevant properties:
+
+1. A 256-bit hash (long enough to match common security practice; not
+   excessively long to hurt performance and disk usage).
+
+2. High quality implementations should be widely available (e.g., in
+   OpenSSL and Apple CommonCrypto).
+
+3. The hash function's properties should match Git's needs (e.g. Git
+   requires collision and 2nd preimage resistance and does not require
+   length extension resistance).
+
+4. As a tiebreaker, the hash should be fast to compute (fortunately
+   many contenders are faster than SHA-1).
+
+There were several contenders for a successor hash to SHA-1, including
+SHA-256, SHA-512/256, SHA-256x16, K12, and BLAKE2bp-256.
+
+In late 2018 the project picked SHA-256 as its successor hash.
+
+See 0ed8d8da374 (doc hash-function-transition: pick SHA-256 as
+NewHash, 2018-08-04) and numerous mailing list threads at the time,
+particularly the one starting at
+https://lore.kernel.org/git/20180609224913.GC38834@xxxxxxxxxxxxxxxxxxxxxxxxxx/
+for more information.
+
+Goals
+-----
+1. The transition to SHA-256 can be done one local repository at a time.
+   a. Requiring no action by any other party.
+   b. A SHA-256 repository can communicate with SHA-1 Git servers
+      (push/fetch).
+   c. Users can use SHA-1 and SHA-256 identifiers for objects
+      interchangeably (see "Object names on the command line", below).
+   d. New signed objects make use of a stronger hash function than
+      SHA-1 for their security guarantees.
+2. Allow a complete transition away from SHA-1.
+   a. Local metadata for SHA-1 compatibility can be removed from a
+      repository if compatibility with SHA-1 is no longer needed.
+3. Maintainability throughout the process.
+   a. The object format is kept simple and consistent.
+   b. Creation of a generalized repository conversion tool.
+
+Non-Goals
+---------
+1. Add SHA-256 support to Git protocol. This is valuable and the
+   logical next step but it is out of scope for this initial design.
+2. Transparently improving the security of existing SHA-1 signed
+   objects.
+3. Intermixing objects using multiple hash functions in a single
+   repository.
+4. Taking the opportunity to fix other bugs in Git's formats and
+   protocols.
+5. Shallow clones and fetches into a SHA-256 repository. (This will
+   change when we add SHA-256 support to Git protocol.)
+6. Skip fetching some submodules of a project into a SHA-256
+   repository. (This also depends on SHA-256 support in Git
+   protocol.)
+
+Overview
+--------
+We introduce a new repository format extension. Repositories with this
+extension enabled use SHA-256 instead of SHA-1 to name their objects.
+This affects both object names and object content -- both the names
+of objects and all references to other objects within an object are
+switched to the new hash function.
+
+SHA-256 repositories cannot be read by older versions of Git.
+
+Alongside the packfile, a SHA-256 repository stores a bidirectional
+mapping between SHA-256 and SHA-1 object names. The mapping is generated
+locally and can be verified using "git fsck". Object lookups use this
+mapping to allow naming objects using either their SHA-1 and SHA-256 names
+interchangeably.
+
+"git cat-file" and "git hash-object" gain options to display an object
+in its SHA-1 form and write an object given its SHA-1 form. This
+requires all objects referenced by that object to be present in the
+object database so that they can be named using the appropriate name
+(using the bidirectional hash mapping).
+
+Fetches from a SHA-1 based server convert the fetched objects into
+SHA-256 form and record the mapping in the bidirectional mapping table
+(see below for details). Pushes to a SHA-1 based server convert the
+objects being pushed into SHA-1 form so the server does not have to be
+aware of the hash function the client is using.
+
+Detailed Design
+---------------
+Repository format extension
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+A SHA-256 repository uses repository format version `1` (see
+linkgit:gitrepository-layout[5]) with `extensions.objectFormat` and
+`extensions.compatObjectFormat` (see linkgit:git-config[1]) set to:
+
+	[core]
+		repositoryFormatVersion = 1
+	[extensions]
+		objectFormat = sha256
+		compatObjectFormat = sha1
+
+The combination of setting `core.repositoryFormatVersion=1` and
+populating `extensions.*` ensures that all versions of Git later than
+`v0.99.9l` will die instead of trying to operate on the SHA-256
+repository, instead producing an error message.
+
+	# Between v0.99.9l and v2.7.0
+	$ git status
+	fatal: Expected git repo version <= 0, found 1
+	# After v2.7.0
+	$ git status
+	fatal: unknown repository extensions found:
+		objectformat
+		compatobjectformat
+
+See the "Transition plan" section below for more details on these
+repository extensions.
+
+Object names
+~~~~~~~~~~~~
+Objects can be named by their 40 hexadecimal digit SHA-1 name or 64
+hexadecimal digit SHA-256 name, plus names derived from those (see
+gitrevisions(7)).
+
+The SHA-1 name of an object is the SHA-1 of the concatenation of its
+type, length, a nul byte, and the object's SHA-1 content. This is the
+traditional <sha1> used in Git to name objects.
+
+The SHA-256 name of an object is the SHA-256 of the concatenation of its
+type, length, a nul byte, and the object's SHA-256 content.
+
+Object format
+~~~~~~~~~~~~~
+The content as a byte sequence of a tag, commit, or tree object named
+by SHA-1 and SHA-256 differ because an object named by SHA-256 name refers to
+other objects by their SHA-256 names and an object named by SHA-1 name
+refers to other objects by their SHA-1 names.
+
+The SHA-256 content of an object is the same as its SHA-1 content, except
+that objects referenced by the object are named using their SHA-256 names
+instead of SHA-1 names. Because a blob object does not refer to any
+other object, its SHA-1 content and SHA-256 content are the same.
+
+The format allows round-trip conversion between SHA-256 content and
+SHA-1 content.
+
+Object storage
+~~~~~~~~~~~~~~
+Loose objects use zlib compression and packed objects use the packed
+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.
+
+Pack index
+~~~~~~~~~~
+Pack index (.idx) files use a new v3 format that supports multiple
+hash functions. They have the following format (all integers are in
+network byte order):
+
+- A header appears at the beginning and consists of the following:
+  * The 4-byte pack index signature: '\377t0c'
+  * 4-byte version number: 3
+  * 4-byte length of the header section, including the signature and
+    version number
+  * 4-byte number of objects contained in the pack
+  * 4-byte number of object formats in this pack index: 2
+  * For each object format:
+    ** 4-byte format identifier (e.g., 'sha1' for SHA-1)
+    ** 4-byte length in bytes of shortened object names. This is the
+      shortest possible length needed to make names in the shortened
+      object name table unambiguous.
+    ** 4-byte integer, recording where tables relating to this format
+      are stored in this index file, as an offset from the beginning.
+  * 4-byte offset to the trailer from the beginning of this file.
+  * Zero or more additional key/value pairs (4-byte key, 4-byte
+    value). Only one key is supported: 'PSRC'. See the "Loose objects
+    and unreachable objects" section for supported values and how this
+    is used.  All other keys are reserved. Readers must ignore
+    unrecognized keys.
+- Zero or more NUL bytes. This can optionally be used to improve the
+  alignment of the full object name table below.
+- Tables for the first object format:
+  * A sorted table of shortened object names.  These are prefixes of
+    the names of all objects in this pack file, packed together
+    without offset values to reduce the cache footprint of the binary
+    search for a specific object name.
+
+  * A table of full object names in pack order. This allows resolving
+    a reference to "the nth object in the pack file" (from a
+    reachability bitmap or from the next table of another object
+    format) to its object name.
+
+  * A table of 4-byte values mapping object name order to pack order.
+    For an object in the table of sorted shortened object names, the
+    value at the corresponding index in this table is the index in the
+    previous table for that same object.
+    This can be used to look up the object in reachability bitmaps or
+    to look up its name in another object format.
+
+  * A table of 4-byte CRC32 values of the packed object data, in the
+    order that the objects appear in the pack file. This is to allow
+    compressed data to be copied directly from pack to pack during
+    repacking without undetected data corruption.
+
+  * A table of 4-byte offset values. For an object in the table of
+    sorted shortened object names, the value at the corresponding
+    index in this table indicates where that object can be found in
+    the pack file. These are usually 31-bit pack file offsets, but
+    large offsets are encoded as an index into the next table with the
+    most significant bit set.
+
+  * 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.
+- Zero or more NUL bytes.
+- Tables for the second object format, with the same layout as above,
+  up to and not including the table of CRC32 values.
+- Zero or more NUL bytes.
+- The trailer consists of the following:
+  * A copy of the 20-byte SHA-256 checksum at the end of the
+    corresponding packfile.
+
+  * 20-byte SHA-256 checksum of all of the above.
+
+Loose object index
+~~~~~~~~~~~~~~~~~~
+A new file $GIT_OBJECT_DIR/loose-object-idx contains information about
+all loose objects. Its format is
+
+  # loose-object-idx
+  (sha256-name SP sha1-name LF)*
+
+where the object names are in hexadecimal format. The file is not
+sorted.
+
+The loose object index is protected against concurrent writes by a
+lock file $GIT_OBJECT_DIR/loose-object-idx.lock. To add a new loose
+object:
+
+1. Write the loose object to a temporary file, like today.
+2. Open loose-object-idx.lock with O_CREAT | O_EXCL to acquire the lock.
+3. Rename the loose object into place.
+4. Open loose-object-idx with O_APPEND and write the new object
+5. Unlink loose-object-idx.lock to release the lock.
+
+To remove entries (e.g. in "git pack-refs" or "git-prune"):
+
+1. Open loose-object-idx.lock with O_CREAT | O_EXCL to acquire the
+   lock.
+2. Write the new content to loose-object-idx.lock.
+3. Unlink any loose objects being removed.
+4. Rename to replace loose-object-idx, releasing the lock.
+
+Translation table
+~~~~~~~~~~~~~~~~~
+The index files support a bidirectional mapping between SHA-1 names
+and SHA-256 names. The lookup proceeds similarly to ordinary object
+lookups. For example, to convert a SHA-1 name to a SHA-256 name:
+
+ 1. Look for the object in idx files. If a match is present in the
+    idx's sorted list of truncated SHA-1 names, then:
+    a. Read the corresponding entry in the SHA-1 name order to pack
+       name order mapping.
+    b. Read the corresponding entry in the full SHA-1 name table to
+       verify we found the right object. If it is, then
+    c. Read the corresponding entry in the full SHA-256 name table.
+       That is the object's SHA-256 name.
+ 2. Check for a loose object. Read lines from loose-object-idx until
+    we find a match.
+
+Step (1) takes the same amount of time as an ordinary object lookup:
+O(number of packs * log(objects per pack)). Step (2) takes O(number of
+loose objects) time. To maintain good performance it will be necessary
+to keep the number of loose objects low. See the "Loose objects and
+unreachable objects" section below for more details.
+
+Since all operations that make new objects (e.g., "git commit") add
+the new objects to the corresponding index, this mapping is possible
+for all objects in the object store.
+
+Reading an object's SHA-1 content
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The SHA-1 content of an object can be read by converting all SHA-256 names
+of its SHA-256 content references to SHA-1 names using the translation table.
+
+Fetch
+~~~~~
+Fetching from a SHA-1 based server requires translating between SHA-1
+and SHA-256 based representations on the fly.
+
+SHA-1s named in the ref advertisement that are present on the client
+can be translated to SHA-256 and looked up as local objects using the
+translation table.
+
+Negotiation proceeds as today. Any "have"s generated locally are
+converted to SHA-1 before being sent to the server, and SHA-1s
+mentioned by the server are converted to SHA-256 when looking them up
+locally.
+
+After negotiation, the server sends a packfile containing the
+requested objects. We convert the packfile to SHA-256 format using
+the following steps:
+
+1. index-pack: inflate each object in the packfile and compute its
+   SHA-1. Objects can contain deltas in OBJ_REF_DELTA format against
+   objects the client has locally. These objects can be looked up
+   using the translation table and their SHA-1 content read as
+   described above to resolve the deltas.
+2. topological sort: starting at the "want"s from the negotiation
+   phase, walk through objects in the pack and emit a list of them,
+   excluding blobs, in reverse topologically sorted order, with each
+   object coming later in the list than all objects it references.
+   (This list only contains objects reachable from the "wants". If the
+   pack from the server contained additional extraneous objects, then
+   they will be discarded.)
+3. convert to SHA-256: open a new SHA-256 packfile. Read the topologically
+   sorted list just generated. For each object, inflate its
+   SHA-1 content, convert to SHA-256 content, and write it to the SHA-256
+   pack. Record the new SHA-1<-->SHA-256 mapping entry for use in the idx.
+4. sort: reorder entries in the new pack to match the order of objects
+   in the pack the server generated and include blobs. Write a SHA-256 idx
+   file
+5. clean up: remove the SHA-1 based pack file, index, and
+   topologically sorted list obtained from the server in steps 1
+   and 2.
+
+Step 3 requires every object referenced by the new object to be in the
+translation table. This is why the topological sort step is necessary.
+
+As an optimization, step 1 could write a file describing what non-blob
+objects each object it has inflated from the packfile references. This
+makes the topological sort in step 2 possible without inflating the
+objects in the packfile for a second time. The objects need to be
+inflated again in step 3, for a total of two inflations.
+
+Step 4 is probably necessary for good read-time performance. "git
+pack-objects" on the server optimizes the pack file for good data
+locality (see Documentation/technical/pack-heuristics.txt).
+
+Details of this process are likely to change. It will take some
+experimenting to get this to perform well.
+
+Push
+~~~~
+Push is simpler than fetch because the objects referenced by the
+pushed objects are already in the translation table. The SHA-1 content
+of each object being pushed can be read as described in the "Reading
+an object's SHA-1 content" section to generate the pack written by git
+send-pack.
+
+Signed Commits
+~~~~~~~~~~~~~~
+We add a new field "gpgsig-sha256" to the commit object format to allow
+signing commits without relying on SHA-1. It is similar to the
+existing "gpgsig" field. Its signed payload is the SHA-256 content of the
+commit object with any "gpgsig" and "gpgsig-sha256" fields removed.
+
+This means commits can be signed
+
+1. using SHA-1 only, as in existing signed commit objects
+2. using both SHA-1 and SHA-256, by using both gpgsig-sha256 and gpgsig
+   fields.
+3. using only SHA-256, by only using the gpgsig-sha256 field.
+
+Old versions of "git verify-commit" can verify the gpgsig signature in
+cases (1) and (2) without modifications and view case (3) as an
+ordinary unsigned commit.
+
+Signed Tags
+~~~~~~~~~~~
+We add a new field "gpgsig-sha256" to the tag object format to allow
+signing tags without relying on SHA-1. Its signed payload is the
+SHA-256 content of the tag with its gpgsig-sha256 field and "-----BEGIN PGP
+SIGNATURE-----" delimited in-body signature removed.
+
+This means tags can be signed
+
+1. using SHA-1 only, as in existing signed tag objects
+2. using both SHA-1 and SHA-256, by using gpgsig-sha256 and an in-body
+   signature.
+3. using only SHA-256, by only using the gpgsig-sha256 field.
+
+Mergetag embedding
+~~~~~~~~~~~~~~~~~~
+The mergetag field in the SHA-1 content of a commit contains the
+SHA-1 content of a tag that was merged by that commit.
+
+The mergetag field in the SHA-256 content of the same commit contains the
+SHA-256 content of the same tag.
+
+Submodules
+~~~~~~~~~~
+To convert recorded submodule pointers, you need to have the converted
+submodule repository in place. The translation table of the submodule
+can be used to look up the new hash.
+
+Loose objects and unreachable objects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Fast lookups in the loose-object-idx require that the number of loose
+objects not grow too high.
+
+"git gc --auto" currently waits for there to be 6700 loose objects
+present before consolidating them into a packfile. We will need to
+measure to find a more appropriate threshold for it to use.
+
+"git gc --auto" currently waits for there to be 50 packs present
+before combining packfiles. Packing loose objects more aggressively
+may cause the number of pack files to grow too quickly. This can be
+mitigated by using a strategy similar to Martin Fick's exponential
+rolling garbage collection script:
+https://gerrit-review.googlesource.com/c/gerrit/+/35215
+
+"git gc" currently expels any unreachable objects it encounters in
+pack files to loose objects in an attempt to prevent a race when
+pruning them (in case another process is simultaneously writing a new
+object that refers to the about-to-be-deleted object). This leads to
+an explosion in the number of loose objects present and disk space
+usage due to the objects in delta form being replaced with independent
+loose objects.  Worse, the race is still present for loose objects.
+
+Instead, "git gc" will need to move unreachable objects to a new
+packfile marked as UNREACHABLE_GARBAGE (using the PSRC field; see
+below). To avoid the race when writing new objects referring to an
+about-to-be-deleted object, code paths that write new objects will
+need to copy any objects from UNREACHABLE_GARBAGE packs that they
+refer to new, non-UNREACHABLE_GARBAGE packs (or loose objects).
+UNREACHABLE_GARBAGE are then safe to delete if their creation time (as
+indicated by the file's mtime) is long enough ago.
+
+To avoid a proliferation of UNREACHABLE_GARBAGE packs, they can be
+combined under certain circumstances. If "gc.garbageTtl" is set to
+greater than one day, then packs created within a single calendar day,
+UTC, can be coalesced together. The resulting packfile would have an
+mtime before midnight on that day, so this makes the effective maximum
+ttl the garbageTtl + 1 day. If "gc.garbageTtl" is less than one day,
+then we divide the calendar day into intervals one-third of that ttl
+in duration. Packs created within the same interval can be coalesced
+together. The resulting packfile would have an mtime before the end of
+the interval, so this makes the effective maximum ttl equal to the
+garbageTtl * 4/3.
+
+This rule comes from Thirumala Reddy Mutchukota's JGit change
+https://git.eclipse.org/r/90465.
+
+The UNREACHABLE_GARBAGE setting goes in the PSRC field of the pack
+index. More generally, that field indicates where a pack came from:
+
+ - 1 (PACK_SOURCE_RECEIVE) for a pack received over the network
+ - 2 (PACK_SOURCE_AUTO) for a pack created by a lightweight
+   "gc --auto" operation
+ - 3 (PACK_SOURCE_GC) for a pack created by a full gc
+ - 4 (PACK_SOURCE_UNREACHABLE_GARBAGE) for potential garbage
+   discovered by gc
+ - 5 (PACK_SOURCE_INSERT) for locally created objects that were
+   written directly to a pack file, e.g. from "git add ."
+
+This information can be useful for debugging and for "gc --auto" to
+make appropriate choices about which packs to coalesce.
+
+Caveats
+-------
+Invalid objects
+~~~~~~~~~~~~~~~
+The conversion from SHA-1 content to SHA-256 content retains any
+brokenness in the original object (e.g., tree entry modes encoded with
+leading 0, tree objects whose paths are not sorted correctly, and
+commit objects without an author or committer). This is a deliberate
+feature of the design to allow the conversion to round-trip.
+
+More profoundly broken objects (e.g., a commit with a truncated "tree"
+header line) cannot be converted but were not usable by current Git
+anyway.
+
+Shallow clone and submodules
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Because it requires all referenced objects to be available in the
+locally generated translation table, this design does not support
+shallow clone or unfetched submodules. Protocol improvements might
+allow lifting this restriction.
+
+Alternates
+~~~~~~~~~~
+For the same reason, a SHA-256 repository cannot borrow objects from a
+SHA-1 repository using objects/info/alternates or
+$GIT_ALTERNATE_OBJECT_REPOSITORIES.
+
+git notes
+~~~~~~~~~
+The "git notes" tool annotates objects using their SHA-1 name as key.
+This design does not describe a way to migrate notes trees to use
+SHA-256 names. That migration is expected to happen separately (for
+example using a file at the root of the notes tree to describe which
+hash it uses).
+
+Server-side cost
+~~~~~~~~~~~~~~~~
+Until Git protocol gains SHA-256 support, using SHA-256 based storage
+on public-facing Git servers is strongly discouraged. Once Git
+protocol gains SHA-256 support, SHA-256 based servers are likely not
+to support SHA-1 compatibility, to avoid what may be a very expensive
+hash re-encode during clone and to encourage peers to modernize.
+
+The design described here allows fetches by SHA-1 clients of a
+personal SHA-256 repository because it's not much more difficult than
+allowing pushes from that repository. This support needs to be guarded
+by a configuration option -- servers like git.kernel.org that serve a
+large number of clients would not be expected to bear that cost.
+
+Meaning of signatures
+~~~~~~~~~~~~~~~~~~~~~
+The signed payload for signed commits and tags does not explicitly
+name the hash used to identify objects. If some day Git adopts a new
+hash function with the same length as the current SHA-1 (40
+hexadecimal digit) or SHA-256 (64 hexadecimal digit) objects then the
+intent behind the PGP signed payload in an object signature is
+unclear:
+
+	object e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7
+	type commit
+	tag v2.12.0
+	tagger Junio C Hamano <gitster@xxxxxxxxx> 1487962205 -0800
+
+	Git 2.12
+
+Does this mean Git v2.12.0 is the commit with SHA-1 name
+e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7 or the commit with
+new-40-digit-hash-name e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7?
+
+Fortunately SHA-256 and SHA-1 have different lengths. If Git starts
+using another hash with the same length to name objects, then it will
+need to change the format of signed payloads using that hash to
+address this issue.
+
+Object names on the command line
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+To support the transition (see Transition plan below), this design
+supports four different modes of operation:
+
+ 1. ("dark launch") Treat object names input by the user as SHA-1 and
+    convert any object names written to output to SHA-1, but store
+    objects using SHA-256.  This allows users to test the code with no
+    visible behavior change except for performance.  This allows
+    running even tests that assume the SHA-1 hash function, to
+    sanity-check the behavior of the new mode.
+
+ 2. ("early transition") Allow both SHA-1 and SHA-256 object names in
+    input. Any object names written to output use SHA-1. This allows
+    users to continue to make use of SHA-1 to communicate with peers
+    (e.g. by email) that have not migrated yet and prepares for mode 3.
+
+ 3. ("late transition") Allow both SHA-1 and SHA-256 object names in
+    input. Any object names written to output use SHA-256. In this
+    mode, users are using a more secure object naming method by
+    default.  The disruption is minimal as long as most of their peers
+    are in mode 2 or mode 3.
+
+ 4. ("post-transition") Treat object names input by the user as
+    SHA-256 and write output using SHA-256. This is safer than mode 3
+    because there is less risk that input is incorrectly interpreted
+    using the wrong hash function.
+
+The mode is specified in configuration.
+
+The user can also explicitly specify which format to use for a
+particular revision specifier and for output, overriding the mode. For
+example:
+
+    git --output-format=sha1 log abac87a^{sha1}..f787cac^{sha256}
+
+Transition plan
+---------------
+Some initial steps can be implemented independently of one another:
+
+- adding a hash function API (vtable)
+- teaching fsck to tolerate the gpgsig-sha256 field
+- excluding gpgsig-* from the fields copied by "git commit --amend"
+- annotating tests that depend on SHA-1 values with a SHA1 test
+  prerequisite
+- using "struct object_id", GIT_MAX_RAWSZ, and GIT_MAX_HEXSZ
+  consistently instead of "unsigned char *" and the hardcoded
+  constants 20 and 40.
+- introducing index v3
+- adding support for the PSRC field and safer object pruning
+
+The first user-visible change is the introduction of the objectFormat
+extension (without compatObjectFormat). This requires:
+
+- teaching fsck about this mode of operation
+- using the hash function API (vtable) when computing object names
+- signing objects and verifying signatures
+- rejecting attempts to fetch from or push to an incompatible
+  repository
+
+Next comes introduction of compatObjectFormat:
+
+- implementing the loose-object-idx
+- translating object names between object formats
+- translating object content between object formats
+- generating and verifying signatures in the compat format
+- adding appropriate index entries when adding a new object to the
+  object store
+- --output-format option
+- ^{sha1} and ^{sha256} revision notation
+- configuration to specify default input and output format (see
+  "Object names on the command line" above)
+
+The next step is supporting fetches and pushes to SHA-1 repositories:
+
+- allow pushes to a repository using the compat format
+- generate a topologically sorted list of the SHA-1 names of fetched
+  objects
+- convert the fetched packfile to SHA-256 format and generate an idx
+  file
+- re-sort to match the order of objects in the fetched packfile
+
+The infrastructure supporting fetch also allows converting an existing
+repository. In converted repositories and new clones, end users can
+gain support for the new hash function without any visible change in
+behavior (see "dark launch" in the "Object names on the command line"
+section). In particular this allows users to verify SHA-256 signatures
+on objects in the repository, and it should ensure the transition code
+is stable in production in preparation for using it more widely.
+
+Over time projects would encourage their users to adopt the "early
+transition" and then "late transition" modes to take advantage of the
+new, more futureproof SHA-256 object names.
+
+When objectFormat and compatObjectFormat are both set, commands
+generating signatures would generate both SHA-1 and SHA-256 signatures
+by default to support both new and old users.
+
+In projects using SHA-256 heavily, users could be encouraged to adopt
+the "post-transition" mode to avoid accidentally making implicit use
+of SHA-1 object names.
+
+Once a critical mass of users have upgraded to a version of Git that
+can verify SHA-256 signatures and have converted their existing
+repositories to support verifying them, we can add support for a
+setting to generate only SHA-256 signatures. This is expected to be at
+least a year later.
+
+That is also a good moment to advertise the ability to convert
+repositories to use SHA-256 only, stripping out all SHA-1 related
+metadata. This improves performance by eliminating translation
+overhead and security by avoiding the possibility of accidentally
+relying on the safety of SHA-1.
+
+Updating Git's protocols to allow a server to specify which hash
+functions it supports is also an important part of this transition. It
+is not discussed in detail in this document but this transition plan
+assumes it happens. :)
+
+Alternatives considered
+-----------------------
+Upgrading everyone working on a particular project on a flag day
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Projects like the Linux kernel are large and complex enough that
+flipping the switch for all projects based on the repository at once
+is infeasible.
+
+Not only would all developers and server operators supporting
+developers have to switch on the same flag day, but supporting tooling
+(continuous integration, code review, bug trackers, etc) would have to
+be adapted as well. This also makes it difficult to get early feedback
+from some project participants testing before it is time for mass
+adoption.
+
+Using hash functions in parallel
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+(e.g. https://lore.kernel.org/git/22708.8913.864049.452252@xxxxxxxxxxxxxxxxxxxxxx/ )
+Objects newly created would be addressed by the new hash, but inside
+such an object (e.g. commit) it is still possible to address objects
+using the old hash function.
+
+* You cannot trust its history (needed for bisectability) in the
+  future without further work
+* Maintenance burden as the number of supported hash functions grows
+  (they will never go away, so they accumulate). In this proposal, by
+  comparison, converted objects lose all references to SHA-1.
+
+Signed objects with multiple hashes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Instead of introducing the gpgsig-sha256 field in commit and tag objects
+for SHA-256 content based signatures, an earlier version of this design
+added "hash sha256 <SHA-256 name>" fields to strengthen the existing
+SHA-1 content based signatures.
+
+In other words, a single signature was used to attest to the object
+content using both hash functions. This had some advantages:
+
+* Using one signature instead of two speeds up the signing process.
+* Having one signed payload with both hashes allows the signer to
+  attest to the SHA-1 name and SHA-256 name referring to the same object.
+* All users consume the same signature. Broken signatures are likely
+  to be detected quickly using current versions of git.
+
+However, it also came with disadvantages:
+
+* Verifying a signed object requires access to the SHA-1 names of all
+  objects it references, even after the transition is complete and
+  translation table is no longer needed for anything else. To support
+  this, the design added fields such as "hash sha1 tree <SHA-1 name>"
+  and "hash sha1 parent <SHA-1 name>" to the SHA-256 content of a signed
+  commit, complicating the conversion process.
+* Allowing signed objects without a SHA-1 (for after the transition is
+  complete) complicated the design further, requiring a "nohash sha1"
+  field to suppress including "hash sha1" fields in the SHA-256 content
+  and signed payload.
+
+Lazily populated translation table
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Some of the work of building the translation table could be deferred to
+push time, but that would significantly complicate and slow down pushes.
+Calculating the SHA-1 name at object creation time at the same time it is
+being streamed to disk and having its SHA-256 name calculated should be
+an acceptable cost.
+
+Document History
+----------------
+
+2017-03-03
+bmwill@xxxxxxxxxx, jonathantanmy@xxxxxxxxxx, jrnieder@xxxxxxxxx,
+sbeller@xxxxxxxxxx
+
+* Initial version sent to https://lore.kernel.org/git/20170304011251.GA26789@xxxxxxxxxxxxxxxxxxxxxxxxx
+
+2017-03-03 jrnieder@xxxxxxxxx
+Incorporated suggestions from jonathantanmy and sbeller:
+
+* Describe purpose of signed objects with each hash type
+* Redefine signed object verification using object content under the
+  first hash function
+
+2017-03-06 jrnieder@xxxxxxxxx
+
+* Use SHA3-256 instead of SHA2 (thanks, Linus and brian m. carlson).[1][2]
+* Make SHA3-based signatures a separate field, avoiding the need for
+  "hash" and "nohash" fields (thanks to peff[3]).
+* Add a sorting phase to fetch (thanks to Junio for noticing the need
+  for this).
+* Omit blobs from the topological sort during fetch (thanks to peff).
+* Discuss alternates, git notes, and git servers in the caveats
+  section (thanks to Junio Hamano, brian m. carlson[4], and Shawn
+  Pearce).
+* Clarify language throughout (thanks to various commenters,
+  especially Junio).
+
+2017-09-27 jrnieder@xxxxxxxxx, sbeller@xxxxxxxxxx
+
+* Use placeholder NewHash instead of SHA3-256
+* Describe criteria for picking a hash function.
+* Include a transition plan (thanks especially to Brandon Williams
+  for fleshing these ideas out)
+* Define the translation table (thanks, Shawn Pearce[5], Jonathan
+  Tan, and Masaya Suzuki)
+* Avoid loose object overhead by packing more aggressively in
+  "git gc --auto"
+
+Later history:
+
+* See the history of this file in git.git for the history of subsequent
+  edits. This document history is no longer being maintained as it
+  would now be superfluous to the commit log
+
+References:
+
+ [1] https://lore.kernel.org/git/CA+55aFzJtejiCjV0e43+9oR3QuJK2PiFiLQemytoLpyJWe6P9w@xxxxxxxxxxxxxx/
+ [2] https://lore.kernel.org/git/CA+55aFz+gkAsDZ24zmePQuEs1XPS9BP_s8O7Q4wQ7LV7X5-oDA@xxxxxxxxxxxxxx/
+ [3] https://lore.kernel.org/git/20170306084353.nrns455dvkdsfgo5@xxxxxxxxxxxxxxxxxxxxx/
+ [4] https://lore.kernel.org/git/20170304224936.rqqtkdvfjgyezsht@xxxxxxxxxxxxxxxxxxxxxxxxxx
+ [5] https://lore.kernel.org/git/CAJo=hJtoX9=AyLHHpUJS7fueV9ciZ_MNpnEPHUz8Whui6g9F0A@xxxxxxxxxxxxxx/
diff --git a/Documentation/technical/long-running-process-protocol.adoc b/Documentation/technical/long-running-process-protocol.adoc
new file mode 100644
index 0000000000..6f33654b42
--- /dev/null
+++ b/Documentation/technical/long-running-process-protocol.adoc
@@ -0,0 +1,50 @@
+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 linkgit:gitprotocol-common[5])
+over standard input and standard output.
+
+Handshake
+---------
+
+Git starts by sending a welcome message (for example,
+"git-filter-client"), a list of supported protocol version numbers, and
+a flush packet. Git expects to read the welcome message with "server"
+instead of "client" (for example, "git-filter-server"), exactly one
+protocol version number from the previously sent list, and a flush
+packet. All further communication will be based on the selected version.
+The remaining protocol description below documents "version=2". Please
+note that "version=42" in the example below does not exist and is only
+there to illustrate how the protocol would look like with more than one
+version.
+
+After the version negotiation Git sends a list of all capabilities that
+it supports and a flush packet. Git expects to read a list of desired
+capabilities, which must be a subset of the supported capabilities list,
+and a flush packet as response:
+------------------------
+packet:          git> git-filter-client
+packet:          git> version=2
+packet:          git> version=42
+packet:          git> 0000
+packet:          git< git-filter-server
+packet:          git< version=2
+packet:          git< 0000
+packet:          git> capability=clean
+packet:          git> capability=smudge
+packet:          git> capability=not-yet-invented
+packet:          git> 0000
+packet:          git< capability=clean
+packet:          git< capability=smudge
+packet:          git< 0000
+------------------------
+
+Shutdown
+--------
+
+Git will close
+the command pipe on exit. The filter is expected to detect EOF
+and exit gracefully on its own. Git will wait until the filter
+process has stopped.
diff --git a/Documentation/technical/meson.build b/Documentation/technical/meson.build
new file mode 100644
index 0000000000..3a65ee59b3
--- /dev/null
+++ b/Documentation/technical/meson.build
@@ -0,0 +1,67 @@
+api_docs = [
+  'api-error-handling.txt',
+  'api-merge.txt',
+  'api-parse-options.txt',
+  'api-simple-ipc.txt',
+  'api-trace2.txt',
+]
+
+articles = [
+  'bitmap-format.txt',
+  'build-systems.txt',
+  'bundle-uri.txt',
+  'commit-graph.txt',
+  'directory-rename-detection.txt',
+  'hash-function-transition.txt',
+  'long-running-process-protocol.txt',
+  'multi-pack-index.txt',
+  'packfile-uri.txt',
+  'pack-heuristics.txt',
+  'parallel-checkout.txt',
+  'partial-clone.txt',
+  'platform-support.txt',
+  'racy-git.txt',
+  'reftable.txt',
+  'remembering-renames.txt',
+  'repository-version.txt',
+  'rerere.txt',
+  'scalar.txt',
+  'send-pack-pipeline.txt',
+  'shallow.txt',
+  'sparse-checkout.txt',
+  'sparse-index.txt',
+  'trivial-merge.txt',
+  'unit-tests.txt',
+]
+
+api_index = custom_target(
+  command: [
+    shell,
+    meson.current_source_dir() / 'api-index.sh',
+    meson.current_source_dir(),
+    '@OUTPUT@',
+  ],
+  env: script_environment,
+  input: api_docs,
+  output: 'api-index.txt',
+)
+
+custom_target(
+  command: asciidoc_html_options,
+  input: api_index,
+  output: 'api-index.html',
+  depends: documentation_deps,
+  install: true,
+  install_dir: get_option('datadir') / 'doc/git-doc/technical',
+)
+
+foreach article : api_docs + articles
+  custom_target(
+    command: asciidoc_html_options,
+    input: article,
+    output: fs.stem(article) + '.html',
+    depends: documentation_deps,
+    install: true,
+    install_dir: get_option('datadir') / 'doc/git-doc/technical',
+  )
+endforeach
diff --git a/Documentation/technical/multi-pack-index.adoc b/Documentation/technical/multi-pack-index.adoc
new file mode 100644
index 0000000000..cc063b30be
--- /dev/null
+++ b/Documentation/technical/multi-pack-index.adoc
@@ -0,0 +1,203 @@
+Multi-Pack-Index (MIDX) Design Notes
+====================================
+
+The Git object directory contains a 'pack' directory containing
+packfiles (with suffix ".pack") and pack-indexes (with suffix
+".idx"). The pack-indexes provide a way to lookup objects and
+navigate to their offset within the pack, but these must come
+in pairs with the packfiles. This pairing depends on the file
+names, as the pack-index differs only in suffix with its pack-
+file. While the pack-indexes provide fast lookup per packfile,
+this performance degrades as the number of packfiles increases,
+because abbreviations need to inspect every packfile and we are
+more likely to have a miss on our most-recently-used packfile.
+For some large repositories, repacking into a single packfile
+is not feasible due to storage space or excessive repack times.
+
+The multi-pack-index (MIDX for short) stores a list of objects
+and their offsets into multiple packfiles. It contains:
+
+* A list of packfile names.
+* A sorted list of object IDs.
+* A list of metadata for the ith object ID including:
+** A value j referring to the jth packfile.
+** An offset within the jth packfile for the object.
+* If large offsets are required, we use another list of large
+  offsets similar to version 2 pack-indexes.
+- An optional list of objects in pseudo-pack order (used with MIDX bitmaps).
+
+Thus, we can provide O(log N) lookup time for any number
+of packfiles.
+
+Design Details
+--------------
+
+- The MIDX is stored in a file named 'multi-pack-index' in the
+  .git/objects/pack directory. This could be stored in the pack
+  directory of an alternate. It refers only to packfiles in that
+  same directory.
+
+- The core.multiPackIndex config setting must be on (which is the
+  default) to consume MIDX files.  Setting it to `false` prevents
+  Git from reading a MIDX file, even if one exists.
+
+- The file format includes parameters for the object ID hash
+  function, so a future change of hash algorithm does not require
+  a change in format.
+
+- The MIDX keeps only one record per object ID. If an object appears
+  in multiple packfiles, then the MIDX selects the copy in the
+  preferred packfile, otherwise selecting from the most-recently
+  modified packfile.
+
+- If there exist packfiles in the pack directory not registered in
+  the MIDX, then those packfiles are loaded into the `packed_git`
+  list and `packed_git_mru` cache.
+
+- The pack-indexes (.idx files) remain in the pack directory so we
+  can delete the MIDX file, set core.midx to false, or downgrade
+  without any loss of information.
+
+- The MIDX file format uses a chunk-based approach (similar to the
+  commit-graph file) that allows optional data to be added.
+
+Incremental multi-pack indexes
+------------------------------
+
+As repositories grow in size, it becomes more expensive to write a
+multi-pack index (MIDX) that includes all packfiles. To accommodate
+this, the "incremental multi-pack indexes" feature allows for combining
+a "chain" of multi-pack indexes.
+
+Each individual component of the chain need only contain a small number
+of packfiles. Appending to the chain does not invalidate earlier parts
+of the chain, so repositories can control how much time is spent
+updating the MIDX chain by determining the number of packs in each layer
+of the MIDX chain.
+
+=== Design state
+
+At present, the incremental multi-pack indexes feature is missing two
+important components:
+
+  - The ability to rewrite earlier portions of the MIDX chain (i.e., to
+    "compact" some collection of adjacent MIDX layers into a single
+    MIDX). At present the only supported way of shrinking a MIDX chain
+    is to rewrite the entire chain from scratch without the `--split`
+    flag.
++
+There are no fundamental limitations that stand in the way of being able
+to implement this feature. It is omitted from the initial implementation
+in order to reduce the complexity, but will be added later.
+
+  - Support for reachability bitmaps. The classic single MIDX
+    implementation does support reachability bitmaps (see the section
+    titled "multi-pack-index reverse indexes" in
+    linkgit:gitformat-pack[5] for more details).
++
+As above, there are no fundamental limitations that stand in the way of
+extending the incremental MIDX format to support reachability bitmaps.
+The design below specifically takes this into account, and support for
+reachability bitmaps will be added in a future patch series. It is
+omitted from the current implementation for the same reason as above.
++
+In brief, to support reachability bitmaps with the incremental MIDX
+feature, the concept of the pseudo-pack order is extended across each
+layer of the incremental MIDX chain to form a concatenated pseudo-pack
+order. This concatenation takes place in the same order as the chain
+itself (in other words, the concatenated pseudo-pack order for a chain
+`{$H1, $H2, $H3}` would be the pseudo-pack order for `$H1`, followed by
+the pseudo-pack order for `$H2`, followed by the pseudo-pack order for
+`$H3`).
++
+The layout will then be extended so that each layer of the incremental
+MIDX chain can write a `*.bitmap`. The objects in each layer's bitmap
+are offset by the number of objects in the previous layers of the chain.
+
+=== File layout
+
+Instead of storing a single `multi-pack-index` file (with an optional
+`.rev` and `.bitmap` extension) in `$GIT_DIR/objects/pack`, incremental
+MIDXs are stored in the following layout:
+
+----
+$GIT_DIR/objects/pack/multi-pack-index.d/
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-chain
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H1.midx
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H2.midx
+$GIT_DIR/objects/pack/multi-pack-index.d/multi-pack-index-$H3.midx
+----
+
+The `multi-pack-index-chain` file contains a list of the incremental
+MIDX files in the chain, in order. The above example shows a chain whose
+`multi-pack-index-chain` file would contain the following lines:
+
+----
+$H1
+$H2
+$H3
+----
+
+The `multi-pack-index-$H1.midx` file contains the first layer of the
+multi-pack-index chain. The `multi-pack-index-$H2.midx` file contains
+the second layer of the chain, and so on.
+
+When both an incremental- and non-incremental MIDX are present, the
+non-incremental MIDX is always read first.
+
+=== Object positions for incremental MIDXs
+
+In the original multi-pack-index design, we refer to objects via their
+lexicographic position (by object IDs) within the repository's singular
+multi-pack-index. In the incremental multi-pack-index design, we refer
+to objects via their index into a concatenated lexicographic ordering
+among each component in the MIDX chain.
+
+If `objects_nr()` is a function that returns the number of objects in a
+given MIDX layer, then the index of an object at lexicographic position
+`i` within, say, $H3 is defined as:
+
+----
+objects_nr($H2) + objects_nr($H1) + i
+----
+
+(in the C implementation, this is often computed as `i +
+m->num_objects_in_base`).
+
+Future Work
+-----------
+
+- The multi-pack-index allows many packfiles, especially in a context
+  where repacking is expensive (such as a very large repo), or
+  unexpected maintenance time is unacceptable (such as a high-demand
+  build machine). However, the multi-pack-index needs to be rewritten
+  in full every time. We can extend the format to be incremental, so
+  writes are fast. By storing a small "tip" multi-pack-index that
+  points to large "base" MIDX files, we can keep writes fast while
+  still reducing the number of binary searches required for object
+  lookups.
+
+- If the multi-pack-index is extended to store a "stable object order"
+  (a function Order(hash) = integer that is constant for a given hash,
+  even as the multi-pack-index is updated) then MIDX bitmaps could be
+  updated independently of the MIDX.
+
+- Packfiles can be marked as "special" using empty files that share
+  the initial name but replace ".pack" with ".keep" or ".promisor".
+  We can add an optional chunk of data to the multi-pack-index that
+  records flags of information about the packfiles. This allows new
+  states, such as 'repacked' or 'redeltified', that can help with
+  pack maintenance in a multi-pack environment. It may also be
+  helpful to organize packfiles by object type (commit, tree, blob,
+  etc.) and use this metadata to help that maintenance.
+
+Related Links
+-------------
+[0] https://bugs.chromium.org/p/git/issues/detail?id=6
+    Chromium work item for: Multi-Pack Index (MIDX)
+
+[1] https://lore.kernel.org/git/20180107181459.222909-1-dstolee@xxxxxxxxxxxxx/
+    An earlier RFC for the multi-pack-index feature
+
+[2] https://lore.kernel.org/git/alpine.DEB.2.20.1803091557510.23109@alexmv-linux/
+    Git Merge 2018 Contributor's summit notes (includes discussion of MIDX)
diff --git a/Documentation/technical/pack-heuristics.adoc b/Documentation/technical/pack-heuristics.adoc
new file mode 100644
index 0000000000..95a07db6e8
--- /dev/null
+++ b/Documentation/technical/pack-heuristics.adoc
@@ -0,0 +1,460 @@
+Concerning Git's Packing Heuristics
+===================================
+
+        Oh, here's a really stupid question:
+
+                  Where do I go
+               to learn the details
+	    of Git's packing heuristics?
+
+Be careful what you ask!
+
+Followers of the Git, please open the Git IRC Log and turn to
+February 10, 2006.
+
+It's a rare occasion, and we are joined by the King Git Himself,
+Linus Torvalds (linus).  Nathaniel Smith, (njs`), has the floor
+and seeks enlightenment.  Others are present, but silent.
+
+Let's listen in!
+
+    <njs`> Oh, here's a really stupid question -- where do I go to
+	learn the details of Git's packing heuristics?  google avails
+        me not, reading the source didn't help a lot, and wading
+        through the whole mailing list seems less efficient than any
+        of that.
+
+It is a bold start!  A plea for help combined with a simultaneous
+tri-part attack on some of the tried and true mainstays in the quest
+for enlightenment.  Brash accusations of google being useless. Hubris!
+Maligning the source.  Heresy!  Disdain for the mailing list archives.
+Woe.
+
+    <pasky> yes, the packing-related delta stuff is somewhat
+        mysterious even for me ;)
+
+Ah!  Modesty after all.
+
+    <linus> njs, I don't think the docs exist. That's something where
+	 I don't think anybody else than me even really got involved.
+	 Most of the rest of Git others have been busy with (especially
+	 Junio), but packing nobody touched after I did it.
+
+It's cryptic, yet vague.  Linus in style for sure.  Wise men
+interpret this as an apology.  A few argue it is merely a
+statement of fact.
+
+    <njs`> I guess the next step is "read the source again", but I
+        have to build up a certain level of gumption first :-)
+
+Indeed!  On both points.
+
+    <linus> The packing heuristic is actually really really simple.
+
+Bait...
+
+    <linus> But strange.
+
+And switch.  That ought to do it!
+
+    <linus> Remember: Git really doesn't follow files. So what it does is
+        - generate a list of all objects
+        - sort the list according to magic heuristics
+        - walk the list, using a sliding window, seeing if an object
+          can be diffed against another object in the window
+        - write out the list in recency order
+
+The traditional understatement:
+
+    <njs`> I suspect that what I'm missing is the precise definition of
+        the word "magic"
+
+The traditional insight:
+
+    <pasky> yes
+
+And Babel-like confusion flowed.
+
+    <njs`> oh, hmm, and I'm not sure what this sliding window means either
+
+    <pasky> iirc, it appeared to me to be just the sha1 of the object
+        when reading the code casually ...
+
+        ... which simply doesn't sound as a very good heuristics, though ;)
+
+    <njs`> .....and recency order.  okay, I think it's clear I didn't
+       even realize how much I wasn't realizing :-)
+
+Ah, grasshopper!  And thus the enlightenment begins anew.
+
+    <linus> The "magic" is actually in theory totally arbitrary.
+        ANY order will give you a working pack, but no, it's not
+	ordered by SHA-1.
+
+        Before talking about the ordering for the sliding delta
+        window, let's talk about the recency order. That's more
+        important in one way.
+
+    <njs`> Right, but if all you want is a working way to pack things
+        together, you could just use cat and save yourself some
+        trouble...
+
+Waaait for it....
+
+    <linus> The recency ordering (which is basically: put objects
+        _physically_ into the pack in the order that they are
+        "reachable" from the head) is important.
+
+    <njs`> okay
+
+    <linus> It's important because that's the thing that gives packs
+        good locality. It keeps the objects close to the head (whether
+        they are old or new, but they are _reachable_ from the head)
+        at the head of the pack. So packs actually have absolutely
+        _wonderful_ IO patterns.
+
+Read that again, because it is important.
+
+    <linus> But recency ordering is totally useless for deciding how
+        to actually generate the deltas, so the delta ordering is
+        something else.
+
+        The delta ordering is (wait for it):
+        - first sort by the "basename" of the object, as defined by
+          the name the object was _first_ reached through when
+          generating the object list
+        - within the same basename, sort by size of the object
+        - but always sort different types separately (commits first).
+
+        That's not exactly it, but it's very close.
+
+    <njs`> The "_first_ reached" thing is not too important, just you
+        need some way to break ties since the same objects may be
+        reachable many ways, yes?
+
+And as if to clarify:
+
+    <linus> The point is that it's all really just any random
+        heuristic, and the ordering is totally unimportant for
+        correctness, but it helps a lot if the heuristic gives
+        "clumping" for things that are likely to delta well against
+        each other.
+
+It is an important point, so secretly, I did my own research and have
+included my results below.  To be fair, it has changed some over time.
+And through the magic of Revisionistic History, I draw upon this entry
+from The Git IRC Logs on my father's birthday, March 1:
+
+    <gitster> The quote from the above linus should be rewritten a
+        bit (wait for it):
+        - first sort by type.  Different objects never delta with
+	  each other.
+        - then sort by filename/dirname.  hash of the basename
+          occupies the top BITS_PER_INT-DIR_BITS bits, and bottom
+          DIR_BITS are for the hash of leading path elements.
+        - then if we are doing "thin" pack, the objects we are _not_
+          going to pack but we know about are sorted earlier than
+          other objects.
+        - and finally sort by size, larger to smaller.
+
+In one swell-foop, clarification and obscurification!  Nonetheless,
+authoritative.  Cryptic, yet concise.  It even solicits notions of
+quotes from The Source Code.  Clearly, more study is needed.
+
+    <gitster> That's the sort order.  What this means is:
+        - we do not delta different object types.
+	- we prefer to delta the objects with the same full path, but
+          allow files with the same name from different directories.
+	- we always prefer to delta against objects we are not going
+          to send, if there are some.
+	- we prefer to delta against larger objects, so that we have
+          lots of removals.
+
+        The penultimate rule is for "thin" packs.  It is used when
+        the other side is known to have such objects.
+
+There it is again. "Thin" packs.  I'm thinking to myself, "What
+is a 'thin' pack?"  So I ask:
+
+    <jdl> What is a "thin" pack?
+
+    <gitster> Use of --objects-edge to rev-list as the upstream of
+        pack-objects.  The pack transfer protocol negotiates that.
+
+Woo hoo!  Cleared that _right_ up!
+
+    <gitster> There are two directions - push and fetch.
+
+There!  Did you see it?  It is not '"push" and "pull"'!  How often the
+confusion has started here.  So casually mentioned, too!
+
+    <gitster> For push, git-send-pack invokes git-receive-pack on the
+        other end.  The receive-pack says "I have up to these commits".
+        send-pack looks at them, and computes what are missing from
+        the other end.  So "thin" could be the default there.
+
+        In the other direction, fetch, git-fetch-pack and
+        git-clone-pack invokes git-upload-pack on the other end
+	(via ssh or by talking to the daemon).
+
+	There are two cases: fetch-pack with -k and clone-pack is one,
+        fetch-pack without -k is the other.  clone-pack and fetch-pack
+        with -k will keep the downloaded packfile without expanded, so
+        we do not use thin pack transfer.  Otherwise, the generated
+        pack will have delta without base object in the same pack.
+
+        But fetch-pack without -k will explode the received pack into
+        individual objects, so we automatically ask upload-pack to
+        give us a thin pack if upload-pack supports it.
+
+OK then.
+
+Uh.
+
+Let's return to the previous conversation still in progress.
+
+    <njs`> and "basename" means something like "the tail of end of
+        path of file objects and dir objects, as per basename(3), and
+        we just declare all commit and tag objects to have the same
+        basename" or something?
+
+Luckily, that too is a point that gitster clarified for us!
+
+If I might add, the trick is to make files that _might_ be similar be
+located close to each other in the hash buckets based on their file
+names.  It used to be that "foo/Makefile", "bar/baz/quux/Makefile" and
+"Makefile" all landed in the same bucket due to their common basename,
+"Makefile". However, now they land in "close" buckets.
+
+The algorithm allows not just for the _same_ bucket, but for _close_
+buckets to be considered delta candidates.  The rationale is
+essentially that files, like Makefiles, often have very similar
+content no matter what directory they live in.
+
+    <linus> I played around with different delta algorithms, and with
+        making the "delta window" bigger, but having too big of a
+        sliding window makes it very expensive to generate the pack:
+        you need to compare every object with a _ton_ of other objects.
+
+        There are a number of other trivial heuristics too, which
+        basically boil down to "don't bother even trying to delta this
+        pair" if we can tell before-hand that the delta isn't worth it
+        (due to size differences, where we can take a previous delta
+        result into account to decide that "ok, no point in trying
+        that one, it will be worse").
+
+        End result: packing is actually very size efficient. It's
+        somewhat CPU-wasteful, but on the other hand, since you're
+        really only supposed to do it maybe once a month (and you can
+        do it during the night), nobody really seems to care.
+
+Nice Engineering Touch, there.  Find when it doesn't matter, and
+proclaim it a non-issue.  Good style too!
+
+    <njs`> So, just to repeat to see if I'm following, we start by
+        getting a list of the objects we want to pack, we sort it by
+        this heuristic (basically lexicographically on the tuple
+        (type, basename, size)).
+
+        Then we walk through this list, and calculate a delta of
+        each object against the last n (tunable parameter) objects,
+        and pick the smallest of these deltas.
+
+Vastly simplified, but the essence is there!
+
+    <linus> Correct.
+
+    <njs`> And then once we have picked a delta or fulltext to
+        represent each object, we re-sort by recency, and write them
+        out in that order.
+
+    <linus> Yup. Some other small details:
+
+And of course there is the "Other Shoe" Factor too.
+
+    <linus> - We limit the delta depth to another magic value (right
+        now both the window and delta depth magic values are just "10")
+
+    <njs`> Hrm, my intuition is that you'd end up with really _bad_ IO
+        patterns, because the things you want are near by, but to
+        actually reconstruct them you may have to jump all over in
+        random ways.
+
+    <linus> - When we write out a delta, and we haven't yet written
+        out the object it is a delta against, we write out the base
+        object first.  And no, when we reconstruct them, we actually
+        get nice IO patterns, because:
+        - larger objects tend to be "more recent" (Linus' law: files grow)
+        - we actively try to generate deltas from a larger object to a
+          smaller one
+        - this means that the top-of-tree very seldom has deltas
+          (i.e. deltas in _practice_ are "backwards deltas")
+
+Again, we should reread that whole paragraph.  Not just because
+Linus has slipped Linus's Law in there on us, but because it is
+important.  Let's make sure we clarify some of the points here:
+
+    <njs`> So the point is just that in practice, delta order and
+        recency order match each other quite well.
+
+    <linus> Yes. There's another nice side to this (and yes, it was
+	designed that way ;):
+        - the reason we generate deltas against the larger object is
+	  actually a big space saver too!
+
+    <njs`> Hmm, but your last comment (if "we haven't yet written out
+        the object it is a delta against, we write out the base object
+        first"), seems like it would make these facts mostly
+        irrelevant because even if in practice you would not have to
+        wander around much, in fact you just brute-force say that in
+        the cases where you might have to wander, don't do that :-)
+
+    <linus> Yes and no. Notice the rule: we only write out the base
+        object first if the delta against it was more recent.  That
+        means that you can actually have deltas that refer to a base
+        object that is _not_ close to the delta object, but that only
+        happens when the delta is needed to generate an _old_ object.
+
+    <linus> See?
+
+Yeah, no.  I missed that on the first two or three readings myself.
+
+    <linus> This keeps the front of the pack dense. The front of the
+        pack never contains data that isn't relevant to a "recent"
+        object.  The size optimization comes from our use of xdelta
+        (but is true for many other delta algorithms): removing data
+        is cheaper (in size) than adding data.
+
+        When you remove data, you only need to say "copy bytes n--m".
+	In contrast, in a delta that _adds_ data, you have to say "add
+        these bytes: 'actual data goes here'"
+
+    *** njs` has quit: Read error: 104 (Connection reset by peer)
+
+    <linus> Uhhuh. I hope I didn't blow njs` mind.
+
+    *** njs` has joined channel #git
+
+    <pasky> :)
+
+The silent observers are amused.  Of course.
+
+And as if njs` was expected to be omniscient:
+
+    <linus> njs - did you miss anything?
+
+OK, I'll spell it out.  That's Geek Humor.  If njs` was not actually
+connected for a little bit there, how would he know if missed anything
+while he was disconnected?  He's a benevolent dictator with a sense of
+humor!  Well noted!
+
+    <njs`> Stupid router.  Or gremlins, or whatever.
+
+It's a cheap shot at Cisco.  Take 'em when you can.
+
+    <njs`> Yes and no. Notice the rule: we only write out the base
+        object first if the delta against it was more recent.
+
+        I'm getting lost in all these orders, let me re-read :-)
+	So the write-out order is from most recent to least recent?
+        (Conceivably it could be the opposite way too, I'm not sure if
+        we've said) though my connection back at home is logging, so I
+        can just read what you said there :-)
+
+And for those of you paying attention, the Omniscient Trick has just
+been detailed!
+
+    <linus> Yes, we always write out most recent first
+
+    <njs`> And, yeah, I got the part about deeper-in-history stuff
+        having worse IO characteristics, one sort of doesn't care.
+
+    <linus> With the caveat that if the "most recent" needs an older
+        object to delta against (hey, shrinking sometimes does
+        happen), we write out the old object with the delta.
+
+    <njs`> (if only it happened more...)
+
+    <linus> Anyway, the pack-file could easily be denser still, but
+	because it's used both for streaming (the Git protocol) and
+        for on-disk, it has a few pessimizations.
+
+Actually, it is a made-up word. But it is a made-up word being
+used as setup for a later optimization, which is a real word:
+
+    <linus> In particular, while the pack-file is then compressed,
+        it's compressed just one object at a time, so the actual
+        compression factor is less than it could be in theory. But it
+        means that it's all nice random-access with a simple index to
+        do "object name->location in packfile" translation.
+
+    <njs`> I'm assuming the real win for delta-ing large->small is
+        more homogeneous statistics for gzip to run over?
+
+        (You have to put the bytes in one place or another, but
+        putting them in a larger blob wins on compression)
+
+        Actually, what is the compression strategy -- each delta
+        individually gzipped, the whole file gzipped, somewhere in
+        between, no compression at all, ....?
+
+        Right.
+
+Reality IRC sets in.  For example:
+
+    <pasky> I'll read the rest in the morning, I really have to go
+        sleep or there's no hope whatsoever for me at the today's
+        exam... g'nite all.
+
+Heh.
+
+    <linus> pasky: g'nite
+
+    <njs`> pasky: 'luck
+
+    <linus> Right: large->small matters exactly because of compression
+        behaviour. If it was non-compressed, it probably wouldn't make
+        any difference.
+
+    <njs`> yeah
+
+    <linus> Anyway: I'm not even trying to claim that the pack-files
+        are perfect, but they do tend to have a nice balance of
+        density vs ease-of use.
+
+Gasp!  OK, saved.  That's a fair Engineering trade off.  Close call!
+In fact, Linus reflects on some Basic Engineering Fundamentals,
+design options, etc.
+
+    <linus> More importantly, they allow Git to still _conceptually_
+        never deal with deltas at all, and be a "whole object" store.
+
+        Which has some problems (we discussed bad huge-file
+	behaviour on the Git lists the other day), but it does mean
+	that the basic Git concepts are really really simple and
+        straightforward.
+
+        It's all been quite stable.
+
+        Which I think is very much a result of having very simple
+        basic ideas, so that there's never any confusion about what's
+        going on.
+
+        Bugs happen, but they are "simple" bugs. And bugs that
+        actually get some object store detail wrong are almost always
+        so obvious that they never go anywhere.
+
+    <njs`> Yeah.
+
+Nuff said.
+
+    <linus> Anyway.  I'm off for bed. It's not 6AM here, but I've got
+	 three kids, and have to get up early in the morning to send
+	 them off. I need my beauty sleep.
+
+    <njs`> :-)
+
+    <njs`> appreciate the infodump, I really was failing to find the
+	details on Git packs :-)
+
+And now you know the rest of the story.
diff --git a/Documentation/technical/packfile-uri.adoc b/Documentation/technical/packfile-uri.adoc
new file mode 100644
index 0000000000..9d453d4765
--- /dev/null
+++ b/Documentation/technical/packfile-uri.adoc
@@ -0,0 +1,82 @@
+Packfile URIs
+=============
+
+This feature allows servers to serve part of their packfile response as URIs.
+This allows server designs that improve scalability in bandwidth and CPU usage
+(for example, by serving some data through a CDN), and (in the future) provides
+some measure of resumability to clients.
+
+This feature is available only in protocol version 2.
+
+Protocol
+--------
+
+The server advertises the `packfile-uris` capability.
+
+If the client then communicates which protocols (HTTPS, etc.) it supports with
+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 linkgit:gitprotocol-v2[5] for the documentation of
+this section.
+
+Clients should then download and index all the given URIs (in addition to
+downloading and indexing the packfile given in the `packfile` section of the
+response) before performing the connectivity check.
+
+Server design
+-------------
+
+The server can be trivially made compatible with the proposed protocol by
+having it advertise `packfile-uris`, tolerating the client sending
+`packfile-uris`, and never sending any `packfile-uris` section. But we should
+include some sort of non-trivial implementation in the Minimum Viable Product,
+at least so that we can test the client.
+
+This is the implementation: a feature, marked experimental, that allows the
+server to be configured by one or more `uploadpack.blobPackfileUri=
+<object-hash> <pack-hash> <uri>` entries. Whenever the list of objects to be
+sent is assembled, all such blobs are excluded, replaced with URIs. As noted
+in "Future work" below, the server can evolve in the future to support
+excluding other objects (or other implementations of servers could be made
+that support excluding other objects) without needing a protocol change, so
+clients should not expect that packfiles downloaded in this way only contain
+single blobs.
+
+Client design
+-------------
+
+The client has a config variable `fetch.uriprotocols` that determines which
+protocols the end user is willing to use. By default, this is empty.
+
+When the client downloads the given URIs, it should store them with "keep"
+files, just like it does with the packfile in the `packfile` section. These
+additional "keep" files can only be removed after the refs have been updated -
+just like the "keep" file for the packfile in the `packfile` section.
+
+The division of work (initial fetch + additional URIs) introduces convenient
+points for resumption of an interrupted clone - such resumption can be done
+after the Minimum Viable Product (see "Future work").
+
+Future work
+-----------
+
+The protocol design allows some evolution of the server and client without any
+need for protocol changes, so only a small-scoped design is included here to
+form the MVP. For example, the following can be done:
+
+ * On the server, more sophisticated means of excluding objects (e.g. by
+   specifying a commit to represent that commit and all objects that it
+   references).
+ * On the client, resumption of clone. If a clone is interrupted, information
+   could be recorded in the repository's config and a "clone-resume" command
+   can resume the clone in progress. (Resumption of subsequent fetches is more
+   difficult because that must deal with the user wanting to use the repository
+   even after the fetch was interrupted.)
+
+There are some possible features that will require a change in protocol:
+
+ * Additional HTTP headers (e.g. authentication)
+ * Byte range support
+ * Different file formats referenced by URIs (e.g. raw object)
diff --git a/Documentation/technical/parallel-checkout.adoc b/Documentation/technical/parallel-checkout.adoc
new file mode 100644
index 0000000000..b4a144e5f4
--- /dev/null
+++ b/Documentation/technical/parallel-checkout.adoc
@@ -0,0 +1,270 @@
+Parallel Checkout Design Notes
+==============================
+
+The "Parallel Checkout" feature attempts to use multiple processes to
+parallelize the work of uncompressing the blobs, applying in-core
+filters, and writing the resulting contents to the working tree during a
+checkout operation. It can be used by all checkout-related commands,
+such as `clone`, `checkout`, `reset`, `sparse-checkout`, and others.
+
+These commands share the following basic structure:
+
+* Step 1: Read the current index file into memory.
+
+* Step 2: Modify the in-memory index based upon the command, and
+  temporarily mark all cache entries that need to be updated.
+
+* Step 3: Populate the working tree to match the new candidate index.
+  This includes iterating over all of the to-be-updated cache entries
+  and delete, create, or overwrite the associated files in the working
+  tree.
+
+* Step 4: Write the new index to disk.
+
+Step 3 is the focus of the "parallel checkout" effort described here.
+
+Sequential Implementation
+-------------------------
+
+For the purposes of discussion here, the current sequential
+implementation of Step 3 is divided in 3 parts, each one implemented in
+its own function:
+
+* Step 3a: `unpack-trees.c:check_updates()` contains a series of
+  sequential loops iterating over the `cache_entry`'s array. The main
+  loop in this function calls the Step 3b function for each of the
+  to-be-updated entries.
+
+* Step 3b: `entry.c:checkout_entry()` examines the existing working tree
+  for file conflicts, collisions, and unsaved changes. It removes files
+  and creates leading directories as necessary. It calls the Step 3c
+  function for each entry to be written.
+
+* Step 3c: `entry.c:write_entry()` loads the blob into memory, smudges
+  it if necessary, creates the file in the working tree, writes the
+  smudged contents, calls `fstat()` or `lstat()`, and updates the
+  associated `cache_entry` struct with the stat information gathered.
+
+It wouldn't be safe to perform Step 3b in parallel, as there could be
+race conditions between file creations and removals. Instead, the
+parallel checkout framework lets the sequential code handle Step 3b,
+and uses parallel workers to replace the sequential
+`entry.c:write_entry()` calls from Step 3c.
+
+Rejected Multi-Threaded Solution
+--------------------------------
+
+The most "straightforward" implementation would be to spread the set of
+to-be-updated cache entries across multiple threads. But due to the
+thread-unsafe functions in the object database code, we would have to use locks to
+coordinate the parallel operation. An early prototype of this solution
+showed that the multi-threaded checkout would bring performance
+improvements over the sequential code, but there was still too much lock
+contention. A `perf` profiling indicated that around 20% of the runtime
+during a local Linux clone (on an SSD) was spent in locking functions.
+For this reason this approach was rejected in favor of using multiple
+child processes, which led to better performance.
+
+Multi-Process Solution
+----------------------
+
+Parallel checkout alters the aforementioned Step 3 to use multiple
+`checkout--worker` background processes to distribute the work. The
+long-running worker processes are controlled by the foreground Git
+command using the existing run-command API.
+
+Overview
+~~~~~~~~
+
+Step 3b is only slightly altered; for each entry to be checked out, the
+main process performs the following steps:
+
+* M1: Check whether there is any untracked or unclean file in the
+  working tree which would be overwritten by this entry, and decide
+  whether to proceed (removing the file(s)) or not.
+
+* M2: Create the leading directories.
+
+* M3: Load the conversion attributes for the entry's path.
+
+* M4: Check, based on the entry's type and conversion attributes,
+  whether the entry is eligible for parallel checkout (more on this
+  later). If it is eligible, enqueue the entry and the loaded
+  attributes to later write the entry in parallel. If not, write the
+  entry right away, using the default sequential code.
+
+Note: we save the conversion attributes associated with each entry
+because the workers don't have access to the main process' index state,
+so they can't load the attributes by themselves (and the attributes are
+needed to properly smudge the entry). Additionally, this has a positive
+impact on performance as (1) we don't need to load the attributes twice
+and (2) the attributes machinery is optimized to handle paths in
+sequential order.
+
+After all entries have passed through the above steps, the main process
+checks if the number of enqueued entries is sufficient to spread among
+the workers. If not, it just writes them sequentially. Otherwise, it
+spawns the workers and distributes the queued entries uniformly in
+continuous chunks. This aims to minimize the chances of two workers
+writing to the same directory simultaneously, which could increase lock
+contention in the kernel.
+
+Then, for each assigned item, each worker:
+
+* W1: Checks if there is any non-directory file in the leading part of
+  the entry's path or if there already exists a file at the entry' path.
+  If so, mark the entry with `PC_ITEM_COLLIDED` and skip it (more on
+  this later).
+
+* W2: Creates the file (with O_CREAT and O_EXCL).
+
+* W3: Loads the blob into memory (inflating and delta reconstructing
+  it).
+
+* W4: Applies any required in-process filter, like end-of-line
+  conversion and re-encoding.
+
+* W5: Writes the result to the file descriptor opened at W2.
+
+* W6: Calls `fstat()` or `lstat()` on the just-written path, and sends
+  the result back to the main process, together with the end status of
+  the operation and the item's identification number.
+
+Note that, when possible, steps W3 to W5 are delegated to the streaming
+machinery, removing the need to keep the entire blob in memory.
+
+If the worker fails to read the blob or to write it to the working tree,
+it removes the created file to avoid leaving empty files behind. This is
+the *only* time a worker is allowed to remove a file.
+
+As mentioned earlier, it is the responsibility of the main process to
+remove any file that blocks the checkout operation (or abort if the
+removal(s) would cause data loss and the user didn't ask to `--force`).
+This is crucial to avoid race conditions and also to properly detect
+path collisions at Step W1.
+
+After the workers finish writing the items and sending back the required
+information, the main process handles the results in two steps:
+
+- First, it updates the in-memory index with the `lstat()` information
+  sent by the workers. (This must be done first as this information
+  might be required in the following step.)
+
+- Then it writes the items which collided on disk (i.e. items marked
+  with `PC_ITEM_COLLIDED`). More on this below.
+
+Path Collisions
+---------------
+
+Path collisions happen when two different paths correspond to the same
+entry in the file system. E.g. the paths 'a' and 'A' would collide in a
+case-insensitive file system.
+
+The sequential checkout deals with collisions in the same way that it
+deals with files that were already present in the working tree before
+checkout. Basically, it checks if the path that it wants to write
+already exists on disk, makes sure the existing file doesn't have
+unsaved data, and then overwrites it. (To be more pedantic: it deletes
+the existing file and creates the new one.) So, if there are multiple
+colliding files to be checked out, the sequential code will write each
+one of them but only the last will actually survive on disk.
+
+Parallel checkout aims to reproduce the same behavior. However, we
+cannot let the workers racily write to the same file on disk. Instead,
+the workers detect when the entry that they want to check out would
+collide with an existing file, and mark it with `PC_ITEM_COLLIDED`.
+Later, the main process can sequentially feed these entries back to
+`checkout_entry()` without the risk of race conditions. On clone, this
+also has the effect of marking the colliding entries to later emit a
+warning for the user, like the classic sequential checkout does.
+
+The workers are able to detect both collisions among the entries being
+concurrently written and collisions between a parallel-eligible entry
+and an ineligible entry. The general idea for collision detection is
+quite straightforward: for each parallel-eligible entry, the main
+process must remove all files that prevent this entry from being written
+(before enqueueing it). This includes any non-directory file in the
+leading path of the entry. Later, when a worker gets assigned the entry,
+it looks again for the non-directory files and for an already existing
+file at the entry's path. If any of these checks finds something, the
+worker knows that there was a path collision.
+
+Because parallel checkout can distinguish path collisions from the case
+where the file was already present in the working tree before checkout,
+we could alternatively choose to skip the checkout of colliding entries.
+However, each entry that doesn't get written would have NULL `lstat()`
+fields on the index. This could cause performance penalties for
+subsequent commands that need to refresh the index, as they would have
+to go to the file system to see if the entry is dirty. Thus, if we have
+N entries in a colliding group and we decide to write and `lstat()` only
+one of them, every subsequent `git-status` will have to read, convert,
+and hash the written file N - 1 times. By checking out all colliding
+entries (like the sequential code does), we only pay the overhead once,
+during checkout.
+
+Eligible Entries for Parallel Checkout
+--------------------------------------
+
+As previously mentioned, not all entries passed to `checkout_entry()`
+will be considered eligible for parallel checkout. More specifically, we
+exclude:
+
+- Symbolic links; to avoid race conditions that, in combination with
+  path collisions, could cause workers to write files at the wrong
+  place. For example, if we were to concurrently check out a symlink
+  'a' -> 'b' and a regular file 'A/f' in a case-insensitive file system,
+  we could potentially end up writing the file 'A/f' at 'a/f', due to a
+  race condition.
+
+- Regular files that require external filters (either "one shot" filters
+  or long-running process filters). These filters are black-boxes to Git
+  and may have their own internal locking or non-concurrent assumptions.
+  So it might not be safe to run multiple instances in parallel.
++
+Besides, long-running filters may use the delayed checkout feature to
+postpone the return of some filtered blobs. The delayed checkout queue
+and the parallel checkout queue are not compatible and should remain
+separate.
++
+Note: regular files that only require internal filters, like end-of-line
+conversion and re-encoding, are eligible for parallel checkout.
+
+Ineligible entries are checked out by the classic sequential codepath
+*before* spawning workers.
+
+Note: submodules' files are also eligible for parallel checkout (as
+long as they don't fall into any of the excluding categories mentioned
+above). But since each submodule is checked out in its own child
+process, we don't mix the superproject's and the submodules' files in
+the same parallel checkout process or queue.
+
+The API
+-------
+
+The parallel checkout API was designed with the goal of minimizing
+changes to the current users of the checkout machinery. This means that
+they don't have to call a different function for sequential or parallel
+checkout. As already mentioned, `checkout_entry()` will automatically
+insert the given entry in the parallel checkout queue when this feature
+is enabled and the entry is eligible; otherwise, it will just write the
+entry right away, using the sequential code. In general, callers of the
+parallel checkout API should look similar to this:
+
+----------------------------------------------
+int pc_workers, pc_threshold, err = 0;
+struct checkout state;
+
+get_parallel_checkout_configs(&pc_workers, &pc_threshold);
+
+/*
+ * This check is not strictly required, but it
+ * should save some time in sequential mode.
+ */
+if (pc_workers > 1)
+	init_parallel_checkout();
+
+for (each cache_entry ce to-be-updated)
+	err |= checkout_entry(ce, &state, NULL, NULL);
+
+err |= run_parallel_checkout(&state, pc_workers, pc_threshold, NULL, NULL);
+----------------------------------------------
diff --git a/Documentation/technical/partial-clone.adoc b/Documentation/technical/partial-clone.adoc
new file mode 100644
index 0000000000..bf5ec5c82d
--- /dev/null
+++ b/Documentation/technical/partial-clone.adoc
@@ -0,0 +1,367 @@
+Partial Clone Design Notes
+==========================
+
+The "Partial Clone" feature is a performance optimization for Git that
+allows Git to function without having a complete copy of the repository.
+The goal of this work is to allow Git to better handle extremely large
+repositories.
+
+During clone and fetch operations, Git downloads the complete contents
+and history of the repository.  This includes all commits, trees, and
+blobs for the complete life of the repository.  For extremely large
+repositories, clones can take hours (or days) and consume 100+GiB of disk
+space.
+
+Often in these repositories there are many blobs and trees that the user
+does not need such as:
+
+  1. files outside of the user's work area in the tree.  For example, in
+     a repository with 500K directories and 3.5M files in every commit,
+     we can avoid downloading many objects if the user only needs a
+     narrow "cone" of the source tree.
+
+  2. large binary assets.  For example, in a repository where large build
+     artifacts are checked into the tree, we can avoid downloading all
+     previous versions of these non-mergeable binary assets and only
+     download versions that are actually referenced.
+
+Partial clone allows us to avoid downloading such unneeded objects *in
+advance* during clone and fetch operations and thereby reduce download
+times and disk usage.  Missing objects can later be "demand fetched"
+if/when needed.
+
+A remote that can later provide the missing objects is called a
+promisor remote, as it promises to send the objects when
+requested. Initially Git supported only one promisor remote, the origin
+remote from which the user cloned and that was configured in the
+"extensions.partialClone" config option. Later support for more than
+one promisor remote has been implemented.
+
+Use of partial clone requires that the user be online and the origin
+remote or other promisor remotes be available for on-demand fetching
+of missing objects.  This may or may not be problematic for the user.
+For example, if the user can stay within the pre-selected subset of
+the source tree, they may not encounter any missing objects.
+Alternatively, the user could try to pre-fetch various objects if they
+know that they are going offline.
+
+
+Non-Goals
+---------
+
+Partial clone is a mechanism to limit the number of blobs and trees downloaded
+*within* a given range of commits -- and is therefore independent of and not
+intended to conflict with existing DAG-level mechanisms to limit the set of
+requested commits (i.e. shallow clone, single branch, or fetch '<refspec>').
+
+
+Design Overview
+---------------
+
+Partial clone logically consists of the following parts:
+
+- A mechanism for the client to describe unneeded or unwanted objects to
+  the server.
+
+- A mechanism for the server to omit such unwanted objects from packfiles
+  sent to the client.
+
+- A mechanism for the client to gracefully handle missing objects (that
+  were previously omitted by the server).
+
+- A mechanism for the client to backfill missing objects as needed.
+
+
+Design Details
+--------------
+
+- A new pack-protocol capability "filter" is added to the fetch-pack and
+  upload-pack negotiation.
++
+This uses the existing capability discovery mechanism.
+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.
++
+There are various filters available to accommodate different situations.
+See "--filter=<filter-spec>" in Documentation/rev-list-options.txt.
+
+- On the server pack-objects applies the requested filter-spec as it
+  creates "filtered" packfiles for the client.
++
+These filtered packfiles are *incomplete* in the traditional sense because
+they may contain objects that reference objects not contained in the
+packfile and that the client doesn't already have.  For example, the
+filtered packfile may contain trees or tags that reference missing blobs
+or commits that reference missing trees.
+
+- On the client these incomplete packfiles are marked as "promisor packfiles"
+  and treated differently by various commands.
+
+- On the client a repository extension is added to the local config to
+  prevent older versions of git from failing mid-operation because of
+  missing objects that they cannot handle.
+  See `extensions.partialClone` in linkgit:git-config[1].
+
+
+Handling Missing Objects
+------------------------
+
+- An object may be missing due to a partial clone or fetch, or missing
+  due to repository corruption.  To differentiate these cases, the
+  local repository specially indicates such filtered packfiles
+  obtained from promisor remotes as "promisor packfiles".
++
+These promisor packfiles consist of a "<name>.promisor" file with
+arbitrary contents (like the "<name>.keep" files), in addition to
+their "<name>.pack" and "<name>.idx" files.
+
+- The local repository considers a "promisor object" to be an object that
+  it knows (to the best of its ability) that promisor remotes have promised
+  that they have, either because the local repository has that object in one of
+  its promisor packfiles, or because another promisor object refers to it.
++
+When Git encounters a missing object, Git can see if it is a promisor object
+and handle it appropriately.  If not, Git can report a corruption.
++
+This means that there is no need for the client to explicitly maintain an
+expensive-to-modify list of missing objects.[a]
+
+- Since almost all Git code currently expects any referenced object to be
+  present locally and because we do not want to force every command to do
+  a dry-run first, a fallback mechanism is added to allow Git to attempt
+  to dynamically fetch missing objects from promisor remotes.
++
+When the normal object lookup fails to find an object, Git invokes
+promisor_remote_get_direct() to try to get the object from a promisor
+remote and then retry the object lookup.  This allows objects to be
+"faulted in" without complicated prediction algorithms.
++
+For efficiency reasons, no check as to whether the missing object is
+actually a promisor object is performed.
++
+Dynamic object fetching tends to be slow as objects are fetched one at
+a time.
+
+- `checkout` (and any other command using `unpack-trees`) has been taught
+  to bulk pre-fetch all required missing blobs in a single batch.
+
+- `rev-list` has been taught to print missing objects.
++
+This can be used by other commands to bulk prefetch objects.
+For example, a "git log -p A..B" may internally want to first do
+something like "git rev-list --objects --quiet --missing=print A..B"
+and prefetch those objects in bulk.
+
+- `fsck` has been updated to be fully aware of promisor objects.
+
+- `repack` in GC has been updated to not touch promisor packfiles at all,
+  and to only repack other objects.
+
+- The global variable "fetch_if_missing" is used to control whether an
+  object lookup will attempt to dynamically fetch a missing object or
+  report an error.
++
+We are not happy with this global variable and would like to remove it,
+but that requires significant refactoring of the object code to pass an
+additional flag.
+
+
+Fetching Missing Objects
+------------------------
+
+- Fetching of objects is done by invoking a "git fetch" subprocess.
+
+- The local repository sends a request with the hashes of all requested
+  objects, and does not perform any packfile negotiation.
+  It then receives a packfile.
+
+- Because we are reusing the existing fetch mechanism, fetching
+  currently fetches all objects referred to by the requested objects, even
+  though they are not necessary.
+
+- Fetching with `--refetch` will request a complete new filtered packfile from
+  the remote, which can be used to change a filter without needing to
+  dynamically fetch missing objects.
+
+Using many promisor remotes
+---------------------------
+
+Many promisor remotes can be configured and used.
+
+This allows for example a user to have multiple geographically-close
+cache servers for fetching missing blobs while continuing to do
+filtered `git-fetch` commands from the central server.
+
+When fetching objects, promisor remotes are tried one after the other
+until all the objects have been fetched.
+
+Remotes that are considered "promisor" remotes are those specified by
+the following configuration variables:
+
+- `extensions.partialClone = <name>`
+
+- `remote.<name>.promisor = true`
+
+- `remote.<name>.partialCloneFilter = ...`
+
+Only one promisor remote can be configured using the
+`extensions.partialClone` config variable. This promisor remote will
+be the last one tried when fetching objects.
+
+We decided to make it the last one we try, because it is likely that
+someone using many promisor remotes is doing so because the other
+promisor remotes are better for some reason (maybe they are closer or
+faster for some kind of objects) than the origin, and the origin is
+likely to be the remote specified by extensions.partialClone.
+
+This justification is not very strong, but one choice had to be made,
+and anyway the long term plan should be to make the order somehow
+fully configurable.
+
+For now though the other promisor remotes will be tried in the order
+they appear in the config file.
+
+Current Limitations
+-------------------
+
+- It is not possible to specify the order in which the promisor
+  remotes are tried in other ways than the order in which they appear
+  in the config file.
++
+It is also not possible to specify an order to be used when fetching
+from one remote and a different order when fetching from another
+remote.
+
+- It is not possible to push only specific objects to a promisor
+  remote.
++
+It is not possible to push at the same time to multiple promisor
+remote in a specific order.
+
+- Dynamic object fetching will only ask promisor remotes for missing
+  objects.  We assume that promisor remotes have a complete view of the
+  repository and can satisfy all such requests.
+
+- Repack essentially treats promisor and non-promisor packfiles as 2
+  distinct partitions and does not mix them.
+
+- Dynamic object fetching invokes fetch-pack once *for each item*
+  because most algorithms stumble upon a missing object and need to have
+  it resolved before continuing their work.  This may incur significant
+  overhead -- and multiple authentication requests -- if many objects are
+  needed.
+
+- Dynamic object fetching currently uses the existing pack protocol V0
+  which means that each object is requested via fetch-pack.  The server
+  will send a full set of info/refs when the connection is established.
+  If there are a large number of refs, this may incur significant overhead.
+
+
+Future Work
+-----------
+
+- Improve the way to specify the order in which promisor remotes are
+  tried.
++
+For example this could allow specifying explicitly something like:
+"When fetching from this remote, I want to use these promisor remotes
+in this order, though, when pushing or fetching to that remote, I want
+to use those promisor remotes in that order."
+
+- Allow pushing to promisor remotes.
++
+The user might want to work in a triangular work flow with multiple
+promisor remotes that each have an incomplete view of the repository.
+
+- Allow non-pathname-based filters to make use of packfile bitmaps (when
+  present).  This was just an omission during the initial implementation.
+
+- Investigate use of a long-running process to dynamically fetch a series
+  of objects, such as proposed in [5,6] to reduce process startup and
+  overhead costs.
++
+It would be nice if pack protocol V2 could allow that long-running
+process to make a series of requests over a single long-running
+connection.
+
+- Investigate pack protocol V2 to avoid the info/refs broadcast on
+  each connection with the server to dynamically fetch missing objects.
+
+- Investigate the need to handle loose promisor objects.
++
+Objects in promisor packfiles are allowed to reference missing objects
+that can be dynamically fetched from the server.  An assumption was
+made that loose objects are only created locally and therefore should
+not reference a missing object.  We may need to revisit that assumption
+if, for example, we dynamically fetch a missing tree and store it as a
+loose object rather than a single object packfile.
++
+This does not necessarily mean we need to mark loose objects as promisor;
+it may be sufficient to relax the object lookup or is-promisor functions.
+
+
+Non-Tasks
+---------
+
+- Every time the subject of "demand loading blobs" comes up it seems
+  that someone suggests that the server be allowed to "guess" and send
+  additional objects that may be related to the requested objects.
++
+No work has gone into actually doing that; we're just documenting that
+it is a common suggestion.  We're not sure how it would work and have
+no plans to work on it.
++
+It is valid for the server to send more objects than requested (even
+for a dynamic object fetch), but we are not building on that.
+
+
+Footnotes
+---------
+
+[a] expensive-to-modify list of missing objects:  Earlier in the design of
+    partial clone we discussed the need for a single list of missing objects.
+    This would essentially be a sorted linear list of OIDs that were
+    omitted by the server during a clone or subsequent fetches.
+
+This file would need to be loaded into memory on every object lookup.
+It would need to be read, updated, and re-written (like the .git/index)
+on every explicit "git fetch" command *and* on any dynamic object fetch.
+
+The cost to read, update, and write this file could add significant
+overhead to every command if there are many missing objects.  For example,
+if there are 100M missing blobs, this file would be at least 2GiB on disk.
+
+With the "promisor" concept, we *infer* a missing object based upon the
+type of packfile that references it.
+
+
+Related Links
+-------------
+[0] https://crbug.com/git/2
+    Bug#2: Partial Clone
+
+[1] https://lore.kernel.org/git/20170113155253.1644-1-benpeart@xxxxxxxxxxxxx/ +
+    Subject: [RFC] Add support for downloading blobs on demand +
+    Date: Fri, 13 Jan 2017 10:52:53 -0500
+
+[2] https://lore.kernel.org/git/cover.1506714999.git.jonathantanmy@xxxxxxxxxx/ +
+    Subject: [PATCH 00/18] Partial clone (from clone to lazy fetch in 18 patches) +
+    Date: Fri, 29 Sep 2017 13:11:36 -0700
+
+[3] https://lore.kernel.org/git/20170426221346.25337-1-jonathantanmy@xxxxxxxxxx/ +
+    Subject: Proposal for missing blob support in Git repos +
+    Date: Wed, 26 Apr 2017 15:13:46 -0700
+
+[4] https://lore.kernel.org/git/1488999039-37631-1-git-send-email-git@xxxxxxxxxxxxxxxxx/ +
+    Subject: [PATCH 00/10] RFC Partial Clone and Fetch +
+    Date: Wed,  8 Mar 2017 18:50:29 +0000
+
+[5] https://lore.kernel.org/git/20170505152802.6724-1-benpeart@xxxxxxxxxxxxx/ +
+    Subject: [PATCH v7 00/10] refactor the filter process code into a reusable module +
+    Date: Fri,  5 May 2017 11:27:52 -0400
+
+[6] https://lore.kernel.org/git/20170714132651.170708-1-benpeart@xxxxxxxxxxxxx/ +
+    Subject: [RFC/PATCH v2 0/1] Add support for downloading blobs on demand +
+    Date: Fri, 14 Jul 2017 09:26:50 -0400
diff --git a/Documentation/technical/platform-support.adoc b/Documentation/technical/platform-support.adoc
new file mode 100644
index 0000000000..0a2fb28d62
--- /dev/null
+++ b/Documentation/technical/platform-support.adoc
@@ -0,0 +1,190 @@
+Platform Support Policy
+=======================
+
+Git has a history of providing broad "support" for exotic platforms and older
+platforms, without an explicit commitment. Stakeholders of these platforms may
+want a more predictable support commitment. This is only possible when platform
+stakeholders supply Git developers with adequate tooling, so we can test for
+compatibility or develop workarounds for platform-specific quirks on our own.
+Various levels of platform-specific tooling will allow us to make more solid
+commitments around Git's compatibility with that platform.
+
+Note that this document is about maintaining existing support for a platform
+that has generally worked in the past; for adding support to a platform which
+doesn't generally work with Git, the stakeholders for that platform are expected
+to do the bulk of that work themselves. We will consider such patches if they
+don't make life harder for other supported platforms or for Git contributors.
+Some contributors may volunteer to help with the initial or continued support,
+but that's not a given. Support work which is too intrusive or difficult for the
+project to maintain may still not be accepted.
+
+Minimum Requirements
+--------------------
+
+The rest of this doc describes best practices for platforms to make themselves
+easy to support. However, before considering support at all, platforms need to
+meet the following minimum requirements:
+
+* Has C99 or C11
+
+* Uses versions of dependencies which are generally accepted as stable and
+  supportable, e.g., in line with the version used by other long-term-support
+  distributions
+
+* Has active security support (taking security releases of dependencies, etc)
+
+These requirements are a starting point, and not sufficient on their own for the
+Git community to be enthusiastic about supporting your platform. Maintainers of
+platforms which do meet these requirements can follow the steps below to make it
+more likely that Git updates will respect the platform's needs.
+
+Compatible by next release
+--------------------------
+
+To increase probability that compatibility issues introduced in a release
+will be fixed in a later release:
+
+* You should send a bug report as soon as you notice the breakage on your
+  platform. The sooner you notice, the better; watching `seen` means you can
+  notice problems before they are considered "done with review"; whereas
+  watching `master` means the stable branch could break for your platform, but
+  you have a decent chance of avoiding a tagged release breaking you. See "The
+  Policy" in link:../howto/maintain-git.html["How to maintain Git"] for an
+  overview of which branches are used in the Git project, and how.
+
+* The bug report should include information about what platform you are using.
+
+* You should also use linkgit:git-bisect[1] and determine which commit
+  introduced the breakage.
+
+* Please include any information you have about the nature of the breakage: is
+  it a memory alignment issue? Is an underlying library missing or broken for
+  your platform? Is there some quirk about your platform which means typical
+  practices (like malloc) behave strangely?
+
+* If possible, build Git from the exact same source both for your platform and
+  for a mainstream platform, to see if the problem you noticed appears only
+  on your platform. If the problem appears in both, then it's not a
+  compatibility issue, but we of course appreciate hearing about it in a bug
+  report anyway, to benefit users of every platform. If it appears only on your
+  platform, mention clearly that it is a compatibility issue in your report.
+
+* Once we begin to fix the issue, please work closely with the contributor
+  working on it to test the proposed fix against your platform.
+
+Example: NonStop
+https://lore.kernel.org/git/01bd01da681a$b8d70a70$2a851f50$@nexbridge.com/[reports
+problems] when they're noticed.
+
+Compatible on `master` and releases
+-----------------------------------
+
+To make sure all stable builds and regular releases work for your platform the
+first time, help us avoid breaking `master` for your platform:
+
+* You should run regular tests against the `next` branch and
+  publish breakage reports to the mailing list immediately when they happen.
+
+** Ideally, these tests should run daily. They must run more often than
+   weekly, as topics generally spend at least 7 days in `next` before graduating
+   to `master`, and it takes time to put the brakes on a patch once it lands in
+   `next`.
+
+** You may want to ask to join the mailto:git-security@xxxxxxxxxxxxxxxx[security
+   mailing list] in order to run tests against the fixes proposed there, too.
+
+* It may make sense to automate these; if you do, make sure they are not noisy
+  (you don't need to send a report when everything works, only when something
+  breaks; you don't need to send repeated reports for the same breakage night
+  after night).
+
+* Breakage reports should be actionable - include clear error messages that can
+  help developers who may not have access to test directly on your platform.
+
+* You should use git-bisect and determine which commit introduced the breakage;
+  if you can't do this with automation, you should do this yourself manually as
+  soon as you notice a breakage report was sent.
+
+* You should either:
+
+** Provide on-demand access to your platform to a trusted developer working to
+   fix the issue, so they can test their fix, OR
+
+** Work closely with the developer fixing the issue; the turnaround to check
+   that their proposed fix works for your platform should be fast enough that it
+   doesn't hinder the developer working on that fix. Slow testing turnarounds
+   may cause the fix to miss the next release, or the developer may lose
+   interest in working on the fix at all.
+
+Example:
+https://lore.kernel.org/git/CAHd-oW6X4cwD_yLNFONPnXXUAFPxgDoccv2SOdpeLrqmHCJB4Q@xxxxxxxxxxxxxx/[AIX]
+provides a build farm and runs tests against release candidates.
+
+Compatible on `next`
+--------------------
+
+To avoid reactive debugging and fixing when changes hit a release or stable, you
+can aim to ensure `next` always works for your platform. (See "The Policy" in
+link:../howto/maintain-git.html["How to maintain Git"] for an overview of how
+`next` is used in the Git project.) To do that:
+
+* You should add a runner for your platform to the GitHub Actions or GitLab CI
+  suite.  This suite is run when any Git developer proposes a new patch, and
+  having a runner for your platform/configuration means every developer will
+  know if they break you, immediately.
+
+** If adding it to an existing CI suite is infeasible (due to architecture
+   constraints or for performance reasons), any other method which runs as
+   automatically and quickly as possible works, too. For example, a service
+   which snoops on the mailing list and automatically runs tests on new [PATCH]
+   emails, replying to the author with the results, would also be within the
+   spirit of this requirement.
+
+* If you rely on Git avoiding a specific pattern that doesn't work well with
+  your platform (like a certain malloc pattern), raise it on the mailing list.
+  We'll work case-by-case to look for a solution that doesn't unnecessarily
+  constrain other platforms to keep compatibility with yours.
+
+* If you rely on some configuration or behavior, add a test for it. Untested
+  behavior is subject to breakage at any time.
+
+** Clearly label these tests as necessary for platform compatibility. Add them
+   to an isolated compatibility-related test suite, like a new t* file or unit
+   test suite, so that they're easy to remove when compatibility is no longer
+   required.  If the specific compatibility need is gated behind an issue with
+   another project, link to documentation of that issue (like a bug or email
+   thread) to make it easier to tell when that compatibility need goes away.
+
+** Include a comment with an expiration date for these tests no more than 1 year
+   from now. You can update the expiration date if your platform still needs
+   that assurance down the road, but we need to know you still care about that
+   compatibility case and are working to make it unnecessary.
+
+Example: We run our
+https://git.kernel.org/pub/scm/git/git.git/tree/.github/workflows/main.yml[CI
+suite] on Windows, Ubuntu, Mac, and others.
+
+Getting help writing platform support patches
+---------------------------------------------
+
+In general, when sending patches to fix platform support problems, follow
+these guidelines to make sure the patch is reviewed with the appropriate level
+of urgency:
+
+* Clearly state in the commit message that you are fixing a platform breakage,
+  and for which platform.
+
+* Use the CI and test suite to ensure that the fix for your platform doesn't
+  break other platforms.
+
+* If possible, add a test ensuring this regression doesn't happen again. If
+  it's not possible to add a test, explain why in the commit message.
+
+Platform Maintainers
+--------------------
+
+If you maintain a platform, or Git for that platform, and intend to work with
+the Git project to ensure compatibility, please send a patch to add yourself to
+this list.
+
+NonStop: Randall S. Becker <rsbecker@xxxxxxxxxxxxx>
diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc
new file mode 100644
index 0000000000..59bea66c0f
--- /dev/null
+++ b/Documentation/technical/racy-git.adoc
@@ -0,0 +1,201 @@
+Use of index and Racy Git problem
+=================================
+
+Background
+----------
+
+The index is one of the most important data structures in Git.
+It represents a virtual working tree state by recording list of
+paths and their object names and serves as a staging area to
+write out the next tree object to be committed.  The state is
+"virtual" in the sense that it does not necessarily have to, and
+often does not, match the files in the working tree.
+
+There are cases where Git needs to examine the differences between the
+virtual working tree state in the index and the files in the
+working tree.  The most obvious case is when the user asks `git
+diff` (or its low level implementation, `git diff-files`) or
+`git-ls-files --modified`.  In addition, Git internally checks
+if the files in the working tree are different from what are
+recorded in the index to avoid stomping on local changes in them
+during patch application, switching branches, and merging.
+
+In order to speed up this comparison between the files in the
+working tree and the index entries, the index entries record the
+information obtained from the filesystem via `lstat(2)` system
+call when they were last updated.  When checking if they differ,
+Git first runs `lstat(2)` on the files and compares the result
+with this information (this is what was originally done by the
+`ce_match_stat()` function, but the current code does it in
+`ce_match_stat_basic()` function).  If some of these "cached
+stat information" fields do not match, Git can tell that the
+files are modified without even looking at their contents.
+
+Note: not all members in `struct stat` obtained via `lstat(2)`
+are used for this comparison.  For example, `st_atime` obviously
+is not useful.  Currently, Git compares the file type (regular
+files vs symbolic links) and executable bits (only for regular
+files) from `st_mode` member, `st_mtime` and `st_ctime`
+timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members.
+With a `USE_STDEV` compile-time option, `st_dev` is also
+compared, but this is not enabled by default because this member
+is not stable on network filesystems.  With `USE_NSEC`
+compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec`
+members are also compared. On Linux, this is not enabled by default
+because in-core timestamps can have finer granularity than
+on-disk timestamps, resulting in meaningless changes when an
+inode is evicted from the inode cache.  See commit 8ce13b0
+of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git
+([PATCH] Sync in core time granularity with filesystems,
+2005-01-04). This patch is included in kernel 2.6.11 and newer, but
+only fixes the issue for file systems with exactly 1 ns or 1 s
+resolution. Other file systems are still broken in current Linux
+kernels (e.g. CEPH, CIFS, NTFS, UDF), see
+https://lore.kernel.org/lkml/5577240D.7020309@xxxxxxxxx/
+
+Racy Git
+--------
+
+There is one slight problem with the optimization based on the
+cached stat information.  Consider this sequence:
+
+  : modify 'foo'
+  $ git update-index 'foo'
+  : modify 'foo' again, in-place, without changing its size
+
+The first `update-index` computes the object name of the
+contents of file `foo` and updates the index entry for `foo`
+along with the `struct stat` information.  If the modification
+that follows it happens very fast so that the file's `st_mtime`
+timestamp does not change, after this sequence, the cached stat
+information the index entry records still exactly match what you
+would see in the filesystem, even though the file `foo` is now
+different.
+This way, Git can incorrectly think files in the working tree
+are unmodified even though they actually are.  This is called
+the "racy Git" problem (discovered by Pasky), and the entries
+that appear clean when they may not be because of this problem
+are called "racily clean".
+
+To avoid this problem, Git does two things:
+
+. When the cached stat information says the file has not been
+  modified, and the `st_mtime` is the same as (or newer than)
+  the timestamp of the index file itself (which is the time `git
+  update-index foo` finished running in the above example), it
+  also compares the contents with the object registered in the
+  index entry to make sure they match.
+
+. When the index file is updated that contains racily clean
+  entries, cached `st_size` information is truncated to zero
+  before writing a new version of the index file.
+
+Because the index file itself is written after collecting all
+the stat information from updated paths, `st_mtime` timestamp of
+it is usually the same as or newer than any of the paths the
+index contains.  And no matter how quick the modification that
+follows `git update-index foo` finishes, the resulting
+`st_mtime` timestamp on `foo` cannot get a value earlier
+than the index file.  Therefore, index entries that can be
+racily clean are limited to the ones that have the same
+timestamp as the index file itself.
+
+The callers that want to check if an index entry matches the
+corresponding file in the working tree continue to call
+`ce_match_stat()`, but with this change, `ce_match_stat()` uses
+`ce_modified_check_fs()` to see if racily clean ones are
+actually clean after comparing the cached stat information using
+`ce_match_stat_basic()`.
+
+The problem the latter solves is this sequence:
+
+  $ git update-index 'foo'
+  : modify 'foo' in-place without changing its size
+  : wait for enough time
+  $ git update-index 'bar'
+
+Without the latter, the timestamp of the index file gets a newer
+value, and falsely clean entry `foo` would not be caught by the
+timestamp comparison check done with the former logic anymore.
+The latter makes sure that the cached stat information for `foo`
+would never match with the file in the working tree, so later
+checks by `ce_match_stat_basic()` would report that the index entry
+does not match the file and Git does not have to fall back on more
+expensive `ce_modified_check_fs()`.
+
+
+Runtime penalty
+---------------
+
+The runtime penalty of falling back to `ce_modified_check_fs()`
+from `ce_match_stat()` can be very expensive when there are many
+racily clean entries.  An obvious way to artificially create
+this situation is to give the same timestamp to all the files in
+the working tree in a large project, run `git update-index` on
+them, and give the same timestamp to the index file:
+
+  $ date >.datestamp
+  $ git ls-files | xargs touch -r .datestamp
+  $ git ls-files | git update-index --stdin
+  $ touch -r .datestamp .git/index
+
+This will make all index entries racily clean.  The linux project, for
+example, there are over 20,000 files in the working tree.  On my
+Athlon 64 X2 3800+, after the above:
+
+  $ /usr/bin/time git diff-files
+  1.68user 0.54system 0:02.22elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
+  0inputs+0outputs (0major+67111minor)pagefaults 0swaps
+  $ git update-index MAINTAINERS
+  $ /usr/bin/time git diff-files
+  0.02user 0.12system 0:00.14elapsed 100%CPU (0avgtext+0avgdata 0maxresident)k
+  0inputs+0outputs (0major+935minor)pagefaults 0swaps
+
+Running `git update-index` in the middle checked the racily
+clean entries, and left the cached `st_mtime` for all the paths
+intact because they were actually clean (so this step took about
+the same amount of time as the first `git diff-files`).  After
+that, they are not racily clean anymore but are truly clean, so
+the second invocation of `git diff-files` fully took advantage
+of the cached stat information.
+
+
+Avoiding runtime penalty
+------------------------
+
+In order to avoid the above runtime penalty, post 1.4.2 Git used
+to have a code that made sure the index file
+got a timestamp newer than the youngest files in the index when
+there were many young files with the same timestamp as the
+resulting index file otherwise would have by waiting
+before finishing writing the index file out.
+
+I suspected that in practice the situation where many paths in the
+index are all racily clean was quite rare.  The only code paths
+that can record recent timestamp for large number of paths are:
+
+. Initial `git add .` of a large project.
+
+. `git checkout` of a large project from an empty index into an
+  unpopulated working tree.
+
+Note: switching branches with `git checkout` keeps the cached
+stat information of existing working tree files that are the
+same between the current branch and the new branch, which are
+all older than the resulting index file, and they will not
+become racily clean.  Only the files that are actually checked
+out can become racily clean.
+
+In a large project where raciness avoidance cost really matters,
+however, the initial computation of all object names in the
+index takes more than one second, and the index file is written
+out after all that happens.  Therefore the timestamp of the
+index file will be more than one second later than the
+youngest file in the working tree.  This means that in these
+cases there actually will not be any racily clean entry in
+the resulting index.
+
+Based on this discussion, the current code does not use the
+"workaround" to avoid the runtime penalty that does not exist in
+practice anymore.  This was done with commit 0fc82cff on Aug 15,
+2006.
diff --git a/Documentation/technical/reftable.adoc b/Documentation/technical/reftable.adoc
new file mode 100644
index 0000000000..dd0b37c4e3
--- /dev/null
+++ b/Documentation/technical/reftable.adoc
@@ -0,0 +1,1098 @@
+reftable
+--------
+
+Overview
+~~~~~~~~
+
+Problem statement
+^^^^^^^^^^^^^^^^^
+
+Some repositories contain a lot of references (e.g. android at 866k,
+rails at 31k). The existing packed-refs format takes up a lot of space
+(e.g. 62M), and does not scale with additional references. Lookup of a
+single reference requires linearly scanning the file.
+
+Atomic pushes modifying multiple references require copying the entire
+packed-refs file, which can be a considerable amount of data moved
+(e.g. 62M in, 62M out) for even small transactions (2 refs modified).
+
+Repositories with many loose references occupy a large number of disk
+blocks from the local file system, as each reference is its own file
+storing 41 bytes (and another file for the corresponding reflog). This
+negatively affects the number of inodes available when a large number of
+repositories are stored on the same filesystem. Readers can be penalized
+due to the larger number of syscalls required to traverse and read the
+`$GIT_DIR/refs` directory.
+
+
+Objectives
+^^^^^^^^^^
+
+* Near constant time lookup for any single reference, even when the
+repository is cold and not in process or kernel cache.
+* Near constant time verification if an object name is referred to by at least
+one reference (for allow-tip-sha1-in-want).
+* Efficient enumeration of an entire namespace, such as `refs/tags/`.
+* Support atomic push with `O(size_of_update)` operations.
+* Combine reflog storage with ref storage for small transactions.
+* Separate reflog storage for base refs and historical logs.
+
+Description
+^^^^^^^^^^^
+
+A reftable file is a portable binary file format customized for
+reference storage. References are sorted, enabling linear scans, binary
+search lookup, and range scans.
+
+Storage in the file is organized into variable sized blocks. Prefix
+compression is used within a single block to reduce disk space. Block
+size and alignment are tunable by the writer.
+
+Performance
+^^^^^^^^^^^
+
+Space used, packed-refs vs. reftable:
+
+[cols=",>,>,>,>,>",options="header",]
+|===============================================================
+|repository |packed-refs |reftable |% original |avg ref |avg obj
+|android |62.2 M |36.1 M |58.0% |33 bytes |5 bytes
+|rails |1.8 M |1.1 M |57.7% |29 bytes |4 bytes
+|git |78.7 K |48.1 K |61.0% |50 bytes |4 bytes
+|git (heads) |332 b |269 b |81.0% |33 bytes |0 bytes
+|===============================================================
+
+Scan (read 866k refs), by reference name lookup (single ref from 866k
+refs), and by SHA-1 lookup (refs with that SHA-1, from 866k refs):
+
+[cols=",>,>,>,>",options="header",]
+|=========================================================
+|format |cache |scan |by name |by SHA-1
+|packed-refs |cold |402 ms |409,660.1 usec |412,535.8 usec
+|packed-refs |hot | |6,844.6 usec |20,110.1 usec
+|reftable |cold |112 ms |33.9 usec |323.2 usec
+|reftable |hot | |20.2 usec |320.8 usec
+|=========================================================
+
+Space used for 149,932 log entries for 43,061 refs, reflog vs. reftable:
+
+[cols=",>,>",options="header",]
+|================================
+|format |size |avg entry
+|$GIT_DIR/logs |173 M |1209 bytes
+|reftable |5 M |37 bytes
+|================================
+
+Details
+~~~~~~~
+
+Peeling
+^^^^^^^
+
+References stored in a reftable are peeled, a record for an annotated
+(or signed) tag records both the tag object, and the object it refers
+to. This is analogous to storage in the packed-refs format.
+
+Reference name encoding
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Reference names are an uninterpreted sequence of bytes that must pass
+linkgit:git-check-ref-format[1] as a valid reference name.
+
+Key unicity
+^^^^^^^^^^^
+
+Each entry must have a unique key; repeated keys are disallowed.
+
+Network byte order
+^^^^^^^^^^^^^^^^^^
+
+All multi-byte, fixed width fields are in network byte order.
+
+Varint encoding
+^^^^^^^^^^^^^^^
+
+Varint encoding is identical to the ofs-delta encoding method used
+within pack files.
+
+Decoder works as follows:
+
+....
+val = buf[ptr] & 0x7f
+while (buf[ptr] & 0x80) {
+  ptr++
+  val = ((val + 1) << 7) | (buf[ptr] & 0x7f)
+}
+....
+
+Ordering
+^^^^^^^^
+
+Blocks are lexicographically ordered by their first reference.
+
+Directory/file conflicts
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The reftable format accepts both `refs/heads/foo` and
+`refs/heads/foo/bar` as distinct references.
+
+This property is useful for retaining log records in reftable, but may
+confuse versions of Git using `$GIT_DIR/refs` directory tree to maintain
+references. Users of reftable may choose to continue to reject `foo` and
+`foo/bar` type conflicts to prevent problems for peers.
+
+File format
+~~~~~~~~~~~
+
+Structure
+^^^^^^^^^
+
+A reftable file has the following high-level structure:
+
+....
+first_block {
+  header
+  first_ref_block
+}
+ref_block*
+ref_index*
+obj_block*
+obj_index*
+log_block*
+log_index*
+footer
+....
+
+A log-only file omits the `ref_block`, `ref_index`, `obj_block` and
+`obj_index` sections, containing only the file header and log block:
+
+....
+first_block {
+  header
+}
+log_block*
+log_index*
+footer
+....
+
+In a log-only file, the first log block immediately follows the file
+header, without padding to block alignment.
+
+Block size
+^^^^^^^^^^
+
+The file's block size is arbitrarily determined by the writer, and does
+not have to be a power of 2. The block size must be larger than the
+longest reference name or log entry used in the repository, as
+references cannot span blocks.
+
+Powers of two that are friendly to the virtual memory system or
+filesystem (such as 4k or 8k) are recommended. Larger sizes (64k) can
+yield better compression, with a possible increased cost incurred by
+readers during access.
+
+The largest block size is `16777215` bytes (15.99 MiB).
+
+Block alignment
+^^^^^^^^^^^^^^^
+
+Writers may choose to align blocks at multiples of the block size by
+including `padding` filled with NUL bytes at the end of a block to round
+out to the chosen alignment. When alignment is used, writers must
+specify the alignment with the file header's `block_size` field.
+
+Block alignment is not required by the file format. Unaligned files must
+set `block_size = 0` in the file header, and omit `padding`. Unaligned
+files with more than one ref block must include the link:#Ref-index[ref
+index] to support fast lookup. Readers must be able to read both aligned
+and non-aligned files.
+
+Very small files (e.g. a single ref block) may omit `padding` and the ref
+index to reduce total file size.
+
+Header (version 1)
+^^^^^^^^^^^^^^^^^^
+
+A 24-byte header appears at the beginning of the file:
+
+....
+'REFT'
+uint8( version_number = 1 )
+uint24( block_size )
+uint64( min_update_index )
+uint64( max_update_index )
+....
+
+Aligned files must specify `block_size` to configure readers with the
+expected block alignment. Unaligned files must set `block_size = 0`.
+
+The `min_update_index` and `max_update_index` describe bounds for the
+`update_index` field of all log records in this file. When reftables are
+used in a stack for link:#Update-transactions[transactions], these
+fields can order the files such that the prior file's
+`max_update_index + 1` is the next file's `min_update_index`.
+
+Header (version 2)
+^^^^^^^^^^^^^^^^^^
+
+A 28-byte header appears at the beginning of the file:
+
+....
+'REFT'
+uint8( version_number = 2 )
+uint24( block_size )
+uint64( min_update_index )
+uint64( max_update_index )
+uint32( hash_id )
+....
+
+The header is identical to `version_number=1`, with the 4-byte hash ID
+("sha1" for SHA1 and "s256" for SHA-256) appended to the header.
+
+For maximum backward compatibility, it is recommended to use version 1 when
+writing SHA1 reftables.
+
+First ref block
+^^^^^^^^^^^^^^^
+
+The first ref block shares the same block as the file header, and is 24
+bytes smaller than all other blocks in the file. The first block
+immediately begins after the file header, at position 24.
+
+If the first block is a log block (a log-only file), its block header
+begins immediately at position 24.
+
+Ref block format
+^^^^^^^^^^^^^^^^
+
+A ref block is written as:
+
+....
+'r'
+uint24( block_len )
+ref_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+Blocks begin with `block_type = 'r'` and a 3-byte `block_len` which
+encodes the number of bytes in the block up to, but not including the
+optional `padding`. This is always less than or equal to the file's
+block size. In the first ref block, `block_len` includes 24 bytes for
+the file header.
+
+The 2-byte `restart_count` stores the number of entries in the
+`restart_offset` list, which must not be empty. Readers can use
+`restart_count` to binary search between restarts before starting a
+linear scan.
+
+Exactly `restart_count` 3-byte `restart_offset` values precede the
+`restart_count`. Offsets are relative to the start of the block and
+refer to the first byte of any `ref_record` whose name has not been
+prefix compressed. Entries in the `restart_offset` list must be sorted,
+ascending. Readers can start linear scans from any of these records.
+
+A variable number of `ref_record` fill the middle of the block,
+describing reference names and values. The format is described below.
+
+As the first ref block shares the first file block with the file header,
+all `restart_offset` in the first block are relative to the start of the
+file (position 0), and include the file header. This forces the first
+`restart_offset` to be `28`.
+
+ref record
+++++++++++
+
+A `ref_record` describes a single reference, storing both the name and
+its value(s). Records are formatted as:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | value_type )
+suffix
+varint( update_index_delta )
+value?
+....
+
+The `prefix_length` field specifies how many leading bytes of the prior
+reference record's name should be copied to obtain this reference's
+name. This must be 0 for the first reference in any block, and also must
+be 0 for any `ref_record` whose offset is listed in the `restart_offset`
+table at the end of the block.
+
+Recovering a reference name from any `ref_record` is a simple concat:
+
+....
+this_name = prior_name[0..prefix_length] + suffix
+....
+
+The `suffix_length` value provides the number of bytes available in
+`suffix` to copy from `suffix` to complete the reference name.
+
+The `update_index` that last modified the reference can be obtained by
+adding `update_index_delta` to the `min_update_index` from the file
+header: `min_update_index + update_index_delta`.
+
+The `value` follows. Its format is determined by `value_type`, one of
+the following:
+
+* `0x0`: deletion; no value data (see transactions, below)
+* `0x1`: one object name; value of the ref
+* `0x2`: two object names; value of the ref, peeled target
+* `0x3`: symbolic reference: `varint( target_len ) target`
+
+Symbolic references use `0x3`, followed by the complete name of the
+reference target. No compression is applied to the target name.
+
+Types `0x4..0x7` are reserved for future use.
+
+Ref index
+^^^^^^^^^
+
+The ref index stores the name of the last reference from every ref block
+in the file, enabling reduced disk seeks for lookups. Any reference can
+be found by searching the index, identifying the containing block, and
+searching within that block.
+
+The index may be organized into a multi-level index, where the 1st level
+index block points to additional ref index blocks (2nd level), which may
+in turn point to either additional index blocks (e.g. 3rd level) or ref
+blocks (leaf level). Disk reads required to access a ref go up with
+higher index levels. Multi-level indexes may be required to ensure no
+single index block exceeds the file format's max block size of
+`16777215` bytes (15.99 MiB). To achieve constant O(1) disk seeks for
+lookups the index must be a single level, which is permitted to exceed
+the file's configured block size, but not the format's max block size of
+15.99 MiB.
+
+If present, the ref index block(s) appears after the last ref block.
+
+If there are at least 4 ref blocks, a ref index block should be written
+to improve lookup times. Cold reads using the index require 2 disk reads
+(read index, read block), and binary searching < 4 blocks also requires
+<= 2 reads. Omitting the index block from smaller files saves space.
+
+If the file is unaligned and contains more than one ref block, the ref
+index must be written.
+
+Index block format:
+
+....
+'i'
+uint24( block_len )
+index_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+The index blocks begin with `block_type = 'i'` and a 3-byte `block_len`
+which encodes the number of bytes in the block, up to but not including
+the optional `padding`.
+
+The `restart_offset` and `restart_count` fields are identical in format,
+meaning and usage as in ref blocks.
+
+To reduce the number of reads required for random access in very large
+files the index block may be larger than other blocks. However, readers
+must hold the entire index in memory to benefit from this, so it's a
+time-space tradeoff in both file size and reader memory.
+
+Increasing the file's block size decreases the index size. Alternatively
+a multi-level index may be used, keeping index blocks within the file's
+block size, but increasing the number of blocks that need to be
+accessed.
+
+index record
+++++++++++++
+
+An index record describes the last entry in another block. Index records
+are written as:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | 0 )
+suffix
+varint( block_position )
+....
+
+Index records use prefix compression exactly like `ref_record`.
+
+Index records store `block_position` after the suffix, specifying the
+absolute position in bytes (from the start of the file) of the block
+that ends with this reference. Readers can seek to `block_position` to
+begin reading the block header.
+
+Readers must examine the block header at `block_position` to determine
+if the next block is another level index block, or the leaf-level ref
+block.
+
+Reading the index
++++++++++++++++++
+
+Readers loading the ref index must first read the footer (below) to
+obtain `ref_index_position`. If not present, the position will be 0. The
+`ref_index_position` is for the 1st level root of the ref index.
+
+Obj block format
+^^^^^^^^^^^^^^^^
+
+Object blocks are optional. Writers may choose to omit object blocks,
+especially if readers will not use the object name to ref mapping.
+
+Object blocks use unique, abbreviated 2-31 byte object name keys, mapping to
+ref blocks containing references pointing to that object directly, or as
+the peeled value of an annotated tag. Like ref blocks, object blocks use
+the file's standard block size. The abbreviation length is available in
+the footer as `obj_id_len`.
+
+To save space in small files, object blocks may be omitted if the ref
+index is not present, as brute force search will only need to read a few
+ref blocks. When missing, readers should brute force a linear search of
+all references to lookup by object name.
+
+An object block is written as:
+
+....
+'o'
+uint24( block_len )
+obj_record+
+uint24( restart_offset )+
+uint16( restart_count )
+
+padding?
+....
+
+Fields are identical to ref block. Binary search using the restart table
+works the same as in reference blocks.
+
+Because object names are abbreviated by writers to the shortest unique
+abbreviation within the reftable, obj key lengths have a variable length. Their
+length must be at least 2 bytes. Readers must compare only for common prefix
+match within an obj block or obj index.
+
+obj record
+++++++++++
+
+An `obj_record` describes a single object abbreviation, and the blocks
+containing references using that unique abbreviation:
+
+....
+varint( prefix_length )
+varint( (suffix_length << 3) | cnt_3 )
+suffix
+varint( cnt_large )?
+varint( position_delta )*
+....
+
+Like in reference blocks, abbreviations are prefix compressed within an
+obj block. On large reftables with many unique objects, higher block
+sizes (64k), and higher restart interval (128), a `prefix_length` of 2
+or 3 and `suffix_length` of 3 may be common in obj records (unique
+abbreviation of 5-6 raw bytes, 10-12 hex digits).
+
+Each record contains `position_count` number of positions for matching
+ref blocks. For 1-7 positions the count is stored in `cnt_3`. When
+`cnt_3 = 0` the actual count follows in a varint, `cnt_large`.
+
+The use of `cnt_3` bets most objects are pointed to by only a single
+reference, some may be pointed to by a couple of references, and very
+few (if any) are pointed to by more than 7 references.
+
+A special case exists when `cnt_3 = 0` and `cnt_large = 0`: there are no
+`position_delta`, but at least one reference starts with this
+abbreviation. A reader that needs exact reference names must scan all
+references to find which specific references have the desired object.
+Writers should use this format when the `position_delta` list would have
+overflowed the file's block size due to a high number of references
+pointing to the same object.
+
+The first `position_delta` is the position from the start of the file.
+Additional `position_delta` entries are sorted ascending and relative to
+the prior entry, e.g. a reader would perform:
+
+....
+pos = position_delta[0]
+prior = pos
+for (j = 1; j < position_count; j++) {
+  pos = prior + position_delta[j]
+  prior = pos
+}
+....
+
+With a position in hand, a reader must linearly scan the ref block,
+starting from the first `ref_record`, testing each reference's object names
+(for `value_type = 0x1` or `0x2`) for full equality. Faster searching by
+object name within a single ref block is not supported by the reftable format.
+Smaller block sizes reduce the number of candidates this step must
+consider.
+
+Obj index
+^^^^^^^^^
+
+The obj index stores the abbreviation from the last entry for every obj
+block in the file, enabling reduced disk seeks for all lookups. It is
+formatted exactly the same as the ref index, but refers to obj blocks.
+
+The obj index should be present if obj blocks are present, as obj blocks
+should only be written in larger files.
+
+Readers loading the obj index must first read the footer (below) to
+obtain `obj_index_position`. If not present, the position will be 0.
+
+Log block format
+^^^^^^^^^^^^^^^^
+
+Unlike ref and obj blocks, log blocks are always unaligned.
+
+Log blocks are variable in size, and do not match the `block_size`
+specified in the file header or footer. Writers should choose an
+appropriate buffer size to prepare a log block for deflation, such as
+`2 * block_size`.
+
+A log block is written as:
+
+....
+'g'
+uint24( block_len )
+zlib_deflate {
+  log_record+
+  uint24( restart_offset )+
+  uint16( restart_count )
+}
+....
+
+Log blocks look similar to ref blocks, except `block_type = 'g'`.
+
+The 4-byte block header is followed by the deflated block contents using
+zlib deflate. The `block_len` in the header is the inflated size
+(including 4-byte block header), and should be used by readers to
+preallocate the inflation output buffer. A log block's `block_len` may
+exceed the file's block size.
+
+Offsets within the log block (e.g. `restart_offset`) still include the
+4-byte header. Readers may prefer prefixing the inflation output buffer
+with the 4-byte header.
+
+Within the deflate container, a variable number of `log_record` describe
+reference changes. The log record format is described below. See ref
+block format (above) for a description of `restart_offset` and
+`restart_count`.
+
+Because log blocks have no alignment or padding between blocks, readers
+must keep track of the bytes consumed by the inflater to know where the
+next log block begins.
+
+log record
+++++++++++
+
+Log record keys are structured as:
+
+....
+ref_name '\0' reverse_int64( update_index )
+....
+
+where `update_index` is the unique transaction identifier. The
+`update_index` field must be unique within the scope of a `ref_name`.
+See the update transactions section below for further details.
+
+The `reverse_int64` function inverses the value so lexicographical
+ordering the network byte order encoding sorts the more recent records
+with higher `update_index` values first:
+
+....
+reverse_int64(int64 t) {
+  return 0xffffffffffffffff - t;
+}
+....
+
+Log records have a similar starting structure to ref and index records,
+utilizing the same prefix compression scheme applied to the log record
+key described above.
+
+....
+    varint( prefix_length )
+    varint( (suffix_length << 3) | log_type )
+    suffix
+    log_data {
+      old_id
+      new_id
+      varint( name_length    )  name
+      varint( email_length   )  email
+      varint( time_seconds )
+      sint16( tz_offset )
+      varint( message_length )  message
+    }?
+....
+
+Log record entries use `log_type` to indicate what follows:
+
+* `0x0`: deletion; no log data.
+* `0x1`: standard git reflog data using `log_data` above.
+
+The `log_type = 0x0` is mostly useful for `git stash drop`, removing an
+entry from the reflog of `refs/stash` in a transaction file (below),
+without needing to rewrite larger files. Readers reading a stack of
+reflogs must treat this as a deletion.
+
+For `log_type = 0x1`, the `log_data` section follows
+linkgit:git-update-ref[1] logging and includes:
+
+* two object names (old id, new id)
+* varint string of committer's name
+* varint string of committer's email
+* varint time in seconds since epoch (Jan 1, 1970)
+* 2-byte timezone offset in minutes (signed)
+* varint string of message
+
+`tz_offset` is the absolute number of minutes from GMT the committer was
+at the time of the update. For example `GMT-0800` is encoded in reftable
+as `sint16(-480)` and `GMT+0230` is `sint16(150)`.
+
+The committer email does not contain `<` or `>`, it's the value normally
+found between the `<>` in a git commit object header.
+
+The `message_length` may be 0, in which case there was no message
+supplied for the update.
+
+Contrary to traditional reflog (which is a file), renames are encoded as
+a combination of ref deletion and ref creation.  A deletion is a log
+record with a zero new_id, and a creation is a log record with a zero old_id.
+
+Reading the log
++++++++++++++++
+
+Readers accessing the log must first read the footer (below) to
+determine the `log_position`. The first block of the log begins at
+`log_position` bytes since the start of the file. The `log_position` is
+not block aligned.
+
+Importing logs
+++++++++++++++
+
+When importing from `$GIT_DIR/logs` writers should globally order all
+log records roughly by timestamp while preserving file order, and assign
+unique, increasing `update_index` values for each log line. Newer log
+records get higher `update_index` values.
+
+Although an import may write only a single reftable file, the reftable
+file must span many unique `update_index`, as each log line requires its
+own `update_index` to preserve semantics.
+
+Log index
+^^^^^^^^^
+
+The log index stores the log key
+(`refname \0 reverse_int64(update_index)`) for the last log record of
+every log block in the file, supporting bounded-time lookup.
+
+A log index block must be written if 2 or more log blocks are written to
+the file. If present, the log index appears after the last log block.
+There is no padding used to align the log index to block alignment.
+
+Log index format is identical to ref index, except the keys are 9 bytes
+longer to include `'\0'` and the 8-byte `reverse_int64(update_index)`.
+Records use `block_position` to refer to the start of a log block.
+
+Reading the index
++++++++++++++++++
+
+Readers loading the log index must first read the footer (below) to
+obtain `log_index_position`. If not present, the position will be 0.
+
+Footer
+^^^^^^
+
+After the last block of the file, a file footer is written. It begins
+like the file header, but is extended with additional data.
+
+....
+    HEADER
+
+    uint64( ref_index_position )
+    uint64( (obj_position << 5) | obj_id_len )
+    uint64( obj_index_position )
+
+    uint64( log_position )
+    uint64( log_index_position )
+
+    uint32( CRC-32 of above )
+....
+
+If a section is missing (e.g. ref index) the corresponding position
+field (e.g. `ref_index_position`) will be 0.
+
+* `obj_position`: byte position for the first obj block.
+* `obj_id_len`: number of bytes used to abbreviate object names in
+obj blocks.
+* `log_position`: byte position for the first log block.
+* `ref_index_position`: byte position for the start of the ref index.
+* `obj_index_position`: byte position for the start of the obj index.
+* `log_index_position`: byte position for the start of the log index.
+
+The size of the footer is 68 bytes for version 1, and 72 bytes for
+version 2.
+
+Reading the footer
+++++++++++++++++++
+
+Readers must first read the file start to determine the version
+number. Then they seek to `file_length - FOOTER_LENGTH` to access the
+footer. A trusted external source (such as `stat(2)`) is necessary to
+obtain `file_length`. When reading the footer, readers must verify:
+
+* 4-byte magic is correct
+* 1-byte version number is recognized
+* 4-byte CRC-32 matches the other 64 bytes (including magic, and
+version)
+
+Once verified, the other fields of the footer can be accessed.
+
+Empty tables
+++++++++++++
+
+A reftable may be empty. In this case, the file starts with a header
+and is immediately followed by a footer.
+
+Binary search
+^^^^^^^^^^^^^
+
+Binary search within a block is supported by the `restart_offset` fields
+at the end of the block. Readers can binary search through the restart
+table to locate between which two restart points the sought reference or
+key should appear.
+
+Each record identified by a `restart_offset` stores the complete key in
+the `suffix` field of the record, making the compare operation during
+binary search straightforward.
+
+Once a restart point lexicographically before the sought reference has
+been identified, readers can linearly scan through the following record
+entries to locate the sought record, terminating if the current record
+sorts after (and therefore the sought key is not present).
+
+Restart point selection
++++++++++++++++++++++++
+
+Writers determine the restart points at file creation. The process is
+arbitrary, but every 16 or 64 records is recommended. Every 16 may be
+more suitable for smaller block sizes (4k or 8k), every 64 for larger
+block sizes (64k).
+
+More frequent restart points reduces prefix compression and increases
+space consumed by the restart table, both of which increase file size.
+
+Less frequent restart points makes prefix compression more effective,
+decreasing overall file size, with increased penalties for readers
+walking through more records after the binary search step.
+
+A maximum of `65535` restart points per block is supported.
+
+Considerations
+~~~~~~~~~~~~~~
+
+Lightweight refs dominate
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The reftable format assumes the vast majority of references are single
+object names valued with common prefixes, such as Gerrit Code Review's
+`refs/changes/` namespace, GitHub's `refs/pulls/` namespace, or many
+lightweight tags in the `refs/tags/` namespace.
+
+Annotated tags storing the peeled object cost an additional object name per
+reference.
+
+Low overhead
+^^^^^^^^^^^^
+
+A reftable with very few references (e.g. git.git with 5 heads) is 269
+bytes for reftable, vs. 332 bytes for packed-refs. This supports
+reftable scaling down for transaction logs (below).
+
+Block size
+^^^^^^^^^^
+
+For a Gerrit Code Review type repository with many change refs, larger
+block sizes (64 KiB) and less frequent restart points (every 64) yield
+better compression due to more references within the block compressing
+against the prior reference.
+
+Larger block sizes reduce the index size, as the reftable will require
+fewer blocks to store the same number of references.
+
+Minimal disk seeks
+^^^^^^^^^^^^^^^^^^
+
+Assuming the index block has been loaded into memory, binary searching
+for any single reference requires exactly 1 disk seek to load the
+containing block.
+
+Scans and lookups dominate
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Scanning all references and lookup by name (or namespace such as
+`refs/heads/`) are the most common activities performed on repositories.
+Object names are stored directly with references to optimize this use case.
+
+Logs are infrequently read
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Logs are infrequently accessed, but can be large. Deflating log blocks
+saves disk space, with some increased penalty at read time.
+
+Logs are stored in an isolated section from refs, reducing the burden on
+reference readers that want to ignore logs. Further, historical logs can
+be isolated into log-only files.
+
+Logs are read backwards
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Logs are frequently accessed backwards (most recent N records for master
+to answer `master@{4}`), so log records are grouped by reference, and
+sorted descending by update index.
+
+Repository format
+~~~~~~~~~~~~~~~~~
+
+Version 1
+^^^^^^^^^
+
+A repository must set its `$GIT_DIR/config` to configure reftable:
+
+....
+[core]
+    repositoryformatversion = 1
+[extensions]
+    refStorage = reftable
+....
+
+Layout
+^^^^^^
+
+A collection of reftable files are stored in the `$GIT_DIR/reftable/` directory.
+Their names should have a random element, such that each filename is globally
+unique; this helps avoid spurious failures on Windows, where open files cannot
+be removed or overwritten. It suggested to use
+`${min_update_index}-${max_update_index}-${random}.ref` as a naming convention.
+
+Log-only files use the `.log` extension, while ref-only and mixed ref
+and log files use `.ref`. extension.
+
+The stack ordering file is `$GIT_DIR/reftable/tables.list` and lists the
+current files, one per line, in order, from oldest (base) to newest
+(most recent):
+
+....
+$ cat .git/reftable/tables.list
+00000001-00000001-RANDOM1.log
+00000002-00000002-RANDOM2.ref
+00000003-00000003-RANDOM3.ref
+....
+
+Readers must read `$GIT_DIR/reftable/tables.list` to determine which
+files are relevant right now, and search through the stack in reverse
+order (last reftable is examined first).
+
+Reftable files not listed in `tables.list` may be new (and about to be
+added to the stack by the active writer), or ancient and ready to be
+pruned.
+
+Backward compatibility
+^^^^^^^^^^^^^^^^^^^^^^
+
+Older clients should continue to recognize the directory as a git
+repository so they don't look for an enclosing repository in parent
+directories. To this end, a reftable-enabled repository must contain the
+following dummy files
+
+* `.git/HEAD`, a regular file containing `ref: refs/heads/.invalid`.
+* `.git/refs/`, a directory
+* `.git/refs/heads`, a regular file
+
+Readers
+^^^^^^^
+
+Readers can obtain a consistent snapshot of the reference space by
+following:
+
+1.  Open and read the `tables.list` file.
+2.  Open each of the reftable files that it mentions.
+3.  If any of the files is missing, goto 1.
+4.  Read from the now-open files as long as necessary.
+
+Update transactions
+^^^^^^^^^^^^^^^^^^^
+
+Although reftables are immutable, mutations are supported by writing a
+new reftable and atomically appending it to the stack:
+
+1.  Acquire `tables.list.lock`.
+2.  Read `tables.list` to determine current reftables.
+3.  Select `update_index` to be most recent file's
+`max_update_index + 1`.
+4.  Prepare temp reftable `tmp_XXXXXX`, including log entries.
+5.  Rename `tmp_XXXXXX` to `${update_index}-${update_index}-${random}.ref`.
+6.  Copy `tables.list` to `tables.list.lock`, appending file from (5).
+7.  Rename `tables.list.lock` to `tables.list`.
+
+During step 4 the new file's `min_update_index` and `max_update_index`
+are both set to the `update_index` selected by step 3. All log records
+for the transaction use the same `update_index` in their keys. This
+enables later correlation of which references were updated by the same
+transaction.
+
+Because a single `tables.list.lock` file is used to manage locking, the
+repository is single-threaded for writers. Writers may have to busy-spin
+(with backoff) around creating `tables.list.lock`, for up to an
+acceptable wait period, aborting if the repository is too busy to
+mutate. Application servers wrapped around repositories (e.g. Gerrit
+Code Review) can layer their own lock/wait queue to improve fairness to
+writers.
+
+Reference deletions
+^^^^^^^^^^^^^^^^^^^
+
+Deletion of any reference can be explicitly stored by setting the `type`
+to `0x0` and omitting the `value` field of the `ref_record`. This serves
+as a tombstone, overriding any assertions about the existence of the
+reference from earlier files in the stack.
+
+Compaction
+^^^^^^^^^^
+
+A partial stack of reftables can be compacted by merging references
+using a straightforward merge join across reftables, selecting the most
+recent value for output, and omitting deleted references that do not
+appear in remaining, lower reftables.
+
+A compacted reftable should set its `min_update_index` to the smallest
+of the input files' `min_update_index`, and its `max_update_index`
+likewise to the largest input `max_update_index`.
+
+For sake of illustration, assume the stack currently consists of
+reftable files (from oldest to newest): A, B, C, and D. The compactor is
+going to compact B and C, leaving A and D alone.
+
+1.  Obtain lock `tables.list.lock` and read the `tables.list` file.
+2.  Obtain locks `B.lock` and `C.lock`. Ownership of these locks
+prevents other processes from trying to compact these files.
+3.  Release `tables.list.lock`.
+4.  Compact `B` and `C` into a temp file
+`${min_update_index}-${max_update_index}_XXXXXX`.
+5.  Reacquire lock `tables.list.lock`.
+6.  Verify that `B` and `C` are still in the stack, in that order. This
+should always be the case, assuming that other processes are adhering to
+the locking protocol.
+7.  Rename `${min_update_index}-${max_update_index}_XXXXXX` to
+`${min_update_index}-${max_update_index}-${random}.ref`.
+8.  Write the new stack to `tables.list.lock`, replacing `B` and `C`
+with the file from (4).
+9.  Rename `tables.list.lock` to `tables.list`.
+10. Delete `B` and `C`, perhaps after a short sleep to avoid forcing
+readers to backtrack.
+
+This strategy permits compactions to proceed independently of updates.
+
+Each reftable (compacted or not) is uniquely identified by its name, so
+open reftables can be cached by their name.
+
+Windows
+^^^^^^^
+
+On windows, and other systems that do not allow deleting or renaming to open
+files, compaction may succeed, but other readers may prevent obsolete tables
+from being deleted.
+
+On these platforms, the following strategy can be followed: on closing a
+reftable stack, reload `tables.list`, and delete any tables no longer mentioned
+in `tables.list`.
+
+Irregular program exit may still leave about unused files. In this case, a
+cleanup operation should proceed as follows:
+
+* take a lock `tables.list.lock` to prevent concurrent modifications
+* refresh the reftable stack, by reading `tables.list`
+* for each `*.ref` file, remove it if
+** it is not mentioned in `tables.list`, and
+** its max update_index is not beyond the max update_index of the stack
+
+
+Alternatives considered
+~~~~~~~~~~~~~~~~~~~~~~~
+
+bzip packed-refs
+^^^^^^^^^^^^^^^^
+
+`bzip2` can significantly shrink a large packed-refs file (e.g. 62 MiB
+compresses to 23 MiB, 37%). However the bzip format does not support
+random access to a single reference. Readers must inflate and discard
+while performing a linear scan.
+
+Breaking packed-refs into chunks (individually compressing each chunk)
+would reduce the amount of data a reader must inflate, but still leaves
+the problem of indexing chunks to support readers efficiently locating
+the correct chunk.
+
+Given the compression achieved by reftable's encoding, it does not seem
+necessary to add the complexity of bzip/gzip/zlib.
+
+Michael Haggerty's alternate format
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Michael Haggerty proposed
+link:https://lore.kernel.org/git/CAMy9T_HCnyc1g8XWOOWhe7nN0aEFyyBskV2aOMb_fe%2BwGvEJ7A%40mail.gmail.com/[an
+alternate] format to reftable on the Git mailing list. This format uses
+smaller chunks, without the restart table, and avoids block alignment
+with padding. Reflog entries immediately follow each ref, and are thus
+interleaved between refs.
+
+Performance testing indicates reftable is faster for lookups (51%
+faster, 11.2 usec vs. 5.4 usec), although reftable produces a slightly
+larger file (+ ~3.2%, 28.3M vs 29.2M):
+
+[cols=">,>,>,>",options="header",]
+|=====================================
+|format |size |seek cold |seek hot
+|mh-alt |28.3 M |23.4 usec |11.2 usec
+|reftable |29.2 M |19.9 usec |5.4 usec
+|=====================================
+
+JGit Ketch RefTree
+^^^^^^^^^^^^^^^^^^
+
+https://dev.eclipse.org/mhonarc/lists/jgit-dev/msg03073.html[JGit Ketch]
+proposed
+link:https://lore.kernel.org/git/CAJo%3DhJvnAPNAdDcAAwAvU9C4RVeQdoS3Ev9WTguHx4fD0V_nOg%40mail.gmail.com/[RefTree],
+an encoding of references inside Git tree objects stored as part of the
+repository's object database.
+
+The RefTree format adds additional load on the object database storage
+layer (more loose objects, more objects in packs), and relies heavily on
+the packer's delta compression to save space. Namespaces which are flat
+(e.g. thousands of tags in refs/tags) initially create very large loose
+objects, and so RefTree does not address the problem of copying many
+references to modify a handful.
+
+Flat namespaces are not efficiently searchable in RefTree, as tree
+objects in canonical formatting cannot be binary searched. This fails
+the need to handle a large number of references in a single namespace,
+such as GitHub's `refs/pulls`, or a project with many tags.
+
+LMDB
+^^^^
+
+David Turner proposed
+https://lore.kernel.org/git/1455772670-21142-26-git-send-email-dturner@xxxxxxxxxxxxxxxx/[using
+LMDB], as LMDB is lightweight (64k of runtime code) and GPL-compatible
+license.
+
+A downside of LMDB is its reliance on a single C implementation. This
+makes embedding inside JGit (a popular reimplementation of Git)
+difficult, and hoisting onto virtual storage (for JGit DFS) virtually
+impossible.
+
+A common format that can be supported by all major Git implementations
+(git-core, JGit, libgit2) is strongly preferred.
diff --git a/Documentation/technical/remembering-renames.adoc b/Documentation/technical/remembering-renames.adoc
new file mode 100644
index 0000000000..73f41761e2
--- /dev/null
+++ b/Documentation/technical/remembering-renames.adoc
@@ -0,0 +1,671 @@
+Rebases and cherry-picks involve a sequence of merges whose results are
+recorded as new single-parent commits.  The first parent side of those
+merges represent the "upstream" side, and often include a far larger set of
+changes than the second parent side.  Traditionally, the renames on the
+first-parent side of that sequence of merges were repeatedly re-detected
+for every merge.  This file explains why it is safe and effective during
+rebases and cherry-picks to remember renames on the upstream side of
+history as an optimization, assuming all merges are automatic and clean
+(i.e. no conflicts and not interrupted for user input or editing).
+
+Outline:
+
+  0. Assumptions
+
+  1. How rebasing and cherry-picking work
+
+  2. Why the renames on MERGE_SIDE1 in any given pick are *always* a
+     superset of the renames on MERGE_SIDE1 for the next pick.
+
+  3. Why any rename on MERGE_SIDE1 in any given pick is _almost_ always also
+     a rename on MERGE_SIDE1 for the next pick
+
+  4. A detailed description of the counter-examples to #3.
+
+  5. Why the special cases in #4 are still fully reasonable to use to pair
+     up files for three-way content merging in the merge machinery, and why
+     they do not affect the correctness of the merge.
+
+  6. Interaction with skipping of "irrelevant" renames
+
+  7. Additional items that need to be cached
+
+  8. How directory rename detection interacts with the above and why this
+     optimization is still safe even if merge.directoryRenames is set to
+     "true".
+
+
+=== 0. Assumptions ===
+
+There are two assumptions that will hold throughout this document:
+
+  * The upstream side where commits are transplanted to is treated as the
+    first parent side when rebase/cherry-pick call the merge machinery
+
+  * All merges are fully automatic
+
+and a third that will hold in sections 2-5 for simplicity, that I'll later
+address in section 8:
+
+  * No directory renames occur
+
+
+Let me explain more about each assumption and why I include it:
+
+
+The first assumption is merely for the purposes of making this document
+clearer; the optimization implementation does not actually depend upon it.
+However, the assumption does hold in all cases because it reflects the way
+that both rebase and cherry-pick were implemented; and the implementation
+of cherry-pick and rebase are not readily changeable for backwards
+compatibility reasons (see for example the discussion of the --ours and
+--theirs flag in the documentation of `git checkout`, particularly the
+comments about how they behave with rebase).  The optimization avoids
+checking first-parent-ness, though.  It checks the conditions that make the
+optimization valid instead, so it would still continue working if someone
+changed the parent ordering that cherry-pick and rebase use.  But making
+this assumption does make this document much clearer and prevents me from
+having to repeat every example twice.
+
+If the second assumption is violated, then the optimization simply is
+turned off and thus isn't relevant to consider.  The second assumption can
+also be stated as "there is no interruption for a user to resolve conflicts
+or to just further edit or tweak files".  While real rebases and
+cherry-picks are often interrupted (either because it's an interactive
+rebase where the user requested to stop and edit, or because there were
+conflicts that the user needs to resolve), the cache of renames is not
+stored on disk, and thus is thrown away as soon as the rebase or cherry
+pick stops for the user to resolve the operation.
+
+The third assumption makes sections 2-5 simpler, and allows people to
+understand the basics of why this optimization is safe and effective, and
+then I can go back and address the specifics in section 8.  It is probably
+also worth noting that if directory renames do occur, then the default of
+merge.directoryRenames being set to "conflict" means that the operation
+will stop for users to resolve the conflicts and the cache will be thrown
+away, and thus that there won't be an optimization to apply.  So, the only
+reason we need to address directory renames specifically, is that some
+users will have set merge.directoryRenames to "true" to allow the merges to
+continue to proceed automatically.  The optimization is still safe with
+this config setting, but we have to discuss a few more cases to show why;
+this discussion is deferred until section 8.
+
+
+=== 1. How rebasing and cherry-picking work ===
+
+Consider the following setup (from the git-rebase manpage):
+
+		     A---B---C topic
+		    /
+	       D---E---F---G main
+
+After rebasing or cherry-picking topic onto main, this will appear as:
+
+			     A'--B'--C' topic
+			    /
+	       D---E---F---G main
+
+The way the commits A', B', and C' are created is through a series of
+merges, where rebase or cherry-pick sequentially uses each of the three
+A-B-C commits in a special merge operation.  Let's label the three commits
+in the merge operation as MERGE_BASE, MERGE_SIDE1, and MERGE_SIDE2.  For
+this picture, the three commits for each of the three merges would be:
+
+To create A':
+   MERGE_BASE:   E
+   MERGE_SIDE1:  G
+   MERGE_SIDE2:  A
+
+To create B':
+   MERGE_BASE:   A
+   MERGE_SIDE1:  A'
+   MERGE_SIDE2:  B
+
+To create C':
+   MERGE_BASE:   B
+   MERGE_SIDE1:  B'
+   MERGE_SIDE2:  C
+
+Sometimes, folks are surprised that these three-way merges are done.  It
+can be useful in understanding these three-way merges to view them in a
+slightly different light.  For example, in creating C', you can view it as
+either:
+
+  * Apply the changes between B & C to B'
+  * Apply the changes between B & B' to C
+
+Conceptually the two statements above are the same as a three-way merge of
+B, B', and C, at least the parts before you decide to record a commit.
+
+
+=== 2. Why the renames on MERGE_SIDE1 in any given pick are always a ===
+===    superset of the renames on MERGE_SIDE1 for the next pick.     ===
+
+The merge machinery uses the filenames it is fed from MERGE_BASE,
+MERGE_SIDE1, and MERGE_SIDE2.  It will only move content to a different
+filename under one of three conditions:
+
+  * To make both pieces of a conflict available to a user during conflict
+    resolution (examples: directory/file conflict, add/add type conflict
+    such as symlink vs. regular file)
+
+  * When MERGE_SIDE1 renames the file.
+
+  * When MERGE_SIDE2 renames the file.
+
+First, let's remember what commits are involved in the first and second
+picks of the cherry-pick or rebase sequence:
+
+To create A':
+   MERGE_BASE:   E
+   MERGE_SIDE1:  G
+   MERGE_SIDE2:  A
+
+To create B':
+   MERGE_BASE:   A
+   MERGE_SIDE1:  A'
+   MERGE_SIDE2:  B
+
+So, in particular, we need to show that the renames between E and G are a
+superset of those between A and A'.
+
+A' is created by the first merge.  A' will only have renames for one of the
+three reasons listed above.  The first case, a conflict, results in a
+situation where the cache is dropped and thus this optimization doesn't
+take effect, so we need not consider that case.  The third case, a rename
+on MERGE_SIDE2 (i.e. from G to A), will show up in A' but it also shows up
+in A -- therefore when diffing A and A' that path does not show up as a
+rename.  The only remaining way for renames to show up in A' is for the
+rename to come from MERGE_SIDE1.  Therefore, all renames between A and A'
+are a subset of those between E and G.  Equivalently, all renames between E
+and G are a superset of those between A and A'.
+
+
+=== 3. Why any rename on MERGE_SIDE1 in any given pick is _almost_   ===
+===    always also a rename on MERGE_SIDE1 for the next pick.        ===
+
+Let's again look at the first two picks:
+
+To create A':
+   MERGE_BASE:   E
+   MERGE_SIDE1:  G
+   MERGE_SIDE2:  A
+
+To create B':
+   MERGE_BASE:   A
+   MERGE_SIDE1:  A'
+   MERGE_SIDE2:  B
+
+Now let's look at any given rename from MERGE_SIDE1 of the first pick, i.e.
+any given rename from E to G.  Let's use the filenames 'oldfile' and
+'newfile' for demonstration purposes.  That first pick will function as
+follows; when the rename is detected, the merge machinery will do a
+three-way content merge of the following:
+    E:oldfile
+    G:newfile
+    A:oldfile
+and produce a new result:
+    A':newfile
+
+Note above that I've assumed that E->A did not rename oldfile.  If that
+side did rename, then we most likely have a rename/rename(1to2) conflict
+that will cause the rebase or cherry-pick operation to halt and drop the
+in-memory cache of renames and thus doesn't need to be considered further.
+In the special case that E->A does rename the file but also renames it to
+newfile, then there is no conflict from the renaming and the merge can
+succeed.  In this special case, the rename is not valid to cache because
+the second merge will find A:newfile in the MERGE_BASE (see also the new
+testcases in t6429 with "rename same file identically" in their
+description).  So a rename/rename(1to1) needs to be specially handled by
+pruning renames from the cache and decrementing the dir_rename_counts in
+the current and leading directories associated with those renames.  Or,
+since these are really rare, one could just take the easy way out and
+disable the remembering renames optimization when a rename/rename(1to1)
+happens.
+
+The previous paragraph handled the cases for E->A renaming oldfile, let's
+continue assuming that oldfile is not renamed in A.
+
+As per the diagram for creating B', MERGE_SIDE1 involves the changes from A
+to A'.  So, we are curious whether A:oldfile and A':newfile will be viewed
+as renames.  Note that:
+
+  * There will be no A':oldfile (because there could not have been a
+    G:oldfile as we do not do break detection in the merge machinery and
+    G:newfile was detected as a rename, and by the construction of the
+    rename above that merged cleanly, the merge machinery will ensure there
+    is no 'oldfile' in the result).
+
+  * There will be no A:newfile (if there had been, we would have had a
+    rename/add conflict).
+
+  * Clearly A:oldfile and A':newfile are "related" (A':newfile came from a
+    clean three-way content merge involving A:oldfile).
+
+We can also expound on the third point above, by noting that three-way
+content merges can also be viewed as applying the differences between the
+base and one side to the other side.  Thus we can view A':newfile as
+having been created by taking the changes between E:oldfile and G:newfile
+(which were detected as being related, i.e. <50% changed) to A:oldfile.
+
+Thus A:oldfile and A':newfile are just as related as E:oldfile and
+G:newfile are -- they have exactly identical differences.  Since the latter
+were detected as renames, A:oldfile and A':newfile should also be
+detectable as renames almost always.
+
+
+=== 4. A detailed description of the counter-examples to #3.         ===
+
+We already noted in section 3 that rename/rename(1to1) (i.e. both sides
+renaming a file the same way) was one counter-example.  The more
+interesting bit, though, is why did we need to use the "almost" qualifier
+when stating that A:oldfile and A':newfile are "almost" always detectable
+as renames?
+
+Let's repeat an earlier point that section 3 made:
+
+  A':newfile was created by applying the changes between E:oldfile and
+  G:newfile to A:oldfile.  The changes between E:oldfile and G:newfile were
+  <50% of the size of E:oldfile.
+
+If those changes that were <50% of the size of E:oldfile are also <50% of
+the size of A:oldfile, then A:oldfile and A':newfile will be detectable as
+renames.  However, if there is a dramatic size reduction between E:oldfile
+and A:oldfile (but the changes between E:oldfile, G:newfile, and A:oldfile
+still somehow merge cleanly), then traditional rename detection would not
+detect A:oldfile and A':newfile as renames.
+
+Here's an example where that can happen:
+  * E:oldfile had 20 lines
+  * G:newfile added 10 new lines at the beginning of the file
+  * A:oldfile kept the first 3 lines of the file, and deleted all the rest
+then
+  => A':newfile would have 13 lines, 3 of which matches those in A:oldfile.
+E:oldfile -> G:newfile would be detected as a rename, but A:oldfile and
+A':newfile would not be.
+
+
+=== 5. Why the special cases in #4 are still fully reasonable to use to    ===
+===    pair up files for three-way content merging in the merge machinery, ===
+===    and why they do not affect the correctness of the merge.            ===
+
+In the rename/rename(1to1) case, A:newfile and A':newfile are not renames
+since they use the *same* filename.  However, files with the same filename
+are obviously fine to pair up for three-way content merging (the merge
+machinery has never employed break detection).  The interesting
+counter-example case is thus not the rename/rename(1to1) case, but the case
+where A did not rename oldfile.  That was the case that we spent most of
+the time discussing in sections 3 and 4.  The remainder of this section
+will be devoted to that case as well.
+
+So, even if A:oldfile and A':newfile aren't detectable as renames, why is
+it still reasonable to pair them up for three-way content merging in the
+merge machinery?  There are multiple reasons:
+
+  * As noted in sections 3 and 4, the diff between A:oldfile and A':newfile
+    is *exactly* the same as the diff between E:oldfile and G:newfile.  The
+    latter pair were detected as renames, so it seems unlikely to surprise
+    users for us to treat A:oldfile and A':newfile as renames.
+
+  * In fact, "oldfile" and "newfile" were at one point detected as renames
+    due to how they were constructed in the E..G chain.  And we used that
+    information once already in this rebase/cherry-pick.  I think users
+    would be unlikely to be surprised at us continuing to treat the files
+    as renames and would quickly understand why we had done so.
+
+  * Marking or declaring files as renames is *not* the end goal for merges.
+    Merges use renames to determine which files make sense to be paired up
+    for three-way content merges.
+
+  * A:oldfile and A':newfile were _already_ paired up in a three-way
+    content merge; that is how A':newfile was created.  In fact, that
+    three-way content merge was clean.  So using them again in a later
+    three-way content merge seems very reasonable.
+
+However, the above is focusing on the common scenarios.  Let's try to look
+at all possible unusual scenarios and compare without the optimization to
+with the optimization.  Consider the following theoretical cases; we will
+then dive into each to determine which of them are possible,
+and if so, what they mean:
+
+  1. Without the optimization, the second merge results in a conflict.
+     With the optimization, the second merge also results in a conflict.
+     Questions: Are the conflicts confusingly different?  Better in one case?
+
+  2. Without the optimization, the second merge results in NO conflict.
+     With the optimization, the second merge also results in NO conflict.
+     Questions: Are the merges the same?
+
+  3. Without the optimization, the second merge results in a conflict.
+     With the optimization, the second merge results in NO conflict.
+     Questions: Possible?  Bug, bugfix, or something else?
+
+  4. Without the optimization, the second merge results in NO conflict.
+     With the optimization, the second merge results in a conflict.
+     Questions: Possible?  Bug, bugfix, or something else?
+
+I'll consider all four cases, but out of order.
+
+The fourth case is impossible.  For the code without the remembering
+renames optimization to not get a conflict, B:oldfile would need to exactly
+match A:oldfile -- if it doesn't, there would be a modify/delete conflict.
+If A:oldfile matches B:oldfile exactly, then a three-way content merge
+between A:oldfile, A':newfile, and B:oldfile would have no conflict and
+just give us the version of newfile from A' as the result.
+
+From the same logic as the above paragraph, the second case would indeed
+result in identical merges.  When A:oldfile exactly matches B:oldfile, an
+undetected rename would say, "Oh, I see one side didn't modify 'oldfile'
+and the other side deleted it.  I'll delete it.  And I see you have this
+brand new file named 'newfile' in A', so I'll keep it."  That gives the
+same results as three-way content merging A:oldfile, A':newfile, and
+B:oldfile -- a removal of oldfile with the version of newfile from A'
+showing up in the result.
+
+The third case is interesting.  It means that A:oldfile and A':newfile were
+not just similar enough, but that the changes between them did not conflict
+with the changes between A:oldfile and B:oldfile.  This would validate our
+hunch that the files were similar enough to be used in a three-way content
+merge, and thus seems entirely correct for us to have used them that way.
+(Sidenote: One particular example here may be enlightening.  Let's say that
+B was an immediate revert of A.  B clearly would have been a clean revert
+of A, since A was B's immediate parent.  One would assume that if you can
+pick a commit, you should also be able to cherry-pick its immediate revert.
+However, this is one of those funny corner cases; without this
+optimization, we just successfully picked a commit cleanly, but we are
+unable to cherry-pick its immediate revert due to the size differences
+between E:oldfile and A:oldfile.)
+
+That leaves only the first case to consider -- when we get conflicts both
+with or without the optimization.  Without the optimization, we'll have a
+modify/delete conflict, where both A':newfile and B:oldfile are left in the
+tree for the user to deal with and no hints about the potential similarity
+between the two.  With the optimization, we'll have a three-way content
+merged A:oldfile, A':newfile, and B:oldfile with conflict markers
+suggesting we thought the files were related but giving the user the chance
+to resolve.  As noted above, I don't think users will find us treating
+'oldfile' and 'newfile' as related as a surprise since they were between E
+and G.  In any event, though, this case shouldn't be concerning since we
+hit a conflict in both cases, told the user what we know, and asked them to
+resolve it.
+
+So, in summary, case 4 is impossible, case 2 yields the same behavior, and
+cases 1 and 3 seem to provide as good or better behavior with the
+optimization than without.
+
+
+=== 6. Interaction with skipping of "irrelevant" renames ===
+
+Previous optimizations involved skipping rename detection for paths
+considered to be "irrelevant".  See for example the following commits:
+
+  * 32a56dfb99 ("merge-ort: precompute subset of sources for which we
+		need rename detection", 2021-03-11)
+  * 2fd9eda462 ("merge-ort: precompute whether directory rename
+		detection is needed", 2021-03-11)
+  * 9bd342137e ("diffcore-rename: determine which relevant_sources are
+		no longer relevant", 2021-03-13)
+
+Relevance is always determined by what the _other_ side of history has
+done, in terms of modifying a file that our side renamed, or adding a
+file to a directory which our side renamed.  This means that a path
+that is "irrelevant" when picking the first commit of a series in a
+rebase or cherry-pick, may suddenly become "relevant" when picking the
+next commit.
+
+The upshot of this is that we can only cache rename detection results
+for relevant paths, and need to re-check relevance in subsequent
+commits.  If those subsequent commits have additional paths that are
+relevant for rename detection, then we will need to redo rename
+detection -- though we can limit it to the paths for which we have not
+already detected renames.
+
+
+=== 7. Additional items that need to be cached ===
+
+It turns out we have to cache more than just renames; we also cache:
+
+  A) non-renames (i.e. unpaired deletes)
+  B) counts of renames within directories
+  C) sources that were marked as RELEVANT_LOCATION, but which were
+     downgraded to RELEVANT_NO_MORE
+  D) the toplevel trees involved in the merge
+
+These are all stored in struct rename_info, and respectively appear in
+  * cached_pairs (along side actual renames, just with a value of NULL)
+  * dir_rename_counts
+  * cached_irrelevant
+  * merge_trees
+
+The reason for (A) comes from the irrelevant renames skipping
+optimization discussed in section 6.  The fact that irrelevant renames
+are skipped means we only get a subset of the potential renames
+detected and subsequent commits may need to run rename detection on
+the upstream side on a subset of the remaining renames (to get the
+renames that are relevant for that later commit).  Since unpaired
+deletes are involved in rename detection too, we don't want to
+repeatedly check that those paths remain unpaired on the upstream side
+with every commit we are transplanting.
+
+The reason for (B) is that diffcore_rename_extended() is what
+generates the counts of renames by directory which is needed in
+directory rename detection, and if we don't run
+diffcore_rename_extended() again then we need to have the output from
+it, including dir_rename_counts, from the previous run.
+
+The reason for (C) is that merge-ort's tree traversal will again think
+those paths are relevant (marking them as RELEVANT_LOCATION), but the
+fact that they were downgraded to RELEVANT_NO_MORE means that
+dir_rename_counts already has the information we need for directory
+rename detection.  (A path which becomes RELEVANT_CONTENT in a
+subsequent commit will be removed from cached_irrelevant.)
+
+The reason for (D) is that is how we determine whether the remember
+renames optimization can be used.  In particular, remembering that our
+sequence of merges looks like:
+
+   Merge 1:
+   MERGE_BASE:   E
+   MERGE_SIDE1:  G
+   MERGE_SIDE2:  A
+   => Creates    A'
+
+   Merge 2:
+   MERGE_BASE:   A
+   MERGE_SIDE1:  A'
+   MERGE_SIDE2:  B
+   => Creates    B'
+
+It is the fact that the trees A and A' appear both in Merge 1 and in
+Merge 2, with A as a parent of A' that allows this optimization.  So
+we store the trees to compare with what we are asked to merge next
+time.
+
+
+=== 8. How directory rename detection interacts with the above and   ===
+===    why this optimization is still safe even if                   ===
+===    merge.directoryRenames is set to "true".                      ===
+
+As noted in the assumptions section:
+
+    """
+    ...if directory renames do occur, then the default of
+    merge.directoryRenames being set to "conflict" means that the operation
+    will stop for users to resolve the conflicts and the cache will be
+    thrown away, and thus that there won't be an optimization to apply.
+    So, the only reason we need to address directory renames specifically,
+    is that some users will have set merge.directoryRenames to "true" to
+    allow the merges to continue to proceed automatically.
+    """
+
+Let's remember that we need to look at how any given pick affects the next
+one.  So let's again use the first two picks from the diagram in section
+one:
+
+  First pick does this three-way merge:
+    MERGE_BASE:   E
+    MERGE_SIDE1:  G
+    MERGE_SIDE2:  A
+    => creates A'
+
+  Second pick does this three-way merge:
+    MERGE_BASE:   A
+    MERGE_SIDE1:  A'
+    MERGE_SIDE2:  B
+    => creates B'
+
+Now, directory rename detection exists so that if one side of history
+renames a directory, and the other side adds a new file to the old
+directory, then the merge (with merge.directoryRenames=true) can move the
+file into the new directory.  There are two qualitatively different ways to
+add a new file to an old directory: create a new file, or rename a file
+into that directory.  Also, directory renames can be done on either side of
+history, so there are four cases to consider:
+
+  * MERGE_SIDE1 renames old dir, MERGE_SIDE2 adds new file to   old dir
+  * MERGE_SIDE1 renames old dir, MERGE_SIDE2 renames  file into old dir
+  * MERGE_SIDE1 adds new file to   old dir, MERGE_SIDE2 renames old dir
+  * MERGE_SIDE1 renames  file into old dir, MERGE_SIDE2 renames old dir
+
+One last note before we consider these four cases: There are some
+important properties about how we implement this optimization with
+respect to directory rename detection that we need to bear in mind
+while considering all of these cases:
+
+  * rename caching occurs *after* applying directory renames
+
+  * a rename created by directory rename detection is recorded for the side
+    of history that did the directory rename.
+
+  * dir_rename_counts, the nested map of
+	{oldname => {newname => count}},
+    is cached between runs as well.  This basically means that directory
+    rename detection is also cached, though only on the side of history
+    that we cache renames for (MERGE_SIDE1 as far as this document is
+    concerned; see the assumptions section).  Two interesting sub-notes
+    about these counts:
+
+    * If we need to perform rename-detection again on the given side (e.g.
+      some paths are relevant for rename detection that weren't before),
+      then we clear dir_rename_counts and recompute it, making use of
+      cached_pairs.  The reason it is important to do this is optimizations
+      around RELEVANT_LOCATION exist to prevent us from computing
+      unnecessary renames for directory rename detection and from computing
+      dir_rename_counts for irrelevant directories; but those same renames
+      or directories may become necessary for subsequent merges.  The
+      easiest way to "fix up" dir_rename_counts in such cases is to just
+      recompute it.
+
+    * If we prune rename/rename(1to1) entries from the cache, then we also
+      need to update dir_rename_counts to decrement the counts for the
+      involved directory and any relevant parent directories (to undo what
+      update_dir_rename_counts() in diffcore-rename.c incremented when the
+      rename was initially found).  If we instead just disable the
+      remembering renames optimization when the exceedingly rare
+      rename/rename(1to1) cases occur, then dir_rename_counts will get
+      re-computed the next time rename detection occurs, as noted above.
+
+  * the side with multiple commits to pick, is the side of history that we
+    do NOT cache renames for.  Thus, there are no additional commits to
+    change the number of renames in a directory, except for those done by
+    directory rename detection (which always pad the majority).
+
+  * the "renames" we cache are modified slightly by any directory rename,
+    as noted below.
+
+Now, with those notes out of the way, let's go through the four cases
+in order:
+
+Case 1: MERGE_SIDE1 renames old dir, MERGE_SIDE2 adds new file to old dir
+
+  This case looks like this:
+
+    MERGE_BASE:   E,   Has olddir/
+    MERGE_SIDE1:  G,   Renames olddir/ -> newdir/
+    MERGE_SIDE2:  A,   Adds olddir/newfile
+    => creates    A',  With newdir/newfile
+
+    MERGE_BASE:   A,   Has olddir/newfile
+    MERGE_SIDE1:  A',  Has newdir/newfile
+    MERGE_SIDE2:  B,   Modifies olddir/newfile
+    => expected   B',  with threeway-merged newdir/newfile from above
+
+  In this case, with the optimization, note that after the first commit:
+    * MERGE_SIDE1 remembers olddir/ -> newdir/
+    * MERGE_SIDE1 has cached olddir/newfile -> newdir/newfile
+  Given the cached rename noted above, the second merge can proceed as
+  expected without needing to perform rename detection from A -> A'.
+
+Case 2: MERGE_SIDE1 renames old dir, MERGE_SIDE2 renames  file into old dir
+
+  This case looks like this:
+    MERGE_BASE:   E    oldfile, olddir/
+    MERGE_SIDE1:  G    oldfile, olddir/ -> newdir/
+    MERGE_SIDE2:  A    oldfile -> olddir/newfile
+    => creates    A',  With newdir/newfile representing original oldfile
+
+    MERGE_BASE:   A    olddir/newfile
+    MERGE_SIDE1:  A'   newdir/newfile
+    MERGE_SIDE2:  B    modify olddir/newfile
+    => expected   B',  with threeway-merged newdir/newfile from above
+
+  In this case, with the optimization, note that after the first commit:
+    * MERGE_SIDE1 remembers olddir/ -> newdir/
+    * MERGE_SIDE1 has cached olddir/newfile -> newdir/newfile
+		  (NOT oldfile -> newdir/newfile; compare to case with
+		   (p->status == 'R' && new_path) in possibly_cache_new_pair())
+
+  Given the cached rename noted above, the second merge can proceed as
+  expected without needing to perform rename detection from A -> A'.
+
+Case 3: MERGE_SIDE1 adds new file to   old dir, MERGE_SIDE2 renames old dir
+
+  This case looks like this:
+
+    MERGE_BASE:   E,   Has olddir/
+    MERGE_SIDE1:  G,   Adds olddir/newfile
+    MERGE_SIDE2:  A,   Renames olddir/ -> newdir/
+    => creates    A',  With newdir/newfile
+
+    MERGE_BASE:   A,   Has newdir/, but no notion of newdir/newfile
+    MERGE_SIDE1:  A',  Has newdir/newfile
+    MERGE_SIDE2:  B,   Has newdir/, but no notion of newdir/newfile
+    => expected   B',  with newdir/newfile from A'
+
+  In this case, with the optimization, note that after the first commit there
+  were no renames on MERGE_SIDE1, and any renames on MERGE_SIDE2 are tossed.
+  But the second merge didn't need any renames so this is fine.
+
+Case 4: MERGE_SIDE1 renames  file into old dir, MERGE_SIDE2 renames old dir
+
+  This case looks like this:
+
+    MERGE_BASE:   E,   Has olddir/
+    MERGE_SIDE1:  G,   Renames oldfile -> olddir/newfile
+    MERGE_SIDE2:  A,   Renames olddir/ -> newdir/
+    => creates    A',  With newdir/newfile representing original oldfile
+
+    MERGE_BASE:   A,   Has oldfile
+    MERGE_SIDE1:  A',  Has newdir/newfile
+    MERGE_SIDE2:  B,   Modifies oldfile
+    => expected   B',  with threeway-merged newdir/newfile from above
+
+  In this case, with the optimization, note that after the first commit:
+    * MERGE_SIDE1 remembers oldfile -> newdir/newfile
+		  (NOT oldfile -> olddir/newfile; compare to case of second
+		   block under p->status == 'R' in possibly_cache_new_pair())
+    * MERGE_SIDE2 renames are tossed because only MERGE_SIDE1 is remembered
+
+  Given the cached rename noted above, the second merge can proceed as
+  expected without needing to perform rename detection from A -> A'.
+
+Finally, I'll just note here that interactions with the
+skip-irrelevant-renames optimization means we sometimes don't detect
+renames for any files within a directory that was renamed, in which
+case we will not have been able to detect any rename for the directory
+itself.  In such a case, we do not know whether the directory was
+renamed; we want to be careful to avoid caching some kind of "this
+directory was not renamed" statement.  If we did, then a subsequent
+commit being rebased could add a file to the old directory, and the
+user would expect it to end up in the correct directory -- something
+our erroneous "this directory was not renamed" cache would preclude.
diff --git a/Documentation/technical/repository-version.adoc b/Documentation/technical/repository-version.adoc
new file mode 100644
index 0000000000..b9bb81a81f
--- /dev/null
+++ b/Documentation/technical/repository-version.adoc
@@ -0,0 +1,70 @@
+== Git Repository Format Versions
+
+Every git repository is marked with a numeric version in the
+`core.repositoryformatversion` key of its `config` file. This version
+specifies the rules for operating on the on-disk repository data. An
+implementation of git which does not understand a particular version
+advertised by an on-disk repository MUST NOT operate on that repository;
+doing so risks not only producing wrong results, but actually losing
+data.
+
+Because of this rule, version bumps should be kept to an absolute
+minimum. Instead, we generally prefer these strategies:
+
+  - bumping format version numbers of individual data files (e.g.,
+    index, packfiles, etc). This restricts the incompatibilities only to
+    those files.
+
+  - introducing new data that gracefully degrades when used by older
+    clients (e.g., pack bitmap files are ignored by older clients, which
+    simply do not take advantage of the optimization they provide).
+
+A whole-repository format version bump should only be part of a change
+that cannot be independently versioned. For instance, if one were to
+change the reachability rules for objects, or the rules for locking
+refs, that would require a bump of the repository format version.
+
+Note that this applies only to accessing the repository's disk contents
+directly. An older client which understands only format `0` may still
+connect via `git://` to a repository using format `1`, as long as the
+server process understands format `1`.
+
+The preferred strategy for rolling out a version bump (whether whole
+repository or for a single file) is to teach git to read the new format,
+and allow writing the new format with a config switch or command line
+option (for experimentation or for those who do not care about backwards
+compatibility with older gits). Then after a long period to allow the
+reading capability to become common, we may switch to writing the new
+format by default.
+
+The currently defined format versions are:
+
+=== Version `0`
+
+This is the format defined by the initial version of git, including but
+not limited to the format of the repository directory, the repository
+configuration file, and the object and ref storage. Specifying the
+complete behavior of git is beyond the scope of this document.
+
+=== Version `1`
+
+This format is identical to version `0`, with the following exceptions:
+
+  1. When reading the `core.repositoryformatversion` variable, a git
+     implementation which supports version 1 MUST also read any
+     configuration keys found in the `extensions` section of the
+     configuration file.
+
+  2. If a version-1 repository specifies any `extensions.*` keys that
+     the running git has not implemented, the operation MUST NOT
+     proceed. Similarly, if the value of any known key is not understood
+     by the implementation, the operation MUST NOT proceed.
+
+Note that if no extensions are specified in the config file, then
+`core.repositoryformatversion` SHOULD be set to `0` (setting it to `1`
+provides no benefit, and makes the repository incompatible with older
+implementations of git).
+
+The defined extensions are given in the `extensions.*` section of
+linkgit:git-config[1]. Any implementation wishing to define a new
+extension should make a note of it there, in order to claim the name.
diff --git a/Documentation/technical/rerere.adoc b/Documentation/technical/rerere.adoc
new file mode 100644
index 0000000000..580f23360a
--- /dev/null
+++ b/Documentation/technical/rerere.adoc
@@ -0,0 +1,186 @@
+Rerere
+======
+
+This document describes the rerere logic.
+
+Conflict normalization
+----------------------
+
+To ensure recorded conflict resolutions can be looked up in the rerere
+database, even when branches are merged in a different order,
+different branches are merged that result in the same conflict, or
+when different conflict style settings are used, rerere normalizes the
+conflicts before writing them to the rerere database.
+
+Different conflict styles and branch names are normalized by stripping
+the labels from the conflict markers, and removing the common ancestor
+version from the `diff3` or `zdiff3` conflict styles.  Branches that
+are merged in different order are normalized by sorting the conflict
+hunks.  More on each of those steps in the following sections.
+
+Once these two normalization operations are applied, a conflict ID is
+calculated based on the normalized conflict, which is later used by
+rerere to look up the conflict in the rerere database.
+
+Removing the common ancestor version
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Say we have three branches AB, AC and AC2.  The common ancestor of
+these branches has a file with a line containing the string "A" (for
+brevity this is called "line A" in the rest of the document).  In
+branch AB this line is changed to "B", in AC, this line is changed to
+"C", and branch AC2 is forked off of AC, after the line was changed to
+"C".
+
+Forking a branch ABAC off of branch AB and then merging AC into it, we
+get a conflict like the following:
+
+    <<<<<<< HEAD
+    B
+    =======
+    C
+    >>>>>>> AC
+
+Doing the analogous with AC2 (forking a branch ABAC2 off of branch AB
+and then merging branch AC2 into it), using the diff3 or zdiff3
+conflict style, we get a conflict like the following:
+
+    <<<<<<< HEAD
+    B
+    ||||||| merged common ancestors
+    A
+    =======
+    C
+    >>>>>>> AC2
+
+By resolving this conflict, to leave line D, the user declares:
+
+    After examining what branches AB and AC did, I believe that making
+    line A into line D is the best thing to do that is compatible with
+    what AB and AC wanted to do.
+
+As branch AC2 refers to the same commit as AC, the above implies that
+this is also compatible with what AB and AC2 wanted to do.
+
+By extension, this means that rerere should recognize that the above
+conflicts are the same.  To do this, the labels on the conflict
+markers are stripped, and the common ancestor version is removed.  The above
+examples would both result in the following normalized conflict:
+
+    <<<<<<<
+    B
+    =======
+    C
+    >>>>>>>
+
+Sorting hunks
+~~~~~~~~~~~~~
+
+As before, let's imagine that a common ancestor had a file with line A
+its early part, and line X in its late part.  And then four branches
+are forked that do these things:
+
+    - AB: changes A to B
+    - AC: changes A to C
+    - XY: changes X to Y
+    - XZ: changes X to Z
+
+Now, forking a branch ABAC off of branch AB and then merging AC into
+it, and forking a branch ACAB off of branch AC and then merging AB
+into it, would yield the conflict in a different order.  The former
+would say "A became B or C, what now?" while the latter would say "A
+became C or B, what now?"
+
+As a reminder, the act of merging AC into ABAC and resolving the
+conflict to leave line D means that the user declares:
+
+    After examining what branches AB and AC did, I believe that
+    making line A into line D is the best thing to do that is
+    compatible with what AB and AC wanted to do.
+
+So the conflict we would see when merging AB into ACAB should be
+resolved the same way--it is the resolution that is in line with that
+declaration.
+
+Imagine that similarly previously a branch XYXZ was forked from XY,
+and XZ was merged into it, and resolved "X became Y or Z" into "X
+became W".
+
+Now, if a branch ABXY was forked from AB and then merged XY, then ABXY
+would have line B in its early part and line Y in its later part.
+Such a merge would be quite clean.  We can construct 4 combinations
+using these four branches ((AB, AC) x (XY, XZ)).
+
+Merging ABXY and ACXZ would make "an early A became B or C, a late X
+became Y or Z" conflict, while merging ACXY and ABXZ would make "an
+early A became C or B, a late X became Y or Z".  We can see there are
+4 combinations of ("B or C", "C or B") x ("X or Y", "Y or X").
+
+By sorting, the conflict is given its canonical name, namely, "an
+early part became B or C, a late part became X or Y", and whenever
+any of these four patterns appear, and we can get to the same conflict
+and resolution that we saw earlier.
+
+Without the sorting, we'd have to somehow find a previous resolution
+from combinatorial explosion.
+
+Conflict ID calculation
+~~~~~~~~~~~~~~~~~~~~~~~
+
+Once the conflict normalization is done, the conflict ID is calculated
+as the sha1 hash of the conflict hunks appended to each other,
+separated by <NUL> characters.  The conflict markers are stripped out
+before the sha1 is calculated.  So in the example above, where we
+merge branch AC which changes line A to line C, into branch AB, which
+changes line A to line C, the conflict ID would be
+SHA1('B<NUL>C<NUL>').
+
+If there are multiple conflicts in one file, the sha1 is calculated
+the same way with all hunks appended to each other, in the order in
+which they appear in the file, separated by a <NUL> character.
+
+Nested conflicts
+~~~~~~~~~~~~~~~~
+
+Nested conflicts are handled very similarly to "simple" conflicts.
+Similar to simple conflicts, the conflict is first normalized by
+stripping the labels from conflict markers, stripping the common ancestor
+version, and sorting the conflict hunks, both for the outer and the
+inner conflict.  This is done recursively, so any number of nested
+conflicts can be handled.
+
+Note that this only works for conflict markers that "cleanly nest".  If
+there are any unmatched conflict markers, rerere will fail to handle
+the conflict and record a conflict resolution.
+
+The only difference is in how the conflict ID is calculated.  For the
+inner conflict, the conflict markers themselves are not stripped out
+before calculating the sha1.
+
+Say we have the following conflict for example:
+
+    <<<<<<< HEAD
+    1
+    =======
+    <<<<<<< HEAD
+    3
+    =======
+    2
+    >>>>>>> branch-2
+    >>>>>>> branch-3~
+
+After stripping out the labels of the conflict markers, and sorting
+the hunks, the conflict would look as follows:
+
+    <<<<<<<
+    1
+    =======
+    <<<<<<<
+    2
+    =======
+    3
+    >>>>>>>
+    >>>>>>>
+
+and finally the conflict ID would be calculated as:
+`sha1('1<NUL><<<<<<<\n3\n=======\n2\n>>>>>>><NUL>')`
diff --git a/Documentation/technical/scalar.adoc b/Documentation/technical/scalar.adoc
new file mode 100644
index 0000000000..921cb104c3
--- /dev/null
+++ b/Documentation/technical/scalar.adoc
@@ -0,0 +1,66 @@
+Scalar
+======
+
+Scalar is a repository management tool that optimizes Git for use in large
+repositories. It accomplishes this by helping users to take advantage of
+advanced performance features in Git. Unlike most other Git built-in commands,
+Scalar is not executed as a subcommand of 'git'; rather, it is built as a
+separate executable containing its own series of subcommands.
+
+Background
+----------
+
+Scalar was originally designed as an add-on to Git and implemented as a .NET
+Core application. It was created based on the learnings from the VFS for Git
+project (another application aimed at improving the experience of working with
+large repositories). As part of its initial implementation, Scalar relied on
+custom features in the Microsoft fork of Git that have since been integrated
+into core Git:
+
+* partial clone,
+* commit graphs,
+* multi-pack index,
+* sparse checkout (cone mode),
+* scheduled background maintenance,
+* etc
+
+With the requisite Git functionality in place and a desire to bring the benefits
+of Scalar to the larger Git community, the Scalar application itself was ported
+from C# to C and integrated upstream.
+
+Features
+--------
+
+Scalar is comprised of two major pieces of functionality: automatically
+configuring built-in Git performance features and managing repository
+enlistments.
+
+The Git performance features configured by Scalar (see "Background" for
+examples) confer substantial performance benefits to large repositories, but are
+either too experimental to enable for all of Git yet, or only benefit large
+repositories. As new features are introduced, Scalar should be updated
+accordingly to incorporate them. This will prevent the tool from becoming stale
+while also providing a path for more easily bringing features to the appropriate
+users.
+
+Enlistments are how Scalar knows which repositories on a user's system should
+utilize Scalar-configured features. This allows it to update performance
+settings when new ones are added to the tool, as well as centrally manage
+repository maintenance. The enlistment structure - a root directory with a
+`src/` subdirectory containing the cloned repository itself - is designed to
+encourage users to route build outputs outside of the repository to avoid the
+performance-limiting overhead of ignoring those files in Git.
+
+Design
+------
+
+Scalar is implemented in C and interacts with Git via a mix of child process
+invocations of Git and direct usage of `libgit.a`. Internally, it is structured
+much like other built-ins with subcommands (e.g., `git stash`), containing a
+`cmd_<subcommand>()` function for each subcommand, routed through a `cmd_main()`
+function. Most options are unique to each subcommand, with `scalar` respecting
+some "global" `git` options (e.g., `-c` and `-C`).
+
+Because `scalar` is not invoked as a Git subcommand (like `git scalar`), it is
+built and installed as its own executable in the `bin/` directory, alongside
+`git`, `git-gui`, etc.
diff --git a/Documentation/technical/send-pack-pipeline.adoc b/Documentation/technical/send-pack-pipeline.adoc
new file mode 100644
index 0000000000..9b5a0bc186
--- /dev/null
+++ b/Documentation/technical/send-pack-pipeline.adoc
@@ -0,0 +1,63 @@
+Git-send-pack internals
+=======================
+
+Overall operation
+-----------------
+
+. Connects to the remote side and invokes git-receive-pack.
+
+. Learns what refs the remote has and what commit they point at.
+  Matches them to the refspecs we are pushing.
+
+. Checks if there are non-fast-forwards.  Unlike fetch-pack,
+  the repository send-pack runs in is supposed to be a superset
+  of the recipient in fast-forward cases, so there is no need
+  for want/have exchanges, and fast-forward check can be done
+  locally.  Tell the result to the other end.
+
+. Calls pack_objects() which generates a packfile and sends it
+  over to the other end.
+
+. If the remote side is new enough (v1.1.0 or later), wait for
+  the unpack and hook status from the other end.
+
+. Exit with appropriate error codes.
+
+
+Pack_objects pipeline
+---------------------
+
+This function gets one file descriptor (`fd`) which is either a
+socket (over the network) or a pipe (local).  What's written to
+this fd goes to git-receive-pack to be unpacked.
+
+    send-pack ---> fd ---> receive-pack
+
+The function pack_objects creates a pipe and then forks.  The
+forked child execs pack-objects with --revs to receive revision
+parameters from its standard input. This process will write the
+packfile to the other end.
+
+    send-pack
+       |
+       pack_objects() ---> fd ---> receive-pack
+          | ^ (pipe)
+	  v |
+         (child)
+
+The child dup2's to arrange its standard output to go back to
+the other end, and read its standard input to come from the
+pipe.  After that it exec's pack-objects.  On the other hand,
+the parent process, before starting to feed the child pipeline,
+closes the reading side of the pipe and fd to receive-pack.
+
+    send-pack
+       |
+       pack_objects(parent)
+          |
+	  v [0]
+         pack-objects [0] ---> receive-pack
+
+
+[jc: the pipeline was much more complex and needed documentation before
+ I understood an earlier bug, but now it is trivial and straightforward.]
diff --git a/Documentation/technical/shallow.adoc b/Documentation/technical/shallow.adoc
new file mode 100644
index 0000000000..f3738baa0f
--- /dev/null
+++ b/Documentation/technical/shallow.adoc
@@ -0,0 +1,60 @@
+Shallow commits
+===============
+
+.Definition
+*********************************************************
+Shallow commits do have parents, but not in the shallow
+repo, and therefore grafts are introduced pretending that
+these commits have no parents.
+*********************************************************
+
+$GIT_DIR/shallow lists commit object names and tells Git to
+pretend as if they are root commits (e.g. "git log" traversal
+stops after showing them; "git fsck" does not complain saying
+the commits listed on their "parent" lines do not exist).
+
+Each line contains exactly one object name. When read, a commit_graft
+will be constructed, which has nr_parent < 0 to make it easier
+to discern from user provided grafts.
+
+Note that the shallow feature could not be changed easily to
+use replace refs: a commit containing a `mergetag` is not allowed
+to be replaced, not even by a root commit. Such a commit can be
+made shallow, though. Also, having a `shallow` file explicitly
+listing all the commits made shallow makes it a *lot* easier to
+do shallow-specific things such as to deepen the history.
+
+Since fsck-objects relies on the library to read the objects,
+it honours shallow commits automatically.
+
+There are some unfinished ends of the whole shallow business:
+
+- maybe we have to force non-thin packs when fetching into a
+  shallow repo (ATM they are forced non-thin).
+
+- A special handling of a shallow upstream is needed. At some
+  stage, upload-pack has to check if it sends a shallow commit,
+  and it should send that information early (or fail, if the
+  client does not support shallow repositories). There is no
+  support at all for this in this patch series.
+
+- Instead of locking $GIT_DIR/shallow at the start, just
+  the timestamp of it is noted, and when it comes to writing it,
+  a check is performed if the mtime is still the same, dying if
+  it is not.
+
+- It is unclear how "push into/from a shallow repo" should behave.
+
+- If you deepen a history, you'd want to get the tags of the
+  newly stored (but older!) commits. This does not work right now.
+
+To make a shallow clone, you can call "git-clone --depth 20 repo".
+The result contains only commit chains with a length of at most 20.
+It also writes an appropriate $GIT_DIR/shallow.
+
+You can deepen a shallow repository with "git-fetch --depth 20
+repo branch", which will fetch branch from repo, but stop at depth
+20, updating $GIT_DIR/shallow.
+
+The special depth 2147483647 (or 0x7fffffff, the largest positive
+number a signed 32-bit integer can contain) means infinite depth.
diff --git a/Documentation/technical/sparse-checkout.adoc b/Documentation/technical/sparse-checkout.adoc
new file mode 100644
index 0000000000..d968659354
--- /dev/null
+++ b/Documentation/technical/sparse-checkout.adoc
@@ -0,0 +1,1103 @@
+Table of contents:
+
+  * Terminology
+  * Purpose of sparse-checkouts
+  * Usecases of primary concern
+  * Oversimplified mental models ("Cliff Notes" for this document!)
+  * Desired behavior
+  * Behavior classes
+  * Subcommand-dependent defaults
+  * Sparse specification vs. sparsity patterns
+  * Implementation Questions
+  * Implementation Goals/Plans
+  * Known bugs
+  * Reference Emails
+
+
+=== Terminology ===
+
+cone mode: one of two modes for specifying the desired subset of files
+	in a sparse-checkout.  In cone-mode, the user specifies
+	directories (getting both everything under that directory as
+	well as everything in leading directories), while in non-cone
+	mode, the user specifies gitignore-style patterns.  Controlled
+	by the --[no-]cone option to sparse-checkout init|set.
+
+SKIP_WORKTREE: When tracked files do not match the sparse specification and
+	are removed from the working tree, the file in the index is marked
+	with a SKIP_WORKTREE bit.  Note that if a tracked file has the
+	SKIP_WORKTREE bit set but the file is later written by the user to
+	the working tree anyway, the SKIP_WORKTREE bit will be cleared at
+	the beginning of any subsequent Git operation.
+
+	Most sparse checkout users are unaware of this implementation
+	detail, and the term should generally be avoided in user-facing
+	descriptions and command flags.  Unfortunately, prior to the
+	`sparse-checkout` subcommand this low-level detail was exposed,
+	and as of time of writing, is still exposed in various places.
+
+sparse-checkout: a subcommand in git used to reduce the files present in
+	the working tree to a subset of all tracked files.  Also, the
+	name of the file in the $GIT_DIR/info directory used to track
+	the sparsity patterns corresponding to the user's desired
+	subset.
+
+sparse cone: see cone mode
+
+sparse directory: An entry in the index corresponding to a directory, which
+	appears in the index instead of all the files under that directory
+	that would normally appear.  See also sparse-index.  Something that
+	can cause confusion is that the "sparse directory" does NOT match
+	the sparse specification, i.e. the directory is NOT present in the
+	working tree.  May be renamed in the future (e.g. to "skipped
+	directory").
+
+sparse index: A special mode for sparse-checkout that also makes the
+	index sparse by recording a directory entry in lieu of all the
+	files underneath that directory (thus making that a "skipped
+	directory" which unfortunately has also been called a "sparse
+	directory"), and does this for potentially multiple
+	directories.  Controlled by the --[no-]sparse-index option to
+	init|set|reapply.
+
+sparsity patterns: patterns from $GIT_DIR/info/sparse-checkout used to
+	define the set of files of interest.  A warning: It is easy to
+	over-use this term (or the shortened "patterns" term), for two
+	reasons: (1) users in cone mode specify directories rather than
+	patterns (their directories are transformed into patterns, but
+	users may think you are talking about non-cone mode if you use the
+	word "patterns"), and (b) the sparse specification might
+	transiently differ in the working tree or index from the sparsity
+	patterns (see "Sparse specification vs. sparsity patterns").
+
+sparse specification: The set of paths in the user's area of focus.  This
+	is typically just the tracked files that match the sparsity
+	patterns, but the sparse specification can temporarily differ and
+	include additional files.  (See also "Sparse specification
+	vs. sparsity patterns")
+
+	* When working with history, the sparse specification is exactly
+	  the set of files matching the sparsity patterns.
+	* When interacting with the working tree, the sparse specification
+	  is the set of tracked files with a clear SKIP_WORKTREE bit or
+	  tracked files present in the working copy.
+	* When modifying or showing results from the index, the sparse
+	  specification is the set of files with a clear SKIP_WORKTREE bit
+	  or that differ in the index from HEAD.
+	* If working with the index and the working copy, the sparse
+	  specification is the union of the paths from above.
+
+vivifying: When a command restores a tracked file to the working tree (and
+	hopefully also clears the SKIP_WORKTREE bit in the index for that
+	file), this is referred to as "vivifying" the file.
+
+
+=== Purpose of sparse-checkouts ===
+
+sparse-checkouts exist to allow users to work with a subset of their
+files.
+
+You can think of sparse-checkouts as subdividing "tracked" files into two
+categories -- a sparse subset, and all the rest.  Implementationally, we
+mark "all the rest" in the index with a SKIP_WORKTREE bit and leave them
+out of the working tree.  The SKIP_WORKTREE files are still tracked, just
+not present in the working tree.
+
+In the past, sparse-checkouts were defined by "SKIP_WORKTREE means the file
+is missing from the working tree but pretend the file contents match HEAD".
+That was not only bogus (it actually meant the file missing from the
+working tree matched the index rather than HEAD), but it was also a
+low-level detail which only provided decent behavior for a few commands.
+There were a surprising number of ways in which that guiding principle gave
+command results that violated user expectations, and as such was a bad
+mental model.  However, it persisted for many years and may still be found
+in some corners of the code base.
+
+Anyway, the idea of "working with a subset of files" is simple enough, but
+there are multiple different high-level usecases which affect how some Git
+subcommands should behave.  Further, even if we only considered one of
+those usecases, sparse-checkouts can modify different subcommands in over a
+half dozen different ways.  Let's start by considering the high level
+usecases:
+
+  A) Users are _only_ interested in the sparse portion of the repo
+
+  A*) Users are _only_ interested in the sparse portion of the repo
+      that they have downloaded so far
+
+  B) Users want a sparse working tree, but are working in a larger whole
+
+  C) sparse-checkout is a behind-the-scenes implementation detail allowing
+     Git to work with a specially crafted in-house virtual file system;
+     users are actually working with a "full" working tree that is
+     lazily populated, and sparse-checkout helps with the lazy population
+     piece.
+
+It may be worth explaining each of these in a bit more detail:
+
+
+  (Behavior A) Users are _only_ interested in the sparse portion of the repo
+
+These folks might know there are other things in the repository, but
+don't care.  They are uninterested in other parts of the repository, and
+only want to know about changes within their area of interest.  Showing
+them other files from history (e.g. from diff/log/grep/etc.)  is a
+usability annoyance, potentially a huge one since other changes in
+history may dwarf the changes they are interested in.
+
+Some of these users also arrive at this usecase from wanting to use partial
+clones together with sparse checkouts (in a way where they have downloaded
+blobs within the sparse specification) and do disconnected development.
+Not only do these users generally not care about other parts of the
+repository, but consider it a blocker for Git commands to try to operate on
+those.  If commands attempt to access paths in history outside the sparsity
+specification, then the partial clone will attempt to download additional
+blobs on demand, fail, and then fail the user's command.  (This may be
+unavoidable in some cases, e.g. when `git merge` has non-trivial changes to
+reconcile outside the sparse specification, but we should limit how often
+users are forced to connect to the network.)
+
+Also, even for users using partial clones that do not mind being
+always connected to the network, the need to download blobs as
+side-effects of various other commands (such as the printed diffstat
+after a merge or pull) can lead to worries about local repository size
+growing unnecessarily[10].
+
+  (Behavior A*) Users are _only_ interested in the sparse portion of the repo
+      that they have downloaded so far (a variant on the first usecase)
+
+This variant is driven by folks who using partial clones together with
+sparse checkouts and do disconnected development (so far sounding like a
+subset of behavior A users) and doing so on very large repositories.  The
+reason for yet another variant is that downloading even just the blobs
+through history within their sparse specification may be too much, so they
+only download some.  They would still like operations to succeed without
+network connectivity, though, so things like `git log -S${SEARCH_TERM} -p`
+or `git grep ${SEARCH_TERM} OLDREV ` would need to be prepared to provide
+partial results that depend on what happens to have been downloaded.
+
+This variant could be viewed as Behavior A with the sparse specification
+for history querying operations modified from "sparsity patterns" to
+"sparsity patterns limited to the blobs we have already downloaded".
+
+  (Behavior B) Users want a sparse working tree, but are working in a
+      larger whole
+
+Stolee described this usecase this way[11]:
+
+"I'm also focused on users that know that they are a part of a larger
+whole. They know they are operating on a large repository but focus on
+what they need to contribute their part. I expect multiple "roles" to
+use very different, almost disjoint parts of the codebase. Some other
+"architect" users operate across the entire tree or hop between different
+sections of the codebase as necessary. In this situation, I'm wary of
+scoping too many features to the sparse-checkout definition, especially
+"git log," as it can be too confusing to have their view of the codebase
+depend on your "point of view."
+
+People might also end up wanting behavior B due to complex inter-project
+dependencies.  The initial attempts to use sparse-checkouts usually involve
+the directories you are directly interested in plus what those directories
+depend upon within your repository.  But there's a monkey wrench here: if
+you have integration tests, they invert the hierarchy: to run integration
+tests, you need not only what you are interested in and its in-tree
+dependencies, you also need everything that depends upon what you are
+interested in or that depends upon one of your dependencies...AND you need
+all the in-tree dependencies of that expanded group.  That can easily
+change your sparse-checkout into a nearly dense one.
+
+Naturally, that tends to kill the benefits of sparse-checkouts.  There are
+a couple solutions to this conundrum: either avoid grabbing in-repo
+dependencies (maybe have built versions of your in-repo dependencies pulled
+from a CI cache somewhere), or say that users shouldn't run integration
+tests directly and instead do it on the CI server when they submit a code
+review.  Or do both.  Regardless of whether you stub out your in-repo
+dependencies or stub out the things that depend upon you, there is
+certainly a reason to want to query and be aware of those other stubbed-out
+parts of the repository, particularly when the dependencies are complex or
+change relatively frequently.  Thus, for such uses, sparse-checkouts can be
+used to limit what you directly build and modify, but these users do not
+necessarily want their sparse checkout paths to limit their queries of
+versions in history.
+
+Some people may also be interested in behavior B over behavior A simply as
+a performance workaround: if they are using non-cone mode, then they have
+to deal with its inherent quadratic performance problems.  In that mode,
+every operation that checks whether paths match the sparsity specification
+can be expensive.  As such, these users may only be willing to pay for
+those expensive checks when interacting with the working copy, and may
+prefer getting "unrelated" results from their history queries over having
+slow commands.
+
+  (Behavior C) sparse-checkout is an implementational detail supporting a
+	       special VFS.
+
+This usecase goes slightly against the traditional definition of
+sparse-checkout in that it actually tries to present a full or dense
+checkout to the user.  However, this usecase utilizes the same underlying
+technical underpinnings in a new way which does provide some performance
+advantages to users.  The basic idea is that a company can have an in-house
+Git-aware Virtual File System which pretends all files are present in the
+working tree, by intercepting all file system accesses and using those to
+fetch and write accessed files on demand via partial clones.  The VFS uses
+sparse-checkout to prevent Git from writing or paying attention to many
+files, and manually updates the sparse checkout patterns itself based on
+user access and modification of files in the working tree.  See commit
+ecc7c8841d ("repo_read_index: add config to expect files outside sparse
+patterns", 2022-02-25) and the link at [17] for a more detailed description
+of such a VFS.
+
+The biggest difference here is that users are completely unaware that the
+sparse-checkout machinery is even in use.  The sparse patterns are not
+specified by the user but rather are under the complete control of the VFS
+(and the patterns are updated frequently and dynamically by it).  The user
+will perceive the checkout as dense, and commands should thus behave as if
+all files are present.
+
+
+=== Usecases of primary concern ===
+
+Most of the rest of this document will focus on Behavior A and Behavior
+B.  Some notes about the other two cases and why we are not focusing on
+them:
+
+  (Behavior A*)
+
+Supporting this usecase is estimated to be difficult and a lot of work.
+There are no plans to implement it currently, but it may be a potential
+future alternative.  Knowing about the existence of additional alternatives
+may affect our choice of command line flags (e.g. if we need tri-state or
+quad-state flags rather than just binary flags), so it was still important
+to at least note.
+
+Further, I believe the descriptions below for Behavior A are probably still
+valid for this usecase, with the only exception being that it redefines the
+sparse specification to restrict it to already-downloaded blobs.  The hard
+part is in making commands capable of respecting that modified definition.
+
+  (Behavior C)
+
+This usecase violates some of the early sparse-checkout documented
+assumptions (since files marked as SKIP_WORKTREE will be displayed to users
+as present in the working tree).  That violation may mean various
+sparse-checkout related behaviors are not well suited to this usecase and
+we may need tweaks -- to both documentation and code -- to handle it.
+However, this usecase is also perhaps the simplest model to support in that
+everything behaves like a dense checkout with a few exceptions (e.g. branch
+checkouts and switches write fewer things, knowing the VFS will lazily
+write the rest on an as-needed basis).
+
+Since there is no publicly available VFS-related code for folks to try,
+the number of folks who can test such a usecase is limited.
+
+The primary reason to note the Behavior C usecase is that as we fix things
+to better support Behaviors A and B, there may be additional places where
+we need to make tweaks allowing folks in this usecase to get the original
+non-sparse treatment.  For an example, see ecc7c8841d ("repo_read_index:
+add config to expect files outside sparse patterns", 2022-02-25).  The
+secondary reason to note Behavior C, is so that folks taking advantage of
+Behavior C do not assume they are part of the Behavior B camp and propose
+patches that break things for the real Behavior B folks.
+
+
+=== Oversimplified mental models ===
+
+An oversimplification of the differences in the above behaviors is:
+
+  Behavior A: Restrict worktree and history operations to sparse specification
+  Behavior B: Restrict worktree operations to sparse specification; have any
+	      history operations work across all files
+  Behavior C: Do not restrict either worktree or history operations to the
+	      sparse specification...with the exception of branch checkouts or
+	      switches which avoid writing files that will match the index so
+	      they can later lazily be populated instead.
+
+
+=== Desired behavior ===
+
+As noted previously, despite the simple idea of just working with a subset
+of files, there are a range of different behavioral changes that need to be
+made to different subcommands to work well with such a feature.  See
+[1,2,3,4,5,6,7,8,9,10] for various examples.  In particular, at [2], we saw
+that mere composition of other commands that individually worked correctly
+in a sparse-checkout context did not imply that the higher level command
+would work correctly; it sometimes requires further tweaks.  So,
+understanding these differences can be beneficial.
+
+* Commands behaving the same regardless of high-level use-case
+
+  * commands that only look at files within the sparsity specification
+
+      * diff (without --cached or REVISION arguments)
+      * grep (without --cached or REVISION arguments)
+      * diff-files
+
+  * commands that restore files to the working tree that match sparsity
+    patterns, and remove unmodified files that don't match those
+    patterns:
+
+      * switch
+      * checkout (the switch-like half)
+      * read-tree
+      * reset --hard
+
+  * commands that write conflicted files to the working tree, but otherwise
+    will omit writing files to the working tree that do not match the
+    sparsity patterns:
+
+      * merge
+      * rebase
+      * cherry-pick
+      * revert
+
+      * `am` and `apply --cached` should probably be in this section but
+	are buggy (see the "Known bugs" section below)
+
+    The behavior for these commands somewhat depends upon the merge
+    strategy being used:
+      * `ort` behaves as described above
+      * `recursive` tries to not vivify files unnecessarily, but does sometimes
+	vivify files without conflicts.
+      * `octopus` and `resolve` will always vivify any file changed in the merge
+	relative to the first parent, which is rather suboptimal.
+
+    It is also important to note that these commands WILL update the index
+    outside the sparse specification relative to when the operation began,
+    BUT these commands often make a commit just before or after such that
+    by the end of the operation there is no change to the index outside the
+    sparse specification.  Of course, if the operation hits conflicts or
+    does not make a commit, then these operations clearly can modify the
+    index outside the sparse specification.
+
+    Finally, it is important to note that at least the first four of these
+    commands also try to remove differences between the sparse
+    specification and the sparsity patterns (much like the commands in the
+    previous section).
+
+  * commands that always ignore sparsity since commits must be full-tree
+
+      * archive
+      * bundle
+      * commit
+      * format-patch
+      * fast-export
+      * fast-import
+      * commit-tree
+
+  * commands that write any modified file to the working tree (conflicted
+    or not, and whether those paths match sparsity patterns or not):
+
+      * stash
+      * apply (without `--index` or `--cached`)
+
+* Commands that may slightly differ for behavior A vs. behavior B:
+
+  Commands in this category behave mostly the same between the two
+  behaviors, but may differ in verbosity and types of warning and error
+  messages.
+
+  * commands that make modifications to which files are tracked:
+      * add
+      * rm
+      * mv
+      * update-index
+
+    The fact that files can move between the 'tracked' and 'untracked'
+    categories means some commands will have to treat untracked files
+    differently.  But if we have to treat untracked files differently,
+    then additional commands may also need changes:
+
+      * status
+      * clean
+
+    In particular, `status` may need to report any untracked files outside
+    the sparsity specification as an erroneous condition (especially to
+    avoid the user trying to `git add` them, forcing `git add` to display
+    an error).
+
+    It's not clear to me exactly how (or even if) `clean` would change,
+    but it's the other command that also affects untracked files.
+
+    `update-index` may be slightly special.  Its --[no-]skip-worktree flag
+    may need to ignore the sparse specification by its nature.  Also, its
+    current --[no-]ignore-skip-worktree-entries default is totally bogus.
+
+  * commands for manually tweaking paths in both the index and the working tree
+      * `restore`
+      * the restore-like half of `checkout`
+
+    These commands should be similar to add/rm/mv in that they should
+    only operate on the sparse specification by default, and require a
+    special flag to operate on all files.
+
+    Also, note that these commands currently have a number of issues (see
+    the "Known bugs" section below)
+
+* Commands that significantly differ for behavior A vs. behavior B:
+
+  * commands that query history
+      * diff (with --cached or REVISION arguments)
+      * grep (with --cached or REVISION arguments)
+      * show (when given commit arguments)
+      * blame (only matters when one or more -C flags are passed)
+	* and annotate
+      * log
+      * whatchanged
+      * ls-files
+      * diff-index
+      * diff-tree
+      * ls-tree
+
+    Note: for log and whatchanged, revision walking logic is unaffected
+    but displaying of patches is affected by scoping the command to the
+    sparse-checkout.  (The fact that revision walking is unaffected is
+    why rev-list, shortlog, show-branch, and bisect are not in this
+    list.)
+
+    ls-files may be slightly special in that e.g. `git ls-files -t` is
+    often used to see what is sparse and what is not.  Perhaps -t should
+    always work on the full tree?
+
+* Commands I don't know how to classify
+
+  * range-diff
+
+    Is this like `log` or `format-patch`?
+
+  * cherry
+
+    See range-diff
+
+* Commands unaffected by sparse-checkouts
+
+  * shortlog
+  * show-branch
+  * rev-list
+  * bisect
+
+  * branch
+  * describe
+  * fetch
+  * gc
+  * init
+  * maintenance
+  * notes
+  * pull (merge & rebase have the necessary changes)
+  * push
+  * submodule
+  * tag
+
+  * config
+  * filter-branch (works in separate checkout without sparse-checkout setup)
+  * pack-refs
+  * prune
+  * remote
+  * repack
+  * replace
+
+  * bugreport
+  * count-objects
+  * fsck
+  * gitweb
+  * help
+  * instaweb
+  * merge-tree (doesn't touch worktree or index, and merges always compute full-tree)
+  * rerere
+  * verify-commit
+  * verify-tag
+
+  * commit-graph
+  * hash-object
+  * index-pack
+  * mktag
+  * mktree
+  * multi-pack-index
+  * pack-objects
+  * prune-packed
+  * symbolic-ref
+  * unpack-objects
+  * update-ref
+  * write-tree (operates on index, possibly optimized to use sparse dir entries)
+
+  * for-each-ref
+  * get-tar-commit-id
+  * ls-remote
+  * merge-base (merges are computed full tree, so merge base should be too)
+  * name-rev
+  * pack-redundant
+  * rev-parse
+  * show-index
+  * show-ref
+  * unpack-file
+  * var
+  * verify-pack
+
+  * <Everything under 'Interacting with Others' in 'git help --all'>
+  * <Everything under 'Low-level...Syncing' in 'git help --all'>
+  * <Everything under 'Low-level...Internal Helpers' in 'git help --all'>
+  * <Everything under 'External commands' in 'git help --all'>
+
+* Commands that might be affected, but who cares?
+
+  * merge-file
+  * merge-index
+  * gitk?
+
+
+=== Behavior classes ===
+
+From the above there are a few classes of behavior:
+
+  * "restrict"
+
+    Commands in this class only read or write files in the working tree
+    within the sparse specification.
+
+    When moving to a new commit (e.g. switch, reset --hard), these commands
+    may update index files outside the sparse specification as of the start
+    of the operation, but by the end of the operation those index files
+    will match HEAD again and thus those files will again be outside the
+    sparse specification.
+
+    When paths are explicitly specified, these paths are intersected with
+    the sparse specification and will only operate on such paths.
+    (e.g. `git restore [--staged] -- '*.png'`, `git reset -p -- '*.md'`)
+
+    Some of these commands may also attempt, at the end of their operation,
+    to cull transient differences between the sparse specification and the
+    sparsity patterns (see "Sparse specification vs. sparsity patterns" for
+    details, but this basically means either removing unmodified files not
+    matching the sparsity patterns and marking those files as
+    SKIP_WORKTREE, or vivifying files that match the sparsity patterns and
+    marking those files as !SKIP_WORKTREE).
+
+  * "restrict modulo conflicts"
+
+    Commands in this class generally behave like the "restrict" class,
+    except that:
+      (1) they will ignore the sparse specification and write files with
+	  conflicts to the working tree (thus temporarily expanding the
+	  sparse specification to include such files.)
+      (2) they are grouped with commands which move to a new commit, since
+	  they often create a commit and then move to it, even though we
+	  know there are many exceptions to moving to the new commit.  (For
+	  example, the user may rebase a commit that becomes empty, or have
+	  a cherry-pick which conflicts, or a user could run `merge
+	  --no-commit`, and we also view `apply --index` kind of like `am
+	  --no-commit`.)  As such, these commands can make changes to index
+	  files outside the sparse specification, though they'll mark such
+	  files with SKIP_WORKTREE.
+
+  * "restrict also specially applied to untracked files"
+
+    Commands in this class generally behave like the "restrict" class,
+    except that they have to handle untracked files differently too, often
+    because these commands are dealing with files changing state between
+    'tracked' and 'untracked'.  Often, this may mean printing an error
+    message if the command had nothing to do, but the arguments may have
+    referred to files whose tracked-ness state could have changed were it
+    not for the sparsity patterns excluding them.
+
+  * "no restrict"
+
+    Commands in this class ignore the sparse specification entirely.
+
+  * "restrict or no restrict dependent upon behavior A vs. behavior B"
+
+    Commands in this class behave like "no restrict" for folks in the
+    behavior B camp, and like "restrict" for folks in the behavior A camp.
+    However, when behaving like "restrict" a warning of some sort might be
+    provided that history queries have been limited by the sparse-checkout
+    specification.
+
+
+=== Subcommand-dependent defaults ===
+
+Note that we have different defaults depending on the command for the
+desired behavior :
+
+  * Commands defaulting to "restrict":
+    * diff-files
+    * diff (without --cached or REVISION arguments)
+    * grep (without --cached or REVISION arguments)
+    * switch
+    * checkout (the switch-like half)
+    * reset (<commit>)
+
+    * restore
+    * checkout (the restore-like half)
+    * checkout-index
+    * reset (with pathspec)
+
+    This behavior makes sense; these interact with the working tree.
+
+  * Commands defaulting to "restrict modulo conflicts":
+    * merge
+    * rebase
+    * cherry-pick
+    * revert
+
+    * am
+    * apply --index (which is kind of like an `am --no-commit`)
+
+    * read-tree (especially with -m or -u; is kind of like a --no-commit merge)
+    * reset (<tree-ish>, due to similarity to read-tree)
+
+    These also interact with the working tree, but require slightly
+    different behavior either so that (a) conflicts can be resolved or (b)
+    because they are kind of like a merge-without-commit operation.
+
+    (See also the "Known bugs" section below regarding `am` and `apply`)
+
+  * Commands defaulting to "no restrict":
+    * archive
+    * bundle
+    * commit
+    * format-patch
+    * fast-export
+    * fast-import
+    * commit-tree
+
+    * stash
+    * apply (without `--index`)
+
+    These have completely different defaults and perhaps deserve the most
+    detailed explanation:
+
+    In the case of commands in the first group (format-patch,
+    fast-export, bundle, archive, etc.), these are commands for
+    communicating history, which will be broken if they restrict to a
+    subset of the repository.  As such, they operate on full paths and
+    have no `--restrict` option for overriding.  Some of these commands may
+    take paths for manually restricting what is exported, but it needs to
+    be very explicit.
+
+    In the case of stash, it needs to vivify files to avoid losing the
+    user's changes.
+
+    In the case of apply without `--index`, that command needs to update
+    the working tree without the index (or the index without the working
+    tree if `--cached` is passed), and if we restrict those updates to the
+    sparse specification then we'll lose changes from the user.
+
+  * Commands defaulting to "restrict also specially applied to untracked files":
+    * add
+    * rm
+    * mv
+    * update-index
+    * status
+    * clean (?)
+
+    Our original implementation for the first three of these commands was
+    "no restrict", but it had some severe usability issues:
+      * `git add <somefile>` if honored and outside the sparse
+	specification, can result in the file randomly disappearing later
+	when some subsequent command is run (since various commands
+	automatically clean up unmodified files outside the sparse
+	specification).
+      * `git rm '*.jpg'` could very negatively surprise users if it deletes
+	files outside the range of the user's interest.
+      * `git mv` has similar surprises when moving into or out of the cone,
+	so best to restrict by default
+
+    So, we switched `add` and `rm` to default to "restrict", which made
+    usability problems much less severe and less frequent, but we still got
+    complaints because commands like:
+	git add <file-outside-sparse-specification>
+	git rm <file-outside-sparse-specification>
+    would silently do nothing.  We should instead print an error in those
+    cases to get usability right.
+
+    update-index needs to be updated to match, and status and maybe clean
+    also need to be updated to specially handle untracked paths.
+
+    There may be a difference in here between behavior A and behavior B in
+    terms of verboseness of errors or additional warnings.
+
+  * Commands falling under "restrict or no restrict dependent upon behavior
+    A vs. behavior B"
+
+    * diff (with --cached or REVISION arguments)
+    * grep (with --cached or REVISION arguments)
+    * show (when given commit arguments)
+    * blame (only matters when one or more -C flags passed)
+      * and annotate
+    * log
+      * and variants: shortlog, gitk, show-branch, whatchanged, rev-list
+    * ls-files
+    * diff-index
+    * diff-tree
+    * ls-tree
+
+    For now, we default to behavior B for these, which want a default of
+    "no restrict".
+
+    Note that two of these commands -- diff and grep -- also appeared in a
+    different list with a default of "restrict", but only when limited to
+    searching the working tree.  The working tree vs. history distinction
+    is fundamental in how behavior B operates, so this is expected.  Note,
+    though, that for diff and grep with --cached, when doing "restrict"
+    behavior, the difference between sparse specification and sparsity
+    patterns is important to handle.
+
+    "restrict" may make more sense as the long term default for these[12].
+    Also, supporting "restrict" for these commands might be a fair amount
+    of work to implement, meaning it might be implemented over multiple
+    releases.  If that behavior were the default in the commands that
+    supported it, that would force behavior B users to need to learn to
+    slowly add additional flags to their commands, depending on git
+    version, to get the behavior they want.  That gradual switchover would
+    be painful, so we should avoid it at least until it's fully
+    implemented.
+
+
+=== Sparse specification vs. sparsity patterns ===
+
+In a well-behaved situation, the sparse specification is given directly
+by the $GIT_DIR/info/sparse-checkout file.  However, it can transiently
+diverge for a few reasons:
+
+    * needing to resolve conflicts (merging will vivify conflicted files)
+    * running Git commands that implicitly vivify files (e.g. "git stash apply")
+    * running Git commands that explicitly vivify files (e.g. "git checkout
+      --ignore-skip-worktree-bits FILENAME")
+    * other commands that write to these files (perhaps a user copies it
+      from elsewhere)
+
+For the last item, note that we do automatically clear the SKIP_WORKTREE
+bit for files that are present in the working tree.  This has been true
+since 82386b4496 ("Merge branch 'en/present-despite-skipped'",
+2022-03-09)
+
+However, such a situation is transient because:
+
+   * Such transient differences can and will be automatically removed as
+     a side-effect of commands which call unpack_trees() (checkout,
+     merge, reset, etc.).
+   * Users can also request such transient differences be corrected via
+     running `git sparse-checkout reapply`.  Various places recommend
+     running that command.
+   * Additional commands are also welcome to implicitly fix these
+     differences; we may add more in the future.
+
+While we avoid dropping unstaged changes or files which have conflicts,
+we otherwise aggressively try to fix these transient differences.  If
+users want these differences to persist, they should run the `set` or
+`add` subcommands of `git sparse-checkout` to reflect their intended
+sparse specification.
+
+However, when we need to do a query on history restricted to the
+"relevant subset of files" such a transiently expanded sparse
+specification is ignored.  There are a couple reasons for this:
+
+   * The behavior wanted when doing something like
+	 git grep expression REVISION
+     is roughly what the users would expect from
+	 git checkout REVISION && git grep expression
+     (modulo a "REVISION:" prefix), which has a couple ramifications:
+
+   * REVISION may have paths not in the current index, so there is no
+     path we can consult for a SKIP_WORKTREE setting for those paths.
+
+   * Since `checkout` is one of those commands that tries to remove
+     transient differences in the sparse specification, it makes sense
+     to use the corrected sparse specification
+     (i.e. $GIT_DIR/info/sparse-checkout) rather than attempting to
+     consult SKIP_WORKTREE anyway.
+
+So, a transiently expanded (or restricted) sparse specification applies to
+the working tree, but not to history queries where we always use the
+sparsity patterns.  (See [16] for an early discussion of this.)
+
+Similar to a transiently expanded sparse specification of the working tree
+based on additional files being present in the working tree, we also need
+to consider additional files being modified in the index.  In particular,
+if the user has staged changes to files (relative to HEAD) that do not
+match the sparsity patterns, and the file is not present in the working
+tree, we still want to consider the file part of the sparse specification
+if we are specifically performing a query related to the index (e.g. git
+diff --cached [REVISION], git diff-index [REVISION], git restore --staged
+--source=REVISION -- PATHS, etc.)  Note that a transiently expanded sparse
+specification for the index usually only matters under behavior A, since
+under behavior B index operations are lumped with history and tend to
+operate full-tree.
+
+
+=== Implementation Questions ===
+
+  * Do the options --scope={sparse,all} sound good to others?  Are there better
+    options?
+    * Names in use, or appearing in patches, or previously suggested:
+      * --sparse/--dense
+      * --ignore-skip-worktree-bits
+      * --ignore-skip-worktree-entries
+      * --ignore-sparsity
+      * --[no-]restrict-to-sparse-paths
+      * --full-tree/--sparse-tree
+      * --[no-]restrict
+      * --scope={sparse,all}
+      * --focus/--unfocus
+      * --limit/--unlimited
+    * Rationale making me lean slightly towards --scope={sparse,all}:
+      * We want a name that works for many commands, so we need a name that
+	does not conflict
+      * We know that we have more than two possible usecases, so it is best
+	to avoid a flag that appears to be binary.
+      * --scope={sparse,all} isn't overly long and seems relatively
+	explanatory
+      * `--sparse`, as used in add/rm/mv, is totally backwards for
+	grep/log/etc.  Changing the meaning of `--sparse` for these
+	commands would fix the backwardness, but possibly break existing
+	scripts.  Using a new name pairing would allow us to treat
+	`--sparse` in these commands as a deprecated alias.
+      * There is a different `--sparse`/`--dense` pair for commands using
+	revision machinery, so using that naming might cause confusion
+      * There is also a `--sparse` in both pack-objects and show-branch, which
+	don't conflict but do suggest that `--sparse` is overloaded
+      * The name --ignore-skip-worktree-bits is a double negative, is
+	quite a mouthful, refers to an implementation detail that many
+	users may not be familiar with, and we'd need a negation for it
+	which would probably be even more ridiculously long.  (But we
+	can make --ignore-skip-worktree-bits a deprecated alias for
+	--no-restrict.)
+
+  * If a config option is added (sparse.scope?) what should the values and
+    description be?  "sparse" (behavior A), "worktree-sparse-history-dense"
+    (behavior B), "dense" (behavior C)?  There's a risk of confusion,
+    because even for Behaviors A and B we want some commands to be
+    full-tree and others to operate sparsely, so the wording may need to be
+    more tied to the usecases and somehow explain that.  Also, right now,
+    the primary difference we are focusing is just the history-querying
+    commands (log/diff/grep).  Previous config suggestion here: [13]
+
+  * Is `--no-expand` a good alias for ls-files's `--sparse` option?
+    (`--sparse` does not map to either `--scope=sparse` or `--scope=all`,
+    because in non-cone mode it does nothing and in cone-mode it shows the
+    sparse directory entries which are technically outside the sparse
+    specification)
+
+  * Under Behavior A:
+    * Does ls-files' `--no-expand` override the default `--scope=all`, or
+      does it need an extra flag?
+    * Does ls-files' `-t` option imply `--scope=all`?
+    * Does update-index's `--[no-]skip-worktree` option imply `--scope=all`?
+
+  * sparse-checkout: once behavior A is fully implemented, should we take
+    an interim measure to ease people into switching the default?  Namely,
+    if folks are not already in a sparse checkout, then require
+    `sparse-checkout init/set` to take a
+    `--set-scope=(sparse|worktree-sparse-history-dense|dense)` flag (which
+    would set sparse.scope according to the setting given), and throw an
+    error if the flag is not provided?  That error would be a great place
+    to warn folks that the default may change in the future, and get them
+    used to specifying what they want so that the eventual default switch
+    is seamless for them.
+
+
+=== Implementation Goals/Plans ===
+
+ * Get buy-in on this document in general.
+
+ * Figure out answers to the 'Implementation Questions' sections (above)
+
+ * Fix bugs in the 'Known bugs' section (below)
+
+ * Provide some kind of method for backfilling the blobs within the sparse
+   specification in a partial clone
+
+ [Below here is kind of spitballing since the first two haven't been resolved]
+
+ * update-index: flip the default to --no-ignore-skip-worktree-entries,
+   nuke this stupid "Oh, there's a bug?  Let me add a flag to let users
+   request that they not trigger this bug." flag
+
+ * Flags & Config
+   * Make `--sparse` in add/rm/mv a deprecated alias for `--scope=all`
+   * Make `--ignore-skip-worktree-bits` in checkout-index/checkout/restore
+     a deprecated aliases for `--scope=all`
+   * Create config option (sparse.scope?), tie it to the "Cliff notes"
+     overview
+
+   * Add --scope=sparse (and --scope=all) flag to each of the history querying
+     commands.  IMPORTANT: make sure diff machinery changes don't mess with
+     format-patch, fast-export, etc.
+
+=== Known bugs ===
+
+This list used to be a lot longer (see e.g. [1,2,3,4,5,6,7,8,9]), but we've
+been working on it.
+
+0. Behavior A is not well supported in Git.  (Behavior B didn't used to
+   be either, but was the easier of the two to implement.)
+
+1. am and apply:
+
+   apply, without `--index` or `--cached`, relies on files being present
+   in the working copy, and also writes to them unconditionally.  As
+   such, it should first check for the files' presence, and if found to
+   be SKIP_WORKTREE, then clear the bit and vivify the paths, then do
+   its work.  Currently, it just throws an error.
+
+   apply, with either `--cached` or `--index`, will not preserve the
+   SKIP_WORKTREE bit.  This is fine if the file has conflicts, but
+   otherwise SKIP_WORKTREE bits should be preserved for --cached and
+   probably also for --index.
+
+   am, if there are no conflicts, will vivify files and fail to preserve
+   the SKIP_WORKTREE bit.  If there are conflicts and `-3` is not
+   specified, it will vivify files and then complain the patch doesn't
+   apply.  If there are conflicts and `-3` is specified, it will vivify
+   files and then complain that those vivified files would be
+   overwritten by merge.
+
+2. reset --hard:
+
+   reset --hard provides confusing error message (works correctly, but
+   misleads the user into believing it didn't):
+
+    $ touch addme
+    $ git add addme
+    $ git ls-files -t
+    H addme
+    H tracked
+    S tracked-but-maybe-skipped
+    $ git reset --hard                           # usually works great
+    error: Path 'addme' not uptodate; will not remove from working tree.
+    HEAD is now at bdbbb6f third
+    $ git ls-files -t
+    H tracked
+    S tracked-but-maybe-skipped
+    $ ls -1
+    tracked
+
+    `git reset --hard` DID remove addme from the index and the working tree, contrary
+    to the error message, but in line with how reset --hard should behave.
+
+3. read-tree
+
+   `read-tree` doesn't apply the 'SKIP_WORKTREE' bit to *any* of the
+   entries it reads into the index, resulting in all your files suddenly
+   appearing to be "deleted".
+
+4. Checkout, restore:
+
+   These command do not handle path & revision arguments appropriately:
+
+    $ ls
+    tracked
+    $ git ls-files -t
+    H tracked
+    S tracked-but-maybe-skipped
+    $ git status --porcelain
+    $ git checkout -- '*skipped'
+    error: pathspec '*skipped' did not match any file(s) known to git
+    $ git ls-files -- '*skipped'
+    tracked-but-maybe-skipped
+    $ git checkout HEAD -- '*skipped'
+    error: pathspec '*skipped' did not match any file(s) known to git
+    $ git ls-tree HEAD | grep skipped
+    100644 blob 276f5a64354b791b13840f02047738c77ad0584f	tracked-but-maybe-skipped
+    $ git status --porcelain
+    $ git checkout HEAD~1 -- '*skipped'
+    $ git ls-files -t
+    H tracked
+    H tracked-but-maybe-skipped
+    $ git status --porcelain
+    M  tracked-but-maybe-skipped
+    $ git checkout HEAD -- '*skipped'
+    $ git status --porcelain
+    $
+
+    Note that checkout without a revision (or restore --staged) fails to
+    find a file to restore from the index, even though ls-files shows
+    such a file certainly exists.
+
+    Similar issues occur with HEAD (--source=HEAD in restore's case),
+    but suddenly works when HEAD~1 is specified.  And then after that it
+    will work with HEAD specified, even though it didn't before.
+
+    Directories are also an issue:
+
+    $ git sparse-checkout set nomatches
+    $ git status
+    On branch main
+    You are in a sparse checkout with 0% of tracked files present.
+
+    nothing to commit, working tree clean
+    $ git checkout .
+    error: pathspec '.' did not match any file(s) known to git
+    $ git checkout HEAD~1 .
+    Updated 1 path from 58916d9
+    $ git ls-files -t
+    S tracked
+    H tracked-but-maybe-skipped
+
+5. checkout and restore --staged, continued:
+
+   These commands do not correctly scope operations to the sparse
+   specification, and make it worse by not setting important SKIP_WORKTREE
+   bits:
+
+   $ git restore --source OLDREV --staged outside-sparse-cone/
+   $ git status --porcelain
+   MD outside-sparse-cone/file1
+   MD outside-sparse-cone/file2
+   MD outside-sparse-cone/file3
+
+   We can add a --scope=all mode to `git restore` to let it operate outside
+   the sparse specification, but then it will be important to set the
+   SKIP_WORKTREE bits appropriately.
+
+6. Performance issues; see:
+    https://lore.kernel.org/git/CABPp-BEkJQoKZsQGCYioyga_uoDQ6iBeW+FKr8JhyuuTMK1RDw@xxxxxxxxxxxxxx/
+
+
+=== Reference Emails ===
+
+Emails that detail various bugs we've had in sparse-checkout:
+
+[1] (Original descriptions of behavior A & behavior B)
+    https://lore.kernel.org/git/CABPp-BGJ_Nvi5TmgriD9Bh6eNXE2EDq2f8e8QKXAeYG3BxZafA@xxxxxxxxxxxxxx/
+[2] (Fix stash applications in sparse checkouts; bugs from behavioral differences)
+    https://lore.kernel.org/git/ccfedc7140dbf63ba26a15f93bd3885180b26517.1606861519.git.gitgitgadget@xxxxxxxxx/
+[3] (Present-despite-skipped entries)
+    https://lore.kernel.org/git/11d46a399d26c913787b704d2b7169cafc28d639.1642175983.git.gitgitgadget@xxxxxxxxx/
+[4] (Clone --no-checkout interaction)
+    https://lore.kernel.org/git/pull.801.v2.git.git.1591324899170.gitgitgadget@xxxxxxxxx/ (clone --no-checkout)
+[5] (The need for update_sparsity() and avoiding `read-tree -mu HEAD`)
+    https://lore.kernel.org/git/3a1f084641eb47515b5a41ed4409a36128913309.1585270142.git.gitgitgadget@xxxxxxxxx/
+[6] (SKIP_WORKTREE is advisory, not mandatory)
+    https://lore.kernel.org/git/844306c3e86ef67591cc086decb2b760e7d710a3.1585270142.git.gitgitgadget@xxxxxxxxx/
+[7] (`worktree add` should copy sparsity settings from current worktree)
+    https://lore.kernel.org/git/c51cb3714e7b1d2f8c9370fe87eca9984ff4859f.1644269584.git.gitgitgadget@xxxxxxxxx/
+[8] (Avoid negative surprises in add, rm, and mv)
+    https://lore.kernel.org/git/cover.1617914011.git.matheus.bernardino@xxxxxx/
+    https://lore.kernel.org/git/pull.1018.v4.git.1632497954.gitgitgadget@xxxxxxxxx/
+[9] (Move from out-of-cone to in-cone)
+    https://lore.kernel.org/git/20220630023737.473690-6-shaoxuan.yuan02@xxxxxxxxx/
+    https://lore.kernel.org/git/20220630023737.473690-4-shaoxuan.yuan02@xxxxxxxxx/
+[10] (Unnecessarily downloading objects outside sparse specification)
+     https://lore.kernel.org/git/CAOLTT8QfwOi9yx_qZZgyGa8iL8kHWutEED7ok_jxwTcYT_hf9Q@xxxxxxxxxxxxxx/
+
+[11] (Stolee's comments on high-level usecases)
+     https://lore.kernel.org/git/1a1e33f6-3514-9afc-0a28-5a6b85bd8014@xxxxxxxxx/
+
+[12] Others commenting on eventually switching default to behavior A:
+  * https://lore.kernel.org/git/xmqqh719pcoo.fsf@gitster.g/
+  * https://lore.kernel.org/git/xmqqzgeqw0sy.fsf@gitster.g/
+  * https://lore.kernel.org/git/a86af661-cf58-a4e5-0214-a67d3a794d7e@xxxxxxxxxx/
+
+[13] Previous config name suggestion and description
+  * https://lore.kernel.org/git/CABPp-BE6zW0nJSStcVU=_DoDBnPgLqOR8pkTXK3dW11=T01OhA@xxxxxxxxxxxxxx/
+
+[14] Tangential issue: switch to cone mode as default sparse specification mechanism:
+  https://lore.kernel.org/git/a1b68fd6126eb341ef3637bb93fedad4309b36d0.1650594746.git.gitgitgadget@xxxxxxxxx/
+
+[15] Lengthy email on grep behavior, covering what should be searched:
+  * https://lore.kernel.org/git/CABPp-BGVO3QdbfE84uF_3QDF0-y2iHHh6G5FAFzNRfeRitkuHw@xxxxxxxxxxxxxx/
+
+[16] Email explaining sparsity patterns vs. SKIP_WORKTREE and history operations,
+     search for the parenthetical comment starting "We do not check".
+    https://lore.kernel.org/git/CABPp-BFsCPPNOZ92JQRJeGyNd0e-TCW-LcLyr0i_+VSQJP+GCg@xxxxxxxxxxxxxx/
+
+[17] https://lore.kernel.org/git/20220207190320.2960362-1-jonathantanmy@xxxxxxxxxx/
diff --git a/Documentation/technical/sparse-index.adoc b/Documentation/technical/sparse-index.adoc
new file mode 100644
index 0000000000..3b24c1a219
--- /dev/null
+++ b/Documentation/technical/sparse-index.adoc
@@ -0,0 +1,208 @@
+Git Sparse-Index Design Document
+================================
+
+The sparse-checkout feature allows users to focus a working directory on
+a subset of the files at HEAD. The cone mode patterns, enabled by
+`core.sparseCheckoutCone`, allow for very fast pattern matching to
+discover which files at HEAD belong in the sparse-checkout cone.
+
+Three important scale dimensions for a Git working directory are:
+
+* `HEAD`: How many files are present at `HEAD`?
+
+* Populated: How many files are within the sparse-checkout cone.
+
+* Modified: How many files has the user modified in the working directory?
+
+We will use big-O notation -- O(X) -- to denote how expensive certain
+operations are in terms of these dimensions.
+
+These dimensions are ordered by their magnitude: users (typically) modify
+fewer files than are populated, and we can only populate files at `HEAD`.
+
+Problems occur if there is an extreme imbalance in these dimensions. For
+example, if `HEAD` contains millions of paths but the populated set has
+only tens of thousands, then commands like `git status` and `git add` can
+be dominated by operations that require O(`HEAD`) operations instead of
+O(Populated). Primarily, the cost is in parsing and rewriting the index,
+which is filled primarily with files at `HEAD` that are marked with the
+`SKIP_WORKTREE` bit.
+
+The sparse-index intends to take these commands that read and modify the
+index from O(`HEAD`) to O(Populated). To do this, we need to modify the
+index format in a significant way: add "sparse directory" entries.
+
+With cone mode patterns, it is possible to detect when an entire
+directory will have its contents outside of the sparse-checkout definition.
+Instead of listing all of the files it contains as individual entries, a
+sparse-index contains an entry with the directory name, referencing the
+object ID of the tree at `HEAD` and marked with the `SKIP_WORKTREE` bit.
+If we need to discover the details for paths within that directory, we
+can parse trees to find that list.
+
+At time of writing, sparse-directory entries violate expectations about the
+index format and its in-memory data structure. There are many consumers in
+the codebase that expect to iterate through all of the index entries and
+see only files. In fact, these loops expect to see a reference to every
+staged file. One way to handle this is to parse trees to replace a
+sparse-directory entry with all of the files within that tree as the index
+is loaded. However, parsing trees is slower than parsing the index format,
+so that is a slower operation than if we left the index alone. The plan is
+to make all of these integrations "sparse aware" so this expansion through
+tree parsing is unnecessary and they use fewer resources than when using a
+full index.
+
+The implementation plan below follows four phases to slowly integrate with
+the sparse-index. The intention is to incrementally update Git commands to
+interact safely with the sparse-index without significant slowdowns. This
+may not always be possible, but the hope is that the primary commands that
+users need in their daily work are dramatically improved.
+
+Phase I: Format and initial speedups
+------------------------------------
+
+During this phase, Git learns to enable the sparse-index and safely parse
+one. Protections are put in place so that every consumer of the in-memory
+data structure can operate with its current assumption of every file at
+`HEAD`.
+
+At first, every index parse will call a helper method,
+`ensure_full_index()`, which scans the index for sparse-directory entries
+(pointing to trees) and replaces them with the full list of paths (with
+blob contents) by parsing tree objects. This will be slower in all cases.
+The only noticeable change in behavior will be that the serialized index
+file contains sparse-directory entries.
+
+To start, we use a new required index extension, `sdir`, to allow
+inserting sparse-directory entries into indexes with file format
+versions 2, 3, and 4. This prevents Git versions that do not understand
+the sparse-index from operating on one, while allowing tools that do not
+understand the sparse-index to operate on repositories as long as they do
+not interact with the index. A new format, index v5, will be introduced
+that includes sparse-directory entries by default. It might also
+introduce other features that have been considered for improving the
+index, as well.
+
+Next, consumers of the index will be guarded against operating on a
+sparse-index by inserting calls to `ensure_full_index()` or
+`expand_index_to_path()`. If a specific path is requested, then those will
+be protected from within the `index_file_exists()` and `index_name_pos()`
+API calls: they will call `ensure_full_index()` if necessary. The
+intention here is to preserve existing behavior when interacting with a
+sparse-checkout. We don't want a change to happen by accident, without
+tests. Many of these locations may not need any change before removing the
+guards, but we should not do so without tests to ensure the expected
+behavior happens.
+
+It may be desirable to _change_ the behavior of some commands in the
+presence of a sparse index or more generally in any sparse-checkout
+scenario. In such cases, these should be carefully communicated and
+tested. No such behavior changes are intended during this phase.
+
+During a scan of the codebase, not every iteration of the cache entries
+needs an `ensure_full_index()` check. The basic reasons include:
+
+1. The loop is scanning for entries with non-zero stage. These entries
+   are not collapsed into a sparse-directory entry.
+
+2. The loop is scanning for submodules. These entries are not collapsed
+   into a sparse-directory entry.
+
+3. The loop is part of the index API, especially around reading or
+   writing the format.
+
+4. The loop is checking for correct order of cache entries and that is
+   correct if and only if the sparse-directory entries are in the correct
+   location.
+
+5. The loop ignores entries with the `SKIP_WORKTREE` bit set, or is
+   otherwise already aware of sparse directory entries.
+
+6. The sparse-index is disabled at this point when using the split-index
+   feature, so no effort is made to protect the split-index API.
+
+Even after inserting these guards, we will keep expanding sparse-indexes
+for most Git commands using the `command_requires_full_index` repository
+setting. This setting will be on by default and disabled one builtin at a
+time until we have sufficient confidence that all of the index operations
+are properly guarded.
+
+To complete this phase, the commands `git status` and `git add` will be
+integrated with the sparse-index so that they operate with O(Populated)
+performance. They will be carefully tested for operations within and
+outside the sparse-checkout definition.
+
+Phase II: Careful integrations
+------------------------------
+
+This phase focuses on ensuring that all index extensions and APIs work
+well with a sparse-index. This requires significant increases to our test
+coverage, especially for operations that interact with the working
+directory outside of the sparse-checkout definition. Some of these
+behaviors may not be the desirable ones, such as some tests already
+marked for failure in `t1092-sparse-checkout-compatibility.sh`.
+
+The index extensions that may require special integrations are:
+
+* FS Monitor
+* Untracked cache
+
+While integrating with these features, we should look for patterns that
+might lead to better APIs for interacting with the index. Coalescing
+common usage patterns into an API call can reduce the number of places
+where sparse-directories need to be handled carefully.
+
+Phase III: Important command speedups
+-------------------------------------
+
+At this point, the patterns for testing and implementing sparse-directory
+logic should be relatively stable. This phase focuses on updating some of
+the most common builtins that use the index to operate as O(Populated).
+Here is a potential list of commands that could be valuable to integrate
+at this point:
+
+* `git commit`
+* `git checkout`
+* `git merge`
+* `git rebase`
+
+Hopefully, commands such as `git merge` and `git rebase` can benefit
+instead from merge algorithms that do not use the index as a data
+structure, such as the merge-ORT strategy. As these topics mature, we
+may enable the ORT strategy by default for repositories using the
+sparse-index feature.
+
+Along with `git status` and `git add`, these commands cover the majority
+of users' interactions with the working directory. In addition, we can
+integrate with these commands:
+
+* `git grep`
+* `git rm`
+
+These have been proposed as some whose behavior could change when in a
+repo with a sparse-checkout definition. It would be good to include this
+behavior automatically when using a sparse-index. Some clarity is needed
+to make the behavior switch clear to the user.
+
+This phase is the first where parallel work might be possible without too
+much conflicts between topics.
+
+Phase IV: The long tail
+-----------------------
+
+This last phase is less a "phase" and more "the new normal" after all of
+the previous work.
+
+To start, the `command_requires_full_index` option could be removed in
+favor of expanding only when hitting an API guard.
+
+There are many Git commands that could use special attention to operate as
+O(Populated), while some might be so rare that it is acceptable to leave
+them with additional overhead when a sparse-index is present.
+
+Here are some commands that might be useful to update:
+
+* `git sparse-checkout set`
+* `git am`
+* `git clean`
+* `git stash`
diff --git a/Documentation/technical/trivial-merge.adoc b/Documentation/technical/trivial-merge.adoc
new file mode 100644
index 0000000000..1f1c33d0da
--- /dev/null
+++ b/Documentation/technical/trivial-merge.adoc
@@ -0,0 +1,121 @@
+Trivial merge rules
+===================
+
+This document describes the outcomes of the trivial merge logic in read-tree.
+
+One-way merge
+-------------
+
+This replaces the index with a different tree, keeping the stat info
+for entries that don't change, and allowing -u to make the minimum
+required changes to the working tree to have it match.
+
+Entries marked '+' have stat information. Spaces marked '*' don't
+affect the result.
+
+   index   tree    result
+   -----------------------
+   *       (empty) (empty)
+   (empty) tree    tree
+   index+  tree    tree
+   index+  index   index+
+
+Two-way merge
+-------------
+
+It is permitted for the index to lack an entry; this does not prevent
+any case from applying.
+
+If the index exists, it is an error for it not to match either the old
+or the result.
+
+If multiple cases apply, the one used is listed first.
+
+A result which changes the index is an error if the index is not empty
+and not up to date.
+
+Entries marked '+' have stat information. Spaces marked '*' don't
+affect the result.
+
+ case  index   old     new     result
+ -------------------------------------
+ 0/2   (empty) *       (empty) (empty)
+ 1/3   (empty) *       new     new
+ 4/5   index+  (empty) (empty) index+
+ 6/7   index+  (empty) index   index+
+ 10    index+  index   (empty) (empty)
+ 14/15 index+  old     old     index+
+ 18/19 index+  old     index   index+
+ 20    index+  index   new     new
+
+Three-way merge
+---------------
+
+It is permitted for the index to lack an entry; this does not prevent
+any case from applying.
+
+If the index exists, it is an error for it not to match either the
+head or (if the merge is trivial) the result.
+
+If multiple cases apply, the one used is listed first.
+
+A result of "no merge" means that index is left in stage 0, ancest in
+stage 1, head in stage 2, and remote in stage 3 (if any of these are
+empty, no entry is left for that stage). Otherwise, the given entry is
+left in stage 0, and there are no other entries.
+
+A result of "no merge" is an error if the index is not empty and not
+up to date.
+
+*empty* means that the tree must not have a directory-file conflict
+ with the entry.
+
+For multiple ancestors, a '+' means that this case applies even if
+only one ancestor or remote fits; a '^' means all of the ancestors
+must be the same.
+
+ case  ancest    head    remote    result
+ ----------------------------------------
+ 1     (empty)+  (empty) (empty)   (empty)
+ 2ALT  (empty)+  *empty* remote    remote
+ 2     (empty)^  (empty) remote    no merge
+ 3ALT  (empty)+  head    *empty*   head
+ 3     (empty)^  head    (empty)   no merge
+ 4     (empty)^  head    remote    no merge
+ 5ALT  *         head    head      head
+ 6     ancest+   (empty) (empty)   no merge
+ 8     ancest^   (empty) ancest    no merge
+ 7     ancest+   (empty) remote    no merge
+ 10    ancest^   ancest  (empty)   no merge
+ 9     ancest+   head    (empty)   no merge
+ 16    anc1/anc2 anc1    anc2      no merge
+ 13    ancest+   head    ancest    head
+ 14    ancest+   ancest  remote    remote
+ 11    ancest+   head    remote    no merge
+
+Only #2ALT and #3ALT use *empty*, because these are the only cases
+where there can be conflicts that didn't exist before. Note that we
+allow directory-file conflicts between things in different stages
+after the trivial merge.
+
+A possible alternative for #6 is (empty), which would make it like
+#1. This is not used, due to the likelihood that it arises due to
+moving the file to multiple different locations or moving and deleting
+it in different branches.
+
+Case #1 is included for completeness, and also in case we decide to
+put on '+' markings; any path that is never mentioned at all isn't
+handled.
+
+Note that #16 is when both #13 and #14 apply; in this case, we refuse
+the trivial merge, because we can't tell from this data which is
+right. This is a case of a reverted patch (in some direction, maybe
+multiple times), and the right answer depends on looking at crossings
+of history or common ancestors of the ancestors.
+
+Note that, between #6, #7, #9, and #11, all cases not otherwise
+covered are handled in this table.
+
+For #8 and #10, there is alternative behavior, not currently
+implemented, where the result is (empty). As currently implemented,
+the automatic merge will generally give this effect.
diff --git a/Documentation/technical/unit-tests.adoc b/Documentation/technical/unit-tests.adoc
new file mode 100644
index 0000000000..5a432b7b29
--- /dev/null
+++ b/Documentation/technical/unit-tests.adoc
@@ -0,0 +1,242 @@
+= Unit Testing
+
+In our current testing environment, we spend a significant amount of effort
+crafting end-to-end tests for error conditions that could easily be captured by
+unit tests (or we simply forgo some hard-to-setup and rare error conditions).
+Unit tests additionally provide stability to the codebase and can simplify
+debugging through isolation. Writing unit tests in pure C, rather than with our
+current shell/test-tool helper setup, simplifies test setup, simplifies passing
+data around (no shell-isms required), and reduces testing runtime by not
+spawning a separate process for every test invocation.
+
+We believe that a large body of unit tests, living alongside the existing test
+suite, will improve code quality for the Git project.
+
+== Definitions
+
+For the purposes of this document, we'll use *test framework* to refer to
+projects that support writing test cases and running tests within the context
+of a single executable. *Test harness* will refer to projects that manage
+running multiple executables (each of which may contain multiple test cases) and
+aggregating their results.
+
+In reality, these terms are not strictly defined, and many of the projects
+discussed below contain features from both categories.
+
+For now, we will evaluate projects solely on their framework features. Since we
+are relying on having TAP output (see below), we can assume that any framework
+can be made to work with a harness that we can choose later.
+
+
+== Summary
+
+We believe the best way forward is to implement a custom TAP framework for the
+Git project. We use a version of the framework originally proposed in
+https://lore.kernel.org/git/c902a166-98ce-afba-93f2-ea6027557176@xxxxxxxxx/[1].
+
+See the <<framework-selection,Framework Selection>> section below for the
+rationale behind this decision.
+
+
+== Choosing a test harness
+
+During upstream discussion, it was occasionally noted that `prove` provides many
+convenient features, such as scheduling slower tests first, or re-running
+previously failed tests.
+
+While we already support the use of `prove` as a test harness for the shell
+tests, it is not strictly required. The t/Makefile allows running shell tests
+directly (though with interleaved output if parallelism is enabled). Git
+developers who wish to use `prove` as a more advanced harness can do so by
+setting DEFAULT_TEST_TARGET=prove in their config.mak.
+
+We will follow a similar approach for unit tests: by default the test
+executables will be run directly from the t/Makefile, but `prove` can be
+configured with DEFAULT_UNIT_TEST_TARGET=prove.
+
+
+[[framework-selection]]
+== Framework selection
+
+There are a variety of features we can use to rank the candidate frameworks, and
+those features have different priorities:
+
+* Critical features: we probably won't consider a framework without these
+** Can we legally / easily use the project?
+*** <<license,License>>
+*** <<vendorable-or-ubiquitous,Vendorable or ubiquitous>>
+*** <<maintainable-extensible,Maintainable / extensible>>
+*** <<major-platform-support,Major platform support>>
+** Does the project support our bare-minimum needs?
+*** <<tap-support,TAP support>>
+*** <<diagnostic-output,Diagnostic output>>
+*** <<runtime-skippable-tests,Runtime-skippable tests>>
+* Nice-to-have features:
+** <<parallel-execution,Parallel execution>>
+** <<mock-support,Mock support>>
+** <<signal-error-handling,Signal & error-handling>>
+* Tie-breaker stats
+** <<project-kloc,Project KLOC>>
+** <<adoption,Adoption>>
+
+[[license]]
+=== License
+
+We must be able to legally use the framework in connection with Git. As Git is
+licensed only under GPLv2, we must eliminate any LGPLv3, GPLv3, or Apache 2.0
+projects.
+
+[[vendorable-or-ubiquitous]]
+=== Vendorable or ubiquitous
+
+We want to avoid forcing Git developers to install new tools just to run unit
+tests. Any prospective frameworks and harnesses must either be vendorable
+(meaning, we can copy their source directly into Git's repository), or so
+ubiquitous that it is reasonable to expect that most developers will have the
+tools installed already.
+
+[[maintainable-extensible]]
+=== Maintainable / extensible
+
+It is unlikely that any pre-existing project perfectly fits our needs, so any
+project we select will need to be actively maintained and open to accepting
+changes. Alternatively, assuming we are vendoring the source into our repo, it
+must be simple enough that Git developers can feel comfortable making changes as
+needed to our version.
+
+In the comparison table below, "True" means that the framework seems to have
+active developers, that it is simple enough that Git developers can make changes
+to it, and that the project seems open to accepting external contributions (or
+that it is vendorable). "Partial" means that at least one of the above
+conditions holds.
+
+[[major-platform-support]]
+=== Major platform support
+
+At a bare minimum, unit-testing must work on Linux, MacOS, and Windows.
+
+In the comparison table below, "True" means that it works on all three major
+platforms with no issues. "Partial" means that there may be annoyances on one or
+more platforms, but it is still usable in principle.
+
+[[tap-support]]
+=== TAP support
+
+The https://testanything.org/[Test Anything Protocol] is a text-based interface
+that allows tests to communicate with a test harness. It is already used by
+Git's integration test suite. Supporting TAP output is a mandatory feature for
+any prospective test framework.
+
+In the comparison table below, "True" means this is natively supported.
+"Partial" means TAP output must be generated by post-processing the native
+output.
+
+Frameworks that do not have at least Partial support will not be evaluated
+further.
+
+[[diagnostic-output]]
+=== Diagnostic output
+
+When a test case fails, the framework must generate enough diagnostic output to
+help developers find the appropriate test case in source code in order to debug
+the failure.
+
+[[runtime-skippable-tests]]
+=== Runtime-skippable tests
+
+Test authors may wish to skip certain test cases based on runtime circumstances,
+so the framework should support this.
+
+[[parallel-execution]]
+=== Parallel execution
+
+Ideally, we will build up a significant collection of unit test cases, most
+likely split across multiple executables. It will be necessary to run these
+tests in parallel to enable fast develop-test-debug cycles.
+
+In the comparison table below, "True" means that individual test cases within a
+single test executable can be run in parallel. We assume that executable-level
+parallelism can be handled by the test harness.
+
+[[mock-support]]
+=== Mock support
+
+Unit test authors may wish to test code that interacts with objects that may be
+inconvenient to handle in a test (e.g. interacting with a network service).
+Mocking allows test authors to provide a fake implementation of these objects
+for more convenient tests.
+
+[[signal-error-handling]]
+=== Signal & error handling
+
+The test framework should fail gracefully when test cases are themselves buggy
+or when they are interrupted by signals during runtime.
+
+[[project-kloc]]
+=== Project KLOC
+
+The size of the project, in thousands of lines of code as measured by
+https://dwheeler.com/sloccount/[sloccount] (rounded up to the next multiple of
+1,000). As a tie-breaker, we probably prefer a project with fewer LOC.
+
+[[adoption]]
+=== Adoption
+
+As a tie-breaker, we prefer a more widely-used project. We use the number of
+GitHub / GitLab stars to estimate this.
+
+
+=== Comparison
+
+:true: [lime-background]#True#
+:false: [red-background]#False#
+:partial: [yellow-background]#Partial#
+
+:gpl: [lime-background]#GPL v2#
+:isc: [lime-background]#ISC#
+:mit: [lime-background]#MIT#
+:expat: [lime-background]#Expat#
+:lgpl: [lime-background]#LGPL v2.1#
+
+:custom-impl: https://lore.kernel.org/git/c902a166-98ce-afba-93f2-ea6027557176@xxxxxxxxx/[Custom Git impl.]
+:greatest: https://github.com/silentbicycle/greatest[Greatest]
+:criterion: https://github.com/Snaipe/Criterion[Criterion]
+:c-tap: https://github.com/rra/c-tap-harness/[C TAP]
+:check: https://libcheck.github.io/check/[Check]
+:clar: https://github.com/clar-test/clar[Clar]
+
+[format="csv",options="header",width="33%",subs="specialcharacters,attributes,quotes,macros"]
+|=====
+Framework,"<<license,License>>","<<vendorable-or-ubiquitous,Vendorable or ubiquitous>>","<<maintainable-extensible,Maintainable / extensible>>","<<major-platform-support,Major platform support>>","<<tap-support,TAP support>>","<<diagnostic-output,Diagnostic output>>","<<runtime--skippable-tests,Runtime- skippable tests>>","<<parallel-execution,Parallel execution>>","<<mock-support,Mock support>>","<<signal-error-handling,Signal & error handling>>","<<project-kloc,Project KLOC>>","<<adoption,Adoption>>"
+{custom-impl},{gpl},{true},{true},{true},{true},{true},{true},{false},{false},{false},1,0
+{greatest},{isc},{true},{partial},{true},{partial},{true},{true},{false},{false},{false},3,1400
+{criterion},{mit},{false},{partial},{true},{true},{true},{true},{true},{false},{true},19,1800
+{c-tap},{expat},{true},{partial},{partial},{true},{false},{true},{false},{false},{false},4,33
+{check},{lgpl},{false},{partial},{true},{true},{true},{false},{false},{false},{true},17,973
+{clar},{isc},{false},{partial},{true},{true},{true},{true},{false},{false},{true},1,192
+|=====
+
+=== Additional framework candidates
+
+Several suggested frameworks have been eliminated from consideration:
+
+* Incompatible licenses:
+** https://github.com/zorgnax/libtap[libtap] (LGPL v3)
+** https://cmocka.org/[cmocka] (Apache 2.0)
+* Missing source: https://www.kindahl.net/mytap/doc/index.html[MyTap]
+* No TAP support:
+** https://nemequ.github.io/munit/[µnit]
+** https://github.com/google/cmockery[cmockery]
+** https://github.com/lpabon/cmockery2[cmockery2]
+** https://github.com/ThrowTheSwitch/Unity[Unity]
+** https://github.com/siu/minunit[minunit]
+** https://cunit.sourceforge.net/[CUnit]
+
+
+== Milestones
+
+* Add useful tests of library-like code
+* Integrate with
+  https://lore.kernel.org/git/20230502211454.1673000-1-calvinwan@xxxxxxxxxx/[stdlib
+  work]
+* Run alongside regular `make test` target
diff --git a/Documentation/texi.xsl b/Documentation/texi.xsl
new file mode 100644
index 0000000000..0f8ff07eca
--- /dev/null
+++ b/Documentation/texi.xsl
@@ -0,0 +1,26 @@
+<!-- texi.xsl:
+     convert refsection elements into refsect elements that docbook2texi can
+     understand -->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
+		version="1.0">
+
+<xsl:output method="xml"
+	    encoding="UTF-8"
+	    doctype-public="-//OASIS//DTD DocBook XML V4.5//EN"
+	    doctype-system="http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"; />
+
+<xsl:template match="//refsection">
+	<xsl:variable name="element">refsect<xsl:value-of select="count(ancestor-or-self::refsection)" /></xsl:variable>
+	<xsl:element name="{$element}">
+		<xsl:apply-templates select="@*|node()" />
+	</xsl:element>
+</xsl:template>
+
+<!-- Copy all other nodes through. -->
+<xsl:template match="node()|@*">
+	<xsl:copy>
+		<xsl:apply-templates select="@*|node()" />
+	</xsl:copy>
+</xsl:template>
+
+</xsl:stylesheet>
diff --git a/Documentation/trace2-target-values.adoc b/Documentation/trace2-target-values.adoc
new file mode 100644
index 0000000000..06f1953313
--- /dev/null
+++ b/Documentation/trace2-target-values.adoc
@@ -0,0 +1,12 @@
+--
+* `0` or `false` - Disables the target.
+* `1` or `true` - Writes to `STDERR`.
+* `[2-9]` - Writes to the already opened file descriptor.
+* `<absolute-pathname>` - Writes to the file in append mode. If the target
+already exists and is a directory, the traces will be written to files (one
+per process) underneath the given directory.
+* `af_unix:[<socket-type>:]<absolute-pathname>` - Write to a
+Unix DomainSocket (on platforms that support them).  Socket
+type can be either `stream` or `dgram`; if omitted Git will
+try both.
+--
diff --git a/Documentation/transfer-data-leaks.adoc b/Documentation/transfer-data-leaks.adoc
new file mode 100644
index 0000000000..914bacc39e
--- /dev/null
+++ b/Documentation/transfer-data-leaks.adoc
@@ -0,0 +1,30 @@
+SECURITY
+--------
+The fetch and push protocols are not designed to prevent one side from
+stealing data from the other repository that was not intended to be
+shared. If you have private data that you need to protect from a malicious
+peer, your best option is to store it in another repository. This applies
+to both clients and servers. In particular, namespaces on a server are not
+effective for read access control; you should only grant read access to a
+namespace to clients that you would trust with read access to the entire
+repository.
+
+The known attack vectors are as follows:
+
+. The victim sends "have" lines advertising the IDs of objects it has that
+  are not explicitly intended to be shared but can be used to optimize the
+  transfer if the peer also has them. The attacker chooses an object ID X
+  to steal and sends a ref to X, but isn't required to send the content of
+  X because the victim already has it. Now the victim believes that the
+  attacker has X, and it sends the content of X back to the attacker
+  later. (This attack is most straightforward for a client to perform on a
+  server, by creating a ref to X in the namespace the client has access
+  to and then fetching it. The most likely way for a server to perform it
+  on a client is to "merge" X into a public branch and hope that the user
+  does additional work on this branch and pushes it back to the server
+  without noticing the merge.)
+
+. As in #1, the attacker chooses an object ID X to steal. The victim sends
+  an object Y that the attacker already has, and the attacker falsely
+  claims to have X and not Y, so the victim sends Y as a delta against X.
+  The delta reveals regions of X that are similar to Y to the attacker.
diff --git a/Documentation/urls-remotes.adoc b/Documentation/urls-remotes.adoc
new file mode 100644
index 0000000000..9b10151198
--- /dev/null
+++ b/Documentation/urls-remotes.adoc
@@ -0,0 +1,96 @@
+include::urls.adoc[]
+
+REMOTES[[REMOTES]]
+------------------
+
+The name of one of the following can be used instead
+of a URL as `<repository>` argument:
+
+* a remote in the Git configuration file: `$GIT_DIR/config`,
+* a file in the `$GIT_DIR/remotes` directory, or
+* a file in the `$GIT_DIR/branches` directory.
+
+All of these also allow you to omit the refspec from the command line
+because they each contain a refspec which git will use by default.
+
+Named remote in configuration file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can choose to provide the name of a remote which you had previously
+configured using linkgit:git-remote[1], linkgit:git-config[1]
+or even by a manual edit to the `$GIT_DIR/config` file.  The URL of
+this remote will be used to access the repository.  The refspec
+of this remote will be used by default when you do
+not provide a refspec on the command line.  The entry in the
+config file would appear like this:
+
+------------
+	[remote "<name>"]
+		url = <URL>
+		pushurl = <pushurl>
+		push = <refspec>
+		fetch = <refspec>
+------------
+
+The `<pushurl>` is used for pushes only. It is optional and defaults
+to `<URL>`. Pushing to a remote affects all defined pushurls or all
+defined urls if no pushurls are defined. Fetch, however, will only
+fetch from the first defined url if multiple urls are defined.
+
+Named file in `$GIT_DIR/remotes`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can choose to provide the name of a
+file in `$GIT_DIR/remotes`.  The URL
+in this file will be used to access the repository.  The refspec
+in this file will be used as default when you do not
+provide a refspec on the command line.  This file should have the
+following format:
+
+------------
+	URL: one of the above URL formats
+	Push: <refspec>
+	Pull: <refspec>
+
+------------
+
+`Push:` lines are used by 'git push' and
+`Pull:` lines are used by 'git pull' and 'git fetch'.
+Multiple `Push:` and `Pull:` lines may
+be specified for additional branch mappings.
+
+Named file in `$GIT_DIR/branches`
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can choose to provide the name of a
+file in `$GIT_DIR/branches`.
+The URL in this file will be used to access the repository.
+This file should have the following format:
+
+
+------------
+	<URL>#<head>
+------------
+
+`<URL>` is required; `#<head>` is optional.
+
+Depending on the operation, git will use one of the following
+refspecs, if you don't provide one on the command line.
+`<branch>` is the name of this file in `$GIT_DIR/branches` and
+`<head>` defaults to `master`.
+
+git fetch uses:
+
+------------
+	refs/heads/<head>:refs/heads/<branch>
+------------
+
+git push uses:
+
+------------
+	HEAD:refs/heads/<head>
+------------
+
+
+
+
diff --git a/Documentation/urls.adoc b/Documentation/urls.adoc
new file mode 100644
index 0000000000..9c871e716a
--- /dev/null
+++ b/Documentation/urls.adoc
@@ -0,0 +1,110 @@
+GIT URLS[[URLS]]
+----------------
+
+In general, URLs contain information about the transport protocol, the
+address of the remote server, and the path to the repository.
+Depending on the transport protocol, some of this information may be
+absent.
+
+Git supports ssh, git, http, and https protocols (in addition, ftp
+and ftps can be used for fetching, but this is inefficient and
+deprecated; do not use them).
+
+The native transport (i.e. `git://` URL) does no authentication and
+should be used with caution on unsecured networks.
+
+The following syntaxes may be used with them:
+
+- `ssh://[<user>@]<host>[:<port>]/<path-to-git-repo>`
+- `git://<host>[:<port>]/<path-to-git-repo>`
+- `http[s]://<host>[:<port>]/<path-to-git-repo>`
+- `ftp[s]://<host>[:<port>]/<path-to-git-repo>`
+
+An alternative scp-like syntax may also be used with the ssh protocol:
+
+- `[<user>@]<host>:/<path-to-git-repo>`
+
+This syntax is only recognized if there are no slashes before the
+first colon. This helps differentiate a local path that contains a
+colon. For example the local path `foo:bar` could be specified as an
+absolute path or `./foo:bar` to avoid being misinterpreted as an ssh
+url.
+
+The ssh and git protocols additionally support `~<username>` expansion:
+
+- `ssh://[<user>@]<host>[:<port>]/~<user>/<path-to-git-repo>`
+- `git://<host>[:<port>]/~<user>/<path-to-git-repo>`
+- `[<user>@]<host>:~<user>/<path-to-git-repo>`
+
+For local repositories, also supported by Git natively, the following
+syntaxes may be used:
+
+- `/path/to/repo.git/`
+- `file:///path/to/repo.git/`
+
+ifndef::git-clone[]
+These two syntaxes are mostly equivalent, except when cloning, when
+the former implies `--local` option. See linkgit:git-clone[1] for
+details.
+endif::git-clone[]
+
+ifdef::git-clone[]
+These two syntaxes are mostly equivalent, except the former implies
+`--local` option.
+endif::git-clone[]
+
+`git clone`, `git fetch` and `git pull`, but not `git push`, will also
+accept a suitable bundle file. See linkgit:git-bundle[1].
+
+When Git doesn't know how to handle a certain transport protocol, it
+attempts to use the `remote-<transport>` remote helper, if one
+exists. To explicitly request a remote helper, the following syntax
+may be used:
+
+- `<transport>::<address>`
+
+where _<address>_ may be a path, a server and path, or an arbitrary
+URL-like string recognized by the specific remote helper being
+invoked. See linkgit:gitremote-helpers[7] for details.
+
+If there are a large number of similarly-named remote repositories and
+you want to use a different format for them (such that the URLs you
+use will be rewritten into URLs that work), you can create a
+configuration section of the form:
+
+[verse]
+--
+	[url "__<actual-url-base>__"]
+		insteadOf = _<other-url-base>_
+--
+
+For example, with this:
+
+------------
+	[url "git://git.host.xz/"]
+		insteadOf = host.xz:/path/to/
+		insteadOf = work:
+------------
+
+a URL like "work:repo.git" or like "host.xz:/path/to/repo.git" will be
+rewritten in any context that takes a URL to be "git://git.host.xz/repo.git".
+
+If you want to rewrite URLs for push only, you can create a
+configuration section of the form:
+
+[verse]
+--
+	[url "__<actual-url-base>__"]
+		pushInsteadOf = _<other-url-base>_
+--
+
+For example, with this:
+
+------------
+	[url "ssh://example.org/"]
+		pushInsteadOf = git://example.org/
+------------
+
+a URL like "git://example.org/path/to/repo.git" will be rewritten to
+"ssh://example.org/path/to/repo.git" for pushes, but pulls will still
+use the original URL.
diff --git a/Documentation/user-manual.adoc b/Documentation/user-manual.adoc
new file mode 100644
index 0000000000..d2b478ad23
--- /dev/null
+++ b/Documentation/user-manual.adoc
@@ -0,0 +1,4638 @@
+= Git User Manual
+
+[preface]
+== Introduction
+
+Git is a fast distributed revision control system.
+
+This manual is designed to be readable by someone with basic UNIX
+command-line skills, but no previous knowledge of Git.
+
+<<repositories-and-branches>> and <<exploring-git-history>> explain how
+to fetch and study a project using git--read these chapters to learn how
+to build and test a particular version of a software project, search for
+regressions, and so on.
+
+People needing to do actual development will also want to read
+<<Developing-With-git>> and <<sharing-development>>.
+
+Further chapters cover more specialized topics.
+
+Comprehensive reference documentation is available through the man
+pages, or linkgit:git-help[1] command.  For example, for the command
+`git clone <repo>`, you can either use:
+
+------------------------------------------------
+$ man git-clone
+------------------------------------------------
+
+or:
+
+------------------------------------------------
+$ git help clone
+------------------------------------------------
+
+With the latter, you can use the manual viewer of your choice; see
+linkgit:git-help[1] for more information.
+
+See also <<git-quick-start>> for a brief overview of Git commands,
+without any explanation.
+
+Finally, see <<todo>> for ways that you can help make this manual more
+complete.
+
+
+[[repositories-and-branches]]
+== Repositories and Branches
+
+[[how-to-get-a-git-repository]]
+=== How to get a Git repository
+
+It will be useful to have a Git repository to experiment with as you
+read this manual.
+
+The best way to get one is by using the linkgit:git-clone[1] command to
+download a copy of an existing repository.  If you don't already have a
+project in mind, here are some interesting examples:
+
+------------------------------------------------
+	# Git itself (approx. 40MB download):
+$ git clone git://git.kernel.org/pub/scm/git/git.git
+	# the Linux kernel (approx. 640MB download):
+$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
+------------------------------------------------
+
+The initial clone may be time-consuming for a large project, but you
+will only need to clone once.
+
+The clone command creates a new directory named after the project
+(`git` or `linux` in the examples above).  After you cd into this
+directory, you will see that it contains a copy of the project files,
+called the <<def_working_tree,working tree>>, together with a special
+top-level directory named `.git`, which contains all the information
+about the history of the project.
+
+[[how-to-check-out]]
+=== How to check out a different version of a project
+
+Git is best thought of as a tool for storing the history of a collection
+of files.  It stores the history as a compressed collection of
+interrelated snapshots of the project's contents.  In Git each such
+version is called a <<def_commit,commit>>.
+
+Those snapshots aren't necessarily all arranged in a single line from
+oldest to newest; instead, work may simultaneously proceed along
+parallel lines of development, called <<def_branch,branches>>, which may
+merge and diverge.
+
+A single Git repository can track development on multiple branches.  It
+does this by keeping a list of <<def_head,heads>> which reference the
+latest commit on each branch; the linkgit:git-branch[1] command shows
+you the list of branch heads:
+
+------------------------------------------------
+$ git branch
+* master
+------------------------------------------------
+
+A freshly cloned repository contains a single branch head, by default
+named "master", with the working directory initialized to the state of
+the project referred to by that branch head.
+
+Most projects also use <<def_tag,tags>>.  Tags, like heads, are
+references into the project's history, and can be listed using the
+linkgit:git-tag[1] command:
+
+------------------------------------------------
+$ git tag -l
+v2.6.11
+v2.6.11-tree
+v2.6.12
+v2.6.12-rc2
+v2.6.12-rc3
+v2.6.12-rc4
+v2.6.12-rc5
+v2.6.12-rc6
+v2.6.13
+...
+------------------------------------------------
+
+Tags are expected to always point at the same version of a project,
+while heads are expected to advance as development progresses.
+
+Create a new branch head pointing to one of these versions and check it
+out using linkgit:git-switch[1]:
+
+------------------------------------------------
+$ git switch -c new v2.6.13
+------------------------------------------------
+
+The working directory then reflects the contents that the project had
+when it was tagged v2.6.13, and linkgit:git-branch[1] shows two
+branches, with an asterisk marking the currently checked-out branch:
+
+------------------------------------------------
+$ git branch
+  master
+* new
+------------------------------------------------
+
+If you decide that you'd rather see version 2.6.17, you can modify
+the current branch to point at v2.6.17 instead, with
+
+------------------------------------------------
+$ git reset --hard v2.6.17
+------------------------------------------------
+
+Note that if the current branch head was your only reference to a
+particular point in history, then resetting that branch may leave you
+with no way to find the history it used to point to; so use this command
+carefully.
+
+[[understanding-commits]]
+=== Understanding History: Commits
+
+Every change in the history of a project is represented by a commit.
+The linkgit:git-show[1] command shows the most recent commit on the
+current branch:
+
+------------------------------------------------
+$ git show
+commit 17cf781661e6d38f737f15f53ab552f1e95960d7
+Author: Linus Torvalds <torvalds@xxxxxxxxxxxxxxx.(none)>
+Date:   Tue Apr 19 14:11:06 2005 -0700
+
+    Remove duplicate getenv(DB_ENVIRONMENT) call
+
+    Noted by Tony Luck.
+
+diff --git a/init-db.c b/init-db.c
+index 65898fa..b002dc6 100644
+--- a/init-db.c
++++ b/init-db.c
+@@ -7,7 +7,7 @@
+ 
+ int main(int argc, char **argv)
+ {
+-	char *sha1_dir = getenv(DB_ENVIRONMENT), *path;
++	char *sha1_dir, *path;
+ 	int len, i;
+ 
+ 	if (mkdir(".git", 0755) < 0) {
+------------------------------------------------
+
+As you can see, a commit shows who made the latest change, what they
+did, and why.
+
+Every commit has a 40-hexdigit id, sometimes called the "object name" or the
+"SHA-1 id", shown on the first line of the `git show` output.  You can usually
+refer to a commit by a shorter name, such as a tag or a branch name, but this
+longer name can also be useful.  Most importantly, it is a globally unique
+name for this commit: so if you tell somebody else the object name (for
+example in email), then you are guaranteed that name will refer to the same
+commit in their repository that it does in yours (assuming their repository
+has that commit at all).  Since the object name is computed as a hash over the
+contents of the commit, you are guaranteed that the commit can never change
+without its name also changing.
+
+In fact, in <<git-concepts>> we shall see that everything stored in Git
+history, including file data and directory contents, is stored in an object
+with a name that is a hash of its contents.
+
+[[understanding-reachability]]
+==== Understanding history: commits, parents, and reachability
+
+Every commit (except the very first commit in a project) also has a
+parent commit which shows what happened before this commit.
+Following the chain of parents will eventually take you back to the
+beginning of the project.
+
+However, the commits do not form a simple list; Git allows lines of
+development to diverge and then reconverge, and the point where two
+lines of development reconverge is called a "merge".  The commit
+representing a merge can therefore have more than one parent, with
+each parent representing the most recent commit on one of the lines
+of development leading to that point.
+
+The best way to see how this works is using the linkgit:gitk[1]
+command; running gitk now on a Git repository and looking for merge
+commits will help understand how Git organizes history.
+
+In the following, we say that commit X is "reachable" from commit Y
+if commit X is an ancestor of commit Y.  Equivalently, you could say
+that Y is a descendant of X, or that there is a chain of parents
+leading from commit Y to commit X.
+
+[[history-diagrams]]
+==== Understanding history: History diagrams
+
+We will sometimes represent Git history using diagrams like the one
+below.  Commits are shown as "o", and the links between them with
+lines drawn with - / and \.  Time goes left to right:
+
+
+................................................
+         o--o--o <-- Branch A
+        /
+ o--o--o <-- master
+        \
+         o--o--o <-- Branch B
+................................................
+
+If we need to talk about a particular commit, the character "o" may
+be replaced with another letter or number.
+
+[[what-is-a-branch]]
+==== Understanding history: What is a branch?
+
+When we need to be precise, we will use the word "branch" to mean a line
+of development, and "branch head" (or just "head") to mean a reference
+to the most recent commit on a branch.  In the example above, the branch
+head named "A" is a pointer to one particular commit, but we refer to
+the line of three commits leading up to that point as all being part of
+"branch A".
+
+However, when no confusion will result, we often just use the term
+"branch" both for branches and for branch heads.
+
+[[manipulating-branches]]
+=== Manipulating branches
+
+Creating, deleting, and modifying branches is quick and easy; here's
+a summary of the commands:
+
+`git branch`::
+	list all branches.
+`git branch <branch>`::
+	create a new branch named `<branch>`, referencing the same
+	point in history as the current branch.
+`git branch <branch> <start-point>`::
+	create a new branch named `<branch>`, referencing
+	`<start-point>`, which may be specified any way you like,
+	including using a branch name or a tag name.
+`git branch -d <branch>`::
+	delete the branch `<branch>`; if the branch is not fully
+	merged in its upstream branch or contained in the current branch,
+	this command will fail with a warning.
+`git branch -D <branch>`::
+	delete the branch `<branch>` irrespective of its merged status.
+`git switch <branch>`::
+	make the current branch `<branch>`, updating the working
+	directory to reflect the version referenced by `<branch>`.
+`git switch -c <new> <start-point>`::
+	create a new branch `<new>` referencing `<start-point>`, and
+	check it out.
+
+The special symbol "HEAD" can always be used to refer to the current
+branch.  In fact, Git uses a file named `HEAD` in the `.git` directory
+to remember which branch is current:
+
+------------------------------------------------
+$ cat .git/HEAD
+ref: refs/heads/master
+------------------------------------------------
+
+[[detached-head]]
+=== Examining an old version without creating a new branch
+
+The `git switch` command normally expects a branch head, but will also
+accept an arbitrary commit when invoked with --detach; for example,
+you can check out the commit referenced by a tag:
+
+------------------------------------------------
+$ git switch --detach v2.6.17
+Note: checking out 'v2.6.17'.
+
+You are in 'detached HEAD' state. You can look around, make experimental
+changes and commit them, and you can discard any commits you make in this
+state without impacting any branches by performing another switch.
+
+If you want to create a new branch to retain commits you create, you may
+do so (now or later) by using -c with the switch command again. Example:
+
+  git switch -c new_branch_name
+
+HEAD is now at 427abfa Linux v2.6.17
+------------------------------------------------
+
+The HEAD then refers to the SHA-1 of the commit instead of to a branch,
+and git branch shows that you are no longer on a branch:
+
+------------------------------------------------
+$ cat .git/HEAD
+427abfa28afedffadfca9dd8b067eb6d36bac53f
+$ git branch
+* (detached from v2.6.17)
+  master
+------------------------------------------------
+
+In this case we say that the HEAD is "detached".
+
+This is an easy way to check out a particular version without having to
+make up a name for the new branch.   You can still create a new branch
+(or tag) for this version later if you decide to.
+
+[[examining-remote-branches]]
+=== Examining branches from a remote repository
+
+The "master" branch that was created at the time you cloned is a copy
+of the HEAD in the repository that you cloned from.  That repository
+may also have had other branches, though, and your local repository
+keeps branches which track each of those remote branches, called
+remote-tracking branches, which you
+can view using the `-r` option to linkgit:git-branch[1]:
+
+------------------------------------------------
+$ git branch -r
+  origin/HEAD
+  origin/html
+  origin/maint
+  origin/man
+  origin/master
+  origin/next
+  origin/seen
+  origin/todo
+------------------------------------------------
+
+In this example, "origin" is called a remote repository, or "remote"
+for short. The branches of this repository are called "remote
+branches" from our point of view. The remote-tracking branches listed
+above were created based on the remote branches at clone time and will
+be updated by `git fetch` (hence `git pull`) and `git push`. See
+<<Updating-a-repository-With-git-fetch>> for details.
+
+You might want to build on one of these remote-tracking branches
+on a branch of your own, just as you would for a tag:
+
+------------------------------------------------
+$ git switch -c my-todo-copy origin/todo
+------------------------------------------------
+
+You can also check out `origin/todo` directly to examine it or
+write a one-off patch.  See <<detached-head,detached head>>.
+
+Note that the name "origin" is just the name that Git uses by default
+to refer to the repository that you cloned from.
+
+[[how-git-stores-references]]
+=== Naming branches, tags, and other references
+
+Branches, remote-tracking branches, and tags are all references to
+commits.  All references are named with a slash-separated path name
+starting with `refs`; the names we've been using so far are actually
+shorthand:
+
+	- The branch `test` is short for `refs/heads/test`.
+	- The tag `v2.6.18` is short for `refs/tags/v2.6.18`.
+	- `origin/master` is short for `refs/remotes/origin/master`.
+
+The full name is occasionally useful if, for example, there ever
+exists a tag and a branch with the same name.
+
+(Newly created refs are actually stored in the `.git/refs` directory,
+under the path given by their name.  However, for efficiency reasons
+they may also be packed together in a single file; see
+linkgit:git-pack-refs[1]).
+
+As another useful shortcut, the "HEAD" of a repository can be referred
+to just using the name of that repository.  So, for example, "origin"
+is usually a shortcut for the HEAD branch in the repository "origin".
+
+For the complete list of paths which Git checks for references, and
+the order it uses to decide which to choose when there are multiple
+references with the same shorthand name, see the "SPECIFYING
+REVISIONS" section of linkgit:gitrevisions[7].
+
+[[Updating-a-repository-With-git-fetch]]
+=== Updating a repository with git fetch
+
+After you clone a repository and commit a few changes of your own, you
+may wish to check the original repository for updates.
+
+The `git-fetch` command, with no arguments, will update all of the
+remote-tracking branches to the latest version found in the original
+repository.  It will not touch any of your own branches--not even the
+"master" branch that was created for you on clone.
+
+[[fetching-branches]]
+=== Fetching branches from other repositories
+
+You can also track branches from repositories other than the one you
+cloned from, using linkgit:git-remote[1]:
+
+-------------------------------------------------
+$ git remote add staging git://git.kernel.org/.../gregkh/staging.git
+$ git fetch staging
+...
+From git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
+ * [new branch]      master     -> staging/master
+ * [new branch]      staging-linus -> staging/staging-linus
+ * [new branch]      staging-next -> staging/staging-next
+-------------------------------------------------
+
+New remote-tracking branches will be stored under the shorthand name
+that you gave `git remote add`, in this case `staging`:
+
+-------------------------------------------------
+$ git branch -r
+  origin/HEAD -> origin/master
+  origin/master
+  staging/master
+  staging/staging-linus
+  staging/staging-next
+-------------------------------------------------
+
+If you run `git fetch <remote>` later, the remote-tracking branches
+for the named `<remote>` will be updated.
+
+If you examine the file `.git/config`, you will see that Git has added
+a new stanza:
+
+-------------------------------------------------
+$ cat .git/config
+...
+[remote "staging"]
+	url = git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
+	fetch = +refs/heads/*:refs/remotes/staging/*
+...
+-------------------------------------------------
+
+This is what causes Git to track the remote's branches; you may modify
+or delete these configuration options by editing `.git/config` with a
+text editor.  (See the "CONFIGURATION FILE" section of
+linkgit:git-config[1] for details.)
+
+[[exploring-git-history]]
+== Exploring Git history
+
+Git is best thought of as a tool for storing the history of a
+collection of files.  It does this by storing compressed snapshots of
+the contents of a file hierarchy, together with "commits" which show
+the relationships between these snapshots.
+
+Git provides extremely flexible and fast tools for exploring the
+history of a project.
+
+We start with one specialized tool that is useful for finding the
+commit that introduced a bug into a project.
+
+[[using-bisect]]
+=== How to use bisect to find a regression
+
+Suppose version 2.6.18 of your project worked, but the version at
+"master" crashes.  Sometimes the best way to find the cause of such a
+regression is to perform a brute-force search through the project's
+history to find the particular commit that caused the problem.  The
+linkgit:git-bisect[1] command can help you do this:
+
+-------------------------------------------------
+$ git bisect start
+$ git bisect good v2.6.18
+$ git bisect bad master
+Bisecting: 3537 revisions left to test after this
+[65934a9a028b88e83e2b0f8b36618fe503349f8e] BLOCK: Make USB storage depend on SCSI rather than selecting it [try #6]
+-------------------------------------------------
+
+If you run `git branch` at this point, you'll see that Git has
+temporarily moved you in "(no branch)". HEAD is now detached from any
+branch and points directly to a commit (with commit id 65934) that
+is reachable from "master" but not from v2.6.18. Compile and test it,
+and see whether it crashes. Assume it does crash. Then:
+
+-------------------------------------------------
+$ git bisect bad
+Bisecting: 1769 revisions left to test after this
+[7eff82c8b1511017ae605f0c99ac275a7e21b867] i2c-core: Drop useless bitmaskings
+-------------------------------------------------
+
+checks out an older version.  Continue like this, telling Git at each
+stage whether the version it gives you is good or bad, and notice
+that the number of revisions left to test is cut approximately in
+half each time.
+
+After about 13 tests (in this case), it will output the commit id of
+the guilty commit.  You can then examine the commit with
+linkgit:git-show[1], find out who wrote it, and mail them your bug
+report with the commit id.  Finally, run
+
+-------------------------------------------------
+$ git bisect reset
+-------------------------------------------------
+
+to return you to the branch you were on before.
+
+Note that the version which `git bisect` checks out for you at each
+point is just a suggestion, and you're free to try a different
+version if you think it would be a good idea.  For example,
+occasionally you may land on a commit that broke something unrelated;
+run
+
+-------------------------------------------------
+$ git bisect visualize
+-------------------------------------------------
+
+which will run gitk and label the commit it chose with a marker that
+says "bisect".  Choose a safe-looking commit nearby, note its commit
+id, and check it out with:
+
+-------------------------------------------------
+$ git reset --hard fb47ddb2db
+-------------------------------------------------
+
+then test, run `bisect good` or `bisect bad` as appropriate, and
+continue.
+
+Instead of `git bisect visualize` and then `git reset --hard
+fb47ddb2db`, you might just want to tell Git that you want to skip
+the current commit:
+
+-------------------------------------------------
+$ git bisect skip
+-------------------------------------------------
+
+In this case, though, Git may not eventually be able to tell the first
+bad one between some first skipped commits and a later bad commit.
+
+There are also ways to automate the bisecting process if you have a
+test script that can tell a good from a bad commit. See
+linkgit:git-bisect[1] for more information about this and other `git
+bisect` features.
+
+[[naming-commits]]
+=== Naming commits
+
+We have seen several ways of naming commits already:
+
+	- 40-hexdigit object name
+	- branch name: refers to the commit at the head of the given
+	  branch
+	- tag name: refers to the commit pointed to by the given tag
+	  (we've seen branches and tags are special cases of
+	  <<how-git-stores-references,references>>).
+	- HEAD: refers to the head of the current branch
+
+There are many more; see the "SPECIFYING REVISIONS" section of the
+linkgit:gitrevisions[7] man page for the complete list of ways to
+name revisions.  Some examples:
+
+-------------------------------------------------
+$ git show fb47ddb2 # the first few characters of the object name
+		    # are usually enough to specify it uniquely
+$ git show HEAD^    # the parent of the HEAD commit
+$ git show HEAD^^   # the grandparent
+$ git show HEAD~4   # the great-great-grandparent
+-------------------------------------------------
+
+Recall that merge commits may have more than one parent; by default,
+`^` and `~` follow the first parent listed in the commit, but you can
+also choose:
+
+-------------------------------------------------
+$ git show HEAD^1   # show the first parent of HEAD
+$ git show HEAD^2   # show the second parent of HEAD
+-------------------------------------------------
+
+In addition to HEAD, there are several other special names for
+commits:
+
+Merges (to be discussed later), as well as operations such as
+`git reset`, which change the currently checked-out commit, generally
+set ORIG_HEAD to the value HEAD had before the current operation.
+
+The `git fetch` operation always stores the head of the last fetched
+branch in FETCH_HEAD.  For example, if you run `git fetch` without
+specifying a local branch as the target of the operation
+
+-------------------------------------------------
+$ git fetch git://example.com/proj.git theirbranch
+-------------------------------------------------
+
+the fetched commits will still be available from FETCH_HEAD.
+
+When we discuss merges we'll also see the special name MERGE_HEAD,
+which refers to the other branch that we're merging in to the current
+branch.
+
+The linkgit:git-rev-parse[1] command is a low-level command that is
+occasionally useful for translating some name for a commit to the object
+name for that commit:
+
+-------------------------------------------------
+$ git rev-parse origin
+e05db0fd4f31dde7005f075a84f96b360d05984b
+-------------------------------------------------
+
+[[creating-tags]]
+=== Creating tags
+
+We can also create a tag to refer to a particular commit; after
+running
+
+-------------------------------------------------
+$ git tag stable-1 1b2e1d63ff
+-------------------------------------------------
+
+You can use `stable-1` to refer to the commit 1b2e1d63ff.
+
+This creates a "lightweight" tag.  If you would also like to include a
+comment with the tag, and possibly sign it cryptographically, then you
+should create a tag object instead; see the linkgit:git-tag[1] man page
+for details.
+
+[[browsing-revisions]]
+=== Browsing revisions
+
+The linkgit:git-log[1] command can show lists of commits.  On its
+own, it shows all commits reachable from the parent commit; but you
+can also make more specific requests:
+
+-------------------------------------------------
+$ git log v2.5..	# commits since (not reachable from) v2.5
+$ git log test..master	# commits reachable from master but not test
+$ git log master..test	# ...reachable from test but not master
+$ git log master...test	# ...reachable from either test or master,
+			#    but not both
+$ git log --since="2 weeks ago" # commits from the last 2 weeks
+$ git log Makefile      # commits which modify Makefile
+$ git log fs/		# ... which modify any file under fs/
+$ git log -S'foo()'	# commits which add or remove any file data
+			# matching the string 'foo()'
+-------------------------------------------------
+
+And of course you can combine all of these; the following finds
+commits since v2.5 which touch the `Makefile` or any file under `fs`:
+
+-------------------------------------------------
+$ git log v2.5.. Makefile fs/
+-------------------------------------------------
+
+You can also ask git log to show patches:
+
+-------------------------------------------------
+$ git log -p
+-------------------------------------------------
+
+See the `--pretty` option in the linkgit:git-log[1] man page for more
+display options.
+
+Note that git log starts with the most recent commit and works
+backwards through the parents; however, since Git history can contain
+multiple independent lines of development, the particular order that
+commits are listed in may be somewhat arbitrary.
+
+[[generating-diffs]]
+=== Generating diffs
+
+You can generate diffs between any two versions using
+linkgit:git-diff[1]:
+
+-------------------------------------------------
+$ git diff master..test
+-------------------------------------------------
+
+That will produce the diff between the tips of the two branches.  If
+you'd prefer to find the diff from their common ancestor to test, you
+can use three dots instead of two:
+
+-------------------------------------------------
+$ git diff master...test
+-------------------------------------------------
+
+Sometimes what you want instead is a set of patches; for this you can
+use linkgit:git-format-patch[1]:
+
+-------------------------------------------------
+$ git format-patch master..test
+-------------------------------------------------
+
+will generate a file with a patch for each commit reachable from test
+but not from master.
+
+[[viewing-old-file-versions]]
+=== Viewing old file versions
+
+You can always view an old version of a file by just checking out the
+correct revision first.  But sometimes it is more convenient to be
+able to view an old version of a single file without checking
+anything out; this command does that:
+
+-------------------------------------------------
+$ git show v2.5:fs/locks.c
+-------------------------------------------------
+
+Before the colon may be anything that names a commit, and after it
+may be any path to a file tracked by Git.
+
+[[history-examples]]
+=== Examples
+
+[[counting-commits-on-a-branch]]
+==== Counting the number of commits on a branch
+
+Suppose you want to know how many commits you've made on `mybranch`
+since it diverged from `origin`:
+
+-------------------------------------------------
+$ git log --pretty=oneline origin..mybranch | wc -l
+-------------------------------------------------
+
+Alternatively, you may often see this sort of thing done with the
+lower-level command linkgit:git-rev-list[1], which just lists the SHA-1's
+of all the given commits:
+
+-------------------------------------------------
+$ git rev-list origin..mybranch | wc -l
+-------------------------------------------------
+
+[[checking-for-equal-branches]]
+==== Check whether two branches point at the same history
+
+Suppose you want to check whether two branches point at the same point
+in history.
+
+-------------------------------------------------
+$ git diff origin..master
+-------------------------------------------------
+
+will tell you whether the contents of the project are the same at the
+two branches; in theory, however, it's possible that the same project
+contents could have been arrived at by two different historical
+routes.  You could compare the object names:
+
+-------------------------------------------------
+$ git rev-list origin
+e05db0fd4f31dde7005f075a84f96b360d05984b
+$ git rev-list master
+e05db0fd4f31dde7005f075a84f96b360d05984b
+-------------------------------------------------
+
+Or you could recall that the `...` operator selects all commits
+reachable from either one reference or the other but not
+both; so
+
+-------------------------------------------------
+$ git log origin...master
+-------------------------------------------------
+
+will return no commits when the two branches are equal.
+
+[[finding-tagged-descendants]]
+==== Find first tagged version including a given fix
+
+Suppose you know that the commit e05db0fd fixed a certain problem.
+You'd like to find the earliest tagged release that contains that
+fix.
+
+Of course, there may be more than one answer--if the history branched
+after commit e05db0fd, then there could be multiple "earliest" tagged
+releases.
+
+You could just visually inspect the commits since e05db0fd:
+
+-------------------------------------------------
+$ gitk e05db0fd..
+-------------------------------------------------
+
+or you can use linkgit:git-name-rev[1], which will give the commit a
+name based on any tag it finds pointing to one of the commit's
+descendants:
+
+-------------------------------------------------
+$ git name-rev --tags e05db0fd
+e05db0fd tags/v1.5.0-rc1^0~23
+-------------------------------------------------
+
+The linkgit:git-describe[1] command does the opposite, naming the
+revision using a tag on which the given commit is based:
+
+-------------------------------------------------
+$ git describe e05db0fd
+v1.5.0-rc0-260-ge05db0f
+-------------------------------------------------
+
+but that may sometimes help you guess which tags might come after the
+given commit.
+
+If you just want to verify whether a given tagged version contains a
+given commit, you could use linkgit:git-merge-base[1]:
+
+-------------------------------------------------
+$ git merge-base e05db0fd v1.5.0-rc1
+e05db0fd4f31dde7005f075a84f96b360d05984b
+-------------------------------------------------
+
+The merge-base command finds a common ancestor of the given commits,
+and always returns one or the other in the case where one is a
+descendant of the other; so the above output shows that e05db0fd
+actually is an ancestor of v1.5.0-rc1.
+
+Alternatively, note that
+
+-------------------------------------------------
+$ git log v1.5.0-rc1..e05db0fd
+-------------------------------------------------
+
+will produce empty output if and only if v1.5.0-rc1 includes e05db0fd,
+because it outputs only commits that are not reachable from v1.5.0-rc1.
+
+As yet another alternative, the linkgit:git-show-branch[1] command lists
+the commits reachable from its arguments with a display on the left-hand
+side that indicates which arguments that commit is reachable from.
+So, if you run something like
+
+-------------------------------------------------
+$ git show-branch e05db0fd v1.5.0-rc0 v1.5.0-rc1 v1.5.0-rc2
+! [e05db0fd] Fix warnings in sha1_file.c - use C99 printf format if
+available
+ ! [v1.5.0-rc0] GIT v1.5.0 preview
+  ! [v1.5.0-rc1] GIT v1.5.0-rc1
+   ! [v1.5.0-rc2] GIT v1.5.0-rc2
+...
+-------------------------------------------------
+
+then a line like
+
+-------------------------------------------------
++ ++ [e05db0fd] Fix warnings in sha1_file.c - use C99 printf format if
+available
+-------------------------------------------------
+
+shows that e05db0fd is reachable from itself, from v1.5.0-rc1,
+and from v1.5.0-rc2, and not from v1.5.0-rc0.
+
+[[showing-commits-unique-to-a-branch]]
+==== Showing commits unique to a given branch
+
+Suppose you would like to see all the commits reachable from the branch
+head named `master` but not from any other head in your repository.
+
+We can list all the heads in this repository with
+linkgit:git-show-ref[1]:
+
+-------------------------------------------------
+$ git show-ref --heads
+bf62196b5e363d73353a9dcf094c59595f3153b7 refs/heads/core-tutorial
+db768d5504c1bb46f63ee9d6e1772bd047e05bf9 refs/heads/maint
+a07157ac624b2524a059a3414e99f6f44bebc1e7 refs/heads/master
+24dbc180ea14dc1aebe09f14c8ecf32010690627 refs/heads/tutorial-2
+1e87486ae06626c2f31eaa63d26fc0fd646c8af2 refs/heads/tutorial-fixes
+-------------------------------------------------
+
+We can get just the branch-head names, and remove `master`, with
+the help of the standard utilities cut and grep:
+
+-------------------------------------------------
+$ git show-ref --heads | cut -d' ' -f2 | grep -v '^refs/heads/master'
+refs/heads/core-tutorial
+refs/heads/maint
+refs/heads/tutorial-2
+refs/heads/tutorial-fixes
+-------------------------------------------------
+
+And then we can ask to see all the commits reachable from master
+but not from these other heads:
+
+-------------------------------------------------
+$ gitk master --not $( git show-ref --heads | cut -d' ' -f2 |
+				grep -v '^refs/heads/master' )
+-------------------------------------------------
+
+Obviously, endless variations are possible; for example, to see all
+commits reachable from some head but not from any tag in the repository:
+
+-------------------------------------------------
+$ gitk $( git show-ref --heads ) --not  $( git show-ref --tags )
+-------------------------------------------------
+
+(See linkgit:gitrevisions[7] for explanations of commit-selecting
+syntax such as `--not`.)
+
+[[making-a-release]]
+==== Creating a changelog and tarball for a software release
+
+The linkgit:git-archive[1] command can create a tar or zip archive from
+any version of a project; for example:
+
+-------------------------------------------------
+$ git archive -o latest.tar.gz --prefix=project/ HEAD
+-------------------------------------------------
+
+will use HEAD to produce a gzipped tar archive in which each filename
+is preceded by `project/`.  The output file format is inferred from
+the output file extension if possible, see linkgit:git-archive[1] for
+details.
+
+Versions of Git older than 1.7.7 don't know about the `tar.gz` format,
+you'll need to use gzip explicitly:
+
+-------------------------------------------------
+$ git archive --format=tar --prefix=project/ HEAD | gzip >latest.tar.gz
+-------------------------------------------------
+
+If you're releasing a new version of a software project, you may want
+to simultaneously make a changelog to include in the release
+announcement.
+
+Linus Torvalds, for example, makes new kernel releases by tagging them,
+then running:
+
+-------------------------------------------------
+$ release-script 2.6.12 2.6.13-rc6 2.6.13-rc7
+-------------------------------------------------
+
+where release-script is a shell script that looks like:
+
+-------------------------------------------------
+#!/bin/sh
+stable="$1"
+last="$2"
+new="$3"
+echo "# git tag v$new"
+echo "git archive --prefix=linux-$new/ v$new | gzip -9 > ../linux-$new.tar.gz"
+echo "git diff v$stable v$new | gzip -9 > ../patch-$new.gz"
+echo "git log --no-merges v$new ^v$last > ../ChangeLog-$new"
+echo "git shortlog --no-merges v$new ^v$last > ../ShortLog"
+echo "git diff --stat --summary -M v$last v$new > ../diffstat-$new"
+-------------------------------------------------
+
+and then he just cut-and-pastes the output commands after verifying that
+they look OK.
+
+[[Finding-commits-With-given-Content]]
+==== Finding commits referencing a file with given content
+
+Somebody hands you a copy of a file, and asks which commits modified a
+file such that it contained the given content either before or after the
+commit.  You can find out with this:
+
+-------------------------------------------------
+$  git log --raw --abbrev=40 --pretty=oneline |
+	grep -B 1 `git hash-object filename`
+-------------------------------------------------
+
+Figuring out why this works is left as an exercise to the (advanced)
+student.  The linkgit:git-log[1], linkgit:git-diff-tree[1], and
+linkgit:git-hash-object[1] man pages may prove helpful.
+
+[[Developing-With-git]]
+== Developing with Git
+
+[[telling-git-your-name]]
+=== Telling Git your name
+
+Before creating any commits, you should introduce yourself to Git.
+The easiest way to do so is to use linkgit:git-config[1]:
+
+------------------------------------------------
+$ git config --global user.name 'Your Name Comes Here'
+$ git config --global user.email 'you@xxxxxxxxxxxxxxxxxxxxxx'
+------------------------------------------------
+
+Which will add the following to a file named `.gitconfig` in your
+home directory:
+
+------------------------------------------------
+[user]
+	name = Your Name Comes Here
+	email = you@xxxxxxxxxxxxxxxxxxxxxx
+------------------------------------------------
+
+See the "CONFIGURATION FILE" section of linkgit:git-config[1] for
+details on the configuration file.  The file is plain text, so you can
+also edit it with your favorite editor.
+
+
+[[creating-a-new-repository]]
+=== Creating a new repository
+
+Creating a new repository from scratch is very easy:
+
+-------------------------------------------------
+$ mkdir project
+$ cd project
+$ git init
+-------------------------------------------------
+
+If you have some initial content (say, a tarball):
+
+-------------------------------------------------
+$ tar xzvf project.tar.gz
+$ cd project
+$ git init
+$ git add . # include everything below ./ in the first commit:
+$ git commit
+-------------------------------------------------
+
+[[how-to-make-a-commit]]
+=== How to make a commit
+
+Creating a new commit takes three steps:
+
+	1. Making some changes to the working directory using your
+	   favorite editor.
+	2. Telling Git about your changes.
+	3. Creating the commit using the content you told Git about
+	   in step 2.
+
+In practice, you can interleave and repeat steps 1 and 2 as many
+times as you want: in order to keep track of what you want committed
+at step 3, Git maintains a snapshot of the tree's contents in a
+special staging area called "the index."
+
+At the beginning, the content of the index will be identical to
+that of the HEAD.  The command `git diff --cached`, which shows
+the difference between the HEAD and the index, should therefore
+produce no output at that point.
+
+Modifying the index is easy:
+
+To update the index with the contents of a new or modified file, use
+
+-------------------------------------------------
+$ git add path/to/file
+-------------------------------------------------
+
+To remove a file from the index and from the working tree, use
+
+-------------------------------------------------
+$ git rm path/to/file
+-------------------------------------------------
+
+After each step you can verify that
+
+-------------------------------------------------
+$ git diff --cached
+-------------------------------------------------
+
+always shows the difference between the HEAD and the index file--this
+is what you'd commit if you created the commit now--and that
+
+-------------------------------------------------
+$ git diff
+-------------------------------------------------
+
+shows the difference between the working tree and the index file.
+
+Note that `git add` always adds just the current contents of a file
+to the index; further changes to the same file will be ignored unless
+you run `git add` on the file again.
+
+When you're ready, just run
+
+-------------------------------------------------
+$ git commit
+-------------------------------------------------
+
+and Git will prompt you for a commit message and then create the new
+commit.  Check to make sure it looks like what you expected with
+
+-------------------------------------------------
+$ git show
+-------------------------------------------------
+
+As a special shortcut,
+
+-------------------------------------------------
+$ git commit -a
+-------------------------------------------------
+
+will update the index with any files that you've modified or removed
+and create a commit, all in one step.
+
+A number of commands are useful for keeping track of what you're
+about to commit:
+
+-------------------------------------------------
+$ git diff --cached # difference between HEAD and the index; what
+		    # would be committed if you ran "commit" now.
+$ git diff	    # difference between the index file and your
+		    # working directory; changes that would not
+		    # be included if you ran "commit" now.
+$ git diff HEAD	    # difference between HEAD and working tree; what
+		    # would be committed if you ran "commit -a" now.
+$ git status	    # a brief per-file summary of the above.
+-------------------------------------------------
+
+You can also use linkgit:git-gui[1] to create commits, view changes in
+the index and the working tree files, and individually select diff hunks
+for inclusion in the index (by right-clicking on the diff hunk and
+choosing "Stage Hunk For Commit").
+
+[[creating-good-commit-messages]]
+=== Creating good commit messages
+
+Though not required, it's a good idea to begin the commit message
+with a single short (no more than 50 characters) line summarizing the
+change, followed by a blank line and then a more thorough
+description.  The text up to the first blank line in a commit
+message is treated as the commit title, and that title is used
+throughout Git.  For example, linkgit:git-format-patch[1] turns a
+commit into email, and it uses the title on the Subject line and the
+rest of the commit in the body.
+
+
+[[ignoring-files]]
+=== Ignoring files
+
+A project will often generate files that you do 'not' want to track with Git.
+This typically includes files generated by a build process or temporary
+backup files made by your editor. Of course, 'not' tracking files with Git
+is just a matter of 'not' calling `git add` on them. But it quickly becomes
+annoying to have these untracked files lying around; e.g. they make
+`git add .` practically useless, and they keep showing up in the output of
+`git status`.
+
+You can tell Git to ignore certain files by creating a file called
+`.gitignore` in the top level of your working directory, with contents
+such as:
+
+-------------------------------------------------
+# Lines starting with '#' are considered comments.
+# Ignore any file named foo.txt.
+foo.txt
+# Ignore (generated) html files,
+*.html
+# except foo.html which is maintained by hand.
+!foo.html
+# Ignore objects and archives.
+*.[oa]
+-------------------------------------------------
+
+See linkgit:gitignore[5] for a detailed explanation of the syntax.  You can
+also place .gitignore files in other directories in your working tree, and they
+will apply to those directories and their subdirectories.  The `.gitignore`
+files can be added to your repository like any other files (just run `git add
+.gitignore` and `git commit`, as usual), which is convenient when the exclude
+patterns (such as patterns matching build output files) would also make sense
+for other users who clone your repository.
+
+If you wish the exclude patterns to affect only certain repositories
+(instead of every repository for a given project), you may instead put
+them in a file in your repository named `.git/info/exclude`, or in any
+file specified by the `core.excludesFile` configuration variable.
+Some Git commands can also take exclude patterns directly on the
+command line.  See linkgit:gitignore[5] for the details.
+
+[[how-to-merge]]
+=== How to merge
+
+You can rejoin two diverging branches of development using
+linkgit:git-merge[1]:
+
+-------------------------------------------------
+$ git merge branchname
+-------------------------------------------------
+
+merges the development in the branch `branchname` into the current
+branch.
+
+A merge is made by combining the changes made in `branchname` and the
+changes made up to the latest commit in your current branch since
+their histories forked. The work tree is overwritten by the result of
+the merge when this combining is done cleanly, or overwritten by a
+half-merged results when this combining results in conflicts.
+Therefore, if you have uncommitted changes touching the same files as
+the ones impacted by the merge, Git will refuse to proceed. Most of
+the time, you will want to commit your changes before you can merge,
+and if you don't, then linkgit:git-stash[1] can take these changes
+away while you're doing the merge, and reapply them afterwards.
+
+If the changes are independent enough, Git will automatically complete
+the merge and commit the result (or reuse an existing commit in case
+of <<fast-forwards,fast-forward>>, see below). On the other hand,
+if there are conflicts--for example, if the same file is
+modified in two different ways in the remote branch and the local
+branch--then you are warned; the output may look something like this:
+
+-------------------------------------------------
+$ git merge next
+ 100% (4/4) done
+Auto-merged file.txt
+CONFLICT (content): Merge conflict in file.txt
+Automatic merge failed; fix conflicts and then commit the result.
+-------------------------------------------------
+
+Conflict markers are left in the problematic files, and after
+you resolve the conflicts manually, you can update the index
+with the contents and run Git commit, as you normally would when
+creating a new file.
+
+If you examine the resulting commit using gitk, you will see that it
+has two parents, one pointing to the top of the current branch, and
+one to the top of the other branch.
+
+[[resolving-a-merge]]
+=== Resolving a merge
+
+When a merge isn't resolved automatically, Git leaves the index and
+the working tree in a special state that gives you all the
+information you need to help resolve the merge.
+
+Files with conflicts are marked specially in the index, so until you
+resolve the problem and update the index, linkgit:git-commit[1] will
+fail:
+
+-------------------------------------------------
+$ git commit
+file.txt: needs merge
+-------------------------------------------------
+
+Also, linkgit:git-status[1] will list those files as "unmerged", and the
+files with conflicts will have conflict markers added, like this:
+
+-------------------------------------------------
+<<<<<<< HEAD:file.txt
+Hello world
+=======
+Goodbye
+>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
+-------------------------------------------------
+
+All you need to do is edit the files to resolve the conflicts, and then
+
+-------------------------------------------------
+$ git add file.txt
+$ git commit
+-------------------------------------------------
+
+Note that the commit message will already be filled in for you with
+some information about the merge.  Normally you can just use this
+default message unchanged, but you may add additional commentary of
+your own if desired.
+
+The above is all you need to know to resolve a simple merge.  But Git
+also provides more information to help resolve conflicts:
+
+[[conflict-resolution]]
+==== Getting conflict-resolution help during a merge
+
+All of the changes that Git was able to merge automatically are
+already added to the index file, so linkgit:git-diff[1] shows only
+the conflicts.  It uses an unusual syntax:
+
+-------------------------------------------------
+$ git diff
+diff --cc file.txt
+index 802992c,2b60207..0000000
+--- a/file.txt
++++ b/file.txt
+@@@ -1,1 -1,1 +1,5 @@@
+++<<<<<<< HEAD:file.txt
+ +Hello world
+++=======
++ Goodbye
+++>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
+-------------------------------------------------
+
+Recall that the commit which will be committed after we resolve this
+conflict will have two parents instead of the usual one: one parent
+will be HEAD, the tip of the current branch; the other will be the
+tip of the other branch, which is stored temporarily in MERGE_HEAD.
+
+During the merge, the index holds three versions of each file.  Each of
+these three "file stages" represents a different version of the file:
+
+-------------------------------------------------
+$ git show :1:file.txt	# the file in a common ancestor of both branches
+$ git show :2:file.txt	# the version from HEAD.
+$ git show :3:file.txt	# the version from MERGE_HEAD.
+-------------------------------------------------
+
+When you ask linkgit:git-diff[1] to show the conflicts, it runs a
+three-way diff between the conflicted merge results in the work tree with
+stages 2 and 3 to show only hunks whose contents come from both sides,
+mixed (in other words, when a hunk's merge results come only from stage 2,
+that part is not conflicting and is not shown.  Same for stage 3).
+
+The diff above shows the differences between the working-tree version of
+file.txt and the stage 2 and stage 3 versions.  So instead of preceding
+each line by a single `+` or `-`, it now uses two columns: the first
+column is used for differences between the first parent and the working
+directory copy, and the second for differences between the second parent
+and the working directory copy.  (See the "COMBINED DIFF FORMAT" section
+of linkgit:git-diff-files[1] for a details of the format.)
+
+After resolving the conflict in the obvious way (but before updating the
+index), the diff will look like:
+
+-------------------------------------------------
+$ git diff
+diff --cc file.txt
+index 802992c,2b60207..0000000
+--- a/file.txt
++++ b/file.txt
+@@@ -1,1 -1,1 +1,1 @@@
+- Hello world
+ -Goodbye
+++Goodbye world
+-------------------------------------------------
+
+This shows that our resolved version deleted "Hello world" from the
+first parent, deleted "Goodbye" from the second parent, and added
+"Goodbye world", which was previously absent from both.
+
+Some special diff options allow diffing the working directory against
+any of these stages:
+
+-------------------------------------------------
+$ git diff -1 file.txt		# diff against stage 1
+$ git diff --base file.txt	# same as the above
+$ git diff -2 file.txt		# diff against stage 2
+$ git diff --ours file.txt	# same as the above
+$ git diff -3 file.txt		# diff against stage 3
+$ git diff --theirs file.txt	# same as the above.
+-------------------------------------------------
+
+When using the 'ort' merge strategy (the default), before updating the working
+tree with the result of the merge, Git writes a ref named AUTO_MERGE
+reflecting the state of the tree it is about to write. Conflicted paths with
+textual conflicts that could not be automatically merged are written to this
+tree with conflict markers, just as in the working tree. AUTO_MERGE can thus be
+used with linkgit:git-diff[1] to show the changes you've made so far to resolve
+conflicts. Using the same example as above, after resolving the conflict we
+get:
+
+-------------------------------------------------
+$ git diff AUTO_MERGE
+diff --git a/file.txt b/file.txt
+index cd10406..8bf5ae7 100644
+--- a/file.txt
++++ b/file.txt
+@@ -1,5 +1 @@
+-<<<<<<< HEAD:file.txt
+-Hello world
+-=======
+-Goodbye
+->>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086:file.txt
++Goodbye world
+-------------------------------------------------
+
+Notice that the diff shows we deleted the conflict markers and both versions of
+the content line, and wrote "Goodbye world" instead.
+
+The linkgit:git-log[1] and linkgit:gitk[1] commands also provide special help
+for merges:
+
+-------------------------------------------------
+$ git log --merge
+$ gitk --merge
+-------------------------------------------------
+
+These will display all commits which exist only on HEAD or on
+MERGE_HEAD, and which touch an unmerged file.
+
+You may also use linkgit:git-mergetool[1], which lets you merge the
+unmerged files using external tools such as Emacs or kdiff3.
+
+Each time you resolve the conflicts in a file and update the index:
+
+-------------------------------------------------
+$ git add file.txt
+-------------------------------------------------
+
+the different stages of that file will be "collapsed", after which
+`git diff` will (by default) no longer show diffs for that file.
+
+[[undoing-a-merge]]
+=== Undoing a merge
+
+If you get stuck and decide to just give up and throw the whole mess
+away, you can always return to the pre-merge state with
+
+-------------------------------------------------
+$ git merge --abort
+-------------------------------------------------
+
+Or, if you've already committed the merge that you want to throw away,
+
+-------------------------------------------------
+$ git reset --hard ORIG_HEAD
+-------------------------------------------------
+
+However, this last command can be dangerous in some cases--never
+throw away a commit you have already committed if that commit may
+itself have been merged into another branch, as doing so may confuse
+further merges.
+
+[[fast-forwards]]
+=== Fast-forward merges
+
+There is one special case not mentioned above, which is treated
+differently.  Normally, a merge results in a merge commit, with two
+parents, one pointing at each of the two lines of development that
+were merged.
+
+However, if the current branch is an ancestor of the other--so every commit
+present in the current branch is already contained in the other branch--then Git
+just performs a "fast-forward"; the head of the current branch is moved forward
+to point at the head of the merged-in branch, without any new commits being
+created.
+
+[[fixing-mistakes]]
+=== Fixing mistakes
+
+If you've messed up the working tree, but haven't yet committed your
+mistake, you can return the entire working tree to the last committed
+state with
+
+-------------------------------------------------
+$ git restore --staged --worktree :/
+-------------------------------------------------
+
+If you make a commit that you later wish you hadn't, there are two
+fundamentally different ways to fix the problem:
+
+	1. You can create a new commit that undoes whatever was done
+	by the old commit.  This is the correct thing if your
+	mistake has already been made public.
+
+	2. You can go back and modify the old commit.  You should
+	never do this if you have already made the history public;
+	Git does not normally expect the "history" of a project to
+	change, and cannot correctly perform repeated merges from
+	a branch that has had its history changed.
+
+[[reverting-a-commit]]
+==== Fixing a mistake with a new commit
+
+Creating a new commit that reverts an earlier change is very easy;
+just pass the linkgit:git-revert[1] command a reference to the bad
+commit; for example, to revert the most recent commit:
+
+-------------------------------------------------
+$ git revert HEAD
+-------------------------------------------------
+
+This will create a new commit which undoes the change in HEAD.  You
+will be given a chance to edit the commit message for the new commit.
+
+You can also revert an earlier change, for example, the next-to-last:
+
+-------------------------------------------------
+$ git revert HEAD^
+-------------------------------------------------
+
+In this case Git will attempt to undo the old change while leaving
+intact any changes made since then.  If more recent changes overlap
+with the changes to be reverted, then you will be asked to fix
+conflicts manually, just as in the case of <<resolving-a-merge,
+resolving a merge>>.
+
+[[fixing-a-mistake-by-rewriting-history]]
+==== Fixing a mistake by rewriting history
+
+If the problematic commit is the most recent commit, and you have not
+yet made that commit public, then you may just
+<<undoing-a-merge,destroy it using `git reset`>>.
+
+Alternatively, you
+can edit the working directory and update the index to fix your
+mistake, just as if you were going to <<how-to-make-a-commit,create a
+new commit>>, then run
+
+-------------------------------------------------
+$ git commit --amend
+-------------------------------------------------
+
+which will replace the old commit by a new commit incorporating your
+changes, giving you a chance to edit the old commit message first.
+
+Again, you should never do this to a commit that may already have
+been merged into another branch; use linkgit:git-revert[1] instead in
+that case.
+
+It is also possible to replace commits further back in the history, but
+this is an advanced topic to be left for
+<<cleaning-up-history,another chapter>>.
+
+[[checkout-of-path]]
+==== Checking out an old version of a file
+
+In the process of undoing a previous bad change, you may find it
+useful to check out an older version of a particular file using
+linkgit:git-restore[1]. The command
+
+-------------------------------------------------
+$ git restore --source=HEAD^ path/to/file
+-------------------------------------------------
+
+replaces path/to/file by the contents it had in the commit HEAD^, and
+also updates the index to match.  It does not change branches.
+
+If you just want to look at an old version of the file, without
+modifying the working directory, you can do that with
+linkgit:git-show[1]:
+
+-------------------------------------------------
+$ git show HEAD^:path/to/file
+-------------------------------------------------
+
+which will display the given version of the file.
+
+[[interrupted-work]]
+==== Temporarily setting aside work in progress
+
+While you are in the middle of working on something complicated, you
+find an unrelated but obvious and trivial bug.  You would like to fix it
+before continuing.  You can use linkgit:git-stash[1] to save the current
+state of your work, and after fixing the bug (or, optionally after doing
+so on a different branch and then coming back), unstash the
+work-in-progress changes.
+
+------------------------------------------------
+$ git stash push -m "work in progress for foo feature"
+------------------------------------------------
+
+This command will save your changes away to the `stash`, and
+reset your working tree and the index to match the tip of your
+current branch.  Then you can make your fix as usual.
+
+------------------------------------------------
+... edit and test ...
+$ git commit -a -m "blorpl: typofix"
+------------------------------------------------
+
+After that, you can go back to what you were working on with
+`git stash pop`:
+
+------------------------------------------------
+$ git stash pop
+------------------------------------------------
+
+
+[[ensuring-good-performance]]
+=== Ensuring good performance
+
+On large repositories, Git depends on compression to keep the history
+information from taking up too much space on disk or in memory.  Some
+Git commands may automatically run linkgit:git-gc[1], so you don't
+have to worry about running it manually.  However, compressing a large
+repository may take a while, so you may want to call `gc` explicitly
+to avoid automatic compression kicking in when it is not convenient.
+
+
+[[ensuring-reliability]]
+=== Ensuring reliability
+
+[[checking-for-corruption]]
+==== Checking the repository for corruption
+
+The linkgit:git-fsck[1] command runs a number of self-consistency checks
+on the repository, and reports on any problems.  This may take some
+time.
+
+-------------------------------------------------
+$ git fsck
+dangling commit 7281251ddd2a61e38657c827739c57015671a6b3
+dangling commit 2706a059f258c6b245f298dc4ff2ccd30ec21a63
+dangling commit 13472b7c4b80851a1bc551779171dcb03655e9b5
+dangling blob 218761f9d90712d37a9c5e36f406f92202db07eb
+dangling commit bf093535a34a4d35731aa2bd90fe6b176302f14f
+dangling commit 8e4bec7f2ddaa268bef999853c25755452100f8e
+dangling tree d50bb86186bf27b681d25af89d3b5b68382e4085
+dangling tree b24c2473f1fd3d91352a624795be026d64c8841f
+...
+-------------------------------------------------
+
+You will see informational messages on dangling objects. They are objects
+that still exist in the repository but are no longer referenced by any of
+your branches, and can (and will) be removed after a while with `gc`.
+You can run `git fsck --no-dangling` to suppress these messages, and still
+view real errors.
+
+[[recovering-lost-changes]]
+==== Recovering lost changes
+
+[[reflogs]]
+===== Reflogs
+
+Say you modify a branch with <<fixing-mistakes,`git reset --hard`>>,
+and then realize that the branch was the only reference you had to
+that point in history.
+
+Fortunately, Git also keeps a log, called a "reflog", of all the
+previous values of each branch.  So in this case you can still find the
+old history using, for example,
+
+-------------------------------------------------
+$ git log master@{1}
+-------------------------------------------------
+
+This lists the commits reachable from the previous version of the
+`master` branch head.  This syntax can be used with any Git command
+that accepts a commit, not just with `git log`.  Some other examples:
+
+-------------------------------------------------
+$ git show master@{2}		# See where the branch pointed 2,
+$ git show master@{3}		# 3, ... changes ago.
+$ gitk master@{yesterday}	# See where it pointed yesterday,
+$ gitk master@{"1 week ago"}	# ... or last week
+$ git log --walk-reflogs master	# show reflog entries for master
+-------------------------------------------------
+
+A separate reflog is kept for the HEAD, so
+
+-------------------------------------------------
+$ git show HEAD@{"1 week ago"}
+-------------------------------------------------
+
+will show what HEAD pointed to one week ago, not what the current branch
+pointed to one week ago.  This allows you to see the history of what
+you've checked out.
+
+The reflogs are kept by default for 30 days, after which they may be
+pruned.  See linkgit:git-reflog[1] and linkgit:git-gc[1] to learn
+how to control this pruning, and see the "SPECIFYING REVISIONS"
+section of linkgit:gitrevisions[7] for details.
+
+Note that the reflog history is very different from normal Git history.
+While normal history is shared by every repository that works on the
+same project, the reflog history is not shared: it tells you only about
+how the branches in your local repository have changed over time.
+
+[[dangling-object-recovery]]
+===== Examining dangling objects
+
+In some situations the reflog may not be able to save you.  For example,
+suppose you delete a branch, then realize you need the history it
+contained.  The reflog is also deleted; however, if you have not yet
+pruned the repository, then you may still be able to find the lost
+commits in the dangling objects that `git fsck` reports.  See
+<<dangling-objects>> for the details.
+
+-------------------------------------------------
+$ git fsck
+dangling commit 7281251ddd2a61e38657c827739c57015671a6b3
+dangling commit 2706a059f258c6b245f298dc4ff2ccd30ec21a63
+dangling commit 13472b7c4b80851a1bc551779171dcb03655e9b5
+...
+-------------------------------------------------
+
+You can examine
+one of those dangling commits with, for example,
+
+------------------------------------------------
+$ gitk 7281251ddd --not --all
+------------------------------------------------
+
+which does what it sounds like: it says that you want to see the commit
+history that is described by the dangling commit(s), but not the
+history that is described by all your existing branches and tags.  Thus
+you get exactly the history reachable from that commit that is lost.
+(And notice that it might not be just one commit: we only report the
+"tip of the line" as being dangling, but there might be a whole deep
+and complex commit history that was dropped.)
+
+If you decide you want the history back, you can always create a new
+reference pointing to it, for example, a new branch:
+
+------------------------------------------------
+$ git branch recovered-branch 7281251ddd
+------------------------------------------------
+
+Other types of dangling objects (blobs and trees) are also possible, and
+dangling objects can arise in other situations.
+
+
+[[sharing-development]]
+== Sharing development with others
+
+[[getting-updates-With-git-pull]]
+=== Getting updates with git pull
+
+After you clone a repository and commit a few changes of your own, you
+may wish to check the original repository for updates and merge them
+into your own work.
+
+We have already seen <<Updating-a-repository-With-git-fetch,how to
+keep remote-tracking branches up to date>> with linkgit:git-fetch[1],
+and how to merge two branches.  So you can merge in changes from the
+original repository's master branch with:
+
+-------------------------------------------------
+$ git fetch
+$ git merge origin/master
+-------------------------------------------------
+
+However, the linkgit:git-pull[1] command provides a way to do this in
+one step:
+
+-------------------------------------------------
+$ git pull origin master
+-------------------------------------------------
+
+In fact, if you have `master` checked out, then this branch has been
+configured by `git clone` to get changes from the HEAD branch of the
+origin repository.  So often you can
+accomplish the above with just a simple
+
+-------------------------------------------------
+$ git pull
+-------------------------------------------------
+
+This command will fetch changes from the remote branches to your
+remote-tracking branches `origin/*`, and merge the default branch into
+the current branch.
+
+More generally, a branch that is created from a remote-tracking branch
+will pull
+by default from that branch.  See the descriptions of the
+`branch.<name>.remote` and `branch.<name>.merge` options in
+linkgit:git-config[1], and the discussion of the `--track` option in
+linkgit:git-checkout[1], to learn how to control these defaults.
+
+In addition to saving you keystrokes, `git pull` also helps you by
+producing a default commit message documenting the branch and
+repository that you pulled from.
+
+(But note that no such commit will be created in the case of a
+<<fast-forwards,fast-forward>>; instead, your branch will just be
+updated to point to the latest commit from the upstream branch.)
+
+The `git pull` command can also be given `.` as the "remote" repository,
+in which case it just merges in a branch from the current repository; so
+the commands
+
+-------------------------------------------------
+$ git pull . branch
+$ git merge branch
+-------------------------------------------------
+
+are roughly equivalent.
+
+[[submitting-patches]]
+=== Submitting patches to a project
+
+If you just have a few changes, the simplest way to submit them may
+just be to send them as patches in email:
+
+First, use linkgit:git-format-patch[1]; for example:
+
+-------------------------------------------------
+$ git format-patch origin
+-------------------------------------------------
+
+will produce a numbered series of files in the current directory, one
+for each patch in the current branch but not in `origin/HEAD`.
+
+`git format-patch` can include an initial "cover letter". You can insert
+commentary on individual patches after the three dash line which
+`format-patch` places after the commit message but before the patch
+itself.  If you use `git notes` to track your cover letter material,
+`git format-patch --notes` will include the commit's notes in a similar
+manner.
+
+You can then import these into your mail client and send them by
+hand.  However, if you have a lot to send at once, you may prefer to
+use the linkgit:git-send-email[1] script to automate the process.
+Consult the mailing list for your project first to determine
+their requirements for submitting patches.
+
+[[importing-patches]]
+=== Importing patches to a project
+
+Git also provides a tool called linkgit:git-am[1] (am stands for
+"apply mailbox"), for importing such an emailed series of patches.
+Just save all of the patch-containing messages, in order, into a
+single mailbox file, say `patches.mbox`, then run
+
+-------------------------------------------------
+$ git am -3 patches.mbox
+-------------------------------------------------
+
+Git will apply each patch in order; if any conflicts are found, it
+will stop, and you can fix the conflicts as described in
+"<<resolving-a-merge,Resolving a merge>>".  (The `-3` option tells
+Git to perform a merge; if you would prefer it just to abort and
+leave your tree and index untouched, you may omit that option.)
+
+Once the index is updated with the results of the conflict
+resolution, instead of creating a new commit, just run
+
+-------------------------------------------------
+$ git am --continue
+-------------------------------------------------
+
+and Git will create the commit for you and continue applying the
+remaining patches from the mailbox.
+
+The final result will be a series of commits, one for each patch in
+the original mailbox, with authorship and commit log message each
+taken from the message containing each patch.
+
+[[public-repositories]]
+=== Public Git repositories
+
+Another way to submit changes to a project is to tell the maintainer
+of that project to pull the changes from your repository using
+linkgit:git-pull[1].  In the section "<<getting-updates-With-git-pull,
+Getting updates with `git pull`>>" we described this as a way to get
+updates from the "main" repository, but it works just as well in the
+other direction.
+
+If you and the maintainer both have accounts on the same machine, then
+you can just pull changes from each other's repositories directly;
+commands that accept repository URLs as arguments will also accept a
+local directory name:
+
+-------------------------------------------------
+$ git clone /path/to/repository
+$ git pull /path/to/other/repository
+-------------------------------------------------
+
+or an ssh URL:
+
+-------------------------------------------------
+$ git clone ssh://yourhost/~you/repository
+-------------------------------------------------
+
+For projects with few developers, or for synchronizing a few private
+repositories, this may be all you need.
+
+However, the more common way to do this is to maintain a separate public
+repository (usually on a different host) for others to pull changes
+from.  This is usually more convenient, and allows you to cleanly
+separate private work in progress from publicly visible work.
+
+You will continue to do your day-to-day work in your personal
+repository, but periodically "push" changes from your personal
+repository into your public repository, allowing other developers to
+pull from that repository.  So the flow of changes, in a situation
+where there is one other developer with a public repository, looks
+like this:
+
+....
+		      you push
+your personal repo ------------------> your public repo
+      ^                                     |
+      |                                     |
+      | you pull                            | they pull
+      |                                     |
+      |                                     |
+      |               they push             V
+their public repo <------------------- their repo
+....
+
+We explain how to do this in the following sections.
+
+[[setting-up-a-public-repository]]
+==== Setting up a public repository
+
+Assume your personal repository is in the directory `~/proj`.  We
+first create a new clone of the repository and tell `git daemon` that it
+is meant to be public:
+
+-------------------------------------------------
+$ git clone --bare ~/proj proj.git
+$ touch proj.git/git-daemon-export-ok
+-------------------------------------------------
+
+The resulting directory proj.git contains a "bare" git repository--it is
+just the contents of the `.git` directory, without any files checked out
+around it.
+
+Next, copy `proj.git` to the server where you plan to host the
+public repository.  You can use scp, rsync, or whatever is most
+convenient.
+
+[[exporting-via-git]]
+==== Exporting a Git repository via the Git protocol
+
+This is the preferred method.
+
+If someone else administers the server, they should tell you what
+directory to put the repository in, and what `git://` URL it will
+appear at.  You can then skip to the section
+"<<pushing-changes-to-a-public-repository,Pushing changes to a public
+repository>>", below.
+
+Otherwise, all you need to do is start linkgit:git-daemon[1]; it will
+listen on port 9418.  By default, it will allow access to any directory
+that looks like a Git directory and contains the magic file
+git-daemon-export-ok.  Passing some directory paths as `git daemon`
+arguments will further restrict the exports to those paths.
+
+You can also run `git daemon` as an inetd service; see the
+linkgit:git-daemon[1] man page for details.  (See especially the
+examples section.)
+
+[[exporting-via-http]]
+==== Exporting a git repository via HTTP
+
+The Git protocol gives better performance and reliability, but on a
+host with a web server set up, HTTP exports may be simpler to set up.
+
+All you need to do is place the newly created bare Git repository in
+a directory that is exported by the web server, and make some
+adjustments to give web clients some extra information they need:
+
+-------------------------------------------------
+$ mv proj.git /home/you/public_html/proj.git
+$ cd proj.git
+$ git --bare update-server-info
+$ mv hooks/post-update.sample hooks/post-update
+-------------------------------------------------
+
+(For an explanation of the last two lines, see
+linkgit:git-update-server-info[1] and linkgit:githooks[5].)
+
+Advertise the URL of `proj.git`.  Anybody else should then be able to
+clone or pull from that URL, for example with a command line like:
+
+-------------------------------------------------
+$ git clone http://yourserver.com/~you/proj.git
+-------------------------------------------------
+
+(See also
+link:howto/setup-git-server-over-http.html[setup-git-server-over-http]
+for a slightly more sophisticated setup using WebDAV which also
+allows pushing over HTTP.)
+
+[[pushing-changes-to-a-public-repository]]
+==== Pushing changes to a public repository
+
+Note that the two techniques outlined above (exporting via
+<<exporting-via-http,http>> or <<exporting-via-git,git>>) allow other
+maintainers to fetch your latest changes, but they do not allow write
+access, which you will need to update the public repository with the
+latest changes created in your private repository.
+
+The simplest way to do this is using linkgit:git-push[1] and ssh; to
+update the remote branch named `master` with the latest state of your
+branch named `master`, run
+
+-------------------------------------------------
+$ git push ssh://yourserver.com/~you/proj.git master:master
+-------------------------------------------------
+
+or just
+
+-------------------------------------------------
+$ git push ssh://yourserver.com/~you/proj.git master
+-------------------------------------------------
+
+As with `git fetch`, `git push` will complain if this does not result in a
+<<fast-forwards,fast-forward>>; see the following section for details on
+handling this case.
+
+Note that the target of a `push` is normally a
+<<def_bare_repository,bare>> repository.  You can also push to a
+repository that has a checked-out working tree, but a push to update the
+currently checked-out branch is denied by default to prevent confusion.
+See the description of the receive.denyCurrentBranch option
+in linkgit:git-config[1] for details.
+
+As with `git fetch`, you may also set up configuration options to
+save typing; so, for example:
+
+-------------------------------------------------
+$ git remote add public-repo ssh://yourserver.com/~you/proj.git
+-------------------------------------------------
+
+adds the following to `.git/config`:
+
+-------------------------------------------------
+[remote "public-repo"]
+	url = yourserver.com:proj.git
+	fetch = +refs/heads/*:refs/remotes/example/*
+-------------------------------------------------
+
+which lets you do the same push with just
+
+-------------------------------------------------
+$ git push public-repo master
+-------------------------------------------------
+
+See the explanations of the `remote.<name>.url`,
+`branch.<name>.remote`, and `remote.<name>.push` options in
+linkgit:git-config[1] for details.
+
+[[forcing-push]]
+==== What to do when a push fails
+
+If a push would not result in a <<fast-forwards,fast-forward>> of the
+remote branch, then it will fail with an error like:
+
+-------------------------------------------------
+ ! [rejected]        master -> master (non-fast-forward)
+error: failed to push some refs to '...'
+hint: Updates were rejected because the tip of your current branch is behind
+hint: its remote counterpart. Integrate the remote changes (e.g.
+hint: 'git pull ...') before pushing again.
+hint: See the 'Note about fast-forwards' in 'git push --help' for details.
+-------------------------------------------------
+
+This can happen, for example, if you:
+
+	- use `git reset --hard` to remove already-published commits, or
+	- use `git commit --amend` to replace already-published commits
+	  (as in <<fixing-a-mistake-by-rewriting-history>>), or
+	- use `git rebase` to rebase any already-published commits (as
+	  in <<using-git-rebase>>).
+
+You may force `git push` to perform the update anyway by preceding the
+branch name with a plus sign:
+
+-------------------------------------------------
+$ git push ssh://yourserver.com/~you/proj.git +master
+-------------------------------------------------
+
+Note the addition of the `+` sign.  Alternatively, you can use the
+`-f` flag to force the remote update, as in:
+
+-------------------------------------------------
+$ git push -f ssh://yourserver.com/~you/proj.git master
+-------------------------------------------------
+
+Normally whenever a branch head in a public repository is modified, it
+is modified to point to a descendant of the commit that it pointed to
+before.  By forcing a push in this situation, you break that convention.
+(See <<problems-With-rewriting-history>>.)
+
+Nevertheless, this is a common practice for people that need a simple
+way to publish a work-in-progress patch series, and it is an acceptable
+compromise as long as you warn other developers that this is how you
+intend to manage the branch.
+
+It's also possible for a push to fail in this way when other people have
+the right to push to the same repository.  In that case, the correct
+solution is to retry the push after first updating your work: either by a
+pull, or by a fetch followed by a rebase; see the
+<<setting-up-a-shared-repository,next section>> and
+linkgit:gitcvs-migration[7] for more.
+
+[[setting-up-a-shared-repository]]
+==== Setting up a shared repository
+
+Another way to collaborate is by using a model similar to that
+commonly used in CVS, where several developers with special rights
+all push to and pull from a single shared repository.  See
+linkgit:gitcvs-migration[7] for instructions on how to
+set this up.
+
+However, while there is nothing wrong with Git's support for shared
+repositories, this mode of operation is not generally recommended,
+simply because the mode of collaboration that Git supports--by
+exchanging patches and pulling from public repositories--has so many
+advantages over the central shared repository:
+
+	- Git's ability to quickly import and merge patches allows a
+	  single maintainer to process incoming changes even at very
+	  high rates.  And when that becomes too much, `git pull` provides
+	  an easy way for that maintainer to delegate this job to other
+	  maintainers while still allowing optional review of incoming
+	  changes.
+	- Since every developer's repository has the same complete copy
+	  of the project history, no repository is special, and it is
+	  trivial for another developer to take over maintenance of a
+	  project, either by mutual agreement, or because a maintainer
+	  becomes unresponsive or difficult to work with.
+	- The lack of a central group of "committers" means there is
+	  less need for formal decisions about who is "in" and who is
+	  "out".
+
+[[setting-up-gitweb]]
+==== Allowing web browsing of a repository
+
+The gitweb cgi script provides users an easy way to browse your
+project's revisions, file contents and logs without having to install
+Git. Features like RSS/Atom feeds and blame/annotation details may
+optionally be enabled.
+
+The linkgit:git-instaweb[1] command provides a simple way to start
+browsing the repository using gitweb. The default server when using
+instaweb is lighttpd.
+
+See the file gitweb/INSTALL in the Git source tree and
+linkgit:gitweb[1] for instructions on details setting up a permanent
+installation with a CGI or Perl capable server.
+
+[[how-to-get-a-git-repository-with-minimal-history]]
+=== How to get a Git repository with minimal history
+
+A <<def_shallow_clone,shallow clone>>, with its truncated
+history, is useful when one is interested only in recent history
+of a project and getting full history from the upstream is
+expensive.
+
+A <<def_shallow_clone,shallow clone>> is created by specifying
+the linkgit:git-clone[1] `--depth` switch. The depth can later be
+changed with the linkgit:git-fetch[1] `--depth` switch, or full
+history restored with `--unshallow`.
+
+Merging inside a <<def_shallow_clone,shallow clone>> will work as long
+as a merge base is in the recent history.
+Otherwise, it will be like merging unrelated histories and may
+have to result in huge conflicts.  This limitation may make such
+a repository unsuitable to be used in merge based workflows.
+
+[[sharing-development-examples]]
+=== Examples
+
+[[maintaining-topic-branches]]
+==== Maintaining topic branches for a Linux subsystem maintainer
+
+This describes how Tony Luck uses Git in his role as maintainer of the
+IA64 architecture for the Linux kernel.
+
+He uses two public branches:
+
+ - A "test" tree into which patches are initially placed so that they
+   can get some exposure when integrated with other ongoing development.
+   This tree is available to Andrew for pulling into -mm whenever he
+   wants.
+
+ - A "release" tree into which tested patches are moved for final sanity
+   checking, and as a vehicle to send them upstream to Linus (by sending
+   him a "please pull" request.)
+
+He also uses a set of temporary branches ("topic branches"), each
+containing a logical grouping of patches.
+
+To set this up, first create your work tree by cloning Linus's public
+tree:
+
+-------------------------------------------------
+$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git work
+$ cd work
+-------------------------------------------------
+
+Linus's tree will be stored in the remote-tracking branch named origin/master,
+and can be updated using linkgit:git-fetch[1]; you can track other
+public trees using linkgit:git-remote[1] to set up a "remote" and
+linkgit:git-fetch[1] to keep them up to date; see
+<<repositories-and-branches>>.
+
+Now create the branches in which you are going to work; these start out
+at the current tip of origin/master branch, and should be set up (using
+the `--track` option to linkgit:git-branch[1]) to merge changes in from
+Linus by default.
+
+-------------------------------------------------
+$ git branch --track test origin/master
+$ git branch --track release origin/master
+-------------------------------------------------
+
+These can be easily kept up to date using linkgit:git-pull[1].
+
+-------------------------------------------------
+$ git switch test && git pull
+$ git switch release && git pull
+-------------------------------------------------
+
+Important note!  If you have any local changes in these branches, then
+this merge will create a commit object in the history (with no local
+changes Git will simply do a "fast-forward" merge).  Many people dislike
+the "noise" that this creates in the Linux history, so you should avoid
+doing this capriciously in the `release` branch, as these noisy commits
+will become part of the permanent history when you ask Linus to pull
+from the release branch.
+
+A few configuration variables (see linkgit:git-config[1]) can
+make it easy to push both branches to your public tree.  (See
+<<setting-up-a-public-repository>>.)
+
+-------------------------------------------------
+$ cat >> .git/config <<EOF
+[remote "mytree"]
+	url =  master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux.git
+	push = release
+	push = test
+EOF
+-------------------------------------------------
+
+Then you can push both the test and release trees using
+linkgit:git-push[1]:
+
+-------------------------------------------------
+$ git push mytree
+-------------------------------------------------
+
+or push just one of the test and release branches using:
+
+-------------------------------------------------
+$ git push mytree test
+-------------------------------------------------
+
+or
+
+-------------------------------------------------
+$ git push mytree release
+-------------------------------------------------
+
+Now to apply some patches from the community.  Think of a short
+snappy name for a branch to hold this patch (or related group of
+patches), and create a new branch from a recent stable tag of
+Linus's branch. Picking a stable base for your branch will:
+1) help you: by avoiding inclusion of unrelated and perhaps lightly
+tested changes
+2) help future bug hunters that use `git bisect` to find problems
+
+-------------------------------------------------
+$ git switch -c speed-up-spinlocks v2.6.35
+-------------------------------------------------
+
+Now you apply the patch(es), run some tests, and commit the change(s).  If
+the patch is a multi-part series, then you should apply each as a separate
+commit to this branch.
+
+-------------------------------------------------
+$ ... patch ... test  ... commit [ ... patch ... test ... commit ]*
+-------------------------------------------------
+
+When you are happy with the state of this change, you can merge it into the
+"test" branch in preparation to make it public:
+
+-------------------------------------------------
+$ git switch test && git merge speed-up-spinlocks
+-------------------------------------------------
+
+It is unlikely that you would have any conflicts here ... but you might if you
+spent a while on this step and had also pulled new versions from upstream.
+
+Sometime later when enough time has passed and testing done, you can pull the
+same branch into the `release` tree ready to go upstream.  This is where you
+see the value of keeping each patch (or patch series) in its own branch.  It
+means that the patches can be moved into the `release` tree in any order.
+
+-------------------------------------------------
+$ git switch release && git merge speed-up-spinlocks
+-------------------------------------------------
+
+After a while, you will have a number of branches, and despite the
+well chosen names you picked for each of them, you may forget what
+they are for, or what status they are in.  To get a reminder of what
+changes are in a specific branch, use:
+
+-------------------------------------------------
+$ git log linux..branchname | git shortlog
+-------------------------------------------------
+
+To see whether it has already been merged into the test or release branches,
+use:
+
+-------------------------------------------------
+$ git log test..branchname
+-------------------------------------------------
+
+or
+
+-------------------------------------------------
+$ git log release..branchname
+-------------------------------------------------
+
+(If this branch has not yet been merged, you will see some log entries.
+If it has been merged, then there will be no output.)
+
+Once a patch completes the great cycle (moving from test to release,
+then pulled by Linus, and finally coming back into your local
+`origin/master` branch), the branch for this change is no longer needed.
+You detect this when the output from:
+
+-------------------------------------------------
+$ git log origin..branchname
+-------------------------------------------------
+
+is empty.  At this point the branch can be deleted:
+
+-------------------------------------------------
+$ git branch -d branchname
+-------------------------------------------------
+
+Some changes are so trivial that it is not necessary to create a separate
+branch and then merge into each of the test and release branches.  For
+these changes, just apply directly to the `release` branch, and then
+merge that into the `test` branch.
+
+After pushing your work to `mytree`, you can use
+linkgit:git-request-pull[1] to prepare a "please pull" request message
+to send to Linus:
+
+-------------------------------------------------
+$ git push mytree
+$ git request-pull origin mytree release
+-------------------------------------------------
+
+Here are some of the scripts that simplify all this even further.
+
+-------------------------------------------------
+==== update script ====
+# Update a branch in my Git tree.  If the branch to be updated
+# is origin, then pull from kernel.org.  Otherwise merge
+# origin/master branch into test|release branch
+
+case "$1" in
+test|release)
+	git checkout $1 && git pull . origin
+	;;
+origin)
+	before=$(git rev-parse refs/remotes/origin/master)
+	git fetch origin
+	after=$(git rev-parse refs/remotes/origin/master)
+	if [ $before != $after ]
+	then
+		git log $before..$after | git shortlog
+	fi
+	;;
+*)
+	echo "usage: $0 origin|test|release" 1>&2
+	exit 1
+	;;
+esac
+-------------------------------------------------
+
+-------------------------------------------------
+==== merge script ====
+# Merge a branch into either the test or release branch
+
+pname=$0
+
+usage()
+{
+	echo "usage: $pname branch test|release" 1>&2
+	exit 1
+}
+
+git show-ref -q --verify -- refs/heads/"$1" || {
+	echo "Can't see branch <$1>" 1>&2
+	usage
+}
+
+case "$2" in
+test|release)
+	if [ $(git log $2..$1 | wc -c) -eq 0 ]
+	then
+		echo $1 already merged into $2 1>&2
+		exit 1
+	fi
+	git checkout $2 && git pull . $1
+	;;
+*)
+	usage
+	;;
+esac
+-------------------------------------------------
+
+-------------------------------------------------
+==== status script ====
+# report on status of my ia64 Git tree
+
+gb=$(tput setab 2)
+rb=$(tput setab 1)
+restore=$(tput setab 9)
+
+if [ `git rev-list test..release | wc -c` -gt 0 ]
+then
+	echo $rb Warning: commits in release that are not in test $restore
+	git log test..release
+fi
+
+for branch in `git show-ref --heads | sed 's|^.*/||'`
+do
+	if [ $branch = test -o $branch = release ]
+	then
+		continue
+	fi
+
+	echo -n $gb ======= $branch ====== $restore " "
+	status=
+	for ref in test release origin/master
+	do
+		if [ `git rev-list $ref..$branch | wc -c` -gt 0 ]
+		then
+			status=$status${ref:0:1}
+		fi
+	done
+	case $status in
+	trl)
+		echo $rb Need to pull into test $restore
+		;;
+	rl)
+		echo "In test"
+		;;
+	l)
+		echo "Waiting for linus"
+		;;
+	"")
+		echo $rb All done $restore
+		;;
+	*)
+		echo $rb "<$status>" $restore
+		;;
+	esac
+	git log origin/master..$branch | git shortlog
+done
+-------------------------------------------------
+
+
+[[cleaning-up-history]]
+== Rewriting history and maintaining patch series
+
+Normally commits are only added to a project, never taken away or
+replaced.  Git is designed with this assumption, and violating it will
+cause Git's merge machinery (for example) to do the wrong thing.
+
+However, there is a situation in which it can be useful to violate this
+assumption.
+
+[[patch-series]]
+=== Creating the perfect patch series
+
+Suppose you are a contributor to a large project, and you want to add a
+complicated feature, and to present it to the other developers in a way
+that makes it easy for them to read your changes, verify that they are
+correct, and understand why you made each change.
+
+If you present all of your changes as a single patch (or commit), they
+may find that it is too much to digest all at once.
+
+If you present them with the entire history of your work, complete with
+mistakes, corrections, and dead ends, they may be overwhelmed.
+
+So the ideal is usually to produce a series of patches such that:
+
+	1. Each patch can be applied in order.
+
+	2. Each patch includes a single logical change, together with a
+	   message explaining the change.
+
+	3. No patch introduces a regression: after applying any initial
+	   part of the series, the resulting project still compiles and
+	   works, and has no bugs that it didn't have before.
+
+	4. The complete series produces the same end result as your own
+	   (probably much messier!) development process did.
+
+We will introduce some tools that can help you do this, explain how to
+use them, and then explain some of the problems that can arise because
+you are rewriting history.
+
+[[using-git-rebase]]
+=== Keeping a patch series up to date using git rebase
+
+Suppose that you create a branch `mywork` on a remote-tracking branch
+`origin`, and create some commits on top of it:
+
+-------------------------------------------------
+$ git switch -c mywork origin
+$ vi file.txt
+$ git commit
+$ vi otherfile.txt
+$ git commit
+...
+-------------------------------------------------
+
+You have performed no merges into mywork, so it is just a simple linear
+sequence of patches on top of `origin`:
+
+................................................
+ o--o--O <-- origin
+        \
+	 a--b--c <-- mywork
+................................................
+
+Some more interesting work has been done in the upstream project, and
+`origin` has advanced:
+
+................................................
+ o--o--O--o--o--o <-- origin
+        \
+         a--b--c <-- mywork
+................................................
+
+At this point, you could use `pull` to merge your changes back in;
+the result would create a new merge commit, like this:
+
+................................................
+ o--o--O--o--o--o <-- origin
+        \        \
+         a--b--c--m <-- mywork
+................................................
+
+However, if you prefer to keep the history in mywork a simple series of
+commits without any merges, you may instead choose to use
+linkgit:git-rebase[1]:
+
+-------------------------------------------------
+$ git switch mywork
+$ git rebase origin
+-------------------------------------------------
+
+This will remove each of your commits from mywork, temporarily saving
+them as patches (in a directory named `.git/rebase-apply`), update mywork to
+point at the latest version of origin, then apply each of the saved
+patches to the new mywork.  The result will look like:
+
+
+................................................
+ o--o--O--o--o--o <-- origin
+		 \
+		  a'--b'--c' <-- mywork
+................................................
+
+In the process, it may discover conflicts.  In that case it will stop
+and allow you to fix the conflicts; after fixing conflicts, use `git add`
+to update the index with those contents, and then, instead of
+running `git commit`, just run
+
+-------------------------------------------------
+$ git rebase --continue
+-------------------------------------------------
+
+and Git will continue applying the rest of the patches.
+
+At any point you may use the `--abort` option to abort this process and
+return mywork to the state it had before you started the rebase:
+
+-------------------------------------------------
+$ git rebase --abort
+-------------------------------------------------
+
+If you need to reorder or edit a number of commits in a branch, it may
+be easier to use `git rebase -i`, which allows you to reorder and
+squash commits, as well as marking them for individual editing during
+the rebase.  See <<interactive-rebase>> for details, and
+<<reordering-patch-series>> for alternatives.
+
+[[rewriting-one-commit]]
+=== Rewriting a single commit
+
+We saw in <<fixing-a-mistake-by-rewriting-history>> that you can replace the
+most recent commit using
+
+-------------------------------------------------
+$ git commit --amend
+-------------------------------------------------
+
+which will replace the old commit by a new commit incorporating your
+changes, giving you a chance to edit the old commit message first.
+This is useful for fixing typos in your last commit, or for adjusting
+the patch contents of a poorly staged commit.
+
+If you need to amend commits from deeper in your history, you can
+use <<interactive-rebase,interactive rebase's `edit` instruction>>.
+
+[[reordering-patch-series]]
+=== Reordering or selecting from a patch series
+
+Sometimes you want to edit a commit deeper in your history.  One
+approach is to use `git format-patch` to create a series of patches
+and then reset the state to before the patches:
+
+-------------------------------------------------
+$ git format-patch origin
+$ git reset --hard origin
+-------------------------------------------------
+
+Then modify, reorder, or eliminate patches as needed before applying
+them again with linkgit:git-am[1]:
+
+-------------------------------------------------
+$ git am *.patch
+-------------------------------------------------
+
+[[interactive-rebase]]
+=== Using interactive rebases
+
+You can also edit a patch series with an interactive rebase.  This is
+the same as <<reordering-patch-series,reordering a patch series using
+`format-patch`>>, so use whichever interface you like best.
+
+Rebase your current HEAD on the last commit you want to retain as-is.
+For example, if you want to reorder the last 5 commits, use:
+
+-------------------------------------------------
+$ git rebase -i HEAD~5
+-------------------------------------------------
+
+This will open your editor with a list of steps to be taken to perform
+your rebase.
+
+-------------------------------------------------
+pick deadbee The oneline of this commit
+pick fa1afe1 The oneline of the next commit
+...
+
+# Rebase c0ffeee..deadbee onto c0ffeee
+#
+# Commands:
+#  p, pick = use commit
+#  r, reword = use commit, but edit the commit message
+#  e, edit = use commit, but stop for amending
+#  s, squash = use commit, but meld into previous commit
+#  f, fixup = like "squash", but discard this commit's log message
+#  x, exec = run command (the rest of the line) using shell
+#
+# These lines can be re-ordered; they are executed from top to bottom.
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+#
+# However, if you remove everything, the rebase will be aborted.
+#
+# Note that empty commits are commented out
+-------------------------------------------------
+
+As explained in the comments, you can reorder commits, squash them
+together, edit commit messages, etc. by editing the list.  Once you
+are satisfied, save the list and close your editor, and the rebase
+will begin.
+
+The rebase will stop where `pick` has been replaced with `edit` or
+when a step in the list fails to mechanically resolve conflicts and
+needs your help.  When you are done editing and/or resolving conflicts
+you can continue with `git rebase --continue`.  If you decide that
+things are getting too hairy, you can always bail out with `git rebase
+--abort`.  Even after the rebase is complete, you can still recover
+the original branch by using the <<reflogs,reflog>>.
+
+For a more detailed discussion of the procedure and additional tips,
+see the "INTERACTIVE MODE" section of linkgit:git-rebase[1].
+
+[[patch-series-tools]]
+=== Other tools
+
+There are numerous other tools, such as StGit, which exist for the
+purpose of maintaining a patch series.  These are outside of the scope of
+this manual.
+
+[[problems-With-rewriting-history]]
+=== Problems with rewriting history
+
+The primary problem with rewriting the history of a branch has to do
+with merging.  Suppose somebody fetches your branch and merges it into
+their branch, with a result something like this:
+
+................................................
+ o--o--O--o--o--o <-- origin
+        \        \
+         t--t--t--m <-- their branch:
+................................................
+
+Then suppose you modify the last three commits:
+
+................................................
+	 o--o--o <-- new head of origin
+	/
+ o--o--O--o--o--o <-- old head of origin
+................................................
+
+If we examined all this history together in one repository, it will
+look like:
+
+................................................
+	 o--o--o <-- new head of origin
+	/
+ o--o--O--o--o--o <-- old head of origin
+        \        \
+         t--t--t--m <-- their branch:
+................................................
+
+Git has no way of knowing that the new head is an updated version of
+the old head; it treats this situation exactly the same as it would if
+two developers had independently done the work on the old and new heads
+in parallel.  At this point, if someone attempts to merge the new head
+in to their branch, Git will attempt to merge together the two (old and
+new) lines of development, instead of trying to replace the old by the
+new.  The results are likely to be unexpected.
+
+You may still choose to publish branches whose history is rewritten,
+and it may be useful for others to be able to fetch those branches in
+order to examine or test them, but they should not attempt to pull such
+branches into their own work.
+
+For true distributed development that supports proper merging,
+published branches should never be rewritten.
+
+[[bisect-merges]]
+=== Why bisecting merge commits can be harder than bisecting linear history
+
+The linkgit:git-bisect[1] command correctly handles history that
+includes merge commits.  However, when the commit that it finds is a
+merge commit, the user may need to work harder than usual to figure out
+why that commit introduced a problem.
+
+Imagine this history:
+
+................................................
+      ---Z---o---X---...---o---A---C---D
+          \                       /
+           o---o---Y---...---o---B
+................................................
+
+Suppose that on the upper line of development, the meaning of one
+of the functions that exists at Z is changed at commit X.  The
+commits from Z leading to A change both the function's
+implementation and all calling sites that exist at Z, as well
+as new calling sites they add, to be consistent.  There is no
+bug at A.
+
+Suppose that in the meantime on the lower line of development somebody
+adds a new calling site for that function at commit Y.  The
+commits from Z leading to B all assume the old semantics of that
+function and the callers and the callee are consistent with each
+other.  There is no bug at B, either.
+
+Suppose further that the two development lines merge cleanly at C,
+so no conflict resolution is required.
+
+Nevertheless, the code at C is broken, because the callers added
+on the lower line of development have not been converted to the new
+semantics introduced on the upper line of development.  So if all
+you know is that D is bad, that Z is good, and that
+linkgit:git-bisect[1] identifies C as the culprit, how will you
+figure out that the problem is due to this change in semantics?
+
+When the result of a `git bisect` is a non-merge commit, you should
+normally be able to discover the problem by examining just that commit.
+Developers can make this easy by breaking their changes into small
+self-contained commits.  That won't help in the case above, however,
+because the problem isn't obvious from examination of any single
+commit; instead, a global view of the development is required.  To
+make matters worse, the change in semantics in the problematic
+function may be just one small part of the changes in the upper
+line of development.
+
+On the other hand, if instead of merging at C you had rebased the
+history between Z to B on top of A, you would have gotten this
+linear history:
+
+................................................................
+    ---Z---o---X--...---o---A---o---o---Y*--...---o---B*--D*
+................................................................
+
+Bisecting between Z and D* would hit a single culprit commit Y*,
+and understanding why Y* was broken would probably be easier.
+
+Partly for this reason, many experienced Git users, even when
+working on an otherwise merge-heavy project, keep the history
+linear by rebasing against the latest upstream version before
+publishing.
+
+[[advanced-branch-management]]
+== Advanced branch management
+
+[[fetching-individual-branches]]
+=== Fetching individual branches
+
+Instead of using linkgit:git-remote[1], you can also choose just
+to update one branch at a time, and to store it locally under an
+arbitrary name:
+
+-------------------------------------------------
+$ git fetch origin todo:my-todo-work
+-------------------------------------------------
+
+The first argument, `origin`, just tells Git to fetch from the
+repository you originally cloned from.  The second argument tells Git
+to fetch the branch named `todo` from the remote repository, and to
+store it locally under the name `refs/heads/my-todo-work`.
+
+You can also fetch branches from other repositories; so
+
+-------------------------------------------------
+$ git fetch git://example.com/proj.git master:example-master
+-------------------------------------------------
+
+will create a new branch named `example-master` and store in it the
+branch named `master` from the repository at the given URL.  If you
+already have a branch named example-master, it will attempt to
+<<fast-forwards,fast-forward>> to the commit given by example.com's
+master branch.  In more detail:
+
+[[fetch-fast-forwards]]
+=== git fetch and fast-forwards
+
+In the previous example, when updating an existing branch, `git fetch`
+checks to make sure that the most recent commit on the remote
+branch is a descendant of the most recent commit on your copy of the
+branch before updating your copy of the branch to point at the new
+commit.  Git calls this process a <<fast-forwards,fast-forward>>.
+
+A fast-forward looks something like this:
+
+................................................
+ o--o--o--o <-- old head of the branch
+           \
+            o--o--o <-- new head of the branch
+................................................
+
+
+In some cases it is possible that the new head will *not* actually be
+a descendant of the old head.  For example, the developer may have
+realized a serious mistake was made and decided to backtrack,
+resulting in a situation like:
+
+................................................
+ o--o--o--o--a--b <-- old head of the branch
+           \
+            o--o--o <-- new head of the branch
+................................................
+
+In this case, `git fetch` will fail, and print out a warning.
+
+In that case, you can still force Git to update to the new head, as
+described in the following section.  However, note that in the
+situation above this may mean losing the commits labeled `a` and `b`,
+unless you've already created a reference of your own pointing to
+them.
+
+[[forcing-fetch]]
+=== Forcing git fetch to do non-fast-forward updates
+
+If git fetch fails because the new head of a branch is not a
+descendant of the old head, you may force the update with:
+
+-------------------------------------------------
+$ git fetch git://example.com/proj.git +master:refs/remotes/example/master
+-------------------------------------------------
+
+Note the addition of the `+` sign.  Alternatively, you can use the `-f`
+flag to force updates of all the fetched branches, as in:
+
+-------------------------------------------------
+$ git fetch -f origin
+-------------------------------------------------
+
+Be aware that commits that the old version of example/master pointed at
+may be lost, as we saw in the previous section.
+
+[[remote-branch-configuration]]
+=== Configuring remote-tracking branches
+
+We saw above that `origin` is just a shortcut to refer to the
+repository that you originally cloned from.  This information is
+stored in Git configuration variables, which you can see using
+linkgit:git-config[1]:
+
+-------------------------------------------------
+$ git config -l
+core.repositoryformatversion=0
+core.filemode=true
+core.logallrefupdates=true
+remote.origin.url=git://git.kernel.org/pub/scm/git/git.git
+remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
+branch.master.remote=origin
+branch.master.merge=refs/heads/master
+-------------------------------------------------
+
+If there are other repositories that you also use frequently, you can
+create similar configuration options to save typing; for example,
+
+-------------------------------------------------
+$ git remote add example git://example.com/proj.git
+-------------------------------------------------
+
+adds the following to `.git/config`:
+
+-------------------------------------------------
+[remote "example"]
+	url = git://example.com/proj.git
+	fetch = +refs/heads/*:refs/remotes/example/*
+-------------------------------------------------
+
+Also note that the above configuration can be performed by directly
+editing the file `.git/config` instead of using linkgit:git-remote[1].
+
+After configuring the remote, the following three commands will do the
+same thing:
+
+-------------------------------------------------
+$ git fetch git://example.com/proj.git +refs/heads/*:refs/remotes/example/*
+$ git fetch example +refs/heads/*:refs/remotes/example/*
+$ git fetch example
+-------------------------------------------------
+
+See linkgit:git-config[1] for more details on the configuration
+options mentioned above and linkgit:git-fetch[1] for more details on
+the refspec syntax.
+
+
+[[git-concepts]]
+== Git concepts
+
+Git is built on a small number of simple but powerful ideas.  While it
+is possible to get things done without understanding them, you will find
+Git much more intuitive if you do.
+
+We start with the most important, the  <<def_object_database,object
+database>> and the <<def_index,index>>.
+
+[[the-object-database]]
+=== The Object Database
+
+
+We already saw in <<understanding-commits>> that all commits are stored
+under a 40-digit "object name".  In fact, all the information needed to
+represent the history of a project is stored in objects with such names.
+In each case the name is calculated by taking the SHA-1 hash of the
+contents of the object.  The SHA-1 hash is a cryptographic hash function.
+What that means to us is that it is impossible to find two different
+objects with the same name.  This has a number of advantages; among
+others:
+
+- Git can quickly determine whether two objects are identical or not,
+  just by comparing names.
+- Since object names are computed the same way in every repository, the
+  same content stored in two repositories will always be stored under
+  the same name.
+- Git can detect errors when it reads an object, by checking that the
+  object's name is still the SHA-1 hash of its contents.
+
+(See <<object-details>> for the details of the object formatting and
+SHA-1 calculation.)
+
+There are four different types of objects: "blob", "tree", "commit", and
+"tag".
+
+- A <<def_blob_object,"blob" object>> is used to store file data.
+- A <<def_tree_object,"tree" object>> ties one or more
+  "blob" objects into a directory structure. In addition, a tree object
+  can refer to other tree objects, thus creating a directory hierarchy.
+- A <<def_commit_object,"commit" object>> ties such directory hierarchies
+  together into a <<def_DAG,directed acyclic graph>> of revisions--each
+  commit contains the object name of exactly one tree designating the
+  directory hierarchy at the time of the commit. In addition, a commit
+  refers to "parent" commit objects that describe the history of how we
+  arrived at that directory hierarchy.
+- A <<def_tag_object,"tag" object>> symbolically identifies and can be
+  used to sign other objects. It contains the object name and type of
+  another object, a symbolic name (of course!) and, optionally, a
+  signature.
+
+The object types in some more detail:
+
+[[commit-object]]
+==== Commit Object
+
+The "commit" object links a physical state of a tree with a description
+of how we got there and why.  Use the `--pretty=raw` option to
+linkgit:git-show[1] or linkgit:git-log[1] to examine your favorite
+commit:
+
+------------------------------------------------
+$ git show -s --pretty=raw 2be7fcb476
+commit 2be7fcb4764f2dbcee52635b91fedb1b3dcf7ab4
+tree fb3a8bdd0ceddd019615af4d57a53f43d8cee2bf
+parent 257a84d9d02e90447b149af58b271c19405edb6a
+author Dave Watson <dwatson@xxxxxxxxxxxx> 1187576872 -0400
+committer Junio C Hamano <gitster@xxxxxxxxx> 1187591163 -0700
+
+    Fix misspelling of 'suppress' in docs
+
+    Signed-off-by: Junio C Hamano <gitster@xxxxxxxxx>
+------------------------------------------------
+
+As you can see, a commit is defined by:
+
+- a tree: The SHA-1 name of a tree object (as defined below), representing
+  the contents of a directory at a certain point in time.
+- parent(s): The SHA-1 name(s) of some number of commits which represent the
+  immediately previous step(s) in the history of the project.  The
+  example above has one parent; merge commits may have more than
+  one.  A commit with no parents is called a "root" commit, and
+  represents the initial revision of a project.  Each project must have
+  at least one root.  A project can also have multiple roots, though
+  that isn't common (or necessarily a good idea).
+- an author: The name of the person responsible for this change, together
+  with its date.
+- a committer: The name of the person who actually created the commit,
+  with the date it was done.  This may be different from the author, for
+  example, if the author was someone who wrote a patch and emailed it
+  to the person who used it to create the commit.
+- a comment describing this commit.
+
+Note that a commit does not itself contain any information about what
+actually changed; all changes are calculated by comparing the contents
+of the tree referred to by this commit with the trees associated with
+its parents.  In particular, Git does not attempt to record file renames
+explicitly, though it can identify cases where the existence of the same
+file data at changing paths suggests a rename.  (See, for example, the
+`-M` option to linkgit:git-diff[1]).
+
+A commit is usually created by linkgit:git-commit[1], which creates a
+commit whose parent is normally the current HEAD, and whose tree is
+taken from the content currently stored in the index.
+
+[[tree-object]]
+==== Tree Object
+
+The ever-versatile linkgit:git-show[1] command can also be used to
+examine tree objects, but linkgit:git-ls-tree[1] will give you more
+details:
+
+------------------------------------------------
+$ git ls-tree fb3a8bdd0ce
+100644 blob 63c918c667fa005ff12ad89437f2fdc80926e21c    .gitignore
+100644 blob 5529b198e8d14decbe4ad99db3f7fb632de0439d    .mailmap
+100644 blob 6ff87c4664981e4397625791c8ea3bbb5f2279a3    COPYING
+040000 tree 2fb783e477100ce076f6bf57e4a6f026013dc745    Documentation
+100755 blob 3c0032cec592a765692234f1cba47dfdcc3a9200    GIT-VERSION-GEN
+100644 blob 289b046a443c0647624607d471289b2c7dcd470b    INSTALL
+100644 blob 4eb463797adc693dc168b926b6932ff53f17d0b1    Makefile
+100644 blob 548142c327a6790ff8821d67c2ee1eff7a656b52    README
+...
+------------------------------------------------
+
+As you can see, a tree object contains a list of entries, each with a
+mode, object type, SHA-1 name, and name, sorted by name.  It represents
+the contents of a single directory tree.
+
+The object type may be a blob, representing the contents of a file, or
+another tree, representing the contents of a subdirectory.  Since trees
+and blobs, like all other objects, are named by the SHA-1 hash of their
+contents, two trees have the same SHA-1 name if and only if their
+contents (including, recursively, the contents of all subdirectories)
+are identical.  This allows Git to quickly determine the differences
+between two related tree objects, since it can ignore any entries with
+identical object names.
+
+(Note: in the presence of submodules, trees may also have commits as
+entries.  See <<submodules>> for documentation.)
+
+Note that the files all have mode 644 or 755: Git actually only pays
+attention to the executable bit.
+
+[[blob-object]]
+==== Blob Object
+
+You can use linkgit:git-show[1] to examine the contents of a blob; take,
+for example, the blob in the entry for `COPYING` from the tree above:
+
+------------------------------------------------
+$ git show 6ff87c4664
+
+ Note that the only valid version of the GPL as far as this project
+ is concerned is _this_ particular version of the license (ie v2, not
+ v2.2 or v3.x or whatever), unless explicitly otherwise stated.
+...
+------------------------------------------------
+
+A "blob" object is nothing but a binary blob of data.  It doesn't refer
+to anything else or have attributes of any kind.
+
+Since the blob is entirely defined by its data, if two files in a
+directory tree (or in multiple different versions of the repository)
+have the same contents, they will share the same blob object. The object
+is totally independent of its location in the directory tree, and
+renaming a file does not change the object that file is associated with.
+
+Note that any tree or blob object can be examined using
+linkgit:git-show[1] with the <revision>:<path> syntax.  This can
+sometimes be useful for browsing the contents of a tree that is not
+currently checked out.
+
+[[trust]]
+==== Trust
+
+If you receive the SHA-1 name of a blob from one source, and its contents
+from another (possibly untrusted) source, you can still trust that those
+contents are correct as long as the SHA-1 name agrees.  This is because
+the SHA-1 is designed so that it is infeasible to find different contents
+that produce the same hash.
+
+Similarly, you need only trust the SHA-1 name of a top-level tree object
+to trust the contents of the entire directory that it refers to, and if
+you receive the SHA-1 name of a commit from a trusted source, then you
+can easily verify the entire history of commits reachable through
+parents of that commit, and all of those contents of the trees referred
+to by those commits.
+
+So to introduce some real trust in the system, the only thing you need
+to do is to digitally sign just 'one' special note, which includes the
+name of a top-level commit.  Your digital signature shows others
+that you trust that commit, and the immutability of the history of
+commits tells others that they can trust the whole history.
+
+In other words, you can easily validate a whole archive by just
+sending out a single email that tells the people the name (SHA-1 hash)
+of the top commit, and digitally sign that email using something
+like GPG/PGP.
+
+To assist in this, Git also provides the tag object...
+
+[[tag-object]]
+==== Tag Object
+
+A tag object contains an object, object type, tag name, the name of the
+person ("tagger") who created the tag, and a message, which may contain
+a signature, as can be seen using linkgit:git-cat-file[1]:
+
+------------------------------------------------
+$ git cat-file tag v1.5.0
+object 437b1b20df4b356c9342dac8d38849f24ef44f27
+type commit
+tag v1.5.0
+tagger Junio C Hamano <junkio@xxxxxxx> 1171411200 +0000
+
+GIT 1.5.0
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+iD8DBQBF0lGqwMbZpPMRm5oRAuRiAJ9ohBLd7s2kqjkKlq1qqC57SbnmzQCdG4ui
+nLE/L9aUXdWeTFPron96DLA=
+=2E+0
+-----END PGP SIGNATURE-----
+------------------------------------------------
+
+See the linkgit:git-tag[1] command to learn how to create and verify tag
+objects.  (Note that linkgit:git-tag[1] can also be used to create
+"lightweight tags", which are not tag objects at all, but just simple
+references whose names begin with `refs/tags/`).
+
+[[pack-files]]
+==== How Git stores objects efficiently: pack files
+
+Newly created objects are initially created in a file named after the
+object's SHA-1 hash (stored in `.git/objects`).
+
+Unfortunately this system becomes inefficient once a project has a
+lot of objects.  Try this on an old project:
+
+------------------------------------------------
+$ git count-objects
+6930 objects, 47620 kilobytes
+------------------------------------------------
+
+The first number is the number of objects which are kept in
+individual files.  The second is the amount of space taken up by
+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 linkgit:gitformat-pack[5].
+
+To put the loose objects into a pack, just run git repack:
+
+------------------------------------------------
+$ git repack
+Counting objects: 6020, done.
+Delta compression using up to 4 threads.
+Compressing objects: 100% (6020/6020), done.
+Writing objects: 100% (6020/6020), done.
+Total 6020 (delta 4070), reused 0 (delta 0)
+------------------------------------------------
+
+This creates a single "pack file" in .git/objects/pack/
+containing all currently unpacked objects.  You can then run
+
+------------------------------------------------
+$ git prune
+------------------------------------------------
+
+to remove any of the "loose" objects that are now contained in the
+pack.  This will also remove any unreferenced objects (which may be
+created when, for example, you use `git reset` to remove a commit).
+You can verify that the loose objects are gone by looking at the
+`.git/objects` directory or by running
+
+------------------------------------------------
+$ git count-objects
+0 objects, 0 kilobytes
+------------------------------------------------
+
+Although the object files are gone, any commands that refer to those
+objects will work exactly as they did before.
+
+The linkgit:git-gc[1] command performs packing, pruning, and more for
+you, so is normally the only high-level command you need.
+
+[[dangling-objects]]
+==== Dangling objects
+
+The linkgit:git-fsck[1] command will sometimes complain about dangling
+objects.  They are not a problem.
+
+The most common cause of dangling objects is that you've rebased a
+branch, or you have pulled from somebody else who rebased a branch--see
+<<cleaning-up-history>>.  In that case, the old head of the original
+branch still exists, as does everything it pointed to. The branch
+pointer itself just doesn't, since you replaced it with another one.
+
+There are also other situations that cause dangling objects. For
+example, a "dangling blob" may arise because you did a `git add` of a
+file, but then, before you actually committed it and made it part of the
+bigger picture, you changed something else in that file and committed
+that *updated* thing--the old state that you added originally ends up
+not being pointed to by any commit or tree, so it's now a dangling blob
+object.
+
+Similarly, when the "ort" merge strategy runs, and finds that
+there are criss-cross merges and thus more than one merge base (which is
+fairly unusual, but it does happen), it will generate one temporary
+midway tree (or possibly even more, if you had lots of criss-crossing
+merges and more than two merge bases) as a temporary internal merge
+base, and again, those are real objects, but the end result will not end
+up pointing to them, so they end up "dangling" in your repository.
+
+Generally, dangling objects aren't anything to worry about. They can
+even be very useful: if you screw something up, the dangling objects can
+be how you recover your old tree (say, you did a rebase, and realized
+that you really didn't want to--you can look at what dangling objects
+you have, and decide to reset your head to some old dangling state).
+
+For commits, you can just use:
+
+------------------------------------------------
+$ gitk <dangling-commit-sha-goes-here> --not --all
+------------------------------------------------
+
+This asks for all the history reachable from the given commit but not
+from any branch, tag, or other reference.  If you decide it's something
+you want, you can always create a new reference to it, e.g.,
+
+------------------------------------------------
+$ git branch recovered-branch <dangling-commit-sha-goes-here>
+------------------------------------------------
+
+For blobs and trees, you can't do the same, but you can still examine
+them.  You can just do
+
+------------------------------------------------
+$ git show <dangling-blob/tree-sha-goes-here>
+------------------------------------------------
+
+to show what the contents of the blob were (or, for a tree, basically
+what the `ls` for that directory was), and that may give you some idea
+of what the operation was that left that dangling object.
+
+Usually, dangling blobs and trees aren't very interesting. They're
+almost always the result of either being a half-way mergebase (the blob
+will often even have the conflict markers from a merge in it, if you
+have had conflicting merges that you fixed up by hand), or simply
+because you interrupted a `git fetch` with ^C or something like that,
+leaving _some_ of the new objects in the object database, but just
+dangling and useless.
+
+Anyway, once you are sure that you're not interested in any dangling
+state, you can just prune all unreachable objects:
+
+------------------------------------------------
+$ git prune
+------------------------------------------------
+
+and they'll be gone. (You should only run `git prune` on a quiescent
+repository--it's kind of like doing a filesystem fsck recovery: you
+don't want to do that while the filesystem is mounted.
+`git prune` is designed not to cause any harm in such cases of concurrent
+accesses to a repository but you might receive confusing or scary messages.)
+
+[[recovering-from-repository-corruption]]
+==== Recovering from repository corruption
+
+By design, Git treats data trusted to it with caution.  However, even in
+the absence of bugs in Git itself, it is still possible that hardware or
+operating system errors could corrupt data.
+
+The first defense against such problems is backups.  You can back up a
+Git directory using clone, or just using cp, tar, or any other backup
+mechanism.
+
+As a last resort, you can search for the corrupted objects and attempt
+to replace them by hand.  Back up your repository before attempting this
+in case you corrupt things even more in the process.
+
+We'll assume that the problem is a single missing or corrupted blob,
+which is sometimes a solvable problem.  (Recovering missing trees and
+especially commits is *much* harder).
+
+Before starting, verify that there is corruption, and figure out where
+it is with linkgit:git-fsck[1]; this may be time-consuming.
+
+Assume the output looks like this:
+
+------------------------------------------------
+$ git fsck --full --no-dangling
+broken link from    tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
+              to    blob 4b9458b3786228369c63936db65827de3cc06200
+missing blob 4b9458b3786228369c63936db65827de3cc06200
+------------------------------------------------
+
+Now you know that blob 4b9458b3 is missing, and that the tree 2d9263c6
+points to it.  If you could find just one copy of that missing blob
+object, possibly in some other repository, you could move it into
+`.git/objects/4b/9458b3...` and be done.  Suppose you can't.  You can
+still examine the tree that pointed to it with linkgit:git-ls-tree[1],
+which might output something like:
+
+------------------------------------------------
+$ git ls-tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
+100644 blob 8d14531846b95bfa3564b58ccfb7913a034323b8	.gitignore
+100644 blob ebf9bf84da0aab5ed944264a5db2a65fe3a3e883	.mailmap
+100644 blob ca442d313d86dc67e0a2e5d584b465bd382cbf5c	COPYING
+...
+100644 blob 4b9458b3786228369c63936db65827de3cc06200	myfile
+...
+------------------------------------------------
+
+So now you know that the missing blob was the data for a file named
+`myfile`.  And chances are you can also identify the directory--let's
+say it's in `somedirectory`.  If you're lucky the missing copy might be
+the same as the copy you have checked out in your working tree at
+`somedirectory/myfile`; you can test whether that's right with
+linkgit:git-hash-object[1]:
+
+------------------------------------------------
+$ git hash-object -w somedirectory/myfile
+------------------------------------------------
+
+which will create and store a blob object with the contents of
+somedirectory/myfile, and output the SHA-1 of that object.  if you're
+extremely lucky it might be 4b9458b3786228369c63936db65827de3cc06200, in
+which case you've guessed right, and the corruption is fixed!
+
+Otherwise, you need more information.  How do you tell which version of
+the file has been lost?
+
+The easiest way to do this is with:
+
+------------------------------------------------
+$ git log --raw --all --full-history -- somedirectory/myfile
+------------------------------------------------
+
+Because you're asking for raw output, you'll now get something like
+
+------------------------------------------------
+commit abc
+Author:
+Date:
+...
+:100644 100644 4b9458b newsha M somedirectory/myfile
+
+
+commit xyz
+Author:
+Date:
+
+...
+:100644 100644 oldsha 4b9458b M somedirectory/myfile
+------------------------------------------------
+
+This tells you that the immediately following version of the file was
+"newsha", and that the immediately preceding version was "oldsha".
+You also know the commit messages that went with the change from oldsha
+to 4b9458b and with the change from 4b9458b to newsha.
+
+If you've been committing small enough changes, you may now have a good
+shot at reconstructing the contents of the in-between state 4b9458b.
+
+If you can do that, you can now recreate the missing object with
+
+------------------------------------------------
+$ git hash-object -w <recreated-file>
+------------------------------------------------
+
+and your repository is good again!
+
+(Btw, you could have ignored the `fsck`, and started with doing a
+
+------------------------------------------------
+$ git log --raw --all
+------------------------------------------------
+
+and just looked for the sha of the missing object (4b9458b) in that
+whole thing. It's up to you--Git does *have* a lot of information, it is
+just missing one particular blob version.
+
+[[the-index]]
+=== The index
+
+The index is a binary file (generally kept in `.git/index`) containing a
+sorted list of path names, each with permissions and the SHA-1 of a blob
+object; linkgit:git-ls-files[1] can show you the contents of the index:
+
+-------------------------------------------------
+$ git ls-files --stage
+100644 63c918c667fa005ff12ad89437f2fdc80926e21c 0	.gitignore
+100644 5529b198e8d14decbe4ad99db3f7fb632de0439d 0	.mailmap
+100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0	COPYING
+100644 a37b2152bd26be2c2289e1f57a292534a51a93c7 0	Documentation/.gitignore
+100644 fbefe9a45b00a54b58d94d06eca48b03d40a50e0 0	Documentation/Makefile
+...
+100644 2511aef8d89ab52be5ec6a5e46236b4b6bcd07ea 0	xdiff/xtypes.h
+100644 2ade97b2574a9f77e7ae4002a4e07a6a38e46d07 0	xdiff/xutils.c
+100644 d5de8292e05e7c36c4b68857c1cf9855e3d2f70a 0	xdiff/xutils.h
+-------------------------------------------------
+
+Note that in older documentation you may see the index called the
+"current directory cache" or just the "cache".  It has three important
+properties:
+
+1. The index contains all the information necessary to generate a single
+(uniquely determined) tree object.
++
+For example, running linkgit:git-commit[1] generates this tree object
+from the index, stores it in the object database, and uses it as the
+tree object associated with the new commit.
+
+2. The index enables fast comparisons between the tree object it defines
+and the working tree.
++
+It does this by storing some additional data for each entry (such as
+the last modified time).  This data is not displayed above, and is not
+stored in the created tree object, but it can be used to determine
+quickly which files in the working directory differ from what was
+stored in the index, and thus save Git from having to read all of the
+data from such files to look for changes.
+
+3. It can efficiently represent information about merge conflicts
+between different tree objects, allowing each pathname to be
+associated with sufficient information about the trees involved that
+you can create a three-way merge between them.
++
+We saw in <<conflict-resolution>> that during a merge the index can
+store multiple versions of a single file (called "stages").  The third
+column in the linkgit:git-ls-files[1] output above is the stage
+number, and will take on values other than 0 for files with merge
+conflicts.
+
+The index is thus a sort of temporary staging area, which is filled with
+a tree which you are in the process of working on.
+
+If you blow the index away entirely, you generally haven't lost any
+information as long as you have the name of the tree that it described.
+
+[[submodules]]
+== Submodules
+
+Large projects are often composed of smaller, self-contained modules.  For
+example, an embedded Linux distribution's source tree would include every
+piece of software in the distribution with some local modifications; a movie
+player might need to build against a specific, known-working version of a
+decompression library; several independent programs might all share the same
+build scripts.
+
+With centralized revision control systems this is often accomplished by
+including every module in one single repository.  Developers can check out
+all modules or only the modules they need to work with.  They can even modify
+files across several modules in a single commit while moving things around
+or updating APIs and translations.
+
+Git does not allow partial checkouts, so duplicating this approach in Git
+would force developers to keep a local copy of modules they are not
+interested in touching.  Commits in an enormous checkout would be slower
+than you'd expect as Git would have to scan every directory for changes.
+If modules have a lot of local history, clones would take forever.
+
+On the plus side, distributed revision control systems can much better
+integrate with external sources.  In a centralized model, a single arbitrary
+snapshot of the external project is exported from its own revision control
+and then imported into the local revision control on a vendor branch.  All
+the history is hidden.  With distributed revision control you can clone the
+entire external history and much more easily follow development and re-merge
+local changes.
+
+Git's submodule support allows a repository to contain, as a subdirectory, a
+checkout of an external project.  Submodules maintain their own identity;
+the submodule support just stores the submodule repository location and
+commit ID, so other developers who clone the containing project
+("superproject") can easily clone all the submodules at the same revision.
+Partial checkouts of the superproject are possible: you can tell Git to
+clone none, some or all of the submodules.
+
+The linkgit:git-submodule[1] command is available since Git 1.5.3.  Users
+with Git 1.5.2 can look up the submodule commits in the repository and
+manually check them out; earlier versions won't recognize the submodules at
+all.
+
+To see how submodule support works, create four example
+repositories that can be used later as a submodule:
+
+-------------------------------------------------
+$ mkdir ~/git
+$ cd ~/git
+$ for i in a b c d
+do
+	mkdir $i
+	cd $i
+	git init
+	echo "module $i" > $i.txt
+	git add $i.txt
+	git commit -m "Initial commit, submodule $i"
+	cd ..
+done
+-------------------------------------------------
+
+Now create the superproject and add all the submodules:
+
+-------------------------------------------------
+$ mkdir super
+$ cd super
+$ git init
+$ for i in a b c d
+do
+	git submodule add ~/git/$i $i
+done
+-------------------------------------------------
+
+NOTE: Do not use local URLs here if you plan to publish your superproject!
+
+See what files `git submodule` created:
+
+-------------------------------------------------
+$ ls -a
+.  ..  .git  .gitmodules  a  b  c  d
+-------------------------------------------------
+
+The `git submodule add <repo> <path>` command does a couple of things:
+
+- It clones the submodule from `<repo>` to the given `<path>` under the
+  current directory and by default checks out the master branch.
+- It adds the submodule's clone path to the linkgit:gitmodules[5] file and
+  adds this file to the index, ready to be committed.
+- It adds the submodule's current commit ID to the index, ready to be
+  committed.
+
+Commit the superproject:
+
+-------------------------------------------------
+$ git commit -m "Add submodules a, b, c and d."
+-------------------------------------------------
+
+Now clone the superproject:
+
+-------------------------------------------------
+$ cd ..
+$ git clone super cloned
+$ cd cloned
+-------------------------------------------------
+
+The submodule directories are there, but they're empty:
+
+-------------------------------------------------
+$ ls -a a
+.  ..
+$ git submodule status
+-d266b9873ad50488163457f025db7cdd9683d88b a
+-e81d457da15309b4fef4249aba9b50187999670d b
+-c1536a972b9affea0f16e0680ba87332dc059146 c
+-d96249ff5d57de5de093e6baff9e0aafa5276a74 d
+-------------------------------------------------
+
+NOTE: The commit object names shown above would be different for you, but they
+should match the HEAD commit object names of your repositories.  You can check
+it by running `git ls-remote ../a`.
+
+Pulling down the submodules is a two-step process. First run `git submodule
+init` to add the submodule repository URLs to `.git/config`:
+
+-------------------------------------------------
+$ git submodule init
+-------------------------------------------------
+
+Now use `git submodule update` to clone the repositories and check out the
+commits specified in the superproject:
+
+-------------------------------------------------
+$ git submodule update
+$ cd a
+$ ls -a
+.  ..  .git  a.txt
+-------------------------------------------------
+
+One major difference between `git submodule update` and `git submodule add` is
+that `git submodule update` checks out a specific commit, rather than the tip
+of a branch. It's like checking out a tag: the head is detached, so you're not
+working on a branch.
+
+-------------------------------------------------
+$ git branch
+* (detached from d266b98)
+  master
+-------------------------------------------------
+
+If you want to make a change within a submodule and you have a detached head,
+then you should create or checkout a branch, make your changes, publish the
+change within the submodule, and then update the superproject to reference the
+new commit:
+
+-------------------------------------------------
+$ git switch master
+-------------------------------------------------
+
+or
+
+-------------------------------------------------
+$ git switch -c fix-up
+-------------------------------------------------
+
+then
+
+-------------------------------------------------
+$ echo "adding a line again" >> a.txt
+$ git commit -a -m "Updated the submodule from within the superproject."
+$ git push
+$ cd ..
+$ git diff
+diff --git a/a b/a
+index d266b98..261dfac 160000
+--- a/a
++++ b/a
+@@ -1 +1 @@
+-Subproject commit d266b9873ad50488163457f025db7cdd9683d88b
++Subproject commit 261dfac35cb99d380eb966e102c1197139f7fa24
+$ git add a
+$ git commit -m "Updated submodule a."
+$ git push
+-------------------------------------------------
+
+You have to run `git submodule update` after `git pull` if you want to update
+submodules, too.
+
+[[pitfalls-with-submodules]]
+=== Pitfalls with submodules
+
+Always publish the submodule change before publishing the change to the
+superproject that references it. If you forget to publish the submodule change,
+others won't be able to clone the repository:
+
+-------------------------------------------------
+$ cd ~/git/super/a
+$ echo i added another line to this file >> a.txt
+$ git commit -a -m "doing it wrong this time"
+$ cd ..
+$ git add a
+$ git commit -m "Updated submodule a again."
+$ git push
+$ cd ~/git/cloned
+$ git pull
+$ git submodule update
+error: pathspec '261dfac35cb99d380eb966e102c1197139f7fa24' did not match any file(s) known to git.
+Did you forget to 'git add'?
+Unable to checkout '261dfac35cb99d380eb966e102c1197139f7fa24' in submodule path 'a'
+-------------------------------------------------
+
+In older Git versions it could be easily forgotten to commit new or modified
+files in a submodule, which silently leads to similar problems as not pushing
+the submodule changes. Starting with Git 1.7.0 both `git status` and `git diff`
+in the superproject show submodules as modified when they contain new or
+modified files to protect against accidentally committing such a state. `git
+diff` will also add a `-dirty` to the work tree side when generating patch
+output or used with the `--submodule` option:
+
+-------------------------------------------------
+$ git diff
+diff --git a/sub b/sub
+--- a/sub
++++ b/sub
+@@ -1 +1 @@
+-Subproject commit 3f356705649b5d566d97ff843cf193359229a453
++Subproject commit 3f356705649b5d566d97ff843cf193359229a453-dirty
+$ git diff --submodule
+Submodule sub 3f35670..3f35670-dirty:
+-------------------------------------------------
+
+You also should not rewind branches in a submodule beyond commits that were
+ever recorded in any superproject.
+
+It's not safe to run `git submodule update` if you've made and committed
+changes within a submodule without checking out a branch first. They will be
+silently overwritten:
+
+-------------------------------------------------
+$ cat a.txt
+module a
+$ echo line added from private2 >> a.txt
+$ git commit -a -m "line added inside private2"
+$ cd ..
+$ git submodule update
+Submodule path 'a': checked out 'd266b9873ad50488163457f025db7cdd9683d88b'
+$ cd a
+$ cat a.txt
+module a
+-------------------------------------------------
+
+NOTE: The changes are still visible in the submodule's reflog.
+
+If you have uncommitted changes in your submodule working tree, `git
+submodule update` will not overwrite them.  Instead, you get the usual
+warning about not being able switch from a dirty branch.
+
+[[low-level-operations]]
+== Low-level Git operations
+
+Many of the higher-level commands were originally implemented as shell
+scripts using a smaller core of low-level Git commands.  These can still
+be useful when doing unusual things with Git, or just as a way to
+understand its inner workings.
+
+[[object-manipulation]]
+=== Object access and manipulation
+
+The linkgit:git-cat-file[1] command can show the contents of any object,
+though the higher-level linkgit:git-show[1] is usually more useful.
+
+The linkgit:git-commit-tree[1] command allows constructing commits with
+arbitrary parents and trees.
+
+A tree can be created with linkgit:git-write-tree[1] and its data can be
+accessed by linkgit:git-ls-tree[1].  Two trees can be compared with
+linkgit:git-diff-tree[1].
+
+A tag is created with linkgit:git-mktag[1], and the signature can be
+verified by linkgit:git-verify-tag[1], though it is normally simpler to
+use linkgit:git-tag[1] for both.
+
+[[the-workflow]]
+=== The Workflow
+
+High-level operations such as linkgit:git-commit[1] and
+linkgit:git-restore[1] work by moving data
+between the working tree, the index, and the object database.  Git
+provides low-level operations which perform each of these steps
+individually.
+
+Generally, all Git operations work on the index file. Some operations
+work *purely* on the index file (showing the current state of the
+index), but most operations move data between the index file and either
+the database or the working directory. Thus there are four main
+combinations:
+
+[[working-directory-to-index]]
+==== working directory -> index
+
+The linkgit:git-update-index[1] command updates the index with
+information from the working directory.  You generally update the
+index information by just specifying the filename you want to update,
+like so:
+
+-------------------------------------------------
+$ git update-index filename
+-------------------------------------------------
+
+but to avoid common mistakes with filename globbing etc., the command
+will not normally add totally new entries or remove old entries,
+i.e. it will normally just update existing cache entries.
+
+To tell Git that yes, you really do realize that certain files no
+longer exist, or that new files should be added, you
+should use the `--remove` and `--add` flags respectively.
+
+NOTE! A `--remove` flag does 'not' mean that subsequent filenames will
+necessarily be removed: if the files still exist in your directory
+structure, the index will be updated with their new status, not
+removed. The only thing `--remove` means is that update-index will be
+considering a removed file to be a valid thing, and if the file really
+does not exist any more, it will update the index accordingly.
+
+As a special case, you can also do `git update-index --refresh`, which
+will refresh the "stat" information of each index to match the current
+stat information. It will 'not' update the object status itself, and
+it will only update the fields that are used to quickly test whether
+an object still matches its old backing store object.
+
+The previously introduced linkgit:git-add[1] is just a wrapper for
+linkgit:git-update-index[1].
+
+[[index-to-object-database]]
+==== index -> object database
+
+You write your current index file to a "tree" object with the program
+
+-------------------------------------------------
+$ git write-tree
+-------------------------------------------------
+
+that doesn't come with any options--it will just write out the
+current index into the set of tree objects that describe that state,
+and it will return the name of the resulting top-level tree. You can
+use that tree to re-generate the index at any time by going in the
+other direction:
+
+[[object-database-to-index]]
+==== object database -> index
+
+You read a "tree" file from the object database, and use that to
+populate (and overwrite--don't do this if your index contains any
+unsaved state that you might want to restore later!) your current
+index.  Normal operation is just
+
+-------------------------------------------------
+$ git read-tree <SHA-1 of tree>
+-------------------------------------------------
+
+and your index file will now be equivalent to the tree that you saved
+earlier. However, that is only your 'index' file: your working
+directory contents have not been modified.
+
+[[index-to-working-directory]]
+==== index -> working directory
+
+You update your working directory from the index by "checking out"
+files. This is not a very common operation, since normally you'd just
+keep your files updated, and rather than write to your working
+directory, you'd tell the index files about the changes in your
+working directory (i.e. `git update-index`).
+
+However, if you decide to jump to a new version, or check out somebody
+else's version, or just restore a previous tree, you'd populate your
+index file with read-tree, and then you need to check out the result
+with
+
+-------------------------------------------------
+$ git checkout-index filename
+-------------------------------------------------
+
+or, if you want to check out all of the index, use `-a`.
+
+NOTE! `git checkout-index` normally refuses to overwrite old files, so
+if you have an old version of the tree already checked out, you will
+need to use the `-f` flag ('before' the `-a` flag or the filename) to
+'force' the checkout.
+
+
+Finally, there are a few odds and ends which are not purely moving
+from one representation to the other:
+
+[[tying-it-all-together]]
+==== Tying it all together
+
+To commit a tree you have instantiated with `git write-tree`, you'd
+create a "commit" object that refers to that tree and the history
+behind it--most notably the "parent" commits that preceded it in
+history.
+
+Normally a "commit" has one parent: the previous state of the tree
+before a certain change was made. However, sometimes it can have two
+or more parent commits, in which case we call it a "merge", due to the
+fact that such a commit brings together ("merges") two or more
+previous states represented by other commits.
+
+In other words, while a "tree" represents a particular directory state
+of a working directory, a "commit" represents that state in time,
+and explains how we got there.
+
+You create a commit object by giving it the tree that describes the
+state at the time of the commit, and a list of parents:
+
+-------------------------------------------------
+$ git commit-tree <tree> -p <parent> [(-p <parent2>)...]
+-------------------------------------------------
+
+and then giving the reason for the commit on stdin (either through
+redirection from a pipe or file, or by just typing it at the tty).
+
+`git commit-tree` will return the name of the object that represents
+that commit, and you should save it away for later use. Normally,
+you'd commit a new `HEAD` state, and while Git doesn't care where you
+save the note about that state, in practice we tend to just write the
+result to the file pointed at by `.git/HEAD`, so that we can always see
+what the last committed state was.
+
+Here is a picture that illustrates how various pieces fit together:
+
+------------
+
+                     commit-tree
+                      commit obj
+                       +----+
+                       |    |
+                       |    |
+                       V    V
+                    +-----------+
+                    | Object DB |
+                    |  Backing  |
+                    |   Store   |
+                    +-----------+
+                       ^
+           write-tree  |     |
+             tree obj  |     |
+                       |     |  read-tree
+                       |     |  tree obj
+                             V
+                    +-----------+
+                    |   Index   |
+                    |  "cache"  |
+                    +-----------+
+         update-index  ^
+             blob obj  |     |
+                       |     |
+    checkout-index -u  |     |  checkout-index
+             stat      |     |  blob obj
+                             V
+                    +-----------+
+                    |  Working  |
+                    | Directory |
+                    +-----------+
+
+------------
+
+
+[[examining-the-data]]
+=== Examining the data
+
+You can examine the data represented in the object database and the
+index with various helper tools. For every object, you can use
+linkgit:git-cat-file[1] to examine details about the
+object:
+
+-------------------------------------------------
+$ git cat-file -t <objectname>
+-------------------------------------------------
+
+shows the type of the object, and once you have the type (which is
+usually implicit in where you find the object), you can use
+
+-------------------------------------------------
+$ git cat-file blob|tree|commit|tag <objectname>
+-------------------------------------------------
+
+to show its contents. NOTE! Trees have binary content, and as a result
+there is a special helper for showing that content, called
+`git ls-tree`, which turns the binary content into a more easily
+readable form.
+
+It's especially instructive to look at "commit" objects, since those
+tend to be small and fairly self-explanatory. In particular, if you
+follow the convention of having the top commit name in `.git/HEAD`,
+you can do
+
+-------------------------------------------------
+$ git cat-file commit HEAD
+-------------------------------------------------
+
+to see what the top commit was.
+
+[[merging-multiple-trees]]
+=== Merging multiple trees
+
+Git can help you perform a three-way merge, which can in turn be
+used for a many-way merge by repeating the merge procedure several
+times.  The usual situation is that you only do one three-way merge
+(reconciling two lines of history) and commit the result, but if
+you like to, you can merge several branches in one go.
+
+To perform a three-way merge, you start with the two commits you
+want to merge, find their closest common parent (a third commit),
+and compare the trees corresponding to these three commits.
+
+To get the "base" for the merge, look up the common parent of two
+commits:
+
+-------------------------------------------------
+$ git merge-base <commit1> <commit2>
+-------------------------------------------------
+
+This prints the name of a commit they are both based on. You should
+now look up the tree objects of those commits, which you can easily
+do with
+
+-------------------------------------------------
+$ git cat-file commit <commitname> | head -1
+-------------------------------------------------
+
+since the tree object information is always the first line in a commit
+object.
+
+Once you know the three trees you are going to merge (the one "original"
+tree, aka the common tree, and the two "result" trees, aka the branches
+you want to merge), you do a "merge" read into the index. This will
+complain if it has to throw away your old index contents, so you should
+make sure that you've committed those--in fact you would normally
+always do a merge against your last commit (which should thus match what
+you have in your current index anyway).
+
+To do the merge, do
+
+-------------------------------------------------
+$ git read-tree -m -u <origtree> <yourtree> <targettree>
+-------------------------------------------------
+
+which will do all trivial merge operations for you directly in the
+index file, and you can just write the result out with
+`git write-tree`.
+
+
+[[merging-multiple-trees-2]]
+=== Merging multiple trees, continued
+
+Sadly, many merges aren't trivial. If there are files that have
+been added, moved or removed, or if both branches have modified the
+same file, you will be left with an index tree that contains "merge
+entries" in it. Such an index tree can 'NOT' be written out to a tree
+object, and you will have to resolve any such merge clashes using
+other tools before you can write out the result.
+
+You can examine such index state with `git ls-files --unmerged`
+command.  An example:
+
+------------------------------------------------
+$ git read-tree -m $orig HEAD $target
+$ git ls-files --unmerged
+100644 263414f423d0e4d70dae8fe53fa34614ff3e2860 1	hello.c
+100644 06fa6a24256dc7e560efa5687fa84b51f0263c3a 2	hello.c
+100644 cc44c73eb783565da5831b4d820c962954019b69 3	hello.c
+------------------------------------------------
+
+Each line of the `git ls-files --unmerged` output begins with
+the blob mode bits, blob SHA-1, 'stage number', and the
+filename.  The 'stage number' is Git's way to say which tree it
+came from: stage 1 corresponds to the `$orig` tree, stage 2 to
+the `HEAD` tree, and stage 3 to the `$target` tree.
+
+Earlier we said that trivial merges are done inside
+`git read-tree -m`.  For example, if the file did not change
+from `$orig` to `HEAD` or `$target`, or if the file changed
+from `$orig` to `HEAD` and `$orig` to `$target` the same way,
+obviously the final outcome is what is in `HEAD`.  What the
+above example shows is that file `hello.c` was changed from
+`$orig` to `HEAD` and `$orig` to `$target` in a different way.
+You could resolve this by running your favorite 3-way merge
+program, e.g.  `diff3`, `merge`, or Git's own merge-file, on
+the blob objects from these three stages yourself, like this:
+
+------------------------------------------------
+$ git cat-file blob 263414f >hello.c~1
+$ git cat-file blob 06fa6a2 >hello.c~2
+$ git cat-file blob cc44c73 >hello.c~3
+$ git merge-file hello.c~2 hello.c~1 hello.c~3
+------------------------------------------------
+
+This would leave the merge result in `hello.c~2` file, along
+with conflict markers if there are conflicts.  After verifying
+the merge result makes sense, you can tell Git what the final
+merge result for this file is by:
+
+-------------------------------------------------
+$ mv -f hello.c~2 hello.c
+$ git update-index hello.c
+-------------------------------------------------
+
+When a path is in the "unmerged" state, running `git update-index` for
+that path tells Git to mark the path resolved.
+
+The above is the description of a Git merge at the lowest level,
+to help you understand what conceptually happens under the hood.
+In practice, nobody, not even Git itself, runs `git cat-file` three times
+for this.  There is a `git merge-index` program that extracts the
+stages to temporary files and calls a "merge" script on it:
+
+-------------------------------------------------
+$ git merge-index git-merge-one-file hello.c
+-------------------------------------------------
+
+and that is what higher level `git merge -s resolve` is implemented with.
+
+[[hacking-git]]
+== Hacking Git
+
+This chapter covers internal details of the Git implementation which
+probably only Git developers need to understand.
+
+[[object-details]]
+=== Object storage format
+
+All objects have a statically determined "type" which identifies the
+format of the object (i.e. how it is used, and how it can refer to other
+objects).  There are currently four different object types: "blob",
+"tree", "commit", and "tag".
+
+Regardless of object type, all objects share the following
+characteristics: they are all deflated with zlib, and have a header
+that not only specifies their type, but also provides size information
+about the data in the object.  It's worth noting that the SHA-1 hash
+that is used to name the object is the hash of the original data
+plus this header, so `sha1sum` 'file' does not match the object name
+for 'file' (the earliest versions of Git hashed slightly differently
+but the conclusion is still the same).
+
+The following is a short example that demonstrates how these hashes
+can be generated manually:
+
+Let's assume a small text file with some simple content:
+
+-------------------------------------------------
+$ echo "Hello world" >hello.txt
+-------------------------------------------------
+
+We can now manually generate the hash Git would use for this file:
+
+- The object we want the hash for is of type "blob" and its size is
+  12 bytes.
+
+- Prepend the object header to the file content and feed this to
+  `sha1sum`:
+
+-------------------------------------------------
+$ { printf "blob 12\0"; cat hello.txt; } | sha1sum
+802992c4220de19a90767f3000a79a31b98d0df7  -
+-------------------------------------------------
+
+This manually constructed hash can be verified using `git hash-object`
+which of course hides the addition of the header:
+
+-------------------------------------------------
+$ git hash-object hello.txt
+802992c4220de19a90767f3000a79a31b98d0df7
+-------------------------------------------------
+
+As a result, the general consistency of an object can always be tested
+independently of the contents or the type of the object: all objects can
+be validated by verifying that (a) their hashes match the content of the
+file and (b) the object successfully inflates to a stream of bytes that
+forms a sequence of
+`<ascii-type-without-space> + <space> + <ascii-decimal-size> +
+<byte\0> + <binary-object-data>`.
+
+The structured objects can further have their structure and
+connectivity to other objects verified. This is generally done with
+the `git fsck` program, which generates a full dependency graph
+of all objects, and verifies their internal consistency (in addition
+to just verifying their superficial consistency through the hash).
+
+[[birdview-on-the-source-code]]
+=== A birds-eye view of Git's source code
+
+It is not always easy for new developers to find their way through Git's
+source code.  This section gives you a little guidance to show where to
+start.
+
+A good place to start is with the contents of the initial commit, with:
+
+----------------------------------------------------
+$ git switch --detach e83c5163
+----------------------------------------------------
+
+The initial revision lays the foundation for almost everything Git has
+today (even though details may differ in a few places), but is small
+enough to read in one sitting.
+
+Note that terminology has changed since that revision.  For example, the
+README in that revision uses the word "changeset" to describe what we
+now call a <<def_commit_object,commit>>.
+
+Also, we do not call it "cache" any more, but rather "index"; however,
+the file is still called `read-cache.h`.
+
+If you grasp the ideas in that initial commit, you should check out a
+more recent version and skim `read-cache-ll.h`, `object.h` and `commit.h`.
+
+In the early days, Git (in the tradition of UNIX) was a bunch of programs
+which were extremely simple, and which you used in scripts, piping the
+output of one into another. This turned out to be good for initial
+development, since it was easier to test new things.  However, recently
+many of these parts have become builtins, and some of the core has been
+"libified", i.e. put into libgit.a for performance, portability reasons,
+and to avoid code duplication.
+
+By now, you know what the index is (and find the corresponding data
+structures in `read-cache-ll.h`), and that there are just a couple of
+object types (blobs, trees, commits and tags) which inherit their
+common structure from `struct object`, which is their first member
+(and thus, you can cast e.g.  `(struct object *)commit` to achieve the
+_same_ as `&commit->object`, i.e.  get at the object name and flags).
+
+Now is a good point to take a break to let this information sink in.
+
+Next step: get familiar with the object naming.  Read <<naming-commits>>.
+There are quite a few ways to name an object (and not only revisions!).
+All of these are handled in `sha1_name.c`. Just have a quick look at
+the function `get_sha1()`. A lot of the special handling is done by
+functions like `get_sha1_basic()` or the likes.
+
+This is just to get you into the groove for the most libified part of Git:
+the revision walker.
+
+Basically, the initial version of `git log` was a shell script:
+
+----------------------------------------------------------------
+$ git-rev-list --pretty $(git-rev-parse --default HEAD "$@") | \
+	LESS=-S ${PAGER:-less}
+----------------------------------------------------------------
+
+What does this mean?
+
+`git rev-list` is the original version of the revision walker, which
+_always_ printed a list of revisions to stdout.  It is still functional,
+and needs to, since most new Git commands start out as scripts using
+`git rev-list`.
+
+`git rev-parse` is not as important any more; it was only used to filter out
+options that were relevant for the different plumbing commands that were
+called by the script.
+
+Most of what `git rev-list` did is contained in `revision.c` and
+`revision.h`.  It wraps the options in a struct named `rev_info`, which
+controls how and what revisions are walked, and more.
+
+The original job of `git rev-parse` is now taken by the function
+`setup_revisions()`, which parses the revisions and the common command-line
+options for the revision walker. This information is stored in the struct
+`rev_info` for later consumption. You can do your own command-line option
+parsing after calling `setup_revisions()`. After that, you have to call
+`prepare_revision_walk()` for initialization, and then you can get the
+commits one by one with the function `get_revision()`.
+
+If you are interested in more details of the revision walking process,
+just have a look at the first implementation of `cmd_log()`; call
+`git show v1.3.0~155^2~4` and scroll down to that function (note that you
+no longer need to call `setup_pager()` directly).
+
+Nowadays, `git log` is a builtin, which means that it is _contained_ in the
+command `git`.  The source side of a builtin is
+
+- a function called `cmd_<bla>`, typically defined in `builtin/<bla.c>`
+  (note that older versions of Git used to have it in `builtin-<bla>.c`
+  instead), and declared in `builtin.h`.
+
+- an entry in the `commands[]` array in `git.c`, and
+
+- an entry in `BUILTIN_OBJECTS` in the `Makefile`.
+
+Sometimes, more than one builtin is contained in one source file.  For
+example, `cmd_whatchanged()` and `cmd_log()` both reside in `builtin/log.c`,
+since they share quite a bit of code.  In that case, the commands which are
+_not_ named like the `.c` file in which they live have to be listed in
+`BUILT_INS` in the `Makefile`.
+
+`git log` looks more complicated in C than it does in the original script,
+but that allows for a much greater flexibility and performance.
+
+Here again it is a good point to take a pause.
+
+Lesson three is: study the code.  Really, it is the best way to learn about
+the organization of Git (after you know the basic concepts).
+
+So, think about something which you are interested in, say, "how can I
+access a blob just knowing the object name of it?".  The first step is to
+find a Git command with which you can do it.  In this example, it is either
+`git show` or `git cat-file`.
+
+For the sake of clarity, let's stay with `git cat-file`, because it
+
+- is plumbing, and
+
+- was around even in the initial commit (it literally went only through
+  some 20 revisions as `cat-file.c`, was renamed to `builtin/cat-file.c`
+  when made a builtin, and then saw less than 10 versions).
+
+So, look into `builtin/cat-file.c`, search for `cmd_cat_file()` and look what
+it does.
+
+------------------------------------------------------------------
+        git_config(git_default_config);
+        if (argc != 3)
+		usage("git cat-file [-t|-s|-e|-p|<type>] <sha1>");
+        if (get_sha1(argv[2], sha1))
+                die("Not a valid object name %s", argv[2]);
+------------------------------------------------------------------
+
+Let's skip over the obvious details; the only really interesting part
+here is the call to `get_sha1()`.  It tries to interpret `argv[2]` as an
+object name, and if it refers to an object which is present in the current
+repository, it writes the resulting SHA-1 into the variable `sha1`.
+
+Two things are interesting here:
+
+- `get_sha1()` returns 0 on _success_.  This might surprise some new
+  Git hackers, but there is a long tradition in UNIX to return different
+  negative numbers in case of different errors--and 0 on success.
+
+- the variable `sha1` in the function signature of `get_sha1()` is `unsigned
+  char *`, but is actually expected to be a pointer to `unsigned
+  char[20]`.  This variable will contain the 160-bit SHA-1 of the given
+  commit.  Note that whenever a SHA-1 is passed as `unsigned char *`, it
+  is the binary representation, as opposed to the ASCII representation in
+  hex characters, which is passed as `char *`.
+
+You will see both of these things throughout the code.
+
+Now, for the meat:
+
+-----------------------------------------------------------------------------
+        case 0:
+                buf = read_object_with_reference(sha1, argv[1], &size, NULL);
+-----------------------------------------------------------------------------
+
+This is how you read a blob (actually, not only a blob, but any type of
+object).  To know how the function `read_object_with_reference()` actually
+works, find the source code for it (something like `git grep
+read_object_with | grep ":[a-z]"` in the Git repository), and read
+the source.
+
+To find out how the result can be used, just read on in `cmd_cat_file()`:
+
+-----------------------------------
+        write_or_die(1, buf, size);
+-----------------------------------
+
+Sometimes, you do not know where to look for a feature.  In many such cases,
+it helps to search through the output of `git log`, and then `git show` the
+corresponding commit.
+
+Example: If you know that there was some test case for `git bundle`, but
+do not remember where it was (yes, you _could_ `git grep bundle t/`, but that
+does not illustrate the point!):
+
+------------------------
+$ git log --no-merges t/
+------------------------
+
+In the pager (`less`), just search for "bundle", go a few lines back,
+and see that it is in commit 18449ab0.  Now just copy this object name,
+and paste it into the command line
+
+-------------------
+$ git show 18449ab0
+-------------------
+
+Voila.
+
+Another example: Find out what to do in order to make some script a
+builtin:
+
+-------------------------------------------------
+$ git log --no-merges --diff-filter=A builtin/*.c
+-------------------------------------------------
+
+You see, Git is actually the best tool to find out about the source of Git
+itself!
+
+[[glossary]]
+== Git Glossary
+
+[[git-explained]]
+=== Git explained
+
+include::glossary-content.adoc[]
+
+[[git-quick-start]]
+[appendix]
+== Git Quick Reference
+
+This is a quick summary of the major commands; the previous chapters
+explain how these work in more detail.
+
+[[quick-creating-a-new-repository]]
+=== Creating a new repository
+
+From a tarball:
+
+-----------------------------------------------
+$ tar xzf project.tar.gz
+$ cd project
+$ git init
+Initialized empty Git repository in .git/
+$ git add .
+$ git commit
+-----------------------------------------------
+
+From a remote repository:
+
+-----------------------------------------------
+$ git clone git://example.com/pub/project.git
+$ cd project
+-----------------------------------------------
+
+[[managing-branches]]
+=== Managing branches
+
+-----------------------------------------------
+$ git branch			# list all local branches in this repo
+$ git switch test	        # switch working directory to branch "test"
+$ git branch new		# create branch "new" starting at current HEAD
+$ git branch -d new		# delete branch "new"
+-----------------------------------------------
+
+Instead of basing a new branch on current HEAD (the default), use:
+
+-----------------------------------------------
+$ git branch new test    # branch named "test"
+$ git branch new v2.6.15 # tag named v2.6.15
+$ git branch new HEAD^   # commit before the most recent
+$ git branch new HEAD^^  # commit before that
+$ git branch new test~10 # ten commits before tip of branch "test"
+-----------------------------------------------
+
+Create and switch to a new branch at the same time:
+
+-----------------------------------------------
+$ git switch -c new v2.6.15
+-----------------------------------------------
+
+Update and examine branches from the repository you cloned from:
+
+-----------------------------------------------
+$ git fetch		# update
+$ git branch -r		# list
+  origin/master
+  origin/next
+  ...
+$ git switch -c masterwork origin/master
+-----------------------------------------------
+
+Fetch a branch from a different repository, and give it a new
+name in your repository:
+
+-----------------------------------------------
+$ git fetch git://example.com/project.git theirbranch:mybranch
+$ git fetch git://example.com/project.git v2.6.15:mybranch
+-----------------------------------------------
+
+Keep a list of repositories you work with regularly:
+
+-----------------------------------------------
+$ git remote add example git://example.com/project.git
+$ git remote			# list remote repositories
+example
+origin
+$ git remote show example	# get details
+* remote example
+  URL: git://example.com/project.git
+  Tracked remote branches
+    master
+    next
+    ...
+$ git fetch example		# update branches from example
+$ git branch -r			# list all remote branches
+-----------------------------------------------
+
+
+[[exploring-history]]
+=== Exploring history
+
+-----------------------------------------------
+$ gitk			    # visualize and browse history
+$ git log		    # list all commits
+$ git log src/		    # ...modifying src/
+$ git log v2.6.15..v2.6.16  # ...in v2.6.16, not in v2.6.15
+$ git log master..test	    # ...in branch test, not in branch master
+$ git log test..master	    # ...in branch master, but not in test
+$ git log test...master	    # ...in one branch, not in both
+$ git log -S'foo()'	    # ...where difference contain "foo()"
+$ git log --since="2 weeks ago"
+$ git log -p		    # show patches as well
+$ git show		    # most recent commit
+$ git diff v2.6.15..v2.6.16 # diff between two tagged versions
+$ git diff v2.6.15..HEAD    # diff with current head
+$ git grep "foo()"	    # search working directory for "foo()"
+$ git grep v2.6.15 "foo()"  # search old tree for "foo()"
+$ git show v2.6.15:a.txt    # look at old version of a.txt
+-----------------------------------------------
+
+Search for regressions:
+
+-----------------------------------------------
+$ git bisect start
+$ git bisect bad		# current version is bad
+$ git bisect good v2.6.13-rc2	# last known good revision
+Bisecting: 675 revisions left to test after this
+				# test here, then:
+$ git bisect good		# if this revision is good, or
+$ git bisect bad		# if this revision is bad.
+				# repeat until done.
+-----------------------------------------------
+
+[[making-changes]]
+=== Making changes
+
+Make sure Git knows who to blame:
+
+------------------------------------------------
+$ cat >>~/.gitconfig <<\EOF
+[user]
+	name = Your Name Comes Here
+	email = you@xxxxxxxxxxxxxxxxxxxxxx
+EOF
+------------------------------------------------
+
+Select file contents to include in the next commit, then make the
+commit:
+
+-----------------------------------------------
+$ git add a.txt    # updated file
+$ git add b.txt    # new file
+$ git rm c.txt     # old file
+$ git commit
+-----------------------------------------------
+
+Or, prepare and create the commit in one step:
+
+-----------------------------------------------
+$ git commit d.txt # use latest content only of d.txt
+$ git commit -a	   # use latest content of all tracked files
+-----------------------------------------------
+
+[[merging]]
+=== Merging
+
+-----------------------------------------------
+$ git merge test   # merge branch "test" into the current branch
+$ git pull git://example.com/project.git master
+		   # fetch and merge in remote branch
+$ git pull . test  # equivalent to git merge test
+-----------------------------------------------
+
+[[sharing-your-changes]]
+=== Sharing your changes
+
+Importing or exporting patches:
+
+-----------------------------------------------
+$ git format-patch origin..HEAD # format a patch for each commit
+				# in HEAD but not in origin
+$ git am mbox # import patches from the mailbox "mbox"
+-----------------------------------------------
+
+Fetch a branch in a different Git repository, then merge into the
+current branch:
+
+-----------------------------------------------
+$ git pull git://example.com/project.git theirbranch
+-----------------------------------------------
+
+Store the fetched branch into a local branch before merging into the
+current branch:
+
+-----------------------------------------------
+$ git pull git://example.com/project.git theirbranch:mybranch
+-----------------------------------------------
+
+After creating commits on a local branch, update the remote
+branch with your commits:
+
+-----------------------------------------------
+$ git push ssh://example.com/project.git mybranch:theirbranch
+-----------------------------------------------
+
+When remote and local branch are both named "test":
+
+-----------------------------------------------
+$ git push ssh://example.com/project.git test
+-----------------------------------------------
+
+Shortcut version for a frequently used remote repository:
+
+-----------------------------------------------
+$ git remote add example ssh://example.com/project.git
+$ git push example test
+-----------------------------------------------
+
+[[repository-maintenance]]
+=== Repository maintenance
+
+Check for corruption:
+
+-----------------------------------------------
+$ git fsck
+-----------------------------------------------
+
+Recompress, remove unused cruft:
+
+-----------------------------------------------
+$ git gc
+-----------------------------------------------
+
+
+[[todo]]
+[appendix]
+== Notes and todo list for this manual
+
+[[todo-list]]
+=== Todo list
+
+This is a work in progress.
+
+The basic requirements:
+
+- It must be readable in order, from beginning to end, by someone
+  intelligent with a basic grasp of the UNIX command line, but without
+  any special knowledge of Git.  If necessary, any other prerequisites
+  should be specifically mentioned as they arise.
+- Whenever possible, section headings should clearly describe the task
+  they explain how to do, in language that requires no more knowledge
+  than necessary: for example, "importing patches into a project" rather
+  than "the `git am` command"
+
+Think about how to create a clear chapter dependency graph that will
+allow people to get to important topics without necessarily reading
+everything in between.
+
+Scan `Documentation/` for other stuff left out; in particular:
+
+- howto's
+- some of `technical/`?
+- hooks
+- list of commands in linkgit:git[1]
+
+Scan email archives for other stuff left out
+
+Scan man pages to see if any assume more background than this manual
+provides.
+
+Add more good examples.  Entire sections of just cookbook examples
+might be a good idea; maybe make an "advanced examples" section a
+standard end-of-chapter section?
+
+Include cross-references to the glossary, where appropriate.
+
+Add a section on working with other version control systems, including
+CVS, Subversion, and just imports of series of release tarballs.
+
+Write a chapter on using plumbing and writing scripts.
+
+Alternates, clone -reference, etc.
+
+More on recovery from repository corruption.  See:
+	https://lore.kernel.org/git/Pine.LNX.4.64.0702272039540.12485@xxxxxxxxxxxxxxxxxxxxxxxxxx/
+	https://lore.kernel.org/git/Pine.LNX.4.64.0702141033400.3604@xxxxxxxxxxxxxxxxxxxxxxxxxx/
diff --git a/GIT-BUILD-OPTIONS.in b/GIT-BUILD-OPTIONS.in
new file mode 100644
index 0000000000..edff75ae16
--- /dev/null
+++ b/GIT-BUILD-OPTIONS.in
@@ -0,0 +1,48 @@
+BROKEN_PATH_FIX=@BROKEN_PATH_FIX@
+DIFF=@DIFF@
+FSMONITOR_DAEMON_BACKEND=@FSMONITOR_DAEMON_BACKEND@
+FSMONITOR_OS_SETTINGS=@FSMONITOR_OS_SETTINGS@
+GITWEBDIR=@GITWEBDIR@
+GIT_INTEROP_MAKE_OPTS=@GIT_INTEROP_MAKE_OPTS@
+GIT_PERF_LARGE_REPO=@GIT_PERF_LARGE_REPO@
+GIT_PERF_MAKE_COMMAND=@GIT_PERF_MAKE_COMMAND@
+GIT_PERF_MAKE_OPTS=@GIT_PERF_MAKE_OPTS@
+GIT_PERF_REPEAT_COUNT=@GIT_PERF_REPEAT_COUNT@
+GIT_PERF_REPO=@GIT_PERF_REPO@
+GIT_TEST_CMP=@GIT_TEST_CMP@
+GIT_TEST_CMP_USE_COPIED_CONTEXT=@GIT_TEST_CMP_USE_COPIED_CONTEXT@
+GIT_TEST_GITPERLLIB=@GIT_TEST_GITPERLLIB@
+GIT_TEST_INDEX_VERSION=@GIT_TEST_INDEX_VERSION@
+GIT_TEST_MERGE_TOOLS_DIR=@GIT_TEST_MERGE_TOOLS_DIR@
+GIT_TEST_OPTS=@GIT_TEST_OPTS@
+GIT_TEST_PERL_FATAL_WARNINGS=@GIT_TEST_PERL_FATAL_WARNINGS@
+GIT_TEST_POPATH=@GIT_TEST_POPATH@
+GIT_TEST_TEMPLATE_DIR=@GIT_TEST_TEMPLATE_DIR@
+GIT_TEST_TEXTDOMAINDIR=@GIT_TEST_TEXTDOMAINDIR@
+GIT_TEST_UTF8_LOCALE=@GIT_TEST_UTF8_LOCALE@
+LOCALEDIR=@LOCALEDIR@
+NO_CURL=@NO_CURL@
+NO_EXPAT=@NO_EXPAT@
+NO_GETTEXT=@NO_GETTEXT@
+NO_GITWEB=@NO_GITWEB@
+NO_ICONV=@NO_ICONV@
+NO_PERL=@NO_PERL@
+NO_PERL_CPAN_FALLBACKS=@NO_PERL_CPAN_FALLBACKS@
+NO_PTHREADS=@NO_PTHREADS@
+NO_PYTHON=@NO_PYTHON@
+NO_REGEX=@NO_REGEX@
+NO_UNIX_SOCKETS=@NO_UNIX_SOCKETS@
+PAGER_ENV=@PAGER_ENV@
+PERL_LOCALEDIR=@PERL_LOCALEDIR@
+PERL_PATH=@PERL_PATH@
+PYTHON_PATH=@PYTHON_PATH@
+RUNTIME_PREFIX=@RUNTIME_PREFIX@
+SANITIZE_ADDRESS=@SANITIZE_ADDRESS@
+SANITIZE_LEAK=@SANITIZE_LEAK@
+SHELL_PATH=@SHELL_PATH@
+TAR=@TAR@
+TEST_OUTPUT_DIRECTORY=@TEST_OUTPUT_DIRECTORY@
+TEST_SHELL_PATH=@TEST_SHELL_PATH@
+USE_GETTEXT_SCHEME=@USE_GETTEXT_SCHEME@
+USE_LIBPCRE2=@USE_LIBPCRE2@
+X=@X@
diff --git a/GIT-VERSION-FILE.in b/GIT-VERSION-FILE.in
new file mode 100644
index 0000000000..3789a48a34
--- /dev/null
+++ b/GIT-VERSION-FILE.in
@@ -0,0 +1 @@
+GIT_VERSION=@GIT_VERSION@
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
new file mode 100755
index 0000000000..3704a1c39e
--- /dev/null
+++ b/GIT-VERSION-GEN
@@ -0,0 +1,96 @@
+#!/bin/sh
+
+DEF_VER=v2.48.GIT
+
+LF='
+'
+
+if test "$#" -ne 3
+then
+    echo >&2 "USAGE: $0 <SOURCE_DIR> <INPUT> <OUTPUT>"
+    exit 1
+fi
+
+SOURCE_DIR="$1"
+INPUT="$2"
+OUTPUT="$3"
+
+if ! test -f "$INPUT"
+then
+	echo >&2 "Input is not a file: $INPUT"
+	exit 1
+fi
+
+# Protect us from reading Git version information outside of the Git directory
+# in case it is not a repository itself, but embedded in an unrelated
+# repository.
+GIT_CEILING_DIRECTORIES="$SOURCE_DIR/.."
+export GIT_CEILING_DIRECTORIES
+
+if test -z "$GIT_VERSION"
+then
+	# First see if there is a version file (included in release tarballs),
+	# then try git-describe, then default.
+	if test -f "$SOURCE_DIR"/version
+	then
+		VN=$(cat "$SOURCE_DIR"/version) || VN="$DEF_VER"
+	elif {
+			test -d "$SOURCE_DIR/.git" ||
+			test -d "${GIT_DIR:-.git}" ||
+			test -f "$SOURCE_DIR"/.git;
+		} &&
+		VN=$(git -C "$SOURCE_DIR" describe --match "v[0-9]*" HEAD 2>/dev/null) &&
+		case "$VN" in
+		*$LF*) (exit 1) ;;
+		v[0-9]*)
+			git -C "$SOURCE_DIR" update-index -q --refresh
+			test -z "$(git -C "$SOURCE_DIR" diff-index --name-only HEAD --)" ||
+			VN="$VN-dirty" ;;
+		esac
+	then
+		VN=$(echo "$VN" | sed -e 's/-/./g');
+	else
+		VN="$DEF_VER"
+	fi
+
+	GIT_VERSION=$(expr "$VN" : v*'\(.*\)')
+fi
+
+if test -z "$GIT_BUILT_FROM_COMMIT"
+then
+	GIT_BUILT_FROM_COMMIT=$(git -C "$SOURCE_DIR" rev-parse -q --verify HEAD 2>/dev/null)
+fi
+
+if test -z "$GIT_DATE"
+then
+	GIT_DATE=$(git -C "$SOURCE_DIR" show --quiet --format='%as' 2>/dev/null)
+fi
+
+if test -z "$GIT_USER_AGENT"
+then
+	GIT_USER_AGENT="git/$GIT_VERSION"
+fi
+
+# While released Git versions only have three numbers, development builds also
+# have a fourth number that corresponds to the number of patches since the last
+# release.
+read GIT_MAJOR_VERSION GIT_MINOR_VERSION GIT_MICRO_VERSION GIT_PATCH_LEVEL trailing <<EOF
+$(echo "$GIT_VERSION" 0 0 0 0 | tr '.a-zA-Z-' ' ')
+EOF
+
+sed -e "s|@GIT_VERSION@|$GIT_VERSION|" \
+	-e "s|@GIT_MAJOR_VERSION@|$GIT_MAJOR_VERSION|" \
+	-e "s|@GIT_MINOR_VERSION@|$GIT_MINOR_VERSION|" \
+	-e "s|@GIT_MICRO_VERSION@|$GIT_MICRO_VERSION|" \
+	-e "s|@GIT_PATCH_LEVEL@|$GIT_PATCH_LEVEL|" \
+	-e "s|@GIT_BUILT_FROM_COMMIT@|$GIT_BUILT_FROM_COMMIT|" \
+	-e "s|@GIT_USER_AGENT@|$GIT_USER_AGENT|" \
+	-e "s|@GIT_DATE@|$GIT_DATE|" \
+	"$INPUT" >"$OUTPUT".$$+
+
+if ! test -f "$OUTPUT" || ! cmp "$OUTPUT".$$+ "$OUTPUT" >/dev/null
+then
+	mv "$OUTPUT".$$+ "$OUTPUT"
+else
+	rm "$OUTPUT".$$+
+fi
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000000..54d7528f9e
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,236 @@
+
+		Git installation
+
+Normally you can just do "make" followed by "make install", and that
+will install the git programs in your own ~/bin/ directory.  If you want
+to do a global install, you can do
+
+	$ make prefix=/usr all doc info ;# as yourself
+	# make prefix=/usr install install-doc install-html install-info ;# as root
+
+(or prefix=/usr/local, of course).  Just like any program suite
+that uses $prefix, the built results have some paths encoded,
+which are derived from $prefix, so "make all; make prefix=/usr
+install" would not work.
+
+The beginning of the Makefile documents many variables that affect the way
+git is built.  You can override them either from the command line, or in a
+config.mak file.
+
+Alternatively you can use autoconf generated ./configure script to
+set up install paths (via config.mak.autogen), so you can write instead
+
+	$ make configure ;# as yourself
+	$ ./configure --prefix=/usr ;# as yourself
+	$ make all doc ;# as yourself
+	# make install install-doc install-html;# as root
+
+If you're willing to trade off (much) longer build time for a later
+faster git you can also do a profile feedback build with
+
+	$ make prefix=/usr profile
+	# make prefix=/usr PROFILE=BUILD install
+
+This will run the complete test suite as training workload and then
+rebuild git with the generated profile feedback. This results in a git
+which is a few percent faster on CPU intensive workloads.  This
+may be a good tradeoff for distribution packagers.
+
+Alternatively you can run profile feedback only with the git benchmark
+suite. This runs significantly faster than the full test suite, but
+has less coverage:
+
+	$ make prefix=/usr profile-fast
+	# make prefix=/usr PROFILE=BUILD install
+
+Or if you just want to install a profile-optimized version of git into
+your home directory, you could run:
+
+	$ make profile-install
+
+or
+	$ make profile-fast-install
+
+As a caveat: a profile-optimized build takes a *lot* longer since the
+git tree must be built twice, and in order for the profiling
+measurements to work properly, ccache must be disabled and the test
+suite has to be run using only a single CPU.  In addition, the profile
+feedback build stage currently generates a lot of additional compiler
+warnings.
+
+Issues of note:
+
+ - Ancient versions of GNU Interactive Tools (pre-4.9.2) installed a
+   program "git", whose name conflicts with this program.  But with
+   version 4.9.2, after long hiatus without active maintenance (since
+   around 1997), it changed its name to gnuit and the name conflict is no
+   longer a problem.
+
+   NOTE: When compiled with backward compatibility option, the GNU
+   Interactive Tools package still can install "git", but you can build it
+   with --disable-transition option to avoid this.
+
+ - You can use git after building but without installing if you want
+   to test drive it.  Simply run git found in bin-wrappers directory
+   in the build directory, or prepend that directory to your $PATH.
+   This however is less efficient than running an installed git, as
+   you always need an extra fork+exec to run any git subcommand.
+
+   It is still possible to use git without installing by setting a few
+   environment variables, which was the way this was done
+   traditionally.  But using git found in bin-wrappers directory in
+   the build directory is far simpler.  As a historical reference, the
+   old way went like this:
+
+	GIT_EXEC_PATH=`pwd`
+	PATH=`pwd`:$PATH
+	GITPERLLIB=`pwd`/perl/build/lib
+	export GIT_EXEC_PATH PATH GITPERLLIB
+
+ - By default (unless NO_PERL is provided) Git will ship various perl
+   scripts. However, for simplicity it doesn't use the
+   ExtUtils::MakeMaker toolchain to decide where to place the perl
+   libraries. Depending on the system this can result in the perl
+   libraries not being where you'd like them if they're expected to be
+   used by things other than Git itself.
+
+   Manually supplying a perllibdir prefix should fix this, if this is
+   a problem you care about, e.g.:
+
+       prefix=/usr perllibdir=/usr/$(/usr/bin/perl -MConfig -wle 'print substr $Config{installsitelib}, 1 + length $Config{siteprefixexp}')
+
+   Will result in e.g. perllibdir=/usr/share/perl/5.26.1 on Debian,
+   perllibdir=/usr/share/perl5 (which we'd use by default) on CentOS.
+
+ - Unless NO_PERL is provided Git will ship various perl libraries it
+   needs. Distributors of Git will usually want to set
+   NO_PERL_CPAN_FALLBACKS if NO_PERL is not provided to use their own
+   copies of the CPAN modules Git needs.
+
+ - Git is reasonably self-sufficient, but does depend on a few external
+   programs and libraries.  Git can be used without most of them by adding
+   the appropriate "NO_<LIBRARY>=YesPlease" to the make command line or
+   config.mak file.
+
+	- "zlib", the compression library. Git won't build without it.
+
+	- "ssh" is used to push and pull over the net.
+
+	- A POSIX-compliant shell is required to run some scripts needed
+	  for everyday use (e.g. "bisect", "request-pull").
+
+	- "Perl" version 5.26.0 or later is needed to use some of the
+	  features (e.g. sending patches using "git send-email",
+	  interacting with svn repositories with "git svn").  If you can
+	  live without these, use NO_PERL.  Note that recent releases of
+	  Redhat/Fedora are reported to ship Perl binary package with some
+	  core modules stripped away (see https://lwn.net/Articles/477234/),
+	  so you might need to install additional packages other than Perl
+	  itself, e.g. Digest::MD5, File::Spec, File::Temp, Net::Domain,
+	  Net::SMTP, and Time::HiRes.
+
+	- "libcurl" library is used for fetching and pushing
+	  repositories over http:// or https://, as well as by
+	  git-imap-send. If you do not need that functionality,
+	  use NO_CURL to build without it.
+
+	  Git requires version "7.61.0" or later of "libcurl" to build
+	  without NO_CURL. This version requirement may be bumped in
+	  the future.
+
+	- "expat" library; git-http-push uses it for remote lock
+	  management over DAV.  Similar to "curl" above, this is optional
+	  (with NO_EXPAT).
+
+	- "wish", the Tcl/Tk windowing shell is used in gitk to show the
+	  history graphically, and in git-gui.  If you don't want gitk or
+	  git-gui, you can use NO_TCLTK.
+
+	- A gettext library is used by default for localizing Git. The
+	  primary target is GNU libintl, but the Solaris gettext
+	  implementation also works.
+
+	  We need a gettext.h on the system for C code, gettext.sh (or
+	  Solaris gettext(1)) for shell scripts, and libintl-perl for Perl
+	  programs.
+
+	  Set NO_GETTEXT to disable localization support and make Git only
+	  use English. Under autoconf the configure script will do this
+	  automatically if it can't find libintl on the system.
+
+	- Python version 2.7 or later is needed to use the git-p4 interface
+	  to Perforce.
+
+ - Some platform specific issues are dealt with Makefile rules,
+   but depending on your specific installation, you may not
+   have all the libraries/tools needed, or you may have
+   necessary libraries at unusual locations.  Please look at the
+   top of the Makefile to see what can be adjusted for your needs.
+   You can place local settings in config.mak and the Makefile
+   will include them.  Note that config.mak is not distributed;
+   the name is reserved for local settings.
+
+ - To build and install documentation suite, you need to have
+   the asciidoc/xmlto toolchain.  Because not many people are
+   inclined to install the tools, the default build target
+   ("make all") does _not_ build them.
+
+   "make doc" builds documentation in man and html formats; there are
+   also "make man", "make html" and "make info". Note that "make html"
+   requires asciidoc, but not xmlto. "make man" (and thus make doc)
+   requires both.
+
+   "make install-doc" installs documentation in man format only; there
+   are also "make install-man", "make install-html" and "make
+   install-info".
+
+   Building and installing the info file additionally requires
+   makeinfo and docbook2X.  Version 0.8.3 is known to work.
+
+   Building and installing the pdf file additionally requires
+   dblatex.  Version >= 0.2.7 is known to work.
+
+   All formats require at least asciidoc 8.4.1. Alternatively, you can
+   use Asciidoctor (requires Ruby) by passing USE_ASCIIDOCTOR=YesPlease
+   to make. You need at least Asciidoctor version 1.5.
+
+   There are also "make quick-install-doc", "make quick-install-man"
+   and "make quick-install-html" which install preformatted man pages
+   and html documentation. To use these build targets, you need to
+   clone two separate git-htmldocs and git-manpages repositories next
+   to the clone of git itself.
+
+   The minimum supported version of docbook-xsl is 1.74.
+
+   Users attempting to build the documentation on Cygwin may need to ensure
+   that the /etc/xml/catalog file looks something like this:
+
+   <?xml version="1.0"?>
+   <!DOCTYPE catalog PUBLIC
+      "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
+      "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd";
+   >
+   <catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+     <rewriteURI
+       uriStartString = "http://docbook.sourceforge.net/release/xsl/current";
+       rewritePrefix = "/usr/share/sgml/docbook/xsl-stylesheets"
+     />
+     <rewriteURI
+       uriStartString="http://www.oasis-open.org/docbook/xml/4.5";
+       rewritePrefix="/usr/share/sgml/docbook/xml-dtd-4.5"
+     />
+  </catalog>
+
+  This can be achieved with the following two xmlcatalog commands:
+
+  xmlcatalog --noout \
+     --add rewriteURI \
+        http://docbook.sourceforge.net/release/xsl/current \
+        /usr/share/sgml/docbook/xsl-stylesheets \
+     /etc/xml/catalog
+
+  xmlcatalog --noout \
+     --add rewriteURI \
+         http://www.oasis-open.org/docbook/xml/4.5/xsl/current \
+         /usr/share/sgml/docbook/xml-dtd-4.5 \
+     /etc/xml/catalog
diff --git a/LGPL-2.1 b/LGPL-2.1
new file mode 100644
index 0000000000..d38b1b92bd
--- /dev/null
+++ b/LGPL-2.1
@@ -0,0 +1,511 @@
+
+ While most of this project is under the GPL (see COPYING), the xdiff/
+ library and some libc code from compat/ are licensed under the
+ GNU LGPL, version 2.1 or (at your option) any later version and some
+ other files are under other licenses.  Check the individual files to
+ be sure.
+
+----------------------------------------
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000..2f6e2d5295
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,3889 @@
+# The default target of this Makefile is...
+all::
+
+# Import tree-wide shared Makefile behavior and libraries
+include shared.mak
+
+# == Makefile defines ==
+#
+# These defines change the behavior of the Makefile itself, but have
+# no impact on what it builds:
+#
+# Define V=1 to have a more verbose compile.
+#
+# == Portability and optional library defines ==
+#
+# These defines indicate what Git can expect from the OS, what
+# libraries are available etc. Much of this is auto-detected in
+# config.mak.uname, or in configure.ac when using the optional "make
+# configure && ./configure" (see INSTALL).
+#
+# Define SHELL_PATH to a POSIX shell if your /bin/sh is broken.
+#
+# Define SANE_TOOL_PATH to a colon-separated list of paths to prepend
+# to PATH if your tools in /usr/bin are broken.
+#
+# Define SOCKLEN_T to a suitable type (such as 'size_t') if your
+# system headers do not define a socklen_t type.
+#
+# Define INLINE to a suitable substitute (such as '__inline' or '') if git
+# fails to compile with errors about undefined inline functions or similar.
+#
+# Define SNPRINTF_RETURNS_BOGUS if you are on a system which snprintf()
+# or vsnprintf() return -1 instead of number of characters which would
+# have been written to the final string if enough space had been available.
+#
+# Define FREAD_READS_DIRECTORIES if you are on a system which succeeds
+# when attempting to read from an fopen'ed directory (or even to fopen
+# it at all).
+#
+# Define OPEN_RETURNS_EINTR if your open() system call may return EINTR
+# when a signal is received (as opposed to restarting).
+#
+# Define NO_OPENSSL environment variable if you do not have OpenSSL.
+#
+# Define HAVE_ALLOCA_H if you have working alloca(3) defined in that header.
+#
+# Define HAVE_PATHS_H if you have paths.h and want to use the default PATH
+# it specifies.
+#
+# Define NO_D_TYPE_IN_DIRENT if your platform defines DT_UNKNOWN but lacks
+# d_type in struct dirent (Cygwin 1.5, fixed in Cygwin 1.7).
+#
+# Define HAVE_STRINGS_H if you have strings.h and need it for strcasecmp.
+#
+# Define NO_STRCASESTR if you don't have strcasestr.
+#
+# Define NO_MEMMEM if you don't have memmem.
+#
+# Define NO_GETPAGESIZE if you don't have getpagesize.
+#
+# Define NO_STRLCPY if you don't have strlcpy.
+#
+# Define NO_STRTOUMAX if you don't have both strtoimax and strtoumax in the
+# C library. If your compiler also does not support long long or does not have
+# strtoull, define NO_STRTOULL.
+#
+# Define NO_SETENV if you don't have setenv in the C library.
+#
+# Define NO_UNSETENV if you don't have unsetenv in the C library.
+#
+# Define NO_MKDTEMP if you don't have mkdtemp in the C library.
+#
+# Define MKDIR_WO_TRAILING_SLASH if your mkdir() can't deal with trailing slash.
+#
+# Define NO_GECOS_IN_PWENT if you don't have pw_gecos in struct passwd
+# in the C library.
+#
+# Define NO_LIBGEN_H if you don't have libgen.h.
+#
+# Define NEEDS_LIBGEN if your libgen needs -lgen when linking
+#
+# Define NO_SYS_SELECT_H if you don't have sys/select.h.
+#
+# Define NO_SYMLINK_HEAD if you never want .git/HEAD to be a symbolic link.
+# Enable it on Windows.  By default, symrefs are still used.
+#
+# Define NO_SVN_TESTS if you want to skip time-consuming SVN interoperability
+# tests.  These tests take up a significant amount of the total test time
+# but are not needed unless you plan to talk to SVN repos.
+#
+# Define NO_FINK if you are building on Darwin/Mac OS X, have Fink
+# installed in /sw, but don't want GIT to link against any libraries
+# installed there.  If defined you may specify your own (or Fink's)
+# include directories and library directories by defining CFLAGS
+# and LDFLAGS appropriately.
+#
+# Define NO_DARWIN_PORTS if you are building on Darwin/Mac OS X,
+# have DarwinPorts installed in /opt/local, but don't want GIT to
+# link against any libraries installed there.  If defined you may
+# specify your own (or DarwinPort's) include directories and
+# library directories by defining CFLAGS and LDFLAGS appropriately.
+#
+# Define NO_APPLE_COMMON_CRYPTO if you are building on Darwin/Mac OS X
+# and do not want to use Apple's CommonCrypto library.  This allows you
+# to provide your own OpenSSL library, for example from MacPorts.
+#
+# Define NEEDS_CRYPTO_WITH_SSL if you need -lcrypto when using -lssl (Darwin).
+#
+# Define NEEDS_SSL_WITH_CRYPTO if you need -lssl when using -lcrypto (Darwin).
+#
+# Define NEEDS_LIBICONV if linking with libc is not enough (Darwin).
+#
+# Define NEEDS_LIBINTL_BEFORE_LIBICONV if you need libintl before libiconv.
+#
+# Define NO_INTPTR_T if you don't have intptr_t or uintptr_t.
+#
+# Define NO_UINTMAX_T if you don't have uintmax_t.
+#
+# Define NEEDS_SOCKET if linking with libc is not enough (SunOS,
+# Patrick Mauritz).
+#
+# Define NEEDS_RESOLV if linking with -lnsl and/or -lsocket is not enough.
+# Notably on Solaris hstrerror resides in libresolv and on Solaris 7
+# inet_ntop and inet_pton additionally reside there.
+#
+# Define NO_MMAP if you want to avoid mmap.
+#
+# Define MMAP_PREVENTS_DELETE if a file that is currently mmapped cannot be
+# deleted or cannot be replaced using rename().
+#
+# Define NO_POLL_H if you don't have poll.h.
+#
+# Define NO_SYS_POLL_H if you don't have sys/poll.h.
+#
+# Define NO_POLL if you do not have or don't want to use poll().
+# This also implies NO_POLL_H and NO_SYS_POLL_H.
+#
+# Define NEEDS_SYS_PARAM_H if you need to include sys/param.h to compile,
+# *PLEASE* REPORT to git@xxxxxxxxxxxxxxx if your platform needs this;
+# we want to know more about the issue.
+#
+# Define NO_PTHREADS if you do not have or do not want to use Pthreads.
+#
+# Define NO_PREAD if you have a problem with pread() system call (e.g.
+# cygwin1.dll before v1.5.22).
+#
+# Define NO_SETITIMER if you don't have setitimer()
+#
+# Define NO_STRUCT_ITIMERVAL if you don't have struct itimerval
+# This also implies NO_SETITIMER
+#
+# Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is
+# generally faster on your platform than accessing the working directory.
+#
+# Define NO_TRUSTABLE_FILEMODE if your filesystem may claim to support
+# the executable mode bit, but doesn't really do so.
+#
+# Define CSPRNG_METHOD to "arc4random" if your system has arc4random and
+# arc4random_buf, "libbsd" if your system has those functions from libbsd,
+# "getrandom" if your system has getrandom, "getentropy" if your system has
+# getentropy, "rtlgenrandom" for RtlGenRandom (Windows only), or "openssl" if
+# you'd want to use the OpenSSL CSPRNG.  You may set multiple options with
+# spaces, in which case a suitable option will be chosen.  If unset or set to
+# anything else, defaults to using "/dev/urandom".
+#
+# Define NEEDS_MODE_TRANSLATION if your OS strays from the typical file type
+# bits in mode values (e.g. z/OS defines I_SFMT to 0xFF000000 as opposed to the
+# usual 0xF000).
+#
+# Define NO_IPV6 if you lack IPv6 support and getaddrinfo().
+#
+# Define NO_UNIX_SOCKETS if your system does not offer unix sockets.
+#
+# Define NO_SOCKADDR_STORAGE if your platform does not have struct
+# sockaddr_storage.
+#
+# Define NO_ICONV if your libc does not properly support iconv.
+#
+# Define OLD_ICONV if your library has an old iconv(), where the second
+# (input buffer pointer) parameter is declared with type (const char **).
+#
+# Define ICONV_OMITS_BOM if your iconv implementation does not write a
+# byte-order mark (BOM) when writing UTF-16 or UTF-32 and always writes in
+# big-endian format.
+#
+# Define NO_DEFLATE_BOUND if your zlib does not have deflateBound.
+#
+# Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback,
+# as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299)
+#
+# Define USE_NSEC below if you want git to care about sub-second file mtimes
+# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On
+# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times
+# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git
+# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See
+# Documentation/technical/racy-git.txt for details.
+#
+# Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of
+# "st_ctim"
+#
+# Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec"
+# available.  This automatically turns USE_NSEC off.
+#
+# Define USE_STDEV below if you want git to care about the underlying device
+# change being considered an inode change from the update-index perspective.
+#
+# Define NO_ST_BLOCKS_IN_STRUCT_STAT if your platform does not have st_blocks
+# field that counts the on-disk footprint in 512-byte blocks.
+#
+# Define USE_ASCIIDOCTOR to use Asciidoctor instead of AsciiDoc to build the
+# documentation.
+#
+# Define ASCIIDOCTOR_EXTENSIONS_LAB to point to the location of the Asciidoctor
+# Extensions Lab if you have it available.
+#
+# Define PERL_PATH to the path of your Perl binary (usually /usr/bin/perl).
+#
+# Define NO_PERL if you do not want Perl scripts or libraries at all.
+#
+# Define NO_PERL_CPAN_FALLBACKS if you do not want to install bundled
+# copies of CPAN modules that serve as a fallback in case the modules
+# are not available on the system. This option is intended for
+# distributions that want to use their packaged versions of Perl
+# modules, instead of the fallbacks shipped with Git.
+#
+# Define NO_GITWEB if you do not want to build or install
+# 'gitweb'. Note that defining NO_PERL currently has the same effect
+# on not installing gitweb, but not on whether it's built in the
+# gitweb/ directory.
+#
+# Define PYTHON_PATH to the path of your Python binary (often /usr/bin/python
+# but /usr/bin/python2.7 or /usr/bin/python3 on some platforms).
+#
+# Define NO_PYTHON if you do not want Python scripts or libraries at all.
+#
+# Define NO_TCLTK if you do not want Tcl/Tk GUI.
+#
+# The TCL_PATH variable governs the location of the Tcl interpreter
+# used to optimize git-gui for your system.  Only used if NO_TCLTK
+# is not set.  Defaults to the bare 'tclsh'.
+#
+# The TCLTK_PATH variable governs the location of the Tcl/Tk interpreter.
+# If not set it defaults to the bare 'wish'. If it is set to the empty
+# string then NO_TCLTK will be forced (this is used by configure script).
+#
+# Define INTERNAL_QSORT to use Git's implementation of qsort(), which
+# is a simplified version of the merge sort used in glibc. This is
+# recommended if Git triggers O(n^2) behavior in your platform's qsort().
+#
+# Define HAVE_ISO_QSORT_S if your platform provides a qsort_s() that's
+# compatible with the one described in C11 Annex K.
+#
+# Define UNRELIABLE_FSTAT if your system's fstat does not return the same
+# information on a not yet closed file that lstat would return for the same
+# file after it was closed.
+#
+# Define OBJECT_CREATION_USES_RENAMES if your operating systems has problems
+# when hardlinking a file to another name and unlinking the original file right
+# away (some NTFS drivers seem to zero the contents in that scenario).
+#
+# Define INSTALL_SYMLINKS if you prefer to have everything that can be
+# symlinked between bin/ and libexec/ to use relative symlinks between
+# the two. This option overrides NO_CROSS_DIRECTORY_HARDLINKS and
+# NO_INSTALL_HARDLINKS which will also use symlinking by indirection
+# within the same directory in some cases, INSTALL_SYMLINKS will
+# always symlink to the final target directly.
+#
+# Define NO_CROSS_DIRECTORY_HARDLINKS if you plan to distribute the installed
+# programs as a tar, where bin/ and libexec/ might be on different file systems.
+#
+# Define NO_INSTALL_HARDLINKS if you prefer to use either symbolic links or
+# copies to install built-in git commands e.g. git-cat-file.
+#
+# Define SKIP_DASHED_BUILT_INS if you do not need the dashed versions of the
+# built-ins to be linked/copied at all.
+#
+# Define USE_NED_ALLOCATOR if you want to replace the platforms default
+# memory allocators with the nedmalloc allocator written by Niall Douglas.
+#
+# Define OVERRIDE_STRDUP to override the libc version of strdup(3).
+# This is necessary when using a custom allocator in order to avoid
+# crashes due to allocation and free working on different 'heaps'.
+# It's defined automatically if USE_NED_ALLOCATOR is set.
+#
+# Define NO_REGEX if your C library lacks regex support with REG_STARTEND
+# feature.
+#
+# Define USE_ENHANCED_BASIC_REGULAR_EXPRESSIONS if your C library provides
+# the flag REG_ENHANCED and you'd like to use it to enable enhanced basic
+# regular expressions.
+#
+# Define HAVE_DEV_TTY if your system can open /dev/tty to interact with the
+# user.
+#
+# Define JSMIN to point to JavaScript minifier that functions as
+# a filter to have gitweb.js minified.
+#
+# Define CSSMIN to point to a CSS minifier in order to generate a minified
+# version of gitweb.css
+#
+# Define DEFAULT_PAGER to a sensible pager command (defaults to "less") if
+# you want to use something different.  The value will be interpreted by the
+# shell at runtime when it is used.
+#
+# Define DEFAULT_EDITOR to a sensible editor command (defaults to "vi") if you
+# want to use something different.  The value will be interpreted by the shell
+# if necessary when it is used.  Examples:
+#
+#   DEFAULT_EDITOR='~/bin/vi',
+#   DEFAULT_EDITOR='$GIT_FALLBACK_EDITOR',
+#   DEFAULT_EDITOR='"C:\Program Files\Vim\gvim.exe" --nofork'
+#
+# Define COMPUTE_HEADER_DEPENDENCIES to "yes" if you want dependencies on
+# header files to be automatically computed, to avoid rebuilding objects when
+# an unrelated header file changes.  Define it to "no" to use the hard-coded
+# dependency rules.  The default is "auto", which means to use computed header
+# dependencies if your compiler is detected to support it.
+#
+# Define NATIVE_CRLF if your platform uses CRLF for line endings.
+#
+# Define GIT_USER_AGENT if you want to change how git identifies itself during
+# network interactions.  The default is "git/$(GIT_VERSION)".
+#
+# Define DEFAULT_HELP_FORMAT to "man", "info" or "html"
+# (defaults to "man") if you want to have a different default when
+# "git help" is called without a parameter specifying the format.
+#
+# Define GIT_TEST_INDEX_VERSION to 2, 3 or 4 to run the test suite
+# with a different indexfile format version.  If it isn't set the index
+# file format used is index-v[23].
+#
+# Define GIT_TEST_UTF8_LOCALE to preferred utf-8 locale for testing.
+# If it isn't set, fallback to $LC_ALL, $LANG or use the first utf-8
+# locale returned by "locale -a".
+#
+# Define HAVE_CLOCK_GETTIME if your platform has clock_gettime.
+#
+# Define HAVE_CLOCK_MONOTONIC if your platform has CLOCK_MONOTONIC.
+#
+# Define HAVE_SYNC_FILE_RANGE if your platform has sync_file_range.
+#
+# Define NEEDS_LIBRT if your platform requires linking with librt (glibc version
+# before 2.17) for clock_gettime and CLOCK_MONOTONIC.
+#
+# Define HAVE_BSD_SYSCTL if your platform has a BSD-compatible sysctl function.
+#
+# Define HAVE_GETDELIM if your system has the getdelim() function.
+#
+# Define FILENO_IS_A_MACRO if fileno() is a macro, not a real function.
+#
+# Define NEED_ACCESS_ROOT_HANDLER if access() under root may success for X_OK
+# even if execution permission isn't granted for any user.
+#
+# Define PAGER_ENV to a SP separated VAR=VAL pairs to define
+# default environment variables to be passed when a pager is spawned, e.g.
+#
+#    PAGER_ENV = LESS=FRX LV=-c
+#
+# to say "export LESS=FRX (and LV=-c) if the environment variable
+# LESS (and LV) is not set, respectively".
+#
+# Define TEST_SHELL_PATH if you want to use a shell besides SHELL_PATH for
+# running the test scripts (e.g., bash has better support for "set -x"
+# tracing).
+#
+# When cross-compiling, define HOST_CPU as the canonical name of the CPU on
+# which the built Git will run (for instance "x86_64").
+#
+# Define RUNTIME_PREFIX to configure Git to resolve its ancillary tooling and
+# support files relative to the location of the runtime binary, rather than
+# hard-coding them into the binary. Git installations built with RUNTIME_PREFIX
+# can be moved to arbitrary filesystem locations. RUNTIME_PREFIX also causes
+# Perl scripts to use a modified entry point header allowing them to resolve
+# support files at runtime.
+#
+# When using RUNTIME_PREFIX, define HAVE_BSD_KERN_PROC_SYSCTL if your platform
+# supports the KERN_PROC BSD sysctl function.
+#
+# When using RUNTIME_PREFIX, define PROCFS_EXECUTABLE_PATH if your platform
+# mounts a "procfs" filesystem capable of resolving the path of the current
+# executable. If defined, this must be the canonical path for the "procfs"
+# current executable path.
+#
+# When using RUNTIME_PREFIX, define HAVE_NS_GET_EXECUTABLE_PATH if your platform
+# supports calling _NSGetExecutablePath to retrieve the path of the running
+# executable.
+#
+# When using RUNTIME_PREFIX, define HAVE_ZOS_GET_EXECUTABLE_PATH if your platform
+# supports calling __getprogramdir and getprogname to retrieve the path of the
+# running executable.
+#
+# When using RUNTIME_PREFIX, define HAVE_WPGMPTR if your platform offers
+# the global variable _wpgmptr containing the absolute path of the current
+# executable (this is the case on Windows).
+#
+# INSTALL_STRIP can be set to "-s" to strip binaries during installation,
+# if your $(INSTALL) command supports the option.
+#
+# Define GENERATE_COMPILATION_DATABASE to "yes" to generate JSON compilation
+# database entries during compilation if your compiler supports it, using the
+# `-MJ` flag. The JSON entries will be placed in the `compile_commands/`
+# directory, and the JSON compilation database 'compile_commands.json' will be
+# created at the root of the repository.
+#
+# If your platform supports a built-in fsmonitor backend, set
+# FSMONITOR_DAEMON_BACKEND to the "<name>" of the corresponding
+# `compat/fsmonitor/fsm-listen-<name>.c` and
+# `compat/fsmonitor/fsm-health-<name>.c` files
+# that implement the `fsm_listen__*()` and `fsm_health__*()` routines.
+#
+# If your platform has OS-specific ways to tell if a repo is incompatible with
+# fsmonitor (whether the hook or IPC daemon version), set FSMONITOR_OS_SETTINGS
+# to the "<name>" of the corresponding `compat/fsmonitor/fsm-settings-<name>.c`
+# that implements the `fsm_os_settings__*()` routines.
+#
+# Define LINK_FUZZ_PROGRAMS if you want `make all` to also build the fuzz test
+# programs in oss-fuzz/.
+#
+# === Optional library: libintl ===
+#
+# Define NO_GETTEXT if you don't want Git output to be translated.
+# A translated Git requires GNU libintl or another gettext implementation,
+# plus libintl-perl at runtime.
+#
+# Define USE_GETTEXT_SCHEME and set it to 'fallthrough', if you don't trust
+# the installed gettext translation of the shell scripts output.
+#
+# Define HAVE_LIBCHARSET_H if you haven't set NO_GETTEXT and you can't
+# trust the langinfo.h's nl_langinfo(CODESET) function to return the
+# current character set. GNU and Solaris have a nl_langinfo(CODESET),
+# FreeBSD can use either, but MinGW and some others need to use
+# libcharset.h's locale_charset() instead.
+#
+# Define CHARSET_LIB to the library you need to link with in order to
+# use locale_charset() function.  On some platforms this needs to set to
+# -lcharset, on others to -liconv .
+#
+# Define LIBC_CONTAINS_LIBINTL if your gettext implementation doesn't
+# need -lintl when linking.
+#
+# Define NO_MSGFMT_EXTENDED_OPTIONS if your implementation of msgfmt
+# doesn't support GNU extensions like --check and --statistics
+#
+# === Optional library: libexpat ===
+#
+# Define NO_EXPAT if you do not have expat installed.  git-http-push is
+# not built, and you cannot push using http:// and https:// transports (dumb).
+#
+# Define EXPATDIR=/foo/bar if your expat header and library files are in
+# /foo/bar/include and /foo/bar/lib directories.
+#
+# Define EXPAT_NEEDS_XMLPARSE_H if you have an old version of expat (e.g.,
+# 1.1 or 1.2) that provides xmlparse.h instead of expat.h.
+
+# === Optional library: libcurl ===
+#
+# Define NO_CURL if you do not have libcurl installed.  git-http-fetch and
+# git-http-push are not built, and you cannot use http:// and https://
+# transports (neither smart nor dumb).
+#
+# Define CURLDIR=/foo/bar if your curl header and library files are in
+# /foo/bar/include and /foo/bar/lib directories.
+#
+# Define CURL_CONFIG to curl's configuration program that prints information
+# about the library (e.g., its version number).  The default is 'curl-config'.
+#
+# Define CURL_LDFLAGS to specify flags that you need to link when using libcurl,
+# if you do not want to rely on the libraries provided by CURL_CONFIG.  The
+# default value is a result of `curl-config --libs`.  An example value for
+# CURL_LDFLAGS is as follows:
+#
+#     CURL_LDFLAGS=-lcurl
+#
+# === Optional library: libpcre2 ===
+#
+# Define USE_LIBPCRE if you have and want to use libpcre. Various
+# commands such as log and grep offer runtime options to use
+# Perl-compatible regular expressions instead of standard or extended
+# POSIX regular expressions.
+#
+# Only libpcre version 2 is supported. USE_LIBPCRE2 is a synonym for
+# USE_LIBPCRE, support for the old USE_LIBPCRE1 has been removed.
+#
+# Define LIBPCREDIR=/foo/bar if your PCRE header and library files are
+# in /foo/bar/include and /foo/bar/lib directories.
+#
+# == SHA-1 and SHA-256 defines ==
+#
+# === SHA-1 backend ===
+#
+# ==== Security ====
+#
+# Due to the SHAttered (https://shattered.io) attack vector on SHA-1
+# it's strongly recommended to use the sha1collisiondetection
+# counter-cryptanalysis library for SHA-1 hashing.
+#
+# If you know that you can trust the repository contents, or where
+# potential SHA-1 attacks are otherwise mitigated the other backends
+# listed in "SHA-1 implementations" are faster than
+# sha1collisiondetection.
+#
+# ==== Default SHA-1 backend ====
+#
+# If no *_SHA1 backend is picked, the first supported one listed in
+# "SHA-1 implementations" will be picked.
+#
+# ==== Options common to all SHA-1 implementations ====
+#
+# Define SHA1_MAX_BLOCK_SIZE to limit the amount of data that will be hashed
+# in one call to the platform's SHA1_Update(). e.g. APPLE_COMMON_CRYPTO
+# wants 'SHA1_MAX_BLOCK_SIZE=1024L*1024L*1024L' defined.
+#
+# ==== SHA-1 implementations ====
+#
+# Define OPENSSL_SHA1 to link to the SHA-1 routines from the OpenSSL
+# library.
+#
+# Define BLK_SHA1 to make use of optimized C SHA-1 routines bundled
+# with git (in the block-sha1/ directory).
+#
+# Define APPLE_COMMON_CRYPTO_SHA1 to use Apple's CommonCrypto for
+# SHA-1.
+#
+# Define the same Makefile knobs as above, but suffixed with _UNSAFE to
+# use the corresponding implementations for unsafe SHA-1 hashing for
+# non-cryptographic purposes.
+#
+# If don't enable any of the *_SHA1 settings in this section, Git will
+# default to its built-in sha1collisiondetection library, which is a
+# collision-detecting sha1 This is slower, but may detect attempted
+# collision attacks.
+#
+# ==== Options for the sha1collisiondetection library ====
+#
+# Define DC_SHA1_EXTERNAL if you want to build / link
+# git with the external SHA1 collision-detect library.
+# Without this option, i.e. the default behavior is to build git with its
+# own built-in code (or submodule).
+#
+# Define DC_SHA1_SUBMODULE to use the
+# sha1collisiondetection shipped as a submodule instead of the
+# non-submodule copy in sha1dc/. This is an experimental option used
+# by the git project to migrate to using sha1collisiondetection as a
+# submodule.
+#
+# === SHA-256 backend ===
+#
+# ==== Security ====
+#
+# Unlike SHA-1 the SHA-256 algorithm does not suffer from any known
+# vulnerabilities, so any implementation will do.
+#
+# ==== SHA-256 implementations ====
+#
+# Define OPENSSL_SHA256 to use the SHA-256 routines in OpenSSL.
+#
+# Define NETTLE_SHA256 to use the SHA-256 routines in libnettle.
+#
+# Define GCRYPT_SHA256 to use the SHA-256 routines in libgcrypt.
+#
+# If don't enable any of the *_SHA256 settings in this section, Git
+# will default to its built-in sha256 implementation.
+#
+# == DEVELOPER defines ==
+#
+# Define DEVELOPER to enable more compiler warnings. Compiler version
+# and family are auto detected, but could be overridden by defining
+# COMPILER_FEATURES (see config.mak.dev). You can still set
+# CFLAGS="..." in combination with DEVELOPER enables, whether that's
+# for tweaking something unrelated (e.g. optimization level), or for
+# selectively overriding something DEVELOPER or one of the DEVOPTS
+# (see just below) brings in.
+#
+# When DEVELOPER is set, DEVOPTS can be used to control compiler
+# options.  This variable contains keywords separated by
+# whitespace. The following keywords are recognized:
+#
+#    no-error:
+#
+#        suppresses the -Werror that implicitly comes with
+#        DEVELOPER=1. Useful for getting the full set of errors
+#        without immediately dying, or for logging them.
+#
+#    extra-all:
+#
+#        The DEVELOPER mode enables -Wextra with a few exceptions. By
+#        setting this flag the exceptions are removed, and all of
+#        -Wextra is used.
+#
+#    no-pedantic:
+#
+#        Disable -pedantic compilation.
+
+# Set our default configuration.
+#
+# Among the variables below, these:
+#   gitexecdir
+#   template_dir
+#   sysconfdir
+# can be specified as a relative path some/where/else;
+# this is interpreted as relative to $(prefix) and "git" built with
+# RUNTIME_PREFIX flag will figure out (at runtime) where they are
+# based on the path to the executable.
+# Additionally, the following will be treated as relative by "git" if they
+# begin with "$(prefix)/":
+#   mandir
+#   infodir
+#   htmldir
+#   localedir
+#   perllibdir
+# This can help installing the suite in a relocatable way.
+
+prefix = $(HOME)
+bindir = $(prefix)/bin
+mandir = $(prefix)/share/man
+infodir = $(prefix)/share/info
+gitexecdir = libexec/git-core
+mergetoolsdir = $(gitexecdir)/mergetools
+sharedir = $(prefix)/share
+gitwebdir = $(sharedir)/gitweb
+gitwebstaticdir = $(gitwebdir)/static
+perllibdir = $(sharedir)/perl5
+localedir = $(sharedir)/locale
+template_dir = share/git-core/templates
+htmldir = $(prefix)/share/doc/git-doc
+ETC_GITCONFIG = $(sysconfdir)/gitconfig
+ETC_GITATTRIBUTES = $(sysconfdir)/gitattributes
+lib = lib
+# DESTDIR =
+pathsep = :
+
+bindir_relative = $(patsubst $(prefix)/%,%,$(bindir))
+mandir_relative = $(patsubst $(prefix)/%,%,$(mandir))
+infodir_relative = $(patsubst $(prefix)/%,%,$(infodir))
+gitexecdir_relative = $(patsubst $(prefix)/%,%,$(gitexecdir))
+localedir_relative = $(patsubst $(prefix)/%,%,$(localedir))
+htmldir_relative = $(patsubst $(prefix)/%,%,$(htmldir))
+perllibdir_relative = $(patsubst $(prefix)/%,%,$(perllibdir))
+
+export prefix bindir sharedir sysconfdir perllibdir localedir
+
+# Set our default programs
+CC = cc
+AR = ar
+RM = rm -f
+DIFF = diff
+TAR = tar
+FIND = find
+INSTALL = install
+TCL_PATH = tclsh
+TCLTK_PATH = wish
+XGETTEXT = xgettext
+MSGCAT = msgcat
+MSGFMT = msgfmt
+MSGMERGE = msgmerge
+CURL_CONFIG = curl-config
+GCOV = gcov
+STRIP = strip
+SPATCH = spatch
+
+export TCL_PATH TCLTK_PATH
+
+# Set our default LIBS variables
+PTHREAD_LIBS = -lpthread
+
+# Guard against environment variables
+BUILTIN_OBJS =
+BUILT_INS =
+COMPAT_CFLAGS =
+COMPAT_OBJS =
+XDIFF_OBJS =
+GENERATED_H =
+EXTRA_CPPFLAGS =
+FUZZ_OBJS =
+FUZZ_PROGRAMS =
+GIT_OBJS =
+LIB_OBJS =
+SCALAR_OBJS =
+OBJECTS =
+OTHER_PROGRAMS =
+PROGRAM_OBJS =
+PROGRAMS =
+EXCLUDED_PROGRAMS =
+SCRIPT_PERL =
+SCRIPT_PYTHON =
+SCRIPT_SH =
+SCRIPT_LIB =
+TEST_BUILTINS_OBJS =
+TEST_OBJS =
+TEST_PROGRAMS_NEED_X =
+THIRD_PARTY_SOURCES =
+UNIT_TEST_PROGRAMS =
+UNIT_TEST_DIR = t/unit-tests
+UNIT_TEST_BIN = $(UNIT_TEST_DIR)/bin
+
+# Having this variable in your environment would break pipelines because
+# you cause "cd" to echo its destination to stdout.  It can also take
+# scripts to unexpected places.  If you like CDPATH, define it for your
+# interactive shell sessions without exporting it.
+unexport CDPATH
+
+SCRIPT_SH += git-difftool--helper.sh
+SCRIPT_SH += git-filter-branch.sh
+SCRIPT_SH += git-merge-octopus.sh
+SCRIPT_SH += git-merge-one-file.sh
+SCRIPT_SH += git-merge-resolve.sh
+SCRIPT_SH += git-mergetool.sh
+SCRIPT_SH += git-quiltimport.sh
+SCRIPT_SH += git-request-pull.sh
+SCRIPT_SH += git-submodule.sh
+SCRIPT_SH += git-web--browse.sh
+
+SCRIPT_LIB += git-mergetool--lib
+SCRIPT_LIB += git-sh-i18n
+SCRIPT_LIB += git-sh-setup
+
+SCRIPT_PERL += git-archimport.perl
+SCRIPT_PERL += git-cvsexportcommit.perl
+SCRIPT_PERL += git-cvsimport.perl
+SCRIPT_PERL += git-cvsserver.perl
+SCRIPT_PERL += git-send-email.perl
+SCRIPT_PERL += git-svn.perl
+
+SCRIPT_PYTHON += git-p4.py
+
+# Generated files for scripts
+SCRIPT_SH_GEN = $(patsubst %.sh,%,$(SCRIPT_SH))
+SCRIPT_PERL_GEN = $(patsubst %.perl,%,$(SCRIPT_PERL))
+SCRIPT_PYTHON_GEN = $(patsubst %.py,%,$(SCRIPT_PYTHON))
+
+# Individual rules to allow e.g.
+# "make -C ../.. SCRIPT_PERL=contrib/foo/bar.perl build-perl-script"
+# from subdirectories like contrib/*/
+.PHONY: build-perl-script build-sh-script build-python-script
+build-perl-script: $(SCRIPT_PERL_GEN)
+build-sh-script: $(SCRIPT_SH_GEN)
+build-python-script: $(SCRIPT_PYTHON_GEN)
+
+.PHONY: install-perl-script install-sh-script install-python-script
+install-sh-script: $(SCRIPT_SH_GEN)
+	$(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+install-perl-script: $(SCRIPT_PERL_GEN)
+	$(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+install-python-script: $(SCRIPT_PYTHON_GEN)
+	$(INSTALL) $^ '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+
+.PHONY: clean-perl-script clean-sh-script clean-python-script
+clean-sh-script:
+	$(RM) $(SCRIPT_SH_GEN)
+clean-perl-script:
+	$(RM) $(SCRIPT_PERL_GEN)
+clean-python-script:
+	$(RM) $(SCRIPT_PYTHON_GEN)
+
+SCRIPTS = $(SCRIPT_SH_GEN) \
+	  $(SCRIPT_PERL_GEN) \
+	  $(SCRIPT_PYTHON_GEN) \
+	  git-instaweb
+
+ETAGS_TARGET = TAGS
+
+# Empty...
+EXTRA_PROGRAMS =
+
+# ... and all the rest that could be moved out of bindir to gitexecdir
+PROGRAMS += $(EXTRA_PROGRAMS)
+
+PROGRAM_OBJS += daemon.o
+PROGRAM_OBJS += http-backend.o
+PROGRAM_OBJS += imap-send.o
+PROGRAM_OBJS += sh-i18n--envsubst.o
+PROGRAM_OBJS += shell.o
+.PHONY: program-objs
+program-objs: $(PROGRAM_OBJS)
+
+# Binary suffix, set to .exe for Windows builds
+X =
+
+PROGRAMS += $(patsubst %.o,git-%$X,$(PROGRAM_OBJS))
+
+TEST_BUILTINS_OBJS += test-advise.o
+TEST_BUILTINS_OBJS += test-bitmap.o
+TEST_BUILTINS_OBJS += test-bloom.o
+TEST_BUILTINS_OBJS += test-bundle-uri.o
+TEST_BUILTINS_OBJS += test-cache-tree.o
+TEST_BUILTINS_OBJS += test-chmtime.o
+TEST_BUILTINS_OBJS += test-config.o
+TEST_BUILTINS_OBJS += test-crontab.o
+TEST_BUILTINS_OBJS += test-csprng.o
+TEST_BUILTINS_OBJS += test-date.o
+TEST_BUILTINS_OBJS += test-delete-gpgsig.o
+TEST_BUILTINS_OBJS += test-delta.o
+TEST_BUILTINS_OBJS += test-dir-iterator.o
+TEST_BUILTINS_OBJS += test-drop-caches.o
+TEST_BUILTINS_OBJS += test-dump-cache-tree.o
+TEST_BUILTINS_OBJS += test-dump-fsmonitor.o
+TEST_BUILTINS_OBJS += test-dump-split-index.o
+TEST_BUILTINS_OBJS += test-dump-untracked-cache.o
+TEST_BUILTINS_OBJS += test-env-helper.o
+TEST_BUILTINS_OBJS += test-example-tap.o
+TEST_BUILTINS_OBJS += test-find-pack.o
+TEST_BUILTINS_OBJS += test-fsmonitor-client.o
+TEST_BUILTINS_OBJS += test-genrandom.o
+TEST_BUILTINS_OBJS += test-genzeros.o
+TEST_BUILTINS_OBJS += test-getcwd.o
+TEST_BUILTINS_OBJS += test-hash-speed.o
+TEST_BUILTINS_OBJS += test-hash.o
+TEST_BUILTINS_OBJS += test-hashmap.o
+TEST_BUILTINS_OBJS += test-hexdump.o
+TEST_BUILTINS_OBJS += test-json-writer.o
+TEST_BUILTINS_OBJS += test-lazy-init-name-hash.o
+TEST_BUILTINS_OBJS += test-match-trees.o
+TEST_BUILTINS_OBJS += test-mergesort.o
+TEST_BUILTINS_OBJS += test-mktemp.o
+TEST_BUILTINS_OBJS += test-online-cpus.o
+TEST_BUILTINS_OBJS += test-pack-mtimes.o
+TEST_BUILTINS_OBJS += test-parse-options.o
+TEST_BUILTINS_OBJS += test-parse-pathspec-file.o
+TEST_BUILTINS_OBJS += test-partial-clone.o
+TEST_BUILTINS_OBJS += test-path-utils.o
+TEST_BUILTINS_OBJS += test-path-walk.o
+TEST_BUILTINS_OBJS += test-pcre2-config.o
+TEST_BUILTINS_OBJS += test-pkt-line.o
+TEST_BUILTINS_OBJS += test-proc-receive.o
+TEST_BUILTINS_OBJS += test-progress.o
+TEST_BUILTINS_OBJS += test-reach.o
+TEST_BUILTINS_OBJS += test-read-cache.o
+TEST_BUILTINS_OBJS += test-read-graph.o
+TEST_BUILTINS_OBJS += test-read-midx.o
+TEST_BUILTINS_OBJS += test-ref-store.o
+TEST_BUILTINS_OBJS += test-reftable.o
+TEST_BUILTINS_OBJS += test-regex.o
+TEST_BUILTINS_OBJS += test-rot13-filter.o
+TEST_BUILTINS_OBJS += test-repository.o
+TEST_BUILTINS_OBJS += test-revision-walking.o
+TEST_BUILTINS_OBJS += test-run-command.o
+TEST_BUILTINS_OBJS += test-scrap-cache-tree.o
+TEST_BUILTINS_OBJS += test-serve-v2.o
+TEST_BUILTINS_OBJS += test-sha1.o
+TEST_BUILTINS_OBJS += test-sha256.o
+TEST_BUILTINS_OBJS += test-sigchain.o
+TEST_BUILTINS_OBJS += test-simple-ipc.o
+TEST_BUILTINS_OBJS += test-string-list.o
+TEST_BUILTINS_OBJS += test-submodule-config.o
+TEST_BUILTINS_OBJS += test-submodule-nested-repo-config.o
+TEST_BUILTINS_OBJS += test-submodule.o
+TEST_BUILTINS_OBJS += test-subprocess.o
+TEST_BUILTINS_OBJS += test-trace2.o
+TEST_BUILTINS_OBJS += test-truncate.o
+TEST_BUILTINS_OBJS += test-userdiff.o
+TEST_BUILTINS_OBJS += test-wildmatch.o
+TEST_BUILTINS_OBJS += test-windows-named-pipe.o
+TEST_BUILTINS_OBJS += test-write-cache.o
+TEST_BUILTINS_OBJS += test-xml-encode.o
+
+# Do not add more tests here unless they have extra dependencies. Add
+# them in TEST_BUILTINS_OBJS above.
+TEST_PROGRAMS_NEED_X += test-fake-ssh
+TEST_PROGRAMS_NEED_X += test-tool
+
+TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
+
+# List built-in command $C whose implementation cmd_$C() is not in
+# builtin/$C.o but is linked in as part of some other command.
+BUILT_INS += $(patsubst builtin/%.o,git-%$X,$(BUILTIN_OBJS))
+
+BUILT_INS += git-cherry$X
+BUILT_INS += git-cherry-pick$X
+BUILT_INS += git-format-patch$X
+BUILT_INS += git-fsck-objects$X
+BUILT_INS += git-init$X
+BUILT_INS += git-maintenance$X
+BUILT_INS += git-merge-subtree$X
+BUILT_INS += git-restore$X
+BUILT_INS += git-show$X
+BUILT_INS += git-stage$X
+BUILT_INS += git-status$X
+BUILT_INS += git-switch$X
+BUILT_INS += git-version$X
+BUILT_INS += git-whatchanged$X
+
+# what 'all' will build but not install in gitexecdir
+OTHER_PROGRAMS += git$X
+OTHER_PROGRAMS += scalar$X
+
+# what test wrappers are needed and 'install' will install, in bindir
+BINDIR_PROGRAMS_NEED_X += git
+BINDIR_PROGRAMS_NEED_X += scalar
+BINDIR_PROGRAMS_NEED_X += git-receive-pack
+BINDIR_PROGRAMS_NEED_X += git-shell
+BINDIR_PROGRAMS_NEED_X += git-upload-archive
+BINDIR_PROGRAMS_NEED_X += git-upload-pack
+
+BINDIR_PROGRAMS_NO_X += git-cvsserver
+
+# Set paths to tools early so that they can be used for version tests.
+ifndef SHELL_PATH
+	SHELL_PATH = /bin/sh
+endif
+ifndef PERL_PATH
+	PERL_PATH = /usr/bin/perl
+endif
+ifndef PYTHON_PATH
+	PYTHON_PATH = /usr/bin/python
+endif
+
+export PERL_PATH
+export PYTHON_PATH
+
+TEST_SHELL_PATH = $(SHELL_PATH)
+
+LIB_FILE = libgit.a
+XDIFF_LIB = xdiff/lib.a
+REFTABLE_LIB = reftable/libreftable.a
+
+GENERATED_H += command-list.h
+GENERATED_H += config-list.h
+GENERATED_H += hook-list.h
+GENERATED_H += $(UNIT_TEST_DIR)/clar-decls.h
+GENERATED_H += $(UNIT_TEST_DIR)/clar.suite
+
+.PHONY: generated-hdrs
+generated-hdrs: $(GENERATED_H)
+
+## Exhaustive lists of our source files, either dynamically generated,
+## or hardcoded.
+SOURCES_CMD = ( \
+	git ls-files --deduplicate \
+		'*.[hcS]' \
+		'*.sh' \
+		':!*[tp][0-9][0-9][0-9][0-9]*' \
+		':!contrib' \
+		2>/dev/null || \
+	$(FIND) . \
+		\( -name .git -type d -prune \) \
+		-o \( -name '[tp][0-9][0-9][0-9][0-9]*' -prune \) \
+		-o \( -name contrib -type d -prune \) \
+		-o \( -name build -type d -prune \) \
+		-o \( -name .build -type d -prune \) \
+		-o \( -name 'trash*' -type d -prune \) \
+		-o \( -name '*.[hcS]' -type f -print \) \
+		-o \( -name '*.sh' -type f -print \) \
+		| sed -e 's|^\./||' \
+	)
+FOUND_SOURCE_FILES := $(filter-out $(GENERATED_H),$(shell $(SOURCES_CMD)))
+
+FOUND_C_SOURCES = $(filter %.c,$(FOUND_SOURCE_FILES))
+FOUND_H_SOURCES = $(filter %.h,$(FOUND_SOURCE_FILES))
+
+COCCI_SOURCES = $(filter-out $(THIRD_PARTY_SOURCES),$(FOUND_C_SOURCES))
+
+LIB_H = $(FOUND_H_SOURCES)
+
+LIB_OBJS += abspath.o
+LIB_OBJS += add-interactive.o
+LIB_OBJS += add-patch.o
+LIB_OBJS += advice.o
+LIB_OBJS += alias.o
+LIB_OBJS += alloc.o
+LIB_OBJS += apply.o
+LIB_OBJS += archive-tar.o
+LIB_OBJS += archive-zip.o
+LIB_OBJS += archive.o
+LIB_OBJS += attr.o
+LIB_OBJS += base85.o
+LIB_OBJS += bisect.o
+LIB_OBJS += blame.o
+LIB_OBJS += blob.o
+LIB_OBJS += bloom.o
+LIB_OBJS += branch.o
+LIB_OBJS += bulk-checkin.o
+LIB_OBJS += bundle-uri.o
+LIB_OBJS += bundle.o
+LIB_OBJS += cache-tree.o
+LIB_OBJS += cbtree.o
+LIB_OBJS += chdir-notify.o
+LIB_OBJS += checkout.o
+LIB_OBJS += chunk-format.o
+LIB_OBJS += color.o
+LIB_OBJS += column.o
+LIB_OBJS += combine-diff.o
+LIB_OBJS += commit-graph.o
+LIB_OBJS += commit-reach.o
+LIB_OBJS += commit.o
+LIB_OBJS += compat/nonblock.o
+LIB_OBJS += compat/obstack.o
+LIB_OBJS += compat/terminal.o
+LIB_OBJS += compat/zlib-uncompress2.o
+LIB_OBJS += config.o
+LIB_OBJS += connect.o
+LIB_OBJS += connected.o
+LIB_OBJS += convert.o
+LIB_OBJS += copy.o
+LIB_OBJS += credential.o
+LIB_OBJS += csum-file.o
+LIB_OBJS += ctype.o
+LIB_OBJS += date.o
+LIB_OBJS += decorate.o
+LIB_OBJS += delta-islands.o
+LIB_OBJS += diagnose.o
+LIB_OBJS += diff-delta.o
+LIB_OBJS += diff-merges.o
+LIB_OBJS += diff-lib.o
+LIB_OBJS += diff-no-index.o
+LIB_OBJS += diff.o
+LIB_OBJS += diffcore-break.o
+LIB_OBJS += diffcore-delta.o
+LIB_OBJS += diffcore-order.o
+LIB_OBJS += diffcore-pickaxe.o
+LIB_OBJS += diffcore-rename.o
+LIB_OBJS += diffcore-rotate.o
+LIB_OBJS += dir-iterator.o
+LIB_OBJS += dir.o
+LIB_OBJS += editor.o
+LIB_OBJS += entry.o
+LIB_OBJS += environment.o
+LIB_OBJS += ewah/bitmap.o
+LIB_OBJS += ewah/ewah_bitmap.o
+LIB_OBJS += ewah/ewah_io.o
+LIB_OBJS += ewah/ewah_rlw.o
+LIB_OBJS += exec-cmd.o
+LIB_OBJS += fetch-negotiator.o
+LIB_OBJS += fetch-pack.o
+LIB_OBJS += fmt-merge-msg.o
+LIB_OBJS += fsck.o
+LIB_OBJS += fsmonitor.o
+LIB_OBJS += fsmonitor-ipc.o
+LIB_OBJS += fsmonitor-settings.o
+LIB_OBJS += gettext.o
+LIB_OBJS += git-zlib.o
+LIB_OBJS += gpg-interface.o
+LIB_OBJS += graph.o
+LIB_OBJS += grep.o
+LIB_OBJS += hash-lookup.o
+LIB_OBJS += hashmap.o
+LIB_OBJS += help.o
+LIB_OBJS += hex.o
+LIB_OBJS += hex-ll.o
+LIB_OBJS += hook.o
+LIB_OBJS += ident.o
+LIB_OBJS += json-writer.o
+LIB_OBJS += kwset.o
+LIB_OBJS += levenshtein.o
+LIB_OBJS += line-log.o
+LIB_OBJS += line-range.o
+LIB_OBJS += linear-assignment.o
+LIB_OBJS += list-objects-filter-options.o
+LIB_OBJS += list-objects-filter.o
+LIB_OBJS += list-objects.o
+LIB_OBJS += lockfile.o
+LIB_OBJS += log-tree.o
+LIB_OBJS += loose.o
+LIB_OBJS += ls-refs.o
+LIB_OBJS += mailinfo.o
+LIB_OBJS += mailmap.o
+LIB_OBJS += match-trees.o
+LIB_OBJS += mem-pool.o
+LIB_OBJS += merge-blobs.o
+LIB_OBJS += merge-ll.o
+LIB_OBJS += merge-ort.o
+LIB_OBJS += merge-ort-wrappers.o
+LIB_OBJS += merge-recursive.o
+LIB_OBJS += merge.o
+LIB_OBJS += midx.o
+LIB_OBJS += midx-write.o
+LIB_OBJS += name-hash.o
+LIB_OBJS += negotiator/default.o
+LIB_OBJS += negotiator/noop.o
+LIB_OBJS += negotiator/skipping.o
+LIB_OBJS += notes-cache.o
+LIB_OBJS += notes-merge.o
+LIB_OBJS += notes-utils.o
+LIB_OBJS += notes.o
+LIB_OBJS += object-file-convert.o
+LIB_OBJS += object-file.o
+LIB_OBJS += object-name.o
+LIB_OBJS += object.o
+LIB_OBJS += oid-array.o
+LIB_OBJS += oidmap.o
+LIB_OBJS += oidset.o
+LIB_OBJS += oidtree.o
+LIB_OBJS += pack-bitmap-write.o
+LIB_OBJS += pack-bitmap.o
+LIB_OBJS += pack-check.o
+LIB_OBJS += pack-mtimes.o
+LIB_OBJS += pack-objects.o
+LIB_OBJS += pack-revindex.o
+LIB_OBJS += pack-write.o
+LIB_OBJS += packfile.o
+LIB_OBJS += pager.o
+LIB_OBJS += parallel-checkout.o
+LIB_OBJS += parse.o
+LIB_OBJS += parse-options-cb.o
+LIB_OBJS += parse-options.o
+LIB_OBJS += patch-delta.o
+LIB_OBJS += patch-ids.o
+LIB_OBJS += path.o
+LIB_OBJS += path-walk.o
+LIB_OBJS += pathspec.o
+LIB_OBJS += pkt-line.o
+LIB_OBJS += preload-index.o
+LIB_OBJS += pretty.o
+LIB_OBJS += prio-queue.o
+LIB_OBJS += progress.o
+LIB_OBJS += promisor-remote.o
+LIB_OBJS += prompt.o
+LIB_OBJS += protocol.o
+LIB_OBJS += protocol-caps.o
+LIB_OBJS += prune-packed.o
+LIB_OBJS += pseudo-merge.o
+LIB_OBJS += quote.o
+LIB_OBJS += range-diff.o
+LIB_OBJS += reachable.o
+LIB_OBJS += read-cache.o
+LIB_OBJS += rebase-interactive.o
+LIB_OBJS += rebase.o
+LIB_OBJS += ref-filter.o
+LIB_OBJS += reflog-walk.o
+LIB_OBJS += reflog.o
+LIB_OBJS += refs.o
+LIB_OBJS += refs/debug.o
+LIB_OBJS += refs/files-backend.o
+LIB_OBJS += refs/reftable-backend.o
+LIB_OBJS += refs/iterator.o
+LIB_OBJS += refs/packed-backend.o
+LIB_OBJS += refs/ref-cache.o
+LIB_OBJS += refspec.o
+LIB_OBJS += remote.o
+LIB_OBJS += replace-object.o
+LIB_OBJS += repo-settings.o
+LIB_OBJS += repository.o
+LIB_OBJS += rerere.o
+LIB_OBJS += reset.o
+LIB_OBJS += resolve-undo.o
+LIB_OBJS += revision.o
+LIB_OBJS += run-command.o
+LIB_OBJS += send-pack.o
+LIB_OBJS += sequencer.o
+LIB_OBJS += serve.o
+LIB_OBJS += server-info.o
+LIB_OBJS += setup.o
+LIB_OBJS += shallow.o
+LIB_OBJS += sideband.o
+LIB_OBJS += sigchain.o
+LIB_OBJS += sparse-index.o
+LIB_OBJS += split-index.o
+LIB_OBJS += stable-qsort.o
+LIB_OBJS += statinfo.o
+LIB_OBJS += strbuf.o
+LIB_OBJS += streaming.o
+LIB_OBJS += string-list.o
+LIB_OBJS += strmap.o
+LIB_OBJS += strvec.o
+LIB_OBJS += sub-process.o
+LIB_OBJS += submodule-config.o
+LIB_OBJS += submodule.o
+LIB_OBJS += symlinks.o
+LIB_OBJS += tag.o
+LIB_OBJS += tempfile.o
+LIB_OBJS += thread-utils.o
+LIB_OBJS += tmp-objdir.o
+LIB_OBJS += trace.o
+LIB_OBJS += trace2.o
+LIB_OBJS += trace2/tr2_cfg.o
+LIB_OBJS += trace2/tr2_cmd_name.o
+LIB_OBJS += trace2/tr2_ctr.o
+LIB_OBJS += trace2/tr2_dst.o
+LIB_OBJS += trace2/tr2_sid.o
+LIB_OBJS += trace2/tr2_sysenv.o
+LIB_OBJS += trace2/tr2_tbuf.o
+LIB_OBJS += trace2/tr2_tgt_event.o
+LIB_OBJS += trace2/tr2_tgt_normal.o
+LIB_OBJS += trace2/tr2_tgt_perf.o
+LIB_OBJS += trace2/tr2_tls.o
+LIB_OBJS += trace2/tr2_tmr.o
+LIB_OBJS += trailer.o
+LIB_OBJS += transport-helper.o
+LIB_OBJS += transport.o
+LIB_OBJS += tree-diff.o
+LIB_OBJS += tree-walk.o
+LIB_OBJS += tree.o
+LIB_OBJS += unpack-trees.o
+LIB_OBJS += upload-pack.o
+LIB_OBJS += url.o
+LIB_OBJS += urlmatch.o
+LIB_OBJS += usage.o
+LIB_OBJS += userdiff.o
+LIB_OBJS += utf8.o
+LIB_OBJS += varint.o
+LIB_OBJS += version.o
+LIB_OBJS += versioncmp.o
+LIB_OBJS += walker.o
+LIB_OBJS += wildmatch.o
+LIB_OBJS += worktree.o
+LIB_OBJS += wrapper.o
+LIB_OBJS += write-or-die.o
+LIB_OBJS += ws.o
+LIB_OBJS += wt-status.o
+LIB_OBJS += xdiff-interface.o
+
+BUILTIN_OBJS += builtin/add.o
+BUILTIN_OBJS += builtin/am.o
+BUILTIN_OBJS += builtin/annotate.o
+BUILTIN_OBJS += builtin/apply.o
+BUILTIN_OBJS += builtin/archive.o
+BUILTIN_OBJS += builtin/bisect.o
+BUILTIN_OBJS += builtin/blame.o
+BUILTIN_OBJS += builtin/branch.o
+BUILTIN_OBJS += builtin/bugreport.o
+BUILTIN_OBJS += builtin/bundle.o
+BUILTIN_OBJS += builtin/cat-file.o
+BUILTIN_OBJS += builtin/check-attr.o
+BUILTIN_OBJS += builtin/check-ignore.o
+BUILTIN_OBJS += builtin/check-mailmap.o
+BUILTIN_OBJS += builtin/check-ref-format.o
+BUILTIN_OBJS += builtin/checkout--worker.o
+BUILTIN_OBJS += builtin/checkout-index.o
+BUILTIN_OBJS += builtin/checkout.o
+BUILTIN_OBJS += builtin/clean.o
+BUILTIN_OBJS += builtin/clone.o
+BUILTIN_OBJS += builtin/column.o
+BUILTIN_OBJS += builtin/commit-graph.o
+BUILTIN_OBJS += builtin/commit-tree.o
+BUILTIN_OBJS += builtin/commit.o
+BUILTIN_OBJS += builtin/config.o
+BUILTIN_OBJS += builtin/count-objects.o
+BUILTIN_OBJS += builtin/credential-cache--daemon.o
+BUILTIN_OBJS += builtin/credential-cache.o
+BUILTIN_OBJS += builtin/credential-store.o
+BUILTIN_OBJS += builtin/credential.o
+BUILTIN_OBJS += builtin/describe.o
+BUILTIN_OBJS += builtin/diagnose.o
+BUILTIN_OBJS += builtin/diff-files.o
+BUILTIN_OBJS += builtin/diff-index.o
+BUILTIN_OBJS += builtin/diff-tree.o
+BUILTIN_OBJS += builtin/diff.o
+BUILTIN_OBJS += builtin/difftool.o
+BUILTIN_OBJS += builtin/fast-export.o
+BUILTIN_OBJS += builtin/fast-import.o
+BUILTIN_OBJS += builtin/fetch-pack.o
+BUILTIN_OBJS += builtin/fetch.o
+BUILTIN_OBJS += builtin/fmt-merge-msg.o
+BUILTIN_OBJS += builtin/for-each-ref.o
+BUILTIN_OBJS += builtin/for-each-repo.o
+BUILTIN_OBJS += builtin/fsck.o
+BUILTIN_OBJS += builtin/fsmonitor--daemon.o
+BUILTIN_OBJS += builtin/gc.o
+BUILTIN_OBJS += builtin/get-tar-commit-id.o
+BUILTIN_OBJS += builtin/grep.o
+BUILTIN_OBJS += builtin/hash-object.o
+BUILTIN_OBJS += builtin/help.o
+BUILTIN_OBJS += builtin/hook.o
+BUILTIN_OBJS += builtin/index-pack.o
+BUILTIN_OBJS += builtin/init-db.o
+BUILTIN_OBJS += builtin/interpret-trailers.o
+BUILTIN_OBJS += builtin/log.o
+BUILTIN_OBJS += builtin/ls-files.o
+BUILTIN_OBJS += builtin/ls-remote.o
+BUILTIN_OBJS += builtin/ls-tree.o
+BUILTIN_OBJS += builtin/mailinfo.o
+BUILTIN_OBJS += builtin/mailsplit.o
+BUILTIN_OBJS += builtin/merge-base.o
+BUILTIN_OBJS += builtin/merge-file.o
+BUILTIN_OBJS += builtin/merge-index.o
+BUILTIN_OBJS += builtin/merge-ours.o
+BUILTIN_OBJS += builtin/merge-recursive.o
+BUILTIN_OBJS += builtin/merge-tree.o
+BUILTIN_OBJS += builtin/merge.o
+BUILTIN_OBJS += builtin/mktag.o
+BUILTIN_OBJS += builtin/mktree.o
+BUILTIN_OBJS += builtin/multi-pack-index.o
+BUILTIN_OBJS += builtin/mv.o
+BUILTIN_OBJS += builtin/name-rev.o
+BUILTIN_OBJS += builtin/notes.o
+BUILTIN_OBJS += builtin/pack-objects.o
+BUILTIN_OBJS += builtin/pack-redundant.o
+BUILTIN_OBJS += builtin/pack-refs.o
+BUILTIN_OBJS += builtin/patch-id.o
+BUILTIN_OBJS += builtin/prune-packed.o
+BUILTIN_OBJS += builtin/prune.o
+BUILTIN_OBJS += builtin/pull.o
+BUILTIN_OBJS += builtin/push.o
+BUILTIN_OBJS += builtin/range-diff.o
+BUILTIN_OBJS += builtin/read-tree.o
+BUILTIN_OBJS += builtin/rebase.o
+BUILTIN_OBJS += builtin/receive-pack.o
+BUILTIN_OBJS += builtin/reflog.o
+BUILTIN_OBJS += builtin/refs.o
+BUILTIN_OBJS += builtin/remote-ext.o
+BUILTIN_OBJS += builtin/remote-fd.o
+BUILTIN_OBJS += builtin/remote.o
+BUILTIN_OBJS += builtin/repack.o
+BUILTIN_OBJS += builtin/replace.o
+BUILTIN_OBJS += builtin/replay.o
+BUILTIN_OBJS += builtin/rerere.o
+BUILTIN_OBJS += builtin/reset.o
+BUILTIN_OBJS += builtin/rev-list.o
+BUILTIN_OBJS += builtin/rev-parse.o
+BUILTIN_OBJS += builtin/revert.o
+BUILTIN_OBJS += builtin/rm.o
+BUILTIN_OBJS += builtin/send-pack.o
+BUILTIN_OBJS += builtin/shortlog.o
+BUILTIN_OBJS += builtin/show-branch.o
+BUILTIN_OBJS += builtin/show-index.o
+BUILTIN_OBJS += builtin/show-ref.o
+BUILTIN_OBJS += builtin/sparse-checkout.o
+BUILTIN_OBJS += builtin/stash.o
+BUILTIN_OBJS += builtin/stripspace.o
+BUILTIN_OBJS += builtin/submodule--helper.o
+BUILTIN_OBJS += builtin/symbolic-ref.o
+BUILTIN_OBJS += builtin/tag.o
+BUILTIN_OBJS += builtin/unpack-file.o
+BUILTIN_OBJS += builtin/unpack-objects.o
+BUILTIN_OBJS += builtin/update-index.o
+BUILTIN_OBJS += builtin/update-ref.o
+BUILTIN_OBJS += builtin/update-server-info.o
+BUILTIN_OBJS += builtin/upload-archive.o
+BUILTIN_OBJS += builtin/upload-pack.o
+BUILTIN_OBJS += builtin/var.o
+BUILTIN_OBJS += builtin/verify-commit.o
+BUILTIN_OBJS += builtin/verify-pack.o
+BUILTIN_OBJS += builtin/verify-tag.o
+BUILTIN_OBJS += builtin/worktree.o
+BUILTIN_OBJS += builtin/write-tree.o
+
+# THIRD_PARTY_SOURCES is a list of patterns compatible with the
+# $(filter) and $(filter-out) family of functions. They specify source
+# files which are taken from some third-party source where we want to be
+# less strict about issues such as coding style so we don't diverge from
+# upstream unnecessarily (making merging in future changes easier).
+THIRD_PARTY_SOURCES += compat/inet_ntop.c
+THIRD_PARTY_SOURCES += compat/inet_pton.c
+THIRD_PARTY_SOURCES += compat/nedmalloc/%
+THIRD_PARTY_SOURCES += compat/obstack.%
+THIRD_PARTY_SOURCES += compat/poll/%
+THIRD_PARTY_SOURCES += compat/regex/%
+THIRD_PARTY_SOURCES += sha1collisiondetection/%
+THIRD_PARTY_SOURCES += sha1dc/%
+THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/%
+THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/%
+
+CLAR_TEST_SUITES += u-ctype
+CLAR_TEST_SUITES += u-hash
+CLAR_TEST_SUITES += u-mem-pool
+CLAR_TEST_SUITES += u-prio-queue
+CLAR_TEST_SUITES += u-reftable-tree
+CLAR_TEST_SUITES += u-strvec
+CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X)
+CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES))
+CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o
+CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o
+
+UNIT_TEST_PROGRAMS += t-example-decorate
+UNIT_TEST_PROGRAMS += t-hashmap
+UNIT_TEST_PROGRAMS += t-oid-array
+UNIT_TEST_PROGRAMS += t-oidmap
+UNIT_TEST_PROGRAMS += t-oidtree
+UNIT_TEST_PROGRAMS += t-reftable-basics
+UNIT_TEST_PROGRAMS += t-reftable-block
+UNIT_TEST_PROGRAMS += t-reftable-merged
+UNIT_TEST_PROGRAMS += t-reftable-pq
+UNIT_TEST_PROGRAMS += t-reftable-reader
+UNIT_TEST_PROGRAMS += t-reftable-readwrite
+UNIT_TEST_PROGRAMS += t-reftable-record
+UNIT_TEST_PROGRAMS += t-reftable-stack
+UNIT_TEST_PROGRAMS += t-strbuf
+UNIT_TEST_PROGRAMS += t-strcmp-offset
+UNIT_TEST_PROGRAMS += t-trailer
+UNIT_TEST_PROGRAMS += t-urlmatch-normalization
+UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
+UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o
+UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.o
+UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o
+
+# xdiff and reftable libs may in turn depend on what is in libgit.a
+GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE)
+EXTLIBS =
+
+GIT_USER_AGENT = git/$(GIT_VERSION)
+
+ifeq ($(wildcard sha1collisiondetection/lib/sha1.h),sha1collisiondetection/lib/sha1.h)
+DC_SHA1_SUBMODULE = auto
+endif
+
+# Set CFLAGS, LDFLAGS and other *FLAGS variables. These might be
+# tweaked by config.* below as well as the command-line, both of
+# which'll override these defaults.
+# Older versions of GCC may require adding "-std=gnu99" at the end.
+CFLAGS = -g -O2 -Wall
+LDFLAGS =
+CC_LD_DYNPATH = -Wl,-rpath,
+BASIC_CFLAGS = -I.
+BASIC_LDFLAGS =
+
+# library flags
+ARFLAGS = rcs
+PTHREAD_CFLAGS =
+
+# For the 'sparse' target
+SPARSE_FLAGS ?= -std=gnu99
+SP_EXTRA_FLAGS =
+
+# For informing GIT-BUILD-OPTIONS of the SANITIZE=leak,address targets
+SANITIZE_LEAK =
+SANITIZE_ADDRESS =
+
+# For the 'coccicheck' target
+SPATCH_INCLUDE_FLAGS = --all-includes
+SPATCH_FLAGS =
+SPATCH_TEST_FLAGS =
+
+# If *.o files are present, have "coccicheck" depend on them, with
+# COMPUTE_HEADER_DEPENDENCIES this will speed up the common-case of
+# only needing to re-generate coccicheck results for the users of a
+# given API if it's changed, and not all files in the project. If
+# COMPUTE_HEADER_DEPENDENCIES=no this will be unset too.
+SPATCH_USE_O_DEPENDENCIES = YesPlease
+
+# Set SPATCH_CONCAT_COCCI to concatenate the contrib/cocci/*.cocci
+# files into a single contrib/cocci/ALL.cocci before running
+# "coccicheck".
+#
+# Pros:
+#
+# - Speeds up a one-shot run of "make coccicheck", as we won't have to
+#   parse *.[ch] files N times for the N *.cocci rules
+#
+# Cons:
+#
+# - Will make incremental development of *.cocci slower, as
+#   e.g. changing strbuf.cocci will re-run all *.cocci.
+#
+# - Makes error and performance analysis harder, as rules will be
+#   applied from a monolithic ALL.cocci, rather than
+#   e.g. strbuf.cocci. To work around this either undefine this, or
+#   generate a specific patch, e.g. this will always use strbuf.cocci,
+#   not ALL.cocci:
+#
+#	make contrib/coccinelle/strbuf.cocci.patch
+SPATCH_CONCAT_COCCI = YesPlease
+
+# Rebuild 'coccicheck' if $(SPATCH), its flags etc. change
+TRACK_SPATCH_DEFINES =
+TRACK_SPATCH_DEFINES += $(SPATCH)
+TRACK_SPATCH_DEFINES += $(SPATCH_INCLUDE_FLAGS)
+TRACK_SPATCH_DEFINES += $(SPATCH_FLAGS)
+TRACK_SPATCH_DEFINES += $(SPATCH_TEST_FLAGS)
+GIT-SPATCH-DEFINES: FORCE
+	@FLAGS='$(TRACK_SPATCH_DEFINES)'; \
+	    if test x"$$FLAGS" != x"`cat GIT-SPATCH-DEFINES 2>/dev/null`" ; then \
+		echo >&2 "    * new spatch flags"; \
+		echo "$$FLAGS" >GIT-SPATCH-DEFINES; \
+            fi
+
+include config.mak.uname
+-include config.mak.autogen
+-include config.mak
+
+ifdef DEVELOPER
+include config.mak.dev
+endif
+
+GIT-VERSION-FILE: FORCE
+	@OLD=$$(cat $@ 2>/dev/null || :) && \
+	$(call version_gen,"$(shell pwd)",GIT-VERSION-FILE.in,$@) && \
+	NEW=$$(cat $@ 2>/dev/null || :) && \
+	if test "$$OLD" != "$$NEW"; then echo "$$NEW" >&2; fi
+
+# We need to set GIT_VERSION_OVERRIDE before including the version file as
+# otherwise any user-provided value for GIT_VERSION would have been overridden
+# already.
+GIT_VERSION_OVERRIDE := $(GIT_VERSION)
+-include GIT-VERSION-FILE
+
+# what 'all' will build and 'install' will install in gitexecdir,
+# excluding programs for built-in commands
+ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
+ALL_COMMANDS_TO_INSTALL = $(ALL_PROGRAMS)
+ifeq (,$(SKIP_DASHED_BUILT_INS))
+ALL_COMMANDS_TO_INSTALL += $(BUILT_INS)
+else
+# git-upload-pack, git-receive-pack and git-upload-archive are special: they
+# are _expected_ to be present in the `bin/` directory in their dashed form.
+ALL_COMMANDS_TO_INSTALL += git-receive-pack$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-archive$(X)
+ALL_COMMANDS_TO_INSTALL += git-upload-pack$(X)
+endif
+
+ALL_CFLAGS = $(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_APPEND)
+ALL_LDFLAGS = $(LDFLAGS) $(LDFLAGS_APPEND)
+
+ifdef SANITIZE
+SANITIZERS := $(foreach flag,$(subst $(comma),$(space),$(SANITIZE)),$(flag))
+BASIC_CFLAGS += -fsanitize=$(SANITIZE) -fno-sanitize-recover=$(SANITIZE)
+BASIC_CFLAGS += -fno-omit-frame-pointer
+ifneq ($(filter undefined,$(SANITIZERS)),)
+BASIC_CFLAGS += -DSHA1DC_FORCE_ALIGNED_ACCESS
+endif
+ifneq ($(filter leak,$(SANITIZERS)),)
+BASIC_CFLAGS += -O0
+SANITIZE_LEAK = YesCompiledWithIt
+endif
+ifneq ($(filter address,$(SANITIZERS)),)
+NO_REGEX = NeededForASAN
+SANITIZE_ADDRESS = YesCompiledWithIt
+endif
+endif
+
+ifndef sysconfdir
+ifeq ($(prefix),/usr)
+sysconfdir = /etc
+else
+sysconfdir = etc
+endif
+endif
+
+ifndef COMPUTE_HEADER_DEPENDENCIES
+COMPUTE_HEADER_DEPENDENCIES = auto
+endif
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),auto)
+dep_check = $(shell $(CC) $(ALL_CFLAGS) \
+	-Wno-pedantic \
+	-c -MF /dev/null -MQ /dev/null -MMD -MP \
+	-x c /dev/null -o /dev/null 2>&1; \
+	echo $$?)
+ifeq ($(dep_check),0)
+override COMPUTE_HEADER_DEPENDENCIES = yes
+else
+override COMPUTE_HEADER_DEPENDENCIES = no
+endif
+endif
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
+USE_COMPUTED_HEADER_DEPENDENCIES = YesPlease
+else
+ifneq ($(COMPUTE_HEADER_DEPENDENCIES),no)
+$(error please set COMPUTE_HEADER_DEPENDENCIES to yes, no, or auto \
+(not "$(COMPUTE_HEADER_DEPENDENCIES)"))
+endif
+endif
+
+ifndef GENERATE_COMPILATION_DATABASE
+GENERATE_COMPILATION_DATABASE = no
+endif
+
+ifeq ($(GENERATE_COMPILATION_DATABASE),yes)
+compdb_check = $(shell $(CC) $(ALL_CFLAGS) \
+	-Wno-pedantic \
+	-c -MJ /dev/null \
+	-x c /dev/null -o /dev/null 2>&1; \
+	echo $$?)
+ifneq ($(compdb_check),0)
+override GENERATE_COMPILATION_DATABASE = no
+$(warning GENERATE_COMPILATION_DATABASE is set to "yes", but your compiler does not \
+support generating compilation database entries)
+endif
+else
+ifneq ($(GENERATE_COMPILATION_DATABASE),no)
+$(error please set GENERATE_COMPILATION_DATABASE to "yes" or "no" \
+(not "$(GENERATE_COMPILATION_DATABASE)"))
+endif
+endif
+
+ifdef SANE_TOOL_PATH
+SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH))
+BROKEN_PATH_FIX = s|^\# @BROKEN_PATH_FIX@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|
+PATH := $(SANE_TOOL_PATH):${PATH}
+else
+BROKEN_PATH_FIX = /^\# @BROKEN_PATH_FIX@$$/d
+endif
+
+ifeq (,$(HOST_CPU))
+	BASIC_CFLAGS += -DGIT_HOST_CPU="\"$(firstword $(subst -, ,$(uname_M)))\""
+else
+	BASIC_CFLAGS += -DGIT_HOST_CPU="\"$(HOST_CPU)\""
+endif
+
+ifneq (,$(INLINE))
+	BASIC_CFLAGS += -Dinline=$(INLINE)
+endif
+
+ifneq (,$(SOCKLEN_T))
+	BASIC_CFLAGS += -Dsocklen_t=$(SOCKLEN_T)
+endif
+
+ifeq ($(uname_S),Darwin)
+        ifndef NO_FINK
+                ifeq ($(shell test -d /sw/lib && echo y),y)
+			BASIC_CFLAGS += -I/sw/include
+			BASIC_LDFLAGS += -L/sw/lib
+                endif
+        endif
+        ifndef NO_DARWIN_PORTS
+                ifeq ($(shell test -d /opt/local/lib && echo y),y)
+			BASIC_CFLAGS += -I/opt/local/include
+			BASIC_LDFLAGS += -L/opt/local/lib
+                endif
+        endif
+        ifndef NO_APPLE_COMMON_CRYPTO
+		NO_OPENSSL = YesPlease
+		APPLE_COMMON_CRYPTO = YesPlease
+		COMPAT_CFLAGS += -DAPPLE_COMMON_CRYPTO
+        endif
+	PTHREAD_LIBS =
+endif
+
+ifdef NO_LIBGEN_H
+	COMPAT_CFLAGS += -DNO_LIBGEN_H
+	COMPAT_OBJS += compat/basename.o
+endif
+
+ifdef USE_LIBPCRE1
+$(error The USE_LIBPCRE1 build option has been removed, use version 2 with USE_LIBPCRE)
+endif
+
+USE_LIBPCRE2 ?= $(USE_LIBPCRE)
+
+ifneq (,$(USE_LIBPCRE2))
+	BASIC_CFLAGS += -DUSE_LIBPCRE2
+	EXTLIBS += -lpcre2-8
+endif
+
+ifdef LIBPCREDIR
+	BASIC_CFLAGS += -I$(LIBPCREDIR)/include
+	EXTLIBS += $(call libpath_template,$(LIBPCREDIR)/$(lib))
+endif
+
+ifdef HAVE_ALLOCA_H
+	BASIC_CFLAGS += -DHAVE_ALLOCA_H
+endif
+
+IMAP_SEND_BUILDDEPS =
+IMAP_SEND_LDFLAGS =
+
+ifdef NO_CURL
+	BASIC_CFLAGS += -DNO_CURL
+	REMOTE_CURL_PRIMARY =
+	REMOTE_CURL_ALIASES =
+	REMOTE_CURL_NAMES =
+	EXCLUDED_PROGRAMS += git-http-fetch git-http-push
+else
+        ifdef CURLDIR
+		# Try "-Wl,-rpath=$(CURLDIR)/$(lib)" in such a case.
+		CURL_CFLAGS = -I$(CURLDIR)/include
+		CURL_LIBCURL = $(call libpath_template,$(CURLDIR)/$(lib))
+        else
+		CURL_CFLAGS =
+		CURL_LIBCURL =
+        endif
+
+        ifndef CURL_LDFLAGS
+		CURL_LDFLAGS = $(eval CURL_LDFLAGS := $$(shell $$(CURL_CONFIG) --libs))$(CURL_LDFLAGS)
+        endif
+	CURL_LIBCURL += $(CURL_LDFLAGS)
+
+        ifndef CURL_CFLAGS
+		CURL_CFLAGS = $(eval CURL_CFLAGS := $$(shell $$(CURL_CONFIG) --cflags))$(CURL_CFLAGS)
+        endif
+	BASIC_CFLAGS += $(CURL_CFLAGS)
+
+	REMOTE_CURL_PRIMARY = git-remote-http$X
+	REMOTE_CURL_ALIASES = git-remote-https$X git-remote-ftp$X git-remote-ftps$X
+	REMOTE_CURL_NAMES = $(REMOTE_CURL_PRIMARY) $(REMOTE_CURL_ALIASES)
+	PROGRAM_OBJS += http-fetch.o
+	PROGRAMS += $(REMOTE_CURL_NAMES)
+        ifndef NO_EXPAT
+		PROGRAM_OBJS += http-push.o
+        endif
+	curl_check := $(shell (echo 072200; $(CURL_CONFIG) --vernum | sed -e '/^70[BC]/s/^/0/') 2>/dev/null | sort -r | sed -ne 2p)
+        ifeq "$(curl_check)" "072200"
+		USE_CURL_FOR_IMAP_SEND = YesPlease
+        endif
+        ifdef USE_CURL_FOR_IMAP_SEND
+		BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
+		IMAP_SEND_BUILDDEPS = http.o
+		IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
+        endif
+        ifndef NO_EXPAT
+                ifdef EXPATDIR
+			BASIC_CFLAGS += -I$(EXPATDIR)/include
+			EXPAT_LIBEXPAT = $(call libpath_template,$(EXPATDIR)/$(lib)) -lexpat
+                else
+			EXPAT_LIBEXPAT = -lexpat
+                endif
+                ifdef EXPAT_NEEDS_XMLPARSE_H
+			BASIC_CFLAGS += -DEXPAT_NEEDS_XMLPARSE_H
+                endif
+        endif
+endif
+IMAP_SEND_LDFLAGS += $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
+
+ifdef ZLIB_PATH
+	BASIC_CFLAGS += -I$(ZLIB_PATH)/include
+	EXTLIBS += $(call libpath_template,$(ZLIB_PATH)/$(lib))
+endif
+EXTLIBS += -lz
+
+ifndef NO_OPENSSL
+	OPENSSL_LIBSSL = -lssl
+        ifdef OPENSSLDIR
+		BASIC_CFLAGS += -I$(OPENSSLDIR)/include
+		OPENSSL_LINK = $(call libpath_template,$(OPENSSLDIR)/$(lib))
+        else
+		OPENSSL_LINK =
+        endif
+        ifdef NEEDS_CRYPTO_WITH_SSL
+		OPENSSL_LIBSSL += -lcrypto
+        endif
+else
+	BASIC_CFLAGS += -DNO_OPENSSL
+	OPENSSL_LIBSSL =
+endif
+ifdef NO_OPENSSL
+	LIB_4_CRYPTO =
+else
+ifdef NEEDS_SSL_WITH_CRYPTO
+	LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto -lssl
+else
+	LIB_4_CRYPTO = $(OPENSSL_LINK) -lcrypto
+endif
+ifdef APPLE_COMMON_CRYPTO
+	LIB_4_CRYPTO += -framework Security -framework CoreFoundation
+endif
+endif
+ifndef NO_ICONV
+        ifdef NEEDS_LIBICONV
+                ifdef ICONVDIR
+			BASIC_CFLAGS += -I$(ICONVDIR)/include
+			ICONV_LINK = $(call libpath_template,$(ICONVDIR)/$(lib))
+                else
+			ICONV_LINK =
+                endif
+                ifdef NEEDS_LIBINTL_BEFORE_LIBICONV
+			ICONV_LINK += -lintl
+                endif
+		EXTLIBS += $(ICONV_LINK) -liconv
+        endif
+endif
+ifdef ICONV_OMITS_BOM
+	BASIC_CFLAGS += -DICONV_OMITS_BOM
+endif
+ifdef NEEDS_LIBGEN
+	EXTLIBS += -lgen
+endif
+ifndef NO_GETTEXT
+ifndef LIBC_CONTAINS_LIBINTL
+	EXTLIBS += -lintl
+endif
+endif
+ifdef NEEDS_SOCKET
+	EXTLIBS += -lsocket
+endif
+ifdef NEEDS_NSL
+	EXTLIBS += -lnsl
+endif
+ifdef NEEDS_RESOLV
+	EXTLIBS += -lresolv
+endif
+ifdef NO_D_TYPE_IN_DIRENT
+	BASIC_CFLAGS += -DNO_D_TYPE_IN_DIRENT
+endif
+ifdef NO_GECOS_IN_PWENT
+	BASIC_CFLAGS += -DNO_GECOS_IN_PWENT
+endif
+ifdef NO_ST_BLOCKS_IN_STRUCT_STAT
+	BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT
+endif
+ifdef USE_NSEC
+	BASIC_CFLAGS += -DUSE_NSEC
+endif
+ifdef USE_ST_TIMESPEC
+	BASIC_CFLAGS += -DUSE_ST_TIMESPEC
+endif
+ifdef NO_NORETURN
+	BASIC_CFLAGS += -DNO_NORETURN
+endif
+ifdef NO_NSEC
+	BASIC_CFLAGS += -DNO_NSEC
+endif
+ifdef SNPRINTF_RETURNS_BOGUS
+	COMPAT_CFLAGS += -DSNPRINTF_RETURNS_BOGUS
+	COMPAT_OBJS += compat/snprintf.o
+endif
+ifdef FREAD_READS_DIRECTORIES
+	COMPAT_CFLAGS += -DFREAD_READS_DIRECTORIES
+	COMPAT_OBJS += compat/fopen.o
+endif
+ifdef OPEN_RETURNS_EINTR
+	COMPAT_CFLAGS += -DOPEN_RETURNS_EINTR
+	COMPAT_OBJS += compat/open.o
+endif
+ifdef NO_SYMLINK_HEAD
+	BASIC_CFLAGS += -DNO_SYMLINK_HEAD
+endif
+ifdef NO_GETTEXT
+	BASIC_CFLAGS += -DNO_GETTEXT
+	USE_GETTEXT_SCHEME ?= fallthrough
+endif
+ifdef NO_POLL
+	NO_POLL_H = YesPlease
+	NO_SYS_POLL_H = YesPlease
+	COMPAT_CFLAGS += -DNO_POLL -Icompat/poll
+	COMPAT_OBJS += compat/poll/poll.o
+endif
+ifdef NO_STRCASESTR
+	COMPAT_CFLAGS += -DNO_STRCASESTR
+	COMPAT_OBJS += compat/strcasestr.o
+endif
+ifdef NO_STRLCPY
+	COMPAT_CFLAGS += -DNO_STRLCPY
+	COMPAT_OBJS += compat/strlcpy.o
+endif
+ifdef NO_STRTOUMAX
+	COMPAT_CFLAGS += -DNO_STRTOUMAX
+	COMPAT_OBJS += compat/strtoumax.o compat/strtoimax.o
+endif
+ifdef NO_STRTOULL
+	COMPAT_CFLAGS += -DNO_STRTOULL
+endif
+ifdef NO_SETENV
+	COMPAT_CFLAGS += -DNO_SETENV
+	COMPAT_OBJS += compat/setenv.o
+endif
+ifdef NO_MKDTEMP
+	COMPAT_CFLAGS += -DNO_MKDTEMP
+	COMPAT_OBJS += compat/mkdtemp.o
+endif
+ifdef MKDIR_WO_TRAILING_SLASH
+	COMPAT_CFLAGS += -DMKDIR_WO_TRAILING_SLASH
+	COMPAT_OBJS += compat/mkdir.o
+endif
+ifdef NO_UNSETENV
+	COMPAT_CFLAGS += -DNO_UNSETENV
+	COMPAT_OBJS += compat/unsetenv.o
+endif
+ifdef NO_SYS_SELECT_H
+	BASIC_CFLAGS += -DNO_SYS_SELECT_H
+endif
+ifdef NO_POLL_H
+	BASIC_CFLAGS += -DNO_POLL_H
+endif
+ifdef NO_SYS_POLL_H
+	BASIC_CFLAGS += -DNO_SYS_POLL_H
+endif
+ifdef NEEDS_SYS_PARAM_H
+	BASIC_CFLAGS += -DNEEDS_SYS_PARAM_H
+endif
+ifdef NO_INTTYPES_H
+	BASIC_CFLAGS += -DNO_INTTYPES_H
+endif
+ifdef NO_INITGROUPS
+	BASIC_CFLAGS += -DNO_INITGROUPS
+endif
+ifdef NO_MMAP
+	COMPAT_CFLAGS += -DNO_MMAP
+	COMPAT_OBJS += compat/mmap.o
+else
+        ifdef USE_WIN32_MMAP
+		COMPAT_CFLAGS += -DUSE_WIN32_MMAP
+		COMPAT_OBJS += compat/win32mmap.o
+        endif
+endif
+ifdef MMAP_PREVENTS_DELETE
+	BASIC_CFLAGS += -DMMAP_PREVENTS_DELETE
+endif
+ifdef OBJECT_CREATION_USES_RENAMES
+	COMPAT_CFLAGS += -DOBJECT_CREATION_MODE=1
+endif
+ifdef NO_STRUCT_ITIMERVAL
+	COMPAT_CFLAGS += -DNO_STRUCT_ITIMERVAL
+	NO_SETITIMER = YesPlease
+endif
+ifdef NO_SETITIMER
+	COMPAT_CFLAGS += -DNO_SETITIMER
+endif
+ifdef NO_PREAD
+	COMPAT_CFLAGS += -DNO_PREAD
+	COMPAT_OBJS += compat/pread.o
+endif
+ifdef NO_FAST_WORKING_DIRECTORY
+	BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY
+endif
+ifdef NO_TRUSTABLE_FILEMODE
+	BASIC_CFLAGS += -DNO_TRUSTABLE_FILEMODE
+endif
+ifdef NEEDS_MODE_TRANSLATION
+	COMPAT_CFLAGS += -DNEEDS_MODE_TRANSLATION
+	COMPAT_OBJS += compat/stat.o
+endif
+ifdef NO_IPV6
+	BASIC_CFLAGS += -DNO_IPV6
+endif
+ifdef NO_INTPTR_T
+	COMPAT_CFLAGS += -DNO_INTPTR_T
+endif
+ifdef NO_UINTMAX_T
+	BASIC_CFLAGS += -Duintmax_t=uint32_t
+endif
+ifdef NO_SOCKADDR_STORAGE
+ifdef NO_IPV6
+	BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in
+else
+	BASIC_CFLAGS += -Dsockaddr_storage=sockaddr_in6
+endif
+endif
+ifdef NO_INET_NTOP
+	LIB_OBJS += compat/inet_ntop.o
+	BASIC_CFLAGS += -DNO_INET_NTOP
+endif
+ifdef NO_INET_PTON
+	LIB_OBJS += compat/inet_pton.o
+	BASIC_CFLAGS += -DNO_INET_PTON
+endif
+ifdef NO_UNIX_SOCKETS
+	BASIC_CFLAGS += -DNO_UNIX_SOCKETS
+else
+	LIB_OBJS += unix-socket.o
+	LIB_OBJS += unix-stream-server.o
+endif
+
+# Simple IPC requires threads and platform-specific IPC support.
+# Only platforms that have both should include these source files
+# in the build.
+#
+# On Windows-based systems, Simple IPC requires threads and Windows
+# Named Pipes.  These are always available, so Simple IPC support
+# is optional.
+#
+# On Unix-based systems, Simple IPC requires pthreads and Unix
+# domain sockets.  So support is only enabled when both are present.
+#
+ifdef USE_WIN32_IPC
+	BASIC_CFLAGS += -DSUPPORTS_SIMPLE_IPC
+	LIB_OBJS += compat/simple-ipc/ipc-shared.o
+	LIB_OBJS += compat/simple-ipc/ipc-win32.o
+else
+ifndef NO_PTHREADS
+ifndef NO_UNIX_SOCKETS
+	BASIC_CFLAGS += -DSUPPORTS_SIMPLE_IPC
+	LIB_OBJS += compat/simple-ipc/ipc-shared.o
+	LIB_OBJS += compat/simple-ipc/ipc-unix-socket.o
+endif
+endif
+endif
+
+ifdef NO_ICONV
+	BASIC_CFLAGS += -DNO_ICONV
+endif
+
+ifdef OLD_ICONV
+	BASIC_CFLAGS += -DOLD_ICONV
+endif
+
+ifdef NO_DEFLATE_BOUND
+	BASIC_CFLAGS += -DNO_DEFLATE_BOUND
+endif
+
+ifdef NO_POSIX_GOODIES
+	BASIC_CFLAGS += -DNO_POSIX_GOODIES
+endif
+
+ifdef APPLE_COMMON_CRYPTO_SHA1
+	# Apple CommonCrypto requires chunking
+	SHA1_MAX_BLOCK_SIZE = 1024L*1024L*1024L
+endif
+
+ifdef PPC_SHA1
+$(error the PPC_SHA1 flag has been removed along with the PowerPC-specific SHA-1 implementation.)
+endif
+
+ifdef OPENSSL_SHA1
+	EXTLIBS += $(LIB_4_CRYPTO)
+	BASIC_CFLAGS += -DSHA1_OPENSSL
+else
+ifdef BLK_SHA1
+	LIB_OBJS += block-sha1/sha1.o
+	BASIC_CFLAGS += -DSHA1_BLK
+else
+ifdef APPLE_COMMON_CRYPTO_SHA1
+	COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
+	BASIC_CFLAGS += -DSHA1_APPLE
+else
+	BASIC_CFLAGS += -DSHA1_DC
+	LIB_OBJS += sha1dc_git.o
+ifdef DC_SHA1_EXTERNAL
+        ifdef DC_SHA1_SUBMODULE
+                ifneq ($(DC_SHA1_SUBMODULE),auto)
+$(error Only set DC_SHA1_EXTERNAL or DC_SHA1_SUBMODULE, not both)
+                endif
+        endif
+	BASIC_CFLAGS += -DDC_SHA1_EXTERNAL
+	EXTLIBS += -lsha1detectcoll
+else
+ifdef DC_SHA1_SUBMODULE
+	LIB_OBJS += sha1collisiondetection/lib/sha1.o
+	LIB_OBJS += sha1collisiondetection/lib/ubc_check.o
+	BASIC_CFLAGS += -DDC_SHA1_SUBMODULE
+else
+	LIB_OBJS += sha1dc/sha1.o
+	LIB_OBJS += sha1dc/ubc_check.o
+endif
+	BASIC_CFLAGS += \
+		-DSHA1DC_NO_STANDARD_INCLUDES \
+		-DSHA1DC_INIT_SAFE_HASH_DEFAULT=0 \
+		-DSHA1DC_CUSTOM_INCLUDE_SHA1_C="\"git-compat-util.h\"" \
+		-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C="\"git-compat-util.h\""
+endif
+endif
+endif
+endif
+
+ifdef OPENSSL_SHA1_UNSAFE
+ifndef OPENSSL_SHA1
+	EXTLIBS += $(LIB_4_CRYPTO)
+	BASIC_CFLAGS += -DSHA1_OPENSSL_UNSAFE
+endif
+else
+ifdef BLK_SHA1_UNSAFE
+ifndef BLK_SHA1
+	LIB_OBJS += block-sha1/sha1.o
+	BASIC_CFLAGS += -DSHA1_BLK_UNSAFE
+endif
+else
+ifdef APPLE_COMMON_CRYPTO_SHA1_UNSAFE
+ifndef APPLE_COMMON_CRYPTO_SHA1
+	COMPAT_CFLAGS += -DCOMMON_DIGEST_FOR_OPENSSL
+	BASIC_CFLAGS += -DSHA1_APPLE_UNSAFE
+endif
+endif
+endif
+endif
+
+ifdef OPENSSL_SHA256
+	EXTLIBS += $(LIB_4_CRYPTO)
+	BASIC_CFLAGS += -DSHA256_OPENSSL
+else
+ifdef NETTLE_SHA256
+	BASIC_CFLAGS += -DSHA256_NETTLE
+	EXTLIBS += -lnettle
+else
+ifdef GCRYPT_SHA256
+	BASIC_CFLAGS += -DSHA256_GCRYPT
+	EXTLIBS += -lgcrypt
+else
+	LIB_OBJS += sha256/block/sha256.o
+	BASIC_CFLAGS += -DSHA256_BLK
+endif
+endif
+endif
+
+ifdef SHA1_MAX_BLOCK_SIZE
+	LIB_OBJS += compat/sha1-chunked.o
+	BASIC_CFLAGS += -DSHA1_MAX_BLOCK_SIZE="$(SHA1_MAX_BLOCK_SIZE)"
+endif
+ifdef NO_HSTRERROR
+	COMPAT_CFLAGS += -DNO_HSTRERROR
+	COMPAT_OBJS += compat/hstrerror.o
+endif
+ifdef NO_MEMMEM
+	COMPAT_CFLAGS += -DNO_MEMMEM
+	COMPAT_OBJS += compat/memmem.o
+endif
+ifdef NO_GETPAGESIZE
+	COMPAT_CFLAGS += -DNO_GETPAGESIZE
+endif
+ifdef INTERNAL_QSORT
+	COMPAT_CFLAGS += -DINTERNAL_QSORT
+endif
+ifdef HAVE_ISO_QSORT_S
+	COMPAT_CFLAGS += -DHAVE_ISO_QSORT_S
+else
+	COMPAT_OBJS += compat/qsort_s.o
+endif
+ifdef RUNTIME_PREFIX
+	COMPAT_CFLAGS += -DRUNTIME_PREFIX
+endif
+
+ifdef NO_PTHREADS
+	BASIC_CFLAGS += -DNO_PTHREADS
+else
+	BASIC_CFLAGS += $(PTHREAD_CFLAGS)
+	EXTLIBS += $(PTHREAD_LIBS)
+endif
+
+ifdef HAVE_PATHS_H
+	BASIC_CFLAGS += -DHAVE_PATHS_H
+endif
+
+ifdef HAVE_LIBCHARSET_H
+	BASIC_CFLAGS += -DHAVE_LIBCHARSET_H
+	EXTLIBS += $(CHARSET_LIB)
+endif
+
+ifdef HAVE_STRINGS_H
+	BASIC_CFLAGS += -DHAVE_STRINGS_H
+endif
+
+ifdef HAVE_DEV_TTY
+	BASIC_CFLAGS += -DHAVE_DEV_TTY
+endif
+
+ifdef DIR_HAS_BSD_GROUP_SEMANTICS
+	COMPAT_CFLAGS += -DDIR_HAS_BSD_GROUP_SEMANTICS
+endif
+ifdef UNRELIABLE_FSTAT
+	BASIC_CFLAGS += -DUNRELIABLE_FSTAT
+endif
+ifdef NO_REGEX
+	COMPAT_CFLAGS += -Icompat/regex
+	COMPAT_OBJS += compat/regex/regex.o
+else
+ifdef USE_ENHANCED_BASIC_REGULAR_EXPRESSIONS
+	COMPAT_CFLAGS += -DUSE_ENHANCED_BASIC_REGULAR_EXPRESSIONS
+	COMPAT_OBJS += compat/regcomp_enhanced.o
+endif
+endif
+ifdef NATIVE_CRLF
+	BASIC_CFLAGS += -DNATIVE_CRLF
+endif
+
+ifdef USE_NED_ALLOCATOR
+	COMPAT_CFLAGS += -Icompat/nedmalloc
+	COMPAT_OBJS += compat/nedmalloc/nedmalloc.o
+	OVERRIDE_STRDUP = YesPlease
+endif
+
+ifdef OVERRIDE_STRDUP
+	COMPAT_CFLAGS += -DOVERRIDE_STRDUP
+	COMPAT_OBJS += compat/strdup.o
+endif
+
+ifdef GIT_TEST_CMP_USE_COPIED_CONTEXT
+	export GIT_TEST_CMP_USE_COPIED_CONTEXT
+endif
+
+ifndef NO_MSGFMT_EXTENDED_OPTIONS
+	MSGFMT += --check
+endif
+
+ifdef HAVE_CLOCK_GETTIME
+	BASIC_CFLAGS += -DHAVE_CLOCK_GETTIME
+endif
+
+ifdef HAVE_CLOCK_MONOTONIC
+	BASIC_CFLAGS += -DHAVE_CLOCK_MONOTONIC
+endif
+
+ifdef HAVE_SYNC_FILE_RANGE
+	BASIC_CFLAGS += -DHAVE_SYNC_FILE_RANGE
+endif
+
+ifdef NEEDS_LIBRT
+	EXTLIBS += -lrt
+endif
+
+ifdef HAVE_BSD_SYSCTL
+	BASIC_CFLAGS += -DHAVE_BSD_SYSCTL
+endif
+
+ifdef HAVE_BSD_KERN_PROC_SYSCTL
+	BASIC_CFLAGS += -DHAVE_BSD_KERN_PROC_SYSCTL
+endif
+
+ifdef HAVE_GETDELIM
+	BASIC_CFLAGS += -DHAVE_GETDELIM
+endif
+
+ifneq ($(findstring arc4random,$(CSPRNG_METHOD)),)
+	BASIC_CFLAGS += -DHAVE_ARC4RANDOM
+endif
+
+ifneq ($(findstring libbsd,$(CSPRNG_METHOD)),)
+	BASIC_CFLAGS += -DHAVE_ARC4RANDOM_LIBBSD
+	EXTLIBS += -lbsd
+endif
+
+ifneq ($(findstring getrandom,$(CSPRNG_METHOD)),)
+	BASIC_CFLAGS += -DHAVE_GETRANDOM
+endif
+
+ifneq ($(findstring getentropy,$(CSPRNG_METHOD)),)
+	BASIC_CFLAGS += -DHAVE_GETENTROPY
+endif
+
+ifneq ($(findstring rtlgenrandom,$(CSPRNG_METHOD)),)
+	BASIC_CFLAGS += -DHAVE_RTLGENRANDOM
+endif
+
+ifneq ($(findstring openssl,$(CSPRNG_METHOD)),)
+	BASIC_CFLAGS += -DHAVE_OPENSSL_CSPRNG
+	EXTLIBS += -lcrypto -lssl
+endif
+
+ifneq ($(PROCFS_EXECUTABLE_PATH),)
+	procfs_executable_path_SQ = $(subst ','\'',$(PROCFS_EXECUTABLE_PATH))
+	BASIC_CFLAGS += '-DPROCFS_EXECUTABLE_PATH="$(procfs_executable_path_SQ)"'
+endif
+
+ifndef HAVE_PLATFORM_PROCINFO
+	COMPAT_OBJS += compat/stub/procinfo.o
+endif
+
+ifdef HAVE_NS_GET_EXECUTABLE_PATH
+	BASIC_CFLAGS += -DHAVE_NS_GET_EXECUTABLE_PATH
+endif
+
+ifdef HAVE_ZOS_GET_EXECUTABLE_PATH
+        BASIC_CFLAGS += -DHAVE_ZOS_GET_EXECUTABLE_PATH
+endif
+
+ifdef HAVE_WPGMPTR
+	BASIC_CFLAGS += -DHAVE_WPGMPTR
+endif
+
+ifdef FILENO_IS_A_MACRO
+	COMPAT_CFLAGS += -DFILENO_IS_A_MACRO
+	COMPAT_OBJS += compat/fileno.o
+endif
+
+ifdef NEED_ACCESS_ROOT_HANDLER
+	COMPAT_CFLAGS += -DNEED_ACCESS_ROOT_HANDLER
+	COMPAT_OBJS += compat/access.o
+endif
+
+ifdef FSMONITOR_DAEMON_BACKEND
+	COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND
+	COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o
+	COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o
+	COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o
+endif
+
+ifdef FSMONITOR_OS_SETTINGS
+	COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS
+	COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o
+	COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o
+endif
+
+ifeq ($(TCLTK_PATH),)
+NO_TCLTK = NoThanks
+endif
+
+ifeq ($(PERL_PATH),)
+NO_PERL = NoThanks
+endif
+
+ifeq ($(PYTHON_PATH),)
+NO_PYTHON = NoThanks
+endif
+
+ifndef PAGER_ENV
+PAGER_ENV = LESS=FRX LV=-c
+endif
+
+ifdef NO_INSTALL_HARDLINKS
+	export NO_INSTALL_HARDLINKS
+endif
+
+### profile feedback build
+#
+
+# Can adjust this to be a global directory if you want to do extended
+# data gathering
+PROFILE_DIR := $(CURDIR)
+
+ifeq ("$(PROFILE)","GEN")
+	BASIC_CFLAGS += -fprofile-generate=$(PROFILE_DIR) -DNO_NORETURN=1
+	EXTLIBS += -lgcov
+	export CCACHE_DISABLE = t
+	V = 1
+else
+ifneq ("$(PROFILE)","")
+	BASIC_CFLAGS += -fprofile-use=$(PROFILE_DIR) -fprofile-correction -DNO_NORETURN=1
+	export CCACHE_DISABLE = t
+	V = 1
+endif
+endif
+
+# Shell quote (do not use $(call) to accommodate ancient setups);
+
+ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG))
+ETC_GITATTRIBUTES_SQ = $(subst ','\'',$(ETC_GITATTRIBUTES))
+
+DESTDIR_SQ = $(subst ','\'',$(DESTDIR))
+NO_GETTEXT_SQ = $(subst ','\'',$(NO_GETTEXT))
+bindir_SQ = $(subst ','\'',$(bindir))
+bindir_relative_SQ = $(subst ','\'',$(bindir_relative))
+mandir_SQ = $(subst ','\'',$(mandir))
+mandir_relative_SQ = $(subst ','\'',$(mandir_relative))
+infodir_relative_SQ = $(subst ','\'',$(infodir_relative))
+perllibdir_SQ = $(subst ','\'',$(perllibdir))
+localedir_SQ = $(subst ','\'',$(localedir))
+localedir_relative_SQ = $(subst ','\'',$(localedir_relative))
+gitexecdir_SQ = $(subst ','\'',$(gitexecdir))
+gitexecdir_relative_SQ = $(subst ','\'',$(gitexecdir_relative))
+template_dir_SQ = $(subst ','\'',$(template_dir))
+htmldir_relative_SQ = $(subst ','\'',$(htmldir_relative))
+prefix_SQ = $(subst ','\'',$(prefix))
+perllibdir_relative_SQ = $(subst ','\'',$(perllibdir_relative))
+gitwebdir_SQ = $(subst ','\'',$(gitwebdir))
+gitwebstaticdir_SQ = $(subst ','\'',$(gitwebstaticdir))
+
+SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+TEST_SHELL_PATH_SQ = $(subst ','\'',$(TEST_SHELL_PATH))
+PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH))
+PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH))
+TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_PATH))
+DIFF_SQ = $(subst ','\'',$(DIFF))
+PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
+
+# RUNTIME_PREFIX's resolution logic requires resource paths to be expressed
+# relative to each other and share an installation path.
+#
+# This is a dependency in:
+# - Git's binary RUNTIME_PREFIX logic in (see "exec_cmd.c").
+# - The runtime prefix Perl header (see
+#   "perl/header_templates/runtime_prefix.template.pl").
+ifdef RUNTIME_PREFIX
+
+ifneq ($(filter /%,$(firstword $(gitexecdir_relative))),)
+$(error RUNTIME_PREFIX requires a relative gitexecdir, not: $(gitexecdir))
+endif
+
+ifneq ($(filter /%,$(firstword $(localedir_relative))),)
+$(error RUNTIME_PREFIX requires a relative localedir, not: $(localedir))
+endif
+
+ifndef NO_PERL
+ifneq ($(filter /%,$(firstword $(perllibdir_relative))),)
+$(error RUNTIME_PREFIX requires a relative perllibdir, not: $(perllibdir))
+endif
+endif
+
+endif
+
+# We must filter out any object files from $(GITLIBS),
+# as it is typically used like:
+#
+#   foo: foo.o $(GITLIBS)
+#	$(CC) $(filter %.o,$^) $(LIBS)
+#
+# where we use it as a dependency. Since we also pull object files
+# from the dependency list, that would make each entry appear twice.
+LIBS = $(filter-out %.o, $(GITLIBS)) $(EXTLIBS)
+
+BASIC_CFLAGS += $(COMPAT_CFLAGS)
+LIB_OBJS += $(COMPAT_OBJS)
+
+# Quote for C
+
+ifdef DEFAULT_EDITOR
+DEFAULT_EDITOR_CQ = "$(subst ",\",$(subst \,\\,$(DEFAULT_EDITOR)))"
+DEFAULT_EDITOR_CQ_SQ = $(subst ','\'',$(DEFAULT_EDITOR_CQ))
+
+BASIC_CFLAGS += -DDEFAULT_EDITOR='$(DEFAULT_EDITOR_CQ_SQ)'
+endif
+
+ifdef DEFAULT_PAGER
+DEFAULT_PAGER_CQ = "$(subst ",\",$(subst \,\\,$(DEFAULT_PAGER)))"
+DEFAULT_PAGER_CQ_SQ = $(subst ','\'',$(DEFAULT_PAGER_CQ))
+
+BASIC_CFLAGS += -DDEFAULT_PAGER='$(DEFAULT_PAGER_CQ_SQ)'
+endif
+
+ifdef SHELL_PATH
+SHELL_PATH_CQ = "$(subst ",\",$(subst \,\\,$(SHELL_PATH)))"
+SHELL_PATH_CQ_SQ = $(subst ','\'',$(SHELL_PATH_CQ))
+
+BASIC_CFLAGS += -DSHELL_PATH='$(SHELL_PATH_CQ_SQ)'
+endif
+
+GIT_USER_AGENT_SQ = $(subst ','\'',$(GIT_USER_AGENT))
+GIT_USER_AGENT_CQ = "$(subst ",\",$(subst \,\\,$(GIT_USER_AGENT)))"
+GIT_USER_AGENT_CQ_SQ = $(subst ','\'',$(GIT_USER_AGENT_CQ))
+GIT-USER-AGENT: FORCE
+	@if test x'$(GIT_USER_AGENT_SQ)' != x"`cat GIT-USER-AGENT 2>/dev/null`"; then \
+		echo '$(GIT_USER_AGENT_SQ)' >GIT-USER-AGENT; \
+	fi
+
+ifdef DEFAULT_HELP_FORMAT
+BASIC_CFLAGS += -DDEFAULT_HELP_FORMAT='"$(DEFAULT_HELP_FORMAT)"'
+endif
+
+ALL_CFLAGS += $(BASIC_CFLAGS)
+ALL_LDFLAGS += $(BASIC_LDFLAGS)
+
+export DIFF TAR INSTALL DESTDIR SHELL_PATH
+
+
+### Build rules
+
+SHELL = $(SHELL_PATH)
+
+all:: shell_compatibility_test
+
+ifeq "$(PROFILE)" "BUILD"
+all:: profile
+endif
+
+profile:: profile-clean
+	$(MAKE) PROFILE=GEN all
+	$(MAKE) PROFILE=GEN -j1 test
+	@if test -n "$$GIT_PERF_REPO" || test -d .git; then \
+		$(MAKE) PROFILE=GEN -j1 perf; \
+	else \
+		echo "Skipping profile of perf tests..."; \
+	fi
+	$(MAKE) PROFILE=USE all
+
+profile-fast: profile-clean
+	$(MAKE) PROFILE=GEN all
+	$(MAKE) PROFILE=GEN -j1 perf
+	$(MAKE) PROFILE=USE all
+
+
+all:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) GIT-BUILD-OPTIONS
+ifneq (,$X)
+	$(QUIET_BUILT_IN)$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) $(OTHER_PROGRAMS))), if test ! -d '$p' && test ! '$p' -ef '$p$X'; then $(RM) '$p'; fi;)
+endif
+
+all::
+ifndef NO_TCLTK
+	$(QUIET_SUBDIR0)git-gui $(QUIET_SUBDIR1) gitexecdir='$(gitexec_instdir_SQ)' all
+	$(QUIET_SUBDIR0)gitk-git $(QUIET_SUBDIR1) all
+endif
+	$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
+
+# If you add a new fuzzer, please also make sure to run it in
+# ci/run-build-and-minimal-fuzzers.sh so that we make sure it still links and
+# runs in the future.
+FUZZ_OBJS += oss-fuzz/dummy-cmd-main.o
+FUZZ_OBJS += oss-fuzz/fuzz-commit-graph.o
+FUZZ_OBJS += oss-fuzz/fuzz-config.o
+FUZZ_OBJS += oss-fuzz/fuzz-credential-from-url-gently.o
+FUZZ_OBJS += oss-fuzz/fuzz-date.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-headers.o
+FUZZ_OBJS += oss-fuzz/fuzz-pack-idx.o
+FUZZ_OBJS += oss-fuzz/fuzz-parse-attr-line.o
+FUZZ_OBJS += oss-fuzz/fuzz-url-decode-mem.o
+.PHONY: fuzz-objs
+fuzz-objs: $(FUZZ_OBJS)
+
+# Always build fuzz objects even if not testing, to prevent bit-rot.
+all:: $(FUZZ_OBJS)
+
+FUZZ_PROGRAMS += $(patsubst %.o,%,$(filter-out %dummy-cmd-main.o,$(FUZZ_OBJS)))
+
+# Build fuzz programs when possible, even without the necessary fuzzing support,
+# to prevent bit-rot.
+ifdef LINK_FUZZ_PROGRAMS
+all:: $(FUZZ_PROGRAMS)
+endif
+
+please_set_SHELL_PATH_to_a_more_modern_shell:
+	@$$(:)
+
+shell_compatibility_test: please_set_SHELL_PATH_to_a_more_modern_shell
+
+strip: $(PROGRAMS) git$X
+	$(STRIP) $(STRIP_OPTS) $^
+
+### Target-specific flags and dependencies
+
+# The generic compilation pattern rule and automatically
+# computed header dependencies (falling back to a dependency on
+# LIB_H) are enough to describe how most targets should be built,
+# but some targets are special enough to need something a little
+# different.
+#
+# - When a source file "foo.c" #includes a generated header file,
+#   we need to list that dependency for the "foo.o" target.
+#
+#   We also list it from other targets that are built from foo.c
+#   like "foo.sp" and "foo.s", even though that is easy to forget
+#   to do because the generated header is already present around
+#   after a regular build attempt.
+#
+# - Some code depends on configuration kept in makefile
+#   variables. The target-specific variable EXTRA_CPPFLAGS can
+#   be used to convey that information to the C preprocessor
+#   using -D options.
+#
+#   The "foo.o" target should have a corresponding dependency on
+#   a file that changes when the value of the makefile variable
+#   changes.  For example, targets making use of the
+#   $(GIT_VERSION) variable depend on GIT-VERSION-FILE.
+#
+#   Technically the ".sp" and ".s" targets do not need this
+#   dependency because they are force-built, but they get the
+#   same dependency for consistency. This way, you do not have to
+#   know how each target is implemented. And it means the
+#   dependencies here will not need to change if the force-build
+#   details change some day.
+
+git.sp git.s git.o: GIT-PREFIX
+git.sp git.s git.o: EXTRA_CPPFLAGS = \
+	'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
+	'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
+	'-DGIT_INFO_PATH="$(infodir_relative_SQ)"'
+
+git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
+		$(filter %.o,$^) $(LIBS)
+
+help.sp help.s help.o: command-list.h
+builtin/bugreport.sp builtin/bugreport.s builtin/bugreport.o: hook-list.h
+
+builtin/help.sp builtin/help.s builtin/help.o: config-list.h GIT-PREFIX
+builtin/help.sp builtin/help.s builtin/help.o: EXTRA_CPPFLAGS = \
+	'-DGIT_HTML_PATH="$(htmldir_relative_SQ)"' \
+	'-DGIT_MAN_PATH="$(mandir_relative_SQ)"' \
+	'-DGIT_INFO_PATH="$(infodir_relative_SQ)"'
+
+PAGER_ENV_SQ = $(subst ','\'',$(PAGER_ENV))
+PAGER_ENV_CQ = "$(subst ",\",$(subst \,\\,$(PAGER_ENV)))"
+PAGER_ENV_CQ_SQ = $(subst ','\'',$(PAGER_ENV_CQ))
+pager.sp pager.s pager.o: EXTRA_CPPFLAGS = \
+	-DPAGER_ENV='$(PAGER_ENV_CQ_SQ)'
+
+version-def.h: version-def.h.in GIT-VERSION-GEN GIT-VERSION-FILE GIT-USER-AGENT
+	$(QUIET_GEN)$(call version_gen,"$(shell pwd)",$<,$@)
+
+version.sp version.s version.o: version-def.h
+
+$(BUILT_INS): git$X
+	$(QUIET_BUILT_IN)$(RM) $@ && \
+	ln $< $@ 2>/dev/null || \
+	ln -s $< $@ 2>/dev/null || \
+	cp $< $@
+
+config-list.h: generate-configlist.sh
+
+config-list.h: Documentation/*config.txt Documentation/config/*.txt
+	$(QUIET_GEN)$(SHELL_PATH) ./generate-configlist.sh . $@
+
+command-list.h: generate-cmdlist.sh command-list.txt
+
+command-list.h: $(wildcard Documentation/git*.txt)
+	$(QUIET_GEN)$(SHELL_PATH) ./generate-cmdlist.sh \
+		$(patsubst %,--exclude-program %,$(EXCLUDED_PROGRAMS)) \
+		. $@
+
+hook-list.h: generate-hooklist.sh Documentation/githooks.txt
+	$(QUIET_GEN)$(SHELL_PATH) ./generate-hooklist.sh . $@
+
+SCRIPT_DEFINES = $(SHELL_PATH_SQ):$(DIFF_SQ):\
+	$(localedir_SQ):$(USE_GETTEXT_SCHEME):$(SANE_TOOL_PATH_SQ):\
+	$(gitwebdir_SQ):$(PERL_PATH_SQ):$(PAGER_ENV):\
+	$(perllibdir_SQ)
+GIT-SCRIPT-DEFINES: FORCE
+	@FLAGS='$(SCRIPT_DEFINES)'; \
+	    if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
+		echo >&2 "    * new script parameters"; \
+		echo "$$FLAGS" >$@; \
+            fi
+
+$(SCRIPT_SH_GEN) $(SCRIPT_LIB) : % : %.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES
+	$(QUIET_GEN)./generate-script.sh "$<" "$@+" ./GIT-BUILD-OPTIONS && \
+	mv $@+ $@
+
+git.rc: git.rc.in GIT-VERSION-GEN GIT-VERSION-FILE
+	$(QUIET_GEN)$(call version_gen,"$(shell pwd)",$<,$@)
+
+git.res: git.rc GIT-PREFIX
+	$(QUIET_RC)$(RC) -i $< -o $@
+
+# This makes sure we depend on the NO_PERL setting itself.
+$(SCRIPT_PERL_GEN): GIT-BUILD-OPTIONS
+
+# Used for substitution in Perl modules. Disabled when using RUNTIME_PREFIX
+# since the locale directory is injected.
+perl_localedir_SQ = $(localedir_SQ)
+
+ifndef NO_PERL
+PERL_HEADER_TEMPLATE = perl/header_templates/fixed_prefix.template.pl
+PERL_DEFINES =
+PERL_DEFINES += $(PERL_PATH_SQ)
+PERL_DEFINES += $(PERLLIB_EXTRA_SQ)
+PERL_DEFINES += $(perllibdir_SQ)
+PERL_DEFINES += $(RUNTIME_PREFIX)
+PERL_DEFINES += $(NO_PERL_CPAN_FALLBACKS)
+PERL_DEFINES += $(NO_GETTEXT)
+
+# Support Perl runtime prefix. In this mode, a different header is installed
+# into Perl scripts.
+ifdef RUNTIME_PREFIX
+
+PERL_HEADER_TEMPLATE = perl/header_templates/runtime_prefix.template.pl
+
+# Don't export a fixed $(localedir) path; it will be resolved by the Perl header
+# at runtime.
+perl_localedir_SQ =
+
+endif
+
+PERL_DEFINES += $(gitexecdir) $(perllibdir) $(localedir)
+
+$(SCRIPT_PERL_GEN): % : %.perl generate-perl.sh GIT-PERL-DEFINES GIT-PERL-HEADER GIT-VERSION-FILE
+	$(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER "$<" "$@+" && \
+	mv $@+ $@
+
+PERL_DEFINES := $(subst $(space),:,$(PERL_DEFINES))
+GIT-PERL-DEFINES: FORCE
+	@FLAGS='$(PERL_DEFINES)'; \
+	    if test x"$$FLAGS" != x"`cat $@ 2>/dev/null`" ; then \
+		echo >&2 "    * new perl-specific parameters"; \
+		echo "$$FLAGS" >$@; \
+	    fi
+
+GIT-PERL-HEADER: $(PERL_HEADER_TEMPLATE) GIT-PERL-DEFINES Makefile
+	$(QUIET_GEN) \
+	INSTLIBDIR='$(perllibdir_SQ)' && \
+	INSTLIBDIR_EXTRA='$(PERLLIB_EXTRA_SQ)' && \
+	INSTLIBDIR="$$INSTLIBDIR$${INSTLIBDIR_EXTRA:+:$$INSTLIBDIR_EXTRA}" && \
+	sed -e 's=@PATHSEP@=$(pathsep)=g' \
+	    -e "s=@INSTLIBDIR@=$$INSTLIBDIR=g" \
+	    -e 's=@PERLLIBDIR_REL@=$(perllibdir_relative_SQ)=g' \
+	    -e 's=@GITEXECDIR_REL@=$(gitexecdir_relative_SQ)=g' \
+	    -e 's=@LOCALEDIR_REL@=$(localedir_relative_SQ)=g' \
+	    $< >$@+ && \
+	mv $@+ $@
+
+.PHONY: perllibdir
+perllibdir:
+	@echo '$(perllibdir_SQ)'
+
+git-instaweb: git-instaweb.sh generate-script.sh GIT-BUILD-OPTIONS GIT-SCRIPT-DEFINES
+	$(QUIET_GEN)./generate-script.sh "$<" "$@+" ./GIT-BUILD-OPTIONS && \
+	chmod +x $@+ && \
+	mv $@+ $@
+else # NO_PERL
+$(SCRIPT_PERL_GEN) git-instaweb: % : unimplemented.sh
+	$(QUIET_GEN) \
+	sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+	    -e 's|@REASON@|NO_PERL=$(NO_PERL)|g' \
+	    unimplemented.sh >$@+ && \
+	chmod +x $@+ && \
+	mv $@+ $@
+endif # NO_PERL
+
+# This makes sure we depend on the NO_PYTHON setting itself.
+$(SCRIPT_PYTHON_GEN): GIT-BUILD-OPTIONS
+
+ifndef NO_PYTHON
+$(SCRIPT_PYTHON_GEN): generate-python.sh
+$(SCRIPT_PYTHON_GEN): % : %.py
+	$(QUIET_GEN)$(SHELL_PATH) generate-python.sh ./GIT-BUILD-OPTIONS "$<" "$@"
+else # NO_PYTHON
+$(SCRIPT_PYTHON_GEN): % : unimplemented.sh
+	$(QUIET_GEN) \
+	sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+	    -e 's|@REASON@|NO_PYTHON=$(NO_PYTHON)|g' \
+	    unimplemented.sh >$@+ && \
+	chmod +x $@+ && \
+	mv $@+ $@
+endif # NO_PYTHON
+
+CONFIGURE_RECIPE = sed -e 's/@GIT_VERSION@/$(GIT_VERSION)/g' \
+			configure.ac >configure.ac+ && \
+		   autoconf -o configure configure.ac+ && \
+		   $(RM) configure.ac+
+
+configure: configure.ac GIT-VERSION-FILE
+	$(QUIET_GEN)$(CONFIGURE_RECIPE)
+
+ifdef AUTOCONFIGURED
+# We avoid depending on 'configure' here, because it gets rebuilt
+# every time GIT-VERSION-FILE is modified, only to update the embedded
+# version number string, which config.status does not care about.  We
+# do want to recheck when the platform/environment detection logic
+# changes, hence this depends on configure.ac.
+config.status: configure.ac
+	$(QUIET_GEN)$(CONFIGURE_RECIPE) && \
+	if test -f config.status; then \
+	  ./config.status --recheck; \
+	else \
+	  ./configure; \
+	fi
+reconfigure config.mak.autogen: config.status
+	$(QUIET_GEN)./config.status
+.PHONY: reconfigure # This is a convenience target.
+endif
+
+XDIFF_OBJS += xdiff/xdiffi.o
+XDIFF_OBJS += xdiff/xemit.o
+XDIFF_OBJS += xdiff/xhistogram.o
+XDIFF_OBJS += xdiff/xmerge.o
+XDIFF_OBJS += xdiff/xpatience.o
+XDIFF_OBJS += xdiff/xprepare.o
+XDIFF_OBJS += xdiff/xutils.o
+.PHONY: xdiff-objs
+xdiff-objs: $(XDIFF_OBJS)
+
+REFTABLE_OBJS += reftable/basics.o
+REFTABLE_OBJS += reftable/error.o
+REFTABLE_OBJS += reftable/block.o
+REFTABLE_OBJS += reftable/blocksource.o
+REFTABLE_OBJS += reftable/iter.o
+REFTABLE_OBJS += reftable/merged.o
+REFTABLE_OBJS += reftable/pq.o
+REFTABLE_OBJS += reftable/reader.o
+REFTABLE_OBJS += reftable/record.o
+REFTABLE_OBJS += reftable/stack.o
+REFTABLE_OBJS += reftable/system.o
+REFTABLE_OBJS += reftable/tree.o
+REFTABLE_OBJS += reftable/writer.o
+
+TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS)) $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS))
+
+.PHONY: test-objs
+test-objs: $(TEST_OBJS)
+
+GIT_OBJS += $(LIB_OBJS)
+GIT_OBJS += $(BUILTIN_OBJS)
+GIT_OBJS += common-main.o
+GIT_OBJS += git.o
+.PHONY: git-objs
+git-objs: $(GIT_OBJS)
+
+SCALAR_OBJS += scalar.o
+.PHONY: scalar-objs
+scalar-objs: $(SCALAR_OBJS)
+
+OBJECTS += $(GIT_OBJS)
+OBJECTS += $(SCALAR_OBJS)
+OBJECTS += $(PROGRAM_OBJS)
+OBJECTS += $(TEST_OBJS)
+OBJECTS += $(XDIFF_OBJS)
+OBJECTS += $(FUZZ_OBJS)
+OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
+OBJECTS += $(UNIT_TEST_OBJS)
+OBJECTS += $(CLAR_TEST_OBJS)
+OBJECTS += $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TEST_PROGRAMS))
+
+ifndef NO_CURL
+	OBJECTS += http.o http-walker.o remote-curl.o
+endif
+
+.PHONY: objects
+objects: $(OBJECTS)
+
+dep_files := $(foreach f,$(OBJECTS),$(dir $f).depend/$(notdir $f).d)
+dep_dirs := $(addsuffix .depend,$(sort $(dir $(OBJECTS))))
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
+$(dep_dirs):
+	@mkdir -p $@
+
+missing_dep_dirs := $(filter-out $(wildcard $(dep_dirs)),$(dep_dirs))
+dep_file = $(dir $@).depend/$(notdir $@).d
+dep_args = -MF $(dep_file) -MQ $@ -MMD -MP
+endif
+
+ifneq ($(COMPUTE_HEADER_DEPENDENCIES),yes)
+missing_dep_dirs =
+dep_args =
+endif
+
+compdb_dir = compile_commands
+
+ifeq ($(GENERATE_COMPILATION_DATABASE),yes)
+missing_compdb_dir = $(compdb_dir)
+$(missing_compdb_dir):
+	@mkdir -p $@
+
+compdb_file = $(compdb_dir)/$(subst /,-,$@.json)
+compdb_args = -MJ $(compdb_file)
+else
+missing_compdb_dir =
+compdb_args =
+endif
+
+$(OBJECTS): %.o: %.c GIT-CFLAGS $(missing_dep_dirs) $(missing_compdb_dir)
+	$(QUIET_CC)$(CC) -o $*.o -c $(dep_args) $(compdb_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+
+%.s: %.c GIT-CFLAGS FORCE
+	$(QUIET_CC)$(CC) -o $@ -S $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $<
+
+ifdef USE_COMPUTED_HEADER_DEPENDENCIES
+# Take advantage of gcc's on-the-fly dependency generation
+# See <https://gcc.gnu.org/gcc-3.0/features.html>.
+dep_files_present := $(wildcard $(dep_files))
+ifneq ($(dep_files_present),)
+include $(dep_files_present)
+endif
+else
+$(OBJECTS): $(LIB_H) $(GENERATED_H)
+endif
+
+ifeq ($(GENERATE_COMPILATION_DATABASE),yes)
+all:: compile_commands.json
+compile_commands.json:
+	$(QUIET_GEN)sed -e '1s/^/[/' -e '$$s/,$$/]/' $(compdb_dir)/*.o.json > $@+
+	@if test -s $@+; then mv $@+ $@; else $(RM) $@+; fi
+endif
+
+exec-cmd.sp exec-cmd.s exec-cmd.o: GIT-PREFIX
+exec-cmd.sp exec-cmd.s exec-cmd.o: EXTRA_CPPFLAGS = \
+	'-DGIT_EXEC_PATH="$(gitexecdir_SQ)"' \
+	'-DGIT_LOCALE_PATH="$(localedir_relative_SQ)"' \
+	'-DBINDIR="$(bindir_relative_SQ)"' \
+	'-DFALLBACK_RUNTIME_PREFIX="$(prefix_SQ)"'
+
+setup.sp setup.s setup.o: GIT-PREFIX
+setup.sp setup.s setup.o: EXTRA_CPPFLAGS = \
+	-DDEFAULT_GIT_TEMPLATE_DIR='"$(template_dir_SQ)"'
+
+config.sp config.s config.o: GIT-PREFIX
+config.sp config.s config.o: EXTRA_CPPFLAGS = \
+	-DETC_GITCONFIG='"$(ETC_GITCONFIG_SQ)"'
+
+attr.sp attr.s attr.o: GIT-PREFIX
+attr.sp attr.s attr.o: EXTRA_CPPFLAGS = \
+	-DETC_GITATTRIBUTES='"$(ETC_GITATTRIBUTES_SQ)"'
+
+gettext.sp gettext.s gettext.o: GIT-PREFIX
+gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
+	-DGIT_LOCALE_PATH='"$(localedir_relative_SQ)"'
+
+http-push.sp http.sp http-walker.sp remote-curl.sp imap-send.sp: SP_EXTRA_FLAGS += \
+	-DCURL_DISABLE_TYPECHECK
+
+pack-revindex.sp: SP_EXTRA_FLAGS += -Wno-memcpy-max-count
+
+ifdef NO_EXPAT
+http-walker.sp http-walker.s http-walker.o: EXTRA_CPPFLAGS = -DNO_EXPAT
+endif
+
+ifdef NO_REGEX
+compat/regex/regex.sp compat/regex/regex.o: EXTRA_CPPFLAGS = \
+	-DGAWK -DNO_MBSUPPORT
+endif
+
+ifdef USE_NED_ALLOCATOR
+compat/nedmalloc/nedmalloc.sp compat/nedmalloc/nedmalloc.o: EXTRA_CPPFLAGS = \
+	-DNDEBUG -DREPLACE_SYSTEM_ALLOCATOR
+compat/nedmalloc/nedmalloc.sp: SP_EXTRA_FLAGS += -Wno-non-pointer-null
+endif
+
+headless-git.o: compat/win32/headless.c GIT-CFLAGS
+	$(QUIET_CC)$(CC) $(ALL_CFLAGS) $(COMPAT_CFLAGS) \
+		-fno-stack-protector -o $@ -c -Wall -Wwrite-strings $<
+
+headless-git$X: headless-git.o git.res GIT-LDFLAGS
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -mwindows -o $@ $< git.res
+
+git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+
+git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+		$(IMAP_SEND_LDFLAGS) $(LIBS)
+
+git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+		$(CURL_LIBCURL) $(LIBS)
+git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+		$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
+
+$(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
+	$(QUIET_LNCP)$(RM) $@ && \
+	ln $< $@ 2>/dev/null || \
+	ln -s $< $@ 2>/dev/null || \
+	cp $< $@
+
+$(REMOTE_CURL_PRIMARY): remote-curl.o http.o http-walker.o GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
+		$(CURL_LIBCURL) $(EXPAT_LIBEXPAT) $(LIBS)
+
+scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
+		$(filter %.o,$^) $(LIBS)
+
+$(LIB_FILE): $(LIB_OBJS)
+	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+
+$(XDIFF_LIB): $(XDIFF_OBJS)
+	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+
+$(REFTABLE_LIB): $(REFTABLE_OBJS)
+	$(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
+
+export DEFAULT_EDITOR DEFAULT_PAGER
+
+Documentation/GIT-EXCLUDED-PROGRAMS: FORCE
+	@EXCLUDED='EXCLUDED_PROGRAMS := $(EXCLUDED_PROGRAMS)'; \
+	    if test x"$$EXCLUDED" != \
+		x"`cat Documentation/GIT-EXCLUDED-PROGRAMS 2>/dev/null`" ; then \
+		echo >&2 "    * new documentation flags"; \
+		echo "$$EXCLUDED" >Documentation/GIT-EXCLUDED-PROGRAMS; \
+            fi
+
+.PHONY: doc man man-perl html info pdf
+doc: man-perl
+	$(MAKE) -C Documentation all
+
+man: man-perl
+	$(MAKE) -C Documentation man
+
+man-perl: perl/build/man/man3/Git.3pm
+
+html:
+	$(MAKE) -C Documentation html
+
+info:
+	$(MAKE) -C Documentation info
+
+pdf:
+	$(MAKE) -C Documentation pdf
+
+XGETTEXT_FLAGS = \
+	--force-po \
+	--add-comments=TRANSLATORS: \
+	--msgid-bugs-address="Git Mailing List <git@xxxxxxxxxxxxxxx>" \
+	--package-name=Git
+XGETTEXT_FLAGS_C = $(XGETTEXT_FLAGS) --language=C \
+	--keyword=_ --keyword=N_ --keyword="Q_:1,2"
+XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) --language=Shell \
+	--keyword=gettextln --keyword=eval_gettextln
+XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --language=Perl \
+	--keyword=__ --keyword=N__ --keyword="__n:1,2"
+MSGMERGE_FLAGS = --add-location --backup=off --update
+LOCALIZED_C = $(sort $(FOUND_C_SOURCES) $(FOUND_H_SOURCES) $(GENERATED_H))
+LOCALIZED_SH = $(sort $(SCRIPT_SH) git-sh-setup.sh)
+LOCALIZED_PERL = $(sort $(SCRIPT_PERL))
+
+ifdef XGETTEXT_INCLUDE_TESTS
+LOCALIZED_C += t/t0200/test.c
+LOCALIZED_SH += t/t0200/test.sh
+LOCALIZED_PERL += t/t0200/test.perl
+endif
+
+## We generate intermediate .build/pot/po/%.po files containing a
+## extract of the translations we find in each file in the source
+## tree. We will assemble them using msgcat to create the final
+## "po/git.pot" file.
+LOCALIZED_ALL_GEN_PO =
+
+LOCALIZED_C_GEN_PO = $(LOCALIZED_C:%=.build/pot/po/%.po)
+LOCALIZED_ALL_GEN_PO += $(LOCALIZED_C_GEN_PO)
+
+LOCALIZED_SH_GEN_PO = $(LOCALIZED_SH:%=.build/pot/po/%.po)
+LOCALIZED_ALL_GEN_PO += $(LOCALIZED_SH_GEN_PO)
+
+LOCALIZED_PERL_GEN_PO = $(LOCALIZED_PERL:%=.build/pot/po/%.po)
+LOCALIZED_ALL_GEN_PO += $(LOCALIZED_PERL_GEN_PO)
+
+## Gettext tools cannot work with our own custom PRItime type, so
+## we replace PRItime with PRIuMAX.  We need to update this to
+## PRIdMAX if we switch to a signed type later.
+$(LOCALIZED_C_GEN_PO): .build/pot/po/%.po: %
+	$(call mkdir_p_parent_template)
+	$(QUIET_XGETTEXT) \
+	    if grep -q PRItime $<; then \
+		(\
+			sed -e 's|PRItime|PRIuMAX|g' <$< \
+				>.build/pot/po/$< && \
+			cd .build/pot/po && \
+			$(XGETTEXT) --omit-header \
+				-o $(@:.build/pot/po/%=%) \
+				$(XGETTEXT_FLAGS_C) $< && \
+			rm $<; \
+		); \
+	    else \
+		$(XGETTEXT) --omit-header \
+			-o $@ $(XGETTEXT_FLAGS_C) $<; \
+	    fi
+
+$(LOCALIZED_SH_GEN_PO): .build/pot/po/%.po: %
+	$(call mkdir_p_parent_template)
+	$(QUIET_XGETTEXT)$(XGETTEXT) --omit-header \
+		-o$@ $(XGETTEXT_FLAGS_SH) $<
+
+$(LOCALIZED_PERL_GEN_PO): .build/pot/po/%.po: %
+	$(call mkdir_p_parent_template)
+	$(QUIET_XGETTEXT)$(XGETTEXT) --omit-header \
+		-o$@ $(XGETTEXT_FLAGS_PERL) $<
+
+define gen_pot_header
+$(XGETTEXT) $(XGETTEXT_FLAGS_C) \
+	-o - /dev/null | \
+sed -e 's|charset=CHARSET|charset=UTF-8|' \
+    -e 's|\(Last-Translator: \)FULL NAME <.*>|\1make by the Makefile|' \
+    -e 's|\(Language-Team: \)LANGUAGE <.*>|\1Git Mailing List <git@xxxxxxxxxxxxxxx>|' \
+    >$@ && \
+echo '"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\\n"' >>$@
+endef
+
+.build/pot/git.header: $(LOCALIZED_ALL_GEN_PO)
+	$(call mkdir_p_parent_template)
+	$(QUIET_GEN)$(gen_pot_header)
+
+po/git.pot: .build/pot/git.header $(LOCALIZED_ALL_GEN_PO)
+	$(QUIET_GEN)$(MSGCAT) $^ >$@
+
+.PHONY: pot
+pot: po/git.pot
+
+define check_po_file_envvar
+	$(if $(PO_FILE), \
+		$(if $(filter po/%.po,$(PO_FILE)), , \
+			$(error PO_FILE should match pattern: "po/%.po")), \
+		$(error PO_FILE is not defined))
+endef
+
+.PHONY: po-update
+po-update: po/git.pot
+	$(check_po_file_envvar)
+	@if test ! -e $(PO_FILE); then \
+		echo >&2 "error: $(PO_FILE) does not exist"; \
+		echo >&2 'To create an initial po file, use: "make po-init PO_FILE=po/XX.po"'; \
+		exit 1; \
+	fi
+	$(QUIET_MSGMERGE)$(MSGMERGE) $(MSGMERGE_FLAGS) $(PO_FILE) po/git.pot
+
+.PHONY: check-pot
+check-pot: $(LOCALIZED_ALL_GEN_PO)
+
+### TODO FIXME: Translating everything in these files is a bad
+### heuristic for "core", as we'll translate obscure error() messages
+### along with commonly seen i18n messages. A better heuristic would
+### be to e.g. use spatch to first remove error/die/warning
+### etc. messages.
+LOCALIZED_C_CORE =
+LOCALIZED_C_CORE += builtin/checkout.c
+LOCALIZED_C_CORE += builtin/clone.c
+LOCALIZED_C_CORE += builtin/index-pack.c
+LOCALIZED_C_CORE += builtin/push.c
+LOCALIZED_C_CORE += builtin/reset.c
+LOCALIZED_C_CORE += remote.c
+LOCALIZED_C_CORE += wt-status.c
+
+LOCALIZED_C_CORE_GEN_PO = $(LOCALIZED_C_CORE:%=.build/pot/po/%.po)
+
+.build/pot/git-core.header: $(LOCALIZED_C_CORE_GEN_PO)
+	$(call mkdir_p_parent_template)
+	$(QUIET_GEN)$(gen_pot_header)
+
+po/git-core.pot: .build/pot/git-core.header $(LOCALIZED_C_CORE_GEN_PO)
+	$(QUIET_GEN)$(MSGCAT) $^ >$@
+
+.PHONY: po-init
+po-init: po/git-core.pot
+	$(check_po_file_envvar)
+	@if test -e $(PO_FILE); then \
+		echo >&2 "error: $(PO_FILE) exists already"; \
+		exit 1; \
+	fi
+	$(QUIET_MSGINIT)msginit \
+		--input=$< \
+		--output=$(PO_FILE) \
+		--no-translator \
+		--locale=$(PO_FILE:po/%.po=%)
+
+## po/*.po files & their rules
+ifdef NO_GETTEXT
+POFILES :=
+MOFILES :=
+else
+POFILES := $(wildcard po/*.po)
+MOFILES := $(patsubst po/%.po,po/build/locale/%/LC_MESSAGES/git.mo,$(POFILES))
+
+all:: $(MOFILES)
+endif
+
+po/build/locale/%/LC_MESSAGES/git.mo: po/%.po
+	$(call mkdir_p_parent_template)
+	$(QUIET_MSGFMT)$(MSGFMT) -o $@ $<
+
+LIB_PERL := $(wildcard perl/Git.pm perl/Git/*.pm perl/Git/*/*.pm perl/Git/*/*/*.pm)
+LIB_PERL_GEN := $(patsubst perl/%.pm,perl/build/lib/%.pm,$(LIB_PERL))
+LIB_CPAN := $(wildcard perl/FromCPAN/*.pm perl/FromCPAN/*/*.pm)
+LIB_CPAN_GEN := $(patsubst perl/%.pm,perl/build/lib/%.pm,$(LIB_CPAN))
+
+ifndef NO_PERL
+all:: $(LIB_PERL_GEN)
+ifndef NO_PERL_CPAN_FALLBACKS
+all:: $(LIB_CPAN_GEN)
+endif
+NO_PERL_CPAN_FALLBACKS_SQ = $(subst ','\'',$(NO_PERL_CPAN_FALLBACKS))
+endif
+
+perl/build/lib/%.pm: perl/%.pm generate-perl.sh GIT-BUILD-OPTIONS GIT-VERSION-FILE GIT-PERL-DEFINES
+	$(call mkdir_p_parent_template)
+	$(QUIET_GEN)$(SHELL_PATH) generate-perl.sh ./GIT-BUILD-OPTIONS ./GIT-VERSION-FILE GIT-PERL-HEADER "$<" "$@"
+
+perl/build/man/man3/Git.3pm: perl/Git.pm
+	$(call mkdir_p_parent_template)
+	$(QUIET_GEN)pod2man $< $@
+
+$(ETAGS_TARGET): $(FOUND_SOURCE_FILES)
+	$(QUIET_GEN)$(RM) $@+ && \
+	echo $(FOUND_SOURCE_FILES) | xargs etags -a -o $@+ && \
+	mv $@+ $@
+
+tags: $(FOUND_SOURCE_FILES)
+	$(QUIET_GEN)$(RM) $@+ && \
+	echo $(FOUND_SOURCE_FILES) | xargs ctags -a -o $@+ && \
+	mv $@+ $@
+
+cscope.out: $(FOUND_SOURCE_FILES)
+	$(QUIET_GEN)$(RM) $@+ && \
+	echo $(FOUND_SOURCE_FILES) | xargs cscope -f$@+ -b && \
+	mv $@+ $@
+
+.PHONY: cscope
+cscope: cscope.out
+
+### Detect prefix changes
+TRACK_PREFIX = $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ):\
+		$(localedir_SQ)
+
+GIT-PREFIX: FORCE
+	@FLAGS='$(TRACK_PREFIX)'; \
+	if test x"$$FLAGS" != x"`cat GIT-PREFIX 2>/dev/null`" ; then \
+		echo >&2 "    * new prefix flags"; \
+		echo "$$FLAGS" >GIT-PREFIX; \
+	fi
+
+TRACK_CFLAGS = $(CC):$(subst ','\'',$(ALL_CFLAGS)):$(USE_GETTEXT_SCHEME)
+
+GIT-CFLAGS: FORCE
+	@FLAGS='$(TRACK_CFLAGS)'; \
+	    if test x"$$FLAGS" != x"`cat GIT-CFLAGS 2>/dev/null`" ; then \
+		echo >&2 "    * new build flags"; \
+		echo "$$FLAGS" >GIT-CFLAGS; \
+            fi
+
+TRACK_LDFLAGS = $(subst ','\'',$(ALL_LDFLAGS))
+
+GIT-LDFLAGS: FORCE
+	@FLAGS='$(TRACK_LDFLAGS)'; \
+	    if test x"$$FLAGS" != x"`cat GIT-LDFLAGS 2>/dev/null`" ; then \
+		echo >&2 "    * new link flags"; \
+		echo "$$FLAGS" >GIT-LDFLAGS; \
+            fi
+
+ifdef RUNTIME_PREFIX
+RUNTIME_PREFIX_OPTION = true
+else
+RUNTIME_PREFIX_OPTION = false
+endif
+
+# We need to apply sq twice, once to protect from the shell
+# that runs GIT-BUILD-OPTIONS, and then again to protect it
+# and the first level quoting from the shell that runs "echo".
+GIT-BUILD-OPTIONS: FORCE
+	@sed \
+		-e "s!@BROKEN_PATH_FIX@!\'$(BROKEN_PATH_FIX)\'!" \
+		-e "s|@DIFF@|\'$(DIFF)\'|" \
+		-e "s|@FSMONITOR_DAEMON_BACKEND@|\'$(FSMONITOR_DAEMON_BACKEND)\'|" \
+		-e "s|@FSMONITOR_OS_SETTINGS@|\'$(FSMONITOR_OS_SETTINGS)\'|" \
+		-e "s|@GITWEBDIR@|\'$(gitwebdir_SQ)\'|" \
+		-e "s|@GIT_INTEROP_MAKE_OPTS@|\'$(GIT_INTEROP_MAKE_OPTS)\'|" \
+		-e "s|@GIT_PERF_LARGE_REPO@|\'$(GIT_PERF_LARGE_REPO)\'|" \
+		-e "s|@GIT_PERF_MAKE_COMMAND@|\'$(GIT_PERF_MAKE_COMMAND)\'|" \
+		-e "s|@GIT_PERF_MAKE_OPTS@|\'$(GIT_PERF_MAKE_OPTS)\'|" \
+		-e "s|@GIT_PERF_REPEAT_COUNT@|\'$(GIT_PERF_REPEAT_COUNT)\'|" \
+		-e "s|@GIT_PERF_REPO@|\'$(GIT_PERF_REPO)\'|" \
+		-e "s|@GIT_TEST_CMP@|\'$(GIT_TEST_CMP)\'|" \
+		-e "s|@GIT_TEST_CMP_USE_COPIED_CONTEXT@|\'$(GIT_TEST_CMP_USE_COPIED_CONTEXT)\'|" \
+		-e "s|@GIT_TEST_GITPERLLIB@|\'$(shell pwd)/perl/build/lib\'|" \
+		-e "s|@GIT_TEST_INDEX_VERSION@|\'$(GIT_TEST_INDEX_VERSION)\'|" \
+		-e "s|@GIT_TEST_MERGE_TOOLS_DIR@|\'$(shell pwd)/mergetools\'|" \
+		-e "s|@GIT_TEST_OPTS@|\'$(GIT_TEST_OPTS)\'|" \
+		-e "s|@GIT_TEST_PERL_FATAL_WARNINGS@|\'$(GIT_TEST_PERL_FATAL_WARNINGS)\'|" \
+		-e "s|@GIT_TEST_POPATH@|\'$(shell pwd)/po\'|" \
+		-e "s|@GIT_TEST_TEMPLATE_DIR@|\'$(shell pwd)/templates/blt\'|" \
+		-e "s|@GIT_TEST_TEXTDOMAINDIR@|\'$(shell pwd)/po/build/locale\'|" \
+		-e "s|@GIT_TEST_UTF8_LOCALE@|\'$(GIT_TEST_UTF8_LOCALE)\'|" \
+		-e "s|@LOCALEDIR@|\'$(localedir_SQ)\'|" \
+		-e "s|@NO_CURL@|\'$(NO_CURL)\'|" \
+		-e "s|@NO_EXPAT@|\'$(NO_EXPAT)\'|" \
+		-e "s|@NO_GETTEXT@|\'$(NO_GETTEXT)\'|" \
+		-e "s|@NO_GITWEB@|\'$(NO_GITWEB)\'|" \
+		-e "s|@NO_ICONV@|\'$(NO_ICONV)\'|" \
+		-e "s|@NO_PERL@|\'$(NO_PERL)\'|" \
+		-e "s|@NO_PERL_CPAN_FALLBACKS@|\'$(NO_PERL_CPAN_FALLBACKS_SQ)\'|" \
+		-e "s|@NO_PTHREADS@|\'$(NO_PTHREADS)\'|" \
+		-e "s|@NO_PYTHON@|\'$(NO_PYTHON)\'|" \
+		-e "s|@NO_REGEX@|\'$(NO_REGEX)\'|" \
+		-e "s|@NO_UNIX_SOCKETS@|\'$(NO_UNIX_SOCKETS)\'|" \
+		-e "s|@PAGER_ENV@|\'$(PAGER_ENV)\'|" \
+		-e "s|@PERL_LOCALEDIR@|\'$(perl_localedir_SQ)\'|" \
+		-e "s|@PERL_PATH@|\'$(PERL_PATH_SQ)\'|" \
+		-e "s|@PYTHON_PATH@|\'$(PYTHON_PATH_SQ)\'|" \
+		-e "s|@RUNTIME_PREFIX@|\'$(RUNTIME_PREFIX_OPTION)\'|" \
+		-e "s|@SANITIZE_ADDRESS@|\'$(SANITIZE_ADDRESS)\'|" \
+		-e "s|@SANITIZE_LEAK@|\'$(SANITIZE_LEAK)\'|" \
+		-e "s|@SHELL_PATH@|\'$(SHELL_PATH_SQ)\'|" \
+		-e "s|@TAR@|\'$(TAR)\'|" \
+		-e "s|@TEST_OUTPUT_DIRECTORY@|\'$(TEST_OUTPUT_DIRECTORY)\'|" \
+		-e "s|@TEST_SHELL_PATH@|\'$(TEST_SHELL_PATH_SQ)\'|" \
+		-e "s|@USE_GETTEXT_SCHEME@|\'$(USE_GETTEXT_SCHEME)\'|" \
+		-e "s|@USE_LIBPCRE2@|\'$(USE_LIBPCRE2)\'|" \
+		-e "s|@X@|\'$(X)\'|" \
+		GIT-BUILD-OPTIONS.in >$@+
+	@if grep -q '^[A-Z][A-Z_]*=@.*@$$' $@+; then echo "Unsubstituted build options in $@" >&2 && exit 1; fi
+	@if cmp $@+ $@ >/dev/null 2>&1; then $(RM) $@+; else mv $@+ $@; fi
+	@if test -f GIT-BUILD-DIR; then rm GIT-BUILD-DIR; fi
+
+### Detect Python interpreter path changes
+ifndef NO_PYTHON
+TRACK_PYTHON = $(subst ','\'',-DPYTHON_PATH='$(PYTHON_PATH_SQ)')
+
+GIT-PYTHON-VARS: FORCE
+	@VARS='$(TRACK_PYTHON)'; \
+	    if test x"$$VARS" != x"`cat $@ 2>/dev/null`" ; then \
+		echo >&2 "    * new Python interpreter location"; \
+		echo "$$VARS" >$@; \
+            fi
+endif
+
+test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))
+
+all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG)
+
+$(test_bindir_programs): bin-wrappers/%: bin-wrappers/wrap-for-bin.sh
+	$(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
+	     -e 's|@BUILD_DIR@|$(shell pwd)|' \
+	     -e 's|@GIT_TEXTDOMAINDIR@|$(shell pwd)/po/build/locale|' \
+	     -e 's|@GITPERLLIB@|$(shell pwd)/perl/build/lib|' \
+	     -e 's|@MERGE_TOOLS_DIR@|$(shell pwd)/mergetools|' \
+	     -e 's|@TEMPLATE_DIR@|$(shell pwd)/templates/blt|' \
+	     -e 's|@PROG@|$(shell pwd)/$(patsubst test-%,t/helper/test-%,$(@F))$(if $(filter-out $(BINDIR_PROGRAMS_NO_X),$(@F)),$(X),)|' < $< > $@ && \
+	chmod +x $@
+
+# GNU make supports exporting all variables by "export" without parameters.
+# However, the environment gets quite big, and some programs have problems
+# with that.
+
+export NO_SVN_TESTS
+export TEST_NO_MALLOC_CHECK
+
+### Testing rules
+
+test: all
+	$(MAKE) -C t/ all
+
+perf: all
+	$(MAKE) -C t/perf/ all
+
+.PHONY: test perf
+
+.PRECIOUS: $(TEST_OBJS)
+
+t/helper/test-tool$X: $(patsubst %,t/helper/%,$(TEST_BUILTINS_OBJS)) $(UNIT_TEST_DIR)/test-lib.o
+
+t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
+
+check-sha1:: t/helper/test-tool$X
+	t/helper/test-sha1.sh
+
+SP_SRC = $(filter-out $(THIRD_PARTY_SOURCES),$(patsubst %.o,%.c,$(OBJECTS)))
+SP_OBJ = $(patsubst %.c,%.sp,$(SP_SRC))
+
+$(SP_OBJ): %.sp: %.c %.o $(GENERATED_H)
+	$(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \
+		-Wsparse-error \
+		$(SPARSE_FLAGS) $(SP_EXTRA_FLAGS) $< && \
+	>$@
+
+.PHONY: sparse
+sparse: $(SP_OBJ)
+
+EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/% $(UNIT_TEST_DIR)/clar/% $(UNIT_TEST_DIR)/clar/clar/%
+ifndef OPENSSL_SHA1
+	EXCEPT_HDRS += sha1/openssl.h
+endif
+ifndef OPENSSL_SHA256
+	EXCEPT_HDRS += sha256/openssl.h
+endif
+ifndef NETTLE_SHA256
+	EXCEPT_HDRS += sha256/nettle.h
+endif
+ifndef GCRYPT_SHA256
+	EXCEPT_HDRS += sha256/gcrypt.h
+endif
+CHK_HDRS = $(filter-out $(EXCEPT_HDRS),$(LIB_H))
+HCO = $(patsubst %.h,%.hco,$(CHK_HDRS))
+HCC = $(HCO:hco=hcc)
+
+%.hcc: %.h
+	@echo '#include "git-compat-util.h"' >$@
+	@echo '#include "$<"' >>$@
+
+$(HCO): %.hco: %.hcc $(GENERATED_H) FORCE
+	$(QUIET_HDR)$(CC) $(ALL_CFLAGS) -o /dev/null -c -xc $<
+
+.PHONY: hdr-check $(HCO)
+hdr-check: $(HCO)
+
+.PHONY: style
+style:
+	git clang-format --style file --diff --extensions c,h
+
+.PHONY: check
+check:
+	@if sparse; \
+	then \
+		echo >&2 "Use 'make sparse' instead"; \
+		$(MAKE) --no-print-directory sparse; \
+	else \
+		echo >&2 "Did you mean 'make test'?"; \
+		exit 1; \
+	fi
+
+COCCI_GEN_ALL = .build/contrib/coccinelle/ALL.cocci
+COCCI_GLOB = $(wildcard contrib/coccinelle/*.cocci)
+COCCI_RULES_TRACKED = $(COCCI_GLOB:%=.build/%)
+COCCI_RULES_TRACKED_NO_PENDING = $(filter-out %.pending.cocci,$(COCCI_RULES_TRACKED))
+COCCI_RULES =
+COCCI_RULES += $(COCCI_GEN_ALL)
+COCCI_RULES += $(COCCI_RULES_TRACKED)
+COCCI_NAMES =
+COCCI_NAMES += $(COCCI_RULES:.build/contrib/coccinelle/%.cocci=%)
+
+COCCICHECK_PENDING = $(filter %.pending.cocci,$(COCCI_RULES))
+COCCICHECK = $(filter-out $(COCCICHECK_PENDING),$(COCCI_RULES))
+
+COCCICHECK_PATCHES = $(COCCICHECK:%=%.patch)
+COCCICHECK_PATCHES_PENDING = $(COCCICHECK_PENDING:%=%.patch)
+
+COCCICHECK_PATCHES_INTREE = $(COCCICHECK_PATCHES:.build/%=%)
+COCCICHECK_PATCHES_PENDING_INTREE = $(COCCICHECK_PATCHES_PENDING:.build/%=%)
+
+# It's expensive to compute the many=many rules below, only eval them
+# on $(MAKECMDGOALS) that match these $(COCCI_RULES)
+COCCI_RULES_GLOB =
+COCCI_RULES_GLOB += cocci%
+COCCI_RULES_GLOB += .build/contrib/coccinelle/%
+COCCI_RULES_GLOB += $(COCCICHECK_PATCHES)
+COCCI_RULES_GLOB += $(COCCICHEC_PATCHES_PENDING)
+COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_INTREE)
+COCCI_RULES_GLOB += $(COCCICHECK_PATCHES_PENDING_INTREE)
+COCCI_GOALS = $(filter $(COCCI_RULES_GLOB),$(MAKECMDGOALS))
+
+COCCI_TEST_RES = $(wildcard contrib/coccinelle/tests/*.res)
+
+$(COCCI_RULES_TRACKED): .build/% : %
+	$(call mkdir_p_parent_template)
+	$(QUIET_CP)cp $< $@
+
+.build/contrib/coccinelle/FOUND_H_SOURCES: $(FOUND_H_SOURCES)
+	$(call mkdir_p_parent_template)
+	$(QUIET_GEN) >$@
+
+$(COCCI_GEN_ALL): $(COCCI_RULES_TRACKED_NO_PENDING)
+	$(call mkdir_p_parent_template)
+	$(QUIET_SPATCH_CAT)cat $^ >$@
+
+ifeq ($(COMPUTE_HEADER_DEPENDENCIES),no)
+SPATCH_USE_O_DEPENDENCIES =
+endif
+define cocci-rule
+
+## Rule for .build/$(1).patch/$(2); Params:
+# $(1) = e.g. ".build/contrib/coccinelle/free.cocci"
+# $(2) = e.g. "grep.c"
+# $(3) = e.g. "grep.o"
+COCCI_$(1:.build/contrib/coccinelle/%.cocci=%) += $(1).d/$(2).patch
+$(1).d/$(2).patch: GIT-SPATCH-DEFINES
+$(1).d/$(2).patch: $(if $(and $(SPATCH_USE_O_DEPENDENCIES),$(wildcard $(3))),$(3),.build/contrib/coccinelle/FOUND_H_SOURCES)
+$(1).d/$(2).patch: $(1)
+$(1).d/$(2).patch: $(1).d/%.patch : %
+	$$(call mkdir_p_parent_template)
+	$$(QUIET_SPATCH)if ! $$(SPATCH) $$(SPATCH_FLAGS) \
+		$$(SPATCH_INCLUDE_FLAGS) \
+		--sp-file $(1) --patch . $$< \
+		>$$@ 2>$$@.log; \
+	then \
+		echo "ERROR when applying '$(1)' to '$$<'; '$$@.log' follows:"; \
+		cat $$@.log; \
+		exit 1; \
+	fi
+endef
+
+define cocci-matrix
+
+$(foreach s,$(COCCI_SOURCES),$(call cocci-rule,$(c),$(s),$(s:%.c=%.o)))
+endef
+
+ifdef COCCI_GOALS
+$(eval $(foreach c,$(COCCI_RULES),$(call cocci-matrix,$(c))))
+endif
+
+define spatch-rule
+
+.build/contrib/coccinelle/$(1).cocci.patch: $$(COCCI_$(1))
+	$$(QUIET_SPATCH_CAT)cat $$^ >$$@ && \
+	if test -s $$@; \
+	then \
+		echo '    ' SPATCH result: $$@; \
+	fi
+contrib/coccinelle/$(1).cocci.patch: .build/contrib/coccinelle/$(1).cocci.patch
+	$$(QUIET_CP)cp $$< $$@
+
+endef
+
+ifdef COCCI_GOALS
+$(eval $(foreach n,$(COCCI_NAMES),$(call spatch-rule,$(n))))
+endif
+
+COCCI_TEST_RES_GEN = $(addprefix .build/,$(COCCI_TEST_RES))
+$(COCCI_TEST_RES_GEN): GIT-SPATCH-DEFINES
+$(COCCI_TEST_RES_GEN): .build/%.res : %.c
+$(COCCI_TEST_RES_GEN): .build/%.res : %.res
+ifdef SPATCH_CONCAT_COCCI
+$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : $(COCCI_GEN_ALL)
+else
+$(COCCI_TEST_RES_GEN): .build/contrib/coccinelle/tests/%.res : contrib/coccinelle/%.cocci
+endif
+	$(call mkdir_p_parent_template)
+	$(QUIET_SPATCH_TEST)$(SPATCH) $(SPATCH_TEST_FLAGS) \
+		--very-quiet --no-show-diff \
+		--sp-file $< -o $@ \
+		$(@:.build/%.res=%.c) && \
+	cmp $(@:.build/%=%) $@ || \
+	git -P diff --no-index $(@:.build/%=%) $@ 2>/dev/null; \
+
+.PHONY: coccicheck-test
+coccicheck-test: $(COCCI_TEST_RES_GEN)
+
+coccicheck: coccicheck-test
+ifdef SPATCH_CONCAT_COCCI
+coccicheck: contrib/coccinelle/ALL.cocci.patch
+else
+coccicheck: $(COCCICHECK_PATCHES_INTREE)
+endif
+
+# See contrib/coccinelle/README
+coccicheck-pending: coccicheck-test
+coccicheck-pending: $(COCCICHECK_PATCHES_PENDING_INTREE)
+
+.PHONY: coccicheck coccicheck-pending
+
+# "Sub"-Makefiles, not really because they can't be run stand-alone,
+# only there to contain directory-specific rules and variables
+## gitweb/Makefile inclusion:
+MAK_DIR_GITWEB = gitweb/
+include gitweb/Makefile
+
+.PHONY: gitweb
+gitweb: $(MAK_DIR_GITWEB_ALL)
+ifndef NO_GITWEB
+all:: gitweb
+endif
+
+### Installation rules
+
+ifneq ($(filter /%,$(firstword $(template_dir))),)
+template_instdir = $(template_dir)
+else
+template_instdir = $(prefix)/$(template_dir)
+endif
+export template_instdir
+
+ifneq ($(filter /%,$(firstword $(gitexecdir))),)
+gitexec_instdir = $(gitexecdir)
+else
+gitexec_instdir = $(prefix)/$(gitexecdir)
+endif
+gitexec_instdir_SQ = $(subst ','\'',$(gitexec_instdir))
+export gitexec_instdir
+
+ifneq ($(filter /%,$(firstword $(mergetoolsdir))),)
+mergetools_instdir = $(mergetoolsdir)
+else
+mergetools_instdir = $(prefix)/$(mergetoolsdir)
+endif
+mergetools_instdir_SQ = $(subst ','\'',$(mergetools_instdir))
+
+install_bindir_xprograms := $(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X))
+install_bindir_programs := $(install_bindir_xprograms) $(BINDIR_PROGRAMS_NO_X)
+
+.PHONY: profile-install profile-fast-install
+profile-install: profile
+	$(MAKE) install
+
+profile-fast-install: profile-fast
+	$(MAKE) install
+
+INSTALL_STRIP =
+
+install: all
+	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'
+	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+	$(INSTALL) $(INSTALL_STRIP) $(PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+	$(INSTALL) $(SCRIPTS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+	$(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+	$(INSTALL) $(INSTALL_STRIP) $(install_bindir_xprograms) '$(DESTDIR_SQ)$(bindir_SQ)'
+	$(INSTALL) $(BINDIR_PROGRAMS_NO_X) '$(DESTDIR_SQ)$(bindir_SQ)'
+
+ifdef MSVC
+	# We DO NOT install the individual foo.o.pdb files because they
+	# have already been rolled up into the exe's pdb file.
+	# We DO NOT have pdb files for the builtin commands (like git-status.exe)
+	# because it is just a copy/hardlink of git.exe, rather than a unique binary.
+	$(INSTALL) $(patsubst %.exe,%.pdb,$(filter-out $(BUILT_INS),$(patsubst %,%$X,$(BINDIR_PROGRAMS_NEED_X)))) '$(DESTDIR_SQ)$(bindir_SQ)'
+	$(INSTALL) $(patsubst %.exe,%.pdb,$(filter-out $(BUILT_INS) $(REMOTE_CURL_ALIASES),$(PROGRAMS))) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
+ifndef DEBUG
+	$(INSTALL) $(vcpkg_rel_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
+	$(INSTALL) $(vcpkg_rel_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
+else
+	$(INSTALL) $(vcpkg_dbg_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
+	$(INSTALL) $(vcpkg_dbg_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
+endif
+endif
+	$(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
+	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
+	$(INSTALL) -m 644 mergetools/* '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
+ifndef NO_GETTEXT
+	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(localedir_SQ)'
+	(cd po/build/locale && $(TAR) cf - .) | \
+	(cd '$(DESTDIR_SQ)$(localedir_SQ)' && umask 022 && $(TAR) xof -)
+endif
+ifndef NO_PERL
+	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perllibdir_SQ)'
+	(cd perl/build/lib && $(TAR) cf - .) | \
+	(cd '$(DESTDIR_SQ)$(perllibdir_SQ)' && umask 022 && $(TAR) xof -)
+endif
+ifndef NO_TCLTK
+	$(MAKE) -C gitk-git install
+	$(MAKE) -C git-gui gitexecdir='$(gitexec_instdir_SQ)' install
+endif
+ifneq (,$X)
+	$(foreach p,$(patsubst %$X,%,$(filter %$X,$(ALL_COMMANDS_TO_INSTALL) $(OTHER_PROGRAMS))), test '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p' -ef '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p$X' || $(RM) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)/$p';)
+endif
+
+	bindir=$$(cd '$(DESTDIR_SQ)$(bindir_SQ)' && pwd) && \
+	execdir=$$(cd '$(DESTDIR_SQ)$(gitexec_instdir_SQ)' && pwd) && \
+	destdir_from_execdir_SQ=$$(echo '$(gitexecdir_relative_SQ)' | sed -e 's|[^/][^/]*|..|g') && \
+	{ test "$$bindir/" = "$$execdir/" || \
+	  for p in $(OTHER_PROGRAMS) $(filter $(install_bindir_programs),$(ALL_PROGRAMS)); do \
+		$(RM) "$$execdir/$$p" && \
+		test -n "$(INSTALL_SYMLINKS)" && \
+		ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/$$p" "$$execdir/$$p" || \
+		{ test -z "$(NO_INSTALL_HARDLINKS)$(NO_CROSS_DIRECTORY_HARDLINKS)" && \
+		  ln "$$bindir/$$p" "$$execdir/$$p" 2>/dev/null || \
+		  cp "$$bindir/$$p" "$$execdir/$$p" || exit; } \
+	  done; \
+	} && \
+	for p in $(filter $(install_bindir_programs),$(BUILT_INS)); do \
+		$(RM) "$$bindir/$$p" && \
+		test -n "$(INSTALL_SYMLINKS)" && \
+		ln -s "git$X" "$$bindir/$$p" || \
+		{ test -z "$(NO_INSTALL_HARDLINKS)" && \
+		  ln "$$bindir/git$X" "$$bindir/$$p" 2>/dev/null || \
+		  ln -s "git$X" "$$bindir/$$p" 2>/dev/null || \
+		  cp "$$bindir/git$X" "$$bindir/$$p" || exit; }; \
+	done && \
+	for p in $(BUILT_INS); do \
+		$(RM) "$$execdir/$$p" && \
+		if test -z "$(SKIP_DASHED_BUILT_INS)"; \
+		then \
+			test -n "$(INSTALL_SYMLINKS)" && \
+			ln -s "$$destdir_from_execdir_SQ/$(bindir_relative_SQ)/git$X" "$$execdir/$$p" || \
+			{ test -z "$(NO_INSTALL_HARDLINKS)" && \
+			  ln "$$execdir/git$X" "$$execdir/$$p" 2>/dev/null || \
+			  ln -s "git$X" "$$execdir/$$p" 2>/dev/null || \
+			  cp "$$execdir/git$X" "$$execdir/$$p" || exit; }; \
+		fi \
+	done && \
+	remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \
+	for p in $$remote_curl_aliases; do \
+		$(RM) "$$execdir/$$p" && \
+		test -n "$(INSTALL_SYMLINKS)" && \
+		ln -s "git-remote-http$X" "$$execdir/$$p" || \
+		{ test -z "$(NO_INSTALL_HARDLINKS)" && \
+		  ln "$$execdir/git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
+		  ln -s "git-remote-http$X" "$$execdir/$$p" 2>/dev/null || \
+		  cp "$$execdir/git-remote-http$X" "$$execdir/$$p" || exit; } \
+	done
+
+.PHONY: install-doc install-man install-man-perl install-html install-info install-pdf
+.PHONY: quick-install-doc quick-install-man quick-install-html
+
+install-doc: install-man-perl
+	$(MAKE) -C Documentation install
+
+install-man: install-man-perl
+	$(MAKE) -C Documentation install-man
+
+install-man-perl: man-perl
+	$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mandir_SQ)/man3'
+	(cd perl/build/man/man3 && $(TAR) cf - .) | \
+	(cd '$(DESTDIR_SQ)$(mandir_SQ)/man3' && umask 022 && $(TAR) xof -)
+
+install-html:
+	$(MAKE) -C Documentation install-html
+
+install-info:
+	$(MAKE) -C Documentation install-info
+
+install-pdf:
+	$(MAKE) -C Documentation install-pdf
+
+quick-install-doc:
+	$(MAKE) -C Documentation quick-install
+
+quick-install-man:
+	$(MAKE) -C Documentation quick-install-man
+
+quick-install-html:
+	$(MAKE) -C Documentation quick-install-html
+
+
+
+### Maintainer's dist rules
+
+GIT_TARNAME = git-$(GIT_VERSION)
+GIT_ARCHIVE_EXTRA_FILES = \
+	--prefix=$(GIT_TARNAME)/ \
+	--add-file=configure \
+	--add-file=.dist-tmp-dir/version \
+	--prefix=$(GIT_TARNAME)/git-gui/ \
+	--add-file=.dist-tmp-dir/git-gui/version
+ifdef DC_SHA1_SUBMODULE
+GIT_ARCHIVE_EXTRA_FILES += \
+	--prefix=$(GIT_TARNAME)/sha1collisiondetection/ \
+	--add-file=sha1collisiondetection/LICENSE.txt \
+	--prefix=$(GIT_TARNAME)/sha1collisiondetection/lib/ \
+	--add-file=sha1collisiondetection/lib/sha1.c \
+	--add-file=sha1collisiondetection/lib/sha1.h \
+	--add-file=sha1collisiondetection/lib/ubc_check.c \
+	--add-file=sha1collisiondetection/lib/ubc_check.h
+endif
+dist: git-archive$(X) configure
+	@$(RM) -r .dist-tmp-dir
+	@mkdir .dist-tmp-dir
+	@echo $(GIT_VERSION) > .dist-tmp-dir/version
+	@$(MAKE) -C git-gui TARDIR=../.dist-tmp-dir/git-gui dist-version
+	./git-archive --format=tar \
+		$(GIT_ARCHIVE_EXTRA_FILES) \
+		--prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
+	@$(RM) -r .dist-tmp-dir
+	gzip -f -9 $(GIT_TARNAME).tar
+
+rpm::
+	@echo >&2 "Use distro packaged sources to run rpmbuild"
+	@false
+.PHONY: rpm
+
+ifneq ($(INCLUDE_DLLS_IN_ARTIFACTS),)
+OTHER_PROGRAMS += $(shell echo *.dll t/helper/*.dll t/unit-tests/bin/*.dll)
+endif
+
+artifacts-tar:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) \
+		GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \
+		$(UNIT_TEST_PROGS) $(CLAR_TEST_PROG) $(MOFILES)
+	$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) \
+		SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
+	test -n "$(ARTIFACTS_DIRECTORY)"
+	mkdir -p "$(ARTIFACTS_DIRECTORY)"
+	$(TAR) czf "$(ARTIFACTS_DIRECTORY)/artifacts.tar.gz" $^ templates/blt/
+.PHONY: artifacts-tar
+
+htmldocs = git-htmldocs-$(GIT_VERSION)
+manpages = git-manpages-$(GIT_VERSION)
+.PHONY: dist-doc distclean
+dist-doc: git$X
+	$(RM) -r .doc-tmp-dir
+	mkdir .doc-tmp-dir
+	$(MAKE) -C Documentation WEBDOC_DEST=../.doc-tmp-dir install-webdoc
+	./git -C .doc-tmp-dir init
+	./git -C .doc-tmp-dir add .
+	./git -C .doc-tmp-dir commit -m htmldocs
+	./git -C .doc-tmp-dir archive --format=tar --prefix=./ HEAD^{tree} \
+		> $(htmldocs).tar
+	gzip -n -9 -f $(htmldocs).tar
+	:
+	$(RM) -r .doc-tmp-dir
+	mkdir -p .doc-tmp-dir/man1 .doc-tmp-dir/man5 .doc-tmp-dir/man7
+	$(MAKE) -C Documentation DESTDIR=./ \
+		man1dir=../.doc-tmp-dir/man1 \
+		man5dir=../.doc-tmp-dir/man5 \
+		man7dir=../.doc-tmp-dir/man7 \
+		install
+	./git -C .doc-tmp-dir init
+	./git -C .doc-tmp-dir add .
+	./git -C .doc-tmp-dir commit -m manpages
+	./git -C .doc-tmp-dir archive --format=tar --prefix=./ HEAD^{tree} \
+		> $(manpages).tar
+	gzip -n -9 -f $(manpages).tar
+	$(RM) -r .doc-tmp-dir
+
+### Cleaning rules
+
+distclean: clean
+	$(RM) configure
+	$(RM) config.log config.status config.cache
+	$(RM) config.mak.autogen config.mak.append
+	$(RM) -r autom4te.cache
+
+profile-clean:
+	$(RM) $(addsuffix *.gcda,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
+	$(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
+
+cocciclean:
+	$(RM) GIT-SPATCH-DEFINES
+	$(RM) -r .build/contrib/coccinelle
+	$(RM) contrib/coccinelle/*.cocci.patch
+
+clean: profile-clean coverage-clean cocciclean
+	$(RM) -r .build $(UNIT_TEST_BIN)
+	$(RM) GIT-TEST-SUITES
+	$(RM) po/git.pot po/git-core.pot
+	$(RM) git.rc git.res
+	$(RM) $(OBJECTS)
+	$(RM) headless-git.o
+	$(RM) $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB)
+	$(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) $(OTHER_PROGRAMS)
+	$(RM) $(TEST_PROGRAMS)
+	$(RM) $(FUZZ_PROGRAMS)
+	$(RM) $(SP_OBJ)
+	$(RM) $(HCC)
+	$(RM) version-def.h
+	$(RM) -r $(dep_dirs) $(compdb_dir) compile_commands.json
+	$(RM) $(test_bindir_programs)
+	$(RM) -r po/build/
+	$(RM) *.pyc *.pyo */*.pyc */*.pyo $(GENERATED_H) $(ETAGS_TARGET) tags cscope*
+	$(RM) -r .dist-tmp-dir .doc-tmp-dir
+	$(RM) $(GIT_TARNAME).tar.gz
+	$(RM) $(htmldocs).tar.gz $(manpages).tar.gz
+	$(MAKE) -C Documentation/ clean
+	$(RM) Documentation/GIT-EXCLUDED-PROGRAMS
+ifndef NO_PERL
+	$(RM) -r perl/build/
+endif
+	$(MAKE) -C templates/ clean
+	$(MAKE) -C t/ clean
+ifndef NO_TCLTK
+	$(MAKE) -C gitk-git clean
+	$(MAKE) -C git-gui clean
+endif
+	$(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
+	$(RM) GIT-USER-AGENT GIT-PREFIX
+	$(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
+ifdef MSVC
+	$(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
+	$(RM) headless-git.o.pdb
+	$(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
+	$(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS))
+	$(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS))
+	$(RM) $(patsubst %.exe,%.pdb,$(PROGRAMS))
+	$(RM) $(patsubst %.exe,%.iobj,$(PROGRAMS))
+	$(RM) $(patsubst %.exe,%.ipdb,$(PROGRAMS))
+	$(RM) $(patsubst %.exe,%.pdb,$(TEST_PROGRAMS))
+	$(RM) $(patsubst %.exe,%.iobj,$(TEST_PROGRAMS))
+	$(RM) $(patsubst %.exe,%.ipdb,$(TEST_PROGRAMS))
+	$(RM) compat/vcbuild/MSVC-DEFS-GEN
+endif
+
+.PHONY: all install profile-clean cocciclean clean strip
+.PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
+.PHONY: FORCE
+
+### Check documentation
+#
+ALL_COMMANDS = $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB)
+ALL_COMMANDS += git
+ALL_COMMANDS += git-citool
+ALL_COMMANDS += git-gui
+ALL_COMMANDS += gitk
+ALL_COMMANDS += gitweb
+ALL_COMMANDS += scalar
+
+.PHONY: check-docs
+check-docs::
+	$(MAKE) -C Documentation lint-docs
+
+### Make sure built-ins do not have dups and listed in git.c
+#
+check-builtins::
+	./check-builtins.sh
+
+### Test suite coverage testing
+#
+.PHONY: coverage coverage-clean coverage-compile coverage-test coverage-report
+.PHONY: coverage-untested-functions cover_db cover_db_html
+.PHONY: coverage-clean-results
+
+coverage:
+	$(MAKE) coverage-test
+	$(MAKE) coverage-untested-functions
+
+object_dirs := $(sort $(dir $(OBJECTS)))
+coverage-clean-results:
+	$(RM) $(addsuffix *.gcov,$(object_dirs))
+	$(RM) $(addsuffix *.gcda,$(object_dirs))
+	$(RM) coverage-untested-functions
+	$(RM) -r cover_db/
+	$(RM) -r cover_db_html/
+	$(RM) coverage-test.made
+
+coverage-clean: coverage-clean-results
+	$(RM) $(addsuffix *.gcno,$(object_dirs))
+
+COVERAGE_CFLAGS = $(CFLAGS) -O0 -ftest-coverage -fprofile-arcs
+COVERAGE_LDFLAGS = $(CFLAGS)  -O0 -lgcov
+GCOVFLAGS = --preserve-paths --branch-probabilities --all-blocks
+
+coverage-compile:
+	$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" all
+
+coverage-test: coverage-clean-results coverage-compile
+	$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
+		DEFAULT_TEST_TARGET=test -j1 test
+	touch coverage-test.made
+
+coverage-test.made:
+	$(MAKE) coverage-test
+
+coverage-prove: coverage-clean-results coverage-compile
+	$(MAKE) CFLAGS="$(COVERAGE_CFLAGS)" LDFLAGS="$(COVERAGE_LDFLAGS)" \
+		DEFAULT_TEST_TARGET=prove GIT_PROVE_OPTS="$(GIT_PROVE_OPTS) -j1" \
+		-j1 test
+
+coverage-report: coverage-test.made
+	$(QUIET_GCOV)for dir in $(object_dirs); do \
+		$(GCOV) $(GCOVFLAGS) --object-directory=$$dir $$dir*.c || exit; \
+	done
+
+coverage-untested-functions: coverage-report
+	grep '^function.*called 0 ' *.c.gcov \
+		| sed -e 's/\([^:]*\)\.gcov: *function \([^ ]*\) called.*/\1: \2/' \
+		> coverage-untested-functions
+
+cover_db: coverage-report
+	gcov2perl -db cover_db *.gcov
+
+cover_db_html: cover_db
+	cover -report html -outputdir cover_db_html cover_db
+
+
+### Fuzz testing
+#
+# Building fuzz targets generally requires a special set of compiler flags that
+# are not necessarily appropriate for general builds, and that vary greatly
+# depending on the compiler version used.
+#
+# An example command to build against libFuzzer from LLVM 11.0.0:
+#
+# make CC=clang FUZZ_CXX=clang++ \
+#      CFLAGS="-fsanitize=fuzzer-no-link,address" \
+#      LIB_FUZZING_ENGINE="-fsanitize=fuzzer,address" \
+#      fuzz-all
+#
+FUZZ_CXX ?= $(CC)
+FUZZ_CXXFLAGS ?= $(ALL_CFLAGS)
+
+.PHONY: fuzz-all
+fuzz-all: $(FUZZ_PROGRAMS)
+
+$(FUZZ_PROGRAMS): %: %.o oss-fuzz/dummy-cmd-main.o $(GITLIBS) GIT-LDFLAGS
+	$(QUIET_LINK)$(FUZZ_CXX) $(FUZZ_CXXFLAGS) -o $@ $(ALL_LDFLAGS) \
+		-Wl,--allow-multiple-definition \
+		$(filter %.o,$^) $(filter %.a,$^) $(LIBS) $(LIB_FUZZING_ENGINE)
+
+$(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o $(UNIT_TEST_OBJS) \
+	$(GITLIBS) GIT-LDFLAGS
+	$(call mkdir_p_parent_template)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
+		$(filter %.o,$^) $(filter %.a,$^) $(LIBS)
+
+GIT-TEST-SUITES: FORCE
+	@FLAGS='$(CLAR_TEST_SUITES)'; \
+	    if test x"$$FLAGS" != x"`cat GIT-TEST-SUITES 2>/dev/null`" ; then \
+		echo >&2 "    * new test suites"; \
+		echo "$$FLAGS" >GIT-TEST-SUITES; \
+            fi
+
+$(UNIT_TEST_DIR)/clar-decls.h: $(patsubst %,$(UNIT_TEST_DIR)/%.c,$(CLAR_TEST_SUITES)) $(UNIT_TEST_DIR)/generate-clar-decls.sh GIT-TEST-SUITES
+	$(QUIET_GEN)$(SHELL_PATH) $(UNIT_TEST_DIR)/generate-clar-decls.sh "$@" $(filter %.c,$^)
+$(UNIT_TEST_DIR)/clar.suite: $(UNIT_TEST_DIR)/clar-decls.h $(UNIT_TEST_DIR)/generate-clar-suites.sh
+	$(QUIET_GEN)$(SHELL_PATH) $(UNIT_TEST_DIR)/generate-clar-suites.sh $< $(UNIT_TEST_DIR)/clar.suite
+$(UNIT_TEST_DIR)/clar/clar.o: $(UNIT_TEST_DIR)/clar.suite
+$(CLAR_TEST_OBJS): $(UNIT_TEST_DIR)/clar-decls.h
+$(CLAR_TEST_OBJS): EXTRA_CPPFLAGS = -I$(UNIT_TEST_DIR)
+$(CLAR_TEST_PROG): $(UNIT_TEST_DIR)/clar.suite $(CLAR_TEST_OBJS) $(GITLIBS) GIT-LDFLAGS
+	$(call mkdir_p_parent_template)
+	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
+
+.PHONY: build-unit-tests unit-tests
+build-unit-tests: $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG)
+unit-tests: $(UNIT_TEST_PROGS) $(CLAR_TEST_PROG) t/helper/test-tool$X
+	$(MAKE) -C t/ unit-tests
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000..665ce5f5a8
--- /dev/null
+++ b/README.md
@@ -0,0 +1,74 @@
+[![Build status](https://github.com/git/git/workflows/CI/badge.svg)](https://github.com/git/git/actions?query=branch%3Amaster+event%3Apush)
+
+Git - fast, scalable, distributed revision control system
+=========================================================
+
+Git is a fast, scalable, distributed revision control system with an
+unusually rich command set that provides both high-level operations
+and full access to internals.
+
+Git is an Open Source project covered by the GNU General Public
+License version 2 (some parts of it are under different licenses,
+compatible with the GPLv2). It was originally written by Linus
+Torvalds with help of a group of hackers around the net.
+
+Please read the file [INSTALL][] for installation instructions.
+
+Many Git online resources are accessible from <https://git-scm.com/>
+including full documentation and Git related tools.
+
+See [Documentation/gittutorial.txt][] to get started, then see
+[Documentation/giteveryday.txt][] for a useful minimum set of commands, and
+`Documentation/git-<commandname>.txt` for documentation of each command.
+If git has been correctly installed, then the tutorial can also be
+read with `man gittutorial` or `git help tutorial`, and the
+documentation of each command with `man git-<commandname>` or `git help
+<commandname>`.
+
+CVS users may also want to read [Documentation/gitcvs-migration.txt][]
+(`man gitcvs-migration` or `git help cvs-migration` if git is
+installed).
+
+The user discussion and development of Git take place on the Git
+mailing list -- everyone is welcome to post bug reports, feature
+requests, comments and patches to git@xxxxxxxxxxxxxxx (read
+[Documentation/SubmittingPatches][] for instructions on patch submission
+and [Documentation/CodingGuidelines][]).
+
+Those wishing to help with error message, usage and informational message
+string translations (localization l10) should see [po/README.md][]
+(a `po` file is a Portable Object file that holds the translations).
+
+To subscribe to the list, send an email to <git+subscribe@xxxxxxxxxxxxxxx>
+(see https://subspace.kernel.org/subscribing.html for details). The mailing
+list archives are available at <https://lore.kernel.org/git/>,
+<https://marc.info/?l=git> and other archival sites.
+
+Issues which are security relevant should be disclosed privately to
+the Git Security mailing list <git-security@xxxxxxxxxxxxxxxx>.
+
+The maintainer frequently sends the "What's cooking" reports that
+list the current status of various development topics to the mailing
+list.  The discussion following them give a good reference for
+project status, development direction and remaining tasks.
+
+The name "git" was given by Linus Torvalds when he wrote the very
+first version. He described the tool as "the stupid content tracker"
+and the name as (depending on your mood):
+
+ - random three-letter combination that is pronounceable, and not
+   actually used by any common UNIX command.  The fact that it is a
+   mispronunciation of "get" may or may not be relevant.
+ - stupid. contemptible and despicable. simple. Take your pick from the
+   dictionary of slang.
+ - "global information tracker": you're in a good mood, and it actually
+   works for you. Angels sing, and a light suddenly fills the room.
+ - "goddamn idiotic truckload of sh*t": when it breaks
+
+[INSTALL]: INSTALL
+[Documentation/gittutorial.txt]: Documentation/gittutorial.txt
+[Documentation/giteveryday.txt]: Documentation/giteveryday.txt
+[Documentation/gitcvs-migration.txt]: Documentation/gitcvs-migration.txt
+[Documentation/SubmittingPatches]: Documentation/SubmittingPatches
+[Documentation/CodingGuidelines]: Documentation/CodingGuidelines
+[po/README.md]: po/README.md
diff --git a/RelNotes b/RelNotes
new file mode 120000
index 0000000000..978481996e
--- /dev/null
+++ b/RelNotes
@@ -0,0 +1 @@
+Documentation/RelNotes/2.49.0.txt
\ No newline at end of file
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000000..c720c2ae7f
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,51 @@
+# Security Policy
+
+## Reporting a vulnerability
+
+Please send a detailed mail to git-security@xxxxxxxxxxxxxxxx to
+report vulnerabilities in Git.
+
+Even when unsure whether the bug in question is an exploitable
+vulnerability, it is recommended to send the report to
+git-security@xxxxxxxxxxxxxxxx (and obviously not to discuss the
+issue anywhere else).
+
+Vulnerabilities are expected to be discussed _only_ on that
+list, and not in public, until the official announcement on the
+Git mailing list on the release date.
+
+Examples for details to include:
+
+- Ideally a short description (or a script) to demonstrate an
+  exploit.
+- The affected platforms and scenarios (the vulnerability might
+  only affect setups with case-sensitive file systems, for
+  example).
+- The name and affiliation of the security researchers who are
+  involved in the discovery, if any.
+- Whether the vulnerability has already been disclosed.
+- How long an embargo would be required to be safe.
+
+## Supported Versions
+
+There are no official "Long Term Support" versions in Git.
+Instead, the maintenance track (i.e. the versions based on the
+most recently published feature release, also known as ".0"
+version) sees occasional updates with bug fixes.
+
+Fixes to vulnerabilities are made for the maintenance track for
+the latest feature release and merged up to the in-development
+branches. The Git project makes no formal guarantee for any
+older maintenance tracks to receive updates. In practice,
+though, critical vulnerability fixes are applied not only to the
+most recent track, but to at least a couple more maintenance
+tracks.
+
+This is typically done by making the fix on the oldest and still
+relevant maintenance track, and merging it upwards to newer and
+newer maintenance tracks.
+
+For example, v2.24.1 was released to address a couple of
+[CVEs](https://cve.mitre.org/), and at the same time v2.14.6,
+v2.15.4, v2.16.6, v2.17.3, v2.18.2, v2.19.3, v2.20.2, v2.21.1,
+v2.22.2 and v2.23.1 were released.
diff --git a/abspath.c b/abspath.c
new file mode 100644
index 0000000000..1202cde23d
--- /dev/null
+++ b/abspath.c
@@ -0,0 +1,327 @@
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "strbuf.h"
+
+/*
+ * Do not use this for inspecting *tracked* content.  When path is a
+ * symlink to a directory, we do not want to say it is a directory when
+ * dealing with tracked content in the working tree.
+ */
+int is_directory(const char *path)
+{
+	struct stat st;
+	return (!stat(path, &st) && S_ISDIR(st.st_mode));
+}
+
+/* removes the last path component from 'path' except if 'path' is root */
+static void strip_last_component(struct strbuf *path)
+{
+	size_t offset = offset_1st_component(path->buf);
+	size_t len = path->len;
+
+	/* Find start of the last component */
+	while (offset < len && !is_dir_sep(path->buf[len - 1]))
+		len--;
+	/* Skip sequences of multiple path-separators */
+	while (offset < len && is_dir_sep(path->buf[len - 1]))
+		len--;
+
+	strbuf_setlen(path, len);
+}
+
+/* get (and remove) the next component in 'remaining' and place it in 'next' */
+static void get_next_component(struct strbuf *next, struct strbuf *remaining)
+{
+	char *start = NULL;
+	char *end = NULL;
+
+	strbuf_reset(next);
+
+	/* look for the next component */
+	/* Skip sequences of multiple path-separators */
+	for (start = remaining->buf; is_dir_sep(*start); start++)
+		; /* nothing */
+	/* Find end of the path component */
+	for (end = start; *end && !is_dir_sep(*end); end++)
+		; /* nothing */
+
+	strbuf_add(next, start, end - start);
+	/* remove the component from 'remaining' */
+	strbuf_remove(remaining, 0, end - remaining->buf);
+}
+
+/* copies root part from remaining to resolved, canonicalizing it on the way */
+static void get_root_part(struct strbuf *resolved, struct strbuf *remaining)
+{
+	int offset = offset_1st_component(remaining->buf);
+
+	strbuf_reset(resolved);
+	strbuf_add(resolved, remaining->buf, offset);
+#ifdef GIT_WINDOWS_NATIVE
+	convert_slashes(resolved->buf);
+#endif
+	strbuf_remove(remaining, 0, offset);
+}
+
+/* We allow "recursive" symbolic links. Only within reason, though. */
+#ifndef MAXSYMLINKS
+#define MAXSYMLINKS 32
+#endif
+
+/*
+ * If set, any number of trailing components may be missing; otherwise, only one
+ * may be.
+ */
+#define REALPATH_MANY_MISSING (1 << 0)
+/* Should we die if there's an error? */
+#define REALPATH_DIE_ON_ERROR (1 << 1)
+
+static char *strbuf_realpath_1(struct strbuf *resolved, const char *path,
+			       int flags)
+{
+	struct strbuf remaining = STRBUF_INIT;
+	struct strbuf next = STRBUF_INIT;
+	struct strbuf symlink = STRBUF_INIT;
+	char *retval = NULL;
+	int num_symlinks = 0;
+	struct stat st;
+
+	if (!*path) {
+		if (flags & REALPATH_DIE_ON_ERROR)
+			die("The empty string is not a valid path");
+		else
+			goto error_out;
+	}
+
+	strbuf_addstr(&remaining, path);
+	get_root_part(resolved, &remaining);
+
+	if (!resolved->len) {
+		/* relative path; can use CWD as the initial resolved path */
+		if (strbuf_getcwd(resolved)) {
+			if (flags & REALPATH_DIE_ON_ERROR)
+				die_errno("unable to get current working directory");
+			else
+				goto error_out;
+		}
+	}
+
+	/* Iterate over the remaining path components */
+	while (remaining.len > 0) {
+		get_next_component(&next, &remaining);
+
+		if (next.len == 0) {
+			continue; /* empty component */
+		} else if (next.len == 1 && !strcmp(next.buf, ".")) {
+			continue; /* '.' component */
+		} else if (next.len == 2 && !strcmp(next.buf, "..")) {
+			/* '..' component; strip the last path component */
+			strip_last_component(resolved);
+			continue;
+		}
+
+		/* append the next component and resolve resultant path */
+		if (!is_dir_sep(resolved->buf[resolved->len - 1]))
+			strbuf_addch(resolved, '/');
+		strbuf_addbuf(resolved, &next);
+
+		if (lstat(resolved->buf, &st)) {
+			/* error out unless this was the last component */
+			if (errno != ENOENT ||
+			   (!(flags & REALPATH_MANY_MISSING) && remaining.len)) {
+				if (flags & REALPATH_DIE_ON_ERROR)
+					die_errno("Invalid path '%s'",
+						  resolved->buf);
+				else
+					goto error_out;
+			}
+		} else if (S_ISLNK(st.st_mode)) {
+			ssize_t len;
+			strbuf_reset(&symlink);
+
+			if (num_symlinks++ > MAXSYMLINKS) {
+				errno = ELOOP;
+
+				if (flags & REALPATH_DIE_ON_ERROR)
+					die("More than %d nested symlinks "
+					    "on path '%s'", MAXSYMLINKS, path);
+				else
+					goto error_out;
+			}
+
+			len = strbuf_readlink(&symlink, resolved->buf,
+					      st.st_size);
+			if (len < 0) {
+				if (flags & REALPATH_DIE_ON_ERROR)
+					die_errno("Invalid symlink '%s'",
+						  resolved->buf);
+				else
+					goto error_out;
+			}
+
+			if (is_absolute_path(symlink.buf)) {
+				/* absolute symlink; set resolved to root */
+				get_root_part(resolved, &symlink);
+			} else {
+				/*
+				 * relative symlink
+				 * strip off the last component since it will
+				 * be replaced with the contents of the symlink
+				 */
+				strip_last_component(resolved);
+			}
+
+			/*
+			 * if there are still remaining components to resolve
+			 * then append them to symlink
+			 */
+			if (remaining.len) {
+				strbuf_addch(&symlink, '/');
+				strbuf_addbuf(&symlink, &remaining);
+			}
+
+			/*
+			 * use the symlink as the remaining components that
+			 * need to be resolved
+			 */
+			strbuf_swap(&symlink, &remaining);
+		}
+	}
+
+	retval = resolved->buf;
+
+error_out:
+	strbuf_release(&remaining);
+	strbuf_release(&next);
+	strbuf_release(&symlink);
+
+	if (!retval)
+		strbuf_reset(resolved);
+
+	return retval;
+}
+
+/*
+ * Return the real path (i.e., absolute path, with symlinks resolved
+ * and extra slashes removed) equivalent to the specified path.  (If
+ * you want an absolute path but don't mind links, use
+ * absolute_path().)  Places the resolved realpath in the provided strbuf.
+ *
+ * The directory part of path (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist.  If die_on_error is set, then die with an
+ * informative error message if there is a problem.  Otherwise, return
+ * NULL on errors (without generating any output).
+ */
+char *strbuf_realpath(struct strbuf *resolved, const char *path,
+		      int die_on_error)
+{
+	return strbuf_realpath_1(resolved, path,
+				 die_on_error ? REALPATH_DIE_ON_ERROR : 0);
+}
+
+/*
+ * Just like strbuf_realpath, but allows an arbitrary number of path
+ * components to be missing.
+ */
+char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path,
+				int die_on_error)
+{
+	return strbuf_realpath_1(resolved, path,
+				 ((die_on_error ? REALPATH_DIE_ON_ERROR : 0) |
+				  REALPATH_MANY_MISSING));
+}
+
+char *real_pathdup(const char *path, int die_on_error)
+{
+	struct strbuf realpath = STRBUF_INIT;
+	char *retval = NULL;
+
+	if (strbuf_realpath(&realpath, path, die_on_error))
+		retval = strbuf_detach(&realpath, NULL);
+
+	strbuf_release(&realpath);
+
+	return retval;
+}
+
+/*
+ * Use this to get an absolute path from a relative one. If you want
+ * to resolve links, you should use strbuf_realpath.
+ */
+const char *absolute_path(const char *path)
+{
+	static struct strbuf sb = STRBUF_INIT;
+	strbuf_reset(&sb);
+	strbuf_add_absolute_path(&sb, path);
+	return sb.buf;
+}
+
+char *absolute_pathdup(const char *path)
+{
+	struct strbuf sb = STRBUF_INIT;
+	strbuf_add_absolute_path(&sb, path);
+	return strbuf_detach(&sb, NULL);
+}
+
+char *prefix_filename(const char *pfx, const char *arg)
+{
+	struct strbuf path = STRBUF_INIT;
+	size_t pfx_len = pfx ? strlen(pfx) : 0;
+
+	if (!pfx_len)
+		; /* nothing to prefix */
+	else if (is_absolute_path(arg))
+		pfx_len = 0;
+	else
+		strbuf_add(&path, pfx, pfx_len);
+
+	strbuf_addstr(&path, arg);
+#ifdef GIT_WINDOWS_NATIVE
+	convert_slashes(path.buf + pfx_len);
+#endif
+	return strbuf_detach(&path, NULL);
+}
+
+char *prefix_filename_except_for_dash(const char *pfx, const char *arg)
+{
+	if (!strcmp(arg, "-"))
+		return xstrdup(arg);
+	return prefix_filename(pfx, arg);
+}
+
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path)
+{
+	if (!*path)
+		die("The empty string is not a valid path");
+	if (!is_absolute_path(path)) {
+		struct stat cwd_stat, pwd_stat;
+		size_t orig_len = sb->len;
+		char *cwd = xgetcwd();
+		char *pwd = getenv("PWD");
+		if (pwd && strcmp(pwd, cwd) &&
+		    !stat(cwd, &cwd_stat) &&
+		    (cwd_stat.st_dev || cwd_stat.st_ino) &&
+		    !stat(pwd, &pwd_stat) &&
+		    pwd_stat.st_dev == cwd_stat.st_dev &&
+		    pwd_stat.st_ino == cwd_stat.st_ino)
+			strbuf_addstr(sb, pwd);
+		else
+			strbuf_addstr(sb, cwd);
+		if (sb->len > orig_len && !is_dir_sep(sb->buf[sb->len - 1]))
+			strbuf_addch(sb, '/');
+		free(cwd);
+	}
+	strbuf_addstr(sb, path);
+}
+
+void strbuf_add_real_path(struct strbuf *sb, const char *path)
+{
+	if (sb->len) {
+		struct strbuf resolved = STRBUF_INIT;
+		strbuf_realpath(&resolved, path, 1);
+		strbuf_addbuf(sb, &resolved);
+		strbuf_release(&resolved);
+	} else
+		strbuf_realpath(sb, path, 1);
+}
diff --git a/abspath.h b/abspath.h
new file mode 100644
index 0000000000..4653080d5e
--- /dev/null
+++ b/abspath.h
@@ -0,0 +1,54 @@
+#ifndef ABSPATH_H
+#define ABSPATH_H
+
+int is_directory(const char *);
+char *strbuf_realpath(struct strbuf *resolved, const char *path,
+		      int die_on_error);
+char *strbuf_realpath_forgiving(struct strbuf *resolved, const char *path,
+				int die_on_error);
+char *real_pathdup(const char *path, int die_on_error);
+const char *absolute_path(const char *path);
+char *absolute_pathdup(const char *path);
+
+/*
+ * Concatenate "prefix" (if len is non-zero) and "path", with no
+ * connecting characters (so "prefix" should end with a "/").
+ * Unlike prefix_path, this should be used if the named file does
+ * not have to interact with index entry; i.e. name of a random file
+ * on the filesystem.
+ *
+ * The return value is always a newly allocated string (even if the
+ * prefix was empty).
+ */
+char *prefix_filename(const char *prefix, const char *path);
+
+/* Likewise, but path=="-" always yields "-" */
+char *prefix_filename_except_for_dash(const char *prefix, const char *path);
+
+static inline int is_absolute_path(const char *path)
+{
+	return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
+}
+
+/**
+ * Add a path to a buffer, converting a relative path to an
+ * absolute one in the process.  Symbolic links are not
+ * resolved.
+ */
+void strbuf_add_absolute_path(struct strbuf *sb, const char *path);
+
+/**
+ * Canonize `path` (make it absolute, resolve symlinks, remove extra
+ * slashes) and append it to `sb`.  Die with an informative error
+ * message if there is a problem.
+ *
+ * The directory part of `path` (i.e., everything up to the last
+ * dir_sep) must denote a valid, existing directory, but the last
+ * component need not exist.
+ *
+ * Callers that don't mind links should use the more lightweight
+ * strbuf_add_absolute_path() instead.
+ */
+void strbuf_add_real_path(struct strbuf *sb, const char *path);
+
+#endif /* ABSPATH_H */
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000000..f11bc7ed7d
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,40 @@
+dnl Check for socklen_t: historically on BSD it is an int, and in
+dnl POSIX 1g it is a type of its own, but some platforms use different
+dnl types for the argument to getsockopt, getpeername, etc.  So we
+dnl have to test to find something that will work.
+AC_DEFUN([TYPE_SOCKLEN_T],
+[
+   AC_CHECK_TYPE([socklen_t], ,[
+      AC_MSG_CHECKING([for socklen_t equivalent])
+      AC_CACHE_VAL([git_cv_socklen_t_equiv],
+      [
+         # Systems have either "struct sockaddr *" or
+         # "void *" as the second argument to getpeername
+         git_cv_socklen_t_equiv=
+         for arg2 in "struct sockaddr" void; do
+            for t in int size_t unsigned long "unsigned long"; do
+               AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+                  #include <sys/types.h>
+                  #include <sys/socket.h>
+
+                  int getpeername (int, $arg2 *, $t *);
+               ],[
+                  $t len;
+                  getpeername(0,0,&len);
+               ])],[
+                  git_cv_socklen_t_equiv="$t"
+                  break 2
+               ])
+            done
+         done
+
+         if test "x$git_cv_socklen_t_equiv" = x; then
+            AC_MSG_ERROR([Cannot find a type to use in place of socklen_t])
+         fi
+      ])
+      AC_MSG_RESULT($git_cv_socklen_t_equiv)
+      AC_DEFINE_UNQUOTED(socklen_t, $git_cv_socklen_t_equiv,
+			[type to use in place of socklen_t if not defined])],
+      [#include <sys/types.h>
+#include <sys/socket.h>])
+])
diff --git a/add-interactive.c b/add-interactive.c
new file mode 100644
index 0000000000..97ff35b6f1
--- /dev/null
+++ b/add-interactive.c
@@ -0,0 +1,1211 @@
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "add-interactive.h"
+#include "color.h"
+#include "config.h"
+#include "diffcore.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "preload-index.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "revision.h"
+#include "refs.h"
+#include "string-list.h"
+#include "lockfile.h"
+#include "dir.h"
+#include "run-command.h"
+#include "prompt.h"
+#include "tree.h"
+
+static void init_color(struct repository *r, struct add_i_state *s,
+		       const char *section_and_slot, char *dst,
+		       const char *default_color)
+{
+	char *key = xstrfmt("color.%s", section_and_slot);
+	const char *value;
+
+	if (!s->use_color)
+		dst[0] = '\0';
+	else if (repo_config_get_value(r, key, &value) ||
+		 color_parse(value, dst))
+		strlcpy(dst, default_color, COLOR_MAXLEN);
+
+	free(key);
+}
+
+void init_add_i_state(struct add_i_state *s, struct repository *r)
+{
+	const char *value;
+
+	s->r = r;
+
+	if (repo_config_get_value(r, "color.interactive", &value))
+		s->use_color = -1;
+	else
+		s->use_color =
+			git_config_colorbool("color.interactive", value);
+	s->use_color = want_color(s->use_color);
+
+	init_color(r, s, "interactive.header", s->header_color, GIT_COLOR_BOLD);
+	init_color(r, s, "interactive.help", s->help_color, GIT_COLOR_BOLD_RED);
+	init_color(r, s, "interactive.prompt", s->prompt_color,
+		   GIT_COLOR_BOLD_BLUE);
+	init_color(r, s, "interactive.error", s->error_color,
+		   GIT_COLOR_BOLD_RED);
+
+	init_color(r, s, "diff.frag", s->fraginfo_color,
+		   diff_get_color(s->use_color, DIFF_FRAGINFO));
+	init_color(r, s, "diff.context", s->context_color, "fall back");
+	if (!strcmp(s->context_color, "fall back"))
+		init_color(r, s, "diff.plain", s->context_color,
+			   diff_get_color(s->use_color, DIFF_CONTEXT));
+	init_color(r, s, "diff.old", s->file_old_color,
+		diff_get_color(s->use_color, DIFF_FILE_OLD));
+	init_color(r, s, "diff.new", s->file_new_color,
+		diff_get_color(s->use_color, DIFF_FILE_NEW));
+
+	strlcpy(s->reset_color,
+		s->use_color ? GIT_COLOR_RESET : "", COLOR_MAXLEN);
+
+	FREE_AND_NULL(s->interactive_diff_filter);
+	repo_config_get_string(r, "interactive.difffilter",
+			       &s->interactive_diff_filter);
+
+	FREE_AND_NULL(s->interactive_diff_algorithm);
+	repo_config_get_string(r, "diff.algorithm",
+			       &s->interactive_diff_algorithm);
+
+	repo_config_get_bool(r, "interactive.singlekey", &s->use_single_key);
+	if (s->use_single_key)
+		setbuf(stdin, NULL);
+}
+
+void clear_add_i_state(struct add_i_state *s)
+{
+	FREE_AND_NULL(s->interactive_diff_filter);
+	FREE_AND_NULL(s->interactive_diff_algorithm);
+	memset(s, 0, sizeof(*s));
+	s->use_color = -1;
+}
+
+/*
+ * A "prefix item list" is a list of items that are identified by a string, and
+ * a unique prefix (if any) is determined for each item.
+ *
+ * It is implemented in the form of a pair of `string_list`s, the first one
+ * duplicating the strings, with the `util` field pointing at a structure whose
+ * first field must be `size_t prefix_length`.
+ *
+ * That `prefix_length` field will be computed by `find_unique_prefixes()`; It
+ * will be set to zero if no valid, unique prefix could be found.
+ *
+ * The second `string_list` is called `sorted` and does _not_ duplicate the
+ * strings but simply reuses the first one's, with the `util` field pointing at
+ * the `string_item_list` of the first `string_list`. It  will be populated and
+ * sorted by `find_unique_prefixes()`.
+ */
+struct prefix_item_list {
+	struct string_list items;
+	struct string_list sorted;
+	int *selected; /* for multi-selections */
+	size_t min_length, max_length;
+};
+#define PREFIX_ITEM_LIST_INIT { \
+	.items = STRING_LIST_INIT_DUP, \
+	.sorted = STRING_LIST_INIT_NODUP, \
+	.min_length = 1, \
+	.max_length = 4, \
+}
+
+static void prefix_item_list_clear(struct prefix_item_list *list)
+{
+	string_list_clear(&list->items, 1);
+	string_list_clear(&list->sorted, 0);
+	FREE_AND_NULL(list->selected);
+}
+
+static void extend_prefix_length(struct string_list_item *p,
+				 const char *other_string, size_t max_length)
+{
+	size_t *len = p->util;
+
+	if (!*len || memcmp(p->string, other_string, *len))
+		return;
+
+	for (;;) {
+		char c = p->string[*len];
+
+		/*
+		 * Is `p` a strict prefix of `other`? Or have we exhausted the
+		 * maximal length of the prefix? Or is the current character a
+		 * multi-byte UTF-8 one? If so, there is no valid, unique
+		 * prefix.
+		 */
+		if (!c || ++*len > max_length || !isascii(c)) {
+			*len = 0;
+			break;
+		}
+
+		if (c != other_string[*len - 1])
+			break;
+	}
+}
+
+static void find_unique_prefixes(struct prefix_item_list *list)
+{
+	size_t i;
+
+	if (list->sorted.nr == list->items.nr)
+		return;
+
+	string_list_clear(&list->sorted, 0);
+	/* Avoid reallocating incrementally */
+	list->sorted.items = xmalloc(st_mult(sizeof(*list->sorted.items),
+					     list->items.nr));
+	list->sorted.nr = list->sorted.alloc = list->items.nr;
+
+	for (i = 0; i < list->items.nr; i++) {
+		list->sorted.items[i].string = list->items.items[i].string;
+		list->sorted.items[i].util = list->items.items + i;
+	}
+
+	string_list_sort(&list->sorted);
+
+	for (i = 0; i < list->sorted.nr; i++) {
+		struct string_list_item *sorted_item = list->sorted.items + i;
+		struct string_list_item *item = sorted_item->util;
+		size_t *len = item->util;
+
+		*len = 0;
+		while (*len < list->min_length) {
+			char c = item->string[(*len)++];
+
+			if (!c || !isascii(c)) {
+				*len = 0;
+				break;
+			}
+		}
+
+		if (i > 0)
+			extend_prefix_length(item, sorted_item[-1].string,
+					     list->max_length);
+		if (i + 1 < list->sorted.nr)
+			extend_prefix_length(item, sorted_item[1].string,
+					     list->max_length);
+	}
+}
+
+static ssize_t find_unique(const char *string, struct prefix_item_list *list)
+{
+	int index = string_list_find_insert_index(&list->sorted, string, 1);
+	struct string_list_item *item;
+
+	if (list->items.nr != list->sorted.nr)
+		BUG("prefix_item_list in inconsistent state (%"PRIuMAX
+		    " vs %"PRIuMAX")",
+		    (uintmax_t)list->items.nr, (uintmax_t)list->sorted.nr);
+
+	if (index < 0)
+		item = list->sorted.items[-1 - index].util;
+	else if (index > 0 &&
+		 starts_with(list->sorted.items[index - 1].string, string))
+		return -1;
+	else if (index + 1 < list->sorted.nr &&
+		 starts_with(list->sorted.items[index + 1].string, string))
+		return -1;
+	else if (index < list->sorted.nr &&
+		 starts_with(list->sorted.items[index].string, string))
+		item = list->sorted.items[index].util;
+	else
+		return -1;
+	return item - list->items.items;
+}
+
+struct list_options {
+	int columns;
+	const char *header;
+	void (*print_item)(int i, int selected, struct string_list_item *item,
+			   void *print_item_data);
+	void *print_item_data;
+};
+
+static void list(struct add_i_state *s, struct string_list *list, int *selected,
+		 struct list_options *opts)
+{
+	int i, last_lf = 0;
+
+	if (!list->nr)
+		return;
+
+	if (opts->header)
+		color_fprintf_ln(stdout, s->header_color,
+				 "%s", opts->header);
+
+	for (i = 0; i < list->nr; i++) {
+		opts->print_item(i, selected ? selected[i] : 0, list->items + i,
+				 opts->print_item_data);
+
+		if ((opts->columns) && ((i + 1) % (opts->columns))) {
+			putchar('\t');
+			last_lf = 0;
+		}
+		else {
+			putchar('\n');
+			last_lf = 1;
+		}
+	}
+
+	if (!last_lf)
+		putchar('\n');
+}
+struct list_and_choose_options {
+	struct list_options list_opts;
+
+	const char *prompt;
+	enum {
+		SINGLETON = (1<<0),
+		IMMEDIATE = (1<<1),
+	} flags;
+	void (*print_help)(struct add_i_state *s);
+};
+
+#define LIST_AND_CHOOSE_ERROR (-1)
+#define LIST_AND_CHOOSE_QUIT  (-2)
+
+/*
+ * Returns the selected index in singleton mode, the number of selected items
+ * otherwise.
+ *
+ * If an error occurred, returns `LIST_AND_CHOOSE_ERROR`. Upon EOF,
+ * `LIST_AND_CHOOSE_QUIT` is returned.
+ */
+static ssize_t list_and_choose(struct add_i_state *s,
+			       struct prefix_item_list *items,
+			       struct list_and_choose_options *opts)
+{
+	int singleton = opts->flags & SINGLETON;
+	int immediate = opts->flags & IMMEDIATE;
+
+	struct strbuf input = STRBUF_INIT;
+	ssize_t res = singleton ? LIST_AND_CHOOSE_ERROR : 0;
+
+	if (!singleton) {
+		free(items->selected);
+		CALLOC_ARRAY(items->selected, items->items.nr);
+	}
+
+	if (singleton && !immediate)
+		BUG("singleton requires immediate");
+
+	find_unique_prefixes(items);
+
+	for (;;) {
+		char *p;
+
+		strbuf_reset(&input);
+
+		list(s, &items->items, items->selected, &opts->list_opts);
+
+		color_fprintf(stdout, s->prompt_color, "%s", opts->prompt);
+		fputs(singleton ? "> " : ">> ", stdout);
+		fflush(stdout);
+
+		if (git_read_line_interactively(&input) == EOF) {
+			putchar('\n');
+			if (immediate)
+				res = LIST_AND_CHOOSE_QUIT;
+			break;
+		}
+
+		if (!input.len)
+			break;
+
+		if (!strcmp(input.buf, "?")) {
+			opts->print_help(s);
+			continue;
+		}
+
+		p = input.buf;
+		for (;;) {
+			size_t sep = strcspn(p, " \t\r\n,");
+			int choose = 1;
+			/* `from` is inclusive, `to` is exclusive */
+			ssize_t from = -1, to = -1;
+
+			if (!sep) {
+				if (!*p)
+					break;
+				p++;
+				continue;
+			}
+
+			/* Input that begins with '-'; de-select */
+			if (*p == '-') {
+				choose = 0;
+				p++;
+				sep--;
+			}
+
+			if (sep == 1 && *p == '*') {
+				from = 0;
+				to = items->items.nr;
+			} else if (isdigit(*p)) {
+				char *endp;
+				/*
+				 * A range can be specified like 5-7 or 5-.
+				 *
+				 * Note: `from` is 0-based while the user input
+				 * is 1-based, hence we have to decrement by
+				 * one. We do not have to decrement `to` even
+				 * if it is 0-based because it is an exclusive
+				 * boundary.
+				 */
+				from = strtoul(p, &endp, 10) - 1;
+				if (endp == p + sep)
+					to = from + 1;
+				else if (*endp == '-') {
+					if (isdigit(*(++endp)))
+						to = strtoul(endp, &endp, 10);
+					else
+						to = items->items.nr;
+					/* extra characters after the range? */
+					if (endp != p + sep)
+						from = -1;
+				}
+			}
+
+			if (p[sep])
+				p[sep++] = '\0';
+			if (from < 0) {
+				from = find_unique(p, items);
+				if (from >= 0)
+					to = from + 1;
+			}
+
+			if (from < 0 || from >= items->items.nr ||
+			    (singleton && from + 1 != to)) {
+				color_fprintf_ln(stderr, s->error_color,
+						 _("Huh (%s)?"), p);
+				break;
+			} else if (singleton) {
+				res = from;
+				break;
+			}
+
+			if (to > items->items.nr)
+				to = items->items.nr;
+
+			for (; from < to; from++)
+				if (items->selected[from] != choose) {
+					items->selected[from] = choose;
+					res += choose ? +1 : -1;
+				}
+
+			p += sep;
+		}
+
+		if ((immediate && res != LIST_AND_CHOOSE_ERROR) ||
+		    !strcmp(input.buf, "*"))
+			break;
+	}
+
+	strbuf_release(&input);
+	return res;
+}
+
+struct adddel {
+	uintmax_t add, del;
+	unsigned seen:1, unmerged:1, binary:1;
+};
+
+struct file_item {
+	size_t prefix_length;
+	struct adddel index, worktree;
+};
+
+static void add_file_item(struct string_list *files, const char *name)
+{
+	struct file_item *item = xcalloc(1, sizeof(*item));
+
+	string_list_append(files, name)->util = item;
+}
+
+struct pathname_entry {
+	struct hashmap_entry ent;
+	const char *name;
+	struct file_item *item;
+};
+
+static int pathname_entry_cmp(const void *cmp_data UNUSED,
+			      const struct hashmap_entry *he1,
+			      const struct hashmap_entry *he2,
+			      const void *name)
+{
+	const struct pathname_entry *e1 =
+		container_of(he1, const struct pathname_entry, ent);
+	const struct pathname_entry *e2 =
+		container_of(he2, const struct pathname_entry, ent);
+
+	return strcmp(e1->name, name ? (const char *)name : e2->name);
+}
+
+struct collection_status {
+	enum { FROM_WORKTREE = 0, FROM_INDEX = 1 } mode;
+
+	const char *reference;
+
+	unsigned skip_unseen:1;
+	size_t unmerged_count, binary_count;
+	struct string_list *files;
+	struct hashmap file_map;
+};
+
+static void collect_changes_cb(struct diff_queue_struct *q,
+			       struct diff_options *options,
+			       void *data)
+{
+	struct collection_status *s = data;
+	struct diffstat_t stat = { 0 };
+	int i;
+
+	if (!q->nr)
+		return;
+
+	compute_diffstat(options, &stat, q);
+
+	for (i = 0; i < stat.nr; i++) {
+		const char *name = stat.files[i]->name;
+		int hash = strhash(name);
+		struct pathname_entry *entry;
+		struct file_item *file_item;
+		struct adddel *adddel, *other_adddel;
+
+		entry = hashmap_get_entry_from_hash(&s->file_map, hash, name,
+						    struct pathname_entry, ent);
+		if (!entry) {
+			if (s->skip_unseen)
+				continue;
+
+			add_file_item(s->files, name);
+
+			CALLOC_ARRAY(entry, 1);
+			hashmap_entry_init(&entry->ent, hash);
+			entry->name = s->files->items[s->files->nr - 1].string;
+			entry->item = s->files->items[s->files->nr - 1].util;
+			hashmap_add(&s->file_map, &entry->ent);
+		}
+
+		file_item = entry->item;
+		adddel = s->mode == FROM_INDEX ?
+			&file_item->index : &file_item->worktree;
+		other_adddel = s->mode == FROM_INDEX ?
+			&file_item->worktree : &file_item->index;
+		adddel->seen = 1;
+		adddel->add = stat.files[i]->added;
+		adddel->del = stat.files[i]->deleted;
+		if (stat.files[i]->is_binary) {
+			if (!other_adddel->binary)
+				s->binary_count++;
+			adddel->binary = 1;
+		}
+		if (stat.files[i]->is_unmerged) {
+			if (!other_adddel->unmerged)
+				s->unmerged_count++;
+			adddel->unmerged = 1;
+		}
+	}
+	free_diffstat_info(&stat);
+}
+
+enum modified_files_filter {
+	NO_FILTER = 0,
+	WORKTREE_ONLY = 1,
+	INDEX_ONLY = 2,
+};
+
+static int get_modified_files(struct repository *r,
+			      enum modified_files_filter filter,
+			      struct prefix_item_list *files,
+			      const struct pathspec *ps,
+			      size_t *unmerged_count,
+			      size_t *binary_count)
+{
+	struct object_id head_oid;
+	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(r),
+						  "HEAD", RESOLVE_REF_READING,
+						  &head_oid, NULL);
+	struct collection_status s = { 0 };
+	int i;
+
+	discard_index(r->index);
+	if (repo_read_index_preload(r, ps, 0) < 0)
+		return error(_("could not read index"));
+
+	prefix_item_list_clear(files);
+	s.files = &files->items;
+	hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0);
+
+	for (i = 0; i < 2; i++) {
+		struct rev_info rev;
+		struct setup_revision_opt opt = { 0 };
+
+		if (filter == INDEX_ONLY)
+			s.mode = (i == 0) ? FROM_INDEX : FROM_WORKTREE;
+		else
+			s.mode = (i == 0) ? FROM_WORKTREE : FROM_INDEX;
+		s.skip_unseen = filter && i;
+
+		opt.def = is_initial ?
+			empty_tree_oid_hex(r->hash_algo) : oid_to_hex(&head_oid);
+
+		repo_init_revisions(r, &rev, NULL);
+		setup_revisions(0, NULL, &rev, &opt);
+
+		rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+		rev.diffopt.format_callback = collect_changes_cb;
+		rev.diffopt.format_callback_data = &s;
+
+		if (ps)
+			copy_pathspec(&rev.prune_data, ps);
+
+		if (s.mode == FROM_INDEX)
+			run_diff_index(&rev, DIFF_INDEX_CACHED);
+		else {
+			rev.diffopt.flags.ignore_dirty_submodules = 1;
+			run_diff_files(&rev, 0);
+		}
+
+		release_revisions(&rev);
+	}
+	hashmap_clear_and_free(&s.file_map, struct pathname_entry, ent);
+	if (unmerged_count)
+		*unmerged_count = s.unmerged_count;
+	if (binary_count)
+		*binary_count = s.binary_count;
+
+	/* While the diffs are ordered already, we ran *two* diffs... */
+	string_list_sort(&files->items);
+
+	return 0;
+}
+
+static void render_adddel(struct strbuf *buf,
+				struct adddel *ad, const char *no_changes)
+{
+	if (ad->binary)
+		strbuf_addstr(buf, _("binary"));
+	else if (ad->seen)
+		strbuf_addf(buf, "+%"PRIuMAX"/-%"PRIuMAX,
+			    (uintmax_t)ad->add, (uintmax_t)ad->del);
+	else
+		strbuf_addstr(buf, no_changes);
+}
+
+/* filters out prefixes which have special meaning to list_and_choose() */
+static int is_valid_prefix(const char *prefix, size_t prefix_len)
+{
+	return prefix_len && prefix &&
+		/*
+		 * We expect `prefix` to be NUL terminated, therefore this
+		 * `strcspn()` call is okay, even if it might do much more
+		 * work than strictly necessary.
+		 */
+		strcspn(prefix, " \t\r\n,") >= prefix_len &&	/* separators */
+		*prefix != '-' &&				/* deselection */
+		!isdigit(*prefix) &&				/* selection */
+		(prefix_len != 1 ||
+		 (*prefix != '*' &&				/* "all" wildcard */
+		  *prefix != '?'));				/* prompt help */
+}
+
+struct print_file_item_data {
+	const char *modified_fmt, *color, *reset;
+	struct strbuf buf, name, index, worktree;
+	unsigned only_names:1;
+};
+
+static void print_file_item(int i, int selected, struct string_list_item *item,
+			    void *print_file_item_data)
+{
+	struct file_item *c = item->util;
+	struct print_file_item_data *d = print_file_item_data;
+	const char *highlighted = NULL;
+
+	strbuf_reset(&d->index);
+	strbuf_reset(&d->worktree);
+	strbuf_reset(&d->buf);
+
+	/* Format the item with the prefix highlighted. */
+	if (c->prefix_length > 0 &&
+	    is_valid_prefix(item->string, c->prefix_length)) {
+		strbuf_reset(&d->name);
+		strbuf_addf(&d->name, "%s%.*s%s%s", d->color,
+			    (int)c->prefix_length, item->string, d->reset,
+			    item->string + c->prefix_length);
+		highlighted = d->name.buf;
+	}
+
+	if (d->only_names) {
+		printf("%c%2d: %s", selected ? '*' : ' ', i + 1,
+		       highlighted ? highlighted : item->string);
+		return;
+	}
+
+	render_adddel(&d->worktree, &c->worktree, _("nothing"));
+	render_adddel(&d->index, &c->index, _("unchanged"));
+
+	strbuf_addf(&d->buf, d->modified_fmt, d->index.buf, d->worktree.buf,
+		    highlighted ? highlighted : item->string);
+
+	printf("%c%2d: %s", selected ? '*' : ' ', i + 1, d->buf.buf);
+}
+
+static int run_status(struct add_i_state *s, const struct pathspec *ps,
+		      struct prefix_item_list *files,
+		      struct list_and_choose_options *opts)
+{
+	if (get_modified_files(s->r, NO_FILTER, files, ps, NULL, NULL) < 0)
+		return -1;
+
+	list(s, &files->items, NULL, &opts->list_opts);
+	putchar('\n');
+
+	return 0;
+}
+
+static int run_update(struct add_i_state *s, const struct pathspec *ps,
+		      struct prefix_item_list *files,
+		      struct list_and_choose_options *opts)
+{
+	int res = 0, fd;
+	size_t count, i;
+	struct lock_file index_lock;
+
+	if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, NULL, NULL) < 0)
+		return -1;
+
+	if (!files->items.nr) {
+		putchar('\n');
+		return 0;
+	}
+
+	opts->prompt = N_("Update");
+	count = list_and_choose(s, files, opts);
+	if (count <= 0) {
+		putchar('\n');
+		return 0;
+	}
+
+	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
+	if (fd < 0) {
+		putchar('\n');
+		return -1;
+	}
+
+	for (i = 0; i < files->items.nr; i++) {
+		const char *name = files->items.items[i].string;
+		struct stat st;
+
+		if (!files->selected[i])
+			continue;
+		if (lstat(name, &st) && is_missing_file_error(errno)) {
+			if (remove_file_from_index(s->r->index, name) < 0) {
+				res = error(_("could not stage '%s'"), name);
+				break;
+			}
+		} else if (add_file_to_index(s->r->index, name, 0) < 0) {
+			res = error(_("could not stage '%s'"), name);
+			break;
+		}
+	}
+
+	if (!res && write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0)
+		res = error(_("could not write index"));
+
+	if (!res)
+		printf(Q_("updated %d path\n",
+			  "updated %d paths\n", count), (int)count);
+
+	putchar('\n');
+	return res;
+}
+
+static void revert_from_diff(struct diff_queue_struct *q,
+			     struct diff_options *opt, void *data UNUSED)
+{
+	int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
+
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filespec *one = q->queue[i]->one;
+		struct cache_entry *ce;
+
+		if (!(one->mode && !is_null_oid(&one->oid))) {
+			remove_file_from_index(opt->repo->index, one->path);
+			printf(_("note: %s is untracked now.\n"), one->path);
+		} else {
+			ce = make_cache_entry(opt->repo->index, one->mode,
+					      &one->oid, one->path, 0, 0);
+			if (!ce)
+				die(_("make_cache_entry failed for path '%s'"),
+				    one->path);
+			add_index_entry(opt->repo->index, ce, add_flags);
+		}
+	}
+}
+
+static int run_revert(struct add_i_state *s, const struct pathspec *ps,
+		      struct prefix_item_list *files,
+		      struct list_and_choose_options *opts)
+{
+	int res = 0, fd;
+	size_t count, i, j;
+
+	struct object_id oid;
+	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(s->r),
+						  "HEAD", RESOLVE_REF_READING,
+						  &oid,
+						  NULL);
+	struct lock_file index_lock;
+	const char **paths;
+	struct tree *tree;
+	struct diff_options diffopt = { NULL };
+
+	if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
+		return -1;
+
+	if (!files->items.nr) {
+		putchar('\n');
+		return 0;
+	}
+
+	opts->prompt = N_("Revert");
+	count = list_and_choose(s, files, opts);
+	if (count <= 0)
+		goto finish_revert;
+
+	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
+	if (fd < 0) {
+		res = -1;
+		goto finish_revert;
+	}
+
+	if (is_initial)
+		oidcpy(&oid, s->r->hash_algo->empty_tree);
+	else {
+		tree = parse_tree_indirect(&oid);
+		if (!tree) {
+			res = error(_("Could not parse HEAD^{tree}"));
+			goto finish_revert;
+		}
+		oidcpy(&oid, &tree->object.oid);
+	}
+
+	ALLOC_ARRAY(paths, count + 1);
+	for (i = j = 0; i < files->items.nr; i++)
+		if (files->selected[i])
+			paths[j++] = files->items.items[i].string;
+	paths[j] = NULL;
+
+	parse_pathspec(&diffopt.pathspec, 0,
+		       PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH,
+		       NULL, paths);
+
+	diffopt.output_format = DIFF_FORMAT_CALLBACK;
+	diffopt.format_callback = revert_from_diff;
+	diffopt.flags.override_submodule_config = 1;
+	diffopt.repo = s->r;
+
+	if (do_diff_cache(&oid, &diffopt)) {
+		diff_free(&diffopt);
+		res = -1;
+	} else {
+		diffcore_std(&diffopt);
+		diff_flush(&diffopt);
+	}
+	free(paths);
+
+	if (!res && write_locked_index(s->r->index, &index_lock,
+				       COMMIT_LOCK) < 0)
+		res = -1;
+	else
+		res = repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0, 1,
+						   NULL, NULL, NULL);
+
+	if (!res)
+		printf(Q_("reverted %d path\n",
+			  "reverted %d paths\n", count), (int)count);
+
+finish_revert:
+	putchar('\n');
+	return res;
+}
+
+static int get_untracked_files(struct repository *r,
+			       struct prefix_item_list *files,
+			       const struct pathspec *ps)
+{
+	struct dir_struct dir = { 0 };
+	size_t i;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (repo_read_index(r) < 0)
+		return error(_("could not read index"));
+
+	prefix_item_list_clear(files);
+	setup_standard_excludes(&dir);
+	add_pattern_list(&dir, EXC_CMDL, "--exclude option");
+	fill_directory(&dir, r->index, ps);
+
+	for (i = 0; i < dir.nr; i++) {
+		struct dir_entry *ent = dir.entries[i];
+
+		if (index_name_is_other(r->index, ent->name, ent->len)) {
+			strbuf_reset(&buf);
+			strbuf_add(&buf, ent->name, ent->len);
+			add_file_item(&files->items, buf.buf);
+		}
+	}
+
+	strbuf_release(&buf);
+	dir_clear(&dir);
+	return 0;
+}
+
+static int run_add_untracked(struct add_i_state *s, const struct pathspec *ps,
+		      struct prefix_item_list *files,
+		      struct list_and_choose_options *opts)
+{
+	struct print_file_item_data *d = opts->list_opts.print_item_data;
+	int res = 0, fd;
+	size_t count, i;
+	struct lock_file index_lock;
+
+	if (get_untracked_files(s->r, files, ps) < 0)
+		return -1;
+
+	if (!files->items.nr) {
+		printf(_("No untracked files.\n"));
+		goto finish_add_untracked;
+	}
+
+	opts->prompt = N_("Add untracked");
+	d->only_names = 1;
+	count = list_and_choose(s, files, opts);
+	d->only_names = 0;
+	if (count <= 0)
+		goto finish_add_untracked;
+
+	fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
+	if (fd < 0) {
+		res = -1;
+		goto finish_add_untracked;
+	}
+
+	for (i = 0; i < files->items.nr; i++) {
+		const char *name = files->items.items[i].string;
+		if (files->selected[i] &&
+		    add_file_to_index(s->r->index, name, 0) < 0) {
+			res = error(_("could not stage '%s'"), name);
+			break;
+		}
+	}
+
+	if (!res &&
+	    write_locked_index(s->r->index, &index_lock, COMMIT_LOCK) < 0)
+		res = error(_("could not write index"));
+
+	if (!res)
+		printf(Q_("added %d path\n",
+			  "added %d paths\n", count), (int)count);
+
+finish_add_untracked:
+	putchar('\n');
+	return res;
+}
+
+static int run_patch(struct add_i_state *s, const struct pathspec *ps,
+		     struct prefix_item_list *files,
+		     struct list_and_choose_options *opts)
+{
+	int res = 0;
+	ssize_t count, i, j;
+	size_t unmerged_count = 0, binary_count = 0;
+
+	if (get_modified_files(s->r, WORKTREE_ONLY, files, ps,
+			       &unmerged_count, &binary_count) < 0)
+		return -1;
+
+	if (unmerged_count || binary_count) {
+		for (i = j = 0; i < files->items.nr; i++) {
+			struct file_item *item = files->items.items[i].util;
+
+			if (item->index.binary || item->worktree.binary) {
+				free(item);
+				free(files->items.items[i].string);
+			} else if (item->index.unmerged ||
+				 item->worktree.unmerged) {
+				color_fprintf_ln(stderr, s->error_color,
+						 _("ignoring unmerged: %s"),
+						 files->items.items[i].string);
+				free(item);
+				free(files->items.items[i].string);
+			} else
+				files->items.items[j++] = files->items.items[i];
+		}
+		files->items.nr = j;
+	}
+
+	if (!files->items.nr) {
+		if (binary_count)
+			fprintf(stderr, _("Only binary files changed.\n"));
+		else
+			fprintf(stderr, _("No changes.\n"));
+		return 0;
+	}
+
+	opts->prompt = N_("Patch update");
+	count = list_and_choose(s, files, opts);
+	if (count > 0) {
+		struct strvec args = STRVEC_INIT;
+		struct pathspec ps_selected = { 0 };
+
+		for (i = 0; i < files->items.nr; i++)
+			if (files->selected[i])
+				strvec_push(&args,
+					    files->items.items[i].string);
+		parse_pathspec(&ps_selected,
+			       PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+			       PATHSPEC_LITERAL_PATH, "", args.v);
+		res = run_add_p(s->r, ADD_P_ADD, NULL, &ps_selected);
+		strvec_clear(&args);
+		clear_pathspec(&ps_selected);
+	}
+
+	return res;
+}
+
+static int run_diff(struct add_i_state *s, const struct pathspec *ps,
+		    struct prefix_item_list *files,
+		    struct list_and_choose_options *opts)
+{
+	int res = 0;
+	ssize_t count, i;
+
+	struct object_id oid;
+	int is_initial = !refs_resolve_ref_unsafe(get_main_ref_store(s->r),
+						  "HEAD", RESOLVE_REF_READING,
+						  &oid,
+						  NULL);
+	if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
+		return -1;
+
+	if (!files->items.nr) {
+		putchar('\n');
+		return 0;
+	}
+
+	opts->prompt = N_("Review diff");
+	opts->flags = IMMEDIATE;
+	count = list_and_choose(s, files, opts);
+	opts->flags = 0;
+	if (count > 0) {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+
+		strvec_pushl(&cmd.args, "git", "diff", "-p", "--cached",
+			     oid_to_hex(!is_initial ? &oid :
+					s->r->hash_algo->empty_tree),
+			     "--", NULL);
+		for (i = 0; i < files->items.nr; i++)
+			if (files->selected[i])
+				strvec_push(&cmd.args,
+					    files->items.items[i].string);
+		res = run_command(&cmd);
+	}
+
+	putchar('\n');
+	return res;
+}
+
+static int run_help(struct add_i_state *s, const struct pathspec *ps UNUSED,
+		    struct prefix_item_list *files UNUSED,
+		    struct list_and_choose_options *opts UNUSED)
+{
+	color_fprintf_ln(stdout, s->help_color, "status        - %s",
+			 _("show paths with changes"));
+	color_fprintf_ln(stdout, s->help_color, "update        - %s",
+			 _("add working tree state to the staged set of changes"));
+	color_fprintf_ln(stdout, s->help_color, "revert        - %s",
+			 _("revert staged set of changes back to the HEAD version"));
+	color_fprintf_ln(stdout, s->help_color, "patch         - %s",
+			 _("pick hunks and update selectively"));
+	color_fprintf_ln(stdout, s->help_color, "diff          - %s",
+			 _("view diff between HEAD and index"));
+	color_fprintf_ln(stdout, s->help_color, "add untracked - %s",
+			 _("add contents of untracked files to the staged set of changes"));
+
+	return 0;
+}
+
+static void choose_prompt_help(struct add_i_state *s)
+{
+	color_fprintf_ln(stdout, s->help_color, "%s",
+			 _("Prompt help:"));
+	color_fprintf_ln(stdout, s->help_color, "1          - %s",
+			 _("select a single item"));
+	color_fprintf_ln(stdout, s->help_color, "3-5        - %s",
+			 _("select a range of items"));
+	color_fprintf_ln(stdout, s->help_color, "2-3,6-9    - %s",
+			 _("select multiple ranges"));
+	color_fprintf_ln(stdout, s->help_color, "foo        - %s",
+			 _("select item based on unique prefix"));
+	color_fprintf_ln(stdout, s->help_color, "-...       - %s",
+			 _("unselect specified items"));
+	color_fprintf_ln(stdout, s->help_color, "*          - %s",
+			 _("choose all items"));
+	color_fprintf_ln(stdout, s->help_color, "           - %s",
+			 _("(empty) finish selecting"));
+}
+
+typedef int (*command_t)(struct add_i_state *s, const struct pathspec *ps,
+			 struct prefix_item_list *files,
+			 struct list_and_choose_options *opts);
+
+struct command_item {
+	size_t prefix_length;
+	command_t command;
+};
+
+struct print_command_item_data {
+	const char *color, *reset;
+};
+
+static void print_command_item(int i, int selected UNUSED,
+			       struct string_list_item *item,
+			       void *print_command_item_data)
+{
+	struct print_command_item_data *d = print_command_item_data;
+	struct command_item *util = item->util;
+
+	if (!util->prefix_length ||
+	    !is_valid_prefix(item->string, util->prefix_length))
+		printf(" %2d: %s", i + 1, item->string);
+	else
+		printf(" %2d: %s%.*s%s%s", i + 1,
+		       d->color, (int)util->prefix_length, item->string,
+		       d->reset, item->string + util->prefix_length);
+}
+
+static void command_prompt_help(struct add_i_state *s)
+{
+	const char *help_color = s->help_color;
+	color_fprintf_ln(stdout, help_color, "%s", _("Prompt help:"));
+	color_fprintf_ln(stdout, help_color, "1          - %s",
+			 _("select a numbered item"));
+	color_fprintf_ln(stdout, help_color, "foo        - %s",
+			 _("select item based on unique prefix"));
+	color_fprintf_ln(stdout, help_color, "           - %s",
+			 _("(empty) select nothing"));
+}
+
+int run_add_i(struct repository *r, const struct pathspec *ps)
+{
+	struct add_i_state s = { NULL };
+	struct print_command_item_data data = { "[", "]" };
+	struct list_and_choose_options main_loop_opts = {
+		{ 4, N_("*** Commands ***"), print_command_item, &data },
+		N_("What now"), SINGLETON | IMMEDIATE, command_prompt_help
+	};
+	struct {
+		const char *string;
+		command_t command;
+	} command_list[] = {
+		{ "status", run_status },
+		{ "update", run_update },
+		{ "revert", run_revert },
+		{ "add untracked", run_add_untracked },
+		{ "patch", run_patch },
+		{ "diff", run_diff },
+		{ "quit", NULL },
+		{ "help", run_help },
+	};
+	struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT;
+
+	struct print_file_item_data print_file_item_data = {
+		"%12s %12s %s", NULL, NULL,
+		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+	};
+	struct list_and_choose_options opts = {
+		{ 0, NULL, print_file_item, &print_file_item_data },
+		NULL, 0, choose_prompt_help
+	};
+	struct strbuf header = STRBUF_INIT;
+	struct prefix_item_list files = PREFIX_ITEM_LIST_INIT;
+	ssize_t i;
+	int res = 0;
+
+	for (i = 0; i < ARRAY_SIZE(command_list); i++) {
+		struct command_item *util = xcalloc(1, sizeof(*util));
+		util->command = command_list[i].command;
+		string_list_append(&commands.items, command_list[i].string)
+			->util = util;
+	}
+
+	init_add_i_state(&s, r);
+
+	/*
+	 * When color was asked for, use the prompt color for
+	 * highlighting, otherwise use square brackets.
+	 */
+	if (s.use_color) {
+		data.color = s.prompt_color;
+		data.reset = s.reset_color;
+	}
+	print_file_item_data.color = data.color;
+	print_file_item_data.reset = data.reset;
+
+	strbuf_addstr(&header, "     ");
+	strbuf_addf(&header, print_file_item_data.modified_fmt,
+		    _("staged"), _("unstaged"), _("path"));
+	opts.list_opts.header = header.buf;
+
+	discard_index(r->index);
+	if (repo_read_index(r) < 0 ||
+	    repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
+					 NULL, NULL, NULL) < 0)
+		warning(_("could not refresh index"));
+
+	res = run_status(&s, ps, &files, &opts);
+
+	for (;;) {
+		struct command_item *util;
+
+		i = list_and_choose(&s, &commands, &main_loop_opts);
+		if (i < 0 || i >= commands.items.nr)
+			util = NULL;
+		else
+			util = commands.items.items[i].util;
+
+		if (i == LIST_AND_CHOOSE_QUIT || (util && !util->command)) {
+			printf(_("Bye.\n"));
+			res = 0;
+			break;
+		}
+
+		if (util)
+			res = util->command(&s, ps, &files, &opts);
+	}
+
+	prefix_item_list_clear(&files);
+	strbuf_release(&print_file_item_data.buf);
+	strbuf_release(&print_file_item_data.name);
+	strbuf_release(&print_file_item_data.index);
+	strbuf_release(&print_file_item_data.worktree);
+	strbuf_release(&header);
+	prefix_item_list_clear(&commands);
+	clear_add_i_state(&s);
+
+	return res;
+}
diff --git a/add-interactive.h b/add-interactive.h
new file mode 100644
index 0000000000..693f125e8e
--- /dev/null
+++ b/add-interactive.h
@@ -0,0 +1,41 @@
+#ifndef ADD_INTERACTIVE_H
+#define ADD_INTERACTIVE_H
+
+#include "color.h"
+
+struct add_i_state {
+	struct repository *r;
+	int use_color;
+	char header_color[COLOR_MAXLEN];
+	char help_color[COLOR_MAXLEN];
+	char prompt_color[COLOR_MAXLEN];
+	char error_color[COLOR_MAXLEN];
+	char reset_color[COLOR_MAXLEN];
+	char fraginfo_color[COLOR_MAXLEN];
+	char context_color[COLOR_MAXLEN];
+	char file_old_color[COLOR_MAXLEN];
+	char file_new_color[COLOR_MAXLEN];
+
+	int use_single_key;
+	char *interactive_diff_filter, *interactive_diff_algorithm;
+};
+
+void init_add_i_state(struct add_i_state *s, struct repository *r);
+void clear_add_i_state(struct add_i_state *s);
+
+struct repository;
+struct pathspec;
+int run_add_i(struct repository *r, const struct pathspec *ps);
+
+enum add_p_mode {
+	ADD_P_ADD,
+	ADD_P_STASH,
+	ADD_P_RESET,
+	ADD_P_CHECKOUT,
+	ADD_P_WORKTREE,
+};
+
+int run_add_p(struct repository *r, enum add_p_mode mode,
+	      const char *revision, const struct pathspec *ps);
+
+#endif
diff --git a/add-patch.c b/add-patch.c
new file mode 100644
index 0000000000..95c67d8c80
--- /dev/null
+++ b/add-patch.c
@@ -0,0 +1,1820 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "add-interactive.h"
+#include "advice.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "pager.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "strbuf.h"
+#include "sigchain.h"
+#include "run-command.h"
+#include "strvec.h"
+#include "pathspec.h"
+#include "color.h"
+#include "compat/terminal.h"
+#include "prompt.h"
+
+enum prompt_mode_type {
+	PROMPT_MODE_CHANGE = 0, PROMPT_DELETION, PROMPT_ADDITION, PROMPT_HUNK,
+	PROMPT_MODE_MAX, /* must be last */
+};
+
+struct patch_mode {
+	/*
+	 * The magic constant 4 is chosen such that all patch modes
+	 * provide enough space for three command-line arguments followed by a
+	 * trailing `NULL`.
+	 */
+	const char *diff_cmd[4], *apply_args[4], *apply_check_args[4];
+	unsigned is_reverse:1, index_only:1, apply_for_checkout:1;
+	const char *prompt_mode[PROMPT_MODE_MAX];
+	const char *edit_hunk_hint, *help_patch_text;
+};
+
+static struct patch_mode patch_mode_add = {
+	.diff_cmd = { "diff-files", NULL },
+	.apply_args = { "--cached", NULL },
+	.apply_check_args = { "--cached", NULL },
+	.prompt_mode = {
+		N_("Stage mode change [y,n,q,a,d%s,?]? "),
+		N_("Stage deletion [y,n,q,a,d%s,?]? "),
+		N_("Stage addition [y,n,q,a,d%s,?]? "),
+		N_("Stage this hunk [y,n,q,a,d%s,?]? ")
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for staging."),
+	.help_patch_text =
+		N_("y - stage this hunk\n"
+		   "n - do not stage this hunk\n"
+		   "q - quit; do not stage this hunk or any of the remaining "
+			"ones\n"
+		   "a - stage this hunk and all later hunks in the file\n"
+		   "d - do not stage this hunk or any of the later hunks in "
+			"the file\n")
+};
+
+static struct patch_mode patch_mode_stash = {
+	.diff_cmd = { "diff-index", "HEAD", NULL },
+	.apply_args = { "--cached", NULL },
+	.apply_check_args = { "--cached", NULL },
+	.prompt_mode = {
+		N_("Stash mode change [y,n,q,a,d%s,?]? "),
+		N_("Stash deletion [y,n,q,a,d%s,?]? "),
+		N_("Stash addition [y,n,q,a,d%s,?]? "),
+		N_("Stash this hunk [y,n,q,a,d%s,?]? "),
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for stashing."),
+	.help_patch_text =
+		N_("y - stash this hunk\n"
+		   "n - do not stash this hunk\n"
+		   "q - quit; do not stash this hunk or any of the remaining "
+			"ones\n"
+		   "a - stash this hunk and all later hunks in the file\n"
+		   "d - do not stash this hunk or any of the later hunks in "
+			"the file\n"),
+};
+
+static struct patch_mode patch_mode_reset_head = {
+	.diff_cmd = { "diff-index", "--cached", NULL },
+	.apply_args = { "-R", "--cached", NULL },
+	.apply_check_args = { "-R", "--cached", NULL },
+	.is_reverse = 1,
+	.index_only = 1,
+	.prompt_mode = {
+		N_("Unstage mode change [y,n,q,a,d%s,?]? "),
+		N_("Unstage deletion [y,n,q,a,d%s,?]? "),
+		N_("Unstage addition [y,n,q,a,d%s,?]? "),
+		N_("Unstage this hunk [y,n,q,a,d%s,?]? "),
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for unstaging."),
+	.help_patch_text =
+		N_("y - unstage this hunk\n"
+		   "n - do not unstage this hunk\n"
+		   "q - quit; do not unstage this hunk or any of the remaining "
+			"ones\n"
+		   "a - unstage this hunk and all later hunks in the file\n"
+		   "d - do not unstage this hunk or any of the later hunks in "
+			"the file\n"),
+};
+
+static struct patch_mode patch_mode_reset_nothead = {
+	.diff_cmd = { "diff-index", "-R", "--cached", NULL },
+	.apply_args = { "--cached", NULL },
+	.apply_check_args = { "--cached", NULL },
+	.index_only = 1,
+	.prompt_mode = {
+		N_("Apply mode change to index [y,n,q,a,d%s,?]? "),
+		N_("Apply deletion to index [y,n,q,a,d%s,?]? "),
+		N_("Apply addition to index [y,n,q,a,d%s,?]? "),
+		N_("Apply this hunk to index [y,n,q,a,d%s,?]? "),
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for applying."),
+	.help_patch_text =
+		N_("y - apply this hunk to index\n"
+		   "n - do not apply this hunk to index\n"
+		   "q - quit; do not apply this hunk or any of the remaining "
+			"ones\n"
+		   "a - apply this hunk and all later hunks in the file\n"
+		   "d - do not apply this hunk or any of the later hunks in "
+			"the file\n"),
+};
+
+static struct patch_mode patch_mode_checkout_index = {
+	.diff_cmd = { "diff-files", NULL },
+	.apply_args = { "-R", NULL },
+	.apply_check_args = { "-R", NULL },
+	.is_reverse = 1,
+	.prompt_mode = {
+		N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for discarding."),
+	.help_patch_text =
+		N_("y - discard this hunk from worktree\n"
+		   "n - do not discard this hunk from worktree\n"
+		   "q - quit; do not discard this hunk or any of the remaining "
+			"ones\n"
+		   "a - discard this hunk and all later hunks in the file\n"
+		   "d - do not discard this hunk or any of the later hunks in "
+			"the file\n"),
+};
+
+static struct patch_mode patch_mode_checkout_head = {
+	.diff_cmd = { "diff-index", NULL },
+	.apply_for_checkout = 1,
+	.apply_check_args = { "-R", NULL },
+	.is_reverse = 1,
+	.prompt_mode = {
+		N_("Discard mode change from index and worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard deletion from index and worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard addition from index and worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard this hunk from index and worktree [y,n,q,a,d%s,?]? "),
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for discarding."),
+	.help_patch_text =
+		N_("y - discard this hunk from index and worktree\n"
+		   "n - do not discard this hunk from index and worktree\n"
+		   "q - quit; do not discard this hunk or any of the remaining "
+			"ones\n"
+		   "a - discard this hunk and all later hunks in the file\n"
+		   "d - do not discard this hunk or any of the later hunks in "
+			"the file\n"),
+};
+
+static struct patch_mode patch_mode_checkout_nothead = {
+	.diff_cmd = { "diff-index", "-R", NULL },
+	.apply_for_checkout = 1,
+	.apply_check_args = { NULL },
+	.prompt_mode = {
+		N_("Apply mode change to index and worktree [y,n,q,a,d%s,?]? "),
+		N_("Apply deletion to index and worktree [y,n,q,a,d%s,?]? "),
+		N_("Apply addition to index and worktree [y,n,q,a,d%s,?]? "),
+		N_("Apply this hunk to index and worktree [y,n,q,a,d%s,?]? "),
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for applying."),
+	.help_patch_text =
+		N_("y - apply this hunk to index and worktree\n"
+		   "n - do not apply this hunk to index and worktree\n"
+		   "q - quit; do not apply this hunk or any of the remaining "
+			"ones\n"
+		   "a - apply this hunk and all later hunks in the file\n"
+		   "d - do not apply this hunk or any of the later hunks in "
+			"the file\n"),
+};
+
+static struct patch_mode patch_mode_worktree_head = {
+	.diff_cmd = { "diff-index", NULL },
+	.apply_args = { "-R", NULL },
+	.apply_check_args = { "-R", NULL },
+	.is_reverse = 1,
+	.prompt_mode = {
+		N_("Discard mode change from worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard deletion from worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard addition from worktree [y,n,q,a,d%s,?]? "),
+		N_("Discard this hunk from worktree [y,n,q,a,d%s,?]? "),
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for discarding."),
+	.help_patch_text =
+		N_("y - discard this hunk from worktree\n"
+		   "n - do not discard this hunk from worktree\n"
+		   "q - quit; do not discard this hunk or any of the remaining "
+			"ones\n"
+		   "a - discard this hunk and all later hunks in the file\n"
+		   "d - do not discard this hunk or any of the later hunks in "
+			"the file\n"),
+};
+
+static struct patch_mode patch_mode_worktree_nothead = {
+	.diff_cmd = { "diff-index", "-R", NULL },
+	.apply_args = { NULL },
+	.apply_check_args = { NULL },
+	.prompt_mode = {
+		N_("Apply mode change to worktree [y,n,q,a,d%s,?]? "),
+		N_("Apply deletion to worktree [y,n,q,a,d%s,?]? "),
+		N_("Apply addition to worktree [y,n,q,a,d%s,?]? "),
+		N_("Apply this hunk to worktree [y,n,q,a,d%s,?]? "),
+	},
+	.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
+			     "will immediately be marked for applying."),
+	.help_patch_text =
+		N_("y - apply this hunk to worktree\n"
+		   "n - do not apply this hunk to worktree\n"
+		   "q - quit; do not apply this hunk or any of the remaining "
+			"ones\n"
+		   "a - apply this hunk and all later hunks in the file\n"
+		   "d - do not apply this hunk or any of the later hunks in "
+			"the file\n"),
+};
+
+struct hunk_header {
+	unsigned long old_offset, old_count, new_offset, new_count;
+	/*
+	 * Start/end offsets to the extra text after the second `@@` in the
+	 * hunk header, e.g. the function signature. This is expected to
+	 * include the newline.
+	 */
+	size_t extra_start, extra_end, colored_extra_start, colored_extra_end;
+	unsigned suppress_colored_line_range:1;
+};
+
+struct hunk {
+	size_t start, end, colored_start, colored_end, splittable_into;
+	ssize_t delta;
+	enum { UNDECIDED_HUNK = 0, SKIP_HUNK, USE_HUNK } use;
+	struct hunk_header header;
+};
+
+struct add_p_state {
+	struct add_i_state s;
+	struct strbuf answer, buf;
+
+	/* parsed diff */
+	struct strbuf plain, colored;
+	struct file_diff {
+		struct hunk head;
+		struct hunk *hunk;
+		size_t hunk_nr, hunk_alloc;
+		unsigned deleted:1, added:1, mode_change:1,binary:1;
+	} *file_diff;
+	size_t file_diff_nr;
+
+	/* patch mode */
+	struct patch_mode *mode;
+	const char *revision;
+};
+
+static void add_p_state_clear(struct add_p_state *s)
+{
+	size_t i;
+
+	strbuf_release(&s->answer);
+	strbuf_release(&s->buf);
+	strbuf_release(&s->plain);
+	strbuf_release(&s->colored);
+	for (i = 0; i < s->file_diff_nr; i++)
+		free(s->file_diff[i].hunk);
+	free(s->file_diff);
+	clear_add_i_state(&s->s);
+}
+
+__attribute__((format (printf, 2, 3)))
+static void err(struct add_p_state *s, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	fputs(s->s.error_color, stdout);
+	vprintf(fmt, args);
+	puts(s->s.reset_color);
+	va_end(args);
+}
+
+LAST_ARG_MUST_BE_NULL
+static void setup_child_process(struct add_p_state *s,
+				struct child_process *cp, ...)
+{
+	va_list ap;
+	const char *arg;
+
+	va_start(ap, cp);
+	while ((arg = va_arg(ap, const char *)))
+		strvec_push(&cp->args, arg);
+	va_end(ap);
+
+	cp->git_cmd = 1;
+	strvec_pushf(&cp->env,
+		     INDEX_ENVIRONMENT "=%s", s->s.r->index_file);
+}
+
+static int parse_range(const char **p,
+		       unsigned long *offset, unsigned long *count)
+{
+	char *pend;
+
+	*offset = strtoul(*p, &pend, 10);
+	if (pend == *p)
+		return -1;
+	if (*pend != ',') {
+		*count = 1;
+		*p = pend;
+		return 0;
+	}
+	*count = strtoul(pend + 1, (char **)p, 10);
+	return *p == pend + 1 ? -1 : 0;
+}
+
+static int parse_hunk_header(struct add_p_state *s, struct hunk *hunk)
+{
+	struct hunk_header *header = &hunk->header;
+	const char *line = s->plain.buf + hunk->start, *p = line;
+	char *eol = memchr(p, '\n', s->plain.len - hunk->start);
+
+	if (!eol)
+		eol = s->plain.buf + s->plain.len;
+
+	if (!skip_prefix(p, "@@ -", &p) ||
+	    parse_range(&p, &header->old_offset, &header->old_count) < 0 ||
+	    !skip_prefix(p, " +", &p) ||
+	    parse_range(&p, &header->new_offset, &header->new_count) < 0 ||
+	    !skip_prefix(p, " @@", &p))
+		return error(_("could not parse hunk header '%.*s'"),
+			     (int)(eol - line), line);
+
+	hunk->start = eol - s->plain.buf + (*eol == '\n');
+	header->extra_start = p - s->plain.buf;
+	header->extra_end = hunk->start;
+
+	if (!s->colored.len) {
+		header->colored_extra_start = header->colored_extra_end = 0;
+		return 0;
+	}
+
+	/* Now find the extra text in the colored diff */
+	line = s->colored.buf + hunk->colored_start;
+	eol = memchr(line, '\n', s->colored.len - hunk->colored_start);
+	if (!eol)
+		eol = s->colored.buf + s->colored.len;
+	p = memmem(line, eol - line, "@@ -", 4);
+	if (p && (p = memmem(p + 4, eol - p - 4, " @@", 3))) {
+		header->colored_extra_start = p + 3 - s->colored.buf;
+	} else {
+		/* could not parse colored hunk header, leave as-is */
+		header->colored_extra_start = hunk->colored_start;
+		header->suppress_colored_line_range = 1;
+	}
+	hunk->colored_start = eol - s->colored.buf + (*eol == '\n');
+	header->colored_extra_end = hunk->colored_start;
+
+	return 0;
+}
+
+static int is_octal(const char *p, size_t len)
+{
+	if (!len)
+		return 0;
+
+	while (len--)
+		if (*p < '0' || *(p++) > '7')
+			return 0;
+	return 1;
+}
+
+static void complete_file(char marker, struct hunk *hunk)
+{
+	if (marker == '-' || marker == '+')
+		/*
+		 * Last hunk ended in non-context line (i.e. it
+		 * appended lines to the file, so there are no
+		 * trailing context lines).
+		 */
+		hunk->splittable_into++;
+}
+
+/* Empty context lines may omit the leading ' ' */
+static int normalize_marker(const char *p)
+{
+	return p[0] == '\n' || (p[0] == '\r' && p[1] == '\n') ? ' ' : p[0];
+}
+
+static int parse_diff(struct add_p_state *s, const struct pathspec *ps)
+{
+	struct strvec args = STRVEC_INIT;
+	const char *diff_algorithm = s->s.interactive_diff_algorithm;
+	struct strbuf *plain = &s->plain, *colored = NULL;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	char *p, *pend, *colored_p = NULL, *colored_pend = NULL, marker = '\0';
+	size_t file_diff_alloc = 0, i, color_arg_index;
+	struct file_diff *file_diff = NULL;
+	struct hunk *hunk = NULL;
+	int res;
+
+	strvec_pushv(&args, s->mode->diff_cmd);
+	if (diff_algorithm)
+		strvec_pushf(&args, "--diff-algorithm=%s", diff_algorithm);
+	if (s->revision) {
+		struct object_id oid;
+		strvec_push(&args,
+			    /* could be on an unborn branch */
+			    !strcmp("HEAD", s->revision) &&
+			    repo_get_oid(the_repository, "HEAD", &oid) ?
+			    empty_tree_oid_hex(the_repository->hash_algo) : s->revision);
+	}
+	color_arg_index = args.nr;
+	/* Use `--no-color` explicitly, just in case `diff.color = always`. */
+	strvec_pushl(&args, "--no-color", "--ignore-submodules=dirty", "-p",
+		     "--", NULL);
+	for (i = 0; i < ps->nr; i++)
+		strvec_push(&args, ps->items[i].original);
+
+	setup_child_process(s, &cp, NULL);
+	strvec_pushv(&cp.args, args.v);
+	res = capture_command(&cp, plain, 0);
+	if (res) {
+		strvec_clear(&args);
+		return error(_("could not parse diff"));
+	}
+	if (!plain->len) {
+		strvec_clear(&args);
+		return 0;
+	}
+	strbuf_complete_line(plain);
+
+	if (want_color_fd(1, -1)) {
+		struct child_process colored_cp = CHILD_PROCESS_INIT;
+		const char *diff_filter = s->s.interactive_diff_filter;
+
+		setup_child_process(s, &colored_cp, NULL);
+		xsnprintf((char *)args.v[color_arg_index], 8, "--color");
+		strvec_pushv(&colored_cp.args, args.v);
+		colored = &s->colored;
+		res = capture_command(&colored_cp, colored, 0);
+		strvec_clear(&args);
+		if (res)
+			return error(_("could not parse colored diff"));
+
+		if (diff_filter) {
+			struct child_process filter_cp = CHILD_PROCESS_INIT;
+
+			setup_child_process(s, &filter_cp,
+					    diff_filter, NULL);
+			filter_cp.git_cmd = 0;
+			filter_cp.use_shell = 1;
+			strbuf_reset(&s->buf);
+			if (pipe_command(&filter_cp,
+					 colored->buf, colored->len,
+					 &s->buf, colored->len,
+					 NULL, 0) < 0)
+				return error(_("failed to run '%s'"),
+					     diff_filter);
+			strbuf_swap(colored, &s->buf);
+		}
+
+		strbuf_complete_line(colored);
+		colored_p = colored->buf;
+		colored_pend = colored_p + colored->len;
+	}
+	strvec_clear(&args);
+
+	/* parse files and hunks */
+	p = plain->buf;
+	pend = p + plain->len;
+	while (p != pend) {
+		char *eol = memchr(p, '\n', pend - p);
+		const char *deleted = NULL, *mode_change = NULL;
+		char ch = normalize_marker(p);
+
+		if (!eol)
+			eol = pend;
+
+		if (starts_with(p, "diff ") ||
+		    starts_with(p, "* Unmerged path ")) {
+			complete_file(marker, hunk);
+			ALLOC_GROW_BY(s->file_diff, s->file_diff_nr, 1,
+				   file_diff_alloc);
+			file_diff = s->file_diff + s->file_diff_nr - 1;
+			hunk = &file_diff->head;
+			hunk->start = p - plain->buf;
+			if (colored_p)
+				hunk->colored_start = colored_p - colored->buf;
+			marker = '\0';
+		} else if (p == plain->buf)
+			BUG("diff starts with unexpected line:\n"
+			    "%.*s\n", (int)(eol - p), p);
+		else if (file_diff->deleted)
+			; /* keep the rest of the file in a single "hunk" */
+		else if (starts_with(p, "@@ ") ||
+			 (hunk == &file_diff->head &&
+			  (skip_prefix(p, "deleted file", &deleted)))) {
+			if (marker == '-' || marker == '+')
+				/*
+				 * Should not happen; previous hunk did not end
+				 * in a context line? Handle it anyway.
+				 */
+				hunk->splittable_into++;
+
+			ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
+				   file_diff->hunk_alloc);
+			hunk = file_diff->hunk + file_diff->hunk_nr - 1;
+
+			hunk->start = p - plain->buf;
+			if (colored)
+				hunk->colored_start = colored_p - colored->buf;
+
+			if (deleted)
+				file_diff->deleted = 1;
+			else if (parse_hunk_header(s, hunk) < 0)
+				return -1;
+
+			/*
+			 * Start counting into how many hunks this one can be
+			 * split
+			 */
+			marker = ch;
+		} else if (hunk == &file_diff->head &&
+			   starts_with(p, "new file")) {
+			file_diff->added = 1;
+		} else if (hunk == &file_diff->head &&
+			   skip_prefix(p, "old mode ", &mode_change) &&
+			   is_octal(mode_change, eol - mode_change)) {
+			if (file_diff->mode_change)
+				BUG("double mode change?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+			if (file_diff->hunk_nr)
+				BUG("mode change in the middle?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+
+			/*
+			 * Do *not* change `hunk`: the mode change pseudo-hunk
+			 * is _part of_ the header "hunk".
+			 */
+			file_diff->mode_change = 1;
+			ALLOC_GROW_BY(file_diff->hunk, file_diff->hunk_nr, 1,
+				   file_diff->hunk_alloc);
+			file_diff->hunk->start = p - plain->buf;
+			if (colored_p)
+				file_diff->hunk->colored_start =
+					colored_p - colored->buf;
+		} else if (hunk == &file_diff->head &&
+			   skip_prefix(p, "new mode ", &mode_change) &&
+			   is_octal(mode_change, eol - mode_change)) {
+
+			/*
+			 * Extend the "mode change" pseudo-hunk to include also
+			 * the "new mode" line.
+			 */
+			if (!file_diff->mode_change)
+				BUG("'new mode' without 'old mode'?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+			if (file_diff->hunk_nr != 1)
+				BUG("mode change in the middle?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+			if (p - plain->buf != file_diff->hunk->end)
+				BUG("'new mode' does not immediately follow "
+				    "'old mode'?\n\n%.*s",
+				    (int)(eol - plain->buf), plain->buf);
+		} else if (hunk == &file_diff->head &&
+			   starts_with(p, "Binary files "))
+			file_diff->binary = 1;
+
+		if (!!file_diff->deleted + !!file_diff->added +
+		    !!file_diff->mode_change > 1)
+			BUG("diff can only contain delete *or* add *or* a "
+			    "mode change?!?\n%.*s",
+			    (int)(eol - (plain->buf + file_diff->head.start)),
+			    plain->buf + file_diff->head.start);
+
+		if ((marker == '-' || marker == '+') && ch == ' ')
+			hunk->splittable_into++;
+		if (marker && ch != '\\')
+			marker = ch;
+
+		p = eol == pend ? pend : eol + 1;
+		hunk->end = p - plain->buf;
+
+		if (colored) {
+			char *colored_eol = memchr(colored_p, '\n',
+						   colored_pend - colored_p);
+			if (colored_eol)
+				colored_p = colored_eol + 1;
+			else if (p != pend)
+				/* non-colored has more lines? */
+				goto mismatched_output;
+			else if (colored_p == colored_pend)
+				/* last line has no matching colored one? */
+				goto mismatched_output;
+			else
+				colored_p = colored_pend;
+
+			hunk->colored_end = colored_p - colored->buf;
+		}
+
+		if (mode_change) {
+			if (file_diff->hunk_nr != 1)
+				BUG("mode change in hunk #%d???",
+				    (int)file_diff->hunk_nr);
+			/* Adjust the end of the "mode change" pseudo-hunk */
+			file_diff->hunk->end = hunk->end;
+			if (colored)
+				file_diff->hunk->colored_end = hunk->colored_end;
+		}
+	}
+	complete_file(marker, hunk);
+
+	/* non-colored shorter than colored? */
+	if (colored_p != colored_pend) {
+mismatched_output:
+		error(_("mismatched output from interactive.diffFilter"));
+		advise(_("Your filter must maintain a one-to-one correspondence\n"
+			 "between its input and output lines."));
+		return -1;
+	}
+
+	return 0;
+}
+
+static size_t find_next_line(struct strbuf *sb, size_t offset)
+{
+	char *eol;
+
+	if (offset >= sb->len)
+		BUG("looking for next line beyond buffer (%d >= %d)\n%s",
+		    (int)offset, (int)sb->len, sb->buf);
+
+	eol = memchr(sb->buf + offset, '\n', sb->len - offset);
+	if (!eol)
+		return sb->len;
+	return eol - sb->buf + 1;
+}
+
+static void render_hunk(struct add_p_state *s, struct hunk *hunk,
+			ssize_t delta, int colored, struct strbuf *out)
+{
+	struct hunk_header *header = &hunk->header;
+
+	if (hunk->header.old_offset != 0 || hunk->header.new_offset != 0) {
+		/*
+		 * Generate the hunk header dynamically, except for special
+		 * hunks (such as the diff header).
+		 */
+		const char *p;
+		size_t len;
+		unsigned long old_offset = header->old_offset;
+		unsigned long new_offset = header->new_offset;
+
+		if (!colored) {
+			p = s->plain.buf + header->extra_start;
+			len = header->extra_end - header->extra_start;
+		} else if (header->suppress_colored_line_range) {
+			strbuf_add(out,
+				   s->colored.buf + header->colored_extra_start,
+				   header->colored_extra_end -
+				   header->colored_extra_start);
+
+			strbuf_add(out, s->colored.buf + hunk->colored_start,
+				   hunk->colored_end - hunk->colored_start);
+			return;
+		} else {
+			strbuf_addstr(out, s->s.fraginfo_color);
+			p = s->colored.buf + header->colored_extra_start;
+			len = header->colored_extra_end
+				- header->colored_extra_start;
+		}
+
+		if (s->mode->is_reverse)
+			old_offset -= delta;
+		else
+			new_offset += delta;
+
+		strbuf_addf(out, "@@ -%lu", old_offset);
+		if (header->old_count != 1)
+			strbuf_addf(out, ",%lu", header->old_count);
+		strbuf_addf(out, " +%lu", new_offset);
+		if (header->new_count != 1)
+			strbuf_addf(out, ",%lu", header->new_count);
+		strbuf_addstr(out, " @@");
+
+		if (len)
+			strbuf_add(out, p, len);
+		else if (colored)
+			strbuf_addf(out, "%s\n", s->s.reset_color);
+		else
+			strbuf_addch(out, '\n');
+	}
+
+	if (colored)
+		strbuf_add(out, s->colored.buf + hunk->colored_start,
+			   hunk->colored_end - hunk->colored_start);
+	else
+		strbuf_add(out, s->plain.buf + hunk->start,
+			   hunk->end - hunk->start);
+}
+
+static void render_diff_header(struct add_p_state *s,
+			       struct file_diff *file_diff, int colored,
+			       struct strbuf *out)
+{
+	/*
+	 * If there was a mode change, the first hunk is a pseudo hunk that
+	 * corresponds to the mode line in the header. If the user did not want
+	 * to stage that "hunk", we actually have to cut it out from the header.
+	 */
+	int skip_mode_change =
+		file_diff->mode_change && file_diff->hunk->use != USE_HUNK;
+	struct hunk *head = &file_diff->head, *first = file_diff->hunk;
+
+	if (!skip_mode_change) {
+		render_hunk(s, head, 0, colored, out);
+		return;
+	}
+
+	if (colored) {
+		const char *p = s->colored.buf;
+
+		strbuf_add(out, p + head->colored_start,
+			    first->colored_start - head->colored_start);
+		strbuf_add(out, p + first->colored_end,
+			    head->colored_end - first->colored_end);
+	} else {
+		const char *p = s->plain.buf;
+
+		strbuf_add(out, p + head->start, first->start - head->start);
+		strbuf_add(out, p + first->end, head->end - first->end);
+	}
+}
+
+/* Coalesce hunks again that were split */
+static int merge_hunks(struct add_p_state *s, struct file_diff *file_diff,
+		       size_t *hunk_index, int use_all, struct hunk *merged)
+{
+	size_t i = *hunk_index, delta;
+	struct hunk *hunk = file_diff->hunk + i;
+	/* `header` corresponds to the merged hunk */
+	struct hunk_header *header = &merged->header, *next;
+
+	if (!use_all && hunk->use != USE_HUNK)
+		return 0;
+
+	*merged = *hunk;
+	/* We simply skip the colored part (if any) when merging hunks */
+	merged->colored_start = merged->colored_end = 0;
+
+	for (; i + 1 < file_diff->hunk_nr; i++) {
+		hunk++;
+		next = &hunk->header;
+
+		/*
+		 * Stop merging hunks when:
+		 *
+		 * - the hunk is not selected for use, or
+		 * - the hunk does not overlap with the already-merged hunk(s)
+		 */
+		if ((!use_all && hunk->use != USE_HUNK) ||
+		    header->new_offset >= next->new_offset + merged->delta ||
+		    header->new_offset + header->new_count
+		    < next->new_offset + merged->delta)
+			break;
+
+		/*
+		 * If the hunks were not edited, and overlap, we can simply
+		 * extend the line range.
+		 */
+		if (merged->start < hunk->start && merged->end > hunk->start) {
+			merged->end = hunk->end;
+			merged->colored_end = hunk->colored_end;
+			delta = 0;
+		} else {
+			const char *plain = s->plain.buf;
+			size_t  overlapping_line_count = header->new_offset
+				+ header->new_count - merged->delta
+				- next->new_offset;
+			size_t overlap_end = hunk->start;
+			size_t overlap_start = overlap_end;
+			size_t overlap_next, len, j;
+
+			/*
+			 * One of the hunks was edited: the modified hunk was
+			 * appended to the strbuf `s->plain`.
+			 *
+			 * Let's ensure that at least the last context line of
+			 * the first hunk overlaps with the corresponding line
+			 * of the second hunk, and then merge.
+			 */
+			for (j = 0; j < overlapping_line_count; j++) {
+				overlap_next = find_next_line(&s->plain,
+							      overlap_end);
+
+				if (overlap_next > hunk->end)
+					BUG("failed to find %d context lines "
+					    "in:\n%.*s",
+					    (int)overlapping_line_count,
+					    (int)(hunk->end - hunk->start),
+					    plain + hunk->start);
+
+				if (normalize_marker(&plain[overlap_end]) != ' ')
+					return error(_("expected context line "
+						       "#%d in\n%.*s"),
+						     (int)(j + 1),
+						     (int)(hunk->end
+							   - hunk->start),
+						     plain + hunk->start);
+
+				overlap_start = overlap_end;
+				overlap_end = overlap_next;
+			}
+			len = overlap_end - overlap_start;
+
+			if (len > merged->end - merged->start ||
+			    memcmp(plain + merged->end - len,
+				   plain + overlap_start, len))
+				return error(_("hunks do not overlap:\n%.*s\n"
+					       "\tdoes not end with:\n%.*s"),
+					     (int)(merged->end - merged->start),
+					     plain + merged->start,
+					     (int)len, plain + overlap_start);
+
+			/*
+			 * Since the start-end ranges are not adjacent, we
+			 * cannot simply take the union of the ranges. To
+			 * address that, we temporarily append the union of the
+			 * lines to the `plain` strbuf.
+			 */
+			if (merged->end != s->plain.len) {
+				size_t start = s->plain.len;
+
+				strbuf_add(&s->plain, plain + merged->start,
+					   merged->end - merged->start);
+				plain = s->plain.buf;
+				merged->start = start;
+				merged->end = s->plain.len;
+			}
+
+			strbuf_add(&s->plain,
+				   plain + overlap_end,
+				   hunk->end - overlap_end);
+			merged->end = s->plain.len;
+			merged->splittable_into += hunk->splittable_into;
+			delta = merged->delta;
+			merged->delta += hunk->delta;
+		}
+
+		header->old_count = next->old_offset + next->old_count
+			- header->old_offset;
+		header->new_count = next->new_offset + delta
+			+ next->new_count - header->new_offset;
+	}
+
+	if (i == *hunk_index)
+		return 0;
+
+	*hunk_index = i;
+	return 1;
+}
+
+static void reassemble_patch(struct add_p_state *s,
+			     struct file_diff *file_diff, int use_all,
+			     struct strbuf *out)
+{
+	struct hunk *hunk;
+	size_t save_len = s->plain.len, i;
+	ssize_t delta = 0;
+
+	render_diff_header(s, file_diff, 0, out);
+
+	for (i = file_diff->mode_change; i < file_diff->hunk_nr; i++) {
+		struct hunk merged = { 0 };
+
+		hunk = file_diff->hunk + i;
+		if (!use_all && hunk->use != USE_HUNK)
+			delta += hunk->header.old_count
+				- hunk->header.new_count;
+		else {
+			/* merge overlapping hunks into a temporary hunk */
+			if (merge_hunks(s, file_diff, &i, use_all, &merged))
+				hunk = &merged;
+
+			render_hunk(s, hunk, delta, 0, out);
+
+			/*
+			 * In case `merge_hunks()` used `plain` as a scratch
+			 * pad (this happens when an edited hunk had to be
+			 * coalesced with another hunk).
+			 */
+			strbuf_setlen(&s->plain, save_len);
+
+			delta += hunk->delta;
+		}
+	}
+}
+
+static int split_hunk(struct add_p_state *s, struct file_diff *file_diff,
+		       size_t hunk_index)
+{
+	int colored = !!s->colored.len, first = 1;
+	struct hunk *hunk = file_diff->hunk + hunk_index;
+	size_t splittable_into;
+	size_t end, colored_end, current, colored_current = 0, context_line_count;
+	struct hunk_header remaining, *header;
+	char marker, ch;
+
+	if (hunk_index >= file_diff->hunk_nr)
+		BUG("invalid hunk index: %d (must be >= 0 and < %d)",
+		    (int)hunk_index, (int)file_diff->hunk_nr);
+
+	if (hunk->splittable_into < 2)
+		return 0;
+	splittable_into = hunk->splittable_into;
+
+	end = hunk->end;
+	colored_end = hunk->colored_end;
+
+	remaining = hunk->header;
+
+	file_diff->hunk_nr += splittable_into - 1;
+	ALLOC_GROW(file_diff->hunk, file_diff->hunk_nr, file_diff->hunk_alloc);
+	if (hunk_index + splittable_into < file_diff->hunk_nr)
+		memmove(file_diff->hunk + hunk_index + splittable_into,
+			file_diff->hunk + hunk_index + 1,
+			(file_diff->hunk_nr - hunk_index - splittable_into)
+			* sizeof(*hunk));
+	hunk = file_diff->hunk + hunk_index;
+	hunk->splittable_into = 1;
+	memset(hunk + 1, 0, (splittable_into - 1) * sizeof(*hunk));
+
+	header = &hunk->header;
+	header->old_count = header->new_count = 0;
+
+	current = hunk->start;
+	if (colored)
+		colored_current = hunk->colored_start;
+	marker = '\0';
+	context_line_count = 0;
+
+	while (splittable_into > 1) {
+		ch = normalize_marker(&s->plain.buf[current]);
+
+		if (!ch)
+			BUG("buffer overrun while splitting hunks");
+
+		/*
+		 * Is this the first context line after a chain of +/- lines?
+		 * Then record the start of the next split hunk.
+		 */
+		if ((marker == '-' || marker == '+') && ch == ' ') {
+			first = 0;
+			hunk[1].start = current;
+			if (colored)
+				hunk[1].colored_start = colored_current;
+			context_line_count = 0;
+		}
+
+		/*
+		 * Was the previous line a +/- one? Alternatively, is this the
+		 * first line (and not a +/- one)?
+		 *
+		 * Then just increment the appropriate counter and continue
+		 * with the next line.
+		 */
+		if (marker != ' ' || (ch != '-' && ch != '+')) {
+next_hunk_line:
+			/* Comment lines are attached to the previous line */
+			if (ch == '\\')
+				ch = marker ? marker : ' ';
+
+			/* current hunk not done yet */
+			if (ch == ' ')
+				context_line_count++;
+			else if (ch == '-')
+				header->old_count++;
+			else if (ch == '+')
+				header->new_count++;
+			else
+				BUG("unhandled diff marker: '%c'", ch);
+			marker = ch;
+			current = find_next_line(&s->plain, current);
+			if (colored)
+				colored_current =
+					find_next_line(&s->colored,
+						       colored_current);
+			continue;
+		}
+
+		/*
+		 * We got us the start of a new hunk!
+		 *
+		 * This is a context line, so it is shared with the previous
+		 * hunk, if any.
+		 */
+
+		if (first) {
+			if (header->old_count || header->new_count)
+				BUG("counts are off: %d/%d",
+				    (int)header->old_count,
+				    (int)header->new_count);
+
+			header->old_count = context_line_count;
+			header->new_count = context_line_count;
+			context_line_count = 0;
+			first = 0;
+			goto next_hunk_line;
+		}
+
+		remaining.old_offset += header->old_count;
+		remaining.old_count -= header->old_count;
+		remaining.new_offset += header->new_count;
+		remaining.new_count -= header->new_count;
+
+		/* initialize next hunk header's offsets */
+		hunk[1].header.old_offset =
+			header->old_offset + header->old_count;
+		hunk[1].header.new_offset =
+			header->new_offset + header->new_count;
+
+		/* add one split hunk */
+		header->old_count += context_line_count;
+		header->new_count += context_line_count;
+
+		hunk->end = current;
+		if (colored)
+			hunk->colored_end = colored_current;
+
+		hunk++;
+		hunk->splittable_into = 1;
+		hunk->use = hunk[-1].use;
+		header = &hunk->header;
+
+		header->old_count = header->new_count = context_line_count;
+		context_line_count = 0;
+
+		splittable_into--;
+		marker = ch;
+	}
+
+	/* last hunk simply gets the rest */
+	if (header->old_offset != remaining.old_offset)
+		BUG("miscounted old_offset: %lu != %lu",
+		    header->old_offset, remaining.old_offset);
+	if (header->new_offset != remaining.new_offset)
+		BUG("miscounted new_offset: %lu != %lu",
+		    header->new_offset, remaining.new_offset);
+	header->old_count = remaining.old_count;
+	header->new_count = remaining.new_count;
+	hunk->end = end;
+	if (colored)
+		hunk->colored_end = colored_end;
+
+	return 0;
+}
+
+static void recolor_hunk(struct add_p_state *s, struct hunk *hunk)
+{
+	const char *plain = s->plain.buf;
+	size_t current, eol, next;
+
+	if (!s->colored.len)
+		return;
+
+	hunk->colored_start = s->colored.len;
+	for (current = hunk->start; current < hunk->end; ) {
+		for (eol = current; eol < hunk->end; eol++)
+			if (plain[eol] == '\n')
+				break;
+		next = eol + (eol < hunk->end);
+		if (eol > current && plain[eol - 1] == '\r')
+			eol--;
+
+		strbuf_addstr(&s->colored,
+			      plain[current] == '-' ?
+			      s->s.file_old_color :
+			      plain[current] == '+' ?
+			      s->s.file_new_color :
+			      s->s.context_color);
+		strbuf_add(&s->colored, plain + current, eol - current);
+		strbuf_addstr(&s->colored, s->s.reset_color);
+		if (next > eol)
+			strbuf_add(&s->colored, plain + eol, next - eol);
+		current = next;
+	}
+	hunk->colored_end = s->colored.len;
+}
+
+static int edit_hunk_manually(struct add_p_state *s, struct hunk *hunk)
+{
+	size_t i;
+
+	strbuf_reset(&s->buf);
+	strbuf_commented_addf(&s->buf, comment_line_str,
+			      _("Manual hunk edit mode -- see bottom for "
+				"a quick guide.\n"));
+	render_hunk(s, hunk, 0, 0, &s->buf);
+	strbuf_commented_addf(&s->buf, comment_line_str,
+			      _("---\n"
+				"To remove '%c' lines, make them ' ' lines "
+				"(context).\n"
+				"To remove '%c' lines, delete them.\n"
+				"Lines starting with %s will be removed.\n"),
+			      s->mode->is_reverse ? '+' : '-',
+			      s->mode->is_reverse ? '-' : '+',
+			      comment_line_str);
+	strbuf_commented_addf(&s->buf, comment_line_str, "%s",
+			      _(s->mode->edit_hunk_hint));
+	/*
+	 * TRANSLATORS: 'it' refers to the patch mentioned in the previous
+	 * messages.
+	 */
+	strbuf_commented_addf(&s->buf, comment_line_str,
+			      _("If it does not apply cleanly, you will be "
+				"given an opportunity to\n"
+				"edit again.  If all lines of the hunk are "
+				"removed, then the edit is\n"
+				"aborted and the hunk is left unchanged.\n"));
+
+	if (strbuf_edit_interactively(the_repository, &s->buf,
+				      "addp-hunk-edit.diff", NULL) < 0)
+		return -1;
+
+	/* strip out commented lines */
+	hunk->start = s->plain.len;
+	for (i = 0; i < s->buf.len; ) {
+		size_t next = find_next_line(&s->buf, i);
+
+		if (!starts_with(s->buf.buf + i, comment_line_str))
+			strbuf_add(&s->plain, s->buf.buf + i, next - i);
+		i = next;
+	}
+
+	hunk->end = s->plain.len;
+	if (hunk->end == hunk->start)
+		/* The user aborted editing by deleting everything */
+		return 0;
+
+	recolor_hunk(s, hunk);
+
+	/*
+	 * If the hunk header is intact, parse it, otherwise simply use the
+	 * hunk header prior to editing (which will adjust `hunk->start` to
+	 * skip the hunk header).
+	 */
+	if (s->plain.buf[hunk->start] == '@' &&
+	    parse_hunk_header(s, hunk) < 0)
+		return error(_("could not parse hunk header"));
+
+	return 1;
+}
+
+static ssize_t recount_edited_hunk(struct add_p_state *s, struct hunk *hunk,
+				   size_t orig_old_count, size_t orig_new_count)
+{
+	struct hunk_header *header = &hunk->header;
+	size_t i;
+
+	header->old_count = header->new_count = 0;
+	for (i = hunk->start; i < hunk->end; ) {
+		switch(normalize_marker(&s->plain.buf[i])) {
+		case '-':
+			header->old_count++;
+			break;
+		case '+':
+			header->new_count++;
+			break;
+		case ' ':
+			header->old_count++;
+			header->new_count++;
+			break;
+		}
+
+		i = find_next_line(&s->plain, i);
+	}
+
+	return orig_old_count - orig_new_count
+		- header->old_count + header->new_count;
+}
+
+static int run_apply_check(struct add_p_state *s,
+			   struct file_diff *file_diff)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	strbuf_reset(&s->buf);
+	reassemble_patch(s, file_diff, 1, &s->buf);
+
+	setup_child_process(s, &cp,
+			    "apply", "--check", NULL);
+	strvec_pushv(&cp.args, s->mode->apply_check_args);
+	if (pipe_command(&cp, s->buf.buf, s->buf.len, NULL, 0, NULL, 0))
+		return error(_("'git apply --cached' failed"));
+
+	return 0;
+}
+
+static int read_single_character(struct add_p_state *s)
+{
+	if (s->s.use_single_key) {
+		int res = read_key_without_echo(&s->answer);
+		printf("%s\n", res == EOF ? "" : s->answer.buf);
+		return res;
+	}
+
+	if (git_read_line_interactively(&s->answer) == EOF)
+		return EOF;
+	return 0;
+}
+
+static int prompt_yesno(struct add_p_state *s, const char *prompt)
+{
+	for (;;) {
+		color_fprintf(stdout, s->s.prompt_color, "%s", _(prompt));
+		fflush(stdout);
+		if (read_single_character(s) == EOF)
+			return -1;
+		/* do not limit to 1-byte input to allow 'no' etc. */
+		switch (tolower(s->answer.buf[0])) {
+		case 'n': return 0;
+		case 'y': return 1;
+		}
+	}
+}
+
+static int edit_hunk_loop(struct add_p_state *s,
+			  struct file_diff *file_diff, struct hunk *hunk)
+{
+	size_t plain_len = s->plain.len, colored_len = s->colored.len;
+	struct hunk backup;
+
+	backup = *hunk;
+
+	for (;;) {
+		int res = edit_hunk_manually(s, hunk);
+		if (res == 0) {
+			/* abandoned */
+			*hunk = backup;
+			return -1;
+		}
+
+		if (res > 0) {
+			hunk->delta +=
+				recount_edited_hunk(s, hunk,
+						    backup.header.old_count,
+						    backup.header.new_count);
+			if (!run_apply_check(s, file_diff))
+				return 0;
+		}
+
+		/* Drop edits (they were appended to s->plain) */
+		strbuf_setlen(&s->plain, plain_len);
+		strbuf_setlen(&s->colored, colored_len);
+		*hunk = backup;
+
+		/*
+		 * TRANSLATORS: do not translate [y/n]
+		 * The program will only accept that input at this point.
+		 * Consider translating (saying "no" discards!) as
+		 * (saying "n" for "no" discards!) if the translation
+		 * of the word "no" does not start with n.
+		 */
+		res = prompt_yesno(s, _("Your edited hunk does not apply. "
+					"Edit again (saying \"no\" discards!) "
+					"[y/n]? "));
+		if (res < 1)
+			return -1;
+	}
+}
+
+static int apply_for_checkout(struct add_p_state *s, struct strbuf *diff,
+			      int is_reverse)
+{
+	const char *reverse = is_reverse ? "-R" : NULL;
+	struct child_process check_index = CHILD_PROCESS_INIT;
+	struct child_process check_worktree = CHILD_PROCESS_INIT;
+	struct child_process apply_index = CHILD_PROCESS_INIT;
+	struct child_process apply_worktree = CHILD_PROCESS_INIT;
+	int applies_index, applies_worktree;
+
+	setup_child_process(s, &check_index,
+			    "apply", "--cached", "--check", reverse, NULL);
+	applies_index = !pipe_command(&check_index, diff->buf, diff->len,
+				      NULL, 0, NULL, 0);
+
+	setup_child_process(s, &check_worktree,
+			    "apply", "--check", reverse, NULL);
+	applies_worktree = !pipe_command(&check_worktree, diff->buf, diff->len,
+					 NULL, 0, NULL, 0);
+
+	if (applies_worktree && applies_index) {
+		setup_child_process(s, &apply_index,
+				    "apply", "--cached", reverse, NULL);
+		pipe_command(&apply_index, diff->buf, diff->len,
+			     NULL, 0, NULL, 0);
+
+		setup_child_process(s, &apply_worktree,
+				    "apply", reverse, NULL);
+		pipe_command(&apply_worktree, diff->buf, diff->len,
+			     NULL, 0, NULL, 0);
+
+		return 1;
+	}
+
+	if (!applies_index) {
+		err(s, _("The selected hunks do not apply to the index!"));
+		if (prompt_yesno(s, _("Apply them to the worktree "
+					  "anyway? ")) > 0) {
+			setup_child_process(s, &apply_worktree,
+					    "apply", reverse, NULL);
+			return pipe_command(&apply_worktree, diff->buf,
+					    diff->len, NULL, 0, NULL, 0);
+		}
+		err(s, _("Nothing was applied.\n"));
+	} else
+		/* As a last resort, show the diff to the user */
+		fwrite(diff->buf, diff->len, 1, stdout);
+
+	return 0;
+}
+
+#define SUMMARY_HEADER_WIDTH 20
+#define SUMMARY_LINE_WIDTH 80
+static void summarize_hunk(struct add_p_state *s, struct hunk *hunk,
+			   struct strbuf *out)
+{
+	struct hunk_header *header = &hunk->header;
+	struct strbuf *plain = &s->plain;
+	size_t len = out->len, i;
+
+	strbuf_addf(out, " -%lu,%lu +%lu,%lu ",
+		    header->old_offset, header->old_count,
+		    header->new_offset, header->new_count);
+	if (out->len - len < SUMMARY_HEADER_WIDTH)
+		strbuf_addchars(out, ' ',
+				SUMMARY_HEADER_WIDTH + len - out->len);
+	for (i = hunk->start; i < hunk->end; i = find_next_line(plain, i))
+		if (plain->buf[i] != ' ')
+			break;
+	if (i < hunk->end)
+		strbuf_add(out, plain->buf + i, find_next_line(plain, i) - i);
+	if (out->len - len > SUMMARY_LINE_WIDTH)
+		strbuf_setlen(out, len + SUMMARY_LINE_WIDTH);
+	strbuf_complete_line(out);
+}
+
+#define DISPLAY_HUNKS_LINES 20
+static size_t display_hunks(struct add_p_state *s,
+			    struct file_diff *file_diff, size_t start_index)
+{
+	size_t end_index = start_index + DISPLAY_HUNKS_LINES;
+
+	if (end_index > file_diff->hunk_nr)
+		end_index = file_diff->hunk_nr;
+
+	while (start_index < end_index) {
+		struct hunk *hunk = file_diff->hunk + start_index++;
+
+		strbuf_reset(&s->buf);
+		strbuf_addf(&s->buf, "%c%2d: ", hunk->use == USE_HUNK ? '+'
+			    : hunk->use == SKIP_HUNK ? '-' : ' ',
+			    (int)start_index);
+		summarize_hunk(s, hunk, &s->buf);
+		fputs(s->buf.buf, stdout);
+	}
+
+	return end_index;
+}
+
+static const char help_patch_remainder[] =
+N_("j - leave this hunk undecided, see next undecided hunk\n"
+   "J - leave this hunk undecided, see next hunk\n"
+   "k - leave this hunk undecided, see previous undecided hunk\n"
+   "K - leave this hunk undecided, see previous hunk\n"
+   "g - select a hunk to go to\n"
+   "/ - search for a hunk matching the given regex\n"
+   "s - split the current hunk into smaller hunks\n"
+   "e - manually edit the current hunk\n"
+   "p - print the current hunk, 'P' to use the pager\n"
+   "? - print help\n");
+
+static int patch_update_file(struct add_p_state *s,
+			     struct file_diff *file_diff)
+{
+	size_t hunk_index = 0;
+	ssize_t i, undecided_previous, undecided_next, rendered_hunk_index = -1;
+	struct hunk *hunk;
+	char ch;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	int colored = !!s->colored.len, quit = 0, use_pager = 0;
+	enum prompt_mode_type prompt_mode_type;
+	enum {
+		ALLOW_GOTO_PREVIOUS_HUNK = 1 << 0,
+		ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK = 1 << 1,
+		ALLOW_GOTO_NEXT_HUNK = 1 << 2,
+		ALLOW_GOTO_NEXT_UNDECIDED_HUNK = 1 << 3,
+		ALLOW_SEARCH_AND_GOTO = 1 << 4,
+		ALLOW_SPLIT = 1 << 5,
+		ALLOW_EDIT = 1 << 6
+	} permitted = 0;
+
+	/* Empty added files have no hunks */
+	if (!file_diff->hunk_nr && !file_diff->added)
+		return 0;
+
+	strbuf_reset(&s->buf);
+	render_diff_header(s, file_diff, colored, &s->buf);
+	fputs(s->buf.buf, stdout);
+	for (;;) {
+		if (hunk_index >= file_diff->hunk_nr)
+			hunk_index = 0;
+		hunk = file_diff->hunk_nr
+				? file_diff->hunk + hunk_index
+				: &file_diff->head;
+		undecided_previous = -1;
+		undecided_next = -1;
+
+		if (file_diff->hunk_nr) {
+			for (i = hunk_index - 1; i >= 0; i--)
+				if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
+					undecided_previous = i;
+					break;
+				}
+
+			for (i = hunk_index + 1; i < file_diff->hunk_nr; i++)
+				if (file_diff->hunk[i].use == UNDECIDED_HUNK) {
+					undecided_next = i;
+					break;
+				}
+		}
+
+		/* Everything decided? */
+		if (undecided_previous < 0 && undecided_next < 0 &&
+		    hunk->use != UNDECIDED_HUNK)
+			break;
+
+		strbuf_reset(&s->buf);
+		if (file_diff->hunk_nr) {
+			if (rendered_hunk_index != hunk_index) {
+				if (use_pager) {
+					setup_pager(the_repository);
+					sigchain_push(SIGPIPE, SIG_IGN);
+				}
+				render_hunk(s, hunk, 0, colored, &s->buf);
+				fputs(s->buf.buf, stdout);
+				rendered_hunk_index = hunk_index;
+				if (use_pager) {
+					sigchain_pop(SIGPIPE);
+					wait_for_pager();
+					use_pager = 0;
+				}
+			}
+
+			strbuf_reset(&s->buf);
+			if (undecided_previous >= 0) {
+				permitted |= ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK;
+				strbuf_addstr(&s->buf, ",k");
+			}
+			if (hunk_index) {
+				permitted |= ALLOW_GOTO_PREVIOUS_HUNK;
+				strbuf_addstr(&s->buf, ",K");
+			}
+			if (undecided_next >= 0) {
+				permitted |= ALLOW_GOTO_NEXT_UNDECIDED_HUNK;
+				strbuf_addstr(&s->buf, ",j");
+			}
+			if (hunk_index + 1 < file_diff->hunk_nr) {
+				permitted |= ALLOW_GOTO_NEXT_HUNK;
+				strbuf_addstr(&s->buf, ",J");
+			}
+			if (file_diff->hunk_nr > 1) {
+				permitted |= ALLOW_SEARCH_AND_GOTO;
+				strbuf_addstr(&s->buf, ",g,/");
+			}
+			if (hunk->splittable_into > 1) {
+				permitted |= ALLOW_SPLIT;
+				strbuf_addstr(&s->buf, ",s");
+			}
+			if (hunk_index + 1 > file_diff->mode_change &&
+			    !file_diff->deleted) {
+				permitted |= ALLOW_EDIT;
+				strbuf_addstr(&s->buf, ",e");
+			}
+			strbuf_addstr(&s->buf, ",p");
+		}
+		if (file_diff->deleted)
+			prompt_mode_type = PROMPT_DELETION;
+		else if (file_diff->added)
+			prompt_mode_type = PROMPT_ADDITION;
+		else if (file_diff->mode_change && !hunk_index)
+			prompt_mode_type = PROMPT_MODE_CHANGE;
+		else
+			prompt_mode_type = PROMPT_HUNK;
+
+		printf("%s(%"PRIuMAX"/%"PRIuMAX") ", s->s.prompt_color,
+			      (uintmax_t)hunk_index + 1,
+			      (uintmax_t)(file_diff->hunk_nr
+						? file_diff->hunk_nr
+						: 1));
+		printf(_(s->mode->prompt_mode[prompt_mode_type]),
+		       s->buf.buf);
+		if (*s->s.reset_color)
+			fputs(s->s.reset_color, stdout);
+		fflush(stdout);
+		if (read_single_character(s) == EOF)
+			break;
+
+		if (!s->answer.len)
+			continue;
+		ch = tolower(s->answer.buf[0]);
+
+		/* 'g' takes a hunk number and '/' takes a regexp */
+		if (s->answer.len != 1 && (ch != 'g' && ch != '/')) {
+			err(s, _("Only one letter is expected, got '%s'"), s->answer.buf);
+			continue;
+		}
+		if (ch == 'y') {
+			hunk->use = USE_HUNK;
+soft_increment:
+			hunk_index = undecided_next < 0 ?
+				file_diff->hunk_nr : undecided_next;
+		} else if (ch == 'n') {
+			hunk->use = SKIP_HUNK;
+			goto soft_increment;
+		} else if (ch == 'a') {
+			if (file_diff->hunk_nr) {
+				for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
+					hunk = file_diff->hunk + hunk_index;
+					if (hunk->use == UNDECIDED_HUNK)
+						hunk->use = USE_HUNK;
+				}
+			} else if (hunk->use == UNDECIDED_HUNK) {
+				hunk->use = USE_HUNK;
+			}
+		} else if (ch == 'd' || ch == 'q') {
+			if (file_diff->hunk_nr) {
+				for (; hunk_index < file_diff->hunk_nr; hunk_index++) {
+					hunk = file_diff->hunk + hunk_index;
+					if (hunk->use == UNDECIDED_HUNK)
+						hunk->use = SKIP_HUNK;
+				}
+			} else if (hunk->use == UNDECIDED_HUNK) {
+				hunk->use = SKIP_HUNK;
+			}
+			if (ch == 'q') {
+				quit = 1;
+				break;
+			}
+		} else if (s->answer.buf[0] == 'K') {
+			if (permitted & ALLOW_GOTO_PREVIOUS_HUNK)
+				hunk_index--;
+			else
+				err(s, _("No previous hunk"));
+		} else if (s->answer.buf[0] == 'J') {
+			if (permitted & ALLOW_GOTO_NEXT_HUNK)
+				hunk_index++;
+			else
+				err(s, _("No next hunk"));
+		} else if (s->answer.buf[0] == 'k') {
+			if (permitted & ALLOW_GOTO_PREVIOUS_UNDECIDED_HUNK)
+				hunk_index = undecided_previous;
+			else
+				err(s, _("No previous hunk"));
+		} else if (s->answer.buf[0] == 'j') {
+			if (permitted & ALLOW_GOTO_NEXT_UNDECIDED_HUNK)
+				hunk_index = undecided_next;
+			else
+				err(s, _("No next hunk"));
+		} else if (s->answer.buf[0] == 'g') {
+			char *pend;
+			unsigned long response;
+
+			if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
+				err(s, _("No other hunks to goto"));
+				continue;
+			}
+			strbuf_remove(&s->answer, 0, 1);
+			strbuf_trim(&s->answer);
+			i = hunk_index - DISPLAY_HUNKS_LINES / 2;
+			if (i < (int)file_diff->mode_change)
+				i = file_diff->mode_change;
+			while (s->answer.len == 0) {
+				i = display_hunks(s, file_diff, i);
+				printf("%s", i < file_diff->hunk_nr ?
+				       _("go to which hunk (<ret> to see "
+					 "more)? ") : _("go to which hunk? "));
+				fflush(stdout);
+				if (strbuf_getline(&s->answer,
+						   stdin) == EOF)
+					break;
+				strbuf_trim_trailing_newline(&s->answer);
+			}
+
+			strbuf_trim(&s->answer);
+			response = strtoul(s->answer.buf, &pend, 10);
+			if (*pend || pend == s->answer.buf)
+				err(s, _("Invalid number: '%s'"),
+				    s->answer.buf);
+			else if (0 < response && response <= file_diff->hunk_nr)
+				hunk_index = response - 1;
+			else
+				err(s, Q_("Sorry, only %d hunk available.",
+					  "Sorry, only %d hunks available.",
+					  file_diff->hunk_nr),
+				    (int)file_diff->hunk_nr);
+		} else if (s->answer.buf[0] == '/') {
+			regex_t regex;
+			int ret;
+
+			if (!(permitted & ALLOW_SEARCH_AND_GOTO)) {
+				err(s, _("No other hunks to search"));
+				continue;
+			}
+			strbuf_remove(&s->answer, 0, 1);
+			strbuf_trim_trailing_newline(&s->answer);
+			if (s->answer.len == 0) {
+				printf("%s", _("search for regex? "));
+				fflush(stdout);
+				if (strbuf_getline(&s->answer,
+						   stdin) == EOF)
+					break;
+				strbuf_trim_trailing_newline(&s->answer);
+				if (s->answer.len == 0)
+					continue;
+			}
+			ret = regcomp(&regex, s->answer.buf,
+				      REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+			if (ret) {
+				char errbuf[1024];
+
+				regerror(ret, &regex, errbuf, sizeof(errbuf));
+				err(s, _("Malformed search regexp %s: %s"),
+				    s->answer.buf, errbuf);
+				continue;
+			}
+			i = hunk_index;
+			for (;;) {
+				/* render the hunk into a scratch buffer */
+				render_hunk(s, file_diff->hunk + i, 0, 0,
+					    &s->buf);
+				if (regexec(&regex, s->buf.buf, 0, NULL, 0)
+				    != REG_NOMATCH)
+					break;
+				i++;
+				if (i == file_diff->hunk_nr)
+					i = 0;
+				if (i != hunk_index)
+					continue;
+				err(s, _("No hunk matches the given pattern"));
+				break;
+			}
+			regfree(&regex);
+			hunk_index = i;
+		} else if (s->answer.buf[0] == 's') {
+			size_t splittable_into = hunk->splittable_into;
+			if (!(permitted & ALLOW_SPLIT)) {
+				err(s, _("Sorry, cannot split this hunk"));
+			} else if (!split_hunk(s, file_diff,
+					     hunk - file_diff->hunk)) {
+				color_fprintf_ln(stdout, s->s.header_color,
+						 _("Split into %d hunks."),
+						 (int)splittable_into);
+				rendered_hunk_index = -1;
+			}
+		} else if (s->answer.buf[0] == 'e') {
+			if (!(permitted & ALLOW_EDIT))
+				err(s, _("Sorry, cannot edit this hunk"));
+			else if (edit_hunk_loop(s, file_diff, hunk) >= 0) {
+				hunk->use = USE_HUNK;
+				goto soft_increment;
+			}
+		} else if (ch == 'p') {
+			rendered_hunk_index = -1;
+			use_pager = (s->answer.buf[0] == 'P') ? 1 : 0;
+		} else if (s->answer.buf[0] == '?') {
+			const char *p = _(help_patch_remainder), *eol = p;
+
+			color_fprintf(stdout, s->s.help_color, "%s",
+				      _(s->mode->help_patch_text));
+
+			/*
+			 * Show only those lines of the remainder that are
+			 * actually applicable with the current hunk.
+			 */
+			for (; *p; p = eol + (*eol == '\n')) {
+				eol = strchrnul(p, '\n');
+
+				/*
+				 * `s->buf` still contains the part of the
+				 * commands shown in the prompt that are not
+				 * always available.
+				 */
+				if (*p != '?' && !strchr(s->buf.buf, *p))
+					continue;
+
+				color_fprintf_ln(stdout, s->s.help_color,
+						 "%.*s", (int)(eol - p), p);
+			}
+		} else {
+			err(s, _("Unknown command '%s' (use '?' for help)"),
+			    s->answer.buf);
+		}
+	}
+
+	/* Any hunk to be used? */
+	for (i = 0; i < file_diff->hunk_nr; i++)
+		if (file_diff->hunk[i].use == USE_HUNK)
+			break;
+
+	if (i < file_diff->hunk_nr ||
+	    (!file_diff->hunk_nr && file_diff->head.use == USE_HUNK)) {
+		/* At least one hunk selected: apply */
+		strbuf_reset(&s->buf);
+		reassemble_patch(s, file_diff, 0, &s->buf);
+
+		discard_index(s->s.r->index);
+		if (s->mode->apply_for_checkout)
+			apply_for_checkout(s, &s->buf,
+					   s->mode->is_reverse);
+		else {
+			setup_child_process(s, &cp, "apply", NULL);
+			strvec_pushv(&cp.args, s->mode->apply_args);
+			if (pipe_command(&cp, s->buf.buf, s->buf.len,
+					 NULL, 0, NULL, 0))
+				error(_("'git apply' failed"));
+		}
+		if (repo_read_index(s->s.r) >= 0)
+			repo_refresh_and_write_index(s->s.r, REFRESH_QUIET, 0,
+						     1, NULL, NULL, NULL);
+	}
+
+	putchar('\n');
+	return quit;
+}
+
+int run_add_p(struct repository *r, enum add_p_mode mode,
+	      const char *revision, const struct pathspec *ps)
+{
+	struct add_p_state s = {
+		{ r }, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+	};
+	size_t i, binary_count = 0;
+
+	init_add_i_state(&s.s, r);
+
+	if (mode == ADD_P_STASH)
+		s.mode = &patch_mode_stash;
+	else if (mode == ADD_P_RESET) {
+		if (!revision || !strcmp(revision, "HEAD"))
+			s.mode = &patch_mode_reset_head;
+		else
+			s.mode = &patch_mode_reset_nothead;
+	} else if (mode == ADD_P_CHECKOUT) {
+		if (!revision)
+			s.mode = &patch_mode_checkout_index;
+		else if (!strcmp(revision, "HEAD"))
+			s.mode = &patch_mode_checkout_head;
+		else
+			s.mode = &patch_mode_checkout_nothead;
+	} else if (mode == ADD_P_WORKTREE) {
+		if (!revision)
+			s.mode = &patch_mode_checkout_index;
+		else if (!strcmp(revision, "HEAD"))
+			s.mode = &patch_mode_worktree_head;
+		else
+			s.mode = &patch_mode_worktree_nothead;
+	} else
+		s.mode = &patch_mode_add;
+	s.revision = revision;
+
+	discard_index(r->index);
+	if (repo_read_index(r) < 0 ||
+	    (!s.mode->index_only &&
+	     repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
+					  NULL, NULL, NULL) < 0) ||
+	    parse_diff(&s, ps) < 0) {
+		add_p_state_clear(&s);
+		return -1;
+	}
+
+	for (i = 0; i < s.file_diff_nr; i++)
+		if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr)
+			binary_count++;
+		else if (patch_update_file(&s, s.file_diff + i))
+			break;
+
+	if (s.file_diff_nr == 0)
+		err(&s, _("No changes."));
+	else if (binary_count == s.file_diff_nr)
+		err(&s, _("Only binary files changed."));
+
+	add_p_state_clear(&s);
+	return 0;
+}
diff --git a/advice.c b/advice.c
new file mode 100644
index 0000000000..1df43b7536
--- /dev/null
+++ b/advice.c
@@ -0,0 +1,313 @@
+#include "git-compat-util.h"
+#include "advice.h"
+#include "config.h"
+#include "color.h"
+#include "environment.h"
+#include "gettext.h"
+#include "help.h"
+#include "string-list.h"
+
+static int advice_use_color = -1;
+static char advice_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_YELLOW,	/* HINT */
+};
+
+enum color_advice {
+	ADVICE_COLOR_RESET = 0,
+	ADVICE_COLOR_HINT = 1,
+};
+
+static int parse_advise_color_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "reset"))
+		return ADVICE_COLOR_RESET;
+	if (!strcasecmp(slot, "hint"))
+		return ADVICE_COLOR_HINT;
+	return -1;
+}
+
+static const char *advise_get_color(enum color_advice ix)
+{
+	if (want_color_stderr(advice_use_color))
+		return advice_colors[ix];
+	return "";
+}
+
+enum advice_level {
+	ADVICE_LEVEL_NONE = 0,
+	ADVICE_LEVEL_DISABLED,
+	ADVICE_LEVEL_ENABLED,
+};
+
+static struct {
+	const char *key;
+	enum advice_level level;
+} advice_setting[] = {
+	[ADVICE_ADD_EMBEDDED_REPO]			= { "addEmbeddedRepo" },
+	[ADVICE_ADD_EMPTY_PATHSPEC]			= { "addEmptyPathspec" },
+	[ADVICE_ADD_IGNORED_FILE]			= { "addIgnoredFile" },
+	[ADVICE_AMBIGUOUS_FETCH_REFSPEC]		= { "ambiguousFetchRefspec" },
+	[ADVICE_AM_WORK_DIR] 				= { "amWorkDir" },
+	[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] 	= { "checkoutAmbiguousRemoteBranchName" },
+	[ADVICE_COMMIT_BEFORE_MERGE]			= { "commitBeforeMerge" },
+	[ADVICE_DETACHED_HEAD]				= { "detachedHead" },
+	[ADVICE_DIVERGING]				= { "diverging" },
+	[ADVICE_FETCH_SET_HEAD_WARN]			= { "fetchRemoteHEADWarn" },
+	[ADVICE_FETCH_SHOW_FORCED_UPDATES]		= { "fetchShowForcedUpdates" },
+	[ADVICE_FORCE_DELETE_BRANCH]			= { "forceDeleteBranch" },
+	[ADVICE_GRAFT_FILE_DEPRECATED]			= { "graftFileDeprecated" },
+	[ADVICE_IGNORED_HOOK]				= { "ignoredHook" },
+	[ADVICE_IMPLICIT_IDENTITY]			= { "implicitIdentity" },
+	[ADVICE_MERGE_CONFLICT]				= { "mergeConflict" },
+	[ADVICE_NESTED_TAG]				= { "nestedTag" },
+	[ADVICE_OBJECT_NAME_WARNING]			= { "objectNameWarning" },
+	[ADVICE_PUSH_ALREADY_EXISTS]			= { "pushAlreadyExists" },
+	[ADVICE_PUSH_FETCH_FIRST]			= { "pushFetchFirst" },
+	[ADVICE_PUSH_NEEDS_FORCE]			= { "pushNeedsForce" },
+	[ADVICE_PUSH_NON_FF_CURRENT]			= { "pushNonFFCurrent" },
+	[ADVICE_PUSH_NON_FF_MATCHING]			= { "pushNonFFMatching" },
+	[ADVICE_PUSH_REF_NEEDS_UPDATE]			= { "pushRefNeedsUpdate" },
+	[ADVICE_PUSH_UNQUALIFIED_REF_NAME]		= { "pushUnqualifiedRefName" },
+	[ADVICE_PUSH_UPDATE_REJECTED]			= { "pushUpdateRejected" },
+	[ADVICE_PUSH_UPDATE_REJECTED_ALIAS]		= { "pushNonFastForward" }, /* backwards compatibility */
+	[ADVICE_REBASE_TODO_ERROR]			= { "rebaseTodoError" },
+	[ADVICE_REF_SYNTAX]				= { "refSyntax" },
+	[ADVICE_RESET_NO_REFRESH_WARNING]		= { "resetNoRefresh" },
+	[ADVICE_RESOLVE_CONFLICT]			= { "resolveConflict" },
+	[ADVICE_RM_HINTS]				= { "rmHints" },
+	[ADVICE_SEQUENCER_IN_USE]			= { "sequencerInUse" },
+	[ADVICE_SET_UPSTREAM_FAILURE]			= { "setUpstreamFailure" },
+	[ADVICE_SKIPPED_CHERRY_PICKS]			= { "skippedCherryPicks" },
+	[ADVICE_SPARSE_INDEX_EXPANDED]			= { "sparseIndexExpanded" },
+	[ADVICE_STATUS_AHEAD_BEHIND_WARNING]		= { "statusAheadBehindWarning" },
+	[ADVICE_STATUS_HINTS]				= { "statusHints" },
+	[ADVICE_STATUS_U_OPTION]			= { "statusUoption" },
+	[ADVICE_SUBMODULES_NOT_UPDATED] 		= { "submodulesNotUpdated" },
+	[ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE] = { "submoduleAlternateErrorStrategyDie" },
+	[ADVICE_SUBMODULE_MERGE_CONFLICT]               = { "submoduleMergeConflict" },
+	[ADVICE_SUGGEST_DETACHING_HEAD]			= { "suggestDetachingHead" },
+	[ADVICE_UPDATE_SPARSE_PATH]			= { "updateSparsePath" },
+	[ADVICE_WAITING_FOR_EDITOR]			= { "waitingForEditor" },
+	[ADVICE_WORKTREE_ADD_ORPHAN]			= { "worktreeAddOrphan" },
+};
+
+static const char turn_off_instructions[] =
+N_("\n"
+   "Disable this message with \"git config set advice.%s false\"");
+
+static void vadvise(const char *advice, int display_instructions,
+		    const char *key, va_list params)
+{
+	struct strbuf buf = STRBUF_INIT;
+	const char *cp, *np;
+
+	strbuf_vaddf(&buf, advice, params);
+
+	if (display_instructions)
+		strbuf_addf(&buf, turn_off_instructions, key);
+
+	for (cp = buf.buf; *cp; cp = np) {
+		np = strchrnul(cp, '\n');
+		fprintf(stderr,	_("%shint:%s%.*s%s\n"),
+			advise_get_color(ADVICE_COLOR_HINT),
+			(np == cp) ? "" : " ",
+			(int)(np - cp), cp,
+			advise_get_color(ADVICE_COLOR_RESET));
+		if (*np)
+			np++;
+	}
+	strbuf_release(&buf);
+}
+
+void advise(const char *advice, ...)
+{
+	va_list params;
+	va_start(params, advice);
+	vadvise(advice, 0, "", params);
+	va_end(params);
+}
+
+int advice_enabled(enum advice_type type)
+{
+	int enabled = advice_setting[type].level != ADVICE_LEVEL_DISABLED;
+	static int globally_enabled = -1;
+
+	if (globally_enabled < 0)
+		globally_enabled = git_env_bool(GIT_ADVICE_ENVIRONMENT, 1);
+	if (!globally_enabled)
+		return 0;
+
+	if (type == ADVICE_PUSH_UPDATE_REJECTED)
+		return enabled &&
+		       advice_enabled(ADVICE_PUSH_UPDATE_REJECTED_ALIAS);
+
+	return enabled;
+}
+
+void advise_if_enabled(enum advice_type type, const char *advice, ...)
+{
+	va_list params;
+
+	if (!advice_enabled(type))
+		return;
+
+	va_start(params, advice);
+	vadvise(advice, !advice_setting[type].level, advice_setting[type].key,
+		params);
+	va_end(params);
+}
+
+int git_default_advice_config(const char *var, const char *value)
+{
+	const char *k, *slot_name;
+
+	if (!strcmp(var, "color.advice")) {
+		advice_use_color = git_config_colorbool(var, value);
+		return 0;
+	}
+
+	if (skip_prefix(var, "color.advice.", &slot_name)) {
+		int slot = parse_advise_color_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!value)
+			return config_error_nonbool(var);
+		return color_parse(value, advice_colors[slot]);
+	}
+
+	if (!skip_prefix(var, "advice.", &k))
+		return 0;
+
+	for (size_t i = 0; i < ARRAY_SIZE(advice_setting); i++) {
+		if (strcasecmp(k, advice_setting[i].key))
+			continue;
+		advice_setting[i].level = git_config_bool(var, value)
+					  ? ADVICE_LEVEL_ENABLED
+					  : ADVICE_LEVEL_DISABLED;
+		return 0;
+	}
+
+	return 0;
+}
+
+void list_config_advices(struct string_list *list, const char *prefix)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(advice_setting); i++)
+		list_config_item(list, prefix, advice_setting[i].key);
+}
+
+int error_resolve_conflict(const char *me)
+{
+	if (!strcmp(me, "cherry-pick"))
+		error(_("Cherry-picking is not possible because you have unmerged files."));
+	else if (!strcmp(me, "commit"))
+		error(_("Committing is not possible because you have unmerged files."));
+	else if (!strcmp(me, "merge"))
+		error(_("Merging is not possible because you have unmerged files."));
+	else if (!strcmp(me, "pull"))
+		error(_("Pulling is not possible because you have unmerged files."));
+	else if (!strcmp(me, "revert"))
+		error(_("Reverting is not possible because you have unmerged files."));
+	else if (!strcmp(me, "rebase"))
+		error(_("Rebasing is not possible because you have unmerged files."));
+	else
+		BUG("Unhandled conflict reason '%s'", me);
+
+	if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
+		/*
+		 * Message used both when 'git commit' fails and when
+		 * other commands doing a merge do.
+		 */
+		advise(_("Fix them up in the work tree, and then use 'git add/rm <file>'\n"
+			 "as appropriate to mark resolution and make a commit."));
+	return -1;
+}
+
+void NORETURN die_resolve_conflict(const char *me)
+{
+	error_resolve_conflict(me);
+	die(_("Exiting because of an unresolved conflict."));
+}
+
+void NORETURN die_conclude_merge(void)
+{
+	error(_("You have not concluded your merge (MERGE_HEAD exists)."));
+	if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
+		advise(_("Please, commit your changes before merging."));
+	die(_("Exiting because of unfinished merge."));
+}
+
+void NORETURN die_ff_impossible(void)
+{
+	advise_if_enabled(ADVICE_DIVERGING,
+		_("Diverging branches can't be fast-forwarded, you need to either:\n"
+		"\n"
+		"\tgit merge --no-ff\n"
+		"\n"
+		"or:\n"
+		"\n"
+		"\tgit rebase\n"));
+	die(_("Not possible to fast-forward, aborting."));
+}
+
+void advise_on_updating_sparse_paths(struct string_list *pathspec_list)
+{
+	struct string_list_item *item;
+
+	if (!pathspec_list->nr)
+		return;
+
+	fprintf(stderr, _("The following paths and/or pathspecs matched paths that exist\n"
+			  "outside of your sparse-checkout definition, so will not be\n"
+			  "updated in the index:\n"));
+	for_each_string_list_item(item, pathspec_list)
+		fprintf(stderr, "%s\n", item->string);
+
+	advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
+			  _("If you intend to update such entries, try one of the following:\n"
+			    "* Use the --sparse option.\n"
+			    "* Disable or modify the sparsity rules."));
+}
+
+void detach_advice(const char *new_name)
+{
+	const char *fmt =
+	_("Note: switching to '%s'.\n"
+	"\n"
+	"You are in 'detached HEAD' state. You can look around, make experimental\n"
+	"changes and commit them, and you can discard any commits you make in this\n"
+	"state without impacting any branches by switching back to a branch.\n"
+	"\n"
+	"If you want to create a new branch to retain commits you create, you may\n"
+	"do so (now or later) by using -c with the switch command. Example:\n"
+	"\n"
+	"  git switch -c <new-branch-name>\n"
+	"\n"
+	"Or undo this operation with:\n"
+	"\n"
+	"  git switch -\n"
+	"\n"
+	"Turn off this advice by setting config variable advice.detachedHead to false\n\n");
+
+	fprintf(stderr, fmt, new_name);
+}
+
+void advise_on_moving_dirty_path(struct string_list *pathspec_list)
+{
+	struct string_list_item *item;
+
+	if (!pathspec_list->nr)
+		return;
+
+	fprintf(stderr, _("The following paths have been moved outside the\n"
+			  "sparse-checkout definition but are not sparse due to local\n"
+			  "modifications.\n"));
+	for_each_string_list_item(item, pathspec_list)
+		fprintf(stderr, "%s\n", item->string);
+
+	advise_if_enabled(ADVICE_UPDATE_SPARSE_PATH,
+			  _("To correct the sparsity of these paths, do the following:\n"
+			    "* Use \"git add --sparse <paths>\" to update the index\n"
+			    "* Use \"git sparse-checkout reapply\" to apply the sparsity rules"));
+}
diff --git a/advice.h b/advice.h
new file mode 100644
index 0000000000..cf2284ec43
--- /dev/null
+++ b/advice.h
@@ -0,0 +1,86 @@
+#ifndef ADVICE_H
+#define ADVICE_H
+
+struct string_list;
+
+/*
+ * To add a new advice, you need to:
+ * Define a new advice_type.
+ * Add a new entry to advice_setting array.
+ * Add the new config variable to Documentation/config/advice.txt.
+ * Call advise_if_enabled to print your advice.
+ */
+enum advice_type {
+	ADVICE_ADD_EMBEDDED_REPO,
+	ADVICE_ADD_EMPTY_PATHSPEC,
+	ADVICE_ADD_IGNORED_FILE,
+	ADVICE_AMBIGUOUS_FETCH_REFSPEC,
+	ADVICE_AM_WORK_DIR,
+	ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
+	ADVICE_COMMIT_BEFORE_MERGE,
+	ADVICE_DETACHED_HEAD,
+	ADVICE_DIVERGING,
+	ADVICE_FETCH_SET_HEAD_WARN,
+	ADVICE_FETCH_SHOW_FORCED_UPDATES,
+	ADVICE_FORCE_DELETE_BRANCH,
+	ADVICE_GRAFT_FILE_DEPRECATED,
+	ADVICE_IGNORED_HOOK,
+	ADVICE_IMPLICIT_IDENTITY,
+	ADVICE_MERGE_CONFLICT,
+	ADVICE_NESTED_TAG,
+	ADVICE_OBJECT_NAME_WARNING,
+	ADVICE_PUSH_ALREADY_EXISTS,
+	ADVICE_PUSH_FETCH_FIRST,
+	ADVICE_PUSH_NEEDS_FORCE,
+	ADVICE_PUSH_NON_FF_CURRENT,
+	ADVICE_PUSH_NON_FF_MATCHING,
+	ADVICE_PUSH_REF_NEEDS_UPDATE,
+	ADVICE_PUSH_UNQUALIFIED_REF_NAME,
+	ADVICE_PUSH_UPDATE_REJECTED,
+	ADVICE_PUSH_UPDATE_REJECTED_ALIAS,
+	ADVICE_REBASE_TODO_ERROR,
+	ADVICE_REF_SYNTAX,
+	ADVICE_RESET_NO_REFRESH_WARNING,
+	ADVICE_RESOLVE_CONFLICT,
+	ADVICE_RM_HINTS,
+	ADVICE_SEQUENCER_IN_USE,
+	ADVICE_SET_UPSTREAM_FAILURE,
+	ADVICE_SKIPPED_CHERRY_PICKS,
+	ADVICE_SPARSE_INDEX_EXPANDED,
+	ADVICE_STATUS_AHEAD_BEHIND_WARNING,
+	ADVICE_STATUS_HINTS,
+	ADVICE_STATUS_U_OPTION,
+	ADVICE_SUBMODULES_NOT_UPDATED,
+	ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE,
+	ADVICE_SUBMODULE_MERGE_CONFLICT,
+	ADVICE_SUGGEST_DETACHING_HEAD,
+	ADVICE_UPDATE_SPARSE_PATH,
+	ADVICE_WAITING_FOR_EDITOR,
+	ADVICE_WORKTREE_ADD_ORPHAN,
+};
+
+int git_default_advice_config(const char *var, const char *value);
+__attribute__((format (printf, 1, 2)))
+void advise(const char *advice, ...);
+
+/**
+ * Checks if advice type is enabled (can be printed to the user).
+ * Should be called before advise().
+ */
+int advice_enabled(enum advice_type type);
+
+/**
+ * Checks the visibility of the advice before printing.
+ */
+__attribute__((format (printf, 2, 3)))
+void advise_if_enabled(enum advice_type type, const char *advice, ...);
+
+int error_resolve_conflict(const char *me);
+void NORETURN die_resolve_conflict(const char *me);
+void NORETURN die_conclude_merge(void);
+void NORETURN die_ff_impossible(void);
+void advise_on_updating_sparse_paths(struct string_list *pathspec_list);
+void detach_advice(const char *new_name);
+void advise_on_moving_dirty_path(struct string_list *pathspec_list);
+
+#endif /* ADVICE_H */
diff --git a/alias.c b/alias.c
new file mode 100644
index 0000000000..1a1a141a0a
--- /dev/null
+++ b/alias.c
@@ -0,0 +1,139 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "alias.h"
+#include "config.h"
+#include "gettext.h"
+#include "strbuf.h"
+#include "string-list.h"
+
+struct config_alias_data {
+	const char *alias;
+	char *v;
+	struct string_list *list;
+};
+
+static int config_alias_cb(const char *key, const char *value,
+			   const struct config_context *ctx UNUSED, void *d)
+{
+	struct config_alias_data *data = d;
+	const char *p;
+
+	if (!skip_prefix(key, "alias.", &p))
+		return 0;
+
+	if (data->alias) {
+		if (!strcasecmp(p, data->alias)) {
+			FREE_AND_NULL(data->v);
+			return git_config_string(&data->v,
+						 key, value);
+		}
+	} else if (data->list) {
+		string_list_append(data->list, p);
+	}
+
+	return 0;
+}
+
+char *alias_lookup(const char *alias)
+{
+	struct config_alias_data data = { alias, NULL };
+
+	read_early_config(the_repository, config_alias_cb, &data);
+
+	return data.v;
+}
+
+void list_aliases(struct string_list *list)
+{
+	struct config_alias_data data = { NULL, NULL, list };
+
+	read_early_config(the_repository, config_alias_cb, &data);
+}
+
+void quote_cmdline(struct strbuf *buf, const char **argv)
+{
+	for (const char **argp = argv; *argp; argp++) {
+		if (argp != argv)
+			strbuf_addch(buf, ' ');
+		strbuf_addch(buf, '"');
+		for (const char *p = *argp; *p; p++) {
+			const char c = *p;
+
+			if (c == '"' || c =='\\')
+				strbuf_addch(buf, '\\');
+			strbuf_addch(buf, c);
+		}
+		strbuf_addch(buf, '"');
+	}
+}
+
+#define SPLIT_CMDLINE_BAD_ENDING 1
+#define SPLIT_CMDLINE_UNCLOSED_QUOTE 2
+#define SPLIT_CMDLINE_ARGC_OVERFLOW 3
+static const char *split_cmdline_errors[] = {
+	N_("cmdline ends with \\"),
+	N_("unclosed quote"),
+	N_("too many arguments"),
+};
+
+int split_cmdline(char *cmdline, const char ***argv)
+{
+	size_t src, dst, count = 0, size = 16;
+	char quoted = 0;
+
+	ALLOC_ARRAY(*argv, size);
+
+	/* split alias_string */
+	(*argv)[count++] = cmdline;
+	for (src = dst = 0; cmdline[src];) {
+		char c = cmdline[src];
+		if (!quoted && isspace(c)) {
+			cmdline[dst++] = 0;
+			while (cmdline[++src]
+					&& isspace(cmdline[src]))
+				; /* skip */
+			ALLOC_GROW(*argv, count + 1, size);
+			(*argv)[count++] = cmdline + dst;
+		} else if (!quoted && (c == '\'' || c == '"')) {
+			quoted = c;
+			src++;
+		} else if (c == quoted) {
+			quoted = 0;
+			src++;
+		} else {
+			if (c == '\\' && quoted != '\'') {
+				src++;
+				c = cmdline[src];
+				if (!c) {
+					FREE_AND_NULL(*argv);
+					return -SPLIT_CMDLINE_BAD_ENDING;
+				}
+			}
+			cmdline[dst++] = c;
+			src++;
+		}
+	}
+
+	cmdline[dst] = 0;
+
+	if (quoted) {
+		FREE_AND_NULL(*argv);
+		return -SPLIT_CMDLINE_UNCLOSED_QUOTE;
+	}
+
+	if (count >= INT_MAX) {
+		FREE_AND_NULL(*argv);
+		return -SPLIT_CMDLINE_ARGC_OVERFLOW;
+	}
+
+	ALLOC_GROW(*argv, count + 1, size);
+	(*argv)[count] = NULL;
+
+	return count;
+}
+
+const char *split_cmdline_strerror(int split_cmdline_errno)
+{
+	return split_cmdline_errors[-split_cmdline_errno - 1];
+}
diff --git a/alias.h b/alias.h
new file mode 100644
index 0000000000..43db736484
--- /dev/null
+++ b/alias.h
@@ -0,0 +1,15 @@
+#ifndef ALIAS_H
+#define ALIAS_H
+
+struct strbuf;
+struct string_list;
+
+char *alias_lookup(const char *alias);
+/* Quote argv so buf can be parsed by split_cmdline() */
+void quote_cmdline(struct strbuf *buf, const char **argv);
+int split_cmdline(char *cmdline, const char ***argv);
+/* Takes a negative value returned by split_cmdline */
+const char *split_cmdline_strerror(int cmdline_errno);
+void list_aliases(struct string_list *list);
+
+#endif
diff --git a/alloc.c b/alloc.c
new file mode 100644
index 0000000000..377e80f5dd
--- /dev/null
+++ b/alloc.c
@@ -0,0 +1,123 @@
+/*
+ * alloc.c  - specialized allocator for internal objects
+ *
+ * Copyright (C) 2006 Linus Torvalds
+ *
+ * The standard malloc/free wastes too much space for objects, partly because
+ * it maintains all the allocation infrastructure, but even more because it ends
+ * up with maximal alignment because it doesn't know what the object alignment
+ * for the new allocation is.
+ */
+#include "git-compat-util.h"
+#include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "repository.h"
+#include "tag.h"
+#include "alloc.h"
+
+#define BLOCKING 1024
+
+union any_object {
+	struct object object;
+	struct blob blob;
+	struct tree tree;
+	struct commit commit;
+	struct tag tag;
+};
+
+struct alloc_state {
+	int nr;    /* number of nodes left in current allocation */
+	void *p;   /* first free node in current allocation */
+
+	/* bookkeeping of allocations */
+	void **slabs;
+	int slab_nr, slab_alloc;
+};
+
+struct alloc_state *allocate_alloc_state(void)
+{
+	return xcalloc(1, sizeof(struct alloc_state));
+}
+
+void clear_alloc_state(struct alloc_state *s)
+{
+	while (s->slab_nr > 0) {
+		s->slab_nr--;
+		free(s->slabs[s->slab_nr]);
+	}
+
+	FREE_AND_NULL(s->slabs);
+}
+
+static inline void *alloc_node(struct alloc_state *s, size_t node_size)
+{
+	void *ret;
+
+	if (!s->nr) {
+		s->nr = BLOCKING;
+		s->p = xmalloc(BLOCKING * node_size);
+
+		ALLOC_GROW(s->slabs, s->slab_nr + 1, s->slab_alloc);
+		s->slabs[s->slab_nr++] = s->p;
+	}
+	s->nr--;
+	ret = s->p;
+	s->p = (char *)s->p + node_size;
+	memset(ret, 0, node_size);
+
+	return ret;
+}
+
+void *alloc_blob_node(struct repository *r)
+{
+	struct blob *b = alloc_node(r->parsed_objects->blob_state, sizeof(struct blob));
+	b->object.type = OBJ_BLOB;
+	return b;
+}
+
+void *alloc_tree_node(struct repository *r)
+{
+	struct tree *t = alloc_node(r->parsed_objects->tree_state, sizeof(struct tree));
+	t->object.type = OBJ_TREE;
+	return t;
+}
+
+void *alloc_tag_node(struct repository *r)
+{
+	struct tag *t = alloc_node(r->parsed_objects->tag_state, sizeof(struct tag));
+	t->object.type = OBJ_TAG;
+	return t;
+}
+
+void *alloc_object_node(struct repository *r)
+{
+	struct object *obj = alloc_node(r->parsed_objects->object_state, sizeof(union any_object));
+	obj->type = OBJ_NONE;
+	return obj;
+}
+
+/*
+ * The returned count is to be used as an index into commit slabs,
+ * that are *NOT* maintained per repository, and that is why a single
+ * global counter is used.
+ */
+static unsigned int alloc_commit_index(void)
+{
+	static unsigned int parsed_commits_count;
+	return parsed_commits_count++;
+}
+
+void init_commit_node(struct commit *c)
+{
+	c->object.type = OBJ_COMMIT;
+	c->index = alloc_commit_index();
+}
+
+void *alloc_commit_node(struct repository *r)
+{
+	struct commit *c = alloc_node(r->parsed_objects->commit_state, sizeof(struct commit));
+	init_commit_node(c);
+	return c;
+}
diff --git a/alloc.h b/alloc.h
new file mode 100644
index 0000000000..3f4a0ad310
--- /dev/null
+++ b/alloc.h
@@ -0,0 +1,20 @@
+#ifndef ALLOC_H
+#define ALLOC_H
+
+struct alloc_state;
+struct tree;
+struct commit;
+struct tag;
+struct repository;
+
+void *alloc_blob_node(struct repository *r);
+void *alloc_tree_node(struct repository *r);
+void init_commit_node(struct commit *c);
+void *alloc_commit_node(struct repository *r);
+void *alloc_tag_node(struct repository *r);
+void *alloc_object_node(struct repository *r);
+
+struct alloc_state *allocate_alloc_state(void);
+void clear_alloc_state(struct alloc_state *s);
+
+#endif
diff --git a/apply.c b/apply.c
new file mode 100644
index 0000000000..4a7b6120ac
--- /dev/null
+++ b/apply.c
@@ -0,0 +1,5163 @@
+/*
+ * apply.c
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ *
+ * This applies patches on top of some (arbitrary) version of the SCM.
+ *
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "base85.h"
+#include "config.h"
+#include "object-store-ll.h"
+#include "delta.h"
+#include "diff.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "xdiff-interface.h"
+#include "merge-ll.h"
+#include "lockfile.h"
+#include "name-hash.h"
+#include "object-name.h"
+#include "object-file.h"
+#include "parse-options.h"
+#include "path.h"
+#include "quote.h"
+#include "read-cache.h"
+#include "repository.h"
+#include "rerere.h"
+#include "apply.h"
+#include "entry.h"
+#include "setup.h"
+#include "symlinks.h"
+#include "wildmatch.h"
+#include "ws.h"
+
+struct gitdiff_data {
+	struct strbuf *root;
+	int linenr;
+	int p_value;
+};
+
+static void git_apply_config(void)
+{
+	git_config_get_string("apply.whitespace", &apply_default_whitespace);
+	git_config_get_string("apply.ignorewhitespace", &apply_default_ignorewhitespace);
+	git_config(git_xmerge_config, NULL);
+}
+
+static int parse_whitespace_option(struct apply_state *state, const char *option)
+{
+	if (!option) {
+		state->ws_error_action = warn_on_ws_error;
+		return 0;
+	}
+	if (!strcmp(option, "warn")) {
+		state->ws_error_action = warn_on_ws_error;
+		return 0;
+	}
+	if (!strcmp(option, "nowarn")) {
+		state->ws_error_action = nowarn_ws_error;
+		return 0;
+	}
+	if (!strcmp(option, "error")) {
+		state->ws_error_action = die_on_ws_error;
+		return 0;
+	}
+	if (!strcmp(option, "error-all")) {
+		state->ws_error_action = die_on_ws_error;
+		state->squelch_whitespace_errors = 0;
+		return 0;
+	}
+	if (!strcmp(option, "strip") || !strcmp(option, "fix")) {
+		state->ws_error_action = correct_ws_error;
+		return 0;
+	}
+	/*
+	 * Please update $__git_whitespacelist in git-completion.bash,
+	 * Documentation/git-apply.txt, and Documentation/git-am.txt
+	 * when you add new options.
+	 */
+	return error(_("unrecognized whitespace option '%s'"), option);
+}
+
+static int parse_ignorewhitespace_option(struct apply_state *state,
+						 const char *option)
+{
+	if (!option || !strcmp(option, "no") ||
+	    !strcmp(option, "false") || !strcmp(option, "never") ||
+	    !strcmp(option, "none")) {
+		state->ws_ignore_action = ignore_ws_none;
+		return 0;
+	}
+	if (!strcmp(option, "change")) {
+		state->ws_ignore_action = ignore_ws_change;
+		return 0;
+	}
+	return error(_("unrecognized whitespace ignore option '%s'"), option);
+}
+
+int init_apply_state(struct apply_state *state,
+		     struct repository *repo,
+		     const char *prefix)
+{
+	memset(state, 0, sizeof(*state));
+	state->prefix = prefix;
+	state->repo = repo;
+	state->apply = 1;
+	state->line_termination = '\n';
+	state->p_value = 1;
+	state->p_context = UINT_MAX;
+	state->squelch_whitespace_errors = 5;
+	state->ws_error_action = warn_on_ws_error;
+	state->ws_ignore_action = ignore_ws_none;
+	state->linenr = 1;
+	string_list_init_nodup(&state->fn_table);
+	string_list_init_nodup(&state->limit_by_name);
+	strset_init(&state->removed_symlinks);
+	strset_init(&state->kept_symlinks);
+	strbuf_init(&state->root, 0);
+
+	git_apply_config();
+	if (apply_default_whitespace && parse_whitespace_option(state, apply_default_whitespace))
+		return -1;
+	if (apply_default_ignorewhitespace && parse_ignorewhitespace_option(state, apply_default_ignorewhitespace))
+		return -1;
+	return 0;
+}
+
+void clear_apply_state(struct apply_state *state)
+{
+	string_list_clear(&state->limit_by_name, 0);
+	strset_clear(&state->removed_symlinks);
+	strset_clear(&state->kept_symlinks);
+	strbuf_release(&state->root);
+	FREE_AND_NULL(state->fake_ancestor);
+
+	/* &state->fn_table is cleared at the end of apply_patch() */
+}
+
+static void mute_routine(const char *msg UNUSED, va_list params UNUSED)
+{
+	/* do nothing */
+}
+
+int check_apply_state(struct apply_state *state, int force_apply)
+{
+	int is_not_gitdir = !startup_info->have_repository;
+
+	if (state->apply_with_reject && state->threeway)
+		return error(_("options '%s' and '%s' cannot be used together"), "--reject", "--3way");
+	if (state->threeway) {
+		if (is_not_gitdir)
+			return error(_("'%s' outside a repository"), "--3way");
+		state->check_index = 1;
+	}
+	if (state->apply_with_reject) {
+		state->apply = 1;
+		if (state->apply_verbosity == verbosity_normal)
+			state->apply_verbosity = verbosity_verbose;
+	}
+	if (!force_apply && (state->diffstat || state->numstat || state->summary || state->check || state->fake_ancestor))
+		state->apply = 0;
+	if (state->check_index && is_not_gitdir)
+		return error(_("'%s' outside a repository"), "--index");
+	if (state->cached) {
+		if (is_not_gitdir)
+			return error(_("'%s' outside a repository"), "--cached");
+		state->check_index = 1;
+	}
+	if (state->ita_only && (state->check_index || is_not_gitdir))
+		state->ita_only = 0;
+	if (state->check_index)
+		state->unsafe_paths = 0;
+
+	if (state->apply_verbosity <= verbosity_silent) {
+		state->saved_error_routine = get_error_routine();
+		state->saved_warn_routine = get_warn_routine();
+		set_error_routine(mute_routine);
+		set_warn_routine(mute_routine);
+	}
+
+	return 0;
+}
+
+static void set_default_whitespace_mode(struct apply_state *state)
+{
+	if (!state->whitespace_option && !apply_default_whitespace)
+		state->ws_error_action = (state->apply ? warn_on_ws_error : nowarn_ws_error);
+}
+
+/*
+ * This represents one "hunk" from a patch, starting with
+ * "@@ -oldpos,oldlines +newpos,newlines @@" marker.  The
+ * patch text is pointed at by patch, and its byte length
+ * is stored in size.  leading and trailing are the number
+ * of context lines.
+ */
+struct fragment {
+	unsigned long leading, trailing;
+	unsigned long oldpos, oldlines;
+	unsigned long newpos, newlines;
+	/*
+	 * 'patch' is usually borrowed from buf in apply_patch(),
+	 * but some codepaths store an allocated buffer.
+	 */
+	const char *patch;
+	unsigned free_patch:1,
+		rejected:1;
+	int size;
+	int linenr;
+	struct fragment *next;
+};
+
+/*
+ * When dealing with a binary patch, we reuse "leading" field
+ * to store the type of the binary hunk, either deflated "delta"
+ * or deflated "literal".
+ */
+#define binary_patch_method leading
+#define BINARY_DELTA_DEFLATED	1
+#define BINARY_LITERAL_DEFLATED 2
+
+static void free_fragment_list(struct fragment *list)
+{
+	while (list) {
+		struct fragment *next = list->next;
+		if (list->free_patch)
+			free((char *)list->patch);
+		free(list);
+		list = next;
+	}
+}
+
+void release_patch(struct patch *patch)
+{
+	free_fragment_list(patch->fragments);
+	free(patch->def_name);
+	free(patch->old_name);
+	free(patch->new_name);
+	free(patch->result);
+}
+
+static void free_patch(struct patch *patch)
+{
+	release_patch(patch);
+	free(patch);
+}
+
+static void free_patch_list(struct patch *list)
+{
+	while (list) {
+		struct patch *next = list->next;
+		free_patch(list);
+		list = next;
+	}
+}
+
+/*
+ * A line in a file, len-bytes long (includes the terminating LF,
+ * except for an incomplete line at the end if the file ends with
+ * one), and its contents hashes to 'hash'.
+ */
+struct line {
+	size_t len;
+	unsigned hash : 24;
+	unsigned flag : 8;
+#define LINE_COMMON     1
+#define LINE_PATCHED	2
+};
+
+/*
+ * This represents a "file", which is an array of "lines".
+ */
+struct image {
+	struct strbuf buf;
+	struct line *line;
+	size_t line_nr, line_alloc;
+};
+#define IMAGE_INIT { \
+	.buf = STRBUF_INIT, \
+}
+
+static void image_init(struct image *image)
+{
+	struct image empty = IMAGE_INIT;
+	memcpy(image, &empty, sizeof(*image));
+}
+
+static void image_clear(struct image *image)
+{
+	strbuf_release(&image->buf);
+	free(image->line);
+	image_init(image);
+}
+
+static uint32_t hash_line(const char *cp, size_t len)
+{
+	size_t i;
+	uint32_t h;
+	for (i = 0, h = 0; i < len; i++) {
+		if (!isspace(cp[i])) {
+			h = h * 3 + (cp[i] & 0xff);
+		}
+	}
+	return h;
+}
+
+static void image_add_line(struct image *img, const char *bol, size_t len, unsigned flag)
+{
+	ALLOC_GROW(img->line, img->line_nr + 1, img->line_alloc);
+	img->line[img->line_nr].len = len;
+	img->line[img->line_nr].hash = hash_line(bol, len);
+	img->line[img->line_nr].flag = flag;
+	img->line_nr++;
+}
+
+/*
+ * "buf" has the file contents to be patched (read from various sources).
+ * attach it to "image" and add line-based index to it.
+ * "image" now owns the "buf".
+ */
+static void image_prepare(struct image *image, char *buf, size_t len,
+			  int prepare_linetable)
+{
+	const char *cp, *ep;
+
+	image_clear(image);
+	strbuf_attach(&image->buf, buf, len, len + 1);
+
+	if (!prepare_linetable)
+		return;
+
+	ep = image->buf.buf + image->buf.len;
+	cp = image->buf.buf;
+	while (cp < ep) {
+		const char *next;
+		for (next = cp; next < ep && *next != '\n'; next++)
+			;
+		if (next < ep)
+			next++;
+		image_add_line(image, cp, next - cp, 0);
+		cp = next;
+	}
+}
+
+static void image_remove_first_line(struct image *img)
+{
+	strbuf_remove(&img->buf, 0, img->line[0].len);
+	img->line_nr--;
+	if (img->line_nr)
+		MOVE_ARRAY(img->line, img->line + 1, img->line_nr);
+}
+
+static void image_remove_last_line(struct image *img)
+{
+	size_t last_line_len = img->line[img->line_nr - 1].len;
+	strbuf_setlen(&img->buf, img->buf.len - last_line_len);
+	img->line_nr--;
+}
+
+/* fmt must contain _one_ %s and no other substitution */
+static void say_patch_name(FILE *output, const char *fmt, struct patch *patch)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	if (patch->old_name && patch->new_name &&
+	    strcmp(patch->old_name, patch->new_name)) {
+		quote_c_style(patch->old_name, &sb, NULL, 0);
+		strbuf_addstr(&sb, " => ");
+		quote_c_style(patch->new_name, &sb, NULL, 0);
+	} else {
+		const char *n = patch->new_name;
+		if (!n)
+			n = patch->old_name;
+		quote_c_style(n, &sb, NULL, 0);
+	}
+	fprintf(output, fmt, sb.buf);
+	fputc('\n', output);
+	strbuf_release(&sb);
+}
+
+#define SLOP (16)
+
+/*
+ * apply.c isn't equipped to handle arbitrarily large patches, because
+ * it intermingles `unsigned long` with `int` for the type used to store
+ * buffer lengths.
+ *
+ * Only process patches that are just shy of 1 GiB large in order to
+ * avoid any truncation or overflow issues.
+ */
+#define MAX_APPLY_SIZE (1024UL * 1024 * 1023)
+
+static int read_patch_file(struct strbuf *sb, int fd)
+{
+	if (strbuf_read(sb, fd, 0) < 0)
+		return error_errno(_("failed to read patch"));
+	else if (sb->len >= MAX_APPLY_SIZE)
+		return error(_("patch too large"));
+	/*
+	 * Make sure that we have some slop in the buffer
+	 * so that we can do speculative "memcmp" etc, and
+	 * see to it that it is NUL-filled.
+	 */
+	strbuf_grow(sb, SLOP);
+	memset(sb->buf + sb->len, 0, SLOP);
+	return 0;
+}
+
+static unsigned long linelen(const char *buffer, unsigned long size)
+{
+	unsigned long len = 0;
+	while (size--) {
+		len++;
+		if (*buffer++ == '\n')
+			break;
+	}
+	return len;
+}
+
+static int is_dev_null(const char *str)
+{
+	return skip_prefix(str, "/dev/null", &str) && isspace(*str);
+}
+
+#define TERM_SPACE	1
+#define TERM_TAB	2
+
+static int name_terminate(int c, int terminate)
+{
+	if (c == ' ' && !(terminate & TERM_SPACE))
+		return 0;
+	if (c == '\t' && !(terminate & TERM_TAB))
+		return 0;
+
+	return 1;
+}
+
+/* remove double slashes to make --index work with such filenames */
+static char *squash_slash(char *name)
+{
+	int i = 0, j = 0;
+
+	if (!name)
+		return NULL;
+
+	while (name[i]) {
+		if ((name[j++] = name[i++]) == '/')
+			while (name[i] == '/')
+				i++;
+	}
+	name[j] = '\0';
+	return name;
+}
+
+static char *find_name_gnu(struct strbuf *root,
+			   const char *line,
+			   int p_value)
+{
+	struct strbuf name = STRBUF_INIT;
+	char *cp;
+
+	/*
+	 * Proposed "new-style" GNU patch/diff format; see
+	 * https://lore.kernel.org/git/7vll0wvb2a.fsf@xxxxxxxxxxxxxxxxxxxxxxxx/
+	 */
+	if (unquote_c_style(&name, line, NULL)) {
+		strbuf_release(&name);
+		return NULL;
+	}
+
+	for (cp = name.buf; p_value; p_value--) {
+		cp = strchr(cp, '/');
+		if (!cp) {
+			strbuf_release(&name);
+			return NULL;
+		}
+		cp++;
+	}
+
+	strbuf_remove(&name, 0, cp - name.buf);
+	if (root->len)
+		strbuf_insert(&name, 0, root->buf, root->len);
+	return squash_slash(strbuf_detach(&name, NULL));
+}
+
+static size_t sane_tz_len(const char *line, size_t len)
+{
+	const char *tz, *p;
+
+	if (len < strlen(" +0500") || line[len-strlen(" +0500")] != ' ')
+		return 0;
+	tz = line + len - strlen(" +0500");
+
+	if (tz[1] != '+' && tz[1] != '-')
+		return 0;
+
+	for (p = tz + 2; p != line + len; p++)
+		if (!isdigit(*p))
+			return 0;
+
+	return line + len - tz;
+}
+
+static size_t tz_with_colon_len(const char *line, size_t len)
+{
+	const char *tz, *p;
+
+	if (len < strlen(" +08:00") || line[len - strlen(":00")] != ':')
+		return 0;
+	tz = line + len - strlen(" +08:00");
+
+	if (tz[0] != ' ' || (tz[1] != '+' && tz[1] != '-'))
+		return 0;
+	p = tz + 2;
+	if (!isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+	    !isdigit(*p++) || !isdigit(*p++))
+		return 0;
+
+	return line + len - tz;
+}
+
+static size_t date_len(const char *line, size_t len)
+{
+	const char *date, *p;
+
+	if (len < strlen("72-02-05") || line[len-strlen("-05")] != '-')
+		return 0;
+	p = date = line + len - strlen("72-02-05");
+
+	if (!isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
+	    !isdigit(*p++) || !isdigit(*p++) || *p++ != '-' ||
+	    !isdigit(*p++) || !isdigit(*p++))	/* Not a date. */
+		return 0;
+
+	if (date - line >= strlen("19") &&
+	    isdigit(date[-1]) && isdigit(date[-2]))	/* 4-digit year */
+		date -= strlen("19");
+
+	return line + len - date;
+}
+
+static size_t short_time_len(const char *line, size_t len)
+{
+	const char *time, *p;
+
+	if (len < strlen(" 07:01:32") || line[len-strlen(":32")] != ':')
+		return 0;
+	p = time = line + len - strlen(" 07:01:32");
+
+	/* Permit 1-digit hours? */
+	if (*p++ != ' ' ||
+	    !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+	    !isdigit(*p++) || !isdigit(*p++) || *p++ != ':' ||
+	    !isdigit(*p++) || !isdigit(*p++))	/* Not a time. */
+		return 0;
+
+	return line + len - time;
+}
+
+static size_t fractional_time_len(const char *line, size_t len)
+{
+	const char *p;
+	size_t n;
+
+	/* Expected format: 19:41:17.620000023 */
+	if (!len || !isdigit(line[len - 1]))
+		return 0;
+	p = line + len - 1;
+
+	/* Fractional seconds. */
+	while (p > line && isdigit(*p))
+		p--;
+	if (*p != '.')
+		return 0;
+
+	/* Hours, minutes, and whole seconds. */
+	n = short_time_len(line, p - line);
+	if (!n)
+		return 0;
+
+	return line + len - p + n;
+}
+
+static size_t trailing_spaces_len(const char *line, size_t len)
+{
+	const char *p;
+
+	/* Expected format: ' ' x (1 or more)  */
+	if (!len || line[len - 1] != ' ')
+		return 0;
+
+	p = line + len;
+	while (p != line) {
+		p--;
+		if (*p != ' ')
+			return line + len - (p + 1);
+	}
+
+	/* All spaces! */
+	return len;
+}
+
+static size_t diff_timestamp_len(const char *line, size_t len)
+{
+	const char *end = line + len;
+	size_t n;
+
+	/*
+	 * Posix: 2010-07-05 19:41:17
+	 * GNU: 2010-07-05 19:41:17.620000023 -0500
+	 */
+
+	if (!isdigit(end[-1]))
+		return 0;
+
+	n = sane_tz_len(line, end - line);
+	if (!n)
+		n = tz_with_colon_len(line, end - line);
+	end -= n;
+
+	n = short_time_len(line, end - line);
+	if (!n)
+		n = fractional_time_len(line, end - line);
+	end -= n;
+
+	n = date_len(line, end - line);
+	if (!n)	/* No date.  Too bad. */
+		return 0;
+	end -= n;
+
+	if (end == line)	/* No space before date. */
+		return 0;
+	if (end[-1] == '\t') {	/* Success! */
+		end--;
+		return line + len - end;
+	}
+	if (end[-1] != ' ')	/* No space before date. */
+		return 0;
+
+	/* Whitespace damage. */
+	end -= trailing_spaces_len(line, end - line);
+	return line + len - end;
+}
+
+static char *find_name_common(struct strbuf *root,
+			      const char *line,
+			      const char *def,
+			      int p_value,
+			      const char *end,
+			      int terminate)
+{
+	int len;
+	const char *start = NULL;
+
+	if (p_value == 0)
+		start = line;
+	while (line != end) {
+		char c = *line;
+
+		if (!end && isspace(c)) {
+			if (c == '\n')
+				break;
+			if (name_terminate(c, terminate))
+				break;
+		}
+		line++;
+		if (c == '/' && !--p_value)
+			start = line;
+	}
+	if (!start)
+		return squash_slash(xstrdup_or_null(def));
+	len = line - start;
+	if (!len)
+		return squash_slash(xstrdup_or_null(def));
+
+	/*
+	 * Generally we prefer the shorter name, especially
+	 * if the other one is just a variation of that with
+	 * something else tacked on to the end (ie "file.orig"
+	 * or "file~").
+	 */
+	if (def) {
+		int deflen = strlen(def);
+		if (deflen < len && !strncmp(start, def, deflen))
+			return squash_slash(xstrdup(def));
+	}
+
+	if (root->len) {
+		char *ret = xstrfmt("%s%.*s", root->buf, len, start);
+		return squash_slash(ret);
+	}
+
+	return squash_slash(xmemdupz(start, len));
+}
+
+static char *find_name(struct strbuf *root,
+		       const char *line,
+		       char *def,
+		       int p_value,
+		       int terminate)
+{
+	if (*line == '"') {
+		char *name = find_name_gnu(root, line, p_value);
+		if (name)
+			return name;
+	}
+
+	return find_name_common(root, line, def, p_value, NULL, terminate);
+}
+
+static char *find_name_traditional(struct strbuf *root,
+				   const char *line,
+				   char *def,
+				   int p_value)
+{
+	size_t len;
+	size_t date_len;
+
+	if (*line == '"') {
+		char *name = find_name_gnu(root, line, p_value);
+		if (name)
+			return name;
+	}
+
+	len = strchrnul(line, '\n') - line;
+	date_len = diff_timestamp_len(line, len);
+	if (!date_len)
+		return find_name_common(root, line, def, p_value, NULL, TERM_TAB);
+	len -= date_len;
+
+	return find_name_common(root, line, def, p_value, line + len, 0);
+}
+
+/*
+ * Given the string after "--- " or "+++ ", guess the appropriate
+ * p_value for the given patch.
+ */
+static int guess_p_value(struct apply_state *state, const char *nameline)
+{
+	char *name, *cp;
+	int val = -1;
+
+	if (is_dev_null(nameline))
+		return -1;
+	name = find_name_traditional(&state->root, nameline, NULL, 0);
+	if (!name)
+		return -1;
+	cp = strchr(name, '/');
+	if (!cp)
+		val = 0;
+	else if (state->prefix) {
+		/*
+		 * Does it begin with "a/$our-prefix" and such?  Then this is
+		 * very likely to apply to our directory.
+		 */
+		if (starts_with(name, state->prefix))
+			val = count_slashes(state->prefix);
+		else {
+			cp++;
+			if (starts_with(cp, state->prefix))
+				val = count_slashes(state->prefix) + 1;
+		}
+	}
+	free(name);
+	return val;
+}
+
+/*
+ * Does the ---/+++ line have the POSIX timestamp after the last HT?
+ * GNU diff puts epoch there to signal a creation/deletion event.  Is
+ * this such a timestamp?
+ */
+static int has_epoch_timestamp(const char *nameline)
+{
+	/*
+	 * We are only interested in epoch timestamp; any non-zero
+	 * fraction cannot be one, hence "(\.0+)?" in the regexp below.
+	 * For the same reason, the date must be either 1969-12-31 or
+	 * 1970-01-01, and the seconds part must be "00".
+	 */
+	const char stamp_regexp[] =
+		"^[0-2][0-9]:([0-5][0-9]):00(\\.0+)?"
+		" "
+		"([-+][0-2][0-9]:?[0-5][0-9])\n";
+	const char *timestamp = NULL, *cp, *colon;
+	static regex_t *stamp;
+	regmatch_t m[10];
+	int zoneoffset, epoch_hour, hour, minute;
+	int status;
+
+	for (cp = nameline; *cp != '\n'; cp++) {
+		if (*cp == '\t')
+			timestamp = cp + 1;
+	}
+	if (!timestamp)
+		return 0;
+
+	/*
+	 * YYYY-MM-DD hh:mm:ss must be from either 1969-12-31
+	 * (west of GMT) or 1970-01-01 (east of GMT)
+	 */
+	if (skip_prefix(timestamp, "1969-12-31 ", &timestamp))
+		epoch_hour = 24;
+	else if (skip_prefix(timestamp, "1970-01-01 ", &timestamp))
+		epoch_hour = 0;
+	else
+		return 0;
+
+	if (!stamp) {
+		stamp = xmalloc(sizeof(*stamp));
+		if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) {
+			warning(_("Cannot prepare timestamp regexp %s"),
+				stamp_regexp);
+			return 0;
+		}
+	}
+
+	status = regexec(stamp, timestamp, ARRAY_SIZE(m), m, 0);
+	if (status) {
+		if (status != REG_NOMATCH)
+			warning(_("regexec returned %d for input: %s"),
+				status, timestamp);
+		return 0;
+	}
+
+	hour = strtol(timestamp, NULL, 10);
+	minute = strtol(timestamp + m[1].rm_so, NULL, 10);
+
+	zoneoffset = strtol(timestamp + m[3].rm_so + 1, (char **) &colon, 10);
+	if (*colon == ':')
+		zoneoffset = zoneoffset * 60 + strtol(colon + 1, NULL, 10);
+	else
+		zoneoffset = (zoneoffset / 100) * 60 + (zoneoffset % 100);
+	if (timestamp[m[3].rm_so] == '-')
+		zoneoffset = -zoneoffset;
+
+	return hour * 60 + minute - zoneoffset == epoch_hour * 60;
+}
+
+/*
+ * Get the name etc info from the ---/+++ lines of a traditional patch header
+ *
+ * FIXME! The end-of-filename heuristics are kind of screwy. For existing
+ * files, we can happily check the index for a match, but for creating a
+ * new file we should try to match whatever "patch" does. I have no idea.
+ */
+static int parse_traditional_patch(struct apply_state *state,
+				   const char *first,
+				   const char *second,
+				   struct patch *patch)
+{
+	char *name;
+
+	first += 4;	/* skip "--- " */
+	second += 4;	/* skip "+++ " */
+	if (!state->p_value_known) {
+		int p, q;
+		p = guess_p_value(state, first);
+		q = guess_p_value(state, second);
+		if (p < 0) p = q;
+		if (0 <= p && p == q) {
+			state->p_value = p;
+			state->p_value_known = 1;
+		}
+	}
+	if (is_dev_null(first)) {
+		patch->is_new = 1;
+		patch->is_delete = 0;
+		name = find_name_traditional(&state->root, second, NULL, state->p_value);
+		patch->new_name = name;
+	} else if (is_dev_null(second)) {
+		patch->is_new = 0;
+		patch->is_delete = 1;
+		name = find_name_traditional(&state->root, first, NULL, state->p_value);
+		patch->old_name = name;
+	} else {
+		char *first_name;
+		first_name = find_name_traditional(&state->root, first, NULL, state->p_value);
+		name = find_name_traditional(&state->root, second, first_name, state->p_value);
+		free(first_name);
+		if (has_epoch_timestamp(first)) {
+			patch->is_new = 1;
+			patch->is_delete = 0;
+			patch->new_name = name;
+		} else if (has_epoch_timestamp(second)) {
+			patch->is_new = 0;
+			patch->is_delete = 1;
+			patch->old_name = name;
+		} else {
+			patch->old_name = name;
+			patch->new_name = xstrdup_or_null(name);
+		}
+	}
+	if (!name)
+		return error(_("unable to find filename in patch at line %d"), state->linenr);
+
+	return 0;
+}
+
+static int gitdiff_hdrend(struct gitdiff_data *state UNUSED,
+			  const char *line UNUSED,
+			  struct patch *patch UNUSED)
+{
+	return 1;
+}
+
+/*
+ * We're anal about diff header consistency, to make
+ * sure that we don't end up having strange ambiguous
+ * patches floating around.
+ *
+ * As a result, gitdiff_{old|new}name() will check
+ * their names against any previous information, just
+ * to make sure..
+ */
+#define DIFF_OLD_NAME 0
+#define DIFF_NEW_NAME 1
+
+static int gitdiff_verify_name(struct gitdiff_data *state,
+			       const char *line,
+			       int isnull,
+			       char **name,
+			       int side)
+{
+	if (!*name && !isnull) {
+		*name = find_name(state->root, line, NULL, state->p_value, TERM_TAB);
+		return 0;
+	}
+
+	if (*name) {
+		char *another;
+		if (isnull)
+			return error(_("git apply: bad git-diff - expected /dev/null, got %s on line %d"),
+				     *name, state->linenr);
+		another = find_name(state->root, line, NULL, state->p_value, TERM_TAB);
+		if (!another || strcmp(another, *name)) {
+			free(another);
+			return error((side == DIFF_NEW_NAME) ?
+			    _("git apply: bad git-diff - inconsistent new filename on line %d") :
+			    _("git apply: bad git-diff - inconsistent old filename on line %d"), state->linenr);
+		}
+		free(another);
+	} else {
+		if (!is_dev_null(line))
+			return error(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
+	}
+
+	return 0;
+}
+
+static int gitdiff_oldname(struct gitdiff_data *state,
+			   const char *line,
+			   struct patch *patch)
+{
+	return gitdiff_verify_name(state, line,
+				   patch->is_new, &patch->old_name,
+				   DIFF_OLD_NAME);
+}
+
+static int gitdiff_newname(struct gitdiff_data *state,
+			   const char *line,
+			   struct patch *patch)
+{
+	return gitdiff_verify_name(state, line,
+				   patch->is_delete, &patch->new_name,
+				   DIFF_NEW_NAME);
+}
+
+static int parse_mode_line(const char *line, int linenr, unsigned int *mode)
+{
+	char *end;
+	*mode = strtoul(line, &end, 8);
+	if (end == line || !isspace(*end))
+		return error(_("invalid mode on line %d: %s"), linenr, line);
+	*mode = canon_mode(*mode);
+	return 0;
+}
+
+static int gitdiff_oldmode(struct gitdiff_data *state,
+			   const char *line,
+			   struct patch *patch)
+{
+	return parse_mode_line(line, state->linenr, &patch->old_mode);
+}
+
+static int gitdiff_newmode(struct gitdiff_data *state,
+			   const char *line,
+			   struct patch *patch)
+{
+	return parse_mode_line(line, state->linenr, &patch->new_mode);
+}
+
+static int gitdiff_delete(struct gitdiff_data *state,
+			  const char *line,
+			  struct patch *patch)
+{
+	patch->is_delete = 1;
+	free(patch->old_name);
+	patch->old_name = xstrdup_or_null(patch->def_name);
+	return gitdiff_oldmode(state, line, patch);
+}
+
+static int gitdiff_newfile(struct gitdiff_data *state,
+			   const char *line,
+			   struct patch *patch)
+{
+	patch->is_new = 1;
+	free(patch->new_name);
+	patch->new_name = xstrdup_or_null(patch->def_name);
+	return gitdiff_newmode(state, line, patch);
+}
+
+static int gitdiff_copysrc(struct gitdiff_data *state,
+			   const char *line,
+			   struct patch *patch)
+{
+	patch->is_copy = 1;
+	free(patch->old_name);
+	patch->old_name = find_name(state->root, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
+	return 0;
+}
+
+static int gitdiff_copydst(struct gitdiff_data *state,
+			   const char *line,
+			   struct patch *patch)
+{
+	patch->is_copy = 1;
+	free(patch->new_name);
+	patch->new_name = find_name(state->root, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
+	return 0;
+}
+
+static int gitdiff_renamesrc(struct gitdiff_data *state,
+			     const char *line,
+			     struct patch *patch)
+{
+	patch->is_rename = 1;
+	free(patch->old_name);
+	patch->old_name = find_name(state->root, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
+	return 0;
+}
+
+static int gitdiff_renamedst(struct gitdiff_data *state,
+			     const char *line,
+			     struct patch *patch)
+{
+	patch->is_rename = 1;
+	free(patch->new_name);
+	patch->new_name = find_name(state->root, line, NULL, state->p_value ? state->p_value - 1 : 0, 0);
+	return 0;
+}
+
+static int gitdiff_similarity(struct gitdiff_data *state UNUSED,
+			      const char *line,
+			      struct patch *patch)
+{
+	unsigned long val = strtoul(line, NULL, 10);
+	if (val <= 100)
+		patch->score = val;
+	return 0;
+}
+
+static int gitdiff_dissimilarity(struct gitdiff_data *state UNUSED,
+				 const char *line,
+				 struct patch *patch)
+{
+	unsigned long val = strtoul(line, NULL, 10);
+	if (val <= 100)
+		patch->score = val;
+	return 0;
+}
+
+static int gitdiff_index(struct gitdiff_data *state,
+			 const char *line,
+			 struct patch *patch)
+{
+	/*
+	 * index line is N hexadecimal, "..", N hexadecimal,
+	 * and optional space with octal mode.
+	 */
+	const char *ptr, *eol;
+	int len;
+	const unsigned hexsz = the_hash_algo->hexsz;
+
+	ptr = strchr(line, '.');
+	if (!ptr || ptr[1] != '.' || hexsz < ptr - line)
+		return 0;
+	len = ptr - line;
+	memcpy(patch->old_oid_prefix, line, len);
+	patch->old_oid_prefix[len] = 0;
+
+	line = ptr + 2;
+	ptr = strchr(line, ' ');
+	eol = strchrnul(line, '\n');
+
+	if (!ptr || eol < ptr)
+		ptr = eol;
+	len = ptr - line;
+
+	if (hexsz < len)
+		return 0;
+	memcpy(patch->new_oid_prefix, line, len);
+	patch->new_oid_prefix[len] = 0;
+	if (*ptr == ' ')
+		return gitdiff_oldmode(state, ptr + 1, patch);
+	return 0;
+}
+
+/*
+ * This is normal for a diff that doesn't change anything: we'll fall through
+ * into the next diff. Tell the parser to break out.
+ */
+static int gitdiff_unrecognized(struct gitdiff_data *state UNUSED,
+				const char *line UNUSED,
+				struct patch *patch UNUSED)
+{
+	return 1;
+}
+
+/*
+ * Skip p_value leading components from "line"; as we do not accept
+ * absolute paths, return NULL in that case.
+ */
+static const char *skip_tree_prefix(int p_value,
+				    const char *line,
+				    int llen)
+{
+	int nslash;
+	int i;
+
+	if (!p_value)
+		return (llen && line[0] == '/') ? NULL : line;
+
+	nslash = p_value;
+	for (i = 0; i < llen; i++) {
+		int ch = line[i];
+		if (ch == '/' && --nslash <= 0)
+			return (i == 0) ? NULL : &line[i + 1];
+	}
+	return NULL;
+}
+
+/*
+ * This is to extract the same name that appears on "diff --git"
+ * line.  We do not find and return anything if it is a rename
+ * patch, and it is OK because we will find the name elsewhere.
+ * We need to reliably find name only when it is mode-change only,
+ * creation or deletion of an empty file.  In any of these cases,
+ * both sides are the same name under a/ and b/ respectively.
+ */
+static char *git_header_name(int p_value,
+			     const char *line,
+			     int llen)
+{
+	const char *name;
+	const char *second = NULL;
+	size_t len, line_len;
+
+	line += strlen("diff --git ");
+	llen -= strlen("diff --git ");
+
+	if (*line == '"') {
+		const char *cp;
+		struct strbuf first = STRBUF_INIT;
+		struct strbuf sp = STRBUF_INIT;
+
+		if (unquote_c_style(&first, line, &second))
+			goto free_and_fail1;
+
+		/* strip the a/b prefix including trailing slash */
+		cp = skip_tree_prefix(p_value, first.buf, first.len);
+		if (!cp)
+			goto free_and_fail1;
+		strbuf_remove(&first, 0, cp - first.buf);
+
+		/*
+		 * second points at one past closing dq of name.
+		 * find the second name.
+		 */
+		while ((second < line + llen) && isspace(*second))
+			second++;
+
+		if (line + llen <= second)
+			goto free_and_fail1;
+		if (*second == '"') {
+			if (unquote_c_style(&sp, second, NULL))
+				goto free_and_fail1;
+			cp = skip_tree_prefix(p_value, sp.buf, sp.len);
+			if (!cp)
+				goto free_and_fail1;
+			/* They must match, otherwise ignore */
+			if (strcmp(cp, first.buf))
+				goto free_and_fail1;
+			strbuf_release(&sp);
+			return strbuf_detach(&first, NULL);
+		}
+
+		/* unquoted second */
+		cp = skip_tree_prefix(p_value, second, line + llen - second);
+		if (!cp)
+			goto free_and_fail1;
+		if (line + llen - cp != first.len ||
+		    memcmp(first.buf, cp, first.len))
+			goto free_and_fail1;
+		return strbuf_detach(&first, NULL);
+
+	free_and_fail1:
+		strbuf_release(&first);
+		strbuf_release(&sp);
+		return NULL;
+	}
+
+	/* unquoted first name */
+	name = skip_tree_prefix(p_value, line, llen);
+	if (!name)
+		return NULL;
+
+	/*
+	 * since the first name is unquoted, a dq if exists must be
+	 * the beginning of the second name.
+	 */
+	for (second = name; second < line + llen; second++) {
+		if (*second == '"') {
+			struct strbuf sp = STRBUF_INIT;
+			const char *np;
+
+			if (unquote_c_style(&sp, second, NULL))
+				goto free_and_fail2;
+
+			np = skip_tree_prefix(p_value, sp.buf, sp.len);
+			if (!np)
+				goto free_and_fail2;
+
+			len = sp.buf + sp.len - np;
+			if (len < second - name &&
+			    !strncmp(np, name, len) &&
+			    isspace(name[len])) {
+				/* Good */
+				strbuf_remove(&sp, 0, np - sp.buf);
+				return strbuf_detach(&sp, NULL);
+			}
+
+		free_and_fail2:
+			strbuf_release(&sp);
+			return NULL;
+		}
+	}
+
+	/*
+	 * Accept a name only if it shows up twice, exactly the same
+	 * form.
+	 */
+	second = strchr(name, '\n');
+	if (!second)
+		return NULL;
+	line_len = second - name;
+	for (len = 0 ; ; len++) {
+		switch (name[len]) {
+		default:
+			continue;
+		case '\n':
+			return NULL;
+		case '\t': case ' ':
+			/*
+			 * Is this the separator between the preimage
+			 * and the postimage pathname?  Again, we are
+			 * only interested in the case where there is
+			 * no rename, as this is only to set def_name
+			 * and a rename patch has the names elsewhere
+			 * in an unambiguous form.
+			 */
+			if (!name[len + 1])
+				return NULL; /* no postimage name */
+			second = skip_tree_prefix(p_value, name + len + 1,
+						  line_len - (len + 1));
+			/*
+			 * If we are at the SP at the end of a directory,
+			 * skip_tree_prefix() may return NULL as that makes
+			 * it appears as if we have an absolute path.
+			 * Keep going to find another SP.
+			 */
+			if (!second)
+				continue;
+
+			/*
+			 * Does len bytes starting at "name" and "second"
+			 * (that are separated by one HT or SP we just
+			 * found) exactly match?
+			 */
+			if (second[len] == '\n' && !strncmp(name, second, len))
+				return xmemdupz(name, len);
+		}
+	}
+}
+
+static int check_header_line(int linenr, struct patch *patch)
+{
+	int extensions = (patch->is_delete == 1) + (patch->is_new == 1) +
+			 (patch->is_rename == 1) + (patch->is_copy == 1);
+	if (extensions > 1)
+		return error(_("inconsistent header lines %d and %d"),
+			     patch->extension_linenr, linenr);
+	if (extensions && !patch->extension_linenr)
+		patch->extension_linenr = linenr;
+	return 0;
+}
+
+int parse_git_diff_header(struct strbuf *root,
+			  int *linenr,
+			  int p_value,
+			  const char *line,
+			  int len,
+			  unsigned int size,
+			  struct patch *patch)
+{
+	unsigned long offset;
+	struct gitdiff_data parse_hdr_state;
+
+	/* A git diff has explicit new/delete information, so we don't guess */
+	patch->is_new = 0;
+	patch->is_delete = 0;
+
+	/*
+	 * Some things may not have the old name in the
+	 * rest of the headers anywhere (pure mode changes,
+	 * or removing or adding empty files), so we get
+	 * the default name from the header.
+	 */
+	patch->def_name = git_header_name(p_value, line, len);
+	if (patch->def_name && root->len) {
+		char *s = xstrfmt("%s%s", root->buf, patch->def_name);
+		free(patch->def_name);
+		patch->def_name = s;
+	}
+
+	line += len;
+	size -= len;
+	(*linenr)++;
+	parse_hdr_state.root = root;
+	parse_hdr_state.linenr = *linenr;
+	parse_hdr_state.p_value = p_value;
+
+	for (offset = len ; size > 0 ; offset += len, size -= len, line += len, (*linenr)++) {
+		static const struct opentry {
+			const char *str;
+			int (*fn)(struct gitdiff_data *, const char *, struct patch *);
+		} optable[] = {
+			{ "@@ -", gitdiff_hdrend },
+			{ "--- ", gitdiff_oldname },
+			{ "+++ ", gitdiff_newname },
+			{ "old mode ", gitdiff_oldmode },
+			{ "new mode ", gitdiff_newmode },
+			{ "deleted file mode ", gitdiff_delete },
+			{ "new file mode ", gitdiff_newfile },
+			{ "copy from ", gitdiff_copysrc },
+			{ "copy to ", gitdiff_copydst },
+			{ "rename old ", gitdiff_renamesrc },
+			{ "rename new ", gitdiff_renamedst },
+			{ "rename from ", gitdiff_renamesrc },
+			{ "rename to ", gitdiff_renamedst },
+			{ "similarity index ", gitdiff_similarity },
+			{ "dissimilarity index ", gitdiff_dissimilarity },
+			{ "index ", gitdiff_index },
+			{ "", gitdiff_unrecognized },
+		};
+		int i;
+
+		len = linelen(line, size);
+		if (!len || line[len-1] != '\n')
+			break;
+		for (i = 0; i < ARRAY_SIZE(optable); i++) {
+			const struct opentry *p = optable + i;
+			int oplen = strlen(p->str);
+			int res;
+			if (len < oplen || memcmp(p->str, line, oplen))
+				continue;
+			res = p->fn(&parse_hdr_state, line + oplen, patch);
+			if (res < 0)
+				return -1;
+			if (check_header_line(*linenr, patch))
+				return -1;
+			if (res > 0)
+				goto done;
+			break;
+		}
+	}
+
+done:
+	if (!patch->old_name && !patch->new_name) {
+		if (!patch->def_name) {
+			error(Q_("git diff header lacks filename information when removing "
+				 "%d leading pathname component (line %d)",
+				 "git diff header lacks filename information when removing "
+				 "%d leading pathname components (line %d)",
+				 parse_hdr_state.p_value),
+			      parse_hdr_state.p_value, *linenr);
+			return -128;
+		}
+		patch->old_name = xstrdup(patch->def_name);
+		patch->new_name = xstrdup(patch->def_name);
+	}
+	if ((!patch->new_name && !patch->is_delete) ||
+	    (!patch->old_name && !patch->is_new)) {
+		error(_("git diff header lacks filename information "
+			"(line %d)"), *linenr);
+		return -128;
+	}
+	patch->is_toplevel_relative = 1;
+	return offset;
+}
+
+static int parse_num(const char *line, unsigned long *p)
+{
+	char *ptr;
+
+	if (!isdigit(*line))
+		return 0;
+	*p = strtoul(line, &ptr, 10);
+	return ptr - line;
+}
+
+static int parse_range(const char *line, int len, int offset, const char *expect,
+		       unsigned long *p1, unsigned long *p2)
+{
+	int digits, ex;
+
+	if (offset < 0 || offset >= len)
+		return -1;
+	line += offset;
+	len -= offset;
+
+	digits = parse_num(line, p1);
+	if (!digits)
+		return -1;
+
+	offset += digits;
+	line += digits;
+	len -= digits;
+
+	*p2 = 1;
+	if (*line == ',') {
+		digits = parse_num(line+1, p2);
+		if (!digits)
+			return -1;
+
+		offset += digits+1;
+		line += digits+1;
+		len -= digits+1;
+	}
+
+	ex = strlen(expect);
+	if (ex > len)
+		return -1;
+	if (memcmp(line, expect, ex))
+		return -1;
+
+	return offset + ex;
+}
+
+static void recount_diff(const char *line, int size, struct fragment *fragment)
+{
+	int oldlines = 0, newlines = 0, ret = 0;
+
+	if (size < 1) {
+		warning("recount: ignore empty hunk");
+		return;
+	}
+
+	for (;;) {
+		int len = linelen(line, size);
+		size -= len;
+		line += len;
+
+		if (size < 1)
+			break;
+
+		switch (*line) {
+		case ' ': case '\n':
+			newlines++;
+			/* fall through */
+		case '-':
+			oldlines++;
+			continue;
+		case '+':
+			newlines++;
+			continue;
+		case '\\':
+			continue;
+		case '@':
+			ret = size < 3 || !starts_with(line, "@@ ");
+			break;
+		case 'd':
+			ret = size < 5 || !starts_with(line, "diff ");
+			break;
+		default:
+			ret = -1;
+			break;
+		}
+		if (ret) {
+			warning(_("recount: unexpected line: %.*s"),
+				(int)linelen(line, size), line);
+			return;
+		}
+		break;
+	}
+	fragment->oldlines = oldlines;
+	fragment->newlines = newlines;
+}
+
+/*
+ * Parse a unified diff fragment header of the
+ * form "@@ -a,b +c,d @@"
+ */
+static int parse_fragment_header(const char *line, int len, struct fragment *fragment)
+{
+	int offset;
+
+	if (!len || line[len-1] != '\n')
+		return -1;
+
+	/* Figure out the number of lines in a fragment */
+	offset = parse_range(line, len, 4, " +", &fragment->oldpos, &fragment->oldlines);
+	offset = parse_range(line, len, offset, " @@", &fragment->newpos, &fragment->newlines);
+
+	return offset;
+}
+
+/*
+ * Find file diff header
+ *
+ * Returns:
+ *  -1 if no header was found
+ *  -128 in case of error
+ *   the size of the header in bytes (called "offset") otherwise
+ */
+static int find_header(struct apply_state *state,
+		       const char *line,
+		       unsigned long size,
+		       int *hdrsize,
+		       struct patch *patch)
+{
+	unsigned long offset, len;
+
+	patch->is_toplevel_relative = 0;
+	patch->is_rename = patch->is_copy = 0;
+	patch->is_new = patch->is_delete = -1;
+	patch->old_mode = patch->new_mode = 0;
+	patch->old_name = patch->new_name = NULL;
+	for (offset = 0; size > 0; offset += len, size -= len, line += len, state->linenr++) {
+		unsigned long nextlen;
+
+		len = linelen(line, size);
+		if (!len)
+			break;
+
+		/* Testing this early allows us to take a few shortcuts.. */
+		if (len < 6)
+			continue;
+
+		/*
+		 * Make sure we don't find any unconnected patch fragments.
+		 * That's a sign that we didn't find a header, and that a
+		 * patch has become corrupted/broken up.
+		 */
+		if (!memcmp("@@ -", line, 4)) {
+			struct fragment dummy;
+			if (parse_fragment_header(line, len, &dummy) < 0)
+				continue;
+			error(_("patch fragment without header at line %d: %.*s"),
+				     state->linenr, (int)len-1, line);
+			return -128;
+		}
+
+		if (size < len + 6)
+			break;
+
+		/*
+		 * Git patch? It might not have a real patch, just a rename
+		 * or mode change, so we handle that specially
+		 */
+		if (!memcmp("diff --git ", line, 11)) {
+			int git_hdr_len = parse_git_diff_header(&state->root, &state->linenr,
+								state->p_value, line, len,
+								size, patch);
+			if (git_hdr_len < 0)
+				return -128;
+			if (git_hdr_len <= len)
+				continue;
+			*hdrsize = git_hdr_len;
+			return offset;
+		}
+
+		/* --- followed by +++ ? */
+		if (memcmp("--- ", line,  4) || memcmp("+++ ", line + len, 4))
+			continue;
+
+		/*
+		 * We only accept unified patches, so we want it to
+		 * at least have "@@ -a,b +c,d @@\n", which is 14 chars
+		 * minimum ("@@ -0,0 +1 @@\n" is the shortest).
+		 */
+		nextlen = linelen(line + len, size - len);
+		if (size < nextlen + 14 || memcmp("@@ -", line + len + nextlen, 4))
+			continue;
+
+		/* Ok, we'll consider it a patch */
+		if (parse_traditional_patch(state, line, line+len, patch))
+			return -128;
+		*hdrsize = len + nextlen;
+		state->linenr += 2;
+		return offset;
+	}
+	return -1;
+}
+
+static void record_ws_error(struct apply_state *state,
+			    unsigned result,
+			    const char *line,
+			    int len,
+			    int linenr)
+{
+	char *err;
+
+	if (!result)
+		return;
+
+	state->whitespace_error++;
+	if (state->squelch_whitespace_errors &&
+	    state->squelch_whitespace_errors < state->whitespace_error)
+		return;
+
+	err = whitespace_error_string(result);
+	if (state->apply_verbosity > verbosity_silent)
+		fprintf(stderr, "%s:%d: %s.\n%.*s\n",
+			state->patch_input_file, linenr, err, len, line);
+	free(err);
+}
+
+static void check_whitespace(struct apply_state *state,
+			     const char *line,
+			     int len,
+			     unsigned ws_rule)
+{
+	unsigned result = ws_check(line + 1, len - 1, ws_rule);
+
+	record_ws_error(state, result, line + 1, len - 2, state->linenr);
+}
+
+/*
+ * Check if the patch has context lines with CRLF or
+ * the patch wants to remove lines with CRLF.
+ */
+static void check_old_for_crlf(struct patch *patch, const char *line, int len)
+{
+	if (len >= 2 && line[len-1] == '\n' && line[len-2] == '\r') {
+		patch->ws_rule |= WS_CR_AT_EOL;
+		patch->crlf_in_old = 1;
+	}
+}
+
+
+/*
+ * Parse a unified diff. Note that this really needs to parse each
+ * fragment separately, since the only way to know the difference
+ * between a "---" that is part of a patch, and a "---" that starts
+ * the next patch is to look at the line counts..
+ */
+static int parse_fragment(struct apply_state *state,
+			  const char *line,
+			  unsigned long size,
+			  struct patch *patch,
+			  struct fragment *fragment)
+{
+	int added, deleted;
+	int len = linelen(line, size), offset;
+	unsigned long oldlines, newlines;
+	unsigned long leading, trailing;
+
+	offset = parse_fragment_header(line, len, fragment);
+	if (offset < 0)
+		return -1;
+	if (offset > 0 && patch->recount)
+		recount_diff(line + offset, size - offset, fragment);
+	oldlines = fragment->oldlines;
+	newlines = fragment->newlines;
+	leading = 0;
+	trailing = 0;
+
+	/* Parse the thing.. */
+	line += len;
+	size -= len;
+	state->linenr++;
+	added = deleted = 0;
+	for (offset = len;
+	     0 < size;
+	     offset += len, size -= len, line += len, state->linenr++) {
+		if (!oldlines && !newlines)
+			break;
+		len = linelen(line, size);
+		if (!len || line[len-1] != '\n')
+			return -1;
+		switch (*line) {
+		default:
+			return -1;
+		case '\n': /* newer GNU diff, an empty context line */
+		case ' ':
+			oldlines--;
+			newlines--;
+			if (!deleted && !added)
+				leading++;
+			trailing++;
+			check_old_for_crlf(patch, line, len);
+			if (!state->apply_in_reverse &&
+			    state->ws_error_action == correct_ws_error)
+				check_whitespace(state, line, len, patch->ws_rule);
+			break;
+		case '-':
+			if (!state->apply_in_reverse)
+				check_old_for_crlf(patch, line, len);
+			if (state->apply_in_reverse &&
+			    state->ws_error_action != nowarn_ws_error)
+				check_whitespace(state, line, len, patch->ws_rule);
+			deleted++;
+			oldlines--;
+			trailing = 0;
+			break;
+		case '+':
+			if (state->apply_in_reverse)
+				check_old_for_crlf(patch, line, len);
+			if (!state->apply_in_reverse &&
+			    state->ws_error_action != nowarn_ws_error)
+				check_whitespace(state, line, len, patch->ws_rule);
+			added++;
+			newlines--;
+			trailing = 0;
+			break;
+
+		/*
+		 * We allow "\ No newline at end of file". Depending
+		 * on locale settings when the patch was produced we
+		 * don't know what this line looks like. The only
+		 * thing we do know is that it begins with "\ ".
+		 * Checking for 12 is just for sanity check -- any
+		 * l10n of "\ No newline..." is at least that long.
+		 */
+		case '\\':
+			if (len < 12 || memcmp(line, "\\ ", 2))
+				return -1;
+			break;
+		}
+	}
+	if (oldlines || newlines)
+		return -1;
+	if (!patch->recount && !deleted && !added)
+		return -1;
+
+	fragment->leading = leading;
+	fragment->trailing = trailing;
+
+	/*
+	 * If a fragment ends with an incomplete line, we failed to include
+	 * it in the above loop because we hit oldlines == newlines == 0
+	 * before seeing it.
+	 */
+	if (12 < size && !memcmp(line, "\\ ", 2))
+		offset += linelen(line, size);
+
+	patch->lines_added += added;
+	patch->lines_deleted += deleted;
+
+	if (0 < patch->is_new && oldlines)
+		return error(_("new file depends on old contents"));
+	if (0 < patch->is_delete && newlines)
+		return error(_("deleted file still has contents"));
+	return offset;
+}
+
+/*
+ * We have seen "diff --git a/... b/..." header (or a traditional patch
+ * header).  Read hunks that belong to this patch into fragments and hang
+ * them to the given patch structure.
+ *
+ * The (fragment->patch, fragment->size) pair points into the memory given
+ * by the caller, not a copy, when we return.
+ *
+ * Returns:
+ *   -1 in case of error,
+ *   the number of bytes in the patch otherwise.
+ */
+static int parse_single_patch(struct apply_state *state,
+			      const char *line,
+			      unsigned long size,
+			      struct patch *patch)
+{
+	unsigned long offset = 0;
+	unsigned long oldlines = 0, newlines = 0, context = 0;
+	struct fragment **fragp = &patch->fragments;
+
+	while (size > 4 && !memcmp(line, "@@ -", 4)) {
+		struct fragment *fragment;
+		int len;
+
+		CALLOC_ARRAY(fragment, 1);
+		fragment->linenr = state->linenr;
+		len = parse_fragment(state, line, size, patch, fragment);
+		if (len <= 0) {
+			free(fragment);
+			return error(_("corrupt patch at line %d"), state->linenr);
+		}
+		fragment->patch = line;
+		fragment->size = len;
+		oldlines += fragment->oldlines;
+		newlines += fragment->newlines;
+		context += fragment->leading + fragment->trailing;
+
+		*fragp = fragment;
+		fragp = &fragment->next;
+
+		offset += len;
+		line += len;
+		size -= len;
+	}
+
+	/*
+	 * If something was removed (i.e. we have old-lines) it cannot
+	 * be creation, and if something was added it cannot be
+	 * deletion.  However, the reverse is not true; --unified=0
+	 * patches that only add are not necessarily creation even
+	 * though they do not have any old lines, and ones that only
+	 * delete are not necessarily deletion.
+	 *
+	 * Unfortunately, a real creation/deletion patch do _not_ have
+	 * any context line by definition, so we cannot safely tell it
+	 * apart with --unified=0 insanity.  At least if the patch has
+	 * more than one hunk it is not creation or deletion.
+	 */
+	if (patch->is_new < 0 &&
+	    (oldlines || (patch->fragments && patch->fragments->next)))
+		patch->is_new = 0;
+	if (patch->is_delete < 0 &&
+	    (newlines || (patch->fragments && patch->fragments->next)))
+		patch->is_delete = 0;
+
+	if (0 < patch->is_new && oldlines)
+		return error(_("new file %s depends on old contents"), patch->new_name);
+	if (0 < patch->is_delete && newlines)
+		return error(_("deleted file %s still has contents"), patch->old_name);
+	if (!patch->is_delete && !newlines && context && state->apply_verbosity > verbosity_silent)
+		fprintf_ln(stderr,
+			   _("** warning: "
+			     "file %s becomes empty but is not deleted"),
+			   patch->new_name);
+
+	return offset;
+}
+
+static inline int metadata_changes(struct patch *patch)
+{
+	return	patch->is_rename > 0 ||
+		patch->is_copy > 0 ||
+		patch->is_new > 0 ||
+		patch->is_delete ||
+		(patch->old_mode && patch->new_mode &&
+		 patch->old_mode != patch->new_mode);
+}
+
+static char *inflate_it(const void *data, unsigned long size,
+			unsigned long inflated_size)
+{
+	git_zstream stream;
+	void *out;
+	int st;
+
+	memset(&stream, 0, sizeof(stream));
+
+	stream.next_in = (unsigned char *)data;
+	stream.avail_in = size;
+	stream.next_out = out = xmalloc(inflated_size);
+	stream.avail_out = inflated_size;
+	git_inflate_init(&stream);
+	st = git_inflate(&stream, Z_FINISH);
+	git_inflate_end(&stream);
+	if ((st != Z_STREAM_END) || stream.total_out != inflated_size) {
+		free(out);
+		return NULL;
+	}
+	return out;
+}
+
+/*
+ * Read a binary hunk and return a new fragment; fragment->patch
+ * points at an allocated memory that the caller must free, so
+ * it is marked as "->free_patch = 1".
+ */
+static struct fragment *parse_binary_hunk(struct apply_state *state,
+					  char **buf_p,
+					  unsigned long *sz_p,
+					  int *status_p,
+					  int *used_p)
+{
+	/*
+	 * Expect a line that begins with binary patch method ("literal"
+	 * or "delta"), followed by the length of data before deflating.
+	 * a sequence of 'length-byte' followed by base-85 encoded data
+	 * should follow, terminated by a newline.
+	 *
+	 * Each 5-byte sequence of base-85 encodes up to 4 bytes,
+	 * and we would limit the patch line to 66 characters,
+	 * so one line can fit up to 13 groups that would decode
+	 * to 52 bytes max.  The length byte 'A'-'Z' corresponds
+	 * to 1-26 bytes, and 'a'-'z' corresponds to 27-52 bytes.
+	 */
+	int llen, used;
+	unsigned long size = *sz_p;
+	char *buffer = *buf_p;
+	int patch_method;
+	unsigned long origlen;
+	char *data = NULL;
+	int hunk_size = 0;
+	struct fragment *frag;
+
+	llen = linelen(buffer, size);
+	used = llen;
+
+	*status_p = 0;
+
+	if (starts_with(buffer, "delta ")) {
+		patch_method = BINARY_DELTA_DEFLATED;
+		origlen = strtoul(buffer + 6, NULL, 10);
+	}
+	else if (starts_with(buffer, "literal ")) {
+		patch_method = BINARY_LITERAL_DEFLATED;
+		origlen = strtoul(buffer + 8, NULL, 10);
+	}
+	else
+		return NULL;
+
+	state->linenr++;
+	buffer += llen;
+	size -= llen;
+	while (1) {
+		int byte_length, max_byte_length, newsize;
+		llen = linelen(buffer, size);
+		used += llen;
+		state->linenr++;
+		if (llen == 1) {
+			/* consume the blank line */
+			buffer++;
+			size--;
+			break;
+		}
+		/*
+		 * Minimum line is "A00000\n" which is 7-byte long,
+		 * and the line length must be multiple of 5 plus 2.
+		 */
+		if ((llen < 7) || (llen-2) % 5)
+			goto corrupt;
+		max_byte_length = (llen - 2) / 5 * 4;
+		byte_length = *buffer;
+		if ('A' <= byte_length && byte_length <= 'Z')
+			byte_length = byte_length - 'A' + 1;
+		else if ('a' <= byte_length && byte_length <= 'z')
+			byte_length = byte_length - 'a' + 27;
+		else
+			goto corrupt;
+		/* if the input length was not multiple of 4, we would
+		 * have filler at the end but the filler should never
+		 * exceed 3 bytes
+		 */
+		if (max_byte_length < byte_length ||
+		    byte_length <= max_byte_length - 4)
+			goto corrupt;
+		newsize = hunk_size + byte_length;
+		data = xrealloc(data, newsize);
+		if (decode_85(data + hunk_size, buffer + 1, byte_length))
+			goto corrupt;
+		hunk_size = newsize;
+		buffer += llen;
+		size -= llen;
+	}
+
+	CALLOC_ARRAY(frag, 1);
+	frag->patch = inflate_it(data, hunk_size, origlen);
+	frag->free_patch = 1;
+	if (!frag->patch)
+		goto corrupt;
+	free(data);
+	frag->size = origlen;
+	*buf_p = buffer;
+	*sz_p = size;
+	*used_p = used;
+	frag->binary_patch_method = patch_method;
+	return frag;
+
+ corrupt:
+	free(data);
+	*status_p = -1;
+	error(_("corrupt binary patch at line %d: %.*s"),
+	      state->linenr-1, llen-1, buffer);
+	return NULL;
+}
+
+/*
+ * Returns:
+ *   -1 in case of error,
+ *   the length of the parsed binary patch otherwise
+ */
+static int parse_binary(struct apply_state *state,
+			char *buffer,
+			unsigned long size,
+			struct patch *patch)
+{
+	/*
+	 * We have read "GIT binary patch\n"; what follows is a line
+	 * that says the patch method (currently, either "literal" or
+	 * "delta") and the length of data before deflating; a
+	 * sequence of 'length-byte' followed by base-85 encoded data
+	 * follows.
+	 *
+	 * When a binary patch is reversible, there is another binary
+	 * hunk in the same format, starting with patch method (either
+	 * "literal" or "delta") with the length of data, and a sequence
+	 * of length-byte + base-85 encoded data, terminated with another
+	 * empty line.  This data, when applied to the postimage, produces
+	 * the preimage.
+	 */
+	struct fragment *forward;
+	struct fragment *reverse;
+	int status;
+	int used, used_1;
+
+	forward = parse_binary_hunk(state, &buffer, &size, &status, &used);
+	if (!forward && !status)
+		/* there has to be one hunk (forward hunk) */
+		return error(_("unrecognized binary patch at line %d"), state->linenr-1);
+	if (status)
+		/* otherwise we already gave an error message */
+		return status;
+
+	reverse = parse_binary_hunk(state, &buffer, &size, &status, &used_1);
+	if (reverse)
+		used += used_1;
+	else if (status) {
+		/*
+		 * Not having reverse hunk is not an error, but having
+		 * a corrupt reverse hunk is.
+		 */
+		free((void*) forward->patch);
+		free(forward);
+		return status;
+	}
+	forward->next = reverse;
+	patch->fragments = forward;
+	patch->is_binary = 1;
+	return used;
+}
+
+static void prefix_one(struct apply_state *state, char **name)
+{
+	char *old_name = *name;
+	if (!old_name)
+		return;
+	*name = prefix_filename(state->prefix, *name);
+	free(old_name);
+}
+
+static void prefix_patch(struct apply_state *state, struct patch *p)
+{
+	if (!state->prefix || p->is_toplevel_relative)
+		return;
+	prefix_one(state, &p->new_name);
+	prefix_one(state, &p->old_name);
+}
+
+/*
+ * include/exclude
+ */
+
+static void add_name_limit(struct apply_state *state,
+			   const char *name,
+			   int exclude)
+{
+	struct string_list_item *it;
+
+	it = string_list_append(&state->limit_by_name, name);
+	it->util = exclude ? NULL : (void *) 1;
+}
+
+static int use_patch(struct apply_state *state, struct patch *p)
+{
+	const char *pathname = p->new_name ? p->new_name : p->old_name;
+	int i;
+
+	/* Paths outside are not touched regardless of "--include" */
+	if (state->prefix && *state->prefix) {
+		const char *rest;
+		if (!skip_prefix(pathname, state->prefix, &rest) || !*rest)
+			return 0;
+	}
+
+	/* See if it matches any of exclude/include rule */
+	for (i = 0; i < state->limit_by_name.nr; i++) {
+		struct string_list_item *it = &state->limit_by_name.items[i];
+		if (!wildmatch(it->string, pathname, 0))
+			return (it->util != NULL);
+	}
+
+	/*
+	 * If we had any include, a path that does not match any rule is
+	 * not used.  Otherwise, we saw bunch of exclude rules (or none)
+	 * and such a path is used.
+	 */
+	return !state->has_include;
+}
+
+/*
+ * Read the patch text in "buffer" that extends for "size" bytes; stop
+ * reading after seeing a single patch (i.e. changes to a single file).
+ * Create fragments (i.e. patch hunks) and hang them to the given patch.
+ *
+ * Returns:
+ *   -1 if no header was found or parse_binary() failed,
+ *   -128 on another error,
+ *   the number of bytes consumed otherwise,
+ *     so that the caller can call us again for the next patch.
+ */
+static int parse_chunk(struct apply_state *state, char *buffer, unsigned long size, struct patch *patch)
+{
+	int hdrsize, patchsize;
+	int offset = find_header(state, buffer, size, &hdrsize, patch);
+
+	if (offset < 0)
+		return offset;
+
+	prefix_patch(state, patch);
+
+	if (!use_patch(state, patch))
+		patch->ws_rule = 0;
+	else if (patch->new_name)
+		patch->ws_rule = whitespace_rule(state->repo->index,
+						 patch->new_name);
+	else
+		patch->ws_rule = whitespace_rule(state->repo->index,
+						 patch->old_name);
+
+	patchsize = parse_single_patch(state,
+				       buffer + offset + hdrsize,
+				       size - offset - hdrsize,
+				       patch);
+
+	if (patchsize < 0)
+		return -128;
+
+	if (!patchsize) {
+		static const char git_binary[] = "GIT binary patch\n";
+		int hd = hdrsize + offset;
+		unsigned long llen = linelen(buffer + hd, size - hd);
+
+		if (llen == sizeof(git_binary) - 1 &&
+		    !memcmp(git_binary, buffer + hd, llen)) {
+			int used;
+			state->linenr++;
+			used = parse_binary(state, buffer + hd + llen,
+					    size - hd - llen, patch);
+			if (used < 0)
+				return -1;
+			if (used)
+				patchsize = used + llen;
+			else
+				patchsize = 0;
+		}
+		else if (!memcmp(" differ\n", buffer + hd + llen - 8, 8)) {
+			static const char *binhdr[] = {
+				"Binary files ",
+				"Files ",
+				NULL,
+			};
+			int i;
+			for (i = 0; binhdr[i]; i++) {
+				int len = strlen(binhdr[i]);
+				if (len < size - hd &&
+				    !memcmp(binhdr[i], buffer + hd, len)) {
+					state->linenr++;
+					patch->is_binary = 1;
+					patchsize = llen;
+					break;
+				}
+			}
+		}
+
+		/* Empty patch cannot be applied if it is a text patch
+		 * without metadata change.  A binary patch appears
+		 * empty to us here.
+		 */
+		if ((state->apply || state->check) &&
+		    (!patch->is_binary && !metadata_changes(patch))) {
+			error(_("patch with only garbage at line %d"), state->linenr);
+			return -128;
+		}
+	}
+
+	return offset + hdrsize + patchsize;
+}
+
+static void reverse_patches(struct patch *p)
+{
+	for (; p; p = p->next) {
+		struct fragment *frag = p->fragments;
+
+		SWAP(p->new_name, p->old_name);
+		if (p->new_mode)
+			SWAP(p->new_mode, p->old_mode);
+		SWAP(p->is_new, p->is_delete);
+		SWAP(p->lines_added, p->lines_deleted);
+		SWAP(p->old_oid_prefix, p->new_oid_prefix);
+
+		for (; frag; frag = frag->next) {
+			SWAP(frag->newpos, frag->oldpos);
+			SWAP(frag->newlines, frag->oldlines);
+		}
+	}
+}
+
+static const char pluses[] =
+"++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
+static const char minuses[]=
+"----------------------------------------------------------------------";
+
+static void show_stats(struct apply_state *state, struct patch *patch)
+{
+	struct strbuf qname = STRBUF_INIT;
+	char *cp = patch->new_name ? patch->new_name : patch->old_name;
+	int max, add, del;
+
+	quote_c_style(cp, &qname, NULL, 0);
+
+	/*
+	 * "scale" the filename
+	 */
+	max = state->max_len;
+	if (max > 50)
+		max = 50;
+
+	if (qname.len > max) {
+		cp = strchr(qname.buf + qname.len + 3 - max, '/');
+		if (!cp)
+			cp = qname.buf + qname.len + 3 - max;
+		strbuf_splice(&qname, 0, cp - qname.buf, "...", 3);
+	}
+
+	if (patch->is_binary) {
+		printf(" %-*s |  Bin\n", max, qname.buf);
+		strbuf_release(&qname);
+		return;
+	}
+
+	printf(" %-*s |", max, qname.buf);
+	strbuf_release(&qname);
+
+	/*
+	 * scale the add/delete
+	 */
+	max = max + state->max_change > 70 ? 70 - max : state->max_change;
+	add = patch->lines_added;
+	del = patch->lines_deleted;
+
+	if (state->max_change > 0) {
+		int total = ((add + del) * max + state->max_change / 2) / state->max_change;
+		add = (add * max + state->max_change / 2) / state->max_change;
+		del = total - add;
+	}
+	printf("%5d %.*s%.*s\n", patch->lines_added + patch->lines_deleted,
+		add, pluses, del, minuses);
+}
+
+static int read_old_data(struct stat *st, struct patch *patch,
+			 const char *path, struct strbuf *buf)
+{
+	int conv_flags = patch->crlf_in_old ?
+		CONV_EOL_KEEP_CRLF : CONV_EOL_RENORMALIZE;
+	switch (st->st_mode & S_IFMT) {
+	case S_IFLNK:
+		if (strbuf_readlink(buf, path, st->st_size) < 0)
+			return error(_("unable to read symlink %s"), path);
+		return 0;
+	case S_IFREG:
+		if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
+			return error(_("unable to open or read %s"), path);
+		/*
+		 * "git apply" without "--index/--cached" should never look
+		 * at the index; the target file may not have been added to
+		 * the index yet, and we may not even be in any Git repository.
+		 * Pass NULL to convert_to_git() to stress this; the function
+		 * should never look at the index when explicit crlf option
+		 * is given.
+		 */
+		convert_to_git(NULL, path, buf->buf, buf->len, buf, conv_flags);
+		return 0;
+	default:
+		return -1;
+	}
+}
+
+/*
+ * Update the preimage, and the common lines in postimage,
+ * from buffer buf of length len.
+ */
+static void update_pre_post_images(struct image *preimage,
+				   struct image *postimage,
+				   char *buf, size_t len)
+{
+	struct image fixed_preimage = IMAGE_INIT;
+	size_t insert_pos = 0;
+	int i, ctx, reduced;
+	const char *fixed;
+
+	/*
+	 * Update the preimage with whitespace fixes.  Note that we
+	 * are not losing preimage->buf -- apply_one_fragment() will
+	 * free "oldlines".
+	 */
+	image_prepare(&fixed_preimage, buf, len, 1);
+	for (i = 0; i < fixed_preimage.line_nr; i++)
+		fixed_preimage.line[i].flag = preimage->line[i].flag;
+	image_clear(preimage);
+	*preimage = fixed_preimage;
+	fixed = preimage->buf.buf;
+
+	/*
+	 * Adjust the common context lines in postimage.
+	 */
+	for (i = reduced = ctx = 0; i < postimage->line_nr; i++) {
+		size_t l_len = postimage->line[i].len;
+
+		if (!(postimage->line[i].flag & LINE_COMMON)) {
+			/* an added line -- no counterparts in preimage */
+			insert_pos += l_len;
+			continue;
+		}
+
+		/* and find the corresponding one in the fixed preimage */
+		while (ctx < preimage->line_nr &&
+		       !(preimage->line[ctx].flag & LINE_COMMON)) {
+			fixed += preimage->line[ctx].len;
+			ctx++;
+		}
+
+		/*
+		 * preimage is expected to run out, if the caller
+		 * fixed addition of trailing blank lines.
+		 */
+		if (preimage->line_nr <= ctx) {
+			reduced++;
+			continue;
+		}
+
+		/* and copy it in, while fixing the line length */
+		l_len = preimage->line[ctx].len;
+		strbuf_splice(&postimage->buf, insert_pos, postimage->line[i].len,
+			      fixed, l_len);
+		insert_pos += l_len;
+		fixed += l_len;
+		postimage->line[i].len = l_len;
+		ctx++;
+	}
+
+	/* Fix the length of the whole thing */
+	postimage->line_nr -= reduced;
+}
+
+/*
+ * Compare lines s1 of length n1 and s2 of length n2, ignoring
+ * whitespace difference. Returns 1 if they match, 0 otherwise
+ */
+static int fuzzy_matchlines(const char *s1, size_t n1,
+			    const char *s2, size_t n2)
+{
+	const char *end1 = s1 + n1;
+	const char *end2 = s2 + n2;
+
+	/* ignore line endings */
+	while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n'))
+		end1--;
+	while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n'))
+		end2--;
+
+	while (s1 < end1 && s2 < end2) {
+		if (isspace(*s1)) {
+			/*
+			 * Skip whitespace. We check on both buffers
+			 * because we don't want "a b" to match "ab".
+			 */
+			if (!isspace(*s2))
+				return 0;
+			while (s1 < end1 && isspace(*s1))
+				s1++;
+			while (s2 < end2 && isspace(*s2))
+				s2++;
+		} else if (*s1++ != *s2++)
+			return 0;
+	}
+
+	/* If we reached the end on one side only, lines don't match. */
+	return s1 == end1 && s2 == end2;
+}
+
+static int line_by_line_fuzzy_match(struct image *img,
+				    struct image *preimage,
+				    struct image *postimage,
+				    unsigned long current,
+				    int current_lno,
+				    int preimage_limit)
+{
+	int i;
+	size_t imgoff = 0;
+	size_t preoff = 0;
+	size_t extra_chars;
+	char *buf;
+	char *preimage_eof;
+	char *preimage_end;
+	struct strbuf fixed;
+	char *fixed_buf;
+	size_t fixed_len;
+
+	for (i = 0; i < preimage_limit; i++) {
+		size_t prelen = preimage->line[i].len;
+		size_t imglen = img->line[current_lno+i].len;
+
+		if (!fuzzy_matchlines(img->buf.buf + current + imgoff, imglen,
+				      preimage->buf.buf + preoff, prelen))
+			return 0;
+		imgoff += imglen;
+		preoff += prelen;
+	}
+
+	/*
+	 * Ok, the preimage matches with whitespace fuzz.
+	 *
+	 * imgoff now holds the true length of the target that
+	 * matches the preimage before the end of the file.
+	 *
+	 * Count the number of characters in the preimage that fall
+	 * beyond the end of the file and make sure that all of them
+	 * are whitespace characters. (This can only happen if
+	 * we are removing blank lines at the end of the file.)
+	 */
+	buf = preimage_eof = preimage->buf.buf + preoff;
+	for ( ; i < preimage->line_nr; i++)
+		preoff += preimage->line[i].len;
+	preimage_end = preimage->buf.buf + preoff;
+	for ( ; buf < preimage_end; buf++)
+		if (!isspace(*buf))
+			return 0;
+
+	/*
+	 * Update the preimage and the common postimage context
+	 * lines to use the same whitespace as the target.
+	 * If whitespace is missing in the target (i.e.
+	 * if the preimage extends beyond the end of the file),
+	 * use the whitespace from the preimage.
+	 */
+	extra_chars = preimage_end - preimage_eof;
+	strbuf_init(&fixed, imgoff + extra_chars);
+	strbuf_add(&fixed, img->buf.buf + current, imgoff);
+	strbuf_add(&fixed, preimage_eof, extra_chars);
+	fixed_buf = strbuf_detach(&fixed, &fixed_len);
+	update_pre_post_images(preimage, postimage,
+			       fixed_buf, fixed_len);
+	return 1;
+}
+
+static int match_fragment(struct apply_state *state,
+			  struct image *img,
+			  struct image *preimage,
+			  struct image *postimage,
+			  unsigned long current,
+			  int current_lno,
+			  unsigned ws_rule,
+			  int match_beginning, int match_end)
+{
+	int i;
+	const char *orig, *target;
+	struct strbuf fixed = STRBUF_INIT;
+	char *fixed_buf;
+	size_t fixed_len;
+	int preimage_limit;
+	int ret;
+
+	if (preimage->line_nr + current_lno <= img->line_nr) {
+		/*
+		 * The hunk falls within the boundaries of img.
+		 */
+		preimage_limit = preimage->line_nr;
+		if (match_end && (preimage->line_nr + current_lno != img->line_nr)) {
+			ret = 0;
+			goto out;
+		}
+	} else if (state->ws_error_action == correct_ws_error &&
+		   (ws_rule & WS_BLANK_AT_EOF)) {
+		/*
+		 * This hunk extends beyond the end of img, and we are
+		 * removing blank lines at the end of the file.  This
+		 * many lines from the beginning of the preimage must
+		 * match with img, and the remainder of the preimage
+		 * must be blank.
+		 */
+		preimage_limit = img->line_nr - current_lno;
+	} else {
+		/*
+		 * The hunk extends beyond the end of the img and
+		 * we are not removing blanks at the end, so we
+		 * should reject the hunk at this position.
+		 */
+		ret = 0;
+		goto out;
+	}
+
+	if (match_beginning && current_lno) {
+		ret = 0;
+		goto out;
+	}
+
+	/* Quick hash check */
+	for (i = 0; i < preimage_limit; i++) {
+		if ((img->line[current_lno + i].flag & LINE_PATCHED) ||
+		    (preimage->line[i].hash != img->line[current_lno + i].hash)) {
+			ret = 0;
+			goto out;
+		}
+	}
+
+	if (preimage_limit == preimage->line_nr) {
+		/*
+		 * Do we have an exact match?  If we were told to match
+		 * at the end, size must be exactly at current+fragsize,
+		 * otherwise current+fragsize must be still within the preimage,
+		 * and either case, the old piece should match the preimage
+		 * exactly.
+		 */
+		if ((match_end
+		     ? (current + preimage->buf.len == img->buf.len)
+		     : (current + preimage->buf.len <= img->buf.len)) &&
+		    !memcmp(img->buf.buf + current, preimage->buf.buf, preimage->buf.len)) {
+			ret = 1;
+			goto out;
+		}
+	} else {
+		/*
+		 * The preimage extends beyond the end of img, so
+		 * there cannot be an exact match.
+		 *
+		 * There must be one non-blank context line that match
+		 * a line before the end of img.
+		 */
+		const char *buf, *buf_end;
+
+		buf = preimage->buf.buf;
+		buf_end = buf;
+		for (i = 0; i < preimage_limit; i++)
+			buf_end += preimage->line[i].len;
+
+		for ( ; buf < buf_end; buf++)
+			if (!isspace(*buf))
+				break;
+		if (buf == buf_end) {
+			ret = 0;
+			goto out;
+		}
+	}
+
+	/*
+	 * No exact match. If we are ignoring whitespace, run a line-by-line
+	 * fuzzy matching. We collect all the line length information because
+	 * we need it to adjust whitespace if we match.
+	 */
+	if (state->ws_ignore_action == ignore_ws_change) {
+		ret = line_by_line_fuzzy_match(img, preimage, postimage,
+					       current, current_lno, preimage_limit);
+		goto out;
+	}
+
+	if (state->ws_error_action != correct_ws_error) {
+		ret = 0;
+		goto out;
+	}
+
+	/*
+	 * The hunk does not apply byte-by-byte, but the hash says
+	 * it might with whitespace fuzz. We weren't asked to
+	 * ignore whitespace, we were asked to correct whitespace
+	 * errors, so let's try matching after whitespace correction.
+	 *
+	 * While checking the preimage against the target, whitespace
+	 * errors in both fixed, we count how large the corresponding
+	 * postimage needs to be.  The postimage prepared by
+	 * apply_one_fragment() has whitespace errors fixed on added
+	 * lines already, but the common lines were propagated as-is,
+	 * which may become longer when their whitespace errors are
+	 * fixed.
+	 */
+
+	/*
+	 * The preimage may extend beyond the end of the file,
+	 * but in this loop we will only handle the part of the
+	 * preimage that falls within the file.
+	 */
+	strbuf_grow(&fixed, preimage->buf.len + 1);
+	orig = preimage->buf.buf;
+	target = img->buf.buf + current;
+	for (i = 0; i < preimage_limit; i++) {
+		size_t oldlen = preimage->line[i].len;
+		size_t tgtlen = img->line[current_lno + i].len;
+		size_t fixstart = fixed.len;
+		struct strbuf tgtfix;
+		int match;
+
+		/* Try fixing the line in the preimage */
+		ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
+
+		/* Try fixing the line in the target */
+		strbuf_init(&tgtfix, tgtlen);
+		ws_fix_copy(&tgtfix, target, tgtlen, ws_rule, NULL);
+
+		/*
+		 * If they match, either the preimage was based on
+		 * a version before our tree fixed whitespace breakage,
+		 * or we are lacking a whitespace-fix patch the tree
+		 * the preimage was based on already had (i.e. target
+		 * has whitespace breakage, the preimage doesn't).
+		 * In either case, we are fixing the whitespace breakages
+		 * so we might as well take the fix together with their
+		 * real change.
+		 */
+		match = (tgtfix.len == fixed.len - fixstart &&
+			 !memcmp(tgtfix.buf, fixed.buf + fixstart,
+					     fixed.len - fixstart));
+
+		strbuf_release(&tgtfix);
+		if (!match) {
+			ret = 0;
+			goto out;
+		}
+
+		orig += oldlen;
+		target += tgtlen;
+	}
+
+
+	/*
+	 * Now handle the lines in the preimage that falls beyond the
+	 * end of the file (if any). They will only match if they are
+	 * empty or only contain whitespace (if WS_BLANK_AT_EOL is
+	 * false).
+	 */
+	for ( ; i < preimage->line_nr; i++) {
+		size_t fixstart = fixed.len; /* start of the fixed preimage */
+		size_t oldlen = preimage->line[i].len;
+		int j;
+
+		/* Try fixing the line in the preimage */
+		ws_fix_copy(&fixed, orig, oldlen, ws_rule, NULL);
+
+		for (j = fixstart; j < fixed.len; j++) {
+			if (!isspace(fixed.buf[j])) {
+				ret = 0;
+				goto out;
+			}
+		}
+
+
+		orig += oldlen;
+	}
+
+	/*
+	 * Yes, the preimage is based on an older version that still
+	 * has whitespace breakages unfixed, and fixing them makes the
+	 * hunk match.  Update the context lines in the postimage.
+	 */
+	fixed_buf = strbuf_detach(&fixed, &fixed_len);
+	update_pre_post_images(preimage, postimage,
+			       fixed_buf, fixed_len);
+
+	ret = 1;
+
+out:
+	strbuf_release(&fixed);
+	return ret;
+}
+
+static int find_pos(struct apply_state *state,
+		    struct image *img,
+		    struct image *preimage,
+		    struct image *postimage,
+		    int line,
+		    unsigned ws_rule,
+		    int match_beginning, int match_end)
+{
+	int i;
+	unsigned long backwards, forwards, current;
+	int backwards_lno, forwards_lno, current_lno;
+
+	/*
+	 * When running with --allow-overlap, it is possible that a hunk is
+	 * seen that pretends to start at the beginning (but no longer does),
+	 * and that *still* needs to match the end. So trust `match_end` more
+	 * than `match_beginning`.
+	 */
+	if (state->allow_overlap && match_beginning && match_end &&
+	    img->line_nr - preimage->line_nr != 0)
+		match_beginning = 0;
+
+	/*
+	 * If match_beginning or match_end is specified, there is no
+	 * point starting from a wrong line that will never match and
+	 * wander around and wait for a match at the specified end.
+	 */
+	if (match_beginning)
+		line = 0;
+	else if (match_end)
+		line = img->line_nr - preimage->line_nr;
+
+	/*
+	 * Because the comparison is unsigned, the following test
+	 * will also take care of a negative line number that can
+	 * result when match_end and preimage is larger than the target.
+	 */
+	if ((size_t) line > img->line_nr)
+		line = img->line_nr;
+
+	current = 0;
+	for (i = 0; i < line; i++)
+		current += img->line[i].len;
+
+	/*
+	 * There's probably some smart way to do this, but I'll leave
+	 * that to the smart and beautiful people. I'm simple and stupid.
+	 */
+	backwards = current;
+	backwards_lno = line;
+	forwards = current;
+	forwards_lno = line;
+	current_lno = line;
+
+	for (i = 0; ; i++) {
+		if (match_fragment(state, img, preimage, postimage,
+				   current, current_lno, ws_rule,
+				   match_beginning, match_end))
+			return current_lno;
+
+	again:
+		if (backwards_lno == 0 && forwards_lno == img->line_nr)
+			break;
+
+		if (i & 1) {
+			if (backwards_lno == 0) {
+				i++;
+				goto again;
+			}
+			backwards_lno--;
+			backwards -= img->line[backwards_lno].len;
+			current = backwards;
+			current_lno = backwards_lno;
+		} else {
+			if (forwards_lno == img->line_nr) {
+				i++;
+				goto again;
+			}
+			forwards += img->line[forwards_lno].len;
+			forwards_lno++;
+			current = forwards;
+			current_lno = forwards_lno;
+		}
+
+	}
+	return -1;
+}
+
+/*
+ * The change from "preimage" and "postimage" has been found to
+ * apply at applied_pos (counts in line numbers) in "img".
+ * Update "img" to remove "preimage" and replace it with "postimage".
+ */
+static void update_image(struct apply_state *state,
+			 struct image *img,
+			 int applied_pos,
+			 struct image *preimage,
+			 struct image *postimage)
+{
+	/*
+	 * remove the copy of preimage at offset in img
+	 * and replace it with postimage
+	 */
+	int i, nr;
+	size_t remove_count, insert_count, applied_at = 0;
+	size_t result_alloc;
+	char *result;
+	int preimage_limit;
+
+	/*
+	 * If we are removing blank lines at the end of img,
+	 * the preimage may extend beyond the end.
+	 * If that is the case, we must be careful only to
+	 * remove the part of the preimage that falls within
+	 * the boundaries of img. Initialize preimage_limit
+	 * to the number of lines in the preimage that falls
+	 * within the boundaries.
+	 */
+	preimage_limit = preimage->line_nr;
+	if (preimage_limit > img->line_nr - applied_pos)
+		preimage_limit = img->line_nr - applied_pos;
+
+	for (i = 0; i < applied_pos; i++)
+		applied_at += img->line[i].len;
+
+	remove_count = 0;
+	for (i = 0; i < preimage_limit; i++)
+		remove_count += img->line[applied_pos + i].len;
+	insert_count = postimage->buf.len;
+
+	/* Adjust the contents */
+	result_alloc = st_add3(st_sub(img->buf.len, remove_count), insert_count, 1);
+	result = xmalloc(result_alloc);
+	memcpy(result, img->buf.buf, applied_at);
+	memcpy(result + applied_at, postimage->buf.buf, postimage->buf.len);
+	memcpy(result + applied_at + postimage->buf.len,
+	       img->buf.buf + (applied_at + remove_count),
+	       img->buf.len - (applied_at + remove_count));
+	strbuf_attach(&img->buf, result, postimage->buf.len + img->buf.len - remove_count,
+		      result_alloc);
+
+	/* Adjust the line table */
+	nr = img->line_nr + postimage->line_nr - preimage_limit;
+	if (preimage_limit < postimage->line_nr)
+		/*
+		 * NOTE: this knows that we never call image_remove_first_line()
+		 * on anything other than pre/post image.
+		 */
+		REALLOC_ARRAY(img->line, nr);
+	if (preimage_limit != postimage->line_nr)
+		MOVE_ARRAY(img->line + applied_pos + postimage->line_nr,
+			   img->line + applied_pos + preimage_limit,
+			   img->line_nr - (applied_pos + preimage_limit));
+	COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->line_nr);
+	if (!state->allow_overlap)
+		for (i = 0; i < postimage->line_nr; i++)
+			img->line[applied_pos + i].flag |= LINE_PATCHED;
+	img->line_nr = nr;
+}
+
+/*
+ * Use the patch-hunk text in "frag" to prepare two images (preimage and
+ * postimage) for the hunk.  Find lines that match "preimage" in "img" and
+ * replace the part of "img" with "postimage" text.
+ */
+static int apply_one_fragment(struct apply_state *state,
+			      struct image *img, struct fragment *frag,
+			      int inaccurate_eof, unsigned ws_rule,
+			      int nth_fragment)
+{
+	int match_beginning, match_end;
+	const char *patch = frag->patch;
+	int size = frag->size;
+	char *old, *oldlines;
+	struct strbuf newlines;
+	int new_blank_lines_at_end = 0;
+	int found_new_blank_lines_at_end = 0;
+	int hunk_linenr = frag->linenr;
+	unsigned long leading, trailing;
+	int pos, applied_pos;
+	struct image preimage = IMAGE_INIT;
+	struct image postimage = IMAGE_INIT;
+
+	oldlines = xmalloc(size);
+	strbuf_init(&newlines, size);
+
+	old = oldlines;
+	while (size > 0) {
+		char first;
+		int len = linelen(patch, size);
+		int plen;
+		int added_blank_line = 0;
+		int is_blank_context = 0;
+		size_t start;
+
+		if (!len)
+			break;
+
+		/*
+		 * "plen" is how much of the line we should use for
+		 * the actual patch data. Normally we just remove the
+		 * first character on the line, but if the line is
+		 * followed by "\ No newline", then we also remove the
+		 * last one (which is the newline, of course).
+		 */
+		plen = len - 1;
+		if (len < size && patch[len] == '\\')
+			plen--;
+		first = *patch;
+		if (state->apply_in_reverse) {
+			if (first == '-')
+				first = '+';
+			else if (first == '+')
+				first = '-';
+		}
+
+		switch (first) {
+		case '\n':
+			/* Newer GNU diff, empty context line */
+			if (plen < 0)
+				/* ... followed by '\No newline'; nothing */
+				break;
+			*old++ = '\n';
+			strbuf_addch(&newlines, '\n');
+			image_add_line(&preimage, "\n", 1, LINE_COMMON);
+			image_add_line(&postimage, "\n", 1, LINE_COMMON);
+			is_blank_context = 1;
+			break;
+		case ' ':
+			if (plen && (ws_rule & WS_BLANK_AT_EOF) &&
+			    ws_blank_line(patch + 1, plen))
+				is_blank_context = 1;
+			/* fallthrough */
+		case '-':
+			memcpy(old, patch + 1, plen);
+			image_add_line(&preimage, old, plen,
+				      (first == ' ' ? LINE_COMMON : 0));
+			old += plen;
+			if (first == '-')
+				break;
+			/* fallthrough */
+		case '+':
+			/* --no-add does not add new lines */
+			if (first == '+' && state->no_add)
+				break;
+
+			start = newlines.len;
+			if (first != '+' ||
+			    !state->whitespace_error ||
+			    state->ws_error_action != correct_ws_error) {
+				strbuf_add(&newlines, patch + 1, plen);
+			}
+			else {
+				ws_fix_copy(&newlines, patch + 1, plen, ws_rule, &state->applied_after_fixing_ws);
+			}
+			image_add_line(&postimage, newlines.buf + start, newlines.len - start,
+				      (first == '+' ? 0 : LINE_COMMON));
+			if (first == '+' &&
+			    (ws_rule & WS_BLANK_AT_EOF) &&
+			    ws_blank_line(patch + 1, plen))
+				added_blank_line = 1;
+			break;
+		case '@': case '\\':
+			/* Ignore it, we already handled it */
+			break;
+		default:
+			if (state->apply_verbosity > verbosity_normal)
+				error(_("invalid start of line: '%c'"), first);
+			applied_pos = -1;
+			goto out;
+		}
+		if (added_blank_line) {
+			if (!new_blank_lines_at_end)
+				found_new_blank_lines_at_end = hunk_linenr;
+			new_blank_lines_at_end++;
+		}
+		else if (is_blank_context)
+			;
+		else
+			new_blank_lines_at_end = 0;
+		patch += len;
+		size -= len;
+		hunk_linenr++;
+	}
+	if (inaccurate_eof &&
+	    old > oldlines && old[-1] == '\n' &&
+	    newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
+		old--;
+		strbuf_setlen(&newlines, newlines.len - 1);
+		preimage.line[preimage.line_nr - 1].len--;
+		postimage.line[postimage.line_nr - 1].len--;
+	}
+
+	leading = frag->leading;
+	trailing = frag->trailing;
+
+	/*
+	 * A hunk to change lines at the beginning would begin with
+	 * @@ -1,L +N,M @@
+	 * but we need to be careful.  -U0 that inserts before the second
+	 * line also has this pattern.
+	 *
+	 * And a hunk to add to an empty file would begin with
+	 * @@ -0,0 +N,M @@
+	 *
+	 * In other words, a hunk that is (frag->oldpos <= 1) with or
+	 * without leading context must match at the beginning.
+	 */
+	match_beginning = (!frag->oldpos ||
+			   (frag->oldpos == 1 && !state->unidiff_zero));
+
+	/*
+	 * A hunk without trailing lines must match at the end.
+	 * However, we simply cannot tell if a hunk must match end
+	 * from the lack of trailing lines if the patch was generated
+	 * with unidiff without any context.
+	 */
+	match_end = !state->unidiff_zero && !trailing;
+
+	pos = frag->newpos ? (frag->newpos - 1) : 0;
+	strbuf_add(&preimage.buf, oldlines, old - oldlines);
+	strbuf_swap(&postimage.buf, &newlines);
+
+	for (;;) {
+
+		applied_pos = find_pos(state, img, &preimage, &postimage, pos,
+				       ws_rule, match_beginning, match_end);
+
+		if (applied_pos >= 0)
+			break;
+
+		/* Am I at my context limits? */
+		if ((leading <= state->p_context) && (trailing <= state->p_context))
+			break;
+		if (match_beginning || match_end) {
+			match_beginning = match_end = 0;
+			continue;
+		}
+
+		/*
+		 * Reduce the number of context lines; reduce both
+		 * leading and trailing if they are equal otherwise
+		 * just reduce the larger context.
+		 */
+		if (leading >= trailing) {
+			image_remove_first_line(&preimage);
+			image_remove_first_line(&postimage);
+			pos--;
+			leading--;
+		}
+		if (trailing > leading) {
+			image_remove_last_line(&preimage);
+			image_remove_last_line(&postimage);
+			trailing--;
+		}
+	}
+
+	if (applied_pos >= 0) {
+		if (new_blank_lines_at_end &&
+		    preimage.line_nr + applied_pos >= img->line_nr &&
+		    (ws_rule & WS_BLANK_AT_EOF) &&
+		    state->ws_error_action != nowarn_ws_error) {
+			record_ws_error(state, WS_BLANK_AT_EOF, "+", 1,
+					found_new_blank_lines_at_end);
+			if (state->ws_error_action == correct_ws_error) {
+				while (new_blank_lines_at_end--)
+					image_remove_last_line(&postimage);
+			}
+			/*
+			 * We would want to prevent write_out_results()
+			 * from taking place in apply_patch() that follows
+			 * the callchain led us here, which is:
+			 * apply_patch->check_patch_list->check_patch->
+			 * apply_data->apply_fragments->apply_one_fragment
+			 */
+			if (state->ws_error_action == die_on_ws_error)
+				state->apply = 0;
+		}
+
+		if (state->apply_verbosity > verbosity_normal && applied_pos != pos) {
+			int offset = applied_pos - pos;
+			if (state->apply_in_reverse)
+				offset = 0 - offset;
+			fprintf_ln(stderr,
+				   Q_("Hunk #%d succeeded at %d (offset %d line).",
+				      "Hunk #%d succeeded at %d (offset %d lines).",
+				      offset),
+				   nth_fragment, applied_pos + 1, offset);
+		}
+
+		/*
+		 * Warn if it was necessary to reduce the number
+		 * of context lines.
+		 */
+		if ((leading != frag->leading ||
+		     trailing != frag->trailing) && state->apply_verbosity > verbosity_silent)
+			fprintf_ln(stderr, _("Context reduced to (%ld/%ld)"
+					     " to apply fragment at %d"),
+				   leading, trailing, applied_pos+1);
+		update_image(state, img, applied_pos, &preimage, &postimage);
+	} else {
+		if (state->apply_verbosity > verbosity_normal)
+			error(_("while searching for:\n%.*s"),
+			      (int)(old - oldlines), oldlines);
+	}
+
+out:
+	free(oldlines);
+	strbuf_release(&newlines);
+	image_clear(&preimage);
+	image_clear(&postimage);
+
+	return (applied_pos < 0);
+}
+
+static int apply_binary_fragment(struct apply_state *state,
+				 struct image *img,
+				 struct patch *patch)
+{
+	struct fragment *fragment = patch->fragments;
+	unsigned long len;
+	void *dst;
+
+	if (!fragment)
+		return error(_("missing binary patch data for '%s'"),
+			     patch->new_name ?
+			     patch->new_name :
+			     patch->old_name);
+
+	/* Binary patch is irreversible without the optional second hunk */
+	if (state->apply_in_reverse) {
+		if (!fragment->next)
+			return error(_("cannot reverse-apply a binary patch "
+				       "without the reverse hunk to '%s'"),
+				     patch->new_name
+				     ? patch->new_name : patch->old_name);
+		fragment = fragment->next;
+	}
+	switch (fragment->binary_patch_method) {
+	case BINARY_DELTA_DEFLATED:
+		dst = patch_delta(img->buf.buf, img->buf.len, fragment->patch,
+				  fragment->size, &len);
+		if (!dst)
+			return -1;
+		image_clear(img);
+		strbuf_attach(&img->buf, dst, len, len + 1);
+		return 0;
+	case BINARY_LITERAL_DEFLATED:
+		image_clear(img);
+		strbuf_add(&img->buf, fragment->patch, fragment->size);
+		return 0;
+	}
+	return -1;
+}
+
+/*
+ * Replace "img" with the result of applying the binary patch.
+ * The binary patch data itself in patch->fragment is still kept
+ * but the preimage prepared by the caller in "img" is freed here
+ * or in the helper function apply_binary_fragment() this calls.
+ */
+static int apply_binary(struct apply_state *state,
+			struct image *img,
+			struct patch *patch)
+{
+	const char *name = patch->old_name ? patch->old_name : patch->new_name;
+	struct object_id oid;
+	const unsigned hexsz = the_hash_algo->hexsz;
+
+	/*
+	 * For safety, we require patch index line to contain
+	 * full hex textual object ID for old and new, at least for now.
+	 */
+	if (strlen(patch->old_oid_prefix) != hexsz ||
+	    strlen(patch->new_oid_prefix) != hexsz ||
+	    get_oid_hex(patch->old_oid_prefix, &oid) ||
+	    get_oid_hex(patch->new_oid_prefix, &oid))
+		return error(_("cannot apply binary patch to '%s' "
+			       "without full index line"), name);
+
+	if (patch->old_name) {
+		/*
+		 * See if the old one matches what the patch
+		 * applies to.
+		 */
+		hash_object_file(the_hash_algo, img->buf.buf, img->buf.len,
+				 OBJ_BLOB, &oid);
+		if (strcmp(oid_to_hex(&oid), patch->old_oid_prefix))
+			return error(_("the patch applies to '%s' (%s), "
+				       "which does not match the "
+				       "current contents."),
+				     name, oid_to_hex(&oid));
+	}
+	else {
+		/* Otherwise, the old one must be empty. */
+		if (img->buf.len)
+			return error(_("the patch applies to an empty "
+				       "'%s' but it is not empty"), name);
+	}
+
+	get_oid_hex(patch->new_oid_prefix, &oid);
+	if (is_null_oid(&oid)) {
+		image_clear(img);
+		return 0; /* deletion patch */
+	}
+
+	if (has_object(the_repository, &oid, 0)) {
+		/* We already have the postimage */
+		enum object_type type;
+		unsigned long size;
+		char *result;
+
+		result = repo_read_object_file(the_repository, &oid, &type,
+					       &size);
+		if (!result)
+			return error(_("the necessary postimage %s for "
+				       "'%s' cannot be read"),
+				     patch->new_oid_prefix, name);
+		image_clear(img);
+		strbuf_attach(&img->buf, result, size, size + 1);
+	} else {
+		/*
+		 * We have verified buf matches the preimage;
+		 * apply the patch data to it, which is stored
+		 * in the patch->fragments->{patch,size}.
+		 */
+		if (apply_binary_fragment(state, img, patch))
+			return error(_("binary patch does not apply to '%s'"),
+				     name);
+
+		/* verify that the result matches */
+		hash_object_file(the_hash_algo, img->buf.buf, img->buf.len, OBJ_BLOB,
+				 &oid);
+		if (strcmp(oid_to_hex(&oid), patch->new_oid_prefix))
+			return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
+				name, patch->new_oid_prefix, oid_to_hex(&oid));
+	}
+
+	return 0;
+}
+
+static int apply_fragments(struct apply_state *state, struct image *img, struct patch *patch)
+{
+	struct fragment *frag = patch->fragments;
+	const char *name = patch->old_name ? patch->old_name : patch->new_name;
+	unsigned ws_rule = patch->ws_rule;
+	unsigned inaccurate_eof = patch->inaccurate_eof;
+	int nth = 0;
+
+	if (patch->is_binary)
+		return apply_binary(state, img, patch);
+
+	while (frag) {
+		nth++;
+		if (apply_one_fragment(state, img, frag, inaccurate_eof, ws_rule, nth)) {
+			error(_("patch failed: %s:%ld"), name, frag->oldpos);
+			if (!state->apply_with_reject)
+				return -1;
+			frag->rejected = 1;
+		}
+		frag = frag->next;
+	}
+	return 0;
+}
+
+static int read_blob_object(struct strbuf *buf, const struct object_id *oid, unsigned mode)
+{
+	if (S_ISGITLINK(mode)) {
+		strbuf_grow(buf, 100);
+		strbuf_addf(buf, "Subproject commit %s\n", oid_to_hex(oid));
+	} else {
+		enum object_type type;
+		unsigned long sz;
+		char *result;
+
+		result = repo_read_object_file(the_repository, oid, &type,
+					       &sz);
+		if (!result)
+			return -1;
+		/* XXX read_sha1_file NUL-terminates */
+		strbuf_attach(buf, result, sz, sz + 1);
+	}
+	return 0;
+}
+
+static int read_file_or_gitlink(const struct cache_entry *ce, struct strbuf *buf)
+{
+	if (!ce)
+		return 0;
+	return read_blob_object(buf, &ce->oid, ce->ce_mode);
+}
+
+static struct patch *in_fn_table(struct apply_state *state, const char *name)
+{
+	struct string_list_item *item;
+
+	if (!name)
+		return NULL;
+
+	item = string_list_lookup(&state->fn_table, name);
+	if (item)
+		return (struct patch *)item->util;
+
+	return NULL;
+}
+
+/*
+ * item->util in the filename table records the status of the path.
+ * Usually it points at a patch (whose result records the contents
+ * of it after applying it), but it could be PATH_WAS_DELETED for a
+ * path that a previously applied patch has already removed, or
+ * PATH_TO_BE_DELETED for a path that a later patch would remove.
+ *
+ * The latter is needed to deal with a case where two paths A and B
+ * are swapped by first renaming A to B and then renaming B to A;
+ * moving A to B should not be prevented due to presence of B as we
+ * will remove it in a later patch.
+ */
+#define PATH_TO_BE_DELETED ((struct patch *) -2)
+#define PATH_WAS_DELETED ((struct patch *) -1)
+
+static int to_be_deleted(struct patch *patch)
+{
+	return patch == PATH_TO_BE_DELETED;
+}
+
+static int was_deleted(struct patch *patch)
+{
+	return patch == PATH_WAS_DELETED;
+}
+
+static void add_to_fn_table(struct apply_state *state, struct patch *patch)
+{
+	struct string_list_item *item;
+
+	/*
+	 * Always add new_name unless patch is a deletion
+	 * This should cover the cases for normal diffs,
+	 * file creations and copies
+	 */
+	if (patch->new_name) {
+		item = string_list_insert(&state->fn_table, patch->new_name);
+		item->util = patch;
+	}
+
+	/*
+	 * store a failure on rename/deletion cases because
+	 * later chunks shouldn't patch old names
+	 */
+	if ((patch->new_name == NULL) || (patch->is_rename)) {
+		item = string_list_insert(&state->fn_table, patch->old_name);
+		item->util = PATH_WAS_DELETED;
+	}
+}
+
+static void prepare_fn_table(struct apply_state *state, struct patch *patch)
+{
+	/*
+	 * store information about incoming file deletion
+	 */
+	while (patch) {
+		if ((patch->new_name == NULL) || (patch->is_rename)) {
+			struct string_list_item *item;
+			item = string_list_insert(&state->fn_table, patch->old_name);
+			item->util = PATH_TO_BE_DELETED;
+		}
+		patch = patch->next;
+	}
+}
+
+static int checkout_target(struct index_state *istate,
+			   struct cache_entry *ce, struct stat *st)
+{
+	struct checkout costate = CHECKOUT_INIT;
+
+	costate.refresh_cache = 1;
+	costate.istate = istate;
+	if (checkout_entry(ce, &costate, NULL, NULL) ||
+	    lstat(ce->name, st))
+		return error(_("cannot checkout %s"), ce->name);
+	return 0;
+}
+
+static struct patch *previous_patch(struct apply_state *state,
+				    struct patch *patch,
+				    int *gone)
+{
+	struct patch *previous;
+
+	*gone = 0;
+	if (patch->is_copy || patch->is_rename)
+		return NULL; /* "git" patches do not depend on the order */
+
+	previous = in_fn_table(state, patch->old_name);
+	if (!previous)
+		return NULL;
+
+	if (to_be_deleted(previous))
+		return NULL; /* the deletion hasn't happened yet */
+
+	if (was_deleted(previous))
+		*gone = 1;
+
+	return previous;
+}
+
+static int verify_index_match(struct apply_state *state,
+			      const struct cache_entry *ce,
+			      struct stat *st)
+{
+	if (S_ISGITLINK(ce->ce_mode)) {
+		if (!S_ISDIR(st->st_mode))
+			return -1;
+		return 0;
+	}
+	return ie_match_stat(state->repo->index, ce, st,
+			     CE_MATCH_IGNORE_VALID | CE_MATCH_IGNORE_SKIP_WORKTREE);
+}
+
+#define SUBMODULE_PATCH_WITHOUT_INDEX 1
+
+static int load_patch_target(struct apply_state *state,
+			     struct strbuf *buf,
+			     const struct cache_entry *ce,
+			     struct stat *st,
+			     struct patch *patch,
+			     const char *name,
+			     unsigned expected_mode)
+{
+	if (state->cached || state->check_index) {
+		if (read_file_or_gitlink(ce, buf))
+			return error(_("failed to read %s"), name);
+	} else if (name) {
+		if (S_ISGITLINK(expected_mode)) {
+			if (ce)
+				return read_file_or_gitlink(ce, buf);
+			else
+				return SUBMODULE_PATCH_WITHOUT_INDEX;
+		} else if (has_symlink_leading_path(name, strlen(name))) {
+			return error(_("reading from '%s' beyond a symbolic link"), name);
+		} else {
+			if (read_old_data(st, patch, name, buf))
+				return error(_("failed to read %s"), name);
+		}
+	}
+	return 0;
+}
+
+/*
+ * We are about to apply "patch"; populate the "image" with the
+ * current version we have, from the working tree or from the index,
+ * depending on the situation e.g. --cached/--index.  If we are
+ * applying a non-git patch that incrementally updates the tree,
+ * we read from the result of a previous diff.
+ */
+static int load_preimage(struct apply_state *state,
+			 struct image *image,
+			 struct patch *patch, struct stat *st,
+			 const struct cache_entry *ce)
+{
+	struct strbuf buf = STRBUF_INIT;
+	size_t len;
+	char *img;
+	struct patch *previous;
+	int status;
+
+	previous = previous_patch(state, patch, &status);
+	if (status)
+		return error(_("path %s has been renamed/deleted"),
+			     patch->old_name);
+	if (previous) {
+		/* We have a patched copy in memory; use that. */
+		strbuf_add(&buf, previous->result, previous->resultsize);
+	} else {
+		status = load_patch_target(state, &buf, ce, st, patch,
+					   patch->old_name, patch->old_mode);
+		if (status < 0)
+			return status;
+		else if (status == SUBMODULE_PATCH_WITHOUT_INDEX) {
+			/*
+			 * There is no way to apply subproject
+			 * patch without looking at the index.
+			 * NEEDSWORK: shouldn't this be flagged
+			 * as an error???
+			 */
+			free_fragment_list(patch->fragments);
+			patch->fragments = NULL;
+		} else if (status) {
+			return error(_("failed to read %s"), patch->old_name);
+		}
+	}
+
+	img = strbuf_detach(&buf, &len);
+	image_prepare(image, img, len, !patch->is_binary);
+	return 0;
+}
+
+static int resolve_to(struct image *image, const struct object_id *result_id)
+{
+	unsigned long size;
+	enum object_type type;
+	char *data;
+
+	image_clear(image);
+
+	data = repo_read_object_file(the_repository, result_id, &type, &size);
+	if (!data || type != OBJ_BLOB)
+		die("unable to read blob object %s", oid_to_hex(result_id));
+	strbuf_attach(&image->buf, data, size, size + 1);
+
+	return 0;
+}
+
+static int three_way_merge(struct apply_state *state,
+			   struct image *image,
+			   char *path,
+			   const struct object_id *base,
+			   const struct object_id *ours,
+			   const struct object_id *theirs)
+{
+	mmfile_t base_file, our_file, their_file;
+	struct ll_merge_options merge_opts = LL_MERGE_OPTIONS_INIT;
+	mmbuffer_t result = { NULL };
+	enum ll_merge_result status;
+
+	/* resolve trivial cases first */
+	if (oideq(base, ours))
+		return resolve_to(image, theirs);
+	else if (oideq(base, theirs) || oideq(ours, theirs))
+		return resolve_to(image, ours);
+
+	read_mmblob(&base_file, base);
+	read_mmblob(&our_file, ours);
+	read_mmblob(&their_file, theirs);
+	merge_opts.variant = state->merge_variant;
+	status = ll_merge(&result, path,
+			  &base_file, "base",
+			  &our_file, "ours",
+			  &their_file, "theirs",
+			  state->repo->index,
+			  &merge_opts);
+	if (status == LL_MERGE_BINARY_CONFLICT)
+		warning("Cannot merge binary files: %s (%s vs. %s)",
+			path, "ours", "theirs");
+	free(base_file.ptr);
+	free(our_file.ptr);
+	free(their_file.ptr);
+	if (status < 0 || !result.ptr) {
+		free(result.ptr);
+		return -1;
+	}
+	image_clear(image);
+	strbuf_attach(&image->buf, result.ptr, result.size, result.size);
+
+	return status;
+}
+
+/*
+ * When directly falling back to add/add three-way merge, we read from
+ * the current contents of the new_name.  In no cases other than that
+ * this function will be called.
+ */
+static int load_current(struct apply_state *state,
+			struct image *image,
+			struct patch *patch)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int status, pos;
+	size_t len;
+	char *img;
+	struct stat st;
+	struct cache_entry *ce;
+	char *name = patch->new_name;
+	unsigned mode = patch->new_mode;
+
+	if (!patch->is_new)
+		BUG("patch to %s is not a creation", patch->old_name);
+
+	pos = index_name_pos(state->repo->index, name, strlen(name));
+	if (pos < 0)
+		return error(_("%s: does not exist in index"), name);
+	ce = state->repo->index->cache[pos];
+	if (lstat(name, &st)) {
+		if (errno != ENOENT)
+			return error_errno("%s", name);
+		if (checkout_target(state->repo->index, ce, &st))
+			return -1;
+	}
+	if (verify_index_match(state, ce, &st))
+		return error(_("%s: does not match index"), name);
+
+	status = load_patch_target(state, &buf, ce, &st, patch, name, mode);
+	if (status < 0)
+		return status;
+	else if (status)
+		return -1;
+	img = strbuf_detach(&buf, &len);
+	image_prepare(image, img, len, !patch->is_binary);
+	return 0;
+}
+
+static int try_threeway(struct apply_state *state,
+			struct image *image,
+			struct patch *patch,
+			struct stat *st,
+			const struct cache_entry *ce)
+{
+	struct object_id pre_oid, post_oid, our_oid;
+	struct strbuf buf = STRBUF_INIT;
+	size_t len;
+	int status;
+	char *img;
+	struct image tmp_image = IMAGE_INIT;
+
+	/* No point falling back to 3-way merge in these cases */
+	if (patch->is_delete ||
+	    S_ISGITLINK(patch->old_mode) || S_ISGITLINK(patch->new_mode) ||
+	    (patch->is_new && !patch->direct_to_threeway) ||
+	    (patch->is_rename && !patch->lines_added && !patch->lines_deleted))
+		return -1;
+
+	/* Preimage the patch was prepared for */
+	if (patch->is_new)
+		write_object_file("", 0, OBJ_BLOB, &pre_oid);
+	else if (repo_get_oid(the_repository, patch->old_oid_prefix, &pre_oid) ||
+		 read_blob_object(&buf, &pre_oid, patch->old_mode))
+		return error(_("repository lacks the necessary blob to perform 3-way merge."));
+
+	if (state->apply_verbosity > verbosity_silent && patch->direct_to_threeway)
+		fprintf(stderr, _("Performing three-way merge...\n"));
+
+	img = strbuf_detach(&buf, &len);
+	image_prepare(&tmp_image, img, len, 1);
+	/* Apply the patch to get the post image */
+	if (apply_fragments(state, &tmp_image, patch) < 0) {
+		image_clear(&tmp_image);
+		return -1;
+	}
+	/* post_oid is theirs */
+	write_object_file(tmp_image.buf.buf, tmp_image.buf.len, OBJ_BLOB, &post_oid);
+	image_clear(&tmp_image);
+
+	/* our_oid is ours */
+	if (patch->is_new) {
+		if (load_current(state, &tmp_image, patch))
+			return error(_("cannot read the current contents of '%s'"),
+				     patch->new_name);
+	} else {
+		if (load_preimage(state, &tmp_image, patch, st, ce))
+			return error(_("cannot read the current contents of '%s'"),
+				     patch->old_name);
+	}
+	write_object_file(tmp_image.buf.buf, tmp_image.buf.len, OBJ_BLOB, &our_oid);
+	image_clear(&tmp_image);
+
+	/* in-core three-way merge between post and our using pre as base */
+	status = three_way_merge(state, image, patch->new_name,
+				 &pre_oid, &our_oid, &post_oid);
+	if (status < 0) {
+		if (state->apply_verbosity > verbosity_silent)
+			fprintf(stderr,
+				_("Failed to perform three-way merge...\n"));
+		return status;
+	}
+
+	if (status) {
+		patch->conflicted_threeway = 1;
+		if (patch->is_new)
+			oidclr(&patch->threeway_stage[0], the_repository->hash_algo);
+		else
+			oidcpy(&patch->threeway_stage[0], &pre_oid);
+		oidcpy(&patch->threeway_stage[1], &our_oid);
+		oidcpy(&patch->threeway_stage[2], &post_oid);
+		if (state->apply_verbosity > verbosity_silent)
+			fprintf(stderr,
+				_("Applied patch to '%s' with conflicts.\n"),
+				patch->new_name);
+	} else {
+		if (state->apply_verbosity > verbosity_silent)
+			fprintf(stderr,
+				_("Applied patch to '%s' cleanly.\n"),
+				patch->new_name);
+	}
+	return 0;
+}
+
+static int apply_data(struct apply_state *state, struct patch *patch,
+		      struct stat *st, const struct cache_entry *ce)
+{
+	struct image image = IMAGE_INIT;
+
+	if (load_preimage(state, &image, patch, st, ce) < 0)
+		return -1;
+
+	if (!state->threeway || try_threeway(state, &image, patch, st, ce) < 0) {
+		if (state->apply_verbosity > verbosity_silent &&
+		    state->threeway && !patch->direct_to_threeway)
+			fprintf(stderr, _("Falling back to direct application...\n"));
+
+		/* Note: with --reject, apply_fragments() returns 0 */
+		if (patch->direct_to_threeway || apply_fragments(state, &image, patch) < 0) {
+			image_clear(&image);
+			return -1;
+		}
+	}
+	patch->result = strbuf_detach(&image.buf, &patch->resultsize);
+	add_to_fn_table(state, patch);
+	free(image.line);
+
+	if (0 < patch->is_delete && patch->resultsize)
+		return error(_("removal patch leaves file contents"));
+
+	return 0;
+}
+
+/*
+ * If "patch" that we are looking at modifies or deletes what we have,
+ * we would want it not to lose any local modification we have, either
+ * in the working tree or in the index.
+ *
+ * This also decides if a non-git patch is a creation patch or a
+ * modification to an existing empty file.  We do not check the state
+ * of the current tree for a creation patch in this function; the caller
+ * check_patch() separately makes sure (and errors out otherwise) that
+ * the path the patch creates does not exist in the current tree.
+ */
+static int check_preimage(struct apply_state *state,
+			  struct patch *patch,
+			  struct cache_entry **ce,
+			  struct stat *st)
+{
+	const char *old_name = patch->old_name;
+	struct patch *previous = NULL;
+	int stat_ret = 0, status;
+	unsigned st_mode = 0;
+
+	if (!old_name)
+		return 0;
+
+	assert(patch->is_new <= 0);
+	previous = previous_patch(state, patch, &status);
+
+	if (status)
+		return error(_("path %s has been renamed/deleted"), old_name);
+	if (previous) {
+		st_mode = previous->new_mode;
+	} else if (!state->cached) {
+		stat_ret = lstat(old_name, st);
+		if (stat_ret && errno != ENOENT)
+			return error_errno("%s", old_name);
+	}
+
+	if (state->check_index && !previous) {
+		int pos = index_name_pos(state->repo->index, old_name,
+					 strlen(old_name));
+		if (pos < 0) {
+			if (patch->is_new < 0)
+				goto is_new;
+			return error(_("%s: does not exist in index"), old_name);
+		}
+		*ce = state->repo->index->cache[pos];
+		if (stat_ret < 0) {
+			if (checkout_target(state->repo->index, *ce, st))
+				return -1;
+		}
+		if (!state->cached && verify_index_match(state, *ce, st))
+			return error(_("%s: does not match index"), old_name);
+		if (state->cached)
+			st_mode = (*ce)->ce_mode;
+	} else if (stat_ret < 0) {
+		if (patch->is_new < 0)
+			goto is_new;
+		return error_errno("%s", old_name);
+	}
+
+	if (!state->cached && !previous) {
+		if (*ce && !(*ce)->ce_mode)
+			BUG("ce_mode == 0 for path '%s'", old_name);
+
+		if (trust_executable_bit)
+			st_mode = ce_mode_from_stat(*ce, st->st_mode);
+		else if (*ce)
+			st_mode = (*ce)->ce_mode;
+		else
+			st_mode = patch->old_mode;
+	}
+
+	if (patch->is_new < 0)
+		patch->is_new = 0;
+	if (!patch->old_mode)
+		patch->old_mode = st_mode;
+	if ((st_mode ^ patch->old_mode) & S_IFMT)
+		return error(_("%s: wrong type"), old_name);
+	if (st_mode != patch->old_mode)
+		warning(_("%s has type %o, expected %o"),
+			old_name, st_mode, patch->old_mode);
+	if (!patch->new_mode && !patch->is_delete)
+		patch->new_mode = st_mode;
+	return 0;
+
+ is_new:
+	patch->is_new = 1;
+	patch->is_delete = 0;
+	FREE_AND_NULL(patch->old_name);
+	return 0;
+}
+
+
+#define EXISTS_IN_INDEX 1
+#define EXISTS_IN_WORKTREE 2
+#define EXISTS_IN_INDEX_AS_ITA 3
+
+static int check_to_create(struct apply_state *state,
+			   const char *new_name,
+			   int ok_if_exists)
+{
+	struct stat nst;
+
+	if (state->check_index && (!ok_if_exists || !state->cached)) {
+		int pos;
+
+		pos = index_name_pos(state->repo->index, new_name, strlen(new_name));
+		if (pos >= 0) {
+			struct cache_entry *ce = state->repo->index->cache[pos];
+
+			/* allow ITA, as they do not yet exist in the index */
+			if (!ok_if_exists && !(ce->ce_flags & CE_INTENT_TO_ADD))
+				return EXISTS_IN_INDEX;
+
+			/* ITA entries can never match working tree files */
+			if (!state->cached && (ce->ce_flags & CE_INTENT_TO_ADD))
+				return EXISTS_IN_INDEX_AS_ITA;
+		}
+	}
+
+	if (state->cached)
+		return 0;
+
+	if (!lstat(new_name, &nst)) {
+		if (S_ISDIR(nst.st_mode) || ok_if_exists)
+			return 0;
+		/*
+		 * A leading component of new_name might be a symlink
+		 * that is going to be removed with this patch, but
+		 * still pointing at somewhere that has the path.
+		 * In such a case, path "new_name" does not exist as
+		 * far as git is concerned.
+		 */
+		if (has_symlink_leading_path(new_name, strlen(new_name)))
+			return 0;
+
+		return EXISTS_IN_WORKTREE;
+	} else if (!is_missing_file_error(errno)) {
+		return error_errno("%s", new_name);
+	}
+	return 0;
+}
+
+static void prepare_symlink_changes(struct apply_state *state, struct patch *patch)
+{
+	for ( ; patch; patch = patch->next) {
+		if ((patch->old_name && S_ISLNK(patch->old_mode)) &&
+		    (patch->is_rename || patch->is_delete))
+			/* the symlink at patch->old_name is removed */
+			strset_add(&state->removed_symlinks, patch->old_name);
+
+		if (patch->new_name && S_ISLNK(patch->new_mode))
+			/* the symlink at patch->new_name is created or remains */
+			strset_add(&state->kept_symlinks, patch->new_name);
+	}
+}
+
+static int path_is_beyond_symlink_1(struct apply_state *state, struct strbuf *name)
+{
+	do {
+		while (--name->len && name->buf[name->len] != '/')
+			; /* scan backwards */
+		if (!name->len)
+			break;
+		name->buf[name->len] = '\0';
+		if (strset_contains(&state->kept_symlinks, name->buf))
+			return 1;
+		if (strset_contains(&state->removed_symlinks, name->buf))
+			/*
+			 * This cannot be "return 0", because we may
+			 * see a new one created at a higher level.
+			 */
+			continue;
+
+		/* otherwise, check the preimage */
+		if (state->check_index) {
+			struct cache_entry *ce;
+
+			ce = index_file_exists(state->repo->index, name->buf,
+					       name->len, ignore_case);
+			if (ce && S_ISLNK(ce->ce_mode))
+				return 1;
+		} else {
+			struct stat st;
+			if (!lstat(name->buf, &st) && S_ISLNK(st.st_mode))
+				return 1;
+		}
+	} while (1);
+	return 0;
+}
+
+static int path_is_beyond_symlink(struct apply_state *state, const char *name_)
+{
+	int ret;
+	struct strbuf name = STRBUF_INIT;
+
+	assert(*name_ != '\0');
+	strbuf_addstr(&name, name_);
+	ret = path_is_beyond_symlink_1(state, &name);
+	strbuf_release(&name);
+
+	return ret;
+}
+
+static int check_unsafe_path(struct patch *patch)
+{
+	const char *old_name = NULL;
+	const char *new_name = NULL;
+	if (patch->is_delete)
+		old_name = patch->old_name;
+	else if (!patch->is_new && !patch->is_copy)
+		old_name = patch->old_name;
+	if (!patch->is_delete)
+		new_name = patch->new_name;
+
+	if (old_name && !verify_path(old_name, patch->old_mode))
+		return error(_("invalid path '%s'"), old_name);
+	if (new_name && !verify_path(new_name, patch->new_mode))
+		return error(_("invalid path '%s'"), new_name);
+	return 0;
+}
+
+/*
+ * Check and apply the patch in-core; leave the result in patch->result
+ * for the caller to write it out to the final destination.
+ */
+static int check_patch(struct apply_state *state, struct patch *patch)
+{
+	struct stat st;
+	const char *old_name = patch->old_name;
+	const char *new_name = patch->new_name;
+	const char *name = old_name ? old_name : new_name;
+	struct cache_entry *ce = NULL;
+	struct patch *tpatch;
+	int ok_if_exists;
+	int status;
+
+	patch->rejected = 1; /* we will drop this after we succeed */
+
+	status = check_preimage(state, patch, &ce, &st);
+	if (status)
+		return status;
+	old_name = patch->old_name;
+
+	/*
+	 * A type-change diff is always split into a patch to delete
+	 * old, immediately followed by a patch to create new (see
+	 * diff.c::run_diff()); in such a case it is Ok that the entry
+	 * to be deleted by the previous patch is still in the working
+	 * tree and in the index.
+	 *
+	 * A patch to swap-rename between A and B would first rename A
+	 * to B and then rename B to A.  While applying the first one,
+	 * the presence of B should not stop A from getting renamed to
+	 * B; ask to_be_deleted() about the later rename.  Removal of
+	 * B and rename from A to B is handled the same way by asking
+	 * was_deleted().
+	 */
+	if ((tpatch = in_fn_table(state, new_name)) &&
+	    (was_deleted(tpatch) || to_be_deleted(tpatch)))
+		ok_if_exists = 1;
+	else
+		ok_if_exists = 0;
+
+	if (new_name &&
+	    ((0 < patch->is_new) || patch->is_rename || patch->is_copy)) {
+		int err = check_to_create(state, new_name, ok_if_exists);
+
+		if (err && state->threeway) {
+			patch->direct_to_threeway = 1;
+		} else switch (err) {
+		case 0:
+			break; /* happy */
+		case EXISTS_IN_INDEX:
+			return error(_("%s: already exists in index"), new_name);
+		case EXISTS_IN_INDEX_AS_ITA:
+			return error(_("%s: does not match index"), new_name);
+		case EXISTS_IN_WORKTREE:
+			return error(_("%s: already exists in working directory"),
+				     new_name);
+		default:
+			return err;
+		}
+
+		if (!patch->new_mode) {
+			if (0 < patch->is_new)
+				patch->new_mode = S_IFREG | 0644;
+			else
+				patch->new_mode = patch->old_mode;
+		}
+	}
+
+	if (new_name && old_name) {
+		int same = !strcmp(old_name, new_name);
+		if (!patch->new_mode)
+			patch->new_mode = patch->old_mode;
+		if ((patch->old_mode ^ patch->new_mode) & S_IFMT) {
+			if (same)
+				return error(_("new mode (%o) of %s does not "
+					       "match old mode (%o)"),
+					patch->new_mode, new_name,
+					patch->old_mode);
+			else
+				return error(_("new mode (%o) of %s does not "
+					       "match old mode (%o) of %s"),
+					patch->new_mode, new_name,
+					patch->old_mode, old_name);
+		}
+	}
+
+	if (!state->unsafe_paths && check_unsafe_path(patch))
+		return -128;
+
+	/*
+	 * An attempt to read from or delete a path that is beyond a
+	 * symbolic link will be prevented by load_patch_target() that
+	 * is called at the beginning of apply_data() so we do not
+	 * have to worry about a patch marked with "is_delete" bit
+	 * here.  We however need to make sure that the patch result
+	 * is not deposited to a path that is beyond a symbolic link
+	 * here.
+	 */
+	if (!patch->is_delete && path_is_beyond_symlink(state, patch->new_name))
+		return error(_("affected file '%s' is beyond a symbolic link"),
+			     patch->new_name);
+
+	if (apply_data(state, patch, &st, ce) < 0)
+		return error(_("%s: patch does not apply"), name);
+	patch->rejected = 0;
+	return 0;
+}
+
+static int check_patch_list(struct apply_state *state, struct patch *patch)
+{
+	int err = 0;
+
+	prepare_symlink_changes(state, patch);
+	prepare_fn_table(state, patch);
+	while (patch) {
+		int res;
+		if (state->apply_verbosity > verbosity_normal)
+			say_patch_name(stderr,
+				       _("Checking patch %s..."), patch);
+		res = check_patch(state, patch);
+		if (res == -128)
+			return -128;
+		err |= res;
+		patch = patch->next;
+	}
+	return err;
+}
+
+static int read_apply_cache(struct apply_state *state)
+{
+	if (state->index_file)
+		return read_index_from(state->repo->index, state->index_file,
+				       repo_get_git_dir(the_repository));
+	else
+		return repo_read_index(state->repo);
+}
+
+/* This function tries to read the object name from the current index */
+static int get_current_oid(struct apply_state *state, const char *path,
+			   struct object_id *oid)
+{
+	int pos;
+
+	if (read_apply_cache(state) < 0)
+		return -1;
+	pos = index_name_pos(state->repo->index, path, strlen(path));
+	if (pos < 0)
+		return -1;
+	oidcpy(oid, &state->repo->index->cache[pos]->oid);
+	return 0;
+}
+
+static int preimage_oid_in_gitlink_patch(struct patch *p, struct object_id *oid)
+{
+	/*
+	 * A usable gitlink patch has only one fragment (hunk) that looks like:
+	 * @@ -1 +1 @@
+	 * -Subproject commit <old sha1>
+	 * +Subproject commit <new sha1>
+	 * or
+	 * @@ -1 +0,0 @@
+	 * -Subproject commit <old sha1>
+	 * for a removal patch.
+	 */
+	struct fragment *hunk = p->fragments;
+	static const char heading[] = "-Subproject commit ";
+	char *preimage;
+
+	if (/* does the patch have only one hunk? */
+	    hunk && !hunk->next &&
+	    /* is its preimage one line? */
+	    hunk->oldpos == 1 && hunk->oldlines == 1 &&
+	    /* does preimage begin with the heading? */
+	    (preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL &&
+	    starts_with(++preimage, heading) &&
+	    /* does it record full SHA-1? */
+	    !get_oid_hex(preimage + sizeof(heading) - 1, oid) &&
+	    preimage[sizeof(heading) + the_hash_algo->hexsz - 1] == '\n' &&
+	    /* does the abbreviated name on the index line agree with it? */
+	    starts_with(preimage + sizeof(heading) - 1, p->old_oid_prefix))
+		return 0; /* it all looks fine */
+
+	/* we may have full object name on the index line */
+	return get_oid_hex(p->old_oid_prefix, oid);
+}
+
+/* Build an index that contains just the files needed for a 3way merge */
+static int build_fake_ancestor(struct apply_state *state, struct patch *list)
+{
+	struct patch *patch;
+	struct index_state result = INDEX_STATE_INIT(state->repo);
+	struct lock_file lock = LOCK_INIT;
+	int res;
+
+	/* Once we start supporting the reverse patch, it may be
+	 * worth showing the new sha1 prefix, but until then...
+	 */
+	for (patch = list; patch; patch = patch->next) {
+		struct object_id oid;
+		struct cache_entry *ce;
+		const char *name;
+
+		name = patch->old_name ? patch->old_name : patch->new_name;
+		if (0 < patch->is_new)
+			continue;
+
+		if (S_ISGITLINK(patch->old_mode)) {
+			if (!preimage_oid_in_gitlink_patch(patch, &oid))
+				; /* ok, the textual part looks sane */
+			else
+				return error(_("sha1 information is lacking or "
+					       "useless for submodule %s"), name);
+		} else if (!repo_get_oid_blob(the_repository, patch->old_oid_prefix, &oid)) {
+			; /* ok */
+		} else if (!patch->lines_added && !patch->lines_deleted) {
+			/* mode-only change: update the current */
+			if (get_current_oid(state, patch->old_name, &oid))
+				return error(_("mode change for %s, which is not "
+					       "in current HEAD"), name);
+		} else
+			return error(_("sha1 information is lacking or useless "
+				       "(%s)."), name);
+
+		ce = make_cache_entry(&result, patch->old_mode, &oid, name, 0, 0);
+		if (!ce)
+			return error(_("make_cache_entry failed for path '%s'"),
+				     name);
+		if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {
+			discard_cache_entry(ce);
+			return error(_("could not add %s to temporary index"),
+				     name);
+		}
+	}
+
+	hold_lock_file_for_update(&lock, state->fake_ancestor, LOCK_DIE_ON_ERROR);
+	res = write_locked_index(&result, &lock, COMMIT_LOCK);
+	discard_index(&result);
+
+	if (res)
+		return error(_("could not write temporary index to %s"),
+			     state->fake_ancestor);
+
+	return 0;
+}
+
+static void stat_patch_list(struct apply_state *state, struct patch *patch)
+{
+	int files, adds, dels;
+
+	for (files = adds = dels = 0 ; patch ; patch = patch->next) {
+		files++;
+		adds += patch->lines_added;
+		dels += patch->lines_deleted;
+		show_stats(state, patch);
+	}
+
+	print_stat_summary(stdout, files, adds, dels);
+}
+
+static void numstat_patch_list(struct apply_state *state,
+			       struct patch *patch)
+{
+	for ( ; patch; patch = patch->next) {
+		const char *name;
+		name = patch->new_name ? patch->new_name : patch->old_name;
+		if (patch->is_binary)
+			printf("-\t-\t");
+		else
+			printf("%d\t%d\t", patch->lines_added, patch->lines_deleted);
+		write_name_quoted(name, stdout, state->line_termination);
+	}
+}
+
+static void show_file_mode_name(const char *newdelete, unsigned int mode, const char *name)
+{
+	if (mode)
+		printf(" %s mode %06o %s\n", newdelete, mode, name);
+	else
+		printf(" %s %s\n", newdelete, name);
+}
+
+static void show_mode_change(struct patch *p, int show_name)
+{
+	if (p->old_mode && p->new_mode && p->old_mode != p->new_mode) {
+		if (show_name)
+			printf(" mode change %06o => %06o %s\n",
+			       p->old_mode, p->new_mode, p->new_name);
+		else
+			printf(" mode change %06o => %06o\n",
+			       p->old_mode, p->new_mode);
+	}
+}
+
+static void show_rename_copy(struct patch *p)
+{
+	const char *renamecopy = p->is_rename ? "rename" : "copy";
+	const char *old_name, *new_name;
+
+	/* Find common prefix */
+	old_name = p->old_name;
+	new_name = p->new_name;
+	while (1) {
+		const char *slash_old, *slash_new;
+		slash_old = strchr(old_name, '/');
+		slash_new = strchr(new_name, '/');
+		if (!slash_old ||
+		    !slash_new ||
+		    slash_old - old_name != slash_new - new_name ||
+		    memcmp(old_name, new_name, slash_new - new_name))
+			break;
+		old_name = slash_old + 1;
+		new_name = slash_new + 1;
+	}
+	/* p->old_name through old_name is the common prefix, and old_name and
+	 * new_name through the end of names are renames
+	 */
+	if (old_name != p->old_name)
+		printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
+		       (int)(old_name - p->old_name), p->old_name,
+		       old_name, new_name, p->score);
+	else
+		printf(" %s %s => %s (%d%%)\n", renamecopy,
+		       p->old_name, p->new_name, p->score);
+	show_mode_change(p, 0);
+}
+
+static void summary_patch_list(struct patch *patch)
+{
+	struct patch *p;
+
+	for (p = patch; p; p = p->next) {
+		if (p->is_new)
+			show_file_mode_name("create", p->new_mode, p->new_name);
+		else if (p->is_delete)
+			show_file_mode_name("delete", p->old_mode, p->old_name);
+		else {
+			if (p->is_rename || p->is_copy)
+				show_rename_copy(p);
+			else {
+				if (p->score) {
+					printf(" rewrite %s (%d%%)\n",
+					       p->new_name, p->score);
+					show_mode_change(p, 0);
+				}
+				else
+					show_mode_change(p, 1);
+			}
+		}
+	}
+}
+
+static void patch_stats(struct apply_state *state, struct patch *patch)
+{
+	int lines = patch->lines_added + patch->lines_deleted;
+
+	if (lines > state->max_change)
+		state->max_change = lines;
+	if (patch->old_name) {
+		int len = quote_c_style(patch->old_name, NULL, NULL, 0);
+		if (!len)
+			len = strlen(patch->old_name);
+		if (len > state->max_len)
+			state->max_len = len;
+	}
+	if (patch->new_name) {
+		int len = quote_c_style(patch->new_name, NULL, NULL, 0);
+		if (!len)
+			len = strlen(patch->new_name);
+		if (len > state->max_len)
+			state->max_len = len;
+	}
+}
+
+static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
+{
+	if (state->update_index && !state->ita_only) {
+		if (remove_file_from_index(state->repo->index, patch->old_name) < 0)
+			return error(_("unable to remove %s from index"), patch->old_name);
+	}
+	if (!state->cached) {
+		if (!remove_or_warn(patch->old_mode, patch->old_name) && rmdir_empty) {
+			remove_path(patch->old_name);
+		}
+	}
+	return 0;
+}
+
+static int add_index_file(struct apply_state *state,
+			  const char *path,
+			  unsigned mode,
+			  void *buf,
+			  unsigned long size)
+{
+	struct stat st;
+	struct cache_entry *ce;
+	int namelen = strlen(path);
+
+	ce = make_empty_cache_entry(state->repo->index, namelen);
+	memcpy(ce->name, path, namelen);
+	ce->ce_mode = create_ce_mode(mode);
+	ce->ce_flags = create_ce_flags(0);
+	ce->ce_namelen = namelen;
+	if (state->ita_only) {
+		ce->ce_flags |= CE_INTENT_TO_ADD;
+		set_object_name_for_intent_to_add_entry(ce);
+	} else if (S_ISGITLINK(mode)) {
+		const char *s;
+
+		if (!skip_prefix(buf, "Subproject commit ", &s) ||
+		    get_oid_hex(s, &ce->oid)) {
+			discard_cache_entry(ce);
+			return error(_("corrupt patch for submodule %s"), path);
+		}
+	} else {
+		if (!state->cached) {
+			if (lstat(path, &st) < 0) {
+				discard_cache_entry(ce);
+				return error_errno(_("unable to stat newly "
+						     "created file '%s'"),
+						   path);
+			}
+			fill_stat_cache_info(state->repo->index, ce, &st);
+		}
+		if (write_object_file(buf, size, OBJ_BLOB, &ce->oid) < 0) {
+			discard_cache_entry(ce);
+			return error(_("unable to create backing store "
+				       "for newly created file %s"), path);
+		}
+	}
+	if (add_index_entry(state->repo->index, ce, ADD_CACHE_OK_TO_ADD) < 0) {
+		discard_cache_entry(ce);
+		return error(_("unable to add cache entry for %s"), path);
+	}
+
+	return 0;
+}
+
+/*
+ * Returns:
+ *  -1 if an unrecoverable error happened
+ *   0 if everything went well
+ *   1 if a recoverable error happened
+ */
+static int try_create_file(struct apply_state *state, const char *path,
+			   unsigned int mode, const char *buf,
+			   unsigned long size)
+{
+	int fd, res;
+	struct strbuf nbuf = STRBUF_INIT;
+
+	if (S_ISGITLINK(mode)) {
+		struct stat st;
+		if (!lstat(path, &st) && S_ISDIR(st.st_mode))
+			return 0;
+		return !!mkdir(path, 0777);
+	}
+
+	if (has_symlinks && S_ISLNK(mode))
+		/* Although buf:size is counted string, it also is NUL
+		 * terminated.
+		 */
+		return !!symlink(buf, path);
+
+	fd = open(path, O_CREAT | O_EXCL | O_WRONLY, (mode & 0100) ? 0777 : 0666);
+	if (fd < 0)
+		return 1;
+
+	if (convert_to_working_tree(state->repo->index, path, buf, size, &nbuf, NULL)) {
+		size = nbuf.len;
+		buf  = nbuf.buf;
+	}
+
+	res = write_in_full(fd, buf, size) < 0;
+	if (res)
+		error_errno(_("failed to write to '%s'"), path);
+	strbuf_release(&nbuf);
+
+	if (close(fd) < 0 && !res)
+		return error_errno(_("closing file '%s'"), path);
+
+	return res ? -1 : 0;
+}
+
+/*
+ * We optimistically assume that the directories exist,
+ * which is true 99% of the time anyway. If they don't,
+ * we create them and try again.
+ *
+ * Returns:
+ *   -1 on error
+ *   0 otherwise
+ */
+static int create_one_file(struct apply_state *state,
+			   char *path,
+			   unsigned mode,
+			   const char *buf,
+			   unsigned long size)
+{
+	char *newpath = NULL;
+	int res;
+
+	if (state->cached)
+		return 0;
+
+	/*
+	 * We already try to detect whether files are beyond a symlink in our
+	 * up-front checks. But in the case where symlinks are created by any
+	 * of the intermediate hunks it can happen that our up-front checks
+	 * didn't yet see the symlink, but at the point of arriving here there
+	 * in fact is one. We thus repeat the check for symlinks here.
+	 *
+	 * Note that this does not make the up-front check obsolete as the
+	 * failure mode is different:
+	 *
+	 * - The up-front checks cause us to abort before we have written
+	 *   anything into the working directory. So when we exit this way the
+	 *   working directory remains clean.
+	 *
+	 * - The checks here happen in the middle of the action where we have
+	 *   already started to apply the patch. The end result will be a dirty
+	 *   working directory.
+	 *
+	 * Ideally, we should update the up-front checks to catch what would
+	 * happen when we apply the patch before we damage the working tree.
+	 * We have all the information necessary to do so.  But for now, as a
+	 * part of embargoed security work, having this check would serve as a
+	 * reasonable first step.
+	 */
+	if (path_is_beyond_symlink(state, path))
+		return error(_("affected file '%s' is beyond a symbolic link"), path);
+
+	res = try_create_file(state, path, mode, buf, size);
+	if (res < 0)
+		return -1;
+	if (!res)
+		return 0;
+
+	if (errno == ENOENT) {
+		if (safe_create_leading_directories_no_share(path))
+			return 0;
+		res = try_create_file(state, path, mode, buf, size);
+		if (res < 0)
+			return -1;
+		if (!res)
+			return 0;
+	}
+
+	if (errno == EEXIST || errno == EACCES) {
+		/* We may be trying to create a file where a directory
+		 * used to be.
+		 */
+		struct stat st;
+		if (!lstat(path, &st) && (!S_ISDIR(st.st_mode) || !rmdir(path)))
+			errno = EEXIST;
+	}
+
+	if (errno == EEXIST) {
+		unsigned int nr = getpid();
+
+		for (;;) {
+			newpath = mkpathdup("%s~%u", path, nr);
+			res = try_create_file(state, newpath, mode, buf, size);
+			if (res < 0)
+				goto out;
+			if (!res) {
+				if (!rename(newpath, path))
+					goto out;
+				unlink_or_warn(newpath);
+				break;
+			}
+			if (errno != EEXIST)
+				break;
+			++nr;
+			FREE_AND_NULL(newpath);
+		}
+	}
+	res = error_errno(_("unable to write file '%s' mode %o"), path, mode);
+out:
+	free(newpath);
+	return res;
+}
+
+static int add_conflicted_stages_file(struct apply_state *state,
+				       struct patch *patch)
+{
+	int stage, namelen;
+	unsigned mode;
+	struct cache_entry *ce;
+
+	if (!state->update_index)
+		return 0;
+	namelen = strlen(patch->new_name);
+	mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
+
+	remove_file_from_index(state->repo->index, patch->new_name);
+	for (stage = 1; stage < 4; stage++) {
+		if (is_null_oid(&patch->threeway_stage[stage - 1]))
+			continue;
+		ce = make_empty_cache_entry(state->repo->index, namelen);
+		memcpy(ce->name, patch->new_name, namelen);
+		ce->ce_mode = create_ce_mode(mode);
+		ce->ce_flags = create_ce_flags(stage);
+		ce->ce_namelen = namelen;
+		oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]);
+		if (add_index_entry(state->repo->index, ce, ADD_CACHE_OK_TO_ADD) < 0) {
+			discard_cache_entry(ce);
+			return error(_("unable to add cache entry for %s"),
+				     patch->new_name);
+		}
+	}
+
+	return 0;
+}
+
+static int create_file(struct apply_state *state, struct patch *patch)
+{
+	char *path = patch->new_name;
+	unsigned mode = patch->new_mode;
+	unsigned long size = patch->resultsize;
+	char *buf = patch->result;
+
+	if (!mode)
+		mode = S_IFREG | 0644;
+	if (create_one_file(state, path, mode, buf, size))
+		return -1;
+
+	if (patch->conflicted_threeway)
+		return add_conflicted_stages_file(state, patch);
+	else if (state->update_index)
+		return add_index_file(state, path, mode, buf, size);
+	return 0;
+}
+
+/* phase zero is to remove, phase one is to create */
+static int write_out_one_result(struct apply_state *state,
+				struct patch *patch,
+				int phase)
+{
+	if (patch->is_delete > 0) {
+		if (phase == 0)
+			return remove_file(state, patch, 1);
+		return 0;
+	}
+	if (patch->is_new > 0 || patch->is_copy) {
+		if (phase == 1)
+			return create_file(state, patch);
+		return 0;
+	}
+	/*
+	 * Rename or modification boils down to the same
+	 * thing: remove the old, write the new
+	 */
+	if (phase == 0)
+		return remove_file(state, patch, patch->is_rename);
+	if (phase == 1)
+		return create_file(state, patch);
+	return 0;
+}
+
+static int write_out_one_reject(struct apply_state *state, struct patch *patch)
+{
+	FILE *rej;
+	char *namebuf;
+	struct fragment *frag;
+	int fd, cnt = 0;
+	struct strbuf sb = STRBUF_INIT;
+
+	for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) {
+		if (!frag->rejected)
+			continue;
+		cnt++;
+	}
+
+	if (!cnt) {
+		if (state->apply_verbosity > verbosity_normal)
+			say_patch_name(stderr,
+				       _("Applied patch %s cleanly."), patch);
+		return 0;
+	}
+
+	/* This should not happen, because a removal patch that leaves
+	 * contents are marked "rejected" at the patch level.
+	 */
+	if (!patch->new_name)
+		die(_("internal error"));
+
+	/* Say this even without --verbose */
+	strbuf_addf(&sb, Q_("Applying patch %%s with %d reject...",
+			    "Applying patch %%s with %d rejects...",
+			    cnt),
+		    cnt);
+	if (state->apply_verbosity > verbosity_silent)
+		say_patch_name(stderr, sb.buf, patch);
+	strbuf_release(&sb);
+
+	namebuf = xstrfmt("%s.rej", patch->new_name);
+
+	fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+	if (fd < 0) {
+		if (errno != EEXIST) {
+			error_errno(_("cannot open %s"), namebuf);
+			goto error;
+		}
+		if (unlink(namebuf)) {
+			error_errno(_("cannot unlink '%s'"), namebuf);
+			goto error;
+		}
+		fd = open(namebuf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+		if (fd < 0) {
+			error_errno(_("cannot open %s"), namebuf);
+			goto error;
+		}
+	}
+	rej = fdopen(fd, "w");
+	if (!rej) {
+		error_errno(_("cannot open %s"), namebuf);
+		close(fd);
+		goto error;
+	}
+
+	/* Normal git tools never deal with .rej, so do not pretend
+	 * this is a git patch by saying --git or giving extended
+	 * headers.  While at it, maybe please "kompare" that wants
+	 * the trailing TAB and some garbage at the end of line ;-).
+	 */
+	fprintf(rej, "diff a/%s b/%s\t(rejected hunks)\n",
+		patch->new_name, patch->new_name);
+	for (cnt = 1, frag = patch->fragments;
+	     frag;
+	     cnt++, frag = frag->next) {
+		if (!frag->rejected) {
+			if (state->apply_verbosity > verbosity_silent)
+				fprintf_ln(stderr, _("Hunk #%d applied cleanly."), cnt);
+			continue;
+		}
+		if (state->apply_verbosity > verbosity_silent)
+			fprintf_ln(stderr, _("Rejected hunk #%d."), cnt);
+		fprintf(rej, "%.*s", frag->size, frag->patch);
+		if (frag->patch[frag->size-1] != '\n')
+			fputc('\n', rej);
+	}
+	fclose(rej);
+error:
+	free(namebuf);
+	return -1;
+}
+
+/*
+ * Returns:
+ *  -1 if an error happened
+ *   0 if the patch applied cleanly
+ *   1 if the patch did not apply cleanly
+ */
+static int write_out_results(struct apply_state *state, struct patch *list)
+{
+	int phase;
+	int errs = 0;
+	struct patch *l;
+	struct string_list cpath = STRING_LIST_INIT_DUP;
+
+	for (phase = 0; phase < 2; phase++) {
+		l = list;
+		while (l) {
+			if (l->rejected)
+				errs = 1;
+			else {
+				if (write_out_one_result(state, l, phase)) {
+					string_list_clear(&cpath, 0);
+					return -1;
+				}
+				if (phase == 1) {
+					if (write_out_one_reject(state, l))
+						errs = 1;
+					if (l->conflicted_threeway) {
+						string_list_append(&cpath, l->new_name);
+						errs = 1;
+					}
+				}
+			}
+			l = l->next;
+		}
+	}
+
+	if (cpath.nr) {
+		struct string_list_item *item;
+
+		string_list_sort(&cpath);
+		if (state->apply_verbosity > verbosity_silent) {
+			for_each_string_list_item(item, &cpath)
+				fprintf(stderr, "U %s\n", item->string);
+		}
+		string_list_clear(&cpath, 0);
+
+		/*
+		 * rerere relies on the partially merged result being in the working
+		 * tree with conflict markers, but that isn't written with --cached.
+		 */
+		if (!state->cached)
+			repo_rerere(state->repo, 0);
+	}
+
+	return errs;
+}
+
+/*
+ * Try to apply a patch.
+ *
+ * Returns:
+ *  -128 if a bad error happened (like patch unreadable)
+ *  -1 if patch did not apply and user cannot deal with it
+ *   0 if the patch applied
+ *   1 if the patch did not apply but user might fix it
+ */
+static int apply_patch(struct apply_state *state,
+		       int fd,
+		       const char *filename,
+		       int options)
+{
+	size_t offset;
+	struct strbuf buf = STRBUF_INIT; /* owns the patch text */
+	struct patch *list = NULL, **listp = &list;
+	int skipped_patch = 0;
+	int res = 0;
+	int flush_attributes = 0;
+
+	state->patch_input_file = filename;
+	if (read_patch_file(&buf, fd) < 0)
+		return -128;
+	offset = 0;
+	while (offset < buf.len) {
+		struct patch *patch;
+		int nr;
+
+		CALLOC_ARRAY(patch, 1);
+		patch->inaccurate_eof = !!(options & APPLY_OPT_INACCURATE_EOF);
+		patch->recount =  !!(options & APPLY_OPT_RECOUNT);
+		nr = parse_chunk(state, buf.buf + offset, buf.len - offset, patch);
+		if (nr < 0) {
+			free_patch(patch);
+			if (nr == -128) {
+				res = -128;
+				goto end;
+			}
+			break;
+		}
+		if (state->apply_in_reverse)
+			reverse_patches(patch);
+		if (use_patch(state, patch)) {
+			patch_stats(state, patch);
+			if (!list || !state->apply_in_reverse) {
+				*listp = patch;
+				listp = &patch->next;
+			} else {
+				patch->next = list;
+				list = patch;
+			}
+
+			if ((patch->new_name &&
+			     ends_with_path_components(patch->new_name,
+						       GITATTRIBUTES_FILE)) ||
+			    (patch->old_name &&
+			     ends_with_path_components(patch->old_name,
+						       GITATTRIBUTES_FILE)))
+				flush_attributes = 1;
+		}
+		else {
+			if (state->apply_verbosity > verbosity_normal)
+				say_patch_name(stderr, _("Skipped patch '%s'."), patch);
+			free_patch(patch);
+			skipped_patch++;
+		}
+		offset += nr;
+	}
+
+	if (!list && !skipped_patch) {
+		if (!state->allow_empty) {
+			error(_("No valid patches in input (allow with \"--allow-empty\")"));
+			res = -128;
+		}
+		goto end;
+	}
+
+	if (state->whitespace_error && (state->ws_error_action == die_on_ws_error))
+		state->apply = 0;
+
+	state->update_index = (state->check_index || state->ita_only) && state->apply;
+	if (state->update_index && !is_lock_file_locked(&state->lock_file)) {
+		if (state->index_file)
+			hold_lock_file_for_update(&state->lock_file,
+						  state->index_file,
+						  LOCK_DIE_ON_ERROR);
+		else
+			repo_hold_locked_index(state->repo, &state->lock_file,
+					       LOCK_DIE_ON_ERROR);
+	}
+
+	if (state->check_index && read_apply_cache(state) < 0) {
+		error(_("unable to read index file"));
+		res = -128;
+		goto end;
+	}
+
+	if (state->check || state->apply) {
+		int r = check_patch_list(state, list);
+		if (r == -128) {
+			res = -128;
+			goto end;
+		}
+		if (r < 0 && !state->apply_with_reject) {
+			res = -1;
+			goto end;
+		}
+	}
+
+	if (state->apply) {
+		int write_res = write_out_results(state, list);
+		if (write_res < 0) {
+			res = -128;
+			goto end;
+		}
+		if (write_res > 0) {
+			/* with --3way, we still need to write the index out */
+			res = state->apply_with_reject ? -1 : 1;
+			goto end;
+		}
+	}
+
+	if (state->fake_ancestor &&
+	    build_fake_ancestor(state, list)) {
+		res = -128;
+		goto end;
+	}
+
+	if (state->diffstat && state->apply_verbosity > verbosity_silent)
+		stat_patch_list(state, list);
+
+	if (state->numstat && state->apply_verbosity > verbosity_silent)
+		numstat_patch_list(state, list);
+
+	if (state->summary && state->apply_verbosity > verbosity_silent)
+		summary_patch_list(list);
+
+	if (flush_attributes)
+		reset_parsed_attributes();
+end:
+	free_patch_list(list);
+	strbuf_release(&buf);
+	string_list_clear(&state->fn_table, 0);
+	return res;
+}
+
+static int apply_option_parse_exclude(const struct option *opt,
+				      const char *arg, int unset)
+{
+	struct apply_state *state = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	add_name_limit(state, arg, 1);
+	return 0;
+}
+
+static int apply_option_parse_include(const struct option *opt,
+				      const char *arg, int unset)
+{
+	struct apply_state *state = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	add_name_limit(state, arg, 0);
+	state->has_include = 1;
+	return 0;
+}
+
+static int apply_option_parse_p(const struct option *opt,
+				const char *arg,
+				int unset)
+{
+	struct apply_state *state = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	state->p_value = atoi(arg);
+	state->p_value_known = 1;
+	return 0;
+}
+
+static int apply_option_parse_space_change(const struct option *opt,
+					   const char *arg, int unset)
+{
+	struct apply_state *state = opt->value;
+
+	BUG_ON_OPT_ARG(arg);
+
+	if (unset)
+		state->ws_ignore_action = ignore_ws_none;
+	else
+		state->ws_ignore_action = ignore_ws_change;
+	return 0;
+}
+
+static int apply_option_parse_whitespace(const struct option *opt,
+					 const char *arg, int unset)
+{
+	struct apply_state *state = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	state->whitespace_option = arg;
+	if (parse_whitespace_option(state, arg))
+		return -1;
+	return 0;
+}
+
+static int apply_option_parse_directory(const struct option *opt,
+					const char *arg, int unset)
+{
+	struct apply_state *state = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	strbuf_reset(&state->root);
+	strbuf_addstr(&state->root, arg);
+	strbuf_complete(&state->root, '/');
+	return 0;
+}
+
+int apply_all_patches(struct apply_state *state,
+		      int argc,
+		      const char **argv,
+		      int options)
+{
+	int i;
+	int res;
+	int errs = 0;
+	int read_stdin = 1;
+
+	for (i = 0; i < argc; i++) {
+		const char *arg = argv[i];
+		char *to_free = NULL;
+		int fd;
+
+		if (!strcmp(arg, "-")) {
+			res = apply_patch(state, 0, "<stdin>", options);
+			if (res < 0)
+				goto end;
+			errs |= res;
+			read_stdin = 0;
+			continue;
+		} else
+			arg = to_free = prefix_filename(state->prefix, arg);
+
+		fd = open(arg, O_RDONLY);
+		if (fd < 0) {
+			error(_("can't open patch '%s': %s"), arg, strerror(errno));
+			res = -128;
+			free(to_free);
+			goto end;
+		}
+		read_stdin = 0;
+		set_default_whitespace_mode(state);
+		res = apply_patch(state, fd, arg, options);
+		close(fd);
+		free(to_free);
+		if (res < 0)
+			goto end;
+		errs |= res;
+	}
+	set_default_whitespace_mode(state);
+	if (read_stdin) {
+		res = apply_patch(state, 0, "<stdin>", options);
+		if (res < 0)
+			goto end;
+		errs |= res;
+	}
+
+	if (state->whitespace_error) {
+		if (state->squelch_whitespace_errors &&
+		    state->squelch_whitespace_errors < state->whitespace_error) {
+			int squelched =
+				state->whitespace_error - state->squelch_whitespace_errors;
+			warning(Q_("squelched %d whitespace error",
+				   "squelched %d whitespace errors",
+				   squelched),
+				squelched);
+		}
+		if (state->ws_error_action == die_on_ws_error) {
+			error(Q_("%d line adds whitespace errors.",
+				 "%d lines add whitespace errors.",
+				 state->whitespace_error),
+			      state->whitespace_error);
+			res = -128;
+			goto end;
+		}
+		if (state->applied_after_fixing_ws && state->apply)
+			warning(Q_("%d line applied after"
+				   " fixing whitespace errors.",
+				   "%d lines applied after"
+				   " fixing whitespace errors.",
+				   state->applied_after_fixing_ws),
+				state->applied_after_fixing_ws);
+		else if (state->whitespace_error)
+			warning(Q_("%d line adds whitespace errors.",
+				   "%d lines add whitespace errors.",
+				   state->whitespace_error),
+				state->whitespace_error);
+	}
+
+	if (state->update_index) {
+		res = write_locked_index(state->repo->index, &state->lock_file, COMMIT_LOCK);
+		if (res) {
+			error(_("Unable to write new index file"));
+			res = -128;
+			goto end;
+		}
+	}
+
+	res = !!errs;
+
+end:
+	rollback_lock_file(&state->lock_file);
+
+	if (state->apply_verbosity <= verbosity_silent) {
+		set_error_routine(state->saved_error_routine);
+		set_warn_routine(state->saved_warn_routine);
+	}
+
+	if (res > -1)
+		return res;
+	return (res == -1 ? 1 : 128);
+}
+
+int apply_parse_options(int argc, const char **argv,
+			struct apply_state *state,
+			int *force_apply, int *options,
+			const char * const *apply_usage)
+{
+	struct option builtin_apply_options[] = {
+		OPT_CALLBACK_F(0, "exclude", state, N_("path"),
+			N_("don't apply changes matching the given path"),
+			PARSE_OPT_NONEG, apply_option_parse_exclude),
+		OPT_CALLBACK_F(0, "include", state, N_("path"),
+			N_("apply changes matching the given path"),
+			PARSE_OPT_NONEG, apply_option_parse_include),
+		OPT_CALLBACK('p', NULL, state, N_("num"),
+			N_("remove <num> leading slashes from traditional diff paths"),
+			apply_option_parse_p),
+		OPT_BOOL(0, "no-add", &state->no_add,
+			N_("ignore additions made by the patch")),
+		OPT_BOOL(0, "stat", &state->diffstat,
+			N_("instead of applying the patch, output diffstat for the input")),
+		OPT_NOOP_NOARG(0, "allow-binary-replacement"),
+		OPT_NOOP_NOARG(0, "binary"),
+		OPT_BOOL(0, "numstat", &state->numstat,
+			N_("show number of added and deleted lines in decimal notation")),
+		OPT_BOOL(0, "summary", &state->summary,
+			N_("instead of applying the patch, output a summary for the input")),
+		OPT_BOOL(0, "check", &state->check,
+			N_("instead of applying the patch, see if the patch is applicable")),
+		OPT_BOOL(0, "index", &state->check_index,
+			N_("make sure the patch is applicable to the current index")),
+		OPT_BOOL('N', "intent-to-add", &state->ita_only,
+			N_("mark new files with `git add --intent-to-add`")),
+		OPT_BOOL(0, "cached", &state->cached,
+			N_("apply a patch without touching the working tree")),
+		OPT_BOOL_F(0, "unsafe-paths", &state->unsafe_paths,
+			   N_("accept a patch that touches outside the working area"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "apply", force_apply,
+			N_("also apply the patch (use with --stat/--summary/--check)")),
+		OPT_BOOL('3', "3way", &state->threeway,
+			 N_( "attempt three-way merge, fall back on normal patch if that fails")),
+		OPT_SET_INT_F(0, "ours", &state->merge_variant,
+			N_("for conflicts, use our version"),
+			XDL_MERGE_FAVOR_OURS, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "theirs", &state->merge_variant,
+			N_("for conflicts, use their version"),
+			XDL_MERGE_FAVOR_THEIRS, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "union", &state->merge_variant,
+			N_("for conflicts, use a union version"),
+			XDL_MERGE_FAVOR_UNION, PARSE_OPT_NONEG),
+		OPT_FILENAME(0, "build-fake-ancestor", &state->fake_ancestor,
+			N_("build a temporary index based on embedded index information")),
+		/* Think twice before adding "--nul" synonym to this */
+		OPT_SET_INT('z', NULL, &state->line_termination,
+			N_("paths are separated with NUL character"), '\0'),
+		OPT_INTEGER('C', NULL, &state->p_context,
+				N_("ensure at least <n> lines of context match")),
+		OPT_CALLBACK(0, "whitespace", state, N_("action"),
+			N_("detect new or modified lines that have whitespace errors"),
+			apply_option_parse_whitespace),
+		OPT_CALLBACK_F(0, "ignore-space-change", state, NULL,
+			N_("ignore changes in whitespace when finding context"),
+			PARSE_OPT_NOARG, apply_option_parse_space_change),
+		OPT_CALLBACK_F(0, "ignore-whitespace", state, NULL,
+			N_("ignore changes in whitespace when finding context"),
+			PARSE_OPT_NOARG, apply_option_parse_space_change),
+		OPT_BOOL('R', "reverse", &state->apply_in_reverse,
+			N_("apply the patch in reverse")),
+		OPT_BOOL(0, "unidiff-zero", &state->unidiff_zero,
+			N_("don't expect at least one line of context")),
+		OPT_BOOL(0, "reject", &state->apply_with_reject,
+			N_("leave the rejected hunks in corresponding *.rej files")),
+		OPT_BOOL(0, "allow-overlap", &state->allow_overlap,
+			N_("allow overlapping hunks")),
+		OPT__VERBOSITY(&state->apply_verbosity),
+		OPT_BIT(0, "inaccurate-eof", options,
+			N_("tolerate incorrectly detected missing new-line at the end of file"),
+			APPLY_OPT_INACCURATE_EOF),
+		OPT_BIT(0, "recount", options,
+			N_("do not trust the line counts in the hunk headers"),
+			APPLY_OPT_RECOUNT),
+		OPT_CALLBACK(0, "directory", state, N_("root"),
+			N_("prepend <root> to all filenames"),
+			apply_option_parse_directory),
+		OPT_BOOL(0, "allow-empty", &state->allow_empty,
+			N_("don't return error for empty patches")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, state->prefix, builtin_apply_options, apply_usage, 0);
+
+	if (state->merge_variant && !state->threeway)
+		die(_("--ours, --theirs, and --union require --3way"));
+
+	return argc;
+}
diff --git a/apply.h b/apply.h
new file mode 100644
index 0000000000..90e887ec0e
--- /dev/null
+++ b/apply.h
@@ -0,0 +1,190 @@
+#ifndef APPLY_H
+#define APPLY_H
+
+#include "hash.h"
+#include "lockfile.h"
+#include "string-list.h"
+#include "strmap.h"
+
+struct repository;
+
+enum apply_ws_error_action {
+	nowarn_ws_error,
+	warn_on_ws_error,
+	die_on_ws_error,
+	correct_ws_error
+};
+
+enum apply_ws_ignore {
+	ignore_ws_none,
+	ignore_ws_change
+};
+
+enum apply_verbosity {
+	verbosity_silent = -1,
+	verbosity_normal = 0,
+	verbosity_verbose = 1
+};
+
+struct apply_state {
+	const char *prefix;
+
+	/* Lock file */
+	struct lock_file lock_file;
+
+	/* These control what gets looked at and modified */
+	int apply; /* this is not a dry-run */
+	int cached; /* apply to the index only */
+	int check; /* preimage must match working tree, don't actually apply */
+	int check_index; /* preimage must match the indexed version */
+	int update_index; /* check_index && apply */
+	int ita_only;	  /* add intent-to-add entries to the index */
+
+	/* These control cosmetic aspect of the output */
+	int diffstat; /* just show a diffstat, and don't actually apply */
+	int numstat; /* just show a numeric diffstat, and don't actually apply */
+	int summary; /* just report creation, deletion, etc, and don't actually apply */
+
+	/* These boolean parameters control how the apply is done */
+	int allow_overlap;
+	int apply_in_reverse;
+	int apply_with_reject;
+	int no_add;
+	int threeway;
+	int unidiff_zero;
+	int unsafe_paths;
+	int allow_empty;
+
+	/* Other non boolean parameters */
+	struct repository *repo;
+	const char *index_file;
+	enum apply_verbosity apply_verbosity;
+	int merge_variant;
+	char *fake_ancestor;
+	const char *patch_input_file;
+	int line_termination;
+	struct strbuf root;
+	int p_value;
+	int p_value_known;
+	unsigned int p_context;
+
+	/* Exclude and include path parameters */
+	struct string_list limit_by_name;
+	int has_include;
+
+	/* Various "current state" */
+	int linenr; /* current line number */
+	/*
+	 * We need to keep track of how symlinks in the preimage are
+	 * manipulated by the patches.  A patch to add a/b/c where a/b
+	 * is a symlink should not be allowed to affect the directory
+	 * the symlink points at, but if the same patch removes a/b,
+	 * it is perfectly fine, as the patch removes a/b to make room
+	 * to create a directory a/b so that a/b/c can be created.
+	 */
+	struct strset removed_symlinks;
+	struct strset kept_symlinks;
+
+	/*
+	 * For "diff-stat" like behaviour, we keep track of the biggest change
+	 * we've seen, and the longest filename. That allows us to do simple
+	 * scaling.
+	 */
+	int max_change;
+	int max_len;
+
+	/*
+	 * Records filenames that have been touched, in order to handle
+	 * the case where more than one patches touch the same file.
+	 */
+	struct string_list fn_table;
+
+	/*
+	 * This is to save reporting routines before using
+	 * set_error_routine() or set_warn_routine() to install muting
+	 * routines when in verbosity_silent mode.
+	 */
+	void (*saved_error_routine)(const char *err, va_list params);
+	void (*saved_warn_routine)(const char *warn, va_list params);
+
+	/* These control whitespace errors */
+	enum apply_ws_error_action ws_error_action;
+	enum apply_ws_ignore ws_ignore_action;
+	const char *whitespace_option;
+	int whitespace_error;
+	int squelch_whitespace_errors;
+	int applied_after_fixing_ws;
+};
+
+/*
+ * This represents a "patch" to a file, both metainfo changes
+ * such as creation/deletion, filemode and content changes represented
+ * as a series of fragments.
+ */
+struct patch {
+	char *new_name, *old_name, *def_name;
+	unsigned int old_mode, new_mode;
+	int is_new, is_delete;	/* -1 = unknown, 0 = false, 1 = true */
+	int rejected;
+	unsigned ws_rule;
+	int lines_added, lines_deleted;
+	int score;
+	int extension_linenr; /* first line specifying delete/new/rename/copy */
+	unsigned int is_toplevel_relative:1;
+	unsigned int inaccurate_eof:1;
+	unsigned int is_binary:1;
+	unsigned int is_copy:1;
+	unsigned int is_rename:1;
+	unsigned int recount:1;
+	unsigned int conflicted_threeway:1;
+	unsigned int direct_to_threeway:1;
+	unsigned int crlf_in_old:1;
+	struct fragment *fragments;
+	char *result;
+	size_t resultsize;
+	char old_oid_prefix[GIT_MAX_HEXSZ + 1];
+	char new_oid_prefix[GIT_MAX_HEXSZ + 1];
+	struct patch *next;
+
+	/* three-way fallback result */
+	struct object_id threeway_stage[3];
+};
+
+int apply_parse_options(int argc, const char **argv,
+			struct apply_state *state,
+			int *force_apply, int *options,
+			const char * const *apply_usage);
+int init_apply_state(struct apply_state *state,
+		     struct repository *repo,
+		     const char *prefix);
+void clear_apply_state(struct apply_state *state);
+int check_apply_state(struct apply_state *state, int force_apply);
+
+/*
+ * Parse a git diff header, starting at line.  Fills the relevant
+ * metadata information in 'struct patch'.
+ *
+ * Returns -1 on failure, the length of the parsed header otherwise.
+ */
+int parse_git_diff_header(struct strbuf *root,
+			  int *linenr,
+			  int p_value,
+			  const char *line,
+			  int len,
+			  unsigned int size,
+			  struct patch *patch);
+
+void release_patch(struct patch *patch);
+
+/*
+ * Some aspects of the apply behavior are controlled by the following
+ * bits in the "options" parameter passed to apply_all_patches().
+ */
+#define APPLY_OPT_INACCURATE_EOF	(1<<0) /* accept inaccurate eof */
+#define APPLY_OPT_RECOUNT		(1<<1) /* accept inaccurate line count */
+
+int apply_all_patches(struct apply_state *state,
+		      int argc, const char **argv,
+		      int options);
+
+#endif
diff --git a/archive-tar.c b/archive-tar.c
new file mode 100644
index 0000000000..e7b3489e1e
--- /dev/null
+++ b/archive-tar.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2005, 2006 Rene Scharfe
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#include "hex.h"
+#include "tar.h"
+#include "archive.h"
+#include "object-store-ll.h"
+#include "strbuf.h"
+#include "streaming.h"
+#include "run-command.h"
+#include "write-or-die.h"
+
+#define RECORDSIZE	(512)
+#define BLOCKSIZE	(RECORDSIZE * 20)
+
+static char block[BLOCKSIZE];
+static unsigned long offset;
+
+static int tar_umask = 002;
+
+static int write_tar_filter_archive(const struct archiver *ar,
+				    struct archiver_args *args);
+
+/*
+ * This is the max value that a ustar size header can specify, as it is fixed
+ * at 11 octal digits. POSIX specifies that we switch to extended headers at
+ * this size.
+ *
+ * Likewise for the mtime (which happens to use a buffer of the same size).
+ */
+#if ULONG_MAX == 0xFFFFFFFF
+#define USTAR_MAX_SIZE ULONG_MAX
+#else
+#define USTAR_MAX_SIZE 077777777777UL
+#endif
+#if TIME_MAX == 0xFFFFFFFF
+#define USTAR_MAX_MTIME TIME_MAX
+#else
+#define USTAR_MAX_MTIME 077777777777ULL
+#endif
+
+static void tar_write_block(const void *buf)
+{
+	write_or_die(1, buf, BLOCKSIZE);
+}
+
+static void (*write_block)(const void *) = tar_write_block;
+
+/* writes out the whole block, but only if it is full */
+static void write_if_needed(void)
+{
+	if (offset == BLOCKSIZE) {
+		write_block(block);
+		offset = 0;
+	}
+}
+
+/*
+ * queues up writes, so that all our write(2) calls write exactly one
+ * full block; pads writes to RECORDSIZE
+ */
+static void do_write_blocked(const void *data, unsigned long size)
+{
+	const char *buf = data;
+
+	if (offset) {
+		unsigned long chunk = BLOCKSIZE - offset;
+		if (size < chunk)
+			chunk = size;
+		memcpy(block + offset, buf, chunk);
+		size -= chunk;
+		offset += chunk;
+		buf += chunk;
+		write_if_needed();
+	}
+	while (size >= BLOCKSIZE) {
+		write_block(buf);
+		size -= BLOCKSIZE;
+		buf += BLOCKSIZE;
+	}
+	if (size) {
+		memcpy(block + offset, buf, size);
+		offset += size;
+	}
+}
+
+static void finish_record(void)
+{
+	unsigned long tail;
+	tail = offset % RECORDSIZE;
+	if (tail)  {
+		memset(block + offset, 0, RECORDSIZE - tail);
+		offset += RECORDSIZE - tail;
+	}
+	write_if_needed();
+}
+
+static void write_blocked(const void *data, unsigned long size)
+{
+	do_write_blocked(data, size);
+	finish_record();
+}
+
+/*
+ * The end of tar archives is marked by 2*512 nul bytes and after that
+ * follows the rest of the block (if any).
+ */
+static void write_trailer(void)
+{
+	int tail = BLOCKSIZE - offset;
+	memset(block + offset, 0, tail);
+	write_block(block);
+	if (tail < 2 * RECORDSIZE) {
+		memset(block, 0, offset);
+		write_block(block);
+	}
+}
+
+/*
+ * queues up writes, so that all our write(2) calls write exactly one
+ * full block; pads writes to RECORDSIZE
+ */
+static int stream_blocked(struct repository *r, const struct object_id *oid)
+{
+	struct git_istream *st;
+	enum object_type type;
+	unsigned long sz;
+	char buf[BLOCKSIZE];
+	ssize_t readlen;
+
+	st = open_istream(r, oid, &type, &sz, NULL);
+	if (!st)
+		return error(_("cannot stream blob %s"), oid_to_hex(oid));
+	for (;;) {
+		readlen = read_istream(st, buf, sizeof(buf));
+		if (readlen <= 0)
+			break;
+		do_write_blocked(buf, readlen);
+	}
+	close_istream(st);
+	if (!readlen)
+		finish_record();
+	return readlen;
+}
+
+/*
+ * pax extended header records have the format "%u %s=%s\n".  %u contains
+ * the size of the whole string (including the %u), the first %s is the
+ * keyword, the second one is the value.  This function constructs such a
+ * string and appends it to a struct strbuf.
+ */
+static void strbuf_append_ext_header(struct strbuf *sb, const char *keyword,
+				     const char *value, size_t valuelen)
+{
+	size_t orig_len = sb->len;
+	size_t len, tmp;
+
+	/* "%u %s=%s\n" */
+	len = 1 + 1 + strlen(keyword) + 1 + valuelen + 1;
+	for (tmp = 1; len / 10 >= tmp; tmp *= 10)
+		len++;
+
+	strbuf_grow(sb, len);
+	strbuf_addf(sb, "%"PRIuMAX" %s=", (uintmax_t)len, keyword);
+	strbuf_add(sb, value, valuelen);
+	strbuf_addch(sb, '\n');
+
+	if (len != sb->len - orig_len)
+		BUG("pax extended header length miscalculated as %"PRIuMAX
+		    ", should be %"PRIuMAX,
+		    (uintmax_t)len, (uintmax_t)(sb->len - orig_len));
+}
+
+/*
+ * Like strbuf_append_ext_header, but for numeric values.
+ */
+static void strbuf_append_ext_header_uint(struct strbuf *sb,
+					  const char *keyword,
+					  uintmax_t value)
+{
+	char buf[40]; /* big enough for 2^128 in decimal, plus NUL */
+	int len;
+
+	len = xsnprintf(buf, sizeof(buf), "%"PRIuMAX, value);
+	strbuf_append_ext_header(sb, keyword, buf, len);
+}
+
+static unsigned int ustar_header_chksum(const struct ustar_header *header)
+{
+	const unsigned char *p = (const unsigned char *)header;
+	unsigned int chksum = 0;
+	while (p < (const unsigned char *)header->chksum)
+		chksum += *p++;
+	chksum += sizeof(header->chksum) * ' ';
+	p += sizeof(header->chksum);
+	while (p < (const unsigned char *)header + sizeof(struct ustar_header))
+		chksum += *p++;
+	return chksum;
+}
+
+static size_t get_path_prefix(const char *path, size_t pathlen, size_t maxlen)
+{
+	size_t i = pathlen;
+	if (i > 1 && path[i - 1] == '/')
+		i--;
+	if (i > maxlen)
+		i = maxlen;
+	do {
+		i--;
+	} while (i > 0 && path[i] != '/');
+	return i;
+}
+
+static void prepare_header(struct archiver_args *args,
+			   struct ustar_header *header,
+			   unsigned int mode, unsigned long size)
+{
+	xsnprintf(header->mode, sizeof(header->mode), "%07o", mode & 07777);
+	xsnprintf(header->size, sizeof(header->size), "%011"PRIoMAX , S_ISREG(mode) ? (uintmax_t)size : (uintmax_t)0);
+	xsnprintf(header->mtime, sizeof(header->mtime), "%011lo", (unsigned long) args->time);
+
+	xsnprintf(header->uid, sizeof(header->uid), "%07o", 0);
+	xsnprintf(header->gid, sizeof(header->gid), "%07o", 0);
+	strlcpy(header->uname, "root", sizeof(header->uname));
+	strlcpy(header->gname, "root", sizeof(header->gname));
+	xsnprintf(header->devmajor, sizeof(header->devmajor), "%07o", 0);
+	xsnprintf(header->devminor, sizeof(header->devminor), "%07o", 0);
+
+	memcpy(header->magic, "ustar", 6);
+	memcpy(header->version, "00", 2);
+
+	xsnprintf(header->chksum, sizeof(header->chksum), "%07o", ustar_header_chksum(header));
+}
+
+static void write_extended_header(struct archiver_args *args,
+				  const struct object_id *oid,
+				  const void *buffer, unsigned long size)
+{
+	struct ustar_header header;
+	unsigned int mode;
+	memset(&header, 0, sizeof(header));
+	*header.typeflag = TYPEFLAG_EXT_HEADER;
+	mode = 0100666;
+	xsnprintf(header.name, sizeof(header.name), "%s.paxheader", oid_to_hex(oid));
+	prepare_header(args, &header, mode, size);
+	write_blocked(&header, sizeof(header));
+	write_blocked(buffer, size);
+}
+
+static int write_tar_entry(struct archiver_args *args,
+			   const struct object_id *oid,
+			   const char *path, size_t pathlen,
+			   unsigned int mode,
+			   void *buffer, unsigned long size)
+{
+	struct ustar_header header;
+	struct strbuf ext_header = STRBUF_INIT;
+	unsigned long size_in_header;
+	int err = 0;
+
+	memset(&header, 0, sizeof(header));
+
+	if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
+		*header.typeflag = TYPEFLAG_DIR;
+		mode = (mode | 0777) & ~tar_umask;
+	} else if (S_ISLNK(mode)) {
+		*header.typeflag = TYPEFLAG_LNK;
+		mode |= 0777;
+	} else if (S_ISREG(mode)) {
+		*header.typeflag = TYPEFLAG_REG;
+		mode = (mode | ((mode & 0100) ? 0777 : 0666)) & ~tar_umask;
+	} else {
+		return error(_("unsupported file mode: 0%o (SHA1: %s)"),
+			     mode, oid_to_hex(oid));
+	}
+	if (pathlen > sizeof(header.name)) {
+		size_t plen = get_path_prefix(path, pathlen,
+					      sizeof(header.prefix));
+		size_t rest = pathlen - plen - 1;
+		if (plen > 0 && rest <= sizeof(header.name)) {
+			memcpy(header.prefix, path, plen);
+			memcpy(header.name, path + plen + 1, rest);
+		} else {
+			xsnprintf(header.name, sizeof(header.name), "%s.data",
+				  oid_to_hex(oid));
+			strbuf_append_ext_header(&ext_header, "path",
+						 path, pathlen);
+		}
+	} else
+		memcpy(header.name, path, pathlen);
+
+	if (S_ISLNK(mode)) {
+		if (size > sizeof(header.linkname)) {
+			xsnprintf(header.linkname, sizeof(header.linkname),
+				  "see %s.paxheader", oid_to_hex(oid));
+			strbuf_append_ext_header(&ext_header, "linkpath",
+			                         buffer, size);
+		} else
+			memcpy(header.linkname, buffer, size);
+	}
+
+	size_in_header = size;
+	if (S_ISREG(mode) && size > USTAR_MAX_SIZE) {
+		size_in_header = 0;
+		strbuf_append_ext_header_uint(&ext_header, "size", size);
+	}
+
+	prepare_header(args, &header, mode, size_in_header);
+
+	if (ext_header.len > 0) {
+		write_extended_header(args, oid, ext_header.buf,
+				      ext_header.len);
+	}
+	strbuf_release(&ext_header);
+	write_blocked(&header, sizeof(header));
+	if (S_ISREG(mode) && size > 0) {
+		if (buffer)
+			write_blocked(buffer, size);
+		else
+			err = stream_blocked(args->repo, oid);
+	}
+	return err;
+}
+
+static void write_global_extended_header(struct archiver_args *args)
+{
+	const struct object_id *oid = args->commit_oid;
+	struct strbuf ext_header = STRBUF_INIT;
+	struct ustar_header header;
+	unsigned int mode;
+
+	if (oid)
+		strbuf_append_ext_header(&ext_header, "comment",
+					 oid_to_hex(oid),
+					 the_hash_algo->hexsz);
+	if (args->time > USTAR_MAX_MTIME) {
+		strbuf_append_ext_header_uint(&ext_header, "mtime",
+					      args->time);
+		args->time = USTAR_MAX_MTIME;
+	}
+
+	if (!ext_header.len)
+		return;
+
+	memset(&header, 0, sizeof(header));
+	*header.typeflag = TYPEFLAG_GLOBAL_HEADER;
+	mode = 0100666;
+	xsnprintf(header.name, sizeof(header.name), "pax_global_header");
+	prepare_header(args, &header, mode, ext_header.len);
+	write_blocked(&header, sizeof(header));
+	write_blocked(ext_header.buf, ext_header.len);
+	strbuf_release(&ext_header);
+}
+
+static struct archiver **tar_filters;
+static int nr_tar_filters;
+static int alloc_tar_filters;
+
+static struct archiver *find_tar_filter(const char *name, size_t len)
+{
+	int i;
+	for (i = 0; i < nr_tar_filters; i++) {
+		struct archiver *ar = tar_filters[i];
+		if (!xstrncmpz(ar->name, name, len))
+			return ar;
+	}
+	return NULL;
+}
+
+static int tar_filter_config(const char *var, const char *value,
+			     void *data UNUSED)
+{
+	struct archiver *ar;
+	const char *name;
+	const char *type;
+	size_t namelen;
+
+	if (parse_config_key(var, "tar", &name, &namelen, &type) < 0 || !name)
+		return 0;
+
+	ar = find_tar_filter(name, namelen);
+	if (!ar) {
+		CALLOC_ARRAY(ar, 1);
+		ar->name = xmemdupz(name, namelen);
+		ar->write_archive = write_tar_filter_archive;
+		ar->flags = ARCHIVER_WANT_COMPRESSION_LEVELS |
+			    ARCHIVER_HIGH_COMPRESSION_LEVELS;
+		ALLOC_GROW(tar_filters, nr_tar_filters + 1, alloc_tar_filters);
+		tar_filters[nr_tar_filters++] = ar;
+	}
+
+	if (!strcmp(type, "command")) {
+		if (!value)
+			return config_error_nonbool(var);
+		free(ar->filter_command);
+		ar->filter_command = xstrdup(value);
+		return 0;
+	}
+	if (!strcmp(type, "remote")) {
+		if (git_config_bool(var, value))
+			ar->flags |= ARCHIVER_REMOTE;
+		else
+			ar->flags &= ~ARCHIVER_REMOTE;
+		return 0;
+	}
+
+	return 0;
+}
+
+static int git_tar_config(const char *var, const char *value,
+			  const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "tar.umask")) {
+		if (value && !strcmp(value, "user")) {
+			tar_umask = umask(0);
+			umask(tar_umask);
+		} else {
+			tar_umask = git_config_int(var, value, ctx->kvi);
+		}
+		return 0;
+	}
+
+	return tar_filter_config(var, value, cb);
+}
+
+static int write_tar_archive(const struct archiver *ar UNUSED,
+			     struct archiver_args *args)
+{
+	int err = 0;
+
+	write_global_extended_header(args);
+	err = write_archive_entries(args, write_tar_entry);
+	if (!err)
+		write_trailer();
+	return err;
+}
+
+static git_zstream gzstream;
+static unsigned char outbuf[16384];
+
+static void tgz_deflate(int flush)
+{
+	while (gzstream.avail_in || flush == Z_FINISH) {
+		int status = git_deflate(&gzstream, flush);
+		if (!gzstream.avail_out || status == Z_STREAM_END) {
+			write_or_die(1, outbuf, gzstream.next_out - outbuf);
+			gzstream.next_out = outbuf;
+			gzstream.avail_out = sizeof(outbuf);
+			if (status == Z_STREAM_END)
+				break;
+		}
+		if (status != Z_OK && status != Z_BUF_ERROR)
+			die(_("deflate error (%d)"), status);
+	}
+}
+
+static void tgz_write_block(const void *data)
+{
+	gzstream.next_in = (void *)data;
+	gzstream.avail_in = BLOCKSIZE;
+	tgz_deflate(Z_NO_FLUSH);
+}
+
+static const char internal_gzip_command[] = "git archive gzip";
+
+static int write_tar_filter_archive(const struct archiver *ar,
+				    struct archiver_args *args)
+{
+#if ZLIB_VERNUM >= 0x1221
+	struct gz_header_s gzhead = { .os = 3 }; /* Unix, for reproducibility */
+#endif
+	struct strbuf cmd = STRBUF_INIT;
+	struct child_process filter = CHILD_PROCESS_INIT;
+	int r;
+
+	if (!ar->filter_command)
+		BUG("tar-filter archiver called with no filter defined");
+
+	if (!strcmp(ar->filter_command, internal_gzip_command)) {
+		write_block = tgz_write_block;
+		git_deflate_init_gzip(&gzstream, args->compression_level);
+#if ZLIB_VERNUM >= 0x1221
+		if (deflateSetHeader(&gzstream.z, &gzhead) != Z_OK)
+			BUG("deflateSetHeader() called too late");
+#endif
+		gzstream.next_out = outbuf;
+		gzstream.avail_out = sizeof(outbuf);
+
+		r = write_tar_archive(ar, args);
+
+		tgz_deflate(Z_FINISH);
+		git_deflate_end(&gzstream);
+		return r;
+	}
+
+	strbuf_addstr(&cmd, ar->filter_command);
+	if (args->compression_level >= 0)
+		strbuf_addf(&cmd, " -%d", args->compression_level);
+
+	strvec_push(&filter.args, cmd.buf);
+	filter.use_shell = 1;
+	filter.in = -1;
+	filter.silent_exec_failure = 1;
+
+	if (start_command(&filter) < 0)
+		die_errno(_("unable to start '%s' filter"), cmd.buf);
+	close(1);
+	if (dup2(filter.in, 1) < 0)
+		die_errno(_("unable to redirect descriptor"));
+	close(filter.in);
+
+	r = write_tar_archive(ar, args);
+
+	close(1);
+	if (finish_command(&filter) != 0)
+		die(_("'%s' filter reported error"), cmd.buf);
+
+	strbuf_release(&cmd);
+	return r;
+}
+
+static struct archiver tar_archiver = {
+	.name = "tar",
+	.write_archive = write_tar_archive,
+	.flags = ARCHIVER_REMOTE,
+};
+
+void init_tar_archiver(void)
+{
+	int i;
+	register_archiver(&tar_archiver);
+
+	tar_filter_config("tar.tgz.command", internal_gzip_command, NULL);
+	tar_filter_config("tar.tgz.remote", "true", NULL);
+	tar_filter_config("tar.tar.gz.command", internal_gzip_command, NULL);
+	tar_filter_config("tar.tar.gz.remote", "true", NULL);
+	git_config(git_tar_config, NULL);
+	for (i = 0; i < nr_tar_filters; i++) {
+		/* omit any filters that never had a command configured */
+		if (tar_filters[i]->filter_command)
+			register_archiver(tar_filters[i]);
+	}
+}
diff --git a/archive-zip.c b/archive-zip.c
new file mode 100644
index 0000000000..9f32730181
--- /dev/null
+++ b/archive-zip.c
@@ -0,0 +1,659 @@
+/*
+ * Copyright (c) 2006 Rene Scharfe
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "archive.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#include "hex.h"
+#include "streaming.h"
+#include "utf8.h"
+#include "object-store-ll.h"
+#include "strbuf.h"
+#include "userdiff.h"
+#include "write-or-die.h"
+#include "xdiff-interface.h"
+#include "date.h"
+
+static int zip_date;
+static int zip_time;
+
+/* We only care about the "buf" part here. */
+static struct strbuf zip_dir;
+
+static uintmax_t zip_offset;
+static uint64_t zip_dir_entries;
+
+static unsigned int max_creator_version;
+
+#define ZIP_STREAM	(1 <<  3)
+#define ZIP_UTF8	(1 << 11)
+
+enum zip_method {
+	ZIP_METHOD_STORE = 0,
+	ZIP_METHOD_DEFLATE = 8
+};
+
+struct zip_local_header {
+	unsigned char magic[4];
+	unsigned char version[2];
+	unsigned char flags[2];
+	unsigned char compression_method[2];
+	unsigned char mtime[2];
+	unsigned char mdate[2];
+	unsigned char crc32[4];
+	unsigned char compressed_size[4];
+	unsigned char size[4];
+	unsigned char filename_length[2];
+	unsigned char extra_length[2];
+	unsigned char _end[1];
+};
+
+struct zip_data_desc {
+	unsigned char magic[4];
+	unsigned char crc32[4];
+	unsigned char compressed_size[4];
+	unsigned char size[4];
+	unsigned char _end[1];
+};
+
+struct zip64_data_desc {
+	unsigned char magic[4];
+	unsigned char crc32[4];
+	unsigned char compressed_size[8];
+	unsigned char size[8];
+	unsigned char _end[1];
+};
+
+struct zip_dir_trailer {
+	unsigned char magic[4];
+	unsigned char disk[2];
+	unsigned char directory_start_disk[2];
+	unsigned char entries_on_this_disk[2];
+	unsigned char entries[2];
+	unsigned char size[4];
+	unsigned char offset[4];
+	unsigned char comment_length[2];
+	unsigned char _end[1];
+};
+
+struct zip_extra_mtime {
+	unsigned char magic[2];
+	unsigned char extra_size[2];
+	unsigned char flags[1];
+	unsigned char mtime[4];
+	unsigned char _end[1];
+};
+
+struct zip64_extra {
+	unsigned char magic[2];
+	unsigned char extra_size[2];
+	unsigned char size[8];
+	unsigned char compressed_size[8];
+	unsigned char _end[1];
+};
+
+struct zip64_dir_trailer {
+	unsigned char magic[4];
+	unsigned char record_size[8];
+	unsigned char creator_version[2];
+	unsigned char version[2];
+	unsigned char disk[4];
+	unsigned char directory_start_disk[4];
+	unsigned char entries_on_this_disk[8];
+	unsigned char entries[8];
+	unsigned char size[8];
+	unsigned char offset[8];
+	unsigned char _end[1];
+};
+
+struct zip64_dir_trailer_locator {
+	unsigned char magic[4];
+	unsigned char disk[4];
+	unsigned char offset[8];
+	unsigned char number_of_disks[4];
+	unsigned char _end[1];
+};
+
+/*
+ * On ARM, padding is added at the end of the struct, so a simple
+ * sizeof(struct ...) reports two bytes more than the payload size
+ * we're interested in.
+ */
+#define ZIP_LOCAL_HEADER_SIZE	offsetof(struct zip_local_header, _end)
+#define ZIP_DATA_DESC_SIZE	offsetof(struct zip_data_desc, _end)
+#define ZIP64_DATA_DESC_SIZE	offsetof(struct zip64_data_desc, _end)
+#define ZIP_DIR_HEADER_SIZE	offsetof(struct zip_dir_header, _end)
+#define ZIP_DIR_TRAILER_SIZE	offsetof(struct zip_dir_trailer, _end)
+#define ZIP_EXTRA_MTIME_SIZE	offsetof(struct zip_extra_mtime, _end)
+#define ZIP_EXTRA_MTIME_PAYLOAD_SIZE \
+	(ZIP_EXTRA_MTIME_SIZE - offsetof(struct zip_extra_mtime, flags))
+#define ZIP64_EXTRA_SIZE	offsetof(struct zip64_extra, _end)
+#define ZIP64_EXTRA_PAYLOAD_SIZE \
+	(ZIP64_EXTRA_SIZE - offsetof(struct zip64_extra, size))
+#define ZIP64_DIR_TRAILER_SIZE	offsetof(struct zip64_dir_trailer, _end)
+#define ZIP64_DIR_TRAILER_RECORD_SIZE \
+	(ZIP64_DIR_TRAILER_SIZE - \
+	 offsetof(struct zip64_dir_trailer, creator_version))
+#define ZIP64_DIR_TRAILER_LOCATOR_SIZE \
+	offsetof(struct zip64_dir_trailer_locator, _end)
+
+static void copy_le16(unsigned char *dest, unsigned int n)
+{
+	dest[0] = 0xff & n;
+	dest[1] = 0xff & (n >> 010);
+}
+
+static void copy_le32(unsigned char *dest, unsigned int n)
+{
+	dest[0] = 0xff & n;
+	dest[1] = 0xff & (n >> 010);
+	dest[2] = 0xff & (n >> 020);
+	dest[3] = 0xff & (n >> 030);
+}
+
+static void copy_le64(unsigned char *dest, uint64_t n)
+{
+	dest[0] = 0xff & n;
+	dest[1] = 0xff & (n >> 010);
+	dest[2] = 0xff & (n >> 020);
+	dest[3] = 0xff & (n >> 030);
+	dest[4] = 0xff & (n >> 040);
+	dest[5] = 0xff & (n >> 050);
+	dest[6] = 0xff & (n >> 060);
+	dest[7] = 0xff & (n >> 070);
+}
+
+static uint64_t clamp_max(uint64_t n, uint64_t max, int *clamped)
+{
+	if (n <= max)
+		return n;
+	*clamped = 1;
+	return max;
+}
+
+static void copy_le16_clamp(unsigned char *dest, uint64_t n, int *clamped)
+{
+	copy_le16(dest, clamp_max(n, 0xffff, clamped));
+}
+
+static void copy_le32_clamp(unsigned char *dest, uint64_t n, int *clamped)
+{
+	copy_le32(dest, clamp_max(n, 0xffffffff, clamped));
+}
+
+static int strbuf_add_le(struct strbuf *sb, size_t size, uintmax_t n)
+{
+	while (size-- > 0) {
+		strbuf_addch(sb, n & 0xff);
+		n >>= 8;
+	}
+	return -!!n;
+}
+
+static uint32_t clamp32(uintmax_t n)
+{
+	const uintmax_t max = 0xffffffff;
+	return (n < max) ? n : max;
+}
+
+static void *zlib_deflate_raw(void *data, unsigned long size,
+			      int compression_level,
+			      unsigned long *compressed_size)
+{
+	git_zstream stream;
+	unsigned long maxsize;
+	void *buffer;
+	int result;
+
+	git_deflate_init_raw(&stream, compression_level);
+	maxsize = git_deflate_bound(&stream, size);
+	buffer = xmalloc(maxsize);
+
+	stream.next_in = data;
+	stream.avail_in = size;
+	stream.next_out = buffer;
+	stream.avail_out = maxsize;
+
+	do {
+		result = git_deflate(&stream, Z_FINISH);
+	} while (result == Z_OK);
+
+	if (result != Z_STREAM_END) {
+		free(buffer);
+		return NULL;
+	}
+
+	git_deflate_end(&stream);
+	*compressed_size = stream.total_out;
+
+	return buffer;
+}
+
+static void write_zip_data_desc(unsigned long size,
+				unsigned long compressed_size,
+				unsigned long crc)
+{
+	if (size >= 0xffffffff || compressed_size >= 0xffffffff) {
+		struct zip64_data_desc trailer;
+		copy_le32(trailer.magic, 0x08074b50);
+		copy_le32(trailer.crc32, crc);
+		copy_le64(trailer.compressed_size, compressed_size);
+		copy_le64(trailer.size, size);
+		write_or_die(1, &trailer, ZIP64_DATA_DESC_SIZE);
+		zip_offset += ZIP64_DATA_DESC_SIZE;
+	} else {
+		struct zip_data_desc trailer;
+		copy_le32(trailer.magic, 0x08074b50);
+		copy_le32(trailer.crc32, crc);
+		copy_le32(trailer.compressed_size, compressed_size);
+		copy_le32(trailer.size, size);
+		write_or_die(1, &trailer, ZIP_DATA_DESC_SIZE);
+		zip_offset += ZIP_DATA_DESC_SIZE;
+	}
+}
+
+static void set_zip_header_data_desc(struct zip_local_header *header,
+				     unsigned long size,
+				     unsigned long compressed_size,
+				     unsigned long crc)
+{
+	copy_le32(header->crc32, crc);
+	copy_le32(header->compressed_size, compressed_size);
+	copy_le32(header->size, size);
+}
+
+static int has_only_ascii(const char *s)
+{
+	for (;;) {
+		int c = *s++;
+		if (c == '\0')
+			return 1;
+		if (!isascii(c))
+			return 0;
+	}
+}
+
+static int entry_is_binary(struct index_state *istate, const char *path,
+			   const void *buffer, size_t size)
+{
+	struct userdiff_driver *driver = userdiff_find_by_path(istate, path);
+	if (!driver)
+		driver = userdiff_find_by_name("default");
+	if (driver->binary != -1)
+		return driver->binary;
+	return buffer_is_binary(buffer, size);
+}
+
+#define STREAM_BUFFER_SIZE (1024 * 16)
+
+static int write_zip_entry(struct archiver_args *args,
+			   const struct object_id *oid,
+			   const char *path, size_t pathlen,
+			   unsigned int mode,
+			   void *buffer, unsigned long size)
+{
+	struct zip_local_header header;
+	uintmax_t offset = zip_offset;
+	struct zip_extra_mtime extra;
+	struct zip64_extra extra64;
+	size_t header_extra_size = ZIP_EXTRA_MTIME_SIZE;
+	int need_zip64_extra = 0;
+	unsigned long attr2;
+	unsigned long compressed_size;
+	unsigned long crc;
+	enum zip_method method;
+	unsigned char *out;
+	void *deflated = NULL;
+	struct git_istream *stream = NULL;
+	unsigned long flags = 0;
+	int is_binary = -1;
+	const char *path_without_prefix = path + args->baselen;
+	unsigned int creator_version = 0;
+	unsigned int version_needed = 10;
+	size_t zip_dir_extra_size = ZIP_EXTRA_MTIME_SIZE;
+	size_t zip64_dir_extra_payload_size = 0;
+
+	crc = crc32(0, NULL, 0);
+
+	if (!has_only_ascii(path)) {
+		if (is_utf8(path))
+			flags |= ZIP_UTF8;
+		else
+			warning(_("path is not valid UTF-8: %s"), path);
+	}
+
+	if (pathlen > 0xffff) {
+		return error(_("path too long (%d chars, SHA1: %s): %s"),
+				(int)pathlen, oid_to_hex(oid), path);
+	}
+
+	if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
+		method = ZIP_METHOD_STORE;
+		attr2 = 16;
+		out = NULL;
+		compressed_size = 0;
+	} else if (S_ISREG(mode) || S_ISLNK(mode)) {
+		method = ZIP_METHOD_STORE;
+		attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) :
+			(mode & 0111) ? ((mode) << 16) : 0;
+		if (S_ISLNK(mode) || (mode & 0111))
+			creator_version = 0x0317;
+		if (S_ISREG(mode) && args->compression_level != 0 && size > 0)
+			method = ZIP_METHOD_DEFLATE;
+
+		if (!buffer) {
+			enum object_type type;
+			stream = open_istream(args->repo, oid, &type, &size,
+					      NULL);
+			if (!stream)
+				return error(_("cannot stream blob %s"),
+					     oid_to_hex(oid));
+			flags |= ZIP_STREAM;
+			out = NULL;
+		} else {
+			crc = crc32(crc, buffer, size);
+			is_binary = entry_is_binary(args->repo->index,
+						    path_without_prefix,
+						    buffer, size);
+			out = buffer;
+		}
+		compressed_size = (method == ZIP_METHOD_STORE) ? size : 0;
+	} else {
+		return error(_("unsupported file mode: 0%o (SHA1: %s)"), mode,
+				oid_to_hex(oid));
+	}
+
+	if (creator_version > max_creator_version)
+		max_creator_version = creator_version;
+
+	if (buffer && method == ZIP_METHOD_DEFLATE) {
+		out = deflated = zlib_deflate_raw(buffer, size,
+						  args->compression_level,
+						  &compressed_size);
+		if (!out || compressed_size >= size) {
+			out = buffer;
+			method = ZIP_METHOD_STORE;
+			compressed_size = size;
+		}
+	}
+
+	copy_le16(extra.magic, 0x5455);
+	copy_le16(extra.extra_size, ZIP_EXTRA_MTIME_PAYLOAD_SIZE);
+	extra.flags[0] = 1;	/* just mtime */
+	copy_le32(extra.mtime, args->time);
+
+	if (size > 0xffffffff || compressed_size > 0xffffffff)
+		need_zip64_extra = 1;
+	if (stream && size > 0x7fffffff)
+		need_zip64_extra = 1;
+
+	if (need_zip64_extra)
+		version_needed = 45;
+
+	copy_le32(header.magic, 0x04034b50);
+	copy_le16(header.version, version_needed);
+	copy_le16(header.flags, flags);
+	copy_le16(header.compression_method, method);
+	copy_le16(header.mtime, zip_time);
+	copy_le16(header.mdate, zip_date);
+	if (need_zip64_extra) {
+		set_zip_header_data_desc(&header, 0xffffffff, 0xffffffff, crc);
+		header_extra_size += ZIP64_EXTRA_SIZE;
+	} else {
+		set_zip_header_data_desc(&header, size, compressed_size, crc);
+	}
+	copy_le16(header.filename_length, pathlen);
+	copy_le16(header.extra_length, header_extra_size);
+	write_or_die(1, &header, ZIP_LOCAL_HEADER_SIZE);
+	zip_offset += ZIP_LOCAL_HEADER_SIZE;
+	write_or_die(1, path, pathlen);
+	zip_offset += pathlen;
+	write_or_die(1, &extra, ZIP_EXTRA_MTIME_SIZE);
+	zip_offset += ZIP_EXTRA_MTIME_SIZE;
+	if (need_zip64_extra) {
+		copy_le16(extra64.magic, 0x0001);
+		copy_le16(extra64.extra_size, ZIP64_EXTRA_PAYLOAD_SIZE);
+		copy_le64(extra64.size, size);
+		copy_le64(extra64.compressed_size, compressed_size);
+		write_or_die(1, &extra64, ZIP64_EXTRA_SIZE);
+		zip_offset += ZIP64_EXTRA_SIZE;
+	}
+
+	if (stream && method == ZIP_METHOD_STORE) {
+		unsigned char buf[STREAM_BUFFER_SIZE];
+		ssize_t readlen;
+
+		for (;;) {
+			readlen = read_istream(stream, buf, sizeof(buf));
+			if (readlen <= 0)
+				break;
+			crc = crc32(crc, buf, readlen);
+			if (is_binary == -1)
+				is_binary = entry_is_binary(args->repo->index,
+							    path_without_prefix,
+							    buf, readlen);
+			write_or_die(1, buf, readlen);
+		}
+		close_istream(stream);
+		if (readlen)
+			return readlen;
+
+		compressed_size = size;
+		zip_offset += compressed_size;
+
+		write_zip_data_desc(size, compressed_size, crc);
+	} else if (stream && method == ZIP_METHOD_DEFLATE) {
+		unsigned char buf[STREAM_BUFFER_SIZE];
+		ssize_t readlen;
+		git_zstream zstream;
+		int result;
+		size_t out_len;
+		unsigned char compressed[STREAM_BUFFER_SIZE * 2];
+
+		git_deflate_init_raw(&zstream, args->compression_level);
+
+		compressed_size = 0;
+		zstream.next_out = compressed;
+		zstream.avail_out = sizeof(compressed);
+
+		for (;;) {
+			readlen = read_istream(stream, buf, sizeof(buf));
+			if (readlen <= 0)
+				break;
+			crc = crc32(crc, buf, readlen);
+			if (is_binary == -1)
+				is_binary = entry_is_binary(args->repo->index,
+							    path_without_prefix,
+							    buf, readlen);
+
+			zstream.next_in = buf;
+			zstream.avail_in = readlen;
+			result = git_deflate(&zstream, 0);
+			if (result != Z_OK)
+				die(_("deflate error (%d)"), result);
+			out_len = zstream.next_out - compressed;
+
+			if (out_len > 0) {
+				write_or_die(1, compressed, out_len);
+				compressed_size += out_len;
+				zstream.next_out = compressed;
+				zstream.avail_out = sizeof(compressed);
+			}
+
+		}
+		close_istream(stream);
+		if (readlen)
+			return readlen;
+
+		zstream.next_in = buf;
+		zstream.avail_in = 0;
+		result = git_deflate(&zstream, Z_FINISH);
+		if (result != Z_STREAM_END)
+			die("deflate error (%d)", result);
+
+		git_deflate_end(&zstream);
+		out_len = zstream.next_out - compressed;
+		write_or_die(1, compressed, out_len);
+		compressed_size += out_len;
+		zip_offset += compressed_size;
+
+		write_zip_data_desc(size, compressed_size, crc);
+	} else if (compressed_size > 0) {
+		write_or_die(1, out, compressed_size);
+		zip_offset += compressed_size;
+	}
+
+	free(deflated);
+
+	if (compressed_size > 0xffffffff || size > 0xffffffff ||
+	    offset > 0xffffffff) {
+		if (compressed_size >= 0xffffffff)
+			zip64_dir_extra_payload_size += 8;
+		if (size >= 0xffffffff)
+			zip64_dir_extra_payload_size += 8;
+		if (offset >= 0xffffffff)
+			zip64_dir_extra_payload_size += 8;
+		zip_dir_extra_size += 2 + 2 + zip64_dir_extra_payload_size;
+	}
+
+	strbuf_add_le(&zip_dir, 4, 0x02014b50);	/* magic */
+	strbuf_add_le(&zip_dir, 2, creator_version);
+	strbuf_add_le(&zip_dir, 2, version_needed);
+	strbuf_add_le(&zip_dir, 2, flags);
+	strbuf_add_le(&zip_dir, 2, method);
+	strbuf_add_le(&zip_dir, 2, zip_time);
+	strbuf_add_le(&zip_dir, 2, zip_date);
+	strbuf_add_le(&zip_dir, 4, crc);
+	strbuf_add_le(&zip_dir, 4, clamp32(compressed_size));
+	strbuf_add_le(&zip_dir, 4, clamp32(size));
+	strbuf_add_le(&zip_dir, 2, pathlen);
+	strbuf_add_le(&zip_dir, 2, zip_dir_extra_size);
+	strbuf_add_le(&zip_dir, 2, 0);		/* comment length */
+	strbuf_add_le(&zip_dir, 2, 0);		/* disk */
+	strbuf_add_le(&zip_dir, 2, !is_binary);
+	strbuf_add_le(&zip_dir, 4, attr2);
+	strbuf_add_le(&zip_dir, 4, clamp32(offset));
+	strbuf_add(&zip_dir, path, pathlen);
+	strbuf_add(&zip_dir, &extra, ZIP_EXTRA_MTIME_SIZE);
+	if (zip64_dir_extra_payload_size) {
+		strbuf_add_le(&zip_dir, 2, 0x0001);	/* magic */
+		strbuf_add_le(&zip_dir, 2, zip64_dir_extra_payload_size);
+		if (size >= 0xffffffff)
+			strbuf_add_le(&zip_dir, 8, size);
+		if (compressed_size >= 0xffffffff)
+			strbuf_add_le(&zip_dir, 8, compressed_size);
+		if (offset >= 0xffffffff)
+			strbuf_add_le(&zip_dir, 8, offset);
+	}
+	zip_dir_entries++;
+
+	return 0;
+}
+
+static void write_zip64_trailer(void)
+{
+	struct zip64_dir_trailer trailer64;
+	struct zip64_dir_trailer_locator locator64;
+
+	copy_le32(trailer64.magic, 0x06064b50);
+	copy_le64(trailer64.record_size, ZIP64_DIR_TRAILER_RECORD_SIZE);
+	copy_le16(trailer64.creator_version, max_creator_version);
+	copy_le16(trailer64.version, 45);
+	copy_le32(trailer64.disk, 0);
+	copy_le32(trailer64.directory_start_disk, 0);
+	copy_le64(trailer64.entries_on_this_disk, zip_dir_entries);
+	copy_le64(trailer64.entries, zip_dir_entries);
+	copy_le64(trailer64.size, zip_dir.len);
+	copy_le64(trailer64.offset, zip_offset);
+
+	copy_le32(locator64.magic, 0x07064b50);
+	copy_le32(locator64.disk, 0);
+	copy_le64(locator64.offset, zip_offset + zip_dir.len);
+	copy_le32(locator64.number_of_disks, 1);
+
+	write_or_die(1, &trailer64, ZIP64_DIR_TRAILER_SIZE);
+	write_or_die(1, &locator64, ZIP64_DIR_TRAILER_LOCATOR_SIZE);
+}
+
+static void write_zip_trailer(const struct object_id *oid)
+{
+	struct zip_dir_trailer trailer;
+	int clamped = 0;
+
+	copy_le32(trailer.magic, 0x06054b50);
+	copy_le16(trailer.disk, 0);
+	copy_le16(trailer.directory_start_disk, 0);
+	copy_le16_clamp(trailer.entries_on_this_disk, zip_dir_entries,
+			&clamped);
+	copy_le16_clamp(trailer.entries, zip_dir_entries, &clamped);
+	copy_le32(trailer.size, zip_dir.len);
+	copy_le32_clamp(trailer.offset, zip_offset, &clamped);
+	copy_le16(trailer.comment_length, oid ? the_hash_algo->hexsz : 0);
+
+	write_or_die(1, zip_dir.buf, zip_dir.len);
+	if (clamped)
+		write_zip64_trailer();
+	write_or_die(1, &trailer, ZIP_DIR_TRAILER_SIZE);
+	if (oid)
+		write_or_die(1, oid_to_hex(oid), the_hash_algo->hexsz);
+}
+
+static void dos_time(timestamp_t *timestamp, int *dos_date, int *dos_time)
+{
+	time_t time;
+	struct tm tm;
+
+	if (date_overflows(*timestamp))
+		die(_("timestamp too large for this system: %"PRItime),
+		    *timestamp);
+	time = (time_t)*timestamp;
+	localtime_r(&time, &tm);
+	*timestamp = time;
+
+	*dos_date = tm.tm_mday + (tm.tm_mon + 1) * 32 +
+		    (tm.tm_year + 1900 - 1980) * 512;
+	*dos_time = tm.tm_sec / 2 + tm.tm_min * 32 + tm.tm_hour * 2048;
+}
+
+static int archive_zip_config(const char *var, const char *value,
+			      const struct config_context *ctx UNUSED,
+			      void *data UNUSED)
+{
+	return userdiff_config(var, value);
+}
+
+static int write_zip_archive(const struct archiver *ar UNUSED,
+			     struct archiver_args *args)
+{
+	int err;
+
+	git_config(archive_zip_config, NULL);
+
+	dos_time(&args->time, &zip_date, &zip_time);
+
+	strbuf_init(&zip_dir, 0);
+
+	err = write_archive_entries(args, write_zip_entry);
+	if (!err)
+		write_zip_trailer(args->commit_oid);
+
+	strbuf_release(&zip_dir);
+
+	return err;
+}
+
+static struct archiver zip_archiver = {
+	.name = "zip",
+	.write_archive = write_zip_archive,
+	.flags = ARCHIVER_WANT_COMPRESSION_LEVELS|ARCHIVER_REMOTE,
+};
+
+void init_zip_archiver(void)
+{
+	register_archiver(&zip_archiver);
+}
diff --git a/archive.c b/archive.c
new file mode 100644
index 0000000000..b9c200cba6
--- /dev/null
+++ b/archive.c
@@ -0,0 +1,809 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "config.h"
+#include "convert.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "path.h"
+#include "pretty.h"
+#include "setup.h"
+#include "refs.h"
+#include "object-store-ll.h"
+#include "commit.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "attr.h"
+#include "archive.h"
+#include "parse-options.h"
+#include "unpack-trees.h"
+#include "quote.h"
+
+static char const * const archive_usage[] = {
+	N_("git archive [<options>] <tree-ish> [<path>...]"),
+	"git archive --list",
+	N_("git archive --remote <repo> [--exec <cmd>] [<options>] <tree-ish> [<path>...]"),
+	N_("git archive --remote <repo> [--exec <cmd>] --list"),
+	NULL
+};
+
+static const struct archiver **archivers;
+static int nr_archivers;
+static int alloc_archivers;
+static int remote_allow_unreachable;
+
+void register_archiver(struct archiver *ar)
+{
+	ALLOC_GROW(archivers, nr_archivers + 1, alloc_archivers);
+	archivers[nr_archivers++] = ar;
+}
+
+void init_archivers(void)
+{
+	init_tar_archiver();
+	init_zip_archiver();
+}
+
+static void format_subst(const struct commit *commit,
+			 const char *src, size_t len,
+			 struct strbuf *buf, struct pretty_print_context *ctx)
+{
+	char *to_free = NULL;
+	struct strbuf fmt = STRBUF_INIT;
+
+	if (src == buf->buf)
+		to_free = strbuf_detach(buf, NULL);
+	for (;;) {
+		const char *b, *c;
+
+		b = memmem(src, len, "$Format:", 8);
+		if (!b)
+			break;
+		c = memchr(b + 8, '$', (src + len) - b - 8);
+		if (!c)
+			break;
+
+		strbuf_reset(&fmt);
+		strbuf_add(&fmt, b + 8, c - b - 8);
+
+		strbuf_add(buf, src, b - src);
+		repo_format_commit_message(the_repository, commit, fmt.buf,
+					   buf, ctx);
+		len -= c + 1 - src;
+		src  = c + 1;
+	}
+	strbuf_add(buf, src, len);
+	strbuf_release(&fmt);
+	free(to_free);
+}
+
+static void *object_file_to_archive(const struct archiver_args *args,
+				    const char *path,
+				    const struct object_id *oid,
+				    unsigned int mode,
+				    enum object_type *type,
+				    unsigned long *sizep)
+{
+	void *buffer;
+	const struct commit *commit = args->convert ? args->commit : NULL;
+	struct checkout_metadata meta;
+
+	init_checkout_metadata(&meta, args->refname,
+			       args->commit_oid ? args->commit_oid :
+			       (args->tree ? &args->tree->object.oid : NULL), oid);
+
+	path += args->baselen;
+	buffer = repo_read_object_file(the_repository, oid, type, sizep);
+	if (buffer && S_ISREG(mode)) {
+		struct strbuf buf = STRBUF_INIT;
+		size_t size = 0;
+
+		strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
+		convert_to_working_tree(args->repo->index, path, buf.buf, buf.len, &buf, &meta);
+		if (commit)
+			format_subst(commit, buf.buf, buf.len, &buf, args->pretty_ctx);
+		buffer = strbuf_detach(&buf, &size);
+		*sizep = size;
+	}
+
+	return buffer;
+}
+
+struct directory {
+	struct directory *up;
+	struct object_id oid;
+	int baselen, len;
+	unsigned mode;
+	char path[FLEX_ARRAY];
+};
+
+struct archiver_context {
+	struct archiver_args *args;
+	write_archive_entry_fn_t write_entry;
+	struct directory *bottom;
+};
+
+static const struct attr_check *get_archive_attrs(struct index_state *istate,
+						  const char *path)
+{
+	static struct attr_check *check;
+	if (!check)
+		check = attr_check_initl("export-ignore", "export-subst", NULL);
+	git_check_attr(istate, path, check);
+	return check;
+}
+
+static int check_attr_export_ignore(const struct attr_check *check)
+{
+	return check && ATTR_TRUE(check->items[0].value);
+}
+
+static int check_attr_export_subst(const struct attr_check *check)
+{
+	return check && ATTR_TRUE(check->items[1].value);
+}
+
+static int write_archive_entry(const struct object_id *oid, const char *base,
+		int baselen, const char *filename, unsigned mode,
+		void *context)
+{
+	static struct strbuf path = STRBUF_INIT;
+	struct archiver_context *c = context;
+	struct archiver_args *args = c->args;
+	write_archive_entry_fn_t write_entry = c->write_entry;
+	int err;
+	const char *path_without_prefix;
+	unsigned long size;
+	void *buffer;
+	enum object_type type;
+
+	args->convert = 0;
+	strbuf_reset(&path);
+	strbuf_grow(&path, PATH_MAX);
+	strbuf_add(&path, args->base, args->baselen);
+	strbuf_add(&path, base, baselen);
+	strbuf_addstr(&path, filename);
+	if (S_ISDIR(mode) || S_ISGITLINK(mode))
+		strbuf_addch(&path, '/');
+	path_without_prefix = path.buf + args->baselen;
+
+	if (!S_ISDIR(mode)) {
+		const struct attr_check *check;
+		check = get_archive_attrs(args->repo->index, path_without_prefix);
+		if (check_attr_export_ignore(check))
+			return 0;
+		args->convert = check_attr_export_subst(check);
+	}
+
+	if (args->prefix) {
+		static struct strbuf new_path = STRBUF_INIT;
+		static struct strbuf buf = STRBUF_INIT;
+		const char *rel;
+
+		rel = relative_path(path_without_prefix, args->prefix, &buf);
+
+		/*
+		 * We don't add an entry for the current working
+		 * directory when we are at the root; skip it also when
+		 * we're in a subdirectory or submodule.  Skip entries
+		 * higher up as well.
+		 */
+		if (!strcmp(rel, "./") || starts_with(rel, "../"))
+			return S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0;
+
+		/* rel can refer to path, so don't edit it in place */
+		strbuf_reset(&new_path);
+		strbuf_add(&new_path, args->base, args->baselen);
+		strbuf_addstr(&new_path, rel);
+		strbuf_swap(&path, &new_path);
+	}
+
+	if (args->verbose)
+		fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
+
+	if (S_ISDIR(mode) || S_ISGITLINK(mode)) {
+		err = write_entry(args, oid, path.buf, path.len, mode, NULL, 0);
+		if (err)
+			return err;
+		return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
+	}
+
+	/* Stream it? */
+	if (S_ISREG(mode) && !args->convert &&
+	    oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
+	    size > big_file_threshold)
+		return write_entry(args, oid, path.buf, path.len, mode, NULL, size);
+
+	buffer = object_file_to_archive(args, path.buf, oid, mode, &type, &size);
+	if (!buffer)
+		return error(_("cannot read '%s'"), oid_to_hex(oid));
+	err = write_entry(args, oid, path.buf, path.len, mode, buffer, size);
+	free(buffer);
+	return err;
+}
+
+static void queue_directory(const struct object_id *oid,
+		struct strbuf *base, const char *filename,
+		unsigned mode, struct archiver_context *c)
+{
+	struct directory *d;
+	size_t len = st_add4(base->len, 1, strlen(filename), 1);
+	d = xmalloc(st_add(sizeof(*d), len));
+	d->up	   = c->bottom;
+	d->baselen = base->len;
+	d->mode	   = mode;
+	c->bottom  = d;
+	d->len = xsnprintf(d->path, len, "%.*s%s/", (int)base->len, base->buf, filename);
+	oidcpy(&d->oid, oid);
+}
+
+static int write_directory(struct archiver_context *c)
+{
+	struct directory *d = c->bottom;
+	int ret;
+
+	if (!d)
+		return 0;
+	c->bottom = d->up;
+	d->path[d->len - 1] = '\0'; /* no trailing slash */
+	ret =
+		write_directory(c) ||
+		write_archive_entry(&d->oid, d->path, d->baselen,
+				    d->path + d->baselen, d->mode,
+				    c) != READ_TREE_RECURSIVE;
+	free(d);
+	return ret ? -1 : 0;
+}
+
+static int queue_or_write_archive_entry(const struct object_id *oid,
+		struct strbuf *base, const char *filename,
+		unsigned mode, void *context)
+{
+	struct archiver_context *c = context;
+
+	while (c->bottom &&
+	       !(base->len >= c->bottom->len &&
+		 !strncmp(base->buf, c->bottom->path, c->bottom->len))) {
+		struct directory *next = c->bottom->up;
+		free(c->bottom);
+		c->bottom = next;
+	}
+
+	if (S_ISDIR(mode)) {
+		size_t baselen = base->len;
+		const struct attr_check *check;
+
+		/* Borrow base, but restore its original value when done. */
+		strbuf_addstr(base, filename);
+		strbuf_addch(base, '/');
+		check = get_archive_attrs(c->args->repo->index, base->buf);
+		strbuf_setlen(base, baselen);
+
+		if (check_attr_export_ignore(check))
+			return 0;
+		queue_directory(oid, base, filename, mode, c);
+		return READ_TREE_RECURSIVE;
+	}
+
+	if (write_directory(c))
+		return -1;
+	return write_archive_entry(oid, base->buf, base->len, filename, mode,
+				   context);
+}
+
+struct extra_file_info {
+	char *base;
+	struct stat stat;
+	void *content;
+};
+
+int write_archive_entries(struct archiver_args *args,
+		write_archive_entry_fn_t write_entry)
+{
+	struct archiver_context context;
+	int err;
+	struct strbuf path_in_archive = STRBUF_INIT;
+	struct strbuf content = STRBUF_INIT;
+	struct object_id fake_oid;
+	int i;
+
+	oidcpy(&fake_oid, null_oid());
+
+	if (args->baselen > 0 && args->base[args->baselen - 1] == '/') {
+		size_t len = args->baselen;
+
+		while (len > 1 && args->base[len - 2] == '/')
+			len--;
+		if (args->verbose)
+			fprintf(stderr, "%.*s\n", (int)len, args->base);
+		err = write_entry(args, &args->tree->object.oid, args->base,
+				  len, 040777, NULL, 0);
+		if (err)
+			return err;
+	}
+
+	memset(&context, 0, sizeof(context));
+	context.args = args;
+	context.write_entry = write_entry;
+
+	err = read_tree(args->repo, args->tree,
+			&args->pathspec,
+			queue_or_write_archive_entry,
+			&context);
+	if (err == READ_TREE_RECURSIVE)
+		err = 0;
+	while (context.bottom) {
+		struct directory *next = context.bottom->up;
+		free(context.bottom);
+		context.bottom = next;
+	}
+
+	for (i = 0; i < args->extra_files.nr; i++) {
+		struct string_list_item *item = args->extra_files.items + i;
+		char *path = item->string;
+		struct extra_file_info *info = item->util;
+
+		put_be64(fake_oid.hash, i + 1);
+
+		if (!info->content) {
+			strbuf_reset(&path_in_archive);
+			if (info->base)
+				strbuf_addstr(&path_in_archive, info->base);
+			strbuf_addstr(&path_in_archive, basename(path));
+
+			strbuf_reset(&content);
+			if (strbuf_read_file(&content, path, info->stat.st_size) < 0)
+				err = error_errno(_("cannot read '%s'"), path);
+			else
+				err = write_entry(args, &fake_oid, path_in_archive.buf,
+						  path_in_archive.len,
+						  canon_mode(info->stat.st_mode),
+						  content.buf, content.len);
+		} else {
+			err = write_entry(args, &fake_oid,
+					  path, strlen(path),
+					  canon_mode(info->stat.st_mode),
+					  info->content, info->stat.st_size);
+		}
+
+		if (err)
+			break;
+	}
+	strbuf_release(&path_in_archive);
+	strbuf_release(&content);
+
+	return err;
+}
+
+static const struct archiver *lookup_archiver(const char *name)
+{
+	int i;
+
+	if (!name)
+		return NULL;
+
+	for (i = 0; i < nr_archivers; i++) {
+		if (!strcmp(name, archivers[i]->name))
+			return archivers[i];
+	}
+	return NULL;
+}
+
+struct path_exists_context {
+	struct pathspec pathspec;
+	struct archiver_args *args;
+};
+
+static int reject_entry(const struct object_id *oid UNUSED,
+			struct strbuf *base,
+			const char *filename, unsigned mode,
+			void *context)
+{
+	int ret = -1;
+	struct path_exists_context *ctx = context;
+
+	if (S_ISDIR(mode)) {
+		struct strbuf sb = STRBUF_INIT;
+		strbuf_addbuf(&sb, base);
+		strbuf_addstr(&sb, filename);
+		if (!match_pathspec(ctx->args->repo->index,
+				    &ctx->pathspec,
+				    sb.buf, sb.len, 0, NULL, 1))
+			ret = READ_TREE_RECURSIVE;
+		strbuf_release(&sb);
+	}
+	return ret;
+}
+
+static int reject_outside(const struct object_id *oid UNUSED,
+			  struct strbuf *base, const char *filename,
+			  unsigned mode, void *context)
+{
+	struct archiver_args *args = context;
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf path = STRBUF_INIT;
+	int ret = 0;
+
+	if (S_ISDIR(mode))
+		return READ_TREE_RECURSIVE;
+
+	strbuf_addbuf(&path, base);
+	strbuf_addstr(&path, filename);
+	if (starts_with(relative_path(path.buf, args->prefix, &buf), "../"))
+		ret = -1;
+	strbuf_release(&buf);
+	strbuf_release(&path);
+	return ret;
+}
+
+static int path_exists(struct archiver_args *args, const char *path)
+{
+	const char *paths[] = { path, NULL };
+	struct path_exists_context ctx;
+	int ret;
+
+	ctx.args = args;
+	parse_pathspec(&ctx.pathspec, 0, PATHSPEC_PREFER_CWD,
+		       args->prefix, paths);
+	ctx.pathspec.recursive = 1;
+	if (args->prefix && read_tree(args->repo, args->tree, &ctx.pathspec,
+				      reject_outside, args))
+		die(_("pathspec '%s' matches files outside the "
+		      "current directory"), path);
+	ret = read_tree(args->repo, args->tree,
+			&ctx.pathspec,
+			reject_entry, &ctx);
+	clear_pathspec(&ctx.pathspec);
+	return ret != 0;
+}
+
+static void parse_pathspec_arg(const char **pathspec,
+		struct archiver_args *ar_args)
+{
+	/*
+	 * must be consistent with parse_pathspec in path_exists()
+	 * Also if pathspec patterns are dependent, we're in big
+	 * trouble as we test each one separately
+	 */
+	parse_pathspec(&ar_args->pathspec, 0, PATHSPEC_PREFER_CWD,
+		       ar_args->prefix, pathspec);
+	ar_args->pathspec.recursive = 1;
+	if (pathspec) {
+		while (*pathspec) {
+			if (**pathspec && !path_exists(ar_args, *pathspec))
+				die(_("pathspec '%s' did not match any files"), *pathspec);
+			pathspec++;
+		}
+	}
+}
+
+static void parse_treeish_arg(const char **argv,
+			      struct archiver_args *ar_args, int remote)
+{
+	const char *name = argv[0];
+	const struct object_id *commit_oid;
+	time_t archive_time;
+	struct tree *tree;
+	const struct commit *commit;
+	struct object_id oid;
+	char *ref = NULL;
+
+	/* Remotes are only allowed to fetch actual refs */
+	if (remote && !remote_allow_unreachable) {
+		const char *colon = strchrnul(name, ':');
+		int refnamelen = colon - name;
+
+		if (!repo_dwim_ref(the_repository, name, refnamelen, &oid, &ref, 0))
+			die(_("no such ref: %.*s"), refnamelen, name);
+	} else {
+		repo_dwim_ref(the_repository, name, strlen(name), &oid, &ref,
+			      0);
+	}
+
+	if (repo_get_oid(the_repository, name, &oid))
+		die(_("not a valid object name: %s"), name);
+
+	commit = lookup_commit_reference_gently(ar_args->repo, &oid, 1);
+	if (commit) {
+		commit_oid = &commit->object.oid;
+		archive_time = commit->date;
+	} else {
+		commit_oid = NULL;
+		archive_time = time(NULL);
+	}
+	if (ar_args->mtime_option)
+		archive_time = approxidate(ar_args->mtime_option);
+
+	tree = parse_tree_indirect(&oid);
+	if (!tree)
+		die(_("not a tree object: %s"), oid_to_hex(&oid));
+
+	/*
+	 * Setup index and instruct attr to read index only
+	 */
+	if (!ar_args->worktree_attributes) {
+		struct unpack_trees_options opts;
+		struct tree_desc t;
+
+		memset(&opts, 0, sizeof(opts));
+		opts.index_only = 1;
+		opts.head_idx = -1;
+		opts.src_index = ar_args->repo->index;
+		opts.dst_index = ar_args->repo->index;
+		opts.fn = oneway_merge;
+		init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
+		if (unpack_trees(1, &t, &opts))
+			die(_("failed to unpack tree object %s"),
+			    oid_to_hex(&tree->object.oid));
+
+		git_attr_set_direction(GIT_ATTR_INDEX);
+	}
+
+	ar_args->refname = ref;
+	ar_args->tree = tree;
+	ar_args->commit_oid = commit_oid;
+	ar_args->commit = commit;
+	ar_args->time = archive_time;
+}
+
+static void extra_file_info_clear(void *util, const char *str UNUSED)
+{
+	struct extra_file_info *info = util;
+	free(info->base);
+	free(info->content);
+	free(info);
+}
+
+static int add_file_cb(const struct option *opt, const char *arg, int unset)
+{
+	struct archiver_args *args = opt->value;
+	const char **basep = (const char **)opt->defval;
+	const char *base = *basep;
+	char *path;
+	struct string_list_item *item;
+	struct extra_file_info *info;
+
+	if (unset) {
+		string_list_clear_func(&args->extra_files,
+				       extra_file_info_clear);
+		return 0;
+	}
+
+	if (!arg)
+		return -1;
+
+	info = xmalloc(sizeof(*info));
+	info->base = xstrdup_or_null(base);
+
+	if (!strcmp(opt->long_name, "add-file")) {
+		path = prefix_filename(args->prefix, arg);
+		if (stat(path, &info->stat))
+			die(_("File not found: %s"), path);
+		if (!S_ISREG(info->stat.st_mode))
+			die(_("Not a regular file: %s"), path);
+		info->content = NULL; /* read the file later */
+	} else if (!strcmp(opt->long_name, "add-virtual-file")) {
+		struct strbuf buf = STRBUF_INIT;
+		const char *p = arg;
+
+		if (*p != '"')
+			p = strchr(p, ':');
+		else if (unquote_c_style(&buf, p, &p) < 0)
+			die(_("unclosed quote: '%s'"), arg);
+
+		if (!p || *p != ':')
+			die(_("missing colon: '%s'"), arg);
+
+		if (p == arg)
+			die(_("empty file name: '%s'"), arg);
+
+		path = buf.len ?
+			strbuf_detach(&buf, NULL) : xstrndup(arg, p - arg);
+
+		if (args->prefix) {
+			char *save = path;
+			path = prefix_filename(args->prefix, path);
+			free(save);
+		}
+		memset(&info->stat, 0, sizeof(info->stat));
+		info->stat.st_mode = S_IFREG | 0644;
+		info->content = xstrdup(p + 1);
+		info->stat.st_size = strlen(info->content);
+	} else {
+		BUG("add_file_cb() called for %s", opt->long_name);
+	}
+	item = string_list_append_nodup(&args->extra_files, path);
+	item->util = info;
+
+	return 0;
+}
+
+static int number_callback(const struct option *opt, const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+	*(int *)opt->value = strtol(arg, NULL, 10);
+	return 0;
+}
+
+static int parse_archive_args(int argc, const char **argv,
+		const struct archiver **ar, struct archiver_args *args,
+		const char *name_hint, int is_remote)
+{
+	const char *format = NULL;
+	const char *base = NULL;
+	const char *remote = NULL;
+	const char *exec = NULL;
+	const char *output = NULL;
+	const char *mtime_option = NULL;
+	int compression_level = -1;
+	int verbose = 0;
+	int i;
+	int list = 0;
+	int worktree_attributes = 0;
+	struct option opts[] = {
+		OPT_GROUP(""),
+		OPT_STRING(0, "format", &format, N_("fmt"), N_("archive format")),
+		OPT_STRING(0, "prefix", &base, N_("prefix"),
+			N_("prepend prefix to each pathname in the archive")),
+		{ OPTION_CALLBACK, 0, "add-file", args, N_("file"),
+		  N_("add untracked file to archive"), 0, add_file_cb,
+		  (intptr_t)&base },
+		{ OPTION_CALLBACK, 0, "add-virtual-file", args,
+		  N_("path:content"), N_("add untracked file to archive"), 0,
+		  add_file_cb, (intptr_t)&base },
+		OPT_STRING('o', "output", &output, N_("file"),
+			N_("write the archive to this file")),
+		OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
+			N_("read .gitattributes in working directory")),
+		OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
+		{ OPTION_STRING, 0, "mtime", &mtime_option, N_("time"),
+		  N_("set modification time of archive entries"),
+		  PARSE_OPT_NONEG },
+		OPT_NUMBER_CALLBACK(&compression_level,
+			N_("set compression level"), number_callback),
+		OPT_GROUP(""),
+		OPT_BOOL('l', "list", &list,
+			N_("list supported archive formats")),
+		OPT_GROUP(""),
+		OPT_STRING(0, "remote", &remote, N_("repo"),
+			N_("retrieve the archive from remote repository <repo>")),
+		OPT_STRING(0, "exec", &exec, N_("command"),
+			N_("path to the remote git-upload-archive command")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, NULL, opts, archive_usage, 0);
+
+	if (remote)
+		die(_("Unexpected option --remote"));
+	if (exec)
+		die(_("the option '%s' requires '%s'"), "--exec", "--remote");
+	if (output)
+		die(_("Unexpected option --output"));
+	if (is_remote && args->extra_files.nr)
+		die(_("options '%s' and '%s' cannot be used together"), "--add-file", "--remote");
+
+	if (!base)
+		base = "";
+
+	if (list) {
+		if (argc)
+			die(_("extra command line parameter '%s'"), *argv);
+		for (i = 0; i < nr_archivers; i++)
+			if (!is_remote || archivers[i]->flags & ARCHIVER_REMOTE)
+				printf("%s\n", archivers[i]->name);
+		exit(0);
+	}
+
+	if (!format && name_hint)
+		format = archive_format_from_filename(name_hint);
+	if (!format)
+		format = "tar";
+
+	/* We need at least one parameter -- tree-ish */
+	if (argc < 1)
+		usage_with_options(archive_usage, opts);
+	*ar = lookup_archiver(format);
+	if (!*ar || (is_remote && !((*ar)->flags & ARCHIVER_REMOTE)))
+		die(_("Unknown archive format '%s'"), format);
+
+	args->compression_level = Z_DEFAULT_COMPRESSION;
+	if (compression_level != -1) {
+		int levels_ok = (*ar)->flags & ARCHIVER_WANT_COMPRESSION_LEVELS;
+		int high_ok = (*ar)->flags & ARCHIVER_HIGH_COMPRESSION_LEVELS;
+		if (levels_ok && (compression_level <= 9 || high_ok))
+			args->compression_level = compression_level;
+		else {
+			die(_("Argument not supported for format '%s': -%d"),
+					format, compression_level);
+		}
+	}
+	args->verbose = verbose;
+	args->base = base;
+	args->baselen = strlen(base);
+	args->worktree_attributes = worktree_attributes;
+	args->mtime_option = mtime_option;
+
+	return argc;
+}
+
+int write_archive(int argc, const char **argv, const char *prefix,
+		  struct repository *repo,
+		  const char *name_hint, int remote)
+{
+	const struct archiver *ar = NULL;
+	struct pretty_print_describe_status describe_status = {0};
+	struct pretty_print_context ctx = {0};
+	struct archiver_args args;
+	const char **argv_copy;
+	int rc;
+
+	git_config_get_bool("uploadarchive.allowunreachable", &remote_allow_unreachable);
+	git_config(git_default_config, NULL);
+
+	describe_status.max_invocations = 1;
+	ctx.date_mode.type = DATE_NORMAL;
+	ctx.abbrev = DEFAULT_ABBREV;
+	ctx.describe_status = &describe_status;
+	args.pretty_ctx = &ctx;
+	args.repo = repo;
+	args.prefix = prefix;
+	string_list_init_dup(&args.extra_files);
+
+	/*
+	 * `parse_archive_args()` modifies contents of `argv`, which is what we
+	 * want. Our callers may not want it though, so we create a copy here.
+	 */
+	DUP_ARRAY(argv_copy, argv, argc);
+	argv = argv_copy;
+
+	argc = parse_archive_args(argc, argv, &ar, &args, name_hint, remote);
+	if (!startup_info->have_repository) {
+		/*
+		 * We know this will die() with an error, so we could just
+		 * die ourselves; but its error message will be more specific
+		 * than what we could write here.
+		 */
+		setup_git_directory();
+	}
+
+	parse_treeish_arg(argv, &args, remote);
+	parse_pathspec_arg(argv + 1, &args);
+
+	rc = ar->write_archive(ar, &args);
+
+	string_list_clear_func(&args.extra_files, extra_file_info_clear);
+	free(args.refname);
+	clear_pathspec(&args.pathspec);
+	free(argv_copy);
+
+	return rc;
+}
+
+static int match_extension(const char *filename, const char *ext)
+{
+	int prefixlen = strlen(filename) - strlen(ext);
+
+	/*
+	 * We need 1 character for the '.', and 1 character to ensure that the
+	 * prefix is non-empty (k.e., we don't match .tar.gz with no actual
+	 * filename).
+	 */
+	if (prefixlen < 2 || filename[prefixlen - 1] != '.')
+		return 0;
+	return !strcmp(filename + prefixlen, ext);
+}
+
+const char *archive_format_from_filename(const char *filename)
+{
+	int i;
+
+	for (i = 0; i < nr_archivers; i++)
+		if (match_extension(filename, archivers[i]->name))
+			return archivers[i]->name;
+	return NULL;
+}
diff --git a/archive.h b/archive.h
new file mode 100644
index 0000000000..bbe65ba0f9
--- /dev/null
+++ b/archive.h
@@ -0,0 +1,63 @@
+#ifndef ARCHIVE_H
+#define ARCHIVE_H
+
+#include "pathspec.h"
+#include "string-list.h"
+
+struct repository;
+struct pretty_print_context;
+
+struct archiver_args {
+	struct repository *repo;
+	char *refname;
+	const char *prefix;
+	const char *base;
+	size_t baselen;
+	struct tree *tree;
+	const struct object_id *commit_oid;
+	const struct commit *commit;
+	const char *mtime_option;
+	timestamp_t time;
+	struct pathspec pathspec;
+	unsigned int verbose : 1;
+	unsigned int worktree_attributes : 1;
+	unsigned int convert : 1;
+	int compression_level;
+	struct string_list extra_files;
+	struct pretty_print_context *pretty_ctx;
+};
+
+/* main api */
+
+int write_archive(int argc, const char **argv, const char *prefix,
+		  struct repository *repo,
+		  const char *name_hint, int remote);
+
+const char *archive_format_from_filename(const char *filename);
+
+/* archive backend stuff */
+
+#define ARCHIVER_WANT_COMPRESSION_LEVELS 1
+#define ARCHIVER_REMOTE 2
+#define ARCHIVER_HIGH_COMPRESSION_LEVELS 4
+struct archiver {
+	const char *name;
+	int (*write_archive)(const struct archiver *, struct archiver_args *);
+	unsigned flags;
+	char *filter_command;
+};
+void register_archiver(struct archiver *);
+
+void init_tar_archiver(void);
+void init_zip_archiver(void);
+void init_archivers(void);
+
+typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
+					const struct object_id *oid,
+					const char *path, size_t pathlen,
+					unsigned int mode,
+					void *buffer, unsigned long size);
+
+int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
+
+#endif	/* ARCHIVE_H */
diff --git a/attr.c b/attr.c
new file mode 100644
index 0000000000..0bd2750528
--- /dev/null
+++ b/attr.c
@@ -0,0 +1,1348 @@
+/*
+ * Handle git attributes.  See gitattributes(5) for a description of
+ * the file syntax, and attr.h for a description of the API.
+ *
+ * One basic design decision here is that we are not going to support
+ * an insanely large number of attributes.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "environment.h"
+#include "exec-cmd.h"
+#include "attr.h"
+#include "dir.h"
+#include "gettext.h"
+#include "path.h"
+#include "utf8.h"
+#include "quote.h"
+#include "read-cache-ll.h"
+#include "refs.h"
+#include "revision.h"
+#include "object-store-ll.h"
+#include "setup.h"
+#include "thread-utils.h"
+#include "tree-walk.h"
+#include "object-name.h"
+
+char *git_attr_tree;
+
+const char git_attr__true[] = "(builtin)true";
+const char git_attr__false[] = "\0(builtin)false";
+static const char git_attr__unknown[] = "(builtin)unknown";
+#define ATTR__TRUE git_attr__true
+#define ATTR__FALSE git_attr__false
+#define ATTR__UNSET NULL
+#define ATTR__UNKNOWN git_attr__unknown
+
+struct git_attr {
+	unsigned int attr_nr; /* unique attribute number */
+	char name[FLEX_ARRAY]; /* attribute name */
+};
+
+const char *git_attr_name(const struct git_attr *attr)
+{
+	return attr->name;
+}
+
+struct attr_hashmap {
+	struct hashmap map;
+	pthread_mutex_t mutex;
+};
+
+static inline void hashmap_lock(struct attr_hashmap *map)
+{
+	pthread_mutex_lock(&map->mutex);
+}
+
+static inline void hashmap_unlock(struct attr_hashmap *map)
+{
+	pthread_mutex_unlock(&map->mutex);
+}
+
+/* The container for objects stored in "struct attr_hashmap" */
+struct attr_hash_entry {
+	struct hashmap_entry ent;
+	const char *key; /* the key; memory should be owned by value */
+	size_t keylen; /* length of the key */
+	void *value; /* the stored value */
+};
+
+/* attr_hashmap comparison function */
+static int attr_hash_entry_cmp(const void *cmp_data UNUSED,
+			       const struct hashmap_entry *eptr,
+			       const struct hashmap_entry *entry_or_key,
+			       const void *keydata UNUSED)
+{
+	const struct attr_hash_entry *a, *b;
+
+	a = container_of(eptr, const struct attr_hash_entry, ent);
+	b = container_of(entry_or_key, const struct attr_hash_entry, ent);
+	return (a->keylen != b->keylen) || strncmp(a->key, b->key, a->keylen);
+}
+
+/*
+ * The global dictionary of all interned attributes.  This
+ * is a singleton object which is shared between threads.
+ * Access to this dictionary must be surrounded with a mutex.
+ */
+static struct attr_hashmap g_attr_hashmap = {
+	.map = HASHMAP_INIT(attr_hash_entry_cmp, NULL),
+};
+
+/*
+ * Retrieve the 'value' stored in a hashmap given the provided 'key'.
+ * If there is no matching entry, return NULL.
+ */
+static void *attr_hashmap_get(struct attr_hashmap *map,
+			      const char *key, size_t keylen)
+{
+	struct attr_hash_entry k;
+	struct attr_hash_entry *e;
+
+	hashmap_entry_init(&k.ent, memhash(key, keylen));
+	k.key = key;
+	k.keylen = keylen;
+	e = hashmap_get_entry(&map->map, &k, ent, NULL);
+
+	return e ? e->value : NULL;
+}
+
+/* Add 'value' to a hashmap based on the provided 'key'. */
+static void attr_hashmap_add(struct attr_hashmap *map,
+			     const char *key, size_t keylen,
+			     void *value)
+{
+	struct attr_hash_entry *e;
+
+	e = xmalloc(sizeof(struct attr_hash_entry));
+	hashmap_entry_init(&e->ent, memhash(key, keylen));
+	e->key = key;
+	e->keylen = keylen;
+	e->value = value;
+
+	hashmap_add(&map->map, &e->ent);
+}
+
+struct all_attrs_item {
+	const struct git_attr *attr;
+	const char *value;
+	/*
+	 * If 'macro' is non-NULL, indicates that 'attr' is a macro based on
+	 * the current attribute stack and contains a pointer to the match_attr
+	 * definition of the macro
+	 */
+	const struct match_attr *macro;
+};
+
+/*
+ * Reallocate and reinitialize the array of all attributes (which is used in
+ * the attribute collection process) in 'check' based on the global dictionary
+ * of attributes.
+ */
+static void all_attrs_init(struct attr_hashmap *map, struct attr_check *check)
+{
+	int i;
+	unsigned int size;
+
+	hashmap_lock(map);
+
+	size = hashmap_get_size(&map->map);
+	if (size < check->all_attrs_nr)
+		BUG("interned attributes shouldn't be deleted");
+
+	/*
+	 * If the number of attributes in the global dictionary has increased
+	 * (or this attr_check instance doesn't have an initialized all_attrs
+	 * field), reallocate the provided attr_check instance's all_attrs
+	 * field and fill each entry with its corresponding git_attr.
+	 */
+	if (size != check->all_attrs_nr) {
+		struct attr_hash_entry *e;
+		struct hashmap_iter iter;
+
+		REALLOC_ARRAY(check->all_attrs, size);
+		check->all_attrs_nr = size;
+
+		hashmap_for_each_entry(&map->map, &iter, e,
+					ent /* member name */) {
+			const struct git_attr *a = e->value;
+			check->all_attrs[a->attr_nr].attr = a;
+		}
+	}
+
+	hashmap_unlock(map);
+
+	/*
+	 * Re-initialize every entry in check->all_attrs.
+	 * This re-initialization can live outside of the locked region since
+	 * the attribute dictionary is no longer being accessed.
+	 */
+	for (i = 0; i < check->all_attrs_nr; i++) {
+		check->all_attrs[i].value = ATTR__UNKNOWN;
+		check->all_attrs[i].macro = NULL;
+	}
+}
+
+/*
+ * Attribute name cannot begin with "builtin_" which
+ * is a reserved namespace for built in attributes values.
+ */
+static int attr_name_reserved(const char *name)
+{
+	return starts_with(name, "builtin_");
+}
+
+static int attr_name_valid(const char *name, size_t namelen)
+{
+	/*
+	 * Attribute name cannot begin with '-' and must consist of
+	 * characters from [-A-Za-z0-9_.].
+	 */
+	if (namelen <= 0 || *name == '-')
+		return 0;
+	while (namelen--) {
+		char ch = *name++;
+		if (! (ch == '-' || ch == '.' || ch == '_' ||
+		       ('0' <= ch && ch <= '9') ||
+		       ('a' <= ch && ch <= 'z') ||
+		       ('A' <= ch && ch <= 'Z')) )
+			return 0;
+	}
+	return 1;
+}
+
+static void report_invalid_attr(const char *name, size_t len,
+				const char *src, int lineno)
+{
+	struct strbuf err = STRBUF_INIT;
+	strbuf_addf(&err, _("%.*s is not a valid attribute name"),
+		    (int) len, name);
+	fprintf(stderr, "%s: %s:%d\n", err.buf, src, lineno);
+	strbuf_release(&err);
+}
+
+/*
+ * Given a 'name', lookup and return the corresponding attribute in the global
+ * dictionary.  If no entry is found, create a new attribute and store it in
+ * the dictionary.
+ */
+static const struct git_attr *git_attr_internal(const char *name, size_t namelen)
+{
+	struct git_attr *a;
+
+	if (!attr_name_valid(name, namelen))
+		return NULL;
+
+	hashmap_lock(&g_attr_hashmap);
+
+	a = attr_hashmap_get(&g_attr_hashmap, name, namelen);
+
+	if (!a) {
+		FLEX_ALLOC_MEM(a, name, name, namelen);
+		a->attr_nr = hashmap_get_size(&g_attr_hashmap.map);
+
+		attr_hashmap_add(&g_attr_hashmap, a->name, namelen, a);
+		if (a->attr_nr != hashmap_get_size(&g_attr_hashmap.map) - 1)
+			die(_("unable to add additional attribute"));
+	}
+
+	hashmap_unlock(&g_attr_hashmap);
+
+	return a;
+}
+
+const struct git_attr *git_attr(const char *name)
+{
+	return git_attr_internal(name, strlen(name));
+}
+
+static const char blank[] = " \t\r\n";
+
+/* Flags usable in read_attr() and parse_attr_line() family of functions. */
+#define READ_ATTR_MACRO_OK (1<<0)
+#define READ_ATTR_NOFOLLOW (1<<1)
+
+/*
+ * Parse a whitespace-delimited attribute state (i.e., "attr",
+ * "-attr", "!attr", or "attr=value") from the string starting at src.
+ * If e is not NULL, write the results to *e.  Return a pointer to the
+ * remainder of the string (with leading whitespace removed), or NULL
+ * if there was an error.
+ */
+static const char *parse_attr(const char *src, int lineno, const char *cp,
+			      struct attr_state *e)
+{
+	const char *ep, *equals;
+	size_t len;
+
+	ep = cp + strcspn(cp, blank);
+	equals = strchr(cp, '=');
+	if (equals && ep < equals)
+		equals = NULL;
+	if (equals)
+		len = equals - cp;
+	else
+		len = ep - cp;
+	if (!e) {
+		if (*cp == '-' || *cp == '!') {
+			cp++;
+			len--;
+		}
+		if (!attr_name_valid(cp, len) || attr_name_reserved(cp)) {
+			report_invalid_attr(cp, len, src, lineno);
+			return NULL;
+		}
+	} else {
+		/*
+		 * As this function is always called twice, once with
+		 * e == NULL in the first pass and then e != NULL in
+		 * the second pass, no need for attr_name_valid()
+		 * check here.
+		 */
+		if (*cp == '-' || *cp == '!') {
+			e->setto = (*cp == '-') ? ATTR__FALSE : ATTR__UNSET;
+			cp++;
+			len--;
+		}
+		else if (!equals)
+			e->setto = ATTR__TRUE;
+		else {
+			e->setto = xmemdupz(equals + 1, ep - equals - 1);
+		}
+		e->attr = git_attr_internal(cp, len);
+	}
+	return ep + strspn(ep, blank);
+}
+
+struct match_attr *parse_attr_line(const char *line, const char *src,
+				   int lineno, unsigned flags)
+{
+	size_t namelen, num_attr, i;
+	const char *cp, *name, *states;
+	struct match_attr *res = NULL;
+	int is_macro;
+	struct strbuf pattern = STRBUF_INIT;
+
+	cp = line + strspn(line, blank);
+	if (!*cp || *cp == '#')
+		return NULL;
+	name = cp;
+
+	if (strlen(line) >= ATTR_MAX_LINE_LENGTH) {
+		warning(_("ignoring overly long attributes line %d"), lineno);
+		return NULL;
+	}
+
+	if (*cp == '"' && !unquote_c_style(&pattern, name, &states)) {
+		name = pattern.buf;
+		namelen = pattern.len;
+	} else {
+		namelen = strcspn(name, blank);
+		states = name + namelen;
+	}
+
+	if (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen &&
+	    starts_with(name, ATTRIBUTE_MACRO_PREFIX)) {
+		if (!(flags & READ_ATTR_MACRO_OK)) {
+			fprintf_ln(stderr, _("%s not allowed: %s:%d"),
+				   name, src, lineno);
+			goto fail_return;
+		}
+		is_macro = 1;
+		name += strlen(ATTRIBUTE_MACRO_PREFIX);
+		name += strspn(name, blank);
+		namelen = strcspn(name, blank);
+		if (!attr_name_valid(name, namelen) || attr_name_reserved(name)) {
+			report_invalid_attr(name, namelen, src, lineno);
+			goto fail_return;
+		}
+	}
+	else
+		is_macro = 0;
+
+	states += strspn(states, blank);
+
+	/* First pass to count the attr_states */
+	for (cp = states, num_attr = 0; *cp; num_attr++) {
+		cp = parse_attr(src, lineno, cp, NULL);
+		if (!cp)
+			goto fail_return;
+	}
+
+	res = xcalloc(1, st_add3(sizeof(*res),
+				 st_mult(sizeof(struct attr_state), num_attr),
+				 is_macro ? 0 : namelen + 1));
+	if (is_macro) {
+		res->u.attr = git_attr_internal(name, namelen);
+	} else {
+		char *p = (char *)&(res->state[num_attr]);
+		memcpy(p, name, namelen);
+		res->u.pat.pattern = p;
+		parse_path_pattern(&res->u.pat.pattern,
+				      &res->u.pat.patternlen,
+				      &res->u.pat.flags,
+				      &res->u.pat.nowildcardlen);
+		if (res->u.pat.flags & PATTERN_FLAG_NEGATIVE) {
+			warning(_("Negative patterns are ignored in git attributes\n"
+				  "Use '\\!' for literal leading exclamation."));
+			goto fail_return;
+		}
+	}
+	res->is_macro = is_macro;
+	res->num_attr = num_attr;
+
+	/* Second pass to fill the attr_states */
+	for (cp = states, i = 0; *cp; i++) {
+		cp = parse_attr(src, lineno, cp, &(res->state[i]));
+	}
+
+	strbuf_release(&pattern);
+	return res;
+
+fail_return:
+	strbuf_release(&pattern);
+	free(res);
+	return NULL;
+}
+
+/*
+ * Like info/exclude and .gitignore, the attribute information can
+ * come from many places.
+ *
+ * (1) .gitattributes file of the same directory;
+ * (2) .gitattributes file of the parent directory if (1) does not have
+ *      any match; this goes recursively upwards, just like .gitignore.
+ * (3) $GIT_DIR/info/attributes, which overrides both of the above.
+ *
+ * In the same file, later entries override the earlier match, so in the
+ * global list, we would have entries from info/attributes the earliest
+ * (reading the file from top to bottom), .gitattributes of the root
+ * directory (again, reading the file from top to bottom) down to the
+ * current directory, and then scan the list backwards to find the first match.
+ * This is exactly the same as what is_excluded() does in dir.c to deal with
+ * .gitignore file and info/excludes file as a fallback.
+ */
+
+struct attr_stack {
+	struct attr_stack *prev;
+	char *origin;
+	size_t originlen;
+	unsigned num_matches;
+	unsigned alloc;
+	struct match_attr **attrs;
+};
+
+static void attr_stack_free(struct attr_stack *e)
+{
+	unsigned i;
+	free(e->origin);
+	for (i = 0; i < e->num_matches; i++) {
+		struct match_attr *a = e->attrs[i];
+		size_t j;
+
+		for (j = 0; j < a->num_attr; j++) {
+			const char *setto = a->state[j].setto;
+			if (setto == ATTR__TRUE ||
+			    setto == ATTR__FALSE ||
+			    setto == ATTR__UNSET ||
+			    setto == ATTR__UNKNOWN)
+				;
+			else
+				free((char *) setto);
+		}
+		free(a);
+	}
+	free(e->attrs);
+	free(e);
+}
+
+static void drop_attr_stack(struct attr_stack **stack)
+{
+	while (*stack) {
+		struct attr_stack *elem = *stack;
+		*stack = elem->prev;
+		attr_stack_free(elem);
+	}
+}
+
+/* List of all attr_check structs; access should be surrounded by mutex */
+static struct check_vector {
+	size_t nr;
+	size_t alloc;
+	struct attr_check **checks;
+	pthread_mutex_t mutex;
+} check_vector;
+
+static inline void vector_lock(void)
+{
+	pthread_mutex_lock(&check_vector.mutex);
+}
+
+static inline void vector_unlock(void)
+{
+	pthread_mutex_unlock(&check_vector.mutex);
+}
+
+static void check_vector_add(struct attr_check *c)
+{
+	vector_lock();
+
+	ALLOC_GROW(check_vector.checks,
+		   check_vector.nr + 1,
+		   check_vector.alloc);
+	check_vector.checks[check_vector.nr++] = c;
+
+	vector_unlock();
+}
+
+static void check_vector_remove(struct attr_check *check)
+{
+	int i;
+
+	vector_lock();
+
+	/* Find entry */
+	for (i = 0; i < check_vector.nr; i++)
+		if (check_vector.checks[i] == check)
+			break;
+
+	if (i >= check_vector.nr)
+		BUG("no entry found");
+
+	/* shift entries over */
+	for (; i < check_vector.nr - 1; i++)
+		check_vector.checks[i] = check_vector.checks[i + 1];
+
+	check_vector.nr--;
+
+	vector_unlock();
+}
+
+/* Iterate through all attr_check instances and drop their stacks */
+static void drop_all_attr_stacks(void)
+{
+	int i;
+
+	vector_lock();
+
+	for (i = 0; i < check_vector.nr; i++) {
+		drop_attr_stack(&check_vector.checks[i]->stack);
+	}
+
+	vector_unlock();
+}
+
+struct attr_check *attr_check_alloc(void)
+{
+	struct attr_check *c = xcalloc(1, sizeof(struct attr_check));
+
+	/* save pointer to the check struct */
+	check_vector_add(c);
+
+	return c;
+}
+
+struct attr_check *attr_check_initl(const char *one, ...)
+{
+	struct attr_check *check;
+	int cnt;
+	va_list params;
+	const char *param;
+
+	va_start(params, one);
+	for (cnt = 1; (param = va_arg(params, const char *)) != NULL; cnt++)
+		;
+	va_end(params);
+
+	check = attr_check_alloc();
+	check->nr = cnt;
+	check->alloc = cnt;
+	CALLOC_ARRAY(check->items, cnt);
+
+	check->items[0].attr = git_attr(one);
+	va_start(params, one);
+	for (cnt = 1; cnt < check->nr; cnt++) {
+		const struct git_attr *attr;
+		param = va_arg(params, const char *);
+		if (!param)
+			BUG("counted %d != ended at %d",
+			    check->nr, cnt);
+		attr = git_attr(param);
+		if (!attr)
+			BUG("%s: not a valid attribute name", param);
+		check->items[cnt].attr = attr;
+	}
+	va_end(params);
+	return check;
+}
+
+struct attr_check *attr_check_dup(const struct attr_check *check)
+{
+	struct attr_check *ret;
+
+	if (!check)
+		return NULL;
+
+	ret = attr_check_alloc();
+
+	ret->nr = check->nr;
+	ret->alloc = check->alloc;
+	DUP_ARRAY(ret->items, check->items, ret->nr);
+
+	return ret;
+}
+
+struct attr_check_item *attr_check_append(struct attr_check *check,
+					  const struct git_attr *attr)
+{
+	struct attr_check_item *item;
+
+	ALLOC_GROW(check->items, check->nr + 1, check->alloc);
+	item = &check->items[check->nr++];
+	item->attr = attr;
+	return item;
+}
+
+void attr_check_reset(struct attr_check *check)
+{
+	check->nr = 0;
+}
+
+void attr_check_clear(struct attr_check *check)
+{
+	FREE_AND_NULL(check->items);
+	check->alloc = 0;
+	check->nr = 0;
+
+	FREE_AND_NULL(check->all_attrs);
+	check->all_attrs_nr = 0;
+
+	drop_attr_stack(&check->stack);
+}
+
+void attr_check_free(struct attr_check *check)
+{
+	if (check) {
+		/* Remove check from the check vector */
+		check_vector_remove(check);
+
+		attr_check_clear(check);
+		free(check);
+	}
+}
+
+static const char *builtin_attr[] = {
+	"[attr]binary -diff -merge -text",
+	NULL,
+};
+
+static void handle_attr_line(struct attr_stack *res,
+			     const char *line,
+			     const char *src,
+			     int lineno,
+			     unsigned flags)
+{
+	struct match_attr *a;
+
+	a = parse_attr_line(line, src, lineno, flags);
+	if (!a)
+		return;
+	ALLOC_GROW_BY(res->attrs, res->num_matches, 1, res->alloc);
+	res->attrs[res->num_matches - 1] = a;
+}
+
+static struct attr_stack *read_attr_from_array(const char **list)
+{
+	struct attr_stack *res;
+	const char *line;
+	int lineno = 0;
+
+	CALLOC_ARRAY(res, 1);
+	while ((line = *(list++)) != NULL)
+		handle_attr_line(res, line, "[builtin]", ++lineno,
+				 READ_ATTR_MACRO_OK);
+	return res;
+}
+
+/*
+ * Callers into the attribute system assume there is a single, system-wide
+ * global state where attributes are read from and when the state is flipped by
+ * calling git_attr_set_direction(), the stack frames that have been
+ * constructed need to be discarded so that subsequent calls into the
+ * attribute system will lazily read from the right place.  Since changing
+ * direction causes a global paradigm shift, it should not ever be called while
+ * another thread could potentially be calling into the attribute system.
+ */
+static enum git_attr_direction direction;
+
+void git_attr_set_direction(enum git_attr_direction new_direction)
+{
+	if (is_bare_repository() && new_direction != GIT_ATTR_INDEX)
+		BUG("non-INDEX attr direction in a bare repo");
+
+	if (new_direction != direction)
+		drop_all_attr_stacks();
+
+	direction = new_direction;
+}
+
+static struct attr_stack *read_attr_from_file(const char *path, unsigned flags)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int fd;
+	FILE *fp;
+	struct attr_stack *res;
+	int lineno = 0;
+	struct stat st;
+
+	if (flags & READ_ATTR_NOFOLLOW)
+		fd = open_nofollow(path, O_RDONLY);
+	else
+		fd = open(path, O_RDONLY);
+
+	if (fd < 0) {
+		warn_on_fopen_errors(path);
+		return NULL;
+	}
+	fp = xfdopen(fd, "r");
+	if (fstat(fd, &st)) {
+		warning_errno(_("cannot fstat gitattributes file '%s'"), path);
+		fclose(fp);
+		return NULL;
+	}
+	if (st.st_size >= ATTR_MAX_FILE_SIZE) {
+		warning(_("ignoring overly large gitattributes file '%s'"), path);
+		fclose(fp);
+		return NULL;
+	}
+
+	CALLOC_ARRAY(res, 1);
+	while (strbuf_getline(&buf, fp) != EOF) {
+		if (!lineno && starts_with(buf.buf, utf8_bom))
+			strbuf_remove(&buf, 0, strlen(utf8_bom));
+		handle_attr_line(res, buf.buf, path, ++lineno, flags);
+	}
+
+	fclose(fp);
+	strbuf_release(&buf);
+	return res;
+}
+
+static struct attr_stack *read_attr_from_buf(char *buf, size_t length,
+					     const char *path, unsigned flags)
+{
+	struct attr_stack *res;
+	char *sp;
+	int lineno = 0;
+
+	if (!buf)
+		return NULL;
+	if (length >= ATTR_MAX_FILE_SIZE) {
+		warning(_("ignoring overly large gitattributes blob '%s'"), path);
+		free(buf);
+		return NULL;
+	}
+
+	CALLOC_ARRAY(res, 1);
+	for (sp = buf; *sp;) {
+		char *ep;
+		int more;
+
+		ep = strchrnul(sp, '\n');
+		more = (*ep == '\n');
+		*ep = '\0';
+		handle_attr_line(res, sp, path, ++lineno, flags);
+		sp = ep + more;
+	}
+	free(buf);
+
+	return res;
+}
+
+static struct attr_stack *read_attr_from_blob(struct index_state *istate,
+					      const struct object_id *tree_oid,
+					      const char *path, unsigned flags)
+{
+	struct object_id oid;
+	unsigned long sz;
+	enum object_type type;
+	void *buf;
+	unsigned short mode;
+
+	if (!tree_oid)
+		return NULL;
+
+	if (get_tree_entry(istate->repo, tree_oid, path, &oid, &mode))
+		return NULL;
+
+	buf = repo_read_object_file(istate->repo, &oid, &type, &sz);
+	if (!buf || type != OBJ_BLOB) {
+		free(buf);
+		return NULL;
+	}
+
+	return read_attr_from_buf(buf, sz, path, flags);
+}
+
+static struct attr_stack *read_attr_from_index(struct index_state *istate,
+					       const char *path, unsigned flags)
+{
+	struct attr_stack *stack = NULL;
+	char *buf;
+	unsigned long size;
+	int sparse_dir_pos = -1;
+
+	if (!istate)
+		return NULL;
+
+	/*
+	 * When handling sparse-checkouts, .gitattributes files
+	 * may reside within a sparse directory. We distinguish
+	 * whether a path exists directly in the index or not by
+	 * evaluating if 'pos' is negative.
+	 * If 'pos' is negative, the path is not directly present
+	 * in the index and is likely within a sparse directory.
+	 * For paths not in the index, The absolute value of 'pos'
+	 * minus 1 gives us the position where the path would be
+	 * inserted in lexicographic order within the index.
+	 * We then subtract another 1 from this value
+	 * (sparse_dir_pos = -pos - 2) to find the position of the
+	 * last index entry which is lexicographically smaller than
+	 * the path. This would be the sparse directory containing
+	 * the path. By identifying the sparse directory containing
+	 * the path, we can correctly read the attributes specified
+	 * in the .gitattributes file from the tree object of the
+	 * sparse directory.
+	 */
+	if (!path_in_cone_mode_sparse_checkout(path, istate)) {
+		int pos = index_name_pos_sparse(istate, path, strlen(path));
+
+		if (pos < 0)
+			sparse_dir_pos = -pos - 2;
+	}
+
+	if (sparse_dir_pos >= 0 &&
+	    S_ISSPARSEDIR(istate->cache[sparse_dir_pos]->ce_mode) &&
+	    !strncmp(istate->cache[sparse_dir_pos]->name, path, ce_namelen(istate->cache[sparse_dir_pos]))) {
+		const char *relative_path = path + ce_namelen(istate->cache[sparse_dir_pos]);
+		stack = read_attr_from_blob(istate, &istate->cache[sparse_dir_pos]->oid, relative_path, flags);
+	} else {
+		buf = read_blob_data_from_index(istate, path, &size);
+		if (buf)
+			stack = read_attr_from_buf(buf, size, path, flags);
+	}
+	return stack;
+}
+
+static struct attr_stack *read_attr(struct index_state *istate,
+				    const struct object_id *tree_oid,
+				    const char *path, unsigned flags)
+{
+	struct attr_stack *res = NULL;
+
+	if (direction == GIT_ATTR_INDEX) {
+		res = read_attr_from_index(istate, path, flags);
+	} else if (tree_oid) {
+		res = read_attr_from_blob(istate, tree_oid, path, flags);
+	} else if (!is_bare_repository()) {
+		if (direction == GIT_ATTR_CHECKOUT) {
+			res = read_attr_from_index(istate, path, flags);
+			if (!res)
+				res = read_attr_from_file(path, flags);
+		} else if (direction == GIT_ATTR_CHECKIN) {
+			res = read_attr_from_file(path, flags);
+			if (!res)
+				/*
+				 * There is no checked out .gitattributes file
+				 * there, but we might have it in the index.
+				 * We allow operation in a sparsely checked out
+				 * work tree, so read from it.
+				 */
+				res = read_attr_from_index(istate, path, flags);
+		}
+	}
+
+	if (!res)
+		CALLOC_ARRAY(res, 1);
+	return res;
+}
+
+const char *git_attr_system_file(void)
+{
+	static const char *system_wide;
+	if (!system_wide)
+		system_wide = system_path(ETC_GITATTRIBUTES);
+	return system_wide;
+}
+
+const char *git_attr_global_file(void)
+{
+	if (!git_attributes_file)
+		git_attributes_file = xdg_config_home("attributes");
+
+	return git_attributes_file;
+}
+
+int git_attr_system_is_enabled(void)
+{
+	return !git_env_bool("GIT_ATTR_NOSYSTEM", 0);
+}
+
+static GIT_PATH_FUNC(git_path_info_attributes, INFOATTRIBUTES_FILE)
+
+static void push_stack(struct attr_stack **attr_stack_p,
+		       struct attr_stack *elem, char *origin, size_t originlen)
+{
+	if (elem) {
+		elem->origin = origin;
+		if (origin)
+			elem->originlen = originlen;
+		elem->prev = *attr_stack_p;
+		*attr_stack_p = elem;
+	}
+}
+
+static void bootstrap_attr_stack(struct index_state *istate,
+				 const struct object_id *tree_oid,
+				 struct attr_stack **stack)
+{
+	struct attr_stack *e;
+	unsigned flags = READ_ATTR_MACRO_OK;
+
+	if (*stack)
+		return;
+
+	/* builtin frame */
+	e = read_attr_from_array(builtin_attr);
+	push_stack(stack, e, NULL, 0);
+
+	/* system-wide frame */
+	if (git_attr_system_is_enabled()) {
+		e = read_attr_from_file(git_attr_system_file(), flags);
+		push_stack(stack, e, NULL, 0);
+	}
+
+	/* home directory */
+	if (git_attr_global_file()) {
+		e = read_attr_from_file(git_attr_global_file(), flags);
+		push_stack(stack, e, NULL, 0);
+	}
+
+	/* root directory */
+	e = read_attr(istate, tree_oid, GITATTRIBUTES_FILE, flags | READ_ATTR_NOFOLLOW);
+	push_stack(stack, e, xstrdup(""), 0);
+
+	/* info frame */
+	if (startup_info->have_repository)
+		e = read_attr_from_file(git_path_info_attributes(), flags);
+	else
+		e = NULL;
+	if (!e)
+		CALLOC_ARRAY(e, 1);
+	push_stack(stack, e, NULL, 0);
+}
+
+static void prepare_attr_stack(struct index_state *istate,
+			       const struct object_id *tree_oid,
+			       const char *path, int dirlen,
+			       struct attr_stack **stack)
+{
+	struct attr_stack *info;
+	struct strbuf pathbuf = STRBUF_INIT;
+
+	/*
+	 * At the bottom of the attribute stack is the built-in
+	 * set of attribute definitions, followed by the contents
+	 * of $(prefix)/etc/gitattributes and a file specified by
+	 * core.attributesfile.  Then, contents from
+	 * .gitattributes files from directories closer to the
+	 * root to the ones in deeper directories are pushed
+	 * to the stack.  Finally, at the very top of the stack
+	 * we always keep the contents of $GIT_DIR/info/attributes.
+	 *
+	 * When checking, we use entries from near the top of the
+	 * stack, preferring $GIT_DIR/info/attributes, then
+	 * .gitattributes in deeper directories to shallower ones,
+	 * and finally use the built-in set as the default.
+	 */
+	bootstrap_attr_stack(istate, tree_oid, stack);
+
+	/*
+	 * Pop the "info" one that is always at the top of the stack.
+	 */
+	info = *stack;
+	*stack = info->prev;
+
+	/*
+	 * Pop the ones from directories that are not the prefix of
+	 * the path we are checking. Break out of the loop when we see
+	 * the root one (whose origin is an empty string "") or the builtin
+	 * one (whose origin is NULL) without popping it.
+	 */
+	while ((*stack)->origin) {
+		int namelen = (*stack)->originlen;
+		struct attr_stack *elem;
+
+		elem = *stack;
+		if (namelen <= dirlen &&
+		    !strncmp(elem->origin, path, namelen) &&
+		    (!namelen || path[namelen] == '/'))
+			break;
+
+		*stack = elem->prev;
+		attr_stack_free(elem);
+	}
+
+	/*
+	 * bootstrap_attr_stack() should have added, and the
+	 * above loop should have stopped before popping, the
+	 * root element whose attr_stack->origin is set to an
+	 * empty string.
+	 */
+	assert((*stack)->origin);
+
+	strbuf_addstr(&pathbuf, (*stack)->origin);
+	/* Build up to the directory 'path' is in */
+	while (pathbuf.len < dirlen) {
+		size_t len = pathbuf.len;
+		struct attr_stack *next;
+		char *origin;
+
+		/* Skip path-separator */
+		if (len < dirlen && is_dir_sep(path[len]))
+			len++;
+		/* Find the end of the next component */
+		while (len < dirlen && !is_dir_sep(path[len]))
+			len++;
+
+		if (pathbuf.len > 0)
+			strbuf_addch(&pathbuf, '/');
+		strbuf_add(&pathbuf, path + pathbuf.len, (len - pathbuf.len));
+		strbuf_addf(&pathbuf, "/%s", GITATTRIBUTES_FILE);
+
+		next = read_attr(istate, tree_oid, pathbuf.buf, READ_ATTR_NOFOLLOW);
+
+		/* reset the pathbuf to not include "/.gitattributes" */
+		strbuf_setlen(&pathbuf, len);
+
+		origin = xstrdup(pathbuf.buf);
+		push_stack(stack, next, origin, len);
+	}
+
+	/*
+	 * Finally push the "info" one at the top of the stack.
+	 */
+	push_stack(stack, info, NULL, 0);
+
+	strbuf_release(&pathbuf);
+}
+
+static int path_matches(const char *pathname, int pathlen,
+			int basename_offset,
+			const struct pattern *pat,
+			const char *base, int baselen)
+{
+	const char *pattern = pat->pattern;
+	int prefix = pat->nowildcardlen;
+	int isdir = (pathlen && pathname[pathlen - 1] == '/');
+
+	if ((pat->flags & PATTERN_FLAG_MUSTBEDIR) && !isdir)
+		return 0;
+
+	if (pat->flags & PATTERN_FLAG_NODIR) {
+		return match_basename(pathname + basename_offset,
+				      pathlen - basename_offset - isdir,
+				      pattern, prefix,
+				      pat->patternlen, pat->flags);
+	}
+	return match_pathname(pathname, pathlen - isdir,
+			      base, baselen,
+			      pattern, prefix, pat->patternlen);
+}
+
+static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem);
+
+static int fill_one(struct all_attrs_item *all_attrs,
+		    const struct match_attr *a, int rem)
+{
+	size_t i;
+
+	for (i = a->num_attr; rem > 0 && i > 0; i--) {
+		const struct git_attr *attr = a->state[i - 1].attr;
+		const char **n = &(all_attrs[attr->attr_nr].value);
+		const char *v = a->state[i - 1].setto;
+
+		if (*n == ATTR__UNKNOWN) {
+			*n = v;
+			rem--;
+			rem = macroexpand_one(all_attrs, attr->attr_nr, rem);
+		}
+	}
+	return rem;
+}
+
+static int fill(const char *path, int pathlen, int basename_offset,
+		const struct attr_stack *stack,
+		struct all_attrs_item *all_attrs, int rem)
+{
+	for (; rem > 0 && stack; stack = stack->prev) {
+		unsigned i;
+		const char *base = stack->origin ? stack->origin : "";
+
+		for (i = stack->num_matches; 0 < rem && 0 < i; i--) {
+			const struct match_attr *a = stack->attrs[i - 1];
+			if (a->is_macro)
+				continue;
+			if (path_matches(path, pathlen, basename_offset,
+					 &a->u.pat, base, stack->originlen))
+				rem = fill_one(all_attrs, a, rem);
+		}
+	}
+
+	return rem;
+}
+
+static int macroexpand_one(struct all_attrs_item *all_attrs, int nr, int rem)
+{
+	const struct all_attrs_item *item = &all_attrs[nr];
+
+	if (item->macro && item->value == ATTR__TRUE)
+		return fill_one(all_attrs, item->macro, rem);
+	else
+		return rem;
+}
+
+/*
+ * Marks the attributes which are macros based on the attribute stack.
+ * This prevents having to search through the attribute stack each time
+ * a macro needs to be expanded during the fill stage.
+ */
+static void determine_macros(struct all_attrs_item *all_attrs,
+			     const struct attr_stack *stack)
+{
+	for (; stack; stack = stack->prev) {
+		unsigned i;
+		for (i = stack->num_matches; i > 0; i--) {
+			const struct match_attr *ma = stack->attrs[i - 1];
+			if (ma->is_macro) {
+				unsigned int n = ma->u.attr->attr_nr;
+				if (!all_attrs[n].macro) {
+					all_attrs[n].macro = ma;
+				}
+			}
+		}
+	}
+}
+
+/*
+ * Collect attributes for path into the array pointed to by check->all_attrs.
+ * If check->check_nr is non-zero, only attributes in check[] are collected.
+ * Otherwise all attributes are collected.
+ */
+static void collect_some_attrs(struct index_state *istate,
+			       const struct object_id *tree_oid,
+			       const char *path, struct attr_check *check)
+{
+	int pathlen, rem, dirlen;
+	const char *cp, *last_slash = NULL;
+	int basename_offset;
+
+	for (cp = path; *cp; cp++) {
+		if (*cp == '/' && cp[1])
+			last_slash = cp;
+	}
+	pathlen = cp - path;
+	if (last_slash) {
+		basename_offset = last_slash + 1 - path;
+		dirlen = last_slash - path;
+	} else {
+		basename_offset = 0;
+		dirlen = 0;
+	}
+
+	prepare_attr_stack(istate, tree_oid, path, dirlen, &check->stack);
+	all_attrs_init(&g_attr_hashmap, check);
+	determine_macros(check->all_attrs, check->stack);
+
+	rem = check->all_attrs_nr;
+	fill(path, pathlen, basename_offset, check->stack, check->all_attrs, rem);
+}
+
+static const char *default_attr_source_tree_object_name;
+
+void set_git_attr_source(const char *tree_object_name)
+{
+	default_attr_source_tree_object_name = xstrdup(tree_object_name);
+}
+
+static int compute_default_attr_source(struct object_id *attr_source)
+{
+	int ignore_bad_attr_tree = 0;
+
+	if (!default_attr_source_tree_object_name)
+		default_attr_source_tree_object_name = getenv(GIT_ATTR_SOURCE_ENVIRONMENT);
+
+	if (!default_attr_source_tree_object_name && git_attr_tree) {
+		default_attr_source_tree_object_name = git_attr_tree;
+		ignore_bad_attr_tree = 1;
+	}
+
+	if (!default_attr_source_tree_object_name)
+		return 0;
+
+	if (!startup_info->have_repository) {
+		if (!ignore_bad_attr_tree)
+			die(_("cannot use --attr-source or GIT_ATTR_SOURCE without repo"));
+		return 0;
+	}
+
+	if (repo_get_oid_treeish(the_repository,
+				 default_attr_source_tree_object_name,
+				 attr_source)) {
+		if (!ignore_bad_attr_tree)
+			die(_("bad --attr-source or GIT_ATTR_SOURCE"));
+		return 0;
+	}
+
+	return 1;
+}
+
+static struct object_id *default_attr_source(void)
+{
+	static struct object_id attr_source;
+	static int has_attr_source = -1;
+
+	if (has_attr_source < 0)
+		has_attr_source = compute_default_attr_source(&attr_source);
+	if (!has_attr_source)
+		return NULL;
+	return &attr_source;
+}
+
+static const char *interned_mode_string(unsigned int mode)
+{
+	static struct {
+		unsigned int val;
+		char str[7];
+	} mode_string[] = {
+		{ .val = 0040000 },
+		{ .val = 0100644 },
+		{ .val = 0100755 },
+		{ .val = 0120000 },
+		{ .val = 0160000 },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(mode_string); i++) {
+		if (mode_string[i].val != mode)
+			continue;
+		if (!*mode_string[i].str)
+			snprintf(mode_string[i].str, sizeof(mode_string[i].str),
+				 "%06o", mode);
+		return mode_string[i].str;
+	}
+	BUG("Unsupported mode 0%o", mode);
+}
+
+static const char *builtin_object_mode_attr(struct index_state *istate, const char *path)
+{
+	unsigned int mode;
+
+	if (direction == GIT_ATTR_CHECKIN) {
+		struct object_id oid;
+		struct stat st;
+		if (lstat(path, &st))
+			die_errno(_("unable to stat '%s'"), path);
+		mode = canon_mode(st.st_mode);
+		if (S_ISDIR(mode)) {
+			/*
+			 *`path` is either a directory or it is a submodule,
+			 * in which case it is already indexed as submodule
+			 * or it does not exist in the index yet and we need to
+			 * check if we can resolve to a ref.
+			*/
+			int pos = index_name_pos(istate, path, strlen(path));
+			if (pos >= 0) {
+				 if (S_ISGITLINK(istate->cache[pos]->ce_mode))
+					 mode = istate->cache[pos]->ce_mode;
+			} else if (repo_resolve_gitlink_ref(the_repository, path,
+							    "HEAD", &oid) == 0) {
+				mode = S_IFGITLINK;
+			}
+		}
+	} else {
+		/*
+		 * For GIT_ATTR_CHECKOUT and GIT_ATTR_INDEX we only check
+		 * for mode in the index.
+		 */
+		int pos = index_name_pos(istate, path, strlen(path));
+		if (pos >= 0)
+			mode = istate->cache[pos]->ce_mode;
+		else
+			return ATTR__UNSET;
+	}
+
+	return interned_mode_string(mode);
+}
+
+
+static const char *compute_builtin_attr(struct index_state *istate,
+					  const char *path,
+					  const struct git_attr *attr) {
+	static const struct git_attr *object_mode_attr;
+
+	if (!object_mode_attr)
+		object_mode_attr = git_attr("builtin_objectmode");
+
+	if (attr == object_mode_attr)
+		return builtin_object_mode_attr(istate, path);
+	return ATTR__UNSET;
+}
+
+void git_check_attr(struct index_state *istate,
+		    const char *path,
+		    struct attr_check *check)
+{
+	int i;
+	const struct object_id *tree_oid = default_attr_source();
+
+	collect_some_attrs(istate, tree_oid, path, check);
+
+	for (i = 0; i < check->nr; i++) {
+		unsigned int n = check->items[i].attr->attr_nr;
+		const char *value = check->all_attrs[n].value;
+		if (value == ATTR__UNKNOWN)
+			value = compute_builtin_attr(istate, path, check->all_attrs[n].attr);
+		check->items[i].value = value;
+	}
+}
+
+void git_all_attrs(struct index_state *istate,
+		   const char *path, struct attr_check *check)
+{
+	int i;
+	const struct object_id *tree_oid = default_attr_source();
+
+	attr_check_reset(check);
+	collect_some_attrs(istate, tree_oid, path, check);
+
+	for (i = 0; i < check->all_attrs_nr; i++) {
+		const char *name = check->all_attrs[i].attr->name;
+		const char *value = check->all_attrs[i].value;
+		struct attr_check_item *item;
+		if (value == ATTR__UNSET || value == ATTR__UNKNOWN)
+			continue;
+		item = attr_check_append(check, git_attr(name));
+		item->value = value;
+	}
+}
+
+void attr_start(void)
+{
+	pthread_mutex_init(&g_attr_hashmap.mutex, NULL);
+	pthread_mutex_init(&check_vector.mutex, NULL);
+}
diff --git a/attr.h b/attr.h
new file mode 100644
index 0000000000..a04a521092
--- /dev/null
+++ b/attr.h
@@ -0,0 +1,286 @@
+#ifndef ATTR_H
+#define ATTR_H
+
+/**
+ * gitattributes mechanism gives a uniform way to associate various attributes
+ * to set of paths.
+ *
+ *
+ * Querying Specific Attributes
+ * ----------------------------
+ *
+ * - Prepare `struct attr_check` using attr_check_initl() function, enumerating
+ *   the names of attributes whose values you are interested in, terminated with
+ *   a NULL pointer.  Alternatively, an empty `struct attr_check` can be
+ *   prepared by calling `attr_check_alloc()` function and then attributes you
+ *   want to ask about can be added to it with `attr_check_append()` function.
+ *
+ * - Call `git_check_attr()` to check the attributes for the path.
+ *
+ * - Inspect `attr_check` structure to see how each of the attribute in the
+ *   array is defined for the path.
+ *
+ *
+ * Example
+ * -------
+ *
+ * To see how attributes "crlf" and "ident" are set for different paths.
+ *
+ * - Prepare a `struct attr_check` with two elements (because we are checking
+ *   two attributes):
+ *
+ * ------------
+ * static struct attr_check *check;
+ * static void setup_check(void)
+ * {
+ * 	if (check)
+ * 		return; // already done
+ * check = attr_check_initl("crlf", "ident", NULL);
+ * }
+ * ------------
+ *
+ * - Call `git_check_attr()` with the prepared `struct attr_check`:
+ *
+ * ------------
+ * const char *path;
+ *
+ * setup_check();
+ * git_check_attr(&the_index, path, check);
+ * ------------
+ *
+ * - Act on `.value` member of the result, left in `check->items[]`:
+ *
+ * ------------
+ * const char *value = check->items[0].value;
+ *
+ * if (ATTR_TRUE(value)) {
+ * The attribute is Set, by listing only the name of the
+ * attribute in the gitattributes file for the path.
+ * } else if (ATTR_FALSE(value)) {
+ * The attribute is Unset, by listing the name of the
+ *         attribute prefixed with a dash - for the path.
+ * } else if (ATTR_UNSET(value)) {
+ * The attribute is neither set nor unset for the path.
+ * } else if (!strcmp(value, "input")) {
+ * If none of ATTR_TRUE(), ATTR_FALSE(), or ATTR_UNSET() is
+ *         true, the value is a string set in the gitattributes
+ * file for the path by saying "attr=value".
+ * } else if (... other check using value as string ...) {
+ * ...
+ * }
+ * ------------
+ *
+ * To see how attributes in argv[] are set for different paths, only
+ * the first step in the above would be different.
+ *
+ * ------------
+ * static struct attr_check *check;
+ * static void setup_check(const char **argv)
+ * {
+ *     check = attr_check_alloc();
+ *     while (*argv) {
+ *         struct git_attr *attr = git_attr(*argv);
+ *         attr_check_append(check, attr);
+ *         argv++;
+ *     }
+ * }
+ * ------------
+ *
+ *
+ * Querying All Attributes
+ * -----------------------
+ *
+ * To get the values of all attributes associated with a file:
+ *
+ * - Prepare an empty `attr_check` structure by calling `attr_check_alloc()`.
+ *
+ * - Call `git_all_attrs()`, which populates the `attr_check` with the
+ * attributes attached to the path.
+ *
+ * - Iterate over the `attr_check.items[]` array to examine the attribute
+ * names and values. The name of the attribute described by an
+ * `attr_check.items[]` object can be retrieved via
+ * `git_attr_name(check->items[i].attr)`. (Please note that no items will be
+ * returned for unset attributes, so `ATTR_UNSET()` will return false for all
+ * returned `attr_check.items[]` objects.)
+ *
+ * - Free the `attr_check` struct by calling `attr_check_free()`.
+ */
+
+/**
+ * The maximum line length for a gitattributes file. If the line exceeds this
+ * length we will ignore it.
+ */
+#define ATTR_MAX_LINE_LENGTH 2048
+
+ /**
+  * The maximum size of the giattributes file. If the file exceeds this size we
+  * will ignore it.
+  */
+#define ATTR_MAX_FILE_SIZE (100 * 1024 * 1024)
+
+struct index_state;
+
+/**
+ * An attribute is an opaque object that is identified by its name. Pass the
+ * name to `git_attr()` function to obtain the object of this type.
+ * The internal representation of this structure is of no interest to the
+ * calling programs. The name of the attribute can be retrieved by calling
+ * `git_attr_name()`.
+ */
+struct git_attr;
+
+/* opaque structures used internally for attribute collection */
+struct all_attrs_item;
+struct attr_stack;
+
+/*
+ * The textual object name for the tree-ish used by git_check_attr()
+ * to read attributes from (instead of from the working tree).
+ */
+void set_git_attr_source(const char *);
+
+/*
+ * Given a string, return the gitattribute object that
+ * corresponds to it.
+ */
+const struct git_attr *git_attr(const char *);
+
+/* Internal use */
+extern const char git_attr__true[];
+extern const char git_attr__false[];
+
+/**
+ * Attribute Values
+ * ----------------
+ *
+ * An attribute for a path can be in one of four states: Set, Unset, Unspecified
+ * or set to a string, and `.value` member of `struct attr_check_item` records
+ * it. The three macros check these, if none of them returns true, `.value`
+ * member points at a string value of the attribute for the path.
+ */
+
+/* Returns true if the attribute is Set for the path. */
+#define ATTR_TRUE(v) ((v) == git_attr__true)
+
+/* Returns true if the attribute is Unset for the path. */
+#define ATTR_FALSE(v) ((v) == git_attr__false)
+
+/* Returns true if the attribute is Unspecified for the path. */
+#define ATTR_UNSET(v) ((v) == NULL)
+
+/* This structure represents one attribute and its value. */
+struct attr_check_item {
+	const struct git_attr *attr;
+	const char *value;
+};
+
+/**
+ * This structure represents a collection of `attr_check_item`. It is passed to
+ * `git_check_attr()` function, specifying the attributes to check, and
+ * receives their values.
+ */
+struct attr_check {
+	int nr;
+	int alloc;
+	struct attr_check_item *items;
+	int all_attrs_nr;
+	struct all_attrs_item *all_attrs;
+	struct attr_stack *stack;
+};
+
+struct attr_check *attr_check_alloc(void);
+
+LAST_ARG_MUST_BE_NULL
+struct attr_check *attr_check_initl(const char *, ...);
+struct attr_check *attr_check_dup(const struct attr_check *check);
+
+struct attr_check_item *attr_check_append(struct attr_check *check,
+					  const struct git_attr *attr);
+
+void attr_check_reset(struct attr_check *check);
+void attr_check_clear(struct attr_check *check);
+void attr_check_free(struct attr_check *check);
+
+/*
+ * Return the name of the attribute represented by the argument.  The
+ * return value is a pointer to a null-delimited string that is part
+ * of the internal data structure; it should not be modified or freed.
+ */
+const char *git_attr_name(const struct git_attr *);
+
+void git_check_attr(struct index_state *istate,
+		    const char *path,
+		    struct attr_check *check);
+
+/*
+ * Retrieve all attributes that apply to the specified path.
+ * check holds the attributes and their values.
+ */
+void git_all_attrs(struct index_state *istate,
+		   const char *path, struct attr_check *check);
+
+enum git_attr_direction {
+	GIT_ATTR_CHECKIN,
+	GIT_ATTR_CHECKOUT,
+	GIT_ATTR_INDEX
+};
+void git_attr_set_direction(enum git_attr_direction new_direction);
+
+void attr_start(void);
+
+/* Return the system gitattributes file. */
+const char *git_attr_system_file(void);
+
+/* Return the global gitattributes file, if any. */
+const char *git_attr_global_file(void);
+
+/* Return whether the system gitattributes file is enabled and should be used. */
+int git_attr_system_is_enabled(void);
+
+extern char *git_attr_tree;
+
+/*
+ * Exposed for fuzz-testing only.
+ */
+
+/* What does a matched pattern decide? */
+struct attr_state {
+	const struct git_attr *attr;
+	const char *setto;
+};
+
+struct pattern {
+	const char *pattern;
+	int patternlen;
+	int nowildcardlen;
+	unsigned flags;		/* PATTERN_FLAG_* */
+};
+
+/*
+ * One rule, as from a .gitattributes file.
+ *
+ * If is_macro is true, then u.attr is a pointer to the git_attr being
+ * defined.
+ *
+ * If is_macro is false, then u.pat is the filename pattern to which the
+ * rule applies.
+ *
+ * In either case, num_attr is the number of attributes affected by
+ * this rule, and state is an array listing them.  The attributes are
+ * listed as they appear in the file (macros unexpanded).
+ */
+struct match_attr {
+	union {
+		struct pattern pat;
+		const struct git_attr *attr;
+	} u;
+	char is_macro;
+	size_t num_attr;
+	struct attr_state state[FLEX_ARRAY];
+};
+
+struct match_attr *parse_attr_line(const char *line, const char *src,
+				   int lineno, unsigned flags);
+
+#endif /* ATTR_H */
diff --git a/banned.h b/banned.h
new file mode 100644
index 0000000000..44e76bd90a
--- /dev/null
+++ b/banned.h
@@ -0,0 +1,44 @@
+#ifndef BANNED_H
+#define BANNED_H
+
+/*
+ * This header lists functions that have been banned from our code base,
+ * because they're too easy to misuse (and even if used correctly,
+ * complicate audits). Including this header turns them into compile-time
+ * errors.
+ */
+
+#define BANNED(func) sorry_##func##_is_a_banned_function
+
+#undef strcpy
+#define strcpy(x,y) BANNED(strcpy)
+#undef strcat
+#define strcat(x,y) BANNED(strcat)
+#undef strncpy
+#define strncpy(x,y,n) BANNED(strncpy)
+#undef strncat
+#define strncat(x,y,n) BANNED(strncat)
+#undef strtok
+#define strtok(x,y) BANNED(strtok)
+#undef strtok_r
+#define strtok_r(x,y,z) BANNED(strtok_r)
+
+#undef sprintf
+#undef vsprintf
+#define sprintf(...) BANNED(sprintf)
+#define vsprintf(...) BANNED(vsprintf)
+
+#undef gmtime
+#define gmtime(t) BANNED(gmtime)
+#undef localtime
+#define localtime(t) BANNED(localtime)
+#undef ctime
+#define ctime(t) BANNED(ctime)
+#undef ctime_r
+#define ctime_r(t, buf) BANNED(ctime_r)
+#undef asctime
+#define asctime(t) BANNED(asctime)
+#undef asctime_r
+#define asctime_r(t, buf) BANNED(asctime_r)
+
+#endif /* BANNED_H */
diff --git a/base85.c b/base85.c
new file mode 100644
index 0000000000..80e899a2b1
--- /dev/null
+++ b/base85.c
@@ -0,0 +1,132 @@
+#include "git-compat-util.h"
+#include "base85.h"
+
+#undef DEBUG_85
+
+#ifdef DEBUG_85
+#define say(a) fprintf(stderr, a)
+#define say1(a,b) fprintf(stderr, a, b)
+#define say2(a,b,c) fprintf(stderr, a, b, c)
+#else
+#define say(a) do { /* nothing */ } while (0)
+#define say1(a,b) do { /* nothing */ } while (0)
+#define say2(a,b,c) do { /* nothing */ } while (0)
+#endif
+
+static const char en85[] = {
+	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+	'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
+	'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
+	'U', 'V', 'W', 'X', 'Y', 'Z',
+	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
+	'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
+	'u', 'v', 'w', 'x', 'y', 'z',
+	'!', '#', '$', '%', '&', '(', ')', '*', '+', '-',
+	';', '<', '=', '>', '?', '@', '^', '_',	'`', '{',
+	'|', '}', '~'
+};
+
+static char de85[256];
+static void prep_base85(void)
+{
+	if (de85['Z'])
+		return;
+	for (size_t i = 0; i < ARRAY_SIZE(en85); i++) {
+		int ch = en85[i];
+		de85[ch] = i + 1;
+	}
+}
+
+int decode_85(char *dst, const char *buffer, int len)
+{
+	prep_base85();
+
+	say2("decode 85 <%.*s>", len / 4 * 5, buffer);
+	while (len) {
+		unsigned acc = 0;
+		int de, cnt = 4;
+		unsigned char ch;
+		do {
+			ch = *buffer++;
+			de = de85[ch];
+			if (--de < 0)
+				return error("invalid base85 alphabet %c", ch);
+			acc = acc * 85 + de;
+		} while (--cnt);
+		ch = *buffer++;
+		de = de85[ch];
+		if (--de < 0)
+			return error("invalid base85 alphabet %c", ch);
+		/* Detect overflow. */
+		if (0xffffffff / 85 < acc ||
+		    0xffffffff - de < (acc *= 85))
+			return error("invalid base85 sequence %.5s", buffer-5);
+		acc += de;
+		say1(" %08x", acc);
+
+		cnt = (len < 4) ? len : 4;
+		len -= cnt;
+		do {
+			acc = (acc << 8) | (acc >> 24);
+			*dst++ = acc;
+		} while (--cnt);
+	}
+	say("\n");
+
+	return 0;
+}
+
+void encode_85(char *buf, const unsigned char *data, int bytes)
+{
+	say("encode 85");
+	while (bytes) {
+		unsigned acc = 0;
+		int cnt;
+		for (cnt = 24; cnt >= 0; cnt -= 8) {
+			unsigned ch = *data++;
+			acc |= ch << cnt;
+			if (--bytes == 0)
+				break;
+		}
+		say1(" %08x", acc);
+		for (cnt = 4; cnt >= 0; cnt--) {
+			int val = acc % 85;
+			acc /= 85;
+			buf[cnt] = en85[val];
+		}
+		buf += 5;
+	}
+	say("\n");
+
+	*buf = 0;
+}
+
+#ifdef DEBUG_85
+int main(int ac, char **av)
+{
+	char buf[1024];
+
+	if (!strcmp(av[1], "-e")) {
+		int len = strlen(av[2]);
+		encode_85(buf, av[2], len);
+		if (len <= 26) len = len + 'A' - 1;
+		else len = len + 'a' - 26 - 1;
+		printf("encoded: %c%s\n", len, buf);
+		return 0;
+	}
+	if (!strcmp(av[1], "-d")) {
+		int len = *av[2];
+		if ('A' <= len && len <= 'Z') len = len - 'A' + 1;
+		else len = len - 'a' + 26 + 1;
+		decode_85(buf, av[2]+1, len);
+		printf("decoded: %.*s\n", len, buf);
+		return 0;
+	}
+	if (!strcmp(av[1], "-t")) {
+		char t[4] = { -1,-1,-1,-1 };
+		encode_85(buf, t, 4);
+		printf("encoded: D%s\n", buf);
+		return 0;
+	}
+}
+#endif
diff --git a/base85.h b/base85.h
new file mode 100644
index 0000000000..c835086e09
--- /dev/null
+++ b/base85.h
@@ -0,0 +1,7 @@
+#ifndef BASE85_H
+#define BASE85_H
+
+int decode_85(char *dst, const char *line, int linelen);
+void encode_85(char *buf, const unsigned char *data, int bytes);
+
+#endif /* BASE85_H */
diff --git a/bin-wrappers/.gitignore b/bin-wrappers/.gitignore
new file mode 100644
index 0000000000..1c6c90458b
--- /dev/null
+++ b/bin-wrappers/.gitignore
@@ -0,0 +1,9 @@
+/git
+/git-cvsserver
+/git-receive-pack
+/git-shell
+/git-upload-archive
+/git-upload-pack
+/scalar
+/test-fake-ssh
+/test-tool
diff --git a/bin-wrappers/meson.build b/bin-wrappers/meson.build
new file mode 100644
index 0000000000..8a4e910c9b
--- /dev/null
+++ b/bin-wrappers/meson.build
@@ -0,0 +1,28 @@
+bin_wrappers_config = configuration_data()
+foreach key, value : {
+      'BUILD_DIR': meson.project_build_root(),
+      'MERGE_TOOLS_DIR': meson.project_source_root() / 'mergetools',
+      'TEMPLATE_DIR': meson.project_build_root() / 'templates',
+      'GIT_TEXTDOMAINDIR': meson.project_build_root() / 'po',
+      'GITPERLLIB': meson.project_build_root() / 'perl/lib',
+}
+  # Paths need to be Unix-style without drive prefixes as they get added to the
+  # PATH variable. And given that drive prefixes contain a colon we'd otherwise
+  # end up with a broken PATH if we didn't convert them.
+  if cygpath.found()
+    value = run_command(cygpath, value, check: true).stdout().strip()
+  endif
+  bin_wrappers_config.set(key, value)
+endforeach
+
+foreach executable : bin_wrappers
+  executable_config = configuration_data()
+  executable_config.merge_from(bin_wrappers_config)
+  executable_config.set('PROG', executable.full_path())
+
+  configure_file(
+    input: 'wrap-for-bin.sh',
+    output: fs.stem(executable.full_path()),
+    configuration: executable_config,
+  )
+endforeach
diff --git a/bin-wrappers/wrap-for-bin.sh b/bin-wrappers/wrap-for-bin.sh
new file mode 100755
index 0000000000..4b658ffd2d
--- /dev/null
+++ b/bin-wrappers/wrap-for-bin.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+# wrap-for-bin.sh: Template for git executable wrapper scripts
+# to run test suite against sandbox, but with only bindir-installed
+# executables in PATH.  The Makefile copies this into various
+# files in bin-wrappers, substituting
+# @BUILD_DIR@, @TEMPLATE_DIR@ and @PROG@.
+
+GIT_EXEC_PATH='@BUILD_DIR@'
+if test -n "$NO_SET_GIT_TEMPLATE_DIR"
+then
+	unset GIT_TEMPLATE_DIR
+else
+	GIT_TEMPLATE_DIR='@TEMPLATE_DIR@'
+	export GIT_TEMPLATE_DIR
+fi
+MERGE_TOOLS_DIR='@MERGE_TOOLS_DIR@'
+GITPERLLIB='@GITPERLLIB@'"${GITPERLLIB:+:$GITPERLLIB}"
+GIT_TEXTDOMAINDIR='@GIT_TEXTDOMAINDIR@'
+PATH='@BUILD_DIR@/bin-wrappers:'"$PATH"
+
+export MERGE_TOOLS_DIR GIT_EXEC_PATH GITPERLLIB PATH GIT_TEXTDOMAINDIR
+
+case "$GIT_DEBUGGER" in
+'')
+	exec "@PROG@" "$@"
+	;;
+1)
+	unset GIT_DEBUGGER
+	exec gdb --args "@PROG@" "$@"
+	;;
+*)
+	GIT_DEBUGGER_ARGS="$GIT_DEBUGGER"
+	unset GIT_DEBUGGER
+	exec ${GIT_DEBUGGER_ARGS} "@PROG@" "$@"
+	;;
+esac
diff --git a/bisect.c b/bisect.c
new file mode 100644
index 0000000000..7a3c77c6d8
--- /dev/null
+++ b/bisect.c
@@ -0,0 +1,1224 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "commit.h"
+#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "revision.h"
+#include "refs.h"
+#include "list-objects.h"
+#include "quote.h"
+#include "run-command.h"
+#include "log-tree.h"
+#include "bisect.h"
+#include "oid-array.h"
+#include "strvec.h"
+#include "commit-slab.h"
+#include "commit-reach.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
+#include "dir.h"
+
+static struct oid_array good_revs;
+static struct oid_array skipped_revs;
+
+static struct object_id *current_bad_oid;
+
+static char *term_bad;
+static char *term_good;
+
+/* Remember to update object flag allocation in object.h */
+#define COUNTED		(1u<<16)
+
+/*
+ * This is a truly stupid algorithm, but it's only
+ * used for bisection, and we just don't care enough.
+ *
+ * We care just barely enough to avoid recursing for
+ * non-merge entries.
+ */
+static int count_distance(struct commit_list *entry)
+{
+	int nr = 0;
+
+	while (entry) {
+		struct commit *commit = entry->item;
+		struct commit_list *p;
+
+		if (commit->object.flags & (UNINTERESTING | COUNTED))
+			break;
+		if (!(commit->object.flags & TREESAME))
+			nr++;
+		commit->object.flags |= COUNTED;
+		p = commit->parents;
+		entry = p;
+		if (p) {
+			p = p->next;
+			while (p) {
+				nr += count_distance(p);
+				p = p->next;
+			}
+		}
+	}
+
+	return nr;
+}
+
+static void clear_distance(struct commit_list *list)
+{
+	while (list) {
+		struct commit *commit = list->item;
+		commit->object.flags &= ~COUNTED;
+		list = list->next;
+	}
+}
+
+define_commit_slab(commit_weight, int *);
+static struct commit_weight commit_weight;
+
+#define DEBUG_BISECT 0
+
+static inline int weight(struct commit_list *elem)
+{
+	return **commit_weight_at(&commit_weight, elem->item);
+}
+
+static inline void weight_set(struct commit_list *elem, int weight)
+{
+	**commit_weight_at(&commit_weight, elem->item) = weight;
+}
+
+static int count_interesting_parents(struct commit *commit, unsigned bisect_flags)
+{
+	struct commit_list *p;
+	int count;
+
+	for (count = 0, p = commit->parents; p; p = p->next) {
+		if (!(p->item->object.flags & UNINTERESTING))
+			count++;
+		if (bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY)
+			break;
+	}
+	return count;
+}
+
+static inline int approx_halfway(struct commit_list *p, int nr)
+{
+	int diff;
+
+	/*
+	 * Don't short-cut something we are not going to return!
+	 */
+	if (p->item->object.flags & TREESAME)
+		return 0;
+	if (DEBUG_BISECT)
+		return 0;
+	/*
+	 * For small number of commits 2 and 3 are halfway of 5, and
+	 * 3 is halfway of 6 but 2 and 4 are not.
+	 */
+	diff = 2 * weight(p) - nr;
+	switch (diff) {
+	case -1: case 0: case 1:
+		return 1;
+	default:
+		/*
+		 * For large number of commits we are not so strict, it's
+		 * good enough if it's within ~0.1% of the halfway point,
+		 * e.g. 5000 is exactly halfway of 10000, but we consider
+		 * the values [4996, 5004] as halfway as well.
+		 */
+		if (abs(diff) < nr / 1024)
+			return 1;
+		return 0;
+	}
+}
+
+static void show_list(const char *debug, int counted, int nr,
+		      struct commit_list *list)
+{
+	struct commit_list *p;
+
+	if (!DEBUG_BISECT)
+		return;
+
+	fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr);
+
+	for (p = list; p; p = p->next) {
+		struct commit_list *pp;
+		struct commit *commit = p->item;
+		unsigned commit_flags = commit->object.flags;
+		enum object_type type;
+		unsigned long size;
+		char *buf = repo_read_object_file(the_repository,
+						  &commit->object.oid, &type,
+						  &size);
+		const char *subject_start;
+		int subject_len;
+
+		if (!buf)
+			die(_("unable to read %s"), oid_to_hex(&commit->object.oid));
+
+		fprintf(stderr, "%c%c%c ",
+			(commit_flags & TREESAME) ? ' ' : 'T',
+			(commit_flags & UNINTERESTING) ? 'U' : ' ',
+			(commit_flags & COUNTED) ? 'C' : ' ');
+		if (*commit_weight_at(&commit_weight, p->item))
+			fprintf(stderr, "%3d", weight(p));
+		else
+			fprintf(stderr, "---");
+		fprintf(stderr, " %.*s", 8, oid_to_hex(&commit->object.oid));
+		for (pp = commit->parents; pp; pp = pp->next)
+			fprintf(stderr, " %.*s", 8,
+				oid_to_hex(&pp->item->object.oid));
+
+		subject_len = find_commit_subject(buf, &subject_start);
+		if (subject_len)
+			fprintf(stderr, " %.*s", subject_len, subject_start);
+		fprintf(stderr, "\n");
+	}
+}
+
+static struct commit_list *best_bisection(struct commit_list *list, int nr)
+{
+	struct commit_list *p, *best;
+	int best_distance = -1;
+
+	best = list;
+	for (p = list; p; p = p->next) {
+		int distance;
+		unsigned commit_flags = p->item->object.flags;
+
+		if (commit_flags & TREESAME)
+			continue;
+		distance = weight(p);
+		if (nr - distance < distance)
+			distance = nr - distance;
+		if (distance > best_distance) {
+			best = p;
+			best_distance = distance;
+		}
+	}
+
+	return best;
+}
+
+struct commit_dist {
+	struct commit *commit;
+	int distance;
+};
+
+static int compare_commit_dist(const void *a_, const void *b_)
+{
+	struct commit_dist *a, *b;
+
+	a = (struct commit_dist *)a_;
+	b = (struct commit_dist *)b_;
+	if (a->distance != b->distance)
+		return b->distance - a->distance; /* desc sort */
+	return oidcmp(&a->commit->object.oid, &b->commit->object.oid);
+}
+
+static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr)
+{
+	struct commit_list *p;
+	struct commit_dist *array = xcalloc(nr, sizeof(*array));
+	struct strbuf buf = STRBUF_INIT;
+	int cnt, i;
+
+	for (p = list, cnt = 0; p; p = p->next) {
+		int distance;
+		unsigned commit_flags = p->item->object.flags;
+
+		if (commit_flags & TREESAME)
+			continue;
+		distance = weight(p);
+		if (nr - distance < distance)
+			distance = nr - distance;
+		array[cnt].commit = p->item;
+		array[cnt].distance = distance;
+		cnt++;
+	}
+	QSORT(array, cnt, compare_commit_dist);
+	for (p = list, i = 0; i < cnt; i++) {
+		struct object *obj = &(array[i].commit->object);
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "dist=%d", array[i].distance);
+		add_name_decoration(DECORATION_NONE, buf.buf, obj);
+
+		p->item = array[i].commit;
+		if (i < cnt - 1)
+			p = p->next;
+	}
+	if (p) {
+		free_commit_list(p->next);
+		p->next = NULL;
+	}
+	strbuf_release(&buf);
+	free(array);
+	return list;
+}
+
+/*
+ * zero or positive weight is the number of interesting commits it can
+ * reach, including itself.  Especially, weight = 0 means it does not
+ * reach any tree-changing commits (e.g. just above uninteresting one
+ * but traversal is with pathspec).
+ *
+ * weight = -1 means it has one parent and its distance is yet to
+ * be computed.
+ *
+ * weight = -2 means it has more than one parent and its distance is
+ * unknown.  After running count_distance() first, they will get zero
+ * or positive distance.
+ */
+static struct commit_list *do_find_bisection(struct commit_list *list,
+					     int nr, int *weights,
+					     unsigned bisect_flags)
+{
+	int n, counted;
+	struct commit_list *p;
+
+	counted = 0;
+
+	for (n = 0, p = list; p; p = p->next) {
+		struct commit *commit = p->item;
+		unsigned commit_flags = commit->object.flags;
+
+		*commit_weight_at(&commit_weight, p->item) = &weights[n++];
+		switch (count_interesting_parents(commit, bisect_flags)) {
+		case 0:
+			if (!(commit_flags & TREESAME)) {
+				weight_set(p, 1);
+				counted++;
+				show_list("bisection 2 count one",
+					  counted, nr, list);
+			}
+			/*
+			 * otherwise, it is known not to reach any
+			 * tree-changing commit and gets weight 0.
+			 */
+			break;
+		case 1:
+			weight_set(p, -1);
+			break;
+		default:
+			weight_set(p, -2);
+			break;
+		}
+	}
+
+	show_list("bisection 2 initialize", counted, nr, list);
+
+	/*
+	 * If you have only one parent in the resulting set
+	 * then you can reach one commit more than that parent
+	 * can reach.  So we do not have to run the expensive
+	 * count_distance() for single strand of pearls.
+	 *
+	 * However, if you have more than one parents, you cannot
+	 * just add their distance and one for yourself, since
+	 * they usually reach the same ancestor and you would
+	 * end up counting them twice that way.
+	 *
+	 * So we will first count distance of merges the usual
+	 * way, and then fill the blanks using cheaper algorithm.
+	 */
+	for (p = list; p; p = p->next) {
+		if (p->item->object.flags & UNINTERESTING)
+			continue;
+		if (weight(p) != -2)
+			continue;
+		if (bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY)
+			BUG("shouldn't be calling count-distance in fp mode");
+		weight_set(p, count_distance(p));
+		clear_distance(list);
+
+		/* Does it happen to be at half-way? */
+		if (!(bisect_flags & FIND_BISECTION_ALL) &&
+		      approx_halfway(p, nr))
+			return p;
+		counted++;
+	}
+
+	show_list("bisection 2 count_distance", counted, nr, list);
+
+	while (counted < nr) {
+		for (p = list; p; p = p->next) {
+			struct commit_list *q;
+			unsigned commit_flags = p->item->object.flags;
+
+			if (0 <= weight(p))
+				continue;
+
+			for (q = p->item->parents;
+			     q;
+			     q = bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY ? NULL : q->next) {
+				if (q->item->object.flags & UNINTERESTING)
+					continue;
+				if (0 <= weight(q))
+					break;
+			}
+			if (!q)
+				continue;
+
+			/*
+			 * weight for p is unknown but q is known.
+			 * add one for p itself if p is to be counted,
+			 * otherwise inherit it from q directly.
+			 */
+			if (!(commit_flags & TREESAME)) {
+				weight_set(p, weight(q)+1);
+				counted++;
+				show_list("bisection 2 count one",
+					  counted, nr, list);
+			}
+			else
+				weight_set(p, weight(q));
+
+			/* Does it happen to be at half-way? */
+			if (!(bisect_flags & FIND_BISECTION_ALL) &&
+			      approx_halfway(p, nr))
+				return p;
+		}
+	}
+
+	show_list("bisection 2 counted all", counted, nr, list);
+
+	if (!(bisect_flags & FIND_BISECTION_ALL))
+		return best_bisection(list, nr);
+	else
+		return best_bisection_sorted(list, nr);
+}
+
+void find_bisection(struct commit_list **commit_list, int *reaches,
+		    int *all, unsigned bisect_flags)
+{
+	int nr, on_list;
+	struct commit_list *list, *p, *best, *next, *last;
+	int *weights;
+
+	show_list("bisection 2 entry", 0, 0, *commit_list);
+	init_commit_weight(&commit_weight);
+
+	/*
+	 * Count the number of total and tree-changing items on the
+	 * list, while reversing the list.
+	 */
+	for (nr = on_list = 0, last = NULL, p = *commit_list;
+	     p;
+	     p = next) {
+		unsigned commit_flags = p->item->object.flags;
+
+		next = p->next;
+		if (commit_flags & UNINTERESTING) {
+			free(p);
+			continue;
+		}
+		p->next = last;
+		last = p;
+		if (!(commit_flags & TREESAME))
+			nr++;
+		on_list++;
+	}
+	list = last;
+	show_list("bisection 2 sorted", 0, nr, list);
+
+	*all = nr;
+	CALLOC_ARRAY(weights, on_list);
+
+	/* Do the real work of finding bisection commit. */
+	best = do_find_bisection(list, nr, weights, bisect_flags);
+	if (best) {
+		if (!(bisect_flags & FIND_BISECTION_ALL)) {
+			list->item = best->item;
+			free_commit_list(list->next);
+			best = list;
+			best->next = NULL;
+		}
+		*reaches = weight(best);
+	}
+	*commit_list = best;
+
+	free(weights);
+	clear_commit_weight(&commit_weight);
+}
+
+static int register_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+			int flags UNUSED, void *cb_data UNUSED)
+{
+	struct strbuf good_prefix = STRBUF_INIT;
+	strbuf_addstr(&good_prefix, term_good);
+	strbuf_addstr(&good_prefix, "-");
+
+	if (!strcmp(refname, term_bad)) {
+		free(current_bad_oid);
+		current_bad_oid = xmalloc(sizeof(*current_bad_oid));
+		oidcpy(current_bad_oid, oid);
+	} else if (starts_with(refname, good_prefix.buf)) {
+		oid_array_append(&good_revs, oid);
+	} else if (starts_with(refname, "skip-")) {
+		oid_array_append(&skipped_revs, oid);
+	}
+
+	strbuf_release(&good_prefix);
+
+	return 0;
+}
+
+static int read_bisect_refs(void)
+{
+	return refs_for_each_ref_in(get_main_ref_store(the_repository),
+				    "refs/bisect/", register_ref, NULL);
+}
+
+static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
+static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
+static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
+static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
+static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
+
+static void read_bisect_paths(struct strvec *array)
+{
+	struct strbuf str = STRBUF_INIT;
+	const char *filename = git_path_bisect_names();
+	FILE *fp = xfopen(filename, "r");
+
+	while (strbuf_getline_lf(&str, fp) != EOF) {
+		strbuf_trim(&str);
+		if (sq_dequote_to_strvec(str.buf, array))
+			die(_("Badly quoted content in file '%s': %s"),
+			    filename, str.buf);
+	}
+
+	strbuf_release(&str);
+	fclose(fp);
+}
+
+static char *join_oid_array_hex(struct oid_array *array, char delim)
+{
+	struct strbuf joined_hexs = STRBUF_INIT;
+	int i;
+
+	for (i = 0; i < array->nr; i++) {
+		strbuf_addstr(&joined_hexs, oid_to_hex(array->oid + i));
+		if (i + 1 < array->nr)
+			strbuf_addch(&joined_hexs, delim);
+	}
+
+	return strbuf_detach(&joined_hexs, NULL);
+}
+
+/*
+ * In this function, passing a not NULL skipped_first is very special.
+ * It means that we want to know if the first commit in the list is
+ * skipped because we will want to test a commit away from it if it is
+ * indeed skipped.
+ * So if the first commit is skipped, we cannot take the shortcut to
+ * just "return list" when we find the first non skipped commit, we
+ * have to return a fully filtered list.
+ *
+ * We use (*skipped_first == -1) to mean "it has been found that the
+ * first commit is not skipped". In this case *skipped_first is set back
+ * to 0 just before the function returns.
+ */
+struct commit_list *filter_skipped(struct commit_list *list,
+				   struct commit_list **tried,
+				   int show_all,
+				   int *count,
+				   int *skipped_first)
+{
+	struct commit_list *filtered = NULL, **f = &filtered;
+
+	*tried = NULL;
+
+	if (skipped_first)
+		*skipped_first = 0;
+	if (count)
+		*count = 0;
+
+	if (!skipped_revs.nr)
+		return list;
+
+	while (list) {
+		struct commit_list *next = list->next;
+		list->next = NULL;
+		if (0 <= oid_array_lookup(&skipped_revs, &list->item->object.oid)) {
+			if (skipped_first && !*skipped_first)
+				*skipped_first = 1;
+			/* Move current to tried list */
+			*tried = list;
+			tried = &list->next;
+		} else {
+			if (!show_all) {
+				if (!skipped_first || !*skipped_first) {
+					free_commit_list(next);
+					free_commit_list(filtered);
+					return list;
+				}
+			} else if (skipped_first && !*skipped_first) {
+				/* This means we know it's not skipped */
+				*skipped_first = -1;
+			}
+			/* Move current to filtered list */
+			*f = list;
+			f = &list->next;
+			if (count)
+				(*count)++;
+		}
+		list = next;
+	}
+
+	if (skipped_first && *skipped_first == -1)
+		*skipped_first = 0;
+
+	return filtered;
+}
+
+#define PRN_MODULO 32768
+
+/*
+ * This is a pseudo random number generator based on "man 3 rand".
+ * It is not used properly because the seed is the argument and it
+ * is increased by one between each call, but that should not matter
+ * for this application.
+ */
+static unsigned get_prn(unsigned count)
+{
+	count = count * 1103515245 + 12345;
+	return (count/65536) % PRN_MODULO;
+}
+
+/*
+ * Custom integer square root from
+ * https://en.wikipedia.org/wiki/Integer_square_root
+ */
+static int sqrti(int val)
+{
+	float d, x = val;
+
+	if (!val)
+		return 0;
+
+	do {
+		float y = (x + (float)val / x) / 2;
+		d = (y > x) ? y - x : x - y;
+		x = y;
+	} while (d >= 0.5);
+
+	return (int)x;
+}
+
+static struct commit_list *skip_away(struct commit_list *list, int count)
+{
+	struct commit_list *cur, *previous, *result = list;
+	int prn, index, i;
+
+	prn = get_prn(count);
+	index = (count * prn / PRN_MODULO) * sqrti(prn) / sqrti(PRN_MODULO);
+
+	cur = list;
+	previous = NULL;
+
+	for (i = 0; cur; cur = cur->next, i++) {
+		if (i == index) {
+			if (!oideq(&cur->item->object.oid, current_bad_oid))
+				result = cur;
+			else if (previous)
+				result = previous;
+			else
+				result = list;
+			break;
+		}
+		previous = cur;
+	}
+
+	for (cur = list; cur != result; ) {
+		struct commit_list *next = cur->next;
+		free(cur);
+		cur = next;
+	}
+
+	return result;
+}
+
+static struct commit_list *managed_skipped(struct commit_list *list,
+					   struct commit_list **tried)
+{
+	int count, skipped_first;
+
+	*tried = NULL;
+
+	if (!skipped_revs.nr)
+		return list;
+
+	list = filter_skipped(list, tried, 0, &count, &skipped_first);
+
+	if (!skipped_first)
+		return list;
+
+	return skip_away(list, count);
+}
+
+static void bisect_rev_setup(struct repository *r, struct rev_info *revs,
+			     struct strvec *rev_argv,
+			     const char *prefix,
+			     const char *bad_format, const char *good_format,
+			     int read_paths)
+{
+	struct setup_revision_opt opt = {
+		.free_removed_argv_elements = 1,
+	};
+	int i;
+
+	repo_init_revisions(r, revs, prefix);
+	revs->abbrev = 0;
+	revs->commit_format = CMIT_FMT_UNSPECIFIED;
+
+	/* rev_argv.argv[0] will be ignored by setup_revisions */
+	strvec_push(rev_argv, "bisect_rev_setup");
+	strvec_pushf(rev_argv, bad_format, oid_to_hex(current_bad_oid));
+	for (i = 0; i < good_revs.nr; i++)
+		strvec_pushf(rev_argv, good_format,
+			     oid_to_hex(good_revs.oid + i));
+	strvec_push(rev_argv, "--");
+	if (read_paths)
+		read_bisect_paths(rev_argv);
+
+	setup_revisions(rev_argv->nr, rev_argv->v, revs, &opt);
+}
+
+static void bisect_common(struct rev_info *revs)
+{
+	if (prepare_revision_walk(revs))
+		die("revision walk setup failed");
+	if (revs->tree_objects)
+		mark_edges_uninteresting(revs, NULL, 0);
+}
+
+static enum bisect_error error_if_skipped_commits(struct commit_list *tried,
+				    const struct object_id *bad)
+{
+	if (!tried)
+		return BISECT_OK;
+
+	printf("There are only 'skip'ped commits left to test.\n"
+	       "The first %s commit could be any of:\n", term_bad);
+
+	for ( ; tried; tried = tried->next)
+		printf("%s\n", oid_to_hex(&tried->item->object.oid));
+
+	if (bad)
+		printf("%s\n", oid_to_hex(bad));
+	printf(_("We cannot bisect more!\n"));
+
+	return BISECT_ONLY_SKIPPED_LEFT;
+}
+
+static int is_expected_rev(const struct object_id *oid)
+{
+	struct object_id expected_oid;
+	if (refs_read_ref(get_main_ref_store(the_repository), "BISECT_EXPECTED_REV", &expected_oid))
+		return 0;
+	return oideq(oid, &expected_oid);
+}
+
+enum bisect_error bisect_checkout(const struct object_id *bisect_rev,
+				  int no_checkout)
+{
+	struct commit *commit;
+	struct pretty_print_context pp = {0};
+	struct strbuf commit_msg = STRBUF_INIT;
+
+	refs_update_ref(get_main_ref_store(the_repository), NULL,
+			"BISECT_EXPECTED_REV", bisect_rev, NULL, 0,
+			UPDATE_REFS_DIE_ON_ERR);
+
+	if (no_checkout) {
+		refs_update_ref(get_main_ref_store(the_repository), NULL,
+				"BISECT_HEAD", bisect_rev, NULL, 0,
+				UPDATE_REFS_DIE_ON_ERR);
+	} else {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+
+		cmd.git_cmd = 1;
+		strvec_pushl(&cmd.args, "checkout", "-q",
+			     oid_to_hex(bisect_rev), "--", NULL);
+		if (run_command(&cmd))
+			/*
+			 * Errors in `run_command()` itself, signaled by res < 0,
+			 * and errors in the child process, signaled by res > 0
+			 * can both be treated as regular BISECT_FAILED (-1).
+			 */
+			return BISECT_FAILED;
+	}
+
+	commit = lookup_commit_reference(the_repository, bisect_rev);
+	repo_format_commit_message(the_repository, commit, "[%H] %s%n",
+				   &commit_msg, &pp);
+	fputs(commit_msg.buf, stdout);
+	strbuf_release(&commit_msg);
+
+	return BISECT_OK;
+}
+
+static struct commit *get_commit_reference(struct repository *r,
+					   const struct object_id *oid)
+{
+	struct commit *c = lookup_commit_reference(r, oid);
+	if (!c)
+		die(_("Not a valid commit name %s"), oid_to_hex(oid));
+	return c;
+}
+
+static struct commit **get_bad_and_good_commits(struct repository *r,
+						size_t *rev_nr)
+{
+	struct commit **rev;
+	size_t i, n = 0;
+
+	ALLOC_ARRAY(rev, 1 + good_revs.nr);
+	rev[n++] = get_commit_reference(r, current_bad_oid);
+	for (i = 0; i < good_revs.nr; i++)
+		rev[n++] = get_commit_reference(r, good_revs.oid + i);
+	*rev_nr = n;
+
+	return rev;
+}
+
+static enum bisect_error handle_bad_merge_base(void)
+{
+	if (is_expected_rev(current_bad_oid)) {
+		char *bad_hex = oid_to_hex(current_bad_oid);
+		char *good_hex = join_oid_array_hex(&good_revs, ' ');
+		if (!strcmp(term_bad, "bad") && !strcmp(term_good, "good")) {
+			fprintf(stderr, _("The merge base %s is bad.\n"
+				"This means the bug has been fixed "
+				"between %s and [%s].\n"),
+				bad_hex, bad_hex, good_hex);
+		} else if (!strcmp(term_bad, "new") && !strcmp(term_good, "old")) {
+			fprintf(stderr, _("The merge base %s is new.\n"
+				"The property has changed "
+				"between %s and [%s].\n"),
+				bad_hex, bad_hex, good_hex);
+		} else {
+			fprintf(stderr, _("The merge base %s is %s.\n"
+				"This means the first '%s' commit is "
+				"between %s and [%s].\n"),
+				bad_hex, term_bad, term_good, bad_hex, good_hex);
+		}
+
+		free(good_hex);
+		return BISECT_MERGE_BASE_CHECK;
+	}
+
+	fprintf(stderr, _("Some %s revs are not ancestors of the %s rev.\n"
+		"git bisect cannot work properly in this case.\n"
+		"Maybe you mistook %s and %s revs?\n"),
+		term_good, term_bad, term_good, term_bad);
+	return BISECT_FAILED;
+}
+
+static void handle_skipped_merge_base(const struct object_id *mb)
+{
+	char *mb_hex = oid_to_hex(mb);
+	char *bad_hex = oid_to_hex(current_bad_oid);
+	char *good_hex = join_oid_array_hex(&good_revs, ' ');
+
+	warning(_("the merge base between %s and [%s] "
+		"must be skipped.\n"
+		"So we cannot be sure the first %s commit is "
+		"between %s and %s.\n"
+		"We continue anyway."),
+		bad_hex, good_hex, term_bad, mb_hex, bad_hex);
+	free(good_hex);
+}
+
+/*
+ * "check_merge_bases" checks that merge bases are not "bad" (or "new").
+ *
+ * - If one is "bad" (or "new"), it means the user assumed something wrong
+ * and we must return error with a non 0 error code.
+ * - If one is "good" (or "old"), that's good, we have nothing to do.
+ * - If one is "skipped", we can't know but we should warn.
+ * - If we don't know, we should check it out and ask the user to test.
+ * - If a merge base must be tested, on success return
+ * BISECT_INTERNAL_SUCCESS_MERGE_BASE (-11) a special condition
+ * for early success, this will be converted back to 0 in
+ * check_good_are_ancestors_of_bad().
+ */
+static enum bisect_error check_merge_bases(size_t rev_nr, struct commit **rev, int no_checkout)
+{
+	enum bisect_error res = BISECT_OK;
+	struct commit_list *result = NULL;
+
+	if (repo_get_merge_bases_many(the_repository, rev[0], rev_nr - 1,
+				      rev + 1, &result) < 0)
+		exit(128);
+
+	for (struct commit_list *l = result; l; l = l->next) {
+		const struct object_id *mb = &l->item->object.oid;
+		if (oideq(mb, current_bad_oid)) {
+			res = handle_bad_merge_base();
+			break;
+		} else if (0 <= oid_array_lookup(&good_revs, mb)) {
+			continue;
+		} else if (0 <= oid_array_lookup(&skipped_revs, mb)) {
+			handle_skipped_merge_base(mb);
+		} else {
+			printf(_("Bisecting: a merge base must be tested\n"));
+			res = bisect_checkout(mb, no_checkout);
+			if (!res)
+				/* indicate early success */
+				res = BISECT_INTERNAL_SUCCESS_MERGE_BASE;
+			break;
+		}
+	}
+
+	free_commit_list(result);
+	return res;
+}
+
+static int check_ancestors(struct repository *r, size_t rev_nr,
+			   struct commit **rev, const char *prefix)
+{
+	struct strvec rev_argv = STRVEC_INIT;
+	struct rev_info revs;
+	int res;
+
+	bisect_rev_setup(r, &revs, &rev_argv, prefix, "^%s", "%s", 0);
+
+	bisect_common(&revs);
+	res = (revs.commits != NULL);
+
+	/* Clean up objects used, as they will be reused. */
+	clear_commit_marks_many(rev_nr, rev, ALL_REV_FLAGS);
+
+	release_revisions(&revs);
+	strvec_clear(&rev_argv);
+	return res;
+}
+
+/*
+ * "check_good_are_ancestors_of_bad" checks that all "good" revs are
+ * ancestor of the "bad" rev.
+ *
+ * If that's not the case, we need to check the merge bases.
+ * If a merge base must be tested by the user, its source code will be
+ * checked out to be tested by the user and we will return.
+ */
+
+static enum bisect_error check_good_are_ancestors_of_bad(struct repository *r,
+					    const char *prefix,
+					    int no_checkout)
+{
+	char *filename;
+	struct stat st;
+	int fd;
+	size_t rev_nr;
+	enum bisect_error res = BISECT_OK;
+	struct commit **rev;
+
+	if (!current_bad_oid)
+		return error(_("a %s revision is needed"), term_bad);
+
+	filename = git_pathdup("BISECT_ANCESTORS_OK");
+
+	/* Check if file BISECT_ANCESTORS_OK exists. */
+	if (!stat(filename, &st) && S_ISREG(st.st_mode))
+		goto done;
+
+	/* Bisecting with no good rev is ok. */
+	if (!good_revs.nr)
+		goto done;
+
+	/* Check if all good revs are ancestor of the bad rev. */
+
+	rev = get_bad_and_good_commits(r, &rev_nr);
+	if (check_ancestors(r, rev_nr, rev, prefix))
+		res = check_merge_bases(rev_nr, rev, no_checkout);
+	free(rev);
+
+	if (!res) {
+		/* Create file BISECT_ANCESTORS_OK. */
+		fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+		if (fd < 0)
+			/*
+			 * BISECT_ANCESTORS_OK file is not absolutely necessary,
+			 * the bisection process will continue at the next
+			 * bisection step.
+			 * So, just signal with a warning that something
+			 * might be wrong.
+			 */
+			warning_errno(_("could not create file '%s'"),
+				filename);
+		else
+			close(fd);
+	}
+ done:
+	free(filename);
+	return res;
+}
+
+/*
+ * Display a commit summary to the user.
+ */
+static void show_commit(struct commit *commit)
+{
+	struct child_process show = CHILD_PROCESS_INIT;
+
+	/*
+	 * Call git show with --no-pager, as it would otherwise
+	 * paginate the "git show" output only, not the output
+	 * from bisect_next_all(); this can be fixed by moving
+	 * it into a --format parameter, but that would override
+	 * the user's default options for "git show", which we
+	 * are trying to honour.
+	 */
+	strvec_pushl(&show.args,
+		     "--no-pager",
+		     "show",
+		     "--stat",
+		     "--summary",
+		     "--no-abbrev-commit",
+		     "--diff-merges=first-parent",
+		     oid_to_hex(&commit->object.oid), NULL);
+	show.git_cmd = 1;
+	if (run_command(&show))
+		die(_("unable to start 'show' for object '%s'"),
+		    oid_to_hex(&commit->object.oid));
+}
+
+/*
+ * The terms used for this bisect session are stored in BISECT_TERMS.
+ * We read them and store them to adapt the messages accordingly.
+ * Default is bad/good.
+ */
+void read_bisect_terms(char **read_bad, char **read_good)
+{
+	struct strbuf str = STRBUF_INIT;
+	const char *filename = git_path_bisect_terms();
+	FILE *fp = fopen(filename, "r");
+
+	if (!fp) {
+		if (errno == ENOENT) {
+			free(*read_bad);
+			*read_bad = xstrdup("bad");
+			free(*read_good);
+			*read_good = xstrdup("good");
+			return;
+		} else {
+			die_errno(_("could not read file '%s'"), filename);
+		}
+	} else {
+		strbuf_getline_lf(&str, fp);
+		free(*read_bad);
+		*read_bad = strbuf_detach(&str, NULL);
+		strbuf_getline_lf(&str, fp);
+		free(*read_good);
+		*read_good = strbuf_detach(&str, NULL);
+	}
+	strbuf_release(&str);
+	fclose(fp);
+}
+
+/*
+ * We use the convention that return BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND (-10) means
+ * the bisection process finished successfully.
+ * In this case the calling function or command should not turn a
+ * BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND return code into an error or a non zero exit code.
+ *
+ * Checking BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND
+ * in bisect_helper::bisect_next() and only transforming it to 0 at
+ * the end of bisect_helper::cmd_bisect__helper() helps bypassing
+ * all the code related to finding a commit to test.
+ */
+enum bisect_error bisect_next_all(struct repository *r, const char *prefix)
+{
+	struct strvec rev_argv = STRVEC_INIT;
+	struct rev_info revs = REV_INFO_INIT;
+	struct commit_list *tried = NULL;
+	int reaches = 0, all = 0, nr, steps;
+	enum bisect_error res = BISECT_OK;
+	struct object_id *bisect_rev;
+	char *steps_msg;
+	/*
+	 * If no_checkout is non-zero, the bisection process does not
+	 * checkout the trial commit but instead simply updates BISECT_HEAD.
+	 */
+	int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
+					  "BISECT_HEAD");
+	unsigned bisect_flags = 0;
+
+	read_bisect_terms(&term_bad, &term_good);
+	if (read_bisect_refs())
+		die(_("reading bisect refs failed"));
+
+	if (file_exists(git_path_bisect_first_parent()))
+		bisect_flags |= FIND_BISECTION_FIRST_PARENT_ONLY;
+
+	if (skipped_revs.nr)
+		bisect_flags |= FIND_BISECTION_ALL;
+
+	res = check_good_are_ancestors_of_bad(r, prefix, no_checkout);
+	if (res)
+		goto cleanup;
+
+	bisect_rev_setup(r, &revs, &rev_argv, prefix, "%s", "^%s", 1);
+
+	revs.first_parent_only = !!(bisect_flags & FIND_BISECTION_FIRST_PARENT_ONLY);
+	revs.limited = 1;
+
+	bisect_common(&revs);
+
+	find_bisection(&revs.commits, &reaches, &all, bisect_flags);
+	revs.commits = managed_skipped(revs.commits, &tried);
+
+	if (!revs.commits) {
+		/*
+		 * We should return error here only if the "bad"
+		 * commit is also a "skip" commit.
+		 */
+		res = error_if_skipped_commits(tried, NULL);
+		if (res < 0)
+			goto cleanup;
+		printf(_("%s was both %s and %s\n"),
+		       oid_to_hex(current_bad_oid),
+		       term_good,
+		       term_bad);
+
+		res = BISECT_FAILED;
+		goto cleanup;
+	}
+
+	if (!all) {
+		fprintf(stderr, _("No testable commit found.\n"
+			"Maybe you started with bad path arguments?\n"));
+
+		res = BISECT_NO_TESTABLE_COMMIT;
+		goto cleanup;
+	}
+
+	bisect_rev = &revs.commits->item->object.oid;
+
+	if (oideq(bisect_rev, current_bad_oid)) {
+		res = error_if_skipped_commits(tried, current_bad_oid);
+		if (res)
+			goto cleanup;
+		printf("%s is the first %s commit\n", oid_to_hex(bisect_rev),
+			term_bad);
+
+		show_commit(revs.commits->item);
+		/*
+		 * This means the bisection process succeeded.
+		 * Using BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND (-10)
+		 * so that the call chain can simply check
+		 * for negative return values for early returns up
+		 * until the cmd_bisect__helper() caller.
+		 */
+		res = BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
+		goto cleanup;
+	}
+
+	nr = all - reaches - 1;
+	steps = estimate_bisect_steps(all);
+
+	steps_msg = xstrfmt(Q_("(roughly %d step)", "(roughly %d steps)",
+		  steps), steps);
+	/*
+	 * TRANSLATORS: the last %s will be replaced with "(roughly %d
+	 * steps)" translation.
+	 */
+	printf(Q_("Bisecting: %d revision left to test after this %s\n",
+		  "Bisecting: %d revisions left to test after this %s\n",
+		  nr), nr, steps_msg);
+	free(steps_msg);
+	/* Clean up objects used, as they will be reused. */
+	repo_clear_commit_marks(r, ALL_REV_FLAGS);
+
+	res = bisect_checkout(bisect_rev, no_checkout);
+cleanup:
+	free_commit_list(tried);
+	release_revisions(&revs);
+	strvec_clear(&rev_argv);
+	return res;
+}
+
+static inline int exp2i(int n)
+{
+	return 1 << n;
+}
+
+/*
+ * Estimate the number of bisect steps left (after the current step)
+ *
+ * For any x between 0 included and 2^n excluded, the probability for
+ * n - 1 steps left looks like:
+ *
+ * P(2^n + x) == (2^n - x) / (2^n + x)
+ *
+ * and P(2^n + x) < 0.5 means 2^n < 3x
+ */
+int estimate_bisect_steps(int all)
+{
+	int n, x, e;
+
+	if (all < 3)
+		return 0;
+
+	n = log2u(all);
+	e = exp2i(n);
+	x = all - e;
+
+	return (e < 3 * x) ? n : n - 1;
+}
+
+static int mark_for_removal(const char *refname,
+			    const char *referent UNUSED,
+			    const struct object_id *oid UNUSED,
+			    int flag UNUSED, void *cb_data)
+{
+	struct string_list *refs = cb_data;
+	char *ref = xstrfmt("refs/bisect%s", refname);
+	string_list_append(refs, ref);
+	return 0;
+}
+
+int bisect_clean_state(void)
+{
+	int result = 0;
+
+	/* There may be some refs packed during bisection */
+	struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
+	refs_for_each_ref_in(get_main_ref_store(the_repository),
+			     "refs/bisect", mark_for_removal,
+			     (void *) &refs_for_removal);
+	string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
+	string_list_append(&refs_for_removal, xstrdup("BISECT_EXPECTED_REV"));
+	result = refs_delete_refs(get_main_ref_store(the_repository),
+				  "bisect: remove", &refs_for_removal,
+				  REF_NO_DEREF);
+	refs_for_removal.strdup_strings = 1;
+	string_list_clear(&refs_for_removal, 0);
+	unlink_or_warn(git_path_bisect_ancestors_ok());
+	unlink_or_warn(git_path_bisect_log());
+	unlink_or_warn(git_path_bisect_names());
+	unlink_or_warn(git_path_bisect_run());
+	unlink_or_warn(git_path_bisect_terms());
+	unlink_or_warn(git_path_bisect_first_parent());
+	/*
+	 * Cleanup BISECT_START last to support the --no-checkout option
+	 * introduced in the commit 4796e823a.
+	 */
+	unlink_or_warn(git_path_bisect_start());
+
+	return result;
+}
diff --git a/bisect.h b/bisect.h
new file mode 100644
index 0000000000..944439bfac
--- /dev/null
+++ b/bisect.h
@@ -0,0 +1,85 @@
+#ifndef BISECT_H
+#define BISECT_H
+
+struct commit_list;
+struct repository;
+struct object_id;
+
+/*
+ * Find bisection. If something is found, `reaches` will be the number of
+ * commits that the best commit reaches. `all` will be the count of
+ * non-SAMETREE commits. If nothing is found, `list` will be NULL.
+ * Otherwise, it will be either all non-SAMETREE commits or the single
+ * best commit, as chosen by `find_all`.
+ */
+void find_bisection(struct commit_list **list, int *reaches, int *all,
+		    unsigned bisect_flags);
+
+struct commit_list *filter_skipped(struct commit_list *list,
+				   struct commit_list **tried,
+				   int show_all,
+				   int *count,
+				   int *skipped_first);
+
+#define BISECT_SHOW_ALL		(1<<0)
+#define REV_LIST_QUIET		(1<<1)
+
+#define FIND_BISECTION_ALL			(1u<<0)
+#define FIND_BISECTION_FIRST_PARENT_ONLY	(1u<<1)
+
+struct rev_list_info {
+	struct rev_info *revs;
+	int flags;
+	int show_timestamp;
+	int hdr_termination;
+	const char *header_prefix;
+};
+
+/*
+ * enum bisect_error represents the following return codes:
+ * BISECT_OK: success code. Internally, it means that next
+ * commit has been found (and possibly checked out) and it
+ * should be tested.
+ * BISECT_FAILED error code: default error code.
+ * BISECT_ONLY_SKIPPED_LEFT error code: only skipped
+ * commits left to be tested.
+ * BISECT_MERGE_BASE_CHECK error code: merge base check failed.
+ * BISECT_NO_TESTABLE_COMMIT error code: no testable commit found.
+ * BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND early success code:
+ * first term_bad commit found.
+ * BISECT_INTERNAL_SUCCESS_MERGE_BASE early success
+ * code: found merge base that should be tested.
+ * Early success codes BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND and
+ * BISECT_INTERNAL_SUCCESS_MERGE_BASE should be only internal codes.
+ */
+enum bisect_error {
+	BISECT_OK = 0,
+	BISECT_FAILED = -1,
+	BISECT_ONLY_SKIPPED_LEFT = -2,
+	BISECT_MERGE_BASE_CHECK = -3,
+	BISECT_NO_TESTABLE_COMMIT = -4,
+	BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND = -10,
+	BISECT_INTERNAL_SUCCESS_MERGE_BASE = -11
+};
+
+/*
+ * Stores how many good/bad commits we have stored for a bisect. nr_bad can
+ * only be 0 or 1.
+ */
+struct bisect_state {
+	unsigned int nr_good;
+	unsigned int nr_bad;
+};
+
+enum bisect_error bisect_next_all(struct repository *r, const char *prefix);
+
+int estimate_bisect_steps(int all);
+
+void read_bisect_terms(char **bad, char **good);
+
+int bisect_clean_state(void);
+
+enum bisect_error bisect_checkout(const struct object_id *bisect_rev,
+				  int no_checkout);
+
+#endif
diff --git a/blame.c b/blame.c
new file mode 100644
index 0000000000..a15ddf9333
--- /dev/null
+++ b/blame.c
@@ -0,0 +1,2953 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "refs.h"
+#include "object-store-ll.h"
+#include "cache-tree.h"
+#include "mergesort.h"
+#include "commit.h"
+#include "convert.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "gettext.h"
+#include "hex.h"
+#include "path.h"
+#include "read-cache.h"
+#include "revision.h"
+#include "setup.h"
+#include "tag.h"
+#include "trace2.h"
+#include "blame.h"
+#include "alloc.h"
+#include "commit-slab.h"
+#include "bloom.h"
+#include "commit-graph.h"
+
+define_commit_slab(blame_suspects, struct blame_origin *);
+static struct blame_suspects blame_suspects;
+
+struct blame_origin *get_blame_suspects(struct commit *commit)
+{
+	struct blame_origin **result;
+
+	result = blame_suspects_peek(&blame_suspects, commit);
+
+	return result ? *result : NULL;
+}
+
+static void set_blame_suspects(struct commit *commit, struct blame_origin *origin)
+{
+	*blame_suspects_at(&blame_suspects, commit) = origin;
+}
+
+void blame_origin_decref(struct blame_origin *o)
+{
+	if (o && --o->refcnt <= 0) {
+		struct blame_origin *p, *l = NULL;
+		if (o->previous)
+			blame_origin_decref(o->previous);
+		free(o->file.ptr);
+		/* Should be present exactly once in commit chain */
+		for (p = get_blame_suspects(o->commit); p; l = p, p = p->next) {
+			if (p == o) {
+				if (l)
+					l->next = p->next;
+				else
+					set_blame_suspects(o->commit, p->next);
+				free(o);
+				return;
+			}
+		}
+		die("internal error in blame_origin_decref");
+	}
+}
+
+/*
+ * Given a commit and a path in it, create a new origin structure.
+ * The callers that add blame to the scoreboard should use
+ * get_origin() to obtain shared, refcounted copy instead of calling
+ * this function directly.
+ */
+static struct blame_origin *make_origin(struct commit *commit, const char *path)
+{
+	struct blame_origin *o;
+	FLEX_ALLOC_STR(o, path, path);
+	o->commit = commit;
+	o->refcnt = 1;
+	o->next = get_blame_suspects(commit);
+	set_blame_suspects(commit, o);
+	return o;
+}
+
+/*
+ * Locate an existing origin or create a new one.
+ * This moves the origin to front position in the commit util list.
+ */
+static struct blame_origin *get_origin(struct commit *commit, const char *path)
+{
+	struct blame_origin *o, *l;
+
+	for (o = get_blame_suspects(commit), l = NULL; o; l = o, o = o->next) {
+		if (!strcmp(o->path, path)) {
+			/* bump to front */
+			if (l) {
+				l->next = o->next;
+				o->next = get_blame_suspects(commit);
+				set_blame_suspects(commit, o);
+			}
+			return blame_origin_incref(o);
+		}
+	}
+	return make_origin(commit, path);
+}
+
+
+
+static void verify_working_tree_path(struct repository *r,
+				     struct commit *work_tree, const char *path)
+{
+	struct commit_list *parents;
+	int pos;
+
+	for (parents = work_tree->parents; parents; parents = parents->next) {
+		const struct object_id *commit_oid = &parents->item->object.oid;
+		struct object_id blob_oid;
+		unsigned short mode;
+
+		if (!get_tree_entry(r, commit_oid, path, &blob_oid, &mode) &&
+		    oid_object_info(r, &blob_oid, NULL) == OBJ_BLOB)
+			return;
+	}
+
+	pos = index_name_pos(r->index, path, strlen(path));
+	if (pos >= 0)
+		; /* path is in the index */
+	else if (-1 - pos < r->index->cache_nr &&
+		 !strcmp(r->index->cache[-1 - pos]->name, path))
+		; /* path is in the index, unmerged */
+	else
+		die("no such path '%s' in HEAD", path);
+}
+
+static struct commit_list **append_parent(struct repository *r,
+					  struct commit_list **tail,
+					  const struct object_id *oid)
+{
+	struct commit *parent;
+
+	parent = lookup_commit_reference(r, oid);
+	if (!parent)
+		die("no such commit %s", oid_to_hex(oid));
+	return &commit_list_insert(parent, tail)->next;
+}
+
+static void append_merge_parents(struct repository *r,
+				 struct commit_list **tail)
+{
+	int merge_head;
+	struct strbuf line = STRBUF_INIT;
+
+	merge_head = open(git_path_merge_head(r), O_RDONLY);
+	if (merge_head < 0) {
+		if (errno == ENOENT)
+			return;
+		die("cannot open '%s' for reading",
+		    git_path_merge_head(r));
+	}
+
+	while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
+		struct object_id oid;
+		if (get_oid_hex(line.buf, &oid))
+			die("unknown line in '%s': %s",
+			    git_path_merge_head(r), line.buf);
+		tail = append_parent(r, tail, &oid);
+	}
+	close(merge_head);
+	strbuf_release(&line);
+}
+
+/*
+ * This isn't as simple as passing sb->buf and sb->len, because we
+ * want to transfer ownership of the buffer to the commit (so we
+ * must use detach).
+ */
+static void set_commit_buffer_from_strbuf(struct repository *r,
+					  struct commit *c,
+					  struct strbuf *sb)
+{
+	size_t len;
+	void *buf = strbuf_detach(sb, &len);
+	set_commit_buffer(r, c, buf, len);
+}
+
+/*
+ * Prepare a dummy commit that represents the work tree (or staged) item.
+ * Note that annotating work tree item never works in the reverse.
+ */
+static struct commit *fake_working_tree_commit(struct repository *r,
+					       struct diff_options *opt,
+					       const char *path,
+					       const char *contents_from,
+					       struct object_id *oid)
+{
+	struct commit *commit;
+	struct blame_origin *origin;
+	struct commit_list **parent_tail, *parent;
+	struct strbuf buf = STRBUF_INIT;
+	const char *ident;
+	time_t now;
+	int len;
+	struct cache_entry *ce;
+	unsigned mode;
+	struct strbuf msg = STRBUF_INIT;
+
+	repo_read_index(r);
+	time(&now);
+	commit = alloc_commit_node(r);
+	commit->object.parsed = 1;
+	commit->date = now;
+	parent_tail = &commit->parents;
+
+	parent_tail = append_parent(r, parent_tail, oid);
+	append_merge_parents(r, parent_tail);
+	verify_working_tree_path(r, commit, path);
+
+	origin = make_origin(commit, path);
+
+	if (contents_from)
+		ident = fmt_ident("External file (--contents)", "external.file",
+				  WANT_BLANK_IDENT, NULL, 0);
+	else
+		ident = fmt_ident("Not Committed Yet", "not.committed.yet",
+				  WANT_BLANK_IDENT, NULL, 0);
+	strbuf_addstr(&msg, "tree 0000000000000000000000000000000000000000\n");
+	for (parent = commit->parents; parent; parent = parent->next)
+		strbuf_addf(&msg, "parent %s\n",
+			    oid_to_hex(&parent->item->object.oid));
+	strbuf_addf(&msg,
+		    "author %s\n"
+		    "committer %s\n\n"
+		    "Version of %s from %s\n",
+		    ident, ident, path,
+		    (!contents_from ? path :
+		     (!strcmp(contents_from, "-") ? "standard input" : contents_from)));
+	set_commit_buffer_from_strbuf(r, commit, &msg);
+
+	if (!contents_from || strcmp("-", contents_from)) {
+		struct stat st;
+		const char *read_from;
+		char *buf_ptr;
+		unsigned long buf_len;
+
+		if (contents_from) {
+			if (stat(contents_from, &st) < 0)
+				die_errno("Cannot stat '%s'", contents_from);
+			read_from = contents_from;
+		}
+		else {
+			if (lstat(path, &st) < 0)
+				die_errno("Cannot lstat '%s'", path);
+			read_from = path;
+		}
+		mode = canon_mode(st.st_mode);
+
+		switch (st.st_mode & S_IFMT) {
+		case S_IFREG:
+			if (opt->flags.allow_textconv &&
+			    textconv_object(r, read_from, mode, null_oid(), 0, &buf_ptr, &buf_len))
+				strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
+			else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
+				die_errno("cannot open or read '%s'", read_from);
+			break;
+		case S_IFLNK:
+			if (strbuf_readlink(&buf, read_from, st.st_size) < 0)
+				die_errno("cannot readlink '%s'", read_from);
+			break;
+		default:
+			die("unsupported file type %s", read_from);
+		}
+	}
+	else {
+		/* Reading from stdin */
+		mode = 0;
+		if (strbuf_read(&buf, 0, 0) < 0)
+			die_errno("failed to read from stdin");
+	}
+	convert_to_git(r->index, path, buf.buf, buf.len, &buf, 0);
+	origin->file.ptr = buf.buf;
+	origin->file.size = buf.len;
+	pretend_object_file(buf.buf, buf.len, OBJ_BLOB, &origin->blob_oid);
+
+	/*
+	 * Read the current index, replace the path entry with
+	 * origin->blob_sha1 without mucking with its mode or type
+	 * bits; we are not going to write this index out -- we just
+	 * want to run "diff-index --cached".
+	 */
+	discard_index(r->index);
+	repo_read_index(r);
+
+	len = strlen(path);
+	if (!mode) {
+		int pos = index_name_pos(r->index, path, len);
+		if (0 <= pos)
+			mode = r->index->cache[pos]->ce_mode;
+		else
+			/* Let's not bother reading from HEAD tree */
+			mode = S_IFREG | 0644;
+	}
+	ce = make_empty_cache_entry(r->index, len);
+	oidcpy(&ce->oid, &origin->blob_oid);
+	memcpy(ce->name, path, len);
+	ce->ce_flags = create_ce_flags(0);
+	ce->ce_namelen = len;
+	ce->ce_mode = create_ce_mode(mode);
+	add_index_entry(r->index, ce,
+			ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+
+	cache_tree_invalidate_path(r->index, path);
+
+	return commit;
+}
+
+
+
+static int diff_hunks(mmfile_t *file_a, mmfile_t *file_b,
+		      xdl_emit_hunk_consume_func_t hunk_func, void *cb_data, int xdl_opts)
+{
+	xpparam_t xpp = {0};
+	xdemitconf_t xecfg = {0};
+	xdemitcb_t ecb = {NULL};
+
+	xpp.flags = xdl_opts;
+	xecfg.hunk_func = hunk_func;
+	ecb.priv = cb_data;
+	return xdi_diff(file_a, file_b, &xpp, &xecfg, &ecb);
+}
+
+static const char *get_next_line(const char *start, const char *end)
+{
+	const char *nl = memchr(start, '\n', end - start);
+
+	return nl ? nl + 1 : end;
+}
+
+static int find_line_starts(int **line_starts, const char *buf,
+			    unsigned long len)
+{
+	const char *end = buf + len;
+	const char *p;
+	int *lineno;
+	int num = 0;
+
+	for (p = buf; p < end; p = get_next_line(p, end))
+		num++;
+
+	ALLOC_ARRAY(*line_starts, num + 1);
+	lineno = *line_starts;
+
+	for (p = buf; p < end; p = get_next_line(p, end))
+		*lineno++ = p - buf;
+
+	*lineno = len;
+
+	return num;
+}
+
+struct fingerprint_entry;
+
+/* A fingerprint is intended to loosely represent a string, such that two
+ * fingerprints can be quickly compared to give an indication of the similarity
+ * of the strings that they represent.
+ *
+ * A fingerprint is represented as a multiset of the lower-cased byte pairs in
+ * the string that it represents. Whitespace is added at each end of the
+ * string. Whitespace pairs are ignored. Whitespace is converted to '\0'.
+ * For example, the string "Darth   Radar" will be converted to the following
+ * fingerprint:
+ * {"\0d", "da", "da", "ar", "ar", "rt", "th", "h\0", "\0r", "ra", "ad", "r\0"}
+ *
+ * The similarity between two fingerprints is the size of the intersection of
+ * their multisets, including repeated elements. See fingerprint_similarity for
+ * examples.
+ *
+ * For ease of implementation, the fingerprint is implemented as a map
+ * of byte pairs to the count of that byte pair in the string, instead of
+ * allowing repeated elements in a set.
+ */
+struct fingerprint {
+	struct hashmap map;
+	/* As we know the maximum number of entries in advance, it's
+	 * convenient to store the entries in a single array instead of having
+	 * the hashmap manage the memory.
+	 */
+	struct fingerprint_entry *entries;
+};
+
+/* A byte pair in a fingerprint. Stores the number of times the byte pair
+ * occurs in the string that the fingerprint represents.
+ */
+struct fingerprint_entry {
+	/* The hashmap entry - the hash represents the byte pair in its
+	 * entirety so we don't need to store the byte pair separately.
+	 */
+	struct hashmap_entry entry;
+	/* The number of times the byte pair occurs in the string that the
+	 * fingerprint represents.
+	 */
+	int count;
+};
+
+/* See `struct fingerprint` for an explanation of what a fingerprint is.
+ * \param result the fingerprint of the string is stored here. This must be
+ * 		 freed later using free_fingerprint.
+ * \param line_begin the start of the string
+ * \param line_end the end of the string
+ */
+static void get_fingerprint(struct fingerprint *result,
+			    const char *line_begin,
+			    const char *line_end)
+{
+	unsigned int hash, c0 = 0, c1;
+	const char *p;
+	int max_map_entry_count = 1 + line_end - line_begin;
+	struct fingerprint_entry *entry = xcalloc(max_map_entry_count,
+		sizeof(struct fingerprint_entry));
+	struct fingerprint_entry *found_entry;
+
+	hashmap_init(&result->map, NULL, NULL, max_map_entry_count);
+	result->entries = entry;
+	for (p = line_begin; p <= line_end; ++p, c0 = c1) {
+		/* Always terminate the string with whitespace.
+		 * Normalise whitespace to 0, and normalise letters to
+		 * lower case. This won't work for multibyte characters but at
+		 * worst will match some unrelated characters.
+		 */
+		if ((p == line_end) || isspace(*p))
+			c1 = 0;
+		else
+			c1 = tolower(*p);
+		hash = c0 | (c1 << 8);
+		/* Ignore whitespace pairs */
+		if (hash == 0)
+			continue;
+		hashmap_entry_init(&entry->entry, hash);
+
+		found_entry = hashmap_get_entry(&result->map, entry,
+						/* member name */ entry, NULL);
+		if (found_entry) {
+			found_entry->count += 1;
+		} else {
+			entry->count = 1;
+			hashmap_add(&result->map, &entry->entry);
+			++entry;
+		}
+	}
+}
+
+static void free_fingerprint(struct fingerprint *f)
+{
+	hashmap_clear(&f->map);
+	free(f->entries);
+}
+
+/* Calculates the similarity between two fingerprints as the size of the
+ * intersection of their multisets, including repeated elements. See
+ * `struct fingerprint` for an explanation of the fingerprint representation.
+ * The similarity between "cat mat" and "father rather" is 2 because "at" is
+ * present twice in both strings while the similarity between "tim" and "mit"
+ * is 0.
+ */
+static int fingerprint_similarity(struct fingerprint *a, struct fingerprint *b)
+{
+	int intersection = 0;
+	struct hashmap_iter iter;
+	const struct fingerprint_entry *entry_a, *entry_b;
+
+	hashmap_for_each_entry(&b->map, &iter, entry_b,
+				entry /* member name */) {
+		entry_a = hashmap_get_entry(&a->map, entry_b, entry, NULL);
+		if (entry_a) {
+			intersection += entry_a->count < entry_b->count ?
+					entry_a->count : entry_b->count;
+		}
+	}
+	return intersection;
+}
+
+/* Subtracts byte-pair elements in B from A, modifying A in place.
+ */
+static void fingerprint_subtract(struct fingerprint *a, struct fingerprint *b)
+{
+	struct hashmap_iter iter;
+	struct fingerprint_entry *entry_a;
+	const struct fingerprint_entry *entry_b;
+
+	hashmap_iter_init(&b->map, &iter);
+
+	hashmap_for_each_entry(&b->map, &iter, entry_b,
+				entry /* member name */) {
+		entry_a = hashmap_get_entry(&a->map, entry_b, entry, NULL);
+		if (entry_a) {
+			if (entry_a->count <= entry_b->count)
+				hashmap_remove(&a->map, &entry_b->entry, NULL);
+			else
+				entry_a->count -= entry_b->count;
+		}
+	}
+}
+
+/* Calculate fingerprints for a series of lines.
+ * Puts the fingerprints in the fingerprints array, which must have been
+ * preallocated to allow storing line_count elements.
+ */
+static void get_line_fingerprints(struct fingerprint *fingerprints,
+				  const char *content, const int *line_starts,
+				  long first_line, long line_count)
+{
+	int i;
+	const char *linestart, *lineend;
+
+	line_starts += first_line;
+	for (i = 0; i < line_count; ++i) {
+		linestart = content + line_starts[i];
+		lineend = content + line_starts[i + 1];
+		get_fingerprint(fingerprints + i, linestart, lineend);
+	}
+}
+
+static void free_line_fingerprints(struct fingerprint *fingerprints,
+				   int nr_fingerprints)
+{
+	int i;
+
+	for (i = 0; i < nr_fingerprints; i++)
+		free_fingerprint(&fingerprints[i]);
+}
+
+/* This contains the data necessary to linearly map a line number in one half
+ * of a diff chunk to the line in the other half of the diff chunk that is
+ * closest in terms of its position as a fraction of the length of the chunk.
+ */
+struct line_number_mapping {
+	int destination_start, destination_length,
+		source_start, source_length;
+};
+
+/* Given a line number in one range, offset and scale it to map it onto the
+ * other range.
+ * Essentially this mapping is a simple linear equation but the calculation is
+ * more complicated to allow performing it with integer operations.
+ * Another complication is that if a line could map onto many lines in the
+ * destination range then we want to choose the line at the center of those
+ * possibilities.
+ * Example: if the chunk is 2 lines long in A and 10 lines long in B then the
+ * first 5 lines in B will map onto the first line in the A chunk, while the
+ * last 5 lines will all map onto the second line in the A chunk.
+ * Example: if the chunk is 10 lines long in A and 2 lines long in B then line
+ * 0 in B will map onto line 2 in A, and line 1 in B will map onto line 7 in A.
+ */
+static int map_line_number(int line_number,
+	const struct line_number_mapping *mapping)
+{
+	return ((line_number - mapping->source_start) * 2 + 1) *
+	       mapping->destination_length /
+	       (mapping->source_length * 2) +
+	       mapping->destination_start;
+}
+
+/* Get a pointer to the element storing the similarity between a line in A
+ * and a line in B.
+ *
+ * The similarities are stored in a 2-dimensional array. Each "row" in the
+ * array contains the similarities for a line in B. The similarities stored in
+ * a row are the similarities between the line in B and the nearby lines in A.
+ * To keep the length of each row the same, it is padded out with values of -1
+ * where the search range extends beyond the lines in A.
+ * For example, if max_search_distance_a is 2 and the two sides of a diff chunk
+ * look like this:
+ * a | m
+ * b | n
+ * c | o
+ * d | p
+ * e | q
+ * Then the similarity array will contain:
+ * [-1, -1, am, bm, cm,
+ *  -1, an, bn, cn, dn,
+ *  ao, bo, co, do, eo,
+ *  bp, cp, dp, ep, -1,
+ *  cq, dq, eq, -1, -1]
+ * Where similarities are denoted either by -1 for invalid, or the
+ * concatenation of the two lines in the diff being compared.
+ *
+ * \param similarities array of similarities between lines in A and B
+ * \param line_a the index of the line in A, in the same frame of reference as
+ *	closest_line_a.
+ * \param local_line_b the index of the line in B, relative to the first line
+ *		       in B that similarities represents.
+ * \param closest_line_a the index of the line in A that is deemed to be
+ *			 closest to local_line_b. This must be in the same
+ *			 frame of reference as line_a. This value defines
+ *			 where similarities is centered for the line in B.
+ * \param max_search_distance_a maximum distance in lines from the closest line
+ * 				in A for other lines in A for which
+ * 				similarities may be calculated.
+ */
+static int *get_similarity(int *similarities,
+			   int line_a, int local_line_b,
+			   int closest_line_a, int max_search_distance_a)
+{
+	assert(abs(line_a - closest_line_a) <=
+	       max_search_distance_a);
+	return similarities + line_a - closest_line_a +
+	       max_search_distance_a +
+	       local_line_b * (max_search_distance_a * 2 + 1);
+}
+
+#define CERTAIN_NOTHING_MATCHES -2
+#define CERTAINTY_NOT_CALCULATED -1
+
+/* Given a line in B, first calculate its similarities with nearby lines in A
+ * if not already calculated, then identify the most similar and second most
+ * similar lines. The "certainty" is calculated based on those two
+ * similarities.
+ *
+ * \param start_a the index of the first line of the chunk in A
+ * \param length_a the length in lines of the chunk in A
+ * \param local_line_b the index of the line in B, relative to the first line
+ * 		       in the chunk.
+ * \param fingerprints_a array of fingerprints for the chunk in A
+ * \param fingerprints_b array of fingerprints for the chunk in B
+ * \param similarities 2-dimensional array of similarities between lines in A
+ * 		       and B. See get_similarity() for more details.
+ * \param certainties array of values indicating how strongly a line in B is
+ * 		      matched with some line in A.
+ * \param second_best_result array of absolute indices in A for the second
+ * 			     closest match of a line in B.
+ * \param result array of absolute indices in A for the closest match of a line
+ * 		 in B.
+ * \param max_search_distance_a maximum distance in lines from the closest line
+ * 				in A for other lines in A for which
+ * 				similarities may be calculated.
+ * \param map_line_number_in_b_to_a parameter to map_line_number().
+ */
+static void find_best_line_matches(
+	int start_a,
+	int length_a,
+	int start_b,
+	int local_line_b,
+	struct fingerprint *fingerprints_a,
+	struct fingerprint *fingerprints_b,
+	int *similarities,
+	int *certainties,
+	int *second_best_result,
+	int *result,
+	const int max_search_distance_a,
+	const struct line_number_mapping *map_line_number_in_b_to_a)
+{
+
+	int i, search_start, search_end, closest_local_line_a, *similarity,
+		best_similarity = 0, second_best_similarity = 0,
+		best_similarity_index = 0, second_best_similarity_index = 0;
+
+	/* certainty has already been calculated so no need to redo the work */
+	if (certainties[local_line_b] != CERTAINTY_NOT_CALCULATED)
+		return;
+
+	closest_local_line_a = map_line_number(
+		local_line_b + start_b, map_line_number_in_b_to_a) - start_a;
+
+	search_start = closest_local_line_a - max_search_distance_a;
+	if (search_start < 0)
+		search_start = 0;
+
+	search_end = closest_local_line_a + max_search_distance_a + 1;
+	if (search_end > length_a)
+		search_end = length_a;
+
+	for (i = search_start; i < search_end; ++i) {
+		similarity = get_similarity(similarities,
+					    i, local_line_b,
+					    closest_local_line_a,
+					    max_search_distance_a);
+		if (*similarity == -1) {
+			/* This value will never exceed 10 but assert just in
+			 * case
+			 */
+			assert(abs(i - closest_local_line_a) < 1000);
+			/* scale the similarity by (1000 - distance from
+			 * closest line) to act as a tie break between lines
+			 * that otherwise are equally similar.
+			 */
+			*similarity = fingerprint_similarity(
+				fingerprints_b + local_line_b,
+				fingerprints_a + i) *
+				(1000 - abs(i - closest_local_line_a));
+		}
+		if (*similarity > best_similarity) {
+			second_best_similarity = best_similarity;
+			second_best_similarity_index = best_similarity_index;
+			best_similarity = *similarity;
+			best_similarity_index = i;
+		} else if (*similarity > second_best_similarity) {
+			second_best_similarity = *similarity;
+			second_best_similarity_index = i;
+		}
+	}
+
+	if (best_similarity == 0) {
+		/* this line definitely doesn't match with anything. Mark it
+		 * with this special value so it doesn't get invalidated and
+		 * won't be recalculated.
+		 */
+		certainties[local_line_b] = CERTAIN_NOTHING_MATCHES;
+		result[local_line_b] = -1;
+	} else {
+		/* Calculate the certainty with which this line matches.
+		 * If the line matches well with two lines then that reduces
+		 * the certainty. However we still want to prioritise matching
+		 * a line that matches very well with two lines over matching a
+		 * line that matches poorly with one line, hence doubling
+		 * best_similarity.
+		 * This means that if we have
+		 * line X that matches only one line with a score of 3,
+		 * line Y that matches two lines equally with a score of 5,
+		 * and line Z that matches only one line with a score or 2,
+		 * then the lines in order of certainty are X, Y, Z.
+		 */
+		certainties[local_line_b] = best_similarity * 2 -
+			second_best_similarity;
+
+		/* We keep both the best and second best results to allow us to
+		 * check at a later stage of the matching process whether the
+		 * result needs to be invalidated.
+		 */
+		result[local_line_b] = start_a + best_similarity_index;
+		second_best_result[local_line_b] =
+			start_a + second_best_similarity_index;
+	}
+}
+
+/*
+ * This finds the line that we can match with the most confidence, and
+ * uses it as a partition. It then calls itself on the lines on either side of
+ * that partition. In this way we avoid lines appearing out of order, and
+ * retain a sensible line ordering.
+ * \param start_a index of the first line in A with which lines in B may be
+ * 		  compared.
+ * \param start_b index of the first line in B for which matching should be
+ * 		  done.
+ * \param length_a number of lines in A with which lines in B may be compared.
+ * \param length_b number of lines in B for which matching should be done.
+ * \param fingerprints_a mutable array of fingerprints in A. The first element
+ * 			 corresponds to the line at start_a.
+ * \param fingerprints_b array of fingerprints in B. The first element
+ * 			 corresponds to the line at start_b.
+ * \param similarities 2-dimensional array of similarities between lines in A
+ * 		       and B. See get_similarity() for more details.
+ * \param certainties array of values indicating how strongly a line in B is
+ * 		      matched with some line in A.
+ * \param second_best_result array of absolute indices in A for the second
+ * 			     closest match of a line in B.
+ * \param result array of absolute indices in A for the closest match of a line
+ * 		 in B.
+ * \param max_search_distance_a maximum distance in lines from the closest line
+ * 			      in A for other lines in A for which
+ * 			      similarities may be calculated.
+ * \param max_search_distance_b an upper bound on the greatest possible
+ * 			      distance between lines in B such that they will
+ *                              both be compared with the same line in A
+ * 			      according to max_search_distance_a.
+ * \param map_line_number_in_b_to_a parameter to map_line_number().
+ */
+static void fuzzy_find_matching_lines_recurse(
+	int start_a, int start_b,
+	int length_a, int length_b,
+	struct fingerprint *fingerprints_a,
+	struct fingerprint *fingerprints_b,
+	int *similarities,
+	int *certainties,
+	int *second_best_result,
+	int *result,
+	int max_search_distance_a,
+	int max_search_distance_b,
+	const struct line_number_mapping *map_line_number_in_b_to_a)
+{
+	int i, invalidate_min, invalidate_max, offset_b,
+		second_half_start_a, second_half_start_b,
+		second_half_length_a, second_half_length_b,
+		most_certain_line_a, most_certain_local_line_b = -1,
+		most_certain_line_certainty = -1,
+		closest_local_line_a;
+
+	for (i = 0; i < length_b; ++i) {
+		find_best_line_matches(start_a,
+				       length_a,
+				       start_b,
+				       i,
+				       fingerprints_a,
+				       fingerprints_b,
+				       similarities,
+				       certainties,
+				       second_best_result,
+				       result,
+				       max_search_distance_a,
+				       map_line_number_in_b_to_a);
+
+		if (certainties[i] > most_certain_line_certainty) {
+			most_certain_line_certainty = certainties[i];
+			most_certain_local_line_b = i;
+		}
+	}
+
+	/* No matches. */
+	if (most_certain_local_line_b == -1)
+		return;
+
+	most_certain_line_a = result[most_certain_local_line_b];
+
+	/*
+	 * Subtract the most certain line's fingerprint in B from the matched
+	 * fingerprint in A. This means that other lines in B can't also match
+	 * the same parts of the line in A.
+	 */
+	fingerprint_subtract(fingerprints_a + most_certain_line_a - start_a,
+			     fingerprints_b + most_certain_local_line_b);
+
+	/* Invalidate results that may be affected by the choice of most
+	 * certain line.
+	 */
+	invalidate_min = most_certain_local_line_b - max_search_distance_b;
+	invalidate_max = most_certain_local_line_b + max_search_distance_b + 1;
+	if (invalidate_min < 0)
+		invalidate_min = 0;
+	if (invalidate_max > length_b)
+		invalidate_max = length_b;
+
+	/* As the fingerprint in A has changed, discard previously calculated
+	 * similarity values with that fingerprint.
+	 */
+	for (i = invalidate_min; i < invalidate_max; ++i) {
+		closest_local_line_a = map_line_number(
+			i + start_b, map_line_number_in_b_to_a) - start_a;
+
+		/* Check that the lines in A and B are close enough that there
+		 * is a similarity value for them.
+		 */
+		if (abs(most_certain_line_a - start_a - closest_local_line_a) >
+			max_search_distance_a) {
+			continue;
+		}
+
+		*get_similarity(similarities, most_certain_line_a - start_a,
+				i, closest_local_line_a,
+				max_search_distance_a) = -1;
+	}
+
+	/* More invalidating of results that may be affected by the choice of
+	 * most certain line.
+	 * Discard the matches for lines in B that are currently matched with a
+	 * line in A such that their ordering contradicts the ordering imposed
+	 * by the choice of most certain line.
+	 */
+	for (i = most_certain_local_line_b - 1; i >= invalidate_min; --i) {
+		/* In this loop we discard results for lines in B that are
+		 * before most-certain-line-B but are matched with a line in A
+		 * that is after most-certain-line-A.
+		 */
+		if (certainties[i] >= 0 &&
+		    (result[i] >= most_certain_line_a ||
+		     second_best_result[i] >= most_certain_line_a)) {
+			certainties[i] = CERTAINTY_NOT_CALCULATED;
+		}
+	}
+	for (i = most_certain_local_line_b + 1; i < invalidate_max; ++i) {
+		/* In this loop we discard results for lines in B that are
+		 * after most-certain-line-B but are matched with a line in A
+		 * that is before most-certain-line-A.
+		 */
+		if (certainties[i] >= 0 &&
+		    (result[i] <= most_certain_line_a ||
+		     second_best_result[i] <= most_certain_line_a)) {
+			certainties[i] = CERTAINTY_NOT_CALCULATED;
+		}
+	}
+
+	/* Repeat the matching process for lines before the most certain line.
+	 */
+	if (most_certain_local_line_b > 0) {
+		fuzzy_find_matching_lines_recurse(
+			start_a, start_b,
+			most_certain_line_a + 1 - start_a,
+			most_certain_local_line_b,
+			fingerprints_a, fingerprints_b, similarities,
+			certainties, second_best_result, result,
+			max_search_distance_a,
+			max_search_distance_b,
+			map_line_number_in_b_to_a);
+	}
+	/* Repeat the matching process for lines after the most certain line.
+	 */
+	if (most_certain_local_line_b + 1 < length_b) {
+		second_half_start_a = most_certain_line_a;
+		offset_b = most_certain_local_line_b + 1;
+		second_half_start_b = start_b + offset_b;
+		second_half_length_a =
+			length_a + start_a - second_half_start_a;
+		second_half_length_b =
+			length_b + start_b - second_half_start_b;
+		fuzzy_find_matching_lines_recurse(
+			second_half_start_a, second_half_start_b,
+			second_half_length_a, second_half_length_b,
+			fingerprints_a + second_half_start_a - start_a,
+			fingerprints_b + offset_b,
+			similarities +
+				offset_b * (max_search_distance_a * 2 + 1),
+			certainties + offset_b,
+			second_best_result + offset_b, result + offset_b,
+			max_search_distance_a,
+			max_search_distance_b,
+			map_line_number_in_b_to_a);
+	}
+}
+
+/* Find the lines in the parent line range that most closely match the lines in
+ * the target line range. This is accomplished by matching fingerprints in each
+ * blame_origin, and choosing the best matches that preserve the line ordering.
+ * See struct fingerprint for details of fingerprint matching, and
+ * fuzzy_find_matching_lines_recurse for details of preserving line ordering.
+ *
+ * The performance is believed to be O(n log n) in the typical case and O(n^2)
+ * in a pathological case, where n is the number of lines in the target range.
+ */
+static int *fuzzy_find_matching_lines(struct blame_origin *parent,
+				      struct blame_origin *target,
+				      int tlno, int parent_slno, int same,
+				      int parent_len)
+{
+	/* We use the terminology "A" for the left hand side of the diff AKA
+	 * parent, and "B" for the right hand side of the diff AKA target. */
+	int start_a = parent_slno;
+	int length_a = parent_len;
+	int start_b = tlno;
+	int length_b = same - tlno;
+
+	struct line_number_mapping map_line_number_in_b_to_a = {
+		start_a, length_a, start_b, length_b
+	};
+
+	struct fingerprint *fingerprints_a = parent->fingerprints;
+	struct fingerprint *fingerprints_b = target->fingerprints;
+
+	int i, *result, *second_best_result,
+		*certainties, *similarities, similarity_count;
+
+	/*
+	 * max_search_distance_a means that given a line in B, compare it to
+	 * the line in A that is closest to its position, and the lines in A
+	 * that are no greater than max_search_distance_a lines away from the
+	 * closest line in A.
+	 *
+	 * max_search_distance_b is an upper bound on the greatest possible
+	 * distance between lines in B such that they will both be compared
+	 * with the same line in A according to max_search_distance_a.
+	 */
+	int max_search_distance_a = 10, max_search_distance_b;
+
+	if (length_a <= 0)
+		return NULL;
+
+	if (max_search_distance_a >= length_a)
+		max_search_distance_a = length_a ? length_a - 1 : 0;
+
+	max_search_distance_b = ((2 * max_search_distance_a + 1) * length_b
+				 - 1) / length_a;
+
+	CALLOC_ARRAY(result, length_b);
+	CALLOC_ARRAY(second_best_result, length_b);
+	CALLOC_ARRAY(certainties, length_b);
+
+	/* See get_similarity() for details of similarities. */
+	similarity_count = length_b * (max_search_distance_a * 2 + 1);
+	CALLOC_ARRAY(similarities, similarity_count);
+
+	for (i = 0; i < length_b; ++i) {
+		result[i] = -1;
+		second_best_result[i] = -1;
+		certainties[i] = CERTAINTY_NOT_CALCULATED;
+	}
+
+	for (i = 0; i < similarity_count; ++i)
+		similarities[i] = -1;
+
+	fuzzy_find_matching_lines_recurse(start_a, start_b,
+					  length_a, length_b,
+					  fingerprints_a + start_a,
+					  fingerprints_b + start_b,
+					  similarities,
+					  certainties,
+					  second_best_result,
+					  result,
+					  max_search_distance_a,
+					  max_search_distance_b,
+					  &map_line_number_in_b_to_a);
+
+	free(similarities);
+	free(certainties);
+	free(second_best_result);
+
+	return result;
+}
+
+static void fill_origin_fingerprints(struct blame_origin *o)
+{
+	int *line_starts;
+
+	if (o->fingerprints)
+		return;
+	o->num_lines = find_line_starts(&line_starts, o->file.ptr,
+					o->file.size);
+	CALLOC_ARRAY(o->fingerprints, o->num_lines);
+	get_line_fingerprints(o->fingerprints, o->file.ptr, line_starts,
+			      0, o->num_lines);
+	free(line_starts);
+}
+
+static void drop_origin_fingerprints(struct blame_origin *o)
+{
+	if (o->fingerprints) {
+		free_line_fingerprints(o->fingerprints, o->num_lines);
+		o->num_lines = 0;
+		FREE_AND_NULL(o->fingerprints);
+	}
+}
+
+/*
+ * Given an origin, prepare mmfile_t structure to be used by the
+ * diff machinery
+ */
+static void fill_origin_blob(struct diff_options *opt,
+			     struct blame_origin *o, mmfile_t *file,
+			     int *num_read_blob, int fill_fingerprints)
+{
+	if (!o->file.ptr) {
+		enum object_type type;
+		unsigned long file_size;
+
+		(*num_read_blob)++;
+		if (opt->flags.allow_textconv &&
+		    textconv_object(opt->repo, o->path, o->mode,
+				    &o->blob_oid, 1, &file->ptr, &file_size))
+			;
+		else
+			file->ptr = repo_read_object_file(the_repository,
+							  &o->blob_oid, &type,
+							  &file_size);
+		file->size = file_size;
+
+		if (!file->ptr)
+			die("Cannot read blob %s for path %s",
+			    oid_to_hex(&o->blob_oid),
+			    o->path);
+		o->file = *file;
+	}
+	else
+		*file = o->file;
+	if (fill_fingerprints)
+		fill_origin_fingerprints(o);
+}
+
+static void drop_origin_blob(struct blame_origin *o)
+{
+	FREE_AND_NULL(o->file.ptr);
+	drop_origin_fingerprints(o);
+}
+
+/*
+ * Any merge of blames happens on lists of blames that arrived via
+ * different parents in a single suspect.  In this case, we want to
+ * sort according to the suspect line numbers as opposed to the final
+ * image line numbers.  The function body is somewhat longish because
+ * it avoids unnecessary writes.
+ */
+
+static struct blame_entry *blame_merge(struct blame_entry *list1,
+				       struct blame_entry *list2)
+{
+	struct blame_entry *p1 = list1, *p2 = list2,
+		**tail = &list1;
+
+	if (!p1)
+		return p2;
+	if (!p2)
+		return p1;
+
+	if (p1->s_lno <= p2->s_lno) {
+		do {
+			tail = &p1->next;
+			if (!(p1 = *tail)) {
+				*tail = p2;
+				return list1;
+			}
+		} while (p1->s_lno <= p2->s_lno);
+	}
+	for (;;) {
+		*tail = p2;
+		do {
+			tail = &p2->next;
+			if (!(p2 = *tail))  {
+				*tail = p1;
+				return list1;
+			}
+		} while (p1->s_lno > p2->s_lno);
+		*tail = p1;
+		do {
+			tail = &p1->next;
+			if (!(p1 = *tail)) {
+				*tail = p2;
+				return list1;
+			}
+		} while (p1->s_lno <= p2->s_lno);
+	}
+}
+
+DEFINE_LIST_SORT(static, sort_blame_entries, struct blame_entry, next);
+
+/*
+ * Final image line numbers are all different, so we don't need a
+ * three-way comparison here.
+ */
+
+static int compare_blame_final(const struct blame_entry *e1,
+			       const struct blame_entry *e2)
+{
+	return e1->lno > e2->lno ? 1 : -1;
+}
+
+static int compare_blame_suspect(const struct blame_entry *s1,
+				 const struct blame_entry *s2)
+{
+	/*
+	 * to allow for collating suspects, we sort according to the
+	 * respective pointer value as the primary sorting criterion.
+	 * The actual relation is pretty unimportant as long as it
+	 * establishes a total order.  Comparing as integers gives us
+	 * that.
+	 */
+	if (s1->suspect != s2->suspect)
+		return (intptr_t)s1->suspect > (intptr_t)s2->suspect ? 1 : -1;
+	if (s1->s_lno == s2->s_lno)
+		return 0;
+	return s1->s_lno > s2->s_lno ? 1 : -1;
+}
+
+void blame_sort_final(struct blame_scoreboard *sb)
+{
+	sort_blame_entries(&sb->ent, compare_blame_final);
+}
+
+static int compare_commits_by_reverse_commit_date(const void *a,
+						  const void *b,
+						  void *c)
+{
+	return -compare_commits_by_commit_date(a, b, c);
+}
+
+/*
+ * For debugging -- origin is refcounted, and this asserts that
+ * we do not underflow.
+ */
+static void sanity_check_refcnt(struct blame_scoreboard *sb)
+{
+	int baa = 0;
+	struct blame_entry *ent;
+
+	for (ent = sb->ent; ent; ent = ent->next) {
+		/* Nobody should have zero or negative refcnt */
+		if (ent->suspect->refcnt <= 0) {
+			fprintf(stderr, "%s in %s has negative refcnt %d\n",
+				ent->suspect->path,
+				oid_to_hex(&ent->suspect->commit->object.oid),
+				ent->suspect->refcnt);
+			baa = 1;
+		}
+	}
+	if (baa)
+		sb->on_sanity_fail(sb, baa);
+}
+
+/*
+ * If two blame entries that are next to each other came from
+ * contiguous lines in the same origin (i.e. <commit, path> pair),
+ * merge them together.
+ */
+void blame_coalesce(struct blame_scoreboard *sb)
+{
+	struct blame_entry *ent, *next;
+
+	for (ent = sb->ent; ent && (next = ent->next); ent = next) {
+		if (ent->suspect == next->suspect &&
+		    ent->s_lno + ent->num_lines == next->s_lno &&
+		    ent->lno + ent->num_lines == next->lno &&
+		    ent->ignored == next->ignored &&
+		    ent->unblamable == next->unblamable) {
+			ent->num_lines += next->num_lines;
+			ent->next = next->next;
+			blame_origin_decref(next->suspect);
+			free(next);
+			ent->score = 0;
+			next = ent; /* again */
+		}
+	}
+
+	if (sb->debug) /* sanity */
+		sanity_check_refcnt(sb);
+}
+
+/*
+ * Merge the given sorted list of blames into a preexisting origin.
+ * If there were no previous blames to that commit, it is entered into
+ * the commit priority queue of the score board.
+ */
+
+static void queue_blames(struct blame_scoreboard *sb, struct blame_origin *porigin,
+			 struct blame_entry *sorted)
+{
+	if (porigin->suspects)
+		porigin->suspects = blame_merge(porigin->suspects, sorted);
+	else {
+		struct blame_origin *o;
+		for (o = get_blame_suspects(porigin->commit); o; o = o->next) {
+			if (o->suspects) {
+				porigin->suspects = sorted;
+				return;
+			}
+		}
+		porigin->suspects = sorted;
+		prio_queue_put(&sb->commits, porigin->commit);
+	}
+}
+
+/*
+ * Fill the blob_sha1 field of an origin if it hasn't, so that later
+ * call to fill_origin_blob() can use it to locate the data.  blob_sha1
+ * for an origin is also used to pass the blame for the entire file to
+ * the parent to detect the case where a child's blob is identical to
+ * that of its parent's.
+ *
+ * This also fills origin->mode for corresponding tree path.
+ */
+static int fill_blob_sha1_and_mode(struct repository *r,
+				   struct blame_origin *origin)
+{
+	if (!is_null_oid(&origin->blob_oid))
+		return 0;
+	if (get_tree_entry(r, &origin->commit->object.oid, origin->path, &origin->blob_oid, &origin->mode))
+		goto error_out;
+	if (oid_object_info(r, &origin->blob_oid, NULL) != OBJ_BLOB)
+		goto error_out;
+	return 0;
+ error_out:
+	oidclr(&origin->blob_oid, the_repository->hash_algo);
+	origin->mode = S_IFINVALID;
+	return -1;
+}
+
+struct blame_bloom_data {
+	/*
+	 * Changed-path Bloom filter keys. These can help prevent
+	 * computing diffs against first parents, but we need to
+	 * expand the list as code is moved or files are renamed.
+	 */
+	struct bloom_filter_settings *settings;
+	struct bloom_key **keys;
+	int nr;
+	int alloc;
+};
+
+static int bloom_count_queries = 0;
+static int bloom_count_no = 0;
+static int maybe_changed_path(struct repository *r,
+			      struct blame_origin *origin,
+			      struct blame_bloom_data *bd)
+{
+	int i;
+	struct bloom_filter *filter;
+
+	if (!bd)
+		return 1;
+
+	if (commit_graph_generation(origin->commit) == GENERATION_NUMBER_INFINITY)
+		return 1;
+
+	filter = get_bloom_filter(r, origin->commit);
+
+	if (!filter)
+		return 1;
+
+	bloom_count_queries++;
+	for (i = 0; i < bd->nr; i++) {
+		if (bloom_filter_contains(filter,
+					  bd->keys[i],
+					  bd->settings))
+			return 1;
+	}
+
+	bloom_count_no++;
+	return 0;
+}
+
+static void add_bloom_key(struct blame_bloom_data *bd,
+			  const char *path)
+{
+	if (!bd)
+		return;
+
+	if (bd->nr >= bd->alloc) {
+		bd->alloc *= 2;
+		REALLOC_ARRAY(bd->keys, bd->alloc);
+	}
+
+	bd->keys[bd->nr] = xmalloc(sizeof(struct bloom_key));
+	fill_bloom_key(path, strlen(path), bd->keys[bd->nr], bd->settings);
+	bd->nr++;
+}
+
+/*
+ * We have an origin -- check if the same path exists in the
+ * parent and return an origin structure to represent it.
+ */
+static struct blame_origin *find_origin(struct repository *r,
+					struct commit *parent,
+					struct blame_origin *origin,
+					struct blame_bloom_data *bd)
+{
+	struct blame_origin *porigin;
+	struct diff_options diff_opts;
+	const char *paths[2];
+
+	/* First check any existing origins */
+	for (porigin = get_blame_suspects(parent); porigin; porigin = porigin->next)
+		if (!strcmp(porigin->path, origin->path)) {
+			/*
+			 * The same path between origin and its parent
+			 * without renaming -- the most common case.
+			 */
+			return blame_origin_incref (porigin);
+		}
+
+	/* See if the origin->path is different between parent
+	 * and origin first.  Most of the time they are the
+	 * same and diff-tree is fairly efficient about this.
+	 */
+	repo_diff_setup(r, &diff_opts);
+	diff_opts.flags.recursive = 1;
+	diff_opts.detect_rename = 0;
+	diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+	paths[0] = origin->path;
+	paths[1] = NULL;
+
+	parse_pathspec(&diff_opts.pathspec,
+		       PATHSPEC_ALL_MAGIC & ~PATHSPEC_LITERAL,
+		       PATHSPEC_LITERAL_PATH, "", paths);
+	diff_setup_done(&diff_opts);
+
+	if (is_null_oid(&origin->commit->object.oid))
+		do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
+	else {
+		int compute_diff = 1;
+		if (origin->commit->parents &&
+		    oideq(&parent->object.oid,
+			  &origin->commit->parents->item->object.oid))
+			compute_diff = maybe_changed_path(r, origin, bd);
+
+		if (compute_diff)
+			diff_tree_oid(get_commit_tree_oid(parent),
+				      get_commit_tree_oid(origin->commit),
+				      "", &diff_opts);
+	}
+	diffcore_std(&diff_opts);
+
+	if (!diff_queued_diff.nr) {
+		/* The path is the same as parent */
+		porigin = get_origin(parent, origin->path);
+		oidcpy(&porigin->blob_oid, &origin->blob_oid);
+		porigin->mode = origin->mode;
+	} else {
+		/*
+		 * Since origin->path is a pathspec, if the parent
+		 * commit had it as a directory, we will see a whole
+		 * bunch of deletion of files in the directory that we
+		 * do not care about.
+		 */
+		int i;
+		struct diff_filepair *p = NULL;
+		for (i = 0; i < diff_queued_diff.nr; i++) {
+			const char *name;
+			p = diff_queued_diff.queue[i];
+			name = p->one->path ? p->one->path : p->two->path;
+			if (!strcmp(name, origin->path))
+				break;
+		}
+		if (!p)
+			die("internal error in blame::find_origin");
+		switch (p->status) {
+		default:
+			die("internal error in blame::find_origin (%c)",
+			    p->status);
+		case 'M':
+			porigin = get_origin(parent, origin->path);
+			oidcpy(&porigin->blob_oid, &p->one->oid);
+			porigin->mode = p->one->mode;
+			break;
+		case 'A':
+		case 'T':
+			/* Did not exist in parent, or type changed */
+			break;
+		}
+	}
+	diff_flush(&diff_opts);
+	return porigin;
+}
+
+/*
+ * We have an origin -- find the path that corresponds to it in its
+ * parent and return an origin structure to represent it.
+ */
+static struct blame_origin *find_rename(struct repository *r,
+					struct commit *parent,
+					struct blame_origin *origin,
+					struct blame_bloom_data *bd)
+{
+	struct blame_origin *porigin = NULL;
+	struct diff_options diff_opts;
+	int i;
+
+	repo_diff_setup(r, &diff_opts);
+	diff_opts.flags.recursive = 1;
+	diff_opts.detect_rename = DIFF_DETECT_RENAME;
+	diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+	diff_opts.single_follow = origin->path;
+	diff_setup_done(&diff_opts);
+
+	if (is_null_oid(&origin->commit->object.oid))
+		do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
+	else
+		diff_tree_oid(get_commit_tree_oid(parent),
+			      get_commit_tree_oid(origin->commit),
+			      "", &diff_opts);
+	diffcore_std(&diff_opts);
+
+	for (i = 0; i < diff_queued_diff.nr; i++) {
+		struct diff_filepair *p = diff_queued_diff.queue[i];
+		if ((p->status == 'R' || p->status == 'C') &&
+		    !strcmp(p->two->path, origin->path)) {
+			add_bloom_key(bd, p->one->path);
+			porigin = get_origin(parent, p->one->path);
+			oidcpy(&porigin->blob_oid, &p->one->oid);
+			porigin->mode = p->one->mode;
+			break;
+		}
+	}
+	diff_flush(&diff_opts);
+	return porigin;
+}
+
+/*
+ * Append a new blame entry to a given output queue.
+ */
+static void add_blame_entry(struct blame_entry ***queue,
+			    const struct blame_entry *src)
+{
+	struct blame_entry *e = xmalloc(sizeof(*e));
+	memcpy(e, src, sizeof(*e));
+	blame_origin_incref(e->suspect);
+
+	e->next = **queue;
+	**queue = e;
+	*queue = &e->next;
+}
+
+/*
+ * src typically is on-stack; we want to copy the information in it to
+ * a malloced blame_entry that gets added to the given queue.  The
+ * origin of dst loses a refcnt.
+ */
+static void dup_entry(struct blame_entry ***queue,
+		      struct blame_entry *dst, struct blame_entry *src)
+{
+	blame_origin_incref(src->suspect);
+	blame_origin_decref(dst->suspect);
+	memcpy(dst, src, sizeof(*src));
+	dst->next = **queue;
+	**queue = dst;
+	*queue = &dst->next;
+}
+
+const char *blame_nth_line(struct blame_scoreboard *sb, long lno)
+{
+	return sb->final_buf + sb->lineno[lno];
+}
+
+/*
+ * It is known that lines between tlno to same came from parent, and e
+ * has an overlap with that range.  it also is known that parent's
+ * line plno corresponds to e's line tlno.
+ *
+ *                <---- e ----->
+ *                   <------>
+ *                   <------------>
+ *             <------------>
+ *             <------------------>
+ *
+ * Split e into potentially three parts; before this chunk, the chunk
+ * to be blamed for the parent, and after that portion.
+ */
+static void split_overlap(struct blame_entry *split,
+			  struct blame_entry *e,
+			  int tlno, int plno, int same,
+			  struct blame_origin *parent)
+{
+	int chunk_end_lno;
+	int i;
+	memset(split, 0, sizeof(struct blame_entry [3]));
+
+	for (i = 0; i < 3; i++) {
+		split[i].ignored = e->ignored;
+		split[i].unblamable = e->unblamable;
+	}
+
+	if (e->s_lno < tlno) {
+		/* there is a pre-chunk part not blamed on parent */
+		split[0].suspect = blame_origin_incref(e->suspect);
+		split[0].lno = e->lno;
+		split[0].s_lno = e->s_lno;
+		split[0].num_lines = tlno - e->s_lno;
+		split[1].lno = e->lno + tlno - e->s_lno;
+		split[1].s_lno = plno;
+	}
+	else {
+		split[1].lno = e->lno;
+		split[1].s_lno = plno + (e->s_lno - tlno);
+	}
+
+	if (same < e->s_lno + e->num_lines) {
+		/* there is a post-chunk part not blamed on parent */
+		split[2].suspect = blame_origin_incref(e->suspect);
+		split[2].lno = e->lno + (same - e->s_lno);
+		split[2].s_lno = e->s_lno + (same - e->s_lno);
+		split[2].num_lines = e->s_lno + e->num_lines - same;
+		chunk_end_lno = split[2].lno;
+	}
+	else
+		chunk_end_lno = e->lno + e->num_lines;
+	split[1].num_lines = chunk_end_lno - split[1].lno;
+
+	/*
+	 * if it turns out there is nothing to blame the parent for,
+	 * forget about the splitting.  !split[1].suspect signals this.
+	 */
+	if (split[1].num_lines < 1)
+		return;
+	split[1].suspect = blame_origin_incref(parent);
+}
+
+/*
+ * split_overlap() divided an existing blame e into up to three parts
+ * in split.  Any assigned blame is moved to queue to
+ * reflect the split.
+ */
+static void split_blame(struct blame_entry ***blamed,
+			struct blame_entry ***unblamed,
+			struct blame_entry *split,
+			struct blame_entry *e)
+{
+	if (split[0].suspect && split[2].suspect) {
+		/* The first part (reuse storage for the existing entry e) */
+		dup_entry(unblamed, e, &split[0]);
+
+		/* The last part -- me */
+		add_blame_entry(unblamed, &split[2]);
+
+		/* ... and the middle part -- parent */
+		add_blame_entry(blamed, &split[1]);
+	}
+	else if (!split[0].suspect && !split[2].suspect)
+		/*
+		 * The parent covers the entire area; reuse storage for
+		 * e and replace it with the parent.
+		 */
+		dup_entry(blamed, e, &split[1]);
+	else if (split[0].suspect) {
+		/* me and then parent */
+		dup_entry(unblamed, e, &split[0]);
+		add_blame_entry(blamed, &split[1]);
+	}
+	else {
+		/* parent and then me */
+		dup_entry(blamed, e, &split[1]);
+		add_blame_entry(unblamed, &split[2]);
+	}
+}
+
+/*
+ * After splitting the blame, the origins used by the
+ * on-stack blame_entry should lose one refcnt each.
+ */
+static void decref_split(struct blame_entry *split)
+{
+	int i;
+
+	for (i = 0; i < 3; i++)
+		blame_origin_decref(split[i].suspect);
+}
+
+/*
+ * reverse_blame reverses the list given in head, appending tail.
+ * That allows us to build lists in reverse order, then reverse them
+ * afterwards.  This can be faster than building the list in proper
+ * order right away.  The reason is that building in proper order
+ * requires writing a link in the _previous_ element, while building
+ * in reverse order just requires placing the list head into the
+ * _current_ element.
+ */
+
+static struct blame_entry *reverse_blame(struct blame_entry *head,
+					 struct blame_entry *tail)
+{
+	while (head) {
+		struct blame_entry *next = head->next;
+		head->next = tail;
+		tail = head;
+		head = next;
+	}
+	return tail;
+}
+
+/*
+ * Splits a blame entry into two entries at 'len' lines.  The original 'e'
+ * consists of len lines, i.e. [e->lno, e->lno + len), and the second part,
+ * which is returned, consists of the remainder: [e->lno + len, e->lno +
+ * e->num_lines).  The caller needs to sort out the reference counting for the
+ * new entry's suspect.
+ */
+static struct blame_entry *split_blame_at(struct blame_entry *e, int len,
+					  struct blame_origin *new_suspect)
+{
+	struct blame_entry *n = xcalloc(1, sizeof(struct blame_entry));
+
+	n->suspect = new_suspect;
+	n->ignored = e->ignored;
+	n->unblamable = e->unblamable;
+	n->lno = e->lno + len;
+	n->s_lno = e->s_lno + len;
+	n->num_lines = e->num_lines - len;
+	e->num_lines = len;
+	e->score = 0;
+	return n;
+}
+
+struct blame_line_tracker {
+	int is_parent;
+	int s_lno;
+};
+
+static int are_lines_adjacent(struct blame_line_tracker *first,
+			      struct blame_line_tracker *second)
+{
+	return first->is_parent == second->is_parent &&
+	       first->s_lno + 1 == second->s_lno;
+}
+
+static int scan_parent_range(struct fingerprint *p_fps,
+			     struct fingerprint *t_fps, int t_idx,
+			     int from, int nr_lines)
+{
+	int sim, p_idx;
+	#define FINGERPRINT_FILE_THRESHOLD	10
+	int best_sim_val = FINGERPRINT_FILE_THRESHOLD;
+	int best_sim_idx = -1;
+
+	for (p_idx = from; p_idx < from + nr_lines; p_idx++) {
+		sim = fingerprint_similarity(&t_fps[t_idx], &p_fps[p_idx]);
+		if (sim < best_sim_val)
+			continue;
+		/* Break ties with the closest-to-target line number */
+		if (sim == best_sim_val && best_sim_idx != -1 &&
+		    abs(best_sim_idx - t_idx) < abs(p_idx - t_idx))
+			continue;
+		best_sim_val = sim;
+		best_sim_idx = p_idx;
+	}
+	return best_sim_idx;
+}
+
+/*
+ * The first pass checks the blame entry (from the target) against the parent's
+ * diff chunk.  If that fails for a line, the second pass tries to match that
+ * line to any part of parent file.  That catches cases where a change was
+ * broken into two chunks by 'context.'
+ */
+static void guess_line_blames(struct blame_origin *parent,
+			      struct blame_origin *target,
+			      int tlno, int offset, int same, int parent_len,
+			      struct blame_line_tracker *line_blames)
+{
+	int i, best_idx, target_idx;
+	int parent_slno = tlno + offset;
+	int *fuzzy_matches;
+
+	fuzzy_matches = fuzzy_find_matching_lines(parent, target,
+						  tlno, parent_slno, same,
+						  parent_len);
+	for (i = 0; i < same - tlno; i++) {
+		target_idx = tlno + i;
+		if (fuzzy_matches && fuzzy_matches[i] >= 0) {
+			best_idx = fuzzy_matches[i];
+		} else {
+			best_idx = scan_parent_range(parent->fingerprints,
+						     target->fingerprints,
+						     target_idx, 0,
+						     parent->num_lines);
+		}
+		if (best_idx >= 0) {
+			line_blames[i].is_parent = 1;
+			line_blames[i].s_lno = best_idx;
+		} else {
+			line_blames[i].is_parent = 0;
+			line_blames[i].s_lno = target_idx;
+		}
+	}
+	free(fuzzy_matches);
+}
+
+/*
+ * This decides which parts of a blame entry go to the parent (added to the
+ * ignoredp list) and which stay with the target (added to the diffp list).  The
+ * actual decision was made in a separate heuristic function, and those answers
+ * for the lines in 'e' are in line_blames.  This consumes e, essentially
+ * putting it on a list.
+ *
+ * Note that the blame entries on the ignoredp list are not necessarily sorted
+ * with respect to the parent's line numbers yet.
+ */
+static void ignore_blame_entry(struct blame_entry *e,
+			       struct blame_origin *parent,
+			       struct blame_entry **diffp,
+			       struct blame_entry **ignoredp,
+			       struct blame_line_tracker *line_blames)
+{
+	int entry_len, nr_lines, i;
+
+	/*
+	 * We carve new entries off the front of e.  Each entry comes from a
+	 * contiguous chunk of lines: adjacent lines from the same origin
+	 * (either the parent or the target).
+	 */
+	entry_len = 1;
+	nr_lines = e->num_lines;	/* e changes in the loop */
+	for (i = 0; i < nr_lines; i++) {
+		struct blame_entry *next = NULL;
+
+		/*
+		 * We are often adjacent to the next line - only split the blame
+		 * entry when we have to.
+		 */
+		if (i + 1 < nr_lines) {
+			if (are_lines_adjacent(&line_blames[i],
+					       &line_blames[i + 1])) {
+				entry_len++;
+				continue;
+			}
+			next = split_blame_at(e, entry_len,
+					      blame_origin_incref(e->suspect));
+		}
+		if (line_blames[i].is_parent) {
+			e->ignored = 1;
+			blame_origin_decref(e->suspect);
+			e->suspect = blame_origin_incref(parent);
+			e->s_lno = line_blames[i - entry_len + 1].s_lno;
+			e->next = *ignoredp;
+			*ignoredp = e;
+		} else {
+			e->unblamable = 1;
+			/* e->s_lno is already in the target's address space. */
+			e->next = *diffp;
+			*diffp = e;
+		}
+		assert(e->num_lines == entry_len);
+		e = next;
+		entry_len = 1;
+	}
+	assert(!e);
+}
+
+/*
+ * Process one hunk from the patch between the current suspect for
+ * blame_entry e and its parent.  This first blames any unfinished
+ * entries before the chunk (which is where target and parent start
+ * differing) on the parent, and then splits blame entries at the
+ * start and at the end of the difference region.  Since use of -M and
+ * -C options may lead to overlapping/duplicate source line number
+ * ranges, all we can rely on from sorting/merging is the order of the
+ * first suspect line number.
+ *
+ * tlno: line number in the target where this chunk begins
+ * same: line number in the target where this chunk ends
+ * offset: add to tlno to get the chunk starting point in the parent
+ * parent_len: number of lines in the parent chunk
+ */
+static void blame_chunk(struct blame_entry ***dstq, struct blame_entry ***srcq,
+			int tlno, int offset, int same, int parent_len,
+			struct blame_origin *parent,
+			struct blame_origin *target, int ignore_diffs)
+{
+	struct blame_entry *e = **srcq;
+	struct blame_entry *samep = NULL, *diffp = NULL, *ignoredp = NULL;
+	struct blame_line_tracker *line_blames = NULL;
+
+	while (e && e->s_lno < tlno) {
+		struct blame_entry *next = e->next;
+		/*
+		 * current record starts before differing portion.  If
+		 * it reaches into it, we need to split it up and
+		 * examine the second part separately.
+		 */
+		if (e->s_lno + e->num_lines > tlno) {
+			/* Move second half to a new record */
+			struct blame_entry *n;
+
+			n = split_blame_at(e, tlno - e->s_lno, e->suspect);
+			/* Push new record to diffp */
+			n->next = diffp;
+			diffp = n;
+		} else
+			blame_origin_decref(e->suspect);
+		/* Pass blame for everything before the differing
+		 * chunk to the parent */
+		e->suspect = blame_origin_incref(parent);
+		e->s_lno += offset;
+		e->next = samep;
+		samep = e;
+		e = next;
+	}
+	/*
+	 * As we don't know how much of a common stretch after this
+	 * diff will occur, the currently blamed parts are all that we
+	 * can assign to the parent for now.
+	 */
+
+	if (samep) {
+		**dstq = reverse_blame(samep, **dstq);
+		*dstq = &samep->next;
+	}
+	/*
+	 * Prepend the split off portions: everything after e starts
+	 * after the blameable portion.
+	 */
+	e = reverse_blame(diffp, e);
+
+	/*
+	 * Now retain records on the target while parts are different
+	 * from the parent.
+	 */
+	samep = NULL;
+	diffp = NULL;
+
+	if (ignore_diffs && same - tlno > 0) {
+		CALLOC_ARRAY(line_blames, same - tlno);
+		guess_line_blames(parent, target, tlno, offset, same,
+				  parent_len, line_blames);
+	}
+
+	while (e && e->s_lno < same) {
+		struct blame_entry *next = e->next;
+
+		/*
+		 * If current record extends into sameness, need to split.
+		 */
+		if (e->s_lno + e->num_lines > same) {
+			/*
+			 * Move second half to a new record to be
+			 * processed by later chunks
+			 */
+			struct blame_entry *n;
+
+			n = split_blame_at(e, same - e->s_lno,
+					   blame_origin_incref(e->suspect));
+			/* Push new record to samep */
+			n->next = samep;
+			samep = n;
+		}
+		if (ignore_diffs) {
+			ignore_blame_entry(e, parent, &diffp, &ignoredp,
+					   line_blames + e->s_lno - tlno);
+		} else {
+			e->next = diffp;
+			diffp = e;
+		}
+		e = next;
+	}
+	free(line_blames);
+	if (ignoredp) {
+		/*
+		 * Note ignoredp is not sorted yet, and thus neither is dstq.
+		 * That list must be sorted before we queue_blames().  We defer
+		 * sorting until after all diff hunks are processed, so that
+		 * guess_line_blames() can pick *any* line in the parent.  The
+		 * slight drawback is that we end up sorting all blame entries
+		 * passed to the parent, including those that are unrelated to
+		 * changes made by the ignored commit.
+		 */
+		**dstq = reverse_blame(ignoredp, **dstq);
+		*dstq = &ignoredp->next;
+	}
+	**srcq = reverse_blame(diffp, reverse_blame(samep, e));
+	/* Move across elements that are in the unblamable portion */
+	if (diffp)
+		*srcq = &diffp->next;
+}
+
+struct blame_chunk_cb_data {
+	struct blame_origin *parent;
+	struct blame_origin *target;
+	long offset;
+	int ignore_diffs;
+	struct blame_entry **dstq;
+	struct blame_entry **srcq;
+};
+
+/* diff chunks are from parent to target */
+static int blame_chunk_cb(long start_a, long count_a,
+			  long start_b, long count_b, void *data)
+{
+	struct blame_chunk_cb_data *d = data;
+	if (start_a - start_b != d->offset)
+		die("internal error in blame::blame_chunk_cb");
+	blame_chunk(&d->dstq, &d->srcq, start_b, start_a - start_b,
+		    start_b + count_b, count_a, d->parent, d->target,
+		    d->ignore_diffs);
+	d->offset = start_a + count_a - (start_b + count_b);
+	return 0;
+}
+
+/*
+ * We are looking at the origin 'target' and aiming to pass blame
+ * for the lines it is suspected to its parent.  Run diff to find
+ * which lines came from parent and pass blame for them.
+ */
+static void pass_blame_to_parent(struct blame_scoreboard *sb,
+				 struct blame_origin *target,
+				 struct blame_origin *parent, int ignore_diffs)
+{
+	mmfile_t file_p, file_o;
+	struct blame_chunk_cb_data d;
+	struct blame_entry *newdest = NULL;
+
+	if (!target->suspects)
+		return; /* nothing remains for this target */
+
+	d.parent = parent;
+	d.target = target;
+	d.offset = 0;
+	d.ignore_diffs = ignore_diffs;
+	d.dstq = &newdest; d.srcq = &target->suspects;
+
+	fill_origin_blob(&sb->revs->diffopt, parent, &file_p,
+			 &sb->num_read_blob, ignore_diffs);
+	fill_origin_blob(&sb->revs->diffopt, target, &file_o,
+			 &sb->num_read_blob, ignore_diffs);
+	sb->num_get_patch++;
+
+	if (diff_hunks(&file_p, &file_o, blame_chunk_cb, &d, sb->xdl_opts))
+		die("unable to generate diff (%s -> %s)",
+		    oid_to_hex(&parent->commit->object.oid),
+		    oid_to_hex(&target->commit->object.oid));
+	/* The rest are the same as the parent */
+	blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, 0,
+		    parent, target, 0);
+	*d.dstq = NULL;
+	if (ignore_diffs)
+		sort_blame_entries(&newdest, compare_blame_suspect);
+	queue_blames(sb, parent, newdest);
+
+	return;
+}
+
+/*
+ * The lines in blame_entry after splitting blames many times can become
+ * very small and trivial, and at some point it becomes pointless to
+ * blame the parents.  E.g. "\t\t}\n\t}\n\n" appears everywhere in any
+ * ordinary C program, and it is not worth to say it was copied from
+ * totally unrelated file in the parent.
+ *
+ * Compute how trivial the lines in the blame_entry are.
+ */
+unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e)
+{
+	unsigned score;
+	const char *cp, *ep;
+
+	if (e->score)
+		return e->score;
+
+	score = 1;
+	cp = blame_nth_line(sb, e->lno);
+	ep = blame_nth_line(sb, e->lno + e->num_lines);
+	while (cp < ep) {
+		unsigned ch = *((unsigned char *)cp);
+		if (isalnum(ch))
+			score++;
+		cp++;
+	}
+	e->score = score;
+	return score;
+}
+
+/*
+ * best_so_far[] and potential[] are both a split of an existing blame_entry
+ * that passes blame to the parent.  Maintain best_so_far the best split so
+ * far, by comparing potential and best_so_far and copying potential into
+ * bst_so_far as needed.
+ */
+static void copy_split_if_better(struct blame_scoreboard *sb,
+				 struct blame_entry *best_so_far,
+				 struct blame_entry *potential)
+{
+	int i;
+
+	if (!potential[1].suspect)
+		return;
+	if (best_so_far[1].suspect) {
+		if (blame_entry_score(sb, &potential[1]) <
+		    blame_entry_score(sb, &best_so_far[1]))
+			return;
+	}
+
+	for (i = 0; i < 3; i++)
+		blame_origin_incref(potential[i].suspect);
+	decref_split(best_so_far);
+	memcpy(best_so_far, potential, sizeof(struct blame_entry[3]));
+}
+
+/*
+ * We are looking at a part of the final image represented by
+ * ent (tlno and same are offset by ent->s_lno).
+ * tlno is where we are looking at in the final image.
+ * up to (but not including) same match preimage.
+ * plno is where we are looking at in the preimage.
+ *
+ * <-------------- final image ---------------------->
+ *       <------ent------>
+ *         ^tlno ^same
+ *    <---------preimage----->
+ *         ^plno
+ *
+ * All line numbers are 0-based.
+ */
+static void handle_split(struct blame_scoreboard *sb,
+			 struct blame_entry *ent,
+			 int tlno, int plno, int same,
+			 struct blame_origin *parent,
+			 struct blame_entry *split)
+{
+	if (ent->num_lines <= tlno)
+		return;
+	if (tlno < same) {
+		struct blame_entry potential[3];
+		tlno += ent->s_lno;
+		same += ent->s_lno;
+		split_overlap(potential, ent, tlno, plno, same, parent);
+		copy_split_if_better(sb, split, potential);
+		decref_split(potential);
+	}
+}
+
+struct handle_split_cb_data {
+	struct blame_scoreboard *sb;
+	struct blame_entry *ent;
+	struct blame_origin *parent;
+	struct blame_entry *split;
+	long plno;
+	long tlno;
+};
+
+static int handle_split_cb(long start_a, long count_a,
+			   long start_b, long count_b, void *data)
+{
+	struct handle_split_cb_data *d = data;
+	handle_split(d->sb, d->ent, d->tlno, d->plno, start_b, d->parent,
+		     d->split);
+	d->plno = start_a + count_a;
+	d->tlno = start_b + count_b;
+	return 0;
+}
+
+/*
+ * Find the lines from parent that are the same as ent so that
+ * we can pass blames to it.  file_p has the blob contents for
+ * the parent.
+ */
+static void find_copy_in_blob(struct blame_scoreboard *sb,
+			      struct blame_entry *ent,
+			      struct blame_origin *parent,
+			      struct blame_entry *split,
+			      mmfile_t *file_p)
+{
+	const char *cp;
+	mmfile_t file_o;
+	struct handle_split_cb_data d;
+
+	memset(&d, 0, sizeof(d));
+	d.sb = sb; d.ent = ent; d.parent = parent; d.split = split;
+	/*
+	 * Prepare mmfile that contains only the lines in ent.
+	 */
+	cp = blame_nth_line(sb, ent->lno);
+	file_o.ptr = (char *) cp;
+	file_o.size = blame_nth_line(sb, ent->lno + ent->num_lines) - cp;
+
+	/*
+	 * file_o is a part of final image we are annotating.
+	 * file_p partially may match that image.
+	 */
+	memset(split, 0, sizeof(struct blame_entry [3]));
+	if (diff_hunks(file_p, &file_o, handle_split_cb, &d, sb->xdl_opts))
+		die("unable to generate diff (%s)",
+		    oid_to_hex(&parent->commit->object.oid));
+	/* remainder, if any, all match the preimage */
+	handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
+}
+
+/* Move all blame entries from list *source that have a score smaller
+ * than score_min to the front of list *small.
+ * Returns a pointer to the link pointing to the old head of the small list.
+ */
+
+static struct blame_entry **filter_small(struct blame_scoreboard *sb,
+					 struct blame_entry **small,
+					 struct blame_entry **source,
+					 unsigned score_min)
+{
+	struct blame_entry *p = *source;
+	struct blame_entry *oldsmall = *small;
+	while (p) {
+		if (blame_entry_score(sb, p) <= score_min) {
+			*small = p;
+			small = &p->next;
+			p = *small;
+		} else {
+			*source = p;
+			source = &p->next;
+			p = *source;
+		}
+	}
+	*small = oldsmall;
+	*source = NULL;
+	return small;
+}
+
+/*
+ * See if lines currently target is suspected for can be attributed to
+ * parent.
+ */
+static void find_move_in_parent(struct blame_scoreboard *sb,
+				struct blame_entry ***blamed,
+				struct blame_entry **toosmall,
+				struct blame_origin *target,
+				struct blame_origin *parent)
+{
+	struct blame_entry *e, split[3];
+	struct blame_entry *unblamed = target->suspects;
+	struct blame_entry *leftover = NULL;
+	mmfile_t file_p;
+
+	if (!unblamed)
+		return; /* nothing remains for this target */
+
+	fill_origin_blob(&sb->revs->diffopt, parent, &file_p,
+			 &sb->num_read_blob, 0);
+	if (!file_p.ptr)
+		return;
+
+	/* At each iteration, unblamed has a NULL-terminated list of
+	 * entries that have not yet been tested for blame.  leftover
+	 * contains the reversed list of entries that have been tested
+	 * without being assignable to the parent.
+	 */
+	do {
+		struct blame_entry **unblamedtail = &unblamed;
+		struct blame_entry *next;
+		for (e = unblamed; e; e = next) {
+			next = e->next;
+			find_copy_in_blob(sb, e, parent, split, &file_p);
+			if (split[1].suspect &&
+			    sb->move_score < blame_entry_score(sb, &split[1])) {
+				split_blame(blamed, &unblamedtail, split, e);
+			} else {
+				e->next = leftover;
+				leftover = e;
+			}
+			decref_split(split);
+		}
+		*unblamedtail = NULL;
+		toosmall = filter_small(sb, toosmall, &unblamed, sb->move_score);
+	} while (unblamed);
+	target->suspects = reverse_blame(leftover, NULL);
+}
+
+struct blame_list {
+	struct blame_entry *ent;
+	struct blame_entry split[3];
+};
+
+/*
+ * Count the number of entries the target is suspected for,
+ * and prepare a list of entry and the best split.
+ */
+static struct blame_list *setup_blame_list(struct blame_entry *unblamed,
+					   int *num_ents_p)
+{
+	struct blame_entry *e;
+	int num_ents, i;
+	struct blame_list *blame_list = NULL;
+
+	for (e = unblamed, num_ents = 0; e; e = e->next)
+		num_ents++;
+	if (num_ents) {
+		CALLOC_ARRAY(blame_list, num_ents);
+		for (e = unblamed, i = 0; e; e = e->next)
+			blame_list[i++].ent = e;
+	}
+	*num_ents_p = num_ents;
+	return blame_list;
+}
+
+/*
+ * For lines target is suspected for, see if we can find code movement
+ * across file boundary from the parent commit.  porigin is the path
+ * in the parent we already tried.
+ */
+static void find_copy_in_parent(struct blame_scoreboard *sb,
+				struct blame_entry ***blamed,
+				struct blame_entry **toosmall,
+				struct blame_origin *target,
+				struct commit *parent,
+				struct blame_origin *porigin,
+				int opt)
+{
+	struct diff_options diff_opts;
+	int i, j;
+	struct blame_list *blame_list;
+	int num_ents;
+	struct blame_entry *unblamed = target->suspects;
+	struct blame_entry *leftover = NULL;
+
+	if (!unblamed)
+		return; /* nothing remains for this target */
+
+	repo_diff_setup(sb->repo, &diff_opts);
+	diff_opts.flags.recursive = 1;
+	diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+
+	diff_setup_done(&diff_opts);
+
+	/* Try "find copies harder" on new path if requested;
+	 * we do not want to use diffcore_rename() actually to
+	 * match things up; find_copies_harder is set only to
+	 * force diff_tree_oid() to feed all filepairs to diff_queue,
+	 * and this code needs to be after diff_setup_done(), which
+	 * usually makes find-copies-harder imply copy detection.
+	 */
+	if ((opt & PICKAXE_BLAME_COPY_HARDEST)
+	    || ((opt & PICKAXE_BLAME_COPY_HARDER)
+		&& (!porigin || strcmp(target->path, porigin->path))))
+		diff_opts.flags.find_copies_harder = 1;
+
+	if (is_null_oid(&target->commit->object.oid))
+		do_diff_cache(get_commit_tree_oid(parent), &diff_opts);
+	else
+		diff_tree_oid(get_commit_tree_oid(parent),
+			      get_commit_tree_oid(target->commit),
+			      "", &diff_opts);
+
+	if (!diff_opts.flags.find_copies_harder)
+		diffcore_std(&diff_opts);
+
+	do {
+		struct blame_entry **unblamedtail = &unblamed;
+		blame_list = setup_blame_list(unblamed, &num_ents);
+
+		for (i = 0; i < diff_queued_diff.nr; i++) {
+			struct diff_filepair *p = diff_queued_diff.queue[i];
+			struct blame_origin *norigin;
+			mmfile_t file_p;
+			struct blame_entry potential[3];
+
+			if (!DIFF_FILE_VALID(p->one))
+				continue; /* does not exist in parent */
+			if (S_ISGITLINK(p->one->mode))
+				continue; /* ignore git links */
+			if (porigin && !strcmp(p->one->path, porigin->path))
+				/* find_move already dealt with this path */
+				continue;
+
+			norigin = get_origin(parent, p->one->path);
+			oidcpy(&norigin->blob_oid, &p->one->oid);
+			norigin->mode = p->one->mode;
+			fill_origin_blob(&sb->revs->diffopt, norigin, &file_p,
+					 &sb->num_read_blob, 0);
+			if (!file_p.ptr)
+				continue;
+
+			for (j = 0; j < num_ents; j++) {
+				find_copy_in_blob(sb, blame_list[j].ent,
+						  norigin, potential, &file_p);
+				copy_split_if_better(sb, blame_list[j].split,
+						     potential);
+				decref_split(potential);
+			}
+			blame_origin_decref(norigin);
+		}
+
+		for (j = 0; j < num_ents; j++) {
+			struct blame_entry *split = blame_list[j].split;
+			if (split[1].suspect &&
+			    sb->copy_score < blame_entry_score(sb, &split[1])) {
+				split_blame(blamed, &unblamedtail, split,
+					    blame_list[j].ent);
+			} else {
+				blame_list[j].ent->next = leftover;
+				leftover = blame_list[j].ent;
+			}
+			decref_split(split);
+		}
+		free(blame_list);
+		*unblamedtail = NULL;
+		toosmall = filter_small(sb, toosmall, &unblamed, sb->copy_score);
+	} while (unblamed);
+	target->suspects = reverse_blame(leftover, NULL);
+	diff_flush(&diff_opts);
+}
+
+/*
+ * The blobs of origin and porigin exactly match, so everything
+ * origin is suspected for can be blamed on the parent.
+ */
+static void pass_whole_blame(struct blame_scoreboard *sb,
+			     struct blame_origin *origin, struct blame_origin *porigin)
+{
+	struct blame_entry *e, *suspects;
+
+	if (!porigin->file.ptr && origin->file.ptr) {
+		/* Steal its file */
+		porigin->file = origin->file;
+		origin->file.ptr = NULL;
+	}
+	suspects = origin->suspects;
+	origin->suspects = NULL;
+	for (e = suspects; e; e = e->next) {
+		blame_origin_incref(porigin);
+		blame_origin_decref(e->suspect);
+		e->suspect = porigin;
+	}
+	queue_blames(sb, porigin, suspects);
+}
+
+/*
+ * We pass blame from the current commit to its parents.  We keep saying
+ * "parent" (and "porigin"), but what we mean is to find scapegoat to
+ * exonerate ourselves.
+ */
+static struct commit_list *first_scapegoat(struct rev_info *revs, struct commit *commit,
+					int reverse)
+{
+	if (!reverse) {
+		if (revs->first_parent_only &&
+		    commit->parents &&
+		    commit->parents->next) {
+			free_commit_list(commit->parents->next);
+			commit->parents->next = NULL;
+		}
+		return commit->parents;
+	}
+	return lookup_decoration(&revs->children, &commit->object);
+}
+
+static int num_scapegoats(struct rev_info *revs, struct commit *commit, int reverse)
+{
+	struct commit_list *l = first_scapegoat(revs, commit, reverse);
+	return commit_list_count(l);
+}
+
+/* Distribute collected unsorted blames to the respected sorted lists
+ * in the various origins.
+ */
+static void distribute_blame(struct blame_scoreboard *sb, struct blame_entry *blamed)
+{
+	sort_blame_entries(&blamed, compare_blame_suspect);
+	while (blamed)
+	{
+		struct blame_origin *porigin = blamed->suspect;
+		struct blame_entry *suspects = NULL;
+		do {
+			struct blame_entry *next = blamed->next;
+			blamed->next = suspects;
+			suspects = blamed;
+			blamed = next;
+		} while (blamed && blamed->suspect == porigin);
+		suspects = reverse_blame(suspects, NULL);
+		queue_blames(sb, porigin, suspects);
+	}
+}
+
+#define MAXSG 16
+
+typedef struct blame_origin *(*blame_find_alg)(struct repository *,
+					       struct commit *,
+					       struct blame_origin *,
+					       struct blame_bloom_data *);
+
+static void pass_blame(struct blame_scoreboard *sb, struct blame_origin *origin, int opt)
+{
+	struct rev_info *revs = sb->revs;
+	int i, pass, num_sg;
+	struct commit *commit = origin->commit;
+	struct commit_list *sg;
+	struct blame_origin *sg_buf[MAXSG];
+	struct blame_origin *porigin, **sg_origin = sg_buf;
+	struct blame_entry *toosmall = NULL;
+	struct blame_entry *blames, **blametail = &blames;
+
+	num_sg = num_scapegoats(revs, commit, sb->reverse);
+	if (!num_sg)
+		goto finish;
+	else if (num_sg < ARRAY_SIZE(sg_buf))
+		memset(sg_buf, 0, sizeof(sg_buf));
+	else
+		CALLOC_ARRAY(sg_origin, num_sg);
+
+	/*
+	 * The first pass looks for unrenamed path to optimize for
+	 * common cases, then we look for renames in the second pass.
+	 */
+	for (pass = 0; pass < 2 - sb->no_whole_file_rename; pass++) {
+		blame_find_alg find = pass ? find_rename : find_origin;
+
+		for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
+		     i < num_sg && sg;
+		     sg = sg->next, i++) {
+			struct commit *p = sg->item;
+			int j, same;
+
+			if (sg_origin[i])
+				continue;
+			if (repo_parse_commit(the_repository, p))
+				continue;
+			porigin = find(sb->repo, p, origin, sb->bloom_data);
+			if (!porigin)
+				continue;
+			if (oideq(&porigin->blob_oid, &origin->blob_oid)) {
+				pass_whole_blame(sb, origin, porigin);
+				blame_origin_decref(porigin);
+				goto finish;
+			}
+			for (j = same = 0; j < i; j++)
+				if (sg_origin[j] &&
+				    oideq(&sg_origin[j]->blob_oid, &porigin->blob_oid)) {
+					same = 1;
+					break;
+				}
+			if (!same)
+				sg_origin[i] = porigin;
+			else
+				blame_origin_decref(porigin);
+		}
+	}
+
+	sb->num_commits++;
+	for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
+	     i < num_sg && sg;
+	     sg = sg->next, i++) {
+		struct blame_origin *porigin = sg_origin[i];
+		if (!porigin)
+			continue;
+		if (!origin->previous) {
+			blame_origin_incref(porigin);
+			origin->previous = porigin;
+		}
+		pass_blame_to_parent(sb, origin, porigin, 0);
+		if (!origin->suspects)
+			goto finish;
+	}
+
+	/*
+	 * Pass remaining suspects for ignored commits to their parents.
+	 */
+	if (oidset_contains(&sb->ignore_list, &commit->object.oid)) {
+		for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
+		     i < num_sg && sg;
+		     sg = sg->next, i++) {
+			struct blame_origin *porigin = sg_origin[i];
+
+			if (!porigin)
+				continue;
+			pass_blame_to_parent(sb, origin, porigin, 1);
+			/*
+			 * Preemptively drop porigin so we can refresh the
+			 * fingerprints if we use the parent again, which can
+			 * occur if you ignore back-to-back commits.
+			 */
+			drop_origin_blob(porigin);
+			if (!origin->suspects)
+				goto finish;
+		}
+	}
+
+	/*
+	 * Optionally find moves in parents' files.
+	 */
+	if (opt & PICKAXE_BLAME_MOVE) {
+		filter_small(sb, &toosmall, &origin->suspects, sb->move_score);
+		if (origin->suspects) {
+			for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
+			     i < num_sg && sg;
+			     sg = sg->next, i++) {
+				struct blame_origin *porigin = sg_origin[i];
+				if (!porigin)
+					continue;
+				find_move_in_parent(sb, &blametail, &toosmall, origin, porigin);
+				if (!origin->suspects)
+					break;
+			}
+		}
+	}
+
+	/*
+	 * Optionally find copies from parents' files.
+	 */
+	if (opt & PICKAXE_BLAME_COPY) {
+		if (sb->copy_score > sb->move_score)
+			filter_small(sb, &toosmall, &origin->suspects, sb->copy_score);
+		else if (sb->copy_score < sb->move_score) {
+			origin->suspects = blame_merge(origin->suspects, toosmall);
+			toosmall = NULL;
+			filter_small(sb, &toosmall, &origin->suspects, sb->copy_score);
+		}
+		if (!origin->suspects)
+			goto finish;
+
+		for (i = 0, sg = first_scapegoat(revs, commit, sb->reverse);
+		     i < num_sg && sg;
+		     sg = sg->next, i++) {
+			struct blame_origin *porigin = sg_origin[i];
+			find_copy_in_parent(sb, &blametail, &toosmall,
+					    origin, sg->item, porigin, opt);
+			if (!origin->suspects)
+				goto finish;
+		}
+	}
+
+finish:
+	*blametail = NULL;
+	distribute_blame(sb, blames);
+	/*
+	 * prepend toosmall to origin->suspects
+	 *
+	 * There is no point in sorting: this ends up on a big
+	 * unsorted list in the caller anyway.
+	 */
+	if (toosmall) {
+		struct blame_entry **tail = &toosmall;
+		while (*tail)
+			tail = &(*tail)->next;
+		*tail = origin->suspects;
+		origin->suspects = toosmall;
+	}
+	for (i = 0; i < num_sg; i++) {
+		if (sg_origin[i]) {
+			if (!sg_origin[i]->suspects)
+				drop_origin_blob(sg_origin[i]);
+			blame_origin_decref(sg_origin[i]);
+		}
+	}
+	drop_origin_blob(origin);
+	if (sg_buf != sg_origin)
+		free(sg_origin);
+}
+
+/*
+ * The main loop -- while we have blobs with lines whose true origin
+ * is still unknown, pick one blob, and allow its lines to pass blames
+ * to its parents. */
+void assign_blame(struct blame_scoreboard *sb, int opt)
+{
+	struct rev_info *revs = sb->revs;
+	struct commit *commit = prio_queue_get(&sb->commits);
+
+	while (commit) {
+		struct blame_entry *ent;
+		struct blame_origin *suspect = get_blame_suspects(commit);
+
+		/* find one suspect to break down */
+		while (suspect && !suspect->suspects)
+			suspect = suspect->next;
+
+		if (!suspect) {
+			commit = prio_queue_get(&sb->commits);
+			continue;
+		}
+
+		assert(commit == suspect->commit);
+
+		/*
+		 * We will use this suspect later in the loop,
+		 * so hold onto it in the meantime.
+		 */
+		blame_origin_incref(suspect);
+		repo_parse_commit(the_repository, commit);
+		if (sb->reverse ||
+		    (!(commit->object.flags & UNINTERESTING) &&
+		     !(revs->max_age != -1 && commit->date < revs->max_age)))
+			pass_blame(sb, suspect, opt);
+		else {
+			commit->object.flags |= UNINTERESTING;
+			if (commit->object.parsed)
+				mark_parents_uninteresting(sb->revs, commit);
+		}
+		/* treat root commit as boundary */
+		if (!commit->parents && !sb->show_root)
+			commit->object.flags |= UNINTERESTING;
+
+		/* Take responsibility for the remaining entries */
+		ent = suspect->suspects;
+		if (ent) {
+			suspect->guilty = 1;
+			for (;;) {
+				struct blame_entry *next = ent->next;
+				if (sb->found_guilty_entry)
+					sb->found_guilty_entry(ent, sb->found_guilty_entry_data);
+				if (next) {
+					ent = next;
+					continue;
+				}
+				ent->next = sb->ent;
+				sb->ent = suspect->suspects;
+				suspect->suspects = NULL;
+				break;
+			}
+		}
+		blame_origin_decref(suspect);
+
+		if (sb->debug) /* sanity */
+			sanity_check_refcnt(sb);
+	}
+}
+
+/*
+ * To allow quick access to the contents of nth line in the
+ * final image, prepare an index in the scoreboard.
+ */
+static int prepare_lines(struct blame_scoreboard *sb)
+{
+	sb->num_lines = find_line_starts(&sb->lineno, sb->final_buf,
+					 sb->final_buf_size);
+	return sb->num_lines;
+}
+
+static struct commit *find_single_final(struct rev_info *revs,
+					const char **name_p)
+{
+	int i;
+	struct commit *found = NULL;
+	const char *name = NULL;
+
+	for (i = 0; i < revs->pending.nr; i++) {
+		struct object *obj = revs->pending.objects[i].item;
+		if (obj->flags & UNINTERESTING)
+			continue;
+		obj = deref_tag(revs->repo, obj, NULL, 0);
+		if (!obj || obj->type != OBJ_COMMIT)
+			die("Non commit %s?", revs->pending.objects[i].name);
+		if (found)
+			die("More than one commit to dig from %s and %s?",
+			    revs->pending.objects[i].name, name);
+		found = (struct commit *)obj;
+		name = revs->pending.objects[i].name;
+	}
+	if (name_p)
+		*name_p = xstrdup_or_null(name);
+	return found;
+}
+
+static struct commit *dwim_reverse_initial(struct rev_info *revs,
+					   const char **name_p)
+{
+	/*
+	 * DWIM "git blame --reverse ONE -- PATH" as
+	 * "git blame --reverse ONE..HEAD -- PATH" but only do so
+	 * when it makes sense.
+	 */
+	struct object *obj;
+	struct commit *head_commit;
+	struct object_id head_oid;
+
+	if (revs->pending.nr != 1)
+		return NULL;
+
+	/* Is that sole rev a committish? */
+	obj = revs->pending.objects[0].item;
+	obj = deref_tag(revs->repo, obj, NULL, 0);
+	if (!obj || obj->type != OBJ_COMMIT)
+		return NULL;
+
+	/* Do we have HEAD? */
+	if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+		return NULL;
+	head_commit = lookup_commit_reference_gently(revs->repo,
+						     &head_oid, 1);
+	if (!head_commit)
+		return NULL;
+
+	/* Turn "ONE" into "ONE..HEAD" then */
+	obj->flags |= UNINTERESTING;
+	add_pending_object(revs, &head_commit->object, "HEAD");
+
+	if (name_p)
+		*name_p = revs->pending.objects[0].name;
+	return (struct commit *)obj;
+}
+
+static struct commit *find_single_initial(struct rev_info *revs,
+					  const char **name_p)
+{
+	int i;
+	struct commit *found = NULL;
+	const char *name = NULL;
+
+	/*
+	 * There must be one and only one negative commit, and it must be
+	 * the boundary.
+	 */
+	for (i = 0; i < revs->pending.nr; i++) {
+		struct object *obj = revs->pending.objects[i].item;
+		if (!(obj->flags & UNINTERESTING))
+			continue;
+		obj = deref_tag(revs->repo, obj, NULL, 0);
+		if (!obj || obj->type != OBJ_COMMIT)
+			die("Non commit %s?", revs->pending.objects[i].name);
+		if (found)
+			die("More than one commit to dig up from, %s and %s?",
+			    revs->pending.objects[i].name, name);
+		found = (struct commit *) obj;
+		name = revs->pending.objects[i].name;
+	}
+
+	if (!name)
+		found = dwim_reverse_initial(revs, &name);
+	if (!name)
+		die("No commit to dig up from?");
+
+	if (name_p)
+		*name_p = xstrdup(name);
+	return found;
+}
+
+void init_scoreboard(struct blame_scoreboard *sb)
+{
+	memset(sb, 0, sizeof(struct blame_scoreboard));
+	sb->move_score = BLAME_DEFAULT_MOVE_SCORE;
+	sb->copy_score = BLAME_DEFAULT_COPY_SCORE;
+}
+
+void setup_scoreboard(struct blame_scoreboard *sb,
+		      struct blame_origin **orig)
+{
+	const char *final_commit_name = NULL;
+	struct blame_origin *o;
+	struct commit *final_commit = NULL;
+	enum object_type type;
+
+	init_blame_suspects(&blame_suspects);
+
+	if (sb->reverse && sb->contents_from)
+		die(_("--contents and --reverse do not blend well."));
+
+	if (!sb->repo)
+		BUG("repo is NULL");
+
+	if (!sb->reverse) {
+		sb->final = find_single_final(sb->revs, &final_commit_name);
+		sb->commits.compare = compare_commits_by_commit_date;
+	} else {
+		sb->final = find_single_initial(sb->revs, &final_commit_name);
+		sb->commits.compare = compare_commits_by_reverse_commit_date;
+	}
+
+	if (sb->reverse && sb->revs->first_parent_only)
+		sb->revs->children.name = NULL;
+
+	if (sb->contents_from || !sb->final) {
+		struct object_id head_oid, *parent_oid;
+
+		/*
+		 * Build a fake commit at the top of the history, when
+		 * (1) "git blame [^A] --path", i.e. with no positive end
+		 *     of the history range, in which case we build such
+		 *     a fake commit on top of the HEAD to blame in-tree
+		 *     modifications.
+		 * (2) "git blame --contents=file [A] -- path", with or
+		 *     without positive end of the history range but with
+		 *     --contents, in which case we pretend that there is
+		 *     a fake commit on top of the positive end (defaulting to
+		 *     HEAD) that has the given contents in the path.
+		 */
+		if (sb->final) {
+			parent_oid = &sb->final->object.oid;
+		} else {
+			if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING, &head_oid, NULL))
+				die("no such ref: HEAD");
+			parent_oid = &head_oid;
+		}
+
+		if (!sb->contents_from)
+			setup_work_tree();
+
+		sb->final = fake_working_tree_commit(sb->repo,
+						     &sb->revs->diffopt,
+						     sb->path, sb->contents_from,
+						     parent_oid);
+		add_pending_object(sb->revs, &(sb->final->object), ":");
+	}
+
+	if (sb->reverse && sb->revs->first_parent_only) {
+		final_commit = find_single_final(sb->revs, NULL);
+		if (!final_commit)
+			die(_("--reverse and --first-parent together require specified latest commit"));
+	}
+
+	/*
+	 * If we have bottom, this will mark the ancestors of the
+	 * bottom commits we would reach while traversing as
+	 * uninteresting.
+	 */
+	if (prepare_revision_walk(sb->revs))
+		die(_("revision walk setup failed"));
+
+	if (sb->reverse && sb->revs->first_parent_only) {
+		struct commit *c = final_commit;
+
+		sb->revs->children.name = "children";
+		while (c->parents &&
+		       !oideq(&c->object.oid, &sb->final->object.oid)) {
+			struct commit_list *l = xcalloc(1, sizeof(*l));
+
+			l->item = c;
+			if (add_decoration(&sb->revs->children,
+					   &c->parents->item->object, l))
+				BUG("not unique item in first-parent chain");
+			c = c->parents->item;
+		}
+
+		if (!oideq(&c->object.oid, &sb->final->object.oid))
+			die(_("--reverse --first-parent together require range along first-parent chain"));
+	}
+
+	if (is_null_oid(&sb->final->object.oid)) {
+		o = get_blame_suspects(sb->final);
+		sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
+		sb->final_buf_size = o->file.size;
+	}
+	else {
+		o = get_origin(sb->final, sb->path);
+		if (fill_blob_sha1_and_mode(sb->repo, o))
+			die(_("no such path %s in %s"), sb->path, final_commit_name);
+
+		if (sb->revs->diffopt.flags.allow_textconv &&
+		    textconv_object(sb->repo, sb->path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
+				    &sb->final_buf_size))
+			;
+		else
+			sb->final_buf = repo_read_object_file(the_repository,
+							      &o->blob_oid,
+							      &type,
+							      &sb->final_buf_size);
+
+		if (!sb->final_buf)
+			die(_("cannot read blob %s for path %s"),
+			    oid_to_hex(&o->blob_oid),
+			    sb->path);
+	}
+	sb->num_read_blob++;
+	prepare_lines(sb);
+
+	if (orig)
+		*orig = o;
+
+	free((char *)final_commit_name);
+}
+
+
+
+struct blame_entry *blame_entry_prepend(struct blame_entry *head,
+					long start, long end,
+					struct blame_origin *o)
+{
+	struct blame_entry *new_head = xcalloc(1, sizeof(struct blame_entry));
+	new_head->lno = start;
+	new_head->num_lines = end - start;
+	new_head->suspect = o;
+	new_head->s_lno = start;
+	new_head->next = head;
+	blame_origin_incref(o);
+	return new_head;
+}
+
+void setup_blame_bloom_data(struct blame_scoreboard *sb)
+{
+	struct blame_bloom_data *bd;
+	struct bloom_filter_settings *bs;
+
+	if (!sb->repo->objects->commit_graph)
+		return;
+
+	bs = get_bloom_filter_settings(sb->repo);
+	if (!bs)
+		return;
+
+	bd = xmalloc(sizeof(struct blame_bloom_data));
+
+	bd->settings = bs;
+
+	bd->alloc = 4;
+	bd->nr = 0;
+	ALLOC_ARRAY(bd->keys, bd->alloc);
+
+	add_bloom_key(bd, sb->path);
+
+	sb->bloom_data = bd;
+}
+
+void cleanup_scoreboard(struct blame_scoreboard *sb)
+{
+	free(sb->lineno);
+	free(sb->final_buf);
+	clear_prio_queue(&sb->commits);
+	oidset_clear(&sb->ignore_list);
+
+	if (sb->bloom_data) {
+		int i;
+		for (i = 0; i < sb->bloom_data->nr; i++) {
+			free(sb->bloom_data->keys[i]->hashes);
+			free(sb->bloom_data->keys[i]);
+		}
+		free(sb->bloom_data->keys);
+		FREE_AND_NULL(sb->bloom_data);
+
+		trace2_data_intmax("blame", sb->repo,
+				   "bloom/queries", bloom_count_queries);
+		trace2_data_intmax("blame", sb->repo,
+				   "bloom/response-no", bloom_count_no);
+	}
+}
diff --git a/blame.h b/blame.h
new file mode 100644
index 0000000000..3b34be0e5c
--- /dev/null
+++ b/blame.h
@@ -0,0 +1,191 @@
+#ifndef BLAME_H
+#define BLAME_H
+
+#include "oidset.h"
+#include "xdiff-interface.h"
+#include "prio-queue.h"
+
+#define PICKAXE_BLAME_MOVE		01
+#define PICKAXE_BLAME_COPY		02
+#define PICKAXE_BLAME_COPY_HARDER	04
+#define PICKAXE_BLAME_COPY_HARDEST	010
+
+#define BLAME_DEFAULT_MOVE_SCORE	20
+#define BLAME_DEFAULT_COPY_SCORE	40
+
+struct fingerprint;
+
+/*
+ * One blob in a commit that is being suspected
+ */
+struct blame_origin {
+	int refcnt;
+	/* Record preceding blame record for this blob */
+	struct blame_origin *previous;
+	/* origins are put in a list linked via `next' hanging off the
+	 * corresponding commit's util field in order to make finding
+	 * them fast.  The presence in this chain does not count
+	 * towards the origin's reference count.  It is tempting to
+	 * let it count as long as the commit is pending examination,
+	 * but even under circumstances where the commit will be
+	 * present multiple times in the priority queue of unexamined
+	 * commits, processing the first instance will not leave any
+	 * work requiring the origin data for the second instance.  An
+	 * interspersed commit changing that would have to be
+	 * preexisting with a different ancestry and with the same
+	 * commit date in order to wedge itself between two instances
+	 * of the same commit in the priority queue _and_ produce
+	 * blame entries relevant for it.  While we don't want to let
+	 * us get tripped up by this case, it certainly does not seem
+	 * worth optimizing for.
+	 */
+	struct blame_origin *next;
+	struct commit *commit;
+	/* `suspects' contains blame entries that may be attributed to
+	 * this origin's commit or to parent commits.  When a commit
+	 * is being processed, all suspects will be moved, either by
+	 * assigning them to an origin in a different commit, or by
+	 * shipping them to the scoreboard's ent list because they
+	 * cannot be attributed to a different commit.
+	 */
+	struct blame_entry *suspects;
+	mmfile_t file;
+	int num_lines;
+	struct fingerprint *fingerprints;
+	struct object_id blob_oid;
+	unsigned short mode;
+	/* guilty gets set when shipping any suspects to the final
+	 * blame list instead of other commits
+	 */
+	char guilty;
+	char path[FLEX_ARRAY];
+};
+
+/*
+ * Each group of lines is described by a blame_entry; it can be split
+ * as we pass blame to the parents.  They are arranged in linked lists
+ * kept as `suspects' of some unprocessed origin, or entered (when the
+ * blame origin has been finalized) into the scoreboard structure.
+ * While the scoreboard structure is only sorted at the end of
+ * processing (according to final image line number), the lists
+ * attached to an origin are sorted by the target line number.
+ */
+struct blame_entry {
+	struct blame_entry *next;
+
+	/* the first line of this group in the final image;
+	 * internally all line numbers are 0 based.
+	 */
+	int lno;
+
+	/* how many lines this group has */
+	int num_lines;
+
+	/* the commit that introduced this group into the final image */
+	struct blame_origin *suspect;
+
+	/* the line number of the first line of this group in the
+	 * suspect's file; internally all line numbers are 0 based.
+	 */
+	int s_lno;
+
+	/* how significant this entry is -- cached to avoid
+	 * scanning the lines over and over.
+	 */
+	unsigned score;
+	int ignored;
+	int unblamable;
+};
+
+struct blame_bloom_data;
+
+/*
+ * The current state of the blame assignment.
+ */
+struct blame_scoreboard {
+	/* the final commit (i.e. where we started digging from) */
+	struct commit *final;
+	/* Priority queue for commits with unassigned blame records */
+	struct prio_queue commits;
+	struct repository *repo;
+	struct rev_info *revs;
+	const char *path;
+
+	/*
+	 * The contents in the final image.
+	 * Used by many functions to obtain contents of the nth line,
+	 * indexed with scoreboard.lineno[blame_entry.lno].
+	 */
+	char *final_buf;
+	unsigned long final_buf_size;
+
+	/* linked list of blames */
+	struct blame_entry *ent;
+
+	struct oidset ignore_list;
+
+	/* look-up a line in the final buffer */
+	int num_lines;
+	int *lineno;
+
+	/* stats */
+	int num_read_blob;
+	int num_get_patch;
+	int num_commits;
+
+	/*
+	 * blame for a blame_entry with score lower than these thresholds
+	 * is not passed to the parent using move/copy logic.
+	 */
+	unsigned move_score;
+	unsigned copy_score;
+
+	/* use this file's contents as the final image */
+	const char *contents_from;
+
+	/* flags */
+	int reverse;
+	int show_root;
+	int xdl_opts;
+	int no_whole_file_rename;
+	int debug;
+
+	/* callbacks */
+	void(*on_sanity_fail)(struct blame_scoreboard *, int);
+	void(*found_guilty_entry)(struct blame_entry *, void *);
+
+	void *found_guilty_entry_data;
+	struct blame_bloom_data *bloom_data;
+};
+
+/*
+ * Origin is refcounted and usually we keep the blob contents to be
+ * reused.
+ */
+static inline struct blame_origin *blame_origin_incref(struct blame_origin *o)
+{
+	if (o)
+		o->refcnt++;
+	return o;
+}
+void blame_origin_decref(struct blame_origin *o);
+
+void blame_coalesce(struct blame_scoreboard *sb);
+void blame_sort_final(struct blame_scoreboard *sb);
+unsigned blame_entry_score(struct blame_scoreboard *sb, struct blame_entry *e);
+void assign_blame(struct blame_scoreboard *sb, int opt);
+const char *blame_nth_line(struct blame_scoreboard *sb, long lno);
+
+void init_scoreboard(struct blame_scoreboard *sb);
+void setup_scoreboard(struct blame_scoreboard *sb,
+		      struct blame_origin **orig);
+void setup_blame_bloom_data(struct blame_scoreboard *sb);
+void cleanup_scoreboard(struct blame_scoreboard *sb);
+
+struct blame_entry *blame_entry_prepend(struct blame_entry *head,
+					long start, long end,
+					struct blame_origin *o);
+
+struct blame_origin *get_blame_suspects(struct commit *commit);
+
+#endif /* BLAME_H */
diff --git a/blob.c b/blob.c
new file mode 100644
index 0000000000..3fb2922b1a
--- /dev/null
+++ b/blob.c
@@ -0,0 +1,18 @@
+#include "git-compat-util.h"
+#include "blob.h"
+#include "alloc.h"
+
+const char *blob_type = "blob";
+
+struct blob *lookup_blob(struct repository *r, const struct object_id *oid)
+{
+	struct object *obj = lookup_object(r, oid);
+	if (!obj)
+		return create_object(r, oid, alloc_blob_node(r));
+	return object_as_type(obj, OBJ_BLOB, 0);
+}
+
+void parse_blob_buffer(struct blob *item)
+{
+	item->object.parsed = 1;
+}
diff --git a/blob.h b/blob.h
new file mode 100644
index 0000000000..74555c90c4
--- /dev/null
+++ b/blob.h
@@ -0,0 +1,24 @@
+#ifndef BLOB_H
+#define BLOB_H
+
+#include "object.h"
+
+extern const char *blob_type;
+
+struct blob {
+	struct object object;
+};
+
+struct blob *lookup_blob(struct repository *r, const struct object_id *oid);
+
+/**
+ * Blobs do not contain references to other objects and do not have
+ * structured data that needs parsing. However, code may use the
+ * "parsed" bit in the struct object for a blob to determine whether
+ * its content has been found to actually be available, so
+ * parse_blob_buffer() is used (by object.c) to flag that the object
+ * has been read successfully from the database.
+ **/
+void parse_blob_buffer(struct blob *item);
+
+#endif /* BLOB_H */
diff --git a/block-sha1/sha1.c b/block-sha1/sha1.c
new file mode 100644
index 0000000000..80cebd2756
--- /dev/null
+++ b/block-sha1/sha1.c
@@ -0,0 +1,230 @@
+/*
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
+ * and to avoid unnecessary copies into the context array.
+ *
+ * This was initially based on the Mozilla SHA1 implementation, although
+ * none of the original Mozilla code remains.
+ */
+
+/* this is only to get definitions for memcpy(), ntohl() and htonl() */
+#include "../git-compat-util.h"
+
+#include "sha1.h"
+
+#define SHA_ROT(X,l,r)	(((X) << (l)) | ((X) >> (r)))
+#define SHA_ROL(X,n)	SHA_ROT(X,n,32-(n))
+#define SHA_ROR(X,n)	SHA_ROT(X,32-(n),n)
+
+/*
+ * If you have 32 registers or more, the compiler can (and should)
+ * try to change the array[] accesses into registers. However, on
+ * machines with less than ~25 registers, that won't really work,
+ * and at least gcc will make an unholy mess of it.
+ *
+ * So to avoid that mess which just slows things down, we force
+ * the stores to memory to actually happen (we might be better off
+ * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as
+ * suggested by Artur Skawina - that will also make gcc unable to
+ * try to do the silly "optimize away loads" part because it won't
+ * see what the value will be).
+ *
+ * On ARM we get the best code generation by forcing a full memory barrier
+ * between each SHA_ROUND, otherwise gcc happily get wild with spilling and
+ * the stack frame size simply explode and performance goes down the drain.
+ */
+
+#if defined(__i386__) || defined(__x86_64__)
+  #define setW(x, val) (*(volatile unsigned int *)&W(x) = (val))
+#elif defined(__GNUC__) && defined(__arm__)
+  #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0)
+#else
+  #define setW(x, val) (W(x) = (val))
+#endif
+
+/* This "rolls" over the 512-bit array */
+#define W(x) (array[(x)&15])
+
+/*
+ * Where do we get the source from? The first 16 iterations get it from
+ * the input data, the next mix it from the 512-bit array.
+ */
+#define SHA_SRC(t) get_be32((unsigned char *) block + (t)*4)
+#define SHA_MIX(t) SHA_ROL(W((t)+13) ^ W((t)+8) ^ W((t)+2) ^ W(t), 1)
+
+#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \
+	unsigned int TEMP = input(t); setW(t, TEMP); \
+	E += TEMP + SHA_ROL(A,5) + (fn) + (constant); \
+	B = SHA_ROR(B, 2); } while (0)
+
+#define T_0_15(t, A, B, C, D, E)  SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E )
+#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E )
+#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E )
+#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) ,  0xca62c1d6, A, B, C, D, E )
+
+static void blk_SHA1_Block(blk_SHA_CTX *ctx, const void *block)
+{
+	unsigned int A,B,C,D,E;
+	unsigned int array[16];
+
+	A = ctx->H[0];
+	B = ctx->H[1];
+	C = ctx->H[2];
+	D = ctx->H[3];
+	E = ctx->H[4];
+
+	/* Round 1 - iterations 0-16 take their input from 'block' */
+	T_0_15( 0, A, B, C, D, E);
+	T_0_15( 1, E, A, B, C, D);
+	T_0_15( 2, D, E, A, B, C);
+	T_0_15( 3, C, D, E, A, B);
+	T_0_15( 4, B, C, D, E, A);
+	T_0_15( 5, A, B, C, D, E);
+	T_0_15( 6, E, A, B, C, D);
+	T_0_15( 7, D, E, A, B, C);
+	T_0_15( 8, C, D, E, A, B);
+	T_0_15( 9, B, C, D, E, A);
+	T_0_15(10, A, B, C, D, E);
+	T_0_15(11, E, A, B, C, D);
+	T_0_15(12, D, E, A, B, C);
+	T_0_15(13, C, D, E, A, B);
+	T_0_15(14, B, C, D, E, A);
+	T_0_15(15, A, B, C, D, E);
+
+	/* Round 1 - tail. Input from 512-bit mixing array */
+	T_16_19(16, E, A, B, C, D);
+	T_16_19(17, D, E, A, B, C);
+	T_16_19(18, C, D, E, A, B);
+	T_16_19(19, B, C, D, E, A);
+
+	/* Round 2 */
+	T_20_39(20, A, B, C, D, E);
+	T_20_39(21, E, A, B, C, D);
+	T_20_39(22, D, E, A, B, C);
+	T_20_39(23, C, D, E, A, B);
+	T_20_39(24, B, C, D, E, A);
+	T_20_39(25, A, B, C, D, E);
+	T_20_39(26, E, A, B, C, D);
+	T_20_39(27, D, E, A, B, C);
+	T_20_39(28, C, D, E, A, B);
+	T_20_39(29, B, C, D, E, A);
+	T_20_39(30, A, B, C, D, E);
+	T_20_39(31, E, A, B, C, D);
+	T_20_39(32, D, E, A, B, C);
+	T_20_39(33, C, D, E, A, B);
+	T_20_39(34, B, C, D, E, A);
+	T_20_39(35, A, B, C, D, E);
+	T_20_39(36, E, A, B, C, D);
+	T_20_39(37, D, E, A, B, C);
+	T_20_39(38, C, D, E, A, B);
+	T_20_39(39, B, C, D, E, A);
+
+	/* Round 3 */
+	T_40_59(40, A, B, C, D, E);
+	T_40_59(41, E, A, B, C, D);
+	T_40_59(42, D, E, A, B, C);
+	T_40_59(43, C, D, E, A, B);
+	T_40_59(44, B, C, D, E, A);
+	T_40_59(45, A, B, C, D, E);
+	T_40_59(46, E, A, B, C, D);
+	T_40_59(47, D, E, A, B, C);
+	T_40_59(48, C, D, E, A, B);
+	T_40_59(49, B, C, D, E, A);
+	T_40_59(50, A, B, C, D, E);
+	T_40_59(51, E, A, B, C, D);
+	T_40_59(52, D, E, A, B, C);
+	T_40_59(53, C, D, E, A, B);
+	T_40_59(54, B, C, D, E, A);
+	T_40_59(55, A, B, C, D, E);
+	T_40_59(56, E, A, B, C, D);
+	T_40_59(57, D, E, A, B, C);
+	T_40_59(58, C, D, E, A, B);
+	T_40_59(59, B, C, D, E, A);
+
+	/* Round 4 */
+	T_60_79(60, A, B, C, D, E);
+	T_60_79(61, E, A, B, C, D);
+	T_60_79(62, D, E, A, B, C);
+	T_60_79(63, C, D, E, A, B);
+	T_60_79(64, B, C, D, E, A);
+	T_60_79(65, A, B, C, D, E);
+	T_60_79(66, E, A, B, C, D);
+	T_60_79(67, D, E, A, B, C);
+	T_60_79(68, C, D, E, A, B);
+	T_60_79(69, B, C, D, E, A);
+	T_60_79(70, A, B, C, D, E);
+	T_60_79(71, E, A, B, C, D);
+	T_60_79(72, D, E, A, B, C);
+	T_60_79(73, C, D, E, A, B);
+	T_60_79(74, B, C, D, E, A);
+	T_60_79(75, A, B, C, D, E);
+	T_60_79(76, E, A, B, C, D);
+	T_60_79(77, D, E, A, B, C);
+	T_60_79(78, C, D, E, A, B);
+	T_60_79(79, B, C, D, E, A);
+
+	ctx->H[0] += A;
+	ctx->H[1] += B;
+	ctx->H[2] += C;
+	ctx->H[3] += D;
+	ctx->H[4] += E;
+}
+
+void blk_SHA1_Init(blk_SHA_CTX *ctx)
+{
+	ctx->size = 0;
+
+	/* Initialize H with the magic constants (see FIPS180 for constants) */
+	ctx->H[0] = 0x67452301;
+	ctx->H[1] = 0xefcdab89;
+	ctx->H[2] = 0x98badcfe;
+	ctx->H[3] = 0x10325476;
+	ctx->H[4] = 0xc3d2e1f0;
+}
+
+void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *data, size_t len)
+{
+	unsigned int lenW = ctx->size & 63;
+
+	ctx->size += len;
+
+	/* Read the data into W and process blocks as they get full */
+	if (lenW) {
+		unsigned int left = 64 - lenW;
+		if (len < left)
+			left = len;
+		memcpy(lenW + (char *)ctx->W, data, left);
+		lenW = (lenW + left) & 63;
+		len -= left;
+		data = ((const char *)data + left);
+		if (lenW)
+			return;
+		blk_SHA1_Block(ctx, ctx->W);
+	}
+	while (len >= 64) {
+		blk_SHA1_Block(ctx, data);
+		data = ((const char *)data + 64);
+		len -= 64;
+	}
+	if (len)
+		memcpy(ctx->W, data, len);
+}
+
+void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx)
+{
+	static const unsigned char pad[64] = { 0x80 };
+	unsigned int padlen[2];
+	int i;
+
+	/* Pad with a binary 1 (ie 0x80), then zeroes, then length */
+	padlen[0] = htonl((uint32_t)(ctx->size >> 29));
+	padlen[1] = htonl((uint32_t)(ctx->size << 3));
+
+	i = ctx->size & 63;
+	blk_SHA1_Update(ctx, pad, 1 + (63 & (55 - i)));
+	blk_SHA1_Update(ctx, padlen, 8);
+
+	/* Output hash */
+	for (i = 0; i < 5; i++)
+		put_be32(hashout + i * 4, ctx->H[i]);
+}
diff --git a/block-sha1/sha1.h b/block-sha1/sha1.h
new file mode 100644
index 0000000000..47bb916636
--- /dev/null
+++ b/block-sha1/sha1.h
@@ -0,0 +1,24 @@
+/*
+ * SHA1 routine optimized to do word accesses rather than byte accesses,
+ * and to avoid unnecessary copies into the context array.
+ *
+ * This was initially based on the Mozilla SHA1 implementation, although
+ * none of the original Mozilla code remains.
+ */
+
+typedef struct {
+	unsigned long long size;
+	unsigned int H[5];
+	unsigned int W[16];
+} blk_SHA_CTX;
+
+void blk_SHA1_Init(blk_SHA_CTX *ctx);
+void blk_SHA1_Update(blk_SHA_CTX *ctx, const void *dataIn, size_t len);
+void blk_SHA1_Final(unsigned char hashout[20], blk_SHA_CTX *ctx);
+
+#ifndef platform_SHA_CTX
+#define platform_SHA_CTX	blk_SHA_CTX
+#define platform_SHA1_Init	blk_SHA1_Init
+#define platform_SHA1_Update	blk_SHA1_Update
+#define platform_SHA1_Final	blk_SHA1_Final
+#endif
diff --git a/bloom.c b/bloom.c
new file mode 100644
index 0000000000..0c8d2cebf9
--- /dev/null
+++ b/bloom.c
@@ -0,0 +1,542 @@
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "bloom.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "hashmap.h"
+#include "commit-graph.h"
+#include "commit.h"
+#include "commit-slab.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "config.h"
+#include "repository.h"
+
+define_commit_slab(bloom_filter_slab, struct bloom_filter);
+
+static struct bloom_filter_slab bloom_filters;
+
+struct pathmap_hash_entry {
+    struct hashmap_entry entry;
+    const char path[FLEX_ARRAY];
+};
+
+static uint32_t rotate_left(uint32_t value, int32_t count)
+{
+	uint32_t mask = 8 * sizeof(uint32_t) - 1;
+	count &= mask;
+	return ((value << count) | (value >> ((-count) & mask)));
+}
+
+static inline unsigned char get_bitmask(uint32_t pos)
+{
+	return ((unsigned char)1) << (pos & (BITS_PER_WORD - 1));
+}
+
+static int check_bloom_offset(struct commit_graph *g, uint32_t pos,
+			      uint32_t offset)
+{
+	/*
+	 * Note that we allow offsets equal to the data size, which would set
+	 * our pointers at one past the end of the chunk memory. This is
+	 * necessary because the on-disk index points to the end of the
+	 * entries (so we can compute size by comparing adjacent ones). And
+	 * naturally the final entry's end is one-past-the-end of the chunk.
+	 */
+	if (offset <= g->chunk_bloom_data_size - BLOOMDATA_CHUNK_HEADER_SIZE)
+		return 0;
+
+	warning("ignoring out-of-range offset (%"PRIuMAX") for changed-path"
+		" filter at pos %"PRIuMAX" of %s (chunk size: %"PRIuMAX")",
+		(uintmax_t)offset, (uintmax_t)pos,
+		g->filename, (uintmax_t)g->chunk_bloom_data_size);
+	return -1;
+}
+
+int load_bloom_filter_from_graph(struct commit_graph *g,
+				 struct bloom_filter *filter,
+				 uint32_t graph_pos)
+{
+	uint32_t lex_pos, start_index, end_index;
+
+	while (graph_pos < g->num_commits_in_base)
+		g = g->base_graph;
+
+	/* The commit graph commit 'c' lives in doesn't carry Bloom filters. */
+	if (!g->chunk_bloom_indexes)
+		return 0;
+
+	lex_pos = graph_pos - g->num_commits_in_base;
+
+	end_index = get_be32(g->chunk_bloom_indexes + 4 * lex_pos);
+
+	if (lex_pos > 0)
+		start_index = get_be32(g->chunk_bloom_indexes + 4 * (lex_pos - 1));
+	else
+		start_index = 0;
+
+	if (check_bloom_offset(g, lex_pos, end_index) < 0 ||
+	    check_bloom_offset(g, lex_pos - 1, start_index) < 0)
+		return 0;
+
+	if (end_index < start_index) {
+		warning("ignoring decreasing changed-path index offsets"
+			" (%"PRIuMAX" > %"PRIuMAX") for positions"
+			" %"PRIuMAX" and %"PRIuMAX" of %s",
+			(uintmax_t)start_index, (uintmax_t)end_index,
+			(uintmax_t)(lex_pos-1), (uintmax_t)lex_pos,
+			g->filename);
+		return 0;
+	}
+
+	filter->len = end_index - start_index;
+	filter->data = (unsigned char *)(g->chunk_bloom_data +
+					sizeof(unsigned char) * start_index +
+					BLOOMDATA_CHUNK_HEADER_SIZE);
+	filter->version = g->bloom_filter_settings->hash_version;
+	filter->to_free = NULL;
+
+	return 1;
+}
+
+/*
+ * Calculate the murmur3 32-bit hash value for the given data
+ * using the given seed.
+ * Produces a uniformly distributed hash value.
+ * Not considered to be cryptographically secure.
+ * Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm
+ */
+uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len)
+{
+	const uint32_t c1 = 0xcc9e2d51;
+	const uint32_t c2 = 0x1b873593;
+	const uint32_t r1 = 15;
+	const uint32_t r2 = 13;
+	const uint32_t m = 5;
+	const uint32_t n = 0xe6546b64;
+	int i;
+	uint32_t k1 = 0;
+	const char *tail;
+
+	int len4 = len / sizeof(uint32_t);
+
+	uint32_t k;
+	for (i = 0; i < len4; i++) {
+		uint32_t byte1 = (uint32_t)(unsigned char)data[4*i];
+		uint32_t byte2 = ((uint32_t)(unsigned char)data[4*i + 1]) << 8;
+		uint32_t byte3 = ((uint32_t)(unsigned char)data[4*i + 2]) << 16;
+		uint32_t byte4 = ((uint32_t)(unsigned char)data[4*i + 3]) << 24;
+		k = byte1 | byte2 | byte3 | byte4;
+		k *= c1;
+		k = rotate_left(k, r1);
+		k *= c2;
+
+		seed ^= k;
+		seed = rotate_left(seed, r2) * m + n;
+	}
+
+	tail = (data + len4 * sizeof(uint32_t));
+
+	switch (len & (sizeof(uint32_t) - 1)) {
+	case 3:
+		k1 ^= ((uint32_t)(unsigned char)tail[2]) << 16;
+		/*-fallthrough*/
+	case 2:
+		k1 ^= ((uint32_t)(unsigned char)tail[1]) << 8;
+		/*-fallthrough*/
+	case 1:
+		k1 ^= ((uint32_t)(unsigned char)tail[0]) << 0;
+		k1 *= c1;
+		k1 = rotate_left(k1, r1);
+		k1 *= c2;
+		seed ^= k1;
+		break;
+	}
+
+	seed ^= (uint32_t)len;
+	seed ^= (seed >> 16);
+	seed *= 0x85ebca6b;
+	seed ^= (seed >> 13);
+	seed *= 0xc2b2ae35;
+	seed ^= (seed >> 16);
+
+	return seed;
+}
+
+static uint32_t murmur3_seeded_v1(uint32_t seed, const char *data, size_t len)
+{
+	const uint32_t c1 = 0xcc9e2d51;
+	const uint32_t c2 = 0x1b873593;
+	const uint32_t r1 = 15;
+	const uint32_t r2 = 13;
+	const uint32_t m = 5;
+	const uint32_t n = 0xe6546b64;
+	int i;
+	uint32_t k1 = 0;
+	const char *tail;
+
+	int len4 = len / sizeof(uint32_t);
+
+	uint32_t k;
+	for (i = 0; i < len4; i++) {
+		uint32_t byte1 = (uint32_t)data[4*i];
+		uint32_t byte2 = ((uint32_t)data[4*i + 1]) << 8;
+		uint32_t byte3 = ((uint32_t)data[4*i + 2]) << 16;
+		uint32_t byte4 = ((uint32_t)data[4*i + 3]) << 24;
+		k = byte1 | byte2 | byte3 | byte4;
+		k *= c1;
+		k = rotate_left(k, r1);
+		k *= c2;
+
+		seed ^= k;
+		seed = rotate_left(seed, r2) * m + n;
+	}
+
+	tail = (data + len4 * sizeof(uint32_t));
+
+	switch (len & (sizeof(uint32_t) - 1)) {
+	case 3:
+		k1 ^= ((uint32_t)tail[2]) << 16;
+		/*-fallthrough*/
+	case 2:
+		k1 ^= ((uint32_t)tail[1]) << 8;
+		/*-fallthrough*/
+	case 1:
+		k1 ^= ((uint32_t)tail[0]) << 0;
+		k1 *= c1;
+		k1 = rotate_left(k1, r1);
+		k1 *= c2;
+		seed ^= k1;
+		break;
+	}
+
+	seed ^= (uint32_t)len;
+	seed ^= (seed >> 16);
+	seed *= 0x85ebca6b;
+	seed ^= (seed >> 13);
+	seed *= 0xc2b2ae35;
+	seed ^= (seed >> 16);
+
+	return seed;
+}
+
+void fill_bloom_key(const char *data,
+		    size_t len,
+		    struct bloom_key *key,
+		    const struct bloom_filter_settings *settings)
+{
+	int i;
+	const uint32_t seed0 = 0x293ae76f;
+	const uint32_t seed1 = 0x7e646e2c;
+	uint32_t hash0, hash1;
+	if (settings->hash_version == 2) {
+		hash0 = murmur3_seeded_v2(seed0, data, len);
+		hash1 = murmur3_seeded_v2(seed1, data, len);
+	} else {
+		hash0 = murmur3_seeded_v1(seed0, data, len);
+		hash1 = murmur3_seeded_v1(seed1, data, len);
+	}
+
+	key->hashes = (uint32_t *)xcalloc(settings->num_hashes, sizeof(uint32_t));
+	for (i = 0; i < settings->num_hashes; i++)
+		key->hashes[i] = hash0 + i * hash1;
+}
+
+void clear_bloom_key(struct bloom_key *key)
+{
+	FREE_AND_NULL(key->hashes);
+}
+
+void add_key_to_filter(const struct bloom_key *key,
+		       struct bloom_filter *filter,
+		       const struct bloom_filter_settings *settings)
+{
+	int i;
+	uint64_t mod = filter->len * BITS_PER_WORD;
+
+	for (i = 0; i < settings->num_hashes; i++) {
+		uint64_t hash_mod = key->hashes[i] % mod;
+		uint64_t block_pos = hash_mod / BITS_PER_WORD;
+
+		filter->data[block_pos] |= get_bitmask(hash_mod);
+	}
+}
+
+void init_bloom_filters(void)
+{
+	init_bloom_filter_slab(&bloom_filters);
+}
+
+static void free_one_bloom_filter(struct bloom_filter *filter)
+{
+	if (!filter)
+		return;
+	free(filter->to_free);
+}
+
+void deinit_bloom_filters(void)
+{
+	deep_clear_bloom_filter_slab(&bloom_filters, free_one_bloom_filter);
+}
+
+static int pathmap_cmp(const void *hashmap_cmp_fn_data UNUSED,
+		       const struct hashmap_entry *eptr,
+		       const struct hashmap_entry *entry_or_key,
+		       const void *keydata UNUSED)
+{
+	const struct pathmap_hash_entry *e1, *e2;
+
+	e1 = container_of(eptr, const struct pathmap_hash_entry, entry);
+	e2 = container_of(entry_or_key, const struct pathmap_hash_entry, entry);
+
+	return strcmp(e1->path, e2->path);
+}
+
+static void init_truncated_large_filter(struct bloom_filter *filter,
+					int version)
+{
+	filter->data = filter->to_free = xmalloc(1);
+	filter->data[0] = 0xFF;
+	filter->len = 1;
+	filter->version = version;
+}
+
+#define VISITED   (1u<<21)
+#define HIGH_BITS (1u<<22)
+
+static int has_entries_with_high_bit(struct repository *r, struct tree *t)
+{
+	if (parse_tree(t))
+		return 1;
+
+	if (!(t->object.flags & VISITED)) {
+		struct tree_desc desc;
+		struct name_entry entry;
+
+		init_tree_desc(&desc, &t->object.oid, t->buffer, t->size);
+		while (tree_entry(&desc, &entry)) {
+			size_t i;
+			for (i = 0; i < entry.pathlen; i++) {
+				if (entry.path[i] & 0x80) {
+					t->object.flags |= HIGH_BITS;
+					goto done;
+				}
+			}
+
+			if (S_ISDIR(entry.mode)) {
+				struct tree *sub = lookup_tree(r, &entry.oid);
+				if (sub && has_entries_with_high_bit(r, sub)) {
+					t->object.flags |= HIGH_BITS;
+					goto done;
+				}
+			}
+
+		}
+
+done:
+		t->object.flags |= VISITED;
+	}
+
+	return !!(t->object.flags & HIGH_BITS);
+}
+
+static int commit_tree_has_high_bit_paths(struct repository *r,
+					  struct commit *c)
+{
+	struct tree *t;
+	if (repo_parse_commit(r, c))
+		return 1;
+	t = repo_get_commit_tree(r, c);
+	if (!t)
+		return 1;
+	return has_entries_with_high_bit(r, t);
+}
+
+static struct bloom_filter *upgrade_filter(struct repository *r, struct commit *c,
+					   struct bloom_filter *filter,
+					   int hash_version)
+{
+	struct commit_list *p = c->parents;
+	if (commit_tree_has_high_bit_paths(r, c))
+		return NULL;
+
+	if (p && commit_tree_has_high_bit_paths(r, p->item))
+		return NULL;
+
+	filter->version = hash_version;
+
+	return filter;
+}
+
+struct bloom_filter *get_bloom_filter(struct repository *r, struct commit *c)
+{
+	struct bloom_filter *filter;
+	int hash_version;
+
+	filter = get_or_compute_bloom_filter(r, c, 0, NULL, NULL);
+	if (!filter)
+		return NULL;
+
+	prepare_repo_settings(r);
+	hash_version = r->settings.commit_graph_changed_paths_version;
+
+	if (!(hash_version == -1 || hash_version == filter->version))
+		return NULL; /* unusable filter */
+	return filter;
+}
+
+struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
+						 struct commit *c,
+						 int compute_if_not_present,
+						 const struct bloom_filter_settings *settings,
+						 enum bloom_filter_computed *computed)
+{
+	struct bloom_filter *filter;
+	int i;
+	struct diff_options diffopt;
+
+	if (computed)
+		*computed = BLOOM_NOT_COMPUTED;
+
+	if (!bloom_filters.slab_size)
+		return NULL;
+
+	filter = bloom_filter_slab_at(&bloom_filters, c);
+
+	if (!filter->data) {
+		uint32_t graph_pos;
+		if (repo_find_commit_pos_in_graph(r, c, &graph_pos))
+			load_bloom_filter_from_graph(r->objects->commit_graph,
+						     filter, graph_pos);
+	}
+
+	if (filter->data && filter->len) {
+		struct bloom_filter *upgrade;
+		if (!settings || settings->hash_version == filter->version)
+			return filter;
+
+		/* version mismatch, see if we can upgrade */
+		if (compute_if_not_present &&
+		    git_env_bool("GIT_TEST_UPGRADE_BLOOM_FILTERS", 1)) {
+			upgrade = upgrade_filter(r, c, filter,
+						 settings->hash_version);
+			if (upgrade) {
+				if (computed)
+					*computed |= BLOOM_UPGRADED;
+				return upgrade;
+			}
+		}
+	}
+	if (!compute_if_not_present)
+		return NULL;
+
+	repo_diff_setup(r, &diffopt);
+	diffopt.flags.recursive = 1;
+	diffopt.detect_rename = 0;
+	diffopt.max_changes = settings->max_changed_paths;
+	diff_setup_done(&diffopt);
+
+	/* ensure commit is parsed so we have parent information */
+	repo_parse_commit(r, c);
+
+	if (c->parents)
+		diff_tree_oid(&c->parents->item->object.oid, &c->object.oid, "", &diffopt);
+	else
+		diff_tree_oid(NULL, &c->object.oid, "", &diffopt);
+	diffcore_std(&diffopt);
+
+	if (diff_queued_diff.nr <= settings->max_changed_paths) {
+		struct hashmap pathmap = HASHMAP_INIT(pathmap_cmp, NULL);
+		struct pathmap_hash_entry *e;
+		struct hashmap_iter iter;
+
+		for (i = 0; i < diff_queued_diff.nr; i++) {
+			const char *path = diff_queued_diff.queue[i]->two->path;
+
+			/*
+			 * Add each leading directory of the changed file, i.e. for
+			 * 'dir/subdir/file' add 'dir' and 'dir/subdir' as well, so
+			 * the Bloom filter could be used to speed up commands like
+			 * 'git log dir/subdir', too.
+			 *
+			 * Note that directories are added without the trailing '/'.
+			 */
+			do {
+				char *last_slash = strrchr(path, '/');
+
+				FLEX_ALLOC_STR(e, path, path);
+				hashmap_entry_init(&e->entry, strhash(path));
+
+				if (!hashmap_get(&pathmap, &e->entry, NULL))
+					hashmap_add(&pathmap, &e->entry);
+				else
+					free(e);
+
+				if (!last_slash)
+					last_slash = (char*)path;
+				*last_slash = '\0';
+
+			} while (*path);
+		}
+
+		if (hashmap_get_size(&pathmap) > settings->max_changed_paths) {
+			init_truncated_large_filter(filter,
+						    settings->hash_version);
+			if (computed)
+				*computed |= BLOOM_TRUNC_LARGE;
+			goto cleanup;
+		}
+
+		filter->len = (hashmap_get_size(&pathmap) * settings->bits_per_entry + BITS_PER_WORD - 1) / BITS_PER_WORD;
+		filter->version = settings->hash_version;
+		if (!filter->len) {
+			if (computed)
+				*computed |= BLOOM_TRUNC_EMPTY;
+			filter->len = 1;
+		}
+		CALLOC_ARRAY(filter->data, filter->len);
+		filter->to_free = filter->data;
+
+		hashmap_for_each_entry(&pathmap, &iter, e, entry) {
+			struct bloom_key key;
+			fill_bloom_key(e->path, strlen(e->path), &key, settings);
+			add_key_to_filter(&key, filter, settings);
+			clear_bloom_key(&key);
+		}
+
+	cleanup:
+		hashmap_clear_and_free(&pathmap, struct pathmap_hash_entry, entry);
+	} else {
+		init_truncated_large_filter(filter, settings->hash_version);
+
+		if (computed)
+			*computed |= BLOOM_TRUNC_LARGE;
+	}
+
+	if (computed)
+		*computed |= BLOOM_COMPUTED;
+
+	diff_queue_clear(&diff_queued_diff);
+	return filter;
+}
+
+int bloom_filter_contains(const struct bloom_filter *filter,
+			  const struct bloom_key *key,
+			  const struct bloom_filter_settings *settings)
+{
+	int i;
+	uint64_t mod = filter->len * BITS_PER_WORD;
+
+	if (!mod)
+		return -1;
+
+	for (i = 0; i < settings->num_hashes; i++) {
+		uint64_t hash_mod = key->hashes[i] % mod;
+		uint64_t block_pos = hash_mod / BITS_PER_WORD;
+		if (!(filter->data[block_pos] & get_bitmask(hash_mod)))
+			return 0;
+	}
+
+	return 1;
+}
diff --git a/bloom.h b/bloom.h
new file mode 100644
index 0000000000..6e46489a20
--- /dev/null
+++ b/bloom.h
@@ -0,0 +1,140 @@
+#ifndef BLOOM_H
+#define BLOOM_H
+
+struct commit;
+struct repository;
+struct commit_graph;
+
+struct bloom_filter_settings {
+	/*
+	 * The version of the hashing technique being used.
+	 * The newest version is 2, which is
+	 * the seeded murmur3 hashing technique implemented
+	 * in bloom.c. Bloom filters of version 1 were created
+	 * with prior versions of Git, which had a bug in the
+	 * implementation of the hash function.
+	 */
+	uint32_t hash_version;
+
+	/*
+	 * The number of times a path is hashed, i.e. the
+	 * number of bit positions that cumulatively
+	 * determine whether a path is present in the
+	 * Bloom filter.
+	 */
+	uint32_t num_hashes;
+
+	/*
+	 * The minimum number of bits per entry in the Bloom
+	 * filter. If the filter contains 'n' entries, then
+	 * filter size is the minimum number of 8-bit words
+	 * that contain n*b bits.
+	 */
+	uint32_t bits_per_entry;
+
+	/*
+	 * The maximum number of changed paths per commit
+	 * before declaring a Bloom filter to be too-large.
+	 *
+	 * Not written to the commit-graph file.
+	 */
+	uint32_t max_changed_paths;
+};
+
+#define DEFAULT_BLOOM_MAX_CHANGES 512
+#define DEFAULT_BLOOM_FILTER_SETTINGS { 1, 7, 10, DEFAULT_BLOOM_MAX_CHANGES }
+#define BITS_PER_WORD 8
+#define BLOOMDATA_CHUNK_HEADER_SIZE 3 * sizeof(uint32_t)
+
+/*
+ * A bloom_filter struct represents a data segment to
+ * use when testing hash values. The 'len' member
+ * dictates how many entries are stored in
+ * 'data'.
+ */
+struct bloom_filter {
+	unsigned char *data;
+	size_t len;
+	int version;
+
+	void *to_free;
+};
+
+/*
+ * A bloom_key represents the k hash values for a
+ * given string. These can be precomputed and
+ * stored in a bloom_key for re-use when testing
+ * against a bloom_filter. The number of hashes is
+ * given by the Bloom filter settings and is the same
+ * for all Bloom filters and keys interacting with
+ * the loaded version of the commit graph file and
+ * the Bloom data chunks.
+ */
+struct bloom_key {
+	uint32_t *hashes;
+};
+
+int load_bloom_filter_from_graph(struct commit_graph *g,
+				 struct bloom_filter *filter,
+				 uint32_t graph_pos);
+
+/*
+ * Calculate the murmur3 32-bit hash value for the given data
+ * using the given seed.
+ * Produces a uniformly distributed hash value.
+ * Not considered to be cryptographically secure.
+ * Implemented as described in https://en.wikipedia.org/wiki/MurmurHash#Algorithm
+ */
+uint32_t murmur3_seeded_v2(uint32_t seed, const char *data, size_t len);
+
+void fill_bloom_key(const char *data,
+		    size_t len,
+		    struct bloom_key *key,
+		    const struct bloom_filter_settings *settings);
+void clear_bloom_key(struct bloom_key *key);
+
+void add_key_to_filter(const struct bloom_key *key,
+		       struct bloom_filter *filter,
+		       const struct bloom_filter_settings *settings);
+
+void init_bloom_filters(void);
+void deinit_bloom_filters(void);
+
+enum bloom_filter_computed {
+	BLOOM_NOT_COMPUTED = (1 << 0),
+	BLOOM_COMPUTED     = (1 << 1),
+	BLOOM_TRUNC_LARGE  = (1 << 2),
+	BLOOM_TRUNC_EMPTY  = (1 << 3),
+	BLOOM_UPGRADED     = (1 << 4),
+};
+
+struct bloom_filter *get_or_compute_bloom_filter(struct repository *r,
+						 struct commit *c,
+						 int compute_if_not_present,
+						 const struct bloom_filter_settings *settings,
+						 enum bloom_filter_computed *computed);
+
+/*
+ * Find the Bloom filter associated with the given commit "c".
+ *
+ * If any of the following are true
+ *
+ *   - the repository does not have a commit-graph, or
+ *   - the repository disables reading from the commit-graph, or
+ *   - the given commit does not have a Bloom filter computed, or
+ *   - there is a Bloom filter for commit "c", but it cannot be read
+ *     because the filter uses an incompatible version of murmur3
+ *
+ * , then `get_bloom_filter()` will return NULL. Otherwise, the corresponding
+ * Bloom filter will be returned.
+ *
+ * For callers who wish to inspect Bloom filters with incompatible hash
+ * versions, use get_or_compute_bloom_filter().
+ */
+struct bloom_filter *get_bloom_filter(struct repository *r, struct commit *c);
+
+int bloom_filter_contains(const struct bloom_filter *filter,
+			  const struct bloom_key *key,
+			  const struct bloom_filter_settings *settings);
+
+#endif
diff --git a/branch.c b/branch.c
new file mode 100644
index 0000000000..77716966fe
--- /dev/null
+++ b/branch.c
@@ -0,0 +1,860 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "advice.h"
+#include "config.h"
+#include "branch.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "path.h"
+#include "refs.h"
+#include "refspec.h"
+#include "remote.h"
+#include "repository.h"
+#include "sequencer.h"
+#include "commit.h"
+#include "worktree.h"
+#include "submodule-config.h"
+#include "run-command.h"
+#include "strmap.h"
+
+struct tracking {
+	struct refspec_item spec;
+	struct string_list *srcs;
+	const char *remote;
+	int matches;
+};
+
+struct find_tracked_branch_cb {
+	struct tracking *tracking;
+	struct string_list ambiguous_remotes;
+};
+
+static int find_tracked_branch(struct remote *remote, void *priv)
+{
+	struct find_tracked_branch_cb *ftb = priv;
+	struct tracking *tracking = ftb->tracking;
+
+	if (!remote_find_tracking(remote, &tracking->spec)) {
+		switch (++tracking->matches) {
+		case 1:
+			string_list_append_nodup(tracking->srcs, tracking->spec.src);
+			tracking->remote = remote->name;
+			break;
+		case 2:
+			/* there are at least two remotes; backfill the first one */
+			string_list_append(&ftb->ambiguous_remotes, tracking->remote);
+			/* fall through */
+		default:
+			string_list_append(&ftb->ambiguous_remotes, remote->name);
+			free(tracking->spec.src);
+			string_list_clear(tracking->srcs, 0);
+		break;
+		}
+		/* remote_find_tracking() searches by src if present */
+		tracking->spec.src = NULL;
+	}
+	return 0;
+}
+
+static int should_setup_rebase(const char *origin)
+{
+	switch (autorebase) {
+	case AUTOREBASE_NEVER:
+		return 0;
+	case AUTOREBASE_LOCAL:
+		return origin == NULL;
+	case AUTOREBASE_REMOTE:
+		return origin != NULL;
+	case AUTOREBASE_ALWAYS:
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ * Install upstream tracking configuration for a branch; specifically, add
+ * `branch.<name>.remote` and `branch.<name>.merge` entries.
+ *
+ * `flag` contains integer flags for options; currently only
+ * BRANCH_CONFIG_VERBOSE is checked.
+ *
+ * `local` is the name of the branch whose configuration we're installing.
+ *
+ * `origin` is the name of the remote owning the upstream branches. NULL means
+ * the upstream branches are local to this repo.
+ *
+ * `remotes` is a list of refs that are upstream of local
+ */
+static int install_branch_config_multiple_remotes(int flag, const char *local,
+		const char *origin, struct string_list *remotes)
+{
+	const char *shortname = NULL;
+	struct strbuf key = STRBUF_INIT;
+	struct string_list_item *item;
+	int rebasing = should_setup_rebase(origin);
+
+	if (!remotes->nr)
+		BUG("must provide at least one remote for branch config");
+	if (rebasing && remotes->nr > 1)
+		die(_("cannot inherit upstream tracking configuration of "
+		      "multiple refs when rebasing is requested"));
+
+	/*
+	 * If the new branch is trying to track itself, something has gone
+	 * wrong. Warn the user and don't proceed any further.
+	 */
+	if (!origin)
+		for_each_string_list_item(item, remotes)
+			if (skip_prefix(item->string, "refs/heads/", &shortname)
+			    && !strcmp(local, shortname)) {
+				warning(_("not setting branch '%s' as its own upstream"),
+					local);
+				return 0;
+			}
+
+	strbuf_addf(&key, "branch.%s.remote", local);
+	if (git_config_set_gently(key.buf, origin ? origin : ".") < 0)
+		goto out_err;
+
+	strbuf_reset(&key);
+	strbuf_addf(&key, "branch.%s.merge", local);
+	/*
+	 * We want to overwrite any existing config with all the branches in
+	 * "remotes". Override any existing config, then write our branches. If
+	 * more than one is provided, use CONFIG_REGEX_NONE to preserve what
+	 * we've written so far.
+	 */
+	if (git_config_set_gently(key.buf, NULL) < 0)
+		goto out_err;
+	for_each_string_list_item(item, remotes)
+		if (git_config_set_multivar_gently(key.buf, item->string, CONFIG_REGEX_NONE, 0) < 0)
+			goto out_err;
+
+	if (rebasing) {
+		strbuf_reset(&key);
+		strbuf_addf(&key, "branch.%s.rebase", local);
+		if (git_config_set_gently(key.buf, "true") < 0)
+			goto out_err;
+	}
+	strbuf_release(&key);
+
+	if (flag & BRANCH_CONFIG_VERBOSE) {
+		struct strbuf tmp_ref_name = STRBUF_INIT;
+		struct string_list friendly_ref_names = STRING_LIST_INIT_DUP;
+
+		for_each_string_list_item(item, remotes) {
+			shortname = item->string;
+			skip_prefix(shortname, "refs/heads/", &shortname);
+			if (origin) {
+				strbuf_addf(&tmp_ref_name, "%s/%s",
+					    origin, shortname);
+				string_list_append_nodup(
+					&friendly_ref_names,
+					strbuf_detach(&tmp_ref_name, NULL));
+			} else {
+				string_list_append(
+					&friendly_ref_names, shortname);
+			}
+		}
+
+		if (remotes->nr == 1) {
+			/*
+			 * Rebasing is only allowed in the case of a single
+			 * upstream branch.
+			 */
+			printf_ln(rebasing ?
+				_("branch '%s' set up to track '%s' by rebasing.") :
+				_("branch '%s' set up to track '%s'."),
+				local, friendly_ref_names.items[0].string);
+		} else {
+			printf_ln(_("branch '%s' set up to track:"), local);
+			for_each_string_list_item(item, &friendly_ref_names)
+				printf_ln("  %s", item->string);
+		}
+
+		string_list_clear(&friendly_ref_names, 0);
+	}
+
+	return 0;
+
+out_err:
+	strbuf_release(&key);
+	error(_("unable to write upstream branch configuration"));
+
+	advise(_("\nAfter fixing the error cause you may try to fix up\n"
+		"the remote tracking information by invoking:"));
+	if (remotes->nr == 1)
+		advise("  git branch --set-upstream-to=%s%s%s",
+			origin ? origin : "",
+			origin ? "/" : "",
+			remotes->items[0].string);
+	else {
+		advise("  git config --add branch.\"%s\".remote %s",
+			local, origin ? origin : ".");
+		for_each_string_list_item(item, remotes)
+			advise("  git config --add branch.\"%s\".merge %s",
+				local, item->string);
+	}
+
+	return -1;
+}
+
+int install_branch_config(int flag, const char *local, const char *origin,
+		const char *remote)
+{
+	int ret;
+	struct string_list remotes = STRING_LIST_INIT_DUP;
+
+	string_list_append(&remotes, remote);
+	ret = install_branch_config_multiple_remotes(flag, local, origin, &remotes);
+	string_list_clear(&remotes, 0);
+	return ret;
+}
+
+static int inherit_tracking(struct tracking *tracking, const char *orig_ref)
+{
+	const char *bare_ref;
+	struct branch *branch;
+	int i;
+
+	bare_ref = orig_ref;
+	skip_prefix(orig_ref, "refs/heads/", &bare_ref);
+
+	branch = branch_get(bare_ref);
+	if (!branch->remote_name) {
+		warning(_("asked to inherit tracking from '%s', but no remote is set"),
+			bare_ref);
+		return -1;
+	}
+
+	if (branch->merge_nr < 1 || !branch->merge_name || !branch->merge_name[0]) {
+		warning(_("asked to inherit tracking from '%s', but no merge configuration is set"),
+			bare_ref);
+		return -1;
+	}
+
+	tracking->remote = branch->remote_name;
+	for (i = 0; i < branch->merge_nr; i++)
+		string_list_append(tracking->srcs, branch->merge_name[i]);
+	return 0;
+}
+
+/*
+ * Used internally to set the branch.<new_ref>.{remote,merge} config
+ * settings so that branch 'new_ref' tracks 'orig_ref'. Unlike
+ * dwim_and_setup_tracking(), this does not do DWIM, i.e. "origin/main"
+ * will not be expanded to "refs/remotes/origin/main", so it is not safe
+ * for 'orig_ref' to be raw user input.
+ */
+static void setup_tracking(const char *new_ref, const char *orig_ref,
+			   enum branch_track track, int quiet)
+{
+	struct tracking tracking;
+	struct string_list tracking_srcs = STRING_LIST_INIT_DUP;
+	int config_flags = quiet ? 0 : BRANCH_CONFIG_VERBOSE;
+	struct find_tracked_branch_cb ftb_cb = {
+		.tracking = &tracking,
+		.ambiguous_remotes = STRING_LIST_INIT_DUP,
+	};
+
+	if (!track)
+		BUG("asked to set up tracking, but tracking is disallowed");
+
+	memset(&tracking, 0, sizeof(tracking));
+	tracking.spec.dst = (char *)orig_ref;
+	tracking.srcs = &tracking_srcs;
+	if (track != BRANCH_TRACK_INHERIT)
+		for_each_remote(find_tracked_branch, &ftb_cb);
+	else if (inherit_tracking(&tracking, orig_ref))
+		goto cleanup;
+
+	if (!tracking.matches)
+		switch (track) {
+		/* If ref is not remote, still use local */
+		case BRANCH_TRACK_ALWAYS:
+		case BRANCH_TRACK_EXPLICIT:
+		case BRANCH_TRACK_OVERRIDE:
+		/* Remote matches not evaluated */
+		case BRANCH_TRACK_INHERIT:
+			break;
+		/* Otherwise, if no remote don't track */
+		default:
+			goto cleanup;
+		}
+
+	/*
+	 * This check does not apply to BRANCH_TRACK_INHERIT;
+	 * that supports multiple entries in tracking_srcs but
+	 * leaves tracking.matches at 0.
+	 */
+	if (tracking.matches > 1) {
+		int status = die_message(_("not tracking: ambiguous information for ref '%s'"),
+					    orig_ref);
+		if (advice_enabled(ADVICE_AMBIGUOUS_FETCH_REFSPEC)) {
+			struct strbuf remotes_advice = STRBUF_INIT;
+			struct string_list_item *item;
+
+			for_each_string_list_item(item, &ftb_cb.ambiguous_remotes)
+				/*
+				 * TRANSLATORS: This is a line listing a remote with duplicate
+				 * refspecs in the advice message below. For RTL languages you'll
+				 * probably want to swap the "%s" and leading "  " space around.
+				 */
+				strbuf_addf(&remotes_advice, _("  %s\n"), item->string);
+
+			/*
+			 * TRANSLATORS: The second argument is a \n-delimited list of
+			 * duplicate refspecs, composed above.
+			 */
+			advise(_("There are multiple remotes whose fetch refspecs map to the remote\n"
+				 "tracking ref '%s':\n"
+				 "%s"
+				 "\n"
+				 "This is typically a configuration error.\n"
+				 "\n"
+				 "To support setting up tracking branches, ensure that\n"
+				 "different remotes' fetch refspecs map into different\n"
+				 "tracking namespaces."), orig_ref,
+			       remotes_advice.buf);
+			strbuf_release(&remotes_advice);
+		}
+		exit(status);
+	}
+
+	if (track == BRANCH_TRACK_SIMPLE) {
+		/*
+		 * Only track if remote branch name matches.
+		 * Reaching into items[0].string is safe because
+		 * we know there is at least one and not more than
+		 * one entry (because only BRANCH_TRACK_INHERIT can
+		 * produce more than one entry).
+		 */
+		const char *tracked_branch;
+		if (!skip_prefix(tracking.srcs->items[0].string,
+				 "refs/heads/", &tracked_branch) ||
+		    strcmp(tracked_branch, new_ref))
+			goto cleanup;
+	}
+
+	if (tracking.srcs->nr < 1)
+		string_list_append(tracking.srcs, orig_ref);
+	if (install_branch_config_multiple_remotes(config_flags, new_ref,
+				tracking.remote, tracking.srcs) < 0)
+		exit(1);
+
+cleanup:
+	string_list_clear(&tracking_srcs, 0);
+	string_list_clear(&ftb_cb.ambiguous_remotes, 0);
+}
+
+int read_branch_desc(struct strbuf *buf, const char *branch_name)
+{
+	char *v = NULL;
+	struct strbuf name = STRBUF_INIT;
+	strbuf_addf(&name, "branch.%s.description", branch_name);
+	if (git_config_get_string(name.buf, &v)) {
+		strbuf_release(&name);
+		return -1;
+	}
+	strbuf_addstr(buf, v);
+	free(v);
+	strbuf_release(&name);
+	return 0;
+}
+
+/*
+ * Check if 'name' can be a valid name for a branch; die otherwise.
+ * Return 1 if the named branch already exists; return 0 otherwise.
+ * Fill ref with the full refname for the branch.
+ */
+int validate_branchname(const char *name, struct strbuf *ref)
+{
+	if (check_branch_ref(ref, name)) {
+		int code = die_message(_("'%s' is not a valid branch name"), name);
+		advise_if_enabled(ADVICE_REF_SYNTAX,
+				  _("See `man git check-ref-format`"));
+		exit(code);
+	}
+
+	return refs_ref_exists(get_main_ref_store(the_repository), ref->buf);
+}
+
+static int initialized_checked_out_branches;
+static struct strmap current_checked_out_branches = STRMAP_INIT;
+
+static void prepare_checked_out_branches(void)
+{
+	int i = 0;
+	struct worktree **worktrees;
+
+	if (initialized_checked_out_branches)
+		return;
+	initialized_checked_out_branches = 1;
+
+	worktrees = get_worktrees();
+
+	while (worktrees[i]) {
+		char *old;
+		struct wt_status_state state = { 0 };
+		struct worktree *wt = worktrees[i++];
+		struct string_list update_refs = STRING_LIST_INIT_DUP;
+
+		if (wt->is_bare)
+			continue;
+
+		if (wt->head_ref) {
+			old = strmap_put(&current_checked_out_branches,
+					 wt->head_ref,
+					 xstrdup(wt->path));
+			free(old);
+		}
+
+		if (wt_status_check_rebase(wt, &state) &&
+		    (state.rebase_in_progress || state.rebase_interactive_in_progress) &&
+		    state.branch) {
+			struct strbuf ref = STRBUF_INIT;
+			strbuf_addf(&ref, "refs/heads/%s", state.branch);
+			old = strmap_put(&current_checked_out_branches,
+					 ref.buf,
+					 xstrdup(wt->path));
+			free(old);
+			strbuf_release(&ref);
+		}
+		wt_status_state_free_buffers(&state);
+
+		if (wt_status_check_bisect(wt, &state) &&
+		    state.bisecting_from) {
+			struct strbuf ref = STRBUF_INIT;
+			strbuf_addf(&ref, "refs/heads/%s", state.bisecting_from);
+			old = strmap_put(&current_checked_out_branches,
+					 ref.buf,
+					 xstrdup(wt->path));
+			free(old);
+			strbuf_release(&ref);
+		}
+		wt_status_state_free_buffers(&state);
+
+		if (!sequencer_get_update_refs_state(get_worktree_git_dir(wt),
+						     &update_refs)) {
+			struct string_list_item *item;
+			for_each_string_list_item(item, &update_refs) {
+				old = strmap_put(&current_checked_out_branches,
+						 item->string,
+						 xstrdup(wt->path));
+				free(old);
+			}
+			string_list_clear(&update_refs, 1);
+		}
+	}
+
+	free_worktrees(worktrees);
+}
+
+const char *branch_checked_out(const char *refname)
+{
+	prepare_checked_out_branches();
+	return strmap_get(&current_checked_out_branches, refname);
+}
+
+/*
+ * Check if a branch 'name' can be created as a new branch; die otherwise.
+ * 'force' can be used when it is OK for the named branch already exists.
+ * Return 1 if the named branch already exists; return 0 otherwise.
+ * Fill ref with the full refname for the branch.
+ */
+int validate_new_branchname(const char *name, struct strbuf *ref, int force)
+{
+	const char *path;
+	if (!validate_branchname(name, ref))
+		return 0;
+
+	if (!force)
+		die(_("a branch named '%s' already exists"),
+		    ref->buf + strlen("refs/heads/"));
+
+	if ((path = branch_checked_out(ref->buf)))
+		die(_("cannot force update the branch '%s' "
+		      "used by worktree at '%s'"),
+		    ref->buf + strlen("refs/heads/"), path);
+
+	return 1;
+}
+
+static int check_tracking_branch(struct remote *remote, void *cb_data)
+{
+	char *tracking_branch = cb_data;
+	struct refspec_item query;
+	int res;
+	memset(&query, 0, sizeof(struct refspec_item));
+	query.dst = tracking_branch;
+	res = !remote_find_tracking(remote, &query);
+	free(query.src);
+	return res;
+}
+
+static int validate_remote_tracking_branch(char *ref)
+{
+	return !for_each_remote(check_tracking_branch, ref);
+}
+
+static const char upstream_not_branch[] =
+N_("cannot set up tracking information; starting point '%s' is not a branch");
+static const char upstream_missing[] =
+N_("the requested upstream branch '%s' does not exist");
+static const char upstream_advice[] =
+N_("\n"
+"If you are planning on basing your work on an upstream\n"
+"branch that already exists at the remote, you may need to\n"
+"run \"git fetch\" to retrieve it.\n"
+"\n"
+"If you are planning to push out a new local branch that\n"
+"will track its remote counterpart, you may want to use\n"
+"\"git push -u\" to set the upstream config as you push.");
+
+/**
+ * DWIMs a user-provided ref to determine the starting point for a
+ * branch and validates it, where:
+ *
+ *   - r is the repository to validate the branch for
+ *
+ *   - start_name is the ref that we would like to test. This is
+ *     expanded with DWIM and assigned to out_real_ref.
+ *
+ *   - track is the tracking mode of the new branch. If tracking is
+ *     explicitly requested, start_name must be a branch (because
+ *     otherwise start_name cannot be tracked)
+ *
+ *   - out_oid is an out parameter containing the object_id of start_name
+ *
+ *   - out_real_ref is an out parameter containing the full, 'real' form
+ *     of start_name e.g. refs/heads/main instead of main
+ *
+ */
+static void dwim_branch_start(struct repository *r, const char *start_name,
+			   enum branch_track track, char **out_real_ref,
+			   struct object_id *out_oid)
+{
+	struct commit *commit;
+	struct object_id oid;
+	char *real_ref;
+	int explicit_tracking = 0;
+
+	if (track == BRANCH_TRACK_EXPLICIT || track == BRANCH_TRACK_OVERRIDE)
+		explicit_tracking = 1;
+
+	real_ref = NULL;
+	if (repo_get_oid_mb(r, start_name, &oid)) {
+		if (explicit_tracking) {
+			int code = die_message(_(upstream_missing), start_name);
+			advise_if_enabled(ADVICE_SET_UPSTREAM_FAILURE,
+					  _(upstream_advice));
+			exit(code);
+		}
+		die(_("not a valid object name: '%s'"), start_name);
+	}
+
+	switch (repo_dwim_ref(r, start_name, strlen(start_name), &oid,
+			      &real_ref, 0)) {
+	case 0:
+		/* Not branching from any existing branch */
+		if (explicit_tracking)
+			die(_(upstream_not_branch), start_name);
+		break;
+	case 1:
+		/* Unique completion -- good, only if it is a real branch */
+		if (!starts_with(real_ref, "refs/heads/") &&
+		    validate_remote_tracking_branch(real_ref)) {
+			if (explicit_tracking)
+				die(_(upstream_not_branch), start_name);
+			else
+				FREE_AND_NULL(real_ref);
+		}
+		break;
+	default:
+		die(_("ambiguous object name: '%s'"), start_name);
+		break;
+	}
+
+	if (!(commit = lookup_commit_reference(r, &oid)))
+		die(_("not a valid branch point: '%s'"), start_name);
+	if (out_real_ref) {
+		*out_real_ref = real_ref;
+		real_ref = NULL;
+	}
+	if (out_oid)
+		oidcpy(out_oid, &commit->object.oid);
+
+	FREE_AND_NULL(real_ref);
+}
+
+void create_branch(struct repository *r,
+		   const char *name, const char *start_name,
+		   int force, int clobber_head_ok, int reflog,
+		   int quiet, enum branch_track track, int dry_run)
+{
+	struct object_id oid;
+	char *real_ref;
+	struct strbuf ref = STRBUF_INIT;
+	int forcing = 0;
+	struct ref_transaction *transaction;
+	struct strbuf err = STRBUF_INIT;
+	int flags = 0;
+	char *msg;
+
+	if (track == BRANCH_TRACK_OVERRIDE)
+		BUG("'track' cannot be BRANCH_TRACK_OVERRIDE. Did you mean to call dwim_and_setup_tracking()?");
+	if (clobber_head_ok && !force)
+		BUG("'clobber_head_ok' can only be used with 'force'");
+
+	if (clobber_head_ok ?
+			  validate_branchname(name, &ref) :
+			  validate_new_branchname(name, &ref, force)) {
+		forcing = 1;
+	}
+
+	dwim_branch_start(r, start_name, track, &real_ref, &oid);
+	if (dry_run)
+		goto cleanup;
+
+	if (reflog)
+		flags |= REF_FORCE_CREATE_REFLOG;
+
+	if (forcing)
+		msg = xstrfmt("branch: Reset to %s", start_name);
+	else
+		msg = xstrfmt("branch: Created from %s", start_name);
+	transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+						  0, &err);
+	if (!transaction ||
+		ref_transaction_update(transaction, ref.buf,
+					&oid, forcing ? NULL : null_oid(),
+					NULL, NULL, flags, msg, &err) ||
+		ref_transaction_commit(transaction, &err))
+		die("%s", err.buf);
+	ref_transaction_free(transaction);
+	strbuf_release(&err);
+	free(msg);
+
+	if (real_ref && track)
+		setup_tracking(ref.buf + 11, real_ref, track, quiet);
+
+cleanup:
+	strbuf_release(&ref);
+	free(real_ref);
+}
+
+void dwim_and_setup_tracking(struct repository *r, const char *new_ref,
+			     const char *orig_ref, enum branch_track track,
+			     int quiet)
+{
+	char *real_orig_ref = NULL;
+	dwim_branch_start(r, orig_ref, track, &real_orig_ref, NULL);
+	setup_tracking(new_ref, real_orig_ref, track, quiet);
+	free(real_orig_ref);
+}
+
+/**
+ * Creates a branch in a submodule by calling
+ * create_branches_recursively() in a child process. The child process
+ * is necessary because install_branch_config_multiple_remotes() (which
+ * is called by setup_tracking()) does not support writing configs to
+ * submodules.
+ */
+static int submodule_create_branch(struct repository *r,
+				   const struct submodule *submodule,
+				   const char *name, const char *start_oid,
+				   const char *tracking_name, int force,
+				   int reflog, int quiet,
+				   enum branch_track track, int dry_run)
+{
+	int ret = 0;
+	struct child_process child = CHILD_PROCESS_INIT;
+	struct strbuf child_err = STRBUF_INIT;
+	struct strbuf out_buf = STRBUF_INIT;
+	char *out_prefix = xstrfmt("submodule '%s': ", submodule->name);
+	child.git_cmd = 1;
+	child.err = -1;
+	child.stdout_to_stderr = 1;
+
+	prepare_other_repo_env(&child.env, r->gitdir);
+	/*
+	 * submodule_create_branch() is indirectly invoked by "git
+	 * branch", but we cannot invoke "git branch" in the child
+	 * process. "git branch" accepts a branch name and start point,
+	 * where the start point is assumed to provide both the OID
+	 * (start_oid) and the branch to use for tracking
+	 * (tracking_name). But when recursing through submodules,
+	 * start_oid and tracking name need to be specified separately
+	 * (see create_branches_recursively()).
+	 */
+	strvec_pushl(&child.args, "submodule--helper", "create-branch", NULL);
+	if (dry_run)
+		strvec_push(&child.args, "--dry-run");
+	if (force)
+		strvec_push(&child.args, "--force");
+	if (quiet)
+		strvec_push(&child.args, "--quiet");
+	if (reflog)
+		strvec_push(&child.args, "--create-reflog");
+
+	switch (track) {
+	case BRANCH_TRACK_NEVER:
+		strvec_push(&child.args, "--no-track");
+		break;
+	case BRANCH_TRACK_ALWAYS:
+	case BRANCH_TRACK_EXPLICIT:
+		strvec_push(&child.args, "--track=direct");
+		break;
+	case BRANCH_TRACK_OVERRIDE:
+		BUG("BRANCH_TRACK_OVERRIDE cannot be used when creating a branch.");
+		break;
+	case BRANCH_TRACK_INHERIT:
+		strvec_push(&child.args, "--track=inherit");
+		break;
+	case BRANCH_TRACK_UNSPECIFIED:
+		/* Default for "git checkout". Do not pass --track. */
+	case BRANCH_TRACK_REMOTE:
+		/* Default for "git branch". Do not pass --track. */
+	case BRANCH_TRACK_SIMPLE:
+		/* Config-driven only. Do not pass --track. */
+		break;
+	}
+
+	strvec_pushl(&child.args, name, start_oid, tracking_name, NULL);
+
+	if ((ret = start_command(&child)))
+		return ret;
+	ret = finish_command(&child);
+	strbuf_read(&child_err, child.err, 0);
+	strbuf_add_lines(&out_buf, out_prefix, child_err.buf, child_err.len);
+
+	if (ret)
+		fprintf(stderr, "%s", out_buf.buf);
+	else
+		printf("%s", out_buf.buf);
+
+	strbuf_release(&child_err);
+	strbuf_release(&out_buf);
+	free(out_prefix);
+	return ret;
+}
+
+void create_branches_recursively(struct repository *r, const char *name,
+				 const char *start_committish,
+				 const char *tracking_name, int force,
+				 int reflog, int quiet, enum branch_track track,
+				 int dry_run)
+{
+	int i = 0;
+	char *branch_point = NULL;
+	struct object_id super_oid;
+	struct submodule_entry_list submodule_entry_list;
+
+	/* Perform dwim on start_committish to get super_oid and branch_point. */
+	dwim_branch_start(r, start_committish, BRANCH_TRACK_NEVER,
+			  &branch_point, &super_oid);
+
+	/*
+	 * If we were not given an explicit name to track, then assume we are at
+	 * the top level and, just like the non-recursive case, the tracking
+	 * name is the branch point.
+	 */
+	if (!tracking_name)
+		tracking_name = branch_point;
+
+	submodules_of_tree(r, &super_oid, &submodule_entry_list);
+	/*
+	 * Before creating any branches, first check that the branch can
+	 * be created in every submodule.
+	 */
+	for (i = 0; i < submodule_entry_list.entry_nr; i++) {
+		if (!submodule_entry_list.entries[i].repo) {
+			int code = die_message(
+				_("submodule '%s': unable to find submodule"),
+				submodule_entry_list.entries[i].submodule->name);
+			if (advice_enabled(ADVICE_SUBMODULES_NOT_UPDATED))
+				advise(_("You may try updating the submodules using 'git checkout --no-recurse-submodules %s && git submodule update --init'"),
+				       start_committish);
+			exit(code);
+		}
+
+		if (submodule_create_branch(
+			    submodule_entry_list.entries[i].repo,
+			    submodule_entry_list.entries[i].submodule, name,
+			    oid_to_hex(&submodule_entry_list.entries[i]
+						.name_entry->oid),
+			    tracking_name, force, reflog, quiet, track, 1))
+			die(_("submodule '%s': cannot create branch '%s'"),
+			    submodule_entry_list.entries[i].submodule->name,
+			    name);
+	}
+
+	create_branch(r, name, start_committish, force, 0, reflog, quiet,
+		      BRANCH_TRACK_NEVER, dry_run);
+	if (dry_run)
+		goto out;
+	/*
+	 * NEEDSWORK If tracking was set up in the superproject but not the
+	 * submodule, users might expect "git branch --recurse-submodules" to
+	 * fail or give a warning, but this is not yet implemented because it is
+	 * tedious to determine whether or not tracking was set up in the
+	 * superproject.
+	 */
+	if (track)
+		setup_tracking(name, tracking_name, track, quiet);
+
+	for (i = 0; i < submodule_entry_list.entry_nr; i++) {
+		if (submodule_create_branch(
+			    submodule_entry_list.entries[i].repo,
+			    submodule_entry_list.entries[i].submodule, name,
+			    oid_to_hex(&submodule_entry_list.entries[i]
+						.name_entry->oid),
+			    tracking_name, force, reflog, quiet, track, 0))
+			die(_("submodule '%s': cannot create branch '%s'"),
+			    submodule_entry_list.entries[i].submodule->name,
+			    name);
+	}
+
+out:
+	submodule_entry_list_release(&submodule_entry_list);
+	free(branch_point);
+}
+
+void remove_merge_branch_state(struct repository *r)
+{
+	unlink(git_path_merge_head(r));
+	unlink(git_path_merge_rr(r));
+	unlink(git_path_merge_msg(r));
+	unlink(git_path_merge_mode(r));
+	refs_delete_ref(get_main_ref_store(r), "", "AUTO_MERGE",
+			NULL, REF_NO_DEREF);
+	save_autostash_ref(r, "MERGE_AUTOSTASH");
+}
+
+void remove_branch_state(struct repository *r, int verbose)
+{
+	sequencer_post_commit_cleanup(r, verbose);
+	unlink(git_path_squash_msg(r));
+	remove_merge_branch_state(r);
+}
+
+void die_if_checked_out(const char *branch, int ignore_current_worktree)
+{
+	struct worktree **worktrees = get_worktrees();
+
+	for (int i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->is_current && ignore_current_worktree)
+			continue;
+
+		if (is_shared_symref(worktrees[i], "HEAD", branch)) {
+			skip_prefix(branch, "refs/heads/", &branch);
+			die(_("'%s' is already used by worktree at '%s'"),
+				branch, worktrees[i]->path);
+		}
+	}
+
+	free_worktrees(worktrees);
+}
diff --git a/branch.h b/branch.h
new file mode 100644
index 0000000000..ec2f35fda4
--- /dev/null
+++ b/branch.h
@@ -0,0 +1,158 @@
+#ifndef BRANCH_H
+#define BRANCH_H
+
+struct repository;
+struct strbuf;
+
+enum branch_track {
+	BRANCH_TRACK_UNSPECIFIED = -1,
+	BRANCH_TRACK_NEVER = 0,
+	BRANCH_TRACK_REMOTE,
+	BRANCH_TRACK_ALWAYS,
+	BRANCH_TRACK_EXPLICIT,
+	BRANCH_TRACK_OVERRIDE,
+	BRANCH_TRACK_INHERIT,
+	BRANCH_TRACK_SIMPLE,
+};
+
+extern enum branch_track git_branch_track;
+
+/* Functions for acting on the information about branches. */
+
+/**
+ * Sets branch.<new_ref>.{remote,merge} config settings such that
+ * new_ref tracks orig_ref according to the specified tracking mode.
+ *
+ *   - new_ref is the name of the branch that we are setting tracking
+ *     for.
+ *
+ *   - orig_ref is the name of the ref that is 'upstream' of new_ref.
+ *     orig_ref will be expanded with DWIM so that the config settings
+ *     are in the correct format e.g. "refs/remotes/origin/main" instead
+ *     of "origin/main".
+ *
+ *   - track is the tracking mode e.g. BRANCH_TRACK_REMOTE causes
+ *     new_ref to track orig_ref directly, whereas BRANCH_TRACK_INHERIT
+ *     causes new_ref to track whatever orig_ref tracks.
+ *
+ *   - quiet suppresses tracking information.
+ */
+void dwim_and_setup_tracking(struct repository *r, const char *new_ref,
+			     const char *orig_ref, enum branch_track track,
+			     int quiet);
+
+/*
+ * Creates a new branch, where:
+ *
+ *   - r is the repository to add a branch to
+ *
+ *   - name is the new branch name
+ *
+ *   - start_name is the name of the existing branch that the new branch should
+ *     start from
+ *
+ *   - force enables overwriting an existing (non-head) branch
+ *
+ *   - clobber_head_ok, when enabled with 'force', allows the currently
+ *     checked out (head) branch to be overwritten
+ *
+ *   - reflog creates a reflog for the branch
+ *
+ *   - quiet suppresses tracking information
+ *
+ *   - track causes the new branch to be configured to merge the remote branch
+ *     that start_name is a tracking branch for (if any).
+ *
+ *   - dry_run causes the branch to be validated but not created.
+ *
+ */
+void create_branch(struct repository *r,
+		   const char *name, const char *start_name,
+		   int force, int clobber_head_ok,
+		   int reflog, int quiet, enum branch_track track,
+		   int dry_run);
+
+/*
+ * Creates a new branch in a repository and its submodules (and its
+ * submodules, recursively). The parameters are mostly analogous to
+ * those of create_branch() except for start_name, which is represented
+ * by two different parameters:
+ *
+ * - start_committish is the commit-ish, in repository r, that determines
+ *   which commits the branches will point to. The superproject branch
+ *   will point to the commit of start_committish and the submodule
+ *   branches will point to the gitlink commit oids in start_committish's
+ *   tree.
+ *
+ * - tracking_name is the name of the ref, in repository r, that will be
+ *   used to set up tracking information. This value is propagated to
+ *   all submodules, which will evaluate the ref using their own ref
+ *   stores. If NULL, this defaults to start_committish.
+ *
+ * When this function is called on the superproject, start_committish
+ * can be any user-provided ref and tracking_name can be NULL (similar
+ * to create_branches()). But when recursing through submodules,
+ * start_committish is the plain gitlink commit oid. Since the oid cannot
+ * be used for tracking information, tracking_name is propagated and
+ * used for tracking instead.
+ */
+void create_branches_recursively(struct repository *r, const char *name,
+				 const char *start_committish,
+				 const char *tracking_name, int force,
+				 int reflog, int quiet, enum branch_track track,
+				 int dry_run);
+
+/*
+ * If the branch at 'refname' is currently checked out in a worktree,
+ * then return the path to that worktree.
+ */
+const char *branch_checked_out(const char *refname);
+
+/*
+ * Check if 'name' can be a valid name for a branch; die otherwise.
+ * Return 1 if the named branch already exists; return 0 otherwise.
+ * Fill ref with the full refname for the branch.
+ */
+int validate_branchname(const char *name, struct strbuf *ref);
+
+/*
+ * Check if a branch 'name' can be created as a new branch; die otherwise.
+ * 'force' can be used when it is OK for the named branch already exists.
+ * Return 1 if the named branch already exists; return 0 otherwise.
+ * Fill ref with the full refname for the branch.
+ */
+int validate_new_branchname(const char *name, struct strbuf *ref, int force);
+
+/*
+ * Remove information about the merge state on the current
+ * branch. (E.g., MERGE_HEAD)
+ */
+void remove_merge_branch_state(struct repository *r);
+
+/*
+ * Remove information about the state of working on the current
+ * branch. (E.g., MERGE_HEAD)
+ */
+void remove_branch_state(struct repository *r, int verbose);
+
+/*
+ * Configure local branch "local" as downstream to branch "remote"
+ * from remote "origin".  Used by git branch --set-upstream.
+ * Returns 0 on success.
+ */
+#define BRANCH_CONFIG_VERBOSE 01
+int install_branch_config(int flag, const char *local, const char *origin, const char *remote);
+
+/*
+ * Read branch description
+ */
+int read_branch_desc(struct strbuf *, const char *branch_name);
+
+/*
+ * Check if a branch is checked out in the main worktree or any linked
+ * worktree and die (with a message describing its checkout location) if
+ * it is.
+ */
+void die_if_checked_out(const char *branch, int ignore_current_worktree);
+
+#endif
diff --git a/builtin.h b/builtin.h
new file mode 100644
index 0000000000..f7b166b334
--- /dev/null
+++ b/builtin.h
@@ -0,0 +1,257 @@
+#ifndef BUILTIN_H
+#define BUILTIN_H
+
+#include "git-compat-util.h"
+#include "repository.h"
+
+/*
+ * builtin API
+ * ===========
+ *
+ * Adding a new built-in
+ * ---------------------
+ *
+ * There are 4 things to do to add a built-in command implementation to
+ * Git:
+ *
+ * . Define the implementation of the built-in command `foo` with
+ *   signature:
+ *
+ *	int cmd_foo(int argc, const char **argv, const char *prefix);
+ *
+ * . Add the external declaration for the function to `builtin.h`.
+ *
+ * . Add the command to the `commands[]` table defined in `git.c`.
+ *   The entry should look like:
+ *
+ *	{ "foo", cmd_foo, <options> },
+ *
+ * where options is the bitwise-or of:
+ *
+ * `RUN_SETUP`:
+ *	If there is not a Git directory to work on, abort.  If there
+ *	is a work tree, chdir to the top of it if the command was
+ *	invoked in a subdirectory.  If there is no work tree, no
+ *	chdir() is done.
+ *
+ * `RUN_SETUP_GENTLY`:
+ *	If there is a Git directory, chdir as per RUN_SETUP, otherwise,
+ *	don't chdir anywhere.
+ *
+ * `USE_PAGER`:
+ *
+ *	If the standard output is connected to a tty, spawn a pager and
+ *	feed our output to it.
+ *
+ * `NEED_WORK_TREE`:
+ *
+ *	Make sure there is a work tree, i.e. the command cannot act
+ *	on bare repositories.
+ *	This only makes sense when `RUN_SETUP` is also set.
+ *
+ * `DELAY_PAGER_CONFIG`:
+ *
+ *	If RUN_SETUP or RUN_SETUP_GENTLY is set, git.c normally handles
+ *	the `pager.<cmd>`-configuration. If this flag is used, git.c
+ *	will skip that step, instead allowing the built-in to make a
+ *	more informed decision, e.g., by ignoring `pager.<cmd>` for
+ *	certain subcommands.
+ *
+ * . Add `builtin/foo.o` to `BUILTIN_OBJS` in `Makefile`.
+ *
+ * Additionally, if `foo` is a new command, there are 4 more things to do:
+ *
+ * . Add tests to `t/` directory.
+ *
+ * . Write documentation in `Documentation/git-foo.txt`.
+ *
+ * . Add an entry for `git-foo` to `command-list.txt`.
+ *
+ * . Add an entry for `/git-foo` to `.gitignore`.
+ *
+ *
+ * How a built-in is called
+ * ------------------------
+ *
+ * The implementation `cmd_foo()` takes three parameters, `argc`, `argv,
+ * and `prefix`.  The first two are similar to what `main()` of a
+ * standalone command would be called with.
+ *
+ * When `RUN_SETUP` is specified in the `commands[]` table, and when you
+ * were started from a subdirectory of the work tree, `cmd_foo()` is called
+ * after chdir(2) to the top of the work tree, and `prefix` gets the path
+ * to the subdirectory the command started from.  This allows you to
+ * convert a user-supplied pathname (typically relative to that directory)
+ * to a pathname relative to the top of the work tree.
+ *
+ * The return value from `cmd_foo()` becomes the exit status of the
+ * command.
+ */
+
+extern const char git_usage_string[];
+extern const char git_more_info_string[];
+
+/**
+ * If a built-in has DELAY_PAGER_CONFIG set, the built-in should call this early
+ * when it wishes to respect the `pager.foo`-config. The `cmd` is the name of
+ * the built-in, e.g., "foo". If a paging-choice has already been setup, this
+ * does nothing. The default in `def` should be 0 for "pager off", 1 for "pager
+ * on" or -1 for "punt".
+ *
+ * You should most likely use a default of 0 or 1. "Punt" (-1) could be useful
+ * to be able to fall back to some historical compatibility name.
+ */
+void setup_auto_pager(const char *cmd, int def);
+
+int is_builtin(const char *s);
+
+/*
+ * Builtins which do not use RUN_SETUP should never see
+ * a prefix that is not empty; use this to protect downstream
+ * code which is not prepared to call prefix_filename(), etc.
+ */
+#define BUG_ON_NON_EMPTY_PREFIX(prefix) do { \
+	if ((prefix)) \
+		BUG("unexpected prefix in builtin: %s", (prefix)); \
+} while (0)
+
+int cmd_add(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_am(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_annotate(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_apply(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_archive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_bisect(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_blame(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_branch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_bugreport(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_bundle(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cat_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout__worker(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_checkout_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_attr(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_ignore(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_mailmap(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_check_ref_format(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cherry(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_cherry_pick(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_clone(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_clean(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_column(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit_graph(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_commit_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_config(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_count_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_cache(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_cache_daemon(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_credential_store(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_describe(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diagnose(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_files(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_diff_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_difftool(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_env__helper(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fast_export(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fast_import(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fetch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fetch_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_for_each_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_for_each_repo(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_format_patch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fsck(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_gc(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_get_tar_commit_id(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_grep(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_hash_object(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_help(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_hook(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_index_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_init_db(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_interpret_trailers(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_log_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_log(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_files(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_ls_remote(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mailinfo(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mailsplit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_maintenance(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_base(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_ours(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_recursive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_merge_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mktag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mktree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_multi_pack_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_mv(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_name_rev(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_notes(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_patch_id(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_prune(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_prune_packed(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pull(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_push(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_range_diff(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_read_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rebase(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rebase__interactive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_receive_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_reflog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_refs(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote_ext(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_remote_fd(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_repack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_replay(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rerere(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_reset(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_restore(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rev_list(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rev_parse(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_revert(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_rm(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_send_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_shortlog(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_branch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_sparse_checkout(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_status(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_stash(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_stripspace(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_submodule__helper(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_switch(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_symbolic_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_tag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_unpack_file(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_unpack_objects(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_index(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_update_server_info(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_archive(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_archive_writer(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_upload_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_var(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_commit(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_tag(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_version(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_whatchanged(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_worktree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_write_tree(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_verify_pack(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_show_ref(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_pack_refs(int argc, const char **argv, const char *prefix, struct repository *repo);
+int cmd_replace(int argc, const char **argv, const char *prefix, struct repository *repo);
+
+#endif
diff --git a/builtin/add.c b/builtin/add.c
new file mode 100644
index 0000000000..78dfb26577
--- /dev/null
+++ b/builtin/add.c
@@ -0,0 +1,593 @@
+/*
+ * "git add" builtin command
+ *
+ * Copyright (C) 2006 Linus Torvalds
+ */
+
+#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "lockfile.h"
+#include "editor.h"
+#include "dir.h"
+#include "gettext.h"
+#include "pathspec.h"
+#include "run-command.h"
+#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "diff.h"
+#include "read-cache.h"
+#include "revision.h"
+#include "bulk-checkin.h"
+#include "strvec.h"
+#include "submodule.h"
+#include "add-interactive.h"
+
+static const char * const builtin_add_usage[] = {
+	N_("git add [<options>] [--] <pathspec>..."),
+	NULL
+};
+static int patch_interactive, add_interactive, edit_interactive;
+static int take_worktree_changes;
+static int add_renormalize;
+static int pathspec_file_nul;
+static int include_sparse;
+static const char *pathspec_from_file;
+
+static int chmod_pathspec(struct repository *repo,
+			  struct pathspec *pathspec,
+			  char flip,
+			  int show_only)
+{
+	int ret = 0;
+
+	for (size_t i = 0; i < repo->index->cache_nr; i++) {
+		struct cache_entry *ce = repo->index->cache[i];
+		int err;
+
+		if (!include_sparse &&
+		    (ce_skip_worktree(ce) ||
+		     !path_in_sparse_checkout(ce->name, repo->index)))
+			continue;
+
+		if (pathspec && !ce_path_match(repo->index, ce, pathspec, NULL))
+			continue;
+
+		if (!show_only)
+			err = chmod_index_entry(repo->index, ce, flip);
+		else
+			err = S_ISREG(ce->ce_mode) ? 0 : -1;
+
+		if (err < 0)
+			ret = error(_("cannot chmod %cx '%s'"), flip, ce->name);
+	}
+
+	return ret;
+}
+
+static int renormalize_tracked_files(struct repository *repo,
+				     const struct pathspec *pathspec,
+				     int flags)
+{
+	int retval = 0;
+
+	for (size_t i = 0; i < repo->index->cache_nr; i++) {
+		struct cache_entry *ce = repo->index->cache[i];
+
+		if (!include_sparse &&
+		    (ce_skip_worktree(ce) ||
+		     !path_in_sparse_checkout(ce->name, repo->index)))
+			continue;
+		if (ce_stage(ce))
+			continue; /* do not touch unmerged paths */
+		if (!S_ISREG(ce->ce_mode) && !S_ISLNK(ce->ce_mode))
+			continue; /* do not touch non blobs */
+		if (pathspec && !ce_path_match(repo->index, ce, pathspec, NULL))
+			continue;
+		retval |= add_file_to_index(repo->index, ce->name,
+					    flags | ADD_CACHE_RENORMALIZE);
+	}
+
+	return retval;
+}
+
+static char *prune_directory(struct repository *repo,
+			     struct dir_struct *dir,
+			     struct pathspec *pathspec,
+			     int prefix)
+{
+	char *seen;
+	int i;
+	struct dir_entry **src, **dst;
+
+	seen = xcalloc(pathspec->nr, 1);
+
+	src = dst = dir->entries;
+	i = dir->nr;
+	while (--i >= 0) {
+		struct dir_entry *entry = *src++;
+		if (dir_path_match(repo->index, entry, pathspec, prefix, seen))
+			*dst++ = entry;
+	}
+	dir->nr = dst - dir->entries;
+	add_pathspec_matches_against_index(pathspec, repo->index, seen,
+					   PS_IGNORE_SKIP_WORKTREE);
+	return seen;
+}
+
+static int refresh(struct repository *repo, int verbose, const struct pathspec *pathspec)
+{
+	char *seen;
+	int i, ret = 0;
+	char *skip_worktree_seen = NULL;
+	struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
+	unsigned int flags = REFRESH_IGNORE_SKIP_WORKTREE |
+		    (verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET);
+
+	seen = xcalloc(pathspec->nr, 1);
+	refresh_index(repo->index, flags, pathspec, seen,
+		      _("Unstaged changes after refreshing the index:"));
+	for (i = 0; i < pathspec->nr; i++) {
+		if (!seen[i]) {
+			const char *path = pathspec->items[i].original;
+
+			if (matches_skip_worktree(pathspec, i, &skip_worktree_seen) ||
+			    !path_in_sparse_checkout(path, repo->index)) {
+				string_list_append(&only_match_skip_worktree,
+						   pathspec->items[i].original);
+			} else {
+				die(_("pathspec '%s' did not match any files"),
+				    pathspec->items[i].original);
+			}
+		}
+	}
+
+	if (only_match_skip_worktree.nr) {
+		advise_on_updating_sparse_paths(&only_match_skip_worktree);
+		ret = 1;
+	}
+
+	free(seen);
+	free(skip_worktree_seen);
+	string_list_clear(&only_match_skip_worktree, 0);
+	return ret;
+}
+
+int interactive_add(struct repository *repo,
+		    const char **argv,
+		    const char *prefix,
+		    int patch)
+{
+	struct pathspec pathspec;
+	int ret;
+
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_FULL |
+		       PATHSPEC_SYMLINK_LEADING_PATH |
+		       PATHSPEC_PREFIX_ORIGIN,
+		       prefix, argv);
+
+	if (patch)
+		ret = !!run_add_p(repo, ADD_P_ADD, NULL, &pathspec);
+	else
+		ret = !!run_add_i(repo, &pathspec);
+
+	clear_pathspec(&pathspec);
+	return ret;
+}
+
+static int edit_patch(struct repository *repo,
+		      int argc,
+		      const char **argv,
+		      const char *prefix)
+{
+	char *file = repo_git_path(repo, "ADD_EDIT.patch");
+	struct child_process child = CHILD_PROCESS_INIT;
+	struct rev_info rev;
+	int out;
+	struct stat st;
+
+	repo_config(repo, git_diff_basic_config, NULL);
+
+	if (repo_read_index(repo) < 0)
+		die(_("could not read the index"));
+
+	repo_init_revisions(repo, &rev, prefix);
+	rev.diffopt.context = 7;
+
+	argc = setup_revisions(argc, argv, &rev, NULL);
+	rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+	rev.diffopt.use_color = 0;
+	rev.diffopt.flags.ignore_dirty_submodules = 1;
+	out = xopen(file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+	rev.diffopt.file = xfdopen(out, "w");
+	rev.diffopt.close_file = 1;
+	run_diff_files(&rev, 0);
+
+	if (launch_editor(file, NULL, NULL))
+		die(_("editing patch failed"));
+
+	if (stat(file, &st))
+		die_errno(_("could not stat '%s'"), file);
+	if (!st.st_size)
+		die(_("empty patch. aborted"));
+
+	child.git_cmd = 1;
+	strvec_pushl(&child.args, "apply", "--recount", "--cached", file,
+		     NULL);
+	if (run_command(&child))
+		die(_("could not apply '%s'"), file);
+
+	unlink(file);
+	free(file);
+	release_revisions(&rev);
+	return 0;
+}
+
+static const char ignore_error[] =
+N_("The following paths are ignored by one of your .gitignore files:\n");
+
+static int verbose, show_only, ignored_too, refresh_only;
+static int ignore_add_errors, intent_to_add, ignore_missing;
+static int warn_on_embedded_repo = 1;
+
+#define ADDREMOVE_DEFAULT 1
+static int addremove = ADDREMOVE_DEFAULT;
+static int addremove_explicit = -1; /* unspecified */
+
+static char *chmod_arg;
+
+static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
+{
+	BUG_ON_OPT_ARG(arg);
+
+	/* if we are told to ignore, we are not adding removals */
+	*(int *)opt->value = !unset ? 0 : 1;
+	return 0;
+}
+
+static struct option builtin_add_options[] = {
+	OPT__DRY_RUN(&show_only, N_("dry run")),
+	OPT__VERBOSE(&verbose, N_("be verbose")),
+	OPT_GROUP(""),
+	OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
+	OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
+	OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
+	OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files"), 0),
+	OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
+	OPT_BOOL(0, "renormalize", &add_renormalize, N_("renormalize EOL of tracked files (implies -u)")),
+	OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
+	OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
+	OPT_CALLBACK_F(0, "ignore-removal", &addremove_explicit,
+	  NULL /* takes no arguments */,
+	  N_("ignore paths removed in the working tree (same as --no-all)"),
+	  PARSE_OPT_NOARG, ignore_removal_cb),
+	OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
+	OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
+	OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
+	OPT_BOOL(0, "sparse", &include_sparse, N_("allow updating entries outside of the sparse-checkout cone")),
+	OPT_STRING(0, "chmod", &chmod_arg, "(+|-)x",
+		   N_("override the executable bit of the listed files")),
+	OPT_HIDDEN_BOOL(0, "warn-embedded-repo", &warn_on_embedded_repo,
+			N_("warn when adding an embedded repository")),
+	OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+	OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
+	OPT_END(),
+};
+
+static int add_config(const char *var, const char *value,
+		      const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "add.ignoreerrors") ||
+	    !strcmp(var, "add.ignore-errors")) {
+		ignore_add_errors = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (git_color_config(var, value, cb) < 0)
+		return -1;
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static const char embedded_advice[] = N_(
+"You've added another git repository inside your current repository.\n"
+"Clones of the outer repository will not contain the contents of\n"
+"the embedded repository and will not know how to obtain it.\n"
+"If you meant to add a submodule, use:\n"
+"\n"
+"	git submodule add <url> %s\n"
+"\n"
+"If you added this path by mistake, you can remove it from the\n"
+"index with:\n"
+"\n"
+"	git rm --cached %s\n"
+"\n"
+"See \"git help submodule\" for more information."
+);
+
+static void check_embedded_repo(const char *path)
+{
+	struct strbuf name = STRBUF_INIT;
+	static int adviced_on_embedded_repo = 0;
+
+	if (!warn_on_embedded_repo)
+		return;
+	if (!ends_with(path, "/"))
+		return;
+
+	/* Drop trailing slash for aesthetics */
+	strbuf_addstr(&name, path);
+	strbuf_strip_suffix(&name, "/");
+
+	warning(_("adding embedded git repository: %s"), name.buf);
+	if (!adviced_on_embedded_repo) {
+		advise_if_enabled(ADVICE_ADD_EMBEDDED_REPO,
+				  embedded_advice, name.buf, name.buf);
+		adviced_on_embedded_repo = 1;
+	}
+
+	strbuf_release(&name);
+}
+
+static int add_files(struct repository *repo, struct dir_struct *dir, int flags)
+{
+	int i, exit_status = 0;
+	struct string_list matched_sparse_paths = STRING_LIST_INIT_NODUP;
+
+	if (dir->ignored_nr) {
+		fprintf(stderr, _(ignore_error));
+		for (i = 0; i < dir->ignored_nr; i++)
+			fprintf(stderr, "%s\n", dir->ignored[i]->name);
+		advise_if_enabled(ADVICE_ADD_IGNORED_FILE,
+				  _("Use -f if you really want to add them."));
+		exit_status = 1;
+	}
+
+	for (i = 0; i < dir->nr; i++) {
+		if (!include_sparse &&
+		    !path_in_sparse_checkout(dir->entries[i]->name, repo->index)) {
+			string_list_append(&matched_sparse_paths,
+					   dir->entries[i]->name);
+			continue;
+		}
+		if (add_file_to_index(repo->index, dir->entries[i]->name, flags)) {
+			if (!ignore_add_errors)
+				die(_("adding files failed"));
+			exit_status = 1;
+		} else {
+			check_embedded_repo(dir->entries[i]->name);
+		}
+	}
+
+	if (matched_sparse_paths.nr) {
+		advise_on_updating_sparse_paths(&matched_sparse_paths);
+		exit_status = 1;
+	}
+
+	string_list_clear(&matched_sparse_paths, 0);
+
+	return exit_status;
+}
+
+int cmd_add(int argc,
+	    const char **argv,
+	    const char *prefix,
+	    struct repository *repo)
+{
+	int exit_status = 0;
+	struct pathspec pathspec;
+	struct dir_struct dir = DIR_INIT;
+	int flags;
+	int add_new_files;
+	int require_pathspec;
+	char *seen = NULL;
+	char *ps_matched = NULL;
+	struct lock_file lock_file = LOCK_INIT;
+
+	if (repo)
+		repo_config(repo, add_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, builtin_add_options,
+			  builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
+	if (patch_interactive)
+		add_interactive = 1;
+	if (add_interactive) {
+		if (show_only)
+			die(_("options '%s' and '%s' cannot be used together"), "--dry-run", "--interactive/--patch");
+		if (pathspec_from_file)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch");
+		exit(interactive_add(repo, argv + 1, prefix, patch_interactive));
+	}
+
+	if (edit_interactive) {
+		if (pathspec_from_file)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--edit");
+		return(edit_patch(repo, argc, argv, prefix));
+	}
+	argc--;
+	argv++;
+
+	if (0 <= addremove_explicit)
+		addremove = addremove_explicit;
+	else if (take_worktree_changes && ADDREMOVE_DEFAULT)
+		addremove = 0; /* "-u" was given but not "-A" */
+
+	if (addremove && take_worktree_changes)
+		die(_("options '%s' and '%s' cannot be used together"), "-A", "-u");
+
+	if (!show_only && ignore_missing)
+		die(_("the option '%s' requires '%s'"), "--ignore-missing", "--dry-run");
+
+	if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') ||
+			  chmod_arg[1] != 'x' || chmod_arg[2]))
+		die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
+
+	add_new_files = !take_worktree_changes && !refresh_only && !add_renormalize;
+	require_pathspec = !(take_worktree_changes || (0 < addremove_explicit));
+
+	prepare_repo_settings(repo);
+	repo->settings.command_requires_full_index = 0;
+
+	repo_hold_locked_index(repo, &lock_file, LOCK_DIE_ON_ERROR);
+
+	/*
+	 * Check the "pathspec '%s' did not match any files" block
+	 * below before enabling new magic.
+	 */
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_FULL |
+		       PATHSPEC_SYMLINK_LEADING_PATH,
+		       prefix, argv);
+
+	if (pathspec_from_file) {
+		if (pathspec.nr)
+			die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
+
+		parse_pathspec_file(&pathspec, 0,
+				    PATHSPEC_PREFER_FULL |
+				    PATHSPEC_SYMLINK_LEADING_PATH,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
+	}
+
+	if (require_pathspec && pathspec.nr == 0) {
+		fprintf(stderr, _("Nothing specified, nothing added.\n"));
+		advise_if_enabled(ADVICE_ADD_EMPTY_PATHSPEC,
+				  _("Maybe you wanted to say 'git add .'?"));
+		return 0;
+	}
+
+	if (!take_worktree_changes && addremove_explicit < 0 && pathspec.nr)
+		/* Turn "git add pathspec..." to "git add -A pathspec..." */
+		addremove = 1;
+
+	flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
+		 (show_only ? ADD_CACHE_PRETEND : 0) |
+		 (intent_to_add ? ADD_CACHE_INTENT : 0) |
+		 (ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
+		 (!(addremove || take_worktree_changes)
+		  ? ADD_CACHE_IGNORE_REMOVAL : 0));
+
+	if (repo_read_index_preload(repo, &pathspec, 0) < 0)
+		die(_("index file corrupt"));
+
+	die_in_unpopulated_submodule(repo->index, prefix);
+	die_path_inside_submodule(repo->index, &pathspec);
+
+	if (add_new_files) {
+		int baselen;
+
+		/* Set up the default git porcelain excludes */
+		if (!ignored_too) {
+			dir.flags |= DIR_COLLECT_IGNORED;
+			setup_standard_excludes(&dir);
+		}
+
+		/* This picks up the paths that are not tracked */
+		baselen = fill_directory(&dir, repo->index, &pathspec);
+		if (pathspec.nr)
+			seen = prune_directory(repo, &dir, &pathspec, baselen);
+	}
+
+	if (refresh_only) {
+		exit_status |= refresh(repo, verbose, &pathspec);
+		goto finish;
+	}
+
+	if (pathspec.nr) {
+		int i;
+		char *skip_worktree_seen = NULL;
+		struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
+
+		if (!seen)
+			seen = find_pathspecs_matching_against_index(&pathspec,
+					repo->index, PS_IGNORE_SKIP_WORKTREE);
+
+		/*
+		 * file_exists() assumes exact match
+		 */
+		GUARD_PATHSPEC(&pathspec,
+			       PATHSPEC_FROMTOP |
+			       PATHSPEC_LITERAL |
+			       PATHSPEC_GLOB |
+			       PATHSPEC_ICASE |
+			       PATHSPEC_EXCLUDE |
+			       PATHSPEC_ATTR);
+
+		for (i = 0; i < pathspec.nr; i++) {
+			const char *path = pathspec.items[i].match;
+
+			if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
+				continue;
+			if (seen[i])
+				continue;
+
+			if (!include_sparse &&
+			    matches_skip_worktree(&pathspec, i, &skip_worktree_seen)) {
+				string_list_append(&only_match_skip_worktree,
+						   pathspec.items[i].original);
+				continue;
+			}
+
+			/* Don't complain at 'git add .' on empty repo */
+			if (!path[0])
+				continue;
+
+			if ((pathspec.items[i].magic & (PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
+			    !file_exists(path)) {
+				if (ignore_missing) {
+					int dtype = DT_UNKNOWN;
+					if (is_excluded(&dir, repo->index, path, &dtype))
+						dir_add_ignored(&dir, repo->index,
+								path, pathspec.items[i].len);
+				} else
+					die(_("pathspec '%s' did not match any files"),
+					    pathspec.items[i].original);
+			}
+		}
+
+
+		if (only_match_skip_worktree.nr) {
+			advise_on_updating_sparse_paths(&only_match_skip_worktree);
+			exit_status = 1;
+		}
+
+		free(seen);
+		free(skip_worktree_seen);
+		string_list_clear(&only_match_skip_worktree, 0);
+	}
+
+	begin_odb_transaction();
+
+	ps_matched = xcalloc(pathspec.nr, 1);
+	if (add_renormalize)
+		exit_status |= renormalize_tracked_files(repo, &pathspec, flags);
+	else
+		exit_status |= add_files_to_cache(repo, prefix,
+						  &pathspec, ps_matched,
+						  include_sparse, flags);
+
+	if (take_worktree_changes && !add_renormalize && !ignore_add_errors &&
+	    report_path_error(ps_matched, &pathspec))
+		exit(128);
+
+	if (add_new_files)
+		exit_status |= add_files(repo, &dir, flags);
+
+	if (chmod_arg && pathspec.nr)
+		exit_status |= chmod_pathspec(repo, &pathspec, chmod_arg[0], show_only);
+	end_odb_transaction();
+
+finish:
+	if (write_locked_index(repo->index, &lock_file,
+			       COMMIT_LOCK | SKIP_IF_UNCHANGED))
+		die(_("unable to write new index file"));
+
+	free(ps_matched);
+	dir_clear(&dir);
+	clear_pathspec(&pathspec);
+	return exit_status;
+}
diff --git a/builtin/am.c b/builtin/am.c
new file mode 100644
index 0000000000..390b463144
--- /dev/null
+++ b/builtin/am.c
@@ -0,0 +1,2544 @@
+/*
+ * Builtin "git am"
+ *
+ * Based on git-am.sh by Junio C Hamano.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "parse-options.h"
+#include "dir.h"
+#include "run-command.h"
+#include "hook.h"
+#include "quote.h"
+#include "tempfile.h"
+#include "lockfile.h"
+#include "cache-tree.h"
+#include "refs.h"
+#include "commit.h"
+#include "diff.h"
+#include "unpack-trees.h"
+#include "branch.h"
+#include "object-name.h"
+#include "preload-index.h"
+#include "sequencer.h"
+#include "revision.h"
+#include "merge-recursive.h"
+#include "log-tree.h"
+#include "notes-utils.h"
+#include "rerere.h"
+#include "mailinfo.h"
+#include "apply.h"
+#include "string-list.h"
+#include "pager.h"
+#include "path.h"
+#include "pretty.h"
+
+/**
+ * Returns the length of the first line of msg.
+ */
+static int linelen(const char *msg)
+{
+	return strchrnul(msg, '\n') - msg;
+}
+
+/**
+ * Returns true if `str` consists of only whitespace, false otherwise.
+ */
+static int str_isspace(const char *str)
+{
+	for (; *str; str++)
+		if (!isspace(*str))
+			return 0;
+
+	return 1;
+}
+
+enum patch_format {
+	PATCH_FORMAT_UNKNOWN = 0,
+	PATCH_FORMAT_MBOX,
+	PATCH_FORMAT_STGIT,
+	PATCH_FORMAT_STGIT_SERIES,
+	PATCH_FORMAT_HG,
+	PATCH_FORMAT_MBOXRD
+};
+
+enum keep_type {
+	KEEP_FALSE = 0,
+	KEEP_TRUE,      /* pass -k flag to git-mailinfo */
+	KEEP_NON_PATCH  /* pass -b flag to git-mailinfo */
+};
+
+enum scissors_type {
+	SCISSORS_UNSET = -1,
+	SCISSORS_FALSE = 0,  /* pass --no-scissors to git-mailinfo */
+	SCISSORS_TRUE        /* pass --scissors to git-mailinfo */
+};
+
+enum signoff_type {
+	SIGNOFF_FALSE = 0,
+	SIGNOFF_TRUE = 1,
+	SIGNOFF_EXPLICIT /* --signoff was set on the command-line */
+};
+
+enum resume_type {
+	RESUME_FALSE = 0,
+	RESUME_APPLY,
+	RESUME_RESOLVED,
+	RESUME_SKIP,
+	RESUME_ABORT,
+	RESUME_QUIT,
+	RESUME_SHOW_PATCH_RAW,
+	RESUME_SHOW_PATCH_DIFF,
+	RESUME_ALLOW_EMPTY,
+};
+
+enum empty_action {
+	STOP_ON_EMPTY_COMMIT = 0,  /* output errors and stop in the middle of an am session */
+	DROP_EMPTY_COMMIT,         /* skip with a notice message, unless "--quiet" has been passed */
+	KEEP_EMPTY_COMMIT,         /* keep recording as empty commits */
+};
+
+struct am_state {
+	/* state directory path */
+	char *dir;
+
+	/* current and last patch numbers, 1-indexed */
+	int cur;
+	int last;
+
+	/* commit metadata and message */
+	char *author_name;
+	char *author_email;
+	char *author_date;
+	char *msg;
+	size_t msg_len;
+
+	/* when --rebasing, records the original commit the patch came from */
+	struct object_id orig_commit;
+
+	/* number of digits in patch filename */
+	int prec;
+
+	/* various operating modes and command line options */
+	int interactive;
+	int no_verify;
+	int threeway;
+	int quiet;
+	int signoff; /* enum signoff_type */
+	int utf8;
+	int keep; /* enum keep_type */
+	int message_id;
+	int scissors; /* enum scissors_type */
+	int quoted_cr; /* enum quoted_cr_action */
+	int empty_type; /* enum empty_action */
+	struct strvec git_apply_opts;
+	const char *resolvemsg;
+	int committer_date_is_author_date;
+	int ignore_date;
+	int allow_rerere_autoupdate;
+	const char *sign_commit;
+	int rebasing;
+};
+
+/**
+ * Initializes am_state with the default values.
+ */
+static void am_state_init(struct am_state *state)
+{
+	int gpgsign;
+
+	memset(state, 0, sizeof(*state));
+
+	state->dir = git_pathdup("rebase-apply");
+
+	state->prec = 4;
+
+	git_config_get_bool("am.threeway", &state->threeway);
+
+	state->utf8 = 1;
+
+	git_config_get_bool("am.messageid", &state->message_id);
+
+	state->scissors = SCISSORS_UNSET;
+	state->quoted_cr = quoted_cr_unset;
+
+	strvec_init(&state->git_apply_opts);
+
+	if (!git_config_get_bool("commit.gpgsign", &gpgsign))
+		state->sign_commit = gpgsign ? "" : NULL;
+}
+
+/**
+ * Releases memory allocated by an am_state.
+ */
+static void am_state_release(struct am_state *state)
+{
+	free(state->dir);
+	free(state->author_name);
+	free(state->author_email);
+	free(state->author_date);
+	free(state->msg);
+	strvec_clear(&state->git_apply_opts);
+}
+
+static int am_option_parse_quoted_cr(const struct option *opt,
+				     const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+
+	if (mailinfo_parse_quoted_cr_action(arg, opt->value) != 0)
+		return error(_("bad action '%s' for '%s'"), arg, "--quoted-cr");
+	return 0;
+}
+
+static int am_option_parse_empty(const struct option *opt,
+				     const char *arg, int unset)
+{
+	int *opt_value = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (!strcmp(arg, "stop"))
+		*opt_value = STOP_ON_EMPTY_COMMIT;
+	else if (!strcmp(arg, "drop"))
+		*opt_value = DROP_EMPTY_COMMIT;
+	else if (!strcmp(arg, "keep"))
+		*opt_value = KEEP_EMPTY_COMMIT;
+	else
+		return error(_("invalid value for '%s': '%s'"), "--empty", arg);
+
+	return 0;
+}
+
+/**
+ * Returns path relative to the am_state directory.
+ */
+static inline const char *am_path(const struct am_state *state, const char *path)
+{
+	return mkpath("%s/%s", state->dir, path);
+}
+
+/**
+ * For convenience to call write_file()
+ */
+static void write_state_text(const struct am_state *state,
+			     const char *name, const char *string)
+{
+	write_file(am_path(state, name), "%s", string);
+}
+
+static void write_state_count(const struct am_state *state,
+			      const char *name, int value)
+{
+	write_file(am_path(state, name), "%d", value);
+}
+
+static void write_state_bool(const struct am_state *state,
+			     const char *name, int value)
+{
+	write_state_text(state, name, value ? "t" : "f");
+}
+
+/**
+ * If state->quiet is false, calls fprintf(fp, fmt, ...), and appends a newline
+ * at the end.
+ */
+__attribute__((format (printf, 3, 4)))
+static void say(const struct am_state *state, FILE *fp, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	if (!state->quiet) {
+		vfprintf(fp, fmt, ap);
+		putc('\n', fp);
+	}
+	va_end(ap);
+}
+
+/**
+ * Returns 1 if there is an am session in progress, 0 otherwise.
+ */
+static int am_in_progress(const struct am_state *state)
+{
+	struct stat st;
+
+	if (lstat(state->dir, &st) < 0 || !S_ISDIR(st.st_mode))
+		return 0;
+	if (lstat(am_path(state, "last"), &st) || !S_ISREG(st.st_mode))
+		return 0;
+	if (lstat(am_path(state, "next"), &st) || !S_ISREG(st.st_mode))
+		return 0;
+	return 1;
+}
+
+/**
+ * Reads the contents of `file` in the `state` directory into `sb`. Returns the
+ * number of bytes read on success, -1 if the file does not exist. If `trim` is
+ * set, trailing whitespace will be removed.
+ */
+static int read_state_file(struct strbuf *sb, const struct am_state *state,
+			const char *file, int trim)
+{
+	strbuf_reset(sb);
+
+	if (strbuf_read_file(sb, am_path(state, file), 0) >= 0) {
+		if (trim)
+			strbuf_trim(sb);
+
+		return sb->len;
+	}
+
+	if (errno == ENOENT)
+		return -1;
+
+	die_errno(_("could not read '%s'"), am_path(state, file));
+}
+
+/**
+ * Reads and parses the state directory's "author-script" file, and sets
+ * state->author_name, state->author_email and state->author_date accordingly.
+ * Returns 0 on success, -1 if the file could not be parsed.
+ *
+ * The author script is of the format:
+ *
+ *	GIT_AUTHOR_NAME='$author_name'
+ *	GIT_AUTHOR_EMAIL='$author_email'
+ *	GIT_AUTHOR_DATE='$author_date'
+ *
+ * where $author_name, $author_email and $author_date are quoted. We are strict
+ * with our parsing, as the file was meant to be eval'd in the old git-am.sh
+ * script, and thus if the file differs from what this function expects, it is
+ * better to bail out than to do something that the user does not expect.
+ */
+static int read_am_author_script(struct am_state *state)
+{
+	const char *filename = am_path(state, "author-script");
+
+	assert(!state->author_name);
+	assert(!state->author_email);
+	assert(!state->author_date);
+
+	return read_author_script(filename, &state->author_name,
+				  &state->author_email, &state->author_date, 1);
+}
+
+/**
+ * Saves state->author_name, state->author_email and state->author_date in the
+ * state directory's "author-script" file.
+ */
+static void write_author_script(const struct am_state *state)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	strbuf_addstr(&sb, "GIT_AUTHOR_NAME=");
+	sq_quote_buf(&sb, state->author_name);
+	strbuf_addch(&sb, '\n');
+
+	strbuf_addstr(&sb, "GIT_AUTHOR_EMAIL=");
+	sq_quote_buf(&sb, state->author_email);
+	strbuf_addch(&sb, '\n');
+
+	strbuf_addstr(&sb, "GIT_AUTHOR_DATE=");
+	sq_quote_buf(&sb, state->author_date);
+	strbuf_addch(&sb, '\n');
+
+	write_state_text(state, "author-script", sb.buf);
+
+	strbuf_release(&sb);
+}
+
+/**
+ * Reads the commit message from the state directory's "final-commit" file,
+ * setting state->msg to its contents and state->msg_len to the length of its
+ * contents in bytes.
+ *
+ * Returns 0 on success, -1 if the file does not exist.
+ */
+static int read_commit_msg(struct am_state *state)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	assert(!state->msg);
+
+	if (read_state_file(&sb, state, "final-commit", 0) < 0) {
+		strbuf_release(&sb);
+		return -1;
+	}
+
+	state->msg = strbuf_detach(&sb, &state->msg_len);
+	return 0;
+}
+
+/**
+ * Saves state->msg in the state directory's "final-commit" file.
+ */
+static void write_commit_msg(const struct am_state *state)
+{
+	const char *filename = am_path(state, "final-commit");
+	write_file_buf(filename, state->msg, state->msg_len);
+}
+
+/**
+ * Loads state from disk.
+ */
+static void am_load(struct am_state *state)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	if (read_state_file(&sb, state, "next", 1) < 0)
+		BUG("state file 'next' does not exist");
+	state->cur = strtol(sb.buf, NULL, 10);
+
+	if (read_state_file(&sb, state, "last", 1) < 0)
+		BUG("state file 'last' does not exist");
+	state->last = strtol(sb.buf, NULL, 10);
+
+	if (read_am_author_script(state) < 0)
+		die(_("could not parse author script"));
+
+	read_commit_msg(state);
+
+	if (read_state_file(&sb, state, "original-commit", 1) < 0)
+		oidclr(&state->orig_commit, the_repository->hash_algo);
+	else if (get_oid_hex(sb.buf, &state->orig_commit) < 0)
+		die(_("could not parse %s"), am_path(state, "original-commit"));
+
+	read_state_file(&sb, state, "threeway", 1);
+	state->threeway = !strcmp(sb.buf, "t");
+
+	read_state_file(&sb, state, "quiet", 1);
+	state->quiet = !strcmp(sb.buf, "t");
+
+	read_state_file(&sb, state, "sign", 1);
+	state->signoff = !strcmp(sb.buf, "t");
+
+	read_state_file(&sb, state, "utf8", 1);
+	state->utf8 = !strcmp(sb.buf, "t");
+
+	if (file_exists(am_path(state, "rerere-autoupdate"))) {
+		read_state_file(&sb, state, "rerere-autoupdate", 1);
+		state->allow_rerere_autoupdate = strcmp(sb.buf, "t") ?
+			RERERE_NOAUTOUPDATE : RERERE_AUTOUPDATE;
+	} else {
+		state->allow_rerere_autoupdate = 0;
+	}
+
+	read_state_file(&sb, state, "keep", 1);
+	if (!strcmp(sb.buf, "t"))
+		state->keep = KEEP_TRUE;
+	else if (!strcmp(sb.buf, "b"))
+		state->keep = KEEP_NON_PATCH;
+	else
+		state->keep = KEEP_FALSE;
+
+	read_state_file(&sb, state, "messageid", 1);
+	state->message_id = !strcmp(sb.buf, "t");
+
+	read_state_file(&sb, state, "scissors", 1);
+	if (!strcmp(sb.buf, "t"))
+		state->scissors = SCISSORS_TRUE;
+	else if (!strcmp(sb.buf, "f"))
+		state->scissors = SCISSORS_FALSE;
+	else
+		state->scissors = SCISSORS_UNSET;
+
+	read_state_file(&sb, state, "quoted-cr", 1);
+	if (!*sb.buf)
+		state->quoted_cr = quoted_cr_unset;
+	else if (mailinfo_parse_quoted_cr_action(sb.buf, &state->quoted_cr) != 0)
+		die(_("could not parse %s"), am_path(state, "quoted-cr"));
+
+	read_state_file(&sb, state, "apply-opt", 1);
+	strvec_clear(&state->git_apply_opts);
+	if (sq_dequote_to_strvec(sb.buf, &state->git_apply_opts) < 0)
+		die(_("could not parse %s"), am_path(state, "apply-opt"));
+
+	state->rebasing = !!file_exists(am_path(state, "rebasing"));
+
+	strbuf_release(&sb);
+}
+
+/**
+ * Removes the am_state directory, forcefully terminating the current am
+ * session.
+ */
+static void am_destroy(const struct am_state *state)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	strbuf_addstr(&sb, state->dir);
+	remove_dir_recursively(&sb, 0);
+	strbuf_release(&sb);
+}
+
+/**
+ * Runs applypatch-msg hook. Returns its exit code.
+ */
+static int run_applypatch_msg_hook(struct am_state *state)
+{
+	int ret = 0;
+
+	assert(state->msg);
+
+	if (!state->no_verify)
+		ret = run_hooks_l(the_repository, "applypatch-msg",
+				  am_path(state, "final-commit"), NULL);
+
+	if (!ret) {
+		FREE_AND_NULL(state->msg);
+		if (read_commit_msg(state) < 0)
+			die(_("'%s' was deleted by the applypatch-msg hook"),
+				am_path(state, "final-commit"));
+	}
+
+	return ret;
+}
+
+/**
+ * Runs post-rewrite hook. Returns it exit code.
+ */
+static int run_post_rewrite_hook(const struct am_state *state)
+{
+	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
+	strvec_push(&opt.args, "rebase");
+	opt.path_to_stdin = am_path(state, "rewritten");
+
+	return run_hooks_opt(the_repository, "post-rewrite", &opt);
+}
+
+/**
+ * Reads the state directory's "rewritten" file, and copies notes from the old
+ * commits listed in the file to their rewritten commits.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int copy_notes_for_rebase(const struct am_state *state)
+{
+	struct notes_rewrite_cfg *c;
+	struct strbuf sb = STRBUF_INIT;
+	const char *invalid_line = _("Malformed input line: '%s'.");
+	const char *msg = "Notes added by 'git rebase'";
+	FILE *fp;
+	int ret = 0;
+
+	assert(state->rebasing);
+
+	c = init_copy_notes_for_rewrite("rebase");
+	if (!c)
+		return 0;
+
+	fp = xfopen(am_path(state, "rewritten"), "r");
+
+	while (!strbuf_getline_lf(&sb, fp)) {
+		struct object_id from_obj, to_obj;
+		const char *p;
+
+		if (sb.len != the_hash_algo->hexsz * 2 + 1) {
+			ret = error(invalid_line, sb.buf);
+			goto finish;
+		}
+
+		if (parse_oid_hex(sb.buf, &from_obj, &p)) {
+			ret = error(invalid_line, sb.buf);
+			goto finish;
+		}
+
+		if (*p != ' ') {
+			ret = error(invalid_line, sb.buf);
+			goto finish;
+		}
+
+		if (get_oid_hex(p + 1, &to_obj)) {
+			ret = error(invalid_line, sb.buf);
+			goto finish;
+		}
+
+		if (copy_note_for_rewrite(c, &from_obj, &to_obj))
+			ret = error(_("Failed to copy notes from '%s' to '%s'"),
+					oid_to_hex(&from_obj), oid_to_hex(&to_obj));
+	}
+
+finish:
+	finish_copy_notes_for_rewrite(the_repository, c, msg);
+	fclose(fp);
+	strbuf_release(&sb);
+	return ret;
+}
+
+/**
+ * Determines if the file looks like a piece of RFC2822 mail by grabbing all
+ * non-indented lines and checking if they look like they begin with valid
+ * header field names.
+ *
+ * Returns 1 if the file looks like a piece of mail, 0 otherwise.
+ */
+static int is_mail(FILE *fp)
+{
+	const char *header_regex = "^[!-9;-~]+:";
+	struct strbuf sb = STRBUF_INIT;
+	regex_t regex;
+	int ret = 1;
+
+	if (fseek(fp, 0L, SEEK_SET))
+		die_errno(_("fseek failed"));
+
+	if (regcomp(&regex, header_regex, REG_NOSUB | REG_EXTENDED))
+		die("invalid pattern: %s", header_regex);
+
+	while (!strbuf_getline(&sb, fp)) {
+		if (!sb.len)
+			break; /* End of header */
+
+		/* Ignore indented folded lines */
+		if (*sb.buf == '\t' || *sb.buf == ' ')
+			continue;
+
+		/* It's a header if it matches header_regex */
+		if (regexec(&regex, sb.buf, 0, NULL, 0)) {
+			ret = 0;
+			goto done;
+		}
+	}
+
+done:
+	regfree(&regex);
+	strbuf_release(&sb);
+	return ret;
+}
+
+/**
+ * Attempts to detect the patch_format of the patches contained in `paths`,
+ * returning the PATCH_FORMAT_* enum value. Returns PATCH_FORMAT_UNKNOWN if
+ * detection fails.
+ */
+static int detect_patch_format(const char **paths)
+{
+	enum patch_format ret = PATCH_FORMAT_UNKNOWN;
+	struct strbuf l1 = STRBUF_INIT;
+	struct strbuf l2 = STRBUF_INIT;
+	struct strbuf l3 = STRBUF_INIT;
+	FILE *fp;
+
+	/*
+	 * We default to mbox format if input is from stdin and for directories
+	 */
+	if (!*paths || !strcmp(*paths, "-") || is_directory(*paths))
+		return PATCH_FORMAT_MBOX;
+
+	/*
+	 * Otherwise, check the first few lines of the first patch, starting
+	 * from the first non-blank line, to try to detect its format.
+	 */
+
+	fp = xfopen(*paths, "r");
+
+	while (!strbuf_getline(&l1, fp)) {
+		if (l1.len)
+			break;
+	}
+
+	if (starts_with(l1.buf, "From ") || starts_with(l1.buf, "From: ")) {
+		ret = PATCH_FORMAT_MBOX;
+		goto done;
+	}
+
+	if (starts_with(l1.buf, "# This series applies on GIT commit")) {
+		ret = PATCH_FORMAT_STGIT_SERIES;
+		goto done;
+	}
+
+	if (!strcmp(l1.buf, "# HG changeset patch")) {
+		ret = PATCH_FORMAT_HG;
+		goto done;
+	}
+
+	strbuf_getline(&l2, fp);
+	strbuf_getline(&l3, fp);
+
+	/*
+	 * If the second line is empty and the third is a From, Author or Date
+	 * entry, this is likely an StGit patch.
+	 */
+	if (l1.len && !l2.len &&
+		(starts_with(l3.buf, "From:") ||
+		 starts_with(l3.buf, "Author:") ||
+		 starts_with(l3.buf, "Date:"))) {
+		ret = PATCH_FORMAT_STGIT;
+		goto done;
+	}
+
+	if (l1.len && is_mail(fp)) {
+		ret = PATCH_FORMAT_MBOX;
+		goto done;
+	}
+
+done:
+	fclose(fp);
+	strbuf_release(&l1);
+	strbuf_release(&l2);
+	strbuf_release(&l3);
+	return ret;
+}
+
+/**
+ * Splits out individual email patches from `paths`, where each path is either
+ * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
+ */
+static int split_mail_mbox(struct am_state *state, const char **paths,
+				int keep_cr, int mboxrd)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+	struct strbuf last = STRBUF_INIT;
+	int ret;
+
+	cp.git_cmd = 1;
+	strvec_push(&cp.args, "mailsplit");
+	strvec_pushf(&cp.args, "-d%d", state->prec);
+	strvec_pushf(&cp.args, "-o%s", state->dir);
+	strvec_push(&cp.args, "-b");
+	if (keep_cr)
+		strvec_push(&cp.args, "--keep-cr");
+	if (mboxrd)
+		strvec_push(&cp.args, "--mboxrd");
+	strvec_push(&cp.args, "--");
+	strvec_pushv(&cp.args, paths);
+
+	ret = capture_command(&cp, &last, 8);
+	if (ret)
+		goto exit;
+
+	state->cur = 1;
+	state->last = strtol(last.buf, NULL, 10);
+
+exit:
+	strbuf_release(&last);
+	return ret ? -1 : 0;
+}
+
+/**
+ * Callback signature for split_mail_conv(). The foreign patch should be
+ * read from `in`, and the converted patch (in RFC2822 mail format) should be
+ * written to `out`. Return 0 on success, or -1 on failure.
+ */
+typedef int (*mail_conv_fn)(FILE *out, FILE *in, int keep_cr);
+
+/**
+ * Calls `fn` for each file in `paths` to convert the foreign patch to the
+ * RFC2822 mail format suitable for parsing with git-mailinfo.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail_conv(mail_conv_fn fn, struct am_state *state,
+			const char **paths, int keep_cr)
+{
+	static const char *stdin_only[] = {"-", NULL};
+	int i;
+
+	if (!*paths)
+		paths = stdin_only;
+
+	for (i = 0; *paths; paths++, i++) {
+		FILE *in, *out;
+		const char *mail;
+		int ret;
+
+		if (!strcmp(*paths, "-"))
+			in = stdin;
+		else
+			in = fopen(*paths, "r");
+
+		if (!in)
+			return error_errno(_("could not open '%s' for reading"),
+					   *paths);
+
+		mail = mkpath("%s/%0*d", state->dir, state->prec, i + 1);
+
+		out = fopen(mail, "w");
+		if (!out) {
+			if (in != stdin)
+				fclose(in);
+			return error_errno(_("could not open '%s' for writing"),
+					   mail);
+		}
+
+		ret = fn(out, in, keep_cr);
+
+		fclose(out);
+		if (in != stdin)
+			fclose(in);
+
+		if (ret)
+			return error(_("could not parse patch '%s'"), *paths);
+	}
+
+	state->cur = 1;
+	state->last = i;
+	return 0;
+}
+
+/**
+ * A split_mail_conv() callback that converts an StGit patch to an RFC2822
+ * message suitable for parsing with git-mailinfo.
+ */
+static int stgit_patch_to_mail(FILE *out, FILE *in, int keep_cr UNUSED)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int subject_printed = 0;
+
+	while (!strbuf_getline_lf(&sb, in)) {
+		const char *str;
+
+		if (str_isspace(sb.buf))
+			continue;
+		else if (skip_prefix(sb.buf, "Author:", &str))
+			fprintf(out, "From:%s\n", str);
+		else if (starts_with(sb.buf, "From") || starts_with(sb.buf, "Date"))
+			fprintf(out, "%s\n", sb.buf);
+		else if (!subject_printed) {
+			fprintf(out, "Subject: %s\n", sb.buf);
+			subject_printed = 1;
+		} else {
+			fprintf(out, "\n%s\n", sb.buf);
+			break;
+		}
+	}
+
+	strbuf_reset(&sb);
+	while (strbuf_fread(&sb, 8192, in) > 0) {
+		fwrite(sb.buf, 1, sb.len, out);
+		strbuf_reset(&sb);
+	}
+
+	strbuf_release(&sb);
+	return 0;
+}
+
+/**
+ * This function only supports a single StGit series file in `paths`.
+ *
+ * Given an StGit series file, converts the StGit patches in the series into
+ * RFC2822 messages suitable for parsing with git-mailinfo, and queues them in
+ * the state directory.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail_stgit_series(struct am_state *state, const char **paths,
+					int keep_cr)
+{
+	const char *series_dir;
+	char *series_dir_buf;
+	FILE *fp;
+	struct strvec patches = STRVEC_INIT;
+	struct strbuf sb = STRBUF_INIT;
+	int ret;
+
+	if (!paths[0] || paths[1])
+		return error(_("Only one StGIT patch series can be applied at once"));
+
+	series_dir_buf = xstrdup(*paths);
+	series_dir = dirname(series_dir_buf);
+
+	fp = fopen(*paths, "r");
+	if (!fp)
+		return error_errno(_("could not open '%s' for reading"), *paths);
+
+	while (!strbuf_getline_lf(&sb, fp)) {
+		if (*sb.buf == '#')
+			continue; /* skip comment lines */
+
+		strvec_push(&patches, mkpath("%s/%s", series_dir, sb.buf));
+	}
+
+	fclose(fp);
+	strbuf_release(&sb);
+	free(series_dir_buf);
+
+	ret = split_mail_conv(stgit_patch_to_mail, state, patches.v, keep_cr);
+
+	strvec_clear(&patches);
+	return ret;
+}
+
+/**
+ * A split_patches_conv() callback that converts a mercurial patch to a RFC2822
+ * message suitable for parsing with git-mailinfo.
+ */
+static int hg_patch_to_mail(FILE *out, FILE *in, int keep_cr UNUSED)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int rc = 0;
+
+	while (!strbuf_getline_lf(&sb, in)) {
+		const char *str;
+
+		if (skip_prefix(sb.buf, "# User ", &str))
+			fprintf(out, "From: %s\n", str);
+		else if (skip_prefix(sb.buf, "# Date ", &str)) {
+			timestamp_t timestamp;
+			long tz, tz2;
+			char *end;
+
+			errno = 0;
+			timestamp = parse_timestamp(str, &end, 10);
+			if (errno) {
+				rc = error(_("invalid timestamp"));
+				goto exit;
+			}
+
+			if (!skip_prefix(end, " ", &str)) {
+				rc = error(_("invalid Date line"));
+				goto exit;
+			}
+
+			errno = 0;
+			tz = strtol(str, &end, 10);
+			if (errno) {
+				rc = error(_("invalid timezone offset"));
+				goto exit;
+			}
+
+			if (*end) {
+				rc = error(_("invalid Date line"));
+				goto exit;
+			}
+
+			/*
+			 * mercurial's timezone is in seconds west of UTC,
+			 * however git's timezone is in hours + minutes east of
+			 * UTC. Convert it.
+			 */
+			tz2 = labs(tz) / 3600 * 100 + labs(tz) % 3600 / 60;
+			if (tz > 0)
+				tz2 = -tz2;
+
+			fprintf(out, "Date: %s\n", show_date(timestamp, tz2, DATE_MODE(RFC2822)));
+		} else if (starts_with(sb.buf, "# ")) {
+			continue;
+		} else {
+			fprintf(out, "\n%s\n", sb.buf);
+			break;
+		}
+	}
+
+	strbuf_reset(&sb);
+	while (strbuf_fread(&sb, 8192, in) > 0) {
+		fwrite(sb.buf, 1, sb.len, out);
+		strbuf_reset(&sb);
+	}
+exit:
+	strbuf_release(&sb);
+	return rc;
+}
+
+/**
+ * Splits a list of files/directories into individual email patches. Each path
+ * in `paths` must be a file/directory that is formatted according to
+ * `patch_format`.
+ *
+ * Once split out, the individual email patches will be stored in the state
+ * directory, with each patch's filename being its index, padded to state->prec
+ * digits.
+ *
+ * state->cur will be set to the index of the first mail, and state->last will
+ * be set to the index of the last mail.
+ *
+ * Set keep_cr to 0 to convert all lines ending with \r\n to end with \n, 1
+ * to disable this behavior, -1 to use the default configured setting.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+static int split_mail(struct am_state *state, enum patch_format patch_format,
+			const char **paths, int keep_cr)
+{
+	if (keep_cr < 0) {
+		keep_cr = 0;
+		git_config_get_bool("am.keepcr", &keep_cr);
+	}
+
+	switch (patch_format) {
+	case PATCH_FORMAT_MBOX:
+		return split_mail_mbox(state, paths, keep_cr, 0);
+	case PATCH_FORMAT_STGIT:
+		return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
+	case PATCH_FORMAT_STGIT_SERIES:
+		return split_mail_stgit_series(state, paths, keep_cr);
+	case PATCH_FORMAT_HG:
+		return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
+	case PATCH_FORMAT_MBOXRD:
+		return split_mail_mbox(state, paths, keep_cr, 1);
+	default:
+		BUG("invalid patch_format");
+	}
+	return -1;
+}
+
+/**
+ * Setup a new am session for applying patches
+ */
+static void am_setup(struct am_state *state, enum patch_format patch_format,
+			const char **paths, int keep_cr)
+{
+	struct object_id curr_head;
+	const char *str;
+	struct strbuf sb = STRBUF_INIT;
+
+	if (!patch_format)
+		patch_format = detect_patch_format(paths);
+
+	if (!patch_format) {
+		fprintf_ln(stderr, _("Patch format detection failed."));
+		exit(128);
+	}
+
+	if (mkdir(state->dir, 0777) < 0 && errno != EEXIST)
+		die_errno(_("failed to create directory '%s'"), state->dir);
+	refs_delete_ref(get_main_ref_store(the_repository), NULL,
+			"REBASE_HEAD", NULL, REF_NO_DEREF);
+
+	if (split_mail(state, patch_format, paths, keep_cr) < 0) {
+		am_destroy(state);
+		die(_("Failed to split patches."));
+	}
+
+	if (state->rebasing)
+		state->threeway = 1;
+
+	write_state_bool(state, "threeway", state->threeway);
+	write_state_bool(state, "quiet", state->quiet);
+	write_state_bool(state, "sign", state->signoff);
+	write_state_bool(state, "utf8", state->utf8);
+
+	if (state->allow_rerere_autoupdate)
+		write_state_bool(state, "rerere-autoupdate",
+			 state->allow_rerere_autoupdate == RERERE_AUTOUPDATE);
+
+	switch (state->keep) {
+	case KEEP_FALSE:
+		str = "f";
+		break;
+	case KEEP_TRUE:
+		str = "t";
+		break;
+	case KEEP_NON_PATCH:
+		str = "b";
+		break;
+	default:
+		BUG("invalid value for state->keep");
+	}
+
+	write_state_text(state, "keep", str);
+	write_state_bool(state, "messageid", state->message_id);
+
+	switch (state->scissors) {
+	case SCISSORS_UNSET:
+		str = "";
+		break;
+	case SCISSORS_FALSE:
+		str = "f";
+		break;
+	case SCISSORS_TRUE:
+		str = "t";
+		break;
+	default:
+		BUG("invalid value for state->scissors");
+	}
+	write_state_text(state, "scissors", str);
+
+	switch (state->quoted_cr) {
+	case quoted_cr_unset:
+		str = "";
+		break;
+	case quoted_cr_nowarn:
+		str = "nowarn";
+		break;
+	case quoted_cr_warn:
+		str = "warn";
+		break;
+	case quoted_cr_strip:
+		str = "strip";
+		break;
+	default:
+		BUG("invalid value for state->quoted_cr");
+	}
+	write_state_text(state, "quoted-cr", str);
+
+	sq_quote_argv(&sb, state->git_apply_opts.v);
+	write_state_text(state, "apply-opt", sb.buf);
+
+	if (state->rebasing)
+		write_state_text(state, "rebasing", "");
+	else
+		write_state_text(state, "applying", "");
+
+	if (!repo_get_oid(the_repository, "HEAD", &curr_head)) {
+		write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
+		if (!state->rebasing)
+			refs_update_ref(get_main_ref_store(the_repository),
+					"am", "ORIG_HEAD", &curr_head, NULL,
+					0,
+					UPDATE_REFS_DIE_ON_ERR);
+	} else {
+		write_state_text(state, "abort-safety", "");
+		if (!state->rebasing)
+			refs_delete_ref(get_main_ref_store(the_repository),
+					NULL, "ORIG_HEAD", NULL, 0);
+	}
+
+	/*
+	 * NOTE: Since the "next" and "last" files determine if an am_state
+	 * session is in progress, they should be written last.
+	 */
+
+	write_state_count(state, "next", state->cur);
+	write_state_count(state, "last", state->last);
+
+	strbuf_release(&sb);
+}
+
+/**
+ * Increments the patch pointer, and cleans am_state for the application of the
+ * next patch.
+ */
+static void am_next(struct am_state *state)
+{
+	struct object_id head;
+
+	FREE_AND_NULL(state->author_name);
+	FREE_AND_NULL(state->author_email);
+	FREE_AND_NULL(state->author_date);
+	FREE_AND_NULL(state->msg);
+	state->msg_len = 0;
+
+	unlink(am_path(state, "author-script"));
+	unlink(am_path(state, "final-commit"));
+
+	oidclr(&state->orig_commit, the_repository->hash_algo);
+	unlink(am_path(state, "original-commit"));
+	refs_delete_ref(get_main_ref_store(the_repository), NULL,
+			"REBASE_HEAD", NULL, REF_NO_DEREF);
+
+	if (!repo_get_oid(the_repository, "HEAD", &head))
+		write_state_text(state, "abort-safety", oid_to_hex(&head));
+	else
+		write_state_text(state, "abort-safety", "");
+
+	state->cur++;
+	write_state_count(state, "next", state->cur);
+}
+
+/**
+ * Returns the filename of the current patch email.
+ */
+static const char *msgnum(const struct am_state *state)
+{
+	static struct strbuf sb = STRBUF_INIT;
+
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%0*d", state->prec, state->cur);
+
+	return sb.buf;
+}
+
+/**
+ * Dies with a user-friendly message on how to proceed after resolving the
+ * problem. This message can be overridden with state->resolvemsg.
+ */
+static void NORETURN die_user_resolve(const struct am_state *state)
+{
+	if (state->resolvemsg) {
+		advise_if_enabled(ADVICE_MERGE_CONFLICT, "%s", state->resolvemsg);
+	} else {
+		const char *cmdline = state->interactive ? "git am -i" : "git am";
+		struct strbuf sb = STRBUF_INIT;
+
+		strbuf_addf(&sb, _("When you have resolved this problem, run \"%s --continue\".\n"), cmdline);
+		strbuf_addf(&sb, _("If you prefer to skip this patch, run \"%s --skip\" instead.\n"), cmdline);
+
+		if (advice_enabled(ADVICE_AM_WORK_DIR) &&
+		    is_empty_or_missing_file(am_path(state, "patch")) &&
+		    !repo_index_has_changes(the_repository, NULL, NULL))
+			strbuf_addf(&sb, _("To record the empty patch as an empty commit, run \"%s --allow-empty\".\n"), cmdline);
+
+		strbuf_addf(&sb, _("To restore the original branch and stop patching, run \"%s --abort\"."), cmdline);
+
+		advise_if_enabled(ADVICE_MERGE_CONFLICT, "%s", sb.buf);
+		strbuf_release(&sb);
+	}
+
+	exit(128);
+}
+
+/**
+ * Appends signoff to the "msg" field of the am_state.
+ */
+static void am_append_signoff(struct am_state *state)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	strbuf_attach(&sb, state->msg, state->msg_len, state->msg_len);
+	append_signoff(&sb, 0, 0);
+	state->msg = strbuf_detach(&sb, &state->msg_len);
+}
+
+/**
+ * Parses `mail` using git-mailinfo, extracting its patch and authorship info.
+ * state->msg will be set to the patch message. state->author_name,
+ * state->author_email and state->author_date will be set to the patch author's
+ * name, email and date respectively. The patch body will be written to the
+ * state directory's "patch" file.
+ *
+ * Returns 1 if the patch should be skipped, 0 otherwise.
+ */
+static int parse_mail(struct am_state *state, const char *mail)
+{
+	FILE *fp;
+	struct strbuf sb = STRBUF_INIT;
+	struct strbuf msg = STRBUF_INIT;
+	struct strbuf author_name = STRBUF_INIT;
+	struct strbuf author_date = STRBUF_INIT;
+	struct strbuf author_email = STRBUF_INIT;
+	int ret = 0;
+	struct mailinfo mi;
+
+	setup_mailinfo(the_repository, &mi);
+
+	if (state->utf8)
+		mi.metainfo_charset = get_commit_output_encoding();
+	else
+		mi.metainfo_charset = NULL;
+
+	switch (state->keep) {
+	case KEEP_FALSE:
+		break;
+	case KEEP_TRUE:
+		mi.keep_subject = 1;
+		break;
+	case KEEP_NON_PATCH:
+		mi.keep_non_patch_brackets_in_subject = 1;
+		break;
+	default:
+		BUG("invalid value for state->keep");
+	}
+
+	if (state->message_id)
+		mi.add_message_id = 1;
+
+	switch (state->scissors) {
+	case SCISSORS_UNSET:
+		break;
+	case SCISSORS_FALSE:
+		mi.use_scissors = 0;
+		break;
+	case SCISSORS_TRUE:
+		mi.use_scissors = 1;
+		break;
+	default:
+		BUG("invalid value for state->scissors");
+	}
+
+	switch (state->quoted_cr) {
+	case quoted_cr_unset:
+		break;
+	case quoted_cr_nowarn:
+	case quoted_cr_warn:
+	case quoted_cr_strip:
+		mi.quoted_cr = state->quoted_cr;
+		break;
+	default:
+		BUG("invalid value for state->quoted_cr");
+	}
+
+	mi.input = xfopen(mail, "r");
+	mi.output = xfopen(am_path(state, "info"), "w");
+	if (mailinfo(&mi, am_path(state, "msg"), am_path(state, "patch")))
+		die("could not parse patch");
+
+	fclose(mi.input);
+	fclose(mi.output);
+
+	if (mi.format_flowed)
+		warning(_("Patch sent with format=flowed; "
+			  "space at the end of lines might be lost."));
+
+	/* Extract message and author information */
+	fp = xfopen(am_path(state, "info"), "r");
+	while (!strbuf_getline_lf(&sb, fp)) {
+		const char *x;
+
+		if (skip_prefix(sb.buf, "Subject: ", &x)) {
+			if (msg.len)
+				strbuf_addch(&msg, '\n');
+			strbuf_addstr(&msg, x);
+		} else if (skip_prefix(sb.buf, "Author: ", &x))
+			strbuf_addstr(&author_name, x);
+		else if (skip_prefix(sb.buf, "Email: ", &x))
+			strbuf_addstr(&author_email, x);
+		else if (skip_prefix(sb.buf, "Date: ", &x))
+			strbuf_addstr(&author_date, x);
+	}
+	fclose(fp);
+
+	/* Skip pine's internal folder data */
+	if (!strcmp(author_name.buf, "Mail System Internal Data")) {
+		ret = 1;
+		goto finish;
+	}
+
+	strbuf_addstr(&msg, "\n\n");
+	strbuf_addbuf(&msg, &mi.log_message);
+	strbuf_stripspace(&msg, NULL);
+
+	assert(!state->author_name);
+	state->author_name = strbuf_detach(&author_name, NULL);
+
+	assert(!state->author_email);
+	state->author_email = strbuf_detach(&author_email, NULL);
+
+	assert(!state->author_date);
+	state->author_date = strbuf_detach(&author_date, NULL);
+
+	assert(!state->msg);
+	state->msg = strbuf_detach(&msg, &state->msg_len);
+
+finish:
+	strbuf_release(&msg);
+	strbuf_release(&author_date);
+	strbuf_release(&author_email);
+	strbuf_release(&author_name);
+	strbuf_release(&sb);
+	clear_mailinfo(&mi);
+	return ret;
+}
+
+/**
+ * Sets commit_id to the commit hash where the mail was generated from.
+ * Returns 0 on success, -1 on failure.
+ */
+static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
+{
+	struct strbuf sb = STRBUF_INIT;
+	FILE *fp = xfopen(mail, "r");
+	const char *x;
+	int ret = 0;
+
+	if (strbuf_getline_lf(&sb, fp) ||
+	    !skip_prefix(sb.buf, "From ", &x) ||
+	    get_oid_hex(x, commit_id) < 0)
+		ret = -1;
+
+	strbuf_release(&sb);
+	fclose(fp);
+	return ret;
+}
+
+/**
+ * Sets state->msg, state->author_name, state->author_email, state->author_date
+ * to the commit's respective info.
+ */
+static void get_commit_info(struct am_state *state, struct commit *commit)
+{
+	const char *buffer, *ident_line, *msg;
+	size_t ident_len;
+	struct ident_split id;
+
+	buffer = repo_logmsg_reencode(the_repository, commit, NULL,
+				      get_commit_output_encoding());
+
+	ident_line = find_commit_header(buffer, "author", &ident_len);
+	if (!ident_line)
+		die(_("missing author line in commit %s"),
+		      oid_to_hex(&commit->object.oid));
+	if (split_ident_line(&id, ident_line, ident_len) < 0)
+		die(_("invalid ident line: %.*s"), (int)ident_len, ident_line);
+
+	assert(!state->author_name);
+	if (id.name_begin)
+		state->author_name =
+			xmemdupz(id.name_begin, id.name_end - id.name_begin);
+	else
+		state->author_name = xstrdup("");
+
+	assert(!state->author_email);
+	if (id.mail_begin)
+		state->author_email =
+			xmemdupz(id.mail_begin, id.mail_end - id.mail_begin);
+	else
+		state->author_email = xstrdup("");
+
+	assert(!state->author_date);
+	state->author_date = xstrdup(show_ident_date(&id, DATE_MODE(NORMAL)));
+
+	assert(!state->msg);
+	msg = strstr(buffer, "\n\n");
+	if (!msg)
+		die(_("unable to parse commit %s"), oid_to_hex(&commit->object.oid));
+	state->msg = xstrdup(msg + 2);
+	state->msg_len = strlen(state->msg);
+	repo_unuse_commit_buffer(the_repository, commit, buffer);
+}
+
+/**
+ * Writes `commit` as a patch to the state directory's "patch" file.
+ */
+static void write_commit_patch(const struct am_state *state, struct commit *commit)
+{
+	struct rev_info rev_info;
+	FILE *fp;
+
+	fp = xfopen(am_path(state, "patch"), "w");
+	repo_init_revisions(the_repository, &rev_info, NULL);
+	rev_info.diff = 1;
+	rev_info.abbrev = 0;
+	rev_info.disable_stdin = 1;
+	rev_info.show_root_diff = 1;
+	rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
+	rev_info.no_commit_id = 1;
+	rev_info.diffopt.flags.binary = 1;
+	rev_info.diffopt.flags.full_index = 1;
+	rev_info.diffopt.use_color = 0;
+	rev_info.diffopt.file = fp;
+	rev_info.diffopt.close_file = 1;
+	add_pending_object(&rev_info, &commit->object, "");
+	diff_setup_done(&rev_info.diffopt);
+	log_tree_commit(&rev_info, commit);
+	release_revisions(&rev_info);
+}
+
+/**
+ * Writes the diff of the index against HEAD as a patch to the state
+ * directory's "patch" file.
+ */
+static void write_index_patch(const struct am_state *state)
+{
+	struct tree *tree;
+	struct object_id head;
+	struct rev_info rev_info;
+	FILE *fp;
+
+	if (!repo_get_oid(the_repository, "HEAD", &head)) {
+		struct commit *commit = lookup_commit_or_die(&head, "HEAD");
+		tree = repo_get_commit_tree(the_repository, commit);
+	} else
+		tree = lookup_tree(the_repository,
+				   the_repository->hash_algo->empty_tree);
+
+	fp = xfopen(am_path(state, "patch"), "w");
+	repo_init_revisions(the_repository, &rev_info, NULL);
+	rev_info.diff = 1;
+	rev_info.disable_stdin = 1;
+	rev_info.no_commit_id = 1;
+	rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
+	rev_info.diffopt.use_color = 0;
+	rev_info.diffopt.file = fp;
+	rev_info.diffopt.close_file = 1;
+	add_pending_object(&rev_info, &tree->object, "");
+	diff_setup_done(&rev_info.diffopt);
+	run_diff_index(&rev_info, DIFF_INDEX_CACHED);
+	release_revisions(&rev_info);
+}
+
+/**
+ * Like parse_mail(), but parses the mail by looking up its commit ID
+ * directly. This is used in --rebasing mode to bypass git-mailinfo's munging
+ * of patches.
+ *
+ * state->orig_commit will be set to the original commit ID.
+ *
+ * Will always return 0 as the patch should never be skipped.
+ */
+static int parse_mail_rebase(struct am_state *state, const char *mail)
+{
+	struct commit *commit;
+	struct object_id commit_oid;
+
+	if (get_mail_commit_oid(&commit_oid, mail) < 0)
+		die(_("could not parse %s"), mail);
+
+	commit = lookup_commit_or_die(&commit_oid, mail);
+
+	get_commit_info(state, commit);
+
+	write_commit_patch(state, commit);
+
+	oidcpy(&state->orig_commit, &commit_oid);
+	write_state_text(state, "original-commit", oid_to_hex(&commit_oid));
+	refs_update_ref(get_main_ref_store(the_repository), "am",
+			"REBASE_HEAD", &commit_oid,
+			NULL, REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
+
+	return 0;
+}
+
+/**
+ * Applies current patch with git-apply. Returns 0 on success, -1 otherwise. If
+ * `index_file` is not NULL, the patch will be applied to that index.
+ */
+static int run_apply(const struct am_state *state, const char *index_file)
+{
+	struct strvec apply_paths = STRVEC_INIT;
+	struct strvec apply_opts = STRVEC_INIT;
+	struct apply_state apply_state;
+	int res, opts_left;
+	int force_apply = 0;
+	int options = 0;
+	const char **apply_argv;
+
+	if (init_apply_state(&apply_state, the_repository, NULL))
+		BUG("init_apply_state() failed");
+
+	strvec_push(&apply_opts, "apply");
+	strvec_pushv(&apply_opts, state->git_apply_opts.v);
+
+	/*
+	 * Build a copy that apply_parse_options() can rearrange.
+	 * apply_opts.v keeps referencing the allocated strings for
+	 * strvec_clear() to release.
+	 */
+	DUP_ARRAY(apply_argv, apply_opts.v, apply_opts.nr);
+
+	opts_left = apply_parse_options(apply_opts.nr, apply_argv,
+					&apply_state, &force_apply, &options,
+					NULL);
+
+	if (opts_left != 0)
+		die("unknown option passed through to git apply");
+
+	if (index_file) {
+		apply_state.index_file = index_file;
+		apply_state.cached = 1;
+	} else
+		apply_state.check_index = 1;
+
+	/*
+	 * If we are allowed to fall back on 3-way merge, don't give false
+	 * errors during the initial attempt.
+	 */
+	if (state->threeway && !index_file)
+		apply_state.apply_verbosity = verbosity_silent;
+
+	if (check_apply_state(&apply_state, force_apply))
+		BUG("check_apply_state() failed");
+
+	strvec_push(&apply_paths, am_path(state, "patch"));
+
+	res = apply_all_patches(&apply_state, apply_paths.nr, apply_paths.v, options);
+
+	strvec_clear(&apply_paths);
+	strvec_clear(&apply_opts);
+	clear_apply_state(&apply_state);
+	free(apply_argv);
+
+	if (res)
+		return res;
+
+	if (index_file) {
+		/* Reload index as apply_all_patches() will have modified it. */
+		discard_index(the_repository->index);
+		read_index_from(the_repository->index, index_file,
+				repo_get_git_dir(the_repository));
+	}
+
+	return 0;
+}
+
+/**
+ * Builds an index that contains just the blobs needed for a 3way merge.
+ */
+static int build_fake_ancestor(const struct am_state *state, const char *index_file)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	cp.git_cmd = 1;
+	strvec_push(&cp.args, "apply");
+	strvec_pushv(&cp.args, state->git_apply_opts.v);
+	strvec_pushf(&cp.args, "--build-fake-ancestor=%s", index_file);
+	strvec_push(&cp.args, am_path(state, "patch"));
+
+	if (run_command(&cp))
+		return -1;
+
+	return 0;
+}
+
+/**
+ * Attempt a threeway merge, using index_path as the temporary index.
+ */
+static int fall_back_threeway(const struct am_state *state, const char *index_path)
+{
+	struct object_id their_tree, our_tree;
+	struct object_id bases[1] = { 0 };
+	struct merge_options o;
+	struct commit *result;
+	char *their_tree_name;
+
+	if (repo_get_oid(the_repository, "HEAD", &our_tree) < 0)
+		oidcpy(&our_tree, the_hash_algo->empty_tree);
+
+	if (build_fake_ancestor(state, index_path))
+		return error("could not build fake ancestor");
+
+	discard_index(the_repository->index);
+	read_index_from(the_repository->index, index_path, repo_get_git_dir(the_repository));
+
+	if (write_index_as_tree(&bases[0], the_repository->index, index_path, 0, NULL))
+		return error(_("Repository lacks necessary blobs to fall back on 3-way merge."));
+
+	say(state, stdout, _("Using index info to reconstruct a base tree..."));
+
+	if (!state->quiet) {
+		/*
+		 * List paths that needed 3-way fallback, so that the user can
+		 * review them with extra care to spot mismerges.
+		 */
+		struct rev_info rev_info;
+
+		repo_init_revisions(the_repository, &rev_info, NULL);
+		rev_info.diffopt.output_format = DIFF_FORMAT_NAME_STATUS;
+		rev_info.diffopt.filter |= diff_filter_bit('A');
+		rev_info.diffopt.filter |= diff_filter_bit('M');
+		add_pending_oid(&rev_info, "HEAD", &our_tree, 0);
+		diff_setup_done(&rev_info.diffopt);
+		run_diff_index(&rev_info, DIFF_INDEX_CACHED);
+		release_revisions(&rev_info);
+	}
+
+	if (run_apply(state, index_path))
+		return error(_("Did you hand edit your patch?\n"
+				"It does not apply to blobs recorded in its index."));
+
+	if (write_index_as_tree(&their_tree, the_repository->index, index_path, 0, NULL))
+		return error("could not write tree");
+
+	say(state, stdout, _("Falling back to patching base and 3-way merge..."));
+
+	discard_index(the_repository->index);
+	repo_read_index(the_repository);
+
+	/*
+	 * This is not so wrong. Depending on which base we picked, orig_tree
+	 * may be wildly different from ours, but their_tree has the same set of
+	 * wildly different changes in parts the patch did not touch, so
+	 * recursive ends up canceling them, saying that we reverted all those
+	 * changes.
+	 */
+
+	init_ui_merge_options(&o, the_repository);
+
+	o.branch1 = "HEAD";
+	their_tree_name = xstrfmt("%.*s", linelen(state->msg), state->msg);
+	o.branch2 = their_tree_name;
+	o.detect_directory_renames = MERGE_DIRECTORY_RENAMES_NONE;
+
+	if (state->quiet)
+		o.verbosity = 0;
+
+	if (merge_recursive_generic(&o, &our_tree, &their_tree, 1, bases, &result)) {
+		repo_rerere(the_repository, state->allow_rerere_autoupdate);
+		free(their_tree_name);
+		return error(_("Failed to merge in the changes."));
+	}
+
+	free(their_tree_name);
+	return 0;
+}
+
+/**
+ * Commits the current index with state->msg as the commit message and
+ * state->author_name, state->author_email and state->author_date as the author
+ * information.
+ */
+static void do_commit(const struct am_state *state)
+{
+	struct object_id tree, parent, commit;
+	const struct object_id *old_oid;
+	struct commit_list *parents = NULL;
+	const char *reflog_msg, *author, *committer = NULL;
+	struct strbuf sb = STRBUF_INIT;
+
+	if (!state->no_verify && run_hooks(the_repository, "pre-applypatch"))
+		exit(1);
+
+	if (write_index_as_tree(&tree, the_repository->index,
+				repo_get_index_file(the_repository),
+				0, NULL))
+		die(_("git write-tree failed to write a tree"));
+
+	if (!repo_get_oid_commit(the_repository, "HEAD", &parent)) {
+		old_oid = &parent;
+		commit_list_insert(lookup_commit(the_repository, &parent),
+				   &parents);
+	} else {
+		old_oid = NULL;
+		say(state, stderr, _("applying to an empty history"));
+	}
+
+	author = fmt_ident(state->author_name, state->author_email,
+		WANT_AUTHOR_IDENT,
+			state->ignore_date ? NULL : state->author_date,
+			IDENT_STRICT);
+
+	if (state->committer_date_is_author_date)
+		committer = fmt_ident(getenv("GIT_COMMITTER_NAME"),
+				      getenv("GIT_COMMITTER_EMAIL"),
+				      WANT_COMMITTER_IDENT,
+				      state->ignore_date ? NULL
+							 : state->author_date,
+				      IDENT_STRICT);
+
+	if (commit_tree_extended(state->msg, state->msg_len, &tree, parents,
+				 &commit, author, committer, state->sign_commit,
+				 NULL))
+		die(_("failed to write commit object"));
+
+	reflog_msg = getenv("GIT_REFLOG_ACTION");
+	if (!reflog_msg)
+		reflog_msg = "am";
+
+	strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
+			state->msg);
+
+	refs_update_ref(get_main_ref_store(the_repository), sb.buf, "HEAD",
+			&commit, old_oid, 0,
+			UPDATE_REFS_DIE_ON_ERR);
+
+	if (state->rebasing) {
+		FILE *fp = xfopen(am_path(state, "rewritten"), "a");
+
+		assert(!is_null_oid(&state->orig_commit));
+		fprintf(fp, "%s ", oid_to_hex(&state->orig_commit));
+		fprintf(fp, "%s\n", oid_to_hex(&commit));
+		fclose(fp);
+	}
+
+	run_hooks(the_repository, "post-applypatch");
+
+	free_commit_list(parents);
+	strbuf_release(&sb);
+}
+
+/**
+ * Validates the am_state for resuming -- the "msg" and authorship fields must
+ * be filled up.
+ */
+static void validate_resume_state(const struct am_state *state)
+{
+	if (!state->msg)
+		die(_("cannot resume: %s does not exist."),
+			am_path(state, "final-commit"));
+
+	if (!state->author_name || !state->author_email || !state->author_date)
+		die(_("cannot resume: %s does not exist."),
+			am_path(state, "author-script"));
+}
+
+/**
+ * Interactively prompt the user on whether the current patch should be
+ * applied.
+ *
+ * Returns 0 if the user chooses to apply the patch, 1 if the user chooses to
+ * skip it.
+ */
+static int do_interactive(struct am_state *state)
+{
+	assert(state->msg);
+
+	for (;;) {
+		char reply[64];
+
+		puts(_("Commit Body is:"));
+		puts("--------------------------");
+		printf("%s", state->msg);
+		puts("--------------------------");
+
+		/*
+		 * TRANSLATORS: Make sure to include [y], [n], [e], [v] and [a]
+		 * in your translation. The program will only accept English
+		 * input at this point.
+		 */
+		printf(_("Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all: "));
+		if (!fgets(reply, sizeof(reply), stdin))
+			die("unable to read from stdin; aborting");
+
+		if (*reply == 'y' || *reply == 'Y') {
+			return 0;
+		} else if (*reply == 'a' || *reply == 'A') {
+			state->interactive = 0;
+			return 0;
+		} else if (*reply == 'n' || *reply == 'N') {
+			return 1;
+		} else if (*reply == 'e' || *reply == 'E') {
+			struct strbuf msg = STRBUF_INIT;
+
+			if (!launch_editor(am_path(state, "final-commit"), &msg, NULL)) {
+				free(state->msg);
+				state->msg = strbuf_detach(&msg, &state->msg_len);
+			}
+			strbuf_release(&msg);
+		} else if (*reply == 'v' || *reply == 'V') {
+			const char *pager = git_pager(the_repository, 1);
+			struct child_process cp = CHILD_PROCESS_INIT;
+
+			if (!pager)
+				pager = "cat";
+			prepare_pager_args(&cp, pager);
+			strvec_push(&cp.args, am_path(state, "patch"));
+			run_command(&cp);
+		}
+	}
+}
+
+/**
+ * Applies all queued mail.
+ *
+ * If `resume` is true, we are "resuming". The "msg" and authorship fields, as
+ * well as the state directory's "patch" file is used as-is for applying the
+ * patch and committing it.
+ */
+static void am_run(struct am_state *state, int resume)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	unlink(am_path(state, "dirtyindex"));
+
+	if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+					 NULL, NULL, NULL) < 0)
+		die(_("unable to write index file"));
+
+	if (repo_index_has_changes(the_repository, NULL, &sb)) {
+		write_state_bool(state, "dirtyindex", 1);
+		die(_("Dirty index: cannot apply patches (dirty: %s)"), sb.buf);
+	}
+
+	strbuf_release(&sb);
+
+	while (state->cur <= state->last) {
+		const char *mail = am_path(state, msgnum(state));
+		int apply_status;
+		int to_keep;
+
+		reset_ident_date();
+
+		if (!file_exists(mail))
+			goto next;
+
+		if (resume) {
+			validate_resume_state(state);
+		} else {
+			int skip;
+
+			if (state->rebasing)
+				skip = parse_mail_rebase(state, mail);
+			else
+				skip = parse_mail(state, mail);
+
+			if (skip)
+				goto next; /* mail should be skipped */
+
+			if (state->signoff)
+				am_append_signoff(state);
+
+			write_author_script(state);
+			write_commit_msg(state);
+		}
+
+		if (state->interactive && do_interactive(state))
+			goto next;
+
+		to_keep = 0;
+		if (is_empty_or_missing_file(am_path(state, "patch"))) {
+			switch (state->empty_type) {
+			case DROP_EMPTY_COMMIT:
+				say(state, stdout, _("Skipping: %.*s"), linelen(state->msg), state->msg);
+				goto next;
+				break;
+			case KEEP_EMPTY_COMMIT:
+				to_keep = 1;
+				say(state, stdout, _("Creating an empty commit: %.*s"),
+					linelen(state->msg), state->msg);
+				break;
+			case STOP_ON_EMPTY_COMMIT:
+				printf_ln(_("Patch is empty."));
+				die_user_resolve(state);
+				break;
+			}
+		}
+
+		if (run_applypatch_msg_hook(state))
+			exit(1);
+		if (to_keep)
+			goto commit;
+
+		say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg);
+
+		apply_status = run_apply(state, NULL);
+
+		if (apply_status && state->threeway) {
+			struct strbuf sb = STRBUF_INIT;
+
+			strbuf_addstr(&sb, am_path(state, "patch-merge-index"));
+			apply_status = fall_back_threeway(state, sb.buf);
+			strbuf_release(&sb);
+
+			/*
+			 * Applying the patch to an earlier tree and merging
+			 * the result may have produced the same tree as ours.
+			 */
+			if (!apply_status &&
+			    !repo_index_has_changes(the_repository, NULL, NULL)) {
+				say(state, stdout, _("No changes -- Patch already applied."));
+				goto next;
+			}
+		}
+
+		if (apply_status) {
+			printf_ln(_("Patch failed at %s %.*s"), msgnum(state),
+				linelen(state->msg), state->msg);
+
+			if (advice_enabled(ADVICE_AM_WORK_DIR))
+				advise(_("Use 'git am --show-current-patch=diff' to see the failed patch"));
+
+			die_user_resolve(state);
+		}
+
+commit:
+		do_commit(state);
+
+next:
+		am_next(state);
+
+		if (resume)
+			am_load(state);
+		resume = 0;
+	}
+
+	if (!is_empty_or_missing_file(am_path(state, "rewritten"))) {
+		assert(state->rebasing);
+		copy_notes_for_rebase(state);
+		run_post_rewrite_hook(state);
+	}
+
+	/*
+	 * In rebasing mode, it's up to the caller to take care of
+	 * housekeeping.
+	 */
+	if (!state->rebasing) {
+		am_destroy(state);
+		run_auto_maintenance(state->quiet);
+	}
+}
+
+/**
+ * Resume the current am session after patch application failure. The user did
+ * all the hard work, and we do not have to do any patch application. Just
+ * trust and commit what the user has in the index and working tree. If `allow_empty`
+ * is true, commit as an empty commit when index has not changed and lacking a patch.
+ */
+static void am_resolve(struct am_state *state, int allow_empty)
+{
+	validate_resume_state(state);
+
+	say(state, stdout, _("Applying: %.*s"), linelen(state->msg), state->msg);
+
+	if (!repo_index_has_changes(the_repository, NULL, NULL)) {
+		if (allow_empty && is_empty_or_missing_file(am_path(state, "patch"))) {
+			printf_ln(_("No changes - recorded it as an empty commit."));
+		} else {
+			printf_ln(_("No changes - did you forget to use 'git add'?\n"
+				    "If there is nothing left to stage, chances are that something else\n"
+				    "already introduced the same changes; you might want to skip this patch."));
+			die_user_resolve(state);
+		}
+	}
+
+	if (unmerged_index(the_repository->index)) {
+		printf_ln(_("You still have unmerged paths in your index.\n"
+			"You should 'git add' each file with resolved conflicts to mark them as such.\n"
+			"You might run `git rm` on a file to accept \"deleted by them\" for it."));
+		die_user_resolve(state);
+	}
+
+	if (state->interactive) {
+		write_index_patch(state);
+		if (do_interactive(state))
+			goto next;
+	}
+
+	repo_rerere(the_repository, 0);
+
+	do_commit(state);
+
+next:
+	am_next(state);
+	am_load(state);
+	am_run(state, 0);
+}
+
+/**
+ * Performs a checkout fast-forward from `head` to `remote`. If `reset` is
+ * true, any unmerged entries will be discarded. Returns 0 on success, -1 on
+ * failure.
+ */
+static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
+{
+	struct lock_file lock_file = LOCK_INIT;
+	struct unpack_trees_options opts;
+	struct tree_desc t[2];
+
+	if (parse_tree(head) || parse_tree(remote))
+		return -1;
+
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+
+	refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = 1;
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+	opts.update = 1;
+	opts.merge = 1;
+	opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
+	opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
+	opts.fn = twoway_merge;
+	init_tree_desc(&t[0], &head->object.oid, head->buffer, head->size);
+	init_tree_desc(&t[1], &remote->object.oid, remote->buffer, remote->size);
+
+	if (unpack_trees(2, t, &opts)) {
+		rollback_lock_file(&lock_file);
+		return -1;
+	}
+
+	if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+		die(_("unable to write new index file"));
+
+	return 0;
+}
+
+/**
+ * Merges a tree into the index. The index's stat info will take precedence
+ * over the merged tree's. Returns 0 on success, -1 on failure.
+ */
+static int merge_tree(struct tree *tree)
+{
+	struct lock_file lock_file = LOCK_INIT;
+	struct unpack_trees_options opts;
+	struct tree_desc t[1];
+
+	if (parse_tree(tree))
+		return -1;
+
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = 1;
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+	opts.merge = 1;
+	opts.fn = oneway_merge;
+	init_tree_desc(&t[0], &tree->object.oid, tree->buffer, tree->size);
+
+	if (unpack_trees(1, t, &opts)) {
+		rollback_lock_file(&lock_file);
+		return -1;
+	}
+
+	if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+		die(_("unable to write new index file"));
+
+	return 0;
+}
+
+/**
+ * Clean the index without touching entries that are not modified between
+ * `head` and `remote`.
+ */
+static int clean_index(const struct object_id *head, const struct object_id *remote)
+{
+	struct tree *head_tree, *remote_tree, *index_tree;
+	struct object_id index;
+
+	head_tree = parse_tree_indirect(head);
+	if (!head_tree)
+		return error(_("Could not parse object '%s'."), oid_to_hex(head));
+
+	remote_tree = parse_tree_indirect(remote);
+	if (!remote_tree)
+		return error(_("Could not parse object '%s'."), oid_to_hex(remote));
+
+	repo_read_index_unmerged(the_repository);
+
+	if (fast_forward_to(head_tree, head_tree, 1))
+		return -1;
+
+	if (write_index_as_tree(&index, the_repository->index,
+				repo_get_index_file(the_repository),
+				0, NULL))
+		return -1;
+
+	index_tree = parse_tree_indirect(&index);
+	if (!index_tree)
+		return error(_("Could not parse object '%s'."), oid_to_hex(&index));
+
+	if (fast_forward_to(index_tree, remote_tree, 0))
+		return -1;
+
+	if (merge_tree(remote_tree))
+		return -1;
+
+	remove_branch_state(the_repository, 0);
+
+	return 0;
+}
+
+/**
+ * Resets rerere's merge resolution metadata.
+ */
+static void am_rerere_clear(void)
+{
+	struct string_list merge_rr = STRING_LIST_INIT_DUP;
+	rerere_clear(the_repository, &merge_rr);
+	string_list_clear(&merge_rr, 1);
+}
+
+/**
+ * Resume the current am session by skipping the current patch.
+ */
+static void am_skip(struct am_state *state)
+{
+	struct object_id head;
+
+	am_rerere_clear();
+
+	if (repo_get_oid(the_repository, "HEAD", &head))
+		oidcpy(&head, the_hash_algo->empty_tree);
+
+	if (clean_index(&head, &head))
+		die(_("failed to clean index"));
+
+	if (state->rebasing) {
+		FILE *fp = xfopen(am_path(state, "rewritten"), "a");
+
+		assert(!is_null_oid(&state->orig_commit));
+		fprintf(fp, "%s ", oid_to_hex(&state->orig_commit));
+		fprintf(fp, "%s\n", oid_to_hex(&head));
+		fclose(fp);
+	}
+
+	am_next(state);
+	am_load(state);
+	am_run(state, 0);
+}
+
+/**
+ * Returns true if it is safe to reset HEAD to the ORIG_HEAD, false otherwise.
+ *
+ * It is not safe to reset HEAD when:
+ * 1. git-am previously failed because the index was dirty.
+ * 2. HEAD has moved since git-am previously failed.
+ */
+static int safe_to_abort(const struct am_state *state)
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct object_id abort_safety, head;
+
+	if (file_exists(am_path(state, "dirtyindex")))
+		return 0;
+
+	if (read_state_file(&sb, state, "abort-safety", 1) > 0) {
+		if (get_oid_hex(sb.buf, &abort_safety))
+			die(_("could not parse %s"), am_path(state, "abort-safety"));
+	} else
+		oidclr(&abort_safety, the_repository->hash_algo);
+	strbuf_release(&sb);
+
+	if (repo_get_oid(the_repository, "HEAD", &head))
+		oidclr(&head, the_repository->hash_algo);
+
+	if (oideq(&head, &abort_safety))
+		return 1;
+
+	warning(_("You seem to have moved HEAD since the last 'am' failure.\n"
+		"Not rewinding to ORIG_HEAD"));
+
+	return 0;
+}
+
+/**
+ * Aborts the current am session if it is safe to do so.
+ */
+static void am_abort(struct am_state *state)
+{
+	struct object_id curr_head, orig_head;
+	int has_curr_head, has_orig_head;
+	char *curr_branch;
+
+	if (!safe_to_abort(state)) {
+		am_destroy(state);
+		return;
+	}
+
+	am_rerere_clear();
+
+	curr_branch = refs_resolve_refdup(get_main_ref_store(the_repository),
+					  "HEAD", 0, &curr_head, NULL);
+	has_curr_head = curr_branch && !is_null_oid(&curr_head);
+	if (!has_curr_head)
+		oidcpy(&curr_head, the_hash_algo->empty_tree);
+
+	has_orig_head = !repo_get_oid(the_repository, "ORIG_HEAD", &orig_head);
+	if (!has_orig_head)
+		oidcpy(&orig_head, the_hash_algo->empty_tree);
+
+	if (clean_index(&curr_head, &orig_head))
+		die(_("failed to clean index"));
+
+	if (has_orig_head)
+		refs_update_ref(get_main_ref_store(the_repository),
+				"am --abort", "HEAD", &orig_head,
+				has_curr_head ? &curr_head : NULL, 0,
+				UPDATE_REFS_DIE_ON_ERR);
+	else if (curr_branch)
+		refs_delete_ref(get_main_ref_store(the_repository), NULL,
+				curr_branch, NULL, REF_NO_DEREF);
+
+	free(curr_branch);
+	am_destroy(state);
+}
+
+static int show_patch(struct am_state *state, enum resume_type resume_mode)
+{
+	struct strbuf sb = STRBUF_INIT;
+	const char *patch_path;
+	int len;
+
+	if (!is_null_oid(&state->orig_commit)) {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+
+		strvec_pushl(&cmd.args, "show", oid_to_hex(&state->orig_commit),
+			     "--", NULL);
+		cmd.git_cmd = 1;
+		return run_command(&cmd);
+	}
+
+	switch (resume_mode) {
+	case RESUME_SHOW_PATCH_RAW:
+		patch_path = am_path(state, msgnum(state));
+		break;
+	case RESUME_SHOW_PATCH_DIFF:
+		patch_path = am_path(state, "patch");
+		break;
+	default:
+		BUG("invalid mode for --show-current-patch");
+	}
+
+	len = strbuf_read_file(&sb, patch_path, 0);
+	if (len < 0)
+		die_errno(_("failed to read '%s'"), patch_path);
+
+	setup_pager(the_repository);
+	write_in_full(1, sb.buf, sb.len);
+	strbuf_release(&sb);
+	return 0;
+}
+
+/**
+ * parse_options() callback that validates and sets opt->value to the
+ * PATCH_FORMAT_* enum value corresponding to `arg`.
+ */
+static int parse_opt_patchformat(const struct option *opt, const char *arg, int unset)
+{
+	int *opt_value = opt->value;
+
+	if (unset)
+		*opt_value = PATCH_FORMAT_UNKNOWN;
+	else if (!strcmp(arg, "mbox"))
+		*opt_value = PATCH_FORMAT_MBOX;
+	else if (!strcmp(arg, "stgit"))
+		*opt_value = PATCH_FORMAT_STGIT;
+	else if (!strcmp(arg, "stgit-series"))
+		*opt_value = PATCH_FORMAT_STGIT_SERIES;
+	else if (!strcmp(arg, "hg"))
+		*opt_value = PATCH_FORMAT_HG;
+	else if (!strcmp(arg, "mboxrd"))
+		*opt_value = PATCH_FORMAT_MBOXRD;
+	/*
+	 * Please update $__git_patchformat in git-completion.bash
+	 * when you add new options
+	 */
+	else
+		return error(_("invalid value for '%s': '%s'"),
+			     "--patch-format", arg);
+	return 0;
+}
+
+static int parse_opt_show_current_patch(const struct option *opt, const char *arg, int unset)
+{
+	int *opt_value = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (!arg)
+		*opt_value = opt->defval;
+	else if (!strcmp(arg, "raw"))
+		*opt_value = RESUME_SHOW_PATCH_RAW;
+	else if (!strcmp(arg, "diff"))
+		*opt_value = RESUME_SHOW_PATCH_DIFF;
+	/*
+	 * Please update $__git_showcurrentpatch in git-completion.bash
+	 * when you add new options
+	 */
+	else
+		return error(_("invalid value for '%s': '%s'"),
+			     "--show-current-patch", arg);
+	return 0;
+}
+
+int cmd_am(int argc,
+	   const char **argv,
+	   const char *prefix,
+	   struct repository *repo UNUSED)
+{
+	struct am_state state;
+	int binary = -1;
+	int keep_cr = -1;
+	int patch_format = PATCH_FORMAT_UNKNOWN;
+	enum resume_type resume_mode = RESUME_FALSE;
+	int in_progress;
+	int ret = 0;
+
+	const char * const usage[] = {
+		N_("git am [<options>] [(<mbox> | <Maildir>)...]"),
+		N_("git am [<options>] (--continue | --skip | --abort)"),
+		NULL
+	};
+
+	struct option options[] = {
+		OPT_BOOL('i', "interactive", &state.interactive,
+			N_("run interactively")),
+		OPT_BOOL('n', "no-verify", &state.no_verify,
+			N_("bypass pre-applypatch and applypatch-msg hooks")),
+		OPT_HIDDEN_BOOL('b', "binary", &binary,
+			N_("historical option -- no-op")),
+		OPT_BOOL('3', "3way", &state.threeway,
+			N_("allow fall back on 3way merging if needed")),
+		OPT__QUIET(&state.quiet, N_("be quiet")),
+		OPT_SET_INT('s', "signoff", &state.signoff,
+			N_("add a Signed-off-by trailer to the commit message"),
+			SIGNOFF_EXPLICIT),
+		OPT_BOOL('u', "utf8", &state.utf8,
+			N_("recode into utf8 (default)")),
+		OPT_SET_INT('k', "keep", &state.keep,
+			N_("pass -k flag to git-mailinfo"), KEEP_TRUE),
+		OPT_SET_INT(0, "keep-non-patch", &state.keep,
+			N_("pass -b flag to git-mailinfo"), KEEP_NON_PATCH),
+		OPT_BOOL('m', "message-id", &state.message_id,
+			N_("pass -m flag to git-mailinfo")),
+		OPT_SET_INT(0, "keep-cr", &keep_cr,
+			    N_("pass --keep-cr flag to git-mailsplit for mbox format"),
+			    1),
+		OPT_BOOL('c', "scissors", &state.scissors,
+			N_("strip everything before a scissors line")),
+		OPT_CALLBACK_F(0, "quoted-cr", &state.quoted_cr, N_("action"),
+			       N_("pass it through git-mailinfo"),
+			       PARSE_OPT_NONEG, am_option_parse_quoted_cr),
+		OPT_PASSTHRU_ARGV(0, "whitespace", &state.git_apply_opts, N_("action"),
+			N_("pass it through git-apply"),
+			0),
+		OPT_PASSTHRU_ARGV(0, "ignore-space-change", &state.git_apply_opts, NULL,
+			N_("pass it through git-apply"),
+			PARSE_OPT_NOARG),
+		OPT_PASSTHRU_ARGV(0, "ignore-whitespace", &state.git_apply_opts, NULL,
+			N_("pass it through git-apply"),
+			PARSE_OPT_NOARG),
+		OPT_PASSTHRU_ARGV(0, "directory", &state.git_apply_opts, N_("root"),
+			N_("pass it through git-apply"),
+			0),
+		OPT_PASSTHRU_ARGV(0, "exclude", &state.git_apply_opts, N_("path"),
+			N_("pass it through git-apply"),
+			0),
+		OPT_PASSTHRU_ARGV(0, "include", &state.git_apply_opts, N_("path"),
+			N_("pass it through git-apply"),
+			0),
+		OPT_PASSTHRU_ARGV('C', NULL, &state.git_apply_opts, N_("n"),
+			N_("pass it through git-apply"),
+			0),
+		OPT_PASSTHRU_ARGV('p', NULL, &state.git_apply_opts, N_("num"),
+			N_("pass it through git-apply"),
+			0),
+		OPT_CALLBACK(0, "patch-format", &patch_format, N_("format"),
+			N_("format the patch(es) are in"),
+			parse_opt_patchformat),
+		OPT_PASSTHRU_ARGV(0, "reject", &state.git_apply_opts, NULL,
+			N_("pass it through git-apply"),
+			PARSE_OPT_NOARG),
+		OPT_STRING(0, "resolvemsg", &state.resolvemsg, NULL,
+			N_("override error message when patch failure occurs")),
+		OPT_CMDMODE(0, "continue", &resume_mode,
+			N_("continue applying patches after resolving a conflict"),
+			RESUME_RESOLVED),
+		OPT_CMDMODE('r', "resolved", &resume_mode,
+			N_("synonyms for --continue"),
+			RESUME_RESOLVED),
+		OPT_CMDMODE(0, "skip", &resume_mode,
+			N_("skip the current patch"),
+			RESUME_SKIP),
+		OPT_CMDMODE(0, "abort", &resume_mode,
+			N_("restore the original branch and abort the patching operation"),
+			RESUME_ABORT),
+		OPT_CMDMODE(0, "quit", &resume_mode,
+			N_("abort the patching operation but keep HEAD where it is"),
+			RESUME_QUIT),
+		{ OPTION_CALLBACK, 0, "show-current-patch", &resume_mode,
+		  "(diff|raw)",
+		  N_("show the patch being applied"),
+		  PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
+		  parse_opt_show_current_patch, RESUME_SHOW_PATCH_RAW },
+		OPT_CMDMODE(0, "retry", &resume_mode,
+			N_("try to apply current patch again"),
+			RESUME_APPLY),
+		OPT_CMDMODE(0, "allow-empty", &resume_mode,
+			N_("record the empty patch as an empty commit"),
+			RESUME_ALLOW_EMPTY),
+		OPT_BOOL(0, "committer-date-is-author-date",
+			&state.committer_date_is_author_date,
+			N_("lie about committer date")),
+		OPT_BOOL(0, "ignore-date", &state.ignore_date,
+			N_("use current timestamp for author date")),
+		OPT_RERERE_AUTOUPDATE(&state.allow_rerere_autoupdate),
+		{ OPTION_STRING, 'S', "gpg-sign", &state.sign_commit, N_("key-id"),
+		  N_("GPG-sign commits"),
+		  PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+		OPT_CALLBACK_F(0, "empty", &state.empty_type, "(stop|drop|keep)",
+		  N_("how to handle empty patches"),
+		  PARSE_OPT_NONEG, am_option_parse_empty),
+		OPT_HIDDEN_BOOL(0, "rebasing", &state.rebasing,
+			N_("(internal use for git-rebase)")),
+		OPT_END()
+	};
+
+	show_usage_with_options_if_asked(argc, argv, usage, options);
+
+	git_config(git_default_config, NULL);
+
+	am_state_init(&state);
+
+	in_progress = am_in_progress(&state);
+	if (in_progress)
+		am_load(&state);
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+	if (binary >= 0)
+		fprintf_ln(stderr, _("The -b/--binary option has been a no-op for long time, and\n"
+				"it will be removed. Please do not use it anymore."));
+
+	/* Ensure a valid committer ident can be constructed */
+	git_committer_info(IDENT_STRICT);
+
+	if (repo_read_index_preload(the_repository, NULL, 0) < 0)
+		die(_("failed to read the index"));
+
+	if (in_progress) {
+		/*
+		 * Catch user error to feed us patches when there is a session
+		 * in progress:
+		 *
+		 * 1. mbox path(s) are provided on the command-line.
+		 * 2. stdin is not a tty: the user is trying to feed us a patch
+		 *    from standard input. This is somewhat unreliable -- stdin
+		 *    could be /dev/null for example and the caller did not
+		 *    intend to feed us a patch but wanted to continue
+		 *    unattended.
+		 */
+		if (argc || (resume_mode == RESUME_FALSE && !isatty(0)))
+			die(_("previous rebase directory %s still exists but mbox given."),
+				state.dir);
+
+		if (resume_mode == RESUME_FALSE)
+			resume_mode = RESUME_APPLY;
+
+		if (state.signoff == SIGNOFF_EXPLICIT)
+			am_append_signoff(&state);
+	} else {
+		struct strvec paths = STRVEC_INIT;
+		int i;
+
+		/*
+		 * Handle stray state directory in the independent-run case. In
+		 * the --rebasing case, it is up to the caller to take care of
+		 * stray directories.
+		 */
+		if (file_exists(state.dir) && !state.rebasing) {
+			if (resume_mode == RESUME_ABORT || resume_mode == RESUME_QUIT) {
+				am_destroy(&state);
+				am_state_release(&state);
+				return 0;
+			}
+
+			die(_("Stray %s directory found.\n"
+				"Use \"git am --abort\" to remove it."),
+				state.dir);
+		}
+
+		if (resume_mode)
+			die(_("Resolve operation not in progress, we are not resuming."));
+
+		for (i = 0; i < argc; i++) {
+			if (is_absolute_path(argv[i]) || !prefix)
+				strvec_push(&paths, argv[i]);
+			else
+				strvec_push(&paths, mkpath("%s/%s", prefix, argv[i]));
+		}
+
+		if (state.interactive && !paths.nr)
+			die(_("interactive mode requires patches on the command line"));
+
+		am_setup(&state, patch_format, paths.v, keep_cr);
+
+		strvec_clear(&paths);
+	}
+
+	switch (resume_mode) {
+	case RESUME_FALSE:
+		am_run(&state, 0);
+		break;
+	case RESUME_APPLY:
+		am_run(&state, 1);
+		break;
+	case RESUME_RESOLVED:
+	case RESUME_ALLOW_EMPTY:
+		am_resolve(&state, resume_mode == RESUME_ALLOW_EMPTY ? 1 : 0);
+		break;
+	case RESUME_SKIP:
+		am_skip(&state);
+		break;
+	case RESUME_ABORT:
+		am_abort(&state);
+		break;
+	case RESUME_QUIT:
+		am_rerere_clear();
+		am_destroy(&state);
+		break;
+	case RESUME_SHOW_PATCH_RAW:
+	case RESUME_SHOW_PATCH_DIFF:
+		ret = show_patch(&state, resume_mode);
+		break;
+	default:
+		BUG("invalid resume value");
+	}
+
+	am_state_release(&state);
+
+	return ret;
+}
diff --git a/builtin/annotate.c b/builtin/annotate.c
new file mode 100644
index 0000000000..7f754f2309
--- /dev/null
+++ b/builtin/annotate.c
@@ -0,0 +1,36 @@
+/*
+ * "git annotate" builtin alias
+ *
+ * Copyright (C) 2006 Ryan Anderson
+ */
+
+#include "git-compat-util.h"
+#include "builtin.h"
+#include "strvec.h"
+
+int cmd_annotate(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo)
+{
+	struct strvec args = STRVEC_INIT;
+	const char **args_copy;
+	int ret;
+
+	strvec_pushl(&args, "annotate", "-c", NULL);
+	for (int i = 1; i < argc; i++)
+		strvec_push(&args, argv[i]);
+
+	/*
+	 * `cmd_blame()` ends up modifying the array, which causes memory leaks
+	 * if we didn't copy the array here.
+	 */
+	CALLOC_ARRAY(args_copy, args.nr + 1);
+	COPY_ARRAY(args_copy, args.v, args.nr);
+
+	ret = cmd_blame(args.nr, args_copy, prefix, repo);
+
+	strvec_clear(&args);
+	free(args_copy);
+	return ret;
+}
diff --git a/builtin/apply.c b/builtin/apply.c
new file mode 100644
index 0000000000..84f1863d3a
--- /dev/null
+++ b/builtin/apply.c
@@ -0,0 +1,46 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "gettext.h"
+#include "hash.h"
+#include "apply.h"
+
+static const char * const apply_usage[] = {
+	N_("git apply [<options>] [<patch>...]"),
+	NULL
+};
+
+int cmd_apply(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	int force_apply = 0;
+	int options = 0;
+	int ret;
+	struct apply_state state;
+
+	if (init_apply_state(&state, the_repository, prefix))
+		exit(128);
+
+	/*
+	 * We could to redo the "apply.c" machinery to make this
+	 * arbitrary fallback unnecessary, but it is dubious that it
+	 * is worth the effort.
+	 * cf. https://lore.kernel.org/git/xmqqcypfcmn4.fsf@gitster.g/
+	 */
+	if (!the_hash_algo)
+		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
+	argc = apply_parse_options(argc, argv,
+				   &state, &force_apply, &options,
+				   apply_usage);
+
+	if (check_apply_state(&state, force_apply))
+		exit(128);
+
+	ret = apply_all_patches(&state, argc, argv, options);
+
+	clear_apply_state(&state);
+
+	return ret;
+}
diff --git a/builtin/archive.c b/builtin/archive.c
new file mode 100644
index 0000000000..13ea7308c8
--- /dev/null
+++ b/builtin/archive.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2006 Franck Bui-Huu
+ * Copyright (c) 2006 Rene Scharfe
+ */
+#include "builtin.h"
+#include "archive.h"
+#include "gettext.h"
+#include "transport.h"
+#include "parse-options.h"
+#include "pkt-line.h"
+
+static void create_output_file(const char *output_file)
+{
+	int output_fd = xopen(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
+	if (output_fd != 1) {
+		if (dup2(output_fd, 1) < 0)
+			die_errno(_("could not redirect output"));
+		else
+			close(output_fd);
+	}
+}
+
+static int run_remote_archiver(int argc, const char **argv,
+			       const char *remote, const char *exec,
+			       const char *name_hint)
+{
+	int fd[2], i, rv;
+	struct transport *transport;
+	struct remote *_remote;
+	struct packet_reader reader;
+
+	_remote = remote_get(remote);
+	transport = transport_get(_remote, _remote->url.v[0]);
+	transport_connect(transport, "git-upload-archive", exec, fd);
+
+	/*
+	 * Inject a fake --format field at the beginning of the
+	 * arguments, with the format inferred from our output
+	 * filename. This way explicit --format options can override
+	 * it.
+	 */
+	if (name_hint) {
+		const char *format = archive_format_from_filename(name_hint);
+		if (format)
+			packet_write_fmt(fd[1], "argument --format=%s\n", format);
+	}
+	for (i = 1; i < argc; i++)
+		packet_write_fmt(fd[1], "argument %s\n", argv[i]);
+	packet_flush(fd[1]);
+
+	packet_reader_init(&reader, fd[0], NULL, 0,
+			   PACKET_READ_CHOMP_NEWLINE |
+			   PACKET_READ_DIE_ON_ERR_PACKET);
+
+	if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
+		die(_("git archive: expected ACK/NAK, got a flush packet"));
+	if (strcmp(reader.line, "ACK")) {
+		if (starts_with(reader.line, "NACK "))
+			die(_("git archive: NACK %s"), reader.line + 5);
+		die(_("git archive: protocol error"));
+	}
+
+	if (packet_reader_read(&reader) != PACKET_READ_FLUSH)
+		die(_("git archive: expected a flush"));
+
+	/* Now, start reading from fd[0] and spit it out to stdout */
+	rv = recv_sideband("archive", fd[0], 1);
+	rv |= transport_disconnect(transport);
+
+	return !!rv;
+}
+
+#define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH | 	\
+			     PARSE_OPT_KEEP_ARGV0 | 	\
+			     PARSE_OPT_KEEP_UNKNOWN_OPT |	\
+			     PARSE_OPT_NO_INTERNAL_HELP	)
+
+int cmd_archive(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo)
+{
+	const char *exec = "git-upload-archive";
+	char *output = NULL;
+	const char *remote = NULL;
+	struct option local_opts[] = {
+		OPT_FILENAME('o', "output", &output,
+			     N_("write the archive to this file")),
+		OPT_STRING(0, "remote", &remote, N_("repo"),
+			N_("retrieve the archive from remote repository <repo>")),
+		OPT_STRING(0, "exec", &exec, N_("command"),
+			N_("path to the remote git-upload-archive command")),
+		OPT_END()
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, local_opts, NULL,
+			     PARSE_OPT_KEEP_ALL);
+
+	init_archivers();
+
+	if (output)
+		create_output_file(output);
+
+	if (remote) {
+		ret = run_remote_archiver(argc, argv, remote, exec, output);
+		goto out;
+	}
+
+	setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
+
+	ret = write_archive(argc, argv, prefix, repo, output, 0);
+
+out:
+	free(output);
+	return ret;
+}
diff --git a/builtin/bisect.c b/builtin/bisect.c
new file mode 100644
index 0000000000..8b8d870cd1
--- /dev/null
+++ b/builtin/bisect.c
@@ -0,0 +1,1470 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "bisect.h"
+#include "refs.h"
+#include "strvec.h"
+#include "run-command.h"
+#include "oid-array.h"
+#include "path.h"
+#include "prompt.h"
+#include "quote.h"
+#include "revision.h"
+
+static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
+static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
+static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
+static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
+static GIT_PATH_FUNC(git_path_bisect_first_parent, "BISECT_FIRST_PARENT")
+static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
+
+#define BUILTIN_GIT_BISECT_START_USAGE \
+	N_("git bisect start [--term-(new|bad)=<term> --term-(old|good)=<term>]" \
+	   "    [--no-checkout] [--first-parent] [<bad> [<good>...]] [--]" \
+	   "    [<pathspec>...]")
+#define BUILTIN_GIT_BISECT_STATE_USAGE \
+	N_("git bisect (good|bad) [<rev>...]")
+#define BUILTIN_GIT_BISECT_TERMS_USAGE \
+	"git bisect terms [--term-good | --term-bad]"
+#define BUILTIN_GIT_BISECT_SKIP_USAGE \
+	N_("git bisect skip [(<rev>|<range>)...]")
+#define BUILTIN_GIT_BISECT_NEXT_USAGE \
+	"git bisect next"
+#define BUILTIN_GIT_BISECT_RESET_USAGE \
+	N_("git bisect reset [<commit>]")
+#define BUILTIN_GIT_BISECT_VISUALIZE_USAGE \
+	"git bisect visualize"
+#define BUILTIN_GIT_BISECT_REPLAY_USAGE \
+	N_("git bisect replay <logfile>")
+#define BUILTIN_GIT_BISECT_LOG_USAGE \
+	"git bisect log"
+#define BUILTIN_GIT_BISECT_RUN_USAGE \
+	N_("git bisect run <cmd> [<arg>...]")
+
+static const char * const git_bisect_usage[] = {
+	BUILTIN_GIT_BISECT_START_USAGE,
+	BUILTIN_GIT_BISECT_STATE_USAGE,
+	BUILTIN_GIT_BISECT_TERMS_USAGE,
+	BUILTIN_GIT_BISECT_SKIP_USAGE,
+	BUILTIN_GIT_BISECT_NEXT_USAGE,
+	BUILTIN_GIT_BISECT_RESET_USAGE,
+	BUILTIN_GIT_BISECT_VISUALIZE_USAGE,
+	BUILTIN_GIT_BISECT_REPLAY_USAGE,
+	BUILTIN_GIT_BISECT_LOG_USAGE,
+	BUILTIN_GIT_BISECT_RUN_USAGE,
+	NULL
+};
+
+struct add_bisect_ref_data {
+	struct rev_info *revs;
+	unsigned int object_flags;
+};
+
+struct bisect_terms {
+	char *term_good;
+	char *term_bad;
+};
+
+static void free_terms(struct bisect_terms *terms)
+{
+	FREE_AND_NULL(terms->term_good);
+	FREE_AND_NULL(terms->term_bad);
+}
+
+static void set_terms(struct bisect_terms *terms, const char *bad,
+		      const char *good)
+{
+	free((void *)terms->term_good);
+	terms->term_good = xstrdup(good);
+	free((void *)terms->term_bad);
+	terms->term_bad = xstrdup(bad);
+}
+
+static const char vocab_bad[] = "bad|new";
+static const char vocab_good[] = "good|old";
+
+static int bisect_autostart(struct bisect_terms *terms);
+
+/*
+ * Check whether the string `term` belongs to the set of strings
+ * included in the variable arguments.
+ */
+LAST_ARG_MUST_BE_NULL
+static int one_of(const char *term, ...)
+{
+	int res = 0;
+	va_list matches;
+	const char *match;
+
+	va_start(matches, term);
+	while (!res && (match = va_arg(matches, const char *)))
+		res = !strcmp(term, match);
+	va_end(matches);
+
+	return res;
+}
+
+/*
+ * return code BISECT_INTERNAL_SUCCESS_MERGE_BASE
+ * and BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND are codes
+ * that indicate special success.
+ */
+
+static int is_bisect_success(enum bisect_error res)
+{
+	return !res ||
+		res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND ||
+		res == BISECT_INTERNAL_SUCCESS_MERGE_BASE;
+}
+
+static int write_in_file(const char *path, const char *mode, const char *format, va_list args)
+{
+	FILE *fp = NULL;
+	int res = 0;
+
+	if (strcmp(mode, "w") && strcmp(mode, "a"))
+		BUG("write-in-file does not support '%s' mode", mode);
+	fp = fopen(path, mode);
+	if (!fp)
+		return error_errno(_("cannot open file '%s' in mode '%s'"), path, mode);
+	res = vfprintf(fp, format, args);
+
+	if (res < 0) {
+		int saved_errno = errno;
+		fclose(fp);
+		errno = saved_errno;
+		return error_errno(_("could not write to file '%s'"), path);
+	}
+
+	return fclose(fp);
+}
+
+__attribute__((format (printf, 2, 3)))
+static int write_to_file(const char *path, const char *format, ...)
+{
+	int res;
+	va_list args;
+
+	va_start(args, format);
+	res = write_in_file(path, "w", format, args);
+	va_end(args);
+
+	return res;
+}
+
+__attribute__((format (printf, 2, 3)))
+static int append_to_file(const char *path, const char *format, ...)
+{
+	int res;
+	va_list args;
+
+	va_start(args, format);
+	res = write_in_file(path, "a", format, args);
+	va_end(args);
+
+	return res;
+}
+
+static int print_file_to_stdout(const char *path)
+{
+	int fd = open(path, O_RDONLY);
+	int ret = 0;
+
+	if (fd < 0)
+		return error_errno(_("cannot open file '%s' for reading"), path);
+	if (copy_fd(fd, 1) < 0)
+		ret = error_errno(_("failed to read '%s'"), path);
+	close(fd);
+	return ret;
+}
+
+static int check_term_format(const char *term, const char *orig_term)
+{
+	int res;
+	char *new_term = xstrfmt("refs/bisect/%s", term);
+
+	res = check_refname_format(new_term, 0);
+	free(new_term);
+
+	if (res)
+		return error(_("'%s' is not a valid term"), term);
+
+	if (one_of(term, "help", "start", "skip", "next", "reset",
+			"visualize", "view", "replay", "log", "run", "terms", NULL))
+		return error(_("can't use the builtin command '%s' as a term"), term);
+
+	/*
+	 * In theory, nothing prevents swapping completely good and bad,
+	 * but this situation could be confusing and hasn't been tested
+	 * enough. Forbid it for now.
+	 */
+
+	if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
+		 (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
+		return error(_("can't change the meaning of the term '%s'"), term);
+
+	return 0;
+}
+
+static int write_terms(const char *bad, const char *good)
+{
+	int res;
+
+	if (!strcmp(bad, good))
+		return error(_("please use two different terms"));
+
+	if (check_term_format(bad, "bad") || check_term_format(good, "good"))
+		return -1;
+
+	res = write_to_file(git_path_bisect_terms(), "%s\n%s\n", bad, good);
+
+	return res;
+}
+
+static int bisect_reset(const char *commit)
+{
+	struct strbuf branch = STRBUF_INIT;
+
+	if (!commit) {
+		if (!strbuf_read_file(&branch, git_path_bisect_start(), 0))
+			printf(_("We are not bisecting.\n"));
+		else
+			strbuf_rtrim(&branch);
+	} else {
+		struct object_id oid;
+
+		if (repo_get_oid_commit(the_repository, commit, &oid))
+			return error(_("'%s' is not a valid commit"), commit);
+		strbuf_addstr(&branch, commit);
+	}
+
+	if (branch.len && !refs_ref_exists(get_main_ref_store(the_repository), "BISECT_HEAD")) {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+
+		cmd.git_cmd = 1;
+		strvec_pushl(&cmd.args, "checkout", "--ignore-other-worktrees",
+				branch.buf, "--", NULL);
+		if (run_command(&cmd)) {
+			error(_("could not check out original"
+				" HEAD '%s'. Try 'git bisect"
+				" reset <commit>'."), branch.buf);
+			strbuf_release(&branch);
+			return -1;
+		}
+	}
+
+	strbuf_release(&branch);
+	return bisect_clean_state();
+}
+
+static void log_commit(FILE *fp,
+		       const char *fmt, const char *state,
+		       struct commit *commit)
+{
+	struct pretty_print_context pp = {0};
+	struct strbuf commit_msg = STRBUF_INIT;
+	char *label = xstrfmt(fmt, state);
+
+	repo_format_commit_message(the_repository, commit, "%s", &commit_msg,
+				   &pp);
+
+	fprintf(fp, "# %s: [%s] %s\n", label, oid_to_hex(&commit->object.oid),
+		commit_msg.buf);
+
+	strbuf_release(&commit_msg);
+	free(label);
+}
+
+static int bisect_write(const char *state, const char *rev,
+			const struct bisect_terms *terms, int nolog)
+{
+	struct strbuf tag = STRBUF_INIT;
+	struct object_id oid;
+	struct commit *commit;
+	FILE *fp = NULL;
+	int res = 0;
+
+	if (!strcmp(state, terms->term_bad)) {
+		strbuf_addf(&tag, "refs/bisect/%s", state);
+	} else if (one_of(state, terms->term_good, "skip", NULL)) {
+		strbuf_addf(&tag, "refs/bisect/%s-%s", state, rev);
+	} else {
+		res = error(_("Bad bisect_write argument: %s"), state);
+		goto finish;
+	}
+
+	if (repo_get_oid(the_repository, rev, &oid)) {
+		res = error(_("couldn't get the oid of the rev '%s'"), rev);
+		goto finish;
+	}
+
+	if (refs_update_ref(get_main_ref_store(the_repository), NULL, tag.buf, &oid, NULL, 0,
+			    UPDATE_REFS_MSG_ON_ERR)) {
+		res = -1;
+		goto finish;
+	}
+
+	fp = fopen(git_path_bisect_log(), "a");
+	if (!fp) {
+		res = error_errno(_("couldn't open the file '%s'"), git_path_bisect_log());
+		goto finish;
+	}
+
+	commit = lookup_commit_reference(the_repository, &oid);
+	log_commit(fp, "%s", state, commit);
+
+	if (!nolog)
+		fprintf(fp, "git bisect %s %s\n", state, rev);
+
+finish:
+	if (fp)
+		fclose(fp);
+	strbuf_release(&tag);
+	return res;
+}
+
+static int check_and_set_terms(struct bisect_terms *terms, const char *cmd)
+{
+	int has_term_file = !is_empty_or_missing_file(git_path_bisect_terms());
+
+	if (one_of(cmd, "skip", "start", "terms", NULL))
+		return 0;
+
+	if (has_term_file && strcmp(cmd, terms->term_bad) &&
+	    strcmp(cmd, terms->term_good))
+		return error(_("Invalid command: you're currently in a "
+				"%s/%s bisect"), terms->term_bad,
+				terms->term_good);
+
+	if (!has_term_file) {
+		if (one_of(cmd, "bad", "good", NULL)) {
+			set_terms(terms, "bad", "good");
+			return write_terms(terms->term_bad, terms->term_good);
+		}
+		if (one_of(cmd, "new", "old", NULL)) {
+			set_terms(terms, "new", "old");
+			return write_terms(terms->term_bad, terms->term_good);
+		}
+	}
+
+	return 0;
+}
+
+static int inc_nr(const char *refname UNUSED,
+		  const char *referent UNUSED,
+		  const struct object_id *oid UNUSED,
+		  int flag UNUSED, void *cb_data)
+{
+	unsigned int *nr = (unsigned int *)cb_data;
+	(*nr)++;
+	return 0;
+}
+
+static const char need_bad_and_good_revision_warning[] =
+	N_("You need to give me at least one %s and %s revision.\n"
+	   "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
+
+static const char need_bisect_start_warning[] =
+	N_("You need to start by \"git bisect start\".\n"
+	   "You then need to give me at least one %s and %s revision.\n"
+	   "You can use \"git bisect %s\" and \"git bisect %s\" for that.");
+
+static int decide_next(const struct bisect_terms *terms,
+		       const char *current_term, int missing_good,
+		       int missing_bad)
+{
+	if (!missing_good && !missing_bad)
+		return 0;
+	if (!current_term)
+		return -1;
+
+	if (missing_good && !missing_bad &&
+	    !strcmp(current_term, terms->term_good)) {
+		char *yesno;
+		/*
+		 * have bad (or new) but not good (or old). We could bisect
+		 * although this is less optimum.
+		 */
+		warning(_("bisecting only with a %s commit"), terms->term_bad);
+		if (!isatty(0))
+			return 0;
+		/*
+		 * TRANSLATORS: Make sure to include [Y] and [n] in your
+		 * translation. The program will only accept English input
+		 * at this point.
+		 */
+		yesno = git_prompt(_("Are you sure [Y/n]? "), PROMPT_ECHO);
+		if (starts_with(yesno, "N") || starts_with(yesno, "n"))
+			return -1;
+		return 0;
+	}
+
+	if (!is_empty_or_missing_file(git_path_bisect_start()))
+		return error(_(need_bad_and_good_revision_warning),
+			     vocab_bad, vocab_good, vocab_bad, vocab_good);
+	else
+		return error(_(need_bisect_start_warning),
+			     vocab_good, vocab_bad, vocab_good, vocab_bad);
+}
+
+static void bisect_status(struct bisect_state *state,
+			  const struct bisect_terms *terms)
+{
+	char *bad_ref = xstrfmt("refs/bisect/%s", terms->term_bad);
+	char *good_glob = xstrfmt("%s-*", terms->term_good);
+
+	if (refs_ref_exists(get_main_ref_store(the_repository), bad_ref))
+		state->nr_bad = 1;
+
+	refs_for_each_glob_ref_in(get_main_ref_store(the_repository), inc_nr,
+				  good_glob, "refs/bisect/",
+				  (void *) &state->nr_good);
+
+	free(good_glob);
+	free(bad_ref);
+}
+
+__attribute__((format (printf, 1, 2)))
+static void bisect_log_printf(const char *fmt, ...)
+{
+	struct strbuf buf = STRBUF_INIT;
+	va_list ap;
+
+	va_start(ap, fmt);
+	strbuf_vaddf(&buf, fmt, ap);
+	va_end(ap);
+
+	printf("%s", buf.buf);
+	append_to_file(git_path_bisect_log(), "# %s", buf.buf);
+
+	strbuf_release(&buf);
+}
+
+static void bisect_print_status(const struct bisect_terms *terms)
+{
+	struct bisect_state state = { 0 };
+
+	bisect_status(&state, terms);
+
+	/* If we had both, we'd already be started, and shouldn't get here. */
+	if (state.nr_good && state.nr_bad)
+		return;
+
+	if (!state.nr_good && !state.nr_bad)
+		bisect_log_printf(_("status: waiting for both good and bad commits\n"));
+	else if (state.nr_good)
+		bisect_log_printf(Q_("status: waiting for bad commit, %d good commit known\n",
+				     "status: waiting for bad commit, %d good commits known\n",
+				     state.nr_good), state.nr_good);
+	else
+		bisect_log_printf(_("status: waiting for good commit(s), bad commit known\n"));
+}
+
+static int bisect_next_check(const struct bisect_terms *terms,
+			     const char *current_term)
+{
+	struct bisect_state state = { 0 };
+	bisect_status(&state, terms);
+	return decide_next(terms, current_term, !state.nr_good, !state.nr_bad);
+}
+
+static int get_terms(struct bisect_terms *terms)
+{
+	struct strbuf str = STRBUF_INIT;
+	FILE *fp = NULL;
+	int res = 0;
+
+	fp = fopen(git_path_bisect_terms(), "r");
+	if (!fp) {
+		res = -1;
+		goto finish;
+	}
+
+	free_terms(terms);
+	strbuf_getline_lf(&str, fp);
+	terms->term_bad = strbuf_detach(&str, NULL);
+	strbuf_getline_lf(&str, fp);
+	terms->term_good = strbuf_detach(&str, NULL);
+
+finish:
+	if (fp)
+		fclose(fp);
+	strbuf_release(&str);
+	return res;
+}
+
+static int bisect_terms(struct bisect_terms *terms, const char *option)
+{
+	if (get_terms(terms))
+		return error(_("no terms defined"));
+
+	if (!option) {
+		printf(_("Your current terms are %s for the old state\n"
+			 "and %s for the new state.\n"),
+		       terms->term_good, terms->term_bad);
+		return 0;
+	}
+	if (one_of(option, "--term-good", "--term-old", NULL))
+		printf("%s\n", terms->term_good);
+	else if (one_of(option, "--term-bad", "--term-new", NULL))
+		printf("%s\n", terms->term_bad);
+	else
+		return error(_("invalid argument %s for 'git bisect terms'.\n"
+			       "Supported options are: "
+			       "--term-good|--term-old and "
+			       "--term-bad|--term-new."), option);
+
+	return 0;
+}
+
+static int bisect_append_log_quoted(const char **argv)
+{
+	int res = 0;
+	FILE *fp = fopen(git_path_bisect_log(), "a");
+	struct strbuf orig_args = STRBUF_INIT;
+
+	if (!fp)
+		return -1;
+
+	if (fprintf(fp, "git bisect start") < 1) {
+		res = -1;
+		goto finish;
+	}
+
+	sq_quote_argv(&orig_args, argv);
+	if (fprintf(fp, "%s\n", orig_args.buf) < 1)
+		res = -1;
+
+finish:
+	fclose(fp);
+	strbuf_release(&orig_args);
+	return res;
+}
+
+static int add_bisect_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+			  int flags UNUSED, void *cb)
+{
+	struct add_bisect_ref_data *data = cb;
+
+	add_pending_oid(data->revs, refname, oid, data->object_flags);
+
+	return 0;
+}
+
+static int prepare_revs(struct bisect_terms *terms, struct rev_info *revs)
+{
+	int res = 0;
+	struct add_bisect_ref_data cb = { revs };
+	char *good = xstrfmt("%s-*", terms->term_good);
+
+	/*
+	 * We cannot use terms->term_bad directly in
+	 * for_each_glob_ref_in() and we have to append a '*' to it,
+	 * otherwise for_each_glob_ref_in() will append '/' and '*'.
+	 */
+	char *bad = xstrfmt("%s*", terms->term_bad);
+
+	/*
+	 * It is important to reset the flags used by revision walks
+	 * as the previous call to bisect_next_all() in turn
+	 * sets up a revision walk.
+	 */
+	reset_revision_walk();
+	repo_init_revisions(the_repository, revs, NULL);
+	setup_revisions(0, NULL, revs, NULL);
+	refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+				  add_bisect_ref, bad, "refs/bisect/", &cb);
+	cb.object_flags = UNINTERESTING;
+	refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+				  add_bisect_ref, good, "refs/bisect/", &cb);
+	if (prepare_revision_walk(revs))
+		res = error(_("revision walk setup failed"));
+
+	free(good);
+	free(bad);
+	return res;
+}
+
+static int bisect_skipped_commits(struct bisect_terms *terms)
+{
+	int res;
+	FILE *fp = NULL;
+	struct rev_info revs;
+	struct commit *commit;
+	struct pretty_print_context pp = {0};
+	struct strbuf commit_name = STRBUF_INIT;
+
+	res = prepare_revs(terms, &revs);
+	if (res)
+		return res;
+
+	fp = fopen(git_path_bisect_log(), "a");
+	if (!fp)
+		return error_errno(_("could not open '%s' for appending"),
+				  git_path_bisect_log());
+
+	if (fprintf(fp, "# only skipped commits left to test\n") < 0)
+		return error_errno(_("failed to write to '%s'"), git_path_bisect_log());
+
+	while ((commit = get_revision(&revs)) != NULL) {
+		strbuf_reset(&commit_name);
+		repo_format_commit_message(the_repository, commit, "%s",
+					   &commit_name, &pp);
+		fprintf(fp, "# possible first %s commit: [%s] %s\n",
+			terms->term_bad, oid_to_hex(&commit->object.oid),
+			commit_name.buf);
+	}
+
+	/*
+	 * Reset the flags used by revision walks in case
+	 * there is another revision walk after this one.
+	 */
+	reset_revision_walk();
+
+	strbuf_release(&commit_name);
+	release_revisions(&revs);
+	fclose(fp);
+	return 0;
+}
+
+static int bisect_successful(struct bisect_terms *terms)
+{
+	struct object_id oid;
+	struct commit *commit;
+	struct pretty_print_context pp = {0};
+	struct strbuf commit_name = STRBUF_INIT;
+	char *bad_ref = xstrfmt("refs/bisect/%s",terms->term_bad);
+	int res;
+
+	refs_read_ref(get_main_ref_store(the_repository), bad_ref, &oid);
+	commit = lookup_commit_reference_by_name(bad_ref);
+	repo_format_commit_message(the_repository, commit, "%s", &commit_name,
+				   &pp);
+
+	res = append_to_file(git_path_bisect_log(), "# first %s commit: [%s] %s\n",
+			    terms->term_bad, oid_to_hex(&commit->object.oid),
+			    commit_name.buf);
+
+	strbuf_release(&commit_name);
+	free(bad_ref);
+	return res;
+}
+
+static enum bisect_error bisect_next(struct bisect_terms *terms, const char *prefix)
+{
+	enum bisect_error res;
+
+	if (bisect_autostart(terms))
+		return BISECT_FAILED;
+
+	if (bisect_next_check(terms, terms->term_good))
+		return BISECT_FAILED;
+
+	/* Perform all bisection computation */
+	res = bisect_next_all(the_repository, prefix);
+
+	if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
+		res = bisect_successful(terms);
+		return res ? res : BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND;
+	} else if (res == BISECT_ONLY_SKIPPED_LEFT) {
+		res = bisect_skipped_commits(terms);
+		return res ? res : BISECT_ONLY_SKIPPED_LEFT;
+	}
+	return res;
+}
+
+static enum bisect_error bisect_auto_next(struct bisect_terms *terms, const char *prefix)
+{
+	if (bisect_next_check(terms, NULL)) {
+		bisect_print_status(terms);
+		return BISECT_OK;
+	}
+
+	return bisect_next(terms, prefix);
+}
+
+static enum bisect_error bisect_start(struct bisect_terms *terms, int argc,
+				      const char **argv)
+{
+	int no_checkout = 0;
+	int first_parent_only = 0;
+	int i, has_double_dash = 0, must_write_terms = 0, bad_seen = 0;
+	int flags, pathspec_pos;
+	enum bisect_error res = BISECT_OK;
+	struct string_list revs = STRING_LIST_INIT_DUP;
+	struct string_list states = STRING_LIST_INIT_DUP;
+	struct strbuf start_head = STRBUF_INIT;
+	struct strbuf bisect_names = STRBUF_INIT;
+	struct object_id head_oid;
+	struct object_id oid;
+	const char *head;
+
+	if (is_bare_repository())
+		no_checkout = 1;
+
+	/*
+	 * Check for one bad and then some good revisions
+	 */
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argv[i], "--")) {
+			has_double_dash = 1;
+			break;
+		}
+	}
+
+	for (i = 0; i < argc; i++) {
+		const char *arg = argv[i];
+		if (!strcmp(argv[i], "--")) {
+			break;
+		} else if (!strcmp(arg, "--no-checkout")) {
+			no_checkout = 1;
+		} else if (!strcmp(arg, "--first-parent")) {
+			first_parent_only = 1;
+		} else if (!strcmp(arg, "--term-good") ||
+			 !strcmp(arg, "--term-old")) {
+			i++;
+			if (argc <= i)
+				return error(_("'' is not a valid term"));
+			must_write_terms = 1;
+			free((void *) terms->term_good);
+			terms->term_good = xstrdup(argv[i]);
+		} else if (skip_prefix(arg, "--term-good=", &arg) ||
+			   skip_prefix(arg, "--term-old=", &arg)) {
+			must_write_terms = 1;
+			free((void *) terms->term_good);
+			terms->term_good = xstrdup(arg);
+		} else if (!strcmp(arg, "--term-bad") ||
+			 !strcmp(arg, "--term-new")) {
+			i++;
+			if (argc <= i)
+				return error(_("'' is not a valid term"));
+			must_write_terms = 1;
+			free((void *) terms->term_bad);
+			terms->term_bad = xstrdup(argv[i]);
+		} else if (skip_prefix(arg, "--term-bad=", &arg) ||
+			   skip_prefix(arg, "--term-new=", &arg)) {
+			must_write_terms = 1;
+			free((void *) terms->term_bad);
+			terms->term_bad = xstrdup(arg);
+		} else if (starts_with(arg, "--")) {
+			return error(_("unrecognized option: '%s'"), arg);
+		} else if (!get_oidf(&oid, "%s^{commit}", arg)) {
+			string_list_append(&revs, oid_to_hex(&oid));
+		} else if (has_double_dash) {
+			die(_("'%s' does not appear to be a valid "
+			      "revision"), arg);
+		} else {
+			break;
+		}
+	}
+	pathspec_pos = i;
+
+	/*
+	 * The user ran "git bisect start <sha1> <sha1>", hence did not
+	 * explicitly specify the terms, but we are already starting to
+	 * set references named with the default terms, and won't be able
+	 * to change afterwards.
+	 */
+	if (revs.nr)
+		must_write_terms = 1;
+	for (i = 0; i < revs.nr; i++) {
+		if (bad_seen) {
+			string_list_append(&states, terms->term_good);
+		} else {
+			bad_seen = 1;
+			string_list_append(&states, terms->term_bad);
+		}
+	}
+
+	/*
+	 * Verify HEAD
+	 */
+	head = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+				       "HEAD", 0, &head_oid, &flags);
+	if (!head)
+		if (repo_get_oid(the_repository, "HEAD", &head_oid))
+			return error(_("bad HEAD - I need a HEAD"));
+
+	/*
+	 * Check if we are bisecting
+	 */
+	if (!is_empty_or_missing_file(git_path_bisect_start())) {
+		/* Reset to the rev from where we started */
+		strbuf_read_file(&start_head, git_path_bisect_start(), 0);
+		strbuf_trim(&start_head);
+		if (!no_checkout) {
+			struct child_process cmd = CHILD_PROCESS_INIT;
+
+			cmd.git_cmd = 1;
+			strvec_pushl(&cmd.args, "checkout", start_head.buf,
+				     "--", NULL);
+			if (run_command(&cmd)) {
+				res = error(_("checking out '%s' failed."
+						 " Try 'git bisect start "
+						 "<valid-branch>'."),
+					       start_head.buf);
+				goto finish;
+			}
+		}
+	} else {
+		/* Get the rev from where we start. */
+		if (!repo_get_oid(the_repository, head, &head_oid) &&
+		    !starts_with(head, "refs/heads/")) {
+			strbuf_reset(&start_head);
+			strbuf_addstr(&start_head, oid_to_hex(&head_oid));
+		} else if (!repo_get_oid(the_repository, head, &head_oid) &&
+			   skip_prefix(head, "refs/heads/", &head)) {
+			strbuf_addstr(&start_head, head);
+		} else {
+			return error(_("bad HEAD - strange symbolic ref"));
+		}
+	}
+
+	/*
+	 * Get rid of any old bisect state.
+	 */
+	if (bisect_clean_state())
+		return BISECT_FAILED;
+
+	/*
+	 * Write new start state
+	 */
+	write_file(git_path_bisect_start(), "%s\n", start_head.buf);
+
+	if (first_parent_only)
+		write_file(git_path_bisect_first_parent(), "\n");
+
+	if (no_checkout) {
+		if (repo_get_oid(the_repository, start_head.buf, &oid) < 0) {
+			res = error(_("invalid ref: '%s'"), start_head.buf);
+			goto finish;
+		}
+		if (refs_update_ref(get_main_ref_store(the_repository), NULL, "BISECT_HEAD", &oid, NULL, 0,
+				    UPDATE_REFS_MSG_ON_ERR)) {
+			res = BISECT_FAILED;
+			goto finish;
+		}
+	}
+
+	if (pathspec_pos < argc - 1)
+		sq_quote_argv(&bisect_names, argv + pathspec_pos);
+	write_file(git_path_bisect_names(), "%s\n", bisect_names.buf);
+
+	for (i = 0; i < states.nr; i++)
+		if (bisect_write(states.items[i].string,
+				 revs.items[i].string, terms, 1)) {
+			res = BISECT_FAILED;
+			goto finish;
+		}
+
+	if (must_write_terms && write_terms(terms->term_bad,
+					    terms->term_good)) {
+		res = BISECT_FAILED;
+		goto finish;
+	}
+
+	res = bisect_append_log_quoted(argv);
+	if (res)
+		res = BISECT_FAILED;
+
+finish:
+	string_list_clear(&revs, 0);
+	string_list_clear(&states, 0);
+	strbuf_release(&start_head);
+	strbuf_release(&bisect_names);
+	if (res)
+		return res;
+
+	res = bisect_auto_next(terms, NULL);
+	if (!is_bisect_success(res))
+		bisect_clean_state();
+	return res;
+}
+
+static inline int file_is_not_empty(const char *path)
+{
+	return !is_empty_or_missing_file(path);
+}
+
+static int bisect_autostart(struct bisect_terms *terms)
+{
+	int res;
+	const char *yesno;
+
+	if (file_is_not_empty(git_path_bisect_start()))
+		return 0;
+
+	fprintf_ln(stderr, _("You need to start by \"git bisect "
+			  "start\"\n"));
+
+	if (!isatty(STDIN_FILENO))
+		return -1;
+
+	/*
+	 * TRANSLATORS: Make sure to include [Y] and [n] in your
+	 * translation. The program will only accept English input
+	 * at this point.
+	 */
+	yesno = git_prompt(_("Do you want me to do it for you "
+			     "[Y/n]? "), PROMPT_ECHO);
+	res = tolower(*yesno) == 'n' ?
+		-1 : bisect_start(terms, 0, empty_strvec);
+
+	return res;
+}
+
+static enum bisect_error bisect_state(struct bisect_terms *terms, int argc,
+				      const char **argv)
+{
+	const char *state;
+	int i, verify_expected = 1;
+	struct object_id oid, expected;
+	struct oid_array revs = OID_ARRAY_INIT;
+
+	if (!argc)
+		return error(_("Please call `--bisect-state` with at least one argument"));
+
+	if (bisect_autostart(terms))
+		return BISECT_FAILED;
+
+	state = argv[0];
+	if (check_and_set_terms(terms, state) ||
+	    !one_of(state, terms->term_good, terms->term_bad, "skip", NULL))
+		return BISECT_FAILED;
+
+	argv++;
+	argc--;
+	if (argc > 1 && !strcmp(state, terms->term_bad))
+		return error(_("'git bisect %s' can take only one argument."), terms->term_bad);
+
+	if (argc == 0) {
+		const char *head = "BISECT_HEAD";
+		enum get_oid_result res_head = repo_get_oid(the_repository,
+							    head, &oid);
+
+		if (res_head == MISSING_OBJECT) {
+			head = "HEAD";
+			res_head = repo_get_oid(the_repository, head, &oid);
+		}
+
+		if (res_head)
+			error(_("Bad rev input: %s"), head);
+		oid_array_append(&revs, &oid);
+	}
+
+	/*
+	 * All input revs must be checked before executing bisect_write()
+	 * to discard junk revs.
+	 */
+
+	for (; argc; argc--, argv++) {
+		struct commit *commit;
+
+		if (repo_get_oid(the_repository, *argv, &oid)){
+			error(_("Bad rev input: %s"), *argv);
+			oid_array_clear(&revs);
+			return BISECT_FAILED;
+		}
+
+		commit = lookup_commit_reference(the_repository, &oid);
+		if (!commit)
+			die(_("Bad rev input (not a commit): %s"), *argv);
+
+		oid_array_append(&revs, &commit->object.oid);
+	}
+
+	if (refs_read_ref(get_main_ref_store(the_repository), "BISECT_EXPECTED_REV", &expected))
+		verify_expected = 0; /* Ignore invalid file contents */
+
+	for (i = 0; i < revs.nr; i++) {
+		if (bisect_write(state, oid_to_hex(&revs.oid[i]), terms, 0)) {
+			oid_array_clear(&revs);
+			return BISECT_FAILED;
+		}
+		if (verify_expected && !oideq(&revs.oid[i], &expected)) {
+			unlink_or_warn(git_path_bisect_ancestors_ok());
+			refs_delete_ref(get_main_ref_store(the_repository),
+					NULL, "BISECT_EXPECTED_REV", NULL,
+					REF_NO_DEREF);
+			verify_expected = 0;
+		}
+	}
+
+	oid_array_clear(&revs);
+	return bisect_auto_next(terms, NULL);
+}
+
+static enum bisect_error bisect_log(void)
+{
+	int fd, status;
+	const char* filename = git_path_bisect_log();
+
+	if (is_empty_or_missing_file(filename))
+		return error(_("We are not bisecting."));
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return BISECT_FAILED;
+
+	status = copy_fd(fd, STDOUT_FILENO);
+	close(fd);
+	return status ? BISECT_FAILED : BISECT_OK;
+}
+
+static int process_replay_line(struct bisect_terms *terms, struct strbuf *line)
+{
+	const char *p = line->buf + strspn(line->buf, " \t");
+	char *word_end, *rev;
+
+	if ((!skip_prefix(p, "git bisect", &p) &&
+	!skip_prefix(p, "git-bisect", &p)) || !isspace(*p))
+		return 0;
+	p += strspn(p, " \t");
+
+	word_end = (char *)p + strcspn(p, " \t");
+	rev = word_end + strspn(word_end, " \t");
+	*word_end = '\0'; /* NUL-terminate the word */
+
+	get_terms(terms);
+	if (check_and_set_terms(terms, p))
+		return -1;
+
+	if (!strcmp(p, "start")) {
+		struct strvec argv = STRVEC_INIT;
+		int res;
+		sq_dequote_to_strvec(rev, &argv);
+		res = bisect_start(terms, argv.nr, argv.v);
+		strvec_clear(&argv);
+		return res;
+	}
+
+	if (one_of(p, terms->term_good,
+	   terms->term_bad, "skip", NULL))
+		return bisect_write(p, rev, terms, 0);
+
+	if (!strcmp(p, "terms")) {
+		struct strvec argv = STRVEC_INIT;
+		int res;
+		sq_dequote_to_strvec(rev, &argv);
+		res = bisect_terms(terms, argv.nr == 1 ? argv.v[0] : NULL);
+		strvec_clear(&argv);
+		return res;
+	}
+	error(_("'%s'?? what are you talking about?"), p);
+
+	return -1;
+}
+
+static enum bisect_error bisect_replay(struct bisect_terms *terms, const char *filename)
+{
+	FILE *fp = NULL;
+	enum bisect_error res = BISECT_OK;
+	struct strbuf line = STRBUF_INIT;
+
+	if (is_empty_or_missing_file(filename))
+		return error(_("cannot read file '%s' for replaying"), filename);
+
+	if (bisect_reset(NULL))
+		return BISECT_FAILED;
+
+	fp = fopen(filename, "r");
+	if (!fp)
+		return BISECT_FAILED;
+
+	while ((strbuf_getline(&line, fp) != EOF) && !res)
+		res = process_replay_line(terms, &line);
+
+	strbuf_release(&line);
+	fclose(fp);
+
+	if (res)
+		return BISECT_FAILED;
+
+	return bisect_auto_next(terms, NULL);
+}
+
+static enum bisect_error bisect_skip(struct bisect_terms *terms, int argc,
+				     const char **argv)
+{
+	int i;
+	enum bisect_error res;
+	struct strvec argv_state = STRVEC_INIT;
+
+	strvec_push(&argv_state, "skip");
+
+	for (i = 0; i < argc; i++) {
+		const char *dotdot = strstr(argv[i], "..");
+
+		if (dotdot) {
+			struct rev_info revs;
+			struct commit *commit;
+
+			repo_init_revisions(the_repository, &revs, NULL);
+			setup_revisions(2, argv + i - 1, &revs, NULL);
+
+			if (prepare_revision_walk(&revs))
+				die(_("revision walk setup failed"));
+			while ((commit = get_revision(&revs)) != NULL)
+				strvec_push(&argv_state,
+						oid_to_hex(&commit->object.oid));
+
+			reset_revision_walk();
+			release_revisions(&revs);
+		} else {
+			strvec_push(&argv_state, argv[i]);
+		}
+	}
+	res = bisect_state(terms, argv_state.nr, argv_state.v);
+
+	strvec_clear(&argv_state);
+	return res;
+}
+
+static int bisect_visualize(struct bisect_terms *terms, int argc,
+			    const char **argv)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	struct strbuf sb = STRBUF_INIT;
+
+	if (bisect_next_check(terms, NULL) != 0)
+		return BISECT_FAILED;
+
+	cmd.no_stdin = 1;
+	if (!argc) {
+		if ((getenv("DISPLAY") || getenv("SESSIONNAME") || getenv("MSYSTEM") ||
+		     getenv("SECURITYSESSIONID")) && exists_in_PATH("gitk")) {
+			strvec_push(&cmd.args, "gitk");
+		} else {
+			strvec_push(&cmd.args, "log");
+			cmd.git_cmd = 1;
+		}
+	} else {
+		if (argv[0][0] == '-') {
+			strvec_push(&cmd.args, "log");
+			cmd.git_cmd = 1;
+		} else if (strcmp(argv[0], "tig") && !starts_with(argv[0], "git"))
+			cmd.git_cmd = 1;
+
+		strvec_pushv(&cmd.args, argv);
+	}
+
+	strvec_pushl(&cmd.args, "--bisect", "--", NULL);
+
+	strbuf_read_file(&sb, git_path_bisect_names(), 0);
+	sq_dequote_to_strvec(sb.buf, &cmd.args);
+	strbuf_release(&sb);
+
+	return run_command(&cmd);
+}
+
+static int get_first_good(const char *refname UNUSED,
+			  const char *referent UNUSED,
+			  const struct object_id *oid,
+			  int flag UNUSED, void *cb_data)
+{
+	oidcpy(cb_data, oid);
+	return 1;
+}
+
+static int do_bisect_run(const char *command)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	printf(_("running %s\n"), command);
+	cmd.use_shell = 1;
+	strvec_push(&cmd.args, command);
+	return run_command(&cmd);
+}
+
+static int verify_good(const struct bisect_terms *terms, const char *command)
+{
+	int rc;
+	enum bisect_error res;
+	struct object_id good_rev;
+	struct object_id current_rev;
+	char *good_glob = xstrfmt("%s-*", terms->term_good);
+	int no_checkout = refs_ref_exists(get_main_ref_store(the_repository),
+					  "BISECT_HEAD");
+
+	refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+				  get_first_good, good_glob, "refs/bisect/",
+				  &good_rev);
+	free(good_glob);
+
+	if (refs_read_ref(get_main_ref_store(the_repository), no_checkout ? "BISECT_HEAD" : "HEAD", &current_rev))
+		return -1;
+
+	res = bisect_checkout(&good_rev, no_checkout);
+	if (res != BISECT_OK)
+		return -1;
+
+	rc = do_bisect_run(command);
+
+	res = bisect_checkout(&current_rev, no_checkout);
+	if (res != BISECT_OK)
+		return -1;
+
+	return rc;
+}
+
+static int bisect_run(struct bisect_terms *terms, int argc, const char **argv)
+{
+	int res = BISECT_OK;
+	struct strbuf command = STRBUF_INIT;
+	const char *new_state;
+	int temporary_stdout_fd, saved_stdout;
+	int is_first_run = 1;
+
+	if (bisect_next_check(terms, NULL))
+		return BISECT_FAILED;
+
+	if (!argc) {
+		error(_("bisect run failed: no command provided."));
+		return BISECT_FAILED;
+	}
+
+	sq_quote_argv(&command, argv);
+	strbuf_ltrim(&command);
+	while (1) {
+		res = do_bisect_run(command.buf);
+
+		/*
+		 * Exit code 126 and 127 can either come from the shell
+		 * if it was unable to execute or even find the script,
+		 * or from the script itself.  Check with a known-good
+		 * revision to avoid trashing the bisect run due to a
+		 * missing or non-executable script.
+		 */
+		if (is_first_run && (res == 126 || res == 127)) {
+			int rc = verify_good(terms, command.buf);
+			is_first_run = 0;
+			if (rc < 0 || 128 <= rc) {
+				error(_("unable to verify %s on good"
+					" revision"), command.buf);
+				res = BISECT_FAILED;
+				break;
+			}
+			if (rc == res) {
+				error(_("bogus exit code %d for good revision"),
+				      rc);
+				res = BISECT_FAILED;
+				break;
+			}
+		}
+
+		if (res < 0 || 128 <= res) {
+			error(_("bisect run failed: exit code %d from"
+				" %s is < 0 or >= 128"), res, command.buf);
+			break;
+		}
+
+		if (res == 125)
+			new_state = "skip";
+		else if (!res)
+			new_state = terms->term_good;
+		else
+			new_state = terms->term_bad;
+
+		temporary_stdout_fd = open(git_path_bisect_run(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
+
+		if (temporary_stdout_fd < 0) {
+			res = error_errno(_("cannot open file '%s' for writing"), git_path_bisect_run());
+			break;
+		}
+
+		fflush(stdout);
+		saved_stdout = dup(1);
+		dup2(temporary_stdout_fd, 1);
+
+		res = bisect_state(terms, 1, &new_state);
+
+		fflush(stdout);
+		dup2(saved_stdout, 1);
+		close(saved_stdout);
+		close(temporary_stdout_fd);
+
+		print_file_to_stdout(git_path_bisect_run());
+
+		if (res == BISECT_ONLY_SKIPPED_LEFT)
+			error(_("bisect run cannot continue any more"));
+		else if (res == BISECT_INTERNAL_SUCCESS_MERGE_BASE) {
+			puts(_("bisect run success"));
+			res = BISECT_OK;
+		} else if (res == BISECT_INTERNAL_SUCCESS_1ST_BAD_FOUND) {
+			puts(_("bisect found first bad commit"));
+			res = BISECT_OK;
+		} else if (res) {
+			error(_("bisect run failed: 'git bisect %s'"
+				" exited with error code %d"), new_state, res);
+		} else {
+			continue;
+		}
+		break;
+	}
+
+	strbuf_release(&command);
+	return res;
+}
+
+static int cmd_bisect__reset(int argc, const char **argv, const char *prefix UNUSED,
+			     struct repository *repo UNUSED)
+{
+	if (argc > 1)
+		return error(_("'%s' requires either no argument or a commit"),
+			     "git bisect reset");
+	return bisect_reset(argc ? argv[0] : NULL);
+}
+
+static int cmd_bisect__terms(int argc, const char **argv, const char *prefix UNUSED,
+			     struct repository *repo UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (argc > 1)
+		return error(_("'%s' requires 0 or 1 argument"),
+			     "git bisect terms");
+	res = bisect_terms(&terms, argc == 1 ? argv[0] : NULL);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__start(int argc, const char **argv, const char *prefix UNUSED,
+			     struct repository *repo UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	set_terms(&terms, "bad", "good");
+	res = bisect_start(&terms, argc, argv);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__next(int argc, const char **argv UNUSED, const char *prefix,
+			    struct repository *repo UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (argc)
+		return error(_("'%s' requires 0 arguments"),
+			     "git bisect next");
+	get_terms(&terms);
+	res = bisect_next(&terms, prefix);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__log(int argc UNUSED, const char **argv UNUSED,
+			   const char *prefix UNUSED,
+			   struct repository *repo UNUSED)
+{
+	return bisect_log();
+}
+
+static int cmd_bisect__replay(int argc, const char **argv, const char *prefix UNUSED,
+			      struct repository *repo UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (argc != 1)
+		return error(_("no logfile given"));
+	set_terms(&terms, "bad", "good");
+	res = bisect_replay(&terms, argv[0]);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__skip(int argc, const char **argv, const char *prefix UNUSED,
+			    struct repository *repo UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	set_terms(&terms, "bad", "good");
+	get_terms(&terms);
+	res = bisect_skip(&terms, argc, argv);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__visualize(int argc, const char **argv, const char *prefix UNUSED,
+				 struct repository *repo UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	get_terms(&terms);
+	res = bisect_visualize(&terms, argc, argv);
+	free_terms(&terms);
+	return res;
+}
+
+static int cmd_bisect__run(int argc, const char **argv, const char *prefix UNUSED,
+			   struct repository *repo UNUSED)
+{
+	int res;
+	struct bisect_terms terms = { 0 };
+
+	if (!argc)
+		return error(_("'%s' failed: no command provided."), "git bisect run");
+	get_terms(&terms);
+	res = bisect_run(&terms, argc, argv);
+	free_terms(&terms);
+	return res;
+}
+
+int cmd_bisect(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo)
+{
+	int res = 0;
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("reset", &fn, cmd_bisect__reset),
+		OPT_SUBCOMMAND("terms", &fn, cmd_bisect__terms),
+		OPT_SUBCOMMAND("start", &fn, cmd_bisect__start),
+		OPT_SUBCOMMAND("next", &fn, cmd_bisect__next),
+		OPT_SUBCOMMAND("log", &fn, cmd_bisect__log),
+		OPT_SUBCOMMAND("replay", &fn, cmd_bisect__replay),
+		OPT_SUBCOMMAND("skip", &fn, cmd_bisect__skip),
+		OPT_SUBCOMMAND("visualize", &fn, cmd_bisect__visualize),
+		OPT_SUBCOMMAND("view", &fn, cmd_bisect__visualize),
+		OPT_SUBCOMMAND("run", &fn, cmd_bisect__run),
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, prefix, options, git_bisect_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL);
+
+	if (!fn) {
+		struct bisect_terms terms = { 0 };
+
+		if (!argc)
+			usage_msg_opt(_("need a command"), git_bisect_usage, options);
+
+		set_terms(&terms, "bad", "good");
+		get_terms(&terms);
+		if (check_and_set_terms(&terms, argv[0]))
+			usage_msg_optf(_("unknown command: '%s'"), git_bisect_usage,
+				       options, argv[0]);
+		res = bisect_state(&terms, argc, argv);
+		free_terms(&terms);
+	} else {
+		argc--;
+		argv++;
+		res = fn(argc, argv, prefix, repo);
+	}
+
+	return is_bisect_success(res) ? 0 : -res;
+}
diff --git a/builtin/blame.c b/builtin/blame.c
new file mode 100644
index 0000000000..c470654c7e
--- /dev/null
+++ b/builtin/blame.c
@@ -0,0 +1,1247 @@
+/*
+ * Blame
+ *
+ * Copyright (c) 2006, 2014 by its authors
+ * See COPYING for licensing conditions
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "color.h"
+#include "builtin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "quote.h"
+#include "string-list.h"
+#include "mailmap.h"
+#include "parse-options.h"
+#include "prio-queue.h"
+#include "utf8.h"
+#include "userdiff.h"
+#include "line-range.h"
+#include "line-log.h"
+#include "progress.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
+#include "blame.h"
+#include "refs.h"
+#include "setup.h"
+#include "tag.h"
+#include "write-or-die.h"
+
+static char blame_usage[] = N_("git blame [<options>] [<rev-opts>] [<rev>] [--] <file>");
+static char annotate_usage[] = N_("git annotate [<options>] [<rev-opts>] [<rev>] [--] <file>");
+
+static const char *blame_opt_usage[] = {
+	blame_usage,
+	"",
+	N_("<rev-opts> are documented in git-rev-list(1)"),
+	NULL
+};
+
+static const char *annotate_opt_usage[] = {
+	annotate_usage,
+	"",
+	N_("<rev-opts> are documented in git-rev-list(1)"),
+	NULL
+};
+
+static int longest_file;
+static int longest_author;
+static int max_orig_digits;
+static int max_digits;
+static int max_score_digits;
+static int show_root;
+static int reverse;
+static int blank_boundary;
+static int incremental;
+static int xdl_opts;
+static int abbrev = -1;
+static int no_whole_file_rename;
+static int show_progress;
+static char repeated_meta_color[COLOR_MAXLEN];
+static int coloring_mode;
+static struct string_list ignore_revs_file_list = STRING_LIST_INIT_DUP;
+static int mark_unblamable_lines;
+static int mark_ignored_lines;
+
+static struct date_mode blame_date_mode = { DATE_ISO8601 };
+static size_t blame_date_width;
+
+static struct string_list mailmap = STRING_LIST_INIT_NODUP;
+
+#ifndef DEBUG_BLAME
+#define DEBUG_BLAME 0
+#endif
+
+static unsigned blame_move_score;
+static unsigned blame_copy_score;
+
+/* Remember to update object flag allocation in object.h */
+#define METAINFO_SHOWN		(1u<<12)
+#define MORE_THAN_ONE_PATH	(1u<<13)
+
+struct progress_info {
+	struct progress *progress;
+	int blamed_lines;
+};
+
+static const char *nth_line_cb(void *data, long lno)
+{
+	return blame_nth_line((struct blame_scoreboard *)data, lno);
+}
+
+/*
+ * Information on commits, used for output.
+ */
+struct commit_info {
+	struct strbuf author;
+	struct strbuf author_mail;
+	timestamp_t author_time;
+	struct strbuf author_tz;
+
+	/* filled only when asked for details */
+	struct strbuf committer;
+	struct strbuf committer_mail;
+	timestamp_t committer_time;
+	struct strbuf committer_tz;
+
+	struct strbuf summary;
+};
+
+#define COMMIT_INFO_INIT { \
+	.author = STRBUF_INIT, \
+	.author_mail = STRBUF_INIT, \
+	.author_tz = STRBUF_INIT, \
+	.committer = STRBUF_INIT, \
+	.committer_mail = STRBUF_INIT, \
+	.committer_tz = STRBUF_INIT, \
+	.summary = STRBUF_INIT, \
+}
+
+/*
+ * Parse author/committer line in the commit object buffer
+ */
+static void get_ac_line(const char *inbuf, const char *what,
+	struct strbuf *name, struct strbuf *mail,
+	timestamp_t *time, struct strbuf *tz)
+{
+	struct ident_split ident;
+	size_t len, maillen, namelen;
+	const char *tmp, *endp;
+	const char *namebuf, *mailbuf;
+
+	tmp = strstr(inbuf, what);
+	if (!tmp)
+		goto error_out;
+	tmp += strlen(what);
+	endp = strchr(tmp, '\n');
+	if (!endp)
+		len = strlen(tmp);
+	else
+		len = endp - tmp;
+
+	if (split_ident_line(&ident, tmp, len)) {
+	error_out:
+		/* Ugh */
+		tmp = "(unknown)";
+		strbuf_addstr(name, tmp);
+		strbuf_addstr(mail, tmp);
+		strbuf_addstr(tz, tmp);
+		*time = 0;
+		return;
+	}
+
+	namelen = ident.name_end - ident.name_begin;
+	namebuf = ident.name_begin;
+
+	maillen = ident.mail_end - ident.mail_begin;
+	mailbuf = ident.mail_begin;
+
+	if (ident.date_begin && ident.date_end)
+		*time = strtoul(ident.date_begin, NULL, 10);
+	else
+		*time = 0;
+
+	if (ident.tz_begin && ident.tz_end)
+		strbuf_add(tz, ident.tz_begin, ident.tz_end - ident.tz_begin);
+	else
+		strbuf_addstr(tz, "(unknown)");
+
+	/*
+	 * Now, convert both name and e-mail using mailmap
+	 */
+	map_user(&mailmap, &mailbuf, &maillen,
+		 &namebuf, &namelen);
+
+	strbuf_addf(mail, "<%.*s>", (int)maillen, mailbuf);
+	strbuf_add(name, namebuf, namelen);
+}
+
+static void commit_info_destroy(struct commit_info *ci)
+{
+
+	strbuf_release(&ci->author);
+	strbuf_release(&ci->author_mail);
+	strbuf_release(&ci->author_tz);
+	strbuf_release(&ci->committer);
+	strbuf_release(&ci->committer_mail);
+	strbuf_release(&ci->committer_tz);
+	strbuf_release(&ci->summary);
+}
+
+static void get_commit_info(struct commit *commit,
+			    struct commit_info *ret,
+			    int detailed)
+{
+	int len;
+	const char *subject, *encoding;
+	const char *message;
+
+	encoding = get_log_output_encoding();
+	message = repo_logmsg_reencode(the_repository, commit, NULL, encoding);
+	get_ac_line(message, "\nauthor ",
+		    &ret->author, &ret->author_mail,
+		    &ret->author_time, &ret->author_tz);
+
+	if (!detailed) {
+		repo_unuse_commit_buffer(the_repository, commit, message);
+		return;
+	}
+
+	get_ac_line(message, "\ncommitter ",
+		    &ret->committer, &ret->committer_mail,
+		    &ret->committer_time, &ret->committer_tz);
+
+	len = find_commit_subject(message, &subject);
+	if (len)
+		strbuf_add(&ret->summary, subject, len);
+	else
+		strbuf_addf(&ret->summary, "(%s)", oid_to_hex(&commit->object.oid));
+
+	repo_unuse_commit_buffer(the_repository, commit, message);
+}
+
+/*
+ * Write out any suspect information which depends on the path. This must be
+ * handled separately from emit_one_suspect_detail(), because a given commit
+ * may have changes in multiple paths. So this needs to appear each time
+ * we mention a new group.
+ *
+ * To allow LF and other nonportable characters in pathnames,
+ * they are c-style quoted as needed.
+ */
+static void write_filename_info(struct blame_origin *suspect)
+{
+	if (suspect->previous) {
+		struct blame_origin *prev = suspect->previous;
+		printf("previous %s ", oid_to_hex(&prev->commit->object.oid));
+		write_name_quoted(prev->path, stdout, '\n');
+	}
+	printf("filename ");
+	write_name_quoted(suspect->path, stdout, '\n');
+}
+
+/*
+ * Porcelain/Incremental format wants to show a lot of details per
+ * commit.  Instead of repeating this every line, emit it only once,
+ * the first time each commit appears in the output (unless the
+ * user has specifically asked for us to repeat).
+ */
+static int emit_one_suspect_detail(struct blame_origin *suspect, int repeat)
+{
+	struct commit_info ci = COMMIT_INFO_INIT;
+
+	if (!repeat && (suspect->commit->object.flags & METAINFO_SHOWN))
+		return 0;
+
+	suspect->commit->object.flags |= METAINFO_SHOWN;
+	get_commit_info(suspect->commit, &ci, 1);
+	printf("author %s\n", ci.author.buf);
+	printf("author-mail %s\n", ci.author_mail.buf);
+	printf("author-time %"PRItime"\n", ci.author_time);
+	printf("author-tz %s\n", ci.author_tz.buf);
+	printf("committer %s\n", ci.committer.buf);
+	printf("committer-mail %s\n", ci.committer_mail.buf);
+	printf("committer-time %"PRItime"\n", ci.committer_time);
+	printf("committer-tz %s\n", ci.committer_tz.buf);
+	printf("summary %s\n", ci.summary.buf);
+	if (suspect->commit->object.flags & UNINTERESTING)
+		printf("boundary\n");
+
+	commit_info_destroy(&ci);
+
+	return 1;
+}
+
+/*
+ * The blame_entry is found to be guilty for the range.
+ * Show it in incremental output.
+ */
+static void found_guilty_entry(struct blame_entry *ent, void *data)
+{
+	struct progress_info *pi = (struct progress_info *)data;
+
+	if (incremental) {
+		struct blame_origin *suspect = ent->suspect;
+
+		printf("%s %d %d %d\n",
+		       oid_to_hex(&suspect->commit->object.oid),
+		       ent->s_lno + 1, ent->lno + 1, ent->num_lines);
+		emit_one_suspect_detail(suspect, 0);
+		write_filename_info(suspect);
+		maybe_flush_or_die(stdout, "stdout");
+	}
+	pi->blamed_lines += ent->num_lines;
+	display_progress(pi->progress, pi->blamed_lines);
+}
+
+static const char *format_time(timestamp_t time, const char *tz_str,
+			       int show_raw_time)
+{
+	static struct strbuf time_buf = STRBUF_INIT;
+
+	strbuf_reset(&time_buf);
+	if (show_raw_time) {
+		strbuf_addf(&time_buf, "%"PRItime" %s", time, tz_str);
+	}
+	else {
+		const char *time_str;
+		size_t time_width;
+		int tz;
+		tz = atoi(tz_str);
+		time_str = show_date(time, tz, blame_date_mode);
+		strbuf_addstr(&time_buf, time_str);
+		/*
+		 * Add space paddings to time_buf to display a fixed width
+		 * string, and use time_width for display width calibration.
+		 */
+		for (time_width = utf8_strwidth(time_str);
+		     time_width < blame_date_width;
+		     time_width++)
+			strbuf_addch(&time_buf, ' ');
+	}
+	return time_buf.buf;
+}
+
+#define OUTPUT_ANNOTATE_COMPAT      (1U<<0)
+#define OUTPUT_LONG_OBJECT_NAME     (1U<<1)
+#define OUTPUT_RAW_TIMESTAMP        (1U<<2)
+#define OUTPUT_PORCELAIN            (1U<<3)
+#define OUTPUT_SHOW_NAME            (1U<<4)
+#define OUTPUT_SHOW_NUMBER          (1U<<5)
+#define OUTPUT_SHOW_SCORE           (1U<<6)
+#define OUTPUT_NO_AUTHOR            (1U<<7)
+#define OUTPUT_SHOW_EMAIL           (1U<<8)
+#define OUTPUT_LINE_PORCELAIN       (1U<<9)
+#define OUTPUT_COLOR_LINE           (1U<<10)
+#define OUTPUT_SHOW_AGE_WITH_COLOR  (1U<<11)
+
+static void emit_porcelain_details(struct blame_origin *suspect, int repeat)
+{
+	if (emit_one_suspect_detail(suspect, repeat) ||
+	    (suspect->commit->object.flags & MORE_THAN_ONE_PATH))
+		write_filename_info(suspect);
+}
+
+static void emit_porcelain(struct blame_scoreboard *sb, struct blame_entry *ent,
+			   int opt)
+{
+	int repeat = opt & OUTPUT_LINE_PORCELAIN;
+	int cnt;
+	const char *cp;
+	struct blame_origin *suspect = ent->suspect;
+	char hex[GIT_MAX_HEXSZ + 1];
+
+	oid_to_hex_r(hex, &suspect->commit->object.oid);
+	printf("%s %d %d %d\n",
+	       hex,
+	       ent->s_lno + 1,
+	       ent->lno + 1,
+	       ent->num_lines);
+	emit_porcelain_details(suspect, repeat);
+
+	cp = blame_nth_line(sb, ent->lno);
+	for (cnt = 0; cnt < ent->num_lines; cnt++) {
+		char ch;
+		if (cnt) {
+			printf("%s %d %d\n", hex,
+			       ent->s_lno + 1 + cnt,
+			       ent->lno + 1 + cnt);
+			if (repeat)
+				emit_porcelain_details(suspect, 1);
+		}
+		putchar('\t');
+		do {
+			ch = *cp++;
+			putchar(ch);
+		} while (ch != '\n' &&
+			 cp < sb->final_buf + sb->final_buf_size);
+	}
+
+	if (sb->final_buf_size && cp[-1] != '\n')
+		putchar('\n');
+}
+
+static struct color_field {
+	timestamp_t hop;
+	char col[COLOR_MAXLEN];
+} *colorfield;
+static int colorfield_nr, colorfield_alloc;
+
+static void parse_color_fields(const char *s)
+{
+	struct string_list l = STRING_LIST_INIT_DUP;
+	struct string_list_item *item;
+	enum { EXPECT_DATE, EXPECT_COLOR } next = EXPECT_COLOR;
+
+	colorfield_nr = 0;
+
+	/* Ideally this would be stripped and split at the same time? */
+	string_list_split(&l, s, ',', -1);
+	ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
+
+	for_each_string_list_item(item, &l) {
+		switch (next) {
+		case EXPECT_DATE:
+			colorfield[colorfield_nr].hop = approxidate(item->string);
+			next = EXPECT_COLOR;
+			colorfield_nr++;
+			ALLOC_GROW(colorfield, colorfield_nr + 1, colorfield_alloc);
+			break;
+		case EXPECT_COLOR:
+			if (color_parse(item->string, colorfield[colorfield_nr].col))
+				die(_("expecting a color: %s"), item->string);
+			next = EXPECT_DATE;
+			break;
+		}
+	}
+
+	if (next == EXPECT_COLOR)
+		die(_("must end with a color"));
+
+	colorfield[colorfield_nr].hop = TIME_MAX;
+	string_list_clear(&l, 0);
+}
+
+static void setup_default_color_by_age(void)
+{
+	parse_color_fields("blue,12 month ago,white,1 month ago,red");
+}
+
+static void determine_line_heat(struct commit_info *ci, const char **dest_color)
+{
+	int i = 0;
+
+	while (i < colorfield_nr && ci->author_time > colorfield[i].hop)
+		i++;
+
+	*dest_color = colorfield[i].col;
+}
+
+static void emit_other(struct blame_scoreboard *sb, struct blame_entry *ent, int opt)
+{
+	int cnt;
+	const char *cp;
+	struct blame_origin *suspect = ent->suspect;
+	struct commit_info ci = COMMIT_INFO_INIT;
+	char hex[GIT_MAX_HEXSZ + 1];
+	int show_raw_time = !!(opt & OUTPUT_RAW_TIMESTAMP);
+	const char *default_color = NULL, *color = NULL, *reset = NULL;
+
+	get_commit_info(suspect->commit, &ci, 1);
+	oid_to_hex_r(hex, &suspect->commit->object.oid);
+
+	cp = blame_nth_line(sb, ent->lno);
+
+	if (opt & OUTPUT_SHOW_AGE_WITH_COLOR) {
+		determine_line_heat(&ci, &default_color);
+		color = default_color;
+		reset = GIT_COLOR_RESET;
+	}
+
+	if (abbrev < MINIMUM_ABBREV)
+		BUG("abbreviation is smaller than minimum length: %d < %d",
+		    abbrev, MINIMUM_ABBREV);
+
+	for (cnt = 0; cnt < ent->num_lines; cnt++) {
+		char ch;
+		size_t length = (opt & OUTPUT_LONG_OBJECT_NAME) ?
+			the_hash_algo->hexsz : (size_t) abbrev;
+
+		if (opt & OUTPUT_COLOR_LINE) {
+			if (cnt > 0) {
+				color = repeated_meta_color;
+				reset = GIT_COLOR_RESET;
+			} else  {
+				color = default_color ? default_color : NULL;
+				reset = default_color ? GIT_COLOR_RESET : NULL;
+			}
+		}
+		if (color)
+			fputs(color, stdout);
+
+		if (suspect->commit->object.flags & UNINTERESTING) {
+			if (blank_boundary) {
+				memset(hex, ' ', strlen(hex));
+			} else if (!(opt & OUTPUT_ANNOTATE_COMPAT)) {
+				length--;
+				putchar('^');
+			}
+		}
+
+		if (mark_unblamable_lines && ent->unblamable) {
+			length--;
+			putchar('*');
+		}
+		if (mark_ignored_lines && ent->ignored) {
+			length--;
+			putchar('?');
+		}
+
+		printf("%.*s", (int)(length < GIT_MAX_HEXSZ ? length : GIT_MAX_HEXSZ), hex);
+		if (opt & OUTPUT_ANNOTATE_COMPAT) {
+			const char *name;
+			if (opt & OUTPUT_SHOW_EMAIL)
+				name = ci.author_mail.buf;
+			else
+				name = ci.author.buf;
+			printf("\t(%10s\t%10s\t%d)", name,
+			       format_time(ci.author_time, ci.author_tz.buf,
+					   show_raw_time),
+			       ent->lno + 1 + cnt);
+		} else {
+			if (opt & OUTPUT_SHOW_SCORE)
+				printf(" %*d %02d",
+				       max_score_digits, ent->score,
+				       ent->suspect->refcnt);
+			if (opt & OUTPUT_SHOW_NAME)
+				printf(" %-*.*s", longest_file, longest_file,
+				       suspect->path);
+			if (opt & OUTPUT_SHOW_NUMBER)
+				printf(" %*d", max_orig_digits,
+				       ent->s_lno + 1 + cnt);
+
+			if (!(opt & OUTPUT_NO_AUTHOR)) {
+				const char *name;
+				int pad;
+				if (opt & OUTPUT_SHOW_EMAIL)
+					name = ci.author_mail.buf;
+				else
+					name = ci.author.buf;
+				pad = longest_author - utf8_strwidth(name);
+				printf(" (%s%*s %10s",
+				       name, pad, "",
+				       format_time(ci.author_time,
+						   ci.author_tz.buf,
+						   show_raw_time));
+			}
+			printf(" %*d) ",
+			       max_digits, ent->lno + 1 + cnt);
+		}
+		if (reset)
+			fputs(reset, stdout);
+		do {
+			ch = *cp++;
+			putchar(ch);
+		} while (ch != '\n' &&
+			 cp < sb->final_buf + sb->final_buf_size);
+	}
+
+	if (sb->final_buf_size && cp[-1] != '\n')
+		putchar('\n');
+
+	commit_info_destroy(&ci);
+}
+
+static void output(struct blame_scoreboard *sb, int option)
+{
+	struct blame_entry *ent;
+
+	if (option & OUTPUT_PORCELAIN) {
+		for (ent = sb->ent; ent; ent = ent->next) {
+			int count = 0;
+			struct blame_origin *suspect;
+			struct commit *commit = ent->suspect->commit;
+			if (commit->object.flags & MORE_THAN_ONE_PATH)
+				continue;
+			for (suspect = get_blame_suspects(commit); suspect; suspect = suspect->next) {
+				if (suspect->guilty && count++) {
+					commit->object.flags |= MORE_THAN_ONE_PATH;
+					break;
+				}
+			}
+		}
+	}
+
+	for (ent = sb->ent; ent; ent = ent->next) {
+		if (option & OUTPUT_PORCELAIN)
+			emit_porcelain(sb, ent, option);
+		else {
+			emit_other(sb, ent, option);
+		}
+	}
+}
+
+/*
+ * Add phony grafts for use with -S; this is primarily to
+ * support git's cvsserver that wants to give a linear history
+ * to its clients.
+ */
+static int read_ancestry(const char *graft_file)
+{
+	FILE *fp = fopen_or_warn(graft_file, "r");
+	struct strbuf buf = STRBUF_INIT;
+	if (!fp)
+		return -1;
+	while (!strbuf_getwholeline(&buf, fp, '\n')) {
+		/* The format is just "Commit Parent1 Parent2 ...\n" */
+		struct commit_graft *graft = read_graft_line(&buf);
+		if (graft)
+			register_commit_graft(the_repository, graft, 0);
+	}
+	fclose(fp);
+	strbuf_release(&buf);
+	return 0;
+}
+
+static int update_auto_abbrev(int auto_abbrev, struct blame_origin *suspect)
+{
+	const char *uniq = repo_find_unique_abbrev(the_repository,
+						   &suspect->commit->object.oid,
+						   auto_abbrev);
+	int len = strlen(uniq);
+	if (auto_abbrev < len)
+		return len;
+	return auto_abbrev;
+}
+
+/*
+ * How many columns do we need to show line numbers, authors,
+ * and filenames?
+ */
+static void find_alignment(struct blame_scoreboard *sb, int *option)
+{
+	int longest_src_lines = 0;
+	int longest_dst_lines = 0;
+	unsigned largest_score = 0;
+	struct blame_entry *e;
+	int compute_auto_abbrev = (abbrev < 0);
+	int auto_abbrev = DEFAULT_ABBREV;
+
+	for (e = sb->ent; e; e = e->next) {
+		struct blame_origin *suspect = e->suspect;
+		int num;
+
+		if (compute_auto_abbrev)
+			auto_abbrev = update_auto_abbrev(auto_abbrev, suspect);
+		if (strcmp(suspect->path, sb->path))
+			*option |= OUTPUT_SHOW_NAME;
+		num = strlen(suspect->path);
+		if (longest_file < num)
+			longest_file = num;
+		if (!(suspect->commit->object.flags & METAINFO_SHOWN)) {
+			struct commit_info ci = COMMIT_INFO_INIT;
+			suspect->commit->object.flags |= METAINFO_SHOWN;
+			get_commit_info(suspect->commit, &ci, 1);
+			if (*option & OUTPUT_SHOW_EMAIL)
+				num = utf8_strwidth(ci.author_mail.buf);
+			else
+				num = utf8_strwidth(ci.author.buf);
+			if (longest_author < num)
+				longest_author = num;
+			commit_info_destroy(&ci);
+		}
+		num = e->s_lno + e->num_lines;
+		if (longest_src_lines < num)
+			longest_src_lines = num;
+		num = e->lno + e->num_lines;
+		if (longest_dst_lines < num)
+			longest_dst_lines = num;
+		if (largest_score < blame_entry_score(sb, e))
+			largest_score = blame_entry_score(sb, e);
+	}
+	max_orig_digits = decimal_width(longest_src_lines);
+	max_digits = decimal_width(longest_dst_lines);
+	max_score_digits = decimal_width(largest_score);
+
+	if (compute_auto_abbrev)
+		/* one more abbrev length is needed for the boundary commit */
+		abbrev = auto_abbrev + 1;
+}
+
+static void sanity_check_on_fail(struct blame_scoreboard *sb, int baa)
+{
+	int opt = OUTPUT_SHOW_SCORE | OUTPUT_SHOW_NUMBER | OUTPUT_SHOW_NAME;
+	find_alignment(sb, &opt);
+	output(sb, opt);
+	die("Baa %d!", baa);
+}
+
+static unsigned parse_score(const char *arg)
+{
+	char *end;
+	unsigned long score = strtoul(arg, &end, 10);
+	if (*end)
+		return 0;
+	return score;
+}
+
+static char *add_prefix(const char *prefix, const char *path)
+{
+	return prefix_path(prefix, prefix ? strlen(prefix) : 0, path);
+}
+
+static int git_blame_config(const char *var, const char *value,
+			    const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "blame.showroot")) {
+		show_root = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "blame.blankboundary")) {
+		blank_boundary = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "blame.showemail")) {
+		int *output_option = cb;
+		if (git_config_bool(var, value))
+			*output_option |= OUTPUT_SHOW_EMAIL;
+		else
+			*output_option &= ~OUTPUT_SHOW_EMAIL;
+		return 0;
+	}
+	if (!strcmp(var, "blame.date")) {
+		if (!value)
+			return config_error_nonbool(var);
+		parse_date_format(value, &blame_date_mode);
+		return 0;
+	}
+	if (!strcmp(var, "blame.ignorerevsfile")) {
+		char *str;
+		int ret;
+
+		ret = git_config_pathname(&str, var, value);
+		if (ret)
+			return ret;
+		string_list_insert(&ignore_revs_file_list, str);
+		free(str);
+		return 0;
+	}
+	if (!strcmp(var, "blame.markunblamablelines")) {
+		mark_unblamable_lines = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "blame.markignoredlines")) {
+		mark_ignored_lines = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "color.blame.repeatedlines")) {
+		if (color_parse_mem(value, strlen(value), repeated_meta_color))
+			warning(_("invalid value for '%s': '%s'"),
+				"color.blame.repeatedLines", value);
+		return 0;
+	}
+	if (!strcmp(var, "color.blame.highlightrecent")) {
+		parse_color_fields(value);
+		return 0;
+	}
+
+	if (!strcmp(var, "blame.coloring")) {
+		if (!value)
+			return config_error_nonbool(var);
+		if (!strcmp(value, "repeatedLines")) {
+			coloring_mode |= OUTPUT_COLOR_LINE;
+		} else if (!strcmp(value, "highlightRecent")) {
+			coloring_mode |= OUTPUT_SHOW_AGE_WITH_COLOR;
+		} else if (!strcmp(value, "none")) {
+			coloring_mode &= ~(OUTPUT_COLOR_LINE |
+					    OUTPUT_SHOW_AGE_WITH_COLOR);
+		} else {
+			warning(_("invalid value for '%s': '%s'"),
+				"blame.coloring", value);
+			return 0;
+		}
+	}
+
+	if (git_diff_heuristic_config(var, value, cb) < 0)
+		return -1;
+	if (userdiff_config(var, value) < 0)
+		return -1;
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static int blame_copy_callback(const struct option *option, const char *arg, int unset)
+{
+	int *opt = option->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	/*
+	 * -C enables copy from removed files;
+	 * -C -C enables copy from existing files, but only
+	 *       when blaming a new file;
+	 * -C -C -C enables copy from existing files for
+	 *          everybody
+	 */
+	if (*opt & PICKAXE_BLAME_COPY_HARDER)
+		*opt |= PICKAXE_BLAME_COPY_HARDEST;
+	if (*opt & PICKAXE_BLAME_COPY)
+		*opt |= PICKAXE_BLAME_COPY_HARDER;
+	*opt |= PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE;
+
+	if (arg)
+		blame_copy_score = parse_score(arg);
+	return 0;
+}
+
+static int blame_move_callback(const struct option *option, const char *arg, int unset)
+{
+	int *opt = option->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	*opt |= PICKAXE_BLAME_MOVE;
+
+	if (arg)
+		blame_move_score = parse_score(arg);
+	return 0;
+}
+
+static int is_a_rev(const char *name)
+{
+	struct object_id oid;
+
+	if (repo_get_oid(the_repository, name, &oid))
+		return 0;
+	return OBJ_NONE < oid_object_info(the_repository, &oid, NULL);
+}
+
+static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)
+{
+	struct repository *r = ((struct blame_scoreboard *)cbdata)->repo;
+	struct object_id oid;
+
+	oidcpy(&oid, oid_ret);
+	while (1) {
+		struct object *obj;
+		int kind = oid_object_info(r, &oid, NULL);
+		if (kind == OBJ_COMMIT) {
+			oidcpy(oid_ret, &oid);
+			return 0;
+		}
+		if (kind != OBJ_TAG)
+			return -1;
+		obj = deref_tag(r, parse_object(r, &oid), NULL, 0);
+		if (!obj)
+			return -1;
+		oidcpy(&oid, &obj->oid);
+	}
+}
+
+static void build_ignorelist(struct blame_scoreboard *sb,
+			     struct string_list *ignore_revs_file_list,
+			     struct string_list *ignore_rev_list)
+{
+	struct string_list_item *i;
+	struct object_id oid;
+
+	oidset_init(&sb->ignore_list, 0);
+	for_each_string_list_item(i, ignore_revs_file_list) {
+		if (!strcmp(i->string, ""))
+			oidset_clear(&sb->ignore_list);
+		else
+			oidset_parse_file_carefully(&sb->ignore_list, i->string,
+						    the_repository->hash_algo,
+						    peel_to_commit_oid, sb);
+	}
+	for_each_string_list_item(i, ignore_rev_list) {
+		if (repo_get_oid_committish(the_repository, i->string, &oid) ||
+		    peel_to_commit_oid(&oid, sb))
+			die(_("cannot find revision %s to ignore"), i->string);
+		oidset_insert(&sb->ignore_list, &oid);
+	}
+}
+
+int cmd_blame(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	struct rev_info revs;
+	char *path = NULL;
+	struct blame_scoreboard sb;
+	struct blame_origin *o;
+	struct blame_entry *ent = NULL;
+	long dashdash_pos, lno;
+	struct progress_info pi = { NULL, 0 };
+
+	struct string_list range_list = STRING_LIST_INIT_NODUP;
+	struct string_list ignore_rev_list = STRING_LIST_INIT_NODUP;
+	int output_option = 0, opt = 0;
+	int show_stats = 0;
+	const char *revs_file = NULL;
+	const char *contents_from = NULL;
+	const struct option options[] = {
+		OPT_BOOL(0, "incremental", &incremental, N_("show blame entries as we find them, incrementally")),
+		OPT_BOOL('b', NULL, &blank_boundary, N_("do not show object names of boundary commits (Default: off)")),
+		OPT_BOOL(0, "root", &show_root, N_("do not treat root commits as boundaries (Default: off)")),
+		OPT_BOOL(0, "show-stats", &show_stats, N_("show work cost statistics")),
+		OPT_BOOL(0, "progress", &show_progress, N_("force progress reporting")),
+		OPT_BIT(0, "score-debug", &output_option, N_("show output score for blame entries"), OUTPUT_SHOW_SCORE),
+		OPT_BIT('f', "show-name", &output_option, N_("show original filename (Default: auto)"), OUTPUT_SHOW_NAME),
+		OPT_BIT('n', "show-number", &output_option, N_("show original linenumber (Default: off)"), OUTPUT_SHOW_NUMBER),
+		OPT_BIT('p', "porcelain", &output_option, N_("show in a format designed for machine consumption"), OUTPUT_PORCELAIN),
+		OPT_BIT(0, "line-porcelain", &output_option, N_("show porcelain format with per-line commit information"), OUTPUT_PORCELAIN|OUTPUT_LINE_PORCELAIN),
+		OPT_BIT('c', NULL, &output_option, N_("use the same output mode as git-annotate (Default: off)"), OUTPUT_ANNOTATE_COMPAT),
+		OPT_BIT('t', NULL, &output_option, N_("show raw timestamp (Default: off)"), OUTPUT_RAW_TIMESTAMP),
+		OPT_BIT('l', NULL, &output_option, N_("show long commit SHA1 (Default: off)"), OUTPUT_LONG_OBJECT_NAME),
+		OPT_BIT('s', NULL, &output_option, N_("suppress author name and timestamp (Default: off)"), OUTPUT_NO_AUTHOR),
+		OPT_BIT('e', "show-email", &output_option, N_("show author email instead of name (Default: off)"), OUTPUT_SHOW_EMAIL),
+		OPT_BIT('w', NULL, &xdl_opts, N_("ignore whitespace differences"), XDF_IGNORE_WHITESPACE),
+		OPT_STRING_LIST(0, "ignore-rev", &ignore_rev_list, N_("rev"), N_("ignore <rev> when blaming")),
+		OPT_STRING_LIST(0, "ignore-revs-file", &ignore_revs_file_list, N_("file"), N_("ignore revisions from <file>")),
+		OPT_BIT(0, "color-lines", &output_option, N_("color redundant metadata from previous line differently"), OUTPUT_COLOR_LINE),
+		OPT_BIT(0, "color-by-age", &output_option, N_("color lines by age"), OUTPUT_SHOW_AGE_WITH_COLOR),
+		OPT_BIT(0, "minimal", &xdl_opts, N_("spend extra cycles to find better match"), XDF_NEED_MINIMAL),
+		OPT_STRING('S', NULL, &revs_file, N_("file"), N_("use revisions from <file> instead of calling git-rev-list")),
+		OPT_STRING(0, "contents", &contents_from, N_("file"), N_("use <file>'s contents as the final image")),
+		OPT_CALLBACK_F('C', NULL, &opt, N_("score"), N_("find line copies within and across files"), PARSE_OPT_OPTARG, blame_copy_callback),
+		OPT_CALLBACK_F('M', NULL, &opt, N_("score"), N_("find line movements within and across files"), PARSE_OPT_OPTARG, blame_move_callback),
+		OPT_STRING_LIST('L', NULL, &range_list, N_("range"),
+				N_("process only line range <start>,<end> or function :<funcname>")),
+		OPT__ABBREV(&abbrev),
+		OPT_END()
+	};
+
+	struct parse_opt_ctx_t ctx;
+	int cmd_is_annotate = !strcmp(argv[0], "annotate");
+	struct range_set ranges;
+	unsigned int range_i;
+	long anchor;
+	long num_lines = 0;
+	const char *str_usage = cmd_is_annotate ? annotate_usage : blame_usage;
+	const char **opt_usage = cmd_is_annotate ? annotate_opt_usage : blame_opt_usage;
+
+	setup_default_color_by_age();
+	git_config(git_blame_config, &output_option);
+	repo_init_revisions(the_repository, &revs, NULL);
+	revs.date_mode = blame_date_mode;
+	revs.diffopt.flags.allow_textconv = 1;
+	revs.diffopt.flags.follow_renames = 1;
+
+	save_commit_buffer = 0;
+	dashdash_pos = 0;
+	show_progress = -1;
+
+	parse_options_start(&ctx, argc, argv, prefix, options,
+			    PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
+	for (;;) {
+		switch (parse_options_step(&ctx, options, opt_usage)) {
+		case PARSE_OPT_NON_OPTION:
+		case PARSE_OPT_UNKNOWN:
+			break;
+		case PARSE_OPT_HELP:
+		case PARSE_OPT_ERROR:
+		case PARSE_OPT_SUBCOMMAND:
+			exit(129);
+		case PARSE_OPT_COMPLETE:
+			exit(0);
+		case PARSE_OPT_DONE:
+			if (ctx.argv[0])
+				dashdash_pos = ctx.cpidx;
+			goto parse_done;
+		}
+
+		if (!strcmp(ctx.argv[0], "--reverse")) {
+			ctx.argv[0] = "--children";
+			reverse = 1;
+		}
+		parse_revision_opt(&revs, &ctx, options, opt_usage);
+	}
+parse_done:
+	revision_opts_finish(&revs);
+	no_whole_file_rename = !revs.diffopt.flags.follow_renames;
+	xdl_opts |= revs.diffopt.xdl_opts & XDF_INDENT_HEURISTIC;
+	revs.diffopt.flags.follow_renames = 0;
+	argc = parse_options_end(&ctx);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	if (incremental || (output_option & OUTPUT_PORCELAIN)) {
+		if (show_progress > 0)
+			die(_("--progress can't be used with --incremental or porcelain formats"));
+		show_progress = 0;
+	} else if (show_progress < 0)
+		show_progress = isatty(2);
+
+	if (0 < abbrev && abbrev < (int)the_hash_algo->hexsz)
+		/* one more abbrev length is needed for the boundary commit */
+		abbrev++;
+	else if (!abbrev)
+		abbrev = the_hash_algo->hexsz;
+
+	if (revs_file && read_ancestry(revs_file))
+		die_errno("reading graft file '%s' failed", revs_file);
+
+	if (cmd_is_annotate) {
+		output_option |= OUTPUT_ANNOTATE_COMPAT;
+		blame_date_mode.type = DATE_ISO8601;
+	} else {
+		blame_date_mode = revs.date_mode;
+	}
+
+	/* The maximum width used to show the dates */
+	switch (blame_date_mode.type) {
+	case DATE_RFC2822:
+		blame_date_width = sizeof("Thu, 19 Oct 2006 16:00:04 -0700");
+		break;
+	case DATE_ISO8601_STRICT:
+		blame_date_width = sizeof("2006-10-19T16:00:04-07:00");
+		break;
+	case DATE_ISO8601:
+		blame_date_width = sizeof("2006-10-19 16:00:04 -0700");
+		break;
+	case DATE_RAW:
+		blame_date_width = sizeof("1161298804 -0700");
+		break;
+	case DATE_UNIX:
+		blame_date_width = sizeof("1161298804");
+		break;
+	case DATE_SHORT:
+		blame_date_width = sizeof("2006-10-19");
+		break;
+	case DATE_RELATIVE:
+		/*
+		 * TRANSLATORS: This string is used to tell us the
+		 * maximum display width for a relative timestamp in
+		 * "git blame" output.  For C locale, "4 years, 11
+		 * months ago", which takes 22 places, is the longest
+		 * among various forms of relative timestamps, but
+		 * your language may need more or fewer display
+		 * columns.
+		 */
+		blame_date_width = utf8_strwidth(_("4 years, 11 months ago")) + 1; /* add the null */
+		break;
+	case DATE_HUMAN:
+		/* If the year is shown, no time is shown */
+		blame_date_width = sizeof("Thu Oct 19 16:00");
+		break;
+	case DATE_NORMAL:
+		blame_date_width = sizeof("Thu Oct 19 16:00:04 2006 -0700");
+		break;
+	case DATE_STRFTIME:
+		blame_date_width = strlen(show_date(0, 0, blame_date_mode)) + 1; /* add the null */
+		break;
+	}
+	blame_date_width -= 1; /* strip the null */
+
+	if (revs.diffopt.flags.find_copies_harder)
+		opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
+			PICKAXE_BLAME_COPY_HARDER);
+
+	/*
+	 * We have collected options unknown to us in argv[1..unk]
+	 * which are to be passed to revision machinery if we are
+	 * going to do the "bottom" processing.
+	 *
+	 * The remaining are:
+	 *
+	 * (1) if dashdash_pos != 0, it is either
+	 *     "blame [revisions] -- <path>" or
+	 *     "blame -- <path> <rev>"
+	 *
+	 * (2) otherwise, it is one of the two:
+	 *     "blame [revisions] <path>"
+	 *     "blame <path> <rev>"
+	 *
+	 * Note that we must strip out <path> from the arguments: we do not
+	 * want the path pruning but we may want "bottom" processing.
+	 */
+	if (dashdash_pos) {
+		switch (argc - dashdash_pos - 1) {
+		case 2: /* (1b) */
+			if (argc != 4)
+				usage_with_options(opt_usage, options);
+			/* reorder for the new way: <rev> -- <path> */
+			argv[1] = argv[3];
+			argv[3] = argv[2];
+			argv[2] = "--";
+			/* FALLTHROUGH */
+		case 1: /* (1a) */
+			path = add_prefix(prefix, argv[--argc]);
+			argv[argc] = NULL;
+			break;
+		default:
+			usage_with_options(opt_usage, options);
+		}
+	} else {
+		if (argc < 2)
+			usage_with_options(opt_usage, options);
+		if (argc == 3 && is_a_rev(argv[argc - 1])) { /* (2b) */
+			path = add_prefix(prefix, argv[1]);
+			argv[1] = argv[2];
+		} else {	/* (2a) */
+			if (argc == 2 && is_a_rev(argv[1]) && !repo_get_work_tree(the_repository))
+				die("missing <path> to blame");
+			path = add_prefix(prefix, argv[argc - 1]);
+		}
+		argv[argc - 1] = "--";
+	}
+
+	revs.disable_stdin = 1;
+	setup_revisions(argc, argv, &revs, NULL);
+	if (!revs.pending.nr && is_bare_repository()) {
+		struct commit *head_commit;
+		struct object_id head_oid;
+
+		if (!refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", RESOLVE_REF_READING,
+					     &head_oid, NULL) ||
+		    !(head_commit = lookup_commit_reference_gently(revs.repo,
+							     &head_oid, 1)))
+			die("no such ref: HEAD");
+
+		add_pending_object(&revs, &head_commit->object, "HEAD");
+	}
+
+	init_scoreboard(&sb);
+	sb.revs = &revs;
+	sb.contents_from = contents_from;
+	sb.reverse = reverse;
+	sb.repo = the_repository;
+	sb.path = path;
+	build_ignorelist(&sb, &ignore_revs_file_list, &ignore_rev_list);
+	string_list_clear(&ignore_revs_file_list, 0);
+	string_list_clear(&ignore_rev_list, 0);
+	setup_scoreboard(&sb, &o);
+
+	/*
+	 * Changed-path Bloom filters are disabled when looking
+	 * for copies.
+	 */
+	if (!(opt & PICKAXE_BLAME_COPY))
+		setup_blame_bloom_data(&sb);
+
+	lno = sb.num_lines;
+
+	if (lno && !range_list.nr)
+		string_list_append(&range_list, "1");
+
+	anchor = 1;
+	range_set_init(&ranges, range_list.nr);
+	for (range_i = 0; range_i < range_list.nr; ++range_i) {
+		long bottom, top;
+		if (parse_range_arg(range_list.items[range_i].string,
+				    nth_line_cb, &sb, lno, anchor,
+				    &bottom, &top, sb.path,
+				    the_repository->index))
+			usage(str_usage);
+		if ((!lno && (top || bottom)) || lno < bottom)
+			die(Q_("file %s has only %lu line",
+			       "file %s has only %lu lines",
+			       lno), sb.path, lno);
+		if (bottom < 1)
+			bottom = 1;
+		if (top < 1 || lno < top)
+			top = lno;
+		bottom--;
+		range_set_append_unsafe(&ranges, bottom, top);
+		anchor = top + 1;
+	}
+	sort_and_merge_range_set(&ranges);
+
+	for (range_i = ranges.nr; range_i > 0; --range_i) {
+		const struct range *r = &ranges.ranges[range_i - 1];
+		ent = blame_entry_prepend(ent, r->start, r->end, o);
+		num_lines += (r->end - r->start);
+	}
+	if (!num_lines)
+		num_lines = sb.num_lines;
+
+	o->suspects = ent;
+	prio_queue_put(&sb.commits, o->commit);
+
+	blame_origin_decref(o);
+
+	range_set_release(&ranges);
+	string_list_clear(&range_list, 0);
+
+	sb.ent = NULL;
+
+	if (blame_move_score)
+		sb.move_score = blame_move_score;
+	if (blame_copy_score)
+		sb.copy_score = blame_copy_score;
+
+	sb.debug = DEBUG_BLAME;
+	sb.on_sanity_fail = &sanity_check_on_fail;
+
+	sb.show_root = show_root;
+	sb.xdl_opts = xdl_opts;
+	sb.no_whole_file_rename = no_whole_file_rename;
+
+	read_mailmap(&mailmap);
+
+	sb.found_guilty_entry = &found_guilty_entry;
+	sb.found_guilty_entry_data = &pi;
+	if (show_progress)
+		pi.progress = start_delayed_progress(the_repository,
+						     _("Blaming lines"),
+						     num_lines);
+
+	assign_blame(&sb, opt);
+
+	stop_progress(&pi.progress);
+
+	if (!incremental)
+		setup_pager(the_repository);
+	else
+		goto cleanup;
+
+	blame_sort_final(&sb);
+
+	blame_coalesce(&sb);
+
+	if (!(output_option & (OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR)))
+		output_option |= coloring_mode;
+
+	if (!(output_option & OUTPUT_PORCELAIN)) {
+		find_alignment(&sb, &output_option);
+		if (!*repeated_meta_color &&
+		    (output_option & OUTPUT_COLOR_LINE))
+			xsnprintf(repeated_meta_color,
+				  sizeof(repeated_meta_color),
+				  "%s", GIT_COLOR_CYAN);
+	}
+	if (output_option & OUTPUT_ANNOTATE_COMPAT)
+		output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
+
+	output(&sb, output_option);
+
+	if (show_stats) {
+		printf("num read blob: %d\n", sb.num_read_blob);
+		printf("num get patch: %d\n", sb.num_get_patch);
+		printf("num commits: %d\n", sb.num_commits);
+	}
+
+cleanup:
+	for (ent = sb.ent; ent; ) {
+		struct blame_entry *e = ent->next;
+		free(ent);
+		ent = e;
+	}
+
+	free(path);
+	cleanup_scoreboard(&sb);
+	release_revisions(&revs);
+	return 0;
+}
diff --git a/builtin/branch.c b/builtin/branch.c
new file mode 100644
index 0000000000..c150131bd9
--- /dev/null
+++ b/builtin/branch.c
@@ -0,0 +1,1023 @@
+/*
+ * Builtin "git branch"
+ *
+ * Copyright (c) 2006 Kristian Høgsberg <krh@xxxxxxxxxx>
+ * Based on git-branch.sh by Junio C Hamano.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "color.h"
+#include "editor.h"
+#include "environment.h"
+#include "refs.h"
+#include "commit.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "remote.h"
+#include "parse-options.h"
+#include "branch.h"
+#include "path.h"
+#include "string-list.h"
+#include "column.h"
+#include "utf8.h"
+#include "ref-filter.h"
+#include "worktree.h"
+#include "help.h"
+#include "advice.h"
+#include "commit-reach.h"
+
+static const char * const builtin_branch_usage[] = {
+	N_("git branch [<options>] [-r | -a] [--merged] [--no-merged]"),
+	N_("git branch [<options>] [-f] [--recurse-submodules] <branch-name> [<start-point>]"),
+	N_("git branch [<options>] [-l] [<pattern>...]"),
+	N_("git branch [<options>] [-r] (-d | -D) <branch-name>..."),
+	N_("git branch [<options>] (-m | -M) [<old-branch>] <new-branch>"),
+	N_("git branch [<options>] (-c | -C) [<old-branch>] <new-branch>"),
+	N_("git branch [<options>] [-r | -a] [--points-at]"),
+	N_("git branch [<options>] [-r | -a] [--format]"),
+	NULL
+};
+
+static const char *head;
+static struct object_id head_oid;
+static int recurse_submodules = 0;
+static int submodule_propagate_branches = 0;
+
+static int branch_use_color = -1;
+static char branch_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_NORMAL,       /* PLAIN */
+	GIT_COLOR_RED,          /* REMOTE */
+	GIT_COLOR_NORMAL,       /* LOCAL */
+	GIT_COLOR_GREEN,        /* CURRENT */
+	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
+};
+enum color_branch {
+	BRANCH_COLOR_RESET = 0,
+	BRANCH_COLOR_PLAIN = 1,
+	BRANCH_COLOR_REMOTE = 2,
+	BRANCH_COLOR_LOCAL = 3,
+	BRANCH_COLOR_CURRENT = 4,
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
+};
+
+static const char *color_branch_slots[] = {
+	[BRANCH_COLOR_RESET]	= "reset",
+	[BRANCH_COLOR_PLAIN]	= "plain",
+	[BRANCH_COLOR_REMOTE]	= "remote",
+	[BRANCH_COLOR_LOCAL]	= "local",
+	[BRANCH_COLOR_CURRENT]	= "current",
+	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
+};
+
+static struct string_list output = STRING_LIST_INIT_DUP;
+static unsigned int colopts;
+
+define_list_config_array(color_branch_slots);
+
+static int git_branch_config(const char *var, const char *value,
+			     const struct config_context *ctx, void *cb)
+{
+	const char *slot_name;
+
+	if (!strcmp(var, "branch.sort")) {
+		if (!value)
+			return config_error_nonbool(var);
+		string_list_append(cb, value);
+		return 0;
+	}
+
+	if (starts_with(var, "column."))
+		return git_column_config(var, value, "branch", &colopts);
+	if (!strcmp(var, "color.branch")) {
+		branch_use_color = git_config_colorbool(var, value);
+		return 0;
+	}
+	if (skip_prefix(var, "color.branch.", &slot_name)) {
+		int slot = LOOKUP_CONFIG(color_branch_slots, slot_name);
+		if (slot < 0)
+			return 0;
+		if (!value)
+			return config_error_nonbool(var);
+		return color_parse(value, branch_colors[slot]);
+	}
+	if (!strcmp(var, "submodule.recurse")) {
+		recurse_submodules = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcasecmp(var, "submodule.propagateBranches")) {
+		submodule_propagate_branches = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (git_color_config(var, value, cb) < 0)
+		return -1;
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static const char *branch_get_color(enum color_branch ix)
+{
+	if (want_color(branch_use_color))
+		return branch_colors[ix];
+	return "";
+}
+
+static int branch_merged(int kind, const char *name,
+			 struct commit *rev, struct commit *head_rev)
+{
+	/*
+	 * This checks whether the merge bases of branch and HEAD (or
+	 * the other branch this branch builds upon) contains the
+	 * branch, which means that the branch has already been merged
+	 * safely to HEAD (or the other branch).
+	 */
+	struct commit *reference_rev = NULL;
+	const char *reference_name = NULL;
+	void *reference_name_to_free = NULL;
+	int merged;
+
+	if (kind == FILTER_REFS_BRANCHES) {
+		struct branch *branch = branch_get(name);
+		const char *upstream = branch_get_upstream(branch, NULL);
+		struct object_id oid;
+
+		if (upstream &&
+		    (reference_name = reference_name_to_free =
+		     refs_resolve_refdup(get_main_ref_store(the_repository), upstream, RESOLVE_REF_READING,
+					 &oid, NULL)) != NULL)
+			reference_rev = lookup_commit_reference(the_repository,
+								&oid);
+	}
+	if (!reference_rev)
+		reference_rev = head_rev;
+
+	merged = reference_rev ? repo_in_merge_bases(the_repository, rev,
+						     reference_rev) : 0;
+	if (merged < 0)
+		exit(128);
+
+	/*
+	 * After the safety valve is fully redefined to "check with
+	 * upstream, if any, otherwise with HEAD", we should just
+	 * return the result of the repo_in_merge_bases() above without
+	 * any of the following code, but during the transition period,
+	 * a gentle reminder is in order.
+	 */
+	if (head_rev != reference_rev) {
+		int expect = head_rev ? repo_in_merge_bases(the_repository, rev, head_rev) : 0;
+		if (expect < 0)
+			exit(128);
+		if (expect == merged)
+			; /* okay */
+		else if (merged)
+			warning(_("deleting branch '%s' that has been merged to\n"
+				"         '%s', but not yet merged to HEAD"),
+				name, reference_name);
+		else
+			warning(_("not deleting branch '%s' that is not yet merged to\n"
+				"         '%s', even though it is merged to HEAD"),
+				name, reference_name);
+	}
+	free(reference_name_to_free);
+	return merged;
+}
+
+static int check_branch_commit(const char *branchname, const char *refname,
+			       const struct object_id *oid, struct commit *head_rev,
+			       int kinds, int force)
+{
+	struct commit *rev = lookup_commit_reference(the_repository, oid);
+	if (!force && !rev) {
+		error(_("couldn't look up commit object for '%s'"), refname);
+		return -1;
+	}
+	if (!force && !branch_merged(kinds, branchname, rev, head_rev)) {
+		error(_("the branch '%s' is not fully merged"), branchname);
+		advise_if_enabled(ADVICE_FORCE_DELETE_BRANCH,
+				  _("If you are sure you want to delete it, "
+				  "run 'git branch -D %s'"), branchname);
+		return -1;
+	}
+	return 0;
+}
+
+static void delete_branch_config(const char *branchname)
+{
+	struct strbuf buf = STRBUF_INIT;
+	strbuf_addf(&buf, "branch.%s", branchname);
+	if (repo_config_rename_section(the_repository, buf.buf, NULL) < 0)
+		warning(_("update of config-file failed"));
+	strbuf_release(&buf);
+}
+
+static int delete_branches(int argc, const char **argv, int force, int kinds,
+			   int quiet)
+{
+	struct commit *head_rev = NULL;
+	struct object_id oid;
+	char *name = NULL;
+	const char *fmt;
+	int i;
+	int ret = 0;
+	int remote_branch = 0;
+	struct strbuf bname = STRBUF_INIT;
+	unsigned allowed_interpret;
+	struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
+	struct string_list_item *item;
+	int branch_name_pos;
+	const char *fmt_remotes = "refs/remotes/%s";
+
+	switch (kinds) {
+	case FILTER_REFS_REMOTES:
+		fmt = fmt_remotes;
+		/* For subsequent UI messages */
+		remote_branch = 1;
+		allowed_interpret = INTERPRET_BRANCH_REMOTE;
+
+		force = 1;
+		break;
+	case FILTER_REFS_BRANCHES:
+		fmt = "refs/heads/%s";
+		allowed_interpret = INTERPRET_BRANCH_LOCAL;
+		break;
+	default:
+		die(_("cannot use -a with -d"));
+	}
+	branch_name_pos = strcspn(fmt, "%");
+
+	if (!force)
+		head_rev = lookup_commit_reference(the_repository, &head_oid);
+
+	for (i = 0; i < argc; i++, strbuf_reset(&bname)) {
+		char *target = NULL;
+		int flags = 0;
+
+		copy_branchname(&bname, argv[i], allowed_interpret);
+		free(name);
+		name = mkpathdup(fmt, bname.buf);
+
+		if (kinds == FILTER_REFS_BRANCHES) {
+			const char *path;
+			if ((path = branch_checked_out(name))) {
+				error(_("cannot delete branch '%s' "
+					"used by worktree at '%s'"),
+				      bname.buf, path);
+				ret = 1;
+				continue;
+			}
+		}
+
+		target = refs_resolve_refdup(get_main_ref_store(the_repository),
+					     name,
+					     RESOLVE_REF_READING
+					     | RESOLVE_REF_NO_RECURSE
+					     | RESOLVE_REF_ALLOW_BAD_NAME,
+					     &oid, &flags);
+		if (!target) {
+			if (remote_branch) {
+				error(_("remote-tracking branch '%s' not found"), bname.buf);
+			} else {
+				char *virtual_name = mkpathdup(fmt_remotes, bname.buf);
+				char *virtual_target = refs_resolve_refdup(get_main_ref_store(the_repository),
+									   virtual_name,
+									   RESOLVE_REF_READING
+									   | RESOLVE_REF_NO_RECURSE
+									   | RESOLVE_REF_ALLOW_BAD_NAME,
+									   &oid,
+									   &flags);
+				FREE_AND_NULL(virtual_name);
+
+				if (virtual_target)
+					error(_("branch '%s' not found.\n"
+						"Did you forget --remote?"),
+						bname.buf);
+				else
+					error(_("branch '%s' not found"), bname.buf);
+				FREE_AND_NULL(virtual_target);
+			}
+			ret = 1;
+			continue;
+		}
+
+		if (!(flags & (REF_ISSYMREF|REF_ISBROKEN)) &&
+		    check_branch_commit(bname.buf, name, &oid, head_rev, kinds,
+					force)) {
+			ret = 1;
+			goto next;
+		}
+
+		item = string_list_append(&refs_to_delete, name);
+		item->util = xstrdup((flags & REF_ISBROKEN) ? "broken"
+				    : (flags & REF_ISSYMREF) ? target
+				    : repo_find_unique_abbrev(the_repository, &oid, DEFAULT_ABBREV));
+
+	next:
+		free(target);
+	}
+
+	if (refs_delete_refs(get_main_ref_store(the_repository), NULL, &refs_to_delete, REF_NO_DEREF))
+		ret = 1;
+
+	for_each_string_list_item(item, &refs_to_delete) {
+		char *describe_ref = item->util;
+		char *name = item->string;
+		if (!refs_ref_exists(get_main_ref_store(the_repository), name)) {
+			char *refname = name + branch_name_pos;
+			if (!quiet)
+				printf(remote_branch
+					? _("Deleted remote-tracking branch %s (was %s).\n")
+					: _("Deleted branch %s (was %s).\n"),
+					name + branch_name_pos, describe_ref);
+
+			delete_branch_config(refname);
+		}
+		free(describe_ref);
+	}
+	string_list_clear(&refs_to_delete, 0);
+
+	free(name);
+	strbuf_release(&bname);
+
+	return ret;
+}
+
+static int calc_maxwidth(struct ref_array *refs, int remote_bonus)
+{
+	int i, max = 0;
+	for (i = 0; i < refs->nr; i++) {
+		struct ref_array_item *it = refs->items[i];
+		const char *desc = it->refname;
+		int w;
+
+		skip_prefix(it->refname, "refs/heads/", &desc);
+		skip_prefix(it->refname, "refs/remotes/", &desc);
+		if (it->kind == FILTER_REFS_DETACHED_HEAD) {
+			char *head_desc = get_head_description();
+			w = utf8_strwidth(head_desc);
+			free(head_desc);
+		} else
+			w = utf8_strwidth(desc);
+
+		if (it->kind == FILTER_REFS_REMOTES)
+			w += remote_bonus;
+		if (w > max)
+			max = w;
+	}
+	return max;
+}
+
+static const char *quote_literal_for_format(const char *s)
+{
+	static struct strbuf buf = STRBUF_INIT;
+
+	strbuf_reset(&buf);
+	while (strbuf_expand_step(&buf, &s))
+		strbuf_addstr(&buf, "%%");
+	return buf.buf;
+}
+
+static char *build_format(struct ref_filter *filter, int maxwidth, const char *remote_prefix)
+{
+	struct strbuf fmt = STRBUF_INIT;
+	struct strbuf local = STRBUF_INIT;
+	struct strbuf remote = STRBUF_INIT;
+
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&remote, "  %s",
+		    branch_get_color(BRANCH_COLOR_REMOTE));
+
+	if (filter->verbose) {
+		struct strbuf obname = STRBUF_INIT;
+
+		if (filter->abbrev < 0)
+			strbuf_addf(&obname, "%%(objectname:short)");
+		else if (!filter->abbrev)
+			strbuf_addf(&obname, "%%(objectname)");
+		else
+			strbuf_addf(&obname, "%%(objectname:short=%d)", filter->abbrev);
+
+		strbuf_addf(&local, "%%(align:%d,left)%%(refname:lstrip=2)%%(end)", maxwidth);
+		strbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));
+		strbuf_addf(&local, " %s ", obname.buf);
+
+		if (filter->verbose > 1)
+		{
+			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
+			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
+				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
+				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+		}
+		else
+			strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
+
+		strbuf_addf(&remote, "%%(align:%d,left)%s%%(refname:lstrip=2)%%(end)%s"
+			    "%%(if)%%(symref)%%(then) -> %%(symref:short)"
+			    "%%(else) %s %%(contents:subject)%%(end)",
+			    maxwidth, quote_literal_for_format(remote_prefix),
+			    branch_get_color(BRANCH_COLOR_RESET), obname.buf);
+		strbuf_release(&obname);
+	} else {
+		strbuf_addf(&local, "%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+			    branch_get_color(BRANCH_COLOR_RESET));
+		strbuf_addf(&remote, "%s%%(refname:lstrip=2)%s%%(if)%%(symref)%%(then) -> %%(symref:short)%%(end)",
+			    quote_literal_for_format(remote_prefix),
+			    branch_get_color(BRANCH_COLOR_RESET));
+	}
+
+	strbuf_addf(&fmt, "%%(if:notequals=refs/remotes)%%(refname:rstrip=-2)%%(then)%s%%(else)%s%%(end)", local.buf, remote.buf);
+
+	strbuf_release(&local);
+	strbuf_release(&remote);
+	return strbuf_detach(&fmt, NULL);
+}
+
+static void print_ref_list(struct ref_filter *filter, struct ref_sorting *sorting,
+			   struct ref_format *format, struct string_list *output)
+{
+	int i;
+	struct ref_array array;
+	int maxwidth = 0;
+	const char *remote_prefix = "";
+	char *to_free = NULL;
+
+	/*
+	 * If we are listing more than just remote branches,
+	 * then remote branches will have a "remotes/" prefix.
+	 * We need to account for this in the width.
+	 */
+	if (filter->kind != FILTER_REFS_REMOTES)
+		remote_prefix = "remotes/";
+
+	memset(&array, 0, sizeof(array));
+
+	filter_refs(&array, filter, filter->kind);
+
+	if (filter->verbose)
+		maxwidth = calc_maxwidth(&array, strlen(remote_prefix));
+
+	if (!format->format)
+		format->format = to_free = build_format(filter, maxwidth, remote_prefix);
+	format->use_color = branch_use_color;
+
+	if (verify_ref_format(format))
+		die(_("unable to parse format string"));
+
+	filter_ahead_behind(the_repository, &array);
+	ref_array_sort(sorting, &array);
+
+	if (column_active(colopts)) {
+		struct strbuf out = STRBUF_INIT, err = STRBUF_INIT;
+
+		assert(!filter->verbose && "--column and --verbose are incompatible");
+
+		for (i = 0; i < array.nr; i++) {
+			strbuf_reset(&err);
+			strbuf_reset(&out);
+			if (format_ref_array_item(array.items[i], format, &out, &err))
+				die("%s", err.buf);
+
+			/* format to a string_list to let print_columns() do its job */
+			string_list_append(output, out.buf);
+		}
+
+		strbuf_release(&err);
+		strbuf_release(&out);
+	} else {
+		print_formatted_ref_array(&array, format);
+	}
+
+	ref_array_clear(&array);
+	free(to_free);
+}
+
+static void print_current_branch_name(void)
+{
+	int flags;
+	const char *refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+						      "HEAD", 0, NULL, &flags);
+	const char *shortname;
+	if (!refname)
+		die(_("could not resolve HEAD"));
+	else if (!(flags & REF_ISSYMREF))
+		return;
+	else if (skip_prefix(refname, "refs/heads/", &shortname))
+		puts(shortname);
+	else
+		die(_("HEAD (%s) points outside of refs/heads/"), refname);
+}
+
+static void reject_rebase_or_bisect_branch(struct worktree **worktrees,
+					   const char *target)
+{
+	int i;
+
+	for (i = 0; worktrees[i]; i++) {
+		struct worktree *wt = worktrees[i];
+
+		if (!wt->is_detached)
+			continue;
+
+		if (is_worktree_being_rebased(wt, target))
+			die(_("branch %s is being rebased at %s"),
+			    target, wt->path);
+
+		if (is_worktree_being_bisected(wt, target))
+			die(_("branch %s is being bisected at %s"),
+			    target, wt->path);
+	}
+}
+
+/*
+ * Update all per-worktree HEADs pointing at the old ref to point the new ref.
+ * This will be used when renaming a branch. Returns 0 if successful, non-zero
+ * otherwise.
+ */
+static int replace_each_worktree_head_symref(struct worktree **worktrees,
+					     const char *oldref, const char *newref,
+					     const char *logmsg)
+{
+	int ret = 0;
+	int i;
+
+	for (i = 0; worktrees[i]; i++) {
+		struct ref_store *refs;
+
+		if (worktrees[i]->is_detached)
+			continue;
+		if (!worktrees[i]->head_ref)
+			continue;
+		if (strcmp(oldref, worktrees[i]->head_ref))
+			continue;
+
+		refs = get_worktree_ref_store(worktrees[i]);
+		if (refs_update_symref(refs, "HEAD", newref, logmsg))
+			ret = error(_("HEAD of working tree %s is not updated"),
+				    worktrees[i]->path);
+	}
+
+	return ret;
+}
+
+#define IS_HEAD 1
+#define IS_ORPHAN 2
+
+static void copy_or_rename_branch(const char *oldname, const char *newname, int copy, int force)
+{
+	struct strbuf oldref = STRBUF_INIT, newref = STRBUF_INIT, logmsg = STRBUF_INIT;
+	struct strbuf oldsection = STRBUF_INIT, newsection = STRBUF_INIT;
+	const char *interpreted_oldname = NULL;
+	const char *interpreted_newname = NULL;
+	int recovery = 0, oldref_usage = 0;
+	struct worktree **worktrees = get_worktrees();
+
+	if (check_branch_ref(&oldref, oldname)) {
+		/*
+		 * Bad name --- this could be an attempt to rename a
+		 * ref that we used to allow to be created by accident.
+		 */
+		if (refs_ref_exists(get_main_ref_store(the_repository), oldref.buf))
+			recovery = 1;
+		else {
+			int code = die_message(_("invalid branch name: '%s'"), oldname);
+			advise_if_enabled(ADVICE_REF_SYNTAX,
+					  _("See `man git check-ref-format`"));
+			exit(code);
+		}
+	}
+
+	for (int i = 0; worktrees[i]; i++) {
+		struct worktree *wt = worktrees[i];
+
+		if (wt->head_ref && !strcmp(oldref.buf, wt->head_ref)) {
+			oldref_usage |= IS_HEAD;
+			if (is_null_oid(&wt->head_oid))
+				oldref_usage |= IS_ORPHAN;
+			break;
+		}
+	}
+
+	if ((copy || !(oldref_usage & IS_HEAD)) && !refs_ref_exists(get_main_ref_store(the_repository), oldref.buf)) {
+		if (oldref_usage & IS_HEAD)
+			die(_("no commit on branch '%s' yet"), oldname);
+		else
+			die(_("no branch named '%s'"), oldname);
+	}
+
+	/*
+	 * A command like "git branch -M currentbranch currentbranch" cannot
+	 * cause the worktree to become inconsistent with HEAD, so allow it.
+	 */
+	if (!strcmp(oldname, newname))
+		validate_branchname(newname, &newref);
+	else
+		validate_new_branchname(newname, &newref, force);
+
+	reject_rebase_or_bisect_branch(worktrees, oldref.buf);
+
+	if (!skip_prefix(oldref.buf, "refs/heads/", &interpreted_oldname) ||
+	    !skip_prefix(newref.buf, "refs/heads/", &interpreted_newname)) {
+		BUG("expected prefix missing for refs");
+	}
+
+	if (copy)
+		strbuf_addf(&logmsg, "Branch: copied %s to %s",
+			    oldref.buf, newref.buf);
+	else
+		strbuf_addf(&logmsg, "Branch: renamed %s to %s",
+			    oldref.buf, newref.buf);
+
+	if (!copy && !(oldref_usage & IS_ORPHAN) &&
+	    refs_rename_ref(get_main_ref_store(the_repository), oldref.buf, newref.buf, logmsg.buf))
+		die(_("branch rename failed"));
+	if (copy && refs_copy_existing_ref(get_main_ref_store(the_repository), oldref.buf, newref.buf, logmsg.buf))
+		die(_("branch copy failed"));
+
+	if (recovery) {
+		if (copy)
+			warning(_("created a copy of a misnamed branch '%s'"),
+				interpreted_oldname);
+		else
+			warning(_("renamed a misnamed branch '%s' away"),
+				interpreted_oldname);
+	}
+
+	if (!copy && (oldref_usage & IS_HEAD) &&
+	    replace_each_worktree_head_symref(worktrees, oldref.buf, newref.buf,
+					      logmsg.buf))
+		die(_("branch renamed to %s, but HEAD is not updated"), newname);
+
+	strbuf_release(&logmsg);
+
+	strbuf_addf(&oldsection, "branch.%s", interpreted_oldname);
+	strbuf_addf(&newsection, "branch.%s", interpreted_newname);
+	if (!copy && repo_config_rename_section(the_repository, oldsection.buf, newsection.buf) < 0)
+		die(_("branch is renamed, but update of config-file failed"));
+	if (copy && strcmp(interpreted_oldname, interpreted_newname) &&
+	    repo_config_copy_section(the_repository, oldsection.buf, newsection.buf) < 0)
+		die(_("branch is copied, but update of config-file failed"));
+	strbuf_release(&oldref);
+	strbuf_release(&newref);
+	strbuf_release(&oldsection);
+	strbuf_release(&newsection);
+	free_worktrees(worktrees);
+}
+
+static GIT_PATH_FUNC(edit_description, "EDIT_DESCRIPTION")
+
+static int edit_branch_description(const char *branch_name)
+{
+	int exists;
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf name = STRBUF_INIT;
+
+	exists = !read_branch_desc(&buf, branch_name);
+	if (!buf.len || buf.buf[buf.len-1] != '\n')
+		strbuf_addch(&buf, '\n');
+	strbuf_commented_addf(&buf, comment_line_str,
+		    _("Please edit the description for the branch\n"
+		      "  %s\n"
+		      "Lines starting with '%s' will be stripped.\n"),
+		    branch_name, comment_line_str);
+	write_file_buf(edit_description(), buf.buf, buf.len);
+	strbuf_reset(&buf);
+	if (launch_editor(edit_description(), &buf, NULL)) {
+		strbuf_release(&buf);
+		return -1;
+	}
+	strbuf_stripspace(&buf, comment_line_str);
+
+	strbuf_addf(&name, "branch.%s.description", branch_name);
+	if (buf.len || exists)
+		git_config_set(name.buf, buf.len ? buf.buf : NULL);
+	strbuf_release(&name);
+	strbuf_release(&buf);
+
+	return 0;
+}
+
+int cmd_branch(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	/* possible actions */
+	int delete = 0, rename = 0, copy = 0, list = 0,
+	    unset_upstream = 0, show_current = 0, edit_description = 0;
+	const char *new_upstream = NULL;
+	int noncreate_actions = 0;
+	/* possible options */
+	int reflog = 0, quiet = 0, icase = 0, force = 0,
+	    recurse_submodules_explicit = 0;
+	enum branch_track track;
+	struct ref_filter filter = REF_FILTER_INIT;
+	static struct ref_sorting *sorting;
+	struct string_list sorting_options = STRING_LIST_INIT_DUP;
+	struct ref_format format = REF_FORMAT_INIT;
+	int ret;
+
+	struct option options[] = {
+		OPT_GROUP(N_("Generic options")),
+		OPT__VERBOSE(&filter.verbose,
+			N_("show hash and subject, give twice for upstream branch")),
+		OPT__QUIET(&quiet, N_("suppress informational messages")),
+		OPT_CALLBACK_F('t', "track",  &track, "(direct|inherit)",
+			N_("set branch tracking configuration"),
+			PARSE_OPT_OPTARG,
+			parse_opt_tracking_mode),
+		OPT_SET_INT_F(0, "set-upstream", &track, N_("do not use"),
+			BRANCH_TRACK_OVERRIDE, PARSE_OPT_HIDDEN),
+		OPT_STRING('u', "set-upstream-to", &new_upstream, N_("upstream"), N_("change the upstream info")),
+		OPT_BOOL(0, "unset-upstream", &unset_upstream, N_("unset the upstream info")),
+		OPT__COLOR(&branch_use_color, N_("use colored output")),
+		OPT_SET_INT_F('r', "remotes",     &filter.kind, N_("act on remote-tracking branches"),
+			      FILTER_REFS_REMOTES,
+			      PARSE_OPT_NONEG),
+		OPT_CONTAINS(&filter.with_commit, N_("print only branches that contain the commit")),
+		OPT_NO_CONTAINS(&filter.no_commit, N_("print only branches that don't contain the commit")),
+		OPT_WITH(&filter.with_commit, N_("print only branches that contain the commit")),
+		OPT_WITHOUT(&filter.no_commit, N_("print only branches that don't contain the commit")),
+		OPT__ABBREV(&filter.abbrev),
+
+		OPT_GROUP(N_("Specific git-branch actions:")),
+		OPT_SET_INT_F('a', "all", &filter.kind, N_("list both remote-tracking and local branches"),
+			      FILTER_REFS_REMOTES | FILTER_REFS_BRANCHES,
+			      PARSE_OPT_NONEG),
+		OPT_BIT('d', "delete", &delete, N_("delete fully merged branch"), 1),
+		OPT_BIT('D', NULL, &delete, N_("delete branch (even if not merged)"), 2),
+		OPT_BIT('m', "move", &rename, N_("move/rename a branch and its reflog"), 1),
+		OPT_BIT('M', NULL, &rename, N_("move/rename a branch, even if target exists"), 2),
+		OPT_BOOL(0, "omit-empty",  &format.array_opts.omit_empty,
+			N_("do not output a newline after empty formatted refs")),
+		OPT_BIT('c', "copy", &copy, N_("copy a branch and its reflog"), 1),
+		OPT_BIT('C', NULL, &copy, N_("copy a branch, even if target exists"), 2),
+		OPT_BOOL('l', "list", &list, N_("list branch names")),
+		OPT_BOOL(0, "show-current", &show_current, N_("show current branch name")),
+		OPT_BOOL(0, "create-reflog", &reflog, N_("create the branch's reflog")),
+		OPT_BOOL(0, "edit-description", &edit_description,
+			 N_("edit the description for the branch")),
+		OPT__FORCE(&force, N_("force creation, move/rename, deletion"), PARSE_OPT_NOCOMPLETE),
+		OPT_MERGED(&filter, N_("print only branches that are merged")),
+		OPT_NO_MERGED(&filter, N_("print only branches that are not merged")),
+		OPT_COLUMN(0, "column", &colopts, N_("list branches in columns")),
+		OPT_REF_SORT(&sorting_options),
+		OPT_CALLBACK(0, "points-at", &filter.points_at, N_("object"),
+			N_("print only branches of the object"), parse_opt_object_name),
+		OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+		OPT_BOOL(0, "recurse-submodules", &recurse_submodules_explicit, N_("recurse through submodules")),
+		OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
+		OPT_END(),
+	};
+
+	setup_ref_filter_porcelain_msg();
+
+	filter.kind = FILTER_REFS_BRANCHES;
+	filter.abbrev = -1;
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_branch_usage, options);
+
+	/*
+	 * Try to set sort keys from config. If config does not set any,
+	 * fall back on default (refname) sorting.
+	 */
+	git_config(git_branch_config, &sorting_options);
+	if (!sorting_options.nr)
+		string_list_append(&sorting_options, "refname");
+
+	track = git_branch_track;
+
+	head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+				   0, &head_oid, NULL);
+	if (!head)
+		die(_("failed to resolve HEAD as a valid ref"));
+	if (!strcmp(head, "HEAD"))
+		filter.detached = 1;
+	else if (!skip_prefix(head, "refs/heads/", &head))
+		die(_("HEAD not found below refs/heads!"));
+
+	argc = parse_options(argc, argv, prefix, options, builtin_branch_usage,
+			     0);
+
+	if (!delete && !rename && !copy && !edit_description && !new_upstream &&
+	    !show_current && !unset_upstream && argc == 0)
+		list = 1;
+
+	if (filter.with_commit || filter.no_commit ||
+	    filter.reachable_from || filter.unreachable_from || filter.points_at.nr)
+		list = 1;
+
+	noncreate_actions = !!delete + !!rename + !!copy + !!new_upstream +
+			    !!show_current + !!list + !!edit_description +
+			    !!unset_upstream;
+	if (noncreate_actions > 1)
+		usage_with_options(builtin_branch_usage, options);
+
+	if (recurse_submodules_explicit) {
+		if (!submodule_propagate_branches)
+			die(_("branch with --recurse-submodules can only be used if submodule.propagateBranches is enabled"));
+		if (noncreate_actions)
+			die(_("--recurse-submodules can only be used to create branches"));
+	}
+
+	recurse_submodules =
+		(recurse_submodules || recurse_submodules_explicit) &&
+		submodule_propagate_branches;
+
+	if (filter.abbrev == -1)
+		filter.abbrev = DEFAULT_ABBREV;
+	filter.ignore_case = icase;
+
+	finalize_colopts(&colopts, -1);
+	if (filter.verbose) {
+		if (explicitly_enable_column(colopts))
+			die(_("options '%s' and '%s' cannot be used together"), "--column", "--verbose");
+		colopts = 0;
+	}
+
+	if (force) {
+		delete *= 2;
+		rename *= 2;
+		copy *= 2;
+	}
+
+	if (list)
+		setup_auto_pager("branch", 1);
+
+	if (delete) {
+		if (!argc)
+			die(_("branch name required"));
+		ret = delete_branches(argc, argv, delete > 1, filter.kind, quiet);
+		goto out;
+	} else if (show_current) {
+		print_current_branch_name();
+		ret = 0;
+		goto out;
+	} else if (list) {
+		/*  git branch --list also shows HEAD when it is detached */
+		if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
+			filter.kind |= FILTER_REFS_DETACHED_HEAD;
+		filter.name_patterns = argv;
+		/*
+		 * If no sorting parameter is given then we default to sorting
+		 * by 'refname'. This would give us an alphabetically sorted
+		 * array with the 'HEAD' ref at the beginning followed by
+		 * local branches 'refs/heads/...' and finally remote-tracking
+		 * branches 'refs/remotes/...'.
+		 */
+		sorting = ref_sorting_options(&sorting_options);
+		ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
+		ref_sorting_set_sort_flags_all(
+			sorting, REF_SORTING_DETACHED_HEAD_FIRST, 1);
+		print_ref_list(&filter, sorting, &format, &output);
+		print_columns(&output, colopts, NULL);
+		string_list_clear(&output, 0);
+		ref_sorting_release(sorting);
+		ref_filter_clear(&filter);
+
+		ret = 0;
+		goto out;
+	} else if (edit_description) {
+		const char *branch_name;
+		struct strbuf branch_ref = STRBUF_INIT;
+		struct strbuf buf = STRBUF_INIT;
+
+		if (!argc) {
+			if (filter.detached)
+				die(_("cannot give description to detached HEAD"));
+			branch_name = head;
+		} else if (argc == 1) {
+			copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+			branch_name = buf.buf;
+		} else {
+			die(_("cannot edit description of more than one branch"));
+		}
+
+		strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
+		if (!refs_ref_exists(get_main_ref_store(the_repository), branch_ref.buf)) {
+			error((!argc || branch_checked_out(branch_ref.buf))
+			      ? _("no commit on branch '%s' yet")
+			      : _("no branch named '%s'"),
+			      branch_name);
+			ret = 1;
+		} else if (!edit_branch_description(branch_name)) {
+			ret = 0; /* happy */
+		} else {
+			ret = 1;
+		}
+
+		strbuf_release(&branch_ref);
+		strbuf_release(&buf);
+
+		goto out;
+	} else if (copy || rename) {
+		if (!argc)
+			die(_("branch name required"));
+		else if ((argc == 1) && filter.detached)
+			die(copy? _("cannot copy the current branch while not on any")
+				: _("cannot rename the current branch while not on any"));
+		else if (argc == 1)
+			copy_or_rename_branch(head, argv[0], copy, copy + rename > 1);
+		else if (argc == 2)
+			copy_or_rename_branch(argv[0], argv[1], copy, copy + rename > 1);
+		else
+			die(copy? _("too many branches for a copy operation")
+				: _("too many arguments for a rename operation"));
+	} else if (new_upstream) {
+		struct branch *branch;
+		struct strbuf buf = STRBUF_INIT;
+
+		if (!argc)
+			branch = branch_get(NULL);
+		else if (argc == 1) {
+			copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+			branch = branch_get(buf.buf);
+		} else
+			die(_("too many arguments to set new upstream"));
+
+		if (!branch) {
+			if (!argc || !strcmp(argv[0], "HEAD"))
+				die(_("could not set upstream of HEAD to %s when "
+				      "it does not point to any branch"),
+				    new_upstream);
+			die(_("no such branch '%s'"), argv[0]);
+		}
+
+		if (!refs_ref_exists(get_main_ref_store(the_repository), branch->refname)) {
+			if (!argc || branch_checked_out(branch->refname))
+				die(_("no commit on branch '%s' yet"), branch->name);
+			die(_("branch '%s' does not exist"), branch->name);
+		}
+
+		dwim_and_setup_tracking(the_repository, branch->name,
+					new_upstream, BRANCH_TRACK_OVERRIDE,
+					quiet);
+		strbuf_release(&buf);
+	} else if (unset_upstream) {
+		struct branch *branch;
+		struct strbuf buf = STRBUF_INIT;
+
+		if (!argc)
+			branch = branch_get(NULL);
+		else if (argc == 1) {
+			copy_branchname(&buf, argv[0], INTERPRET_BRANCH_LOCAL);
+			branch = branch_get(buf.buf);
+		} else
+			die(_("too many arguments to unset upstream"));
+
+		if (!branch) {
+			if (!argc || !strcmp(argv[0], "HEAD"))
+				die(_("could not unset upstream of HEAD when "
+				      "it does not point to any branch"));
+			die(_("no such branch '%s'"), argv[0]);
+		}
+
+		if (!branch_has_merge_config(branch))
+			die(_("branch '%s' has no upstream information"), branch->name);
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "branch.%s.remote", branch->name);
+		git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "branch.%s.merge", branch->name);
+		git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+		strbuf_release(&buf);
+	} else if (!noncreate_actions && argc > 0 && argc <= 2) {
+		const char *branch_name = argv[0];
+		const char *start_name = argc == 2 ? argv[1] : head;
+
+		if (filter.kind != FILTER_REFS_BRANCHES)
+			die(_("the -a, and -r, options to 'git branch' do not take a branch name.\n"
+				  "Did you mean to use: -a|-r --list <pattern>?"));
+
+		if (track == BRANCH_TRACK_OVERRIDE)
+			die(_("the '--set-upstream' option is no longer supported. Please use '--track' or '--set-upstream-to' instead"));
+
+		if (recurse_submodules) {
+			create_branches_recursively(the_repository, branch_name,
+						    start_name, NULL, force,
+						    reflog, quiet, track, 0);
+			ret = 0;
+			goto out;
+		}
+		create_branch(the_repository, branch_name, start_name, force, 0,
+			      reflog, quiet, track, 0);
+	} else
+		usage_with_options(builtin_branch_usage, options);
+
+	ret = 0;
+
+out:
+	string_list_clear(&sorting_options, 0);
+	return ret;
+}
diff --git a/builtin/bugreport.c b/builtin/bugreport.c
new file mode 100644
index 0000000000..0ac59cc8dc
--- /dev/null
+++ b/builtin/bugreport.c
@@ -0,0 +1,208 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "editor.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "help.h"
+#include "compat/compiler.h"
+#include "hook.h"
+#include "hook-list.h"
+#include "diagnose.h"
+#include "object-file.h"
+#include "setup.h"
+
+static void get_system_info(struct strbuf *sys_info)
+{
+	struct utsname uname_info;
+	char *shell = NULL;
+
+	/* get git version from native cmd */
+	strbuf_addstr(sys_info, _("git version:\n"));
+	get_version_info(sys_info, 1);
+
+	/* system call for other version info */
+	strbuf_addstr(sys_info, "uname: ");
+	if (uname(&uname_info))
+		strbuf_addf(sys_info, _("uname() failed with error '%s' (%d)\n"),
+			    strerror(errno),
+			    errno);
+	else
+		strbuf_addf(sys_info, "%s %s %s %s\n",
+			    uname_info.sysname,
+			    uname_info.release,
+			    uname_info.version,
+			    uname_info.machine);
+
+	strbuf_addstr(sys_info, _("compiler info: "));
+	get_compiler_info(sys_info);
+
+	strbuf_addstr(sys_info, _("libc info: "));
+	get_libc_info(sys_info);
+
+	shell = getenv("SHELL");
+	strbuf_addf(sys_info, "$SHELL (typically, interactive shell): %s\n",
+		    shell ? shell : "<unset>");
+}
+
+static void get_populated_hooks(struct strbuf *hook_info, int nongit)
+{
+	const char **p;
+
+	if (nongit) {
+		strbuf_addstr(hook_info,
+			_("not run from a git repository - no hooks to show\n"));
+		return;
+	}
+
+	for (p = hook_name_list; *p; p++) {
+		const char *hook = *p;
+
+		if (hook_exists(the_repository, hook))
+			strbuf_addf(hook_info, "%s\n", hook);
+	}
+}
+
+static const char * const bugreport_usage[] = {
+	N_("git bugreport [(-o | --output-directory) <path>]\n"
+	   "              [(-s | --suffix) <format> | --no-suffix]\n"
+	   "              [--diagnose[=<mode>]]"),
+	NULL
+};
+
+static int get_bug_template(struct strbuf *template)
+{
+	const char template_text[] = N_(
+"Thank you for filling out a Git bug report!\n"
+"Please answer the following questions to help us understand your issue.\n"
+"\n"
+"What did you do before the bug happened? (Steps to reproduce your issue)\n"
+"\n"
+"What did you expect to happen? (Expected behavior)\n"
+"\n"
+"What happened instead? (Actual behavior)\n"
+"\n"
+"What's different between what you expected and what actually happened?\n"
+"\n"
+"Anything else you want to add:\n"
+"\n"
+"Please review the rest of the bug report below.\n"
+"You can delete any lines you don't wish to share.\n");
+
+	strbuf_addstr(template, _(template_text));
+	return 0;
+}
+
+static void get_header(struct strbuf *buf, const char *title)
+{
+	strbuf_addf(buf, "\n\n[%s]\n", title);
+}
+
+int cmd_bugreport(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	struct strbuf buffer = STRBUF_INIT;
+	struct strbuf report_path = STRBUF_INIT;
+	int report = -1;
+	time_t now = time(NULL);
+	struct tm tm;
+	enum diagnose_mode diagnose = DIAGNOSE_NONE;
+	char *option_output = NULL;
+	const char *option_suffix = "%Y-%m-%d-%H%M";
+	const char *user_relative_path = NULL;
+	char *prefixed_filename;
+	size_t output_path_len;
+	int ret;
+
+	const struct option bugreport_options[] = {
+		OPT_CALLBACK_F(0, "diagnose", &diagnose, N_("mode"),
+			       N_("create an additional zip archive of detailed diagnostics (default 'stats')"),
+			       PARSE_OPT_OPTARG, option_parse_diagnose),
+		OPT_STRING('o', "output-directory", &option_output, N_("path"),
+			   N_("specify a destination for the bugreport file(s)")),
+		OPT_STRING('s', "suffix", &option_suffix, N_("format"),
+			   N_("specify a strftime format suffix for the filename(s)")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, bugreport_options,
+			     bugreport_usage, 0);
+
+	if (argc) {
+		error(_("unknown argument `%s'"), argv[0]);
+		usage(bugreport_usage[0]);
+	}
+
+	/* Prepare the path to put the result */
+	prefixed_filename = prefix_filename(prefix,
+					    option_output ? option_output : "");
+	strbuf_addstr(&report_path, prefixed_filename);
+	strbuf_complete(&report_path, '/');
+	output_path_len = report_path.len;
+
+	strbuf_addstr(&report_path, "git-bugreport");
+	if (option_suffix) {
+		strbuf_addch(&report_path, '-');
+		strbuf_addftime(&report_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+	}
+	strbuf_addstr(&report_path, ".txt");
+
+	switch (safe_create_leading_directories(report_path.buf)) {
+	case SCLD_OK:
+	case SCLD_EXISTS:
+		break;
+	default:
+		die(_("could not create leading directories for '%s'"),
+		    report_path.buf);
+	}
+
+	/* Prepare diagnostics, if requested */
+	if (diagnose != DIAGNOSE_NONE) {
+		struct strbuf zip_path = STRBUF_INIT;
+		strbuf_add(&zip_path, report_path.buf, output_path_len);
+		strbuf_addstr(&zip_path, "git-diagnostics-");
+		strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+		strbuf_addstr(&zip_path, ".zip");
+
+		if (create_diagnostics_archive(the_repository, &zip_path, diagnose))
+			die_errno(_("unable to create diagnostics archive %s"), zip_path.buf);
+
+		strbuf_release(&zip_path);
+	}
+
+	/* Prepare the report contents */
+	get_bug_template(&buffer);
+
+	get_header(&buffer, _("System Info"));
+	get_system_info(&buffer);
+
+	get_header(&buffer, _("Enabled Hooks"));
+	get_populated_hooks(&buffer, !startup_info->have_repository);
+
+	/* fopen doesn't offer us an O_EXCL alternative, except with glibc. */
+	report = xopen(report_path.buf, O_CREAT | O_EXCL | O_WRONLY, 0666);
+
+	if (write_in_full(report, buffer.buf, buffer.len) < 0)
+		die_errno(_("unable to write to %s"), report_path.buf);
+
+	close(report);
+
+	/*
+	 * We want to print the path relative to the user, but we still need the
+	 * path relative to us to give to the editor.
+	 */
+	if (!(prefix && skip_prefix(report_path.buf, prefix, &user_relative_path)))
+		user_relative_path = report_path.buf;
+	fprintf(stderr, _("Created new report at '%s'.\n"),
+		user_relative_path);
+
+	free(prefixed_filename);
+	strbuf_release(&buffer);
+
+	ret = !!launch_editor(report_path.buf, NULL, NULL);
+	strbuf_release(&report_path);
+	return ret;
+}
diff --git a/builtin/bundle.c b/builtin/bundle.c
new file mode 100644
index 0000000000..1e170e9278
--- /dev/null
+++ b/builtin/bundle.c
@@ -0,0 +1,255 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "setup.h"
+#include "strvec.h"
+#include "parse-options.h"
+#include "pkt-line.h"
+#include "bundle.h"
+
+/*
+ * Basic handler for bundle files to connect repositories via sneakernet.
+ * Invocation must include action.
+ * This function can create a bundle or provide information on an existing
+ * bundle supporting "fetch", "pull", and "ls-remote".
+ */
+
+#define BUILTIN_BUNDLE_CREATE_USAGE \
+	N_("git bundle create [-q | --quiet | --progress]\n" \
+	   "                  [--version=<version>] <file> <git-rev-list-args>")
+#define BUILTIN_BUNDLE_VERIFY_USAGE \
+	N_("git bundle verify [-q | --quiet] <file>")
+#define BUILTIN_BUNDLE_LIST_HEADS_USAGE \
+	N_("git bundle list-heads <file> [<refname>...]")
+#define BUILTIN_BUNDLE_UNBUNDLE_USAGE \
+	N_("git bundle unbundle [--progress] <file> [<refname>...]")
+
+static char const * const builtin_bundle_usage[] = {
+	BUILTIN_BUNDLE_CREATE_USAGE,
+	BUILTIN_BUNDLE_VERIFY_USAGE,
+	BUILTIN_BUNDLE_LIST_HEADS_USAGE,
+	BUILTIN_BUNDLE_UNBUNDLE_USAGE,
+	NULL,
+};
+
+static const char * const builtin_bundle_create_usage[] = {
+	BUILTIN_BUNDLE_CREATE_USAGE,
+	NULL
+};
+
+static const char * const builtin_bundle_verify_usage[] = {
+	BUILTIN_BUNDLE_VERIFY_USAGE,
+	NULL
+};
+
+static const char * const builtin_bundle_list_heads_usage[] = {
+	BUILTIN_BUNDLE_LIST_HEADS_USAGE,
+	NULL
+};
+
+static const char * const builtin_bundle_unbundle_usage[] = {
+	BUILTIN_BUNDLE_UNBUNDLE_USAGE,
+	NULL
+};
+
+static int parse_options_cmd_bundle(int argc,
+		const char **argv,
+		const char* prefix,
+		const char * const usagestr[],
+		const struct option options[],
+		char **bundle_file) {
+	argc = parse_options(argc, argv, NULL, options, usagestr,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (!argc)
+		usage_msg_opt(_("need a <file> argument"), usagestr, options);
+	*bundle_file = prefix_filename_except_for_dash(prefix, argv[0]);
+	return argc;
+}
+
+static int cmd_bundle_create(int argc, const char **argv, const char *prefix,
+			     struct repository *repo UNUSED) {
+	struct strvec pack_opts = STRVEC_INIT;
+	int version = -1;
+	int ret;
+	struct option options[] = {
+		OPT_PASSTHRU_ARGV('q', "quiet", &pack_opts, NULL,
+				  N_("do not show progress meter"),
+				  PARSE_OPT_NOARG),
+		OPT_PASSTHRU_ARGV(0, "progress", &pack_opts, NULL,
+				  N_("show progress meter"),
+				  PARSE_OPT_NOARG),
+		OPT_PASSTHRU_ARGV(0, "all-progress", &pack_opts, NULL,
+				  N_("historical; same as --progress"),
+				  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
+		OPT_PASSTHRU_ARGV(0, "all-progress-implied", &pack_opts, NULL,
+				  N_("historical; does nothing"),
+				  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
+		OPT_INTEGER(0, "version", &version,
+			    N_("specify bundle format version")),
+		OPT_END()
+	};
+	char *bundle_file;
+
+	if (isatty(STDERR_FILENO))
+		strvec_push(&pack_opts, "--progress");
+	strvec_push(&pack_opts, "--all-progress-implied");
+
+	argc = parse_options_cmd_bundle(argc, argv, prefix,
+			builtin_bundle_create_usage, options, &bundle_file);
+	/* bundle internals use argv[1] as further parameters */
+
+	if (!startup_info->have_repository)
+		die(_("Need a repository to create a bundle."));
+	ret = !!create_bundle(the_repository, bundle_file, argc, argv, &pack_opts, version);
+	strvec_clear(&pack_opts);
+	free(bundle_file);
+	return ret;
+}
+
+/*
+ * Similar to read_bundle_header(), but handle "-" as stdin.
+ */
+static int open_bundle(const char *path, struct bundle_header *header,
+		       const char **name)
+{
+	if (!strcmp(path, "-")) {
+		if (name)
+			*name = "<stdin>";
+		return read_bundle_header_fd(0, header, "<stdin>");
+	}
+
+	if (name)
+		*name = path;
+	return read_bundle_header(path, header);
+}
+
+static int cmd_bundle_verify(int argc, const char **argv, const char *prefix,
+			     struct repository *repo UNUSED) {
+	struct bundle_header header = BUNDLE_HEADER_INIT;
+	int bundle_fd = -1;
+	int quiet = 0;
+	int ret;
+	struct option options[] = {
+		OPT_BOOL('q', "quiet", &quiet,
+			    N_("do not show bundle details")),
+		OPT_END()
+	};
+	char *bundle_file;
+	const char *name;
+
+	argc = parse_options_cmd_bundle(argc, argv, prefix,
+			builtin_bundle_verify_usage, options, &bundle_file);
+	/* bundle internals use argv[1] as further parameters */
+
+	if (!startup_info->have_repository) {
+		ret = error(_("need a repository to verify a bundle"));
+		goto cleanup;
+	}
+
+	if ((bundle_fd = open_bundle(bundle_file, &header, &name)) < 0) {
+		ret = 1;
+		goto cleanup;
+	}
+	close(bundle_fd);
+	if (verify_bundle(the_repository, &header,
+			  quiet ? VERIFY_BUNDLE_QUIET : VERIFY_BUNDLE_VERBOSE)) {
+		ret = 1;
+		goto cleanup;
+	}
+
+	fprintf(stderr, _("%s is okay\n"), name);
+	ret = 0;
+cleanup:
+	free(bundle_file);
+	bundle_header_release(&header);
+	return ret;
+}
+
+static int cmd_bundle_list_heads(int argc, const char **argv, const char *prefix,
+				 struct repository *repo UNUSED) {
+	struct bundle_header header = BUNDLE_HEADER_INIT;
+	int bundle_fd = -1;
+	int ret;
+	struct option options[] = {
+		OPT_END()
+	};
+	char *bundle_file;
+
+	argc = parse_options_cmd_bundle(argc, argv, prefix,
+			builtin_bundle_list_heads_usage, options, &bundle_file);
+	/* bundle internals use argv[1] as further parameters */
+
+	if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
+		ret = 1;
+		goto cleanup;
+	}
+	close(bundle_fd);
+	ret = !!list_bundle_refs(&header, argc, argv);
+cleanup:
+	free(bundle_file);
+	bundle_header_release(&header);
+	return ret;
+}
+
+static int cmd_bundle_unbundle(int argc, const char **argv, const char *prefix,
+			       struct repository *repo UNUSED) {
+	struct bundle_header header = BUNDLE_HEADER_INIT;
+	int bundle_fd = -1;
+	int ret;
+	int progress = isatty(2);
+
+	struct option options[] = {
+		OPT_BOOL(0, "progress", &progress,
+			 N_("show progress meter")),
+		OPT_END()
+	};
+	char *bundle_file;
+	struct strvec extra_index_pack_args = STRVEC_INIT;
+
+	argc = parse_options_cmd_bundle(argc, argv, prefix,
+			builtin_bundle_unbundle_usage, options, &bundle_file);
+	/* bundle internals use argv[1] as further parameters */
+
+	if (!startup_info->have_repository)
+		die(_("Need a repository to unbundle."));
+
+	if ((bundle_fd = open_bundle(bundle_file, &header, NULL)) < 0) {
+		ret = 1;
+		goto cleanup;
+	}
+	if (progress)
+		strvec_pushl(&extra_index_pack_args, "-v", "--progress-title",
+			     _("Unbundling objects"), NULL);
+	ret = !!unbundle(the_repository, &header, bundle_fd,
+			 &extra_index_pack_args, NULL) ||
+		list_bundle_refs(&header, argc, argv);
+	bundle_header_release(&header);
+
+cleanup:
+	strvec_clear(&extra_index_pack_args);
+	free(bundle_file);
+	return ret;
+}
+
+int cmd_bundle(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("create", &fn, cmd_bundle_create),
+		OPT_SUBCOMMAND("verify", &fn, cmd_bundle_verify),
+		OPT_SUBCOMMAND("list-heads", &fn, cmd_bundle_list_heads),
+		OPT_SUBCOMMAND("unbundle", &fn, cmd_bundle_unbundle),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, builtin_bundle_usage,
+			     0);
+
+	packet_trace_identity("bundle");
+
+	return !!fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
new file mode 100644
index 0000000000..b13561cf73
--- /dev/null
+++ b/builtin/cat-file.c
@@ -0,0 +1,1101 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "convert.h"
+#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "ident.h"
+#include "parse-options.h"
+#include "userdiff.h"
+#include "streaming.h"
+#include "oid-array.h"
+#include "packfile.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
+#include "promisor-remote.h"
+#include "mailmap.h"
+#include "write-or-die.h"
+
+enum batch_mode {
+	BATCH_MODE_CONTENTS,
+	BATCH_MODE_INFO,
+	BATCH_MODE_QUEUE_AND_DISPATCH,
+};
+
+struct batch_options {
+	int enabled;
+	int follow_symlinks;
+	enum batch_mode batch_mode;
+	int buffer_output;
+	int all_objects;
+	int unordered;
+	int transform_mode; /* may be 'w' or 'c' for --filters or --textconv */
+	char input_delim;
+	char output_delim;
+	const char *format;
+};
+
+static const char *force_path;
+
+static struct string_list mailmap = STRING_LIST_INIT_NODUP;
+static int use_mailmap;
+
+static char *replace_idents_using_mailmap(char *, size_t *);
+
+static char *replace_idents_using_mailmap(char *object_buf, size_t *size)
+{
+	struct strbuf sb = STRBUF_INIT;
+	const char *headers[] = { "author ", "committer ", "tagger ", NULL };
+
+	strbuf_attach(&sb, object_buf, *size, *size + 1);
+	apply_mailmap_to_header(&sb, headers, &mailmap);
+	*size = sb.len;
+	return strbuf_detach(&sb, NULL);
+}
+
+static int filter_object(const char *path, unsigned mode,
+			 const struct object_id *oid,
+			 char **buf, unsigned long *size)
+{
+	enum object_type type;
+
+	*buf = repo_read_object_file(the_repository, oid, &type, size);
+	if (!*buf)
+		return error(_("cannot read object %s '%s'"),
+			     oid_to_hex(oid), path);
+	if ((type == OBJ_BLOB) && S_ISREG(mode)) {
+		struct strbuf strbuf = STRBUF_INIT;
+		struct checkout_metadata meta;
+
+		init_checkout_metadata(&meta, NULL, NULL, oid);
+		if (convert_to_working_tree(the_repository->index, path, *buf, *size, &strbuf, &meta)) {
+			free(*buf);
+			*size = strbuf.len;
+			*buf = strbuf_detach(&strbuf, NULL);
+		}
+	}
+
+	return 0;
+}
+
+static int stream_blob(const struct object_id *oid)
+{
+	if (stream_blob_to_fd(1, oid, NULL, 0))
+		die("unable to stream %s to stdout", oid_to_hex(oid));
+	return 0;
+}
+
+static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
+			int unknown_type)
+{
+	int ret;
+	struct object_id oid;
+	enum object_type type;
+	char *buf;
+	unsigned long size;
+	struct object_context obj_context = {0};
+	struct object_info oi = OBJECT_INFO_INIT;
+	struct strbuf sb = STRBUF_INIT;
+	unsigned flags = OBJECT_INFO_LOOKUP_REPLACE;
+	unsigned get_oid_flags =
+		GET_OID_RECORD_PATH |
+		GET_OID_ONLY_TO_DIE |
+		GET_OID_HASH_ANY;
+	const char *path = force_path;
+	const int opt_cw = (opt == 'c' || opt == 'w');
+	if (!path && opt_cw)
+		get_oid_flags |= GET_OID_REQUIRE_PATH;
+
+	if (unknown_type)
+		flags |= OBJECT_INFO_ALLOW_UNKNOWN_TYPE;
+
+	if (get_oid_with_context(the_repository, obj_name, get_oid_flags, &oid,
+				 &obj_context))
+		die("Not a valid object name %s", obj_name);
+
+	if (!path)
+		path = obj_context.path;
+	if (obj_context.mode == S_IFINVALID)
+		obj_context.mode = 0100644;
+
+	buf = NULL;
+	switch (opt) {
+	case 't':
+		oi.type_name = &sb;
+		if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
+			die("git cat-file: could not get object info");
+		if (sb.len) {
+			printf("%s\n", sb.buf);
+			strbuf_release(&sb);
+			ret = 0;
+			goto cleanup;
+		}
+		break;
+
+	case 's':
+		oi.sizep = &size;
+
+		if (use_mailmap) {
+			oi.typep = &type;
+			oi.contentp = (void**)&buf;
+		}
+
+		if (oid_object_info_extended(the_repository, &oid, &oi, flags) < 0)
+			die("git cat-file: could not get object info");
+
+		if (use_mailmap && (type == OBJ_COMMIT || type == OBJ_TAG)) {
+			size_t s = size;
+			buf = replace_idents_using_mailmap(buf, &s);
+			size = cast_size_t_to_ulong(s);
+		}
+
+		printf("%"PRIuMAX"\n", (uintmax_t)size);
+		ret = 0;
+		goto cleanup;
+
+	case 'e':
+		ret = !repo_has_object_file(the_repository, &oid);
+		goto cleanup;
+
+	case 'w':
+
+		if (filter_object(path, obj_context.mode,
+				  &oid, &buf, &size)) {
+			ret = -1;
+			goto cleanup;
+		}
+		break;
+
+	case 'c':
+		if (textconv_object(the_repository, path, obj_context.mode,
+				    &oid, 1, &buf, &size))
+			break;
+		/* else fallthrough */
+
+	case 'p':
+		type = oid_object_info(the_repository, &oid, NULL);
+		if (type < 0)
+			die("Not a valid object name %s", obj_name);
+
+		/* custom pretty-print here */
+		if (type == OBJ_TREE) {
+			const char *ls_args[3] = { NULL };
+			ls_args[0] =  "ls-tree";
+			ls_args[1] =  obj_name;
+			ret = cmd_ls_tree(2, ls_args, NULL, the_repository);
+			goto cleanup;
+		}
+
+		if (type == OBJ_BLOB) {
+			ret = stream_blob(&oid);
+			goto cleanup;
+		}
+		buf = repo_read_object_file(the_repository, &oid, &type,
+					    &size);
+		if (!buf)
+			die("Cannot read object %s", obj_name);
+
+		if (use_mailmap) {
+			size_t s = size;
+			buf = replace_idents_using_mailmap(buf, &s);
+			size = cast_size_t_to_ulong(s);
+		}
+
+		/* otherwise just spit out the data */
+		break;
+
+	case 0:
+	{
+		enum object_type exp_type_id = type_from_string(exp_type);
+
+		if (exp_type_id == OBJ_BLOB) {
+			struct object_id blob_oid;
+			if (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {
+				char *buffer = repo_read_object_file(the_repository,
+								     &oid,
+								     &type,
+								     &size);
+				const char *target;
+
+				if (!buffer)
+					die(_("unable to read %s"), oid_to_hex(&oid));
+
+				if (!skip_prefix(buffer, "object ", &target) ||
+				    get_oid_hex_algop(target, &blob_oid,
+						      &hash_algos[oid.algo]))
+					die("%s not a valid tag", oid_to_hex(&oid));
+				free(buffer);
+			} else
+				oidcpy(&blob_oid, &oid);
+
+			if (oid_object_info(the_repository, &blob_oid, NULL) == OBJ_BLOB) {
+				ret = stream_blob(&blob_oid);
+				goto cleanup;
+			}
+			/*
+			 * we attempted to dereference a tag to a blob
+			 * and failed; there may be new dereference
+			 * mechanisms this code is not aware of.
+			 * fall-back to the usual case.
+			 */
+		}
+		buf = read_object_with_reference(the_repository, &oid,
+						 exp_type_id, &size, NULL);
+
+		if (use_mailmap) {
+			size_t s = size;
+			buf = replace_idents_using_mailmap(buf, &s);
+			size = cast_size_t_to_ulong(s);
+		}
+		break;
+	}
+	default:
+		die("git cat-file: unknown option: %s", exp_type);
+	}
+
+	if (!buf)
+		die("git cat-file %s: bad file", obj_name);
+
+	write_or_die(1, buf, size);
+	ret = 0;
+cleanup:
+	free(buf);
+	object_context_release(&obj_context);
+	return ret;
+}
+
+struct expand_data {
+	struct object_id oid;
+	enum object_type type;
+	unsigned long size;
+	off_t disk_size;
+	const char *rest;
+	struct object_id delta_base_oid;
+
+	/*
+	 * If mark_query is true, we do not expand anything, but rather
+	 * just mark the object_info with items we wish to query.
+	 */
+	int mark_query;
+
+	/*
+	 * Whether to split the input on whitespace before feeding it to
+	 * get_sha1; this is decided during the mark_query phase based on
+	 * whether we have a %(rest) token in our format.
+	 */
+	int split_on_whitespace;
+
+	/*
+	 * After a mark_query run, this object_info is set up to be
+	 * passed to oid_object_info_extended. It will point to the data
+	 * elements above, so you can retrieve the response from there.
+	 */
+	struct object_info info;
+
+	/*
+	 * This flag will be true if the requested batch format and options
+	 * don't require us to call oid_object_info, which can then be
+	 * optimized out.
+	 */
+	unsigned skip_object_info : 1;
+};
+
+static int is_atom(const char *atom, const char *s, int slen)
+{
+	int alen = strlen(atom);
+	return alen == slen && !memcmp(atom, s, alen);
+}
+
+static int expand_atom(struct strbuf *sb, const char *atom, int len,
+		       struct expand_data *data)
+{
+	if (is_atom("objectname", atom, len)) {
+		if (!data->mark_query)
+			strbuf_addstr(sb, oid_to_hex(&data->oid));
+	} else if (is_atom("objecttype", atom, len)) {
+		if (data->mark_query)
+			data->info.typep = &data->type;
+		else
+			strbuf_addstr(sb, type_name(data->type));
+	} else if (is_atom("objectsize", atom, len)) {
+		if (data->mark_query)
+			data->info.sizep = &data->size;
+		else
+			strbuf_addf(sb, "%"PRIuMAX , (uintmax_t)data->size);
+	} else if (is_atom("objectsize:disk", atom, len)) {
+		if (data->mark_query)
+			data->info.disk_sizep = &data->disk_size;
+		else
+			strbuf_addf(sb, "%"PRIuMAX, (uintmax_t)data->disk_size);
+	} else if (is_atom("rest", atom, len)) {
+		if (data->mark_query)
+			data->split_on_whitespace = 1;
+		else if (data->rest)
+			strbuf_addstr(sb, data->rest);
+	} else if (is_atom("deltabase", atom, len)) {
+		if (data->mark_query)
+			data->info.delta_base_oid = &data->delta_base_oid;
+		else
+			strbuf_addstr(sb,
+				      oid_to_hex(&data->delta_base_oid));
+	} else
+		return 0;
+	return 1;
+}
+
+static void expand_format(struct strbuf *sb, const char *start,
+			  struct expand_data *data)
+{
+	while (strbuf_expand_step(sb, &start)) {
+		const char *end;
+
+		if (skip_prefix(start, "%", &start) || *start != '(')
+			strbuf_addch(sb, '%');
+		else if ((end = strchr(start + 1, ')')) &&
+			 expand_atom(sb, start + 1, end - start - 1, data))
+			start = end + 1;
+		else
+			strbuf_expand_bad_format(start, "cat-file");
+	}
+}
+
+static void batch_write(struct batch_options *opt, const void *data, int len)
+{
+	if (opt->buffer_output) {
+		if (fwrite(data, 1, len, stdout) != len)
+			die_errno("unable to write to stdout");
+	} else
+		write_or_die(1, data, len);
+}
+
+static void print_object_or_die(struct batch_options *opt, struct expand_data *data)
+{
+	const struct object_id *oid = &data->oid;
+
+	assert(data->info.typep);
+
+	if (data->type == OBJ_BLOB) {
+		if (opt->buffer_output)
+			fflush(stdout);
+		if (opt->transform_mode) {
+			char *contents;
+			unsigned long size;
+
+			if (!data->rest)
+				die("missing path for '%s'", oid_to_hex(oid));
+
+			if (opt->transform_mode == 'w') {
+				if (filter_object(data->rest, 0100644, oid,
+						  &contents, &size))
+					die("could not convert '%s' %s",
+					    oid_to_hex(oid), data->rest);
+			} else if (opt->transform_mode == 'c') {
+				enum object_type type;
+				if (!textconv_object(the_repository,
+						     data->rest, 0100644, oid,
+						     1, &contents, &size))
+					contents = repo_read_object_file(the_repository,
+									 oid,
+									 &type,
+									 &size);
+				if (!contents)
+					die("could not convert '%s' %s",
+					    oid_to_hex(oid), data->rest);
+			} else
+				BUG("invalid transform_mode: %c", opt->transform_mode);
+			batch_write(opt, contents, size);
+			free(contents);
+		} else {
+			stream_blob(oid);
+		}
+	}
+	else {
+		enum object_type type;
+		unsigned long size;
+		void *contents;
+
+		contents = repo_read_object_file(the_repository, oid, &type,
+						 &size);
+		if (!contents)
+			die("object %s disappeared", oid_to_hex(oid));
+
+		if (use_mailmap) {
+			size_t s = size;
+			contents = replace_idents_using_mailmap(contents, &s);
+			size = cast_size_t_to_ulong(s);
+		}
+
+		if (type != data->type)
+			die("object %s changed type!?", oid_to_hex(oid));
+		if (data->info.sizep && size != data->size && !use_mailmap)
+			die("object %s changed size!?", oid_to_hex(oid));
+
+		batch_write(opt, contents, size);
+		free(contents);
+	}
+}
+
+static void print_default_format(struct strbuf *scratch, struct expand_data *data,
+				 struct batch_options *opt)
+{
+	strbuf_addf(scratch, "%s %s %"PRIuMAX"%c", oid_to_hex(&data->oid),
+		    type_name(data->type),
+		    (uintmax_t)data->size, opt->output_delim);
+}
+
+/*
+ * If "pack" is non-NULL, then "offset" is the byte offset within the pack from
+ * which the object may be accessed (though note that we may also rely on
+ * data->oid, too). If "pack" is NULL, then offset is ignored.
+ */
+static void batch_object_write(const char *obj_name,
+			       struct strbuf *scratch,
+			       struct batch_options *opt,
+			       struct expand_data *data,
+			       struct packed_git *pack,
+			       off_t offset)
+{
+	if (!data->skip_object_info) {
+		int ret;
+
+		if (use_mailmap)
+			data->info.typep = &data->type;
+
+		if (pack)
+			ret = packed_object_info(the_repository, pack, offset,
+						 &data->info);
+		else
+			ret = oid_object_info_extended(the_repository,
+						       &data->oid, &data->info,
+						       OBJECT_INFO_LOOKUP_REPLACE);
+		if (ret < 0) {
+			printf("%s missing%c",
+			       obj_name ? obj_name : oid_to_hex(&data->oid), opt->output_delim);
+			fflush(stdout);
+			return;
+		}
+
+		if (use_mailmap && (data->type == OBJ_COMMIT || data->type == OBJ_TAG)) {
+			size_t s = data->size;
+			char *buf = NULL;
+
+			buf = repo_read_object_file(the_repository, &data->oid, &data->type,
+						    &data->size);
+			if (!buf)
+				die(_("unable to read %s"), oid_to_hex(&data->oid));
+			buf = replace_idents_using_mailmap(buf, &s);
+			data->size = cast_size_t_to_ulong(s);
+
+			free(buf);
+		}
+	}
+
+	strbuf_reset(scratch);
+
+	if (!opt->format) {
+		print_default_format(scratch, data, opt);
+	} else {
+		expand_format(scratch, opt->format, data);
+		strbuf_addch(scratch, opt->output_delim);
+	}
+
+	batch_write(opt, scratch->buf, scratch->len);
+
+	if (opt->batch_mode == BATCH_MODE_CONTENTS) {
+		print_object_or_die(opt, data);
+		batch_write(opt, &opt->output_delim, 1);
+	}
+}
+
+static void batch_one_object(const char *obj_name,
+			     struct strbuf *scratch,
+			     struct batch_options *opt,
+			     struct expand_data *data)
+{
+	struct object_context ctx = {0};
+	int flags =
+		GET_OID_HASH_ANY |
+		(opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0);
+	enum get_oid_result result;
+
+	result = get_oid_with_context(the_repository, obj_name,
+				      flags, &data->oid, &ctx);
+	if (result != FOUND) {
+		switch (result) {
+		case MISSING_OBJECT:
+			printf("%s missing%c", obj_name, opt->output_delim);
+			break;
+		case SHORT_NAME_AMBIGUOUS:
+			printf("%s ambiguous%c", obj_name, opt->output_delim);
+			break;
+		case DANGLING_SYMLINK:
+			printf("dangling %"PRIuMAX"%c%s%c",
+			       (uintmax_t)strlen(obj_name),
+			       opt->output_delim, obj_name, opt->output_delim);
+			break;
+		case SYMLINK_LOOP:
+			printf("loop %"PRIuMAX"%c%s%c",
+			       (uintmax_t)strlen(obj_name),
+			       opt->output_delim, obj_name, opt->output_delim);
+			break;
+		case NOT_DIR:
+			printf("notdir %"PRIuMAX"%c%s%c",
+			       (uintmax_t)strlen(obj_name),
+			       opt->output_delim, obj_name, opt->output_delim);
+			break;
+		default:
+			BUG("unknown get_sha1_with_context result %d\n",
+			       result);
+			break;
+		}
+		fflush(stdout);
+
+		goto out;
+	}
+
+	if (ctx.mode == 0) {
+		printf("symlink %"PRIuMAX"%c%s%c",
+		       (uintmax_t)ctx.symlink_path.len,
+		       opt->output_delim, ctx.symlink_path.buf, opt->output_delim);
+		fflush(stdout);
+		goto out;
+	}
+
+	batch_object_write(obj_name, scratch, opt, data, NULL, 0);
+
+out:
+	object_context_release(&ctx);
+}
+
+struct object_cb_data {
+	struct batch_options *opt;
+	struct expand_data *expand;
+	struct oidset *seen;
+	struct strbuf *scratch;
+};
+
+static int batch_object_cb(const struct object_id *oid, void *vdata)
+{
+	struct object_cb_data *data = vdata;
+	oidcpy(&data->expand->oid, oid);
+	batch_object_write(NULL, data->scratch, data->opt, data->expand,
+			   NULL, 0);
+	return 0;
+}
+
+static int collect_loose_object(const struct object_id *oid,
+				const char *path UNUSED,
+				void *data)
+{
+	oid_array_append(data, oid);
+	return 0;
+}
+
+static int collect_packed_object(const struct object_id *oid,
+				 struct packed_git *pack UNUSED,
+				 uint32_t pos UNUSED,
+				 void *data)
+{
+	oid_array_append(data, oid);
+	return 0;
+}
+
+static int batch_unordered_object(const struct object_id *oid,
+				  struct packed_git *pack, off_t offset,
+				  void *vdata)
+{
+	struct object_cb_data *data = vdata;
+
+	if (oidset_insert(data->seen, oid))
+		return 0;
+
+	oidcpy(&data->expand->oid, oid);
+	batch_object_write(NULL, data->scratch, data->opt, data->expand,
+			   pack, offset);
+	return 0;
+}
+
+static int batch_unordered_loose(const struct object_id *oid,
+				 const char *path UNUSED,
+				 void *data)
+{
+	return batch_unordered_object(oid, NULL, 0, data);
+}
+
+static int batch_unordered_packed(const struct object_id *oid,
+				  struct packed_git *pack,
+				  uint32_t pos,
+				  void *data)
+{
+	return batch_unordered_object(oid, pack,
+				      nth_packed_object_offset(pack, pos),
+				      data);
+}
+
+typedef void (*parse_cmd_fn_t)(struct batch_options *, const char *,
+			       struct strbuf *, struct expand_data *);
+
+struct queued_cmd {
+	parse_cmd_fn_t fn;
+	char *line;
+};
+
+static void parse_cmd_contents(struct batch_options *opt,
+			     const char *line,
+			     struct strbuf *output,
+			     struct expand_data *data)
+{
+	opt->batch_mode = BATCH_MODE_CONTENTS;
+	batch_one_object(line, output, opt, data);
+}
+
+static void parse_cmd_info(struct batch_options *opt,
+			   const char *line,
+			   struct strbuf *output,
+			   struct expand_data *data)
+{
+	opt->batch_mode = BATCH_MODE_INFO;
+	batch_one_object(line, output, opt, data);
+}
+
+static void dispatch_calls(struct batch_options *opt,
+		struct strbuf *output,
+		struct expand_data *data,
+		struct queued_cmd *cmd,
+		int nr)
+{
+	int i;
+
+	if (!opt->buffer_output)
+		die(_("flush is only for --buffer mode"));
+
+	for (i = 0; i < nr; i++)
+		cmd[i].fn(opt, cmd[i].line, output, data);
+
+	fflush(stdout);
+}
+
+static void free_cmds(struct queued_cmd *cmd, size_t *nr)
+{
+	size_t i;
+
+	for (i = 0; i < *nr; i++)
+		FREE_AND_NULL(cmd[i].line);
+
+	*nr = 0;
+}
+
+
+static const struct parse_cmd {
+	const char *name;
+	parse_cmd_fn_t fn;
+	unsigned takes_args;
+} commands[] = {
+	{ "contents", parse_cmd_contents, 1},
+	{ "info", parse_cmd_info, 1},
+	{ "flush", NULL, 0},
+};
+
+static void batch_objects_command(struct batch_options *opt,
+				    struct strbuf *output,
+				    struct expand_data *data)
+{
+	struct strbuf input = STRBUF_INIT;
+	struct queued_cmd *queued_cmd = NULL;
+	size_t alloc = 0, nr = 0;
+
+	while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
+		int i;
+		const struct parse_cmd *cmd = NULL;
+		const char *p = NULL, *cmd_end;
+		struct queued_cmd call = {0};
+
+		if (!input.len)
+			die(_("empty command in input"));
+		if (isspace(*input.buf))
+			die(_("whitespace before command: '%s'"), input.buf);
+
+		for (i = 0; i < ARRAY_SIZE(commands); i++) {
+			if (!skip_prefix(input.buf, commands[i].name, &cmd_end))
+				continue;
+
+			cmd = &commands[i];
+			if (cmd->takes_args) {
+				if (*cmd_end != ' ')
+					die(_("%s requires arguments"),
+					    commands[i].name);
+
+				p = cmd_end + 1;
+			} else if (*cmd_end) {
+				die(_("%s takes no arguments"),
+				    commands[i].name);
+			}
+
+			break;
+		}
+
+		if (!cmd)
+			die(_("unknown command: '%s'"), input.buf);
+
+		if (!strcmp(cmd->name, "flush")) {
+			dispatch_calls(opt, output, data, queued_cmd, nr);
+			free_cmds(queued_cmd, &nr);
+		} else if (!opt->buffer_output) {
+			cmd->fn(opt, p, output, data);
+		} else {
+			ALLOC_GROW(queued_cmd, nr + 1, alloc);
+			call.fn = cmd->fn;
+			call.line = xstrdup_or_null(p);
+			queued_cmd[nr++] = call;
+		}
+	}
+
+	if (opt->buffer_output &&
+	    nr &&
+	    !git_env_bool("GIT_TEST_CAT_FILE_NO_FLUSH_ON_EXIT", 0)) {
+		dispatch_calls(opt, output, data, queued_cmd, nr);
+		free_cmds(queued_cmd, &nr);
+	}
+
+	free_cmds(queued_cmd, &nr);
+	free(queued_cmd);
+	strbuf_release(&input);
+}
+
+#define DEFAULT_FORMAT "%(objectname) %(objecttype) %(objectsize)"
+
+static int batch_objects(struct batch_options *opt)
+{
+	struct strbuf input = STRBUF_INIT;
+	struct strbuf output = STRBUF_INIT;
+	struct expand_data data;
+	int save_warning;
+	int retval = 0;
+
+	/*
+	 * Expand once with our special mark_query flag, which will prime the
+	 * object_info to be handed to oid_object_info_extended for each
+	 * object.
+	 */
+	memset(&data, 0, sizeof(data));
+	data.mark_query = 1;
+	expand_format(&output,
+		      opt->format ? opt->format : DEFAULT_FORMAT,
+		      &data);
+	data.mark_query = 0;
+	strbuf_release(&output);
+	if (opt->transform_mode)
+		data.split_on_whitespace = 1;
+
+	if (opt->format && !strcmp(opt->format, DEFAULT_FORMAT))
+		opt->format = NULL;
+	/*
+	 * If we are printing out the object, then always fill in the type,
+	 * since we will want to decide whether or not to stream.
+	 */
+	if (opt->batch_mode == BATCH_MODE_CONTENTS)
+		data.info.typep = &data.type;
+
+	if (opt->all_objects) {
+		struct object_cb_data cb;
+		struct object_info empty = OBJECT_INFO_INIT;
+
+		if (!memcmp(&data.info, &empty, sizeof(empty)))
+			data.skip_object_info = 1;
+
+		if (repo_has_promisor_remote(the_repository))
+			warning("This repository uses promisor remotes. Some objects may not be loaded.");
+
+		disable_replace_refs();
+
+		cb.opt = opt;
+		cb.expand = &data;
+		cb.scratch = &output;
+
+		if (opt->unordered) {
+			struct oidset seen = OIDSET_INIT;
+
+			cb.seen = &seen;
+
+			for_each_loose_object(batch_unordered_loose, &cb, 0);
+			for_each_packed_object(the_repository, batch_unordered_packed,
+					       &cb, FOR_EACH_OBJECT_PACK_ORDER);
+
+			oidset_clear(&seen);
+		} else {
+			struct oid_array sa = OID_ARRAY_INIT;
+
+			for_each_loose_object(collect_loose_object, &sa, 0);
+			for_each_packed_object(the_repository, collect_packed_object,
+					       &sa, 0);
+
+			oid_array_for_each_unique(&sa, batch_object_cb, &cb);
+
+			oid_array_clear(&sa);
+		}
+
+		strbuf_release(&output);
+		return 0;
+	}
+
+	/*
+	 * We are going to call get_sha1 on a potentially very large number of
+	 * objects. In most large cases, these will be actual object sha1s. The
+	 * cost to double-check that each one is not also a ref (just so we can
+	 * warn) ends up dwarfing the actual cost of the object lookups
+	 * themselves. We can work around it by just turning off the warning.
+	 */
+	save_warning = warn_on_object_refname_ambiguity;
+	warn_on_object_refname_ambiguity = 0;
+
+	if (opt->batch_mode == BATCH_MODE_QUEUE_AND_DISPATCH) {
+		batch_objects_command(opt, &output, &data);
+		goto cleanup;
+	}
+
+	while (strbuf_getdelim_strip_crlf(&input, stdin, opt->input_delim) != EOF) {
+		if (data.split_on_whitespace) {
+			/*
+			 * Split at first whitespace, tying off the beginning
+			 * of the string and saving the remainder (or NULL) in
+			 * data.rest.
+			 */
+			char *p = strpbrk(input.buf, " \t");
+			if (p) {
+				while (*p && strchr(" \t", *p))
+					*p++ = '\0';
+			}
+			data.rest = p;
+		}
+
+		batch_one_object(input.buf, &output, opt, &data);
+	}
+
+ cleanup:
+	strbuf_release(&input);
+	strbuf_release(&output);
+	warn_on_object_refname_ambiguity = save_warning;
+	return retval;
+}
+
+static int git_cat_file_config(const char *var, const char *value,
+			       const struct config_context *ctx, void *cb)
+{
+	if (userdiff_config(var, value) < 0)
+		return -1;
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static int batch_option_callback(const struct option *opt,
+				 const char *arg,
+				 int unset)
+{
+	struct batch_options *bo = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (bo->enabled) {
+		return error(_("only one batch option may be specified"));
+	}
+
+	bo->enabled = 1;
+
+	if (!strcmp(opt->long_name, "batch"))
+		bo->batch_mode = BATCH_MODE_CONTENTS;
+	else if (!strcmp(opt->long_name, "batch-check"))
+		bo->batch_mode = BATCH_MODE_INFO;
+	else if (!strcmp(opt->long_name, "batch-command"))
+		bo->batch_mode = BATCH_MODE_QUEUE_AND_DISPATCH;
+	else
+		BUG("%s given to batch-option-callback", opt->long_name);
+
+	bo->format = arg;
+
+	return 0;
+}
+
+int cmd_cat_file(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	int opt = 0;
+	int opt_cw = 0;
+	int opt_epts = 0;
+	const char *exp_type = NULL, *obj_name = NULL;
+	struct batch_options batch = {0};
+	int unknown_type = 0;
+	int input_nul_terminated = 0;
+	int nul_terminated = 0;
+
+	const char * const usage[] = {
+		N_("git cat-file <type> <object>"),
+		N_("git cat-file (-e | -p) <object>"),
+		N_("git cat-file (-t | -s) [--allow-unknown-type] <object>"),
+		N_("git cat-file (--textconv | --filters)\n"
+		   "             [<rev>:<path|tree-ish> | --path=<path|tree-ish> <rev>]"),
+		N_("git cat-file (--batch | --batch-check | --batch-command) [--batch-all-objects]\n"
+		   "             [--buffer] [--follow-symlinks] [--unordered]\n"
+		   "             [--textconv | --filters] [-Z]"),
+		NULL
+	};
+	const struct option options[] = {
+		/* Simple queries */
+		OPT_GROUP(N_("Check object existence or emit object contents")),
+		OPT_CMDMODE('e', NULL, &opt,
+			    N_("check if <object> exists"), 'e'),
+		OPT_CMDMODE('p', NULL, &opt, N_("pretty-print <object> content"), 'p'),
+
+		OPT_GROUP(N_("Emit [broken] object attributes")),
+		OPT_CMDMODE('t', NULL, &opt, N_("show object type (one of 'blob', 'tree', 'commit', 'tag', ...)"), 't'),
+		OPT_CMDMODE('s', NULL, &opt, N_("show object size"), 's'),
+		OPT_BOOL(0, "allow-unknown-type", &unknown_type,
+			  N_("allow -s and -t to work with broken/corrupt objects")),
+		OPT_BOOL(0, "use-mailmap", &use_mailmap, N_("use mail map file")),
+		OPT_ALIAS(0, "mailmap", "use-mailmap"),
+		/* Batch mode */
+		OPT_GROUP(N_("Batch objects requested on stdin (or --batch-all-objects)")),
+		OPT_CALLBACK_F(0, "batch", &batch, N_("format"),
+			N_("show full <object> or <rev> contents"),
+			PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+			batch_option_callback),
+		OPT_CALLBACK_F(0, "batch-check", &batch, N_("format"),
+			N_("like --batch, but don't emit <contents>"),
+			PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+			batch_option_callback),
+		OPT_BOOL_F('z', NULL, &input_nul_terminated, N_("stdin is NUL-terminated"),
+			PARSE_OPT_HIDDEN),
+		OPT_BOOL('Z', NULL, &nul_terminated, N_("stdin and stdout is NUL-terminated")),
+		OPT_CALLBACK_F(0, "batch-command", &batch, N_("format"),
+			N_("read commands from stdin"),
+			PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+			batch_option_callback),
+		OPT_CMDMODE(0, "batch-all-objects", &opt,
+			    N_("with --batch[-check]: ignores stdin, batches all known objects"), 'b'),
+		/* Batch-specific options */
+		OPT_GROUP(N_("Change or optimize batch output")),
+		OPT_BOOL(0, "buffer", &batch.buffer_output, N_("buffer --batch output")),
+		OPT_BOOL(0, "follow-symlinks", &batch.follow_symlinks,
+			 N_("follow in-tree symlinks")),
+		OPT_BOOL(0, "unordered", &batch.unordered,
+			 N_("do not order objects before emitting them")),
+		/* Textconv options, stand-ole*/
+		OPT_GROUP(N_("Emit object (blob or tree) with conversion or filter (stand-alone, or with batch)")),
+		OPT_CMDMODE(0, "textconv", &opt,
+			    N_("run textconv on object's content"), 'c'),
+		OPT_CMDMODE(0, "filters", &opt,
+			    N_("run filters on object's content"), 'w'),
+		OPT_STRING(0, "path", &force_path, N_("blob|tree"),
+			   N_("use a <path> for (--textconv | --filters); Not with 'batch'")),
+		OPT_END()
+	};
+
+	git_config(git_cat_file_config, NULL);
+
+	batch.buffer_output = -1;
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+	opt_cw = (opt == 'c' || opt == 'w');
+	opt_epts = (opt == 'e' || opt == 'p' || opt == 't' || opt == 's');
+
+	if (use_mailmap)
+		read_mailmap(&mailmap);
+
+	/* --batch-all-objects? */
+	if (opt == 'b')
+		batch.all_objects = 1;
+
+	/* Option compatibility */
+	if (force_path && !opt_cw)
+		usage_msg_optf(_("'%s=<%s>' needs '%s' or '%s'"),
+			       usage, options,
+			       "--path", _("path|tree-ish"), "--filters",
+			       "--textconv");
+
+	/* Option compatibility with batch mode */
+	if (batch.enabled)
+		;
+	else if (batch.follow_symlinks)
+		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
+			       "--follow-symlinks");
+	else if (batch.buffer_output >= 0)
+		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
+			       "--buffer");
+	else if (batch.all_objects)
+		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
+			       "--batch-all-objects");
+	else if (input_nul_terminated)
+		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
+			       "-z");
+	else if (nul_terminated)
+		usage_msg_optf(_("'%s' requires a batch mode"), usage, options,
+			       "-Z");
+
+	batch.input_delim = batch.output_delim = '\n';
+	if (input_nul_terminated)
+		batch.input_delim = '\0';
+	if (nul_terminated)
+		batch.input_delim = batch.output_delim = '\0';
+
+	/* Batch defaults */
+	if (batch.buffer_output < 0)
+		batch.buffer_output = batch.all_objects;
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	/* Return early if we're in batch mode? */
+	if (batch.enabled) {
+		if (opt_cw)
+			batch.transform_mode = opt;
+		else if (opt && opt != 'b')
+			usage_msg_optf(_("'-%c' is incompatible with batch mode"),
+				       usage, options, opt);
+		else if (argc)
+			usage_msg_opt(_("batch modes take no arguments"), usage,
+				      options);
+
+		return batch_objects(&batch);
+	}
+
+	if (opt) {
+		if (!argc && opt == 'c')
+			usage_msg_optf(_("<rev> required with '%s'"),
+				       usage, options, "--textconv");
+		else if (!argc && opt == 'w')
+			usage_msg_optf(_("<rev> required with '%s'"),
+				       usage, options, "--filters");
+		else if (!argc && opt_epts)
+			usage_msg_optf(_("<object> required with '-%c'"),
+				       usage, options, opt);
+		else if (argc == 1)
+			obj_name = argv[0];
+		else
+			usage_msg_opt(_("too many arguments"), usage, options);
+	} else if (!argc) {
+		usage_with_options(usage, options);
+	} else if (argc != 2) {
+		usage_msg_optf(_("only two arguments allowed in <type> <object> mode, not %d"),
+			      usage, options, argc);
+	} else if (argc) {
+		exp_type = argv[0];
+		obj_name = argv[1];
+	}
+
+	if (unknown_type && opt != 't' && opt != 's')
+		die("git cat-file --allow-unknown-type: use with -s or -t");
+	return cat_one_file(opt, exp_type, obj_name, unknown_type);
+}
diff --git a/builtin/check-attr.c b/builtin/check-attr.c
new file mode 100644
index 0000000000..7cf275b893
--- /dev/null
+++ b/builtin/check-attr.c
@@ -0,0 +1,207 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "attr.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "quote.h"
+#include "setup.h"
+#include "parse-options.h"
+#include "write-or-die.h"
+
+static int all_attrs;
+static int cached_attrs;
+static int stdin_paths;
+static char *source;
+static const char * const check_attr_usage[] = {
+N_("git check-attr [--source <tree-ish>] [-a | --all | <attr>...] [--] <pathname>..."),
+N_("git check-attr --stdin [-z] [--source <tree-ish>] [-a | --all | <attr>...]"),
+NULL
+};
+
+static int nul_term_line;
+
+static const struct option check_attr_options[] = {
+	OPT_BOOL('a', "all", &all_attrs, N_("report all attributes set on file")),
+	OPT_BOOL(0,  "cached", &cached_attrs, N_("use .gitattributes only from the index")),
+	OPT_BOOL(0 , "stdin", &stdin_paths, N_("read file names from stdin")),
+	OPT_BOOL('z', NULL, &nul_term_line,
+		 N_("terminate input and output records by a NUL character")),
+	OPT_STRING(0, "source", &source, N_("<tree-ish>"), N_("which tree-ish to check attributes at")),
+	OPT_END()
+};
+
+static void output_attr(struct attr_check *check, const char *file)
+{
+	int j;
+	int cnt = check->nr;
+
+	for (j = 0; j < cnt; j++) {
+		const char *value = check->items[j].value;
+
+		if (ATTR_TRUE(value))
+			value = "set";
+		else if (ATTR_FALSE(value))
+			value = "unset";
+		else if (ATTR_UNSET(value))
+			value = "unspecified";
+
+		if (nul_term_line) {
+			printf("%s%c" /* path */
+			       "%s%c" /* attrname */
+			       "%s%c" /* attrvalue */,
+			       file, 0,
+			       git_attr_name(check->items[j].attr), 0, value, 0);
+		} else {
+			quote_c_style(file, NULL, stdout, 0);
+			printf(": %s: %s\n",
+			       git_attr_name(check->items[j].attr), value);
+		}
+	}
+}
+
+static void check_attr(const char *prefix, struct attr_check *check,
+		       int collect_all,
+		       const char *file)
+
+{
+	char *full_path =
+		prefix_path(prefix, prefix ? strlen(prefix) : 0, file);
+
+	if (collect_all) {
+		git_all_attrs(the_repository->index, full_path, check);
+	} else {
+		git_check_attr(the_repository->index, full_path, check);
+	}
+	output_attr(check, file);
+
+	free(full_path);
+}
+
+static void check_attr_stdin_paths(const char *prefix, struct attr_check *check,
+				   int collect_all)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf unquoted = STRBUF_INIT;
+	strbuf_getline_fn getline_fn;
+
+	getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
+	while (getline_fn(&buf, stdin) != EOF) {
+		if (!nul_term_line && buf.buf[0] == '"') {
+			strbuf_reset(&unquoted);
+			if (unquote_c_style(&unquoted, buf.buf, NULL))
+				die("line is badly quoted");
+			strbuf_swap(&buf, &unquoted);
+		}
+		check_attr(prefix, check, collect_all, buf.buf);
+		maybe_flush_or_die(stdout, "attribute to stdout");
+	}
+	strbuf_release(&buf);
+	strbuf_release(&unquoted);
+}
+
+static NORETURN void error_with_usage(const char *msg)
+{
+	error("%s", msg);
+	usage_with_options(check_attr_usage, check_attr_options);
+}
+
+int cmd_check_attr(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct attr_check *check;
+	struct object_id initialized_oid;
+	int cnt, i, doubledash, filei;
+
+	if (!is_bare_repository())
+		setup_work_tree();
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, check_attr_options,
+			     check_attr_usage, PARSE_OPT_KEEP_DASHDASH);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	if (repo_read_index(the_repository) < 0) {
+		die("invalid cache");
+	}
+
+	if (cached_attrs)
+		git_attr_set_direction(GIT_ATTR_INDEX);
+
+	doubledash = -1;
+	for (i = 0; doubledash < 0 && i < argc; i++) {
+		if (!strcmp(argv[i], "--"))
+			doubledash = i;
+	}
+
+	/* Process --all and/or attribute arguments: */
+	if (all_attrs) {
+		if (doubledash >= 1)
+			error_with_usage("Attributes and --all both specified");
+
+		cnt = 0;
+		filei = doubledash + 1;
+	} else if (doubledash == 0) {
+		error_with_usage("No attribute specified");
+	} else if (doubledash < 0) {
+		if (!argc)
+			error_with_usage("No attribute specified");
+
+		if (stdin_paths) {
+			/* Treat all arguments as attribute names. */
+			cnt = argc;
+			filei = argc;
+		} else {
+			/* Treat exactly one argument as an attribute name. */
+			cnt = 1;
+			filei = 1;
+		}
+	} else {
+		cnt = doubledash;
+		filei = doubledash + 1;
+	}
+
+	/* Check file argument(s): */
+	if (stdin_paths) {
+		if (filei < argc)
+			error_with_usage("Can't specify files with --stdin");
+	} else {
+		if (filei >= argc)
+			error_with_usage("No file specified");
+	}
+
+	check = attr_check_alloc();
+	if (!all_attrs) {
+		for (i = 0; i < cnt; i++) {
+			const struct git_attr *a = git_attr(argv[i]);
+
+			if (!a)
+				return error("%s: not a valid attribute name",
+					     argv[i]);
+			attr_check_append(check, a);
+		}
+	}
+
+	if (source) {
+		if (repo_get_oid_tree(the_repository, source, &initialized_oid))
+			die("%s: not a valid tree-ish source", source);
+		set_git_attr_source(source);
+	}
+
+	if (stdin_paths)
+		check_attr_stdin_paths(prefix, check, all_attrs);
+	else {
+		for (i = filei; i < argc; i++)
+			check_attr(prefix, check, all_attrs, argv[i]);
+		maybe_flush_or_die(stdout, "attribute to stdout");
+	}
+
+	attr_check_free(check);
+	return 0;
+}
diff --git a/builtin/check-ignore.c b/builtin/check-ignore.c
new file mode 100644
index 0000000000..7b7831d13a
--- /dev/null
+++ b/builtin/check-ignore.c
@@ -0,0 +1,201 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "dir.h"
+#include "gettext.h"
+#include "quote.h"
+#include "pathspec.h"
+#include "parse-options.h"
+#include "submodule.h"
+#include "write-or-die.h"
+
+static int quiet, verbose, stdin_paths, show_non_matching, no_index;
+static const char * const check_ignore_usage[] = {
+"git check-ignore [<options>] <pathname>...",
+"git check-ignore [<options>] --stdin",
+NULL
+};
+
+static int nul_term_line;
+
+static const struct option check_ignore_options[] = {
+	OPT__QUIET(&quiet, N_("suppress progress reporting")),
+	OPT__VERBOSE(&verbose, N_("be verbose")),
+	OPT_GROUP(""),
+	OPT_BOOL(0, "stdin", &stdin_paths,
+		 N_("read file names from stdin")),
+	OPT_BOOL('z', NULL, &nul_term_line,
+		 N_("terminate input and output records by a NUL character")),
+	OPT_BOOL('n', "non-matching", &show_non_matching,
+		 N_("show non-matching input paths")),
+	OPT_BOOL(0, "no-index", &no_index,
+		 N_("ignore index when checking")),
+	OPT_END()
+};
+
+static void output_pattern(const char *path, struct path_pattern *pattern)
+{
+	const char *bang  = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE)  ? "!" : "";
+	const char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
+	if (!nul_term_line) {
+		if (!verbose) {
+			write_name_quoted(path, stdout, '\n');
+		} else {
+			if (pattern) {
+				quote_c_style(pattern->pl->src, NULL, stdout, 0);
+				printf(":%d:%s%s%s\t",
+				       pattern->srcpos,
+				       bang, pattern->pattern, slash);
+			}
+			else {
+				printf("::\t");
+			}
+			quote_c_style(path, NULL, stdout, 0);
+			fputc('\n', stdout);
+		}
+	} else {
+		if (!verbose) {
+			printf("%s%c", path, '\0');
+		} else {
+			if (pattern)
+				printf("%s%c%d%c%s%s%s%c%s%c",
+				       pattern->pl->src, '\0',
+				       pattern->srcpos, '\0',
+				       bang, pattern->pattern, slash, '\0',
+				       path, '\0');
+			else
+				printf("%c%c%c%s%c", '\0', '\0', '\0', path, '\0');
+		}
+	}
+}
+
+static int check_ignore(struct dir_struct *dir,
+			const char *prefix, int argc, const char **argv)
+{
+	const char *full_path;
+	char *seen;
+	int num_ignored = 0, i;
+	struct path_pattern *pattern;
+	struct pathspec pathspec;
+
+	if (!argc) {
+		if (!quiet)
+			fprintf(stderr, "no pathspec given.\n");
+		return 0;
+	}
+
+	/*
+	 * check-ignore just needs paths. Magic beyond :/ is really
+	 * irrelevant.
+	 */
+	parse_pathspec(&pathspec,
+		       PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
+		       PATHSPEC_SYMLINK_LEADING_PATH |
+		       PATHSPEC_KEEP_ORDER,
+		       prefix, argv);
+
+	die_path_inside_submodule(the_repository->index, &pathspec);
+
+	/*
+	 * look for pathspecs matching entries in the index, since these
+	 * should not be ignored, in order to be consistent with
+	 * 'git status', 'git add' etc.
+	 */
+	seen = find_pathspecs_matching_against_index(&pathspec, the_repository->index,
+						     PS_HEED_SKIP_WORKTREE);
+	for (i = 0; i < pathspec.nr; i++) {
+		full_path = pathspec.items[i].match;
+		pattern = NULL;
+		if (!seen[i]) {
+			int dtype = DT_UNKNOWN;
+			pattern = last_matching_pattern(dir, the_repository->index,
+							full_path, &dtype);
+			if (!verbose && pattern &&
+			    pattern->flags & PATTERN_FLAG_NEGATIVE)
+				pattern = NULL;
+		}
+		if (!quiet && (pattern || show_non_matching))
+			output_pattern(pathspec.items[i].original, pattern);
+		if (pattern)
+			num_ignored++;
+	}
+	free(seen);
+	clear_pathspec(&pathspec);
+
+	return num_ignored;
+}
+
+static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf unquoted = STRBUF_INIT;
+	char *pathspec[2] = { NULL, NULL };
+	strbuf_getline_fn getline_fn;
+	int num_ignored = 0;
+
+	getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
+	while (getline_fn(&buf, stdin) != EOF) {
+		if (!nul_term_line && buf.buf[0] == '"') {
+			strbuf_reset(&unquoted);
+			if (unquote_c_style(&unquoted, buf.buf, NULL))
+				die("line is badly quoted");
+			strbuf_swap(&buf, &unquoted);
+		}
+		pathspec[0] = buf.buf;
+		num_ignored += check_ignore(dir, prefix,
+					    1, (const char **)pathspec);
+		maybe_flush_or_die(stdout, "check-ignore to stdout");
+	}
+	strbuf_release(&buf);
+	strbuf_release(&unquoted);
+	return num_ignored;
+}
+
+int cmd_check_ignore(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	int num_ignored;
+	struct dir_struct dir = DIR_INIT;
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, check_ignore_options,
+			     check_ignore_usage, 0);
+
+	if (stdin_paths) {
+		if (argc > 0)
+			die(_("cannot specify pathnames with --stdin"));
+	} else {
+		if (nul_term_line)
+			die(_("-z only makes sense with --stdin"));
+		if (argc == 0)
+			die(_("no path specified"));
+	}
+	if (quiet) {
+		if (argc > 1)
+			die(_("--quiet is only valid with a single pathname"));
+		if (verbose)
+			die(_("cannot have both --quiet and --verbose"));
+	}
+	if (show_non_matching && !verbose)
+		die(_("--non-matching is only valid with --verbose"));
+
+	/* read_cache() is only necessary so we can watch out for submodules. */
+	if (!no_index && repo_read_index(the_repository) < 0)
+		die(_("index file corrupt"));
+
+	setup_standard_excludes(&dir);
+
+	if (stdin_paths) {
+		num_ignored = check_ignore_stdin_paths(&dir, prefix);
+	} else {
+		num_ignored = check_ignore(&dir, prefix, argc, argv);
+		maybe_flush_or_die(stdout, "ignore to stdout");
+	}
+
+	dir_clear(&dir);
+
+	return !num_ignored;
+}
diff --git a/builtin/check-mailmap.c b/builtin/check-mailmap.c
new file mode 100644
index 0000000000..df00b5ee13
--- /dev/null
+++ b/builtin/check-mailmap.c
@@ -0,0 +1,86 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "ident.h"
+#include "mailmap.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "string-list.h"
+#include "write-or-die.h"
+
+static int use_stdin;
+static const char *mailmap_file, *mailmap_blob;
+static const char * const check_mailmap_usage[] = {
+N_("git check-mailmap [<options>] <contact>..."),
+NULL
+};
+
+static const struct option check_mailmap_options[] = {
+	OPT_BOOL(0, "stdin", &use_stdin, N_("also read contacts from stdin")),
+	OPT_FILENAME(0, "mailmap-file", &mailmap_file, N_("read additional mailmap entries from file")),
+	OPT_STRING(0, "mailmap-blob", &mailmap_blob, N_("blob"), N_("read additional mailmap entries from blob")),
+	OPT_END()
+};
+
+static void check_mailmap(struct string_list *mailmap, const char *contact)
+{
+	const char *name, *mail;
+	size_t namelen, maillen;
+	struct ident_split ident;
+
+	if (!split_ident_line(&ident, contact, strlen(contact))) {
+		name = ident.name_begin;
+		namelen = ident.name_end - ident.name_begin;
+		mail = ident.mail_begin;
+		maillen = ident.mail_end - ident.mail_begin;
+	} else {
+		name = NULL;
+		namelen = 0;
+		mail = contact;
+		maillen = strlen(contact);
+	}
+
+	map_user(mailmap, &mail, &maillen, &name, &namelen);
+
+	if (namelen)
+		printf("%.*s ", (int)namelen, name);
+	printf("<%.*s>\n", (int)maillen, mail);
+}
+
+int cmd_check_mailmap(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	int i;
+	struct string_list mailmap = STRING_LIST_INIT_NODUP;
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, check_mailmap_options,
+			     check_mailmap_usage, 0);
+	if (argc == 0 && !use_stdin)
+		die(_("no contacts specified"));
+
+	read_mailmap(&mailmap);
+	if (mailmap_blob)
+		read_mailmap_blob(&mailmap, mailmap_blob);
+	if (mailmap_file)
+		read_mailmap_file(&mailmap, mailmap_file, 0);
+
+	for (i = 0; i < argc; ++i)
+		check_mailmap(&mailmap, argv[i]);
+	maybe_flush_or_die(stdout, "stdout");
+
+	if (use_stdin) {
+		struct strbuf buf = STRBUF_INIT;
+		while (strbuf_getline_lf(&buf, stdin) != EOF) {
+			check_mailmap(&mailmap, buf.buf);
+			maybe_flush_or_die(stdout, "stdout");
+		}
+		strbuf_release(&buf);
+	}
+
+	clear_mailmap(&mailmap);
+	return 0;
+}
diff --git a/builtin/check-ref-format.c b/builtin/check-ref-format.c
new file mode 100644
index 0000000000..5d80afeec0
--- /dev/null
+++ b/builtin/check-ref-format.c
@@ -0,0 +1,100 @@
+/*
+ * GIT - The information manager from hell
+ */
+#include "builtin.h"
+#include "refs.h"
+#include "setup.h"
+#include "strbuf.h"
+
+static const char builtin_check_ref_format_usage[] =
+"git check-ref-format [--normalize] [<options>] <refname>\n"
+"   or: git check-ref-format --branch <branchname-shorthand>";
+
+/*
+ * Return a copy of refname but with leading slashes removed and runs
+ * of adjacent slashes replaced with single slashes.
+ *
+ * This function is similar to normalize_path_copy(), but stripped down
+ * to meet check_ref_format's simpler needs.
+ */
+static char *collapse_slashes(const char *refname)
+{
+	char *ret = xmallocz(strlen(refname));
+	char ch;
+	char prev = '/';
+	char *cp = ret;
+
+	while ((ch = *refname++) != '\0') {
+		if (prev == '/' && ch == prev)
+			continue;
+
+		*cp++ = ch;
+		prev = ch;
+	}
+	*cp = '\0';
+	return ret;
+}
+
+static int check_ref_format_branch(const char *arg)
+{
+	struct strbuf sb = STRBUF_INIT;
+	const char *name;
+	int nongit;
+
+	setup_git_directory_gently(&nongit);
+	if (check_branch_ref(&sb, arg) ||
+	    !skip_prefix(sb.buf, "refs/heads/", &name))
+		die("'%s' is not a valid branch name", arg);
+	printf("%s\n", name);
+	strbuf_release(&sb);
+	return 0;
+}
+
+int cmd_check_ref_format(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	int i;
+	int normalize = 0;
+	int flags = 0;
+	const char *refname;
+	char *to_free = NULL;
+	int ret = 1;
+
+	BUG_ON_NON_EMPTY_PREFIX(prefix);
+
+	show_usage_if_asked(argc, argv,
+			    builtin_check_ref_format_usage);
+
+	if (argc == 3 && !strcmp(argv[1], "--branch"))
+		return check_ref_format_branch(argv[2]);
+
+	for (i = 1; i < argc && argv[i][0] == '-'; i++) {
+		if (!strcmp(argv[i], "--normalize") || !strcmp(argv[i], "--print"))
+			normalize = 1;
+		else if (!strcmp(argv[i], "--allow-onelevel"))
+			flags |= REFNAME_ALLOW_ONELEVEL;
+		else if (!strcmp(argv[i], "--no-allow-onelevel"))
+			flags &= ~REFNAME_ALLOW_ONELEVEL;
+		else if (!strcmp(argv[i], "--refspec-pattern"))
+			flags |= REFNAME_REFSPEC_PATTERN;
+		else
+			usage(builtin_check_ref_format_usage);
+	}
+	if (! (i == argc - 1))
+		usage(builtin_check_ref_format_usage);
+
+	refname = argv[i];
+	if (normalize)
+		refname = to_free = collapse_slashes(refname);
+	if (check_refname_format(refname, flags))
+		goto cleanup;
+	if (normalize)
+		printf("%s\n", refname);
+
+	ret = 0;
+cleanup:
+	free(to_free);
+	return ret;
+}
diff --git a/builtin/checkout--worker.c b/builtin/checkout--worker.c
new file mode 100644
index 0000000000..da9345a44b
--- /dev/null
+++ b/builtin/checkout--worker.c
@@ -0,0 +1,153 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "entry.h"
+#include "gettext.h"
+#include "parallel-checkout.h"
+#include "parse-options.h"
+#include "pkt-line.h"
+#include "read-cache-ll.h"
+
+static void packet_to_pc_item(const char *buffer, int len,
+			      struct parallel_checkout_item *pc_item)
+{
+	const struct pc_item_fixed_portion *fixed_portion;
+	const char *variant;
+	char *encoding;
+
+	if (len < sizeof(struct pc_item_fixed_portion))
+		BUG("checkout worker received too short item (got %dB, exp %dB)",
+		    len, (int)sizeof(struct pc_item_fixed_portion));
+
+	fixed_portion = (struct pc_item_fixed_portion *)buffer;
+
+	if (len - sizeof(struct pc_item_fixed_portion) !=
+		fixed_portion->name_len + fixed_portion->working_tree_encoding_len)
+		BUG("checkout worker received corrupted item");
+
+	variant = buffer + sizeof(struct pc_item_fixed_portion);
+
+	/*
+	 * Note: the main process uses zero length to communicate that the
+	 * encoding is NULL. There is no use case that requires sending an
+	 * actual empty string, since convert_attrs() never sets
+	 * ca.working_tree_enconding to "".
+	 */
+	if (fixed_portion->working_tree_encoding_len) {
+		encoding = xmemdupz(variant,
+				    fixed_portion->working_tree_encoding_len);
+		variant += fixed_portion->working_tree_encoding_len;
+	} else {
+		encoding = NULL;
+	}
+
+	memset(pc_item, 0, sizeof(*pc_item));
+	pc_item->ce = make_empty_transient_cache_entry(fixed_portion->name_len, NULL);
+	pc_item->ce->ce_namelen = fixed_portion->name_len;
+	pc_item->ce->ce_mode = fixed_portion->ce_mode;
+	memcpy(pc_item->ce->name, variant, pc_item->ce->ce_namelen);
+	oidcpy(&pc_item->ce->oid, &fixed_portion->oid);
+
+	pc_item->id = fixed_portion->id;
+	pc_item->ca.crlf_action = fixed_portion->crlf_action;
+	pc_item->ca.ident = fixed_portion->ident;
+	pc_item->ca.working_tree_encoding = encoding;
+}
+
+static void report_result(struct parallel_checkout_item *pc_item)
+{
+	struct pc_item_result res = { 0 };
+	size_t size;
+
+	res.id = pc_item->id;
+	res.status = pc_item->status;
+
+	if (pc_item->status == PC_ITEM_WRITTEN) {
+		res.st = pc_item->st;
+		size = sizeof(res);
+	} else {
+		size = PC_ITEM_RESULT_BASE_SIZE;
+	}
+
+	packet_write(1, (const char *)&res, size);
+}
+
+/* Free the worker-side malloced data, but not pc_item itself. */
+static void release_pc_item_data(struct parallel_checkout_item *pc_item)
+{
+	free((char *)pc_item->ca.working_tree_encoding);
+	discard_cache_entry(pc_item->ce);
+}
+
+static void worker_loop(struct checkout *state)
+{
+	struct parallel_checkout_item *items = NULL;
+	size_t i, nr = 0, alloc = 0;
+
+	while (1) {
+		int len = packet_read(0, packet_buffer, sizeof(packet_buffer),
+				      0);
+
+		if (len < 0)
+			BUG("packet_read() returned negative value");
+		else if (!len)
+			break;
+
+		ALLOC_GROW(items, nr + 1, alloc);
+		packet_to_pc_item(packet_buffer, len, &items[nr++]);
+	}
+
+	for (i = 0; i < nr; i++) {
+		struct parallel_checkout_item *pc_item = &items[i];
+		write_pc_item(pc_item, state);
+		report_result(pc_item);
+		release_pc_item_data(pc_item);
+	}
+
+	packet_flush(1);
+
+	free(items);
+}
+
+static const char * const checkout_worker_usage[] = {
+	N_("git checkout--worker [<options>]"),
+	NULL
+};
+
+int cmd_checkout__worker(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	struct checkout state = CHECKOUT_INIT;
+	struct option checkout_worker_options[] = {
+		OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
+			N_("when creating files, prepend <string>")),
+		OPT_END()
+	};
+
+	show_usage_with_options_if_asked(argc, argv,
+					 checkout_worker_usage,
+					 checkout_worker_options);
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, checkout_worker_options,
+			     checkout_worker_usage, 0);
+	if (argc > 0)
+		usage_with_options(checkout_worker_usage, checkout_worker_options);
+
+	if (state.base_dir)
+		state.base_dir_len = strlen(state.base_dir);
+
+	/*
+	 * Setting this on a worker won't actually update the index. We just
+	 * need to tell the checkout machinery to lstat() the written entries,
+	 * so that we can send this data back to the main process.
+	 */
+	state.refresh_cache = 1;
+
+	worker_loop(&state);
+	return 0;
+}
diff --git a/builtin/checkout-index.c b/builtin/checkout-index.c
new file mode 100644
index 0000000000..e30086c7d4
--- /dev/null
+++ b/builtin/checkout-index.c
@@ -0,0 +1,350 @@
+/*
+ * Check-out files from the "current cache directory"
+ *
+ * Copyright (C) 2005 Linus Torvalds
+ *
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "lockfile.h"
+#include "quote.h"
+#include "cache-tree.h"
+#include "parse-options.h"
+#include "entry.h"
+#include "parallel-checkout.h"
+#include "read-cache-ll.h"
+#include "setup.h"
+#include "sparse-index.h"
+
+#define CHECKOUT_ALL 4
+static int nul_term_line;
+static int checkout_stage; /* default to checkout stage0 */
+static int ignore_skip_worktree; /* default to 0 */
+static int to_tempfile = -1;
+static char topath[4][TEMPORARY_FILENAME_LENGTH + 1];
+
+static struct checkout state = CHECKOUT_INIT;
+
+static void write_tempfile_record(const char *name, const char *prefix)
+{
+	int i;
+	int have_tempname = 0;
+
+	if (CHECKOUT_ALL == checkout_stage) {
+		for (i = 1; i < 4; i++)
+			if (topath[i][0]) {
+				have_tempname = 1;
+				break;
+			}
+
+		if (have_tempname) {
+			for (i = 1; i < 4; i++) {
+				if (i > 1)
+					putchar(' ');
+				if (topath[i][0])
+					fputs(topath[i], stdout);
+				else
+					putchar('.');
+			}
+		}
+	} else if (topath[checkout_stage][0]) {
+		have_tempname = 1;
+		fputs(topath[checkout_stage], stdout);
+	}
+
+	if (have_tempname) {
+		putchar('\t');
+		write_name_quoted_relative(name, prefix, stdout,
+					   nul_term_line ? '\0' : '\n');
+	}
+
+	for (i = 0; i < 4; i++) {
+		topath[i][0] = 0;
+	}
+}
+
+static int checkout_file(const char *name, const char *prefix)
+{
+	int namelen = strlen(name);
+	int pos = index_name_pos(the_repository->index, name, namelen);
+	int has_same_name = 0;
+	int is_file = 0;
+	int is_skipped = 1;
+	int did_checkout = 0;
+	int errs = 0;
+
+	if (pos < 0)
+		pos = -pos - 1;
+
+	while (pos <the_repository->index->cache_nr) {
+		struct cache_entry *ce =the_repository->index->cache[pos];
+		if (ce_namelen(ce) != namelen ||
+		    memcmp(ce->name, name, namelen))
+			break;
+		has_same_name = 1;
+		pos++;
+		if (S_ISSPARSEDIR(ce->ce_mode))
+			break;
+		is_file = 1;
+		if (!ignore_skip_worktree && ce_skip_worktree(ce))
+			break;
+		is_skipped = 0;
+		if (ce_stage(ce) != checkout_stage
+		    && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
+			continue;
+		did_checkout = 1;
+		if (checkout_entry(ce, &state,
+				   to_tempfile ? topath[ce_stage(ce)] : NULL,
+				   NULL) < 0)
+			errs++;
+	}
+
+	if (did_checkout) {
+		if (to_tempfile)
+			write_tempfile_record(name, prefix);
+		return errs > 0 ? -1 : 0;
+	}
+
+	/*
+	 * At this point we know we didn't try to check anything out. If it was
+	 * because we did find an entry but it was stage 0, that's not an
+	 * error.
+	 */
+	if (has_same_name && checkout_stage == CHECKOUT_ALL)
+		return 0;
+
+	if (!state.quiet) {
+		fprintf(stderr, "git checkout-index: %s ", name);
+		if (!has_same_name)
+			fprintf(stderr, "is not in the cache");
+		else if (!is_file)
+			fprintf(stderr, "is a sparse directory");
+		else if (is_skipped)
+			fprintf(stderr, "has skip-worktree enabled; "
+					"use '--ignore-skip-worktree-bits' to checkout");
+		else if (checkout_stage)
+			fprintf(stderr, "does not exist at stage %d",
+				checkout_stage);
+		else
+			fprintf(stderr, "is unmerged");
+		fputc('\n', stderr);
+	}
+	return -1;
+}
+
+static int checkout_all(const char *prefix, int prefix_length)
+{
+	int i, errs = 0;
+	struct cache_entry *last_ce = NULL;
+
+	for (i = 0; i < the_repository->index->cache_nr ; i++) {
+		struct cache_entry *ce = the_repository->index->cache[i];
+
+		if (S_ISSPARSEDIR(ce->ce_mode)) {
+			if (!ce_skip_worktree(ce))
+				BUG("sparse directory '%s' does not have skip-worktree set", ce->name);
+
+			/*
+			 * If the current entry is a sparse directory and skip-worktree
+			 * entries are being checked out, expand the index and continue
+			 * the loop on the current index position (now pointing to the
+			 * first entry inside the expanded sparse directory).
+			 */
+			if (ignore_skip_worktree) {
+				ensure_full_index(the_repository->index);
+				ce = the_repository->index->cache[i];
+			}
+		}
+
+		if (!ignore_skip_worktree && ce_skip_worktree(ce))
+			continue;
+		if (ce_stage(ce) != checkout_stage
+		    && (CHECKOUT_ALL != checkout_stage || !ce_stage(ce)))
+			continue;
+		if (prefix && *prefix &&
+		    (ce_namelen(ce) <= prefix_length ||
+		     memcmp(prefix, ce->name, prefix_length)))
+			continue;
+		if (last_ce && to_tempfile) {
+			if (ce_namelen(last_ce) != ce_namelen(ce)
+			    || memcmp(last_ce->name, ce->name, ce_namelen(ce)))
+				write_tempfile_record(last_ce->name, prefix);
+		}
+		if (checkout_entry(ce, &state,
+				   to_tempfile ? topath[ce_stage(ce)] : NULL,
+				   NULL) < 0)
+			errs++;
+		last_ce = ce;
+	}
+	if (last_ce && to_tempfile)
+		write_tempfile_record(last_ce->name, prefix);
+	return !!errs;
+}
+
+static const char * const builtin_checkout_index_usage[] = {
+	N_("git checkout-index [<options>] [--] [<file>...]"),
+	NULL
+};
+
+static int option_parse_stage(const struct option *opt,
+			      const char *arg, int unset)
+{
+	int *stage = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (!strcmp(arg, "all")) {
+		*stage = CHECKOUT_ALL;
+	} else {
+		int ch = arg[0];
+		if ('1' <= ch && ch <= '3')
+			*stage = arg[0] - '0';
+		else
+			die(_("stage should be between 1 and 3 or all"));
+	}
+	return 0;
+}
+
+int cmd_checkout_index(int argc,
+		       const char **argv,
+		       const char *prefix,
+		       struct repository *repo UNUSED)
+{
+	int i;
+	struct lock_file lock_file = LOCK_INIT;
+	int all = 0;
+	int read_from_stdin = 0;
+	int prefix_length;
+	int force = 0, quiet = 0, not_new = 0;
+	int index_opt = 0;
+	int err = 0;
+	int pc_workers, pc_threshold;
+	struct option builtin_checkout_index_options[] = {
+		OPT_BOOL('a', "all", &all,
+			N_("check out all files in the index")),
+		OPT_BOOL(0, "ignore-skip-worktree-bits", &ignore_skip_worktree,
+			N_("do not skip files with skip-worktree set")),
+		OPT__FORCE(&force, N_("force overwrite of existing files"), 0),
+		OPT__QUIET(&quiet,
+			N_("no warning for existing files and files not in index")),
+		OPT_BOOL('n', "no-create", &not_new,
+			N_("don't checkout new files")),
+		OPT_BOOL('u', "index", &index_opt,
+			 N_("update stat information in the index file")),
+		OPT_BOOL('z', NULL, &nul_term_line,
+			N_("paths are separated with NUL character")),
+		OPT_BOOL(0, "stdin", &read_from_stdin,
+			N_("read list of paths from the standard input")),
+		OPT_BOOL(0, "temp", &to_tempfile,
+			N_("write the content to temporary files")),
+		OPT_STRING(0, "prefix", &state.base_dir, N_("string"),
+			N_("when creating files, prepend <string>")),
+		OPT_CALLBACK_F(0, "stage", &checkout_stage, "(1|2|3|all)",
+			N_("copy out the files from named stage"),
+			PARSE_OPT_NONEG, option_parse_stage),
+		OPT_END()
+	};
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_checkout_index_usage,
+					 builtin_checkout_index_options);
+	git_config(git_default_config, NULL);
+	prefix_length = prefix ? strlen(prefix) : 0;
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	if (repo_read_index(the_repository) < 0) {
+		die("invalid cache");
+	}
+
+	argc = parse_options(argc, argv, prefix, builtin_checkout_index_options,
+			builtin_checkout_index_usage, 0);
+	state.istate = the_repository->index;
+	state.force = force;
+	state.quiet = quiet;
+	state.not_new = not_new;
+
+	if (!state.base_dir)
+		state.base_dir = "";
+	state.base_dir_len = strlen(state.base_dir);
+
+	if (to_tempfile < 0)
+		to_tempfile = (checkout_stage == CHECKOUT_ALL);
+	if (!to_tempfile && checkout_stage == CHECKOUT_ALL)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--stage=all", "--no-temp");
+
+	/*
+	 * when --prefix is specified we do not want to update cache.
+	 */
+	if (index_opt && !state.base_dir_len && !to_tempfile) {
+		state.refresh_cache = 1;
+		state.istate = the_repository->index;
+		repo_hold_locked_index(the_repository, &lock_file,
+				       LOCK_DIE_ON_ERROR);
+	}
+
+	get_parallel_checkout_configs(&pc_workers, &pc_threshold);
+	if (pc_workers > 1)
+		init_parallel_checkout();
+
+	/* Check out named files first */
+	for (i = 0; i < argc; i++) {
+		const char *arg = argv[i];
+		char *p;
+
+		if (all)
+			die("git checkout-index: don't mix '--all' and explicit filenames");
+		if (read_from_stdin)
+			die("git checkout-index: don't mix '--stdin' and explicit filenames");
+		p = prefix_path(prefix, prefix_length, arg);
+		err |= checkout_file(p, prefix);
+		free(p);
+	}
+
+	if (read_from_stdin) {
+		struct strbuf buf = STRBUF_INIT;
+		struct strbuf unquoted = STRBUF_INIT;
+		strbuf_getline_fn getline_fn;
+
+		if (all)
+			die("git checkout-index: don't mix '--all' and '--stdin'");
+
+		getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
+		while (getline_fn(&buf, stdin) != EOF) {
+			char *p;
+			if (!nul_term_line && buf.buf[0] == '"') {
+				strbuf_reset(&unquoted);
+				if (unquote_c_style(&unquoted, buf.buf, NULL))
+					die("line is badly quoted");
+				strbuf_swap(&buf, &unquoted);
+			}
+			p = prefix_path(prefix, prefix_length, buf.buf);
+			err |= checkout_file(p, prefix);
+			free(p);
+		}
+		strbuf_release(&unquoted);
+		strbuf_release(&buf);
+	}
+
+	if (all)
+		err |= checkout_all(prefix, prefix_length);
+
+	if (pc_workers > 1)
+		err |= run_parallel_checkout(&state, pc_workers, pc_threshold,
+					     NULL, NULL);
+
+	if (err)
+		return 1;
+
+	if (is_lock_file_locked(&lock_file) &&
+	    write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+		die("Unable to write new index file");
+	return 0;
+}
diff --git a/builtin/checkout.c b/builtin/checkout.c
new file mode 100644
index 0000000000..01ea9ff8b2
--- /dev/null
+++ b/builtin/checkout.c
@@ -0,0 +1,2085 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "advice.h"
+#include "branch.h"
+#include "cache-tree.h"
+#include "checkout.h"
+#include "commit.h"
+#include "config.h"
+#include "diff.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "hook.h"
+#include "merge-ll.h"
+#include "lockfile.h"
+#include "mem-pool.h"
+#include "merge-recursive.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
+#include "refs.h"
+#include "remote.h"
+#include "repo-settings.h"
+#include "resolve-undo.h"
+#include "revision.h"
+#include "setup.h"
+#include "submodule.h"
+#include "symlinks.h"
+#include "trace2.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "unpack-trees.h"
+#include "wt-status.h"
+#include "xdiff-interface.h"
+#include "entry.h"
+#include "parallel-checkout.h"
+#include "add-interactive.h"
+
+static const char * const checkout_usage[] = {
+	N_("git checkout [<options>] <branch>"),
+	N_("git checkout [<options>] [<branch>] -- <file>..."),
+	NULL,
+};
+
+static const char * const switch_branch_usage[] = {
+	N_("git switch [<options>] [<branch>]"),
+	NULL,
+};
+
+static const char * const restore_usage[] = {
+	N_("git restore [<options>] [--source=<branch>] <file>..."),
+	NULL,
+};
+
+struct checkout_opts {
+	int patch_mode;
+	int quiet;
+	int merge;
+	int force;
+	int force_detach;
+	int implicit_detach;
+	int writeout_stage;
+	int overwrite_ignore;
+	int ignore_skipworktree;
+	int ignore_other_worktrees;
+	int show_progress;
+	int count_checkout_paths;
+	int overlay_mode;
+	int dwim_new_local_branch;
+	int discard_changes;
+	int accept_ref;
+	int accept_pathspec;
+	int switch_branch_doing_nothing_is_ok;
+	int only_merge_on_switching_branches;
+	int can_switch_when_in_progress;
+	int orphan_from_empty_tree;
+	int empty_pathspec_ok;
+	int checkout_index;
+	int checkout_worktree;
+	const char *ignore_unmerged_opt;
+	int ignore_unmerged;
+	int pathspec_file_nul;
+	char *pathspec_from_file;
+
+	const char *new_branch;
+	const char *new_branch_force;
+	const char *new_orphan_branch;
+	int new_branch_log;
+	enum branch_track track;
+	struct diff_options diff_options;
+	int conflict_style;
+
+	int branch_exists;
+	const char *prefix;
+	struct pathspec pathspec;
+	const char *from_treeish;
+	struct tree *source_tree;
+};
+
+#define CHECKOUT_OPTS_INIT { .conflict_style = -1, .merge = -1 }
+
+struct branch_info {
+	char *name; /* The short name used */
+	char *path; /* The full name of a real branch */
+	struct commit *commit; /* The named commit */
+	char *refname; /* The full name of the ref being checked out. */
+	struct object_id oid; /* The object ID of the commit being checked out. */
+	/*
+	 * if not null the branch is detached because it's already
+	 * checked out in this checkout
+	 */
+	char *checkout;
+};
+
+static void branch_info_release(struct branch_info *info)
+{
+	free(info->name);
+	free(info->path);
+	free(info->refname);
+	free(info->checkout);
+}
+
+static int post_checkout_hook(struct commit *old_commit, struct commit *new_commit,
+			      int changed)
+{
+	return run_hooks_l(the_repository, "post-checkout",
+			   oid_to_hex(old_commit ? &old_commit->object.oid : null_oid()),
+			   oid_to_hex(new_commit ? &new_commit->object.oid : null_oid()),
+			   changed ? "1" : "0", NULL);
+	/* "new_commit" can be NULL when checking out from the index before
+	   a commit exists. */
+
+}
+
+static int update_some(const struct object_id *oid, struct strbuf *base,
+		       const char *pathname, unsigned mode, void *context UNUSED)
+{
+	int len;
+	struct cache_entry *ce;
+	int pos;
+
+	if (S_ISDIR(mode))
+		return READ_TREE_RECURSIVE;
+
+	len = base->len + strlen(pathname);
+	ce = make_empty_cache_entry(the_repository->index, len);
+	oidcpy(&ce->oid, oid);
+	memcpy(ce->name, base->buf, base->len);
+	memcpy(ce->name + base->len, pathname, len - base->len);
+	ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
+	ce->ce_namelen = len;
+	ce->ce_mode = create_ce_mode(mode);
+
+	/*
+	 * If the entry is the same as the current index, we can leave the old
+	 * entry in place. Whether it is UPTODATE or not, checkout_entry will
+	 * do the right thing.
+	 */
+	pos = index_name_pos(the_repository->index, ce->name, ce->ce_namelen);
+	if (pos >= 0) {
+		struct cache_entry *old = the_repository->index->cache[pos];
+		if (ce->ce_mode == old->ce_mode &&
+		    !ce_intent_to_add(old) &&
+		    oideq(&ce->oid, &old->oid)) {
+			old->ce_flags |= CE_UPDATE;
+			discard_cache_entry(ce);
+			return 0;
+		}
+	}
+
+	add_index_entry(the_repository->index, ce,
+			ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+	return 0;
+}
+
+static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
+{
+	read_tree(the_repository, tree,
+		  pathspec, update_some, NULL);
+
+	/* update the index with the given tree's info
+	 * for all args, expanding wildcards, and exit
+	 * with any non-zero return code.
+	 */
+	return 0;
+}
+
+static int skip_same_name(const struct cache_entry *ce, int pos)
+{
+	while (++pos < the_repository->index->cache_nr &&
+	       !strcmp(the_repository->index->cache[pos]->name, ce->name))
+		; /* skip */
+	return pos;
+}
+
+static int check_stage(int stage, const struct cache_entry *ce, int pos,
+		       int overlay_mode)
+{
+	while (pos < the_repository->index->cache_nr &&
+	       !strcmp(the_repository->index->cache[pos]->name, ce->name)) {
+		if (ce_stage(the_repository->index->cache[pos]) == stage)
+			return 0;
+		pos++;
+	}
+	if (!overlay_mode)
+		return 0;
+	if (stage == 2)
+		return error(_("path '%s' does not have our version"), ce->name);
+	else
+		return error(_("path '%s' does not have their version"), ce->name);
+}
+
+static int check_stages(unsigned stages, const struct cache_entry *ce, int pos)
+{
+	unsigned seen = 0;
+	const char *name = ce->name;
+
+	while (pos < the_repository->index->cache_nr) {
+		ce = the_repository->index->cache[pos];
+		if (strcmp(name, ce->name))
+			break;
+		seen |= (1 << ce_stage(ce));
+		pos++;
+	}
+	if ((stages & seen) != stages)
+		return error(_("path '%s' does not have all necessary versions"),
+			     name);
+	return 0;
+}
+
+static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
+			  const struct checkout *state, int *nr_checkouts,
+			  int overlay_mode)
+{
+	while (pos < the_repository->index->cache_nr &&
+	       !strcmp(the_repository->index->cache[pos]->name, ce->name)) {
+		if (ce_stage(the_repository->index->cache[pos]) == stage)
+			return checkout_entry(the_repository->index->cache[pos], state,
+					      NULL, nr_checkouts);
+		pos++;
+	}
+	if (!overlay_mode) {
+		unlink_entry(ce, NULL);
+		return 0;
+	}
+	if (stage == 2)
+		return error(_("path '%s' does not have our version"), ce->name);
+	else
+		return error(_("path '%s' does not have their version"), ce->name);
+}
+
+static int checkout_merged(int pos, const struct checkout *state,
+			   int *nr_checkouts, struct mem_pool *ce_mem_pool,
+			   int conflict_style)
+{
+	struct cache_entry *ce = the_repository->index->cache[pos];
+	const char *path = ce->name;
+	mmfile_t ancestor, ours, theirs;
+	enum ll_merge_result merge_status;
+	int status;
+	struct object_id oid;
+	mmbuffer_t result_buf;
+	struct object_id threeway[3];
+	unsigned mode = 0;
+	struct ll_merge_options ll_opts = LL_MERGE_OPTIONS_INIT;
+	int renormalize = 0;
+
+	memset(threeway, 0, sizeof(threeway));
+	while (pos < the_repository->index->cache_nr) {
+		int stage;
+		stage = ce_stage(ce);
+		if (!stage || strcmp(path, ce->name))
+			break;
+		oidcpy(&threeway[stage - 1], &ce->oid);
+		if (stage == 2)
+			mode = create_ce_mode(ce->ce_mode);
+		pos++;
+		ce = the_repository->index->cache[pos];
+	}
+	if (is_null_oid(&threeway[1]) || is_null_oid(&threeway[2]))
+		return error(_("path '%s' does not have necessary versions"), path);
+
+	read_mmblob(&ancestor, &threeway[0]);
+	read_mmblob(&ours, &threeway[1]);
+	read_mmblob(&theirs, &threeway[2]);
+
+	git_config_get_bool("merge.renormalize", &renormalize);
+	ll_opts.renormalize = renormalize;
+	ll_opts.conflict_style = conflict_style;
+	merge_status = ll_merge(&result_buf, path, &ancestor, "base",
+				&ours, "ours", &theirs, "theirs",
+				state->istate, &ll_opts);
+	free(ancestor.ptr);
+	free(ours.ptr);
+	free(theirs.ptr);
+	if (merge_status == LL_MERGE_BINARY_CONFLICT)
+		warning("Cannot merge binary files: %s (%s vs. %s)",
+			path, "ours", "theirs");
+	if (merge_status < 0 || !result_buf.ptr) {
+		free(result_buf.ptr);
+		return error(_("path '%s': cannot merge"), path);
+	}
+
+	/*
+	 * NEEDSWORK:
+	 * There is absolutely no reason to write this as a blob object
+	 * and create a phony cache entry.  This hack is primarily to get
+	 * to the write_entry() machinery that massages the contents to
+	 * work-tree format and writes out which only allows it for a
+	 * cache entry.  The code in write_entry() needs to be refactored
+	 * to allow us to feed a <buffer, size, mode> instead of a cache
+	 * entry.  Such a refactoring would help merge_recursive as well
+	 * (it also writes the merge result to the object database even
+	 * when it may contain conflicts).
+	 */
+	if (write_object_file(result_buf.ptr, result_buf.size, OBJ_BLOB, &oid))
+		die(_("Unable to add merge result for '%s'"), path);
+	free(result_buf.ptr);
+	ce = make_transient_cache_entry(mode, &oid, path, 2, ce_mem_pool);
+	if (!ce)
+		die(_("make_cache_entry failed for path '%s'"), path);
+	status = checkout_entry(ce, state, NULL, nr_checkouts);
+	return status;
+}
+
+static void mark_ce_for_checkout_overlay(struct cache_entry *ce,
+					 char *ps_matched,
+					 const struct checkout_opts *opts)
+{
+	ce->ce_flags &= ~CE_MATCHED;
+	if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
+		return;
+	if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+		/*
+		 * "git checkout tree-ish -- path", but this entry
+		 * is in the original index but is not in tree-ish
+		 * or does not match the pathspec; it will not be
+		 * checked out to the working tree.  We will not do
+		 * anything to this entry at all.
+		 */
+		return;
+	/*
+	 * Either this entry came from the tree-ish we are
+	 * checking the paths out of, or we are checking out
+	 * of the index.
+	 *
+	 * If it comes from the tree-ish, we already know it
+	 * matches the pathspec and could just stamp
+	 * CE_MATCHED to it from update_some(). But we still
+	 * need ps_matched and read_tree (and
+	 * eventually tree_entry_interesting) cannot fill
+	 * ps_matched yet. Once it can, we can avoid calling
+	 * match_pathspec() for _all_ entries when
+	 * opts->source_tree != NULL.
+	 */
+	if (ce_path_match(the_repository->index, ce, &opts->pathspec, ps_matched))
+		ce->ce_flags |= CE_MATCHED;
+}
+
+static void mark_ce_for_checkout_no_overlay(struct cache_entry *ce,
+					    char *ps_matched,
+					    const struct checkout_opts *opts)
+{
+	ce->ce_flags &= ~CE_MATCHED;
+	if (!opts->ignore_skipworktree && ce_skip_worktree(ce))
+		return;
+	if (ce_path_match(the_repository->index, ce, &opts->pathspec, ps_matched)) {
+		ce->ce_flags |= CE_MATCHED;
+		if (opts->source_tree && !(ce->ce_flags & CE_UPDATE))
+			/*
+			 * In overlay mode, but the path is not in
+			 * tree-ish, which means we should remove it
+			 * from the index and the working tree.
+			 */
+			ce->ce_flags |= CE_REMOVE | CE_WT_REMOVE;
+	}
+}
+
+static int checkout_worktree(const struct checkout_opts *opts,
+			     const struct branch_info *info)
+{
+	struct checkout state = CHECKOUT_INIT;
+	int nr_checkouts = 0, nr_unmerged = 0;
+	int errs = 0;
+	int pos;
+	int pc_workers, pc_threshold;
+	struct mem_pool ce_mem_pool;
+
+	state.force = 1;
+	state.refresh_cache = 1;
+	state.istate = the_repository->index;
+
+	mem_pool_init(&ce_mem_pool, 0);
+	get_parallel_checkout_configs(&pc_workers, &pc_threshold);
+	init_checkout_metadata(&state.meta, info->refname,
+			       info->commit ? &info->commit->object.oid : &info->oid,
+			       NULL);
+
+	enable_delayed_checkout(&state);
+
+	if (pc_workers > 1)
+		init_parallel_checkout();
+
+	for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+		struct cache_entry *ce = the_repository->index->cache[pos];
+		if (ce->ce_flags & CE_MATCHED) {
+			if (!ce_stage(ce)) {
+				errs |= checkout_entry(ce, &state,
+						       NULL, &nr_checkouts);
+				continue;
+			}
+			if (opts->writeout_stage)
+				errs |= checkout_stage(opts->writeout_stage,
+						       ce, pos,
+						       &state,
+						       &nr_checkouts, opts->overlay_mode);
+			else if (opts->merge)
+				errs |= checkout_merged(pos, &state,
+							&nr_unmerged,
+							&ce_mem_pool,
+							opts->conflict_style);
+			pos = skip_same_name(ce, pos) - 1;
+		}
+	}
+	if (pc_workers > 1)
+		errs |= run_parallel_checkout(&state, pc_workers, pc_threshold,
+					      NULL, NULL);
+	mem_pool_discard(&ce_mem_pool, should_validate_cache_entries());
+	remove_marked_cache_entries(the_repository->index, 1);
+	remove_scheduled_dirs();
+	errs |= finish_delayed_checkout(&state, opts->show_progress);
+
+	if (opts->count_checkout_paths) {
+		if (nr_unmerged)
+			fprintf_ln(stderr, Q_("Recreated %d merge conflict",
+					      "Recreated %d merge conflicts",
+					      nr_unmerged),
+				   nr_unmerged);
+		if (opts->source_tree)
+			fprintf_ln(stderr, Q_("Updated %d path from %s",
+					      "Updated %d paths from %s",
+					      nr_checkouts),
+				   nr_checkouts,
+				   repo_find_unique_abbrev(the_repository, &opts->source_tree->object.oid,
+							   DEFAULT_ABBREV));
+		else if (!nr_unmerged || nr_checkouts)
+			fprintf_ln(stderr, Q_("Updated %d path from the index",
+					      "Updated %d paths from the index",
+					      nr_checkouts),
+				   nr_checkouts);
+	}
+
+	return errs;
+}
+
+static int checkout_paths(const struct checkout_opts *opts,
+			  const struct branch_info *new_branch_info)
+{
+	int pos;
+	static char *ps_matched;
+	struct object_id rev;
+	struct commit *head;
+	int errs = 0;
+	struct lock_file lock_file = LOCK_INIT;
+	int checkout_index;
+
+	trace2_cmd_mode(opts->patch_mode ? "patch" : "path");
+
+	if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+		die(_("'%s' cannot be used with updating paths"), "--track");
+
+	if (opts->new_branch_log)
+		die(_("'%s' cannot be used with updating paths"), "-l");
+
+	if (opts->ignore_unmerged && opts->patch_mode)
+		die(_("'%s' cannot be used with updating paths"),
+		    opts->ignore_unmerged_opt);
+
+	if (opts->force_detach)
+		die(_("'%s' cannot be used with updating paths"), "--detach");
+
+	if (opts->merge && opts->patch_mode)
+		die(_("options '%s' and '%s' cannot be used together"), "--merge", "--patch");
+
+	if (opts->ignore_unmerged && opts->merge)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    opts->ignore_unmerged_opt, "-m");
+
+	if (opts->new_branch)
+		die(_("Cannot update paths and switch to branch '%s' at the same time."),
+		    opts->new_branch);
+
+	if (!opts->checkout_worktree && !opts->checkout_index)
+		die(_("neither '%s' or '%s' is specified"),
+		    "--staged", "--worktree");
+
+	if (!opts->checkout_worktree && !opts->from_treeish)
+		die(_("'%s' must be used when '%s' is not specified"),
+		    "--worktree", "--source");
+
+	/*
+	 * Reject --staged option to the restore command when combined with
+	 * merge-related options. Use the accept_ref flag to distinguish it
+	 * from the checkout command, which does not accept --staged anyway.
+	 *
+	 * `restore --ours|--theirs --worktree --staged` could mean resolving
+	 * conflicted paths to one side in both the worktree and the index,
+	 * but does not currently.
+	 *
+	 * `restore --merge|--conflict=<style>` already recreates conflicts
+	 * in both the worktree and the index, so adding --staged would be
+	 * meaningless.
+	 */
+	if (!opts->accept_ref && opts->checkout_index) {
+		if (opts->writeout_stage)
+			die(_("'%s' or '%s' cannot be used with %s"),
+			    "--ours", "--theirs", "--staged");
+
+		if (opts->merge)
+			die(_("'%s' or '%s' cannot be used with %s"),
+			    "--merge", "--conflict", "--staged");
+	}
+
+	/*
+	 * recreating unmerged index entries and writing out data from
+	 * unmerged index entries would make no sense when checking out
+	 * of a tree-ish.
+	 */
+	if ((opts->merge || opts->writeout_stage) && opts->source_tree)
+		die(_("'%s', '%s', or '%s' cannot be used when checking out of a tree"),
+		    "--merge", "--ours", "--theirs");
+
+	if (opts->patch_mode) {
+		enum add_p_mode patch_mode;
+		const char *rev = new_branch_info->name;
+		char rev_oid[GIT_MAX_HEXSZ + 1];
+
+		/*
+		 * Since rev can be in the form of `<a>...<b>` (which is not
+		 * recognized by diff-index), we will always replace the name
+		 * with the hex of the commit (whether it's in `...` form or
+		 * not) for the run_add_interactive() machinery to work
+		 * properly. However, there is special logic for the HEAD case
+		 * so we mustn't replace that.  Also, when we were given a
+		 * tree-object, new_branch_info->commit would be NULL, but we
+		 * do not have to do any replacement, either.
+		 */
+		if (rev && new_branch_info->commit && strcmp(rev, "HEAD"))
+			rev = oid_to_hex_r(rev_oid, &new_branch_info->commit->object.oid);
+
+		if (opts->checkout_index && opts->checkout_worktree)
+			patch_mode = ADD_P_CHECKOUT;
+		else if (opts->checkout_index && !opts->checkout_worktree)
+			patch_mode = ADD_P_RESET;
+		else if (!opts->checkout_index && opts->checkout_worktree)
+			patch_mode = ADD_P_WORKTREE;
+		else
+			BUG("either flag must have been set, worktree=%d, index=%d",
+			    opts->checkout_worktree, opts->checkout_index);
+		return !!run_add_p(the_repository, patch_mode, rev,
+				   &opts->pathspec);
+	}
+
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+	if (repo_read_index_preload(the_repository, &opts->pathspec, 0) < 0)
+		return error(_("index file corrupt"));
+
+	if (opts->source_tree)
+		read_tree_some(opts->source_tree, &opts->pathspec);
+	if (opts->merge)
+		unmerge_index(the_repository->index, &opts->pathspec, CE_MATCHED);
+
+	ps_matched = xcalloc(opts->pathspec.nr, 1);
+
+	/*
+	 * Make sure all pathspecs participated in locating the paths
+	 * to be checked out.
+	 */
+	for (pos = 0; pos < the_repository->index->cache_nr; pos++)
+		if (opts->overlay_mode)
+			mark_ce_for_checkout_overlay(the_repository->index->cache[pos],
+						     ps_matched,
+						     opts);
+		else
+			mark_ce_for_checkout_no_overlay(the_repository->index->cache[pos],
+							ps_matched,
+							opts);
+
+	if (report_path_error(ps_matched, &opts->pathspec)) {
+		free(ps_matched);
+		return 1;
+	}
+	free(ps_matched);
+
+	/* Any unmerged paths? */
+	for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+		const struct cache_entry *ce = the_repository->index->cache[pos];
+		if (ce->ce_flags & CE_MATCHED) {
+			if (!ce_stage(ce))
+				continue;
+			if (opts->ignore_unmerged) {
+				if (!opts->quiet)
+					warning(_("path '%s' is unmerged"), ce->name);
+			} else if (opts->writeout_stage) {
+				errs |= check_stage(opts->writeout_stage, ce, pos, opts->overlay_mode);
+			} else if (opts->merge) {
+				errs |= check_stages((1<<2) | (1<<3), ce, pos);
+			} else {
+				errs = 1;
+				error(_("path '%s' is unmerged"), ce->name);
+			}
+			pos = skip_same_name(ce, pos) - 1;
+		}
+	}
+	if (errs)
+		return 1;
+
+	/* Now we are committed to check them out */
+	if (opts->checkout_worktree)
+		errs |= checkout_worktree(opts, new_branch_info);
+	else
+		remove_marked_cache_entries(the_repository->index, 1);
+
+	/*
+	 * Allow updating the index when checking out from the index.
+	 * This is to save new stat info.
+	 */
+	if (opts->checkout_worktree && !opts->checkout_index && !opts->source_tree)
+		checkout_index = 1;
+	else
+		checkout_index = opts->checkout_index;
+
+	if (checkout_index) {
+		if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+			die(_("unable to write new index file"));
+	} else {
+		/*
+		 * NEEDSWORK: if --worktree is not specified, we
+		 * should save stat info of checked out files in the
+		 * index to avoid the next (potentially costly)
+		 * refresh. But it's a bit tricker to do...
+		 */
+		rollback_lock_file(&lock_file);
+	}
+
+	refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", 0,
+			   &rev, NULL);
+	head = lookup_commit_reference_gently(the_repository, &rev, 1);
+
+	errs |= post_checkout_hook(head, head, 0);
+	return errs;
+}
+
+static void show_local_changes(struct object *head,
+			       const struct diff_options *opts)
+{
+	struct rev_info rev;
+	/* I think we want full paths, even if we're in a subdirectory. */
+	repo_init_revisions(the_repository, &rev, NULL);
+	rev.diffopt.flags = opts->flags;
+	rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
+	rev.diffopt.flags.recursive = 1;
+	diff_setup_done(&rev.diffopt);
+	add_pending_object(&rev, head, NULL);
+	run_diff_index(&rev, 0);
+	release_revisions(&rev);
+}
+
+static void describe_detached_head(const char *msg, struct commit *commit)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	if (!repo_parse_commit(the_repository, commit))
+		pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
+	if (print_sha1_ellipsis()) {
+		fprintf(stderr, "%s %s... %s\n", msg,
+			repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
+			sb.buf);
+	} else {
+		fprintf(stderr, "%s %s %s\n", msg,
+			repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV),
+			sb.buf);
+	}
+	strbuf_release(&sb);
+}
+
+static int reset_tree(struct tree *tree, const struct checkout_opts *o,
+		      int worktree, int *writeout_error,
+		      struct branch_info *info)
+{
+	struct unpack_trees_options opts;
+	struct tree_desc tree_desc;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = -1;
+	opts.update = worktree;
+	opts.skip_unmerged = !worktree;
+	opts.reset = o->force ? UNPACK_RESET_OVERWRITE_UNTRACKED :
+				UNPACK_RESET_PROTECT_UNTRACKED;
+	opts.preserve_ignored = (!o->force && !o->overwrite_ignore);
+	opts.merge = 1;
+	opts.fn = oneway_merge;
+	opts.verbose_update = o->show_progress;
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+	init_checkout_metadata(&opts.meta, info->refname,
+			       info->commit ? &info->commit->object.oid : null_oid(),
+			       NULL);
+	if (parse_tree(tree) < 0)
+		return 128;
+	init_tree_desc(&tree_desc, &tree->object.oid, tree->buffer, tree->size);
+	switch (unpack_trees(1, &tree_desc, &opts)) {
+	case -2:
+		*writeout_error = 1;
+		/*
+		 * We return 0 nevertheless, as the index is all right
+		 * and more importantly we have made best efforts to
+		 * update paths in the work tree, and we cannot revert
+		 * them.
+		 */
+		/* fallthrough */
+	case 0:
+		return 0;
+	default:
+		return 128;
+	}
+}
+
+static void setup_branch_path(struct branch_info *branch)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	/*
+	 * If this is a ref, resolve it; otherwise, look up the OID for our
+	 * expression.  Failure here is okay.
+	 */
+	if (!repo_dwim_ref(the_repository, branch->name, strlen(branch->name),
+			   &branch->oid, &branch->refname, 0))
+		repo_get_oid_committish(the_repository, branch->name, &branch->oid);
+
+	copy_branchname(&buf, branch->name, INTERPRET_BRANCH_LOCAL);
+	if (strcmp(buf.buf, branch->name)) {
+		free(branch->name);
+		branch->name = xstrdup(buf.buf);
+	}
+	strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
+	free(branch->path);
+	branch->path = strbuf_detach(&buf, NULL);
+}
+
+static void init_topts(struct unpack_trees_options *topts, int merge,
+		       int show_progress, int overwrite_ignore,
+		       struct commit *old_commit)
+{
+	memset(topts, 0, sizeof(*topts));
+	topts->head_idx = -1;
+	topts->src_index = the_repository->index;
+	topts->dst_index = the_repository->index;
+
+	setup_unpack_trees_porcelain(topts, "checkout");
+
+	topts->initial_checkout = is_index_unborn(the_repository->index);
+	topts->update = 1;
+	topts->merge = 1;
+	topts->quiet = merge && old_commit;
+	topts->verbose_update = show_progress;
+	topts->fn = twoway_merge;
+	topts->preserve_ignored = !overwrite_ignore;
+}
+
+static int merge_working_tree(const struct checkout_opts *opts,
+			      struct branch_info *old_branch_info,
+			      struct branch_info *new_branch_info,
+			      int *writeout_error)
+{
+	int ret;
+	struct lock_file lock_file = LOCK_INIT;
+	struct tree *new_tree;
+
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+	if (repo_read_index_preload(the_repository, NULL, 0) < 0)
+		return error(_("index file corrupt"));
+
+	resolve_undo_clear_index(the_repository->index);
+	if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
+		if (new_branch_info->commit)
+			BUG("'switch --orphan' should never accept a commit as starting point");
+		new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
+		if (!new_tree)
+			BUG("unable to read empty tree");
+	} else {
+		new_tree = repo_get_commit_tree(the_repository,
+						new_branch_info->commit);
+		if (!new_tree)
+			return error(_("unable to read tree (%s)"),
+				     oid_to_hex(&new_branch_info->commit->object.oid));
+	}
+	if (opts->discard_changes) {
+		ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
+		if (ret)
+			return ret;
+	} else {
+		struct tree_desc trees[2];
+		struct tree *tree;
+		struct unpack_trees_options topts;
+		const struct object_id *old_commit_oid;
+
+		refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
+
+		if (unmerged_index(the_repository->index)) {
+			error(_("you need to resolve your current index first"));
+			return 1;
+		}
+
+		/* 2-way merge to the new branch */
+		init_topts(&topts, opts->merge, opts->show_progress,
+			   opts->overwrite_ignore, old_branch_info->commit);
+		init_checkout_metadata(&topts.meta, new_branch_info->refname,
+				       new_branch_info->commit ?
+				       &new_branch_info->commit->object.oid :
+				       &new_branch_info->oid, NULL);
+
+		old_commit_oid = old_branch_info->commit ?
+			&old_branch_info->commit->object.oid :
+			the_hash_algo->empty_tree;
+		tree = parse_tree_indirect(old_commit_oid);
+		if (!tree)
+			die(_("unable to parse commit %s"),
+				oid_to_hex(old_commit_oid));
+
+		init_tree_desc(&trees[0], &tree->object.oid,
+			       tree->buffer, tree->size);
+		if (parse_tree(new_tree) < 0)
+			exit(128);
+		tree = new_tree;
+		init_tree_desc(&trees[1], &tree->object.oid,
+			       tree->buffer, tree->size);
+
+		ret = unpack_trees(2, trees, &topts);
+		clear_unpack_trees_porcelain(&topts);
+		if (ret == -1) {
+			/*
+			 * Unpack couldn't do a trivial merge; either
+			 * give up or do a real merge, depending on
+			 * whether the merge flag was used.
+			 */
+			struct tree *work;
+			struct tree *old_tree;
+			struct merge_options o;
+			struct strbuf sb = STRBUF_INIT;
+			struct strbuf old_commit_shortname = STRBUF_INIT;
+
+			if (!opts->merge)
+				return 1;
+
+			/*
+			 * Without old_branch_info->commit, the below is the same as
+			 * the two-tree unpack we already tried and failed.
+			 */
+			if (!old_branch_info->commit)
+				return 1;
+			old_tree = repo_get_commit_tree(the_repository,
+							old_branch_info->commit);
+
+			if (repo_index_has_changes(the_repository, old_tree, &sb))
+				die(_("cannot continue with staged changes in "
+				      "the following files:\n%s"), sb.buf);
+			strbuf_release(&sb);
+
+			/* Do more real merge */
+
+			/*
+			 * We update the index fully, then write the
+			 * tree from the index, then merge the new
+			 * branch with the current tree, with the old
+			 * branch as the base. Then we reset the index
+			 * (but not the working tree) to the new
+			 * branch, leaving the working tree as the
+			 * merged version, but skipping unmerged
+			 * entries in the index.
+			 */
+
+			add_files_to_cache(the_repository, NULL, NULL, NULL, 0,
+					   0);
+			init_ui_merge_options(&o, the_repository);
+			o.verbosity = 0;
+			work = write_in_core_index_as_tree(the_repository);
+
+			ret = reset_tree(new_tree,
+					 opts, 1,
+					 writeout_error, new_branch_info);
+			if (ret)
+				return ret;
+			o.ancestor = old_branch_info->name;
+			if (!old_branch_info->name) {
+				strbuf_add_unique_abbrev(&old_commit_shortname,
+							 &old_branch_info->commit->object.oid,
+							 DEFAULT_ABBREV);
+				o.ancestor = old_commit_shortname.buf;
+			}
+			o.branch1 = new_branch_info->name;
+			o.branch2 = "local";
+			o.conflict_style = opts->conflict_style;
+			ret = merge_trees(&o,
+					  new_tree,
+					  work,
+					  old_tree);
+			if (ret < 0)
+				exit(128);
+			ret = reset_tree(new_tree,
+					 opts, 0,
+					 writeout_error, new_branch_info);
+			strbuf_release(&o.obuf);
+			strbuf_release(&old_commit_shortname);
+			if (ret)
+				return ret;
+		}
+	}
+
+	if (!cache_tree_fully_valid(the_repository->index->cache_tree))
+		cache_tree_update(the_repository->index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
+
+	if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+		die(_("unable to write new index file"));
+
+	if (!opts->discard_changes && !opts->quiet && new_branch_info->commit)
+		show_local_changes(&new_branch_info->commit->object, &opts->diff_options);
+
+	return 0;
+}
+
+static void report_tracking(struct branch_info *new_branch_info)
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct branch *branch = branch_get(new_branch_info->name);
+
+	if (!format_tracking_info(branch, &sb, AHEAD_BEHIND_FULL, 1))
+		return;
+	fputs(sb.buf, stdout);
+	strbuf_release(&sb);
+}
+
+static void update_refs_for_switch(const struct checkout_opts *opts,
+				   struct branch_info *old_branch_info,
+				   struct branch_info *new_branch_info)
+{
+	struct strbuf msg = STRBUF_INIT;
+	const char *old_desc, *reflog_msg;
+	if (opts->new_branch) {
+		if (opts->new_orphan_branch) {
+			enum log_refs_config log_all_ref_updates =
+				repo_settings_get_log_all_ref_updates(the_repository);
+			char *refname;
+
+			refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
+			if (opts->new_branch_log &&
+			    !should_autocreate_reflog(log_all_ref_updates, refname)) {
+				int ret;
+				struct strbuf err = STRBUF_INIT;
+
+				ret = refs_create_reflog(get_main_ref_store(the_repository),
+							 refname, &err);
+				if (ret) {
+					fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
+						opts->new_orphan_branch, err.buf);
+					strbuf_release(&err);
+					free(refname);
+					return;
+				}
+				strbuf_release(&err);
+			}
+			free(refname);
+		}
+		else
+			create_branch(the_repository,
+				      opts->new_branch, new_branch_info->name,
+				      opts->new_branch_force ? 1 : 0,
+				      opts->new_branch_force ? 1 : 0,
+				      opts->new_branch_log,
+				      opts->quiet,
+				      opts->track,
+				      0);
+		free(new_branch_info->name);
+		free(new_branch_info->refname);
+		new_branch_info->name = xstrdup(opts->new_branch);
+		setup_branch_path(new_branch_info);
+	}
+
+	old_desc = old_branch_info->name;
+	if (!old_desc && old_branch_info->commit)
+		old_desc = oid_to_hex(&old_branch_info->commit->object.oid);
+
+	reflog_msg = getenv("GIT_REFLOG_ACTION");
+	if (!reflog_msg)
+		strbuf_addf(&msg, "checkout: moving from %s to %s",
+			old_desc ? old_desc : "(invalid)", new_branch_info->name);
+	else
+		strbuf_insertstr(&msg, 0, reflog_msg);
+
+	if (!strcmp(new_branch_info->name, "HEAD") && !new_branch_info->path && !opts->force_detach) {
+		/* Nothing to do. */
+	} else if (opts->force_detach || !new_branch_info->path) {	/* No longer on any branch. */
+		refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+				"HEAD", &new_branch_info->commit->object.oid,
+				NULL,
+				REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
+		if (!opts->quiet) {
+			if (old_branch_info->path &&
+			    advice_enabled(ADVICE_DETACHED_HEAD) && !opts->force_detach)
+				detach_advice(new_branch_info->name);
+			describe_detached_head(_("HEAD is now at"), new_branch_info->commit);
+		}
+	} else if (new_branch_info->path) {	/* Switch branches. */
+		if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", new_branch_info->path, msg.buf) < 0)
+			die(_("unable to update HEAD"));
+		if (!opts->quiet) {
+			if (old_branch_info->path && !strcmp(new_branch_info->path, old_branch_info->path)) {
+				if (opts->new_branch_force)
+					fprintf(stderr, _("Reset branch '%s'\n"),
+						new_branch_info->name);
+				else
+					fprintf(stderr, _("Already on '%s'\n"),
+						new_branch_info->name);
+			} else if (opts->new_branch) {
+				if (opts->branch_exists)
+					fprintf(stderr, _("Switched to and reset branch '%s'\n"), new_branch_info->name);
+				else
+					fprintf(stderr, _("Switched to a new branch '%s'\n"), new_branch_info->name);
+			} else {
+				fprintf(stderr, _("Switched to branch '%s'\n"),
+					new_branch_info->name);
+			}
+		}
+		if (old_branch_info->path && old_branch_info->name) {
+			if (!refs_ref_exists(get_main_ref_store(the_repository), old_branch_info->path) && refs_reflog_exists(get_main_ref_store(the_repository), old_branch_info->path))
+				refs_delete_reflog(get_main_ref_store(the_repository),
+						   old_branch_info->path);
+		}
+	}
+	remove_branch_state(the_repository, !opts->quiet);
+	strbuf_release(&msg);
+	if (!opts->quiet &&
+	    !opts->force_detach &&
+	    (new_branch_info->path || !strcmp(new_branch_info->name, "HEAD")))
+		report_tracking(new_branch_info);
+}
+
+static int add_pending_uninteresting_ref(const char *refname, const char *referent UNUSED,
+					 const struct object_id *oid,
+					 int flags UNUSED, void *cb_data)
+{
+	add_pending_oid(cb_data, refname, oid, UNINTERESTING);
+	return 0;
+}
+
+static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
+{
+	strbuf_addstr(sb, "  ");
+	strbuf_add_unique_abbrev(sb, &commit->object.oid, DEFAULT_ABBREV);
+	strbuf_addch(sb, ' ');
+	if (!repo_parse_commit(the_repository, commit))
+		pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
+	strbuf_addch(sb, '\n');
+}
+
+#define ORPHAN_CUTOFF 4
+static void suggest_reattach(struct commit *commit, struct rev_info *revs)
+{
+	struct commit *c, *last = NULL;
+	struct strbuf sb = STRBUF_INIT;
+	int lost = 0;
+	while ((c = get_revision(revs)) != NULL) {
+		if (lost < ORPHAN_CUTOFF)
+			describe_one_orphan(&sb, c);
+		last = c;
+		lost++;
+	}
+	if (ORPHAN_CUTOFF < lost) {
+		int more = lost - ORPHAN_CUTOFF;
+		if (more == 1)
+			describe_one_orphan(&sb, last);
+		else
+			strbuf_addf(&sb, _(" ... and %d more.\n"), more);
+	}
+
+	fprintf(stderr,
+		Q_(
+		/* The singular version */
+		"Warning: you are leaving %d commit behind, "
+		"not connected to\n"
+		"any of your branches:\n\n"
+		"%s\n",
+		/* The plural version */
+		"Warning: you are leaving %d commits behind, "
+		"not connected to\n"
+		"any of your branches:\n\n"
+		"%s\n",
+		/* Give ngettext() the count */
+		lost),
+		lost,
+		sb.buf);
+	strbuf_release(&sb);
+
+	if (advice_enabled(ADVICE_DETACHED_HEAD))
+		fprintf(stderr,
+			Q_(
+			/* The singular version */
+			"If you want to keep it by creating a new branch, "
+			"this may be a good time\nto do so with:\n\n"
+			" git branch <new-branch-name> %s\n\n",
+			/* The plural version */
+			"If you want to keep them by creating a new branch, "
+			"this may be a good time\nto do so with:\n\n"
+			" git branch <new-branch-name> %s\n\n",
+			/* Give ngettext() the count */
+			lost),
+			repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
+}
+
+/*
+ * We are about to leave commit that was at the tip of a detached
+ * HEAD.  If it is not reachable from any ref, this is the last chance
+ * for the user to do so without resorting to reflog.
+ */
+static void orphaned_commit_warning(struct commit *old_commit, struct commit *new_commit)
+{
+	struct rev_info revs;
+	struct object *object = &old_commit->object;
+
+	repo_init_revisions(the_repository, &revs, NULL);
+	setup_revisions(0, NULL, &revs, NULL);
+
+	object->flags &= ~UNINTERESTING;
+	add_pending_object(&revs, object, oid_to_hex(&object->oid));
+
+	refs_for_each_ref(get_main_ref_store(the_repository),
+			  add_pending_uninteresting_ref, &revs);
+	if (new_commit)
+		add_pending_oid(&revs, "HEAD",
+				&new_commit->object.oid,
+				UNINTERESTING);
+
+	if (prepare_revision_walk(&revs))
+		die(_("internal error in revision walk"));
+	if (!(old_commit->object.flags & UNINTERESTING))
+		suggest_reattach(old_commit, &revs);
+	else
+		describe_detached_head(_("Previous HEAD position was"), old_commit);
+
+	/* Clean up objects used, as they will be reused. */
+	repo_clear_commit_marks(the_repository, ALL_REV_FLAGS);
+	release_revisions(&revs);
+}
+
+static int switch_branches(const struct checkout_opts *opts,
+			   struct branch_info *new_branch_info)
+{
+	int ret = 0;
+	struct branch_info old_branch_info = { 0 };
+	struct object_id rev;
+	int flag, writeout_error = 0;
+	int do_merge = 1;
+
+	trace2_cmd_mode("branch");
+
+	memset(&old_branch_info, 0, sizeof(old_branch_info));
+	old_branch_info.path = refs_resolve_refdup(get_main_ref_store(the_repository),
+						   "HEAD", 0, &rev, &flag);
+	if (old_branch_info.path)
+		old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);
+	if (!(flag & REF_ISSYMREF))
+		FREE_AND_NULL(old_branch_info.path);
+
+	if (old_branch_info.path) {
+		const char *const prefix = "refs/heads/";
+		const char *p;
+		if (skip_prefix(old_branch_info.path, prefix, &p))
+			old_branch_info.name = xstrdup(p);
+	}
+
+	if (opts->new_orphan_branch && opts->orphan_from_empty_tree) {
+		if (new_branch_info->name)
+			BUG("'switch --orphan' should never accept a commit as starting point");
+		new_branch_info->commit = NULL;
+		new_branch_info->name = xstrdup("(empty)");
+		do_merge = 1;
+	}
+
+	if (!new_branch_info->name) {
+		new_branch_info->name = xstrdup("HEAD");
+		new_branch_info->commit = old_branch_info.commit;
+		if (!new_branch_info->commit)
+			die(_("You are on a branch yet to be born"));
+		parse_commit_or_die(new_branch_info->commit);
+
+		if (opts->only_merge_on_switching_branches)
+			do_merge = 0;
+	}
+
+	if (do_merge) {
+		ret = merge_working_tree(opts, &old_branch_info, new_branch_info, &writeout_error);
+		if (ret) {
+			branch_info_release(&old_branch_info);
+			return ret;
+		}
+	}
+
+	if (!opts->quiet && !old_branch_info.path && old_branch_info.commit && new_branch_info->commit != old_branch_info.commit)
+		orphaned_commit_warning(old_branch_info.commit, new_branch_info->commit);
+
+	update_refs_for_switch(opts, &old_branch_info, new_branch_info);
+
+	ret = post_checkout_hook(old_branch_info.commit, new_branch_info->commit, 1);
+	branch_info_release(&old_branch_info);
+
+	return ret || writeout_error;
+}
+
+static int git_checkout_config(const char *var, const char *value,
+			       const struct config_context *ctx, void *cb)
+{
+	struct checkout_opts *opts = cb;
+
+	if (!strcmp(var, "diff.ignoresubmodules")) {
+		if (!value)
+			return config_error_nonbool(var);
+		handle_ignore_submodules_arg(&opts->diff_options, value);
+		return 0;
+	}
+	if (!strcmp(var, "checkout.guess")) {
+		opts->dwim_new_local_branch = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (starts_with(var, "submodule."))
+		return git_default_submodule_config(var, value, NULL);
+
+	return git_xmerge_config(var, value, ctx, NULL);
+}
+
+static void setup_new_branch_info_and_source_tree(
+	struct branch_info *new_branch_info,
+	struct checkout_opts *opts,
+	struct object_id *rev,
+	const char *arg)
+{
+	struct tree **source_tree = &opts->source_tree;
+	struct object_id branch_rev;
+
+	/* treat '@' as a shortcut for 'HEAD' */
+	new_branch_info->name = !strcmp(arg, "@") ? xstrdup("HEAD") :
+						    xstrdup(arg);
+	setup_branch_path(new_branch_info);
+
+	if (!check_refname_format(new_branch_info->path, 0) &&
+	    !refs_read_ref(get_main_ref_store(the_repository), new_branch_info->path, &branch_rev))
+		oidcpy(rev, &branch_rev);
+	else
+		/* not an existing branch */
+		FREE_AND_NULL(new_branch_info->path);
+
+	new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
+	if (!new_branch_info->commit) {
+		/* not a commit */
+		*source_tree = parse_tree_indirect(rev);
+		if (!*source_tree)
+			die(_("unable to read tree (%s)"), oid_to_hex(rev));
+	} else {
+		parse_commit_or_die(new_branch_info->commit);
+		*source_tree = repo_get_commit_tree(the_repository,
+						    new_branch_info->commit);
+		if (!*source_tree)
+			die(_("unable to read tree (%s)"),
+			    oid_to_hex(&new_branch_info->commit->object.oid));
+	}
+}
+
+static char *parse_remote_branch(const char *arg,
+				 struct object_id *rev,
+				 int could_be_checkout_paths)
+{
+	int num_matches = 0;
+	char *remote = unique_tracking_name(arg, rev, &num_matches);
+
+	if (remote && could_be_checkout_paths) {
+		die(_("'%s' could be both a local file and a tracking branch.\n"
+			"Please use -- (and optionally --no-guess) to disambiguate"),
+		    arg);
+	}
+
+	if (!remote && num_matches > 1) {
+	    if (advice_enabled(ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME)) {
+		    advise(_("If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
+			     "you can do so by fully qualifying the name with the --track option:\n"
+			     "\n"
+			     "    git checkout --track origin/<name>\n"
+			     "\n"
+			     "If you'd like to always have checkouts of an ambiguous <name> prefer\n"
+			     "one remote, e.g. the 'origin' remote, consider setting\n"
+			     "checkout.defaultRemote=origin in your config."));
+	    }
+
+	    die(_("'%s' matched multiple (%d) remote tracking branches"),
+		arg, num_matches);
+	}
+
+	return remote;
+}
+
+static int parse_branchname_arg(int argc, const char **argv,
+				int dwim_new_local_branch_ok,
+				struct branch_info *new_branch_info,
+				struct checkout_opts *opts,
+				struct object_id *rev)
+{
+	const char **new_branch = &opts->new_branch;
+	int argcount = 0;
+	const char *arg;
+	char *remote = NULL;
+	int dash_dash_pos;
+	int has_dash_dash = 0;
+	int i;
+
+	/*
+	 * case 1: git checkout <ref> -- [<paths>]
+	 *
+	 *   <ref> must be a valid tree, everything after the '--' must be
+	 *   a path.
+	 *
+	 * case 2: git checkout -- [<paths>]
+	 *
+	 *   everything after the '--' must be paths.
+	 *
+	 * case 3: git checkout <something> [--]
+	 *
+	 *   (a) If <something> is a commit, that is to
+	 *       switch to the branch or detach HEAD at it.  As a special case,
+	 *       if <something> is A...B (missing A or B means HEAD but you can
+	 *       omit at most one side), and if there is a unique merge base
+	 *       between A and B, A...B names that merge base.
+	 *
+	 *   (b) If <something> is _not_ a commit, either "--" is present
+	 *       or <something> is not a path, no -t or -b was given,
+	 *       and there is a tracking branch whose name is <something>
+	 *       in one and only one remote (or if the branch exists on the
+	 *       remote named in checkout.defaultRemote), then this is a
+	 *       short-hand to fork local <something> from that
+	 *       remote-tracking branch.
+	 *
+	 *   (c) Otherwise, if "--" is present, treat it like case (1).
+	 *
+	 *   (d) Otherwise :
+	 *       - if it's a reference, treat it like case (1)
+	 *       - else if it's a path, treat it like case (2)
+	 *       - else: fail.
+	 *
+	 * case 4: git checkout <something> <paths>
+	 *
+	 *   The first argument must not be ambiguous.
+	 *   - If it's *only* a reference, treat it like case (1).
+	 *   - If it's only a path, treat it like case (2).
+	 *   - else: fail.
+	 *
+	 */
+	if (!argc)
+		return 0;
+
+	if (!opts->accept_pathspec) {
+		if (argc > 1)
+			die(_("only one reference expected"));
+		has_dash_dash = 1; /* helps disambiguate */
+	}
+
+	arg = argv[0];
+	dash_dash_pos = -1;
+	for (i = 0; i < argc; i++) {
+		if (opts->accept_pathspec && !strcmp(argv[i], "--")) {
+			dash_dash_pos = i;
+			break;
+		}
+	}
+	if (dash_dash_pos == 0)
+		return 1; /* case (2) */
+	else if (dash_dash_pos == 1)
+		has_dash_dash = 1; /* case (3) or (1) */
+	else if (dash_dash_pos >= 2)
+		die(_("only one reference expected, %d given."), dash_dash_pos);
+	opts->count_checkout_paths = !opts->quiet && !has_dash_dash;
+
+	if (!strcmp(arg, "-"))
+		arg = "@{-1}";
+
+	if (repo_get_oid_mb(the_repository, arg, rev)) {
+		/*
+		 * Either case (3) or (4), with <something> not being
+		 * a commit, or an attempt to use case (1) with an
+		 * invalid ref.
+		 *
+		 * It's likely an error, but we need to find out if
+		 * we should auto-create the branch, case (3).(b).
+		 */
+		int recover_with_dwim = dwim_new_local_branch_ok;
+
+		int could_be_checkout_paths = !has_dash_dash &&
+			check_filename(opts->prefix, arg);
+
+		if (!has_dash_dash && !no_wildcard(arg))
+			recover_with_dwim = 0;
+
+		/*
+		 * Accept "git checkout foo", "git checkout foo --"
+		 * and "git switch foo" as candidates for dwim.
+		 */
+		if (!(argc == 1 && !has_dash_dash) &&
+		    !(argc == 2 && has_dash_dash) &&
+		    opts->accept_pathspec)
+			recover_with_dwim = 0;
+
+		if (recover_with_dwim) {
+			remote = parse_remote_branch(arg, rev,
+						     could_be_checkout_paths);
+			if (remote) {
+				*new_branch = arg;
+				arg = remote;
+				/* DWIMmed to create local branch, case (3).(b) */
+			} else {
+				recover_with_dwim = 0;
+			}
+		}
+
+		if (!recover_with_dwim) {
+			if (has_dash_dash)
+				die(_("invalid reference: %s"), arg);
+			return argcount;
+		}
+	}
+
+	/* we can't end up being in (2) anymore, eat the argument */
+	argcount++;
+	argv++;
+	argc--;
+
+	setup_new_branch_info_and_source_tree(new_branch_info, opts, rev, arg);
+
+	if (!opts->source_tree)                   /* case (1): want a tree */
+		die(_("reference is not a tree: %s"), arg);
+
+	if (!has_dash_dash) {	/* case (3).(d) -> (1) */
+		/*
+		 * Do not complain the most common case
+		 *	git checkout branch
+		 * even if there happen to be a file called 'branch';
+		 * it would be extremely annoying.
+		 */
+		if (argc)
+			verify_non_filename(opts->prefix, arg);
+	} else if (opts->accept_pathspec) {
+		argcount++;
+		argv++;
+		argc--;
+	}
+
+	free(remote);
+	return argcount;
+}
+
+static int switch_unborn_to_new_branch(const struct checkout_opts *opts)
+{
+	int status;
+	struct strbuf branch_ref = STRBUF_INIT;
+
+	trace2_cmd_mode("unborn");
+
+	if (!opts->new_branch)
+		die(_("You are on a branch yet to be born"));
+	strbuf_addf(&branch_ref, "refs/heads/%s", opts->new_branch);
+	status = refs_update_symref(get_main_ref_store(the_repository),
+				    "HEAD", branch_ref.buf, "checkout -b");
+	strbuf_release(&branch_ref);
+	if (!opts->quiet)
+		fprintf(stderr, _("Switched to a new branch '%s'\n"),
+			opts->new_branch);
+	return status;
+}
+
+static void die_expecting_a_branch(const struct branch_info *branch_info)
+{
+	struct object_id oid;
+	char *to_free;
+	int code;
+
+	if (repo_dwim_ref(the_repository, branch_info->name,
+			  strlen(branch_info->name), &oid, &to_free, 0) == 1) {
+		const char *ref = to_free;
+
+		if (skip_prefix(ref, "refs/tags/", &ref))
+			code = die_message(_("a branch is expected, got tag '%s'"), ref);
+		else if (skip_prefix(ref, "refs/remotes/", &ref))
+			code = die_message(_("a branch is expected, got remote branch '%s'"), ref);
+		else
+			code = die_message(_("a branch is expected, got '%s'"), ref);
+	}
+	else if (branch_info->commit)
+		code = die_message(_("a branch is expected, got commit '%s'"), branch_info->name);
+	else
+		/*
+		 * This case should never happen because we already die() on
+		 * non-commit, but just in case.
+		 */
+		code = die_message(_("a branch is expected, got '%s'"), branch_info->name);
+
+	if (advice_enabled(ADVICE_SUGGEST_DETACHING_HEAD))
+		advise(_("If you want to detach HEAD at the commit, try again with the --detach option."));
+
+	exit(code);
+}
+
+static void die_if_some_operation_in_progress(void)
+{
+	struct wt_status_state state;
+
+	memset(&state, 0, sizeof(state));
+	wt_status_get_state(the_repository, &state, 0);
+
+	if (state.merge_in_progress)
+		die(_("cannot switch branch while merging\n"
+		      "Consider \"git merge --quit\" "
+		      "or \"git worktree add\"."));
+	if (state.am_in_progress)
+		die(_("cannot switch branch in the middle of an am session\n"
+		      "Consider \"git am --quit\" "
+		      "or \"git worktree add\"."));
+	if (state.rebase_interactive_in_progress || state.rebase_in_progress)
+		die(_("cannot switch branch while rebasing\n"
+		      "Consider \"git rebase --quit\" "
+		      "or \"git worktree add\"."));
+	if (state.cherry_pick_in_progress)
+		die(_("cannot switch branch while cherry-picking\n"
+		      "Consider \"git cherry-pick --quit\" "
+		      "or \"git worktree add\"."));
+	if (state.revert_in_progress)
+		die(_("cannot switch branch while reverting\n"
+		      "Consider \"git revert --quit\" "
+		      "or \"git worktree add\"."));
+	if (state.bisect_in_progress)
+		warning(_("you are switching branch while bisecting"));
+
+	wt_status_state_free_buffers(&state);
+}
+
+/*
+ * die if attempting to checkout an existing branch that is in use
+ * in another worktree, unless ignore-other-wortrees option is given.
+ * The check is bypassed when the branch is already the current one,
+ * as it will not make things any worse.
+ */
+static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts,
+						const char *full_ref)
+{
+	int flags;
+	char *head_ref;
+
+	if (opts->ignore_other_worktrees)
+		return;
+	head_ref = refs_resolve_refdup(get_main_ref_store(the_repository),
+				       "HEAD", 0, NULL, &flags);
+	if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref, full_ref)))
+		die_if_checked_out(full_ref, 1);
+	free(head_ref);
+}
+
+static int checkout_branch(struct checkout_opts *opts,
+			   struct branch_info *new_branch_info)
+{
+	int noop_switch = (!new_branch_info->name &&
+			   !opts->new_branch &&
+			   !opts->force_detach);
+
+	if (opts->pathspec.nr)
+		die(_("paths cannot be used with switching branches"));
+
+	if (opts->patch_mode)
+		die(_("'%s' cannot be used with switching branches"),
+		    "--patch");
+
+	if (opts->overlay_mode != -1)
+		die(_("'%s' cannot be used with switching branches"),
+		    "--[no]-overlay");
+
+	if (opts->writeout_stage) {
+		const char *msg;
+		if (noop_switch)
+			msg = _("'%s' needs the paths to check out");
+		else
+			msg = _("'%s' cannot be used with switching branches");
+		die(msg, "--ours/--theirs");
+	}
+
+	if (opts->force && opts->merge)
+		die(_("'%s' cannot be used with '%s'"), "-f", "-m");
+
+	if (opts->discard_changes && opts->merge)
+		die(_("'%s' cannot be used with '%s'"), "--discard-changes", "--merge");
+
+	if (opts->force_detach && opts->new_branch)
+		die(_("'%s' cannot be used with '%s'"),
+		    "--detach", "-b/-B/--orphan");
+
+	if (opts->new_orphan_branch) {
+		if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+			die(_("'%s' cannot be used with '%s'"), "--orphan", "-t");
+		if (opts->orphan_from_empty_tree && new_branch_info->name)
+			die(_("'%s' cannot take <start-point>"), "--orphan");
+	} else if (opts->force_detach) {
+		if (opts->track != BRANCH_TRACK_UNSPECIFIED)
+			die(_("'%s' cannot be used with '%s'"), "--detach", "-t");
+	} else if (opts->track == BRANCH_TRACK_UNSPECIFIED)
+		opts->track = git_branch_track;
+
+	if (new_branch_info->name && !new_branch_info->commit)
+		die(_("Cannot switch branch to a non-commit '%s'"),
+		    new_branch_info->name);
+
+	if (noop_switch &&
+	    !opts->switch_branch_doing_nothing_is_ok)
+		die(_("missing branch or commit argument"));
+
+	if (!opts->implicit_detach &&
+	    !opts->force_detach &&
+	    !opts->new_branch &&
+	    !opts->new_branch_force &&
+	    new_branch_info->name &&
+	    !new_branch_info->path)
+		die_expecting_a_branch(new_branch_info);
+
+	if (!opts->can_switch_when_in_progress)
+		die_if_some_operation_in_progress();
+
+	/* "git checkout <branch>" */
+	if (new_branch_info->path && !opts->force_detach && !opts->new_branch)
+		die_if_switching_to_a_branch_in_use(opts, new_branch_info->path);
+
+	/* "git checkout -B <branch>" */
+	if (opts->new_branch_force) {
+		char *full_ref = xstrfmt("refs/heads/%s", opts->new_branch);
+		die_if_switching_to_a_branch_in_use(opts, full_ref);
+		free(full_ref);
+	}
+
+	if (!new_branch_info->commit && opts->new_branch) {
+		struct object_id rev;
+		int flag;
+
+		if (!refs_read_ref_full(get_main_ref_store(the_repository), "HEAD", 0, &rev, &flag) &&
+		    (flag & REF_ISSYMREF) && is_null_oid(&rev))
+			return switch_unborn_to_new_branch(opts);
+	}
+	return switch_branches(opts, new_branch_info);
+}
+
+static int parse_opt_conflict(const struct option *o, const char *arg, int unset)
+{
+	struct checkout_opts *opts = o->value;
+
+	if (unset) {
+		opts->conflict_style = -1;
+		return 0;
+	}
+	opts->conflict_style = parse_conflict_style_name(arg);
+	if (opts->conflict_style < 0)
+		return error(_("unknown conflict style '%s'"), arg);
+	/* --conflict overrides a previous --no-merge */
+	if (!opts->merge)
+		opts->merge = -1;
+
+	return 0;
+}
+
+static struct option *add_common_options(struct checkout_opts *opts,
+					 struct option *prevopts)
+{
+	struct option options[] = {
+		OPT__QUIET(&opts->quiet, N_("suppress progress reporting")),
+		OPT_CALLBACK_F(0, "recurse-submodules", NULL,
+			    "checkout", "control recursive updating of submodules",
+			    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
+		OPT_BOOL(0, "progress", &opts->show_progress, N_("force progress reporting")),
+		OPT_BOOL('m', "merge", &opts->merge, N_("perform a 3-way merge with the new branch")),
+		OPT_CALLBACK(0, "conflict", opts, N_("style"),
+			     N_("conflict style (merge, diff3, or zdiff3)"),
+			     parse_opt_conflict),
+		OPT_END()
+	};
+	struct option *newopts = parse_options_concat(prevopts, options);
+	free(prevopts);
+	return newopts;
+}
+
+static struct option *add_common_switch_branch_options(
+	struct checkout_opts *opts, struct option *prevopts)
+{
+	struct option options[] = {
+		OPT_BOOL('d', "detach", &opts->force_detach, N_("detach HEAD at named commit")),
+		OPT_CALLBACK_F('t', "track",  &opts->track, "(direct|inherit)",
+			N_("set branch tracking configuration"),
+			PARSE_OPT_OPTARG,
+			parse_opt_tracking_mode),
+		OPT__FORCE(&opts->force, N_("force checkout (throw away local modifications)"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_STRING(0, "orphan", &opts->new_orphan_branch, N_("new-branch"), N_("new unborn branch")),
+		OPT_BOOL_F(0, "overwrite-ignore", &opts->overwrite_ignore,
+			   N_("update ignored files (default)"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "ignore-other-worktrees", &opts->ignore_other_worktrees,
+			 N_("do not check if another worktree is using this branch")),
+		OPT_END()
+	};
+	struct option *newopts = parse_options_concat(prevopts, options);
+	free(prevopts);
+	return newopts;
+}
+
+static struct option *add_checkout_path_options(struct checkout_opts *opts,
+						struct option *prevopts)
+{
+	struct option options[] = {
+		OPT_SET_INT_F('2', "ours", &opts->writeout_stage,
+			      N_("checkout our version for unmerged files"),
+			      2, PARSE_OPT_NONEG),
+		OPT_SET_INT_F('3', "theirs", &opts->writeout_stage,
+			      N_("checkout their version for unmerged files"),
+			      3, PARSE_OPT_NONEG),
+		OPT_BOOL('p', "patch", &opts->patch_mode, N_("select hunks interactively")),
+		OPT_BOOL(0, "ignore-skip-worktree-bits", &opts->ignore_skipworktree,
+			 N_("do not limit pathspecs to sparse entries only")),
+		OPT_PATHSPEC_FROM_FILE(&opts->pathspec_from_file),
+		OPT_PATHSPEC_FILE_NUL(&opts->pathspec_file_nul),
+		OPT_END()
+	};
+	struct option *newopts = parse_options_concat(prevopts, options);
+	free(prevopts);
+	return newopts;
+}
+
+/* create-branch option (either b or c) */
+static char cb_option = 'b';
+
+static int checkout_main(int argc, const char **argv, const char *prefix,
+			 struct checkout_opts *opts, struct option *options,
+			 const char * const usagestr[])
+{
+	int parseopt_flags = 0;
+	struct branch_info new_branch_info = { 0 };
+	int ret;
+
+	opts->overwrite_ignore = 1;
+	opts->prefix = prefix;
+	opts->show_progress = -1;
+
+	git_config(git_checkout_config, opts);
+	if (the_repository->gitdir) {
+		prepare_repo_settings(the_repository);
+		the_repository->settings.command_requires_full_index = 0;
+	}
+
+	opts->track = BRANCH_TRACK_UNSPECIFIED;
+
+	if (!opts->accept_pathspec && !opts->accept_ref)
+		BUG("make up your mind, you need to take _something_");
+	if (opts->accept_pathspec && opts->accept_ref)
+		parseopt_flags = PARSE_OPT_KEEP_DASHDASH;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     usagestr, parseopt_flags);
+
+	if (opts->show_progress < 0) {
+		if (opts->quiet)
+			opts->show_progress = 0;
+		else
+			opts->show_progress = isatty(2);
+	}
+
+	/* --conflicts implies --merge */
+	if (opts->merge == -1)
+		opts->merge = opts->conflict_style >= 0;
+
+	if (opts->force) {
+		opts->discard_changes = 1;
+		opts->ignore_unmerged_opt = "--force";
+		opts->ignore_unmerged = 1;
+	}
+
+	if ((!!opts->new_branch + !!opts->new_branch_force + !!opts->new_orphan_branch) > 1)
+		die(_("options '-%c', '-%c', and '%s' cannot be used together"),
+			cb_option, toupper(cb_option), "--orphan");
+
+	if (opts->overlay_mode == 1 && opts->patch_mode)
+		die(_("options '%s' and '%s' cannot be used together"), "-p", "--overlay");
+
+	if (opts->checkout_index >= 0 || opts->checkout_worktree >= 0) {
+		if (opts->checkout_index < 0)
+			opts->checkout_index = 0;
+		if (opts->checkout_worktree < 0)
+			opts->checkout_worktree = 0;
+	} else {
+		if (opts->checkout_index < 0)
+			opts->checkout_index = -opts->checkout_index - 1;
+		if (opts->checkout_worktree < 0)
+			opts->checkout_worktree = -opts->checkout_worktree - 1;
+	}
+	if (opts->checkout_index < 0 || opts->checkout_worktree < 0)
+		BUG("these flags should be non-negative by now");
+	/*
+	 * convenient shortcut: "git restore --staged [--worktree]" equals
+	 * "git restore --staged [--worktree] --source HEAD"
+	 */
+	if (!opts->from_treeish && opts->checkout_index)
+		opts->from_treeish = "HEAD";
+
+	/*
+	 * From here on, new_branch will contain the branch to be checked out,
+	 * and new_branch_force and new_orphan_branch will tell us which one of
+	 * -b/-B/-c/-C/--orphan is being used.
+	 */
+	if (opts->new_branch_force)
+		opts->new_branch = opts->new_branch_force;
+
+	if (opts->new_orphan_branch)
+		opts->new_branch = opts->new_orphan_branch;
+
+	/* --track without -c/-C/-b/-B/--orphan should DWIM */
+	if (opts->track != BRANCH_TRACK_UNSPECIFIED && !opts->new_branch) {
+		const char *argv0 = argv[0];
+		if (!argc || !strcmp(argv0, "--"))
+			die(_("--track needs a branch name"));
+		skip_prefix(argv0, "refs/", &argv0);
+		skip_prefix(argv0, "remotes/", &argv0);
+		argv0 = strchr(argv0, '/');
+		if (!argv0 || !argv0[1])
+			die(_("missing branch name; try -%c"), cb_option);
+		opts->new_branch = argv0 + 1;
+	}
+
+	/*
+	 * Extract branch name from command line arguments, so
+	 * all that is left is pathspecs.
+	 *
+	 * Handle
+	 *
+	 *  1) git checkout <tree> -- [<paths>]
+	 *  2) git checkout -- [<paths>]
+	 *  3) git checkout <something> [<paths>]
+	 *
+	 * including "last branch" syntax and DWIM-ery for names of
+	 * remote branches, erroring out for invalid or ambiguous cases.
+	 */
+	if (argc && opts->accept_ref) {
+		struct object_id rev;
+		int dwim_ok =
+			!opts->patch_mode &&
+			opts->dwim_new_local_branch &&
+			opts->track == BRANCH_TRACK_UNSPECIFIED &&
+			!opts->new_branch;
+		int n = parse_branchname_arg(argc, argv, dwim_ok,
+					     &new_branch_info, opts, &rev);
+		argv += n;
+		argc -= n;
+	} else if (!opts->accept_ref && opts->from_treeish) {
+		struct object_id rev;
+
+		if (repo_get_oid_mb(the_repository, opts->from_treeish, &rev))
+			die(_("could not resolve %s"), opts->from_treeish);
+
+		setup_new_branch_info_and_source_tree(&new_branch_info,
+						      opts, &rev,
+						      opts->from_treeish);
+
+		if (!opts->source_tree)
+			die(_("reference is not a tree: %s"), opts->from_treeish);
+	}
+
+	if (argc) {
+		parse_pathspec(&opts->pathspec, 0,
+			       opts->patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0,
+			       prefix, argv);
+
+		if (!opts->pathspec.nr)
+			die(_("invalid path specification"));
+
+		/*
+		 * Try to give more helpful suggestion.
+		 * new_branch && argc > 1 will be caught later.
+		 */
+		if (opts->new_branch && argc == 1 && !new_branch_info.commit)
+			die(_("'%s' is not a commit and a branch '%s' cannot be created from it"),
+				argv[0], opts->new_branch);
+
+		if (opts->force_detach)
+			die(_("git checkout: --detach does not take a path argument '%s'"),
+			    argv[0]);
+	}
+
+	if (opts->pathspec_from_file) {
+		if (opts->pathspec.nr)
+			die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
+
+		if (opts->force_detach)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--detach");
+
+		if (opts->patch_mode)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--patch");
+
+		parse_pathspec_file(&opts->pathspec, 0,
+				    0,
+				    prefix, opts->pathspec_from_file, opts->pathspec_file_nul);
+	} else if (opts->pathspec_file_nul) {
+		die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
+	}
+
+	opts->pathspec.recursive = 1;
+
+	if (opts->pathspec.nr) {
+		if (1 < !!opts->writeout_stage + !!opts->force + !!opts->merge)
+			die(_("git checkout: --ours/--theirs, --force and --merge are incompatible when\n"
+			      "checking out of the index."));
+	} else {
+		if (opts->accept_pathspec && !opts->empty_pathspec_ok &&
+		    !opts->patch_mode)	/* patch mode is special */
+			die(_("you must specify path(s) to restore"));
+	}
+
+	if (opts->new_branch) {
+		struct strbuf buf = STRBUF_INIT;
+
+		if (opts->new_branch_force)
+			opts->branch_exists = validate_branchname(opts->new_branch, &buf);
+		else
+			opts->branch_exists =
+				validate_new_branchname(opts->new_branch, &buf, 0);
+		strbuf_release(&buf);
+	}
+
+	if (opts->patch_mode || opts->pathspec.nr)
+		ret = checkout_paths(opts, &new_branch_info);
+	else
+		ret = checkout_branch(opts, &new_branch_info);
+
+	branch_info_release(&new_branch_info);
+	clear_pathspec(&opts->pathspec);
+	free(opts->pathspec_from_file);
+	free(options);
+
+	return ret;
+}
+
+int cmd_checkout(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct checkout_opts opts = CHECKOUT_OPTS_INIT;
+	struct option *options;
+	struct option checkout_options[] = {
+		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
+			   N_("create and checkout a new branch")),
+		OPT_STRING('B', NULL, &opts.new_branch_force, N_("branch"),
+			   N_("create/reset and checkout a branch")),
+		OPT_BOOL('l', NULL, &opts.new_branch_log, N_("create reflog for new branch")),
+		OPT_BOOL(0, "guess", &opts.dwim_new_local_branch,
+			 N_("second guess 'git checkout <no-such-branch>' (default)")),
+		OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode (default)")),
+		OPT_END()
+	};
+
+	opts.dwim_new_local_branch = 1;
+	opts.switch_branch_doing_nothing_is_ok = 1;
+	opts.only_merge_on_switching_branches = 0;
+	opts.accept_ref = 1;
+	opts.accept_pathspec = 1;
+	opts.implicit_detach = 1;
+	opts.can_switch_when_in_progress = 1;
+	opts.orphan_from_empty_tree = 0;
+	opts.empty_pathspec_ok = 1;
+	opts.overlay_mode = -1;
+	opts.checkout_index = -2;    /* default on */
+	opts.checkout_worktree = -2; /* default on */
+
+	if (argc == 3 && !strcmp(argv[1], "-b")) {
+		/*
+		 * User ran 'git checkout -b <branch>' and expects
+		 * the same behavior as 'git switch -c <branch>'.
+		 */
+		opts.switch_branch_doing_nothing_is_ok = 0;
+		opts.only_merge_on_switching_branches = 1;
+	}
+
+	options = parse_options_dup(checkout_options);
+	options = add_common_options(&opts, options);
+	options = add_common_switch_branch_options(&opts, options);
+	options = add_checkout_path_options(&opts, options);
+
+	return checkout_main(argc, argv, prefix, &opts, options,
+			     checkout_usage);
+}
+
+int cmd_switch(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct checkout_opts opts = CHECKOUT_OPTS_INIT;
+	struct option *options = NULL;
+	struct option switch_options[] = {
+		OPT_STRING('c', "create", &opts.new_branch, N_("branch"),
+			   N_("create and switch to a new branch")),
+		OPT_STRING('C', "force-create", &opts.new_branch_force, N_("branch"),
+			   N_("create/reset and switch to a branch")),
+		OPT_BOOL(0, "guess", &opts.dwim_new_local_branch,
+			 N_("second guess 'git switch <no-such-branch>'")),
+		OPT_BOOL(0, "discard-changes", &opts.discard_changes,
+			 N_("throw away local modifications")),
+		OPT_END()
+	};
+
+	opts.dwim_new_local_branch = 1;
+	opts.accept_ref = 1;
+	opts.accept_pathspec = 0;
+	opts.switch_branch_doing_nothing_is_ok = 0;
+	opts.only_merge_on_switching_branches = 1;
+	opts.implicit_detach = 0;
+	opts.can_switch_when_in_progress = 0;
+	opts.orphan_from_empty_tree = 1;
+	opts.overlay_mode = -1;
+
+	options = parse_options_dup(switch_options);
+	options = add_common_options(&opts, options);
+	options = add_common_switch_branch_options(&opts, options);
+
+	cb_option = 'c';
+
+	return checkout_main(argc, argv, prefix, &opts, options,
+			     switch_branch_usage);
+}
+
+int cmd_restore(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
+{
+	struct checkout_opts opts = CHECKOUT_OPTS_INIT;
+	struct option *options;
+	struct option restore_options[] = {
+		OPT_STRING('s', "source", &opts.from_treeish, "<tree-ish>",
+			   N_("which tree-ish to checkout from")),
+		OPT_BOOL('S', "staged", &opts.checkout_index,
+			   N_("restore the index")),
+		OPT_BOOL('W', "worktree", &opts.checkout_worktree,
+			   N_("restore the working tree (default)")),
+		OPT_BOOL(0, "ignore-unmerged", &opts.ignore_unmerged,
+			 N_("ignore unmerged entries")),
+		OPT_BOOL(0, "overlay", &opts.overlay_mode, N_("use overlay mode")),
+		OPT_END()
+	};
+
+	opts.accept_ref = 0;
+	opts.accept_pathspec = 1;
+	opts.empty_pathspec_ok = 0;
+	opts.overlay_mode = 0;
+	opts.checkout_index = -1;    /* default off */
+	opts.checkout_worktree = -2; /* default on */
+	opts.ignore_unmerged_opt = "--ignore-unmerged";
+
+	options = parse_options_dup(restore_options);
+	options = add_common_options(&opts, options);
+	options = add_checkout_path_options(&opts, options);
+
+	return checkout_main(argc, argv, prefix, &opts, options,
+			     restore_usage);
+}
diff --git a/builtin/clean.c b/builtin/clean.c
new file mode 100644
index 0000000000..053c94fc6b
--- /dev/null
+++ b/builtin/clean.c
@@ -0,0 +1,1099 @@
+/*
+ * "git clean" builtin command
+ *
+ * Copyright (C) 2007 Shawn Bohrer
+ *
+ * Based on git-clean.sh by Pavel Roskin
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "dir.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "setup.h"
+#include "string-list.h"
+#include "quote.h"
+#include "column.h"
+#include "color.h"
+#include "pathspec.h"
+#include "help.h"
+#include "prompt.h"
+
+static int require_force = -1; /* unset */
+static int interactive;
+static struct string_list del_list = STRING_LIST_INIT_DUP;
+static unsigned int colopts;
+
+static const char *const builtin_clean_usage[] = {
+	N_("git clean [-d] [-f] [-i] [-n] [-q] [-e <pattern>] [-x | -X] [--] [<pathspec>...]"),
+	NULL
+};
+
+static const char *msg_remove = N_("Removing %s\n");
+static const char *msg_would_remove = N_("Would remove %s\n");
+static const char *msg_skip_git_dir = N_("Skipping repository %s\n");
+static const char *msg_would_skip_git_dir = N_("Would skip repository %s\n");
+static const char *msg_warn_remove_failed = N_("failed to remove %s");
+static const char *msg_warn_lstat_failed = N_("could not lstat %s\n");
+static const char *msg_skip_cwd = N_("Refusing to remove current working directory\n");
+static const char *msg_would_skip_cwd = N_("Would refuse to remove current working directory\n");
+
+enum color_clean {
+	CLEAN_COLOR_RESET = 0,
+	CLEAN_COLOR_PLAIN = 1,
+	CLEAN_COLOR_PROMPT = 2,
+	CLEAN_COLOR_HEADER = 3,
+	CLEAN_COLOR_HELP = 4,
+	CLEAN_COLOR_ERROR = 5
+};
+
+static const char *color_interactive_slots[] = {
+	[CLEAN_COLOR_ERROR]  = "error",
+	[CLEAN_COLOR_HEADER] = "header",
+	[CLEAN_COLOR_HELP]   = "help",
+	[CLEAN_COLOR_PLAIN]  = "plain",
+	[CLEAN_COLOR_PROMPT] = "prompt",
+	[CLEAN_COLOR_RESET]  = "reset",
+};
+
+static int clean_use_color = -1;
+static char clean_colors[][COLOR_MAXLEN] = {
+	[CLEAN_COLOR_ERROR] = GIT_COLOR_BOLD_RED,
+	[CLEAN_COLOR_HEADER] = GIT_COLOR_BOLD,
+	[CLEAN_COLOR_HELP] = GIT_COLOR_BOLD_RED,
+	[CLEAN_COLOR_PLAIN] = GIT_COLOR_NORMAL,
+	[CLEAN_COLOR_PROMPT] = GIT_COLOR_BOLD_BLUE,
+	[CLEAN_COLOR_RESET] = GIT_COLOR_RESET,
+};
+
+#define MENU_OPTS_SINGLETON		01
+#define MENU_OPTS_IMMEDIATE		02
+#define MENU_OPTS_LIST_ONLY		04
+
+struct menu_opts {
+	const char *header;
+	const char *prompt;
+	int flags;
+};
+
+#define MENU_RETURN_NO_LOOP		10
+
+struct menu_item {
+	char hotkey;
+	const char *title;
+	int selected;
+	int (*fn)(void);
+};
+
+enum menu_stuff_type {
+	MENU_STUFF_TYPE_STRING_LIST = 1,
+	MENU_STUFF_TYPE_MENU_ITEM
+};
+
+struct menu_stuff {
+	enum menu_stuff_type type;
+	int nr;
+	void *stuff;
+};
+
+define_list_config_array(color_interactive_slots);
+
+static int git_clean_config(const char *var, const char *value,
+			    const struct config_context *ctx, void *cb)
+{
+	const char *slot_name;
+
+	if (starts_with(var, "column."))
+		return git_column_config(var, value, "clean", &colopts);
+
+	/* honors the color.interactive* config variables which also
+	   applied in git-add--interactive and git-stash */
+	if (!strcmp(var, "color.interactive")) {
+		clean_use_color = git_config_colorbool(var, value);
+		return 0;
+	}
+	if (skip_prefix(var, "color.interactive.", &slot_name)) {
+		int slot = LOOKUP_CONFIG(color_interactive_slots, slot_name);
+		if (slot < 0)
+			return 0;
+		if (!value)
+			return config_error_nonbool(var);
+		return color_parse(value, clean_colors[slot]);
+	}
+
+	if (!strcmp(var, "clean.requireforce")) {
+		require_force = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (git_color_config(var, value, cb) < 0)
+		return -1;
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static const char *clean_get_color(enum color_clean ix)
+{
+	if (want_color(clean_use_color))
+		return clean_colors[ix];
+	return "";
+}
+
+static void clean_print_color(enum color_clean ix)
+{
+	printf("%s", clean_get_color(ix));
+}
+
+static int exclude_cb(const struct option *opt, const char *arg, int unset)
+{
+	struct string_list *exclude_list = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	string_list_append(exclude_list, arg);
+	return 0;
+}
+
+static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag,
+		int dry_run, int quiet, int *dir_gone)
+{
+	DIR *dir;
+	struct strbuf quoted = STRBUF_INIT;
+	struct strbuf realpath = STRBUF_INIT;
+	struct strbuf real_ocwd = STRBUF_INIT;
+	struct dirent *e;
+	int res = 0, ret = 0, gone = 1, original_len = path->len, len;
+	struct string_list dels = STRING_LIST_INIT_DUP;
+
+	*dir_gone = 1;
+
+	if ((force_flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
+	    is_nonbare_repository_dir(path)) {
+		if (!quiet) {
+			quote_path(path->buf, prefix, &quoted, 0);
+			printf(dry_run ?  _(msg_would_skip_git_dir) : _(msg_skip_git_dir),
+					quoted.buf);
+		}
+
+		*dir_gone = 0;
+		goto out;
+	}
+
+	dir = opendir(path->buf);
+	if (!dir) {
+		/* an empty dir could be removed even if it is unreadble */
+		res = dry_run ? 0 : rmdir(path->buf);
+		if (res) {
+			int saved_errno = errno;
+			quote_path(path->buf, prefix, &quoted, 0);
+			errno = saved_errno;
+			warning_errno(_(msg_warn_remove_failed), quoted.buf);
+			*dir_gone = 0;
+		}
+		ret = res;
+		goto out;
+	}
+
+	strbuf_complete(path, '/');
+
+	len = path->len;
+	while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL) {
+		struct stat st;
+
+		strbuf_setlen(path, len);
+		strbuf_addstr(path, e->d_name);
+		if (lstat(path->buf, &st))
+			warning_errno(_(msg_warn_lstat_failed), path->buf);
+		else if (S_ISDIR(st.st_mode)) {
+			if (remove_dirs(path, prefix, force_flag, dry_run, quiet, &gone))
+				ret = 1;
+			if (gone) {
+				quote_path(path->buf, prefix, &quoted, 0);
+				string_list_append(&dels, quoted.buf);
+			} else
+				*dir_gone = 0;
+			continue;
+		} else {
+			res = dry_run ? 0 : unlink(path->buf);
+			if (!res) {
+				quote_path(path->buf, prefix, &quoted, 0);
+				string_list_append(&dels, quoted.buf);
+			} else {
+				int saved_errno = errno;
+				quote_path(path->buf, prefix, &quoted, 0);
+				errno = saved_errno;
+				warning_errno(_(msg_warn_remove_failed), quoted.buf);
+				*dir_gone = 0;
+				ret = 1;
+			}
+			continue;
+		}
+
+		/* path too long, stat fails, or non-directory still exists */
+		*dir_gone = 0;
+		ret = 1;
+		break;
+	}
+	closedir(dir);
+
+	strbuf_setlen(path, original_len);
+
+	if (*dir_gone) {
+		/*
+		 * Normalize path components in path->buf, e.g. change '\' to
+		 * '/' on Windows.
+		 */
+		strbuf_realpath(&realpath, path->buf, 1);
+
+		/*
+		 * path and realpath are absolute; for comparison, we would
+		 * like to transform startup_info->original_cwd to an absolute
+		 * path too.
+		 */
+		 if (startup_info->original_cwd)
+			 strbuf_realpath(&real_ocwd,
+					 startup_info->original_cwd, 1);
+
+		if (!strbuf_cmp(&realpath, &real_ocwd)) {
+			printf("%s", dry_run ? _(msg_would_skip_cwd) : _(msg_skip_cwd));
+			*dir_gone = 0;
+		} else {
+			res = dry_run ? 0 : rmdir(path->buf);
+			if (!res)
+				*dir_gone = 1;
+			else {
+				int saved_errno = errno;
+				quote_path(path->buf, prefix, &quoted, 0);
+				errno = saved_errno;
+				warning_errno(_(msg_warn_remove_failed), quoted.buf);
+				*dir_gone = 0;
+				ret = 1;
+			}
+		}
+	}
+
+	if (!*dir_gone && !quiet) {
+		int i;
+		for (i = 0; i < dels.nr; i++)
+			printf(dry_run ?  _(msg_would_remove) : _(msg_remove), dels.items[i].string);
+	}
+out:
+	strbuf_release(&realpath);
+	strbuf_release(&real_ocwd);
+	strbuf_release(&quoted);
+	string_list_clear(&dels, 0);
+	return ret;
+}
+
+static void pretty_print_dels(void)
+{
+	struct string_list list = STRING_LIST_INIT_DUP;
+	struct string_list_item *item;
+	struct strbuf buf = STRBUF_INIT;
+	const char *qname;
+	struct column_options copts;
+
+	for_each_string_list_item(item, &del_list) {
+		qname = quote_path(item->string, NULL, &buf, 0);
+		string_list_append(&list, qname);
+	}
+
+	/*
+	 * always enable column display, we only consult column.*
+	 * about layout strategy and stuff
+	 */
+	colopts = (colopts & ~COL_ENABLE_MASK) | COL_ENABLED;
+	memset(&copts, 0, sizeof(copts));
+	copts.indent = "  ";
+	copts.padding = 2;
+	print_columns(&list, colopts, &copts);
+	strbuf_release(&buf);
+	string_list_clear(&list, 0);
+}
+
+static void pretty_print_menus(struct string_list *menu_list)
+{
+	unsigned int local_colopts = 0;
+	struct column_options copts;
+
+	local_colopts = COL_ENABLED | COL_ROW;
+	memset(&copts, 0, sizeof(copts));
+	copts.indent = "  ";
+	copts.padding = 2;
+	print_columns(menu_list, local_colopts, &copts);
+}
+
+static void prompt_help_cmd(int singleton)
+{
+	clean_print_color(CLEAN_COLOR_HELP);
+	printf(singleton ?
+		  _("Prompt help:\n"
+		    "1          - select a numbered item\n"
+		    "foo        - select item based on unique prefix\n"
+		    "           - (empty) select nothing\n") :
+		  _("Prompt help:\n"
+		    "1          - select a single item\n"
+		    "3-5        - select a range of items\n"
+		    "2-3,6-9    - select multiple ranges\n"
+		    "foo        - select item based on unique prefix\n"
+		    "-...       - unselect specified items\n"
+		    "*          - choose all items\n"
+		    "           - (empty) finish selecting\n"));
+	clean_print_color(CLEAN_COLOR_RESET);
+}
+
+/*
+ * display menu stuff with number prefix and hotkey highlight
+ */
+static void print_highlight_menu_stuff(struct menu_stuff *stuff, int **chosen)
+{
+	struct string_list menu_list = STRING_LIST_INIT_DUP;
+	struct strbuf menu = STRBUF_INIT;
+	struct menu_item *menu_item;
+	struct string_list_item *string_list_item;
+	int i;
+
+	switch (stuff->type) {
+	default:
+		die("Bad type of menu_stuff when print menu");
+	case MENU_STUFF_TYPE_MENU_ITEM:
+		menu_item = (struct menu_item *)stuff->stuff;
+		for (i = 0; i < stuff->nr; i++, menu_item++) {
+			const char *p;
+			int highlighted = 0;
+
+			p = menu_item->title;
+			if ((*chosen)[i] < 0)
+				(*chosen)[i] = menu_item->selected ? 1 : 0;
+			strbuf_addf(&menu, "%s%2d: ", (*chosen)[i] ? "*" : " ", i+1);
+			for (; *p; p++) {
+				if (!highlighted && *p == menu_item->hotkey) {
+					strbuf_addstr(&menu, clean_get_color(CLEAN_COLOR_PROMPT));
+					strbuf_addch(&menu, *p);
+					strbuf_addstr(&menu, clean_get_color(CLEAN_COLOR_RESET));
+					highlighted = 1;
+				} else {
+					strbuf_addch(&menu, *p);
+				}
+			}
+			string_list_append(&menu_list, menu.buf);
+			strbuf_reset(&menu);
+		}
+		break;
+	case MENU_STUFF_TYPE_STRING_LIST:
+		i = 0;
+		for_each_string_list_item(string_list_item, (struct string_list *)stuff->stuff) {
+			if ((*chosen)[i] < 0)
+				(*chosen)[i] = 0;
+			strbuf_addf(&menu, "%s%2d: %s",
+				    (*chosen)[i] ? "*" : " ", i+1, string_list_item->string);
+			string_list_append(&menu_list, menu.buf);
+			strbuf_reset(&menu);
+			i++;
+		}
+		break;
+	}
+
+	pretty_print_menus(&menu_list);
+
+	strbuf_release(&menu);
+	string_list_clear(&menu_list, 0);
+}
+
+static int find_unique(const char *choice, struct menu_stuff *menu_stuff)
+{
+	struct menu_item *menu_item;
+	struct string_list_item *string_list_item;
+	int i, len, found = 0;
+
+	len = strlen(choice);
+	switch (menu_stuff->type) {
+	default:
+		die("Bad type of menu_stuff when parse choice");
+	case MENU_STUFF_TYPE_MENU_ITEM:
+
+		menu_item = (struct menu_item *)menu_stuff->stuff;
+		for (i = 0; i < menu_stuff->nr; i++, menu_item++) {
+			if (len == 1 && *choice == menu_item->hotkey) {
+				found = i + 1;
+				break;
+			}
+			if (!strncasecmp(choice, menu_item->title, len)) {
+				if (found) {
+					if (len == 1) {
+						/* continue for hotkey matching */
+						found = -1;
+					} else {
+						found = 0;
+						break;
+					}
+				} else {
+					found = i + 1;
+				}
+			}
+		}
+		break;
+	case MENU_STUFF_TYPE_STRING_LIST:
+		string_list_item = ((struct string_list *)menu_stuff->stuff)->items;
+		for (i = 0; i < menu_stuff->nr; i++, string_list_item++) {
+			if (!strncasecmp(choice, string_list_item->string, len)) {
+				if (found) {
+					found = 0;
+					break;
+				}
+				found = i + 1;
+			}
+		}
+		break;
+	}
+	return found;
+}
+
+/*
+ * Parse user input, and return choice(s) for menu (menu_stuff).
+ *
+ * Input
+ *     (for single choice)
+ *         1          - select a numbered item
+ *         foo        - select item based on menu title
+ *                    - (empty) select nothing
+ *
+ *     (for multiple choice)
+ *         1          - select a single item
+ *         3-5        - select a range of items
+ *         2-3,6-9    - select multiple ranges
+ *         foo        - select item based on menu title
+ *         -...       - unselect specified items
+ *         *          - choose all items
+ *                    - (empty) finish selecting
+ *
+ * The parse result will be saved in array **chosen, and
+ * return number of total selections.
+ */
+static int parse_choice(struct menu_stuff *menu_stuff,
+			int is_single,
+			struct strbuf input,
+			int **chosen)
+{
+	struct strbuf **choice_list, **ptr;
+	int nr = 0;
+	int i;
+
+	if (is_single) {
+		choice_list = strbuf_split_max(&input, '\n', 0);
+	} else {
+		char *p = input.buf;
+		do {
+			if (*p == ',')
+				*p = ' ';
+		} while (*p++);
+		choice_list = strbuf_split_max(&input, ' ', 0);
+	}
+
+	for (ptr = choice_list; *ptr; ptr++) {
+		char *p;
+		int choose = 1;
+		int bottom = 0, top = 0;
+		int is_range, is_number;
+
+		strbuf_trim(*ptr);
+		if (!(*ptr)->len)
+			continue;
+
+		/* Input that begins with '-'; unchoose */
+		if (*(*ptr)->buf == '-') {
+			choose = 0;
+			strbuf_remove((*ptr), 0, 1);
+		}
+
+		is_range = 0;
+		is_number = 1;
+		for (p = (*ptr)->buf; *p; p++) {
+			if ('-' == *p) {
+				if (!is_range) {
+					is_range = 1;
+					is_number = 0;
+				} else {
+					is_number = 0;
+					is_range = 0;
+					break;
+				}
+			} else if (!isdigit(*p)) {
+				is_number = 0;
+				is_range = 0;
+				break;
+			}
+		}
+
+		if (is_number) {
+			bottom = atoi((*ptr)->buf);
+			top = bottom;
+		} else if (is_range) {
+			bottom = atoi((*ptr)->buf);
+			/* a range can be specified like 5-7 or 5- */
+			if (!*(strchr((*ptr)->buf, '-') + 1))
+				top = menu_stuff->nr;
+			else
+				top = atoi(strchr((*ptr)->buf, '-') + 1);
+		} else if (!strcmp((*ptr)->buf, "*")) {
+			bottom = 1;
+			top = menu_stuff->nr;
+		} else {
+			bottom = find_unique((*ptr)->buf, menu_stuff);
+			top = bottom;
+		}
+
+		if (top <= 0 || bottom <= 0 || top > menu_stuff->nr || bottom > top ||
+		    (is_single && bottom != top)) {
+			clean_print_color(CLEAN_COLOR_ERROR);
+			printf(_("Huh (%s)?\n"), (*ptr)->buf);
+			clean_print_color(CLEAN_COLOR_RESET);
+			continue;
+		}
+
+		for (i = bottom; i <= top; i++)
+			(*chosen)[i-1] = choose;
+	}
+
+	strbuf_list_free(choice_list);
+
+	for (i = 0; i < menu_stuff->nr; i++)
+		nr += (*chosen)[i];
+	return nr;
+}
+
+/*
+ * Implement a git-add-interactive compatible UI, which is borrowed
+ * from add-interactive.c.
+ *
+ * Return value:
+ *
+ *   - Return an array of integers
+ *   - , and it is up to you to free the allocated memory.
+ *   - The array ends with EOF.
+ *   - If user pressed CTRL-D (i.e. EOF), no selection returned.
+ */
+static int *list_and_choose(struct menu_opts *opts, struct menu_stuff *stuff)
+{
+	struct strbuf choice = STRBUF_INIT;
+	int *chosen, *result;
+	int nr = 0;
+	int eof = 0;
+	int i;
+
+	ALLOC_ARRAY(chosen, stuff->nr);
+	/* set chosen as uninitialized */
+	for (i = 0; i < stuff->nr; i++)
+		chosen[i] = -1;
+
+	for (;;) {
+		if (opts->header) {
+			printf_ln("%s%s%s",
+				  clean_get_color(CLEAN_COLOR_HEADER),
+				  _(opts->header),
+				  clean_get_color(CLEAN_COLOR_RESET));
+		}
+
+		/* chosen will be initialized by print_highlight_menu_stuff */
+		print_highlight_menu_stuff(stuff, &chosen);
+
+		if (opts->flags & MENU_OPTS_LIST_ONLY)
+			break;
+
+		if (opts->prompt) {
+			printf("%s%s%s%s",
+			       clean_get_color(CLEAN_COLOR_PROMPT),
+			       _(opts->prompt),
+			       opts->flags & MENU_OPTS_SINGLETON ? "> " : ">> ",
+			       clean_get_color(CLEAN_COLOR_RESET));
+		}
+
+		if (git_read_line_interactively(&choice) == EOF) {
+			eof = 1;
+			break;
+		}
+
+		/* help for prompt */
+		if (!strcmp(choice.buf, "?")) {
+			prompt_help_cmd(opts->flags & MENU_OPTS_SINGLETON);
+			continue;
+		}
+
+		/* for a multiple-choice menu, press ENTER (empty) will return back */
+		if (!(opts->flags & MENU_OPTS_SINGLETON) && !choice.len)
+			break;
+
+		nr = parse_choice(stuff,
+				  opts->flags & MENU_OPTS_SINGLETON,
+				  choice,
+				  &chosen);
+
+		if (opts->flags & MENU_OPTS_SINGLETON) {
+			if (nr)
+				break;
+		} else if (opts->flags & MENU_OPTS_IMMEDIATE) {
+			break;
+		}
+	}
+
+	if (eof) {
+		result = xmalloc(sizeof(int));
+		*result = EOF;
+	} else {
+		int j = 0;
+
+		/*
+		 * recalculate nr, if return back from menu directly with
+		 * default selections.
+		 */
+		if (!nr) {
+			for (i = 0; i < stuff->nr; i++)
+				nr += chosen[i];
+		}
+
+		CALLOC_ARRAY(result, st_add(nr, 1));
+		for (i = 0; i < stuff->nr && j < nr; i++) {
+			if (chosen[i])
+				result[j++] = i;
+		}
+		result[j] = EOF;
+	}
+
+	free(chosen);
+	strbuf_release(&choice);
+	return result;
+}
+
+static int clean_cmd(void)
+{
+	return MENU_RETURN_NO_LOOP;
+}
+
+static int filter_by_patterns_cmd(void)
+{
+	struct dir_struct dir = DIR_INIT;
+	struct strbuf confirm = STRBUF_INIT;
+	struct strbuf **ignore_list;
+	struct string_list_item *item;
+	struct pattern_list *pl;
+	int changed = -1, i;
+
+	for (;;) {
+		if (!del_list.nr)
+			break;
+
+		if (changed)
+			pretty_print_dels();
+
+		clean_print_color(CLEAN_COLOR_PROMPT);
+		printf(_("Input ignore patterns>> "));
+		clean_print_color(CLEAN_COLOR_RESET);
+		if (git_read_line_interactively(&confirm) == EOF)
+			putchar('\n');
+
+		/* quit filter_by_pattern mode if press ENTER or Ctrl-D */
+		if (!confirm.len)
+			break;
+
+		pl = add_pattern_list(&dir, EXC_CMDL, "manual exclude");
+		ignore_list = strbuf_split_max(&confirm, ' ', 0);
+
+		for (i = 0; ignore_list[i]; i++) {
+			strbuf_trim(ignore_list[i]);
+			if (!ignore_list[i]->len)
+				continue;
+
+			add_pattern(ignore_list[i]->buf, "", 0, pl, -(i+1));
+		}
+
+		changed = 0;
+		for_each_string_list_item(item, &del_list) {
+			int dtype = DT_UNKNOWN;
+
+			if (is_excluded(&dir, the_repository->index, item->string, &dtype)) {
+				*item->string = '\0';
+				changed++;
+			}
+		}
+
+		if (changed) {
+			string_list_remove_empty_items(&del_list, 0);
+		} else {
+			clean_print_color(CLEAN_COLOR_ERROR);
+			printf_ln(_("WARNING: Cannot find items matched by: %s"), confirm.buf);
+			clean_print_color(CLEAN_COLOR_RESET);
+		}
+
+		strbuf_list_free(ignore_list);
+		dir_clear(&dir);
+	}
+
+	strbuf_release(&confirm);
+	return 0;
+}
+
+static int select_by_numbers_cmd(void)
+{
+	struct menu_opts menu_opts;
+	struct menu_stuff menu_stuff;
+	struct string_list_item *items;
+	int *chosen;
+	int i, j;
+
+	menu_opts.header = NULL;
+	menu_opts.prompt = N_("Select items to delete");
+	menu_opts.flags = 0;
+
+	menu_stuff.type = MENU_STUFF_TYPE_STRING_LIST;
+	menu_stuff.stuff = &del_list;
+	menu_stuff.nr = del_list.nr;
+
+	chosen = list_and_choose(&menu_opts, &menu_stuff);
+	items = del_list.items;
+	for (i = 0, j = 0; i < del_list.nr; i++) {
+		if (i < chosen[j]) {
+			*(items[i].string) = '\0';
+		} else if (i == chosen[j]) {
+			/* delete selected item */
+			j++;
+			continue;
+		} else {
+			/* end of chosen (chosen[j] == EOF), won't delete */
+			*(items[i].string) = '\0';
+		}
+	}
+
+	string_list_remove_empty_items(&del_list, 0);
+
+	free(chosen);
+	return 0;
+}
+
+static int ask_each_cmd(void)
+{
+	struct strbuf confirm = STRBUF_INIT;
+	struct strbuf buf = STRBUF_INIT;
+	struct string_list_item *item;
+	const char *qname;
+	int changed = 0, eof = 0;
+
+	for_each_string_list_item(item, &del_list) {
+		/* Ctrl-D should stop removing files */
+		if (!eof) {
+			qname = quote_path(item->string, NULL, &buf, 0);
+			/* TRANSLATORS: Make sure to keep [y/N] as is */
+			printf(_("Remove %s [y/N]? "), qname);
+			if (git_read_line_interactively(&confirm) == EOF) {
+				putchar('\n');
+				eof = 1;
+			}
+		}
+		if (!confirm.len || strncasecmp(confirm.buf, "yes", confirm.len)) {
+			*item->string = '\0';
+			changed++;
+		}
+	}
+
+	if (changed)
+		string_list_remove_empty_items(&del_list, 0);
+
+	strbuf_release(&buf);
+	strbuf_release(&confirm);
+	return MENU_RETURN_NO_LOOP;
+}
+
+static int quit_cmd(void)
+{
+	string_list_clear(&del_list, 0);
+	printf(_("Bye.\n"));
+	return MENU_RETURN_NO_LOOP;
+}
+
+static int help_cmd(void)
+{
+	clean_print_color(CLEAN_COLOR_HELP);
+	printf_ln(_(
+		    "clean               - start cleaning\n"
+		    "filter by pattern   - exclude items from deletion\n"
+		    "select by numbers   - select items to be deleted by numbers\n"
+		    "ask each            - confirm each deletion (like \"rm -i\")\n"
+		    "quit                - stop cleaning\n"
+		    "help                - this screen\n"
+		    "?                   - help for prompt selection"
+		   ));
+	clean_print_color(CLEAN_COLOR_RESET);
+	return 0;
+}
+
+static void interactive_main_loop(void)
+{
+	while (del_list.nr) {
+		struct menu_opts menu_opts;
+		struct menu_stuff menu_stuff;
+		struct menu_item menus[] = {
+			{'c', "clean",			0, clean_cmd},
+			{'f', "filter by pattern",	0, filter_by_patterns_cmd},
+			{'s', "select by numbers",	0, select_by_numbers_cmd},
+			{'a', "ask each",		0, ask_each_cmd},
+			{'q', "quit",			0, quit_cmd},
+			{'h', "help",			0, help_cmd},
+		};
+		int *chosen;
+
+		menu_opts.header = N_("*** Commands ***");
+		menu_opts.prompt = N_("What now");
+		menu_opts.flags = MENU_OPTS_SINGLETON;
+
+		menu_stuff.type = MENU_STUFF_TYPE_MENU_ITEM;
+		menu_stuff.stuff = menus;
+		menu_stuff.nr = sizeof(menus) / sizeof(struct menu_item);
+
+		clean_print_color(CLEAN_COLOR_HEADER);
+		printf_ln(Q_("Would remove the following item:",
+			     "Would remove the following items:",
+			     del_list.nr));
+		clean_print_color(CLEAN_COLOR_RESET);
+
+		pretty_print_dels();
+
+		chosen = list_and_choose(&menu_opts, &menu_stuff);
+
+		if (*chosen != EOF) {
+			int ret;
+			ret = menus[*chosen].fn();
+			if (ret != MENU_RETURN_NO_LOOP) {
+				FREE_AND_NULL(chosen);
+				if (!del_list.nr) {
+					clean_print_color(CLEAN_COLOR_ERROR);
+					printf_ln(_("No more files to clean, exiting."));
+					clean_print_color(CLEAN_COLOR_RESET);
+					break;
+				}
+				continue;
+			}
+		} else {
+			quit_cmd();
+		}
+
+		FREE_AND_NULL(chosen);
+		break;
+	}
+}
+
+static void correct_untracked_entries(struct dir_struct *dir)
+{
+	int src, dst, ign;
+
+	for (src = dst = ign = 0; src < dir->nr; src++) {
+		/* skip paths in ignored[] that cannot be inside entries[src] */
+		while (ign < dir->ignored_nr &&
+		       0 <= cmp_dir_entry(&dir->entries[src], &dir->ignored[ign]))
+			ign++;
+
+		if (ign < dir->ignored_nr &&
+		    check_dir_entry_contains(dir->entries[src], dir->ignored[ign])) {
+			/* entries[src] contains an ignored path, so we drop it */
+			free(dir->entries[src]);
+		} else {
+			struct dir_entry *ent = dir->entries[src++];
+
+			/* entries[src] does not contain an ignored path, so we keep it */
+			dir->entries[dst++] = ent;
+
+			/* then discard paths in entries[] contained inside entries[src] */
+			while (src < dir->nr &&
+			       check_dir_entry_contains(ent, dir->entries[src]))
+				free(dir->entries[src++]);
+
+			/* compensate for the outer loop's loop control */
+			src--;
+		}
+	}
+	dir->nr = dst;
+}
+
+int cmd_clean(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	int i, res;
+	int dry_run = 0, remove_directories = 0, quiet = 0, ignored = 0;
+	int ignored_only = 0, force = 0, errors = 0, gone = 1;
+	int rm_flags = REMOVE_DIR_KEEP_NESTED_GIT;
+	struct strbuf abs_path = STRBUF_INIT;
+	struct dir_struct dir = DIR_INIT;
+	struct pathspec pathspec;
+	struct strbuf buf = STRBUF_INIT;
+	struct string_list exclude_list = STRING_LIST_INIT_NODUP;
+	struct pattern_list *pl;
+	struct string_list_item *item;
+	const char *qname;
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("do not print names of files removed")),
+		OPT__DRY_RUN(&dry_run, N_("dry run")),
+		OPT__FORCE(&force, N_("force"), PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL('i', "interactive", &interactive, N_("interactive cleaning")),
+		OPT_BOOL('d', NULL, &remove_directories,
+				N_("remove whole directories")),
+		OPT_CALLBACK_F('e', "exclude", &exclude_list, N_("pattern"),
+		  N_("add <pattern> to ignore rules"), PARSE_OPT_NONEG, exclude_cb),
+		OPT_BOOL('x', NULL, &ignored, N_("remove ignored files, too")),
+		OPT_BOOL('X', NULL, &ignored_only,
+				N_("remove only ignored files")),
+		OPT_END()
+	};
+
+	git_config(git_clean_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, options, builtin_clean_usage,
+			     0);
+
+	if (require_force != 0 && !force && !interactive && !dry_run)
+		die(_("clean.requireForce is true and -f not given: refusing to clean"));
+
+	if (force > 1)
+		rm_flags = 0;
+	else
+		dir.flags |= DIR_SKIP_NESTED_GIT;
+
+	dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
+
+	if (ignored && ignored_only)
+		die(_("options '%s' and '%s' cannot be used together"), "-x", "-X");
+	if (!ignored)
+		setup_standard_excludes(&dir);
+	if (ignored_only)
+		dir.flags |= DIR_SHOW_IGNORED;
+
+	if (argc) {
+		/*
+		 * Remaining args implies pathspecs specified, and we should
+		 * recurse within those.
+		 */
+		remove_directories = 1;
+	}
+
+	if (remove_directories && !ignored_only) {
+		/*
+		 * We need to know about ignored files too:
+		 *
+		 * If (ignored), then we will delete ignored files as well.
+		 *
+		 * If (!ignored), then even though we not are doing
+		 * anything with ignored files, we need to know about them
+		 * so that we can avoid deleting a directory of untracked
+		 * files that also contains an ignored file within it.
+		 *
+		 * For the (!ignored) case, since we only need to avoid
+		 * deleting ignored files, we can set
+		 * DIR_SHOW_IGNORED_TOO_MODE_MATCHING in order to avoid
+		 * recursing into a directory which is itself ignored.
+		 */
+		dir.flags |= DIR_SHOW_IGNORED_TOO;
+		if (!ignored)
+			dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
+
+		/*
+		 * Let the fill_directory() machinery know that we aren't
+		 * just recursing to collect the ignored files; we want all
+		 * the untracked ones so that we can delete them.  (Note:
+		 * we could also set DIR_KEEP_UNTRACKED_CONTENTS when
+		 * ignored_only is true, since DIR_KEEP_UNTRACKED_CONTENTS
+		 * only has effect in combination with DIR_SHOW_IGNORED_TOO.  It makes
+		 * the code clearer to exclude it, though.
+		 */
+		dir.flags |= DIR_KEEP_UNTRACKED_CONTENTS;
+	}
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	if (repo_read_index(the_repository) < 0)
+		die(_("index file corrupt"));
+
+	pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
+	for (i = 0; i < exclude_list.nr; i++)
+		add_pattern(exclude_list.items[i].string, "", 0, pl, -(i+1));
+
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_CWD,
+		       prefix, argv);
+
+	fill_directory(&dir, the_repository->index, &pathspec);
+	correct_untracked_entries(&dir);
+
+	for (i = 0; i < dir.nr; i++) {
+		struct dir_entry *ent = dir.entries[i];
+		struct stat st;
+		const char *rel;
+
+		if (!index_name_is_other(the_repository->index, ent->name, ent->len))
+			continue;
+
+		if (lstat(ent->name, &st))
+			die_errno("Cannot lstat '%s'", ent->name);
+
+		if (S_ISDIR(st.st_mode) && !remove_directories)
+			continue;
+
+		rel = relative_path(ent->name, prefix, &buf);
+		string_list_append(&del_list, rel);
+	}
+
+	dir_clear(&dir);
+
+	if (interactive && del_list.nr > 0)
+		interactive_main_loop();
+
+	for_each_string_list_item(item, &del_list) {
+		struct stat st;
+
+		strbuf_reset(&abs_path);
+		if (prefix)
+			strbuf_addstr(&abs_path, prefix);
+
+		strbuf_addstr(&abs_path, item->string);
+
+		/*
+		 * we might have removed this as part of earlier
+		 * recursive directory removal, so lstat() here could
+		 * fail with ENOENT.
+		 */
+		if (lstat(abs_path.buf, &st))
+			continue;
+
+		if (S_ISDIR(st.st_mode)) {
+			if (remove_dirs(&abs_path, prefix, rm_flags, dry_run, quiet, &gone))
+				errors++;
+			if (gone && !quiet) {
+				qname = quote_path(item->string, NULL, &buf, 0);
+				printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
+			}
+		} else {
+			res = dry_run ? 0 : unlink(abs_path.buf);
+			if (res) {
+				int saved_errno = errno;
+				qname = quote_path(item->string, NULL, &buf, 0);
+				errno = saved_errno;
+				warning_errno(_(msg_warn_remove_failed), qname);
+				errors++;
+			} else if (!quiet) {
+				qname = quote_path(item->string, NULL, &buf, 0);
+				printf(dry_run ? _(msg_would_remove) : _(msg_remove), qname);
+			}
+		}
+	}
+
+	strbuf_release(&abs_path);
+	strbuf_release(&buf);
+	string_list_clear(&del_list, 0);
+	string_list_clear(&exclude_list, 0);
+	clear_pathspec(&pathspec);
+	return (errors != 0);
+}
diff --git a/builtin/clone.c b/builtin/clone.c
new file mode 100644
index 0000000000..fd001d800c
--- /dev/null
+++ b/builtin/clone.c
@@ -0,0 +1,1596 @@
+/*
+ * Builtin "git clone"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@xxxxxxxxxx>,
+ *		 2008 Daniel Barkalow <barkalow@xxxxxxxxxxxx>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ *
+ * Clone a repository into a different directory that does not yet exist.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+
+#include "abspath.h"
+#include "advice.h"
+#include "config.h"
+#include "copy.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "refspec.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "unpack-trees.h"
+#include "transport.h"
+#include "strbuf.h"
+#include "dir.h"
+#include "dir-iterator.h"
+#include "iterator.h"
+#include "sigchain.h"
+#include "branch.h"
+#include "remote.h"
+#include "run-command.h"
+#include "setup.h"
+#include "connected.h"
+#include "packfile.h"
+#include "path.h"
+#include "pkt-line.h"
+#include "list-objects-filter-options.h"
+#include "hook.h"
+#include "bundle.h"
+#include "bundle-uri.h"
+
+/*
+ * Overall FIXMEs:
+ *  - respect DB_ENVIRONMENT for .git/objects.
+ *
+ * Implementation notes:
+ *  - dropping use-separate-remote and no-separate-remote compatibility
+ *
+ */
+static const char * const builtin_clone_usage[] = {
+	N_("git clone [<options>] [--] <repo> [<dir>]"),
+	NULL
+};
+
+static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
+static int option_local = -1, option_no_hardlinks, option_shared;
+static int option_no_tags;
+static int option_shallow_submodules;
+static int option_reject_shallow = -1;    /* unspecified */
+static int config_reject_shallow = -1;    /* unspecified */
+static int deepen;
+static char *option_template, *option_depth, *option_since;
+static char *option_origin = NULL;
+static char *remote_name = NULL;
+static char *option_branch = NULL;
+static struct string_list option_not = STRING_LIST_INIT_NODUP;
+static const char *real_git_dir;
+static const char *ref_format;
+static const char *option_upload_pack = "git-upload-pack";
+static int option_verbosity;
+static int option_progress = -1;
+static int option_sparse_checkout;
+static enum transport_family family;
+static struct string_list option_config = STRING_LIST_INIT_NODUP;
+static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
+static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
+static int option_dissociate;
+static int max_jobs = -1;
+static struct string_list option_recurse_submodules = STRING_LIST_INIT_NODUP;
+static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
+static int option_filter_submodules = -1;    /* unspecified */
+static int config_filter_submodules = -1;    /* unspecified */
+static struct string_list server_options = STRING_LIST_INIT_NODUP;
+static int option_remote_submodules;
+static const char *bundle_uri;
+
+static int recurse_submodules_cb(const struct option *opt,
+				 const char *arg, int unset)
+{
+	if (unset)
+		string_list_clear((struct string_list *)opt->value, 0);
+	else if (arg)
+		string_list_append((struct string_list *)opt->value, arg);
+	else
+		string_list_append((struct string_list *)opt->value,
+				   (const char *)opt->defval);
+
+	return 0;
+}
+
+static struct option builtin_clone_options[] = {
+	OPT__VERBOSITY(&option_verbosity),
+	OPT_BOOL(0, "progress", &option_progress,
+		 N_("force progress reporting")),
+	OPT_BOOL(0, "reject-shallow", &option_reject_shallow,
+		 N_("don't clone shallow repository")),
+	OPT_BOOL('n', "no-checkout", &option_no_checkout,
+		 N_("don't create a checkout")),
+	OPT_BOOL(0, "bare", &option_bare, N_("create a bare repository")),
+	OPT_HIDDEN_BOOL(0, "naked", &option_bare,
+			N_("create a bare repository")),
+	OPT_BOOL(0, "mirror", &option_mirror,
+		 N_("create a mirror repository (implies --bare)")),
+	OPT_BOOL('l', "local", &option_local,
+		N_("to clone from a local repository")),
+	OPT_BOOL(0, "no-hardlinks", &option_no_hardlinks,
+		    N_("don't use local hardlinks, always copy")),
+	OPT_BOOL('s', "shared", &option_shared,
+		    N_("setup as shared repository")),
+	{ OPTION_CALLBACK, 0, "recurse-submodules", &option_recurse_submodules,
+	  N_("pathspec"), N_("initialize submodules in the clone"),
+	  PARSE_OPT_OPTARG, recurse_submodules_cb, (intptr_t)"." },
+	OPT_ALIAS(0, "recursive", "recurse-submodules"),
+	OPT_INTEGER('j', "jobs", &max_jobs,
+		    N_("number of submodules cloned in parallel")),
+	OPT_STRING(0, "template", &option_template, N_("template-directory"),
+		   N_("directory from which templates will be used")),
+	OPT_STRING_LIST(0, "reference", &option_required_reference, N_("repo"),
+			N_("reference repository")),
+	OPT_STRING_LIST(0, "reference-if-able", &option_optional_reference,
+			N_("repo"), N_("reference repository")),
+	OPT_BOOL(0, "dissociate", &option_dissociate,
+		 N_("use --reference only while cloning")),
+	OPT_STRING('o', "origin", &option_origin, N_("name"),
+		   N_("use <name> instead of 'origin' to track upstream")),
+	OPT_STRING('b', "branch", &option_branch, N_("branch"),
+		   N_("checkout <branch> instead of the remote's HEAD")),
+	OPT_STRING('u', "upload-pack", &option_upload_pack, N_("path"),
+		   N_("path to git-upload-pack on the remote")),
+	OPT_STRING(0, "depth", &option_depth, N_("depth"),
+		    N_("create a shallow clone of that depth")),
+	OPT_STRING(0, "shallow-since", &option_since, N_("time"),
+		    N_("create a shallow clone since a specific time")),
+	OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("ref"),
+			N_("deepen history of shallow clone, excluding ref")),
+	OPT_BOOL(0, "single-branch", &option_single_branch,
+		    N_("clone only one branch, HEAD or --branch")),
+	OPT_BOOL(0, "no-tags", &option_no_tags,
+		 N_("don't clone any tags, and make later fetches not to follow them")),
+	OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
+		    N_("any cloned submodules will be shallow")),
+	OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+		   N_("separate git dir from working tree")),
+	OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+		   N_("specify the reference format to use")),
+	OPT_STRING_LIST('c', "config", &option_config, N_("key=value"),
+			N_("set config inside the new repository")),
+	OPT_STRING_LIST(0, "server-option", &server_options,
+			N_("server-specific"), N_("option to transmit")),
+	OPT_IPVERSION(&family),
+	OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+	OPT_BOOL(0, "also-filter-submodules", &option_filter_submodules,
+		    N_("apply partial clone filters to submodules")),
+	OPT_BOOL(0, "remote-submodules", &option_remote_submodules,
+		    N_("any cloned submodules will use their remote-tracking branch")),
+	OPT_BOOL(0, "sparse", &option_sparse_checkout,
+		    N_("initialize sparse-checkout file to include only files at root")),
+	OPT_STRING(0, "bundle-uri", &bundle_uri,
+		   N_("uri"), N_("a URI for downloading bundles before fetching from origin remote")),
+	OPT_END()
+};
+
+static const char *get_repo_path_1(struct strbuf *path, int *is_bundle)
+{
+	static const char *suffix[] = { "/.git", "", ".git/.git", ".git" };
+	static const char *bundle_suffix[] = { ".bundle", "" };
+	size_t baselen = path->len;
+	struct stat st;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(suffix); i++) {
+		strbuf_setlen(path, baselen);
+		strbuf_addstr(path, suffix[i]);
+		if (stat(path->buf, &st))
+			continue;
+		if (S_ISDIR(st.st_mode) && is_git_directory(path->buf)) {
+			*is_bundle = 0;
+			return path->buf;
+		} else if (S_ISREG(st.st_mode) && st.st_size > 8) {
+			/* Is it a "gitfile"? */
+			char signature[8];
+			const char *dst;
+			int len, fd = open(path->buf, O_RDONLY);
+			if (fd < 0)
+				continue;
+			len = read_in_full(fd, signature, 8);
+			close(fd);
+			if (len != 8 || strncmp(signature, "gitdir: ", 8))
+				continue;
+			dst = read_gitfile(path->buf);
+			if (dst) {
+				*is_bundle = 0;
+				return dst;
+			}
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(bundle_suffix); i++) {
+		strbuf_setlen(path, baselen);
+		strbuf_addstr(path, bundle_suffix[i]);
+		if (!stat(path->buf, &st) && S_ISREG(st.st_mode)) {
+			*is_bundle = 1;
+			return path->buf;
+		}
+	}
+
+	return NULL;
+}
+
+static char *get_repo_path(const char *repo, int *is_bundle)
+{
+	struct strbuf path = STRBUF_INIT;
+	const char *raw;
+	char *canon;
+
+	strbuf_addstr(&path, repo);
+	raw = get_repo_path_1(&path, is_bundle);
+	canon = raw ? absolute_pathdup(raw) : NULL;
+	strbuf_release(&path);
+	return canon;
+}
+
+static int add_one_reference(struct string_list_item *item, void *cb_data)
+{
+	struct strbuf err = STRBUF_INIT;
+	int *required = cb_data;
+	char *ref_git = compute_alternate_path(item->string, &err);
+
+	if (!ref_git) {
+		if (*required)
+			die("%s", err.buf);
+		else
+			fprintf(stderr,
+				_("info: Could not add alternate for '%s': %s\n"),
+				item->string, err.buf);
+	} else {
+		struct strbuf sb = STRBUF_INIT;
+		strbuf_addf(&sb, "%s/objects", ref_git);
+		add_to_alternates_file(sb.buf);
+		strbuf_release(&sb);
+	}
+
+	strbuf_release(&err);
+	free(ref_git);
+	return 0;
+}
+
+static void setup_reference(void)
+{
+	int required = 1;
+	for_each_string_list(&option_required_reference,
+			     add_one_reference, &required);
+	required = 0;
+	for_each_string_list(&option_optional_reference,
+			     add_one_reference, &required);
+}
+
+static void copy_alternates(struct strbuf *src, const char *src_repo)
+{
+	/*
+	 * Read from the source objects/info/alternates file
+	 * and copy the entries to corresponding file in the
+	 * destination repository with add_to_alternates_file().
+	 * Both src and dst have "$path/objects/info/alternates".
+	 *
+	 * Instead of copying bit-for-bit from the original,
+	 * we need to append to existing one so that the already
+	 * created entry via "clone -s" is not lost, and also
+	 * to turn entries with paths relative to the original
+	 * absolute, so that they can be used in the new repository.
+	 */
+	FILE *in = xfopen(src->buf, "r");
+	struct strbuf line = STRBUF_INIT;
+
+	while (strbuf_getline(&line, in) != EOF) {
+		char *abs_path;
+		if (!line.len || line.buf[0] == '#')
+			continue;
+		if (is_absolute_path(line.buf)) {
+			add_to_alternates_file(line.buf);
+			continue;
+		}
+		abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
+		if (!normalize_path_copy(abs_path, abs_path))
+			add_to_alternates_file(abs_path);
+		else
+			warning("skipping invalid relative alternate: %s/%s",
+				src_repo, line.buf);
+		free(abs_path);
+	}
+	strbuf_release(&line);
+	fclose(in);
+}
+
+static void mkdir_if_missing(const char *pathname, mode_t mode)
+{
+	struct stat st;
+
+	if (!mkdir(pathname, mode))
+		return;
+
+	if (errno != EEXIST)
+		die_errno(_("failed to create directory '%s'"), pathname);
+	else if (stat(pathname, &st))
+		die_errno(_("failed to stat '%s'"), pathname);
+	else if (!S_ISDIR(st.st_mode))
+		die(_("%s exists and is not a directory"), pathname);
+}
+
+static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
+				   const char *src_repo)
+{
+	int src_len, dest_len;
+	struct dir_iterator *iter;
+	int iter_status;
+
+	/*
+	 * Refuse copying directories by default which aren't owned by us. The
+	 * code that performs either the copying or hardlinking is not prepared
+	 * to handle various edge cases where an adversary may for example
+	 * racily swap out files for symlinks. This can cause us to
+	 * inadvertently use the wrong source file.
+	 *
+	 * Furthermore, even if we were prepared to handle such races safely,
+	 * creating hardlinks across user boundaries is an inherently unsafe
+	 * operation as the hardlinked files can be rewritten at will by the
+	 * potentially-untrusted user. We thus refuse to do so by default.
+	 */
+	die_upon_dubious_ownership(NULL, NULL, src_repo);
+
+	mkdir_if_missing(dest->buf, 0777);
+
+	iter = dir_iterator_begin(src->buf, DIR_ITERATOR_PEDANTIC);
+
+	if (!iter) {
+		if (errno == ENOTDIR) {
+			int saved_errno = errno;
+			struct stat st;
+
+			if (!lstat(src->buf, &st) && S_ISLNK(st.st_mode))
+				die(_("'%s' is a symlink, refusing to clone with --local"),
+				    src->buf);
+			errno = saved_errno;
+		}
+		die_errno(_("failed to start iterator over '%s'"), src->buf);
+	}
+
+	strbuf_addch(src, '/');
+	src_len = src->len;
+	strbuf_addch(dest, '/');
+	dest_len = dest->len;
+
+	while ((iter_status = dir_iterator_advance(iter)) == ITER_OK) {
+		strbuf_setlen(src, src_len);
+		strbuf_addstr(src, iter->relative_path);
+		strbuf_setlen(dest, dest_len);
+		strbuf_addstr(dest, iter->relative_path);
+
+		if (S_ISLNK(iter->st.st_mode))
+			die(_("symlink '%s' exists, refusing to clone with --local"),
+			    iter->relative_path);
+
+		if (S_ISDIR(iter->st.st_mode)) {
+			mkdir_if_missing(dest->buf, 0777);
+			continue;
+		}
+
+		/* Files that cannot be copied bit-for-bit... */
+		if (!fspathcmp(iter->relative_path, "info/alternates")) {
+			copy_alternates(src, src_repo);
+			continue;
+		}
+
+		if (unlink(dest->buf) && errno != ENOENT)
+			die_errno(_("failed to unlink '%s'"), dest->buf);
+		if (!option_no_hardlinks) {
+			if (!link(src->buf, dest->buf)) {
+				struct stat st;
+
+				/*
+				 * Sanity-check whether the created hardlink
+				 * actually links to the expected file now. This
+				 * catches time-of-check-time-of-use bugs in
+				 * case the source file was meanwhile swapped.
+				 */
+				if (lstat(dest->buf, &st))
+					die(_("hardlink cannot be checked at '%s'"), dest->buf);
+				if (st.st_mode != iter->st.st_mode ||
+				    st.st_ino != iter->st.st_ino ||
+				    st.st_dev != iter->st.st_dev ||
+				    st.st_size != iter->st.st_size ||
+				    st.st_uid != iter->st.st_uid ||
+				    st.st_gid != iter->st.st_gid)
+					die(_("hardlink different from source at '%s'"), dest->buf);
+
+				continue;
+			}
+			if (option_local > 0)
+				die_errno(_("failed to create link '%s'"), dest->buf);
+			option_no_hardlinks = 1;
+		}
+		if (copy_file_with_time(dest->buf, src->buf, 0666))
+			die_errno(_("failed to copy file to '%s'"), dest->buf);
+	}
+
+	if (iter_status != ITER_DONE) {
+		strbuf_setlen(src, src_len);
+		die(_("failed to iterate over '%s'"), src->buf);
+	}
+}
+
+static void clone_local(const char *src_repo, const char *dest_repo)
+{
+	if (option_shared) {
+		struct strbuf alt = STRBUF_INIT;
+		get_common_dir(&alt, src_repo);
+		strbuf_addstr(&alt, "/objects");
+		add_to_alternates_file(alt.buf);
+		strbuf_release(&alt);
+	} else {
+		struct strbuf src = STRBUF_INIT;
+		struct strbuf dest = STRBUF_INIT;
+		get_common_dir(&src, src_repo);
+		get_common_dir(&dest, dest_repo);
+		strbuf_addstr(&src, "/objects");
+		strbuf_addstr(&dest, "/objects");
+		copy_or_link_directory(&src, &dest, src_repo);
+		strbuf_release(&src);
+		strbuf_release(&dest);
+	}
+
+	if (0 <= option_verbosity)
+		fprintf(stderr, _("done.\n"));
+}
+
+static const char *junk_work_tree;
+static int junk_work_tree_flags;
+static const char *junk_git_dir;
+static int junk_git_dir_flags;
+static enum {
+	JUNK_LEAVE_NONE,
+	JUNK_LEAVE_REPO,
+	JUNK_LEAVE_ALL
+} junk_mode = JUNK_LEAVE_NONE;
+
+static const char junk_leave_repo_msg[] =
+N_("Clone succeeded, but checkout failed.\n"
+   "You can inspect what was checked out with 'git status'\n"
+   "and retry with 'git restore --source=HEAD :/'\n");
+
+static void remove_junk(void)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	switch (junk_mode) {
+	case JUNK_LEAVE_REPO:
+		warning("%s", _(junk_leave_repo_msg));
+		/* fall-through */
+	case JUNK_LEAVE_ALL:
+		return;
+	default:
+		/* proceed to removal */
+		break;
+	}
+
+	if (junk_git_dir) {
+		strbuf_addstr(&sb, junk_git_dir);
+		remove_dir_recursively(&sb, junk_git_dir_flags);
+		strbuf_reset(&sb);
+	}
+	if (junk_work_tree) {
+		strbuf_addstr(&sb, junk_work_tree);
+		remove_dir_recursively(&sb, junk_work_tree_flags);
+	}
+	strbuf_release(&sb);
+}
+
+static void remove_junk_on_signal(int signo)
+{
+	remove_junk();
+	sigchain_pop(signo);
+	raise(signo);
+}
+
+static struct ref *find_remote_branch(const struct ref *refs, const char *branch)
+{
+	struct ref *ref;
+	struct strbuf head = STRBUF_INIT;
+	strbuf_addstr(&head, "refs/heads/");
+	strbuf_addstr(&head, branch);
+	ref = find_ref_by_name(refs, head.buf);
+	strbuf_release(&head);
+
+	if (ref)
+		return ref;
+
+	strbuf_addstr(&head, "refs/tags/");
+	strbuf_addstr(&head, branch);
+	ref = find_ref_by_name(refs, head.buf);
+	strbuf_release(&head);
+
+	return ref;
+}
+
+static struct ref *wanted_peer_refs(const struct ref *refs,
+		struct refspec *refspec)
+{
+	struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
+	struct ref *local_refs = head;
+	struct ref **tail = head ? &head->next : &local_refs;
+	struct refspec_item tag_refspec;
+
+	refspec_item_init(&tag_refspec, TAG_REFSPEC, 0);
+
+	if (option_single_branch) {
+		struct ref *remote_head = NULL;
+
+		if (!option_branch)
+			remote_head = guess_remote_head(head, refs, 0);
+		else {
+			free_one_ref(head);
+			local_refs = head = NULL;
+			tail = &local_refs;
+			remote_head = copy_ref(find_remote_branch(refs, option_branch));
+		}
+
+		if (!remote_head && option_branch)
+			warning(_("Could not find remote branch %s to clone."),
+				option_branch);
+		else {
+			int i;
+			for (i = 0; i < refspec->nr; i++)
+				get_fetch_map(remote_head, &refspec->items[i],
+					      &tail, 0);
+
+			/* if --branch=tag, pull the requested tag explicitly */
+			get_fetch_map(remote_head, &tag_refspec, &tail, 0);
+		}
+		free_refs(remote_head);
+	} else {
+		int i;
+		for (i = 0; i < refspec->nr; i++)
+			get_fetch_map(refs, &refspec->items[i], &tail, 0);
+	}
+
+	if (!option_mirror && !option_single_branch && !option_no_tags)
+		get_fetch_map(refs, &tag_refspec, &tail, 0);
+
+	refspec_item_clear(&tag_refspec);
+	return local_refs;
+}
+
+static void write_remote_refs(const struct ref *local_refs)
+{
+	const struct ref *r;
+
+	struct ref_transaction *t;
+	struct strbuf err = STRBUF_INIT;
+
+	t = ref_store_transaction_begin(get_main_ref_store(the_repository),
+					REF_TRANSACTION_FLAG_INITIAL, &err);
+	if (!t)
+		die("%s", err.buf);
+
+	for (r = local_refs; r; r = r->next) {
+		if (!r->peer_ref)
+			continue;
+		if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
+					   NULL, 0, NULL, &err))
+			die("%s", err.buf);
+	}
+
+	if (ref_transaction_commit(t, &err))
+		die("%s", err.buf);
+
+	strbuf_release(&err);
+	ref_transaction_free(t);
+}
+
+static void write_followtags(const struct ref *refs, const char *msg)
+{
+	const struct ref *ref;
+	for (ref = refs; ref; ref = ref->next) {
+		if (!starts_with(ref->name, "refs/tags/"))
+			continue;
+		if (ends_with(ref->name, "^{}"))
+			continue;
+		if (!repo_has_object_file_with_flags(the_repository, &ref->old_oid,
+						     OBJECT_INFO_QUICK |
+						     OBJECT_INFO_SKIP_FETCH_OBJECT))
+			continue;
+		refs_update_ref(get_main_ref_store(the_repository), msg,
+				ref->name, &ref->old_oid, NULL, 0,
+				UPDATE_REFS_DIE_ON_ERR);
+	}
+}
+
+static const struct object_id *iterate_ref_map(void *cb_data)
+{
+	struct ref **rm = cb_data;
+	struct ref *ref = *rm;
+
+	/*
+	 * Skip anything missing a peer_ref, which we are not
+	 * actually going to write a ref for.
+	 */
+	while (ref && !ref->peer_ref)
+		ref = ref->next;
+	if (!ref)
+		return NULL;
+
+	*rm = ref->next;
+	return &ref->old_oid;
+}
+
+static void update_remote_refs(const struct ref *refs,
+			       const struct ref *mapped_refs,
+			       const struct ref *remote_head_points_at,
+			       const char *branch_top,
+			       const char *msg,
+			       struct transport *transport,
+			       int check_connectivity)
+{
+	const struct ref *rm = mapped_refs;
+
+	if (check_connectivity) {
+		struct check_connected_options opt = CHECK_CONNECTED_INIT;
+
+		opt.transport = transport;
+		opt.progress = transport->progress;
+
+		if (check_connected(iterate_ref_map, &rm, &opt))
+			die(_("remote did not send all necessary objects"));
+	}
+
+	if (refs) {
+		write_remote_refs(mapped_refs);
+		if (option_single_branch && !option_no_tags)
+			write_followtags(refs, msg);
+	}
+
+	if (remote_head_points_at && !option_bare) {
+		struct strbuf head_ref = STRBUF_INIT;
+		strbuf_addstr(&head_ref, branch_top);
+		strbuf_addstr(&head_ref, "HEAD");
+		if (refs_update_symref(get_main_ref_store(the_repository), head_ref.buf,
+				       remote_head_points_at->peer_ref->name,
+				       msg) < 0)
+			die(_("unable to update %s"), head_ref.buf);
+		strbuf_release(&head_ref);
+	}
+}
+
+static void update_head(const struct ref *our, const struct ref *remote,
+			const char *unborn, const char *msg)
+{
+	const char *head;
+	if (our && skip_prefix(our->name, "refs/heads/", &head)) {
+		/* Local default branch link */
+		if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", our->name, NULL) < 0)
+			die(_("unable to update HEAD"));
+		if (!option_bare) {
+			refs_update_ref(get_main_ref_store(the_repository),
+					msg, "HEAD", &our->old_oid, NULL, 0,
+					UPDATE_REFS_DIE_ON_ERR);
+			install_branch_config(0, head, remote_name, our->name);
+		}
+	} else if (our) {
+		struct commit *c = lookup_commit_reference(the_repository,
+							   &our->old_oid);
+		/* --branch specifies a non-branch (i.e. tags), detach HEAD */
+		refs_update_ref(get_main_ref_store(the_repository), msg,
+				"HEAD", &c->object.oid, NULL, REF_NO_DEREF,
+				UPDATE_REFS_DIE_ON_ERR);
+	} else if (remote) {
+		/*
+		 * We know remote HEAD points to a non-branch, or
+		 * HEAD points to a branch but we don't know which one.
+		 * Detach HEAD in all these cases.
+		 */
+		refs_update_ref(get_main_ref_store(the_repository), msg,
+				"HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
+				UPDATE_REFS_DIE_ON_ERR);
+	} else if (unborn && skip_prefix(unborn, "refs/heads/", &head)) {
+		/*
+		 * Unborn head from remote; same as "our" case above except
+		 * that we have no ref to update.
+		 */
+		if (refs_update_symref(get_main_ref_store(the_repository), "HEAD", unborn, NULL) < 0)
+			die(_("unable to update HEAD"));
+		if (!option_bare)
+			install_branch_config(0, head, remote_name, unborn);
+	}
+}
+
+static int git_sparse_checkout_init(const char *repo)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	int result = 0;
+	strvec_pushl(&cmd.args, "-C", repo, "sparse-checkout", "set", NULL);
+
+	/*
+	 * We must apply the setting in the current process
+	 * for the later checkout to use the sparse-checkout file.
+	 */
+	core_apply_sparse_checkout = 1;
+
+	cmd.git_cmd = 1;
+	if (run_command(&cmd)) {
+		error(_("failed to initialize sparse-checkout"));
+		result = 1;
+	}
+
+	return result;
+}
+
+static int checkout(int submodule_progress, int filter_submodules,
+		    enum ref_storage_format ref_storage_format)
+{
+	struct object_id oid;
+	char *head;
+	struct lock_file lock_file = LOCK_INIT;
+	struct unpack_trees_options opts;
+	struct tree *tree;
+	struct tree_desc t;
+	int err = 0;
+
+	if (option_no_checkout)
+		return 0;
+
+	head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+				   RESOLVE_REF_READING, &oid, NULL);
+	if (!head) {
+		warning(_("remote HEAD refers to nonexistent ref, "
+			  "unable to checkout"));
+		return 0;
+	}
+	if (!strcmp(head, "HEAD")) {
+		if (advice_enabled(ADVICE_DETACHED_HEAD))
+			detach_advice(oid_to_hex(&oid));
+		FREE_AND_NULL(head);
+	} else {
+		if (!starts_with(head, "refs/heads/"))
+			die(_("HEAD not found below refs/heads!"));
+	}
+
+	/* We need to be in the new work tree for the checkout */
+	setup_work_tree();
+
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+
+	memset(&opts, 0, sizeof opts);
+	opts.update = 1;
+	opts.merge = 1;
+	opts.clone = 1;
+	opts.preserve_ignored = 0;
+	opts.fn = oneway_merge;
+	opts.verbose_update = (option_verbosity >= 0);
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+	init_checkout_metadata(&opts.meta, head, &oid, NULL);
+
+	tree = parse_tree_indirect(&oid);
+	if (!tree)
+		die(_("unable to parse commit %s"), oid_to_hex(&oid));
+	if (parse_tree(tree) < 0)
+		exit(128);
+	init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
+	if (unpack_trees(1, &t, &opts) < 0)
+		die(_("unable to checkout working tree"));
+
+	free(head);
+
+	if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+		die(_("unable to write new index file"));
+
+	err |= run_hooks_l(the_repository, "post-checkout", oid_to_hex(null_oid()),
+			   oid_to_hex(&oid), "1", NULL);
+
+	if (!err && (option_recurse_submodules.nr > 0)) {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+		strvec_pushl(&cmd.args, "submodule", "update", "--require-init",
+			     "--recursive", NULL);
+
+		if (option_shallow_submodules == 1)
+			strvec_push(&cmd.args, "--depth=1");
+
+		if (max_jobs != -1)
+			strvec_pushf(&cmd.args, "--jobs=%d", max_jobs);
+
+		if (submodule_progress)
+			strvec_push(&cmd.args, "--progress");
+
+		if (option_verbosity < 0)
+			strvec_push(&cmd.args, "--quiet");
+
+		if (option_remote_submodules) {
+			strvec_push(&cmd.args, "--remote");
+			strvec_push(&cmd.args, "--no-fetch");
+		}
+
+		if (ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+			strvec_pushf(&cmd.args, "--ref-format=%s",
+				     ref_storage_format_to_name(ref_storage_format));
+
+		if (filter_submodules && filter_options.choice)
+			strvec_pushf(&cmd.args, "--filter=%s",
+				     expand_list_objects_filter_spec(&filter_options));
+
+		if (option_single_branch >= 0)
+			strvec_push(&cmd.args, option_single_branch ?
+					       "--single-branch" :
+					       "--no-single-branch");
+
+		cmd.git_cmd = 1;
+		err = run_command(&cmd);
+	}
+
+	return err;
+}
+
+static int git_clone_config(const char *k, const char *v,
+			    const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(k, "clone.defaultremotename")) {
+		if (!v)
+			return config_error_nonbool(k);
+		free(remote_name);
+		remote_name = xstrdup(v);
+	}
+	if (!strcmp(k, "clone.rejectshallow"))
+		config_reject_shallow = git_config_bool(k, v);
+	if (!strcmp(k, "clone.filtersubmodules"))
+		config_filter_submodules = git_config_bool(k, v);
+
+	return git_default_config(k, v, ctx, cb);
+}
+
+static int write_one_config(const char *key, const char *value,
+			    const struct config_context *ctx,
+			    void *data)
+{
+	/*
+	 * give git_clone_config a chance to write config values back to the
+	 * environment, since git_config_set_multivar_gently only deals with
+	 * config-file writes
+	 */
+	int apply_failed = git_clone_config(key, value, ctx, data);
+	if (apply_failed)
+		return apply_failed;
+
+	return git_config_set_multivar_gently(key,
+					      value ? value : "true",
+					      CONFIG_REGEX_NONE, 0);
+}
+
+static void write_config(struct string_list *config)
+{
+	int i;
+
+	for (i = 0; i < config->nr; i++) {
+		if (git_config_parse_parameter(config->items[i].string,
+					       write_one_config, NULL) < 0)
+			die(_("unable to write parameters to config file"));
+	}
+}
+
+static void write_refspec_config(const char *src_ref_prefix,
+		const struct ref *our_head_points_at,
+		const struct ref *remote_head_points_at,
+		struct strbuf *branch_top)
+{
+	struct strbuf key = STRBUF_INIT;
+	struct strbuf value = STRBUF_INIT;
+
+	if (option_mirror || !option_bare) {
+		if (option_single_branch && !option_mirror) {
+			if (option_branch) {
+				if (starts_with(our_head_points_at->name, "refs/tags/"))
+					strbuf_addf(&value, "+%s:%s", our_head_points_at->name,
+						our_head_points_at->name);
+				else
+					strbuf_addf(&value, "+%s:%s%s", our_head_points_at->name,
+						branch_top->buf, option_branch);
+			} else if (remote_head_points_at) {
+				const char *head = remote_head_points_at->name;
+				if (!skip_prefix(head, "refs/heads/", &head))
+					BUG("remote HEAD points at non-head?");
+
+				strbuf_addf(&value, "+%s:%s%s", remote_head_points_at->name,
+						branch_top->buf, head);
+			}
+			/*
+			 * otherwise, the next "git fetch" will
+			 * simply fetch from HEAD without updating
+			 * any remote-tracking branch, which is what
+			 * we want.
+			 */
+		} else {
+			strbuf_addf(&value, "+%s*:%s*", src_ref_prefix, branch_top->buf);
+		}
+		/* Configure the remote */
+		if (value.len) {
+			strbuf_addf(&key, "remote.%s.fetch", remote_name);
+			git_config_set_multivar(key.buf, value.buf, "^$", 0);
+			strbuf_reset(&key);
+
+			if (option_mirror) {
+				strbuf_addf(&key, "remote.%s.mirror", remote_name);
+				git_config_set(key.buf, "true");
+				strbuf_reset(&key);
+			}
+		}
+	}
+
+	strbuf_release(&key);
+	strbuf_release(&value);
+}
+
+static void dissociate_from_references(void)
+{
+	char *alternates = git_pathdup("objects/info/alternates");
+
+	if (!access(alternates, F_OK)) {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+
+		cmd.git_cmd = 1;
+		cmd.no_stdin = 1;
+		strvec_pushl(&cmd.args, "repack", "-a", "-d", NULL);
+		if (run_command(&cmd))
+			die(_("cannot repack to clean up"));
+		if (unlink(alternates) && errno != ENOENT)
+			die_errno(_("cannot unlink temporary alternates file"));
+	}
+	free(alternates);
+}
+
+static int path_exists(const char *path)
+{
+	struct stat sb;
+	return !stat(path, &sb);
+}
+
+int cmd_clone(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repository UNUSED)
+{
+	int is_bundle = 0, is_local;
+	int reject_shallow = 0;
+	const char *repo_name, *repo, *work_tree, *git_dir;
+	char *repo_to_free = NULL;
+	char *path = NULL, *dir, *display_repo = NULL;
+	int dest_exists, real_dest_exists = 0;
+	const struct ref *refs, *remote_head;
+	struct ref *remote_head_points_at = NULL;
+	const struct ref *our_head_points_at;
+	char *unborn_head = NULL;
+	struct ref *mapped_refs = NULL;
+	const struct ref *ref;
+	struct strbuf key = STRBUF_INIT;
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf branch_top = STRBUF_INIT, reflog_msg = STRBUF_INIT;
+	struct transport *transport = NULL;
+	const char *src_ref_prefix = "refs/heads/";
+	struct remote *remote;
+	int err = 0, complete_refs_before_fetch = 1;
+	int submodule_progress;
+	int filter_submodules = 0;
+	int hash_algo;
+	enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
+	const int do_not_override_repo_unix_permissions = -1;
+
+	struct transport_ls_refs_options transport_ls_refs_options =
+		TRANSPORT_LS_REFS_OPTIONS_INIT;
+
+	packet_trace_identity("clone");
+
+	git_config(git_clone_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, builtin_clone_options,
+			     builtin_clone_usage, 0);
+
+	if (argc > 2)
+		usage_msg_opt(_("Too many arguments."),
+			builtin_clone_usage, builtin_clone_options);
+
+	if (argc == 0)
+		usage_msg_opt(_("You must specify a repository to clone."),
+			builtin_clone_usage, builtin_clone_options);
+
+	if (option_depth || option_since || option_not.nr)
+		deepen = 1;
+	if (option_single_branch == -1)
+		option_single_branch = deepen ? 1 : 0;
+
+	if (ref_format) {
+		ref_storage_format = ref_storage_format_by_name(ref_format);
+		if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown ref storage format '%s'"), ref_format);
+	}
+
+	if (option_mirror)
+		option_bare = 1;
+
+	if (option_bare) {
+		if (real_git_dir)
+			die(_("options '%s' and '%s' cannot be used together"), "--bare", "--separate-git-dir");
+		option_no_checkout = 1;
+	}
+
+	if (bundle_uri && deepen)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--bundle-uri",
+		    "--depth/--shallow-since/--shallow-exclude");
+
+	repo_name = argv[0];
+
+	path = get_repo_path(repo_name, &is_bundle);
+	if (path) {
+		FREE_AND_NULL(path);
+		repo = repo_to_free = absolute_pathdup(repo_name);
+	} else if (strchr(repo_name, ':')) {
+		repo = repo_name;
+		display_repo = transport_anonymize_url(repo);
+	} else
+		die(_("repository '%s' does not exist"), repo_name);
+
+	/* no need to be strict, transport_set_option() will validate it again */
+	if (option_depth && atoi(option_depth) < 1)
+		die(_("depth %s is not a positive number"), option_depth);
+
+	if (argc == 2)
+		dir = xstrdup(argv[1]);
+	else
+		dir = git_url_basename(repo_name, is_bundle, option_bare);
+	strip_dir_trailing_slashes(dir);
+
+	dest_exists = path_exists(dir);
+	if (dest_exists && !is_empty_dir(dir))
+		die(_("destination path '%s' already exists and is not "
+			"an empty directory."), dir);
+
+	if (real_git_dir) {
+		real_dest_exists = path_exists(real_git_dir);
+		if (real_dest_exists && !is_empty_dir(real_git_dir))
+			die(_("repository path '%s' already exists and is not "
+				"an empty directory."), real_git_dir);
+	}
+
+
+	strbuf_addf(&reflog_msg, "clone: from %s",
+		    display_repo ? display_repo : repo);
+	free(display_repo);
+
+	if (option_bare)
+		work_tree = NULL;
+	else {
+		work_tree = getenv("GIT_WORK_TREE");
+		if (work_tree && path_exists(work_tree))
+			die(_("working tree '%s' already exists."), work_tree);
+	}
+
+	if (option_bare || work_tree)
+		git_dir = xstrdup(dir);
+	else {
+		work_tree = dir;
+		git_dir = mkpathdup("%s/.git", dir);
+	}
+
+	atexit(remove_junk);
+	sigchain_push_common(remove_junk_on_signal);
+
+	if (!option_bare) {
+		if (safe_create_leading_directories_const(work_tree) < 0)
+			die_errno(_("could not create leading directories of '%s'"),
+				  work_tree);
+		if (dest_exists)
+			junk_work_tree_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+		else if (mkdir(work_tree, 0777))
+			die_errno(_("could not create work tree dir '%s'"),
+				  work_tree);
+		junk_work_tree = work_tree;
+		set_git_work_tree(work_tree);
+	}
+
+	if (real_git_dir) {
+		if (real_dest_exists)
+			junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+		junk_git_dir = real_git_dir;
+	} else {
+		if (dest_exists)
+			junk_git_dir_flags |= REMOVE_DIR_KEEP_TOPLEVEL;
+		junk_git_dir = git_dir;
+	}
+	if (safe_create_leading_directories_const(git_dir) < 0)
+		die(_("could not create leading directories of '%s'"), git_dir);
+
+	if (0 <= option_verbosity) {
+		if (option_bare)
+			fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
+		else
+			fprintf(stderr, _("Cloning into '%s'...\n"), dir);
+	}
+
+	if (option_recurse_submodules.nr > 0) {
+		struct string_list_item *item;
+		struct strbuf sb = STRBUF_INIT;
+		int val;
+
+		/* remove duplicates */
+		string_list_sort(&option_recurse_submodules);
+		string_list_remove_duplicates(&option_recurse_submodules, 0);
+
+		/*
+		 * NEEDSWORK: In a multi-working-tree world, this needs to be
+		 * set in the per-worktree config.
+		 */
+		for_each_string_list_item(item, &option_recurse_submodules) {
+			strbuf_addf(&sb, "submodule.active=%s",
+				    item->string);
+			string_list_append(&option_config,
+					   strbuf_detach(&sb, NULL));
+		}
+
+		if (!git_config_get_bool("submodule.stickyRecursiveClone", &val) &&
+		    val)
+			string_list_append(&option_config, "submodule.recurse=true");
+
+		if (option_required_reference.nr &&
+		    option_optional_reference.nr)
+			die(_("clone --recursive is not compatible with "
+			      "both --reference and --reference-if-able"));
+		else if (option_required_reference.nr) {
+			string_list_append(&option_config,
+				"submodule.alternateLocation=superproject");
+			string_list_append(&option_config,
+				"submodule.alternateErrorStrategy=die");
+		} else if (option_optional_reference.nr) {
+			string_list_append(&option_config,
+				"submodule.alternateLocation=superproject");
+			string_list_append(&option_config,
+				"submodule.alternateErrorStrategy=info");
+		}
+	}
+
+	/*
+	 * Initialize the repository, but skip initializing the reference
+	 * database. We do not yet know about the object format of the
+	 * repository, and reference backends may persist that information into
+	 * their on-disk data structures.
+	 */
+	init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN,
+		ref_storage_format, NULL,
+		do_not_override_repo_unix_permissions, INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
+
+	if (real_git_dir) {
+		free((char *)git_dir);
+		git_dir = real_git_dir;
+	}
+
+	/*
+	 * We have a chicken-and-egg situation between initializing the refdb
+	 * and spawning transport helpers:
+	 *
+	 *   - Initializing the refdb requires us to know about the object
+	 *     format. We thus have to spawn the transport helper to learn
+	 *     about it.
+	 *
+	 *   - The transport helper may want to access the Git repository. But
+	 *     because the refdb has not been initialized, we don't have "HEAD"
+	 *     or "refs/". Thus, the helper cannot find the Git repository.
+	 *
+	 * Ideally, we would have structured the helper protocol such that it's
+	 * mandatory for the helper to first announce its capabilities without
+	 * yet assuming a fully initialized repository. Like that, we could
+	 * have added a "lazy-refdb-init" capability that announces whether the
+	 * helper is ready to handle not-yet-initialized refdbs. If any helper
+	 * didn't support them, we would have fully initialized the refdb with
+	 * the SHA1 object format, but later on bailed out if we found out that
+	 * the remote repository used a different object format.
+	 *
+	 * But we didn't, and thus we use the following workaround to partially
+	 * initialize the repository's refdb such that it can be discovered by
+	 * Git commands. To do so, we:
+	 *
+	 *   - Create an invalid HEAD ref pointing at "refs/heads/.invalid".
+	 *
+	 *   - Create the "refs/" directory.
+	 *
+	 *   - Set up the ref storage format and repository version as
+	 *     required.
+	 *
+	 * This is sufficient for Git commands to discover the Git directory.
+	 */
+	initialize_repository_version(GIT_HASH_UNKNOWN,
+				      the_repository->ref_storage_format, 1);
+
+	strbuf_addf(&buf, "%s/HEAD", git_dir);
+	write_file(buf.buf, "ref: refs/heads/.invalid");
+
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "%s/refs", git_dir);
+	safe_create_dir(buf.buf, 1);
+
+	/*
+	 * additional config can be injected with -c, make sure it's included
+	 * after init_db, which clears the entire config environment.
+	 */
+	write_config(&option_config);
+
+	/*
+	 * re-read config after init_db and write_config to pick up any config
+	 * injected by --template and --config, respectively.
+	 */
+	git_config(git_clone_config, NULL);
+
+	/*
+	 * If option_reject_shallow is specified from CLI option,
+	 * ignore config_reject_shallow from git_clone_config.
+	 */
+	if (config_reject_shallow != -1)
+		reject_shallow = config_reject_shallow;
+	if (option_reject_shallow != -1)
+		reject_shallow = option_reject_shallow;
+
+	/*
+	 * If option_filter_submodules is specified from CLI option,
+	 * ignore config_filter_submodules from git_clone_config.
+	 */
+	if (config_filter_submodules != -1)
+		filter_submodules = config_filter_submodules;
+	if (option_filter_submodules != -1)
+		filter_submodules = option_filter_submodules;
+
+	/*
+	 * Exit if the user seems to be doing something silly with submodule
+	 * filter flags (but not with filter configs, as those should be
+	 * set-and-forget).
+	 */
+	if (option_filter_submodules > 0 && !filter_options.choice)
+		die(_("the option '%s' requires '%s'"),
+		    "--also-filter-submodules", "--filter");
+	if (option_filter_submodules > 0 && !option_recurse_submodules.nr)
+		die(_("the option '%s' requires '%s'"),
+		    "--also-filter-submodules", "--recurse-submodules");
+
+	/*
+	 * apply the remote name provided by --origin only after this second
+	 * call to git_config, to ensure it overrides all config-based values.
+	 */
+	if (option_origin) {
+		free(remote_name);
+		remote_name = xstrdup(option_origin);
+	}
+
+	if (!remote_name)
+		remote_name = xstrdup("origin");
+
+	if (!valid_remote_name(remote_name))
+		die(_("'%s' is not a valid remote name"), remote_name);
+
+	if (option_bare) {
+		if (option_mirror)
+			src_ref_prefix = "refs/";
+		strbuf_addstr(&branch_top, src_ref_prefix);
+
+		git_config_set("core.bare", "true");
+	} else {
+		strbuf_addf(&branch_top, "refs/remotes/%s/", remote_name);
+	}
+
+	strbuf_addf(&key, "remote.%s.url", remote_name);
+	git_config_set(key.buf, repo);
+	strbuf_reset(&key);
+
+	if (option_no_tags) {
+		strbuf_addf(&key, "remote.%s.tagOpt", remote_name);
+		git_config_set(key.buf, "--no-tags");
+		strbuf_reset(&key);
+	}
+
+	if (option_required_reference.nr || option_optional_reference.nr)
+		setup_reference();
+
+	remote = remote_get_early(remote_name);
+
+	refspec_appendf(&remote->fetch, "+%s*:%s*", src_ref_prefix,
+			branch_top.buf);
+
+	path = get_repo_path(remote->url.v[0], &is_bundle);
+	is_local = option_local != 0 && path && !is_bundle;
+	if (is_local) {
+		if (option_depth)
+			warning(_("--depth is ignored in local clones; use file:// instead."));
+		if (option_since)
+			warning(_("--shallow-since is ignored in local clones; use file:// instead."));
+		if (option_not.nr)
+			warning(_("--shallow-exclude is ignored in local clones; use file:// instead."));
+		if (filter_options.choice)
+			warning(_("--filter is ignored in local clones; use file:// instead."));
+		if (!access(mkpath("%s/shallow", path), F_OK)) {
+			if (reject_shallow)
+				die(_("source repository is shallow, reject to clone."));
+			if (option_local > 0)
+				warning(_("source repository is shallow, ignoring --local"));
+			is_local = 0;
+		}
+	}
+	if (option_local > 0 && !is_local)
+		warning(_("--local is ignored"));
+
+	transport = transport_get(remote, path ? path : remote->url.v[0]);
+	transport_set_verbosity(transport, option_verbosity, option_progress);
+	transport->family = family;
+	transport->cloning = 1;
+
+	if (is_bundle) {
+		struct bundle_header header = BUNDLE_HEADER_INIT;
+		int fd = read_bundle_header(path, &header);
+		int has_filter = header.filter.choice != LOFC_DISABLED;
+
+		if (fd > 0)
+			close(fd);
+		bundle_header_release(&header);
+		if (has_filter)
+			die(_("cannot clone from filtered bundle"));
+	}
+
+	transport_set_option(transport, TRANS_OPT_KEEP, "yes");
+
+	if (reject_shallow)
+		transport_set_option(transport, TRANS_OPT_REJECT_SHALLOW, "1");
+	if (option_depth)
+		transport_set_option(transport, TRANS_OPT_DEPTH,
+				     option_depth);
+	if (option_since)
+		transport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,
+				     option_since);
+	if (option_not.nr)
+		transport_set_option(transport, TRANS_OPT_DEEPEN_NOT,
+				     (const char *)&option_not);
+	if (option_single_branch)
+		transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
+
+	if (option_upload_pack)
+		transport_set_option(transport, TRANS_OPT_UPLOADPACK,
+				     option_upload_pack);
+
+	if (server_options.nr)
+		transport->server_options = &server_options;
+
+	if (filter_options.choice) {
+		const char *spec =
+			expand_list_objects_filter_spec(&filter_options);
+		transport_set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER,
+				     spec);
+		transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
+	}
+
+	if (transport->smart_options && !deepen && !filter_options.choice)
+		transport->smart_options->check_self_contained_and_connected = 1;
+
+	strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+	refspec_ref_prefixes(&remote->fetch,
+			     &transport_ls_refs_options.ref_prefixes);
+	if (option_branch)
+		expand_ref_prefix(&transport_ls_refs_options.ref_prefixes,
+				  option_branch);
+	if (!option_no_tags)
+		strvec_push(&transport_ls_refs_options.ref_prefixes,
+			    "refs/tags/");
+
+	refs = transport_get_remote_refs(transport, &transport_ls_refs_options);
+
+	/*
+	 * Now that we know what algorithm the remote side is using, let's set
+	 * ours to the same thing.
+	 */
+	hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+	initialize_repository_version(hash_algo, the_repository->ref_storage_format, 1);
+	repo_set_hash_algo(the_repository, hash_algo);
+	create_reference_database(the_repository->ref_storage_format, NULL, 1);
+
+	/*
+	 * Before fetching from the remote, download and install bundle
+	 * data from the --bundle-uri option.
+	 */
+	if (bundle_uri) {
+		struct remote_state *state;
+		int has_heuristic = 0;
+
+		/*
+		 * We need to save the remote state as our remote's lifetime is
+		 * tied to it.
+		 */
+		state = the_repository->remote_state;
+		the_repository->remote_state = NULL;
+		repo_clear(the_repository);
+
+		/* At this point, we need the_repository to match the cloned repo. */
+		if (repo_init(the_repository, git_dir, work_tree))
+			warning(_("failed to initialize the repo, skipping bundle URI"));
+		else if (fetch_bundle_uri(the_repository, bundle_uri, &has_heuristic))
+			warning(_("failed to fetch objects from bundle URI '%s'"),
+				bundle_uri);
+		else if (has_heuristic)
+			git_config_set_gently("fetch.bundleuri", bundle_uri);
+
+		remote_state_clear(the_repository->remote_state);
+		free(the_repository->remote_state);
+		the_repository->remote_state = state;
+	} else {
+		/*
+		* Populate transport->got_remote_bundle_uri and
+		* transport->bundle_uri. We might get nothing.
+		*/
+		transport_get_remote_bundle_uri(transport);
+
+		if (transport->bundles &&
+		    hashmap_get_size(&transport->bundles->bundles)) {
+			struct remote_state *state;
+
+			/*
+			 * We need to save the remote state as our remote's
+			 * lifetime is tied to it.
+			 */
+			state = the_repository->remote_state;
+			the_repository->remote_state = NULL;
+			repo_clear(the_repository);
+
+			/* At this point, we need the_repository to match the cloned repo. */
+			if (repo_init(the_repository, git_dir, work_tree))
+				warning(_("failed to initialize the repo, skipping bundle URI"));
+			else if (fetch_bundle_list(the_repository,
+						   transport->bundles))
+				warning(_("failed to fetch advertised bundles"));
+
+			remote_state_clear(the_repository->remote_state);
+			free(the_repository->remote_state);
+			the_repository->remote_state = state;
+		} else {
+			clear_bundle_list(transport->bundles);
+			FREE_AND_NULL(transport->bundles);
+		}
+	}
+
+	if (refs)
+		mapped_refs = wanted_peer_refs(refs, &remote->fetch);
+
+	if (mapped_refs) {
+		/*
+		 * transport_get_remote_refs() may return refs with null sha-1
+		 * in mapped_refs (see struct transport->get_refs_list
+		 * comment). In that case we need fetch it early because
+		 * remote_head code below relies on it.
+		 *
+		 * for normal clones, transport_get_remote_refs() should
+		 * return reliable ref set, we can delay cloning until after
+		 * remote HEAD check.
+		 */
+		for (ref = refs; ref; ref = ref->next)
+			if (is_null_oid(&ref->old_oid)) {
+				complete_refs_before_fetch = 0;
+				break;
+			}
+
+		if (!is_local && !complete_refs_before_fetch) {
+			if (transport_fetch_refs(transport, mapped_refs))
+				die(_("remote transport reported error"));
+		}
+	}
+
+	remote_head = find_ref_by_name(refs, "HEAD");
+	remote_head_points_at = guess_remote_head(remote_head, mapped_refs, 0);
+
+	if (option_branch) {
+		our_head_points_at = find_remote_branch(mapped_refs, option_branch);
+		if (!our_head_points_at)
+			die(_("Remote branch %s not found in upstream %s"),
+			    option_branch, remote_name);
+	} else if (remote_head_points_at) {
+		our_head_points_at = remote_head_points_at;
+	} else if (remote_head) {
+		our_head_points_at = NULL;
+	} else {
+		char *to_free = NULL;
+		const char *branch;
+
+		if (!mapped_refs) {
+			warning(_("You appear to have cloned an empty repository."));
+			option_no_checkout = 1;
+		}
+
+		if (transport_ls_refs_options.unborn_head_target &&
+		    skip_prefix(transport_ls_refs_options.unborn_head_target,
+				"refs/heads/", &branch)) {
+			unborn_head  = xstrdup(transport_ls_refs_options.unborn_head_target);
+		} else {
+			branch = to_free = repo_default_branch_name(the_repository, 0);
+			unborn_head = xstrfmt("refs/heads/%s", branch);
+		}
+
+		/*
+		 * We may have selected a local default branch name "foo",
+		 * and even though the remote's HEAD does not point there,
+		 * it may still have a "foo" branch. If so, set it up so
+		 * that we can follow the usual checkout code later.
+		 *
+		 * Note that for an empty repo we'll already have set
+		 * option_no_checkout above, which would work against us here.
+		 * But for an empty repo, find_remote_branch() can never find
+		 * a match.
+		 */
+		our_head_points_at = find_remote_branch(mapped_refs, branch);
+
+		free(to_free);
+	}
+
+	write_refspec_config(src_ref_prefix, our_head_points_at,
+			remote_head_points_at, &branch_top);
+
+	if (filter_options.choice)
+		partial_clone_register(remote_name, &filter_options);
+
+	if (is_local)
+		clone_local(path, git_dir);
+	else if (mapped_refs && complete_refs_before_fetch) {
+		if (transport_fetch_refs(transport, mapped_refs))
+			die(_("remote transport reported error"));
+	}
+
+	update_remote_refs(refs, mapped_refs, remote_head_points_at,
+			   branch_top.buf, reflog_msg.buf, transport,
+			   !is_local);
+
+	update_head(our_head_points_at, remote_head, unborn_head, reflog_msg.buf);
+
+	/*
+	 * We want to show progress for recursive submodule clones iff
+	 * we did so for the main clone. But only the transport knows
+	 * the final decision for this flag, so we need to rescue the value
+	 * before we free the transport.
+	 */
+	submodule_progress = transport->progress;
+
+	transport_unlock_pack(transport, 0);
+	transport_disconnect(transport);
+
+	if (option_dissociate) {
+		close_object_store(the_repository->objects);
+		dissociate_from_references();
+	}
+
+	if (option_sparse_checkout && git_sparse_checkout_init(dir))
+		return 1;
+
+	junk_mode = JUNK_LEAVE_REPO;
+	err = checkout(submodule_progress, filter_submodules,
+		       ref_storage_format);
+
+	free(remote_name);
+	strbuf_release(&reflog_msg);
+	strbuf_release(&branch_top);
+	strbuf_release(&buf);
+	strbuf_release(&key);
+	free_refs(mapped_refs);
+	free_refs(remote_head_points_at);
+	free(unborn_head);
+	free(dir);
+	free(path);
+	free(repo_to_free);
+	junk_mode = JUNK_LEAVE_ALL;
+
+	transport_ls_refs_options_release(&transport_ls_refs_options);
+	return err;
+}
diff --git a/builtin/column.c b/builtin/column.c
new file mode 100644
index 0000000000..50314cc255
--- /dev/null
+++ b/builtin/column.c
@@ -0,0 +1,68 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "strbuf.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "column.h"
+
+static const char * const builtin_column_usage[] = {
+	N_("git column [<options>]"),
+	NULL
+};
+static unsigned int colopts;
+
+static int column_config(const char *var, const char *value,
+			 const struct config_context *ctx UNUSED, void *cb)
+{
+	return git_column_config(var, value, cb, &colopts);
+}
+
+int cmd_column(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct string_list list = STRING_LIST_INIT_DUP;
+	struct strbuf sb = STRBUF_INIT;
+	struct column_options copts;
+	const char *command = NULL, *real_command = NULL;
+	struct option options[] = {
+		OPT_STRING(0, "command", &real_command, N_("name"), N_("lookup config vars")),
+		OPT_COLUMN(0, "mode", &colopts, N_("layout to use")),
+		OPT_INTEGER(0, "raw-mode", &colopts, N_("layout to use")),
+		OPT_INTEGER(0, "width", &copts.width, N_("maximum width")),
+		OPT_STRING(0, "indent", &copts.indent, N_("string"), N_("padding space on left border")),
+		OPT_STRING(0, "nl", &copts.nl, N_("string"), N_("padding space on right border")),
+		OPT_INTEGER(0, "padding", &copts.padding, N_("padding space between columns")),
+		OPT_END()
+	};
+
+	/* This one is special and must be the first one */
+	if (argc > 1 && starts_with(argv[1], "--command=")) {
+		command = argv[1] + 10;
+		git_config(column_config, (void *)command);
+	} else
+		git_config(column_config, NULL);
+
+	memset(&copts, 0, sizeof(copts));
+	copts.padding = 1;
+	argc = parse_options(argc, argv, prefix, options, builtin_column_usage, 0);
+	if (copts.padding < 0)
+		die(_("%s must be non-negative"), "--padding");
+	if (argc)
+		usage_with_options(builtin_column_usage, options);
+	if (real_command || command) {
+		if (!real_command || !command || strcmp(real_command, command))
+			die(_("--command must be the first argument"));
+	}
+	finalize_colopts(&colopts, -1);
+	while (!strbuf_getline(&sb, stdin))
+		string_list_append(&list, sb.buf);
+
+	print_columns(&list, colopts, &copts);
+	strbuf_release(&sb);
+	string_list_clear(&list, 0);
+	return 0;
+}
diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c
new file mode 100644
index 0000000000..8ca75262c5
--- /dev/null
+++ b/builtin/commit-graph.c
@@ -0,0 +1,359 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "commit.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "parse-options.h"
+#include "commit-graph.h"
+#include "object-store-ll.h"
+#include "progress.h"
+#include "replace-object.h"
+#include "strbuf.h"
+#include "tag.h"
+#include "trace2.h"
+
+#define BUILTIN_COMMIT_GRAPH_VERIFY_USAGE \
+	N_("git commit-graph verify [--object-dir <dir>] [--shallow] [--[no-]progress]")
+
+#define BUILTIN_COMMIT_GRAPH_WRITE_USAGE \
+	N_("git commit-graph write [--object-dir <dir>] [--append]\n" \
+	   "                       [--split[=<strategy>]] [--reachable | --stdin-packs | --stdin-commits]\n" \
+	   "                       [--changed-paths] [--[no-]max-new-filters <n>] [--[no-]progress]\n" \
+	   "                       <split-options>")
+
+static const char * builtin_commit_graph_verify_usage[] = {
+	BUILTIN_COMMIT_GRAPH_VERIFY_USAGE,
+	NULL
+};
+
+static const char * builtin_commit_graph_write_usage[] = {
+	BUILTIN_COMMIT_GRAPH_WRITE_USAGE,
+	NULL
+};
+
+static char const * const builtin_commit_graph_usage[] = {
+	BUILTIN_COMMIT_GRAPH_VERIFY_USAGE,
+	BUILTIN_COMMIT_GRAPH_WRITE_USAGE,
+	NULL,
+};
+
+static struct opts_commit_graph {
+	const char *obj_dir;
+	int reachable;
+	int stdin_packs;
+	int stdin_commits;
+	int append;
+	int split;
+	int shallow;
+	int progress;
+	int enable_changed_paths;
+} opts;
+
+static struct option common_opts[] = {
+	OPT_STRING(0, "object-dir", &opts.obj_dir,
+		   N_("dir"),
+		   N_("the object directory to store the graph")),
+	OPT_END()
+};
+
+static struct option *add_common_options(struct option *to)
+{
+	return parse_options_concat(common_opts, to);
+}
+
+static int graph_verify(int argc, const char **argv, const char *prefix,
+			struct repository *repo UNUSED)
+{
+	struct commit_graph *graph = NULL;
+	struct object_directory *odb = NULL;
+	char *graph_name;
+	char *chain_name;
+	enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE;
+	int fd;
+	struct stat st;
+	int flags = 0;
+	int incomplete_chain = 0;
+	int ret;
+
+	static struct option builtin_commit_graph_verify_options[] = {
+		OPT_BOOL(0, "shallow", &opts.shallow,
+			 N_("if the commit-graph is split, only verify the tip file")),
+		OPT_BOOL(0, "progress", &opts.progress,
+			 N_("force progress reporting")),
+		OPT_END(),
+	};
+	struct option *options = add_common_options(builtin_commit_graph_verify_options);
+
+	trace2_cmd_mode("verify");
+
+	opts.progress = isatty(2);
+	argc = parse_options(argc, argv, prefix,
+			     options,
+			     builtin_commit_graph_verify_usage, 0);
+	if (argc)
+		usage_with_options(builtin_commit_graph_verify_usage, options);
+
+	if (!opts.obj_dir)
+		opts.obj_dir = repo_get_object_directory(the_repository);
+	if (opts.shallow)
+		flags |= COMMIT_GRAPH_VERIFY_SHALLOW;
+	if (opts.progress)
+		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
+
+	odb = find_odb(the_repository, opts.obj_dir);
+	graph_name = get_commit_graph_filename(odb);
+	chain_name = get_commit_graph_chain_filename(odb);
+	if (open_commit_graph(graph_name, &fd, &st))
+		opened = OPENED_GRAPH;
+	else if (errno != ENOENT)
+		die_errno(_("Could not open commit-graph '%s'"), graph_name);
+	else if (open_commit_graph_chain(chain_name, &fd, &st))
+		opened = OPENED_CHAIN;
+	else if (errno != ENOENT)
+		die_errno(_("could not open commit-graph chain '%s'"), chain_name);
+
+	FREE_AND_NULL(graph_name);
+	FREE_AND_NULL(chain_name);
+	FREE_AND_NULL(options);
+
+	if (opened == OPENED_NONE)
+		return 0;
+	else if (opened == OPENED_GRAPH)
+		graph = load_commit_graph_one_fd_st(the_repository, fd, &st, odb);
+	else
+		graph = load_commit_graph_chain_fd_st(the_repository, fd, &st,
+						      &incomplete_chain);
+
+	if (!graph)
+		return 1;
+
+	ret = verify_commit_graph(the_repository, graph, flags);
+	free_commit_graph(graph);
+
+	if (incomplete_chain) {
+		error("one or more commit-graph chain files could not be loaded");
+		ret |= 1;
+	}
+
+	return ret;
+}
+
+extern int read_replace_refs;
+static struct commit_graph_opts write_opts;
+
+static int write_option_parse_split(const struct option *opt, const char *arg,
+				    int unset)
+{
+	enum commit_graph_split_flags *flags = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	opts.split = 1;
+	if (!arg)
+		return 0;
+
+	if (!strcmp(arg, "no-merge"))
+		*flags = COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED;
+	else if (!strcmp(arg, "replace"))
+		*flags = COMMIT_GRAPH_SPLIT_REPLACE;
+	else
+		die(_("unrecognized --split argument, %s"), arg);
+
+	return 0;
+}
+
+static int read_one_commit(struct oidset *commits, struct progress *progress,
+			   const char *hash)
+{
+	struct object *result;
+	struct object_id oid;
+	const char *end;
+
+	if (parse_oid_hex(hash, &oid, &end))
+		return error(_("unexpected non-hex object ID: %s"), hash);
+
+	result = deref_tag(the_repository, parse_object(the_repository, &oid),
+			   NULL, 0);
+	if (!result)
+		return error(_("invalid object: %s"), hash);
+	else if (object_as_type(result, OBJ_COMMIT, 1))
+		oidset_insert(commits, &result->oid);
+
+	display_progress(progress, oidset_size(commits));
+
+	return 0;
+}
+
+static int write_option_max_new_filters(const struct option *opt,
+					const char *arg,
+					int unset)
+{
+	int *to = opt->value;
+	if (unset)
+		*to = -1;
+	else {
+		const char *s;
+		*to = strtol(arg, (char **)&s, 10);
+		if (*s)
+			return error(_("option `%s' expects a numerical value"),
+				     "max-new-filters");
+	}
+	return 0;
+}
+
+static int git_commit_graph_write_config(const char *var, const char *value,
+					 const struct config_context *ctx,
+					 void *cb UNUSED)
+{
+	if (!strcmp(var, "commitgraph.maxnewfilters"))
+		write_opts.max_new_filters = git_config_int(var, value, ctx->kvi);
+	/*
+	 * No need to fall-back to 'git_default_config', since this was already
+	 * called in 'cmd_commit_graph()'.
+	 */
+	return 0;
+}
+
+static int graph_write(int argc, const char **argv, const char *prefix,
+		       struct repository *repo UNUSED)
+{
+	struct string_list pack_indexes = STRING_LIST_INIT_DUP;
+	struct strbuf buf = STRBUF_INIT;
+	struct oidset commits = OIDSET_INIT;
+	struct object_directory *odb = NULL;
+	int result = 0;
+	enum commit_graph_write_flags flags = 0;
+	struct progress *progress = NULL;
+
+	static struct option builtin_commit_graph_write_options[] = {
+		OPT_BOOL(0, "reachable", &opts.reachable,
+			N_("start walk at all refs")),
+		OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
+			N_("scan pack-indexes listed by stdin for commits")),
+		OPT_BOOL(0, "stdin-commits", &opts.stdin_commits,
+			N_("start walk at commits listed by stdin")),
+		OPT_BOOL(0, "append", &opts.append,
+			N_("include all commits already in the commit-graph file")),
+		OPT_BOOL(0, "changed-paths", &opts.enable_changed_paths,
+			N_("enable computation for changed paths")),
+		OPT_CALLBACK_F(0, "split", &write_opts.split_flags, NULL,
+			N_("allow writing an incremental commit-graph file"),
+			PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+			write_option_parse_split),
+		OPT_INTEGER(0, "max-commits", &write_opts.max_commits,
+			N_("maximum number of commits in a non-base split commit-graph")),
+		OPT_INTEGER(0, "size-multiple", &write_opts.size_multiple,
+			N_("maximum ratio between two levels of a split commit-graph")),
+		OPT_EXPIRY_DATE(0, "expire-time", &write_opts.expire_time,
+			N_("only expire files older than a given date-time")),
+		OPT_CALLBACK_F(0, "max-new-filters", &write_opts.max_new_filters,
+			NULL, N_("maximum number of changed-path Bloom filters to compute"),
+			0, write_option_max_new_filters),
+		OPT_BOOL(0, "progress", &opts.progress,
+			 N_("force progress reporting")),
+		OPT_END(),
+	};
+	struct option *options = add_common_options(builtin_commit_graph_write_options);
+
+	opts.progress = isatty(2);
+	opts.enable_changed_paths = -1;
+	write_opts.size_multiple = 2;
+	write_opts.max_commits = 0;
+	write_opts.expire_time = 0;
+	write_opts.max_new_filters = -1;
+
+	trace2_cmd_mode("write");
+
+	git_config(git_commit_graph_write_config, &opts);
+
+	argc = parse_options(argc, argv, prefix,
+			     options,
+			     builtin_commit_graph_write_usage, 0);
+	if (argc)
+		usage_with_options(builtin_commit_graph_write_usage, options);
+
+	if (opts.reachable + opts.stdin_packs + opts.stdin_commits > 1)
+		die(_("use at most one of --reachable, --stdin-commits, or --stdin-packs"));
+	if (!opts.obj_dir)
+		opts.obj_dir = repo_get_object_directory(the_repository);
+	if (opts.append)
+		flags |= COMMIT_GRAPH_WRITE_APPEND;
+	if (opts.split)
+		flags |= COMMIT_GRAPH_WRITE_SPLIT;
+	if (opts.progress)
+		flags |= COMMIT_GRAPH_WRITE_PROGRESS;
+	if (!opts.enable_changed_paths)
+		flags |= COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS;
+	if (opts.enable_changed_paths == 1 ||
+	    git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
+		flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;
+
+	odb = find_odb(the_repository, opts.obj_dir);
+
+	if (opts.reachable) {
+		if (write_commit_graph_reachable(odb, flags, &write_opts))
+			result = 1;
+		goto cleanup;
+	}
+
+	if (opts.stdin_packs) {
+		while (strbuf_getline(&buf, stdin) != EOF)
+			string_list_append_nodup(&pack_indexes,
+						 strbuf_detach(&buf, NULL));
+	} else if (opts.stdin_commits) {
+		oidset_init(&commits, 0);
+		if (opts.progress)
+			progress = start_delayed_progress(
+				the_repository,
+				_("Collecting commits from input"), 0);
+
+		while (strbuf_getline(&buf, stdin) != EOF) {
+			if (read_one_commit(&commits, progress, buf.buf)) {
+				result = 1;
+				goto cleanup;
+			}
+		}
+
+		stop_progress(&progress);
+	}
+
+	if (write_commit_graph(odb,
+			       opts.stdin_packs ? &pack_indexes : NULL,
+			       opts.stdin_commits ? &commits : NULL,
+			       flags,
+			       &write_opts))
+		result = 1;
+
+cleanup:
+	FREE_AND_NULL(options);
+	string_list_clear(&pack_indexes, 0);
+	strbuf_release(&buf);
+	oidset_clear(&commits);
+	return result;
+}
+
+int cmd_commit_graph(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option builtin_commit_graph_options[] = {
+		OPT_SUBCOMMAND("verify", &fn, graph_verify),
+		OPT_SUBCOMMAND("write", &fn, graph_write),
+		OPT_END(),
+	};
+	struct option *options = parse_options_concat(builtin_commit_graph_options, common_opts);
+
+	git_config(git_default_config, NULL);
+
+	disable_replace_refs();
+	save_commit_buffer = 0;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_commit_graph_usage, 0);
+	FREE_AND_NULL(options);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/commit-tree.c b/builtin/commit-tree.c
new file mode 100644
index 0000000000..38457600a4
--- /dev/null
+++ b/builtin/commit-tree.c
@@ -0,0 +1,151 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+
+#include "commit.h"
+#include "parse-options.h"
+
+static const char * const commit_tree_usage[] = {
+	N_("git commit-tree <tree> [(-p <parent>)...]"),
+	N_("git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...]\n"
+	   "                [(-F <file>)...] <tree>"),
+	NULL
+};
+
+static const char *sign_commit;
+
+static void new_parent(struct commit *parent, struct commit_list **parents_p)
+{
+	struct object_id *oid = &parent->object.oid;
+	struct commit_list *parents;
+	for (parents = *parents_p; parents; parents = parents->next) {
+		if (parents->item == parent) {
+			error(_("duplicate parent %s ignored"), oid_to_hex(oid));
+			return;
+		}
+		parents_p = &parents->next;
+	}
+	commit_list_insert(parent, parents_p);
+}
+
+static int parse_parent_arg_callback(const struct option *opt,
+		const char *arg, int unset)
+{
+	struct object_id oid;
+	struct commit_list **parents = opt->value;
+
+	BUG_ON_OPT_NEG_NOARG(unset, arg);
+
+	if (repo_get_oid_commit(the_repository, arg, &oid))
+		die(_("not a valid object name %s"), arg);
+
+	assert_oid_type(&oid, OBJ_COMMIT);
+	new_parent(lookup_commit(the_repository, &oid), parents);
+	return 0;
+}
+
+static int parse_message_arg_callback(const struct option *opt,
+		const char *arg, int unset)
+{
+	struct strbuf *buf = opt->value;
+
+	BUG_ON_OPT_NEG_NOARG(unset, arg);
+
+	if (buf->len)
+		strbuf_addch(buf, '\n');
+	strbuf_addstr(buf, arg);
+	strbuf_complete_line(buf);
+
+	return 0;
+}
+
+static int parse_file_arg_callback(const struct option *opt,
+		const char *arg, int unset)
+{
+	int fd;
+	struct strbuf *buf = opt->value;
+
+	BUG_ON_OPT_NEG_NOARG(unset, arg);
+
+	if (buf->len)
+		strbuf_addch(buf, '\n');
+	if (!strcmp(arg, "-"))
+		fd = 0;
+	else {
+		fd = xopen(arg, O_RDONLY);
+	}
+	if (strbuf_read(buf, fd, 0) < 0)
+		die_errno(_("git commit-tree: failed to read '%s'"), arg);
+	if (fd && close(fd))
+		die_errno(_("git commit-tree: failed to close '%s'"), arg);
+
+	return 0;
+}
+
+int cmd_commit_tree(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
+{
+	static struct strbuf buffer = STRBUF_INIT;
+	struct commit_list *parents = NULL;
+	struct object_id tree_oid;
+	struct object_id commit_oid;
+
+	struct option options[] = {
+		OPT_CALLBACK_F('p', NULL, &parents, N_("parent"),
+			N_("id of a parent commit object"), PARSE_OPT_NONEG,
+			parse_parent_arg_callback),
+		OPT_CALLBACK_F('m', NULL, &buffer, N_("message"),
+			N_("commit message"), PARSE_OPT_NONEG,
+			parse_message_arg_callback),
+		OPT_CALLBACK_F('F', NULL, &buffer, N_("file"),
+			N_("read commit log message from file"), PARSE_OPT_NONEG,
+			parse_file_arg_callback),
+		{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
+			N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+		OPT_END()
+	};
+	int ret;
+
+	git_config(git_default_config, NULL);
+
+	show_usage_with_options_if_asked(argc, argv,
+					 commit_tree_usage, options);
+
+	argc = parse_options(argc, argv, prefix, options, commit_tree_usage, 0);
+
+	if (argc != 1)
+		die(_("must give exactly one tree"));
+
+	if (repo_get_oid_tree(the_repository, argv[0], &tree_oid))
+		die(_("not a valid object name %s"), argv[0]);
+
+	if (!buffer.len) {
+		if (strbuf_read(&buffer, 0, 0) < 0)
+			die_errno(_("git commit-tree: failed to read"));
+	}
+
+	if (commit_tree(buffer.buf, buffer.len, &tree_oid, parents, &commit_oid,
+			NULL, sign_commit)) {
+		ret = 1;
+		goto out;
+	}
+
+	printf("%s\n", oid_to_hex(&commit_oid));
+	ret = 0;
+
+out:
+	free_commit_list(parents);
+	strbuf_release(&buffer);
+	return ret;
+}
diff --git a/builtin/commit.c b/builtin/commit.c
new file mode 100644
index 0000000000..9fb405dd4a
--- /dev/null
+++ b/builtin/commit.c
@@ -0,0 +1,1927 @@
+/*
+ * Builtin "git commit"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@xxxxxxxxxx>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "lockfile.h"
+#include "cache-tree.h"
+#include "color.h"
+#include "dir.h"
+#include "editor.h"
+#include "environment.h"
+#include "diff.h"
+#include "commit.h"
+#include "gettext.h"
+#include "revision.h"
+#include "wt-status.h"
+#include "run-command.h"
+#include "strbuf.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "path.h"
+#include "preload-index.h"
+#include "read-cache.h"
+#include "repository.h"
+#include "string-list.h"
+#include "rerere.h"
+#include "unpack-trees.h"
+#include "column.h"
+#include "sequencer.h"
+#include "sparse-index.h"
+#include "mailmap.h"
+#include "help.h"
+#include "commit-reach.h"
+#include "commit-graph.h"
+#include "pretty.h"
+#include "trailer.h"
+
+static const char * const builtin_commit_usage[] = {
+	N_("git commit [-a | --interactive | --patch] [-s] [-v] [-u[<mode>]] [--amend]\n"
+	   "           [--dry-run] [(-c | -C | --squash) <commit> | --fixup [(amend|reword):]<commit>]\n"
+	   "           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]\n"
+	   "           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]\n"
+	   "           [--date=<date>] [--cleanup=<mode>] [--[no-]status]\n"
+	   "           [-i | -o] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+	   "           [(--trailer <token>[(=|:)<value>])...] [-S[<keyid>]]\n"
+	   "           [--] [<pathspec>...]"),
+	NULL
+};
+
+static const char * const builtin_status_usage[] = {
+	N_("git status [<options>] [--] [<pathspec>...]"),
+	NULL
+};
+
+static const char empty_amend_advice[] =
+N_("You asked to amend the most recent commit, but doing so would make\n"
+"it empty. You can repeat your command with --allow-empty, or you can\n"
+"remove the commit entirely with \"git reset HEAD^\".\n");
+
+static const char empty_cherry_pick_advice[] =
+N_("The previous cherry-pick is now empty, possibly due to conflict resolution.\n"
+"If you wish to commit it anyway, use:\n"
+"\n"
+"    git commit --allow-empty\n"
+"\n");
+
+static const char empty_rebase_pick_advice[] =
+N_("Otherwise, please use 'git rebase --skip'\n");
+
+static const char empty_cherry_pick_advice_single[] =
+N_("Otherwise, please use 'git cherry-pick --skip'\n");
+
+static const char empty_cherry_pick_advice_multi[] =
+N_("and then use:\n"
+"\n"
+"    git cherry-pick --continue\n"
+"\n"
+"to resume cherry-picking the remaining commits.\n"
+"If you wish to skip this commit, use:\n"
+"\n"
+"    git cherry-pick --skip\n"
+"\n");
+
+static const char *color_status_slots[] = {
+	[WT_STATUS_HEADER]	  = "header",
+	[WT_STATUS_UPDATED]	  = "updated",
+	[WT_STATUS_CHANGED]	  = "changed",
+	[WT_STATUS_UNTRACKED]	  = "untracked",
+	[WT_STATUS_NOBRANCH]	  = "noBranch",
+	[WT_STATUS_UNMERGED]	  = "unmerged",
+	[WT_STATUS_LOCAL_BRANCH]  = "localBranch",
+	[WT_STATUS_REMOTE_BRANCH] = "remoteBranch",
+	[WT_STATUS_ONBRANCH]	  = "branch",
+};
+
+static const char *use_message_buffer;
+static struct lock_file index_lock; /* real index */
+static struct lock_file false_lock; /* used only for partial commits */
+static enum {
+	COMMIT_AS_IS = 1,
+	COMMIT_NORMAL,
+	COMMIT_PARTIAL
+} commit_style;
+
+static const char *force_author;
+static char *logfile;
+static char *template_file;
+/*
+ * The _message variables are commit names from which to take
+ * the commit message and/or authorship.
+ */
+static const char *author_message, *author_message_buffer;
+static const char *edit_message, *use_message;
+static char *fixup_message, *fixup_commit, *squash_message;
+static const char *fixup_prefix;
+static int all, also, interactive, patch_interactive, only, amend, signoff;
+static int edit_flag = -1; /* unspecified */
+static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
+static int config_commit_verbose = -1; /* unspecified */
+static int no_post_rewrite, allow_empty_message, pathspec_file_nul;
+static const char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
+static const char *sign_commit, *pathspec_from_file;
+static struct strvec trailer_args = STRVEC_INIT;
+
+/*
+ * The default commit message cleanup mode will remove the lines
+ * beginning with # (shell comments) and leading and trailing
+ * whitespaces (empty lines or containing only whitespaces)
+ * if editor is used, and only the whitespaces if the message
+ * is specified explicitly.
+ */
+static enum commit_msg_cleanup_mode cleanup_mode;
+static char *cleanup_config;
+
+static enum commit_whence whence;
+static int use_editor = 1, include_status = 1;
+static int have_option_m;
+static struct strbuf message = STRBUF_INIT;
+
+static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
+
+static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset)
+{
+	enum wt_status_format *value = (enum wt_status_format *)opt->value;
+	if (unset)
+		*value = STATUS_FORMAT_NONE;
+	else if (!arg)
+		*value = STATUS_FORMAT_PORCELAIN;
+	else if (!strcmp(arg, "v1") || !strcmp(arg, "1"))
+		*value = STATUS_FORMAT_PORCELAIN;
+	else if (!strcmp(arg, "v2") || !strcmp(arg, "2"))
+		*value = STATUS_FORMAT_PORCELAIN_V2;
+	else
+		die("unsupported porcelain version '%s'", arg);
+
+	return 0;
+}
+
+static int opt_parse_m(const struct option *opt, const char *arg, int unset)
+{
+	struct strbuf *buf = opt->value;
+	if (unset) {
+		have_option_m = 0;
+		strbuf_setlen(buf, 0);
+	} else {
+		have_option_m = 1;
+		if (buf->len)
+			strbuf_addch(buf, '\n');
+		strbuf_addstr(buf, arg);
+		strbuf_complete_line(buf);
+	}
+	return 0;
+}
+
+static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset)
+{
+	const char **value = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (arg != NULL && *arg == '=')
+		arg = arg + 1;
+
+	*value = arg;
+	return 0;
+}
+
+static void determine_whence(struct wt_status *s)
+{
+	if (file_exists(git_path_merge_head(the_repository)))
+		whence = FROM_MERGE;
+	else if (!sequencer_determine_whence(the_repository, &whence))
+		whence = FROM_COMMIT;
+	if (s)
+		s->whence = whence;
+}
+
+static void status_init_config(struct wt_status *s, config_fn_t fn)
+{
+	wt_status_prepare(the_repository, s);
+	init_diff_ui_defaults();
+	git_config(fn, s);
+	determine_whence(s);
+	s->hints = advice_enabled(ADVICE_STATUS_HINTS); /* must come after git_config() */
+}
+
+static void rollback_index_files(void)
+{
+	switch (commit_style) {
+	case COMMIT_AS_IS:
+		break; /* nothing to do */
+	case COMMIT_NORMAL:
+		rollback_lock_file(&index_lock);
+		break;
+	case COMMIT_PARTIAL:
+		rollback_lock_file(&index_lock);
+		rollback_lock_file(&false_lock);
+		break;
+	}
+}
+
+static int commit_index_files(void)
+{
+	int err = 0;
+
+	switch (commit_style) {
+	case COMMIT_AS_IS:
+		break; /* nothing to do */
+	case COMMIT_NORMAL:
+		err = commit_lock_file(&index_lock);
+		break;
+	case COMMIT_PARTIAL:
+		err = commit_lock_file(&index_lock);
+		rollback_lock_file(&false_lock);
+		break;
+	}
+
+	return err;
+}
+
+/*
+ * Take a union of paths in the index and the named tree (typically, "HEAD"),
+ * and return the paths that match the given pattern in list.
+ */
+static int list_paths(struct string_list *list, const char *with_tree,
+		      const struct pathspec *pattern)
+{
+	int i, ret;
+	char *m;
+
+	if (!pattern->nr)
+		return 0;
+
+	m = xcalloc(1, pattern->nr);
+
+	if (with_tree) {
+		char *max_prefix = common_prefix(pattern);
+		overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
+		free(max_prefix);
+	}
+
+	/* TODO: audit for interaction with sparse-index. */
+	ensure_full_index(the_repository->index);
+	for (i = 0; i < the_repository->index->cache_nr; i++) {
+		const struct cache_entry *ce = the_repository->index->cache[i];
+		struct string_list_item *item;
+
+		if (ce->ce_flags & CE_UPDATE)
+			continue;
+		if (!ce_path_match(the_repository->index, ce, pattern, m))
+			continue;
+		item = string_list_insert(list, ce->name);
+		if (ce_skip_worktree(ce))
+			item->util = item; /* better a valid pointer than a fake one */
+	}
+
+	ret = report_path_error(m, pattern);
+	free(m);
+	return ret;
+}
+
+static void add_remove_files(struct string_list *list)
+{
+	int i;
+	for (i = 0; i < list->nr; i++) {
+		struct stat st;
+		struct string_list_item *p = &(list->items[i]);
+
+		/* p->util is skip-worktree */
+		if (p->util)
+			continue;
+
+		if (!lstat(p->string, &st)) {
+			if (add_to_index(the_repository->index, p->string, &st, 0))
+				die(_("updating files failed"));
+		} else
+			remove_file_from_index(the_repository->index, p->string);
+	}
+}
+
+static void create_base_index(const struct commit *current_head)
+{
+	struct tree *tree;
+	struct unpack_trees_options opts;
+	struct tree_desc t;
+
+	if (!current_head) {
+		discard_index(the_repository->index);
+		return;
+	}
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = 1;
+	opts.index_only = 1;
+	opts.merge = 1;
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+
+	opts.fn = oneway_merge;
+	tree = parse_tree_indirect(&current_head->object.oid);
+	if (!tree)
+		die(_("failed to unpack HEAD tree object"));
+	if (parse_tree(tree) < 0)
+		exit(128);
+	init_tree_desc(&t, &tree->object.oid, tree->buffer, tree->size);
+	if (unpack_trees(1, &t, &opts))
+		exit(128); /* We've already reported the error, finish dying */
+}
+
+static void refresh_cache_or_die(int refresh_flags)
+{
+	/*
+	 * refresh_flags contains REFRESH_QUIET, so the only errors
+	 * are for unmerged entries.
+	 */
+	if (refresh_index(the_repository->index, refresh_flags | REFRESH_IN_PORCELAIN, NULL, NULL, NULL))
+		die_resolve_conflict("commit");
+}
+
+static const char *prepare_index(const char **argv, const char *prefix,
+				 const struct commit *current_head, int is_status)
+{
+	struct string_list partial = STRING_LIST_INIT_DUP;
+	struct pathspec pathspec;
+	int refresh_flags = REFRESH_QUIET;
+	const char *ret;
+
+	if (is_status)
+		refresh_flags |= REFRESH_UNMERGED;
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_FULL,
+		       prefix, argv);
+
+	if (pathspec_from_file) {
+		if (interactive)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--interactive/--patch");
+
+		if (all)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "-a");
+
+		if (pathspec.nr)
+			die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
+
+		parse_pathspec_file(&pathspec, 0,
+				    PATHSPEC_PREFER_FULL,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
+	}
+
+	if (!pathspec.nr && (also || (only && !allow_empty &&
+	    (!amend || (fixup_message && strcmp(fixup_prefix, "amend"))))))
+		die(_("No paths with --include/--only does not make sense."));
+
+	if (repo_read_index_preload(the_repository, &pathspec, 0) < 0)
+		die(_("index file corrupt"));
+
+	if (interactive) {
+		char *old_index_env = NULL, *old_repo_index_file;
+		repo_hold_locked_index(the_repository, &index_lock,
+				       LOCK_DIE_ON_ERROR);
+
+		refresh_cache_or_die(refresh_flags);
+
+		if (write_locked_index(the_repository->index, &index_lock, 0))
+			die(_("unable to create temporary index"));
+
+		old_repo_index_file = the_repository->index_file;
+		the_repository->index_file =
+			(char *)get_lock_file_path(&index_lock);
+		old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
+		setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
+
+		if (interactive_add(the_repository, argv, prefix, patch_interactive) != 0)
+			die(_("interactive add failed"));
+
+		the_repository->index_file = old_repo_index_file;
+		if (old_index_env && *old_index_env)
+			setenv(INDEX_ENVIRONMENT, old_index_env, 1);
+		else
+			unsetenv(INDEX_ENVIRONMENT);
+		FREE_AND_NULL(old_index_env);
+
+		discard_index(the_repository->index);
+		read_index_from(the_repository->index, get_lock_file_path(&index_lock),
+				repo_get_git_dir(the_repository));
+		if (cache_tree_update(the_repository->index, WRITE_TREE_SILENT) == 0) {
+			if (reopen_lock_file(&index_lock) < 0)
+				die(_("unable to write index file"));
+			if (write_locked_index(the_repository->index, &index_lock, 0))
+				die(_("unable to update temporary index"));
+		} else
+			warning(_("Failed to update main cache tree"));
+
+		commit_style = COMMIT_NORMAL;
+		ret = get_lock_file_path(&index_lock);
+		goto out;
+	}
+
+	/*
+	 * Non partial, non as-is commit.
+	 *
+	 * (1) get the real index;
+	 * (2) update the_index as necessary;
+	 * (3) write the_index out to the real index (still locked);
+	 * (4) return the name of the locked index file.
+	 *
+	 * The caller should run hooks on the locked real index, and
+	 * (A) if all goes well, commit the real index;
+	 * (B) on failure, rollback the real index.
+	 */
+	if (all || (also && pathspec.nr)) {
+		char *ps_matched = xcalloc(pathspec.nr, 1);
+		repo_hold_locked_index(the_repository, &index_lock,
+				       LOCK_DIE_ON_ERROR);
+		add_files_to_cache(the_repository, also ? prefix : NULL,
+				   &pathspec, ps_matched, 0, 0);
+		if (!all && report_path_error(ps_matched, &pathspec))
+			exit(128);
+
+		refresh_cache_or_die(refresh_flags);
+		cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+		if (write_locked_index(the_repository->index, &index_lock, 0))
+			die(_("unable to write new index file"));
+		commit_style = COMMIT_NORMAL;
+		ret = get_lock_file_path(&index_lock);
+		free(ps_matched);
+		goto out;
+	}
+
+	/*
+	 * As-is commit.
+	 *
+	 * (1) return the name of the real index file.
+	 *
+	 * The caller should run hooks on the real index,
+	 * and create commit from the_index.
+	 * We still need to refresh the index here.
+	 */
+	if (!only && !pathspec.nr) {
+		repo_hold_locked_index(the_repository, &index_lock,
+				       LOCK_DIE_ON_ERROR);
+		refresh_cache_or_die(refresh_flags);
+		if (the_repository->index->cache_changed
+		    || !cache_tree_fully_valid(the_repository->index->cache_tree))
+			cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+		if (write_locked_index(the_repository->index, &index_lock,
+				       COMMIT_LOCK | SKIP_IF_UNCHANGED))
+			die(_("unable to write new index file"));
+		commit_style = COMMIT_AS_IS;
+		ret = repo_get_index_file(the_repository);
+		goto out;
+	}
+
+	/*
+	 * A partial commit.
+	 *
+	 * (0) find the set of affected paths;
+	 * (1) get lock on the real index file;
+	 * (2) update the_index with the given paths;
+	 * (3) write the_index out to the real index (still locked);
+	 * (4) get lock on the false index file;
+	 * (5) reset the_index from HEAD;
+	 * (6) update the_index the same way as (2);
+	 * (7) write the_index out to the false index file;
+	 * (8) return the name of the false index file (still locked);
+	 *
+	 * The caller should run hooks on the locked false index, and
+	 * create commit from it.  Then
+	 * (A) if all goes well, commit the real index;
+	 * (B) on failure, rollback the real index;
+	 * In either case, rollback the false index.
+	 */
+	commit_style = COMMIT_PARTIAL;
+
+	if (whence != FROM_COMMIT) {
+		if (whence == FROM_MERGE)
+			die(_("cannot do a partial commit during a merge."));
+		else if (is_from_cherry_pick(whence))
+			die(_("cannot do a partial commit during a cherry-pick."));
+		else if (is_from_rebase(whence))
+			die(_("cannot do a partial commit during a rebase."));
+	}
+
+	if (list_paths(&partial, !current_head ? NULL : "HEAD", &pathspec))
+		exit(1);
+
+	discard_index(the_repository->index);
+	if (repo_read_index(the_repository) < 0)
+		die(_("cannot read the index"));
+
+	repo_hold_locked_index(the_repository, &index_lock, LOCK_DIE_ON_ERROR);
+	add_remove_files(&partial);
+	refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
+	cache_tree_update(the_repository->index, WRITE_TREE_SILENT);
+	if (write_locked_index(the_repository->index, &index_lock, 0))
+		die(_("unable to write new index file"));
+
+	hold_lock_file_for_update(&false_lock,
+				  git_path("next-index-%"PRIuMAX,
+					   (uintmax_t) getpid()),
+				  LOCK_DIE_ON_ERROR);
+
+	create_base_index(current_head);
+	add_remove_files(&partial);
+	refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
+
+	if (write_locked_index(the_repository->index, &false_lock, 0))
+		die(_("unable to write temporary index file"));
+
+	discard_index(the_repository->index);
+	ret = get_lock_file_path(&false_lock);
+	read_index_from(the_repository->index, ret, repo_get_git_dir(the_repository));
+out:
+	string_list_clear(&partial, 0);
+	clear_pathspec(&pathspec);
+	return ret;
+}
+
+static int run_status(FILE *fp, const char *index_file, const char *prefix, int nowarn,
+		      struct wt_status *s)
+{
+	struct object_id oid;
+
+	if (s->relative_paths)
+		s->prefix = prefix;
+
+	if (amend) {
+		s->amend = 1;
+		s->reference = "HEAD^1";
+	}
+	s->verbose = verbose;
+	s->index_file = index_file;
+	s->fp = fp;
+	s->nowarn = nowarn;
+	s->is_initial = repo_get_oid(the_repository, s->reference, &oid) ? 1 : 0;
+	if (!s->is_initial)
+		oidcpy(&s->oid_commit, &oid);
+	s->status_format = status_format;
+	s->ignore_submodule_arg = ignore_submodule_arg;
+
+	wt_status_collect(s);
+	wt_status_print(s);
+	wt_status_collect_free_buffers(s);
+
+	return s->committable;
+}
+
+static int is_a_merge(const struct commit *current_head)
+{
+	return !!(current_head->parents && current_head->parents->next);
+}
+
+static void assert_split_ident(struct ident_split *id, const struct strbuf *buf)
+{
+	if (split_ident_line(id, buf->buf, buf->len) || !id->date_begin)
+		BUG("unable to parse our own ident: %s", buf->buf);
+}
+
+static void export_one(const char *var, const char *s, const char *e, int hack)
+{
+	struct strbuf buf = STRBUF_INIT;
+	if (hack)
+		strbuf_addch(&buf, hack);
+	strbuf_add(&buf, s, e - s);
+	setenv(var, buf.buf, 1);
+	strbuf_release(&buf);
+}
+
+static int parse_force_date(const char *in, struct strbuf *out)
+{
+	strbuf_addch(out, '@');
+
+	if (parse_date(in, out) < 0) {
+		int errors = 0;
+		unsigned long t = approxidate_careful(in, &errors);
+		if (errors)
+			return -1;
+		strbuf_addf(out, "%lu", t);
+	}
+
+	return 0;
+}
+
+static void set_ident_var(char **buf, char *val)
+{
+	free(*buf);
+	*buf = val;
+}
+
+static void determine_author_info(struct strbuf *author_ident)
+{
+	char *name, *email, *date;
+	struct ident_split author;
+
+	name = xstrdup_or_null(getenv("GIT_AUTHOR_NAME"));
+	email = xstrdup_or_null(getenv("GIT_AUTHOR_EMAIL"));
+	date = xstrdup_or_null(getenv("GIT_AUTHOR_DATE"));
+
+	if (author_message) {
+		struct ident_split ident;
+		size_t len;
+		const char *a;
+
+		a = find_commit_header(author_message_buffer, "author", &len);
+		if (!a)
+			die(_("commit '%s' lacks author header"), author_message);
+		if (split_ident_line(&ident, a, len) < 0)
+			die(_("commit '%s' has malformed author line"), author_message);
+
+		set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin));
+		set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin));
+
+		if (ident.date_begin) {
+			struct strbuf date_buf = STRBUF_INIT;
+			strbuf_addch(&date_buf, '@');
+			strbuf_add(&date_buf, ident.date_begin, ident.date_end - ident.date_begin);
+			strbuf_addch(&date_buf, ' ');
+			strbuf_add(&date_buf, ident.tz_begin, ident.tz_end - ident.tz_begin);
+			set_ident_var(&date, strbuf_detach(&date_buf, NULL));
+		}
+	}
+
+	if (force_author) {
+		struct ident_split ident;
+
+		if (split_ident_line(&ident, force_author, strlen(force_author)) < 0)
+			die(_("malformed --author parameter"));
+		set_ident_var(&name, xmemdupz(ident.name_begin, ident.name_end - ident.name_begin));
+		set_ident_var(&email, xmemdupz(ident.mail_begin, ident.mail_end - ident.mail_begin));
+	}
+
+	if (force_date) {
+		struct strbuf date_buf = STRBUF_INIT;
+		if (parse_force_date(force_date, &date_buf))
+			die(_("invalid date format: %s"), force_date);
+		set_ident_var(&date, strbuf_detach(&date_buf, NULL));
+	}
+
+	strbuf_addstr(author_ident, fmt_ident(name, email, WANT_AUTHOR_IDENT, date,
+				IDENT_STRICT));
+	assert_split_ident(&author, author_ident);
+	export_one("GIT_AUTHOR_NAME", author.name_begin, author.name_end, 0);
+	export_one("GIT_AUTHOR_EMAIL", author.mail_begin, author.mail_end, 0);
+	export_one("GIT_AUTHOR_DATE", author.date_begin, author.tz_end, '@');
+	free(name);
+	free(email);
+	free(date);
+}
+
+static int author_date_is_interesting(void)
+{
+	return author_message || force_date;
+}
+
+static void adjust_comment_line_char(const struct strbuf *sb)
+{
+	char candidates[] = "#;@!$%^&|:";
+	char *candidate;
+	const char *p;
+
+	if (!memchr(sb->buf, candidates[0], sb->len)) {
+		free(comment_line_str_to_free);
+		comment_line_str = comment_line_str_to_free =
+			xstrfmt("%c", candidates[0]);
+		return;
+	}
+
+	p = sb->buf;
+	candidate = strchr(candidates, *p);
+	if (candidate)
+		*candidate = ' ';
+	for (p = sb->buf; *p; p++) {
+		if ((p[0] == '\n' || p[0] == '\r') && p[1]) {
+			candidate = strchr(candidates, p[1]);
+			if (candidate)
+				*candidate = ' ';
+		}
+	}
+
+	for (p = candidates; *p == ' '; p++)
+		;
+	if (!*p)
+		die(_("unable to select a comment character that is not used\n"
+		      "in the current commit message"));
+	free(comment_line_str_to_free);
+	comment_line_str = comment_line_str_to_free = xstrfmt("%c", *p);
+}
+
+static void prepare_amend_commit(struct commit *commit, struct strbuf *sb,
+				struct pretty_print_context *ctx)
+{
+	const char *buffer, *subject, *fmt;
+
+	buffer = repo_get_commit_buffer(the_repository, commit, NULL);
+	find_commit_subject(buffer, &subject);
+	/*
+	 * If we amend the 'amend!' commit then we don't want to
+	 * duplicate the subject line.
+	 */
+	fmt = starts_with(subject, "amend!") ? "%b" : "%B";
+	repo_format_commit_message(the_repository, commit, fmt, sb, ctx);
+	repo_unuse_commit_buffer(the_repository, commit, buffer);
+}
+
+static void change_data_free(void *util, const char *str UNUSED)
+{
+	struct wt_status_change_data *d = util;
+	free(d->rename_source);
+	free(d);
+}
+
+static int prepare_to_commit(const char *index_file, const char *prefix,
+			     struct commit *current_head,
+			     struct wt_status *s,
+			     struct strbuf *author_ident)
+{
+	struct stat statbuf;
+	struct strbuf committer_ident = STRBUF_INIT;
+	int committable;
+	struct strbuf sb = STRBUF_INIT;
+	const char *hook_arg1 = NULL;
+	const char *hook_arg2 = NULL;
+	int clean_message_contents = (cleanup_mode != COMMIT_MSG_CLEANUP_NONE);
+	int old_display_comment_prefix;
+	int invoked_hook;
+
+	/* This checks and barfs if author is badly specified */
+	determine_author_info(author_ident);
+
+	if (!no_verify && run_commit_hook(use_editor, index_file, &invoked_hook,
+					  "pre-commit", NULL))
+		return 0;
+
+	if (squash_message) {
+		/*
+		 * Insert the proper subject line before other commit
+		 * message options add their content.
+		 */
+		if (use_message && !strcmp(use_message, squash_message))
+			strbuf_addstr(&sb, "squash! ");
+		else {
+			struct pretty_print_context ctx = {0};
+			struct commit *c;
+			c = lookup_commit_reference_by_name(squash_message);
+			if (!c)
+				die(_("could not lookup commit '%s'"), squash_message);
+			ctx.output_encoding = get_commit_output_encoding();
+			repo_format_commit_message(the_repository, c,
+						   "squash! %s\n\n", &sb,
+						   &ctx);
+		}
+	}
+
+	if (have_option_m && !fixup_message) {
+		strbuf_addbuf(&sb, &message);
+		hook_arg1 = "message";
+	} else if (logfile && !strcmp(logfile, "-")) {
+		if (isatty(0))
+			fprintf(stderr, _("(reading log message from standard input)\n"));
+		if (strbuf_read(&sb, 0, 0) < 0)
+			die_errno(_("could not read log from standard input"));
+		hook_arg1 = "message";
+	} else if (logfile) {
+		if (strbuf_read_file(&sb, logfile, 0) < 0)
+			die_errno(_("could not read log file '%s'"),
+				  logfile);
+		hook_arg1 = "message";
+	} else if (use_message) {
+		char *buffer;
+		buffer = strstr(use_message_buffer, "\n\n");
+		if (buffer)
+			strbuf_addstr(&sb, skip_blank_lines(buffer + 2));
+		hook_arg1 = "commit";
+		hook_arg2 = use_message;
+	} else if (fixup_message) {
+		struct pretty_print_context ctx = {0};
+		struct commit *commit;
+		char *fmt;
+		commit = lookup_commit_reference_by_name(fixup_commit);
+		if (!commit)
+			die(_("could not lookup commit '%s'"), fixup_commit);
+		ctx.output_encoding = get_commit_output_encoding();
+		fmt = xstrfmt("%s! %%s\n\n", fixup_prefix);
+		repo_format_commit_message(the_repository, commit, fmt, &sb,
+					   &ctx);
+		free(fmt);
+		hook_arg1 = "message";
+
+		/*
+		 * Only `-m` commit message option is checked here, as
+		 * it supports `--fixup` to append the commit message.
+		 *
+		 * The other commit message options `-c`/`-C`/`-F` are
+		 * incompatible with all the forms of `--fixup` and
+		 * have already errored out while parsing the `git commit`
+		 * options.
+		 */
+		if (have_option_m && !strcmp(fixup_prefix, "fixup"))
+			strbuf_addbuf(&sb, &message);
+
+		if (!strcmp(fixup_prefix, "amend")) {
+			if (have_option_m)
+				die(_("options '%s' and '%s:%s' cannot be used together"), "-m", "--fixup", fixup_message);
+			prepare_amend_commit(commit, &sb, &ctx);
+		}
+	} else if (!stat(git_path_merge_msg(the_repository), &statbuf)) {
+		size_t merge_msg_start;
+
+		/*
+		 * prepend SQUASH_MSG here if it exists and a
+		 * "merge --squash" was originally performed
+		 */
+		if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
+			if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
+				die_errno(_("could not read SQUASH_MSG"));
+			hook_arg1 = "squash";
+		} else
+			hook_arg1 = "merge";
+
+		merge_msg_start = sb.len;
+		if (strbuf_read_file(&sb, git_path_merge_msg(the_repository), 0) < 0)
+			die_errno(_("could not read MERGE_MSG"));
+
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS &&
+		    wt_status_locate_end(sb.buf + merge_msg_start,
+					 sb.len - merge_msg_start) <
+				sb.len - merge_msg_start)
+			s->added_cut_line = 1;
+	} else if (!stat(git_path_squash_msg(the_repository), &statbuf)) {
+		if (strbuf_read_file(&sb, git_path_squash_msg(the_repository), 0) < 0)
+			die_errno(_("could not read SQUASH_MSG"));
+		hook_arg1 = "squash";
+	} else if (template_file) {
+		if (strbuf_read_file(&sb, template_file, 0) < 0)
+			die_errno(_("could not read '%s'"), template_file);
+		hook_arg1 = "template";
+		clean_message_contents = 0;
+	}
+
+	/*
+	 * The remaining cases don't modify the template message, but
+	 * just set the argument(s) to the prepare-commit-msg hook.
+	 */
+	else if (whence == FROM_MERGE)
+		hook_arg1 = "merge";
+	else if (is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) {
+		hook_arg1 = "commit";
+		hook_arg2 = "CHERRY_PICK_HEAD";
+	}
+
+	if (squash_message) {
+		/*
+		 * If squash_commit was used for the commit subject,
+		 * then we're possibly hijacking other commit log options.
+		 * Reset the hook args to tell the real story.
+		 */
+		hook_arg1 = "message";
+		hook_arg2 = "";
+	}
+
+	s->fp = fopen_for_writing(git_path_commit_editmsg());
+	if (!s->fp)
+		die_errno(_("could not open '%s'"), git_path_commit_editmsg());
+
+	/* Ignore status.displayCommentPrefix: we do need comments in COMMIT_EDITMSG. */
+	old_display_comment_prefix = s->display_comment_prefix;
+	s->display_comment_prefix = 1;
+
+	/*
+	 * Most hints are counter-productive when the commit has
+	 * already started.
+	 */
+	s->hints = 0;
+
+	if (clean_message_contents)
+		strbuf_stripspace(&sb, NULL);
+
+	if (signoff)
+		append_signoff(&sb, ignored_log_message_bytes(sb.buf, sb.len), 0);
+
+	if (fwrite(sb.buf, 1, sb.len, s->fp) < sb.len)
+		die_errno(_("could not write commit template"));
+
+	if (auto_comment_line_char)
+		adjust_comment_line_char(&sb);
+	strbuf_release(&sb);
+
+	/* This checks if committer ident is explicitly given */
+	strbuf_addstr(&committer_ident, git_committer_info(IDENT_STRICT));
+	if (use_editor && include_status) {
+		int ident_shown = 0;
+		int saved_color_setting;
+		struct ident_split ci, ai;
+		const char *hint_cleanup_all = allow_empty_message ?
+			_("Please enter the commit message for your changes."
+			  " Lines starting\nwith '%s' will be ignored.\n") :
+			_("Please enter the commit message for your changes."
+			  " Lines starting\nwith '%s' will be ignored, and an empty"
+			  " message aborts the commit.\n");
+		const char *hint_cleanup_space = allow_empty_message ?
+			_("Please enter the commit message for your changes."
+			  " Lines starting\n"
+			  "with '%s' will be kept; you may remove them"
+			  " yourself if you want to.\n") :
+			_("Please enter the commit message for your changes."
+			  " Lines starting\n"
+			  "with '%s' will be kept; you may remove them"
+			  " yourself if you want to.\n"
+			  "An empty message aborts the commit.\n");
+		if (whence != FROM_COMMIT) {
+			if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+				wt_status_add_cut_line(s);
+			status_printf_ln(
+				s, GIT_COLOR_NORMAL,
+				whence == FROM_MERGE ?
+					      _("\n"
+					  "It looks like you may be committing a merge.\n"
+					  "If this is not correct, please run\n"
+					  "	git update-ref -d MERGE_HEAD\n"
+					  "and try again.\n") :
+					      _("\n"
+					  "It looks like you may be committing a cherry-pick.\n"
+					  "If this is not correct, please run\n"
+					  "	git update-ref -d CHERRY_PICK_HEAD\n"
+					  "and try again.\n"));
+		}
+
+		fprintf(s->fp, "\n");
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_ALL)
+			status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_all, comment_line_str);
+		else if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			if (whence == FROM_COMMIT)
+				wt_status_add_cut_line(s);
+		} else /* COMMIT_MSG_CLEANUP_SPACE, that is. */
+			status_printf(s, GIT_COLOR_NORMAL, hint_cleanup_space, comment_line_str);
+
+		/*
+		 * These should never fail because they come from our own
+		 * fmt_ident. They may fail the sane_ident test, but we know
+		 * that the name and mail pointers will at least be valid,
+		 * which is enough for our tests and printing here.
+		 */
+		assert_split_ident(&ai, author_ident);
+		assert_split_ident(&ci, &committer_ident);
+
+		if (ident_cmp(&ai, &ci))
+			status_printf_ln(s, GIT_COLOR_NORMAL,
+				_("%s"
+				"Author:    %.*s <%.*s>"),
+				ident_shown++ ? "" : "\n",
+				(int)(ai.name_end - ai.name_begin), ai.name_begin,
+				(int)(ai.mail_end - ai.mail_begin), ai.mail_begin);
+
+		if (author_date_is_interesting())
+			status_printf_ln(s, GIT_COLOR_NORMAL,
+				_("%s"
+				"Date:      %s"),
+				ident_shown++ ? "" : "\n",
+				show_ident_date(&ai, DATE_MODE(NORMAL)));
+
+		if (!committer_ident_sufficiently_given())
+			status_printf_ln(s, GIT_COLOR_NORMAL,
+				_("%s"
+				"Committer: %.*s <%.*s>"),
+				ident_shown++ ? "" : "\n",
+				(int)(ci.name_end - ci.name_begin), ci.name_begin,
+				(int)(ci.mail_end - ci.mail_begin), ci.mail_begin);
+
+		status_printf_ln(s, GIT_COLOR_NORMAL, "%s", ""); /* Add new line for clarity */
+
+		saved_color_setting = s->use_color;
+		s->use_color = 0;
+		committable = run_status(s->fp, index_file, prefix, 1, s);
+		s->use_color = saved_color_setting;
+		string_list_clear_func(&s->change, change_data_free);
+	} else {
+		struct object_id oid;
+		const char *parent = "HEAD";
+
+		if (!the_repository->index->initialized && repo_read_index(the_repository) < 0)
+			die(_("Cannot read index"));
+
+		if (amend)
+			parent = "HEAD^1";
+
+		if (repo_get_oid(the_repository, parent, &oid)) {
+			int i, ita_nr = 0;
+
+			/* TODO: audit for interaction with sparse-index. */
+			ensure_full_index(the_repository->index);
+			for (i = 0; i < the_repository->index->cache_nr; i++)
+				if (ce_intent_to_add(the_repository->index->cache[i]))
+					ita_nr++;
+			committable = the_repository->index->cache_nr - ita_nr > 0;
+		} else {
+			/*
+			 * Unless the user did explicitly request a submodule
+			 * ignore mode by passing a command line option we do
+			 * not ignore any changed submodule SHA-1s when
+			 * comparing index and parent, no matter what is
+			 * configured. Otherwise we won't commit any
+			 * submodules which were manually staged, which would
+			 * be really confusing.
+			 */
+			struct diff_flags flags = DIFF_FLAGS_INIT;
+			flags.override_submodule_config = 1;
+			if (ignore_submodule_arg &&
+			    !strcmp(ignore_submodule_arg, "all"))
+				flags.ignore_submodules = 1;
+			committable = index_differs_from(the_repository,
+							 parent, &flags, 1);
+		}
+	}
+	strbuf_release(&committer_ident);
+
+	fclose(s->fp);
+
+	if (trailer_args.nr) {
+		if (amend_file_with_trailers(git_path_commit_editmsg(), &trailer_args))
+			die(_("unable to pass trailers to --trailers"));
+		strvec_clear(&trailer_args);
+	}
+
+	/*
+	 * Reject an attempt to record a non-merge empty commit without
+	 * explicit --allow-empty. In the cherry-pick case, it may be
+	 * empty due to conflict resolution, which the user should okay.
+	 */
+	if (!committable && whence != FROM_MERGE && !allow_empty &&
+	    !(amend && is_a_merge(current_head))) {
+		s->hints = advice_enabled(ADVICE_STATUS_HINTS);
+		s->display_comment_prefix = old_display_comment_prefix;
+		run_status(stdout, index_file, prefix, 0, s);
+		if (amend)
+			fputs(_(empty_amend_advice), stderr);
+		else if (is_from_cherry_pick(whence) ||
+			 whence == FROM_REBASE_PICK) {
+			fputs(_(empty_cherry_pick_advice), stderr);
+			if (whence == FROM_CHERRY_PICK_SINGLE)
+				fputs(_(empty_cherry_pick_advice_single), stderr);
+			else if (whence == FROM_CHERRY_PICK_MULTI)
+				fputs(_(empty_cherry_pick_advice_multi), stderr);
+			else
+				fputs(_(empty_rebase_pick_advice), stderr);
+		}
+		return 0;
+	}
+
+	if (!no_verify && invoked_hook) {
+		/*
+		 * Re-read the index as the pre-commit-commit hook was invoked
+		 * and could have updated it. We must do this before we invoke
+		 * the editor and after we invoke run_status above.
+		 */
+		discard_index(the_repository->index);
+	}
+	read_index_from(the_repository->index, index_file, repo_get_git_dir(the_repository));
+
+	if (cache_tree_update(the_repository->index, 0)) {
+		error(_("Error building trees"));
+		return 0;
+	}
+
+	if (run_commit_hook(use_editor, index_file, NULL, "prepare-commit-msg",
+			    git_path_commit_editmsg(), hook_arg1, hook_arg2, NULL))
+		return 0;
+
+	if (use_editor) {
+		struct strvec env = STRVEC_INIT;
+
+		strvec_pushf(&env, "GIT_INDEX_FILE=%s", index_file);
+		if (launch_editor(git_path_commit_editmsg(), NULL, env.v)) {
+			fprintf(stderr,
+			_("Please supply the message using either -m or -F option.\n"));
+			exit(1);
+		}
+		strvec_clear(&env);
+	}
+
+	if (!no_verify &&
+	    run_commit_hook(use_editor, index_file, NULL, "commit-msg",
+			    git_path_commit_editmsg(), NULL)) {
+		return 0;
+	}
+
+	return 1;
+}
+
+static const char *find_author_by_nickname(const char *name)
+{
+	struct rev_info revs;
+	struct commit *commit;
+	struct strbuf buf = STRBUF_INIT;
+	const char *av[20];
+	int ac = 0;
+
+	repo_init_revisions(the_repository, &revs, NULL);
+	strbuf_addf(&buf, "--author=%s", name);
+	av[++ac] = "--all";
+	av[++ac] = "-i";
+	av[++ac] = buf.buf;
+	av[++ac] = NULL;
+	setup_revisions(ac, av, &revs, NULL);
+	revs.mailmap = xmalloc(sizeof(struct string_list));
+	string_list_init_nodup(revs.mailmap);
+	read_mailmap(revs.mailmap);
+
+	if (prepare_revision_walk(&revs))
+		die(_("revision walk setup failed"));
+	commit = get_revision(&revs);
+	if (commit) {
+		struct pretty_print_context ctx = {0};
+		ctx.date_mode.type = DATE_NORMAL;
+		strbuf_release(&buf);
+		repo_format_commit_message(the_repository, commit,
+					   "%aN <%aE>", &buf, &ctx);
+		release_revisions(&revs);
+		return strbuf_detach(&buf, NULL);
+	}
+	die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
+}
+
+static void handle_ignored_arg(struct wt_status *s)
+{
+	if (!ignored_arg)
+		; /* default already initialized */
+	else if (!strcmp(ignored_arg, "traditional"))
+		s->show_ignored_mode = SHOW_TRADITIONAL_IGNORED;
+	else if (!strcmp(ignored_arg, "no"))
+		s->show_ignored_mode = SHOW_NO_IGNORED;
+	else if (!strcmp(ignored_arg, "matching"))
+		s->show_ignored_mode = SHOW_MATCHING_IGNORED;
+	else
+		die(_("Invalid ignored mode '%s'"), ignored_arg);
+}
+
+static enum untracked_status_type parse_untracked_setting_name(const char *u)
+{
+	/*
+	 * Please update $__git_untracked_file_modes in
+	 * git-completion.bash when you add new options
+	 */
+	switch (git_parse_maybe_bool(u)) {
+	case 0:
+		u = "no";
+		break;
+	case 1:
+		u = "normal";
+		break;
+	default:
+		break;
+	}
+
+	if (!strcmp(u, "no"))
+		return SHOW_NO_UNTRACKED_FILES;
+	else if (!strcmp(u, "normal"))
+		return SHOW_NORMAL_UNTRACKED_FILES;
+	else if (!strcmp(u, "all"))
+		return SHOW_ALL_UNTRACKED_FILES;
+	else
+		return SHOW_UNTRACKED_FILES_ERROR;
+}
+
+static void handle_untracked_files_arg(struct wt_status *s)
+{
+	enum untracked_status_type u;
+
+	if (!untracked_files_arg)
+		return; /* default already initialized */
+
+	u = parse_untracked_setting_name(untracked_files_arg);
+	if (u == SHOW_UNTRACKED_FILES_ERROR)
+		die(_("Invalid untracked files mode '%s'"),
+		    untracked_files_arg);
+	s->show_untracked_files = u;
+}
+
+static const char *read_commit_message(const char *name)
+{
+	const char *out_enc;
+	struct commit *commit;
+
+	commit = lookup_commit_reference_by_name(name);
+	if (!commit)
+		die(_("could not lookup commit '%s'"), name);
+	out_enc = get_commit_output_encoding();
+	return repo_logmsg_reencode(the_repository, commit, NULL, out_enc);
+}
+
+/*
+ * Enumerate what needs to be propagated when --porcelain
+ * is not in effect here.
+ */
+static struct status_deferred_config {
+	enum wt_status_format status_format;
+	int show_branch;
+	enum ahead_behind_flags ahead_behind;
+} status_deferred_config = {
+	STATUS_FORMAT_UNSPECIFIED,
+	-1, /* unspecified */
+	AHEAD_BEHIND_UNSPECIFIED,
+};
+
+static void finalize_deferred_config(struct wt_status *s)
+{
+	int use_deferred_config = (status_format != STATUS_FORMAT_PORCELAIN &&
+				   status_format != STATUS_FORMAT_PORCELAIN_V2 &&
+				   !s->null_termination);
+
+	if (s->null_termination) {
+		if (status_format == STATUS_FORMAT_NONE ||
+		    status_format == STATUS_FORMAT_UNSPECIFIED)
+			status_format = STATUS_FORMAT_PORCELAIN;
+		else if (status_format == STATUS_FORMAT_LONG)
+			die(_("options '%s' and '%s' cannot be used together"), "--long", "-z");
+	}
+
+	if (use_deferred_config && status_format == STATUS_FORMAT_UNSPECIFIED)
+		status_format = status_deferred_config.status_format;
+	if (status_format == STATUS_FORMAT_UNSPECIFIED)
+		status_format = STATUS_FORMAT_NONE;
+
+	if (use_deferred_config && s->show_branch < 0)
+		s->show_branch = status_deferred_config.show_branch;
+	if (s->show_branch < 0)
+		s->show_branch = 0;
+
+	/*
+	 * If the user did not give a "--[no]-ahead-behind" command
+	 * line argument *AND* we will print in a human-readable format
+	 * (short, long etc.) then we inherit from the status.aheadbehind
+	 * config setting.  In all other cases (and porcelain V[12] formats
+	 * in particular), we inherit _FULL for backwards compatibility.
+	 */
+	if (use_deferred_config &&
+	    s->ahead_behind_flags == AHEAD_BEHIND_UNSPECIFIED)
+		s->ahead_behind_flags = status_deferred_config.ahead_behind;
+
+	if (s->ahead_behind_flags == AHEAD_BEHIND_UNSPECIFIED)
+		s->ahead_behind_flags = AHEAD_BEHIND_FULL;
+}
+
+static void check_fixup_reword_options(int argc, const char *argv[]) {
+	if (whence != FROM_COMMIT) {
+		if (whence == FROM_MERGE)
+			die(_("You are in the middle of a merge -- cannot reword."));
+		else if (is_from_cherry_pick(whence))
+			die(_("You are in the middle of a cherry-pick -- cannot reword."));
+	}
+	if (argc)
+		die(_("reword option of '%s' and path '%s' cannot be used together"), "--fixup", *argv);
+	if (patch_interactive || interactive || all || also || only)
+		die(_("reword option of '%s' and '%s' cannot be used together"),
+			"--fixup", "--patch/--interactive/--all/--include/--only");
+}
+
+static int parse_and_validate_options(int argc, const char *argv[],
+				      const struct option *options,
+				      const char * const usage[],
+				      const char *prefix,
+				      struct commit *current_head,
+				      struct wt_status *s)
+{
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+	finalize_deferred_config(s);
+
+	if (force_author && !strchr(force_author, '>'))
+		force_author = find_author_by_nickname(force_author);
+
+	if (force_author && renew_authorship)
+		die(_("options '%s' and '%s' cannot be used together"), "--reset-author", "--author");
+
+	if (logfile || have_option_m || use_message)
+		use_editor = 0;
+
+	/* Sanity check options */
+	if (amend && !current_head)
+		die(_("You have nothing to amend."));
+	if (amend && whence != FROM_COMMIT) {
+		if (whence == FROM_MERGE)
+			die(_("You are in the middle of a merge -- cannot amend."));
+		else if (is_from_cherry_pick(whence))
+			die(_("You are in the middle of a cherry-pick -- cannot amend."));
+		else if (whence == FROM_REBASE_PICK)
+			die(_("You are in the middle of a rebase -- cannot amend."));
+	}
+	if (fixup_message && squash_message)
+		die(_("options '%s' and '%s' cannot be used together"), "--squash", "--fixup");
+	die_for_incompatible_opt4(!!use_message, "-C",
+				  !!edit_message, "-c",
+				  !!logfile, "-F",
+				  !!fixup_message, "--fixup");
+	die_for_incompatible_opt4(have_option_m, "-m",
+				  !!edit_message, "-c",
+				  !!use_message, "-C",
+				  !!logfile, "-F");
+	if (use_message || edit_message || logfile ||fixup_message || have_option_m)
+		FREE_AND_NULL(template_file);
+	if (edit_message)
+		use_message = edit_message;
+	if (amend && !use_message && !fixup_message)
+		use_message = "HEAD";
+	if (!use_message && !is_from_cherry_pick(whence) &&
+	    !is_from_rebase(whence) && renew_authorship)
+		die(_("--reset-author can be used only with -C, -c or --amend."));
+	if (use_message) {
+		use_message_buffer = read_commit_message(use_message);
+		if (!renew_authorship) {
+			author_message = use_message;
+			author_message_buffer = use_message_buffer;
+		}
+	}
+	if ((is_from_cherry_pick(whence) || whence == FROM_REBASE_PICK) &&
+	    !renew_authorship) {
+		author_message = "CHERRY_PICK_HEAD";
+		author_message_buffer = read_commit_message(author_message);
+	}
+
+	if (patch_interactive)
+		interactive = 1;
+
+	die_for_incompatible_opt4(also, "-i/--include",
+				  only, "-o/--only",
+				  all, "-a/--all",
+				  interactive, "--interactive/-p/--patch");
+	if (fixup_message) {
+		/*
+		 * We limit --fixup's suboptions to only alpha characters.
+		 * If the first character after a run of alpha is colon,
+		 * then the part before the colon may be a known suboption
+		 * name like `amend` or `reword`, or a misspelt suboption
+		 * name. In either case, we treat it as
+		 * --fixup=<suboption>:<arg>.
+		 *
+		 * Otherwise, we are dealing with --fixup=<commit>.
+		 */
+		char *p = fixup_message;
+		while (isalpha(*p))
+			p++;
+		if (p > fixup_message && *p == ':') {
+			*p = '\0';
+			fixup_commit = p + 1;
+			if (!strcmp("amend", fixup_message) ||
+			    !strcmp("reword", fixup_message)) {
+				fixup_prefix = "amend";
+				allow_empty = 1;
+				if (*fixup_message == 'r') {
+					check_fixup_reword_options(argc, argv);
+					only = 1;
+				}
+			} else {
+				die(_("unknown option: --fixup=%s:%s"), fixup_message, fixup_commit);
+			}
+		} else {
+			fixup_commit = fixup_message;
+			fixup_prefix = "fixup";
+			use_editor = 0;
+		}
+	}
+
+	if (0 <= edit_flag)
+		use_editor = edit_flag;
+
+	handle_untracked_files_arg(s);
+
+	if (all && argc > 0)
+		die(_("paths '%s ...' with -a does not make sense"),
+		    argv[0]);
+
+	if (status_format != STATUS_FORMAT_NONE)
+		dry_run = 1;
+
+	return argc;
+}
+
+static int dry_run_commit(const char **argv, const char *prefix,
+			  const struct commit *current_head, struct wt_status *s)
+{
+	int committable;
+	const char *index_file;
+
+	index_file = prepare_index(argv, prefix, current_head, 1);
+	committable = run_status(stdout, index_file, prefix, 0, s);
+	rollback_index_files();
+
+	return committable ? 0 : 1;
+}
+
+define_list_config_array_extra(color_status_slots, {"added"});
+
+static int parse_status_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "added"))
+		return WT_STATUS_UPDATED;
+
+	return LOOKUP_CONFIG(color_status_slots, slot);
+}
+
+static int git_status_config(const char *k, const char *v,
+			     const struct config_context *ctx, void *cb)
+{
+	struct wt_status *s = cb;
+	const char *slot_name;
+
+	if (starts_with(k, "column."))
+		return git_column_config(k, v, "status", &s->colopts);
+	if (!strcmp(k, "status.submodulesummary")) {
+		int is_bool;
+		s->submodule_summary = git_config_bool_or_int(k, v, ctx->kvi,
+							      &is_bool);
+		if (is_bool && s->submodule_summary)
+			s->submodule_summary = -1;
+		return 0;
+	}
+	if (!strcmp(k, "status.short")) {
+		if (git_config_bool(k, v))
+			status_deferred_config.status_format = STATUS_FORMAT_SHORT;
+		else
+			status_deferred_config.status_format = STATUS_FORMAT_NONE;
+		return 0;
+	}
+	if (!strcmp(k, "status.branch")) {
+		status_deferred_config.show_branch = git_config_bool(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "status.aheadbehind")) {
+		status_deferred_config.ahead_behind = git_config_bool(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "status.showstash")) {
+		s->show_stash = git_config_bool(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "status.color") || !strcmp(k, "color.status")) {
+		s->use_color = git_config_colorbool(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "status.displaycommentprefix")) {
+		s->display_comment_prefix = git_config_bool(k, v);
+		return 0;
+	}
+	if (skip_prefix(k, "status.color.", &slot_name) ||
+	    skip_prefix(k, "color.status.", &slot_name)) {
+		int slot = parse_status_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!v)
+			return config_error_nonbool(k);
+		return color_parse(v, s->color_palette[slot]);
+	}
+	if (!strcmp(k, "status.relativepaths")) {
+		s->relative_paths = git_config_bool(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "status.showuntrackedfiles")) {
+		enum untracked_status_type u;
+
+		u = parse_untracked_setting_name(v);
+		if (u == SHOW_UNTRACKED_FILES_ERROR)
+			return error(_("Invalid untracked files mode '%s'"), v);
+		s->show_untracked_files = u;
+		return 0;
+	}
+	if (!strcmp(k, "diff.renamelimit")) {
+		if (s->rename_limit == -1)
+			s->rename_limit = git_config_int(k, v, ctx->kvi);
+		return 0;
+	}
+	if (!strcmp(k, "status.renamelimit")) {
+		s->rename_limit = git_config_int(k, v, ctx->kvi);
+		return 0;
+	}
+	if (!strcmp(k, "diff.renames")) {
+		if (s->detect_rename == -1)
+			s->detect_rename = git_config_rename(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "status.renames")) {
+		s->detect_rename = git_config_rename(k, v);
+		return 0;
+	}
+	return git_diff_ui_config(k, v, ctx, NULL);
+}
+
+int cmd_status(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
+{
+	static int no_renames = -1;
+	static const char *rename_score_arg = (const char *)-1;
+	static struct wt_status s;
+	unsigned int progress_flag = 0;
+	int fd;
+	struct object_id oid;
+	static struct option builtin_status_options[] = {
+		OPT__VERBOSE(&verbose, N_("be verbose")),
+		OPT_SET_INT('s', "short", &status_format,
+			    N_("show status concisely"), STATUS_FORMAT_SHORT),
+		OPT_BOOL('b', "branch", &s.show_branch,
+			 N_("show branch information")),
+		OPT_BOOL(0, "show-stash", &s.show_stash,
+			 N_("show stash information")),
+		OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
+			 N_("compute full ahead/behind values")),
+		OPT_CALLBACK_F(0, "porcelain", &status_format,
+		  N_("version"), N_("machine-readable output"),
+		  PARSE_OPT_OPTARG, opt_parse_porcelain),
+		OPT_SET_INT(0, "long", &status_format,
+			    N_("show status in long format (default)"),
+			    STATUS_FORMAT_LONG),
+		OPT_BOOL('z', "null", &s.null_termination,
+			 N_("terminate entries with NUL")),
+		{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg,
+		  N_("mode"),
+		  N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
+		  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+		{ OPTION_STRING, 0, "ignored", &ignored_arg,
+		  N_("mode"),
+		  N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"),
+		  PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" },
+		{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
+		  N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
+		  PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+		OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
+		OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")),
+		OPT_CALLBACK_F('M', "find-renames", &rename_score_arg,
+		  N_("n"), N_("detect renames, optionally set similarity index"),
+		  PARSE_OPT_OPTARG | PARSE_OPT_NONEG, opt_parse_rename_score),
+		OPT_END(),
+	};
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_status_usage, builtin_status_options);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	status_init_config(&s, git_status_config);
+	argc = parse_options(argc, argv, prefix,
+			     builtin_status_options,
+			     builtin_status_usage, 0);
+	finalize_colopts(&s.colopts, -1);
+	finalize_deferred_config(&s);
+
+	handle_untracked_files_arg(&s);
+	handle_ignored_arg(&s);
+
+	if (s.show_ignored_mode == SHOW_MATCHING_IGNORED &&
+	    s.show_untracked_files == SHOW_NO_UNTRACKED_FILES)
+		die(_("Unsupported combination of ignored and untracked-files arguments"));
+
+	parse_pathspec(&s.pathspec, 0,
+		       PATHSPEC_PREFER_FULL,
+		       prefix, argv);
+
+	if (status_format != STATUS_FORMAT_PORCELAIN &&
+	    status_format != STATUS_FORMAT_PORCELAIN_V2)
+		progress_flag = REFRESH_PROGRESS;
+	repo_read_index(the_repository);
+	refresh_index(the_repository->index,
+		      REFRESH_QUIET|REFRESH_UNMERGED|progress_flag,
+		      &s.pathspec, NULL, NULL);
+
+	if (use_optional_locks())
+		fd = repo_hold_locked_index(the_repository, &index_lock, 0);
+	else
+		fd = -1;
+
+	s.is_initial = repo_get_oid(the_repository, s.reference, &oid) ? 1 : 0;
+	if (!s.is_initial)
+		oidcpy(&s.oid_commit, &oid);
+
+	s.ignore_submodule_arg = ignore_submodule_arg;
+	s.status_format = status_format;
+	s.verbose = verbose;
+	if (no_renames != -1)
+		s.detect_rename = !no_renames;
+	if ((intptr_t)rename_score_arg != -1) {
+		if (s.detect_rename < DIFF_DETECT_RENAME)
+			s.detect_rename = DIFF_DETECT_RENAME;
+		if (rename_score_arg)
+			s.rename_score = parse_rename_score(&rename_score_arg);
+	}
+
+	wt_status_collect(&s);
+
+	if (0 <= fd)
+		repo_update_index_if_able(the_repository, &index_lock);
+
+	if (s.relative_paths)
+		s.prefix = prefix;
+
+	wt_status_print(&s);
+	wt_status_collect_free_buffers(&s);
+
+	return 0;
+}
+
+static int git_commit_config(const char *k, const char *v,
+			     const struct config_context *ctx, void *cb)
+{
+	struct wt_status *s = cb;
+
+	if (!strcmp(k, "commit.template"))
+		return git_config_pathname(&template_file, k, v);
+	if (!strcmp(k, "commit.status")) {
+		include_status = git_config_bool(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "commit.cleanup")) {
+		FREE_AND_NULL(cleanup_config);
+		return git_config_string(&cleanup_config, k, v);
+	}
+	if (!strcmp(k, "commit.gpgsign")) {
+		sign_commit = git_config_bool(k, v) ? "" : NULL;
+		return 0;
+	}
+	if (!strcmp(k, "commit.verbose")) {
+		int is_bool;
+		config_commit_verbose = git_config_bool_or_int(k, v, ctx->kvi,
+							       &is_bool);
+		return 0;
+	}
+
+	return git_status_config(k, v, ctx, s);
+}
+
+int cmd_commit(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	static struct wt_status s;
+	static const char *cleanup_arg = NULL;
+	static struct option builtin_commit_options[] = {
+		OPT__QUIET(&quiet, N_("suppress summary after successful commit")),
+		OPT__VERBOSE(&verbose, N_("show diff in commit message template")),
+
+		OPT_GROUP(N_("Commit message options")),
+		OPT_FILENAME('F', "file", &logfile, N_("read message from file")),
+		OPT_STRING(0, "author", &force_author, N_("author"), N_("override author for commit")),
+		OPT_STRING(0, "date", &force_date, N_("date"), N_("override date for commit")),
+		OPT_CALLBACK('m', "message", &message, N_("message"), N_("commit message"), opt_parse_m),
+		OPT_STRING('c', "reedit-message", &edit_message, N_("commit"), N_("reuse and edit message from specified commit")),
+		OPT_STRING('C', "reuse-message", &use_message, N_("commit"), N_("reuse message from specified commit")),
+		/*
+		 * TRANSLATORS: Leave "[(amend|reword):]" as-is,
+		 * and only translate <commit>.
+		 */
+		OPT_STRING(0, "fixup", &fixup_message, N_("[(amend|reword):]commit"), N_("use autosquash formatted message to fixup or amend/reword specified commit")),
+		OPT_STRING(0, "squash", &squash_message, N_("commit"), N_("use autosquash formatted message to squash specified commit")),
+		OPT_BOOL(0, "reset-author", &renew_authorship, N_("the commit is authored by me now (used with -C/-c/--amend)")),
+		OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"), N_("add custom trailer(s)"), PARSE_OPT_NONEG),
+		OPT_BOOL('s', "signoff", &signoff, N_("add a Signed-off-by trailer")),
+		OPT_FILENAME('t', "template", &template_file, N_("use specified template file")),
+		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of commit")),
+		OPT_CLEANUP(&cleanup_arg),
+		OPT_BOOL(0, "status", &include_status, N_("include status in commit message template")),
+		{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
+		  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+		/* end commit message options */
+
+		OPT_GROUP(N_("Commit contents options")),
+		OPT_BOOL('a', "all", &all, N_("commit all changed files")),
+		OPT_BOOL('i', "include", &also, N_("add specified files to index for commit")),
+		OPT_BOOL(0, "interactive", &interactive, N_("interactively add files")),
+		OPT_BOOL('p', "patch", &patch_interactive, N_("interactively add changes")),
+		OPT_BOOL('o', "only", &only, N_("commit only specified files")),
+		OPT_BOOL('n', "no-verify", &no_verify, N_("bypass pre-commit and commit-msg hooks")),
+		OPT_BOOL(0, "dry-run", &dry_run, N_("show what would be committed")),
+		OPT_SET_INT(0, "short", &status_format, N_("show status concisely"),
+			    STATUS_FORMAT_SHORT),
+		OPT_BOOL(0, "branch", &s.show_branch, N_("show branch information")),
+		OPT_BOOL(0, "ahead-behind", &s.ahead_behind_flags,
+			 N_("compute full ahead/behind values")),
+		OPT_SET_INT(0, "porcelain", &status_format,
+			    N_("machine-readable output"), STATUS_FORMAT_PORCELAIN),
+		OPT_SET_INT(0, "long", &status_format,
+			    N_("show status in long format (default)"),
+			    STATUS_FORMAT_LONG),
+		OPT_BOOL('z', "null", &s.null_termination,
+			 N_("terminate entries with NUL")),
+		OPT_BOOL(0, "amend", &amend, N_("amend previous commit")),
+		OPT_BOOL(0, "no-post-rewrite", &no_post_rewrite, N_("bypass post-rewrite hook")),
+		{ OPTION_STRING, 'u', "untracked-files", &untracked_files_arg, N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
+		OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+		OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
+		/* end commit contents options */
+
+		OPT_HIDDEN_BOOL(0, "allow-empty", &allow_empty,
+				N_("ok to record an empty change")),
+		OPT_HIDDEN_BOOL(0, "allow-empty-message", &allow_empty_message,
+				N_("ok to record a change with an empty message")),
+
+		OPT_END()
+	};
+
+	struct strbuf sb = STRBUF_INIT;
+	struct strbuf author_ident = STRBUF_INIT;
+	const char *index_file, *reflog_msg;
+	struct object_id oid;
+	struct commit_list *parents = NULL;
+	struct stat statbuf;
+	struct commit *current_head = NULL;
+	struct commit_extra_header *extra = NULL;
+	struct strbuf err = STRBUF_INIT;
+	int ret = 0;
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_commit_usage, builtin_commit_options);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	status_init_config(&s, git_commit_config);
+	s.commit_template = 1;
+	status_format = STATUS_FORMAT_NONE; /* Ignore status.short */
+	s.colopts = 0;
+
+	if (repo_get_oid(the_repository, "HEAD", &oid))
+		current_head = NULL;
+	else {
+		current_head = lookup_commit_or_die(&oid, "HEAD");
+		if (repo_parse_commit(the_repository, current_head))
+			die(_("could not parse HEAD commit"));
+	}
+	verbose = -1; /* unspecified */
+	argc = parse_and_validate_options(argc, argv, builtin_commit_options,
+					  builtin_commit_usage,
+					  prefix, current_head, &s);
+	if (verbose == -1)
+		verbose = (config_commit_verbose < 0) ? 0 : config_commit_verbose;
+
+	if (cleanup_arg) {
+		free(cleanup_config);
+		cleanup_config = xstrdup(cleanup_arg);
+	}
+	cleanup_mode = get_cleanup_mode(cleanup_config, use_editor);
+
+	if (dry_run)
+		return dry_run_commit(argv, prefix, current_head, &s);
+	index_file = prepare_index(argv, prefix, current_head, 0);
+
+	/* Set up everything for writing the commit object.  This includes
+	   running hooks, writing the trees, and interacting with the user.  */
+	if (!prepare_to_commit(index_file, prefix,
+			       current_head, &s, &author_ident)) {
+		ret = 1;
+		rollback_index_files();
+		goto cleanup;
+	}
+
+	/* Determine parents */
+	reflog_msg = getenv("GIT_REFLOG_ACTION");
+	if (!current_head) {
+		if (!reflog_msg)
+			reflog_msg = "commit (initial)";
+	} else if (amend) {
+		if (!reflog_msg)
+			reflog_msg = "commit (amend)";
+		parents = copy_commit_list(current_head->parents);
+	} else if (whence == FROM_MERGE) {
+		struct strbuf m = STRBUF_INIT;
+		FILE *fp;
+		int allow_fast_forward = 1;
+		struct commit_list **pptr = &parents;
+
+		if (!reflog_msg)
+			reflog_msg = "commit (merge)";
+		pptr = commit_list_append(current_head, pptr);
+		fp = xfopen(git_path_merge_head(the_repository), "r");
+		while (strbuf_getline_lf(&m, fp) != EOF) {
+			struct commit *parent;
+
+			parent = get_merge_parent(m.buf);
+			if (!parent)
+				die(_("Corrupt MERGE_HEAD file (%s)"), m.buf);
+			pptr = commit_list_append(parent, pptr);
+		}
+		fclose(fp);
+		strbuf_release(&m);
+		if (!stat(git_path_merge_mode(the_repository), &statbuf)) {
+			if (strbuf_read_file(&sb, git_path_merge_mode(the_repository), 0) < 0)
+				die_errno(_("could not read MERGE_MODE"));
+			if (!strcmp(sb.buf, "no-ff"))
+				allow_fast_forward = 0;
+		}
+		if (allow_fast_forward)
+			reduce_heads_replace(&parents);
+	} else {
+		if (!reflog_msg)
+			reflog_msg = is_from_cherry_pick(whence)
+					? "commit (cherry-pick)"
+					: is_from_rebase(whence)
+					? "commit (rebase)"
+					: "commit";
+		commit_list_insert(current_head, &parents);
+	}
+
+	/* Finally, get the commit message */
+	strbuf_reset(&sb);
+	if (strbuf_read_file(&sb, git_path_commit_editmsg(), 0) < 0) {
+		int saved_errno = errno;
+		rollback_index_files();
+		die(_("could not read commit message: %s"), strerror(saved_errno));
+	}
+
+	cleanup_message(&sb, cleanup_mode, verbose);
+
+	if (message_is_empty(&sb, cleanup_mode) && !allow_empty_message) {
+		rollback_index_files();
+		fprintf(stderr, _("Aborting commit due to empty commit message.\n"));
+		exit(1);
+	}
+	if (template_untouched(&sb, template_file, cleanup_mode) && !allow_empty_message) {
+		rollback_index_files();
+		fprintf(stderr, _("Aborting commit; you did not edit the message.\n"));
+		exit(1);
+	}
+
+	if (fixup_message && starts_with(sb.buf, "amend! ") &&
+	    !allow_empty_message) {
+		struct strbuf body = STRBUF_INIT;
+		size_t len = commit_subject_length(sb.buf);
+		strbuf_addstr(&body, sb.buf + len);
+		if (message_is_empty(&body, cleanup_mode)) {
+			rollback_index_files();
+			fprintf(stderr, _("Aborting commit due to empty commit message body.\n"));
+			exit(1);
+		}
+		strbuf_release(&body);
+	}
+
+	if (amend) {
+		const char *exclude_gpgsig[3] = { "gpgsig", "gpgsig-sha256", NULL };
+		extra = read_commit_extra_headers(current_head, exclude_gpgsig);
+	} else {
+		struct commit_extra_header **tail = &extra;
+		append_merge_tag_headers(parents, &tail);
+	}
+
+	if (commit_tree_extended(sb.buf, sb.len, &the_repository->index->cache_tree->oid,
+				 parents, &oid, author_ident.buf, NULL,
+				 sign_commit, extra)) {
+		rollback_index_files();
+		die(_("failed to write commit object"));
+	}
+
+	if (update_head_with_reflog(current_head, &oid, reflog_msg, &sb,
+				    &err)) {
+		rollback_index_files();
+		die("%s", err.buf);
+	}
+
+	sequencer_post_commit_cleanup(the_repository, 0);
+	unlink(git_path_merge_head(the_repository));
+	unlink(git_path_merge_msg(the_repository));
+	unlink(git_path_merge_mode(the_repository));
+	unlink(git_path_squash_msg(the_repository));
+
+	if (commit_index_files())
+		die(_("repository has been updated, but unable to write\n"
+		      "new index file. Check that disk is not full and quota is\n"
+		      "not exceeded, and then \"git restore --staged :/\" to recover."));
+
+	git_test_write_commit_graph_or_die();
+
+	repo_rerere(the_repository, 0);
+	run_auto_maintenance(quiet);
+	run_commit_hook(use_editor, repo_get_index_file(the_repository),
+			NULL, "post-commit", NULL);
+	if (amend && !no_post_rewrite) {
+		commit_post_rewrite(the_repository, current_head, &oid);
+	}
+	if (!quiet) {
+		unsigned int flags = 0;
+
+		if (!current_head)
+			flags |= SUMMARY_INITIAL_COMMIT;
+		if (author_date_is_interesting())
+			flags |= SUMMARY_SHOW_AUTHOR_DATE;
+		print_commit_summary(the_repository, prefix,
+				     &oid, flags);
+	}
+
+	apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
+
+cleanup:
+	free_commit_extra_headers(extra);
+	free_commit_list(parents);
+	strbuf_release(&author_ident);
+	strbuf_release(&err);
+	strbuf_release(&sb);
+	free(logfile);
+	free(template_file);
+	return ret;
+}
diff --git a/builtin/config.c b/builtin/config.c
new file mode 100644
index 0000000000..16e6e30555
--- /dev/null
+++ b/builtin/config.c
@@ -0,0 +1,1436 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "color.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "ident.h"
+#include "parse-options.h"
+#include "urlmatch.h"
+#include "path.h"
+#include "quote.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "worktree.h"
+
+static const char *const builtin_config_usage[] = {
+	N_("git config list [<file-option>] [<display-option>] [--includes]"),
+	N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+	N_("git config set [<file-option>] [--type=<type>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+	N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
+	N_("git config rename-section [<file-option>] <old-name> <new-name>"),
+	N_("git config remove-section [<file-option>] <name>"),
+	N_("git config edit [<file-option>]"),
+	N_("git config [<file-option>] --get-colorbool <name> [<stdout-is-tty>]"),
+	NULL
+};
+
+static const char *const builtin_config_list_usage[] = {
+	N_("git config list [<file-option>] [<display-option>] [--includes]"),
+	NULL
+};
+
+static const char *const builtin_config_get_usage[] = {
+	N_("git config get [<file-option>] [<display-option>] [--includes] [--all] [--regexp=<regexp>] [--value=<value>] [--fixed-value] [--default=<default>] <name>"),
+	NULL
+};
+
+static const char *const builtin_config_set_usage[] = {
+	N_("git config set [<file-option>] [--type=<type>] [--comment=<message>] [--all] [--value=<value>] [--fixed-value] <name> <value>"),
+	NULL
+};
+
+static const char *const builtin_config_unset_usage[] = {
+	N_("git config unset [<file-option>] [--all] [--value=<value>] [--fixed-value] <name>"),
+	NULL
+};
+
+static const char *const builtin_config_rename_section_usage[] = {
+	N_("git config rename-section [<file-option>] <old-name> <new-name>"),
+	NULL
+};
+
+static const char *const builtin_config_remove_section_usage[] = {
+	N_("git config remove-section [<file-option>] <name>"),
+	NULL
+};
+
+static const char *const builtin_config_edit_usage[] = {
+	N_("git config edit [<file-option>]"),
+	NULL
+};
+
+#define CONFIG_LOCATION_OPTIONS(opts) \
+	OPT_GROUP(N_("Config file location")), \
+	OPT_BOOL(0, "global", &opts.use_global_config, N_("use global config file")), \
+	OPT_BOOL(0, "system", &opts.use_system_config, N_("use system config file")), \
+	OPT_BOOL(0, "local", &opts.use_local_config, N_("use repository config file")), \
+	OPT_BOOL(0, "worktree", &opts.use_worktree_config, N_("use per-worktree config file")), \
+	OPT_STRING('f', "file", &opts.source.file, N_("file"), N_("use given config file")), \
+	OPT_STRING(0, "blob", &opts.source.blob, N_("blob-id"), N_("read config from given blob object"))
+
+struct config_location_options {
+	struct git_config_source source;
+	struct config_options options;
+	char *file_to_free;
+	int use_global_config;
+	int use_system_config;
+	int use_local_config;
+	int use_worktree_config;
+	int respect_includes_opt;
+};
+#define CONFIG_LOCATION_OPTIONS_INIT { \
+	.respect_includes_opt = -1, \
+}
+
+#define CONFIG_TYPE_OPTIONS(type) \
+	OPT_GROUP(N_("Type")), \
+	OPT_CALLBACK('t', "type", &type, N_("type"), N_("value is given this type"), option_parse_type), \
+	OPT_CALLBACK_VALUE(0, "bool", &type, N_("value is \"true\" or \"false\""), TYPE_BOOL), \
+	OPT_CALLBACK_VALUE(0, "int", &type, N_("value is decimal number"), TYPE_INT), \
+	OPT_CALLBACK_VALUE(0, "bool-or-int", &type, N_("value is --bool or --int"), TYPE_BOOL_OR_INT), \
+	OPT_CALLBACK_VALUE(0, "bool-or-str", &type, N_("value is --bool or string"), TYPE_BOOL_OR_STR), \
+	OPT_CALLBACK_VALUE(0, "path", &type, N_("value is a path (file or directory name)"), TYPE_PATH), \
+	OPT_CALLBACK_VALUE(0, "expiry-date", &type, N_("value is an expiry date"), TYPE_EXPIRY_DATE)
+
+#define CONFIG_DISPLAY_OPTIONS(opts) \
+	OPT_GROUP(N_("Display options")), \
+	OPT_BOOL('z', "null", &opts.end_nul, N_("terminate values with NUL byte")), \
+	OPT_BOOL(0, "name-only", &opts.omit_values, N_("show variable names only")), \
+	OPT_BOOL(0, "show-origin", &opts.show_origin, N_("show origin of config (file, standard input, blob, command line)")), \
+	OPT_BOOL(0, "show-scope", &opts.show_scope, N_("show scope of config (worktree, local, global, system, command)")), \
+	OPT_BOOL(0, "show-names", &opts.show_keys, N_("show config keys in addition to their values")), \
+	CONFIG_TYPE_OPTIONS(opts.type)
+
+struct config_display_options {
+	int end_nul;
+	int omit_values;
+	int show_origin;
+	int show_scope;
+	int show_keys;
+	int type;
+	char *default_value;
+	/* Populated via `display_options_init()`. */
+	int term;
+	int delim;
+	int key_delim;
+};
+#define CONFIG_DISPLAY_OPTIONS_INIT { \
+	.term = '\n', \
+	.delim = '=', \
+	.key_delim = ' ', \
+}
+
+#define TYPE_BOOL		1
+#define TYPE_INT		2
+#define TYPE_BOOL_OR_INT	3
+#define TYPE_PATH		4
+#define TYPE_EXPIRY_DATE	5
+#define TYPE_COLOR		6
+#define TYPE_BOOL_OR_STR	7
+
+#define OPT_CALLBACK_VALUE(s, l, v, h, i) \
+	{ OPTION_CALLBACK, (s), (l), (v), NULL, (h), PARSE_OPT_NOARG | \
+	PARSE_OPT_NONEG, option_parse_type, (i) }
+
+static int option_parse_type(const struct option *opt, const char *arg,
+			     int unset)
+{
+	int new_type, *to_type;
+
+	if (unset) {
+		*((int *) opt->value) = 0;
+		return 0;
+	}
+
+	/*
+	 * To support '--<type>' style flags, begin with new_type equal to
+	 * opt->defval.
+	 */
+	new_type = opt->defval;
+	if (!new_type) {
+		if (!strcmp(arg, "bool"))
+			new_type = TYPE_BOOL;
+		else if (!strcmp(arg, "int"))
+			new_type = TYPE_INT;
+		else if (!strcmp(arg, "bool-or-int"))
+			new_type = TYPE_BOOL_OR_INT;
+		else if (!strcmp(arg, "bool-or-str"))
+			new_type = TYPE_BOOL_OR_STR;
+		else if (!strcmp(arg, "path"))
+			new_type = TYPE_PATH;
+		else if (!strcmp(arg, "expiry-date"))
+			new_type = TYPE_EXPIRY_DATE;
+		else if (!strcmp(arg, "color"))
+			new_type = TYPE_COLOR;
+		else
+			die(_("unrecognized --type argument, %s"), arg);
+	}
+
+	to_type = opt->value;
+	if (*to_type && *to_type != new_type) {
+		/*
+		 * Complain when there is a new type not equal to the old type.
+		 * This allows for combinations like '--int --type=int' and
+		 * '--type=int --type=int', but disallows ones like '--type=bool
+		 * --int' and '--type=bool
+		 * --type=int'.
+		 */
+		error(_("only one type at a time"));
+		exit(129);
+	}
+	*to_type = new_type;
+
+	return 0;
+}
+
+static void check_argc(int argc, int min, int max)
+{
+	if (argc >= min && argc <= max)
+		return;
+	if (min == max)
+		error(_("wrong number of arguments, should be %d"), min);
+	else
+		error(_("wrong number of arguments, should be from %d to %d"),
+		      min, max);
+	exit(129);
+}
+
+static void show_config_origin(const struct config_display_options *opts,
+			       const struct key_value_info *kvi,
+			       struct strbuf *buf)
+{
+	const char term = opts->end_nul ? '\0' : '\t';
+
+	strbuf_addstr(buf, config_origin_type_name(kvi->origin_type));
+	strbuf_addch(buf, ':');
+	if (opts->end_nul)
+		strbuf_addstr(buf, kvi->filename ? kvi->filename : "");
+	else
+		quote_c_style(kvi->filename ? kvi->filename : "", buf, NULL, 0);
+	strbuf_addch(buf, term);
+}
+
+static void show_config_scope(const struct config_display_options *opts,
+			      const struct key_value_info *kvi,
+			      struct strbuf *buf)
+{
+	const char term = opts->end_nul ? '\0' : '\t';
+	const char *scope = config_scope_name(kvi->scope);
+
+	strbuf_addstr(buf, N_(scope));
+	strbuf_addch(buf, term);
+}
+
+static int show_all_config(const char *key_, const char *value_,
+			   const struct config_context *ctx,
+			   void *cb)
+{
+	const struct config_display_options *opts = cb;
+	const struct key_value_info *kvi = ctx->kvi;
+
+	if (opts->show_origin || opts->show_scope) {
+		struct strbuf buf = STRBUF_INIT;
+		if (opts->show_scope)
+			show_config_scope(opts, kvi, &buf);
+		if (opts->show_origin)
+			show_config_origin(opts, kvi, &buf);
+		/* Use fwrite as "buf" can contain \0's if "end_null" is set. */
+		fwrite(buf.buf, 1, buf.len, stdout);
+		strbuf_release(&buf);
+	}
+	if (!opts->omit_values && value_)
+		printf("%s%c%s%c", key_, opts->delim, value_, opts->term);
+	else
+		printf("%s%c", key_, opts->term);
+	return 0;
+}
+
+struct strbuf_list {
+	struct strbuf *items;
+	int nr;
+	int alloc;
+};
+
+static int format_config(const struct config_display_options *opts,
+			 struct strbuf *buf, const char *key_,
+			 const char *value_, const struct key_value_info *kvi)
+{
+	if (opts->show_scope)
+		show_config_scope(opts, kvi, buf);
+	if (opts->show_origin)
+		show_config_origin(opts, kvi, buf);
+	if (opts->show_keys)
+		strbuf_addstr(buf, key_);
+	if (!opts->omit_values) {
+		if (opts->show_keys)
+			strbuf_addch(buf, opts->key_delim);
+
+		if (opts->type == TYPE_INT)
+			strbuf_addf(buf, "%"PRId64,
+				    git_config_int64(key_, value_ ? value_ : "", kvi));
+		else if (opts->type == TYPE_BOOL)
+			strbuf_addstr(buf, git_config_bool(key_, value_) ?
+				      "true" : "false");
+		else if (opts->type == TYPE_BOOL_OR_INT) {
+			int is_bool, v;
+			v = git_config_bool_or_int(key_, value_, kvi,
+						   &is_bool);
+			if (is_bool)
+				strbuf_addstr(buf, v ? "true" : "false");
+			else
+				strbuf_addf(buf, "%d", v);
+		} else if (opts->type == TYPE_BOOL_OR_STR) {
+			int v = git_parse_maybe_bool(value_);
+			if (v < 0)
+				strbuf_addstr(buf, value_);
+			else
+				strbuf_addstr(buf, v ? "true" : "false");
+		} else if (opts->type == TYPE_PATH) {
+			char *v;
+			if (git_config_pathname(&v, key_, value_) < 0)
+				return -1;
+			strbuf_addstr(buf, v);
+			free((char *)v);
+		} else if (opts->type == TYPE_EXPIRY_DATE) {
+			timestamp_t t;
+			if (git_config_expiry_date(&t, key_, value_) < 0)
+				return -1;
+			strbuf_addf(buf, "%"PRItime, t);
+		} else if (opts->type == TYPE_COLOR) {
+			char v[COLOR_MAXLEN];
+			if (git_config_color(v, key_, value_) < 0)
+				return -1;
+			strbuf_addstr(buf, v);
+		} else if (value_) {
+			strbuf_addstr(buf, value_);
+		} else {
+			/* Just show the key name; back out delimiter */
+			if (opts->show_keys)
+				strbuf_setlen(buf, buf->len - 1);
+		}
+	}
+	strbuf_addch(buf, opts->term);
+	return 0;
+}
+
+#define GET_VALUE_ALL        (1 << 0)
+#define GET_VALUE_KEY_REGEXP (1 << 1)
+
+struct collect_config_data {
+	const struct config_display_options *display_opts;
+	struct strbuf_list *values;
+	const char *value_pattern;
+	const char *key;
+	regex_t *regexp;
+	regex_t *key_regexp;
+	int do_not_match;
+	unsigned get_value_flags;
+	unsigned flags;
+};
+
+static int collect_config(const char *key_, const char *value_,
+			  const struct config_context *ctx, void *cb)
+{
+	struct collect_config_data *data = cb;
+	struct strbuf_list *values = data->values;
+	const struct key_value_info *kvi = ctx->kvi;
+
+	if (!(data->get_value_flags & GET_VALUE_KEY_REGEXP) &&
+	    strcmp(key_, data->key))
+		return 0;
+	if ((data->get_value_flags & GET_VALUE_KEY_REGEXP) &&
+	    regexec(data->key_regexp, key_, 0, NULL, 0))
+		return 0;
+	if ((data->flags & CONFIG_FLAGS_FIXED_VALUE) &&
+	    strcmp(data->value_pattern, (value_?value_:"")))
+		return 0;
+	if (data->regexp &&
+	    (data->do_not_match ^ !!regexec(data->regexp, (value_?value_:""), 0, NULL, 0)))
+		return 0;
+
+	ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+	strbuf_init(&values->items[values->nr], 0);
+
+	return format_config(data->display_opts, &values->items[values->nr++],
+			     key_, value_, kvi);
+}
+
+static int get_value(const struct config_location_options *opts,
+		     const struct config_display_options *display_opts,
+		     const char *key_, const char *regex_,
+		     unsigned get_value_flags, unsigned flags)
+{
+	int ret = CONFIG_GENERIC_ERROR;
+	struct strbuf_list values = {NULL};
+	struct collect_config_data data = {
+		.display_opts = display_opts,
+		.values = &values,
+		.get_value_flags = get_value_flags,
+		.flags = flags,
+	};
+	char *key = NULL;
+	int i;
+
+	if (get_value_flags & GET_VALUE_KEY_REGEXP) {
+		char *tl;
+
+		/*
+		 * NEEDSWORK: this naive pattern lowercasing obviously does not
+		 * work for more complex patterns like "^[^.]*Foo.*bar".
+		 * Perhaps we should deprecate this altogether someday.
+		 */
+
+		key = xstrdup(key_);
+		for (tl = key + strlen(key) - 1;
+		     tl >= key && *tl != '.';
+		     tl--)
+			*tl = tolower(*tl);
+		for (tl = key; *tl && *tl != '.'; tl++)
+			*tl = tolower(*tl);
+
+		data.key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
+		if (regcomp(data.key_regexp, key, REG_EXTENDED)) {
+			error(_("invalid key pattern: %s"), key_);
+			FREE_AND_NULL(data.key_regexp);
+			ret = CONFIG_INVALID_PATTERN;
+			goto free_strings;
+		}
+	} else {
+		if (git_config_parse_key(key_, &key, NULL)) {
+			ret = CONFIG_INVALID_KEY;
+			goto free_strings;
+		}
+
+		data.key = key;
+	}
+
+	if (regex_ && (flags & CONFIG_FLAGS_FIXED_VALUE))
+		data.value_pattern = regex_;
+	else if (regex_) {
+		if (regex_[0] == '!') {
+			data.do_not_match = 1;
+			regex_++;
+		}
+
+		data.regexp = (regex_t*)xmalloc(sizeof(regex_t));
+		if (regcomp(data.regexp, regex_, REG_EXTENDED)) {
+			error(_("invalid pattern: %s"), regex_);
+			FREE_AND_NULL(data.regexp);
+			ret = CONFIG_INVALID_PATTERN;
+			goto free_strings;
+		}
+	}
+
+	config_with_options(collect_config, &data,
+			    &opts->source, the_repository,
+			    &opts->options);
+
+	if (!values.nr && display_opts->default_value) {
+		struct key_value_info kvi = KVI_INIT;
+		struct strbuf *item;
+
+		kvi_from_param(&kvi);
+		ALLOC_GROW(values.items, values.nr + 1, values.alloc);
+		item = &values.items[values.nr++];
+		strbuf_init(item, 0);
+		if (format_config(display_opts, item, key_,
+				  display_opts->default_value, &kvi) < 0)
+			die(_("failed to format default config value: %s"),
+			    display_opts->default_value);
+	}
+
+	ret = !values.nr;
+
+	for (i = 0; i < values.nr; i++) {
+		struct strbuf *buf = values.items + i;
+		if ((get_value_flags & GET_VALUE_ALL) || i == values.nr - 1)
+			fwrite(buf->buf, 1, buf->len, stdout);
+		strbuf_release(buf);
+	}
+	free(values.items);
+
+free_strings:
+	free(key);
+	if (data.key_regexp) {
+		regfree(data.key_regexp);
+		free(data.key_regexp);
+	}
+	if (data.regexp) {
+		regfree(data.regexp);
+		free(data.regexp);
+	}
+
+	return ret;
+}
+
+static char *normalize_value(const char *key, const char *value,
+			     int type, struct key_value_info *kvi)
+{
+	if (!value)
+		return NULL;
+
+	if (type == 0 || type == TYPE_PATH || type == TYPE_EXPIRY_DATE)
+		/*
+		 * We don't do normalization for TYPE_PATH here: If
+		 * the path is like ~/foobar/, we prefer to store
+		 * "~/foobar/" in the config file, and to expand the ~
+		 * when retrieving the value.
+		 * Also don't do normalization for expiry dates.
+		 */
+		return xstrdup(value);
+	if (type == TYPE_INT)
+		return xstrfmt("%"PRId64, git_config_int64(key, value, kvi));
+	if (type == TYPE_BOOL)
+		return xstrdup(git_config_bool(key, value) ?  "true" : "false");
+	if (type == TYPE_BOOL_OR_INT) {
+		int is_bool, v;
+		v = git_config_bool_or_int(key, value, kvi, &is_bool);
+		if (!is_bool)
+			return xstrfmt("%d", v);
+		else
+			return xstrdup(v ? "true" : "false");
+	}
+	if (type == TYPE_BOOL_OR_STR) {
+		int v = git_parse_maybe_bool(value);
+		if (v < 0)
+			return xstrdup(value);
+		else
+			return xstrdup(v ? "true" : "false");
+	}
+	if (type == TYPE_COLOR) {
+		char v[COLOR_MAXLEN];
+		if (git_config_color(v, key, value))
+			die(_("cannot parse color '%s'"), value);
+
+		/*
+		 * The contents of `v` now contain an ANSI escape
+		 * sequence, not suitable for including within a
+		 * configuration file. Treat the above as a
+		 * "sanity-check", and return the given value, which we
+		 * know is representable as valid color code.
+		 */
+		return xstrdup(value);
+	}
+
+	BUG("cannot normalize type %d", type);
+}
+
+struct get_color_config_data {
+	int get_color_found;
+	const char *get_color_slot;
+	char parsed_color[COLOR_MAXLEN];
+};
+
+static int git_get_color_config(const char *var, const char *value,
+				const struct config_context *ctx UNUSED,
+				void *cb)
+{
+	struct get_color_config_data *data = cb;
+
+	if (!strcmp(var, data->get_color_slot)) {
+		if (!value)
+			config_error_nonbool(var);
+		if (color_parse(value, data->parsed_color) < 0)
+			return -1;
+		data->get_color_found = 1;
+	}
+	return 0;
+}
+
+static void get_color(const struct config_location_options *opts,
+		      const char *var, const char *def_color)
+{
+	struct get_color_config_data data = {
+		.get_color_slot = var,
+		.parsed_color[0] = '\0',
+	};
+
+	config_with_options(git_get_color_config, &data,
+			    &opts->source, the_repository,
+			    &opts->options);
+
+	if (!data.get_color_found && def_color) {
+		if (color_parse(def_color, data.parsed_color) < 0)
+			die(_("unable to parse default color value"));
+	}
+
+	fputs(data.parsed_color, stdout);
+}
+
+struct get_colorbool_config_data {
+	int get_colorbool_found;
+	int get_diff_color_found;
+	int get_color_ui_found;
+	const char *get_colorbool_slot;
+};
+
+static int git_get_colorbool_config(const char *var, const char *value,
+				    const struct config_context *ctx UNUSED,
+				    void *cb)
+{
+	struct get_colorbool_config_data *data = cb;
+
+	if (!strcmp(var, data->get_colorbool_slot))
+		data->get_colorbool_found = git_config_colorbool(var, value);
+	else if (!strcmp(var, "diff.color"))
+		data->get_diff_color_found = git_config_colorbool(var, value);
+	else if (!strcmp(var, "color.ui"))
+		data->get_color_ui_found = git_config_colorbool(var, value);
+	return 0;
+}
+
+static int get_colorbool(const struct config_location_options *opts,
+			 const char *var, int print)
+{
+	struct get_colorbool_config_data data = {
+		.get_colorbool_slot = var,
+		.get_colorbool_found = -1,
+		.get_diff_color_found = -1,
+		.get_color_ui_found = -1,
+	};
+
+	config_with_options(git_get_colorbool_config, &data,
+			    &opts->source, the_repository,
+			    &opts->options);
+
+	if (data.get_colorbool_found < 0) {
+		if (!strcmp(data.get_colorbool_slot, "color.diff"))
+			data.get_colorbool_found = data.get_diff_color_found;
+		if (data.get_colorbool_found < 0)
+			data.get_colorbool_found = data.get_color_ui_found;
+	}
+
+	if (data.get_colorbool_found < 0)
+		/* default value if none found in config */
+		data.get_colorbool_found = GIT_COLOR_AUTO;
+
+	data.get_colorbool_found = want_color(data.get_colorbool_found);
+
+	if (print) {
+		printf("%s\n", data.get_colorbool_found ? "true" : "false");
+		return 0;
+	} else
+		return data.get_colorbool_found ? 0 : 1;
+}
+
+static void check_write(const struct git_config_source *source)
+{
+	if (!source->file && !startup_info->have_repository)
+		die(_("not in a git directory"));
+
+	if (source->use_stdin)
+		die(_("writing to stdin is not supported"));
+
+	if (source->blob)
+		die(_("writing config blobs is not supported"));
+}
+
+struct urlmatch_current_candidate_value {
+	char value_is_null;
+	struct strbuf value;
+	struct key_value_info kvi;
+};
+
+static int urlmatch_collect_fn(const char *var, const char *value,
+			       const struct config_context *ctx,
+			       void *cb)
+{
+	struct string_list *values = cb;
+	struct string_list_item *item = string_list_insert(values, var);
+	struct urlmatch_current_candidate_value *matched = item->util;
+	const struct key_value_info *kvi = ctx->kvi;
+
+	if (!matched) {
+		matched = xmalloc(sizeof(*matched));
+		strbuf_init(&matched->value, 0);
+		item->util = matched;
+	} else {
+		strbuf_reset(&matched->value);
+	}
+	matched->kvi = *kvi;
+
+	if (value) {
+		strbuf_addstr(&matched->value, value);
+		matched->value_is_null = 0;
+	} else {
+		matched->value_is_null = 1;
+	}
+	return 0;
+}
+
+static int get_urlmatch(const struct config_location_options *opts,
+			const struct config_display_options *_display_opts,
+			const char *var, const char *url)
+{
+	int ret;
+	char *section_tail;
+	struct config_display_options display_opts = *_display_opts;
+	struct string_list_item *item;
+	struct urlmatch_config config = URLMATCH_CONFIG_INIT;
+	struct string_list values = STRING_LIST_INIT_DUP;
+
+	config.collect_fn = urlmatch_collect_fn;
+	config.cascade_fn = NULL;
+	config.cb = &values;
+
+	if (!url_normalize(url, &config.url))
+		die("%s", config.url.err);
+
+	config.section = xstrdup_tolower(var);
+	section_tail = strchr(config.section, '.');
+	if (section_tail) {
+		*section_tail = '\0';
+		config.key = section_tail + 1;
+		display_opts.show_keys = 0;
+	} else {
+		config.key = NULL;
+		display_opts.show_keys = 1;
+	}
+
+	config_with_options(urlmatch_config_entry, &config,
+			    &opts->source, the_repository,
+			    &opts->options);
+
+	ret = !values.nr;
+
+	for_each_string_list_item(item, &values) {
+		struct urlmatch_current_candidate_value *matched = item->util;
+		struct strbuf buf = STRBUF_INIT;
+
+		format_config(&display_opts, &buf, item->string,
+			      matched->value_is_null ? NULL : matched->value.buf,
+			      &matched->kvi);
+		fwrite(buf.buf, 1, buf.len, stdout);
+		strbuf_release(&buf);
+
+		strbuf_release(&matched->value);
+	}
+	urlmatch_config_release(&config);
+	string_list_clear(&values, 1);
+	free(config.url.url);
+
+	free((void *)config.section);
+	return ret;
+}
+
+static char *default_user_config(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+	strbuf_addf(&buf,
+		    _("# This is Git's per-user configuration file.\n"
+		      "[user]\n"
+		      "# Please adapt and uncomment the following lines:\n"
+		      "#	name = %s\n"
+		      "#	email = %s\n"),
+		    ident_default_name(),
+		    ident_default_email());
+	return strbuf_detach(&buf, NULL);
+}
+
+static void location_options_init(struct config_location_options *opts,
+				  const char *prefix)
+{
+	if (!opts->source.file)
+		opts->source.file = opts->file_to_free =
+			xstrdup_or_null(getenv(CONFIG_ENVIRONMENT));
+
+	if (opts->use_global_config + opts->use_system_config +
+	    opts->use_local_config + opts->use_worktree_config +
+	    !!opts->source.file + !!opts->source.blob > 1) {
+		error(_("only one config file at a time"));
+		exit(129);
+	}
+
+	if (!startup_info->have_repository) {
+		if (opts->use_local_config)
+			die(_("--local can only be used inside a git repository"));
+		if (opts->source.blob)
+			die(_("--blob can only be used inside a git repository"));
+		if (opts->use_worktree_config)
+			die(_("--worktree can only be used inside a git repository"));
+	}
+
+	if (opts->source.file &&
+			!strcmp(opts->source.file, "-")) {
+		opts->source.file = NULL;
+		opts->source.use_stdin = 1;
+		opts->source.scope = CONFIG_SCOPE_COMMAND;
+	}
+
+	if (opts->use_global_config) {
+		opts->source.file = opts->file_to_free = git_global_config();
+		if (!opts->source.file)
+			/*
+			 * It is unknown if HOME/.gitconfig exists, so
+			 * we do not know if we should write to XDG
+			 * location; error out even if XDG_CONFIG_HOME
+			 * is set and points at a sane location.
+			 */
+			die(_("$HOME not set"));
+		opts->source.scope = CONFIG_SCOPE_GLOBAL;
+	} else if (opts->use_system_config) {
+		opts->source.file = opts->file_to_free = git_system_config();
+		opts->source.scope = CONFIG_SCOPE_SYSTEM;
+	} else if (opts->use_local_config) {
+		opts->source.file = opts->file_to_free = git_pathdup("config");
+		opts->source.scope = CONFIG_SCOPE_LOCAL;
+	} else if (opts->use_worktree_config) {
+		struct worktree **worktrees = get_worktrees();
+		if (the_repository->repository_format_worktree_config)
+			opts->source.file = opts->file_to_free =
+				git_pathdup("config.worktree");
+		else if (worktrees[0] && worktrees[1])
+			die(_("--worktree cannot be used with multiple "
+			      "working trees unless the config\n"
+			      "extension worktreeConfig is enabled. "
+			      "Please read \"CONFIGURATION FILE\"\n"
+			      "section in \"git help worktree\" for details"));
+		else
+			opts->source.file = opts->file_to_free =
+				git_pathdup("config");
+		opts->source.scope = CONFIG_SCOPE_LOCAL;
+		free_worktrees(worktrees);
+	} else if (opts->source.file) {
+		if (!is_absolute_path(opts->source.file) && prefix)
+			opts->source.file = opts->file_to_free =
+				prefix_filename(prefix, opts->source.file);
+		opts->source.scope = CONFIG_SCOPE_COMMAND;
+	} else if (opts->source.blob) {
+		opts->source.scope = CONFIG_SCOPE_COMMAND;
+	}
+
+	if (opts->respect_includes_opt == -1)
+		opts->options.respect_includes = !opts->source.file;
+	else
+		opts->options.respect_includes = opts->respect_includes_opt;
+	if (startup_info->have_repository) {
+		opts->options.commondir = repo_get_common_dir(the_repository);
+		opts->options.git_dir = repo_get_git_dir(the_repository);
+	}
+}
+
+static void location_options_release(struct config_location_options *opts)
+{
+	free(opts->file_to_free);
+}
+
+static void display_options_init(struct config_display_options *opts)
+{
+	if (opts->end_nul) {
+		opts->term = '\0';
+		opts->delim = '\n';
+		opts->key_delim = '\n';
+	}
+}
+
+static int cmd_config_list(int argc, const char **argv, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+	struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+	struct option opts[] = {
+		CONFIG_LOCATION_OPTIONS(location_opts),
+		CONFIG_DISPLAY_OPTIONS(display_opts),
+		OPT_GROUP(N_("Other")),
+		OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+			 N_("respect include directives on lookup")),
+		OPT_END(),
+	};
+
+	argc = parse_options(argc, argv, prefix, opts, builtin_config_list_usage, 0);
+	check_argc(argc, 0, 0);
+
+	location_options_init(&location_opts, prefix);
+	display_options_init(&display_opts);
+
+	setup_auto_pager("config", 1);
+
+	if (config_with_options(show_all_config, &display_opts,
+				&location_opts.source, the_repository,
+				&location_opts.options) < 0) {
+		if (location_opts.source.file)
+			die_errno(_("unable to read config file '%s'"),
+				  location_opts.source.file);
+		else
+			die(_("error processing config file(s)"));
+	}
+
+	location_options_release(&location_opts);
+	return 0;
+}
+
+static int cmd_config_get(int argc, const char **argv, const char *prefix,
+			  struct repository *repo UNUSED)
+{
+	struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+	struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+	const char *value_pattern = NULL, *url = NULL;
+	int flags = 0;
+	unsigned get_value_flags = 0;
+	struct option opts[] = {
+		CONFIG_LOCATION_OPTIONS(location_opts),
+		OPT_GROUP(N_("Filter options")),
+		OPT_BIT(0, "all", &get_value_flags, N_("return all values for multi-valued config options"), GET_VALUE_ALL),
+		OPT_BIT(0, "regexp", &get_value_flags, N_("interpret the name as a regular expression"), GET_VALUE_KEY_REGEXP),
+		OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+		OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+		OPT_STRING(0, "url", &url, N_("URL"), N_("show config matching the given URL")),
+		CONFIG_DISPLAY_OPTIONS(display_opts),
+		OPT_GROUP(N_("Other")),
+		OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+			 N_("respect include directives on lookup")),
+		OPT_STRING(0, "default", &display_opts.default_value,
+			   N_("value"), N_("use default value when missing entry")),
+		OPT_END(),
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, opts, builtin_config_get_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	check_argc(argc, 1, 1);
+
+	if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+		die(_("--fixed-value only applies with 'value-pattern'"));
+	if (display_opts.default_value &&
+	    ((get_value_flags & GET_VALUE_ALL) || url))
+		die(_("--default= cannot be used with --all or --url="));
+	if (url && ((get_value_flags & GET_VALUE_ALL) ||
+		    (get_value_flags & GET_VALUE_KEY_REGEXP) ||
+		    value_pattern))
+		die(_("--url= cannot be used with --all, --regexp or --value"));
+
+	location_options_init(&location_opts, prefix);
+	display_options_init(&display_opts);
+
+	setup_auto_pager("config", 1);
+
+	if (url)
+		ret = get_urlmatch(&location_opts, &display_opts, argv[0], url);
+	else
+		ret = get_value(&location_opts, &display_opts, argv[0], value_pattern,
+				get_value_flags, flags);
+
+	location_options_release(&location_opts);
+	return ret;
+}
+
+static int cmd_config_set(int argc, const char **argv, const char *prefix,
+			  struct repository *repo UNUSED)
+{
+	struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+	const char *value_pattern = NULL, *comment_arg = NULL;
+	char *comment = NULL;
+	int flags = 0, append = 0, type = 0;
+	struct option opts[] = {
+		CONFIG_LOCATION_OPTIONS(location_opts),
+		CONFIG_TYPE_OPTIONS(type),
+		OPT_GROUP(N_("Filter")),
+		OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE),
+		OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+		OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+		OPT_GROUP(N_("Other")),
+		OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
+		OPT_BOOL(0, "append", &append, N_("add a new line without altering any existing values")),
+		OPT_END(),
+	};
+	struct key_value_info default_kvi = KVI_INIT;
+	char *value;
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, opts, builtin_config_set_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	check_argc(argc, 2, 2);
+
+	if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+		die(_("--fixed-value only applies with --value=<pattern>"));
+	if (append && value_pattern)
+		die(_("--append cannot be used with --value=<pattern>"));
+	if (append)
+		value_pattern = CONFIG_REGEX_NONE;
+
+	comment = git_config_prepare_comment_string(comment_arg);
+
+	location_options_init(&location_opts, prefix);
+	check_write(&location_opts.source);
+
+	value = normalize_value(argv[0], argv[1], type, &default_kvi);
+
+	if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern) {
+		ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+							     argv[0], value, value_pattern,
+							     comment, flags);
+	} else {
+		ret = git_config_set_in_file_gently(location_opts.source.file,
+						    argv[0], comment, value);
+		if (ret == CONFIG_NOTHING_SET)
+			error(_("cannot overwrite multiple values with a single value\n"
+			"       Use a regexp, --add or --replace-all to change %s."), argv[0]);
+	}
+
+	location_options_release(&location_opts);
+	free(comment);
+	free(value);
+	return ret;
+}
+
+static int cmd_config_unset(int argc, const char **argv, const char *prefix,
+			    struct repository *repo UNUSED)
+{
+	struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+	const char *value_pattern = NULL;
+	int flags = 0;
+	struct option opts[] = {
+		CONFIG_LOCATION_OPTIONS(location_opts),
+		OPT_GROUP(N_("Filter")),
+		OPT_BIT(0, "all", &flags, N_("replace multi-valued config option with new value"), CONFIG_FLAGS_MULTI_REPLACE),
+		OPT_STRING(0, "value", &value_pattern, N_("pattern"), N_("show config with values matching the pattern")),
+		OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+		OPT_END(),
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, opts, builtin_config_unset_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	check_argc(argc, 1, 1);
+
+	if ((flags & CONFIG_FLAGS_FIXED_VALUE) && !value_pattern)
+		die(_("--fixed-value only applies with 'value-pattern'"));
+
+	location_options_init(&location_opts, prefix);
+	check_write(&location_opts.source);
+
+	if ((flags & CONFIG_FLAGS_MULTI_REPLACE) || value_pattern)
+		ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+							     argv[0], NULL, value_pattern,
+							     NULL, flags);
+	else
+		ret = git_config_set_in_file_gently(location_opts.source.file, argv[0],
+						    NULL, NULL);
+
+	location_options_release(&location_opts);
+	return ret;
+}
+
+static int cmd_config_rename_section(int argc, const char **argv, const char *prefix,
+				     struct repository *repo UNUSED)
+{
+	struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+	struct option opts[] = {
+		CONFIG_LOCATION_OPTIONS(location_opts),
+		OPT_END(),
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, opts, builtin_config_rename_section_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	check_argc(argc, 2, 2);
+
+	location_options_init(&location_opts, prefix);
+	check_write(&location_opts.source);
+
+	ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+						 argv[0], argv[1]);
+	if (ret < 0)
+		goto out;
+	else if (!ret)
+		die(_("no such section: %s"), argv[0]);
+	ret = 0;
+
+out:
+	location_options_release(&location_opts);
+	return ret;
+}
+
+static int cmd_config_remove_section(int argc, const char **argv, const char *prefix,
+				     struct repository *repo UNUSED)
+{
+	struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+	struct option opts[] = {
+		CONFIG_LOCATION_OPTIONS(location_opts),
+		OPT_END(),
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, opts, builtin_config_remove_section_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	check_argc(argc, 1, 1);
+
+	location_options_init(&location_opts, prefix);
+	check_write(&location_opts.source);
+
+	ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+						 argv[0], NULL);
+	if (ret < 0)
+		goto out;
+	else if (!ret)
+		die(_("no such section: %s"), argv[0]);
+	ret = 0;
+
+out:
+	location_options_release(&location_opts);
+	return ret;
+}
+
+static int show_editor(struct config_location_options *opts)
+{
+	char *config_file;
+
+	if (!opts->source.file && !startup_info->have_repository)
+		die(_("not in a git directory"));
+	if (opts->source.use_stdin)
+		die(_("editing stdin is not supported"));
+	if (opts->source.blob)
+		die(_("editing blobs is not supported"));
+	git_config(git_default_config, NULL);
+	config_file = opts->source.file ?
+			xstrdup(opts->source.file) :
+			git_pathdup("config");
+	if (opts->use_global_config) {
+		int fd = open(config_file, O_CREAT | O_EXCL | O_WRONLY, 0666);
+		if (fd >= 0) {
+			char *content = default_user_config();
+			write_str_in_full(fd, content);
+			free(content);
+			close(fd);
+		}
+		else if (errno != EEXIST)
+			die_errno(_("cannot create configuration file %s"), config_file);
+	}
+	launch_editor(config_file, NULL, NULL);
+	free(config_file);
+
+	return 0;
+}
+
+static int cmd_config_edit(int argc, const char **argv, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+	struct option opts[] = {
+		CONFIG_LOCATION_OPTIONS(location_opts),
+		OPT_END(),
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, opts, builtin_config_edit_usage, 0);
+	check_argc(argc, 0, 0);
+
+	location_options_init(&location_opts, prefix);
+	check_write(&location_opts.source);
+
+	ret = show_editor(&location_opts);
+	location_options_release(&location_opts);
+	return ret;
+}
+
+static int cmd_config_actions(int argc, const char **argv, const char *prefix)
+{
+	enum {
+		ACTION_GET = (1<<0),
+		ACTION_GET_ALL = (1<<1),
+		ACTION_GET_REGEXP = (1<<2),
+		ACTION_REPLACE_ALL = (1<<3),
+		ACTION_ADD = (1<<4),
+		ACTION_UNSET = (1<<5),
+		ACTION_UNSET_ALL = (1<<6),
+		ACTION_RENAME_SECTION = (1<<7),
+		ACTION_REMOVE_SECTION = (1<<8),
+		ACTION_LIST = (1<<9),
+		ACTION_EDIT = (1<<10),
+		ACTION_SET = (1<<11),
+		ACTION_SET_ALL = (1<<12),
+		ACTION_GET_COLOR = (1<<13),
+		ACTION_GET_COLORBOOL = (1<<14),
+		ACTION_GET_URLMATCH = (1<<15),
+	};
+	struct config_location_options location_opts = CONFIG_LOCATION_OPTIONS_INIT;
+	struct config_display_options display_opts = CONFIG_DISPLAY_OPTIONS_INIT;
+	const char *comment_arg = NULL;
+	int actions = 0;
+	unsigned flags = 0;
+	struct option opts[] = {
+		CONFIG_LOCATION_OPTIONS(location_opts),
+		OPT_GROUP(N_("Action")),
+		OPT_CMDMODE(0, "get", &actions, N_("get value: name [<value-pattern>]"), ACTION_GET),
+		OPT_CMDMODE(0, "get-all", &actions, N_("get all values: key [<value-pattern>]"), ACTION_GET_ALL),
+		OPT_CMDMODE(0, "get-regexp", &actions, N_("get values for regexp: name-regex [<value-pattern>]"), ACTION_GET_REGEXP),
+		OPT_CMDMODE(0, "get-urlmatch", &actions, N_("get value specific for the URL: section[.var] URL"), ACTION_GET_URLMATCH),
+		OPT_CMDMODE(0, "replace-all", &actions, N_("replace all matching variables: name value [<value-pattern>]"), ACTION_REPLACE_ALL),
+		OPT_CMDMODE(0, "add", &actions, N_("add a new variable: name value"), ACTION_ADD),
+		OPT_CMDMODE(0, "unset", &actions, N_("remove a variable: name [<value-pattern>]"), ACTION_UNSET),
+		OPT_CMDMODE(0, "unset-all", &actions, N_("remove all matches: name [<value-pattern>]"), ACTION_UNSET_ALL),
+		OPT_CMDMODE(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
+		OPT_CMDMODE(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
+		OPT_CMDMODE('l', "list", &actions, N_("list all"), ACTION_LIST),
+		OPT_CMDMODE('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
+		OPT_CMDMODE(0, "get-color", &actions, N_("find the color configured: slot [<default>]"), ACTION_GET_COLOR),
+		OPT_CMDMODE(0, "get-colorbool", &actions, N_("find the color setting: slot [<stdout-is-tty>]"), ACTION_GET_COLORBOOL),
+		CONFIG_DISPLAY_OPTIONS(display_opts),
+		OPT_GROUP(N_("Other")),
+		OPT_STRING(0, "default", &display_opts.default_value,
+			   N_("value"), N_("with --get, use default value when missing entry")),
+		OPT_STRING(0, "comment", &comment_arg, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
+		OPT_BIT(0, "fixed-value", &flags, N_("use string equality when comparing values to value pattern"), CONFIG_FLAGS_FIXED_VALUE),
+		OPT_BOOL(0, "includes", &location_opts.respect_includes_opt,
+			 N_("respect include directives on lookup")),
+		OPT_END(),
+	};
+	char *value = NULL, *comment = NULL;
+	int ret = 0;
+	struct key_value_info default_kvi = KVI_INIT;
+
+	argc = parse_options(argc, argv, prefix, opts,
+			     builtin_config_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+
+	location_options_init(&location_opts, prefix);
+	display_options_init(&display_opts);
+
+	if ((actions & (ACTION_GET_COLOR|ACTION_GET_COLORBOOL)) && display_opts.type) {
+		error(_("--get-color and variable type are incoherent"));
+		exit(129);
+	}
+
+	if (actions == 0)
+		switch (argc) {
+		case 1: actions = ACTION_GET; break;
+		case 2: actions = ACTION_SET; break;
+		case 3: actions = ACTION_SET_ALL; break;
+		default:
+			error(_("no action specified"));
+			exit(129);
+		}
+	if (display_opts.omit_values &&
+	    !(actions == ACTION_LIST || actions == ACTION_GET_REGEXP)) {
+		error(_("--name-only is only applicable to --list or --get-regexp"));
+		exit(129);
+	}
+
+	if (display_opts.show_origin && !(actions &
+		(ACTION_GET|ACTION_GET_ALL|ACTION_GET_REGEXP|ACTION_LIST))) {
+		error(_("--show-origin is only applicable to --get, --get-all, "
+			"--get-regexp, and --list"));
+		exit(129);
+	}
+
+	if (display_opts.default_value && !(actions & ACTION_GET)) {
+		error(_("--default is only applicable to --get"));
+		exit(129);
+	}
+
+	if (comment_arg &&
+	    !(actions & (ACTION_ADD|ACTION_SET|ACTION_SET_ALL|ACTION_REPLACE_ALL))) {
+		error(_("--comment is only applicable to add/set/replace operations"));
+		exit(129);
+	}
+
+	/* check usage of --fixed-value */
+	if (flags & CONFIG_FLAGS_FIXED_VALUE) {
+		int allowed_usage = 0;
+
+		switch (actions) {
+		/* git config --get <name> <value-pattern> */
+		case ACTION_GET:
+		/* git config --get-all <name> <value-pattern> */
+		case ACTION_GET_ALL:
+		/* git config --get-regexp <name-pattern> <value-pattern> */
+		case ACTION_GET_REGEXP:
+		/* git config --unset <name> <value-pattern> */
+		case ACTION_UNSET:
+		/* git config --unset-all <name> <value-pattern> */
+		case ACTION_UNSET_ALL:
+			allowed_usage = argc > 1 && !!argv[1];
+			break;
+
+		/* git config <name> <value> <value-pattern> */
+		case ACTION_SET_ALL:
+		/* git config --replace-all <name> <value> <value-pattern> */
+		case ACTION_REPLACE_ALL:
+			allowed_usage = argc > 2 && !!argv[2];
+			break;
+
+		/* other options don't allow --fixed-value */
+		}
+
+		if (!allowed_usage) {
+			error(_("--fixed-value only applies with 'value-pattern'"));
+			exit(129);
+		}
+	}
+
+	comment = git_config_prepare_comment_string(comment_arg);
+
+	/*
+	 * The following actions may produce more than one line of output and
+	 * should therefore be paged.
+	 */
+	if (actions & (ACTION_LIST | ACTION_GET_ALL | ACTION_GET_REGEXP | ACTION_GET_URLMATCH))
+		setup_auto_pager("config", 1);
+
+	if (actions == ACTION_LIST) {
+		check_argc(argc, 0, 0);
+		if (config_with_options(show_all_config, &display_opts,
+					&location_opts.source, the_repository,
+					&location_opts.options) < 0) {
+			if (location_opts.source.file)
+				die_errno(_("unable to read config file '%s'"),
+					  location_opts.source.file);
+			else
+				die(_("error processing config file(s)"));
+		}
+	}
+	else if (actions == ACTION_EDIT) {
+		ret = show_editor(&location_opts);
+	}
+	else if (actions == ACTION_SET) {
+		check_write(&location_opts.source);
+		check_argc(argc, 2, 2);
+		value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+		ret = git_config_set_in_file_gently(location_opts.source.file, argv[0], comment, value);
+		if (ret == CONFIG_NOTHING_SET)
+			error(_("cannot overwrite multiple values with a single value\n"
+			"       Use a regexp, --add or --replace-all to change %s."), argv[0]);
+	}
+	else if (actions == ACTION_SET_ALL) {
+		check_write(&location_opts.source);
+		check_argc(argc, 2, 3);
+		value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+		ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+							     argv[0], value, argv[2],
+							     comment, flags);
+	}
+	else if (actions == ACTION_ADD) {
+		check_write(&location_opts.source);
+		check_argc(argc, 2, 2);
+		value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+		ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+							     argv[0], value,
+							     CONFIG_REGEX_NONE,
+							     comment, flags);
+	}
+	else if (actions == ACTION_REPLACE_ALL) {
+		check_write(&location_opts.source);
+		check_argc(argc, 2, 3);
+		value = normalize_value(argv[0], argv[1], display_opts.type, &default_kvi);
+		ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+							     argv[0], value, argv[2],
+							     comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
+	}
+	else if (actions == ACTION_GET) {
+		check_argc(argc, 1, 2);
+		ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+				0, flags);
+	}
+	else if (actions == ACTION_GET_ALL) {
+		check_argc(argc, 1, 2);
+		ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+				GET_VALUE_ALL, flags);
+	}
+	else if (actions == ACTION_GET_REGEXP) {
+		display_opts.show_keys = 1;
+		check_argc(argc, 1, 2);
+		ret = get_value(&location_opts, &display_opts, argv[0], argv[1],
+				GET_VALUE_ALL|GET_VALUE_KEY_REGEXP, flags);
+	}
+	else if (actions == ACTION_GET_URLMATCH) {
+		check_argc(argc, 2, 2);
+		ret = get_urlmatch(&location_opts, &display_opts, argv[0], argv[1]);
+	}
+	else if (actions == ACTION_UNSET) {
+		check_write(&location_opts.source);
+		check_argc(argc, 1, 2);
+		if (argc == 2)
+			ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+								     argv[0], NULL, argv[1],
+								     NULL, flags);
+		else
+			ret = git_config_set_in_file_gently(location_opts.source.file,
+							    argv[0], NULL, NULL);
+	}
+	else if (actions == ACTION_UNSET_ALL) {
+		check_write(&location_opts.source);
+		check_argc(argc, 1, 2);
+		ret = git_config_set_multivar_in_file_gently(location_opts.source.file,
+							     argv[0], NULL, argv[1],
+							     NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
+	}
+	else if (actions == ACTION_RENAME_SECTION) {
+		check_write(&location_opts.source);
+		check_argc(argc, 2, 2);
+		ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+							 argv[0], argv[1]);
+		if (ret < 0)
+			goto out;
+		else if (!ret)
+			die(_("no such section: %s"), argv[0]);
+		else
+			ret = 0;
+	}
+	else if (actions == ACTION_REMOVE_SECTION) {
+		check_write(&location_opts.source);
+		check_argc(argc, 1, 1);
+		ret = repo_config_rename_section_in_file(the_repository, location_opts.source.file,
+							 argv[0], NULL);
+		if (ret < 0)
+			goto out;
+		else if (!ret)
+			die(_("no such section: %s"), argv[0]);
+		else
+			ret = 0;
+	}
+	else if (actions == ACTION_GET_COLOR) {
+		check_argc(argc, 1, 2);
+		get_color(&location_opts, argv[0], argv[1]);
+	}
+	else if (actions == ACTION_GET_COLORBOOL) {
+		check_argc(argc, 1, 2);
+		if (argc == 2)
+			color_stdout_is_tty = git_config_bool("command line", argv[1]);
+		ret = get_colorbool(&location_opts, argv[0], argc == 2);
+	}
+
+out:
+	location_options_release(&location_opts);
+	free(comment);
+	free(value);
+	return ret;
+}
+
+int cmd_config(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo)
+{
+	parse_opt_subcommand_fn *subcommand = NULL;
+	struct option subcommand_opts[] = {
+		OPT_SUBCOMMAND("list", &subcommand, cmd_config_list),
+		OPT_SUBCOMMAND("get", &subcommand, cmd_config_get),
+		OPT_SUBCOMMAND("set", &subcommand, cmd_config_set),
+		OPT_SUBCOMMAND("unset", &subcommand, cmd_config_unset),
+		OPT_SUBCOMMAND("rename-section", &subcommand, cmd_config_rename_section),
+		OPT_SUBCOMMAND("remove-section", &subcommand, cmd_config_remove_section),
+		OPT_SUBCOMMAND("edit", &subcommand, cmd_config_edit),
+		OPT_END(),
+	};
+
+	/*
+	 * This is somewhat hacky: we first parse the command line while
+	 * keeping all args intact in order to determine whether a subcommand
+	 * has been specified. If so, we re-parse it a second time, but this
+	 * time we drop KEEP_ARGV0. This is so that we don't munge the command
+	 * line in case no subcommand was given, which would otherwise confuse
+	 * us when parsing the legacy-style modes that don't use subcommands.
+	 */
+	argc = parse_options(argc, argv, prefix, subcommand_opts, builtin_config_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_ARGV0|PARSE_OPT_KEEP_UNKNOWN_OPT);
+	if (subcommand) {
+		argc = parse_options(argc, argv, prefix, subcommand_opts, builtin_config_usage,
+		       PARSE_OPT_SUBCOMMAND_OPTIONAL|PARSE_OPT_KEEP_UNKNOWN_OPT);
+		return subcommand(argc, argv, prefix, repo);
+	}
+
+	return cmd_config_actions(argc, argv, prefix);
+}
diff --git a/builtin/count-objects.c b/builtin/count-objects.c
new file mode 100644
index 0000000000..1e89148ed7
--- /dev/null
+++ b/builtin/count-objects.c
@@ -0,0 +1,177 @@
+/*
+ * Builtin "git count-objects".
+ *
+ * Copyright (c) 2006 Junio C Hamano
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "dir.h"
+#include "gettext.h"
+#include "path.h"
+#include "parse-options.h"
+#include "quote.h"
+#include "packfile.h"
+#include "object-store-ll.h"
+
+static unsigned long garbage;
+static off_t size_garbage;
+static int verbose;
+static unsigned long loose, packed, packed_loose;
+static off_t loose_size;
+
+static const char *bits_to_msg(unsigned seen_bits)
+{
+	switch (seen_bits) {
+	case 0:
+		return "no corresponding .idx or .pack";
+	case PACKDIR_FILE_GARBAGE:
+		return "garbage found";
+	case PACKDIR_FILE_PACK:
+		return "no corresponding .idx";
+	case PACKDIR_FILE_IDX:
+		return "no corresponding .pack";
+	case PACKDIR_FILE_PACK|PACKDIR_FILE_IDX:
+	default:
+		return NULL;
+	}
+}
+
+static void real_report_garbage(unsigned seen_bits, const char *path)
+{
+	struct stat st;
+	const char *desc = bits_to_msg(seen_bits);
+
+	if (!desc)
+		return;
+
+	if (!stat(path, &st))
+		size_garbage += st.st_size;
+	warning("%s: %s", desc, path);
+	garbage++;
+}
+
+static void loose_garbage(const char *path)
+{
+	if (verbose)
+		report_garbage(PACKDIR_FILE_GARBAGE, path);
+}
+
+static int count_loose(const struct object_id *oid, const char *path,
+		       void *data UNUSED)
+{
+	struct stat st;
+
+	if (lstat(path, &st) || !S_ISREG(st.st_mode))
+		loose_garbage(path);
+	else {
+		loose_size += on_disk_bytes(st);
+		loose++;
+		if (verbose && has_object_pack(the_repository, oid))
+			packed_loose++;
+	}
+	return 0;
+}
+
+static int count_cruft(const char *basename UNUSED, const char *path,
+		       void *data UNUSED)
+{
+	loose_garbage(path);
+	return 0;
+}
+
+static int print_alternate(struct object_directory *odb, void *data UNUSED)
+{
+	printf("alternate: ");
+	quote_c_style(odb->path, NULL, stdout, 0);
+	putchar('\n');
+	return 0;
+}
+
+static char const * const count_objects_usage[] = {
+	"git count-objects [-v] [-H | --human-readable]",
+	NULL
+};
+
+int cmd_count_objects(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	int human_readable = 0;
+	struct option opts[] = {
+		OPT__VERBOSE(&verbose, N_("be verbose")),
+		OPT_BOOL('H', "human-readable", &human_readable,
+			 N_("print sizes in human readable format")),
+		OPT_END(),
+	};
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, opts, count_objects_usage, 0);
+	/* we do not take arguments other than flags for now */
+	if (argc)
+		usage_with_options(count_objects_usage, opts);
+	if (verbose) {
+		report_garbage = real_report_garbage;
+		report_linked_checkout_garbage(the_repository);
+	}
+
+	for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+				      count_loose, count_cruft, NULL, NULL);
+
+	if (verbose) {
+		struct packed_git *p;
+		unsigned long num_pack = 0;
+		off_t size_pack = 0;
+		struct strbuf loose_buf = STRBUF_INIT;
+		struct strbuf pack_buf = STRBUF_INIT;
+		struct strbuf garbage_buf = STRBUF_INIT;
+
+		for (p = get_all_packs(the_repository); p; p = p->next) {
+			if (!p->pack_local)
+				continue;
+			if (open_pack_index(p))
+				continue;
+			packed += p->num_objects;
+			size_pack += p->pack_size + p->index_size;
+			num_pack++;
+		}
+
+		if (human_readable) {
+			strbuf_humanise_bytes(&loose_buf, loose_size);
+			strbuf_humanise_bytes(&pack_buf, size_pack);
+			strbuf_humanise_bytes(&garbage_buf, size_garbage);
+		} else {
+			strbuf_addf(&loose_buf, "%lu",
+				    (unsigned long)(loose_size / 1024));
+			strbuf_addf(&pack_buf, "%lu",
+				    (unsigned long)(size_pack / 1024));
+			strbuf_addf(&garbage_buf, "%lu",
+				    (unsigned long)(size_garbage / 1024));
+		}
+
+		printf("count: %lu\n", loose);
+		printf("size: %s\n", loose_buf.buf);
+		printf("in-pack: %lu\n", packed);
+		printf("packs: %lu\n", num_pack);
+		printf("size-pack: %s\n", pack_buf.buf);
+		printf("prune-packable: %lu\n", packed_loose);
+		printf("garbage: %lu\n", garbage);
+		printf("size-garbage: %s\n", garbage_buf.buf);
+		foreach_alt_odb(print_alternate, NULL);
+		strbuf_release(&loose_buf);
+		strbuf_release(&pack_buf);
+		strbuf_release(&garbage_buf);
+	} else {
+		struct strbuf buf = STRBUF_INIT;
+		if (human_readable)
+			strbuf_humanise_bytes(&buf, loose_size);
+		else
+			strbuf_addf(&buf, "%lu kilobytes",
+				    (unsigned long)(loose_size / 1024));
+		printf("%lu objects, %s\n", loose, buf.buf);
+		strbuf_release(&buf);
+	}
+	return 0;
+}
diff --git a/builtin/credential-cache--daemon.c b/builtin/credential-cache--daemon.c
new file mode 100644
index 0000000000..e707618e74
--- /dev/null
+++ b/builtin/credential-cache--daemon.c
@@ -0,0 +1,354 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "object-file.h"
+#include "parse-options.h"
+
+#ifndef NO_UNIX_SOCKETS
+
+#include "config.h"
+#include "tempfile.h"
+#include "credential.h"
+#include "unix-socket.h"
+
+struct credential_cache_entry {
+	struct credential item;
+	timestamp_t expiration;
+};
+static struct credential_cache_entry *entries;
+static int entries_nr;
+static int entries_alloc;
+
+static void cache_credential(struct credential *c, int timeout)
+{
+	struct credential_cache_entry *e;
+
+	ALLOC_GROW(entries, entries_nr + 1, entries_alloc);
+	e = &entries[entries_nr++];
+
+	/* take ownership of pointers */
+	memcpy(&e->item, c, sizeof(*c));
+	memset(c, 0, sizeof(*c));
+	e->expiration = time(NULL) + timeout;
+}
+
+static struct credential_cache_entry *lookup_credential(const struct credential *c)
+{
+	int i;
+	for (i = 0; i < entries_nr; i++) {
+		struct credential *e = &entries[i].item;
+		if (credential_match(c, e, 0))
+			return &entries[i];
+	}
+	return NULL;
+}
+
+static void remove_credential(const struct credential *c, int match_password)
+{
+	struct credential_cache_entry *e;
+
+	int i;
+	for (i = 0; i < entries_nr; i++) {
+		e = &entries[i];
+		if (credential_match(c, &e->item, match_password))
+			e->expiration = 0;
+	}
+}
+
+static timestamp_t check_expirations(void)
+{
+	static timestamp_t wait_for_entry_until;
+	int i = 0;
+	timestamp_t now = time(NULL);
+	timestamp_t next = TIME_MAX;
+
+	/*
+	 * Initially give the client 30 seconds to actually contact us
+	 * and store a credential before we decide there's no point in
+	 * keeping the daemon around.
+	 */
+	if (!wait_for_entry_until)
+		wait_for_entry_until = now + 30;
+
+	while (i < entries_nr) {
+		if (entries[i].expiration <= now) {
+			entries_nr--;
+			credential_clear(&entries[i].item);
+			if (i != entries_nr)
+				memcpy(&entries[i], &entries[entries_nr], sizeof(*entries));
+			/*
+			 * Stick around 30 seconds in case a new credential
+			 * shows up (e.g., because we just removed a failed
+			 * one, and we will soon get the correct one).
+			 */
+			wait_for_entry_until = now + 30;
+		}
+		else {
+			if (entries[i].expiration < next)
+				next = entries[i].expiration;
+			i++;
+		}
+	}
+
+	if (!entries_nr) {
+		if (wait_for_entry_until <= now)
+			return 0;
+		next = wait_for_entry_until;
+	}
+
+	return next - now;
+}
+
+static int read_request(FILE *fh, struct credential *c,
+			struct strbuf *action, int *timeout)
+{
+	static struct strbuf item = STRBUF_INIT;
+	const char *p;
+
+	strbuf_getline_lf(&item, fh);
+	if (!skip_prefix(item.buf, "action=", &p))
+		return error("client sent bogus action line: %s", item.buf);
+	strbuf_addstr(action, p);
+
+	strbuf_getline_lf(&item, fh);
+	if (!skip_prefix(item.buf, "timeout=", &p))
+		return error("client sent bogus timeout line: %s", item.buf);
+	*timeout = atoi(p);
+
+	credential_set_all_capabilities(c, CREDENTIAL_OP_INITIAL);
+
+	if (credential_read(c, fh, CREDENTIAL_OP_HELPER) < 0)
+		return -1;
+	return 0;
+}
+
+static void serve_one_client(FILE *in, FILE *out)
+{
+	struct credential c = CREDENTIAL_INIT;
+	struct strbuf action = STRBUF_INIT;
+	int timeout = -1;
+
+	if (read_request(in, &c, &action, &timeout) < 0)
+		/* ignore error */ ;
+	else if (!strcmp(action.buf, "get")) {
+		struct credential_cache_entry *e = lookup_credential(&c);
+		if (e) {
+			e->item.capa_authtype.request_initial = 1;
+			e->item.capa_authtype.request_helper = 1;
+
+			fprintf(out, "capability[]=authtype\n");
+			if (e->item.username)
+				fprintf(out, "username=%s\n", e->item.username);
+			if (e->item.password)
+				fprintf(out, "password=%s\n", e->item.password);
+			if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_RESPONSE) && e->item.authtype)
+				fprintf(out, "authtype=%s\n", e->item.authtype);
+			if (credential_has_capability(&c.capa_authtype, CREDENTIAL_OP_RESPONSE) && e->item.credential)
+				fprintf(out, "credential=%s\n", e->item.credential);
+			if (e->item.password_expiry_utc != TIME_MAX)
+				fprintf(out, "password_expiry_utc=%"PRItime"\n",
+					e->item.password_expiry_utc);
+			if (e->item.oauth_refresh_token)
+				fprintf(out, "oauth_refresh_token=%s\n",
+					e->item.oauth_refresh_token);
+		}
+	}
+	else if (!strcmp(action.buf, "exit")) {
+		/*
+		 * It's important that we clean up our socket first, and then
+		 * signal the client only once we have finished the cleanup.
+		 * Calling exit() directly does this, because we clean up in
+		 * our atexit() handler, and then signal the client when our
+		 * process actually ends, which closes the socket and gives
+		 * them EOF.
+		 */
+		exit(0);
+	}
+	else if (!strcmp(action.buf, "erase"))
+		remove_credential(&c, 1);
+	else if (!strcmp(action.buf, "store")) {
+		if (timeout < 0)
+			warning("cache client didn't specify a timeout");
+		else if ((!c.username || !c.password) && (!c.authtype && !c.credential))
+			warning("cache client gave us a partial credential");
+		else if (c.ephemeral)
+			warning("not storing ephemeral credential");
+		else {
+			remove_credential(&c, 0);
+			cache_credential(&c, timeout);
+		}
+	}
+	else
+		warning("cache client sent unknown action: %s", action.buf);
+
+	credential_clear(&c);
+	strbuf_release(&action);
+}
+
+static int serve_cache_loop(int fd)
+{
+	struct pollfd pfd;
+	timestamp_t wakeup;
+
+	wakeup = check_expirations();
+	if (!wakeup)
+		return 0;
+
+	pfd.fd = fd;
+	pfd.events = POLLIN;
+	if (poll(&pfd, 1, 1000 * wakeup) < 0) {
+		if (errno != EINTR)
+			die_errno("poll failed");
+		return 1;
+	}
+
+	if (pfd.revents & POLLIN) {
+		int client, client2;
+		FILE *in, *out;
+
+		client = accept(fd, NULL, NULL);
+		if (client < 0) {
+			warning_errno("accept failed");
+			return 1;
+		}
+		client2 = dup(client);
+		if (client2 < 0) {
+			warning_errno("dup failed");
+			close(client);
+			return 1;
+		}
+
+		in = xfdopen(client, "r");
+		out = xfdopen(client2, "w");
+		serve_one_client(in, out);
+		fclose(in);
+		fclose(out);
+	}
+	return 1;
+}
+
+static void serve_cache(const char *socket_path, int debug)
+{
+	struct unix_stream_listen_opts opts = UNIX_STREAM_LISTEN_OPTS_INIT;
+	int fd;
+
+	fd = unix_stream_listen(socket_path, &opts);
+	if (fd < 0)
+		die_errno("unable to bind to '%s'", socket_path);
+
+	printf("ok\n");
+	fclose(stdout);
+	if (!debug) {
+		if (!freopen("/dev/null", "w", stderr))
+			die_errno("unable to point stderr to /dev/null");
+	}
+
+	while (serve_cache_loop(fd))
+		; /* nothing */
+
+	close(fd);
+}
+
+static const char permissions_advice[] = N_(
+"The permissions on your socket directory are too loose; other\n"
+"users may be able to read your cached credentials. Consider running:\n"
+"\n"
+"	chmod 0700 %s");
+static void init_socket_directory(const char *path)
+{
+	struct stat st;
+	char *path_copy = xstrdup(path);
+	char *dir = dirname(path_copy);
+
+	if (!stat(dir, &st)) {
+		if (st.st_mode & 077)
+			die(_(permissions_advice), dir);
+	} else {
+		/*
+		 * We must be sure to create the directory with the correct mode,
+		 * not just chmod it after the fact; otherwise, there is a race
+		 * condition in which somebody can chdir to it, sleep, then try to open
+		 * our protected socket.
+		 */
+		if (safe_create_leading_directories_const(dir) < 0)
+			die_errno("unable to create directories for '%s'", dir);
+		if (mkdir(dir, 0700) < 0)
+			die_errno("unable to mkdir '%s'", dir);
+	}
+
+	if (chdir(dir))
+		/*
+		 * We don't actually care what our cwd is; we chdir here just to
+		 * be a friendly daemon and avoid tying up our original cwd.
+		 * If this fails, it's OK to just continue without that benefit.
+		 */
+		;
+
+	free(path_copy);
+}
+
+int cmd_credential_cache_daemon(int argc,
+				const char **argv,
+				const char *prefix,
+				struct repository *repo UNUSED)
+{
+	struct tempfile *socket_file;
+	const char *socket_path;
+	int ignore_sighup = 0;
+	static const char *usage[] = {
+		"git credential-cache--daemon [--debug] <socket-path>",
+		NULL
+	};
+	int debug = 0;
+	const struct option options[] = {
+		OPT_BOOL(0, "debug", &debug,
+			 N_("print debugging messages to stderr")),
+		OPT_END()
+	};
+
+	git_config_get_bool("credentialcache.ignoresighup", &ignore_sighup);
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+	socket_path = argv[0];
+
+	if (!have_unix_sockets())
+		die(_("credential-cache--daemon unavailable; no unix socket support"));
+	if (!socket_path)
+		usage_with_options(usage, options);
+
+	if (!is_absolute_path(socket_path))
+		die("socket directory must be an absolute path");
+
+	init_socket_directory(socket_path);
+	socket_file = register_tempfile(socket_path);
+
+	if (ignore_sighup)
+		signal(SIGHUP, SIG_IGN);
+
+	serve_cache(socket_path, debug);
+	delete_tempfile(&socket_file);
+
+	return 0;
+}
+
+#else
+
+int cmd_credential_cache_daemon(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
+{
+	const char * const usage[] = {
+		"git credential-cache--daemon [--debug] <socket-path>",
+		"",
+		"credential-cache--daemon is disabled in this build of Git",
+		NULL
+	};
+	struct option options[] = { OPT_END() };
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+	die(_("credential-cache--daemon unavailable; no unix socket support"));
+}
+
+#endif /* NO_UNIX_SOCKET */
diff --git a/builtin/credential-cache.c b/builtin/credential-cache.c
new file mode 100644
index 0000000000..7f733cb756
--- /dev/null
+++ b/builtin/credential-cache.c
@@ -0,0 +1,207 @@
+#include "builtin.h"
+#include "credential.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "path.h"
+#include "strbuf.h"
+#include "write-or-die.h"
+
+#ifndef NO_UNIX_SOCKETS
+
+#include "unix-socket.h"
+#include "run-command.h"
+
+#define FLAG_SPAWN 0x1
+#define FLAG_RELAY 0x2
+
+#ifdef GIT_WINDOWS_NATIVE
+
+static int connection_closed(int error)
+{
+	return (error == EINVAL);
+}
+
+static int connection_fatally_broken(int error)
+{
+	return (error != ENOENT) && (error != ENETDOWN);
+}
+
+#else
+
+static int connection_closed(int error)
+{
+	return error == ECONNRESET || error == ECONNABORTED;
+}
+
+static int connection_fatally_broken(int error)
+{
+	return (error != ENOENT) && (error != ECONNREFUSED);
+}
+
+#endif
+
+static int send_request(const char *socket, const struct strbuf *out)
+{
+	int got_data = 0;
+	int fd = unix_stream_connect(socket, 0);
+
+	if (fd < 0)
+		return -1;
+
+	if (write_in_full(fd, out->buf, out->len) < 0)
+		die_errno("unable to write to cache daemon");
+	shutdown(fd, SHUT_WR);
+
+	while (1) {
+		char in[1024];
+		int r;
+
+		r = read_in_full(fd, in, sizeof(in));
+		if (r == 0 || (r < 0 && connection_closed(errno)))
+			break;
+		if (r < 0)
+			die_errno("read error from cache daemon");
+		write_or_die(1, in, r);
+		got_data = 1;
+	}
+	close(fd);
+	return got_data;
+}
+
+static void spawn_daemon(const char *socket)
+{
+	struct child_process daemon = CHILD_PROCESS_INIT;
+	char buf[128];
+	int r;
+
+	strvec_pushl(&daemon.args,
+		     "credential-cache--daemon", socket,
+		     NULL);
+	daemon.git_cmd = 1;
+	daemon.no_stdin = 1;
+	daemon.out = -1;
+
+	if (start_command(&daemon))
+		die_errno("unable to start cache daemon");
+	r = read_in_full(daemon.out, buf, sizeof(buf));
+	if (r < 0)
+		die_errno("unable to read result code from cache daemon");
+	if (r != 3 || memcmp(buf, "ok\n", 3))
+		die("cache daemon did not start: %.*s", r, buf);
+
+	child_process_clear(&daemon);
+	close(daemon.out);
+}
+
+static void do_cache(const char *socket, const char *action, int timeout,
+		     int flags)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	strbuf_addf(&buf, "action=%s\n", action);
+	strbuf_addf(&buf, "timeout=%d\n", timeout);
+	if (flags & FLAG_RELAY) {
+		if (strbuf_read(&buf, 0, 0) < 0)
+			die_errno("unable to relay credential");
+	}
+
+	if (send_request(socket, &buf) < 0) {
+		if (connection_fatally_broken(errno))
+			die_errno("unable to connect to cache daemon");
+		if (flags & FLAG_SPAWN) {
+			spawn_daemon(socket);
+			if (send_request(socket, &buf) < 0)
+				die_errno("unable to connect to cache daemon");
+		}
+	}
+	strbuf_release(&buf);
+}
+
+static char *get_socket_path(void)
+{
+	struct stat sb;
+	char *old_dir, *socket;
+	old_dir = interpolate_path("~/.git-credential-cache", 0);
+	if (old_dir && !stat(old_dir, &sb) && S_ISDIR(sb.st_mode))
+		socket = xstrfmt("%s/socket", old_dir);
+	else
+		socket = xdg_cache_home("credential/socket");
+	free(old_dir);
+	return socket;
+}
+
+static void announce_capabilities(void)
+{
+	struct credential c = CREDENTIAL_INIT;
+	c.capa_authtype.request_initial = 1;
+	credential_announce_capabilities(&c, stdout);
+}
+
+int cmd_credential_cache(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	const char *socket_path_arg = NULL;
+	char *socket_path;
+	int timeout = 900;
+	const char *op;
+	const char * const usage[] = {
+		"git credential-cache [<options>] <action>",
+		NULL
+	};
+	struct option options[] = {
+		OPT_INTEGER(0, "timeout", &timeout,
+			    "number of seconds to cache credentials"),
+		OPT_STRING(0, "socket", &socket_path_arg, "path",
+			   "path of cache-daemon socket"),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+	if (!argc)
+		usage_with_options(usage, options);
+	op = argv[0];
+
+	if (!have_unix_sockets())
+		die(_("credential-cache unavailable; no unix socket support"));
+
+	socket_path = xstrdup_or_null(socket_path_arg);
+	if (!socket_path)
+		socket_path = get_socket_path();
+	if (!socket_path)
+		die("unable to find a suitable socket path; use --socket");
+
+	if (!strcmp(op, "exit"))
+		do_cache(socket_path, op, timeout, 0);
+	else if (!strcmp(op, "get") || !strcmp(op, "erase"))
+		do_cache(socket_path, op, timeout, FLAG_RELAY);
+	else if (!strcmp(op, "store"))
+		do_cache(socket_path, op, timeout, FLAG_RELAY|FLAG_SPAWN);
+	else if (!strcmp(op, "capability"))
+		announce_capabilities();
+	else
+		; /* ignore unknown operation */
+
+	free(socket_path);
+	return 0;
+}
+
+#else
+
+int cmd_credential_cache(int argc, const char **argv, const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	const char * const usage[] = {
+		"git credential-cache [options] <action>",
+		"",
+		"credential-cache is disabled in this build of Git",
+		NULL
+	};
+	struct option options[] = { OPT_END() };
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+	die(_("credential-cache unavailable; no unix socket support"));
+}
+
+#endif /* NO_UNIX_SOCKETS */
diff --git a/builtin/credential-store.c b/builtin/credential-store.c
new file mode 100644
index 0000000000..e669e99dbf
--- /dev/null
+++ b/builtin/credential-store.c
@@ -0,0 +1,227 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "lockfile.h"
+#include "credential.h"
+#include "path.h"
+#include "string-list.h"
+#include "parse-options.h"
+#include "write-or-die.h"
+
+static struct lock_file credential_lock;
+
+static int parse_credential_file(const char *fn,
+				  struct credential *c,
+				  void (*match_cb)(struct credential *),
+				  void (*other_cb)(struct strbuf *),
+				  int match_password)
+{
+	FILE *fh;
+	struct strbuf line = STRBUF_INIT;
+	struct credential entry = CREDENTIAL_INIT;
+	int found_credential = 0;
+
+	fh = fopen(fn, "r");
+	if (!fh) {
+		if (errno != ENOENT && errno != EACCES)
+			die_errno("unable to open %s", fn);
+		return found_credential;
+	}
+
+	while (strbuf_getline_lf(&line, fh) != EOF) {
+		if (!credential_from_url_gently(&entry, line.buf, 1) &&
+		    entry.username && entry.password &&
+		    credential_match(c, &entry, match_password)) {
+			found_credential = 1;
+			if (match_cb) {
+				match_cb(&entry);
+				break;
+			}
+		}
+		else if (other_cb)
+			other_cb(&line);
+	}
+
+	credential_clear(&entry);
+	strbuf_release(&line);
+	fclose(fh);
+	return found_credential;
+}
+
+static void print_entry(struct credential *c)
+{
+	printf("username=%s\n", c->username);
+	printf("password=%s\n", c->password);
+}
+
+static void print_line(struct strbuf *buf)
+{
+	strbuf_addch(buf, '\n');
+	write_or_die(get_lock_file_fd(&credential_lock), buf->buf, buf->len);
+}
+
+static void rewrite_credential_file(const char *fn, struct credential *c,
+				    struct strbuf *extra, int match_password)
+{
+	int timeout_ms = 1000;
+
+	git_config_get_int("credentialstore.locktimeoutms", &timeout_ms);
+	if (hold_lock_file_for_update_timeout(&credential_lock, fn, 0, timeout_ms) < 0)
+		die_errno(_("unable to get credential storage lock in %d ms"), timeout_ms);
+	if (extra)
+		print_line(extra);
+	parse_credential_file(fn, c, NULL, print_line, match_password);
+	if (commit_lock_file(&credential_lock) < 0)
+		die_errno("unable to write credential store");
+}
+
+static int is_rfc3986_unreserved(char ch)
+{
+	return isalnum(ch) ||
+		ch == '-' || ch == '_' || ch == '.' || ch == '~';
+}
+
+static int is_rfc3986_reserved_or_unreserved(char ch)
+{
+	if (is_rfc3986_unreserved(ch))
+		return 1;
+	switch (ch) {
+		case '!': case '*': case '\'': case '(': case ')': case ';':
+		case ':': case '@': case '&': case '=': case '+': case '$':
+		case ',': case '/': case '?': case '#': case '[': case ']':
+			return 1;
+	}
+	return 0;
+}
+
+static void store_credential_file(const char *fn, struct credential *c)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	strbuf_addf(&buf, "%s://", c->protocol);
+	strbuf_addstr_urlencode(&buf, c->username, is_rfc3986_unreserved);
+	strbuf_addch(&buf, ':');
+	strbuf_addstr_urlencode(&buf, c->password, is_rfc3986_unreserved);
+	strbuf_addch(&buf, '@');
+	if (c->host)
+		strbuf_addstr_urlencode(&buf, c->host, is_rfc3986_unreserved);
+	if (c->path) {
+		strbuf_addch(&buf, '/');
+		strbuf_addstr_urlencode(&buf, c->path,
+					is_rfc3986_reserved_or_unreserved);
+	}
+
+	rewrite_credential_file(fn, c, &buf, 0);
+	strbuf_release(&buf);
+}
+
+static void store_credential(const struct string_list *fns, struct credential *c)
+{
+	struct string_list_item *fn;
+
+	/*
+	 * Sanity check that what we are storing is actually sensible.
+	 * In particular, we can't make a URL without a protocol field.
+	 * Without either a host or pathname (depending on the scheme),
+	 * we have no primary key. And without a username and password,
+	 * we are not actually storing a credential.
+	 */
+	if (!c->protocol || !(c->host || c->path) || !c->username || !c->password)
+		return;
+
+	for_each_string_list_item(fn, fns)
+		if (!access(fn->string, F_OK)) {
+			store_credential_file(fn->string, c);
+			return;
+		}
+	/*
+	 * Write credential to the filename specified by fns->items[0], thus
+	 * creating it
+	 */
+	if (fns->nr)
+		store_credential_file(fns->items[0].string, c);
+}
+
+static void remove_credential(const struct string_list *fns, struct credential *c)
+{
+	struct string_list_item *fn;
+
+	/*
+	 * Sanity check that we actually have something to match
+	 * against. The input we get is a restrictive pattern,
+	 * so technically a blank credential means "erase everything".
+	 * But it is too easy to accidentally send this, since it is equivalent
+	 * to empty input. So explicitly disallow it, and require that the
+	 * pattern have some actual content to match.
+	 */
+	if (!c->protocol && !c->host && !c->path && !c->username)
+		return;
+	for_each_string_list_item(fn, fns)
+		if (!access(fn->string, F_OK))
+			rewrite_credential_file(fn->string, c, NULL, 1);
+}
+
+static void lookup_credential(const struct string_list *fns, struct credential *c)
+{
+	struct string_list_item *fn;
+
+	for_each_string_list_item(fn, fns)
+		if (parse_credential_file(fn->string, c, print_entry, NULL, 0))
+			return; /* Found credential */
+}
+
+int cmd_credential_store(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	const char * const usage[] = {
+		"git credential-store [<options>] <action>",
+		NULL
+	};
+	const char *op;
+	struct credential c = CREDENTIAL_INIT;
+	struct string_list fns = STRING_LIST_INIT_DUP;
+	char *file = NULL;
+	struct option options[] = {
+		OPT_STRING(0, "file", &file, "path",
+			   "fetch and store credentials in <path>"),
+		OPT_END()
+	};
+
+	umask(077);
+
+	argc = parse_options(argc, (const char **)argv, prefix, options, usage, 0);
+	if (argc != 1)
+		usage_with_options(usage, options);
+	op = argv[0];
+
+	if (file) {
+		string_list_append(&fns, file);
+	} else {
+		if ((file = interpolate_path("~/.git-credentials", 0)))
+			string_list_append_nodup(&fns, file);
+		file = xdg_config_home("credentials");
+		if (file)
+			string_list_append_nodup(&fns, file);
+	}
+	if (!fns.nr)
+		die("unable to set up default path; use --file");
+
+	if (credential_read(&c, stdin, CREDENTIAL_OP_HELPER) < 0)
+		die("unable to read credential");
+
+	if (!strcmp(op, "get"))
+		lookup_credential(&fns, &c);
+	else if (!strcmp(op, "erase"))
+		remove_credential(&fns, &c);
+	else if (!strcmp(op, "store"))
+		store_credential(&fns, &c);
+	else
+		; /* Ignore unknown operation. */
+
+	string_list_clear(&fns, 0);
+	credential_clear(&c);
+	return 0;
+}
diff --git a/builtin/credential.c b/builtin/credential.c
new file mode 100644
index 0000000000..2e11b15dde
--- /dev/null
+++ b/builtin/credential.c
@@ -0,0 +1,51 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "credential.h"
+#include "builtin.h"
+#include "config.h"
+
+static const char usage_msg[] =
+	"git credential (fill|approve|reject)";
+
+int cmd_credential(int argc,
+		   const char **argv,
+		   const char *prefix UNUSED,
+		   struct repository *repo UNUSED)
+{
+	const char *op;
+	struct credential c = CREDENTIAL_INIT;
+
+	git_config(git_default_config, NULL);
+
+	show_usage_if_asked(argc, argv, usage_msg);
+	if (argc != 2)
+		usage(usage_msg);
+	op = argv[1];
+
+	if (!strcmp(op, "capability")) {
+		credential_set_all_capabilities(&c, CREDENTIAL_OP_INITIAL);
+		credential_announce_capabilities(&c, stdout);
+		return 0;
+	}
+
+	if (credential_read(&c, stdin, CREDENTIAL_OP_INITIAL) < 0)
+		die("unable to read credential from stdin");
+
+	if (!strcmp(op, "fill")) {
+		credential_fill(the_repository, &c, 0);
+		credential_next_state(&c);
+		credential_write(&c, stdout, CREDENTIAL_OP_RESPONSE);
+	} else if (!strcmp(op, "approve")) {
+		credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER);
+		credential_approve(the_repository, &c);
+	} else if (!strcmp(op, "reject")) {
+		credential_set_all_capabilities(&c, CREDENTIAL_OP_HELPER);
+		credential_reject(the_repository, &c);
+	} else {
+		usage(usage_msg);
+	}
+
+	credential_clear(&c);
+	return 0;
+}
diff --git a/builtin/describe.c b/builtin/describe.c
new file mode 100644
index 0000000000..e2e73f3d75
--- /dev/null
+++ b/builtin/describe.c
@@ -0,0 +1,743 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "commit.h"
+#include "tag.h"
+#include "refs.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "read-cache-ll.h"
+#include "revision.h"
+#include "diff.h"
+#include "hashmap.h"
+#include "setup.h"
+#include "strvec.h"
+#include "run-command.h"
+#include "object-store-ll.h"
+#include "list-objects.h"
+#include "commit-slab.h"
+#include "wildmatch.h"
+
+#define MAX_TAGS	(FLAG_BITS - 1)
+#define DEFAULT_CANDIDATES 10
+
+define_commit_slab(commit_names, struct commit_name *);
+
+static const char * const describe_usage[] = {
+	N_("git describe [--all] [--tags] [--contains] [--abbrev=<n>] [<commit-ish>...]"),
+	N_("git describe [--all] [--tags] [--contains] [--abbrev=<n>] --dirty[=<mark>]"),
+	N_("git describe <blob>"),
+	NULL
+};
+
+static int debug;	/* Display lots of verbose info */
+static int all;	/* Any valid ref can be used */
+static int tags;	/* Allow lightweight tags */
+static int longformat;
+static int first_parent;
+static int abbrev = -1; /* unspecified */
+static int max_candidates = DEFAULT_CANDIDATES;
+static struct hashmap names;
+static int have_util;
+static struct string_list patterns = STRING_LIST_INIT_NODUP;
+static struct string_list exclude_patterns = STRING_LIST_INIT_NODUP;
+static int always;
+static const char *suffix, *dirty, *broken;
+static struct commit_names commit_names;
+
+/* diff-index command arguments to check if working tree is dirty. */
+static const char *diff_index_args[] = {
+	"diff-index", "--quiet", "HEAD", "--", NULL
+};
+
+static const char *update_index_args[] = {
+	"update-index", "--unmerged", "-q", "--refresh", NULL
+};
+
+struct commit_name {
+	struct hashmap_entry entry;
+	struct object_id peeled;
+	struct tag *tag;
+	unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
+	unsigned name_checked:1;
+	unsigned misnamed:1;
+	struct object_id oid;
+	char *path;
+};
+
+static const char *prio_names[] = {
+	N_("head"), N_("lightweight"), N_("annotated"),
+};
+
+static int commit_name_neq(const void *cmp_data UNUSED,
+			   const struct hashmap_entry *eptr,
+			   const struct hashmap_entry *entry_or_key,
+			   const void *peeled)
+{
+	const struct commit_name *cn1, *cn2;
+
+	cn1 = container_of(eptr, const struct commit_name, entry);
+	cn2 = container_of(entry_or_key, const struct commit_name, entry);
+
+	return !oideq(&cn1->peeled, peeled ? peeled : &cn2->peeled);
+}
+
+static inline struct commit_name *find_commit_name(const struct object_id *peeled)
+{
+	return hashmap_get_entry_from_hash(&names, oidhash(peeled), peeled,
+						struct commit_name, entry);
+}
+
+static int replace_name(struct commit_name *e,
+			       int prio,
+			       const struct object_id *oid,
+			       struct tag **tag)
+{
+	if (!e || e->prio < prio)
+		return 1;
+
+	if (e->prio == 2 && prio == 2) {
+		/* Multiple annotated tags point to the same commit.
+		 * Select one to keep based upon their tagger date.
+		 */
+		struct tag *t;
+
+		if (!e->tag) {
+			t = lookup_tag(the_repository, &e->oid);
+			if (!t || parse_tag(t))
+				return 1;
+			e->tag = t;
+		}
+
+		t = lookup_tag(the_repository, oid);
+		if (!t || parse_tag(t))
+			return 0;
+		*tag = t;
+
+		if (e->tag->date < t->date)
+			return 1;
+	}
+
+	return 0;
+}
+
+static void add_to_known_names(const char *path,
+			       const struct object_id *peeled,
+			       int prio,
+			       const struct object_id *oid)
+{
+	struct commit_name *e = find_commit_name(peeled);
+	struct tag *tag = NULL;
+	if (replace_name(e, prio, oid, &tag)) {
+		if (!e) {
+			e = xmalloc(sizeof(struct commit_name));
+			oidcpy(&e->peeled, peeled);
+			hashmap_entry_init(&e->entry, oidhash(peeled));
+			hashmap_add(&names, &e->entry);
+			e->path = NULL;
+		}
+		e->tag = tag;
+		e->prio = prio;
+		e->name_checked = 0;
+		e->misnamed = 0;
+		oidcpy(&e->oid, oid);
+		free(e->path);
+		e->path = xstrdup(path);
+	}
+}
+
+static int get_name(const char *path, const char *referent UNUSED, const struct object_id *oid,
+		    int flag UNUSED, void *cb_data UNUSED)
+{
+	int is_tag = 0;
+	struct object_id peeled;
+	int is_annotated, prio;
+	const char *path_to_match = NULL;
+
+	if (skip_prefix(path, "refs/tags/", &path_to_match)) {
+		is_tag = 1;
+	} else if (all) {
+		if ((exclude_patterns.nr || patterns.nr) &&
+		    !skip_prefix(path, "refs/heads/", &path_to_match) &&
+		    !skip_prefix(path, "refs/remotes/", &path_to_match)) {
+			/* Only accept reference of known type if there are match/exclude patterns */
+			return 0;
+		}
+	} else {
+		/* Reject anything outside refs/tags/ unless --all */
+		return 0;
+	}
+
+	/*
+	 * If we're given exclude patterns, first exclude any tag which match
+	 * any of the exclude pattern.
+	 */
+	if (exclude_patterns.nr) {
+		struct string_list_item *item;
+
+		for_each_string_list_item(item, &exclude_patterns) {
+			if (!wildmatch(item->string, path_to_match, 0))
+				return 0;
+		}
+	}
+
+	/*
+	 * If we're given patterns, accept only tags which match at least one
+	 * pattern.
+	 */
+	if (patterns.nr) {
+		int found = 0;
+		struct string_list_item *item;
+
+		for_each_string_list_item(item, &patterns) {
+			if (!wildmatch(item->string, path_to_match, 0)) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found)
+			return 0;
+	}
+
+	/* Is it annotated? */
+	if (!peel_iterated_oid(the_repository, oid, &peeled)) {
+		is_annotated = !oideq(oid, &peeled);
+	} else {
+		oidcpy(&peeled, oid);
+		is_annotated = 0;
+	}
+
+	/*
+	 * By default, we only use annotated tags, but with --tags
+	 * we fall back to lightweight ones (even without --tags,
+	 * we still remember lightweight ones, only to give hints
+	 * in an error message).  --all allows any refs to be used.
+	 */
+	if (is_annotated)
+		prio = 2;
+	else if (is_tag)
+		prio = 1;
+	else
+		prio = 0;
+
+	add_to_known_names(all ? path + 5 : path + 10, &peeled, prio, oid);
+	return 0;
+}
+
+struct possible_tag {
+	struct commit_name *name;
+	int depth;
+	int found_order;
+	unsigned flag_within;
+};
+
+static int compare_pt(const void *a_, const void *b_)
+{
+	struct possible_tag *a = (struct possible_tag *)a_;
+	struct possible_tag *b = (struct possible_tag *)b_;
+	if (a->depth != b->depth)
+		return a->depth - b->depth;
+	if (a->found_order != b->found_order)
+		return a->found_order - b->found_order;
+	return 0;
+}
+
+static unsigned long finish_depth_computation(
+	struct commit_list **list,
+	struct possible_tag *best)
+{
+	unsigned long seen_commits = 0;
+	while (*list) {
+		struct commit *c = pop_commit(list);
+		struct commit_list *parents = c->parents;
+		seen_commits++;
+		if (c->object.flags & best->flag_within) {
+			struct commit_list *a = *list;
+			while (a) {
+				struct commit *i = a->item;
+				if (!(i->object.flags & best->flag_within))
+					break;
+				a = a->next;
+			}
+			if (!a)
+				break;
+		} else
+			best->depth++;
+		while (parents) {
+			struct commit *p = parents->item;
+			repo_parse_commit(the_repository, p);
+			if (!(p->object.flags & SEEN))
+				commit_list_insert_by_date(p, list);
+			p->object.flags |= c->object.flags;
+			parents = parents->next;
+		}
+	}
+	return seen_commits;
+}
+
+static void append_name(struct commit_name *n, struct strbuf *dst)
+{
+	if (n->prio == 2 && !n->tag) {
+		n->tag = lookup_tag(the_repository, &n->oid);
+		if (!n->tag || parse_tag(n->tag))
+			die(_("annotated tag %s not available"), n->path);
+	}
+	if (n->tag && !n->name_checked) {
+		if (strcmp(n->tag->tag, all ? n->path + 5 : n->path)) {
+			warning(_("tag '%s' is externally known as '%s'"),
+				n->path, n->tag->tag);
+			n->misnamed = 1;
+		}
+		n->name_checked = 1;
+	}
+
+	if (n->tag) {
+		if (all)
+			strbuf_addstr(dst, "tags/");
+		strbuf_addstr(dst, n->tag->tag);
+	} else {
+		strbuf_addstr(dst, n->path);
+	}
+}
+
+static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
+{
+	strbuf_addf(dst, "-%d-g%s", depth,
+		    repo_find_unique_abbrev(the_repository, oid, abbrev));
+}
+
+static void describe_commit(struct object_id *oid, struct strbuf *dst)
+{
+	struct commit *cmit, *gave_up_on = NULL;
+	struct commit_list *list;
+	struct commit_name *n;
+	struct possible_tag all_matches[MAX_TAGS];
+	unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
+	unsigned long seen_commits = 0;
+	unsigned int unannotated_cnt = 0;
+
+	cmit = lookup_commit_reference(the_repository, oid);
+
+	n = find_commit_name(&cmit->object.oid);
+	if (n && (tags || all || n->prio == 2)) {
+		/*
+		 * Exact match to an existing ref.
+		 */
+		append_name(n, dst);
+		if (n->misnamed || longformat)
+			append_suffix(0, n->tag ? get_tagged_oid(n->tag) : oid, dst);
+		if (suffix)
+			strbuf_addstr(dst, suffix);
+		return;
+	}
+
+	if (!max_candidates)
+		die(_("no tag exactly matches '%s'"), oid_to_hex(&cmit->object.oid));
+	if (debug)
+		fprintf(stderr, _("No exact match on refs or tags, searching to describe\n"));
+
+	if (!have_util) {
+		struct hashmap_iter iter;
+		struct commit *c;
+		struct commit_name *n;
+
+		init_commit_names(&commit_names);
+		hashmap_for_each_entry(&names, &iter, n,
+					entry /* member name */) {
+			c = lookup_commit_reference_gently(the_repository,
+							   &n->peeled, 1);
+			if (c)
+				*commit_names_at(&commit_names, c) = n;
+		}
+		have_util = 1;
+	}
+
+	list = NULL;
+	cmit->object.flags = SEEN;
+	commit_list_insert(cmit, &list);
+	while (list) {
+		struct commit *c = pop_commit(&list);
+		struct commit_list *parents = c->parents;
+		struct commit_name **slot;
+
+		seen_commits++;
+
+		if (match_cnt == max_candidates ||
+		    match_cnt == hashmap_get_size(&names)) {
+			gave_up_on = c;
+			break;
+		}
+
+		slot = commit_names_peek(&commit_names, c);
+		n = slot ? *slot : NULL;
+		if (n) {
+			if (!tags && !all && n->prio < 2) {
+				unannotated_cnt++;
+			} else if (match_cnt < max_candidates) {
+				struct possible_tag *t = &all_matches[match_cnt++];
+				t->name = n;
+				t->depth = seen_commits - 1;
+				t->flag_within = 1u << match_cnt;
+				t->found_order = match_cnt;
+				c->object.flags |= t->flag_within;
+				if (n->prio == 2)
+					annotated_cnt++;
+			}
+		}
+		for (cur_match = 0; cur_match < match_cnt; cur_match++) {
+			struct possible_tag *t = &all_matches[cur_match];
+			if (!(c->object.flags & t->flag_within))
+				t->depth++;
+		}
+		/* Stop if last remaining path already covered by best candidate(s) */
+		if (annotated_cnt && !list) {
+			int best_depth = INT_MAX;
+			unsigned best_within = 0;
+			for (cur_match = 0; cur_match < match_cnt; cur_match++) {
+				struct possible_tag *t = &all_matches[cur_match];
+				if (t->depth < best_depth) {
+					best_depth = t->depth;
+					best_within = t->flag_within;
+				} else if (t->depth == best_depth) {
+					best_within |= t->flag_within;
+				}
+			}
+			if ((c->object.flags & best_within) == best_within) {
+				if (debug)
+					fprintf(stderr, _("finished search at %s\n"),
+						oid_to_hex(&c->object.oid));
+				break;
+			}
+		}
+		while (parents) {
+			struct commit *p = parents->item;
+			repo_parse_commit(the_repository, p);
+			if (!(p->object.flags & SEEN))
+				commit_list_insert_by_date(p, &list);
+			p->object.flags |= c->object.flags;
+			parents = parents->next;
+
+			if (first_parent)
+				break;
+		}
+	}
+
+	if (!match_cnt) {
+		struct object_id *cmit_oid = &cmit->object.oid;
+		if (always) {
+			strbuf_add_unique_abbrev(dst, cmit_oid, abbrev);
+			if (suffix)
+				strbuf_addstr(dst, suffix);
+			return;
+		}
+		if (unannotated_cnt)
+			die(_("No annotated tags can describe '%s'.\n"
+			    "However, there were unannotated tags: try --tags."),
+			    oid_to_hex(cmit_oid));
+		else
+			die(_("No tags can describe '%s'.\n"
+			    "Try --always, or create some tags."),
+			    oid_to_hex(cmit_oid));
+	}
+
+	QSORT(all_matches, match_cnt, compare_pt);
+
+	if (gave_up_on) {
+		commit_list_insert_by_date(gave_up_on, &list);
+		seen_commits--;
+	}
+	seen_commits += finish_depth_computation(&list, &all_matches[0]);
+	free_commit_list(list);
+
+	if (debug) {
+		static int label_width = -1;
+		if (label_width < 0) {
+			int i, w;
+			for (i = 0; i < ARRAY_SIZE(prio_names); i++) {
+				w = strlen(_(prio_names[i]));
+				if (label_width < w)
+					label_width = w;
+			}
+		}
+		for (cur_match = 0; cur_match < match_cnt; cur_match++) {
+			struct possible_tag *t = &all_matches[cur_match];
+			fprintf(stderr, " %-*s %8d %s\n",
+				label_width, _(prio_names[t->name->prio]),
+				t->depth, t->name->path);
+		}
+		fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
+		if (gave_up_on) {
+			fprintf(stderr,
+				_("found %i tags; gave up search at %s\n"),
+				max_candidates,
+				oid_to_hex(&gave_up_on->object.oid));
+		}
+	}
+
+	append_name(all_matches[0].name, dst);
+	if (all_matches[0].name->misnamed || abbrev)
+		append_suffix(all_matches[0].depth, &cmit->object.oid, dst);
+	if (suffix)
+		strbuf_addstr(dst, suffix);
+}
+
+struct process_commit_data {
+	struct object_id current_commit;
+	struct object_id looking_for;
+	struct strbuf *dst;
+	struct rev_info *revs;
+};
+
+static void process_commit(struct commit *commit, void *data)
+{
+	struct process_commit_data *pcd = data;
+	pcd->current_commit = commit->object.oid;
+}
+
+static void process_object(struct object *obj, const char *path, void *data)
+{
+	struct process_commit_data *pcd = data;
+
+	if (oideq(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
+		reset_revision_walk();
+		describe_commit(&pcd->current_commit, pcd->dst);
+		strbuf_addf(pcd->dst, ":%s", path);
+		free_commit_list(pcd->revs->commits);
+		pcd->revs->commits = NULL;
+	}
+}
+
+static void describe_blob(struct object_id oid, struct strbuf *dst)
+{
+	struct rev_info revs;
+	struct strvec args = STRVEC_INIT;
+	struct process_commit_data pcd = { *null_oid(), oid, dst, &revs};
+
+	strvec_pushl(&args, "internal: The first arg is not parsed",
+		     "--objects", "--in-commit-order", "--reverse", "HEAD",
+		     NULL);
+
+	repo_init_revisions(the_repository, &revs, NULL);
+	if (setup_revisions(args.nr, args.v, &revs, NULL) > 1)
+		BUG("setup_revisions could not handle all args?");
+
+	if (prepare_revision_walk(&revs))
+		die("revision walk setup failed");
+
+	traverse_commit_list(&revs, process_commit, process_object, &pcd);
+	reset_revision_walk();
+	release_revisions(&revs);
+	strvec_clear(&args);
+}
+
+static void describe(const char *arg, int last_one)
+{
+	struct object_id oid;
+	struct commit *cmit;
+	struct strbuf sb = STRBUF_INIT;
+
+	if (debug)
+		fprintf(stderr, _("describe %s\n"), arg);
+
+	if (repo_get_oid(the_repository, arg, &oid))
+		die(_("Not a valid object name %s"), arg);
+	cmit = lookup_commit_reference_gently(the_repository, &oid, 1);
+
+	if (cmit)
+		describe_commit(&oid, &sb);
+	else if (oid_object_info(the_repository, &oid, NULL) == OBJ_BLOB)
+		describe_blob(oid, &sb);
+	else
+		die(_("%s is neither a commit nor blob"), arg);
+
+	puts(sb.buf);
+
+	if (!last_one)
+		clear_commit_marks(cmit, -1);
+
+	strbuf_release(&sb);
+}
+
+static int option_parse_exact_match(const struct option *opt, const char *arg,
+				    int unset)
+{
+	int *val = opt->value;
+
+	BUG_ON_OPT_ARG(arg);
+
+	*val = unset ? DEFAULT_CANDIDATES : 0;
+	return 0;
+}
+
+int cmd_describe(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED )
+{
+	int contains = 0;
+	struct option options[] = {
+		OPT_BOOL(0, "contains",   &contains, N_("find the tag that comes after the commit")),
+		OPT_BOOL(0, "debug",      &debug, N_("debug search strategy on stderr")),
+		OPT_BOOL(0, "all",        &all, N_("use any ref")),
+		OPT_BOOL(0, "tags",       &tags, N_("use any tag, even unannotated")),
+		OPT_BOOL(0, "long",       &longformat, N_("always use long format")),
+		OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
+		OPT__ABBREV(&abbrev),
+		OPT_CALLBACK_F(0, "exact-match", &max_candidates, NULL,
+			       N_("only output exact matches"),
+			       PARSE_OPT_NOARG, option_parse_exact_match),
+		OPT_INTEGER(0, "candidates", &max_candidates,
+			    N_("consider <n> most recent tags (default: 10)")),
+		OPT_STRING_LIST(0, "match", &patterns, N_("pattern"),
+			   N_("only consider tags matching <pattern>")),
+		OPT_STRING_LIST(0, "exclude", &exclude_patterns, N_("pattern"),
+			   N_("do not consider tags matching <pattern>")),
+		OPT_BOOL(0, "always",        &always,
+			N_("show abbreviated commit object as fallback")),
+		{OPTION_STRING, 0, "dirty",  &dirty, N_("mark"),
+			N_("append <mark> on dirty working tree (default: \"-dirty\")"),
+			PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
+		{OPTION_STRING, 0, "broken",  &broken, N_("mark"),
+			N_("append <mark> on broken working tree (default: \"-broken\")"),
+			PARSE_OPT_OPTARG, NULL, (intptr_t) "-broken"},
+		OPT_END(),
+	};
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
+	if (abbrev < 0)
+		abbrev = DEFAULT_ABBREV;
+
+	if (max_candidates < 0)
+		max_candidates = 0;
+	else if (max_candidates > MAX_TAGS)
+		max_candidates = MAX_TAGS;
+
+	save_commit_buffer = 0;
+
+	if (longformat && abbrev == 0)
+		die(_("options '%s' and '%s' cannot be used together"), "--long", "--abbrev=0");
+
+	if (contains) {
+		struct string_list_item *item;
+		struct strvec args;
+		const char **argv_copy;
+		int ret;
+
+		strvec_init(&args);
+		strvec_pushl(&args, "name-rev",
+			     "--peel-tag", "--name-only", "--no-undefined",
+			     NULL);
+		if (always)
+			strvec_push(&args, "--always");
+		if (!all) {
+			strvec_push(&args, "--tags");
+			for_each_string_list_item(item, &patterns)
+				strvec_pushf(&args, "--refs=refs/tags/%s", item->string);
+			for_each_string_list_item(item, &exclude_patterns)
+				strvec_pushf(&args, "--exclude=refs/tags/%s", item->string);
+		}
+		if (argc)
+			strvec_pushv(&args, argv);
+		else
+			strvec_push(&args, "HEAD");
+
+		/*
+		 * `cmd_name_rev()` modifies the array, so we'd leak its
+		 * contained strings if we didn't do a copy here.
+		 */
+		ALLOC_ARRAY(argv_copy, args.nr + 1);
+		for (size_t i = 0; i < args.nr; i++)
+			argv_copy[i] = args.v[i];
+		argv_copy[args.nr] = NULL;
+
+		ret = cmd_name_rev(args.nr, argv_copy, prefix, the_repository);
+
+		strvec_clear(&args);
+		free(argv_copy);
+		return ret;
+	}
+
+	hashmap_init(&names, commit_name_neq, NULL, 0);
+	refs_for_each_rawref(get_main_ref_store(the_repository), get_name,
+			     NULL);
+	if (!hashmap_get_size(&names) && !always)
+		die(_("No names found, cannot describe anything."));
+
+	if (argc == 0) {
+		if (broken) {
+			struct child_process cp = CHILD_PROCESS_INIT;
+
+			strvec_pushv(&cp.args, update_index_args);
+			cp.git_cmd = 1;
+			cp.no_stdin = 1;
+			cp.no_stdout = 1;
+			run_command(&cp);
+
+			child_process_init(&cp);
+			strvec_pushv(&cp.args, diff_index_args);
+			cp.git_cmd = 1;
+			cp.no_stdin = 1;
+			cp.no_stdout = 1;
+
+			if (!dirty)
+				dirty = "-dirty";
+
+			switch (run_command(&cp)) {
+			case 0:
+				suffix = NULL;
+				break;
+			case 1:
+				suffix = dirty;
+				break;
+			default:
+				/* diff-index aborted abnormally */
+				suffix = broken;
+			}
+		} else if (dirty) {
+			struct lock_file index_lock = LOCK_INIT;
+			struct rev_info revs;
+			int fd;
+
+			setup_work_tree();
+			prepare_repo_settings(the_repository);
+			the_repository->settings.command_requires_full_index = 0;
+			repo_read_index(the_repository);
+			refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED,
+				      NULL, NULL, NULL);
+			fd = repo_hold_locked_index(the_repository,
+						    &index_lock, 0);
+			if (0 <= fd)
+				repo_update_index_if_able(the_repository, &index_lock);
+
+			repo_init_revisions(the_repository, &revs, prefix);
+
+			if (setup_revisions(ARRAY_SIZE(diff_index_args) - 1,
+					    diff_index_args, &revs, NULL) != 1)
+				BUG("malformed internal diff-index command line");
+			run_diff_index(&revs, 0);
+
+			if (!diff_result_code(&revs))
+				suffix = NULL;
+			else
+				suffix = dirty;
+			release_revisions(&revs);
+		}
+		describe("HEAD", 1);
+	} else if (dirty) {
+		die(_("option '%s' and commit-ishes cannot be used together"), "--dirty");
+	} else if (broken) {
+		die(_("option '%s' and commit-ishes cannot be used together"), "--broken");
+	} else {
+		while (argc-- > 0)
+			describe(*argv++, argc == 0);
+	}
+	return 0;
+}
diff --git a/builtin/diagnose.c b/builtin/diagnose.c
new file mode 100644
index 0000000000..33c39bd598
--- /dev/null
+++ b/builtin/diagnose.c
@@ -0,0 +1,70 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "object-file.h"
+#include "parse-options.h"
+#include "diagnose.h"
+
+static const char * const diagnose_usage[] = {
+	N_("git diagnose [(-o | --output-directory) <path>] [(-s | --suffix) <format>]\n"
+	   "             [--mode=<mode>]"),
+	NULL
+};
+
+int cmd_diagnose(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct strbuf zip_path = STRBUF_INIT;
+	time_t now = time(NULL);
+	struct tm tm;
+	enum diagnose_mode mode = DIAGNOSE_STATS;
+	char *option_output = NULL;
+	const char *option_suffix = "%Y-%m-%d-%H%M";
+	char *prefixed_filename;
+
+	const struct option diagnose_options[] = {
+		OPT_STRING('o', "output-directory", &option_output, N_("path"),
+			   N_("specify a destination for the diagnostics archive")),
+		OPT_STRING('s', "suffix", &option_suffix, N_("format"),
+			   N_("specify a strftime format suffix for the filename")),
+		OPT_CALLBACK_F(0, "mode", &mode, "(stats|all)",
+			       N_("specify the content of the diagnostic archive"),
+			       PARSE_OPT_NONEG, option_parse_diagnose),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, diagnose_options,
+			     diagnose_usage, 0);
+
+	/* Prepare the path to put the result */
+	prefixed_filename = prefix_filename(prefix,
+					    option_output ? option_output : "");
+	strbuf_addstr(&zip_path, prefixed_filename);
+	strbuf_complete(&zip_path, '/');
+
+	strbuf_addstr(&zip_path, "git-diagnostics-");
+	strbuf_addftime(&zip_path, option_suffix, localtime_r(&now, &tm), 0, 0);
+	strbuf_addstr(&zip_path, ".zip");
+
+	switch (safe_create_leading_directories(zip_path.buf)) {
+	case SCLD_OK:
+	case SCLD_EXISTS:
+		break;
+	default:
+		die_errno(_("could not create leading directories for '%s'"),
+			  zip_path.buf);
+	}
+
+	/* Prepare diagnostics */
+	if (create_diagnostics_archive(the_repository, &zip_path, mode))
+		die_errno(_("unable to create diagnostics archive %s"),
+			  zip_path.buf);
+
+	free(prefixed_filename);
+	strbuf_release(&zip_path);
+	return 0;
+}
diff --git a/builtin/diff-files.c b/builtin/diff-files.c
new file mode 100644
index 0000000000..99b1749723
--- /dev/null
+++ b/builtin/diff-files.c
@@ -0,0 +1,93 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "diff.h"
+#include "diff-merges.h"
+#include "commit.h"
+#include "preload-index.h"
+#include "revision.h"
+
+static const char diff_files_usage[] =
+"git diff-files [-q] [-0 | -1 | -2 | -3 | -c | --cc] [<common-diff-options>] [<path>...]"
+"\n"
+COMMON_DIFF_OPTIONS_HELP;
+
+int cmd_diff_files(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct rev_info rev;
+	int result;
+	unsigned options = 0;
+
+	show_usage_if_asked(argc, argv, diff_files_usage);
+
+	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	repo_init_revisions(the_repository, &rev, prefix);
+	rev.abbrev = 0;
+
+	/*
+	 * Consider "intent-to-add" files as new by default, unless
+	 * explicitly specified in the command line or anywhere else.
+	 */
+	rev.diffopt.ita_invisible_in_index = 1;
+
+	prefix = precompose_argv_prefix(argc, argv, prefix);
+
+	argc = setup_revisions(argc, argv, &rev, NULL);
+	while (1 < argc && argv[1][0] == '-') {
+		if (!strcmp(argv[1], "--base"))
+			rev.max_count = 1;
+		else if (!strcmp(argv[1], "--ours"))
+			rev.max_count = 2;
+		else if (!strcmp(argv[1], "--theirs"))
+			rev.max_count = 3;
+		else if (!strcmp(argv[1], "-q"))
+			options |= DIFF_SILENT_ON_REMOVED;
+		else
+			usage(diff_files_usage);
+		argv++; argc--;
+	}
+	if (!rev.diffopt.output_format)
+		rev.diffopt.output_format = DIFF_FORMAT_RAW;
+	rev.diffopt.rotate_to_strict = 1;
+
+	/*
+	 * Make sure there are NO revision (i.e. pending object) parameter,
+	 * rev.max_count is reasonable (0 <= n <= 3), and
+	 * there is no other revision filtering parameters.
+	 */
+	if (rev.pending.nr ||
+	    rev.min_age != -1 || rev.max_age != -1 ||
+	    3 < rev.max_count)
+		usage(diff_files_usage);
+
+	/*
+	 * "diff-files --base -p" should not combine merges because it
+	 * was not asked to.  "diff-files -c -p" should not densify
+	 * (the user should ask with "diff-files --cc" explicitly).
+	 */
+	if (rev.max_count == -1 &&
+	    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))
+		diff_merges_set_dense_combined_if_unset(&rev);
+
+	if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0)
+		die_errno("repo_read_index_preload");
+	run_diff_files(&rev, options);
+	result = diff_result_code(&rev);
+	release_revisions(&rev);
+	return result;
+}
diff --git a/builtin/diff-index.c b/builtin/diff-index.c
new file mode 100644
index 0000000000..81c0bc8ed7
--- /dev/null
+++ b/builtin/diff-index.c
@@ -0,0 +1,85 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "diff.h"
+#include "diff-merges.h"
+#include "commit.h"
+#include "preload-index.h"
+#include "revision.h"
+#include "setup.h"
+
+static const char diff_cache_usage[] =
+"git diff-index [-m] [--cached] [--merge-base] "
+"[<common-diff-options>] <tree-ish> [<path>...]"
+"\n"
+COMMON_DIFF_OPTIONS_HELP;
+
+int cmd_diff_index(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct rev_info rev;
+	unsigned int option = 0;
+	int i;
+	int result;
+
+	show_usage_if_asked(argc, argv, diff_cache_usage);
+
+	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	repo_init_revisions(the_repository, &rev, prefix);
+	rev.abbrev = 0;
+	prefix = precompose_argv_prefix(argc, argv, prefix);
+
+	/*
+	 * We need (some of) diff for merges options (e.g., --cc), and we need
+	 * to avoid conflict with our own meaning of "-m".
+	 */
+	diff_merges_suppress_m_parsing();
+
+	argc = setup_revisions(argc, argv, &rev, NULL);
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (!strcmp(arg, "--cached"))
+			option |= DIFF_INDEX_CACHED;
+		else if (!strcmp(arg, "--merge-base"))
+			option |= DIFF_INDEX_MERGE_BASE;
+		else if (!strcmp(arg, "-m"))
+			rev.match_missing = 1;
+		else
+			usage(diff_cache_usage);
+	}
+	if (!rev.diffopt.output_format)
+		rev.diffopt.output_format = DIFF_FORMAT_RAW;
+
+	rev.diffopt.rotate_to_strict = 1;
+
+	/*
+	 * Make sure there is one revision (i.e. pending object),
+	 * and there is no revision filtering parameters.
+	 */
+	if (rev.pending.nr != 1 ||
+	    rev.max_count != -1 || rev.min_age != -1 || rev.max_age != -1)
+		usage(diff_cache_usage);
+	if (!(option & DIFF_INDEX_CACHED)) {
+		setup_work_tree();
+		if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
+			perror("repo_read_index_preload");
+			return -1;
+		}
+	} else if (repo_read_index(the_repository) < 0) {
+		perror("repo_read_index");
+		return -1;
+	}
+	run_diff_index(&rev, option);
+	result = diff_result_code(&rev);
+	release_revisions(&rev);
+	return result;
+}
diff --git a/builtin/diff-tree.c b/builtin/diff-tree.c
new file mode 100644
index 0000000000..e31cc797fe
--- /dev/null
+++ b/builtin/diff-tree.c
@@ -0,0 +1,238 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "diff.h"
+#include "commit.h"
+#include "gettext.h"
+#include "hex.h"
+#include "log-tree.h"
+#include "read-cache-ll.h"
+#include "revision.h"
+#include "tmp-objdir.h"
+#include "tree.h"
+
+static struct rev_info log_tree_opt;
+
+static int diff_tree_commit_oid(const struct object_id *oid)
+{
+	struct commit *commit = lookup_commit_reference(the_repository, oid);
+	if (!commit)
+		return -1;
+	return log_tree_commit(&log_tree_opt, commit);
+}
+
+/* Diff one or more commits. */
+static int stdin_diff_commit(struct commit *commit, const char *p)
+{
+	struct object_id oid;
+	struct commit_list **pptr = NULL;
+
+	/* Graft the fake parents locally to the commit */
+	while (isspace(*p++) && !parse_oid_hex(p, &oid, &p)) {
+		struct commit *parent = lookup_commit(the_repository, &oid);
+		if (!pptr) {
+			/* Free the real parent list */
+			free_commit_list(commit->parents);
+			commit->parents = NULL;
+			pptr = &(commit->parents);
+		}
+		if (parent) {
+			pptr = &commit_list_insert(parent, pptr)->next;
+		}
+	}
+	return log_tree_commit(&log_tree_opt, commit);
+}
+
+/* Diff two trees. */
+static int stdin_diff_trees(struct tree *tree1, const char *p)
+{
+	struct object_id oid;
+	struct tree *tree2;
+	if (!isspace(*p++) || parse_oid_hex(p, &oid, &p) || *p)
+		return error("Need exactly two trees, separated by a space");
+	tree2 = lookup_tree(the_repository, &oid);
+	if (!tree2 || parse_tree(tree2))
+		return -1;
+	printf("%s %s\n", oid_to_hex(&tree1->object.oid),
+			  oid_to_hex(&tree2->object.oid));
+	diff_tree_oid(&tree1->object.oid, &tree2->object.oid,
+		      "", &log_tree_opt.diffopt);
+	log_tree_diff_flush(&log_tree_opt);
+	return 0;
+}
+
+static int diff_tree_stdin(char *line)
+{
+	int len = strlen(line);
+	struct object_id oid;
+	struct object *obj;
+	const char *p;
+
+	if (!len || line[len-1] != '\n')
+		return -1;
+	line[len-1] = 0;
+	if (parse_oid_hex(line, &oid, &p))
+		return -1;
+	obj = parse_object(the_repository, &oid);
+	if (!obj)
+		return -1;
+	if (obj->type == OBJ_COMMIT)
+		return stdin_diff_commit((struct commit *)obj, p);
+	if (obj->type == OBJ_TREE)
+		return stdin_diff_trees((struct tree *)obj, p);
+	error("Object %s is a %s, not a commit or tree",
+	      oid_to_hex(&oid), type_name(obj->type));
+	return -1;
+}
+
+static const char diff_tree_usage[] =
+"git diff-tree [--stdin] [-m] [-s] [-v] [--no-commit-id] [--pretty]\n"
+"              [-t] [-r] [-c | --cc] [--combined-all-paths] [--root] [--merge-base]\n"
+"              [<common-diff-options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+"\n"
+"  -r            diff recursively\n"
+"  -c            show combined diff for merge commits\n"
+"  --cc          show combined diff for merge commits removing uninteresting hunks\n"
+"  --combined-all-paths\n"
+"                show name of file in all parents for combined diffs\n"
+"  --root        include the initial commit as diff against /dev/null\n"
+COMMON_DIFF_OPTIONS_HELP;
+
+static void diff_tree_tweak_rev(struct rev_info *rev)
+{
+	if (!rev->diffopt.output_format) {
+		if (rev->dense_combined_merges)
+			rev->diffopt.output_format = DIFF_FORMAT_PATCH;
+		else
+			rev->diffopt.output_format = DIFF_FORMAT_RAW;
+	}
+}
+
+int cmd_diff_tree(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	char line[1000];
+	struct object *tree1, *tree2;
+	static struct rev_info *opt = &log_tree_opt;
+	struct setup_revision_opt s_r_opt;
+	struct userformat_want w;
+	int read_stdin = 0;
+	int merge_base = 0;
+
+	show_usage_if_asked(argc, argv, diff_tree_usage);
+
+	git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	repo_init_revisions(the_repository, opt, prefix);
+	if (repo_read_index(the_repository) < 0)
+		die(_("index file corrupt"));
+	opt->abbrev = 0;
+	opt->diff = 1;
+	opt->disable_stdin = 1;
+	memset(&s_r_opt, 0, sizeof(s_r_opt));
+	s_r_opt.tweak = diff_tree_tweak_rev;
+
+	prefix = precompose_argv_prefix(argc, argv, prefix);
+	argc = setup_revisions(argc, argv, opt, &s_r_opt);
+
+	memset(&w, 0, sizeof(w));
+	userformat_find_requirements(NULL, &w);
+
+	if (!opt->show_notes_given && w.notes)
+		opt->show_notes = 1;
+	if (opt->show_notes)
+		load_display_notes(&opt->notes_opt);
+
+	while (--argc > 0) {
+		const char *arg = *++argv;
+
+		if (!strcmp(arg, "--stdin")) {
+			read_stdin = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--merge-base")) {
+			merge_base = 1;
+			continue;
+		}
+		usage(diff_tree_usage);
+	}
+
+	if (read_stdin && merge_base)
+		die(_("options '%s' and '%s' cannot be used together"), "--stdin", "--merge-base");
+	if (merge_base && opt->pending.nr != 2)
+		die(_("--merge-base only works with two commits"));
+
+	opt->diffopt.rotate_to_strict = 1;
+
+	/*
+	 * NOTE!  We expect "a..b" to expand to "^a b" but it is
+	 * perfectly valid for revision range parser to yield "b ^a",
+	 * which means the same thing. If we get the latter, i.e. the
+	 * second one is marked UNINTERESTING, we recover the original
+	 * order the user gave, i.e. "a..b", by swapping the trees.
+	 */
+	switch (opt->pending.nr) {
+	case 0:
+		if (!read_stdin)
+			usage(diff_tree_usage);
+		break;
+	case 1:
+		tree1 = opt->pending.objects[0].item;
+		diff_tree_commit_oid(&tree1->oid);
+		break;
+	case 2:
+		tree1 = opt->pending.objects[0].item;
+		tree2 = opt->pending.objects[1].item;
+		if (merge_base) {
+			struct object_id oid;
+
+			diff_get_merge_base(opt, &oid);
+			tree1 = lookup_object(the_repository, &oid);
+		} else if (tree2->flags & UNINTERESTING) {
+			SWAP(tree2, tree1);
+		}
+		diff_tree_oid(&tree1->oid, &tree2->oid, "", &opt->diffopt);
+		log_tree_diff_flush(opt);
+		break;
+	}
+
+	if (read_stdin) {
+		int saved_nrl = 0;
+		int saved_dcctc = 0;
+
+		opt->diffopt.rotate_to_strict = 0;
+		opt->diffopt.no_free = 1;
+		if (opt->diffopt.detect_rename) {
+			if (the_repository->index->cache)
+				repo_read_index(the_repository);
+			opt->diffopt.setup |= DIFF_SETUP_USE_SIZE_CACHE;
+		}
+		while (fgets(line, sizeof(line), stdin)) {
+			struct object_id oid;
+
+			if (get_oid_hex(line, &oid)) {
+				fputs(line, stdout);
+				fflush(stdout);
+			}
+			else {
+				diff_tree_stdin(line);
+				if (saved_nrl < opt->diffopt.needed_rename_limit)
+					saved_nrl = opt->diffopt.needed_rename_limit;
+				if (opt->diffopt.degraded_cc_to_c)
+					saved_dcctc = 1;
+			}
+		}
+		opt->diffopt.degraded_cc_to_c = saved_dcctc;
+		opt->diffopt.needed_rename_limit = saved_nrl;
+		opt->diffopt.no_free = 0;
+		diff_free(&opt->diffopt);
+	}
+
+	return diff_result_code(opt);
+}
diff --git a/builtin/diff.c b/builtin/diff.c
new file mode 100644
index 0000000000..a4fffee42c
--- /dev/null
+++ b/builtin/diff.c
@@ -0,0 +1,635 @@
+/*
+ * Builtin "git diff"
+ *
+ * Copyright (c) 2006 Junio C Hamano
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "ewah/ewok.h"
+#include "lockfile.h"
+#include "color.h"
+#include "commit.h"
+#include "gettext.h"
+#include "tag.h"
+#include "diff.h"
+#include "diff-merges.h"
+#include "diffcore.h"
+#include "preload-index.h"
+#include "read-cache-ll.h"
+#include "revision.h"
+#include "log-tree.h"
+#include "setup.h"
+#include "oid-array.h"
+#include "tree.h"
+
+#define DIFF_NO_INDEX_EXPLICIT 1
+#define DIFF_NO_INDEX_IMPLICIT 2
+
+static const char builtin_diff_usage[] =
+"git diff [<options>] [<commit>] [--] [<path>...]\n"
+"   or: git diff [<options>] --cached [--merge-base] [<commit>] [--] [<path>...]\n"
+"   or: git diff [<options>] [--merge-base] <commit> [<commit>...] <commit> [--] [<path>...]\n"
+"   or: git diff [<options>] <commit>...<commit> [--] [<path>...]\n"
+"   or: git diff [<options>] <blob> <blob>\n"
+"   or: git diff [<options>] --no-index [--] <path> <path>"
+"\n"
+COMMON_DIFF_OPTIONS_HELP;
+
+static const char *blob_path(struct object_array_entry *entry)
+{
+	return entry->path ? entry->path : entry->name;
+}
+
+static void stuff_change(struct diff_options *opt,
+			 unsigned old_mode, unsigned new_mode,
+			 const struct object_id *old_oid,
+			 const struct object_id *new_oid,
+			 int old_oid_valid,
+			 int new_oid_valid,
+			 const char *old_path,
+			 const char *new_path)
+{
+	struct diff_filespec *one, *two;
+
+	if (!is_null_oid(old_oid) && !is_null_oid(new_oid) &&
+	    oideq(old_oid, new_oid) && (old_mode == new_mode))
+		return;
+
+	if (opt->flags.reverse_diff) {
+		SWAP(old_mode, new_mode);
+		SWAP(old_oid, new_oid);
+		SWAP(old_path, new_path);
+	}
+
+	if (opt->prefix &&
+	    (strncmp(old_path, opt->prefix, opt->prefix_length) ||
+	     strncmp(new_path, opt->prefix, opt->prefix_length)))
+		return;
+
+	one = alloc_filespec(old_path);
+	two = alloc_filespec(new_path);
+	fill_filespec(one, old_oid, old_oid_valid, old_mode);
+	fill_filespec(two, new_oid, new_oid_valid, new_mode);
+
+	diff_queue(&diff_queued_diff, one, two);
+}
+
+static void builtin_diff_b_f(struct rev_info *revs,
+			     int argc, const char **argv UNUSED,
+			     struct object_array_entry **blob)
+{
+	/* Blob vs file in the working tree*/
+	struct stat st;
+	const char *path;
+
+	if (argc > 1)
+		usage(builtin_diff_usage);
+
+	GUARD_PATHSPEC(&revs->prune_data, PATHSPEC_FROMTOP | PATHSPEC_LITERAL);
+	path = revs->prune_data.items[0].match;
+
+	if (lstat(path, &st))
+		die_errno(_("failed to stat '%s'"), path);
+	if (!(S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)))
+		die(_("'%s': not a regular file or symlink"), path);
+
+	diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/");
+
+	if (blob[0]->mode == S_IFINVALID)
+		blob[0]->mode = canon_mode(st.st_mode);
+
+	stuff_change(&revs->diffopt,
+		     blob[0]->mode, canon_mode(st.st_mode),
+		     &blob[0]->item->oid, null_oid(),
+		     1, 0,
+		     blob[0]->path ? blob[0]->path : path,
+		     path);
+	diffcore_std(&revs->diffopt);
+	diff_flush(&revs->diffopt);
+}
+
+static void builtin_diff_blobs(struct rev_info *revs,
+			       int argc, const char **argv UNUSED,
+			       struct object_array_entry **blob)
+{
+	const unsigned mode = canon_mode(S_IFREG | 0644);
+
+	if (argc > 1)
+		usage(builtin_diff_usage);
+
+	if (blob[0]->mode == S_IFINVALID)
+		blob[0]->mode = mode;
+
+	if (blob[1]->mode == S_IFINVALID)
+		blob[1]->mode = mode;
+
+	stuff_change(&revs->diffopt,
+		     blob[0]->mode, blob[1]->mode,
+		     &blob[0]->item->oid, &blob[1]->item->oid,
+		     1, 1,
+		     blob_path(blob[0]), blob_path(blob[1]));
+	diffcore_std(&revs->diffopt);
+	diff_flush(&revs->diffopt);
+}
+
+static void builtin_diff_index(struct rev_info *revs,
+			       int argc, const char **argv)
+{
+	unsigned int option = 0;
+	while (1 < argc) {
+		const char *arg = argv[1];
+		if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged"))
+			option |= DIFF_INDEX_CACHED;
+		else if (!strcmp(arg, "--merge-base"))
+			option |= DIFF_INDEX_MERGE_BASE;
+		else
+			usage(builtin_diff_usage);
+		argv++; argc--;
+	}
+	/*
+	 * Make sure there is one revision (i.e. pending object),
+	 * and there is no revision filtering parameters.
+	 */
+	if (revs->pending.nr != 1 ||
+	    revs->max_count != -1 || revs->min_age != -1 ||
+	    revs->max_age != -1)
+		usage(builtin_diff_usage);
+	if (!(option & DIFF_INDEX_CACHED)) {
+		setup_work_tree();
+		if (repo_read_index_preload(the_repository,
+					    &revs->diffopt.pathspec, 0) < 0) {
+			die_errno("repo_read_index_preload");
+		}
+	} else if (repo_read_index(the_repository) < 0) {
+		die_errno("repo_read_cache");
+	}
+	run_diff_index(revs, option);
+}
+
+static void builtin_diff_tree(struct rev_info *revs,
+			      int argc, const char **argv,
+			      struct object_array_entry *ent0,
+			      struct object_array_entry *ent1)
+{
+	const struct object_id *(oid[2]);
+	struct object_id mb_oid;
+	int merge_base = 0;
+
+	while (1 < argc) {
+		const char *arg = argv[1];
+		if (!strcmp(arg, "--merge-base"))
+			merge_base = 1;
+		else
+			usage(builtin_diff_usage);
+		argv++; argc--;
+	}
+
+	if (merge_base) {
+		diff_get_merge_base(revs, &mb_oid);
+		oid[0] = &mb_oid;
+		oid[1] = &revs->pending.objects[1].item->oid;
+	} else {
+		int swap = 0;
+
+		/*
+		 * We saw two trees, ent0 and ent1.  If ent1 is uninteresting,
+		 * swap them.
+		 */
+		if (ent1->item->flags & UNINTERESTING)
+			swap = 1;
+		oid[swap] = &ent0->item->oid;
+		oid[1 - swap] = &ent1->item->oid;
+	}
+	diff_tree_oid(oid[0], oid[1], "", &revs->diffopt);
+	log_tree_diff_flush(revs);
+}
+
+static void builtin_diff_combined(struct rev_info *revs,
+				  int argc, const char **argv UNUSED,
+				  struct object_array_entry *ent,
+				  int ents, int first_non_parent)
+{
+	struct oid_array parents = OID_ARRAY_INIT;
+	int i;
+
+	if (argc > 1)
+		usage(builtin_diff_usage);
+
+	if (first_non_parent < 0)
+		die(_("no merge given, only parents."));
+	if (first_non_parent >= ents)
+		BUG("first_non_parent out of range: %d", first_non_parent);
+
+	diff_merges_set_dense_combined_if_unset(revs);
+
+	for (i = 0; i < ents; i++) {
+		if (i != first_non_parent)
+			oid_array_append(&parents, &ent[i].item->oid);
+	}
+	diff_tree_combined(&ent[first_non_parent].item->oid, &parents, revs);
+	oid_array_clear(&parents);
+}
+
+static void refresh_index_quietly(void)
+{
+	struct lock_file lock_file = LOCK_INIT;
+	int fd;
+
+	fd = repo_hold_locked_index(the_repository, &lock_file, 0);
+	if (fd < 0)
+		return;
+	discard_index(the_repository->index);
+	repo_read_index(the_repository);
+	refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, NULL, NULL,
+		      NULL);
+	repo_update_index_if_able(the_repository, &lock_file);
+}
+
+static void builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
+{
+	unsigned int options = 0;
+
+	while (1 < argc && argv[1][0] == '-') {
+		if (!strcmp(argv[1], "--base"))
+			revs->max_count = 1;
+		else if (!strcmp(argv[1], "--ours"))
+			revs->max_count = 2;
+		else if (!strcmp(argv[1], "--theirs"))
+			revs->max_count = 3;
+		else if (!strcmp(argv[1], "-q"))
+			options |= DIFF_SILENT_ON_REMOVED;
+		else if (!strcmp(argv[1], "-h"))
+			usage(builtin_diff_usage);
+		else {
+			error(_("invalid option: %s"), argv[1]);
+			usage(builtin_diff_usage);
+		}
+		argv++; argc--;
+	}
+
+	/*
+	 * "diff --base" should not combine merges because it was not
+	 * asked to.  "diff -c" should not densify (if the user wants
+	 * dense one, --cc can be explicitly asked for, or just rely
+	 * on the default).
+	 */
+	if (revs->max_count == -1 &&
+	    (revs->diffopt.output_format & DIFF_FORMAT_PATCH))
+		diff_merges_set_dense_combined_if_unset(revs);
+
+	setup_work_tree();
+	if (repo_read_index_preload(the_repository, &revs->diffopt.pathspec,
+				    0) < 0) {
+		die_errno("repo_read_index_preload");
+	}
+	run_diff_files(revs, options);
+}
+
+struct symdiff {
+	struct bitmap *skip;
+	int warn;
+	const char *base, *left, *right;
+};
+
+/*
+ * Check for symmetric-difference arguments, and if present, arrange
+ * everything we need to know to handle them correctly.  As a bonus,
+ * weed out all bogus range-based revision specifications, e.g.,
+ * "git diff A..B C..D" or "git diff A..B C" get rejected.
+ *
+ * For an actual symmetric diff, *symdiff is set this way:
+ *
+ *  - its skip is non-NULL and marks *all* rev->pending.objects[i]
+ *    indices that the caller should ignore (extra merge bases, of
+ *    which there might be many, and A in A...B).  Note that the
+ *    chosen merge base and right side are NOT marked.
+ *  - warn is set if there are multiple merge bases.
+ *  - base, left, and right point to the names to use in a
+ *    warning about multiple merge bases.
+ *
+ * If there is no symmetric diff argument, sym->skip is NULL and
+ * sym->warn is cleared.  The remaining fields are not set.
+ */
+static void symdiff_prepare(struct rev_info *rev, struct symdiff *sym)
+{
+	int i, is_symdiff = 0, basecount = 0, othercount = 0;
+	int lpos = -1, rpos = -1, basepos = -1;
+	struct bitmap *map = NULL;
+
+	/*
+	 * Use the whence fields to find merge bases and left and
+	 * right parts of symmetric difference, so that we do not
+	 * depend on the order that revisions are parsed.  If there
+	 * are any revs that aren't from these sources, we have a
+	 * "git diff C A...B" or "git diff A...B C" case.  Or we
+	 * could even get "git diff A...B C...E", for instance.
+	 *
+	 * If we don't have just one merge base, we pick one
+	 * at random.
+	 *
+	 * NB: REV_CMD_LEFT, REV_CMD_RIGHT are also used for A..B,
+	 * so we must check for SYMMETRIC_LEFT too.  The two arrays
+	 * rev->pending.objects and rev->cmdline.rev are parallel.
+	 */
+	for (i = 0; i < rev->cmdline.nr; i++) {
+		struct object *obj = rev->pending.objects[i].item;
+		switch (rev->cmdline.rev[i].whence) {
+		case REV_CMD_MERGE_BASE:
+			if (basepos < 0)
+				basepos = i;
+			basecount++;
+			break;		/* do mark all bases */
+		case REV_CMD_LEFT:
+			if (lpos >= 0)
+				usage(builtin_diff_usage);
+			lpos = i;
+			if (obj->flags & SYMMETRIC_LEFT) {
+				is_symdiff = 1;
+				break;	/* do mark A */
+			}
+			continue;
+		case REV_CMD_RIGHT:
+			if (rpos >= 0)
+				usage(builtin_diff_usage);
+			rpos = i;
+			continue;	/* don't mark B */
+		case REV_CMD_PARENTS_ONLY:
+		case REV_CMD_REF:
+		case REV_CMD_REV:
+			othercount++;
+			continue;
+		}
+		if (!map)
+			map = bitmap_new();
+		bitmap_set(map, i);
+	}
+
+	/*
+	 * Forbid any additional revs for both A...B and A..B.
+	 */
+	if (lpos >= 0 && othercount > 0)
+		usage(builtin_diff_usage);
+
+	if (!is_symdiff) {
+		bitmap_free(map);
+		sym->warn = 0;
+		sym->skip = NULL;
+		return;
+	}
+
+	sym->left = rev->pending.objects[lpos].name;
+	sym->right = rev->pending.objects[rpos].name;
+	if (basecount == 0)
+		die(_("%s...%s: no merge base"), sym->left, sym->right);
+	sym->base = rev->pending.objects[basepos].name;
+	bitmap_unset(map, basepos);	/* unmark the base we want */
+	sym->warn = basecount > 1;
+	sym->skip = map;
+}
+
+static void symdiff_release(struct symdiff *sdiff)
+{
+	bitmap_free(sdiff->skip);
+}
+
+int cmd_diff(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
+{
+	int i;
+	struct rev_info rev;
+	struct object_array ent = OBJECT_ARRAY_INIT;
+	int first_non_parent = -1;
+	int blobs = 0, paths = 0;
+	struct object_array_entry *blob[2];
+	int nongit = 0, no_index = 0;
+	int result;
+	struct symdiff sdiff;
+
+	/*
+	 * We could get N tree-ish in the rev.pending_objects list.
+	 * Also there could be M blobs there, and P pathspecs. --cached may
+	 * also be present.
+	 *
+	 * N=0, M=0:
+	 *      cache vs files (diff-files)
+	 *
+	 * N=0, M=0, --cached:
+	 *      HEAD vs cache (diff-index --cached)
+	 *
+	 * N=0, M=2:
+	 *      compare two random blobs.  P must be zero.
+	 *
+	 * N=0, M=1, P=1:
+	 *      compare a blob with a working tree file.
+	 *
+	 * N=1, M=0:
+	 *      tree vs files (diff-index)
+	 *
+	 * N=1, M=0, --cached:
+	 *      tree vs cache (diff-index --cached)
+	 *
+	 * N=2, M=0:
+	 *      tree vs tree (diff-tree)
+	 *
+	 * N=0, M=0, P=2:
+	 *      compare two filesystem entities (aka --no-index).
+	 *
+	 * Other cases are errors.
+	 */
+
+	/* Were we asked to do --no-index explicitly? */
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "--")) {
+			i++;
+			break;
+		}
+		if (!strcmp(argv[i], "--no-index"))
+			no_index = DIFF_NO_INDEX_EXPLICIT;
+		if (argv[i][0] != '-')
+			break;
+	}
+
+	prefix = setup_git_directory_gently(&nongit);
+
+	if (!nongit) {
+		prepare_repo_settings(the_repository);
+		the_repository->settings.command_requires_full_index = 0;
+	}
+
+	if (!no_index) {
+		/*
+		 * Treat git diff with at least one path outside of the
+		 * repo the same as if the command would have been executed
+		 * outside of a git repository.  In this case it behaves
+		 * the same way as "git diff --no-index <a> <b>", which acts
+		 * as a colourful "diff" replacement.
+		 */
+		if (nongit || ((argc == i + 2) &&
+			       (!path_inside_repo(prefix, argv[i]) ||
+				!path_inside_repo(prefix, argv[i + 1]))))
+			no_index = DIFF_NO_INDEX_IMPLICIT;
+	}
+
+	/*
+	 * When operating outside of a Git repository we need to have a hash
+	 * algorithm at hand so that we can generate the blob hashes. We
+	 * default to SHA1 here, but may eventually want to change this to be
+	 * configurable via a command line option.
+	 */
+	if (nongit)
+		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
+	init_diff_ui_defaults();
+	git_config(git_diff_ui_config, NULL);
+	prefix = precompose_argv_prefix(argc, argv, prefix);
+
+	repo_init_revisions(the_repository, &rev, prefix);
+
+	/* Set up defaults that will apply to both no-index and regular diffs. */
+	init_diffstat_widths(&rev.diffopt);
+	rev.diffopt.flags.allow_external = 1;
+	rev.diffopt.flags.allow_textconv = 1;
+
+	/* If this is a no-index diff, just run it and exit there. */
+	if (no_index)
+		exit(diff_no_index(&rev, no_index == DIFF_NO_INDEX_IMPLICIT,
+				   argc, argv));
+
+
+	/*
+	 * Otherwise, we are doing the usual "git" diff; set up any
+	 * further defaults that apply to regular diffs.
+	 */
+	rev.diffopt.skip_stat_unmatch = !!diff_auto_refresh_index;
+
+	/*
+	 * Default to intent-to-add entries invisible in the
+	 * index. This makes them show up as new files in diff-files
+	 * and not at all in diff-cached.
+	 */
+	rev.diffopt.ita_invisible_in_index = 1;
+
+	if (nongit)
+		die(_("Not a git repository"));
+	argc = setup_revisions(argc, argv, &rev, NULL);
+	if (!rev.diffopt.output_format) {
+		rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+		diff_setup_done(&rev.diffopt);
+	}
+
+	rev.diffopt.flags.recursive = 1;
+	rev.diffopt.rotate_to_strict = 1;
+
+	setup_diff_pager(&rev.diffopt);
+
+	/*
+	 * Do we have --cached and not have a pending object, then
+	 * default to HEAD by hand.  Eek.
+	 */
+	if (!rev.pending.nr) {
+		int i;
+		for (i = 1; i < argc; i++) {
+			const char *arg = argv[i];
+			if (!strcmp(arg, "--"))
+				break;
+			else if (!strcmp(arg, "--cached") ||
+				 !strcmp(arg, "--staged")) {
+				add_head_to_pending(&rev);
+				if (!rev.pending.nr) {
+					struct tree *tree;
+					tree = lookup_tree(the_repository,
+							   the_repository->hash_algo->empty_tree);
+					add_pending_object(&rev, &tree->object, "HEAD");
+				}
+				break;
+			}
+		}
+	}
+
+	symdiff_prepare(&rev, &sdiff);
+	for (i = 0; i < rev.pending.nr; i++) {
+		struct object_array_entry *entry = &rev.pending.objects[i];
+		struct object *obj = entry->item;
+		const char *name = entry->name;
+		int flags = (obj->flags & UNINTERESTING);
+		if (!obj->parsed)
+			obj = parse_object(the_repository, &obj->oid);
+		obj = deref_tag(the_repository, obj, NULL, 0);
+		if (!obj)
+			die(_("invalid object '%s' given."), name);
+		if (obj->type == OBJ_COMMIT)
+			obj = &repo_get_commit_tree(the_repository,
+						    ((struct commit *)obj))->object;
+
+		if (obj->type == OBJ_TREE) {
+			if (sdiff.skip && bitmap_get(sdiff.skip, i))
+				continue;
+			obj->flags |= flags;
+			add_object_array(obj, name, &ent);
+			if (first_non_parent < 0 &&
+			    (i >= rev.cmdline.nr || /* HEAD by hand. */
+			     rev.cmdline.rev[i].whence != REV_CMD_PARENTS_ONLY))
+				first_non_parent = ent.nr - 1;
+		} else if (obj->type == OBJ_BLOB) {
+			if (2 <= blobs)
+				die(_("more than two blobs given: '%s'"), name);
+			blob[blobs] = entry;
+			blobs++;
+
+		} else {
+			die(_("unhandled object '%s' given."), name);
+		}
+	}
+	if (rev.prune_data.nr)
+		paths += rev.prune_data.nr;
+
+	/*
+	 * Now, do the arguments look reasonable?
+	 */
+	if (!ent.nr) {
+		switch (blobs) {
+		case 0:
+			builtin_diff_files(&rev, argc, argv);
+			break;
+		case 1:
+			if (paths != 1)
+				usage(builtin_diff_usage);
+			builtin_diff_b_f(&rev, argc, argv, blob);
+			break;
+		case 2:
+			if (paths)
+				usage(builtin_diff_usage);
+			builtin_diff_blobs(&rev, argc, argv, blob);
+			break;
+		default:
+			usage(builtin_diff_usage);
+		}
+	}
+	else if (blobs)
+		usage(builtin_diff_usage);
+	else if (ent.nr == 1)
+		builtin_diff_index(&rev, argc, argv);
+	else if (ent.nr == 2) {
+		if (sdiff.warn)
+			warning(_("%s...%s: multiple merge bases, using %s"),
+				sdiff.left, sdiff.right, sdiff.base);
+		builtin_diff_tree(&rev, argc, argv,
+				  &ent.objects[0], &ent.objects[1]);
+	} else
+		builtin_diff_combined(&rev, argc, argv,
+				      ent.objects, ent.nr,
+				      first_non_parent);
+	result = diff_result_code(&rev);
+	if (1 < rev.diffopt.skip_stat_unmatch)
+		refresh_index_quietly();
+	release_revisions(&rev);
+	object_array_clear(&ent);
+	symdiff_release(&sdiff);
+	return result;
+}
diff --git a/builtin/difftool.c b/builtin/difftool.c
new file mode 100644
index 0000000000..03a8bb92a9
--- /dev/null
+++ b/builtin/difftool.c
@@ -0,0 +1,804 @@
+/*
+ * "git difftool" builtin command
+ *
+ * This is a wrapper around the GIT_EXTERNAL_DIFF-compatible
+ * git-difftool--helper script.
+ *
+ * This script exports GIT_EXTERNAL_DIFF and GIT_PAGER for use by git.
+ * The GIT_DIFF* variables are exported for use by git-difftool--helper.
+ *
+ * Any arguments that are unknown to this script are forwarded to 'git diff'.
+ *
+ * Copyright (C) 2016 Johannes Schindelin
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+
+#include "abspath.h"
+#include "config.h"
+#include "copy.h"
+#include "run-command.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "parse-options.h"
+#include "read-cache-ll.h"
+#include "repository.h"
+#include "sparse-index.h"
+#include "strvec.h"
+#include "strbuf.h"
+#include "lockfile.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "dir.h"
+#include "entry.h"
+#include "setup.h"
+
+static int trust_exit_code;
+
+static const char *const builtin_difftool_usage[] = {
+	N_("git difftool [<options>] [<commit> [<commit>]] [--] [<path>...]"),
+	NULL
+};
+
+static int difftool_config(const char *var, const char *value,
+			   const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "difftool.trustexitcode")) {
+		trust_exit_code = git_config_bool(var, value);
+		return 0;
+	}
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static int print_tool_help(void)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	cmd.git_cmd = 1;
+	strvec_pushl(&cmd.args, "mergetool", "--tool-help=diff", NULL);
+	return run_command(&cmd);
+}
+
+static int parse_index_info(char *p, int *mode1, int *mode2,
+			    struct object_id *oid1, struct object_id *oid2,
+			    char *status)
+{
+	if (*p != ':')
+		return error("expected ':', got '%c'", *p);
+	*mode1 = (int)strtol(p + 1, &p, 8);
+	if (*p != ' ')
+		return error("expected ' ', got '%c'", *p);
+	*mode2 = (int)strtol(p + 1, &p, 8);
+	if (*p != ' ')
+		return error("expected ' ', got '%c'", *p);
+	if (parse_oid_hex(++p, oid1, (const char **)&p))
+		return error("expected object ID, got '%s'", p);
+	if (*p != ' ')
+		return error("expected ' ', got '%c'", *p);
+	if (parse_oid_hex(++p, oid2, (const char **)&p))
+		return error("expected object ID, got '%s'", p);
+	if (*p != ' ')
+		return error("expected ' ', got '%c'", *p);
+	*status = *++p;
+	if (!*status)
+		return error("missing status");
+	if (p[1] && !isdigit(p[1]))
+		return error("unexpected trailer: '%s'", p + 1);
+	return 0;
+}
+
+/*
+ * Remove any trailing slash from $workdir
+ * before starting to avoid double slashes in symlink targets.
+ */
+static void add_path(struct strbuf *buf, size_t base_len, const char *path)
+{
+	strbuf_setlen(buf, base_len);
+	if (buf->len && buf->buf[buf->len - 1] != '/')
+		strbuf_addch(buf, '/');
+	strbuf_addstr(buf, path);
+}
+
+/*
+ * Determine whether we can simply reuse the file in the worktree.
+ */
+static int use_wt_file(const char *workdir, const char *name,
+		       struct object_id *oid)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct stat st;
+	int use = 0;
+
+	strbuf_addstr(&buf, workdir);
+	add_path(&buf, buf.len, name);
+
+	if (!lstat(buf.buf, &st) && !S_ISLNK(st.st_mode)) {
+		struct object_id wt_oid;
+		int fd = open(buf.buf, O_RDONLY);
+
+		if (fd >= 0 &&
+		    !index_fd(the_repository->index, &wt_oid, fd, &st, OBJ_BLOB, name, 0)) {
+			if (is_null_oid(oid)) {
+				oidcpy(oid, &wt_oid);
+				use = 1;
+			} else if (oideq(oid, &wt_oid))
+				use = 1;
+		}
+	}
+
+	strbuf_release(&buf);
+
+	return use;
+}
+
+struct working_tree_entry {
+	struct hashmap_entry entry;
+	char path[FLEX_ARRAY];
+};
+
+static int working_tree_entry_cmp(const void *cmp_data UNUSED,
+				  const struct hashmap_entry *eptr,
+				  const struct hashmap_entry *entry_or_key,
+				  const void *keydata UNUSED)
+{
+	const struct working_tree_entry *a, *b;
+
+	a = container_of(eptr, const struct working_tree_entry, entry);
+	b = container_of(entry_or_key, const struct working_tree_entry, entry);
+
+	return strcmp(a->path, b->path);
+}
+
+/*
+ * The `left` and `right` entries hold paths for the symlinks hashmap,
+ * and a SHA-1 surrounded by brief text for submodules.
+ */
+struct pair_entry {
+	struct hashmap_entry entry;
+	char left[PATH_MAX], right[PATH_MAX];
+	const char path[FLEX_ARRAY];
+};
+
+static int pair_cmp(const void *cmp_data UNUSED,
+		    const struct hashmap_entry *eptr,
+		    const struct hashmap_entry *entry_or_key,
+		    const void *keydata UNUSED)
+{
+	const struct pair_entry *a, *b;
+
+	a = container_of(eptr, const struct pair_entry, entry);
+	b = container_of(entry_or_key, const struct pair_entry, entry);
+
+	return strcmp(a->path, b->path);
+}
+
+static void add_left_or_right(struct hashmap *map, const char *path,
+			      const char *content, int is_right)
+{
+	struct pair_entry *e, *existing;
+
+	FLEX_ALLOC_STR(e, path, path);
+	hashmap_entry_init(&e->entry, strhash(path));
+	existing = hashmap_get_entry(map, e, entry, NULL);
+	if (existing) {
+		free(e);
+		e = existing;
+	} else {
+		e->left[0] = e->right[0] = '\0';
+		hashmap_add(map, &e->entry);
+	}
+	strlcpy(is_right ? e->right : e->left, content, PATH_MAX);
+}
+
+struct path_entry {
+	struct hashmap_entry entry;
+	char path[FLEX_ARRAY];
+};
+
+static int path_entry_cmp(const void *cmp_data UNUSED,
+			  const struct hashmap_entry *eptr,
+			  const struct hashmap_entry *entry_or_key,
+			  const void *key)
+{
+	const struct path_entry *a, *b;
+
+	a = container_of(eptr, const struct path_entry, entry);
+	b = container_of(entry_or_key, const struct path_entry, entry);
+
+	return strcmp(a->path, key ? key : b->path);
+}
+
+static void changed_files(struct hashmap *result, const char *index_path,
+			  const char *workdir)
+{
+	struct child_process update_index = CHILD_PROCESS_INIT;
+	struct child_process diff_files = CHILD_PROCESS_INIT;
+	struct strbuf buf = STRBUF_INIT;
+	const char *git_dir = absolute_path(repo_get_git_dir(the_repository));
+	FILE *fp;
+
+	strvec_pushl(&update_index.args,
+		     "--git-dir", git_dir, "--work-tree", workdir,
+		     "update-index", "--really-refresh", "-q",
+		     "--unmerged", NULL);
+	update_index.no_stdin = 1;
+	update_index.no_stdout = 1;
+	update_index.no_stderr = 1;
+	update_index.git_cmd = 1;
+	update_index.use_shell = 0;
+	update_index.clean_on_exit = 1;
+	update_index.dir = workdir;
+	strvec_pushf(&update_index.env, "GIT_INDEX_FILE=%s", index_path);
+	/* Ignore any errors of update-index */
+	run_command(&update_index);
+
+	strvec_pushl(&diff_files.args,
+		     "--git-dir", git_dir, "--work-tree", workdir,
+		     "diff-files", "--name-only", "-z", NULL);
+	diff_files.no_stdin = 1;
+	diff_files.git_cmd = 1;
+	diff_files.use_shell = 0;
+	diff_files.clean_on_exit = 1;
+	diff_files.out = -1;
+	diff_files.dir = workdir;
+	strvec_pushf(&diff_files.env, "GIT_INDEX_FILE=%s", index_path);
+	if (start_command(&diff_files))
+		die("could not obtain raw diff");
+	fp = xfdopen(diff_files.out, "r");
+	while (!strbuf_getline_nul(&buf, fp)) {
+		struct path_entry *entry;
+		FLEX_ALLOC_STR(entry, path, buf.buf);
+		hashmap_entry_init(&entry->entry, strhash(buf.buf));
+		hashmap_add(result, &entry->entry);
+	}
+	fclose(fp);
+	if (finish_command(&diff_files))
+		die("diff-files did not exit properly");
+	strbuf_release(&buf);
+}
+
+static int ensure_leading_directories(char *path)
+{
+	switch (safe_create_leading_directories(path)) {
+		case SCLD_OK:
+		case SCLD_EXISTS:
+			return 0;
+		default:
+			return error(_("could not create leading directories "
+				       "of '%s'"), path);
+	}
+}
+
+/*
+ * Unconditional writing of a plain regular file is what
+ * "git difftool --dir-diff" wants to do for symlinks.  We are preparing two
+ * temporary directories to be fed to a Git-unaware tool that knows how to
+ * show a diff of two directories (e.g. "diff -r A B").
+ *
+ * Because the tool is Git-unaware, if a symbolic link appears in either of
+ * these temporary directories, it will try to dereference and show the
+ * difference of the target of the symbolic link, which is not what we want,
+ * as the goal of the dir-diff mode is to produce an output that is logically
+ * equivalent to what "git diff" produces.
+ *
+ * Most importantly, we want to get textual comparison of the result of the
+ * readlink(2).  get_symlink() provides that---it returns the contents of
+ * the symlink that gets written to a regular file to force the external tool
+ * to compare the readlink(2) result as text, even on a filesystem that is
+ * capable of doing a symbolic link.
+ */
+static char *get_symlink(const struct object_id *oid, const char *path)
+{
+	char *data;
+	if (is_null_oid(oid)) {
+		/* The symlink is unknown to Git so read from the filesystem */
+		struct strbuf link = STRBUF_INIT;
+		if (has_symlinks) {
+			if (strbuf_readlink(&link, path, strlen(path)))
+				die(_("could not read symlink %s"), path);
+		} else if (strbuf_read_file(&link, path, 128))
+			die(_("could not read symlink file %s"), path);
+
+		data = strbuf_detach(&link, NULL);
+	} else {
+		enum object_type type;
+		unsigned long size;
+		data = repo_read_object_file(the_repository, oid, &type,
+					     &size);
+		if (!data)
+			die(_("could not read object %s for symlink %s"),
+				oid_to_hex(oid), path);
+	}
+
+	return data;
+}
+
+static int checkout_path(unsigned mode, struct object_id *oid,
+			 const char *path, const struct checkout *state)
+{
+	struct cache_entry *ce;
+	int ret;
+
+	ce = make_transient_cache_entry(mode, oid, path, 0, NULL);
+	ret = checkout_entry(ce, state, NULL, NULL);
+
+	discard_cache_entry(ce);
+	return ret;
+}
+
+static void write_file_in_directory(struct strbuf *dir, size_t dir_len,
+			const char *path, const char *content)
+{
+	add_path(dir, dir_len, path);
+	ensure_leading_directories(dir->buf);
+	unlink(dir->buf);
+	write_file(dir->buf, "%s", content);
+}
+
+/* Write the file contents for the left and right sides of the difftool
+ * dir-diff representation for submodules and symlinks. Symlinks and submodules
+ * are written as regular text files so that external diff tools can diff them
+ * as text files, resulting in behavior that is analogous to what "git diff"
+ * displays for symlink and submodule diffs.
+ */
+static void write_standin_files(struct pair_entry *entry,
+			struct strbuf *ldir, size_t ldir_len,
+			struct strbuf *rdir, size_t rdir_len)
+{
+	if (*entry->left)
+		write_file_in_directory(ldir, ldir_len, entry->path, entry->left);
+	if (*entry->right)
+		write_file_in_directory(rdir, rdir_len, entry->path, entry->right);
+}
+
+static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
+			struct child_process *child)
+{
+	struct strbuf info = STRBUF_INIT, lpath = STRBUF_INIT;
+	struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT;
+	struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT;
+	struct strbuf wtdir = STRBUF_INIT;
+	struct strbuf tmpdir = STRBUF_INIT;
+	char *lbase_dir = NULL, *rbase_dir = NULL;
+	size_t ldir_len, rdir_len, wtdir_len;
+	const char *workdir, *tmp;
+	int ret = 0;
+	size_t i;
+	FILE *fp = NULL;
+	struct hashmap working_tree_dups = HASHMAP_INIT(working_tree_entry_cmp,
+							NULL);
+	struct hashmap submodules = HASHMAP_INIT(pair_cmp, NULL);
+	struct hashmap symlinks2 = HASHMAP_INIT(pair_cmp, NULL);
+	struct hashmap_iter iter;
+	struct pair_entry *entry;
+	struct index_state wtindex = INDEX_STATE_INIT(the_repository);
+	struct checkout lstate, rstate;
+	int err = 0;
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	struct hashmap wt_modified = HASHMAP_INIT(path_entry_cmp, NULL);
+	struct hashmap tmp_modified = HASHMAP_INIT(path_entry_cmp, NULL);
+	int indices_loaded = 0;
+
+	workdir = repo_get_work_tree(the_repository);
+
+	/* Setup temp directories */
+	tmp = getenv("TMPDIR");
+	strbuf_add_absolute_path(&tmpdir, tmp ? tmp : "/tmp");
+	strbuf_trim_trailing_dir_sep(&tmpdir);
+	strbuf_addstr(&tmpdir, "/git-difftool.XXXXXX");
+	if (!mkdtemp(tmpdir.buf)) {
+		ret = error("could not create '%s'", tmpdir.buf);
+		goto finish;
+	}
+	strbuf_addf(&ldir, "%s/left/", tmpdir.buf);
+	strbuf_addf(&rdir, "%s/right/", tmpdir.buf);
+	strbuf_addstr(&wtdir, workdir);
+	if (!wtdir.len || !is_dir_sep(wtdir.buf[wtdir.len - 1]))
+		strbuf_addch(&wtdir, '/');
+	mkdir(ldir.buf, 0700);
+	mkdir(rdir.buf, 0700);
+
+	memset(&lstate, 0, sizeof(lstate));
+	lstate.base_dir = lbase_dir = xstrdup(ldir.buf);
+	lstate.base_dir_len = ldir.len;
+	lstate.force = 1;
+	memset(&rstate, 0, sizeof(rstate));
+	rstate.base_dir = rbase_dir = xstrdup(rdir.buf);
+	rstate.base_dir_len = rdir.len;
+	rstate.force = 1;
+
+	ldir_len = ldir.len;
+	rdir_len = rdir.len;
+	wtdir_len = wtdir.len;
+
+	child->no_stdin = 1;
+	child->git_cmd = 1;
+	child->use_shell = 0;
+	child->clean_on_exit = 1;
+	child->dir = prefix;
+	child->out = -1;
+	if (start_command(child))
+		die("could not obtain raw diff");
+	fp = xfdopen(child->out, "r");
+
+	/* Build index info for left and right sides of the diff */
+	i = 0;
+	while (!strbuf_getline_nul(&info, fp)) {
+		int lmode, rmode;
+		struct object_id loid, roid;
+		char status;
+		const char *src_path, *dst_path;
+
+		if (starts_with(info.buf, "::"))
+			die(N_("combined diff formats ('-c' and '--cc') are "
+			       "not supported in\n"
+			       "directory diff mode ('-d' and '--dir-diff')."));
+
+		if (parse_index_info(info.buf, &lmode, &rmode, &loid, &roid,
+				     &status))
+			break;
+		if (strbuf_getline_nul(&lpath, fp))
+			break;
+		src_path = lpath.buf;
+
+		i++;
+		if (status != 'C' && status != 'R') {
+			dst_path = src_path;
+		} else {
+			if (strbuf_getline_nul(&rpath, fp))
+				break;
+			dst_path = rpath.buf;
+		}
+
+		if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "Subproject commit %s",
+				    oid_to_hex(&loid));
+			add_left_or_right(&submodules, src_path, buf.buf, 0);
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "Subproject commit %s",
+				    oid_to_hex(&roid));
+			if (oideq(&loid, &roid))
+				strbuf_addstr(&buf, "-dirty");
+			add_left_or_right(&submodules, dst_path, buf.buf, 1);
+			continue;
+		}
+
+		if (S_ISLNK(lmode)) {
+			char *content = get_symlink(&loid, src_path);
+			add_left_or_right(&symlinks2, src_path, content, 0);
+			free(content);
+		}
+
+		if (S_ISLNK(rmode)) {
+			char *content = get_symlink(&roid, dst_path);
+			add_left_or_right(&symlinks2, dst_path, content, 1);
+			free(content);
+		}
+
+		if (lmode && status != 'C') {
+			if (checkout_path(lmode, &loid, src_path, &lstate)) {
+				ret = error("could not write '%s'", src_path);
+				goto finish;
+			}
+		}
+
+		if (rmode && !S_ISLNK(rmode)) {
+			struct working_tree_entry *entry;
+
+			/* Avoid duplicate working_tree entries */
+			FLEX_ALLOC_STR(entry, path, dst_path);
+			hashmap_entry_init(&entry->entry, strhash(dst_path));
+			if (hashmap_get(&working_tree_dups, &entry->entry,
+					NULL)) {
+				free(entry);
+				continue;
+			}
+			hashmap_add(&working_tree_dups, &entry->entry);
+
+			if (!use_wt_file(workdir, dst_path, &roid)) {
+				if (checkout_path(rmode, &roid, dst_path,
+						  &rstate)) {
+					ret = error("could not write '%s'",
+						    dst_path);
+					goto finish;
+				}
+			} else if (!is_null_oid(&roid)) {
+				/*
+				 * Changes in the working tree need special
+				 * treatment since they are not part of the
+				 * index.
+				 */
+				struct cache_entry *ce2 =
+					make_cache_entry(&wtindex, rmode, &roid,
+							 dst_path, 0, 0);
+
+				add_index_entry(&wtindex, ce2,
+						ADD_CACHE_JUST_APPEND);
+
+				add_path(&rdir, rdir_len, dst_path);
+				if (ensure_leading_directories(rdir.buf)) {
+					ret = error("could not create "
+						    "directory for '%s'",
+						    dst_path);
+					goto finish;
+				}
+				add_path(&wtdir, wtdir_len, dst_path);
+				if (symlinks) {
+					if (symlink(wtdir.buf, rdir.buf)) {
+						ret = error_errno("could not symlink '%s' to '%s'", wtdir.buf, rdir.buf);
+						goto finish;
+					}
+				} else {
+					struct stat st;
+					if (stat(wtdir.buf, &st))
+						st.st_mode = 0644;
+					if (copy_file(rdir.buf, wtdir.buf,
+						      st.st_mode)) {
+						ret = error("could not copy '%s' to '%s'", wtdir.buf, rdir.buf);
+						goto finish;
+					}
+				}
+			}
+		}
+	}
+
+	fclose(fp);
+	fp = NULL;
+	if (finish_command(child)) {
+		ret = error("error occurred running diff --raw");
+		goto finish;
+	}
+
+	if (!i)
+		goto finish;
+
+	/*
+	 * Changes to submodules require special treatment.This loop writes a
+	 * temporary file to both the left and right directories to show the
+	 * change in the recorded SHA1 for the submodule.
+	 */
+	hashmap_for_each_entry(&submodules, &iter, entry,
+				entry /* member name */) {
+		write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
+	}
+
+	/*
+	 * Symbolic links require special treatment. The standard "git diff"
+	 * shows only the link itself, not the contents of the link target.
+	 * This loop replicates that behavior.
+	 */
+	hashmap_for_each_entry(&symlinks2, &iter, entry,
+				entry /* member name */) {
+
+		write_standin_files(entry, &ldir, ldir_len, &rdir, rdir_len);
+	}
+
+	strbuf_setlen(&ldir, ldir_len);
+	strbuf_setlen(&rdir, rdir_len);
+
+	if (extcmd) {
+		strvec_push(&cmd.args, extcmd);
+	} else {
+		strvec_push(&cmd.args, "difftool--helper");
+		cmd.git_cmd = 1;
+		setenv("GIT_DIFFTOOL_DIRDIFF", "true", 1);
+	}
+	strvec_pushl(&cmd.args, ldir.buf, rdir.buf, NULL);
+	ret = run_command(&cmd);
+
+	/* TODO: audit for interaction with sparse-index. */
+	ensure_full_index(&wtindex);
+
+	/*
+	 * If the diff includes working copy files and those
+	 * files were modified during the diff, then the changes
+	 * should be copied back to the working tree.
+	 * Do not copy back files when symlinks are used and the
+	 * external tool did not replace the original link with a file.
+	 *
+	 * These hashes are loaded lazily since they aren't needed
+	 * in the common case of --symlinks and the difftool updating
+	 * files through the symlink.
+	 */
+	for (i = 0; i < wtindex.cache_nr; i++) {
+		struct hashmap_entry dummy;
+		const char *name = wtindex.cache[i]->name;
+		struct stat st;
+
+		add_path(&rdir, rdir_len, name);
+		if (lstat(rdir.buf, &st))
+			continue;
+
+		if ((symlinks && S_ISLNK(st.st_mode)) || !S_ISREG(st.st_mode))
+			continue;
+
+		if (!indices_loaded) {
+			struct lock_file lock = LOCK_INIT;
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "%s/wtindex", tmpdir.buf);
+			if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
+			    write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {
+				ret = error("could not write %s", buf.buf);
+				goto finish;
+			}
+			changed_files(&wt_modified, buf.buf, workdir);
+			strbuf_setlen(&rdir, rdir_len);
+			changed_files(&tmp_modified, buf.buf, rdir.buf);
+			add_path(&rdir, rdir_len, name);
+			indices_loaded = 1;
+		}
+
+		hashmap_entry_init(&dummy, strhash(name));
+		if (hashmap_get(&tmp_modified, &dummy, name)) {
+			add_path(&wtdir, wtdir_len, name);
+			if (hashmap_get(&wt_modified, &dummy, name)) {
+				warning(_("both files modified: '%s' and '%s'."),
+					wtdir.buf, rdir.buf);
+				warning(_("working tree file has been left."));
+				warning("%s", "");
+				err = 1;
+			} else if (unlink(wtdir.buf) ||
+				   copy_file(wtdir.buf, rdir.buf, st.st_mode))
+				warning_errno(_("could not copy '%s' to '%s'"),
+					      rdir.buf, wtdir.buf);
+		}
+	}
+
+	if (err) {
+		warning(_("temporary files exist in '%s'."), tmpdir.buf);
+		warning(_("you may want to cleanup or recover these."));
+		ret = 1;
+	} else {
+		remove_dir_recursively(&tmpdir, 0);
+		if (ret)
+			warning(_("failed: %d"), ret);
+	}
+
+finish:
+	if (fp)
+		fclose(fp);
+
+	hashmap_clear_and_free(&working_tree_dups, struct working_tree_entry, entry);
+	hashmap_clear_and_free(&wt_modified, struct path_entry, entry);
+	hashmap_clear_and_free(&tmp_modified, struct path_entry, entry);
+	hashmap_clear_and_free(&submodules, struct pair_entry, entry);
+	hashmap_clear_and_free(&symlinks2, struct pair_entry, entry);
+	release_index(&wtindex);
+	free(lbase_dir);
+	free(rbase_dir);
+	strbuf_release(&info);
+	strbuf_release(&lpath);
+	strbuf_release(&rpath);
+	strbuf_release(&ldir);
+	strbuf_release(&rdir);
+	strbuf_release(&wtdir);
+	strbuf_release(&buf);
+	strbuf_release(&tmpdir);
+
+	return (ret < 0) ? 1 : ret;
+}
+
+static int run_file_diff(int prompt, const char *prefix,
+			 struct child_process *child)
+{
+	strvec_push(&child->env, "GIT_PAGER=");
+	strvec_push(&child->env, "GIT_EXTERNAL_DIFF=git-difftool--helper");
+	if (prompt > 0)
+		strvec_push(&child->env, "GIT_DIFFTOOL_PROMPT=true");
+	else if (!prompt)
+		strvec_push(&child->env, "GIT_DIFFTOOL_NO_PROMPT=true");
+
+	child->git_cmd = 1;
+	child->dir = prefix;
+
+	return run_command(child);
+}
+
+int cmd_difftool(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	int use_gui_tool = -1, dir_diff = 0, prompt = -1, symlinks = 0,
+	    tool_help = 0, no_index = 0;
+	static char *difftool_cmd = NULL, *extcmd = NULL;
+	struct option builtin_difftool_options[] = {
+		OPT_BOOL('g', "gui", &use_gui_tool,
+			 N_("use `diff.guitool` instead of `diff.tool`")),
+		OPT_BOOL('d', "dir-diff", &dir_diff,
+			 N_("perform a full-directory diff")),
+		OPT_SET_INT_F('y', "no-prompt", &prompt,
+			N_("do not prompt before launching a diff tool"),
+			0, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "prompt", &prompt, NULL,
+			1, PARSE_OPT_NONEG | PARSE_OPT_HIDDEN),
+		OPT_BOOL(0, "symlinks", &symlinks,
+			 N_("use symlinks in dir-diff mode")),
+		OPT_STRING('t', "tool", &difftool_cmd, N_("tool"),
+			   N_("use the specified diff tool")),
+		OPT_BOOL(0, "tool-help", &tool_help,
+			 N_("print a list of diff tools that may be used with "
+			    "`--tool`")),
+		OPT_BOOL(0, "trust-exit-code", &trust_exit_code,
+			 N_("make 'git-difftool' exit when an invoked diff "
+			    "tool returns a non-zero exit code")),
+		OPT_STRING('x', "extcmd", &extcmd, N_("command"),
+			   N_("specify a custom command for viewing diffs")),
+		OPT_BOOL(0, "no-index", &no_index, N_("passed to `diff`")),
+		OPT_END()
+	};
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	git_config(difftool_config, NULL);
+	symlinks = has_symlinks;
+
+	argc = parse_options(argc, argv, prefix, builtin_difftool_options,
+			     builtin_difftool_usage, PARSE_OPT_KEEP_UNKNOWN_OPT |
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	if (tool_help)
+		return print_tool_help();
+
+	if (!no_index && !startup_info->have_repository)
+		die(_("difftool requires worktree or --no-index"));
+
+	if (!no_index){
+		setup_work_tree();
+		setenv(GIT_DIR_ENVIRONMENT, absolute_path(repo_get_git_dir(the_repository)), 1);
+		setenv(GIT_WORK_TREE_ENVIRONMENT, absolute_path(repo_get_work_tree(the_repository)), 1);
+	} else if (dir_diff)
+		die(_("options '%s' and '%s' cannot be used together"), "--dir-diff", "--no-index");
+
+	die_for_incompatible_opt3(use_gui_tool == 1, "--gui",
+				  !!difftool_cmd, "--tool",
+				  !!extcmd, "--extcmd");
+
+	/*
+	 * Explicitly specified GUI option is forwarded to git-mergetool--lib.sh;
+	 * empty or unset means "use the difftool.guiDefault config or default to
+	 * false".
+	 */
+	if (use_gui_tool == 1)
+		setenv("GIT_MERGETOOL_GUI", "true", 1);
+	else if (use_gui_tool == 0)
+		setenv("GIT_MERGETOOL_GUI", "false", 1);
+
+	if (difftool_cmd) {
+		if (*difftool_cmd)
+			setenv("GIT_DIFF_TOOL", difftool_cmd, 1);
+		else
+			die(_("no <tool> given for --tool=<tool>"));
+	}
+
+	if (extcmd) {
+		if (*extcmd)
+			setenv("GIT_DIFFTOOL_EXTCMD", extcmd, 1);
+		else
+			die(_("no <cmd> given for --extcmd=<cmd>"));
+	}
+
+	setenv("GIT_DIFFTOOL_TRUST_EXIT_CODE",
+	       trust_exit_code ? "true" : "false", 1);
+
+	/*
+	 * In directory diff mode, 'git-difftool--helper' is called once
+	 * to compare the a / b directories. In file diff mode, 'git diff'
+	 * will invoke a separate instance of 'git-difftool--helper' for
+	 * each file that changed.
+	 */
+	strvec_push(&child.args, "diff");
+	if (no_index)
+		strvec_push(&child.args, "--no-index");
+	if (dir_diff)
+		strvec_pushl(&child.args, "--raw", "--no-abbrev", "-z", NULL);
+	strvec_pushv(&child.args, argv);
+
+	if (dir_diff)
+		return run_dir_diff(extcmd, symlinks, prefix, &child);
+	return run_file_diff(prompt, prefix, &child);
+}
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
new file mode 100644
index 0000000000..a5c82eef1d
--- /dev/null
+++ b/builtin/fast-export.c
@@ -0,0 +1,1315 @@
+/*
+ * "git fast-export" builtin command
+ *
+ * Copyright (C) 2007 Johannes E. Schindelin
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "refs.h"
+#include "refspec.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "commit.h"
+#include "object.h"
+#include "tag.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "log-tree.h"
+#include "revision.h"
+#include "decorate.h"
+#include "string-list.h"
+#include "utf8.h"
+#include "parse-options.h"
+#include "quote.h"
+#include "remote.h"
+#include "blob.h"
+
+static const char *fast_export_usage[] = {
+	N_("git fast-export [<rev-list-opts>]"),
+	NULL
+};
+
+static int progress;
+static enum signed_tag_mode { SIGNED_TAG_ABORT, VERBATIM, WARN, WARN_STRIP, STRIP } signed_tag_mode = SIGNED_TAG_ABORT;
+static enum tag_of_filtered_mode { TAG_FILTERING_ABORT, DROP, REWRITE } tag_of_filtered_mode = TAG_FILTERING_ABORT;
+static enum reencode_mode { REENCODE_ABORT, REENCODE_YES, REENCODE_NO } reencode_mode = REENCODE_ABORT;
+static int fake_missing_tagger;
+static int use_done_feature;
+static int no_data;
+static int full_tree;
+static int reference_excluded_commits;
+static int show_original_ids;
+static int mark_tags;
+static struct string_list extra_refs = STRING_LIST_INIT_DUP;
+static struct string_list tag_refs = STRING_LIST_INIT_DUP;
+static struct refspec refspecs = REFSPEC_INIT_FETCH;
+static int anonymize;
+static struct hashmap anonymized_seeds;
+static struct revision_sources revision_sources;
+
+static int parse_opt_signed_tag_mode(const struct option *opt,
+				     const char *arg, int unset)
+{
+	enum signed_tag_mode *val = opt->value;
+
+	if (unset || !strcmp(arg, "abort"))
+		*val = SIGNED_TAG_ABORT;
+	else if (!strcmp(arg, "verbatim") || !strcmp(arg, "ignore"))
+		*val = VERBATIM;
+	else if (!strcmp(arg, "warn"))
+		*val = WARN;
+	else if (!strcmp(arg, "warn-strip"))
+		*val = WARN_STRIP;
+	else if (!strcmp(arg, "strip"))
+		*val = STRIP;
+	else
+		return error("Unknown signed-tags mode: %s", arg);
+	return 0;
+}
+
+static int parse_opt_tag_of_filtered_mode(const struct option *opt,
+					  const char *arg, int unset)
+{
+	enum tag_of_filtered_mode *val = opt->value;
+
+	if (unset || !strcmp(arg, "abort"))
+		*val = TAG_FILTERING_ABORT;
+	else if (!strcmp(arg, "drop"))
+		*val = DROP;
+	else if (!strcmp(arg, "rewrite"))
+		*val = REWRITE;
+	else
+		return error("Unknown tag-of-filtered mode: %s", arg);
+	return 0;
+}
+
+static int parse_opt_reencode_mode(const struct option *opt,
+				   const char *arg, int unset)
+{
+	enum reencode_mode *val = opt->value;
+
+	if (unset) {
+		*val = REENCODE_ABORT;
+		return 0;
+	}
+
+	switch (git_parse_maybe_bool(arg)) {
+	case 0:
+		*val = REENCODE_NO;
+		break;
+	case 1:
+		*val = REENCODE_YES;
+		break;
+	default:
+		if (!strcasecmp(arg, "abort"))
+			*val = REENCODE_ABORT;
+		else
+			return error("Unknown reencoding mode: %s", arg);
+	}
+
+	return 0;
+}
+
+static struct decoration idnums;
+static uint32_t last_idnum;
+struct anonymized_entry {
+	struct hashmap_entry hash;
+	char *anon;
+	const char orig[FLEX_ARRAY];
+};
+
+struct anonymized_entry_key {
+	struct hashmap_entry hash;
+	const char *orig;
+	size_t orig_len;
+};
+
+static int anonymized_entry_cmp(const void *cmp_data UNUSED,
+				const struct hashmap_entry *eptr,
+				const struct hashmap_entry *entry_or_key,
+				const void *keydata)
+{
+	const struct anonymized_entry *a, *b;
+
+	a = container_of(eptr, const struct anonymized_entry, hash);
+	if (keydata) {
+		const struct anonymized_entry_key *key = keydata;
+		int equal = !xstrncmpz(a->orig, key->orig, key->orig_len);
+		return !equal;
+	}
+
+	b = container_of(entry_or_key, const struct anonymized_entry, hash);
+	return strcmp(a->orig, b->orig);
+}
+
+static struct anonymized_entry *add_anonymized_entry(struct hashmap *map,
+						     unsigned hash,
+						     const char *orig, size_t len,
+						     char *anon)
+{
+	struct anonymized_entry *ret, *old;
+
+	if (!map->cmpfn)
+		hashmap_init(map, anonymized_entry_cmp, NULL, 0);
+
+	FLEX_ALLOC_MEM(ret, orig, orig, len);
+	hashmap_entry_init(&ret->hash, hash);
+	ret->anon = anon;
+	old = hashmap_put_entry(map, ret, hash);
+
+	if (old) {
+		free(old->anon);
+		free(old);
+	}
+
+	return ret;
+}
+
+/*
+ * Basically keep a cache of X->Y so that we can repeatedly replace
+ * the same anonymized string with another. The actual generation
+ * is farmed out to the generate function.
+ */
+static const char *anonymize_str(struct hashmap *map,
+				 char *(*generate)(void),
+				 const char *orig, size_t len)
+{
+	struct anonymized_entry_key key;
+	struct anonymized_entry *ret;
+
+	hashmap_entry_init(&key.hash, memhash(orig, len));
+	key.orig = orig;
+	key.orig_len = len;
+
+	/* First check if it's a token the user configured manually... */
+	ret = hashmap_get_entry(&anonymized_seeds, &key, hash, &key);
+
+	/* ...otherwise check if we've already seen it in this context... */
+	if (!ret)
+		ret = hashmap_get_entry(map, &key, hash, &key);
+
+	/* ...and finally generate a new mapping if necessary */
+	if (!ret)
+		ret = add_anonymized_entry(map, key.hash.hash,
+					   orig, len, generate());
+
+	return ret->anon;
+}
+
+/*
+ * We anonymize each component of a path individually,
+ * so that paths a/b and a/c will share a common root.
+ * The paths are cached via anonymize_mem so that repeated
+ * lookups for "a" will yield the same value.
+ */
+static void anonymize_path(struct strbuf *out, const char *path,
+			   struct hashmap *map,
+			   char *(*generate)(void))
+{
+	while (*path) {
+		const char *end_of_component = strchrnul(path, '/');
+		size_t len = end_of_component - path;
+		const char *c = anonymize_str(map, generate, path, len);
+		strbuf_addstr(out, c);
+		path = end_of_component;
+		if (*path)
+			strbuf_addch(out, *path++);
+	}
+}
+
+static inline void *mark_to_ptr(uint32_t mark)
+{
+	return (void *)(uintptr_t)mark;
+}
+
+static inline uint32_t ptr_to_mark(void * mark)
+{
+	return (uint32_t)(uintptr_t)mark;
+}
+
+static inline void mark_object(struct object *object, uint32_t mark)
+{
+	add_decoration(&idnums, object, mark_to_ptr(mark));
+}
+
+static inline void mark_next_object(struct object *object)
+{
+	mark_object(object, ++last_idnum);
+}
+
+static int get_object_mark(struct object *object)
+{
+	void *decoration = lookup_decoration(&idnums, object);
+	if (!decoration)
+		return 0;
+	return ptr_to_mark(decoration);
+}
+
+static struct commit *rewrite_commit(struct commit *p)
+{
+	for (;;) {
+		if (p->parents && p->parents->next)
+			break;
+		if (p->object.flags & UNINTERESTING)
+			break;
+		if (!(p->object.flags & TREESAME))
+			break;
+		if (!p->parents)
+			return NULL;
+		p = p->parents->item;
+	}
+	return p;
+}
+
+static void show_progress(void)
+{
+	static int counter = 0;
+	if (!progress)
+		return;
+	if ((++counter % progress) == 0)
+		printf("progress %d objects\n", counter);
+}
+
+/*
+ * Ideally we would want some transformation of the blob data here
+ * that is unreversible, but would still be the same size and have
+ * the same data relationship to other blobs (so that we get the same
+ * delta and packing behavior as the original). But the first and last
+ * requirements there are probably mutually exclusive, so let's take
+ * the easy way out for now, and just generate arbitrary content.
+ *
+ * There's no need to cache this result with anonymize_mem, since
+ * we already handle blob content caching with marks.
+ */
+static char *anonymize_blob(unsigned long *size)
+{
+	static int counter;
+	struct strbuf out = STRBUF_INIT;
+	strbuf_addf(&out, "anonymous blob %d", counter++);
+	*size = out.len;
+	return strbuf_detach(&out, NULL);
+}
+
+static void export_blob(const struct object_id *oid)
+{
+	unsigned long size;
+	enum object_type type;
+	char *buf;
+	struct object *object;
+	int eaten;
+
+	if (no_data)
+		return;
+
+	if (is_null_oid(oid))
+		return;
+
+	object = lookup_object(the_repository, oid);
+	if (object && object->flags & SHOWN)
+		return;
+
+	if (anonymize) {
+		buf = anonymize_blob(&size);
+		object = (struct object *)lookup_blob(the_repository, oid);
+		eaten = 0;
+	} else {
+		buf = repo_read_object_file(the_repository, oid, &type, &size);
+		if (!buf)
+			die("could not read blob %s", oid_to_hex(oid));
+		if (check_object_signature(the_repository, oid, buf, size,
+					   type) < 0)
+			die("oid mismatch in blob %s", oid_to_hex(oid));
+		object = parse_object_buffer(the_repository, oid, type,
+					     size, buf, &eaten);
+	}
+
+	if (!object)
+		die("Could not read blob %s", oid_to_hex(oid));
+
+	mark_next_object(object);
+
+	printf("blob\nmark :%"PRIu32"\n", last_idnum);
+	if (show_original_ids)
+		printf("original-oid %s\n", oid_to_hex(oid));
+	printf("data %"PRIuMAX"\n", (uintmax_t)size);
+	if (size && fwrite(buf, size, 1, stdout) != 1)
+		die_errno("could not write blob '%s'", oid_to_hex(oid));
+	printf("\n");
+
+	show_progress();
+
+	object->flags |= SHOWN;
+	if (!eaten)
+		free(buf);
+}
+
+static int depth_first(const void *a_, const void *b_)
+{
+	const struct diff_filepair *a = *((const struct diff_filepair **)a_);
+	const struct diff_filepair *b = *((const struct diff_filepair **)b_);
+	const char *name_a, *name_b;
+	int len_a, len_b, len;
+	int cmp;
+
+	name_a = a->one ? a->one->path : a->two->path;
+	name_b = b->one ? b->one->path : b->two->path;
+
+	len_a = strlen(name_a);
+	len_b = strlen(name_b);
+	len = (len_a < len_b) ? len_a : len_b;
+
+	/* strcmp will sort 'd' before 'd/e', we want 'd/e' before 'd' */
+	cmp = memcmp(name_a, name_b, len);
+	if (cmp)
+		return cmp;
+	cmp = len_b - len_a;
+	if (cmp)
+		return cmp;
+	/*
+	 * Move 'R'ename entries last so that all references of the file
+	 * appear in the output before it is renamed (e.g., when a file
+	 * was copied and renamed in the same commit).
+	 */
+	return (a->status == 'R') - (b->status == 'R');
+}
+
+static void print_path_1(const char *path)
+{
+	int need_quote = quote_c_style(path, NULL, NULL, 0);
+	if (need_quote)
+		quote_c_style(path, NULL, stdout, 0);
+	else if (strchr(path, ' '))
+		printf("\"%s\"", path);
+	else
+		printf("%s", path);
+}
+
+static char *anonymize_path_component(void)
+{
+	static int counter;
+	struct strbuf out = STRBUF_INIT;
+	strbuf_addf(&out, "path%d", counter++);
+	return strbuf_detach(&out, NULL);
+}
+
+static void print_path(const char *path)
+{
+	if (!anonymize)
+		print_path_1(path);
+	else {
+		static struct hashmap paths;
+		static struct strbuf anon = STRBUF_INIT;
+
+		anonymize_path(&anon, path, &paths, anonymize_path_component);
+		print_path_1(anon.buf);
+		strbuf_reset(&anon);
+	}
+}
+
+static char *generate_fake_oid(void)
+{
+	static uint32_t counter = 1; /* avoid null oid */
+	const unsigned hashsz = the_hash_algo->rawsz;
+	struct object_id oid;
+	char *hex = xmallocz(GIT_MAX_HEXSZ);
+
+	oidclr(&oid, the_repository->hash_algo);
+	put_be32(oid.hash + hashsz - 4, counter++);
+	return oid_to_hex_r(hex, &oid);
+}
+
+static const char *anonymize_oid(const char *oid_hex)
+{
+	static struct hashmap objs;
+	size_t len = strlen(oid_hex);
+	return anonymize_str(&objs, generate_fake_oid, oid_hex, len);
+}
+
+static void show_filemodify(struct diff_queue_struct *q,
+			    struct diff_options *options UNUSED, void *data)
+{
+	int i;
+	struct string_list *changed = data;
+
+	/*
+	 * Handle files below a directory first, in case they are all deleted
+	 * and the directory changes to a file or symlink.
+	 */
+	QSORT(q->queue, q->nr, depth_first);
+
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filespec *ospec = q->queue[i]->one;
+		struct diff_filespec *spec = q->queue[i]->two;
+
+		switch (q->queue[i]->status) {
+		case DIFF_STATUS_DELETED:
+			printf("D ");
+			print_path(spec->path);
+			string_list_insert(changed, spec->path);
+			putchar('\n');
+			break;
+
+		case DIFF_STATUS_COPIED:
+		case DIFF_STATUS_RENAMED:
+			/*
+			 * If a change in the file corresponding to ospec->path
+			 * has been observed, we cannot trust its contents
+			 * because the diff is calculated based on the prior
+			 * contents, not the current contents.  So, declare a
+			 * copy or rename only if there was no change observed.
+			 */
+			if (!string_list_has_string(changed, ospec->path)) {
+				printf("%c ", q->queue[i]->status);
+				print_path(ospec->path);
+				putchar(' ');
+				print_path(spec->path);
+				string_list_insert(changed, spec->path);
+				putchar('\n');
+
+				if (oideq(&ospec->oid, &spec->oid) &&
+				    ospec->mode == spec->mode)
+					break;
+			}
+			/* fallthrough */
+
+		case DIFF_STATUS_TYPE_CHANGED:
+		case DIFF_STATUS_MODIFIED:
+		case DIFF_STATUS_ADDED:
+			/*
+			 * Links refer to objects in another repositories;
+			 * output the SHA-1 verbatim.
+			 */
+			if (no_data || S_ISGITLINK(spec->mode))
+				printf("M %06o %s ", spec->mode,
+				       anonymize ?
+				       anonymize_oid(oid_to_hex(&spec->oid)) :
+				       oid_to_hex(&spec->oid));
+			else {
+				struct object *object = lookup_object(the_repository,
+								      &spec->oid);
+				printf("M %06o :%d ", spec->mode,
+				       get_object_mark(object));
+			}
+			print_path(spec->path);
+			string_list_insert(changed, spec->path);
+			putchar('\n');
+			break;
+
+		default:
+			die("Unexpected comparison status '%c' for %s, %s",
+				q->queue[i]->status,
+				ospec->path ? ospec->path : "none",
+				spec->path ? spec->path : "none");
+		}
+	}
+}
+
+static const char *find_encoding(const char *begin, const char *end)
+{
+	const char *needle = "\nencoding ";
+	char *bol, *eol;
+
+	bol = memmem(begin, end ? end - begin : strlen(begin),
+		     needle, strlen(needle));
+	if (!bol)
+		return NULL;
+	bol += strlen(needle);
+	eol = strchrnul(bol, '\n');
+	*eol = '\0';
+	return bol;
+}
+
+static char *anonymize_ref_component(void)
+{
+	static int counter;
+	struct strbuf out = STRBUF_INIT;
+	strbuf_addf(&out, "ref%d", counter++);
+	return strbuf_detach(&out, NULL);
+}
+
+static const char *anonymize_refname(const char *refname)
+{
+	/*
+	 * If any of these prefixes is found, we will leave it intact
+	 * so that tags remain tags and so forth.
+	 */
+	static const char *prefixes[] = {
+		"refs/heads/",
+		"refs/tags/",
+		"refs/remotes/",
+		"refs/"
+	};
+	static struct hashmap refs;
+	static struct strbuf anon = STRBUF_INIT;
+	int i;
+
+	strbuf_reset(&anon);
+	for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
+		if (skip_prefix(refname, prefixes[i], &refname)) {
+			strbuf_addstr(&anon, prefixes[i]);
+			break;
+		}
+	}
+
+	anonymize_path(&anon, refname, &refs, anonymize_ref_component);
+	return anon.buf;
+}
+
+/*
+ * We do not even bother to cache commit messages, as they are unlikely
+ * to be repeated verbatim, and it is not that interesting when they are.
+ */
+static char *anonymize_commit_message(void)
+{
+	static int counter;
+	return xstrfmt("subject %d\n\nbody\n", counter++);
+}
+
+static char *anonymize_ident(void)
+{
+	static int counter;
+	struct strbuf out = STRBUF_INIT;
+	strbuf_addf(&out, "User %d <user%d@xxxxxxxxxxx>", counter, counter);
+	counter++;
+	return strbuf_detach(&out, NULL);
+}
+
+/*
+ * Our strategy here is to anonymize the names and email addresses,
+ * but keep timestamps intact, as they influence things like traversal
+ * order (and by themselves should not be too revealing).
+ */
+static void anonymize_ident_line(const char **beg, const char **end)
+{
+	static struct hashmap idents;
+	static struct strbuf buffers[] = { STRBUF_INIT, STRBUF_INIT };
+	static unsigned which_buffer;
+
+	struct strbuf *out;
+	struct ident_split split;
+	const char *end_of_header;
+
+	out = &buffers[which_buffer++];
+	which_buffer %= ARRAY_SIZE(buffers);
+	strbuf_reset(out);
+
+	/* skip "committer", "author", "tagger", etc */
+	end_of_header = strchr(*beg, ' ');
+	if (!end_of_header)
+		BUG("malformed line fed to anonymize_ident_line: %.*s",
+		    (int)(*end - *beg), *beg);
+	end_of_header++;
+	strbuf_add(out, *beg, end_of_header - *beg);
+
+	if (!split_ident_line(&split, end_of_header, *end - end_of_header) &&
+	    split.date_begin) {
+		const char *ident;
+		size_t len;
+
+		len = split.mail_end - split.name_begin;
+		ident = anonymize_str(&idents, anonymize_ident,
+				      split.name_begin, len);
+		strbuf_addstr(out, ident);
+		strbuf_addch(out, ' ');
+		strbuf_add(out, split.date_begin, split.tz_end - split.date_begin);
+	} else {
+		strbuf_addstr(out, "Malformed Ident <malformed@xxxxxxxxxxx> 0 -0000");
+	}
+
+	*beg = out->buf;
+	*end = out->buf + out->len;
+}
+
+static void handle_commit(struct commit *commit, struct rev_info *rev,
+			  struct string_list *paths_of_changed_objects)
+{
+	int saved_output_format = rev->diffopt.output_format;
+	const char *commit_buffer;
+	const char *author, *author_end, *committer, *committer_end;
+	const char *encoding, *message;
+	char *reencoded = NULL;
+	struct commit_list *p;
+	const char *refname;
+	int i;
+
+	rev->diffopt.output_format = DIFF_FORMAT_CALLBACK;
+
+	parse_commit_or_die(commit);
+	commit_buffer = repo_get_commit_buffer(the_repository, commit, NULL);
+	author = strstr(commit_buffer, "\nauthor ");
+	if (!author)
+		die("could not find author in commit %s",
+		    oid_to_hex(&commit->object.oid));
+	author++;
+	author_end = strchrnul(author, '\n');
+	committer = strstr(author_end, "\ncommitter ");
+	if (!committer)
+		die("could not find committer in commit %s",
+		    oid_to_hex(&commit->object.oid));
+	committer++;
+	committer_end = strchrnul(committer, '\n');
+	message = strstr(committer_end, "\n\n");
+	encoding = find_encoding(committer_end, message);
+	if (message)
+		message += 2;
+
+	if (commit->parents &&
+	    (get_object_mark(&commit->parents->item->object) != 0 ||
+	     reference_excluded_commits) &&
+	    !full_tree) {
+		parse_commit_or_die(commit->parents->item);
+		diff_tree_oid(get_commit_tree_oid(commit->parents->item),
+			      get_commit_tree_oid(commit), "", &rev->diffopt);
+	}
+	else
+		diff_root_tree_oid(get_commit_tree_oid(commit),
+				   "", &rev->diffopt);
+
+	/* Export the referenced blobs, and remember the marks. */
+	for (i = 0; i < diff_queued_diff.nr; i++)
+		if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode))
+			export_blob(&diff_queued_diff.queue[i]->two->oid);
+
+	refname = *revision_sources_at(&revision_sources, commit);
+	/*
+	 * FIXME: string_list_remove() below for each ref is overall
+	 * O(N^2).  Compared to a history walk and diffing trees, this is
+	 * just lost in the noise in practice.  However, theoretically a
+	 * repo may have enough refs for this to become slow.
+	 */
+	string_list_remove(&extra_refs, refname, 0);
+	if (anonymize) {
+		refname = anonymize_refname(refname);
+		anonymize_ident_line(&committer, &committer_end);
+		anonymize_ident_line(&author, &author_end);
+	}
+
+	mark_next_object(&commit->object);
+	if (anonymize) {
+		reencoded = anonymize_commit_message();
+	} else if (encoding) {
+		switch(reencode_mode) {
+		case REENCODE_YES:
+			reencoded = reencode_string(message, "UTF-8", encoding);
+			break;
+		case REENCODE_NO:
+			break;
+		case REENCODE_ABORT:
+			die("Encountered commit-specific encoding %s in commit "
+			    "%s; use --reencode=[yes|no] to handle it",
+			    encoding, oid_to_hex(&commit->object.oid));
+		}
+	}
+	if (!commit->parents)
+		printf("reset %s\n", refname);
+	printf("commit %s\nmark :%"PRIu32"\n", refname, last_idnum);
+	if (show_original_ids)
+		printf("original-oid %s\n", oid_to_hex(&commit->object.oid));
+	printf("%.*s\n%.*s\n",
+	       (int)(author_end - author), author,
+	       (int)(committer_end - committer), committer);
+	if (!reencoded && encoding)
+		printf("encoding %s\n", encoding);
+	printf("data %u\n%s",
+	       (unsigned)(reencoded
+			  ? strlen(reencoded) : message
+			  ? strlen(message) : 0),
+	       reencoded ? reencoded : message ? message : "");
+	free(reencoded);
+	repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
+
+	for (i = 0, p = commit->parents; p; p = p->next) {
+		struct object *obj = &p->item->object;
+		int mark = get_object_mark(obj);
+
+		if (!mark && !reference_excluded_commits)
+			continue;
+		if (i == 0)
+			printf("from ");
+		else
+			printf("merge ");
+		if (mark)
+			printf(":%d\n", mark);
+		else
+			printf("%s\n",
+			       anonymize ?
+			       anonymize_oid(oid_to_hex(&obj->oid)) :
+			       oid_to_hex(&obj->oid));
+		i++;
+	}
+
+	if (full_tree)
+		printf("deleteall\n");
+	log_tree_diff_flush(rev);
+	string_list_clear(paths_of_changed_objects, 0);
+	rev->diffopt.output_format = saved_output_format;
+
+	printf("\n");
+
+	show_progress();
+}
+
+static char *anonymize_tag(void)
+{
+	static int counter;
+	struct strbuf out = STRBUF_INIT;
+	strbuf_addf(&out, "tag message %d", counter++);
+	return strbuf_detach(&out, NULL);
+}
+
+
+static void handle_tag(const char *name, struct tag *tag)
+{
+	unsigned long size;
+	enum object_type type;
+	char *buf;
+	const char *tagger, *tagger_end, *message;
+	size_t message_size = 0;
+	struct object *tagged;
+	int tagged_mark;
+	struct commit *p;
+
+	/* Trees have no identifier in fast-export output, thus we have no way
+	 * to output tags of trees, tags of tags of trees, etc.  Simply omit
+	 * such tags.
+	 */
+	tagged = tag->tagged;
+	while (tagged->type == OBJ_TAG) {
+		tagged = ((struct tag *)tagged)->tagged;
+	}
+	if (tagged->type == OBJ_TREE) {
+		warning("Omitting tag %s,\nsince tags of trees (or tags of tags of trees, etc.) are not supported.",
+			oid_to_hex(&tag->object.oid));
+		return;
+	}
+
+	buf = repo_read_object_file(the_repository, &tag->object.oid, &type,
+				    &size);
+	if (!buf)
+		die("could not read tag %s", oid_to_hex(&tag->object.oid));
+	message = memmem(buf, size, "\n\n", 2);
+	if (message) {
+		message += 2;
+		message_size = strlen(message);
+	}
+	tagger = memmem(buf, message ? message - buf : size, "\ntagger ", 8);
+	if (!tagger) {
+		if (fake_missing_tagger)
+			tagger = "tagger Unspecified Tagger "
+				"<unspecified-tagger> 0 +0000";
+		else
+			tagger = "";
+		tagger_end = tagger + strlen(tagger);
+	} else {
+		tagger++;
+		tagger_end = strchrnul(tagger, '\n');
+		if (anonymize)
+			anonymize_ident_line(&tagger, &tagger_end);
+	}
+
+	if (anonymize) {
+		name = anonymize_refname(name);
+		if (message) {
+			static struct hashmap tags;
+			message = anonymize_str(&tags, anonymize_tag,
+						message, message_size);
+			message_size = strlen(message);
+		}
+	}
+
+	/* handle signed tags */
+	if (message) {
+		const char *signature = strstr(message,
+					       "\n-----BEGIN PGP SIGNATURE-----\n");
+		if (signature)
+			switch(signed_tag_mode) {
+			case SIGNED_TAG_ABORT:
+				die("encountered signed tag %s; use "
+				    "--signed-tags=<mode> to handle it",
+				    oid_to_hex(&tag->object.oid));
+			case WARN:
+				warning("exporting signed tag %s",
+					oid_to_hex(&tag->object.oid));
+				/* fallthru */
+			case VERBATIM:
+				break;
+			case WARN_STRIP:
+				warning("stripping signature from tag %s",
+					oid_to_hex(&tag->object.oid));
+				/* fallthru */
+			case STRIP:
+				message_size = signature + 1 - message;
+				break;
+			}
+	}
+
+	/* handle tag->tagged having been filtered out due to paths specified */
+	tagged = tag->tagged;
+	tagged_mark = get_object_mark(tagged);
+	if (!tagged_mark) {
+		switch(tag_of_filtered_mode) {
+		case TAG_FILTERING_ABORT:
+			die("tag %s tags unexported object; use "
+			    "--tag-of-filtered-object=<mode> to handle it",
+			    oid_to_hex(&tag->object.oid));
+		case DROP:
+			/* Ignore this tag altogether */
+			free(buf);
+			return;
+		case REWRITE:
+			if (tagged->type == OBJ_TAG && !mark_tags) {
+				die(_("Error: Cannot export nested tags unless --mark-tags is specified."));
+			} else if (tagged->type == OBJ_COMMIT) {
+				p = rewrite_commit((struct commit *)tagged);
+				if (!p) {
+					printf("reset %s\nfrom %s\n\n",
+					       name, oid_to_hex(null_oid()));
+					free(buf);
+					return;
+				}
+				tagged_mark = get_object_mark(&p->object);
+			} else {
+				/* tagged->type is either OBJ_BLOB or OBJ_TAG */
+				tagged_mark = get_object_mark(tagged);
+			}
+		}
+	}
+
+	if (tagged->type == OBJ_TAG) {
+		printf("reset %s\nfrom %s\n\n",
+		       name, oid_to_hex(null_oid()));
+	}
+	skip_prefix(name, "refs/tags/", &name);
+	printf("tag %s\n", name);
+	if (mark_tags) {
+		mark_next_object(&tag->object);
+		printf("mark :%"PRIu32"\n", last_idnum);
+	}
+	if (tagged_mark)
+		printf("from :%d\n", tagged_mark);
+	else
+		printf("from %s\n", oid_to_hex(&tagged->oid));
+
+	if (show_original_ids)
+		printf("original-oid %s\n", oid_to_hex(&tag->object.oid));
+	printf("%.*s%sdata %d\n%.*s\n",
+	       (int)(tagger_end - tagger), tagger,
+	       tagger == tagger_end ? "" : "\n",
+	       (int)message_size, (int)message_size, message ? message : "");
+	free(buf);
+}
+
+static struct commit *get_commit(struct rev_cmdline_entry *e, const char *full_name)
+{
+	switch (e->item->type) {
+	case OBJ_COMMIT:
+		return (struct commit *)e->item;
+	case OBJ_TAG: {
+		struct tag *tag = (struct tag *)e->item;
+
+		/* handle nested tags */
+		while (tag && tag->object.type == OBJ_TAG) {
+			parse_object(the_repository, &tag->object.oid);
+			string_list_append(&tag_refs, full_name)->util = tag;
+			tag = (struct tag *)tag->tagged;
+		}
+		if (!tag)
+			die("Tag %s points nowhere?", e->name);
+		return (struct commit *)tag;
+	}
+	default:
+		return NULL;
+	}
+}
+
+static void get_tags_and_duplicates(struct rev_cmdline_info *info)
+{
+	int i;
+
+	for (i = 0; i < info->nr; i++) {
+		struct rev_cmdline_entry *e = info->rev + i;
+		struct object_id oid;
+		struct commit *commit;
+		char *full_name = NULL;
+
+		if (e->flags & UNINTERESTING)
+			continue;
+
+		if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
+				  &oid, &full_name, 0) != 1) {
+			free(full_name);
+			continue;
+		}
+
+		if (refspecs.nr) {
+			char *private;
+			private = apply_refspecs(&refspecs, full_name);
+			if (private) {
+				free(full_name);
+				full_name = private;
+			}
+		}
+
+		commit = get_commit(e, full_name);
+		if (!commit) {
+			warning("%s: Unexpected object of type %s, skipping.",
+				e->name,
+				type_name(e->item->type));
+			free(full_name);
+			continue;
+		}
+
+		switch(commit->object.type) {
+		case OBJ_COMMIT:
+			break;
+		case OBJ_BLOB:
+			export_blob(&commit->object.oid);
+			free(full_name);
+			continue;
+		default: /* OBJ_TAG (nested tags) is already handled */
+			warning("Tag points to object of unexpected type %s, skipping.",
+				type_name(commit->object.type));
+			free(full_name);
+			continue;
+		}
+
+		/*
+		 * Make sure this ref gets properly updated eventually, whether
+		 * through a commit or manually at the end.
+		 */
+		if (e->item->type != OBJ_TAG)
+			string_list_append(&extra_refs, full_name)->util = commit;
+
+		if (!*revision_sources_at(&revision_sources, commit))
+			*revision_sources_at(&revision_sources, commit) = full_name;
+		else
+			free(full_name);
+	}
+
+	string_list_sort(&extra_refs);
+	string_list_remove_duplicates(&extra_refs, 0);
+}
+
+static void handle_tags_and_duplicates(struct string_list *extras)
+{
+	struct commit *commit;
+	int i;
+
+	for (i = extras->nr - 1; i >= 0; i--) {
+		const char *name = extras->items[i].string;
+		struct object *object = extras->items[i].util;
+		int mark;
+
+		switch (object->type) {
+		case OBJ_TAG:
+			handle_tag(name, (struct tag *)object);
+			break;
+		case OBJ_COMMIT:
+			if (anonymize)
+				name = anonymize_refname(name);
+			/* create refs pointing to already seen commits */
+			commit = rewrite_commit((struct commit *)object);
+			if (!commit) {
+				/*
+				 * Neither this object nor any of its
+				 * ancestors touch any relevant paths, so
+				 * it has been filtered to nothing.  Delete
+				 * it.
+				 */
+				printf("reset %s\nfrom %s\n\n",
+				       name, oid_to_hex(null_oid()));
+				continue;
+			}
+
+			mark = get_object_mark(&commit->object);
+			if (!mark) {
+				/*
+				 * Getting here means we have a commit which
+				 * was excluded by a negative refspec (e.g.
+				 * fast-export ^HEAD HEAD).  If we are
+				 * referencing excluded commits, set the ref
+				 * to the exact commit.  Otherwise, the user
+				 * wants the branch exported but every commit
+				 * in its history to be deleted, which basically
+				 * just means deletion of the ref.
+				 */
+				if (!reference_excluded_commits) {
+					/* delete the ref */
+					printf("reset %s\nfrom %s\n\n",
+					       name, oid_to_hex(null_oid()));
+					continue;
+				}
+				/* set ref to commit using oid, not mark */
+				printf("reset %s\nfrom %s\n\n", name,
+				       oid_to_hex(&commit->object.oid));
+				continue;
+			}
+
+			printf("reset %s\nfrom :%d\n\n", name, mark
+			       );
+			show_progress();
+			break;
+		}
+	}
+}
+
+static void export_marks(char *file)
+{
+	unsigned int i;
+	uint32_t mark;
+	struct decoration_entry *deco = idnums.entries;
+	FILE *f;
+	int e = 0;
+
+	f = fopen_for_writing(file);
+	if (!f)
+		die_errno("Unable to open marks file %s for writing.", file);
+
+	for (i = 0; i < idnums.size; i++) {
+		if (deco->base && deco->base->type == 1) {
+			mark = ptr_to_mark(deco->decoration);
+			if (fprintf(f, ":%"PRIu32" %s\n", mark,
+				oid_to_hex(&deco->base->oid)) < 0) {
+			    e = 1;
+			    break;
+			}
+		}
+		deco++;
+	}
+
+	e |= ferror(f);
+	e |= fclose(f);
+	if (e)
+		error("Unable to write marks file %s.", file);
+}
+
+static void import_marks(char *input_file, int check_exists)
+{
+	char line[512];
+	FILE *f;
+	struct stat sb;
+
+	if (check_exists && stat(input_file, &sb))
+		return;
+
+	f = xfopen(input_file, "r");
+	while (fgets(line, sizeof(line), f)) {
+		uint32_t mark;
+		char *line_end, *mark_end;
+		struct object_id oid;
+		struct object *object;
+		struct commit *commit;
+		enum object_type type;
+
+		line_end = strchr(line, '\n');
+		if (line[0] != ':' || !line_end)
+			die("corrupt mark line: %s", line);
+		*line_end = '\0';
+
+		mark = strtoumax(line + 1, &mark_end, 10);
+		if (!mark || mark_end == line + 1
+			|| *mark_end != ' ' || get_oid_hex(mark_end + 1, &oid))
+			die("corrupt mark line: %s", line);
+
+		if (last_idnum < mark)
+			last_idnum = mark;
+
+		type = oid_object_info(the_repository, &oid, NULL);
+		if (type < 0)
+			die("object not found: %s", oid_to_hex(&oid));
+
+		if (type != OBJ_COMMIT)
+			/* only commits */
+			continue;
+
+		commit = lookup_commit(the_repository, &oid);
+		if (!commit)
+			die("not a commit? can't happen: %s", oid_to_hex(&oid));
+
+		object = &commit->object;
+
+		if (object->flags & SHOWN)
+			error("Object %s already has a mark", oid_to_hex(&oid));
+
+		mark_object(object, mark);
+
+		object->flags |= SHOWN;
+	}
+	fclose(f);
+}
+
+static void handle_deletes(void)
+{
+	int i;
+	for (i = 0; i < refspecs.nr; i++) {
+		struct refspec_item *refspec = &refspecs.items[i];
+		if (*refspec->src)
+			continue;
+
+		printf("reset %s\nfrom %s\n\n",
+				refspec->dst, oid_to_hex(null_oid()));
+	}
+}
+
+static int parse_opt_anonymize_map(const struct option *opt,
+				   const char *arg, int unset)
+{
+	struct hashmap *map = opt->value;
+	const char *delim, *value;
+	size_t keylen;
+
+	BUG_ON_OPT_NEG(unset);
+
+	delim = strchr(arg, ':');
+	if (delim) {
+		keylen = delim - arg;
+		value = delim + 1;
+	} else {
+		keylen = strlen(arg);
+		value = arg;
+	}
+
+	if (!keylen || !*value)
+		return error(_("--anonymize-map token cannot be empty"));
+
+	add_anonymized_entry(map, memhash(arg, keylen), arg, keylen,
+			     xstrdup(value));
+
+	return 0;
+}
+
+int cmd_fast_export(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
+{
+	struct rev_info revs;
+	struct commit *commit;
+	char *export_filename = NULL,
+	     *import_filename = NULL,
+	     *import_filename_if_exists = NULL;
+	uint32_t lastimportid;
+	struct string_list refspecs_list = STRING_LIST_INIT_NODUP;
+	struct string_list paths_of_changed_objects = STRING_LIST_INIT_DUP;
+	struct option options[] = {
+		OPT_INTEGER(0, "progress", &progress,
+			    N_("show progress after <n> objects")),
+		OPT_CALLBACK(0, "signed-tags", &signed_tag_mode, N_("mode"),
+			     N_("select handling of signed tags"),
+			     parse_opt_signed_tag_mode),
+		OPT_CALLBACK(0, "tag-of-filtered-object", &tag_of_filtered_mode, N_("mode"),
+			     N_("select handling of tags that tag filtered objects"),
+			     parse_opt_tag_of_filtered_mode),
+		OPT_CALLBACK(0, "reencode", &reencode_mode, N_("mode"),
+			     N_("select handling of commit messages in an alternate encoding"),
+			     parse_opt_reencode_mode),
+		OPT_STRING(0, "export-marks", &export_filename, N_("file"),
+			     N_("dump marks to this file")),
+		OPT_STRING(0, "import-marks", &import_filename, N_("file"),
+			     N_("import marks from this file")),
+		OPT_STRING(0, "import-marks-if-exists",
+			     &import_filename_if_exists,
+			     N_("file"),
+			     N_("import marks from this file if it exists")),
+		OPT_BOOL(0, "fake-missing-tagger", &fake_missing_tagger,
+			 N_("fake a tagger when tags lack one")),
+		OPT_BOOL(0, "full-tree", &full_tree,
+			 N_("output full tree for each commit")),
+		OPT_BOOL(0, "use-done-feature", &use_done_feature,
+			     N_("use the done feature to terminate the stream")),
+		OPT_BOOL(0, "no-data", &no_data, N_("skip output of blob data")),
+		OPT_STRING_LIST(0, "refspec", &refspecs_list, N_("refspec"),
+			     N_("apply refspec to exported refs")),
+		OPT_BOOL(0, "anonymize", &anonymize, N_("anonymize output")),
+		OPT_CALLBACK_F(0, "anonymize-map", &anonymized_seeds, N_("from:to"),
+			       N_("convert <from> to <to> in anonymized output"),
+			       PARSE_OPT_NONEG, parse_opt_anonymize_map),
+		OPT_BOOL(0, "reference-excluded-parents",
+			 &reference_excluded_commits, N_("reference parents which are not in fast-export stream by object id")),
+		OPT_BOOL(0, "show-original-ids", &show_original_ids,
+			    N_("show original object ids of blobs/commits")),
+		OPT_BOOL(0, "mark-tags", &mark_tags,
+			    N_("label tags with mark ids")),
+
+		OPT_END()
+	};
+
+	if (argc == 1)
+		usage_with_options (fast_export_usage, options);
+
+	/* we handle encodings */
+	git_config(git_default_config, NULL);
+
+	repo_init_revisions(the_repository, &revs, prefix);
+	init_revision_sources(&revision_sources);
+	revs.topo_order = 1;
+	revs.sources = &revision_sources;
+	revs.rewrite_parents = 1;
+	argc = parse_options(argc, argv, prefix, options, fast_export_usage,
+			PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
+	argc = setup_revisions(argc, argv, &revs, NULL);
+	if (argc > 1)
+		usage_with_options (fast_export_usage, options);
+
+	if (anonymized_seeds.cmpfn && !anonymize)
+		die(_("the option '%s' requires '%s'"), "--anonymize-map", "--anonymize");
+
+	if (refspecs_list.nr) {
+		int i;
+
+		for (i = 0; i < refspecs_list.nr; i++)
+			refspec_append(&refspecs, refspecs_list.items[i].string);
+
+		string_list_clear(&refspecs_list, 1);
+	}
+
+	if (use_done_feature)
+		printf("feature done\n");
+
+	if (import_filename && import_filename_if_exists)
+		die(_("options '%s' and '%s' cannot be used together"), "--import-marks", "--import-marks-if-exists");
+	if (import_filename)
+		import_marks(import_filename, 0);
+	else if (import_filename_if_exists)
+		import_marks(import_filename_if_exists, 1);
+	lastimportid = last_idnum;
+
+	if (import_filename && revs.prune_data.nr)
+		full_tree = 1;
+
+	get_tags_and_duplicates(&revs.cmdline);
+
+	if (prepare_revision_walk(&revs))
+		die("revision walk setup failed");
+
+	revs.reverse = 1;
+	revs.diffopt.format_callback = show_filemodify;
+	revs.diffopt.format_callback_data = &paths_of_changed_objects;
+	revs.diffopt.flags.recursive = 1;
+
+	revs.diffopt.no_free = 1;
+	while ((commit = get_revision(&revs)))
+		handle_commit(commit, &revs, &paths_of_changed_objects);
+	revs.diffopt.no_free = 0;
+
+	handle_tags_and_duplicates(&extra_refs);
+	handle_tags_and_duplicates(&tag_refs);
+	handle_deletes();
+
+	if (export_filename && lastimportid != last_idnum)
+		export_marks(export_filename);
+
+	if (use_done_feature)
+		printf("done\n");
+
+	refspec_clear(&refspecs);
+	release_revisions(&revs);
+
+	return 0;
+}
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
new file mode 100644
index 0000000000..2da46fecdc
--- /dev/null
+++ b/builtin/fast-import.c
@@ -0,0 +1,3690 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "config.h"
+#include "lockfile.h"
+#include "object.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "delta.h"
+#include "pack.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "refs.h"
+#include "csum-file.h"
+#include "quote.h"
+#include "dir.h"
+#include "run-command.h"
+#include "packfile.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "mem-pool.h"
+#include "commit-reach.h"
+#include "khash.h"
+#include "date.h"
+
+#define PACK_ID_BITS 16
+#define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
+#define DEPTH_BITS 13
+#define MAX_DEPTH ((1<<DEPTH_BITS)-1)
+
+/*
+ * We abuse the setuid bit on directories to mean "do not delta".
+ */
+#define NO_DELTA S_ISUID
+
+/*
+ * The amount of additional space required in order to write an object into the
+ * current pack. This is the hash lengths at the end of the pack, plus the
+ * length of one object ID.
+ */
+#define PACK_SIZE_THRESHOLD (the_hash_algo->rawsz * 3)
+
+struct object_entry {
+	struct pack_idx_entry idx;
+	struct hashmap_entry ent;
+	uint32_t type : TYPE_BITS,
+		pack_id : PACK_ID_BITS,
+		depth : DEPTH_BITS;
+};
+
+static int object_entry_hashcmp(const void *map_data UNUSED,
+				const struct hashmap_entry *eptr,
+				const struct hashmap_entry *entry_or_key,
+				const void *keydata)
+{
+	const struct object_id *oid = keydata;
+	const struct object_entry *e1, *e2;
+
+	e1 = container_of(eptr, const struct object_entry, ent);
+	if (oid)
+		return oidcmp(&e1->idx.oid, oid);
+
+	e2 = container_of(entry_or_key, const struct object_entry, ent);
+	return oidcmp(&e1->idx.oid, &e2->idx.oid);
+}
+
+struct object_entry_pool {
+	struct object_entry_pool *next_pool;
+	struct object_entry *next_free;
+	struct object_entry *end;
+	struct object_entry entries[FLEX_ARRAY]; /* more */
+};
+
+struct mark_set {
+	union {
+		struct object_id *oids[1024];
+		struct object_entry *marked[1024];
+		struct mark_set *sets[1024];
+	} data;
+	unsigned int shift;
+};
+
+struct last_object {
+	struct strbuf data;
+	off_t offset;
+	unsigned int depth;
+	unsigned no_swap : 1;
+};
+
+struct atom_str {
+	struct atom_str *next_atom;
+	unsigned short str_len;
+	char str_dat[FLEX_ARRAY]; /* more */
+};
+
+struct tree_content;
+struct tree_entry {
+	struct tree_content *tree;
+	struct atom_str *name;
+	struct tree_entry_ms {
+		uint16_t mode;
+		struct object_id oid;
+	} versions[2];
+};
+
+struct tree_content {
+	unsigned int entry_capacity; /* must match avail_tree_content */
+	unsigned int entry_count;
+	unsigned int delta_depth;
+	struct tree_entry *entries[FLEX_ARRAY]; /* more */
+};
+
+struct avail_tree_content {
+	unsigned int entry_capacity; /* must match tree_content */
+	struct avail_tree_content *next_avail;
+};
+
+struct branch {
+	struct branch *table_next_branch;
+	struct branch *active_next_branch;
+	const char *name;
+	struct tree_entry branch_tree;
+	uintmax_t last_commit;
+	uintmax_t num_notes;
+	unsigned active : 1;
+	unsigned delete : 1;
+	unsigned pack_id : PACK_ID_BITS;
+	struct object_id oid;
+};
+
+struct tag {
+	struct tag *next_tag;
+	const char *name;
+	unsigned int pack_id;
+	struct object_id oid;
+};
+
+struct hash_list {
+	struct hash_list *next;
+	struct object_id oid;
+};
+
+typedef enum {
+	WHENSPEC_RAW = 1,
+	WHENSPEC_RAW_PERMISSIVE,
+	WHENSPEC_RFC2822,
+	WHENSPEC_NOW
+} whenspec_type;
+
+struct recent_command {
+	struct recent_command *prev;
+	struct recent_command *next;
+	char *buf;
+};
+
+typedef void (*mark_set_inserter_t)(struct mark_set **s, struct object_id *oid, uintmax_t mark);
+typedef void (*each_mark_fn_t)(uintmax_t mark, void *obj, void *cbp);
+
+/* Configured limits on output */
+static unsigned long max_depth = 50;
+static off_t max_packsize;
+static int unpack_limit = 100;
+static int force_update;
+
+/* Stats and misc. counters */
+static uintmax_t alloc_count;
+static uintmax_t marks_set_count;
+static uintmax_t object_count_by_type[1 << TYPE_BITS];
+static uintmax_t duplicate_count_by_type[1 << TYPE_BITS];
+static uintmax_t delta_count_by_type[1 << TYPE_BITS];
+static uintmax_t delta_count_attempts_by_type[1 << TYPE_BITS];
+static unsigned long object_count;
+static unsigned long branch_count;
+static unsigned long branch_load_count;
+static int failure;
+static FILE *pack_edges;
+static unsigned int show_stats = 1;
+static unsigned int quiet;
+static int global_argc;
+static const char **global_argv;
+static const char *global_prefix;
+
+/* Memory pools */
+static struct mem_pool fi_mem_pool = {
+	.block_alloc = 2*1024*1024 - sizeof(struct mp_block),
+};
+
+/* Atom management */
+static unsigned int atom_table_sz = 4451;
+static unsigned int atom_cnt;
+static struct atom_str **atom_table;
+
+/* The .pack file being generated */
+static struct pack_idx_option pack_idx_opts;
+static unsigned int pack_id;
+static struct hashfile *pack_file;
+static struct packed_git *pack_data;
+static struct packed_git **all_packs;
+static off_t pack_size;
+
+/* Table of objects we've written. */
+static unsigned int object_entry_alloc = 5000;
+static struct object_entry_pool *blocks;
+static struct hashmap object_table;
+static struct mark_set *marks;
+static char *export_marks_file;
+static char *import_marks_file;
+static int import_marks_file_from_stream;
+static int import_marks_file_ignore_missing;
+static int import_marks_file_done;
+static int relative_marks_paths;
+
+/* Our last blob */
+static struct last_object last_blob = {
+	.data = STRBUF_INIT,
+ };
+
+/* Tree management */
+static unsigned int tree_entry_alloc = 1000;
+static void *avail_tree_entry;
+static unsigned int avail_tree_table_sz = 100;
+static struct avail_tree_content **avail_tree_table;
+static size_t tree_entry_allocd;
+static struct strbuf old_tree = STRBUF_INIT;
+static struct strbuf new_tree = STRBUF_INIT;
+
+/* Branch data */
+static unsigned long max_active_branches = 5;
+static unsigned long cur_active_branches;
+static unsigned long branch_table_sz = 1039;
+static struct branch **branch_table;
+static struct branch *active_branches;
+
+/* Tag data */
+static struct tag *first_tag;
+static struct tag *last_tag;
+
+/* Input stream parsing */
+static whenspec_type whenspec = WHENSPEC_RAW;
+static struct strbuf command_buf = STRBUF_INIT;
+static int unread_command_buf;
+static struct recent_command cmd_hist = {
+	.prev = &cmd_hist,
+	.next = &cmd_hist,
+};
+static struct recent_command *cmd_tail = &cmd_hist;
+static struct recent_command *rc_free;
+static unsigned int cmd_save = 100;
+static uintmax_t next_mark;
+static struct strbuf new_data = STRBUF_INIT;
+static int seen_data_command;
+static int require_explicit_termination;
+static int allow_unsafe_features;
+
+/* Signal handling */
+static volatile sig_atomic_t checkpoint_requested;
+
+/* Submodule marks */
+static struct string_list sub_marks_from = STRING_LIST_INIT_DUP;
+static struct string_list sub_marks_to = STRING_LIST_INIT_DUP;
+static kh_oid_map_t *sub_oid_map;
+
+/* Where to write output of cat-blob commands */
+static int cat_blob_fd = STDOUT_FILENO;
+
+static void parse_argv(void);
+static void parse_get_mark(const char *p);
+static void parse_cat_blob(const char *p);
+static void parse_ls(const char *p, struct branch *b);
+
+static void for_each_mark(struct mark_set *m, uintmax_t base, each_mark_fn_t callback, void *p)
+{
+	uintmax_t k;
+	if (m->shift) {
+		for (k = 0; k < 1024; k++) {
+			if (m->data.sets[k])
+				for_each_mark(m->data.sets[k], base + (k << m->shift), callback, p);
+		}
+	} else {
+		for (k = 0; k < 1024; k++) {
+			if (m->data.marked[k])
+				callback(base + k, m->data.marked[k], p);
+		}
+	}
+}
+
+static void dump_marks_fn(uintmax_t mark, void *object, void *cbp) {
+	struct object_entry *e = object;
+	FILE *f = cbp;
+
+	fprintf(f, ":%" PRIuMAX " %s\n", mark, oid_to_hex(&e->idx.oid));
+}
+
+static void write_branch_report(FILE *rpt, struct branch *b)
+{
+	fprintf(rpt, "%s:\n", b->name);
+
+	fprintf(rpt, "  status      :");
+	if (b->active)
+		fputs(" active", rpt);
+	if (b->branch_tree.tree)
+		fputs(" loaded", rpt);
+	if (is_null_oid(&b->branch_tree.versions[1].oid))
+		fputs(" dirty", rpt);
+	fputc('\n', rpt);
+
+	fprintf(rpt, "  tip commit  : %s\n", oid_to_hex(&b->oid));
+	fprintf(rpt, "  old tree    : %s\n",
+		oid_to_hex(&b->branch_tree.versions[0].oid));
+	fprintf(rpt, "  cur tree    : %s\n",
+		oid_to_hex(&b->branch_tree.versions[1].oid));
+	fprintf(rpt, "  commit clock: %" PRIuMAX "\n", b->last_commit);
+
+	fputs("  last pack   : ", rpt);
+	if (b->pack_id < MAX_PACK_ID)
+		fprintf(rpt, "%u", b->pack_id);
+	fputc('\n', rpt);
+
+	fputc('\n', rpt);
+}
+
+static void write_crash_report(const char *err)
+{
+	char *loc = git_pathdup("fast_import_crash_%"PRIuMAX, (uintmax_t) getpid());
+	FILE *rpt = fopen(loc, "w");
+	struct branch *b;
+	unsigned long lu;
+	struct recent_command *rc;
+
+	if (!rpt) {
+		error_errno("can't write crash report %s", loc);
+		free(loc);
+		return;
+	}
+
+	fprintf(stderr, "fast-import: dumping crash report to %s\n", loc);
+
+	fprintf(rpt, "fast-import crash report:\n");
+	fprintf(rpt, "    fast-import process: %"PRIuMAX"\n", (uintmax_t) getpid());
+	fprintf(rpt, "    parent process     : %"PRIuMAX"\n", (uintmax_t) getppid());
+	fprintf(rpt, "    at %s\n", show_date(time(NULL), 0, DATE_MODE(ISO8601)));
+	fputc('\n', rpt);
+
+	fputs("fatal: ", rpt);
+	fputs(err, rpt);
+	fputc('\n', rpt);
+
+	fputc('\n', rpt);
+	fputs("Most Recent Commands Before Crash\n", rpt);
+	fputs("---------------------------------\n", rpt);
+	for (rc = cmd_hist.next; rc != &cmd_hist; rc = rc->next) {
+		if (rc->next == &cmd_hist)
+			fputs("* ", rpt);
+		else
+			fputs("  ", rpt);
+		fputs(rc->buf, rpt);
+		fputc('\n', rpt);
+	}
+
+	fputc('\n', rpt);
+	fputs("Active Branch LRU\n", rpt);
+	fputs("-----------------\n", rpt);
+	fprintf(rpt, "    active_branches = %lu cur, %lu max\n",
+		cur_active_branches,
+		max_active_branches);
+	fputc('\n', rpt);
+	fputs("  pos  clock name\n", rpt);
+	fputs("  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n", rpt);
+	for (b = active_branches, lu = 0; b; b = b->active_next_branch)
+		fprintf(rpt, "  %2lu) %6" PRIuMAX" %s\n",
+			++lu, b->last_commit, b->name);
+
+	fputc('\n', rpt);
+	fputs("Inactive Branches\n", rpt);
+	fputs("-----------------\n", rpt);
+	for (lu = 0; lu < branch_table_sz; lu++) {
+		for (b = branch_table[lu]; b; b = b->table_next_branch)
+			write_branch_report(rpt, b);
+	}
+
+	if (first_tag) {
+		struct tag *tg;
+		fputc('\n', rpt);
+		fputs("Annotated Tags\n", rpt);
+		fputs("--------------\n", rpt);
+		for (tg = first_tag; tg; tg = tg->next_tag) {
+			fputs(oid_to_hex(&tg->oid), rpt);
+			fputc(' ', rpt);
+			fputs(tg->name, rpt);
+			fputc('\n', rpt);
+		}
+	}
+
+	fputc('\n', rpt);
+	fputs("Marks\n", rpt);
+	fputs("-----\n", rpt);
+	if (export_marks_file)
+		fprintf(rpt, "  exported to %s\n", export_marks_file);
+	else
+		for_each_mark(marks, 0, dump_marks_fn, rpt);
+
+	fputc('\n', rpt);
+	fputs("-------------------\n", rpt);
+	fputs("END OF CRASH REPORT\n", rpt);
+	fclose(rpt);
+	free(loc);
+}
+
+static void end_packfile(void);
+static void unkeep_all_packs(void);
+static void dump_marks(void);
+
+static NORETURN void die_nicely(const char *err, va_list params)
+{
+	va_list cp;
+	static int zombie;
+	report_fn die_message_fn = get_die_message_routine();
+
+	va_copy(cp, params);
+	die_message_fn(err, params);
+
+	if (!zombie) {
+		char message[2 * PATH_MAX];
+
+		zombie = 1;
+		vsnprintf(message, sizeof(message), err, cp);
+		write_crash_report(message);
+		end_packfile();
+		unkeep_all_packs();
+		dump_marks();
+	}
+	exit(128);
+}
+
+#ifndef SIGUSR1	/* Windows, for example */
+
+static void set_checkpoint_signal(void)
+{
+}
+
+#else
+
+static void checkpoint_signal(int signo UNUSED)
+{
+	checkpoint_requested = 1;
+}
+
+static void set_checkpoint_signal(void)
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = checkpoint_signal;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_RESTART;
+	sigaction(SIGUSR1, &sa, NULL);
+}
+
+#endif
+
+static void alloc_objects(unsigned int cnt)
+{
+	struct object_entry_pool *b;
+
+	b = xmalloc(sizeof(struct object_entry_pool)
+		+ cnt * sizeof(struct object_entry));
+	b->next_pool = blocks;
+	b->next_free = b->entries;
+	b->end = b->entries + cnt;
+	blocks = b;
+	alloc_count += cnt;
+}
+
+static struct object_entry *new_object(struct object_id *oid)
+{
+	struct object_entry *e;
+
+	if (blocks->next_free == blocks->end)
+		alloc_objects(object_entry_alloc);
+
+	e = blocks->next_free++;
+	oidcpy(&e->idx.oid, oid);
+	return e;
+}
+
+static struct object_entry *find_object(struct object_id *oid)
+{
+	return hashmap_get_entry_from_hash(&object_table, oidhash(oid), oid,
+					   struct object_entry, ent);
+}
+
+static struct object_entry *insert_object(struct object_id *oid)
+{
+	struct object_entry *e;
+	unsigned int hash = oidhash(oid);
+
+	e = hashmap_get_entry_from_hash(&object_table, hash, oid,
+					struct object_entry, ent);
+	if (!e) {
+		e = new_object(oid);
+		e->idx.offset = 0;
+		hashmap_entry_init(&e->ent, hash);
+		hashmap_add(&object_table, &e->ent);
+	}
+
+	return e;
+}
+
+static void invalidate_pack_id(unsigned int id)
+{
+	unsigned long lu;
+	struct tag *t;
+	struct hashmap_iter iter;
+	struct object_entry *e;
+
+	hashmap_for_each_entry(&object_table, &iter, e, ent) {
+		if (e->pack_id == id)
+			e->pack_id = MAX_PACK_ID;
+	}
+
+	for (lu = 0; lu < branch_table_sz; lu++) {
+		struct branch *b;
+
+		for (b = branch_table[lu]; b; b = b->table_next_branch)
+			if (b->pack_id == id)
+				b->pack_id = MAX_PACK_ID;
+	}
+
+	for (t = first_tag; t; t = t->next_tag)
+		if (t->pack_id == id)
+			t->pack_id = MAX_PACK_ID;
+}
+
+static unsigned int hc_str(const char *s, size_t len)
+{
+	unsigned int r = 0;
+	while (len-- > 0)
+		r = r * 31 + *s++;
+	return r;
+}
+
+static void insert_mark(struct mark_set **top, uintmax_t idnum, struct object_entry *oe)
+{
+	struct mark_set *s = *top;
+
+	while ((idnum >> s->shift) >= 1024) {
+		s = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct mark_set));
+		s->shift = (*top)->shift + 10;
+		s->data.sets[0] = *top;
+		*top = s;
+	}
+	while (s->shift) {
+		uintmax_t i = idnum >> s->shift;
+		idnum -= i << s->shift;
+		if (!s->data.sets[i]) {
+			s->data.sets[i] = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct mark_set));
+			s->data.sets[i]->shift = s->shift - 10;
+		}
+		s = s->data.sets[i];
+	}
+	if (!s->data.marked[idnum])
+		marks_set_count++;
+	s->data.marked[idnum] = oe;
+}
+
+static void *find_mark(struct mark_set *s, uintmax_t idnum)
+{
+	uintmax_t orig_idnum = idnum;
+	struct object_entry *oe = NULL;
+	if ((idnum >> s->shift) < 1024) {
+		while (s && s->shift) {
+			uintmax_t i = idnum >> s->shift;
+			idnum -= i << s->shift;
+			s = s->data.sets[i];
+		}
+		if (s)
+			oe = s->data.marked[idnum];
+	}
+	if (!oe)
+		die("mark :%" PRIuMAX " not declared", orig_idnum);
+	return oe;
+}
+
+static struct atom_str *to_atom(const char *s, unsigned short len)
+{
+	unsigned int hc = hc_str(s, len) % atom_table_sz;
+	struct atom_str *c;
+
+	for (c = atom_table[hc]; c; c = c->next_atom)
+		if (c->str_len == len && !strncmp(s, c->str_dat, len))
+			return c;
+
+	c = mem_pool_alloc(&fi_mem_pool, sizeof(struct atom_str) + len + 1);
+	c->str_len = len;
+	memcpy(c->str_dat, s, len);
+	c->str_dat[len] = 0;
+	c->next_atom = atom_table[hc];
+	atom_table[hc] = c;
+	atom_cnt++;
+	return c;
+}
+
+static struct branch *lookup_branch(const char *name)
+{
+	unsigned int hc = hc_str(name, strlen(name)) % branch_table_sz;
+	struct branch *b;
+
+	for (b = branch_table[hc]; b; b = b->table_next_branch)
+		if (!strcmp(name, b->name))
+			return b;
+	return NULL;
+}
+
+static struct branch *new_branch(const char *name)
+{
+	unsigned int hc = hc_str(name, strlen(name)) % branch_table_sz;
+	struct branch *b = lookup_branch(name);
+
+	if (b)
+		die("Invalid attempt to create duplicate branch: %s", name);
+	if (check_refname_format(name, REFNAME_ALLOW_ONELEVEL))
+		die("Branch name doesn't conform to GIT standards: %s", name);
+
+	b = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));
+	b->name = mem_pool_strdup(&fi_mem_pool, name);
+	b->table_next_branch = branch_table[hc];
+	b->branch_tree.versions[0].mode = S_IFDIR;
+	b->branch_tree.versions[1].mode = S_IFDIR;
+	b->num_notes = 0;
+	b->active = 0;
+	b->pack_id = MAX_PACK_ID;
+	branch_table[hc] = b;
+	branch_count++;
+	return b;
+}
+
+static unsigned int hc_entries(unsigned int cnt)
+{
+	cnt = cnt & 7 ? (cnt / 8) + 1 : cnt / 8;
+	return cnt < avail_tree_table_sz ? cnt : avail_tree_table_sz - 1;
+}
+
+static struct tree_content *new_tree_content(unsigned int cnt)
+{
+	struct avail_tree_content *f, *l = NULL;
+	struct tree_content *t;
+	unsigned int hc = hc_entries(cnt);
+
+	for (f = avail_tree_table[hc]; f; l = f, f = f->next_avail)
+		if (f->entry_capacity >= cnt)
+			break;
+
+	if (f) {
+		if (l)
+			l->next_avail = f->next_avail;
+		else
+			avail_tree_table[hc] = f->next_avail;
+	} else {
+		cnt = cnt & 7 ? ((cnt / 8) + 1) * 8 : cnt;
+		f = mem_pool_alloc(&fi_mem_pool, sizeof(*t) + sizeof(t->entries[0]) * cnt);
+		f->entry_capacity = cnt;
+	}
+
+	t = (struct tree_content*)f;
+	t->entry_count = 0;
+	t->delta_depth = 0;
+	return t;
+}
+
+static void release_tree_entry(struct tree_entry *e);
+static void release_tree_content(struct tree_content *t)
+{
+	struct avail_tree_content *f = (struct avail_tree_content*)t;
+	unsigned int hc = hc_entries(f->entry_capacity);
+	f->next_avail = avail_tree_table[hc];
+	avail_tree_table[hc] = f;
+}
+
+static void release_tree_content_recursive(struct tree_content *t)
+{
+	unsigned int i;
+	for (i = 0; i < t->entry_count; i++)
+		release_tree_entry(t->entries[i]);
+	release_tree_content(t);
+}
+
+static struct tree_content *grow_tree_content(
+	struct tree_content *t,
+	int amt)
+{
+	struct tree_content *r = new_tree_content(t->entry_count + amt);
+	r->entry_count = t->entry_count;
+	r->delta_depth = t->delta_depth;
+	COPY_ARRAY(r->entries, t->entries, t->entry_count);
+	release_tree_content(t);
+	return r;
+}
+
+static struct tree_entry *new_tree_entry(void)
+{
+	struct tree_entry *e;
+
+	if (!avail_tree_entry) {
+		unsigned int n = tree_entry_alloc;
+		tree_entry_allocd += n * sizeof(struct tree_entry);
+		ALLOC_ARRAY(e, n);
+		avail_tree_entry = e;
+		while (n-- > 1) {
+			*((void**)e) = e + 1;
+			e++;
+		}
+		*((void**)e) = NULL;
+	}
+
+	e = avail_tree_entry;
+	avail_tree_entry = *((void**)e);
+	return e;
+}
+
+static void release_tree_entry(struct tree_entry *e)
+{
+	if (e->tree)
+		release_tree_content_recursive(e->tree);
+	*((void**)e) = avail_tree_entry;
+	avail_tree_entry = e;
+}
+
+static struct tree_content *dup_tree_content(struct tree_content *s)
+{
+	struct tree_content *d;
+	struct tree_entry *a, *b;
+	unsigned int i;
+
+	if (!s)
+		return NULL;
+	d = new_tree_content(s->entry_count);
+	for (i = 0; i < s->entry_count; i++) {
+		a = s->entries[i];
+		b = new_tree_entry();
+		memcpy(b, a, sizeof(*a));
+		if (a->tree && is_null_oid(&b->versions[1].oid))
+			b->tree = dup_tree_content(a->tree);
+		else
+			b->tree = NULL;
+		d->entries[i] = b;
+	}
+	d->entry_count = s->entry_count;
+	d->delta_depth = s->delta_depth;
+
+	return d;
+}
+
+static void start_packfile(void)
+{
+	struct strbuf tmp_file = STRBUF_INIT;
+	struct packed_git *p;
+	int pack_fd;
+
+	pack_fd = odb_mkstemp(&tmp_file, "pack/tmp_pack_XXXXXX");
+	FLEX_ALLOC_STR(p, pack_name, tmp_file.buf);
+	strbuf_release(&tmp_file);
+
+	p->pack_fd = pack_fd;
+	p->do_not_close = 1;
+	p->repo = the_repository;
+	pack_file = hashfd(pack_fd, p->pack_name);
+
+	pack_data = p;
+	pack_size = write_pack_header(pack_file, 0);
+	object_count = 0;
+
+	REALLOC_ARRAY(all_packs, pack_id + 1);
+	all_packs[pack_id] = p;
+}
+
+static const char *create_index(void)
+{
+	const char *tmpfile;
+	struct pack_idx_entry **idx, **c, **last;
+	struct object_entry *e;
+	struct object_entry_pool *o;
+
+	/* Build the table of object IDs. */
+	ALLOC_ARRAY(idx, object_count);
+	c = idx;
+	for (o = blocks; o; o = o->next_pool)
+		for (e = o->next_free; e-- != o->entries;)
+			if (pack_id == e->pack_id)
+				*c++ = &e->idx;
+	last = idx + object_count;
+	if (c != last)
+		die("internal consistency error creating the index");
+
+	tmpfile = write_idx_file(NULL, idx, object_count, &pack_idx_opts,
+				 pack_data->hash);
+	free(idx);
+	return tmpfile;
+}
+
+static char *keep_pack(const char *curr_index_name)
+{
+	static const char *keep_msg = "fast-import";
+	struct strbuf name = STRBUF_INIT;
+	int keep_fd;
+
+	odb_pack_name(pack_data->repo, &name, pack_data->hash, "keep");
+	keep_fd = odb_pack_keep(name.buf);
+	if (keep_fd < 0)
+		die_errno("cannot create keep file");
+	write_or_die(keep_fd, keep_msg, strlen(keep_msg));
+	if (close(keep_fd))
+		die_errno("failed to write keep file");
+
+	odb_pack_name(pack_data->repo, &name, pack_data->hash, "pack");
+	if (finalize_object_file(pack_data->pack_name, name.buf))
+		die("cannot store pack file");
+
+	odb_pack_name(pack_data->repo, &name, pack_data->hash, "idx");
+	if (finalize_object_file(curr_index_name, name.buf))
+		die("cannot store index file");
+	free((void *)curr_index_name);
+	return strbuf_detach(&name, NULL);
+}
+
+static void unkeep_all_packs(void)
+{
+	struct strbuf name = STRBUF_INIT;
+	int k;
+
+	for (k = 0; k < pack_id; k++) {
+		struct packed_git *p = all_packs[k];
+		odb_pack_name(p->repo, &name, p->hash, "keep");
+		unlink_or_warn(name.buf);
+	}
+	strbuf_release(&name);
+}
+
+static int loosen_small_pack(const struct packed_git *p)
+{
+	struct child_process unpack = CHILD_PROCESS_INIT;
+
+	if (lseek(p->pack_fd, 0, SEEK_SET) < 0)
+		die_errno("Failed seeking to start of '%s'", p->pack_name);
+
+	unpack.in = p->pack_fd;
+	unpack.git_cmd = 1;
+	unpack.stdout_to_stderr = 1;
+	strvec_push(&unpack.args, "unpack-objects");
+	if (!show_stats)
+		strvec_push(&unpack.args, "-q");
+
+	return run_command(&unpack);
+}
+
+static void end_packfile(void)
+{
+	static int running;
+
+	if (running || !pack_data)
+		return;
+
+	running = 1;
+	clear_delta_base_cache();
+	if (object_count) {
+		struct packed_git *new_p;
+		struct object_id cur_pack_oid;
+		char *idx_name;
+		int i;
+		struct branch *b;
+		struct tag *t;
+
+		close_pack_windows(pack_data);
+		finalize_hashfile(pack_file, cur_pack_oid.hash, FSYNC_COMPONENT_PACK, 0);
+		fixup_pack_header_footer(pack_data->pack_fd, pack_data->hash,
+					 pack_data->pack_name, object_count,
+					 cur_pack_oid.hash, pack_size);
+
+		if (object_count <= unpack_limit) {
+			if (!loosen_small_pack(pack_data)) {
+				invalidate_pack_id(pack_id);
+				goto discard_pack;
+			}
+		}
+
+		close(pack_data->pack_fd);
+		idx_name = keep_pack(create_index());
+
+		/* Register the packfile with core git's machinery. */
+		new_p = add_packed_git(pack_data->repo, idx_name, strlen(idx_name), 1);
+		if (!new_p)
+			die("core git rejected index %s", idx_name);
+		all_packs[pack_id] = new_p;
+		install_packed_git(the_repository, new_p);
+		free(idx_name);
+
+		/* Print the boundary */
+		if (pack_edges) {
+			fprintf(pack_edges, "%s:", new_p->pack_name);
+			for (i = 0; i < branch_table_sz; i++) {
+				for (b = branch_table[i]; b; b = b->table_next_branch) {
+					if (b->pack_id == pack_id)
+						fprintf(pack_edges, " %s",
+							oid_to_hex(&b->oid));
+				}
+			}
+			for (t = first_tag; t; t = t->next_tag) {
+				if (t->pack_id == pack_id)
+					fprintf(pack_edges, " %s",
+						oid_to_hex(&t->oid));
+			}
+			fputc('\n', pack_edges);
+			fflush(pack_edges);
+		}
+
+		pack_id++;
+	}
+	else {
+discard_pack:
+		close(pack_data->pack_fd);
+		unlink_or_warn(pack_data->pack_name);
+	}
+	FREE_AND_NULL(pack_data);
+	running = 0;
+
+	/* We can't carry a delta across packfiles. */
+	strbuf_release(&last_blob.data);
+	last_blob.offset = 0;
+	last_blob.depth = 0;
+}
+
+static void cycle_packfile(void)
+{
+	end_packfile();
+	start_packfile();
+}
+
+static int store_object(
+	enum object_type type,
+	struct strbuf *dat,
+	struct last_object *last,
+	struct object_id *oidout,
+	uintmax_t mark)
+{
+	void *out, *delta;
+	struct object_entry *e;
+	unsigned char hdr[96];
+	struct object_id oid;
+	unsigned long hdrlen, deltalen;
+	git_hash_ctx c;
+	git_zstream s;
+
+	hdrlen = format_object_header((char *)hdr, sizeof(hdr), type,
+				      dat->len);
+	the_hash_algo->init_fn(&c);
+	the_hash_algo->update_fn(&c, hdr, hdrlen);
+	the_hash_algo->update_fn(&c, dat->buf, dat->len);
+	the_hash_algo->final_oid_fn(&oid, &c);
+	if (oidout)
+		oidcpy(oidout, &oid);
+
+	e = insert_object(&oid);
+	if (mark)
+		insert_mark(&marks, mark, e);
+	if (e->idx.offset) {
+		duplicate_count_by_type[type]++;
+		return 1;
+	} else if (find_oid_pack(&oid, get_all_packs(the_repository))) {
+		e->type = type;
+		e->pack_id = MAX_PACK_ID;
+		e->idx.offset = 1; /* just not zero! */
+		duplicate_count_by_type[type]++;
+		return 1;
+	}
+
+	if (last && last->data.len && last->data.buf && last->depth < max_depth
+		&& dat->len > the_hash_algo->rawsz) {
+
+		delta_count_attempts_by_type[type]++;
+		delta = diff_delta(last->data.buf, last->data.len,
+			dat->buf, dat->len,
+			&deltalen, dat->len - the_hash_algo->rawsz);
+	} else
+		delta = NULL;
+
+	git_deflate_init(&s, pack_compression_level);
+	if (delta) {
+		s.next_in = delta;
+		s.avail_in = deltalen;
+	} else {
+		s.next_in = (void *)dat->buf;
+		s.avail_in = dat->len;
+	}
+	s.avail_out = git_deflate_bound(&s, s.avail_in);
+	s.next_out = out = xmalloc(s.avail_out);
+	while (git_deflate(&s, Z_FINISH) == Z_OK)
+		; /* nothing */
+	git_deflate_end(&s);
+
+	/* Determine if we should auto-checkpoint. */
+	if ((max_packsize
+		&& (pack_size + PACK_SIZE_THRESHOLD + s.total_out) > max_packsize)
+		|| (pack_size + PACK_SIZE_THRESHOLD + s.total_out) < pack_size) {
+
+		/* This new object needs to *not* have the current pack_id. */
+		e->pack_id = pack_id + 1;
+		cycle_packfile();
+
+		/* We cannot carry a delta into the new pack. */
+		if (delta) {
+			FREE_AND_NULL(delta);
+
+			git_deflate_init(&s, pack_compression_level);
+			s.next_in = (void *)dat->buf;
+			s.avail_in = dat->len;
+			s.avail_out = git_deflate_bound(&s, s.avail_in);
+			s.next_out = out = xrealloc(out, s.avail_out);
+			while (git_deflate(&s, Z_FINISH) == Z_OK)
+				; /* nothing */
+			git_deflate_end(&s);
+		}
+	}
+
+	e->type = type;
+	e->pack_id = pack_id;
+	e->idx.offset = pack_size;
+	object_count++;
+	object_count_by_type[type]++;
+
+	crc32_begin(pack_file);
+
+	if (delta) {
+		off_t ofs = e->idx.offset - last->offset;
+		unsigned pos = sizeof(hdr) - 1;
+
+		delta_count_by_type[type]++;
+		e->depth = last->depth + 1;
+
+		hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr),
+						      OBJ_OFS_DELTA, deltalen);
+		hashwrite(pack_file, hdr, hdrlen);
+		pack_size += hdrlen;
+
+		hdr[pos] = ofs & 127;
+		while (ofs >>= 7)
+			hdr[--pos] = 128 | (--ofs & 127);
+		hashwrite(pack_file, hdr + pos, sizeof(hdr) - pos);
+		pack_size += sizeof(hdr) - pos;
+	} else {
+		e->depth = 0;
+		hdrlen = encode_in_pack_object_header(hdr, sizeof(hdr),
+						      type, dat->len);
+		hashwrite(pack_file, hdr, hdrlen);
+		pack_size += hdrlen;
+	}
+
+	hashwrite(pack_file, out, s.total_out);
+	pack_size += s.total_out;
+
+	e->idx.crc32 = crc32_end(pack_file);
+
+	free(out);
+	free(delta);
+	if (last) {
+		if (last->no_swap) {
+			last->data = *dat;
+		} else {
+			strbuf_swap(&last->data, dat);
+		}
+		last->offset = e->idx.offset;
+		last->depth = e->depth;
+	}
+	return 0;
+}
+
+static void truncate_pack(struct hashfile_checkpoint *checkpoint)
+{
+	if (hashfile_truncate(pack_file, checkpoint))
+		die_errno("cannot truncate pack to skip duplicate");
+	pack_size = checkpoint->offset;
+}
+
+static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
+{
+	size_t in_sz = 64 * 1024, out_sz = 64 * 1024;
+	unsigned char *in_buf = xmalloc(in_sz);
+	unsigned char *out_buf = xmalloc(out_sz);
+	struct object_entry *e;
+	struct object_id oid;
+	unsigned long hdrlen;
+	off_t offset;
+	git_hash_ctx c;
+	git_zstream s;
+	struct hashfile_checkpoint checkpoint;
+	int status = Z_OK;
+
+	/* Determine if we should auto-checkpoint. */
+	if ((max_packsize
+		&& (pack_size + PACK_SIZE_THRESHOLD + len) > max_packsize)
+		|| (pack_size + PACK_SIZE_THRESHOLD + len) < pack_size)
+		cycle_packfile();
+
+	the_hash_algo->unsafe_init_fn(&checkpoint.ctx);
+	hashfile_checkpoint(pack_file, &checkpoint);
+	offset = checkpoint.offset;
+
+	hdrlen = format_object_header((char *)out_buf, out_sz, OBJ_BLOB, len);
+
+	the_hash_algo->init_fn(&c);
+	the_hash_algo->update_fn(&c, out_buf, hdrlen);
+
+	crc32_begin(pack_file);
+
+	git_deflate_init(&s, pack_compression_level);
+
+	hdrlen = encode_in_pack_object_header(out_buf, out_sz, OBJ_BLOB, len);
+
+	s.next_out = out_buf + hdrlen;
+	s.avail_out = out_sz - hdrlen;
+
+	while (status != Z_STREAM_END) {
+		if (0 < len && !s.avail_in) {
+			size_t cnt = in_sz < len ? in_sz : (size_t)len;
+			size_t n = fread(in_buf, 1, cnt, stdin);
+			if (!n && feof(stdin))
+				die("EOF in data (%" PRIuMAX " bytes remaining)", len);
+
+			the_hash_algo->update_fn(&c, in_buf, n);
+			s.next_in = in_buf;
+			s.avail_in = n;
+			len -= n;
+		}
+
+		status = git_deflate(&s, len ? 0 : Z_FINISH);
+
+		if (!s.avail_out || status == Z_STREAM_END) {
+			size_t n = s.next_out - out_buf;
+			hashwrite(pack_file, out_buf, n);
+			pack_size += n;
+			s.next_out = out_buf;
+			s.avail_out = out_sz;
+		}
+
+		switch (status) {
+		case Z_OK:
+		case Z_BUF_ERROR:
+		case Z_STREAM_END:
+			continue;
+		default:
+			die("unexpected deflate failure: %d", status);
+		}
+	}
+	git_deflate_end(&s);
+	the_hash_algo->final_oid_fn(&oid, &c);
+
+	if (oidout)
+		oidcpy(oidout, &oid);
+
+	e = insert_object(&oid);
+
+	if (mark)
+		insert_mark(&marks, mark, e);
+
+	if (e->idx.offset) {
+		duplicate_count_by_type[OBJ_BLOB]++;
+		truncate_pack(&checkpoint);
+
+	} else if (find_oid_pack(&oid, get_all_packs(the_repository))) {
+		e->type = OBJ_BLOB;
+		e->pack_id = MAX_PACK_ID;
+		e->idx.offset = 1; /* just not zero! */
+		duplicate_count_by_type[OBJ_BLOB]++;
+		truncate_pack(&checkpoint);
+
+	} else {
+		e->depth = 0;
+		e->type = OBJ_BLOB;
+		e->pack_id = pack_id;
+		e->idx.offset = offset;
+		e->idx.crc32 = crc32_end(pack_file);
+		object_count++;
+		object_count_by_type[OBJ_BLOB]++;
+	}
+
+	free(in_buf);
+	free(out_buf);
+}
+
+/* All calls must be guarded by find_object() or find_mark() to
+ * ensure the 'struct object_entry' passed was written by this
+ * process instance.  We unpack the entry by the offset, avoiding
+ * the need for the corresponding .idx file.  This unpacking rule
+ * works because we only use OBJ_REF_DELTA within the packfiles
+ * created by fast-import.
+ *
+ * oe must not be NULL.  Such an oe usually comes from giving
+ * an unknown SHA-1 to find_object() or an undefined mark to
+ * find_mark().  Callers must test for this condition and use
+ * the standard read_sha1_file() when it happens.
+ *
+ * oe->pack_id must not be MAX_PACK_ID.  Such an oe is usually from
+ * find_mark(), where the mark was reloaded from an existing marks
+ * file and is referencing an object that this fast-import process
+ * instance did not write out to a packfile.  Callers must test for
+ * this condition and use read_sha1_file() instead.
+ */
+static void *gfi_unpack_entry(
+	struct object_entry *oe,
+	unsigned long *sizep)
+{
+	enum object_type type;
+	struct packed_git *p = all_packs[oe->pack_id];
+	if (p == pack_data && p->pack_size < (pack_size + the_hash_algo->rawsz)) {
+		/* The object is stored in the packfile we are writing to
+		 * and we have modified it since the last time we scanned
+		 * back to read a previously written object.  If an old
+		 * window covered [p->pack_size, p->pack_size + rawsz) its
+		 * data is stale and is not valid.  Closing all windows
+		 * and updating the packfile length ensures we can read
+		 * the newly written data.
+		 */
+		close_pack_windows(p);
+		hashflush(pack_file);
+
+		/* We have to offer rawsz bytes additional on the end of
+		 * the packfile as the core unpacker code assumes the
+		 * footer is present at the file end and must promise
+		 * at least rawsz bytes within any window it maps.  But
+		 * we don't actually create the footer here.
+		 */
+		p->pack_size = pack_size + the_hash_algo->rawsz;
+	}
+	return unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);
+}
+
+static void load_tree(struct tree_entry *root)
+{
+	struct object_id *oid = &root->versions[1].oid;
+	struct object_entry *myoe;
+	struct tree_content *t;
+	unsigned long size;
+	char *buf;
+	const char *c;
+
+	root->tree = t = new_tree_content(8);
+	if (is_null_oid(oid))
+		return;
+
+	myoe = find_object(oid);
+	if (myoe && myoe->pack_id != MAX_PACK_ID) {
+		if (myoe->type != OBJ_TREE)
+			die("Not a tree: %s", oid_to_hex(oid));
+		t->delta_depth = myoe->depth;
+		buf = gfi_unpack_entry(myoe, &size);
+		if (!buf)
+			die("Can't load tree %s", oid_to_hex(oid));
+	} else {
+		enum object_type type;
+		buf = repo_read_object_file(the_repository, oid, &type, &size);
+		if (!buf || type != OBJ_TREE)
+			die("Can't load tree %s", oid_to_hex(oid));
+	}
+
+	c = buf;
+	while (c != (buf + size)) {
+		struct tree_entry *e = new_tree_entry();
+
+		if (t->entry_count == t->entry_capacity)
+			root->tree = t = grow_tree_content(t, t->entry_count);
+		t->entries[t->entry_count++] = e;
+
+		e->tree = NULL;
+		c = parse_mode(c, &e->versions[1].mode);
+		if (!c)
+			die("Corrupt mode in %s", oid_to_hex(oid));
+		e->versions[0].mode = e->versions[1].mode;
+		e->name = to_atom(c, strlen(c));
+		c += e->name->str_len + 1;
+		oidread(&e->versions[0].oid, (unsigned char *)c,
+			the_repository->hash_algo);
+		oidread(&e->versions[1].oid, (unsigned char *)c,
+			the_repository->hash_algo);
+		c += the_hash_algo->rawsz;
+	}
+	free(buf);
+}
+
+static int tecmp0 (const void *_a, const void *_b)
+{
+	struct tree_entry *a = *((struct tree_entry**)_a);
+	struct tree_entry *b = *((struct tree_entry**)_b);
+	return base_name_compare(
+		a->name->str_dat, a->name->str_len, a->versions[0].mode,
+		b->name->str_dat, b->name->str_len, b->versions[0].mode);
+}
+
+static int tecmp1 (const void *_a, const void *_b)
+{
+	struct tree_entry *a = *((struct tree_entry**)_a);
+	struct tree_entry *b = *((struct tree_entry**)_b);
+	return base_name_compare(
+		a->name->str_dat, a->name->str_len, a->versions[1].mode,
+		b->name->str_dat, b->name->str_len, b->versions[1].mode);
+}
+
+static void mktree(struct tree_content *t, int v, struct strbuf *b)
+{
+	size_t maxlen = 0;
+	unsigned int i;
+
+	if (!v)
+		QSORT(t->entries, t->entry_count, tecmp0);
+	else
+		QSORT(t->entries, t->entry_count, tecmp1);
+
+	for (i = 0; i < t->entry_count; i++) {
+		if (t->entries[i]->versions[v].mode)
+			maxlen += t->entries[i]->name->str_len + 34;
+	}
+
+	strbuf_reset(b);
+	strbuf_grow(b, maxlen);
+	for (i = 0; i < t->entry_count; i++) {
+		struct tree_entry *e = t->entries[i];
+		if (!e->versions[v].mode)
+			continue;
+		strbuf_addf(b, "%o %s%c",
+			(unsigned int)(e->versions[v].mode & ~NO_DELTA),
+			e->name->str_dat, '\0');
+		strbuf_add(b, e->versions[v].oid.hash, the_hash_algo->rawsz);
+	}
+}
+
+static void store_tree(struct tree_entry *root)
+{
+	struct tree_content *t;
+	unsigned int i, j, del;
+	struct last_object lo = { STRBUF_INIT, 0, 0, /* no_swap */ 1 };
+	struct object_entry *le = NULL;
+
+	if (!is_null_oid(&root->versions[1].oid))
+		return;
+
+	if (!root->tree)
+		load_tree(root);
+	t = root->tree;
+
+	for (i = 0; i < t->entry_count; i++) {
+		if (t->entries[i]->tree)
+			store_tree(t->entries[i]);
+	}
+
+	if (!(root->versions[0].mode & NO_DELTA))
+		le = find_object(&root->versions[0].oid);
+	if (S_ISDIR(root->versions[0].mode) && le && le->pack_id == pack_id) {
+		mktree(t, 0, &old_tree);
+		lo.data = old_tree;
+		lo.offset = le->idx.offset;
+		lo.depth = t->delta_depth;
+	}
+
+	mktree(t, 1, &new_tree);
+	store_object(OBJ_TREE, &new_tree, &lo, &root->versions[1].oid, 0);
+
+	t->delta_depth = lo.depth;
+	for (i = 0, j = 0, del = 0; i < t->entry_count; i++) {
+		struct tree_entry *e = t->entries[i];
+		if (e->versions[1].mode) {
+			e->versions[0].mode = e->versions[1].mode;
+			oidcpy(&e->versions[0].oid, &e->versions[1].oid);
+			t->entries[j++] = e;
+		} else {
+			release_tree_entry(e);
+			del++;
+		}
+	}
+	t->entry_count -= del;
+}
+
+static void tree_content_replace(
+	struct tree_entry *root,
+	const struct object_id *oid,
+	const uint16_t mode,
+	struct tree_content *newtree)
+{
+	if (!S_ISDIR(mode))
+		die("Root cannot be a non-directory");
+	oidclr(&root->versions[0].oid, the_repository->hash_algo);
+	oidcpy(&root->versions[1].oid, oid);
+	if (root->tree)
+		release_tree_content_recursive(root->tree);
+	root->tree = newtree;
+}
+
+static int tree_content_set(
+	struct tree_entry *root,
+	const char *p,
+	const struct object_id *oid,
+	const uint16_t mode,
+	struct tree_content *subtree)
+{
+	struct tree_content *t;
+	const char *slash1;
+	unsigned int i, n;
+	struct tree_entry *e;
+
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
+	if (!n)
+		die("Empty path component found in input");
+	if (!*slash1 && !S_ISDIR(mode) && subtree)
+		die("Non-directories cannot have subtrees");
+
+	if (!root->tree)
+		load_tree(root);
+	t = root->tree;
+	for (i = 0; i < t->entry_count; i++) {
+		e = t->entries[i];
+		if (e->name->str_len == n && !fspathncmp(p, e->name->str_dat, n)) {
+			if (!*slash1) {
+				if (!S_ISDIR(mode)
+						&& e->versions[1].mode == mode
+						&& oideq(&e->versions[1].oid, oid))
+					return 0;
+				e->versions[1].mode = mode;
+				oidcpy(&e->versions[1].oid, oid);
+				if (e->tree)
+					release_tree_content_recursive(e->tree);
+				e->tree = subtree;
+
+				/*
+				 * We need to leave e->versions[0].sha1 alone
+				 * to avoid modifying the preimage tree used
+				 * when writing out the parent directory.
+				 * But after replacing the subdir with a
+				 * completely different one, it's not a good
+				 * delta base any more, and besides, we've
+				 * thrown away the tree entries needed to
+				 * make a delta against it.
+				 *
+				 * So let's just explicitly disable deltas
+				 * for the subtree.
+				 */
+				if (S_ISDIR(e->versions[0].mode))
+					e->versions[0].mode |= NO_DELTA;
+
+				oidclr(&root->versions[1].oid, the_repository->hash_algo);
+				return 1;
+			}
+			if (!S_ISDIR(e->versions[1].mode)) {
+				e->tree = new_tree_content(8);
+				e->versions[1].mode = S_IFDIR;
+			}
+			if (!e->tree)
+				load_tree(e);
+			if (tree_content_set(e, slash1 + 1, oid, mode, subtree)) {
+				oidclr(&root->versions[1].oid, the_repository->hash_algo);
+				return 1;
+			}
+			return 0;
+		}
+	}
+
+	if (t->entry_count == t->entry_capacity)
+		root->tree = t = grow_tree_content(t, t->entry_count);
+	e = new_tree_entry();
+	e->name = to_atom(p, n);
+	e->versions[0].mode = 0;
+	oidclr(&e->versions[0].oid, the_repository->hash_algo);
+	t->entries[t->entry_count++] = e;
+	if (*slash1) {
+		e->tree = new_tree_content(8);
+		e->versions[1].mode = S_IFDIR;
+		tree_content_set(e, slash1 + 1, oid, mode, subtree);
+	} else {
+		e->tree = subtree;
+		e->versions[1].mode = mode;
+		oidcpy(&e->versions[1].oid, oid);
+	}
+	oidclr(&root->versions[1].oid, the_repository->hash_algo);
+	return 1;
+}
+
+static int tree_content_remove(
+	struct tree_entry *root,
+	const char *p,
+	struct tree_entry *backup_leaf,
+	int allow_root)
+{
+	struct tree_content *t;
+	const char *slash1;
+	unsigned int i, n;
+	struct tree_entry *e;
+
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
+
+	if (!root->tree)
+		load_tree(root);
+
+	if (!*p && allow_root) {
+		e = root;
+		goto del_entry;
+	}
+
+	t = root->tree;
+	for (i = 0; i < t->entry_count; i++) {
+		e = t->entries[i];
+		if (e->name->str_len == n && !fspathncmp(p, e->name->str_dat, n)) {
+			if (*slash1 && !S_ISDIR(e->versions[1].mode))
+				/*
+				 * If p names a file in some subdirectory, and a
+				 * file or symlink matching the name of the
+				 * parent directory of p exists, then p cannot
+				 * exist and need not be deleted.
+				 */
+				return 1;
+			if (!*slash1 || !S_ISDIR(e->versions[1].mode))
+				goto del_entry;
+			if (!e->tree)
+				load_tree(e);
+			if (tree_content_remove(e, slash1 + 1, backup_leaf, 0)) {
+				for (n = 0; n < e->tree->entry_count; n++) {
+					if (e->tree->entries[n]->versions[1].mode) {
+						oidclr(&root->versions[1].oid,
+						       the_repository->hash_algo);
+						return 1;
+					}
+				}
+				backup_leaf = NULL;
+				goto del_entry;
+			}
+			return 0;
+		}
+	}
+	return 0;
+
+del_entry:
+	if (backup_leaf)
+		memcpy(backup_leaf, e, sizeof(*backup_leaf));
+	else if (e->tree)
+		release_tree_content_recursive(e->tree);
+	e->tree = NULL;
+	e->versions[1].mode = 0;
+	oidclr(&e->versions[1].oid, the_repository->hash_algo);
+	oidclr(&root->versions[1].oid, the_repository->hash_algo);
+	return 1;
+}
+
+static int tree_content_get(
+	struct tree_entry *root,
+	const char *p,
+	struct tree_entry *leaf,
+	int allow_root)
+{
+	struct tree_content *t;
+	const char *slash1;
+	unsigned int i, n;
+	struct tree_entry *e;
+
+	slash1 = strchrnul(p, '/');
+	n = slash1 - p;
+	if (!n && !allow_root)
+		die("Empty path component found in input");
+
+	if (!root->tree)
+		load_tree(root);
+
+	if (!n) {
+		e = root;
+		goto found_entry;
+	}
+
+	t = root->tree;
+	for (i = 0; i < t->entry_count; i++) {
+		e = t->entries[i];
+		if (e->name->str_len == n && !fspathncmp(p, e->name->str_dat, n)) {
+			if (!*slash1)
+				goto found_entry;
+			if (!S_ISDIR(e->versions[1].mode))
+				return 0;
+			if (!e->tree)
+				load_tree(e);
+			return tree_content_get(e, slash1 + 1, leaf, 0);
+		}
+	}
+	return 0;
+
+found_entry:
+	memcpy(leaf, e, sizeof(*leaf));
+	if (e->tree && is_null_oid(&e->versions[1].oid))
+		leaf->tree = dup_tree_content(e->tree);
+	else
+		leaf->tree = NULL;
+	return 1;
+}
+
+static int update_branch(struct branch *b)
+{
+	static const char *msg = "fast-import";
+	struct ref_transaction *transaction;
+	struct object_id old_oid;
+	struct strbuf err = STRBUF_INIT;
+	static const char *replace_prefix = "refs/replace/";
+
+	if (starts_with(b->name, replace_prefix) &&
+	    !strcmp(b->name + strlen(replace_prefix),
+		    oid_to_hex(&b->oid))) {
+		if (!quiet)
+			warning("Dropping %s since it would point to "
+				"itself (i.e. to %s)",
+				b->name, oid_to_hex(&b->oid));
+		refs_delete_ref(get_main_ref_store(the_repository),
+				NULL, b->name, NULL, 0);
+		return 0;
+	}
+	if (is_null_oid(&b->oid)) {
+		if (b->delete)
+			refs_delete_ref(get_main_ref_store(the_repository),
+					NULL, b->name, NULL, 0);
+		return 0;
+	}
+	if (refs_read_ref(get_main_ref_store(the_repository), b->name, &old_oid))
+		oidclr(&old_oid, the_repository->hash_algo);
+	if (!force_update && !is_null_oid(&old_oid)) {
+		struct commit *old_cmit, *new_cmit;
+		int ret;
+
+		old_cmit = lookup_commit_reference_gently(the_repository,
+							  &old_oid, 0);
+		new_cmit = lookup_commit_reference_gently(the_repository,
+							  &b->oid, 0);
+		if (!old_cmit || !new_cmit)
+			return error("Branch %s is missing commits.", b->name);
+
+		ret = repo_in_merge_bases(the_repository, old_cmit, new_cmit);
+		if (ret < 0)
+			exit(128);
+		if (!ret) {
+			warning("Not updating %s"
+				" (new tip %s does not contain %s)",
+				b->name, oid_to_hex(&b->oid),
+				oid_to_hex(&old_oid));
+			return -1;
+		}
+	}
+	transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+						  0, &err);
+	if (!transaction ||
+	    ref_transaction_update(transaction, b->name, &b->oid, &old_oid,
+				   NULL, NULL, 0, msg, &err) ||
+	    ref_transaction_commit(transaction, &err)) {
+		ref_transaction_free(transaction);
+		error("%s", err.buf);
+		strbuf_release(&err);
+		return -1;
+	}
+	ref_transaction_free(transaction);
+	strbuf_release(&err);
+	return 0;
+}
+
+static void dump_branches(void)
+{
+	unsigned int i;
+	struct branch *b;
+
+	for (i = 0; i < branch_table_sz; i++) {
+		for (b = branch_table[i]; b; b = b->table_next_branch)
+			failure |= update_branch(b);
+	}
+}
+
+static void dump_tags(void)
+{
+	static const char *msg = "fast-import";
+	struct tag *t;
+	struct strbuf ref_name = STRBUF_INIT;
+	struct strbuf err = STRBUF_INIT;
+	struct ref_transaction *transaction;
+
+	transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+						  0, &err);
+	if (!transaction) {
+		failure |= error("%s", err.buf);
+		goto cleanup;
+	}
+	for (t = first_tag; t; t = t->next_tag) {
+		strbuf_reset(&ref_name);
+		strbuf_addf(&ref_name, "refs/tags/%s", t->name);
+
+		if (ref_transaction_update(transaction, ref_name.buf,
+					   &t->oid, NULL, NULL, NULL,
+					   0, msg, &err)) {
+			failure |= error("%s", err.buf);
+			goto cleanup;
+		}
+	}
+	if (ref_transaction_commit(transaction, &err))
+		failure |= error("%s", err.buf);
+
+ cleanup:
+	ref_transaction_free(transaction);
+	strbuf_release(&ref_name);
+	strbuf_release(&err);
+}
+
+static void dump_marks(void)
+{
+	struct lock_file mark_lock = LOCK_INIT;
+	FILE *f;
+
+	if (!export_marks_file || (import_marks_file && !import_marks_file_done))
+		return;
+
+	if (safe_create_leading_directories_const(export_marks_file)) {
+		failure |= error_errno("unable to create leading directories of %s",
+				       export_marks_file);
+		return;
+	}
+
+	if (hold_lock_file_for_update(&mark_lock, export_marks_file, 0) < 0) {
+		failure |= error_errno("Unable to write marks file %s",
+				       export_marks_file);
+		return;
+	}
+
+	f = fdopen_lock_file(&mark_lock, "w");
+	if (!f) {
+		int saved_errno = errno;
+		rollback_lock_file(&mark_lock);
+		failure |= error("Unable to write marks file %s: %s",
+			export_marks_file, strerror(saved_errno));
+		return;
+	}
+
+	for_each_mark(marks, 0, dump_marks_fn, f);
+	if (commit_lock_file(&mark_lock)) {
+		failure |= error_errno("Unable to write file %s",
+				       export_marks_file);
+		return;
+	}
+}
+
+static void insert_object_entry(struct mark_set **s, struct object_id *oid, uintmax_t mark)
+{
+	struct object_entry *e;
+	e = find_object(oid);
+	if (!e) {
+		enum object_type type = oid_object_info(the_repository,
+							oid, NULL);
+		if (type < 0)
+			die("object not found: %s", oid_to_hex(oid));
+		e = insert_object(oid);
+		e->type = type;
+		e->pack_id = MAX_PACK_ID;
+		e->idx.offset = 1; /* just not zero! */
+	}
+	insert_mark(s, mark, e);
+}
+
+static void insert_oid_entry(struct mark_set **s, struct object_id *oid, uintmax_t mark)
+{
+	insert_mark(s, mark, xmemdupz(oid, sizeof(*oid)));
+}
+
+static void read_mark_file(struct mark_set **s, FILE *f, mark_set_inserter_t inserter)
+{
+	char line[512];
+	while (fgets(line, sizeof(line), f)) {
+		uintmax_t mark;
+		char *end;
+		struct object_id oid;
+
+		/* Ensure SHA-1 objects are padded with zeros. */
+		memset(oid.hash, 0, sizeof(oid.hash));
+
+		end = strchr(line, '\n');
+		if (line[0] != ':' || !end)
+			die("corrupt mark line: %s", line);
+		*end = 0;
+		mark = strtoumax(line + 1, &end, 10);
+		if (!mark || end == line + 1
+			|| *end != ' '
+			|| get_oid_hex_any(end + 1, &oid) == GIT_HASH_UNKNOWN)
+			die("corrupt mark line: %s", line);
+		inserter(s, &oid, mark);
+	}
+}
+
+static void read_marks(void)
+{
+	FILE *f = fopen(import_marks_file, "r");
+	if (f)
+		;
+	else if (import_marks_file_ignore_missing && errno == ENOENT)
+		goto done; /* Marks file does not exist */
+	else
+		die_errno("cannot read '%s'", import_marks_file);
+	read_mark_file(&marks, f, insert_object_entry);
+	fclose(f);
+done:
+	import_marks_file_done = 1;
+}
+
+
+static int read_next_command(void)
+{
+	static int stdin_eof = 0;
+
+	if (stdin_eof) {
+		unread_command_buf = 0;
+		return EOF;
+	}
+
+	for (;;) {
+		if (unread_command_buf) {
+			unread_command_buf = 0;
+		} else {
+			struct recent_command *rc;
+
+			stdin_eof = strbuf_getline_lf(&command_buf, stdin);
+			if (stdin_eof)
+				return EOF;
+
+			if (!seen_data_command
+				&& !starts_with(command_buf.buf, "feature ")
+				&& !starts_with(command_buf.buf, "option ")) {
+				parse_argv();
+			}
+
+			rc = rc_free;
+			if (rc)
+				rc_free = rc->next;
+			else {
+				rc = cmd_hist.next;
+				cmd_hist.next = rc->next;
+				cmd_hist.next->prev = &cmd_hist;
+				free(rc->buf);
+			}
+
+			rc->buf = xstrdup(command_buf.buf);
+			rc->prev = cmd_tail;
+			rc->next = cmd_hist.prev;
+			rc->prev->next = rc;
+			cmd_tail = rc;
+		}
+		if (command_buf.buf[0] == '#')
+			continue;
+		return 0;
+	}
+}
+
+static void skip_optional_lf(void)
+{
+	int term_char = fgetc(stdin);
+	if (term_char != '\n' && term_char != EOF)
+		ungetc(term_char, stdin);
+}
+
+static void parse_mark(void)
+{
+	const char *v;
+	if (skip_prefix(command_buf.buf, "mark :", &v)) {
+		next_mark = strtoumax(v, NULL, 10);
+		read_next_command();
+	}
+	else
+		next_mark = 0;
+}
+
+static void parse_original_identifier(void)
+{
+	const char *v;
+	if (skip_prefix(command_buf.buf, "original-oid ", &v))
+		read_next_command();
+}
+
+static int parse_data(struct strbuf *sb, uintmax_t limit, uintmax_t *len_res)
+{
+	const char *data;
+	strbuf_reset(sb);
+
+	if (!skip_prefix(command_buf.buf, "data ", &data))
+		die("Expected 'data n' command, found: %s", command_buf.buf);
+
+	if (skip_prefix(data, "<<", &data)) {
+		char *term = xstrdup(data);
+		size_t term_len = command_buf.len - (data - command_buf.buf);
+
+		for (;;) {
+			if (strbuf_getline_lf(&command_buf, stdin) == EOF)
+				die("EOF in data (terminator '%s' not found)", term);
+			if (term_len == command_buf.len
+				&& !strcmp(term, command_buf.buf))
+				break;
+			strbuf_addbuf(sb, &command_buf);
+			strbuf_addch(sb, '\n');
+		}
+		free(term);
+	}
+	else {
+		uintmax_t len = strtoumax(data, NULL, 10);
+		size_t n = 0, length = (size_t)len;
+
+		if (limit && limit < len) {
+			*len_res = len;
+			return 0;
+		}
+		if (length < len)
+			die("data is too large to use in this context");
+
+		while (n < length) {
+			size_t s = strbuf_fread(sb, length - n, stdin);
+			if (!s && feof(stdin))
+				die("EOF in data (%lu bytes remaining)",
+					(unsigned long)(length - n));
+			n += s;
+		}
+	}
+
+	skip_optional_lf();
+	return 1;
+}
+
+static int validate_raw_date(const char *src, struct strbuf *result, int strict)
+{
+	const char *orig_src = src;
+	char *endp;
+	unsigned long num;
+
+	errno = 0;
+
+	num = strtoul(src, &endp, 10);
+	/*
+	 * NEEDSWORK: perhaps check for reasonable values? For example, we
+	 *            could error on values representing times more than a
+	 *            day in the future.
+	 */
+	if (errno || endp == src || *endp != ' ')
+		return -1;
+
+	src = endp + 1;
+	if (*src != '-' && *src != '+')
+		return -1;
+
+	num = strtoul(src + 1, &endp, 10);
+	/*
+	 * NEEDSWORK: check for brokenness other than num > 1400, such as
+	 *            (num % 100) >= 60, or ((num % 100) % 15) != 0 ?
+	 */
+	if (errno || endp == src + 1 || *endp || /* did not parse */
+	    (strict && (1400 < num))             /* parsed a broken timezone */
+	   )
+		return -1;
+
+	strbuf_addstr(result, orig_src);
+	return 0;
+}
+
+static char *parse_ident(const char *buf)
+{
+	const char *ltgt;
+	size_t name_len;
+	struct strbuf ident = STRBUF_INIT;
+
+	/* ensure there is a space delimiter even if there is no name */
+	if (*buf == '<')
+		--buf;
+
+	ltgt = buf + strcspn(buf, "<>");
+	if (*ltgt != '<')
+		die("Missing < in ident string: %s", buf);
+	if (ltgt != buf && ltgt[-1] != ' ')
+		die("Missing space before < in ident string: %s", buf);
+	ltgt = ltgt + 1 + strcspn(ltgt + 1, "<>");
+	if (*ltgt != '>')
+		die("Missing > in ident string: %s", buf);
+	ltgt++;
+	if (*ltgt != ' ')
+		die("Missing space after > in ident string: %s", buf);
+	ltgt++;
+	name_len = ltgt - buf;
+	strbuf_add(&ident, buf, name_len);
+
+	switch (whenspec) {
+	case WHENSPEC_RAW:
+		if (validate_raw_date(ltgt, &ident, 1) < 0)
+			die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
+		break;
+	case WHENSPEC_RAW_PERMISSIVE:
+		if (validate_raw_date(ltgt, &ident, 0) < 0)
+			die("Invalid raw date \"%s\" in ident: %s", ltgt, buf);
+		break;
+	case WHENSPEC_RFC2822:
+		if (parse_date(ltgt, &ident) < 0)
+			die("Invalid rfc2822 date \"%s\" in ident: %s", ltgt, buf);
+		break;
+	case WHENSPEC_NOW:
+		if (strcmp("now", ltgt))
+			die("Date in ident must be 'now': %s", buf);
+		datestamp(&ident);
+		break;
+	}
+
+	return strbuf_detach(&ident, NULL);
+}
+
+static void parse_and_store_blob(
+	struct last_object *last,
+	struct object_id *oidout,
+	uintmax_t mark)
+{
+	static struct strbuf buf = STRBUF_INIT;
+	uintmax_t len;
+
+	if (parse_data(&buf, big_file_threshold, &len))
+		store_object(OBJ_BLOB, &buf, last, oidout, mark);
+	else {
+		if (last) {
+			strbuf_release(&last->data);
+			last->offset = 0;
+			last->depth = 0;
+		}
+		stream_blob(len, oidout, mark);
+		skip_optional_lf();
+	}
+}
+
+static void parse_new_blob(void)
+{
+	read_next_command();
+	parse_mark();
+	parse_original_identifier();
+	parse_and_store_blob(&last_blob, NULL, next_mark);
+}
+
+static void unload_one_branch(void)
+{
+	while (cur_active_branches
+		&& cur_active_branches >= max_active_branches) {
+		uintmax_t min_commit = ULONG_MAX;
+		struct branch *e, *l = NULL, *p = NULL;
+
+		for (e = active_branches; e; e = e->active_next_branch) {
+			if (e->last_commit < min_commit) {
+				p = l;
+				min_commit = e->last_commit;
+			}
+			l = e;
+		}
+
+		if (p) {
+			e = p->active_next_branch;
+			p->active_next_branch = e->active_next_branch;
+		} else {
+			e = active_branches;
+			active_branches = e->active_next_branch;
+		}
+		e->active = 0;
+		e->active_next_branch = NULL;
+		if (e->branch_tree.tree) {
+			release_tree_content_recursive(e->branch_tree.tree);
+			e->branch_tree.tree = NULL;
+		}
+		cur_active_branches--;
+	}
+}
+
+static void load_branch(struct branch *b)
+{
+	load_tree(&b->branch_tree);
+	if (!b->active) {
+		b->active = 1;
+		b->active_next_branch = active_branches;
+		active_branches = b;
+		cur_active_branches++;
+		branch_load_count++;
+	}
+}
+
+static unsigned char convert_num_notes_to_fanout(uintmax_t num_notes)
+{
+	unsigned char fanout = 0;
+	while ((num_notes >>= 8))
+		fanout++;
+	return fanout;
+}
+
+static void construct_path_with_fanout(const char *hex_sha1,
+		unsigned char fanout, char *path)
+{
+	unsigned int i = 0, j = 0;
+	if (fanout >= the_hash_algo->rawsz)
+		die("Too large fanout (%u)", fanout);
+	while (fanout) {
+		path[i++] = hex_sha1[j++];
+		path[i++] = hex_sha1[j++];
+		path[i++] = '/';
+		fanout--;
+	}
+	memcpy(path + i, hex_sha1 + j, the_hash_algo->hexsz - j);
+	path[i + the_hash_algo->hexsz - j] = '\0';
+}
+
+static uintmax_t do_change_note_fanout(
+		struct tree_entry *orig_root, struct tree_entry *root,
+		char *hex_oid, unsigned int hex_oid_len,
+		char *fullpath, unsigned int fullpath_len,
+		unsigned char fanout)
+{
+	struct tree_content *t;
+	struct tree_entry *e, leaf;
+	unsigned int i, tmp_hex_oid_len, tmp_fullpath_len;
+	uintmax_t num_notes = 0;
+	struct object_id oid;
+	/* hex oid + '/' between each pair of hex digits + NUL */
+	char realpath[GIT_MAX_HEXSZ + ((GIT_MAX_HEXSZ / 2) - 1) + 1];
+	const unsigned hexsz = the_hash_algo->hexsz;
+
+	if (!root->tree)
+		load_tree(root);
+	t = root->tree;
+
+	for (i = 0; t && i < t->entry_count; i++) {
+		e = t->entries[i];
+		tmp_hex_oid_len = hex_oid_len + e->name->str_len;
+		tmp_fullpath_len = fullpath_len;
+
+		/*
+		 * We're interested in EITHER existing note entries (entries
+		 * with exactly 40 hex chars in path, not including directory
+		 * separators), OR directory entries that may contain note
+		 * entries (with < 40 hex chars in path).
+		 * Also, each path component in a note entry must be a multiple
+		 * of 2 chars.
+		 */
+		if (!e->versions[1].mode ||
+		    tmp_hex_oid_len > hexsz ||
+		    e->name->str_len % 2)
+			continue;
+
+		/* This _may_ be a note entry, or a subdir containing notes */
+		memcpy(hex_oid + hex_oid_len, e->name->str_dat,
+		       e->name->str_len);
+		if (tmp_fullpath_len)
+			fullpath[tmp_fullpath_len++] = '/';
+		memcpy(fullpath + tmp_fullpath_len, e->name->str_dat,
+		       e->name->str_len);
+		tmp_fullpath_len += e->name->str_len;
+		fullpath[tmp_fullpath_len] = '\0';
+
+		if (tmp_hex_oid_len == hexsz && !get_oid_hex(hex_oid, &oid)) {
+			/* This is a note entry */
+			if (fanout == 0xff) {
+				/* Counting mode, no rename */
+				num_notes++;
+				continue;
+			}
+			construct_path_with_fanout(hex_oid, fanout, realpath);
+			if (!strcmp(fullpath, realpath)) {
+				/* Note entry is in correct location */
+				num_notes++;
+				continue;
+			}
+
+			/* Rename fullpath to realpath */
+			if (!tree_content_remove(orig_root, fullpath, &leaf, 0))
+				die("Failed to remove path %s", fullpath);
+			tree_content_set(orig_root, realpath,
+				&leaf.versions[1].oid,
+				leaf.versions[1].mode,
+				leaf.tree);
+		} else if (S_ISDIR(e->versions[1].mode)) {
+			/* This is a subdir that may contain note entries */
+			num_notes += do_change_note_fanout(orig_root, e,
+				hex_oid, tmp_hex_oid_len,
+				fullpath, tmp_fullpath_len, fanout);
+		}
+
+		/* The above may have reallocated the current tree_content */
+		t = root->tree;
+	}
+	return num_notes;
+}
+
+static uintmax_t change_note_fanout(struct tree_entry *root,
+		unsigned char fanout)
+{
+	/*
+	 * The size of path is due to one slash between every two hex digits,
+	 * plus the terminating NUL.  Note that there is no slash at the end, so
+	 * the number of slashes is one less than half the number of hex
+	 * characters.
+	 */
+	char hex_oid[GIT_MAX_HEXSZ], path[GIT_MAX_HEXSZ + (GIT_MAX_HEXSZ / 2) - 1 + 1];
+	return do_change_note_fanout(root, root, hex_oid, 0, path, 0, fanout);
+}
+
+static int parse_mapped_oid_hex(const char *hex, struct object_id *oid, const char **end)
+{
+	int algo;
+	khiter_t it;
+
+	/* Make SHA-1 object IDs have all-zero padding. */
+	memset(oid->hash, 0, sizeof(oid->hash));
+
+	algo = parse_oid_hex_any(hex, oid, end);
+	if (algo == GIT_HASH_UNKNOWN)
+		return -1;
+
+	it = kh_get_oid_map(sub_oid_map, *oid);
+	/* No such object? */
+	if (it == kh_end(sub_oid_map)) {
+		/* If we're using the same algorithm, pass it through. */
+		if (hash_algos[algo].format_id == the_hash_algo->format_id)
+			return 0;
+		return -1;
+	}
+	oidcpy(oid, kh_value(sub_oid_map, it));
+	return 0;
+}
+
+/*
+ * Given a pointer into a string, parse a mark reference:
+ *
+ *   idnum ::= ':' bigint;
+ *
+ * Update *endptr to point to the first character after the value.
+ *
+ * Complain if the following character is not what is expected,
+ * either a space or end of the string.
+ */
+static uintmax_t parse_mark_ref(const char *p, char **endptr)
+{
+	uintmax_t mark;
+
+	assert(*p == ':');
+	p++;
+	mark = strtoumax(p, endptr, 10);
+	if (*endptr == p)
+		die("No value after ':' in mark: %s", command_buf.buf);
+	return mark;
+}
+
+/*
+ * Parse the mark reference, and complain if this is not the end of
+ * the string.
+ */
+static uintmax_t parse_mark_ref_eol(const char *p)
+{
+	char *end;
+	uintmax_t mark;
+
+	mark = parse_mark_ref(p, &end);
+	if (*end != '\0')
+		die("Garbage after mark: %s", command_buf.buf);
+	return mark;
+}
+
+/*
+ * Parse the mark reference, demanding a trailing space. Update *p to
+ * point to the first character after the space.
+ */
+static uintmax_t parse_mark_ref_space(const char **p)
+{
+	uintmax_t mark;
+	char *end;
+
+	mark = parse_mark_ref(*p, &end);
+	if (*end++ != ' ')
+		die("Missing space after mark: %s", command_buf.buf);
+	*p = end;
+	return mark;
+}
+
+/*
+ * Parse the path string into the strbuf. The path can either be quoted with
+ * escape sequences or unquoted without escape sequences. Unquoted strings may
+ * contain spaces only if `is_last_field` is nonzero; otherwise, it stops
+ * parsing at the first space.
+ */
+static void parse_path(struct strbuf *sb, const char *p, const char **endp,
+		int is_last_field, const char *field)
+{
+	if (*p == '"') {
+		if (unquote_c_style(sb, p, endp))
+			die("Invalid %s: %s", field, command_buf.buf);
+		if (strlen(sb->buf) != sb->len)
+			die("NUL in %s: %s", field, command_buf.buf);
+	} else {
+		/*
+		 * Unless we are parsing the last field of a line,
+		 * SP is the end of this field.
+		 */
+		*endp = is_last_field
+			? p + strlen(p)
+			: strchrnul(p, ' ');
+		strbuf_add(sb, p, *endp - p);
+	}
+}
+
+/*
+ * Parse the path string into the strbuf, and complain if this is not the end of
+ * the string. Unquoted strings may contain spaces.
+ */
+static void parse_path_eol(struct strbuf *sb, const char *p, const char *field)
+{
+	const char *end;
+
+	parse_path(sb, p, &end, 1, field);
+	if (*end)
+		die("Garbage after %s: %s", field, command_buf.buf);
+}
+
+/*
+ * Parse the path string into the strbuf, and ensure it is followed by a space.
+ * Unquoted strings may not contain spaces. Update *endp to point to the first
+ * character after the space.
+ */
+static void parse_path_space(struct strbuf *sb, const char *p,
+		const char **endp, const char *field)
+{
+	parse_path(sb, p, endp, 0, field);
+	if (**endp != ' ')
+		die("Missing space after %s: %s", field, command_buf.buf);
+	(*endp)++;
+}
+
+static void file_change_m(const char *p, struct branch *b)
+{
+	static struct strbuf path = STRBUF_INIT;
+	struct object_entry *oe;
+	struct object_id oid;
+	uint16_t mode, inline_data = 0;
+
+	p = parse_mode(p, &mode);
+	if (!p)
+		die("Corrupt mode: %s", command_buf.buf);
+	switch (mode) {
+	case 0644:
+	case 0755:
+		mode |= S_IFREG;
+	case S_IFREG | 0644:
+	case S_IFREG | 0755:
+	case S_IFLNK:
+	case S_IFDIR:
+	case S_IFGITLINK:
+		/* ok */
+		break;
+	default:
+		die("Corrupt mode: %s", command_buf.buf);
+	}
+
+	if (*p == ':') {
+		oe = find_mark(marks, parse_mark_ref_space(&p));
+		oidcpy(&oid, &oe->idx.oid);
+	} else if (skip_prefix(p, "inline ", &p)) {
+		inline_data = 1;
+		oe = NULL; /* not used with inline_data, but makes gcc happy */
+	} else {
+		if (parse_mapped_oid_hex(p, &oid, &p))
+			die("Invalid dataref: %s", command_buf.buf);
+		oe = find_object(&oid);
+		if (*p++ != ' ')
+			die("Missing space after SHA1: %s", command_buf.buf);
+	}
+
+	strbuf_reset(&path);
+	parse_path_eol(&path, p, "path");
+
+	/* Git does not track empty, non-toplevel directories. */
+	if (S_ISDIR(mode) &&
+	    is_empty_tree_oid(&oid, the_repository->hash_algo) &&
+	    *path.buf) {
+		tree_content_remove(&b->branch_tree, path.buf, NULL, 0);
+		return;
+	}
+
+	if (S_ISGITLINK(mode)) {
+		if (inline_data)
+			die("Git links cannot be specified 'inline': %s",
+				command_buf.buf);
+		else if (oe) {
+			if (oe->type != OBJ_COMMIT)
+				die("Not a commit (actually a %s): %s",
+					type_name(oe->type), command_buf.buf);
+		}
+		/*
+		 * Accept the sha1 without checking; it expected to be in
+		 * another repository.
+		 */
+	} else if (inline_data) {
+		if (S_ISDIR(mode))
+			die("Directories cannot be specified 'inline': %s",
+				command_buf.buf);
+		while (read_next_command() != EOF) {
+			const char *v;
+			if (skip_prefix(command_buf.buf, "cat-blob ", &v))
+				parse_cat_blob(v);
+			else {
+				parse_and_store_blob(&last_blob, &oid, 0);
+				break;
+			}
+		}
+	} else {
+		enum object_type expected = S_ISDIR(mode) ?
+						OBJ_TREE: OBJ_BLOB;
+		enum object_type type = oe ? oe->type :
+					oid_object_info(the_repository, &oid,
+							NULL);
+		if (type < 0)
+			die("%s not found: %s",
+					S_ISDIR(mode) ?  "Tree" : "Blob",
+					command_buf.buf);
+		if (type != expected)
+			die("Not a %s (actually a %s): %s",
+				type_name(expected), type_name(type),
+				command_buf.buf);
+	}
+
+	if (!*path.buf) {
+		tree_content_replace(&b->branch_tree, &oid, mode, NULL);
+		return;
+	}
+
+	if (!verify_path(path.buf, mode))
+		die("invalid path '%s'", path.buf);
+	tree_content_set(&b->branch_tree, path.buf, &oid, mode, NULL);
+}
+
+static void file_change_d(const char *p, struct branch *b)
+{
+	static struct strbuf path = STRBUF_INIT;
+
+	strbuf_reset(&path);
+	parse_path_eol(&path, p, "path");
+	tree_content_remove(&b->branch_tree, path.buf, NULL, 1);
+}
+
+static void file_change_cr(const char *p, struct branch *b, int rename)
+{
+	static struct strbuf source = STRBUF_INIT;
+	static struct strbuf dest = STRBUF_INIT;
+	struct tree_entry leaf;
+
+	strbuf_reset(&source);
+	parse_path_space(&source, p, &p, "source");
+	strbuf_reset(&dest);
+	parse_path_eol(&dest, p, "dest");
+
+	memset(&leaf, 0, sizeof(leaf));
+	if (rename)
+		tree_content_remove(&b->branch_tree, source.buf, &leaf, 1);
+	else
+		tree_content_get(&b->branch_tree, source.buf, &leaf, 1);
+	if (!leaf.versions[1].mode)
+		die("Path %s not in branch", source.buf);
+	if (!*dest.buf) {	/* C "path/to/subdir" "" */
+		tree_content_replace(&b->branch_tree,
+			&leaf.versions[1].oid,
+			leaf.versions[1].mode,
+			leaf.tree);
+		return;
+	}
+	if (!verify_path(dest.buf, leaf.versions[1].mode))
+		die("invalid path '%s'", dest.buf);
+	tree_content_set(&b->branch_tree, dest.buf,
+		&leaf.versions[1].oid,
+		leaf.versions[1].mode,
+		leaf.tree);
+}
+
+static void note_change_n(const char *p, struct branch *b, unsigned char *old_fanout)
+{
+	struct object_entry *oe;
+	struct branch *s;
+	struct object_id oid, commit_oid;
+	char path[GIT_MAX_RAWSZ * 3];
+	uint16_t inline_data = 0;
+	unsigned char new_fanout;
+
+	/*
+	 * When loading a branch, we don't traverse its tree to count the real
+	 * number of notes (too expensive to do this for all non-note refs).
+	 * This means that recently loaded notes refs might incorrectly have
+	 * b->num_notes == 0, and consequently, old_fanout might be wrong.
+	 *
+	 * Fix this by traversing the tree and counting the number of notes
+	 * when b->num_notes == 0. If the notes tree is truly empty, the
+	 * calculation should not take long.
+	 */
+	if (b->num_notes == 0 && *old_fanout == 0) {
+		/* Invoke change_note_fanout() in "counting mode". */
+		b->num_notes = change_note_fanout(&b->branch_tree, 0xff);
+		*old_fanout = convert_num_notes_to_fanout(b->num_notes);
+	}
+
+	/* Now parse the notemodify command. */
+	/* <dataref> or 'inline' */
+	if (*p == ':') {
+		oe = find_mark(marks, parse_mark_ref_space(&p));
+		oidcpy(&oid, &oe->idx.oid);
+	} else if (skip_prefix(p, "inline ", &p)) {
+		inline_data = 1;
+		oe = NULL; /* not used with inline_data, but makes gcc happy */
+	} else {
+		if (parse_mapped_oid_hex(p, &oid, &p))
+			die("Invalid dataref: %s", command_buf.buf);
+		oe = find_object(&oid);
+		if (*p++ != ' ')
+			die("Missing space after SHA1: %s", command_buf.buf);
+	}
+
+	/* <commit-ish> */
+	s = lookup_branch(p);
+	if (s) {
+		if (is_null_oid(&s->oid))
+			die("Can't add a note on empty branch.");
+		oidcpy(&commit_oid, &s->oid);
+	} else if (*p == ':') {
+		uintmax_t commit_mark = parse_mark_ref_eol(p);
+		struct object_entry *commit_oe = find_mark(marks, commit_mark);
+		if (commit_oe->type != OBJ_COMMIT)
+			die("Mark :%" PRIuMAX " not a commit", commit_mark);
+		oidcpy(&commit_oid, &commit_oe->idx.oid);
+	} else if (!repo_get_oid(the_repository, p, &commit_oid)) {
+		unsigned long size;
+		char *buf = read_object_with_reference(the_repository,
+						       &commit_oid,
+						       OBJ_COMMIT, &size,
+						       &commit_oid);
+		if (!buf || size < the_hash_algo->hexsz + 6)
+			die("Not a valid commit: %s", p);
+		free(buf);
+	} else
+		die("Invalid ref name or SHA1 expression: %s", p);
+
+	if (inline_data) {
+		read_next_command();
+		parse_and_store_blob(&last_blob, &oid, 0);
+	} else if (oe) {
+		if (oe->type != OBJ_BLOB)
+			die("Not a blob (actually a %s): %s",
+				type_name(oe->type), command_buf.buf);
+	} else if (!is_null_oid(&oid)) {
+		enum object_type type = oid_object_info(the_repository, &oid,
+							NULL);
+		if (type < 0)
+			die("Blob not found: %s", command_buf.buf);
+		if (type != OBJ_BLOB)
+			die("Not a blob (actually a %s): %s",
+			    type_name(type), command_buf.buf);
+	}
+
+	construct_path_with_fanout(oid_to_hex(&commit_oid), *old_fanout, path);
+	if (tree_content_remove(&b->branch_tree, path, NULL, 0))
+		b->num_notes--;
+
+	if (is_null_oid(&oid))
+		return; /* nothing to insert */
+
+	b->num_notes++;
+	new_fanout = convert_num_notes_to_fanout(b->num_notes);
+	construct_path_with_fanout(oid_to_hex(&commit_oid), new_fanout, path);
+	tree_content_set(&b->branch_tree, path, &oid, S_IFREG | 0644, NULL);
+}
+
+static void file_change_deleteall(struct branch *b)
+{
+	release_tree_content_recursive(b->branch_tree.tree);
+	oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo);
+	oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);
+	load_tree(&b->branch_tree);
+	b->num_notes = 0;
+}
+
+static void parse_from_commit(struct branch *b, char *buf, unsigned long size)
+{
+	if (!buf || size < the_hash_algo->hexsz + 6)
+		die("Not a valid commit: %s", oid_to_hex(&b->oid));
+	if (memcmp("tree ", buf, 5)
+		|| get_oid_hex(buf + 5, &b->branch_tree.versions[1].oid))
+		die("The commit %s is corrupt", oid_to_hex(&b->oid));
+	oidcpy(&b->branch_tree.versions[0].oid,
+	       &b->branch_tree.versions[1].oid);
+}
+
+static void parse_from_existing(struct branch *b)
+{
+	if (is_null_oid(&b->oid)) {
+		oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo);
+		oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);
+	} else {
+		unsigned long size;
+		char *buf;
+
+		buf = read_object_with_reference(the_repository,
+						 &b->oid, OBJ_COMMIT, &size,
+						 &b->oid);
+		parse_from_commit(b, buf, size);
+		free(buf);
+	}
+}
+
+static int parse_objectish(struct branch *b, const char *objectish)
+{
+	struct branch *s;
+	struct object_id oid;
+
+	oidcpy(&oid, &b->branch_tree.versions[1].oid);
+
+	s = lookup_branch(objectish);
+	if (b == s)
+		die("Can't create a branch from itself: %s", b->name);
+	else if (s) {
+		struct object_id *t = &s->branch_tree.versions[1].oid;
+		oidcpy(&b->oid, &s->oid);
+		oidcpy(&b->branch_tree.versions[0].oid, t);
+		oidcpy(&b->branch_tree.versions[1].oid, t);
+	} else if (*objectish == ':') {
+		uintmax_t idnum = parse_mark_ref_eol(objectish);
+		struct object_entry *oe = find_mark(marks, idnum);
+		if (oe->type != OBJ_COMMIT)
+			die("Mark :%" PRIuMAX " not a commit", idnum);
+		if (!oideq(&b->oid, &oe->idx.oid)) {
+			oidcpy(&b->oid, &oe->idx.oid);
+			if (oe->pack_id != MAX_PACK_ID) {
+				unsigned long size;
+				char *buf = gfi_unpack_entry(oe, &size);
+				parse_from_commit(b, buf, size);
+				free(buf);
+			} else
+				parse_from_existing(b);
+		}
+	} else if (!repo_get_oid(the_repository, objectish, &b->oid)) {
+		parse_from_existing(b);
+		if (is_null_oid(&b->oid))
+			b->delete = 1;
+	}
+	else
+		die("Invalid ref name or SHA1 expression: %s", objectish);
+
+	if (b->branch_tree.tree && !oideq(&oid, &b->branch_tree.versions[1].oid)) {
+		release_tree_content_recursive(b->branch_tree.tree);
+		b->branch_tree.tree = NULL;
+	}
+
+	read_next_command();
+	return 1;
+}
+
+static int parse_from(struct branch *b)
+{
+	const char *from;
+
+	if (!skip_prefix(command_buf.buf, "from ", &from))
+		return 0;
+
+	return parse_objectish(b, from);
+}
+
+static int parse_objectish_with_prefix(struct branch *b, const char *prefix)
+{
+	const char *base;
+
+	if (!skip_prefix(command_buf.buf, prefix, &base))
+		return 0;
+
+	return parse_objectish(b, base);
+}
+
+static struct hash_list *parse_merge(unsigned int *count)
+{
+	struct hash_list *list = NULL, **tail = &list, *n;
+	const char *from;
+	struct branch *s;
+
+	*count = 0;
+	while (skip_prefix(command_buf.buf, "merge ", &from)) {
+		n = xmalloc(sizeof(*n));
+		s = lookup_branch(from);
+		if (s)
+			oidcpy(&n->oid, &s->oid);
+		else if (*from == ':') {
+			uintmax_t idnum = parse_mark_ref_eol(from);
+			struct object_entry *oe = find_mark(marks, idnum);
+			if (oe->type != OBJ_COMMIT)
+				die("Mark :%" PRIuMAX " not a commit", idnum);
+			oidcpy(&n->oid, &oe->idx.oid);
+		} else if (!repo_get_oid(the_repository, from, &n->oid)) {
+			unsigned long size;
+			char *buf = read_object_with_reference(the_repository,
+							       &n->oid,
+							       OBJ_COMMIT,
+							       &size, &n->oid);
+			if (!buf || size < the_hash_algo->hexsz + 6)
+				die("Not a valid commit: %s", from);
+			free(buf);
+		} else
+			die("Invalid ref name or SHA1 expression: %s", from);
+
+		n->next = NULL;
+		*tail = n;
+		tail = &n->next;
+
+		(*count)++;
+		read_next_command();
+	}
+	return list;
+}
+
+static void parse_new_commit(const char *arg)
+{
+	static struct strbuf msg = STRBUF_INIT;
+	struct branch *b;
+	char *author = NULL;
+	char *committer = NULL;
+	char *encoding = NULL;
+	struct hash_list *merge_list = NULL;
+	unsigned int merge_count;
+	unsigned char prev_fanout, new_fanout;
+	const char *v;
+
+	b = lookup_branch(arg);
+	if (!b)
+		b = new_branch(arg);
+
+	read_next_command();
+	parse_mark();
+	parse_original_identifier();
+	if (skip_prefix(command_buf.buf, "author ", &v)) {
+		author = parse_ident(v);
+		read_next_command();
+	}
+	if (skip_prefix(command_buf.buf, "committer ", &v)) {
+		committer = parse_ident(v);
+		read_next_command();
+	}
+	if (!committer)
+		die("Expected committer but didn't get one");
+	if (skip_prefix(command_buf.buf, "encoding ", &v)) {
+		encoding = xstrdup(v);
+		read_next_command();
+	}
+	parse_data(&msg, 0, NULL);
+	read_next_command();
+	parse_from(b);
+	merge_list = parse_merge(&merge_count);
+
+	/* ensure the branch is active/loaded */
+	if (!b->branch_tree.tree || !max_active_branches) {
+		unload_one_branch();
+		load_branch(b);
+	}
+
+	prev_fanout = convert_num_notes_to_fanout(b->num_notes);
+
+	/* file_change* */
+	while (command_buf.len > 0) {
+		if (skip_prefix(command_buf.buf, "M ", &v))
+			file_change_m(v, b);
+		else if (skip_prefix(command_buf.buf, "D ", &v))
+			file_change_d(v, b);
+		else if (skip_prefix(command_buf.buf, "R ", &v))
+			file_change_cr(v, b, 1);
+		else if (skip_prefix(command_buf.buf, "C ", &v))
+			file_change_cr(v, b, 0);
+		else if (skip_prefix(command_buf.buf, "N ", &v))
+			note_change_n(v, b, &prev_fanout);
+		else if (!strcmp("deleteall", command_buf.buf))
+			file_change_deleteall(b);
+		else if (skip_prefix(command_buf.buf, "ls ", &v))
+			parse_ls(v, b);
+		else if (skip_prefix(command_buf.buf, "cat-blob ", &v))
+			parse_cat_blob(v);
+		else {
+			unread_command_buf = 1;
+			break;
+		}
+		if (read_next_command() == EOF)
+			break;
+	}
+
+	new_fanout = convert_num_notes_to_fanout(b->num_notes);
+	if (new_fanout != prev_fanout)
+		b->num_notes = change_note_fanout(&b->branch_tree, new_fanout);
+
+	/* build the tree and the commit */
+	store_tree(&b->branch_tree);
+	oidcpy(&b->branch_tree.versions[0].oid,
+	       &b->branch_tree.versions[1].oid);
+
+	strbuf_reset(&new_data);
+	strbuf_addf(&new_data, "tree %s\n",
+		oid_to_hex(&b->branch_tree.versions[1].oid));
+	if (!is_null_oid(&b->oid))
+		strbuf_addf(&new_data, "parent %s\n",
+			    oid_to_hex(&b->oid));
+	while (merge_list) {
+		struct hash_list *next = merge_list->next;
+		strbuf_addf(&new_data, "parent %s\n",
+			    oid_to_hex(&merge_list->oid));
+		free(merge_list);
+		merge_list = next;
+	}
+	strbuf_addf(&new_data,
+		"author %s\n"
+		"committer %s\n",
+		author ? author : committer, committer);
+	if (encoding)
+		strbuf_addf(&new_data,
+			"encoding %s\n",
+			encoding);
+	strbuf_addch(&new_data, '\n');
+	strbuf_addbuf(&new_data, &msg);
+	free(author);
+	free(committer);
+	free(encoding);
+
+	if (!store_object(OBJ_COMMIT, &new_data, NULL, &b->oid, next_mark))
+		b->pack_id = pack_id;
+	b->last_commit = object_count_by_type[OBJ_COMMIT];
+}
+
+static void parse_new_tag(const char *arg)
+{
+	static struct strbuf msg = STRBUF_INIT;
+	const char *from;
+	char *tagger;
+	struct branch *s;
+	struct tag *t;
+	uintmax_t from_mark = 0;
+	struct object_id oid;
+	enum object_type type;
+	const char *v;
+
+	t = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct tag));
+	t->name = mem_pool_strdup(&fi_mem_pool, arg);
+	if (last_tag)
+		last_tag->next_tag = t;
+	else
+		first_tag = t;
+	last_tag = t;
+	read_next_command();
+	parse_mark();
+
+	/* from ... */
+	if (!skip_prefix(command_buf.buf, "from ", &from))
+		die("Expected from command, got %s", command_buf.buf);
+	s = lookup_branch(from);
+	if (s) {
+		if (is_null_oid(&s->oid))
+			die("Can't tag an empty branch.");
+		oidcpy(&oid, &s->oid);
+		type = OBJ_COMMIT;
+	} else if (*from == ':') {
+		struct object_entry *oe;
+		from_mark = parse_mark_ref_eol(from);
+		oe = find_mark(marks, from_mark);
+		type = oe->type;
+		oidcpy(&oid, &oe->idx.oid);
+	} else if (!repo_get_oid(the_repository, from, &oid)) {
+		struct object_entry *oe = find_object(&oid);
+		if (!oe) {
+			type = oid_object_info(the_repository, &oid, NULL);
+			if (type < 0)
+				die("Not a valid object: %s", from);
+		} else
+			type = oe->type;
+	} else
+		die("Invalid ref name or SHA1 expression: %s", from);
+	read_next_command();
+
+	/* original-oid ... */
+	parse_original_identifier();
+
+	/* tagger ... */
+	if (skip_prefix(command_buf.buf, "tagger ", &v)) {
+		tagger = parse_ident(v);
+		read_next_command();
+	} else
+		tagger = NULL;
+
+	/* tag payload/message */
+	parse_data(&msg, 0, NULL);
+
+	/* build the tag object */
+	strbuf_reset(&new_data);
+
+	strbuf_addf(&new_data,
+		    "object %s\n"
+		    "type %s\n"
+		    "tag %s\n",
+		    oid_to_hex(&oid), type_name(type), t->name);
+	if (tagger)
+		strbuf_addf(&new_data,
+			    "tagger %s\n", tagger);
+	strbuf_addch(&new_data, '\n');
+	strbuf_addbuf(&new_data, &msg);
+	free(tagger);
+
+	if (store_object(OBJ_TAG, &new_data, NULL, &t->oid, next_mark))
+		t->pack_id = MAX_PACK_ID;
+	else
+		t->pack_id = pack_id;
+}
+
+static void parse_reset_branch(const char *arg)
+{
+	struct branch *b;
+	const char *tag_name;
+
+	b = lookup_branch(arg);
+	if (b) {
+		oidclr(&b->oid, the_repository->hash_algo);
+		oidclr(&b->branch_tree.versions[0].oid, the_repository->hash_algo);
+		oidclr(&b->branch_tree.versions[1].oid, the_repository->hash_algo);
+		if (b->branch_tree.tree) {
+			release_tree_content_recursive(b->branch_tree.tree);
+			b->branch_tree.tree = NULL;
+		}
+	}
+	else
+		b = new_branch(arg);
+	read_next_command();
+	parse_from(b);
+	if (b->delete && skip_prefix(b->name, "refs/tags/", &tag_name)) {
+		/*
+		 * Elsewhere, we call dump_branches() before dump_tags(),
+		 * and dump_branches() will handle ref deletions first, so
+		 * in order to make sure the deletion actually takes effect,
+		 * we need to remove the tag from our list of tags to update.
+		 *
+		 * NEEDSWORK: replace list of tags with hashmap for faster
+		 * deletion?
+		 */
+		struct tag *t, *prev = NULL;
+		for (t = first_tag; t; t = t->next_tag) {
+			if (!strcmp(t->name, tag_name))
+				break;
+			prev = t;
+		}
+		if (t) {
+			if (prev)
+				prev->next_tag = t->next_tag;
+			else
+				first_tag = t->next_tag;
+			if (!t->next_tag)
+				last_tag = prev;
+			/* There is no mem_pool_free(t) function to call. */
+		}
+	}
+	if (command_buf.len > 0)
+		unread_command_buf = 1;
+}
+
+static void cat_blob_write(const char *buf, unsigned long size)
+{
+	if (write_in_full(cat_blob_fd, buf, size) < 0)
+		die_errno("Write to frontend failed");
+}
+
+static void cat_blob(struct object_entry *oe, struct object_id *oid)
+{
+	struct strbuf line = STRBUF_INIT;
+	unsigned long size;
+	enum object_type type = 0;
+	char *buf;
+
+	if (!oe || oe->pack_id == MAX_PACK_ID) {
+		buf = repo_read_object_file(the_repository, oid, &type, &size);
+	} else {
+		type = oe->type;
+		buf = gfi_unpack_entry(oe, &size);
+	}
+
+	/*
+	 * Output based on batch_one_object() from cat-file.c.
+	 */
+	if (type <= 0) {
+		strbuf_reset(&line);
+		strbuf_addf(&line, "%s missing\n", oid_to_hex(oid));
+		cat_blob_write(line.buf, line.len);
+		strbuf_release(&line);
+		free(buf);
+		return;
+	}
+	if (!buf)
+		die("Can't read object %s", oid_to_hex(oid));
+	if (type != OBJ_BLOB)
+		die("Object %s is a %s but a blob was expected.",
+		    oid_to_hex(oid), type_name(type));
+	strbuf_reset(&line);
+	strbuf_addf(&line, "%s %s %"PRIuMAX"\n", oid_to_hex(oid),
+		    type_name(type), (uintmax_t)size);
+	cat_blob_write(line.buf, line.len);
+	strbuf_release(&line);
+	cat_blob_write(buf, size);
+	cat_blob_write("\n", 1);
+	if (oe && oe->pack_id == pack_id) {
+		last_blob.offset = oe->idx.offset;
+		strbuf_attach(&last_blob.data, buf, size, size);
+		last_blob.depth = oe->depth;
+	} else
+		free(buf);
+}
+
+static void parse_get_mark(const char *p)
+{
+	struct object_entry *oe;
+	char output[GIT_MAX_HEXSZ + 2];
+
+	/* get-mark SP <object> LF */
+	if (*p != ':')
+		die("Not a mark: %s", p);
+
+	oe = find_mark(marks, parse_mark_ref_eol(p));
+	if (!oe)
+		die("Unknown mark: %s", command_buf.buf);
+
+	xsnprintf(output, sizeof(output), "%s\n", oid_to_hex(&oe->idx.oid));
+	cat_blob_write(output, the_hash_algo->hexsz + 1);
+}
+
+static void parse_cat_blob(const char *p)
+{
+	struct object_entry *oe;
+	struct object_id oid;
+
+	/* cat-blob SP <object> LF */
+	if (*p == ':') {
+		oe = find_mark(marks, parse_mark_ref_eol(p));
+		if (!oe)
+			die("Unknown mark: %s", command_buf.buf);
+		oidcpy(&oid, &oe->idx.oid);
+	} else {
+		if (parse_mapped_oid_hex(p, &oid, &p))
+			die("Invalid dataref: %s", command_buf.buf);
+		if (*p)
+			die("Garbage after SHA1: %s", command_buf.buf);
+		oe = find_object(&oid);
+	}
+
+	cat_blob(oe, &oid);
+}
+
+static struct object_entry *dereference(struct object_entry *oe,
+					struct object_id *oid)
+{
+	unsigned long size;
+	char *buf = NULL;
+	const unsigned hexsz = the_hash_algo->hexsz;
+
+	if (!oe) {
+		enum object_type type = oid_object_info(the_repository, oid,
+							NULL);
+		if (type < 0)
+			die("object not found: %s", oid_to_hex(oid));
+		/* cache it! */
+		oe = insert_object(oid);
+		oe->type = type;
+		oe->pack_id = MAX_PACK_ID;
+		oe->idx.offset = 1;
+	}
+	switch (oe->type) {
+	case OBJ_TREE:	/* easy case. */
+		return oe;
+	case OBJ_COMMIT:
+	case OBJ_TAG:
+		break;
+	default:
+		die("Not a tree-ish: %s", command_buf.buf);
+	}
+
+	if (oe->pack_id != MAX_PACK_ID) {	/* in a pack being written */
+		buf = gfi_unpack_entry(oe, &size);
+	} else {
+		enum object_type unused;
+		buf = repo_read_object_file(the_repository, oid, &unused,
+					    &size);
+	}
+	if (!buf)
+		die("Can't load object %s", oid_to_hex(oid));
+
+	/* Peel one layer. */
+	switch (oe->type) {
+	case OBJ_TAG:
+		if (size < hexsz + strlen("object ") ||
+		    get_oid_hex(buf + strlen("object "), oid))
+			die("Invalid SHA1 in tag: %s", command_buf.buf);
+		break;
+	case OBJ_COMMIT:
+		if (size < hexsz + strlen("tree ") ||
+		    get_oid_hex(buf + strlen("tree "), oid))
+			die("Invalid SHA1 in commit: %s", command_buf.buf);
+	}
+
+	free(buf);
+	return find_object(oid);
+}
+
+static void insert_mapped_mark(uintmax_t mark, void *object, void *cbp)
+{
+	struct object_id *fromoid = object;
+	struct object_id *tooid = find_mark(cbp, mark);
+	int ret;
+	khiter_t it;
+
+	it = kh_put_oid_map(sub_oid_map, *fromoid, &ret);
+	/* We've already seen this object. */
+	if (ret == 0)
+		return;
+	kh_value(sub_oid_map, it) = tooid;
+}
+
+static void build_mark_map_one(struct mark_set *from, struct mark_set *to)
+{
+	for_each_mark(from, 0, insert_mapped_mark, to);
+}
+
+static void build_mark_map(struct string_list *from, struct string_list *to)
+{
+	struct string_list_item *fromp, *top;
+
+	sub_oid_map = kh_init_oid_map();
+
+	for_each_string_list_item(fromp, from) {
+		top = string_list_lookup(to, fromp->string);
+		if (!fromp->util) {
+			die(_("Missing from marks for submodule '%s'"), fromp->string);
+		} else if (!top || !top->util) {
+			die(_("Missing to marks for submodule '%s'"), fromp->string);
+		}
+		build_mark_map_one(fromp->util, top->util);
+	}
+}
+
+static struct object_entry *parse_treeish_dataref(const char **p)
+{
+	struct object_id oid;
+	struct object_entry *e;
+
+	if (**p == ':') {	/* <mark> */
+		e = find_mark(marks, parse_mark_ref_space(p));
+		if (!e)
+			die("Unknown mark: %s", command_buf.buf);
+		oidcpy(&oid, &e->idx.oid);
+	} else {	/* <sha1> */
+		if (parse_mapped_oid_hex(*p, &oid, p))
+			die("Invalid dataref: %s", command_buf.buf);
+		e = find_object(&oid);
+		if (*(*p)++ != ' ')
+			die("Missing space after tree-ish: %s", command_buf.buf);
+	}
+
+	while (!e || e->type != OBJ_TREE)
+		e = dereference(e, &oid);
+	return e;
+}
+
+static void print_ls(int mode, const unsigned char *hash, const char *path)
+{
+	static struct strbuf line = STRBUF_INIT;
+
+	/* See show_tree(). */
+	const char *type =
+		S_ISGITLINK(mode) ? commit_type :
+		S_ISDIR(mode) ? tree_type :
+		blob_type;
+
+	if (!mode) {
+		/* missing SP path LF */
+		strbuf_reset(&line);
+		strbuf_addstr(&line, "missing ");
+		quote_c_style(path, &line, NULL, 0);
+		strbuf_addch(&line, '\n');
+	} else {
+		/* mode SP type SP object_name TAB path LF */
+		strbuf_reset(&line);
+		strbuf_addf(&line, "%06o %s %s\t",
+				mode & ~NO_DELTA, type, hash_to_hex(hash));
+		quote_c_style(path, &line, NULL, 0);
+		strbuf_addch(&line, '\n');
+	}
+	cat_blob_write(line.buf, line.len);
+}
+
+static void parse_ls(const char *p, struct branch *b)
+{
+	static struct strbuf path = STRBUF_INIT;
+	struct tree_entry *root = NULL;
+	struct tree_entry leaf = {NULL};
+
+	/* ls SP (<tree-ish> SP)? <path> */
+	if (*p == '"') {
+		if (!b)
+			die("Not in a commit: %s", command_buf.buf);
+		root = &b->branch_tree;
+	} else {
+		struct object_entry *e = parse_treeish_dataref(&p);
+		root = new_tree_entry();
+		oidcpy(&root->versions[1].oid, &e->idx.oid);
+		if (!is_null_oid(&root->versions[1].oid))
+			root->versions[1].mode = S_IFDIR;
+		load_tree(root);
+	}
+	strbuf_reset(&path);
+	parse_path_eol(&path, p, "path");
+	tree_content_get(root, path.buf, &leaf, 1);
+	/*
+	 * A directory in preparation would have a sha1 of zero
+	 * until it is saved.  Save, for simplicity.
+	 */
+	if (S_ISDIR(leaf.versions[1].mode))
+		store_tree(&leaf);
+
+	print_ls(leaf.versions[1].mode, leaf.versions[1].oid.hash, path.buf);
+	if (leaf.tree)
+		release_tree_content_recursive(leaf.tree);
+	if (!b || root != &b->branch_tree)
+		release_tree_entry(root);
+}
+
+static void checkpoint(void)
+{
+	checkpoint_requested = 0;
+	if (object_count) {
+		cycle_packfile();
+	}
+	dump_branches();
+	dump_tags();
+	dump_marks();
+}
+
+static void parse_checkpoint(void)
+{
+	checkpoint_requested = 1;
+	skip_optional_lf();
+}
+
+static void parse_progress(void)
+{
+	fwrite(command_buf.buf, 1, command_buf.len, stdout);
+	fputc('\n', stdout);
+	fflush(stdout);
+	skip_optional_lf();
+}
+
+static void parse_alias(void)
+{
+	struct object_entry *e;
+	struct branch b;
+
+	skip_optional_lf();
+	read_next_command();
+
+	/* mark ... */
+	parse_mark();
+	if (!next_mark)
+		die(_("Expected 'mark' command, got %s"), command_buf.buf);
+
+	/* to ... */
+	memset(&b, 0, sizeof(b));
+	if (!parse_objectish_with_prefix(&b, "to "))
+		die(_("Expected 'to' command, got %s"), command_buf.buf);
+	e = find_object(&b.oid);
+	assert(e);
+	insert_mark(&marks, next_mark, e);
+}
+
+static char* make_fast_import_path(const char *path)
+{
+	if (!relative_marks_paths || is_absolute_path(path))
+		return prefix_filename(global_prefix, path);
+	return git_pathdup("info/fast-import/%s", path);
+}
+
+static void option_import_marks(const char *marks,
+					int from_stream, int ignore_missing)
+{
+	if (import_marks_file) {
+		if (from_stream)
+			die("Only one import-marks command allowed per stream");
+
+		/* read previous mark file */
+		if(!import_marks_file_from_stream)
+			read_marks();
+	}
+
+	free(import_marks_file);
+	import_marks_file = make_fast_import_path(marks);
+	import_marks_file_from_stream = from_stream;
+	import_marks_file_ignore_missing = ignore_missing;
+}
+
+static void option_date_format(const char *fmt)
+{
+	if (!strcmp(fmt, "raw"))
+		whenspec = WHENSPEC_RAW;
+	else if (!strcmp(fmt, "raw-permissive"))
+		whenspec = WHENSPEC_RAW_PERMISSIVE;
+	else if (!strcmp(fmt, "rfc2822"))
+		whenspec = WHENSPEC_RFC2822;
+	else if (!strcmp(fmt, "now"))
+		whenspec = WHENSPEC_NOW;
+	else
+		die("unknown --date-format argument %s", fmt);
+}
+
+static unsigned long ulong_arg(const char *option, const char *arg)
+{
+	char *endptr;
+	unsigned long rv = strtoul(arg, &endptr, 0);
+	if (strchr(arg, '-') || endptr == arg || *endptr)
+		die("%s: argument must be a non-negative integer", option);
+	return rv;
+}
+
+static void option_depth(const char *depth)
+{
+	max_depth = ulong_arg("--depth", depth);
+	if (max_depth > MAX_DEPTH)
+		die("--depth cannot exceed %u", MAX_DEPTH);
+}
+
+static void option_active_branches(const char *branches)
+{
+	max_active_branches = ulong_arg("--active-branches", branches);
+}
+
+static void option_export_marks(const char *marks)
+{
+	free(export_marks_file);
+	export_marks_file = make_fast_import_path(marks);
+}
+
+static void option_cat_blob_fd(const char *fd)
+{
+	unsigned long n = ulong_arg("--cat-blob-fd", fd);
+	if (n > (unsigned long) INT_MAX)
+		die("--cat-blob-fd cannot exceed %d", INT_MAX);
+	cat_blob_fd = (int) n;
+}
+
+static void option_export_pack_edges(const char *edges)
+{
+	char *fn = prefix_filename(global_prefix, edges);
+	if (pack_edges)
+		fclose(pack_edges);
+	pack_edges = xfopen(fn, "a");
+	free(fn);
+}
+
+static void option_rewrite_submodules(const char *arg, struct string_list *list)
+{
+	struct mark_set *ms;
+	FILE *fp;
+	char *s = xstrdup(arg);
+	char *f = strchr(s, ':');
+	if (!f)
+		die(_("Expected format name:filename for submodule rewrite option"));
+	*f = '\0';
+	f++;
+	CALLOC_ARRAY(ms, 1);
+
+	f = prefix_filename(global_prefix, f);
+	fp = fopen(f, "r");
+	if (!fp)
+		die_errno("cannot read '%s'", f);
+	read_mark_file(&ms, fp, insert_oid_entry);
+	fclose(fp);
+	free(f);
+
+	string_list_insert(list, s)->util = ms;
+
+	free(s);
+}
+
+static int parse_one_option(const char *option)
+{
+	if (skip_prefix(option, "max-pack-size=", &option)) {
+		unsigned long v;
+		if (!git_parse_ulong(option, &v))
+			return 0;
+		if (v < 8192) {
+			warning("max-pack-size is now in bytes, assuming --max-pack-size=%lum", v);
+			v *= 1024 * 1024;
+		} else if (v < 1024 * 1024) {
+			warning("minimum max-pack-size is 1 MiB");
+			v = 1024 * 1024;
+		}
+		max_packsize = v;
+	} else if (skip_prefix(option, "big-file-threshold=", &option)) {
+		unsigned long v;
+		if (!git_parse_ulong(option, &v))
+			return 0;
+		big_file_threshold = v;
+	} else if (skip_prefix(option, "depth=", &option)) {
+		option_depth(option);
+	} else if (skip_prefix(option, "active-branches=", &option)) {
+		option_active_branches(option);
+	} else if (skip_prefix(option, "export-pack-edges=", &option)) {
+		option_export_pack_edges(option);
+	} else if (!strcmp(option, "quiet")) {
+		show_stats = 0;
+		quiet = 1;
+	} else if (!strcmp(option, "stats")) {
+		show_stats = 1;
+	} else if (!strcmp(option, "allow-unsafe-features")) {
+		; /* already handled during early option parsing */
+	} else {
+		return 0;
+	}
+
+	return 1;
+}
+
+static void check_unsafe_feature(const char *feature, int from_stream)
+{
+	if (from_stream && !allow_unsafe_features)
+		die(_("feature '%s' forbidden in input without --allow-unsafe-features"),
+		    feature);
+}
+
+static int parse_one_feature(const char *feature, int from_stream)
+{
+	const char *arg;
+
+	if (skip_prefix(feature, "date-format=", &arg)) {
+		option_date_format(arg);
+	} else if (skip_prefix(feature, "import-marks=", &arg)) {
+		check_unsafe_feature("import-marks", from_stream);
+		option_import_marks(arg, from_stream, 0);
+	} else if (skip_prefix(feature, "import-marks-if-exists=", &arg)) {
+		check_unsafe_feature("import-marks-if-exists", from_stream);
+		option_import_marks(arg, from_stream, 1);
+	} else if (skip_prefix(feature, "export-marks=", &arg)) {
+		check_unsafe_feature(feature, from_stream);
+		option_export_marks(arg);
+	} else if (!strcmp(feature, "alias")) {
+		; /* Don't die - this feature is supported */
+	} else if (skip_prefix(feature, "rewrite-submodules-to=", &arg)) {
+		option_rewrite_submodules(arg, &sub_marks_to);
+	} else if (skip_prefix(feature, "rewrite-submodules-from=", &arg)) {
+		option_rewrite_submodules(arg, &sub_marks_from);
+	} else if (!strcmp(feature, "get-mark")) {
+		; /* Don't die - this feature is supported */
+	} else if (!strcmp(feature, "cat-blob")) {
+		; /* Don't die - this feature is supported */
+	} else if (!strcmp(feature, "relative-marks")) {
+		relative_marks_paths = 1;
+	} else if (!strcmp(feature, "no-relative-marks")) {
+		relative_marks_paths = 0;
+	} else if (!strcmp(feature, "done")) {
+		require_explicit_termination = 1;
+	} else if (!strcmp(feature, "force")) {
+		force_update = 1;
+	} else if (!strcmp(feature, "notes") || !strcmp(feature, "ls")) {
+		; /* do nothing; we have the feature */
+	} else {
+		return 0;
+	}
+
+	return 1;
+}
+
+static void parse_feature(const char *feature)
+{
+	if (seen_data_command)
+		die("Got feature command '%s' after data command", feature);
+
+	if (parse_one_feature(feature, 1))
+		return;
+
+	die("This version of fast-import does not support feature %s.", feature);
+}
+
+static void parse_option(const char *option)
+{
+	if (seen_data_command)
+		die("Got option command '%s' after data command", option);
+
+	if (parse_one_option(option))
+		return;
+
+	die("This version of fast-import does not support option: %s", option);
+}
+
+static void git_pack_config(void)
+{
+	int indexversion_value;
+	int limit;
+	unsigned long packsizelimit_value;
+
+	if (!git_config_get_ulong("pack.depth", &max_depth)) {
+		if (max_depth > MAX_DEPTH)
+			max_depth = MAX_DEPTH;
+	}
+	if (!git_config_get_int("pack.indexversion", &indexversion_value)) {
+		pack_idx_opts.version = indexversion_value;
+		if (pack_idx_opts.version > 2)
+			git_die_config(the_repository, "pack.indexversion",
+				       "bad pack.indexVersion=%"PRIu32, pack_idx_opts.version);
+	}
+	if (!git_config_get_ulong("pack.packsizelimit", &packsizelimit_value))
+		max_packsize = packsizelimit_value;
+
+	if (!git_config_get_int("fastimport.unpacklimit", &limit))
+		unpack_limit = limit;
+	else if (!git_config_get_int("transfer.unpacklimit", &limit))
+		unpack_limit = limit;
+
+	git_config(git_default_config, NULL);
+}
+
+static const char fast_import_usage[] =
+"git fast-import [--date-format=<f>] [--max-pack-size=<n>] [--big-file-threshold=<n>] [--depth=<n>] [--active-branches=<n>] [--export-marks=<marks.file>]";
+
+static void parse_argv(void)
+{
+	unsigned int i;
+
+	for (i = 1; i < global_argc; i++) {
+		const char *a = global_argv[i];
+
+		if (*a != '-' || !strcmp(a, "--"))
+			break;
+
+		if (!skip_prefix(a, "--", &a))
+			die("unknown option %s", a);
+
+		if (parse_one_option(a))
+			continue;
+
+		if (parse_one_feature(a, 0))
+			continue;
+
+		if (skip_prefix(a, "cat-blob-fd=", &a)) {
+			option_cat_blob_fd(a);
+			continue;
+		}
+
+		die("unknown option --%s", a);
+	}
+	if (i != global_argc)
+		usage(fast_import_usage);
+
+	seen_data_command = 1;
+	if (import_marks_file)
+		read_marks();
+	build_mark_map(&sub_marks_from, &sub_marks_to);
+}
+
+int cmd_fast_import(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo)
+{
+	unsigned int i;
+
+	show_usage_if_asked(argc, argv, fast_import_usage);
+
+	reset_pack_idx_option(&pack_idx_opts);
+	git_pack_config();
+
+	alloc_objects(object_entry_alloc);
+	strbuf_init(&command_buf, 0);
+	CALLOC_ARRAY(atom_table, atom_table_sz);
+	CALLOC_ARRAY(branch_table, branch_table_sz);
+	CALLOC_ARRAY(avail_tree_table, avail_tree_table_sz);
+	marks = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct mark_set));
+
+	hashmap_init(&object_table, object_entry_hashcmp, NULL, 0);
+
+	/*
+	 * We don't parse most options until after we've seen the set of
+	 * "feature" lines at the start of the stream (which allows the command
+	 * line to override stream data). But we must do an early parse of any
+	 * command-line options that impact how we interpret the feature lines.
+	 */
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (*arg != '-' || !strcmp(arg, "--"))
+			break;
+		if (!strcmp(arg, "--allow-unsafe-features"))
+			allow_unsafe_features = 1;
+	}
+
+	global_argc = argc;
+	global_argv = argv;
+	global_prefix = prefix;
+
+	rc_free = mem_pool_alloc(&fi_mem_pool, cmd_save * sizeof(*rc_free));
+	for (i = 0; i < (cmd_save - 1); i++)
+		rc_free[i].next = &rc_free[i + 1];
+	rc_free[cmd_save - 1].next = NULL;
+
+	start_packfile();
+	set_die_routine(die_nicely);
+	set_checkpoint_signal();
+	while (read_next_command() != EOF) {
+		const char *v;
+		if (!strcmp("blob", command_buf.buf))
+			parse_new_blob();
+		else if (skip_prefix(command_buf.buf, "commit ", &v))
+			parse_new_commit(v);
+		else if (skip_prefix(command_buf.buf, "tag ", &v))
+			parse_new_tag(v);
+		else if (skip_prefix(command_buf.buf, "reset ", &v))
+			parse_reset_branch(v);
+		else if (skip_prefix(command_buf.buf, "ls ", &v))
+			parse_ls(v, NULL);
+		else if (skip_prefix(command_buf.buf, "cat-blob ", &v))
+			parse_cat_blob(v);
+		else if (skip_prefix(command_buf.buf, "get-mark ", &v))
+			parse_get_mark(v);
+		else if (!strcmp("checkpoint", command_buf.buf))
+			parse_checkpoint();
+		else if (!strcmp("done", command_buf.buf))
+			break;
+		else if (!strcmp("alias", command_buf.buf))
+			parse_alias();
+		else if (starts_with(command_buf.buf, "progress "))
+			parse_progress();
+		else if (skip_prefix(command_buf.buf, "feature ", &v))
+			parse_feature(v);
+		else if (skip_prefix(command_buf.buf, "option git ", &v))
+			parse_option(v);
+		else if (starts_with(command_buf.buf, "option "))
+			/* ignore non-git options*/;
+		else
+			die("Unsupported command: %s", command_buf.buf);
+
+		if (checkpoint_requested)
+			checkpoint();
+	}
+
+	/* argv hasn't been parsed yet, do so */
+	if (!seen_data_command)
+		parse_argv();
+
+	if (require_explicit_termination && feof(stdin))
+		die("stream ends early");
+
+	end_packfile();
+
+	dump_branches();
+	dump_tags();
+	unkeep_all_packs();
+	dump_marks();
+
+	if (pack_edges)
+		fclose(pack_edges);
+
+	if (show_stats) {
+		uintmax_t total_count = 0, duplicate_count = 0;
+		for (i = 0; i < ARRAY_SIZE(object_count_by_type); i++)
+			total_count += object_count_by_type[i];
+		for (i = 0; i < ARRAY_SIZE(duplicate_count_by_type); i++)
+			duplicate_count += duplicate_count_by_type[i];
+
+		fprintf(stderr, "%s statistics:\n", argv[0]);
+		fprintf(stderr, "---------------------------------------------------------------------\n");
+		fprintf(stderr, "Alloc'd objects: %10" PRIuMAX "\n", alloc_count);
+		fprintf(stderr, "Total objects:   %10" PRIuMAX " (%10" PRIuMAX " duplicates                  )\n", total_count, duplicate_count);
+		fprintf(stderr, "      blobs  :   %10" PRIuMAX " (%10" PRIuMAX " duplicates %10" PRIuMAX " deltas of %10" PRIuMAX" attempts)\n", object_count_by_type[OBJ_BLOB], duplicate_count_by_type[OBJ_BLOB], delta_count_by_type[OBJ_BLOB], delta_count_attempts_by_type[OBJ_BLOB]);
+		fprintf(stderr, "      trees  :   %10" PRIuMAX " (%10" PRIuMAX " duplicates %10" PRIuMAX " deltas of %10" PRIuMAX" attempts)\n", object_count_by_type[OBJ_TREE], duplicate_count_by_type[OBJ_TREE], delta_count_by_type[OBJ_TREE], delta_count_attempts_by_type[OBJ_TREE]);
+		fprintf(stderr, "      commits:   %10" PRIuMAX " (%10" PRIuMAX " duplicates %10" PRIuMAX " deltas of %10" PRIuMAX" attempts)\n", object_count_by_type[OBJ_COMMIT], duplicate_count_by_type[OBJ_COMMIT], delta_count_by_type[OBJ_COMMIT], delta_count_attempts_by_type[OBJ_COMMIT]);
+		fprintf(stderr, "      tags   :   %10" PRIuMAX " (%10" PRIuMAX " duplicates %10" PRIuMAX " deltas of %10" PRIuMAX" attempts)\n", object_count_by_type[OBJ_TAG], duplicate_count_by_type[OBJ_TAG], delta_count_by_type[OBJ_TAG], delta_count_attempts_by_type[OBJ_TAG]);
+		fprintf(stderr, "Total branches:  %10lu (%10lu loads     )\n", branch_count, branch_load_count);
+		fprintf(stderr, "      marks:     %10" PRIuMAX " (%10" PRIuMAX " unique    )\n", (((uintmax_t)1) << marks->shift) * 1024, marks_set_count);
+		fprintf(stderr, "      atoms:     %10u\n", atom_cnt);
+		fprintf(stderr, "Memory total:    %10" PRIuMAX " KiB\n", (tree_entry_allocd + fi_mem_pool.pool_alloc + alloc_count*sizeof(struct object_entry))/1024);
+		fprintf(stderr, "       pools:    %10lu KiB\n", (unsigned long)((tree_entry_allocd + fi_mem_pool.pool_alloc) /1024));
+		fprintf(stderr, "     objects:    %10" PRIuMAX " KiB\n", (alloc_count*sizeof(struct object_entry))/1024);
+		fprintf(stderr, "---------------------------------------------------------------------\n");
+		pack_report(repo);
+		fprintf(stderr, "---------------------------------------------------------------------\n");
+		fprintf(stderr, "\n");
+	}
+
+	return failure ? 1 : 0;
+}
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
new file mode 100644
index 0000000000..d07eec9e55
--- /dev/null
+++ b/builtin/fetch-pack.c
@@ -0,0 +1,304 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "pkt-line.h"
+#include "fetch-pack.h"
+#include "remote.h"
+#include "connect.h"
+#include "oid-array.h"
+#include "protocol.h"
+
+static const char fetch_pack_usage[] =
+"git fetch-pack [--all] [--stdin] [--quiet | -q] [--keep | -k] [--thin] "
+"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
+"[--no-progress] [--diag-url] [-v] [<host>:]<directory> [<refs>...]";
+
+static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
+			     const char *name)
+{
+	struct ref *ref;
+	struct object_id oid;
+	const char *p;
+
+	if (!parse_oid_hex(name, &oid, &p)) {
+		if (*p == ' ') {
+			/* <oid> <ref>, find refname */
+			name = p + 1;
+		} else if (*p == '\0') {
+			; /* <oid>, leave oid as name */
+		} else {
+			/* <ref>, clear cruft from oid */
+			oidclr(&oid, the_repository->hash_algo);
+		}
+	} else {
+		/* <ref>, clear cruft from get_oid_hex */
+		oidclr(&oid, the_repository->hash_algo);
+	}
+
+	ref = alloc_ref(name);
+	oidcpy(&ref->old_oid, &oid);
+	(*nr)++;
+	ALLOC_GROW(*sought, *nr, *alloc);
+	(*sought)[*nr - 1] = ref;
+}
+
+int cmd_fetch_pack(int argc,
+		   const char **argv,
+		   const char *prefix UNUSED,
+		   struct repository *repo UNUSED)
+{
+	int i, ret;
+	struct ref *fetched_refs = NULL, *remote_refs = NULL;
+	const char *dest = NULL;
+	struct ref **sought = NULL;
+	struct ref **sought_to_free = NULL;
+	int nr_sought = 0, alloc_sought = 0;
+	int fd[2];
+	struct string_list pack_lockfiles = STRING_LIST_INIT_DUP;
+	struct string_list *pack_lockfiles_ptr = NULL;
+	struct child_process *conn;
+	struct fetch_pack_args args;
+	struct oid_array shallow = OID_ARRAY_INIT;
+	struct string_list deepen_not = STRING_LIST_INIT_DUP;
+	struct packet_reader reader;
+	enum protocol_version version;
+
+	fetch_if_missing = 0;
+
+	packet_trace_identity("fetch-pack");
+
+	memset(&args, 0, sizeof(args));
+	list_objects_filter_init(&args.filter_options);
+	args.uploadpack = "git-upload-pack";
+
+	show_usage_if_asked(argc, argv, fetch_pack_usage);
+
+	for (i = 1; i < argc && *argv[i] == '-'; i++) {
+		const char *arg = argv[i];
+
+		if (skip_prefix(arg, "--upload-pack=", &arg)) {
+			args.uploadpack = arg;
+			continue;
+		}
+		if (skip_prefix(arg, "--exec=", &arg)) {
+			args.uploadpack = arg;
+			continue;
+		}
+		if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
+			args.quiet = 1;
+			continue;
+		}
+		if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
+			args.lock_pack = args.keep_pack;
+			args.keep_pack = 1;
+			continue;
+		}
+		if (!strcmp("--thin", arg)) {
+			args.use_thin_pack = 1;
+			continue;
+		}
+		if (!strcmp("--include-tag", arg)) {
+			args.include_tag = 1;
+			continue;
+		}
+		if (!strcmp("--all", arg)) {
+			args.fetch_all = 1;
+			continue;
+		}
+		if (!strcmp("--stdin", arg)) {
+			args.stdin_refs = 1;
+			continue;
+		}
+		if (!strcmp("--diag-url", arg)) {
+			args.diag_url = 1;
+			continue;
+		}
+		if (!strcmp("-v", arg)) {
+			args.verbose = 1;
+			continue;
+		}
+		if (skip_prefix(arg, "--depth=", &arg)) {
+			args.depth = strtol(arg, NULL, 0);
+			continue;
+		}
+		if (skip_prefix(arg, "--shallow-since=", &arg)) {
+			args.deepen_since = xstrdup(arg);
+			continue;
+		}
+		if (skip_prefix(arg, "--shallow-exclude=", &arg)) {
+			string_list_append(&deepen_not, arg);
+			continue;
+		}
+		if (!strcmp(arg, "--deepen-relative")) {
+			args.deepen_relative = 1;
+			continue;
+		}
+		if (!strcmp("--no-progress", arg)) {
+			args.no_progress = 1;
+			continue;
+		}
+		if (!strcmp("--stateless-rpc", arg)) {
+			args.stateless_rpc = 1;
+			continue;
+		}
+		if (!strcmp("--lock-pack", arg)) {
+			args.lock_pack = 1;
+			pack_lockfiles_ptr = &pack_lockfiles;
+			continue;
+		}
+		if (!strcmp("--check-self-contained-and-connected", arg)) {
+			args.check_self_contained_and_connected = 1;
+			continue;
+		}
+		if (!strcmp("--cloning", arg)) {
+			args.cloning = 1;
+			continue;
+		}
+		if (!strcmp("--update-shallow", arg)) {
+			args.update_shallow = 1;
+			continue;
+		}
+		if (!strcmp("--from-promisor", arg)) {
+			args.from_promisor = 1;
+			continue;
+		}
+		if (!strcmp("--refetch", arg)) {
+			args.refetch = 1;
+			continue;
+		}
+		if (skip_prefix(arg, ("--filter="), &arg)) {
+			parse_list_objects_filter(&args.filter_options, arg);
+			continue;
+		}
+		if (!strcmp(arg, ("--no-filter"))) {
+			list_objects_filter_set_no_filter(&args.filter_options);
+			continue;
+		}
+		usage(fetch_pack_usage);
+	}
+	if (deepen_not.nr)
+		args.deepen_not = &deepen_not;
+
+	if (i < argc)
+		dest = argv[i++];
+	else
+		usage(fetch_pack_usage);
+
+	/*
+	 * Copy refs from cmdline to growable list, then append any
+	 * refs from the standard input:
+	 */
+	for (; i < argc; i++)
+		add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]);
+	if (args.stdin_refs) {
+		if (args.stateless_rpc) {
+			/* in stateless RPC mode we use pkt-line to read
+			 * from stdin, until we get a flush packet
+			 */
+			for (;;) {
+				char *line = packet_read_line(0, NULL);
+				if (!line)
+					break;
+				add_sought_entry(&sought, &nr_sought,  &alloc_sought, line);
+			}
+		}
+		else {
+			/* read from stdin one ref per line, until EOF */
+			struct strbuf line = STRBUF_INIT;
+			while (strbuf_getline_lf(&line, stdin) != EOF)
+				add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);
+			strbuf_release(&line);
+		}
+	}
+
+	if (args.stateless_rpc) {
+		conn = NULL;
+		fd[0] = 0;
+		fd[1] = 1;
+	} else {
+		int flags = args.verbose ? CONNECT_VERBOSE : 0;
+		if (args.diag_url)
+			flags |= CONNECT_DIAG_URL;
+		conn = git_connect(fd, dest, "git-upload-pack",
+				   args.uploadpack, flags);
+		if (!conn)
+			return args.diag_url ? 0 : 1;
+	}
+
+	packet_reader_init(&reader, fd[0], NULL, 0,
+			   PACKET_READ_CHOMP_NEWLINE |
+			   PACKET_READ_GENTLE_ON_EOF |
+			   PACKET_READ_DIE_ON_ERR_PACKET);
+
+	version = discover_version(&reader);
+	switch (version) {
+	case protocol_v2:
+		get_remote_refs(fd[1], &reader, &remote_refs, 0, NULL, NULL,
+				args.stateless_rpc);
+		break;
+	case protocol_v1:
+	case protocol_v0:
+		get_remote_heads(&reader, &remote_refs, 0, NULL, &shallow);
+		break;
+	case protocol_unknown_version:
+		BUG("unknown protocol version");
+	}
+
+	/*
+	 * Create a shallow copy of `sought` so that we can free all of its entries.
+	 * This is because `fetch_pack()` will modify the array to evict some
+	 * entries, but won't free those.
+	 */
+	DUP_ARRAY(sought_to_free, sought, nr_sought);
+
+	fetched_refs = fetch_pack(&args, fd, remote_refs, sought, nr_sought,
+			 &shallow, pack_lockfiles_ptr, version);
+
+	if (pack_lockfiles.nr) {
+		int i;
+
+		printf("lock %s\n", pack_lockfiles.items[0].string);
+		fflush(stdout);
+		for (i = 1; i < pack_lockfiles.nr; i++)
+			warning(_("Lockfile created but not reported: %s"),
+				pack_lockfiles.items[i].string);
+	}
+	if (args.check_self_contained_and_connected &&
+	    args.self_contained_and_connected) {
+		printf("connectivity-ok\n");
+		fflush(stdout);
+	}
+	close(fd[0]);
+	close(fd[1]);
+	if (finish_connect(conn))
+		return 1;
+
+	ret = !fetched_refs;
+
+	/*
+	 * If the heads to pull were given, we should have consumed
+	 * all of them by matching the remote.  Otherwise, 'git fetch
+	 * remote no-such-ref' would silently succeed without issuing
+	 * an error.
+	 */
+	ret |= report_unmatched_refs(sought, nr_sought);
+
+	for (struct ref *ref = fetched_refs; ref; ref = ref->next)
+		printf("%s %s\n",
+		       oid_to_hex(&ref->old_oid), ref->name);
+
+	for (size_t i = 0; i < nr_sought; i++)
+		free_one_ref(sought_to_free[i]);
+	free(sought_to_free);
+	free(sought);
+	free_refs(fetched_refs);
+	free_refs(remote_refs);
+	list_objects_filter_release(&args.filter_options);
+	oid_array_clear(&shallow);
+	string_list_clear(&pack_lockfiles, 0);
+	return ret;
+}
diff --git a/builtin/fetch.c b/builtin/fetch.c
new file mode 100644
index 0000000000..fe2b26c74a
--- /dev/null
+++ b/builtin/fetch.c
@@ -0,0 +1,2693 @@
+/*
+ * "git fetch"
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "gettext.h"
+#include "environment.h"
+#include "hex.h"
+#include "refs.h"
+#include "refspec.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "oidset.h"
+#include "oid-array.h"
+#include "commit.h"
+#include "string-list.h"
+#include "remote.h"
+#include "transport.h"
+#include "run-command.h"
+#include "parse-options.h"
+#include "sigchain.h"
+#include "submodule-config.h"
+#include "submodule.h"
+#include "connected.h"
+#include "strvec.h"
+#include "utf8.h"
+#include "pager.h"
+#include "path.h"
+#include "pkt-line.h"
+#include "list-objects-filter-options.h"
+#include "commit-reach.h"
+#include "branch.h"
+#include "promisor-remote.h"
+#include "commit-graph.h"
+#include "shallow.h"
+#include "trace.h"
+#include "trace2.h"
+#include "bundle-uri.h"
+
+#define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
+
+static const char * const builtin_fetch_usage[] = {
+	N_("git fetch [<options>] [<repository> [<refspec>...]]"),
+	N_("git fetch [<options>] <group>"),
+	N_("git fetch --multiple [<options>] [(<repository> | <group>)...]"),
+	N_("git fetch --all [<options>]"),
+	NULL
+};
+
+enum {
+	TAGS_UNSET = 0,
+	TAGS_DEFAULT = 1,
+	TAGS_SET = 2
+};
+
+enum display_format {
+	DISPLAY_FORMAT_FULL,
+	DISPLAY_FORMAT_COMPACT,
+	DISPLAY_FORMAT_PORCELAIN,
+};
+
+struct display_state {
+	struct strbuf buf;
+
+	int refcol_width;
+	enum display_format format;
+
+	char *url;
+	int url_len, shown_url;
+};
+
+static uint64_t forced_updates_ms = 0;
+static int prefetch = 0;
+static int prune = -1; /* unspecified */
+#define PRUNE_BY_DEFAULT 0 /* do we prune by default? */
+
+static int prune_tags = -1; /* unspecified */
+#define PRUNE_TAGS_BY_DEFAULT 0 /* do we prune tags by default? */
+
+static int append, dry_run, force, keep, update_head_ok;
+static int write_fetch_head = 1;
+static int verbosity, deepen_relative, set_upstream, refetch;
+static int progress = -1;
+static int tags = TAGS_DEFAULT, update_shallow, deepen;
+static int atomic_fetch;
+static enum transport_family family;
+static const char *depth;
+static const char *deepen_since;
+static const char *upload_pack;
+static struct string_list deepen_not = STRING_LIST_INIT_NODUP;
+static struct strbuf default_rla = STRBUF_INIT;
+static struct transport *gtransport;
+static struct transport *gsecondary;
+static struct refspec refmap = REFSPEC_INIT_FETCH;
+static struct list_objects_filter_options filter_options = LIST_OBJECTS_FILTER_INIT;
+static struct string_list server_options = STRING_LIST_INIT_DUP;
+static struct string_list negotiation_tip = STRING_LIST_INIT_NODUP;
+
+struct fetch_config {
+	enum display_format display_format;
+	int all;
+	int prune;
+	int prune_tags;
+	int show_forced_updates;
+	int recurse_submodules;
+	int parallel;
+	int submodule_fetch_jobs;
+};
+
+static int git_fetch_config(const char *k, const char *v,
+			    const struct config_context *ctx, void *cb)
+{
+	struct fetch_config *fetch_config = cb;
+
+	if (!strcmp(k, "fetch.all")) {
+		fetch_config->all = git_config_bool(k, v);
+		return 0;
+	}
+
+	if (!strcmp(k, "fetch.prune")) {
+		fetch_config->prune = git_config_bool(k, v);
+		return 0;
+	}
+
+	if (!strcmp(k, "fetch.prunetags")) {
+		fetch_config->prune_tags = git_config_bool(k, v);
+		return 0;
+	}
+
+	if (!strcmp(k, "fetch.showforcedupdates")) {
+		fetch_config->show_forced_updates = git_config_bool(k, v);
+		return 0;
+	}
+
+	if (!strcmp(k, "submodule.recurse")) {
+		int r = git_config_bool(k, v) ?
+			RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
+		fetch_config->recurse_submodules = r;
+		return 0;
+	}
+
+	if (!strcmp(k, "submodule.fetchjobs")) {
+		fetch_config->submodule_fetch_jobs = parse_submodule_fetchjobs(k, v, ctx->kvi);
+		return 0;
+	} else if (!strcmp(k, "fetch.recursesubmodules")) {
+		fetch_config->recurse_submodules = parse_fetch_recurse_submodules_arg(k, v);
+		return 0;
+	}
+
+	if (!strcmp(k, "fetch.parallel")) {
+		fetch_config->parallel = git_config_int(k, v, ctx->kvi);
+		if (fetch_config->parallel < 0)
+			die(_("fetch.parallel cannot be negative"));
+		if (!fetch_config->parallel)
+			fetch_config->parallel = online_cpus();
+		return 0;
+	}
+
+	if (!strcmp(k, "fetch.output")) {
+		if (!v)
+			return config_error_nonbool(k);
+		else if (!strcasecmp(v, "full"))
+			fetch_config->display_format = DISPLAY_FORMAT_FULL;
+		else if (!strcasecmp(v, "compact"))
+			fetch_config->display_format = DISPLAY_FORMAT_COMPACT;
+		else
+			die(_("invalid value for '%s': '%s'"),
+			    "fetch.output", v);
+	}
+
+	return git_default_config(k, v, ctx, cb);
+}
+
+static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+
+	/*
+	 * "git fetch --refmap='' origin foo"
+	 * can be used to tell the command not to store anywhere
+	 */
+	refspec_append(opt->value, arg);
+
+	return 0;
+}
+
+static void unlock_pack(unsigned int flags)
+{
+	if (gtransport)
+		transport_unlock_pack(gtransport, flags);
+	if (gsecondary)
+		transport_unlock_pack(gsecondary, flags);
+}
+
+static void unlock_pack_atexit(void)
+{
+	unlock_pack(0);
+}
+
+static void unlock_pack_on_signal(int signo)
+{
+	unlock_pack(TRANSPORT_UNLOCK_PACK_IN_SIGNAL_HANDLER);
+	sigchain_pop(signo);
+	raise(signo);
+}
+
+static void add_merge_config(struct ref **head,
+			   const struct ref *remote_refs,
+		           struct branch *branch,
+		           struct ref ***tail)
+{
+	int i;
+
+	for (i = 0; i < branch->merge_nr; i++) {
+		struct ref *rm, **old_tail = *tail;
+		struct refspec_item refspec;
+
+		for (rm = *head; rm; rm = rm->next) {
+			if (branch_merge_matches(branch, i, rm->name)) {
+				rm->fetch_head_status = FETCH_HEAD_MERGE;
+				break;
+			}
+		}
+		if (rm)
+			continue;
+
+		/*
+		 * Not fetched to a remote-tracking branch?  We need to fetch
+		 * it anyway to allow this branch's "branch.$name.merge"
+		 * to be honored by 'git pull', but we do not have to
+		 * fail if branch.$name.merge is misconfigured to point
+		 * at a nonexisting branch.  If we were indeed called by
+		 * 'git pull', it will notice the misconfiguration because
+		 * there is no entry in the resulting FETCH_HEAD marked
+		 * for merging.
+		 */
+		memset(&refspec, 0, sizeof(refspec));
+		refspec.src = branch->merge[i]->src;
+		get_fetch_map(remote_refs, &refspec, tail, 1);
+		for (rm = *old_tail; rm; rm = rm->next)
+			rm->fetch_head_status = FETCH_HEAD_MERGE;
+	}
+}
+
+static void create_fetch_oidset(struct ref **head, struct oidset *out)
+{
+	struct ref *rm = *head;
+	while (rm) {
+		oidset_insert(out, &rm->old_oid);
+		rm = rm->next;
+	}
+}
+
+struct refname_hash_entry {
+	struct hashmap_entry ent;
+	struct object_id oid;
+	int ignore;
+	char refname[FLEX_ARRAY];
+};
+
+static int refname_hash_entry_cmp(const void *hashmap_cmp_fn_data UNUSED,
+				  const struct hashmap_entry *eptr,
+				  const struct hashmap_entry *entry_or_key,
+				  const void *keydata)
+{
+	const struct refname_hash_entry *e1, *e2;
+
+	e1 = container_of(eptr, const struct refname_hash_entry, ent);
+	e2 = container_of(entry_or_key, const struct refname_hash_entry, ent);
+	return strcmp(e1->refname, keydata ? keydata : e2->refname);
+}
+
+static struct refname_hash_entry *refname_hash_add(struct hashmap *map,
+						   const char *refname,
+						   const struct object_id *oid)
+{
+	struct refname_hash_entry *ent;
+	size_t len = strlen(refname);
+
+	FLEX_ALLOC_MEM(ent, refname, refname, len);
+	hashmap_entry_init(&ent->ent, strhash(refname));
+	oidcpy(&ent->oid, oid);
+	hashmap_add(map, &ent->ent);
+	return ent;
+}
+
+static int add_one_refname(const char *refname, const char *referent UNUSED,
+			   const struct object_id *oid,
+			   int flag UNUSED, void *cbdata)
+{
+	struct hashmap *refname_map = cbdata;
+
+	(void) refname_hash_add(refname_map, refname, oid);
+	return 0;
+}
+
+static void refname_hash_init(struct hashmap *map)
+{
+	hashmap_init(map, refname_hash_entry_cmp, NULL, 0);
+}
+
+static int refname_hash_exists(struct hashmap *map, const char *refname)
+{
+	return !!hashmap_get_from_hash(map, strhash(refname), refname);
+}
+
+static void clear_item(struct refname_hash_entry *item)
+{
+	item->ignore = 1;
+}
+
+
+static void add_already_queued_tags(const char *refname,
+				    const struct object_id *old_oid UNUSED,
+				    const struct object_id *new_oid,
+				    void *cb_data)
+{
+	struct hashmap *queued_tags = cb_data;
+	if (starts_with(refname, "refs/tags/") && new_oid)
+		(void) refname_hash_add(queued_tags, refname, new_oid);
+}
+
+static void find_non_local_tags(const struct ref *refs,
+				struct ref_transaction *transaction,
+				struct ref **head,
+				struct ref ***tail)
+{
+	struct hashmap existing_refs;
+	struct hashmap remote_refs;
+	struct oidset fetch_oids = OIDSET_INIT;
+	struct string_list remote_refs_list = STRING_LIST_INIT_NODUP;
+	struct string_list_item *remote_ref_item;
+	const struct ref *ref;
+	struct refname_hash_entry *item = NULL;
+	const int quick_flags = OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT;
+
+	refname_hash_init(&existing_refs);
+	refname_hash_init(&remote_refs);
+	create_fetch_oidset(head, &fetch_oids);
+
+	refs_for_each_ref(get_main_ref_store(the_repository), add_one_refname,
+			  &existing_refs);
+
+	/*
+	 * If we already have a transaction, then we need to filter out all
+	 * tags which have already been queued up.
+	 */
+	if (transaction)
+		ref_transaction_for_each_queued_update(transaction,
+						       add_already_queued_tags,
+						       &existing_refs);
+
+	for (ref = refs; ref; ref = ref->next) {
+		if (!starts_with(ref->name, "refs/tags/"))
+			continue;
+
+		/*
+		 * The peeled ref always follows the matching base
+		 * ref, so if we see a peeled ref that we don't want
+		 * to fetch then we can mark the ref entry in the list
+		 * as one to ignore by setting util to NULL.
+		 */
+		if (ends_with(ref->name, "^{}")) {
+			if (item &&
+			    !repo_has_object_file_with_flags(the_repository, &ref->old_oid, quick_flags) &&
+			    !oidset_contains(&fetch_oids, &ref->old_oid) &&
+			    !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
+			    !oidset_contains(&fetch_oids, &item->oid))
+				clear_item(item);
+			item = NULL;
+			continue;
+		}
+
+		/*
+		 * If item is non-NULL here, then we previously saw a
+		 * ref not followed by a peeled reference, so we need
+		 * to check if it is a lightweight tag that we want to
+		 * fetch.
+		 */
+		if (item &&
+		    !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
+		    !oidset_contains(&fetch_oids, &item->oid))
+			clear_item(item);
+
+		item = NULL;
+
+		/* skip duplicates and refs that we already have */
+		if (refname_hash_exists(&remote_refs, ref->name) ||
+		    refname_hash_exists(&existing_refs, ref->name))
+			continue;
+
+		item = refname_hash_add(&remote_refs, ref->name, &ref->old_oid);
+		string_list_insert(&remote_refs_list, ref->name);
+	}
+	hashmap_clear_and_free(&existing_refs, struct refname_hash_entry, ent);
+
+	/*
+	 * We may have a final lightweight tag that needs to be
+	 * checked to see if it needs fetching.
+	 */
+	if (item &&
+	    !repo_has_object_file_with_flags(the_repository, &item->oid, quick_flags) &&
+	    !oidset_contains(&fetch_oids, &item->oid))
+		clear_item(item);
+
+	/*
+	 * For all the tags in the remote_refs_list,
+	 * add them to the list of refs to be fetched
+	 */
+	for_each_string_list_item(remote_ref_item, &remote_refs_list) {
+		const char *refname = remote_ref_item->string;
+		struct ref *rm;
+		unsigned int hash = strhash(refname);
+
+		item = hashmap_get_entry_from_hash(&remote_refs, hash, refname,
+					struct refname_hash_entry, ent);
+		if (!item)
+			BUG("unseen remote ref?");
+
+		/* Unless we have already decided to ignore this item... */
+		if (item->ignore)
+			continue;
+
+		rm = alloc_ref(item->refname);
+		rm->peer_ref = alloc_ref(item->refname);
+		oidcpy(&rm->old_oid, &item->oid);
+		**tail = rm;
+		*tail = &rm->next;
+	}
+	hashmap_clear_and_free(&remote_refs, struct refname_hash_entry, ent);
+	string_list_clear(&remote_refs_list, 0);
+	oidset_clear(&fetch_oids);
+}
+
+static void filter_prefetch_refspec(struct refspec *rs)
+{
+	int i;
+
+	if (!prefetch)
+		return;
+
+	for (i = 0; i < rs->nr; i++) {
+		struct strbuf new_dst = STRBUF_INIT;
+		char *old_dst;
+		const char *sub = NULL;
+
+		if (rs->items[i].negative)
+			continue;
+		if (!rs->items[i].dst ||
+		    (rs->items[i].src &&
+		     starts_with(rs->items[i].src,
+				 ref_namespace[NAMESPACE_TAGS].ref))) {
+			int j;
+
+			refspec_item_clear(&rs->items[i]);
+
+			for (j = i + 1; j < rs->nr; j++)
+				rs->items[j - 1] = rs->items[j];
+			rs->nr--;
+			i--;
+			continue;
+		}
+
+		old_dst = rs->items[i].dst;
+		strbuf_addstr(&new_dst, ref_namespace[NAMESPACE_PREFETCH].ref);
+
+		/*
+		 * If old_dst starts with "refs/", then place
+		 * sub after that prefix. Otherwise, start at
+		 * the beginning of the string.
+		 */
+		if (!skip_prefix(old_dst, "refs/", &sub))
+			sub = old_dst;
+		strbuf_addstr(&new_dst, sub);
+
+		rs->items[i].dst = strbuf_detach(&new_dst, NULL);
+		rs->items[i].force = 1;
+
+		free(old_dst);
+	}
+}
+
+static struct ref *get_ref_map(struct remote *remote,
+			       const struct ref *remote_refs,
+			       struct refspec *rs,
+			       int tags, int *autotags)
+{
+	int i;
+	struct ref *rm;
+	struct ref *ref_map = NULL;
+	struct ref **tail = &ref_map;
+
+	/* opportunistically-updated references: */
+	struct ref *orefs = NULL, **oref_tail = &orefs;
+
+	struct hashmap existing_refs;
+	int existing_refs_populated = 0;
+
+	filter_prefetch_refspec(rs);
+	if (remote)
+		filter_prefetch_refspec(&remote->fetch);
+
+	if (rs->nr) {
+		struct refspec *fetch_refspec;
+
+		for (i = 0; i < rs->nr; i++) {
+			get_fetch_map(remote_refs, &rs->items[i], &tail, 0);
+			if (rs->items[i].dst && rs->items[i].dst[0])
+				*autotags = 1;
+		}
+		/* Merge everything on the command line (but not --tags) */
+		for (rm = ref_map; rm; rm = rm->next)
+			rm->fetch_head_status = FETCH_HEAD_MERGE;
+
+		/*
+		 * For any refs that we happen to be fetching via
+		 * command-line arguments, the destination ref might
+		 * have been missing or have been different than the
+		 * remote-tracking ref that would be derived from the
+		 * configured refspec.  In these cases, we want to
+		 * take the opportunity to update their configured
+		 * remote-tracking reference.  However, we do not want
+		 * to mention these entries in FETCH_HEAD at all, as
+		 * they would simply be duplicates of existing
+		 * entries, so we set them FETCH_HEAD_IGNORE below.
+		 *
+		 * We compute these entries now, based only on the
+		 * refspecs specified on the command line.  But we add
+		 * them to the list following the refspecs resulting
+		 * from the tags option so that one of the latter,
+		 * which has FETCH_HEAD_NOT_FOR_MERGE, is not removed
+		 * by ref_remove_duplicates() in favor of one of these
+		 * opportunistic entries with FETCH_HEAD_IGNORE.
+		 */
+		if (refmap.nr)
+			fetch_refspec = &refmap;
+		else
+			fetch_refspec = &remote->fetch;
+
+		for (i = 0; i < fetch_refspec->nr; i++)
+			get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
+	} else if (refmap.nr) {
+		die("--refmap option is only meaningful with command-line refspec(s)");
+	} else {
+		/* Use the defaults */
+		struct branch *branch = branch_get(NULL);
+		int has_merge = branch_has_merge_config(branch);
+		if (remote &&
+		    (remote->fetch.nr ||
+		     /* Note: has_merge implies non-NULL branch->remote_name */
+		     (has_merge && !strcmp(branch->remote_name, remote->name)))) {
+			for (i = 0; i < remote->fetch.nr; i++) {
+				get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0);
+				if (remote->fetch.items[i].dst &&
+				    remote->fetch.items[i].dst[0])
+					*autotags = 1;
+				if (!i && !has_merge && ref_map &&
+				    !remote->fetch.items[0].pattern)
+					ref_map->fetch_head_status = FETCH_HEAD_MERGE;
+			}
+			/*
+			 * if the remote we're fetching from is the same
+			 * as given in branch.<name>.remote, we add the
+			 * ref given in branch.<name>.merge, too.
+			 *
+			 * Note: has_merge implies non-NULL branch->remote_name
+			 */
+			if (has_merge &&
+			    !strcmp(branch->remote_name, remote->name))
+				add_merge_config(&ref_map, remote_refs, branch, &tail);
+		} else if (!prefetch) {
+			ref_map = get_remote_ref(remote_refs, "HEAD");
+			if (!ref_map)
+				die(_("couldn't find remote ref HEAD"));
+			ref_map->fetch_head_status = FETCH_HEAD_MERGE;
+			tail = &ref_map->next;
+		}
+	}
+
+	if (tags == TAGS_SET) {
+		struct refspec_item tag_refspec;
+
+		/* also fetch all tags */
+		refspec_item_init(&tag_refspec, TAG_REFSPEC, 0);
+		get_fetch_map(remote_refs, &tag_refspec, &tail, 0);
+		refspec_item_clear(&tag_refspec);
+	} else if (tags == TAGS_DEFAULT && *autotags) {
+		find_non_local_tags(remote_refs, NULL, &ref_map, &tail);
+	}
+
+	/* Now append any refs to be updated opportunistically: */
+	*tail = orefs;
+	for (rm = orefs; rm; rm = rm->next) {
+		rm->fetch_head_status = FETCH_HEAD_IGNORE;
+		tail = &rm->next;
+	}
+
+	/*
+	 * apply negative refspecs first, before we remove duplicates. This is
+	 * necessary as negative refspecs might remove an otherwise conflicting
+	 * duplicate.
+	 */
+	if (rs->nr)
+		ref_map = apply_negative_refspecs(ref_map, rs);
+	else
+		ref_map = apply_negative_refspecs(ref_map, &remote->fetch);
+
+	ref_map = ref_remove_duplicates(ref_map);
+
+	for (rm = ref_map; rm; rm = rm->next) {
+		if (rm->peer_ref) {
+			const char *refname = rm->peer_ref->name;
+			struct refname_hash_entry *peer_item;
+			unsigned int hash = strhash(refname);
+
+			if (!existing_refs_populated) {
+				refname_hash_init(&existing_refs);
+				refs_for_each_ref(get_main_ref_store(the_repository),
+						  add_one_refname,
+						  &existing_refs);
+				existing_refs_populated = 1;
+			}
+
+			peer_item = hashmap_get_entry_from_hash(&existing_refs,
+						hash, refname,
+						struct refname_hash_entry, ent);
+			if (peer_item) {
+				struct object_id *old_oid = &peer_item->oid;
+				oidcpy(&rm->peer_ref->old_oid, old_oid);
+			}
+		}
+	}
+	if (existing_refs_populated)
+		hashmap_clear_and_free(&existing_refs, struct refname_hash_entry, ent);
+
+	return ref_map;
+}
+
+#define STORE_REF_ERROR_OTHER 1
+#define STORE_REF_ERROR_DF_CONFLICT 2
+
+static int s_update_ref(const char *action,
+			struct ref *ref,
+			struct ref_transaction *transaction,
+			int check_old)
+{
+	char *msg;
+	char *rla = getenv("GIT_REFLOG_ACTION");
+	struct ref_transaction *our_transaction = NULL;
+	struct strbuf err = STRBUF_INIT;
+	int ret;
+
+	if (dry_run)
+		return 0;
+	if (!rla)
+		rla = default_rla.buf;
+	msg = xstrfmt("%s: %s", rla, action);
+
+	/*
+	 * If no transaction was passed to us, we manage the transaction
+	 * ourselves. Otherwise, we trust the caller to handle the transaction
+	 * lifecycle.
+	 */
+	if (!transaction) {
+		transaction = our_transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+									    0, &err);
+		if (!transaction) {
+			ret = STORE_REF_ERROR_OTHER;
+			goto out;
+		}
+	}
+
+	ret = ref_transaction_update(transaction, ref->name, &ref->new_oid,
+				     check_old ? &ref->old_oid : NULL,
+				     NULL, NULL, 0, msg, &err);
+	if (ret) {
+		ret = STORE_REF_ERROR_OTHER;
+		goto out;
+	}
+
+	if (our_transaction) {
+		switch (ref_transaction_commit(our_transaction, &err)) {
+		case 0:
+			break;
+		case TRANSACTION_NAME_CONFLICT:
+			ret = STORE_REF_ERROR_DF_CONFLICT;
+			goto out;
+		default:
+			ret = STORE_REF_ERROR_OTHER;
+			goto out;
+		}
+	}
+
+out:
+	ref_transaction_free(our_transaction);
+	if (ret)
+		error("%s", err.buf);
+	strbuf_release(&err);
+	free(msg);
+	return ret;
+}
+
+static int refcol_width(const struct ref *ref_map, int compact_format)
+{
+	const struct ref *ref;
+	int max, width = 10;
+
+	max = term_columns();
+	if (compact_format)
+		max = max * 2 / 3;
+
+	for (ref = ref_map; ref; ref = ref->next) {
+		int rlen, llen = 0, len;
+
+		if (ref->status == REF_STATUS_REJECT_SHALLOW ||
+		    !ref->peer_ref ||
+		    !strcmp(ref->name, "HEAD"))
+			continue;
+
+		/* uptodate lines are only shown on high verbosity level */
+		if (verbosity <= 0 && oideq(&ref->peer_ref->old_oid, &ref->old_oid))
+			continue;
+
+		rlen = utf8_strwidth(prettify_refname(ref->name));
+		if (!compact_format)
+			llen = utf8_strwidth(prettify_refname(ref->peer_ref->name));
+
+		/*
+		 * rough estimation to see if the output line is too long and
+		 * should not be counted (we can't do precise calculation
+		 * anyway because we don't know if the error explanation part
+		 * will be printed in update_local_ref)
+		 */
+		len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
+		if (len >= max)
+			continue;
+
+		if (width < rlen)
+			width = rlen;
+	}
+
+	return width;
+}
+
+static void display_state_init(struct display_state *display_state, struct ref *ref_map,
+			       const char *raw_url, enum display_format format)
+{
+	int i;
+
+	memset(display_state, 0, sizeof(*display_state));
+	strbuf_init(&display_state->buf, 0);
+	display_state->format = format;
+
+	if (raw_url)
+		display_state->url = transport_anonymize_url(raw_url);
+	else
+		display_state->url = xstrdup("foreign");
+
+	display_state->url_len = strlen(display_state->url);
+	for (i = display_state->url_len - 1; display_state->url[i] == '/' && 0 <= i; i--)
+		;
+	display_state->url_len = i + 1;
+	if (4 < i && !strncmp(".git", display_state->url + i - 3, 4))
+		display_state->url_len = i - 3;
+
+	if (verbosity < 0)
+		return;
+
+	switch (display_state->format) {
+	case DISPLAY_FORMAT_FULL:
+	case DISPLAY_FORMAT_COMPACT:
+		display_state->refcol_width = refcol_width(ref_map,
+							   display_state->format == DISPLAY_FORMAT_COMPACT);
+		break;
+	case DISPLAY_FORMAT_PORCELAIN:
+		/* We don't need to precompute anything here. */
+		break;
+	default:
+		BUG("unexpected display format %d", display_state->format);
+	}
+}
+
+static void display_state_release(struct display_state *display_state)
+{
+	strbuf_release(&display_state->buf);
+	free(display_state->url);
+}
+
+static void print_remote_to_local(struct display_state *display_state,
+				  const char *remote, const char *local)
+{
+	strbuf_addf(&display_state->buf, "%-*s -> %s",
+		    display_state->refcol_width, remote, local);
+}
+
+static int find_and_replace(struct strbuf *haystack,
+			    const char *needle,
+			    const char *placeholder)
+{
+	const char *p = NULL;
+	int plen, nlen;
+
+	nlen = strlen(needle);
+	if (ends_with(haystack->buf, needle))
+		p = haystack->buf + haystack->len - nlen;
+	else
+		p = strstr(haystack->buf, needle);
+	if (!p)
+		return 0;
+
+	if (p > haystack->buf && p[-1] != '/')
+		return 0;
+
+	plen = strlen(p);
+	if (plen > nlen && p[nlen] != '/')
+		return 0;
+
+	strbuf_splice(haystack, p - haystack->buf, nlen,
+		      placeholder, strlen(placeholder));
+	return 1;
+}
+
+static void print_compact(struct display_state *display_state,
+			  const char *remote, const char *local)
+{
+	struct strbuf r = STRBUF_INIT;
+	struct strbuf l = STRBUF_INIT;
+
+	if (!strcmp(remote, local)) {
+		strbuf_addf(&display_state->buf, "%-*s -> *", display_state->refcol_width, remote);
+		return;
+	}
+
+	strbuf_addstr(&r, remote);
+	strbuf_addstr(&l, local);
+
+	if (!find_and_replace(&r, local, "*"))
+		find_and_replace(&l, remote, "*");
+	print_remote_to_local(display_state, r.buf, l.buf);
+
+	strbuf_release(&r);
+	strbuf_release(&l);
+}
+
+static void display_ref_update(struct display_state *display_state, char code,
+			       const char *summary, const char *error,
+			       const char *remote, const char *local,
+			       const struct object_id *old_oid,
+			       const struct object_id *new_oid,
+			       int summary_width)
+{
+	FILE *f = stderr;
+
+	if (verbosity < 0)
+		return;
+
+	strbuf_reset(&display_state->buf);
+
+	switch (display_state->format) {
+	case DISPLAY_FORMAT_FULL:
+	case DISPLAY_FORMAT_COMPACT: {
+		int width;
+
+		if (!display_state->shown_url) {
+			strbuf_addf(&display_state->buf, _("From %.*s\n"),
+				    display_state->url_len, display_state->url);
+			display_state->shown_url = 1;
+		}
+
+		width = (summary_width + strlen(summary) - gettext_width(summary));
+		remote = prettify_refname(remote);
+		local = prettify_refname(local);
+
+		strbuf_addf(&display_state->buf, " %c %-*s ", code, width, summary);
+
+		if (display_state->format != DISPLAY_FORMAT_COMPACT)
+			print_remote_to_local(display_state, remote, local);
+		else
+			print_compact(display_state, remote, local);
+
+		if (error)
+			strbuf_addf(&display_state->buf, "  (%s)", error);
+
+		break;
+	}
+	case DISPLAY_FORMAT_PORCELAIN:
+		strbuf_addf(&display_state->buf, "%c %s %s %s", code,
+			    oid_to_hex(old_oid), oid_to_hex(new_oid), local);
+		f = stdout;
+		break;
+	default:
+		BUG("unexpected display format %d", display_state->format);
+	};
+	strbuf_addch(&display_state->buf, '\n');
+
+	fputs(display_state->buf.buf, f);
+}
+
+static int update_local_ref(struct ref *ref,
+			    struct ref_transaction *transaction,
+			    struct display_state *display_state,
+			    const struct ref *remote_ref,
+			    int summary_width,
+			    const struct fetch_config *config)
+{
+	struct commit *current = NULL, *updated;
+	int fast_forward = 0;
+
+	if (!repo_has_object_file(the_repository, &ref->new_oid))
+		die(_("object %s not found"), oid_to_hex(&ref->new_oid));
+
+	if (oideq(&ref->old_oid, &ref->new_oid)) {
+		if (verbosity > 0)
+			display_ref_update(display_state, '=', _("[up to date]"), NULL,
+					   remote_ref->name, ref->name,
+					   &ref->old_oid, &ref->new_oid, summary_width);
+		return 0;
+	}
+
+	if (!update_head_ok &&
+	    !is_null_oid(&ref->old_oid) &&
+	    branch_checked_out(ref->name)) {
+		/*
+		 * If this is the head, and it's not okay to update
+		 * the head, and the old value of the head isn't empty...
+		 */
+		display_ref_update(display_state, '!', _("[rejected]"),
+				   _("can't fetch into checked-out branch"),
+				   remote_ref->name, ref->name,
+				   &ref->old_oid, &ref->new_oid, summary_width);
+		return 1;
+	}
+
+	if (!is_null_oid(&ref->old_oid) &&
+	    starts_with(ref->name, "refs/tags/")) {
+		if (force || ref->force) {
+			int r;
+			r = s_update_ref("updating tag", ref, transaction, 0);
+			display_ref_update(display_state, r ? '!' : 't', _("[tag update]"),
+					   r ? _("unable to update local ref") : NULL,
+					   remote_ref->name, ref->name,
+					   &ref->old_oid, &ref->new_oid, summary_width);
+			return r;
+		} else {
+			display_ref_update(display_state, '!', _("[rejected]"),
+					   _("would clobber existing tag"),
+					   remote_ref->name, ref->name,
+					   &ref->old_oid, &ref->new_oid, summary_width);
+			return 1;
+		}
+	}
+
+	current = lookup_commit_reference_gently(the_repository,
+						 &ref->old_oid, 1);
+	updated = lookup_commit_reference_gently(the_repository,
+						 &ref->new_oid, 1);
+	if (!current || !updated) {
+		const char *msg;
+		const char *what;
+		int r;
+		/*
+		 * Nicely describe the new ref we're fetching.
+		 * Base this on the remote's ref name, as it's
+		 * more likely to follow a standard layout.
+		 */
+		if (starts_with(remote_ref->name, "refs/tags/")) {
+			msg = "storing tag";
+			what = _("[new tag]");
+		} else if (starts_with(remote_ref->name, "refs/heads/")) {
+			msg = "storing head";
+			what = _("[new branch]");
+		} else {
+			msg = "storing ref";
+			what = _("[new ref]");
+		}
+
+		r = s_update_ref(msg, ref, transaction, 0);
+		display_ref_update(display_state, r ? '!' : '*', what,
+				   r ? _("unable to update local ref") : NULL,
+				   remote_ref->name, ref->name,
+				   &ref->old_oid, &ref->new_oid, summary_width);
+		return r;
+	}
+
+	if (config->show_forced_updates) {
+		uint64_t t_before = getnanotime();
+		fast_forward = repo_in_merge_bases(the_repository, current,
+						   updated);
+		if (fast_forward < 0)
+			exit(128);
+		forced_updates_ms += (getnanotime() - t_before) / 1000000;
+	} else {
+		fast_forward = 1;
+	}
+
+	if (fast_forward) {
+		struct strbuf quickref = STRBUF_INIT;
+		int r;
+
+		strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
+		strbuf_addstr(&quickref, "..");
+		strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
+		r = s_update_ref("fast-forward", ref, transaction, 1);
+		display_ref_update(display_state, r ? '!' : ' ', quickref.buf,
+				   r ? _("unable to update local ref") : NULL,
+				   remote_ref->name, ref->name,
+				   &ref->old_oid, &ref->new_oid, summary_width);
+		strbuf_release(&quickref);
+		return r;
+	} else if (force || ref->force) {
+		struct strbuf quickref = STRBUF_INIT;
+		int r;
+		strbuf_add_unique_abbrev(&quickref, &current->object.oid, DEFAULT_ABBREV);
+		strbuf_addstr(&quickref, "...");
+		strbuf_add_unique_abbrev(&quickref, &ref->new_oid, DEFAULT_ABBREV);
+		r = s_update_ref("forced-update", ref, transaction, 1);
+		display_ref_update(display_state, r ? '!' : '+', quickref.buf,
+				   r ? _("unable to update local ref") : _("forced update"),
+				   remote_ref->name, ref->name,
+				   &ref->old_oid, &ref->new_oid, summary_width);
+		strbuf_release(&quickref);
+		return r;
+	} else {
+		display_ref_update(display_state, '!', _("[rejected]"), _("non-fast-forward"),
+				   remote_ref->name, ref->name,
+				   &ref->old_oid, &ref->new_oid, summary_width);
+		return 1;
+	}
+}
+
+static const struct object_id *iterate_ref_map(void *cb_data)
+{
+	struct ref **rm = cb_data;
+	struct ref *ref = *rm;
+
+	while (ref && ref->status == REF_STATUS_REJECT_SHALLOW)
+		ref = ref->next;
+	if (!ref)
+		return NULL;
+	*rm = ref->next;
+	return &ref->old_oid;
+}
+
+struct fetch_head {
+	FILE *fp;
+	struct strbuf buf;
+};
+
+static int open_fetch_head(struct fetch_head *fetch_head)
+{
+	const char *filename = git_path_fetch_head(the_repository);
+
+	if (write_fetch_head) {
+		fetch_head->fp = fopen(filename, "a");
+		if (!fetch_head->fp)
+			return error_errno(_("cannot open '%s'"), filename);
+		strbuf_init(&fetch_head->buf, 0);
+	} else {
+		fetch_head->fp = NULL;
+	}
+
+	return 0;
+}
+
+static void append_fetch_head(struct fetch_head *fetch_head,
+			      const struct object_id *old_oid,
+			      enum fetch_head_status fetch_head_status,
+			      const char *note,
+			      const char *url, size_t url_len)
+{
+	char old_oid_hex[GIT_MAX_HEXSZ + 1];
+	const char *merge_status_marker;
+	size_t i;
+
+	if (!fetch_head->fp)
+		return;
+
+	switch (fetch_head_status) {
+	case FETCH_HEAD_NOT_FOR_MERGE:
+		merge_status_marker = "not-for-merge";
+		break;
+	case FETCH_HEAD_MERGE:
+		merge_status_marker = "";
+		break;
+	default:
+		/* do not write anything to FETCH_HEAD */
+		return;
+	}
+
+	strbuf_addf(&fetch_head->buf, "%s\t%s\t%s",
+		    oid_to_hex_r(old_oid_hex, old_oid), merge_status_marker, note);
+	for (i = 0; i < url_len; ++i)
+		if ('\n' == url[i])
+			strbuf_addstr(&fetch_head->buf, "\\n");
+		else
+			strbuf_addch(&fetch_head->buf, url[i]);
+	strbuf_addch(&fetch_head->buf, '\n');
+
+	/*
+	 * When using an atomic fetch, we do not want to update FETCH_HEAD if
+	 * any of the reference updates fails. We thus have to write all
+	 * updates to a buffer first and only commit it as soon as all
+	 * references have been successfully updated.
+	 */
+	if (!atomic_fetch) {
+		strbuf_write(&fetch_head->buf, fetch_head->fp);
+		strbuf_reset(&fetch_head->buf);
+	}
+}
+
+static void commit_fetch_head(struct fetch_head *fetch_head)
+{
+	if (!fetch_head->fp || !atomic_fetch)
+		return;
+	strbuf_write(&fetch_head->buf, fetch_head->fp);
+}
+
+static void close_fetch_head(struct fetch_head *fetch_head)
+{
+	if (!fetch_head->fp)
+		return;
+
+	fclose(fetch_head->fp);
+	strbuf_release(&fetch_head->buf);
+}
+
+static const char warn_show_forced_updates[] =
+N_("fetch normally indicates which branches had a forced update,\n"
+   "but that check has been disabled; to re-enable, use '--show-forced-updates'\n"
+   "flag or run 'git config fetch.showForcedUpdates true'");
+static const char warn_time_show_forced_updates[] =
+N_("it took %.2f seconds to check forced updates; you can use\n"
+   "'--no-show-forced-updates' or run 'git config fetch.showForcedUpdates false'\n"
+   "to avoid this check\n");
+
+static int store_updated_refs(struct display_state *display_state,
+			      const char *remote_name,
+			      int connectivity_checked,
+			      struct ref_transaction *transaction, struct ref *ref_map,
+			      struct fetch_head *fetch_head,
+			      const struct fetch_config *config)
+{
+	int rc = 0;
+	struct strbuf note = STRBUF_INIT;
+	const char *what, *kind;
+	struct ref *rm;
+	int want_status;
+	int summary_width = 0;
+
+	if (verbosity >= 0)
+		summary_width = transport_summary_width(ref_map);
+
+	if (!connectivity_checked) {
+		struct check_connected_options opt = CHECK_CONNECTED_INIT;
+
+		opt.exclude_hidden_refs_section = "fetch";
+		rm = ref_map;
+		if (check_connected(iterate_ref_map, &rm, &opt)) {
+			rc = error(_("%s did not send all necessary objects"),
+				   display_state->url);
+			goto abort;
+		}
+	}
+
+	/*
+	 * We do a pass for each fetch_head_status type in their enum order, so
+	 * merged entries are written before not-for-merge. That lets readers
+	 * use FETCH_HEAD as a refname to refer to the ref to be merged.
+	 */
+	for (want_status = FETCH_HEAD_MERGE;
+	     want_status <= FETCH_HEAD_IGNORE;
+	     want_status++) {
+		for (rm = ref_map; rm; rm = rm->next) {
+			struct ref *ref = NULL;
+
+			if (rm->status == REF_STATUS_REJECT_SHALLOW) {
+				if (want_status == FETCH_HEAD_MERGE)
+					warning(_("rejected %s because shallow roots are not allowed to be updated"),
+						rm->peer_ref ? rm->peer_ref->name : rm->name);
+				continue;
+			}
+
+			/*
+			 * When writing FETCH_HEAD we need to determine whether
+			 * we already have the commit or not. If not, then the
+			 * reference is not for merge and needs to be written
+			 * to the reflog after other commits which we already
+			 * have. We're not interested in this property though
+			 * in case FETCH_HEAD is not to be updated, so we can
+			 * skip the classification in that case.
+			 */
+			if (fetch_head->fp) {
+				struct commit *commit = NULL;
+
+				/*
+				 * References in "refs/tags/" are often going to point
+				 * to annotated tags, which are not part of the
+				 * commit-graph. We thus only try to look up refs in
+				 * the graph which are not in that namespace to not
+				 * regress performance in repositories with many
+				 * annotated tags.
+				 */
+				if (!starts_with(rm->name, "refs/tags/"))
+					commit = lookup_commit_in_graph(the_repository, &rm->old_oid);
+				if (!commit) {
+					commit = lookup_commit_reference_gently(the_repository,
+										&rm->old_oid,
+										1);
+					if (!commit)
+						rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
+				}
+			}
+
+			if (rm->fetch_head_status != want_status)
+				continue;
+
+			if (rm->peer_ref) {
+				ref = alloc_ref(rm->peer_ref->name);
+				oidcpy(&ref->old_oid, &rm->peer_ref->old_oid);
+				oidcpy(&ref->new_oid, &rm->old_oid);
+				ref->force = rm->peer_ref->force;
+			}
+
+			if (config->recurse_submodules != RECURSE_SUBMODULES_OFF &&
+			    (!rm->peer_ref || !oideq(&ref->old_oid, &ref->new_oid))) {
+				check_for_new_submodule_commits(&rm->old_oid);
+			}
+
+			if (!strcmp(rm->name, "HEAD")) {
+				kind = "";
+				what = "";
+			} else if (skip_prefix(rm->name, "refs/heads/", &what)) {
+				kind = "branch";
+			} else if (skip_prefix(rm->name, "refs/tags/", &what)) {
+				kind = "tag";
+			} else if (skip_prefix(rm->name, "refs/remotes/", &what)) {
+				kind = "remote-tracking branch";
+			} else {
+				kind = "";
+				what = rm->name;
+			}
+
+			strbuf_reset(&note);
+			if (*what) {
+				if (*kind)
+					strbuf_addf(&note, "%s ", kind);
+				strbuf_addf(&note, "'%s' of ", what);
+			}
+
+			append_fetch_head(fetch_head, &rm->old_oid,
+					  rm->fetch_head_status,
+					  note.buf, display_state->url,
+					  display_state->url_len);
+
+			if (ref) {
+				rc |= update_local_ref(ref, transaction, display_state,
+						       rm, summary_width, config);
+				free(ref);
+			} else if (write_fetch_head || dry_run) {
+				/*
+				 * Display fetches written to FETCH_HEAD (or
+				 * would be written to FETCH_HEAD, if --dry-run
+				 * is set).
+				 */
+				display_ref_update(display_state, '*',
+						   *kind ? kind : "branch", NULL,
+						   rm->name,
+						   "FETCH_HEAD",
+						   &rm->new_oid, &rm->old_oid,
+						   summary_width);
+			}
+		}
+	}
+
+	if (rc & STORE_REF_ERROR_DF_CONFLICT)
+		error(_("some local refs could not be updated; try running\n"
+		      " 'git remote prune %s' to remove any old, conflicting "
+		      "branches"), remote_name);
+
+	if (advice_enabled(ADVICE_FETCH_SHOW_FORCED_UPDATES)) {
+		if (!config->show_forced_updates) {
+			warning(_(warn_show_forced_updates));
+		} else if (forced_updates_ms > FORCED_UPDATES_DELAY_WARNING_IN_MS) {
+			warning(_(warn_time_show_forced_updates),
+				forced_updates_ms / 1000.0);
+		}
+	}
+
+ abort:
+	strbuf_release(&note);
+	return rc;
+}
+
+/*
+ * We would want to bypass the object transfer altogether if
+ * everything we are going to fetch already exists and is connected
+ * locally.
+ */
+static int check_exist_and_connected(struct ref *ref_map)
+{
+	struct ref *rm = ref_map;
+	struct check_connected_options opt = CHECK_CONNECTED_INIT;
+	struct ref *r;
+
+	/*
+	 * If we are deepening a shallow clone we already have these
+	 * objects reachable.  Running rev-list here will return with
+	 * a good (0) exit status and we'll bypass the fetch that we
+	 * really need to perform.  Claiming failure now will ensure
+	 * we perform the network exchange to deepen our history.
+	 */
+	if (deepen)
+		return -1;
+
+	/*
+	 * Similarly, if we need to refetch, we always want to perform a full
+	 * fetch ignoring existing objects.
+	 */
+	if (refetch)
+		return -1;
+
+
+	/*
+	 * check_connected() allows objects to merely be promised, but
+	 * we need all direct targets to exist.
+	 */
+	for (r = rm; r; r = r->next) {
+		if (!repo_has_object_file_with_flags(the_repository, &r->old_oid,
+						     OBJECT_INFO_SKIP_FETCH_OBJECT))
+			return -1;
+	}
+
+	opt.quiet = 1;
+	opt.exclude_hidden_refs_section = "fetch";
+	return check_connected(iterate_ref_map, &rm, &opt);
+}
+
+static int fetch_and_consume_refs(struct display_state *display_state,
+				  struct transport *transport,
+				  struct ref_transaction *transaction,
+				  struct ref *ref_map,
+				  struct fetch_head *fetch_head,
+				  const struct fetch_config *config)
+{
+	int connectivity_checked = 1;
+	int ret;
+
+	/*
+	 * We don't need to perform a fetch in case we can already satisfy all
+	 * refs.
+	 */
+	ret = check_exist_and_connected(ref_map);
+	if (ret) {
+		trace2_region_enter("fetch", "fetch_refs", the_repository);
+		ret = transport_fetch_refs(transport, ref_map);
+		trace2_region_leave("fetch", "fetch_refs", the_repository);
+		if (ret)
+			goto out;
+		connectivity_checked = transport->smart_options ?
+			transport->smart_options->connectivity_checked : 0;
+	}
+
+	trace2_region_enter("fetch", "consume_refs", the_repository);
+	ret = store_updated_refs(display_state, transport->remote->name,
+				 connectivity_checked, transaction, ref_map,
+				 fetch_head, config);
+	trace2_region_leave("fetch", "consume_refs", the_repository);
+
+out:
+	transport_unlock_pack(transport, 0);
+	return ret;
+}
+
+static int prune_refs(struct display_state *display_state,
+		      struct refspec *rs,
+		      struct ref_transaction *transaction,
+		      struct ref *ref_map)
+{
+	int result = 0;
+	struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
+	struct strbuf err = STRBUF_INIT;
+	const char *dangling_msg = dry_run
+		? _("   (%s will become dangling)")
+		: _("   (%s has become dangling)");
+
+	if (!dry_run) {
+		if (transaction) {
+			for (ref = stale_refs; ref; ref = ref->next) {
+				result = ref_transaction_delete(transaction, ref->name, NULL,
+								NULL, 0, "fetch: prune", &err);
+				if (result)
+					goto cleanup;
+			}
+		} else {
+			struct string_list refnames = STRING_LIST_INIT_NODUP;
+
+			for (ref = stale_refs; ref; ref = ref->next)
+				string_list_append(&refnames, ref->name);
+
+			result = refs_delete_refs(get_main_ref_store(the_repository),
+						  "fetch: prune", &refnames,
+						  0);
+			string_list_clear(&refnames, 0);
+		}
+	}
+
+	if (verbosity >= 0) {
+		int summary_width = transport_summary_width(stale_refs);
+
+		for (ref = stale_refs; ref; ref = ref->next) {
+			display_ref_update(display_state, '-', _("[deleted]"), NULL,
+					   _("(none)"), ref->name,
+					   &ref->new_oid, &ref->old_oid,
+					   summary_width);
+			refs_warn_dangling_symref(get_main_ref_store(the_repository),
+						  stderr, dangling_msg, ref->name);
+		}
+	}
+
+cleanup:
+	strbuf_release(&err);
+	free_refs(stale_refs);
+	return result;
+}
+
+static void check_not_current_branch(struct ref *ref_map)
+{
+	const char *path;
+	for (; ref_map; ref_map = ref_map->next)
+		if (ref_map->peer_ref &&
+		    starts_with(ref_map->peer_ref->name, "refs/heads/") &&
+		    (path = branch_checked_out(ref_map->peer_ref->name)))
+			die(_("refusing to fetch into branch '%s' "
+			      "checked out at '%s'"),
+			    ref_map->peer_ref->name, path);
+}
+
+static int truncate_fetch_head(void)
+{
+	const char *filename = git_path_fetch_head(the_repository);
+	FILE *fp = fopen_for_writing(filename);
+
+	if (!fp)
+		return error_errno(_("cannot open '%s'"), filename);
+	fclose(fp);
+	return 0;
+}
+
+static void set_option(struct transport *transport, const char *name, const char *value)
+{
+	int r = transport_set_option(transport, name, value);
+	if (r < 0)
+		die(_("option \"%s\" value \"%s\" is not valid for %s"),
+		    name, value, transport->url);
+	if (r > 0)
+		warning(_("option \"%s\" is ignored for %s"),
+			name, transport->url);
+}
+
+
+static int add_oid(const char *refname UNUSED,
+		   const char *referent UNUSED,
+		   const struct object_id *oid,
+		   int flags UNUSED, void *cb_data)
+{
+	struct oid_array *oids = cb_data;
+
+	oid_array_append(oids, oid);
+	return 0;
+}
+
+static void add_negotiation_tips(struct git_transport_options *smart_options)
+{
+	struct oid_array *oids = xcalloc(1, sizeof(*oids));
+	int i;
+
+	for (i = 0; i < negotiation_tip.nr; i++) {
+		const char *s = negotiation_tip.items[i].string;
+		int old_nr;
+		if (!has_glob_specials(s)) {
+			struct object_id oid;
+			if (repo_get_oid(the_repository, s, &oid))
+				die(_("%s is not a valid object"), s);
+			if (!has_object(the_repository, &oid, 0))
+				die(_("the object %s does not exist"), s);
+			oid_array_append(oids, &oid);
+			continue;
+		}
+		old_nr = oids->nr;
+		refs_for_each_glob_ref(get_main_ref_store(the_repository),
+				       add_oid, s, oids);
+		if (old_nr == oids->nr)
+			warning("ignoring --negotiation-tip=%s because it does not match any refs",
+				s);
+	}
+	smart_options->negotiation_tips = oids;
+}
+
+static struct transport *prepare_transport(struct remote *remote, int deepen)
+{
+	struct transport *transport;
+
+	transport = transport_get(remote, NULL);
+	transport_set_verbosity(transport, verbosity, progress);
+	transport->family = family;
+	if (upload_pack)
+		set_option(transport, TRANS_OPT_UPLOADPACK, upload_pack);
+	if (keep)
+		set_option(transport, TRANS_OPT_KEEP, "yes");
+	if (depth)
+		set_option(transport, TRANS_OPT_DEPTH, depth);
+	if (deepen && deepen_since)
+		set_option(transport, TRANS_OPT_DEEPEN_SINCE, deepen_since);
+	if (deepen && deepen_not.nr)
+		set_option(transport, TRANS_OPT_DEEPEN_NOT,
+			   (const char *)&deepen_not);
+	if (deepen_relative)
+		set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, "yes");
+	if (update_shallow)
+		set_option(transport, TRANS_OPT_UPDATE_SHALLOW, "yes");
+	if (refetch)
+		set_option(transport, TRANS_OPT_REFETCH, "yes");
+	if (filter_options.choice) {
+		const char *spec =
+			expand_list_objects_filter_spec(&filter_options);
+		set_option(transport, TRANS_OPT_LIST_OBJECTS_FILTER, spec);
+		set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
+	}
+	if (negotiation_tip.nr) {
+		if (transport->smart_options)
+			add_negotiation_tips(transport->smart_options);
+		else
+			warning("ignoring --negotiation-tip because the protocol does not support it");
+	}
+	return transport;
+}
+
+static int backfill_tags(struct display_state *display_state,
+			 struct transport *transport,
+			 struct ref_transaction *transaction,
+			 struct ref *ref_map,
+			 struct fetch_head *fetch_head,
+			 const struct fetch_config *config)
+{
+	int retcode, cannot_reuse;
+
+	/*
+	 * Once we have set TRANS_OPT_DEEPEN_SINCE, we can't unset it
+	 * when remote helper is used (setting it to an empty string
+	 * is not unsetting). We could extend the remote helper
+	 * protocol for that, but for now, just force a new connection
+	 * without deepen-since. Similar story for deepen-not.
+	 */
+	cannot_reuse = transport->cannot_reuse ||
+		deepen_since || deepen_not.nr;
+	if (cannot_reuse) {
+		gsecondary = prepare_transport(transport->remote, 0);
+		transport = gsecondary;
+	}
+
+	transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, NULL);
+	transport_set_option(transport, TRANS_OPT_DEPTH, "0");
+	transport_set_option(transport, TRANS_OPT_DEEPEN_RELATIVE, NULL);
+	retcode = fetch_and_consume_refs(display_state, transport, transaction, ref_map,
+					 fetch_head, config);
+
+	if (gsecondary) {
+		transport_disconnect(gsecondary);
+		gsecondary = NULL;
+	}
+
+	return retcode;
+}
+
+static const char *strip_refshead(const char *name){
+	skip_prefix(name, "refs/heads/", &name);
+	return name;
+}
+
+static void set_head_advice_msg(const char *remote, const char *head_name)
+{
+	const char message_advice_set_head[] =
+	N_("Run 'git remote set-head %s %s' to follow the change, or set\n"
+	   "'remote.%s.followRemoteHEAD' configuration option to a different value\n"
+	   "if you do not want to see this message. Specifically running\n"
+	   "'git config set remote.%s.followRemoteHEAD warn-if-not-branch-%s'\n"
+	   "will disable the warning until the remote changes HEAD to something else.");
+
+	advise_if_enabled(ADVICE_FETCH_SET_HEAD_WARN, _(message_advice_set_head),
+			remote, head_name, remote, remote, head_name);
+}
+
+static void report_set_head(const char *remote, const char *head_name,
+			struct strbuf *buf_prev, int updateres) {
+	struct strbuf buf_prefix = STRBUF_INIT;
+	const char *prev_head = NULL;
+
+	strbuf_addf(&buf_prefix, "refs/remotes/%s/", remote);
+	skip_prefix(buf_prev->buf, buf_prefix.buf, &prev_head);
+
+	if (prev_head && strcmp(prev_head, head_name)) {
+		printf("'HEAD' at '%s' is '%s', but we have '%s' locally.\n",
+			remote, head_name, prev_head);
+		set_head_advice_msg(remote, head_name);
+	}
+	else if (updateres && buf_prev->len) {
+		printf("'HEAD' at '%s' is '%s', "
+			"but we have a detached HEAD pointing to '%s' locally.\n",
+			remote, head_name, buf_prev->buf);
+		set_head_advice_msg(remote, head_name);
+	}
+	strbuf_release(&buf_prefix);
+}
+
+static int set_head(const struct ref *remote_refs, int follow_remote_head,
+		const char *no_warn_branch)
+{
+	int result = 0, create_only, is_bare, was_detached;
+	struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
+		      b_local_head = STRBUF_INIT;
+	const char *remote = gtransport->remote->name;
+	char *head_name = NULL;
+	struct ref *ref, *matches;
+	struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
+	struct refspec_item refspec = {
+		.force = 0,
+		.pattern = 1,
+		.src = (char *) "refs/heads/*",
+		.dst = (char *) "refs/heads/*",
+	};
+	struct string_list heads = STRING_LIST_INIT_DUP;
+	struct ref_store *refs = get_main_ref_store(the_repository);
+
+	get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
+	matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
+				    fetch_map, 1);
+	for (ref = matches; ref; ref = ref->next) {
+		string_list_append(&heads, strip_refshead(ref->name));
+	}
+
+	if (follow_remote_head == FOLLOW_REMOTE_NEVER)
+		goto cleanup;
+
+	if (!heads.nr)
+		result = 1;
+	else if (heads.nr > 1)
+		result = 1;
+	else
+		head_name = xstrdup(heads.items[0].string);
+
+	if (!head_name)
+		goto cleanup;
+	is_bare = is_bare_repository();
+	create_only = follow_remote_head == FOLLOW_REMOTE_ALWAYS ? 0 : !is_bare;
+	if (is_bare) {
+		strbuf_addstr(&b_head, "HEAD");
+		strbuf_addf(&b_remote_head, "refs/heads/%s", head_name);
+	} else {
+		strbuf_addf(&b_head, "refs/remotes/%s/HEAD", remote);
+		strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", remote, head_name);
+	}
+		/* make sure it's valid */
+	if (!is_bare && !refs_ref_exists(refs, b_remote_head.buf)) {
+		result = 1;
+		goto cleanup;
+	}
+	was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
+					"fetch", &b_local_head, create_only);
+	if (was_detached == -1) {
+		result = 1;
+		goto cleanup;
+	}
+	if (verbosity >= 0 &&
+		follow_remote_head == FOLLOW_REMOTE_WARN &&
+		(!no_warn_branch || strcmp(no_warn_branch, head_name)))
+		report_set_head(remote, head_name, &b_local_head, was_detached);
+
+cleanup:
+	free(head_name);
+	free_refs(fetch_map);
+	free_refs(matches);
+	string_list_clear(&heads, 0);
+	strbuf_release(&b_head);
+	strbuf_release(&b_local_head);
+	strbuf_release(&b_remote_head);
+	return result;
+}
+
+static int uses_remote_tracking(struct transport *transport, struct refspec *rs)
+{
+	if (!remote_is_configured(transport->remote, 0))
+		return 0;
+
+	if (!rs->nr)
+		rs = &transport->remote->fetch;
+
+	for (int i = 0; i < rs->nr; i++)
+		if (rs->items[i].dst)
+			return 1;
+
+	return 0;
+}
+
+static int do_fetch(struct transport *transport,
+		    struct refspec *rs,
+		    const struct fetch_config *config)
+{
+	struct ref_transaction *transaction = NULL;
+	struct ref *ref_map = NULL;
+	struct display_state display_state = { 0 };
+	int autotags = (transport->remote->fetch_tags == 1);
+	int retcode = 0;
+	const struct ref *remote_refs;
+	struct transport_ls_refs_options transport_ls_refs_options =
+		TRANSPORT_LS_REFS_OPTIONS_INIT;
+	int must_list_refs = 1;
+	struct fetch_head fetch_head = { 0 };
+	struct strbuf err = STRBUF_INIT;
+
+	if (tags == TAGS_DEFAULT) {
+		if (transport->remote->fetch_tags == 2)
+			tags = TAGS_SET;
+		if (transport->remote->fetch_tags == -1)
+			tags = TAGS_UNSET;
+	}
+
+	/* if not appending, truncate FETCH_HEAD */
+	if (!append && write_fetch_head) {
+		retcode = truncate_fetch_head();
+		if (retcode)
+			goto cleanup;
+	}
+
+	if (rs->nr) {
+		int i;
+
+		refspec_ref_prefixes(rs, &transport_ls_refs_options.ref_prefixes);
+
+		/*
+		 * We can avoid listing refs if all of them are exact
+		 * OIDs
+		 */
+		must_list_refs = 0;
+		for (i = 0; i < rs->nr; i++) {
+			if (!rs->items[i].exact_sha1) {
+				must_list_refs = 1;
+				break;
+			}
+		}
+	} else {
+		struct branch *branch = branch_get(NULL);
+
+		if (transport->remote->fetch.nr)
+			refspec_ref_prefixes(&transport->remote->fetch,
+					     &transport_ls_refs_options.ref_prefixes);
+		if (branch_has_merge_config(branch) &&
+		    !strcmp(branch->remote_name, transport->remote->name)) {
+			int i;
+			for (i = 0; i < branch->merge_nr; i++) {
+				strvec_push(&transport_ls_refs_options.ref_prefixes,
+					    branch->merge[i]->src);
+			}
+		}
+	}
+
+	if (tags == TAGS_SET || tags == TAGS_DEFAULT) {
+		must_list_refs = 1;
+		if (transport_ls_refs_options.ref_prefixes.nr)
+			strvec_push(&transport_ls_refs_options.ref_prefixes,
+				    "refs/tags/");
+	}
+
+	if (uses_remote_tracking(transport, rs)) {
+		must_list_refs = 1;
+		strvec_push(&transport_ls_refs_options.ref_prefixes, "HEAD");
+	}
+
+	if (must_list_refs) {
+		trace2_region_enter("fetch", "remote_refs", the_repository);
+		remote_refs = transport_get_remote_refs(transport,
+							&transport_ls_refs_options);
+		trace2_region_leave("fetch", "remote_refs", the_repository);
+	} else
+		remote_refs = NULL;
+
+	transport_ls_refs_options_release(&transport_ls_refs_options);
+
+	ref_map = get_ref_map(transport->remote, remote_refs, rs,
+			      tags, &autotags);
+	if (!update_head_ok)
+		check_not_current_branch(ref_map);
+
+	retcode = open_fetch_head(&fetch_head);
+	if (retcode)
+		goto cleanup;
+
+	display_state_init(&display_state, ref_map, transport->url,
+			   config->display_format);
+
+	if (atomic_fetch) {
+		transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+							  0, &err);
+		if (!transaction) {
+			retcode = -1;
+			goto cleanup;
+		}
+	}
+
+	if (tags == TAGS_DEFAULT && autotags)
+		transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
+	if (prune) {
+		/*
+		 * We only prune based on refspecs specified
+		 * explicitly (via command line or configuration); we
+		 * don't care whether --tags was specified.
+		 */
+		if (rs->nr) {
+			retcode = prune_refs(&display_state, rs, transaction, ref_map);
+		} else {
+			retcode = prune_refs(&display_state, &transport->remote->fetch,
+					     transaction, ref_map);
+		}
+		if (retcode != 0)
+			retcode = 1;
+	}
+
+	if (fetch_and_consume_refs(&display_state, transport, transaction, ref_map,
+				   &fetch_head, config)) {
+		retcode = 1;
+		goto cleanup;
+	}
+
+	/*
+	 * If neither --no-tags nor --tags was specified, do automated tag
+	 * following.
+	 */
+	if (tags == TAGS_DEFAULT && autotags) {
+		struct ref *tags_ref_map = NULL, **tail = &tags_ref_map;
+
+		find_non_local_tags(remote_refs, transaction, &tags_ref_map, &tail);
+		if (tags_ref_map) {
+			/*
+			 * If backfilling of tags fails then we want to tell
+			 * the user so, but we have to continue regardless to
+			 * populate upstream information of the references we
+			 * have already fetched above. The exception though is
+			 * when `--atomic` is passed: in that case we'll abort
+			 * the transaction and don't commit anything.
+			 */
+			if (backfill_tags(&display_state, transport, transaction, tags_ref_map,
+					  &fetch_head, config))
+				retcode = 1;
+		}
+
+		free_refs(tags_ref_map);
+	}
+
+	if (transaction) {
+		if (retcode)
+			goto cleanup;
+
+		retcode = ref_transaction_commit(transaction, &err);
+		if (retcode)
+			goto cleanup;
+	}
+
+	commit_fetch_head(&fetch_head);
+
+	if (set_upstream) {
+		struct branch *branch = branch_get("HEAD");
+		struct ref *rm;
+		struct ref *source_ref = NULL;
+
+		/*
+		 * We're setting the upstream configuration for the
+		 * current branch. The relevant upstream is the
+		 * fetched branch that is meant to be merged with the
+		 * current one, i.e. the one fetched to FETCH_HEAD.
+		 *
+		 * When there are several such branches, consider the
+		 * request ambiguous and err on the safe side by doing
+		 * nothing and just emit a warning.
+		 */
+		for (rm = ref_map; rm; rm = rm->next) {
+			if (!rm->peer_ref) {
+				if (source_ref) {
+					warning(_("multiple branches detected, incompatible with --set-upstream"));
+					goto cleanup;
+				} else {
+					source_ref = rm;
+				}
+			}
+		}
+		if (source_ref) {
+			if (!branch) {
+				const char *shortname = source_ref->name;
+				skip_prefix(shortname, "refs/heads/", &shortname);
+
+				warning(_("could not set upstream of HEAD to '%s' from '%s' when "
+					  "it does not point to any branch."),
+					shortname, transport->remote->name);
+				goto cleanup;
+			}
+
+			if (!strcmp(source_ref->name, "HEAD") ||
+			    starts_with(source_ref->name, "refs/heads/"))
+				install_branch_config(0,
+						      branch->name,
+						      transport->remote->name,
+						      source_ref->name);
+			else if (starts_with(source_ref->name, "refs/remotes/"))
+				warning(_("not setting upstream for a remote remote-tracking branch"));
+			else if (starts_with(source_ref->name, "refs/tags/"))
+				warning(_("not setting upstream for a remote tag"));
+			else
+				warning(_("unknown branch type"));
+		} else {
+			warning(_("no source branch found;\n"
+				  "you need to specify exactly one branch with the --set-upstream option"));
+		}
+	}
+	if (set_head(remote_refs, transport->remote->follow_remote_head,
+		transport->remote->no_warn_branch))
+		;
+		/*
+		 * Way too many cases where this can go wrong
+		 * so let's just fail silently for now.
+		 */
+
+cleanup:
+	if (retcode) {
+		if (err.len) {
+			error("%s", err.buf);
+			strbuf_reset(&err);
+		}
+		if (transaction && ref_transaction_abort(transaction, &err) &&
+		    err.len)
+			error("%s", err.buf);
+		transaction = NULL;
+	}
+
+	if (transaction)
+		ref_transaction_free(transaction);
+	display_state_release(&display_state);
+	close_fetch_head(&fetch_head);
+	strbuf_release(&err);
+	free_refs(ref_map);
+	return retcode;
+}
+
+static int get_one_remote_for_fetch(struct remote *remote, void *priv)
+{
+	struct string_list *list = priv;
+	if (!remote->skip_default_update)
+		string_list_append(list, remote->name);
+	return 0;
+}
+
+struct remote_group_data {
+	const char *name;
+	struct string_list *list;
+};
+
+static int get_remote_group(const char *key, const char *value,
+			    const struct config_context *ctx UNUSED,
+			    void *priv)
+{
+	struct remote_group_data *g = priv;
+
+	if (skip_prefix(key, "remotes.", &key) && !strcmp(key, g->name)) {
+		/* split list by white space */
+		while (*value) {
+			size_t wordlen = strcspn(value, " \t\n");
+
+			if (wordlen >= 1)
+				string_list_append_nodup(g->list,
+						   xstrndup(value, wordlen));
+			value += wordlen + (value[wordlen] != '\0');
+		}
+	}
+
+	return 0;
+}
+
+static int add_remote_or_group(const char *name, struct string_list *list)
+{
+	int prev_nr = list->nr;
+	struct remote_group_data g;
+	g.name = name; g.list = list;
+
+	git_config(get_remote_group, &g);
+	if (list->nr == prev_nr) {
+		struct remote *remote = remote_get(name);
+		if (!remote_is_configured(remote, 0))
+			return 0;
+		string_list_append(list, remote->name);
+	}
+	return 1;
+}
+
+static void add_options_to_argv(struct strvec *argv,
+				const struct fetch_config *config)
+{
+	if (dry_run)
+		strvec_push(argv, "--dry-run");
+	if (prune != -1)
+		strvec_push(argv, prune ? "--prune" : "--no-prune");
+	if (prune_tags != -1)
+		strvec_push(argv, prune_tags ? "--prune-tags" : "--no-prune-tags");
+	if (update_head_ok)
+		strvec_push(argv, "--update-head-ok");
+	if (force)
+		strvec_push(argv, "--force");
+	if (keep)
+		strvec_push(argv, "--keep");
+	if (config->recurse_submodules == RECURSE_SUBMODULES_ON)
+		strvec_push(argv, "--recurse-submodules");
+	else if (config->recurse_submodules == RECURSE_SUBMODULES_OFF)
+		strvec_push(argv, "--no-recurse-submodules");
+	else if (config->recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
+		strvec_push(argv, "--recurse-submodules=on-demand");
+	if (tags == TAGS_SET)
+		strvec_push(argv, "--tags");
+	else if (tags == TAGS_UNSET)
+		strvec_push(argv, "--no-tags");
+	if (verbosity >= 2)
+		strvec_push(argv, "-v");
+	if (verbosity >= 1)
+		strvec_push(argv, "-v");
+	else if (verbosity < 0)
+		strvec_push(argv, "-q");
+	if (family == TRANSPORT_FAMILY_IPV4)
+		strvec_push(argv, "--ipv4");
+	else if (family == TRANSPORT_FAMILY_IPV6)
+		strvec_push(argv, "--ipv6");
+	if (!write_fetch_head)
+		strvec_push(argv, "--no-write-fetch-head");
+	if (config->display_format == DISPLAY_FORMAT_PORCELAIN)
+		strvec_pushf(argv, "--porcelain");
+}
+
+/* Fetch multiple remotes in parallel */
+
+struct parallel_fetch_state {
+	const char **argv;
+	struct string_list *remotes;
+	int next, result;
+	const struct fetch_config *config;
+};
+
+static int fetch_next_remote(struct child_process *cp,
+			     struct strbuf *out UNUSED,
+			     void *cb, void **task_cb)
+{
+	struct parallel_fetch_state *state = cb;
+	char *remote;
+
+	if (state->next < 0 || state->next >= state->remotes->nr)
+		return 0;
+
+	remote = state->remotes->items[state->next++].string;
+	*task_cb = remote;
+
+	strvec_pushv(&cp->args, state->argv);
+	strvec_push(&cp->args, remote);
+	cp->git_cmd = 1;
+
+	if (verbosity >= 0 && state->config->display_format != DISPLAY_FORMAT_PORCELAIN)
+		printf(_("Fetching %s\n"), remote);
+
+	return 1;
+}
+
+static int fetch_failed_to_start(struct strbuf *out UNUSED,
+				 void *cb, void *task_cb)
+{
+	struct parallel_fetch_state *state = cb;
+	const char *remote = task_cb;
+
+	state->result = error(_("could not fetch %s"), remote);
+
+	return 0;
+}
+
+static int fetch_finished(int result, struct strbuf *out,
+			  void *cb, void *task_cb)
+{
+	struct parallel_fetch_state *state = cb;
+	const char *remote = task_cb;
+
+	if (result) {
+		strbuf_addf(out, _("could not fetch '%s' (exit code: %d)\n"),
+			    remote, result);
+		state->result = -1;
+	}
+
+	return 0;
+}
+
+static int fetch_multiple(struct string_list *list, int max_children,
+			  const struct fetch_config *config)
+{
+	int i, result = 0;
+	struct strvec argv = STRVEC_INIT;
+
+	if (!append && write_fetch_head) {
+		int errcode = truncate_fetch_head();
+		if (errcode)
+			return errcode;
+	}
+
+	/*
+	 * Cancel out the fetch.bundleURI config when running subprocesses,
+	 * to avoid fetching from the same bundle list multiple times.
+	 */
+	strvec_pushl(&argv, "-c", "fetch.bundleURI=",
+		     "fetch", "--append", "--no-auto-gc",
+		     "--no-write-commit-graph", NULL);
+	for (i = 0; i < server_options.nr; i++)
+		strvec_pushf(&argv, "--server-option=%s", server_options.items[i].string);
+	add_options_to_argv(&argv, config);
+
+	if (max_children != 1 && list->nr != 1) {
+		struct parallel_fetch_state state = { argv.v, list, 0, 0, config };
+		const struct run_process_parallel_opts opts = {
+			.tr2_category = "fetch",
+			.tr2_label = "parallel/fetch",
+
+			.processes = max_children,
+
+			.get_next_task = &fetch_next_remote,
+			.start_failure = &fetch_failed_to_start,
+			.task_finished = &fetch_finished,
+			.data = &state,
+		};
+
+		strvec_push(&argv, "--end-of-options");
+
+		run_processes_parallel(&opts);
+		result = state.result;
+	} else
+		for (i = 0; i < list->nr; i++) {
+			const char *name = list->items[i].string;
+			struct child_process cmd = CHILD_PROCESS_INIT;
+
+			strvec_pushv(&cmd.args, argv.v);
+			strvec_push(&cmd.args, name);
+			if (verbosity >= 0 && config->display_format != DISPLAY_FORMAT_PORCELAIN)
+				printf(_("Fetching %s\n"), name);
+			cmd.git_cmd = 1;
+			if (run_command(&cmd)) {
+				error(_("could not fetch %s"), name);
+				result = 1;
+			}
+		}
+
+	strvec_clear(&argv);
+	return !!result;
+}
+
+/*
+ * Fetching from the promisor remote should use the given filter-spec
+ * or inherit the default filter-spec from the config.
+ */
+static inline void fetch_one_setup_partial(struct remote *remote)
+{
+	/*
+	 * Explicit --no-filter argument overrides everything, regardless
+	 * of any prior partial clones and fetches.
+	 */
+	if (filter_options.no_filter)
+		return;
+
+	/*
+	 * If no prior partial clone/fetch and the current fetch DID NOT
+	 * request a partial-fetch, do a normal fetch.
+	 */
+	if (!repo_has_promisor_remote(the_repository) && !filter_options.choice)
+		return;
+
+	/*
+	 * If this is a partial-fetch request, we enable partial on
+	 * this repo if not already enabled and remember the given
+	 * filter-spec as the default for subsequent fetches to this
+	 * remote if there is currently no default filter-spec.
+	 */
+	if (filter_options.choice) {
+		partial_clone_register(remote->name, &filter_options);
+		return;
+	}
+
+	/*
+	 * Do a partial-fetch from the promisor remote using either the
+	 * explicitly given filter-spec or inherit the filter-spec from
+	 * the config.
+	 */
+	if (!filter_options.choice)
+		partial_clone_get_default_filter_spec(&filter_options, remote->name);
+	return;
+}
+
+static int fetch_one(struct remote *remote, int argc, const char **argv,
+		     int prune_tags_ok, int use_stdin_refspecs,
+		     const struct fetch_config *config)
+{
+	struct refspec rs = REFSPEC_INIT_FETCH;
+	int i;
+	int exit_code;
+	int maybe_prune_tags;
+	int remote_via_config = remote_is_configured(remote, 0);
+
+	if (!remote)
+		die(_("no remote repository specified; please specify either a URL or a\n"
+		      "remote name from which new revisions should be fetched"));
+
+	gtransport = prepare_transport(remote, 1);
+
+	if (prune < 0) {
+		/* no command line request */
+		if (0 <= remote->prune)
+			prune = remote->prune;
+		else if (0 <= config->prune)
+			prune = config->prune;
+		else
+			prune = PRUNE_BY_DEFAULT;
+	}
+
+	if (prune_tags < 0) {
+		/* no command line request */
+		if (0 <= remote->prune_tags)
+			prune_tags = remote->prune_tags;
+		else if (0 <= config->prune_tags)
+			prune_tags = config->prune_tags;
+		else
+			prune_tags = PRUNE_TAGS_BY_DEFAULT;
+	}
+
+	maybe_prune_tags = prune_tags_ok && prune_tags;
+	if (maybe_prune_tags && remote_via_config)
+		refspec_append(&remote->fetch, TAG_REFSPEC);
+
+	if (maybe_prune_tags && (argc || !remote_via_config))
+		refspec_append(&rs, TAG_REFSPEC);
+
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argv[i], "tag")) {
+			i++;
+			if (i >= argc)
+				die(_("you need to specify a tag name"));
+
+			refspec_appendf(&rs, "refs/tags/%s:refs/tags/%s",
+					argv[i], argv[i]);
+		} else {
+			refspec_append(&rs, argv[i]);
+		}
+	}
+
+	if (use_stdin_refspecs) {
+		struct strbuf line = STRBUF_INIT;
+		while (strbuf_getline_lf(&line, stdin) != EOF)
+			refspec_append(&rs, line.buf);
+		strbuf_release(&line);
+	}
+
+	if (server_options.nr)
+		gtransport->server_options = &server_options;
+
+	sigchain_push_common(unlock_pack_on_signal);
+	atexit(unlock_pack_atexit);
+	sigchain_push(SIGPIPE, SIG_IGN);
+	exit_code = do_fetch(gtransport, &rs, config);
+	sigchain_pop(SIGPIPE);
+	refspec_clear(&rs);
+	transport_disconnect(gtransport);
+	gtransport = NULL;
+	return exit_code;
+}
+
+int cmd_fetch(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	struct fetch_config config = {
+		.display_format = DISPLAY_FORMAT_FULL,
+		.prune = -1,
+		.prune_tags = -1,
+		.show_forced_updates = 1,
+		.recurse_submodules = RECURSE_SUBMODULES_DEFAULT,
+		.parallel = 1,
+		.submodule_fetch_jobs = -1,
+	};
+	const char *submodule_prefix = "";
+	const char *bundle_uri;
+	struct string_list list = STRING_LIST_INIT_DUP;
+	struct remote *remote = NULL;
+	int all = -1, multiple = 0;
+	int result = 0;
+	int prune_tags_ok = 1;
+	int enable_auto_gc = 1;
+	int unshallow = 0;
+	int max_jobs = -1;
+	int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
+	int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
+	int fetch_write_commit_graph = -1;
+	int stdin_refspecs = 0;
+	int negotiate_only = 0;
+	int porcelain = 0;
+	int i;
+
+	struct option builtin_fetch_options[] = {
+		OPT__VERBOSITY(&verbosity),
+		OPT_BOOL(0, "all", &all,
+			 N_("fetch from all remotes")),
+		OPT_BOOL(0, "set-upstream", &set_upstream,
+			 N_("set upstream for git pull/fetch")),
+		OPT_BOOL('a', "append", &append,
+			 N_("append to .git/FETCH_HEAD instead of overwriting")),
+		OPT_BOOL(0, "atomic", &atomic_fetch,
+			 N_("use atomic transaction to update references")),
+		OPT_STRING(0, "upload-pack", &upload_pack, N_("path"),
+			   N_("path to upload pack on remote end")),
+		OPT__FORCE(&force, N_("force overwrite of local reference"), 0),
+		OPT_BOOL('m', "multiple", &multiple,
+			 N_("fetch from multiple remotes")),
+		OPT_SET_INT('t', "tags", &tags,
+			    N_("fetch all tags and associated objects"), TAGS_SET),
+		OPT_SET_INT('n', NULL, &tags,
+			    N_("do not fetch all tags (--no-tags)"), TAGS_UNSET),
+		OPT_INTEGER('j', "jobs", &max_jobs,
+			    N_("number of submodules fetched in parallel")),
+		OPT_BOOL(0, "prefetch", &prefetch,
+			 N_("modify the refspec to place all refs within refs/prefetch/")),
+		OPT_BOOL('p', "prune", &prune,
+			 N_("prune remote-tracking branches no longer on remote")),
+		OPT_BOOL('P', "prune-tags", &prune_tags,
+			 N_("prune local tags no longer on remote and clobber changed tags")),
+		OPT_CALLBACK_F(0, "recurse-submodules", &recurse_submodules_cli, N_("on-demand"),
+			    N_("control recursive fetching of submodules"),
+			    PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
+		OPT_BOOL(0, "dry-run", &dry_run,
+			 N_("dry run")),
+		OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+		OPT_BOOL(0, "write-fetch-head", &write_fetch_head,
+			 N_("write fetched references to the FETCH_HEAD file")),
+		OPT_BOOL('k', "keep", &keep, N_("keep downloaded pack")),
+		OPT_BOOL('u', "update-head-ok", &update_head_ok,
+			    N_("allow updating of HEAD ref")),
+		OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+		OPT_STRING(0, "depth", &depth, N_("depth"),
+			   N_("deepen history of shallow clone")),
+		OPT_STRING(0, "shallow-since", &deepen_since, N_("time"),
+			   N_("deepen history of shallow repository based on time")),
+		OPT_STRING_LIST(0, "shallow-exclude", &deepen_not, N_("ref"),
+				N_("deepen history of shallow clone, excluding ref")),
+		OPT_INTEGER(0, "deepen", &deepen_relative,
+			    N_("deepen history of shallow clone")),
+		OPT_SET_INT_F(0, "unshallow", &unshallow,
+			      N_("convert to a complete repository"),
+			      1, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "refetch", &refetch,
+			      N_("re-fetch without negotiating common commits"),
+			      1, PARSE_OPT_NONEG),
+		{ OPTION_STRING, 0, "submodule-prefix", &submodule_prefix, N_("dir"),
+			   N_("prepend this to submodule path output"), PARSE_OPT_HIDDEN },
+		OPT_CALLBACK_F(0, "recurse-submodules-default",
+			   &recurse_submodules_default, N_("on-demand"),
+			   N_("default for recursive fetching of submodules "
+			      "(lower priority than config files)"),
+			   PARSE_OPT_HIDDEN, option_fetch_parse_recurse_submodules),
+		OPT_BOOL(0, "update-shallow", &update_shallow,
+			 N_("accept refs that update .git/shallow")),
+		OPT_CALLBACK_F(0, "refmap", &refmap, N_("refmap"),
+			       N_("specify fetch refmap"), PARSE_OPT_NONEG, parse_refmap_arg),
+		OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
+		OPT_IPVERSION(&family),
+		OPT_STRING_LIST(0, "negotiation-tip", &negotiation_tip, N_("revision"),
+				N_("report that we have only objects reachable from this object")),
+		OPT_BOOL(0, "negotiate-only", &negotiate_only,
+			 N_("do not fetch a packfile; instead, print ancestors of negotiation tips")),
+		OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+		OPT_BOOL(0, "auto-maintenance", &enable_auto_gc,
+			 N_("run 'maintenance --auto' after fetching")),
+		OPT_BOOL(0, "auto-gc", &enable_auto_gc,
+			 N_("run 'maintenance --auto' after fetching")),
+		OPT_BOOL(0, "show-forced-updates", &config.show_forced_updates,
+			 N_("check for forced-updates on all updated branches")),
+		OPT_BOOL(0, "write-commit-graph", &fetch_write_commit_graph,
+			 N_("write the commit-graph after fetching")),
+		OPT_BOOL(0, "stdin", &stdin_refspecs,
+			 N_("accept refspecs from stdin")),
+		OPT_END()
+	};
+
+	packet_trace_identity("fetch");
+
+	/* Record the command line for the reflog */
+	strbuf_addstr(&default_rla, "fetch");
+	for (i = 1; i < argc; i++) {
+		/* This handles non-URLs gracefully */
+		char *anon = transport_anonymize_url(argv[i]);
+
+		strbuf_addf(&default_rla, " %s", anon);
+		free(anon);
+	}
+
+	git_config(git_fetch_config, &config);
+	if (the_repository->gitdir) {
+		prepare_repo_settings(the_repository);
+		the_repository->settings.command_requires_full_index = 0;
+	}
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_fetch_options, builtin_fetch_usage, 0);
+
+	if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
+		config.recurse_submodules = recurse_submodules_cli;
+
+	if (negotiate_only) {
+		switch (recurse_submodules_cli) {
+		case RECURSE_SUBMODULES_OFF:
+		case RECURSE_SUBMODULES_DEFAULT:
+			/*
+			 * --negotiate-only should never recurse into
+			 * submodules. Skip it by setting recurse_submodules to
+			 * RECURSE_SUBMODULES_OFF.
+			 */
+			config.recurse_submodules = RECURSE_SUBMODULES_OFF;
+			break;
+
+		default:
+			die(_("options '%s' and '%s' cannot be used together"),
+			    "--negotiate-only", "--recurse-submodules");
+		}
+	}
+
+	if (config.recurse_submodules != RECURSE_SUBMODULES_OFF) {
+		int *sfjc = config.submodule_fetch_jobs == -1
+			    ? &config.submodule_fetch_jobs : NULL;
+		int *rs = config.recurse_submodules == RECURSE_SUBMODULES_DEFAULT
+			  ? &config.recurse_submodules : NULL;
+
+		fetch_config_from_gitmodules(sfjc, rs);
+	}
+
+
+	if (porcelain) {
+		switch (recurse_submodules_cli) {
+		case RECURSE_SUBMODULES_OFF:
+		case RECURSE_SUBMODULES_DEFAULT:
+			/*
+			 * Reference updates in submodules would be ambiguous
+			 * in porcelain mode, so we reject this combination.
+			 */
+			config.recurse_submodules = RECURSE_SUBMODULES_OFF;
+			break;
+
+		default:
+			die(_("options '%s' and '%s' cannot be used together"),
+			    "--porcelain", "--recurse-submodules");
+		}
+
+		config.display_format = DISPLAY_FORMAT_PORCELAIN;
+	}
+
+	if (negotiate_only && !negotiation_tip.nr)
+		die(_("--negotiate-only needs one or more --negotiation-tip=*"));
+
+	if (deepen_relative) {
+		if (deepen_relative < 0)
+			die(_("negative depth in --deepen is not supported"));
+		if (depth)
+			die(_("options '%s' and '%s' cannot be used together"), "--deepen", "--depth");
+		depth = xstrfmt("%d", deepen_relative);
+	}
+	if (unshallow) {
+		if (depth)
+			die(_("options '%s' and '%s' cannot be used together"), "--depth", "--unshallow");
+		else if (!is_repository_shallow(the_repository))
+			die(_("--unshallow on a complete repository does not make sense"));
+		else
+			depth = xstrfmt("%d", INFINITE_DEPTH);
+	}
+
+	/* no need to be strict, transport_set_option() will validate it again */
+	if (depth && atoi(depth) < 1)
+		die(_("depth %s is not a positive number"), depth);
+	if (depth || deepen_since || deepen_not.nr)
+		deepen = 1;
+
+	/* FETCH_HEAD never gets updated in --dry-run mode */
+	if (dry_run)
+		write_fetch_head = 0;
+
+	if (!max_jobs)
+		max_jobs = online_cpus();
+
+	if (!git_config_get_string_tmp("fetch.bundleuri", &bundle_uri) &&
+	    fetch_bundle_uri(the_repository, bundle_uri, NULL))
+		warning(_("failed to fetch bundles from '%s'"), bundle_uri);
+
+	if (all < 0) {
+		/*
+		 * no --[no-]all given;
+		 * only use config option if no remote was explicitly specified
+		 */
+		all = (!argc) ? config.all : 0;
+	}
+
+	if (all) {
+		if (argc == 1)
+			die(_("fetch --all does not take a repository argument"));
+		else if (argc > 1)
+			die(_("fetch --all does not make sense with refspecs"));
+
+		(void) for_each_remote(get_one_remote_for_fetch, &list);
+
+		/* do not do fetch_multiple() of one */
+		if (list.nr == 1)
+			remote = remote_get(list.items[0].string);
+	} else if (argc == 0) {
+		/* No arguments -- use default remote */
+		remote = remote_get(NULL);
+	} else if (multiple) {
+		/* All arguments are assumed to be remotes or groups */
+		for (i = 0; i < argc; i++)
+			if (!add_remote_or_group(argv[i], &list))
+				die(_("no such remote or remote group: %s"),
+				    argv[i]);
+	} else {
+		/* Single remote or group */
+		(void) add_remote_or_group(argv[0], &list);
+		if (list.nr > 1) {
+			/* More than one remote */
+			if (argc > 1)
+				die(_("fetching a group and specifying refspecs does not make sense"));
+		} else {
+			/* Zero or one remotes */
+			remote = remote_get(argv[0]);
+			prune_tags_ok = (argc == 1);
+			argc--;
+			argv++;
+		}
+	}
+	string_list_remove_duplicates(&list, 0);
+
+	if (negotiate_only) {
+		struct oidset acked_commits = OIDSET_INIT;
+		struct oidset_iter iter;
+		const struct object_id *oid;
+
+		trace2_region_enter("fetch", "negotiate-only", the_repository);
+		if (!remote)
+			die(_("must supply remote when using --negotiate-only"));
+		gtransport = prepare_transport(remote, 1);
+		if (gtransport->smart_options) {
+			gtransport->smart_options->acked_commits = &acked_commits;
+		} else {
+			warning(_("protocol does not support --negotiate-only, exiting"));
+			result = 1;
+			trace2_region_leave("fetch", "negotiate-only", the_repository);
+			goto cleanup;
+		}
+		if (server_options.nr)
+			gtransport->server_options = &server_options;
+		result = transport_fetch_refs(gtransport, NULL);
+
+		oidset_iter_init(&acked_commits, &iter);
+		while ((oid = oidset_iter_next(&iter)))
+			printf("%s\n", oid_to_hex(oid));
+		oidset_clear(&acked_commits);
+		trace2_region_leave("fetch", "negotiate-only", the_repository);
+	} else if (remote) {
+		if (filter_options.choice || repo_has_promisor_remote(the_repository)) {
+			trace2_region_enter("fetch", "setup-partial", the_repository);
+			fetch_one_setup_partial(remote);
+			trace2_region_leave("fetch", "setup-partial", the_repository);
+		}
+		trace2_region_enter("fetch", "fetch-one", the_repository);
+		result = fetch_one(remote, argc, argv, prune_tags_ok, stdin_refspecs,
+				   &config);
+		trace2_region_leave("fetch", "fetch-one", the_repository);
+	} else {
+		int max_children = max_jobs;
+
+		if (filter_options.choice)
+			die(_("--filter can only be used with the remote "
+			      "configured in extensions.partialclone"));
+
+		if (atomic_fetch)
+			die(_("--atomic can only be used when fetching "
+			      "from one remote"));
+
+		if (stdin_refspecs)
+			die(_("--stdin can only be used when fetching "
+			      "from one remote"));
+
+		if (max_children < 0)
+			max_children = config.parallel;
+
+		/* TODO should this also die if we have a previous partial-clone? */
+		trace2_region_enter("fetch", "fetch-multiple", the_repository);
+		result = fetch_multiple(&list, max_children, &config);
+		trace2_region_leave("fetch", "fetch-multiple", the_repository);
+	}
+
+	/*
+	 * This is only needed after fetch_one(), which does not fetch
+	 * submodules by itself.
+	 *
+	 * When we fetch from multiple remotes, fetch_multiple() has
+	 * already updated submodules to grab commits necessary for
+	 * the fetched history from each remote, so there is no need
+	 * to fetch submodules from here.
+	 */
+	if (!result && remote && (config.recurse_submodules != RECURSE_SUBMODULES_OFF)) {
+		struct strvec options = STRVEC_INIT;
+		int max_children = max_jobs;
+
+		if (max_children < 0)
+			max_children = config.submodule_fetch_jobs;
+		if (max_children < 0)
+			max_children = config.parallel;
+
+		add_options_to_argv(&options, &config);
+		trace2_region_enter_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
+		result = fetch_submodules(the_repository,
+					  &options,
+					  submodule_prefix,
+					  config.recurse_submodules,
+					  recurse_submodules_default,
+					  verbosity < 0,
+					  max_children);
+		trace2_region_leave_printf("fetch", "recurse-submodule", the_repository, "%s", submodule_prefix);
+		strvec_clear(&options);
+	}
+
+	/*
+	 * Skip irrelevant tasks because we know objects were not
+	 * fetched.
+	 *
+	 * NEEDSWORK: as a future optimization, we can return early
+	 * whenever objects were not fetched e.g. if we already have all
+	 * of them.
+	 */
+	if (negotiate_only)
+		goto cleanup;
+
+	prepare_repo_settings(the_repository);
+	if (fetch_write_commit_graph > 0 ||
+	    (fetch_write_commit_graph < 0 &&
+	     the_repository->settings.fetch_write_commit_graph)) {
+		int commit_graph_flags = COMMIT_GRAPH_WRITE_SPLIT;
+
+		if (progress)
+			commit_graph_flags |= COMMIT_GRAPH_WRITE_PROGRESS;
+
+		trace2_region_enter("fetch", "write-commit-graph", the_repository);
+		write_commit_graph_reachable(the_repository->objects->odb,
+					     commit_graph_flags,
+					     NULL);
+		trace2_region_leave("fetch", "write-commit-graph", the_repository);
+	}
+
+	if (enable_auto_gc) {
+		if (refetch) {
+			/*
+			 * Hint auto-maintenance strongly to encourage repacking,
+			 * but respect config settings disabling it.
+			 */
+			int opt_val;
+			if (git_config_get_int("gc.autopacklimit", &opt_val))
+				opt_val = -1;
+			if (opt_val != 0)
+				git_config_push_parameter("gc.autoPackLimit=1");
+
+			if (git_config_get_int("maintenance.incremental-repack.auto", &opt_val))
+				opt_val = -1;
+			if (opt_val != 0)
+				git_config_push_parameter("maintenance.incremental-repack.auto=-1");
+		}
+		run_auto_maintenance(verbosity < 0);
+	}
+
+ cleanup:
+	string_list_clear(&list, 0);
+	return result;
+}
diff --git a/builtin/fmt-merge-msg.c b/builtin/fmt-merge-msg.c
new file mode 100644
index 0000000000..189cd1096a
--- /dev/null
+++ b/builtin/fmt-merge-msg.c
@@ -0,0 +1,78 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "fmt-merge-msg.h"
+#include "gettext.h"
+#include "parse-options.h"
+
+static const char * const fmt_merge_msg_usage[] = {
+	N_("git fmt-merge-msg [-m <message>] [--log[=<n>] | --no-log] [--file <file>]"),
+	NULL
+};
+
+int cmd_fmt_merge_msg(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	char *inpath = NULL;
+	const char *message = NULL;
+	char *into_name = NULL;
+	int shortlog_len = -1;
+	struct option options[] = {
+		{ OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
+		  N_("populate log with at most <n> entries from shortlog"),
+		  PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
+		{ OPTION_INTEGER, 0, "summary", &shortlog_len, N_("n"),
+		  N_("alias for --log (deprecated)"),
+		  PARSE_OPT_OPTARG | PARSE_OPT_HIDDEN, NULL,
+		  DEFAULT_MERGE_LOG_LEN },
+		OPT_STRING('m', "message", &message, N_("text"),
+			N_("use <text> as start of message")),
+		OPT_STRING(0, "into-name", &into_name, N_("name"),
+			   N_("use <name> instead of the real target branch")),
+		OPT_FILENAME('F', "file", &inpath, N_("file to read from")),
+		OPT_END()
+	};
+
+	FILE *in = stdin;
+	struct strbuf input = STRBUF_INIT, output = STRBUF_INIT;
+	int ret;
+	struct fmt_merge_msg_opts opts;
+
+	git_config(fmt_merge_msg_config, NULL);
+	argc = parse_options(argc, argv, prefix, options, fmt_merge_msg_usage,
+			     0);
+	if (argc > 0)
+		usage_with_options(fmt_merge_msg_usage, options);
+	if (shortlog_len < 0)
+		shortlog_len = (merge_log_config > 0) ? merge_log_config : 0;
+
+	if (inpath && strcmp(inpath, "-")) {
+		in = fopen(inpath, "r");
+		if (!in)
+			die_errno("cannot open '%s'", inpath);
+	}
+
+	if (strbuf_read(&input, fileno(in), 0) < 0)
+		die_errno("could not read input file");
+
+	if (message)
+		strbuf_addstr(&output, message);
+
+	memset(&opts, 0, sizeof(opts));
+	opts.add_title = !message;
+	opts.credit_people = 1;
+	opts.shortlog_len = shortlog_len;
+	opts.into_name = into_name;
+
+	ret = fmt_merge_msg(&input, &output, &opts);
+	if (ret)
+		return ret;
+	write_in_full(STDOUT_FILENO, output.buf, output.len);
+
+	strbuf_release(&input);
+	strbuf_release(&output);
+	free(inpath);
+	return 0;
+}
diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c
new file mode 100644
index 0000000000..8085ebd8fe
--- /dev/null
+++ b/builtin/for-each-ref.c
@@ -0,0 +1,114 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "commit.h"
+#include "config.h"
+#include "gettext.h"
+#include "object.h"
+#include "parse-options.h"
+#include "ref-filter.h"
+#include "strbuf.h"
+#include "strvec.h"
+
+static char const * const for_each_ref_usage[] = {
+	N_("git for-each-ref [<options>] [<pattern>]"),
+	N_("git for-each-ref [--points-at <object>]"),
+	N_("git for-each-ref [--merged [<commit>]] [--no-merged [<commit>]]"),
+	N_("git for-each-ref [--contains [<commit>]] [--no-contains [<commit>]]"),
+	NULL
+};
+
+int cmd_for_each_ref(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	struct ref_sorting *sorting;
+	struct string_list sorting_options = STRING_LIST_INIT_DUP;
+	int icase = 0, include_root_refs = 0, from_stdin = 0;
+	struct ref_filter filter = REF_FILTER_INIT;
+	struct ref_format format = REF_FORMAT_INIT;
+	unsigned int flags = FILTER_REFS_REGULAR;
+	struct strvec vec = STRVEC_INIT;
+
+	struct option opts[] = {
+		OPT_BIT('s', "shell", &format.quote_style,
+			N_("quote placeholders suitably for shells"), QUOTE_SHELL),
+		OPT_BIT('p', "perl",  &format.quote_style,
+			N_("quote placeholders suitably for perl"), QUOTE_PERL),
+		OPT_BIT(0 , "python", &format.quote_style,
+			N_("quote placeholders suitably for python"), QUOTE_PYTHON),
+		OPT_BIT(0 , "tcl",  &format.quote_style,
+			N_("quote placeholders suitably for Tcl"), QUOTE_TCL),
+		OPT_BOOL(0, "omit-empty",  &format.array_opts.omit_empty,
+			N_("do not output a newline after empty formatted refs")),
+
+		OPT_GROUP(""),
+		OPT_INTEGER( 0 , "count", &format.array_opts.max_count, N_("show only <n> matched refs")),
+		OPT_STRING(  0 , "format", &format.format, N_("format"), N_("format to use for the output")),
+		OPT__COLOR(&format.use_color, N_("respect format colors")),
+		OPT_REF_FILTER_EXCLUDE(&filter),
+		OPT_REF_SORT(&sorting_options),
+		OPT_CALLBACK(0, "points-at", &filter.points_at,
+			     N_("object"), N_("print only refs which points at the given object"),
+			     parse_opt_object_name),
+		OPT_MERGED(&filter, N_("print only refs that are merged")),
+		OPT_NO_MERGED(&filter, N_("print only refs that are not merged")),
+		OPT_CONTAINS(&filter.with_commit, N_("print only refs which contain the commit")),
+		OPT_NO_CONTAINS(&filter.no_commit, N_("print only refs which don't contain the commit")),
+		OPT_BOOL(0, "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+		OPT_BOOL(0, "stdin", &from_stdin, N_("read reference patterns from stdin")),
+		OPT_BOOL(0, "include-root-refs", &include_root_refs, N_("also include HEAD ref and pseudorefs")),
+		OPT_END(),
+	};
+
+	format.format = "%(objectname) %(objecttype)\t%(refname)";
+
+	git_config(git_default_config, NULL);
+
+	/* Set default (refname) sorting */
+	string_list_append(&sorting_options, "refname");
+
+	parse_options(argc, argv, prefix, opts, for_each_ref_usage, 0);
+	if (format.array_opts.max_count < 0) {
+		error("invalid --count argument: `%d'", format.array_opts.max_count);
+		usage_with_options(for_each_ref_usage, opts);
+	}
+	if (HAS_MULTI_BITS(format.quote_style)) {
+		error("more than one quoting style?");
+		usage_with_options(for_each_ref_usage, opts);
+	}
+	if (verify_ref_format(&format))
+		usage_with_options(for_each_ref_usage, opts);
+
+	sorting = ref_sorting_options(&sorting_options);
+	ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
+	filter.ignore_case = icase;
+
+	if (from_stdin) {
+		struct strbuf line = STRBUF_INIT;
+
+		if (argv[0])
+			die(_("unknown arguments supplied with --stdin"));
+
+		while (strbuf_getline(&line, stdin) != EOF)
+			strvec_push(&vec, line.buf);
+
+		strbuf_release(&line);
+
+		/* vec.v is NULL-terminated, just like 'argv'. */
+		filter.name_patterns = vec.v;
+	} else {
+		filter.name_patterns = argv;
+	}
+
+	if (include_root_refs)
+		flags |= FILTER_REFS_ROOT_REFS | FILTER_REFS_DETACHED_HEAD;
+
+	filter.match_as_path = 1;
+	filter_and_format_refs(&filter, flags, sorting, &format);
+
+	ref_filter_clear(&filter);
+	ref_sorting_release(sorting);
+	strvec_clear(&vec);
+	return 0;
+}
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
new file mode 100644
index 0000000000..325a7925f1
--- /dev/null
+++ b/builtin/for-each-repo.c
@@ -0,0 +1,75 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "path.h"
+#include "run-command.h"
+#include "string-list.h"
+
+static const char * const for_each_repo_usage[] = {
+	N_("git for-each-repo --config=<config> [--] <arguments>"),
+	NULL
+};
+
+static int run_command_on_repo(const char *path, int argc, const char ** argv)
+{
+	int i;
+	struct child_process child = CHILD_PROCESS_INIT;
+	char *abspath = interpolate_path(path, 0);
+
+	child.git_cmd = 1;
+	strvec_pushl(&child.args, "-C", abspath, NULL);
+
+	for (i = 0; i < argc; i++)
+		strvec_push(&child.args, argv[i]);
+
+	free(abspath);
+
+	return run_command(&child);
+}
+
+int cmd_for_each_repo(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	static const char *config_key = NULL;
+	int keep_going = 0;
+	int result = 0;
+	const struct string_list *values;
+	int err;
+
+	const struct option options[] = {
+		OPT_STRING(0, "config", &config_key, N_("config"),
+			   N_("config key storing a list of repository paths")),
+		OPT_BOOL(0, "keep-going", &keep_going,
+			 N_("keep going even if command fails in a repository")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, for_each_repo_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (!config_key)
+		die(_("missing --config=<config>"));
+
+	err = repo_config_get_string_multi(the_repository, config_key, &values);
+	if (err < 0)
+		usage_msg_optf(_("got bad config --config=%s"),
+			       for_each_repo_usage, options, config_key);
+	else if (err)
+		return 0;
+
+	for (size_t i = 0; i < values->nr; i++) {
+		int ret = run_command_on_repo(values->items[i].string, argc, argv);
+		if (ret) {
+			if (!keep_going)
+					return ret;
+			result = 1;
+		}
+	}
+
+	return result;
+}
diff --git a/builtin/fsck.c b/builtin/fsck.c
new file mode 100644
index 0000000000..7a4dcb0716
--- /dev/null
+++ b/builtin/fsck.c
@@ -0,0 +1,1119 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
+#include "config.h"
+#include "commit.h"
+#include "tree.h"
+#include "blob.h"
+#include "tag.h"
+#include "refs.h"
+#include "pack.h"
+#include "cache-tree.h"
+#include "fsck.h"
+#include "parse-options.h"
+#include "progress.h"
+#include "streaming.h"
+#include "packfile.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "replace-object.h"
+#include "resolve-undo.h"
+#include "run-command.h"
+#include "sparse-index.h"
+#include "worktree.h"
+#include "pack-revindex.h"
+#include "pack-bitmap.h"
+
+#define REACHABLE 0x0001
+#define SEEN      0x0002
+#define HAS_OBJ   0x0004
+/* This flag is set if something points to this object. */
+#define USED      0x0008
+
+static int show_root;
+static int show_tags;
+static int show_unreachable;
+static int include_reflogs = 1;
+static int check_full = 1;
+static int connectivity_only;
+static int check_strict;
+static int keep_cache_objects;
+static struct fsck_options fsck_walk_options = FSCK_OPTIONS_DEFAULT;
+static struct fsck_options fsck_obj_options = FSCK_OPTIONS_DEFAULT;
+static int errors_found;
+static int write_lost_and_found;
+static int verbose;
+static int show_progress = -1;
+static int show_dangling = 1;
+static int name_objects;
+#define ERROR_OBJECT 01
+#define ERROR_REACHABLE 02
+#define ERROR_PACK 04
+#define ERROR_REFS 010
+#define ERROR_COMMIT_GRAPH 020
+#define ERROR_MULTI_PACK_INDEX 040
+#define ERROR_PACK_REV_INDEX 0100
+#define ERROR_BITMAP 0200
+
+static const char *describe_object(const struct object_id *oid)
+{
+	return fsck_describe_object(&fsck_walk_options, oid);
+}
+
+static const char *printable_type(const struct object_id *oid,
+				  enum object_type type)
+{
+	const char *ret;
+
+	if (type == OBJ_NONE)
+		type = oid_object_info(the_repository, oid, NULL);
+
+	ret = type_name(type);
+	if (!ret)
+		ret = _("unknown");
+
+	return ret;
+}
+
+static int objerror(struct object *obj, const char *err)
+{
+	errors_found |= ERROR_OBJECT;
+	/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
+	fprintf_ln(stderr, _("error in %s %s: %s"),
+		   printable_type(&obj->oid, obj->type),
+		   describe_object(&obj->oid), err);
+	return -1;
+}
+
+static int fsck_objects_error_func(struct fsck_options *o UNUSED,
+				   void *fsck_report,
+				   enum fsck_msg_type msg_type,
+				   enum fsck_msg_id msg_id UNUSED,
+				   const char *message)
+{
+	struct fsck_object_report *report = fsck_report;
+	const struct object_id *oid = report->oid;
+	enum object_type object_type = report->object_type;
+
+	switch (msg_type) {
+	case FSCK_WARN:
+		/* TRANSLATORS: e.g. warning in tree 01bfda: <more explanation> */
+		fprintf_ln(stderr, _("warning in %s %s: %s"),
+			   printable_type(oid, object_type),
+			   describe_object(oid), message);
+		return 0;
+	case FSCK_ERROR:
+		/* TRANSLATORS: e.g. error in tree 01bfda: <more explanation> */
+		fprintf_ln(stderr, _("error in %s %s: %s"),
+			   printable_type(oid, object_type),
+			   describe_object(oid), message);
+		return 1;
+	default:
+		BUG("%d (FSCK_IGNORE?) should never trigger this callback",
+		    msg_type);
+	}
+}
+
+static struct object_array pending;
+
+static int mark_object(struct object *obj, enum object_type type,
+		       void *data, struct fsck_options *options UNUSED)
+{
+	struct object *parent = data;
+
+	/*
+	 * The only case data is NULL or type is OBJ_ANY is when
+	 * mark_object_reachable() calls us.  All the callers of
+	 * that function has non-NULL obj hence ...
+	 */
+	if (!obj) {
+		/* ... these references to parent->fld are safe here */
+		printf_ln(_("broken link from %7s %s"),
+			  printable_type(&parent->oid, parent->type),
+			  describe_object(&parent->oid));
+		printf_ln(_("broken link from %7s %s"),
+			  (type == OBJ_ANY ? _("unknown") : type_name(type)),
+			  _("unknown"));
+		errors_found |= ERROR_REACHABLE;
+		return 1;
+	}
+
+	if (type != OBJ_ANY && obj->type != type)
+		/* ... and the reference to parent is safe here */
+		objerror(parent, _("wrong object type in link"));
+
+	if (obj->flags & REACHABLE)
+		return 0;
+	obj->flags |= REACHABLE;
+
+	if (is_promisor_object(the_repository, &obj->oid))
+		/*
+		 * Further recursion does not need to be performed on this
+		 * object since it is a promisor object (so it does not need to
+		 * be added to "pending").
+		 */
+		return 0;
+
+	if (!(obj->flags & HAS_OBJ)) {
+		if (parent && !has_object(the_repository, &obj->oid, 1)) {
+			printf_ln(_("broken link from %7s %s\n"
+				    "              to %7s %s"),
+				  printable_type(&parent->oid, parent->type),
+				  describe_object(&parent->oid),
+				  printable_type(&obj->oid, obj->type),
+				  describe_object(&obj->oid));
+			errors_found |= ERROR_REACHABLE;
+		}
+		return 1;
+	}
+
+	add_object_array(obj, NULL, &pending);
+	return 0;
+}
+
+static void mark_object_reachable(struct object *obj)
+{
+	mark_object(obj, OBJ_ANY, NULL, NULL);
+}
+
+static int traverse_one_object(struct object *obj)
+{
+	int result = fsck_walk(obj, obj, &fsck_walk_options);
+
+	if (obj->type == OBJ_TREE) {
+		struct tree *tree = (struct tree *)obj;
+		free_tree_buffer(tree);
+	}
+	return result;
+}
+
+static int traverse_reachable(void)
+{
+	struct progress *progress = NULL;
+	unsigned int nr = 0;
+	int result = 0;
+	if (show_progress)
+		progress = start_delayed_progress(the_repository,
+						  _("Checking connectivity"), 0);
+	while (pending.nr) {
+		result |= traverse_one_object(object_array_pop(&pending));
+		display_progress(progress, ++nr);
+	}
+	stop_progress(&progress);
+	return !!result;
+}
+
+static int mark_used(struct object *obj, enum object_type type UNUSED,
+		     void *data UNUSED, struct fsck_options *options UNUSED)
+{
+	if (!obj)
+		return 1;
+	obj->flags |= USED;
+	return 0;
+}
+
+static void mark_unreachable_referents(const struct object_id *oid)
+{
+	struct fsck_options options = FSCK_OPTIONS_DEFAULT;
+	struct object *obj = lookup_object(the_repository, oid);
+
+	if (!obj || !(obj->flags & HAS_OBJ))
+		return; /* not part of our original set */
+	if (obj->flags & REACHABLE)
+		return; /* reachable objects already traversed */
+
+	/*
+	 * Avoid passing OBJ_NONE to fsck_walk, which will parse the object
+	 * (and we want to avoid parsing blobs).
+	 */
+	if (obj->type == OBJ_NONE) {
+		enum object_type type = oid_object_info(the_repository,
+							&obj->oid, NULL);
+		if (type > 0)
+			object_as_type(obj, type, 0);
+	}
+
+	options.walk = mark_used;
+	fsck_walk(obj, NULL, &options);
+	if (obj->type == OBJ_TREE)
+		free_tree_buffer((struct tree *)obj);
+}
+
+static int mark_loose_unreachable_referents(const struct object_id *oid,
+					    const char *path UNUSED,
+					    void *data UNUSED)
+{
+	mark_unreachable_referents(oid);
+	return 0;
+}
+
+static int mark_packed_unreachable_referents(const struct object_id *oid,
+					     struct packed_git *pack UNUSED,
+					     uint32_t pos UNUSED,
+					     void *data UNUSED)
+{
+	mark_unreachable_referents(oid);
+	return 0;
+}
+
+/*
+ * Check a single reachable object
+ */
+static void check_reachable_object(struct object *obj)
+{
+	/*
+	 * We obviously want the object to be parsed,
+	 * except if it was in a pack-file and we didn't
+	 * do a full fsck
+	 */
+	if (!(obj->flags & HAS_OBJ)) {
+		if (is_promisor_object(the_repository, &obj->oid))
+			return;
+		if (has_object_pack(the_repository, &obj->oid))
+			return; /* it is in pack - forget about it */
+		printf_ln(_("missing %s %s"),
+			  printable_type(&obj->oid, obj->type),
+			  describe_object(&obj->oid));
+		errors_found |= ERROR_REACHABLE;
+		return;
+	}
+}
+
+/*
+ * Check a single unreachable object
+ */
+static void check_unreachable_object(struct object *obj)
+{
+	/*
+	 * Missing unreachable object? Ignore it. It's not like
+	 * we miss it (since it can't be reached), nor do we want
+	 * to complain about it being unreachable (since it does
+	 * not exist).
+	 */
+	if (!(obj->flags & HAS_OBJ))
+		return;
+
+	/*
+	 * Unreachable object that exists? Show it if asked to,
+	 * since this is something that is prunable.
+	 */
+	if (show_unreachable) {
+		printf_ln(_("unreachable %s %s"),
+			  printable_type(&obj->oid, obj->type),
+			  describe_object(&obj->oid));
+		return;
+	}
+
+	/*
+	 * "!USED" means that nothing at all points to it, including
+	 * other unreachable objects. In other words, it's the "tip"
+	 * of some set of unreachable objects, usually a commit that
+	 * got dropped.
+	 *
+	 * Such starting points are more interesting than some random
+	 * set of unreachable objects, so we show them even if the user
+	 * hasn't asked for _all_ unreachable objects. If you have
+	 * deleted a branch by mistake, this is a prime candidate to
+	 * start looking at, for example.
+	 */
+	if (!(obj->flags & USED)) {
+		if (show_dangling)
+			printf_ln(_("dangling %s %s"),
+				  printable_type(&obj->oid, obj->type),
+				  describe_object(&obj->oid));
+		if (write_lost_and_found) {
+			char *filename = git_pathdup("lost-found/%s/%s",
+				obj->type == OBJ_COMMIT ? "commit" : "other",
+				describe_object(&obj->oid));
+			FILE *f;
+
+			if (safe_create_leading_directories_const(filename)) {
+				error(_("could not create lost-found"));
+				free(filename);
+				return;
+			}
+			f = xfopen(filename, "w");
+			if (obj->type == OBJ_BLOB) {
+				if (stream_blob_to_fd(fileno(f), &obj->oid, NULL, 1))
+					die_errno(_("could not write '%s'"), filename);
+			} else
+				fprintf(f, "%s\n", describe_object(&obj->oid));
+			if (fclose(f))
+				die_errno(_("could not finish '%s'"),
+					  filename);
+			free(filename);
+		}
+		return;
+	}
+
+	/*
+	 * Otherwise? It's there, it's unreachable, and some other unreachable
+	 * object points to it. Ignore it - it's not interesting, and we showed
+	 * all the interesting cases above.
+	 */
+}
+
+static void check_object(struct object *obj)
+{
+	if (verbose)
+		fprintf_ln(stderr, _("Checking %s"), describe_object(&obj->oid));
+
+	if (obj->flags & REACHABLE)
+		check_reachable_object(obj);
+	else
+		check_unreachable_object(obj);
+}
+
+static void check_connectivity(void)
+{
+	int i, max;
+
+	/* Traverse the pending reachable objects */
+	traverse_reachable();
+
+	/*
+	 * With --connectivity-only, we won't have actually opened and marked
+	 * unreachable objects with USED. Do that now to make --dangling, etc
+	 * accurate.
+	 */
+	if (connectivity_only && (show_dangling || write_lost_and_found)) {
+		/*
+		 * Even though we already have a "struct object" for each of
+		 * these in memory, we must not iterate over the internal
+		 * object hash as we do below. Our loop would potentially
+		 * resize the hash, making our iteration invalid.
+		 *
+		 * Instead, we'll just go back to the source list of objects,
+		 * and ignore any that weren't present in our earlier
+		 * traversal.
+		 */
+		for_each_loose_object(mark_loose_unreachable_referents, NULL, 0);
+		for_each_packed_object(the_repository,
+				       mark_packed_unreachable_referents,
+				       NULL,
+				       0);
+	}
+
+	/* Look up all the requirements, warn about missing objects.. */
+	max = get_max_object_index();
+	if (verbose)
+		fprintf_ln(stderr, _("Checking connectivity (%d objects)"), max);
+
+	for (i = 0; i < max; i++) {
+		struct object *obj = get_indexed_object(i);
+
+		if (obj)
+			check_object(obj);
+	}
+}
+
+static int fsck_obj(struct object *obj, void *buffer, unsigned long size)
+{
+	int err;
+
+	if (obj->flags & SEEN)
+		return 0;
+	obj->flags |= SEEN;
+
+	if (verbose)
+		fprintf_ln(stderr, _("Checking %s %s"),
+			   printable_type(&obj->oid, obj->type),
+			   describe_object(&obj->oid));
+
+	if (fsck_walk(obj, NULL, &fsck_obj_options))
+		objerror(obj, _("broken links"));
+	err = fsck_object(obj, buffer, size, &fsck_obj_options);
+	if (err)
+		goto out;
+
+	if (obj->type == OBJ_COMMIT) {
+		struct commit *commit = (struct commit *) obj;
+
+		if (!commit->parents && show_root)
+			printf_ln(_("root %s"),
+				  describe_object(&commit->object.oid));
+	}
+
+	if (obj->type == OBJ_TAG) {
+		struct tag *tag = (struct tag *) obj;
+
+		if (show_tags && tag->tagged) {
+			printf_ln(_("tagged %s %s (%s) in %s"),
+				  printable_type(&tag->tagged->oid, tag->tagged->type),
+				  describe_object(&tag->tagged->oid),
+				  tag->tag,
+				  describe_object(&tag->object.oid));
+		}
+	}
+
+out:
+	if (obj->type == OBJ_TREE)
+		free_tree_buffer((struct tree *)obj);
+	return err;
+}
+
+static int fsck_obj_buffer(const struct object_id *oid, enum object_type type,
+			   unsigned long size, void *buffer, int *eaten)
+{
+	/*
+	 * Note, buffer may be NULL if type is OBJ_BLOB. See
+	 * verify_packfile(), data_valid variable for details.
+	 */
+	struct object *obj;
+	obj = parse_object_buffer(the_repository, oid, type, size, buffer,
+				  eaten);
+	if (!obj) {
+		errors_found |= ERROR_OBJECT;
+		return error(_("%s: object corrupt or missing"),
+			     oid_to_hex(oid));
+	}
+	obj->flags &= ~(REACHABLE | SEEN);
+	obj->flags |= HAS_OBJ;
+	return fsck_obj(obj, buffer, size);
+}
+
+static int default_refs;
+
+static void fsck_handle_reflog_oid(const char *refname, struct object_id *oid,
+	timestamp_t timestamp)
+{
+	struct object *obj;
+
+	if (!is_null_oid(oid)) {
+		obj = lookup_object(the_repository, oid);
+		if (obj && (obj->flags & HAS_OBJ)) {
+			if (timestamp)
+				fsck_put_object_name(&fsck_walk_options, oid,
+						     "%s@{%"PRItime"}",
+						     refname, timestamp);
+			obj->flags |= USED;
+			mark_object_reachable(obj);
+		} else if (!is_promisor_object(the_repository, oid)) {
+			error(_("%s: invalid reflog entry %s"),
+			      refname, oid_to_hex(oid));
+			errors_found |= ERROR_REACHABLE;
+		}
+	}
+}
+
+static int fsck_handle_reflog_ent(struct object_id *ooid, struct object_id *noid,
+				  const char *email UNUSED,
+				  timestamp_t timestamp, int tz UNUSED,
+				  const char *message UNUSED, void *cb_data)
+{
+	const char *refname = cb_data;
+
+	if (verbose)
+		fprintf_ln(stderr, _("Checking reflog %s->%s"),
+			   oid_to_hex(ooid), oid_to_hex(noid));
+
+	fsck_handle_reflog_oid(refname, ooid, 0);
+	fsck_handle_reflog_oid(refname, noid, timestamp);
+	return 0;
+}
+
+static int fsck_handle_reflog(const char *logname, void *cb_data)
+{
+	struct strbuf refname = STRBUF_INIT;
+
+	strbuf_worktree_ref(cb_data, &refname, logname);
+	refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+				 refname.buf, fsck_handle_reflog_ent,
+				 refname.buf);
+	strbuf_release(&refname);
+	return 0;
+}
+
+static int fsck_handle_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+			   int flag UNUSED, void *cb_data UNUSED)
+{
+	struct object *obj;
+
+	obj = parse_object(the_repository, oid);
+	if (!obj) {
+		if (is_promisor_object(the_repository, oid)) {
+			/*
+			 * Increment default_refs anyway, because this is a
+			 * valid ref.
+			 */
+			 default_refs++;
+			 return 0;
+		}
+		error(_("%s: invalid sha1 pointer %s"),
+		      refname, oid_to_hex(oid));
+		errors_found |= ERROR_REACHABLE;
+		/* We'll continue with the rest despite the error.. */
+		return 0;
+	}
+	if (obj->type != OBJ_COMMIT && is_branch(refname)) {
+		error(_("%s: not a commit"), refname);
+		errors_found |= ERROR_REFS;
+	}
+	default_refs++;
+	obj->flags |= USED;
+	fsck_put_object_name(&fsck_walk_options,
+			     oid, "%s", refname);
+	mark_object_reachable(obj);
+
+	return 0;
+}
+
+static int fsck_head_link(const char *head_ref_name,
+			  const char **head_points_at,
+			  struct object_id *head_oid);
+
+static void get_default_heads(void)
+{
+	struct worktree **worktrees, **p;
+	const char *head_points_at;
+	struct object_id head_oid;
+
+	refs_for_each_rawref(get_main_ref_store(the_repository),
+			     fsck_handle_ref, NULL);
+
+	worktrees = get_worktrees();
+	for (p = worktrees; *p; p++) {
+		struct worktree *wt = *p;
+		struct strbuf ref = STRBUF_INIT;
+
+		strbuf_worktree_ref(wt, &ref, "HEAD");
+		fsck_head_link(ref.buf, &head_points_at, &head_oid);
+		if (head_points_at && !is_null_oid(&head_oid))
+			fsck_handle_ref(ref.buf, NULL, &head_oid, 0, NULL);
+		strbuf_release(&ref);
+
+		if (include_reflogs)
+			refs_for_each_reflog(get_worktree_ref_store(wt),
+					     fsck_handle_reflog, wt);
+	}
+	free_worktrees(worktrees);
+
+	/*
+	 * Not having any default heads isn't really fatal, but
+	 * it does mean that "--unreachable" no longer makes any
+	 * sense (since in this case everything will obviously
+	 * be unreachable by definition.
+	 *
+	 * Showing dangling objects is valid, though (as those
+	 * dangling objects are likely lost heads).
+	 *
+	 * So we just print a warning about it, and clear the
+	 * "show_unreachable" flag.
+	 */
+	if (!default_refs) {
+		fprintf_ln(stderr, _("notice: No default references"));
+		show_unreachable = 0;
+	}
+}
+
+struct for_each_loose_cb
+{
+	struct progress *progress;
+	struct strbuf obj_type;
+};
+
+static int fsck_loose(const struct object_id *oid, const char *path, void *data)
+{
+	struct for_each_loose_cb *cb_data = data;
+	struct object *obj;
+	enum object_type type = OBJ_NONE;
+	unsigned long size;
+	void *contents = NULL;
+	int eaten;
+	struct object_info oi = OBJECT_INFO_INIT;
+	struct object_id real_oid = *null_oid();
+	int err = 0;
+
+	strbuf_reset(&cb_data->obj_type);
+	oi.type_name = &cb_data->obj_type;
+	oi.sizep = &size;
+	oi.typep = &type;
+
+	if (read_loose_object(path, oid, &real_oid, &contents, &oi) < 0) {
+		if (contents && !oideq(&real_oid, oid))
+			err = error(_("%s: hash-path mismatch, found at: %s"),
+				    oid_to_hex(&real_oid), path);
+		else
+			err = error(_("%s: object corrupt or missing: %s"),
+				    oid_to_hex(oid), path);
+	}
+	if (type != OBJ_NONE && type < 0)
+		err = error(_("%s: object is of unknown type '%s': %s"),
+			    oid_to_hex(&real_oid), cb_data->obj_type.buf,
+			    path);
+	if (err < 0) {
+		errors_found |= ERROR_OBJECT;
+		free(contents);
+		return 0; /* keep checking other objects */
+	}
+
+	if (!contents && type != OBJ_BLOB)
+		BUG("read_loose_object streamed a non-blob");
+
+	obj = parse_object_buffer(the_repository, oid, type, size,
+				  contents, &eaten);
+
+	if (!obj) {
+		errors_found |= ERROR_OBJECT;
+		error(_("%s: object could not be parsed: %s"),
+		      oid_to_hex(oid), path);
+		if (!eaten)
+			free(contents);
+		return 0; /* keep checking other objects */
+	}
+
+	obj->flags &= ~(REACHABLE | SEEN);
+	obj->flags |= HAS_OBJ;
+	if (fsck_obj(obj, contents, size))
+		errors_found |= ERROR_OBJECT;
+
+	if (!eaten)
+		free(contents);
+	return 0; /* keep checking other objects, even if we saw an error */
+}
+
+static int fsck_cruft(const char *basename, const char *path,
+		      void *data UNUSED)
+{
+	if (!starts_with(basename, "tmp_obj_"))
+		fprintf_ln(stderr, _("bad sha1 file: %s"), path);
+	return 0;
+}
+
+static int fsck_subdir(unsigned int nr, const char *path UNUSED, void *data)
+{
+	struct for_each_loose_cb *cb_data = data;
+	struct progress *progress = cb_data->progress;
+	display_progress(progress, nr + 1);
+	return 0;
+}
+
+static void fsck_object_dir(const char *path)
+{
+	struct progress *progress = NULL;
+	struct for_each_loose_cb cb_data = {
+		.obj_type = STRBUF_INIT,
+		.progress = progress,
+	};
+
+	if (verbose)
+		fprintf_ln(stderr, _("Checking object directory"));
+
+	if (show_progress)
+		progress = start_progress(the_repository,
+					  _("Checking object directories"), 256);
+
+	for_each_loose_file_in_objdir(path, fsck_loose, fsck_cruft, fsck_subdir,
+				      &cb_data);
+	display_progress(progress, 256);
+	stop_progress(&progress);
+	strbuf_release(&cb_data.obj_type);
+}
+
+static int fsck_head_link(const char *head_ref_name,
+			  const char **head_points_at,
+			  struct object_id *head_oid)
+{
+	int null_is_error = 0;
+
+	if (verbose)
+		fprintf_ln(stderr, _("Checking %s link"), head_ref_name);
+
+	*head_points_at = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+						  head_ref_name, 0, head_oid,
+						  NULL);
+	if (!*head_points_at) {
+		errors_found |= ERROR_REFS;
+		return error(_("invalid %s"), head_ref_name);
+	}
+	if (!strcmp(*head_points_at, head_ref_name))
+		/* detached HEAD */
+		null_is_error = 1;
+	else if (!starts_with(*head_points_at, "refs/heads/")) {
+		errors_found |= ERROR_REFS;
+		return error(_("%s points to something strange (%s)"),
+			     head_ref_name, *head_points_at);
+	}
+	if (is_null_oid(head_oid)) {
+		if (null_is_error) {
+			errors_found |= ERROR_REFS;
+			return error(_("%s: detached HEAD points at nothing"),
+				     head_ref_name);
+		}
+		fprintf_ln(stderr,
+			   _("notice: %s points to an unborn branch (%s)"),
+			   head_ref_name, *head_points_at + 11);
+	}
+	return 0;
+}
+
+static int fsck_cache_tree(struct cache_tree *it, const char *index_path)
+{
+	int i;
+	int err = 0;
+
+	if (verbose)
+		fprintf_ln(stderr, _("Checking cache tree of %s"), index_path);
+
+	if (0 <= it->entry_count) {
+		struct object *obj = parse_object(the_repository, &it->oid);
+		if (!obj) {
+			error(_("%s: invalid sha1 pointer in cache-tree of %s"),
+			      oid_to_hex(&it->oid), index_path);
+			errors_found |= ERROR_REFS;
+			return 1;
+		}
+		obj->flags |= USED;
+		fsck_put_object_name(&fsck_walk_options, &it->oid, ":");
+		mark_object_reachable(obj);
+		if (obj->type != OBJ_TREE)
+			err |= objerror(obj, _("non-tree in cache-tree"));
+	}
+	for (i = 0; i < it->subtree_nr; i++)
+		err |= fsck_cache_tree(it->down[i]->cache_tree, index_path);
+	return err;
+}
+
+static int fsck_resolve_undo(struct index_state *istate,
+			     const char *index_path)
+{
+	struct string_list_item *item;
+	struct string_list *resolve_undo = istate->resolve_undo;
+
+	if (!resolve_undo)
+		return 0;
+
+	for_each_string_list_item(item, resolve_undo) {
+		const char *path = item->string;
+		struct resolve_undo_info *ru = item->util;
+		int i;
+
+		if (!ru)
+			continue;
+		for (i = 0; i < 3; i++) {
+			struct object *obj;
+
+			if (!ru->mode[i] || !S_ISREG(ru->mode[i]))
+				continue;
+
+			obj = parse_object(the_repository, &ru->oid[i]);
+			if (!obj) {
+				error(_("%s: invalid sha1 pointer in resolve-undo of %s"),
+				      oid_to_hex(&ru->oid[i]),
+				      index_path);
+				errors_found |= ERROR_REFS;
+				continue;
+			}
+			obj->flags |= USED;
+			fsck_put_object_name(&fsck_walk_options, &ru->oid[i],
+					     ":(%d):%s", i, path);
+			mark_object_reachable(obj);
+		}
+	}
+	return 0;
+}
+
+static void fsck_index(struct index_state *istate, const char *index_path,
+		       int is_current_worktree)
+{
+	unsigned int i;
+
+	/* TODO: audit for interaction with sparse-index. */
+	ensure_full_index(istate);
+	for (i = 0; i < istate->cache_nr; i++) {
+		unsigned int mode;
+		struct blob *blob;
+		struct object *obj;
+
+		mode = istate->cache[i]->ce_mode;
+		if (S_ISGITLINK(mode))
+			continue;
+		blob = lookup_blob(the_repository,
+				   &istate->cache[i]->oid);
+		if (!blob)
+			continue;
+		obj = &blob->object;
+		obj->flags |= USED;
+		fsck_put_object_name(&fsck_walk_options, &obj->oid,
+				     "%s:%s",
+				     is_current_worktree ? "" : index_path,
+				     istate->cache[i]->name);
+		mark_object_reachable(obj);
+	}
+	if (istate->cache_tree)
+		fsck_cache_tree(istate->cache_tree, index_path);
+	fsck_resolve_undo(istate, index_path);
+}
+
+static void mark_object_for_connectivity(const struct object_id *oid)
+{
+	struct object *obj = lookup_unknown_object(the_repository, oid);
+	obj->flags |= HAS_OBJ;
+}
+
+static int mark_loose_for_connectivity(const struct object_id *oid,
+				       const char *path UNUSED,
+				       void *data UNUSED)
+{
+	mark_object_for_connectivity(oid);
+	return 0;
+}
+
+static int mark_packed_for_connectivity(const struct object_id *oid,
+					struct packed_git *pack UNUSED,
+					uint32_t pos UNUSED,
+					void *data UNUSED)
+{
+	mark_object_for_connectivity(oid);
+	return 0;
+}
+
+static int check_pack_rev_indexes(struct repository *r, int show_progress)
+{
+	struct progress *progress = NULL;
+	uint32_t pack_count = 0;
+	int res = 0;
+
+	if (show_progress) {
+		for (struct packed_git *p = get_all_packs(r); p; p = p->next)
+			pack_count++;
+		progress = start_delayed_progress(the_repository,
+						  "Verifying reverse pack-indexes", pack_count);
+		pack_count = 0;
+	}
+
+	for (struct packed_git *p = get_all_packs(r); p; p = p->next) {
+		int load_error = load_pack_revindex_from_disk(p);
+
+		if (load_error < 0) {
+			error(_("unable to load rev-index for pack '%s'"), p->pack_name);
+			res = ERROR_PACK_REV_INDEX;
+		} else if (!load_error &&
+			   !load_pack_revindex(r, p) &&
+			   verify_pack_revindex(p)) {
+			error(_("invalid rev-index for pack '%s'"), p->pack_name);
+			res = ERROR_PACK_REV_INDEX;
+		}
+		display_progress(progress, ++pack_count);
+	}
+	stop_progress(&progress);
+
+	return res;
+}
+
+static char const * const fsck_usage[] = {
+	N_("git fsck [--tags] [--root] [--unreachable] [--cache] [--no-reflogs]\n"
+	   "         [--[no-]full] [--strict] [--verbose] [--lost-found]\n"
+	   "         [--[no-]dangling] [--[no-]progress] [--connectivity-only]\n"
+	   "         [--[no-]name-objects] [<object>...]"),
+	NULL
+};
+
+static struct option fsck_opts[] = {
+	OPT__VERBOSE(&verbose, N_("be verbose")),
+	OPT_BOOL(0, "unreachable", &show_unreachable, N_("show unreachable objects")),
+	OPT_BOOL(0, "dangling", &show_dangling, N_("show dangling objects")),
+	OPT_BOOL(0, "tags", &show_tags, N_("report tags")),
+	OPT_BOOL(0, "root", &show_root, N_("report root nodes")),
+	OPT_BOOL(0, "cache", &keep_cache_objects, N_("make index objects head nodes")),
+	OPT_BOOL(0, "reflogs", &include_reflogs, N_("make reflogs head nodes (default)")),
+	OPT_BOOL(0, "full", &check_full, N_("also consider packs and alternate objects")),
+	OPT_BOOL(0, "connectivity-only", &connectivity_only, N_("check only connectivity")),
+	OPT_BOOL(0, "strict", &check_strict, N_("enable more strict checking")),
+	OPT_BOOL(0, "lost-found", &write_lost_and_found,
+				N_("write dangling objects in .git/lost-found")),
+	OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
+	OPT_BOOL(0, "name-objects", &name_objects, N_("show verbose names for reachable objects")),
+	OPT_END(),
+};
+
+int cmd_fsck(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
+{
+	int i;
+	struct object_directory *odb;
+
+	/* fsck knows how to handle missing promisor objects */
+	fetch_if_missing = 0;
+
+	errors_found = 0;
+	disable_replace_refs();
+	save_commit_buffer = 0;
+
+	argc = parse_options(argc, argv, prefix, fsck_opts, fsck_usage, 0);
+
+	fsck_walk_options.walk = mark_object;
+	fsck_obj_options.walk = mark_used;
+	fsck_obj_options.error_func = fsck_objects_error_func;
+	if (check_strict)
+		fsck_obj_options.strict = 1;
+
+	if (show_progress == -1)
+		show_progress = isatty(2);
+	if (verbose)
+		show_progress = 0;
+
+	if (write_lost_and_found) {
+		check_full = 1;
+		include_reflogs = 0;
+	}
+
+	if (name_objects)
+		fsck_enable_object_names(&fsck_walk_options);
+
+	git_config(git_fsck_config, &fsck_obj_options);
+	prepare_repo_settings(the_repository);
+
+	if (connectivity_only) {
+		for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
+		for_each_packed_object(the_repository,
+				       mark_packed_for_connectivity, NULL, 0);
+	} else {
+		prepare_alt_odb(the_repository);
+		for (odb = the_repository->objects->odb; odb; odb = odb->next)
+			fsck_object_dir(odb->path);
+
+		if (check_full) {
+			struct packed_git *p;
+			uint32_t total = 0, count = 0;
+			struct progress *progress = NULL;
+
+			if (show_progress) {
+				for (p = get_all_packs(the_repository); p;
+				     p = p->next) {
+					if (open_pack_index(p))
+						continue;
+					total += p->num_objects;
+				}
+
+				progress = start_progress(the_repository,
+							  _("Checking objects"), total);
+			}
+			for (p = get_all_packs(the_repository); p;
+			     p = p->next) {
+				/* verify gives error messages itself */
+				if (verify_pack(the_repository,
+						p, fsck_obj_buffer,
+						progress, count))
+					errors_found |= ERROR_PACK;
+				count += p->num_objects;
+			}
+			stop_progress(&progress);
+		}
+
+		if (fsck_finish(&fsck_obj_options))
+			errors_found |= ERROR_OBJECT;
+	}
+
+	for (i = 0; i < argc; i++) {
+		const char *arg = argv[i];
+		struct object_id oid;
+		if (!repo_get_oid(the_repository, arg, &oid)) {
+			struct object *obj = lookup_object(the_repository,
+							   &oid);
+
+			if (!obj || !(obj->flags & HAS_OBJ)) {
+				if (is_promisor_object(the_repository, &oid))
+					continue;
+				error(_("%s: object missing"), oid_to_hex(&oid));
+				errors_found |= ERROR_OBJECT;
+				continue;
+			}
+
+			obj->flags |= USED;
+			fsck_put_object_name(&fsck_walk_options, &oid,
+					     "%s", arg);
+			mark_object_reachable(obj);
+			continue;
+		}
+		error(_("invalid parameter: expected sha1, got '%s'"), arg);
+		errors_found |= ERROR_OBJECT;
+	}
+
+	/*
+	 * If we've not been given any explicit head information, do the
+	 * default ones from .git/refs. We also consider the index file
+	 * in this case (ie this implies --cache).
+	 */
+	if (!argc) {
+		get_default_heads();
+		keep_cache_objects = 1;
+	}
+
+	if (keep_cache_objects) {
+		struct worktree **worktrees, **p;
+
+		verify_index_checksum = 1;
+		verify_ce_order = 1;
+
+		worktrees = get_worktrees();
+		for (p = worktrees; *p; p++) {
+			struct worktree *wt = *p;
+			struct index_state istate =
+				INDEX_STATE_INIT(the_repository);
+			char *path;
+
+			/*
+			 * Make a copy since the buffer is reusable
+			 * and may get overwritten by other calls
+			 * while we're examining the index.
+			 */
+			path = xstrdup(worktree_git_path(the_repository, wt, "index"));
+			read_index_from(&istate, path, get_worktree_git_dir(wt));
+			fsck_index(&istate, path, wt->is_current);
+			discard_index(&istate);
+			free(path);
+		}
+		free_worktrees(worktrees);
+	}
+
+	errors_found |= check_pack_rev_indexes(the_repository, show_progress);
+	if (verify_bitmap_files(the_repository))
+		errors_found |= ERROR_BITMAP;
+
+	check_connectivity();
+
+	if (the_repository->settings.core_commit_graph) {
+		struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
+
+		prepare_alt_odb(the_repository);
+		for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+			child_process_init(&commit_graph_verify);
+			commit_graph_verify.git_cmd = 1;
+			strvec_pushl(&commit_graph_verify.args, "commit-graph",
+				     "verify", "--object-dir", odb->path, NULL);
+			if (show_progress)
+				strvec_push(&commit_graph_verify.args, "--progress");
+			else
+				strvec_push(&commit_graph_verify.args, "--no-progress");
+			if (run_command(&commit_graph_verify))
+				errors_found |= ERROR_COMMIT_GRAPH;
+		}
+	}
+
+	if (the_repository->settings.core_multi_pack_index) {
+		struct child_process midx_verify = CHILD_PROCESS_INIT;
+
+		prepare_alt_odb(the_repository);
+		for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+			child_process_init(&midx_verify);
+			midx_verify.git_cmd = 1;
+			strvec_pushl(&midx_verify.args, "multi-pack-index",
+				     "verify", "--object-dir", odb->path, NULL);
+			if (show_progress)
+				strvec_push(&midx_verify.args, "--progress");
+			else
+				strvec_push(&midx_verify.args, "--no-progress");
+			if (run_command(&midx_verify))
+				errors_found |= ERROR_MULTI_PACK_INDEX;
+		}
+	}
+
+	return errors_found;
+}
diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c
new file mode 100644
index 0000000000..0820e524f1
--- /dev/null
+++ b/builtin/fsmonitor--daemon.c
@@ -0,0 +1,1606 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "dir.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "fsmonitor-ll.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "compat/fsmonitor/fsm-health.h"
+#include "compat/fsmonitor/fsm-listen.h"
+#include "fsmonitor--daemon.h"
+
+#include "simple-ipc.h"
+#include "khash.h"
+#include "run-command.h"
+#include "trace.h"
+#include "trace2.h"
+
+static const char * const builtin_fsmonitor__daemon_usage[] = {
+	N_("git fsmonitor--daemon start [<options>]"),
+	N_("git fsmonitor--daemon run [<options>]"),
+	"git fsmonitor--daemon stop",
+	"git fsmonitor--daemon status",
+	NULL
+};
+
+#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
+/*
+ * Global state loaded from config.
+ */
+#define FSMONITOR__IPC_THREADS "fsmonitor.ipcthreads"
+static int fsmonitor__ipc_threads = 8;
+
+#define FSMONITOR__START_TIMEOUT "fsmonitor.starttimeout"
+static int fsmonitor__start_timeout_sec = 60;
+
+#define FSMONITOR__ANNOUNCE_STARTUP "fsmonitor.announcestartup"
+static int fsmonitor__announce_startup = 0;
+
+static int fsmonitor_config(const char *var, const char *value,
+			    const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, FSMONITOR__IPC_THREADS)) {
+		int i = git_config_int(var, value, ctx->kvi);
+		if (i < 1)
+			return error(_("value of '%s' out of range: %d"),
+				     FSMONITOR__IPC_THREADS, i);
+		fsmonitor__ipc_threads = i;
+		return 0;
+	}
+
+	if (!strcmp(var, FSMONITOR__START_TIMEOUT)) {
+		int i = git_config_int(var, value, ctx->kvi);
+		if (i < 0)
+			return error(_("value of '%s' out of range: %d"),
+				     FSMONITOR__START_TIMEOUT, i);
+		fsmonitor__start_timeout_sec = i;
+		return 0;
+	}
+
+	if (!strcmp(var, FSMONITOR__ANNOUNCE_STARTUP)) {
+		int is_bool;
+		int i = git_config_bool_or_int(var, value, ctx->kvi, &is_bool);
+		if (i < 0)
+			return error(_("value of '%s' not bool or int: %d"),
+				     var, i);
+		fsmonitor__announce_startup = i;
+		return 0;
+	}
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+/*
+ * Acting as a CLIENT.
+ *
+ * Send a "quit" command to the `git-fsmonitor--daemon` (if running)
+ * and wait for it to shutdown.
+ */
+static int do_as_client__send_stop(void)
+{
+	struct strbuf answer = STRBUF_INIT;
+	int ret;
+
+	ret = fsmonitor_ipc__send_command("quit", &answer);
+
+	/* The quit command does not return any response data. */
+	strbuf_release(&answer);
+
+	if (ret)
+		return ret;
+
+	trace2_region_enter("fsm_client", "polling-for-daemon-exit", NULL);
+	while (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
+		sleep_millisec(50);
+	trace2_region_leave("fsm_client", "polling-for-daemon-exit", NULL);
+
+	return 0;
+}
+
+static int do_as_client__status(void)
+{
+	enum ipc_active_state state = fsmonitor_ipc__get_state();
+
+	switch (state) {
+	case IPC_STATE__LISTENING:
+		printf(_("fsmonitor-daemon is watching '%s'\n"),
+		       the_repository->worktree);
+		return 0;
+
+	default:
+		printf(_("fsmonitor-daemon is not watching '%s'\n"),
+		       the_repository->worktree);
+		return 1;
+	}
+}
+
+enum fsmonitor_cookie_item_result {
+	FCIR_ERROR = -1, /* could not create cookie file ? */
+	FCIR_INIT,
+	FCIR_SEEN,
+	FCIR_ABORT,
+};
+
+struct fsmonitor_cookie_item {
+	struct hashmap_entry entry;
+	char *name;
+	enum fsmonitor_cookie_item_result result;
+};
+
+static int cookies_cmp(const void *data UNUSED,
+		       const struct hashmap_entry *he1,
+		       const struct hashmap_entry *he2, const void *keydata)
+{
+	const struct fsmonitor_cookie_item *a =
+		container_of(he1, const struct fsmonitor_cookie_item, entry);
+	const struct fsmonitor_cookie_item *b =
+		container_of(he2, const struct fsmonitor_cookie_item, entry);
+
+	return strcmp(a->name, keydata ? keydata : b->name);
+}
+
+static enum fsmonitor_cookie_item_result with_lock__wait_for_cookie(
+	struct fsmonitor_daemon_state *state)
+{
+	/* assert current thread holding state->main_lock */
+
+	int fd;
+	struct fsmonitor_cookie_item *cookie;
+	struct strbuf cookie_pathname = STRBUF_INIT;
+	struct strbuf cookie_filename = STRBUF_INIT;
+	enum fsmonitor_cookie_item_result result;
+	int my_cookie_seq;
+
+	CALLOC_ARRAY(cookie, 1);
+
+	my_cookie_seq = state->cookie_seq++;
+
+	strbuf_addf(&cookie_filename, "%i-%i", getpid(), my_cookie_seq);
+
+	strbuf_addbuf(&cookie_pathname, &state->path_cookie_prefix);
+	strbuf_addbuf(&cookie_pathname, &cookie_filename);
+
+	cookie->name = strbuf_detach(&cookie_filename, NULL);
+	cookie->result = FCIR_INIT;
+	hashmap_entry_init(&cookie->entry, strhash(cookie->name));
+
+	hashmap_add(&state->cookies, &cookie->entry);
+
+	trace_printf_key(&trace_fsmonitor, "cookie-wait: '%s' '%s'",
+			 cookie->name, cookie_pathname.buf);
+
+	/*
+	 * Create the cookie file on disk and then wait for a notification
+	 * that the listener thread has seen it.
+	 */
+	fd = open(cookie_pathname.buf, O_WRONLY | O_CREAT | O_EXCL, 0600);
+	if (fd < 0) {
+		error_errno(_("could not create fsmonitor cookie '%s'"),
+			    cookie->name);
+
+		cookie->result = FCIR_ERROR;
+		goto done;
+	}
+
+	/*
+	 * Technically, close() and unlink() can fail, but we don't
+	 * care here.  We only created the file to trigger a watch
+	 * event from the FS to know that when we're up to date.
+	 */
+	close(fd);
+	unlink(cookie_pathname.buf);
+
+	/*
+	 * Technically, this is an infinite wait (well, unless another
+	 * thread sends us an abort).  I'd like to change this to
+	 * use `pthread_cond_timedwait()` and return an error/timeout
+	 * and let the caller do the trivial response thing, but we
+	 * don't have that routine in our thread-utils.
+	 *
+	 * After extensive beta testing I'm not really worried about
+	 * this.  Also note that the above open() and unlink() calls
+	 * will cause at least two FS events on that path, so the odds
+	 * of getting stuck are pretty slim.
+	 */
+	while (cookie->result == FCIR_INIT)
+		pthread_cond_wait(&state->cookies_cond,
+				  &state->main_lock);
+
+done:
+	hashmap_remove(&state->cookies, &cookie->entry, NULL);
+
+	result = cookie->result;
+
+	free(cookie->name);
+	free(cookie);
+	strbuf_release(&cookie_pathname);
+
+	return result;
+}
+
+/*
+ * Mark these cookies as _SEEN and wake up the corresponding client threads.
+ */
+static void with_lock__mark_cookies_seen(struct fsmonitor_daemon_state *state,
+					 const struct string_list *cookie_names)
+{
+	/* assert current thread holding state->main_lock */
+
+	int k;
+	int nr_seen = 0;
+
+	for (k = 0; k < cookie_names->nr; k++) {
+		struct fsmonitor_cookie_item key;
+		struct fsmonitor_cookie_item *cookie;
+
+		key.name = cookie_names->items[k].string;
+		hashmap_entry_init(&key.entry, strhash(key.name));
+
+		cookie = hashmap_get_entry(&state->cookies, &key, entry, NULL);
+		if (cookie) {
+			trace_printf_key(&trace_fsmonitor, "cookie-seen: '%s'",
+					 cookie->name);
+			cookie->result = FCIR_SEEN;
+			nr_seen++;
+		}
+	}
+
+	if (nr_seen)
+		pthread_cond_broadcast(&state->cookies_cond);
+}
+
+/*
+ * Set _ABORT on all pending cookies and wake up all client threads.
+ */
+static void with_lock__abort_all_cookies(struct fsmonitor_daemon_state *state)
+{
+	/* assert current thread holding state->main_lock */
+
+	struct hashmap_iter iter;
+	struct fsmonitor_cookie_item *cookie;
+	int nr_aborted = 0;
+
+	hashmap_for_each_entry(&state->cookies, &iter, cookie, entry) {
+		trace_printf_key(&trace_fsmonitor, "cookie-abort: '%s'",
+				 cookie->name);
+		cookie->result = FCIR_ABORT;
+		nr_aborted++;
+	}
+
+	if (nr_aborted)
+		pthread_cond_broadcast(&state->cookies_cond);
+}
+
+/*
+ * Requests to and from a FSMonitor Protocol V2 provider use an opaque
+ * "token" as a virtual timestamp.  Clients can request a summary of all
+ * created/deleted/modified files relative to a token.  In the response,
+ * clients receive a new token for the next (relative) request.
+ *
+ *
+ * Token Format
+ * ============
+ *
+ * The contents of the token are private and provider-specific.
+ *
+ * For the built-in fsmonitor--daemon, we define a token as follows:
+ *
+ *     "builtin" ":" <token_id> ":" <sequence_nr>
+ *
+ * The "builtin" prefix is used as a namespace to avoid conflicts
+ * with other providers (such as Watchman).
+ *
+ * The <token_id> is an arbitrary OPAQUE string, such as a GUID,
+ * UUID, or {timestamp,pid}.  It is used to group all filesystem
+ * events that happened while the daemon was monitoring (and in-sync
+ * with the filesystem).
+ *
+ *     Unlike FSMonitor Protocol V1, it is not defined as a timestamp
+ *     and does not define less-than/greater-than relationships.
+ *     (There are too many race conditions to rely on file system
+ *     event timestamps.)
+ *
+ * The <sequence_nr> is a simple integer incremented whenever the
+ * daemon needs to make its state public.  For example, if 1000 file
+ * system events come in, but no clients have requested the data,
+ * the daemon can continue to accumulate file changes in the same
+ * bin and does not need to advance the sequence number.  However,
+ * as soon as a client does arrive, the daemon needs to start a new
+ * bin and increment the sequence number.
+ *
+ *     The sequence number serves as the boundary between 2 sets
+ *     of bins -- the older ones that the client has already seen
+ *     and the newer ones that it hasn't.
+ *
+ * When a new <token_id> is created, the <sequence_nr> is reset to
+ * zero.
+ *
+ *
+ * About Token Ids
+ * ===============
+ *
+ * A new token_id is created:
+ *
+ * [1] each time the daemon is started.
+ *
+ * [2] any time that the daemon must re-sync with the filesystem
+ *     (such as when the kernel drops or we miss events on a very
+ *     active volume).
+ *
+ * [3] in response to a client "flush" command (for dropped event
+ *     testing).
+ *
+ * When a new token_id is created, the daemon is free to discard all
+ * cached filesystem events associated with any previous token_ids.
+ * Events associated with a non-current token_id will never be sent
+ * to a client.  A token_id change implicitly means that the daemon
+ * has gap in its event history.
+ *
+ * Therefore, clients that present a token with a stale (non-current)
+ * token_id will always be given a trivial response.
+ */
+struct fsmonitor_token_data {
+	struct strbuf token_id;
+	struct fsmonitor_batch *batch_head;
+	struct fsmonitor_batch *batch_tail;
+	uint64_t client_ref_count;
+};
+
+struct fsmonitor_batch {
+	struct fsmonitor_batch *next;
+	uint64_t batch_seq_nr;
+	const char **interned_paths;
+	size_t nr, alloc;
+	time_t pinned_time;
+};
+
+static struct fsmonitor_token_data *fsmonitor_new_token_data(void)
+{
+	static int test_env_value = -1;
+	static uint64_t flush_count = 0;
+	struct fsmonitor_token_data *token;
+	struct fsmonitor_batch *batch;
+
+	CALLOC_ARRAY(token, 1);
+	batch = fsmonitor_batch__new();
+
+	strbuf_init(&token->token_id, 0);
+	token->batch_head = batch;
+	token->batch_tail = batch;
+	token->client_ref_count = 0;
+
+	if (test_env_value < 0)
+		test_env_value = git_env_bool("GIT_TEST_FSMONITOR_TOKEN", 0);
+
+	if (!test_env_value) {
+		struct timeval tv;
+		struct tm tm;
+		time_t secs;
+
+		gettimeofday(&tv, NULL);
+		secs = tv.tv_sec;
+		gmtime_r(&secs, &tm);
+
+		strbuf_addf(&token->token_id,
+			    "%"PRIu64".%d.%4d%02d%02dT%02d%02d%02d.%06ldZ",
+			    flush_count++,
+			    getpid(),
+			    tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+			    tm.tm_hour, tm.tm_min, tm.tm_sec,
+			    (long)tv.tv_usec);
+	} else {
+		strbuf_addf(&token->token_id, "test_%08x", test_env_value++);
+	}
+
+	/*
+	 * We created a new <token_id> and are starting a new series
+	 * of tokens with a zero <seq_nr>.
+	 *
+	 * Since clients cannot guess our new (non test) <token_id>
+	 * they will always receive a trivial response (because of the
+	 * mismatch on the <token_id>).  The trivial response will
+	 * tell them our new <token_id> so that subsequent requests
+	 * will be relative to our new series.  (And when sending that
+	 * response, we pin the current head of the batch list.)
+	 *
+	 * Even if the client correctly guesses the <token_id>, their
+	 * request of "builtin:<token_id>:0" asks for all changes MORE
+	 * RECENT than batch/bin 0.
+	 *
+	 * This implies that it is a waste to accumulate paths in the
+	 * initial batch/bin (because they will never be transmitted).
+	 *
+	 * So the daemon could be running for days and watching the
+	 * file system, but doesn't need to actually accumulate any
+	 * paths UNTIL we need to set a reference point for a later
+	 * relative request.
+	 *
+	 * However, it is very useful for testing to always have a
+	 * reference point set.  Pin batch 0 to force early file system
+	 * events to accumulate.
+	 */
+	if (test_env_value)
+		batch->pinned_time = time(NULL);
+
+	return token;
+}
+
+struct fsmonitor_batch *fsmonitor_batch__new(void)
+{
+	struct fsmonitor_batch *batch;
+
+	CALLOC_ARRAY(batch, 1);
+
+	return batch;
+}
+
+void fsmonitor_batch__free_list(struct fsmonitor_batch *batch)
+{
+	while (batch) {
+		struct fsmonitor_batch *next = batch->next;
+
+		/*
+		 * The actual strings within the array of this batch
+		 * are interned, so we don't own them.  We only own
+		 * the array.
+		 */
+		free(batch->interned_paths);
+		free(batch);
+
+		batch = next;
+	}
+}
+
+void fsmonitor_batch__add_path(struct fsmonitor_batch *batch,
+			       const char *path)
+{
+	const char *interned_path = strintern(path);
+
+	trace_printf_key(&trace_fsmonitor, "event: %s", interned_path);
+
+	ALLOC_GROW(batch->interned_paths, batch->nr + 1, batch->alloc);
+	batch->interned_paths[batch->nr++] = interned_path;
+}
+
+static void fsmonitor_batch__combine(struct fsmonitor_batch *batch_dest,
+				     const struct fsmonitor_batch *batch_src)
+{
+	size_t k;
+
+	ALLOC_GROW(batch_dest->interned_paths,
+		   batch_dest->nr + batch_src->nr + 1,
+		   batch_dest->alloc);
+
+	for (k = 0; k < batch_src->nr; k++)
+		batch_dest->interned_paths[batch_dest->nr++] =
+			batch_src->interned_paths[k];
+}
+
+/*
+ * To keep the batch list from growing unbounded in response to filesystem
+ * activity, we try to truncate old batches from the end of the list as
+ * they become irrelevant.
+ *
+ * We assume that the .git/index will be updated with the most recent token
+ * any time the index is updated.  And future commands will only ask for
+ * recent changes *since* that new token.  So as tokens advance into the
+ * future, older batch items will never be requested/needed.  So we can
+ * truncate them without loss of functionality.
+ *
+ * However, multiple commands may be talking to the daemon concurrently
+ * or perform a slow command, so a little "token skew" is possible.
+ * Therefore, we want this to be a little bit lazy and have a generous
+ * delay.
+ *
+ * The current reader thread walked backwards in time from `token->batch_head`
+ * back to `batch_marker` somewhere in the middle of the batch list.
+ *
+ * Let's walk backwards in time from that marker an arbitrary delay
+ * and truncate the list there.  Note that these timestamps are completely
+ * artificial (based on when we pinned the batch item) and not on any
+ * filesystem activity.
+ *
+ * Return the obsolete portion of the list after we have removed it from
+ * the official list so that the caller can free it after leaving the lock.
+ */
+#define MY_TIME_DELAY_SECONDS (5 * 60) /* seconds */
+
+static struct fsmonitor_batch *with_lock__truncate_old_batches(
+	struct fsmonitor_daemon_state *state,
+	const struct fsmonitor_batch *batch_marker)
+{
+	/* assert current thread holding state->main_lock */
+
+	const struct fsmonitor_batch *batch;
+	struct fsmonitor_batch *remainder;
+
+	if (!batch_marker)
+		return NULL;
+
+	trace_printf_key(&trace_fsmonitor, "Truncate: mark (%"PRIu64",%"PRIu64")",
+			 batch_marker->batch_seq_nr,
+			 (uint64_t)batch_marker->pinned_time);
+
+	for (batch = batch_marker; batch; batch = batch->next) {
+		time_t t;
+
+		if (!batch->pinned_time) /* an overflow batch */
+			continue;
+
+		t = batch->pinned_time + MY_TIME_DELAY_SECONDS;
+		if (t > batch_marker->pinned_time) /* too close to marker */
+			continue;
+
+		goto truncate_past_here;
+	}
+
+	return NULL;
+
+truncate_past_here:
+	state->current_token_data->batch_tail = (struct fsmonitor_batch *)batch;
+
+	remainder = ((struct fsmonitor_batch *)batch)->next;
+	((struct fsmonitor_batch *)batch)->next = NULL;
+
+	return remainder;
+}
+
+static void fsmonitor_free_token_data(struct fsmonitor_token_data *token)
+{
+	if (!token)
+		return;
+
+	assert(token->client_ref_count == 0);
+
+	strbuf_release(&token->token_id);
+
+	fsmonitor_batch__free_list(token->batch_head);
+
+	free(token);
+}
+
+/*
+ * Flush all of our cached data about the filesystem.  Call this if we
+ * lose sync with the filesystem and miss some notification events.
+ *
+ * [1] If we are missing events, then we no longer have a complete
+ *     history of the directory (relative to our current start token).
+ *     We should create a new token and start fresh (as if we just
+ *     booted up).
+ *
+ * [2] Some of those lost events may have been for cookie files.  We
+ *     should assume the worst and abort them rather letting them starve.
+ *
+ * If there are no concurrent threads reading the current token data
+ * series, we can free it now.  Otherwise, let the last reader free
+ * it.
+ *
+ * Either way, the old token data series is no longer associated with
+ * our state data.
+ */
+static void with_lock__do_force_resync(struct fsmonitor_daemon_state *state)
+{
+	/* assert current thread holding state->main_lock */
+
+	struct fsmonitor_token_data *free_me = NULL;
+	struct fsmonitor_token_data *new_one = NULL;
+
+	new_one = fsmonitor_new_token_data();
+
+	if (state->current_token_data->client_ref_count == 0)
+		free_me = state->current_token_data;
+	state->current_token_data = new_one;
+
+	fsmonitor_free_token_data(free_me);
+
+	with_lock__abort_all_cookies(state);
+}
+
+void fsmonitor_force_resync(struct fsmonitor_daemon_state *state)
+{
+	pthread_mutex_lock(&state->main_lock);
+	with_lock__do_force_resync(state);
+	pthread_mutex_unlock(&state->main_lock);
+}
+
+/*
+ * Format an opaque token string to send to the client.
+ */
+static void with_lock__format_response_token(
+	struct strbuf *response_token,
+	const struct strbuf *response_token_id,
+	const struct fsmonitor_batch *batch)
+{
+	/* assert current thread holding state->main_lock */
+
+	strbuf_reset(response_token);
+	strbuf_addf(response_token, "builtin:%s:%"PRIu64,
+		    response_token_id->buf, batch->batch_seq_nr);
+}
+
+/*
+ * Parse an opaque token from the client.
+ * Returns -1 on error.
+ */
+static int fsmonitor_parse_client_token(const char *buf_token,
+					struct strbuf *requested_token_id,
+					uint64_t *seq_nr)
+{
+	const char *p;
+	char *p_end;
+
+	strbuf_reset(requested_token_id);
+	*seq_nr = 0;
+
+	if (!skip_prefix(buf_token, "builtin:", &p))
+		return -1;
+
+	while (*p && *p != ':')
+		strbuf_addch(requested_token_id, *p++);
+	if (!*p++)
+		return -1;
+
+	*seq_nr = (uint64_t)strtoumax(p, &p_end, 10);
+	if (*p_end)
+		return -1;
+
+	return 0;
+}
+
+KHASH_INIT(str, const char *, int, 0, kh_str_hash_func, kh_str_hash_equal)
+
+static int do_handle_client(struct fsmonitor_daemon_state *state,
+			    const char *command,
+			    ipc_server_reply_cb *reply,
+			    struct ipc_server_reply_data *reply_data)
+{
+	struct fsmonitor_token_data *token_data = NULL;
+	struct strbuf response_token = STRBUF_INIT;
+	struct strbuf requested_token_id = STRBUF_INIT;
+	struct strbuf payload = STRBUF_INIT;
+	uint64_t requested_oldest_seq_nr = 0;
+	uint64_t total_response_len = 0;
+	const char *p;
+	const struct fsmonitor_batch *batch_head;
+	const struct fsmonitor_batch *batch;
+	struct fsmonitor_batch *remainder = NULL;
+	intmax_t count = 0, duplicates = 0;
+	kh_str_t *shown;
+	int hash_ret;
+	int do_trivial = 0;
+	int do_flush = 0;
+	int do_cookie = 0;
+	enum fsmonitor_cookie_item_result cookie_result;
+
+	/*
+	 * We expect `command` to be of the form:
+	 *
+	 * <command> := quit NUL
+	 *            | flush NUL
+	 *            | <V1-time-since-epoch-ns> NUL
+	 *            | <V2-opaque-fsmonitor-token> NUL
+	 */
+
+	if (!strcmp(command, "quit")) {
+		/*
+		 * A client has requested over the socket/pipe that the
+		 * daemon shutdown.
+		 *
+		 * Tell the IPC thread pool to shutdown (which completes
+		 * the await in the main thread (which can stop the
+		 * fsmonitor listener thread)).
+		 *
+		 * There is no reply to the client.
+		 */
+		return SIMPLE_IPC_QUIT;
+
+	} else if (!strcmp(command, "flush")) {
+		/*
+		 * Flush all of our cached data and generate a new token
+		 * just like if we lost sync with the filesystem.
+		 *
+		 * Then send a trivial response using the new token.
+		 */
+		do_flush = 1;
+		do_trivial = 1;
+
+	} else if (!skip_prefix(command, "builtin:", &p)) {
+		/* assume V1 timestamp or garbage */
+
+		char *p_end;
+
+		strtoumax(command, &p_end, 10);
+		trace_printf_key(&trace_fsmonitor,
+				 ((*p_end) ?
+				  "fsmonitor: invalid command line '%s'" :
+				  "fsmonitor: unsupported V1 protocol '%s'"),
+				 command);
+		do_trivial = 1;
+		do_cookie = 1;
+
+	} else {
+		/* We have "builtin:*" */
+		if (fsmonitor_parse_client_token(command, &requested_token_id,
+						 &requested_oldest_seq_nr)) {
+			trace_printf_key(&trace_fsmonitor,
+					 "fsmonitor: invalid V2 protocol token '%s'",
+					 command);
+			do_trivial = 1;
+			do_cookie = 1;
+
+		} else {
+			/*
+			 * We have a V2 valid token:
+			 *     "builtin:<token_id>:<seq_nr>"
+			 */
+			do_cookie = 1;
+		}
+	}
+
+	pthread_mutex_lock(&state->main_lock);
+
+	if (!state->current_token_data)
+		BUG("fsmonitor state does not have a current token");
+
+	/*
+	 * Write a cookie file inside the directory being watched in
+	 * an effort to flush out existing filesystem events that we
+	 * actually care about.  Suspend this client thread until we
+	 * see the filesystem events for this cookie file.
+	 *
+	 * Creating the cookie lets us guarantee that our FS listener
+	 * thread has drained the kernel queue and we are caught up
+	 * with the kernel.
+	 *
+	 * If we cannot create the cookie (or otherwise guarantee that
+	 * we are caught up), we send a trivial response.  We have to
+	 * assume that there might be some very, very recent activity
+	 * on the FS still in flight.
+	 */
+	if (do_cookie) {
+		cookie_result = with_lock__wait_for_cookie(state);
+		if (cookie_result != FCIR_SEEN) {
+			error(_("fsmonitor: cookie_result '%d' != SEEN"),
+			      cookie_result);
+			do_trivial = 1;
+		}
+	}
+
+	if (do_flush)
+		with_lock__do_force_resync(state);
+
+	/*
+	 * We mark the current head of the batch list as "pinned" so
+	 * that the listener thread will treat this item as read-only
+	 * (and prevent any more paths from being added to it) from
+	 * now on.
+	 */
+	token_data = state->current_token_data;
+	batch_head = token_data->batch_head;
+	((struct fsmonitor_batch *)batch_head)->pinned_time = time(NULL);
+
+	/*
+	 * FSMonitor Protocol V2 requires that we send a response header
+	 * with a "new current token" and then all of the paths that changed
+	 * since the "requested token".  We send the seq_nr of the just-pinned
+	 * head batch so that future requests from a client will be relative
+	 * to it.
+	 */
+	with_lock__format_response_token(&response_token,
+					 &token_data->token_id, batch_head);
+
+	reply(reply_data, response_token.buf, response_token.len + 1);
+	total_response_len += response_token.len + 1;
+
+	trace2_data_string("fsmonitor", the_repository, "response/token",
+			   response_token.buf);
+	trace_printf_key(&trace_fsmonitor, "response token: %s",
+			 response_token.buf);
+
+	if (!do_trivial) {
+		if (strcmp(requested_token_id.buf, token_data->token_id.buf)) {
+			/*
+			 * The client last spoke to a different daemon
+			 * instance -OR- the daemon had to resync with
+			 * the filesystem (and lost events), so reject.
+			 */
+			trace2_data_string("fsmonitor", the_repository,
+					   "response/token", "different");
+			do_trivial = 1;
+
+		} else if (requested_oldest_seq_nr <
+			   token_data->batch_tail->batch_seq_nr) {
+			/*
+			 * The client wants older events than we have for
+			 * this token_id.  This means that the end of our
+			 * batch list was truncated and we cannot give the
+			 * client a complete snapshot relative to their
+			 * request.
+			 */
+			trace_printf_key(&trace_fsmonitor,
+					 "client requested truncated data");
+			do_trivial = 1;
+		}
+	}
+
+	if (do_trivial) {
+		pthread_mutex_unlock(&state->main_lock);
+
+		reply(reply_data, "/", 2);
+
+		trace2_data_intmax("fsmonitor", the_repository,
+				   "response/trivial", 1);
+
+		goto cleanup;
+	}
+
+	/*
+	 * We're going to hold onto a pointer to the current
+	 * token-data while we walk the list of batches of files.
+	 * During this time, we will NOT be under the lock.
+	 * So we ref-count it.
+	 *
+	 * This allows the listener thread to continue prepending
+	 * new batches of items to the token-data (which we'll ignore).
+	 *
+	 * AND it allows the listener thread to do a token-reset
+	 * (and install a new `current_token_data`).
+	 */
+	token_data->client_ref_count++;
+
+	pthread_mutex_unlock(&state->main_lock);
+
+	/*
+	 * The client request is relative to the token that they sent,
+	 * so walk the batch list backwards from the current head back
+	 * to the batch (sequence number) they named.
+	 *
+	 * We use khash to de-dup the list of pathnames.
+	 *
+	 * NEEDSWORK: each batch contains a list of interned strings,
+	 * so we only need to do pointer comparisons here to build the
+	 * hash table.  Currently, we're still comparing the string
+	 * values.
+	 */
+	shown = kh_init_str();
+	for (batch = batch_head;
+	     batch && batch->batch_seq_nr > requested_oldest_seq_nr;
+	     batch = batch->next) {
+		size_t k;
+
+		for (k = 0; k < batch->nr; k++) {
+			const char *s = batch->interned_paths[k];
+			size_t s_len;
+
+			if (kh_get_str(shown, s) != kh_end(shown))
+				duplicates++;
+			else {
+				kh_put_str(shown, s, &hash_ret);
+
+				trace_printf_key(&trace_fsmonitor,
+						 "send[%"PRIuMAX"]: %s",
+						 count, s);
+
+				/* Each path gets written with a trailing NUL */
+				s_len = strlen(s) + 1;
+
+				if (payload.len + s_len >=
+				    LARGE_PACKET_DATA_MAX) {
+					reply(reply_data, payload.buf,
+					      payload.len);
+					total_response_len += payload.len;
+					strbuf_reset(&payload);
+				}
+
+				strbuf_add(&payload, s, s_len);
+				count++;
+			}
+		}
+	}
+
+	if (payload.len) {
+		reply(reply_data, payload.buf, payload.len);
+		total_response_len += payload.len;
+	}
+
+	kh_release_str(shown);
+
+	pthread_mutex_lock(&state->main_lock);
+
+	if (token_data->client_ref_count > 0)
+		token_data->client_ref_count--;
+
+	if (token_data->client_ref_count == 0) {
+		if (token_data != state->current_token_data) {
+			/*
+			 * The listener thread did a token-reset while we were
+			 * walking the batch list.  Therefore, this token is
+			 * stale and can be discarded completely.  If we are
+			 * the last reader thread using this token, we own
+			 * that work.
+			 */
+			fsmonitor_free_token_data(token_data);
+		} else if (batch) {
+			/*
+			 * We are holding the lock and are the only
+			 * reader of the ref-counted portion of the
+			 * list, so we get the honor of seeing if the
+			 * list can be truncated to save memory.
+			 *
+			 * The main loop did not walk to the end of the
+			 * list, so this batch is the first item in the
+			 * batch-list that is older than the requested
+			 * end-point sequence number.  See if the tail
+			 * end of the list is obsolete.
+			 */
+			remainder = with_lock__truncate_old_batches(state,
+								    batch);
+		}
+	}
+
+	pthread_mutex_unlock(&state->main_lock);
+
+	if (remainder)
+		fsmonitor_batch__free_list(remainder);
+
+	trace2_data_intmax("fsmonitor", the_repository, "response/length", total_response_len);
+	trace2_data_intmax("fsmonitor", the_repository, "response/count/files", count);
+	trace2_data_intmax("fsmonitor", the_repository, "response/count/duplicates", duplicates);
+
+cleanup:
+	strbuf_release(&response_token);
+	strbuf_release(&requested_token_id);
+	strbuf_release(&payload);
+
+	return 0;
+}
+
+static ipc_server_application_cb handle_client;
+
+static int handle_client(void *data,
+			 const char *command, size_t command_len,
+			 ipc_server_reply_cb *reply,
+			 struct ipc_server_reply_data *reply_data)
+{
+	struct fsmonitor_daemon_state *state = data;
+	int result;
+
+	/*
+	 * The Simple IPC API now supports {char*, len} arguments, but
+	 * FSMonitor always uses proper null-terminated strings, so
+	 * we can ignore the command_len argument.  (Trust, but verify.)
+	 */
+	if (command_len != strlen(command))
+		BUG("FSMonitor assumes text messages");
+
+	trace_printf_key(&trace_fsmonitor, "requested token: %s", command);
+
+	trace2_region_enter("fsmonitor", "handle_client", the_repository);
+	trace2_data_string("fsmonitor", the_repository, "request", command);
+
+	result = do_handle_client(state, command, reply, reply_data);
+
+	trace2_region_leave("fsmonitor", "handle_client", the_repository);
+
+	return result;
+}
+
+#define FSMONITOR_DIR           "fsmonitor--daemon"
+#define FSMONITOR_COOKIE_DIR    "cookies"
+#define FSMONITOR_COOKIE_PREFIX (FSMONITOR_DIR "/" FSMONITOR_COOKIE_DIR "/")
+
+enum fsmonitor_path_type fsmonitor_classify_path_workdir_relative(
+	const char *rel)
+{
+	if (fspathncmp(rel, ".git", 4))
+		return IS_WORKDIR_PATH;
+	rel += 4;
+
+	if (!*rel)
+		return IS_DOT_GIT;
+	if (*rel != '/')
+		return IS_WORKDIR_PATH; /* e.g. .gitignore */
+	rel++;
+
+	if (!fspathncmp(rel, FSMONITOR_COOKIE_PREFIX,
+			strlen(FSMONITOR_COOKIE_PREFIX)))
+		return IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX;
+
+	return IS_INSIDE_DOT_GIT;
+}
+
+enum fsmonitor_path_type fsmonitor_classify_path_gitdir_relative(
+	const char *rel)
+{
+	if (!fspathncmp(rel, FSMONITOR_COOKIE_PREFIX,
+			strlen(FSMONITOR_COOKIE_PREFIX)))
+		return IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX;
+
+	return IS_INSIDE_GITDIR;
+}
+
+static enum fsmonitor_path_type try_classify_workdir_abs_path(
+	struct fsmonitor_daemon_state *state,
+	const char *path)
+{
+	const char *rel;
+
+	if (fspathncmp(path, state->path_worktree_watch.buf,
+		       state->path_worktree_watch.len))
+		return IS_OUTSIDE_CONE;
+
+	rel = path + state->path_worktree_watch.len;
+
+	if (!*rel)
+		return IS_WORKDIR_PATH; /* it is the root dir exactly */
+	if (*rel != '/')
+		return IS_OUTSIDE_CONE;
+	rel++;
+
+	return fsmonitor_classify_path_workdir_relative(rel);
+}
+
+enum fsmonitor_path_type fsmonitor_classify_path_absolute(
+	struct fsmonitor_daemon_state *state,
+	const char *path)
+{
+	const char *rel;
+	enum fsmonitor_path_type t;
+
+	t = try_classify_workdir_abs_path(state, path);
+	if (state->nr_paths_watching == 1)
+		return t;
+	if (t != IS_OUTSIDE_CONE)
+		return t;
+
+	if (fspathncmp(path, state->path_gitdir_watch.buf,
+		       state->path_gitdir_watch.len))
+		return IS_OUTSIDE_CONE;
+
+	rel = path + state->path_gitdir_watch.len;
+
+	if (!*rel)
+		return IS_GITDIR; /* it is the <gitdir> exactly */
+	if (*rel != '/')
+		return IS_OUTSIDE_CONE;
+	rel++;
+
+	return fsmonitor_classify_path_gitdir_relative(rel);
+}
+
+/*
+ * We try to combine small batches at the front of the batch-list to avoid
+ * having a long list.  This hopefully makes it a little easier when we want
+ * to truncate and maintain the list.  However, we don't want the paths array
+ * to just keep growing and growing with realloc, so we insert an arbitrary
+ * limit.
+ */
+#define MY_COMBINE_LIMIT (1024)
+
+void fsmonitor_publish(struct fsmonitor_daemon_state *state,
+		       struct fsmonitor_batch *batch,
+		       const struct string_list *cookie_names)
+{
+	if (!batch && !cookie_names->nr)
+		return;
+
+	pthread_mutex_lock(&state->main_lock);
+
+	if (batch) {
+		struct fsmonitor_batch *head;
+
+		head = state->current_token_data->batch_head;
+		if (!head) {
+			BUG("token does not have batch");
+		} else if (head->pinned_time) {
+			/*
+			 * We cannot alter the current batch list
+			 * because:
+			 *
+			 * [a] it is being transmitted to at least one
+			 * client and the handle_client() thread has a
+			 * ref-count, but not a lock on the batch list
+			 * starting with this item.
+			 *
+			 * [b] it has been transmitted in the past to
+			 * at least one client such that future
+			 * requests are relative to this head batch.
+			 *
+			 * So, we can only prepend a new batch onto
+			 * the front of the list.
+			 */
+			batch->batch_seq_nr = head->batch_seq_nr + 1;
+			batch->next = head;
+			state->current_token_data->batch_head = batch;
+		} else if (!head->batch_seq_nr) {
+			/*
+			 * Batch 0 is unpinned.  See the note in
+			 * `fsmonitor_new_token_data()` about why we
+			 * don't need to accumulate these paths.
+			 */
+			fsmonitor_batch__free_list(batch);
+		} else if (head->nr + batch->nr > MY_COMBINE_LIMIT) {
+			/*
+			 * The head batch in the list has never been
+			 * transmitted to a client, but folding the
+			 * contents of the new batch onto it would
+			 * exceed our arbitrary limit, so just prepend
+			 * the new batch onto the list.
+			 */
+			batch->batch_seq_nr = head->batch_seq_nr + 1;
+			batch->next = head;
+			state->current_token_data->batch_head = batch;
+		} else {
+			/*
+			 * We are free to add the paths in the given
+			 * batch onto the end of the current head batch.
+			 */
+			fsmonitor_batch__combine(head, batch);
+			fsmonitor_batch__free_list(batch);
+		}
+	}
+
+	if (cookie_names->nr)
+		with_lock__mark_cookies_seen(state, cookie_names);
+
+	pthread_mutex_unlock(&state->main_lock);
+}
+
+static void *fsm_health__thread_proc(void *_state)
+{
+	struct fsmonitor_daemon_state *state = _state;
+
+	trace2_thread_start("fsm-health");
+
+	fsm_health__loop(state);
+
+	trace2_thread_exit();
+	return NULL;
+}
+
+static void *fsm_listen__thread_proc(void *_state)
+{
+	struct fsmonitor_daemon_state *state = _state;
+
+	trace2_thread_start("fsm-listen");
+
+	trace_printf_key(&trace_fsmonitor, "Watching: worktree '%s'",
+			 state->path_worktree_watch.buf);
+	if (state->nr_paths_watching > 1)
+		trace_printf_key(&trace_fsmonitor, "Watching: gitdir '%s'",
+				 state->path_gitdir_watch.buf);
+
+	fsm_listen__loop(state);
+
+	pthread_mutex_lock(&state->main_lock);
+	if (state->current_token_data &&
+	    state->current_token_data->client_ref_count == 0)
+		fsmonitor_free_token_data(state->current_token_data);
+	state->current_token_data = NULL;
+	pthread_mutex_unlock(&state->main_lock);
+
+	trace2_thread_exit();
+	return NULL;
+}
+
+static int fsmonitor_run_daemon_1(struct fsmonitor_daemon_state *state)
+{
+	struct ipc_server_opts ipc_opts = {
+		.nr_threads = fsmonitor__ipc_threads,
+
+		/*
+		 * We know that there are no other active threads yet,
+		 * so we can let the IPC layer temporarily chdir() if
+		 * it needs to when creating the server side of the
+		 * Unix domain socket.
+		 */
+		.uds_disallow_chdir = 0
+	};
+	int health_started = 0;
+	int listener_started = 0;
+	int err = 0;
+
+	/*
+	 * Start the IPC thread pool before the we've started the file
+	 * system event listener thread so that we have the IPC handle
+	 * before we need it.
+	 */
+	if (ipc_server_init_async(&state->ipc_server_data,
+				  state->path_ipc.buf, &ipc_opts,
+				  handle_client, state))
+		return error_errno(
+			_("could not start IPC thread pool on '%s'"),
+			state->path_ipc.buf);
+
+	/*
+	 * Start the fsmonitor listener thread to collect filesystem
+	 * events.
+	 */
+	if (pthread_create(&state->listener_thread, NULL,
+			   fsm_listen__thread_proc, state)) {
+		ipc_server_stop_async(state->ipc_server_data);
+		err = error(_("could not start fsmonitor listener thread"));
+		goto cleanup;
+	}
+	listener_started = 1;
+
+	/*
+	 * Start the health thread to watch over our process.
+	 */
+	if (pthread_create(&state->health_thread, NULL,
+			   fsm_health__thread_proc, state)) {
+		ipc_server_stop_async(state->ipc_server_data);
+		err = error(_("could not start fsmonitor health thread"));
+		goto cleanup;
+	}
+	health_started = 1;
+
+	/*
+	 * The daemon is now fully functional in background threads.
+	 * Our primary thread should now just wait while the threads
+	 * do all the work.
+	 */
+cleanup:
+	/*
+	 * Wait for the IPC thread pool to shutdown (whether by client
+	 * request, from filesystem activity, or an error).
+	 */
+	ipc_server_await(state->ipc_server_data);
+
+	/*
+	 * The fsmonitor listener thread may have received a shutdown
+	 * event from the IPC thread pool, but it doesn't hurt to tell
+	 * it again.  And wait for it to shutdown.
+	 */
+	if (listener_started) {
+		fsm_listen__stop_async(state);
+		pthread_join(state->listener_thread, NULL);
+	}
+
+	if (health_started) {
+		fsm_health__stop_async(state);
+		pthread_join(state->health_thread, NULL);
+	}
+
+	if (err)
+		return err;
+	if (state->listen_error_code)
+		return state->listen_error_code;
+	if (state->health_error_code)
+		return state->health_error_code;
+	return 0;
+}
+
+static int fsmonitor_run_daemon(void)
+{
+	struct fsmonitor_daemon_state state;
+	const char *home;
+	int err;
+
+	memset(&state, 0, sizeof(state));
+
+	hashmap_init(&state.cookies, cookies_cmp, NULL, 0);
+	pthread_mutex_init(&state.main_lock, NULL);
+	pthread_cond_init(&state.cookies_cond, NULL);
+	state.listen_error_code = 0;
+	state.health_error_code = 0;
+	state.current_token_data = fsmonitor_new_token_data();
+
+	/* Prepare to (recursively) watch the <worktree-root> directory. */
+	strbuf_init(&state.path_worktree_watch, 0);
+	strbuf_addstr(&state.path_worktree_watch,
+		      absolute_path(repo_get_work_tree(the_repository)));
+	state.nr_paths_watching = 1;
+
+	strbuf_init(&state.alias.alias, 0);
+	strbuf_init(&state.alias.points_to, 0);
+	if ((err = fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias)))
+		goto done;
+
+	/*
+	 * We create and delete cookie files somewhere inside the .git
+	 * directory to help us keep sync with the file system.  If
+	 * ".git" is not a directory, then <gitdir> is not inside the
+	 * cone of <worktree-root>, so set up a second watch to watch
+	 * the <gitdir> so that we get events for the cookie files.
+	 */
+	strbuf_init(&state.path_gitdir_watch, 0);
+	strbuf_addbuf(&state.path_gitdir_watch, &state.path_worktree_watch);
+	strbuf_addstr(&state.path_gitdir_watch, "/.git");
+	if (!is_directory(state.path_gitdir_watch.buf)) {
+		strbuf_reset(&state.path_gitdir_watch);
+		strbuf_addstr(&state.path_gitdir_watch,
+			      absolute_path(repo_get_git_dir(the_repository)));
+		strbuf_strip_suffix(&state.path_gitdir_watch, "/.");
+		state.nr_paths_watching = 2;
+	}
+
+	/*
+	 * We will write filesystem syncing cookie files into
+	 * <gitdir>/<fsmonitor-dir>/<cookie-dir>/<pid>-<seq>.
+	 *
+	 * The extra layers of subdirectories here keep us from
+	 * changing the mtime on ".git/" or ".git/foo/" when we create
+	 * or delete cookie files.
+	 *
+	 * There have been problems with some IDEs that do a
+	 * non-recursive watch of the ".git/" directory and run a
+	 * series of commands any time something happens.
+	 *
+	 * For example, if we place our cookie files directly in
+	 * ".git/" or ".git/foo/" then a `git status` (or similar
+	 * command) from the IDE will cause a cookie file to be
+	 * created in one of those dirs.  This causes the mtime of
+	 * those dirs to change.  This triggers the IDE's watch
+	 * notification.  This triggers the IDE to run those commands
+	 * again.  And the process repeats and the machine never goes
+	 * idle.
+	 *
+	 * Adding the extra layers of subdirectories prevents the
+	 * mtime of ".git/" and ".git/foo" from changing when a
+	 * cookie file is created.
+	 */
+	strbuf_init(&state.path_cookie_prefix, 0);
+	strbuf_addbuf(&state.path_cookie_prefix, &state.path_gitdir_watch);
+
+	strbuf_addch(&state.path_cookie_prefix, '/');
+	strbuf_addstr(&state.path_cookie_prefix, FSMONITOR_DIR);
+	mkdir(state.path_cookie_prefix.buf, 0777);
+
+	strbuf_addch(&state.path_cookie_prefix, '/');
+	strbuf_addstr(&state.path_cookie_prefix, FSMONITOR_COOKIE_DIR);
+	mkdir(state.path_cookie_prefix.buf, 0777);
+
+	strbuf_addch(&state.path_cookie_prefix, '/');
+
+	/*
+	 * We create a named-pipe or unix domain socket inside of the
+	 * ".git" directory.  (Well, on Windows, we base our named
+	 * pipe in the NPFS on the absolute path of the git
+	 * directory.)
+	 */
+	strbuf_init(&state.path_ipc, 0);
+	strbuf_addstr(&state.path_ipc,
+		absolute_path(fsmonitor_ipc__get_path(the_repository)));
+
+	/*
+	 * Confirm that we can create platform-specific resources for the
+	 * filesystem listener before we bother starting all the threads.
+	 */
+	if (fsm_listen__ctor(&state)) {
+		err = error(_("could not initialize listener thread"));
+		goto done;
+	}
+
+	if (fsm_health__ctor(&state)) {
+		err = error(_("could not initialize health thread"));
+		goto done;
+	}
+
+	/*
+	 * CD out of the worktree root directory.
+	 *
+	 * The common Git startup mechanism causes our CWD to be the
+	 * root of the worktree.  On Windows, this causes our process
+	 * to hold a locked handle on the CWD.  This prevents the
+	 * worktree from being moved or deleted while the daemon is
+	 * running.
+	 *
+	 * We assume that our FS and IPC listener threads have either
+	 * opened all of the handles that they need or will do
+	 * everything using absolute paths.
+	 */
+	home = getenv("HOME");
+	if (home && *home && chdir(home))
+		die_errno(_("could not cd home '%s'"), home);
+
+	err = fsmonitor_run_daemon_1(&state);
+
+done:
+	pthread_cond_destroy(&state.cookies_cond);
+	pthread_mutex_destroy(&state.main_lock);
+	fsm_listen__dtor(&state);
+	fsm_health__dtor(&state);
+
+	ipc_server_free(state.ipc_server_data);
+
+	strbuf_release(&state.path_worktree_watch);
+	strbuf_release(&state.path_gitdir_watch);
+	strbuf_release(&state.path_cookie_prefix);
+	strbuf_release(&state.path_ipc);
+	strbuf_release(&state.alias.alias);
+	strbuf_release(&state.alias.points_to);
+
+	return err;
+}
+
+static int try_to_run_foreground_daemon(int detach_console MAYBE_UNUSED)
+{
+	/*
+	 * Technically, we don't need to probe for an existing daemon
+	 * process, since we could just call `fsmonitor_run_daemon()`
+	 * and let it fail if the pipe/socket is busy.
+	 *
+	 * However, this method gives us a nicer error message for a
+	 * common error case.
+	 */
+	if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
+		die(_("fsmonitor--daemon is already running '%s'"),
+		    the_repository->worktree);
+
+	if (fsmonitor__announce_startup) {
+		fprintf(stderr, _("running fsmonitor-daemon in '%s'\n"),
+			the_repository->worktree);
+		fflush(stderr);
+	}
+
+#ifdef GIT_WINDOWS_NATIVE
+	if (detach_console)
+		FreeConsole();
+#endif
+
+	return !!fsmonitor_run_daemon();
+}
+
+static start_bg_wait_cb bg_wait_cb;
+
+static int bg_wait_cb(const struct child_process *cp UNUSED,
+		      void *cb_data UNUSED)
+{
+	enum ipc_active_state s = fsmonitor_ipc__get_state();
+
+	switch (s) {
+	case IPC_STATE__LISTENING:
+		/* child is "ready" */
+		return 0;
+
+	case IPC_STATE__NOT_LISTENING:
+	case IPC_STATE__PATH_NOT_FOUND:
+		/* give child more time */
+		return 1;
+
+	default:
+	case IPC_STATE__INVALID_PATH:
+	case IPC_STATE__OTHER_ERROR:
+		/* all the time in world won't help */
+		return -1;
+	}
+}
+
+static int try_to_start_background_daemon(void)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+	enum start_bg_result sbgr;
+
+	/*
+	 * Before we try to create a background daemon process, see
+	 * if a daemon process is already listening.  This makes it
+	 * easier for us to report an already-listening error to the
+	 * console, since our spawn/daemon can only report the success
+	 * of creating the background process (and not whether it
+	 * immediately exited).
+	 */
+	if (fsmonitor_ipc__get_state() == IPC_STATE__LISTENING)
+		die(_("fsmonitor--daemon is already running '%s'"),
+		    the_repository->worktree);
+
+	if (fsmonitor__announce_startup) {
+		fprintf(stderr, _("starting fsmonitor-daemon in '%s'\n"),
+			the_repository->worktree);
+		fflush(stderr);
+	}
+
+	cp.git_cmd = 1;
+
+	strvec_push(&cp.args, "fsmonitor--daemon");
+	strvec_push(&cp.args, "run");
+	strvec_push(&cp.args, "--detach");
+	strvec_pushf(&cp.args, "--ipc-threads=%d", fsmonitor__ipc_threads);
+
+	cp.no_stdin = 1;
+	cp.no_stdout = 1;
+	cp.no_stderr = 1;
+
+	sbgr = start_bg_command(&cp, bg_wait_cb, NULL,
+				fsmonitor__start_timeout_sec);
+
+	switch (sbgr) {
+	case SBGR_READY:
+		return 0;
+
+	default:
+	case SBGR_ERROR:
+	case SBGR_CB_ERROR:
+		return error(_("daemon failed to start"));
+
+	case SBGR_TIMEOUT:
+		return error(_("daemon not online yet"));
+
+	case SBGR_DIED:
+		return error(_("daemon terminated"));
+	}
+}
+
+int cmd_fsmonitor__daemon(int argc,
+			  const char **argv,
+			  const char *prefix,
+			  struct repository *repo UNUSED)
+{
+	const char *subcmd;
+	enum fsmonitor_reason reason;
+	int detach_console = 0;
+
+	struct option options[] = {
+		OPT_BOOL(0, "detach", &detach_console, N_("detach from console")),
+		OPT_INTEGER(0, "ipc-threads",
+			    &fsmonitor__ipc_threads,
+			    N_("use <n> ipc worker threads")),
+		OPT_INTEGER(0, "start-timeout",
+			    &fsmonitor__start_timeout_sec,
+			    N_("max seconds to wait for background daemon startup")),
+
+		OPT_END()
+	};
+
+	git_config(fsmonitor_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_fsmonitor__daemon_usage, 0);
+	if (argc != 1)
+		usage_with_options(builtin_fsmonitor__daemon_usage, options);
+	subcmd = argv[0];
+
+	if (fsmonitor__ipc_threads < 1)
+		die(_("invalid 'ipc-threads' value (%d)"),
+		    fsmonitor__ipc_threads);
+
+	prepare_repo_settings(the_repository);
+	/*
+	 * If the repo is fsmonitor-compatible, explicitly set IPC-mode
+	 * (without bothering to load the `core.fsmonitor` config settings).
+	 *
+	 * If the repo is not compatible, the repo-settings will be set to
+	 * incompatible rather than IPC, so we can use one of the __get
+	 * routines to detect the discrepancy.
+	 */
+	fsm_settings__set_ipc(the_repository);
+
+	reason = fsm_settings__get_reason(the_repository);
+	if (reason > FSMONITOR_REASON_OK)
+		die("%s",
+		    fsm_settings__get_incompatible_msg(the_repository,
+						       reason));
+
+	if (!strcmp(subcmd, "start"))
+		return !!try_to_start_background_daemon();
+
+	if (!strcmp(subcmd, "run"))
+		return !!try_to_run_foreground_daemon(detach_console);
+
+	if (!strcmp(subcmd, "stop"))
+		return !!do_as_client__send_stop();
+
+	if (!strcmp(subcmd, "status"))
+		return !!do_as_client__status();
+
+	die(_("Unhandled subcommand '%s'"), subcmd);
+}
+
+#else
+int cmd_fsmonitor__daemon(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_fsmonitor__daemon_usage, options);
+
+	die(_("fsmonitor--daemon not supported on this platform"));
+}
+#endif
diff --git a/builtin/gc.c b/builtin/gc.c
new file mode 100644
index 0000000000..0bf3533494
--- /dev/null
+++ b/builtin/gc.c
@@ -0,0 +1,3015 @@
+/*
+ * git gc builtin command
+ *
+ * Cleanup unreachable files and optimize the repository.
+ *
+ * Copyright (c) 2007 James Bowes
+ *
+ * Based on git-gc.sh, which is
+ *
+ * Copyright (c) 2006 Shawn O. Pearce
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+#include "date.h"
+#include "environment.h"
+#include "hex.h"
+#include "config.h"
+#include "tempfile.h"
+#include "lockfile.h"
+#include "parse-options.h"
+#include "run-command.h"
+#include "sigchain.h"
+#include "strvec.h"
+#include "commit.h"
+#include "commit-graph.h"
+#include "packfile.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "pack.h"
+#include "pack-objects.h"
+#include "path.h"
+#include "blob.h"
+#include "tree.h"
+#include "promisor-remote.h"
+#include "refs.h"
+#include "remote.h"
+#include "exec-cmd.h"
+#include "gettext.h"
+#include "hook.h"
+#include "setup.h"
+#include "trace2.h"
+
+#define FAILED_RUN "failed to run %s"
+
+static const char * const builtin_gc_usage[] = {
+	N_("git gc [<options>]"),
+	NULL
+};
+
+static timestamp_t gc_log_expire_time;
+
+static struct strvec reflog = STRVEC_INIT;
+static struct strvec repack = STRVEC_INIT;
+static struct strvec prune = STRVEC_INIT;
+static struct strvec prune_worktrees = STRVEC_INIT;
+static struct strvec rerere = STRVEC_INIT;
+
+static struct tempfile *pidfile;
+static struct lock_file log_lock;
+
+static struct string_list pack_garbage = STRING_LIST_INIT_DUP;
+
+static void clean_pack_garbage(void)
+{
+	int i;
+	for (i = 0; i < pack_garbage.nr; i++)
+		unlink_or_warn(pack_garbage.items[i].string);
+	string_list_clear(&pack_garbage, 0);
+}
+
+static void report_pack_garbage(unsigned seen_bits, const char *path)
+{
+	if (seen_bits == PACKDIR_FILE_IDX)
+		string_list_append(&pack_garbage, path);
+}
+
+static void process_log_file(void)
+{
+	struct stat st;
+	if (fstat(get_lock_file_fd(&log_lock), &st)) {
+		/*
+		 * Perhaps there was an i/o error or another
+		 * unlikely situation.  Try to make a note of
+		 * this in gc.log along with any existing
+		 * messages.
+		 */
+		int saved_errno = errno;
+		fprintf(stderr, _("Failed to fstat %s: %s"),
+			get_lock_file_path(&log_lock),
+			strerror(saved_errno));
+		fflush(stderr);
+		commit_lock_file(&log_lock);
+		errno = saved_errno;
+	} else if (st.st_size) {
+		/* There was some error recorded in the lock file */
+		commit_lock_file(&log_lock);
+	} else {
+		/* No error, clean up any old gc.log */
+		unlink(git_path("gc.log"));
+		rollback_lock_file(&log_lock);
+	}
+}
+
+static void process_log_file_at_exit(void)
+{
+	fflush(stderr);
+	process_log_file();
+}
+
+static int gc_config_is_timestamp_never(const char *var)
+{
+	const char *value;
+	timestamp_t expire;
+
+	if (!git_config_get_value(var, &value) && value) {
+		if (parse_expiry_date(value, &expire))
+			die(_("failed to parse '%s' value '%s'"), var, value);
+		return expire == 0;
+	}
+	return 0;
+}
+
+struct gc_config {
+	int pack_refs;
+	int prune_reflogs;
+	int cruft_packs;
+	unsigned long max_cruft_size;
+	int aggressive_depth;
+	int aggressive_window;
+	int gc_auto_threshold;
+	int gc_auto_pack_limit;
+	int detach_auto;
+	char *gc_log_expire;
+	char *prune_expire;
+	char *prune_worktrees_expire;
+	char *repack_filter;
+	char *repack_filter_to;
+	unsigned long big_pack_threshold;
+	unsigned long max_delta_cache_size;
+	/*
+	 * Remove this member from gc_config once repo_settings is passed
+	 * through the callchain.
+	 */
+	size_t delta_base_cache_limit;
+};
+
+#define GC_CONFIG_INIT { \
+	.pack_refs = 1, \
+	.prune_reflogs = 1, \
+	.cruft_packs = 1, \
+	.aggressive_depth = 50, \
+	.aggressive_window = 250, \
+	.gc_auto_threshold = 6700, \
+	.gc_auto_pack_limit = 50, \
+	.detach_auto = 1, \
+	.gc_log_expire = xstrdup("1.day.ago"), \
+	.prune_expire = xstrdup("2.weeks.ago"), \
+	.prune_worktrees_expire = xstrdup("3.months.ago"), \
+	.max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE, \
+	.delta_base_cache_limit = DEFAULT_DELTA_BASE_CACHE_LIMIT, \
+}
+
+static void gc_config_release(struct gc_config *cfg)
+{
+	free(cfg->gc_log_expire);
+	free(cfg->prune_expire);
+	free(cfg->prune_worktrees_expire);
+	free(cfg->repack_filter);
+	free(cfg->repack_filter_to);
+}
+
+static void gc_config(struct gc_config *cfg)
+{
+	const char *value;
+	char *owned = NULL;
+	unsigned long ulongval;
+
+	if (!git_config_get_value("gc.packrefs", &value)) {
+		if (value && !strcmp(value, "notbare"))
+			cfg->pack_refs = -1;
+		else
+			cfg->pack_refs = git_config_bool("gc.packrefs", value);
+	}
+
+	if (gc_config_is_timestamp_never("gc.reflogexpire") &&
+	    gc_config_is_timestamp_never("gc.reflogexpireunreachable"))
+		cfg->prune_reflogs = 0;
+
+	git_config_get_int("gc.aggressivewindow", &cfg->aggressive_window);
+	git_config_get_int("gc.aggressivedepth", &cfg->aggressive_depth);
+	git_config_get_int("gc.auto", &cfg->gc_auto_threshold);
+	git_config_get_int("gc.autopacklimit", &cfg->gc_auto_pack_limit);
+	git_config_get_bool("gc.autodetach", &cfg->detach_auto);
+	git_config_get_bool("gc.cruftpacks", &cfg->cruft_packs);
+	git_config_get_ulong("gc.maxcruftsize", &cfg->max_cruft_size);
+
+	if (!repo_config_get_expiry(the_repository, "gc.pruneexpire", &owned)) {
+		free(cfg->prune_expire);
+		cfg->prune_expire = owned;
+	}
+
+	if (!repo_config_get_expiry(the_repository, "gc.worktreepruneexpire", &owned)) {
+		free(cfg->prune_worktrees_expire);
+		cfg->prune_worktrees_expire = owned;
+	}
+
+	if (!repo_config_get_expiry(the_repository, "gc.logexpiry", &owned)) {
+		free(cfg->gc_log_expire);
+		cfg->gc_log_expire = owned;
+	}
+
+	git_config_get_ulong("gc.bigpackthreshold", &cfg->big_pack_threshold);
+	git_config_get_ulong("pack.deltacachesize", &cfg->max_delta_cache_size);
+
+	if (!git_config_get_ulong("core.deltabasecachelimit", &ulongval))
+		cfg->delta_base_cache_limit = ulongval;
+
+	if (!git_config_get_string("gc.repackfilter", &owned)) {
+		free(cfg->repack_filter);
+		cfg->repack_filter = owned;
+	}
+
+	if (!git_config_get_string("gc.repackfilterto", &owned)) {
+		free(cfg->repack_filter_to);
+		cfg->repack_filter_to = owned;
+	}
+
+	git_config(git_default_config, NULL);
+}
+
+enum schedule_priority {
+	SCHEDULE_NONE = 0,
+	SCHEDULE_WEEKLY = 1,
+	SCHEDULE_DAILY = 2,
+	SCHEDULE_HOURLY = 3,
+};
+
+static enum schedule_priority parse_schedule(const char *value)
+{
+	if (!value)
+		return SCHEDULE_NONE;
+	if (!strcasecmp(value, "hourly"))
+		return SCHEDULE_HOURLY;
+	if (!strcasecmp(value, "daily"))
+		return SCHEDULE_DAILY;
+	if (!strcasecmp(value, "weekly"))
+		return SCHEDULE_WEEKLY;
+	return SCHEDULE_NONE;
+}
+
+struct maintenance_run_opts {
+	int auto_flag;
+	int detach;
+	int quiet;
+	enum schedule_priority schedule;
+};
+#define MAINTENANCE_RUN_OPTS_INIT { \
+	.detach = -1, \
+}
+
+static int pack_refs_condition(UNUSED struct gc_config *cfg)
+{
+	/*
+	 * The auto-repacking logic for refs is handled by the ref backends and
+	 * exposed via `git pack-refs --auto`. We thus always return truish
+	 * here and let the backend decide for us.
+	 */
+	return 1;
+}
+
+static int maintenance_task_pack_refs(struct maintenance_run_opts *opts,
+				      UNUSED struct gc_config *cfg)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	cmd.git_cmd = 1;
+	strvec_pushl(&cmd.args, "pack-refs", "--all", "--prune", NULL);
+	if (opts->auto_flag)
+		strvec_push(&cmd.args, "--auto");
+
+	return run_command(&cmd);
+}
+
+static int too_many_loose_objects(struct gc_config *cfg)
+{
+	/*
+	 * Quickly check if a "gc" is needed, by estimating how
+	 * many loose objects there are.  Because SHA-1 is evenly
+	 * distributed, we can check only one and get a reasonable
+	 * estimate.
+	 */
+	DIR *dir;
+	struct dirent *ent;
+	int auto_threshold;
+	int num_loose = 0;
+	int needed = 0;
+	const unsigned hexsz_loose = the_hash_algo->hexsz - 2;
+
+	dir = opendir(git_path("objects/17"));
+	if (!dir)
+		return 0;
+
+	auto_threshold = DIV_ROUND_UP(cfg->gc_auto_threshold, 256);
+	while ((ent = readdir(dir)) != NULL) {
+		if (strspn(ent->d_name, "0123456789abcdef") != hexsz_loose ||
+		    ent->d_name[hexsz_loose] != '\0')
+			continue;
+		if (++num_loose > auto_threshold) {
+			needed = 1;
+			break;
+		}
+	}
+	closedir(dir);
+	return needed;
+}
+
+static struct packed_git *find_base_packs(struct string_list *packs,
+					  unsigned long limit)
+{
+	struct packed_git *p, *base = NULL;
+
+	for (p = get_all_packs(the_repository); p; p = p->next) {
+		if (!p->pack_local || p->is_cruft)
+			continue;
+		if (limit) {
+			if (p->pack_size >= limit)
+				string_list_append(packs, p->pack_name);
+		} else if (!base || base->pack_size < p->pack_size) {
+			base = p;
+		}
+	}
+
+	if (base)
+		string_list_append(packs, base->pack_name);
+
+	return base;
+}
+
+static int too_many_packs(struct gc_config *cfg)
+{
+	struct packed_git *p;
+	int cnt;
+
+	if (cfg->gc_auto_pack_limit <= 0)
+		return 0;
+
+	for (cnt = 0, p = get_all_packs(the_repository); p; p = p->next) {
+		if (!p->pack_local)
+			continue;
+		if (p->pack_keep)
+			continue;
+		/*
+		 * Perhaps check the size of the pack and count only
+		 * very small ones here?
+		 */
+		cnt++;
+	}
+	return cfg->gc_auto_pack_limit < cnt;
+}
+
+static uint64_t total_ram(void)
+{
+#if defined(HAVE_SYSINFO)
+	struct sysinfo si;
+
+	if (!sysinfo(&si))
+		return si.totalram;
+#elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM))
+	int64_t physical_memory;
+	int mib[2];
+	size_t length;
+
+	mib[0] = CTL_HW;
+# if defined(HW_MEMSIZE)
+	mib[1] = HW_MEMSIZE;
+# else
+	mib[1] = HW_PHYSMEM;
+# endif
+	length = sizeof(int64_t);
+	if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0))
+		return physical_memory;
+#elif defined(GIT_WINDOWS_NATIVE)
+	MEMORYSTATUSEX memInfo;
+
+	memInfo.dwLength = sizeof(MEMORYSTATUSEX);
+	if (GlobalMemoryStatusEx(&memInfo))
+		return memInfo.ullTotalPhys;
+#endif
+	return 0;
+}
+
+static uint64_t estimate_repack_memory(struct gc_config *cfg,
+				       struct packed_git *pack)
+{
+	unsigned long nr_objects = repo_approximate_object_count(the_repository);
+	size_t os_cache, heap;
+
+	if (!pack || !nr_objects)
+		return 0;
+
+	/*
+	 * First we have to scan through at least one pack.
+	 * Assume enough room in OS file cache to keep the entire pack
+	 * or we may accidentally evict data of other processes from
+	 * the cache.
+	 */
+	os_cache = pack->pack_size + pack->index_size;
+	/* then pack-objects needs lots more for book keeping */
+	heap = sizeof(struct object_entry) * nr_objects;
+	/*
+	 * internal rev-list --all --objects takes up some memory too,
+	 * let's say half of it is for blobs
+	 */
+	heap += sizeof(struct blob) * nr_objects / 2;
+	/*
+	 * and the other half is for trees (commits and tags are
+	 * usually insignificant)
+	 */
+	heap += sizeof(struct tree) * nr_objects / 2;
+	/* and then obj_hash[], underestimated in fact */
+	heap += sizeof(struct object *) * nr_objects;
+	/* revindex is used also */
+	heap += (sizeof(off_t) + sizeof(uint32_t)) * nr_objects;
+	/*
+	 * read_sha1_file() (either at delta calculation phase, or
+	 * writing phase) also fills up the delta base cache
+	 */
+	heap += cfg->delta_base_cache_limit;
+	/* and of course pack-objects has its own delta cache */
+	heap += cfg->max_delta_cache_size;
+
+	return os_cache + heap;
+}
+
+static int keep_one_pack(struct string_list_item *item, void *data UNUSED)
+{
+	strvec_pushf(&repack, "--keep-pack=%s", basename(item->string));
+	return 0;
+}
+
+static void add_repack_all_option(struct gc_config *cfg,
+				  struct string_list *keep_pack)
+{
+	if (cfg->prune_expire && !strcmp(cfg->prune_expire, "now"))
+		strvec_push(&repack, "-a");
+	else if (cfg->cruft_packs) {
+		strvec_push(&repack, "--cruft");
+		if (cfg->prune_expire)
+			strvec_pushf(&repack, "--cruft-expiration=%s", cfg->prune_expire);
+		if (cfg->max_cruft_size)
+			strvec_pushf(&repack, "--max-cruft-size=%lu",
+				     cfg->max_cruft_size);
+	} else {
+		strvec_push(&repack, "-A");
+		if (cfg->prune_expire)
+			strvec_pushf(&repack, "--unpack-unreachable=%s", cfg->prune_expire);
+	}
+
+	if (keep_pack)
+		for_each_string_list(keep_pack, keep_one_pack, NULL);
+
+	if (cfg->repack_filter && *cfg->repack_filter)
+		strvec_pushf(&repack, "--filter=%s", cfg->repack_filter);
+	if (cfg->repack_filter_to && *cfg->repack_filter_to)
+		strvec_pushf(&repack, "--filter-to=%s", cfg->repack_filter_to);
+}
+
+static void add_repack_incremental_option(void)
+{
+	strvec_push(&repack, "--no-write-bitmap-index");
+}
+
+static int need_to_gc(struct gc_config *cfg)
+{
+	/*
+	 * Setting gc.auto to 0 or negative can disable the
+	 * automatic gc.
+	 */
+	if (cfg->gc_auto_threshold <= 0)
+		return 0;
+
+	/*
+	 * If there are too many loose objects, but not too many
+	 * packs, we run "repack -d -l".  If there are too many packs,
+	 * we run "repack -A -d -l".  Otherwise we tell the caller
+	 * there is no need.
+	 */
+	if (too_many_packs(cfg)) {
+		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+		if (cfg->big_pack_threshold) {
+			find_base_packs(&keep_pack, cfg->big_pack_threshold);
+			if (keep_pack.nr >= cfg->gc_auto_pack_limit) {
+				cfg->big_pack_threshold = 0;
+				string_list_clear(&keep_pack, 0);
+				find_base_packs(&keep_pack, 0);
+			}
+		} else {
+			struct packed_git *p = find_base_packs(&keep_pack, 0);
+			uint64_t mem_have, mem_want;
+
+			mem_have = total_ram();
+			mem_want = estimate_repack_memory(cfg, p);
+
+			/*
+			 * Only allow 1/2 of memory for pack-objects, leave
+			 * the rest for the OS and other processes in the
+			 * system.
+			 */
+			if (!mem_have || mem_want < mem_have / 2)
+				string_list_clear(&keep_pack, 0);
+		}
+
+		add_repack_all_option(cfg, &keep_pack);
+		string_list_clear(&keep_pack, 0);
+	} else if (too_many_loose_objects(cfg))
+		add_repack_incremental_option();
+	else
+		return 0;
+
+	if (run_hooks(the_repository, "pre-auto-gc"))
+		return 0;
+	return 1;
+}
+
+/* return NULL on success, else hostname running the gc */
+static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
+{
+	struct lock_file lock = LOCK_INIT;
+	char my_host[HOST_NAME_MAX + 1];
+	struct strbuf sb = STRBUF_INIT;
+	struct stat st;
+	uintmax_t pid;
+	FILE *fp;
+	int fd;
+	char *pidfile_path;
+
+	if (is_tempfile_active(pidfile))
+		/* already locked */
+		return NULL;
+
+	if (xgethostname(my_host, sizeof(my_host)))
+		xsnprintf(my_host, sizeof(my_host), "unknown");
+
+	pidfile_path = git_pathdup("gc.pid");
+	fd = hold_lock_file_for_update(&lock, pidfile_path,
+				       LOCK_DIE_ON_ERROR);
+	if (!force) {
+		static char locking_host[HOST_NAME_MAX + 1];
+		static char *scan_fmt;
+		int should_exit;
+
+		if (!scan_fmt)
+			scan_fmt = xstrfmt("%s %%%ds", "%"SCNuMAX, HOST_NAME_MAX);
+		fp = fopen(pidfile_path, "r");
+		memset(locking_host, 0, sizeof(locking_host));
+		should_exit =
+			fp != NULL &&
+			!fstat(fileno(fp), &st) &&
+			/*
+			 * 12 hour limit is very generous as gc should
+			 * never take that long. On the other hand we
+			 * don't really need a strict limit here,
+			 * running gc --auto one day late is not a big
+			 * problem. --force can be used in manual gc
+			 * after the user verifies that no gc is
+			 * running.
+			 */
+			time(NULL) - st.st_mtime <= 12 * 3600 &&
+			fscanf(fp, scan_fmt, &pid, locking_host) == 2 &&
+			/* be gentle to concurrent "gc" on remote hosts */
+			(strcmp(locking_host, my_host) || !kill(pid, 0) || errno == EPERM);
+		if (fp)
+			fclose(fp);
+		if (should_exit) {
+			if (fd >= 0)
+				rollback_lock_file(&lock);
+			*ret_pid = pid;
+			free(pidfile_path);
+			return locking_host;
+		}
+	}
+
+	strbuf_addf(&sb, "%"PRIuMAX" %s",
+		    (uintmax_t) getpid(), my_host);
+	write_in_full(fd, sb.buf, sb.len);
+	strbuf_release(&sb);
+	commit_lock_file(&lock);
+	pidfile = register_tempfile(pidfile_path);
+	free(pidfile_path);
+	return NULL;
+}
+
+/*
+ * Returns 0 if there was no previous error and gc can proceed, 1 if
+ * gc should not proceed due to an error in the last run. Prints a
+ * message and returns with a non-[01] status code if an error occurred
+ * while reading gc.log
+ */
+static int report_last_gc_error(void)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 0;
+	ssize_t len;
+	struct stat st;
+	char *gc_log_path = git_pathdup("gc.log");
+
+	if (stat(gc_log_path, &st)) {
+		if (errno == ENOENT)
+			goto done;
+
+		ret = die_message_errno(_("cannot stat '%s'"), gc_log_path);
+		goto done;
+	}
+
+	if (st.st_mtime < gc_log_expire_time)
+		goto done;
+
+	len = strbuf_read_file(&sb, gc_log_path, 0);
+	if (len < 0)
+		ret = die_message_errno(_("cannot read '%s'"), gc_log_path);
+	else if (len > 0) {
+		/*
+		 * A previous gc failed.  Report the error, and don't
+		 * bother with an automatic gc run since it is likely
+		 * to fail in the same way.
+		 */
+		warning(_("The last gc run reported the following. "
+			       "Please correct the root cause\n"
+			       "and remove %s\n"
+			       "Automatic cleanup will not be performed "
+			       "until the file is removed.\n\n"
+			       "%s"),
+			    gc_log_path, sb.buf);
+		ret = 1;
+	}
+	strbuf_release(&sb);
+done:
+	free(gc_log_path);
+	return ret;
+}
+
+static void gc_before_repack(struct maintenance_run_opts *opts,
+			     struct gc_config *cfg)
+{
+	/*
+	 * We may be called twice, as both the pre- and
+	 * post-daemonized phases will call us, but running these
+	 * commands more than once is pointless and wasteful.
+	 */
+	static int done = 0;
+	if (done++)
+		return;
+
+	if (cfg->pack_refs && maintenance_task_pack_refs(opts, cfg))
+		die(FAILED_RUN, "pack-refs");
+
+	if (cfg->prune_reflogs) {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+
+		cmd.git_cmd = 1;
+		strvec_pushv(&cmd.args, reflog.v);
+		if (run_command(&cmd))
+			die(FAILED_RUN, reflog.v[0]);
+	}
+}
+
+int cmd_gc(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
+{
+	int aggressive = 0;
+	int quiet = 0;
+	int force = 0;
+	const char *name;
+	pid_t pid;
+	int daemonized = 0;
+	int keep_largest_pack = -1;
+	timestamp_t dummy;
+	struct child_process rerere_cmd = CHILD_PROCESS_INIT;
+	struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
+	struct gc_config cfg = GC_CONFIG_INIT;
+	const char *prune_expire_sentinel = "sentinel";
+	const char *prune_expire_arg = prune_expire_sentinel;
+	int ret;
+
+	struct option builtin_gc_options[] = {
+		OPT__QUIET(&quiet, N_("suppress progress reporting")),
+		{ OPTION_STRING, 0, "prune", &prune_expire_arg, N_("date"),
+			N_("prune unreferenced objects"),
+			PARSE_OPT_OPTARG, NULL, (intptr_t)prune_expire_arg },
+		OPT_BOOL(0, "cruft", &cfg.cruft_packs, N_("pack unreferenced objects separately")),
+		OPT_MAGNITUDE(0, "max-cruft-size", &cfg.max_cruft_size,
+			      N_("with --cruft, limit the size of new cruft packs")),
+		OPT_BOOL(0, "aggressive", &aggressive, N_("be more thorough (increased runtime)")),
+		OPT_BOOL_F(0, "auto", &opts.auto_flag, N_("enable auto-gc mode"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "detach", &opts.detach,
+			 N_("perform garbage collection in the background")),
+		OPT_BOOL_F(0, "force", &force,
+			   N_("force running gc even if there may be another gc running"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "keep-largest-pack", &keep_largest_pack,
+			 N_("repack all other packs except the largest pack")),
+		OPT_END()
+	};
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_gc_usage, builtin_gc_options);
+
+	strvec_pushl(&reflog, "reflog", "expire", "--all", NULL);
+	strvec_pushl(&repack, "repack", "-d", "-l", NULL);
+	strvec_pushl(&prune, "prune", "--expire", NULL);
+	strvec_pushl(&prune_worktrees, "worktree", "prune", "--expire", NULL);
+	strvec_pushl(&rerere, "rerere", "gc", NULL);
+
+	gc_config(&cfg);
+
+	if (parse_expiry_date(cfg.gc_log_expire, &gc_log_expire_time))
+		die(_("failed to parse gc.logExpiry value %s"), cfg.gc_log_expire);
+
+	if (cfg.pack_refs < 0)
+		cfg.pack_refs = !is_bare_repository();
+
+	argc = parse_options(argc, argv, prefix, builtin_gc_options,
+			     builtin_gc_usage, 0);
+	if (argc > 0)
+		usage_with_options(builtin_gc_usage, builtin_gc_options);
+
+	if (prune_expire_arg != prune_expire_sentinel) {
+		free(cfg.prune_expire);
+		cfg.prune_expire = xstrdup_or_null(prune_expire_arg);
+	}
+	if (cfg.prune_expire && parse_expiry_date(cfg.prune_expire, &dummy))
+		die(_("failed to parse prune expiry value %s"), cfg.prune_expire);
+
+	if (aggressive) {
+		strvec_push(&repack, "-f");
+		if (cfg.aggressive_depth > 0)
+			strvec_pushf(&repack, "--depth=%d", cfg.aggressive_depth);
+		if (cfg.aggressive_window > 0)
+			strvec_pushf(&repack, "--window=%d", cfg.aggressive_window);
+	}
+	if (quiet)
+		strvec_push(&repack, "-q");
+
+	if (opts.auto_flag) {
+		if (cfg.detach_auto && opts.detach < 0)
+			opts.detach = 1;
+
+		/*
+		 * Auto-gc should be least intrusive as possible.
+		 */
+		if (!need_to_gc(&cfg)) {
+			ret = 0;
+			goto out;
+		}
+
+		if (!quiet) {
+			if (opts.detach > 0)
+				fprintf(stderr, _("Auto packing the repository in background for optimum performance.\n"));
+			else
+				fprintf(stderr, _("Auto packing the repository for optimum performance.\n"));
+			fprintf(stderr, _("See \"git help gc\" for manual housekeeping.\n"));
+		}
+	} else {
+		struct string_list keep_pack = STRING_LIST_INIT_NODUP;
+
+		if (keep_largest_pack != -1) {
+			if (keep_largest_pack)
+				find_base_packs(&keep_pack, 0);
+		} else if (cfg.big_pack_threshold) {
+			find_base_packs(&keep_pack, cfg.big_pack_threshold);
+		}
+
+		add_repack_all_option(&cfg, &keep_pack);
+		string_list_clear(&keep_pack, 0);
+	}
+
+	if (opts.detach > 0) {
+		ret = report_last_gc_error();
+		if (ret == 1) {
+			/* Last gc --auto failed. Skip this one. */
+			ret = 0;
+			goto out;
+
+		} else if (ret) {
+			/* an I/O error occurred, already reported */
+			goto out;
+		}
+
+		if (lock_repo_for_gc(force, &pid)) {
+			ret = 0;
+			goto out;
+		}
+
+		gc_before_repack(&opts, &cfg); /* dies on failure */
+		delete_tempfile(&pidfile);
+
+		/*
+		 * failure to daemonize is ok, we'll continue
+		 * in foreground
+		 */
+		daemonized = !daemonize();
+	}
+
+	name = lock_repo_for_gc(force, &pid);
+	if (name) {
+		if (opts.auto_flag) {
+			ret = 0;
+			goto out; /* be quiet on --auto */
+		}
+
+		die(_("gc is already running on machine '%s' pid %"PRIuMAX" (use --force if not)"),
+		    name, (uintmax_t)pid);
+	}
+
+	if (daemonized) {
+		hold_lock_file_for_update(&log_lock,
+					  git_path("gc.log"),
+					  LOCK_DIE_ON_ERROR);
+		dup2(get_lock_file_fd(&log_lock), 2);
+		atexit(process_log_file_at_exit);
+	}
+
+	gc_before_repack(&opts, &cfg);
+
+	if (!repository_format_precious_objects) {
+		struct child_process repack_cmd = CHILD_PROCESS_INIT;
+
+		repack_cmd.git_cmd = 1;
+		repack_cmd.close_object_store = 1;
+		strvec_pushv(&repack_cmd.args, repack.v);
+		if (run_command(&repack_cmd))
+			die(FAILED_RUN, repack.v[0]);
+
+		if (cfg.prune_expire) {
+			struct child_process prune_cmd = CHILD_PROCESS_INIT;
+
+			/* run `git prune` even if using cruft packs */
+			strvec_push(&prune, cfg.prune_expire);
+			if (quiet)
+				strvec_push(&prune, "--no-progress");
+			if (repo_has_promisor_remote(the_repository))
+				strvec_push(&prune,
+					    "--exclude-promisor-objects");
+			prune_cmd.git_cmd = 1;
+			strvec_pushv(&prune_cmd.args, prune.v);
+			if (run_command(&prune_cmd))
+				die(FAILED_RUN, prune.v[0]);
+		}
+	}
+
+	if (cfg.prune_worktrees_expire) {
+		struct child_process prune_worktrees_cmd = CHILD_PROCESS_INIT;
+
+		strvec_push(&prune_worktrees, cfg.prune_worktrees_expire);
+		prune_worktrees_cmd.git_cmd = 1;
+		strvec_pushv(&prune_worktrees_cmd.args, prune_worktrees.v);
+		if (run_command(&prune_worktrees_cmd))
+			die(FAILED_RUN, prune_worktrees.v[0]);
+	}
+
+	rerere_cmd.git_cmd = 1;
+	strvec_pushv(&rerere_cmd.args, rerere.v);
+	if (run_command(&rerere_cmd))
+		die(FAILED_RUN, rerere.v[0]);
+
+	report_garbage = report_pack_garbage;
+	reprepare_packed_git(the_repository);
+	if (pack_garbage.nr > 0) {
+		close_object_store(the_repository->objects);
+		clean_pack_garbage();
+	}
+
+	if (the_repository->settings.gc_write_commit_graph == 1)
+		write_commit_graph_reachable(the_repository->objects->odb,
+					     !quiet && !daemonized ? COMMIT_GRAPH_WRITE_PROGRESS : 0,
+					     NULL);
+
+	if (opts.auto_flag && too_many_loose_objects(&cfg))
+		warning(_("There are too many unreachable loose objects; "
+			"run 'git prune' to remove them."));
+
+	if (!daemonized)
+		unlink(git_path("gc.log"));
+
+out:
+	gc_config_release(&cfg);
+	return 0;
+}
+
+static const char *const builtin_maintenance_run_usage[] = {
+	N_("git maintenance run [--auto] [--[no-]quiet] [--task=<task>] [--schedule]"),
+	NULL
+};
+
+static int maintenance_opt_schedule(const struct option *opt, const char *arg,
+				    int unset)
+{
+	enum schedule_priority *priority = opt->value;
+
+	if (unset)
+		die(_("--no-schedule is not allowed"));
+
+	*priority = parse_schedule(arg);
+
+	if (!*priority)
+		die(_("unrecognized --schedule argument '%s'"), arg);
+
+	return 0;
+}
+
+/* Remember to update object flag allocation in object.h */
+#define SEEN		(1u<<0)
+
+struct cg_auto_data {
+	int num_not_in_graph;
+	int limit;
+};
+
+static int dfs_on_ref(const char *refname UNUSED,
+		      const char *referent UNUSED,
+		      const struct object_id *oid,
+		      int flags UNUSED,
+		      void *cb_data)
+{
+	struct cg_auto_data *data = (struct cg_auto_data *)cb_data;
+	int result = 0;
+	struct object_id peeled;
+	struct commit_list *stack = NULL;
+	struct commit *commit;
+
+	if (!peel_iterated_oid(the_repository, oid, &peeled))
+		oid = &peeled;
+	if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
+		return 0;
+
+	commit = lookup_commit(the_repository, oid);
+	if (!commit)
+		return 0;
+	if (repo_parse_commit(the_repository, commit) ||
+	    commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
+		return 0;
+
+	data->num_not_in_graph++;
+
+	if (data->num_not_in_graph >= data->limit)
+		return 1;
+
+	commit_list_append(commit, &stack);
+
+	while (!result && stack) {
+		struct commit_list *parent;
+
+		commit = pop_commit(&stack);
+
+		for (parent = commit->parents; parent; parent = parent->next) {
+			if (repo_parse_commit(the_repository, parent->item) ||
+			    commit_graph_position(parent->item) != COMMIT_NOT_FROM_GRAPH ||
+			    parent->item->object.flags & SEEN)
+				continue;
+
+			parent->item->object.flags |= SEEN;
+			data->num_not_in_graph++;
+
+			if (data->num_not_in_graph >= data->limit) {
+				result = 1;
+				break;
+			}
+
+			commit_list_append(parent->item, &stack);
+		}
+	}
+
+	free_commit_list(stack);
+	return result;
+}
+
+static int should_write_commit_graph(struct gc_config *cfg UNUSED)
+{
+	int result;
+	struct cg_auto_data data;
+
+	data.num_not_in_graph = 0;
+	data.limit = 100;
+	git_config_get_int("maintenance.commit-graph.auto",
+			   &data.limit);
+
+	if (!data.limit)
+		return 0;
+	if (data.limit < 0)
+		return 1;
+
+	result = refs_for_each_ref(get_main_ref_store(the_repository),
+				   dfs_on_ref, &data);
+
+	repo_clear_commit_marks(the_repository, SEEN);
+
+	return result;
+}
+
+static int run_write_commit_graph(struct maintenance_run_opts *opts)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	child.git_cmd = child.close_object_store = 1;
+	strvec_pushl(&child.args, "commit-graph", "write",
+		     "--split", "--reachable", NULL);
+
+	if (opts->quiet)
+		strvec_push(&child.args, "--no-progress");
+
+	return !!run_command(&child);
+}
+
+static int maintenance_task_commit_graph(struct maintenance_run_opts *opts,
+					 struct gc_config *cfg UNUSED)
+{
+	prepare_repo_settings(the_repository);
+	if (!the_repository->settings.core_commit_graph)
+		return 0;
+
+	if (run_write_commit_graph(opts)) {
+		error(_("failed to write commit-graph"));
+		return 1;
+	}
+
+	return 0;
+}
+
+static int fetch_remote(struct remote *remote, void *cbdata)
+{
+	struct maintenance_run_opts *opts = cbdata;
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	if (remote->skip_default_update)
+		return 0;
+
+	child.git_cmd = 1;
+	strvec_pushl(&child.args, "fetch", remote->name,
+		     "--prefetch", "--prune", "--no-tags",
+		     "--no-write-fetch-head", "--recurse-submodules=no",
+		     NULL);
+
+	if (opts->quiet)
+		strvec_push(&child.args, "--quiet");
+
+	return !!run_command(&child);
+}
+
+static int maintenance_task_prefetch(struct maintenance_run_opts *opts,
+				     struct gc_config *cfg UNUSED)
+{
+	if (for_each_remote(fetch_remote, opts)) {
+		error(_("failed to prefetch remotes"));
+		return 1;
+	}
+
+	return 0;
+}
+
+static int maintenance_task_gc(struct maintenance_run_opts *opts,
+			       struct gc_config *cfg UNUSED)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	child.git_cmd = child.close_object_store = 1;
+	strvec_push(&child.args, "gc");
+
+	if (opts->auto_flag)
+		strvec_push(&child.args, "--auto");
+	if (opts->quiet)
+		strvec_push(&child.args, "--quiet");
+	else
+		strvec_push(&child.args, "--no-quiet");
+	strvec_push(&child.args, "--no-detach");
+
+	return run_command(&child);
+}
+
+static int prune_packed(struct maintenance_run_opts *opts)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	child.git_cmd = 1;
+	strvec_push(&child.args, "prune-packed");
+
+	if (opts->quiet)
+		strvec_push(&child.args, "--quiet");
+
+	return !!run_command(&child);
+}
+
+struct write_loose_object_data {
+	FILE *in;
+	int count;
+	int batch_size;
+};
+
+static int loose_object_auto_limit = 100;
+
+static int loose_object_count(const struct object_id *oid UNUSED,
+			      const char *path UNUSED,
+			      void *data)
+{
+	int *count = (int*)data;
+	if (++(*count) >= loose_object_auto_limit)
+		return 1;
+	return 0;
+}
+
+static int loose_object_auto_condition(struct gc_config *cfg UNUSED)
+{
+	int count = 0;
+
+	git_config_get_int("maintenance.loose-objects.auto",
+			   &loose_object_auto_limit);
+
+	if (!loose_object_auto_limit)
+		return 0;
+	if (loose_object_auto_limit < 0)
+		return 1;
+
+	return for_each_loose_file_in_objdir(the_repository->objects->odb->path,
+					     loose_object_count,
+					     NULL, NULL, &count);
+}
+
+static int bail_on_loose(const struct object_id *oid UNUSED,
+			 const char *path UNUSED,
+			 void *data UNUSED)
+{
+	return 1;
+}
+
+static int write_loose_object_to_stdin(const struct object_id *oid,
+				       const char *path UNUSED,
+				       void *data)
+{
+	struct write_loose_object_data *d = (struct write_loose_object_data *)data;
+
+	fprintf(d->in, "%s\n", oid_to_hex(oid));
+
+	return ++(d->count) > d->batch_size;
+}
+
+static int pack_loose(struct maintenance_run_opts *opts)
+{
+	struct repository *r = the_repository;
+	int result = 0;
+	struct write_loose_object_data data;
+	struct child_process pack_proc = CHILD_PROCESS_INIT;
+
+	/*
+	 * Do not start pack-objects process
+	 * if there are no loose objects.
+	 */
+	if (!for_each_loose_file_in_objdir(r->objects->odb->path,
+					   bail_on_loose,
+					   NULL, NULL, NULL))
+		return 0;
+
+	pack_proc.git_cmd = 1;
+
+	strvec_push(&pack_proc.args, "pack-objects");
+	if (opts->quiet)
+		strvec_push(&pack_proc.args, "--quiet");
+	strvec_pushf(&pack_proc.args, "%s/pack/loose", r->objects->odb->path);
+
+	pack_proc.in = -1;
+
+	/*
+	 * git-pack-objects(1) ends up writing the pack hash to stdout, which
+	 * we do not care for.
+	 */
+	pack_proc.out = -1;
+
+	if (start_command(&pack_proc)) {
+		error(_("failed to start 'git pack-objects' process"));
+		return 1;
+	}
+
+	data.in = xfdopen(pack_proc.in, "w");
+	data.count = 0;
+	data.batch_size = 50000;
+
+	for_each_loose_file_in_objdir(r->objects->odb->path,
+				      write_loose_object_to_stdin,
+				      NULL,
+				      NULL,
+				      &data);
+
+	fclose(data.in);
+
+	if (finish_command(&pack_proc)) {
+		error(_("failed to finish 'git pack-objects' process"));
+		result = 1;
+	}
+
+	return result;
+}
+
+static int maintenance_task_loose_objects(struct maintenance_run_opts *opts,
+					  struct gc_config *cfg UNUSED)
+{
+	return prune_packed(opts) || pack_loose(opts);
+}
+
+static int incremental_repack_auto_condition(struct gc_config *cfg UNUSED)
+{
+	struct packed_git *p;
+	int incremental_repack_auto_limit = 10;
+	int count = 0;
+
+	prepare_repo_settings(the_repository);
+	if (!the_repository->settings.core_multi_pack_index)
+		return 0;
+
+	git_config_get_int("maintenance.incremental-repack.auto",
+			   &incremental_repack_auto_limit);
+
+	if (!incremental_repack_auto_limit)
+		return 0;
+	if (incremental_repack_auto_limit < 0)
+		return 1;
+
+	for (p = get_packed_git(the_repository);
+	     count < incremental_repack_auto_limit && p;
+	     p = p->next) {
+		if (!p->multi_pack_index)
+			count++;
+	}
+
+	return count >= incremental_repack_auto_limit;
+}
+
+static int multi_pack_index_write(struct maintenance_run_opts *opts)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	child.git_cmd = 1;
+	strvec_pushl(&child.args, "multi-pack-index", "write", NULL);
+
+	if (opts->quiet)
+		strvec_push(&child.args, "--no-progress");
+
+	if (run_command(&child))
+		return error(_("failed to write multi-pack-index"));
+
+	return 0;
+}
+
+static int multi_pack_index_expire(struct maintenance_run_opts *opts)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	child.git_cmd = child.close_object_store = 1;
+	strvec_pushl(&child.args, "multi-pack-index", "expire", NULL);
+
+	if (opts->quiet)
+		strvec_push(&child.args, "--no-progress");
+
+	if (run_command(&child))
+		return error(_("'git multi-pack-index expire' failed"));
+
+	return 0;
+}
+
+#define TWO_GIGABYTES (INT32_MAX)
+
+static off_t get_auto_pack_size(void)
+{
+	/*
+	 * The "auto" value is special: we optimize for
+	 * one large pack-file (i.e. from a clone) and
+	 * expect the rest to be small and they can be
+	 * repacked quickly.
+	 *
+	 * The strategy we select here is to select a
+	 * size that is one more than the second largest
+	 * pack-file. This ensures that we will repack
+	 * at least two packs if there are three or more
+	 * packs.
+	 */
+	off_t max_size = 0;
+	off_t second_largest_size = 0;
+	off_t result_size;
+	struct packed_git *p;
+	struct repository *r = the_repository;
+
+	reprepare_packed_git(r);
+	for (p = get_all_packs(r); p; p = p->next) {
+		if (p->pack_size > max_size) {
+			second_largest_size = max_size;
+			max_size = p->pack_size;
+		} else if (p->pack_size > second_largest_size)
+			second_largest_size = p->pack_size;
+	}
+
+	result_size = second_largest_size + 1;
+
+	/* But limit ourselves to a batch size of 2g */
+	if (result_size > TWO_GIGABYTES)
+		result_size = TWO_GIGABYTES;
+
+	return result_size;
+}
+
+static int multi_pack_index_repack(struct maintenance_run_opts *opts)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	child.git_cmd = child.close_object_store = 1;
+	strvec_pushl(&child.args, "multi-pack-index", "repack", NULL);
+
+	if (opts->quiet)
+		strvec_push(&child.args, "--no-progress");
+
+	strvec_pushf(&child.args, "--batch-size=%"PRIuMAX,
+				  (uintmax_t)get_auto_pack_size());
+
+	if (run_command(&child))
+		return error(_("'git multi-pack-index repack' failed"));
+
+	return 0;
+}
+
+static int maintenance_task_incremental_repack(struct maintenance_run_opts *opts,
+					       struct gc_config *cfg UNUSED)
+{
+	prepare_repo_settings(the_repository);
+	if (!the_repository->settings.core_multi_pack_index) {
+		warning(_("skipping incremental-repack task because core.multiPackIndex is disabled"));
+		return 0;
+	}
+
+	if (multi_pack_index_write(opts))
+		return 1;
+	if (multi_pack_index_expire(opts))
+		return 1;
+	if (multi_pack_index_repack(opts))
+		return 1;
+	return 0;
+}
+
+typedef int maintenance_task_fn(struct maintenance_run_opts *opts,
+				struct gc_config *cfg);
+
+/*
+ * An auto condition function returns 1 if the task should run
+ * and 0 if the task should NOT run. See needs_to_gc() for an
+ * example.
+ */
+typedef int maintenance_auto_fn(struct gc_config *cfg);
+
+struct maintenance_task {
+	const char *name;
+	maintenance_task_fn *fn;
+	maintenance_auto_fn *auto_condition;
+	unsigned enabled:1;
+
+	enum schedule_priority schedule;
+
+	/* -1 if not selected. */
+	int selected_order;
+};
+
+enum maintenance_task_label {
+	TASK_PREFETCH,
+	TASK_LOOSE_OBJECTS,
+	TASK_INCREMENTAL_REPACK,
+	TASK_GC,
+	TASK_COMMIT_GRAPH,
+	TASK_PACK_REFS,
+
+	/* Leave as final value */
+	TASK__COUNT
+};
+
+static struct maintenance_task tasks[] = {
+	[TASK_PREFETCH] = {
+		"prefetch",
+		maintenance_task_prefetch,
+	},
+	[TASK_LOOSE_OBJECTS] = {
+		"loose-objects",
+		maintenance_task_loose_objects,
+		loose_object_auto_condition,
+	},
+	[TASK_INCREMENTAL_REPACK] = {
+		"incremental-repack",
+		maintenance_task_incremental_repack,
+		incremental_repack_auto_condition,
+	},
+	[TASK_GC] = {
+		"gc",
+		maintenance_task_gc,
+		need_to_gc,
+		1,
+	},
+	[TASK_COMMIT_GRAPH] = {
+		"commit-graph",
+		maintenance_task_commit_graph,
+		should_write_commit_graph,
+	},
+	[TASK_PACK_REFS] = {
+		"pack-refs",
+		maintenance_task_pack_refs,
+		pack_refs_condition,
+	},
+};
+
+static int compare_tasks_by_selection(const void *a_, const void *b_)
+{
+	const struct maintenance_task *a = a_;
+	const struct maintenance_task *b = b_;
+
+	return b->selected_order - a->selected_order;
+}
+
+static int maintenance_run_tasks(struct maintenance_run_opts *opts,
+				 struct gc_config *cfg)
+{
+	int i, found_selected = 0;
+	int result = 0;
+	struct lock_file lk;
+	struct repository *r = the_repository;
+	char *lock_path = xstrfmt("%s/maintenance", r->objects->odb->path);
+
+	if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
+		/*
+		 * Another maintenance command is running.
+		 *
+		 * If --auto was provided, then it is likely due to a
+		 * recursive process stack. Do not report an error in
+		 * that case.
+		 */
+		if (!opts->auto_flag && !opts->quiet)
+			warning(_("lock file '%s' exists, skipping maintenance"),
+				lock_path);
+		free(lock_path);
+		return 0;
+	}
+	free(lock_path);
+
+	/* Failure to daemonize is ok, we'll continue in foreground. */
+	if (opts->detach > 0) {
+		trace2_region_enter("maintenance", "detach", the_repository);
+		daemonize();
+		trace2_region_leave("maintenance", "detach", the_repository);
+	}
+
+	for (i = 0; !found_selected && i < TASK__COUNT; i++)
+		found_selected = tasks[i].selected_order >= 0;
+
+	if (found_selected)
+		QSORT(tasks, TASK__COUNT, compare_tasks_by_selection);
+
+	for (i = 0; i < TASK__COUNT; i++) {
+		if (found_selected && tasks[i].selected_order < 0)
+			continue;
+
+		if (!found_selected && !tasks[i].enabled)
+			continue;
+
+		if (opts->auto_flag &&
+		    (!tasks[i].auto_condition ||
+		     !tasks[i].auto_condition(cfg)))
+			continue;
+
+		if (opts->schedule && tasks[i].schedule < opts->schedule)
+			continue;
+
+		trace2_region_enter("maintenance", tasks[i].name, r);
+		if (tasks[i].fn(opts, cfg)) {
+			error(_("task '%s' failed"), tasks[i].name);
+			result = 1;
+		}
+		trace2_region_leave("maintenance", tasks[i].name, r);
+	}
+
+	rollback_lock_file(&lk);
+	return result;
+}
+
+static void initialize_maintenance_strategy(void)
+{
+	const char *config_str;
+
+	if (git_config_get_string_tmp("maintenance.strategy", &config_str))
+		return;
+
+	if (!strcasecmp(config_str, "incremental")) {
+		tasks[TASK_GC].schedule = SCHEDULE_NONE;
+		tasks[TASK_COMMIT_GRAPH].enabled = 1;
+		tasks[TASK_COMMIT_GRAPH].schedule = SCHEDULE_HOURLY;
+		tasks[TASK_PREFETCH].enabled = 1;
+		tasks[TASK_PREFETCH].schedule = SCHEDULE_HOURLY;
+		tasks[TASK_INCREMENTAL_REPACK].enabled = 1;
+		tasks[TASK_INCREMENTAL_REPACK].schedule = SCHEDULE_DAILY;
+		tasks[TASK_LOOSE_OBJECTS].enabled = 1;
+		tasks[TASK_LOOSE_OBJECTS].schedule = SCHEDULE_DAILY;
+		tasks[TASK_PACK_REFS].enabled = 1;
+		tasks[TASK_PACK_REFS].schedule = SCHEDULE_WEEKLY;
+	}
+}
+
+static void initialize_task_config(int schedule)
+{
+	int i;
+	struct strbuf config_name = STRBUF_INIT;
+
+	if (schedule)
+		initialize_maintenance_strategy();
+
+	for (i = 0; i < TASK__COUNT; i++) {
+		int config_value;
+		char *config_str;
+
+		strbuf_reset(&config_name);
+		strbuf_addf(&config_name, "maintenance.%s.enabled",
+			    tasks[i].name);
+
+		if (!git_config_get_bool(config_name.buf, &config_value))
+			tasks[i].enabled = config_value;
+
+		strbuf_reset(&config_name);
+		strbuf_addf(&config_name, "maintenance.%s.schedule",
+			    tasks[i].name);
+
+		if (!git_config_get_string(config_name.buf, &config_str)) {
+			tasks[i].schedule = parse_schedule(config_str);
+			free(config_str);
+		}
+	}
+
+	strbuf_release(&config_name);
+}
+
+static int task_option_parse(const struct option *opt UNUSED,
+			     const char *arg, int unset)
+{
+	int i, num_selected = 0;
+	struct maintenance_task *task = NULL;
+
+	BUG_ON_OPT_NEG(unset);
+
+	for (i = 0; i < TASK__COUNT; i++) {
+		if (tasks[i].selected_order >= 0)
+			num_selected++;
+		if (!strcasecmp(tasks[i].name, arg)) {
+			task = &tasks[i];
+		}
+	}
+
+	if (!task) {
+		error(_("'%s' is not a valid task"), arg);
+		return 1;
+	}
+
+	if (task->selected_order >= 0) {
+		error(_("task '%s' cannot be selected multiple times"), arg);
+		return 1;
+	}
+
+	task->selected_order = num_selected + 1;
+
+	return 0;
+}
+
+static int maintenance_run(int argc, const char **argv, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	int i;
+	struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
+	struct gc_config cfg = GC_CONFIG_INIT;
+	struct option builtin_maintenance_run_options[] = {
+		OPT_BOOL(0, "auto", &opts.auto_flag,
+			 N_("run tasks based on the state of the repository")),
+		OPT_BOOL(0, "detach", &opts.detach,
+			 N_("perform maintenance in the background")),
+		OPT_CALLBACK(0, "schedule", &opts.schedule, N_("frequency"),
+			     N_("run tasks based on frequency"),
+			     maintenance_opt_schedule),
+		OPT_BOOL(0, "quiet", &opts.quiet,
+			 N_("do not report progress or other information over stderr")),
+		OPT_CALLBACK_F(0, "task", NULL, N_("task"),
+			N_("run a specific task"),
+			PARSE_OPT_NONEG, task_option_parse),
+		OPT_END()
+	};
+	int ret;
+
+	opts.quiet = !isatty(2);
+
+	for (i = 0; i < TASK__COUNT; i++)
+		tasks[i].selected_order = -1;
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_maintenance_run_options,
+			     builtin_maintenance_run_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (opts.auto_flag && opts.schedule)
+		die(_("use at most one of --auto and --schedule=<frequency>"));
+
+	gc_config(&cfg);
+	initialize_task_config(opts.schedule);
+
+	if (argc != 0)
+		usage_with_options(builtin_maintenance_run_usage,
+				   builtin_maintenance_run_options);
+
+	ret = maintenance_run_tasks(&opts, &cfg);
+	gc_config_release(&cfg);
+	return ret;
+}
+
+static char *get_maintpath(void)
+{
+	struct strbuf sb = STRBUF_INIT;
+	const char *p = the_repository->worktree ?
+		the_repository->worktree : the_repository->gitdir;
+
+	strbuf_realpath(&sb, p, 1);
+	return strbuf_detach(&sb, NULL);
+}
+
+static char const * const builtin_maintenance_register_usage[] = {
+	"git maintenance register [--config-file <path>]",
+	NULL
+};
+
+static int maintenance_register(int argc, const char **argv, const char *prefix,
+				struct repository *repo UNUSED)
+{
+	char *config_file = NULL;
+	struct option options[] = {
+		OPT_STRING(0, "config-file", &config_file, N_("file"), N_("use given config file")),
+		OPT_END(),
+	};
+	int found = 0;
+	const char *key = "maintenance.repo";
+	char *maintpath = get_maintpath();
+	struct string_list_item *item;
+	const struct string_list *list;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_maintenance_register_usage, 0);
+	if (argc)
+		usage_with_options(builtin_maintenance_register_usage,
+				   options);
+
+	/* Disable foreground maintenance */
+	git_config_set("maintenance.auto", "false");
+
+	/* Set maintenance strategy, if unset */
+	if (git_config_get("maintenance.strategy"))
+		git_config_set("maintenance.strategy", "incremental");
+
+	if (!git_config_get_string_multi(key, &list)) {
+		for_each_string_list_item(item, list) {
+			if (!strcmp(maintpath, item->string)) {
+				found = 1;
+				break;
+			}
+		}
+	}
+
+	if (!found) {
+		int rc;
+		char *global_config_file = NULL;
+
+		if (!config_file) {
+			global_config_file = git_global_config();
+			config_file = global_config_file;
+		}
+		if (!config_file)
+			die(_("$HOME not set"));
+		rc = git_config_set_multivar_in_file_gently(
+			config_file, "maintenance.repo", maintpath,
+			CONFIG_REGEX_NONE, NULL, 0);
+		free(global_config_file);
+
+		if (rc)
+			die(_("unable to add '%s' value of '%s'"),
+			    key, maintpath);
+	}
+
+	free(maintpath);
+	return 0;
+}
+
+static char const * const builtin_maintenance_unregister_usage[] = {
+	"git maintenance unregister [--config-file <path>] [--force]",
+	NULL
+};
+
+static int maintenance_unregister(int argc, const char **argv, const char *prefix,
+				  struct repository *repo UNUSED)
+{
+	int force = 0;
+	char *config_file = NULL;
+	struct option options[] = {
+		OPT_STRING(0, "config-file", &config_file, N_("file"), N_("use given config file")),
+		OPT__FORCE(&force,
+			   N_("return success even if repository was not registered"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_END(),
+	};
+	const char *key = "maintenance.repo";
+	char *maintpath = get_maintpath();
+	int found = 0;
+	struct string_list_item *item;
+	const struct string_list *list;
+	struct config_set cs = { { 0 } };
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_maintenance_unregister_usage, 0);
+	if (argc)
+		usage_with_options(builtin_maintenance_unregister_usage,
+				   options);
+
+	if (config_file) {
+		git_configset_init(&cs);
+		git_configset_add_file(&cs, config_file);
+	}
+	if (!(config_file
+	      ? git_configset_get_string_multi(&cs, key, &list)
+	      : git_config_get_string_multi(key, &list))) {
+		for_each_string_list_item(item, list) {
+			if (!strcmp(maintpath, item->string)) {
+				found = 1;
+				break;
+			}
+		}
+	}
+
+	if (found) {
+		int rc;
+		char *global_config_file = NULL;
+
+		if (!config_file) {
+			global_config_file = git_global_config();
+			config_file = global_config_file;
+		}
+		if (!config_file)
+			die(_("$HOME not set"));
+		rc = git_config_set_multivar_in_file_gently(
+			config_file, key, NULL, maintpath, NULL,
+			CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
+		free(global_config_file);
+
+		if (rc &&
+		    (!force || rc == CONFIG_NOTHING_SET))
+			die(_("unable to unset '%s' value of '%s'"),
+			    key, maintpath);
+	} else if (!force) {
+		die(_("repository '%s' is not registered"), maintpath);
+	}
+
+	git_configset_clear(&cs);
+	free(maintpath);
+	return 0;
+}
+
+static const char *get_frequency(enum schedule_priority schedule)
+{
+	switch (schedule) {
+	case SCHEDULE_HOURLY:
+		return "hourly";
+	case SCHEDULE_DAILY:
+		return "daily";
+	case SCHEDULE_WEEKLY:
+		return "weekly";
+	default:
+		BUG("invalid schedule %d", schedule);
+	}
+}
+
+static const char *extraconfig[] = {
+	"credential.interactive=false",
+	"core.askPass=true", /* 'true' returns success, but no output. */
+	NULL
+};
+
+static const char *get_extra_config_parameters(void) {
+	static const char *result = NULL;
+	struct strbuf builder = STRBUF_INIT;
+
+	if (result)
+		return result;
+
+	for (const char **s = extraconfig; s && *s; s++)
+		strbuf_addf(&builder, "-c %s ", *s);
+
+	result = strbuf_detach(&builder, NULL);
+	return result;
+}
+
+static const char *get_extra_launchctl_strings(void) {
+	static const char *result = NULL;
+	struct strbuf builder = STRBUF_INIT;
+
+	if (result)
+		return result;
+
+	for (const char **s = extraconfig; s && *s; s++) {
+		strbuf_addstr(&builder, "<string>-c</string>\n");
+		strbuf_addf(&builder, "<string>%s</string>\n", *s);
+	}
+
+	result = strbuf_detach(&builder, NULL);
+	return result;
+}
+
+/*
+ * get_schedule_cmd` reads the GIT_TEST_MAINT_SCHEDULER environment variable
+ * to mock the schedulers that `git maintenance start` rely on.
+ *
+ * For test purpose, GIT_TEST_MAINT_SCHEDULER can be set to a comma-separated
+ * list of colon-separated key/value pairs where each pair contains a scheduler
+ * and its corresponding mock.
+ *
+ * * If $GIT_TEST_MAINT_SCHEDULER is not set, return false and leave the
+ *   arguments unmodified.
+ *
+ * * If $GIT_TEST_MAINT_SCHEDULER is set, return true.
+ *   In this case, the *cmd value is read as input.
+ *
+ *   * if the input value cmd is the key of one of the comma-separated list
+ *     item, then *is_available is set to true and *out is set to
+ *     the mock command.
+ *
+ *   * if the input value *cmd isn’t the key of any of the comma-separated list
+ *     item, then *is_available is set to false and *out is set to the original
+ *     command.
+ *
+ * Ex.:
+ *   GIT_TEST_MAINT_SCHEDULER not set
+ *     +-------+-------------------------------------------------+
+ *     | Input |                     Output                      |
+ *     | *cmd  | return code |       *out        | *is_available |
+ *     +-------+-------------+-------------------+---------------+
+ *     | "foo" |    false    | "foo" (allocated) |  (unchanged)  |
+ *     +-------+-------------+-------------------+---------------+
+ *
+ *   GIT_TEST_MAINT_SCHEDULER set to “foo:./mock_foo.sh,bar:./mock_bar.sh”
+ *     +-------+-------------------------------------------------+
+ *     | Input |                     Output                      |
+ *     | *cmd  | return code |       *out        | *is_available |
+ *     +-------+-------------+-------------------+---------------+
+ *     | "foo" |    true     |  "./mock.foo.sh"  |     true      |
+ *     | "qux" |    true     | "qux" (allocated) |     false     |
+ *     +-------+-------------+-------------------+---------------+
+ */
+static int get_schedule_cmd(const char *cmd, int *is_available, char **out)
+{
+	char *testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER"));
+	struct string_list_item *item;
+	struct string_list list = STRING_LIST_INIT_NODUP;
+
+	if (!testing) {
+		if (out)
+			*out = xstrdup(cmd);
+		return 0;
+	}
+
+	if (is_available)
+		*is_available = 0;
+
+	string_list_split_in_place(&list, testing, ",", -1);
+	for_each_string_list_item(item, &list) {
+		struct string_list pair = STRING_LIST_INIT_NODUP;
+
+		if (string_list_split_in_place(&pair, item->string, ":", 2) != 2)
+			continue;
+
+		if (!strcmp(cmd, pair.items[0].string)) {
+			if (out)
+				*out = xstrdup(pair.items[1].string);
+			if (is_available)
+				*is_available = 1;
+			string_list_clear(&pair, 0);
+			goto out;
+		}
+
+		string_list_clear(&pair, 0);
+	}
+
+	if (out)
+		*out = xstrdup(cmd);
+
+out:
+	string_list_clear(&list, 0);
+	free(testing);
+	return 1;
+}
+
+static int get_random_minute(void)
+{
+	/* Use a static value when under tests. */
+	if (getenv("GIT_TEST_MAINT_SCHEDULER"))
+		return 13;
+
+	return git_rand(0) % 60;
+}
+
+static int is_launchctl_available(void)
+{
+	int is_available;
+	if (get_schedule_cmd("launchctl", &is_available, NULL))
+		return is_available;
+
+#ifdef __APPLE__
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+static char *launchctl_service_name(const char *frequency)
+{
+	struct strbuf label = STRBUF_INIT;
+	strbuf_addf(&label, "org.git-scm.git.%s", frequency);
+	return strbuf_detach(&label, NULL);
+}
+
+static char *launchctl_service_filename(const char *name)
+{
+	char *expanded;
+	struct strbuf filename = STRBUF_INIT;
+	strbuf_addf(&filename, "~/Library/LaunchAgents/%s.plist", name);
+
+	expanded = interpolate_path(filename.buf, 1);
+	if (!expanded)
+		die(_("failed to expand path '%s'"), filename.buf);
+
+	strbuf_release(&filename);
+	return expanded;
+}
+
+static char *launchctl_get_uid(void)
+{
+	return xstrfmt("gui/%d", getuid());
+}
+
+static int launchctl_boot_plist(int enable, const char *filename)
+{
+	char *cmd;
+	int result;
+	struct child_process child = CHILD_PROCESS_INIT;
+	char *uid = launchctl_get_uid();
+
+	get_schedule_cmd("launchctl", NULL, &cmd);
+	strvec_split(&child.args, cmd);
+	strvec_pushl(&child.args, enable ? "bootstrap" : "bootout", uid,
+		     filename, NULL);
+
+	child.no_stderr = 1;
+	child.no_stdout = 1;
+
+	if (start_command(&child))
+		die(_("failed to start launchctl"));
+
+	result = finish_command(&child);
+
+	free(cmd);
+	free(uid);
+	return result;
+}
+
+static int launchctl_remove_plist(enum schedule_priority schedule)
+{
+	const char *frequency = get_frequency(schedule);
+	char *name = launchctl_service_name(frequency);
+	char *filename = launchctl_service_filename(name);
+	int result = launchctl_boot_plist(0, filename);
+	unlink(filename);
+	free(filename);
+	free(name);
+	return result;
+}
+
+static int launchctl_remove_plists(void)
+{
+	return launchctl_remove_plist(SCHEDULE_HOURLY) ||
+	       launchctl_remove_plist(SCHEDULE_DAILY) ||
+	       launchctl_remove_plist(SCHEDULE_WEEKLY);
+}
+
+static int launchctl_list_contains_plist(const char *name, const char *cmd)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	strvec_split(&child.args, cmd);
+	strvec_pushl(&child.args, "list", name, NULL);
+
+	child.no_stderr = 1;
+	child.no_stdout = 1;
+
+	if (start_command(&child))
+		die(_("failed to start launchctl"));
+
+	/* Returns failure if 'name' doesn't exist. */
+	return !finish_command(&child);
+}
+
+static int launchctl_schedule_plist(const char *exec_path, enum schedule_priority schedule)
+{
+	int i, fd;
+	const char *preamble, *repeat;
+	const char *frequency = get_frequency(schedule);
+	char *name = launchctl_service_name(frequency);
+	char *filename = launchctl_service_filename(name);
+	struct lock_file lk = LOCK_INIT;
+	static unsigned long lock_file_timeout_ms = ULONG_MAX;
+	struct strbuf plist = STRBUF_INIT, plist2 = STRBUF_INIT;
+	struct stat st;
+	char *cmd;
+	int minute = get_random_minute();
+
+	get_schedule_cmd("launchctl", NULL, &cmd);
+	preamble = "<?xml version=\"1.0\"?>\n"
+		   "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\";>\n"
+		   "<plist version=\"1.0\">"
+		   "<dict>\n"
+		   "<key>Label</key><string>%s</string>\n"
+		   "<key>ProgramArguments</key>\n"
+		   "<array>\n"
+		   "<string>%s/git</string>\n"
+		   "<string>--exec-path=%s</string>\n"
+		   "%s" /* For extra config parameters. */
+		   "<string>for-each-repo</string>\n"
+		   "<string>--keep-going</string>\n"
+		   "<string>--config=maintenance.repo</string>\n"
+		   "<string>maintenance</string>\n"
+		   "<string>run</string>\n"
+		   "<string>--schedule=%s</string>\n"
+		   "</array>\n"
+		   "<key>StartCalendarInterval</key>\n"
+		   "<array>\n";
+	strbuf_addf(&plist, preamble, name, exec_path, exec_path,
+		    get_extra_launchctl_strings(), frequency);
+
+	switch (schedule) {
+	case SCHEDULE_HOURLY:
+		repeat = "<dict>\n"
+			 "<key>Hour</key><integer>%d</integer>\n"
+			 "<key>Minute</key><integer>%d</integer>\n"
+			 "</dict>\n";
+		for (i = 1; i <= 23; i++)
+			strbuf_addf(&plist, repeat, i, minute);
+		break;
+
+	case SCHEDULE_DAILY:
+		repeat = "<dict>\n"
+			 "<key>Day</key><integer>%d</integer>\n"
+			 "<key>Hour</key><integer>0</integer>\n"
+			 "<key>Minute</key><integer>%d</integer>\n"
+			 "</dict>\n";
+		for (i = 1; i <= 6; i++)
+			strbuf_addf(&plist, repeat, i, minute);
+		break;
+
+	case SCHEDULE_WEEKLY:
+		strbuf_addf(&plist,
+			    "<dict>\n"
+			    "<key>Day</key><integer>0</integer>\n"
+			    "<key>Hour</key><integer>0</integer>\n"
+			    "<key>Minute</key><integer>%d</integer>\n"
+			    "</dict>\n",
+			    minute);
+		break;
+
+	default:
+		/* unreachable */
+		break;
+	}
+	strbuf_addstr(&plist, "</array>\n</dict>\n</plist>\n");
+
+	if (safe_create_leading_directories(filename))
+		die(_("failed to create directories for '%s'"), filename);
+
+	if ((long)lock_file_timeout_ms < 0 &&
+	    git_config_get_ulong("gc.launchctlplistlocktimeoutms",
+				 &lock_file_timeout_ms))
+		lock_file_timeout_ms = 150;
+
+	fd = hold_lock_file_for_update_timeout(&lk, filename, LOCK_DIE_ON_ERROR,
+					       lock_file_timeout_ms);
+
+	/*
+	 * Does this file already exist? With the intended contents? Is it
+	 * registered already? Then it does not need to be re-registered.
+	 */
+	if (!stat(filename, &st) && st.st_size == plist.len &&
+	    strbuf_read_file(&plist2, filename, plist.len) == plist.len &&
+	    !strbuf_cmp(&plist, &plist2) &&
+	    launchctl_list_contains_plist(name, cmd))
+		rollback_lock_file(&lk);
+	else {
+		if (write_in_full(fd, plist.buf, plist.len) < 0 ||
+		    commit_lock_file(&lk))
+			die_errno(_("could not write '%s'"), filename);
+
+		/* bootout might fail if not already running, so ignore */
+		launchctl_boot_plist(0, filename);
+		if (launchctl_boot_plist(1, filename))
+			die(_("failed to bootstrap service %s"), filename);
+	}
+
+	free(filename);
+	free(name);
+	free(cmd);
+	strbuf_release(&plist);
+	strbuf_release(&plist2);
+	return 0;
+}
+
+static int launchctl_add_plists(void)
+{
+	const char *exec_path = git_exec_path();
+
+	return launchctl_schedule_plist(exec_path, SCHEDULE_HOURLY) ||
+	       launchctl_schedule_plist(exec_path, SCHEDULE_DAILY) ||
+	       launchctl_schedule_plist(exec_path, SCHEDULE_WEEKLY);
+}
+
+static int launchctl_update_schedule(int run_maintenance, int fd UNUSED)
+{
+	if (run_maintenance)
+		return launchctl_add_plists();
+	else
+		return launchctl_remove_plists();
+}
+
+static int is_schtasks_available(void)
+{
+	int is_available;
+	if (get_schedule_cmd("schtasks", &is_available, NULL))
+		return is_available;
+
+#ifdef GIT_WINDOWS_NATIVE
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+static char *schtasks_task_name(const char *frequency)
+{
+	struct strbuf label = STRBUF_INIT;
+	strbuf_addf(&label, "Git Maintenance (%s)", frequency);
+	return strbuf_detach(&label, NULL);
+}
+
+static int schtasks_remove_task(enum schedule_priority schedule)
+{
+	char *cmd;
+	struct child_process child = CHILD_PROCESS_INIT;
+	const char *frequency = get_frequency(schedule);
+	char *name = schtasks_task_name(frequency);
+
+	get_schedule_cmd("schtasks", NULL, &cmd);
+	strvec_split(&child.args, cmd);
+	strvec_pushl(&child.args, "/delete", "/tn", name, "/f", NULL);
+	free(name);
+	free(cmd);
+
+	return run_command(&child);
+}
+
+static int schtasks_remove_tasks(void)
+{
+	return schtasks_remove_task(SCHEDULE_HOURLY) ||
+	       schtasks_remove_task(SCHEDULE_DAILY) ||
+	       schtasks_remove_task(SCHEDULE_WEEKLY);
+}
+
+static int schtasks_schedule_task(const char *exec_path, enum schedule_priority schedule)
+{
+	char *cmd;
+	int result;
+	struct child_process child = CHILD_PROCESS_INIT;
+	const char *xml;
+	struct tempfile *tfile;
+	const char *frequency = get_frequency(schedule);
+	char *name = schtasks_task_name(frequency);
+	struct strbuf tfilename = STRBUF_INIT;
+	int minute = get_random_minute();
+
+	get_schedule_cmd("schtasks", NULL, &cmd);
+
+	strbuf_addf(&tfilename, "%s/schedule_%s_XXXXXX",
+		    repo_get_common_dir(the_repository), frequency);
+	tfile = xmks_tempfile(tfilename.buf);
+	strbuf_release(&tfilename);
+
+	if (!fdopen_tempfile(tfile, "w"))
+		die(_("failed to create temp xml file"));
+
+	xml = "<?xml version=\"1.0\" ?>\n"
+	      "<Task version=\"1.4\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\";>\n"
+	      "<Triggers>\n"
+	      "<CalendarTrigger>\n";
+	fputs(xml, tfile->fp);
+
+	switch (schedule) {
+	case SCHEDULE_HOURLY:
+		fprintf(tfile->fp,
+			"<StartBoundary>2020-01-01T01:%02d:00</StartBoundary>\n"
+			"<Enabled>true</Enabled>\n"
+			"<ScheduleByDay>\n"
+			"<DaysInterval>1</DaysInterval>\n"
+			"</ScheduleByDay>\n"
+			"<Repetition>\n"
+			"<Interval>PT1H</Interval>\n"
+			"<Duration>PT23H</Duration>\n"
+			"<StopAtDurationEnd>false</StopAtDurationEnd>\n"
+			"</Repetition>\n",
+			minute);
+		break;
+
+	case SCHEDULE_DAILY:
+		fprintf(tfile->fp,
+			"<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
+			"<Enabled>true</Enabled>\n"
+			"<ScheduleByWeek>\n"
+			"<DaysOfWeek>\n"
+			"<Monday />\n"
+			"<Tuesday />\n"
+			"<Wednesday />\n"
+			"<Thursday />\n"
+			"<Friday />\n"
+			"<Saturday />\n"
+			"</DaysOfWeek>\n"
+			"<WeeksInterval>1</WeeksInterval>\n"
+			"</ScheduleByWeek>\n",
+			minute);
+		break;
+
+	case SCHEDULE_WEEKLY:
+		fprintf(tfile->fp,
+			"<StartBoundary>2020-01-01T00:%02d:00</StartBoundary>\n"
+			"<Enabled>true</Enabled>\n"
+			"<ScheduleByWeek>\n"
+			"<DaysOfWeek>\n"
+			"<Sunday />\n"
+			"</DaysOfWeek>\n"
+			"<WeeksInterval>1</WeeksInterval>\n"
+			"</ScheduleByWeek>\n",
+			minute);
+		break;
+
+	default:
+		break;
+	}
+
+	xml = "</CalendarTrigger>\n"
+	      "</Triggers>\n"
+	      "<Principals>\n"
+	      "<Principal id=\"Author\">\n"
+	      "<LogonType>InteractiveToken</LogonType>\n"
+	      "<RunLevel>LeastPrivilege</RunLevel>\n"
+	      "</Principal>\n"
+	      "</Principals>\n"
+	      "<Settings>\n"
+	      "<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>\n"
+	      "<Enabled>true</Enabled>\n"
+	      "<Hidden>true</Hidden>\n"
+	      "<UseUnifiedSchedulingEngine>true</UseUnifiedSchedulingEngine>\n"
+	      "<WakeToRun>false</WakeToRun>\n"
+	      "<ExecutionTimeLimit>PT72H</ExecutionTimeLimit>\n"
+	      "<Priority>7</Priority>\n"
+	      "</Settings>\n"
+	      "<Actions Context=\"Author\">\n"
+	      "<Exec>\n"
+	      "<Command>\"%s\\headless-git.exe\"</Command>\n"
+	      "<Arguments>--exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%s</Arguments>\n"
+	      "</Exec>\n"
+	      "</Actions>\n"
+	      "</Task>\n";
+	fprintf(tfile->fp, xml, exec_path, exec_path,
+		get_extra_config_parameters(), frequency);
+	strvec_split(&child.args, cmd);
+	strvec_pushl(&child.args, "/create", "/tn", name, "/f", "/xml",
+				  get_tempfile_path(tfile), NULL);
+	close_tempfile_gently(tfile);
+
+	child.no_stdout = 1;
+	child.no_stderr = 1;
+
+	if (start_command(&child))
+		die(_("failed to start schtasks"));
+	result = finish_command(&child);
+
+	delete_tempfile(&tfile);
+	free(name);
+	free(cmd);
+	return result;
+}
+
+static int schtasks_schedule_tasks(void)
+{
+	const char *exec_path = git_exec_path();
+
+	return schtasks_schedule_task(exec_path, SCHEDULE_HOURLY) ||
+	       schtasks_schedule_task(exec_path, SCHEDULE_DAILY) ||
+	       schtasks_schedule_task(exec_path, SCHEDULE_WEEKLY);
+}
+
+static int schtasks_update_schedule(int run_maintenance, int fd UNUSED)
+{
+	if (run_maintenance)
+		return schtasks_schedule_tasks();
+	else
+		return schtasks_remove_tasks();
+}
+
+MAYBE_UNUSED
+static int check_crontab_process(const char *cmd)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	strvec_split(&child.args, cmd);
+	strvec_push(&child.args, "-l");
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.no_stderr = 1;
+	child.silent_exec_failure = 1;
+
+	if (start_command(&child))
+		return 0;
+	/* Ignore exit code, as an empty crontab will return error. */
+	finish_command(&child);
+	return 1;
+}
+
+static int is_crontab_available(void)
+{
+	char *cmd;
+	int is_available;
+	int ret;
+
+	if (get_schedule_cmd("crontab", &is_available, &cmd)) {
+		ret = is_available;
+		goto out;
+	}
+
+#ifdef __APPLE__
+	/*
+	 * macOS has cron, but it requires special permissions and will
+	 * create a UI alert when attempting to run this command.
+	 */
+	ret = 0;
+#else
+	ret = check_crontab_process(cmd);
+#endif
+
+out:
+	free(cmd);
+	return ret;
+}
+
+#define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE"
+#define END_LINE "# END GIT MAINTENANCE SCHEDULE"
+
+static int crontab_update_schedule(int run_maintenance, int fd)
+{
+	char *cmd;
+	int result = 0;
+	int in_old_region = 0;
+	struct child_process crontab_list = CHILD_PROCESS_INIT;
+	struct child_process crontab_edit = CHILD_PROCESS_INIT;
+	FILE *cron_list, *cron_in;
+	struct strbuf line = STRBUF_INIT;
+	struct tempfile *tmpedit = NULL;
+	int minute = get_random_minute();
+
+	get_schedule_cmd("crontab", NULL, &cmd);
+	strvec_split(&crontab_list.args, cmd);
+	strvec_push(&crontab_list.args, "-l");
+	crontab_list.in = -1;
+	crontab_list.out = dup(fd);
+	crontab_list.git_cmd = 0;
+
+	if (start_command(&crontab_list)) {
+		result = error(_("failed to run 'crontab -l'; your system might not support 'cron'"));
+		goto out;
+	}
+
+	/* Ignore exit code, as an empty crontab will return error. */
+	finish_command(&crontab_list);
+
+	tmpedit = mks_tempfile_t(".git_cron_edit_tmpXXXXXX");
+	if (!tmpedit) {
+		result = error(_("failed to create crontab temporary file"));
+		goto out;
+	}
+	cron_in = fdopen_tempfile(tmpedit, "w");
+	if (!cron_in) {
+		result = error(_("failed to open temporary file"));
+		goto out;
+	}
+
+	/*
+	 * Read from the .lock file, filtering out the old
+	 * schedule while appending the new schedule.
+	 */
+	cron_list = fdopen(fd, "r");
+	rewind(cron_list);
+
+	while (!strbuf_getline_lf(&line, cron_list)) {
+		if (!in_old_region && !strcmp(line.buf, BEGIN_LINE))
+			in_old_region = 1;
+		else if (in_old_region && !strcmp(line.buf, END_LINE))
+			in_old_region = 0;
+		else if (!in_old_region)
+			fprintf(cron_in, "%s\n", line.buf);
+	}
+	strbuf_release(&line);
+
+	if (run_maintenance) {
+		struct strbuf line_format = STRBUF_INIT;
+		const char *exec_path = git_exec_path();
+
+		fprintf(cron_in, "%s\n", BEGIN_LINE);
+		fprintf(cron_in,
+			"# The following schedule was created by Git\n");
+		fprintf(cron_in, "# Any edits made in this region might be\n");
+		fprintf(cron_in,
+			"# replaced in the future by a Git command.\n\n");
+
+		strbuf_addf(&line_format,
+			    "%%d %%s * * %%s \"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%s\n",
+			    exec_path, exec_path, get_extra_config_parameters());
+		fprintf(cron_in, line_format.buf, minute, "1-23", "*", "hourly");
+		fprintf(cron_in, line_format.buf, minute, "0", "1-6", "daily");
+		fprintf(cron_in, line_format.buf, minute, "0", "0", "weekly");
+		strbuf_release(&line_format);
+
+		fprintf(cron_in, "\n%s\n", END_LINE);
+	}
+
+	fflush(cron_in);
+
+	strvec_split(&crontab_edit.args, cmd);
+	strvec_push(&crontab_edit.args, get_tempfile_path(tmpedit));
+	crontab_edit.git_cmd = 0;
+
+	if (start_command(&crontab_edit)) {
+		result = error(_("failed to run 'crontab'; your system might not support 'cron'"));
+		goto out;
+	}
+
+	if (finish_command(&crontab_edit))
+		result = error(_("'crontab' died"));
+	else
+		fclose(cron_list);
+
+out:
+	delete_tempfile(&tmpedit);
+	free(cmd);
+	return result;
+}
+
+static int real_is_systemd_timer_available(void)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	strvec_pushl(&child.args, "systemctl", "--user", "list-timers", NULL);
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.no_stderr = 1;
+	child.silent_exec_failure = 1;
+
+	if (start_command(&child))
+		return 0;
+	if (finish_command(&child))
+		return 0;
+	return 1;
+}
+
+static int is_systemd_timer_available(void)
+{
+	int is_available;
+
+	if (get_schedule_cmd("systemctl", &is_available, NULL))
+		return is_available;
+
+	return real_is_systemd_timer_available();
+}
+
+static char *xdg_config_home_systemd(const char *filename)
+{
+	return xdg_config_home_for("systemd/user", filename);
+}
+
+#define SYSTEMD_UNIT_FORMAT "git-maintenance@%s.%s"
+
+static int systemd_timer_delete_timer_file(enum schedule_priority priority)
+{
+	int ret = 0;
+	const char *frequency = get_frequency(priority);
+	char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+	char *filename = xdg_config_home_systemd(local_timer_name);
+
+	if (unlink(filename) && !is_missing_file_error(errno))
+		ret = error_errno(_("failed to delete '%s'"), filename);
+
+	free(filename);
+	free(local_timer_name);
+	return ret;
+}
+
+static int systemd_timer_delete_service_template(void)
+{
+	int ret = 0;
+	char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+	char *filename = xdg_config_home_systemd(local_service_name);
+	if (unlink(filename) && !is_missing_file_error(errno))
+		ret = error_errno(_("failed to delete '%s'"), filename);
+
+	free(filename);
+	free(local_service_name);
+	return ret;
+}
+
+/*
+ * Write the schedule information into a git-maintenance@<schedule>.timer
+ * file using a custom minute. This timer file cannot use the templating
+ * system, so we generate a specific file for each.
+ */
+static int systemd_timer_write_timer_file(enum schedule_priority schedule,
+					  int minute)
+{
+	int res = -1;
+	char *filename;
+	FILE *file;
+	const char *unit;
+	char *schedule_pattern = NULL;
+	const char *frequency = get_frequency(schedule);
+	char *local_timer_name = xstrfmt(SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+	filename = xdg_config_home_systemd(local_timer_name);
+
+	if (safe_create_leading_directories(filename)) {
+		error(_("failed to create directories for '%s'"), filename);
+		goto error;
+	}
+	file = fopen_or_warn(filename, "w");
+	if (!file)
+		goto error;
+
+	switch (schedule) {
+	case SCHEDULE_HOURLY:
+		schedule_pattern = xstrfmt("*-*-* 1..23:%02d:00", minute);
+		break;
+
+	case SCHEDULE_DAILY:
+		schedule_pattern = xstrfmt("Tue..Sun *-*-* 0:%02d:00", minute);
+		break;
+
+	case SCHEDULE_WEEKLY:
+		schedule_pattern = xstrfmt("Mon 0:%02d:00", minute);
+		break;
+
+	default:
+		BUG("Unhandled schedule_priority");
+	}
+
+	unit = "# This file was created and is maintained by Git.\n"
+	       "# Any edits made in this file might be replaced in the future\n"
+	       "# by a Git command.\n"
+	       "\n"
+	       "[Unit]\n"
+	       "Description=Optimize Git repositories data\n"
+	       "\n"
+	       "[Timer]\n"
+	       "OnCalendar=%s\n"
+	       "Persistent=true\n"
+	       "\n"
+	       "[Install]\n"
+	       "WantedBy=timers.target\n";
+	if (fprintf(file, unit, schedule_pattern) < 0) {
+		error(_("failed to write to '%s'"), filename);
+		fclose(file);
+		goto error;
+	}
+	if (fclose(file) == EOF) {
+		error_errno(_("failed to flush '%s'"), filename);
+		goto error;
+	}
+
+	res = 0;
+
+error:
+	free(schedule_pattern);
+	free(local_timer_name);
+	free(filename);
+	return res;
+}
+
+/*
+ * No matter the schedule, we use the same service and can make use of the
+ * templating system. When installing git-maintenance@<schedule>.timer,
+ * systemd will notice that git-maintenance@.service exists as a template
+ * and will use this file and insert the <schedule> into the template at
+ * the position of "%i".
+ */
+static int systemd_timer_write_service_template(const char *exec_path)
+{
+	int res = -1;
+	char *filename;
+	FILE *file;
+	const char *unit;
+	char *local_service_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "service");
+
+	filename = xdg_config_home_systemd(local_service_name);
+	if (safe_create_leading_directories(filename)) {
+		error(_("failed to create directories for '%s'"), filename);
+		goto error;
+	}
+	file = fopen_or_warn(filename, "w");
+	if (!file)
+		goto error;
+
+	unit = "# This file was created and is maintained by Git.\n"
+	       "# Any edits made in this file might be replaced in the future\n"
+	       "# by a Git command.\n"
+	       "\n"
+	       "[Unit]\n"
+	       "Description=Optimize Git repositories data\n"
+	       "\n"
+	       "[Service]\n"
+	       "Type=oneshot\n"
+	       "ExecStart=\"%s/git\" --exec-path=\"%s\" %s for-each-repo --keep-going --config=maintenance.repo maintenance run --schedule=%%i\n"
+	       "LockPersonality=yes\n"
+	       "MemoryDenyWriteExecute=yes\n"
+	       "NoNewPrivileges=yes\n"
+	       "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_VSOCK\n"
+	       "RestrictNamespaces=yes\n"
+	       "RestrictRealtime=yes\n"
+	       "RestrictSUIDSGID=yes\n"
+	       "SystemCallArchitectures=native\n"
+	       "SystemCallFilter=@system-service\n";
+	if (fprintf(file, unit, exec_path, exec_path, get_extra_config_parameters()) < 0) {
+		error(_("failed to write to '%s'"), filename);
+		fclose(file);
+		goto error;
+	}
+	if (fclose(file) == EOF) {
+		error_errno(_("failed to flush '%s'"), filename);
+		goto error;
+	}
+
+	res = 0;
+
+error:
+	free(local_service_name);
+	free(filename);
+	return res;
+}
+
+static int systemd_timer_enable_unit(int enable,
+				     enum schedule_priority schedule,
+				     int minute)
+{
+	char *cmd = NULL;
+	struct child_process child = CHILD_PROCESS_INIT;
+	const char *frequency = get_frequency(schedule);
+	int ret;
+
+	/*
+	 * Disabling the systemd unit while it is already disabled makes
+	 * systemctl print an error.
+	 * Let's ignore it since it means we already are in the expected state:
+	 * the unit is disabled.
+	 *
+	 * On the other hand, enabling a systemd unit which is already enabled
+	 * produces no error.
+	 */
+	if (!enable) {
+		child.no_stderr = 1;
+	} else if (systemd_timer_write_timer_file(schedule, minute)) {
+		ret = -1;
+		goto out;
+	}
+
+	get_schedule_cmd("systemctl", NULL, &cmd);
+	strvec_split(&child.args, cmd);
+	strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
+		     "--now", NULL);
+	strvec_pushf(&child.args, SYSTEMD_UNIT_FORMAT, frequency, "timer");
+
+	if (start_command(&child)) {
+		ret = error(_("failed to start systemctl"));
+		goto out;
+	}
+
+	if (finish_command(&child)) {
+		/*
+		 * Disabling an already disabled systemd unit makes
+		 * systemctl fail.
+		 * Let's ignore this failure.
+		 *
+		 * Enabling an enabled systemd unit doesn't fail.
+		 */
+		if (enable) {
+			ret = error(_("failed to run systemctl"));
+			goto out;
+		}
+	}
+
+	ret = 0;
+
+out:
+	free(cmd);
+	return ret;
+}
+
+/*
+ * A previous version of Git wrote the timer units as template files.
+ * Clean these up, if they exist.
+ */
+static void systemd_timer_delete_stale_timer_templates(void)
+{
+	char *timer_template_name = xstrfmt(SYSTEMD_UNIT_FORMAT, "", "timer");
+	char *filename = xdg_config_home_systemd(timer_template_name);
+
+	if (unlink(filename) && !is_missing_file_error(errno))
+		warning(_("failed to delete '%s'"), filename);
+
+	free(filename);
+	free(timer_template_name);
+}
+
+static int systemd_timer_delete_unit_files(void)
+{
+	systemd_timer_delete_stale_timer_templates();
+
+	/* Purposefully not short-circuited to make sure all are called. */
+	return systemd_timer_delete_timer_file(SCHEDULE_HOURLY) |
+	       systemd_timer_delete_timer_file(SCHEDULE_DAILY) |
+	       systemd_timer_delete_timer_file(SCHEDULE_WEEKLY) |
+	       systemd_timer_delete_service_template();
+}
+
+static int systemd_timer_delete_units(void)
+{
+	int minute = get_random_minute();
+	/* Purposefully not short-circuited to make sure all are called. */
+	return systemd_timer_enable_unit(0, SCHEDULE_HOURLY, minute) |
+	       systemd_timer_enable_unit(0, SCHEDULE_DAILY, minute) |
+	       systemd_timer_enable_unit(0, SCHEDULE_WEEKLY, minute) |
+	       systemd_timer_delete_unit_files();
+}
+
+static int systemd_timer_setup_units(void)
+{
+	int minute = get_random_minute();
+	const char *exec_path = git_exec_path();
+
+	int ret = systemd_timer_write_service_template(exec_path) ||
+		  systemd_timer_enable_unit(1, SCHEDULE_HOURLY, minute) ||
+		  systemd_timer_enable_unit(1, SCHEDULE_DAILY, minute) ||
+		  systemd_timer_enable_unit(1, SCHEDULE_WEEKLY, minute);
+
+	if (ret)
+		systemd_timer_delete_units();
+	else
+		systemd_timer_delete_stale_timer_templates();
+
+	return ret;
+}
+
+static int systemd_timer_update_schedule(int run_maintenance, int fd UNUSED)
+{
+	if (run_maintenance)
+		return systemd_timer_setup_units();
+	else
+		return systemd_timer_delete_units();
+}
+
+enum scheduler {
+	SCHEDULER_INVALID = -1,
+	SCHEDULER_AUTO,
+	SCHEDULER_CRON,
+	SCHEDULER_SYSTEMD,
+	SCHEDULER_LAUNCHCTL,
+	SCHEDULER_SCHTASKS,
+};
+
+static const struct {
+	const char *name;
+	int (*is_available)(void);
+	int (*update_schedule)(int run_maintenance, int fd);
+} scheduler_fn[] = {
+	[SCHEDULER_CRON] = {
+		.name = "crontab",
+		.is_available = is_crontab_available,
+		.update_schedule = crontab_update_schedule,
+	},
+	[SCHEDULER_SYSTEMD] = {
+		.name = "systemctl",
+		.is_available = is_systemd_timer_available,
+		.update_schedule = systemd_timer_update_schedule,
+	},
+	[SCHEDULER_LAUNCHCTL] = {
+		.name = "launchctl",
+		.is_available = is_launchctl_available,
+		.update_schedule = launchctl_update_schedule,
+	},
+	[SCHEDULER_SCHTASKS] = {
+		.name = "schtasks",
+		.is_available = is_schtasks_available,
+		.update_schedule = schtasks_update_schedule,
+	},
+};
+
+static enum scheduler parse_scheduler(const char *value)
+{
+	if (!value)
+		return SCHEDULER_INVALID;
+	else if (!strcasecmp(value, "auto"))
+		return SCHEDULER_AUTO;
+	else if (!strcasecmp(value, "cron") || !strcasecmp(value, "crontab"))
+		return SCHEDULER_CRON;
+	else if (!strcasecmp(value, "systemd") ||
+		 !strcasecmp(value, "systemd-timer"))
+		return SCHEDULER_SYSTEMD;
+	else if (!strcasecmp(value, "launchctl"))
+		return SCHEDULER_LAUNCHCTL;
+	else if (!strcasecmp(value, "schtasks"))
+		return SCHEDULER_SCHTASKS;
+	else
+		return SCHEDULER_INVALID;
+}
+
+static int maintenance_opt_scheduler(const struct option *opt, const char *arg,
+				     int unset)
+{
+	enum scheduler *scheduler = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	*scheduler = parse_scheduler(arg);
+	if (*scheduler == SCHEDULER_INVALID)
+		return error(_("unrecognized --scheduler argument '%s'"), arg);
+	return 0;
+}
+
+struct maintenance_start_opts {
+	enum scheduler scheduler;
+};
+
+static enum scheduler resolve_scheduler(enum scheduler scheduler)
+{
+	if (scheduler != SCHEDULER_AUTO)
+		return scheduler;
+
+#if defined(__APPLE__)
+	return SCHEDULER_LAUNCHCTL;
+
+#elif defined(GIT_WINDOWS_NATIVE)
+	return SCHEDULER_SCHTASKS;
+
+#elif defined(__linux__)
+	if (is_systemd_timer_available())
+		return SCHEDULER_SYSTEMD;
+	else if (is_crontab_available())
+		return SCHEDULER_CRON;
+	else
+		die(_("neither systemd timers nor crontab are available"));
+
+#else
+	return SCHEDULER_CRON;
+#endif
+}
+
+static void validate_scheduler(enum scheduler scheduler)
+{
+	if (scheduler == SCHEDULER_INVALID)
+		BUG("invalid scheduler");
+	if (scheduler == SCHEDULER_AUTO)
+		BUG("resolve_scheduler should have been called before");
+
+	if (!scheduler_fn[scheduler].is_available())
+		die(_("%s scheduler is not available"),
+		    scheduler_fn[scheduler].name);
+}
+
+static int update_background_schedule(const struct maintenance_start_opts *opts,
+				      int enable)
+{
+	unsigned int i;
+	int result = 0;
+	struct lock_file lk;
+	char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path);
+
+	if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) {
+		if (errno == EEXIST)
+			error(_("unable to create '%s.lock': %s.\n\n"
+			    "Another scheduled git-maintenance(1) process seems to be running in this\n"
+			    "repository. Please make sure no other maintenance processes are running and\n"
+			    "then try again. If it still fails, a git-maintenance(1) process may have\n"
+			    "crashed in this repository earlier: remove the file manually to continue."),
+			    absolute_path(lock_path), strerror(errno));
+		else
+			error_errno(_("cannot acquire lock for scheduled background maintenance"));
+		free(lock_path);
+		return -1;
+	}
+
+	for (i = 1; i < ARRAY_SIZE(scheduler_fn); i++) {
+		if (enable && opts->scheduler == i)
+			continue;
+		if (!scheduler_fn[i].is_available())
+			continue;
+		scheduler_fn[i].update_schedule(0, get_lock_file_fd(&lk));
+	}
+
+	if (enable)
+		result = scheduler_fn[opts->scheduler].update_schedule(
+			1, get_lock_file_fd(&lk));
+
+	rollback_lock_file(&lk);
+
+	free(lock_path);
+	return result;
+}
+
+static const char *const builtin_maintenance_start_usage[] = {
+	N_("git maintenance start [--scheduler=<scheduler>]"),
+	NULL
+};
+
+static int maintenance_start(int argc, const char **argv, const char *prefix,
+			     struct repository *repo)
+{
+	struct maintenance_start_opts opts = { 0 };
+	struct option options[] = {
+		OPT_CALLBACK_F(
+			0, "scheduler", &opts.scheduler, N_("scheduler"),
+			N_("scheduler to trigger git maintenance run"),
+			PARSE_OPT_NONEG, maintenance_opt_scheduler),
+		OPT_END()
+	};
+	const char *register_args[] = { "register", NULL };
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_maintenance_start_usage, 0);
+	if (argc)
+		usage_with_options(builtin_maintenance_start_usage, options);
+
+	opts.scheduler = resolve_scheduler(opts.scheduler);
+	validate_scheduler(opts.scheduler);
+
+	if (update_background_schedule(&opts, 1))
+		die(_("failed to set up maintenance schedule"));
+
+	if (maintenance_register(ARRAY_SIZE(register_args)-1, register_args, NULL, repo))
+		warning(_("failed to add repo to global config"));
+	return 0;
+}
+
+static const char *const builtin_maintenance_stop_usage[] = {
+	"git maintenance stop",
+	NULL
+};
+
+static int maintenance_stop(int argc, const char **argv, const char *prefix,
+			    struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_maintenance_stop_usage, 0);
+	if (argc)
+		usage_with_options(builtin_maintenance_stop_usage, options);
+	return update_background_schedule(NULL, 0);
+}
+
+static const char * const builtin_maintenance_usage[] = {
+	N_("git maintenance <subcommand> [<options>]"),
+	NULL,
+};
+
+int cmd_maintenance(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option builtin_maintenance_options[] = {
+		OPT_SUBCOMMAND("run", &fn, maintenance_run),
+		OPT_SUBCOMMAND("start", &fn, maintenance_start),
+		OPT_SUBCOMMAND("stop", &fn, maintenance_stop),
+		OPT_SUBCOMMAND("register", &fn, maintenance_register),
+		OPT_SUBCOMMAND("unregister", &fn, maintenance_unregister),
+		OPT_END(),
+	};
+
+	argc = parse_options(argc, argv, prefix, builtin_maintenance_options,
+			     builtin_maintenance_usage, 0);
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/get-tar-commit-id.c b/builtin/get-tar-commit-id.c
new file mode 100644
index 0000000000..e4cd1627b4
--- /dev/null
+++ b/builtin/get-tar-commit-id.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2005, 2006 Rene Scharfe
+ */
+#include "builtin.h"
+#include "commit.h"
+#include "tar.h"
+
+static const char builtin_get_tar_commit_id_usage[] =
+"git get-tar-commit-id";
+
+/* ustar header + extended global header content */
+#define RECORDSIZE	(512)
+#define HEADERSIZE (2 * RECORDSIZE)
+
+int cmd_get_tar_commit_id(int argc,
+			  const char **argv,
+			  const char *prefix,
+			  struct repository *repo UNUSED)
+{
+	char buffer[HEADERSIZE];
+	struct ustar_header *header = (struct ustar_header *)buffer;
+	char *content = buffer + RECORDSIZE;
+	const char *comment;
+	ssize_t n;
+	long len;
+	char *end;
+
+	BUG_ON_NON_EMPTY_PREFIX(prefix);
+
+	show_usage_if_asked(argc, argv, builtin_get_tar_commit_id_usage);
+
+	if (argc != 1)
+		usage(builtin_get_tar_commit_id_usage);
+
+	n = read_in_full(0, buffer, HEADERSIZE);
+	if (n < 0)
+		die_errno("git get-tar-commit-id: read error");
+	if (n != HEADERSIZE)
+		die_errno("git get-tar-commit-id: EOF before reading tar header");
+	if (header->typeflag[0] != TYPEFLAG_GLOBAL_HEADER)
+		return 1;
+
+	errno = 0;
+	len = strtol(content, &end, 10);
+	if (errno == ERANGE || end == content || len < 0)
+		return 1;
+	if (!skip_prefix(end, " comment=", &comment))
+		return 1;
+	len -= comment - content;
+	if (len < 1 || !(len % 2) ||
+	    hash_algo_by_length((len - 1) / 2) == GIT_HASH_UNKNOWN)
+		return 1;
+
+	if (write_in_full(1, comment, len) < 0)
+		die_errno("git get-tar-commit-id: write error");
+
+	return 0;
+}
diff --git a/builtin/grep.c b/builtin/grep.c
new file mode 100644
index 0000000000..d1427290f7
--- /dev/null
+++ b/builtin/grep.c
@@ -0,0 +1,1286 @@
+/*
+ * Builtin "git grep"
+ *
+ * Copyright (c) 2006 Junio C Hamano
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+#include "gettext.h"
+#include "hex.h"
+#include "config.h"
+#include "tag.h"
+#include "tree-walk.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "run-command.h"
+#include "grep.h"
+#include "quote.h"
+#include "dir.h"
+#include "pathspec.h"
+#include "setup.h"
+#include "submodule.h"
+#include "submodule-config.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "packfile.h"
+#include "pager.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "write-or-die.h"
+
+static const char *grep_prefix;
+
+static char const * const grep_usage[] = {
+	N_("git grep [<options>] [-e] <pattern> [<rev>...] [[--] <path>...]"),
+	NULL
+};
+
+static int recurse_submodules;
+
+static int num_threads;
+
+static pthread_t *threads;
+
+/* We use one producer thread and THREADS consumer
+ * threads. The producer adds struct work_items to 'todo' and the
+ * consumers pick work items from the same array.
+ */
+struct work_item {
+	struct grep_source source;
+	char done;
+	struct strbuf out;
+};
+
+/* In the range [todo_done, todo_start) in 'todo' we have work_items
+ * that have been or are processed by a consumer thread. We haven't
+ * written the result for these to stdout yet.
+ *
+ * The work_items in [todo_start, todo_end) are waiting to be picked
+ * up by a consumer thread.
+ *
+ * The ranges are modulo TODO_SIZE.
+ */
+#define TODO_SIZE 128
+static struct work_item todo[TODO_SIZE];
+static int todo_start;
+static int todo_end;
+static int todo_done;
+
+/* Has all work items been added? */
+static int all_work_added;
+
+static struct repository **repos_to_free;
+static size_t repos_to_free_nr, repos_to_free_alloc;
+
+/* This lock protects all the variables above. */
+static pthread_mutex_t grep_mutex;
+
+static inline void grep_lock(void)
+{
+	pthread_mutex_lock(&grep_mutex);
+}
+
+static inline void grep_unlock(void)
+{
+	pthread_mutex_unlock(&grep_mutex);
+}
+
+/* Signalled when a new work_item is added to todo. */
+static pthread_cond_t cond_add;
+
+/* Signalled when the result from one work_item is written to
+ * stdout.
+ */
+static pthread_cond_t cond_write;
+
+/* Signalled when we are finished with everything. */
+static pthread_cond_t cond_result;
+
+static int skip_first_line;
+
+static void add_work(struct grep_opt *opt, struct grep_source *gs)
+{
+	if (opt->binary != GREP_BINARY_TEXT)
+		grep_source_load_driver(gs, opt->repo->index);
+
+	grep_lock();
+
+	while ((todo_end+1) % ARRAY_SIZE(todo) == todo_done) {
+		pthread_cond_wait(&cond_write, &grep_mutex);
+	}
+
+	todo[todo_end].source = *gs;
+	todo[todo_end].done = 0;
+	strbuf_reset(&todo[todo_end].out);
+	todo_end = (todo_end + 1) % ARRAY_SIZE(todo);
+
+	pthread_cond_signal(&cond_add);
+	grep_unlock();
+}
+
+static struct work_item *get_work(void)
+{
+	struct work_item *ret;
+
+	grep_lock();
+	while (todo_start == todo_end && !all_work_added) {
+		pthread_cond_wait(&cond_add, &grep_mutex);
+	}
+
+	if (todo_start == todo_end && all_work_added) {
+		ret = NULL;
+	} else {
+		ret = &todo[todo_start];
+		todo_start = (todo_start + 1) % ARRAY_SIZE(todo);
+	}
+	grep_unlock();
+	return ret;
+}
+
+static void work_done(struct work_item *w)
+{
+	int old_done;
+
+	grep_lock();
+	w->done = 1;
+	old_done = todo_done;
+	for(; todo[todo_done].done && todo_done != todo_start;
+	    todo_done = (todo_done+1) % ARRAY_SIZE(todo)) {
+		w = &todo[todo_done];
+		if (w->out.len) {
+			const char *p = w->out.buf;
+			size_t len = w->out.len;
+
+			/* Skip the leading hunk mark of the first file. */
+			if (skip_first_line) {
+				while (len) {
+					len--;
+					if (*p++ == '\n')
+						break;
+				}
+				skip_first_line = 0;
+			}
+
+			write_or_die(1, p, len);
+		}
+		grep_source_clear(&w->source);
+	}
+
+	if (old_done != todo_done)
+		pthread_cond_signal(&cond_write);
+
+	if (all_work_added && todo_done == todo_end)
+		pthread_cond_signal(&cond_result);
+
+	grep_unlock();
+}
+
+static void free_repos(void)
+{
+	int i;
+
+	for (i = 0; i < repos_to_free_nr; i++) {
+		repo_clear(repos_to_free[i]);
+		free(repos_to_free[i]);
+	}
+	FREE_AND_NULL(repos_to_free);
+	repos_to_free_nr = 0;
+	repos_to_free_alloc = 0;
+}
+
+static void *run(void *arg)
+{
+	int hit = 0;
+	struct grep_opt *opt = arg;
+
+	while (1) {
+		struct work_item *w = get_work();
+		if (!w)
+			break;
+
+		opt->output_priv = w;
+		hit |= grep_source(opt, &w->source);
+		grep_source_clear_data(&w->source);
+		work_done(w);
+	}
+	free_grep_patterns(opt);
+	free(opt);
+
+	return (void*) (intptr_t) hit;
+}
+
+static void strbuf_out(struct grep_opt *opt, const void *buf, size_t size)
+{
+	struct work_item *w = opt->output_priv;
+	strbuf_add(&w->out, buf, size);
+}
+
+static void start_threads(struct grep_opt *opt)
+{
+	int i;
+
+	pthread_mutex_init(&grep_mutex, NULL);
+	pthread_mutex_init(&grep_attr_mutex, NULL);
+	pthread_cond_init(&cond_add, NULL);
+	pthread_cond_init(&cond_write, NULL);
+	pthread_cond_init(&cond_result, NULL);
+	grep_use_locks = 1;
+	enable_obj_read_lock();
+
+	for (i = 0; i < ARRAY_SIZE(todo); i++) {
+		strbuf_init(&todo[i].out, 0);
+	}
+
+	CALLOC_ARRAY(threads, num_threads);
+	for (i = 0; i < num_threads; i++) {
+		int err;
+		struct grep_opt *o = grep_opt_dup(opt);
+		o->output = strbuf_out;
+		compile_grep_patterns(o);
+		err = pthread_create(&threads[i], NULL, run, o);
+
+		if (err)
+			die(_("grep: failed to create thread: %s"),
+			    strerror(err));
+	}
+}
+
+static int wait_all(void)
+{
+	int hit = 0;
+	int i;
+
+	if (!HAVE_THREADS)
+		BUG("Never call this function unless you have started threads");
+
+	grep_lock();
+	all_work_added = 1;
+
+	/* Wait until all work is done. */
+	while (todo_done != todo_end)
+		pthread_cond_wait(&cond_result, &grep_mutex);
+
+	/* Wake up all the consumer threads so they can see that there
+	 * is no more work to do.
+	 */
+	pthread_cond_broadcast(&cond_add);
+	grep_unlock();
+
+	for (i = 0; i < num_threads; i++) {
+		void *h;
+		pthread_join(threads[i], &h);
+		hit |= (int) (intptr_t) h;
+	}
+
+	free(threads);
+
+	pthread_mutex_destroy(&grep_mutex);
+	pthread_mutex_destroy(&grep_attr_mutex);
+	pthread_cond_destroy(&cond_add);
+	pthread_cond_destroy(&cond_write);
+	pthread_cond_destroy(&cond_result);
+	grep_use_locks = 0;
+	disable_obj_read_lock();
+
+	return hit;
+}
+
+static int grep_cmd_config(const char *var, const char *value,
+			   const struct config_context *ctx, void *cb)
+{
+	int st = grep_config(var, value, ctx, cb);
+
+	if (git_color_config(var, value, cb) < 0)
+		st = -1;
+	else if (git_default_config(var, value, ctx, cb) < 0)
+		st = -1;
+
+	if (!strcmp(var, "grep.threads")) {
+		num_threads = git_config_int(var, value, ctx->kvi);
+		if (num_threads < 0)
+			die(_("invalid number of threads specified (%d) for %s"),
+			    num_threads, var);
+		else if (!HAVE_THREADS && num_threads > 1) {
+			/*
+			 * TRANSLATORS: %s is the configuration
+			 * variable for tweaking threads, currently
+			 * grep.threads
+			 */
+			warning(_("no threads support, ignoring %s"), var);
+			num_threads = 1;
+		}
+	}
+
+	if (!strcmp(var, "submodule.recurse"))
+		recurse_submodules = git_config_bool(var, value);
+
+	return st;
+}
+
+static void grep_source_name(struct grep_opt *opt, const char *filename,
+			     int tree_name_len, struct strbuf *out)
+{
+	strbuf_reset(out);
+
+	if (opt->null_following_name) {
+		if (opt->relative && grep_prefix) {
+			struct strbuf rel_buf = STRBUF_INIT;
+			const char *rel_name =
+				relative_path(filename + tree_name_len,
+					      grep_prefix, &rel_buf);
+
+			if (tree_name_len)
+				strbuf_add(out, filename, tree_name_len);
+
+			strbuf_addstr(out, rel_name);
+			strbuf_release(&rel_buf);
+		} else {
+			strbuf_addstr(out, filename);
+		}
+		return;
+	}
+
+	if (opt->relative && grep_prefix)
+		quote_path(filename + tree_name_len, grep_prefix, out, 0);
+	else
+		quote_c_style(filename + tree_name_len, out, NULL, 0);
+
+	if (tree_name_len)
+		strbuf_insert(out, 0, filename, tree_name_len);
+}
+
+static int grep_oid(struct grep_opt *opt, const struct object_id *oid,
+		     const char *filename, int tree_name_len,
+		     const char *path)
+{
+	struct strbuf pathbuf = STRBUF_INIT;
+	struct grep_source gs;
+
+	grep_source_name(opt, filename, tree_name_len, &pathbuf);
+	grep_source_init_oid(&gs, pathbuf.buf, path, oid, opt->repo);
+	strbuf_release(&pathbuf);
+
+	if (num_threads > 1) {
+		/*
+		 * add_work() copies gs and thus assumes ownership of
+		 * its fields, so do not call grep_source_clear()
+		 */
+		add_work(opt, &gs);
+		return 0;
+	} else {
+		int hit;
+
+		hit = grep_source(opt, &gs);
+
+		grep_source_clear(&gs);
+		return hit;
+	}
+}
+
+static int grep_file(struct grep_opt *opt, const char *filename)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct grep_source gs;
+
+	grep_source_name(opt, filename, 0, &buf);
+	grep_source_init_file(&gs, buf.buf, filename);
+	strbuf_release(&buf);
+
+	if (num_threads > 1) {
+		/*
+		 * add_work() copies gs and thus assumes ownership of
+		 * its fields, so do not call grep_source_clear()
+		 */
+		add_work(opt, &gs);
+		return 0;
+	} else {
+		int hit;
+
+		hit = grep_source(opt, &gs);
+
+		grep_source_clear(&gs);
+		return hit;
+	}
+}
+
+static void append_path(struct grep_opt *opt, const void *data, size_t len)
+{
+	struct string_list *path_list = opt->output_priv;
+
+	if (len == 1 && *(const char *)data == '\0')
+		return;
+	string_list_append_nodup(path_list, xstrndup(data, len));
+}
+
+static void run_pager(struct grep_opt *opt, const char *prefix)
+{
+	struct string_list *path_list = opt->output_priv;
+	struct child_process child = CHILD_PROCESS_INIT;
+	int i, status;
+
+	for (i = 0; i < path_list->nr; i++)
+		strvec_push(&child.args, path_list->items[i].string);
+	child.dir = prefix;
+	child.use_shell = 1;
+
+	status = run_command(&child);
+	if (status)
+		exit(status);
+}
+
+static int grep_cache(struct grep_opt *opt,
+		      const struct pathspec *pathspec, int cached);
+static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
+		     struct tree_desc *tree, struct strbuf *base, int tn_len,
+		     int check_attr);
+
+static int grep_submodule(struct grep_opt *opt,
+			  const struct pathspec *pathspec,
+			  const struct object_id *oid,
+			  const char *filename, const char *path, int cached)
+{
+	struct repository *subrepo;
+	struct repository *superproject = opt->repo;
+	struct grep_opt subopt;
+	int hit = 0;
+
+	if (!is_submodule_active(superproject, path))
+		return 0;
+
+	subrepo = xmalloc(sizeof(*subrepo));
+	if (repo_submodule_init(subrepo, superproject, path, null_oid())) {
+		free(subrepo);
+		return 0;
+	}
+	ALLOC_GROW(repos_to_free, repos_to_free_nr + 1, repos_to_free_alloc);
+	repos_to_free[repos_to_free_nr++] = subrepo;
+
+	/*
+	 * NEEDSWORK: repo_read_gitmodules() might call
+	 * add_to_alternates_memory() via config_from_gitmodules(). This
+	 * operation causes a race condition with concurrent object readings
+	 * performed by the worker threads. That's why we need obj_read_lock()
+	 * here. It should be removed once it's no longer necessary to add the
+	 * subrepo's odbs to the in-memory alternates list.
+	 */
+	obj_read_lock();
+
+	/*
+	 * NEEDSWORK: when reading a submodule, the sparsity settings in the
+	 * superproject are incorrectly forgotten or misused. For example:
+	 *
+	 * 1. "command_requires_full_index"
+	 * 	When this setting is turned on for `grep`, only the superproject
+	 *	knows it. All the submodules are read with their own configs
+	 *	and get prepare_repo_settings()'d. Therefore, these submodules
+	 *	"forget" the sparse-index feature switch. As a result, the index
+	 *	of these submodules are expanded unexpectedly.
+	 *
+	 * 2. "core_apply_sparse_checkout"
+	 *	When running `grep` in the superproject, this setting is
+	 *	populated using the superproject's configs. However, once
+	 *	initialized, this config is globally accessible and is read by
+	 *	prepare_repo_settings() for the submodules. For instance, if a
+	 *	submodule is using a sparse-checkout, however, the superproject
+	 *	is not, the result is that the config from the superproject will
+	 *	dictate the behavior for the submodule, making it "forget" its
+	 *	sparse-checkout state.
+	 *
+	 * 3. "core_sparse_checkout_cone"
+	 *	ditto.
+	 *
+	 * Note that this list is not exhaustive.
+	 */
+	repo_read_gitmodules(subrepo, 0);
+
+	/*
+	 * All code paths tested by test code no longer need submodule ODBs to
+	 * be added as alternates, but add it to the list just in case.
+	 * Submodule ODBs added through add_submodule_odb_by_path() will be
+	 * lazily registered as alternates when needed (and except in an
+	 * unexpected code interaction, it won't be needed).
+	 */
+	add_submodule_odb_by_path(subrepo->objects->odb->path);
+	obj_read_unlock();
+
+	memcpy(&subopt, opt, sizeof(subopt));
+	subopt.repo = subrepo;
+
+	if (oid) {
+		enum object_type object_type;
+		struct tree_desc tree;
+		void *data;
+		unsigned long size;
+		struct strbuf base = STRBUF_INIT;
+
+		obj_read_lock();
+		object_type = oid_object_info(subrepo, oid, NULL);
+		obj_read_unlock();
+		data = read_object_with_reference(subrepo,
+						  oid, OBJ_TREE,
+						  &size, NULL);
+		if (!data)
+			die(_("unable to read tree (%s)"), oid_to_hex(oid));
+
+		strbuf_addstr(&base, filename);
+		strbuf_addch(&base, '/');
+
+		init_tree_desc(&tree, oid, data, size);
+		hit = grep_tree(&subopt, pathspec, &tree, &base, base.len,
+				object_type == OBJ_COMMIT);
+		strbuf_release(&base);
+		free(data);
+	} else {
+		hit = grep_cache(&subopt, pathspec, cached);
+	}
+
+	return hit;
+}
+
+static int grep_cache(struct grep_opt *opt,
+		      const struct pathspec *pathspec, int cached)
+{
+	struct repository *repo = opt->repo;
+	int hit = 0;
+	int nr;
+	struct strbuf name = STRBUF_INIT;
+	int name_base_len = 0;
+	if (repo->submodule_prefix) {
+		name_base_len = strlen(repo->submodule_prefix);
+		strbuf_addstr(&name, repo->submodule_prefix);
+	}
+
+	if (repo_read_index(repo) < 0)
+		die(_("index file corrupt"));
+
+	for (nr = 0; nr < repo->index->cache_nr; nr++) {
+		const struct cache_entry *ce = repo->index->cache[nr];
+
+		if (!cached && ce_skip_worktree(ce))
+			continue;
+
+		strbuf_setlen(&name, name_base_len);
+		strbuf_addstr(&name, ce->name);
+		if (S_ISSPARSEDIR(ce->ce_mode)) {
+			enum object_type type;
+			struct tree_desc tree;
+			void *data;
+			unsigned long size;
+
+			data = repo_read_object_file(the_repository, &ce->oid,
+						     &type, &size);
+			if (!data)
+				die(_("unable to read tree %s"), oid_to_hex(&ce->oid));
+			init_tree_desc(&tree, &ce->oid, data, size);
+
+			hit |= grep_tree(opt, pathspec, &tree, &name, 0, 0);
+			strbuf_setlen(&name, name_base_len);
+			strbuf_addstr(&name, ce->name);
+			free(data);
+		} else if (S_ISREG(ce->ce_mode) &&
+		    match_pathspec(repo->index, pathspec, name.buf, name.len, 0, NULL,
+				   S_ISDIR(ce->ce_mode) ||
+				   S_ISGITLINK(ce->ce_mode))) {
+			/*
+			 * If CE_VALID is on, we assume worktree file and its
+			 * cache entry are identical, even if worktree file has
+			 * been modified, so use cache version instead
+			 */
+			if (cached || (ce->ce_flags & CE_VALID)) {
+				if (ce_stage(ce) || ce_intent_to_add(ce))
+					continue;
+				hit |= grep_oid(opt, &ce->oid, name.buf,
+						 0, name.buf);
+			} else {
+				hit |= grep_file(opt, name.buf);
+			}
+		} else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
+			   submodule_path_match(repo->index, pathspec, name.buf, NULL)) {
+			hit |= grep_submodule(opt, pathspec, NULL, ce->name,
+					      ce->name, cached);
+		} else {
+			continue;
+		}
+
+		if (ce_stage(ce)) {
+			do {
+				nr++;
+			} while (nr < repo->index->cache_nr &&
+				 !strcmp(ce->name, repo->index->cache[nr]->name));
+			nr--; /* compensate for loop control */
+		}
+		if (hit && opt->status_only)
+			break;
+	}
+
+	strbuf_release(&name);
+	return hit;
+}
+
+static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
+		     struct tree_desc *tree, struct strbuf *base, int tn_len,
+		     int check_attr)
+{
+	struct repository *repo = opt->repo;
+	int hit = 0;
+	enum interesting match = entry_not_interesting;
+	struct name_entry entry;
+	int old_baselen = base->len;
+	struct strbuf name = STRBUF_INIT;
+	int name_base_len = 0;
+	if (repo->submodule_prefix) {
+		strbuf_addstr(&name, repo->submodule_prefix);
+		name_base_len = name.len;
+	}
+
+	while (tree_entry(tree, &entry)) {
+		int te_len = tree_entry_len(&entry);
+
+		if (match != all_entries_interesting) {
+			strbuf_addstr(&name, base->buf + tn_len);
+			match = tree_entry_interesting(repo->index,
+						       &entry, &name,
+						       pathspec);
+			strbuf_setlen(&name, name_base_len);
+
+			if (match == all_entries_not_interesting)
+				break;
+			if (match == entry_not_interesting)
+				continue;
+		}
+
+		strbuf_add(base, entry.path, te_len);
+
+		if (S_ISREG(entry.mode)) {
+			hit |= grep_oid(opt, &entry.oid, base->buf, tn_len,
+					 check_attr ? base->buf + tn_len : NULL);
+		} else if (S_ISDIR(entry.mode)) {
+			enum object_type type;
+			struct tree_desc sub;
+			void *data;
+			unsigned long size;
+
+			data = repo_read_object_file(the_repository,
+						     &entry.oid, &type, &size);
+			if (!data)
+				die(_("unable to read tree (%s)"),
+				    oid_to_hex(&entry.oid));
+
+			strbuf_addch(base, '/');
+			init_tree_desc(&sub, &entry.oid, data, size);
+			hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
+					 check_attr);
+			free(data);
+		} else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
+			hit |= grep_submodule(opt, pathspec, &entry.oid,
+					      base->buf, base->buf + tn_len,
+					      1); /* ignored */
+		}
+
+		strbuf_setlen(base, old_baselen);
+
+		if (hit && opt->status_only)
+			break;
+	}
+
+	strbuf_release(&name);
+	return hit;
+}
+
+static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
+		       struct object *obj, const char *name, const char *path)
+{
+	if (obj->type == OBJ_BLOB)
+		return grep_oid(opt, &obj->oid, name, 0, path);
+	if (obj->type == OBJ_COMMIT || obj->type == OBJ_TREE) {
+		struct tree_desc tree;
+		void *data;
+		unsigned long size;
+		struct strbuf base;
+		int hit, len;
+
+		data = read_object_with_reference(opt->repo,
+						  &obj->oid, OBJ_TREE,
+						  &size, NULL);
+		if (!data)
+			die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
+
+		len = name ? strlen(name) : 0;
+		strbuf_init(&base, PATH_MAX + len + 1);
+		if (len) {
+			strbuf_add(&base, name, len);
+			strbuf_addch(&base, ':');
+		}
+		init_tree_desc(&tree, &obj->oid, data, size);
+		hit = grep_tree(opt, pathspec, &tree, &base, base.len,
+				obj->type == OBJ_COMMIT);
+		strbuf_release(&base);
+		free(data);
+		return hit;
+	}
+	die(_("unable to grep from object of type %s"), type_name(obj->type));
+}
+
+static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
+			const struct object_array *list)
+{
+	unsigned int i;
+	int hit = 0;
+	const unsigned int nr = list->nr;
+
+	for (i = 0; i < nr; i++) {
+		struct object *real_obj;
+
+		obj_read_lock();
+		real_obj = deref_tag(opt->repo, list->objects[i].item,
+				     NULL, 0);
+		obj_read_unlock();
+
+		if (!real_obj) {
+			char hex[GIT_MAX_HEXSZ + 1];
+			const char *name = list->objects[i].name;
+
+			if (!name) {
+				oid_to_hex_r(hex, &list->objects[i].item->oid);
+				name = hex;
+			}
+			die(_("invalid object '%s' given."), name);
+		}
+
+		/* load the gitmodules file for this rev */
+		if (recurse_submodules) {
+			submodule_free(opt->repo);
+			obj_read_lock();
+			gitmodules_config_oid(&real_obj->oid);
+			obj_read_unlock();
+		}
+		if (grep_object(opt, pathspec, real_obj, list->objects[i].name,
+				list->objects[i].path)) {
+			hit = 1;
+			if (opt->status_only)
+				break;
+		}
+	}
+	return hit;
+}
+
+static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,
+			  int exc_std, int use_index)
+{
+	struct dir_struct dir = DIR_INIT;
+	int i, hit = 0;
+
+	if (!use_index)
+		dir.flags |= DIR_NO_GITLINKS;
+	if (exc_std)
+		setup_standard_excludes(&dir);
+
+	fill_directory(&dir, opt->repo->index, pathspec);
+	for (i = 0; i < dir.nr; i++) {
+		hit |= grep_file(opt, dir.entries[i]->name);
+		if (hit && opt->status_only)
+			break;
+	}
+	dir_clear(&dir);
+	return hit;
+}
+
+static int context_callback(const struct option *opt, const char *arg,
+			    int unset)
+{
+	struct grep_opt *grep_opt = opt->value;
+	int value;
+	const char *endp;
+
+	if (unset) {
+		grep_opt->pre_context = grep_opt->post_context = 0;
+		return 0;
+	}
+	value = strtol(arg, (char **)&endp, 10);
+	if (*endp) {
+		return error(_("switch `%c' expects a numerical value"),
+			     opt->short_name);
+	}
+	grep_opt->pre_context = grep_opt->post_context = value;
+	return 0;
+}
+
+static int file_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct grep_opt *grep_opt = opt->value;
+	int from_stdin;
+	const char *filename = arg;
+	FILE *patterns;
+	int lno = 0;
+	struct strbuf sb = STRBUF_INIT;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (!*filename)
+		; /* leave it as-is */
+	else
+		filename = prefix_filename_except_for_dash(grep_prefix, filename);
+
+	from_stdin = !strcmp(filename, "-");
+	patterns = from_stdin ? stdin : fopen(filename, "r");
+	if (!patterns)
+		die_errno(_("cannot open '%s'"), arg);
+	while (strbuf_getline(&sb, patterns) == 0) {
+		/* ignore empty line like grep does */
+		if (sb.len == 0)
+			continue;
+
+		append_grep_pat(grep_opt, sb.buf, sb.len, arg, ++lno,
+				GREP_PATTERN);
+	}
+	if (!from_stdin)
+		fclose(patterns);
+	strbuf_release(&sb);
+	if (filename != arg)
+		free((void *)filename);
+	return 0;
+}
+
+static int not_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct grep_opt *grep_opt = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	append_grep_pattern(grep_opt, "--not", "command line", 0, GREP_NOT);
+	return 0;
+}
+
+static int and_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct grep_opt *grep_opt = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	append_grep_pattern(grep_opt, "--and", "command line", 0, GREP_AND);
+	return 0;
+}
+
+static int open_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct grep_opt *grep_opt = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	append_grep_pattern(grep_opt, "(", "command line", 0, GREP_OPEN_PAREN);
+	return 0;
+}
+
+static int close_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct grep_opt *grep_opt = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	append_grep_pattern(grep_opt, ")", "command line", 0, GREP_CLOSE_PAREN);
+	return 0;
+}
+
+static int pattern_callback(const struct option *opt, const char *arg,
+			    int unset)
+{
+	struct grep_opt *grep_opt = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	append_grep_pattern(grep_opt, arg, "-e option", 0, GREP_PATTERN);
+	return 0;
+}
+
+int cmd_grep(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
+{
+	int hit = 0;
+	int cached = 0, untracked = 0, opt_exclude = -1;
+	int seen_dashdash = 0;
+	int external_grep_allowed__ignored;
+	const char *show_in_pager = NULL, *default_pager = "dummy";
+	struct grep_opt opt;
+	struct object_array list = OBJECT_ARRAY_INIT;
+	struct pathspec pathspec;
+	struct string_list path_list = STRING_LIST_INIT_DUP;
+	int i;
+	int dummy;
+	int use_index = 1;
+	int allow_revs;
+	int ret;
+
+	struct option options[] = {
+		OPT_BOOL(0, "cached", &cached,
+			N_("search in index instead of in the work tree")),
+		OPT_NEGBIT(0, "no-index", &use_index,
+			 N_("find in contents not managed by git"), 1),
+		OPT_BOOL(0, "untracked", &untracked,
+			N_("search in both tracked and untracked files")),
+		OPT_SET_INT(0, "exclude-standard", &opt_exclude,
+			    N_("ignore files specified via '.gitignore'"), 1),
+		OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
+			 N_("recursively search in each submodule")),
+		OPT_GROUP(""),
+		OPT_BOOL('v', "invert-match", &opt.invert,
+			N_("show non-matching lines")),
+		OPT_BOOL('i', "ignore-case", &opt.ignore_case,
+			N_("case insensitive matching")),
+		OPT_BOOL('w', "word-regexp", &opt.word_regexp,
+			N_("match patterns only at word boundaries")),
+		OPT_SET_INT('a', "text", &opt.binary,
+			N_("process binary files as text"), GREP_BINARY_TEXT),
+		OPT_SET_INT('I', NULL, &opt.binary,
+			N_("don't match patterns in binary files"),
+			GREP_BINARY_NOMATCH),
+		OPT_BOOL(0, "textconv", &opt.allow_textconv,
+			 N_("process binary files with textconv filters")),
+		OPT_SET_INT('r', "recursive", &opt.max_depth,
+			    N_("search in subdirectories (default)"), -1),
+		OPT_INTEGER_F(0, "max-depth", &opt.max_depth,
+			N_("descend at most <n> levels"), PARSE_OPT_NONEG),
+		OPT_GROUP(""),
+		OPT_SET_INT('E', "extended-regexp", &opt.pattern_type_option,
+			    N_("use extended POSIX regular expressions"),
+			    GREP_PATTERN_TYPE_ERE),
+		OPT_SET_INT('G', "basic-regexp", &opt.pattern_type_option,
+			    N_("use basic POSIX regular expressions (default)"),
+			    GREP_PATTERN_TYPE_BRE),
+		OPT_SET_INT('F', "fixed-strings", &opt.pattern_type_option,
+			    N_("interpret patterns as fixed strings"),
+			    GREP_PATTERN_TYPE_FIXED),
+		OPT_SET_INT('P', "perl-regexp", &opt.pattern_type_option,
+			    N_("use Perl-compatible regular expressions"),
+			    GREP_PATTERN_TYPE_PCRE),
+		OPT_GROUP(""),
+		OPT_BOOL('n', "line-number", &opt.linenum, N_("show line numbers")),
+		OPT_BOOL(0, "column", &opt.columnnum, N_("show column number of first match")),
+		OPT_NEGBIT('h', NULL, &opt.pathname, N_("don't show filenames"), 1),
+		OPT_BIT('H', NULL, &opt.pathname, N_("show filenames"), 1),
+		OPT_NEGBIT(0, "full-name", &opt.relative,
+			N_("show filenames relative to top directory"), 1),
+		OPT_BOOL('l', "files-with-matches", &opt.name_only,
+			N_("show only filenames instead of matching lines")),
+		OPT_BOOL(0, "name-only", &opt.name_only,
+			N_("synonym for --files-with-matches")),
+		OPT_BOOL('L', "files-without-match",
+			&opt.unmatch_name_only,
+			N_("show only the names of files without match")),
+		OPT_BOOL_F('z', "null", &opt.null_following_name,
+			   N_("print NUL after filenames"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL('o', "only-matching", &opt.only_matching,
+			N_("show only matching parts of a line")),
+		OPT_BOOL('c', "count", &opt.count,
+			N_("show the number of matches instead of matching lines")),
+		OPT__COLOR(&opt.color, N_("highlight matches")),
+		OPT_BOOL(0, "break", &opt.file_break,
+			N_("print empty line between matches from different files")),
+		OPT_BOOL(0, "heading", &opt.heading,
+			N_("show filename only once above matches from same file")),
+		OPT_GROUP(""),
+		OPT_CALLBACK('C', "context", &opt, N_("n"),
+			N_("show <n> context lines before and after matches"),
+			context_callback),
+		OPT_INTEGER('B', "before-context", &opt.pre_context,
+			N_("show <n> context lines before matches")),
+		OPT_INTEGER('A', "after-context", &opt.post_context,
+			N_("show <n> context lines after matches")),
+		OPT_INTEGER(0, "threads", &num_threads,
+			N_("use <n> worker threads")),
+		OPT_NUMBER_CALLBACK(&opt, N_("shortcut for -C NUM"),
+			context_callback),
+		OPT_BOOL('p', "show-function", &opt.funcname,
+			N_("show a line with the function name before matches")),
+		OPT_BOOL('W', "function-context", &opt.funcbody,
+			N_("show the surrounding function")),
+		OPT_GROUP(""),
+		OPT_CALLBACK('f', NULL, &opt, N_("file"),
+			N_("read patterns from file"), file_callback),
+		OPT_CALLBACK_F('e', NULL, &opt, N_("pattern"),
+			N_("match <pattern>"), PARSE_OPT_NONEG, pattern_callback),
+		OPT_CALLBACK_F(0, "and", &opt, NULL,
+			N_("combine patterns specified with -e"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback),
+		OPT_BOOL_F(0, "or", &dummy, "", PARSE_OPT_NONEG),
+		OPT_CALLBACK_F(0, "not", &opt, NULL, "",
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, not_callback),
+		OPT_CALLBACK_F('(', NULL, &opt, NULL, "",
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
+			open_callback),
+		OPT_CALLBACK_F(')', NULL, &opt, NULL, "",
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG | PARSE_OPT_NODASH,
+			close_callback),
+		OPT__QUIET(&opt.status_only,
+			   N_("indicate hit with exit status without output")),
+		OPT_BOOL(0, "all-match", &opt.all_match,
+			N_("show only matches from files that match all patterns")),
+		OPT_GROUP(""),
+		{ OPTION_STRING, 'O', "open-files-in-pager", &show_in_pager,
+			N_("pager"), N_("show matching files in the pager"),
+			PARSE_OPT_OPTARG | PARSE_OPT_NOCOMPLETE,
+			NULL, (intptr_t)default_pager },
+		OPT_BOOL_F(0, "ext-grep", &external_grep_allowed__ignored,
+			   N_("allow calling of grep(1) (ignored by this build)"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_INTEGER('m', "max-count", &opt.max_count,
+			N_("maximum number of results per file")),
+		OPT_END()
+	};
+	grep_prefix = prefix;
+
+	grep_init(&opt, the_repository);
+	git_config(grep_cmd_config, &opt);
+
+	/*
+	 * If there is no -- then the paths must exist in the working
+	 * tree.  If there is no explicit pattern specified with -e or
+	 * -f, we take the first unrecognized non option to be the
+	 * pattern, but then what follows it must be zero or more
+	 * valid refs up to the -- (if exists), and then existing
+	 * paths.  If there is an explicit pattern, then the first
+	 * unrecognized non option is the beginning of the refs list
+	 * that continues up to the -- (if exists), and then paths.
+	 */
+	argc = parse_options(argc, argv, prefix, options, grep_usage,
+			     PARSE_OPT_KEEP_DASHDASH |
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (the_repository->gitdir) {
+		prepare_repo_settings(the_repository);
+		the_repository->settings.command_requires_full_index = 0;
+	}
+
+	if (use_index && !startup_info->have_repository) {
+		int fallback = 0;
+		git_config_get_bool("grep.fallbacktonoindex", &fallback);
+		if (fallback)
+			use_index = 0;
+		else
+			/* die the same way as if we did it at the beginning */
+			setup_git_directory();
+	}
+	/* Ignore --recurse-submodules if --no-index is given or implied */
+	if (!use_index)
+		recurse_submodules = 0;
+
+	/*
+	 * skip a -- separator; we know it cannot be
+	 * separating revisions from pathnames if
+	 * we haven't even had any patterns yet
+	 */
+	if (argc > 0 && !opt.pattern_list && !strcmp(argv[0], "--")) {
+		argv++;
+		argc--;
+	}
+
+	/* First unrecognized non-option token */
+	if (argc > 0 && !opt.pattern_list) {
+		append_grep_pattern(&opt, argv[0], "command line", 0,
+				    GREP_PATTERN);
+		argv++;
+		argc--;
+	}
+
+	if (show_in_pager == default_pager)
+		show_in_pager = git_pager(the_repository, 1);
+	if (show_in_pager) {
+		opt.color = 0;
+		opt.name_only = 1;
+		opt.null_following_name = 1;
+		opt.output_priv = &path_list;
+		opt.output = append_path;
+		string_list_append(&path_list, show_in_pager);
+	}
+
+	if (!opt.pattern_list)
+		die(_("no pattern given"));
+
+	/* --only-matching has no effect with --invert. */
+	if (opt.invert)
+		opt.only_matching = 0;
+
+	/*
+	 * We have to find "--" in a separate pass, because its presence
+	 * influences how we will parse arguments that come before it.
+	 */
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argv[i], "--")) {
+			seen_dashdash = 1;
+			break;
+		}
+	}
+
+	/*
+	 * Resolve any rev arguments. If we have a dashdash, then everything up
+	 * to it must resolve as a rev. If not, then we stop at the first
+	 * non-rev and assume everything else is a path.
+	 */
+	allow_revs = use_index && !untracked;
+	for (i = 0; i < argc; i++) {
+		const char *arg = argv[i];
+		struct object_id oid;
+		struct object_context oc = {0};
+		struct object *object;
+
+		if (!strcmp(arg, "--")) {
+			i++;
+			break;
+		}
+
+		if (!allow_revs) {
+			if (seen_dashdash)
+				die(_("--no-index or --untracked cannot be used with revs"));
+			break;
+		}
+
+		if (get_oid_with_context(the_repository, arg,
+					 GET_OID_RECORD_PATH,
+					 &oid, &oc)) {
+			if (seen_dashdash)
+				die(_("unable to resolve revision: %s"), arg);
+			object_context_release(&oc);
+			break;
+		}
+
+		object = parse_object_or_die(&oid, arg);
+		if (!seen_dashdash)
+			verify_non_filename(prefix, arg);
+		add_object_array_with_path(object, arg, &list, oc.mode, oc.path);
+		object_context_release(&oc);
+	}
+
+	/*
+	 * Anything left over is presumed to be a path. But in the non-dashdash
+	 * "do what I mean" case, we verify and complain when that isn't true.
+	 */
+	if (!seen_dashdash) {
+		int j;
+		for (j = i; j < argc; j++)
+			verify_filename(prefix, argv[j], j == i && allow_revs);
+	}
+
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_CWD |
+		       (opt.max_depth != -1 ? PATHSPEC_MAXDEPTH_VALID : 0),
+		       prefix, argv + i);
+	pathspec.max_depth = opt.max_depth;
+	pathspec.recursive = 1;
+	pathspec.recurse_submodules = !!recurse_submodules;
+
+	if (recurse_submodules && untracked)
+		die(_("--untracked not supported with --recurse-submodules"));
+
+	/*
+	 * Optimize out the case where the amount of matches is limited to zero.
+	 * We do this to keep results consistent with GNU grep(1).
+	 */
+	if (opt.max_count == 0) {
+		ret = 1;
+		goto out;
+	}
+
+	if (show_in_pager) {
+		if (num_threads > 1)
+			warning(_("invalid option combination, ignoring --threads"));
+		num_threads = 1;
+	} else if (!HAVE_THREADS && num_threads > 1) {
+		warning(_("no threads support, ignoring --threads"));
+		num_threads = 1;
+	} else if (num_threads < 0)
+		die(_("invalid number of threads specified (%d)"), num_threads);
+	else if (num_threads == 0)
+		num_threads = HAVE_THREADS ? online_cpus() : 1;
+
+	if (num_threads > 1) {
+		if (!HAVE_THREADS)
+			BUG("Somebody got num_threads calculation wrong!");
+		if (!(opt.name_only || opt.unmatch_name_only || opt.count)
+		    && (opt.pre_context || opt.post_context ||
+			opt.file_break || opt.funcbody))
+			skip_first_line = 1;
+
+		/*
+		 * Pre-read gitmodules (if not read already) and force eager
+		 * initialization of packed_git to prevent racy lazy
+		 * reading/initialization once worker threads are started.
+		 */
+		if (recurse_submodules)
+			repo_read_gitmodules(the_repository, 1);
+		if (startup_info->have_repository)
+			(void)get_packed_git(the_repository);
+
+		start_threads(&opt);
+	} else {
+		/*
+		 * The compiled patterns on the main path are only
+		 * used when not using threading. Otherwise
+		 * start_threads() above calls compile_grep_patterns()
+		 * for each thread.
+		 */
+		compile_grep_patterns(&opt);
+	}
+
+	if (show_in_pager && (cached || list.nr))
+		die(_("--open-files-in-pager only works on the worktree"));
+
+	if (show_in_pager && opt.pattern_list && !opt.pattern_list->next) {
+		const char *pager = path_list.items[0].string;
+		int len = strlen(pager);
+
+		if (len > 4 && is_dir_sep(pager[len - 5]))
+			pager += len - 4;
+
+		if (opt.ignore_case && !strcmp("less", pager))
+			string_list_append(&path_list, "-I");
+
+		if (!strcmp("less", pager) || !strcmp("vi", pager)) {
+			struct strbuf buf = STRBUF_INIT;
+			strbuf_addf(&buf, "+/%s%s",
+					strcmp("less", pager) ? "" : "*",
+					opt.pattern_list->pattern);
+			string_list_append_nodup(&path_list,
+						 strbuf_detach(&buf, NULL));
+		}
+	}
+
+	if (!show_in_pager && !opt.status_only)
+		setup_pager(the_repository);
+
+	die_for_incompatible_opt3(!use_index, "--no-index",
+				  untracked, "--untracked",
+				  cached, "--cached");
+
+	if (!use_index || untracked) {
+		int use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;
+		hit = grep_directory(&opt, &pathspec, use_exclude, use_index);
+	} else if (0 <= opt_exclude) {
+		die(_("--[no-]exclude-standard cannot be used for tracked contents"));
+	} else if (!list.nr) {
+		if (!cached)
+			setup_work_tree();
+
+		hit = grep_cache(&opt, &pathspec, cached);
+	} else {
+		if (cached)
+			die(_("both --cached and trees are given"));
+
+		hit = grep_objects(&opt, &pathspec, &list);
+	}
+
+	if (num_threads > 1)
+		hit |= wait_all();
+	if (hit && show_in_pager)
+		run_pager(&opt, prefix);
+
+	ret = !hit;
+
+out:
+	clear_pathspec(&pathspec);
+	string_list_clear(&path_list, 0);
+	free_grep_patterns(&opt);
+	object_array_clear(&list);
+	free_repos();
+	return ret;
+}
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
new file mode 100644
index 0000000000..a25f0403f4
--- /dev/null
+++ b/builtin/hash-object.c
@@ -0,0 +1,180 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ * Copyright (C) Junio C Hamano, 2005
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "blob.h"
+#include "quote.h"
+#include "parse-options.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "write-or-die.h"
+
+/*
+ * This is to create corrupt objects for debugging and as such it
+ * needs to bypass the data conversion performed by, and the type
+ * limitation imposed by, index_fd() and its callees.
+ */
+static int hash_literally(struct object_id *oid, int fd, const char *type, unsigned flags)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int ret;
+
+	if (strbuf_read(&buf, fd, 4096) < 0)
+		ret = -1;
+	else
+		ret = write_object_file_literally(buf.buf, buf.len, type, oid,
+						 flags);
+	close(fd);
+	strbuf_release(&buf);
+	return ret;
+}
+
+static void hash_fd(int fd, const char *type, const char *path, unsigned flags,
+		    int literally)
+{
+	struct stat st;
+	struct object_id oid;
+
+	if (fstat(fd, &st) < 0 ||
+	    (literally
+	     ? hash_literally(&oid, fd, type, flags)
+	     : index_fd(the_repository->index, &oid, fd, &st,
+			type_from_string(type), path, flags)))
+		die((flags & HASH_WRITE_OBJECT)
+		    ? "Unable to add %s to database"
+		    : "Unable to hash %s", path);
+	printf("%s\n", oid_to_hex(&oid));
+	maybe_flush_or_die(stdout, "hash to stdout");
+}
+
+static void hash_object(const char *path, const char *type, const char *vpath,
+			unsigned flags, int literally)
+{
+	int fd;
+	fd = xopen(path, O_RDONLY);
+	hash_fd(fd, type, vpath, flags, literally);
+}
+
+static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,
+			     int literally)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf unquoted = STRBUF_INIT;
+
+	while (strbuf_getline(&buf, stdin) != EOF) {
+		if (buf.buf[0] == '"') {
+			strbuf_reset(&unquoted);
+			if (unquote_c_style(&unquoted, buf.buf, NULL))
+				die("line is badly quoted");
+			strbuf_swap(&buf, &unquoted);
+		}
+		hash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags,
+			    literally);
+	}
+	strbuf_release(&buf);
+	strbuf_release(&unquoted);
+}
+
+int cmd_hash_object(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
+{
+	static const char * const hash_object_usage[] = {
+		N_("git hash-object [-t <type>] [-w] [--path=<file> | --no-filters]\n"
+		   "                [--stdin [--literally]] [--] <file>..."),
+		N_("git hash-object [-t <type>] [-w] --stdin-paths [--no-filters]"),
+		NULL
+	};
+	const char *type = blob_type;
+	int hashstdin = 0;
+	int stdin_paths = 0;
+	int no_filters = 0;
+	int literally = 0;
+	int nongit = 0;
+	unsigned flags = HASH_FORMAT_CHECK;
+	const char *vpath = NULL;
+	char *vpath_free = NULL;
+	const struct option hash_object_options[] = {
+		OPT_STRING('t', NULL, &type, N_("type"), N_("object type")),
+		OPT_BIT('w', NULL, &flags, N_("write the object into the object database"),
+			HASH_WRITE_OBJECT),
+		OPT_COUNTUP( 0 , "stdin", &hashstdin, N_("read the object from stdin")),
+		OPT_BOOL( 0 , "stdin-paths", &stdin_paths, N_("read file names from stdin")),
+		OPT_BOOL( 0 , "no-filters", &no_filters, N_("store file as is without filters")),
+		OPT_BOOL( 0, "literally", &literally, N_("just hash any random garbage to create corrupt objects for debugging Git")),
+		OPT_STRING( 0 , "path", &vpath, N_("file"), N_("process file as it were from this path")),
+		OPT_END()
+	};
+	int i;
+	const char *errstr = NULL;
+
+	argc = parse_options(argc, argv, prefix, hash_object_options,
+			     hash_object_usage, 0);
+
+	if (flags & HASH_WRITE_OBJECT)
+		prefix = setup_git_directory();
+	else
+		prefix = setup_git_directory_gently(&nongit);
+
+	if (nongit && !the_hash_algo)
+		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
+	if (vpath && prefix) {
+		vpath_free = prefix_filename(prefix, vpath);
+		vpath = vpath_free;
+	}
+
+	git_config(git_default_config, NULL);
+
+	if (stdin_paths) {
+		if (hashstdin)
+			errstr = "Can't use --stdin-paths with --stdin";
+		else if (argc)
+			errstr = "Can't specify files with --stdin-paths";
+		else if (vpath)
+			errstr = "Can't use --stdin-paths with --path";
+	}
+	else {
+		if (hashstdin > 1)
+			errstr = "Multiple --stdin arguments are not supported";
+		if (vpath && no_filters)
+			errstr = "Can't use --path with --no-filters";
+	}
+
+	if (errstr) {
+		error("%s", errstr);
+		usage_with_options(hash_object_usage, hash_object_options);
+	}
+
+	if (hashstdin)
+		hash_fd(0, type, vpath, flags, literally);
+
+	for (i = 0 ; i < argc; i++) {
+		const char *arg = argv[i];
+		char *to_free = NULL;
+
+		if (prefix)
+			arg = to_free = prefix_filename(prefix, arg);
+		hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
+			    flags, literally);
+		free(to_free);
+	}
+
+	if (stdin_paths)
+		hash_stdin_paths(type, no_filters, flags, literally);
+
+	free(vpath_free);
+
+	return 0;
+}
diff --git a/builtin/help.c b/builtin/help.c
new file mode 100644
index 0000000000..c257079ceb
--- /dev/null
+++ b/builtin/help.c
@@ -0,0 +1,734 @@
+/*
+ * Builtin help command
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "exec-cmd.h"
+#include "gettext.h"
+#include "pager.h"
+#include "parse-options.h"
+#include "path.h"
+#include "run-command.h"
+#include "config-list.h"
+#include "help.h"
+#include "alias.h"
+#include "setup.h"
+
+#ifndef DEFAULT_HELP_FORMAT
+#define DEFAULT_HELP_FORMAT "man"
+#endif
+
+static struct man_viewer_list {
+	struct man_viewer_list *next;
+	char name[FLEX_ARRAY];
+} *man_viewer_list;
+
+static struct man_viewer_info_list {
+	struct man_viewer_info_list *next;
+	const char *info;
+	char name[FLEX_ARRAY];
+} *man_viewer_info_list;
+
+enum help_format {
+	HELP_FORMAT_NONE,
+	HELP_FORMAT_MAN,
+	HELP_FORMAT_INFO,
+	HELP_FORMAT_WEB
+};
+
+enum show_config_type {
+	SHOW_CONFIG_HUMAN,
+	SHOW_CONFIG_VARS,
+	SHOW_CONFIG_SECTIONS,
+};
+
+static enum help_action {
+	HELP_ACTION_ALL = 1,
+	HELP_ACTION_GUIDES,
+	HELP_ACTION_CONFIG,
+	HELP_ACTION_USER_INTERFACES,
+	HELP_ACTION_DEVELOPER_INTERFACES,
+	HELP_ACTION_CONFIG_FOR_COMPLETION,
+	HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION,
+} cmd_mode;
+
+static char *html_path;
+static int verbose = 1;
+static enum help_format help_format = HELP_FORMAT_NONE;
+static int exclude_guides;
+static int show_external_commands = -1;
+static int show_aliases = -1;
+static struct option builtin_help_options[] = {
+	OPT_CMDMODE('a', "all", &cmd_mode, N_("print all available commands"),
+		    HELP_ACTION_ALL),
+	OPT_BOOL(0, "external-commands", &show_external_commands,
+		 N_("show external commands in --all")),
+	OPT_BOOL(0, "aliases", &show_aliases, N_("show aliases in --all")),
+	OPT_HIDDEN_BOOL(0, "exclude-guides", &exclude_guides, N_("exclude guides")),
+	OPT_SET_INT('m', "man", &help_format, N_("show man page"), HELP_FORMAT_MAN),
+	OPT_SET_INT('w', "web", &help_format, N_("show manual in web browser"),
+			HELP_FORMAT_WEB),
+	OPT_SET_INT('i', "info", &help_format, N_("show info page"),
+			HELP_FORMAT_INFO),
+	OPT__VERBOSE(&verbose, N_("print command description")),
+
+	OPT_CMDMODE('g', "guides", &cmd_mode, N_("print list of useful guides"),
+		    HELP_ACTION_GUIDES),
+	OPT_CMDMODE(0, "user-interfaces", &cmd_mode,
+		    N_("print list of user-facing repository, command and file interfaces"),
+		    HELP_ACTION_USER_INTERFACES),
+	OPT_CMDMODE(0, "developer-interfaces", &cmd_mode,
+		    N_("print list of file formats, protocols and other developer interfaces"),
+		    HELP_ACTION_DEVELOPER_INTERFACES),
+	OPT_CMDMODE('c', "config", &cmd_mode, N_("print all configuration variable names"),
+		    HELP_ACTION_CONFIG),
+	OPT_CMDMODE_F(0, "config-for-completion", &cmd_mode, "",
+		    HELP_ACTION_CONFIG_FOR_COMPLETION, PARSE_OPT_HIDDEN),
+	OPT_CMDMODE_F(0, "config-sections-for-completion", &cmd_mode, "",
+		    HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION, PARSE_OPT_HIDDEN),
+
+	OPT_END(),
+};
+
+static const char * const builtin_help_usage[] = {
+	"git help [-a|--all] [--[no-]verbose] [--[no-]external-commands] [--[no-]aliases]",
+	N_("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]",
+	NULL
+};
+
+struct slot_expansion {
+	const char *prefix;
+	const char *placeholder;
+	void (*fn)(struct string_list *list, const char *prefix);
+	int found;
+};
+
+static void list_config_help(enum show_config_type type)
+{
+	struct slot_expansion slot_expansions[] = {
+		{ "advice", "*", list_config_advices },
+		{ "color.branch", "<slot>", list_config_color_branch_slots },
+		{ "color.decorate", "<slot>", list_config_color_decorate_slots },
+		{ "color.diff", "<slot>", list_config_color_diff_slots },
+		{ "color.grep", "<slot>", list_config_color_grep_slots },
+		{ "color.interactive", "<slot>", list_config_color_interactive_slots },
+		{ "color.remote", "<slot>", list_config_color_sideband_slots },
+		{ "color.status", "<slot>", list_config_color_status_slots },
+		{ "fsck", "<msg-id>", list_config_fsck_msg_ids },
+		{ "receive.fsck", "<msg-id>", list_config_fsck_msg_ids },
+		{ NULL, NULL, NULL }
+	};
+	const char **p;
+	struct slot_expansion *e;
+	struct string_list keys = STRING_LIST_INIT_DUP;
+	struct string_list keys_uniq = STRING_LIST_INIT_DUP;
+	struct string_list_item *item;
+
+	for (p = config_name_list; *p; p++) {
+		const char *var = *p;
+		struct strbuf sb = STRBUF_INIT;
+
+		for (e = slot_expansions; e->prefix; e++) {
+
+			strbuf_reset(&sb);
+			strbuf_addf(&sb, "%s.%s", e->prefix, e->placeholder);
+			if (!strcasecmp(var, sb.buf)) {
+				e->fn(&keys, e->prefix);
+				e->found++;
+				break;
+			}
+		}
+		strbuf_release(&sb);
+		if (!e->prefix)
+			string_list_append(&keys, var);
+	}
+
+	for (e = slot_expansions; e->prefix; e++)
+		if (!e->found)
+			BUG("slot_expansion %s.%s is not used",
+			    e->prefix, e->placeholder);
+
+	string_list_sort(&keys);
+	for (size_t i = 0; i < keys.nr; i++) {
+		const char *var = keys.items[i].string;
+		const char *wildcard, *tag, *cut;
+		const char *dot = NULL;
+		struct strbuf sb = STRBUF_INIT;
+
+		switch (type) {
+		case SHOW_CONFIG_HUMAN:
+			puts(var);
+			continue;
+		case SHOW_CONFIG_SECTIONS:
+			dot = strchr(var, '.');
+			break;
+		case SHOW_CONFIG_VARS:
+			break;
+		}
+		wildcard = strchr(var, '*');
+		tag = strchr(var, '<');
+
+		if (!dot && !wildcard && !tag) {
+			string_list_append(&keys_uniq, var);
+			continue;
+		}
+
+		if (dot)
+			cut = dot;
+		else if (wildcard && !tag)
+			cut = wildcard;
+		else if (!wildcard && tag)
+			cut = tag;
+		else
+			cut = wildcard < tag ? wildcard : tag;
+
+		strbuf_add(&sb, var, cut - var);
+		string_list_append(&keys_uniq, sb.buf);
+		strbuf_release(&sb);
+
+	}
+	string_list_clear(&keys, 0);
+	string_list_remove_duplicates(&keys_uniq, 0);
+	for_each_string_list_item(item, &keys_uniq)
+		puts(item->string);
+	string_list_clear(&keys_uniq, 0);
+}
+
+static enum help_format parse_help_format(const char *format)
+{
+	if (!strcmp(format, "man"))
+		return HELP_FORMAT_MAN;
+	if (!strcmp(format, "info"))
+		return HELP_FORMAT_INFO;
+	if (!strcmp(format, "web") || !strcmp(format, "html"))
+		return HELP_FORMAT_WEB;
+	/*
+	 * Please update _git_config() in git-completion.bash when you
+	 * add new help formats.
+	 */
+	die(_("unrecognized help format '%s'"), format);
+}
+
+static const char *get_man_viewer_info(const char *name)
+{
+	struct man_viewer_info_list *viewer;
+
+	for (viewer = man_viewer_info_list; viewer; viewer = viewer->next)
+	{
+		if (!strcasecmp(name, viewer->name))
+			return viewer->info;
+	}
+	return NULL;
+}
+
+static int check_emacsclient_version(void)
+{
+	struct strbuf buffer = STRBUF_INIT;
+	struct child_process ec_process = CHILD_PROCESS_INIT;
+	int version;
+
+	/* emacsclient prints its version number on stderr */
+	strvec_pushl(&ec_process.args, "emacsclient", "--version", NULL);
+	ec_process.err = -1;
+	ec_process.stdout_to_stderr = 1;
+	if (start_command(&ec_process))
+		return error(_("Failed to start emacsclient."));
+
+	strbuf_read(&buffer, ec_process.err, 20);
+	close(ec_process.err);
+
+	/*
+	 * Don't bother checking return value, because "emacsclient --version"
+	 * seems to always exits with code 1.
+	 */
+	finish_command(&ec_process);
+
+	if (!starts_with(buffer.buf, "emacsclient")) {
+		strbuf_release(&buffer);
+		return error(_("Failed to parse emacsclient version."));
+	}
+
+	strbuf_remove(&buffer, 0, strlen("emacsclient"));
+	version = atoi(buffer.buf);
+
+	if (version < 22) {
+		strbuf_release(&buffer);
+		return error(_("emacsclient version '%d' too old (< 22)."),
+			version);
+	}
+
+	strbuf_release(&buffer);
+	return 0;
+}
+
+static void exec_woman_emacs(const char *path, const char *page)
+{
+	if (!check_emacsclient_version()) {
+		/* This works only with emacsclient version >= 22. */
+		struct strbuf man_page = STRBUF_INIT;
+
+		if (!path)
+			path = "emacsclient";
+		strbuf_addf(&man_page, "(woman \"%s\")", page);
+		execlp(path, "emacsclient", "-e", man_page.buf, (char *)NULL);
+		warning_errno(_("failed to exec '%s'"), path);
+		strbuf_release(&man_page);
+	}
+}
+
+static void exec_man_konqueror(const char *path, const char *page)
+{
+	const char *display = getenv("DISPLAY");
+	if (display && *display) {
+		struct strbuf man_page = STRBUF_INIT;
+		const char *filename = "kfmclient";
+
+		/* It's simpler to launch konqueror using kfmclient. */
+		if (path) {
+			size_t len;
+			if (strip_suffix(path, "/konqueror", &len))
+				path = xstrfmt("%.*s/kfmclient", (int)len, path);
+			filename = basename((char *)path);
+		} else
+			path = "kfmclient";
+		strbuf_addf(&man_page, "man:%s(1)", page);
+		execlp(path, filename, "newTab", man_page.buf, (char *)NULL);
+		warning_errno(_("failed to exec '%s'"), path);
+		strbuf_release(&man_page);
+	}
+}
+
+static void exec_man_man(const char *path, const char *page)
+{
+	if (!path)
+		path = "man";
+	execlp(path, "man", page, (char *)NULL);
+	warning_errno(_("failed to exec '%s'"), path);
+}
+
+static void exec_man_cmd(const char *cmd, const char *page)
+{
+	struct strbuf shell_cmd = STRBUF_INIT;
+	strbuf_addf(&shell_cmd, "%s %s", cmd, page);
+	execl(SHELL_PATH, SHELL_PATH, "-c", shell_cmd.buf, (char *)NULL);
+	warning(_("failed to exec '%s'"), cmd);
+	strbuf_release(&shell_cmd);
+}
+
+static void add_man_viewer(const char *name)
+{
+	struct man_viewer_list **p = &man_viewer_list;
+
+	while (*p)
+		p = &((*p)->next);
+	FLEX_ALLOC_STR(*p, name, name);
+}
+
+static int supported_man_viewer(const char *name, size_t len)
+{
+	return (!strncasecmp("man", name, len) ||
+		!strncasecmp("woman", name, len) ||
+		!strncasecmp("konqueror", name, len));
+}
+
+static void do_add_man_viewer_info(const char *name,
+				   size_t len,
+				   const char *value)
+{
+	struct man_viewer_info_list *new_man_viewer;
+	FLEX_ALLOC_MEM(new_man_viewer, name, name, len);
+	new_man_viewer->info = xstrdup(value);
+	new_man_viewer->next = man_viewer_info_list;
+	man_viewer_info_list = new_man_viewer;
+}
+
+static int add_man_viewer_path(const char *name,
+			       size_t len,
+			       const char *value)
+{
+	if (supported_man_viewer(name, len))
+		do_add_man_viewer_info(name, len, value);
+	else
+		warning(_("'%s': path for unsupported man viewer.\n"
+			  "Please consider using 'man.<tool>.cmd' instead."),
+			name);
+
+	return 0;
+}
+
+static int add_man_viewer_cmd(const char *name,
+			      size_t len,
+			      const char *value)
+{
+	if (supported_man_viewer(name, len))
+		warning(_("'%s': cmd for supported man viewer.\n"
+			  "Please consider using 'man.<tool>.path' instead."),
+			name);
+	else
+		do_add_man_viewer_info(name, len, value);
+
+	return 0;
+}
+
+static int add_man_viewer_info(const char *var, const char *value)
+{
+	const char *name, *subkey;
+	size_t namelen;
+
+	if (parse_config_key(var, "man", &name, &namelen, &subkey) < 0 || !name)
+		return 0;
+
+	if (!strcmp(subkey, "path")) {
+		if (!value)
+			return config_error_nonbool(var);
+		return add_man_viewer_path(name, namelen, value);
+	}
+	if (!strcmp(subkey, "cmd")) {
+		if (!value)
+			return config_error_nonbool(var);
+		return add_man_viewer_cmd(name, namelen, value);
+	}
+
+	return 0;
+}
+
+static int git_help_config(const char *var, const char *value,
+			   const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "help.format")) {
+		if (!value)
+			return config_error_nonbool(var);
+		help_format = parse_help_format(value);
+		return 0;
+	}
+	if (!strcmp(var, "help.htmlpath")) {
+		if (!value)
+			return config_error_nonbool(var);
+		free(html_path);
+		html_path = xstrdup(value);
+		return 0;
+	}
+	if (!strcmp(var, "man.viewer")) {
+		if (!value)
+			return config_error_nonbool(var);
+		add_man_viewer(value);
+		return 0;
+	}
+	if (starts_with(var, "man."))
+		return add_man_viewer_info(var, value);
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static struct cmdnames main_cmds, other_cmds;
+
+static int is_git_command(const char *s)
+{
+	if (is_builtin(s))
+		return 1;
+
+	load_command_list("git-", &main_cmds, &other_cmds);
+	return is_in_cmdlist(&main_cmds, s) ||
+		is_in_cmdlist(&other_cmds, s);
+}
+
+static const char *cmd_to_page(const char *git_cmd)
+{
+	if (!git_cmd)
+		return "git";
+	else if (starts_with(git_cmd, "git"))
+		return git_cmd;
+	else if (is_git_command(git_cmd))
+		return xstrfmt("git-%s", git_cmd);
+	else if (!strcmp("scalar", git_cmd))
+		return xstrdup(git_cmd);
+	else
+		return xstrfmt("git%s", git_cmd);
+}
+
+static void setup_man_path(void)
+{
+	struct strbuf new_path = STRBUF_INIT;
+	const char *old_path = getenv("MANPATH");
+	char *git_man_path = system_path(GIT_MAN_PATH);
+
+	/* We should always put ':' after our path. If there is no
+	 * old_path, the ':' at the end will let 'man' to try
+	 * system-wide paths after ours to find the manual page. If
+	 * there is old_path, we need ':' as delimiter. */
+	strbuf_addstr(&new_path, git_man_path);
+	strbuf_addch(&new_path, ':');
+	if (old_path)
+		strbuf_addstr(&new_path, old_path);
+
+	free(git_man_path);
+	setenv("MANPATH", new_path.buf, 1);
+
+	strbuf_release(&new_path);
+}
+
+static void exec_viewer(const char *name, const char *page)
+{
+	const char *info = get_man_viewer_info(name);
+
+	if (!strcasecmp(name, "man"))
+		exec_man_man(info, page);
+	else if (!strcasecmp(name, "woman"))
+		exec_woman_emacs(info, page);
+	else if (!strcasecmp(name, "konqueror"))
+		exec_man_konqueror(info, page);
+	else if (info)
+		exec_man_cmd(info, page);
+	else
+		warning(_("'%s': unknown man viewer."), name);
+}
+
+static void show_man_page(const char *page)
+{
+	struct man_viewer_list *viewer;
+	const char *fallback = getenv("GIT_MAN_VIEWER");
+
+	setup_man_path();
+	for (viewer = man_viewer_list; viewer; viewer = viewer->next)
+	{
+		exec_viewer(viewer->name, page); /* will return when unable */
+	}
+	if (fallback)
+		exec_viewer(fallback, page);
+	exec_viewer("man", page);
+	die(_("no man viewer handled the request"));
+}
+
+static void show_info_page(const char *page)
+{
+	setenv("INFOPATH", system_path(GIT_INFO_PATH), 1);
+	execlp("info", "info", "gitman", page, (char *)NULL);
+	die(_("no info viewer handled the request"));
+}
+
+static void get_html_page_path(struct strbuf *page_path, const char *page)
+{
+	struct stat st;
+	const char *path = html_path;
+	char *to_free = NULL;
+
+	if (!path)
+		path = to_free = system_path(GIT_HTML_PATH);
+
+	/*
+	 * Check that the page we're looking for exists.
+	 */
+	if (!strstr(path, "://")) {
+		if (stat(mkpath("%s/%s.html", path, page), &st)
+		    || !S_ISREG(st.st_mode))
+			die("'%s/%s.html': documentation file not found.",
+				path, page);
+	}
+
+	strbuf_init(page_path, 0);
+	strbuf_addf(page_path, "%s/%s.html", path, page);
+	free(to_free);
+}
+
+static void open_html(const char *path)
+{
+	execl_git_cmd("web--browse", "-c", "help.browser", path, (char *)NULL);
+}
+
+static void show_html_page(const char *page)
+{
+	struct strbuf page_path; /* it leaks but we exec below */
+
+	get_html_page_path(&page_path, page);
+
+	open_html(page_path.buf);
+}
+
+static char *check_git_cmd(const char *cmd)
+{
+	char *alias;
+
+	if (is_git_command(cmd))
+		return xstrdup(cmd);
+
+	alias = alias_lookup(cmd);
+	if (alias) {
+		const char **argv;
+		int count;
+
+		/*
+		 * handle_builtin() in git.c rewrites "git cmd --help"
+		 * to "git help --exclude-guides cmd", so we can use
+		 * exclude_guides to distinguish "git cmd --help" from
+		 * "git help cmd". In the latter case, or if cmd is an
+		 * alias for a shell command, just print the alias
+		 * definition.
+		 */
+		if (!exclude_guides || alias[0] == '!') {
+			printf_ln(_("'%s' is aliased to '%s'"), cmd, alias);
+			free(alias);
+			exit(0);
+		}
+		/*
+		 * Otherwise, we pretend that the command was "git
+		 * word0 --help". We use split_cmdline() to get the
+		 * first word of the alias, to ensure that we use the
+		 * same rules as when the alias is actually
+		 * used. split_cmdline() modifies alias in-place.
+		 */
+		fprintf_ln(stderr, _("'%s' is aliased to '%s'"), cmd, alias);
+		count = split_cmdline(alias, &argv);
+		if (count < 0)
+			die(_("bad alias.%s string: %s"), cmd,
+			    split_cmdline_strerror(count));
+		free(argv);
+		return alias;
+	}
+
+	if (exclude_guides)
+		return help_unknown_cmd(cmd);
+
+	return xstrdup(cmd);
+}
+
+static void no_help_format(const char *opt_mode, enum help_format fmt)
+{
+	const char *opt_fmt;
+
+	switch (fmt) {
+	case HELP_FORMAT_NONE:
+		return;
+	case HELP_FORMAT_MAN:
+		opt_fmt = "--man";
+		break;
+	case HELP_FORMAT_INFO:
+		opt_fmt = "--info";
+		break;
+	case HELP_FORMAT_WEB:
+		opt_fmt = "--web";
+		break;
+	default:
+		BUG("unreachable");
+	}
+
+	usage_msg_optf(_("options '%s' and '%s' cannot be used together"),
+		       builtin_help_usage, builtin_help_options, opt_mode,
+		       opt_fmt);
+}
+
+static void opt_mode_usage(int argc, const char *opt_mode,
+			   enum help_format fmt)
+{
+	if (argc)
+		usage_msg_optf(_("the '%s' option doesn't take any non-option arguments"),
+			       builtin_help_usage, builtin_help_options,
+			       opt_mode);
+
+	no_help_format(opt_mode, fmt);
+}
+
+int cmd_help(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
+{
+	int nongit;
+	enum help_format parsed_help_format;
+	char *command = NULL;
+	const char *page;
+
+	argc = parse_options(argc, argv, prefix, builtin_help_options,
+			builtin_help_usage, 0);
+	parsed_help_format = help_format;
+
+	if (cmd_mode != HELP_ACTION_ALL &&
+	    (show_external_commands >= 0 ||
+	     show_aliases >= 0))
+		usage_msg_opt(_("the '--no-[external-commands|aliases]' options can only be used with '--all'"),
+			      builtin_help_usage, builtin_help_options);
+
+	switch (cmd_mode) {
+	case HELP_ACTION_ALL:
+		opt_mode_usage(argc, "--all", help_format);
+		if (verbose) {
+			setup_pager(the_repository);
+			list_all_cmds_help(show_external_commands,
+					   show_aliases);
+			return 0;
+		}
+		printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
+		load_command_list("git-", &main_cmds, &other_cmds);
+		list_commands(&main_cmds, &other_cmds);
+		printf("%s\n", _(git_more_info_string));
+		break;
+	case HELP_ACTION_GUIDES:
+		opt_mode_usage(argc, "--guides", help_format);
+		list_guides_help();
+		printf("%s\n", _(git_more_info_string));
+		return 0;
+	case HELP_ACTION_CONFIG_FOR_COMPLETION:
+		opt_mode_usage(argc, "--config-for-completion", help_format);
+		list_config_help(SHOW_CONFIG_VARS);
+		return 0;
+	case HELP_ACTION_USER_INTERFACES:
+		opt_mode_usage(argc, "--user-interfaces", help_format);
+		list_user_interfaces_help();
+		return 0;
+	case HELP_ACTION_DEVELOPER_INTERFACES:
+		opt_mode_usage(argc, "--developer-interfaces", help_format);
+		list_developer_interfaces_help();
+		return 0;
+	case HELP_ACTION_CONFIG_SECTIONS_FOR_COMPLETION:
+		opt_mode_usage(argc, "--config-sections-for-completion",
+			       help_format);
+		list_config_help(SHOW_CONFIG_SECTIONS);
+		return 0;
+	case HELP_ACTION_CONFIG:
+		opt_mode_usage(argc, "--config", help_format);
+		setup_pager(the_repository);
+		list_config_help(SHOW_CONFIG_HUMAN);
+		printf("\n%s\n", _("'git help config' for more information"));
+		return 0;
+	}
+
+	if (!argv[0]) {
+		printf(_("usage: %s%s"), _(git_usage_string), "\n\n");
+		list_common_cmds_help();
+		printf("\n%s\n", _(git_more_info_string));
+		return 0;
+	}
+
+	setup_git_directory_gently(&nongit);
+	git_config(git_help_config, NULL);
+
+	if (parsed_help_format != HELP_FORMAT_NONE)
+		help_format = parsed_help_format;
+	if (help_format == HELP_FORMAT_NONE)
+		help_format = parse_help_format(DEFAULT_HELP_FORMAT);
+
+	command = check_git_cmd(argv[0]);
+
+	page = cmd_to_page(command);
+	switch (help_format) {
+	case HELP_FORMAT_NONE:
+	case HELP_FORMAT_MAN:
+		show_man_page(page);
+		break;
+	case HELP_FORMAT_INFO:
+		show_info_page(page);
+		break;
+	case HELP_FORMAT_WEB:
+		show_html_page(page);
+		break;
+	}
+
+	free(command);
+	return 0;
+}
diff --git a/builtin/hook.c b/builtin/hook.c
new file mode 100644
index 0000000000..672d2e37e8
--- /dev/null
+++ b/builtin/hook.c
@@ -0,0 +1,86 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "hook.h"
+#include "parse-options.h"
+#include "strvec.h"
+
+#define BUILTIN_HOOK_RUN_USAGE \
+	N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
+
+static const char * const builtin_hook_usage[] = {
+	BUILTIN_HOOK_RUN_USAGE,
+	NULL
+};
+
+static const char * const builtin_hook_run_usage[] = {
+	BUILTIN_HOOK_RUN_USAGE,
+	NULL
+};
+
+static int run(int argc, const char **argv, const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	int i;
+	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+	int ignore_missing = 0;
+	const char *hook_name;
+	struct option run_options[] = {
+		OPT_BOOL(0, "ignore-missing", &ignore_missing,
+			 N_("silently ignore missing requested <hook-name>")),
+		OPT_STRING(0, "to-stdin", &opt.path_to_stdin, N_("path"),
+			   N_("file to read into hooks' stdin")),
+		OPT_END(),
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, run_options,
+			     builtin_hook_run_usage,
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	if (!argc)
+		goto usage;
+
+	/*
+	 * Having a -- for "run" when providing <hook-args> is
+	 * mandatory.
+	 */
+	if (argc > 1 && strcmp(argv[1], "--") &&
+	    strcmp(argv[1], "--end-of-options"))
+		goto usage;
+
+	/* Add our arguments, start after -- */
+	for (i = 2 ; i < argc; i++)
+		strvec_push(&opt.args, argv[i]);
+
+	/* Need to take into account core.hooksPath */
+	git_config(git_default_config, NULL);
+
+	hook_name = argv[0];
+	if (!ignore_missing)
+		opt.error_if_missing = 1;
+	ret = run_hooks_opt(the_repository, hook_name, &opt);
+	if (ret < 0) /* error() return */
+		ret = 1;
+	return ret;
+usage:
+	usage_with_options(builtin_hook_run_usage, run_options);
+}
+
+int cmd_hook(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option builtin_hook_options[] = {
+		OPT_SUBCOMMAND("run", &fn, run),
+		OPT_END(),
+	};
+
+	argc = parse_options(argc, argv, NULL, builtin_hook_options,
+			     builtin_hook_usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
new file mode 100644
index 0000000000..6ffbb7ce35
--- /dev/null
+++ b/builtin/index-pack.c
@@ -0,0 +1,2130 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "delta.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "pack.h"
+#include "csum-file.h"
+#include "blob.h"
+#include "commit.h"
+#include "tag.h"
+#include "tree.h"
+#include "progress.h"
+#include "fsck.h"
+#include "strbuf.h"
+#include "streaming.h"
+#include "thread-utils.h"
+#include "packfile.h"
+#include "pack-revindex.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "oidset.h"
+#include "path.h"
+#include "replace-object.h"
+#include "tree-walk.h"
+#include "promisor-remote.h"
+#include "run-command.h"
+#include "setup.h"
+#include "strvec.h"
+
+static const char index_pack_usage[] =
+"git index-pack [-v] [-o <index-file>] [--keep | --keep=<msg>] [--[no-]rev-index] [--verify] [--strict[=<msg-id>=<severity>...]] [--fsck-objects[=<msg-id>=<severity>...]] (<pack-file> | --stdin [--fix-thin] [<pack-file>])";
+
+struct object_entry {
+	struct pack_idx_entry idx;
+	unsigned long size;
+	unsigned char hdr_size;
+	signed char type;
+	signed char real_type;
+};
+
+struct object_stat {
+	unsigned delta_depth;
+	int base_object_no;
+};
+
+struct base_data {
+	/* Initialized by make_base(). */
+	struct base_data *base;
+	struct object_entry *obj;
+	int ref_first, ref_last;
+	int ofs_first, ofs_last;
+	/*
+	 * Threads should increment retain_data if they are about to call
+	 * patch_delta() using this struct's data as a base, and decrement this
+	 * when they are done. While retain_data is nonzero, this struct's data
+	 * will not be freed even if the delta base cache limit is exceeded.
+	 */
+	int retain_data;
+	/*
+	 * The number of direct children that have not been fully processed
+	 * (entered work_head, entered done_head, left done_head). When this
+	 * number reaches zero, this struct base_data can be freed.
+	 */
+	int children_remaining;
+
+	/* Not initialized by make_base(). */
+	struct list_head list;
+	void *data;
+	unsigned long size;
+};
+
+/*
+ * Stack of struct base_data that have unprocessed children.
+ * threaded_second_pass() uses this as a source of work (the other being the
+ * objects array).
+ *
+ * Guarded by work_mutex.
+ */
+static LIST_HEAD(work_head);
+
+/*
+ * Stack of struct base_data that have children, all of whom have been
+ * processed or are being processed, and at least one child is being processed.
+ * These struct base_data must be kept around until the last child is
+ * processed.
+ *
+ * Guarded by work_mutex.
+ */
+static LIST_HEAD(done_head);
+
+/*
+ * All threads share one delta base cache.
+ *
+ * base_cache_used is guarded by work_mutex, and base_cache_limit is read-only
+ * in a thread.
+ */
+static size_t base_cache_used;
+static size_t base_cache_limit;
+
+struct thread_local_data {
+	pthread_t thread;
+	int pack_fd;
+};
+
+/* Remember to update object flag allocation in object.h */
+#define FLAG_LINK (1u<<20)
+#define FLAG_CHECKED (1u<<21)
+
+struct ofs_delta_entry {
+	off_t offset;
+	int obj_no;
+};
+
+struct ref_delta_entry {
+	struct object_id oid;
+	int obj_no;
+};
+
+static struct object_entry *objects;
+static struct object_stat *obj_stat;
+static struct ofs_delta_entry *ofs_deltas;
+static struct ref_delta_entry *ref_deltas;
+static struct thread_local_data nothread_data;
+static int nr_objects;
+static int nr_ofs_deltas;
+static int nr_ref_deltas;
+static int ref_deltas_alloc;
+static int nr_resolved_deltas;
+static int nr_threads;
+
+static int from_stdin;
+static int strict;
+static int do_fsck_object;
+static struct fsck_options fsck_options = FSCK_OPTIONS_MISSING_GITMODULES;
+static int verbose;
+static const char *progress_title;
+static int show_resolving_progress;
+static int show_stat;
+static int check_self_contained_and_connected;
+
+static struct progress *progress;
+
+/* We always read in 4kB chunks. */
+static unsigned char input_buffer[4096];
+static unsigned int input_offset, input_len;
+static off_t consumed_bytes;
+static off_t max_input_size;
+static unsigned deepest_delta;
+static git_hash_ctx input_ctx;
+static uint32_t input_crc32;
+static int input_fd, output_fd;
+static const char *curr_pack;
+
+/*
+ * outgoing_links is guarded by read_mutex, and record_outgoing_links is
+ * read-only in a thread.
+ */
+static struct oidset outgoing_links = OIDSET_INIT;
+static int record_outgoing_links;
+
+static struct thread_local_data *thread_data;
+static int nr_dispatched;
+static int threads_active;
+
+static pthread_mutex_t read_mutex;
+#define read_lock()		lock_mutex(&read_mutex)
+#define read_unlock()		unlock_mutex(&read_mutex)
+
+static pthread_mutex_t counter_mutex;
+#define counter_lock()		lock_mutex(&counter_mutex)
+#define counter_unlock()	unlock_mutex(&counter_mutex)
+
+static pthread_mutex_t work_mutex;
+#define work_lock()		lock_mutex(&work_mutex)
+#define work_unlock()		unlock_mutex(&work_mutex)
+
+static pthread_mutex_t deepest_delta_mutex;
+#define deepest_delta_lock()	lock_mutex(&deepest_delta_mutex)
+#define deepest_delta_unlock()	unlock_mutex(&deepest_delta_mutex)
+
+static pthread_key_t key;
+
+static inline void lock_mutex(pthread_mutex_t *mutex)
+{
+	if (threads_active)
+		pthread_mutex_lock(mutex);
+}
+
+static inline void unlock_mutex(pthread_mutex_t *mutex)
+{
+	if (threads_active)
+		pthread_mutex_unlock(mutex);
+}
+
+/*
+ * Mutex and conditional variable can't be statically-initialized on Windows.
+ */
+static void init_thread(void)
+{
+	int i;
+	init_recursive_mutex(&read_mutex);
+	pthread_mutex_init(&counter_mutex, NULL);
+	pthread_mutex_init(&work_mutex, NULL);
+	if (show_stat)
+		pthread_mutex_init(&deepest_delta_mutex, NULL);
+	pthread_key_create(&key, NULL);
+	CALLOC_ARRAY(thread_data, nr_threads);
+	for (i = 0; i < nr_threads; i++) {
+		thread_data[i].pack_fd = xopen(curr_pack, O_RDONLY);
+	}
+
+	threads_active = 1;
+}
+
+static void cleanup_thread(void)
+{
+	int i;
+	if (!threads_active)
+		return;
+	threads_active = 0;
+	pthread_mutex_destroy(&read_mutex);
+	pthread_mutex_destroy(&counter_mutex);
+	pthread_mutex_destroy(&work_mutex);
+	if (show_stat)
+		pthread_mutex_destroy(&deepest_delta_mutex);
+	for (i = 0; i < nr_threads; i++)
+		close(thread_data[i].pack_fd);
+	pthread_key_delete(key);
+	free(thread_data);
+}
+
+static int mark_link(struct object *obj, enum object_type type,
+		     void *data UNUSED,
+		     struct fsck_options *options UNUSED)
+{
+	if (!obj)
+		return -1;
+
+	if (type != OBJ_ANY && obj->type != type)
+		die(_("object type mismatch at %s"), oid_to_hex(&obj->oid));
+
+	obj->flags |= FLAG_LINK;
+	return 0;
+}
+
+/* The content of each linked object must have been checked
+   or it must be already present in the object database */
+static unsigned check_object(struct object *obj)
+{
+	if (!obj)
+		return 0;
+
+	if (!(obj->flags & FLAG_LINK))
+		return 0;
+
+	if (!(obj->flags & FLAG_CHECKED)) {
+		unsigned long size;
+		int type = oid_object_info(the_repository, &obj->oid, &size);
+		if (type <= 0)
+			die(_("did not receive expected object %s"),
+			      oid_to_hex(&obj->oid));
+		if (type != obj->type)
+			die(_("object %s: expected type %s, found %s"),
+			    oid_to_hex(&obj->oid),
+			    type_name(obj->type), type_name(type));
+		obj->flags |= FLAG_CHECKED;
+		return 1;
+	}
+
+	return 0;
+}
+
+static unsigned check_objects(void)
+{
+	unsigned i, max, foreign_nr = 0;
+
+	max = get_max_object_index();
+
+	if (verbose)
+		progress = start_delayed_progress(the_repository,
+						  _("Checking objects"), max);
+
+	for (i = 0; i < max; i++) {
+		foreign_nr += check_object(get_indexed_object(i));
+		display_progress(progress, i + 1);
+	}
+
+	stop_progress(&progress);
+	return foreign_nr;
+}
+
+
+/* Discard current buffer used content. */
+static void flush(void)
+{
+	if (input_offset) {
+		if (output_fd >= 0)
+			write_or_die(output_fd, input_buffer, input_offset);
+		the_hash_algo->update_fn(&input_ctx, input_buffer, input_offset);
+		memmove(input_buffer, input_buffer + input_offset, input_len);
+		input_offset = 0;
+	}
+}
+
+/*
+ * Make sure at least "min" bytes are available in the buffer, and
+ * return the pointer to the buffer.
+ */
+static void *fill(int min)
+{
+	if (min <= input_len)
+		return input_buffer + input_offset;
+	if (min > sizeof(input_buffer))
+		die(Q_("cannot fill %d byte",
+		       "cannot fill %d bytes",
+		       min),
+		    min);
+	flush();
+	do {
+		ssize_t ret = xread(input_fd, input_buffer + input_len,
+				sizeof(input_buffer) - input_len);
+		if (ret <= 0) {
+			if (!ret)
+				die(_("early EOF"));
+			die_errno(_("read error on input"));
+		}
+		input_len += ret;
+		if (from_stdin)
+			display_throughput(progress, consumed_bytes + input_len);
+	} while (input_len < min);
+	return input_buffer;
+}
+
+static void use(int bytes)
+{
+	if (bytes > input_len)
+		die(_("used more bytes than were available"));
+	input_crc32 = crc32(input_crc32, input_buffer + input_offset, bytes);
+	input_len -= bytes;
+	input_offset += bytes;
+
+	/* make sure off_t is sufficiently large not to wrap */
+	if (signed_add_overflows(consumed_bytes, bytes))
+		die(_("pack too large for current definition of off_t"));
+	consumed_bytes += bytes;
+	if (max_input_size && consumed_bytes > max_input_size) {
+		struct strbuf size_limit = STRBUF_INIT;
+		strbuf_humanise_bytes(&size_limit, max_input_size);
+		die(_("pack exceeds maximum allowed size (%s)"),
+		    size_limit.buf);
+	}
+}
+
+static const char *open_pack_file(const char *pack_name)
+{
+	if (from_stdin) {
+		input_fd = 0;
+		if (!pack_name) {
+			struct strbuf tmp_file = STRBUF_INIT;
+			output_fd = odb_mkstemp(&tmp_file,
+						"pack/tmp_pack_XXXXXX");
+			pack_name = strbuf_detach(&tmp_file, NULL);
+		} else {
+			output_fd = xopen(pack_name, O_CREAT|O_EXCL|O_RDWR, 0600);
+		}
+		nothread_data.pack_fd = output_fd;
+	} else {
+		input_fd = xopen(pack_name, O_RDONLY);
+		output_fd = -1;
+		nothread_data.pack_fd = input_fd;
+	}
+	the_hash_algo->init_fn(&input_ctx);
+	return pack_name;
+}
+
+static void parse_pack_header(void)
+{
+	unsigned char *hdr = fill(sizeof(struct pack_header));
+
+	/* Header consistency check */
+	if (get_be32(hdr) != PACK_SIGNATURE)
+		die(_("pack signature mismatch"));
+	hdr += 4;
+	if (!pack_version_ok_native(get_be32(hdr)))
+		die(_("pack version %"PRIu32" unsupported"),
+		    get_be32(hdr));
+	hdr += 4;
+
+	nr_objects = get_be32(hdr);
+	use(sizeof(struct pack_header));
+}
+
+__attribute__((format (printf, 2, 3)))
+static NORETURN void bad_object(off_t offset, const char *format, ...)
+{
+	va_list params;
+	char buf[1024];
+
+	va_start(params, format);
+	vsnprintf(buf, sizeof(buf), format, params);
+	va_end(params);
+	die(_("pack has bad object at offset %"PRIuMAX": %s"),
+	    (uintmax_t)offset, buf);
+}
+
+static inline struct thread_local_data *get_thread_data(void)
+{
+	if (HAVE_THREADS) {
+		if (threads_active)
+			return pthread_getspecific(key);
+		assert(!threads_active &&
+		       "This should only be reached when all threads are gone");
+	}
+	return &nothread_data;
+}
+
+static void set_thread_data(struct thread_local_data *data)
+{
+	if (threads_active)
+		pthread_setspecific(key, data);
+}
+
+static void free_base_data(struct base_data *c)
+{
+	if (c->data) {
+		FREE_AND_NULL(c->data);
+		base_cache_used -= c->size;
+	}
+}
+
+static void prune_base_data(struct base_data *retain)
+{
+	struct list_head *pos;
+
+	if (base_cache_used <= base_cache_limit)
+		return;
+
+	list_for_each_prev(pos, &done_head) {
+		struct base_data *b = list_entry(pos, struct base_data, list);
+		if (b->retain_data || b == retain)
+			continue;
+		if (b->data) {
+			free_base_data(b);
+			if (base_cache_used <= base_cache_limit)
+				return;
+		}
+	}
+
+	list_for_each_prev(pos, &work_head) {
+		struct base_data *b = list_entry(pos, struct base_data, list);
+		if (b->retain_data || b == retain)
+			continue;
+		if (b->data) {
+			free_base_data(b);
+			if (base_cache_used <= base_cache_limit)
+				return;
+		}
+	}
+}
+
+static int is_delta_type(enum object_type type)
+{
+	return (type == OBJ_REF_DELTA || type == OBJ_OFS_DELTA);
+}
+
+static void *unpack_entry_data(off_t offset, unsigned long size,
+			       enum object_type type, struct object_id *oid)
+{
+	static char fixed_buf[8192];
+	int status;
+	git_zstream stream;
+	void *buf;
+	git_hash_ctx c;
+	char hdr[32];
+	int hdrlen;
+
+	if (!is_delta_type(type)) {
+		hdrlen = format_object_header(hdr, sizeof(hdr), type, size);
+		the_hash_algo->init_fn(&c);
+		the_hash_algo->update_fn(&c, hdr, hdrlen);
+	} else
+		oid = NULL;
+	if (type == OBJ_BLOB && size > big_file_threshold)
+		buf = fixed_buf;
+	else
+		buf = xmallocz(size);
+
+	memset(&stream, 0, sizeof(stream));
+	git_inflate_init(&stream);
+	stream.next_out = buf;
+	stream.avail_out = buf == fixed_buf ? sizeof(fixed_buf) : size;
+
+	do {
+		unsigned char *last_out = stream.next_out;
+		stream.next_in = fill(1);
+		stream.avail_in = input_len;
+		status = git_inflate(&stream, 0);
+		use(input_len - stream.avail_in);
+		if (oid)
+			the_hash_algo->update_fn(&c, last_out, stream.next_out - last_out);
+		if (buf == fixed_buf) {
+			stream.next_out = buf;
+			stream.avail_out = sizeof(fixed_buf);
+		}
+	} while (status == Z_OK);
+	if (stream.total_out != size || status != Z_STREAM_END)
+		bad_object(offset, _("inflate returned %d"), status);
+	git_inflate_end(&stream);
+	if (oid)
+		the_hash_algo->final_oid_fn(oid, &c);
+	return buf == fixed_buf ? NULL : buf;
+}
+
+static void *unpack_raw_entry(struct object_entry *obj,
+			      off_t *ofs_offset,
+			      struct object_id *ref_oid,
+			      struct object_id *oid)
+{
+	unsigned char *p;
+	unsigned long size, c;
+	off_t base_offset;
+	unsigned shift;
+	void *data;
+
+	obj->idx.offset = consumed_bytes;
+	input_crc32 = crc32(0, NULL, 0);
+
+	p = fill(1);
+	c = *p;
+	use(1);
+	obj->type = (c >> 4) & 7;
+	size = (c & 15);
+	shift = 4;
+	while (c & 0x80) {
+		p = fill(1);
+		c = *p;
+		use(1);
+		size += (c & 0x7f) << shift;
+		shift += 7;
+	}
+	obj->size = size;
+
+	switch (obj->type) {
+	case OBJ_REF_DELTA:
+		oidread(ref_oid, fill(the_hash_algo->rawsz),
+			the_repository->hash_algo);
+		use(the_hash_algo->rawsz);
+		break;
+	case OBJ_OFS_DELTA:
+		p = fill(1);
+		c = *p;
+		use(1);
+		base_offset = c & 127;
+		while (c & 128) {
+			base_offset += 1;
+			if (!base_offset || MSB(base_offset, 7))
+				bad_object(obj->idx.offset, _("offset value overflow for delta base object"));
+			p = fill(1);
+			c = *p;
+			use(1);
+			base_offset = (base_offset << 7) + (c & 127);
+		}
+		*ofs_offset = obj->idx.offset - base_offset;
+		if (*ofs_offset <= 0 || *ofs_offset >= obj->idx.offset)
+			bad_object(obj->idx.offset, _("delta base offset is out of bound"));
+		break;
+	case OBJ_COMMIT:
+	case OBJ_TREE:
+	case OBJ_BLOB:
+	case OBJ_TAG:
+		break;
+	default:
+		bad_object(obj->idx.offset, _("unknown object type %d"), obj->type);
+	}
+	obj->hdr_size = consumed_bytes - obj->idx.offset;
+
+	data = unpack_entry_data(obj->idx.offset, obj->size, obj->type, oid);
+	obj->idx.crc32 = input_crc32;
+	return data;
+}
+
+static void *unpack_data(struct object_entry *obj,
+			 int (*consume)(const unsigned char *, unsigned long, void *),
+			 void *cb_data)
+{
+	off_t from = obj[0].idx.offset + obj[0].hdr_size;
+	off_t len = obj[1].idx.offset - from;
+	unsigned char *data, *inbuf;
+	git_zstream stream;
+	int status;
+
+	data = xmallocz(consume ? 64*1024 : obj->size);
+	inbuf = xmalloc((len < 64*1024) ? (int)len : 64*1024);
+
+	memset(&stream, 0, sizeof(stream));
+	git_inflate_init(&stream);
+	stream.next_out = data;
+	stream.avail_out = consume ? 64*1024 : obj->size;
+
+	do {
+		ssize_t n = (len < 64*1024) ? (ssize_t)len : 64*1024;
+		n = xpread(get_thread_data()->pack_fd, inbuf, n, from);
+		if (n < 0)
+			die_errno(_("cannot pread pack file"));
+		if (!n)
+			die(Q_("premature end of pack file, %"PRIuMAX" byte missing",
+			       "premature end of pack file, %"PRIuMAX" bytes missing",
+			       len),
+			    (uintmax_t)len);
+		from += n;
+		len -= n;
+		stream.next_in = inbuf;
+		stream.avail_in = n;
+		if (!consume)
+			status = git_inflate(&stream, 0);
+		else {
+			do {
+				status = git_inflate(&stream, 0);
+				if (consume(data, stream.next_out - data, cb_data)) {
+					free(inbuf);
+					free(data);
+					return NULL;
+				}
+				stream.next_out = data;
+				stream.avail_out = 64*1024;
+			} while (status == Z_OK && stream.avail_in);
+		}
+	} while (len && status == Z_OK && !stream.avail_in);
+
+	/* This has been inflated OK when first encountered, so... */
+	if (status != Z_STREAM_END || stream.total_out != obj->size)
+		die(_("serious inflate inconsistency"));
+
+	git_inflate_end(&stream);
+	free(inbuf);
+	if (consume) {
+		FREE_AND_NULL(data);
+	}
+	return data;
+}
+
+static void *get_data_from_pack(struct object_entry *obj)
+{
+	return unpack_data(obj, NULL, NULL);
+}
+
+static int compare_ofs_delta_bases(off_t offset1, off_t offset2,
+				   enum object_type type1,
+				   enum object_type type2)
+{
+	int cmp = type1 - type2;
+	if (cmp)
+		return cmp;
+	return offset1 < offset2 ? -1 :
+	       offset1 > offset2 ?  1 :
+	       0;
+}
+
+static int find_ofs_delta(const off_t offset)
+{
+	int first = 0, last = nr_ofs_deltas;
+
+	while (first < last) {
+		int next = first + (last - first) / 2;
+		struct ofs_delta_entry *delta = &ofs_deltas[next];
+		int cmp;
+
+		cmp = compare_ofs_delta_bases(offset, delta->offset,
+					      OBJ_OFS_DELTA,
+					      objects[delta->obj_no].type);
+		if (!cmp)
+			return next;
+		if (cmp < 0) {
+			last = next;
+			continue;
+		}
+		first = next+1;
+	}
+	return -first-1;
+}
+
+static void find_ofs_delta_children(off_t offset,
+				    int *first_index, int *last_index)
+{
+	int first = find_ofs_delta(offset);
+	int last = first;
+	int end = nr_ofs_deltas - 1;
+
+	if (first < 0) {
+		*first_index = 0;
+		*last_index = -1;
+		return;
+	}
+	while (first > 0 && ofs_deltas[first - 1].offset == offset)
+		--first;
+	while (last < end && ofs_deltas[last + 1].offset == offset)
+		++last;
+	*first_index = first;
+	*last_index = last;
+}
+
+static int compare_ref_delta_bases(const struct object_id *oid1,
+				   const struct object_id *oid2,
+				   enum object_type type1,
+				   enum object_type type2)
+{
+	int cmp = type1 - type2;
+	if (cmp)
+		return cmp;
+	return oidcmp(oid1, oid2);
+}
+
+static int find_ref_delta(const struct object_id *oid)
+{
+	int first = 0, last = nr_ref_deltas;
+
+	while (first < last) {
+		int next = first + (last - first) / 2;
+		struct ref_delta_entry *delta = &ref_deltas[next];
+		int cmp;
+
+		cmp = compare_ref_delta_bases(oid, &delta->oid,
+					      OBJ_REF_DELTA,
+					      objects[delta->obj_no].type);
+		if (!cmp)
+			return next;
+		if (cmp < 0) {
+			last = next;
+			continue;
+		}
+		first = next+1;
+	}
+	return -first-1;
+}
+
+static void find_ref_delta_children(const struct object_id *oid,
+				    int *first_index, int *last_index)
+{
+	int first = find_ref_delta(oid);
+	int last = first;
+	int end = nr_ref_deltas - 1;
+
+	if (first < 0) {
+		*first_index = 0;
+		*last_index = -1;
+		return;
+	}
+	while (first > 0 && oideq(&ref_deltas[first - 1].oid, oid))
+		--first;
+	while (last < end && oideq(&ref_deltas[last + 1].oid, oid))
+		++last;
+	*first_index = first;
+	*last_index = last;
+}
+
+struct compare_data {
+	struct object_entry *entry;
+	struct git_istream *st;
+	unsigned char *buf;
+	unsigned long buf_size;
+};
+
+static int compare_objects(const unsigned char *buf, unsigned long size,
+			   void *cb_data)
+{
+	struct compare_data *data = cb_data;
+
+	if (data->buf_size < size) {
+		free(data->buf);
+		data->buf = xmalloc(size);
+		data->buf_size = size;
+	}
+
+	while (size) {
+		ssize_t len = read_istream(data->st, data->buf, size);
+		if (len == 0)
+			die(_("SHA1 COLLISION FOUND WITH %s !"),
+			    oid_to_hex(&data->entry->idx.oid));
+		if (len < 0)
+			die(_("unable to read %s"),
+			    oid_to_hex(&data->entry->idx.oid));
+		if (memcmp(buf, data->buf, len))
+			die(_("SHA1 COLLISION FOUND WITH %s !"),
+			    oid_to_hex(&data->entry->idx.oid));
+		size -= len;
+		buf += len;
+	}
+	return 0;
+}
+
+static int check_collison(struct object_entry *entry)
+{
+	struct compare_data data;
+	enum object_type type;
+	unsigned long size;
+
+	if (entry->size <= big_file_threshold || entry->type != OBJ_BLOB)
+		return -1;
+
+	memset(&data, 0, sizeof(data));
+	data.entry = entry;
+	data.st = open_istream(the_repository, &entry->idx.oid, &type, &size,
+			       NULL);
+	if (!data.st)
+		return -1;
+	if (size != entry->size || type != entry->type)
+		die(_("SHA1 COLLISION FOUND WITH %s !"),
+		    oid_to_hex(&entry->idx.oid));
+	unpack_data(entry, compare_objects, &data);
+	close_istream(data.st);
+	free(data.buf);
+	return 0;
+}
+
+static void record_outgoing_link(const struct object_id *oid)
+{
+	oidset_insert(&outgoing_links, oid);
+}
+
+static void maybe_record_name_entry(const struct name_entry *entry)
+{
+	/*
+	 * Checking only trees here results in a significantly faster packfile
+	 * indexing, but the drawback is that if the packfile to be indexed
+	 * references a local blob only directly (that is, never through a
+	 * local tree), that local blob is in danger of being garbage
+	 * collected. Such a situation may arise if we push local commits,
+	 * including one with a change to a blob in the root tree, and then the
+	 * server incorporates them into its main branch through a "rebase" or
+	 * "squash" merge strategy, and then we fetch the new main branch from
+	 * the server.
+	 *
+	 * This situation has not been observed yet - we have only noticed
+	 * missing commits, not missing trees or blobs. (In fact, if it were
+	 * believed that only missing commits are problematic, one could argue
+	 * that we should also exclude trees during the outgoing link check;
+	 * but it is safer to include them.)
+	 *
+	 * Due to the rarity of the situation (it has not been observed to
+	 * happen in real life), and because the "penalty" in such a situation
+	 * is merely to refetch the missing blob when it's needed (and this
+	 * happens only once - when refetched, the blob goes into a promisor
+	 * pack, so it won't be GC-ed, the tradeoff seems worth it.
+	*/
+	if (S_ISDIR(entry->mode))
+		record_outgoing_link(&entry->oid);
+}
+
+static void do_record_outgoing_links(struct object *obj)
+{
+	if (obj->type == OBJ_TREE) {
+		struct tree *tree = (struct tree *)obj;
+		struct tree_desc desc;
+		struct name_entry entry;
+		if (init_tree_desc_gently(&desc, &tree->object.oid,
+					  tree->buffer, tree->size, 0))
+			/*
+			 * Error messages are given when packs are
+			 * verified, so do not print any here.
+			 */
+			return;
+		while (tree_entry_gently(&desc, &entry))
+			maybe_record_name_entry(&entry);
+	} else if (obj->type == OBJ_COMMIT) {
+		struct commit *commit = (struct commit *) obj;
+		struct commit_list *parents = commit->parents;
+
+		record_outgoing_link(get_commit_tree_oid(commit));
+		for (; parents; parents = parents->next)
+			record_outgoing_link(&parents->item->object.oid);
+	} else if (obj->type == OBJ_TAG) {
+		struct tag *tag = (struct tag *) obj;
+		record_outgoing_link(get_tagged_oid(tag));
+	}
+}
+
+static void sha1_object(const void *data, struct object_entry *obj_entry,
+			unsigned long size, enum object_type type,
+			const struct object_id *oid)
+{
+	void *new_data = NULL;
+	int collision_test_needed = 0;
+
+	assert(data || obj_entry);
+
+	if (startup_info->have_repository) {
+		read_lock();
+		collision_test_needed =
+			repo_has_object_file_with_flags(the_repository, oid,
+							OBJECT_INFO_QUICK);
+		read_unlock();
+	}
+
+	if (collision_test_needed && !data) {
+		read_lock();
+		if (!check_collison(obj_entry))
+			collision_test_needed = 0;
+		read_unlock();
+	}
+	if (collision_test_needed) {
+		void *has_data;
+		enum object_type has_type;
+		unsigned long has_size;
+		read_lock();
+		has_type = oid_object_info(the_repository, oid, &has_size);
+		if (has_type < 0)
+			die(_("cannot read existing object info %s"), oid_to_hex(oid));
+		if (has_type != type || has_size != size)
+			die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
+		has_data = repo_read_object_file(the_repository, oid,
+						 &has_type, &has_size);
+		read_unlock();
+		if (!data)
+			data = new_data = get_data_from_pack(obj_entry);
+		if (!has_data)
+			die(_("cannot read existing object %s"), oid_to_hex(oid));
+		if (size != has_size || type != has_type ||
+		    memcmp(data, has_data, size) != 0)
+			die(_("SHA1 COLLISION FOUND WITH %s !"), oid_to_hex(oid));
+		free(has_data);
+	}
+
+	if (strict || do_fsck_object || record_outgoing_links) {
+		read_lock();
+		if (type == OBJ_BLOB) {
+			struct blob *blob = lookup_blob(the_repository, oid);
+			if (blob)
+				blob->object.flags |= FLAG_CHECKED;
+			else
+				die(_("invalid blob object %s"), oid_to_hex(oid));
+			if (do_fsck_object &&
+			    fsck_object(&blob->object, (void *)data, size, &fsck_options))
+				die(_("fsck error in packed object"));
+		} else {
+			struct object *obj;
+			int eaten;
+			void *buf = (void *) data;
+
+			assert(data && "data can only be NULL for large _blobs_");
+
+			/*
+			 * we do not need to free the memory here, as the
+			 * buf is deleted by the caller.
+			 */
+			obj = parse_object_buffer(the_repository, oid, type,
+						  size, buf,
+						  &eaten);
+			if (!obj)
+				die(_("invalid %s"), type_name(type));
+			if (do_fsck_object &&
+			    fsck_object(obj, buf, size, &fsck_options))
+				die(_("fsck error in packed object"));
+			if (strict && fsck_walk(obj, NULL, &fsck_options))
+				die(_("Not all child objects of %s are reachable"), oid_to_hex(&obj->oid));
+			if (record_outgoing_links)
+				do_record_outgoing_links(obj);
+
+			if (obj->type == OBJ_TREE) {
+				struct tree *item = (struct tree *) obj;
+				item->buffer = NULL;
+				obj->parsed = 0;
+			}
+			if (obj->type == OBJ_COMMIT) {
+				struct commit *commit = (struct commit *) obj;
+				if (detach_commit_buffer(commit, NULL) != data)
+					BUG("parse_object_buffer transmogrified our buffer");
+			}
+			obj->flags |= FLAG_CHECKED;
+		}
+		read_unlock();
+	}
+
+	free(new_data);
+}
+
+/*
+ * Ensure that this node has been reconstructed and return its contents.
+ *
+ * In the typical and best case, this node would already be reconstructed
+ * (through the invocation to resolve_delta() in threaded_second_pass()) and it
+ * would not be pruned. However, if pruning of this node was necessary due to
+ * reaching delta_base_cache_limit, this function will find the closest
+ * ancestor with reconstructed data that has not been pruned (or if there is
+ * none, the ultimate base object), and reconstruct each node in the delta
+ * chain in order to generate the reconstructed data for this node.
+ */
+static void *get_base_data(struct base_data *c)
+{
+	if (!c->data) {
+		struct object_entry *obj = c->obj;
+		struct base_data **delta = NULL;
+		int delta_nr = 0, delta_alloc = 0;
+
+		while (is_delta_type(c->obj->type) && !c->data) {
+			ALLOC_GROW(delta, delta_nr + 1, delta_alloc);
+			delta[delta_nr++] = c;
+			c = c->base;
+		}
+		if (!delta_nr) {
+			c->data = get_data_from_pack(obj);
+			c->size = obj->size;
+			base_cache_used += c->size;
+			prune_base_data(c);
+		}
+		for (; delta_nr > 0; delta_nr--) {
+			void *base, *raw;
+			c = delta[delta_nr - 1];
+			obj = c->obj;
+			base = get_base_data(c->base);
+			raw = get_data_from_pack(obj);
+			c->data = patch_delta(
+				base, c->base->size,
+				raw, obj->size,
+				&c->size);
+			free(raw);
+			if (!c->data)
+				bad_object(obj->idx.offset, _("failed to apply delta"));
+			base_cache_used += c->size;
+			prune_base_data(c);
+		}
+		free(delta);
+	}
+	return c->data;
+}
+
+static struct base_data *make_base(struct object_entry *obj,
+				   struct base_data *parent)
+{
+	struct base_data *base = xcalloc(1, sizeof(struct base_data));
+	base->base = parent;
+	base->obj = obj;
+	find_ref_delta_children(&obj->idx.oid,
+				&base->ref_first, &base->ref_last);
+	find_ofs_delta_children(obj->idx.offset,
+				&base->ofs_first, &base->ofs_last);
+	base->children_remaining = base->ref_last - base->ref_first +
+		base->ofs_last - base->ofs_first + 2;
+	return base;
+}
+
+static struct base_data *resolve_delta(struct object_entry *delta_obj,
+				       struct base_data *base)
+{
+	void *delta_data, *result_data;
+	struct base_data *result;
+	unsigned long result_size;
+
+	if (show_stat) {
+		int i = delta_obj - objects;
+		int j = base->obj - objects;
+		obj_stat[i].delta_depth = obj_stat[j].delta_depth + 1;
+		deepest_delta_lock();
+		if (deepest_delta < obj_stat[i].delta_depth)
+			deepest_delta = obj_stat[i].delta_depth;
+		deepest_delta_unlock();
+		obj_stat[i].base_object_no = j;
+	}
+	delta_data = get_data_from_pack(delta_obj);
+	assert(base->data);
+	result_data = patch_delta(base->data, base->size,
+				  delta_data, delta_obj->size, &result_size);
+	free(delta_data);
+	if (!result_data)
+		bad_object(delta_obj->idx.offset, _("failed to apply delta"));
+	hash_object_file(the_hash_algo, result_data, result_size,
+			 delta_obj->real_type, &delta_obj->idx.oid);
+	sha1_object(result_data, NULL, result_size, delta_obj->real_type,
+		    &delta_obj->idx.oid);
+
+	result = make_base(delta_obj, base);
+	result->data = result_data;
+	result->size = result_size;
+
+	counter_lock();
+	nr_resolved_deltas++;
+	counter_unlock();
+
+	return result;
+}
+
+static int compare_ofs_delta_entry(const void *a, const void *b)
+{
+	const struct ofs_delta_entry *delta_a = a;
+	const struct ofs_delta_entry *delta_b = b;
+
+	return delta_a->offset < delta_b->offset ? -1 :
+	       delta_a->offset > delta_b->offset ?  1 :
+	       0;
+}
+
+static int compare_ref_delta_entry(const void *a, const void *b)
+{
+	const struct ref_delta_entry *delta_a = a;
+	const struct ref_delta_entry *delta_b = b;
+
+	return oidcmp(&delta_a->oid, &delta_b->oid);
+}
+
+static void *threaded_second_pass(void *data)
+{
+	if (data)
+		set_thread_data(data);
+	for (;;) {
+		struct base_data *parent = NULL;
+		struct object_entry *child_obj;
+		struct base_data *child;
+
+		counter_lock();
+		display_progress(progress, nr_resolved_deltas);
+		counter_unlock();
+
+		work_lock();
+		if (list_empty(&work_head)) {
+			/*
+			 * Take an object from the object array.
+			 */
+			while (nr_dispatched < nr_objects &&
+			       is_delta_type(objects[nr_dispatched].type))
+				nr_dispatched++;
+			if (nr_dispatched >= nr_objects) {
+				work_unlock();
+				break;
+			}
+			child_obj = &objects[nr_dispatched++];
+		} else {
+			/*
+			 * Peek at the top of the stack, and take a child from
+			 * it.
+			 */
+			parent = list_first_entry(&work_head, struct base_data,
+						  list);
+
+			if (parent->ref_first <= parent->ref_last) {
+				int offset = ref_deltas[parent->ref_first++].obj_no;
+				child_obj = objects + offset;
+				if (child_obj->real_type != OBJ_REF_DELTA)
+					die("REF_DELTA at offset %"PRIuMAX" already resolved (duplicate base %s?)",
+					    (uintmax_t) child_obj->idx.offset,
+					    oid_to_hex(&parent->obj->idx.oid));
+				child_obj->real_type = parent->obj->real_type;
+			} else {
+				child_obj = objects +
+					ofs_deltas[parent->ofs_first++].obj_no;
+				assert(child_obj->real_type == OBJ_OFS_DELTA);
+				child_obj->real_type = parent->obj->real_type;
+			}
+
+			if (parent->ref_first > parent->ref_last &&
+			    parent->ofs_first > parent->ofs_last) {
+				/*
+				 * This parent has run out of children, so move
+				 * it to done_head.
+				 */
+				list_del(&parent->list);
+				list_add(&parent->list, &done_head);
+			}
+
+			/*
+			 * Ensure that the parent has data, since we will need
+			 * it later.
+			 *
+			 * NEEDSWORK: If parent data needs to be reloaded, this
+			 * prolongs the time that the current thread spends in
+			 * the mutex. A mitigating factor is that parent data
+			 * needs to be reloaded only if the delta base cache
+			 * limit is exceeded, so in the typical case, this does
+			 * not happen.
+			 */
+			get_base_data(parent);
+			parent->retain_data++;
+		}
+		work_unlock();
+
+		if (parent) {
+			child = resolve_delta(child_obj, parent);
+			if (!child->children_remaining)
+				FREE_AND_NULL(child->data);
+		} else {
+			child = make_base(child_obj, NULL);
+			if (child->children_remaining) {
+				/*
+				 * Since this child has its own delta children,
+				 * we will need this data in the future.
+				 * Inflate now so that future iterations will
+				 * have access to this object's data while
+				 * outside the work mutex.
+				 */
+				child->data = get_data_from_pack(child_obj);
+				child->size = child_obj->size;
+			}
+		}
+
+		work_lock();
+		if (parent)
+			parent->retain_data--;
+		if (child->data) {
+			/*
+			 * This child has its own children, so add it to
+			 * work_head.
+			 */
+			list_add(&child->list, &work_head);
+			base_cache_used += child->size;
+			prune_base_data(NULL);
+			free_base_data(child);
+		} else {
+			/*
+			 * This child does not have its own children. It may be
+			 * the last descendant of its ancestors; free those
+			 * that we can.
+			 */
+			struct base_data *p = parent;
+
+			while (p) {
+				struct base_data *next_p;
+
+				p->children_remaining--;
+				if (p->children_remaining)
+					break;
+
+				next_p = p->base;
+				free_base_data(p);
+				list_del(&p->list);
+				free(p);
+
+				p = next_p;
+			}
+			FREE_AND_NULL(child);
+		}
+		work_unlock();
+	}
+	return NULL;
+}
+
+/*
+ * First pass:
+ * - find locations of all objects;
+ * - calculate SHA1 of all non-delta objects;
+ * - remember base (SHA1 or offset) for all deltas.
+ */
+static void parse_pack_objects(unsigned char *hash)
+{
+	int i, nr_delays = 0;
+	struct ofs_delta_entry *ofs_delta = ofs_deltas;
+	struct object_id ref_delta_oid;
+	struct stat st;
+	git_hash_ctx tmp_ctx;
+
+	if (verbose)
+		progress = start_progress(
+				the_repository,
+				progress_title ? progress_title :
+				from_stdin ? _("Receiving objects") : _("Indexing objects"),
+				nr_objects);
+	for (i = 0; i < nr_objects; i++) {
+		struct object_entry *obj = &objects[i];
+		void *data = unpack_raw_entry(obj, &ofs_delta->offset,
+					      &ref_delta_oid,
+					      &obj->idx.oid);
+		obj->real_type = obj->type;
+		if (obj->type == OBJ_OFS_DELTA) {
+			nr_ofs_deltas++;
+			ofs_delta->obj_no = i;
+			ofs_delta++;
+		} else if (obj->type == OBJ_REF_DELTA) {
+			ALLOC_GROW(ref_deltas, nr_ref_deltas + 1, ref_deltas_alloc);
+			oidcpy(&ref_deltas[nr_ref_deltas].oid, &ref_delta_oid);
+			ref_deltas[nr_ref_deltas].obj_no = i;
+			nr_ref_deltas++;
+		} else if (!data) {
+			/* large blobs, check later */
+			obj->real_type = OBJ_BAD;
+			nr_delays++;
+		} else
+			sha1_object(data, NULL, obj->size, obj->type,
+				    &obj->idx.oid);
+		free(data);
+		display_progress(progress, i+1);
+	}
+	objects[i].idx.offset = consumed_bytes;
+	stop_progress(&progress);
+
+	/* Check pack integrity */
+	flush();
+	the_hash_algo->init_fn(&tmp_ctx);
+	the_hash_algo->clone_fn(&tmp_ctx, &input_ctx);
+	the_hash_algo->final_fn(hash, &tmp_ctx);
+	if (!hasheq(fill(the_hash_algo->rawsz), hash, the_repository->hash_algo))
+		die(_("pack is corrupted (SHA1 mismatch)"));
+	use(the_hash_algo->rawsz);
+
+	/* If input_fd is a file, we should have reached its end now. */
+	if (fstat(input_fd, &st))
+		die_errno(_("cannot fstat packfile"));
+	if (S_ISREG(st.st_mode) &&
+			lseek(input_fd, 0, SEEK_CUR) - input_len != st.st_size)
+		die(_("pack has junk at the end"));
+
+	for (i = 0; i < nr_objects; i++) {
+		struct object_entry *obj = &objects[i];
+		if (obj->real_type != OBJ_BAD)
+			continue;
+		obj->real_type = obj->type;
+		sha1_object(NULL, obj, obj->size, obj->type,
+			    &obj->idx.oid);
+		nr_delays--;
+	}
+	if (nr_delays)
+		die(_("confusion beyond insanity in parse_pack_objects()"));
+}
+
+/*
+ * Second pass:
+ * - for all non-delta objects, look if it is used as a base for
+ *   deltas;
+ * - if used as a base, uncompress the object and apply all deltas,
+ *   recursively checking if the resulting object is used as a base
+ *   for some more deltas.
+ */
+static void resolve_deltas(struct pack_idx_option *opts)
+{
+	int i;
+
+	if (!nr_ofs_deltas && !nr_ref_deltas)
+		return;
+
+	/* Sort deltas by base SHA1/offset for fast searching */
+	QSORT(ofs_deltas, nr_ofs_deltas, compare_ofs_delta_entry);
+	QSORT(ref_deltas, nr_ref_deltas, compare_ref_delta_entry);
+
+	if (verbose || show_resolving_progress)
+		progress = start_progress(the_repository,
+					  _("Resolving deltas"),
+					  nr_ref_deltas + nr_ofs_deltas);
+
+	nr_dispatched = 0;
+	base_cache_limit = opts->delta_base_cache_limit * nr_threads;
+	if (nr_threads > 1 || getenv("GIT_FORCE_THREADS")) {
+		init_thread();
+		for (i = 0; i < nr_threads; i++) {
+			int ret = pthread_create(&thread_data[i].thread, NULL,
+						 threaded_second_pass, thread_data + i);
+			if (ret)
+				die(_("unable to create thread: %s"),
+				    strerror(ret));
+		}
+		for (i = 0; i < nr_threads; i++)
+			pthread_join(thread_data[i].thread, NULL);
+		cleanup_thread();
+		return;
+	}
+	threaded_second_pass(&nothread_data);
+}
+
+/*
+ * Third pass:
+ * - append objects to convert thin pack to full pack if required
+ * - write the final pack hash
+ */
+static void fix_unresolved_deltas(struct hashfile *f);
+static void conclude_pack(int fix_thin_pack, const char *curr_pack, unsigned char *pack_hash)
+{
+	if (nr_ref_deltas + nr_ofs_deltas == nr_resolved_deltas) {
+		stop_progress(&progress);
+		/* Flush remaining pack final hash. */
+		flush();
+		return;
+	}
+
+	if (fix_thin_pack) {
+		struct hashfile *f;
+		unsigned char read_hash[GIT_MAX_RAWSZ], tail_hash[GIT_MAX_RAWSZ];
+		struct strbuf msg = STRBUF_INIT;
+		int nr_unresolved = nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas;
+		int nr_objects_initial = nr_objects;
+		if (nr_unresolved <= 0)
+			die(_("confusion beyond insanity"));
+		REALLOC_ARRAY(objects, nr_objects + nr_unresolved + 1);
+		memset(objects + nr_objects + 1, 0,
+		       nr_unresolved * sizeof(*objects));
+		f = hashfd(output_fd, curr_pack);
+		fix_unresolved_deltas(f);
+		strbuf_addf(&msg, Q_("completed with %d local object",
+				     "completed with %d local objects",
+				     nr_objects - nr_objects_initial),
+			    nr_objects - nr_objects_initial);
+		stop_progress_msg(&progress, msg.buf);
+		strbuf_release(&msg);
+		finalize_hashfile(f, tail_hash, FSYNC_COMPONENT_PACK, 0);
+		hashcpy(read_hash, pack_hash, the_repository->hash_algo);
+		fixup_pack_header_footer(output_fd, pack_hash,
+					 curr_pack, nr_objects,
+					 read_hash, consumed_bytes-the_hash_algo->rawsz);
+		if (!hasheq(read_hash, tail_hash, the_repository->hash_algo))
+			die(_("Unexpected tail checksum for %s "
+			      "(disk corruption?)"), curr_pack);
+	}
+	if (nr_ofs_deltas + nr_ref_deltas != nr_resolved_deltas)
+		die(Q_("pack has %d unresolved delta",
+		       "pack has %d unresolved deltas",
+		       nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas),
+		    nr_ofs_deltas + nr_ref_deltas - nr_resolved_deltas);
+}
+
+static int write_compressed(struct hashfile *f, void *in, unsigned int size)
+{
+	git_zstream stream;
+	int status;
+	unsigned char outbuf[4096];
+
+	git_deflate_init(&stream, zlib_compression_level);
+	stream.next_in = in;
+	stream.avail_in = size;
+
+	do {
+		stream.next_out = outbuf;
+		stream.avail_out = sizeof(outbuf);
+		status = git_deflate(&stream, Z_FINISH);
+		hashwrite(f, outbuf, sizeof(outbuf) - stream.avail_out);
+	} while (status == Z_OK);
+
+	if (status != Z_STREAM_END)
+		die(_("unable to deflate appended object (%d)"), status);
+	size = stream.total_out;
+	git_deflate_end(&stream);
+	return size;
+}
+
+static struct object_entry *append_obj_to_pack(struct hashfile *f,
+			       const unsigned char *sha1, void *buf,
+			       unsigned long size, enum object_type type)
+{
+	struct object_entry *obj = &objects[nr_objects++];
+	unsigned char header[10];
+	unsigned long s = size;
+	int n = 0;
+	unsigned char c = (type << 4) | (s & 15);
+	s >>= 4;
+	while (s) {
+		header[n++] = c | 0x80;
+		c = s & 0x7f;
+		s >>= 7;
+	}
+	header[n++] = c;
+	crc32_begin(f);
+	hashwrite(f, header, n);
+	obj[0].size = size;
+	obj[0].hdr_size = n;
+	obj[0].type = type;
+	obj[0].real_type = type;
+	obj[1].idx.offset = obj[0].idx.offset + n;
+	obj[1].idx.offset += write_compressed(f, buf, size);
+	obj[0].idx.crc32 = crc32_end(f);
+	hashflush(f);
+	oidread(&obj->idx.oid, sha1, the_repository->hash_algo);
+	return obj;
+}
+
+static int delta_pos_compare(const void *_a, const void *_b)
+{
+	struct ref_delta_entry *a = *(struct ref_delta_entry **)_a;
+	struct ref_delta_entry *b = *(struct ref_delta_entry **)_b;
+	return a->obj_no - b->obj_no;
+}
+
+static void fix_unresolved_deltas(struct hashfile *f)
+{
+	struct ref_delta_entry **sorted_by_pos;
+	int i;
+
+	/*
+	 * Since many unresolved deltas may well be themselves base objects
+	 * for more unresolved deltas, we really want to include the
+	 * smallest number of base objects that would cover as much delta
+	 * as possible by picking the
+	 * trunc deltas first, allowing for other deltas to resolve without
+	 * additional base objects.  Since most base objects are to be found
+	 * before deltas depending on them, a good heuristic is to start
+	 * resolving deltas in the same order as their position in the pack.
+	 */
+	ALLOC_ARRAY(sorted_by_pos, nr_ref_deltas);
+	for (i = 0; i < nr_ref_deltas; i++)
+		sorted_by_pos[i] = &ref_deltas[i];
+	QSORT(sorted_by_pos, nr_ref_deltas, delta_pos_compare);
+
+	if (repo_has_promisor_remote(the_repository)) {
+		/*
+		 * Prefetch the delta bases.
+		 */
+		struct oid_array to_fetch = OID_ARRAY_INIT;
+		for (i = 0; i < nr_ref_deltas; i++) {
+			struct ref_delta_entry *d = sorted_by_pos[i];
+			if (!oid_object_info_extended(the_repository, &d->oid,
+						      NULL,
+						      OBJECT_INFO_FOR_PREFETCH))
+				continue;
+			oid_array_append(&to_fetch, &d->oid);
+		}
+		promisor_remote_get_direct(the_repository,
+					   to_fetch.oid, to_fetch.nr);
+		oid_array_clear(&to_fetch);
+	}
+
+	for (i = 0; i < nr_ref_deltas; i++) {
+		struct ref_delta_entry *d = sorted_by_pos[i];
+		enum object_type type;
+		void *data;
+		unsigned long size;
+
+		if (objects[d->obj_no].real_type != OBJ_REF_DELTA)
+			continue;
+		data = repo_read_object_file(the_repository, &d->oid, &type,
+					     &size);
+		if (!data)
+			continue;
+
+		if (check_object_signature(the_repository, &d->oid, data, size,
+					   type) < 0)
+			die(_("local object %s is corrupt"), oid_to_hex(&d->oid));
+
+		/*
+		 * Add this as an object to the objects array and call
+		 * threaded_second_pass() (which will pick up the added
+		 * object).
+		 */
+		append_obj_to_pack(f, d->oid.hash, data, size, type);
+		free(data);
+		threaded_second_pass(NULL);
+
+		display_progress(progress, nr_resolved_deltas);
+	}
+	free(sorted_by_pos);
+}
+
+static const char *derive_filename(const char *pack_name, const char *strip,
+				   const char *suffix, struct strbuf *buf)
+{
+	size_t len;
+	if (!strip_suffix(pack_name, strip, &len) || !len ||
+	    pack_name[len - 1] != '.')
+		die(_("packfile name '%s' does not end with '.%s'"),
+		    pack_name, strip);
+	strbuf_add(buf, pack_name, len);
+	strbuf_addstr(buf, suffix);
+	return buf->buf;
+}
+
+static void write_special_file(const char *suffix, const char *msg,
+			       const char *pack_name, const unsigned char *hash,
+			       const char **report)
+{
+	struct strbuf name_buf = STRBUF_INIT;
+	const char *filename;
+	int fd;
+	int msg_len = strlen(msg);
+
+	if (pack_name)
+		filename = derive_filename(pack_name, "pack", suffix, &name_buf);
+	else
+		filename = odb_pack_name(the_repository, &name_buf, hash, suffix);
+
+	fd = odb_pack_keep(filename);
+	if (fd < 0) {
+		if (errno != EEXIST)
+			die_errno(_("cannot write %s file '%s'"),
+				  suffix, filename);
+	} else {
+		if (msg_len > 0) {
+			write_or_die(fd, msg, msg_len);
+			write_or_die(fd, "\n", 1);
+		}
+		if (close(fd) != 0)
+			die_errno(_("cannot close written %s file '%s'"),
+				  suffix, filename);
+		if (report)
+			*report = suffix;
+	}
+	strbuf_release(&name_buf);
+}
+
+static void rename_tmp_packfile(const char **final_name,
+				const char *curr_name,
+				struct strbuf *name, unsigned char *hash,
+				const char *ext, int make_read_only_if_same)
+{
+	if (!*final_name || strcmp(*final_name, curr_name)) {
+		if (!*final_name)
+			*final_name = odb_pack_name(the_repository, name, hash, ext);
+		if (finalize_object_file(curr_name, *final_name))
+			die(_("unable to rename temporary '*.%s' file to '%s'"),
+			    ext, *final_name);
+	} else if (make_read_only_if_same) {
+		chmod(*final_name, 0444);
+	}
+}
+
+static void final(const char *final_pack_name, const char *curr_pack_name,
+		  const char *final_index_name, const char *curr_index_name,
+		  const char *final_rev_index_name, const char *curr_rev_index_name,
+		  const char *keep_msg, const char *promisor_msg,
+		  unsigned char *hash)
+{
+	const char *report = "pack";
+	struct strbuf pack_name = STRBUF_INIT;
+	struct strbuf index_name = STRBUF_INIT;
+	struct strbuf rev_index_name = STRBUF_INIT;
+
+	if (!from_stdin) {
+		close(input_fd);
+	} else {
+		fsync_component_or_die(FSYNC_COMPONENT_PACK, output_fd, curr_pack_name);
+		if (close(output_fd))
+			die_errno(_("error while closing pack file"));
+	}
+
+	if (keep_msg)
+		write_special_file("keep", keep_msg, final_pack_name, hash,
+				   &report);
+	if (promisor_msg)
+		write_special_file("promisor", promisor_msg, final_pack_name,
+				   hash, NULL);
+
+	rename_tmp_packfile(&final_pack_name, curr_pack_name, &pack_name,
+			    hash, "pack", from_stdin);
+	if (curr_rev_index_name)
+		rename_tmp_packfile(&final_rev_index_name, curr_rev_index_name,
+				    &rev_index_name, hash, "rev", 1);
+	rename_tmp_packfile(&final_index_name, curr_index_name, &index_name,
+			    hash, "idx", 1);
+
+	if (do_fsck_object) {
+		struct packed_git *p;
+		p = add_packed_git(the_repository, final_index_name,
+				   strlen(final_index_name), 0);
+		if (p)
+			install_packed_git(the_repository, p);
+	}
+
+	if (!from_stdin) {
+		printf("%s\n", hash_to_hex(hash));
+	} else {
+		struct strbuf buf = STRBUF_INIT;
+
+		strbuf_addf(&buf, "%s\t%s\n", report, hash_to_hex(hash));
+		write_or_die(1, buf.buf, buf.len);
+		strbuf_release(&buf);
+
+		/* Write the last part of the buffer to stdout */
+		write_in_full(1, input_buffer + input_offset, input_len);
+	}
+
+	strbuf_release(&rev_index_name);
+	strbuf_release(&index_name);
+	strbuf_release(&pack_name);
+}
+
+static int git_index_pack_config(const char *k, const char *v,
+				 const struct config_context *ctx, void *cb)
+{
+	struct pack_idx_option *opts = cb;
+
+	if (!strcmp(k, "pack.indexversion")) {
+		opts->version = git_config_int(k, v, ctx->kvi);
+		if (opts->version > 2)
+			die(_("bad pack.indexVersion=%"PRIu32), opts->version);
+		return 0;
+	}
+	if (!strcmp(k, "pack.threads")) {
+		nr_threads = git_config_int(k, v, ctx->kvi);
+		if (nr_threads < 0)
+			die(_("invalid number of threads specified (%d)"),
+			    nr_threads);
+		if (!HAVE_THREADS && nr_threads != 1) {
+			warning(_("no threads support, ignoring %s"), k);
+			nr_threads = 1;
+		}
+		return 0;
+	}
+	if (!strcmp(k, "pack.writereverseindex")) {
+		if (git_config_bool(k, v))
+			opts->flags |= WRITE_REV;
+		else
+			opts->flags &= ~WRITE_REV;
+	}
+	if (!strcmp(k, "core.deltabasecachelimit")) {
+		opts->delta_base_cache_limit = git_config_ulong(k, v, ctx->kvi);
+		return 0;
+	}
+	return git_default_config(k, v, ctx, cb);
+}
+
+static int cmp_uint32(const void *a_, const void *b_)
+{
+	uint32_t a = *((uint32_t *)a_);
+	uint32_t b = *((uint32_t *)b_);
+
+	return (a < b) ? -1 : (a != b);
+}
+
+static void read_v2_anomalous_offsets(struct packed_git *p,
+				      struct pack_idx_option *opts)
+{
+	const uint32_t *idx1, *idx2;
+	uint32_t i;
+
+	/* The address of the 4-byte offset table */
+	idx1 = (((const uint32_t *)((const uint8_t *)p->index_data + p->crc_offset))
+		+ (size_t)p->num_objects /* CRC32 table */
+		);
+
+	/* The address of the 8-byte offset table */
+	idx2 = idx1 + p->num_objects;
+
+	for (i = 0; i < p->num_objects; i++) {
+		uint32_t off = ntohl(idx1[i]);
+		if (!(off & 0x80000000))
+			continue;
+		off = off & 0x7fffffff;
+		check_pack_index_ptr(p, &idx2[off * 2]);
+		if (idx2[off * 2])
+			continue;
+		/*
+		 * The real offset is ntohl(idx2[off * 2]) in high 4
+		 * octets, and ntohl(idx2[off * 2 + 1]) in low 4
+		 * octets.  But idx2[off * 2] is Zero!!!
+		 */
+		ALLOC_GROW(opts->anomaly, opts->anomaly_nr + 1, opts->anomaly_alloc);
+		opts->anomaly[opts->anomaly_nr++] = ntohl(idx2[off * 2 + 1]);
+	}
+
+	QSORT(opts->anomaly, opts->anomaly_nr, cmp_uint32);
+}
+
+static void read_idx_option(struct pack_idx_option *opts, const char *pack_name)
+{
+	struct packed_git *p = add_packed_git(the_repository, pack_name,
+					      strlen(pack_name), 1);
+
+	if (!p)
+		die(_("Cannot open existing pack file '%s'"), pack_name);
+	if (open_pack_index(p))
+		die(_("Cannot open existing pack idx file for '%s'"), pack_name);
+
+	/* Read the attributes from the existing idx file */
+	opts->version = p->index_version;
+
+	if (opts->version == 2)
+		read_v2_anomalous_offsets(p, opts);
+
+	/*
+	 * Get rid of the idx file as we do not need it anymore.
+	 * NEEDSWORK: extract this bit from free_pack_by_name() in
+	 * object-file.c, perhaps?  It shouldn't matter very much as we
+	 * know we haven't installed this pack (hence we never have
+	 * read anything from it).
+	 */
+	close_pack_index(p);
+	free(p);
+}
+
+static void show_pack_info(int stat_only)
+{
+	int i, baseobjects = nr_objects - nr_ref_deltas - nr_ofs_deltas;
+	unsigned long *chain_histogram = NULL;
+
+	if (deepest_delta)
+		CALLOC_ARRAY(chain_histogram, deepest_delta);
+
+	for (i = 0; i < nr_objects; i++) {
+		struct object_entry *obj = &objects[i];
+
+		if (is_delta_type(obj->type))
+			chain_histogram[obj_stat[i].delta_depth - 1]++;
+		if (stat_only)
+			continue;
+		printf("%s %-6s %"PRIuMAX" %"PRIuMAX" %"PRIuMAX,
+		       oid_to_hex(&obj->idx.oid),
+		       type_name(obj->real_type), (uintmax_t)obj->size,
+		       (uintmax_t)(obj[1].idx.offset - obj->idx.offset),
+		       (uintmax_t)obj->idx.offset);
+		if (is_delta_type(obj->type)) {
+			struct object_entry *bobj = &objects[obj_stat[i].base_object_no];
+			printf(" %u %s", obj_stat[i].delta_depth,
+			       oid_to_hex(&bobj->idx.oid));
+		}
+		putchar('\n');
+	}
+
+	if (baseobjects)
+		printf_ln(Q_("non delta: %d object",
+			     "non delta: %d objects",
+			     baseobjects),
+			  baseobjects);
+	for (i = 0; i < deepest_delta; i++) {
+		if (!chain_histogram[i])
+			continue;
+		printf_ln(Q_("chain length = %d: %lu object",
+			     "chain length = %d: %lu objects",
+			     chain_histogram[i]),
+			  i + 1,
+			  chain_histogram[i]);
+	}
+	free(chain_histogram);
+}
+
+static void repack_local_links(void)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	FILE *out;
+	struct strbuf line = STRBUF_INIT;
+	struct oidset_iter iter;
+	struct object_id *oid;
+	char *base_name = NULL;
+
+	if (!oidset_size(&outgoing_links))
+		return;
+
+	oidset_iter_init(&outgoing_links, &iter);
+	while ((oid = oidset_iter_next(&iter))) {
+		struct object_info info = OBJECT_INFO_INIT;
+		if (oid_object_info_extended(the_repository, oid, &info, 0))
+			/* Missing; assume it is a promisor object */
+			continue;
+		if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
+			continue;
+
+		if (!cmd.args.nr) {
+			base_name = mkpathdup(
+				"%s/pack/pack",
+				repo_get_object_directory(the_repository));
+			strvec_push(&cmd.args, "pack-objects");
+			strvec_push(&cmd.args,
+				    "--exclude-promisor-objects-best-effort");
+			strvec_push(&cmd.args, base_name);
+			cmd.git_cmd = 1;
+			cmd.in = -1;
+			cmd.out = -1;
+			if (start_command(&cmd))
+				die(_("could not start pack-objects to repack local links"));
+		}
+
+		if (write_in_full(cmd.in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+		    write_in_full(cmd.in, "\n", 1) < 0)
+			die(_("failed to feed local object to pack-objects"));
+	}
+
+	if (!cmd.args.nr)
+		return;
+
+	close(cmd.in);
+
+	out = xfdopen(cmd.out, "r");
+	while (strbuf_getline_lf(&line, out) != EOF) {
+		unsigned char binary[GIT_MAX_RAWSZ];
+		if (line.len != the_hash_algo->hexsz ||
+		    !hex_to_bytes(binary, line.buf, line.len))
+			die(_("index-pack: Expecting full hex object ID lines only from pack-objects."));
+
+		/*
+		 * pack-objects creates the .pack and .idx files, but not the
+		 * .promisor file. Create the .promisor file, which is empty.
+		 */
+		write_special_file("promisor", "", NULL, binary, NULL);
+	}
+
+	fclose(out);
+	if (finish_command(&cmd))
+		die(_("could not finish pack-objects to repack local links"));
+	strbuf_release(&line);
+	free(base_name);
+}
+
+int cmd_index_pack(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	int i, fix_thin_pack = 0, verify = 0, stat_only = 0, rev_index;
+	const char *curr_index;
+	char *curr_rev_index = NULL;
+	const char *index_name = NULL, *pack_name = NULL, *rev_index_name = NULL;
+	const char *keep_msg = NULL;
+	const char *promisor_msg = NULL;
+	struct strbuf index_name_buf = STRBUF_INIT;
+	struct strbuf rev_index_name_buf = STRBUF_INIT;
+	struct pack_idx_entry **idx_objects;
+	struct pack_idx_option opts;
+	unsigned char pack_hash[GIT_MAX_RAWSZ];
+	unsigned foreign_nr = 1;	/* zero is a "good" value, assume bad */
+	int report_end_of_input = 0;
+	int hash_algo = 0;
+
+	/*
+	 * index-pack never needs to fetch missing objects except when
+	 * REF_DELTA bases are missing (which are explicitly handled). It only
+	 * accesses the repo to do hash collision checks and to check which
+	 * REF_DELTA bases need to be fetched.
+	 */
+	fetch_if_missing = 0;
+
+	show_usage_if_asked(argc, argv, index_pack_usage);
+
+	disable_replace_refs();
+	fsck_options.walk = mark_link;
+
+	reset_pack_idx_option(&opts);
+	opts.flags |= WRITE_REV;
+	git_config(git_index_pack_config, &opts);
+	if (prefix && chdir(prefix))
+		die(_("Cannot come back to cwd"));
+
+	if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+		rev_index = 0;
+	else
+		rev_index = !!(opts.flags & (WRITE_REV_VERIFY | WRITE_REV));
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (*arg == '-') {
+			if (!strcmp(arg, "--stdin")) {
+				from_stdin = 1;
+			} else if (!strcmp(arg, "--fix-thin")) {
+				fix_thin_pack = 1;
+			} else if (skip_to_optional_arg(arg, "--strict", &arg)) {
+				strict = 1;
+				do_fsck_object = 1;
+				fsck_set_msg_types(&fsck_options, arg);
+			} else if (!strcmp(arg, "--check-self-contained-and-connected")) {
+				strict = 1;
+				check_self_contained_and_connected = 1;
+			} else if (skip_to_optional_arg(arg, "--fsck-objects", &arg)) {
+				do_fsck_object = 1;
+				fsck_set_msg_types(&fsck_options, arg);
+			} else if (!strcmp(arg, "--verify")) {
+				verify = 1;
+			} else if (!strcmp(arg, "--verify-stat")) {
+				verify = 1;
+				show_stat = 1;
+			} else if (!strcmp(arg, "--verify-stat-only")) {
+				verify = 1;
+				show_stat = 1;
+				stat_only = 1;
+			} else if (skip_to_optional_arg(arg, "--keep", &keep_msg)) {
+				; /* nothing to do */
+			} else if (skip_to_optional_arg(arg, "--promisor", &promisor_msg)) {
+				record_outgoing_links = 1;
+			} else if (starts_with(arg, "--threads=")) {
+				char *end;
+				nr_threads = strtoul(arg+10, &end, 0);
+				if (!arg[10] || *end || nr_threads < 0)
+					usage(index_pack_usage);
+				if (!HAVE_THREADS && nr_threads != 1) {
+					warning(_("no threads support, ignoring %s"), arg);
+					nr_threads = 1;
+				}
+			} else if (skip_prefix(arg, "--pack_header=", &arg)) {
+				if (parse_pack_header_option(arg,
+							     input_buffer,
+							     &input_len) < 0)
+					die(_("bad --pack_header: %s"), arg);
+			} else if (!strcmp(arg, "-v")) {
+				verbose = 1;
+			} else if (!strcmp(arg, "--progress-title")) {
+				if (progress_title || (i+1) >= argc)
+					usage(index_pack_usage);
+				progress_title = argv[++i];
+			} else if (!strcmp(arg, "--show-resolving-progress")) {
+				show_resolving_progress = 1;
+			} else if (!strcmp(arg, "--report-end-of-input")) {
+				report_end_of_input = 1;
+			} else if (!strcmp(arg, "-o")) {
+				if (index_name || (i+1) >= argc)
+					usage(index_pack_usage);
+				index_name = argv[++i];
+			} else if (starts_with(arg, "--index-version=")) {
+				char *c;
+				opts.version = strtoul(arg + 16, &c, 10);
+				if (opts.version > 2)
+					die(_("bad %s"), arg);
+				if (*c == ',')
+					opts.off32_limit = strtoul(c+1, &c, 0);
+				if (*c || opts.off32_limit & 0x80000000)
+					die(_("bad %s"), arg);
+			} else if (skip_prefix(arg, "--max-input-size=", &arg)) {
+				max_input_size = strtoumax(arg, NULL, 10);
+			} else if (skip_prefix(arg, "--object-format=", &arg)) {
+				hash_algo = hash_algo_by_name(arg);
+				if (hash_algo == GIT_HASH_UNKNOWN)
+					die(_("unknown hash algorithm '%s'"), arg);
+				repo_set_hash_algo(the_repository, hash_algo);
+			} else if (!strcmp(arg, "--rev-index")) {
+				rev_index = 1;
+			} else if (!strcmp(arg, "--no-rev-index")) {
+				rev_index = 0;
+			} else
+				usage(index_pack_usage);
+			continue;
+		}
+
+		if (pack_name)
+			usage(index_pack_usage);
+		pack_name = arg;
+	}
+
+	if (!pack_name && !from_stdin)
+		usage(index_pack_usage);
+	if (fix_thin_pack && !from_stdin)
+		die(_("the option '%s' requires '%s'"), "--fix-thin", "--stdin");
+	if (promisor_msg && pack_name)
+		die(_("--promisor cannot be used with a pack name"));
+	if (from_stdin && !startup_info->have_repository)
+		die(_("--stdin requires a git repository"));
+	if (from_stdin && hash_algo)
+		die(_("options '%s' and '%s' cannot be used together"), "--object-format", "--stdin");
+	if (!index_name && pack_name)
+		index_name = derive_filename(pack_name, "pack", "idx", &index_name_buf);
+
+	/*
+	 * Packfiles and indices do not carry enough information to be able to
+	 * identify their object hash. So when we are neither in a repository
+	 * nor has the user told us which object hash to use we have no other
+	 * choice but to guess the object hash.
+	 */
+	if (!the_repository->hash_algo)
+		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
+	opts.flags &= ~(WRITE_REV | WRITE_REV_VERIFY);
+	if (rev_index) {
+		opts.flags |= verify ? WRITE_REV_VERIFY : WRITE_REV;
+		if (index_name)
+			rev_index_name = derive_filename(index_name,
+							 "idx", "rev",
+							 &rev_index_name_buf);
+	}
+
+	if (verify) {
+		if (!index_name)
+			die(_("--verify with no packfile name given"));
+		read_idx_option(&opts, index_name);
+		opts.flags |= WRITE_IDX_VERIFY | WRITE_IDX_STRICT;
+	}
+	if (strict)
+		opts.flags |= WRITE_IDX_STRICT;
+
+	if (HAVE_THREADS && !nr_threads) {
+		nr_threads = online_cpus();
+		/*
+		 * Experiments show that going above 20 threads doesn't help,
+		 * no matter how many cores you have. Below that, we tend to
+		 * max at half the number of online_cpus(), presumably because
+		 * half of those are hyperthreads rather than full cores. We'll
+		 * never reduce the level below "3", though, to match a
+		 * historical value that nobody complained about.
+		 */
+		if (nr_threads < 4)
+			; /* too few cores to consider capping */
+		else if (nr_threads < 6)
+			nr_threads = 3; /* historic cap */
+		else if (nr_threads < 40)
+			nr_threads /= 2;
+		else
+			nr_threads = 20; /* hard cap */
+	}
+
+	curr_pack = open_pack_file(pack_name);
+	parse_pack_header();
+	CALLOC_ARRAY(objects, st_add(nr_objects, 1));
+	if (show_stat)
+		CALLOC_ARRAY(obj_stat, st_add(nr_objects, 1));
+	CALLOC_ARRAY(ofs_deltas, nr_objects);
+	parse_pack_objects(pack_hash);
+	if (report_end_of_input)
+		write_in_full(2, "\0", 1);
+	resolve_deltas(&opts);
+	conclude_pack(fix_thin_pack, curr_pack, pack_hash);
+	free(ofs_deltas);
+	free(ref_deltas);
+	if (strict)
+		foreign_nr = check_objects();
+
+	if (show_stat)
+		show_pack_info(stat_only);
+
+	ALLOC_ARRAY(idx_objects, nr_objects);
+	for (i = 0; i < nr_objects; i++)
+		idx_objects[i] = &objects[i].idx;
+	curr_index = write_idx_file(index_name, idx_objects, nr_objects, &opts, pack_hash);
+	if (rev_index)
+		curr_rev_index = write_rev_file(rev_index_name, idx_objects,
+						nr_objects, pack_hash,
+						opts.flags);
+	free(idx_objects);
+
+	if (!verify)
+		final(pack_name, curr_pack,
+		      index_name, curr_index,
+		      rev_index_name, curr_rev_index,
+		      keep_msg, promisor_msg,
+		      pack_hash);
+	else
+		close(input_fd);
+
+	if (do_fsck_object && fsck_finish(&fsck_options))
+		die(_("fsck error in pack objects"));
+
+	free(opts.anomaly);
+	free(objects);
+	strbuf_release(&index_name_buf);
+	strbuf_release(&rev_index_name_buf);
+	if (!pack_name)
+		free((void *) curr_pack);
+	if (!index_name)
+		free((void *) curr_index);
+	free(curr_rev_index);
+
+	repack_local_links();
+
+	/*
+	 * Let the caller know this pack is not self contained
+	 */
+	if (check_self_contained_and_connected && foreign_nr)
+		return 1;
+
+	return 0;
+}
diff --git a/builtin/init-db.c b/builtin/init-db.c
new file mode 100644
index 0000000000..096f96b9c4
--- /dev/null
+++ b/builtin/init-db.c
@@ -0,0 +1,260 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-file.h"
+#include "parse-options.h"
+#include "path.h"
+#include "refs.h"
+#include "setup.h"
+#include "strbuf.h"
+
+static int guess_repository_type(const char *git_dir)
+{
+	const char *slash;
+	char *cwd;
+	int cwd_is_git_dir;
+
+	/*
+	 * "GIT_DIR=. git init" is always bare.
+	 * "GIT_DIR=`pwd` git init" too.
+	 */
+	if (!strcmp(".", git_dir))
+		return 1;
+	cwd = xgetcwd();
+	cwd_is_git_dir = !strcmp(git_dir, cwd);
+	free(cwd);
+	if (cwd_is_git_dir)
+		return 1;
+	/*
+	 * "GIT_DIR=.git or GIT_DIR=something/.git is usually not.
+	 */
+	if (!strcmp(git_dir, ".git"))
+		return 0;
+	slash = strrchr(git_dir, '/');
+	if (slash && !strcmp(slash, "/.git"))
+		return 0;
+
+	/*
+	 * Otherwise it is often bare.  At this point
+	 * we are just guessing.
+	 */
+	return 1;
+}
+
+static int shared_callback(const struct option *opt, const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+	*((int *) opt->value) = (arg) ? git_config_perm("arg", arg) : PERM_GROUP;
+	return 0;
+}
+
+static const char *const init_db_usage[] = {
+	N_("git init [-q | --quiet] [--bare] [--template=<template-directory>]\n"
+	   "         [--separate-git-dir <git-dir>] [--object-format=<format>]\n"
+	   "         [--ref-format=<format>]\n"
+	   "         [-b <branch-name> | --initial-branch=<branch-name>]\n"
+	   "         [--shared[=<permissions>]] [<directory>]"),
+	NULL
+};
+
+/*
+ * If you want to, you can share the DB area with any number of branches.
+ * That has advantages: you can save space by sharing all the SHA1 objects.
+ * On the other hand, it might just make lookup slower and messier. You
+ * be the judge.  The default case is to have one DB per managed directory.
+ */
+int cmd_init_db(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
+{
+	char *git_dir;
+	const char *real_git_dir = NULL;
+	char *real_git_dir_to_free = NULL;
+	char *work_tree = NULL;
+	const char *template_dir = NULL;
+	char *template_dir_to_free = NULL;
+	unsigned int flags = 0;
+	const char *object_format = NULL;
+	const char *ref_format = NULL;
+	const char *initial_branch = NULL;
+	int hash_algo = GIT_HASH_UNKNOWN;
+	enum ref_storage_format ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN;
+	int init_shared_repository = -1;
+	const struct option init_db_options[] = {
+		OPT_STRING(0, "template", &template_dir, N_("template-directory"),
+				N_("directory from which templates will be used")),
+		OPT_SET_INT(0, "bare", &is_bare_repository_cfg,
+				N_("create a bare repository"), 1),
+		{ OPTION_CALLBACK, 0, "shared", &init_shared_repository,
+			N_("permissions"),
+			N_("specify that the git repository is to be shared amongst several users"),
+			PARSE_OPT_OPTARG | PARSE_OPT_NONEG, shared_callback, 0},
+		OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
+		OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
+			   N_("separate git dir from working tree")),
+		OPT_STRING('b', "initial-branch", &initial_branch, N_("name"),
+			   N_("override the name of the initial branch")),
+		OPT_STRING(0, "object-format", &object_format, N_("hash"),
+			   N_("specify the hash algorithm to use")),
+		OPT_STRING(0, "ref-format", &ref_format, N_("format"),
+			   N_("specify the reference format to use")),
+		OPT_END()
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
+
+	if (real_git_dir && is_bare_repository_cfg == 1)
+		die(_("options '%s' and '%s' cannot be used together"), "--separate-git-dir", "--bare");
+
+	if (real_git_dir && !is_absolute_path(real_git_dir))
+		real_git_dir = real_git_dir_to_free = real_pathdup(real_git_dir, 1);
+
+	if (template_dir && *template_dir && !is_absolute_path(template_dir))
+		template_dir = template_dir_to_free = absolute_pathdup(template_dir);
+
+	if (argc == 1) {
+		int mkdir_tried = 0;
+	retry:
+		if (chdir(argv[0]) < 0) {
+			if (!mkdir_tried) {
+				int saved;
+				/*
+				 * At this point we haven't read any configuration,
+				 * and we know shared_repository should always be 0;
+				 * but just in case we play safe.
+				 */
+				saved = get_shared_repository();
+				set_shared_repository(0);
+				switch (safe_create_leading_directories_const(argv[0])) {
+				case SCLD_OK:
+				case SCLD_PERMS:
+					break;
+				case SCLD_EXISTS:
+					errno = EEXIST;
+					/* fallthru */
+				default:
+					die_errno(_("cannot mkdir %s"), argv[0]);
+					break;
+				}
+				set_shared_repository(saved);
+				if (mkdir(argv[0], 0777) < 0)
+					die_errno(_("cannot mkdir %s"), argv[0]);
+				mkdir_tried = 1;
+				goto retry;
+			}
+			die_errno(_("cannot chdir to %s"), argv[0]);
+		}
+	} else if (0 < argc) {
+		usage(init_db_usage[0]);
+	}
+	if (is_bare_repository_cfg == 1) {
+		char *cwd = xgetcwd();
+		setenv(GIT_DIR_ENVIRONMENT, cwd, argc > 0);
+		free(cwd);
+	}
+
+	if (object_format) {
+		hash_algo = hash_algo_by_name(object_format);
+		if (hash_algo == GIT_HASH_UNKNOWN)
+			die(_("unknown hash algorithm '%s'"), object_format);
+	}
+
+	if (ref_format) {
+		ref_storage_format = ref_storage_format_by_name(ref_format);
+		if (ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown ref storage format '%s'"), ref_format);
+	}
+
+	if (init_shared_repository != -1)
+		set_shared_repository(init_shared_repository);
+
+	/*
+	 * GIT_WORK_TREE makes sense only in conjunction with GIT_DIR
+	 * without --bare.  Catch the error early.
+	 */
+	git_dir = xstrdup_or_null(getenv(GIT_DIR_ENVIRONMENT));
+	work_tree = xstrdup_or_null(getenv(GIT_WORK_TREE_ENVIRONMENT));
+	if ((!git_dir || is_bare_repository_cfg == 1) && work_tree)
+		die(_("%s (or --work-tree=<directory>) not allowed without "
+			  "specifying %s (or --git-dir=<directory>)"),
+		    GIT_WORK_TREE_ENVIRONMENT,
+		    GIT_DIR_ENVIRONMENT);
+
+	/*
+	 * Set up the default .git directory contents
+	 */
+	if (!git_dir)
+		git_dir = xstrdup(DEFAULT_GIT_DIR_ENVIRONMENT);
+
+	/*
+	 * When --separate-git-dir is used inside a linked worktree, take
+	 * care to ensure that the common .git/ directory is relocated, not
+	 * the worktree-specific .git/worktrees/<id>/ directory.
+	 */
+	if (real_git_dir) {
+		int err;
+		const char *p;
+		struct strbuf sb = STRBUF_INIT;
+
+		p = read_gitfile_gently(git_dir, &err);
+		if (p && get_common_dir(&sb, p)) {
+			struct strbuf mainwt = STRBUF_INIT;
+
+			strbuf_addbuf(&mainwt, &sb);
+			strbuf_strip_suffix(&mainwt, "/.git");
+			if (chdir(mainwt.buf) < 0)
+				die_errno(_("cannot chdir to %s"), mainwt.buf);
+			strbuf_release(&mainwt);
+			free(git_dir);
+			git_dir = strbuf_detach(&sb, NULL);
+		}
+		strbuf_release(&sb);
+	}
+
+	if (is_bare_repository_cfg < 0)
+		is_bare_repository_cfg = guess_repository_type(git_dir);
+
+	if (!is_bare_repository_cfg) {
+		const char *git_dir_parent = strrchr(git_dir, '/');
+		if (git_dir_parent) {
+			char *rel = xstrndup(git_dir, git_dir_parent - git_dir);
+			git_work_tree_cfg = real_pathdup(rel, 1);
+			free(rel);
+		}
+		if (!git_work_tree_cfg)
+			git_work_tree_cfg = xgetcwd();
+		if (work_tree)
+			set_git_work_tree(work_tree);
+		else
+			set_git_work_tree(git_work_tree_cfg);
+		if (access(repo_get_work_tree(the_repository), X_OK))
+			die_errno (_("Cannot access work tree '%s'"),
+				   repo_get_work_tree(the_repository));
+	}
+	else {
+		if (real_git_dir)
+			die(_("--separate-git-dir incompatible with bare repository"));
+		if (work_tree)
+			set_git_work_tree(work_tree);
+	}
+
+	flags |= INIT_DB_EXIST_OK;
+	ret = init_db(git_dir, real_git_dir, template_dir, hash_algo,
+		      ref_storage_format, initial_branch,
+		      init_shared_repository, flags);
+
+	free(template_dir_to_free);
+	free(real_git_dir_to_free);
+	free(work_tree);
+	free(git_dir);
+	return ret;
+}
diff --git a/builtin/interpret-trailers.c b/builtin/interpret-trailers.c
new file mode 100644
index 0000000000..44d8ccddc9
--- /dev/null
+++ b/builtin/interpret-trailers.c
@@ -0,0 +1,247 @@
+/*
+ * Builtin "git interpret-trailers"
+ *
+ * Copyright (c) 2013, 2014 Christian Couder <chriscool@xxxxxxxxxxxxx>
+ *
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "tempfile.h"
+#include "trailer.h"
+#include "config.h"
+
+static const char * const git_interpret_trailers_usage[] = {
+	N_("git interpret-trailers [--in-place] [--trim-empty]\n"
+	   "                       [(--trailer (<key>|<key-alias>)[(=|:)<value>])...]\n"
+	   "                       [--parse] [<file>...]"),
+	NULL
+};
+
+static enum trailer_where where;
+static enum trailer_if_exists if_exists;
+static enum trailer_if_missing if_missing;
+
+static int option_parse_where(const struct option *opt,
+			      const char *arg, int unset UNUSED)
+{
+	/* unset implies NULL arg, which is handled in our helper */
+	return trailer_set_where(opt->value, arg);
+}
+
+static int option_parse_if_exists(const struct option *opt,
+				  const char *arg, int unset UNUSED)
+{
+	/* unset implies NULL arg, which is handled in our helper */
+	return trailer_set_if_exists(opt->value, arg);
+}
+
+static int option_parse_if_missing(const struct option *opt,
+				   const char *arg, int unset UNUSED)
+{
+	/* unset implies NULL arg, which is handled in our helper */
+	return trailer_set_if_missing(opt->value, arg);
+}
+
+static void new_trailers_clear(struct list_head *trailers)
+{
+	struct list_head *pos, *tmp;
+	struct new_trailer_item *item;
+
+	list_for_each_safe(pos, tmp, trailers) {
+		item = list_entry(pos, struct new_trailer_item, list);
+		list_del(pos);
+		free(item);
+	}
+}
+
+static int option_parse_trailer(const struct option *opt,
+				   const char *arg, int unset)
+{
+	struct list_head *trailers = opt->value;
+	struct new_trailer_item *item;
+
+	if (unset) {
+		new_trailers_clear(trailers);
+		return 0;
+	}
+
+	if (!arg)
+		return -1;
+
+	item = xmalloc(sizeof(*item));
+	item->text = arg;
+	item->where = where;
+	item->if_exists = if_exists;
+	item->if_missing = if_missing;
+	list_add_tail(&item->list, trailers);
+	return 0;
+}
+
+static int parse_opt_parse(const struct option *opt, const char *arg,
+			   int unset)
+{
+	struct process_trailer_options *v = opt->value;
+	v->only_trailers = 1;
+	v->only_input = 1;
+	v->unfold = 1;
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	return 0;
+}
+
+static struct tempfile *trailers_tempfile;
+
+static FILE *create_in_place_tempfile(const char *file)
+{
+	struct stat st;
+	struct strbuf filename_template = STRBUF_INIT;
+	const char *tail;
+	FILE *outfile;
+
+	if (stat(file, &st))
+		die_errno(_("could not stat %s"), file);
+	if (!S_ISREG(st.st_mode))
+		die(_("file %s is not a regular file"), file);
+	if (!(st.st_mode & S_IWUSR))
+		die(_("file %s is not writable by user"), file);
+
+	/* Create temporary file in the same directory as the original */
+	tail = strrchr(file, '/');
+	if (tail)
+		strbuf_add(&filename_template, file, tail - file + 1);
+	strbuf_addstr(&filename_template, "git-interpret-trailers-XXXXXX");
+
+	trailers_tempfile = xmks_tempfile_m(filename_template.buf, st.st_mode);
+	strbuf_release(&filename_template);
+	outfile = fdopen_tempfile(trailers_tempfile, "w");
+	if (!outfile)
+		die_errno(_("could not open temporary file"));
+
+	return outfile;
+}
+
+static void read_input_file(struct strbuf *sb, const char *file)
+{
+	if (file) {
+		if (strbuf_read_file(sb, file, 0) < 0)
+			die_errno(_("could not read input file '%s'"), file);
+	} else {
+		if (strbuf_read(sb, fileno(stdin), 0) < 0)
+			die_errno(_("could not read from stdin"));
+	}
+	strbuf_complete_line(sb);
+}
+
+static void interpret_trailers(const struct process_trailer_options *opts,
+			       struct list_head *new_trailer_head,
+			       const char *file)
+{
+	LIST_HEAD(head);
+	struct strbuf sb = STRBUF_INIT;
+	struct strbuf trailer_block_sb = STRBUF_INIT;
+	struct trailer_block *trailer_block;
+	FILE *outfile = stdout;
+
+	trailer_config_init();
+
+	read_input_file(&sb, file);
+
+	if (opts->in_place)
+		outfile = create_in_place_tempfile(file);
+
+	trailer_block = parse_trailers(opts, sb.buf, &head);
+
+	/* Print the lines before the trailer block */
+	if (!opts->only_trailers)
+		fwrite(sb.buf, 1, trailer_block_start(trailer_block), outfile);
+
+	if (!opts->only_trailers && !blank_line_before_trailer_block(trailer_block))
+		fprintf(outfile, "\n");
+
+
+	if (!opts->only_input) {
+		LIST_HEAD(config_head);
+		LIST_HEAD(arg_head);
+		parse_trailers_from_config(&config_head);
+		parse_trailers_from_command_line_args(&arg_head, new_trailer_head);
+		list_splice(&config_head, &arg_head);
+		process_trailers_lists(&head, &arg_head);
+	}
+
+	/* Print trailer block. */
+	format_trailers(opts, &head, &trailer_block_sb);
+	free_trailers(&head);
+	fwrite(trailer_block_sb.buf, 1, trailer_block_sb.len, outfile);
+	strbuf_release(&trailer_block_sb);
+
+	/* Print the lines after the trailer block as is. */
+	if (!opts->only_trailers)
+		fwrite(sb.buf + trailer_block_end(trailer_block), 1,
+		       sb.len - trailer_block_end(trailer_block), outfile);
+	trailer_block_release(trailer_block);
+
+	if (opts->in_place)
+		if (rename_tempfile(&trailers_tempfile, file))
+			die_errno(_("could not rename temporary file to %s"), file);
+
+	strbuf_release(&sb);
+}
+
+int cmd_interpret_trailers(int argc,
+			   const char **argv,
+			   const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	struct process_trailer_options opts = PROCESS_TRAILER_OPTIONS_INIT;
+	LIST_HEAD(trailers);
+
+	struct option options[] = {
+		OPT_BOOL(0, "in-place", &opts.in_place, N_("edit files in place")),
+		OPT_BOOL(0, "trim-empty", &opts.trim_empty, N_("trim empty trailers")),
+
+		OPT_CALLBACK(0, "where", &where, N_("placement"),
+			     N_("where to place the new trailer"), option_parse_where),
+		OPT_CALLBACK(0, "if-exists", &if_exists, N_("action"),
+			     N_("action if trailer already exists"), option_parse_if_exists),
+		OPT_CALLBACK(0, "if-missing", &if_missing, N_("action"),
+			     N_("action if trailer is missing"), option_parse_if_missing),
+
+		OPT_BOOL(0, "only-trailers", &opts.only_trailers, N_("output only the trailers")),
+		OPT_BOOL(0, "only-input", &opts.only_input, N_("do not apply trailer.* configuration variables")),
+		OPT_BOOL(0, "unfold", &opts.unfold, N_("reformat multiline trailer values as single-line values")),
+		OPT_CALLBACK_F(0, "parse", &opts, NULL, N_("alias for --only-trailers --only-input --unfold"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_parse),
+		OPT_BOOL(0, "no-divider", &opts.no_divider, N_("do not treat \"---\" as the end of input")),
+		OPT_CALLBACK(0, "trailer", &trailers, N_("trailer"),
+				N_("trailer(s) to add"), option_parse_trailer),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_interpret_trailers_usage, 0);
+
+	if (opts.only_input && !list_empty(&trailers))
+		usage_msg_opt(
+			_("--trailer with --only-input does not make sense"),
+			git_interpret_trailers_usage,
+			options);
+
+	if (argc) {
+		int i;
+		for (i = 0; i < argc; i++)
+			interpret_trailers(&opts, &trailers, argv[i]);
+	} else {
+		if (opts.in_place)
+			die(_("no input file given for in-place editing"));
+		interpret_trailers(&opts, &trailers, NULL);
+	}
+
+	new_trailers_clear(&trailers);
+
+	return 0;
+}
diff --git a/builtin/log.c b/builtin/log.c
new file mode 100644
index 0000000000..e41f88945e
--- /dev/null
+++ b/builtin/log.c
@@ -0,0 +1,2721 @@
+/*
+ * Builtin "git log" and related commands (show, whatchanged)
+ *
+ * (C) Copyright 2006 Linus Torvalds
+ *		 2006 Junio Hamano
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "refs.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "pager.h"
+#include "color.h"
+#include "commit.h"
+#include "diff.h"
+#include "diff-merges.h"
+#include "revision.h"
+#include "log-tree.h"
+#include "builtin.h"
+#include "oid-array.h"
+#include "tag.h"
+#include "reflog-walk.h"
+#include "patch-ids.h"
+#include "shortlog.h"
+#include "remote.h"
+#include "string-list.h"
+#include "parse-options.h"
+#include "line-log.h"
+#include "branch.h"
+#include "streaming.h"
+#include "version.h"
+#include "mailmap.h"
+#include "progress.h"
+#include "commit-slab.h"
+
+#include "commit-reach.h"
+#include "range-diff.h"
+#include "tmp-objdir.h"
+#include "tree.h"
+#include "write-or-die.h"
+
+#define MAIL_DEFAULT_WRAP 72
+#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
+#define FORMAT_PATCH_NAME_MAX_DEFAULT 64
+
+static unsigned int force_in_body_from;
+static int stdout_mboxrd;
+static int format_no_prefix;
+
+static const char * const builtin_log_usage[] = {
+	N_("git log [<options>] [<revision-range>] [[--] <path>...]"),
+	N_("git show [<options>] <object>..."),
+	NULL
+};
+
+struct line_opt_callback_data {
+	struct rev_info *rev;
+	const char *prefix;
+	struct string_list args;
+};
+
+static int session_is_interactive(void)
+{
+	return isatty(1) || pager_in_use();
+}
+
+static int auto_decoration_style(void)
+{
+	return session_is_interactive() ? DECORATE_SHORT_REFS : 0;
+}
+
+static int parse_decoration_style(const char *value)
+{
+	switch (git_parse_maybe_bool(value)) {
+	case 1:
+		return DECORATE_SHORT_REFS;
+	case 0:
+		return 0;
+	default:
+		break;
+	}
+	if (!strcmp(value, "full"))
+		return DECORATE_FULL_REFS;
+	else if (!strcmp(value, "short"))
+		return DECORATE_SHORT_REFS;
+	else if (!strcmp(value, "auto"))
+		return auto_decoration_style();
+	/*
+	 * Please update _git_log() in git-completion.bash when you
+	 * add new decoration styles.
+	 */
+	return -1;
+}
+
+struct log_config {
+	int default_abbrev_commit;
+	int default_show_root;
+	int default_follow;
+	int default_show_signature;
+	int default_encode_email_headers;
+	int decoration_style;
+	int decoration_given;
+	int use_mailmap_config;
+	char *fmt_patch_subject_prefix;
+	int fmt_patch_name_max;
+	char *fmt_pretty;
+	char *default_date_mode;
+};
+
+static void log_config_init(struct log_config *cfg)
+{
+	memset(cfg, 0, sizeof(*cfg));
+	cfg->default_show_root = 1;
+	cfg->default_encode_email_headers = 1;
+	cfg->use_mailmap_config = 1;
+	cfg->fmt_patch_subject_prefix = xstrdup("PATCH");
+	cfg->fmt_patch_name_max = FORMAT_PATCH_NAME_MAX_DEFAULT;
+	cfg->decoration_style = auto_decoration_style();
+}
+
+static void log_config_release(struct log_config *cfg)
+{
+	free(cfg->default_date_mode);
+	free(cfg->fmt_pretty);
+	free(cfg->fmt_patch_subject_prefix);
+}
+
+static int use_default_decoration_filter = 1;
+static struct string_list decorate_refs_exclude = STRING_LIST_INIT_NODUP;
+static struct string_list decorate_refs_exclude_config = STRING_LIST_INIT_NODUP;
+static struct string_list decorate_refs_include = STRING_LIST_INIT_NODUP;
+
+static int clear_decorations_callback(const struct option *opt UNUSED,
+				      const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	string_list_clear(&decorate_refs_include, 0);
+	string_list_clear(&decorate_refs_exclude, 0);
+	use_default_decoration_filter = 0;
+	return 0;
+}
+
+static int decorate_callback(const struct option *opt, const char *arg,
+			     int unset)
+{
+	struct log_config *cfg = opt->value;
+
+	if (unset)
+		cfg->decoration_style = 0;
+	else if (arg)
+		cfg->decoration_style = parse_decoration_style(arg);
+	else
+		cfg->decoration_style = DECORATE_SHORT_REFS;
+
+	if (cfg->decoration_style < 0)
+		die(_("invalid --decorate option: %s"), arg);
+
+	cfg->decoration_given = 1;
+
+	return 0;
+}
+
+static int log_line_range_callback(const struct option *option, const char *arg, int unset)
+{
+	struct line_opt_callback_data *data = option->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (!arg)
+		return -1;
+
+	data->rev->line_level_traverse = 1;
+	string_list_append(&data->args, arg);
+
+	return 0;
+}
+
+static void cmd_log_init_defaults(struct rev_info *rev,
+				  struct log_config *cfg)
+{
+	if (cfg->fmt_pretty)
+		get_commit_format(cfg->fmt_pretty, rev);
+	if (cfg->default_follow)
+		rev->diffopt.flags.default_follow_renames = 1;
+	rev->verbose_header = 1;
+	init_diffstat_widths(&rev->diffopt);
+	rev->diffopt.flags.recursive = 1;
+	rev->diffopt.flags.allow_textconv = 1;
+	rev->abbrev_commit = cfg->default_abbrev_commit;
+	rev->show_root_diff = cfg->default_show_root;
+	rev->subject_prefix = cfg->fmt_patch_subject_prefix;
+	rev->patch_name_max = cfg->fmt_patch_name_max;
+	rev->show_signature = cfg->default_show_signature;
+	rev->encode_email_headers = cfg->default_encode_email_headers;
+
+	if (cfg->default_date_mode)
+		parse_date_format(cfg->default_date_mode, &rev->date_mode);
+}
+
+static void set_default_decoration_filter(struct decoration_filter *decoration_filter)
+{
+	char *value = NULL;
+	struct string_list *include = decoration_filter->include_ref_pattern;
+	const struct string_list *config_exclude;
+
+	if (!git_config_get_string_multi("log.excludeDecoration",
+					 &config_exclude)) {
+		struct string_list_item *item;
+		for_each_string_list_item(item, config_exclude)
+			string_list_append(decoration_filter->exclude_ref_config_pattern,
+					   item->string);
+	}
+
+	/*
+	 * By default, decorate_all is disabled. Enable it if
+	 * log.initialDecorationSet=all. Don't ever disable it by config,
+	 * since the command-line takes precedent.
+	 */
+	if (use_default_decoration_filter &&
+	    !git_config_get_string("log.initialdecorationset", &value) &&
+	    !strcmp("all", value))
+		use_default_decoration_filter = 0;
+	free(value);
+
+	if (!use_default_decoration_filter ||
+	    decoration_filter->exclude_ref_pattern->nr ||
+	    decoration_filter->include_ref_pattern->nr ||
+	    decoration_filter->exclude_ref_config_pattern->nr)
+		return;
+
+	/*
+	 * No command-line or config options were given, so
+	 * populate with sensible defaults.
+	 */
+	for (size_t i = 0; i < ARRAY_SIZE(ref_namespace); i++) {
+		if (!ref_namespace[i].decoration)
+			continue;
+
+		string_list_append(include, ref_namespace[i].ref);
+	}
+}
+
+static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
+			 struct rev_info *rev, struct setup_revision_opt *opt,
+			 struct log_config *cfg)
+{
+	struct userformat_want w;
+	int quiet = 0, source = 0, mailmap;
+	static struct line_opt_callback_data line_cb = {NULL, NULL, STRING_LIST_INIT_DUP};
+	struct decoration_filter decoration_filter = {
+		.exclude_ref_pattern = &decorate_refs_exclude,
+		.include_ref_pattern = &decorate_refs_include,
+		.exclude_ref_config_pattern = &decorate_refs_exclude_config,
+	};
+	static struct revision_sources revision_sources;
+
+	const struct option builtin_log_options[] = {
+		OPT__QUIET(&quiet, N_("suppress diff output")),
+		OPT_BOOL(0, "source", &source, N_("show source")),
+		OPT_BOOL(0, "use-mailmap", &mailmap, N_("use mail map file")),
+		OPT_ALIAS(0, "mailmap", "use-mailmap"),
+		OPT_CALLBACK_F(0, "clear-decorations", NULL, NULL,
+			       N_("clear all previously-defined decoration filters"),
+			       PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			       clear_decorations_callback),
+		OPT_STRING_LIST(0, "decorate-refs", &decorate_refs_include,
+				N_("pattern"), N_("only decorate refs that match <pattern>")),
+		OPT_STRING_LIST(0, "decorate-refs-exclude", &decorate_refs_exclude,
+				N_("pattern"), N_("do not decorate refs that match <pattern>")),
+		OPT_CALLBACK_F(0, "decorate", cfg, NULL, N_("decorate options"),
+			       PARSE_OPT_OPTARG, decorate_callback),
+		OPT_CALLBACK('L', NULL, &line_cb, "range:file",
+			     N_("trace the evolution of line range <start>,<end> or function :<funcname> in <file>"),
+			     log_line_range_callback),
+		OPT_END()
+	};
+
+	line_cb.rev = rev;
+	line_cb.prefix = prefix;
+
+	mailmap = cfg->use_mailmap_config;
+	argc = parse_options(argc, argv, prefix,
+			     builtin_log_options, builtin_log_usage,
+			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	if (quiet)
+		rev->diffopt.output_format |= DIFF_FORMAT_NO_OUTPUT;
+	argc = setup_revisions(argc, argv, rev, opt);
+
+	/* Any arguments at this point are not recognized */
+	if (argc > 1)
+		die(_("unrecognized argument: %s"), argv[1]);
+
+	if (rev->line_level_traverse && rev->prune_data.nr)
+		die(_("-L<range>:<file> cannot be used with pathspec"));
+
+	memset(&w, 0, sizeof(w));
+	userformat_find_requirements(NULL, &w);
+
+	if (!rev->show_notes_given && (!rev->pretty_given || w.notes))
+		rev->show_notes = 1;
+	if (rev->show_notes)
+		load_display_notes(&rev->notes_opt);
+
+	if ((rev->diffopt.pickaxe_opts & DIFF_PICKAXE_KINDS_MASK) ||
+	    rev->diffopt.filter || rev->diffopt.flags.follow_renames)
+		rev->always_show_header = 0;
+
+	if (source || w.source) {
+		init_revision_sources(&revision_sources);
+		rev->sources = &revision_sources;
+	}
+
+	if (mailmap) {
+		rev->mailmap = xmalloc(sizeof(struct string_list));
+		string_list_init_nodup(rev->mailmap);
+		read_mailmap(rev->mailmap);
+	}
+
+	if (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {
+		/*
+		 * "log --pretty=raw" is special; ignore UI oriented
+		 * configuration variables such as decoration.
+		 */
+		if (!cfg->decoration_given)
+			cfg->decoration_style = 0;
+		if (!rev->abbrev_commit_given)
+			rev->abbrev_commit = 0;
+	}
+
+	if (rev->commit_format == CMIT_FMT_USERFORMAT) {
+		if (!w.decorate) {
+			/*
+			 * Disable decoration loading if the format will not
+			 * show them anyway.
+			 */
+			cfg->decoration_style = 0;
+		} else if (!cfg->decoration_style) {
+			/*
+			 * If we are going to show them, make sure we do load
+			 * them here, but taking care not to override a
+			 * specific style set by config or --decorate.
+			 */
+			cfg->decoration_style = DECORATE_SHORT_REFS;
+		}
+	}
+
+	if (cfg->decoration_style || rev->simplify_by_decoration) {
+		set_default_decoration_filter(&decoration_filter);
+
+		if (cfg->decoration_style)
+			rev->show_decorations = 1;
+
+		load_ref_decorations(&decoration_filter, cfg->decoration_style);
+	}
+
+	if (rev->line_level_traverse)
+		line_log_init(rev, line_cb.prefix, &line_cb.args);
+
+	setup_pager(the_repository);
+}
+
+static void cmd_log_init(int argc, const char **argv, const char *prefix,
+			 struct rev_info *rev, struct setup_revision_opt *opt,
+			 struct log_config *cfg)
+{
+	cmd_log_init_defaults(rev, cfg);
+	cmd_log_init_finish(argc, argv, prefix, rev, opt, cfg);
+}
+
+/*
+ * This gives a rough estimate for how many commits we
+ * will print out in the list.
+ */
+static int estimate_commit_count(struct commit_list *list)
+{
+	int n = 0;
+
+	while (list) {
+		struct commit *commit = list->item;
+		unsigned int flags = commit->object.flags;
+		list = list->next;
+		if (!(flags & (TREESAME | UNINTERESTING)))
+			n++;
+	}
+	return n;
+}
+
+static void show_early_header(struct rev_info *rev, const char *stage, int nr)
+{
+	if (rev->shown_one) {
+		rev->shown_one = 0;
+		if (rev->commit_format != CMIT_FMT_ONELINE)
+			putchar(rev->diffopt.line_termination);
+	}
+	fprintf(rev->diffopt.file, _("Final output: %d %s\n"), nr, stage);
+}
+
+static struct itimerval early_output_timer;
+
+static void log_show_early(struct rev_info *revs, struct commit_list *list)
+{
+	int i = revs->early_output;
+	int show_header = 1;
+	int no_free = revs->diffopt.no_free;
+
+	revs->diffopt.no_free = 0;
+	sort_in_topological_order(&list, revs->sort_order);
+	while (list && i) {
+		struct commit *commit = list->item;
+		switch (simplify_commit(revs, commit)) {
+		case commit_show:
+			if (show_header) {
+				int n = estimate_commit_count(list);
+				show_early_header(revs, "incomplete", n);
+				show_header = 0;
+			}
+			log_tree_commit(revs, commit);
+			i--;
+			break;
+		case commit_ignore:
+			break;
+		case commit_error:
+			revs->diffopt.no_free = no_free;
+			diff_free(&revs->diffopt);
+			return;
+		}
+		list = list->next;
+	}
+
+	/* Did we already get enough commits for the early output? */
+	if (!i) {
+		revs->diffopt.no_free = 0;
+		diff_free(&revs->diffopt);
+		return;
+	}
+
+	/*
+	 * ..if no, then repeat it twice a second until we
+	 * do.
+	 *
+	 * NOTE! We don't use "it_interval", because if the
+	 * reader isn't listening, we want our output to be
+	 * throttled by the writing, and not have the timer
+	 * trigger every second even if we're blocked on a
+	 * reader!
+	 */
+	early_output_timer.it_value.tv_sec = 0;
+	early_output_timer.it_value.tv_usec = 500000;
+	setitimer(ITIMER_REAL, &early_output_timer, NULL);
+}
+
+static void early_output(int signal UNUSED)
+{
+	show_early_output = log_show_early;
+}
+
+static void setup_early_output(void)
+{
+	struct sigaction sa;
+
+	/*
+	 * Set up the signal handler, minimally intrusively:
+	 * we only set a single volatile integer word (not
+	 * using sigatomic_t - trying to avoid unnecessary
+	 * system dependencies and headers), and using
+	 * SA_RESTART.
+	 */
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = early_output;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_RESTART;
+	sigaction(SIGALRM, &sa, NULL);
+
+	/*
+	 * If we can get the whole output in less than a
+	 * tenth of a second, don't even bother doing the
+	 * early-output thing..
+	 *
+	 * This is a one-time-only trigger.
+	 */
+	early_output_timer.it_value.tv_sec = 0;
+	early_output_timer.it_value.tv_usec = 100000;
+	setitimer(ITIMER_REAL, &early_output_timer, NULL);
+}
+
+static void finish_early_output(struct rev_info *rev)
+{
+	int n = estimate_commit_count(rev->commits);
+	signal(SIGALRM, SIG_IGN);
+	show_early_header(rev, "done", n);
+}
+
+static int cmd_log_walk_no_free(struct rev_info *rev)
+{
+	struct commit *commit;
+	int saved_nrl = 0;
+	int saved_dcctc = 0;
+	int result;
+
+	if (rev->early_output)
+		setup_early_output();
+
+	if (prepare_revision_walk(rev))
+		die(_("revision walk setup failed"));
+
+	if (rev->early_output)
+		finish_early_output(rev);
+
+	/*
+	 * For --check and --exit-code, the exit code is based on CHECK_FAILED
+	 * and HAS_CHANGES being accumulated in rev->diffopt, so be careful to
+	 * retain that state information if replacing rev->diffopt in this loop
+	 */
+	while ((commit = get_revision(rev)) != NULL) {
+		if (!log_tree_commit(rev, commit) && rev->max_count >= 0)
+			/*
+			 * We decremented max_count in get_revision,
+			 * but we didn't actually show the commit.
+			 */
+			rev->max_count++;
+		if (!rev->reflog_info && !rev->remerge_diff) {
+			/*
+			 * We may show a given commit multiple times when
+			 * walking the reflogs. Therefore we still need it.
+			 *
+			 * Likewise, we potentially still need the parents
+			 * of * already shown commits to determine merge
+			 * bases when showing remerge diffs.
+			 */
+			free_commit_buffer(the_repository->parsed_objects,
+					   commit);
+			free_commit_list(commit->parents);
+			commit->parents = NULL;
+		}
+		if (saved_nrl < rev->diffopt.needed_rename_limit)
+			saved_nrl = rev->diffopt.needed_rename_limit;
+		if (rev->diffopt.degraded_cc_to_c)
+			saved_dcctc = 1;
+	}
+	rev->diffopt.degraded_cc_to_c = saved_dcctc;
+	rev->diffopt.needed_rename_limit = saved_nrl;
+
+	result = diff_result_code(rev);
+	if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
+	    rev->diffopt.flags.check_failed) {
+		result = 02;
+	}
+	return result;
+}
+
+static int cmd_log_walk(struct rev_info *rev)
+{
+	int retval;
+
+	rev->diffopt.no_free = 1;
+	retval = cmd_log_walk_no_free(rev);
+	rev->diffopt.no_free = 0;
+	diff_free(&rev->diffopt);
+	return retval;
+}
+
+static int git_log_config(const char *var, const char *value,
+			  const struct config_context *ctx, void *cb)
+{
+	struct log_config *cfg = cb;
+	const char *slot_name;
+
+	if (!strcmp(var, "format.pretty")) {
+		FREE_AND_NULL(cfg->fmt_pretty);
+		return git_config_string(&cfg->fmt_pretty, var, value);
+	}
+	if (!strcmp(var, "format.subjectprefix")) {
+		FREE_AND_NULL(cfg->fmt_patch_subject_prefix);
+		return git_config_string(&cfg->fmt_patch_subject_prefix, var, value);
+	}
+	if (!strcmp(var, "format.filenamemaxlength")) {
+		cfg->fmt_patch_name_max = git_config_int(var, value, ctx->kvi);
+		return 0;
+	}
+	if (!strcmp(var, "format.encodeemailheaders")) {
+		cfg->default_encode_email_headers = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "log.abbrevcommit")) {
+		cfg->default_abbrev_commit = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "log.date")) {
+		FREE_AND_NULL(cfg->default_date_mode);
+		return git_config_string(&cfg->default_date_mode, var, value);
+	}
+	if (!strcmp(var, "log.decorate")) {
+		cfg->decoration_style = parse_decoration_style(value);
+		if (cfg->decoration_style < 0)
+			cfg->decoration_style = 0; /* maybe warn? */
+		return 0;
+	}
+	if (!strcmp(var, "log.diffmerges")) {
+		if (!value)
+			return config_error_nonbool(var);
+		return diff_merges_config(value);
+	}
+	if (!strcmp(var, "log.showroot")) {
+		cfg->default_show_root = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "log.follow")) {
+		cfg->default_follow = git_config_bool(var, value);
+		return 0;
+	}
+	if (skip_prefix(var, "color.decorate.", &slot_name))
+		return parse_decorate_color_config(var, slot_name, value);
+	if (!strcmp(var, "log.mailmap")) {
+		cfg->use_mailmap_config = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "log.showsignature")) {
+		cfg->default_show_signature = git_config_bool(var, value);
+		return 0;
+	}
+
+	return git_diff_ui_config(var, value, ctx, cb);
+}
+
+int cmd_whatchanged(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
+{
+	struct log_config cfg;
+	struct rev_info rev;
+	struct setup_revision_opt opt;
+	int ret;
+
+	log_config_init(&cfg);
+	init_diff_ui_defaults();
+	git_config(git_log_config, &cfg);
+
+	repo_init_revisions(the_repository, &rev, prefix);
+	git_config(grep_config, &rev.grep_filter);
+
+	rev.diff = 1;
+	rev.simplify_history = 0;
+	memset(&opt, 0, sizeof(opt));
+	opt.def = "HEAD";
+	opt.revarg_opt = REVARG_COMMITTISH;
+	cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
+	if (!rev.diffopt.output_format)
+		rev.diffopt.output_format = DIFF_FORMAT_RAW;
+
+	ret = cmd_log_walk(&rev);
+
+	release_revisions(&rev);
+	log_config_release(&cfg);
+	return ret;
+}
+
+static void show_tagger(const char *buf, struct rev_info *rev)
+{
+	struct strbuf out = STRBUF_INIT;
+	struct pretty_print_context pp = {0};
+
+	pp.fmt = rev->commit_format;
+	pp.date_mode = rev->date_mode;
+	pp_user_info(&pp, "Tagger", &out, buf, get_log_output_encoding());
+	fprintf(rev->diffopt.file, "%s", out.buf);
+	strbuf_release(&out);
+}
+
+static int show_blob_object(const struct object_id *oid, struct rev_info *rev, const char *obj_name)
+{
+	struct object_id oidc;
+	struct object_context obj_context = {0};
+	char *buf;
+	unsigned long size;
+
+	fflush(rev->diffopt.file);
+	if (!rev->diffopt.flags.textconv_set_via_cmdline ||
+	    !rev->diffopt.flags.allow_textconv)
+		return stream_blob_to_fd(1, oid, NULL, 0);
+
+	if (get_oid_with_context(the_repository, obj_name,
+				 GET_OID_RECORD_PATH,
+				 &oidc, &obj_context))
+		die(_("not a valid object name %s"), obj_name);
+	if (!obj_context.path ||
+	    !textconv_object(the_repository, obj_context.path,
+			     obj_context.mode, &oidc, 1, &buf, &size)) {
+		object_context_release(&obj_context);
+		return stream_blob_to_fd(1, oid, NULL, 0);
+	}
+
+	if (!buf)
+		die(_("git show %s: bad file"), obj_name);
+
+	write_or_die(1, buf, size);
+	object_context_release(&obj_context);
+	free(buf);
+	return 0;
+}
+
+static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
+{
+	unsigned long size;
+	enum object_type type;
+	char *buf = repo_read_object_file(the_repository, oid, &type, &size);
+	unsigned long offset = 0;
+
+	if (!buf)
+		return error(_("could not read object %s"), oid_to_hex(oid));
+
+	assert(type == OBJ_TAG);
+	while (offset < size && buf[offset] != '\n') {
+		unsigned long new_offset = offset + 1;
+		const char *ident;
+		while (new_offset < size && buf[new_offset++] != '\n')
+			; /* do nothing */
+		if (skip_prefix(buf + offset, "tagger ", &ident))
+			show_tagger(ident, rev);
+		offset = new_offset;
+	}
+
+	if (offset < size)
+		fwrite(buf + offset, size - offset, 1, rev->diffopt.file);
+	free(buf);
+	return 0;
+}
+
+static int show_tree_object(const struct object_id *oid UNUSED,
+			    struct strbuf *base UNUSED,
+			    const char *pathname, unsigned mode,
+			    void *context)
+{
+	FILE *file = context;
+	fprintf(file, "%s%s\n", pathname, S_ISDIR(mode) ? "/" : "");
+	return 0;
+}
+
+static void show_setup_revisions_tweak(struct rev_info *rev)
+{
+	if (rev->first_parent_only)
+		diff_merges_default_to_first_parent(rev);
+	else
+		diff_merges_default_to_dense_combined(rev);
+	if (!rev->diffopt.output_format)
+		rev->diffopt.output_format = DIFF_FORMAT_PATCH;
+}
+
+int cmd_show(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo UNUSED)
+{
+	struct log_config cfg;
+	struct rev_info rev;
+	unsigned int i;
+	struct setup_revision_opt opt;
+	struct pathspec match_all;
+	int ret = 0;
+
+	log_config_init(&cfg);
+	init_diff_ui_defaults();
+	git_config(git_log_config, &cfg);
+
+	if (the_repository->gitdir) {
+		prepare_repo_settings(the_repository);
+		the_repository->settings.command_requires_full_index = 0;
+	}
+
+	memset(&match_all, 0, sizeof(match_all));
+	repo_init_revisions(the_repository, &rev, prefix);
+	git_config(grep_config, &rev.grep_filter);
+
+	rev.diff = 1;
+	rev.always_show_header = 1;
+	rev.no_walk = 1;
+	rev.diffopt.stat_width = -1; 	/* Scale to real terminal size */
+
+	memset(&opt, 0, sizeof(opt));
+	opt.def = "HEAD";
+	opt.tweak = show_setup_revisions_tweak;
+	cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
+
+	if (!rev.no_walk) {
+		ret = cmd_log_walk(&rev);
+		release_revisions(&rev);
+		log_config_release(&cfg);
+		return ret;
+	}
+
+	rev.diffopt.no_free = 1;
+	for (i = 0; i < rev.pending.nr && !ret; i++) {
+		struct object *o = rev.pending.objects[i].item;
+		const char *name = rev.pending.objects[i].name;
+		switch (o->type) {
+		case OBJ_BLOB:
+			ret = show_blob_object(&o->oid, &rev, name);
+			break;
+		case OBJ_TAG: {
+			struct tag *t = (struct tag *)o;
+			struct object_id *oid = get_tagged_oid(t);
+
+			if (rev.shown_one)
+				putchar('\n');
+			fprintf(rev.diffopt.file, "%stag %s%s\n",
+					diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
+					t->tag,
+					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
+			ret = show_tag_object(&o->oid, &rev);
+			rev.shown_one = 1;
+			if (ret)
+				break;
+			o = parse_object(the_repository, oid);
+			if (!o)
+				ret = error(_("could not read object %s"),
+					    oid_to_hex(oid));
+			rev.pending.objects[i].item = o;
+			i--;
+			break;
+		}
+		case OBJ_TREE:
+			if (rev.shown_one)
+				putchar('\n');
+			fprintf(rev.diffopt.file, "%stree %s%s\n\n",
+					diff_get_color_opt(&rev.diffopt, DIFF_COMMIT),
+					name,
+					diff_get_color_opt(&rev.diffopt, DIFF_RESET));
+			read_tree(the_repository, (struct tree *)o,
+				  &match_all, show_tree_object,
+				  rev.diffopt.file);
+			rev.shown_one = 1;
+			break;
+		case OBJ_COMMIT:
+		{
+			struct object_array old;
+			struct object_array blank = OBJECT_ARRAY_INIT;
+
+			memcpy(&old, &rev.pending, sizeof(old));
+			memcpy(&rev.pending, &blank, sizeof(rev.pending));
+
+			add_object_array(o, name, &rev.pending);
+			ret = cmd_log_walk_no_free(&rev);
+
+			/*
+			 * No need for
+			 * object_array_clear(&pending). It was
+			 * cleared already in prepare_revision_walk()
+			 */
+			memcpy(&rev.pending, &old, sizeof(rev.pending));
+			break;
+		}
+		default:
+			ret = error(_("unknown type: %d"), o->type);
+		}
+	}
+
+	rev.diffopt.no_free = 0;
+	diff_free(&rev.diffopt);
+	release_revisions(&rev);
+	log_config_release(&cfg);
+
+	return ret;
+}
+
+/*
+ * This is equivalent to "git log -g --abbrev-commit --pretty=oneline"
+ */
+int cmd_log_reflog(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct log_config cfg;
+	struct rev_info rev;
+	struct setup_revision_opt opt;
+	int ret;
+
+	log_config_init(&cfg);
+	init_diff_ui_defaults();
+	git_config(git_log_config, &cfg);
+
+	repo_init_revisions(the_repository, &rev, prefix);
+	init_reflog_walk(&rev.reflog_info);
+	git_config(grep_config, &rev.grep_filter);
+
+	rev.verbose_header = 1;
+	memset(&opt, 0, sizeof(opt));
+	opt.def = "HEAD";
+	cmd_log_init_defaults(&rev, &cfg);
+	rev.abbrev_commit = 1;
+	rev.commit_format = CMIT_FMT_ONELINE;
+	rev.use_terminator = 1;
+	rev.always_show_header = 1;
+	cmd_log_init_finish(argc, argv, prefix, &rev, &opt, &cfg);
+
+	ret = cmd_log_walk(&rev);
+
+	release_revisions(&rev);
+	log_config_release(&cfg);
+	return ret;
+}
+
+static void log_setup_revisions_tweak(struct rev_info *rev)
+{
+	if (rev->diffopt.flags.default_follow_renames &&
+	    diff_check_follow_pathspec(&rev->prune_data, 0))
+		rev->diffopt.flags.follow_renames = 1;
+
+	if (rev->first_parent_only)
+		diff_merges_default_to_first_parent(rev);
+}
+
+int cmd_log(int argc,
+	    const char **argv,
+	    const char *prefix,
+	    struct repository *repo UNUSED)
+{
+	struct log_config cfg;
+	struct rev_info rev;
+	struct setup_revision_opt opt;
+	int ret;
+
+	log_config_init(&cfg);
+	init_diff_ui_defaults();
+	git_config(git_log_config, &cfg);
+
+	repo_init_revisions(the_repository, &rev, prefix);
+	git_config(grep_config, &rev.grep_filter);
+
+	rev.always_show_header = 1;
+	memset(&opt, 0, sizeof(opt));
+	opt.def = "HEAD";
+	opt.revarg_opt = REVARG_COMMITTISH;
+	opt.tweak = log_setup_revisions_tweak;
+	cmd_log_init(argc, argv, prefix, &rev, &opt, &cfg);
+
+	ret = cmd_log_walk(&rev);
+
+	release_revisions(&rev);
+	log_config_release(&cfg);
+	return ret;
+}
+
+/* format-patch */
+
+enum cover_setting {
+	COVER_UNSET,
+	COVER_OFF,
+	COVER_ON,
+	COVER_AUTO
+};
+
+enum thread_level {
+	THREAD_UNSET,
+	THREAD_SHALLOW,
+	THREAD_DEEP
+};
+
+enum cover_from_description {
+	COVER_FROM_NONE,
+	COVER_FROM_MESSAGE,
+	COVER_FROM_SUBJECT,
+	COVER_FROM_AUTO
+};
+
+enum auto_base_setting {
+	AUTO_BASE_NEVER,
+	AUTO_BASE_ALWAYS,
+	AUTO_BASE_WHEN_ABLE
+};
+
+struct format_config {
+	struct log_config log;
+	enum thread_level thread;
+	int do_signoff;
+	enum auto_base_setting auto_base;
+	char *base_commit;
+	char *from;
+	char *signature;
+	char *signature_file;
+	enum cover_setting config_cover_letter;
+	char *config_output_directory;
+	enum cover_from_description cover_from_description_mode;
+	int show_notes;
+	struct display_notes_opt notes_opt;
+	int numbered_cmdline_opt;
+	int numbered;
+	int auto_number;
+	char *default_attach;
+	struct string_list extra_hdr;
+	struct string_list extra_to;
+	struct string_list extra_cc;
+	int keep_subject;
+	int subject_prefix;
+	struct strbuf sprefix;
+	char *fmt_patch_suffix;
+};
+
+static void format_config_init(struct format_config *cfg)
+{
+	memset(cfg, 0, sizeof(*cfg));
+	log_config_init(&cfg->log);
+	cfg->cover_from_description_mode = COVER_FROM_MESSAGE;
+	cfg->auto_number = 1;
+	string_list_init_dup(&cfg->extra_hdr);
+	string_list_init_dup(&cfg->extra_to);
+	string_list_init_dup(&cfg->extra_cc);
+	strbuf_init(&cfg->sprefix, 0);
+	cfg->fmt_patch_suffix = xstrdup(".patch");
+}
+
+static void format_config_release(struct format_config *cfg)
+{
+	log_config_release(&cfg->log);
+	free(cfg->base_commit);
+	free(cfg->from);
+	free(cfg->signature);
+	free(cfg->signature_file);
+	free(cfg->config_output_directory);
+	free(cfg->default_attach);
+	string_list_clear(&cfg->extra_hdr, 0);
+	string_list_clear(&cfg->extra_to, 0);
+	string_list_clear(&cfg->extra_cc, 0);
+	strbuf_release(&cfg->sprefix);
+	free(cfg->fmt_patch_suffix);
+}
+
+static enum cover_from_description parse_cover_from_description(const char *arg)
+{
+	if (!arg || !strcmp(arg, "default"))
+		return COVER_FROM_MESSAGE;
+	else if (!strcmp(arg, "none"))
+		return COVER_FROM_NONE;
+	else if (!strcmp(arg, "message"))
+		return COVER_FROM_MESSAGE;
+	else if (!strcmp(arg, "subject"))
+		return COVER_FROM_SUBJECT;
+	else if (!strcmp(arg, "auto"))
+		return COVER_FROM_AUTO;
+	else
+		die(_("%s: invalid cover from description mode"), arg);
+}
+
+static void add_header(struct format_config *cfg, const char *value)
+{
+	struct string_list_item *item;
+	int len = strlen(value);
+	while (len && value[len - 1] == '\n')
+		len--;
+
+	if (!strncasecmp(value, "to: ", 4)) {
+		item = string_list_append(&cfg->extra_to, value + 4);
+		len -= 4;
+	} else if (!strncasecmp(value, "cc: ", 4)) {
+		item = string_list_append(&cfg->extra_cc, value + 4);
+		len -= 4;
+	} else {
+		item = string_list_append(&cfg->extra_hdr, value);
+	}
+
+	item->string[len] = '\0';
+}
+
+static int git_format_config(const char *var, const char *value,
+			     const struct config_context *ctx, void *cb)
+{
+	struct format_config *cfg = cb;
+
+	if (!strcmp(var, "format.headers")) {
+		if (!value)
+			die(_("format.headers without value"));
+		add_header(cfg, value);
+		return 0;
+	}
+	if (!strcmp(var, "format.suffix")) {
+		FREE_AND_NULL(cfg->fmt_patch_suffix);
+		return git_config_string(&cfg->fmt_patch_suffix, var, value);
+	}
+	if (!strcmp(var, "format.to")) {
+		if (!value)
+			return config_error_nonbool(var);
+		string_list_append(&cfg->extra_to, value);
+		return 0;
+	}
+	if (!strcmp(var, "format.cc")) {
+		if (!value)
+			return config_error_nonbool(var);
+		string_list_append(&cfg->extra_cc, value);
+		return 0;
+	}
+	if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff") ||
+	    !strcmp(var, "color.ui") || !strcmp(var, "diff.submodule")) {
+		return 0;
+	}
+	if (!strcmp(var, "format.numbered")) {
+		if (value && !strcasecmp(value, "auto")) {
+			cfg->auto_number = 1;
+			return 0;
+		}
+		cfg->numbered = git_config_bool(var, value);
+		cfg->auto_number = cfg->auto_number && cfg->numbered;
+		return 0;
+	}
+	if (!strcmp(var, "format.attach")) {
+		if (value && *value) {
+			FREE_AND_NULL(cfg->default_attach);
+			cfg->default_attach = xstrdup(value);
+		} else if (value && !*value) {
+			FREE_AND_NULL(cfg->default_attach);
+		} else {
+			FREE_AND_NULL(cfg->default_attach);
+			cfg->default_attach = xstrdup(git_version_string);
+		}
+		return 0;
+	}
+	if (!strcmp(var, "format.thread")) {
+		if (value && !strcasecmp(value, "deep")) {
+			cfg->thread = THREAD_DEEP;
+			return 0;
+		}
+		if (value && !strcasecmp(value, "shallow")) {
+			cfg->thread = THREAD_SHALLOW;
+			return 0;
+		}
+		cfg->thread = git_config_bool(var, value) ? THREAD_SHALLOW : THREAD_UNSET;
+		return 0;
+	}
+	if (!strcmp(var, "format.signoff")) {
+		cfg->do_signoff = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "format.signature")) {
+		FREE_AND_NULL(cfg->signature);
+		return git_config_string(&cfg->signature, var, value);
+	}
+	if (!strcmp(var, "format.signaturefile")) {
+		FREE_AND_NULL(cfg->signature_file);
+		return git_config_pathname(&cfg->signature_file, var, value);
+	}
+	if (!strcmp(var, "format.coverletter")) {
+		if (value && !strcasecmp(value, "auto")) {
+			cfg->config_cover_letter = COVER_AUTO;
+			return 0;
+		}
+		cfg->config_cover_letter = git_config_bool(var, value) ? COVER_ON : COVER_OFF;
+		return 0;
+	}
+	if (!strcmp(var, "format.outputdirectory")) {
+		FREE_AND_NULL(cfg->config_output_directory);
+		return git_config_string(&cfg->config_output_directory, var, value);
+	}
+	if (!strcmp(var, "format.useautobase")) {
+		if (value && !strcasecmp(value, "whenAble")) {
+			cfg->auto_base = AUTO_BASE_WHEN_ABLE;
+			return 0;
+		}
+		cfg->auto_base = git_config_bool(var, value) ? AUTO_BASE_ALWAYS : AUTO_BASE_NEVER;
+		return 0;
+	}
+	if (!strcmp(var, "format.from")) {
+		int b = git_parse_maybe_bool(value);
+		FREE_AND_NULL(cfg->from);
+		if (b < 0)
+			cfg->from = xstrdup(value);
+		else if (b)
+			cfg->from = xstrdup(git_committer_info(IDENT_NO_DATE));
+		return 0;
+	}
+	if (!strcmp(var, "format.forceinbodyfrom")) {
+		force_in_body_from = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "format.notes")) {
+		int b = git_parse_maybe_bool(value);
+		if (b < 0)
+			enable_ref_display_notes(&cfg->notes_opt, &cfg->show_notes, value);
+		else if (b)
+			enable_default_display_notes(&cfg->notes_opt, &cfg->show_notes);
+		else
+			disable_display_notes(&cfg->notes_opt, &cfg->show_notes);
+		return 0;
+	}
+	if (!strcmp(var, "format.coverfromdescription")) {
+		cfg->cover_from_description_mode = parse_cover_from_description(value);
+		return 0;
+	}
+	if (!strcmp(var, "format.mboxrd")) {
+		stdout_mboxrd = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "format.noprefix")) {
+		format_no_prefix = 1;
+		return 0;
+	}
+
+	/*
+	 * ignore some porcelain config which would otherwise be parsed by
+	 * git_diff_ui_config(), via git_log_config(); we can't just avoid
+	 * diff_ui_config completely, because we do care about some ui options
+	 * like color.
+	 */
+	if (!strcmp(var, "diff.noprefix"))
+		return 0;
+
+	return git_log_config(var, value, ctx, &cfg->log);
+}
+
+static const char *output_directory = NULL;
+static int outdir_offset;
+
+static int open_next_file(struct commit *commit, const char *subject,
+			 struct rev_info *rev, int quiet)
+{
+	struct strbuf filename = STRBUF_INIT;
+
+	if (output_directory) {
+		strbuf_addstr(&filename, output_directory);
+		strbuf_complete(&filename, '/');
+	}
+
+	if (rev->numbered_files)
+		strbuf_addf(&filename, "%d", rev->nr);
+	else if (commit)
+		fmt_output_commit(&filename, commit, rev);
+	else
+		fmt_output_subject(&filename, subject, rev);
+
+	if (!quiet)
+		printf("%s\n", filename.buf + outdir_offset);
+
+	if (!(rev->diffopt.file = fopen(filename.buf, "w"))) {
+		error_errno(_("cannot open patch file %s"), filename.buf);
+		strbuf_release(&filename);
+		return -1;
+	}
+
+	strbuf_release(&filename);
+	return 0;
+}
+
+static void get_patch_ids(struct rev_info *rev, struct patch_ids *ids)
+{
+	struct rev_info check_rev;
+	struct commit *commit, *c1, *c2;
+	struct object *o1, *o2;
+	unsigned flags1, flags2;
+
+	if (rev->pending.nr != 2)
+		die(_("need exactly one range"));
+
+	o1 = rev->pending.objects[0].item;
+	o2 = rev->pending.objects[1].item;
+	flags1 = o1->flags;
+	flags2 = o2->flags;
+	c1 = lookup_commit_reference(the_repository, &o1->oid);
+	c2 = lookup_commit_reference(the_repository, &o2->oid);
+
+	if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING))
+		die(_("not a range"));
+
+	init_patch_ids(the_repository, ids);
+
+	/* given a range a..b get all patch ids for b..a */
+	repo_init_revisions(the_repository, &check_rev, rev->prefix);
+	check_rev.max_parents = 1;
+	o1->flags ^= UNINTERESTING;
+	o2->flags ^= UNINTERESTING;
+	add_pending_object(&check_rev, o1, "o1");
+	add_pending_object(&check_rev, o2, "o2");
+	if (prepare_revision_walk(&check_rev))
+		die(_("revision walk setup failed"));
+
+	while ((commit = get_revision(&check_rev)) != NULL) {
+		add_commit_patch_id(commit, ids);
+	}
+
+	/* reset for next revision walk */
+	clear_commit_marks(c1, SEEN | UNINTERESTING | SHOWN | ADDED);
+	clear_commit_marks(c2, SEEN | UNINTERESTING | SHOWN | ADDED);
+	o1->flags = flags1;
+	o2->flags = flags2;
+}
+
+static void gen_message_id(struct rev_info *info, const char *base)
+{
+	struct strbuf buf = STRBUF_INIT;
+	strbuf_addf(&buf, "%s.%"PRItime".git.%s", base,
+		    (timestamp_t) time(NULL),
+		    git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT));
+	info->message_id = strbuf_detach(&buf, NULL);
+}
+
+static void print_signature(const char *signature, FILE *file)
+{
+	if (!signature || !*signature)
+		return;
+
+	fprintf(file, "-- \n%s", signature);
+	if (signature[strlen(signature)-1] != '\n')
+		putc('\n', file);
+	putc('\n', file);
+}
+
+static char *find_branch_name(struct rev_info *rev)
+{
+	struct object_id branch_oid;
+	const struct object_id *tip_oid;
+	const char *ref, *v;
+	char *full_ref, *branch = NULL;
+	int interesting_found = 0;
+	size_t idx;
+
+	for (size_t i = 0; i < rev->cmdline.nr; i++) {
+		if (rev->cmdline.rev[i].flags & UNINTERESTING)
+			continue;
+		if (interesting_found)
+			return NULL;
+		interesting_found = 1;
+		idx = i;
+	}
+	if (!interesting_found)
+		return NULL;
+	ref = rev->cmdline.rev[idx].name;
+	tip_oid = &rev->cmdline.rev[idx].item->oid;
+	if (repo_dwim_ref(the_repository, ref, strlen(ref), &branch_oid,
+			  &full_ref, 0) &&
+	    skip_prefix(full_ref, "refs/heads/", &v) &&
+	    oideq(tip_oid, &branch_oid))
+		branch = xstrdup(v);
+	free(full_ref);
+	return branch;
+}
+
+static void show_diffstat(struct rev_info *rev,
+			  struct commit *origin, struct commit *head)
+{
+	struct diff_options opts;
+
+	memcpy(&opts, &rev->diffopt, sizeof(opts));
+	opts.output_format = DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+	diff_setup_done(&opts);
+
+	diff_tree_oid(get_commit_tree_oid(origin),
+		      get_commit_tree_oid(head),
+		      "", &opts);
+	diffcore_std(&opts);
+	diff_flush(&opts);
+
+	fprintf(rev->diffopt.file, "\n");
+}
+
+static void read_desc_file(struct strbuf *buf, const char *desc_file)
+{
+	if (strbuf_read_file(buf, desc_file, 0) < 0)
+		die_errno(_("unable to read branch description file '%s'"),
+			  desc_file);
+}
+
+static void prepare_cover_text(struct pretty_print_context *pp,
+			       const char *description_file,
+			       const char *branch_name,
+			       struct strbuf *sb,
+			       const char *encoding,
+			       int need_8bit_cte,
+			       const struct format_config *cfg)
+{
+	const char *subject = "*** SUBJECT HERE ***";
+	const char *body = "*** BLURB HERE ***";
+	struct strbuf description_sb = STRBUF_INIT;
+	struct strbuf subject_sb = STRBUF_INIT;
+
+	if (cfg->cover_from_description_mode == COVER_FROM_NONE)
+		goto do_pp;
+
+	if (description_file && *description_file)
+		read_desc_file(&description_sb, description_file);
+	else if (branch_name && *branch_name)
+		read_branch_desc(&description_sb, branch_name);
+	if (!description_sb.len)
+		goto do_pp;
+
+	if (cfg->cover_from_description_mode == COVER_FROM_SUBJECT ||
+	    cfg->cover_from_description_mode == COVER_FROM_AUTO)
+		body = format_subject(&subject_sb, description_sb.buf, " ");
+
+	if (cfg->cover_from_description_mode == COVER_FROM_MESSAGE ||
+	    (cfg->cover_from_description_mode == COVER_FROM_AUTO &&
+	     subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
+		body = description_sb.buf;
+	else
+		subject = subject_sb.buf;
+
+do_pp:
+	pp_email_subject(pp, &subject, sb, encoding, need_8bit_cte);
+	pp_remainder(pp, &body, sb, 0);
+
+	strbuf_release(&description_sb);
+	strbuf_release(&subject_sb);
+}
+
+static int get_notes_refs(struct string_list_item *item, void *arg)
+{
+	strvec_pushf(arg, "--notes=%s", item->string);
+	return 0;
+}
+
+static void get_notes_args(struct strvec *arg, struct rev_info *rev)
+{
+	if (!rev->show_notes) {
+		strvec_push(arg, "--no-notes");
+	} else if (rev->notes_opt.use_default_notes > 0 ||
+		   (rev->notes_opt.use_default_notes == -1 &&
+		    !rev->notes_opt.extra_notes_refs.nr)) {
+		strvec_push(arg, "--notes");
+	} else {
+		for_each_string_list(&rev->notes_opt.extra_notes_refs, get_notes_refs, arg);
+	}
+}
+
+static void make_cover_letter(struct rev_info *rev, int use_separate_file,
+			      struct commit *origin,
+			      int nr, struct commit **list,
+			      const char *description_file,
+			      const char *branch_name,
+			      int quiet,
+			      const struct format_config *cfg)
+{
+	const char *committer;
+	struct shortlog log;
+	struct strbuf sb = STRBUF_INIT;
+	int i;
+	const char *encoding = "UTF-8";
+	int need_8bit_cte = 0;
+	struct pretty_print_context pp = {0};
+	struct commit *head = list[0];
+	char *to_free = NULL;
+
+	if (!cmit_fmt_is_mail(rev->commit_format))
+		die(_("cover letter needs email format"));
+
+	committer = git_committer_info(0);
+
+	if (use_separate_file &&
+	    open_next_file(NULL, rev->numbered_files ? NULL : "cover-letter", rev, quiet))
+		die(_("failed to create cover-letter file"));
+
+	log_write_email_headers(rev, head, &pp.after_subject, &need_8bit_cte, 0);
+
+	for (i = 0; !need_8bit_cte && i < nr; i++) {
+		const char *buf = repo_get_commit_buffer(the_repository,
+							 list[i], NULL);
+		if (has_non_ascii(buf))
+			need_8bit_cte = 1;
+		repo_unuse_commit_buffer(the_repository, list[i], buf);
+	}
+
+	if (!branch_name)
+		branch_name = to_free = find_branch_name(rev);
+
+	pp.fmt = CMIT_FMT_EMAIL;
+	pp.date_mode.type = DATE_RFC2822;
+	pp.rev = rev;
+	pp.encode_email_headers = rev->encode_email_headers;
+	pp_user_info(&pp, NULL, &sb, committer, encoding);
+	prepare_cover_text(&pp, description_file, branch_name, &sb,
+			   encoding, need_8bit_cte, cfg);
+	fprintf(rev->diffopt.file, "%s\n", sb.buf);
+
+	free(to_free);
+	free(pp.after_subject);
+	strbuf_release(&sb);
+
+	shortlog_init(&log);
+	log.wrap_lines = 1;
+	log.wrap = MAIL_DEFAULT_WRAP;
+	log.in1 = 2;
+	log.in2 = 4;
+	log.file = rev->diffopt.file;
+	log.groups = SHORTLOG_GROUP_AUTHOR;
+	shortlog_finish_setup(&log);
+	for (i = 0; i < nr; i++)
+		shortlog_add_commit(&log, list[i]);
+
+	shortlog_output(&log);
+
+	/* We can only do diffstat with a unique reference point */
+	if (origin)
+		show_diffstat(rev, origin, head);
+
+	if (rev->idiff_oid1) {
+		fprintf_ln(rev->diffopt.file, "%s", rev->idiff_title);
+		show_interdiff(rev->idiff_oid1, rev->idiff_oid2, 0,
+			       &rev->diffopt);
+	}
+
+	if (rev->rdiff1) {
+		/*
+		 * Pass minimum required diff-options to range-diff; others
+		 * can be added later if deemed desirable.
+		 */
+		struct diff_options opts;
+		struct strvec other_arg = STRVEC_INIT;
+		struct range_diff_options range_diff_opts = {
+			.creation_factor = rev->creation_factor,
+			.dual_color = 1,
+			.diffopt = &opts,
+			.other_arg = &other_arg
+		};
+
+		repo_diff_setup(the_repository, &opts);
+		opts.file = rev->diffopt.file;
+		opts.use_color = rev->diffopt.use_color;
+		diff_setup_done(&opts);
+		fprintf_ln(rev->diffopt.file, "%s", rev->rdiff_title);
+		get_notes_args(&other_arg, rev);
+		show_range_diff(rev->rdiff1, rev->rdiff2, &range_diff_opts);
+		strvec_clear(&other_arg);
+	}
+}
+
+static char *clean_message_id(const char *msg_id)
+{
+	char ch;
+	const char *a, *z, *m;
+
+	m = msg_id;
+	while ((ch = *m) && (isspace(ch) || (ch == '<')))
+		m++;
+	a = m;
+	z = NULL;
+	while ((ch = *m)) {
+		if (!isspace(ch) && (ch != '>'))
+			z = m;
+		m++;
+	}
+	if (!z)
+		die(_("insane in-reply-to: %s"), msg_id);
+	if (++z == m)
+		return xstrdup(a);
+	return xmemdupz(a, z - a);
+}
+
+static const char *set_outdir(const char *prefix, const char *output_directory)
+{
+	if (output_directory && is_absolute_path(output_directory))
+		return output_directory;
+
+	if (!prefix || !*prefix) {
+		if (output_directory)
+			return output_directory;
+		/* The user did not explicitly ask for "./" */
+		outdir_offset = 2;
+		return "./";
+	}
+
+	outdir_offset = strlen(prefix);
+	if (!output_directory)
+		return prefix;
+
+	return prefix_filename(prefix, output_directory);
+}
+
+static const char * const builtin_format_patch_usage[] = {
+	N_("git format-patch [<options>] [<since> | <revision-range>]"),
+	NULL
+};
+
+struct keep_callback_data {
+	struct format_config *cfg;
+	struct rev_info *revs;
+};
+
+static int keep_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct keep_callback_data *data = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	data->revs->total = -1;
+	data->cfg->keep_subject = 1;
+	return 0;
+}
+
+static int subject_prefix_callback(const struct option *opt, const char *arg,
+			    int unset)
+{
+	struct format_config *cfg = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	cfg->subject_prefix = 1;
+	strbuf_reset(&cfg->sprefix);
+	strbuf_addstr(&cfg->sprefix, arg);
+	return 0;
+}
+
+static int rfc_callback(const struct option *opt, const char *arg,
+			int unset)
+{
+	const char **rfc = opt->value;
+
+	*rfc = opt->value;
+	if (unset)
+		*rfc = NULL;
+	else
+		*rfc = arg ? arg : "RFC";
+	return 0;
+}
+
+static int numbered_callback(const struct option *opt, const char *arg,
+			     int unset)
+{
+	struct format_config *cfg = opt->value;
+	BUG_ON_OPT_ARG(arg);
+	cfg->numbered = cfg->numbered_cmdline_opt = unset ? 0 : 1;
+	if (unset)
+		cfg->auto_number =  0;
+	return 0;
+}
+
+static int no_numbered_callback(const struct option *opt, const char *arg,
+				int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+	return numbered_callback(opt, arg, 1);
+}
+
+static int output_directory_callback(const struct option *opt, const char *arg,
+			      int unset)
+{
+	const char **dir = (const char **)opt->value;
+	BUG_ON_OPT_NEG(unset);
+	if (*dir)
+		die(_("two output directories?"));
+	*dir = arg;
+	return 0;
+}
+
+static int thread_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct format_config *cfg = opt->value;
+
+	if (unset)
+		cfg->thread = THREAD_UNSET;
+	else if (!arg || !strcmp(arg, "shallow"))
+		cfg->thread = THREAD_SHALLOW;
+	else if (!strcmp(arg, "deep"))
+		cfg->thread = THREAD_DEEP;
+	/*
+	 * Please update _git_formatpatch() in git-completion.bash
+	 * when you add new options.
+	 */
+	else
+		return 1;
+	return 0;
+}
+
+static int attach_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct rev_info *rev = (struct rev_info *)opt->value;
+	if (unset)
+		rev->mime_boundary = NULL;
+	else if (arg)
+		rev->mime_boundary = arg;
+	else
+		rev->mime_boundary = git_version_string;
+	rev->no_inline = unset ? 0 : 1;
+	return 0;
+}
+
+static int inline_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct rev_info *rev = (struct rev_info *)opt->value;
+	if (unset)
+		rev->mime_boundary = NULL;
+	else if (arg)
+		rev->mime_boundary = arg;
+	else
+		rev->mime_boundary = git_version_string;
+	rev->no_inline = 0;
+	return 0;
+}
+
+static int header_callback(const struct option *opt, const char *arg,
+			   int unset)
+{
+	struct format_config *cfg = opt->value;
+
+	if (unset) {
+		string_list_clear(&cfg->extra_hdr, 0);
+		string_list_clear(&cfg->extra_to, 0);
+		string_list_clear(&cfg->extra_cc, 0);
+	} else {
+		add_header(cfg, arg);
+	}
+	return 0;
+}
+
+static int from_callback(const struct option *opt, const char *arg, int unset)
+{
+	char **from = opt->value;
+
+	free(*from);
+
+	if (unset)
+		*from = NULL;
+	else if (arg)
+		*from = xstrdup(arg);
+	else
+		*from = xstrdup(git_committer_info(IDENT_NO_DATE));
+	return 0;
+}
+
+static int base_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct format_config *cfg = opt->value;
+
+	if (unset) {
+		cfg->auto_base = AUTO_BASE_NEVER;
+		FREE_AND_NULL(cfg->base_commit);
+	} else if (!strcmp(arg, "auto")) {
+		cfg->auto_base = AUTO_BASE_ALWAYS;
+		FREE_AND_NULL(cfg->base_commit);
+	} else {
+		cfg->auto_base = AUTO_BASE_NEVER;
+		cfg->base_commit = xstrdup(arg);
+	}
+	return 0;
+}
+
+struct base_tree_info {
+	struct object_id base_commit;
+	int nr_patch_id, alloc_patch_id;
+	struct object_id *patch_id;
+};
+
+static struct commit *get_base_commit(const struct format_config *cfg,
+				      struct commit **list,
+				      size_t total)
+{
+	struct commit *base = NULL;
+	struct commit **rev;
+	int auto_select, die_on_failure, ret;
+	size_t i = 0, rev_nr = 0;
+
+	switch (cfg->auto_base) {
+	case AUTO_BASE_NEVER:
+		if (cfg->base_commit) {
+			auto_select = 0;
+			die_on_failure = 1;
+		} else {
+			/* no base information is requested */
+			return NULL;
+		}
+		break;
+	case AUTO_BASE_ALWAYS:
+	case AUTO_BASE_WHEN_ABLE:
+		if (cfg->base_commit) {
+			BUG("requested automatic base selection but a commit was provided");
+		} else {
+			auto_select = 1;
+			die_on_failure = cfg->auto_base == AUTO_BASE_ALWAYS;
+		}
+		break;
+	default:
+		BUG("unexpected automatic base selection method");
+	}
+
+	if (!auto_select) {
+		base = lookup_commit_reference_by_name(cfg->base_commit);
+		if (!base)
+			die(_("unknown commit %s"), cfg->base_commit);
+	} else {
+		struct branch *curr_branch = branch_get(NULL);
+		const char *upstream = branch_get_upstream(curr_branch, NULL);
+		if (upstream) {
+			struct commit_list *base_list = NULL;
+			struct commit *commit;
+			struct object_id oid;
+
+			if (repo_get_oid(the_repository, upstream, &oid)) {
+				if (die_on_failure)
+					die(_("failed to resolve '%s' as a valid ref"), upstream);
+				else
+					return NULL;
+			}
+			commit = lookup_commit_or_die(&oid, "upstream base");
+			if (repo_get_merge_bases_many(the_repository,
+						      commit, total,
+						      list,
+						      &base_list) < 0 ||
+			    /* There should be one and only one merge base. */
+			    !base_list || base_list->next) {
+				if (die_on_failure) {
+					die(_("could not find exact merge base"));
+				} else {
+					free_commit_list(base_list);
+					return NULL;
+				}
+			}
+			base = base_list->item;
+			free_commit_list(base_list);
+		} else {
+			if (die_on_failure)
+				die(_("failed to get upstream, if you want to record base commit automatically,\n"
+				      "please use git branch --set-upstream-to to track a remote branch.\n"
+				      "Or you could specify base commit by --base=<base-commit-id> manually"));
+			else
+				return NULL;
+		}
+	}
+
+	ALLOC_ARRAY(rev, total);
+	for (i = 0; i < total; i++)
+		rev[i] = list[i];
+
+	rev_nr = total;
+	/*
+	 * Get merge base through pair-wise computations
+	 * and store it in rev[0].
+	 */
+	while (rev_nr > 1) {
+		for (i = 0; i < rev_nr / 2; i++) {
+			struct commit_list *merge_base = NULL;
+			if (repo_get_merge_bases(the_repository,
+						 rev[2 * i],
+						 rev[2 * i + 1], &merge_base) < 0 ||
+			    !merge_base || merge_base->next) {
+				if (die_on_failure) {
+					die(_("failed to find exact merge base"));
+				} else {
+					free_commit_list(merge_base);
+					free(rev);
+					return NULL;
+				}
+			}
+
+			rev[i] = merge_base->item;
+			free_commit_list(merge_base);
+		}
+
+		if (rev_nr % 2)
+			rev[i] = rev[2 * i];
+		rev_nr = DIV_ROUND_UP(rev_nr, 2);
+	}
+
+	ret = repo_in_merge_bases(the_repository, base, rev[0]);
+	if (ret < 0)
+		exit(128);
+	if (!ret) {
+		if (die_on_failure) {
+			die(_("base commit should be the ancestor of revision list"));
+		} else {
+			free(rev);
+			return NULL;
+		}
+	}
+
+	for (i = 0; i < total; i++) {
+		if (base == list[i]) {
+			if (die_on_failure) {
+				die(_("base commit shouldn't be in revision list"));
+			} else {
+				free(rev);
+				return NULL;
+			}
+		}
+	}
+
+	free(rev);
+	return base;
+}
+
+define_commit_slab(commit_base, int);
+
+static void prepare_bases(struct base_tree_info *bases,
+			  struct commit *base,
+			  struct commit **list,
+			  size_t total)
+{
+	struct commit *commit;
+	struct rev_info revs;
+	struct diff_options diffopt;
+	struct commit_base commit_base;
+
+	if (!base)
+		return;
+
+	init_commit_base(&commit_base);
+	repo_diff_setup(the_repository, &diffopt);
+	diffopt.flags.recursive = 1;
+	diff_setup_done(&diffopt);
+
+	oidcpy(&bases->base_commit, &base->object.oid);
+
+	repo_init_revisions(the_repository, &revs, NULL);
+	revs.max_parents = 1;
+	revs.topo_order = 1;
+	for (size_t i = 0; i < total; i++) {
+		list[i]->object.flags &= ~UNINTERESTING;
+		add_pending_object(&revs, &list[i]->object, "rev_list");
+		*commit_base_at(&commit_base, list[i]) = 1;
+	}
+	base->object.flags |= UNINTERESTING;
+	add_pending_object(&revs, &base->object, "base");
+
+	if (prepare_revision_walk(&revs))
+		die(_("revision walk setup failed"));
+	/*
+	 * Traverse the commits list, get prerequisite patch ids
+	 * and stuff them in bases structure.
+	 */
+	while ((commit = get_revision(&revs)) != NULL) {
+		struct object_id oid;
+		struct object_id *patch_id;
+		if (*commit_base_at(&commit_base, commit))
+			continue;
+		if (commit_patch_id(commit, &diffopt, &oid, 0))
+			die(_("cannot get patch id"));
+		ALLOC_GROW(bases->patch_id, bases->nr_patch_id + 1, bases->alloc_patch_id);
+		patch_id = bases->patch_id + bases->nr_patch_id;
+		oidcpy(patch_id, &oid);
+		bases->nr_patch_id++;
+	}
+	clear_commit_base(&commit_base);
+}
+
+static void print_bases(struct base_tree_info *bases, FILE *file)
+{
+	int i;
+
+	/* Only do this once, either for the cover or for the first one */
+	if (is_null_oid(&bases->base_commit))
+		return;
+
+	/* Show the base commit */
+	fprintf(file, "\nbase-commit: %s\n", oid_to_hex(&bases->base_commit));
+
+	/* Show the prerequisite patches */
+	for (i = bases->nr_patch_id - 1; i >= 0; i--)
+		fprintf(file, "prerequisite-patch-id: %s\n", oid_to_hex(&bases->patch_id[i]));
+
+	free(bases->patch_id);
+	bases->nr_patch_id = 0;
+	bases->alloc_patch_id = 0;
+	oidclr(&bases->base_commit, the_repository->hash_algo);
+}
+
+static const char *diff_title(struct strbuf *sb,
+			      const char *reroll_count,
+			      const char *generic,
+			      const char *rerolled)
+{
+	int v;
+
+	/* RFC may be v0, so allow -v1 to diff against v0 */
+	if (reroll_count && !strtol_i(reroll_count, 10, &v) &&
+	    v >= 1)
+		strbuf_addf(sb, rerolled, v - 1);
+	else
+		strbuf_addstr(sb, generic);
+	return sb->buf;
+}
+
+static void infer_range_diff_ranges(struct strbuf *r1,
+				    struct strbuf *r2,
+				    const char *prev,
+				    struct commit *origin,
+				    struct commit *head)
+{
+	const char *head_oid = oid_to_hex(&head->object.oid);
+	int prev_is_range = is_range_diff_range(prev);
+
+	if (prev_is_range)
+		strbuf_addstr(r1, prev);
+	else
+		strbuf_addf(r1, "%s..%s", head_oid, prev);
+
+	if (origin)
+		strbuf_addf(r2, "%s..%s", oid_to_hex(&origin->object.oid), head_oid);
+	else if (prev_is_range)
+		die(_("failed to infer range-diff origin of current series"));
+	else {
+		warning(_("using '%s' as range-diff origin of current series"), prev);
+		strbuf_addf(r2, "%s..%s", prev, head_oid);
+	}
+}
+
+int cmd_format_patch(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	struct format_config cfg;
+	struct commit *commit;
+	struct commit **list = NULL;
+	struct rev_info rev;
+	char *to_free = NULL;
+	struct setup_revision_opt s_r_opt;
+	size_t nr = 0, total, i;
+	int use_stdout = 0;
+	int start_number = -1;
+	int just_numbers = 0;
+	int ignore_if_in_upstream = 0;
+	int cover_letter = -1;
+	int boundary_count = 0;
+	int no_binary_diff = 0;
+	int zero_commit = 0;
+	struct commit *origin = NULL;
+	const char *in_reply_to = NULL;
+	struct patch_ids ids;
+	struct strbuf buf = STRBUF_INIT;
+	int use_patch_format = 0;
+	int quiet = 0;
+	const char *reroll_count = NULL;
+	char *cover_from_description_arg = NULL;
+	char *description_file = NULL;
+	char *branch_name = NULL;
+	struct base_tree_info bases;
+	struct commit *base;
+	int show_progress = 0;
+	struct progress *progress = NULL;
+	struct oid_array idiff_prev = OID_ARRAY_INIT;
+	struct strbuf idiff_title = STRBUF_INIT;
+	const char *rdiff_prev = NULL;
+	struct strbuf rdiff1 = STRBUF_INIT;
+	struct strbuf rdiff2 = STRBUF_INIT;
+	struct strbuf rdiff_title = STRBUF_INIT;
+	const char *rfc = NULL;
+	int creation_factor = -1;
+	const char *signature = git_version_string;
+	char *signature_to_free = NULL;
+	char *signature_file_arg = NULL;
+	struct keep_callback_data keep_callback_data = {
+		.cfg = &cfg,
+		.revs = &rev,
+	};
+	const char *fmt_patch_suffix = NULL;
+
+	const struct option builtin_format_patch_options[] = {
+		OPT_CALLBACK_F('n', "numbered", &cfg, NULL,
+			    N_("use [PATCH n/m] even with a single patch"),
+			    PARSE_OPT_NOARG, numbered_callback),
+		OPT_CALLBACK_F('N', "no-numbered", &cfg, NULL,
+			    N_("use [PATCH] even with multiple patches"),
+			    PARSE_OPT_NOARG | PARSE_OPT_NONEG, no_numbered_callback),
+		OPT_BOOL('s', "signoff", &cfg.do_signoff, N_("add a Signed-off-by trailer")),
+		OPT_BOOL(0, "stdout", &use_stdout,
+			    N_("print patches to standard out")),
+		OPT_BOOL(0, "cover-letter", &cover_letter,
+			    N_("generate a cover letter")),
+		OPT_BOOL(0, "numbered-files", &just_numbers,
+			    N_("use simple number sequence for output file names")),
+		OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
+			    N_("use <sfx> instead of '.patch'")),
+		OPT_INTEGER(0, "start-number", &start_number,
+			    N_("start numbering patches at <n> instead of 1")),
+		OPT_STRING('v', "reroll-count", &reroll_count, N_("reroll-count"),
+			    N_("mark the series as Nth re-roll")),
+		OPT_INTEGER(0, "filename-max-length", &cfg.log.fmt_patch_name_max,
+			    N_("max length of output filename")),
+		OPT_CALLBACK_F(0, "rfc", &rfc, N_("rfc"),
+			       N_("add <rfc> (default 'RFC') before 'PATCH'"),
+			       PARSE_OPT_OPTARG, rfc_callback),
+		OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
+			    N_("cover-from-description-mode"),
+			    N_("generate parts of a cover letter based on a branch's description")),
+		OPT_FILENAME(0, "description-file", &description_file,
+			     N_("use branch description from file")),
+		OPT_CALLBACK_F(0, "subject-prefix", &cfg, N_("prefix"),
+			    N_("use [<prefix>] instead of [PATCH]"),
+			    PARSE_OPT_NONEG, subject_prefix_callback),
+		OPT_CALLBACK_F('o', "output-directory", &output_directory,
+			    N_("dir"), N_("store resulting files in <dir>"),
+			    PARSE_OPT_NONEG, output_directory_callback),
+		OPT_CALLBACK_F('k', "keep-subject", &keep_callback_data, NULL,
+			    N_("don't strip/add [PATCH]"),
+			    PARSE_OPT_NOARG | PARSE_OPT_NONEG, keep_callback),
+		OPT_BOOL(0, "no-binary", &no_binary_diff,
+			 N_("don't output binary diffs")),
+		OPT_BOOL(0, "zero-commit", &zero_commit,
+			 N_("output all-zero hash in From header")),
+		OPT_BOOL(0, "ignore-if-in-upstream", &ignore_if_in_upstream,
+			 N_("don't include a patch matching a commit upstream")),
+		OPT_SET_INT_F('p', "no-stat", &use_patch_format,
+			      N_("show patch format instead of default (patch + stat)"),
+			      1, PARSE_OPT_NONEG),
+		OPT_GROUP(N_("Messaging")),
+		OPT_CALLBACK(0, "add-header", &cfg, N_("header"),
+			    N_("add email header"), header_callback),
+		OPT_STRING_LIST(0, "to", &cfg.extra_to, N_("email"), N_("add To: header")),
+		OPT_STRING_LIST(0, "cc", &cfg.extra_cc, N_("email"), N_("add Cc: header")),
+		OPT_CALLBACK_F(0, "from", &cfg.from, N_("ident"),
+			    N_("set From address to <ident> (or committer ident if absent)"),
+			    PARSE_OPT_OPTARG, from_callback),
+		OPT_STRING(0, "in-reply-to", &in_reply_to, N_("message-id"),
+			    N_("make first mail a reply to <message-id>")),
+		OPT_CALLBACK_F(0, "attach", &rev, N_("boundary"),
+			    N_("attach the patch"), PARSE_OPT_OPTARG,
+			    attach_callback),
+		OPT_CALLBACK_F(0, "inline", &rev, N_("boundary"),
+			    N_("inline the patch"),
+			    PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+			    inline_callback),
+		OPT_CALLBACK_F(0, "thread", &cfg, N_("style"),
+			    N_("enable message threading, styles: shallow, deep"),
+			    PARSE_OPT_OPTARG, thread_callback),
+		OPT_STRING(0, "signature", &signature, N_("signature"),
+			    N_("add a signature")),
+		OPT_CALLBACK_F(0, "base", &cfg, N_("base-commit"),
+			       N_("add prerequisite tree info to the patch series"),
+			       0, base_callback),
+		OPT_FILENAME(0, "signature-file", &signature_file_arg,
+				N_("add a signature from a file")),
+		OPT__QUIET(&quiet, N_("don't print the patch filenames")),
+		OPT_BOOL(0, "progress", &show_progress,
+			 N_("show progress while generating patches")),
+		OPT_CALLBACK(0, "interdiff", &idiff_prev, N_("rev"),
+			     N_("show changes against <rev> in cover letter or single patch"),
+			     parse_opt_object_name),
+		OPT_STRING(0, "range-diff", &rdiff_prev, N_("refspec"),
+			   N_("show changes against <refspec> in cover letter or single patch")),
+		OPT_INTEGER(0, "creation-factor", &creation_factor,
+			    N_("percentage by which creation is weighted")),
+		OPT_BOOL(0, "force-in-body-from", &force_in_body_from,
+			 N_("show in-body From: even if identical to the e-mail header")),
+		OPT_END()
+	};
+
+	format_config_init(&cfg);
+	init_diff_ui_defaults();
+	init_display_notes(&cfg.notes_opt);
+	git_config(git_format_config, &cfg);
+	repo_init_revisions(the_repository, &rev, prefix);
+	git_config(grep_config, &rev.grep_filter);
+
+	rev.show_notes = cfg.show_notes;
+	memcpy(&rev.notes_opt, &cfg.notes_opt, sizeof(cfg.notes_opt));
+	rev.commit_format = CMIT_FMT_EMAIL;
+	rev.encode_email_headers = cfg.log.default_encode_email_headers;
+	rev.expand_tabs_in_log_default = 0;
+	rev.verbose_header = 1;
+	rev.diff = 1;
+	rev.max_parents = 1;
+	rev.diffopt.flags.recursive = 1;
+	rev.diffopt.no_free = 1;
+	memset(&s_r_opt, 0, sizeof(s_r_opt));
+	s_r_opt.def = "HEAD";
+	s_r_opt.revarg_opt = REVARG_COMMITTISH;
+
+	strbuf_addstr(&cfg.sprefix, cfg.log.fmt_patch_subject_prefix);
+	if (format_no_prefix)
+		diff_set_noprefix(&rev.diffopt);
+
+	if (cfg.default_attach) {
+		rev.mime_boundary = cfg.default_attach;
+		rev.no_inline = 1;
+	}
+
+	/*
+	 * Parse the arguments before setup_revisions(), or something
+	 * like "git format-patch -o a123 HEAD^.." may fail; a123 is
+	 * possibly a valid SHA1.
+	 */
+	argc = parse_options(argc, argv, prefix, builtin_format_patch_options,
+			     builtin_format_patch_usage,
+			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	rev.force_in_body_from = force_in_body_from;
+
+	if (!fmt_patch_suffix)
+		fmt_patch_suffix = cfg.fmt_patch_suffix;
+
+	/* Make sure "0000-$sub.patch" gives non-negative length for $sub */
+	if (cfg.log.fmt_patch_name_max <= cast_size_t_to_int(strlen("0000-") + strlen(fmt_patch_suffix)))
+		cfg.log.fmt_patch_name_max = strlen("0000-") + strlen(fmt_patch_suffix);
+
+	if (cover_from_description_arg)
+		cfg.cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
+
+	if (rfc && rfc[0]) {
+		cfg.subject_prefix = 1;
+		if (rfc[0] == '-')
+			strbuf_addf(&cfg.sprefix, " %s", rfc + 1);
+		else
+			strbuf_insertf(&cfg.sprefix, 0, "%s ", rfc);
+	}
+
+	if (reroll_count) {
+		strbuf_addf(&cfg.sprefix, " v%s", reroll_count);
+		rev.reroll_count = reroll_count;
+	}
+
+	rev.subject_prefix = cfg.sprefix.buf;
+
+	for (i = 0; i < cfg.extra_hdr.nr; i++) {
+		strbuf_addstr(&buf, cfg.extra_hdr.items[i].string);
+		strbuf_addch(&buf, '\n');
+	}
+
+	if (cfg.extra_to.nr)
+		strbuf_addstr(&buf, "To: ");
+	for (i = 0; i < cfg.extra_to.nr; i++) {
+		if (i)
+			strbuf_addstr(&buf, "    ");
+		strbuf_addstr(&buf, cfg.extra_to.items[i].string);
+		if (i + 1 < cfg.extra_to.nr)
+			strbuf_addch(&buf, ',');
+		strbuf_addch(&buf, '\n');
+	}
+
+	if (cfg.extra_cc.nr)
+		strbuf_addstr(&buf, "Cc: ");
+	for (i = 0; i < cfg.extra_cc.nr; i++) {
+		if (i)
+			strbuf_addstr(&buf, "    ");
+		strbuf_addstr(&buf, cfg.extra_cc.items[i].string);
+		if (i + 1 < cfg.extra_cc.nr)
+			strbuf_addch(&buf, ',');
+		strbuf_addch(&buf, '\n');
+	}
+
+	rev.extra_headers = to_free = strbuf_detach(&buf, NULL);
+
+	if (cfg.from) {
+		if (split_ident_line(&rev.from_ident, cfg.from, strlen(cfg.from)))
+			die(_("invalid ident line: %s"), cfg.from);
+	}
+
+	if (start_number < 0)
+		start_number = 1;
+
+	/*
+	 * If numbered is set solely due to format.numbered in config,
+	 * and it would conflict with --keep-subject (-k) from the
+	 * command line, reset "numbered".
+	 */
+	if (cfg.numbered && cfg.keep_subject && !cfg.numbered_cmdline_opt)
+		cfg.numbered = 0;
+
+	if (cfg.numbered && cfg.keep_subject)
+		die(_("options '%s' and '%s' cannot be used together"), "-n", "-k");
+	if (cfg.keep_subject && cfg.subject_prefix)
+		die(_("options '%s' and '%s' cannot be used together"), "--subject-prefix/--rfc", "-k");
+	rev.preserve_subject = cfg.keep_subject;
+
+	argc = setup_revisions(argc, argv, &rev, &s_r_opt);
+	if (argc > 1)
+		die(_("unrecognized argument: %s"), argv[1]);
+
+	if (rev.diffopt.output_format & DIFF_FORMAT_NAME)
+		die(_("--name-only does not make sense"));
+	if (rev.diffopt.output_format & DIFF_FORMAT_NAME_STATUS)
+		die(_("--name-status does not make sense"));
+	if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
+		die(_("--check does not make sense"));
+	if (rev.remerge_diff)
+		die(_("--remerge-diff does not make sense"));
+
+	if (!use_patch_format &&
+		(!rev.diffopt.output_format ||
+		 rev.diffopt.output_format == DIFF_FORMAT_PATCH))
+		rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_SUMMARY;
+	if (!rev.diffopt.stat_width)
+		rev.diffopt.stat_width = MAIL_DEFAULT_WRAP;
+
+	/* Always generate a patch */
+	rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+	rev.always_show_header = 1;
+
+	rev.zero_commit = zero_commit;
+	rev.patch_name_max = cfg.log.fmt_patch_name_max;
+
+	if (!rev.diffopt.flags.text && !no_binary_diff)
+		rev.diffopt.flags.binary = 1;
+
+	if (rev.show_notes)
+		load_display_notes(&rev.notes_opt);
+
+	die_for_incompatible_opt3(use_stdout, "--stdout",
+				  rev.diffopt.close_file, "--output",
+				  !!output_directory, "--output-directory");
+
+	if (use_stdout && stdout_mboxrd)
+		rev.commit_format = CMIT_FMT_MBOXRD;
+
+	if (use_stdout) {
+		setup_pager(the_repository);
+	} else if (!rev.diffopt.close_file) {
+		int saved;
+
+		if (!output_directory)
+			output_directory = cfg.config_output_directory;
+		output_directory = set_outdir(prefix, output_directory);
+
+		if (rev.diffopt.use_color != GIT_COLOR_ALWAYS)
+			rev.diffopt.use_color = GIT_COLOR_NEVER;
+		/*
+		 * We consider <outdir> as 'outside of gitdir', therefore avoid
+		 * applying adjust_shared_perm in s-c-l-d.
+		 */
+		saved = get_shared_repository();
+		set_shared_repository(0);
+		switch (safe_create_leading_directories_const(output_directory)) {
+		case SCLD_OK:
+		case SCLD_EXISTS:
+			break;
+		default:
+			die(_("could not create leading directories "
+			      "of '%s'"), output_directory);
+		}
+		set_shared_repository(saved);
+		if (mkdir(output_directory, 0777) < 0 && errno != EEXIST)
+			die_errno(_("could not create directory '%s'"),
+				  output_directory);
+	}
+
+	if (rev.pending.nr == 1) {
+		int check_head = 0;
+
+		if (rev.max_count < 0 && !rev.show_root_diff) {
+			/*
+			 * This is traditional behaviour of "git format-patch
+			 * origin" that prepares what the origin side still
+			 * does not have.
+			 */
+			rev.pending.objects[0].item->flags |= UNINTERESTING;
+			add_head_to_pending(&rev);
+			check_head = 1;
+		}
+		/*
+		 * Otherwise, it is "format-patch -22 HEAD", and/or
+		 * "format-patch --root HEAD".  The user wants
+		 * get_revision() to do the usual traversal.
+		 */
+
+		if (!strcmp(rev.pending.objects[0].name, "HEAD"))
+			check_head = 1;
+
+		if (check_head) {
+			const char *ref, *v;
+			ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+						      "HEAD",
+						      RESOLVE_REF_READING,
+						      NULL, NULL);
+			if (ref && skip_prefix(ref, "refs/heads/", &v))
+				branch_name = xstrdup(v);
+			else
+				branch_name = xstrdup(""); /* no branch */
+		}
+	}
+
+	/*
+	 * We cannot move this anywhere earlier because we do want to
+	 * know if --root was given explicitly from the command line.
+	 */
+	rev.show_root_diff = 1;
+
+	if (ignore_if_in_upstream) {
+		/* Don't say anything if head and upstream are the same. */
+		if (rev.pending.nr == 2) {
+			struct object_array_entry *o = rev.pending.objects;
+			if (oideq(&o[0].item->oid, &o[1].item->oid))
+				goto done;
+		}
+		get_patch_ids(&rev, &ids);
+	}
+
+	if (prepare_revision_walk(&rev))
+		die(_("revision walk setup failed"));
+	rev.boundary = 1;
+	while ((commit = get_revision(&rev)) != NULL) {
+		if (commit->object.flags & BOUNDARY) {
+			boundary_count++;
+			origin = (boundary_count == 1) ? commit : NULL;
+			continue;
+		}
+
+		if (ignore_if_in_upstream && has_commit_patch_id(commit, &ids))
+			continue;
+
+		nr++;
+		REALLOC_ARRAY(list, nr);
+		list[nr - 1] = commit;
+	}
+	if (nr == 0)
+		/* nothing to do */
+		goto done;
+	total = nr;
+	if (cover_letter == -1) {
+		if (cfg.config_cover_letter == COVER_AUTO)
+			cover_letter = (total > 1);
+		else if ((idiff_prev.nr || rdiff_prev) && (total > 1))
+			cover_letter = (cfg.config_cover_letter != COVER_OFF);
+		else
+			cover_letter = (cfg.config_cover_letter == COVER_ON);
+	}
+	if (!cfg.keep_subject && cfg.auto_number && (total > 1 || cover_letter))
+		cfg.numbered = 1;
+	if (cfg.numbered)
+		rev.total = total + start_number - 1;
+
+	if (idiff_prev.nr) {
+		if (!cover_letter && total != 1)
+			die(_("--interdiff requires --cover-letter or single patch"));
+		rev.idiff_oid1 = &idiff_prev.oid[idiff_prev.nr - 1];
+		rev.idiff_oid2 = get_commit_tree_oid(list[0]);
+		rev.idiff_title = diff_title(&idiff_title, reroll_count,
+					     _("Interdiff:"),
+					     _("Interdiff against v%d:"));
+	}
+
+	if (creation_factor < 0)
+		creation_factor = CREATION_FACTOR_FOR_THE_SAME_SERIES;
+	else if (!rdiff_prev)
+		die(_("the option '%s' requires '%s'"), "--creation-factor", "--range-diff");
+
+	if (rdiff_prev) {
+		if (!cover_letter && total != 1)
+			die(_("--range-diff requires --cover-letter or single patch"));
+
+		infer_range_diff_ranges(&rdiff1, &rdiff2, rdiff_prev,
+					origin, list[0]);
+		rev.rdiff1 = rdiff1.buf;
+		rev.rdiff2 = rdiff2.buf;
+		rev.creation_factor = creation_factor;
+		rev.rdiff_title = diff_title(&rdiff_title, reroll_count,
+					     _("Range-diff:"),
+					     _("Range-diff against v%d:"));
+	}
+
+	/*
+	 * The order of precedence is:
+	 *
+	 *   1. The `--signature` and `--no-signature` options.
+	 *   2. The `--signature-file` option.
+	 *   3. The `format.signature` config.
+	 *   4. The `format.signatureFile` config.
+	 *   5. Default `git_version_string`.
+	 */
+	if (!signature) {
+		; /* --no-signature inhibits all signatures */
+	} else if (signature && signature != git_version_string) {
+		; /* non-default signature already set */
+	} else if (signature_file_arg || (cfg.signature_file && !cfg.signature)) {
+		struct strbuf buf = STRBUF_INIT;
+		const char *signature_file = signature_file_arg ?
+			signature_file_arg : cfg.signature_file;
+
+		if (strbuf_read_file(&buf, signature_file, 128) < 0)
+			die_errno(_("unable to read signature file '%s'"), signature_file);
+		signature = signature_to_free = strbuf_detach(&buf, NULL);
+	} else if (cfg.signature) {
+		signature = cfg.signature;
+	}
+
+	memset(&bases, 0, sizeof(bases));
+	base = get_base_commit(&cfg, list, nr);
+	if (base) {
+		reset_revision_walk();
+		clear_object_flags(UNINTERESTING);
+		prepare_bases(&bases, base, list, nr);
+	}
+
+	if (in_reply_to || cfg.thread || cover_letter) {
+		rev.ref_message_ids = xmalloc(sizeof(*rev.ref_message_ids));
+		string_list_init_dup(rev.ref_message_ids);
+	}
+	if (in_reply_to) {
+		char *msgid = clean_message_id(in_reply_to);
+		string_list_append_nodup(rev.ref_message_ids, msgid);
+	}
+	rev.numbered_files = just_numbers;
+	rev.patch_suffix = fmt_patch_suffix;
+	if (cover_letter) {
+		if (cfg.thread)
+			gen_message_id(&rev, "cover");
+		make_cover_letter(&rev, !!output_directory,
+				  origin, nr, list, description_file, branch_name, quiet, &cfg);
+		print_bases(&bases, rev.diffopt.file);
+		print_signature(signature, rev.diffopt.file);
+		total++;
+		start_number--;
+		/* interdiff/range-diff in cover-letter; omit from patches */
+		rev.idiff_oid1 = NULL;
+		rev.rdiff1 = NULL;
+	}
+	rev.add_signoff = cfg.do_signoff;
+
+	if (show_progress)
+		progress = start_delayed_progress(the_repository,
+						  _("Generating patches"), total);
+	for (i = 0; i < nr; i++) {
+		size_t idx = nr - i - 1;
+		int shown;
+
+		display_progress(progress, total - idx);
+		commit = list[idx];
+		rev.nr = total - idx + (start_number - 1);
+
+		/* Make the second and subsequent mails replies to the first */
+		if (cfg.thread) {
+			/* Have we already had a message ID? */
+			if (rev.message_id) {
+				/*
+				 * For deep threading: make every mail
+				 * a reply to the previous one, no
+				 * matter what other options are set.
+				 *
+				 * For shallow threading:
+				 *
+				 * Without --cover-letter and
+				 * --in-reply-to, make every mail a
+				 * reply to the one before.
+				 *
+				 * With --in-reply-to but no
+				 * --cover-letter, make every mail a
+				 * reply to the <reply-to>.
+				 *
+				 * With --cover-letter, make every
+				 * mail but the cover letter a reply
+				 * to the cover letter.  The cover
+				 * letter is a reply to the
+				 * --in-reply-to, if specified.
+				 */
+				if (cfg.thread == THREAD_SHALLOW
+				    && rev.ref_message_ids->nr > 0
+				    && (!cover_letter || rev.nr > 1))
+					free(rev.message_id);
+				else
+					string_list_append_nodup(rev.ref_message_ids,
+								 rev.message_id);
+			}
+			gen_message_id(&rev, oid_to_hex(&commit->object.oid));
+		}
+
+		if (output_directory &&
+		    open_next_file(rev.numbered_files ? NULL : commit, NULL, &rev, quiet))
+			die(_("failed to create output files"));
+		shown = log_tree_commit(&rev, commit);
+		free_commit_buffer(the_repository->parsed_objects,
+				   commit);
+
+		/* We put one extra blank line between formatted
+		 * patches and this flag is used by log-tree code
+		 * to see if it needs to emit a LF before showing
+		 * the log; when using one file per patch, we do
+		 * not want the extra blank line.
+		 */
+		if (output_directory)
+			rev.shown_one = 0;
+		if (shown) {
+			print_bases(&bases, rev.diffopt.file);
+			if (rev.mime_boundary)
+				fprintf(rev.diffopt.file, "\n--%s%s--\n\n\n",
+				       mime_boundary_leader,
+				       rev.mime_boundary);
+			else
+				print_signature(signature, rev.diffopt.file);
+		}
+		if (output_directory) {
+			fclose(rev.diffopt.file);
+			rev.diffopt.file = NULL;
+		}
+	}
+	stop_progress(&progress);
+	free(list);
+	if (ignore_if_in_upstream)
+		free_patch_ids(&ids);
+
+done:
+	oid_array_clear(&idiff_prev);
+	strbuf_release(&idiff_title);
+	strbuf_release(&rdiff1);
+	strbuf_release(&rdiff2);
+	strbuf_release(&rdiff_title);
+	free(description_file);
+	free(signature_file_arg);
+	free(signature_to_free);
+	free(branch_name);
+	free(to_free);
+	free(rev.message_id);
+	if (rev.ref_message_ids)
+		string_list_clear(rev.ref_message_ids, 0);
+	free(rev.ref_message_ids);
+	rev.diffopt.no_free = 0;
+	release_revisions(&rev);
+	format_config_release(&cfg);
+	return 0;
+}
+
+static int add_pending_commit(const char *arg, struct rev_info *revs, int flags)
+{
+	struct object_id oid;
+	if (repo_get_oid(the_repository, arg, &oid) == 0) {
+		struct commit *commit = lookup_commit_reference(the_repository,
+								&oid);
+		if (commit) {
+			commit->object.flags |= flags;
+			add_pending_object(revs, &commit->object, arg);
+			return 0;
+		}
+	}
+	return -1;
+}
+
+static const char * const cherry_usage[] = {
+	N_("git cherry [-v] [<upstream> [<head> [<limit>]]]"),
+	NULL
+};
+
+static void print_commit(char sign, struct commit *commit, int verbose,
+			 int abbrev, FILE *file)
+{
+	if (!verbose) {
+		fprintf(file, "%c %s\n", sign,
+		       repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev));
+	} else {
+		struct strbuf buf = STRBUF_INIT;
+		pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
+		fprintf(file, "%c %s %s\n", sign,
+		       repo_find_unique_abbrev(the_repository, &commit->object.oid, abbrev),
+		       buf.buf);
+		strbuf_release(&buf);
+	}
+}
+
+int cmd_cherry(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct rev_info revs;
+	struct patch_ids ids;
+	struct commit *commit;
+	struct commit_list *list = NULL;
+	struct branch *current_branch;
+	const char *upstream;
+	const char *head = "HEAD";
+	const char *limit = NULL;
+	int verbose = 0, abbrev = 0;
+
+	struct option options[] = {
+		OPT__ABBREV(&abbrev),
+		OPT__VERBOSE(&verbose, N_("be verbose")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, cherry_usage, 0);
+
+	switch (argc) {
+	case 3:
+		limit = argv[2];
+		/* FALLTHROUGH */
+	case 2:
+		head = argv[1];
+		/* FALLTHROUGH */
+	case 1:
+		upstream = argv[0];
+		break;
+	default:
+		current_branch = branch_get(NULL);
+		upstream = branch_get_upstream(current_branch, NULL);
+		if (!upstream) {
+			fprintf(stderr, _("Could not find a tracked"
+					" remote branch, please"
+					" specify <upstream> manually.\n"));
+			usage_with_options(cherry_usage, options);
+		}
+	}
+
+	repo_init_revisions(the_repository, &revs, prefix);
+	revs.max_parents = 1;
+
+	if (add_pending_commit(head, &revs, 0))
+		die(_("unknown commit %s"), head);
+	if (add_pending_commit(upstream, &revs, UNINTERESTING))
+		die(_("unknown commit %s"), upstream);
+
+	/* Don't say anything if head and upstream are the same. */
+	if (revs.pending.nr == 2) {
+		struct object_array_entry *o = revs.pending.objects;
+		if (oideq(&o[0].item->oid, &o[1].item->oid))
+			return 0;
+	}
+
+	get_patch_ids(&revs, &ids);
+
+	if (limit && add_pending_commit(limit, &revs, UNINTERESTING))
+		die(_("unknown commit %s"), limit);
+
+	/* reverse the list of commits */
+	if (prepare_revision_walk(&revs))
+		die(_("revision walk setup failed"));
+	while ((commit = get_revision(&revs)) != NULL) {
+		commit_list_insert(commit, &list);
+	}
+
+	for (struct commit_list *l = list; l; l = l->next) {
+		char sign = '+';
+
+		commit = l->item;
+		if (has_commit_patch_id(commit, &ids))
+			sign = '-';
+		print_commit(sign, commit, verbose, abbrev, revs.diffopt.file);
+	}
+
+	free_commit_list(list);
+	free_patch_ids(&ids);
+	return 0;
+}
diff --git a/builtin/ls-files.c b/builtin/ls-files.c
new file mode 100644
index 0000000000..a4431429b7
--- /dev/null
+++ b/builtin/ls-files.c
@@ -0,0 +1,768 @@
+/*
+ * This merges the file listing in the directory cache index
+ * with the actual working directory list, and shows different
+ * combinations of the two.
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "convert.h"
+#include "quote.h"
+#include "dir.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "strbuf.h"
+#include "parse-options.h"
+#include "resolve-undo.h"
+#include "string-list.h"
+#include "path.h"
+#include "pathspec.h"
+#include "read-cache.h"
+#include "setup.h"
+#include "sparse-index.h"
+#include "submodule.h"
+#include "object-store.h"
+#include "hex.h"
+
+
+static int abbrev;
+static int show_deleted;
+static int show_cached;
+static int show_others;
+static int show_stage;
+static int show_unmerged;
+static int show_resolve_undo;
+static int show_modified;
+static int show_killed;
+static int show_valid_bit;
+static int show_fsmonitor_bit;
+static int line_terminator = '\n';
+static int debug_mode;
+static int show_eol;
+static int recurse_submodules;
+static int skipping_duplicates;
+static int show_sparse_dirs;
+
+static const char *prefix;
+static int max_prefix_len;
+static int prefix_len;
+static struct pathspec pathspec;
+static int error_unmatch;
+static char *ps_matched;
+static const char *with_tree;
+static int exc_given;
+static int exclude_args;
+static const char *format;
+
+static const char *tag_cached = "";
+static const char *tag_unmerged = "";
+static const char *tag_removed = "";
+static const char *tag_other = "";
+static const char *tag_killed = "";
+static const char *tag_modified = "";
+static const char *tag_skip_worktree = "";
+static const char *tag_resolve_undo = "";
+
+static void write_eolinfo(struct index_state *istate,
+			  const struct cache_entry *ce, const char *path)
+{
+	if (show_eol) {
+		struct stat st;
+		const char *i_txt = "";
+		const char *w_txt = "";
+		const char *a_txt = get_convert_attr_ascii(istate, path);
+		if (ce && S_ISREG(ce->ce_mode))
+			i_txt = get_cached_convert_stats_ascii(istate,
+							       ce->name);
+		if (!lstat(path, &st) && S_ISREG(st.st_mode))
+			w_txt = get_wt_convert_stats_ascii(path);
+		printf("i/%-5s w/%-5s attr/%-17s\t", i_txt, w_txt, a_txt);
+	}
+}
+
+static void write_name(const char *name)
+{
+	/*
+	 * With "--full-name", prefix_len=0; this caller needs to pass
+	 * an empty string in that case (a NULL is good for "").
+	 */
+	write_name_quoted_relative(name, prefix_len ? prefix : NULL,
+				   stdout, line_terminator);
+}
+
+static void write_name_to_buf(struct strbuf *sb, const char *name)
+{
+	struct strbuf buf = STRBUF_INIT;
+	const char *rel = relative_path(name, prefix_len ? prefix : NULL, &buf);
+
+	if (line_terminator)
+		quote_c_style(rel, sb, NULL, 0);
+	else
+		strbuf_addstr(sb, rel);
+
+	strbuf_release(&buf);
+}
+
+static const char *get_tag(const struct cache_entry *ce, const char *tag)
+{
+	static char alttag[4];
+
+	if (tag && *tag && ((show_valid_bit && (ce->ce_flags & CE_VALID)) ||
+		(show_fsmonitor_bit && (ce->ce_flags & CE_FSMONITOR_VALID)))) {
+		memcpy(alttag, tag, 3);
+
+		if (isalpha(tag[0])) {
+			alttag[0] = tolower(tag[0]);
+		} else if (tag[0] == '?') {
+			alttag[0] = '!';
+		} else {
+			alttag[0] = 'v';
+			alttag[1] = tag[0];
+			alttag[2] = ' ';
+			alttag[3] = 0;
+		}
+
+		tag = alttag;
+	}
+
+	return tag;
+}
+
+static void print_debug(const struct cache_entry *ce)
+{
+	if (debug_mode) {
+		const struct stat_data *sd = &ce->ce_stat_data;
+
+		printf("  ctime: %u:%u\n", sd->sd_ctime.sec, sd->sd_ctime.nsec);
+		printf("  mtime: %u:%u\n", sd->sd_mtime.sec, sd->sd_mtime.nsec);
+		printf("  dev: %u\tino: %u\n", sd->sd_dev, sd->sd_ino);
+		printf("  uid: %u\tgid: %u\n", sd->sd_uid, sd->sd_gid);
+		printf("  size: %u\tflags: %x\n", sd->sd_size, ce->ce_flags);
+	}
+}
+
+static void show_dir_entry(struct index_state *istate,
+			   const char *tag, struct dir_entry *ent)
+{
+	int len = max_prefix_len;
+
+	if (len > ent->len)
+		die("git ls-files: internal error - directory entry not superset of prefix");
+
+	/* If ps_matches is non-NULL, figure out which pathspec(s) match. */
+	if (ps_matched)
+		dir_path_match(istate, ent, &pathspec, len, ps_matched);
+
+	fputs(tag, stdout);
+	write_eolinfo(istate, NULL, ent->name);
+	write_name(ent->name);
+}
+
+static void show_other_files(struct index_state *istate,
+			     const struct dir_struct *dir)
+{
+	int i;
+
+	for (i = 0; i < dir->nr; i++) {
+		struct dir_entry *ent = dir->entries[i];
+		if (!index_name_is_other(istate, ent->name, ent->len))
+			continue;
+		show_dir_entry(istate, tag_other, ent);
+	}
+}
+
+static void show_killed_files(struct index_state *istate,
+			      const struct dir_struct *dir)
+{
+	int i;
+	for (i = 0; i < dir->nr; i++) {
+		struct dir_entry *ent = dir->entries[i];
+		char *cp, *sp;
+		int pos, len, killed = 0;
+
+		for (cp = ent->name; cp - ent->name < ent->len; cp = sp + 1) {
+			sp = strchr(cp, '/');
+			if (!sp) {
+				/* If ent->name is prefix of an entry in the
+				 * cache, it will be killed.
+				 */
+				pos = index_name_pos(istate, ent->name, ent->len);
+				if (0 <= pos)
+					BUG("killed-file %.*s not found",
+						ent->len, ent->name);
+				pos = -pos - 1;
+				while (pos < istate->cache_nr &&
+				       ce_stage(istate->cache[pos]))
+					pos++; /* skip unmerged */
+				if (istate->cache_nr <= pos)
+					break;
+				/* pos points at a name immediately after
+				 * ent->name in the cache.  Does it expect
+				 * ent->name to be a directory?
+				 */
+				len = ce_namelen(istate->cache[pos]);
+				if ((ent->len < len) &&
+				    !strncmp(istate->cache[pos]->name,
+					     ent->name, ent->len) &&
+				    istate->cache[pos]->name[ent->len] == '/')
+					killed = 1;
+				break;
+			}
+			if (0 <= index_name_pos(istate, ent->name, sp - ent->name)) {
+				/* If any of the leading directories in
+				 * ent->name is registered in the cache,
+				 * ent->name will be killed.
+				 */
+				killed = 1;
+				break;
+			}
+		}
+		if (killed)
+			show_dir_entry(istate, tag_killed, dir->entries[i]);
+	}
+}
+
+static void show_files(struct repository *repo, struct dir_struct *dir);
+
+static void show_submodule(struct repository *superproject,
+			   struct dir_struct *dir, const char *path)
+{
+	struct repository subrepo;
+
+	if (repo_submodule_init(&subrepo, superproject, path, null_oid()))
+		return;
+
+	if (repo_read_index(&subrepo) < 0)
+		die("index file corrupt");
+
+	show_files(&subrepo, dir);
+
+	repo_clear(&subrepo);
+}
+
+static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
+			      const enum object_type type, unsigned int padded)
+{
+	if (type == OBJ_BLOB) {
+		unsigned long size;
+		if (oid_object_info(the_repository, oid, &size) < 0)
+			die(_("could not get object info about '%s'"),
+			    oid_to_hex(oid));
+		if (padded)
+			strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
+		else
+			strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
+	} else if (padded) {
+		strbuf_addf(line, "%7s", "-");
+	} else {
+		strbuf_addstr(line, "-");
+	}
+}
+
+static void show_ce_fmt(struct repository *repo, const struct cache_entry *ce,
+			const char *format, const char *fullname) {
+	struct strbuf sb = STRBUF_INIT;
+
+	while (strbuf_expand_step(&sb, &format)) {
+		size_t len;
+		struct stat st;
+
+		if (skip_prefix(format, "%", &format))
+			strbuf_addch(&sb, '%');
+		else if ((len = strbuf_expand_literal(&sb, format)))
+			format += len;
+		else if (skip_prefix(format, "(objectmode)", &format))
+			strbuf_addf(&sb, "%06o", ce->ce_mode);
+		else if (skip_prefix(format, "(objectname)", &format))
+			strbuf_add_unique_abbrev(&sb, &ce->oid, abbrev);
+		else if (skip_prefix(format, "(objecttype)", &format))
+			strbuf_addstr(&sb, type_name(object_type(ce->ce_mode)));
+		else if (skip_prefix(format, "(objectsize:padded)", &format))
+			expand_objectsize(&sb, &ce->oid,
+					  object_type(ce->ce_mode), 1);
+		else if (skip_prefix(format, "(objectsize)", &format))
+			expand_objectsize(&sb, &ce->oid,
+					  object_type(ce->ce_mode), 0);
+		else if (skip_prefix(format, "(stage)", &format))
+			strbuf_addf(&sb, "%d", ce_stage(ce));
+		else if (skip_prefix(format, "(eolinfo:index)", &format))
+			strbuf_addstr(&sb, S_ISREG(ce->ce_mode) ?
+				      get_cached_convert_stats_ascii(repo->index,
+				      ce->name) : "");
+		else if (skip_prefix(format, "(eolinfo:worktree)", &format))
+			strbuf_addstr(&sb, !lstat(fullname, &st) &&
+				      S_ISREG(st.st_mode) ?
+				      get_wt_convert_stats_ascii(fullname) : "");
+		else if (skip_prefix(format, "(eolattr)", &format))
+			strbuf_addstr(&sb, get_convert_attr_ascii(repo->index,
+								 fullname));
+		else if (skip_prefix(format, "(path)", &format))
+			write_name_to_buf(&sb, fullname);
+		else
+			strbuf_expand_bad_format(format, "ls-files");
+	}
+	strbuf_addch(&sb, line_terminator);
+	fwrite(sb.buf, sb.len, 1, stdout);
+	strbuf_release(&sb);
+}
+
+static void show_ce(struct repository *repo, struct dir_struct *dir,
+		    const struct cache_entry *ce, const char *fullname,
+		    const char *tag)
+{
+	if (max_prefix_len > strlen(fullname))
+		die("git ls-files: internal error - cache entry not superset of prefix");
+
+	if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
+	    is_submodule_active(repo, ce->name)) {
+		show_submodule(repo, dir, ce->name);
+	} else if (match_pathspec(repo->index, &pathspec, fullname, strlen(fullname),
+				  max_prefix_len, ps_matched,
+				  S_ISDIR(ce->ce_mode) ||
+				  S_ISGITLINK(ce->ce_mode))) {
+		if (format) {
+			show_ce_fmt(repo, ce, format, fullname);
+			print_debug(ce);
+			return;
+		}
+
+		tag = get_tag(ce, tag);
+
+		if (!show_stage) {
+			fputs(tag, stdout);
+		} else {
+			printf("%s%06o %s %d\t",
+			       tag,
+			       ce->ce_mode,
+			       repo_find_unique_abbrev(repo, &ce->oid, abbrev),
+			       ce_stage(ce));
+		}
+		write_eolinfo(repo->index, ce, fullname);
+		write_name(fullname);
+		print_debug(ce);
+	}
+}
+
+static void show_ru_info(struct index_state *istate)
+{
+	struct string_list_item *item;
+
+	if (!istate->resolve_undo)
+		return;
+
+	for_each_string_list_item(item, istate->resolve_undo) {
+		const char *path = item->string;
+		struct resolve_undo_info *ui = item->util;
+		int i, len;
+
+		len = strlen(path);
+		if (len < max_prefix_len)
+			continue; /* outside of the prefix */
+		if (!match_pathspec(istate, &pathspec, path, len,
+				    max_prefix_len, ps_matched, 0))
+			continue; /* uninterested */
+		for (i = 0; i < 3; i++) {
+			if (!ui->mode[i])
+				continue;
+			printf("%s%06o %s %d\t", tag_resolve_undo, ui->mode[i],
+			       repo_find_unique_abbrev(the_repository, &ui->oid[i], abbrev),
+			       i + 1);
+			write_name(path);
+		}
+	}
+}
+
+static int ce_excluded(struct dir_struct *dir, struct index_state *istate,
+		       const char *fullname, const struct cache_entry *ce)
+{
+	int dtype = ce_to_dtype(ce);
+	return is_excluded(dir, istate, fullname, &dtype);
+}
+
+static void construct_fullname(struct strbuf *out, const struct repository *repo,
+			       const struct cache_entry *ce)
+{
+	strbuf_reset(out);
+	if (repo->submodule_prefix)
+		strbuf_addstr(out, repo->submodule_prefix);
+	strbuf_addstr(out, ce->name);
+}
+
+static void show_files(struct repository *repo, struct dir_struct *dir)
+{
+	int i;
+	struct strbuf fullname = STRBUF_INIT;
+
+	/* For cached/deleted files we don't need to even do the readdir */
+	if (show_others || show_killed) {
+		if (!show_others)
+			dir->flags |= DIR_COLLECT_KILLED_ONLY;
+		fill_directory(dir, repo->index, &pathspec);
+		if (show_others)
+			show_other_files(repo->index, dir);
+		if (show_killed)
+			show_killed_files(repo->index, dir);
+	}
+
+	if (!(show_cached || show_stage || show_deleted || show_modified))
+		return;
+
+	if (!show_sparse_dirs)
+		ensure_full_index(repo->index);
+
+	for (i = 0; i < repo->index->cache_nr; i++) {
+		const struct cache_entry *ce = repo->index->cache[i];
+		struct stat st;
+		int stat_err;
+
+		construct_fullname(&fullname, repo, ce);
+
+		if ((dir->flags & DIR_SHOW_IGNORED) &&
+			!ce_excluded(dir, repo->index, fullname.buf, ce))
+			continue;
+		if (ce->ce_flags & CE_UPDATE)
+			continue;
+		if ((show_cached || show_stage) &&
+		    (!show_unmerged || ce_stage(ce))) {
+			show_ce(repo, dir, ce, fullname.buf,
+				ce_stage(ce) ? tag_unmerged :
+				(ce_skip_worktree(ce) ? tag_skip_worktree :
+				 tag_cached));
+			if (skipping_duplicates)
+				goto skip_to_next_name;
+		}
+
+		if (!(show_deleted || show_modified))
+			continue;
+		if (ce_skip_worktree(ce))
+			continue;
+		stat_err = lstat(fullname.buf, &st);
+		if (stat_err && (errno != ENOENT && errno != ENOTDIR))
+			error_errno("cannot lstat '%s'", fullname.buf);
+		if (stat_err && show_deleted) {
+			show_ce(repo, dir, ce, fullname.buf, tag_removed);
+			if (skipping_duplicates)
+				goto skip_to_next_name;
+		}
+		if (show_modified &&
+		    (stat_err || ie_modified(repo->index, ce, &st, 0))) {
+			show_ce(repo, dir, ce, fullname.buf, tag_modified);
+			if (skipping_duplicates)
+				goto skip_to_next_name;
+		}
+		continue;
+
+skip_to_next_name:
+		{
+			int j;
+			struct cache_entry **cache = repo->index->cache;
+			for (j = i + 1; j < repo->index->cache_nr; j++)
+				if (strcmp(ce->name, cache[j]->name))
+					break;
+			i = j - 1; /* compensate for the for loop */
+		}
+	}
+
+	strbuf_release(&fullname);
+}
+
+/*
+ * Prune the index to only contain stuff starting with "prefix"
+ */
+static void prune_index(struct index_state *istate,
+			const char *prefix, size_t prefixlen)
+{
+	int pos;
+	unsigned int first, last;
+
+	if (!prefix || !istate->cache_nr)
+		return;
+	pos = index_name_pos(istate, prefix, prefixlen);
+	if (pos < 0)
+		pos = -pos-1;
+	first = pos;
+	last = istate->cache_nr;
+	while (last > first) {
+		int next = first + ((last - first) >> 1);
+		const struct cache_entry *ce = istate->cache[next];
+		if (!strncmp(ce->name, prefix, prefixlen)) {
+			first = next+1;
+			continue;
+		}
+		last = next;
+	}
+	MOVE_ARRAY(istate->cache, istate->cache + pos, last - pos);
+	istate->cache_nr = last - pos;
+}
+
+static int get_common_prefix_len(const char *common_prefix)
+{
+	int common_prefix_len;
+
+	if (!common_prefix)
+		return 0;
+
+	common_prefix_len = strlen(common_prefix);
+
+	/*
+	 * If the prefix has a trailing slash, strip it so that submodules won't
+	 * be pruned from the index.
+	 */
+	if (common_prefix[common_prefix_len - 1] == '/')
+		common_prefix_len--;
+
+	return common_prefix_len;
+}
+
+static const char * const ls_files_usage[] = {
+	N_("git ls-files [<options>] [<file>...]"),
+	NULL
+};
+
+static int option_parse_exclude(const struct option *opt,
+				const char *arg, int unset)
+{
+	struct string_list *exclude_list = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	exc_given = 1;
+	string_list_append(exclude_list, arg);
+
+	return 0;
+}
+
+static int option_parse_exclude_from(const struct option *opt,
+				     const char *arg, int unset)
+{
+	struct dir_struct *dir = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	exc_given = 1;
+	add_patterns_from_file(dir, arg);
+
+	return 0;
+}
+
+static int option_parse_exclude_standard(const struct option *opt,
+					 const char *arg, int unset)
+{
+	struct dir_struct *dir = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	exc_given = 1;
+	setup_standard_excludes(dir);
+
+	return 0;
+}
+
+int cmd_ls_files(int argc,
+		 const char **argv,
+		 const char *cmd_prefix,
+		 struct repository *repo UNUSED)
+{
+	int require_work_tree = 0, show_tag = 0, i;
+	char *max_prefix;
+	struct dir_struct dir = DIR_INIT;
+	struct pattern_list *pl;
+	struct string_list exclude_list = STRING_LIST_INIT_NODUP;
+	struct option builtin_ls_files_options[] = {
+		/* Think twice before adding "--nul" synonym to this */
+		OPT_SET_INT('z', NULL, &line_terminator,
+			N_("separate paths with the NUL character"), '\0'),
+		OPT_BOOL('t', NULL, &show_tag,
+			N_("identify the file status with tags")),
+		OPT_BOOL('v', NULL, &show_valid_bit,
+			N_("use lowercase letters for 'assume unchanged' files")),
+		OPT_BOOL('f', NULL, &show_fsmonitor_bit,
+			N_("use lowercase letters for 'fsmonitor clean' files")),
+		OPT_BOOL('c', "cached", &show_cached,
+			N_("show cached files in the output (default)")),
+		OPT_BOOL('d', "deleted", &show_deleted,
+			N_("show deleted files in the output")),
+		OPT_BOOL('m', "modified", &show_modified,
+			N_("show modified files in the output")),
+		OPT_BOOL('o', "others", &show_others,
+			N_("show other files in the output")),
+		OPT_BIT('i', "ignored", &dir.flags,
+			N_("show ignored files in the output"),
+			DIR_SHOW_IGNORED),
+		OPT_BOOL('s', "stage", &show_stage,
+			N_("show staged contents' object name in the output")),
+		OPT_BOOL('k', "killed", &show_killed,
+			N_("show files on the filesystem that need to be removed")),
+		OPT_BIT(0, "directory", &dir.flags,
+			N_("show 'other' directories' names only"),
+			DIR_SHOW_OTHER_DIRECTORIES),
+		OPT_BOOL(0, "eol", &show_eol, N_("show line endings of files")),
+		OPT_NEGBIT(0, "empty-directory", &dir.flags,
+			N_("don't show empty directories"),
+			DIR_HIDE_EMPTY_DIRECTORIES),
+		OPT_BOOL('u', "unmerged", &show_unmerged,
+			N_("show unmerged files in the output")),
+		OPT_BOOL(0, "resolve-undo", &show_resolve_undo,
+			    N_("show resolve-undo information")),
+		OPT_CALLBACK_F('x', "exclude", &exclude_list, N_("pattern"),
+			N_("skip files matching pattern"),
+			PARSE_OPT_NONEG, option_parse_exclude),
+		OPT_CALLBACK_F('X', "exclude-from", &dir, N_("file"),
+			N_("read exclude patterns from <file>"),
+			PARSE_OPT_NONEG, option_parse_exclude_from),
+		OPT_STRING(0, "exclude-per-directory", &dir.exclude_per_dir, N_("file"),
+			N_("read additional per-directory exclude patterns in <file>")),
+		OPT_CALLBACK_F(0, "exclude-standard", &dir, NULL,
+			N_("add the standard git exclusions"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			option_parse_exclude_standard),
+		OPT_SET_INT_F(0, "full-name", &prefix_len,
+			      N_("make the output relative to the project top directory"),
+			      0, PARSE_OPT_NONEG),
+		OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
+			N_("recurse through submodules")),
+		OPT_BOOL(0, "error-unmatch", &error_unmatch,
+			N_("if any <file> is not in the index, treat this as an error")),
+		OPT_STRING(0, "with-tree", &with_tree, N_("tree-ish"),
+			N_("pretend that paths removed since <tree-ish> are still present")),
+		OPT__ABBREV(&abbrev),
+		OPT_BOOL(0, "debug", &debug_mode, N_("show debugging data")),
+		OPT_BOOL(0, "deduplicate", &skipping_duplicates,
+			 N_("suppress duplicate entries")),
+		OPT_BOOL(0, "sparse", &show_sparse_dirs,
+			 N_("show sparse directories in the presence of a sparse index")),
+		OPT_STRING_F(0, "format", &format, N_("format"),
+			     N_("format to use for the output"),
+			     PARSE_OPT_NONEG),
+		OPT_END()
+	};
+	int ret = 0;
+
+	show_usage_with_options_if_asked(argc, argv,
+					 ls_files_usage, builtin_ls_files_options);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	prefix = cmd_prefix;
+	if (prefix)
+		prefix_len = strlen(prefix);
+	git_config(git_default_config, NULL);
+
+	if (repo_read_index(the_repository) < 0)
+		die("index file corrupt");
+
+	argc = parse_options(argc, argv, prefix, builtin_ls_files_options,
+			ls_files_usage, 0);
+	pl = add_pattern_list(&dir, EXC_CMDL, "--exclude option");
+	for (i = 0; i < exclude_list.nr; i++) {
+		add_pattern(exclude_list.items[i].string, "", 0, pl, --exclude_args);
+	}
+
+	if (format && (show_stage || show_others || show_killed ||
+		show_resolve_undo || skipping_duplicates || show_eol || show_tag))
+			usage_msg_opt(_("--format cannot be used with -s, -o, -k, -t, "
+				      "--resolve-undo, --deduplicate, --eol"),
+				      ls_files_usage, builtin_ls_files_options);
+
+	if (show_tag || show_valid_bit || show_fsmonitor_bit) {
+		tag_cached = "H ";
+		tag_unmerged = "M ";
+		tag_removed = "R ";
+		tag_modified = "C ";
+		tag_other = "? ";
+		tag_killed = "K ";
+		tag_skip_worktree = "S ";
+		tag_resolve_undo = "U ";
+	}
+	if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
+		require_work_tree = 1;
+	if (show_unmerged)
+		/*
+		 * There's no point in showing unmerged unless
+		 * you also show the stage information.
+		 */
+		show_stage = 1;
+	if (show_tag || show_stage)
+		skipping_duplicates = 0;
+	if (dir.exclude_per_dir)
+		exc_given = 1;
+
+	if (require_work_tree && !is_inside_work_tree())
+		setup_work_tree();
+
+	if (recurse_submodules &&
+	    (show_deleted || show_others || show_unmerged ||
+	     show_killed || show_modified || show_resolve_undo || with_tree))
+		die("ls-files --recurse-submodules unsupported mode");
+
+	if (recurse_submodules && error_unmatch)
+		die("ls-files --recurse-submodules does not support "
+		    "--error-unmatch");
+
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_CWD,
+		       prefix, argv);
+
+	/*
+	 * Find common prefix for all pathspec's
+	 * This is used as a performance optimization which unfortunately cannot
+	 * be done when recursing into submodules because when a pathspec is
+	 * given which spans repository boundaries you can't simply remove the
+	 * submodule entry because the pathspec may match something inside the
+	 * submodule.
+	 */
+	if (recurse_submodules)
+		max_prefix = NULL;
+	else
+		max_prefix = common_prefix(&pathspec);
+	max_prefix_len = get_common_prefix_len(max_prefix);
+
+	prune_index(the_repository->index, max_prefix, max_prefix_len);
+
+	/* Treat unmatching pathspec elements as errors */
+	if (pathspec.nr && error_unmatch)
+		ps_matched = xcalloc(pathspec.nr, 1);
+
+	if ((dir.flags & DIR_SHOW_IGNORED) && !show_others && !show_cached)
+		die("ls-files -i must be used with either -o or -c");
+
+	if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given)
+		die("ls-files --ignored needs some exclude pattern");
+
+	/* With no flags, we default to showing the cached files */
+	if (!(show_stage || show_deleted || show_others || show_unmerged ||
+	      show_killed || show_modified || show_resolve_undo))
+		show_cached = 1;
+
+	if (with_tree) {
+		/*
+		 * Basic sanity check; show-stages and show-unmerged
+		 * would not make any sense with this option.
+		 */
+		if (show_stage || show_unmerged)
+			die(_("options '%s' and '%s' cannot be used together"), "ls-files --with-tree", "-s/-u");
+		overlay_tree_on_index(the_repository->index, with_tree, max_prefix);
+	}
+
+	show_files(the_repository, &dir);
+
+	if (show_resolve_undo)
+		show_ru_info(the_repository->index);
+
+	if (ps_matched && report_path_error(ps_matched, &pathspec)) {
+		fprintf(stderr, "Did you forget to 'git add'?\n");
+		ret = 1;
+	}
+
+	string_list_clear(&exclude_list, 0);
+	dir_clear(&dir);
+	free(max_prefix);
+	return ret;
+}
diff --git a/builtin/ls-remote.c b/builtin/ls-remote.c
new file mode 100644
index 0000000000..42f34e1236
--- /dev/null
+++ b/builtin/ls-remote.c
@@ -0,0 +1,179 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
+#include "transport.h"
+#include "pkt-line.h"
+#include "ref-filter.h"
+#include "remote.h"
+#include "parse-options.h"
+#include "wildmatch.h"
+
+static const char * const ls_remote_usage[] = {
+	N_("git ls-remote [--branches] [--tags] [--refs] [--upload-pack=<exec>]\n"
+	   "              [-q | --quiet] [--exit-code] [--get-url] [--sort=<key>]\n"
+	   "              [--symref] [<repository> [<patterns>...]]"),
+	NULL
+};
+
+/*
+ * Is there one among the list of patterns that match the tail part
+ * of the path?
+ */
+static int tail_match(const struct strvec *pattern, const char *path)
+{
+	char *pathbuf;
+
+	if (!pattern->nr)
+		return 1; /* no restriction */
+
+	pathbuf = xstrfmt("/%s", path);
+	for (size_t i = 0; i < pattern->nr; i++) {
+		if (!wildmatch(pattern->v[i], pathbuf, 0)) {
+			free(pathbuf);
+			return 1;
+		}
+	}
+	free(pathbuf);
+	return 0;
+}
+
+int cmd_ls_remote(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	const char *dest = NULL;
+	unsigned flags = 0;
+	int get_url = 0;
+	int quiet = 0;
+	int status = 0;
+	int show_symref_target = 0;
+	const char *uploadpack = NULL;
+	struct strvec pattern = STRVEC_INIT;
+	struct transport_ls_refs_options transport_options =
+		TRANSPORT_LS_REFS_OPTIONS_INIT;
+	int i;
+	struct string_list server_options = STRING_LIST_INIT_DUP;
+
+	struct remote *remote;
+	struct transport *transport;
+	const struct ref *ref;
+	struct ref_array ref_array;
+	struct ref_sorting *sorting;
+	struct string_list sorting_options = STRING_LIST_INIT_DUP;
+
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("do not print remote URL")),
+		OPT_STRING(0, "upload-pack", &uploadpack, N_("exec"),
+			   N_("path of git-upload-pack on the remote host")),
+		{ OPTION_STRING, 0, "exec", &uploadpack, N_("exec"),
+			   N_("path of git-upload-pack on the remote host"),
+			   PARSE_OPT_HIDDEN },
+		OPT_BIT('t', "tags", &flags, N_("limit to tags"), REF_TAGS),
+		OPT_BIT('b', "branches", &flags, N_("limit to branches"), REF_BRANCHES),
+		OPT_BIT_F('h', "heads", &flags,
+			  N_("deprecated synonym for --branches"), REF_BRANCHES,
+			  PARSE_OPT_HIDDEN),
+		OPT_BIT(0, "refs", &flags, N_("do not show peeled tags"), REF_NORMAL),
+		OPT_BOOL(0, "get-url", &get_url,
+			 N_("take url.<base>.insteadOf into account")),
+		OPT_REF_SORT(&sorting_options),
+		OPT_SET_INT_F(0, "exit-code", &status,
+			      N_("exit with exit code 2 if no matching refs are found"),
+			      2, PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "symref", &show_symref_target,
+			 N_("show underlying ref in addition to the object pointed by it")),
+		OPT_STRING_LIST('o', "server-option", &server_options, N_("server-specific"), N_("option to transmit")),
+		OPT_END()
+	};
+
+	memset(&ref_array, 0, sizeof(ref_array));
+
+	argc = parse_options(argc, argv, prefix, options, ls_remote_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	dest = argv[0];
+
+	/*
+	 * TODO: This is buggy, but required for transport helpers. When a
+	 * transport helper advertises a "refspec", then we'd add that to a
+	 * list of refspecs via `refspec_append()`, which transitively depends
+	 * on `the_hash_algo`. Thus, when the hash algorithm isn't properly set
+	 * up, this would lead to a segfault.
+	 *
+	 * We really should fix this in the transport helper logic such that we
+	 * lazily parse refspec capabilities _after_ we have learned about the
+	 * remote's object format. Otherwise, we may end up misparsing refspecs
+	 * depending on what object hash the remote uses.
+	 */
+	if (!the_repository->hash_algo)
+		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
+	packet_trace_identity("ls-remote");
+
+	for (int i = 1; i < argc; i++)
+		strvec_pushf(&pattern, "*/%s", argv[i]);
+
+	if (flags & REF_TAGS)
+		strvec_push(&transport_options.ref_prefixes, "refs/tags/");
+	if (flags & REF_BRANCHES)
+		strvec_push(&transport_options.ref_prefixes, "refs/heads/");
+
+	remote = remote_get(dest);
+	if (!remote) {
+		if (dest)
+			die("bad repository '%s'", dest);
+		die("No remote configured to list refs from.");
+	}
+
+	if (get_url) {
+		printf("%s\n", remote->url.v[0]);
+		return 0;
+	}
+
+	transport = transport_get(remote, NULL);
+	if (uploadpack)
+		transport_set_option(transport, TRANS_OPT_UPLOADPACK, uploadpack);
+	if (server_options.nr)
+		transport->server_options = &server_options;
+
+	ref = transport_get_remote_refs(transport, &transport_options);
+	if (ref) {
+		int hash_algo = hash_algo_by_ptr(transport_get_hash_algo(transport));
+		repo_set_hash_algo(the_repository, hash_algo);
+	}
+
+	if (!dest && !quiet)
+		fprintf(stderr, "From %s\n", remote->url.v[0]);
+	for ( ; ref; ref = ref->next) {
+		struct ref_array_item *item;
+		if (!check_ref_type(ref, flags))
+			continue;
+		if (!tail_match(&pattern, ref->name))
+			continue;
+		item = ref_array_push(&ref_array, ref->name, &ref->old_oid);
+		item->symref = xstrdup_or_null(ref->symref);
+	}
+
+	sorting = ref_sorting_options(&sorting_options);
+	ref_array_sort(sorting, &ref_array);
+
+	for (i = 0; i < ref_array.nr; i++) {
+		const struct ref_array_item *ref = ref_array.items[i];
+		if (show_symref_target && ref->symref)
+			printf("ref: %s\t%s\n", ref->symref, ref->refname);
+		printf("%s\t%s\n", oid_to_hex(&ref->objectname), ref->refname);
+		status = 0; /* we found something */
+	}
+
+	string_list_clear(&server_options, 0);
+	ref_sorting_release(sorting);
+	ref_array_clear(&ref_array);
+	if (transport_disconnect(transport))
+		status = 1;
+	transport_ls_refs_options_release(&transport_options);
+
+	strvec_clear(&pattern);
+	string_list_clear(&server_options, 0);
+	return status;
+}
diff --git a/builtin/ls-tree.c b/builtin/ls-tree.c
new file mode 100644
index 0000000000..8542b5d53e
--- /dev/null
+++ b/builtin/ls-tree.c
@@ -0,0 +1,451 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "tree.h"
+#include "path.h"
+#include "quote.h"
+#include "parse-options.h"
+#include "pathspec.h"
+
+static const char * const ls_tree_usage[] = {
+	N_("git ls-tree [<options>] <tree-ish> [<path>...]"),
+	NULL
+};
+
+static void expand_objectsize(struct strbuf *line, const struct object_id *oid,
+			      const enum object_type type, unsigned int padded)
+{
+	if (type == OBJ_BLOB) {
+		unsigned long size;
+		if (oid_object_info(the_repository, oid, &size) < 0)
+			die(_("could not get object info about '%s'"),
+			    oid_to_hex(oid));
+		if (padded)
+			strbuf_addf(line, "%7"PRIuMAX, (uintmax_t)size);
+		else
+			strbuf_addf(line, "%"PRIuMAX, (uintmax_t)size);
+	} else if (padded) {
+		strbuf_addf(line, "%7s", "-");
+	} else {
+		strbuf_addstr(line, "-");
+	}
+}
+
+struct ls_tree_options {
+	unsigned null_termination:1;
+	int abbrev;
+	enum ls_tree_path_options {
+		LS_RECURSIVE = 1 << 0,
+		LS_TREE_ONLY = 1 << 1,
+		LS_SHOW_TREES = 1 << 2,
+	} ls_options;
+	struct pathspec pathspec;
+	const char *prefix;
+	const char *format;
+};
+
+static int show_recursive(struct ls_tree_options *options, const char *base,
+			  size_t baselen, const char *pathname)
+{
+	int i;
+
+	if (options->ls_options & LS_RECURSIVE)
+		return 1;
+
+	if (!options->pathspec.nr)
+		return 0;
+
+	for (i = 0; i < options->pathspec.nr; i++) {
+		const char *spec = options->pathspec.items[i].match;
+		size_t len, speclen;
+
+		if (strncmp(base, spec, baselen))
+			continue;
+		len = strlen(pathname);
+		spec += baselen;
+		speclen = strlen(spec);
+		if (speclen <= len)
+			continue;
+		if (spec[len] && spec[len] != '/')
+			continue;
+		if (memcmp(pathname, spec, len))
+			continue;
+		return 1;
+	}
+	return 0;
+}
+
+static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
+			 const char *pathname, unsigned mode, void *context)
+{
+	struct ls_tree_options *options = context;
+	int recurse = 0;
+	struct strbuf sb = STRBUF_INIT;
+	enum object_type type = object_type(mode);
+	const char *format = options->format;
+
+	if (type == OBJ_TREE && show_recursive(options, base->buf, base->len, pathname))
+		recurse = READ_TREE_RECURSIVE;
+	if (type == OBJ_TREE && recurse && !(options->ls_options & LS_SHOW_TREES))
+		return recurse;
+	if (type == OBJ_BLOB && (options->ls_options & LS_TREE_ONLY))
+		return 0;
+
+	while (strbuf_expand_step(&sb, &format)) {
+		size_t len;
+
+		if (skip_prefix(format, "%", &format))
+			strbuf_addch(&sb, '%');
+		else if ((len = strbuf_expand_literal(&sb, format)))
+			format += len;
+		else if (skip_prefix(format, "(objectmode)", &format))
+			strbuf_addf(&sb, "%06o", mode);
+		else if (skip_prefix(format, "(objecttype)", &format))
+			strbuf_addstr(&sb, type_name(type));
+		else if (skip_prefix(format, "(objectsize:padded)", &format))
+			expand_objectsize(&sb, oid, type, 1);
+		else if (skip_prefix(format, "(objectsize)", &format))
+			expand_objectsize(&sb, oid, type, 0);
+		else if (skip_prefix(format, "(objectname)", &format))
+			strbuf_add_unique_abbrev(&sb, oid, options->abbrev);
+		else if (skip_prefix(format, "(path)", &format)) {
+			const char *name;
+			const char *prefix = options->prefix;
+			struct strbuf sbuf = STRBUF_INIT;
+			size_t baselen = base->len;
+
+			strbuf_addstr(base, pathname);
+			name = relative_path(base->buf, prefix, &sbuf);
+			quote_c_style(name, &sb, NULL, 0);
+			strbuf_setlen(base, baselen);
+			strbuf_release(&sbuf);
+		} else
+			strbuf_expand_bad_format(format, "ls-tree");
+	}
+	strbuf_addch(&sb, options->null_termination ? '\0' : '\n');
+	fwrite(sb.buf, sb.len, 1, stdout);
+	strbuf_release(&sb);
+	return recurse;
+}
+
+static int show_tree_common(struct ls_tree_options *options, int *recurse,
+			    struct strbuf *base, const char *pathname,
+			    enum object_type type)
+{
+	int ret = -1;
+	*recurse = 0;
+
+	if (type == OBJ_BLOB) {
+		if (options->ls_options & LS_TREE_ONLY)
+			ret = 0;
+	} else if (type == OBJ_TREE &&
+		   show_recursive(options, base->buf, base->len, pathname)) {
+		*recurse = READ_TREE_RECURSIVE;
+		if (!(options->ls_options & LS_SHOW_TREES))
+			ret = *recurse;
+	}
+
+	return ret;
+}
+
+static void show_tree_common_default_long(struct ls_tree_options *options,
+					  struct strbuf *base,
+					  const char *pathname,
+					  const size_t baselen)
+{
+	const char *prefix = options->prefix;
+
+	strbuf_addstr(base, pathname);
+
+	if (options->null_termination) {
+		struct strbuf sb = STRBUF_INIT;
+		const char *name = relative_path(base->buf, prefix, &sb);
+
+		fputs(name, stdout);
+		fputc('\0', stdout);
+
+		strbuf_release(&sb);
+	} else {
+		write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+	}
+
+	strbuf_setlen(base, baselen);
+}
+
+static int show_tree_default(const struct object_id *oid, struct strbuf *base,
+			     const char *pathname, unsigned mode,
+			     void *context)
+{
+	struct ls_tree_options *options = context;
+	int early;
+	int recurse;
+	enum object_type type = object_type(mode);
+
+	early = show_tree_common(options, &recurse, base, pathname, type);
+	if (early >= 0)
+		return early;
+
+	printf("%06o %s %s\t", mode, type_name(object_type(mode)),
+	       repo_find_unique_abbrev(the_repository, oid, options->abbrev));
+	show_tree_common_default_long(options, base, pathname, base->len);
+	return recurse;
+}
+
+static int show_tree_long(const struct object_id *oid, struct strbuf *base,
+			  const char *pathname, unsigned mode,
+			  void *context)
+{
+	struct ls_tree_options *options = context;
+	int early;
+	int recurse;
+	char size_text[24];
+	enum object_type type = object_type(mode);
+
+	early = show_tree_common(options, &recurse, base, pathname, type);
+	if (early >= 0)
+		return early;
+
+	if (type == OBJ_BLOB) {
+		unsigned long size;
+		if (oid_object_info(the_repository, oid, &size) == OBJ_BAD)
+			xsnprintf(size_text, sizeof(size_text), "BAD");
+		else
+			xsnprintf(size_text, sizeof(size_text),
+				  "%" PRIuMAX, (uintmax_t)size);
+	} else {
+		xsnprintf(size_text, sizeof(size_text), "-");
+	}
+
+	printf("%06o %s %s %7s\t", mode, type_name(type),
+	       repo_find_unique_abbrev(the_repository, oid, options->abbrev),
+	       size_text);
+	show_tree_common_default_long(options, base, pathname, base->len);
+	return recurse;
+}
+
+static int show_tree_name_only(const struct object_id *oid UNUSED,
+			       struct strbuf *base,
+			       const char *pathname, unsigned mode,
+			       void *context)
+{
+	struct ls_tree_options *options = context;
+	int early;
+	int recurse;
+	const size_t baselen = base->len;
+	enum object_type type = object_type(mode);
+	const char *prefix;
+
+	early = show_tree_common(options, &recurse, base, pathname, type);
+	if (early >= 0)
+		return early;
+
+	prefix = options->prefix;
+	strbuf_addstr(base, pathname);
+	if (options->null_termination) {
+		struct strbuf sb = STRBUF_INIT;
+		const char *name = relative_path(base->buf, prefix, &sb);
+
+		fputs(name, stdout);
+		fputc('\0', stdout);
+
+		strbuf_release(&sb);
+	} else {
+		write_name_quoted_relative(base->buf, prefix, stdout, '\n');
+	}
+	strbuf_setlen(base, baselen);
+	return recurse;
+}
+
+static int show_tree_object(const struct object_id *oid, struct strbuf *base,
+			    const char *pathname, unsigned mode,
+			    void *context)
+{
+	struct ls_tree_options *options = context;
+	int early;
+	int recurse;
+	enum object_type type = object_type(mode);
+	const char *str;
+
+	early = show_tree_common(options, &recurse, base, pathname, type);
+	if (early >= 0)
+		return early;
+
+	str = repo_find_unique_abbrev(the_repository, oid, options->abbrev);
+	if (options->null_termination) {
+		fputs(str, stdout);
+		fputc('\0', stdout);
+	} else  {
+		puts(str);
+	}
+	return recurse;
+}
+
+enum ls_tree_cmdmode {
+	MODE_DEFAULT = 0,
+	MODE_LONG,
+	MODE_NAME_ONLY,
+	MODE_NAME_STATUS,
+	MODE_OBJECT_ONLY,
+};
+
+struct ls_tree_cmdmode_to_fmt {
+	enum ls_tree_cmdmode mode;
+	const char *const fmt;
+	read_tree_fn_t fn;
+};
+
+static struct ls_tree_cmdmode_to_fmt ls_tree_cmdmode_format[] = {
+	{
+		.mode = MODE_DEFAULT,
+		.fmt = "%(objectmode) %(objecttype) %(objectname)%x09%(path)",
+		.fn = show_tree_default,
+	},
+	{
+		.mode = MODE_LONG,
+		.fmt = "%(objectmode) %(objecttype) %(objectname) %(objectsize:padded)%x09%(path)",
+		.fn = show_tree_long,
+	},
+	{
+		.mode = MODE_NAME_ONLY, /* And MODE_NAME_STATUS */
+		.fmt = "%(path)",
+		.fn = show_tree_name_only,
+	},
+	{
+		.mode = MODE_OBJECT_ONLY,
+		.fmt = "%(objectname)",
+		.fn = show_tree_object
+	},
+	{
+		/* fallback */
+		.fn = show_tree_default,
+	},
+};
+
+int cmd_ls_tree(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
+{
+	struct object_id oid;
+	struct tree *tree;
+	int i, full_tree = 0;
+	int full_name = !prefix || !*prefix;
+	read_tree_fn_t fn = NULL;
+	enum ls_tree_cmdmode cmdmode = MODE_DEFAULT;
+	int null_termination = 0;
+	struct ls_tree_options options = { 0 };
+	const struct option ls_tree_options[] = {
+		OPT_BIT('d', NULL, &options.ls_options, N_("only show trees"),
+			LS_TREE_ONLY),
+		OPT_BIT('r', NULL, &options.ls_options, N_("recurse into subtrees"),
+			LS_RECURSIVE),
+		OPT_BIT('t', NULL, &options.ls_options, N_("show trees when recursing"),
+			LS_SHOW_TREES),
+		OPT_BOOL('z', NULL, &null_termination,
+			 N_("terminate entries with NUL byte")),
+		OPT_CMDMODE('l', "long", &cmdmode, N_("include object size"),
+			    MODE_LONG),
+		OPT_CMDMODE(0, "name-only", &cmdmode, N_("list only filenames"),
+			    MODE_NAME_ONLY),
+		OPT_CMDMODE(0, "name-status", &cmdmode, N_("list only filenames"),
+			    MODE_NAME_STATUS),
+		OPT_CMDMODE(0, "object-only", &cmdmode, N_("list only objects"),
+			    MODE_OBJECT_ONLY),
+		OPT_BOOL(0, "full-name", &full_name, N_("use full path names")),
+		OPT_BOOL(0, "full-tree", &full_tree,
+			 N_("list entire tree; not just current directory "
+			    "(implies --full-name)")),
+		OPT_STRING_F(0, "format", &options.format, N_("format"),
+					 N_("format to use for the output"),
+					 PARSE_OPT_NONEG),
+		OPT__ABBREV(&options.abbrev),
+		OPT_END()
+	};
+	struct ls_tree_cmdmode_to_fmt *m2f = ls_tree_cmdmode_format;
+	struct object_context obj_context = {0};
+	int ret;
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, ls_tree_options,
+			     ls_tree_usage, 0);
+	options.null_termination = null_termination;
+
+	if (full_tree)
+		prefix = NULL;
+	options.prefix = full_name ? NULL : prefix;
+
+	/*
+	 * We wanted to detect conflicts between --name-only and
+	 * --name-status, but once we're done with that subsequent
+	 * code should only need to check the primary name.
+	 */
+	if (cmdmode == MODE_NAME_STATUS)
+		cmdmode = MODE_NAME_ONLY;
+
+	/* -d -r should imply -t, but -d by itself should not have to. */
+	if ( (LS_TREE_ONLY|LS_RECURSIVE) ==
+	    ((LS_TREE_ONLY|LS_RECURSIVE) & options.ls_options))
+		options.ls_options |= LS_SHOW_TREES;
+
+	if (options.format && cmdmode)
+		usage_msg_opt(
+			_("--format can't be combined with other format-altering options"),
+			ls_tree_usage, ls_tree_options);
+	if (argc < 1)
+		usage_with_options(ls_tree_usage, ls_tree_options);
+	if (get_oid_with_context(the_repository, argv[0],
+				 GET_OID_HASH_ANY, &oid,
+				 &obj_context))
+		die("Not a valid object name %s", argv[0]);
+
+	/*
+	 * show_recursive() rolls its own matching code and is
+	 * generally ignorant of 'struct pathspec'. The magic mask
+	 * cannot be lifted until it is converted to use
+	 * match_pathspec() or tree_entry_interesting()
+	 */
+	parse_pathspec(&options.pathspec, PATHSPEC_ALL_MAGIC &
+		       ~(PATHSPEC_FROMTOP | PATHSPEC_LITERAL),
+		       PATHSPEC_PREFER_CWD,
+		       prefix, argv + 1);
+	for (i = 0; i < options.pathspec.nr; i++)
+		options.pathspec.items[i].nowildcard_len = options.pathspec.items[i].len;
+	options.pathspec.has_wildcard = 0;
+	tree = parse_tree_indirect(&oid);
+	if (!tree)
+		die("not a tree object");
+	/*
+	 * The generic show_tree_fmt() is slower than show_tree(), so
+	 * take the fast path if possible.
+	 */
+	while (m2f) {
+		if (!m2f->fmt) {
+			fn = options.format ? show_tree_fmt : show_tree_default;
+		} else if (options.format && !strcmp(options.format, m2f->fmt)) {
+			cmdmode = m2f->mode;
+			fn = m2f->fn;
+		} else if (!options.format && cmdmode == m2f->mode) {
+			fn = m2f->fn;
+		} else {
+			m2f++;
+			continue;
+		}
+		break;
+	}
+
+	ret = !!read_tree(the_repository, tree, &options.pathspec, fn, &options);
+	clear_pathspec(&options.pathspec);
+	object_context_release(&obj_context);
+	return ret;
+}
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
new file mode 100644
index 0000000000..8de7ba7de1
--- /dev/null
+++ b/builtin/mailinfo.c
@@ -0,0 +1,119 @@
+/*
+ * Another stupid program, this one parsing the headers of an
+ * email to figure out authorship and subject
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "strbuf.h"
+#include "mailinfo.h"
+#include "parse-options.h"
+
+static const char * const mailinfo_usage[] = {
+	/* TRANSLATORS: keep <> in "<" mail ">" info. */
+	N_("git mailinfo [<options>] <msg> <patch> < mail >info"),
+	NULL,
+};
+
+struct metainfo_charset
+{
+	enum {
+		CHARSET_DEFAULT,
+		CHARSET_NO_REENCODE,
+		CHARSET_EXPLICIT,
+	} policy;
+	const char *charset;
+};
+
+static int parse_opt_explicit_encoding(const struct option *opt,
+				       const char *arg, int unset)
+{
+	struct metainfo_charset *meta_charset = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	meta_charset->policy = CHARSET_EXPLICIT;
+	meta_charset->charset = arg;
+
+	return 0;
+}
+
+static int parse_opt_quoted_cr(const struct option *opt, const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+
+	if (mailinfo_parse_quoted_cr_action(arg, opt->value) != 0)
+		return error(_("bad action '%s' for '%s'"), arg, "--quoted-cr");
+	return 0;
+}
+
+int cmd_mailinfo(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct metainfo_charset meta_charset;
+	struct mailinfo mi;
+	int status;
+	char *msgfile, *patchfile;
+
+	struct option options[] = {
+		OPT_BOOL('k', NULL, &mi.keep_subject, N_("keep subject")),
+		OPT_BOOL('b', NULL, &mi.keep_non_patch_brackets_in_subject,
+			 N_("keep non patch brackets in subject")),
+		OPT_BOOL('m', "message-id", &mi.add_message_id,
+			 N_("copy Message-ID to the end of commit message")),
+		OPT_SET_INT_F('u', NULL, &meta_charset.policy,
+			      N_("re-code metadata to i18n.commitEncoding"),
+			      CHARSET_DEFAULT, PARSE_OPT_NONEG),
+		OPT_SET_INT_F('n', NULL, &meta_charset.policy,
+			      N_("disable charset re-coding of metadata"),
+			      CHARSET_NO_REENCODE, PARSE_OPT_NONEG),
+		OPT_CALLBACK_F(0, "encoding", &meta_charset, N_("encoding"),
+			       N_("re-code metadata to this encoding"),
+			       PARSE_OPT_NONEG, parse_opt_explicit_encoding),
+		OPT_BOOL(0, "scissors", &mi.use_scissors, N_("use scissors")),
+		OPT_CALLBACK_F(0, "quoted-cr", &mi.quoted_cr, N_("<action>"),
+			       N_("action when quoted CR is found"),
+			       PARSE_OPT_NONEG, parse_opt_quoted_cr),
+		OPT_HIDDEN_BOOL(0, "inbody-headers", &mi.use_inbody_headers,
+			 N_("use headers in message's body")),
+		OPT_END()
+	};
+
+	setup_mailinfo(the_repository, &mi);
+	meta_charset.policy = CHARSET_DEFAULT;
+
+	argc = parse_options(argc, argv, prefix, options, mailinfo_usage, 0);
+
+	if (argc != 2)
+		usage_with_options(mailinfo_usage, options);
+
+	switch (meta_charset.policy) {
+	case CHARSET_DEFAULT:
+		mi.metainfo_charset = get_commit_output_encoding();
+		break;
+	case CHARSET_NO_REENCODE:
+		mi.metainfo_charset = NULL;
+		break;
+	case CHARSET_EXPLICIT:
+		break;
+	default:
+		BUG("invalid meta_charset.policy");
+	}
+
+	mi.input = stdin;
+	mi.output = stdout;
+
+	msgfile = prefix_filename(prefix, argv[0]);
+	patchfile = prefix_filename(prefix, argv[1]);
+
+	status = !!mailinfo(&mi, msgfile, patchfile);
+	clear_mailinfo(&mi);
+
+	free(msgfile);
+	free(patchfile);
+	return status;
+}
diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
new file mode 100644
index 0000000000..264df6259a
--- /dev/null
+++ b/builtin/mailsplit.c
@@ -0,0 +1,377 @@
+/*
+ * Totally braindamaged mbox splitter program.
+ *
+ * It just splits a mbox into a list of files: "0001" "0002" ..
+ * so you can process them further from there.
+ */
+
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "gettext.h"
+#include "string-list.h"
+#include "strbuf.h"
+
+static const char git_mailsplit_usage[] =
+"git mailsplit [-d<prec>] [-f<n>] [-b] [--keep-cr] -o<directory> [(<mbox>|<Maildir>)...]";
+
+static int is_from_line(const char *line, int len)
+{
+	const char *colon;
+
+	if (len < 20 || memcmp("From ", line, 5))
+		return 0;
+
+	colon = line + len - 2;
+	line += 5;
+	for (;;) {
+		if (colon < line)
+			return 0;
+		if (*--colon == ':')
+			break;
+	}
+
+	if (!isdigit(colon[-4]) ||
+	    !isdigit(colon[-2]) ||
+	    !isdigit(colon[-1]) ||
+	    !isdigit(colon[ 1]) ||
+	    !isdigit(colon[ 2]))
+		return 0;
+
+	/* year */
+	if (strtol(colon+3, NULL, 10) <= 90)
+		return 0;
+
+	/* Ok, close enough */
+	return 1;
+}
+
+static struct strbuf buf = STRBUF_INIT;
+static int keep_cr;
+static int mboxrd;
+
+static int is_gtfrom(const struct strbuf *buf)
+{
+	size_t min = strlen(">From ");
+	size_t ngt;
+
+	if (buf->len < min)
+		return 0;
+
+	ngt = strspn(buf->buf, ">");
+	return ngt && starts_with(buf->buf + ngt, "From ");
+}
+
+/* Called with the first line (potentially partial)
+ * already in buf[] -- normally that should begin with
+ * the Unix "From " line.  Write it into the specified
+ * file.
+ */
+static int split_one(FILE *mbox, const char *name, int allow_bare)
+{
+	FILE *output;
+	int fd;
+	int status = 0;
+	int is_bare = !is_from_line(buf.buf, buf.len);
+
+	if (is_bare && !allow_bare) {
+		fprintf(stderr, "corrupt mailbox\n");
+		exit(1);
+	}
+	fd = xopen(name, O_WRONLY | O_CREAT | O_EXCL, 0666);
+	output = xfdopen(fd, "w");
+
+	/* Copy it out, while searching for a line that begins with
+	 * "From " and having something that looks like a date format.
+	 */
+	for (;;) {
+		if (!keep_cr && buf.len > 1 && buf.buf[buf.len-1] == '\n' &&
+			buf.buf[buf.len-2] == '\r') {
+			strbuf_setlen(&buf, buf.len-2);
+			strbuf_addch(&buf, '\n');
+		}
+
+		if (mboxrd && is_gtfrom(&buf))
+			strbuf_remove(&buf, 0, 1);
+
+		if (fwrite(buf.buf, 1, buf.len, output) != buf.len)
+			die_errno("cannot write output");
+
+		if (strbuf_getwholeline(&buf, mbox, '\n')) {
+			if (feof(mbox)) {
+				status = 1;
+				break;
+			}
+			die_errno("cannot read mbox");
+		}
+		if (!is_bare && is_from_line(buf.buf, buf.len))
+			break; /* done with one message */
+	}
+	fclose(output);
+	return status;
+}
+
+static int populate_maildir_list(struct string_list *list, const char *path)
+{
+	DIR *dir;
+	struct dirent *dent;
+	char *name = NULL;
+	const char *subs[] = { "cur", "new", NULL };
+	const char **sub;
+	int ret = -1;
+
+	for (sub = subs; *sub; ++sub) {
+		free(name);
+		name = xstrfmt("%s/%s", path, *sub);
+		if (!(dir = opendir(name))) {
+			if (errno == ENOENT)
+				continue;
+			error_errno("cannot opendir %s", name);
+			goto out;
+		}
+
+		while ((dent = readdir(dir)) != NULL) {
+			if (dent->d_name[0] == '.')
+				continue;
+			free(name);
+			name = xstrfmt("%s/%s", *sub, dent->d_name);
+			string_list_insert(list, name);
+		}
+
+		closedir(dir);
+	}
+
+	ret = 0;
+
+out:
+	free(name);
+	return ret;
+}
+
+static int maildir_filename_cmp(const char *a, const char *b)
+{
+	while (*a && *b) {
+		if (isdigit(*a) && isdigit(*b)) {
+			long int na, nb;
+			na = strtol(a, (char **)&a, 10);
+			nb = strtol(b, (char **)&b, 10);
+			if (na != nb)
+				return na - nb;
+			/* strtol advanced our pointers */
+		}
+		else {
+			if (*a != *b)
+				return (unsigned char)*a - (unsigned char)*b;
+			a++;
+			b++;
+		}
+	}
+	return (unsigned char)*a - (unsigned char)*b;
+}
+
+static int split_maildir(const char *maildir, const char *dir,
+	int nr_prec, int skip)
+{
+	char *file = NULL;
+	FILE *f = NULL;
+	int ret = -1;
+	struct string_list list = STRING_LIST_INIT_DUP;
+
+	list.cmp = maildir_filename_cmp;
+
+	if (populate_maildir_list(&list, maildir) < 0)
+		goto out;
+
+	for (size_t i = 0; i < list.nr; i++) {
+		char *name;
+
+		free(file);
+		file = xstrfmt("%s/%s", maildir, list.items[i].string);
+
+		f = fopen(file, "r");
+		if (!f) {
+			error_errno("cannot open mail %s", file);
+			goto out;
+		}
+
+		if (strbuf_getwholeline(&buf, f, '\n')) {
+			error_errno("cannot read mail %s", file);
+			goto out;
+		}
+
+		name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
+		split_one(f, name, 1);
+		free(name);
+
+		fclose(f);
+		f = NULL;
+	}
+
+	ret = skip;
+out:
+	if (f)
+		fclose(f);
+	free(file);
+	string_list_clear(&list, 1);
+	return ret;
+}
+
+static int split_mbox(const char *file, const char *dir, int allow_bare,
+		      int nr_prec, int skip)
+{
+	int ret = -1;
+	int peek;
+
+	FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
+	int file_done = 0;
+
+	if (isatty(fileno(f)))
+		warning(_("reading patches from stdin/tty..."));
+
+	if (!f) {
+		error_errno("cannot open mbox %s", file);
+		goto out;
+	}
+
+	do {
+		peek = fgetc(f);
+		if (peek == EOF) {
+			if (f == stdin)
+				/* empty stdin is OK */
+				ret = skip;
+			else {
+				fclose(f);
+				error(_("empty mbox: '%s'"), file);
+			}
+			goto out;
+		}
+	} while (isspace(peek));
+	ungetc(peek, f);
+
+	if (strbuf_getwholeline(&buf, f, '\n')) {
+		/* empty stdin is OK */
+		if (f != stdin) {
+			error("cannot read mbox %s", file);
+			goto out;
+		}
+		file_done = 1;
+	}
+
+	while (!file_done) {
+		char *name = xstrfmt("%s/%0*d", dir, nr_prec, ++skip);
+		file_done = split_one(f, name, allow_bare);
+		free(name);
+	}
+
+	if (f != stdin)
+		fclose(f);
+
+	ret = skip;
+out:
+	return ret;
+}
+
+int cmd_mailsplit(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	int nr = 0, nr_prec = 4, num = 0;
+	int allow_bare = 0;
+	const char *dir = NULL;
+	const char **argp;
+	static const char *stdin_only[] = { "-", NULL };
+
+	BUG_ON_NON_EMPTY_PREFIX(prefix);
+
+	show_usage_if_asked(argc, argv, git_mailsplit_usage);
+
+	for (argp = argv+1; *argp; argp++) {
+		const char *arg = *argp;
+
+		if (arg[0] != '-')
+			break;
+		/* do flags here */
+		if ( arg[1] == 'd' ) {
+			nr_prec = strtol(arg+2, NULL, 10);
+			if (nr_prec < 3 || 10 <= nr_prec)
+				usage(git_mailsplit_usage);
+			continue;
+		} else if ( arg[1] == 'f' ) {
+			nr = strtol(arg+2, NULL, 10);
+		} else if ( arg[1] == 'b' && !arg[2] ) {
+			allow_bare = 1;
+		} else if (!strcmp(arg, "--keep-cr")) {
+			keep_cr = 1;
+		} else if ( arg[1] == 'o' && arg[2] ) {
+			dir = arg+2;
+		} else if (!strcmp(arg, "--mboxrd")) {
+			mboxrd = 1;
+		} else if ( arg[1] == '-' && !arg[2] ) {
+			argp++;	/* -- marks end of options */
+			break;
+		} else {
+			die("unknown option: %s", arg);
+		}
+	}
+
+	if ( !dir ) {
+		/* Backwards compatibility: if no -o specified, accept
+		   <mbox> <dir> or just <dir> */
+		switch (argc - (argp-argv)) {
+		case 1:
+			dir = argp[0];
+			argp = stdin_only;
+			break;
+		case 2:
+			stdin_only[0] = argp[0];
+			dir = argp[1];
+			argp = stdin_only;
+			break;
+		default:
+			usage(git_mailsplit_usage);
+		}
+	} else {
+		/* New usage: if no more argument, parse stdin */
+		if ( !*argp )
+			argp = stdin_only;
+	}
+
+	while (*argp) {
+		const char *arg = *argp++;
+		struct stat argstat;
+		int ret = 0;
+
+		if (arg[0] == '-' && arg[1] == 0) {
+			ret = split_mbox(arg, dir, allow_bare, nr_prec, nr);
+			if (ret < 0) {
+				error("cannot split patches from stdin");
+				return 1;
+			}
+			num += (ret - nr);
+			nr = ret;
+			continue;
+		}
+
+		if (stat(arg, &argstat) == -1) {
+			error_errno("cannot stat %s", arg);
+			return 1;
+		}
+
+		if (S_ISDIR(argstat.st_mode))
+			ret = split_maildir(arg, dir, nr_prec, nr);
+		else
+			ret = split_mbox(arg, dir, allow_bare, nr_prec, nr);
+
+		if (ret < 0) {
+			error("cannot split patches from %s", arg);
+			return 1;
+		}
+		num += (ret - nr);
+		nr = ret;
+	}
+
+	printf("%d\n", num);
+
+	return 0;
+}
diff --git a/builtin/merge-base.c b/builtin/merge-base.c
new file mode 100644
index 0000000000..123c81515e
--- /dev/null
+++ b/builtin/merge-base.c
@@ -0,0 +1,207 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "commit.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "commit-reach.h"
+
+static int show_merge_base(struct commit **rev, size_t rev_nr, int show_all)
+{
+	struct commit_list *result = NULL, *r;
+
+	if (repo_get_merge_bases_many_dirty(the_repository, rev[0],
+					    rev_nr - 1, rev + 1, &result) < 0) {
+		free_commit_list(result);
+		return -1;
+	}
+
+	if (!result)
+		return 1;
+
+	for (r = result; r; r = r->next) {
+		printf("%s\n", oid_to_hex(&r->item->object.oid));
+		if (!show_all)
+			break;
+	}
+
+	free_commit_list(result);
+	return 0;
+}
+
+static const char * const merge_base_usage[] = {
+	N_("git merge-base [-a | --all] <commit> <commit>..."),
+	N_("git merge-base [-a | --all] --octopus <commit>..."),
+	N_("git merge-base --is-ancestor <commit> <commit>"),
+	N_("git merge-base --independent <commit>..."),
+	N_("git merge-base --fork-point <ref> [<commit>]"),
+	NULL
+};
+
+static struct commit *get_commit_reference(const char *arg)
+{
+	struct object_id revkey;
+	struct commit *r;
+
+	if (repo_get_oid(the_repository, arg, &revkey))
+		die("Not a valid object name %s", arg);
+	r = lookup_commit_reference(the_repository, &revkey);
+	if (!r)
+		die("Not a valid commit name %s", arg);
+
+	return r;
+}
+
+static int handle_independent(int count, const char **args)
+{
+	struct commit_list *revs = NULL, *rev;
+	int i;
+
+	for (i = count - 1; i >= 0; i--)
+		commit_list_insert(get_commit_reference(args[i]), &revs);
+
+	reduce_heads_replace(&revs);
+
+	if (!revs)
+		return 1;
+
+	for (rev = revs; rev; rev = rev->next)
+		printf("%s\n", oid_to_hex(&rev->item->object.oid));
+
+	free_commit_list(revs);
+	return 0;
+}
+
+static int handle_octopus(int count, const char **args, int show_all)
+{
+	struct commit_list *revs = NULL;
+	struct commit_list *result = NULL, *rev;
+	int i;
+
+	for (i = count - 1; i >= 0; i--)
+		commit_list_insert(get_commit_reference(args[i]), &revs);
+
+	if (get_octopus_merge_bases(revs, &result) < 0) {
+		free_commit_list(revs);
+		free_commit_list(result);
+		return 128;
+	}
+	free_commit_list(revs);
+	reduce_heads_replace(&result);
+
+	if (!result)
+		return 1;
+
+	for (rev = result; rev; rev = rev->next) {
+		printf("%s\n", oid_to_hex(&rev->item->object.oid));
+		if (!show_all)
+			break;
+	}
+
+	free_commit_list(result);
+	return 0;
+}
+
+static int handle_is_ancestor(int argc, const char **argv)
+{
+	struct commit *one, *two;
+	int ret;
+
+	if (argc != 2)
+		die("--is-ancestor takes exactly two commits");
+	one = get_commit_reference(argv[0]);
+	two = get_commit_reference(argv[1]);
+	ret = repo_in_merge_bases(the_repository, one, two);
+	if (ret < 0)
+		exit(128);
+	if (ret)
+		return 0;
+	else
+		return 1;
+}
+
+static int handle_fork_point(int argc, const char **argv)
+{
+	struct object_id oid;
+	struct commit *derived, *fork_point;
+	const char *commitname;
+
+	commitname = (argc == 2) ? argv[1] : "HEAD";
+	if (repo_get_oid(the_repository, commitname, &oid))
+		die("Not a valid object name: '%s'", commitname);
+
+	derived = lookup_commit_reference(the_repository, &oid);
+
+	fork_point = get_fork_point(argv[0], derived);
+
+	if (!fork_point)
+		return 1;
+
+	printf("%s\n", oid_to_hex(&fork_point->object.oid));
+	return 0;
+}
+
+int cmd_merge_base(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct commit **rev;
+	size_t rev_nr = 0;
+	int show_all = 0;
+	int cmdmode = 0;
+	int ret;
+
+	struct option options[] = {
+		OPT_BOOL('a', "all", &show_all, N_("output all common ancestors")),
+		OPT_CMDMODE(0, "octopus", &cmdmode,
+			    N_("find ancestors for a single n-way merge"), 'o'),
+		OPT_CMDMODE(0, "independent", &cmdmode,
+			    N_("list revs not reachable from others"), 'r'),
+		OPT_CMDMODE(0, "is-ancestor", &cmdmode,
+			    N_("is the first one ancestor of the other?"), 'a'),
+		OPT_CMDMODE(0, "fork-point", &cmdmode,
+			    N_("find where <commit> forked from reflog of <ref>"), 'f'),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, options, merge_base_usage, 0);
+
+	if (cmdmode == 'a') {
+		if (argc < 2)
+			usage_with_options(merge_base_usage, options);
+		if (show_all)
+			die(_("options '%s' and '%s' cannot be used together"),
+			    "--is-ancestor", "--all");
+		return handle_is_ancestor(argc, argv);
+	}
+
+	if (cmdmode == 'r' && show_all)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--independent", "--all");
+
+	if (cmdmode == 'o')
+		return handle_octopus(argc, argv, show_all);
+
+	if (cmdmode == 'r')
+		return handle_independent(argc, argv);
+
+	if (cmdmode == 'f') {
+		if (argc < 1 || 2 < argc)
+			usage_with_options(merge_base_usage, options);
+		return handle_fork_point(argc, argv);
+	}
+
+	if (argc < 2)
+		usage_with_options(merge_base_usage, options);
+
+	ALLOC_ARRAY(rev, argc);
+	while (argc-- > 0)
+		rev[rev_nr++] = get_commit_reference(*argv++);
+	ret = show_merge_base(rev, rev_nr, show_all);
+	free(rev);
+	return ret;
+}
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
new file mode 100644
index 0000000000..7e315f374b
--- /dev/null
+++ b/builtin/merge-file.c
@@ -0,0 +1,190 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+#include "diff.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store.h"
+#include "config.h"
+#include "gettext.h"
+#include "setup.h"
+#include "xdiff/xdiff.h"
+#include "xdiff-interface.h"
+#include "parse-options.h"
+
+static const char *const merge_file_usage[] = {
+	N_("git merge-file [<options>] [-L <name1> [-L <orig> [-L <name2>]]] <file1> <orig-file> <file2>"),
+	NULL
+};
+
+static int label_cb(const struct option *opt, const char *arg, int unset)
+{
+	static int label_count = 0;
+	const char **names = (const char **)opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (label_count >= 3)
+		return error("too many labels on the command line");
+	names[label_count++] = arg;
+	return 0;
+}
+
+static int set_diff_algorithm(xpparam_t *xpp,
+			      const char *alg)
+{
+	long diff_algorithm = parse_algorithm_value(alg);
+	if (diff_algorithm < 0)
+		return -1;
+	xpp->flags = (xpp->flags & ~XDF_DIFF_ALGORITHM_MASK) | diff_algorithm;
+	return 0;
+}
+
+static int diff_algorithm_cb(const struct option *opt,
+				const char *arg, int unset)
+{
+	xpparam_t *xpp = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (set_diff_algorithm(xpp, arg))
+		return error(_("option diff-algorithm accepts \"myers\", "
+			       "\"minimal\", \"patience\" and \"histogram\""));
+
+	return 0;
+}
+
+int cmd_merge_file(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	const char *names[3] = { 0 };
+	mmfile_t mmfs[3] = { 0 };
+	mmbuffer_t result = { 0 };
+	xmparam_t xmp = { 0 };
+	int ret = 0, i = 0, to_stdout = 0, object_id = 0;
+	int quiet = 0;
+	struct option options[] = {
+		OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
+		OPT_BOOL(0,   "object-id", &object_id, N_("use object IDs instead of filenames")),
+		OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
+		OPT_SET_INT(0, "zdiff3", &xmp.style, N_("use a zealous diff3 based merge"),
+				XDL_MERGE_ZEALOUS_DIFF3),
+		OPT_SET_INT(0, "ours", &xmp.favor, N_("for conflicts, use our version"),
+			    XDL_MERGE_FAVOR_OURS),
+		OPT_SET_INT(0, "theirs", &xmp.favor, N_("for conflicts, use their version"),
+			    XDL_MERGE_FAVOR_THEIRS),
+		OPT_SET_INT(0, "union", &xmp.favor, N_("for conflicts, use a union version"),
+			    XDL_MERGE_FAVOR_UNION),
+		OPT_CALLBACK_F(0, "diff-algorithm", &xmp.xpp, N_("<algorithm>"),
+			     N_("choose a diff algorithm"),
+			     PARSE_OPT_NONEG, diff_algorithm_cb),
+		OPT_INTEGER(0, "marker-size", &xmp.marker_size,
+			    N_("for conflicts, use this marker size")),
+		OPT__QUIET(&quiet, N_("do not warn about conflicts")),
+		OPT_CALLBACK('L', NULL, names, N_("name"),
+			     N_("set labels for file1/orig-file/file2"), &label_cb),
+		OPT_END(),
+	};
+
+	xmp.level = XDL_MERGE_ZEALOUS_ALNUM;
+	xmp.style = 0;
+	xmp.favor = 0;
+
+	if (startup_info->have_repository) {
+		/* Read the configuration file */
+		git_config(git_xmerge_config, NULL);
+		if (0 <= git_xmerge_style)
+			xmp.style = git_xmerge_style;
+	}
+
+	argc = parse_options(argc, argv, prefix, options, merge_file_usage, 0);
+	if (argc != 3)
+		usage_with_options(merge_file_usage, options);
+	if (quiet) {
+		if (!freopen("/dev/null", "w", stderr))
+			return error_errno("failed to redirect stderr to /dev/null");
+	}
+
+	if (object_id)
+		setup_git_directory();
+
+	for (i = 0; i < 3; i++) {
+		char *fname;
+		struct object_id oid;
+		mmfile_t *mmf = mmfs + i;
+
+		if (!names[i])
+			names[i] = argv[i];
+
+		fname = prefix_filename(prefix, argv[i]);
+
+		if (object_id) {
+			if (repo_get_oid(the_repository, argv[i], &oid))
+				ret = error(_("object '%s' does not exist"),
+					      argv[i]);
+			else if (!oideq(&oid, the_hash_algo->empty_blob))
+				read_mmblob(mmf, &oid);
+			else
+				read_mmfile(mmf, "/dev/null");
+		} else if (read_mmfile(mmf, fname)) {
+			ret = -1;
+		}
+		if (ret != -1 && (mmf->size > MAX_XDIFF_SIZE ||
+		    buffer_is_binary(mmf->ptr, mmf->size))) {
+			ret = error("Cannot merge binary files: %s",
+				    argv[i]);
+		}
+
+		free(fname);
+		if (ret)
+			goto cleanup;
+
+	}
+
+	xmp.ancestor = names[1];
+	xmp.file1 = names[0];
+	xmp.file2 = names[2];
+	ret = xdl_merge(mmfs + 1, mmfs + 0, mmfs + 2, &xmp, &result);
+
+	if (ret >= 0) {
+		if (object_id && !to_stdout) {
+			struct object_id oid;
+			if (result.size) {
+				if (write_object_file(result.ptr, result.size, OBJ_BLOB, &oid) < 0)
+					ret = error(_("Could not write object file"));
+			} else {
+				oidcpy(&oid, the_hash_algo->empty_blob);
+			}
+			if (ret >= 0)
+				printf("%s\n", oid_to_hex(&oid));
+		} else {
+			const char *filename = argv[0];
+			char *fpath = prefix_filename(prefix, argv[0]);
+			FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
+
+			if (!f)
+				ret = error_errno("Could not open %s for writing",
+						  filename);
+			else if (result.size &&
+				 fwrite(result.ptr, result.size, 1, f) != 1)
+				ret = error_errno("Could not write to %s", filename);
+			else if (fclose(f))
+				ret = error_errno("Could not close %s", filename);
+			free(fpath);
+		}
+		free(result.ptr);
+	}
+
+	if (ret > 127)
+		ret = 127;
+
+cleanup:
+	for (i = 0; i < 3; i++)
+		free(mmfs[i].ptr);
+
+	return ret;
+}
diff --git a/builtin/merge-index.c b/builtin/merge-index.c
new file mode 100644
index 0000000000..3314fb1336
--- /dev/null
+++ b/builtin/merge-index.c
@@ -0,0 +1,131 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "hex.h"
+#include "read-cache-ll.h"
+#include "run-command.h"
+#include "sparse-index.h"
+
+static const char *pgm;
+static int one_shot, quiet;
+static int err;
+
+static int merge_entry(int pos, const char *path)
+{
+	int found;
+	const char *arguments[] = { pgm, "", "", "", path, "", "", "", NULL };
+	char hexbuf[4][GIT_MAX_HEXSZ + 1];
+	char ownbuf[4][60];
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	if (pos >= the_repository->index->cache_nr)
+		die("git merge-index: %s not in the cache", path);
+	found = 0;
+	do {
+		const struct cache_entry *ce = the_repository->index->cache[pos];
+		int stage = ce_stage(ce);
+
+		if (strcmp(ce->name, path))
+			break;
+		found++;
+		oid_to_hex_r(hexbuf[stage], &ce->oid);
+		xsnprintf(ownbuf[stage], sizeof(ownbuf[stage]), "%o", ce->ce_mode);
+		arguments[stage] = hexbuf[stage];
+		arguments[stage + 4] = ownbuf[stage];
+	} while (++pos < the_repository->index->cache_nr);
+	if (!found)
+		die("git merge-index: %s not in the cache", path);
+
+	strvec_pushv(&cmd.args, arguments);
+	if (run_command(&cmd)) {
+		if (one_shot)
+			err++;
+		else {
+			if (!quiet)
+				die("merge program failed");
+			exit(1);
+		}
+	}
+	return found;
+}
+
+static void merge_one_path(const char *path)
+{
+	int pos = index_name_pos(the_repository->index, path, strlen(path));
+
+	/*
+	 * If it already exists in the cache as stage0, it's
+	 * already merged and there is nothing to do.
+	 */
+	if (pos < 0)
+		merge_entry(-pos-1, path);
+}
+
+static void merge_all(void)
+{
+	int i;
+	/* TODO: audit for interaction with sparse-index. */
+	ensure_full_index(the_repository->index);
+	for (i = 0; i < the_repository->index->cache_nr; i++) {
+		const struct cache_entry *ce = the_repository->index->cache[i];
+		if (!ce_stage(ce))
+			continue;
+		i += merge_entry(i, ce->name)-1;
+	}
+}
+
+static const char usage_string[] =
+"git merge-index [-o] [-q] <merge-program> (-a | [--] [<filename>...])";
+
+int cmd_merge_index(int argc,
+		    const char **argv,
+		    const char *prefix UNUSED,
+		    struct repository *repo UNUSED)
+{
+	int i, force_file = 0;
+
+	/* Without this we cannot rely on waitpid() to tell
+	 * what happened to our children.
+	 */
+	signal(SIGCHLD, SIG_DFL);
+
+	show_usage_if_asked(argc, argv, usage_string);
+
+	if (argc < 3)
+		usage(usage_string);
+
+	repo_read_index(the_repository);
+
+	/* TODO: audit for interaction with sparse-index. */
+	ensure_full_index(the_repository->index);
+
+	i = 1;
+	if (!strcmp(argv[i], "-o")) {
+		one_shot = 1;
+		i++;
+	}
+	if (!strcmp(argv[i], "-q")) {
+		quiet = 1;
+		i++;
+	}
+	pgm = argv[i++];
+	for (; i < argc; i++) {
+		const char *arg = argv[i];
+		if (!force_file && *arg == '-') {
+			if (!strcmp(arg, "--")) {
+				force_file = 1;
+				continue;
+			}
+			if (!strcmp(arg, "-a")) {
+				merge_all();
+				continue;
+			}
+			die("git merge-index: unknown option %s", arg);
+		}
+		merge_one_path(arg);
+	}
+	if (err && !quiet)
+		die("merge program failed");
+	return err;
+}
diff --git a/builtin/merge-ours.c b/builtin/merge-ours.c
new file mode 100644
index 0000000000..97b8a792c7
--- /dev/null
+++ b/builtin/merge-ours.c
@@ -0,0 +1,38 @@
+/*
+ * Implementation of git-merge-ours.sh as builtin
+ *
+ * Copyright (c) 2007 Thomas Harning Jr
+ * Original:
+ * Original Copyright (c) 2005 Junio C Hamano
+ *
+ * Pretend we resolved the heads, but declare our tree trumps everybody else.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "builtin.h"
+#include "diff.h"
+
+
+static const char builtin_merge_ours_usage[] =
+	"git merge-ours <base>... -- HEAD <remote>...";
+
+int cmd_merge_ours(int argc,
+		   const char **argv,
+		   const char *prefix UNUSED,
+		   struct repository *repo UNUSED)
+{
+	show_usage_if_asked(argc, argv, builtin_merge_ours_usage);
+
+	/*
+	 * The contents of the current index becomes the tree we
+	 * commit.  The index must match HEAD, or this merge cannot go
+	 * through.
+	 */
+	if (repo_read_index(the_repository) < 0)
+		die_errno("read_cache failed");
+	if (index_differs_from(the_repository, "HEAD", NULL, 0))
+		return 2;
+	return 0;
+}
diff --git a/builtin/merge-recursive.c b/builtin/merge-recursive.c
new file mode 100644
index 0000000000..abfc060e28
--- /dev/null
+++ b/builtin/merge-recursive.c
@@ -0,0 +1,100 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "advice.h"
+#include "gettext.h"
+#include "hash.h"
+#include "merge-recursive.h"
+#include "object-name.h"
+
+static const char builtin_merge_recursive_usage[] =
+	"git %s <base>... -- <head> <remote> ...";
+
+static char *better_branch_name(const char *branch)
+{
+	static char githead_env[8 + GIT_MAX_HEXSZ + 1];
+	char *name;
+
+	if (strlen(branch) != the_hash_algo->hexsz)
+		return xstrdup(branch);
+	xsnprintf(githead_env, sizeof(githead_env), "GITHEAD_%s", branch);
+	name = getenv(githead_env);
+	return xstrdup(name ? name : branch);
+}
+
+int cmd_merge_recursive(int argc,
+			const char **argv,
+			const char *prefix UNUSED,
+			struct repository *repo UNUSED)
+{
+	struct object_id bases[21];
+	unsigned bases_count = 0;
+	int i, failed;
+	struct object_id h1, h2;
+	struct merge_options o;
+	char *better1, *better2;
+	struct commit *result;
+
+	init_basic_merge_options(&o, the_repository);
+	if (argv[0] && ends_with(argv[0], "-subtree"))
+		o.subtree_shift = "";
+
+	if (argc == 2 && !strcmp(argv[1], "-h")) {
+		struct strbuf msg = STRBUF_INIT;
+		strbuf_addf(&msg, builtin_merge_recursive_usage, argv[0]);
+		show_usage_if_asked(argc, argv, msg.buf);
+	}
+
+	if (argc < 4)
+		usagef(builtin_merge_recursive_usage, argv[0]);
+
+	for (i = 1; i < argc; ++i) {
+		const char *arg = argv[i];
+
+		if (starts_with(arg, "--")) {
+			if (!arg[2])
+				break;
+			if (parse_merge_opt(&o, arg + 2))
+				die(_("unknown option %s"), arg);
+			continue;
+		}
+		if (bases_count < ARRAY_SIZE(bases)-1) {
+			if (repo_get_oid(the_repository, argv[i], &bases[bases_count++]))
+				die(_("could not parse object '%s'"), argv[i]);
+		}
+		else
+			warning(Q_("cannot handle more than %d base. "
+				   "Ignoring %s.",
+				   "cannot handle more than %d bases. "
+				   "Ignoring %s.",
+				    ARRAY_SIZE(bases)-1),
+				(int)ARRAY_SIZE(bases)-1, argv[i]);
+	}
+	if (argc - i != 3) /* "--" "<head>" "<remote>" */
+		die(_("not handling anything other than two heads merge."));
+
+	if (repo_read_index_unmerged(the_repository))
+		die_resolve_conflict("merge");
+
+	o.branch1 = argv[++i];
+	o.branch2 = argv[++i];
+
+	if (repo_get_oid(the_repository, o.branch1, &h1))
+		die(_("could not resolve ref '%s'"), o.branch1);
+	if (repo_get_oid(the_repository, o.branch2, &h2))
+		die(_("could not resolve ref '%s'"), o.branch2);
+
+	o.branch1 = better1 = better_branch_name(o.branch1);
+	o.branch2 = better2 = better_branch_name(o.branch2);
+
+	if (o.verbosity >= 3)
+		printf(_("Merging %s with %s\n"), o.branch1, o.branch2);
+
+	failed = merge_recursive_generic(&o, &h1, &h2, bases_count, bases, &result);
+
+	free(better1);
+	free(better2);
+
+	if (failed < 0)
+		return 128; /* die() error code */
+	return failed;
+}
diff --git a/builtin/merge-tree.c b/builtin/merge-tree.c
new file mode 100644
index 0000000000..9a6c8b4e4c
--- /dev/null
+++ b/builtin/merge-tree.c
@@ -0,0 +1,680 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "tree-walk.h"
+#include "xdiff-interface.h"
+#include "help.h"
+#include "gettext.h"
+#include "hex.h"
+#include "commit.h"
+#include "commit-reach.h"
+#include "merge-ort.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "parse-options.h"
+#include "blob.h"
+#include "merge-blobs.h"
+#include "quote.h"
+#include "tree.h"
+#include "config.h"
+#include "strvec.h"
+
+static int line_termination = '\n';
+
+struct merge_list {
+	struct merge_list *next;
+	struct merge_list *link;	/* other stages for this object */
+
+	unsigned int stage : 2;
+	unsigned int mode;
+	const char *path;
+	struct blob *blob;
+};
+
+static struct merge_list *merge_result, **merge_result_end = &merge_result;
+
+static void add_merge_entry(struct merge_list *entry)
+{
+	*merge_result_end = entry;
+	merge_result_end = &entry->next;
+}
+
+static void trivial_merge_trees(struct tree_desc t[3], const char *base);
+
+static const char *explanation(struct merge_list *entry)
+{
+	switch (entry->stage) {
+	case 0:
+		return "merged";
+	case 3:
+		return "added in remote";
+	case 2:
+		if (entry->link)
+			return "added in both";
+		return "added in local";
+	}
+
+	/* Existed in base */
+	entry = entry->link;
+	if (!entry)
+		return "removed in both";
+
+	if (entry->link)
+		return "changed in both";
+
+	if (entry->stage == 3)
+		return "removed in local";
+	return "removed in remote";
+}
+
+static void *result(struct merge_list *entry, unsigned long *size)
+{
+	enum object_type type;
+	struct blob *base, *our, *their;
+	const char *path = entry->path;
+
+	if (!entry->stage)
+		return repo_read_object_file(the_repository,
+					     &entry->blob->object.oid, &type,
+					     size);
+	base = NULL;
+	if (entry->stage == 1) {
+		base = entry->blob;
+		entry = entry->link;
+	}
+	our = NULL;
+	if (entry && entry->stage == 2) {
+		our = entry->blob;
+		entry = entry->link;
+	}
+	their = NULL;
+	if (entry)
+		their = entry->blob;
+	return merge_blobs(the_repository->index, path,
+			   base, our, their, size);
+}
+
+static void *origin(struct merge_list *entry, unsigned long *size)
+{
+	enum object_type type;
+	while (entry) {
+		if (entry->stage == 2)
+			return repo_read_object_file(the_repository,
+						     &entry->blob->object.oid,
+						     &type, size);
+		entry = entry->link;
+	}
+	return NULL;
+}
+
+static int show_outf(void *priv UNUSED, mmbuffer_t *mb, int nbuf)
+{
+	int i;
+	for (i = 0; i < nbuf; i++)
+		printf("%.*s", (int) mb[i].size, mb[i].ptr);
+	return 0;
+}
+
+static void show_diff(struct merge_list *entry)
+{
+	unsigned long size;
+	mmfile_t src, dst;
+	xpparam_t xpp;
+	xdemitconf_t xecfg;
+	xdemitcb_t ecb = { .out_line = show_outf };
+
+	memset(&xpp, 0, sizeof(xpp));
+	xpp.flags = 0;
+	memset(&xecfg, 0, sizeof(xecfg));
+	xecfg.ctxlen = 3;
+
+	src.ptr = origin(entry, &size);
+	if (!src.ptr)
+		size = 0;
+	src.size = size;
+	dst.ptr = result(entry, &size);
+	if (!dst.ptr)
+		size = 0;
+	dst.size = size;
+	if (xdi_diff(&src, &dst, &xpp, &xecfg, &ecb))
+		die("unable to generate diff");
+	free(src.ptr);
+	free(dst.ptr);
+}
+
+static void show_result_list(struct merge_list *entry)
+{
+	printf("%s\n", explanation(entry));
+	do {
+		struct merge_list *link = entry->link;
+		static const char *desc[4] = { "result", "base", "our", "their" };
+		printf("  %-6s %o %s %s\n", desc[entry->stage], entry->mode, oid_to_hex(&entry->blob->object.oid), entry->path);
+		entry = link;
+	} while (entry);
+}
+
+static void show_result(void)
+{
+	struct merge_list *walk;
+
+	walk = merge_result;
+	while (walk) {
+		show_result_list(walk);
+		show_diff(walk);
+		walk = walk->next;
+	}
+}
+
+/* An empty entry never compares same, not even to another empty entry */
+static int same_entry(struct name_entry *a, struct name_entry *b)
+{
+	return	!is_null_oid(&a->oid) &&
+		!is_null_oid(&b->oid) &&
+		oideq(&a->oid, &b->oid) &&
+		a->mode == b->mode;
+}
+
+static int both_empty(struct name_entry *a, struct name_entry *b)
+{
+	return is_null_oid(&a->oid) && is_null_oid(&b->oid);
+}
+
+static struct merge_list *create_entry(unsigned stage, unsigned mode, const struct object_id *oid, const char *path)
+{
+	struct merge_list *res = xcalloc(1, sizeof(*res));
+
+	res->stage = stage;
+	res->path = path;
+	res->mode = mode;
+	res->blob = lookup_blob(the_repository, oid);
+	return res;
+}
+
+static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
+{
+	struct strbuf buf = STRBUF_INIT;
+	strbuf_make_traverse_path(&buf, info, n->path, n->pathlen);
+	return strbuf_detach(&buf, NULL);
+}
+
+static void resolve(const struct traverse_info *info, struct name_entry *ours, struct name_entry *result)
+{
+	struct merge_list *orig, *final;
+	const char *path;
+
+	/* If it's already ours, don't bother showing it */
+	if (!ours)
+		return;
+
+	path = traverse_path(info, result);
+	orig = create_entry(2, ours->mode, &ours->oid, path);
+	final = create_entry(0, result->mode, &result->oid, path);
+
+	final->link = orig;
+
+	add_merge_entry(final);
+}
+
+static void unresolved_directory(const struct traverse_info *info,
+				 struct name_entry n[3])
+{
+	struct repository *r = the_repository;
+	char *newbase;
+	struct name_entry *p;
+	struct tree_desc t[3];
+	void *buf0, *buf1, *buf2;
+
+	for (p = n; p < n + 3; p++) {
+		if (p->mode && S_ISDIR(p->mode))
+			break;
+	}
+	if (n + 3 <= p)
+		return; /* there is no tree here */
+
+	newbase = traverse_path(info, p);
+
+#define ENTRY_OID(e) (((e)->mode && S_ISDIR((e)->mode)) ? &(e)->oid : NULL)
+	buf0 = fill_tree_descriptor(r, t + 0, ENTRY_OID(n + 0));
+	buf1 = fill_tree_descriptor(r, t + 1, ENTRY_OID(n + 1));
+	buf2 = fill_tree_descriptor(r, t + 2, ENTRY_OID(n + 2));
+#undef ENTRY_OID
+
+	trivial_merge_trees(t, newbase);
+
+	free(buf0);
+	free(buf1);
+	free(buf2);
+	free(newbase);
+}
+
+
+static struct merge_list *link_entry(unsigned stage, const struct traverse_info *info, struct name_entry *n, struct merge_list *entry)
+{
+	const char *path;
+	struct merge_list *link;
+
+	if (!n->mode)
+		return entry;
+	if (entry)
+		path = entry->path;
+	else
+		path = traverse_path(info, n);
+	link = create_entry(stage, n->mode, &n->oid, path);
+	link->link = entry;
+	return link;
+}
+
+static void unresolved(const struct traverse_info *info, struct name_entry n[3])
+{
+	struct merge_list *entry = NULL;
+	int i;
+	unsigned dirmask = 0, mask = 0;
+
+	for (i = 0; i < 3; i++) {
+		mask |= (1 << i);
+		/*
+		 * Treat missing entries as directories so that we return
+		 * after unresolved_directory has handled this.
+		 */
+		if (!n[i].mode || S_ISDIR(n[i].mode))
+			dirmask |= (1 << i);
+	}
+
+	unresolved_directory(info, n);
+
+	if (dirmask == mask)
+		return;
+
+	if (n[2].mode && !S_ISDIR(n[2].mode))
+		entry = link_entry(3, info, n + 2, entry);
+	if (n[1].mode && !S_ISDIR(n[1].mode))
+		entry = link_entry(2, info, n + 1, entry);
+	if (n[0].mode && !S_ISDIR(n[0].mode))
+		entry = link_entry(1, info, n + 0, entry);
+
+	add_merge_entry(entry);
+}
+
+/*
+ * Merge two trees together (t[1] and t[2]), using a common base (t[0])
+ * as the origin.
+ *
+ * This walks the (sorted) trees in lock-step, checking every possible
+ * name. Note that directories automatically sort differently from other
+ * files (see "base_name_compare"), so you'll never see file/directory
+ * conflicts, because they won't ever compare the same.
+ *
+ * IOW, if a directory changes to a filename, it will automatically be
+ * seen as the directory going away, and the filename being created.
+ *
+ * Think of this as a three-way diff.
+ *
+ * The output will be either:
+ *  - successful merge
+ *	 "0 mode sha1 filename"
+ *    NOTE NOTE NOTE! FIXME! We really really need to walk the index
+ *    in parallel with this too!
+ *
+ *  - conflict:
+ *	"1 mode sha1 filename"
+ *	"2 mode sha1 filename"
+ *	"3 mode sha1 filename"
+ *    where not all of the 1/2/3 lines may exist, of course.
+ *
+ * The successful merge rules are the same as for the three-way merge
+ * in git-read-tree.
+ */
+static int threeway_callback(int n UNUSED, unsigned long mask,
+			     unsigned long dirmask UNUSED,
+			     struct name_entry *entry, struct traverse_info *info)
+{
+	/* Same in both? */
+	if (same_entry(entry+1, entry+2) || both_empty(entry+1, entry+2)) {
+		/* Modified, added or removed identically */
+		resolve(info, NULL, entry+1);
+		return mask;
+	}
+
+	if (same_entry(entry+0, entry+1)) {
+		if (!is_null_oid(&entry[2].oid) && !S_ISDIR(entry[2].mode)) {
+			/* We did not touch, they modified -- take theirs */
+			resolve(info, entry+1, entry+2);
+			return mask;
+		}
+		/*
+		 * If we did not touch a directory but they made it
+		 * into a file, we fall through and unresolved()
+		 * recurses down.  Likewise for the opposite case.
+		 */
+	}
+
+	if (same_entry(entry+0, entry+2) || both_empty(entry+0, entry+2)) {
+		/* We added, modified or removed, they did not touch -- take ours */
+		resolve(info, NULL, entry+1);
+		return mask;
+	}
+
+	unresolved(info, entry);
+	return mask;
+}
+
+static void trivial_merge_trees(struct tree_desc t[3], const char *base)
+{
+	struct traverse_info info;
+
+	setup_traverse_info(&info, base);
+	info.fn = threeway_callback;
+	traverse_trees(the_repository->index, 3, t, &info);
+}
+
+static void *get_tree_descriptor(struct repository *r,
+				 struct tree_desc *desc,
+				 const char *rev)
+{
+	struct object_id oid;
+	void *buf;
+
+	if (repo_get_oid(r, rev, &oid))
+		die("unknown rev %s", rev);
+	buf = fill_tree_descriptor(r, desc, &oid);
+	if (!buf)
+		die("%s is not a tree", rev);
+	return buf;
+}
+
+static int trivial_merge(const char *base,
+			 const char *branch1,
+			 const char *branch2)
+{
+	struct repository *r = the_repository;
+	struct tree_desc t[3];
+	void *buf1, *buf2, *buf3;
+
+	buf1 = get_tree_descriptor(r, t+0, base);
+	buf2 = get_tree_descriptor(r, t+1, branch1);
+	buf3 = get_tree_descriptor(r, t+2, branch2);
+	trivial_merge_trees(t, "");
+	free(buf1);
+	free(buf2);
+	free(buf3);
+
+	show_result();
+	return 0;
+}
+
+enum mode {
+	MODE_UNKNOWN,
+	MODE_TRIVIAL,
+	MODE_REAL,
+};
+
+struct merge_tree_options {
+	int mode;
+	int allow_unrelated_histories;
+	int show_messages;
+	int name_only;
+	int use_stdin;
+	struct merge_options merge_options;
+};
+
+static int real_merge(struct merge_tree_options *o,
+		      const char *merge_base,
+		      const char *branch1, const char *branch2,
+		      const char *prefix)
+{
+	struct commit *parent1, *parent2;
+	struct commit_list *merge_bases = NULL;
+	struct merge_result result = { 0 };
+	int show_messages = o->show_messages;
+	struct merge_options opt;
+
+	copy_merge_options(&opt, &o->merge_options);
+	opt.show_rename_progress = 0;
+
+	opt.branch1 = branch1;
+	opt.branch2 = branch2;
+
+	if (merge_base) {
+		struct tree *base_tree, *parent1_tree, *parent2_tree;
+
+		/*
+		 * We actually only need the trees because we already
+		 * have a merge base.
+		 */
+		struct object_id base_oid, head_oid, merge_oid;
+
+		if (repo_get_oid_treeish(the_repository, merge_base, &base_oid))
+			die(_("could not parse as tree '%s'"), merge_base);
+		base_tree = parse_tree_indirect(&base_oid);
+		if (!base_tree)
+			die(_("unable to read tree (%s)"), oid_to_hex(&base_oid));
+		if (repo_get_oid_treeish(the_repository, branch1, &head_oid))
+			die(_("could not parse as tree '%s'"), branch1);
+		parent1_tree = parse_tree_indirect(&head_oid);
+		if (!parent1_tree)
+			die(_("unable to read tree (%s)"), oid_to_hex(&head_oid));
+		if (repo_get_oid_treeish(the_repository, branch2, &merge_oid))
+			die(_("could not parse as tree '%s'"), branch2);
+		parent2_tree = parse_tree_indirect(&merge_oid);
+		if (!parent2_tree)
+			die(_("unable to read tree (%s)"), oid_to_hex(&merge_oid));
+
+		opt.ancestor = merge_base;
+		merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
+	} else {
+		parent1 = get_merge_parent(branch1);
+		if (!parent1)
+			help_unknown_ref(branch1, "merge-tree",
+					 _("not something we can merge"));
+
+		parent2 = get_merge_parent(branch2);
+		if (!parent2)
+			help_unknown_ref(branch2, "merge-tree",
+					 _("not something we can merge"));
+
+		/*
+		 * Get the merge bases, in reverse order; see comment above
+		 * merge_incore_recursive in merge-ort.h
+		 */
+		if (repo_get_merge_bases(the_repository, parent1,
+					 parent2, &merge_bases) < 0)
+			exit(128);
+		if (!merge_bases && !o->allow_unrelated_histories)
+			die(_("refusing to merge unrelated histories"));
+		merge_bases = reverse_commit_list(merge_bases);
+		merge_incore_recursive(&opt, merge_bases, parent1, parent2, &result);
+		free_commit_list(merge_bases);
+	}
+
+	if (result.clean < 0)
+		die(_("failure to merge"));
+
+	if (show_messages == -1)
+		show_messages = !result.clean;
+
+	if (o->use_stdin)
+		printf("%d%c", result.clean, line_termination);
+	printf("%s%c", oid_to_hex(&result.tree->object.oid), line_termination);
+	if (!result.clean) {
+		struct string_list conflicted_files = STRING_LIST_INIT_NODUP;
+		const char *last = NULL;
+
+		merge_get_conflicted_files(&result, &conflicted_files);
+		for (size_t i = 0; i < conflicted_files.nr; i++) {
+			const char *name = conflicted_files.items[i].string;
+			struct stage_info *c = conflicted_files.items[i].util;
+			if (!o->name_only)
+				printf("%06o %s %d\t",
+				       c->mode, oid_to_hex(&c->oid), c->stage);
+			else if (last && !strcmp(last, name))
+				continue;
+			write_name_quoted_relative(
+				name, prefix, stdout, line_termination);
+			last = name;
+		}
+		string_list_clear(&conflicted_files, 1);
+	}
+	if (show_messages) {
+		putchar(line_termination);
+		merge_display_update_messages(&opt, line_termination == '\0',
+					      &result);
+	}
+	if (o->use_stdin)
+		putchar(line_termination);
+	merge_finalize(&opt, &result);
+	clear_merge_options(&opt);
+	return !result.clean; /* result.clean < 0 handled above */
+}
+
+int cmd_merge_tree(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct merge_tree_options o = { .show_messages = -1 };
+	struct strvec xopts = STRVEC_INIT;
+	int expected_remaining_argc;
+	int original_argc;
+	const char *merge_base = NULL;
+	int ret;
+
+	const char * const merge_tree_usage[] = {
+		N_("git merge-tree [--write-tree] [<options>] <branch1> <branch2>"),
+		N_("git merge-tree [--trivial-merge] <base-tree> <branch1> <branch2>"),
+		NULL
+	};
+	struct option mt_options[] = {
+		OPT_CMDMODE(0, "write-tree", &o.mode,
+			    N_("do a real merge instead of a trivial merge"),
+			    MODE_REAL),
+		OPT_CMDMODE(0, "trivial-merge", &o.mode,
+			    N_("do a trivial merge only"), MODE_TRIVIAL),
+		OPT_BOOL(0, "messages", &o.show_messages,
+			 N_("also show informational/conflict messages")),
+		OPT_SET_INT('z', NULL, &line_termination,
+			    N_("separate paths with the NUL character"), '\0'),
+		OPT_BOOL_F(0, "name-only",
+			   &o.name_only,
+			   N_("list filenames without modes/oids/stages"),
+			   PARSE_OPT_NONEG),
+		OPT_BOOL_F(0, "allow-unrelated-histories",
+			   &o.allow_unrelated_histories,
+			   N_("allow merging unrelated histories"),
+			   PARSE_OPT_NONEG),
+		OPT_BOOL_F(0, "stdin",
+			   &o.use_stdin,
+			   N_("perform multiple merges, one per line of input"),
+			   PARSE_OPT_NONEG),
+		OPT_STRING(0, "merge-base",
+			   &merge_base,
+			   N_("tree-ish"),
+			   N_("specify a merge-base for the merge")),
+		OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+			N_("option for selected merge strategy")),
+		OPT_END()
+	};
+
+	/* Init merge options */
+	init_ui_merge_options(&o.merge_options, the_repository);
+
+	/* Parse arguments */
+	original_argc = argc - 1; /* ignoring argv[0] */
+	argc = parse_options(argc, argv, prefix, mt_options,
+			     merge_tree_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (xopts.nr && o.mode == MODE_TRIVIAL)
+		die(_("--trivial-merge is incompatible with all other options"));
+	for (size_t x = 0; x < xopts.nr; x++)
+		if (parse_merge_opt(&o.merge_options, xopts.v[x]))
+			die(_("unknown strategy option: -X%s"), xopts.v[x]);
+
+	/* Handle --stdin */
+	if (o.use_stdin) {
+		struct strbuf buf = STRBUF_INIT;
+
+		if (o.mode == MODE_TRIVIAL)
+			die(_("--trivial-merge is incompatible with all other options"));
+		if (merge_base)
+			die(_("options '%s' and '%s' cannot be used together"),
+			    "--merge-base", "--stdin");
+		line_termination = '\0';
+		while (strbuf_getline_lf(&buf, stdin) != EOF) {
+			struct strbuf **split;
+			int result;
+			const char *input_merge_base = NULL;
+
+			split = strbuf_split(&buf, ' ');
+			if (!split[0] || !split[1])
+				die(_("malformed input line: '%s'."), buf.buf);
+			strbuf_rtrim(split[0]);
+			strbuf_rtrim(split[1]);
+
+			/* parse the merge-base */
+			if (!strcmp(split[1]->buf, "--")) {
+				input_merge_base = split[0]->buf;
+			}
+
+			if (input_merge_base && split[2] && split[3] && !split[4]) {
+				strbuf_rtrim(split[2]);
+				strbuf_rtrim(split[3]);
+				result = real_merge(&o, input_merge_base, split[2]->buf, split[3]->buf, prefix);
+			} else if (!input_merge_base && !split[2]) {
+				result = real_merge(&o, NULL, split[0]->buf, split[1]->buf, prefix);
+			} else {
+				die(_("malformed input line: '%s'."), buf.buf);
+			}
+
+			if (result < 0)
+				die(_("merging cannot continue; got unclean result of %d"), result);
+			strbuf_list_free(split);
+		}
+		strbuf_release(&buf);
+
+		ret = 0;
+		goto out;
+	}
+
+	/* Figure out which mode to use */
+	switch (o.mode) {
+	default:
+		BUG("unexpected command mode %d", o.mode);
+	case MODE_UNKNOWN:
+		switch (argc) {
+		default:
+			usage_with_options(merge_tree_usage, mt_options);
+		case 2:
+			o.mode = MODE_REAL;
+			break;
+		case 3:
+			o.mode = MODE_TRIVIAL;
+			break;
+		}
+		expected_remaining_argc = argc;
+		break;
+	case MODE_REAL:
+		expected_remaining_argc = 2;
+		break;
+	case MODE_TRIVIAL:
+		expected_remaining_argc = 3;
+		/* Removal of `--trivial-merge` is expected */
+		original_argc--;
+		break;
+	}
+	if (o.mode == MODE_TRIVIAL && argc < original_argc)
+		die(_("--trivial-merge is incompatible with all other options"));
+
+	if (argc != expected_remaining_argc)
+		usage_with_options(merge_tree_usage, mt_options);
+
+	git_config(git_default_config, NULL);
+
+	/* Do the relevant type of merge */
+	if (o.mode == MODE_REAL)
+		ret = real_merge(&o, merge_base, argv[0], argv[1], prefix);
+	else
+		ret = trivial_merge(argv[0], argv[1], argv[2]);
+
+out:
+	strvec_clear(&xopts);
+	return ret;
+}
diff --git a/builtin/merge.c b/builtin/merge.c
new file mode 100644
index 0000000000..ba9faf126a
--- /dev/null
+++ b/builtin/merge.c
@@ -0,0 +1,1825 @@
+/*
+ * Builtin "git merge"
+ *
+ * Copyright (c) 2008 Miklos Vajna <vmiklos@xxxxxxxxxxxxxx>
+ *
+ * Based on git-merge.sh by Junio C Hamano.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+
+#include "abspath.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "lockfile.h"
+#include "repository.h"
+#include "run-command.h"
+#include "hook.h"
+#include "diff.h"
+#include "diff-merges.h"
+#include "refs.h"
+#include "refspec.h"
+#include "commit.h"
+#include "diffcore.h"
+#include "path.h"
+#include "revision.h"
+#include "unpack-trees.h"
+#include "cache-tree.h"
+#include "dir.h"
+#include "color.h"
+#include "rerere.h"
+#include "help.h"
+#include "merge.h"
+#include "merge-recursive.h"
+#include "merge-ort-wrappers.h"
+#include "resolve-undo.h"
+#include "remote.h"
+#include "fmt-merge-msg.h"
+#include "sequencer.h"
+#include "string-list.h"
+#include "tag.h"
+#include "alias.h"
+#include "branch.h"
+#include "commit-reach.h"
+#include "wt-status.h"
+#include "commit-graph.h"
+
+#define DEFAULT_TWOHEAD (1<<0)
+#define DEFAULT_OCTOPUS (1<<1)
+#define NO_FAST_FORWARD (1<<2)
+#define NO_TRIVIAL      (1<<3)
+
+struct strategy {
+	const char *name;
+	unsigned attr;
+};
+
+static const char * const builtin_merge_usage[] = {
+	N_("git merge [<options>] [<commit>...]"),
+	"git merge --abort",
+	"git merge --continue",
+	NULL
+};
+
+static int show_diffstat = 1, shortlog_len = -1, squash;
+static int option_commit = -1;
+static int option_edit = -1;
+static int allow_trivial = 1, have_message, verify_signatures;
+static int check_trust_level = 1;
+static int overwrite_ignore = 1;
+static struct strbuf merge_msg = STRBUF_INIT;
+static struct strategy **use_strategies;
+static size_t use_strategies_nr, use_strategies_alloc;
+static struct strvec xopts = STRVEC_INIT;
+static const char *branch;
+static char *branch_mergeoptions;
+static int verbosity;
+static int allow_rerere_auto;
+static int abort_current_merge;
+static int quit_current_merge;
+static int continue_current_merge;
+static int allow_unrelated_histories;
+static int show_progress = -1;
+static int default_to_upstream = 1;
+static int signoff;
+static const char *sign_commit;
+static int autostash;
+static int no_verify;
+static char *into_name;
+
+static struct strategy all_strategy[] = {
+	{ "recursive",  NO_TRIVIAL },
+	{ "octopus",    DEFAULT_OCTOPUS },
+	{ "ort",        DEFAULT_TWOHEAD | NO_TRIVIAL },
+	{ "resolve",    0 },
+	{ "ours",       NO_FAST_FORWARD | NO_TRIVIAL },
+	{ "subtree",    NO_FAST_FORWARD | NO_TRIVIAL },
+};
+
+static char *pull_twohead, *pull_octopus;
+
+enum ff_type {
+	FF_NO,
+	FF_ALLOW,
+	FF_ONLY
+};
+
+static enum ff_type fast_forward = FF_ALLOW;
+
+static char *cleanup_arg;
+static enum commit_msg_cleanup_mode cleanup_mode;
+
+static int option_parse_message(const struct option *opt,
+				const char *arg, int unset)
+{
+	struct strbuf *buf = opt->value;
+
+	if (unset)
+		strbuf_setlen(buf, 0);
+	else if (arg) {
+		strbuf_addf(buf, "%s%s", buf->len ? "\n\n" : "", arg);
+		have_message = 1;
+	} else
+		return error(_("switch `m' requires a value"));
+	return 0;
+}
+
+static enum parse_opt_result option_read_message(struct parse_opt_ctx_t *ctx,
+						 const struct option *opt,
+						 const char *arg_not_used,
+						 int unset)
+{
+	struct strbuf *buf = opt->value;
+	const char *arg;
+
+	BUG_ON_OPT_ARG(arg_not_used);
+	if (unset)
+		BUG("-F cannot be negated");
+
+	if (ctx->opt) {
+		arg = ctx->opt;
+		ctx->opt = NULL;
+	} else if (ctx->argc > 1) {
+		ctx->argc--;
+		arg = *++ctx->argv;
+	} else
+		return error(_("option `%s' requires a value"), opt->long_name);
+
+	if (buf->len)
+		strbuf_addch(buf, '\n');
+	if (ctx->prefix && !is_absolute_path(arg))
+		arg = prefix_filename(ctx->prefix, arg);
+	if (strbuf_read_file(buf, arg, 0) < 0)
+		return error(_("could not read file '%s'"), arg);
+	have_message = 1;
+
+	return 0;
+}
+
+static struct strategy *get_strategy(const char *name)
+{
+	int i;
+	struct strategy *ret;
+	static struct cmdnames main_cmds = {0}, other_cmds = {0};
+	static int loaded;
+	char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
+
+	if (!name)
+		return NULL;
+
+	if (default_strategy &&
+	    !strcmp(default_strategy, "ort") &&
+	    !strcmp(name, "recursive")) {
+		name = "ort";
+	}
+
+	for (i = 0; i < ARRAY_SIZE(all_strategy); i++)
+		if (!strcmp(name, all_strategy[i].name))
+			return &all_strategy[i];
+
+	if (!loaded) {
+		struct cmdnames not_strategies = {0};
+		loaded = 1;
+
+		load_command_list("git-merge-", &main_cmds, &other_cmds);
+		for (i = 0; i < main_cmds.cnt; i++) {
+			int j, found = 0;
+			struct cmdname *ent = main_cmds.names[i];
+			for (j = 0; !found && j < ARRAY_SIZE(all_strategy); j++)
+				if (!xstrncmpz(all_strategy[j].name, ent->name, ent->len))
+					found = 1;
+			if (!found)
+				add_cmdname(&not_strategies, ent->name, ent->len);
+		}
+		exclude_cmds(&main_cmds, &not_strategies);
+
+		cmdnames_release(&not_strategies);
+	}
+	if (!is_in_cmdlist(&main_cmds, name) && !is_in_cmdlist(&other_cmds, name)) {
+		fprintf(stderr, _("Could not find merge strategy '%s'.\n"), name);
+		fprintf(stderr, _("Available strategies are:"));
+		for (i = 0; i < main_cmds.cnt; i++)
+			fprintf(stderr, " %s", main_cmds.names[i]->name);
+		fprintf(stderr, ".\n");
+		if (other_cmds.cnt) {
+			fprintf(stderr, _("Available custom strategies are:"));
+			for (i = 0; i < other_cmds.cnt; i++)
+				fprintf(stderr, " %s", other_cmds.names[i]->name);
+			fprintf(stderr, ".\n");
+		}
+		exit(1);
+	}
+
+	CALLOC_ARRAY(ret, 1);
+	ret->name = xstrdup(name);
+	ret->attr = NO_TRIVIAL;
+
+	cmdnames_release(&main_cmds);
+	cmdnames_release(&other_cmds);
+	return ret;
+}
+
+static void append_strategy(struct strategy *s)
+{
+	ALLOC_GROW(use_strategies, use_strategies_nr + 1, use_strategies_alloc);
+	use_strategies[use_strategies_nr++] = s;
+}
+
+static int option_parse_strategy(const struct option *opt UNUSED,
+				 const char *name, int unset)
+{
+	if (unset)
+		return 0;
+
+	append_strategy(get_strategy(name));
+	return 0;
+}
+
+static struct option builtin_merge_options[] = {
+	OPT_SET_INT('n', NULL, &show_diffstat,
+		N_("do not show a diffstat at the end of the merge"), 0),
+	OPT_BOOL(0, "stat", &show_diffstat,
+		N_("show a diffstat at the end of the merge")),
+	OPT_BOOL(0, "summary", &show_diffstat, N_("(synonym to --stat)")),
+	{ OPTION_INTEGER, 0, "log", &shortlog_len, N_("n"),
+	  N_("add (at most <n>) entries from shortlog to merge commit message"),
+	  PARSE_OPT_OPTARG, NULL, DEFAULT_MERGE_LOG_LEN },
+	OPT_BOOL(0, "squash", &squash,
+		N_("create a single commit instead of doing a merge")),
+	OPT_BOOL(0, "commit", &option_commit,
+		N_("perform a commit if the merge succeeds (default)")),
+	OPT_BOOL('e', "edit", &option_edit,
+		N_("edit message before committing")),
+	OPT_CLEANUP(&cleanup_arg),
+	OPT_SET_INT(0, "ff", &fast_forward, N_("allow fast-forward (default)"), FF_ALLOW),
+	OPT_SET_INT_F(0, "ff-only", &fast_forward,
+		      N_("abort if fast-forward is not possible"),
+		      FF_ONLY, PARSE_OPT_NONEG),
+	OPT_RERERE_AUTOUPDATE(&allow_rerere_auto),
+	OPT_BOOL(0, "verify-signatures", &verify_signatures,
+		N_("verify that the named commit has a valid GPG signature")),
+	OPT_CALLBACK('s', "strategy", NULL, N_("strategy"),
+		N_("merge strategy to use"), option_parse_strategy),
+	OPT_STRVEC('X', "strategy-option", &xopts, N_("option=value"),
+		N_("option for selected merge strategy")),
+	OPT_CALLBACK('m', "message", &merge_msg, N_("message"),
+		N_("merge commit message (for a non-fast-forward merge)"),
+		option_parse_message),
+	{ OPTION_LOWLEVEL_CALLBACK, 'F', "file", &merge_msg, N_("path"),
+		N_("read message from file"), PARSE_OPT_NONEG,
+		NULL, 0, option_read_message },
+	OPT_STRING(0, "into-name", &into_name, N_("name"),
+		   N_("use <name> instead of the real target")),
+	OPT__VERBOSITY(&verbosity),
+	OPT_BOOL(0, "abort", &abort_current_merge,
+		N_("abort the current in-progress merge")),
+	OPT_BOOL(0, "quit", &quit_current_merge,
+		N_("--abort but leave index and working tree alone")),
+	OPT_BOOL(0, "continue", &continue_current_merge,
+		N_("continue the current in-progress merge")),
+	OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories,
+		 N_("allow merging unrelated histories")),
+	OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1),
+	{ OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
+	  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+	OPT_AUTOSTASH(&autostash),
+	OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")),
+	OPT_BOOL(0, "signoff", &signoff, N_("add a Signed-off-by trailer")),
+	OPT_BOOL(0, "no-verify", &no_verify, N_("bypass pre-merge-commit and commit-msg hooks")),
+	OPT_END()
+};
+
+static int save_state(struct object_id *stash)
+{
+	int len;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	struct strbuf buffer = STRBUF_INIT;
+	struct lock_file lock_file = LOCK_INIT;
+	int fd;
+	int rc = -1;
+
+	fd = repo_hold_locked_index(the_repository, &lock_file, 0);
+	refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
+	if (0 <= fd)
+		repo_update_index_if_able(the_repository, &lock_file);
+	rollback_lock_file(&lock_file);
+
+	strvec_pushl(&cp.args, "stash", "create", NULL);
+	cp.out = -1;
+	cp.git_cmd = 1;
+
+	if (start_command(&cp))
+		die(_("could not run stash."));
+	len = strbuf_read(&buffer, cp.out, 1024);
+	close(cp.out);
+
+	if (finish_command(&cp) || len < 0)
+		die(_("stash failed"));
+	else if (!len)		/* no changes */
+		goto out;
+	strbuf_setlen(&buffer, buffer.len-1);
+	if (repo_get_oid(the_repository, buffer.buf, stash))
+		die(_("not a valid object: %s"), buffer.buf);
+	rc = 0;
+out:
+	strbuf_release(&buffer);
+	return rc;
+}
+
+static void read_empty(const struct object_id *oid)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	strvec_pushl(&cmd.args, "read-tree", "-m", "-u",
+		     empty_tree_oid_hex(the_repository->hash_algo),
+		     oid_to_hex(oid), NULL);
+	cmd.git_cmd = 1;
+
+	if (run_command(&cmd))
+		die(_("read-tree failed"));
+}
+
+static void reset_hard(const struct object_id *oid)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	strvec_pushl(&cmd.args, "read-tree", "-v", "--reset", "-u",
+		     oid_to_hex(oid), NULL);
+	cmd.git_cmd = 1;
+
+	if (run_command(&cmd))
+		die(_("read-tree failed"));
+}
+
+static void restore_state(const struct object_id *head,
+			  const struct object_id *stash)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	reset_hard(head);
+
+	if (is_null_oid(stash))
+		goto refresh_cache;
+
+	strvec_pushl(&cmd.args, "stash", "apply", "--index", "--quiet", NULL);
+	strvec_push(&cmd.args, oid_to_hex(stash));
+
+	/*
+	 * It is OK to ignore error here, for example when there was
+	 * nothing to restore.
+	 */
+	cmd.git_cmd = 1;
+	run_command(&cmd);
+
+refresh_cache:
+	discard_index(the_repository->index);
+	if (repo_read_index(the_repository) < 0)
+		die(_("could not read index"));
+}
+
+/* This is called when no merge was necessary. */
+static void finish_up_to_date(void)
+{
+	if (verbosity >= 0) {
+		if (squash)
+			puts(_("Already up to date. (nothing to squash)"));
+		else
+			puts(_("Already up to date."));
+	}
+	remove_merge_branch_state(the_repository);
+}
+
+static void squash_message(struct commit *commit, struct commit_list *remoteheads)
+{
+	struct rev_info rev;
+	struct strbuf out = STRBUF_INIT;
+	struct commit_list *j;
+	struct pretty_print_context ctx = {0};
+
+	printf(_("Squash commit -- not updating HEAD\n"));
+
+	repo_init_revisions(the_repository, &rev, NULL);
+	diff_merges_suppress(&rev);
+	rev.commit_format = CMIT_FMT_MEDIUM;
+
+	commit->object.flags |= UNINTERESTING;
+	add_pending_object(&rev, &commit->object, NULL);
+
+	for (j = remoteheads; j; j = j->next)
+		add_pending_object(&rev, &j->item->object, NULL);
+
+	setup_revisions(0, NULL, &rev, NULL);
+	if (prepare_revision_walk(&rev))
+		die(_("revision walk setup failed"));
+
+	ctx.abbrev = rev.abbrev;
+	ctx.date_mode = rev.date_mode;
+	ctx.fmt = rev.commit_format;
+
+	strbuf_addstr(&out, "Squashed commit of the following:\n");
+	while ((commit = get_revision(&rev)) != NULL) {
+		strbuf_addch(&out, '\n');
+		strbuf_addf(&out, "commit %s\n",
+			oid_to_hex(&commit->object.oid));
+		pretty_print_commit(&ctx, commit, &out);
+	}
+	write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len);
+	strbuf_release(&out);
+	release_revisions(&rev);
+}
+
+static void finish(struct commit *head_commit,
+		   struct commit_list *remoteheads,
+		   const struct object_id *new_head, const char *msg)
+{
+	struct strbuf reflog_message = STRBUF_INIT;
+	const struct object_id *head = &head_commit->object.oid;
+
+	if (!msg)
+		strbuf_addstr(&reflog_message, getenv("GIT_REFLOG_ACTION"));
+	else {
+		if (verbosity >= 0)
+			printf("%s\n", msg);
+		strbuf_addf(&reflog_message, "%s: %s",
+			getenv("GIT_REFLOG_ACTION"), msg);
+	}
+	if (squash) {
+		squash_message(head_commit, remoteheads);
+	} else {
+		if (verbosity >= 0 && !merge_msg.len)
+			printf(_("No merge message -- not updating HEAD\n"));
+		else {
+			refs_update_ref(get_main_ref_store(the_repository),
+					reflog_message.buf, "HEAD", new_head,
+					head,
+					0, UPDATE_REFS_DIE_ON_ERR);
+			/*
+			 * We ignore errors in 'gc --auto', since the
+			 * user should see them.
+			 */
+			run_auto_maintenance(verbosity < 0);
+		}
+	}
+	if (new_head && show_diffstat) {
+		struct diff_options opts;
+		repo_diff_setup(the_repository, &opts);
+		init_diffstat_widths(&opts);
+		opts.output_format |=
+			DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+		opts.detect_rename = DIFF_DETECT_RENAME;
+		diff_setup_done(&opts);
+		diff_tree_oid(head, new_head, "", &opts);
+		diffcore_std(&opts);
+		diff_flush(&opts);
+	}
+
+	/* Run a post-merge hook */
+	run_hooks_l(the_repository, "post-merge", squash ? "1" : "0", NULL);
+
+	if (new_head)
+		apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
+	strbuf_release(&reflog_message);
+}
+
+/* Get the name for the merge commit's message. */
+static void merge_name(const char *remote, struct strbuf *msg)
+{
+	struct commit *remote_head;
+	struct object_id branch_head;
+	struct strbuf bname = STRBUF_INIT;
+	struct merge_remote_desc *desc;
+	const char *ptr;
+	char *found_ref = NULL;
+	int len, early;
+
+	copy_branchname(&bname, remote, 0);
+	remote = bname.buf;
+
+	oidclr(&branch_head, the_repository->hash_algo);
+	remote_head = get_merge_parent(remote);
+	if (!remote_head)
+		die(_("'%s' does not point to a commit"), remote);
+
+	if (repo_dwim_ref(the_repository, remote, strlen(remote), &branch_head,
+			  &found_ref, 0) > 0) {
+		if (starts_with(found_ref, "refs/heads/")) {
+			strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
+				    oid_to_hex(&branch_head), remote);
+			goto cleanup;
+		}
+		if (starts_with(found_ref, "refs/tags/")) {
+			strbuf_addf(msg, "%s\t\ttag '%s' of .\n",
+				    oid_to_hex(&branch_head), remote);
+			goto cleanup;
+		}
+		if (starts_with(found_ref, "refs/remotes/")) {
+			strbuf_addf(msg, "%s\t\tremote-tracking branch '%s' of .\n",
+				    oid_to_hex(&branch_head), remote);
+			goto cleanup;
+		}
+	}
+
+	/* See if remote matches <name>^^^.. or <name>~<number> */
+	for (len = 0, ptr = remote + strlen(remote);
+	     remote < ptr && ptr[-1] == '^';
+	     ptr--)
+		len++;
+	if (len)
+		early = 1;
+	else {
+		early = 0;
+		ptr = strrchr(remote, '~');
+		if (ptr) {
+			int seen_nonzero = 0;
+
+			len++; /* count ~ */
+			while (*++ptr && isdigit(*ptr)) {
+				seen_nonzero |= (*ptr != '0');
+				len++;
+			}
+			if (*ptr)
+				len = 0; /* not ...~<number> */
+			else if (seen_nonzero)
+				early = 1;
+			else if (len == 1)
+				early = 1; /* "name~" is "name~1"! */
+		}
+	}
+	if (len) {
+		struct strbuf truname = STRBUF_INIT;
+		strbuf_addf(&truname, "refs/heads/%s", remote);
+		strbuf_setlen(&truname, truname.len - len);
+		if (refs_ref_exists(get_main_ref_store(the_repository), truname.buf)) {
+			strbuf_addf(msg,
+				    "%s\t\tbranch '%s'%s of .\n",
+				    oid_to_hex(&remote_head->object.oid),
+				    truname.buf + 11,
+				    (early ? " (early part)" : ""));
+			strbuf_release(&truname);
+			goto cleanup;
+		}
+		strbuf_release(&truname);
+	}
+
+	desc = merge_remote_util(remote_head);
+	if (desc && desc->obj && desc->obj->type == OBJ_TAG) {
+		strbuf_addf(msg, "%s\t\t%s '%s'\n",
+			    oid_to_hex(&desc->obj->oid),
+			    type_name(desc->obj->type),
+			    remote);
+		goto cleanup;
+	}
+
+	strbuf_addf(msg, "%s\t\tcommit '%s'\n",
+		oid_to_hex(&remote_head->object.oid), remote);
+cleanup:
+	free(found_ref);
+	strbuf_release(&bname);
+}
+
+static void parse_branch_merge_options(char *bmo)
+{
+	const char **argv;
+	int argc;
+
+	if (!bmo)
+		return;
+	argc = split_cmdline(bmo, &argv);
+	if (argc < 0)
+		die(_("Bad branch.%s.mergeoptions string: %s"), branch,
+		    _(split_cmdline_strerror(argc)));
+	REALLOC_ARRAY(argv, argc + 2);
+	MOVE_ARRAY(argv + 1, argv, argc + 1);
+	argc++;
+	argv[0] = "branch.*.mergeoptions";
+	parse_options(argc, argv, NULL, builtin_merge_options,
+		      builtin_merge_usage, 0);
+	free(argv);
+}
+
+static int git_merge_config(const char *k, const char *v,
+			    const struct config_context *ctx, void *cb)
+{
+	int status;
+	const char *str;
+
+	if (branch &&
+	    skip_prefix(k, "branch.", &str) &&
+	    skip_prefix(str, branch, &str) &&
+	    !strcmp(str, ".mergeoptions")) {
+		free(branch_mergeoptions);
+		branch_mergeoptions = xstrdup(v);
+		return 0;
+	}
+
+	if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat")) {
+		show_diffstat = git_config_bool(k, v);
+	} else if (!strcmp(k, "merge.verifysignatures")) {
+		verify_signatures = git_config_bool(k, v);
+	} else if (!strcmp(k, "pull.twohead")) {
+		FREE_AND_NULL(pull_twohead);
+		return git_config_string(&pull_twohead, k, v);
+	} else if (!strcmp(k, "pull.octopus")) {
+		FREE_AND_NULL(pull_octopus);
+		return git_config_string(&pull_octopus, k, v);
+	} else if (!strcmp(k, "commit.cleanup")) {
+		return git_config_string(&cleanup_arg, k, v);
+	} else if (!strcmp(k, "merge.ff")) {
+		int boolval = git_parse_maybe_bool(v);
+		if (0 <= boolval) {
+			fast_forward = boolval ? FF_ALLOW : FF_NO;
+		} else if (v && !strcmp(v, "only")) {
+			fast_forward = FF_ONLY;
+		} /* do not barf on values from future versions of git */
+		return 0;
+	} else if (!strcmp(k, "merge.defaulttoupstream")) {
+		default_to_upstream = git_config_bool(k, v);
+		return 0;
+	} else if (!strcmp(k, "commit.gpgsign")) {
+		sign_commit = git_config_bool(k, v) ? "" : NULL;
+		return 0;
+	} else if (!strcmp(k, "gpg.mintrustlevel")) {
+		check_trust_level = 0;
+	} else if (!strcmp(k, "merge.autostash")) {
+		autostash = git_config_bool(k, v);
+		return 0;
+	}
+
+	status = fmt_merge_msg_config(k, v, ctx, cb);
+	if (status)
+		return status;
+	return git_diff_ui_config(k, v, ctx, cb);
+}
+
+static int read_tree_trivial(struct object_id *common, struct object_id *head,
+			     struct object_id *one)
+{
+	int i, nr_trees = 0;
+	struct tree *trees[MAX_UNPACK_TREES];
+	struct tree_desc t[MAX_UNPACK_TREES];
+	struct unpack_trees_options opts;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = 2;
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+	opts.update = 1;
+	opts.verbose_update = 1;
+	opts.trivial_merges_only = 1;
+	opts.merge = 1;
+	opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
+	trees[nr_trees] = parse_tree_indirect(common);
+	if (!trees[nr_trees++])
+		return -1;
+	trees[nr_trees] = parse_tree_indirect(head);
+	if (!trees[nr_trees++])
+		return -1;
+	trees[nr_trees] = parse_tree_indirect(one);
+	if (!trees[nr_trees++])
+		return -1;
+	opts.fn = threeway_merge;
+	cache_tree_free(&the_repository->index->cache_tree);
+	for (i = 0; i < nr_trees; i++) {
+		parse_tree(trees[i]);
+		init_tree_desc(t+i, &trees[i]->object.oid,
+			       trees[i]->buffer, trees[i]->size);
+	}
+	if (unpack_trees(nr_trees, t, &opts))
+		return -1;
+	return 0;
+}
+
+static void write_tree_trivial(struct object_id *oid)
+{
+	if (write_index_as_tree(oid, the_repository->index,
+				repo_get_index_file(the_repository),
+				0, NULL))
+		die(_("git write-tree failed to write a tree"));
+}
+
+static int try_merge_strategy(const char *strategy, struct commit_list *common,
+			      struct commit_list *remoteheads,
+			      struct commit *head)
+{
+	const char *head_arg = "HEAD";
+
+	if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
+					 SKIP_IF_UNCHANGED, 0, NULL, NULL,
+					 NULL) < 0)
+		die(_("Unable to write index."));
+
+	if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree") ||
+	    !strcmp(strategy, "ort")) {
+		struct lock_file lock = LOCK_INIT;
+		int clean, x;
+		struct commit *result;
+		struct commit_list *reversed = NULL;
+		struct merge_options o;
+		struct commit_list *j;
+
+		if (remoteheads->next) {
+			error(_("Not handling anything other than two heads merge."));
+			return 2;
+		}
+
+		init_ui_merge_options(&o, the_repository);
+		if (!strcmp(strategy, "subtree"))
+			o.subtree_shift = "";
+
+		o.show_rename_progress =
+			show_progress == -1 ? isatty(2) : show_progress;
+
+		for (x = 0; x < xopts.nr; x++)
+			if (parse_merge_opt(&o, xopts.v[x]))
+				die(_("unknown strategy option: -X%s"), xopts.v[x]);
+
+		o.branch1 = head_arg;
+		o.branch2 = merge_remote_util(remoteheads->item)->name;
+
+		for (j = common; j; j = j->next)
+			commit_list_insert(j->item, &reversed);
+
+		repo_hold_locked_index(the_repository, &lock,
+				       LOCK_DIE_ON_ERROR);
+		if (!strcmp(strategy, "ort"))
+			clean = merge_ort_recursive(&o, head, remoteheads->item,
+						    reversed, &result);
+		else
+			clean = merge_recursive(&o, head, remoteheads->item,
+						reversed, &result);
+		free_commit_list(reversed);
+		strbuf_release(&o.obuf);
+
+		if (clean < 0) {
+			rollback_lock_file(&lock);
+			return 2;
+		}
+		if (write_locked_index(the_repository->index, &lock,
+				       COMMIT_LOCK | SKIP_IF_UNCHANGED))
+			die(_("unable to write %s"), repo_get_index_file(the_repository));
+		return clean ? 0 : 1;
+	} else {
+		return try_merge_command(the_repository,
+					 strategy, xopts.nr, xopts.v,
+					 common, head_arg, remoteheads);
+	}
+}
+
+static void count_diff_files(struct diff_queue_struct *q,
+			     struct diff_options *opt UNUSED, void *data)
+{
+	int *count = data;
+
+	(*count) += q->nr;
+}
+
+static int count_unmerged_entries(void)
+{
+	int i, ret = 0;
+
+	for (i = 0; i < the_repository->index->cache_nr; i++)
+		if (ce_stage(the_repository->index->cache[i]))
+			ret++;
+
+	return ret;
+}
+
+static void add_strategies(const char *string, unsigned attr)
+{
+	int i;
+
+	if (string) {
+		struct string_list list = STRING_LIST_INIT_DUP;
+		struct string_list_item *item;
+		string_list_split(&list, string, ' ', -1);
+		for_each_string_list_item(item, &list)
+			append_strategy(get_strategy(item->string));
+		string_list_clear(&list, 0);
+		return;
+	}
+	for (i = 0; i < ARRAY_SIZE(all_strategy); i++)
+		if (all_strategy[i].attr & attr)
+			append_strategy(&all_strategy[i]);
+
+}
+
+static void read_merge_msg(struct strbuf *msg)
+{
+	const char *filename = git_path_merge_msg(the_repository);
+	strbuf_reset(msg);
+	if (strbuf_read_file(msg, filename, 0) < 0)
+		die_errno(_("Could not read from '%s'"), filename);
+}
+
+static void write_merge_state(struct commit_list *);
+static void abort_commit(struct commit_list *remoteheads, const char *err_msg)
+{
+	if (err_msg)
+		error("%s", err_msg);
+	fprintf(stderr,
+		_("Not committing merge; use 'git commit' to complete the merge.\n"));
+	write_merge_state(remoteheads);
+	exit(1);
+}
+
+static const char merge_editor_comment[] =
+N_("Please enter a commit message to explain why this merge is necessary,\n"
+   "especially if it merges an updated upstream into a topic branch.\n"
+   "\n");
+
+static const char scissors_editor_comment[] =
+N_("An empty message aborts the commit.\n");
+
+static const char no_scissors_editor_comment[] =
+N_("Lines starting with '%s' will be ignored, and an empty message aborts\n"
+   "the commit.\n");
+
+static void write_merge_heads(struct commit_list *);
+static void prepare_to_commit(struct commit_list *remoteheads)
+{
+	struct strbuf msg = STRBUF_INIT;
+	const char *index_file = repo_get_index_file(the_repository);
+
+	if (!no_verify) {
+		int invoked_hook;
+
+		if (run_commit_hook(0 < option_edit, index_file, &invoked_hook,
+				    "pre-merge-commit", NULL))
+			abort_commit(remoteheads, NULL);
+		/*
+		 * Re-read the index as pre-merge-commit hook could have updated it,
+		 * and write it out as a tree.  We must do this before we invoke
+		 * the editor and after we invoke run_status above.
+		 */
+		if (invoked_hook)
+			discard_index(the_repository->index);
+	}
+	read_index_from(the_repository->index, index_file,
+			repo_get_git_dir(the_repository));
+	strbuf_addbuf(&msg, &merge_msg);
+	if (squash)
+		BUG("the control must not reach here under --squash");
+	if (0 < option_edit) {
+		strbuf_addch(&msg, '\n');
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) {
+			wt_status_append_cut_line(&msg);
+			strbuf_commented_addf(&msg, comment_line_str, "\n");
+		}
+		strbuf_commented_addf(&msg, comment_line_str,
+				      _(merge_editor_comment));
+		if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS)
+			strbuf_commented_addf(&msg, comment_line_str,
+					      _(scissors_editor_comment));
+		else
+			strbuf_commented_addf(&msg, comment_line_str,
+				_(no_scissors_editor_comment), comment_line_str);
+	}
+	if (signoff)
+		append_signoff(&msg, ignored_log_message_bytes(msg.buf, msg.len), 0);
+	write_merge_heads(remoteheads);
+	write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len);
+	if (run_commit_hook(0 < option_edit, repo_get_index_file(the_repository),
+			    NULL, "prepare-commit-msg",
+			    git_path_merge_msg(the_repository), "merge", NULL))
+		abort_commit(remoteheads, NULL);
+	if (0 < option_edit) {
+		if (launch_editor(git_path_merge_msg(the_repository), NULL, NULL))
+			abort_commit(remoteheads, NULL);
+	}
+
+	if (!no_verify && run_commit_hook(0 < option_edit, repo_get_index_file(the_repository),
+					  NULL, "commit-msg",
+					  git_path_merge_msg(the_repository), NULL))
+		abort_commit(remoteheads, NULL);
+
+	read_merge_msg(&msg);
+	cleanup_message(&msg, cleanup_mode, 0);
+	if (!msg.len)
+		abort_commit(remoteheads, _("Empty commit message."));
+	strbuf_release(&merge_msg);
+	strbuf_addbuf(&merge_msg, &msg);
+	strbuf_release(&msg);
+}
+
+static int merge_trivial(struct commit *head, struct commit_list *remoteheads)
+{
+	struct object_id result_tree, result_commit;
+	struct commit_list *parents = NULL, **pptr = &parents;
+
+	if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET,
+					 SKIP_IF_UNCHANGED, 0, NULL, NULL,
+					 NULL) < 0)
+		return error(_("Unable to write index."));
+
+	write_tree_trivial(&result_tree);
+	printf(_("Wonderful.\n"));
+	pptr = commit_list_append(head, pptr);
+	pptr = commit_list_append(remoteheads->item, pptr);
+	prepare_to_commit(remoteheads);
+	if (commit_tree(merge_msg.buf, merge_msg.len, &result_tree, parents,
+			&result_commit, NULL, sign_commit))
+		die(_("failed to write commit object"));
+	finish(head, remoteheads, &result_commit, "In-index merge");
+
+	remove_merge_branch_state(the_repository);
+	free_commit_list(parents);
+	return 0;
+}
+
+static int finish_automerge(struct commit *head,
+			    int head_subsumed,
+			    struct commit_list *common,
+			    struct commit_list *remoteheads,
+			    struct object_id *result_tree,
+			    const char *wt_strategy)
+{
+	struct commit_list *parents = NULL;
+	struct strbuf buf = STRBUF_INIT;
+	struct object_id result_commit;
+
+	write_tree_trivial(result_tree);
+	free_commit_list(common);
+	parents = remoteheads;
+	if (!head_subsumed || fast_forward == FF_NO)
+		commit_list_insert(head, &parents);
+	prepare_to_commit(remoteheads);
+	if (commit_tree(merge_msg.buf, merge_msg.len, result_tree, parents,
+			&result_commit, NULL, sign_commit))
+		die(_("failed to write commit object"));
+	strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy);
+	finish(head, remoteheads, &result_commit, buf.buf);
+
+	strbuf_release(&buf);
+	remove_merge_branch_state(the_repository);
+	free_commit_list(parents);
+	return 0;
+}
+
+static int suggest_conflicts(void)
+{
+	const char *filename;
+	FILE *fp;
+	struct strbuf msgbuf = STRBUF_INIT;
+
+	filename = git_path_merge_msg(the_repository);
+	fp = xfopen(filename, "a");
+
+	/*
+	 * We can't use cleanup_mode because if we're not using the editor,
+	 * get_cleanup_mode will return COMMIT_MSG_CLEANUP_SPACE instead, even
+	 * though the message is meant to be processed later by git-commit.
+	 * Thus, we will get the cleanup mode which is returned when we _are_
+	 * using an editor.
+	 */
+	append_conflicts_hint(the_repository->index, &msgbuf,
+			      get_cleanup_mode(cleanup_arg, 1));
+	fputs(msgbuf.buf, fp);
+	strbuf_release(&msgbuf);
+	fclose(fp);
+	repo_rerere(the_repository, allow_rerere_auto);
+	printf(_("Automatic merge failed; "
+			"fix conflicts and then commit the result.\n"));
+	return 1;
+}
+
+static int evaluate_result(void)
+{
+	int cnt = 0;
+	struct rev_info rev;
+
+	/* Check how many files differ. */
+	repo_init_revisions(the_repository, &rev, "");
+	setup_revisions(0, NULL, &rev, NULL);
+	rev.diffopt.output_format |=
+		DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = count_diff_files;
+	rev.diffopt.format_callback_data = &cnt;
+	run_diff_files(&rev, 0);
+
+	/*
+	 * Check how many unmerged entries are
+	 * there.
+	 */
+	cnt += count_unmerged_entries();
+
+	release_revisions(&rev);
+	return cnt;
+}
+
+/*
+ * Pretend as if the user told us to merge with the remote-tracking
+ * branch we have for the upstream of the current branch
+ */
+static int setup_with_upstream(const char ***argv)
+{
+	struct branch *branch = branch_get(NULL);
+	int i;
+	const char **args;
+
+	if (!branch)
+		die(_("No current branch."));
+	if (!branch->remote_name)
+		die(_("No remote for the current branch."));
+	if (!branch->merge_nr)
+		die(_("No default upstream defined for the current branch."));
+
+	args = xcalloc(st_add(branch->merge_nr, 1), sizeof(char *));
+	for (i = 0; i < branch->merge_nr; i++) {
+		if (!branch->merge[i]->dst)
+			die(_("No remote-tracking branch for %s from %s"),
+			    branch->merge[i]->src, branch->remote_name);
+		args[i] = branch->merge[i]->dst;
+	}
+	args[i] = NULL;
+	*argv = args;
+	return i;
+}
+
+static void write_merge_heads(struct commit_list *remoteheads)
+{
+	struct commit_list *j;
+	struct strbuf buf = STRBUF_INIT;
+
+	for (j = remoteheads; j; j = j->next) {
+		struct object_id *oid;
+		struct commit *c = j->item;
+		struct merge_remote_desc *desc;
+
+		desc = merge_remote_util(c);
+		if (desc && desc->obj) {
+			oid = &desc->obj->oid;
+		} else {
+			oid = &c->object.oid;
+		}
+		strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
+	}
+	write_file_buf(git_path_merge_head(the_repository), buf.buf, buf.len);
+
+	strbuf_reset(&buf);
+	if (fast_forward == FF_NO)
+		strbuf_addstr(&buf, "no-ff");
+	write_file_buf(git_path_merge_mode(the_repository), buf.buf, buf.len);
+	strbuf_release(&buf);
+}
+
+static void write_merge_state(struct commit_list *remoteheads)
+{
+	write_merge_heads(remoteheads);
+	strbuf_addch(&merge_msg, '\n');
+	write_file_buf(git_path_merge_msg(the_repository), merge_msg.buf,
+		       merge_msg.len);
+}
+
+static int default_edit_option(void)
+{
+	static const char name[] = "GIT_MERGE_AUTOEDIT";
+	const char *e = getenv(name);
+	struct stat st_stdin, st_stdout;
+
+	if (have_message)
+		/* an explicit -m msg without --[no-]edit */
+		return 0;
+
+	if (e) {
+		int v = git_parse_maybe_bool(e);
+		if (v < 0)
+			die(_("Bad value '%s' in environment '%s'"), e, name);
+		return v;
+	}
+
+	/* Use editor if stdin and stdout are the same and is a tty */
+	return (!fstat(0, &st_stdin) &&
+		!fstat(1, &st_stdout) &&
+		isatty(0) && isatty(1) &&
+		st_stdin.st_dev == st_stdout.st_dev &&
+		st_stdin.st_ino == st_stdout.st_ino &&
+		st_stdin.st_mode == st_stdout.st_mode);
+}
+
+static struct commit_list *reduce_parents(struct commit *head_commit,
+					  int *head_subsumed,
+					  struct commit_list *remoteheads)
+{
+	struct commit_list *parents, **remotes;
+
+	/*
+	 * Is the current HEAD reachable from another commit being
+	 * merged?  If so we do not want to record it as a parent of
+	 * the resulting merge, unless --no-ff is given.  We will flip
+	 * this variable to 0 when we find HEAD among the independent
+	 * tips being merged.
+	 */
+	*head_subsumed = 1;
+
+	/* Find what parents to record by checking independent ones. */
+	parents = reduce_heads(remoteheads);
+	free_commit_list(remoteheads);
+
+	remoteheads = NULL;
+	remotes = &remoteheads;
+	while (parents) {
+		struct commit *commit = pop_commit(&parents);
+		if (commit == head_commit)
+			*head_subsumed = 0;
+		else
+			remotes = &commit_list_insert(commit, remotes)->next;
+	}
+	return remoteheads;
+}
+
+static void prepare_merge_message(struct strbuf *merge_names, struct strbuf *merge_msg)
+{
+	struct fmt_merge_msg_opts opts;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.add_title = !have_message;
+	opts.shortlog_len = shortlog_len;
+	opts.credit_people = (0 < option_edit);
+	opts.into_name = into_name;
+
+	fmt_merge_msg(merge_names, merge_msg, &opts);
+	if (merge_msg->len)
+		strbuf_setlen(merge_msg, merge_msg->len - 1);
+}
+
+static void handle_fetch_head(struct commit_list **remotes, struct strbuf *merge_names)
+{
+	const char *filename;
+	int fd, pos, npos;
+	struct strbuf fetch_head_file = STRBUF_INIT;
+	const unsigned hexsz = the_hash_algo->hexsz;
+
+	if (!merge_names)
+		merge_names = &fetch_head_file;
+
+	filename = git_path_fetch_head(the_repository);
+	fd = xopen(filename, O_RDONLY);
+
+	if (strbuf_read(merge_names, fd, 0) < 0)
+		die_errno(_("could not read '%s'"), filename);
+	if (close(fd) < 0)
+		die_errno(_("could not close '%s'"), filename);
+
+	for (pos = 0; pos < merge_names->len; pos = npos) {
+		struct object_id oid;
+		char *ptr;
+		struct commit *commit;
+
+		ptr = strchr(merge_names->buf + pos, '\n');
+		if (ptr)
+			npos = ptr - merge_names->buf + 1;
+		else
+			npos = merge_names->len;
+
+		if (npos - pos < hexsz + 2 ||
+		    get_oid_hex(merge_names->buf + pos, &oid))
+			commit = NULL; /* bad */
+		else if (memcmp(merge_names->buf + pos + hexsz, "\t\t", 2))
+			continue; /* not-for-merge */
+		else {
+			char saved = merge_names->buf[pos + hexsz];
+			merge_names->buf[pos + hexsz] = '\0';
+			commit = get_merge_parent(merge_names->buf + pos);
+			merge_names->buf[pos + hexsz] = saved;
+		}
+		if (!commit) {
+			if (ptr)
+				*ptr = '\0';
+			die(_("not something we can merge in %s: %s"),
+			    filename, merge_names->buf + pos);
+		}
+		remotes = &commit_list_insert(commit, remotes)->next;
+	}
+
+	if (merge_names == &fetch_head_file)
+		strbuf_release(&fetch_head_file);
+}
+
+static struct commit_list *collect_parents(struct commit *head_commit,
+					   int *head_subsumed,
+					   int argc, const char **argv,
+					   struct strbuf *merge_msg)
+{
+	int i;
+	struct commit_list *remoteheads = NULL;
+	struct commit_list **remotes = &remoteheads;
+	struct strbuf merge_names = STRBUF_INIT, *autogen = NULL;
+
+	if (merge_msg && (!have_message || shortlog_len))
+		autogen = &merge_names;
+
+	if (head_commit)
+		remotes = &commit_list_insert(head_commit, remotes)->next;
+
+	if (argc == 1 && !strcmp(argv[0], "FETCH_HEAD")) {
+		handle_fetch_head(remotes, autogen);
+		remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
+	} else {
+		for (i = 0; i < argc; i++) {
+			struct commit *commit = get_merge_parent(argv[i]);
+			if (!commit)
+				help_unknown_ref(argv[i], "merge",
+						 _("not something we can merge"));
+			remotes = &commit_list_insert(commit, remotes)->next;
+		}
+		remoteheads = reduce_parents(head_commit, head_subsumed, remoteheads);
+		if (autogen) {
+			struct commit_list *p;
+			for (p = remoteheads; p; p = p->next)
+				merge_name(merge_remote_util(p->item)->name, autogen);
+		}
+	}
+
+	if (autogen) {
+		prepare_merge_message(autogen, merge_msg);
+		strbuf_release(autogen);
+	}
+
+	return remoteheads;
+}
+
+static int merging_a_throwaway_tag(struct commit *commit)
+{
+	char *tag_ref;
+	struct object_id oid;
+	int is_throwaway_tag = 0;
+
+	/* Are we merging a tag? */
+	if (!merge_remote_util(commit) ||
+	    !merge_remote_util(commit)->obj ||
+	    merge_remote_util(commit)->obj->type != OBJ_TAG)
+		return is_throwaway_tag;
+
+	/*
+	 * Now we know we are merging a tag object.  Are we downstream
+	 * and following the tags from upstream?  If so, we must have
+	 * the tag object pointed at by "refs/tags/$T" where $T is the
+	 * tagname recorded in the tag object.  We want to allow such
+	 * a "just to catch up" merge to fast-forward.
+	 *
+	 * Otherwise, we are playing an integrator's role, making a
+	 * merge with a throw-away tag from a contributor with
+	 * something like "git pull $contributor $signed_tag".
+	 * We want to forbid such a merge from fast-forwarding
+	 * by default; otherwise we would not keep the signature
+	 * anywhere.
+	 */
+	tag_ref = xstrfmt("refs/tags/%s",
+			  ((struct tag *)merge_remote_util(commit)->obj)->tag);
+	if (!refs_read_ref(get_main_ref_store(the_repository), tag_ref, &oid) &&
+	    oideq(&oid, &merge_remote_util(commit)->obj->oid))
+		is_throwaway_tag = 0;
+	else
+		is_throwaway_tag = 1;
+	free(tag_ref);
+	return is_throwaway_tag;
+}
+
+int cmd_merge(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	struct object_id result_tree, stash, head_oid;
+	struct commit *head_commit;
+	struct strbuf buf = STRBUF_INIT;
+	int i, ret = 0, head_subsumed;
+	int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
+	struct commit_list *common = NULL;
+	const char *best_strategy = NULL, *wt_strategy = NULL;
+	struct commit_list *remoteheads = NULL, *p;
+	void *branch_to_free;
+	int orig_argc = argc;
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_merge_usage, builtin_merge_options);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	/*
+	 * Check if we are _not_ on a detached HEAD, i.e. if there is a
+	 * current branch.
+	 */
+	branch = branch_to_free = refs_resolve_refdup(get_main_ref_store(the_repository),
+						      "HEAD", 0, &head_oid,
+						      NULL);
+	if (branch)
+		skip_prefix(branch, "refs/heads/", &branch);
+
+	if (!pull_twohead) {
+		char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
+		if (default_strategy && !strcmp(default_strategy, "ort"))
+			pull_twohead = xstrdup("ort");
+	}
+
+	init_diff_ui_defaults();
+	git_config(git_merge_config, NULL);
+
+	if (!branch || is_null_oid(&head_oid))
+		head_commit = NULL;
+	else
+		head_commit = lookup_commit_or_die(&head_oid, "HEAD");
+
+	if (branch_mergeoptions)
+		parse_branch_merge_options(branch_mergeoptions);
+	argc = parse_options(argc, argv, prefix, builtin_merge_options,
+			builtin_merge_usage, 0);
+	if (shortlog_len < 0)
+		shortlog_len = (merge_log_config > 0) ? merge_log_config : 0;
+
+	if (verbosity < 0 && show_progress == -1)
+		show_progress = 0;
+
+	if (abort_current_merge) {
+		int nargc = 2;
+		const char *nargv[] = {"reset", "--merge", NULL};
+		char stash_oid_hex[GIT_MAX_HEXSZ + 1];
+		struct object_id stash_oid = {0};
+
+		if (orig_argc != 2)
+			usage_msg_opt(_("--abort expects no arguments"),
+			      builtin_merge_usage, builtin_merge_options);
+
+		if (!file_exists(git_path_merge_head(the_repository)))
+			die(_("There is no merge to abort (MERGE_HEAD missing)."));
+
+		if (!refs_read_ref(get_main_ref_store(the_repository), "MERGE_AUTOSTASH", &stash_oid))
+			refs_delete_ref(get_main_ref_store(the_repository),
+					"", "MERGE_AUTOSTASH", &stash_oid,
+					REF_NO_DEREF);
+
+		/* Invoke 'git reset --merge' */
+		ret = cmd_reset(nargc, nargv, prefix, the_repository);
+
+		if (!is_null_oid(&stash_oid)) {
+			oid_to_hex_r(stash_oid_hex, &stash_oid);
+			apply_autostash_oid(stash_oid_hex);
+		}
+
+		goto done;
+	}
+
+	if (quit_current_merge) {
+		if (orig_argc != 2)
+			usage_msg_opt(_("--quit expects no arguments"),
+				      builtin_merge_usage,
+				      builtin_merge_options);
+
+		remove_merge_branch_state(the_repository);
+		goto done;
+	}
+
+	if (continue_current_merge) {
+		int nargc = 1;
+		const char *nargv[] = {"commit", NULL};
+
+		if (orig_argc != 2)
+			usage_msg_opt(_("--continue expects no arguments"),
+			      builtin_merge_usage, builtin_merge_options);
+
+		if (!file_exists(git_path_merge_head(the_repository)))
+			die(_("There is no merge in progress (MERGE_HEAD missing)."));
+
+		/* Invoke 'git commit' */
+		ret = cmd_commit(nargc, nargv, prefix, the_repository);
+		goto done;
+	}
+
+	if (repo_read_index_unmerged(the_repository))
+		die_resolve_conflict("merge");
+
+	if (file_exists(git_path_merge_head(the_repository))) {
+		/*
+		 * There is no unmerged entry, don't advise 'git
+		 * add/rm <file>', just 'git commit'.
+		 */
+		if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
+			die(_("You have not concluded your merge (MERGE_HEAD exists).\n"
+				  "Please, commit your changes before you merge."));
+		else
+			die(_("You have not concluded your merge (MERGE_HEAD exists)."));
+	}
+	if (refs_ref_exists(get_main_ref_store(the_repository), "CHERRY_PICK_HEAD")) {
+		if (advice_enabled(ADVICE_RESOLVE_CONFLICT))
+			die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists).\n"
+			    "Please, commit your changes before you merge."));
+		else
+			die(_("You have not concluded your cherry-pick (CHERRY_PICK_HEAD exists)."));
+	}
+	resolve_undo_clear_index(the_repository->index);
+
+	if (option_edit < 0)
+		option_edit = default_edit_option();
+
+	cleanup_mode = get_cleanup_mode(cleanup_arg, 0 < option_edit);
+
+	if (verbosity < 0)
+		show_diffstat = 0;
+
+	if (squash) {
+		if (fast_forward == FF_NO)
+			die(_("options '%s' and '%s' cannot be used together"), "--squash", "--no-ff.");
+		if (option_commit > 0)
+			die(_("options '%s' and '%s' cannot be used together"), "--squash", "--commit.");
+		/*
+		 * squash can now silently disable option_commit - this is not
+		 * a problem as it is only overriding the default, not a user
+		 * supplied option.
+		 */
+		option_commit = 0;
+	}
+
+	if (option_commit < 0)
+		option_commit = 1;
+
+	if (!argc) {
+		if (default_to_upstream)
+			argc = setup_with_upstream(&argv);
+		else
+			die(_("No commit specified and merge.defaultToUpstream not set."));
+	} else if (argc == 1 && !strcmp(argv[0], "-")) {
+		argv[0] = "@{-1}";
+	}
+
+	if (!argc)
+		usage_with_options(builtin_merge_usage,
+			builtin_merge_options);
+
+	if (!head_commit) {
+		/*
+		 * If the merged head is a valid one there is no reason
+		 * to forbid "git merge" into a branch yet to be born.
+		 * We do the same for "git pull".
+		 */
+		struct object_id *remote_head_oid;
+		if (squash)
+			die(_("Squash commit into empty head not supported yet"));
+		if (fast_forward == FF_NO)
+			die(_("Non-fast-forward commit does not make sense into "
+			    "an empty head"));
+		remoteheads = collect_parents(head_commit, &head_subsumed,
+					      argc, argv, NULL);
+		if (!remoteheads)
+			die(_("%s - not something we can merge"), argv[0]);
+		if (remoteheads->next)
+			die(_("Can merge only exactly one commit into empty head"));
+
+		if (verify_signatures)
+			verify_merge_signature(remoteheads->item, verbosity,
+					       check_trust_level);
+
+		remote_head_oid = &remoteheads->item->object.oid;
+		read_empty(remote_head_oid);
+		refs_update_ref(get_main_ref_store(the_repository),
+				"initial pull", "HEAD", remote_head_oid, NULL,
+				0,
+				UPDATE_REFS_DIE_ON_ERR);
+		goto done;
+	}
+
+	/*
+	 * All the rest are the commits being merged; prepare
+	 * the standard merge summary message to be appended
+	 * to the given message.
+	 */
+	remoteheads = collect_parents(head_commit, &head_subsumed,
+				      argc, argv, &merge_msg);
+
+	if (!head_commit || !argc)
+		usage_with_options(builtin_merge_usage,
+			builtin_merge_options);
+
+	if (verify_signatures) {
+		for (p = remoteheads; p; p = p->next) {
+			verify_merge_signature(p->item, verbosity,
+					       check_trust_level);
+		}
+	}
+
+	strbuf_addstr(&buf, "merge");
+	for (p = remoteheads; p; p = p->next)
+		strbuf_addf(&buf, " %s", merge_remote_util(p->item)->name);
+	setenv("GIT_REFLOG_ACTION", buf.buf, 0);
+	strbuf_reset(&buf);
+
+	for (p = remoteheads; p; p = p->next) {
+		struct commit *commit = p->item;
+		strbuf_addf(&buf, "GITHEAD_%s",
+			    oid_to_hex(&commit->object.oid));
+		setenv(buf.buf, merge_remote_util(commit)->name, 1);
+		strbuf_reset(&buf);
+		if (fast_forward != FF_ONLY && merging_a_throwaway_tag(commit))
+			fast_forward = FF_NO;
+	}
+
+	if (!use_strategies && !pull_twohead &&
+	    remoteheads && !remoteheads->next) {
+		char *default_strategy = getenv("GIT_TEST_MERGE_ALGORITHM");
+		if (default_strategy)
+			append_strategy(get_strategy(default_strategy));
+	}
+	if (!use_strategies) {
+		if (!remoteheads)
+			; /* already up-to-date */
+		else if (!remoteheads->next)
+			add_strategies(pull_twohead, DEFAULT_TWOHEAD);
+		else
+			add_strategies(pull_octopus, DEFAULT_OCTOPUS);
+	}
+
+	for (i = 0; i < use_strategies_nr; i++) {
+		if (use_strategies[i]->attr & NO_FAST_FORWARD)
+			fast_forward = FF_NO;
+		if (use_strategies[i]->attr & NO_TRIVIAL)
+			allow_trivial = 0;
+	}
+
+	if (!remoteheads)
+		; /* already up-to-date */
+	else if (!remoteheads->next) {
+		if (repo_get_merge_bases(the_repository, head_commit,
+					 remoteheads->item, &common) < 0) {
+			ret = 2;
+			goto done;
+		}
+	} else {
+		struct commit_list *list = remoteheads;
+		commit_list_insert(head_commit, &list);
+		if (get_octopus_merge_bases(list, &common) < 0) {
+			free(list);
+			ret = 2;
+			goto done;
+		}
+		free(list);
+	}
+
+	refs_update_ref(get_main_ref_store(the_repository),
+			"updating ORIG_HEAD", "ORIG_HEAD",
+			&head_commit->object.oid, NULL, 0,
+			UPDATE_REFS_DIE_ON_ERR);
+
+	if (remoteheads && !common) {
+		/* No common ancestors found. */
+		if (!allow_unrelated_histories)
+			die(_("refusing to merge unrelated histories"));
+		/* otherwise, we need a real merge. */
+	} else if (!remoteheads ||
+		 (!remoteheads->next && !common->next &&
+		  common->item == remoteheads->item)) {
+		/*
+		 * If head can reach all the merge then we are up to date.
+		 * but first the most common case of merging one remote.
+		 */
+		finish_up_to_date();
+		goto done;
+	} else if (fast_forward != FF_NO && !remoteheads->next &&
+			!common->next &&
+			oideq(&common->item->object.oid, &head_commit->object.oid)) {
+		/* Again the most common case of merging one remote. */
+		const char *msg = have_message ?
+			"Fast-forward (no commit created; -m option ignored)" :
+			"Fast-forward";
+		struct commit *commit;
+
+		if (verbosity >= 0) {
+			printf(_("Updating %s..%s\n"),
+			       repo_find_unique_abbrev(the_repository, &head_commit->object.oid,
+						       DEFAULT_ABBREV),
+			       repo_find_unique_abbrev(the_repository, &remoteheads->item->object.oid,
+						       DEFAULT_ABBREV));
+		}
+		commit = remoteheads->item;
+		if (!commit) {
+			ret = 1;
+			goto done;
+		}
+
+		if (autostash)
+			create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
+		if (checkout_fast_forward(the_repository,
+					  &head_commit->object.oid,
+					  &commit->object.oid,
+					  overwrite_ignore)) {
+			apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
+			ret = 1;
+			goto done;
+		}
+
+		finish(head_commit, remoteheads, &commit->object.oid, msg);
+		remove_merge_branch_state(the_repository);
+		goto done;
+	} else if (!remoteheads->next && common->next)
+		;
+		/*
+		 * We are not doing octopus and not fast-forward.  Need
+		 * a real merge.
+		 */
+	else if (!remoteheads->next && !common->next && option_commit) {
+		/*
+		 * We are not doing octopus, not fast-forward, and have
+		 * only one common.
+		 */
+		refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL);
+		if (allow_trivial && fast_forward != FF_ONLY) {
+			/*
+			 * Must first ensure that index matches HEAD before
+			 * attempting a trivial merge.
+			 */
+			struct tree *head_tree = repo_get_commit_tree(the_repository,
+								      head_commit);
+			struct strbuf sb = STRBUF_INIT;
+
+			if (repo_index_has_changes(the_repository, head_tree,
+						   &sb)) {
+				error(_("Your local changes to the following files would be overwritten by merge:\n  %s"),
+				      sb.buf);
+				strbuf_release(&sb);
+				ret = 2;
+				goto done;
+			}
+
+			/* See if it is really trivial. */
+			git_committer_info(IDENT_STRICT);
+			printf(_("Trying really trivial in-index merge...\n"));
+			if (!read_tree_trivial(&common->item->object.oid,
+					       &head_commit->object.oid,
+					       &remoteheads->item->object.oid)) {
+				ret = merge_trivial(head_commit, remoteheads);
+				goto done;
+			}
+			printf(_("Nope.\n"));
+		}
+	} else {
+		/*
+		 * An octopus.  If we can reach all the remote we are up
+		 * to date.
+		 */
+		int up_to_date = 1;
+		struct commit_list *j;
+
+		for (j = remoteheads; j; j = j->next) {
+			struct commit_list *common_one = NULL;
+			struct commit *common_item;
+
+			/*
+			 * Here we *have* to calculate the individual
+			 * merge_bases again, otherwise "git merge HEAD^
+			 * HEAD^^" would be missed.
+			 */
+			if (repo_get_merge_bases(the_repository, head_commit,
+						 j->item, &common_one) < 0)
+				exit(128);
+
+			common_item = common_one->item;
+			free_commit_list(common_one);
+			if (!oideq(&common_item->object.oid, &j->item->object.oid)) {
+				up_to_date = 0;
+				break;
+			}
+		}
+		if (up_to_date) {
+			finish_up_to_date();
+			goto done;
+		}
+	}
+
+	if (fast_forward == FF_ONLY)
+		die_ff_impossible();
+
+	if (autostash)
+		create_autostash_ref(the_repository, "MERGE_AUTOSTASH");
+
+	/* We are going to make a new commit. */
+	git_committer_info(IDENT_STRICT);
+
+	/*
+	 * At this point, we need a real merge.  No matter what strategy
+	 * we use, it would operate on the index, possibly affecting the
+	 * working tree, and when resolved cleanly, have the desired
+	 * tree in the index -- this means that the index must be in
+	 * sync with the head commit.  The strategies are responsible
+	 * to ensure this.
+	 *
+	 * Stash away the local changes so that we can try more than one
+	 * and/or recover from merge strategies bailing while leaving the
+	 * index and working tree polluted.
+	 */
+	if (save_state(&stash))
+		oidclr(&stash, the_repository->hash_algo);
+
+	for (i = 0; i < use_strategies_nr; i++) {
+		int ret, cnt;
+		if (i) {
+			printf(_("Rewinding the tree to pristine...\n"));
+			restore_state(&head_commit->object.oid, &stash);
+		}
+		if (use_strategies_nr != 1)
+			printf(_("Trying merge strategy %s...\n"),
+				use_strategies[i]->name);
+		/*
+		 * Remember which strategy left the state in the working
+		 * tree.
+		 */
+		wt_strategy = use_strategies[i]->name;
+
+		ret = try_merge_strategy(wt_strategy,
+					 common, remoteheads,
+					 head_commit);
+		/*
+		 * The backend exits with 1 when conflicts are
+		 * left to be resolved, with 2 when it does not
+		 * handle the given merge at all.
+		 */
+		if (ret < 2) {
+			if (!ret) {
+				/*
+				 * This strategy worked; no point in trying
+				 * another.
+				 */
+				merge_was_ok = 1;
+				best_strategy = wt_strategy;
+				break;
+			}
+			cnt = (use_strategies_nr > 1) ? evaluate_result() : 0;
+			if (best_cnt <= 0 || cnt <= best_cnt) {
+				best_strategy = wt_strategy;
+				best_cnt = cnt;
+			}
+		}
+	}
+
+	/*
+	 * If we have a resulting tree, that means the strategy module
+	 * auto resolved the merge cleanly.
+	 */
+	if (merge_was_ok && option_commit) {
+		automerge_was_ok = 1;
+		ret = finish_automerge(head_commit, head_subsumed,
+				       common, remoteheads,
+				       &result_tree, wt_strategy);
+		goto done;
+	}
+
+	/*
+	 * Pick the result from the best strategy and have the user fix
+	 * it up.
+	 */
+	if (!best_strategy) {
+		restore_state(&head_commit->object.oid, &stash);
+		if (use_strategies_nr > 1)
+			fprintf(stderr,
+				_("No merge strategy handled the merge.\n"));
+		else
+			fprintf(stderr, _("Merge with strategy %s failed.\n"),
+				use_strategies[0]->name);
+		apply_autostash_ref(the_repository, "MERGE_AUTOSTASH");
+		ret = 2;
+		goto done;
+	} else if (best_strategy == wt_strategy)
+		; /* We already have its result in the working tree. */
+	else {
+		printf(_("Rewinding the tree to pristine...\n"));
+		restore_state(&head_commit->object.oid, &stash);
+		printf(_("Using the %s strategy to prepare resolving by hand.\n"),
+			best_strategy);
+		try_merge_strategy(best_strategy, common, remoteheads,
+				   head_commit);
+	}
+
+	if (squash) {
+		finish(head_commit, remoteheads, NULL, NULL);
+
+		git_test_write_commit_graph_or_die();
+	} else
+		write_merge_state(remoteheads);
+
+	if (merge_was_ok)
+		fprintf(stderr, _("Automatic merge went well; "
+			"stopped before committing as requested\n"));
+	else
+		ret = suggest_conflicts();
+	if (autostash)
+		printf(_("When finished, apply stashed changes with `git stash pop`\n"));
+
+done:
+	if (!automerge_was_ok) {
+		free_commit_list(common);
+		free_commit_list(remoteheads);
+	}
+	strbuf_release(&buf);
+	free(branch_to_free);
+	free(pull_twohead);
+	free(pull_octopus);
+	discard_index(the_repository->index);
+	return ret;
+}
diff --git a/builtin/mktag.c b/builtin/mktag.c
new file mode 100644
index 0000000000..6e188dce50
--- /dev/null
+++ b/builtin/mktag.c
@@ -0,0 +1,115 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
+#include "parse-options.h"
+#include "strbuf.h"
+#include "replace-object.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "fsck.h"
+#include "config.h"
+
+static char const * const builtin_mktag_usage[] = {
+	"git mktag",
+	NULL
+};
+static int option_strict = 1;
+
+static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
+
+static int mktag_fsck_error_func(struct fsck_options *o UNUSED,
+				 void *fsck_report UNUSED,
+				 enum fsck_msg_type msg_type,
+				 enum fsck_msg_id msg_id UNUSED,
+				 const char *message)
+{
+	switch (msg_type) {
+	case FSCK_WARN:
+		if (!option_strict) {
+			fprintf_ln(stderr, _("warning: tag input does not pass fsck: %s"), message);
+			return 0;
+
+		}
+		/* fallthrough */
+	case FSCK_ERROR:
+		/*
+		 * We treat both warnings and errors as errors, things
+		 * like missing "tagger" lines are "only" warnings
+		 * under fsck, we've always considered them an error.
+		 */
+		fprintf_ln(stderr, _("error: tag input does not pass fsck: %s"), message);
+		return 1;
+	default:
+		BUG(_("%d (FSCK_IGNORE?) should never trigger this callback"),
+		    msg_type);
+	}
+}
+
+static int verify_object_in_tag(struct object_id *tagged_oid, int *tagged_type)
+{
+	int ret;
+	enum object_type type;
+	unsigned long size;
+	void *buffer;
+	const struct object_id *repl;
+
+	buffer = repo_read_object_file(the_repository, tagged_oid, &type,
+				       &size);
+	if (!buffer)
+		die(_("could not read tagged object '%s'"),
+		    oid_to_hex(tagged_oid));
+	if (type != *tagged_type)
+		die(_("object '%s' tagged as '%s', but is a '%s' type"),
+		    oid_to_hex(tagged_oid),
+		    type_name(*tagged_type), type_name(type));
+
+	repl = lookup_replace_object(the_repository, tagged_oid);
+	ret = check_object_signature(the_repository, repl, buffer, size,
+				     *tagged_type);
+	free(buffer);
+
+	return ret;
+}
+
+int cmd_mktag(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	static struct option builtin_mktag_options[] = {
+		OPT_BOOL(0, "strict", &option_strict,
+			 N_("enable more strict checking")),
+		OPT_END(),
+	};
+	struct strbuf buf = STRBUF_INIT;
+	struct object_id tagged_oid;
+	int tagged_type;
+	struct object_id result;
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_mktag_options,
+			     builtin_mktag_usage, 0);
+
+	if (strbuf_read(&buf, 0, 0) < 0)
+		die_errno(_("could not read from stdin"));
+
+	fsck_options.error_func = mktag_fsck_error_func;
+	fsck_set_msg_type_from_ids(&fsck_options, FSCK_MSG_EXTRA_HEADER_ENTRY,
+				   FSCK_WARN);
+	/* config might set fsck.extraHeaderEntry=* again */
+	git_config(git_fsck_config, &fsck_options);
+	if (fsck_tag_standalone(NULL, buf.buf, buf.len, &fsck_options,
+				&tagged_oid, &tagged_type))
+		die(_("tag on stdin did not pass our strict fsck check"));
+
+	if (verify_object_in_tag(&tagged_oid, &tagged_type) < 0)
+		die(_("tag on stdin did not refer to a valid object"));
+
+	if (write_object_file(buf.buf, buf.len, OBJ_TAG, &result) < 0)
+		die(_("unable to write tag file"));
+
+	strbuf_release(&buf);
+	puts(oid_to_hex(&result));
+	return 0;
+}
diff --git a/builtin/mktree.c b/builtin/mktree.c
new file mode 100644
index 0000000000..3c16faa40e
--- /dev/null
+++ b/builtin/mktree.c
@@ -0,0 +1,208 @@
+/*
+ * GIT - the stupid content tracker
+ *
+ * Copyright (c) Junio C Hamano, 2006, 2009
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
+#include "quote.h"
+#include "strbuf.h"
+#include "tree.h"
+#include "parse-options.h"
+#include "object-store-ll.h"
+
+static struct treeent {
+	unsigned mode;
+	struct object_id oid;
+	int len;
+	char name[FLEX_ARRAY];
+} **entries;
+static int alloc, used;
+
+static void append_to_tree(unsigned mode, struct object_id *oid, char *path)
+{
+	struct treeent *ent;
+	size_t len = strlen(path);
+	if (strchr(path, '/'))
+		die("path %s contains slash", path);
+
+	FLEX_ALLOC_MEM(ent, name, path, len);
+	ent->mode = mode;
+	ent->len = len;
+	oidcpy(&ent->oid, oid);
+
+	ALLOC_GROW(entries, used + 1, alloc);
+	entries[used++] = ent;
+}
+
+static int ent_compare(const void *a_, const void *b_)
+{
+	struct treeent *a = *(struct treeent **)a_;
+	struct treeent *b = *(struct treeent **)b_;
+	return base_name_compare(a->name, a->len, a->mode,
+				 b->name, b->len, b->mode);
+}
+
+static void write_tree(struct object_id *oid)
+{
+	struct strbuf buf;
+	size_t size;
+	int i;
+
+	QSORT(entries, used, ent_compare);
+	for (size = i = 0; i < used; i++)
+		size += 32 + entries[i]->len;
+
+	strbuf_init(&buf, size);
+	for (i = 0; i < used; i++) {
+		struct treeent *ent = entries[i];
+		strbuf_addf(&buf, "%o %s%c", ent->mode, ent->name, '\0');
+		strbuf_add(&buf, ent->oid.hash, the_hash_algo->rawsz);
+	}
+
+	write_object_file(buf.buf, buf.len, OBJ_TREE, oid);
+	strbuf_release(&buf);
+}
+
+static const char *mktree_usage[] = {
+	"git mktree [-z] [--missing] [--batch]",
+	NULL
+};
+
+static void mktree_line(char *buf, int nul_term_line, int allow_missing)
+{
+	char *ptr, *ntr;
+	const char *p;
+	unsigned mode;
+	enum object_type mode_type; /* object type derived from mode */
+	enum object_type obj_type; /* object type derived from sha */
+	struct object_info oi = OBJECT_INFO_INIT;
+	char *path, *to_free = NULL;
+	struct object_id oid;
+
+	ptr = buf;
+	/*
+	 * Read non-recursive ls-tree output format:
+	 *     mode SP type SP sha1 TAB name
+	 */
+	mode = strtoul(ptr, &ntr, 8);
+	if (ptr == ntr || !ntr || *ntr != ' ')
+		die("input format error: %s", buf);
+	ptr = ntr + 1; /* type */
+	ntr = strchr(ptr, ' ');
+	if (!ntr || parse_oid_hex(ntr + 1, &oid, &p) ||
+	    *p != '\t')
+		die("input format error: %s", buf);
+
+	/* It is perfectly normal if we do not have a commit from a submodule */
+	if (S_ISGITLINK(mode))
+		allow_missing = 1;
+
+
+	*ntr++ = 0; /* now at the beginning of SHA1 */
+
+	path = (char *)p + 1;  /* at the beginning of name */
+	if (!nul_term_line && path[0] == '"') {
+		struct strbuf p_uq = STRBUF_INIT;
+		if (unquote_c_style(&p_uq, path, NULL))
+			die("invalid quoting");
+		path = to_free = strbuf_detach(&p_uq, NULL);
+	}
+
+	/*
+	 * Object type is redundantly derivable three ways.
+	 * These should all agree.
+	 */
+	mode_type = object_type(mode);
+	if (mode_type != type_from_string(ptr)) {
+		die("entry '%s' object type (%s) doesn't match mode type (%s)",
+			path, ptr, type_name(mode_type));
+	}
+
+	/* Check the type of object identified by oid without fetching objects */
+	oi.typep = &obj_type;
+	if (oid_object_info_extended(the_repository, &oid, &oi,
+				     OBJECT_INFO_LOOKUP_REPLACE |
+				     OBJECT_INFO_QUICK |
+				     OBJECT_INFO_SKIP_FETCH_OBJECT) < 0)
+		obj_type = -1;
+
+	if (obj_type < 0) {
+		if (allow_missing) {
+			; /* no problem - missing objects are presumed to be of the right type */
+		} else {
+			die("entry '%s' object %s is unavailable", path, oid_to_hex(&oid));
+		}
+	} else {
+		if (obj_type != mode_type) {
+			/*
+			 * The object exists but is of the wrong type.
+			 * This is a problem regardless of allow_missing
+			 * because the new tree entry will never be correct.
+			 */
+			die("entry '%s' object %s is a %s but specified type was (%s)",
+				path, oid_to_hex(&oid), type_name(obj_type), type_name(mode_type));
+		}
+	}
+
+	append_to_tree(mode, &oid, path);
+	free(to_free);
+}
+
+int cmd_mktree(int ac,
+	       const char **av,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct strbuf sb = STRBUF_INIT;
+	struct object_id oid;
+	int nul_term_line = 0;
+	int allow_missing = 0;
+	int is_batch_mode = 0;
+	int got_eof = 0;
+	strbuf_getline_fn getline_fn;
+
+	const struct option option[] = {
+		OPT_BOOL('z', NULL, &nul_term_line, N_("input is NUL terminated")),
+		OPT_SET_INT( 0 , "missing", &allow_missing, N_("allow missing objects"), 1),
+		OPT_SET_INT( 0 , "batch", &is_batch_mode, N_("allow creation of more than one tree"), 1),
+		OPT_END()
+	};
+
+	ac = parse_options(ac, av, prefix, option, mktree_usage, 0);
+	getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
+
+	while (!got_eof) {
+		while (1) {
+			if (getline_fn(&sb, stdin) == EOF) {
+				got_eof = 1;
+				break;
+			}
+			if (sb.buf[0] == '\0') {
+				/* empty lines denote tree boundaries in batch mode */
+				if (is_batch_mode)
+					break;
+				die("input format error: (blank line only valid in batch mode)");
+			}
+			mktree_line(sb.buf, nul_term_line, allow_missing);
+		}
+		if (is_batch_mode && got_eof && used < 1) {
+			/*
+			 * Execution gets here if the last tree entry is terminated with a
+			 * new-line.  The final new-line has been made optional to be
+			 * consistent with the original non-batch behaviour of mktree.
+			 */
+			; /* skip creating an empty tree */
+		} else {
+			write_tree(&oid);
+			puts(oid_to_hex(&oid));
+			fflush(stdout);
+		}
+		used=0; /* reset tree entry buffer for re-use in batch mode */
+	}
+	strbuf_release(&sb);
+
+	return 0;
+}
diff --git a/builtin/multi-pack-index.c b/builtin/multi-pack-index.c
new file mode 100644
index 0000000000..2a938466f5
--- /dev/null
+++ b/builtin/multi-pack-index.c
@@ -0,0 +1,308 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "midx.h"
+#include "strbuf.h"
+#include "trace2.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
+#include "repository.h"
+
+#define BUILTIN_MIDX_WRITE_USAGE \
+	N_("git multi-pack-index [<options>] write [--preferred-pack=<pack>]" \
+	   "[--refs-snapshot=<path>]")
+
+#define BUILTIN_MIDX_VERIFY_USAGE \
+	N_("git multi-pack-index [<options>] verify")
+
+#define BUILTIN_MIDX_EXPIRE_USAGE \
+	N_("git multi-pack-index [<options>] expire")
+
+#define BUILTIN_MIDX_REPACK_USAGE \
+	N_("git multi-pack-index [<options>] repack [--batch-size=<size>]")
+
+static char const * const builtin_multi_pack_index_write_usage[] = {
+	BUILTIN_MIDX_WRITE_USAGE,
+	NULL
+};
+static char const * const builtin_multi_pack_index_verify_usage[] = {
+	BUILTIN_MIDX_VERIFY_USAGE,
+	NULL
+};
+static char const * const builtin_multi_pack_index_expire_usage[] = {
+	BUILTIN_MIDX_EXPIRE_USAGE,
+	NULL
+};
+static char const * const builtin_multi_pack_index_repack_usage[] = {
+	BUILTIN_MIDX_REPACK_USAGE,
+	NULL
+};
+static char const * const builtin_multi_pack_index_usage[] = {
+	BUILTIN_MIDX_WRITE_USAGE,
+	BUILTIN_MIDX_VERIFY_USAGE,
+	BUILTIN_MIDX_EXPIRE_USAGE,
+	BUILTIN_MIDX_REPACK_USAGE,
+	NULL
+};
+
+static struct opts_multi_pack_index {
+	char *object_dir;
+	const char *preferred_pack;
+	char *refs_snapshot;
+	unsigned long batch_size;
+	unsigned flags;
+	int stdin_packs;
+} opts;
+
+
+static int parse_object_dir(const struct option *opt, const char *arg,
+			    int unset)
+{
+	char **value = opt->value;
+	free(*value);
+	if (unset)
+		*value = xstrdup(repo_get_object_directory(the_repository));
+	else
+		*value = real_pathdup(arg, 1);
+	return 0;
+}
+
+static struct option common_opts[] = {
+	OPT_CALLBACK(0, "object-dir", &opts.object_dir,
+	  N_("directory"),
+	  N_("object directory containing set of packfile and pack-index pairs"),
+	  parse_object_dir),
+	OPT_END(),
+};
+
+static struct option *add_common_options(struct option *prev)
+{
+	return parse_options_concat(common_opts, prev);
+}
+
+static int git_multi_pack_index_write_config(const char *var, const char *value,
+					     const struct config_context *ctx UNUSED,
+					     void *cb UNUSED)
+{
+	if (!strcmp(var, "pack.writebitmaphashcache")) {
+		if (git_config_bool(var, value))
+			opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
+		else
+			opts.flags &= ~MIDX_WRITE_BITMAP_HASH_CACHE;
+	}
+
+	if (!strcmp(var, "pack.writebitmaplookuptable")) {
+		if (git_config_bool(var, value))
+			opts.flags |= MIDX_WRITE_BITMAP_LOOKUP_TABLE;
+		else
+			opts.flags &= ~MIDX_WRITE_BITMAP_LOOKUP_TABLE;
+	}
+
+	/*
+	 * We should never make a fall-back call to 'git_default_config', since
+	 * this was already called in 'cmd_multi_pack_index()'.
+	 */
+	return 0;
+}
+
+static void read_packs_from_stdin(struct string_list *to)
+{
+	struct strbuf buf = STRBUF_INIT;
+	while (strbuf_getline(&buf, stdin) != EOF)
+		string_list_append(to, buf.buf);
+	string_list_sort(to);
+
+	strbuf_release(&buf);
+}
+
+static int cmd_multi_pack_index_write(int argc, const char **argv,
+				      const char *prefix,
+				      struct repository *repo)
+{
+	struct option *options;
+	static struct option builtin_multi_pack_index_write_options[] = {
+		OPT_STRING(0, "preferred-pack", &opts.preferred_pack,
+			   N_("preferred-pack"),
+			   N_("pack for reuse when computing a multi-pack bitmap")),
+		OPT_BIT(0, "bitmap", &opts.flags, N_("write multi-pack bitmap"),
+			MIDX_WRITE_BITMAP | MIDX_WRITE_REV_INDEX),
+		OPT_BIT(0, "progress", &opts.flags,
+			N_("force progress reporting"), MIDX_PROGRESS),
+		OPT_BIT(0, "incremental", &opts.flags,
+			N_("write a new incremental MIDX"), MIDX_WRITE_INCREMENTAL),
+		OPT_BOOL(0, "stdin-packs", &opts.stdin_packs,
+			 N_("write multi-pack index containing only given indexes")),
+		OPT_FILENAME(0, "refs-snapshot", &opts.refs_snapshot,
+			     N_("refs snapshot for selecting bitmap commits")),
+		OPT_END(),
+	};
+	int ret;
+
+	opts.flags |= MIDX_WRITE_BITMAP_HASH_CACHE;
+
+	git_config(git_multi_pack_index_write_config, NULL);
+
+	options = add_common_options(builtin_multi_pack_index_write_options);
+
+	trace2_cmd_mode(argv[0]);
+
+	if (isatty(2))
+		opts.flags |= MIDX_PROGRESS;
+	argc = parse_options(argc, argv, prefix,
+			     options, builtin_multi_pack_index_write_usage,
+			     0);
+	if (argc)
+		usage_with_options(builtin_multi_pack_index_write_usage,
+				   options);
+
+	FREE_AND_NULL(options);
+
+	if (opts.stdin_packs) {
+		struct string_list packs = STRING_LIST_INIT_DUP;
+
+		read_packs_from_stdin(&packs);
+
+		ret = write_midx_file_only(repo, opts.object_dir, &packs,
+					   opts.preferred_pack,
+					   opts.refs_snapshot, opts.flags);
+
+		string_list_clear(&packs, 0);
+		free(opts.refs_snapshot);
+
+		return ret;
+
+	}
+
+	ret = write_midx_file(repo, opts.object_dir, opts.preferred_pack,
+			      opts.refs_snapshot, opts.flags);
+
+	free(opts.refs_snapshot);
+	return ret;
+}
+
+static int cmd_multi_pack_index_verify(int argc, const char **argv,
+				       const char *prefix,
+				       struct repository *repo UNUSED)
+{
+	struct option *options;
+	static struct option builtin_multi_pack_index_verify_options[] = {
+		OPT_BIT(0, "progress", &opts.flags,
+			N_("force progress reporting"), MIDX_PROGRESS),
+		OPT_END(),
+	};
+	options = add_common_options(builtin_multi_pack_index_verify_options);
+
+	trace2_cmd_mode(argv[0]);
+
+	if (isatty(2))
+		opts.flags |= MIDX_PROGRESS;
+	argc = parse_options(argc, argv, prefix,
+			     options, builtin_multi_pack_index_verify_usage,
+			     0);
+	if (argc)
+		usage_with_options(builtin_multi_pack_index_verify_usage,
+				   options);
+
+	FREE_AND_NULL(options);
+
+	return verify_midx_file(the_repository, opts.object_dir, opts.flags);
+}
+
+static int cmd_multi_pack_index_expire(int argc, const char **argv,
+				       const char *prefix,
+				       struct repository *repo UNUSED)
+{
+	struct option *options;
+	static struct option builtin_multi_pack_index_expire_options[] = {
+		OPT_BIT(0, "progress", &opts.flags,
+			N_("force progress reporting"), MIDX_PROGRESS),
+		OPT_END(),
+	};
+	options = add_common_options(builtin_multi_pack_index_expire_options);
+
+	trace2_cmd_mode(argv[0]);
+
+	if (isatty(2))
+		opts.flags |= MIDX_PROGRESS;
+	argc = parse_options(argc, argv, prefix,
+			     options, builtin_multi_pack_index_expire_usage,
+			     0);
+	if (argc)
+		usage_with_options(builtin_multi_pack_index_expire_usage,
+				   options);
+
+	FREE_AND_NULL(options);
+
+	return expire_midx_packs(the_repository, opts.object_dir, opts.flags);
+}
+
+static int cmd_multi_pack_index_repack(int argc, const char **argv,
+				       const char *prefix,
+				       struct repository *repo UNUSED)
+{
+	struct option *options;
+	static struct option builtin_multi_pack_index_repack_options[] = {
+		OPT_MAGNITUDE(0, "batch-size", &opts.batch_size,
+		  N_("during repack, collect pack-files of smaller size into a batch that is larger than this size")),
+		OPT_BIT(0, "progress", &opts.flags,
+		  N_("force progress reporting"), MIDX_PROGRESS),
+		OPT_END(),
+	};
+
+	options = add_common_options(builtin_multi_pack_index_repack_options);
+
+	trace2_cmd_mode(argv[0]);
+
+	if (isatty(2))
+		opts.flags |= MIDX_PROGRESS;
+	argc = parse_options(argc, argv, prefix,
+			     options,
+			     builtin_multi_pack_index_repack_usage,
+			     0);
+	if (argc)
+		usage_with_options(builtin_multi_pack_index_repack_usage,
+				   options);
+
+	FREE_AND_NULL(options);
+
+	return midx_repack(the_repository, opts.object_dir,
+			   (size_t)opts.batch_size, opts.flags);
+}
+
+int cmd_multi_pack_index(int argc,
+			 const char **argv,
+			 const char *prefix,
+			 struct repository *repo)
+{
+	int res;
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option builtin_multi_pack_index_options[] = {
+		OPT_SUBCOMMAND("repack", &fn, cmd_multi_pack_index_repack),
+		OPT_SUBCOMMAND("write", &fn, cmd_multi_pack_index_write),
+		OPT_SUBCOMMAND("verify", &fn, cmd_multi_pack_index_verify),
+		OPT_SUBCOMMAND("expire", &fn, cmd_multi_pack_index_expire),
+		OPT_END(),
+	};
+	struct option *options = parse_options_concat(builtin_multi_pack_index_options, common_opts);
+
+	disable_replace_refs();
+
+	git_config(git_default_config, NULL);
+
+	if (the_repository &&
+	    the_repository->objects &&
+	    the_repository->objects->odb)
+		opts.object_dir = xstrdup(the_repository->objects->odb->path);
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_multi_pack_index_usage, 0);
+	FREE_AND_NULL(options);
+
+	res = fn(argc, argv, prefix, repo);
+
+	free(opts.object_dir);
+	return res;
+}
diff --git a/builtin/mv.c b/builtin/mv.c
new file mode 100644
index 0000000000..55a7d471dc
--- /dev/null
+++ b/builtin/mv.c
@@ -0,0 +1,593 @@
+/*
+ * "git mv" builtin command
+ *
+ * Copyright (C) 2006 Johannes Schindelin
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "name-hash.h"
+#include "object-file.h"
+#include "pathspec.h"
+#include "lockfile.h"
+#include "dir.h"
+#include "string-list.h"
+#include "parse-options.h"
+#include "read-cache-ll.h"
+
+#include "setup.h"
+#include "strvec.h"
+#include "submodule.h"
+#include "entry.h"
+
+static const char * const builtin_mv_usage[] = {
+	N_("git mv [<options>] <source>... <destination>"),
+	NULL
+};
+
+enum update_mode {
+	WORKING_DIRECTORY = (1 << 1),
+	INDEX = (1 << 2),
+	SPARSE = (1 << 3),
+	SKIP_WORKTREE_DIR = (1 << 4),
+};
+
+#define DUP_BASENAME 1
+#define KEEP_TRAILING_SLASH 2
+
+static void internal_prefix_pathspec(struct strvec *out,
+				     const char *prefix,
+				     const char **pathspec,
+				     int count, unsigned flags)
+{
+	int prefixlen = prefix ? strlen(prefix) : 0;
+
+	/* Create an intermediate copy of the pathspec based on the flags */
+	for (int i = 0; i < count; i++) {
+		size_t length = strlen(pathspec[i]);
+		size_t to_copy = length;
+		const char *maybe_basename;
+		char *trimmed, *prefixed_path;
+
+		while (!(flags & KEEP_TRAILING_SLASH) &&
+		       to_copy > 0 && is_dir_sep(pathspec[i][to_copy - 1]))
+			to_copy--;
+
+		trimmed = xmemdupz(pathspec[i], to_copy);
+		maybe_basename = (flags & DUP_BASENAME) ? basename(trimmed) : trimmed;
+		prefixed_path = prefix_path(prefix, prefixlen, maybe_basename);
+		strvec_push(out, prefixed_path);
+
+		free(prefixed_path);
+		free(trimmed);
+	}
+}
+
+static char *add_slash(const char *path)
+{
+	size_t len = strlen(path);
+	if (len && path[len - 1] != '/') {
+		char *with_slash = xmalloc(st_add(len, 2));
+		memcpy(with_slash, path, len);
+		with_slash[len++] = '/';
+		with_slash[len] = 0;
+		return with_slash;
+	}
+	return xstrdup(path);
+}
+
+#define SUBMODULE_WITH_GITDIR ((const char *)1)
+
+static const char *submodule_gitfile_path(const char *src, int first)
+{
+	struct strbuf submodule_dotgit = STRBUF_INIT;
+	const char *path;
+
+	if (!S_ISGITLINK(the_repository->index->cache[first]->ce_mode))
+		die(_("Directory %s is in index and no submodule?"), src);
+	if (!is_staging_gitmodules_ok(the_repository->index))
+		die(_("Please stage your changes to .gitmodules or stash them to proceed"));
+
+	strbuf_addf(&submodule_dotgit, "%s/.git", src);
+
+	path = read_gitfile(submodule_dotgit.buf);
+	strbuf_release(&submodule_dotgit);
+	if (path)
+		return path;
+	return SUBMODULE_WITH_GITDIR;
+}
+
+static int index_range_of_same_dir(const char *src, int length,
+				   int *first_p, int *last_p)
+{
+	char *src_w_slash = add_slash(src);
+	int first, last, len_w_slash = length + 1;
+
+	first = index_name_pos(the_repository->index, src_w_slash, len_w_slash);
+	if (first >= 0)
+		die(_("%.*s is in index"), len_w_slash, src_w_slash);
+
+	first = -1 - first;
+	for (last = first; last < the_repository->index->cache_nr; last++) {
+		const char *path = the_repository->index->cache[last]->name;
+		if (strncmp(path, src_w_slash, len_w_slash))
+			break;
+	}
+
+	free(src_w_slash);
+	*first_p = first;
+	*last_p = last;
+	return last - first;
+}
+
+/*
+ * Given the path of a directory that does not exist on-disk, check whether the
+ * directory contains any entries in the index with the SKIP_WORKTREE flag
+ * enabled.
+ * Return 1 if such index entries exist.
+ * Return 0 otherwise.
+ */
+static int empty_dir_has_sparse_contents(const char *name)
+{
+	int ret = 0;
+	char *with_slash = add_slash(name);
+	int length = strlen(with_slash);
+
+	int pos = index_name_pos(the_repository->index, with_slash, length);
+	const struct cache_entry *ce;
+
+	if (pos < 0) {
+		pos = -pos - 1;
+		if (pos >= the_repository->index->cache_nr)
+			goto free_return;
+		ce = the_repository->index->cache[pos];
+		if (strncmp(with_slash, ce->name, length))
+			goto free_return;
+		if (ce_skip_worktree(ce))
+			ret = 1;
+	}
+
+free_return:
+	free(with_slash);
+	return ret;
+}
+
+static void remove_empty_src_dirs(const char **src_dir, size_t src_dir_nr)
+{
+	size_t i;
+	struct strbuf a_src_dir = STRBUF_INIT;
+
+	for (i = 0; i < src_dir_nr; i++) {
+		int dummy;
+		strbuf_addstr(&a_src_dir, src_dir[i]);
+		/*
+		 * if entries under a_src_dir are all moved away,
+		 * recursively remove a_src_dir to cleanup
+		 */
+		if (index_range_of_same_dir(a_src_dir.buf, a_src_dir.len,
+					    &dummy, &dummy) < 1) {
+			remove_dir_recursively(&a_src_dir, 0);
+		}
+		strbuf_reset(&a_src_dir);
+	}
+
+	strbuf_release(&a_src_dir);
+}
+
+int cmd_mv(int argc,
+	   const char **argv,
+	   const char *prefix,
+	   struct repository *repo UNUSED)
+{
+	int i, flags, gitmodules_modified = 0;
+	int verbose = 0, show_only = 0, force = 0, ignore_errors = 0, ignore_sparse = 0;
+	struct option builtin_mv_options[] = {
+		OPT__VERBOSE(&verbose, N_("be verbose")),
+		OPT__DRY_RUN(&show_only, N_("dry run")),
+		OPT__FORCE(&force, N_("force move/rename even if target exists"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL('k', NULL, &ignore_errors, N_("skip move/rename errors")),
+		OPT_BOOL(0, "sparse", &ignore_sparse, N_("allow updating entries outside of the sparse-checkout cone")),
+		OPT_END(),
+	};
+	struct strvec sources = STRVEC_INIT;
+	struct strvec dest_paths = STRVEC_INIT;
+	struct strvec destinations = STRVEC_INIT;
+	struct strvec submodule_gitfiles_to_free = STRVEC_INIT;
+	const char **submodule_gitfiles;
+	char *dst_w_slash = NULL;
+	struct strvec src_dir = STRVEC_INIT;
+	enum update_mode *modes, dst_mode = 0;
+	struct stat st, dest_st;
+	struct string_list src_for_dst = STRING_LIST_INIT_DUP;
+	struct lock_file lock_file = LOCK_INIT;
+	struct cache_entry *ce;
+	struct string_list only_match_skip_worktree = STRING_LIST_INIT_DUP;
+	struct string_list dirty_paths = STRING_LIST_INIT_DUP;
+	int ret;
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, builtin_mv_options,
+			     builtin_mv_usage, 0);
+	if (--argc < 1)
+		usage_with_options(builtin_mv_usage, builtin_mv_options);
+
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+	if (repo_read_index(the_repository) < 0)
+		die(_("index file corrupt"));
+
+	internal_prefix_pathspec(&sources, prefix, argv, argc, 0);
+	CALLOC_ARRAY(modes, argc);
+
+	/*
+	 * Keep trailing slash, needed to let
+	 * "git mv file no-such-dir/" error out, except in the case
+	 * "git mv directory no-such-dir/".
+	 */
+	flags = KEEP_TRAILING_SLASH;
+	if (argc == 1 && is_directory(argv[0]) && !is_directory(argv[1]))
+		flags = 0;
+	internal_prefix_pathspec(&dest_paths, prefix, argv + argc, 1, flags);
+	dst_w_slash = add_slash(dest_paths.v[0]);
+	submodule_gitfiles = xcalloc(argc, sizeof(char *));
+
+	if (dest_paths.v[0][0] == '\0')
+		/* special case: "." was normalized to "" */
+		internal_prefix_pathspec(&destinations, dest_paths.v[0], argv, argc, DUP_BASENAME);
+	else if (!lstat(dest_paths.v[0], &st) && S_ISDIR(st.st_mode)) {
+		internal_prefix_pathspec(&destinations, dst_w_slash, argv, argc, DUP_BASENAME);
+	} else if (!path_in_sparse_checkout(dst_w_slash, the_repository->index) &&
+		   empty_dir_has_sparse_contents(dst_w_slash)) {
+		internal_prefix_pathspec(&destinations, dst_w_slash, argv, argc, DUP_BASENAME);
+		dst_mode = SKIP_WORKTREE_DIR;
+	} else if (argc != 1) {
+		die(_("destination '%s' is not a directory"), dest_paths.v[0]);
+	} else {
+		strvec_pushv(&destinations, dest_paths.v);
+
+		/*
+		 * <destination> is a file outside of sparse-checkout
+		 * cone. Insist on cone mode here for backward
+		 * compatibility. We don't want dst_mode to be assigned
+		 * for a file when the repo is using no-cone mode (which
+		 * is deprecated at this point) sparse-checkout. As
+		 * SPARSE here is only considering cone-mode situation.
+		 */
+		if (!path_in_cone_mode_sparse_checkout(destinations.v[0], the_repository->index))
+			dst_mode = SPARSE;
+	}
+
+	/* Checking */
+	for (i = 0; i < argc; i++) {
+		const char *src = sources.v[i], *dst = destinations.v[i];
+		int length;
+		const char *bad = NULL;
+		int skip_sparse = 0;
+
+		if (show_only)
+			printf(_("Checking rename of '%s' to '%s'\n"), src, dst);
+
+		length = strlen(src);
+		if (lstat(src, &st) < 0) {
+			int pos;
+			const struct cache_entry *ce;
+
+			pos = index_name_pos(the_repository->index, src, length);
+			if (pos < 0) {
+				char *src_w_slash = add_slash(src);
+				if (!path_in_sparse_checkout(src_w_slash, the_repository->index) &&
+				    empty_dir_has_sparse_contents(src)) {
+					free(src_w_slash);
+					modes[i] |= SKIP_WORKTREE_DIR;
+					goto dir_check;
+				}
+				free(src_w_slash);
+				/* only error if existence is expected. */
+				if (!(modes[i] & SPARSE))
+					bad = _("bad source");
+				goto act_on_entry;
+			}
+			ce = the_repository->index->cache[pos];
+			if (!ce_skip_worktree(ce)) {
+				bad = _("bad source");
+				goto act_on_entry;
+			}
+			if (!ignore_sparse) {
+				string_list_append(&only_match_skip_worktree, src);
+				goto act_on_entry;
+			}
+			/* Check if dst exists in index */
+			if (index_name_pos(the_repository->index, dst, strlen(dst)) < 0) {
+				modes[i] |= SPARSE;
+				goto act_on_entry;
+			}
+			if (!force) {
+				bad = _("destination exists");
+				goto act_on_entry;
+			}
+			modes[i] |= SPARSE;
+			goto act_on_entry;
+		}
+		if (!strncmp(src, dst, length) &&
+		    (dst[length] == 0 || dst[length] == '/')) {
+			bad = _("can not move directory into itself");
+			goto act_on_entry;
+		}
+		if (S_ISDIR(st.st_mode)
+		    && lstat(dst, &dest_st) == 0) {
+			bad = _("destination already exists");
+			goto act_on_entry;
+		}
+
+dir_check:
+		if (S_ISDIR(st.st_mode)) {
+			char *dst_with_slash;
+			size_t dst_with_slash_len;
+			int j, n;
+			int first = index_name_pos(the_repository->index, src, length), last;
+
+			if (first >= 0) {
+				const char *path = submodule_gitfile_path(src, first);
+				if (path != SUBMODULE_WITH_GITDIR)
+					path = strvec_push(&submodule_gitfiles_to_free, path);
+				submodule_gitfiles[i] = path;
+				goto act_on_entry;
+			} else if (index_range_of_same_dir(src, length,
+							   &first, &last) < 1) {
+				bad = _("source directory is empty");
+				goto act_on_entry;
+			}
+
+			/* last - first >= 1 */
+			modes[i] |= WORKING_DIRECTORY;
+
+			strvec_push(&src_dir, src);
+
+			n = argc + last - first;
+			REALLOC_ARRAY(modes, n);
+			REALLOC_ARRAY(submodule_gitfiles, n);
+
+			dst_with_slash = add_slash(dst);
+			dst_with_slash_len = strlen(dst_with_slash);
+
+			for (j = 0; j < last - first; j++) {
+				const struct cache_entry *ce = the_repository->index->cache[first + j];
+				const char *path = ce->name;
+				char *prefixed_path = prefix_path(dst_with_slash, dst_with_slash_len, path + length + 1);
+
+				strvec_push(&sources, path);
+				strvec_push(&destinations, prefixed_path);
+
+				memset(modes + argc + j, 0, sizeof(enum update_mode));
+				modes[argc + j] |= ce_skip_worktree(ce) ? SPARSE : INDEX;
+				submodule_gitfiles[argc + j] = NULL;
+
+				free(prefixed_path);
+			}
+
+			free(dst_with_slash);
+			argc += last - first;
+			goto act_on_entry;
+		}
+		if (!(ce = index_file_exists(the_repository->index, src, length, 0))) {
+			bad = _("not under version control");
+			goto act_on_entry;
+		}
+		if (ce_stage(ce)) {
+			bad = _("conflicted");
+			goto act_on_entry;
+		}
+		if (lstat(dst, &st) == 0 &&
+		    (!ignore_case || strcasecmp(src, dst))) {
+			bad = _("destination exists");
+			if (force) {
+				/*
+				 * only files can overwrite each other:
+				 * check both source and destination
+				 */
+				if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+					if (verbose)
+						warning(_("overwriting '%s'"), dst);
+					bad = NULL;
+				} else
+					bad = _("Cannot overwrite");
+			}
+			goto act_on_entry;
+		}
+		if (string_list_has_string(&src_for_dst, dst)) {
+			bad = _("multiple sources for the same target");
+			goto act_on_entry;
+		}
+		if (is_dir_sep(dst[strlen(dst) - 1])) {
+			bad = _("destination directory does not exist");
+			goto act_on_entry;
+		}
+
+		if (ignore_sparse &&
+		    (dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
+		    index_entry_exists(the_repository->index, dst, strlen(dst))) {
+			bad = _("destination exists in the index");
+			if (force) {
+				if (verbose)
+					warning(_("overwriting '%s'"), dst);
+				bad = NULL;
+			} else {
+				goto act_on_entry;
+			}
+		}
+		/*
+		 * We check if the paths are in the sparse-checkout
+		 * definition as a very final check, since that
+		 * allows us to point the user to the --sparse
+		 * option as a way to have a successful run.
+		 */
+		if (!ignore_sparse &&
+		    !path_in_sparse_checkout(src, the_repository->index)) {
+			string_list_append(&only_match_skip_worktree, src);
+			skip_sparse = 1;
+		}
+		if (!ignore_sparse &&
+		    !path_in_sparse_checkout(dst, the_repository->index)) {
+			string_list_append(&only_match_skip_worktree, dst);
+			skip_sparse = 1;
+		}
+
+		if (skip_sparse)
+			goto remove_entry;
+
+		string_list_insert(&src_for_dst, dst);
+
+act_on_entry:
+		if (!bad)
+			continue;
+		if (!ignore_errors)
+			die(_("%s, source=%s, destination=%s"),
+			     bad, src, dst);
+remove_entry:
+		if (--argc > 0) {
+			int n = argc - i;
+			strvec_remove(&sources, i);
+			strvec_remove(&destinations, i);
+			MOVE_ARRAY(modes + i, modes + i + 1, n);
+			MOVE_ARRAY(submodule_gitfiles + i,
+				   submodule_gitfiles + i + 1, n);
+			i--;
+		}
+	}
+
+	if (only_match_skip_worktree.nr) {
+		advise_on_updating_sparse_paths(&only_match_skip_worktree);
+		if (!ignore_errors) {
+			ret = 1;
+			goto out;
+		}
+	}
+
+	for (i = 0; i < argc; i++) {
+		const char *src = sources.v[i], *dst = destinations.v[i];
+		enum update_mode mode = modes[i];
+		int pos;
+		int sparse_and_dirty = 0;
+		struct checkout state = CHECKOUT_INIT;
+		state.istate = the_repository->index;
+
+		if (force)
+			state.force = 1;
+		if (show_only || verbose)
+			printf(_("Renaming %s to %s\n"), src, dst);
+		if (show_only)
+			continue;
+		if (!(mode & (INDEX | SPARSE | SKIP_WORKTREE_DIR)) &&
+		    !(dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
+		    rename(src, dst) < 0) {
+			if (ignore_errors)
+				continue;
+			die_errno(_("renaming '%s' failed"), src);
+		}
+		if (submodule_gitfiles[i]) {
+			if (!update_path_in_gitmodules(src, dst))
+				gitmodules_modified = 1;
+			if (submodule_gitfiles[i] != SUBMODULE_WITH_GITDIR)
+				connect_work_tree_and_git_dir(dst,
+							      submodule_gitfiles[i],
+							      1);
+		}
+
+		if (mode & (WORKING_DIRECTORY | SKIP_WORKTREE_DIR))
+			continue;
+
+		pos = index_name_pos(the_repository->index, src, strlen(src));
+		assert(pos >= 0);
+		if (!(mode & SPARSE) && !lstat(src, &st))
+			sparse_and_dirty = ie_modified(the_repository->index,
+						       the_repository->index->cache[pos],
+						       &st,
+						       0);
+		rename_index_entry_at(the_repository->index, pos, dst);
+
+		if (ignore_sparse &&
+		    core_apply_sparse_checkout &&
+		    core_sparse_checkout_cone) {
+			/*
+			 * NEEDSWORK: we are *not* paying attention to
+			 * "out-to-out" move (<source> is out-of-cone and
+			 * <destination> is out-of-cone) at this point. It
+			 * should be added in a future patch.
+			 */
+			if ((mode & SPARSE) &&
+			    path_in_sparse_checkout(dst, the_repository->index)) {
+				/* from out-of-cone to in-cone */
+				int dst_pos = index_name_pos(the_repository->index, dst,
+							     strlen(dst));
+				struct cache_entry *dst_ce = the_repository->index->cache[dst_pos];
+
+				dst_ce->ce_flags &= ~CE_SKIP_WORKTREE;
+
+				if (checkout_entry(dst_ce, &state, NULL, NULL))
+					die(_("cannot checkout %s"), dst_ce->name);
+			} else if ((dst_mode & (SKIP_WORKTREE_DIR | SPARSE)) &&
+				   !(mode & SPARSE) &&
+				   !path_in_sparse_checkout(dst, the_repository->index)) {
+				/* from in-cone to out-of-cone */
+				int dst_pos = index_name_pos(the_repository->index, dst,
+							     strlen(dst));
+				struct cache_entry *dst_ce = the_repository->index->cache[dst_pos];
+
+				/*
+				 * if src is clean, it will suffice to remove it
+				 */
+				if (!sparse_and_dirty) {
+					dst_ce->ce_flags |= CE_SKIP_WORKTREE;
+					unlink_or_warn(src);
+				} else {
+					/*
+					 * if src is dirty, move it to the
+					 * destination and create leading
+					 * dirs if necessary
+					 */
+					char *dst_dup = xstrdup(dst);
+					string_list_append(&dirty_paths, dst);
+					safe_create_leading_directories(dst_dup);
+					FREE_AND_NULL(dst_dup);
+					rename(src, dst);
+				}
+			}
+		}
+	}
+
+	remove_empty_src_dirs(src_dir.v, src_dir.nr);
+
+	if (dirty_paths.nr)
+		advise_on_moving_dirty_path(&dirty_paths);
+
+	if (gitmodules_modified)
+		stage_updated_gitmodules(the_repository->index);
+
+	if (write_locked_index(the_repository->index, &lock_file,
+			       COMMIT_LOCK | SKIP_IF_UNCHANGED))
+		die(_("Unable to write new index file"));
+
+	ret = 0;
+
+out:
+	strvec_clear(&src_dir);
+	free(dst_w_slash);
+	string_list_clear(&src_for_dst, 0);
+	string_list_clear(&dirty_paths, 0);
+	string_list_clear(&only_match_skip_worktree, 0);
+	strvec_clear(&sources);
+	strvec_clear(&dest_paths);
+	strvec_clear(&destinations);
+	strvec_clear(&submodule_gitfiles_to_free);
+	free(submodule_gitfiles);
+	free(modes);
+	return ret;
+}
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
new file mode 100644
index 0000000000..beac166b5c
--- /dev/null
+++ b/builtin/name-rev.c
@@ -0,0 +1,690 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "config.h"
+#include "commit.h"
+#include "tag.h"
+#include "refs.h"
+#include "object-name.h"
+#include "pager.h"
+#include "parse-options.h"
+#include "prio-queue.h"
+#include "hash-lookup.h"
+#include "commit-slab.h"
+#include "commit-graph.h"
+#include "wildmatch.h"
+#include "mem-pool.h"
+
+/*
+ * One day.  See the 'name a rev shortly after epoch' test in t6120 when
+ * changing this value
+ */
+#define CUTOFF_DATE_SLOP 86400
+
+struct rev_name {
+	const char *tip_name;
+	timestamp_t taggerdate;
+	int generation;
+	int distance;
+	int from_tag;
+};
+
+define_commit_slab(commit_rev_name, struct rev_name);
+
+static timestamp_t generation_cutoff = GENERATION_NUMBER_INFINITY;
+static timestamp_t cutoff = TIME_MAX;
+static struct commit_rev_name rev_names;
+
+/* Disable the cutoff checks entirely */
+static void disable_cutoff(void)
+{
+	generation_cutoff = 0;
+	cutoff = 0;
+}
+
+/* Cutoff searching any commits older than this one */
+static void set_commit_cutoff(struct commit *commit)
+{
+
+	if (cutoff > commit->date)
+		cutoff = commit->date;
+
+	if (generation_cutoff) {
+		timestamp_t generation = commit_graph_generation(commit);
+
+		if (generation_cutoff > generation)
+			generation_cutoff = generation;
+	}
+}
+
+/* adjust the commit date cutoff with a slop to allow for slightly incorrect
+ * commit timestamps in case of clock skew.
+ */
+static void adjust_cutoff_timestamp_for_slop(void)
+{
+	if (cutoff) {
+		/* check for underflow */
+		if (cutoff > TIME_MIN + CUTOFF_DATE_SLOP)
+			cutoff = cutoff - CUTOFF_DATE_SLOP;
+		else
+			cutoff = TIME_MIN;
+	}
+}
+
+/* Check if a commit is before the cutoff. Prioritize generation numbers
+ * first, but use the commit timestamp if we lack generation data.
+ */
+static int commit_is_before_cutoff(struct commit *commit)
+{
+	if (generation_cutoff < GENERATION_NUMBER_INFINITY)
+		return generation_cutoff &&
+			commit_graph_generation(commit) < generation_cutoff;
+
+	return commit->date < cutoff;
+}
+
+/* How many generations are maximally preferred over _one_ merge traversal? */
+#define MERGE_TRAVERSAL_WEIGHT 65535
+
+static int is_valid_rev_name(const struct rev_name *name)
+{
+	return name && name->tip_name;
+}
+
+static struct rev_name *get_commit_rev_name(const struct commit *commit)
+{
+	struct rev_name *name = commit_rev_name_peek(&rev_names, commit);
+
+	return is_valid_rev_name(name) ? name : NULL;
+}
+
+static int effective_distance(int distance, int generation)
+{
+	return distance + (generation > 0 ? MERGE_TRAVERSAL_WEIGHT : 0);
+}
+
+static int is_better_name(struct rev_name *name,
+			  timestamp_t taggerdate,
+			  int generation,
+			  int distance,
+			  int from_tag)
+{
+	int name_distance = effective_distance(name->distance, name->generation);
+	int new_distance = effective_distance(distance, generation);
+
+	/* If both are tags, we prefer the nearer one. */
+	if (from_tag && name->from_tag)
+		return name_distance > new_distance;
+
+	/* Favor a tag over a non-tag. */
+	if (name->from_tag != from_tag)
+		return from_tag;
+
+	/*
+	 * We are now looking at two non-tags.  Tiebreak to favor
+	 * shorter hops.
+	 */
+	if (name_distance != new_distance)
+		return name_distance > new_distance;
+
+	/* ... or tiebreak to favor older date */
+	if (name->taggerdate != taggerdate)
+		return name->taggerdate > taggerdate;
+
+	/* keep the current one if we cannot decide */
+	return 0;
+}
+
+static struct rev_name *create_or_update_name(struct commit *commit,
+					      timestamp_t taggerdate,
+					      int generation, int distance,
+					      int from_tag)
+{
+	struct rev_name *name = commit_rev_name_at(&rev_names, commit);
+
+	if (is_valid_rev_name(name) &&
+	    !is_better_name(name, taggerdate, generation, distance, from_tag))
+		return NULL;
+
+	name->taggerdate = taggerdate;
+	name->generation = generation;
+	name->distance = distance;
+	name->from_tag = from_tag;
+
+	return name;
+}
+
+static char *get_parent_name(const struct rev_name *name, int parent_number,
+			     struct mem_pool *string_pool)
+{
+	size_t len;
+
+	strip_suffix(name->tip_name, "^0", &len);
+	if (name->generation > 0) {
+		return mem_pool_strfmt(string_pool, "%.*s~%d^%d",
+				       (int)len, name->tip_name,
+				       name->generation, parent_number);
+	} else {
+		return mem_pool_strfmt(string_pool, "%.*s^%d",
+				       (int)len, name->tip_name, parent_number);
+	}
+}
+
+static void name_rev(struct commit *start_commit,
+		const char *tip_name, timestamp_t taggerdate,
+		int from_tag, int deref, struct mem_pool *string_pool)
+{
+	struct prio_queue queue;
+	struct commit *commit;
+	struct commit **parents_to_queue = NULL;
+	size_t parents_to_queue_nr, parents_to_queue_alloc = 0;
+	struct rev_name *start_name;
+
+	repo_parse_commit(the_repository, start_commit);
+	if (commit_is_before_cutoff(start_commit))
+		return;
+
+	start_name = create_or_update_name(start_commit, taggerdate, 0, 0,
+					   from_tag);
+	if (!start_name)
+		return;
+	if (deref)
+		start_name->tip_name = mem_pool_strfmt(string_pool, "%s^0",
+						       tip_name);
+	else
+		start_name->tip_name = mem_pool_strdup(string_pool, tip_name);
+
+	memset(&queue, 0, sizeof(queue)); /* Use the prio_queue as LIFO */
+	prio_queue_put(&queue, start_commit);
+
+	while ((commit = prio_queue_get(&queue))) {
+		struct rev_name *name = get_commit_rev_name(commit);
+		struct commit_list *parents;
+		int parent_number = 1;
+
+		parents_to_queue_nr = 0;
+
+		for (parents = commit->parents;
+				parents;
+				parents = parents->next, parent_number++) {
+			struct commit *parent = parents->item;
+			struct rev_name *parent_name;
+			int generation, distance;
+
+			repo_parse_commit(the_repository, parent);
+			if (commit_is_before_cutoff(parent))
+				continue;
+
+			if (parent_number > 1) {
+				generation = 0;
+				distance = name->distance + MERGE_TRAVERSAL_WEIGHT;
+			} else {
+				generation = name->generation + 1;
+				distance = name->distance + 1;
+			}
+
+			parent_name = create_or_update_name(parent, taggerdate,
+							    generation,
+							    distance, from_tag);
+			if (parent_name) {
+				if (parent_number > 1)
+					parent_name->tip_name =
+						get_parent_name(name,
+								parent_number,
+								string_pool);
+				else
+					parent_name->tip_name = name->tip_name;
+				ALLOC_GROW(parents_to_queue,
+					   parents_to_queue_nr + 1,
+					   parents_to_queue_alloc);
+				parents_to_queue[parents_to_queue_nr] = parent;
+				parents_to_queue_nr++;
+			}
+		}
+
+		/* The first parent must come out first from the prio_queue */
+		while (parents_to_queue_nr)
+			prio_queue_put(&queue,
+				       parents_to_queue[--parents_to_queue_nr]);
+	}
+
+	clear_prio_queue(&queue);
+	free(parents_to_queue);
+}
+
+static int subpath_matches(const char *path, const char *filter)
+{
+	const char *subpath = path;
+
+	while (subpath) {
+		if (!wildmatch(filter, subpath, 0))
+			return subpath - path;
+		subpath = strchr(subpath, '/');
+		if (subpath)
+			subpath++;
+	}
+	return -1;
+}
+
+struct name_ref_data {
+	int tags_only;
+	int name_only;
+	struct string_list ref_filters;
+	struct string_list exclude_filters;
+};
+
+static struct tip_table {
+	struct tip_table_entry {
+		struct object_id oid;
+		const char *refname;
+		struct commit *commit;
+		timestamp_t taggerdate;
+		unsigned int from_tag:1;
+		unsigned int deref:1;
+	} *table;
+	int nr;
+	int alloc;
+	int sorted;
+} tip_table;
+
+static void add_to_tip_table(const struct object_id *oid, const char *refname,
+			     int shorten_unambiguous, struct commit *commit,
+			     timestamp_t taggerdate, int from_tag, int deref)
+{
+	char *short_refname = NULL;
+
+	if (shorten_unambiguous)
+		short_refname = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+							     refname, 0);
+	else if (skip_prefix(refname, "refs/heads/", &refname))
+		; /* refname already advanced */
+	else
+		skip_prefix(refname, "refs/", &refname);
+
+	ALLOC_GROW(tip_table.table, tip_table.nr + 1, tip_table.alloc);
+	oidcpy(&tip_table.table[tip_table.nr].oid, oid);
+	tip_table.table[tip_table.nr].refname = short_refname ?
+		short_refname : xstrdup(refname);
+	tip_table.table[tip_table.nr].commit = commit;
+	tip_table.table[tip_table.nr].taggerdate = taggerdate;
+	tip_table.table[tip_table.nr].from_tag = from_tag;
+	tip_table.table[tip_table.nr].deref = deref;
+	tip_table.nr++;
+	tip_table.sorted = 0;
+}
+
+static int tipcmp(const void *a_, const void *b_)
+{
+	const struct tip_table_entry *a = a_, *b = b_;
+	return oidcmp(&a->oid, &b->oid);
+}
+
+static int cmp_by_tag_and_age(const void *a_, const void *b_)
+{
+	const struct tip_table_entry *a = a_, *b = b_;
+	int cmp;
+
+	/* Prefer tags. */
+	cmp = b->from_tag - a->from_tag;
+	if (cmp)
+		return cmp;
+
+	/* Older is better. */
+	if (a->taggerdate < b->taggerdate)
+		return -1;
+	return a->taggerdate != b->taggerdate;
+}
+
+static int name_ref(const char *path, const char *referent UNUSED, const struct object_id *oid,
+		    int flags UNUSED, void *cb_data)
+{
+	struct object *o = parse_object(the_repository, oid);
+	struct name_ref_data *data = cb_data;
+	int can_abbreviate_output = data->tags_only && data->name_only;
+	int deref = 0;
+	int from_tag = 0;
+	struct commit *commit = NULL;
+	timestamp_t taggerdate = TIME_MAX;
+
+	if (data->tags_only && !starts_with(path, "refs/tags/"))
+		return 0;
+
+	if (data->exclude_filters.nr) {
+		struct string_list_item *item;
+
+		for_each_string_list_item(item, &data->exclude_filters) {
+			if (subpath_matches(path, item->string) >= 0)
+				return 0;
+		}
+	}
+
+	if (data->ref_filters.nr) {
+		struct string_list_item *item;
+		int matched = 0;
+
+		/* See if any of the patterns match. */
+		for_each_string_list_item(item, &data->ref_filters) {
+			/*
+			 * Check all patterns even after finding a match, so
+			 * that we can see if a match with a subpath exists.
+			 * When a user asked for 'refs/tags/v*' and 'v1.*',
+			 * both of which match, the user is showing her
+			 * willingness to accept a shortened output by having
+			 * the 'v1.*' in the acceptable refnames, so we
+			 * shouldn't stop when seeing 'refs/tags/v1.4' matches
+			 * 'refs/tags/v*'.  We should show it as 'v1.4'.
+			 */
+			switch (subpath_matches(path, item->string)) {
+			case -1: /* did not match */
+				break;
+			case 0: /* matched fully */
+				matched = 1;
+				break;
+			default: /* matched subpath */
+				matched = 1;
+				can_abbreviate_output = 1;
+				break;
+			}
+		}
+
+		/* If none of the patterns matched, stop now */
+		if (!matched)
+			return 0;
+	}
+
+	while (o && o->type == OBJ_TAG) {
+		struct tag *t = (struct tag *) o;
+		if (!t->tagged)
+			break; /* broken repository */
+		o = parse_object(the_repository, &t->tagged->oid);
+		deref = 1;
+		taggerdate = t->date;
+	}
+	if (o && o->type == OBJ_COMMIT) {
+		commit = (struct commit *)o;
+		from_tag = starts_with(path, "refs/tags/");
+		if (taggerdate == TIME_MAX)
+			taggerdate = commit->date;
+	}
+
+	add_to_tip_table(oid, path, can_abbreviate_output, commit, taggerdate,
+			 from_tag, deref);
+	return 0;
+}
+
+static void name_tips(struct mem_pool *string_pool)
+{
+	int i;
+
+	/*
+	 * Try to set better names first, so that worse ones spread
+	 * less.
+	 */
+	QSORT(tip_table.table, tip_table.nr, cmp_by_tag_and_age);
+	for (i = 0; i < tip_table.nr; i++) {
+		struct tip_table_entry *e = &tip_table.table[i];
+		if (e->commit) {
+			name_rev(e->commit, e->refname, e->taggerdate,
+				 e->from_tag, e->deref, string_pool);
+		}
+	}
+}
+
+static const struct object_id *nth_tip_table_ent(size_t ix, const void *table_)
+{
+	const struct tip_table_entry *table = table_;
+	return &table[ix].oid;
+}
+
+static const char *get_exact_ref_match(const struct object *o)
+{
+	int found;
+
+	if (!tip_table.table || !tip_table.nr)
+		return NULL;
+
+	if (!tip_table.sorted) {
+		QSORT(tip_table.table, tip_table.nr, tipcmp);
+		tip_table.sorted = 1;
+	}
+
+	found = oid_pos(&o->oid, tip_table.table, tip_table.nr,
+			nth_tip_table_ent);
+	if (0 <= found)
+		return tip_table.table[found].refname;
+	return NULL;
+}
+
+/* may return a constant string or use "buf" as scratch space */
+static const char *get_rev_name(const struct object *o, struct strbuf *buf)
+{
+	struct rev_name *n;
+	const struct commit *c;
+
+	if (o->type != OBJ_COMMIT)
+		return get_exact_ref_match(o);
+	c = (const struct commit *) o;
+	n = get_commit_rev_name(c);
+	if (!n)
+		return NULL;
+
+	if (!n->generation)
+		return n->tip_name;
+	else {
+		strbuf_reset(buf);
+		strbuf_addstr(buf, n->tip_name);
+		strbuf_strip_suffix(buf, "^0");
+		strbuf_addf(buf, "~%d", n->generation);
+		return buf->buf;
+	}
+}
+
+static void show_name(const struct object *obj,
+		      const char *caller_name,
+		      int always, int allow_undefined, int name_only)
+{
+	const char *name;
+	const struct object_id *oid = &obj->oid;
+	struct strbuf buf = STRBUF_INIT;
+
+	if (!name_only)
+		printf("%s ", caller_name ? caller_name : oid_to_hex(oid));
+	name = get_rev_name(obj, &buf);
+	if (name)
+		printf("%s\n", name);
+	else if (allow_undefined)
+		printf("undefined\n");
+	else if (always)
+		printf("%s\n",
+		       repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
+	else
+		die("cannot describe '%s'", oid_to_hex(oid));
+	strbuf_release(&buf);
+}
+
+static char const * const name_rev_usage[] = {
+	N_("git name-rev [<options>] <commit>..."),
+	N_("git name-rev [<options>] --all"),
+	N_("git name-rev [<options>] --annotate-stdin"),
+	NULL
+};
+
+static void name_rev_line(char *p, struct name_ref_data *data)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int counter = 0;
+	char *p_start;
+	const unsigned hexsz = the_hash_algo->hexsz;
+
+	for (p_start = p; *p; p++) {
+#define ishex(x) (isdigit((x)) || ((x) >= 'a' && (x) <= 'f'))
+		if (!ishex(*p))
+			counter = 0;
+		else if (++counter == hexsz &&
+			 !ishex(*(p+1))) {
+			struct object_id oid;
+			const char *name = NULL;
+			char c = *(p+1);
+			int p_len = p - p_start + 1;
+
+			counter = 0;
+
+			*(p+1) = 0;
+			if (!repo_get_oid(the_repository, p - (hexsz - 1), &oid)) {
+				struct object *o =
+					lookup_object(the_repository, &oid);
+				if (o)
+					name = get_rev_name(o, &buf);
+			}
+			*(p+1) = c;
+
+			if (!name)
+				continue;
+
+			if (data->name_only)
+				printf("%.*s%s", p_len - hexsz, p_start, name);
+			else
+				printf("%.*s (%s)", p_len, p_start, name);
+			p_start = p + 1;
+		}
+	}
+
+	/* flush */
+	if (p_start != p)
+		fwrite(p_start, p - p_start, 1, stdout);
+
+	strbuf_release(&buf);
+}
+
+int cmd_name_rev(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct mem_pool string_pool;
+	struct object_array revs = OBJECT_ARRAY_INIT;
+	int all = 0, annotate_stdin = 0, transform_stdin = 0, allow_undefined = 1, always = 0, peel_tag = 0;
+	struct name_ref_data data = { 0, 0, STRING_LIST_INIT_NODUP, STRING_LIST_INIT_NODUP };
+	struct option opts[] = {
+		OPT_BOOL(0, "name-only", &data.name_only, N_("print only ref-based names (no object names)")),
+		OPT_BOOL(0, "tags", &data.tags_only, N_("only use tags to name the commits")),
+		OPT_STRING_LIST(0, "refs", &data.ref_filters, N_("pattern"),
+				   N_("only use refs matching <pattern>")),
+		OPT_STRING_LIST(0, "exclude", &data.exclude_filters, N_("pattern"),
+				   N_("ignore refs matching <pattern>")),
+		OPT_GROUP(""),
+		OPT_BOOL(0, "all", &all, N_("list all commits reachable from all refs")),
+		OPT_BOOL_F(0,
+			   "stdin",
+			   &transform_stdin,
+			   N_("deprecated: use --annotate-stdin instead"),
+			   PARSE_OPT_HIDDEN),
+		OPT_BOOL(0, "annotate-stdin", &annotate_stdin, N_("annotate text from stdin")),
+		OPT_BOOL(0, "undefined", &allow_undefined, N_("allow to print `undefined` names (default)")),
+		OPT_BOOL(0, "always",     &always,
+			   N_("show abbreviated commit object as fallback")),
+		OPT_HIDDEN_BOOL(0, "peel-tag", &peel_tag,
+			   N_("dereference tags in the input (internal use)")),
+		OPT_END(),
+	};
+
+	mem_pool_init(&string_pool, 0);
+	init_commit_rev_name(&rev_names);
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, opts, name_rev_usage, 0);
+
+	if (transform_stdin) {
+		warning("--stdin is deprecated. Please use --annotate-stdin instead, "
+					"which is functionally equivalent.\n"
+					"This option will be removed in a future release.");
+		annotate_stdin = 1;
+	}
+
+	if (all + annotate_stdin + !!argc > 1) {
+		error("Specify either a list, or --all, not both!");
+		usage_with_options(name_rev_usage, opts);
+	}
+	if (all || annotate_stdin)
+		disable_cutoff();
+
+	for (; argc; argc--, argv++) {
+		struct object_id oid;
+		struct object *object;
+		struct commit *commit;
+
+		if (repo_get_oid(the_repository, *argv, &oid)) {
+			fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
+					*argv);
+			continue;
+		}
+
+		commit = NULL;
+		object = parse_object(the_repository, &oid);
+		if (object) {
+			struct object *peeled = deref_tag(the_repository,
+							  object, *argv, 0);
+			if (peeled && peeled->type == OBJ_COMMIT)
+				commit = (struct commit *)peeled;
+		}
+
+		if (!object) {
+			fprintf(stderr, "Could not get object for %s. Skipping.\n",
+					*argv);
+			continue;
+		}
+
+		if (commit)
+			set_commit_cutoff(commit);
+
+		if (peel_tag) {
+			if (!commit) {
+				fprintf(stderr, "Could not get commit for %s. Skipping.\n",
+					*argv);
+				continue;
+			}
+			object = (struct object *)commit;
+		}
+		add_object_array(object, *argv, &revs);
+	}
+
+	adjust_cutoff_timestamp_for_slop();
+
+	refs_for_each_ref(get_main_ref_store(the_repository), name_ref, &data);
+	name_tips(&string_pool);
+
+	if (annotate_stdin) {
+		struct strbuf sb = STRBUF_INIT;
+
+		while (strbuf_getline(&sb, stdin) != EOF) {
+			strbuf_addch(&sb, '\n');
+			name_rev_line(sb.buf, &data);
+		}
+		strbuf_release(&sb);
+	} else if (all) {
+		int i, max;
+
+		max = get_max_object_index();
+		for (i = 0; i < max; i++) {
+			struct object *obj = get_indexed_object(i);
+			if (!obj || obj->type != OBJ_COMMIT)
+				continue;
+			show_name(obj, NULL,
+				  always, allow_undefined, data.name_only);
+		}
+	} else {
+		int i;
+		for (i = 0; i < revs.nr; i++)
+			show_name(revs.objects[i].item, revs.objects[i].name,
+				  always, allow_undefined, data.name_only);
+	}
+
+	string_list_clear(&data.ref_filters, 0);
+	string_list_clear(&data.exclude_filters, 0);
+	mem_pool_discard(&string_pool, 0);
+	object_array_clear(&revs);
+	return 0;
+}
diff --git a/builtin/notes.c b/builtin/notes.c
new file mode 100644
index 0000000000..d051abf6df
--- /dev/null
+++ b/builtin/notes.c
@@ -0,0 +1,1162 @@
+/*
+ * Builtin "git notes"
+ *
+ * Copyright (c) 2010 Johan Herland <johan@xxxxxxxxxxx>
+ *
+ * Based on git-notes.sh by Johannes Schindelin,
+ * and builtin/tag.c by Kristian Høgsberg and Carlos Rica.
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "notes.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
+
+#include "pretty.h"
+#include "refs.h"
+#include "exec-cmd.h"
+#include "run-command.h"
+#include "parse-options.h"
+#include "string-list.h"
+#include "notes-merge.h"
+#include "notes-utils.h"
+#include "worktree.h"
+#include "write-or-die.h"
+
+static const char *separator = "\n";
+static const char * const git_notes_usage[] = {
+	N_("git notes [--ref <notes-ref>] [list [<object>]]"),
+	N_("git notes [--ref <notes-ref>] add [-f] [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>] [-e]"),
+	N_("git notes [--ref <notes-ref>] copy [-f] <from-object> <to-object>"),
+	N_("git notes [--ref <notes-ref>] append [--allow-empty] [--[no-]separator|--separator=<paragraph-break>] [--[no-]stripspace] [-m <msg> | -F <file> | (-c | -C) <object>] [<object>] [-e]"),
+	N_("git notes [--ref <notes-ref>] edit [--allow-empty] [<object>]"),
+	N_("git notes [--ref <notes-ref>] show [<object>]"),
+	N_("git notes [--ref <notes-ref>] merge [-v | -q] [-s <strategy>] <notes-ref>"),
+	"git notes merge --commit [-v | -q]",
+	"git notes merge --abort [-v | -q]",
+	N_("git notes [--ref <notes-ref>] remove [<object>...]"),
+	N_("git notes [--ref <notes-ref>] prune [-n] [-v]"),
+	N_("git notes [--ref <notes-ref>] get-ref"),
+	NULL
+};
+
+static const char * const git_notes_list_usage[] = {
+	N_("git notes [list [<object>]]"),
+	NULL
+};
+
+static const char * const git_notes_add_usage[] = {
+	N_("git notes add [<options>] [<object>]"),
+	NULL
+};
+
+static const char * const git_notes_copy_usage[] = {
+	N_("git notes copy [<options>] <from-object> <to-object>"),
+	N_("git notes copy --stdin [<from-object> <to-object>]..."),
+	NULL
+};
+
+static const char * const git_notes_append_usage[] = {
+	N_("git notes append [<options>] [<object>]"),
+	NULL
+};
+
+static const char * const git_notes_edit_usage[] = {
+	N_("git notes edit [<object>]"),
+	NULL
+};
+
+static const char * const git_notes_show_usage[] = {
+	N_("git notes show [<object>]"),
+	NULL
+};
+
+static const char * const git_notes_merge_usage[] = {
+	N_("git notes merge [<options>] <notes-ref>"),
+	N_("git notes merge --commit [<options>]"),
+	N_("git notes merge --abort [<options>]"),
+	NULL
+};
+
+static const char * const git_notes_remove_usage[] = {
+	N_("git notes remove [<object>]"),
+	NULL
+};
+
+static const char * const git_notes_prune_usage[] = {
+	N_("git notes prune [<options>]"),
+	NULL
+};
+
+static const char * const git_notes_get_ref_usage[] = {
+	"git notes get-ref",
+	NULL
+};
+
+static const char note_template[] =
+	N_("Write/edit the notes for the following object:");
+
+enum notes_stripspace {
+	UNSPECIFIED = -1,
+	NO_STRIPSPACE = 0,
+	STRIPSPACE = 1,
+};
+
+struct note_msg {
+	enum notes_stripspace stripspace;
+	struct strbuf buf;
+};
+
+struct note_data {
+	int use_editor;
+	int stripspace;
+	char *edit_path;
+	struct strbuf buf;
+	struct note_msg **messages;
+	size_t msg_nr;
+	size_t msg_alloc;
+};
+
+static void free_note_data(struct note_data *d)
+{
+	if (d->edit_path) {
+		unlink_or_warn(d->edit_path);
+		free(d->edit_path);
+	}
+	strbuf_release(&d->buf);
+
+	while (d->msg_nr--) {
+		strbuf_release(&d->messages[d->msg_nr]->buf);
+		free(d->messages[d->msg_nr]);
+	}
+	free(d->messages);
+}
+
+static int list_each_note(const struct object_id *object_oid,
+			  const struct object_id *note_oid,
+			  char *note_path UNUSED,
+			  void *cb_data UNUSED)
+{
+	printf("%s %s\n", oid_to_hex(note_oid), oid_to_hex(object_oid));
+	return 0;
+}
+
+static void copy_obj_to_fd(int fd, const struct object_id *oid)
+{
+	unsigned long size;
+	enum object_type type;
+	char *buf = repo_read_object_file(the_repository, oid, &type, &size);
+	if (buf) {
+		if (size)
+			write_or_die(fd, buf, size);
+		free(buf);
+	}
+}
+
+static void write_commented_object(int fd, const struct object_id *object)
+{
+	struct child_process show = CHILD_PROCESS_INIT;
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf cbuf = STRBUF_INIT;
+
+	/* Invoke "git show --stat --no-notes $object" */
+	strvec_pushl(&show.args, "show", "--stat", "--no-notes",
+		     oid_to_hex(object), NULL);
+	show.no_stdin = 1;
+	show.out = -1;
+	show.err = 0;
+	show.git_cmd = 1;
+	if (start_command(&show))
+		die(_("unable to start 'show' for object '%s'"),
+		    oid_to_hex(object));
+
+	if (strbuf_read(&buf, show.out, 0) < 0)
+		die_errno(_("could not read 'show' output"));
+	strbuf_add_commented_lines(&cbuf, buf.buf, buf.len, comment_line_str);
+	write_or_die(fd, cbuf.buf, cbuf.len);
+
+	strbuf_release(&cbuf);
+	strbuf_release(&buf);
+
+	if (finish_command(&show))
+		die(_("failed to finish 'show' for object '%s'"),
+		    oid_to_hex(object));
+}
+
+static void prepare_note_data(const struct object_id *object, struct note_data *d,
+		const struct object_id *old_note)
+{
+	if (d->use_editor || !d->msg_nr) {
+		int fd;
+		struct strbuf buf = STRBUF_INIT;
+
+		/* write the template message before editing: */
+		d->edit_path = git_pathdup("NOTES_EDITMSG");
+		fd = xopen(d->edit_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+
+		if (d->msg_nr)
+			write_or_die(fd, d->buf.buf, d->buf.len);
+		else if (old_note)
+			copy_obj_to_fd(fd, old_note);
+
+		strbuf_addch(&buf, '\n');
+		strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_str);
+		strbuf_add_commented_lines(&buf, _(note_template), strlen(_(note_template)),
+					   comment_line_str);
+		strbuf_add_commented_lines(&buf, "\n", strlen("\n"), comment_line_str);
+		write_or_die(fd, buf.buf, buf.len);
+
+		write_commented_object(fd, object);
+
+		close(fd);
+		strbuf_release(&buf);
+		strbuf_reset(&d->buf);
+
+		if (launch_editor(d->edit_path, &d->buf, NULL)) {
+			die(_("please supply the note contents using either -m or -F option"));
+		}
+		if (d->stripspace)
+			strbuf_stripspace(&d->buf, comment_line_str);
+	}
+}
+
+static void write_note_data(struct note_data *d, struct object_id *oid)
+{
+	if (write_object_file(d->buf.buf, d->buf.len, OBJ_BLOB, oid)) {
+		int status = die_message(_("unable to write note object"));
+
+		if (d->edit_path)
+			die_message(_("the note contents have been left in %s"),
+				    d->edit_path);
+		exit(status);
+	}
+}
+
+static void append_separator(struct strbuf *message)
+{
+	size_t sep_len = 0;
+
+	if (!separator)
+		return;
+	else if ((sep_len = strlen(separator)) && separator[sep_len - 1] == '\n')
+		strbuf_addstr(message, separator);
+	else
+		strbuf_addf(message, "%s%s", separator, "\n");
+}
+
+static void concat_messages(struct note_data *d)
+{
+	struct strbuf msg = STRBUF_INIT;
+	size_t i;
+
+	for (i = 0; i < d->msg_nr ; i++) {
+		if (d->buf.len)
+			append_separator(&d->buf);
+		strbuf_add(&msg, d->messages[i]->buf.buf, d->messages[i]->buf.len);
+		strbuf_addbuf(&d->buf, &msg);
+		if ((d->stripspace == UNSPECIFIED &&
+		     d->messages[i]->stripspace == STRIPSPACE) ||
+		    d->stripspace == STRIPSPACE)
+			strbuf_stripspace(&d->buf, NULL);
+		strbuf_reset(&msg);
+	}
+	strbuf_release(&msg);
+}
+
+static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
+{
+	struct note_data *d = opt->value;
+	struct note_msg *msg = xmalloc(sizeof(*msg));
+
+	BUG_ON_OPT_NEG(unset);
+
+	strbuf_init(&msg->buf, strlen(arg));
+	strbuf_addstr(&msg->buf, arg);
+	ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+	d->messages[d->msg_nr - 1] = msg;
+	msg->stripspace = STRIPSPACE;
+	return 0;
+}
+
+static int parse_file_arg(const struct option *opt, const char *arg, int unset)
+{
+	struct note_data *d = opt->value;
+	struct note_msg *msg = xmalloc(sizeof(*msg));
+
+	BUG_ON_OPT_NEG(unset);
+
+	strbuf_init(&msg->buf , 0);
+	if (!strcmp(arg, "-")) {
+		if (strbuf_read(&msg->buf, 0, 1024) < 0)
+			die_errno(_("cannot read '%s'"), arg);
+	} else if (strbuf_read_file(&msg->buf, arg, 1024) < 0)
+		die_errno(_("could not open or read '%s'"), arg);
+
+	ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+	d->messages[d->msg_nr - 1] = msg;
+	msg->stripspace = STRIPSPACE;
+	return 0;
+}
+
+static int parse_reuse_arg(const struct option *opt, const char *arg, int unset)
+{
+	struct note_data *d = opt->value;
+	struct note_msg *msg = xmalloc(sizeof(*msg));
+	char *value;
+	struct object_id object;
+	enum object_type type;
+	unsigned long len;
+
+	BUG_ON_OPT_NEG(unset);
+
+	strbuf_init(&msg->buf, 0);
+	if (repo_get_oid(the_repository, arg, &object))
+		die(_("failed to resolve '%s' as a valid ref."), arg);
+	if (!(value = repo_read_object_file(the_repository, &object, &type, &len)))
+		die(_("failed to read object '%s'."), arg);
+	if (type != OBJ_BLOB) {
+		strbuf_release(&msg->buf);
+		free(value);
+		free(msg);
+		die(_("cannot read note data from non-blob object '%s'."), arg);
+	}
+
+	strbuf_add(&msg->buf, value, len);
+	free(value);
+
+	msg->buf.len = len;
+	ALLOC_GROW_BY(d->messages, d->msg_nr, 1, d->msg_alloc);
+	d->messages[d->msg_nr - 1] = msg;
+	msg->stripspace = NO_STRIPSPACE;
+	return 0;
+}
+
+static int parse_reedit_arg(const struct option *opt, const char *arg, int unset)
+{
+	struct note_data *d = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	d->use_editor = 1;
+	return parse_reuse_arg(opt, arg, unset);
+}
+
+static int parse_separator_arg(const struct option *opt, const char *arg,
+			       int unset)
+{
+	if (unset)
+		*(const char **)opt->value = NULL;
+	else
+		*(const char **)opt->value = arg ? arg : "\n";
+	return 0;
+}
+
+static int notes_copy_from_stdin(int force, const char *rewrite_cmd)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct notes_rewrite_cfg *c = NULL;
+	struct notes_tree *t = NULL;
+	int ret = 0;
+	const char *msg = "Notes added by 'git notes copy'";
+
+	if (rewrite_cmd) {
+		c = init_copy_notes_for_rewrite(rewrite_cmd);
+		if (!c)
+			return 0;
+	} else {
+		init_notes(NULL, NULL, NULL, NOTES_INIT_WRITABLE);
+		t = &default_notes_tree;
+	}
+
+	while (strbuf_getline_lf(&buf, stdin) != EOF) {
+		struct object_id from_obj, to_obj;
+		struct strbuf **split;
+		int err;
+
+		split = strbuf_split(&buf, ' ');
+		if (!split[0] || !split[1])
+			die(_("malformed input line: '%s'."), buf.buf);
+		strbuf_rtrim(split[0]);
+		strbuf_rtrim(split[1]);
+		if (repo_get_oid(the_repository, split[0]->buf, &from_obj))
+			die(_("failed to resolve '%s' as a valid ref."), split[0]->buf);
+		if (repo_get_oid(the_repository, split[1]->buf, &to_obj))
+			die(_("failed to resolve '%s' as a valid ref."), split[1]->buf);
+
+		if (rewrite_cmd)
+			err = copy_note_for_rewrite(c, &from_obj, &to_obj);
+		else
+			err = copy_note(t, &from_obj, &to_obj, force,
+					combine_notes_overwrite);
+
+		if (err) {
+			error(_("failed to copy notes from '%s' to '%s'"),
+			      split[0]->buf, split[1]->buf);
+			ret = 1;
+		}
+
+		strbuf_list_free(split);
+	}
+
+	if (!rewrite_cmd) {
+		commit_notes(the_repository, t, msg);
+		free_notes(t);
+	} else {
+		finish_copy_notes_for_rewrite(the_repository, c, msg);
+	}
+	strbuf_release(&buf);
+	return ret;
+}
+
+static struct notes_tree *init_notes_check(const char *subcommand,
+					   int flags)
+{
+	struct notes_tree *t;
+	const char *ref;
+	init_notes(NULL, NULL, NULL, flags);
+	t = &default_notes_tree;
+
+	ref = (flags & NOTES_INIT_WRITABLE) ? t->update_ref : t->ref;
+	if (!starts_with(ref, "refs/notes/"))
+		/*
+		 * TRANSLATORS: the first %s will be replaced by a git
+		 * notes command: 'add', 'merge', 'remove', etc.
+		 */
+		die(_("refusing to %s notes in %s (outside of refs/notes/)"),
+		    subcommand, ref);
+	return t;
+}
+
+static int list(int argc, const char **argv, const char *prefix,
+		struct repository *repo UNUSED)
+{
+	struct notes_tree *t;
+	struct object_id object;
+	const struct object_id *note;
+	int retval = -1;
+	struct option options[] = {
+		OPT_END()
+	};
+
+	if (argc)
+		argc = parse_options(argc, argv, prefix, options,
+				     git_notes_list_usage, 0);
+
+	if (1 < argc) {
+		error(_("too many arguments"));
+		usage_with_options(git_notes_list_usage, options);
+	}
+
+	t = init_notes_check("list", 0);
+	if (argc) {
+		if (repo_get_oid(the_repository, argv[0], &object))
+			die(_("failed to resolve '%s' as a valid ref."), argv[0]);
+		note = get_note(t, &object);
+		if (note) {
+			puts(oid_to_hex(note));
+			retval = 0;
+		} else
+			retval = error(_("no note found for object %s."),
+				       oid_to_hex(&object));
+	} else
+		retval = for_each_note(t, 0, list_each_note, NULL);
+
+	free_notes(t);
+	return retval;
+}
+
+static int append_edit(int argc, const char **argv, const char *prefix,
+		       struct repository *repo UNUSED);
+
+static int add(int argc, const char **argv, const char *prefix,
+	       struct repository *repo)
+{
+	int force = 0, allow_empty = 0;
+	const char *object_ref;
+	struct notes_tree *t;
+	struct object_id object, new_note;
+	const struct object_id *note;
+	struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
+
+	struct option options[] = {
+		OPT_CALLBACK_F('m', "message", &d, N_("message"),
+			N_("note contents as a string"), PARSE_OPT_NONEG,
+			parse_msg_arg),
+		OPT_CALLBACK_F('F', "file", &d, N_("file"),
+			N_("note contents in a file"), PARSE_OPT_NONEG,
+			parse_file_arg),
+		OPT_CALLBACK_F('c', "reedit-message", &d, N_("object"),
+			N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
+			parse_reedit_arg),
+		OPT_BOOL('e', "edit", &d.use_editor,
+			N_("edit note message in editor")),
+		OPT_CALLBACK_F('C', "reuse-message", &d, N_("object"),
+			N_("reuse specified note object"), PARSE_OPT_NONEG,
+			parse_reuse_arg),
+		OPT_BOOL(0, "allow-empty", &allow_empty,
+			N_("allow storing empty note")),
+		OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
+		OPT_CALLBACK_F(0, "separator", &separator,
+			N_("<paragraph-break>"),
+			N_("insert <paragraph-break> between paragraphs"),
+			PARSE_OPT_OPTARG, parse_separator_arg),
+		OPT_BOOL(0, "stripspace", &d.stripspace,
+			N_("remove unnecessary whitespace")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, git_notes_add_usage,
+			     PARSE_OPT_KEEP_ARGV0);
+
+	if (2 < argc) {
+		error(_("too many arguments"));
+		usage_with_options(git_notes_add_usage, options);
+	}
+
+	if (d.msg_nr)
+		concat_messages(&d);
+
+	object_ref = argc > 1 ? argv[1] : "HEAD";
+
+	if (repo_get_oid(the_repository, object_ref, &object))
+		die(_("failed to resolve '%s' as a valid ref."), object_ref);
+
+	t = init_notes_check("add", NOTES_INIT_WRITABLE);
+	note = get_note(t, &object);
+
+	if (note) {
+		if (!force) {
+			free_notes(t);
+			if (d.msg_nr) {
+				free_note_data(&d);
+				return error(_("Cannot add notes. "
+					"Found existing notes for object %s. "
+					"Use '-f' to overwrite existing notes"),
+					oid_to_hex(&object));
+			}
+			/*
+			 * Redirect to "edit" subcommand.
+			 *
+			 * We only end up here if none of -m/-F/-c/-C or -f are
+			 * given. The original args are therefore still in
+			 * argv[0-1].
+			 */
+			argv[0] = "edit";
+			return append_edit(argc, argv, prefix, repo);
+		}
+		fprintf(stderr, _("Overwriting existing notes for object %s\n"),
+			oid_to_hex(&object));
+	}
+
+	prepare_note_data(&object, &d, note);
+	if (d.buf.len || allow_empty) {
+		write_note_data(&d, &new_note);
+		if (add_note(t, &object, &new_note, combine_notes_overwrite))
+			BUG("combine_notes_overwrite failed");
+		commit_notes(the_repository, t,
+			     "Notes added by 'git notes add'");
+	} else {
+		fprintf(stderr, _("Removing note for object %s\n"),
+			oid_to_hex(&object));
+		remove_note(t, object.hash);
+		commit_notes(the_repository, t,
+			     "Notes removed by 'git notes add'");
+	}
+
+	free_note_data(&d);
+	free_notes(t);
+	return 0;
+}
+
+static int copy(int argc, const char **argv, const char *prefix,
+		struct repository *repo UNUSED)
+{
+	int retval = 0, force = 0, from_stdin = 0;
+	const struct object_id *from_note, *note;
+	const char *object_ref;
+	struct object_id object, from_obj;
+	struct notes_tree *t;
+	const char *rewrite_cmd = NULL;
+	struct option options[] = {
+		OPT__FORCE(&force, N_("replace existing notes"), PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "stdin", &from_stdin, N_("read objects from stdin")),
+		OPT_STRING(0, "for-rewrite", &rewrite_cmd, N_("command"),
+			   N_("load rewriting config for <command> (implies "
+			      "--stdin)")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, git_notes_copy_usage,
+			     0);
+
+	if (from_stdin || rewrite_cmd) {
+		if (argc) {
+			error(_("too many arguments"));
+			usage_with_options(git_notes_copy_usage, options);
+		} else {
+			return notes_copy_from_stdin(force, rewrite_cmd);
+		}
+	}
+
+	if (argc < 1) {
+		error(_("too few arguments"));
+		usage_with_options(git_notes_copy_usage, options);
+	}
+	if (2 < argc) {
+		error(_("too many arguments"));
+		usage_with_options(git_notes_copy_usage, options);
+	}
+
+	if (repo_get_oid(the_repository, argv[0], &from_obj))
+		die(_("failed to resolve '%s' as a valid ref."), argv[0]);
+
+	object_ref = 1 < argc ? argv[1] : "HEAD";
+
+	if (repo_get_oid(the_repository, object_ref, &object))
+		die(_("failed to resolve '%s' as a valid ref."), object_ref);
+
+	t = init_notes_check("copy", NOTES_INIT_WRITABLE);
+	note = get_note(t, &object);
+
+	if (note) {
+		if (!force) {
+			retval = error(_("Cannot copy notes. Found existing "
+				       "notes for object %s. Use '-f' to "
+				       "overwrite existing notes"),
+				       oid_to_hex(&object));
+			goto out;
+		}
+		fprintf(stderr, _("Overwriting existing notes for object %s\n"),
+			oid_to_hex(&object));
+	}
+
+	from_note = get_note(t, &from_obj);
+	if (!from_note) {
+		retval = error(_("missing notes on source object %s. Cannot "
+			       "copy."), oid_to_hex(&from_obj));
+		goto out;
+	}
+
+	if (add_note(t, &object, from_note, combine_notes_overwrite))
+		BUG("combine_notes_overwrite failed");
+	commit_notes(the_repository, t,
+		     "Notes added by 'git notes copy'");
+out:
+	free_notes(t);
+	return retval;
+}
+
+static int append_edit(int argc, const char **argv, const char *prefix,
+		       struct repository *repo UNUSED)
+{
+	int allow_empty = 0;
+	const char *object_ref;
+	struct notes_tree *t;
+	struct object_id object, new_note;
+	const struct object_id *note;
+	char *logmsg;
+	const char * const *usage;
+	struct note_data d = { .buf = STRBUF_INIT, .stripspace = UNSPECIFIED };
+	struct option options[] = {
+		OPT_CALLBACK_F('m', "message", &d, N_("message"),
+			N_("note contents as a string"), PARSE_OPT_NONEG,
+			parse_msg_arg),
+		OPT_CALLBACK_F('F', "file", &d, N_("file"),
+			N_("note contents in a file"), PARSE_OPT_NONEG,
+			parse_file_arg),
+		OPT_CALLBACK_F('c', "reedit-message", &d, N_("object"),
+			N_("reuse and edit specified note object"), PARSE_OPT_NONEG,
+			parse_reedit_arg),
+		OPT_CALLBACK_F('C', "reuse-message", &d, N_("object"),
+			N_("reuse specified note object"), PARSE_OPT_NONEG,
+			parse_reuse_arg),
+		OPT_BOOL('e', "edit", &d.use_editor,
+			N_("edit note message in editor")),
+		OPT_BOOL(0, "allow-empty", &allow_empty,
+			N_("allow storing empty note")),
+		OPT_CALLBACK_F(0, "separator", &separator,
+			N_("<paragraph-break>"),
+			N_("insert <paragraph-break> between paragraphs"),
+			PARSE_OPT_OPTARG, parse_separator_arg),
+		OPT_BOOL(0, "stripspace", &d.stripspace,
+			N_("remove unnecessary whitespace")),
+		OPT_END()
+	};
+	int edit = !strcmp(argv[0], "edit");
+
+	usage = edit ? git_notes_edit_usage : git_notes_append_usage;
+	argc = parse_options(argc, argv, prefix, options, usage,
+			     PARSE_OPT_KEEP_ARGV0);
+
+	if (2 < argc) {
+		error(_("too many arguments"));
+		usage_with_options(usage, options);
+	}
+
+	if (d.msg_nr) {
+		concat_messages(&d);
+		if (edit)
+			fprintf(stderr, _("The -m/-F/-c/-C options have been "
+				"deprecated for the 'edit' subcommand.\n"
+				"Please use 'git notes add -f -m/-F/-c/-C' "
+				"instead.\n"));
+	}
+
+	object_ref = 1 < argc ? argv[1] : "HEAD";
+
+	if (repo_get_oid(the_repository, object_ref, &object))
+		die(_("failed to resolve '%s' as a valid ref."), object_ref);
+
+	t = init_notes_check(argv[0], NOTES_INIT_WRITABLE);
+	note = get_note(t, &object);
+
+	prepare_note_data(&object, &d, edit && note ? note : NULL);
+
+	if (note && !edit) {
+		/* Append buf to previous note contents */
+		unsigned long size;
+		enum object_type type;
+		struct strbuf buf = STRBUF_INIT;
+		char *prev_buf = repo_read_object_file(the_repository, note, &type, &size);
+
+		if (!prev_buf)
+			die(_("unable to read %s"), oid_to_hex(note));
+		if (size)
+			strbuf_add(&buf, prev_buf, size);
+		if (d.buf.len && size)
+			append_separator(&buf);
+		strbuf_insert(&d.buf, 0, buf.buf, buf.len);
+
+		free(prev_buf);
+		strbuf_release(&buf);
+	}
+
+	if (d.buf.len || allow_empty) {
+		write_note_data(&d, &new_note);
+		if (add_note(t, &object, &new_note, combine_notes_overwrite))
+			BUG("combine_notes_overwrite failed");
+		logmsg = xstrfmt("Notes added by 'git notes %s'", argv[0]);
+	} else {
+		fprintf(stderr, _("Removing note for object %s\n"),
+			oid_to_hex(&object));
+		remove_note(t, object.hash);
+		logmsg = xstrfmt("Notes removed by 'git notes %s'", argv[0]);
+	}
+	commit_notes(the_repository, t, logmsg);
+
+	free(logmsg);
+	free_note_data(&d);
+	free_notes(t);
+	return 0;
+}
+
+static int show(int argc, const char **argv, const char *prefix,
+		struct repository *repo UNUSED)
+{
+	const char *object_ref;
+	struct notes_tree *t;
+	struct object_id object;
+	const struct object_id *note;
+	int retval;
+	struct option options[] = {
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, git_notes_show_usage,
+			     0);
+
+	if (1 < argc) {
+		error(_("too many arguments"));
+		usage_with_options(git_notes_show_usage, options);
+	}
+
+	object_ref = argc ? argv[0] : "HEAD";
+
+	if (repo_get_oid(the_repository, object_ref, &object))
+		die(_("failed to resolve '%s' as a valid ref."), object_ref);
+
+	t = init_notes_check("show", 0);
+	note = get_note(t, &object);
+
+	if (!note)
+		retval = error(_("no note found for object %s."),
+			       oid_to_hex(&object));
+	else {
+		const char *show_args[3] = {"show", oid_to_hex(note), NULL};
+		retval = execv_git_cmd(show_args);
+	}
+	free_notes(t);
+	return retval;
+}
+
+static int merge_abort(struct notes_merge_options *o)
+{
+	int ret = 0;
+
+	/*
+	 * Remove .git/NOTES_MERGE_PARTIAL and .git/NOTES_MERGE_REF, and call
+	 * notes_merge_abort() to remove .git/NOTES_MERGE_WORKTREE.
+	 */
+
+	if (refs_delete_ref(get_main_ref_store(the_repository), NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
+		ret += error(_("failed to delete ref NOTES_MERGE_PARTIAL"));
+	if (refs_delete_ref(get_main_ref_store(the_repository), NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
+		ret += error(_("failed to delete ref NOTES_MERGE_REF"));
+	if (notes_merge_abort(o))
+		ret += error(_("failed to remove 'git notes merge' worktree"));
+	return ret;
+}
+
+static int merge_commit(struct notes_merge_options *o)
+{
+	struct strbuf msg = STRBUF_INIT;
+	struct object_id oid, parent_oid;
+	struct notes_tree t = {0};
+	struct commit *partial;
+	struct pretty_print_context pretty_ctx;
+	void *local_ref_to_free;
+	int ret;
+
+	/*
+	 * Read partial merge result from .git/NOTES_MERGE_PARTIAL,
+	 * and target notes ref from .git/NOTES_MERGE_REF.
+	 */
+
+	if (repo_get_oid(the_repository, "NOTES_MERGE_PARTIAL", &oid))
+		die(_("failed to read ref NOTES_MERGE_PARTIAL"));
+	else if (!(partial = lookup_commit_reference(the_repository, &oid)))
+		die(_("could not find commit from NOTES_MERGE_PARTIAL."));
+	else if (repo_parse_commit(the_repository, partial))
+		die(_("could not parse commit from NOTES_MERGE_PARTIAL."));
+
+	if (partial->parents)
+		oidcpy(&parent_oid, &partial->parents->item->object.oid);
+	else
+		oidclr(&parent_oid, the_repository->hash_algo);
+
+	init_notes(&t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
+
+	o->local_ref = local_ref_to_free =
+		refs_resolve_refdup(get_main_ref_store(the_repository),
+				    "NOTES_MERGE_REF", 0, &oid, NULL);
+	if (!o->local_ref)
+		die(_("failed to resolve NOTES_MERGE_REF"));
+
+	if (notes_merge_commit(o, &t, partial, &oid))
+		die(_("failed to finalize notes merge"));
+
+	/* Reuse existing commit message in reflog message */
+	memset(&pretty_ctx, 0, sizeof(pretty_ctx));
+	repo_format_commit_message(the_repository, partial, "%s", &msg,
+				   &pretty_ctx);
+	strbuf_trim(&msg);
+	strbuf_insertstr(&msg, 0, "notes: ");
+	refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+			o->local_ref, &oid,
+			is_null_oid(&parent_oid) ? NULL : &parent_oid,
+			0, UPDATE_REFS_DIE_ON_ERR);
+
+	free_notes(&t);
+	strbuf_release(&msg);
+	ret = merge_abort(o);
+	free(local_ref_to_free);
+	return ret;
+}
+
+static int git_config_get_notes_strategy(const char *key,
+					 enum notes_merge_strategy *strategy)
+{
+	char *value;
+
+	if (git_config_get_string(key, &value))
+		return 1;
+	if (parse_notes_merge_strategy(value, strategy))
+		git_die_config(the_repository, key, _("unknown notes merge strategy %s"), value);
+
+	free(value);
+	return 0;
+}
+
+static int merge(int argc, const char **argv, const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;
+	struct object_id result_oid;
+	struct notes_tree *t;
+	struct notes_merge_options o;
+	int do_merge = 0, do_commit = 0, do_abort = 0;
+	int verbosity = 0, result;
+	const char *strategy = NULL;
+	struct option options[] = {
+		OPT_GROUP(N_("General options")),
+		OPT__VERBOSITY(&verbosity),
+		OPT_GROUP(N_("Merge options")),
+		OPT_STRING('s', "strategy", &strategy, N_("strategy"),
+			   N_("resolve notes conflicts using the given strategy "
+			      "(manual/ours/theirs/union/cat_sort_uniq)")),
+		OPT_GROUP(N_("Committing unmerged notes")),
+		OPT_SET_INT_F(0, "commit", &do_commit,
+			      N_("finalize notes merge by committing unmerged notes"),
+			      1, PARSE_OPT_NONEG),
+		OPT_GROUP(N_("Aborting notes merge resolution")),
+		OPT_SET_INT_F(0, "abort", &do_abort,
+			      N_("abort notes merge"),
+			      1, PARSE_OPT_NONEG),
+		OPT_END()
+	};
+	char *notes_ref;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_notes_merge_usage, 0);
+
+	if (strategy || do_commit + do_abort == 0)
+		do_merge = 1;
+	if (do_merge + do_commit + do_abort != 1) {
+		error(_("cannot mix --commit, --abort or -s/--strategy"));
+		usage_with_options(git_notes_merge_usage, options);
+	}
+
+	if (do_merge && argc != 1) {
+		error(_("must specify a notes ref to merge"));
+		usage_with_options(git_notes_merge_usage, options);
+	} else if (!do_merge && argc) {
+		error(_("too many arguments"));
+		usage_with_options(git_notes_merge_usage, options);
+	}
+
+	init_notes_merge_options(the_repository, &o);
+	o.verbosity = verbosity + NOTES_MERGE_VERBOSITY_DEFAULT;
+
+	if (do_abort)
+		return merge_abort(&o);
+	if (do_commit)
+		return merge_commit(&o);
+
+	notes_ref = default_notes_ref(the_repository);
+	o.local_ref = notes_ref;
+	strbuf_addstr(&remote_ref, argv[0]);
+	expand_loose_notes_ref(&remote_ref);
+	o.remote_ref = remote_ref.buf;
+
+	t = init_notes_check("merge", NOTES_INIT_WRITABLE);
+
+	if (strategy) {
+		if (parse_notes_merge_strategy(strategy, &o.strategy)) {
+			error(_("unknown -s/--strategy: %s"), strategy);
+			usage_with_options(git_notes_merge_usage, options);
+		}
+	} else {
+		struct strbuf merge_key = STRBUF_INIT;
+		const char *short_ref = NULL;
+
+		if (!skip_prefix(o.local_ref, "refs/notes/", &short_ref))
+			BUG("local ref %s is outside of refs/notes/",
+			    o.local_ref);
+
+		strbuf_addf(&merge_key, "notes.%s.mergeStrategy", short_ref);
+
+		if (git_config_get_notes_strategy(merge_key.buf, &o.strategy))
+			git_config_get_notes_strategy("notes.mergeStrategy", &o.strategy);
+
+		strbuf_release(&merge_key);
+	}
+
+	strbuf_addf(&msg, "notes: Merged notes from %s into %s",
+		    remote_ref.buf, notes_ref);
+	strbuf_add(&(o.commit_msg), msg.buf + 7, msg.len - 7); /* skip "notes: " */
+
+	result = notes_merge(&o, t, &result_oid);
+
+	if (result >= 0) /* Merge resulted (trivially) in result_oid */
+		/* Update default notes ref with new commit */
+		refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+				notes_ref, &result_oid, NULL, 0,
+				UPDATE_REFS_DIE_ON_ERR);
+	else { /* Merge has unresolved conflicts */
+		struct worktree **worktrees;
+		const struct worktree *wt;
+		/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
+		refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+				"NOTES_MERGE_PARTIAL", &result_oid, NULL,
+				0, UPDATE_REFS_DIE_ON_ERR);
+		/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
+		worktrees = get_worktrees();
+		wt = find_shared_symref(worktrees, "NOTES_MERGE_REF",
+					notes_ref);
+		if (wt)
+			die(_("a notes merge into %s is already in-progress at %s"),
+			    notes_ref, wt->path);
+		free_worktrees(worktrees);
+		if (refs_update_symref(get_main_ref_store(the_repository), "NOTES_MERGE_REF", notes_ref, NULL))
+			die(_("failed to store link to current notes ref (%s)"),
+			    notes_ref);
+		fprintf(stderr, _("Automatic notes merge failed. Fix conflicts in %s "
+				  "and commit the result with 'git notes merge --commit', "
+				  "or abort the merge with 'git notes merge --abort'.\n"),
+			git_path(NOTES_MERGE_WORKTREE));
+	}
+
+	free_notes(t);
+	free(notes_ref);
+	strbuf_release(&remote_ref);
+	strbuf_release(&msg);
+	return result < 0; /* return non-zero on conflicts */
+}
+
+#define IGNORE_MISSING 1
+
+static int remove_one_note(struct notes_tree *t, const char *name, unsigned flag)
+{
+	int status;
+	struct object_id oid;
+	if (repo_get_oid(the_repository, name, &oid))
+		return error(_("Failed to resolve '%s' as a valid ref."), name);
+	status = remove_note(t, oid.hash);
+	if (status)
+		fprintf(stderr, _("Object %s has no note\n"), name);
+	else
+		fprintf(stderr, _("Removing note for object %s\n"), name);
+	return (flag & IGNORE_MISSING) ? 0 : status;
+}
+
+static int remove_cmd(int argc, const char **argv, const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	unsigned flag = 0;
+	int from_stdin = 0;
+	struct option options[] = {
+		OPT_BIT(0, "ignore-missing", &flag,
+			N_("attempt to remove non-existent note is not an error"),
+			IGNORE_MISSING),
+		OPT_BOOL(0, "stdin", &from_stdin,
+			    N_("read object names from the standard input")),
+		OPT_END()
+	};
+	struct notes_tree *t;
+	int retval = 0;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_notes_remove_usage, 0);
+
+	t = init_notes_check("remove", NOTES_INIT_WRITABLE);
+
+	if (!argc && !from_stdin) {
+		retval = remove_one_note(t, "HEAD", flag);
+	} else {
+		while (*argv) {
+			retval |= remove_one_note(t, *argv, flag);
+			argv++;
+		}
+	}
+	if (from_stdin) {
+		struct strbuf sb = STRBUF_INIT;
+		while (strbuf_getwholeline(&sb, stdin, '\n') != EOF) {
+			strbuf_rtrim(&sb);
+			retval |= remove_one_note(t, sb.buf, flag);
+		}
+		strbuf_release(&sb);
+	}
+	if (!retval)
+		commit_notes(the_repository, t,
+			     "Notes removed by 'git notes remove'");
+	free_notes(t);
+	return retval;
+}
+
+static int prune(int argc, const char **argv, const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct notes_tree *t;
+	int show_only = 0, verbose = 0;
+	struct option options[] = {
+		OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
+		OPT__VERBOSE(&verbose, N_("report pruned notes")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, git_notes_prune_usage,
+			     0);
+
+	if (argc) {
+		error(_("too many arguments"));
+		usage_with_options(git_notes_prune_usage, options);
+	}
+
+	t = init_notes_check("prune", NOTES_INIT_WRITABLE);
+
+	prune_notes(t, (verbose ? NOTES_PRUNE_VERBOSE : 0) |
+		(show_only ? NOTES_PRUNE_VERBOSE|NOTES_PRUNE_DRYRUN : 0) );
+	if (!show_only)
+		commit_notes(the_repository, t,
+			     "Notes removed by 'git notes prune'");
+	free_notes(t);
+	return 0;
+}
+
+static int get_ref(int argc, const char **argv, const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct option options[] = { OPT_END() };
+	char *notes_ref;
+	argc = parse_options(argc, argv, prefix, options,
+			     git_notes_get_ref_usage, 0);
+
+	if (argc) {
+		error(_("too many arguments"));
+		usage_with_options(git_notes_get_ref_usage, options);
+	}
+
+	notes_ref = default_notes_ref(the_repository);
+	puts(notes_ref);
+	free(notes_ref);
+	return 0;
+}
+
+int cmd_notes(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo)
+{
+	const char *override_notes_ref = NULL;
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_STRING(0, "ref", &override_notes_ref, N_("notes-ref"),
+			   N_("use notes from <notes-ref>")),
+		OPT_SUBCOMMAND("list", &fn, list),
+		OPT_SUBCOMMAND("add", &fn, add),
+		OPT_SUBCOMMAND("copy", &fn, copy),
+		OPT_SUBCOMMAND("append", &fn, append_edit),
+		OPT_SUBCOMMAND("edit", &fn, append_edit),
+		OPT_SUBCOMMAND("show", &fn, show),
+		OPT_SUBCOMMAND("merge", &fn, merge),
+		OPT_SUBCOMMAND("remove", &fn, remove_cmd),
+		OPT_SUBCOMMAND("prune", &fn, prune),
+		OPT_SUBCOMMAND("get-ref", &fn, get_ref),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, options, git_notes_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL);
+	if (!fn) {
+		if (argc) {
+			error(_("unknown subcommand: `%s'"), argv[0]);
+			usage_with_options(git_notes_usage, options);
+		}
+		fn = list;
+	}
+
+	if (override_notes_ref) {
+		struct strbuf sb = STRBUF_INIT;
+		strbuf_addstr(&sb, override_notes_ref);
+		expand_notes_ref(&sb);
+		setenv("GIT_NOTES_REF", sb.buf, 1);
+		strbuf_release(&sb);
+	}
+
+	return !!fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
new file mode 100644
index 0000000000..d51c021d99
--- /dev/null
+++ b/builtin/pack-objects.c
@@ -0,0 +1,4704 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "config.h"
+#include "attr.h"
+#include "object.h"
+#include "commit.h"
+#include "tag.h"
+#include "delta.h"
+#include "pack.h"
+#include "pack-revindex.h"
+#include "csum-file.h"
+#include "tree-walk.h"
+#include "diff.h"
+#include "revision.h"
+#include "list-objects.h"
+#include "list-objects-filter-options.h"
+#include "pack-objects.h"
+#include "progress.h"
+#include "refs.h"
+#include "streaming.h"
+#include "thread-utils.h"
+#include "pack-bitmap.h"
+#include "delta-islands.h"
+#include "reachable.h"
+#include "oid-array.h"
+#include "strvec.h"
+#include "list.h"
+#include "packfile.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
+#include "dir.h"
+#include "midx.h"
+#include "trace2.h"
+#include "shallow.h"
+#include "promisor-remote.h"
+#include "pack-mtimes.h"
+#include "parse-options.h"
+
+/*
+ * Objects we are going to pack are collected in the `to_pack` structure.
+ * It contains an array (dynamically expanded) of the object data, and a map
+ * that can resolve SHA1s to their position in the array.
+ */
+static struct packing_data to_pack;
+
+static inline struct object_entry *oe_delta(
+		const struct packing_data *pack,
+		const struct object_entry *e)
+{
+	if (!e->delta_idx)
+		return NULL;
+	if (e->ext_base)
+		return &pack->ext_bases[e->delta_idx - 1];
+	else
+		return &pack->objects[e->delta_idx - 1];
+}
+
+static inline unsigned long oe_delta_size(struct packing_data *pack,
+					  const struct object_entry *e)
+{
+	if (e->delta_size_valid)
+		return e->delta_size_;
+
+	/*
+	 * pack->delta_size[] can't be NULL because oe_set_delta_size()
+	 * must have been called when a new delta is saved with
+	 * oe_set_delta().
+	 * If oe_delta() returns NULL (i.e. default state, which means
+	 * delta_size_valid is also false), then the caller must never
+	 * call oe_delta_size().
+	 */
+	return pack->delta_size[e - pack->objects];
+}
+
+unsigned long oe_get_size_slow(struct packing_data *pack,
+			       const struct object_entry *e);
+
+static inline unsigned long oe_size(struct packing_data *pack,
+				    const struct object_entry *e)
+{
+	if (e->size_valid)
+		return e->size_;
+
+	return oe_get_size_slow(pack, e);
+}
+
+static inline void oe_set_delta(struct packing_data *pack,
+				struct object_entry *e,
+				struct object_entry *delta)
+{
+	if (delta)
+		e->delta_idx = (delta - pack->objects) + 1;
+	else
+		e->delta_idx = 0;
+}
+
+static inline struct object_entry *oe_delta_sibling(
+		const struct packing_data *pack,
+		const struct object_entry *e)
+{
+	if (e->delta_sibling_idx)
+		return &pack->objects[e->delta_sibling_idx - 1];
+	return NULL;
+}
+
+static inline struct object_entry *oe_delta_child(
+		const struct packing_data *pack,
+		const struct object_entry *e)
+{
+	if (e->delta_child_idx)
+		return &pack->objects[e->delta_child_idx - 1];
+	return NULL;
+}
+
+static inline void oe_set_delta_child(struct packing_data *pack,
+				      struct object_entry *e,
+				      struct object_entry *delta)
+{
+	if (delta)
+		e->delta_child_idx = (delta - pack->objects) + 1;
+	else
+		e->delta_child_idx = 0;
+}
+
+static inline void oe_set_delta_sibling(struct packing_data *pack,
+					struct object_entry *e,
+					struct object_entry *delta)
+{
+	if (delta)
+		e->delta_sibling_idx = (delta - pack->objects) + 1;
+	else
+		e->delta_sibling_idx = 0;
+}
+
+static inline void oe_set_size(struct packing_data *pack,
+			       struct object_entry *e,
+			       unsigned long size)
+{
+	if (size < pack->oe_size_limit) {
+		e->size_ = size;
+		e->size_valid = 1;
+	} else {
+		e->size_valid = 0;
+		if (oe_get_size_slow(pack, e) != size)
+			BUG("'size' is supposed to be the object size!");
+	}
+}
+
+static inline void oe_set_delta_size(struct packing_data *pack,
+				     struct object_entry *e,
+				     unsigned long size)
+{
+	if (size < pack->oe_delta_size_limit) {
+		e->delta_size_ = size;
+		e->delta_size_valid = 1;
+	} else {
+		packing_data_lock(pack);
+		if (!pack->delta_size)
+			ALLOC_ARRAY(pack->delta_size, pack->nr_alloc);
+		packing_data_unlock(pack);
+
+		pack->delta_size[e - pack->objects] = size;
+		e->delta_size_valid = 0;
+	}
+}
+
+#define IN_PACK(obj) oe_in_pack(&to_pack, obj)
+#define SIZE(obj) oe_size(&to_pack, obj)
+#define SET_SIZE(obj,size) oe_set_size(&to_pack, obj, size)
+#define DELTA_SIZE(obj) oe_delta_size(&to_pack, obj)
+#define DELTA(obj) oe_delta(&to_pack, obj)
+#define DELTA_CHILD(obj) oe_delta_child(&to_pack, obj)
+#define DELTA_SIBLING(obj) oe_delta_sibling(&to_pack, obj)
+#define SET_DELTA(obj, val) oe_set_delta(&to_pack, obj, val)
+#define SET_DELTA_EXT(obj, oid) oe_set_delta_ext(&to_pack, obj, oid)
+#define SET_DELTA_SIZE(obj, val) oe_set_delta_size(&to_pack, obj, val)
+#define SET_DELTA_CHILD(obj, val) oe_set_delta_child(&to_pack, obj, val)
+#define SET_DELTA_SIBLING(obj, val) oe_set_delta_sibling(&to_pack, obj, val)
+
+static const char *pack_usage[] = {
+	N_("git pack-objects --stdout [<options>] [< <ref-list> | < <object-list>]"),
+	N_("git pack-objects [<options>] <base-name> [< <ref-list> | < <object-list>]"),
+	NULL
+};
+
+static struct pack_idx_entry **written_list;
+static uint32_t nr_result, nr_written, nr_seen;
+static struct bitmap_index *bitmap_git;
+static uint32_t write_layer;
+
+static int non_empty;
+static int reuse_delta = 1, reuse_object = 1;
+static int keep_unreachable, unpack_unreachable, include_tag;
+static timestamp_t unpack_unreachable_expiration;
+static int pack_loose_unreachable;
+static int cruft;
+static timestamp_t cruft_expiration;
+static int local;
+static int have_non_local_packs;
+static int incremental;
+static int ignore_packed_keep_on_disk;
+static int ignore_packed_keep_in_core;
+static int allow_ofs_delta;
+static struct pack_idx_option pack_idx_opts;
+static const char *base_name;
+static int progress = 1;
+static int window = 10;
+static unsigned long pack_size_limit;
+static int depth = 50;
+static int delta_search_threads;
+static int pack_to_stdout;
+static int sparse;
+static int thin;
+static int num_preferred_base;
+static struct progress *progress_state;
+
+static struct bitmapped_pack *reuse_packfiles;
+static size_t reuse_packfiles_nr;
+static size_t reuse_packfiles_used_nr;
+static uint32_t reuse_packfile_objects;
+static struct bitmap *reuse_packfile_bitmap;
+
+static int use_bitmap_index_default = 1;
+static int use_bitmap_index = -1;
+static enum {
+	NO_PACK_REUSE = 0,
+	SINGLE_PACK_REUSE,
+	MULTI_PACK_REUSE,
+} allow_pack_reuse = SINGLE_PACK_REUSE;
+static enum {
+	WRITE_BITMAP_FALSE = 0,
+	WRITE_BITMAP_QUIET,
+	WRITE_BITMAP_TRUE,
+} write_bitmap_index;
+static uint16_t write_bitmap_options = BITMAP_OPT_HASH_CACHE;
+
+static int exclude_promisor_objects;
+static int exclude_promisor_objects_best_effort;
+
+static int use_delta_islands;
+
+static unsigned long delta_cache_size = 0;
+static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
+static unsigned long cache_max_small_delta_size = 1000;
+
+static unsigned long window_memory_limit = 0;
+
+static struct string_list uri_protocols = STRING_LIST_INIT_NODUP;
+
+enum missing_action {
+	MA_ERROR = 0,      /* fail if any missing objects are encountered */
+	MA_ALLOW_ANY,      /* silently allow ALL missing objects */
+	MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
+};
+static enum missing_action arg_missing_action;
+static show_object_fn fn_show_object;
+
+struct configured_exclusion {
+	struct oidmap_entry e;
+	char *pack_hash_hex;
+	char *uri;
+};
+static struct oidmap configured_exclusions;
+
+static struct oidset excluded_by_config;
+
+/*
+ * stats
+ */
+static uint32_t written, written_delta;
+static uint32_t reused, reused_delta;
+
+/*
+ * Indexed commits
+ */
+static struct commit **indexed_commits;
+static unsigned int indexed_commits_nr;
+static unsigned int indexed_commits_alloc;
+
+static void index_commit_for_bitmap(struct commit *commit)
+{
+	if (indexed_commits_nr >= indexed_commits_alloc) {
+		indexed_commits_alloc = (indexed_commits_alloc + 32) * 2;
+		REALLOC_ARRAY(indexed_commits, indexed_commits_alloc);
+	}
+
+	indexed_commits[indexed_commits_nr++] = commit;
+}
+
+static void *get_delta(struct object_entry *entry)
+{
+	unsigned long size, base_size, delta_size;
+	void *buf, *base_buf, *delta_buf;
+	enum object_type type;
+
+	buf = repo_read_object_file(the_repository, &entry->idx.oid, &type,
+				    &size);
+	if (!buf)
+		die(_("unable to read %s"), oid_to_hex(&entry->idx.oid));
+	base_buf = repo_read_object_file(the_repository,
+					 &DELTA(entry)->idx.oid, &type,
+					 &base_size);
+	if (!base_buf)
+		die("unable to read %s",
+		    oid_to_hex(&DELTA(entry)->idx.oid));
+	delta_buf = diff_delta(base_buf, base_size,
+			       buf, size, &delta_size, 0);
+	/*
+	 * We successfully computed this delta once but dropped it for
+	 * memory reasons. Something is very wrong if this time we
+	 * recompute and create a different delta.
+	 */
+	if (!delta_buf || delta_size != DELTA_SIZE(entry))
+		BUG("delta size changed");
+	free(buf);
+	free(base_buf);
+	return delta_buf;
+}
+
+static unsigned long do_compress(void **pptr, unsigned long size)
+{
+	git_zstream stream;
+	void *in, *out;
+	unsigned long maxsize;
+
+	git_deflate_init(&stream, pack_compression_level);
+	maxsize = git_deflate_bound(&stream, size);
+
+	in = *pptr;
+	out = xmalloc(maxsize);
+	*pptr = out;
+
+	stream.next_in = in;
+	stream.avail_in = size;
+	stream.next_out = out;
+	stream.avail_out = maxsize;
+	while (git_deflate(&stream, Z_FINISH) == Z_OK)
+		; /* nothing */
+	git_deflate_end(&stream);
+
+	free(in);
+	return stream.total_out;
+}
+
+static unsigned long write_large_blob_data(struct git_istream *st, struct hashfile *f,
+					   const struct object_id *oid)
+{
+	git_zstream stream;
+	unsigned char ibuf[1024 * 16];
+	unsigned char obuf[1024 * 16];
+	unsigned long olen = 0;
+
+	git_deflate_init(&stream, pack_compression_level);
+
+	for (;;) {
+		ssize_t readlen;
+		int zret = Z_OK;
+		readlen = read_istream(st, ibuf, sizeof(ibuf));
+		if (readlen == -1)
+			die(_("unable to read %s"), oid_to_hex(oid));
+
+		stream.next_in = ibuf;
+		stream.avail_in = readlen;
+		while ((stream.avail_in || readlen == 0) &&
+		       (zret == Z_OK || zret == Z_BUF_ERROR)) {
+			stream.next_out = obuf;
+			stream.avail_out = sizeof(obuf);
+			zret = git_deflate(&stream, readlen ? 0 : Z_FINISH);
+			hashwrite(f, obuf, stream.next_out - obuf);
+			olen += stream.next_out - obuf;
+		}
+		if (stream.avail_in)
+			die(_("deflate error (%d)"), zret);
+		if (readlen == 0) {
+			if (zret != Z_STREAM_END)
+				die(_("deflate error (%d)"), zret);
+			break;
+		}
+	}
+	git_deflate_end(&stream);
+	return olen;
+}
+
+/*
+ * we are going to reuse the existing object data as is.  make
+ * sure it is not corrupt.
+ */
+static int check_pack_inflate(struct packed_git *p,
+		struct pack_window **w_curs,
+		off_t offset,
+		off_t len,
+		unsigned long expect)
+{
+	git_zstream stream;
+	unsigned char fakebuf[4096], *in;
+	int st;
+
+	memset(&stream, 0, sizeof(stream));
+	git_inflate_init(&stream);
+	do {
+		in = use_pack(p, w_curs, offset, &stream.avail_in);
+		stream.next_in = in;
+		stream.next_out = fakebuf;
+		stream.avail_out = sizeof(fakebuf);
+		st = git_inflate(&stream, Z_FINISH);
+		offset += stream.next_in - in;
+	} while (st == Z_OK || st == Z_BUF_ERROR);
+	git_inflate_end(&stream);
+	return (st == Z_STREAM_END &&
+		stream.total_out == expect &&
+		stream.total_in == len) ? 0 : -1;
+}
+
+static void copy_pack_data(struct hashfile *f,
+		struct packed_git *p,
+		struct pack_window **w_curs,
+		off_t offset,
+		off_t len)
+{
+	unsigned char *in;
+	unsigned long avail;
+
+	while (len) {
+		in = use_pack(p, w_curs, offset, &avail);
+		if (avail > len)
+			avail = (unsigned long)len;
+		hashwrite(f, in, avail);
+		offset += avail;
+		len -= avail;
+	}
+}
+
+static inline int oe_size_greater_than(struct packing_data *pack,
+				       const struct object_entry *lhs,
+				       unsigned long rhs)
+{
+	if (lhs->size_valid)
+		return lhs->size_ > rhs;
+	if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */
+		return 1;
+	return oe_get_size_slow(pack, lhs) > rhs;
+}
+
+/* Return 0 if we will bust the pack-size limit */
+static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry,
+					   unsigned long limit, int usable_delta)
+{
+	unsigned long size, datalen;
+	unsigned char header[MAX_PACK_OBJECT_HEADER],
+		      dheader[MAX_PACK_OBJECT_HEADER];
+	unsigned hdrlen;
+	enum object_type type;
+	void *buf;
+	struct git_istream *st = NULL;
+	const unsigned hashsz = the_hash_algo->rawsz;
+
+	if (!usable_delta) {
+		if (oe_type(entry) == OBJ_BLOB &&
+		    oe_size_greater_than(&to_pack, entry, big_file_threshold) &&
+		    (st = open_istream(the_repository, &entry->idx.oid, &type,
+				       &size, NULL)) != NULL)
+			buf = NULL;
+		else {
+			buf = repo_read_object_file(the_repository,
+						    &entry->idx.oid, &type,
+						    &size);
+			if (!buf)
+				die(_("unable to read %s"),
+				    oid_to_hex(&entry->idx.oid));
+		}
+		/*
+		 * make sure no cached delta data remains from a
+		 * previous attempt before a pack split occurred.
+		 */
+		FREE_AND_NULL(entry->delta_data);
+		entry->z_delta_size = 0;
+	} else if (entry->delta_data) {
+		size = DELTA_SIZE(entry);
+		buf = entry->delta_data;
+		entry->delta_data = NULL;
+		type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
+			OBJ_OFS_DELTA : OBJ_REF_DELTA;
+	} else {
+		buf = get_delta(entry);
+		size = DELTA_SIZE(entry);
+		type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
+			OBJ_OFS_DELTA : OBJ_REF_DELTA;
+	}
+
+	if (st)	/* large blob case, just assume we don't compress well */
+		datalen = size;
+	else if (entry->z_delta_size)
+		datalen = entry->z_delta_size;
+	else
+		datalen = do_compress(&buf, size);
+
+	/*
+	 * The object header is a byte of 'type' followed by zero or
+	 * more bytes of length.
+	 */
+	hdrlen = encode_in_pack_object_header(header, sizeof(header),
+					      type, size);
+
+	if (type == OBJ_OFS_DELTA) {
+		/*
+		 * Deltas with relative base contain an additional
+		 * encoding of the relative offset for the delta
+		 * base from this object's position in the pack.
+		 */
+		off_t ofs = entry->idx.offset - DELTA(entry)->idx.offset;
+		unsigned pos = sizeof(dheader) - 1;
+		dheader[pos] = ofs & 127;
+		while (ofs >>= 7)
+			dheader[--pos] = 128 | (--ofs & 127);
+		if (limit && hdrlen + sizeof(dheader) - pos + datalen + hashsz >= limit) {
+			if (st)
+				close_istream(st);
+			free(buf);
+			return 0;
+		}
+		hashwrite(f, header, hdrlen);
+		hashwrite(f, dheader + pos, sizeof(dheader) - pos);
+		hdrlen += sizeof(dheader) - pos;
+	} else if (type == OBJ_REF_DELTA) {
+		/*
+		 * Deltas with a base reference contain
+		 * additional bytes for the base object ID.
+		 */
+		if (limit && hdrlen + hashsz + datalen + hashsz >= limit) {
+			if (st)
+				close_istream(st);
+			free(buf);
+			return 0;
+		}
+		hashwrite(f, header, hdrlen);
+		hashwrite(f, DELTA(entry)->idx.oid.hash, hashsz);
+		hdrlen += hashsz;
+	} else {
+		if (limit && hdrlen + datalen + hashsz >= limit) {
+			if (st)
+				close_istream(st);
+			free(buf);
+			return 0;
+		}
+		hashwrite(f, header, hdrlen);
+	}
+	if (st) {
+		datalen = write_large_blob_data(st, f, &entry->idx.oid);
+		close_istream(st);
+	} else {
+		hashwrite(f, buf, datalen);
+		free(buf);
+	}
+
+	return hdrlen + datalen;
+}
+
+/* Return 0 if we will bust the pack-size limit */
+static off_t write_reuse_object(struct hashfile *f, struct object_entry *entry,
+				unsigned long limit, int usable_delta)
+{
+	struct packed_git *p = IN_PACK(entry);
+	struct pack_window *w_curs = NULL;
+	uint32_t pos;
+	off_t offset;
+	enum object_type type = oe_type(entry);
+	off_t datalen;
+	unsigned char header[MAX_PACK_OBJECT_HEADER],
+		      dheader[MAX_PACK_OBJECT_HEADER];
+	unsigned hdrlen;
+	const unsigned hashsz = the_hash_algo->rawsz;
+	unsigned long entry_size = SIZE(entry);
+
+	if (DELTA(entry))
+		type = (allow_ofs_delta && DELTA(entry)->idx.offset) ?
+			OBJ_OFS_DELTA : OBJ_REF_DELTA;
+	hdrlen = encode_in_pack_object_header(header, sizeof(header),
+					      type, entry_size);
+
+	offset = entry->in_pack_offset;
+	if (offset_to_pack_pos(p, offset, &pos) < 0)
+		die(_("write_reuse_object: could not locate %s, expected at "
+		      "offset %"PRIuMAX" in pack %s"),
+		    oid_to_hex(&entry->idx.oid), (uintmax_t)offset,
+		    p->pack_name);
+	datalen = pack_pos_to_offset(p, pos + 1) - offset;
+	if (!pack_to_stdout && p->index_version > 1 &&
+	    check_pack_crc(p, &w_curs, offset, datalen,
+			   pack_pos_to_index(p, pos))) {
+		error(_("bad packed object CRC for %s"),
+		      oid_to_hex(&entry->idx.oid));
+		unuse_pack(&w_curs);
+		return write_no_reuse_object(f, entry, limit, usable_delta);
+	}
+
+	offset += entry->in_pack_header_size;
+	datalen -= entry->in_pack_header_size;
+
+	if (!pack_to_stdout && p->index_version == 1 &&
+	    check_pack_inflate(p, &w_curs, offset, datalen, entry_size)) {
+		error(_("corrupt packed object for %s"),
+		      oid_to_hex(&entry->idx.oid));
+		unuse_pack(&w_curs);
+		return write_no_reuse_object(f, entry, limit, usable_delta);
+	}
+
+	if (type == OBJ_OFS_DELTA) {
+		off_t ofs = entry->idx.offset - DELTA(entry)->idx.offset;
+		unsigned pos = sizeof(dheader) - 1;
+		dheader[pos] = ofs & 127;
+		while (ofs >>= 7)
+			dheader[--pos] = 128 | (--ofs & 127);
+		if (limit && hdrlen + sizeof(dheader) - pos + datalen + hashsz >= limit) {
+			unuse_pack(&w_curs);
+			return 0;
+		}
+		hashwrite(f, header, hdrlen);
+		hashwrite(f, dheader + pos, sizeof(dheader) - pos);
+		hdrlen += sizeof(dheader) - pos;
+		reused_delta++;
+	} else if (type == OBJ_REF_DELTA) {
+		if (limit && hdrlen + hashsz + datalen + hashsz >= limit) {
+			unuse_pack(&w_curs);
+			return 0;
+		}
+		hashwrite(f, header, hdrlen);
+		hashwrite(f, DELTA(entry)->idx.oid.hash, hashsz);
+		hdrlen += hashsz;
+		reused_delta++;
+	} else {
+		if (limit && hdrlen + datalen + hashsz >= limit) {
+			unuse_pack(&w_curs);
+			return 0;
+		}
+		hashwrite(f, header, hdrlen);
+	}
+	copy_pack_data(f, p, &w_curs, offset, datalen);
+	unuse_pack(&w_curs);
+	reused++;
+	return hdrlen + datalen;
+}
+
+/* Return 0 if we will bust the pack-size limit */
+static off_t write_object(struct hashfile *f,
+			  struct object_entry *entry,
+			  off_t write_offset)
+{
+	unsigned long limit;
+	off_t len;
+	int usable_delta, to_reuse;
+
+	if (!pack_to_stdout)
+		crc32_begin(f);
+
+	/* apply size limit if limited packsize and not first object */
+	if (!pack_size_limit || !nr_written)
+		limit = 0;
+	else if (pack_size_limit <= write_offset)
+		/*
+		 * the earlier object did not fit the limit; avoid
+		 * mistaking this with unlimited (i.e. limit = 0).
+		 */
+		limit = 1;
+	else
+		limit = pack_size_limit - write_offset;
+
+	if (!DELTA(entry))
+		usable_delta = 0;	/* no delta */
+	else if (!pack_size_limit)
+	       usable_delta = 1;	/* unlimited packfile */
+	else if (DELTA(entry)->idx.offset == (off_t)-1)
+		usable_delta = 0;	/* base was written to another pack */
+	else if (DELTA(entry)->idx.offset)
+		usable_delta = 1;	/* base already exists in this pack */
+	else
+		usable_delta = 0;	/* base could end up in another pack */
+
+	if (!reuse_object)
+		to_reuse = 0;	/* explicit */
+	else if (!IN_PACK(entry))
+		to_reuse = 0;	/* can't reuse what we don't have */
+	else if (oe_type(entry) == OBJ_REF_DELTA ||
+		 oe_type(entry) == OBJ_OFS_DELTA)
+				/* check_object() decided it for us ... */
+		to_reuse = usable_delta;
+				/* ... but pack split may override that */
+	else if (oe_type(entry) != entry->in_pack_type)
+		to_reuse = 0;	/* pack has delta which is unusable */
+	else if (DELTA(entry))
+		to_reuse = 0;	/* we want to pack afresh */
+	else
+		to_reuse = 1;	/* we have it in-pack undeltified,
+				 * and we do not need to deltify it.
+				 */
+
+	if (!to_reuse)
+		len = write_no_reuse_object(f, entry, limit, usable_delta);
+	else
+		len = write_reuse_object(f, entry, limit, usable_delta);
+	if (!len)
+		return 0;
+
+	if (usable_delta)
+		written_delta++;
+	written++;
+	if (!pack_to_stdout)
+		entry->idx.crc32 = crc32_end(f);
+	return len;
+}
+
+enum write_one_status {
+	WRITE_ONE_SKIP = -1, /* already written */
+	WRITE_ONE_BREAK = 0, /* writing this will bust the limit; not written */
+	WRITE_ONE_WRITTEN = 1, /* normal */
+	WRITE_ONE_RECURSIVE = 2 /* already scheduled to be written */
+};
+
+static enum write_one_status write_one(struct hashfile *f,
+				       struct object_entry *e,
+				       off_t *offset)
+{
+	off_t size;
+	int recursing;
+
+	/*
+	 * we set offset to 1 (which is an impossible value) to mark
+	 * the fact that this object is involved in "write its base
+	 * first before writing a deltified object" recursion.
+	 */
+	recursing = (e->idx.offset == 1);
+	if (recursing) {
+		warning(_("recursive delta detected for object %s"),
+			oid_to_hex(&e->idx.oid));
+		return WRITE_ONE_RECURSIVE;
+	} else if (e->idx.offset || e->preferred_base) {
+		/* offset is non zero if object is written already. */
+		return WRITE_ONE_SKIP;
+	}
+
+	/* if we are deltified, write out base object first. */
+	if (DELTA(e)) {
+		e->idx.offset = 1; /* now recurse */
+		switch (write_one(f, DELTA(e), offset)) {
+		case WRITE_ONE_RECURSIVE:
+			/* we cannot depend on this one */
+			SET_DELTA(e, NULL);
+			break;
+		default:
+			break;
+		case WRITE_ONE_BREAK:
+			e->idx.offset = recursing;
+			return WRITE_ONE_BREAK;
+		}
+	}
+
+	e->idx.offset = *offset;
+	size = write_object(f, e, *offset);
+	if (!size) {
+		e->idx.offset = recursing;
+		return WRITE_ONE_BREAK;
+	}
+	written_list[nr_written++] = &e->idx;
+
+	/* make sure off_t is sufficiently large not to wrap */
+	if (signed_add_overflows(*offset, size))
+		die(_("pack too large for current definition of off_t"));
+	*offset += size;
+	return WRITE_ONE_WRITTEN;
+}
+
+static int mark_tagged(const char *path UNUSED, const char *referent UNUSED, const struct object_id *oid,
+		       int flag UNUSED, void *cb_data UNUSED)
+{
+	struct object_id peeled;
+	struct object_entry *entry = packlist_find(&to_pack, oid);
+
+	if (entry)
+		entry->tagged = 1;
+	if (!peel_iterated_oid(the_repository, oid, &peeled)) {
+		entry = packlist_find(&to_pack, &peeled);
+		if (entry)
+			entry->tagged = 1;
+	}
+	return 0;
+}
+
+static inline unsigned char oe_layer(struct packing_data *pack,
+				     struct object_entry *e)
+{
+	if (!pack->layer)
+		return 0;
+	return pack->layer[e - pack->objects];
+}
+
+static inline void add_to_write_order(struct object_entry **wo,
+			       unsigned int *endp,
+			       struct object_entry *e)
+{
+	if (e->filled || oe_layer(&to_pack, e) != write_layer)
+		return;
+	wo[(*endp)++] = e;
+	e->filled = 1;
+}
+
+static void add_descendants_to_write_order(struct object_entry **wo,
+					   unsigned int *endp,
+					   struct object_entry *e)
+{
+	int add_to_order = 1;
+	while (e) {
+		if (add_to_order) {
+			struct object_entry *s;
+			/* add this node... */
+			add_to_write_order(wo, endp, e);
+			/* all its siblings... */
+			for (s = DELTA_SIBLING(e); s; s = DELTA_SIBLING(s)) {
+				add_to_write_order(wo, endp, s);
+			}
+		}
+		/* drop down a level to add left subtree nodes if possible */
+		if (DELTA_CHILD(e)) {
+			add_to_order = 1;
+			e = DELTA_CHILD(e);
+		} else {
+			add_to_order = 0;
+			/* our sibling might have some children, it is next */
+			if (DELTA_SIBLING(e)) {
+				e = DELTA_SIBLING(e);
+				continue;
+			}
+			/* go back to our parent node */
+			e = DELTA(e);
+			while (e && !DELTA_SIBLING(e)) {
+				/* we're on the right side of a subtree, keep
+				 * going up until we can go right again */
+				e = DELTA(e);
+			}
+			if (!e) {
+				/* done- we hit our original root node */
+				return;
+			}
+			/* pass it off to sibling at this level */
+			e = DELTA_SIBLING(e);
+		}
+	};
+}
+
+static void add_family_to_write_order(struct object_entry **wo,
+				      unsigned int *endp,
+				      struct object_entry *e)
+{
+	struct object_entry *root;
+
+	for (root = e; DELTA(root); root = DELTA(root))
+		; /* nothing */
+	add_descendants_to_write_order(wo, endp, root);
+}
+
+static void compute_layer_order(struct object_entry **wo, unsigned int *wo_end)
+{
+	unsigned int i, last_untagged;
+	struct object_entry *objects = to_pack.objects;
+
+	for (i = 0; i < to_pack.nr_objects; i++) {
+		if (objects[i].tagged)
+			break;
+		add_to_write_order(wo, wo_end, &objects[i]);
+	}
+	last_untagged = i;
+
+	/*
+	 * Then fill all the tagged tips.
+	 */
+	for (; i < to_pack.nr_objects; i++) {
+		if (objects[i].tagged)
+			add_to_write_order(wo, wo_end, &objects[i]);
+	}
+
+	/*
+	 * And then all remaining commits and tags.
+	 */
+	for (i = last_untagged; i < to_pack.nr_objects; i++) {
+		if (oe_type(&objects[i]) != OBJ_COMMIT &&
+		    oe_type(&objects[i]) != OBJ_TAG)
+			continue;
+		add_to_write_order(wo, wo_end, &objects[i]);
+	}
+
+	/*
+	 * And then all the trees.
+	 */
+	for (i = last_untagged; i < to_pack.nr_objects; i++) {
+		if (oe_type(&objects[i]) != OBJ_TREE)
+			continue;
+		add_to_write_order(wo, wo_end, &objects[i]);
+	}
+
+	/*
+	 * Finally all the rest in really tight order
+	 */
+	for (i = last_untagged; i < to_pack.nr_objects; i++) {
+		if (!objects[i].filled && oe_layer(&to_pack, &objects[i]) == write_layer)
+			add_family_to_write_order(wo, wo_end, &objects[i]);
+	}
+}
+
+static struct object_entry **compute_write_order(void)
+{
+	uint32_t max_layers = 1;
+	unsigned int i, wo_end;
+
+	struct object_entry **wo;
+	struct object_entry *objects = to_pack.objects;
+
+	for (i = 0; i < to_pack.nr_objects; i++) {
+		objects[i].tagged = 0;
+		objects[i].filled = 0;
+		SET_DELTA_CHILD(&objects[i], NULL);
+		SET_DELTA_SIBLING(&objects[i], NULL);
+	}
+
+	/*
+	 * Fully connect delta_child/delta_sibling network.
+	 * Make sure delta_sibling is sorted in the original
+	 * recency order.
+	 */
+	for (i = to_pack.nr_objects; i > 0;) {
+		struct object_entry *e = &objects[--i];
+		if (!DELTA(e))
+			continue;
+		/* Mark me as the first child */
+		e->delta_sibling_idx = DELTA(e)->delta_child_idx;
+		SET_DELTA_CHILD(DELTA(e), e);
+	}
+
+	/*
+	 * Mark objects that are at the tip of tags.
+	 */
+	refs_for_each_tag_ref(get_main_ref_store(the_repository), mark_tagged,
+			      NULL);
+
+	if (use_delta_islands) {
+		max_layers = compute_pack_layers(&to_pack);
+		free_island_marks();
+	}
+
+	ALLOC_ARRAY(wo, to_pack.nr_objects);
+	wo_end = 0;
+
+	for (; write_layer < max_layers; ++write_layer)
+		compute_layer_order(wo, &wo_end);
+
+	if (wo_end != to_pack.nr_objects)
+		die(_("ordered %u objects, expected %"PRIu32),
+		    wo_end, to_pack.nr_objects);
+
+	return wo;
+}
+
+
+/*
+ * A reused set of objects. All objects in a chunk have the same
+ * relative position in the original packfile and the generated
+ * packfile.
+ */
+
+static struct reused_chunk {
+	/* The offset of the first object of this chunk in the original
+	 * packfile. */
+	off_t original;
+	/* The difference for "original" minus the offset of the first object of
+	 * this chunk in the generated packfile. */
+	off_t difference;
+} *reused_chunks;
+static int reused_chunks_nr;
+static int reused_chunks_alloc;
+
+static void record_reused_object(off_t where, off_t offset)
+{
+	if (reused_chunks_nr && reused_chunks[reused_chunks_nr-1].difference == offset)
+		return;
+
+	ALLOC_GROW(reused_chunks, reused_chunks_nr + 1,
+		   reused_chunks_alloc);
+	reused_chunks[reused_chunks_nr].original = where;
+	reused_chunks[reused_chunks_nr].difference = offset;
+	reused_chunks_nr++;
+}
+
+/*
+ * Binary search to find the chunk that "where" is in. Note
+ * that we're not looking for an exact match, just the first
+ * chunk that contains it (which implicitly ends at the start
+ * of the next chunk.
+ */
+static off_t find_reused_offset(off_t where)
+{
+	int lo = 0, hi = reused_chunks_nr;
+	while (lo < hi) {
+		int mi = lo + ((hi - lo) / 2);
+		if (where == reused_chunks[mi].original)
+			return reused_chunks[mi].difference;
+		if (where < reused_chunks[mi].original)
+			hi = mi;
+		else
+			lo = mi + 1;
+	}
+
+	/*
+	 * The first chunk starts at zero, so we can't have gone below
+	 * there.
+	 */
+	assert(lo);
+	return reused_chunks[lo-1].difference;
+}
+
+static void write_reused_pack_one(struct packed_git *reuse_packfile,
+				  size_t pos, struct hashfile *out,
+				  off_t pack_start,
+				  struct pack_window **w_curs)
+{
+	off_t offset, next, cur;
+	enum object_type type;
+	unsigned long size;
+
+	offset = pack_pos_to_offset(reuse_packfile, pos);
+	next = pack_pos_to_offset(reuse_packfile, pos + 1);
+
+	record_reused_object(offset,
+			     offset - (hashfile_total(out) - pack_start));
+
+	cur = offset;
+	type = unpack_object_header(reuse_packfile, w_curs, &cur, &size);
+	assert(type >= 0);
+
+	if (type == OBJ_OFS_DELTA) {
+		off_t base_offset;
+		off_t fixup;
+
+		unsigned char header[MAX_PACK_OBJECT_HEADER];
+		unsigned len;
+
+		base_offset = get_delta_base(reuse_packfile, w_curs, &cur, type, offset);
+		assert(base_offset != 0);
+
+		/* Convert to REF_DELTA if we must... */
+		if (!allow_ofs_delta) {
+			uint32_t base_pos;
+			struct object_id base_oid;
+
+			if (offset_to_pack_pos(reuse_packfile, base_offset, &base_pos) < 0)
+				die(_("expected object at offset %"PRIuMAX" "
+				      "in pack %s"),
+				    (uintmax_t)base_offset,
+				    reuse_packfile->pack_name);
+
+			nth_packed_object_id(&base_oid, reuse_packfile,
+					     pack_pos_to_index(reuse_packfile, base_pos));
+
+			len = encode_in_pack_object_header(header, sizeof(header),
+							   OBJ_REF_DELTA, size);
+			hashwrite(out, header, len);
+			hashwrite(out, base_oid.hash, the_hash_algo->rawsz);
+			copy_pack_data(out, reuse_packfile, w_curs, cur, next - cur);
+			return;
+		}
+
+		/* Otherwise see if we need to rewrite the offset... */
+		fixup = find_reused_offset(offset) -
+			find_reused_offset(base_offset);
+		if (fixup) {
+			unsigned char ofs_header[MAX_PACK_OBJECT_HEADER];
+			unsigned i, ofs_len;
+			off_t ofs = offset - base_offset - fixup;
+
+			len = encode_in_pack_object_header(header, sizeof(header),
+							   OBJ_OFS_DELTA, size);
+
+			i = sizeof(ofs_header) - 1;
+			ofs_header[i] = ofs & 127;
+			while (ofs >>= 7)
+				ofs_header[--i] = 128 | (--ofs & 127);
+
+			ofs_len = sizeof(ofs_header) - i;
+
+			hashwrite(out, header, len);
+			hashwrite(out, ofs_header + sizeof(ofs_header) - ofs_len, ofs_len);
+			copy_pack_data(out, reuse_packfile, w_curs, cur, next - cur);
+			return;
+		}
+
+		/* ...otherwise we have no fixup, and can write it verbatim */
+	}
+
+	copy_pack_data(out, reuse_packfile, w_curs, offset, next - offset);
+}
+
+static size_t write_reused_pack_verbatim(struct bitmapped_pack *reuse_packfile,
+					 struct hashfile *out,
+					 struct pack_window **w_curs)
+{
+	size_t pos = 0;
+	size_t end;
+
+	if (reuse_packfile->bitmap_pos) {
+		/*
+		 * We can't reuse whole chunks verbatim out of
+		 * non-preferred packs since we can't guarantee that
+		 * all duplicate objects were resolved in favor of
+		 * that pack.
+		 *
+		 * Even if we have a whole eword_t worth of bits that
+		 * could be reused, there may be objects between the
+		 * objects corresponding to the first and last bit of
+		 * that word which were selected from a different
+		 * pack, causing us to send duplicate or unwanted
+		 * objects.
+		 *
+		 * Handle non-preferred packs from within
+		 * write_reused_pack(), which inspects and reuses
+		 * individual bits.
+		 */
+		return reuse_packfile->bitmap_pos / BITS_IN_EWORD;
+	}
+
+	/*
+	 * Only read through the last word whose bits all correspond
+	 * to objects in the given packfile, since we must stop at a
+	 * word boundary.
+	 *
+	 * If there is no whole word to read (i.e. the packfile
+	 * contains fewer than BITS_IN_EWORD objects), then we'll
+	 * inspect bits one-by-one in write_reused_pack().
+	 */
+	end = reuse_packfile->bitmap_nr / BITS_IN_EWORD;
+	if (reuse_packfile_bitmap->word_alloc < end)
+		BUG("fewer words than expected in reuse_packfile_bitmap");
+
+	while (pos < end && reuse_packfile_bitmap->words[pos] == (eword_t)~0)
+		pos++;
+
+	if (pos) {
+		off_t to_write;
+
+		written = (pos * BITS_IN_EWORD);
+		to_write = pack_pos_to_offset(reuse_packfile->p, written)
+			- sizeof(struct pack_header);
+
+		/* We're recording one chunk, not one object. */
+		record_reused_object(sizeof(struct pack_header), 0);
+		hashflush(out);
+		copy_pack_data(out, reuse_packfile->p, w_curs,
+			sizeof(struct pack_header), to_write);
+
+		display_progress(progress_state, written);
+	}
+	return pos;
+}
+
+static void write_reused_pack(struct bitmapped_pack *reuse_packfile,
+			      struct hashfile *f)
+{
+	size_t i = reuse_packfile->bitmap_pos / BITS_IN_EWORD;
+	uint32_t offset;
+	off_t pack_start = hashfile_total(f) - sizeof(struct pack_header);
+	struct pack_window *w_curs = NULL;
+
+	if (allow_ofs_delta)
+		i = write_reused_pack_verbatim(reuse_packfile, f, &w_curs);
+
+	for (; i < reuse_packfile_bitmap->word_alloc; ++i) {
+		eword_t word = reuse_packfile_bitmap->words[i];
+		size_t pos = (i * BITS_IN_EWORD);
+
+		for (offset = 0; offset < BITS_IN_EWORD; ++offset) {
+			uint32_t pack_pos;
+			if ((word >> offset) == 0)
+				break;
+
+			offset += ewah_bit_ctz64(word >> offset);
+			if (pos + offset < reuse_packfile->bitmap_pos)
+				continue;
+			if (pos + offset >= reuse_packfile->bitmap_pos + reuse_packfile->bitmap_nr)
+				goto done;
+
+			if (reuse_packfile->bitmap_pos) {
+				/*
+				 * When doing multi-pack reuse on a
+				 * non-preferred pack, translate bit positions
+				 * from the MIDX pseudo-pack order back to their
+				 * pack-relative positions before attempting
+				 * reuse.
+				 */
+				struct multi_pack_index *m = reuse_packfile->from_midx;
+				uint32_t midx_pos;
+				off_t pack_ofs;
+
+				if (!m)
+					BUG("non-zero bitmap position without MIDX");
+
+				midx_pos = pack_pos_to_midx(m, pos + offset);
+				pack_ofs = nth_midxed_offset(m, midx_pos);
+
+				if (offset_to_pack_pos(reuse_packfile->p,
+						       pack_ofs, &pack_pos) < 0)
+					BUG("could not find expected object at offset %"PRIuMAX" in pack %s",
+					    (uintmax_t)pack_ofs,
+					    pack_basename(reuse_packfile->p));
+			} else {
+				/*
+				 * Can use bit positions directly, even for MIDX
+				 * bitmaps. See comment in try_partial_reuse()
+				 * for why.
+				 */
+				pack_pos = pos + offset;
+			}
+
+			write_reused_pack_one(reuse_packfile->p, pack_pos, f,
+					      pack_start, &w_curs);
+			display_progress(progress_state, ++written);
+		}
+	}
+
+done:
+	unuse_pack(&w_curs);
+}
+
+static void write_excluded_by_configs(void)
+{
+	struct oidset_iter iter;
+	const struct object_id *oid;
+
+	oidset_iter_init(&excluded_by_config, &iter);
+	while ((oid = oidset_iter_next(&iter))) {
+		struct configured_exclusion *ex =
+			oidmap_get(&configured_exclusions, oid);
+
+		if (!ex)
+			BUG("configured exclusion wasn't configured");
+		write_in_full(1, ex->pack_hash_hex, strlen(ex->pack_hash_hex));
+		write_in_full(1, " ", 1);
+		write_in_full(1, ex->uri, strlen(ex->uri));
+		write_in_full(1, "\n", 1);
+	}
+}
+
+static const char no_split_warning[] = N_(
+"disabling bitmap writing, packs are split due to pack.packSizeLimit"
+);
+
+static void write_pack_file(void)
+{
+	uint32_t i = 0, j;
+	struct hashfile *f;
+	off_t offset;
+	uint32_t nr_remaining = nr_result;
+	time_t last_mtime = 0;
+	struct object_entry **write_order;
+
+	if (progress > pack_to_stdout)
+		progress_state = start_progress(the_repository,
+						_("Writing objects"), nr_result);
+	ALLOC_ARRAY(written_list, to_pack.nr_objects);
+	write_order = compute_write_order();
+
+	do {
+		unsigned char hash[GIT_MAX_RAWSZ];
+		char *pack_tmp_name = NULL;
+
+		if (pack_to_stdout)
+			f = hashfd_throughput(1, "<stdout>", progress_state);
+		else
+			f = create_tmp_packfile(&pack_tmp_name);
+
+		offset = write_pack_header(f, nr_remaining);
+
+		if (reuse_packfiles_nr) {
+			assert(pack_to_stdout);
+			for (j = 0; j < reuse_packfiles_nr; j++) {
+				reused_chunks_nr = 0;
+				write_reused_pack(&reuse_packfiles[j], f);
+				if (reused_chunks_nr)
+					reuse_packfiles_used_nr++;
+			}
+			offset = hashfile_total(f);
+		}
+
+		nr_written = 0;
+		for (; i < to_pack.nr_objects; i++) {
+			struct object_entry *e = write_order[i];
+			if (write_one(f, e, &offset) == WRITE_ONE_BREAK)
+				break;
+			display_progress(progress_state, written);
+		}
+
+		if (pack_to_stdout) {
+			/*
+			 * We never fsync when writing to stdout since we may
+			 * not be writing to an actual pack file. For instance,
+			 * the upload-pack code passes a pipe here. Calling
+			 * fsync on a pipe results in unnecessary
+			 * synchronization with the reader on some platforms.
+			 */
+			finalize_hashfile(f, hash, FSYNC_COMPONENT_NONE,
+					  CSUM_HASH_IN_STREAM | CSUM_CLOSE);
+		} else if (nr_written == nr_remaining) {
+			finalize_hashfile(f, hash, FSYNC_COMPONENT_PACK,
+					  CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
+		} else {
+			/*
+			 * If we wrote the wrong number of entries in the
+			 * header, rewrite it like in fast-import.
+			 */
+
+			int fd = finalize_hashfile(f, hash, FSYNC_COMPONENT_PACK, 0);
+			fixup_pack_header_footer(fd, hash, pack_tmp_name,
+						 nr_written, hash, offset);
+			close(fd);
+			if (write_bitmap_index) {
+				if (write_bitmap_index != WRITE_BITMAP_QUIET)
+					warning(_(no_split_warning));
+				write_bitmap_index = 0;
+			}
+		}
+
+		if (!pack_to_stdout) {
+			struct stat st;
+			struct strbuf tmpname = STRBUF_INIT;
+			struct bitmap_writer bitmap_writer;
+			char *idx_tmp_name = NULL;
+
+			/*
+			 * Packs are runtime accessed in their mtime
+			 * order since newer packs are more likely to contain
+			 * younger objects.  So if we are creating multiple
+			 * packs then we should modify the mtime of later ones
+			 * to preserve this property.
+			 */
+			if (stat(pack_tmp_name, &st) < 0) {
+				warning_errno(_("failed to stat %s"), pack_tmp_name);
+			} else if (!last_mtime) {
+				last_mtime = st.st_mtime;
+			} else {
+				struct utimbuf utb;
+				utb.actime = st.st_atime;
+				utb.modtime = --last_mtime;
+				if (utime(pack_tmp_name, &utb) < 0)
+					warning_errno(_("failed utime() on %s"), pack_tmp_name);
+			}
+
+			strbuf_addf(&tmpname, "%s-%s.", base_name,
+				    hash_to_hex(hash));
+
+			if (write_bitmap_index) {
+				bitmap_writer_init(&bitmap_writer,
+						   the_repository, &to_pack);
+				bitmap_writer_set_checksum(&bitmap_writer, hash);
+				bitmap_writer_build_type_index(&bitmap_writer,
+							       written_list);
+			}
+
+			if (cruft)
+				pack_idx_opts.flags |= WRITE_MTIMES;
+
+			stage_tmp_packfiles(&tmpname, pack_tmp_name,
+					    written_list, nr_written,
+					    &to_pack, &pack_idx_opts, hash,
+					    &idx_tmp_name);
+
+			if (write_bitmap_index) {
+				size_t tmpname_len = tmpname.len;
+
+				strbuf_addstr(&tmpname, "bitmap");
+				stop_progress(&progress_state);
+
+				bitmap_writer_show_progress(&bitmap_writer,
+							    progress);
+				bitmap_writer_select_commits(&bitmap_writer,
+							     indexed_commits,
+							     indexed_commits_nr);
+				if (bitmap_writer_build(&bitmap_writer) < 0)
+					die(_("failed to write bitmap index"));
+				bitmap_writer_finish(&bitmap_writer,
+						     written_list,
+						     tmpname.buf, write_bitmap_options);
+				bitmap_writer_free(&bitmap_writer);
+				write_bitmap_index = 0;
+				strbuf_setlen(&tmpname, tmpname_len);
+			}
+
+			rename_tmp_packfile_idx(&tmpname, &idx_tmp_name);
+
+			free(idx_tmp_name);
+			strbuf_release(&tmpname);
+			free(pack_tmp_name);
+			puts(hash_to_hex(hash));
+		}
+
+		/* mark written objects as written to previous pack */
+		for (j = 0; j < nr_written; j++) {
+			written_list[j]->offset = (off_t)-1;
+		}
+		nr_remaining -= nr_written;
+	} while (nr_remaining && i < to_pack.nr_objects);
+
+	free(written_list);
+	free(write_order);
+	stop_progress(&progress_state);
+	if (written != nr_result)
+		die(_("wrote %"PRIu32" objects while expecting %"PRIu32),
+		    written, nr_result);
+	trace2_data_intmax("pack-objects", the_repository,
+			   "write_pack_file/wrote", nr_result);
+}
+
+static int no_try_delta(const char *path)
+{
+	static struct attr_check *check;
+
+	if (!check)
+		check = attr_check_initl("delta", NULL);
+	git_check_attr(the_repository->index, path, check);
+	if (ATTR_FALSE(check->items[0].value))
+		return 1;
+	return 0;
+}
+
+/*
+ * When adding an object, check whether we have already added it
+ * to our packing list. If so, we can skip. However, if we are
+ * being asked to excludei t, but the previous mention was to include
+ * it, make sure to adjust its flags and tweak our numbers accordingly.
+ *
+ * As an optimization, we pass out the index position where we would have
+ * found the item, since that saves us from having to look it up again a
+ * few lines later when we want to add the new entry.
+ */
+static int have_duplicate_entry(const struct object_id *oid,
+				int exclude)
+{
+	struct object_entry *entry;
+
+	if (reuse_packfile_bitmap &&
+	    bitmap_walk_contains(bitmap_git, reuse_packfile_bitmap, oid))
+		return 1;
+
+	entry = packlist_find(&to_pack, oid);
+	if (!entry)
+		return 0;
+
+	if (exclude) {
+		if (!entry->preferred_base)
+			nr_result--;
+		entry->preferred_base = 1;
+	}
+
+	return 1;
+}
+
+static int want_found_object(const struct object_id *oid, int exclude,
+			     struct packed_git *p)
+{
+	if (exclude)
+		return 1;
+	if (incremental)
+		return 0;
+
+	if (!is_pack_valid(p))
+		return -1;
+
+	/*
+	 * When asked to do --local (do not include an object that appears in a
+	 * pack we borrow from elsewhere) or --honor-pack-keep (do not include
+	 * an object that appears in a pack marked with .keep), finding a pack
+	 * that matches the criteria is sufficient for us to decide to omit it.
+	 * However, even if this pack does not satisfy the criteria, we need to
+	 * make sure no copy of this object appears in _any_ pack that makes us
+	 * to omit the object, so we need to check all the packs.
+	 *
+	 * We can however first check whether these options can possibly matter;
+	 * if they do not matter we know we want the object in generated pack.
+	 * Otherwise, we signal "-1" at the end to tell the caller that we do
+	 * not know either way, and it needs to check more packs.
+	 */
+
+	/*
+	 * Objects in packs borrowed from elsewhere are discarded regardless of
+	 * if they appear in other packs that weren't borrowed.
+	 */
+	if (local && !p->pack_local)
+		return 0;
+
+	/*
+	 * Then handle .keep first, as we have a fast(er) path there.
+	 */
+	if (ignore_packed_keep_on_disk || ignore_packed_keep_in_core) {
+		/*
+		 * Set the flags for the kept-pack cache to be the ones we want
+		 * to ignore.
+		 *
+		 * That is, if we are ignoring objects in on-disk keep packs,
+		 * then we want to search through the on-disk keep and ignore
+		 * the in-core ones.
+		 */
+		unsigned flags = 0;
+		if (ignore_packed_keep_on_disk)
+			flags |= ON_DISK_KEEP_PACKS;
+		if (ignore_packed_keep_in_core)
+			flags |= IN_CORE_KEEP_PACKS;
+
+		if (ignore_packed_keep_on_disk && p->pack_keep)
+			return 0;
+		if (ignore_packed_keep_in_core && p->pack_keep_in_core)
+			return 0;
+		if (has_object_kept_pack(p->repo, oid, flags))
+			return 0;
+	}
+
+	/*
+	 * At this point we know definitively that either we don't care about
+	 * keep-packs, or the object is not in one. Keep checking other
+	 * conditions...
+	 */
+	if (!local || !have_non_local_packs)
+		return 1;
+
+	/* we don't know yet; keep looking for more packs */
+	return -1;
+}
+
+static int want_object_in_pack_one(struct packed_git *p,
+				   const struct object_id *oid,
+				   int exclude,
+				   struct packed_git **found_pack,
+				   off_t *found_offset)
+{
+	off_t offset;
+
+	if (p == *found_pack)
+		offset = *found_offset;
+	else
+		offset = find_pack_entry_one(oid, p);
+
+	if (offset) {
+		if (!*found_pack) {
+			if (!is_pack_valid(p))
+				return -1;
+			*found_offset = offset;
+			*found_pack = p;
+		}
+		return want_found_object(oid, exclude, p);
+	}
+	return -1;
+}
+
+/*
+ * Check whether we want the object in the pack (e.g., we do not want
+ * objects found in non-local stores if the "--local" option was used).
+ *
+ * If the caller already knows an existing pack it wants to take the object
+ * from, that is passed in *found_pack and *found_offset; otherwise this
+ * function finds if there is any pack that has the object and returns the pack
+ * and its offset in these variables.
+ */
+static int want_object_in_pack(const struct object_id *oid,
+			       int exclude,
+			       struct packed_git **found_pack,
+			       off_t *found_offset)
+{
+	int want;
+	struct list_head *pos;
+	struct multi_pack_index *m;
+
+	if (!exclude && local && has_loose_object_nonlocal(oid))
+		return 0;
+
+	/*
+	 * If we already know the pack object lives in, start checks from that
+	 * pack - in the usual case when neither --local was given nor .keep files
+	 * are present we will determine the answer right now.
+	 */
+	if (*found_pack) {
+		want = want_found_object(oid, exclude, *found_pack);
+		if (want != -1)
+			return want;
+
+		*found_pack = NULL;
+		*found_offset = 0;
+	}
+
+	for (m = get_multi_pack_index(the_repository); m; m = m->next) {
+		struct pack_entry e;
+		if (fill_midx_entry(the_repository, oid, &e, m)) {
+			want = want_object_in_pack_one(e.p, oid, exclude, found_pack, found_offset);
+			if (want != -1)
+				return want;
+		}
+	}
+
+	list_for_each(pos, get_packed_git_mru(the_repository)) {
+		struct packed_git *p = list_entry(pos, struct packed_git, mru);
+		want = want_object_in_pack_one(p, oid, exclude, found_pack, found_offset);
+		if (!exclude && want > 0)
+			list_move(&p->mru,
+				  get_packed_git_mru(the_repository));
+		if (want != -1)
+			return want;
+	}
+
+	if (uri_protocols.nr) {
+		struct configured_exclusion *ex =
+			oidmap_get(&configured_exclusions, oid);
+		int i;
+		const char *p;
+
+		if (ex) {
+			for (i = 0; i < uri_protocols.nr; i++) {
+				if (skip_prefix(ex->uri,
+						uri_protocols.items[i].string,
+						&p) &&
+				    *p == ':') {
+					oidset_insert(&excluded_by_config, oid);
+					return 0;
+				}
+			}
+		}
+	}
+
+	return 1;
+}
+
+static struct object_entry *create_object_entry(const struct object_id *oid,
+						enum object_type type,
+						uint32_t hash,
+						int exclude,
+						int no_try_delta,
+						struct packed_git *found_pack,
+						off_t found_offset)
+{
+	struct object_entry *entry;
+
+	entry = packlist_alloc(&to_pack, oid);
+	entry->hash = hash;
+	oe_set_type(entry, type);
+	if (exclude)
+		entry->preferred_base = 1;
+	else
+		nr_result++;
+	if (found_pack) {
+		oe_set_in_pack(&to_pack, entry, found_pack);
+		entry->in_pack_offset = found_offset;
+	}
+
+	entry->no_try_delta = no_try_delta;
+
+	return entry;
+}
+
+static const char no_closure_warning[] = N_(
+"disabling bitmap writing, as some objects are not being packed"
+);
+
+static int add_object_entry(const struct object_id *oid, enum object_type type,
+			    const char *name, int exclude)
+{
+	struct packed_git *found_pack = NULL;
+	off_t found_offset = 0;
+
+	display_progress(progress_state, ++nr_seen);
+
+	if (have_duplicate_entry(oid, exclude))
+		return 0;
+
+	if (!want_object_in_pack(oid, exclude, &found_pack, &found_offset)) {
+		/* The pack is missing an object, so it will not have closure */
+		if (write_bitmap_index) {
+			if (write_bitmap_index != WRITE_BITMAP_QUIET)
+				warning(_(no_closure_warning));
+			write_bitmap_index = 0;
+		}
+		return 0;
+	}
+
+	create_object_entry(oid, type, pack_name_hash(name),
+			    exclude, name && no_try_delta(name),
+			    found_pack, found_offset);
+	return 1;
+}
+
+static int add_object_entry_from_bitmap(const struct object_id *oid,
+					enum object_type type,
+					int flags UNUSED, uint32_t name_hash,
+					struct packed_git *pack, off_t offset)
+{
+	display_progress(progress_state, ++nr_seen);
+
+	if (have_duplicate_entry(oid, 0))
+		return 0;
+
+	if (!want_object_in_pack(oid, 0, &pack, &offset))
+		return 0;
+
+	create_object_entry(oid, type, name_hash, 0, 0, pack, offset);
+	return 1;
+}
+
+struct pbase_tree_cache {
+	struct object_id oid;
+	int ref;
+	int temporary;
+	void *tree_data;
+	unsigned long tree_size;
+};
+
+static struct pbase_tree_cache *(pbase_tree_cache[256]);
+static int pbase_tree_cache_ix(const struct object_id *oid)
+{
+	return oid->hash[0] % ARRAY_SIZE(pbase_tree_cache);
+}
+static int pbase_tree_cache_ix_incr(int ix)
+{
+	return (ix+1) % ARRAY_SIZE(pbase_tree_cache);
+}
+
+static struct pbase_tree {
+	struct pbase_tree *next;
+	/* This is a phony "cache" entry; we are not
+	 * going to evict it or find it through _get()
+	 * mechanism -- this is for the toplevel node that
+	 * would almost always change with any commit.
+	 */
+	struct pbase_tree_cache pcache;
+} *pbase_tree;
+
+static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
+{
+	struct pbase_tree_cache *ent, *nent;
+	void *data;
+	unsigned long size;
+	enum object_type type;
+	int neigh;
+	int my_ix = pbase_tree_cache_ix(oid);
+	int available_ix = -1;
+
+	/* pbase-tree-cache acts as a limited hashtable.
+	 * your object will be found at your index or within a few
+	 * slots after that slot if it is cached.
+	 */
+	for (neigh = 0; neigh < 8; neigh++) {
+		ent = pbase_tree_cache[my_ix];
+		if (ent && oideq(&ent->oid, oid)) {
+			ent->ref++;
+			return ent;
+		}
+		else if (((available_ix < 0) && (!ent || !ent->ref)) ||
+			 ((0 <= available_ix) &&
+			  (!ent && pbase_tree_cache[available_ix])))
+			available_ix = my_ix;
+		if (!ent)
+			break;
+		my_ix = pbase_tree_cache_ix_incr(my_ix);
+	}
+
+	/* Did not find one.  Either we got a bogus request or
+	 * we need to read and perhaps cache.
+	 */
+	data = repo_read_object_file(the_repository, oid, &type, &size);
+	if (!data)
+		return NULL;
+	if (type != OBJ_TREE) {
+		free(data);
+		return NULL;
+	}
+
+	/* We need to either cache or return a throwaway copy */
+
+	if (available_ix < 0)
+		ent = NULL;
+	else {
+		ent = pbase_tree_cache[available_ix];
+		my_ix = available_ix;
+	}
+
+	if (!ent) {
+		nent = xmalloc(sizeof(*nent));
+		nent->temporary = (available_ix < 0);
+	}
+	else {
+		/* evict and reuse */
+		free(ent->tree_data);
+		nent = ent;
+	}
+	oidcpy(&nent->oid, oid);
+	nent->tree_data = data;
+	nent->tree_size = size;
+	nent->ref = 1;
+	if (!nent->temporary)
+		pbase_tree_cache[my_ix] = nent;
+	return nent;
+}
+
+static void pbase_tree_put(struct pbase_tree_cache *cache)
+{
+	if (!cache->temporary) {
+		cache->ref--;
+		return;
+	}
+	free(cache->tree_data);
+	free(cache);
+}
+
+static size_t name_cmp_len(const char *name)
+{
+	return strcspn(name, "\n/");
+}
+
+static void add_pbase_object(struct tree_desc *tree,
+			     const char *name,
+			     size_t cmplen,
+			     const char *fullname)
+{
+	struct name_entry entry;
+	int cmp;
+
+	while (tree_entry(tree,&entry)) {
+		if (S_ISGITLINK(entry.mode))
+			continue;
+		cmp = tree_entry_len(&entry) != cmplen ? 1 :
+		      memcmp(name, entry.path, cmplen);
+		if (cmp > 0)
+			continue;
+		if (cmp < 0)
+			return;
+		if (name[cmplen] != '/') {
+			add_object_entry(&entry.oid,
+					 object_type(entry.mode),
+					 fullname, 1);
+			return;
+		}
+		if (S_ISDIR(entry.mode)) {
+			struct tree_desc sub;
+			struct pbase_tree_cache *tree;
+			const char *down = name+cmplen+1;
+			size_t downlen = name_cmp_len(down);
+
+			tree = pbase_tree_get(&entry.oid);
+			if (!tree)
+				return;
+			init_tree_desc(&sub, &tree->oid,
+				       tree->tree_data, tree->tree_size);
+
+			add_pbase_object(&sub, down, downlen, fullname);
+			pbase_tree_put(tree);
+		}
+	}
+}
+
+static unsigned *done_pbase_paths;
+static int done_pbase_paths_num;
+static int done_pbase_paths_alloc;
+static int done_pbase_path_pos(unsigned hash)
+{
+	int lo = 0;
+	int hi = done_pbase_paths_num;
+	while (lo < hi) {
+		int mi = lo + (hi - lo) / 2;
+		if (done_pbase_paths[mi] == hash)
+			return mi;
+		if (done_pbase_paths[mi] < hash)
+			hi = mi;
+		else
+			lo = mi + 1;
+	}
+	return -lo-1;
+}
+
+static int check_pbase_path(unsigned hash)
+{
+	int pos = done_pbase_path_pos(hash);
+	if (0 <= pos)
+		return 1;
+	pos = -pos - 1;
+	ALLOC_GROW(done_pbase_paths,
+		   done_pbase_paths_num + 1,
+		   done_pbase_paths_alloc);
+	done_pbase_paths_num++;
+	if (pos < done_pbase_paths_num)
+		MOVE_ARRAY(done_pbase_paths + pos + 1, done_pbase_paths + pos,
+			   done_pbase_paths_num - pos - 1);
+	done_pbase_paths[pos] = hash;
+	return 0;
+}
+
+static void add_preferred_base_object(const char *name)
+{
+	struct pbase_tree *it;
+	size_t cmplen;
+	unsigned hash = pack_name_hash(name);
+
+	if (!num_preferred_base || check_pbase_path(hash))
+		return;
+
+	cmplen = name_cmp_len(name);
+	for (it = pbase_tree; it; it = it->next) {
+		if (cmplen == 0) {
+			add_object_entry(&it->pcache.oid, OBJ_TREE, NULL, 1);
+		}
+		else {
+			struct tree_desc tree;
+			init_tree_desc(&tree, &it->pcache.oid,
+				       it->pcache.tree_data, it->pcache.tree_size);
+			add_pbase_object(&tree, name, cmplen, name);
+		}
+	}
+}
+
+static void add_preferred_base(struct object_id *oid)
+{
+	struct pbase_tree *it;
+	void *data;
+	unsigned long size;
+	struct object_id tree_oid;
+
+	if (window <= num_preferred_base++)
+		return;
+
+	data = read_object_with_reference(the_repository, oid,
+					  OBJ_TREE, &size, &tree_oid);
+	if (!data)
+		return;
+
+	for (it = pbase_tree; it; it = it->next) {
+		if (oideq(&it->pcache.oid, &tree_oid)) {
+			free(data);
+			return;
+		}
+	}
+
+	CALLOC_ARRAY(it, 1);
+	it->next = pbase_tree;
+	pbase_tree = it;
+
+	oidcpy(&it->pcache.oid, &tree_oid);
+	it->pcache.tree_data = data;
+	it->pcache.tree_size = size;
+}
+
+static void cleanup_preferred_base(void)
+{
+	struct pbase_tree *it;
+	unsigned i;
+
+	it = pbase_tree;
+	pbase_tree = NULL;
+	while (it) {
+		struct pbase_tree *tmp = it;
+		it = tmp->next;
+		free(tmp->pcache.tree_data);
+		free(tmp);
+	}
+
+	for (i = 0; i < ARRAY_SIZE(pbase_tree_cache); i++) {
+		if (!pbase_tree_cache[i])
+			continue;
+		free(pbase_tree_cache[i]->tree_data);
+		FREE_AND_NULL(pbase_tree_cache[i]);
+	}
+
+	FREE_AND_NULL(done_pbase_paths);
+	done_pbase_paths_num = done_pbase_paths_alloc = 0;
+}
+
+/*
+ * Return 1 iff the object specified by "delta" can be sent
+ * literally as a delta against the base in "base_sha1". If
+ * so, then *base_out will point to the entry in our packing
+ * list, or NULL if we must use the external-base list.
+ *
+ * Depth value does not matter - find_deltas() will
+ * never consider reused delta as the base object to
+ * deltify other objects against, in order to avoid
+ * circular deltas.
+ */
+static int can_reuse_delta(const struct object_id *base_oid,
+			   struct object_entry *delta,
+			   struct object_entry **base_out)
+{
+	struct object_entry *base;
+
+	/*
+	 * First see if we're already sending the base (or it's explicitly in
+	 * our "excluded" list).
+	 */
+	base = packlist_find(&to_pack, base_oid);
+	if (base) {
+		if (!in_same_island(&delta->idx.oid, &base->idx.oid))
+			return 0;
+		*base_out = base;
+		return 1;
+	}
+
+	/*
+	 * Otherwise, reachability bitmaps may tell us if the receiver has it,
+	 * even if it was buried too deep in history to make it into the
+	 * packing list.
+	 */
+	if (thin && bitmap_has_oid_in_uninteresting(bitmap_git, base_oid)) {
+		if (use_delta_islands) {
+			if (!in_same_island(&delta->idx.oid, base_oid))
+				return 0;
+		}
+		*base_out = NULL;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void prefetch_to_pack(uint32_t object_index_start) {
+	struct oid_array to_fetch = OID_ARRAY_INIT;
+	uint32_t i;
+
+	for (i = object_index_start; i < to_pack.nr_objects; i++) {
+		struct object_entry *entry = to_pack.objects + i;
+
+		if (!oid_object_info_extended(the_repository,
+					      &entry->idx.oid,
+					      NULL,
+					      OBJECT_INFO_FOR_PREFETCH))
+			continue;
+		oid_array_append(&to_fetch, &entry->idx.oid);
+	}
+	promisor_remote_get_direct(the_repository,
+				   to_fetch.oid, to_fetch.nr);
+	oid_array_clear(&to_fetch);
+}
+
+static void check_object(struct object_entry *entry, uint32_t object_index)
+{
+	unsigned long canonical_size;
+	enum object_type type;
+	struct object_info oi = {.typep = &type, .sizep = &canonical_size};
+
+	if (IN_PACK(entry)) {
+		struct packed_git *p = IN_PACK(entry);
+		struct pack_window *w_curs = NULL;
+		int have_base = 0;
+		struct object_id base_ref;
+		struct object_entry *base_entry;
+		unsigned long used, used_0;
+		unsigned long avail;
+		off_t ofs;
+		unsigned char *buf, c;
+		enum object_type type;
+		unsigned long in_pack_size;
+
+		buf = use_pack(p, &w_curs, entry->in_pack_offset, &avail);
+
+		/*
+		 * We want in_pack_type even if we do not reuse delta
+		 * since non-delta representations could still be reused.
+		 */
+		used = unpack_object_header_buffer(buf, avail,
+						   &type,
+						   &in_pack_size);
+		if (used == 0)
+			goto give_up;
+
+		if (type < 0)
+			BUG("invalid type %d", type);
+		entry->in_pack_type = type;
+
+		/*
+		 * Determine if this is a delta and if so whether we can
+		 * reuse it or not.  Otherwise let's find out as cheaply as
+		 * possible what the actual type and size for this object is.
+		 */
+		switch (entry->in_pack_type) {
+		default:
+			/* Not a delta hence we've already got all we need. */
+			oe_set_type(entry, entry->in_pack_type);
+			SET_SIZE(entry, in_pack_size);
+			entry->in_pack_header_size = used;
+			if (oe_type(entry) < OBJ_COMMIT || oe_type(entry) > OBJ_BLOB)
+				goto give_up;
+			unuse_pack(&w_curs);
+			return;
+		case OBJ_REF_DELTA:
+			if (reuse_delta && !entry->preferred_base) {
+				oidread(&base_ref,
+					use_pack(p, &w_curs,
+						 entry->in_pack_offset + used,
+						 NULL),
+					the_repository->hash_algo);
+				have_base = 1;
+			}
+			entry->in_pack_header_size = used + the_hash_algo->rawsz;
+			break;
+		case OBJ_OFS_DELTA:
+			buf = use_pack(p, &w_curs,
+				       entry->in_pack_offset + used, NULL);
+			used_0 = 0;
+			c = buf[used_0++];
+			ofs = c & 127;
+			while (c & 128) {
+				ofs += 1;
+				if (!ofs || MSB(ofs, 7)) {
+					error(_("delta base offset overflow in pack for %s"),
+					      oid_to_hex(&entry->idx.oid));
+					goto give_up;
+				}
+				c = buf[used_0++];
+				ofs = (ofs << 7) + (c & 127);
+			}
+			ofs = entry->in_pack_offset - ofs;
+			if (ofs <= 0 || ofs >= entry->in_pack_offset) {
+				error(_("delta base offset out of bound for %s"),
+				      oid_to_hex(&entry->idx.oid));
+				goto give_up;
+			}
+			if (reuse_delta && !entry->preferred_base) {
+				uint32_t pos;
+				if (offset_to_pack_pos(p, ofs, &pos) < 0)
+					goto give_up;
+				if (!nth_packed_object_id(&base_ref, p,
+							  pack_pos_to_index(p, pos)))
+					have_base = 1;
+			}
+			entry->in_pack_header_size = used + used_0;
+			break;
+		}
+
+		if (have_base &&
+		    can_reuse_delta(&base_ref, entry, &base_entry)) {
+			oe_set_type(entry, entry->in_pack_type);
+			SET_SIZE(entry, in_pack_size); /* delta size */
+			SET_DELTA_SIZE(entry, in_pack_size);
+
+			if (base_entry) {
+				SET_DELTA(entry, base_entry);
+				entry->delta_sibling_idx = base_entry->delta_child_idx;
+				SET_DELTA_CHILD(base_entry, entry);
+			} else {
+				SET_DELTA_EXT(entry, &base_ref);
+			}
+
+			unuse_pack(&w_curs);
+			return;
+		}
+
+		if (oe_type(entry)) {
+			off_t delta_pos;
+
+			/*
+			 * This must be a delta and we already know what the
+			 * final object type is.  Let's extract the actual
+			 * object size from the delta header.
+			 */
+			delta_pos = entry->in_pack_offset + entry->in_pack_header_size;
+			canonical_size = get_size_from_delta(p, &w_curs, delta_pos);
+			if (canonical_size == 0)
+				goto give_up;
+			SET_SIZE(entry, canonical_size);
+			unuse_pack(&w_curs);
+			return;
+		}
+
+		/*
+		 * No choice but to fall back to the recursive delta walk
+		 * with oid_object_info() to find about the object type
+		 * at this point...
+		 */
+		give_up:
+		unuse_pack(&w_curs);
+	}
+
+	if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
+				     OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0) {
+		if (repo_has_promisor_remote(the_repository)) {
+			prefetch_to_pack(object_index);
+			if (oid_object_info_extended(the_repository, &entry->idx.oid, &oi,
+						     OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_LOOKUP_REPLACE) < 0)
+				type = -1;
+		} else {
+			type = -1;
+		}
+	}
+	oe_set_type(entry, type);
+	if (entry->type_valid) {
+		SET_SIZE(entry, canonical_size);
+	} else {
+		/*
+		 * Bad object type is checked in prepare_pack().  This is
+		 * to permit a missing preferred base object to be ignored
+		 * as a preferred base.  Doing so can result in a larger
+		 * pack file, but the transfer will still take place.
+		 */
+	}
+}
+
+static int pack_offset_sort(const void *_a, const void *_b)
+{
+	const struct object_entry *a = *(struct object_entry **)_a;
+	const struct object_entry *b = *(struct object_entry **)_b;
+	const struct packed_git *a_in_pack = IN_PACK(a);
+	const struct packed_git *b_in_pack = IN_PACK(b);
+
+	/* avoid filesystem trashing with loose objects */
+	if (!a_in_pack && !b_in_pack)
+		return oidcmp(&a->idx.oid, &b->idx.oid);
+
+	if (a_in_pack < b_in_pack)
+		return -1;
+	if (a_in_pack > b_in_pack)
+		return 1;
+	return a->in_pack_offset < b->in_pack_offset ? -1 :
+			(a->in_pack_offset > b->in_pack_offset);
+}
+
+/*
+ * Drop an on-disk delta we were planning to reuse. Naively, this would
+ * just involve blanking out the "delta" field, but we have to deal
+ * with some extra book-keeping:
+ *
+ *   1. Removing ourselves from the delta_sibling linked list.
+ *
+ *   2. Updating our size/type to the non-delta representation. These were
+ *      either not recorded initially (size) or overwritten with the delta type
+ *      (type) when check_object() decided to reuse the delta.
+ *
+ *   3. Resetting our delta depth, as we are now a base object.
+ */
+static void drop_reused_delta(struct object_entry *entry)
+{
+	unsigned *idx = &to_pack.objects[entry->delta_idx - 1].delta_child_idx;
+	struct object_info oi = OBJECT_INFO_INIT;
+	enum object_type type;
+	unsigned long size;
+
+	while (*idx) {
+		struct object_entry *oe = &to_pack.objects[*idx - 1];
+
+		if (oe == entry)
+			*idx = oe->delta_sibling_idx;
+		else
+			idx = &oe->delta_sibling_idx;
+	}
+	SET_DELTA(entry, NULL);
+	entry->depth = 0;
+
+	oi.sizep = &size;
+	oi.typep = &type;
+	if (packed_object_info(the_repository, IN_PACK(entry), entry->in_pack_offset, &oi) < 0) {
+		/*
+		 * We failed to get the info from this pack for some reason;
+		 * fall back to oid_object_info, which may find another copy.
+		 * And if that fails, the error will be recorded in oe_type(entry)
+		 * and dealt with in prepare_pack().
+		 */
+		oe_set_type(entry,
+			    oid_object_info(the_repository, &entry->idx.oid, &size));
+	} else {
+		oe_set_type(entry, type);
+	}
+	SET_SIZE(entry, size);
+}
+
+/*
+ * Follow the chain of deltas from this entry onward, throwing away any links
+ * that cause us to hit a cycle (as determined by the DFS state flags in
+ * the entries).
+ *
+ * We also detect too-long reused chains that would violate our --depth
+ * limit.
+ */
+static void break_delta_chains(struct object_entry *entry)
+{
+	/*
+	 * The actual depth of each object we will write is stored as an int,
+	 * as it cannot exceed our int "depth" limit. But before we break
+	 * changes based no that limit, we may potentially go as deep as the
+	 * number of objects, which is elsewhere bounded to a uint32_t.
+	 */
+	uint32_t total_depth;
+	struct object_entry *cur, *next;
+
+	for (cur = entry, total_depth = 0;
+	     cur;
+	     cur = DELTA(cur), total_depth++) {
+		if (cur->dfs_state == DFS_DONE) {
+			/*
+			 * We've already seen this object and know it isn't
+			 * part of a cycle. We do need to append its depth
+			 * to our count.
+			 */
+			total_depth += cur->depth;
+			break;
+		}
+
+		/*
+		 * We break cycles before looping, so an ACTIVE state (or any
+		 * other cruft which made its way into the state variable)
+		 * is a bug.
+		 */
+		if (cur->dfs_state != DFS_NONE)
+			BUG("confusing delta dfs state in first pass: %d",
+			    cur->dfs_state);
+
+		/*
+		 * Now we know this is the first time we've seen the object. If
+		 * it's not a delta, we're done traversing, but we'll mark it
+		 * done to save time on future traversals.
+		 */
+		if (!DELTA(cur)) {
+			cur->dfs_state = DFS_DONE;
+			break;
+		}
+
+		/*
+		 * Mark ourselves as active and see if the next step causes
+		 * us to cycle to another active object. It's important to do
+		 * this _before_ we loop, because it impacts where we make the
+		 * cut, and thus how our total_depth counter works.
+		 * E.g., We may see a partial loop like:
+		 *
+		 *   A -> B -> C -> D -> B
+		 *
+		 * Cutting B->C breaks the cycle. But now the depth of A is
+		 * only 1, and our total_depth counter is at 3. The size of the
+		 * error is always one less than the size of the cycle we
+		 * broke. Commits C and D were "lost" from A's chain.
+		 *
+		 * If we instead cut D->B, then the depth of A is correct at 3.
+		 * We keep all commits in the chain that we examined.
+		 */
+		cur->dfs_state = DFS_ACTIVE;
+		if (DELTA(cur)->dfs_state == DFS_ACTIVE) {
+			drop_reused_delta(cur);
+			cur->dfs_state = DFS_DONE;
+			break;
+		}
+	}
+
+	/*
+	 * And now that we've gone all the way to the bottom of the chain, we
+	 * need to clear the active flags and set the depth fields as
+	 * appropriate. Unlike the loop above, which can quit when it drops a
+	 * delta, we need to keep going to look for more depth cuts. So we need
+	 * an extra "next" pointer to keep going after we reset cur->delta.
+	 */
+	for (cur = entry; cur; cur = next) {
+		next = DELTA(cur);
+
+		/*
+		 * We should have a chain of zero or more ACTIVE states down to
+		 * a final DONE. We can quit after the DONE, because either it
+		 * has no bases, or we've already handled them in a previous
+		 * call.
+		 */
+		if (cur->dfs_state == DFS_DONE)
+			break;
+		else if (cur->dfs_state != DFS_ACTIVE)
+			BUG("confusing delta dfs state in second pass: %d",
+			    cur->dfs_state);
+
+		/*
+		 * If the total_depth is more than depth, then we need to snip
+		 * the chain into two or more smaller chains that don't exceed
+		 * the maximum depth. Most of the resulting chains will contain
+		 * (depth + 1) entries (i.e., depth deltas plus one base), and
+		 * the last chain (i.e., the one containing entry) will contain
+		 * whatever entries are left over, namely
+		 * (total_depth % (depth + 1)) of them.
+		 *
+		 * Since we are iterating towards decreasing depth, we need to
+		 * decrement total_depth as we go, and we need to write to the
+		 * entry what its final depth will be after all of the
+		 * snipping. Since we're snipping into chains of length (depth
+		 * + 1) entries, the final depth of an entry will be its
+		 * original depth modulo (depth + 1). Any time we encounter an
+		 * entry whose final depth is supposed to be zero, we snip it
+		 * from its delta base, thereby making it so.
+		 */
+		cur->depth = (total_depth--) % (depth + 1);
+		if (!cur->depth)
+			drop_reused_delta(cur);
+
+		cur->dfs_state = DFS_DONE;
+	}
+}
+
+static void get_object_details(void)
+{
+	uint32_t i;
+	struct object_entry **sorted_by_offset;
+
+	if (progress)
+		progress_state = start_progress(the_repository,
+						_("Counting objects"),
+						to_pack.nr_objects);
+
+	CALLOC_ARRAY(sorted_by_offset, to_pack.nr_objects);
+	for (i = 0; i < to_pack.nr_objects; i++)
+		sorted_by_offset[i] = to_pack.objects + i;
+	QSORT(sorted_by_offset, to_pack.nr_objects, pack_offset_sort);
+
+	for (i = 0; i < to_pack.nr_objects; i++) {
+		struct object_entry *entry = sorted_by_offset[i];
+		check_object(entry, i);
+		if (entry->type_valid &&
+		    oe_size_greater_than(&to_pack, entry, big_file_threshold))
+			entry->no_try_delta = 1;
+		display_progress(progress_state, i + 1);
+	}
+	stop_progress(&progress_state);
+
+	/*
+	 * This must happen in a second pass, since we rely on the delta
+	 * information for the whole list being completed.
+	 */
+	for (i = 0; i < to_pack.nr_objects; i++)
+		break_delta_chains(&to_pack.objects[i]);
+
+	free(sorted_by_offset);
+}
+
+/*
+ * We search for deltas in a list sorted by type, by filename hash, and then
+ * by size, so that we see progressively smaller and smaller files.
+ * That's because we prefer deltas to be from the bigger file
+ * to the smaller -- deletes are potentially cheaper, but perhaps
+ * more importantly, the bigger file is likely the more recent
+ * one.  The deepest deltas are therefore the oldest objects which are
+ * less susceptible to be accessed often.
+ */
+static int type_size_sort(const void *_a, const void *_b)
+{
+	const struct object_entry *a = *(struct object_entry **)_a;
+	const struct object_entry *b = *(struct object_entry **)_b;
+	const enum object_type a_type = oe_type(a);
+	const enum object_type b_type = oe_type(b);
+	const unsigned long a_size = SIZE(a);
+	const unsigned long b_size = SIZE(b);
+
+	if (a_type > b_type)
+		return -1;
+	if (a_type < b_type)
+		return 1;
+	if (a->hash > b->hash)
+		return -1;
+	if (a->hash < b->hash)
+		return 1;
+	if (a->preferred_base > b->preferred_base)
+		return -1;
+	if (a->preferred_base < b->preferred_base)
+		return 1;
+	if (use_delta_islands) {
+		const int island_cmp = island_delta_cmp(&a->idx.oid, &b->idx.oid);
+		if (island_cmp)
+			return island_cmp;
+	}
+	if (a_size > b_size)
+		return -1;
+	if (a_size < b_size)
+		return 1;
+	return a < b ? -1 : (a > b);  /* newest first */
+}
+
+struct unpacked {
+	struct object_entry *entry;
+	void *data;
+	struct delta_index *index;
+	unsigned depth;
+};
+
+static int delta_cacheable(unsigned long src_size, unsigned long trg_size,
+			   unsigned long delta_size)
+{
+	if (max_delta_cache_size && delta_cache_size + delta_size > max_delta_cache_size)
+		return 0;
+
+	if (delta_size < cache_max_small_delta_size)
+		return 1;
+
+	/* cache delta, if objects are large enough compared to delta size */
+	if ((src_size >> 20) + (trg_size >> 21) > (delta_size >> 10))
+		return 1;
+
+	return 0;
+}
+
+/* Protect delta_cache_size */
+static pthread_mutex_t cache_mutex;
+#define cache_lock()		pthread_mutex_lock(&cache_mutex)
+#define cache_unlock()		pthread_mutex_unlock(&cache_mutex)
+
+/*
+ * Protect object list partitioning (e.g. struct thread_param) and
+ * progress_state
+ */
+static pthread_mutex_t progress_mutex;
+#define progress_lock()		pthread_mutex_lock(&progress_mutex)
+#define progress_unlock()	pthread_mutex_unlock(&progress_mutex)
+
+/*
+ * Access to struct object_entry is unprotected since each thread owns
+ * a portion of the main object list. Just don't access object entries
+ * ahead in the list because they can be stolen and would need
+ * progress_mutex for protection.
+ */
+
+static inline int oe_size_less_than(struct packing_data *pack,
+				    const struct object_entry *lhs,
+				    unsigned long rhs)
+{
+	if (lhs->size_valid)
+		return lhs->size_ < rhs;
+	if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */
+		return 0;
+	return oe_get_size_slow(pack, lhs) < rhs;
+}
+
+static inline void oe_set_tree_depth(struct packing_data *pack,
+				     struct object_entry *e,
+				     unsigned int tree_depth)
+{
+	if (!pack->tree_depth)
+		CALLOC_ARRAY(pack->tree_depth, pack->nr_alloc);
+	pack->tree_depth[e - pack->objects] = tree_depth;
+}
+
+/*
+ * Return the size of the object without doing any delta
+ * reconstruction (so non-deltas are true object sizes, but deltas
+ * return the size of the delta data).
+ */
+unsigned long oe_get_size_slow(struct packing_data *pack,
+			       const struct object_entry *e)
+{
+	struct packed_git *p;
+	struct pack_window *w_curs;
+	unsigned char *buf;
+	enum object_type type;
+	unsigned long used, avail, size;
+
+	if (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {
+		packing_data_lock(&to_pack);
+		if (oid_object_info(the_repository, &e->idx.oid, &size) < 0)
+			die(_("unable to get size of %s"),
+			    oid_to_hex(&e->idx.oid));
+		packing_data_unlock(&to_pack);
+		return size;
+	}
+
+	p = oe_in_pack(pack, e);
+	if (!p)
+		BUG("when e->type is a delta, it must belong to a pack");
+
+	packing_data_lock(&to_pack);
+	w_curs = NULL;
+	buf = use_pack(p, &w_curs, e->in_pack_offset, &avail);
+	used = unpack_object_header_buffer(buf, avail, &type, &size);
+	if (used == 0)
+		die(_("unable to parse object header of %s"),
+		    oid_to_hex(&e->idx.oid));
+
+	unuse_pack(&w_curs);
+	packing_data_unlock(&to_pack);
+	return size;
+}
+
+static int try_delta(struct unpacked *trg, struct unpacked *src,
+		     unsigned max_depth, unsigned long *mem_usage)
+{
+	struct object_entry *trg_entry = trg->entry;
+	struct object_entry *src_entry = src->entry;
+	unsigned long trg_size, src_size, delta_size, sizediff, max_size, sz;
+	unsigned ref_depth;
+	enum object_type type;
+	void *delta_buf;
+
+	/* Don't bother doing diffs between different types */
+	if (oe_type(trg_entry) != oe_type(src_entry))
+		return -1;
+
+	/*
+	 * We do not bother to try a delta that we discarded on an
+	 * earlier try, but only when reusing delta data.  Note that
+	 * src_entry that is marked as the preferred_base should always
+	 * be considered, as even if we produce a suboptimal delta against
+	 * it, we will still save the transfer cost, as we already know
+	 * the other side has it and we won't send src_entry at all.
+	 */
+	if (reuse_delta && IN_PACK(trg_entry) &&
+	    IN_PACK(trg_entry) == IN_PACK(src_entry) &&
+	    !src_entry->preferred_base &&
+	    trg_entry->in_pack_type != OBJ_REF_DELTA &&
+	    trg_entry->in_pack_type != OBJ_OFS_DELTA)
+		return 0;
+
+	/* Let's not bust the allowed depth. */
+	if (src->depth >= max_depth)
+		return 0;
+
+	/* Now some size filtering heuristics. */
+	trg_size = SIZE(trg_entry);
+	if (!DELTA(trg_entry)) {
+		max_size = trg_size/2 - the_hash_algo->rawsz;
+		ref_depth = 1;
+	} else {
+		max_size = DELTA_SIZE(trg_entry);
+		ref_depth = trg->depth;
+	}
+	max_size = (uint64_t)max_size * (max_depth - src->depth) /
+						(max_depth - ref_depth + 1);
+	if (max_size == 0)
+		return 0;
+	src_size = SIZE(src_entry);
+	sizediff = src_size < trg_size ? trg_size - src_size : 0;
+	if (sizediff >= max_size)
+		return 0;
+	if (trg_size < src_size / 32)
+		return 0;
+
+	if (!in_same_island(&trg->entry->idx.oid, &src->entry->idx.oid))
+		return 0;
+
+	/* Load data if not already done */
+	if (!trg->data) {
+		packing_data_lock(&to_pack);
+		trg->data = repo_read_object_file(the_repository,
+						  &trg_entry->idx.oid, &type,
+						  &sz);
+		packing_data_unlock(&to_pack);
+		if (!trg->data)
+			die(_("object %s cannot be read"),
+			    oid_to_hex(&trg_entry->idx.oid));
+		if (sz != trg_size)
+			die(_("object %s inconsistent object length (%"PRIuMAX" vs %"PRIuMAX")"),
+			    oid_to_hex(&trg_entry->idx.oid), (uintmax_t)sz,
+			    (uintmax_t)trg_size);
+		*mem_usage += sz;
+	}
+	if (!src->data) {
+		packing_data_lock(&to_pack);
+		src->data = repo_read_object_file(the_repository,
+						  &src_entry->idx.oid, &type,
+						  &sz);
+		packing_data_unlock(&to_pack);
+		if (!src->data) {
+			if (src_entry->preferred_base) {
+				static int warned = 0;
+				if (!warned++)
+					warning(_("object %s cannot be read"),
+						oid_to_hex(&src_entry->idx.oid));
+				/*
+				 * Those objects are not included in the
+				 * resulting pack.  Be resilient and ignore
+				 * them if they can't be read, in case the
+				 * pack could be created nevertheless.
+				 */
+				return 0;
+			}
+			die(_("object %s cannot be read"),
+			    oid_to_hex(&src_entry->idx.oid));
+		}
+		if (sz != src_size)
+			die(_("object %s inconsistent object length (%"PRIuMAX" vs %"PRIuMAX")"),
+			    oid_to_hex(&src_entry->idx.oid), (uintmax_t)sz,
+			    (uintmax_t)src_size);
+		*mem_usage += sz;
+	}
+	if (!src->index) {
+		src->index = create_delta_index(src->data, src_size);
+		if (!src->index) {
+			static int warned = 0;
+			if (!warned++)
+				warning(_("suboptimal pack - out of memory"));
+			return 0;
+		}
+		*mem_usage += sizeof_delta_index(src->index);
+	}
+
+	delta_buf = create_delta(src->index, trg->data, trg_size, &delta_size, max_size);
+	if (!delta_buf)
+		return 0;
+
+	if (DELTA(trg_entry)) {
+		/* Prefer only shallower same-sized deltas. */
+		if (delta_size == DELTA_SIZE(trg_entry) &&
+		    src->depth + 1 >= trg->depth) {
+			free(delta_buf);
+			return 0;
+		}
+	}
+
+	/*
+	 * Handle memory allocation outside of the cache
+	 * accounting lock.  Compiler will optimize the strangeness
+	 * away when NO_PTHREADS is defined.
+	 */
+	free(trg_entry->delta_data);
+	cache_lock();
+	if (trg_entry->delta_data) {
+		delta_cache_size -= DELTA_SIZE(trg_entry);
+		trg_entry->delta_data = NULL;
+	}
+	if (delta_cacheable(src_size, trg_size, delta_size)) {
+		delta_cache_size += delta_size;
+		cache_unlock();
+		trg_entry->delta_data = xrealloc(delta_buf, delta_size);
+	} else {
+		cache_unlock();
+		free(delta_buf);
+	}
+
+	SET_DELTA(trg_entry, src_entry);
+	SET_DELTA_SIZE(trg_entry, delta_size);
+	trg->depth = src->depth + 1;
+
+	return 1;
+}
+
+static unsigned int check_delta_limit(struct object_entry *me, unsigned int n)
+{
+	struct object_entry *child = DELTA_CHILD(me);
+	unsigned int m = n;
+	while (child) {
+		const unsigned int c = check_delta_limit(child, n + 1);
+		if (m < c)
+			m = c;
+		child = DELTA_SIBLING(child);
+	}
+	return m;
+}
+
+static unsigned long free_unpacked(struct unpacked *n)
+{
+	unsigned long freed_mem = sizeof_delta_index(n->index);
+	free_delta_index(n->index);
+	n->index = NULL;
+	if (n->data) {
+		freed_mem += SIZE(n->entry);
+		FREE_AND_NULL(n->data);
+	}
+	n->entry = NULL;
+	n->depth = 0;
+	return freed_mem;
+}
+
+static void find_deltas(struct object_entry **list, unsigned *list_size,
+			int window, int depth, unsigned *processed)
+{
+	uint32_t i, idx = 0, count = 0;
+	struct unpacked *array;
+	unsigned long mem_usage = 0;
+
+	CALLOC_ARRAY(array, window);
+
+	for (;;) {
+		struct object_entry *entry;
+		struct unpacked *n = array + idx;
+		int j, max_depth, best_base = -1;
+
+		progress_lock();
+		if (!*list_size) {
+			progress_unlock();
+			break;
+		}
+		entry = *list++;
+		(*list_size)--;
+		if (!entry->preferred_base) {
+			(*processed)++;
+			display_progress(progress_state, *processed);
+		}
+		progress_unlock();
+
+		mem_usage -= free_unpacked(n);
+		n->entry = entry;
+
+		while (window_memory_limit &&
+		       mem_usage > window_memory_limit &&
+		       count > 1) {
+			const uint32_t tail = (idx + window - count) % window;
+			mem_usage -= free_unpacked(array + tail);
+			count--;
+		}
+
+		/* We do not compute delta to *create* objects we are not
+		 * going to pack.
+		 */
+		if (entry->preferred_base)
+			goto next;
+
+		/*
+		 * If the current object is at pack edge, take the depth the
+		 * objects that depend on the current object into account
+		 * otherwise they would become too deep.
+		 */
+		max_depth = depth;
+		if (DELTA_CHILD(entry)) {
+			max_depth -= check_delta_limit(entry, 0);
+			if (max_depth <= 0)
+				goto next;
+		}
+
+		j = window;
+		while (--j > 0) {
+			int ret;
+			uint32_t other_idx = idx + j;
+			struct unpacked *m;
+			if (other_idx >= window)
+				other_idx -= window;
+			m = array + other_idx;
+			if (!m->entry)
+				break;
+			ret = try_delta(n, m, max_depth, &mem_usage);
+			if (ret < 0)
+				break;
+			else if (ret > 0)
+				best_base = other_idx;
+		}
+
+		/*
+		 * If we decided to cache the delta data, then it is best
+		 * to compress it right away.  First because we have to do
+		 * it anyway, and doing it here while we're threaded will
+		 * save a lot of time in the non threaded write phase,
+		 * as well as allow for caching more deltas within
+		 * the same cache size limit.
+		 * ...
+		 * But only if not writing to stdout, since in that case
+		 * the network is most likely throttling writes anyway,
+		 * and therefore it is best to go to the write phase ASAP
+		 * instead, as we can afford spending more time compressing
+		 * between writes at that moment.
+		 */
+		if (entry->delta_data && !pack_to_stdout) {
+			unsigned long size;
+
+			size = do_compress(&entry->delta_data, DELTA_SIZE(entry));
+			if (size < (1U << OE_Z_DELTA_BITS)) {
+				entry->z_delta_size = size;
+				cache_lock();
+				delta_cache_size -= DELTA_SIZE(entry);
+				delta_cache_size += entry->z_delta_size;
+				cache_unlock();
+			} else {
+				FREE_AND_NULL(entry->delta_data);
+				entry->z_delta_size = 0;
+			}
+		}
+
+		/* if we made n a delta, and if n is already at max
+		 * depth, leaving it in the window is pointless.  we
+		 * should evict it first.
+		 */
+		if (DELTA(entry) && max_depth <= n->depth)
+			continue;
+
+		/*
+		 * Move the best delta base up in the window, after the
+		 * currently deltified object, to keep it longer.  It will
+		 * be the first base object to be attempted next.
+		 */
+		if (DELTA(entry)) {
+			struct unpacked swap = array[best_base];
+			int dist = (window + idx - best_base) % window;
+			int dst = best_base;
+			while (dist--) {
+				int src = (dst + 1) % window;
+				array[dst] = array[src];
+				dst = src;
+			}
+			array[dst] = swap;
+		}
+
+		next:
+		idx++;
+		if (count + 1 < window)
+			count++;
+		if (idx >= window)
+			idx = 0;
+	}
+
+	for (i = 0; i < window; ++i) {
+		free_delta_index(array[i].index);
+		free(array[i].data);
+	}
+	free(array);
+}
+
+/*
+ * The main object list is split into smaller lists, each is handed to
+ * one worker.
+ *
+ * The main thread waits on the condition that (at least) one of the workers
+ * has stopped working (which is indicated in the .working member of
+ * struct thread_params).
+ *
+ * When a work thread has completed its work, it sets .working to 0 and
+ * signals the main thread and waits on the condition that .data_ready
+ * becomes 1.
+ *
+ * The main thread steals half of the work from the worker that has
+ * most work left to hand it to the idle worker.
+ */
+
+struct thread_params {
+	pthread_t thread;
+	struct object_entry **list;
+	unsigned list_size;
+	unsigned remaining;
+	int window;
+	int depth;
+	int working;
+	int data_ready;
+	pthread_mutex_t mutex;
+	pthread_cond_t cond;
+	unsigned *processed;
+};
+
+static pthread_cond_t progress_cond;
+
+/*
+ * Mutex and conditional variable can't be statically-initialized on Windows.
+ */
+static void init_threaded_search(void)
+{
+	pthread_mutex_init(&cache_mutex, NULL);
+	pthread_mutex_init(&progress_mutex, NULL);
+	pthread_cond_init(&progress_cond, NULL);
+}
+
+static void cleanup_threaded_search(void)
+{
+	pthread_cond_destroy(&progress_cond);
+	pthread_mutex_destroy(&cache_mutex);
+	pthread_mutex_destroy(&progress_mutex);
+}
+
+static void *threaded_find_deltas(void *arg)
+{
+	struct thread_params *me = arg;
+
+	progress_lock();
+	while (me->remaining) {
+		progress_unlock();
+
+		find_deltas(me->list, &me->remaining,
+			    me->window, me->depth, me->processed);
+
+		progress_lock();
+		me->working = 0;
+		pthread_cond_signal(&progress_cond);
+		progress_unlock();
+
+		/*
+		 * We must not set ->data_ready before we wait on the
+		 * condition because the main thread may have set it to 1
+		 * before we get here. In order to be sure that new
+		 * work is available if we see 1 in ->data_ready, it
+		 * was initialized to 0 before this thread was spawned
+		 * and we reset it to 0 right away.
+		 */
+		pthread_mutex_lock(&me->mutex);
+		while (!me->data_ready)
+			pthread_cond_wait(&me->cond, &me->mutex);
+		me->data_ready = 0;
+		pthread_mutex_unlock(&me->mutex);
+
+		progress_lock();
+	}
+	progress_unlock();
+	/* leave ->working 1 so that this doesn't get more work assigned */
+	return NULL;
+}
+
+static void ll_find_deltas(struct object_entry **list, unsigned list_size,
+			   int window, int depth, unsigned *processed)
+{
+	struct thread_params *p;
+	int i, ret, active_threads = 0;
+
+	init_threaded_search();
+
+	if (delta_search_threads <= 1) {
+		find_deltas(list, &list_size, window, depth, processed);
+		cleanup_threaded_search();
+		return;
+	}
+	if (progress > pack_to_stdout)
+		fprintf_ln(stderr, _("Delta compression using up to %d threads"),
+			   delta_search_threads);
+	CALLOC_ARRAY(p, delta_search_threads);
+
+	/* Partition the work amongst work threads. */
+	for (i = 0; i < delta_search_threads; i++) {
+		unsigned sub_size = list_size / (delta_search_threads - i);
+
+		/* don't use too small segments or no deltas will be found */
+		if (sub_size < 2*window && i+1 < delta_search_threads)
+			sub_size = 0;
+
+		p[i].window = window;
+		p[i].depth = depth;
+		p[i].processed = processed;
+		p[i].working = 1;
+		p[i].data_ready = 0;
+
+		/* try to split chunks on "path" boundaries */
+		while (sub_size && sub_size < list_size &&
+		       list[sub_size]->hash &&
+		       list[sub_size]->hash == list[sub_size-1]->hash)
+			sub_size++;
+
+		p[i].list = list;
+		p[i].list_size = sub_size;
+		p[i].remaining = sub_size;
+
+		list += sub_size;
+		list_size -= sub_size;
+	}
+
+	/* Start work threads. */
+	for (i = 0; i < delta_search_threads; i++) {
+		if (!p[i].list_size)
+			continue;
+		pthread_mutex_init(&p[i].mutex, NULL);
+		pthread_cond_init(&p[i].cond, NULL);
+		ret = pthread_create(&p[i].thread, NULL,
+				     threaded_find_deltas, &p[i]);
+		if (ret)
+			die(_("unable to create thread: %s"), strerror(ret));
+		active_threads++;
+	}
+
+	/*
+	 * Now let's wait for work completion.  Each time a thread is done
+	 * with its work, we steal half of the remaining work from the
+	 * thread with the largest number of unprocessed objects and give
+	 * it to that newly idle thread.  This ensure good load balancing
+	 * until the remaining object list segments are simply too short
+	 * to be worth splitting anymore.
+	 */
+	while (active_threads) {
+		struct thread_params *target = NULL;
+		struct thread_params *victim = NULL;
+		unsigned sub_size = 0;
+
+		progress_lock();
+		for (;;) {
+			for (i = 0; !target && i < delta_search_threads; i++)
+				if (!p[i].working)
+					target = &p[i];
+			if (target)
+				break;
+			pthread_cond_wait(&progress_cond, &progress_mutex);
+		}
+
+		for (i = 0; i < delta_search_threads; i++)
+			if (p[i].remaining > 2*window &&
+			    (!victim || victim->remaining < p[i].remaining))
+				victim = &p[i];
+		if (victim) {
+			sub_size = victim->remaining / 2;
+			list = victim->list + victim->list_size - sub_size;
+			while (sub_size && list[0]->hash &&
+			       list[0]->hash == list[-1]->hash) {
+				list++;
+				sub_size--;
+			}
+			if (!sub_size) {
+				/*
+				 * It is possible for some "paths" to have
+				 * so many objects that no hash boundary
+				 * might be found.  Let's just steal the
+				 * exact half in that case.
+				 */
+				sub_size = victim->remaining / 2;
+				list -= sub_size;
+			}
+			target->list = list;
+			victim->list_size -= sub_size;
+			victim->remaining -= sub_size;
+		}
+		target->list_size = sub_size;
+		target->remaining = sub_size;
+		target->working = 1;
+		progress_unlock();
+
+		pthread_mutex_lock(&target->mutex);
+		target->data_ready = 1;
+		pthread_cond_signal(&target->cond);
+		pthread_mutex_unlock(&target->mutex);
+
+		if (!sub_size) {
+			pthread_join(target->thread, NULL);
+			pthread_cond_destroy(&target->cond);
+			pthread_mutex_destroy(&target->mutex);
+			active_threads--;
+		}
+	}
+	cleanup_threaded_search();
+	free(p);
+}
+
+static int obj_is_packed(const struct object_id *oid)
+{
+	return packlist_find(&to_pack, oid) ||
+		(reuse_packfile_bitmap &&
+		 bitmap_walk_contains(bitmap_git, reuse_packfile_bitmap, oid));
+}
+
+static void add_tag_chain(const struct object_id *oid)
+{
+	struct tag *tag;
+
+	/*
+	 * We catch duplicates already in add_object_entry(), but we'd
+	 * prefer to do this extra check to avoid having to parse the
+	 * tag at all if we already know that it's being packed (e.g., if
+	 * it was included via bitmaps, we would not have parsed it
+	 * previously).
+	 */
+	if (obj_is_packed(oid))
+		return;
+
+	tag = lookup_tag(the_repository, oid);
+	while (1) {
+		if (!tag || parse_tag(tag) || !tag->tagged)
+			die(_("unable to pack objects reachable from tag %s"),
+			    oid_to_hex(oid));
+
+		add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0);
+
+		if (tag->tagged->type != OBJ_TAG)
+			return;
+
+		tag = (struct tag *)tag->tagged;
+	}
+}
+
+static int add_ref_tag(const char *tag UNUSED, const char *referent UNUSED, const struct object_id *oid,
+		       int flag UNUSED, void *cb_data UNUSED)
+{
+	struct object_id peeled;
+
+	if (!peel_iterated_oid(the_repository, oid, &peeled) && obj_is_packed(&peeled))
+		add_tag_chain(oid);
+	return 0;
+}
+
+static void prepare_pack(int window, int depth)
+{
+	struct object_entry **delta_list;
+	uint32_t i, nr_deltas;
+	unsigned n;
+
+	if (use_delta_islands)
+		resolve_tree_islands(the_repository, progress, &to_pack);
+
+	get_object_details();
+
+	/*
+	 * If we're locally repacking then we need to be doubly careful
+	 * from now on in order to make sure no stealth corruption gets
+	 * propagated to the new pack.  Clients receiving streamed packs
+	 * should validate everything they get anyway so no need to incur
+	 * the additional cost here in that case.
+	 */
+	if (!pack_to_stdout)
+		do_check_packed_object_crc = 1;
+
+	if (!to_pack.nr_objects || !window || !depth)
+		return;
+
+	ALLOC_ARRAY(delta_list, to_pack.nr_objects);
+	nr_deltas = n = 0;
+
+	for (i = 0; i < to_pack.nr_objects; i++) {
+		struct object_entry *entry = to_pack.objects + i;
+
+		if (DELTA(entry))
+			/* This happens if we decided to reuse existing
+			 * delta from a pack.  "reuse_delta &&" is implied.
+			 */
+			continue;
+
+		if (!entry->type_valid ||
+		    oe_size_less_than(&to_pack, entry, 50))
+			continue;
+
+		if (entry->no_try_delta)
+			continue;
+
+		if (!entry->preferred_base) {
+			nr_deltas++;
+			if (oe_type(entry) < 0)
+				die(_("unable to get type of object %s"),
+				    oid_to_hex(&entry->idx.oid));
+		} else {
+			if (oe_type(entry) < 0) {
+				/*
+				 * This object is not found, but we
+				 * don't have to include it anyway.
+				 */
+				continue;
+			}
+		}
+
+		delta_list[n++] = entry;
+	}
+
+	if (nr_deltas && n > 1) {
+		unsigned nr_done = 0;
+
+		if (progress)
+			progress_state = start_progress(the_repository,
+							_("Compressing objects"),
+							nr_deltas);
+		QSORT(delta_list, n, type_size_sort);
+		ll_find_deltas(delta_list, n, window+1, depth, &nr_done);
+		stop_progress(&progress_state);
+		if (nr_done != nr_deltas)
+			die(_("inconsistency with delta count"));
+	}
+	free(delta_list);
+}
+
+static int git_pack_config(const char *k, const char *v,
+			   const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(k, "pack.window")) {
+		window = git_config_int(k, v, ctx->kvi);
+		return 0;
+	}
+	if (!strcmp(k, "pack.windowmemory")) {
+		window_memory_limit = git_config_ulong(k, v, ctx->kvi);
+		return 0;
+	}
+	if (!strcmp(k, "pack.depth")) {
+		depth = git_config_int(k, v, ctx->kvi);
+		return 0;
+	}
+	if (!strcmp(k, "pack.deltacachesize")) {
+		max_delta_cache_size = git_config_int(k, v, ctx->kvi);
+		return 0;
+	}
+	if (!strcmp(k, "pack.deltacachelimit")) {
+		cache_max_small_delta_size = git_config_int(k, v, ctx->kvi);
+		return 0;
+	}
+	if (!strcmp(k, "pack.writebitmaphashcache")) {
+		if (git_config_bool(k, v))
+			write_bitmap_options |= BITMAP_OPT_HASH_CACHE;
+		else
+			write_bitmap_options &= ~BITMAP_OPT_HASH_CACHE;
+	}
+
+	if (!strcmp(k, "pack.writebitmaplookuptable")) {
+		if (git_config_bool(k, v))
+			write_bitmap_options |= BITMAP_OPT_LOOKUP_TABLE;
+		else
+			write_bitmap_options &= ~BITMAP_OPT_LOOKUP_TABLE;
+	}
+
+	if (!strcmp(k, "pack.usebitmaps")) {
+		use_bitmap_index_default = git_config_bool(k, v);
+		return 0;
+	}
+	if (!strcmp(k, "pack.allowpackreuse")) {
+		int res = git_parse_maybe_bool_text(v);
+		if (res < 0) {
+			if (!strcasecmp(v, "single"))
+				allow_pack_reuse = SINGLE_PACK_REUSE;
+			else if (!strcasecmp(v, "multi"))
+				allow_pack_reuse = MULTI_PACK_REUSE;
+			else
+				die(_("invalid pack.allowPackReuse value: '%s'"), v);
+		} else if (res) {
+			allow_pack_reuse = SINGLE_PACK_REUSE;
+		} else {
+			allow_pack_reuse = NO_PACK_REUSE;
+		}
+		return 0;
+	}
+	if (!strcmp(k, "pack.threads")) {
+		delta_search_threads = git_config_int(k, v, ctx->kvi);
+		if (delta_search_threads < 0)
+			die(_("invalid number of threads specified (%d)"),
+			    delta_search_threads);
+		if (!HAVE_THREADS && delta_search_threads != 1) {
+			warning(_("no threads support, ignoring %s"), k);
+			delta_search_threads = 0;
+		}
+		return 0;
+	}
+	if (!strcmp(k, "pack.indexversion")) {
+		pack_idx_opts.version = git_config_int(k, v, ctx->kvi);
+		if (pack_idx_opts.version > 2)
+			die(_("bad pack.indexVersion=%"PRIu32),
+			    pack_idx_opts.version);
+		return 0;
+	}
+	if (!strcmp(k, "pack.writereverseindex")) {
+		if (git_config_bool(k, v))
+			pack_idx_opts.flags |= WRITE_REV;
+		else
+			pack_idx_opts.flags &= ~WRITE_REV;
+		return 0;
+	}
+	if (!strcmp(k, "uploadpack.blobpackfileuri")) {
+		struct configured_exclusion *ex;
+		const char *oid_end, *pack_end;
+		/*
+		 * Stores the pack hash. This is not a true object ID, but is
+		 * of the same form.
+		 */
+		struct object_id pack_hash;
+
+		if (!v)
+			return config_error_nonbool(k);
+
+		ex = xmalloc(sizeof(*ex));
+		if (parse_oid_hex(v, &ex->e.oid, &oid_end) ||
+		    *oid_end != ' ' ||
+		    parse_oid_hex(oid_end + 1, &pack_hash, &pack_end) ||
+		    *pack_end != ' ')
+			die(_("value of uploadpack.blobpackfileuri must be "
+			      "of the form '<object-hash> <pack-hash> <uri>' (got '%s')"), v);
+		if (oidmap_get(&configured_exclusions, &ex->e.oid))
+			die(_("object already configured in another "
+			      "uploadpack.blobpackfileuri (got '%s')"), v);
+		ex->pack_hash_hex = xcalloc(1, pack_end - oid_end);
+		memcpy(ex->pack_hash_hex, oid_end + 1, pack_end - oid_end - 1);
+		ex->uri = xstrdup(pack_end + 1);
+		oidmap_put(&configured_exclusions, ex);
+	}
+	return git_default_config(k, v, ctx, cb);
+}
+
+/* Counters for trace2 output when in --stdin-packs mode. */
+static int stdin_packs_found_nr;
+static int stdin_packs_hints_nr;
+
+static int add_object_entry_from_pack(const struct object_id *oid,
+				      struct packed_git *p,
+				      uint32_t pos,
+				      void *_data)
+{
+	off_t ofs;
+	enum object_type type = OBJ_NONE;
+
+	display_progress(progress_state, ++nr_seen);
+
+	if (have_duplicate_entry(oid, 0))
+		return 0;
+
+	ofs = nth_packed_object_offset(p, pos);
+	if (!want_object_in_pack(oid, 0, &p, &ofs))
+		return 0;
+
+	if (p) {
+		struct rev_info *revs = _data;
+		struct object_info oi = OBJECT_INFO_INIT;
+
+		oi.typep = &type;
+		if (packed_object_info(the_repository, p, ofs, &oi) < 0) {
+			die(_("could not get type of object %s in pack %s"),
+			    oid_to_hex(oid), p->pack_name);
+		} else if (type == OBJ_COMMIT) {
+			/*
+			 * commits in included packs are used as starting points for the
+			 * subsequent revision walk
+			 */
+			add_pending_oid(revs, NULL, oid, 0);
+		}
+
+		stdin_packs_found_nr++;
+	}
+
+	create_object_entry(oid, type, 0, 0, 0, p, ofs);
+
+	return 0;
+}
+
+static void show_commit_pack_hint(struct commit *commit UNUSED,
+				  void *data UNUSED)
+{
+	/* nothing to do; commits don't have a namehash */
+}
+
+static void show_object_pack_hint(struct object *object, const char *name,
+				  void *data UNUSED)
+{
+	struct object_entry *oe = packlist_find(&to_pack, &object->oid);
+	if (!oe)
+		return;
+
+	/*
+	 * Our 'to_pack' list was constructed by iterating all objects packed in
+	 * included packs, and so doesn't have a non-zero hash field that you
+	 * would typically pick up during a reachability traversal.
+	 *
+	 * Make a best-effort attempt to fill in the ->hash and ->no_try_delta
+	 * here using a now in order to perhaps improve the delta selection
+	 * process.
+	 */
+	oe->hash = pack_name_hash(name);
+	oe->no_try_delta = name && no_try_delta(name);
+
+	stdin_packs_hints_nr++;
+}
+
+static int pack_mtime_cmp(const void *_a, const void *_b)
+{
+	struct packed_git *a = ((const struct string_list_item*)_a)->util;
+	struct packed_git *b = ((const struct string_list_item*)_b)->util;
+
+	/*
+	 * order packs by descending mtime so that objects are laid out
+	 * roughly as newest-to-oldest
+	 */
+	if (a->mtime < b->mtime)
+		return 1;
+	else if (b->mtime < a->mtime)
+		return -1;
+	else
+		return 0;
+}
+
+static void read_packs_list_from_stdin(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct string_list include_packs = STRING_LIST_INIT_DUP;
+	struct string_list exclude_packs = STRING_LIST_INIT_DUP;
+	struct string_list_item *item = NULL;
+
+	struct packed_git *p;
+	struct rev_info revs;
+
+	repo_init_revisions(the_repository, &revs, NULL);
+	/*
+	 * Use a revision walk to fill in the namehash of objects in the include
+	 * packs. To save time, we'll avoid traversing through objects that are
+	 * in excluded packs.
+	 *
+	 * That may cause us to avoid populating all of the namehash fields of
+	 * all included objects, but our goal is best-effort, since this is only
+	 * an optimization during delta selection.
+	 */
+	revs.no_kept_objects = 1;
+	revs.keep_pack_cache_flags |= IN_CORE_KEEP_PACKS;
+	revs.blob_objects = 1;
+	revs.tree_objects = 1;
+	revs.tag_objects = 1;
+	revs.ignore_missing_links = 1;
+
+	while (strbuf_getline(&buf, stdin) != EOF) {
+		if (!buf.len)
+			continue;
+
+		if (*buf.buf == '^')
+			string_list_append(&exclude_packs, buf.buf + 1);
+		else
+			string_list_append(&include_packs, buf.buf);
+
+		strbuf_reset(&buf);
+	}
+
+	string_list_sort(&include_packs);
+	string_list_remove_duplicates(&include_packs, 0);
+	string_list_sort(&exclude_packs);
+	string_list_remove_duplicates(&exclude_packs, 0);
+
+	for (p = get_all_packs(the_repository); p; p = p->next) {
+		const char *pack_name = pack_basename(p);
+
+		if ((item = string_list_lookup(&include_packs, pack_name)))
+			item->util = p;
+		if ((item = string_list_lookup(&exclude_packs, pack_name)))
+			item->util = p;
+	}
+
+	/*
+	 * Arguments we got on stdin may not even be packs. First
+	 * check that to avoid segfaulting later on in
+	 * e.g. pack_mtime_cmp(), excluded packs are handled below.
+	 *
+	 * Since we first parsed our STDIN and then sorted the input
+	 * lines the pack we error on will be whatever line happens to
+	 * sort first. This is lazy, it's enough that we report one
+	 * bad case here, we don't need to report the first/last one,
+	 * or all of them.
+	 */
+	for_each_string_list_item(item, &include_packs) {
+		struct packed_git *p = item->util;
+		if (!p)
+			die(_("could not find pack '%s'"), item->string);
+		if (!is_pack_valid(p))
+			die(_("packfile %s cannot be accessed"), p->pack_name);
+	}
+
+	/*
+	 * Then, handle all of the excluded packs, marking them as
+	 * kept in-core so that later calls to add_object_entry()
+	 * discards any objects that are also found in excluded packs.
+	 */
+	for_each_string_list_item(item, &exclude_packs) {
+		struct packed_git *p = item->util;
+		if (!p)
+			die(_("could not find pack '%s'"), item->string);
+		p->pack_keep_in_core = 1;
+	}
+
+	/*
+	 * Order packs by ascending mtime; use QSORT directly to access the
+	 * string_list_item's ->util pointer, which string_list_sort() does not
+	 * provide.
+	 */
+	QSORT(include_packs.items, include_packs.nr, pack_mtime_cmp);
+
+	for_each_string_list_item(item, &include_packs) {
+		struct packed_git *p = item->util;
+		for_each_object_in_pack(p,
+					add_object_entry_from_pack,
+					&revs,
+					FOR_EACH_OBJECT_PACK_ORDER);
+	}
+
+	if (prepare_revision_walk(&revs))
+		die(_("revision walk setup failed"));
+	traverse_commit_list(&revs,
+			     show_commit_pack_hint,
+			     show_object_pack_hint,
+			     NULL);
+
+	trace2_data_intmax("pack-objects", the_repository, "stdin_packs_found",
+			   stdin_packs_found_nr);
+	trace2_data_intmax("pack-objects", the_repository, "stdin_packs_hints",
+			   stdin_packs_hints_nr);
+
+	strbuf_release(&buf);
+	string_list_clear(&include_packs, 0);
+	string_list_clear(&exclude_packs, 0);
+}
+
+static void add_cruft_object_entry(const struct object_id *oid, enum object_type type,
+				   struct packed_git *pack, off_t offset,
+				   const char *name, uint32_t mtime)
+{
+	struct object_entry *entry;
+
+	display_progress(progress_state, ++nr_seen);
+
+	entry = packlist_find(&to_pack, oid);
+	if (entry) {
+		if (name) {
+			entry->hash = pack_name_hash(name);
+			entry->no_try_delta = no_try_delta(name);
+		}
+	} else {
+		if (!want_object_in_pack(oid, 0, &pack, &offset))
+			return;
+		if (!pack && type == OBJ_BLOB && !has_loose_object(oid)) {
+			/*
+			 * If a traversed tree has a missing blob then we want
+			 * to avoid adding that missing object to our pack.
+			 *
+			 * This only applies to missing blobs, not trees,
+			 * because the traversal needs to parse sub-trees but
+			 * not blobs.
+			 *
+			 * Note we only perform this check when we couldn't
+			 * already find the object in a pack, so we're really
+			 * limited to "ensure non-tip blobs which don't exist in
+			 * packs do exist via loose objects". Confused?
+			 */
+			return;
+		}
+
+		entry = create_object_entry(oid, type, pack_name_hash(name),
+					    0, name && no_try_delta(name),
+					    pack, offset);
+	}
+
+	if (mtime > oe_cruft_mtime(&to_pack, entry))
+		oe_set_cruft_mtime(&to_pack, entry, mtime);
+	return;
+}
+
+static void show_cruft_object(struct object *obj, const char *name, void *data UNUSED)
+{
+	/*
+	 * if we did not record it earlier, it's at least as old as our
+	 * expiration value. Rather than find it exactly, just use that
+	 * value.  This may bump it forward from its real mtime, but it
+	 * will still be "too old" next time we run with the same
+	 * expiration.
+	 *
+	 * if obj does appear in the packing list, this call is a noop (or may
+	 * set the namehash).
+	 */
+	add_cruft_object_entry(&obj->oid, obj->type, NULL, 0, name, cruft_expiration);
+}
+
+static void show_cruft_commit(struct commit *commit, void *data)
+{
+	show_cruft_object((struct object*)commit, NULL, data);
+}
+
+static int cruft_include_check_obj(struct object *obj, void *data UNUSED)
+{
+	return !has_object_kept_pack(to_pack.repo, &obj->oid, IN_CORE_KEEP_PACKS);
+}
+
+static int cruft_include_check(struct commit *commit, void *data)
+{
+	return cruft_include_check_obj((struct object*)commit, data);
+}
+
+static void set_cruft_mtime(const struct object *object,
+			    struct packed_git *pack,
+			    off_t offset, time_t mtime)
+{
+	add_cruft_object_entry(&object->oid, object->type, pack, offset, NULL,
+			       mtime);
+}
+
+static void mark_pack_kept_in_core(struct string_list *packs, unsigned keep)
+{
+	struct string_list_item *item = NULL;
+	for_each_string_list_item(item, packs) {
+		struct packed_git *p = item->util;
+		if (!p)
+			die(_("could not find pack '%s'"), item->string);
+		p->pack_keep_in_core = keep;
+	}
+}
+
+static void add_unreachable_loose_objects(void);
+static void add_objects_in_unpacked_packs(void);
+
+static void enumerate_cruft_objects(void)
+{
+	if (progress)
+		progress_state = start_progress(the_repository,
+						_("Enumerating cruft objects"), 0);
+
+	add_objects_in_unpacked_packs();
+	add_unreachable_loose_objects();
+
+	stop_progress(&progress_state);
+}
+
+static void enumerate_and_traverse_cruft_objects(struct string_list *fresh_packs)
+{
+	struct packed_git *p;
+	struct rev_info revs;
+	int ret;
+
+	repo_init_revisions(the_repository, &revs, NULL);
+
+	revs.tag_objects = 1;
+	revs.tree_objects = 1;
+	revs.blob_objects = 1;
+
+	revs.include_check = cruft_include_check;
+	revs.include_check_obj = cruft_include_check_obj;
+
+	revs.ignore_missing_links = 1;
+
+	if (progress)
+		progress_state = start_progress(the_repository,
+						_("Enumerating cruft objects"), 0);
+	ret = add_unseen_recent_objects_to_traversal(&revs, cruft_expiration,
+						     set_cruft_mtime, 1);
+	stop_progress(&progress_state);
+
+	if (ret)
+		die(_("unable to add cruft objects"));
+
+	/*
+	 * Re-mark only the fresh packs as kept so that objects in
+	 * unknown packs do not halt the reachability traversal early.
+	 */
+	for (p = get_all_packs(the_repository); p; p = p->next)
+		p->pack_keep_in_core = 0;
+	mark_pack_kept_in_core(fresh_packs, 1);
+
+	if (prepare_revision_walk(&revs))
+		die(_("revision walk setup failed"));
+	if (progress)
+		progress_state = start_progress(the_repository,
+						_("Traversing cruft objects"), 0);
+	nr_seen = 0;
+	traverse_commit_list(&revs, show_cruft_commit, show_cruft_object, NULL);
+
+	stop_progress(&progress_state);
+}
+
+static void read_cruft_objects(void)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct string_list discard_packs = STRING_LIST_INIT_DUP;
+	struct string_list fresh_packs = STRING_LIST_INIT_DUP;
+	struct packed_git *p;
+
+	ignore_packed_keep_in_core = 1;
+
+	while (strbuf_getline(&buf, stdin) != EOF) {
+		if (!buf.len)
+			continue;
+
+		if (*buf.buf == '-')
+			string_list_append(&discard_packs, buf.buf + 1);
+		else
+			string_list_append(&fresh_packs, buf.buf);
+	}
+
+	string_list_sort(&discard_packs);
+	string_list_sort(&fresh_packs);
+
+	for (p = get_all_packs(the_repository); p; p = p->next) {
+		const char *pack_name = pack_basename(p);
+		struct string_list_item *item;
+
+		item = string_list_lookup(&fresh_packs, pack_name);
+		if (!item)
+			item = string_list_lookup(&discard_packs, pack_name);
+
+		if (item) {
+			item->util = p;
+		} else {
+			/*
+			 * This pack wasn't mentioned in either the "fresh" or
+			 * "discard" list, so the caller didn't know about it.
+			 *
+			 * Mark it as kept so that its objects are ignored by
+			 * add_unseen_recent_objects_to_traversal(). We'll
+			 * unmark it before starting the traversal so it doesn't
+			 * halt the traversal early.
+			 */
+			p->pack_keep_in_core = 1;
+		}
+	}
+
+	mark_pack_kept_in_core(&fresh_packs, 1);
+	mark_pack_kept_in_core(&discard_packs, 0);
+
+	if (cruft_expiration)
+		enumerate_and_traverse_cruft_objects(&fresh_packs);
+	else
+		enumerate_cruft_objects();
+
+	strbuf_release(&buf);
+	string_list_clear(&discard_packs, 0);
+	string_list_clear(&fresh_packs, 0);
+}
+
+static void read_object_list_from_stdin(void)
+{
+	char line[GIT_MAX_HEXSZ + 1 + PATH_MAX + 2];
+	struct object_id oid;
+	const char *p;
+
+	for (;;) {
+		if (!fgets(line, sizeof(line), stdin)) {
+			if (feof(stdin))
+				break;
+			if (!ferror(stdin))
+				BUG("fgets returned NULL, not EOF, not error!");
+			if (errno != EINTR)
+				die_errno("fgets");
+			clearerr(stdin);
+			continue;
+		}
+		if (line[0] == '-') {
+			if (get_oid_hex(line+1, &oid))
+				die(_("expected edge object ID, got garbage:\n %s"),
+				    line);
+			add_preferred_base(&oid);
+			continue;
+		}
+		if (parse_oid_hex(line, &oid, &p))
+			die(_("expected object ID, got garbage:\n %s"), line);
+
+		add_preferred_base_object(p + 1);
+		add_object_entry(&oid, OBJ_NONE, p + 1, 0);
+	}
+}
+
+static void show_commit(struct commit *commit, void *data UNUSED)
+{
+	add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0);
+
+	if (write_bitmap_index)
+		index_commit_for_bitmap(commit);
+
+	if (use_delta_islands)
+		propagate_island_marks(commit);
+}
+
+static void show_object(struct object *obj, const char *name,
+			void *data UNUSED)
+{
+	add_preferred_base_object(name);
+	add_object_entry(&obj->oid, obj->type, name, 0);
+
+	if (use_delta_islands) {
+		const char *p;
+		unsigned depth;
+		struct object_entry *ent;
+
+		/* the empty string is a root tree, which is depth 0 */
+		depth = *name ? 1 : 0;
+		for (p = strchr(name, '/'); p; p = strchr(p + 1, '/'))
+			depth++;
+
+		ent = packlist_find(&to_pack, &obj->oid);
+		if (ent && depth > oe_tree_depth(&to_pack, ent))
+			oe_set_tree_depth(&to_pack, ent, depth);
+	}
+}
+
+static void show_object__ma_allow_any(struct object *obj, const char *name, void *data)
+{
+	assert(arg_missing_action == MA_ALLOW_ANY);
+
+	/*
+	 * Quietly ignore ALL missing objects.  This avoids problems with
+	 * staging them now and getting an odd error later.
+	 */
+	if (!has_object(the_repository, &obj->oid, 0))
+		return;
+
+	show_object(obj, name, data);
+}
+
+static void show_object__ma_allow_promisor(struct object *obj, const char *name, void *data)
+{
+	assert(arg_missing_action == MA_ALLOW_PROMISOR);
+
+	/*
+	 * Quietly ignore EXPECTED missing objects.  This avoids problems with
+	 * staging them now and getting an odd error later.
+	 */
+	if (!has_object(the_repository, &obj->oid, 0) &&
+	    is_promisor_object(to_pack.repo, &obj->oid))
+		return;
+
+	show_object(obj, name, data);
+}
+
+static int option_parse_missing_action(const struct option *opt UNUSED,
+				       const char *arg, int unset)
+{
+	assert(arg);
+	assert(!unset);
+
+	if (!strcmp(arg, "error")) {
+		arg_missing_action = MA_ERROR;
+		fn_show_object = show_object;
+		return 0;
+	}
+
+	if (!strcmp(arg, "allow-any")) {
+		arg_missing_action = MA_ALLOW_ANY;
+		fetch_if_missing = 0;
+		fn_show_object = show_object__ma_allow_any;
+		return 0;
+	}
+
+	if (!strcmp(arg, "allow-promisor")) {
+		arg_missing_action = MA_ALLOW_PROMISOR;
+		fetch_if_missing = 0;
+		fn_show_object = show_object__ma_allow_promisor;
+		return 0;
+	}
+
+	die(_("invalid value for '%s': '%s'"), "--missing", arg);
+	return 0;
+}
+
+static void show_edge(struct commit *commit)
+{
+	add_preferred_base(&commit->object.oid);
+}
+
+static int add_object_in_unpacked_pack(const struct object_id *oid,
+				       struct packed_git *pack,
+				       uint32_t pos,
+				       void *data UNUSED)
+{
+	if (cruft) {
+		off_t offset;
+		time_t mtime;
+
+		if (pack->is_cruft) {
+			if (load_pack_mtimes(pack) < 0)
+				die(_("could not load cruft pack .mtimes"));
+			mtime = nth_packed_mtime(pack, pos);
+		} else {
+			mtime = pack->mtime;
+		}
+		offset = nth_packed_object_offset(pack, pos);
+
+		add_cruft_object_entry(oid, OBJ_NONE, pack, offset,
+				       NULL, mtime);
+	} else {
+		add_object_entry(oid, OBJ_NONE, "", 0);
+	}
+	return 0;
+}
+
+static void add_objects_in_unpacked_packs(void)
+{
+	if (for_each_packed_object(to_pack.repo,
+				   add_object_in_unpacked_pack,
+				   NULL,
+				   FOR_EACH_OBJECT_PACK_ORDER |
+				   FOR_EACH_OBJECT_LOCAL_ONLY |
+				   FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
+				   FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS))
+		die(_("cannot open pack index"));
+}
+
+static int add_loose_object(const struct object_id *oid, const char *path,
+			    void *data UNUSED)
+{
+	enum object_type type = oid_object_info(the_repository, oid, NULL);
+
+	if (type < 0) {
+		warning(_("loose object at %s could not be examined"), path);
+		return 0;
+	}
+
+	if (cruft) {
+		struct stat st;
+		if (stat(path, &st) < 0) {
+			if (errno == ENOENT)
+				return 0;
+			return error_errno("unable to stat %s", oid_to_hex(oid));
+		}
+
+		add_cruft_object_entry(oid, type, NULL, 0, NULL,
+				       st.st_mtime);
+	} else {
+		add_object_entry(oid, type, "", 0);
+	}
+	return 0;
+}
+
+/*
+ * We actually don't even have to worry about reachability here.
+ * add_object_entry will weed out duplicates, so we just add every
+ * loose object we find.
+ */
+static void add_unreachable_loose_objects(void)
+{
+	for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+				      add_loose_object,
+				      NULL, NULL, NULL);
+}
+
+static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
+{
+	static struct packed_git *last_found = (void *)1;
+	struct packed_git *p;
+
+	p = (last_found != (void *)1) ? last_found :
+					get_all_packs(the_repository);
+
+	while (p) {
+		if ((!p->pack_local || p->pack_keep ||
+				p->pack_keep_in_core) &&
+			find_pack_entry_one(oid, p)) {
+			last_found = p;
+			return 1;
+		}
+		if (p == last_found)
+			p = get_all_packs(the_repository);
+		else
+			p = p->next;
+		if (p == last_found)
+			p = p->next;
+	}
+	return 0;
+}
+
+/*
+ * Store a list of sha1s that are should not be discarded
+ * because they are either written too recently, or are
+ * reachable from another object that was.
+ *
+ * This is filled by get_object_list.
+ */
+static struct oid_array recent_objects;
+
+static int loosened_object_can_be_discarded(const struct object_id *oid,
+					    timestamp_t mtime)
+{
+	if (!unpack_unreachable_expiration)
+		return 0;
+	if (mtime > unpack_unreachable_expiration)
+		return 0;
+	if (oid_array_lookup(&recent_objects, oid) >= 0)
+		return 0;
+	return 1;
+}
+
+static void loosen_unused_packed_objects(void)
+{
+	struct packed_git *p;
+	uint32_t i;
+	uint32_t loosened_objects_nr = 0;
+	struct object_id oid;
+
+	for (p = get_all_packs(the_repository); p; p = p->next) {
+		if (!p->pack_local || p->pack_keep || p->pack_keep_in_core)
+			continue;
+
+		if (open_pack_index(p))
+			die(_("cannot open pack index"));
+
+		for (i = 0; i < p->num_objects; i++) {
+			nth_packed_object_id(&oid, p, i);
+			if (!packlist_find(&to_pack, &oid) &&
+			    !has_sha1_pack_kept_or_nonlocal(&oid) &&
+			    !loosened_object_can_be_discarded(&oid, p->mtime)) {
+				if (force_object_loose(&oid, p->mtime))
+					die(_("unable to force loose object"));
+				loosened_objects_nr++;
+			}
+		}
+	}
+
+	trace2_data_intmax("pack-objects", the_repository,
+			   "loosen_unused_packed_objects/loosened", loosened_objects_nr);
+}
+
+/*
+ * This tracks any options which pack-reuse code expects to be on, or which a
+ * reader of the pack might not understand, and which would therefore prevent
+ * blind reuse of what we have on disk.
+ */
+static int pack_options_allow_reuse(void)
+{
+	return allow_pack_reuse != NO_PACK_REUSE &&
+	       pack_to_stdout &&
+	       !ignore_packed_keep_on_disk &&
+	       !ignore_packed_keep_in_core &&
+	       (!local || !have_non_local_packs) &&
+	       !incremental;
+}
+
+static int get_object_list_from_bitmap(struct rev_info *revs)
+{
+	if (!(bitmap_git = prepare_bitmap_walk(revs, 0)))
+		return -1;
+
+	if (pack_options_allow_reuse())
+		reuse_partial_packfile_from_bitmap(bitmap_git,
+						   &reuse_packfiles,
+						   &reuse_packfiles_nr,
+						   &reuse_packfile_bitmap,
+						   allow_pack_reuse == MULTI_PACK_REUSE);
+
+	if (reuse_packfiles) {
+		reuse_packfile_objects = bitmap_popcount(reuse_packfile_bitmap);
+		if (!reuse_packfile_objects)
+			BUG("expected non-empty reuse bitmap");
+
+		nr_result += reuse_packfile_objects;
+		nr_seen += reuse_packfile_objects;
+		display_progress(progress_state, nr_seen);
+	}
+
+	traverse_bitmap_commit_list(bitmap_git, revs,
+				    &add_object_entry_from_bitmap);
+	return 0;
+}
+
+static void record_recent_object(struct object *obj,
+				 const char *name UNUSED,
+				 void *data UNUSED)
+{
+	oid_array_append(&recent_objects, &obj->oid);
+}
+
+static void record_recent_commit(struct commit *commit, void *data UNUSED)
+{
+	oid_array_append(&recent_objects, &commit->object.oid);
+}
+
+static int mark_bitmap_preferred_tip(const char *refname,
+				     const char *referent UNUSED,
+				     const struct object_id *oid,
+				     int flags UNUSED,
+				     void *data UNUSED)
+{
+	struct object_id peeled;
+	struct object *object;
+
+	if (!peel_iterated_oid(the_repository, oid, &peeled))
+		oid = &peeled;
+
+	object = parse_object_or_die(oid, refname);
+	if (object->type == OBJ_COMMIT)
+		object->flags |= NEEDS_BITMAP;
+
+	return 0;
+}
+
+static void mark_bitmap_preferred_tips(void)
+{
+	struct string_list_item *item;
+	const struct string_list *preferred_tips;
+
+	preferred_tips = bitmap_preferred_tips(the_repository);
+	if (!preferred_tips)
+		return;
+
+	for_each_string_list_item(item, preferred_tips) {
+		refs_for_each_ref_in(get_main_ref_store(the_repository),
+				     item->string, mark_bitmap_preferred_tip,
+				     NULL);
+	}
+}
+
+static void get_object_list(struct rev_info *revs, int ac, const char **av)
+{
+	struct setup_revision_opt s_r_opt = {
+		.allow_exclude_promisor_objects = 1,
+	};
+	char line[1000];
+	int flags = 0;
+	int save_warning;
+
+	save_commit_buffer = 0;
+	setup_revisions(ac, av, revs, &s_r_opt);
+
+	/* make sure shallows are read */
+	is_repository_shallow(the_repository);
+
+	save_warning = warn_on_object_refname_ambiguity;
+	warn_on_object_refname_ambiguity = 0;
+
+	while (fgets(line, sizeof(line), stdin) != NULL) {
+		int len = strlen(line);
+		if (len && line[len - 1] == '\n')
+			line[--len] = 0;
+		if (!len)
+			break;
+		if (*line == '-') {
+			if (!strcmp(line, "--not")) {
+				flags ^= UNINTERESTING;
+				write_bitmap_index = 0;
+				continue;
+			}
+			if (starts_with(line, "--shallow ")) {
+				struct object_id oid;
+				if (get_oid_hex(line + 10, &oid))
+					die("not an object name '%s'", line + 10);
+				register_shallow(the_repository, &oid);
+				use_bitmap_index = 0;
+				continue;
+			}
+			die(_("not a rev '%s'"), line);
+		}
+		if (handle_revision_arg(line, revs, flags, REVARG_CANNOT_BE_FILENAME))
+			die(_("bad revision '%s'"), line);
+	}
+
+	warn_on_object_refname_ambiguity = save_warning;
+
+	if (use_bitmap_index && !get_object_list_from_bitmap(revs))
+		return;
+
+	if (use_delta_islands)
+		load_delta_islands(the_repository, progress);
+
+	if (write_bitmap_index)
+		mark_bitmap_preferred_tips();
+
+	if (prepare_revision_walk(revs))
+		die(_("revision walk setup failed"));
+	mark_edges_uninteresting(revs, show_edge, sparse);
+
+	if (!fn_show_object)
+		fn_show_object = show_object;
+	traverse_commit_list(revs,
+			     show_commit, fn_show_object,
+			     NULL);
+
+	if (unpack_unreachable_expiration) {
+		revs->ignore_missing_links = 1;
+		if (add_unseen_recent_objects_to_traversal(revs,
+				unpack_unreachable_expiration, NULL, 0))
+			die(_("unable to add recent objects"));
+		if (prepare_revision_walk(revs))
+			die(_("revision walk setup failed"));
+		traverse_commit_list(revs, record_recent_commit,
+				     record_recent_object, NULL);
+	}
+
+	if (keep_unreachable)
+		add_objects_in_unpacked_packs();
+	if (pack_loose_unreachable)
+		add_unreachable_loose_objects();
+	if (unpack_unreachable)
+		loosen_unused_packed_objects();
+
+	oid_array_clear(&recent_objects);
+}
+
+static void add_extra_kept_packs(const struct string_list *names)
+{
+	struct packed_git *p;
+
+	if (!names->nr)
+		return;
+
+	for (p = get_all_packs(the_repository); p; p = p->next) {
+		const char *name = basename(p->pack_name);
+		int i;
+
+		if (!p->pack_local)
+			continue;
+
+		for (i = 0; i < names->nr; i++)
+			if (!fspathcmp(name, names->items[i].string))
+				break;
+
+		if (i < names->nr) {
+			p->pack_keep_in_core = 1;
+			ignore_packed_keep_in_core = 1;
+			continue;
+		}
+	}
+}
+
+static int option_parse_quiet(const struct option *opt, const char *arg,
+			      int unset)
+{
+	int *val = opt->value;
+
+	BUG_ON_OPT_ARG(arg);
+
+	if (!unset)
+		*val = 0;
+	else if (!*val)
+		*val = 1;
+	return 0;
+}
+
+static int option_parse_index_version(const struct option *opt,
+				      const char *arg, int unset)
+{
+	struct pack_idx_option *popts = opt->value;
+	char *c;
+	const char *val = arg;
+
+	BUG_ON_OPT_NEG(unset);
+
+	popts->version = strtoul(val, &c, 10);
+	if (popts->version > 2)
+		die(_("unsupported index version %s"), val);
+	if (*c == ',' && c[1])
+		popts->off32_limit = strtoul(c+1, &c, 0);
+	if (*c || popts->off32_limit & 0x80000000)
+		die(_("bad index version '%s'"), val);
+	return 0;
+}
+
+static int option_parse_unpack_unreachable(const struct option *opt UNUSED,
+					   const char *arg, int unset)
+{
+	if (unset) {
+		unpack_unreachable = 0;
+		unpack_unreachable_expiration = 0;
+	}
+	else {
+		unpack_unreachable = 1;
+		if (arg)
+			unpack_unreachable_expiration = approxidate(arg);
+	}
+	return 0;
+}
+
+static int option_parse_cruft_expiration(const struct option *opt UNUSED,
+					 const char *arg, int unset)
+{
+	if (unset) {
+		cruft = 0;
+		cruft_expiration = 0;
+	} else {
+		cruft = 1;
+		if (arg)
+			cruft_expiration = approxidate(arg);
+	}
+	return 0;
+}
+
+static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
+{
+	struct object_info info = OBJECT_INFO_INIT;
+	if (oid_object_info_extended(the_repository, &obj->oid, &info, 0))
+		BUG("should_include_obj should only be called on existing objects");
+	return info.whence != OI_PACKED || !info.u.packed.pack->pack_promisor;
+}
+
+static int is_not_in_promisor_pack(struct commit *commit, void *data) {
+	return is_not_in_promisor_pack_obj((struct object *) commit, data);
+}
+
+int cmd_pack_objects(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	int use_internal_rev_list = 0;
+	int shallow = 0;
+	int all_progress_implied = 0;
+	struct strvec rp = STRVEC_INIT;
+	int rev_list_unpacked = 0, rev_list_all = 0, rev_list_reflog = 0;
+	int rev_list_index = 0;
+	int stdin_packs = 0;
+	struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
+	struct list_objects_filter_options filter_options =
+		LIST_OBJECTS_FILTER_INIT;
+
+	struct option pack_objects_options[] = {
+		OPT_CALLBACK_F('q', "quiet", &progress, NULL,
+			       N_("do not show progress meter"),
+			       PARSE_OPT_NOARG, option_parse_quiet),
+		OPT_SET_INT(0, "progress", &progress,
+			    N_("show progress meter"), 1),
+		OPT_SET_INT(0, "all-progress", &progress,
+			    N_("show progress meter during object writing phase"), 2),
+		OPT_BOOL(0, "all-progress-implied",
+			 &all_progress_implied,
+			 N_("similar to --all-progress when progress meter is shown")),
+		OPT_CALLBACK_F(0, "index-version", &pack_idx_opts, N_("<version>[,<offset>]"),
+		  N_("write the pack index file in the specified idx format version"),
+		  PARSE_OPT_NONEG, option_parse_index_version),
+		OPT_MAGNITUDE(0, "max-pack-size", &pack_size_limit,
+			      N_("maximum size of each output pack file")),
+		OPT_BOOL(0, "local", &local,
+			 N_("ignore borrowed objects from alternate object store")),
+		OPT_BOOL(0, "incremental", &incremental,
+			 N_("ignore packed objects")),
+		OPT_INTEGER(0, "window", &window,
+			    N_("limit pack window by objects")),
+		OPT_MAGNITUDE(0, "window-memory", &window_memory_limit,
+			      N_("limit pack window by memory in addition to object limit")),
+		OPT_INTEGER(0, "depth", &depth,
+			    N_("maximum length of delta chain allowed in the resulting pack")),
+		OPT_BOOL(0, "reuse-delta", &reuse_delta,
+			 N_("reuse existing deltas")),
+		OPT_BOOL(0, "reuse-object", &reuse_object,
+			 N_("reuse existing objects")),
+		OPT_BOOL(0, "delta-base-offset", &allow_ofs_delta,
+			 N_("use OFS_DELTA objects")),
+		OPT_INTEGER(0, "threads", &delta_search_threads,
+			    N_("use threads when searching for best delta matches")),
+		OPT_BOOL(0, "non-empty", &non_empty,
+			 N_("do not create an empty pack output")),
+		OPT_BOOL(0, "revs", &use_internal_rev_list,
+			 N_("read revision arguments from standard input")),
+		OPT_SET_INT_F(0, "unpacked", &rev_list_unpacked,
+			      N_("limit the objects to those that are not yet packed"),
+			      1, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "all", &rev_list_all,
+			      N_("include objects reachable from any reference"),
+			      1, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "reflog", &rev_list_reflog,
+			      N_("include objects referred by reflog entries"),
+			      1, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "indexed-objects", &rev_list_index,
+			      N_("include objects referred to by the index"),
+			      1, PARSE_OPT_NONEG),
+		OPT_BOOL(0, "stdin-packs", &stdin_packs,
+			 N_("read packs from stdin")),
+		OPT_BOOL(0, "stdout", &pack_to_stdout,
+			 N_("output pack to stdout")),
+		OPT_BOOL(0, "include-tag", &include_tag,
+			 N_("include tag objects that refer to objects to be packed")),
+		OPT_BOOL(0, "keep-unreachable", &keep_unreachable,
+			 N_("keep unreachable objects")),
+		OPT_BOOL(0, "pack-loose-unreachable", &pack_loose_unreachable,
+			 N_("pack loose unreachable objects")),
+		OPT_CALLBACK_F(0, "unpack-unreachable", NULL, N_("time"),
+		  N_("unpack unreachable objects newer than <time>"),
+		  PARSE_OPT_OPTARG, option_parse_unpack_unreachable),
+		OPT_BOOL(0, "cruft", &cruft, N_("create a cruft pack")),
+		OPT_CALLBACK_F(0, "cruft-expiration", NULL, N_("time"),
+		  N_("expire cruft objects older than <time>"),
+		  PARSE_OPT_OPTARG, option_parse_cruft_expiration),
+		OPT_BOOL(0, "sparse", &sparse,
+			 N_("use the sparse reachability algorithm")),
+		OPT_BOOL(0, "thin", &thin,
+			 N_("create thin packs")),
+		OPT_BOOL(0, "shallow", &shallow,
+			 N_("create packs suitable for shallow fetches")),
+		OPT_BOOL(0, "honor-pack-keep", &ignore_packed_keep_on_disk,
+			 N_("ignore packs that have companion .keep file")),
+		OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
+				N_("ignore this pack")),
+		OPT_INTEGER(0, "compression", &pack_compression_level,
+			    N_("pack compression level")),
+		OPT_BOOL(0, "keep-true-parents", &grafts_keep_true_parents,
+			 N_("do not hide commits by grafts")),
+		OPT_BOOL(0, "use-bitmap-index", &use_bitmap_index,
+			 N_("use a bitmap index if available to speed up counting objects")),
+		OPT_SET_INT(0, "write-bitmap-index", &write_bitmap_index,
+			    N_("write a bitmap index together with the pack index"),
+			    WRITE_BITMAP_TRUE),
+		OPT_SET_INT_F(0, "write-bitmap-index-quiet",
+			      &write_bitmap_index,
+			      N_("write a bitmap index if possible"),
+			      WRITE_BITMAP_QUIET, PARSE_OPT_HIDDEN),
+		OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+		OPT_CALLBACK_F(0, "missing", NULL, N_("action"),
+		  N_("handling for missing objects"), PARSE_OPT_NONEG,
+		  option_parse_missing_action),
+		OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
+			 N_("do not pack objects in promisor packfiles")),
+		OPT_BOOL(0, "exclude-promisor-objects-best-effort",
+			 &exclude_promisor_objects_best_effort,
+			 N_("implies --missing=allow-any")),
+		OPT_BOOL(0, "delta-islands", &use_delta_islands,
+			 N_("respect islands during delta compression")),
+		OPT_STRING_LIST(0, "uri-protocol", &uri_protocols,
+				N_("protocol"),
+				N_("exclude any configured uploadpack.blobpackfileuri with this protocol")),
+		OPT_END(),
+	};
+
+	if (DFS_NUM_STATES > (1 << OE_DFS_STATE_BITS))
+		BUG("too many dfs states, increase OE_DFS_STATE_BITS");
+
+	disable_replace_refs();
+
+	sparse = git_env_bool("GIT_TEST_PACK_SPARSE", -1);
+	if (the_repository->gitdir) {
+		prepare_repo_settings(the_repository);
+		if (sparse < 0)
+			sparse = the_repository->settings.pack_use_sparse;
+		if (the_repository->settings.pack_use_multi_pack_reuse)
+			allow_pack_reuse = MULTI_PACK_REUSE;
+	}
+
+	reset_pack_idx_option(&pack_idx_opts);
+	pack_idx_opts.flags |= WRITE_REV;
+	git_config(git_pack_config, NULL);
+	if (git_env_bool(GIT_TEST_NO_WRITE_REV_INDEX, 0))
+		pack_idx_opts.flags &= ~WRITE_REV;
+
+	progress = isatty(2);
+	argc = parse_options(argc, argv, prefix, pack_objects_options,
+			     pack_usage, 0);
+
+	if (argc) {
+		base_name = argv[0];
+		argc--;
+	}
+	if (pack_to_stdout != !base_name || argc)
+		usage_with_options(pack_usage, pack_objects_options);
+
+	if (depth < 0)
+		depth = 0;
+	if (depth >= (1 << OE_DEPTH_BITS)) {
+		warning(_("delta chain depth %d is too deep, forcing %d"),
+			depth, (1 << OE_DEPTH_BITS) - 1);
+		depth = (1 << OE_DEPTH_BITS) - 1;
+	}
+	if (cache_max_small_delta_size >= (1U << OE_Z_DELTA_BITS)) {
+		warning(_("pack.deltaCacheLimit is too high, forcing %d"),
+			(1U << OE_Z_DELTA_BITS) - 1);
+		cache_max_small_delta_size = (1U << OE_Z_DELTA_BITS) - 1;
+	}
+	if (window < 0)
+		window = 0;
+
+	strvec_push(&rp, "pack-objects");
+	if (thin) {
+		use_internal_rev_list = 1;
+		strvec_push(&rp, shallow
+				? "--objects-edge-aggressive"
+				: "--objects-edge");
+	} else
+		strvec_push(&rp, "--objects");
+
+	if (rev_list_all) {
+		use_internal_rev_list = 1;
+		strvec_push(&rp, "--all");
+	}
+	if (rev_list_reflog) {
+		use_internal_rev_list = 1;
+		strvec_push(&rp, "--reflog");
+	}
+	if (rev_list_index) {
+		use_internal_rev_list = 1;
+		strvec_push(&rp, "--indexed-objects");
+	}
+	if (rev_list_unpacked && !stdin_packs) {
+		use_internal_rev_list = 1;
+		strvec_push(&rp, "--unpacked");
+	}
+
+	if (exclude_promisor_objects && exclude_promisor_objects_best_effort)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--exclude-promisor-objects", "--exclude-promisor-objects-best-effort");
+	if (exclude_promisor_objects) {
+		use_internal_rev_list = 1;
+		fetch_if_missing = 0;
+		strvec_push(&rp, "--exclude-promisor-objects");
+	} else if (exclude_promisor_objects_best_effort) {
+		use_internal_rev_list = 1;
+		fetch_if_missing = 0;
+		option_parse_missing_action(NULL, "allow-any", 0);
+		/* revs configured below */
+	}
+	if (unpack_unreachable || keep_unreachable || pack_loose_unreachable)
+		use_internal_rev_list = 1;
+
+	if (!reuse_object)
+		reuse_delta = 0;
+	if (pack_compression_level == -1)
+		pack_compression_level = Z_DEFAULT_COMPRESSION;
+	else if (pack_compression_level < 0 || pack_compression_level > Z_BEST_COMPRESSION)
+		die(_("bad pack compression level %d"), pack_compression_level);
+
+	if (!delta_search_threads)	/* --threads=0 means autodetect */
+		delta_search_threads = online_cpus();
+
+	if (!HAVE_THREADS && delta_search_threads != 1)
+		warning(_("no threads support, ignoring --threads"));
+	if (!pack_to_stdout && !pack_size_limit)
+		pack_size_limit = pack_size_limit_cfg;
+	if (pack_to_stdout && pack_size_limit)
+		die(_("--max-pack-size cannot be used to build a pack for transfer"));
+	if (pack_size_limit && pack_size_limit < 1024*1024) {
+		warning(_("minimum pack size limit is 1 MiB"));
+		pack_size_limit = 1024*1024;
+	}
+
+	if (!pack_to_stdout && thin)
+		die(_("--thin cannot be used to build an indexable pack"));
+
+	if (keep_unreachable && unpack_unreachable)
+		die(_("options '%s' and '%s' cannot be used together"), "--keep-unreachable", "--unpack-unreachable");
+	if (!rev_list_all || !rev_list_reflog || !rev_list_index)
+		unpack_unreachable_expiration = 0;
+
+	if (stdin_packs && filter_options.choice)
+		die(_("cannot use --filter with --stdin-packs"));
+
+	if (stdin_packs && use_internal_rev_list)
+		die(_("cannot use internal rev list with --stdin-packs"));
+
+	if (cruft) {
+		if (use_internal_rev_list)
+			die(_("cannot use internal rev list with --cruft"));
+		if (stdin_packs)
+			die(_("cannot use --stdin-packs with --cruft"));
+	}
+
+	/*
+	 * "soft" reasons not to use bitmaps - for on-disk repack by default we want
+	 *
+	 * - to produce good pack (with bitmap index not-yet-packed objects are
+	 *   packed in suboptimal order).
+	 *
+	 * - to use more robust pack-generation codepath (avoiding possible
+	 *   bugs in bitmap code and possible bitmap index corruption).
+	 */
+	if (!pack_to_stdout)
+		use_bitmap_index_default = 0;
+
+	if (use_bitmap_index < 0)
+		use_bitmap_index = use_bitmap_index_default;
+
+	/* "hard" reasons not to use bitmaps; these just won't work at all */
+	if (!use_internal_rev_list || (!pack_to_stdout && write_bitmap_index) || is_repository_shallow(the_repository))
+		use_bitmap_index = 0;
+
+	if (pack_to_stdout || !rev_list_all)
+		write_bitmap_index = 0;
+
+	if (use_delta_islands)
+		strvec_push(&rp, "--topo-order");
+
+	if (progress && all_progress_implied)
+		progress = 2;
+
+	add_extra_kept_packs(&keep_pack_list);
+	if (ignore_packed_keep_on_disk) {
+		struct packed_git *p;
+		for (p = get_all_packs(the_repository); p; p = p->next)
+			if (p->pack_local && p->pack_keep)
+				break;
+		if (!p) /* no keep-able packs found */
+			ignore_packed_keep_on_disk = 0;
+	}
+	if (local) {
+		/*
+		 * unlike ignore_packed_keep_on_disk above, we do not
+		 * want to unset "local" based on looking at packs, as
+		 * it also covers non-local objects
+		 */
+		struct packed_git *p;
+		for (p = get_all_packs(the_repository); p; p = p->next) {
+			if (!p->pack_local) {
+				have_non_local_packs = 1;
+				break;
+			}
+		}
+	}
+
+	trace2_region_enter("pack-objects", "enumerate-objects",
+			    the_repository);
+	prepare_packing_data(the_repository, &to_pack);
+
+	if (progress && !cruft)
+		progress_state = start_progress(the_repository,
+						_("Enumerating objects"), 0);
+	if (stdin_packs) {
+		/* avoids adding objects in excluded packs */
+		ignore_packed_keep_in_core = 1;
+		read_packs_list_from_stdin();
+		if (rev_list_unpacked)
+			add_unreachable_loose_objects();
+	} else if (cruft) {
+		read_cruft_objects();
+	} else if (!use_internal_rev_list) {
+		read_object_list_from_stdin();
+	} else {
+		struct rev_info revs;
+
+		repo_init_revisions(the_repository, &revs, NULL);
+		list_objects_filter_copy(&revs.filter, &filter_options);
+		if (exclude_promisor_objects_best_effort) {
+			revs.include_check = is_not_in_promisor_pack;
+			revs.include_check_obj = is_not_in_promisor_pack_obj;
+		}
+		get_object_list(&revs, rp.nr, rp.v);
+		release_revisions(&revs);
+	}
+	cleanup_preferred_base();
+	if (include_tag && nr_result)
+		refs_for_each_tag_ref(get_main_ref_store(the_repository),
+				      add_ref_tag, NULL);
+	stop_progress(&progress_state);
+	trace2_region_leave("pack-objects", "enumerate-objects",
+			    the_repository);
+
+	if (non_empty && !nr_result)
+		goto cleanup;
+	if (nr_result) {
+		trace2_region_enter("pack-objects", "prepare-pack",
+				    the_repository);
+		prepare_pack(window, depth);
+		trace2_region_leave("pack-objects", "prepare-pack",
+				    the_repository);
+	}
+
+	trace2_region_enter("pack-objects", "write-pack-file", the_repository);
+	write_excluded_by_configs();
+	write_pack_file();
+	trace2_region_leave("pack-objects", "write-pack-file", the_repository);
+
+	if (progress)
+		fprintf_ln(stderr,
+			   _("Total %"PRIu32" (delta %"PRIu32"),"
+			     " reused %"PRIu32" (delta %"PRIu32"),"
+			     " pack-reused %"PRIu32" (from %"PRIuMAX")"),
+			   written, written_delta, reused, reused_delta,
+			   reuse_packfile_objects,
+			   (uintmax_t)reuse_packfiles_used_nr);
+
+	trace2_data_intmax("pack-objects", the_repository, "written", written);
+	trace2_data_intmax("pack-objects", the_repository, "written/delta", written_delta);
+	trace2_data_intmax("pack-objects", the_repository, "reused", reused);
+	trace2_data_intmax("pack-objects", the_repository, "reused/delta", reused_delta);
+	trace2_data_intmax("pack-objects", the_repository, "pack-reused", reuse_packfile_objects);
+	trace2_data_intmax("pack-objects", the_repository, "packs-reused", reuse_packfiles_used_nr);
+
+cleanup:
+	clear_packing_data(&to_pack);
+	list_objects_filter_release(&filter_options);
+	string_list_clear(&keep_pack_list, 0);
+	strvec_clear(&rp);
+
+	return 0;
+}
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
new file mode 100644
index 0000000000..3febe732f8
--- /dev/null
+++ b/builtin/pack-redundant.c
@@ -0,0 +1,705 @@
+/*
+*
+* Copyright 2005, Lukas Sandstrom <lukass@xxxxxxxxxxxxxxxx>
+*
+* This file is licensed under the GPL v2.
+*
+*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "gettext.h"
+#include "hex.h"
+
+#include "packfile.h"
+#include "object-store-ll.h"
+#include "strbuf.h"
+
+#define BLKSIZE 512
+
+static const char pack_redundant_usage[] =
+"git pack-redundant [--verbose] [--alt-odb] (--all | <pack-filename>...)";
+
+static int load_all_packs, verbose, alt_odb;
+
+struct llist_item {
+	struct llist_item *next;
+	struct object_id oid;
+};
+static struct llist {
+	struct llist_item *front;
+	struct llist_item *back;
+	size_t size;
+} *all_objects; /* all objects which must be present in local packfiles */
+
+static struct pack_list {
+	struct pack_list *next;
+	struct packed_git *pack;
+	struct llist *unique_objects;
+	struct llist *remaining_objects;
+	size_t all_objects_size;
+} *local_packs = NULL, *altodb_packs = NULL;
+
+static struct llist_item *free_nodes;
+
+static inline void llist_item_put(struct llist_item *item)
+{
+	item->next = free_nodes;
+	free_nodes = item;
+}
+
+static inline struct llist_item *llist_item_get(void)
+{
+	struct llist_item *new_item;
+	if ( free_nodes ) {
+		new_item = free_nodes;
+		free_nodes = free_nodes->next;
+	} else {
+		int i = 1;
+		ALLOC_ARRAY(new_item, BLKSIZE);
+		for (; i < BLKSIZE; i++)
+			llist_item_put(&new_item[i]);
+	}
+	return new_item;
+}
+
+static inline void llist_init(struct llist **list)
+{
+	*list = xmalloc(sizeof(struct llist));
+	(*list)->front = (*list)->back = NULL;
+	(*list)->size = 0;
+}
+
+static void llist_free(struct llist *list)
+{
+	for (struct llist_item *i = list->front, *next; i; i = next) {
+		next = i->next;
+		llist_item_put(i);
+	}
+	free(list);
+}
+
+static struct llist * llist_copy(struct llist *list)
+{
+	struct llist *ret;
+	struct llist_item *new_item, *old_item, *prev;
+
+	llist_init(&ret);
+
+	if ((ret->size = list->size) == 0)
+		return ret;
+
+	new_item = ret->front = llist_item_get();
+	new_item->oid = list->front->oid;
+
+	old_item = list->front->next;
+	while (old_item) {
+		prev = new_item;
+		new_item = llist_item_get();
+		prev->next = new_item;
+		new_item->oid = old_item->oid;
+		old_item = old_item->next;
+	}
+	new_item->next = NULL;
+	ret->back = new_item;
+
+	return ret;
+}
+
+static inline struct llist_item *llist_insert(struct llist *list,
+					      struct llist_item *after,
+					      const unsigned char *oid)
+{
+	struct llist_item *new_item = llist_item_get();
+	oidread(&new_item->oid, oid, the_repository->hash_algo);
+	new_item->next = NULL;
+
+	if (after) {
+		new_item->next = after->next;
+		after->next = new_item;
+		if (after == list->back)
+			list->back = new_item;
+	} else {/* insert in front */
+		if (list->size == 0)
+			list->back = new_item;
+		else
+			new_item->next = list->front;
+		list->front = new_item;
+	}
+	list->size++;
+	return new_item;
+}
+
+static inline struct llist_item *llist_insert_back(struct llist *list,
+						   const unsigned char *oid)
+{
+	return llist_insert(list, list->back, oid);
+}
+
+static inline struct llist_item *llist_insert_sorted_unique(struct llist *list,
+			const struct object_id *oid, struct llist_item *hint)
+{
+	struct llist_item *prev = NULL, *l;
+
+	l = (hint == NULL) ? list->front : hint;
+	while (l) {
+		int cmp = oidcmp(&l->oid, oid);
+		if (cmp > 0) { /* we insert before this entry */
+			return llist_insert(list, prev, oid->hash);
+		}
+		if (!cmp) { /* already exists */
+			return l;
+		}
+		prev = l;
+		l = l->next;
+	}
+	/* insert at the end */
+	return llist_insert_back(list, oid->hash);
+}
+
+/* returns a pointer to an item in front of sha1 */
+static inline struct llist_item * llist_sorted_remove(struct llist *list, const unsigned char *oid, struct llist_item *hint)
+{
+	struct llist_item *prev, *l;
+
+redo_from_start:
+	l = (hint == NULL) ? list->front : hint;
+	prev = NULL;
+	while (l) {
+		const int cmp = hashcmp(l->oid.hash, oid, the_repository->hash_algo);
+		if (cmp > 0) /* not in list, since sorted */
+			return prev;
+		if (!cmp) { /* found */
+			if (!prev) {
+				if (hint != NULL && hint != list->front) {
+					/* we don't know the previous element */
+					hint = NULL;
+					goto redo_from_start;
+				}
+				list->front = l->next;
+			} else
+				prev->next = l->next;
+			if (l == list->back)
+				list->back = prev;
+			llist_item_put(l);
+			list->size--;
+			return prev;
+		}
+		prev = l;
+		l = l->next;
+	}
+	return prev;
+}
+
+/* computes A\B */
+static void llist_sorted_difference_inplace(struct llist *A,
+				     struct llist *B)
+{
+	struct llist_item *hint, *b;
+
+	hint = NULL;
+	b = B->front;
+
+	while (b) {
+		hint = llist_sorted_remove(A, b->oid.hash, hint);
+		b = b->next;
+	}
+}
+
+static inline struct pack_list * pack_list_insert(struct pack_list **pl,
+					   struct pack_list *entry)
+{
+	struct pack_list *p = xmalloc(sizeof(struct pack_list));
+	memcpy(p, entry, sizeof(struct pack_list));
+	p->next = *pl;
+	*pl = p;
+	return p;
+}
+
+static void pack_list_free(struct pack_list *pl)
+{
+	for (struct pack_list *next; pl; pl = next) {
+		next = pl->next;
+		free(pl);
+	}
+}
+
+static inline size_t pack_list_size(struct pack_list *pl)
+{
+	size_t ret = 0;
+	while (pl) {
+		ret++;
+		pl = pl->next;
+	}
+	return ret;
+}
+
+static struct pack_list * pack_list_difference(const struct pack_list *A,
+					       const struct pack_list *B)
+{
+	struct pack_list *ret;
+	const struct pack_list *pl;
+
+	if (!A)
+		return NULL;
+
+	pl = B;
+	while (pl != NULL) {
+		if (A->pack == pl->pack)
+			return pack_list_difference(A->next, B);
+		pl = pl->next;
+	}
+	ret = xmalloc(sizeof(struct pack_list));
+	memcpy(ret, A, sizeof(struct pack_list));
+	ret->next = pack_list_difference(A->next, B);
+	return ret;
+}
+
+static void cmp_two_packs(struct pack_list *p1, struct pack_list *p2)
+{
+	size_t p1_off = 0, p2_off = 0, p1_step, p2_step;
+	const unsigned char *p1_base, *p2_base;
+	struct llist_item *p1_hint = NULL, *p2_hint = NULL;
+	const unsigned int hashsz = the_hash_algo->rawsz;
+
+	if (!p1->unique_objects)
+		p1->unique_objects = llist_copy(p1->remaining_objects);
+	if (!p2->unique_objects)
+		p2->unique_objects = llist_copy(p2->remaining_objects);
+
+	p1_base = p1->pack->index_data;
+	p2_base = p2->pack->index_data;
+	p1_base += 256 * 4 + ((p1->pack->index_version < 2) ? 4 : 8);
+	p2_base += 256 * 4 + ((p2->pack->index_version < 2) ? 4 : 8);
+	p1_step = hashsz + ((p1->pack->index_version < 2) ? 4 : 0);
+	p2_step = hashsz + ((p2->pack->index_version < 2) ? 4 : 0);
+
+	while (p1_off < p1->pack->num_objects * p1_step &&
+	       p2_off < p2->pack->num_objects * p2_step)
+	{
+		const int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off,
+					the_repository->hash_algo);
+		/* cmp ~ p1 - p2 */
+		if (cmp == 0) {
+			p1_hint = llist_sorted_remove(p1->unique_objects,
+					p1_base + p1_off,
+					p1_hint);
+			p2_hint = llist_sorted_remove(p2->unique_objects,
+					p1_base + p1_off,
+					p2_hint);
+			p1_off += p1_step;
+			p2_off += p2_step;
+			continue;
+		}
+		if (cmp < 0) { /* p1 has the object, p2 doesn't */
+			p1_off += p1_step;
+		} else { /* p2 has the object, p1 doesn't */
+			p2_off += p2_step;
+		}
+	}
+}
+
+static size_t sizeof_union(struct packed_git *p1, struct packed_git *p2)
+{
+	size_t ret = 0;
+	size_t p1_off = 0, p2_off = 0, p1_step, p2_step;
+	const unsigned char *p1_base, *p2_base;
+	const unsigned int hashsz = the_hash_algo->rawsz;
+
+	p1_base = p1->index_data;
+	p2_base = p2->index_data;
+	p1_base += 256 * 4 + ((p1->index_version < 2) ? 4 : 8);
+	p2_base += 256 * 4 + ((p2->index_version < 2) ? 4 : 8);
+	p1_step = hashsz + ((p1->index_version < 2) ? 4 : 0);
+	p2_step = hashsz + ((p2->index_version < 2) ? 4 : 0);
+
+	while (p1_off < p1->num_objects * p1_step &&
+	       p2_off < p2->num_objects * p2_step)
+	{
+		int cmp = hashcmp(p1_base + p1_off, p2_base + p2_off,
+				  the_repository->hash_algo);
+		/* cmp ~ p1 - p2 */
+		if (cmp == 0) {
+			ret++;
+			p1_off += p1_step;
+			p2_off += p2_step;
+			continue;
+		}
+		if (cmp < 0) { /* p1 has the object, p2 doesn't */
+			p1_off += p1_step;
+		} else { /* p2 has the object, p1 doesn't */
+			p2_off += p2_step;
+		}
+	}
+	return ret;
+}
+
+/* another O(n^2) function ... */
+static size_t get_pack_redundancy(struct pack_list *pl)
+{
+	struct pack_list *subset;
+	size_t ret = 0;
+
+	if (!pl)
+		return 0;
+
+	while ((subset = pl->next)) {
+		while (subset) {
+			ret += sizeof_union(pl->pack, subset->pack);
+			subset = subset->next;
+		}
+		pl = pl->next;
+	}
+	return ret;
+}
+
+static inline off_t pack_set_bytecount(struct pack_list *pl)
+{
+	off_t ret = 0;
+	while (pl) {
+		ret += pl->pack->pack_size;
+		ret += pl->pack->index_size;
+		pl = pl->next;
+	}
+	return ret;
+}
+
+static int cmp_remaining_objects(const void *a, const void *b)
+{
+	struct pack_list *pl_a = *((struct pack_list **)a);
+	struct pack_list *pl_b = *((struct pack_list **)b);
+
+	if (pl_a->remaining_objects->size == pl_b->remaining_objects->size) {
+		/* have the same remaining_objects, big pack first */
+		if (pl_a->all_objects_size == pl_b->all_objects_size)
+			return 0;
+		else if (pl_a->all_objects_size < pl_b->all_objects_size)
+			return 1;
+		else
+			return -1;
+	} else if (pl_a->remaining_objects->size < pl_b->remaining_objects->size) {
+		/* sort by remaining objects, more objects first */
+		return 1;
+	} else {
+		return -1;
+	}
+}
+
+/* Sort pack_list, greater size of remaining_objects first */
+static void sort_pack_list(struct pack_list **pl)
+{
+	struct pack_list **ary, *p;
+	size_t n = pack_list_size(*pl);
+
+	if (n < 2)
+		return;
+
+	/* prepare an array of packed_list for easier sorting */
+	CALLOC_ARRAY(ary, n);
+	for (n = 0, p = *pl; p; p = p->next)
+		ary[n++] = p;
+
+	QSORT(ary, n, cmp_remaining_objects);
+
+	/* link them back again */
+	for (size_t i = 0; i < n - 1; i++)
+		ary[i]->next = ary[i + 1];
+	ary[n - 1]->next = NULL;
+	*pl = ary[0];
+
+	free(ary);
+}
+
+
+static void minimize(struct pack_list **min)
+{
+	struct pack_list *pl, *unique = NULL, *non_unique = NULL;
+	struct llist *missing, *unique_pack_objects;
+
+	pl = local_packs;
+	while (pl) {
+		if (pl->unique_objects->size)
+			pack_list_insert(&unique, pl);
+		else
+			pack_list_insert(&non_unique, pl);
+		pl = pl->next;
+	}
+	/* find out which objects are missing from the set of unique packs */
+	missing = llist_copy(all_objects);
+	pl = unique;
+	while (pl) {
+		llist_sorted_difference_inplace(missing, pl->remaining_objects);
+		pl = pl->next;
+	}
+
+	*min = unique;
+
+	/* return if there are no objects missing from the unique set */
+	if (missing->size == 0) {
+		llist_free(missing);
+		pack_list_free(non_unique);
+		return;
+	}
+
+	unique_pack_objects = llist_copy(all_objects);
+	llist_sorted_difference_inplace(unique_pack_objects, missing);
+
+	/* remove unique pack objects from the non_unique packs */
+	pl = non_unique;
+	while (pl) {
+		llist_sorted_difference_inplace(pl->remaining_objects, unique_pack_objects);
+		pl = pl->next;
+	}
+
+	while (non_unique) {
+		struct pack_list *next;
+
+		/* sort the non_unique packs, greater size of remaining_objects first */
+		sort_pack_list(&non_unique);
+		if (non_unique->remaining_objects->size == 0)
+			break;
+
+		pack_list_insert(min, non_unique);
+
+		for (pl = non_unique->next; pl && pl->remaining_objects->size > 0;  pl = pl->next)
+			llist_sorted_difference_inplace(pl->remaining_objects, non_unique->remaining_objects);
+
+		next = non_unique->next;
+		free(non_unique);
+		non_unique = next;
+	}
+
+	pack_list_free(non_unique);
+	llist_free(unique_pack_objects);
+	llist_free(missing);
+}
+
+static void load_all_objects(void)
+{
+	struct pack_list *pl = local_packs;
+	struct llist_item *hint, *l;
+
+	llist_init(&all_objects);
+
+	while (pl) {
+		hint = NULL;
+		l = pl->remaining_objects->front;
+		while (l) {
+			hint = llist_insert_sorted_unique(all_objects,
+							  &l->oid, hint);
+			l = l->next;
+		}
+		pl = pl->next;
+	}
+	/* remove objects present in remote packs */
+	pl = altodb_packs;
+	while (pl) {
+		llist_sorted_difference_inplace(all_objects, pl->remaining_objects);
+		pl = pl->next;
+	}
+}
+
+/* this scales like O(n^2) */
+static void cmp_local_packs(void)
+{
+	struct pack_list *subset, *pl = local_packs;
+
+	/* only one packfile */
+	if (!pl->next) {
+		llist_init(&pl->unique_objects);
+		return;
+	}
+
+	while ((subset = pl)) {
+		while ((subset = subset->next))
+			cmp_two_packs(pl, subset);
+		pl = pl->next;
+	}
+}
+
+static void scan_alt_odb_packs(void)
+{
+	struct pack_list *local, *alt;
+
+	alt = altodb_packs;
+	while (alt) {
+		local = local_packs;
+		while (local) {
+			llist_sorted_difference_inplace(local->remaining_objects,
+							alt->remaining_objects);
+			local = local->next;
+		}
+		alt = alt->next;
+	}
+}
+
+static struct pack_list * add_pack(struct packed_git *p)
+{
+	struct pack_list l;
+	size_t off = 0, step;
+	const unsigned char *base;
+
+	if (!p->pack_local && !(alt_odb || verbose))
+		return NULL;
+
+	l.pack = p;
+	llist_init(&l.remaining_objects);
+
+	if (open_pack_index(p))
+		return NULL;
+
+	base = p->index_data;
+	base += 256 * 4 + ((p->index_version < 2) ? 4 : 8);
+	step = the_hash_algo->rawsz + ((p->index_version < 2) ? 4 : 0);
+	while (off < p->num_objects * step) {
+		llist_insert_back(l.remaining_objects, base + off);
+		off += step;
+	}
+	l.all_objects_size = l.remaining_objects->size;
+	l.unique_objects = NULL;
+	if (p->pack_local)
+		return pack_list_insert(&local_packs, &l);
+	else
+		return pack_list_insert(&altodb_packs, &l);
+}
+
+static struct pack_list * add_pack_file(const char *filename)
+{
+	struct packed_git *p = get_all_packs(the_repository);
+
+	if (strlen(filename) < 40)
+		die("Bad pack filename: %s", filename);
+
+	while (p) {
+		if (strstr(p->pack_name, filename))
+			return add_pack(p);
+		p = p->next;
+	}
+	die("Filename %s not found in packed_git", filename);
+}
+
+static void load_all(void)
+{
+	struct packed_git *p = get_all_packs(the_repository);
+
+	while (p) {
+		add_pack(p);
+		p = p->next;
+	}
+}
+
+int cmd_pack_redundant(int argc, const char **argv, const char *prefix UNUSED, struct repository *repo UNUSED) {
+	int i; int i_still_use_this = 0; struct pack_list *min = NULL, *red, *pl;
+	struct llist *ignore;
+	struct strbuf idx_name = STRBUF_INIT;
+	char buf[GIT_MAX_HEXSZ + 2]; /* hex hash + \n + \0 */
+
+	show_usage_if_asked(argc, argv, pack_redundant_usage);
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (!strcmp(arg, "--")) {
+			i++;
+			break;
+		}
+		if (!strcmp(arg, "--all")) {
+			load_all_packs = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--verbose")) {
+			verbose = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--alt-odb")) {
+			alt_odb = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--i-still-use-this")) {
+			i_still_use_this = 1;
+			continue;
+		}
+		if (*arg == '-')
+			usage(pack_redundant_usage);
+		else
+			break;
+	}
+
+	if (!i_still_use_this) {
+		fputs(_("'git pack-redundant' is nominated for removal.\n"
+			"If you still use this command, please add an extra\n"
+			"option, '--i-still-use-this', on the command line\n"
+			"and let us know you still use it by sending an e-mail\n"
+			"to <git@xxxxxxxxxxxxxxx>.  Thanks.\n"), stderr);
+		die(_("refusing to run without --i-still-use-this"));
+	}
+
+	if (load_all_packs)
+		load_all();
+	else
+		while (*(argv + i) != NULL)
+			add_pack_file(*(argv + i++));
+
+	if (!local_packs)
+		die("Zero packs found!");
+
+	load_all_objects();
+
+	if (alt_odb)
+		scan_alt_odb_packs();
+
+	/* ignore objects given on stdin */
+	llist_init(&ignore);
+	if (!isatty(0)) {
+		struct object_id oid;
+		while (fgets(buf, sizeof(buf), stdin)) {
+			if (get_oid_hex(buf, &oid))
+				die("Bad object ID on stdin: %s", buf);
+			llist_insert_sorted_unique(ignore, &oid, NULL);
+		}
+	}
+	llist_sorted_difference_inplace(all_objects, ignore);
+	pl = local_packs;
+	while (pl) {
+		llist_sorted_difference_inplace(pl->remaining_objects, ignore);
+		pl = pl->next;
+	}
+
+	cmp_local_packs();
+
+	minimize(&min);
+
+	if (verbose) {
+		fprintf(stderr, "There are %lu packs available in alt-odbs.\n",
+			(unsigned long)pack_list_size(altodb_packs));
+		fprintf(stderr, "The smallest (bytewise) set of packs is:\n");
+		pl = min;
+		while (pl) {
+			fprintf(stderr, "\t%s\n", pl->pack->pack_name);
+			pl = pl->next;
+		}
+		fprintf(stderr, "containing %lu duplicate objects "
+				"with a total size of %lukb.\n",
+			(unsigned long)get_pack_redundancy(min),
+			(unsigned long)pack_set_bytecount(min)/1024);
+		fprintf(stderr, "A total of %lu unique objects were considered.\n",
+			(unsigned long)all_objects->size);
+		fprintf(stderr, "Redundant packs (with indexes):\n");
+	}
+	pl = red = pack_list_difference(local_packs, min);
+	while (pl) {
+		printf("%s\n%s\n",
+		       odb_pack_name(pl->pack->repo, &idx_name, pl->pack->hash, "idx"),
+		       pl->pack->pack_name);
+		pl = pl->next;
+	}
+	if (verbose)
+		fprintf(stderr, "%luMB of redundant packs in total.\n",
+			(unsigned long)pack_set_bytecount(red)/(1024*1024));
+
+	pack_list_free(red);
+	pack_list_free(min);
+	llist_free(ignore);
+	strbuf_release(&idx_name);
+	return 0;
+}
diff --git a/builtin/pack-refs.c b/builtin/pack-refs.c
new file mode 100644
index 0000000000..4fdd68880e
--- /dev/null
+++ b/builtin/pack-refs.c
@@ -0,0 +1,61 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "revision.h"
+
+static char const * const pack_refs_usage[] = {
+	N_("git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]"),
+	NULL
+};
+
+int cmd_pack_refs(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
+	struct string_list included_refs = STRING_LIST_INIT_NODUP;
+	struct pack_refs_opts pack_refs_opts = {
+		.exclusions = &excludes,
+		.includes = &included_refs,
+		.flags = PACK_REFS_PRUNE,
+	};
+	struct string_list option_excluded_refs = STRING_LIST_INIT_NODUP;
+	struct string_list_item *item;
+	int pack_all = 0;
+	int ret;
+
+	struct option opts[] = {
+		OPT_BOOL(0, "all",   &pack_all, N_("pack everything")),
+		OPT_BIT(0, "prune", &pack_refs_opts.flags, N_("prune loose refs (default)"), PACK_REFS_PRUNE),
+		OPT_BIT(0, "auto", &pack_refs_opts.flags, N_("auto-pack refs as needed"), PACK_REFS_AUTO),
+		OPT_STRING_LIST(0, "include", pack_refs_opts.includes, N_("pattern"),
+			N_("references to include")),
+		OPT_STRING_LIST(0, "exclude", &option_excluded_refs, N_("pattern"),
+			N_("references to exclude")),
+		OPT_END(),
+	};
+	git_config(git_default_config, NULL);
+	if (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))
+		usage_with_options(pack_refs_usage, opts);
+
+	for_each_string_list_item(item, &option_excluded_refs)
+		add_ref_exclusion(pack_refs_opts.exclusions, item->string);
+
+	if (pack_all)
+		string_list_append(pack_refs_opts.includes, "*");
+
+	if (!pack_refs_opts.includes->nr)
+		string_list_append(pack_refs_opts.includes, "refs/tags/*");
+
+	ret = refs_pack_refs(get_main_ref_store(the_repository), &pack_refs_opts);
+
+	clear_ref_exclusions(&excludes);
+	string_list_clear(&included_refs, 0);
+	string_list_clear(&option_excluded_refs, 0);
+	return ret;
+}
diff --git a/builtin/patch-id.c b/builtin/patch-id.c
new file mode 100644
index 0000000000..f540d8daa7
--- /dev/null
+++ b/builtin/patch-id.c
@@ -0,0 +1,262 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "diff.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "parse-options.h"
+#include "setup.h"
+
+static void flush_current_id(size_t patchlen, struct object_id *id, struct object_id *result)
+{
+	if (patchlen)
+		printf("%s %s\n", oid_to_hex(result), oid_to_hex(id));
+}
+
+static size_t remove_space(char *line)
+{
+	char *src = line;
+	char *dst = line;
+	unsigned char c;
+
+	while ((c = *src++) != '\0') {
+		if (!isspace(c))
+			*dst++ = c;
+	}
+	return dst - line;
+}
+
+static int scan_hunk_header(const char *p, int *p_before, int *p_after)
+{
+	static const char digits[] = "0123456789";
+	const char *q, *r;
+	int n;
+
+	q = p + 4;
+	n = strspn(q, digits);
+	if (q[n] == ',') {
+		q += n + 1;
+		*p_before = atoi(q);
+		n = strspn(q, digits);
+	} else {
+		*p_before = 1;
+	}
+
+	if (n == 0 || q[n] != ' ' || q[n+1] != '+')
+		return 0;
+
+	r = q + n + 2;
+	n = strspn(r, digits);
+	if (r[n] == ',') {
+		r += n + 1;
+		*p_after = atoi(r);
+		n = strspn(r, digits);
+	} else {
+		*p_after = 1;
+	}
+	if (n == 0)
+		return 0;
+
+	return 1;
+}
+
+static size_t get_one_patchid(struct object_id *next_oid, struct object_id *result,
+			      struct strbuf *line_buf, int stable, int verbatim)
+{
+	size_t patchlen = 0;
+	int found_next = 0;
+	int before = -1, after = -1;
+	int diff_is_binary = 0;
+	char pre_oid_str[GIT_MAX_HEXSZ + 1], post_oid_str[GIT_MAX_HEXSZ + 1];
+	git_hash_ctx ctx;
+
+	the_hash_algo->init_fn(&ctx);
+	oidclr(result, the_repository->hash_algo);
+
+	while (strbuf_getwholeline(line_buf, stdin, '\n') != EOF) {
+		char *line = line_buf->buf;
+		const char *p = line;
+		size_t len;
+
+		/* Possibly skip over the prefix added by "log" or "format-patch" */
+		if (!skip_prefix(line, "commit ", &p) &&
+		    !skip_prefix(line, "From ", &p) &&
+		    starts_with(line, "\\ ") && 12 < strlen(line)) {
+			if (verbatim)
+				the_hash_algo->update_fn(&ctx, line, strlen(line));
+			continue;
+		}
+
+		if (!get_oid_hex(p, next_oid)) {
+			found_next = 1;
+			break;
+		}
+
+		/* Ignore commit comments */
+		if (!patchlen && !starts_with(line, "diff "))
+			continue;
+
+		/* Parsing diff header?  */
+		if (before == -1) {
+			if (starts_with(line, "GIT binary patch") ||
+			    starts_with(line, "Binary files")) {
+				diff_is_binary = 1;
+				before = 0;
+				the_hash_algo->update_fn(&ctx, pre_oid_str,
+							 strlen(pre_oid_str));
+				the_hash_algo->update_fn(&ctx, post_oid_str,
+							 strlen(post_oid_str));
+				if (stable)
+					flush_one_hunk(result, &ctx);
+				continue;
+			} else if (skip_prefix(line, "index ", &p)) {
+				char *oid1_end = strstr(line, "..");
+				char *oid2_end = NULL;
+				if (oid1_end)
+					oid2_end = strstr(oid1_end, " ");
+				if (!oid2_end)
+					oid2_end = line + strlen(line) - 1;
+				if (oid1_end != NULL && oid2_end != NULL) {
+					*oid1_end = *oid2_end = '\0';
+					strlcpy(pre_oid_str, p, GIT_MAX_HEXSZ + 1);
+					strlcpy(post_oid_str, oid1_end + 2, GIT_MAX_HEXSZ + 1);
+				}
+				continue;
+			} else if (starts_with(line, "--- "))
+				before = after = 1;
+			else if (!isalpha(line[0]))
+				break;
+		}
+
+		if (diff_is_binary) {
+			if (starts_with(line, "diff ")) {
+				diff_is_binary = 0;
+				before = -1;
+			}
+			continue;
+		}
+
+		/* Looking for a valid hunk header?  */
+		if (before == 0 && after == 0) {
+			if (starts_with(line, "@@ -")) {
+				/* Parse next hunk, but ignore line numbers.  */
+				scan_hunk_header(line, &before, &after);
+				continue;
+			}
+
+			/* Split at the end of the patch.  */
+			if (!starts_with(line, "diff "))
+				break;
+
+			/* Else we're parsing another header.  */
+			if (stable)
+				flush_one_hunk(result, &ctx);
+			before = after = -1;
+		}
+
+		/* If we get here, we're inside a hunk.  */
+		if (line[0] == '-' || line[0] == ' ')
+			before--;
+		if (line[0] == '+' || line[0] == ' ')
+			after--;
+
+		/* Add line to hash algo (possibly removing whitespace) */
+		len = verbatim ? strlen(line) : remove_space(line);
+		patchlen += len;
+		the_hash_algo->update_fn(&ctx, line, len);
+	}
+
+	if (!found_next)
+		oidclr(next_oid, the_repository->hash_algo);
+
+	flush_one_hunk(result, &ctx);
+
+	return patchlen;
+}
+
+static void generate_id_list(int stable, int verbatim)
+{
+	struct object_id oid, n, result;
+	size_t patchlen;
+	struct strbuf line_buf = STRBUF_INIT;
+
+	oidclr(&oid, the_repository->hash_algo);
+	while (!feof(stdin)) {
+		patchlen = get_one_patchid(&n, &result, &line_buf, stable, verbatim);
+		flush_current_id(patchlen, &oid, &result);
+		oidcpy(&oid, &n);
+	}
+	strbuf_release(&line_buf);
+}
+
+static const char *const patch_id_usage[] = {
+	N_("git patch-id [--stable | --unstable | --verbatim]"), NULL
+};
+
+struct patch_id_opts {
+	int stable;
+	int verbatim;
+};
+
+static int git_patch_id_config(const char *var, const char *value,
+			       const struct config_context *ctx, void *cb)
+{
+	struct patch_id_opts *opts = cb;
+
+	if (!strcmp(var, "patchid.stable")) {
+		opts->stable = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "patchid.verbatim")) {
+		opts->verbatim = git_config_bool(var, value);
+		return 0;
+	}
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+int cmd_patch_id(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	/* if nothing is set, default to unstable */
+	struct patch_id_opts config = {0, 0};
+	int opts = 0;
+	struct option builtin_patch_id_options[] = {
+		OPT_CMDMODE(0, "unstable", &opts,
+		    N_("use the unstable patch-id algorithm"), 1),
+		OPT_CMDMODE(0, "stable", &opts,
+		    N_("use the stable patch-id algorithm"), 2),
+		OPT_CMDMODE(0, "verbatim", &opts,
+			N_("don't strip whitespace from the patch"), 3),
+		OPT_END()
+	};
+
+	git_config(git_patch_id_config, &config);
+
+	/* verbatim implies stable */
+	if (config.verbatim)
+		config.stable = 1;
+
+	argc = parse_options(argc, argv, prefix, builtin_patch_id_options,
+			     patch_id_usage, 0);
+
+	/*
+	 * We rely on `the_hash_algo` to compute patch IDs. This is dubious as
+	 * it means that the hash algorithm now depends on the object hash of
+	 * the repository, even though git-patch-id(1) clearly defines that
+	 * patch IDs always use SHA1.
+	 *
+	 * NEEDSWORK: This hack should be removed in favor of converting
+	 * the code that computes patch IDs to always use SHA1.
+	 */
+	if (!the_hash_algo)
+		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
+	generate_id_list(opts ? opts > 1 : config.stable,
+			 opts ? opts == 3 : config.verbatim);
+	return 0;
+}
diff --git a/builtin/prune-packed.c b/builtin/prune-packed.c
new file mode 100644
index 0000000000..4d63f26b0a
--- /dev/null
+++ b/builtin/prune-packed.c
@@ -0,0 +1,35 @@
+#include "builtin.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "prune-packed.h"
+
+static const char * const prune_packed_usage[] = {
+	"git prune-packed [-n | --dry-run] [-q | --quiet]",
+	NULL
+};
+
+int cmd_prune_packed(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	int opts = isatty(2) ? PRUNE_PACKED_VERBOSE : 0;
+	const struct option prune_packed_options[] = {
+		OPT_BIT('n', "dry-run", &opts, N_("dry run"),
+			PRUNE_PACKED_DRY_RUN),
+		OPT_NEGBIT('q', "quiet", &opts, N_("be quiet"),
+			   PRUNE_PACKED_VERBOSE),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, prune_packed_options,
+			     prune_packed_usage, 0);
+
+	if (argc > 0)
+		usage_msg_opt(_("too many arguments"),
+			      prune_packed_usage,
+			      prune_packed_options);
+
+	prune_packed_objects(opts);
+	return 0;
+}
diff --git a/builtin/prune.c b/builtin/prune.c
new file mode 100644
index 0000000000..1c357fffd8
--- /dev/null
+++ b/builtin/prune.c
@@ -0,0 +1,219 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "commit.h"
+#include "diff.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "revision.h"
+#include "reachable.h"
+#include "parse-options.h"
+#include "path.h"
+#include "progress.h"
+#include "prune-packed.h"
+#include "replace-object.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "shallow.h"
+
+static const char * const prune_usage[] = {
+	N_("git prune [-n] [-v] [--progress] [--expire <time>] [--] [<head>...]"),
+	NULL
+};
+static int show_only;
+static int verbose;
+static timestamp_t expire;
+static int show_progress = -1;
+
+static int prune_tmp_file(const char *fullpath)
+{
+	struct stat st;
+	if (lstat(fullpath, &st))
+		return error("Could not stat '%s'", fullpath);
+	if (st.st_mtime > expire)
+		return 0;
+	if (S_ISDIR(st.st_mode)) {
+		if (show_only || verbose)
+			printf("Removing stale temporary directory %s\n", fullpath);
+		if (!show_only) {
+			struct strbuf remove_dir_buf = STRBUF_INIT;
+
+			strbuf_addstr(&remove_dir_buf, fullpath);
+			remove_dir_recursively(&remove_dir_buf, 0);
+			strbuf_release(&remove_dir_buf);
+		}
+	} else {
+		if (show_only || verbose)
+			printf("Removing stale temporary file %s\n", fullpath);
+		if (!show_only)
+			unlink_or_warn(fullpath);
+	}
+	return 0;
+}
+
+static void perform_reachability_traversal(struct rev_info *revs)
+{
+	static int initialized;
+	struct progress *progress = NULL;
+
+	if (initialized)
+		return;
+
+	if (show_progress)
+		progress = start_delayed_progress(the_repository,
+						  _("Checking connectivity"), 0);
+	mark_reachable_objects(revs, 1, expire, progress);
+	stop_progress(&progress);
+	initialized = 1;
+}
+
+static int is_object_reachable(const struct object_id *oid,
+			       struct rev_info *revs)
+{
+	struct object *obj;
+
+	perform_reachability_traversal(revs);
+
+	obj = lookup_object(the_repository, oid);
+	return obj && (obj->flags & SEEN);
+}
+
+static int prune_object(const struct object_id *oid, const char *fullpath,
+			void *data)
+{
+	struct rev_info *revs = data;
+	struct stat st;
+
+	if (is_object_reachable(oid, revs))
+		return 0;
+
+	if (lstat(fullpath, &st)) {
+		/* report errors, but do not stop pruning */
+		error("Could not stat '%s'", fullpath);
+		return 0;
+	}
+	if (st.st_mtime > expire)
+		return 0;
+	if (show_only || verbose) {
+		enum object_type type = oid_object_info(the_repository, oid,
+							NULL);
+		printf("%s %s\n", oid_to_hex(oid),
+		       (type > 0) ? type_name(type) : "unknown");
+	}
+	if (!show_only)
+		unlink_or_warn(fullpath);
+	return 0;
+}
+
+static int prune_cruft(const char *basename, const char *path,
+		       void *data UNUSED)
+{
+	if (starts_with(basename, "tmp_obj_"))
+		prune_tmp_file(path);
+	else
+		fprintf(stderr, "bad sha1 file: %s\n", path);
+	return 0;
+}
+
+static int prune_subdir(unsigned int nr UNUSED, const char *path,
+			void *data UNUSED)
+{
+	if (!show_only)
+		rmdir(path);
+	return 0;
+}
+
+/*
+ * Write errors (particularly out of space) can result in
+ * failed temporary packs (and more rarely indexes and other
+ * files beginning with "tmp_") accumulating in the object
+ * and the pack directories.
+ */
+static void remove_temporary_files(const char *path)
+{
+	DIR *dir;
+	struct dirent *de;
+
+	dir = opendir(path);
+	if (!dir) {
+		if (errno != ENOENT)
+			fprintf(stderr, "Unable to open directory %s: %s\n",
+				path, strerror(errno));
+		return;
+	}
+	while ((de = readdir(dir)) != NULL)
+		if (starts_with(de->d_name, "tmp_"))
+			prune_tmp_file(mkpath("%s/%s", path, de->d_name));
+	closedir(dir);
+}
+
+int cmd_prune(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	struct rev_info revs;
+	int exclude_promisor_objects = 0;
+	const struct option options[] = {
+		OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
+		OPT__VERBOSE(&verbose, N_("report pruned objects")),
+		OPT_BOOL(0, "progress", &show_progress, N_("show progress")),
+		OPT_EXPIRY_DATE(0, "expire", &expire,
+				N_("expire objects older than <time>")),
+		OPT_BOOL(0, "exclude-promisor-objects", &exclude_promisor_objects,
+			 N_("limit traversal to objects outside promisor packfiles")),
+		OPT_END()
+	};
+	char *s;
+
+	expire = TIME_MAX;
+	save_commit_buffer = 0;
+	disable_replace_refs();
+	repo_init_revisions(the_repository, &revs, prefix);
+
+	argc = parse_options(argc, argv, prefix, options, prune_usage, 0);
+
+	if (repository_format_precious_objects)
+		die(_("cannot prune in a precious-objects repo"));
+
+	while (argc--) {
+		struct object_id oid;
+		const char *name = *argv++;
+
+		if (!repo_get_oid(the_repository, name, &oid)) {
+			struct object *object = parse_object_or_die(&oid,
+								    name);
+			add_pending_object(&revs, object, "");
+		}
+		else
+			die("unrecognized argument: %s", name);
+	}
+
+	if (show_progress == -1)
+		show_progress = isatty(2);
+	if (exclude_promisor_objects) {
+		fetch_if_missing = 0;
+		revs.exclude_promisor_objects = 1;
+	}
+
+	for_each_loose_file_in_objdir(repo_get_object_directory(the_repository),
+				      prune_object, prune_cruft, prune_subdir, &revs);
+
+	prune_packed_objects(show_only ? PRUNE_PACKED_DRY_RUN : 0);
+	remove_temporary_files(repo_get_object_directory(the_repository));
+	s = mkpathdup("%s/pack", repo_get_object_directory(the_repository));
+	remove_temporary_files(s);
+	free(s);
+
+	if (is_repository_shallow(the_repository)) {
+		perform_reachability_traversal(&revs);
+		prune_shallow(show_only ? PRUNE_SHOW_ONLY : 0);
+	}
+
+	release_revisions(&revs);
+	return 0;
+}
diff --git a/builtin/pull.c b/builtin/pull.c
new file mode 100644
index 0000000000..9c4a00620a
--- /dev/null
+++ b/builtin/pull.c
@@ -0,0 +1,1167 @@
+/*
+ * Builtin "git pull"
+ *
+ * Based on git-pull.sh by Junio C Hamano
+ *
+ * Fetch one or more remote refs and merge it/them into the current HEAD.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "merge.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "run-command.h"
+#include "oid-array.h"
+#include "remote.h"
+#include "dir.h"
+#include "path.h"
+#include "read-cache-ll.h"
+#include "rebase.h"
+#include "refs.h"
+#include "refspec.h"
+#include "submodule.h"
+#include "submodule-config.h"
+#include "wt-status.h"
+#include "commit-reach.h"
+#include "sequencer.h"
+
+/**
+ * Parses the value of --rebase. If value is a false value, returns
+ * REBASE_FALSE. If value is a true value, returns REBASE_TRUE. If value is
+ * "merges", returns REBASE_MERGES. If value is a invalid value, dies with
+ * a fatal error if fatal is true, otherwise returns REBASE_INVALID.
+ */
+static enum rebase_type parse_config_rebase(const char *key, const char *value,
+		int fatal)
+{
+	enum rebase_type v = rebase_parse_value(value);
+	if (v != REBASE_INVALID)
+		return v;
+
+	if (fatal)
+		die(_("invalid value for '%s': '%s'"), key, value);
+	else
+		error(_("invalid value for '%s': '%s'"), key, value);
+
+	return REBASE_INVALID;
+}
+
+/**
+ * Callback for --rebase, which parses arg with parse_config_rebase().
+ */
+static int parse_opt_rebase(const struct option *opt, const char *arg, int unset)
+{
+	enum rebase_type *value = opt->value;
+
+	if (arg)
+		*value = parse_config_rebase("--rebase", arg, 0);
+	else
+		*value = unset ? REBASE_FALSE : REBASE_TRUE;
+	return *value == REBASE_INVALID ? -1 : 0;
+}
+
+static const char * const pull_usage[] = {
+	N_("git pull [<options>] [<repository> [<refspec>...]]"),
+	NULL
+};
+
+/* Shared options */
+static int opt_verbosity;
+static const char *opt_progress;
+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static int recurse_submodules_cli = RECURSE_SUBMODULES_DEFAULT;
+
+/* Options passed to git-merge or git-rebase */
+static enum rebase_type opt_rebase = -1;
+static const char *opt_diffstat;
+static const char *opt_log;
+static const char *opt_signoff;
+static const char *opt_squash;
+static const char *opt_commit;
+static const char *opt_edit;
+static const char *cleanup_arg;
+static char *opt_ff;
+static const char *opt_verify_signatures;
+static const char *opt_verify;
+static int opt_autostash = -1;
+static int config_autostash;
+static int check_trust_level = 1;
+static struct strvec opt_strategies = STRVEC_INIT;
+static struct strvec opt_strategy_opts = STRVEC_INIT;
+static const char *opt_gpg_sign;
+static int opt_allow_unrelated_histories;
+
+/* Options passed to git-fetch */
+static const char *opt_all;
+static const char *opt_append;
+static const char *opt_upload_pack;
+static int opt_force;
+static const char *opt_tags;
+static const char *opt_prune;
+static const char *max_children;
+static int opt_dry_run;
+static const char *opt_keep;
+static const char *opt_depth;
+static const char *opt_unshallow;
+static const char *opt_update_shallow;
+static const char *opt_refmap;
+static const char *opt_ipv4;
+static const char *opt_ipv6;
+static int opt_show_forced_updates = -1;
+static const char *set_upstream;
+static struct strvec opt_fetch = STRVEC_INIT;
+
+static struct option pull_options[] = {
+	/* Shared options */
+	OPT__VERBOSITY(&opt_verbosity),
+	OPT_PASSTHRU(0, "progress", &opt_progress, NULL,
+		N_("force progress reporting"),
+		PARSE_OPT_NOARG),
+	OPT_CALLBACK_F(0, "recurse-submodules",
+		   &recurse_submodules_cli, N_("on-demand"),
+		   N_("control for recursive fetching of submodules"),
+		   PARSE_OPT_OPTARG, option_fetch_parse_recurse_submodules),
+
+	/* Options passed to git-merge or git-rebase */
+	OPT_GROUP(N_("Options related to merging")),
+	OPT_CALLBACK_F('r', "rebase", &opt_rebase,
+		"(false|true|merges|interactive)",
+		N_("incorporate changes by rebasing rather than merging"),
+		PARSE_OPT_OPTARG, parse_opt_rebase),
+	OPT_PASSTHRU('n', NULL, &opt_diffstat, NULL,
+		N_("do not show a diffstat at the end of the merge"),
+		PARSE_OPT_NOARG | PARSE_OPT_NONEG),
+	OPT_PASSTHRU(0, "stat", &opt_diffstat, NULL,
+		N_("show a diffstat at the end of the merge"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "summary", &opt_diffstat, NULL,
+		N_("(synonym to --stat)"),
+		PARSE_OPT_NOARG | PARSE_OPT_HIDDEN),
+	OPT_PASSTHRU(0, "log", &opt_log, N_("n"),
+		N_("add (at most <n>) entries from shortlog to merge commit message"),
+		PARSE_OPT_OPTARG),
+	OPT_PASSTHRU(0, "signoff", &opt_signoff, NULL,
+		N_("add a Signed-off-by trailer"),
+		PARSE_OPT_OPTARG),
+	OPT_PASSTHRU(0, "squash", &opt_squash, NULL,
+		N_("create a single commit instead of doing a merge"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "commit", &opt_commit, NULL,
+		N_("perform a commit if the merge succeeds (default)"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "edit", &opt_edit, NULL,
+		N_("edit message before committing"),
+		PARSE_OPT_NOARG),
+	OPT_CLEANUP(&cleanup_arg),
+	OPT_PASSTHRU(0, "ff", &opt_ff, NULL,
+		N_("allow fast-forward"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "ff-only", &opt_ff, NULL,
+		N_("abort if fast-forward is not possible"),
+		PARSE_OPT_NOARG | PARSE_OPT_NONEG),
+	OPT_PASSTHRU(0, "verify", &opt_verify, NULL,
+		N_("control use of pre-merge-commit and commit-msg hooks"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "verify-signatures", &opt_verify_signatures, NULL,
+		N_("verify that the named commit has a valid GPG signature"),
+		PARSE_OPT_NOARG),
+	OPT_BOOL(0, "autostash", &opt_autostash,
+		N_("automatically stash/stash pop before and after")),
+	OPT_PASSTHRU_ARGV('s', "strategy", &opt_strategies, N_("strategy"),
+		N_("merge strategy to use"),
+		0),
+	OPT_PASSTHRU_ARGV('X', "strategy-option", &opt_strategy_opts,
+		N_("option=value"),
+		N_("option for selected merge strategy"),
+		0),
+	OPT_PASSTHRU('S', "gpg-sign", &opt_gpg_sign, N_("key-id"),
+		N_("GPG sign commit"),
+		PARSE_OPT_OPTARG),
+	OPT_SET_INT(0, "allow-unrelated-histories",
+		    &opt_allow_unrelated_histories,
+		    N_("allow merging unrelated histories"), 1),
+
+	/* Options passed to git-fetch */
+	OPT_GROUP(N_("Options related to fetching")),
+	OPT_PASSTHRU(0, "all", &opt_all, NULL,
+		N_("fetch from all remotes"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU('a', "append", &opt_append, NULL,
+		N_("append to .git/FETCH_HEAD instead of overwriting"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "upload-pack", &opt_upload_pack, N_("path"),
+		N_("path to upload pack on remote end"),
+		0),
+	OPT__FORCE(&opt_force, N_("force overwrite of local branch"), 0),
+	OPT_PASSTHRU('t', "tags", &opt_tags, NULL,
+		N_("fetch all tags and associated objects"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU('p', "prune", &opt_prune, NULL,
+		N_("prune remote-tracking branches no longer on remote"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU('j', "jobs", &max_children, N_("n"),
+		N_("number of submodules pulled in parallel"),
+		PARSE_OPT_OPTARG),
+	OPT_BOOL(0, "dry-run", &opt_dry_run,
+		N_("dry run")),
+	OPT_PASSTHRU('k', "keep", &opt_keep, NULL,
+		N_("keep downloaded pack"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "depth", &opt_depth, N_("depth"),
+		N_("deepen history of shallow clone"),
+		0),
+	OPT_PASSTHRU_ARGV(0, "shallow-since", &opt_fetch, N_("time"),
+		N_("deepen history of shallow repository based on time"),
+		0),
+	OPT_PASSTHRU_ARGV(0, "shallow-exclude", &opt_fetch, N_("ref"),
+		N_("deepen history of shallow clone, excluding ref"),
+		0),
+	OPT_PASSTHRU_ARGV(0, "deepen", &opt_fetch, N_("n"),
+		N_("deepen history of shallow clone"),
+		0),
+	OPT_PASSTHRU(0, "unshallow", &opt_unshallow, NULL,
+		N_("convert to a complete repository"),
+		PARSE_OPT_NONEG | PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "update-shallow", &opt_update_shallow, NULL,
+		N_("accept refs that update .git/shallow"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU(0, "refmap", &opt_refmap, N_("refmap"),
+		N_("specify fetch refmap"),
+		PARSE_OPT_NONEG),
+	OPT_PASSTHRU_ARGV('o', "server-option", &opt_fetch,
+		N_("server-specific"),
+		N_("option to transmit"),
+		0),
+	OPT_PASSTHRU('4',  "ipv4", &opt_ipv4, NULL,
+		N_("use IPv4 addresses only"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU('6',  "ipv6", &opt_ipv6, NULL,
+		N_("use IPv6 addresses only"),
+		PARSE_OPT_NOARG),
+	OPT_PASSTHRU_ARGV(0, "negotiation-tip", &opt_fetch, N_("revision"),
+		N_("report that we have only objects reachable from this object"),
+		0),
+	OPT_BOOL(0, "show-forced-updates", &opt_show_forced_updates,
+		 N_("check for forced-updates on all updated branches")),
+	OPT_PASSTHRU(0, "set-upstream", &set_upstream, NULL,
+		N_("set upstream for git pull/fetch"),
+		PARSE_OPT_NOARG),
+
+	OPT_END()
+};
+
+/**
+ * Pushes "-q" or "-v" switches into arr to match the opt_verbosity level.
+ */
+static void argv_push_verbosity(struct strvec *arr)
+{
+	int verbosity;
+
+	for (verbosity = opt_verbosity; verbosity > 0; verbosity--)
+		strvec_push(arr, "-v");
+
+	for (verbosity = opt_verbosity; verbosity < 0; verbosity++)
+		strvec_push(arr, "-q");
+}
+
+/**
+ * Pushes "-f" switches into arr to match the opt_force level.
+ */
+static void argv_push_force(struct strvec *arr)
+{
+	int force = opt_force;
+	while (force-- > 0)
+		strvec_push(arr, "-f");
+}
+
+/**
+ * Sets the GIT_REFLOG_ACTION environment variable to the concatenation of argv
+ */
+static void set_reflog_message(int argc, const char **argv)
+{
+	int i;
+	struct strbuf msg = STRBUF_INIT;
+
+	for (i = 0; i < argc; i++) {
+		if (i)
+			strbuf_addch(&msg, ' ');
+		strbuf_addstr(&msg, argv[i]);
+	}
+
+	setenv("GIT_REFLOG_ACTION", msg.buf, 0);
+
+	strbuf_release(&msg);
+}
+
+/**
+ * If pull.ff is unset, returns NULL. If pull.ff is "true", returns "--ff". If
+ * pull.ff is "false", returns "--no-ff". If pull.ff is "only", returns
+ * "--ff-only". Otherwise, if pull.ff is set to an invalid value, die with an
+ * error.
+ */
+static const char *config_get_ff(void)
+{
+	const char *value;
+
+	if (git_config_get_value("pull.ff", &value))
+		return NULL;
+
+	switch (git_parse_maybe_bool(value)) {
+	case 0:
+		return "--no-ff";
+	case 1:
+		return "--ff";
+	}
+
+	if (!strcmp(value, "only"))
+		return "--ff-only";
+
+	die(_("invalid value for '%s': '%s'"), "pull.ff", value);
+}
+
+/**
+ * Returns the default configured value for --rebase. It first looks for the
+ * value of "branch.$curr_branch.rebase", where $curr_branch is the current
+ * branch, and if HEAD is detached or the configuration key does not exist,
+ * looks for the value of "pull.rebase". If both configuration keys do not
+ * exist, returns REBASE_FALSE.
+ */
+static enum rebase_type config_get_rebase(int *rebase_unspecified)
+{
+	struct branch *curr_branch = branch_get("HEAD");
+	const char *value;
+
+	if (curr_branch) {
+		char *key = xstrfmt("branch.%s.rebase", curr_branch->name);
+
+		if (!git_config_get_value(key, &value)) {
+			enum rebase_type ret = parse_config_rebase(key, value, 1);
+			free(key);
+			return ret;
+		}
+
+		free(key);
+	}
+
+	if (!git_config_get_value("pull.rebase", &value))
+		return parse_config_rebase("pull.rebase", value, 1);
+
+	*rebase_unspecified = 1;
+
+	return REBASE_FALSE;
+}
+
+/**
+ * Read config variables.
+ */
+static int git_pull_config(const char *var, const char *value,
+			   const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "rebase.autostash")) {
+		config_autostash = git_config_bool(var, value);
+		return 0;
+	} else if (!strcmp(var, "submodule.recurse")) {
+		recurse_submodules = git_config_bool(var, value) ?
+			RECURSE_SUBMODULES_ON : RECURSE_SUBMODULES_OFF;
+		return 0;
+	} else if (!strcmp(var, "gpg.mintrustlevel")) {
+		check_trust_level = 0;
+	}
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+/**
+ * Appends merge candidates from FETCH_HEAD that are not marked not-for-merge
+ * into merge_heads.
+ */
+static void get_merge_heads(struct oid_array *merge_heads)
+{
+	const char *filename = git_path_fetch_head(the_repository);
+	FILE *fp;
+	struct strbuf sb = STRBUF_INIT;
+	struct object_id oid;
+
+	fp = xfopen(filename, "r");
+	while (strbuf_getline_lf(&sb, fp) != EOF) {
+		const char *p;
+		if (parse_oid_hex(sb.buf, &oid, &p))
+			continue;  /* invalid line: does not start with object ID */
+		if (starts_with(p, "\tnot-for-merge\t"))
+			continue;  /* ref is not-for-merge */
+		oid_array_append(merge_heads, &oid);
+	}
+	fclose(fp);
+	strbuf_release(&sb);
+}
+
+/**
+ * Used by die_no_merge_candidates() as a for_each_remote() callback to
+ * retrieve the name of the remote if the repository only has one remote.
+ */
+static int get_only_remote(struct remote *remote, void *cb_data)
+{
+	const char **remote_name = cb_data;
+
+	if (*remote_name)
+		return -1;
+
+	*remote_name = remote->name;
+	return 0;
+}
+
+/**
+ * Dies with the appropriate reason for why there are no merge candidates:
+ *
+ * 1. We fetched from a specific remote, and a refspec was given, but it ended
+ *    up not fetching anything. This is usually because the user provided a
+ *    wildcard refspec which had no matches on the remote end.
+ *
+ * 2. We fetched from a non-default remote, but didn't specify a branch to
+ *    merge. We can't use the configured one because it applies to the default
+ *    remote, thus the user must specify the branches to merge.
+ *
+ * 3. We fetched from the branch's or repo's default remote, but:
+ *
+ *    a. We are not on a branch, so there will never be a configured branch to
+ *       merge with.
+ *
+ *    b. We are on a branch, but there is no configured branch to merge with.
+ *
+ * 4. We fetched from the branch's or repo's default remote, but the configured
+ *    branch to merge didn't get fetched. (Either it doesn't exist, or wasn't
+ *    part of the configured fetch refspec.)
+ */
+static void NORETURN die_no_merge_candidates(const char *repo, const char **refspecs)
+{
+	struct branch *curr_branch = branch_get("HEAD");
+	const char *remote = curr_branch ? curr_branch->remote_name : NULL;
+
+	if (*refspecs) {
+		if (opt_rebase)
+			fprintf_ln(stderr, _("There is no candidate for rebasing against among the refs that you just fetched."));
+		else
+			fprintf_ln(stderr, _("There are no candidates for merging among the refs that you just fetched."));
+		fprintf_ln(stderr, _("Generally this means that you provided a wildcard refspec which had no\n"
+					"matches on the remote end."));
+	} else if (repo && curr_branch && (!remote || strcmp(repo, remote))) {
+		fprintf_ln(stderr, _("You asked to pull from the remote '%s', but did not specify\n"
+			"a branch. Because this is not the default configured remote\n"
+			"for your current branch, you must specify a branch on the command line."),
+			repo);
+	} else if (!curr_branch) {
+		fprintf_ln(stderr, _("You are not currently on a branch."));
+		if (opt_rebase)
+			fprintf_ln(stderr, _("Please specify which branch you want to rebase against."));
+		else
+			fprintf_ln(stderr, _("Please specify which branch you want to merge with."));
+		fprintf_ln(stderr, _("See git-pull(1) for details."));
+		fprintf(stderr, "\n");
+		fprintf_ln(stderr, "    git pull %s %s", _("<remote>"), _("<branch>"));
+		fprintf(stderr, "\n");
+	} else if (!curr_branch->merge_nr) {
+		const char *remote_name = NULL;
+
+		if (for_each_remote(get_only_remote, &remote_name) || !remote_name)
+			remote_name = _("<remote>");
+
+		fprintf_ln(stderr, _("There is no tracking information for the current branch."));
+		if (opt_rebase)
+			fprintf_ln(stderr, _("Please specify which branch you want to rebase against."));
+		else
+			fprintf_ln(stderr, _("Please specify which branch you want to merge with."));
+		fprintf_ln(stderr, _("See git-pull(1) for details."));
+		fprintf(stderr, "\n");
+		fprintf_ln(stderr, "    git pull %s %s", _("<remote>"), _("<branch>"));
+		fprintf(stderr, "\n");
+		fprintf_ln(stderr, _("If you wish to set tracking information for this branch you can do so with:"));
+		fprintf(stderr, "\n");
+		fprintf_ln(stderr, "    git branch --set-upstream-to=%s/%s %s\n",
+				remote_name, _("<branch>"), curr_branch->name);
+	} else
+		fprintf_ln(stderr, _("Your configuration specifies to merge with the ref '%s'\n"
+			"from the remote, but no such ref was fetched."),
+			*curr_branch->merge_name);
+	exit(1);
+}
+
+/**
+ * Parses argv into [<repo> [<refspecs>...]], returning their values in `repo`
+ * as a string and `refspecs` as a null-terminated array of strings. If `repo`
+ * is not provided in argv, it is set to NULL.
+ */
+static void parse_repo_refspecs(int argc, const char **argv, const char **repo,
+		const char ***refspecs)
+{
+	if (argc > 0) {
+		*repo = *argv++;
+		argc--;
+	} else
+		*repo = NULL;
+	*refspecs = argv;
+}
+
+/**
+ * Runs git-fetch, returning its exit status. `repo` and `refspecs` are the
+ * repository and refspecs to fetch, or NULL if they are not provided.
+ */
+static int run_fetch(const char *repo, const char **refspecs)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	strvec_pushl(&cmd.args, "fetch", "--update-head-ok", NULL);
+
+	/* Shared options */
+	argv_push_verbosity(&cmd.args);
+	if (opt_progress)
+		strvec_push(&cmd.args, opt_progress);
+
+	/* Options passed to git-fetch */
+	if (opt_all)
+		strvec_push(&cmd.args, opt_all);
+	if (opt_append)
+		strvec_push(&cmd.args, opt_append);
+	if (opt_upload_pack)
+		strvec_push(&cmd.args, opt_upload_pack);
+	argv_push_force(&cmd.args);
+	if (opt_tags)
+		strvec_push(&cmd.args, opt_tags);
+	if (opt_prune)
+		strvec_push(&cmd.args, opt_prune);
+	if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
+		switch (recurse_submodules_cli) {
+		case RECURSE_SUBMODULES_ON:
+			strvec_push(&cmd.args, "--recurse-submodules=on");
+			break;
+		case RECURSE_SUBMODULES_OFF:
+			strvec_push(&cmd.args, "--recurse-submodules=no");
+			break;
+		case RECURSE_SUBMODULES_ON_DEMAND:
+			strvec_push(&cmd.args, "--recurse-submodules=on-demand");
+			break;
+		default:
+			BUG("submodule recursion option not understood");
+		}
+	if (max_children)
+		strvec_push(&cmd.args, max_children);
+	if (opt_dry_run)
+		strvec_push(&cmd.args, "--dry-run");
+	if (opt_keep)
+		strvec_push(&cmd.args, opt_keep);
+	if (opt_depth)
+		strvec_push(&cmd.args, opt_depth);
+	if (opt_unshallow)
+		strvec_push(&cmd.args, opt_unshallow);
+	if (opt_update_shallow)
+		strvec_push(&cmd.args, opt_update_shallow);
+	if (opt_refmap)
+		strvec_push(&cmd.args, opt_refmap);
+	if (opt_ipv4)
+		strvec_push(&cmd.args, opt_ipv4);
+	if (opt_ipv6)
+		strvec_push(&cmd.args, opt_ipv6);
+	if (opt_show_forced_updates > 0)
+		strvec_push(&cmd.args, "--show-forced-updates");
+	else if (opt_show_forced_updates == 0)
+		strvec_push(&cmd.args, "--no-show-forced-updates");
+	if (set_upstream)
+		strvec_push(&cmd.args, set_upstream);
+	strvec_pushv(&cmd.args, opt_fetch.v);
+
+	if (repo) {
+		strvec_push(&cmd.args, repo);
+		strvec_pushv(&cmd.args, refspecs);
+	} else if (*refspecs)
+		BUG("refspecs without repo?");
+	cmd.git_cmd = 1;
+	cmd.close_object_store = 1;
+	return run_command(&cmd);
+}
+
+/**
+ * "Pulls into void" by branching off merge_head.
+ */
+static int pull_into_void(const struct object_id *merge_head,
+		const struct object_id *curr_head)
+{
+	if (opt_verify_signatures) {
+		struct commit *commit;
+
+		commit = lookup_commit(the_repository, merge_head);
+		if (!commit)
+			die(_("unable to access commit %s"),
+			    oid_to_hex(merge_head));
+
+		verify_merge_signature(commit, opt_verbosity,
+				       check_trust_level);
+	}
+
+	/*
+	 * Two-way merge: we treat the index as based on an empty tree,
+	 * and try to fast-forward to HEAD. This ensures we will not lose
+	 * index/worktree changes that the user already made on the unborn
+	 * branch.
+	 */
+	if (checkout_fast_forward(the_repository,
+				  the_hash_algo->empty_tree,
+				  merge_head, 0))
+		return 1;
+
+	if (refs_update_ref(get_main_ref_store(the_repository), "initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
+		return 1;
+
+	return 0;
+}
+
+static int rebase_submodules(void)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	cp.git_cmd = 1;
+	cp.no_stdin = 1;
+	strvec_pushl(&cp.args, "submodule", "update",
+		     "--recursive", "--rebase", NULL);
+	argv_push_verbosity(&cp.args);
+
+	return run_command(&cp);
+}
+
+static int update_submodules(void)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	cp.git_cmd = 1;
+	cp.no_stdin = 1;
+	strvec_pushl(&cp.args, "submodule", "update",
+		     "--recursive", "--checkout", NULL);
+	argv_push_verbosity(&cp.args);
+
+	return run_command(&cp);
+}
+
+/**
+ * Runs git-merge, returning its exit status.
+ */
+static int run_merge(void)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	strvec_pushl(&cmd.args, "merge", NULL);
+
+	/* Shared options */
+	argv_push_verbosity(&cmd.args);
+	if (opt_progress)
+		strvec_push(&cmd.args, opt_progress);
+
+	/* Options passed to git-merge */
+	if (opt_diffstat)
+		strvec_push(&cmd.args, opt_diffstat);
+	if (opt_log)
+		strvec_push(&cmd.args, opt_log);
+	if (opt_signoff)
+		strvec_push(&cmd.args, opt_signoff);
+	if (opt_squash)
+		strvec_push(&cmd.args, opt_squash);
+	if (opt_commit)
+		strvec_push(&cmd.args, opt_commit);
+	if (opt_edit)
+		strvec_push(&cmd.args, opt_edit);
+	if (cleanup_arg)
+		strvec_pushf(&cmd.args, "--cleanup=%s", cleanup_arg);
+	if (opt_ff)
+		strvec_push(&cmd.args, opt_ff);
+	if (opt_verify)
+		strvec_push(&cmd.args, opt_verify);
+	if (opt_verify_signatures)
+		strvec_push(&cmd.args, opt_verify_signatures);
+	strvec_pushv(&cmd.args, opt_strategies.v);
+	strvec_pushv(&cmd.args, opt_strategy_opts.v);
+	if (opt_gpg_sign)
+		strvec_push(&cmd.args, opt_gpg_sign);
+	if (opt_autostash == 0)
+		strvec_push(&cmd.args, "--no-autostash");
+	else if (opt_autostash == 1)
+		strvec_push(&cmd.args, "--autostash");
+	if (opt_allow_unrelated_histories > 0)
+		strvec_push(&cmd.args, "--allow-unrelated-histories");
+
+	strvec_push(&cmd.args, "FETCH_HEAD");
+	cmd.git_cmd = 1;
+	return run_command(&cmd);
+}
+
+/**
+ * Returns remote's upstream branch for the current branch. If remote is NULL,
+ * the current branch's configured default remote is used. Returns NULL if
+ * `remote` does not name a valid remote, HEAD does not point to a branch,
+ * remote is not the branch's configured remote or the branch does not have any
+ * configured upstream branch.
+ */
+static const char *get_upstream_branch(const char *remote)
+{
+	struct remote *rm;
+	struct branch *curr_branch;
+	const char *curr_branch_remote;
+
+	rm = remote_get(remote);
+	if (!rm)
+		return NULL;
+
+	curr_branch = branch_get("HEAD");
+	if (!curr_branch)
+		return NULL;
+
+	curr_branch_remote = remote_for_branch(curr_branch, NULL);
+	assert(curr_branch_remote);
+
+	if (strcmp(curr_branch_remote, rm->name))
+		return NULL;
+
+	return branch_get_upstream(curr_branch, NULL);
+}
+
+/**
+ * Derives the remote-tracking branch from the remote and refspec.
+ *
+ * FIXME: The current implementation assumes the default mapping of
+ * refs/heads/<branch_name> to refs/remotes/<remote_name>/<branch_name>.
+ */
+static const char *get_tracking_branch(const char *remote, const char *refspec)
+{
+	struct refspec_item spec;
+	const char *spec_src;
+	const char *merge_branch;
+
+	refspec_item_init_or_die(&spec, refspec, REFSPEC_FETCH);
+	spec_src = spec.src;
+	if (!*spec_src || !strcmp(spec_src, "HEAD"))
+		spec_src = "HEAD";
+	else if (skip_prefix(spec_src, "heads/", &spec_src))
+		;
+	else if (skip_prefix(spec_src, "refs/heads/", &spec_src))
+		;
+	else if (starts_with(spec_src, "refs/") ||
+		starts_with(spec_src, "tags/") ||
+		starts_with(spec_src, "remotes/"))
+		spec_src = "";
+
+	if (*spec_src) {
+		if (!strcmp(remote, "."))
+			merge_branch = mkpath("refs/heads/%s", spec_src);
+		else
+			merge_branch = mkpath("refs/remotes/%s/%s", remote, spec_src);
+	} else
+		merge_branch = NULL;
+
+	refspec_item_clear(&spec);
+	return merge_branch;
+}
+
+/**
+ * Given the repo and refspecs, sets fork_point to the point at which the
+ * current branch forked from its remote-tracking branch. Returns 0 on success,
+ * -1 on failure.
+ */
+static int get_rebase_fork_point(struct object_id *fork_point, const char *repo,
+		const char *refspec)
+{
+	int ret;
+	struct branch *curr_branch;
+	const char *remote_branch;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	struct strbuf sb = STRBUF_INIT;
+
+	curr_branch = branch_get("HEAD");
+	if (!curr_branch)
+		return -1;
+
+	if (refspec)
+		remote_branch = get_tracking_branch(repo, refspec);
+	else
+		remote_branch = get_upstream_branch(repo);
+
+	if (!remote_branch)
+		return -1;
+
+	strvec_pushl(&cp.args, "merge-base", "--fork-point",
+		     remote_branch, curr_branch->name, NULL);
+	cp.no_stdin = 1;
+	cp.no_stderr = 1;
+	cp.git_cmd = 1;
+
+	ret = capture_command(&cp, &sb, GIT_MAX_HEXSZ);
+	if (ret)
+		goto cleanup;
+
+	ret = get_oid_hex(sb.buf, fork_point);
+	if (ret)
+		goto cleanup;
+
+cleanup:
+	strbuf_release(&sb);
+	return ret ? -1 : 0;
+}
+
+/**
+ * Sets merge_base to the octopus merge base of curr_head, merge_head and
+ * fork_point. Returns 0 if a merge base is found, 1 otherwise.
+ */
+static int get_octopus_merge_base(struct object_id *merge_base,
+		const struct object_id *curr_head,
+		const struct object_id *merge_head,
+		const struct object_id *fork_point)
+{
+	struct commit_list *revs = NULL, *result = NULL;
+
+	commit_list_insert(lookup_commit_reference(the_repository, curr_head),
+			   &revs);
+	commit_list_insert(lookup_commit_reference(the_repository, merge_head),
+			   &revs);
+	if (!is_null_oid(fork_point))
+		commit_list_insert(lookup_commit_reference(the_repository, fork_point),
+				   &revs);
+
+	if (get_octopus_merge_bases(revs, &result) < 0)
+		exit(128);
+	free_commit_list(revs);
+	reduce_heads_replace(&result);
+
+	if (!result)
+		return 1;
+
+	oidcpy(merge_base, &result->item->object.oid);
+	free_commit_list(result);
+	return 0;
+}
+
+/**
+ * Given the current HEAD oid, the merge head returned from git-fetch and the
+ * fork point calculated by get_rebase_fork_point(), compute the <newbase> and
+ * <upstream> arguments to use for the upcoming git-rebase invocation.
+ */
+static int get_rebase_newbase_and_upstream(struct object_id *newbase,
+		struct object_id *upstream,
+		const struct object_id *curr_head,
+		const struct object_id *merge_head,
+		const struct object_id *fork_point)
+{
+	struct object_id oct_merge_base;
+
+	if (!get_octopus_merge_base(&oct_merge_base, curr_head, merge_head, fork_point))
+		if (!is_null_oid(fork_point) && oideq(&oct_merge_base, fork_point))
+			fork_point = NULL;
+
+	if (fork_point && !is_null_oid(fork_point))
+		oidcpy(upstream, fork_point);
+	else
+		oidcpy(upstream, merge_head);
+
+	oidcpy(newbase, merge_head);
+
+	return 0;
+}
+
+/**
+ * Given the <newbase> and <upstream> calculated by
+ * get_rebase_newbase_and_upstream(), runs git-rebase with the
+ * appropriate arguments and returns its exit status.
+ */
+static int run_rebase(const struct object_id *newbase,
+		const struct object_id *upstream)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	strvec_push(&cmd.args, "rebase");
+
+	/* Shared options */
+	argv_push_verbosity(&cmd.args);
+
+	/* Options passed to git-rebase */
+	if (opt_rebase == REBASE_MERGES)
+		strvec_push(&cmd.args, "--rebase-merges");
+	else if (opt_rebase == REBASE_INTERACTIVE)
+		strvec_push(&cmd.args, "--interactive");
+	if (opt_diffstat)
+		strvec_push(&cmd.args, opt_diffstat);
+	strvec_pushv(&cmd.args, opt_strategies.v);
+	strvec_pushv(&cmd.args, opt_strategy_opts.v);
+	if (opt_gpg_sign)
+		strvec_push(&cmd.args, opt_gpg_sign);
+	if (opt_signoff)
+		strvec_push(&cmd.args, opt_signoff);
+	if (opt_autostash == 0)
+		strvec_push(&cmd.args, "--no-autostash");
+	else if (opt_autostash == 1)
+		strvec_push(&cmd.args, "--autostash");
+	if (opt_verify_signatures &&
+	    !strcmp(opt_verify_signatures, "--verify-signatures"))
+		warning(_("ignoring --verify-signatures for rebase"));
+
+	strvec_push(&cmd.args, "--onto");
+	strvec_push(&cmd.args, oid_to_hex(newbase));
+
+	strvec_push(&cmd.args, oid_to_hex(upstream));
+
+	cmd.git_cmd = 1;
+	return run_command(&cmd);
+}
+
+static int get_can_ff(struct object_id *orig_head,
+		      struct oid_array *merge_heads)
+{
+	int ret;
+	struct commit_list *list = NULL;
+	struct commit *merge_head, *head;
+	struct object_id *orig_merge_head;
+
+	if (merge_heads->nr > 1)
+		return 0;
+
+	orig_merge_head = &merge_heads->oid[0];
+	head = lookup_commit_reference(the_repository, orig_head);
+	commit_list_insert(head, &list);
+	merge_head = lookup_commit_reference(the_repository, orig_merge_head);
+	ret = repo_is_descendant_of(the_repository, merge_head, list);
+	free_commit_list(list);
+	if (ret < 0)
+		exit(128);
+	return ret;
+}
+
+/*
+ * Is orig_head a descendant of _all_ merge_heads?
+ * Unfortunately is_descendant_of() cannot be used as it asks
+ * if orig_head is a descendant of at least one of them.
+ */
+static int already_up_to_date(struct object_id *orig_head,
+			      struct oid_array *merge_heads)
+{
+	struct commit *ours;
+
+	ours = lookup_commit_reference(the_repository, orig_head);
+	for (size_t i = 0; i < merge_heads->nr; i++) {
+		struct commit_list *list = NULL;
+		struct commit *theirs;
+		int ok;
+
+		theirs = lookup_commit_reference(the_repository, &merge_heads->oid[i]);
+		commit_list_insert(theirs, &list);
+		ok = repo_is_descendant_of(the_repository, ours, list);
+		free_commit_list(list);
+		if (ok < 0)
+			exit(128);
+		if (!ok)
+			return 0;
+	}
+	return 1;
+}
+
+static void show_advice_pull_non_ff(void)
+{
+	advise(_("You have divergent branches and need to specify how to reconcile them.\n"
+		 "You can do so by running one of the following commands sometime before\n"
+		 "your next pull:\n"
+		 "\n"
+		 "  git config pull.rebase false  # merge\n"
+		 "  git config pull.rebase true   # rebase\n"
+		 "  git config pull.ff only       # fast-forward only\n"
+		 "\n"
+		 "You can replace \"git config\" with \"git config --global\" to set a default\n"
+		 "preference for all repositories. You can also pass --rebase, --no-rebase,\n"
+		 "or --ff-only on the command line to override the configured default per\n"
+		 "invocation.\n"));
+}
+
+int cmd_pull(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repository UNUSED)
+{
+	const char *repo, **refspecs;
+	struct oid_array merge_heads = OID_ARRAY_INIT;
+	struct object_id orig_head, curr_head;
+	struct object_id rebase_fork_point;
+	int rebase_unspecified = 0;
+	int can_ff;
+	int divergent;
+	int ret;
+
+	if (!getenv("GIT_REFLOG_ACTION"))
+		set_reflog_message(argc, argv);
+
+	git_config(git_pull_config, NULL);
+	if (the_repository->gitdir) {
+		prepare_repo_settings(the_repository);
+		the_repository->settings.command_requires_full_index = 0;
+	}
+
+	argc = parse_options(argc, argv, prefix, pull_options, pull_usage, 0);
+
+	if (recurse_submodules_cli != RECURSE_SUBMODULES_DEFAULT)
+		recurse_submodules = recurse_submodules_cli;
+
+	if (cleanup_arg)
+		/*
+		 * this only checks the validity of cleanup_arg; we don't need
+		 * a valid value for use_editor
+		 */
+		get_cleanup_mode(cleanup_arg, 0);
+
+	parse_repo_refspecs(argc, argv, &repo, &refspecs);
+
+	if (!opt_ff) {
+		opt_ff = xstrdup_or_null(config_get_ff());
+		/*
+		 * A subtle point: opt_ff was set on the line above via
+		 * reading from config.  opt_rebase, in contrast, is set
+		 * before this point via command line options.  The setting
+		 * of opt_rebase via reading from config (using
+		 * config_get_rebase()) does not happen until later.  We
+		 * are relying on the next if-condition happening before
+		 * the config_get_rebase() call so that an explicit
+		 * "--rebase" can override a config setting of
+		 * pull.ff=only.
+		 */
+		if (opt_rebase >= 0 && opt_ff && !strcmp(opt_ff, "--ff-only")) {
+			free(opt_ff);
+			opt_ff = xstrdup("--ff");
+		}
+	}
+
+	if (opt_rebase < 0)
+		opt_rebase = config_get_rebase(&rebase_unspecified);
+
+	if (repo_read_index_unmerged(the_repository))
+		die_resolve_conflict("pull");
+
+	if (file_exists(git_path_merge_head(the_repository)))
+		die_conclude_merge();
+
+	if (repo_get_oid(the_repository, "HEAD", &orig_head))
+		oidclr(&orig_head, the_repository->hash_algo);
+
+	if (opt_rebase) {
+		if (opt_autostash == -1)
+			opt_autostash = config_autostash;
+
+		if (is_null_oid(&orig_head) && !is_index_unborn(the_repository->index))
+			die(_("Updating an unborn branch with changes added to the index."));
+
+		if (!opt_autostash)
+			require_clean_work_tree(the_repository,
+				N_("pull with rebase"),
+				_("Please commit or stash them."), 1, 0);
+
+		if (get_rebase_fork_point(&rebase_fork_point, repo, *refspecs))
+			oidclr(&rebase_fork_point, the_repository->hash_algo);
+	}
+
+	if (run_fetch(repo, refspecs))
+		return 1;
+
+	if (opt_dry_run)
+		return 0;
+
+	if (repo_get_oid(the_repository, "HEAD", &curr_head))
+		oidclr(&curr_head, the_repository->hash_algo);
+
+	if (!is_null_oid(&orig_head) && !is_null_oid(&curr_head) &&
+			!oideq(&orig_head, &curr_head)) {
+		/*
+		 * The fetch involved updating the current branch.
+		 *
+		 * The working tree and the index file are still based on
+		 * orig_head commit, but we are merging into curr_head.
+		 * Update the working tree to match curr_head.
+		 */
+
+		warning(_("fetch updated the current branch head.\n"
+			"fast-forwarding your working tree from\n"
+			"commit %s."), oid_to_hex(&orig_head));
+
+		if (checkout_fast_forward(the_repository, &orig_head,
+					  &curr_head, 0))
+			die(_("Cannot fast-forward your working tree.\n"
+				"After making sure that you saved anything precious from\n"
+				"$ git diff %s\n"
+				"output, run\n"
+				"$ git reset --hard\n"
+				"to recover."), oid_to_hex(&orig_head));
+	}
+
+	get_merge_heads(&merge_heads);
+
+	if (!merge_heads.nr)
+		die_no_merge_candidates(repo, refspecs);
+
+	if (is_null_oid(&orig_head)) {
+		if (merge_heads.nr > 1)
+			die(_("Cannot merge multiple branches into empty head."));
+		ret = pull_into_void(merge_heads.oid, &curr_head);
+		goto cleanup;
+	}
+	if (merge_heads.nr > 1) {
+		if (opt_rebase)
+			die(_("Cannot rebase onto multiple branches."));
+		if (opt_ff && !strcmp(opt_ff, "--ff-only"))
+			die(_("Cannot fast-forward to multiple branches."));
+	}
+
+	can_ff = get_can_ff(&orig_head, &merge_heads);
+	divergent = !can_ff && !already_up_to_date(&orig_head, &merge_heads);
+
+	/* ff-only takes precedence over rebase */
+	if (opt_ff && !strcmp(opt_ff, "--ff-only")) {
+		if (divergent)
+			die_ff_impossible();
+		opt_rebase = REBASE_FALSE;
+	}
+	/* If no action specified and we can't fast forward, then warn. */
+	if (!opt_ff && rebase_unspecified && divergent) {
+		show_advice_pull_non_ff();
+		die(_("Need to specify how to reconcile divergent branches."));
+	}
+
+	if (opt_rebase) {
+		struct object_id newbase;
+		struct object_id upstream;
+		get_rebase_newbase_and_upstream(&newbase, &upstream, &curr_head,
+						merge_heads.oid, &rebase_fork_point);
+
+		if ((recurse_submodules == RECURSE_SUBMODULES_ON ||
+		     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) &&
+		    submodule_touches_in_range(the_repository, &upstream, &curr_head))
+			die(_("cannot rebase with locally recorded submodule modifications"));
+
+		if (can_ff) {
+			/* we can fast-forward this without invoking rebase */
+			free(opt_ff);
+			opt_ff = xstrdup("--ff-only");
+			ret = run_merge();
+		} else {
+			ret = run_rebase(&newbase, &upstream);
+		}
+
+		if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
+			     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
+			ret = rebase_submodules();
+
+		goto cleanup;
+	} else {
+		ret = run_merge();
+		if (!ret && (recurse_submodules == RECURSE_SUBMODULES_ON ||
+			     recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND))
+			ret = update_submodules();
+		goto cleanup;
+	}
+
+cleanup:
+	oid_array_clear(&merge_heads);
+	return ret;
+}
diff --git a/builtin/push.c b/builtin/push.c
new file mode 100644
index 0000000000..90de3746b5
--- /dev/null
+++ b/builtin/push.c
@@ -0,0 +1,672 @@
+/*
+ * "git push"
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "advice.h"
+#include "branch.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "refspec.h"
+#include "run-command.h"
+#include "remote.h"
+#include "transport.h"
+#include "parse-options.h"
+#include "pkt-line.h"
+#include "submodule.h"
+#include "submodule-config.h"
+#include "send-pack.h"
+#include "trace2.h"
+#include "color.h"
+
+static const char * const push_usage[] = {
+	N_("git push [<options>] [<repository> [<refspec>...]]"),
+	NULL,
+};
+
+static int push_use_color = -1;
+static char push_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_RED,	/* ERROR */
+};
+
+enum color_push {
+	PUSH_COLOR_RESET = 0,
+	PUSH_COLOR_ERROR = 1
+};
+
+static int parse_push_color_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "reset"))
+		return PUSH_COLOR_RESET;
+	if (!strcasecmp(slot, "error"))
+		return PUSH_COLOR_ERROR;
+	return -1;
+}
+
+static const char *push_get_color(enum color_push ix)
+{
+	if (want_color_stderr(push_use_color))
+		return push_colors[ix];
+	return "";
+}
+
+static int thin = 1;
+static int deleterefs;
+static const char *receivepack;
+static int verbosity;
+static int progress = -1;
+static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
+static enum transport_family family;
+
+static struct push_cas_option cas;
+
+static struct refspec rs = REFSPEC_INIT_PUSH;
+
+static struct string_list push_options_config = STRING_LIST_INIT_DUP;
+
+static void refspec_append_mapped(struct refspec *refspec, const char *ref,
+				  struct remote *remote, struct ref *matched)
+{
+	const char *branch_name;
+
+	if (remote->push.nr) {
+		struct refspec_item query = {
+			.src = matched->name,
+		};
+
+		if (!query_refspecs(&remote->push, &query) && query.dst) {
+			refspec_appendf(refspec, "%s%s:%s",
+					query.force ? "+" : "",
+					query.src, query.dst);
+			free(query.dst);
+			return;
+		}
+	}
+
+	if (push_default == PUSH_DEFAULT_UPSTREAM &&
+	    skip_prefix(matched->name, "refs/heads/", &branch_name)) {
+		struct branch *branch = branch_get(branch_name);
+		if (branch->merge_nr == 1 && branch->merge[0]->src) {
+			refspec_appendf(refspec, "%s:%s",
+					ref, branch->merge[0]->src);
+			return;
+		}
+	}
+
+	refspec_append(refspec, ref);
+}
+
+static void set_refspecs(const char **refs, int nr, struct remote *remote)
+{
+	struct ref *local_refs = NULL;
+	int i;
+
+	for (i = 0; i < nr; i++) {
+		const char *ref = refs[i];
+		if (!strcmp("tag", ref)) {
+			if (nr <= ++i)
+				die(_("tag shorthand without <tag>"));
+			ref = refs[i];
+			if (deleterefs)
+				refspec_appendf(&rs, ":refs/tags/%s", ref);
+			else
+				refspec_appendf(&rs, "refs/tags/%s", ref);
+		} else if (deleterefs) {
+			if (strchr(ref, ':') || !*ref)
+				die(_("--delete only accepts plain target ref names"));
+			refspec_appendf(&rs, ":%s", ref);
+		} else if (!strchr(ref, ':')) {
+			struct ref *matched = NULL;
+
+			/* lazily grab local_refs */
+			if (!local_refs)
+				local_refs = get_local_heads();
+
+			/* Does "ref" uniquely name our ref? */
+			if (count_refspec_match(ref, local_refs, &matched) != 1)
+				refspec_append(&rs, ref);
+			else
+				refspec_append_mapped(&rs, ref, remote, matched);
+		} else
+			refspec_append(&rs, ref);
+	}
+	free_refs(local_refs);
+}
+
+static NORETURN void die_push_simple(struct branch *branch,
+				     struct remote *remote)
+{
+	/*
+	 * There's no point in using shorten_unambiguous_ref here,
+	 * as the ambiguity would be on the remote side, not what
+	 * we have locally. Plus, this is supposed to be the simple
+	 * mode. If the user is doing something crazy like setting
+	 * upstream to a non-branch, we should probably be showing
+	 * them the big ugly fully qualified ref.
+	 */
+	const char *advice_pushdefault_maybe = "";
+	const char *advice_automergesimple_maybe = "";
+	const char *short_upstream = branch->merge[0]->src;
+
+	skip_prefix(short_upstream, "refs/heads/", &short_upstream);
+
+	/*
+	 * Don't show advice for people who explicitly set
+	 * push.default.
+	 */
+	if (push_default == PUSH_DEFAULT_UNSPECIFIED)
+		advice_pushdefault_maybe = _("\n"
+				 "To choose either option permanently, "
+				 "see push.default in 'git help config'.\n");
+	if (git_branch_track != BRANCH_TRACK_SIMPLE)
+		advice_automergesimple_maybe = _("\n"
+				 "To avoid automatically configuring "
+				 "an upstream branch when its name\n"
+				 "won't match the local branch, see option "
+				 "'simple' of branch.autoSetupMerge\n"
+				 "in 'git help config'.\n");
+	die(_("The upstream branch of your current branch does not match\n"
+	      "the name of your current branch.  To push to the upstream branch\n"
+	      "on the remote, use\n"
+	      "\n"
+	      "    git push %s HEAD:%s\n"
+	      "\n"
+	      "To push to the branch of the same name on the remote, use\n"
+	      "\n"
+	      "    git push %s HEAD\n"
+	      "%s%s"),
+	    remote->name, short_upstream,
+	    remote->name, advice_pushdefault_maybe,
+	    advice_automergesimple_maybe);
+}
+
+static const char message_detached_head_die[] =
+	N_("You are not currently on a branch.\n"
+	   "To push the history leading to the current (detached HEAD)\n"
+	   "state now, use\n"
+	   "\n"
+	   "    git push %s HEAD:<name-of-remote-branch>\n");
+
+static const char *get_upstream_ref(int flags, struct branch *branch, const char *remote_name)
+{
+	if (branch->merge_nr == 0 && (flags & TRANSPORT_PUSH_AUTO_UPSTREAM)) {
+		/* if missing, assume same; set_upstream will be defined later */
+		return branch->refname;
+	}
+
+	if (!branch->merge_nr || !branch->merge || !branch->remote_name) {
+		const char *advice_autosetup_maybe = "";
+		if (!(flags & TRANSPORT_PUSH_AUTO_UPSTREAM)) {
+			advice_autosetup_maybe = _("\n"
+					   "To have this happen automatically for "
+					   "branches without a tracking\n"
+					   "upstream, see 'push.autoSetupRemote' "
+					   "in 'git help config'.\n");
+		}
+		die(_("The current branch %s has no upstream branch.\n"
+		    "To push the current branch and set the remote as upstream, use\n"
+		    "\n"
+		    "    git push --set-upstream %s %s\n"
+		    "%s"),
+		    branch->name,
+		    remote_name,
+		    branch->name,
+		    advice_autosetup_maybe);
+	}
+	if (branch->merge_nr != 1)
+		die(_("The current branch %s has multiple upstream branches, "
+		    "refusing to push."), branch->name);
+
+	return branch->merge[0]->src;
+}
+
+static void setup_default_push_refspecs(int *flags, struct remote *remote)
+{
+	struct branch *branch;
+	const char *dst;
+	int same_remote;
+
+	switch (push_default) {
+	case PUSH_DEFAULT_MATCHING:
+		refspec_append(&rs, ":");
+		return;
+
+	case PUSH_DEFAULT_NOTHING:
+		die(_("You didn't specify any refspecs to push, and "
+		    "push.default is \"nothing\"."));
+		return;
+	default:
+		break;
+	}
+
+	branch = branch_get(NULL);
+	if (!branch)
+		die(_(message_detached_head_die), remote->name);
+
+	dst = branch->refname;
+	same_remote = !strcmp(remote->name, remote_for_branch(branch, NULL));
+
+	switch (push_default) {
+	default:
+	case PUSH_DEFAULT_UNSPECIFIED:
+	case PUSH_DEFAULT_SIMPLE:
+		if (!same_remote)
+			break;
+		if (strcmp(branch->refname, get_upstream_ref(*flags, branch, remote->name)))
+			die_push_simple(branch, remote);
+		break;
+
+	case PUSH_DEFAULT_UPSTREAM:
+		if (!same_remote)
+			die(_("You are pushing to remote '%s', which is not the upstream of\n"
+			      "your current branch '%s', without telling me what to push\n"
+			      "to update which remote branch."),
+			    remote->name, branch->name);
+		dst = get_upstream_ref(*flags, branch, remote->name);
+		break;
+
+	case PUSH_DEFAULT_CURRENT:
+		break;
+	}
+
+	/*
+	 * this is a default push - if auto-upstream is enabled and there is
+	 * no upstream defined, then set it (with options 'simple', 'upstream',
+	 * and 'current').
+	 */
+	if ((*flags & TRANSPORT_PUSH_AUTO_UPSTREAM) && branch->merge_nr == 0)
+		*flags |= TRANSPORT_PUSH_SET_UPSTREAM;
+
+	refspec_appendf(&rs, "%s:%s", branch->refname, dst);
+}
+
+static const char message_advice_pull_before_push[] =
+	N_("Updates were rejected because the tip of your current branch is behind\n"
+	   "its remote counterpart. If you want to integrate the remote changes,\n"
+	   "use 'git pull' before pushing again.\n"
+	   "See the 'Note about fast-forwards' in 'git push --help' for details.");
+
+static const char message_advice_checkout_pull_push[] =
+	N_("Updates were rejected because a pushed branch tip is behind its remote\n"
+	   "counterpart. If you want to integrate the remote changes, use 'git pull'\n"
+	   "before pushing again.\n"
+	   "See the 'Note about fast-forwards' in 'git push --help' for details.");
+
+static const char message_advice_ref_fetch_first[] =
+	N_("Updates were rejected because the remote contains work that you do not\n"
+	   "have locally. This is usually caused by another repository pushing to\n"
+	   "the same ref. If you want to integrate the remote changes, use\n"
+	   "'git pull' before pushing again.\n"
+	   "See the 'Note about fast-forwards' in 'git push --help' for details.");
+
+static const char message_advice_ref_already_exists[] =
+	N_("Updates were rejected because the tag already exists in the remote.");
+
+static const char message_advice_ref_needs_force[] =
+	N_("You cannot update a remote ref that points at a non-commit object,\n"
+	   "or update a remote ref to make it point at a non-commit object,\n"
+	   "without using the '--force' option.\n");
+
+static const char message_advice_ref_needs_update[] =
+	N_("Updates were rejected because the tip of the remote-tracking branch has\n"
+	   "been updated since the last checkout. If you want to integrate the\n"
+	   "remote changes, use 'git pull' before pushing again.\n"
+	   "See the 'Note about fast-forwards' in 'git push --help' for details.");
+
+static void advise_pull_before_push(void)
+{
+	if (!advice_enabled(ADVICE_PUSH_NON_FF_CURRENT) || !advice_enabled(ADVICE_PUSH_UPDATE_REJECTED))
+		return;
+	advise(_(message_advice_pull_before_push));
+}
+
+static void advise_checkout_pull_push(void)
+{
+	if (!advice_enabled(ADVICE_PUSH_NON_FF_MATCHING) || !advice_enabled(ADVICE_PUSH_UPDATE_REJECTED))
+		return;
+	advise(_(message_advice_checkout_pull_push));
+}
+
+static void advise_ref_already_exists(void)
+{
+	if (!advice_enabled(ADVICE_PUSH_ALREADY_EXISTS) || !advice_enabled(ADVICE_PUSH_UPDATE_REJECTED))
+		return;
+	advise(_(message_advice_ref_already_exists));
+}
+
+static void advise_ref_fetch_first(void)
+{
+	if (!advice_enabled(ADVICE_PUSH_FETCH_FIRST) || !advice_enabled(ADVICE_PUSH_UPDATE_REJECTED))
+		return;
+	advise(_(message_advice_ref_fetch_first));
+}
+
+static void advise_ref_needs_force(void)
+{
+	if (!advice_enabled(ADVICE_PUSH_NEEDS_FORCE) || !advice_enabled(ADVICE_PUSH_UPDATE_REJECTED))
+		return;
+	advise(_(message_advice_ref_needs_force));
+}
+
+static void advise_ref_needs_update(void)
+{
+	if (!advice_enabled(ADVICE_PUSH_REF_NEEDS_UPDATE) || !advice_enabled(ADVICE_PUSH_UPDATE_REJECTED))
+		return;
+	advise(_(message_advice_ref_needs_update));
+}
+
+static int push_with_options(struct transport *transport, struct refspec *rs,
+			     int flags)
+{
+	int err;
+	unsigned int reject_reasons;
+	char *anon_url = transport_anonymize_url(transport->url);
+
+	transport_set_verbosity(transport, verbosity, progress);
+	transport->family = family;
+
+	if (receivepack)
+		transport_set_option(transport,
+				     TRANS_OPT_RECEIVEPACK, receivepack);
+	transport_set_option(transport, TRANS_OPT_THIN, thin ? "yes" : NULL);
+
+	if (!is_empty_cas(&cas)) {
+		if (!transport->smart_options)
+			die("underlying transport does not support --%s option",
+			    "force-with-lease");
+		transport->smart_options->cas = &cas;
+	}
+
+	if (verbosity > 0)
+		fprintf(stderr, _("Pushing to %s\n"), anon_url);
+	trace2_region_enter("push", "transport_push", the_repository);
+	err = transport_push(the_repository, transport,
+			     rs, flags, &reject_reasons);
+	trace2_region_leave("push", "transport_push", the_repository);
+	if (err != 0) {
+		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
+		error(_("failed to push some refs to '%s'"), anon_url);
+		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_RESET));
+	}
+
+	err |= transport_disconnect(transport);
+	free(anon_url);
+	if (!err)
+		return 0;
+
+	if (reject_reasons & REJECT_NON_FF_HEAD) {
+		advise_pull_before_push();
+	} else if (reject_reasons & REJECT_NON_FF_OTHER) {
+		advise_checkout_pull_push();
+	} else if (reject_reasons & REJECT_ALREADY_EXISTS) {
+		advise_ref_already_exists();
+	} else if (reject_reasons & REJECT_FETCH_FIRST) {
+		advise_ref_fetch_first();
+	} else if (reject_reasons & REJECT_NEEDS_FORCE) {
+		advise_ref_needs_force();
+	} else if (reject_reasons & REJECT_REF_NEEDS_UPDATE) {
+		advise_ref_needs_update();
+	}
+
+	return 1;
+}
+
+static int do_push(int flags,
+		   const struct string_list *push_options,
+		   struct remote *remote)
+{
+	int errs;
+	struct strvec *url;
+	struct refspec *push_refspec = &rs;
+
+	if (push_options->nr)
+		flags |= TRANSPORT_PUSH_OPTIONS;
+
+	if (!push_refspec->nr && !(flags & TRANSPORT_PUSH_ALL)) {
+		if (remote->push.nr) {
+			push_refspec = &remote->push;
+		} else if (!(flags & TRANSPORT_PUSH_MIRROR))
+			setup_default_push_refspecs(&flags, remote);
+	}
+	errs = 0;
+	url = push_url_of_remote(remote);
+	for (size_t i = 0; i < url->nr; i++) {
+		struct transport *transport =
+			transport_get(remote, url->v[i]);
+		if (flags & TRANSPORT_PUSH_OPTIONS)
+			transport->push_options = push_options;
+		if (push_with_options(transport, push_refspec, flags))
+			errs++;
+	}
+	return !!errs;
+}
+
+static int option_parse_recurse_submodules(const struct option *opt,
+				   const char *arg, int unset)
+{
+	int *recurse_submodules = opt->value;
+
+	if (unset)
+		*recurse_submodules = RECURSE_SUBMODULES_OFF;
+	else {
+		if (!strcmp(arg, "only-is-on-demand")) {
+			if (*recurse_submodules == RECURSE_SUBMODULES_ONLY) {
+				warning(_("recursing into submodule with push.recurseSubmodules=only; using on-demand instead"));
+				*recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
+			}
+		} else {
+			*recurse_submodules = parse_push_recurse_submodules_arg(opt->long_name, arg);
+		}
+	}
+
+	return 0;
+}
+
+static void set_push_cert_flags(int *flags, int v)
+{
+	switch (v) {
+	case SEND_PACK_PUSH_CERT_NEVER:
+		*flags &= ~(TRANSPORT_PUSH_CERT_ALWAYS | TRANSPORT_PUSH_CERT_IF_ASKED);
+		break;
+	case SEND_PACK_PUSH_CERT_ALWAYS:
+		*flags |= TRANSPORT_PUSH_CERT_ALWAYS;
+		*flags &= ~TRANSPORT_PUSH_CERT_IF_ASKED;
+		break;
+	case SEND_PACK_PUSH_CERT_IF_ASKED:
+		*flags |= TRANSPORT_PUSH_CERT_IF_ASKED;
+		*flags &= ~TRANSPORT_PUSH_CERT_ALWAYS;
+		break;
+	}
+}
+
+
+static int git_push_config(const char *k, const char *v,
+			   const struct config_context *ctx, void *cb)
+{
+	const char *slot_name;
+	int *flags = cb;
+
+	if (!strcmp(k, "push.followtags")) {
+		if (git_config_bool(k, v))
+			*flags |= TRANSPORT_PUSH_FOLLOW_TAGS;
+		else
+			*flags &= ~TRANSPORT_PUSH_FOLLOW_TAGS;
+		return 0;
+	} else if (!strcmp(k, "push.autosetupremote")) {
+		if (git_config_bool(k, v))
+			*flags |= TRANSPORT_PUSH_AUTO_UPSTREAM;
+		return 0;
+	} else if (!strcmp(k, "push.gpgsign")) {
+		switch (git_parse_maybe_bool(v)) {
+		case 0:
+			set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_NEVER);
+			break;
+		case 1:
+			set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_ALWAYS);
+			break;
+		default:
+			if (!strcasecmp(v, "if-asked"))
+				set_push_cert_flags(flags, SEND_PACK_PUSH_CERT_IF_ASKED);
+			else
+				return error(_("invalid value for '%s'"), k);
+		}
+	} else if (!strcmp(k, "push.recursesubmodules")) {
+		recurse_submodules = parse_push_recurse_submodules_arg(k, v);
+	} else if (!strcmp(k, "submodule.recurse")) {
+		int val = git_config_bool(k, v) ?
+			RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
+		recurse_submodules = val;
+	} else if (!strcmp(k, "push.pushoption")) {
+		return parse_transport_option(k, v, &push_options_config);
+	} else if (!strcmp(k, "color.push")) {
+		push_use_color = git_config_colorbool(k, v);
+		return 0;
+	} else if (skip_prefix(k, "color.push.", &slot_name)) {
+		int slot = parse_push_color_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!v)
+			return config_error_nonbool(k);
+		return color_parse(v, push_colors[slot]);
+	} else if (!strcmp(k, "push.useforceifincludes")) {
+		if (git_config_bool(k, v))
+			*flags |= TRANSPORT_PUSH_FORCE_IF_INCLUDES;
+		else
+			*flags &= ~TRANSPORT_PUSH_FORCE_IF_INCLUDES;
+		return 0;
+	}
+
+	return git_default_config(k, v, ctx, NULL);
+}
+
+int cmd_push(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repository UNUSED)
+{
+	int flags = 0;
+	int tags = 0;
+	int push_cert = -1;
+	int rc;
+	const char *repo = NULL;	/* default repository */
+	struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
+	struct string_list *push_options;
+	const struct string_list_item *item;
+	struct remote *remote;
+
+	struct option options[] = {
+		OPT__VERBOSITY(&verbosity),
+		OPT_STRING( 0 , "repo", &repo, N_("repository"), N_("repository")),
+		OPT_BIT( 0 , "all", &flags, N_("push all branches"), TRANSPORT_PUSH_ALL),
+		OPT_ALIAS( 0 , "branches", "all"),
+		OPT_BIT( 0 , "mirror", &flags, N_("mirror all refs"),
+			    (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE)),
+		OPT_BOOL('d', "delete", &deleterefs, N_("delete refs")),
+		OPT_BOOL( 0 , "tags", &tags, N_("push tags (can't be used with --all or --branches or --mirror)")),
+		OPT_BIT('n' , "dry-run", &flags, N_("dry run"), TRANSPORT_PUSH_DRY_RUN),
+		OPT_BIT( 0,  "porcelain", &flags, N_("machine-readable output"), TRANSPORT_PUSH_PORCELAIN),
+		OPT_BIT('f', "force", &flags, N_("force updates"), TRANSPORT_PUSH_FORCE),
+		OPT_CALLBACK_F(0, "force-with-lease", &cas, N_("<refname>:<expect>"),
+			       N_("require old value of ref to be at this value"),
+			       PARSE_OPT_OPTARG | PARSE_OPT_LITERAL_ARGHELP, parseopt_push_cas_option),
+		OPT_BIT(0, TRANS_OPT_FORCE_IF_INCLUDES, &flags,
+			N_("require remote updates to be integrated locally"),
+			TRANSPORT_PUSH_FORCE_IF_INCLUDES),
+		OPT_CALLBACK(0, "recurse-submodules", &recurse_submodules, "(check|on-demand|no)",
+			     N_("control recursive pushing of submodules"), option_parse_recurse_submodules),
+		OPT_BOOL_F( 0 , "thin", &thin, N_("use thin pack"), PARSE_OPT_NOCOMPLETE),
+		OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
+		OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive pack program")),
+		OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"),
+			TRANSPORT_PUSH_SET_UPSTREAM),
+		OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+		OPT_BIT(0, "prune", &flags, N_("prune locally removed refs"),
+			TRANSPORT_PUSH_PRUNE),
+		OPT_BIT(0, "no-verify", &flags, N_("bypass pre-push hook"), TRANSPORT_PUSH_NO_HOOK),
+		OPT_BIT(0, "follow-tags", &flags, N_("push missing but relevant tags"),
+			TRANSPORT_PUSH_FOLLOW_TAGS),
+		OPT_CALLBACK_F(0, "signed", &push_cert, "(yes|no|if-asked)", N_("GPG sign the push"),
+				PARSE_OPT_OPTARG, option_parse_push_signed),
+		OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
+		OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")),
+		OPT_IPVERSION(&family),
+		OPT_END()
+	};
+
+	packet_trace_identity("push");
+	git_config(git_push_config, &flags);
+	argc = parse_options(argc, argv, prefix, options, push_usage, 0);
+	push_options = (push_options_cmdline.nr
+		? &push_options_cmdline
+		: &push_options_config);
+	set_push_cert_flags(&flags, push_cert);
+
+	die_for_incompatible_opt4(deleterefs, "--delete",
+				  tags, "--tags",
+				  flags & TRANSPORT_PUSH_ALL, "--all/--branches",
+				  flags & TRANSPORT_PUSH_MIRROR, "--mirror");
+	if (deleterefs && argc < 2)
+		die(_("--delete doesn't make sense without any refs"));
+
+	if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
+		flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
+	else if (recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND)
+		flags |= TRANSPORT_RECURSE_SUBMODULES_ON_DEMAND;
+	else if (recurse_submodules == RECURSE_SUBMODULES_ONLY)
+		flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY;
+
+	if (tags)
+		refspec_append(&rs, "refs/tags/*");
+
+	if (argc > 0)
+		repo = argv[0];
+
+	remote = pushremote_get(repo);
+	if (!remote) {
+		if (repo)
+			die(_("bad repository '%s'"), repo);
+		die(_("No configured push destination.\n"
+		    "Either specify the URL from the command-line or configure a remote repository using\n"
+		    "\n"
+		    "    git remote add <name> <url>\n"
+		    "\n"
+		    "and then push using the remote name\n"
+		    "\n"
+		    "    git push <name>\n"));
+	}
+
+	if (argc > 0)
+		set_refspecs(argv + 1, argc - 1, remote);
+
+	if (remote->mirror)
+		flags |= (TRANSPORT_PUSH_MIRROR|TRANSPORT_PUSH_FORCE);
+
+	if (flags & TRANSPORT_PUSH_ALL) {
+		if (argc >= 2)
+			die(_("--all can't be combined with refspecs"));
+	}
+	if (flags & TRANSPORT_PUSH_MIRROR) {
+		if (argc >= 2)
+			die(_("--mirror can't be combined with refspecs"));
+	}
+
+	if (!is_empty_cas(&cas) && (flags & TRANSPORT_PUSH_FORCE_IF_INCLUDES))
+		cas.use_force_if_includes = 1;
+
+	for_each_string_list_item(item, push_options)
+		if (strchr(item->string, '\n'))
+			die(_("push options must not have new line characters"));
+
+	rc = do_push(flags, push_options, remote);
+	string_list_clear(&push_options_cmdline, 0);
+	string_list_clear(&push_options_config, 0);
+	clear_cas_option(&cas);
+	if (rc == -1)
+		usage_with_options(push_usage, options);
+	else
+		return rc;
+}
diff --git a/builtin/range-diff.c b/builtin/range-diff.c
new file mode 100644
index 0000000000..32ddb6613f
--- /dev/null
+++ b/builtin/range-diff.c
@@ -0,0 +1,175 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "range-diff.h"
+#include "config.h"
+
+
+static const char * const builtin_range_diff_usage[] = {
+N_("git range-diff [<options>] <old-base>..<old-tip> <new-base>..<new-tip>"),
+N_("git range-diff [<options>] <old-tip>...<new-tip>"),
+N_("git range-diff [<options>] <base> <old-tip> <new-tip>"),
+NULL
+};
+
+int cmd_range_diff(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct diff_options diffopt = { NULL };
+	struct strvec other_arg = STRVEC_INIT;
+	struct strvec diff_merges_arg = STRVEC_INIT;
+	struct range_diff_options range_diff_opts = {
+		.creation_factor = RANGE_DIFF_CREATION_FACTOR_DEFAULT,
+		.diffopt = &diffopt,
+		.other_arg = &other_arg
+	};
+	int simple_color = -1, left_only = 0, right_only = 0;
+	struct option range_diff_options[] = {
+		OPT_INTEGER(0, "creation-factor",
+			    &range_diff_opts.creation_factor,
+			    N_("percentage by which creation is weighted")),
+		OPT_BOOL(0, "no-dual-color", &simple_color,
+			    N_("use simple diff colors")),
+		OPT_PASSTHRU_ARGV(0, "notes", &other_arg,
+				  N_("notes"), N_("passed to 'git log'"),
+				  PARSE_OPT_OPTARG),
+		OPT_PASSTHRU_ARGV(0, "diff-merges", &diff_merges_arg,
+				  N_("style"), N_("passed to 'git log'"), 0),
+		OPT_PASSTHRU_ARGV(0, "remerge-diff", &diff_merges_arg, NULL,
+				  N_("passed to 'git log'"), PARSE_OPT_NOARG),
+		OPT_BOOL(0, "left-only", &left_only,
+			 N_("only emit output related to the first range")),
+		OPT_BOOL(0, "right-only", &right_only,
+			 N_("only emit output related to the second range")),
+		OPT_END()
+	};
+	struct option *options;
+	int i, dash_dash = -1, res = 0;
+	struct strbuf range1 = STRBUF_INIT, range2 = STRBUF_INIT;
+	struct object_id oid;
+	const char *three_dots = NULL;
+
+	git_config(git_diff_ui_config, NULL);
+
+	repo_diff_setup(the_repository, &diffopt);
+
+	options = add_diff_options(range_diff_options, &diffopt);
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_range_diff_usage, PARSE_OPT_KEEP_DASHDASH);
+
+	diff_setup_done(&diffopt);
+
+	/* force color when --dual-color was used */
+	if (!simple_color)
+		diffopt.use_color = 1;
+
+	/* If `--diff-merges` was specified, imply `--merges` */
+	if (diff_merges_arg.nr) {
+		range_diff_opts.include_merges = 1;
+		strvec_pushv(&other_arg, diff_merges_arg.v);
+	}
+
+	for (i = 0; i < argc; i++)
+		if (!strcmp(argv[i], "--")) {
+			dash_dash = i;
+			break;
+		}
+
+	if (dash_dash == 3 ||
+	    (dash_dash < 0 && argc > 2 &&
+	     !repo_get_oid_committish(the_repository, argv[0], &oid) &&
+	     !repo_get_oid_committish(the_repository, argv[1], &oid) &&
+	     !repo_get_oid_committish(the_repository, argv[2], &oid))) {
+		if (dash_dash < 0)
+			; /* already validated arguments */
+		else if (repo_get_oid_committish(the_repository, argv[0], &oid))
+			usage_msg_optf(_("not a revision: '%s'"),
+				       builtin_range_diff_usage, options,
+				       argv[0]);
+		else if (repo_get_oid_committish(the_repository, argv[1], &oid))
+			usage_msg_optf(_("not a revision: '%s'"),
+				       builtin_range_diff_usage, options,
+				       argv[1]);
+		else if (repo_get_oid_committish(the_repository, argv[2], &oid))
+			usage_msg_optf(_("not a revision: '%s'"),
+				       builtin_range_diff_usage, options,
+				       argv[2]);
+
+		strbuf_addf(&range1, "%s..%s", argv[0], argv[1]);
+		strbuf_addf(&range2, "%s..%s", argv[0], argv[2]);
+
+		strvec_pushv(&other_arg, argv +
+			     (dash_dash < 0 ? 3 : dash_dash));
+	} else if (dash_dash == 2 ||
+		   (dash_dash < 0 && argc > 1 &&
+		    is_range_diff_range(argv[0]) &&
+		    is_range_diff_range(argv[1]))) {
+		if (dash_dash < 0)
+			; /* already validated arguments */
+		else if (!is_range_diff_range(argv[0]))
+			usage_msg_optf(_("not a commit range: '%s'"),
+				       builtin_range_diff_usage, options,
+				       argv[0]);
+		else if (!is_range_diff_range(argv[1]))
+			usage_msg_optf(_("not a commit range: '%s'"),
+				       builtin_range_diff_usage, options,
+				       argv[1]);
+
+		strbuf_addstr(&range1, argv[0]);
+		strbuf_addstr(&range2, argv[1]);
+
+		strvec_pushv(&other_arg, argv +
+			     (dash_dash < 0 ? 2 : dash_dash));
+	} else if (dash_dash == 1 ||
+		   (dash_dash < 0 && argc > 0 &&
+		    (three_dots = strstr(argv[0], "...")))) {
+		const char *a, *b;
+		int a_len;
+
+		if (dash_dash < 0)
+			; /* already validated arguments */
+		else if (!(three_dots = strstr(argv[0], "...")))
+			usage_msg_optf(_("not a symmetric range: '%s'"),
+					 builtin_range_diff_usage, options,
+					 argv[0]);
+
+		if (three_dots == argv[0]) {
+			a = "HEAD";
+			a_len = strlen(a);
+		} else {
+			a = argv[0];
+			a_len = (int)(three_dots - a);
+		}
+
+		if (three_dots[3])
+			b = three_dots + 3;
+		else
+			b = "HEAD";
+
+		strbuf_addf(&range1, "%s..%.*s", b, a_len, a);
+		strbuf_addf(&range2, "%.*s..%s", a_len, a, b);
+
+		strvec_pushv(&other_arg, argv +
+			     (dash_dash < 0 ? 1 : dash_dash));
+	} else
+		usage_msg_opt(_("need two commit ranges"),
+			      builtin_range_diff_usage, options);
+	FREE_AND_NULL(options);
+
+	range_diff_opts.dual_color = simple_color < 1;
+	range_diff_opts.left_only = left_only;
+	range_diff_opts.right_only = right_only;
+	res = show_range_diff(range1.buf, range2.buf, &range_diff_opts);
+
+	strvec_clear(&other_arg);
+	strvec_clear(&diff_merges_arg);
+	strbuf_release(&range1);
+	strbuf_release(&range2);
+
+	return res;
+}
diff --git a/builtin/read-tree.c b/builtin/read-tree.c
new file mode 100644
index 0000000000..d2a807a828
--- /dev/null
+++ b/builtin/read-tree.c
@@ -0,0 +1,289 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "object.h"
+#include "object-name.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "cache-tree.h"
+#include "unpack-trees.h"
+#include "parse-options.h"
+#include "resolve-undo.h"
+#include "setup.h"
+#include "sparse-index.h"
+#include "submodule.h"
+
+static int nr_trees;
+static int read_empty;
+static struct tree *trees[MAX_UNPACK_TREES];
+
+static int list_tree(struct object_id *oid)
+{
+	struct tree *tree;
+
+	if (nr_trees >= MAX_UNPACK_TREES)
+		die("I cannot read more than %d trees", MAX_UNPACK_TREES);
+	tree = parse_tree_indirect(oid);
+	if (!tree)
+		return -1;
+	trees[nr_trees++] = tree;
+	return 0;
+}
+
+static const char * const read_tree_usage[] = {
+	N_("git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>)\n"
+	   "              [-u | -i]] [--index-output=<file>] [--no-sparse-checkout]\n"
+	   "              (--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])"),
+	NULL
+};
+
+static int index_output_cb(const struct option *opt UNUSED, const char *arg,
+				 int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+	set_alternate_index_output(arg);
+	return 0;
+}
+
+static int exclude_per_directory_cb(const struct option *opt, const char *arg,
+				    int unset)
+{
+	struct unpack_trees_options *opts;
+
+	BUG_ON_OPT_NEG(unset);
+
+	opts = (struct unpack_trees_options *)opt->value;
+
+	if (!opts->update)
+		die("--exclude-per-directory is meaningless unless -u");
+	if (strcmp(arg, ".gitignore"))
+		die("--exclude-per-directory argument must be .gitignore");
+	return 0;
+}
+
+static void debug_stage(const char *label, const struct cache_entry *ce,
+			struct unpack_trees_options *o)
+{
+	printf("%s ", label);
+	if (!ce)
+		printf("(missing)\n");
+	else if (ce == o->df_conflict_entry)
+		printf("(conflict)\n");
+	else
+		printf("%06o #%d %s %.8s\n",
+		       ce->ce_mode, ce_stage(ce), ce->name,
+		       oid_to_hex(&ce->oid));
+}
+
+static int debug_merge(const struct cache_entry * const *stages,
+		       struct unpack_trees_options *o)
+{
+	int i;
+
+	printf("* %d-way merge\n", o->internal.merge_size);
+	debug_stage("index", stages[0], o);
+	for (i = 1; i <= o->internal.merge_size; i++) {
+		char buf[24];
+		xsnprintf(buf, sizeof(buf), "ent#%d", i);
+		debug_stage(buf, stages[i], o);
+	}
+	return 0;
+}
+
+static int git_read_tree_config(const char *var, const char *value,
+				const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "submodule.recurse"))
+		return git_default_submodule_config(var, value, cb);
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+int cmd_read_tree(int argc,
+		  const char **argv,
+		  const char *cmd_prefix,
+		  struct repository *repo UNUSED)
+{
+	int i, stage = 0;
+	struct object_id oid;
+	struct tree_desc t[MAX_UNPACK_TREES];
+	struct unpack_trees_options opts;
+	int prefix_set = 0;
+	struct lock_file lock_file = LOCK_INIT;
+	const struct option read_tree_options[] = {
+		OPT__SUPER_PREFIX(&opts.super_prefix),
+		OPT_CALLBACK_F(0, "index-output", NULL, N_("file"),
+		  N_("write resulting index to <file>"),
+		  PARSE_OPT_NONEG, index_output_cb),
+		OPT_BOOL(0, "empty", &read_empty,
+			    N_("only empty the index")),
+		OPT__VERBOSE(&opts.verbose_update, N_("be verbose")),
+		OPT_GROUP(N_("Merging")),
+		OPT_BOOL('m', NULL, &opts.merge,
+			 N_("perform a merge in addition to a read")),
+		OPT_BOOL(0, "trivial", &opts.trivial_merges_only,
+			 N_("3-way merge if no file level merging required")),
+		OPT_BOOL(0, "aggressive", &opts.aggressive,
+			 N_("3-way merge in presence of adds and removes")),
+		OPT_BOOL(0, "reset", &opts.reset,
+			 N_("same as -m, but discard unmerged entries")),
+		{ OPTION_STRING, 0, "prefix", &opts.prefix, N_("<subdirectory>/"),
+		  N_("read the tree into the index under <subdirectory>/"),
+		  PARSE_OPT_NONEG },
+		OPT_BOOL('u', NULL, &opts.update,
+			 N_("update working tree with merge result")),
+		OPT_CALLBACK_F(0, "exclude-per-directory", &opts,
+		  N_("gitignore"),
+		  N_("allow explicitly ignored files to be overwritten"),
+		  PARSE_OPT_NONEG, exclude_per_directory_cb),
+		OPT_BOOL('i', NULL, &opts.index_only,
+			 N_("don't check the working tree after merging")),
+		OPT__DRY_RUN(&opts.dry_run, N_("don't update the index or the work tree")),
+		OPT_BOOL(0, "no-sparse-checkout", &opts.skip_sparse_checkout,
+			 N_("skip applying sparse checkout filter")),
+		OPT_BOOL(0, "debug-unpack", &opts.internal.debug_unpack,
+			 N_("debug unpack-trees")),
+		OPT_CALLBACK_F(0, "recurse-submodules", NULL,
+			    "checkout", "control recursive updating of submodules",
+			    PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater),
+		OPT__QUIET(&opts.quiet, N_("suppress feedback messages")),
+		OPT_END()
+	};
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = -1;
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+
+	git_config(git_read_tree_config, NULL);
+
+	argc = parse_options(argc, argv, cmd_prefix, read_tree_options,
+			     read_tree_usage, 0);
+
+	prefix_set = opts.prefix ? 1 : 0;
+	if (1 < opts.merge + opts.reset + prefix_set)
+		die("Which one? -m, --reset, or --prefix?");
+
+	/* Prefix should not start with a directory separator */
+	if (opts.prefix && opts.prefix[0] == '/')
+		die("Invalid prefix, prefix cannot start with '/'");
+
+	if (opts.reset)
+		opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+
+	/*
+	 * NEEDSWORK
+	 *
+	 * The old index should be read anyway even if we're going to
+	 * destroy all index entries because we still need to preserve
+	 * certain information such as index version or split-index
+	 * mode.
+	 */
+
+	if (opts.reset || opts.merge || opts.prefix) {
+		if (repo_read_index_unmerged(the_repository) && (opts.prefix || opts.merge))
+			die(_("You need to resolve your current index first"));
+		stage = opts.merge = 1;
+	}
+	resolve_undo_clear_index(the_repository->index);
+
+	for (i = 0; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (repo_get_oid(the_repository, arg, &oid))
+			die("Not a valid object name %s", arg);
+		if (list_tree(&oid) < 0)
+			die("failed to unpack tree object %s", arg);
+		stage++;
+	}
+	if (!nr_trees && !read_empty && !opts.merge)
+		warning("read-tree: emptying the index with no arguments is deprecated; use --empty");
+	else if (nr_trees > 0 && read_empty)
+		die("passing trees as arguments contradicts --empty");
+
+	if (1 < opts.index_only + opts.update)
+		die("-u and -i at the same time makes no sense");
+	if ((opts.update || opts.index_only) && !opts.merge)
+		die("%s is meaningless without -m, --reset, or --prefix",
+		    opts.update ? "-u" : "-i");
+	if (opts.update && !opts.reset)
+		opts.preserve_ignored = 0;
+	/* otherwise, opts.preserve_ignored is irrelevant */
+	if (opts.merge && !opts.index_only)
+		setup_work_tree();
+
+	if (opts.skip_sparse_checkout)
+		ensure_full_index(the_repository->index);
+
+	if (opts.merge) {
+		switch (stage - 1) {
+		case 0:
+			die("you must specify at least one tree to merge");
+			break;
+		case 1:
+			opts.fn = opts.prefix ? bind_merge : oneway_merge;
+			break;
+		case 2:
+			opts.fn = twoway_merge;
+			opts.initial_checkout = is_index_unborn(the_repository->index);
+			break;
+		case 3:
+		default:
+			opts.fn = threeway_merge;
+			break;
+		}
+
+		if (stage - 1 >= 3)
+			opts.head_idx = stage - 2;
+		else
+			opts.head_idx = 1;
+	}
+
+	if (opts.internal.debug_unpack)
+		opts.fn = debug_merge;
+
+	/* If we're going to prime_cache_tree later, skip cache tree update */
+	if (nr_trees == 1 && !opts.prefix)
+		opts.skip_cache_tree_update = 1;
+
+	cache_tree_free(&the_repository->index->cache_tree);
+	for (i = 0; i < nr_trees; i++) {
+		struct tree *tree = trees[i];
+		if (parse_tree(tree) < 0)
+			return 128;
+		init_tree_desc(t+i, &tree->object.oid, tree->buffer, tree->size);
+	}
+	if (unpack_trees(nr_trees, t, &opts))
+		return 128;
+
+	if (opts.internal.debug_unpack || opts.dry_run)
+		return 0; /* do not write the index out */
+
+	/*
+	 * When reading only one tree (either the most basic form,
+	 * "-m ent" or "--reset ent" form), we can obtain a fully
+	 * valid cache-tree because the index must match exactly
+	 * what came from the tree.
+	 */
+	if (nr_trees == 1 && !opts.prefix)
+		prime_cache_tree(the_repository,
+				 the_repository->index,
+				 trees[0]);
+
+	if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+		die("unable to write new index file");
+	return 0;
+}
diff --git a/builtin/rebase.c b/builtin/rebase.c
new file mode 100644
index 0000000000..6c9eaf3788
--- /dev/null
+++ b/builtin/rebase.c
@@ -0,0 +1,1892 @@
+/*
+ * "git rebase" builtin command
+ *
+ * Copyright (c) 2018 Pratik Karki
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "run-command.h"
+#include "strvec.h"
+#include "dir.h"
+#include "refs.h"
+#include "config.h"
+#include "unpack-trees.h"
+#include "lockfile.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "path.h"
+#include "commit.h"
+#include "diff.h"
+#include "wt-status.h"
+#include "revision.h"
+#include "commit-reach.h"
+#include "rerere.h"
+#include "branch.h"
+#include "sequencer.h"
+#include "rebase-interactive.h"
+#include "reset.h"
+#include "trace2.h"
+#include "hook.h"
+
+static char const * const builtin_rebase_usage[] = {
+	N_("git rebase [-i] [options] [--exec <cmd>] "
+		"[--onto <newbase> | --keep-base] [<upstream> [<branch>]]"),
+	N_("git rebase [-i] [options] [--exec <cmd>] [--onto <newbase>] "
+		"--root [<branch>]"),
+	"git rebase --continue | --abort | --skip | --edit-todo",
+	NULL
+};
+
+static GIT_PATH_FUNC(path_squash_onto, "rebase-merge/squash-onto")
+static GIT_PATH_FUNC(path_interactive, "rebase-merge/interactive")
+static GIT_PATH_FUNC(apply_dir, "rebase-apply")
+static GIT_PATH_FUNC(merge_dir, "rebase-merge")
+
+enum rebase_type {
+	REBASE_UNSPECIFIED = -1,
+	REBASE_APPLY,
+	REBASE_MERGE
+};
+
+enum empty_type {
+	EMPTY_UNSPECIFIED = -1,
+	EMPTY_DROP,
+	EMPTY_KEEP,
+	EMPTY_STOP
+};
+
+enum action {
+	ACTION_NONE = 0,
+	ACTION_CONTINUE,
+	ACTION_SKIP,
+	ACTION_ABORT,
+	ACTION_QUIT,
+	ACTION_EDIT_TODO,
+	ACTION_SHOW_CURRENT_PATCH
+};
+
+static const char *action_names[] = {
+	"undefined",
+	"continue",
+	"skip",
+	"abort",
+	"quit",
+	"edit_todo",
+	"show_current_patch"
+};
+
+struct rebase_options {
+	enum rebase_type type;
+	enum empty_type empty;
+	char *default_backend;
+	const char *state_dir;
+	struct commit *upstream;
+	const char *upstream_name;
+	const char *upstream_arg;
+	char *head_name;
+	struct commit *orig_head;
+	struct commit *onto;
+	const char *onto_name;
+	const char *revisions;
+	const char *switch_to;
+	int root, root_with_onto;
+	struct object_id *squash_onto;
+	struct commit *restrict_revision;
+	int dont_finish_rebase;
+	enum {
+		REBASE_NO_QUIET = 1<<0,
+		REBASE_VERBOSE = 1<<1,
+		REBASE_DIFFSTAT = 1<<2,
+		REBASE_FORCE = 1<<3,
+		REBASE_INTERACTIVE_EXPLICIT = 1<<4,
+	} flags;
+	struct strvec git_am_opts;
+	enum action action;
+	char *reflog_action;
+	int signoff;
+	int allow_rerere_autoupdate;
+	int keep_empty;
+	int autosquash;
+	char *gpg_sign_opt;
+	int autostash;
+	int committer_date_is_author_date;
+	int ignore_date;
+	struct string_list exec;
+	int allow_empty_message;
+	int rebase_merges, rebase_cousins;
+	char *strategy;
+	struct string_list strategy_opts;
+	struct strbuf git_format_patch_opt;
+	int reschedule_failed_exec;
+	int reapply_cherry_picks;
+	int fork_point;
+	int update_refs;
+	int config_autosquash;
+	int config_rebase_merges;
+	int config_update_refs;
+};
+
+#define REBASE_OPTIONS_INIT {			  	\
+		.type = REBASE_UNSPECIFIED,	  	\
+		.empty = EMPTY_UNSPECIFIED,	  	\
+		.keep_empty = 1,			\
+		.default_backend = xstrdup("merge"),  	\
+		.flags = REBASE_NO_QUIET, 		\
+		.git_am_opts = STRVEC_INIT,		\
+		.exec = STRING_LIST_INIT_NODUP,		\
+		.git_format_patch_opt = STRBUF_INIT,	\
+		.fork_point = -1,			\
+		.reapply_cherry_picks = -1,             \
+		.allow_empty_message = 1,               \
+		.autosquash = -1,                       \
+		.rebase_merges = -1,                    \
+		.config_rebase_merges = -1,             \
+		.update_refs = -1,                      \
+		.config_update_refs = -1,               \
+		.strategy_opts = STRING_LIST_INIT_NODUP,\
+	}
+
+static void rebase_options_release(struct rebase_options *opts)
+{
+	free(opts->default_backend);
+	free(opts->reflog_action);
+	free(opts->head_name);
+	strvec_clear(&opts->git_am_opts);
+	free(opts->gpg_sign_opt);
+	string_list_clear(&opts->exec, 0);
+	free(opts->strategy);
+	string_list_clear(&opts->strategy_opts, 0);
+	strbuf_release(&opts->git_format_patch_opt);
+}
+
+static struct replay_opts get_replay_opts(const struct rebase_options *opts)
+{
+	struct replay_opts replay = REPLAY_OPTS_INIT;
+
+	replay.action = REPLAY_INTERACTIVE_REBASE;
+	replay.strategy = NULL;
+	sequencer_init_config(&replay);
+
+	replay.signoff = opts->signoff;
+	replay.allow_ff = !(opts->flags & REBASE_FORCE);
+	if (opts->allow_rerere_autoupdate)
+		replay.allow_rerere_auto = opts->allow_rerere_autoupdate;
+	replay.allow_empty = 1;
+	replay.allow_empty_message = opts->allow_empty_message;
+	replay.drop_redundant_commits = (opts->empty == EMPTY_DROP);
+	replay.keep_redundant_commits = (opts->empty == EMPTY_KEEP);
+	replay.quiet = !(opts->flags & REBASE_NO_QUIET);
+	replay.verbose = opts->flags & REBASE_VERBOSE;
+	replay.reschedule_failed_exec = opts->reschedule_failed_exec;
+	replay.committer_date_is_author_date =
+					opts->committer_date_is_author_date;
+	replay.ignore_date = opts->ignore_date;
+	free(replay.gpg_sign);
+	replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
+	replay.reflog_action = xstrdup(opts->reflog_action);
+	if (opts->strategy)
+		replay.strategy = xstrdup_or_null(opts->strategy);
+	else if (!replay.strategy && replay.default_strategy) {
+		replay.strategy = replay.default_strategy;
+		replay.default_strategy = NULL;
+	}
+
+	for (size_t i = 0; i < opts->strategy_opts.nr; i++)
+		strvec_push(&replay.xopts, opts->strategy_opts.items[i].string);
+
+	if (opts->squash_onto) {
+		oidcpy(&replay.squash_onto, opts->squash_onto);
+		replay.have_squash_onto = 1;
+	}
+
+	return replay;
+}
+
+static int edit_todo_file(unsigned flags, struct replay_opts *opts)
+{
+	const char *todo_file = rebase_path_todo();
+	struct todo_list todo_list = TODO_LIST_INIT,
+		new_todo = TODO_LIST_INIT;
+	int res = 0;
+
+	if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0)
+		return error_errno(_("could not read '%s'."), todo_file);
+
+	strbuf_stripspace(&todo_list.buf, comment_line_str);
+	res = edit_todo_list(the_repository, opts, &todo_list, &new_todo,
+			     NULL, NULL, flags);
+	if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file,
+					    NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS)))
+		res = error_errno(_("could not write '%s'"), todo_file);
+
+	todo_list_release(&todo_list);
+	todo_list_release(&new_todo);
+
+	return res;
+}
+
+static int get_revision_ranges(struct commit *upstream, struct commit *onto,
+			       struct object_id *orig_head, char **revisions,
+			       char **shortrevisions)
+{
+	struct commit *base_rev = upstream ? upstream : onto;
+	const char *shorthead;
+
+	*revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
+			     oid_to_hex(orig_head));
+
+	shorthead = repo_find_unique_abbrev(the_repository, orig_head,
+					    DEFAULT_ABBREV);
+
+	if (upstream) {
+		const char *shortrev;
+
+		shortrev = repo_find_unique_abbrev(the_repository,
+						   &base_rev->object.oid,
+						   DEFAULT_ABBREV);
+
+		*shortrevisions = xstrfmt("%s..%s", shortrev, shorthead);
+	} else
+		*shortrevisions = xstrdup(shorthead);
+
+	return 0;
+}
+
+static int init_basic_state(struct replay_opts *opts, const char *head_name,
+			    struct commit *onto,
+			    const struct object_id *orig_head)
+{
+	FILE *interactive;
+
+	if (!is_directory(merge_dir()) && mkdir_in_gitdir(merge_dir()))
+		return error_errno(_("could not create temporary %s"), merge_dir());
+
+	refs_delete_reflog(get_main_ref_store(the_repository), "REBASE_HEAD");
+
+	interactive = fopen(path_interactive(), "w");
+	if (!interactive)
+		return error_errno(_("could not mark as interactive"));
+	fclose(interactive);
+
+	return write_basic_state(opts, head_name, onto, orig_head);
+}
+
+static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
+{
+	int ret = -1;
+	char *revisions = NULL, *shortrevisions = NULL;
+	struct strvec make_script_args = STRVEC_INIT;
+	struct todo_list todo_list = TODO_LIST_INIT;
+	struct replay_opts replay = get_replay_opts(opts);
+
+	if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head->object.oid,
+				&revisions, &shortrevisions))
+		goto cleanup;
+
+	if (init_basic_state(&replay,
+			     opts->head_name ? opts->head_name : "detached HEAD",
+			     opts->onto, &opts->orig_head->object.oid))
+		goto cleanup;
+
+	if (!opts->upstream && opts->squash_onto)
+		write_file(path_squash_onto(), "%s\n",
+			   oid_to_hex(opts->squash_onto));
+
+	strvec_pushl(&make_script_args, "", revisions, NULL);
+	if (opts->restrict_revision)
+		strvec_pushf(&make_script_args, "^%s",
+			     oid_to_hex(&opts->restrict_revision->object.oid));
+
+	ret = sequencer_make_script(the_repository, &todo_list.buf,
+				    make_script_args.nr, make_script_args.v,
+				    flags);
+
+	if (ret)
+		error(_("could not generate todo list"));
+	else {
+		discard_index(the_repository->index);
+		if (todo_list_parse_insn_buffer(the_repository, &replay,
+						todo_list.buf.buf, &todo_list))
+			BUG("unusable todo list");
+
+		ret = complete_action(the_repository, &replay, flags,
+			shortrevisions, opts->onto_name, opts->onto,
+			&opts->orig_head->object.oid, &opts->exec,
+			opts->autosquash, opts->update_refs, &todo_list);
+	}
+
+cleanup:
+	replay_opts_release(&replay);
+	free(revisions);
+	free(shortrevisions);
+	todo_list_release(&todo_list);
+	strvec_clear(&make_script_args);
+
+	return ret;
+}
+
+static int run_sequencer_rebase(struct rebase_options *opts)
+{
+	unsigned flags = 0;
+	int abbreviate_commands = 0, ret = 0;
+
+	git_config_get_bool("rebase.abbreviatecommands", &abbreviate_commands);
+
+	flags |= opts->keep_empty ? TODO_LIST_KEEP_EMPTY : 0;
+	flags |= abbreviate_commands ? TODO_LIST_ABBREVIATE_CMDS : 0;
+	flags |= opts->rebase_merges ? TODO_LIST_REBASE_MERGES : 0;
+	flags |= opts->rebase_cousins > 0 ? TODO_LIST_REBASE_COUSINS : 0;
+	flags |= opts->root_with_onto ? TODO_LIST_ROOT_WITH_ONTO : 0;
+	flags |= opts->reapply_cherry_picks ? TODO_LIST_REAPPLY_CHERRY_PICKS : 0;
+	flags |= opts->flags & REBASE_NO_QUIET ? TODO_LIST_WARN_SKIPPED_CHERRY_PICKS : 0;
+
+	switch (opts->action) {
+	case ACTION_NONE: {
+		if (!opts->onto && !opts->upstream)
+			die(_("a base commit must be provided with --upstream or --onto"));
+
+		ret = do_interactive_rebase(opts, flags);
+		break;
+	}
+	case ACTION_SKIP: {
+		struct string_list merge_rr = STRING_LIST_INIT_DUP;
+
+		rerere_clear(the_repository, &merge_rr);
+	}
+		/* fallthrough */
+	case ACTION_CONTINUE: {
+		struct replay_opts replay_opts = get_replay_opts(opts);
+
+		ret = sequencer_continue(the_repository, &replay_opts);
+		replay_opts_release(&replay_opts);
+		break;
+	}
+	case ACTION_EDIT_TODO: {
+		struct replay_opts replay_opts = get_replay_opts(opts);
+
+		ret = edit_todo_file(flags, &replay_opts);
+		replay_opts_release(&replay_opts);
+		break;
+	}
+	case ACTION_SHOW_CURRENT_PATCH: {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+
+		cmd.git_cmd = 1;
+		strvec_pushl(&cmd.args, "show", "REBASE_HEAD", "--", NULL);
+		ret = run_command(&cmd);
+
+		break;
+	}
+	default:
+		BUG("invalid command '%d'", opts->action);
+	}
+
+	return ret;
+}
+
+static int is_merge(struct rebase_options *opts)
+{
+	return opts->type == REBASE_MERGE;
+}
+
+static void imply_merge(struct rebase_options *opts, const char *option)
+{
+	switch (opts->type) {
+	case REBASE_APPLY:
+		die(_("%s requires the merge backend"), option);
+		break;
+	case REBASE_MERGE:
+		break;
+	default:
+		opts->type = REBASE_MERGE; /* implied */
+		break;
+	}
+}
+
+/* Returns the filename prefixed by the state_dir */
+static const char *state_dir_path(const char *filename, struct rebase_options *opts)
+{
+	static struct strbuf path = STRBUF_INIT;
+	static size_t prefix_len;
+
+	if (!prefix_len) {
+		strbuf_addf(&path, "%s/", opts->state_dir);
+		prefix_len = path.len;
+	}
+
+	strbuf_setlen(&path, prefix_len);
+	strbuf_addstr(&path, filename);
+	return path.buf;
+}
+
+/* Initialize the rebase options from the state directory. */
+static int read_basic_state(struct rebase_options *opts)
+{
+	struct strbuf head_name = STRBUF_INIT;
+	struct strbuf buf = STRBUF_INIT;
+	struct object_id oid;
+
+	if (!read_oneliner(&head_name, state_dir_path("head-name", opts),
+			   READ_ONELINER_WARN_MISSING) ||
+	    !read_oneliner(&buf, state_dir_path("onto", opts),
+			   READ_ONELINER_WARN_MISSING))
+		return -1;
+	opts->head_name = starts_with(head_name.buf, "refs/") ?
+		xstrdup(head_name.buf) : NULL;
+	strbuf_release(&head_name);
+	if (get_oid_hex(buf.buf, &oid) ||
+	    !(opts->onto = lookup_commit_object(the_repository, &oid)))
+		return error(_("invalid onto: '%s'"), buf.buf);
+
+	/*
+	 * We always write to orig-head, but interactive rebase used to write to
+	 * head. Fall back to reading from head to cover for the case that the
+	 * user upgraded git with an ongoing interactive rebase.
+	 */
+	strbuf_reset(&buf);
+	if (file_exists(state_dir_path("orig-head", opts))) {
+		if (!read_oneliner(&buf, state_dir_path("orig-head", opts),
+				   READ_ONELINER_WARN_MISSING))
+			return -1;
+	} else if (!read_oneliner(&buf, state_dir_path("head", opts),
+				  READ_ONELINER_WARN_MISSING))
+		return -1;
+	if (get_oid_hex(buf.buf, &oid) ||
+	    !(opts->orig_head = lookup_commit_object(the_repository, &oid)))
+		return error(_("invalid orig-head: '%s'"), buf.buf);
+
+	if (file_exists(state_dir_path("quiet", opts)))
+		opts->flags &= ~REBASE_NO_QUIET;
+	else
+		opts->flags |= REBASE_NO_QUIET;
+
+	if (file_exists(state_dir_path("verbose", opts)))
+		opts->flags |= REBASE_VERBOSE;
+
+	if (file_exists(state_dir_path("signoff", opts))) {
+		opts->signoff = 1;
+		opts->flags |= REBASE_FORCE;
+	}
+
+	if (file_exists(state_dir_path("allow_rerere_autoupdate", opts))) {
+		strbuf_reset(&buf);
+		if (!read_oneliner(&buf, state_dir_path("allow_rerere_autoupdate", opts),
+				   READ_ONELINER_WARN_MISSING))
+			return -1;
+		if (!strcmp(buf.buf, "--rerere-autoupdate"))
+			opts->allow_rerere_autoupdate = RERERE_AUTOUPDATE;
+		else if (!strcmp(buf.buf, "--no-rerere-autoupdate"))
+			opts->allow_rerere_autoupdate = RERERE_NOAUTOUPDATE;
+		else
+			warning(_("ignoring invalid allow_rerere_autoupdate: "
+				  "'%s'"), buf.buf);
+	}
+
+	if (file_exists(state_dir_path("gpg_sign_opt", opts))) {
+		strbuf_reset(&buf);
+		if (!read_oneliner(&buf, state_dir_path("gpg_sign_opt", opts),
+				   READ_ONELINER_WARN_MISSING))
+			return -1;
+		free(opts->gpg_sign_opt);
+		opts->gpg_sign_opt = xstrdup(buf.buf);
+	}
+
+	strbuf_release(&buf);
+
+	return 0;
+}
+
+static int rebase_write_basic_state(struct rebase_options *opts)
+{
+	write_file(state_dir_path("head-name", opts), "%s",
+		   opts->head_name ? opts->head_name : "detached HEAD");
+	write_file(state_dir_path("onto", opts), "%s",
+		   opts->onto ? oid_to_hex(&opts->onto->object.oid) : "");
+	write_file(state_dir_path("orig-head", opts), "%s",
+		   oid_to_hex(&opts->orig_head->object.oid));
+	if (!(opts->flags & REBASE_NO_QUIET))
+		write_file(state_dir_path("quiet", opts), "%s", "");
+	if (opts->flags & REBASE_VERBOSE)
+		write_file(state_dir_path("verbose", opts), "%s", "");
+	if (opts->allow_rerere_autoupdate > 0)
+		write_file(state_dir_path("allow_rerere_autoupdate", opts),
+			   "-%s-rerere-autoupdate",
+			   opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE ?
+				"" : "-no");
+	if (opts->gpg_sign_opt)
+		write_file(state_dir_path("gpg_sign_opt", opts), "%s",
+			   opts->gpg_sign_opt);
+	if (opts->signoff)
+		write_file(state_dir_path("signoff", opts), "--signoff");
+
+	return 0;
+}
+
+static int cleanup_autostash(struct rebase_options *opts)
+{
+	int ret;
+	struct strbuf dir = STRBUF_INIT;
+	const char *path = state_dir_path("autostash", opts);
+
+	if (!file_exists(path))
+		return 0;
+	ret = apply_autostash(path);
+	strbuf_addstr(&dir, opts->state_dir);
+	if (remove_dir_recursively(&dir, 0))
+		ret = error_errno(_("could not remove '%s'"), opts->state_dir);
+	strbuf_release(&dir);
+
+	return ret;
+}
+
+static int finish_rebase(struct rebase_options *opts)
+{
+	struct strbuf dir = STRBUF_INIT;
+	int ret = 0;
+
+	refs_delete_ref(get_main_ref_store(the_repository), NULL,
+			"REBASE_HEAD", NULL, REF_NO_DEREF);
+	refs_delete_ref(get_main_ref_store(the_repository), NULL,
+			"AUTO_MERGE", NULL, REF_NO_DEREF);
+	apply_autostash(state_dir_path("autostash", opts));
+	/*
+	 * We ignore errors in 'git maintenance run --auto', since the
+	 * user should see them.
+	 */
+	run_auto_maintenance(!(opts->flags & (REBASE_NO_QUIET|REBASE_VERBOSE)));
+	if (opts->type == REBASE_MERGE) {
+		struct replay_opts replay = REPLAY_OPTS_INIT;
+
+		replay.action = REPLAY_INTERACTIVE_REBASE;
+		ret = sequencer_remove_state(&replay);
+		replay_opts_release(&replay);
+	} else {
+		strbuf_addstr(&dir, opts->state_dir);
+		if (remove_dir_recursively(&dir, 0))
+			ret = error(_("could not remove '%s'"),
+				    opts->state_dir);
+		strbuf_release(&dir);
+	}
+
+	return ret;
+}
+
+static int move_to_original_branch(struct rebase_options *opts)
+{
+	struct strbuf branch_reflog = STRBUF_INIT, head_reflog = STRBUF_INIT;
+	struct reset_head_opts ropts = { 0 };
+	int ret;
+
+	if (!opts->head_name)
+		return 0; /* nothing to move back to */
+
+	if (!opts->onto)
+		BUG("move_to_original_branch without onto");
+
+	strbuf_addf(&branch_reflog, "%s (finish): %s onto %s",
+		    opts->reflog_action,
+		    opts->head_name, oid_to_hex(&opts->onto->object.oid));
+	strbuf_addf(&head_reflog, "%s (finish): returning to %s",
+		    opts->reflog_action, opts->head_name);
+	ropts.branch = opts->head_name;
+	ropts.flags = RESET_HEAD_REFS_ONLY;
+	ropts.branch_msg = branch_reflog.buf;
+	ropts.head_msg = head_reflog.buf;
+	ret = reset_head(the_repository, &ropts);
+
+	strbuf_release(&branch_reflog);
+	strbuf_release(&head_reflog);
+	return ret;
+}
+
+static int run_am(struct rebase_options *opts)
+{
+	struct child_process am = CHILD_PROCESS_INIT;
+	struct child_process format_patch = CHILD_PROCESS_INIT;
+	int status;
+	char *rebased_patches;
+
+	am.git_cmd = 1;
+	strvec_push(&am.args, "am");
+	strvec_pushf(&am.env, GIT_REFLOG_ACTION_ENVIRONMENT "=%s (pick)",
+		     opts->reflog_action);
+	if (opts->action == ACTION_CONTINUE) {
+		strvec_push(&am.args, "--resolved");
+		strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
+		if (opts->gpg_sign_opt)
+			strvec_push(&am.args, opts->gpg_sign_opt);
+		status = run_command(&am);
+		if (status)
+			return status;
+
+		return move_to_original_branch(opts);
+	}
+	if (opts->action == ACTION_SKIP) {
+		strvec_push(&am.args, "--skip");
+		strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
+		status = run_command(&am);
+		if (status)
+			return status;
+
+		return move_to_original_branch(opts);
+	}
+	if (opts->action == ACTION_SHOW_CURRENT_PATCH) {
+		strvec_push(&am.args, "--show-current-patch");
+		return run_command(&am);
+	}
+
+	rebased_patches = xstrdup(git_path("rebased-patches"));
+	format_patch.out = open(rebased_patches,
+				O_WRONLY | O_CREAT | O_TRUNC, 0666);
+	if (format_patch.out < 0) {
+		status = error_errno(_("could not open '%s' for writing"),
+				     rebased_patches);
+		free(rebased_patches);
+		child_process_clear(&am);
+		return status;
+	}
+
+	format_patch.git_cmd = 1;
+	strvec_pushl(&format_patch.args, "format-patch", "-k", "--stdout",
+		     "--full-index", "--cherry-pick", "--right-only",
+		     "--default-prefix", "--no-renames",
+		     "--no-cover-letter", "--pretty=mboxrd", "--topo-order",
+		     "--no-base", NULL);
+	if (opts->git_format_patch_opt.len)
+		strvec_split(&format_patch.args,
+			     opts->git_format_patch_opt.buf);
+	strvec_pushf(&format_patch.args, "%s...%s",
+		     oid_to_hex(opts->root ?
+				/* this is now equivalent to !opts->upstream */
+				&opts->onto->object.oid :
+				&opts->upstream->object.oid),
+		     oid_to_hex(&opts->orig_head->object.oid));
+	if (opts->restrict_revision)
+		strvec_pushf(&format_patch.args, "^%s",
+			     oid_to_hex(&opts->restrict_revision->object.oid));
+
+	status = run_command(&format_patch);
+	if (status) {
+		struct reset_head_opts ropts = { 0 };
+		unlink(rebased_patches);
+		free(rebased_patches);
+		child_process_clear(&am);
+
+		ropts.oid = &opts->orig_head->object.oid;
+		ropts.branch = opts->head_name;
+		ropts.default_reflog_action = opts->reflog_action;
+		reset_head(the_repository, &ropts);
+		error(_("\ngit encountered an error while preparing the "
+			"patches to replay\n"
+			"these revisions:\n"
+			"\n    %s\n\n"
+			"As a result, git cannot rebase them."),
+		      opts->revisions);
+
+		return status;
+	}
+
+	am.in = open(rebased_patches, O_RDONLY);
+	if (am.in < 0) {
+		status = error_errno(_("could not open '%s' for reading"),
+				     rebased_patches);
+		free(rebased_patches);
+		child_process_clear(&am);
+		return status;
+	}
+
+	strvec_pushv(&am.args, opts->git_am_opts.v);
+	strvec_push(&am.args, "--rebasing");
+	strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg);
+	strvec_push(&am.args, "--patch-format=mboxrd");
+	if (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE)
+		strvec_push(&am.args, "--rerere-autoupdate");
+	else if (opts->allow_rerere_autoupdate == RERERE_NOAUTOUPDATE)
+		strvec_push(&am.args, "--no-rerere-autoupdate");
+	if (opts->gpg_sign_opt)
+		strvec_push(&am.args, opts->gpg_sign_opt);
+	status = run_command(&am);
+	unlink(rebased_patches);
+	free(rebased_patches);
+
+	if (!status) {
+		return move_to_original_branch(opts);
+	}
+
+	if (is_directory(opts->state_dir))
+		rebase_write_basic_state(opts);
+
+	return status;
+}
+
+static int run_specific_rebase(struct rebase_options *opts)
+{
+	int status;
+
+	if (opts->type == REBASE_MERGE) {
+		/* Run sequencer-based rebase */
+		if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT))
+			setenv("GIT_SEQUENCE_EDITOR", ":", 1);
+		if (opts->gpg_sign_opt) {
+			/* remove the leading "-S" */
+			char *tmp = xstrdup(opts->gpg_sign_opt + 2);
+			free(opts->gpg_sign_opt);
+			opts->gpg_sign_opt = tmp;
+		}
+
+		status = run_sequencer_rebase(opts);
+	} else if (opts->type == REBASE_APPLY)
+		status = run_am(opts);
+	else
+		BUG("Unhandled rebase type %d", opts->type);
+
+	if (opts->dont_finish_rebase)
+		; /* do nothing */
+	else if (opts->type == REBASE_MERGE)
+		; /* merge backend cleans up after itself */
+	else if (status == 0) {
+		if (!file_exists(state_dir_path("stopped-sha", opts)))
+			finish_rebase(opts);
+	} else if (status == 2) {
+		struct strbuf dir = STRBUF_INIT;
+
+		apply_autostash(state_dir_path("autostash", opts));
+		strbuf_addstr(&dir, opts->state_dir);
+		remove_dir_recursively(&dir, 0);
+		strbuf_release(&dir);
+		die("Nothing to do");
+	}
+
+	return status ? -1 : 0;
+}
+
+static void parse_rebase_merges_value(struct rebase_options *options, const char *value)
+{
+	if (!strcmp("no-rebase-cousins", value))
+		options->rebase_cousins = 0;
+	else if (!strcmp("rebase-cousins", value))
+		options->rebase_cousins = 1;
+	else
+		die(_("Unknown rebase-merges mode: %s"), value);
+}
+
+static int rebase_config(const char *var, const char *value,
+			 const struct config_context *ctx, void *data)
+{
+	struct rebase_options *opts = data;
+
+	if (!strcmp(var, "rebase.stat")) {
+		if (git_config_bool(var, value))
+			opts->flags |= REBASE_DIFFSTAT;
+		else
+			opts->flags &= ~REBASE_DIFFSTAT;
+		return 0;
+	}
+
+	if (!strcmp(var, "rebase.autosquash")) {
+		opts->config_autosquash = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "commit.gpgsign")) {
+		free(opts->gpg_sign_opt);
+		opts->gpg_sign_opt = git_config_bool(var, value) ?
+			xstrdup("-S") : NULL;
+		return 0;
+	}
+
+	if (!strcmp(var, "rebase.autostash")) {
+		opts->autostash = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "rebase.rebasemerges")) {
+		opts->config_rebase_merges = git_parse_maybe_bool(value);
+		if (opts->config_rebase_merges < 0) {
+			opts->config_rebase_merges = 1;
+			parse_rebase_merges_value(opts, value);
+		} else {
+			opts->rebase_cousins = 0;
+		}
+		return 0;
+	}
+
+	if (!strcmp(var, "rebase.updaterefs")) {
+		opts->config_update_refs = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "rebase.reschedulefailedexec")) {
+		opts->reschedule_failed_exec = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "rebase.forkpoint")) {
+		opts->fork_point = git_config_bool(var, value) ? -1 : 0;
+		return 0;
+	}
+
+	if (!strcmp(var, "rebase.backend")) {
+		FREE_AND_NULL(opts->default_backend);
+		return git_config_string(&opts->default_backend, var, value);
+	}
+
+	return git_default_config(var, value, ctx, data);
+}
+
+static int checkout_up_to_date(struct rebase_options *options)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct reset_head_opts ropts = { 0 };
+	int ret = 0;
+
+	strbuf_addf(&buf, "%s: checkout %s",
+		    options->reflog_action, options->switch_to);
+	ropts.oid = &options->orig_head->object.oid;
+	ropts.branch = options->head_name;
+	ropts.flags = RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
+	if (!ropts.branch)
+		ropts.flags |=  RESET_HEAD_DETACH;
+	ropts.head_msg = buf.buf;
+	if (reset_head(the_repository, &ropts) < 0)
+		ret = error(_("could not switch to %s"), options->switch_to);
+	strbuf_release(&buf);
+
+	return ret;
+}
+
+/*
+ * Determines whether the commits in from..to are linear, i.e. contain
+ * no merge commits. This function *expects* `from` to be an ancestor of
+ * `to`.
+ */
+static int is_linear_history(struct commit *from, struct commit *to)
+{
+	while (to && to != from) {
+		repo_parse_commit(the_repository, to);
+		if (!to->parents)
+			return 1;
+		if (to->parents->next)
+			return 0;
+		to = to->parents->item;
+	}
+	return 1;
+}
+
+static int can_fast_forward(struct commit *onto, struct commit *upstream,
+			    struct commit *restrict_revision,
+			    struct commit *head, struct object_id *branch_base)
+{
+	struct commit_list *merge_bases = NULL;
+	int res = 0;
+
+	if (is_null_oid(branch_base))
+		goto done; /* fill_branch_base() found multiple merge bases */
+
+	if (!oideq(branch_base, &onto->object.oid))
+		goto done;
+
+	if (restrict_revision && !oideq(&restrict_revision->object.oid, branch_base))
+		goto done;
+
+	if (!upstream)
+		goto done;
+
+	if (repo_get_merge_bases(the_repository, upstream, head, &merge_bases) < 0)
+		exit(128);
+	if (!merge_bases || merge_bases->next)
+		goto done;
+
+	if (!oideq(&onto->object.oid, &merge_bases->item->object.oid))
+		goto done;
+
+	res = 1;
+
+done:
+	free_commit_list(merge_bases);
+	return res && is_linear_history(onto, head);
+}
+
+static void fill_branch_base(struct rebase_options *options,
+			    struct object_id *branch_base)
+{
+	struct commit_list *merge_bases = NULL;
+
+	if (repo_get_merge_bases(the_repository, options->onto,
+				 options->orig_head, &merge_bases) < 0)
+		exit(128);
+	if (!merge_bases || merge_bases->next)
+		oidcpy(branch_base, null_oid());
+	else
+		oidcpy(branch_base, &merge_bases->item->object.oid);
+
+	free_commit_list(merge_bases);
+}
+
+static int parse_opt_am(const struct option *opt, const char *arg, int unset)
+{
+	struct rebase_options *opts = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_APPLY)
+	    die(_("apply options and merge options cannot be used together"));
+
+	opts->type = REBASE_APPLY;
+
+	return 0;
+}
+
+/* -i followed by -m is still -i */
+static int parse_opt_merge(const struct option *opt, const char *arg, int unset)
+{
+	struct rebase_options *opts = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_MERGE)
+	    die(_("apply options and merge options cannot be used together"));
+
+	opts->type = REBASE_MERGE;
+
+	return 0;
+}
+
+/* -i followed by -r is still explicitly interactive, but -r alone is not */
+static int parse_opt_interactive(const struct option *opt, const char *arg,
+				 int unset)
+{
+	struct rebase_options *opts = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	if (opts->type != REBASE_UNSPECIFIED && opts->type != REBASE_MERGE)
+	    die(_("apply options and merge options cannot be used together"));
+
+	opts->type = REBASE_MERGE;
+	opts->flags |= REBASE_INTERACTIVE_EXPLICIT;
+
+	return 0;
+}
+
+static enum empty_type parse_empty_value(const char *value)
+{
+	if (!strcasecmp(value, "drop"))
+		return EMPTY_DROP;
+	else if (!strcasecmp(value, "keep"))
+		return EMPTY_KEEP;
+	else if (!strcasecmp(value, "stop"))
+		return EMPTY_STOP;
+	else if (!strcasecmp(value, "ask")) {
+		warning(_("--empty=ask is deprecated; use '--empty=stop' instead."));
+		return EMPTY_STOP;
+	}
+
+	die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"stop\"."), value);
+}
+
+static int parse_opt_keep_empty(const struct option *opt, const char *arg,
+				int unset)
+{
+	struct rebase_options *opts = opt->value;
+
+	BUG_ON_OPT_ARG(arg);
+
+	imply_merge(opts, unset ? "--no-keep-empty" : "--keep-empty");
+	opts->keep_empty = !unset;
+	return 0;
+}
+
+static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
+{
+	struct rebase_options *options = opt->value;
+	enum empty_type value = parse_empty_value(arg);
+
+	BUG_ON_OPT_NEG(unset);
+
+	options->empty = value;
+	return 0;
+}
+
+static int parse_opt_rebase_merges(const struct option *opt, const char *arg, int unset)
+{
+	struct rebase_options *options = opt->value;
+
+	options->rebase_merges = !unset;
+	options->rebase_cousins = 0;
+
+	if (arg) {
+		if (!*arg) {
+			warning(_("--rebase-merges with an empty string "
+				  "argument is deprecated and will stop "
+				  "working in a future version of Git. Use "
+				  "--rebase-merges without an argument "
+				  "instead, which does the same thing."));
+			return 0;
+		}
+		parse_rebase_merges_value(options, arg);
+	}
+
+	return 0;
+}
+
+static void NORETURN error_on_missing_default_upstream(void)
+{
+	struct branch *current_branch = branch_get(NULL);
+
+	printf(_("%s\n"
+		 "Please specify which branch you want to rebase against.\n"
+		 "See git-rebase(1) for details.\n"
+		 "\n"
+		 "    git rebase '<branch>'\n"
+		 "\n"),
+		current_branch ? _("There is no tracking information for "
+			"the current branch.") :
+			_("You are not currently on a branch."));
+
+	if (current_branch) {
+		const char *remote = current_branch->remote_name;
+
+		if (!remote)
+			remote = _("<remote>");
+
+		printf(_("If you wish to set tracking information for this "
+			 "branch you can do so with:\n"
+			 "\n"
+			 "    git branch --set-upstream-to=%s/<branch> %s\n"
+			 "\n"),
+		       remote, current_branch->name);
+	}
+	exit(1);
+}
+
+static int check_exec_cmd(const char *cmd)
+{
+	if (strchr(cmd, '\n'))
+		return error(_("exec commands cannot contain newlines"));
+
+	/* Does the command consist purely of whitespace? */
+	if (!cmd[strspn(cmd, " \t\r\f\v")])
+		return error(_("empty exec command"));
+
+	return 0;
+}
+
+int cmd_rebase(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct rebase_options options = REBASE_OPTIONS_INIT;
+	const char *branch_name;
+	const char *strategy_opt = NULL;
+	int ret, flags, total_argc, in_progress = 0;
+	int keep_base = 0;
+	int ok_to_skip_pre_rebase = 0;
+	struct strbuf msg = STRBUF_INIT;
+	struct strbuf revisions = STRBUF_INIT;
+	struct strbuf buf = STRBUF_INIT;
+	struct object_id branch_base;
+	int ignore_whitespace = 0;
+	const char *gpg_sign = NULL;
+	struct object_id squash_onto;
+	char *squash_onto_name = NULL;
+	char *keep_base_onto_name = NULL;
+	int reschedule_failed_exec = -1;
+	int allow_preemptive_ff = 1;
+	int preserve_merges_selected = 0;
+	struct reset_head_opts ropts = { 0 };
+	struct option builtin_rebase_options[] = {
+		OPT_STRING(0, "onto", &options.onto_name,
+			   N_("revision"),
+			   N_("rebase onto given branch instead of upstream")),
+		OPT_BOOL(0, "keep-base", &keep_base,
+			 N_("use the merge-base of upstream and branch as the current base")),
+		OPT_BOOL(0, "no-verify", &ok_to_skip_pre_rebase,
+			 N_("allow pre-rebase hook to run")),
+		OPT_NEGBIT('q', "quiet", &options.flags,
+			   N_("be quiet. implies --no-stat"),
+			   REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
+		OPT_BIT('v', "verbose", &options.flags,
+			N_("display a diffstat of what changed upstream"),
+			REBASE_NO_QUIET | REBASE_VERBOSE | REBASE_DIFFSTAT),
+		{OPTION_NEGBIT, 'n', "no-stat", &options.flags, NULL,
+			N_("do not show diffstat of what changed upstream"),
+			PARSE_OPT_NOARG, NULL, REBASE_DIFFSTAT },
+		OPT_BOOL(0, "signoff", &options.signoff,
+			 N_("add a Signed-off-by trailer to each commit")),
+		OPT_BOOL(0, "committer-date-is-author-date",
+			 &options.committer_date_is_author_date,
+			 N_("make committer date match author date")),
+		OPT_BOOL(0, "reset-author-date", &options.ignore_date,
+			 N_("ignore author date and use current date")),
+		OPT_HIDDEN_BOOL(0, "ignore-date", &options.ignore_date,
+				N_("synonym of --reset-author-date")),
+		OPT_PASSTHRU_ARGV('C', NULL, &options.git_am_opts, N_("n"),
+				  N_("passed to 'git apply'"), 0),
+		OPT_BOOL(0, "ignore-whitespace", &ignore_whitespace,
+			 N_("ignore changes in whitespace")),
+		OPT_PASSTHRU_ARGV(0, "whitespace", &options.git_am_opts,
+				  N_("action"), N_("passed to 'git apply'"), 0),
+		OPT_BIT('f', "force-rebase", &options.flags,
+			N_("cherry-pick all commits, even if unchanged"),
+			REBASE_FORCE),
+		OPT_BIT(0, "no-ff", &options.flags,
+			N_("cherry-pick all commits, even if unchanged"),
+			REBASE_FORCE),
+		OPT_CMDMODE(0, "continue", &options.action, N_("continue"),
+			    ACTION_CONTINUE),
+		OPT_CMDMODE(0, "skip", &options.action,
+			    N_("skip current patch and continue"), ACTION_SKIP),
+		OPT_CMDMODE(0, "abort", &options.action,
+			    N_("abort and check out the original branch"),
+			    ACTION_ABORT),
+		OPT_CMDMODE(0, "quit", &options.action,
+			    N_("abort but keep HEAD where it is"), ACTION_QUIT),
+		OPT_CMDMODE(0, "edit-todo", &options.action, N_("edit the todo list "
+			    "during an interactive rebase"), ACTION_EDIT_TODO),
+		OPT_CMDMODE(0, "show-current-patch", &options.action,
+			    N_("show the patch file being applied or merged"),
+			    ACTION_SHOW_CURRENT_PATCH),
+		OPT_CALLBACK_F(0, "apply", &options, NULL,
+			N_("use apply strategies to rebase"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			parse_opt_am),
+		OPT_CALLBACK_F('m', "merge", &options, NULL,
+			N_("use merging strategies to rebase"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			parse_opt_merge),
+		OPT_CALLBACK_F('i', "interactive", &options, NULL,
+			N_("let the user edit the list of commits to rebase"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			parse_opt_interactive),
+		OPT_SET_INT_F('p', "preserve-merges", &preserve_merges_selected,
+			      N_("(REMOVED) was: try to recreate merges "
+				 "instead of ignoring them"),
+			      1, PARSE_OPT_HIDDEN),
+		OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate),
+		OPT_CALLBACK_F(0, "empty", &options, "(drop|keep|stop)",
+			       N_("how to handle commits that become empty"),
+			       PARSE_OPT_NONEG, parse_opt_empty),
+		OPT_CALLBACK_F('k', "keep-empty", &options, NULL,
+			N_("keep commits which start empty"),
+			PARSE_OPT_NOARG | PARSE_OPT_HIDDEN,
+			parse_opt_keep_empty),
+		OPT_BOOL(0, "autosquash", &options.autosquash,
+			 N_("move commits that begin with "
+			    "squash!/fixup! under -i")),
+		OPT_BOOL(0, "update-refs", &options.update_refs,
+			 N_("update branches that point to commits "
+			    "that are being rebased")),
+		{ OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
+			N_("GPG-sign commits"),
+			PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+		OPT_AUTOSTASH(&options.autostash),
+		OPT_STRING_LIST('x', "exec", &options.exec, N_("exec"),
+				N_("add exec lines after each commit of the "
+				   "editable list")),
+		OPT_BOOL_F(0, "allow-empty-message",
+			   &options.allow_empty_message,
+			   N_("allow rebasing commits with empty messages"),
+			   PARSE_OPT_HIDDEN),
+		OPT_CALLBACK_F('r', "rebase-merges", &options, N_("mode"),
+			N_("try to rebase merges instead of skipping them"),
+			PARSE_OPT_OPTARG, parse_opt_rebase_merges),
+		OPT_BOOL(0, "fork-point", &options.fork_point,
+			 N_("use 'merge-base --fork-point' to refine upstream")),
+		OPT_STRING('s', "strategy", &strategy_opt,
+			   N_("strategy"), N_("use the given merge strategy")),
+		OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts,
+				N_("option"),
+				N_("pass the argument through to the merge "
+				   "strategy")),
+		OPT_BOOL(0, "root", &options.root,
+			 N_("rebase all reachable commits up to the root(s)")),
+		OPT_BOOL(0, "reschedule-failed-exec",
+			 &reschedule_failed_exec,
+			 N_("automatically re-schedule any `exec` that fails")),
+		OPT_BOOL(0, "reapply-cherry-picks", &options.reapply_cherry_picks,
+			 N_("apply all changes, even those already present upstream")),
+		OPT_END(),
+	};
+	int i;
+
+	show_usage_with_options_if_asked(argc, argv,
+					 builtin_rebase_usage,
+					 builtin_rebase_options);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	git_config(rebase_config, &options);
+	/* options.gpg_sign_opt will be either "-S" or NULL */
+	gpg_sign = options.gpg_sign_opt ? "" : NULL;
+	FREE_AND_NULL(options.gpg_sign_opt);
+
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "%s/applying", apply_dir());
+	if(file_exists(buf.buf))
+		die(_("It looks like 'git am' is in progress. Cannot rebase."));
+
+	if (is_directory(apply_dir())) {
+		options.type = REBASE_APPLY;
+		options.state_dir = apply_dir();
+	} else if (is_directory(merge_dir())) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%s/rewritten", merge_dir());
+		if (!(options.action == ACTION_ABORT) && is_directory(buf.buf)) {
+			die(_("`rebase --preserve-merges` (-p) is no longer supported.\n"
+			"Use `git rebase --abort` to terminate current rebase.\n"
+			"Or downgrade to v2.33, or earlier, to complete the rebase."));
+		} else {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "%s/interactive", merge_dir());
+			options.type = REBASE_MERGE;
+			if (file_exists(buf.buf))
+				options.flags |= REBASE_INTERACTIVE_EXPLICIT;
+		}
+		options.state_dir = merge_dir();
+	}
+
+	if (options.type != REBASE_UNSPECIFIED)
+		in_progress = 1;
+
+	total_argc = argc;
+	argc = parse_options(argc, argv, prefix,
+			     builtin_rebase_options,
+			     builtin_rebase_usage, 0);
+
+	if (preserve_merges_selected)
+		die(_("--preserve-merges was replaced by --rebase-merges\n"
+			"Note: Your `pull.rebase` configuration may also be set to 'preserve',\n"
+			"which is no longer supported; use 'merges' instead"));
+
+	if (options.action != ACTION_NONE && total_argc != 2) {
+		usage_with_options(builtin_rebase_usage,
+				   builtin_rebase_options);
+	}
+
+	if (argc > 2)
+		usage_with_options(builtin_rebase_usage,
+				   builtin_rebase_options);
+
+	if (keep_base) {
+		if (options.onto_name)
+			die(_("options '%s' and '%s' cannot be used together"), "--keep-base", "--onto");
+		if (options.root)
+			die(_("options '%s' and '%s' cannot be used together"), "--keep-base", "--root");
+		/*
+		 * --keep-base defaults to --no-fork-point to keep the
+		 * base the same.
+		 */
+		if (options.fork_point < 0)
+			options.fork_point = 0;
+	}
+	if (options.root && options.fork_point > 0)
+		die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
+
+	if (options.action != ACTION_NONE && !in_progress)
+		die(_("no rebase in progress"));
+
+	if (options.action == ACTION_EDIT_TODO && !is_merge(&options))
+		die(_("The --edit-todo action can only be used during "
+		      "interactive rebase."));
+
+	if (trace2_is_enabled()) {
+		if (is_merge(&options))
+			trace2_cmd_mode("interactive");
+		else if (options.exec.nr)
+			trace2_cmd_mode("interactive-exec");
+		else
+			trace2_cmd_mode(action_names[options.action]);
+	}
+
+	options.reflog_action = getenv(GIT_REFLOG_ACTION_ENVIRONMENT);
+	options.reflog_action =
+		xstrdup(options.reflog_action ? options.reflog_action : "rebase");
+
+	switch (options.action) {
+	case ACTION_CONTINUE: {
+		struct object_id head;
+		struct lock_file lock_file = LOCK_INIT;
+		int fd;
+
+		/* Sanity check */
+		if (repo_get_oid(the_repository, "HEAD", &head))
+			die(_("Cannot read HEAD"));
+
+		fd = repo_hold_locked_index(the_repository, &lock_file, 0);
+		if (repo_read_index(the_repository) < 0)
+			die(_("could not read index"));
+		refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL,
+			      NULL);
+		if (0 <= fd)
+			repo_update_index_if_able(the_repository, &lock_file);
+		rollback_lock_file(&lock_file);
+
+		if (has_unstaged_changes(the_repository, 1)) {
+			puts(_("You must edit all merge conflicts and then\n"
+			       "mark them as resolved using git add"));
+			exit(1);
+		}
+		if (read_basic_state(&options))
+			exit(1);
+		goto run_rebase;
+	}
+	case ACTION_SKIP: {
+		struct string_list merge_rr = STRING_LIST_INIT_DUP;
+
+		rerere_clear(the_repository, &merge_rr);
+		string_list_clear(&merge_rr, 1);
+		ropts.flags = RESET_HEAD_HARD;
+		if (reset_head(the_repository, &ropts) < 0)
+			die(_("could not discard worktree changes"));
+		remove_branch_state(the_repository, 0);
+		if (read_basic_state(&options))
+			exit(1);
+		goto run_rebase;
+	}
+	case ACTION_ABORT: {
+		struct string_list merge_rr = STRING_LIST_INIT_DUP;
+		struct strbuf head_msg = STRBUF_INIT;
+
+		rerere_clear(the_repository, &merge_rr);
+		string_list_clear(&merge_rr, 1);
+
+		if (read_basic_state(&options))
+			exit(1);
+
+		strbuf_addf(&head_msg, "%s (abort): returning to %s",
+			    options.reflog_action,
+			    options.head_name ? options.head_name
+					      : oid_to_hex(&options.orig_head->object.oid));
+		ropts.oid = &options.orig_head->object.oid;
+		ropts.head_msg = head_msg.buf;
+		ropts.branch = options.head_name;
+		ropts.flags = RESET_HEAD_HARD;
+		if (reset_head(the_repository, &ropts) < 0)
+			die(_("could not move back to %s"),
+			    oid_to_hex(&options.orig_head->object.oid));
+		strbuf_release(&head_msg);
+		remove_branch_state(the_repository, 0);
+		ret = finish_rebase(&options);
+		goto cleanup;
+	}
+	case ACTION_QUIT: {
+		save_autostash(state_dir_path("autostash", &options));
+		if (options.type == REBASE_MERGE) {
+			struct replay_opts replay = REPLAY_OPTS_INIT;
+
+			replay.action = REPLAY_INTERACTIVE_REBASE;
+			ret = sequencer_remove_state(&replay);
+			replay_opts_release(&replay);
+		} else {
+			strbuf_reset(&buf);
+			strbuf_addstr(&buf, options.state_dir);
+			ret = remove_dir_recursively(&buf, 0);
+			if (ret)
+				error(_("could not remove '%s'"),
+				       options.state_dir);
+		}
+		goto cleanup;
+	}
+	case ACTION_EDIT_TODO:
+		options.dont_finish_rebase = 1;
+		goto run_rebase;
+	case ACTION_SHOW_CURRENT_PATCH:
+		options.dont_finish_rebase = 1;
+		goto run_rebase;
+	case ACTION_NONE:
+		break;
+	default:
+		BUG("action: %d", options.action);
+	}
+
+	/* Make sure no rebase is in progress */
+	if (in_progress) {
+		const char *last_slash = strrchr(options.state_dir, '/');
+		const char *state_dir_base =
+			last_slash ? last_slash + 1 : options.state_dir;
+		const char *cmd_live_rebase =
+			"git rebase (--continue | --abort | --skip)";
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "rm -fr \"%s\"", options.state_dir);
+		die(_("It seems that there is already a %s directory, and\n"
+		      "I wonder if you are in the middle of another rebase.  "
+		      "If that is the\n"
+		      "case, please try\n\t%s\n"
+		      "If that is not the case, please\n\t%s\n"
+		      "and run me again.  I am stopping in case you still "
+		      "have something\n"
+		      "valuable there.\n"),
+		    state_dir_base, cmd_live_rebase, buf.buf);
+	}
+
+	if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) ||
+	    (options.action != ACTION_NONE) ||
+	    (options.exec.nr > 0) ||
+	    options.autosquash == 1) {
+		allow_preemptive_ff = 0;
+	}
+	if (options.committer_date_is_author_date || options.ignore_date)
+		options.flags |= REBASE_FORCE;
+
+	for (i = 0; i < options.git_am_opts.nr; i++) {
+		const char *option = options.git_am_opts.v[i], *p;
+		if (!strcmp(option, "--whitespace=fix") ||
+		    !strcmp(option, "--whitespace=strip"))
+			allow_preemptive_ff = 0;
+		else if (skip_prefix(option, "-C", &p)) {
+			while (*p)
+				if (!isdigit(*(p++)))
+					die(_("switch `C' expects a "
+					      "numerical value"));
+		} else if (skip_prefix(option, "--whitespace=", &p)) {
+			if (*p && strcmp(p, "warn") && strcmp(p, "nowarn") &&
+			    strcmp(p, "error") && strcmp(p, "error-all"))
+				die("Invalid whitespace option: '%s'", p);
+		}
+	}
+
+	for (i = 0; i < options.exec.nr; i++)
+		if (check_exec_cmd(options.exec.items[i].string))
+			exit(1);
+
+	if (!(options.flags & REBASE_NO_QUIET))
+		strvec_push(&options.git_am_opts, "-q");
+
+	if (options.empty != EMPTY_UNSPECIFIED)
+		imply_merge(&options, "--empty");
+
+	if (options.reapply_cherry_picks < 0)
+		/*
+		 * We default to --no-reapply-cherry-picks unless
+		 * --keep-base is given; when --keep-base is given, we want
+		 * to default to --reapply-cherry-picks.
+		 */
+		options.reapply_cherry_picks = keep_base;
+	else if (!keep_base)
+		/*
+		 * The apply backend always searches for and drops cherry
+		 * picks.  This is often not wanted with --keep-base, so
+		 * --keep-base allows --reapply-cherry-picks to be
+		 * simulated by altering the upstream such that
+		 * cherry-picks cannot be detected and thus all commits are
+		 * reapplied.  Thus, --[no-]reapply-cherry-picks is
+		 * supported when --keep-base is specified, but not when
+		 * --keep-base is left out.
+		 */
+		imply_merge(&options, options.reapply_cherry_picks ?
+					  "--reapply-cherry-picks" :
+					  "--no-reapply-cherry-picks");
+
+	if (gpg_sign)
+		options.gpg_sign_opt = xstrfmt("-S%s", gpg_sign);
+
+	if (options.exec.nr)
+		imply_merge(&options, "--exec");
+
+	if (options.type == REBASE_APPLY) {
+		if (ignore_whitespace)
+			strvec_push(&options.git_am_opts,
+				    "--ignore-whitespace");
+		if (options.committer_date_is_author_date)
+			strvec_push(&options.git_am_opts,
+				    "--committer-date-is-author-date");
+		if (options.ignore_date)
+			strvec_push(&options.git_am_opts, "--ignore-date");
+	} else {
+		/* REBASE_MERGE */
+		if (ignore_whitespace) {
+			string_list_append(&options.strategy_opts,
+					   "ignore-space-change");
+		}
+	}
+
+	if (strategy_opt)
+		options.strategy = xstrdup(strategy_opt);
+	else if (options.strategy_opts.nr && !options.strategy)
+		options.strategy = xstrdup("ort");
+	if (options.strategy)
+		imply_merge(&options, "--strategy");
+
+	if (options.root && !options.onto_name)
+		imply_merge(&options, "--root without --onto");
+
+	if (isatty(2) && options.flags & REBASE_NO_QUIET)
+		strbuf_addstr(&options.git_format_patch_opt, " --progress");
+
+	if (options.git_am_opts.nr || options.type == REBASE_APPLY) {
+		/* all am options except -q are compatible only with --apply */
+		for (i = options.git_am_opts.nr - 1; i >= 0; i--)
+			if (strcmp(options.git_am_opts.v[i], "-q"))
+				break;
+
+		if (i >= 0 || options.type == REBASE_APPLY) {
+			if (is_merge(&options))
+				die(_("apply options and merge options "
+					  "cannot be used together"));
+			else if (options.rebase_merges == -1 && options.config_rebase_merges == 1)
+				die(_("apply options are incompatible with rebase.rebaseMerges.  Consider adding --no-rebase-merges"));
+			else if (options.update_refs == -1 && options.config_update_refs == 1)
+				die(_("apply options are incompatible with rebase.updateRefs.  Consider adding --no-update-refs"));
+			else
+				options.type = REBASE_APPLY;
+		}
+	}
+
+	if (options.update_refs == 1)
+		imply_merge(&options, "--update-refs");
+	options.update_refs = (options.update_refs >= 0) ? options.update_refs :
+			     ((options.config_update_refs >= 0) ? options.config_update_refs : 0);
+
+	if (options.rebase_merges == 1)
+		imply_merge(&options, "--rebase-merges");
+	options.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges :
+				((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0);
+
+	if (options.autosquash == 1) {
+		imply_merge(&options, "--autosquash");
+	} else if (options.autosquash == -1) {
+		options.autosquash =
+			options.config_autosquash &&
+			(options.flags & REBASE_INTERACTIVE_EXPLICIT);
+	}
+
+	if (options.type == REBASE_UNSPECIFIED) {
+		if (!strcmp(options.default_backend, "merge"))
+			options.type = REBASE_MERGE;
+		else if (!strcmp(options.default_backend, "apply"))
+			options.type = REBASE_APPLY;
+		else
+			die(_("Unknown rebase backend: %s"),
+			    options.default_backend);
+	}
+
+	if (options.type == REBASE_MERGE &&
+	    !options.strategy &&
+	    getenv("GIT_TEST_MERGE_ALGORITHM"))
+		options.strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
+
+	switch (options.type) {
+	case REBASE_MERGE:
+		options.state_dir = merge_dir();
+		break;
+	case REBASE_APPLY:
+		options.state_dir = apply_dir();
+		break;
+	default:
+		BUG("options.type was just set above; should be unreachable.");
+	}
+
+	if (options.empty == EMPTY_UNSPECIFIED) {
+		if (options.flags & REBASE_INTERACTIVE_EXPLICIT)
+			options.empty = EMPTY_STOP;
+		else if (options.exec.nr > 0)
+			options.empty = EMPTY_KEEP;
+		else
+			options.empty = EMPTY_DROP;
+	}
+	if (reschedule_failed_exec > 0 && !is_merge(&options))
+		die(_("--reschedule-failed-exec requires "
+		      "--exec or --interactive"));
+	if (reschedule_failed_exec >= 0)
+		options.reschedule_failed_exec = reschedule_failed_exec;
+
+	if (options.signoff) {
+		strvec_push(&options.git_am_opts, "--signoff");
+		options.flags |= REBASE_FORCE;
+	}
+
+	if (!options.root) {
+		if (argc < 1) {
+			struct branch *branch;
+
+			branch = branch_get(NULL);
+			options.upstream_name = branch_get_upstream(branch,
+								    NULL);
+			if (!options.upstream_name)
+				error_on_missing_default_upstream();
+			if (options.fork_point < 0)
+				options.fork_point = 1;
+		} else {
+			options.upstream_name = argv[0];
+			argc--;
+			argv++;
+			if (!strcmp(options.upstream_name, "-"))
+				options.upstream_name = "@{-1}";
+		}
+		options.upstream =
+			lookup_commit_reference_by_name(options.upstream_name);
+		if (!options.upstream)
+			die(_("invalid upstream '%s'"), options.upstream_name);
+		options.upstream_arg = options.upstream_name;
+	} else {
+		if (!options.onto_name) {
+			if (commit_tree("", 0, the_hash_algo->empty_tree, NULL,
+					&squash_onto, NULL, NULL) < 0)
+				die(_("Could not create new root commit"));
+			options.squash_onto = &squash_onto;
+			options.onto_name = squash_onto_name =
+				xstrdup(oid_to_hex(&squash_onto));
+		} else
+			options.root_with_onto = 1;
+
+		options.upstream_name = NULL;
+		options.upstream = NULL;
+		if (argc > 1)
+			usage_with_options(builtin_rebase_usage,
+					   builtin_rebase_options);
+		options.upstream_arg = "--root";
+	}
+
+	/*
+	 * If the branch to rebase is given, that is the branch we will rebase
+	 * branch_name -- branch/commit being rebased, or
+	 * 		  HEAD (already detached)
+	 * orig_head -- commit object name of tip of the branch before rebasing
+	 * head_name -- refs/heads/<that-branch> or NULL (detached HEAD)
+	 */
+	if (argc == 1) {
+		/* Is it "rebase other branchname" or "rebase other commit"? */
+		struct object_id branch_oid;
+		branch_name = argv[0];
+		options.switch_to = argv[0];
+
+		/* Is it a local branch? */
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/heads/%s", branch_name);
+		if (!refs_read_ref(get_main_ref_store(the_repository), buf.buf, &branch_oid)) {
+			die_if_checked_out(buf.buf, 1);
+			options.head_name = xstrdup(buf.buf);
+			options.orig_head =
+				lookup_commit_object(the_repository,
+						     &branch_oid);
+		/* If not is it a valid ref (branch or commit)? */
+		} else {
+			options.orig_head =
+				lookup_commit_reference_by_name(branch_name);
+			options.head_name = NULL;
+		}
+		if (!options.orig_head)
+			die(_("no such branch/commit '%s'"), branch_name);
+	} else if (argc == 0) {
+		/* Do not need to switch branches, we are already on it. */
+		options.head_name =
+			xstrdup_or_null(refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL,
+								&flags));
+		if (!options.head_name)
+			die(_("No such ref: %s"), "HEAD");
+		if (flags & REF_ISSYMREF) {
+			if (!skip_prefix(options.head_name,
+					 "refs/heads/", &branch_name))
+				branch_name = options.head_name;
+
+		} else {
+			FREE_AND_NULL(options.head_name);
+			branch_name = "HEAD";
+		}
+		options.orig_head = lookup_commit_reference_by_name("HEAD");
+		if (!options.orig_head)
+			die(_("Could not resolve HEAD to a commit"));
+	} else
+		BUG("unexpected number of arguments left to parse");
+
+	/* Make sure the branch to rebase onto is valid. */
+	if (keep_base) {
+		strbuf_reset(&buf);
+		strbuf_addstr(&buf, options.upstream_name);
+		strbuf_addstr(&buf, "...");
+		strbuf_addstr(&buf, branch_name);
+		options.onto_name = keep_base_onto_name = xstrdup(buf.buf);
+	} else if (!options.onto_name)
+		options.onto_name = options.upstream_name;
+	if (strstr(options.onto_name, "...")) {
+		if (repo_get_oid_mb(the_repository, options.onto_name, &branch_base) < 0) {
+			if (keep_base)
+				die(_("'%s': need exactly one merge base with branch"),
+				    options.upstream_name);
+			else
+				die(_("'%s': need exactly one merge base"),
+				    options.onto_name);
+		}
+		options.onto = lookup_commit_or_die(&branch_base,
+						    options.onto_name);
+	} else {
+		options.onto =
+			lookup_commit_reference_by_name(options.onto_name);
+		if (!options.onto)
+			die(_("Does not point to a valid commit '%s'"),
+				options.onto_name);
+		fill_branch_base(&options, &branch_base);
+	}
+
+	if (keep_base && options.reapply_cherry_picks)
+		options.upstream = options.onto;
+
+	if (options.fork_point > 0)
+		options.restrict_revision =
+			get_fork_point(options.upstream_name, options.orig_head);
+
+	if (repo_read_index(the_repository) < 0)
+		die(_("could not read index"));
+
+	if (options.autostash)
+		create_autostash(the_repository,
+				 state_dir_path("autostash", &options));
+
+
+	if (require_clean_work_tree(the_repository, "rebase",
+				    _("Please commit or stash them."), 1, 1)) {
+		ret = -1;
+		goto cleanup_autostash;
+	}
+
+	/*
+	 * Now we are rebasing commits upstream..orig_head (or with --root,
+	 * everything leading up to orig_head) on top of onto.
+	 */
+
+	/*
+	 * Check if we are already based on onto with linear history,
+	 * in which case we could fast-forward without replacing the commits
+	 * with new commits recreated by replaying their changes.
+	 */
+	if (allow_preemptive_ff &&
+	    can_fast_forward(options.onto, options.upstream, options.restrict_revision,
+			     options.orig_head, &branch_base)) {
+		int flag;
+
+		if (!(options.flags & REBASE_FORCE)) {
+			/* Lazily switch to the target branch if needed... */
+			if (options.switch_to) {
+				ret = checkout_up_to_date(&options);
+				if (ret)
+					goto cleanup_autostash;
+			}
+
+			if (!(options.flags & REBASE_NO_QUIET))
+				; /* be quiet */
+			else if (!strcmp(branch_name, "HEAD") &&
+				 refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, &flag))
+				puts(_("HEAD is up to date."));
+			else
+				printf(_("Current branch %s is up to date.\n"),
+				       branch_name);
+			ret = finish_rebase(&options);
+			goto cleanup;
+		} else if (!(options.flags & REBASE_NO_QUIET))
+			; /* be quiet */
+		else if (!strcmp(branch_name, "HEAD") &&
+			 refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, &flag))
+			puts(_("HEAD is up to date, rebase forced."));
+		else
+			printf(_("Current branch %s is up to date, rebase "
+				 "forced.\n"), branch_name);
+	}
+
+	/* If a hook exists, give it a chance to interrupt*/
+	if (!ok_to_skip_pre_rebase &&
+	    run_hooks_l(the_repository, "pre-rebase", options.upstream_arg,
+			argc ? argv[0] : NULL, NULL)) {
+		ret = error(_("The pre-rebase hook refused to rebase."));
+		goto cleanup_autostash;
+	}
+
+	if (options.flags & REBASE_DIFFSTAT) {
+		struct diff_options opts;
+
+		if (options.flags & REBASE_VERBOSE) {
+			if (is_null_oid(&branch_base))
+				printf(_("Changes to %s:\n"),
+				       oid_to_hex(&options.onto->object.oid));
+			else
+				printf(_("Changes from %s to %s:\n"),
+				       oid_to_hex(&branch_base),
+				       oid_to_hex(&options.onto->object.oid));
+		}
+
+		/* We want color (if set), but no pager */
+		repo_diff_setup(the_repository, &opts);
+		init_diffstat_widths(&opts);
+		opts.output_format |=
+			DIFF_FORMAT_SUMMARY | DIFF_FORMAT_DIFFSTAT;
+		opts.detect_rename = DIFF_DETECT_RENAME;
+		diff_setup_done(&opts);
+		diff_tree_oid(is_null_oid(&branch_base) ?
+			      the_hash_algo->empty_tree : &branch_base,
+			      &options.onto->object.oid, "", &opts);
+		diffcore_std(&opts);
+		diff_flush(&opts);
+	}
+
+	if (is_merge(&options))
+		goto run_rebase;
+
+	/* Detach HEAD and reset the tree */
+	if (options.flags & REBASE_NO_QUIET)
+		printf(_("First, rewinding head to replay your work on top of "
+			 "it...\n"));
+
+	strbuf_addf(&msg, "%s (start): checkout %s",
+		    options.reflog_action, options.onto_name);
+	ropts.oid = &options.onto->object.oid;
+	ropts.orig_head = &options.orig_head->object.oid,
+	ropts.flags = RESET_HEAD_DETACH | RESET_ORIG_HEAD |
+			RESET_HEAD_RUN_POST_CHECKOUT_HOOK;
+	ropts.head_msg = msg.buf;
+	ropts.default_reflog_action = options.reflog_action;
+	if (reset_head(the_repository, &ropts)) {
+		ret = error(_("Could not detach HEAD"));
+		goto cleanup_autostash;
+	}
+
+	/*
+	 * If the onto is a proper descendant of the tip of the branch, then
+	 * we just fast-forwarded.
+	 */
+	if (oideq(&branch_base, &options.orig_head->object.oid)) {
+		printf(_("Fast-forwarded %s to %s.\n"),
+			branch_name, options.onto_name);
+		move_to_original_branch(&options);
+		ret = finish_rebase(&options);
+		goto cleanup;
+	}
+
+	strbuf_addf(&revisions, "%s..%s",
+		    options.root ? oid_to_hex(&options.onto->object.oid) :
+		    (options.restrict_revision ?
+		     oid_to_hex(&options.restrict_revision->object.oid) :
+		     oid_to_hex(&options.upstream->object.oid)),
+		    oid_to_hex(&options.orig_head->object.oid));
+
+	options.revisions = revisions.buf;
+
+run_rebase:
+	ret = run_specific_rebase(&options);
+
+cleanup:
+	strbuf_release(&buf);
+	strbuf_release(&msg);
+	strbuf_release(&revisions);
+	rebase_options_release(&options);
+	free(squash_onto_name);
+	free(keep_base_onto_name);
+	return !!ret;
+
+cleanup_autostash:
+	ret |= !!cleanup_autostash(&options);
+	goto cleanup;
+}
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
new file mode 100644
index 0000000000..0fb0266cfd
--- /dev/null
+++ b/builtin/receive-pack.c
@@ -0,0 +1,2641 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "pack.h"
+#include "refs.h"
+#include "pkt-line.h"
+#include "sideband.h"
+#include "run-command.h"
+#include "hook.h"
+#include "exec-cmd.h"
+#include "commit.h"
+#include "object.h"
+#include "remote.h"
+#include "connect.h"
+#include "string-list.h"
+#include "oid-array.h"
+#include "connected.h"
+#include "strvec.h"
+#include "version.h"
+#include "gpg-interface.h"
+#include "sigchain.h"
+#include "fsck.h"
+#include "tmp-objdir.h"
+#include "oidset.h"
+#include "packfile.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
+#include "protocol.h"
+#include "commit-reach.h"
+#include "server-info.h"
+#include "trace.h"
+#include "trace2.h"
+#include "worktree.h"
+#include "shallow.h"
+#include "parse-options.h"
+
+static const char * const receive_pack_usage[] = {
+	N_("git receive-pack <git-dir>"),
+	NULL
+};
+
+enum deny_action {
+	DENY_UNCONFIGURED,
+	DENY_IGNORE,
+	DENY_WARN,
+	DENY_REFUSE,
+	DENY_UPDATE_INSTEAD
+};
+
+static int deny_deletes;
+static int deny_non_fast_forwards;
+static enum deny_action deny_current_branch = DENY_UNCONFIGURED;
+static enum deny_action deny_delete_current = DENY_UNCONFIGURED;
+static int receive_fsck_objects = -1;
+static int transfer_fsck_objects = -1;
+static struct strbuf fsck_msg_types = STRBUF_INIT;
+static int receive_unpack_limit = -1;
+static int transfer_unpack_limit = -1;
+static int advertise_atomic_push = 1;
+static int advertise_push_options;
+static int advertise_sid;
+static int unpack_limit = 100;
+static off_t max_input_size;
+static int report_status;
+static int report_status_v2;
+static int use_sideband;
+static int use_atomic;
+static int use_push_options;
+static int quiet;
+static int prefer_ofs_delta = 1;
+static int auto_update_server_info;
+static int auto_gc = 1;
+static int reject_thin;
+static int stateless_rpc;
+static const char *service_dir;
+static const char *head_name;
+static void *head_name_to_free;
+static int sent_capabilities;
+static int shallow_update;
+static const char *alt_shallow_file;
+static struct strbuf push_cert = STRBUF_INIT;
+static struct object_id push_cert_oid;
+static struct signature_check sigcheck;
+static const char *push_cert_nonce;
+static char *cert_nonce_seed;
+static struct strvec hidden_refs = STRVEC_INIT;
+
+static const char *NONCE_UNSOLICITED = "UNSOLICITED";
+static const char *NONCE_BAD = "BAD";
+static const char *NONCE_MISSING = "MISSING";
+static const char *NONCE_OK = "OK";
+static const char *NONCE_SLOP = "SLOP";
+static const char *nonce_status;
+static long nonce_stamp_slop;
+static timestamp_t nonce_stamp_slop_limit;
+static struct ref_transaction *transaction;
+
+static enum {
+	KEEPALIVE_NEVER = 0,
+	KEEPALIVE_AFTER_NUL,
+	KEEPALIVE_ALWAYS
+} use_keepalive;
+static int keepalive_in_sec = 5;
+
+static struct tmp_objdir *tmp_objdir;
+
+static struct proc_receive_ref {
+	unsigned int want_add:1,
+		     want_delete:1,
+		     want_modify:1,
+		     negative_ref:1;
+	char *ref_prefix;
+	struct proc_receive_ref *next;
+} *proc_receive_ref;
+
+static void proc_receive_ref_append(const char *prefix);
+
+static enum deny_action parse_deny_action(const char *var, const char *value)
+{
+	if (value) {
+		if (!strcasecmp(value, "ignore"))
+			return DENY_IGNORE;
+		if (!strcasecmp(value, "warn"))
+			return DENY_WARN;
+		if (!strcasecmp(value, "refuse"))
+			return DENY_REFUSE;
+		if (!strcasecmp(value, "updateinstead"))
+			return DENY_UPDATE_INSTEAD;
+	}
+	if (git_config_bool(var, value))
+		return DENY_REFUSE;
+	return DENY_IGNORE;
+}
+
+static int receive_pack_config(const char *var, const char *value,
+			       const struct config_context *ctx, void *cb)
+{
+	const char *msg_id;
+	int status = parse_hide_refs_config(var, value, "receive", &hidden_refs);
+
+	if (status)
+		return status;
+
+	if (strcmp(var, "receive.denydeletes") == 0) {
+		deny_deletes = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.denynonfastforwards") == 0) {
+		deny_non_fast_forwards = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.unpacklimit") == 0) {
+		receive_unpack_limit = git_config_int(var, value, ctx->kvi);
+		return 0;
+	}
+
+	if (strcmp(var, "transfer.unpacklimit") == 0) {
+		transfer_unpack_limit = git_config_int(var, value, ctx->kvi);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.fsck.skiplist") == 0) {
+		char *path;
+
+		if (git_config_pathname(&path, var, value))
+			return -1;
+		strbuf_addf(&fsck_msg_types, "%cskiplist=%s",
+			fsck_msg_types.len ? ',' : '=', path);
+		free(path);
+		return 0;
+	}
+
+	if (skip_prefix(var, "receive.fsck.", &msg_id)) {
+		if (!value)
+			return config_error_nonbool(var);
+		if (is_valid_msg_type(msg_id, value))
+			strbuf_addf(&fsck_msg_types, "%c%s=%s",
+				fsck_msg_types.len ? ',' : '=', msg_id, value);
+		else
+			warning("skipping unknown msg id '%s'", msg_id);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.fsckobjects") == 0) {
+		receive_fsck_objects = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "transfer.fsckobjects") == 0) {
+		transfer_fsck_objects = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "receive.denycurrentbranch")) {
+		deny_current_branch = parse_deny_action(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.denydeletecurrent") == 0) {
+		deny_delete_current = parse_deny_action(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "repack.usedeltabaseoffset") == 0) {
+		prefer_ofs_delta = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.updateserverinfo") == 0) {
+		auto_update_server_info = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.autogc") == 0) {
+		auto_gc = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.shallowupdate") == 0) {
+		shallow_update = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.certnonceseed") == 0)
+		return git_config_string(&cert_nonce_seed, var, value);
+
+	if (strcmp(var, "receive.certnonceslop") == 0) {
+		nonce_stamp_slop_limit = git_config_ulong(var, value, ctx->kvi);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.advertiseatomic") == 0) {
+		advertise_atomic_push = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.advertisepushoptions") == 0) {
+		advertise_push_options = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.keepalive") == 0) {
+		keepalive_in_sec = git_config_int(var, value, ctx->kvi);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.maxinputsize") == 0) {
+		max_input_size = git_config_int64(var, value, ctx->kvi);
+		return 0;
+	}
+
+	if (strcmp(var, "receive.procreceiverefs") == 0) {
+		if (!value)
+			return config_error_nonbool(var);
+		proc_receive_ref_append(value);
+		return 0;
+	}
+
+	if (strcmp(var, "transfer.advertisesid") == 0) {
+		advertise_sid = git_config_bool(var, value);
+		return 0;
+	}
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static void show_ref(const char *path, const struct object_id *oid)
+{
+	if (sent_capabilities) {
+		packet_write_fmt(1, "%s %s\n", oid_to_hex(oid), path);
+	} else {
+		struct strbuf cap = STRBUF_INIT;
+
+		strbuf_addstr(&cap,
+			      "report-status report-status-v2 delete-refs side-band-64k quiet");
+		if (advertise_atomic_push)
+			strbuf_addstr(&cap, " atomic");
+		if (prefer_ofs_delta)
+			strbuf_addstr(&cap, " ofs-delta");
+		if (push_cert_nonce)
+			strbuf_addf(&cap, " push-cert=%s", push_cert_nonce);
+		if (advertise_push_options)
+			strbuf_addstr(&cap, " push-options");
+		if (advertise_sid)
+			strbuf_addf(&cap, " session-id=%s", trace2_session_id());
+		strbuf_addf(&cap, " object-format=%s", the_hash_algo->name);
+		strbuf_addf(&cap, " agent=%s", git_user_agent_sanitized());
+		packet_write_fmt(1, "%s %s%c%s\n",
+			     oid_to_hex(oid), path, 0, cap.buf);
+		strbuf_release(&cap);
+		sent_capabilities = 1;
+	}
+}
+
+static int show_ref_cb(const char *path_full, const char *referent UNUSED, const struct object_id *oid,
+		       int flag UNUSED, void *data)
+{
+	struct oidset *seen = data;
+	const char *path = strip_namespace(path_full);
+
+	if (ref_is_hidden(path, path_full, &hidden_refs))
+		return 0;
+
+	/*
+	 * Advertise refs outside our current namespace as ".have"
+	 * refs, so that the client can use them to minimize data
+	 * transfer but will otherwise ignore them.
+	 */
+	if (!path) {
+		if (oidset_insert(seen, oid))
+			return 0;
+		path = ".have";
+	} else {
+		oidset_insert(seen, oid);
+	}
+	show_ref(path, oid);
+	return 0;
+}
+
+static void show_one_alternate_ref(const struct object_id *oid,
+				   void *data)
+{
+	struct oidset *seen = data;
+
+	if (oidset_insert(seen, oid))
+		return;
+
+	show_ref(".have", oid);
+}
+
+static void write_head_info(void)
+{
+	static struct oidset seen = OIDSET_INIT;
+	struct strvec excludes_vector = STRVEC_INIT;
+	const char **exclude_patterns;
+
+	/*
+	 * We need access to the reference names both with and without their
+	 * namespace and thus cannot use `refs_for_each_namespaced_ref()`. We
+	 * thus have to adapt exclude patterns to carry the namespace prefix
+	 * ourselves.
+	 */
+	exclude_patterns = get_namespaced_exclude_patterns(
+		hidden_refs_to_excludes(&hidden_refs),
+		get_git_namespace(), &excludes_vector);
+
+	refs_for_each_fullref_in(get_main_ref_store(the_repository), "",
+				 exclude_patterns, show_ref_cb, &seen);
+	for_each_alternate_ref(show_one_alternate_ref, &seen);
+
+	oidset_clear(&seen);
+	strvec_clear(&excludes_vector);
+
+	if (!sent_capabilities)
+		show_ref("capabilities^{}", null_oid());
+
+	advertise_shallow_grafts(1);
+
+	/* EOF */
+	packet_flush(1);
+}
+
+#define RUN_PROC_RECEIVE_SCHEDULED	1
+#define RUN_PROC_RECEIVE_RETURNED	2
+struct command {
+	struct command *next;
+	const char *error_string;
+	char *error_string_owned;
+	struct ref_push_report *report;
+	unsigned int skip_update:1,
+		     did_not_exist:1,
+		     run_proc_receive:2;
+	int index;
+	struct object_id old_oid;
+	struct object_id new_oid;
+	char ref_name[FLEX_ARRAY]; /* more */
+};
+
+static void proc_receive_ref_append(const char *prefix)
+{
+	struct proc_receive_ref *ref_pattern;
+	char *p;
+	int len;
+
+	CALLOC_ARRAY(ref_pattern, 1);
+	p = strchr(prefix, ':');
+	if (p) {
+		while (prefix < p) {
+			if (*prefix == 'a')
+				ref_pattern->want_add = 1;
+			else if (*prefix == 'd')
+				ref_pattern->want_delete = 1;
+			else if (*prefix == 'm')
+				ref_pattern->want_modify = 1;
+			else if (*prefix == '!')
+				ref_pattern->negative_ref = 1;
+			prefix++;
+		}
+		prefix++;
+	} else {
+		ref_pattern->want_add = 1;
+		ref_pattern->want_delete = 1;
+		ref_pattern->want_modify = 1;
+	}
+	len = strlen(prefix);
+	while (len && prefix[len - 1] == '/')
+		len--;
+	ref_pattern->ref_prefix = xmemdupz(prefix, len);
+	if (!proc_receive_ref) {
+		proc_receive_ref = ref_pattern;
+	} else {
+		struct proc_receive_ref *end;
+
+		end = proc_receive_ref;
+		while (end->next)
+			end = end->next;
+		end->next = ref_pattern;
+	}
+}
+
+static int proc_receive_ref_matches(struct command *cmd)
+{
+	struct proc_receive_ref *p;
+
+	if (!proc_receive_ref)
+		return 0;
+
+	for (p = proc_receive_ref; p; p = p->next) {
+		const char *match = p->ref_prefix;
+		const char *remains;
+
+		if (!p->want_add && is_null_oid(&cmd->old_oid))
+			continue;
+		else if (!p->want_delete && is_null_oid(&cmd->new_oid))
+			continue;
+		else if (!p->want_modify &&
+			 !is_null_oid(&cmd->old_oid) &&
+			 !is_null_oid(&cmd->new_oid))
+			continue;
+
+		if (skip_prefix(cmd->ref_name, match, &remains) &&
+		    (!*remains || *remains == '/')) {
+			if (!p->negative_ref)
+				return 1;
+		} else if (p->negative_ref) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static void report_message(const char *prefix, const char *err, va_list params)
+{
+	int sz;
+	char msg[4096];
+
+	sz = xsnprintf(msg, sizeof(msg), "%s", prefix);
+	sz += vsnprintf(msg + sz, sizeof(msg) - sz, err, params);
+	if (sz > (sizeof(msg) - 1))
+		sz = sizeof(msg) - 1;
+	msg[sz++] = '\n';
+
+	if (use_sideband)
+		send_sideband(1, 2, msg, sz, use_sideband);
+	else
+		xwrite(2, msg, sz);
+}
+
+__attribute__((format (printf, 1, 2)))
+static void rp_warning(const char *err, ...)
+{
+	va_list params;
+	va_start(params, err);
+	report_message("warning: ", err, params);
+	va_end(params);
+}
+
+__attribute__((format (printf, 1, 2)))
+static void rp_error(const char *err, ...)
+{
+	va_list params;
+	va_start(params, err);
+	report_message("error: ", err, params);
+	va_end(params);
+}
+
+static int copy_to_sideband(int in, int out UNUSED, void *arg UNUSED)
+{
+	char data[128];
+	int keepalive_active = 0;
+
+	if (keepalive_in_sec <= 0)
+		use_keepalive = KEEPALIVE_NEVER;
+	if (use_keepalive == KEEPALIVE_ALWAYS)
+		keepalive_active = 1;
+
+	while (1) {
+		ssize_t sz;
+
+		if (keepalive_active) {
+			struct pollfd pfd;
+			int ret;
+
+			pfd.fd = in;
+			pfd.events = POLLIN;
+			ret = poll(&pfd, 1, 1000 * keepalive_in_sec);
+
+			if (ret < 0) {
+				if (errno == EINTR)
+					continue;
+				else
+					break;
+			} else if (ret == 0) {
+				/* no data; send a keepalive packet */
+				static const char buf[] = "0005\1";
+				write_or_die(1, buf, sizeof(buf) - 1);
+				continue;
+			} /* else there is actual data to read */
+		}
+
+		sz = xread(in, data, sizeof(data));
+		if (sz <= 0)
+			break;
+
+		if (use_keepalive == KEEPALIVE_AFTER_NUL && !keepalive_active) {
+			const char *p = memchr(data, '\0', sz);
+			if (p) {
+				/*
+				 * The NUL tells us to start sending keepalives. Make
+				 * sure we send any other data we read along
+				 * with it.
+				 */
+				keepalive_active = 1;
+				send_sideband(1, 2, data, p - data, use_sideband);
+				send_sideband(1, 2, p + 1, sz - (p - data + 1), use_sideband);
+				continue;
+			}
+		}
+
+		/*
+		 * Either we're not looking for a NUL signal, or we didn't see
+		 * it yet; just pass along the data.
+		 */
+		send_sideband(1, 2, data, sz, use_sideband);
+	}
+	close(in);
+	return 0;
+}
+
+static void hmac_hash(unsigned char *out,
+		      const char *key_in, size_t key_len,
+		      const char *text, size_t text_len)
+{
+	unsigned char key[GIT_MAX_BLKSZ];
+	unsigned char k_ipad[GIT_MAX_BLKSZ];
+	unsigned char k_opad[GIT_MAX_BLKSZ];
+	int i;
+	git_hash_ctx ctx;
+
+	/* RFC 2104 2. (1) */
+	memset(key, '\0', GIT_MAX_BLKSZ);
+	if (the_hash_algo->blksz < key_len) {
+		the_hash_algo->init_fn(&ctx);
+		the_hash_algo->update_fn(&ctx, key_in, key_len);
+		the_hash_algo->final_fn(key, &ctx);
+	} else {
+		memcpy(key, key_in, key_len);
+	}
+
+	/* RFC 2104 2. (2) & (5) */
+	for (i = 0; i < sizeof(key); i++) {
+		k_ipad[i] = key[i] ^ 0x36;
+		k_opad[i] = key[i] ^ 0x5c;
+	}
+
+	/* RFC 2104 2. (3) & (4) */
+	the_hash_algo->init_fn(&ctx);
+	the_hash_algo->update_fn(&ctx, k_ipad, sizeof(k_ipad));
+	the_hash_algo->update_fn(&ctx, text, text_len);
+	the_hash_algo->final_fn(out, &ctx);
+
+	/* RFC 2104 2. (6) & (7) */
+	the_hash_algo->init_fn(&ctx);
+	the_hash_algo->update_fn(&ctx, k_opad, sizeof(k_opad));
+	the_hash_algo->update_fn(&ctx, out, the_hash_algo->rawsz);
+	the_hash_algo->final_fn(out, &ctx);
+}
+
+static char *prepare_push_cert_nonce(const char *path, timestamp_t stamp)
+{
+	struct strbuf buf = STRBUF_INIT;
+	unsigned char hash[GIT_MAX_RAWSZ];
+
+	strbuf_addf(&buf, "%s:%"PRItime, path, stamp);
+	hmac_hash(hash, buf.buf, buf.len, cert_nonce_seed, strlen(cert_nonce_seed));
+	strbuf_release(&buf);
+
+	/* RFC 2104 5. HMAC-SHA1 or HMAC-SHA256 */
+	strbuf_addf(&buf, "%"PRItime"-%.*s", stamp, (int)the_hash_algo->hexsz, hash_to_hex(hash));
+	return strbuf_detach(&buf, NULL);
+}
+
+/*
+ * Return zero if a and b are equal up to n bytes and nonzero if they are not.
+ * This operation is guaranteed to run in constant time to avoid leaking data.
+ */
+static int constant_memequal(const char *a, const char *b, size_t n)
+{
+	int res = 0;
+	size_t i;
+
+	for (i = 0; i < n; i++)
+		res |= a[i] ^ b[i];
+	return res;
+}
+
+static const char *check_nonce(const char *buf)
+{
+	size_t noncelen;
+	const char *found = find_commit_header(buf, "nonce", &noncelen);
+	char *nonce = found ? xmemdupz(found, noncelen) : NULL;
+	timestamp_t stamp, ostamp;
+	char *bohmac, *expect = NULL;
+	const char *retval = NONCE_BAD;
+
+	if (!nonce) {
+		retval = NONCE_MISSING;
+		goto leave;
+	} else if (!push_cert_nonce) {
+		retval = NONCE_UNSOLICITED;
+		goto leave;
+	} else if (!strcmp(push_cert_nonce, nonce)) {
+		retval = NONCE_OK;
+		goto leave;
+	}
+
+	if (!stateless_rpc) {
+		/* returned nonce MUST match what we gave out earlier */
+		retval = NONCE_BAD;
+		goto leave;
+	}
+
+	/*
+	 * In stateless mode, we may be receiving a nonce issued by
+	 * another instance of the server that serving the same
+	 * repository, and the timestamps may not match, but the
+	 * nonce-seed and dir should match, so we can recompute and
+	 * report the time slop.
+	 *
+	 * In addition, when a nonce issued by another instance has
+	 * timestamp within receive.certnonceslop seconds, we pretend
+	 * as if we issued that nonce when reporting to the hook.
+	 */
+
+	/* nonce is concat(<seconds-since-epoch>, "-", <hmac>) */
+	if (*nonce <= '0' || '9' < *nonce) {
+		retval = NONCE_BAD;
+		goto leave;
+	}
+	stamp = parse_timestamp(nonce, &bohmac, 10);
+	if (bohmac == nonce || bohmac[0] != '-') {
+		retval = NONCE_BAD;
+		goto leave;
+	}
+
+	expect = prepare_push_cert_nonce(service_dir, stamp);
+	if (noncelen != strlen(expect)) {
+		/* This is not even the right size. */
+		retval = NONCE_BAD;
+		goto leave;
+	}
+	if (constant_memequal(expect, nonce, noncelen)) {
+		/* Not what we would have signed earlier */
+		retval = NONCE_BAD;
+		goto leave;
+	}
+
+	/*
+	 * By how many seconds is this nonce stale?  Negative value
+	 * would mean it was issued by another server with its clock
+	 * skewed in the future.
+	 */
+	ostamp = parse_timestamp(push_cert_nonce, NULL, 10);
+	nonce_stamp_slop = (long)ostamp - (long)stamp;
+
+	if (nonce_stamp_slop_limit &&
+	    labs(nonce_stamp_slop) <= nonce_stamp_slop_limit) {
+		/*
+		 * Pretend as if the received nonce (which passes the
+		 * HMAC check, so it is not a forged by third-party)
+		 * is what we issued.
+		 */
+		free((void *)push_cert_nonce);
+		push_cert_nonce = xstrdup(nonce);
+		retval = NONCE_OK;
+	} else {
+		retval = NONCE_SLOP;
+	}
+
+leave:
+	free(nonce);
+	free(expect);
+	return retval;
+}
+
+/*
+ * Return 1 if there is no push_cert or if the push options in push_cert are
+ * the same as those in the argument; 0 otherwise.
+ */
+static int check_cert_push_options(const struct string_list *push_options)
+{
+	const char *buf = push_cert.buf;
+
+	const char *option;
+	size_t optionlen;
+	int options_seen = 0;
+
+	int retval = 1;
+
+	if (!*buf)
+		return 1;
+
+	while ((option = find_commit_header(buf, "push-option", &optionlen))) {
+		buf = option + optionlen + 1;
+		options_seen++;
+		if (options_seen > push_options->nr
+		    || xstrncmpz(push_options->items[options_seen - 1].string,
+				 option, optionlen))
+			return 0;
+	}
+
+	if (options_seen != push_options->nr)
+		retval = 0;
+
+	return retval;
+}
+
+static void prepare_push_cert_sha1(struct child_process *proc)
+{
+	static int already_done;
+
+	if (!push_cert.len)
+		return;
+
+	if (!already_done) {
+		int bogs /* beginning_of_gpg_sig */;
+
+		already_done = 1;
+		if (write_object_file(push_cert.buf, push_cert.len, OBJ_BLOB,
+				      &push_cert_oid))
+			oidclr(&push_cert_oid, the_repository->hash_algo);
+
+		memset(&sigcheck, '\0', sizeof(sigcheck));
+
+		bogs = parse_signed_buffer(push_cert.buf, push_cert.len);
+		sigcheck.payload = xmemdupz(push_cert.buf, bogs);
+		sigcheck.payload_len = bogs;
+		check_signature(&sigcheck, push_cert.buf + bogs,
+				push_cert.len - bogs);
+
+		nonce_status = check_nonce(sigcheck.payload);
+	}
+	if (!is_null_oid(&push_cert_oid)) {
+		strvec_pushf(&proc->env, "GIT_PUSH_CERT=%s",
+			     oid_to_hex(&push_cert_oid));
+		strvec_pushf(&proc->env, "GIT_PUSH_CERT_SIGNER=%s",
+			     sigcheck.signer ? sigcheck.signer : "");
+		strvec_pushf(&proc->env, "GIT_PUSH_CERT_KEY=%s",
+			     sigcheck.key ? sigcheck.key : "");
+		strvec_pushf(&proc->env, "GIT_PUSH_CERT_STATUS=%c",
+			     sigcheck.result);
+		if (push_cert_nonce) {
+			strvec_pushf(&proc->env,
+				     "GIT_PUSH_CERT_NONCE=%s",
+				     push_cert_nonce);
+			strvec_pushf(&proc->env,
+				     "GIT_PUSH_CERT_NONCE_STATUS=%s",
+				     nonce_status);
+			if (nonce_status == NONCE_SLOP)
+				strvec_pushf(&proc->env,
+					     "GIT_PUSH_CERT_NONCE_SLOP=%ld",
+					     nonce_stamp_slop);
+		}
+	}
+}
+
+struct receive_hook_feed_state {
+	struct command *cmd;
+	struct ref_push_report *report;
+	int skip_broken;
+	struct strbuf buf;
+	const struct string_list *push_options;
+};
+
+typedef int (*feed_fn)(void *, const char **, size_t *);
+static int run_and_feed_hook(const char *hook_name, feed_fn feed,
+			     struct receive_hook_feed_state *feed_state)
+{
+	struct child_process proc = CHILD_PROCESS_INIT;
+	struct async muxer;
+	int code;
+	const char *hook_path = find_hook(the_repository, hook_name);
+
+	if (!hook_path)
+		return 0;
+
+	strvec_push(&proc.args, hook_path);
+	proc.in = -1;
+	proc.stdout_to_stderr = 1;
+	proc.trace2_hook_name = hook_name;
+
+	if (feed_state->push_options) {
+		size_t i;
+		for (i = 0; i < feed_state->push_options->nr; i++)
+			strvec_pushf(&proc.env,
+				     "GIT_PUSH_OPTION_%"PRIuMAX"=%s",
+				     (uintmax_t)i,
+				     feed_state->push_options->items[i].string);
+		strvec_pushf(&proc.env, "GIT_PUSH_OPTION_COUNT=%"PRIuMAX"",
+			     (uintmax_t)feed_state->push_options->nr);
+	} else
+		strvec_pushf(&proc.env, "GIT_PUSH_OPTION_COUNT");
+
+	if (tmp_objdir)
+		strvec_pushv(&proc.env, tmp_objdir_env(tmp_objdir));
+
+	if (use_sideband) {
+		memset(&muxer, 0, sizeof(muxer));
+		muxer.proc = copy_to_sideband;
+		muxer.in = -1;
+		code = start_async(&muxer);
+		if (code)
+			return code;
+		proc.err = muxer.in;
+	}
+
+	prepare_push_cert_sha1(&proc);
+
+	code = start_command(&proc);
+	if (code) {
+		if (use_sideband)
+			finish_async(&muxer);
+		return code;
+	}
+
+	sigchain_push(SIGPIPE, SIG_IGN);
+
+	while (1) {
+		const char *buf;
+		size_t n;
+		if (feed(feed_state, &buf, &n))
+			break;
+		if (write_in_full(proc.in, buf, n) < 0)
+			break;
+	}
+	close(proc.in);
+	if (use_sideband)
+		finish_async(&muxer);
+
+	sigchain_pop(SIGPIPE);
+
+	return finish_command(&proc);
+}
+
+static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
+{
+	struct receive_hook_feed_state *state = state_;
+	struct command *cmd = state->cmd;
+
+	while (cmd &&
+	       state->skip_broken && (cmd->error_string || cmd->did_not_exist))
+		cmd = cmd->next;
+	if (!cmd)
+		return -1; /* EOF */
+	if (!bufp)
+		return 0; /* OK, can feed something. */
+	strbuf_reset(&state->buf);
+	if (!state->report)
+		state->report = cmd->report;
+	if (state->report) {
+		struct object_id *old_oid;
+		struct object_id *new_oid;
+		const char *ref_name;
+
+		old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid;
+		new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid;
+		ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name;
+		strbuf_addf(&state->buf, "%s %s %s\n",
+			    oid_to_hex(old_oid), oid_to_hex(new_oid),
+			    ref_name);
+		state->report = state->report->next;
+		if (!state->report)
+			state->cmd = cmd->next;
+	} else {
+		strbuf_addf(&state->buf, "%s %s %s\n",
+			    oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
+			    cmd->ref_name);
+		state->cmd = cmd->next;
+	}
+	if (bufp) {
+		*bufp = state->buf.buf;
+		*sizep = state->buf.len;
+	}
+	return 0;
+}
+
+static int run_receive_hook(struct command *commands,
+			    const char *hook_name,
+			    int skip_broken,
+			    const struct string_list *push_options)
+{
+	struct receive_hook_feed_state state;
+	int status;
+
+	strbuf_init(&state.buf, 0);
+	state.cmd = commands;
+	state.skip_broken = skip_broken;
+	state.report = NULL;
+	if (feed_receive_hook(&state, NULL, NULL))
+		return 0;
+	state.cmd = commands;
+	state.push_options = push_options;
+	status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
+	strbuf_release(&state.buf);
+	return status;
+}
+
+static int run_update_hook(struct command *cmd)
+{
+	struct child_process proc = CHILD_PROCESS_INIT;
+	int code;
+	const char *hook_path = find_hook(the_repository, "update");
+
+	if (!hook_path)
+		return 0;
+
+	strvec_push(&proc.args, hook_path);
+	strvec_push(&proc.args, cmd->ref_name);
+	strvec_push(&proc.args, oid_to_hex(&cmd->old_oid));
+	strvec_push(&proc.args, oid_to_hex(&cmd->new_oid));
+
+	proc.no_stdin = 1;
+	proc.stdout_to_stderr = 1;
+	proc.err = use_sideband ? -1 : 0;
+	proc.trace2_hook_name = "update";
+
+	code = start_command(&proc);
+	if (code)
+		return code;
+	if (use_sideband)
+		copy_to_sideband(proc.err, -1, NULL);
+	return finish_command(&proc);
+}
+
+static struct command *find_command_by_refname(struct command *list,
+					       const char *refname)
+{
+	for (; list; list = list->next)
+		if (!strcmp(list->ref_name, refname))
+			return list;
+	return NULL;
+}
+
+static int read_proc_receive_report(struct packet_reader *reader,
+				    struct command *commands,
+				    struct strbuf *errmsg)
+{
+	struct command *cmd;
+	struct command *hint = NULL;
+	struct ref_push_report *report = NULL;
+	int new_report = 0;
+	int code = 0;
+	int once = 0;
+	int response = 0;
+
+	for (;;) {
+		struct object_id old_oid, new_oid;
+		const char *head;
+		const char *refname;
+		char *p;
+		enum packet_read_status status;
+
+		status = packet_reader_read(reader);
+		if (status != PACKET_READ_NORMAL) {
+			/* Check whether proc-receive exited abnormally */
+			if (status == PACKET_READ_EOF && !response) {
+				strbuf_addstr(errmsg, "proc-receive exited abnormally");
+				return -1;
+			}
+			break;
+		}
+		response++;
+
+		head = reader->line;
+		p = strchr(head, ' ');
+		if (!p) {
+			strbuf_addf(errmsg, "proc-receive reported incomplete status line: '%s'\n", head);
+			code = -1;
+			continue;
+		}
+		*p++ = '\0';
+		if (!strcmp(head, "option")) {
+			const char *key, *val;
+
+			if (!hint || !(report || new_report)) {
+				if (!once++)
+					strbuf_addstr(errmsg, "proc-receive reported 'option' without a matching 'ok/ng' directive\n");
+				code = -1;
+				continue;
+			}
+			if (new_report) {
+				if (!hint->report) {
+					CALLOC_ARRAY(hint->report, 1);
+					report = hint->report;
+				} else {
+					report = hint->report;
+					while (report->next)
+						report = report->next;
+					report->next = xcalloc(1, sizeof(struct ref_push_report));
+					report = report->next;
+				}
+				new_report = 0;
+			}
+			key = p;
+			p = strchr(key, ' ');
+			if (p)
+				*p++ = '\0';
+			val = p;
+			if (!strcmp(key, "refname"))
+				report->ref_name = xstrdup_or_null(val);
+			else if (!strcmp(key, "old-oid") && val &&
+				 !parse_oid_hex(val, &old_oid, &val))
+				report->old_oid = oiddup(&old_oid);
+			else if (!strcmp(key, "new-oid") && val &&
+				 !parse_oid_hex(val, &new_oid, &val))
+				report->new_oid = oiddup(&new_oid);
+			else if (!strcmp(key, "forced-update"))
+				report->forced_update = 1;
+			else if (!strcmp(key, "fall-through"))
+				/* Fall through, let 'receive-pack' to execute it. */
+				hint->run_proc_receive = 0;
+			continue;
+		}
+
+		report = NULL;
+		new_report = 0;
+		refname = p;
+		p = strchr(refname, ' ');
+		if (p)
+			*p++ = '\0';
+		if (strcmp(head, "ok") && strcmp(head, "ng")) {
+			strbuf_addf(errmsg, "proc-receive reported bad status '%s' on ref '%s'\n",
+				    head, refname);
+			code = -1;
+			continue;
+		}
+
+		/* first try searching at our hint, falling back to all refs */
+		if (hint)
+			hint = find_command_by_refname(hint, refname);
+		if (!hint)
+			hint = find_command_by_refname(commands, refname);
+		if (!hint) {
+			strbuf_addf(errmsg, "proc-receive reported status on unknown ref: %s\n",
+				    refname);
+			code = -1;
+			continue;
+		}
+		if (!hint->run_proc_receive) {
+			strbuf_addf(errmsg, "proc-receive reported status on unexpected ref: %s\n",
+				    refname);
+			code = -1;
+			continue;
+		}
+		hint->run_proc_receive |= RUN_PROC_RECEIVE_RETURNED;
+		if (!strcmp(head, "ng")) {
+			if (p)
+				hint->error_string = hint->error_string_owned = xstrdup(p);
+			else
+				hint->error_string = "failed";
+			code = -1;
+			continue;
+		}
+		new_report = 1;
+	}
+
+	for (cmd = commands; cmd; cmd = cmd->next)
+		if (cmd->run_proc_receive && !cmd->error_string &&
+		    !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED)) {
+		    cmd->error_string = "proc-receive failed to report status";
+		    code = -1;
+		}
+	return code;
+}
+
+static int run_proc_receive_hook(struct command *commands,
+				 const struct string_list *push_options)
+{
+	struct child_process proc = CHILD_PROCESS_INIT;
+	struct async muxer;
+	struct command *cmd;
+	struct packet_reader reader;
+	struct strbuf cap = STRBUF_INIT;
+	struct strbuf errmsg = STRBUF_INIT;
+	int hook_use_push_options = 0;
+	int version = 0;
+	int code;
+	const char *hook_path = find_hook(the_repository, "proc-receive");
+
+	if (!hook_path) {
+		rp_error("cannot find hook 'proc-receive'");
+		return -1;
+	}
+
+	strvec_push(&proc.args, hook_path);
+	proc.in = -1;
+	proc.out = -1;
+	proc.trace2_hook_name = "proc-receive";
+
+	if (use_sideband) {
+		memset(&muxer, 0, sizeof(muxer));
+		muxer.proc = copy_to_sideband;
+		muxer.in = -1;
+		code = start_async(&muxer);
+		if (code)
+			return code;
+		proc.err = muxer.in;
+	} else {
+		proc.err = 0;
+	}
+
+	code = start_command(&proc);
+	if (code) {
+		if (use_sideband)
+			finish_async(&muxer);
+		return code;
+	}
+
+	sigchain_push(SIGPIPE, SIG_IGN);
+
+	/* Version negotiaton */
+	packet_reader_init(&reader, proc.out, NULL, 0,
+			   PACKET_READ_CHOMP_NEWLINE |
+			   PACKET_READ_GENTLE_ON_EOF);
+	if (use_atomic)
+		strbuf_addstr(&cap, " atomic");
+	if (use_push_options)
+		strbuf_addstr(&cap, " push-options");
+	if (cap.len) {
+		code = packet_write_fmt_gently(proc.in, "version=1%c%s\n", '\0', cap.buf + 1);
+		strbuf_release(&cap);
+	} else {
+		code = packet_write_fmt_gently(proc.in, "version=1\n");
+	}
+	if (!code)
+		code = packet_flush_gently(proc.in);
+
+	if (!code)
+		for (;;) {
+			int linelen;
+			enum packet_read_status status;
+
+			status = packet_reader_read(&reader);
+			if (status != PACKET_READ_NORMAL) {
+				/* Check whether proc-receive exited abnormally */
+				if (status == PACKET_READ_EOF)
+					code = -1;
+				break;
+			}
+
+			if (reader.pktlen > 8 && starts_with(reader.line, "version=")) {
+				version = atoi(reader.line + 8);
+				linelen = strlen(reader.line);
+				if (linelen < reader.pktlen) {
+					const char *feature_list = reader.line + linelen + 1;
+					if (parse_feature_request(feature_list, "push-options"))
+						hook_use_push_options = 1;
+				}
+			}
+		}
+
+	if (code) {
+		strbuf_addstr(&errmsg, "fail to negotiate version with proc-receive hook");
+		goto cleanup;
+	}
+
+	switch (version) {
+	case 0:
+		/* fallthrough */
+	case 1:
+		break;
+	default:
+		strbuf_addf(&errmsg, "proc-receive version '%d' is not supported",
+			    version);
+		code = -1;
+		goto cleanup;
+	}
+
+	/* Send commands */
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (!cmd->run_proc_receive || cmd->skip_update || cmd->error_string)
+			continue;
+		code = packet_write_fmt_gently(proc.in, "%s %s %s",
+					       oid_to_hex(&cmd->old_oid),
+					       oid_to_hex(&cmd->new_oid),
+					       cmd->ref_name);
+		if (code)
+			break;
+	}
+	if (!code)
+		code = packet_flush_gently(proc.in);
+	if (code) {
+		strbuf_addstr(&errmsg, "fail to write commands to proc-receive hook");
+		goto cleanup;
+	}
+
+	/* Send push options */
+	if (hook_use_push_options) {
+		struct string_list_item *item;
+
+		for_each_string_list_item(item, push_options) {
+			code = packet_write_fmt_gently(proc.in, "%s", item->string);
+			if (code)
+				break;
+		}
+		if (!code)
+			code = packet_flush_gently(proc.in);
+		if (code) {
+			strbuf_addstr(&errmsg,
+				      "fail to write push-options to proc-receive hook");
+			goto cleanup;
+		}
+	}
+
+	/* Read result from proc-receive */
+	code = read_proc_receive_report(&reader, commands, &errmsg);
+
+cleanup:
+	close(proc.in);
+	close(proc.out);
+	if (use_sideband)
+		finish_async(&muxer);
+	if (finish_command(&proc))
+		code = -1;
+	if (errmsg.len >0) {
+		char *p = errmsg.buf;
+
+		p += errmsg.len - 1;
+		if (*p == '\n')
+			*p = '\0';
+		rp_error("%s", errmsg.buf);
+		strbuf_release(&errmsg);
+	}
+	sigchain_pop(SIGPIPE);
+
+	return code;
+}
+
+static const char *refuse_unconfigured_deny_msg =
+	N_("By default, updating the current branch in a non-bare repository\n"
+	   "is denied, because it will make the index and work tree inconsistent\n"
+	   "with what you pushed, and will require 'git reset --hard' to match\n"
+	   "the work tree to HEAD.\n"
+	   "\n"
+	   "You can set the 'receive.denyCurrentBranch' configuration variable\n"
+	   "to 'ignore' or 'warn' in the remote repository to allow pushing into\n"
+	   "its current branch; however, this is not recommended unless you\n"
+	   "arranged to update its work tree to match what you pushed in some\n"
+	   "other way.\n"
+	   "\n"
+	   "To squelch this message and still keep the default behaviour, set\n"
+	   "'receive.denyCurrentBranch' configuration variable to 'refuse'.");
+
+static void refuse_unconfigured_deny(void)
+{
+	rp_error("%s", _(refuse_unconfigured_deny_msg));
+}
+
+static const char *refuse_unconfigured_deny_delete_current_msg =
+	N_("By default, deleting the current branch is denied, because the next\n"
+	   "'git clone' won't result in any file checked out, causing confusion.\n"
+	   "\n"
+	   "You can set 'receive.denyDeleteCurrent' configuration variable to\n"
+	   "'warn' or 'ignore' in the remote repository to allow deleting the\n"
+	   "current branch, with or without a warning message.\n"
+	   "\n"
+	   "To squelch this message, you can set it to 'refuse'.");
+
+static void refuse_unconfigured_deny_delete_current(void)
+{
+	rp_error("%s", _(refuse_unconfigured_deny_delete_current_msg));
+}
+
+static const struct object_id *command_singleton_iterator(void *cb_data);
+static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
+{
+	struct shallow_lock shallow_lock = SHALLOW_LOCK_INIT;
+	struct oid_array extra = OID_ARRAY_INIT;
+	struct check_connected_options opt = CHECK_CONNECTED_INIT;
+	uint32_t mask = 1 << (cmd->index % 32);
+	int i;
+
+	trace_printf_key(&trace_shallow,
+			 "shallow: update_shallow_ref %s\n", cmd->ref_name);
+	for (i = 0; i < si->shallow->nr; i++)
+		if (si->used_shallow[i] &&
+		    (si->used_shallow[i][cmd->index / 32] & mask) &&
+		    !delayed_reachability_test(si, i))
+			oid_array_append(&extra, &si->shallow->oid[i]);
+
+	opt.env = tmp_objdir_env(tmp_objdir);
+	setup_alternate_shallow(&shallow_lock, &opt.shallow_file, &extra);
+	if (check_connected(command_singleton_iterator, cmd, &opt)) {
+		rollback_shallow_file(the_repository, &shallow_lock);
+		oid_array_clear(&extra);
+		return -1;
+	}
+
+	commit_shallow_file(the_repository, &shallow_lock);
+
+	/*
+	 * Make sure setup_alternate_shallow() for the next ref does
+	 * not lose these new roots..
+	 */
+	for (i = 0; i < extra.nr; i++)
+		register_shallow(the_repository, &extra.oid[i]);
+
+	si->shallow_ref[cmd->index] = 0;
+	oid_array_clear(&extra);
+	return 0;
+}
+
+/*
+ * NEEDSWORK: we should consolidate various implementations of "are we
+ * on an unborn branch?" test into one, and make the unified one more
+ * robust. !get_sha1() based check used here and elsewhere would not
+ * allow us to tell an unborn branch from corrupt ref, for example.
+ * For the purpose of fixing "deploy-to-update does not work when
+ * pushing into an empty repository" issue, this should suffice for
+ * now.
+ */
+static int head_has_history(void)
+{
+	struct object_id oid;
+
+	return !repo_get_oid(the_repository, "HEAD", &oid);
+}
+
+static const char *push_to_deploy(unsigned char *sha1,
+				  struct strvec *env,
+				  const char *work_tree)
+{
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	strvec_pushl(&child.args, "update-index", "-q", "--ignore-submodules",
+		     "--refresh", NULL);
+	strvec_pushv(&child.env, env->v);
+	child.dir = work_tree;
+	child.no_stdin = 1;
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		return "Up-to-date check failed";
+
+	/* run_command() does not clean up completely; reinitialize */
+	child_process_init(&child);
+	strvec_pushl(&child.args, "diff-files", "--quiet",
+		     "--ignore-submodules", "--", NULL);
+	strvec_pushv(&child.env, env->v);
+	child.dir = work_tree;
+	child.no_stdin = 1;
+	child.stdout_to_stderr = 1;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		return "Working directory has unstaged changes";
+
+	child_process_init(&child);
+	strvec_pushl(&child.args, "diff-index", "--quiet", "--cached",
+		     "--ignore-submodules",
+		     /* diff-index with either HEAD or an empty tree */
+		     head_has_history() ? "HEAD" : empty_tree_oid_hex(the_repository->hash_algo),
+		     "--", NULL);
+	strvec_pushv(&child.env, env->v);
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		return "Working directory has staged changes";
+
+	child_process_init(&child);
+	strvec_pushl(&child.args, "read-tree", "-u", "-m", hash_to_hex(sha1),
+		     NULL);
+	strvec_pushv(&child.env, env->v);
+	child.dir = work_tree;
+	child.no_stdin = 1;
+	child.no_stdout = 1;
+	child.stdout_to_stderr = 0;
+	child.git_cmd = 1;
+	if (run_command(&child))
+		return "Could not update working tree to new HEAD";
+
+	return NULL;
+}
+
+static const char *push_to_checkout_hook = "push-to-checkout";
+
+static const char *push_to_checkout(unsigned char *hash,
+				    int *invoked_hook,
+				    struct strvec *env,
+				    const char *work_tree)
+{
+	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+	opt.invoked_hook = invoked_hook;
+
+	strvec_pushf(env, "GIT_WORK_TREE=%s", absolute_path(work_tree));
+	strvec_pushv(&opt.env, env->v);
+	strvec_push(&opt.args, hash_to_hex(hash));
+	if (run_hooks_opt(the_repository, push_to_checkout_hook, &opt))
+		return "push-to-checkout hook declined";
+	else
+		return NULL;
+}
+
+static const char *update_worktree(unsigned char *sha1, const struct worktree *worktree)
+{
+	const char *retval, *git_dir;
+	struct strvec env = STRVEC_INIT;
+	int invoked_hook;
+
+	if (!worktree || !worktree->path)
+		BUG("worktree->path must be non-NULL");
+
+	if (worktree->is_bare)
+		return "denyCurrentBranch = updateInstead needs a worktree";
+	git_dir = get_worktree_git_dir(worktree);
+
+	strvec_pushf(&env, "GIT_DIR=%s", absolute_path(git_dir));
+
+	retval = push_to_checkout(sha1, &invoked_hook, &env, worktree->path);
+	if (!invoked_hook)
+		retval = push_to_deploy(sha1, &env, worktree->path);
+
+	strvec_clear(&env);
+	return retval;
+}
+
+static const char *update(struct command *cmd, struct shallow_info *si)
+{
+	const char *name = cmd->ref_name;
+	struct strbuf namespaced_name_buf = STRBUF_INIT;
+	static char *namespaced_name;
+	const char *ret;
+	struct object_id *old_oid = &cmd->old_oid;
+	struct object_id *new_oid = &cmd->new_oid;
+	int do_update_worktree = 0;
+	struct worktree **worktrees = get_worktrees();
+	const struct worktree *worktree =
+		find_shared_symref(worktrees, "HEAD", name);
+
+	/* only refs/... are allowed */
+	if (!starts_with(name, "refs/") ||
+	    check_refname_format(name + 5, is_null_oid(new_oid) ?
+				 REFNAME_ALLOW_ONELEVEL : 0)) {
+		rp_error("refusing to update funny ref '%s' remotely", name);
+		ret = "funny refname";
+		goto out;
+	}
+
+	strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+	free(namespaced_name);
+	namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
+
+	if (worktree && !worktree->is_bare) {
+		switch (deny_current_branch) {
+		case DENY_IGNORE:
+			break;
+		case DENY_WARN:
+			rp_warning("updating the current branch");
+			break;
+		case DENY_REFUSE:
+		case DENY_UNCONFIGURED:
+			rp_error("refusing to update checked out branch: %s", name);
+			if (deny_current_branch == DENY_UNCONFIGURED)
+				refuse_unconfigured_deny();
+			ret = "branch is currently checked out";
+			goto out;
+		case DENY_UPDATE_INSTEAD:
+			/* pass -- let other checks intervene first */
+			do_update_worktree = 1;
+			break;
+		}
+	}
+
+	if (!is_null_oid(new_oid) && !repo_has_object_file(the_repository, new_oid)) {
+		error("unpack should have generated %s, "
+		      "but I can't find it!", oid_to_hex(new_oid));
+		ret = "bad pack";
+		goto out;
+	}
+
+	if (!is_null_oid(old_oid) && is_null_oid(new_oid)) {
+		if (deny_deletes && starts_with(name, "refs/heads/")) {
+			rp_error("denying ref deletion for %s", name);
+			ret = "deletion prohibited";
+			goto out;
+		}
+
+		if (worktree || (head_name && !strcmp(namespaced_name, head_name))) {
+			switch (deny_delete_current) {
+			case DENY_IGNORE:
+				break;
+			case DENY_WARN:
+				rp_warning("deleting the current branch");
+				break;
+			case DENY_REFUSE:
+			case DENY_UNCONFIGURED:
+			case DENY_UPDATE_INSTEAD:
+				if (deny_delete_current == DENY_UNCONFIGURED)
+					refuse_unconfigured_deny_delete_current();
+				rp_error("refusing to delete the current branch: %s", name);
+				ret = "deletion of the current branch prohibited";
+				goto out;
+			default:
+				ret = "Invalid denyDeleteCurrent setting";
+				goto out;
+			}
+		}
+	}
+
+	if (deny_non_fast_forwards && !is_null_oid(new_oid) &&
+	    !is_null_oid(old_oid) &&
+	    starts_with(name, "refs/heads/")) {
+		struct object *old_object, *new_object;
+		struct commit *old_commit, *new_commit;
+		int ret2;
+
+		old_object = parse_object(the_repository, old_oid);
+		new_object = parse_object(the_repository, new_oid);
+
+		if (!old_object || !new_object ||
+		    old_object->type != OBJ_COMMIT ||
+		    new_object->type != OBJ_COMMIT) {
+			error("bad sha1 objects for %s", name);
+			ret = "bad ref";
+			goto out;
+		}
+		old_commit = (struct commit *)old_object;
+		new_commit = (struct commit *)new_object;
+		ret2 = repo_in_merge_bases(the_repository, old_commit, new_commit);
+		if (ret2 < 0)
+			exit(128);
+		if (!ret2) {
+			rp_error("denying non-fast-forward %s"
+				 " (you should pull first)", name);
+			ret = "non-fast-forward";
+			goto out;
+		}
+	}
+	if (run_update_hook(cmd)) {
+		rp_error("hook declined to update %s", name);
+		ret = "hook declined";
+		goto out;
+	}
+
+	if (do_update_worktree) {
+		ret = update_worktree(new_oid->hash, worktree);
+		if (ret)
+			goto out;
+	}
+
+	if (is_null_oid(new_oid)) {
+		struct strbuf err = STRBUF_INIT;
+		if (!parse_object(the_repository, old_oid)) {
+			old_oid = NULL;
+			if (refs_ref_exists(get_main_ref_store(the_repository), name)) {
+				rp_warning("allowing deletion of corrupt ref");
+			} else {
+				rp_warning("deleting a non-existent ref");
+				cmd->did_not_exist = 1;
+			}
+		}
+		if (ref_transaction_delete(transaction,
+					   namespaced_name,
+					   old_oid,
+					   NULL, 0,
+					   "push", &err)) {
+			rp_error("%s", err.buf);
+			ret = "failed to delete";
+		} else {
+			ret = NULL; /* good */
+		}
+		strbuf_release(&err);
+	}
+	else {
+		struct strbuf err = STRBUF_INIT;
+		if (shallow_update && si->shallow_ref[cmd->index] &&
+		    update_shallow_ref(cmd, si)) {
+			ret = "shallow error";
+			goto out;
+		}
+
+		if (ref_transaction_update(transaction,
+					   namespaced_name,
+					   new_oid, old_oid,
+					   NULL, NULL,
+					   0, "push",
+					   &err)) {
+			rp_error("%s", err.buf);
+			ret = "failed to update ref";
+		} else {
+			ret = NULL; /* good */
+		}
+		strbuf_release(&err);
+	}
+
+out:
+	free_worktrees(worktrees);
+	return ret;
+}
+
+static void run_update_post_hook(struct command *commands)
+{
+	struct command *cmd;
+	struct child_process proc = CHILD_PROCESS_INIT;
+	const char *hook;
+
+	hook = find_hook(the_repository, "post-update");
+	if (!hook)
+		return;
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (cmd->error_string || cmd->did_not_exist)
+			continue;
+		if (!proc.args.nr)
+			strvec_push(&proc.args, hook);
+		strvec_push(&proc.args, cmd->ref_name);
+	}
+	if (!proc.args.nr)
+		return;
+
+	proc.no_stdin = 1;
+	proc.stdout_to_stderr = 1;
+	proc.err = use_sideband ? -1 : 0;
+	proc.trace2_hook_name = "post-update";
+
+	if (!start_command(&proc)) {
+		if (use_sideband)
+			copy_to_sideband(proc.err, -1, NULL);
+		finish_command(&proc);
+	}
+}
+
+static void check_aliased_update_internal(struct command *cmd,
+					  struct string_list *list,
+					  const char *dst_name, int flag)
+{
+	struct string_list_item *item;
+	struct command *dst_cmd;
+
+	if (!(flag & REF_ISSYMREF))
+		return;
+
+	if (!dst_name) {
+		rp_error("refusing update to broken symref '%s'", cmd->ref_name);
+		cmd->skip_update = 1;
+		cmd->error_string = "broken symref";
+		return;
+	}
+	dst_name = strip_namespace(dst_name);
+
+	if (!(item = string_list_lookup(list, dst_name)))
+		return;
+
+	cmd->skip_update = 1;
+
+	dst_cmd = (struct command *) item->util;
+
+	if (oideq(&cmd->old_oid, &dst_cmd->old_oid) &&
+	    oideq(&cmd->new_oid, &dst_cmd->new_oid))
+		return;
+
+	dst_cmd->skip_update = 1;
+
+	rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
+		 " its target '%s' (%s..%s)",
+		 cmd->ref_name,
+		 repo_find_unique_abbrev(the_repository, &cmd->old_oid, DEFAULT_ABBREV),
+		 repo_find_unique_abbrev(the_repository, &cmd->new_oid, DEFAULT_ABBREV),
+		 dst_cmd->ref_name,
+		 repo_find_unique_abbrev(the_repository, &dst_cmd->old_oid, DEFAULT_ABBREV),
+		 repo_find_unique_abbrev(the_repository, &dst_cmd->new_oid, DEFAULT_ABBREV));
+
+	cmd->error_string = dst_cmd->error_string =
+		"inconsistent aliased update";
+}
+
+static void check_aliased_update(struct command *cmd, struct string_list *list)
+{
+	struct strbuf buf = STRBUF_INIT;
+	const char *dst_name;
+	int flag;
+
+	strbuf_addf(&buf, "%s%s", get_git_namespace(), cmd->ref_name);
+	dst_name = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+					   buf.buf, 0, NULL, &flag);
+	check_aliased_update_internal(cmd, list, dst_name, flag);
+	strbuf_release(&buf);
+}
+
+static void check_aliased_updates(struct command *commands)
+{
+	struct command *cmd;
+	struct string_list ref_list = STRING_LIST_INIT_NODUP;
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		struct string_list_item *item =
+			string_list_append(&ref_list, cmd->ref_name);
+		item->util = (void *)cmd;
+	}
+	string_list_sort(&ref_list);
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (!cmd->error_string)
+			check_aliased_update(cmd, &ref_list);
+	}
+
+	string_list_clear(&ref_list, 0);
+}
+
+static const struct object_id *command_singleton_iterator(void *cb_data)
+{
+	struct command **cmd_list = cb_data;
+	struct command *cmd = *cmd_list;
+
+	if (!cmd || is_null_oid(&cmd->new_oid))
+		return NULL;
+	*cmd_list = NULL; /* this returns only one */
+	return &cmd->new_oid;
+}
+
+static void set_connectivity_errors(struct command *commands,
+				    struct shallow_info *si)
+{
+	struct command *cmd;
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		struct command *singleton = cmd;
+		struct check_connected_options opt = CHECK_CONNECTED_INIT;
+
+		if (shallow_update && si->shallow_ref[cmd->index])
+			/* to be checked in update_shallow_ref() */
+			continue;
+
+		opt.env = tmp_objdir_env(tmp_objdir);
+		if (!check_connected(command_singleton_iterator, &singleton,
+				     &opt))
+			continue;
+
+		cmd->error_string = "missing necessary objects";
+	}
+}
+
+struct iterate_data {
+	struct command *cmds;
+	struct shallow_info *si;
+};
+
+static const struct object_id *iterate_receive_command_list(void *cb_data)
+{
+	struct iterate_data *data = cb_data;
+	struct command **cmd_list = &data->cmds;
+	struct command *cmd = *cmd_list;
+
+	for (; cmd; cmd = cmd->next) {
+		if (shallow_update && data->si->shallow_ref[cmd->index])
+			/* to be checked in update_shallow_ref() */
+			continue;
+		if (!is_null_oid(&cmd->new_oid) && !cmd->skip_update) {
+			*cmd_list = cmd->next;
+			return &cmd->new_oid;
+		}
+	}
+	return NULL;
+}
+
+static void reject_updates_to_hidden(struct command *commands)
+{
+	struct strbuf refname_full = STRBUF_INIT;
+	size_t prefix_len;
+	struct command *cmd;
+
+	strbuf_addstr(&refname_full, get_git_namespace());
+	prefix_len = refname_full.len;
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (cmd->error_string)
+			continue;
+
+		strbuf_setlen(&refname_full, prefix_len);
+		strbuf_addstr(&refname_full, cmd->ref_name);
+
+		if (!ref_is_hidden(cmd->ref_name, refname_full.buf, &hidden_refs))
+			continue;
+		if (is_null_oid(&cmd->new_oid))
+			cmd->error_string = "deny deleting a hidden ref";
+		else
+			cmd->error_string = "deny updating a hidden ref";
+	}
+
+	strbuf_release(&refname_full);
+}
+
+static int should_process_cmd(struct command *cmd)
+{
+	return !cmd->error_string && !cmd->skip_update;
+}
+
+static void BUG_if_skipped_connectivity_check(struct command *commands,
+					       struct shallow_info *si)
+{
+	struct command *cmd;
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (should_process_cmd(cmd) && si->shallow_ref[cmd->index])
+			bug("connectivity check has not been run on ref %s",
+			    cmd->ref_name);
+	}
+	BUG_if_bug("connectivity check skipped???");
+}
+
+static void execute_commands_non_atomic(struct command *commands,
+					struct shallow_info *si)
+{
+	struct command *cmd;
+	struct strbuf err = STRBUF_INIT;
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (!should_process_cmd(cmd) || cmd->run_proc_receive)
+			continue;
+
+		transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+							  0, &err);
+		if (!transaction) {
+			rp_error("%s", err.buf);
+			strbuf_reset(&err);
+			cmd->error_string = "transaction failed to start";
+			continue;
+		}
+
+		cmd->error_string = update(cmd, si);
+
+		if (!cmd->error_string
+		    && ref_transaction_commit(transaction, &err)) {
+			rp_error("%s", err.buf);
+			strbuf_reset(&err);
+			cmd->error_string = "failed to update ref";
+		}
+		ref_transaction_free(transaction);
+	}
+	strbuf_release(&err);
+}
+
+static void execute_commands_atomic(struct command *commands,
+					struct shallow_info *si)
+{
+	struct command *cmd;
+	struct strbuf err = STRBUF_INIT;
+	const char *reported_error = "atomic push failure";
+
+	transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+						  0, &err);
+	if (!transaction) {
+		rp_error("%s", err.buf);
+		strbuf_reset(&err);
+		reported_error = "transaction failed to start";
+		goto failure;
+	}
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (!should_process_cmd(cmd) || cmd->run_proc_receive)
+			continue;
+
+		cmd->error_string = update(cmd, si);
+
+		if (cmd->error_string)
+			goto failure;
+	}
+
+	if (ref_transaction_commit(transaction, &err)) {
+		rp_error("%s", err.buf);
+		reported_error = "atomic transaction failed";
+		goto failure;
+	}
+	goto cleanup;
+
+failure:
+	for (cmd = commands; cmd; cmd = cmd->next)
+		if (!cmd->error_string)
+			cmd->error_string = reported_error;
+
+cleanup:
+	ref_transaction_free(transaction);
+	strbuf_release(&err);
+}
+
+static void execute_commands(struct command *commands,
+			     const char *unpacker_error,
+			     struct shallow_info *si,
+			     const struct string_list *push_options)
+{
+	struct check_connected_options opt = CHECK_CONNECTED_INIT;
+	struct command *cmd;
+	struct iterate_data data;
+	struct async muxer;
+	int err_fd = 0;
+	int run_proc_receive = 0;
+
+	if (unpacker_error) {
+		for (cmd = commands; cmd; cmd = cmd->next)
+			cmd->error_string = "unpacker error";
+		return;
+	}
+
+	if (use_sideband) {
+		memset(&muxer, 0, sizeof(muxer));
+		muxer.proc = copy_to_sideband;
+		muxer.in = -1;
+		if (!start_async(&muxer))
+			err_fd = muxer.in;
+		/* ...else, continue without relaying sideband */
+	}
+
+	data.cmds = commands;
+	data.si = si;
+	opt.err_fd = err_fd;
+	opt.progress = err_fd && !quiet;
+	opt.env = tmp_objdir_env(tmp_objdir);
+	opt.exclude_hidden_refs_section = "receive";
+
+	if (check_connected(iterate_receive_command_list, &data, &opt))
+		set_connectivity_errors(commands, si);
+
+	if (use_sideband)
+		finish_async(&muxer);
+
+	reject_updates_to_hidden(commands);
+
+	/*
+	 * Try to find commands that have special prefix in their reference names,
+	 * and mark them to run an external "proc-receive" hook later.
+	 */
+	if (proc_receive_ref) {
+		for (cmd = commands; cmd; cmd = cmd->next) {
+			if (!should_process_cmd(cmd))
+				continue;
+
+			if (proc_receive_ref_matches(cmd)) {
+				cmd->run_proc_receive = RUN_PROC_RECEIVE_SCHEDULED;
+				run_proc_receive = 1;
+			}
+		}
+	}
+
+	if (run_receive_hook(commands, "pre-receive", 0, push_options)) {
+		for (cmd = commands; cmd; cmd = cmd->next) {
+			if (!cmd->error_string)
+				cmd->error_string = "pre-receive hook declined";
+		}
+		return;
+	}
+
+	/*
+	 * If there is no command ready to run, should return directly to destroy
+	 * temporary data in the quarantine area.
+	 */
+	for (cmd = commands; cmd && cmd->error_string; cmd = cmd->next)
+		; /* nothing */
+	if (!cmd)
+		return;
+
+	/*
+	 * Now we'll start writing out refs, which means the objects need
+	 * to be in their final positions so that other processes can see them.
+	 */
+	if (tmp_objdir_migrate(tmp_objdir) < 0) {
+		for (cmd = commands; cmd; cmd = cmd->next) {
+			if (!cmd->error_string)
+				cmd->error_string = "unable to migrate objects to permanent storage";
+		}
+		return;
+	}
+	tmp_objdir = NULL;
+
+	check_aliased_updates(commands);
+
+	free(head_name_to_free);
+	head_name = head_name_to_free = refs_resolve_refdup(get_main_ref_store(the_repository),
+							    "HEAD", 0, NULL,
+							    NULL);
+
+	if (run_proc_receive &&
+	    run_proc_receive_hook(commands, push_options))
+		for (cmd = commands; cmd; cmd = cmd->next)
+			if (!cmd->error_string &&
+			    !(cmd->run_proc_receive & RUN_PROC_RECEIVE_RETURNED) &&
+			    (cmd->run_proc_receive || use_atomic))
+				cmd->error_string = "fail to run proc-receive hook";
+
+	if (use_atomic)
+		execute_commands_atomic(commands, si);
+	else
+		execute_commands_non_atomic(commands, si);
+
+	if (shallow_update)
+		BUG_if_skipped_connectivity_check(commands, si);
+}
+
+static struct command **queue_command(struct command **tail,
+				      const char *line,
+				      int linelen)
+{
+	struct object_id old_oid, new_oid;
+	struct command *cmd;
+	const char *refname;
+	int reflen;
+	const char *p;
+
+	if (parse_oid_hex(line, &old_oid, &p) ||
+	    *p++ != ' ' ||
+	    parse_oid_hex(p, &new_oid, &p) ||
+	    *p++ != ' ')
+		die("protocol error: expected old/new/ref, got '%s'", line);
+
+	refname = p;
+	reflen = linelen - (p - line);
+	FLEX_ALLOC_MEM(cmd, ref_name, refname, reflen);
+	oidcpy(&cmd->old_oid, &old_oid);
+	oidcpy(&cmd->new_oid, &new_oid);
+	*tail = cmd;
+	return &cmd->next;
+}
+
+static void free_commands(struct command *commands)
+{
+	while (commands) {
+		struct command *next = commands->next;
+
+		ref_push_report_free(commands->report);
+		free(commands->error_string_owned);
+		free(commands);
+		commands = next;
+	}
+}
+
+static void queue_commands_from_cert(struct command **tail,
+				     struct strbuf *push_cert)
+{
+	const char *boc, *eoc;
+
+	if (*tail)
+		die("protocol error: got both push certificate and unsigned commands");
+
+	boc = strstr(push_cert->buf, "\n\n");
+	if (!boc)
+		die("malformed push certificate %.*s", 100, push_cert->buf);
+	else
+		boc += 2;
+	eoc = push_cert->buf + parse_signed_buffer(push_cert->buf, push_cert->len);
+
+	while (boc < eoc) {
+		const char *eol = memchr(boc, '\n', eoc - boc);
+		tail = queue_command(tail, boc, eol ? eol - boc : eoc - boc);
+		boc = eol ? eol + 1 : eoc;
+	}
+}
+
+static struct command *read_head_info(struct packet_reader *reader,
+				      struct oid_array *shallow)
+{
+	struct command *commands = NULL;
+	struct command **p = &commands;
+	for (;;) {
+		int linelen;
+
+		if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+			break;
+
+		if (reader->pktlen > 8 && starts_with(reader->line, "shallow ")) {
+			struct object_id oid;
+			if (get_oid_hex(reader->line + 8, &oid))
+				die("protocol error: expected shallow sha, got '%s'",
+				    reader->line + 8);
+			oid_array_append(shallow, &oid);
+			continue;
+		}
+
+		linelen = strlen(reader->line);
+		if (linelen < reader->pktlen) {
+			const char *feature_list = reader->line + linelen + 1;
+			const char *hash = NULL;
+			const char *client_sid;
+			size_t len = 0;
+			if (parse_feature_request(feature_list, "report-status"))
+				report_status = 1;
+			if (parse_feature_request(feature_list, "report-status-v2"))
+				report_status_v2 = 1;
+			if (parse_feature_request(feature_list, "side-band-64k"))
+				use_sideband = LARGE_PACKET_MAX;
+			if (parse_feature_request(feature_list, "quiet"))
+				quiet = 1;
+			if (advertise_atomic_push
+			    && parse_feature_request(feature_list, "atomic"))
+				use_atomic = 1;
+			if (advertise_push_options
+			    && parse_feature_request(feature_list, "push-options"))
+				use_push_options = 1;
+			hash = parse_feature_value(feature_list, "object-format", &len, NULL);
+			if (!hash) {
+				hash = hash_algos[GIT_HASH_SHA1].name;
+				len = strlen(hash);
+			}
+			if (xstrncmpz(the_hash_algo->name, hash, len))
+				die("error: unsupported object format '%s'", hash);
+			client_sid = parse_feature_value(feature_list, "session-id", &len, NULL);
+			if (client_sid) {
+				char *sid = xstrndup(client_sid, len);
+				trace2_data_string("transfer", NULL, "client-sid", client_sid);
+				free(sid);
+			}
+		}
+
+		if (!strcmp(reader->line, "push-cert")) {
+			int true_flush = 0;
+			int saved_options = reader->options;
+			reader->options &= ~PACKET_READ_CHOMP_NEWLINE;
+
+			for (;;) {
+				packet_reader_read(reader);
+				if (reader->status == PACKET_READ_FLUSH) {
+					true_flush = 1;
+					break;
+				}
+				if (reader->status != PACKET_READ_NORMAL) {
+					die("protocol error: got an unexpected packet");
+				}
+				if (!strcmp(reader->line, "push-cert-end\n"))
+					break; /* end of cert */
+				strbuf_addstr(&push_cert, reader->line);
+			}
+			reader->options = saved_options;
+
+			if (true_flush)
+				break;
+			continue;
+		}
+
+		p = queue_command(p, reader->line, linelen);
+	}
+
+	if (push_cert.len)
+		queue_commands_from_cert(p, &push_cert);
+
+	return commands;
+}
+
+static void read_push_options(struct packet_reader *reader,
+			      struct string_list *options)
+{
+	while (1) {
+		if (packet_reader_read(reader) != PACKET_READ_NORMAL)
+			break;
+
+		string_list_append(options, reader->line);
+	}
+}
+
+static const char *parse_pack_header(struct pack_header *hdr)
+{
+	switch (read_pack_header(0, hdr)) {
+	case PH_ERROR_EOF:
+		return "eof before pack header was fully read";
+
+	case PH_ERROR_PACK_SIGNATURE:
+		return "protocol error (pack signature mismatch detected)";
+
+	case PH_ERROR_PROTOCOL:
+		return "protocol error (pack version unsupported)";
+
+	default:
+		return "unknown error in parse_pack_header";
+
+	case 0:
+		return NULL;
+	}
+}
+
+static struct tempfile *pack_lockfile;
+
+static void push_header_arg(struct strvec *args, struct pack_header *hdr)
+{
+	strvec_pushf(args, "--pack_header=%"PRIu32",%"PRIu32,
+		     ntohl(hdr->hdr_version), ntohl(hdr->hdr_entries));
+}
+
+static const char *unpack(int err_fd, struct shallow_info *si)
+{
+	struct pack_header hdr;
+	const char *hdr_err;
+	int status;
+	struct child_process child = CHILD_PROCESS_INIT;
+	int fsck_objects = (receive_fsck_objects >= 0
+			    ? receive_fsck_objects
+			    : transfer_fsck_objects >= 0
+			    ? transfer_fsck_objects
+			    : 0);
+
+	hdr_err = parse_pack_header(&hdr);
+	if (hdr_err) {
+		if (err_fd > 0)
+			close(err_fd);
+		return hdr_err;
+	}
+
+	if (si->nr_ours || si->nr_theirs) {
+		alt_shallow_file = setup_temporary_shallow(si->shallow);
+		strvec_push(&child.args, "--shallow-file");
+		strvec_push(&child.args, alt_shallow_file);
+	}
+
+	tmp_objdir = tmp_objdir_create(the_repository, "incoming");
+	if (!tmp_objdir) {
+		if (err_fd > 0)
+			close(err_fd);
+		return "unable to create temporary object directory";
+	}
+	strvec_pushv(&child.env, tmp_objdir_env(tmp_objdir));
+
+	/*
+	 * Normally we just pass the tmp_objdir environment to the child
+	 * processes that do the heavy lifting, but we may need to see these
+	 * objects ourselves to set up shallow information.
+	 */
+	tmp_objdir_add_as_alternate(tmp_objdir);
+
+	if (ntohl(hdr.hdr_entries) < unpack_limit) {
+		strvec_push(&child.args, "unpack-objects");
+		push_header_arg(&child.args, &hdr);
+		if (quiet)
+			strvec_push(&child.args, "-q");
+		if (fsck_objects)
+			strvec_pushf(&child.args, "--strict%s",
+				     fsck_msg_types.buf);
+		if (max_input_size)
+			strvec_pushf(&child.args, "--max-input-size=%"PRIuMAX,
+				     (uintmax_t)max_input_size);
+		child.no_stdout = 1;
+		child.err = err_fd;
+		child.git_cmd = 1;
+		status = run_command(&child);
+		if (status)
+			return "unpack-objects abnormal exit";
+	} else {
+		char hostname[HOST_NAME_MAX + 1];
+		char *lockfile;
+
+		strvec_pushl(&child.args, "index-pack", "--stdin", NULL);
+		push_header_arg(&child.args, &hdr);
+
+		if (xgethostname(hostname, sizeof(hostname)))
+			xsnprintf(hostname, sizeof(hostname), "localhost");
+		strvec_pushf(&child.args,
+			     "--keep=receive-pack %"PRIuMAX" on %s",
+			     (uintmax_t)getpid(),
+			     hostname);
+
+		if (!quiet && err_fd)
+			strvec_push(&child.args, "--show-resolving-progress");
+		if (use_sideband)
+			strvec_push(&child.args, "--report-end-of-input");
+		if (fsck_objects)
+			strvec_pushf(&child.args, "--strict%s",
+				     fsck_msg_types.buf);
+		if (!reject_thin)
+			strvec_push(&child.args, "--fix-thin");
+		if (max_input_size)
+			strvec_pushf(&child.args, "--max-input-size=%"PRIuMAX,
+				     (uintmax_t)max_input_size);
+		child.out = -1;
+		child.err = err_fd;
+		child.git_cmd = 1;
+		status = start_command(&child);
+		if (status)
+			return "index-pack fork failed";
+
+		lockfile = index_pack_lockfile(child.out, NULL);
+		if (lockfile) {
+			pack_lockfile = register_tempfile(lockfile);
+			free(lockfile);
+		}
+		close(child.out);
+
+		status = finish_command(&child);
+		if (status)
+			return "index-pack abnormal exit";
+		reprepare_packed_git(the_repository);
+	}
+	return NULL;
+}
+
+static const char *unpack_with_sideband(struct shallow_info *si)
+{
+	struct async muxer;
+	const char *ret;
+
+	if (!use_sideband)
+		return unpack(0, si);
+
+	use_keepalive = KEEPALIVE_AFTER_NUL;
+	memset(&muxer, 0, sizeof(muxer));
+	muxer.proc = copy_to_sideband;
+	muxer.in = -1;
+	if (start_async(&muxer))
+		return NULL;
+
+	ret = unpack(muxer.in, si);
+
+	finish_async(&muxer);
+	return ret;
+}
+
+static void prepare_shallow_update(struct shallow_info *si)
+{
+	int i, j, k, bitmap_size = DIV_ROUND_UP(si->ref->nr, 32);
+
+	ALLOC_ARRAY(si->used_shallow, si->shallow->nr);
+	assign_shallow_commits_to_refs(si, si->used_shallow, NULL);
+
+	CALLOC_ARRAY(si->need_reachability_test, si->shallow->nr);
+	CALLOC_ARRAY(si->reachable, si->shallow->nr);
+	CALLOC_ARRAY(si->shallow_ref, si->ref->nr);
+
+	for (i = 0; i < si->nr_ours; i++)
+		si->need_reachability_test[si->ours[i]] = 1;
+
+	for (i = 0; i < si->shallow->nr; i++) {
+		if (!si->used_shallow[i])
+			continue;
+		for (j = 0; j < bitmap_size; j++) {
+			if (!si->used_shallow[i][j])
+				continue;
+			si->need_reachability_test[i]++;
+			for (k = 0; k < 32; k++)
+				if (si->used_shallow[i][j] & (1U << k))
+					si->shallow_ref[j * 32 + k]++;
+		}
+
+		/*
+		 * true for those associated with some refs and belong
+		 * in "ours" list aka "step 7 not done yet"
+		 */
+		si->need_reachability_test[i] =
+			si->need_reachability_test[i] > 1;
+	}
+
+	/*
+	 * keep hooks happy by forcing a temporary shallow file via
+	 * env variable because we can't add --shallow-file to every
+	 * command. check_connected() will be done with
+	 * true .git/shallow though.
+	 */
+	setenv(GIT_SHALLOW_FILE_ENVIRONMENT, alt_shallow_file, 1);
+}
+
+static void update_shallow_info(struct command *commands,
+				struct shallow_info *si,
+				struct oid_array *ref)
+{
+	struct command *cmd;
+	int *ref_status;
+	remove_nonexistent_theirs_shallow(si);
+	if (!si->nr_ours && !si->nr_theirs) {
+		shallow_update = 0;
+		return;
+	}
+
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (is_null_oid(&cmd->new_oid))
+			continue;
+		oid_array_append(ref, &cmd->new_oid);
+		cmd->index = ref->nr - 1;
+	}
+	si->ref = ref;
+
+	if (shallow_update) {
+		prepare_shallow_update(si);
+		return;
+	}
+
+	ALLOC_ARRAY(ref_status, ref->nr);
+	assign_shallow_commits_to_refs(si, NULL, ref_status);
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (is_null_oid(&cmd->new_oid))
+			continue;
+		if (ref_status[cmd->index]) {
+			cmd->error_string = "shallow update not allowed";
+			cmd->skip_update = 1;
+		}
+	}
+	free(ref_status);
+}
+
+static void report(struct command *commands, const char *unpack_status)
+{
+	struct command *cmd;
+	struct strbuf buf = STRBUF_INIT;
+
+	packet_buf_write(&buf, "unpack %s\n",
+			 unpack_status ? unpack_status : "ok");
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (!cmd->error_string)
+			packet_buf_write(&buf, "ok %s\n",
+					 cmd->ref_name);
+		else
+			packet_buf_write(&buf, "ng %s %s\n",
+					 cmd->ref_name, cmd->error_string);
+	}
+	packet_buf_flush(&buf);
+
+	if (use_sideband)
+		send_sideband(1, 1, buf.buf, buf.len, use_sideband);
+	else
+		write_or_die(1, buf.buf, buf.len);
+	strbuf_release(&buf);
+}
+
+static void report_v2(struct command *commands, const char *unpack_status)
+{
+	struct command *cmd;
+	struct strbuf buf = STRBUF_INIT;
+	struct ref_push_report *report;
+
+	packet_buf_write(&buf, "unpack %s\n",
+			 unpack_status ? unpack_status : "ok");
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		int count = 0;
+
+		if (cmd->error_string) {
+			packet_buf_write(&buf, "ng %s %s\n",
+					 cmd->ref_name,
+					 cmd->error_string);
+			continue;
+		}
+		packet_buf_write(&buf, "ok %s\n",
+				 cmd->ref_name);
+		for (report = cmd->report; report; report = report->next) {
+			if (count++ > 0)
+				packet_buf_write(&buf, "ok %s\n",
+						 cmd->ref_name);
+			if (report->ref_name)
+				packet_buf_write(&buf, "option refname %s\n",
+						 report->ref_name);
+			if (report->old_oid)
+				packet_buf_write(&buf, "option old-oid %s\n",
+						 oid_to_hex(report->old_oid));
+			if (report->new_oid)
+				packet_buf_write(&buf, "option new-oid %s\n",
+						 oid_to_hex(report->new_oid));
+			if (report->forced_update)
+				packet_buf_write(&buf, "option forced-update\n");
+		}
+	}
+	packet_buf_flush(&buf);
+
+	if (use_sideband)
+		send_sideband(1, 1, buf.buf, buf.len, use_sideband);
+	else
+		write_or_die(1, buf.buf, buf.len);
+	strbuf_release(&buf);
+}
+
+static int delete_only(struct command *commands)
+{
+	struct command *cmd;
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (!is_null_oid(&cmd->new_oid))
+			return 0;
+	}
+	return 1;
+}
+
+int cmd_receive_pack(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	int advertise_refs = 0;
+	struct command *commands;
+	struct oid_array shallow = OID_ARRAY_INIT;
+	struct oid_array ref = OID_ARRAY_INIT;
+	struct shallow_info si;
+	struct packet_reader reader;
+
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("quiet")),
+		OPT_HIDDEN_BOOL(0, "stateless-rpc", &stateless_rpc, NULL),
+		OPT_HIDDEN_BOOL(0, "http-backend-info-refs", &advertise_refs, NULL),
+		OPT_ALIAS(0, "advertise-refs", "http-backend-info-refs"),
+		OPT_HIDDEN_BOOL(0, "reject-thin-pack-for-testing", &reject_thin, NULL),
+		OPT_END()
+	};
+
+	packet_trace_identity("receive-pack");
+
+	argc = parse_options(argc, argv, prefix, options, receive_pack_usage, 0);
+
+	if (argc > 1)
+		usage_msg_opt(_("too many arguments"), receive_pack_usage, options);
+	if (argc == 0)
+		usage_msg_opt(_("you must specify a directory"), receive_pack_usage, options);
+
+	service_dir = argv[0];
+
+	setup_path();
+
+	if (!enter_repo(service_dir, 0))
+		die("'%s' does not appear to be a git repository", service_dir);
+
+	git_config(receive_pack_config, NULL);
+	if (cert_nonce_seed)
+		push_cert_nonce = prepare_push_cert_nonce(service_dir, time(NULL));
+
+	if (0 <= receive_unpack_limit)
+		unpack_limit = receive_unpack_limit;
+	else if (0 <= transfer_unpack_limit)
+		unpack_limit = transfer_unpack_limit;
+
+	switch (determine_protocol_version_server()) {
+	case protocol_v2:
+		/*
+		 * push support for protocol v2 has not been implemented yet,
+		 * so ignore the request to use v2 and fallback to using v0.
+		 */
+		break;
+	case protocol_v1:
+		/*
+		 * v1 is just the original protocol with a version string,
+		 * so just fall through after writing the version string.
+		 */
+		if (advertise_refs || !stateless_rpc)
+			packet_write_fmt(1, "version 1\n");
+
+		/* fallthrough */
+	case protocol_v0:
+		break;
+	case protocol_unknown_version:
+		BUG("unknown protocol version");
+	}
+
+	if (advertise_refs || !stateless_rpc) {
+		write_head_info();
+	}
+	if (advertise_refs)
+		return 0;
+
+	packet_reader_init(&reader, 0, NULL, 0,
+			   PACKET_READ_CHOMP_NEWLINE |
+			   PACKET_READ_DIE_ON_ERR_PACKET);
+
+	if ((commands = read_head_info(&reader, &shallow))) {
+		const char *unpack_status = NULL;
+		struct string_list push_options = STRING_LIST_INIT_DUP;
+
+		if (use_push_options)
+			read_push_options(&reader, &push_options);
+		if (!check_cert_push_options(&push_options)) {
+			struct command *cmd;
+			for (cmd = commands; cmd; cmd = cmd->next)
+				cmd->error_string = "inconsistent push options";
+		}
+
+		prepare_shallow_info(&si, &shallow);
+		if (!si.nr_ours && !si.nr_theirs)
+			shallow_update = 0;
+		if (!delete_only(commands)) {
+			unpack_status = unpack_with_sideband(&si);
+			update_shallow_info(commands, &si, &ref);
+		}
+		use_keepalive = KEEPALIVE_ALWAYS;
+		execute_commands(commands, unpack_status, &si,
+				 &push_options);
+		delete_tempfile(&pack_lockfile);
+		sigchain_push(SIGPIPE, SIG_IGN);
+		if (report_status_v2)
+			report_v2(commands, unpack_status);
+		else if (report_status)
+			report(commands, unpack_status);
+		sigchain_pop(SIGPIPE);
+		run_receive_hook(commands, "post-receive", 1,
+				 &push_options);
+		run_update_post_hook(commands);
+		free_commands(commands);
+		string_list_clear(&push_options, 0);
+		if (auto_gc) {
+			struct child_process proc = CHILD_PROCESS_INIT;
+
+			if (prepare_auto_maintenance(1, &proc)) {
+				proc.no_stdin = 1;
+				proc.stdout_to_stderr = 1;
+				proc.err = use_sideband ? -1 : 0;
+
+				if (!start_command(&proc)) {
+					if (use_sideband)
+						copy_to_sideband(proc.err, -1, NULL);
+					finish_command(&proc);
+				}
+			}
+		}
+		if (auto_update_server_info)
+			update_server_info(the_repository, 0);
+		clear_shallow_info(&si);
+	}
+	if (use_sideband)
+		packet_flush(1);
+	oid_array_clear(&shallow);
+	oid_array_clear(&ref);
+	strvec_clear(&hidden_refs);
+	free((void *)push_cert_nonce);
+	return 0;
+}
diff --git a/builtin/reflog.c b/builtin/reflog.c
new file mode 100644
index 0000000000..95f264989b
--- /dev/null
+++ b/builtin/reflog.c
@@ -0,0 +1,479 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "revision.h"
+#include "reachable.h"
+#include "wildmatch.h"
+#include "worktree.h"
+#include "reflog.h"
+#include "refs.h"
+#include "parse-options.h"
+
+#define BUILTIN_REFLOG_SHOW_USAGE \
+	N_("git reflog [show] [<log-options>] [<ref>]")
+
+#define BUILTIN_REFLOG_LIST_USAGE \
+	N_("git reflog list")
+
+#define BUILTIN_REFLOG_EXPIRE_USAGE \
+	N_("git reflog expire [--expire=<time>] [--expire-unreachable=<time>]\n" \
+	   "                  [--rewrite] [--updateref] [--stale-fix]\n" \
+	   "                  [--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>...]")
+
+#define BUILTIN_REFLOG_DELETE_USAGE \
+	N_("git reflog delete [--rewrite] [--updateref]\n" \
+	   "                  [--dry-run | -n] [--verbose] <ref>@{<specifier>}...")
+
+#define BUILTIN_REFLOG_EXISTS_USAGE \
+	N_("git reflog exists <ref>")
+
+static const char *const reflog_show_usage[] = {
+	BUILTIN_REFLOG_SHOW_USAGE,
+	NULL,
+};
+
+static const char *const reflog_list_usage[] = {
+	BUILTIN_REFLOG_LIST_USAGE,
+	NULL,
+};
+
+static const char *const reflog_expire_usage[] = {
+	BUILTIN_REFLOG_EXPIRE_USAGE,
+	NULL
+};
+
+static const char *const reflog_delete_usage[] = {
+	BUILTIN_REFLOG_DELETE_USAGE,
+	NULL
+};
+
+static const char *const reflog_exists_usage[] = {
+	BUILTIN_REFLOG_EXISTS_USAGE,
+	NULL,
+};
+
+static const char *const reflog_usage[] = {
+	BUILTIN_REFLOG_SHOW_USAGE,
+	BUILTIN_REFLOG_LIST_USAGE,
+	BUILTIN_REFLOG_EXPIRE_USAGE,
+	BUILTIN_REFLOG_DELETE_USAGE,
+	BUILTIN_REFLOG_EXISTS_USAGE,
+	NULL
+};
+
+static timestamp_t default_reflog_expire;
+static timestamp_t default_reflog_expire_unreachable;
+
+struct worktree_reflogs {
+	struct worktree *worktree;
+	struct string_list reflogs;
+};
+
+static int collect_reflog(const char *ref, void *cb_data)
+{
+	struct worktree_reflogs *cb = cb_data;
+	struct worktree *worktree = cb->worktree;
+	struct strbuf newref = STRBUF_INIT;
+
+	/*
+	 * Avoid collecting the same shared ref multiple times because
+	 * they are available via all worktrees.
+	 */
+	if (!worktree->is_current &&
+	    parse_worktree_ref(ref, NULL, NULL, NULL) == REF_WORKTREE_SHARED)
+		return 0;
+
+	strbuf_worktree_ref(worktree, &newref, ref);
+	string_list_append_nodup(&cb->reflogs, strbuf_detach(&newref, NULL));
+
+	return 0;
+}
+
+static struct reflog_expire_cfg {
+	struct reflog_expire_cfg *next;
+	timestamp_t expire_total;
+	timestamp_t expire_unreachable;
+	char pattern[FLEX_ARRAY];
+} *reflog_expire_cfg, **reflog_expire_cfg_tail;
+
+static struct reflog_expire_cfg *find_cfg_ent(const char *pattern, size_t len)
+{
+	struct reflog_expire_cfg *ent;
+
+	if (!reflog_expire_cfg_tail)
+		reflog_expire_cfg_tail = &reflog_expire_cfg;
+
+	for (ent = reflog_expire_cfg; ent; ent = ent->next)
+		if (!xstrncmpz(ent->pattern, pattern, len))
+			return ent;
+
+	FLEX_ALLOC_MEM(ent, pattern, pattern, len);
+	*reflog_expire_cfg_tail = ent;
+	reflog_expire_cfg_tail = &(ent->next);
+	return ent;
+}
+
+/* expiry timer slot */
+#define EXPIRE_TOTAL   01
+#define EXPIRE_UNREACH 02
+
+static int reflog_expire_config(const char *var, const char *value,
+				const struct config_context *ctx, void *cb)
+{
+	const char *pattern, *key;
+	size_t pattern_len;
+	timestamp_t expire;
+	int slot;
+	struct reflog_expire_cfg *ent;
+
+	if (parse_config_key(var, "gc", &pattern, &pattern_len, &key) < 0)
+		return git_default_config(var, value, ctx, cb);
+
+	if (!strcmp(key, "reflogexpire")) {
+		slot = EXPIRE_TOTAL;
+		if (git_config_expiry_date(&expire, var, value))
+			return -1;
+	} else if (!strcmp(key, "reflogexpireunreachable")) {
+		slot = EXPIRE_UNREACH;
+		if (git_config_expiry_date(&expire, var, value))
+			return -1;
+	} else
+		return git_default_config(var, value, ctx, cb);
+
+	if (!pattern) {
+		switch (slot) {
+		case EXPIRE_TOTAL:
+			default_reflog_expire = expire;
+			break;
+		case EXPIRE_UNREACH:
+			default_reflog_expire_unreachable = expire;
+			break;
+		}
+		return 0;
+	}
+
+	ent = find_cfg_ent(pattern, pattern_len);
+	if (!ent)
+		return -1;
+	switch (slot) {
+	case EXPIRE_TOTAL:
+		ent->expire_total = expire;
+		break;
+	case EXPIRE_UNREACH:
+		ent->expire_unreachable = expire;
+		break;
+	}
+	return 0;
+}
+
+static void set_reflog_expiry_param(struct cmd_reflog_expire_cb *cb, const char *ref)
+{
+	struct reflog_expire_cfg *ent;
+
+	if (cb->explicit_expiry == (EXPIRE_TOTAL|EXPIRE_UNREACH))
+		return; /* both given explicitly -- nothing to tweak */
+
+	for (ent = reflog_expire_cfg; ent; ent = ent->next) {
+		if (!wildmatch(ent->pattern, ref, 0)) {
+			if (!(cb->explicit_expiry & EXPIRE_TOTAL))
+				cb->expire_total = ent->expire_total;
+			if (!(cb->explicit_expiry & EXPIRE_UNREACH))
+				cb->expire_unreachable = ent->expire_unreachable;
+			return;
+		}
+	}
+
+	/*
+	 * If unconfigured, make stash never expire
+	 */
+	if (!strcmp(ref, "refs/stash")) {
+		if (!(cb->explicit_expiry & EXPIRE_TOTAL))
+			cb->expire_total = 0;
+		if (!(cb->explicit_expiry & EXPIRE_UNREACH))
+			cb->expire_unreachable = 0;
+		return;
+	}
+
+	/* Nothing matched -- use the default value */
+	if (!(cb->explicit_expiry & EXPIRE_TOTAL))
+		cb->expire_total = default_reflog_expire;
+	if (!(cb->explicit_expiry & EXPIRE_UNREACH))
+		cb->expire_unreachable = default_reflog_expire_unreachable;
+}
+
+static int expire_unreachable_callback(const struct option *opt,
+				 const char *arg,
+				 int unset)
+{
+	struct cmd_reflog_expire_cb *cmd = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (parse_expiry_date(arg, &cmd->expire_unreachable))
+		die(_("invalid timestamp '%s' given to '--%s'"),
+		    arg, opt->long_name);
+
+	cmd->explicit_expiry |= EXPIRE_UNREACH;
+	return 0;
+}
+
+static int expire_total_callback(const struct option *opt,
+				 const char *arg,
+				 int unset)
+{
+	struct cmd_reflog_expire_cb *cmd = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (parse_expiry_date(arg, &cmd->expire_total))
+		die(_("invalid timestamp '%s' given to '--%s'"),
+		    arg, opt->long_name);
+
+	cmd->explicit_expiry |= EXPIRE_TOTAL;
+	return 0;
+}
+
+static int cmd_reflog_show(int argc, const char **argv, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+
+	parse_options(argc, argv, prefix, options, reflog_show_usage,
+		      PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
+		      PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+	return cmd_log_reflog(argc, argv, prefix, the_repository);
+}
+
+static int show_reflog(const char *refname, void *cb_data UNUSED)
+{
+	printf("%s\n", refname);
+	return 0;
+}
+
+static int cmd_reflog_list(int argc, const char **argv, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	struct ref_store *ref_store;
+
+	argc = parse_options(argc, argv, prefix, options, reflog_list_usage, 0);
+	if (argc)
+		return error(_("%s does not accept arguments: '%s'"),
+			     "list", argv[0]);
+
+	ref_store = get_main_ref_store(the_repository);
+
+	return refs_for_each_reflog(ref_store, show_reflog, NULL);
+}
+
+static int cmd_reflog_expire(int argc, const char **argv, const char *prefix,
+			     struct repository *repo UNUSED)
+{
+	struct cmd_reflog_expire_cb cmd = { 0 };
+	timestamp_t now = time(NULL);
+	int i, status, do_all, single_worktree = 0;
+	unsigned int flags = 0;
+	int verbose = 0;
+	reflog_expiry_should_prune_fn *should_prune_fn = should_expire_reflog_ent;
+	const struct option options[] = {
+		OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
+			EXPIRE_REFLOGS_DRY_RUN),
+		OPT_BIT(0, "rewrite", &flags,
+			N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
+			EXPIRE_REFLOGS_REWRITE),
+		OPT_BIT(0, "updateref", &flags,
+			N_("update the reference to the value of the top reflog entry"),
+			EXPIRE_REFLOGS_UPDATE_REF),
+		OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")),
+		OPT_CALLBACK_F(0, "expire", &cmd, N_("timestamp"),
+			       N_("prune entries older than the specified time"),
+			       PARSE_OPT_NONEG,
+			       expire_total_callback),
+		OPT_CALLBACK_F(0, "expire-unreachable", &cmd, N_("timestamp"),
+			       N_("prune entries older than <time> that are not reachable from the current tip of the branch"),
+			       PARSE_OPT_NONEG,
+			       expire_unreachable_callback),
+		OPT_BOOL(0, "stale-fix", &cmd.stalefix,
+			 N_("prune any reflog entries that point to broken commits")),
+		OPT_BOOL(0, "all", &do_all, N_("process the reflogs of all references")),
+		OPT_BOOL(0, "single-worktree", &single_worktree,
+			 N_("limits processing to reflogs from the current worktree only")),
+		OPT_END()
+	};
+
+	default_reflog_expire_unreachable = now - 30 * 24 * 3600;
+	default_reflog_expire = now - 90 * 24 * 3600;
+	git_config(reflog_expire_config, NULL);
+
+	save_commit_buffer = 0;
+	do_all = status = 0;
+
+	cmd.explicit_expiry = 0;
+	cmd.expire_total = default_reflog_expire;
+	cmd.expire_unreachable = default_reflog_expire_unreachable;
+
+	argc = parse_options(argc, argv, prefix, options, reflog_expire_usage, 0);
+
+	if (verbose)
+		should_prune_fn = should_expire_reflog_ent_verbose;
+
+	/*
+	 * We can trust the commits and objects reachable from refs
+	 * even in older repository.  We cannot trust what's reachable
+	 * from reflog if the repository was pruned with older git.
+	 */
+	if (cmd.stalefix) {
+		struct rev_info revs;
+
+		repo_init_revisions(the_repository, &revs, prefix);
+		revs.do_not_die_on_missing_objects = 1;
+		revs.ignore_missing = 1;
+		revs.ignore_missing_links = 1;
+		if (verbose)
+			printf(_("Marking reachable objects..."));
+		mark_reachable_objects(&revs, 0, 0, NULL);
+		release_revisions(&revs);
+		if (verbose)
+			putchar('\n');
+	}
+
+	if (do_all) {
+		struct worktree_reflogs collected = {
+			.reflogs = STRING_LIST_INIT_DUP,
+		};
+		struct string_list_item *item;
+		struct worktree **worktrees, **p;
+
+		worktrees = get_worktrees();
+		for (p = worktrees; *p; p++) {
+			if (single_worktree && !(*p)->is_current)
+				continue;
+			collected.worktree = *p;
+			refs_for_each_reflog(get_worktree_ref_store(*p),
+					     collect_reflog, &collected);
+		}
+		free_worktrees(worktrees);
+
+		for_each_string_list_item(item, &collected.reflogs) {
+			struct expire_reflog_policy_cb cb = {
+				.cmd = cmd,
+				.dry_run = !!(flags & EXPIRE_REFLOGS_DRY_RUN),
+			};
+
+			set_reflog_expiry_param(&cb.cmd,  item->string);
+			status |= refs_reflog_expire(get_main_ref_store(the_repository),
+						     item->string, flags,
+						     reflog_expiry_prepare,
+						     should_prune_fn,
+						     reflog_expiry_cleanup,
+						     &cb);
+		}
+		string_list_clear(&collected.reflogs, 0);
+	}
+
+	for (i = 0; i < argc; i++) {
+		char *ref;
+		struct expire_reflog_policy_cb cb = { .cmd = cmd };
+
+		if (!repo_dwim_log(the_repository, argv[i], strlen(argv[i]), NULL, &ref)) {
+			status |= error(_("%s points nowhere!"), argv[i]);
+			continue;
+		}
+		set_reflog_expiry_param(&cb.cmd, ref);
+		status |= refs_reflog_expire(get_main_ref_store(the_repository),
+					     ref, flags,
+					     reflog_expiry_prepare,
+					     should_prune_fn,
+					     reflog_expiry_cleanup,
+					     &cb);
+		free(ref);
+	}
+	return status;
+}
+
+static int cmd_reflog_delete(int argc, const char **argv, const char *prefix,
+			     struct repository *repo UNUSED)
+{
+	int i, status = 0;
+	unsigned int flags = 0;
+	int verbose = 0;
+
+	const struct option options[] = {
+		OPT_BIT('n', "dry-run", &flags, N_("do not actually prune any entries"),
+			EXPIRE_REFLOGS_DRY_RUN),
+		OPT_BIT(0, "rewrite", &flags,
+			N_("rewrite the old SHA1 with the new SHA1 of the entry that now precedes it"),
+			EXPIRE_REFLOGS_REWRITE),
+		OPT_BIT(0, "updateref", &flags,
+			N_("update the reference to the value of the top reflog entry"),
+			EXPIRE_REFLOGS_UPDATE_REF),
+		OPT_BOOL(0, "verbose", &verbose, N_("print extra information on screen")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, reflog_delete_usage, 0);
+
+	if (argc < 1)
+		return error(_("no reflog specified to delete"));
+
+	for (i = 0; i < argc; i++)
+		status |= reflog_delete(argv[i], flags, verbose);
+
+	return status;
+}
+
+static int cmd_reflog_exists(int argc, const char **argv, const char *prefix,
+			     struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	const char *refname;
+
+	argc = parse_options(argc, argv, prefix, options, reflog_exists_usage,
+			     0);
+	if (!argc)
+		usage_with_options(reflog_exists_usage, options);
+
+	refname = argv[0];
+	if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
+		die(_("invalid ref format: %s"), refname);
+	return !refs_reflog_exists(get_main_ref_store(the_repository),
+				   refname);
+}
+
+/*
+ * main "reflog"
+ */
+
+int cmd_reflog(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repository)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("show", &fn, cmd_reflog_show),
+		OPT_SUBCOMMAND("list", &fn, cmd_reflog_list),
+		OPT_SUBCOMMAND("expire", &fn, cmd_reflog_expire),
+		OPT_SUBCOMMAND("delete", &fn, cmd_reflog_delete),
+		OPT_SUBCOMMAND("exists", &fn, cmd_reflog_exists),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, reflog_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL |
+			     PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0 |
+			     PARSE_OPT_KEEP_UNKNOWN_OPT);
+	if (fn)
+		return fn(argc - 1, argv + 1, prefix, repository);
+	else
+		return cmd_log_reflog(argc, argv, prefix, repository);
+}
diff --git a/builtin/refs.c b/builtin/refs.c
new file mode 100644
index 0000000000..a29f195834
--- /dev/null
+++ b/builtin/refs.c
@@ -0,0 +1,120 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "fsck.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "strbuf.h"
+#include "worktree.h"
+
+#define REFS_MIGRATE_USAGE \
+	N_("git refs migrate --ref-format=<format> [--dry-run]")
+
+#define REFS_VERIFY_USAGE \
+	N_("git refs verify [--strict] [--verbose]")
+
+static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,
+			    struct repository *repo UNUSED)
+{
+	const char * const migrate_usage[] = {
+		REFS_MIGRATE_USAGE,
+		NULL,
+	};
+	const char *format_str = NULL;
+	enum ref_storage_format format;
+	unsigned int flags = 0;
+	struct option options[] = {
+		OPT_STRING_F(0, "ref-format", &format_str, N_("format"),
+			N_("specify the reference format to convert to"),
+			PARSE_OPT_NONEG),
+		OPT_BIT(0, "dry-run", &flags,
+			N_("perform a non-destructive dry-run"),
+			REPO_MIGRATE_REF_STORAGE_FORMAT_DRYRUN),
+		OPT_END(),
+	};
+	struct strbuf errbuf = STRBUF_INIT;
+	int err;
+
+	argc = parse_options(argc, argv, prefix, options, migrate_usage, 0);
+	if (argc)
+		usage(_("too many arguments"));
+	if (!format_str)
+		usage(_("missing --ref-format=<format>"));
+
+	format = ref_storage_format_by_name(format_str);
+	if (format == REF_STORAGE_FORMAT_UNKNOWN) {
+		err = error(_("unknown ref storage format '%s'"), format_str);
+		goto out;
+	}
+
+	if (the_repository->ref_storage_format == format) {
+		err = error(_("repository already uses '%s' format"),
+			    ref_storage_format_to_name(format));
+		goto out;
+	}
+
+	if (repo_migrate_ref_storage_format(the_repository, format, flags, &errbuf) < 0) {
+		err = error("%s", errbuf.buf);
+		goto out;
+	}
+
+	err = 0;
+
+out:
+	strbuf_release(&errbuf);
+	return err;
+}
+
+static int cmd_refs_verify(int argc, const char **argv, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	struct fsck_options fsck_refs_options = FSCK_REFS_OPTIONS_DEFAULT;
+	struct worktree **worktrees;
+	const char * const verify_usage[] = {
+		REFS_VERIFY_USAGE,
+		NULL,
+	};
+	struct option options[] = {
+		OPT_BOOL(0, "verbose", &fsck_refs_options.verbose, N_("be verbose")),
+		OPT_BOOL(0, "strict", &fsck_refs_options.strict, N_("enable strict checking")),
+		OPT_END(),
+	};
+	int ret = 0;
+
+	argc = parse_options(argc, argv, prefix, options, verify_usage, 0);
+	if (argc)
+		usage(_("'git refs verify' takes no arguments"));
+
+	git_config(git_fsck_config, &fsck_refs_options);
+	prepare_repo_settings(the_repository);
+
+	worktrees = get_worktrees();
+	for (size_t i = 0; worktrees[i]; i++)
+		ret |= refs_fsck(get_worktree_ref_store(worktrees[i]),
+				 &fsck_refs_options, worktrees[i]);
+
+	fsck_options_clear(&fsck_refs_options);
+	free_worktrees(worktrees);
+	return ret;
+}
+
+int cmd_refs(int argc,
+	     const char **argv,
+	     const char *prefix,
+	     struct repository *repo)
+{
+	const char * const refs_usage[] = {
+		REFS_MIGRATE_USAGE,
+		REFS_VERIFY_USAGE,
+		NULL,
+	};
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option opts[] = {
+		OPT_SUBCOMMAND("migrate", &fn, cmd_refs_migrate),
+		OPT_SUBCOMMAND("verify", &fn, cmd_refs_verify),
+		OPT_END(),
+	};
+
+	argc = parse_options(argc, argv, prefix, opts, refs_usage, 0);
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
new file mode 100644
index 0000000000..bd2037f27d
--- /dev/null
+++ b/builtin/remote-ext.c
@@ -0,0 +1,211 @@
+#include "builtin.h"
+#include "transport.h"
+#include "run-command.h"
+#include "pkt-line.h"
+
+static const char usage_msg[] =
+	"git remote-ext <remote> <url>";
+
+/*
+ * URL syntax:
+ *	'command [arg1 [arg2 [...]]]'	Invoke command with given arguments.
+ *	Special characters:
+ *	'% ': Literal space in argument.
+ *	'%%': Literal percent sign.
+ *	'%S': Name of service (git-upload-pack/git-upload-archive/
+ *		git-receive-pack.
+ *	'%s': Same as \s, but with possible git- prefix stripped.
+ *	'%G': Only allowed as first 'character' of argument. Do not pass this
+ *		Argument to command, instead send this as name of repository
+ *		in in-line git://-style request (also activates sending this
+ *		style of request).
+ *	'%V': Only allowed as first 'character' of argument. Used in
+ *		conjunction with '%G': Do not pass this argument to command,
+ *		instead send this as vhost in git://-style request (note: does
+ *		not activate sending git:// style request).
+ */
+
+static char *git_req;
+static char *git_req_vhost;
+
+static char *strip_escapes(const char *str, const char *service,
+	const char **next)
+{
+	size_t rpos = 0;
+	int escape = 0;
+	char special = 0;
+	const char *service_noprefix = service;
+	struct strbuf ret = STRBUF_INIT;
+
+	skip_prefix(service_noprefix, "git-", &service_noprefix);
+
+	/* Pass the service to command. */
+	setenv("GIT_EXT_SERVICE", service, 1);
+	setenv("GIT_EXT_SERVICE_NOPREFIX", service_noprefix, 1);
+
+	/* Scan the length of argument. */
+	while (str[rpos] && (escape || str[rpos] != ' ')) {
+		if (escape) {
+			switch (str[rpos]) {
+			case ' ':
+			case '%':
+			case 's':
+			case 'S':
+				break;
+			case 'G':
+			case 'V':
+				special = str[rpos];
+				if (rpos == 1)
+					break;
+				/* fallthrough */
+			default:
+				die("Bad remote-ext placeholder '%%%c'.",
+					str[rpos]);
+			}
+			escape = 0;
+		} else
+			escape = (str[rpos] == '%');
+		rpos++;
+	}
+	if (escape && !str[rpos])
+		die("remote-ext command has incomplete placeholder");
+	*next = str + rpos;
+	if (**next == ' ')
+		++*next;	/* Skip over space */
+
+	/*
+	 * Do the actual placeholder substitution. The string will be short
+	 * enough not to overflow integers.
+	 */
+	rpos = special ? 2 : 0;		/* Skip first 2 bytes in specials. */
+	escape = 0;
+	while (str[rpos] && (escape || str[rpos] != ' ')) {
+		if (escape) {
+			switch (str[rpos]) {
+			case ' ':
+			case '%':
+				strbuf_addch(&ret, str[rpos]);
+				break;
+			case 's':
+				strbuf_addstr(&ret, service_noprefix);
+				break;
+			case 'S':
+				strbuf_addstr(&ret, service);
+				break;
+			}
+			escape = 0;
+		} else
+			switch (str[rpos]) {
+			case '%':
+				escape = 1;
+				break;
+			default:
+				strbuf_addch(&ret, str[rpos]);
+				break;
+			}
+		rpos++;
+	}
+	switch (special) {
+	case 'G':
+		git_req = strbuf_detach(&ret, NULL);
+		return NULL;
+	case 'V':
+		git_req_vhost = strbuf_detach(&ret, NULL);
+		return NULL;
+	default:
+		return strbuf_detach(&ret, NULL);
+	}
+}
+
+static void parse_argv(struct strvec *out, const char *arg, const char *service)
+{
+	while (*arg) {
+		char *expanded = strip_escapes(arg, service, &arg);
+		if (expanded)
+			strvec_push(out, expanded);
+		free(expanded);
+	}
+}
+
+static void send_git_request(int stdin_fd, const char *serv, const char *repo,
+	const char *vhost)
+{
+	if (!vhost)
+		packet_write_fmt(stdin_fd, "%s %s%c", serv, repo, 0);
+	else
+		packet_write_fmt(stdin_fd, "%s %s%chost=%s%c", serv, repo, 0,
+			     vhost, 0);
+}
+
+static int run_child(const char *arg, const char *service)
+{
+	int r;
+	struct child_process child = CHILD_PROCESS_INIT;
+
+	child.in = -1;
+	child.out = -1;
+	child.err = 0;
+	parse_argv(&child.args, arg, service);
+
+	if (start_command(&child) < 0)
+		die("Can't run specified command");
+
+	if (git_req)
+		send_git_request(child.in, service, git_req, git_req_vhost);
+
+	r = bidirectional_transfer_loop(child.out, child.in);
+	if (!r)
+		r = finish_command(&child);
+	else
+		finish_command(&child);
+	return r;
+}
+
+#define MAXCOMMAND 4096
+
+static int command_loop(const char *child)
+{
+	char buffer[MAXCOMMAND];
+
+	while (1) {
+		size_t i;
+		const char *arg;
+
+		if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
+			if (ferror(stdin))
+				die("Command input error");
+			exit(0);
+		}
+		/* Strip end of line characters. */
+		i = strlen(buffer);
+		while (i > 0 && isspace(buffer[i - 1]))
+			buffer[--i] = 0;
+
+		if (!strcmp(buffer, "capabilities")) {
+			printf("*connect\n\n");
+			fflush(stdout);
+		} else if (skip_prefix(buffer, "connect ", &arg)) {
+			printf("\n");
+			fflush(stdout);
+			return run_child(child, arg);
+		} else {
+			fprintf(stderr, "Bad command");
+			return 1;
+		}
+	}
+}
+
+int cmd_remote_ext(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	BUG_ON_NON_EMPTY_PREFIX(prefix);
+
+	show_usage_if_asked(argc, argv, usage_msg);
+
+	if (argc != 3)
+		usage(usage_msg);
+
+	return command_loop(argv[2]);
+}
diff --git a/builtin/remote-fd.c b/builtin/remote-fd.c
new file mode 100644
index 0000000000..39908546ba
--- /dev/null
+++ b/builtin/remote-fd.c
@@ -0,0 +1,88 @@
+#include "builtin.h"
+#include "transport.h"
+
+static const char usage_msg[] =
+	"git remote-fd <remote> <url>";
+
+/*
+ * URL syntax:
+ *	'fd::<inoutfd>[/<anything>]'		Read/write socket pair
+ *						<inoutfd>.
+ *	'fd::<infd>,<outfd>[/<anything>]'	Read pipe <infd> and write
+ *						pipe <outfd>.
+ *	[foo] indicates 'foo' is optional. <anything> is any string.
+ *
+ * The data output to <outfd>/<inoutfd> should be passed unmolested to
+ * git-receive-pack/git-upload-pack/git-upload-archive and output of
+ * git-receive-pack/git-upload-pack/git-upload-archive should be passed
+ * unmolested to <infd>/<inoutfd>.
+ *
+ */
+
+#define MAXCOMMAND 4096
+
+static void command_loop(int input_fd, int output_fd)
+{
+	char buffer[MAXCOMMAND];
+
+	while (1) {
+		size_t i;
+		if (!fgets(buffer, MAXCOMMAND - 1, stdin)) {
+			if (ferror(stdin))
+				die("Input error");
+			return;
+		}
+		/* Strip end of line characters. */
+		i = strlen(buffer);
+		while (i > 0 && isspace(buffer[i - 1]))
+			buffer[--i] = 0;
+
+		if (!strcmp(buffer, "capabilities")) {
+			printf("*connect\n\n");
+			fflush(stdout);
+		} else if (starts_with(buffer, "connect ")) {
+			printf("\n");
+			fflush(stdout);
+			if (bidirectional_transfer_loop(input_fd,
+				output_fd))
+				die("Copying data between file descriptors failed");
+			return;
+		} else {
+			die("Bad command: %s", buffer);
+		}
+	}
+}
+
+int cmd_remote_fd(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	int input_fd = -1;
+	int output_fd = -1;
+	char *end;
+
+	BUG_ON_NON_EMPTY_PREFIX(prefix);
+
+	show_usage_if_asked(argc, argv, usage_msg);
+	if (argc != 3)
+		usage(usage_msg);
+
+	input_fd = (int)strtoul(argv[2], &end, 10);
+
+	if ((end == argv[2]) || (*end != ',' && *end != '/' && *end))
+		die("Bad URL syntax");
+
+	if (*end == '/' || !*end) {
+		output_fd = input_fd;
+	} else {
+		char *end2;
+		output_fd = (int)strtoul(end + 1, &end2, 10);
+
+		if ((end2 == end + 1) || (*end2 != '/' && *end2))
+			die("Bad URL syntax");
+	}
+
+	command_loop(input_fd, output_fd);
+	return 0;
+}
diff --git a/builtin/remote.c b/builtin/remote.c
new file mode 100644
index 0000000000..315cbb88e6
--- /dev/null
+++ b/builtin/remote.c
@@ -0,0 +1,1858 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "path.h"
+#include "transport.h"
+#include "remote.h"
+#include "string-list.h"
+#include "strbuf.h"
+#include "run-command.h"
+#include "rebase.h"
+#include "refs.h"
+#include "refspec.h"
+#include "object-store-ll.h"
+#include "strvec.h"
+#include "commit-reach.h"
+#include "progress.h"
+
+static const char * const builtin_remote_usage[] = {
+	"git remote [-v | --verbose]",
+	N_("git remote add [-t <branch>] [-m <master>] [-f] [--tags | --no-tags] [--mirror=<fetch|push>] <name> <url>"),
+	N_("git remote rename [--[no-]progress] <old> <new>"),
+	N_("git remote remove <name>"),
+	N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
+	N_("git remote [-v | --verbose] show [-n] <name>"),
+	N_("git remote prune [-n | --dry-run] <name>"),
+	N_("git remote [-v | --verbose] update [-p | --prune] [(<group> | <remote>)...]"),
+	N_("git remote set-branches [--add] <name> <branch>..."),
+	N_("git remote get-url [--push] [--all] <name>"),
+	N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
+	N_("git remote set-url --add <name> <newurl>"),
+	N_("git remote set-url --delete <name> <url>"),
+	NULL
+};
+
+static const char * const builtin_remote_add_usage[] = {
+	N_("git remote add [<options>] <name> <url>"),
+	NULL
+};
+
+static const char * const builtin_remote_rename_usage[] = {
+	N_("git remote rename [--[no-]progress] <old> <new>"),
+	NULL
+};
+
+static const char * const builtin_remote_rm_usage[] = {
+	N_("git remote remove <name>"),
+	NULL
+};
+
+static const char * const builtin_remote_sethead_usage[] = {
+	N_("git remote set-head <name> (-a | --auto | -d | --delete | <branch>)"),
+	NULL
+};
+
+static const char * const builtin_remote_setbranches_usage[] = {
+	N_("git remote set-branches <name> <branch>..."),
+	N_("git remote set-branches --add <name> <branch>..."),
+	NULL
+};
+
+static const char * const builtin_remote_show_usage[] = {
+	N_("git remote show [<options>] <name>"),
+	NULL
+};
+
+static const char * const builtin_remote_prune_usage[] = {
+	N_("git remote prune [<options>] <name>"),
+	NULL
+};
+
+static const char * const builtin_remote_update_usage[] = {
+	N_("git remote update [<options>] [<group> | <remote>]..."),
+	NULL
+};
+
+static const char * const builtin_remote_geturl_usage[] = {
+	N_("git remote get-url [--push] [--all] <name>"),
+	NULL
+};
+
+static const char * const builtin_remote_seturl_usage[] = {
+	N_("git remote set-url [--push] <name> <newurl> [<oldurl>]"),
+	N_("git remote set-url --add <name> <newurl>"),
+	N_("git remote set-url --delete <name> <url>"),
+	NULL
+};
+
+#define GET_REF_STATES (1<<0)
+#define GET_HEAD_NAMES (1<<1)
+#define GET_PUSH_REF_STATES (1<<2)
+
+static int verbose;
+
+static int fetch_remote(const char *name)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+
+	strvec_push(&cmd.args, "fetch");
+	if (verbose)
+		strvec_push(&cmd.args, "-v");
+	strvec_push(&cmd.args, name);
+	cmd.git_cmd = 1;
+	printf_ln(_("Updating %s"), name);
+	if (run_command(&cmd))
+		return error(_("Could not fetch %s"), name);
+	return 0;
+}
+
+enum {
+	TAGS_UNSET = 0,
+	TAGS_DEFAULT = 1,
+	TAGS_SET = 2
+};
+
+#define MIRROR_NONE 0
+#define MIRROR_FETCH 1
+#define MIRROR_PUSH 2
+#define MIRROR_BOTH (MIRROR_FETCH|MIRROR_PUSH)
+
+static void add_branch(const char *key, const char *branchname,
+		       const char *remotename, int mirror, struct strbuf *tmp)
+{
+	strbuf_reset(tmp);
+	strbuf_addch(tmp, '+');
+	if (mirror)
+		strbuf_addf(tmp, "refs/%s:refs/%s",
+				branchname, branchname);
+	else
+		strbuf_addf(tmp, "refs/heads/%s:refs/remotes/%s/%s",
+				branchname, remotename, branchname);
+	git_config_set_multivar(key, tmp->buf, "^$", 0);
+}
+
+static const char mirror_advice[] =
+N_("--mirror is dangerous and deprecated; please\n"
+   "\t use --mirror=fetch or --mirror=push instead");
+
+static int parse_mirror_opt(const struct option *opt, const char *arg, int not)
+{
+	unsigned *mirror = opt->value;
+	if (not)
+		*mirror = MIRROR_NONE;
+	else if (!arg) {
+		warning("%s", _(mirror_advice));
+		*mirror = MIRROR_BOTH;
+	}
+	else if (!strcmp(arg, "fetch"))
+		*mirror = MIRROR_FETCH;
+	else if (!strcmp(arg, "push"))
+		*mirror = MIRROR_PUSH;
+	else
+		return error(_("unknown --mirror argument: %s"), arg);
+	return 0;
+}
+
+static int add(int argc, const char **argv, const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	int fetch = 0, fetch_tags = TAGS_DEFAULT;
+	unsigned mirror = MIRROR_NONE;
+	struct string_list track = STRING_LIST_INIT_NODUP;
+	const char *master = NULL;
+	struct remote *remote;
+	struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;
+	const char *name, *url;
+	int i;
+	int result = 0;
+
+	struct option options[] = {
+		OPT_BOOL('f', "fetch", &fetch, N_("fetch the remote branches")),
+		OPT_SET_INT(0, "tags", &fetch_tags,
+			    N_("import all tags and associated objects when fetching\n"
+			       "or do not fetch any tag at all (--no-tags)"),
+			    TAGS_SET),
+		OPT_STRING_LIST('t', "track", &track, N_("branch"),
+				N_("branch(es) to track")),
+		OPT_STRING('m', "master", &master, N_("branch"), N_("master branch")),
+		OPT_CALLBACK_F(0, "mirror", &mirror, "(push|fetch)",
+			N_("set up remote as a mirror to push to or fetch from"),
+			PARSE_OPT_OPTARG | PARSE_OPT_COMP_ARG, parse_mirror_opt),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_add_usage, 0);
+
+	if (argc != 2)
+		usage_with_options(builtin_remote_add_usage, options);
+
+	if (mirror && master)
+		die(_("specifying a master branch makes no sense with --mirror"));
+	if (mirror && !(mirror & MIRROR_FETCH) && track.nr)
+		die(_("specifying branches to track makes sense only with fetch mirrors"));
+
+	name = argv[0];
+	url = argv[1];
+
+	remote = remote_get(name);
+	if (remote_is_configured(remote, 1)) {
+		error(_("remote %s already exists."), name);
+		exit(3);
+	}
+
+	if (!valid_remote_name(name))
+		die(_("'%s' is not a valid remote name"), name);
+
+	strbuf_addf(&buf, "remote.%s.url", name);
+	git_config_set(buf.buf, url);
+
+	if (!mirror || mirror & MIRROR_FETCH) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "remote.%s.fetch", name);
+		if (track.nr == 0)
+			string_list_append(&track, "*");
+		for (i = 0; i < track.nr; i++) {
+			add_branch(buf.buf, track.items[i].string,
+				   name, mirror, &buf2);
+		}
+	}
+
+	if (mirror & MIRROR_PUSH) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "remote.%s.mirror", name);
+		git_config_set(buf.buf, "true");
+	}
+
+	if (fetch_tags != TAGS_DEFAULT) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "remote.%s.tagOpt", name);
+		git_config_set(buf.buf,
+			       fetch_tags == TAGS_SET ? "--tags" : "--no-tags");
+	}
+
+	if (fetch && fetch_remote(name)) {
+		result = 1;
+		goto out;
+	}
+
+	if (master) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "refs/remotes/%s/HEAD", name);
+
+		strbuf_reset(&buf2);
+		strbuf_addf(&buf2, "refs/remotes/%s/%s", name, master);
+
+		if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, "remote add"))
+			result = error(_("Could not setup master '%s'"), master);
+	}
+
+out:
+	strbuf_release(&buf);
+	strbuf_release(&buf2);
+	string_list_clear(&track, 0);
+
+	return result;
+}
+
+struct branch_info {
+	char *remote_name;
+	struct string_list merge;
+	enum rebase_type rebase;
+	char *push_remote_name;
+};
+
+static struct string_list branch_list = STRING_LIST_INIT_DUP;
+
+static const char *abbrev_ref(const char *name, const char *prefix)
+{
+	skip_prefix(name, prefix, &name);
+	return name;
+}
+#define abbrev_branch(name) abbrev_ref((name), "refs/heads/")
+
+static int config_read_branches(const char *key, const char *value,
+				const struct config_context *ctx UNUSED,
+				void *data UNUSED)
+{
+	const char *orig_key = key;
+	char *name;
+	struct string_list_item *item;
+	struct branch_info *info;
+	enum { REMOTE, MERGE, REBASE, PUSH_REMOTE } type;
+	size_t key_len;
+
+	if (!starts_with(key, "branch."))
+		return 0;
+
+	key += strlen("branch.");
+	if (strip_suffix(key, ".remote", &key_len))
+		type = REMOTE;
+	else if (strip_suffix(key, ".merge", &key_len))
+		type = MERGE;
+	else if (strip_suffix(key, ".rebase", &key_len))
+		type = REBASE;
+	else if (strip_suffix(key, ".pushremote", &key_len))
+		type = PUSH_REMOTE;
+	else
+		return 0;
+
+	name = xmemdupz(key, key_len);
+	item = string_list_insert(&branch_list, name);
+
+	if (!item->util)
+		item->util = xcalloc(1, sizeof(struct branch_info));
+	info = item->util;
+	switch (type) {
+	case REMOTE:
+		if (info->remote_name)
+			warning(_("more than one %s"), orig_key);
+		info->remote_name = xstrdup(value);
+		break;
+	case MERGE: {
+		char *space = strchr(value, ' ');
+		value = abbrev_branch(value);
+		while (space) {
+			char *merge;
+			merge = xstrndup(value, space - value);
+			string_list_append(&info->merge, merge);
+			value = abbrev_branch(space + 1);
+			space = strchr(value, ' ');
+		}
+		string_list_append(&info->merge, xstrdup(value));
+		break;
+	}
+	case REBASE:
+		/*
+		 * Consider invalid values as false and check the
+		 * truth value with >= REBASE_TRUE.
+		 */
+		info->rebase = rebase_parse_value(value);
+		if (info->rebase == REBASE_INVALID)
+			warning(_("unhandled branch.%s.rebase=%s; assuming "
+				  "'true'"), name, value);
+		break;
+	case PUSH_REMOTE:
+		if (info->push_remote_name)
+			warning(_("more than one %s"), orig_key);
+		info->push_remote_name = xstrdup(value);
+		break;
+	default:
+		BUG("unexpected type=%d", type);
+	}
+
+	free(name);
+	return 0;
+}
+
+static void read_branches(void)
+{
+	if (branch_list.nr)
+		return;
+	git_config(config_read_branches, NULL);
+}
+
+struct ref_states {
+	struct remote *remote;
+	struct string_list new_refs, skipped, stale, tracked, heads, push;
+	int queried;
+};
+
+#define REF_STATES_INIT { \
+	.new_refs = STRING_LIST_INIT_DUP, \
+	.skipped = STRING_LIST_INIT_DUP, \
+	.stale = STRING_LIST_INIT_DUP, \
+	.tracked = STRING_LIST_INIT_DUP, \
+	.heads = STRING_LIST_INIT_DUP, \
+	.push = STRING_LIST_INIT_DUP, \
+}
+
+static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)
+{
+	struct ref *fetch_map = NULL, **tail = &fetch_map;
+	struct ref *ref, *stale_refs;
+	int i;
+
+	for (i = 0; i < states->remote->fetch.nr; i++)
+		if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1))
+			die(_("Could not get fetch map for refspec %s"),
+				states->remote->fetch.items[i].raw);
+
+	for (ref = fetch_map; ref; ref = ref->next) {
+		if (omit_name_by_refspec(ref->name, &states->remote->fetch))
+			string_list_append(&states->skipped, abbrev_branch(ref->name));
+		else if (!ref->peer_ref || !refs_ref_exists(get_main_ref_store(the_repository), ref->peer_ref->name))
+			string_list_append(&states->new_refs, abbrev_branch(ref->name));
+		else
+			string_list_append(&states->tracked, abbrev_branch(ref->name));
+	}
+	stale_refs = get_stale_heads(&states->remote->fetch, fetch_map);
+	for (ref = stale_refs; ref; ref = ref->next) {
+		struct string_list_item *item =
+			string_list_append(&states->stale, abbrev_branch(ref->name));
+		item->util = xstrdup(ref->name);
+	}
+	free_refs(stale_refs);
+	free_refs(fetch_map);
+
+	string_list_sort(&states->new_refs);
+	string_list_sort(&states->skipped);
+	string_list_sort(&states->tracked);
+	string_list_sort(&states->stale);
+
+	return 0;
+}
+
+struct push_info {
+	char *dest;
+	int forced;
+	enum {
+		PUSH_STATUS_CREATE = 0,
+		PUSH_STATUS_DELETE,
+		PUSH_STATUS_UPTODATE,
+		PUSH_STATUS_FASTFORWARD,
+		PUSH_STATUS_OUTOFDATE,
+		PUSH_STATUS_NOTQUERIED
+	} status;
+};
+
+static int get_push_ref_states(const struct ref *remote_refs,
+	struct ref_states *states)
+{
+	struct remote *remote = states->remote;
+	struct ref *ref, *local_refs, *push_map;
+	if (remote->mirror)
+		return 0;
+
+	local_refs = get_local_heads();
+	push_map = copy_ref_list(remote_refs);
+
+	match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE);
+
+	for (ref = push_map; ref; ref = ref->next) {
+		struct string_list_item *item;
+		struct push_info *info;
+
+		if (!ref->peer_ref)
+			continue;
+		oidcpy(&ref->new_oid, &ref->peer_ref->new_oid);
+
+		item = string_list_append(&states->push,
+					  abbrev_branch(ref->peer_ref->name));
+		item->util = xcalloc(1, sizeof(struct push_info));
+		info = item->util;
+		info->forced = ref->force;
+		info->dest = xstrdup(abbrev_branch(ref->name));
+
+		if (is_null_oid(&ref->new_oid)) {
+			info->status = PUSH_STATUS_DELETE;
+		} else if (oideq(&ref->old_oid, &ref->new_oid))
+			info->status = PUSH_STATUS_UPTODATE;
+		else if (is_null_oid(&ref->old_oid))
+			info->status = PUSH_STATUS_CREATE;
+		else if (repo_has_object_file(the_repository, &ref->old_oid) &&
+			 ref_newer(&ref->new_oid, &ref->old_oid))
+			info->status = PUSH_STATUS_FASTFORWARD;
+		else
+			info->status = PUSH_STATUS_OUTOFDATE;
+	}
+	free_refs(local_refs);
+	free_refs(push_map);
+	return 0;
+}
+
+static int get_push_ref_states_noquery(struct ref_states *states)
+{
+	int i;
+	struct remote *remote = states->remote;
+	struct string_list_item *item;
+	struct push_info *info;
+
+	if (remote->mirror)
+		return 0;
+
+	if (!remote->push.nr) {
+		item = string_list_append(&states->push, _("(matching)"));
+		info = item->util = xcalloc(1, sizeof(struct push_info));
+		info->status = PUSH_STATUS_NOTQUERIED;
+		info->dest = xstrdup(item->string);
+	}
+	for (i = 0; i < remote->push.nr; i++) {
+		const struct refspec_item *spec = &remote->push.items[i];
+		if (spec->matching)
+			item = string_list_append(&states->push, _("(matching)"));
+		else if (strlen(spec->src))
+			item = string_list_append(&states->push, spec->src);
+		else
+			item = string_list_append(&states->push, _("(delete)"));
+
+		info = item->util = xcalloc(1, sizeof(struct push_info));
+		info->forced = spec->force;
+		info->status = PUSH_STATUS_NOTQUERIED;
+		info->dest = xstrdup(spec->dst ? spec->dst : item->string);
+	}
+	return 0;
+}
+
+static int get_head_names(const struct ref *remote_refs, struct ref_states *states)
+{
+	struct ref *ref, *matches;
+	struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
+	struct refspec_item refspec = {
+		.force = 0,
+		.pattern = 1,
+		.src = (char *) "refs/heads/*",
+		.dst = (char *) "refs/heads/*",
+	};
+
+	get_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);
+	matches = guess_remote_head(find_ref_by_name(remote_refs, "HEAD"),
+				    fetch_map, 1);
+	for (ref = matches; ref; ref = ref->next)
+		string_list_append(&states->heads, abbrev_branch(ref->name));
+
+	free_refs(fetch_map);
+	free_refs(matches);
+	return 0;
+}
+
+struct known_remote {
+	struct known_remote *next;
+	struct remote *remote;
+};
+
+struct known_remotes {
+	struct remote *to_delete;
+	struct known_remote *list;
+};
+
+static int add_known_remote(struct remote *remote, void *cb_data)
+{
+	struct known_remotes *all = cb_data;
+	struct known_remote *r;
+
+	if (!strcmp(all->to_delete->name, remote->name))
+		return 0;
+
+	r = xmalloc(sizeof(*r));
+	r->remote = remote;
+	r->next = all->list;
+	all->list = r;
+	return 0;
+}
+
+struct branches_for_remote {
+	struct remote *remote;
+	struct string_list *branches, *skipped;
+	struct known_remotes *keep;
+};
+
+static int add_branch_for_removal(const char *refname,
+				  const char *referent UNUSED,
+				  const struct object_id *oid UNUSED,
+				  int flags UNUSED, void *cb_data)
+{
+	struct branches_for_remote *branches = cb_data;
+	struct refspec_item refspec;
+	struct known_remote *kr;
+
+	memset(&refspec, 0, sizeof(refspec));
+	refspec.dst = (char *)refname;
+	if (remote_find_tracking(branches->remote, &refspec))
+		return 0;
+	free(refspec.src);
+
+	/* don't delete a branch if another remote also uses it */
+	for (kr = branches->keep->list; kr; kr = kr->next) {
+		memset(&refspec, 0, sizeof(refspec));
+		refspec.dst = (char *)refname;
+		if (!remote_find_tracking(kr->remote, &refspec)) {
+			free(refspec.src);
+			return 0;
+		}
+	}
+
+	/* don't delete non-remote-tracking refs */
+	if (!starts_with(refname, "refs/remotes/")) {
+		/* advise user how to delete local branches */
+		if (starts_with(refname, "refs/heads/"))
+			string_list_append(branches->skipped,
+					   abbrev_branch(refname));
+		/* silently skip over other non-remote refs */
+		return 0;
+	}
+
+	string_list_append(branches->branches, refname);
+
+	return 0;
+}
+
+struct rename_info {
+	const char *old_name;
+	const char *new_name;
+	struct string_list *remote_branches;
+	uint32_t symrefs_nr;
+};
+
+static int read_remote_branches(const char *refname, const char *referent UNUSED,
+				const struct object_id *oid UNUSED,
+				int flags UNUSED, void *cb_data)
+{
+	struct rename_info *rename = cb_data;
+	struct strbuf buf = STRBUF_INIT;
+	struct string_list_item *item;
+	int flag;
+	const char *symref;
+
+	strbuf_addf(&buf, "refs/remotes/%s/", rename->old_name);
+	if (starts_with(refname, buf.buf)) {
+		item = string_list_append(rename->remote_branches, refname);
+		symref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+						 refname, RESOLVE_REF_READING,
+						 NULL, &flag);
+		if (symref && (flag & REF_ISSYMREF)) {
+			item->util = xstrdup(symref);
+			rename->symrefs_nr++;
+		} else {
+			item->util = NULL;
+		}
+	}
+	strbuf_release(&buf);
+
+	return 0;
+}
+
+static int migrate_file(struct remote *remote)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int i;
+
+	strbuf_addf(&buf, "remote.%s.url", remote->name);
+	for (i = 0; i < remote->url.nr; i++)
+		git_config_set_multivar(buf.buf, remote->url.v[i], "^$", 0);
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "remote.%s.push", remote->name);
+	for (i = 0; i < remote->push.nr; i++)
+		git_config_set_multivar(buf.buf, remote->push.items[i].raw, "^$", 0);
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "remote.%s.fetch", remote->name);
+	for (i = 0; i < remote->fetch.nr; i++)
+		git_config_set_multivar(buf.buf, remote->fetch.items[i].raw, "^$", 0);
+	if (remote->origin == REMOTE_REMOTES)
+		unlink_or_warn(git_path("remotes/%s", remote->name));
+	else if (remote->origin == REMOTE_BRANCHES)
+		unlink_or_warn(git_path("branches/%s", remote->name));
+	strbuf_release(&buf);
+
+	return 0;
+}
+
+struct push_default_info
+{
+	const char *old_name;
+	enum config_scope scope;
+	struct strbuf origin;
+	int linenr;
+};
+
+static int config_read_push_default(const char *key, const char *value,
+	const struct config_context *ctx, void *cb)
+{
+	const struct key_value_info *kvi = ctx->kvi;
+
+	struct push_default_info* info = cb;
+	if (strcmp(key, "remote.pushdefault") ||
+	    !value || strcmp(value, info->old_name))
+		return 0;
+
+	info->scope = kvi->scope;
+	strbuf_reset(&info->origin);
+	strbuf_addstr(&info->origin, config_origin_type_name(kvi->origin_type));
+	info->linenr = kvi->linenr;
+
+	return 0;
+}
+
+static void handle_push_default(const char* old_name, const char* new_name)
+{
+	struct push_default_info push_default = {
+		.old_name = old_name,
+		.scope = CONFIG_SCOPE_UNKNOWN,
+		.origin = STRBUF_INIT,
+		.linenr = -1,
+	};
+	git_config(config_read_push_default, &push_default);
+	if (push_default.scope >= CONFIG_SCOPE_COMMAND)
+		; /* pass */
+	else if (push_default.scope >= CONFIG_SCOPE_LOCAL) {
+		int result = git_config_set_gently("remote.pushDefault",
+						   new_name);
+		if (new_name && result && result != CONFIG_NOTHING_SET)
+			die(_("could not set '%s'"), "remote.pushDefault");
+		else if (!new_name && result && result != CONFIG_NOTHING_SET)
+			die(_("could not unset '%s'"), "remote.pushDefault");
+	} else if (push_default.scope >= CONFIG_SCOPE_SYSTEM) {
+		/* warn */
+		warning(_("The %s configuration remote.pushDefault in:\n"
+			  "\t%s:%d\n"
+			  "now names the non-existent remote '%s'"),
+			config_scope_name(push_default.scope),
+			push_default.origin.buf, push_default.linenr,
+			old_name);
+	}
+
+	strbuf_release(&push_default.origin);
+}
+
+
+static int mv(int argc, const char **argv, const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	int show_progress = isatty(2);
+	struct option options[] = {
+		OPT_BOOL(0, "progress", &show_progress, N_("force progress reporting")),
+		OPT_END()
+	};
+	struct remote *oldremote, *newremote;
+	struct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT, buf3 = STRBUF_INIT,
+		old_remote_context = STRBUF_INIT;
+	struct string_list remote_branches = STRING_LIST_INIT_DUP;
+	struct rename_info rename;
+	int i, refs_renamed_nr = 0, refspec_updated = 0;
+	struct progress *progress = NULL;
+	int result = 0;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_rename_usage, 0);
+
+	if (argc != 2)
+		usage_with_options(builtin_remote_rename_usage, options);
+
+	rename.old_name = argv[0];
+	rename.new_name = argv[1];
+	rename.remote_branches = &remote_branches;
+	rename.symrefs_nr = 0;
+
+	oldremote = remote_get(rename.old_name);
+	if (!remote_is_configured(oldremote, 1)) {
+		error(_("No such remote: '%s'"), rename.old_name);
+		exit(2);
+	}
+
+	if (!strcmp(rename.old_name, rename.new_name) && oldremote->origin != REMOTE_CONFIG)
+		return migrate_file(oldremote);
+
+	newremote = remote_get(rename.new_name);
+	if (remote_is_configured(newremote, 1)) {
+		error(_("remote %s already exists."), rename.new_name);
+		exit(3);
+	}
+
+	if (!valid_remote_name(rename.new_name))
+		die(_("'%s' is not a valid remote name"), rename.new_name);
+
+	strbuf_addf(&buf, "remote.%s", rename.old_name);
+	strbuf_addf(&buf2, "remote.%s", rename.new_name);
+	if (repo_config_rename_section(the_repository, buf.buf, buf2.buf) < 1) {
+		result = error(_("Could not rename config section '%s' to '%s'"),
+			       buf.buf, buf2.buf);
+		goto out;
+	}
+
+	if (oldremote->fetch.nr) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
+		git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+		strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
+		for (i = 0; i < oldremote->fetch.nr; i++) {
+			char *ptr;
+
+			strbuf_reset(&buf2);
+			strbuf_addstr(&buf2, oldremote->fetch.items[i].raw);
+			ptr = strstr(buf2.buf, old_remote_context.buf);
+			if (ptr) {
+				refspec_updated = 1;
+				strbuf_splice(&buf2,
+					      ptr-buf2.buf + strlen(":refs/remotes/"),
+					      strlen(rename.old_name), rename.new_name,
+					      strlen(rename.new_name));
+			} else
+				warning(_("Not updating non-default fetch refspec\n"
+					  "\t%s\n"
+					  "\tPlease update the configuration manually if necessary."),
+					buf2.buf);
+
+			git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
+		}
+	}
+
+	read_branches();
+	for (i = 0; i < branch_list.nr; i++) {
+		struct string_list_item *item = branch_list.items + i;
+		struct branch_info *info = item->util;
+		if (info->remote_name && !strcmp(info->remote_name, rename.old_name)) {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "branch.%s.remote", item->string);
+			git_config_set(buf.buf, rename.new_name);
+		}
+		if (info->push_remote_name && !strcmp(info->push_remote_name, rename.old_name)) {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "branch.%s.pushRemote", item->string);
+			git_config_set(buf.buf, rename.new_name);
+		}
+	}
+
+	if (!refspec_updated)
+		goto out;
+
+	/*
+	 * First remove symrefs, then rename the rest, finally create
+	 * the new symrefs.
+	 */
+	refs_for_each_ref(get_main_ref_store(the_repository),
+			  read_remote_branches, &rename);
+	if (show_progress) {
+		/*
+		 * Count symrefs twice, since "renaming" them is done by
+		 * deleting and recreating them in two separate passes.
+		 */
+		progress = start_progress(the_repository,
+					  _("Renaming remote references"),
+					  rename.remote_branches->nr + rename.symrefs_nr);
+	}
+	for (i = 0; i < remote_branches.nr; i++) {
+		struct string_list_item *item = remote_branches.items + i;
+		struct strbuf referent = STRBUF_INIT;
+
+		if (refs_read_symbolic_ref(get_main_ref_store(the_repository), item->string,
+					   &referent))
+			continue;
+		if (refs_delete_ref(get_main_ref_store(the_repository), NULL, item->string, NULL, REF_NO_DEREF))
+			die(_("deleting '%s' failed"), item->string);
+
+		strbuf_release(&referent);
+		display_progress(progress, ++refs_renamed_nr);
+	}
+	for (i = 0; i < remote_branches.nr; i++) {
+		struct string_list_item *item = remote_branches.items + i;
+
+		if (item->util)
+			continue;
+		strbuf_reset(&buf);
+		strbuf_addstr(&buf, item->string);
+		strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
+				rename.new_name, strlen(rename.new_name));
+		strbuf_reset(&buf2);
+		strbuf_addf(&buf2, "remote: renamed %s to %s",
+				item->string, buf.buf);
+		if (refs_rename_ref(get_main_ref_store(the_repository), item->string, buf.buf, buf2.buf))
+			die(_("renaming '%s' failed"), item->string);
+		display_progress(progress, ++refs_renamed_nr);
+	}
+	for (i = 0; i < remote_branches.nr; i++) {
+		struct string_list_item *item = remote_branches.items + i;
+
+		if (!item->util)
+			continue;
+		strbuf_reset(&buf);
+		strbuf_addstr(&buf, item->string);
+		strbuf_splice(&buf, strlen("refs/remotes/"), strlen(rename.old_name),
+				rename.new_name, strlen(rename.new_name));
+		strbuf_reset(&buf2);
+		strbuf_addstr(&buf2, item->util);
+		strbuf_splice(&buf2, strlen("refs/remotes/"), strlen(rename.old_name),
+				rename.new_name, strlen(rename.new_name));
+		strbuf_reset(&buf3);
+		strbuf_addf(&buf3, "remote: renamed %s to %s",
+				item->string, buf.buf);
+		if (refs_update_symref(get_main_ref_store(the_repository), buf.buf, buf2.buf, buf3.buf))
+			die(_("creating '%s' failed"), buf.buf);
+		display_progress(progress, ++refs_renamed_nr);
+	}
+	stop_progress(&progress);
+
+	handle_push_default(rename.old_name, rename.new_name);
+
+out:
+	string_list_clear(&remote_branches, 1);
+	strbuf_release(&old_remote_context);
+	strbuf_release(&buf);
+	strbuf_release(&buf2);
+	strbuf_release(&buf3);
+	return result;
+}
+
+static int rm(int argc, const char **argv, const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	struct remote *remote;
+	struct strbuf buf = STRBUF_INIT;
+	struct known_remotes known_remotes = { NULL, NULL };
+	struct string_list branches = STRING_LIST_INIT_DUP;
+	struct string_list skipped = STRING_LIST_INIT_DUP;
+	struct branches_for_remote cb_data;
+	int i, result;
+
+	memset(&cb_data, 0, sizeof(cb_data));
+	cb_data.branches = &branches;
+	cb_data.skipped = &skipped;
+	cb_data.keep = &known_remotes;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_rm_usage, 0);
+	if (argc != 1)
+		usage_with_options(builtin_remote_rm_usage, options);
+
+	remote = remote_get(argv[0]);
+	if (!remote_is_configured(remote, 1)) {
+		error(_("No such remote: '%s'"), argv[0]);
+		exit(2);
+	}
+
+	known_remotes.to_delete = remote;
+	for_each_remote(add_known_remote, &known_remotes);
+
+	read_branches();
+	for (i = 0; i < branch_list.nr; i++) {
+		struct string_list_item *item = branch_list.items + i;
+		struct branch_info *info = item->util;
+		if (info->remote_name && !strcmp(info->remote_name, remote->name)) {
+			const char *keys[] = { "remote", "merge", NULL }, **k;
+			for (k = keys; *k; k++) {
+				strbuf_reset(&buf);
+				strbuf_addf(&buf, "branch.%s.%s",
+						item->string, *k);
+				result = git_config_set_gently(buf.buf, NULL);
+				if (result && result != CONFIG_NOTHING_SET)
+					die(_("could not unset '%s'"), buf.buf);
+			}
+		}
+		if (info->push_remote_name && !strcmp(info->push_remote_name, remote->name)) {
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "branch.%s.pushremote", item->string);
+			result = git_config_set_gently(buf.buf, NULL);
+			if (result && result != CONFIG_NOTHING_SET)
+				die(_("could not unset '%s'"), buf.buf);
+		}
+	}
+
+	/*
+	 * We cannot just pass a function to for_each_ref() which deletes
+	 * the branches one by one, since for_each_ref() relies on cached
+	 * refs, which are invalidated when deleting a branch.
+	 */
+	cb_data.remote = remote;
+	result = refs_for_each_ref(get_main_ref_store(the_repository),
+				   add_branch_for_removal, &cb_data);
+	strbuf_release(&buf);
+
+	if (!result)
+		result = refs_delete_refs(get_main_ref_store(the_repository),
+					  "remote: remove", &branches,
+					  REF_NO_DEREF);
+	string_list_clear(&branches, 0);
+
+	if (skipped.nr) {
+		fprintf_ln(stderr,
+			   Q_("Note: A branch outside the refs/remotes/ hierarchy was not removed;\n"
+			      "to delete it, use:",
+			      "Note: Some branches outside the refs/remotes/ hierarchy were not removed;\n"
+			      "to delete them, use:",
+			      skipped.nr));
+		for (i = 0; i < skipped.nr; i++)
+			fprintf(stderr, "  git branch -d %s\n",
+				skipped.items[i].string);
+	}
+	string_list_clear(&skipped, 0);
+
+	if (!result) {
+		strbuf_addf(&buf, "remote.%s", remote->name);
+		if (repo_config_rename_section(the_repository, buf.buf, NULL) < 1) {
+			result = error(_("Could not remove config section '%s'"), buf.buf);
+			goto out;
+		}
+
+		handle_push_default(remote->name, NULL);
+	}
+
+out:
+	for (struct known_remote *r = known_remotes.list; r;) {
+		struct known_remote *next = r->next;
+		free(r);
+		r = next;
+	}
+	strbuf_release(&buf);
+	return result;
+}
+
+static void clear_push_info(void *util, const char *string UNUSED)
+{
+	struct push_info *info = util;
+	free(info->dest);
+	free(info);
+}
+
+static void free_remote_ref_states(struct ref_states *states)
+{
+	string_list_clear(&states->new_refs, 0);
+	string_list_clear(&states->skipped, 0);
+	string_list_clear(&states->stale, 1);
+	string_list_clear(&states->tracked, 0);
+	string_list_clear(&states->heads, 0);
+	string_list_clear_func(&states->push, clear_push_info);
+}
+
+static int append_ref_to_tracked_list(const char *refname,
+				      const char *referent UNUSED,
+				      const struct object_id *oid UNUSED,
+				      int flags, void *cb_data)
+{
+	struct ref_states *states = cb_data;
+	struct refspec_item refspec;
+
+	if (flags & REF_ISSYMREF)
+		return 0;
+
+	memset(&refspec, 0, sizeof(refspec));
+	refspec.dst = (char *)refname;
+	if (!remote_find_tracking(states->remote, &refspec)) {
+		string_list_append(&states->tracked, abbrev_branch(refspec.src));
+		free(refspec.src);
+	}
+
+	return 0;
+}
+
+static int get_remote_ref_states(const char *name,
+				 struct ref_states *states,
+				 int query)
+{
+	states->remote = remote_get(name);
+	if (!states->remote)
+		return error(_("No such remote: '%s'"), name);
+
+	read_branches();
+
+	if (query) {
+		struct transport *transport;
+		const struct ref *remote_refs;
+
+		transport = transport_get(states->remote, states->remote->url.v[0]);
+		remote_refs = transport_get_remote_refs(transport, NULL);
+
+		states->queried = 1;
+		if (query & GET_REF_STATES)
+			get_ref_states(remote_refs, states);
+		if (query & GET_HEAD_NAMES)
+			get_head_names(remote_refs, states);
+		if (query & GET_PUSH_REF_STATES)
+			get_push_ref_states(remote_refs, states);
+		transport_disconnect(transport);
+	} else {
+		refs_for_each_ref(get_main_ref_store(the_repository),
+				  append_ref_to_tracked_list, states);
+		string_list_sort(&states->tracked);
+		get_push_ref_states_noquery(states);
+	}
+
+	return 0;
+}
+
+struct show_info {
+	struct string_list list;
+	struct ref_states states;
+	int width, width2;
+	int any_rebase;
+};
+
+#define SHOW_INFO_INIT { \
+	.list = STRING_LIST_INIT_DUP, \
+	.states = REF_STATES_INIT, \
+}
+
+static int add_remote_to_show_info(struct string_list_item *item, void *cb_data)
+{
+	struct show_info *info = cb_data;
+	int n = strlen(item->string);
+	if (n > info->width)
+		info->width = n;
+	string_list_insert(&info->list, item->string);
+	return 0;
+}
+
+static int show_remote_info_item(struct string_list_item *item, void *cb_data)
+{
+	struct show_info *info = cb_data;
+	struct ref_states *states = &info->states;
+	const char *name = item->string;
+
+	if (states->queried) {
+		const char *fmt = "%s";
+		const char *arg = "";
+		if (string_list_has_string(&states->new_refs, name)) {
+			fmt = _(" new (next fetch will store in remotes/%s)");
+			arg = states->remote->name;
+		} else if (string_list_has_string(&states->tracked, name))
+			arg = _(" tracked");
+		else if (string_list_has_string(&states->skipped, name))
+			arg = _(" skipped");
+		else if (string_list_has_string(&states->stale, name))
+			arg = _(" stale (use 'git remote prune' to remove)");
+		else
+			arg = _(" ???");
+		printf("    %-*s", info->width, name);
+		printf(fmt, arg);
+		printf("\n");
+	} else
+		printf("    %s\n", name);
+
+	return 0;
+}
+
+static int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)
+{
+	struct show_info *show_info = cb_data;
+	struct ref_states *states = &show_info->states;
+	struct branch_info *branch_info = branch_item->util;
+	struct string_list_item *item;
+	int n;
+
+	if (!branch_info->merge.nr || !branch_info->remote_name ||
+	    strcmp(states->remote->name, branch_info->remote_name))
+		return 0;
+	if ((n = strlen(branch_item->string)) > show_info->width)
+		show_info->width = n;
+	if (branch_info->rebase >= REBASE_TRUE)
+		show_info->any_rebase = 1;
+
+	item = string_list_insert(&show_info->list, branch_item->string);
+	item->util = branch_info;
+
+	return 0;
+}
+
+static int show_local_info_item(struct string_list_item *item, void *cb_data)
+{
+	struct show_info *show_info = cb_data;
+	struct branch_info *branch_info = item->util;
+	struct string_list *merge = &branch_info->merge;
+	int width = show_info->width + 4;
+	int i;
+
+	if (branch_info->rebase >= REBASE_TRUE && branch_info->merge.nr > 1) {
+		error(_("invalid branch.%s.merge; cannot rebase onto > 1 branch"),
+			item->string);
+		return 0;
+	}
+
+	printf("    %-*s ", show_info->width, item->string);
+	if (branch_info->rebase >= REBASE_TRUE) {
+		const char *msg;
+		if (branch_info->rebase == REBASE_INTERACTIVE)
+			msg = _("rebases interactively onto remote %s");
+		else if (branch_info->rebase == REBASE_MERGES)
+			msg = _("rebases interactively (with merges) onto "
+				"remote %s");
+		else
+			msg = _("rebases onto remote %s");
+		printf_ln(msg, merge->items[0].string);
+		return 0;
+	} else if (show_info->any_rebase) {
+		printf_ln(_(" merges with remote %s"), merge->items[0].string);
+		width++;
+	} else {
+		printf_ln(_("merges with remote %s"), merge->items[0].string);
+	}
+	for (i = 1; i < merge->nr; i++)
+		printf(_("%-*s    and with remote %s\n"), width, "",
+		       merge->items[i].string);
+
+	return 0;
+}
+
+static int add_push_to_show_info(struct string_list_item *push_item, void *cb_data)
+{
+	struct show_info *show_info = cb_data;
+	struct push_info *push_info = push_item->util;
+	struct string_list_item *item;
+	int n;
+	if ((n = strlen(push_item->string)) > show_info->width)
+		show_info->width = n;
+	if ((n = strlen(push_info->dest)) > show_info->width2)
+		show_info->width2 = n;
+	item = string_list_append(&show_info->list, push_item->string);
+	item->util = push_item->util;
+	return 0;
+}
+
+/*
+ * Sorting comparison for a string list that has push_info
+ * structs in its util field
+ */
+static int cmp_string_with_push(const void *va, const void *vb)
+{
+	const struct string_list_item *a = va;
+	const struct string_list_item *b = vb;
+	const struct push_info *a_push = a->util;
+	const struct push_info *b_push = b->util;
+	int cmp = strcmp(a->string, b->string);
+	return cmp ? cmp : strcmp(a_push->dest, b_push->dest);
+}
+
+static int show_push_info_item(struct string_list_item *item, void *cb_data)
+{
+	struct show_info *show_info = cb_data;
+	struct push_info *push_info = item->util;
+	const char *src = item->string, *status = NULL;
+
+	switch (push_info->status) {
+	case PUSH_STATUS_CREATE:
+		status = _("create");
+		break;
+	case PUSH_STATUS_DELETE:
+		status = _("delete");
+		src = _("(none)");
+		break;
+	case PUSH_STATUS_UPTODATE:
+		status = _("up to date");
+		break;
+	case PUSH_STATUS_FASTFORWARD:
+		status = _("fast-forwardable");
+		break;
+	case PUSH_STATUS_OUTOFDATE:
+		status = _("local out of date");
+		break;
+	case PUSH_STATUS_NOTQUERIED:
+		break;
+	}
+	if (status) {
+		if (push_info->forced)
+			printf_ln(_("    %-*s forces to %-*s (%s)"), show_info->width, src,
+			       show_info->width2, push_info->dest, status);
+		else
+			printf_ln(_("    %-*s pushes to %-*s (%s)"), show_info->width, src,
+			       show_info->width2, push_info->dest, status);
+	} else {
+		if (push_info->forced)
+			printf_ln(_("    %-*s forces to %s"), show_info->width, src,
+			       push_info->dest);
+		else
+			printf_ln(_("    %-*s pushes to %s"), show_info->width, src,
+			       push_info->dest);
+	}
+	return 0;
+}
+
+static int get_one_entry(struct remote *remote, void *priv)
+{
+	struct string_list *list = priv;
+	struct strbuf remote_info_buf = STRBUF_INIT;
+	struct strvec *url;
+	int i;
+
+	if (remote->url.nr > 0) {
+		struct strbuf promisor_config = STRBUF_INIT;
+		const char *partial_clone_filter = NULL;
+
+		strbuf_addf(&promisor_config, "remote.%s.partialclonefilter", remote->name);
+		strbuf_addf(&remote_info_buf, "%s (fetch)", remote->url.v[0]);
+		if (!git_config_get_string_tmp(promisor_config.buf, &partial_clone_filter))
+			strbuf_addf(&remote_info_buf, " [%s]", partial_clone_filter);
+
+		strbuf_release(&promisor_config);
+		string_list_append(list, remote->name)->util =
+				strbuf_detach(&remote_info_buf, NULL);
+	} else
+		string_list_append(list, remote->name)->util = NULL;
+	url = push_url_of_remote(remote);
+	for (i = 0; i < url->nr; i++)
+	{
+		strbuf_addf(&remote_info_buf, "%s (push)", url->v[i]);
+		string_list_append(list, remote->name)->util =
+				strbuf_detach(&remote_info_buf, NULL);
+	}
+
+	return 0;
+}
+
+static int show_all(void)
+{
+	struct string_list list = STRING_LIST_INIT_DUP;
+	int result;
+
+	result = for_each_remote(get_one_entry, &list);
+
+	if (!result) {
+		int i;
+
+		string_list_sort(&list);
+		for (i = 0; i < list.nr; i++) {
+			struct string_list_item *item = list.items + i;
+			if (verbose)
+				printf("%s\t%s\n", item->string,
+					item->util ? (const char *)item->util : "");
+			else {
+				if (i && !strcmp((item - 1)->string, item->string))
+					continue;
+				printf("%s\n", item->string);
+			}
+		}
+	}
+	string_list_clear(&list, 1);
+	return result;
+}
+
+static int show(int argc, const char **argv, const char *prefix,
+		struct repository *repo UNUSED)
+{
+	int no_query = 0, result = 0, query_flag = 0;
+	struct option options[] = {
+		OPT_BOOL('n', NULL, &no_query, N_("do not query remotes")),
+		OPT_END()
+	};
+	struct show_info info = SHOW_INFO_INIT;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_show_usage,
+			     0);
+
+	if (argc < 1)
+		return show_all();
+
+	if (!no_query)
+		query_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);
+
+	for (; argc; argc--, argv++) {
+		int i;
+		struct strvec *url;
+
+		get_remote_ref_states(*argv, &info.states, query_flag);
+
+		printf_ln(_("* remote %s"), *argv);
+		printf_ln(_("  Fetch URL: %s"), info.states.remote->url.v[0]);
+		url = push_url_of_remote(info.states.remote);
+		for (i = 0; i < url->nr; i++)
+			/*
+			 * TRANSLATORS: the colon ':' should align
+			 * with the one in " Fetch URL: %s"
+			 * translation.
+			 */
+			printf_ln(_("  Push  URL: %s"), url->v[i]);
+		if (!i)
+			printf_ln(_("  Push  URL: %s"), _("(no URL)"));
+		if (no_query)
+			printf_ln(_("  HEAD branch: %s"), _("(not queried)"));
+		else if (!info.states.heads.nr)
+			printf_ln(_("  HEAD branch: %s"), _("(unknown)"));
+		else if (info.states.heads.nr == 1)
+			printf_ln(_("  HEAD branch: %s"), info.states.heads.items[0].string);
+		else {
+			printf(_("  HEAD branch (remote HEAD is ambiguous,"
+				 " may be one of the following):\n"));
+			for (i = 0; i < info.states.heads.nr; i++)
+				printf("    %s\n", info.states.heads.items[i].string);
+		}
+
+		/* remote branch info */
+		info.width = 0;
+		for_each_string_list(&info.states.new_refs, add_remote_to_show_info, &info);
+		for_each_string_list(&info.states.skipped, add_remote_to_show_info, &info);
+		for_each_string_list(&info.states.tracked, add_remote_to_show_info, &info);
+		for_each_string_list(&info.states.stale, add_remote_to_show_info, &info);
+		if (info.list.nr)
+			printf_ln(Q_("  Remote branch:%s",
+				     "  Remote branches:%s",
+				     info.list.nr),
+				  no_query ? _(" (status not queried)") : "");
+		for_each_string_list(&info.list, show_remote_info_item, &info);
+		string_list_clear(&info.list, 0);
+
+		/* git pull info */
+		info.width = 0;
+		info.any_rebase = 0;
+		for_each_string_list(&branch_list, add_local_to_show_info, &info);
+		if (info.list.nr)
+			printf_ln(Q_("  Local branch configured for 'git pull':",
+				     "  Local branches configured for 'git pull':",
+				     info.list.nr));
+		for_each_string_list(&info.list, show_local_info_item, &info);
+		string_list_clear(&info.list, 0);
+
+		/* git push info */
+		if (info.states.remote->mirror)
+			printf_ln(_("  Local refs will be mirrored by 'git push'"));
+
+		info.width = info.width2 = 0;
+		for_each_string_list(&info.states.push, add_push_to_show_info, &info);
+		QSORT(info.list.items, info.list.nr, cmp_string_with_push);
+		if (info.list.nr)
+			printf_ln(Q_("  Local ref configured for 'git push'%s:",
+				     "  Local refs configured for 'git push'%s:",
+				     info.list.nr),
+				  no_query ? _(" (status not queried)") : "");
+		for_each_string_list(&info.list, show_push_info_item, &info);
+		string_list_clear(&info.list, 0);
+
+		free_remote_ref_states(&info.states);
+	}
+
+	return result;
+}
+
+static void report_set_head_auto(const char *remote, const char *head_name,
+			struct strbuf *b_local_head, int was_detached) {
+	struct strbuf buf_prefix = STRBUF_INIT;
+	const char *prev_head = NULL;
+
+	strbuf_addf(&buf_prefix, "refs/remotes/%s/", remote);
+	skip_prefix(b_local_head->buf, buf_prefix.buf, &prev_head);
+
+	if (prev_head && !strcmp(prev_head, head_name))
+		printf(_("'%s/HEAD' is unchanged and points to '%s'\n"),
+			remote, head_name);
+	else if (prev_head)
+		printf(_("'%s/HEAD' has changed from '%s' and now points to '%s'\n"),
+			remote, prev_head, head_name);
+	else if (!b_local_head->len)
+		printf(_("'%s/HEAD' is now created and points to '%s'\n"),
+			remote, head_name);
+	else if (was_detached && b_local_head->len)
+		printf(_("'%s/HEAD' was detached at '%s' and now points to '%s'\n"),
+			remote, b_local_head->buf, head_name);
+	else
+		printf(_("'%s/HEAD' used to point to '%s' "
+			"(which is not a remote branch), but now points to '%s'\n"),
+			remote, b_local_head->buf, head_name);
+	strbuf_release(&buf_prefix);
+}
+
+static int set_head(int argc, const char **argv, const char *prefix,
+		    struct repository *repo UNUSED)
+{
+	int i, opt_a = 0, opt_d = 0, result = 0, was_detached;
+	struct strbuf b_head = STRBUF_INIT, b_remote_head = STRBUF_INIT,
+		b_local_head = STRBUF_INIT;
+	char *head_name = NULL;
+	struct ref_store *refs = get_main_ref_store(the_repository);
+	struct remote *remote;
+
+	struct option options[] = {
+		OPT_BOOL('a', "auto", &opt_a,
+			 N_("set refs/remotes/<name>/HEAD according to remote")),
+		OPT_BOOL('d', "delete", &opt_d,
+			 N_("delete refs/remotes/<name>/HEAD")),
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_sethead_usage, 0);
+	if (argc) {
+		strbuf_addf(&b_head, "refs/remotes/%s/HEAD", argv[0]);
+		remote = remote_get(argv[0]);
+	}
+
+	if (!opt_a && !opt_d && argc == 2) {
+		head_name = xstrdup(argv[1]);
+	} else if (opt_a && !opt_d && argc == 1) {
+		struct ref_states states = REF_STATES_INIT;
+		get_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);
+		if (!states.heads.nr)
+			result |= error(_("Cannot determine remote HEAD"));
+		else if (states.heads.nr > 1) {
+			result |= error(_("Multiple remote HEAD branches. "
+					  "Please choose one explicitly with:"));
+			for (i = 0; i < states.heads.nr; i++)
+				fprintf(stderr, "  git remote set-head %s %s\n",
+					argv[0], states.heads.items[i].string);
+		} else
+			head_name = xstrdup(states.heads.items[0].string);
+		free_remote_ref_states(&states);
+	} else if (opt_d && !opt_a && argc == 1) {
+		if (refs_delete_ref(refs, NULL, b_head.buf, NULL, REF_NO_DEREF))
+			result |= error(_("Could not delete %s"), b_head.buf);
+	} else
+		usage_with_options(builtin_remote_sethead_usage, options);
+
+	if (!head_name)
+		goto cleanup;
+	strbuf_addf(&b_remote_head, "refs/remotes/%s/%s", argv[0], head_name);
+	if (!refs_ref_exists(refs, b_remote_head.buf)) {
+		result |= error(_("Not a valid ref: %s"), b_remote_head.buf);
+		goto cleanup;
+	}
+	was_detached = refs_update_symref_extended(refs, b_head.buf, b_remote_head.buf,
+			"remote set-head", &b_local_head, 0);
+	if (was_detached == -1) {
+		result |= error(_("Could not set up %s"), b_head.buf);
+		goto cleanup;
+	}
+	if (opt_a)
+		report_set_head_auto(argv[0], head_name, &b_local_head, was_detached);
+	if (remote->follow_remote_head == FOLLOW_REMOTE_ALWAYS) {
+		struct strbuf config_name = STRBUF_INIT;
+		strbuf_addf(&config_name,
+			"remote.%s.followremotehead", remote->name);
+		git_config_set(config_name.buf, "warn");
+		strbuf_release(&config_name);
+	}
+
+cleanup:
+	free(head_name);
+	strbuf_release(&b_head);
+	strbuf_release(&b_remote_head);
+	strbuf_release(&b_local_head);
+	return result;
+}
+
+static int prune_remote(const char *remote, int dry_run)
+{
+	int result = 0;
+	struct ref_states states = REF_STATES_INIT;
+	struct string_list refs_to_prune = STRING_LIST_INIT_NODUP;
+	struct string_list_item *item;
+	const char *dangling_msg = dry_run
+		? _(" %s will become dangling!")
+		: _(" %s has become dangling!");
+
+	get_remote_ref_states(remote, &states, GET_REF_STATES);
+
+	if (!states.stale.nr) {
+		free_remote_ref_states(&states);
+		return 0;
+	}
+
+	printf_ln(_("Pruning %s"), remote);
+	printf_ln(_("URL: %s"), states.remote->url.v[0]);
+
+	for_each_string_list_item(item, &states.stale)
+		string_list_append(&refs_to_prune, item->util);
+	string_list_sort(&refs_to_prune);
+
+	if (!dry_run)
+		result |= refs_delete_refs(get_main_ref_store(the_repository),
+					   "remote: prune", &refs_to_prune, 0);
+
+	for_each_string_list_item(item, &states.stale) {
+		const char *refname = item->util;
+
+		if (dry_run)
+			printf_ln(_(" * [would prune] %s"),
+			       abbrev_ref(refname, "refs/remotes/"));
+		else
+			printf_ln(_(" * [pruned] %s"),
+			       abbrev_ref(refname, "refs/remotes/"));
+	}
+
+	refs_warn_dangling_symrefs(get_main_ref_store(the_repository),
+				   stdout, dangling_msg, &refs_to_prune);
+
+	string_list_clear(&refs_to_prune, 0);
+	free_remote_ref_states(&states);
+	return result;
+}
+
+static int prune(int argc, const char **argv, const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	int dry_run = 0, result = 0;
+	struct option options[] = {
+		OPT__DRY_RUN(&dry_run, N_("dry run")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_prune_usage, 0);
+
+	if (argc < 1)
+		usage_with_options(builtin_remote_prune_usage, options);
+
+	for (; argc; argc--, argv++)
+		result |= prune_remote(*argv, dry_run);
+
+	return result;
+}
+
+static int get_remote_default(const char *key, const char *value UNUSED,
+			      const struct config_context *ctx UNUSED,
+			      void *priv)
+{
+	if (strcmp(key, "remotes.default") == 0) {
+		int *found = priv;
+		*found = 1;
+	}
+	return 0;
+}
+
+static int update(int argc, const char **argv, const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	int i, prune = -1;
+	struct option options[] = {
+		OPT_BOOL('p', "prune", &prune,
+			 N_("prune remotes after fetching")),
+		OPT_END()
+	};
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	int default_defined = 0;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_update_usage,
+			     PARSE_OPT_KEEP_ARGV0);
+
+	strvec_push(&cmd.args, "fetch");
+
+	if (prune != -1)
+		strvec_push(&cmd.args, prune ? "--prune" : "--no-prune");
+	if (verbose)
+		strvec_push(&cmd.args, "-v");
+	strvec_push(&cmd.args, "--multiple");
+	if (argc < 2)
+		strvec_push(&cmd.args, "default");
+	for (i = 1; i < argc; i++)
+		strvec_push(&cmd.args, argv[i]);
+
+	if (strcmp(cmd.args.v[cmd.args.nr-1], "default") == 0) {
+		git_config(get_remote_default, &default_defined);
+		if (!default_defined) {
+			strvec_pop(&cmd.args);
+			strvec_push(&cmd.args, "--all");
+		}
+	}
+
+	cmd.git_cmd = 1;
+	return run_command(&cmd);
+}
+
+static int remove_all_fetch_refspecs(const char *key)
+{
+	return git_config_set_multivar_gently(key, NULL, NULL,
+					      CONFIG_FLAGS_MULTI_REPLACE);
+}
+
+static void add_branches(struct remote *remote, const char **branches,
+			 const char *key)
+{
+	const char *remotename = remote->name;
+	int mirror = remote->mirror;
+	struct strbuf refspec = STRBUF_INIT;
+
+	for (; *branches; branches++)
+		add_branch(key, *branches, remotename, mirror, &refspec);
+
+	strbuf_release(&refspec);
+}
+
+static int set_remote_branches(const char *remotename, const char **branches,
+				int add_mode)
+{
+	struct strbuf key = STRBUF_INIT;
+	struct remote *remote;
+
+	strbuf_addf(&key, "remote.%s.fetch", remotename);
+
+	remote = remote_get(remotename);
+	if (!remote_is_configured(remote, 1)) {
+		error(_("No such remote '%s'"), remotename);
+		exit(2);
+	}
+
+	if (!add_mode && remove_all_fetch_refspecs(key.buf)) {
+		strbuf_release(&key);
+		return 1;
+	}
+	add_branches(remote, branches, key.buf);
+
+	strbuf_release(&key);
+	return 0;
+}
+
+static int set_branches(int argc, const char **argv, const char *prefix,
+			struct repository *repo UNUSED)
+{
+	int add_mode = 0;
+	struct option options[] = {
+		OPT_BOOL('\0', "add", &add_mode, N_("add branch")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_setbranches_usage, 0);
+	if (argc == 0) {
+		error(_("no remote specified"));
+		usage_with_options(builtin_remote_setbranches_usage, options);
+	}
+	argv[argc] = NULL;
+
+	return set_remote_branches(argv[0], argv + 1, add_mode);
+}
+
+static int get_url(int argc, const char **argv, const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	int i, push_mode = 0, all_mode = 0;
+	const char *remotename = NULL;
+	struct remote *remote;
+	struct strvec *url;
+	struct option options[] = {
+		OPT_BOOL('\0', "push", &push_mode,
+			 N_("query push URLs rather than fetch URLs")),
+		OPT_BOOL('\0', "all", &all_mode,
+			 N_("return all URLs")),
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_geturl_usage, 0);
+
+	if (argc != 1)
+		usage_with_options(builtin_remote_geturl_usage, options);
+
+	remotename = argv[0];
+
+	remote = remote_get(remotename);
+	if (!remote_is_configured(remote, 1)) {
+		error(_("No such remote '%s'"), remotename);
+		exit(2);
+	}
+
+	url = push_mode ? push_url_of_remote(remote) : &remote->url;
+
+	if (all_mode) {
+		for (i = 0; i < url->nr; i++)
+			printf_ln("%s", url->v[i]);
+	} else {
+		printf_ln("%s", url->v[0]);
+	}
+
+	return 0;
+}
+
+static int set_url(int argc, const char **argv, const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	int i, push_mode = 0, add_mode = 0, delete_mode = 0;
+	int matches = 0, negative_matches = 0;
+	const char *remotename = NULL;
+	const char *newurl = NULL;
+	const char *oldurl = NULL;
+	struct remote *remote;
+	regex_t old_regex;
+	struct strvec *urlset;
+	struct strbuf name_buf = STRBUF_INIT;
+	struct option options[] = {
+		OPT_BOOL('\0', "push", &push_mode,
+			 N_("manipulate push URLs")),
+		OPT_BOOL('\0', "add", &add_mode,
+			 N_("add URL")),
+		OPT_BOOL('\0', "delete", &delete_mode,
+			    N_("delete URLs")),
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, prefix, options,
+			     builtin_remote_seturl_usage,
+			     PARSE_OPT_KEEP_ARGV0);
+
+	if (add_mode && delete_mode)
+		die(_("--add --delete doesn't make sense"));
+
+	if (argc < 3 || argc > 4 || ((add_mode || delete_mode) && argc != 3))
+		usage_with_options(builtin_remote_seturl_usage, options);
+
+	remotename = argv[1];
+	newurl = argv[2];
+	if (argc > 3)
+		oldurl = argv[3];
+
+	if (delete_mode)
+		oldurl = newurl;
+
+	remote = remote_get(remotename);
+	if (!remote_is_configured(remote, 1)) {
+		error(_("No such remote '%s'"), remotename);
+		exit(2);
+	}
+
+	if (push_mode) {
+		strbuf_addf(&name_buf, "remote.%s.pushurl", remotename);
+		urlset = &remote->pushurl;
+	} else {
+		strbuf_addf(&name_buf, "remote.%s.url", remotename);
+		urlset = &remote->url;
+	}
+
+	/* Special cases that add new entry. */
+	if ((!oldurl && !delete_mode) || add_mode) {
+		if (add_mode)
+			git_config_set_multivar(name_buf.buf, newurl,
+						       "^$", 0);
+		else
+			git_config_set(name_buf.buf, newurl);
+		goto out;
+	}
+
+	/* Old URL specified. Demand that one matches. */
+	if (regcomp(&old_regex, oldurl, REG_EXTENDED))
+		die(_("Invalid old URL pattern: %s"), oldurl);
+
+	for (i = 0; i < urlset->nr; i++)
+		if (!regexec(&old_regex, urlset->v[i], 0, NULL, 0))
+			matches++;
+		else
+			negative_matches++;
+	if (!delete_mode && !matches)
+		die(_("No such URL found: %s"), oldurl);
+	if (delete_mode && !negative_matches && !push_mode)
+		die(_("Will not delete all non-push URLs"));
+
+	regfree(&old_regex);
+
+	if (!delete_mode)
+		git_config_set_multivar(name_buf.buf, newurl, oldurl, 0);
+	else
+		git_config_set_multivar(name_buf.buf, NULL, oldurl,
+					CONFIG_FLAGS_MULTI_REPLACE);
+out:
+	strbuf_release(&name_buf);
+	return 0;
+}
+
+int cmd_remote(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT__VERBOSE(&verbose, N_("be verbose; must be placed before a subcommand")),
+		OPT_SUBCOMMAND("add", &fn, add),
+		OPT_SUBCOMMAND("rename", &fn, mv),
+		OPT_SUBCOMMAND_F("rm", &fn, rm, PARSE_OPT_NOCOMPLETE),
+		OPT_SUBCOMMAND("remove", &fn, rm),
+		OPT_SUBCOMMAND("set-head", &fn, set_head),
+		OPT_SUBCOMMAND("set-branches", &fn, set_branches),
+		OPT_SUBCOMMAND("get-url", &fn, get_url),
+		OPT_SUBCOMMAND("set-url", &fn, set_url),
+		OPT_SUBCOMMAND("show", &fn, show),
+		OPT_SUBCOMMAND("prune", &fn, prune),
+		OPT_SUBCOMMAND("update", &fn, update),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, builtin_remote_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL);
+
+	if (fn) {
+		return !!fn(argc, argv, prefix, repo);
+	} else {
+		if (argc) {
+			error(_("unknown subcommand: `%s'"), argv[0]);
+			usage_with_options(builtin_remote_usage, options);
+		}
+		return !!show_all();
+	}
+}
diff --git a/builtin/repack.c b/builtin/repack.c
new file mode 100644
index 0000000000..81d13630ea
--- /dev/null
+++ b/builtin/repack.c
@@ -0,0 +1,1587 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "parse-options.h"
+#include "path.h"
+#include "run-command.h"
+#include "server-info.h"
+#include "strbuf.h"
+#include "string-list.h"
+#include "strvec.h"
+#include "midx.h"
+#include "packfile.h"
+#include "prune-packed.h"
+#include "object-store-ll.h"
+#include "promisor-remote.h"
+#include "shallow.h"
+#include "pack.h"
+#include "pack-bitmap.h"
+#include "refs.h"
+#include "list-objects-filter-options.h"
+
+#define ALL_INTO_ONE 1
+#define LOOSEN_UNREACHABLE 2
+#define PACK_CRUFT 4
+
+#define DELETE_PACK 1
+#define RETAIN_PACK 2
+
+static int pack_everything;
+static int delta_base_offset = 1;
+static int pack_kept_objects = -1;
+static int write_bitmaps = -1;
+static int use_delta_islands;
+static int run_update_server_info = 1;
+static char *packdir, *packtmp_name, *packtmp;
+
+static const char *const git_repack_usage[] = {
+	N_("git repack [<options>]"),
+	NULL
+};
+
+static const char incremental_bitmap_conflict_error[] = N_(
+"Incremental repacks are incompatible with bitmap indexes.  Use\n"
+"--no-write-bitmap-index or disable the pack.writeBitmaps configuration."
+);
+
+struct pack_objects_args {
+	char *window;
+	char *window_memory;
+	char *depth;
+	char *threads;
+	unsigned long max_pack_size;
+	int no_reuse_delta;
+	int no_reuse_object;
+	int quiet;
+	int local;
+	struct list_objects_filter_options filter_options;
+};
+
+static int repack_config(const char *var, const char *value,
+			 const struct config_context *ctx, void *cb)
+{
+	struct pack_objects_args *cruft_po_args = cb;
+	if (!strcmp(var, "repack.usedeltabaseoffset")) {
+		delta_base_offset = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "repack.packkeptobjects")) {
+		pack_kept_objects = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "repack.writebitmaps") ||
+	    !strcmp(var, "pack.writebitmaps")) {
+		write_bitmaps = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "repack.usedeltaislands")) {
+		use_delta_islands = git_config_bool(var, value);
+		return 0;
+	}
+	if (strcmp(var, "repack.updateserverinfo") == 0) {
+		run_update_server_info = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "repack.cruftwindow")) {
+		free(cruft_po_args->window);
+		return git_config_string(&cruft_po_args->window, var, value);
+	}
+	if (!strcmp(var, "repack.cruftwindowmemory")) {
+		free(cruft_po_args->window_memory);
+		return git_config_string(&cruft_po_args->window_memory, var, value);
+	}
+	if (!strcmp(var, "repack.cruftdepth")) {
+		free(cruft_po_args->depth);
+		return git_config_string(&cruft_po_args->depth, var, value);
+	}
+	if (!strcmp(var, "repack.cruftthreads")) {
+		free(cruft_po_args->threads);
+		return git_config_string(&cruft_po_args->threads, var, value);
+	}
+	return git_default_config(var, value, ctx, cb);
+}
+
+static void pack_objects_args_release(struct pack_objects_args *args)
+{
+	free(args->window);
+	free(args->window_memory);
+	free(args->depth);
+	free(args->threads);
+	list_objects_filter_release(&args->filter_options);
+}
+
+struct existing_packs {
+	struct string_list kept_packs;
+	struct string_list non_kept_packs;
+	struct string_list cruft_packs;
+};
+
+#define EXISTING_PACKS_INIT { \
+	.kept_packs = STRING_LIST_INIT_DUP, \
+	.non_kept_packs = STRING_LIST_INIT_DUP, \
+	.cruft_packs = STRING_LIST_INIT_DUP, \
+}
+
+static int has_existing_non_kept_packs(const struct existing_packs *existing)
+{
+	return existing->non_kept_packs.nr || existing->cruft_packs.nr;
+}
+
+static void pack_mark_for_deletion(struct string_list_item *item)
+{
+	item->util = (void*)((uintptr_t)item->util | DELETE_PACK);
+}
+
+static void pack_unmark_for_deletion(struct string_list_item *item)
+{
+	item->util = (void*)((uintptr_t)item->util & ~DELETE_PACK);
+}
+
+static int pack_is_marked_for_deletion(struct string_list_item *item)
+{
+	return (uintptr_t)item->util & DELETE_PACK;
+}
+
+static void pack_mark_retained(struct string_list_item *item)
+{
+	item->util = (void*)((uintptr_t)item->util | RETAIN_PACK);
+}
+
+static int pack_is_retained(struct string_list_item *item)
+{
+	return (uintptr_t)item->util & RETAIN_PACK;
+}
+
+static void mark_packs_for_deletion_1(struct string_list *names,
+				      struct string_list *list)
+{
+	struct string_list_item *item;
+	const int hexsz = the_hash_algo->hexsz;
+
+	for_each_string_list_item(item, list) {
+		char *sha1;
+		size_t len = strlen(item->string);
+		if (len < hexsz)
+			continue;
+		sha1 = item->string + len - hexsz;
+
+		if (pack_is_retained(item)) {
+			pack_unmark_for_deletion(item);
+		} else if (!string_list_has_string(names, sha1)) {
+			/*
+			 * Mark this pack for deletion, which ensures
+			 * that this pack won't be included in a MIDX
+			 * (if `--write-midx` was given) and that we
+			 * will actually delete this pack (if `-d` was
+			 * given).
+			 */
+			pack_mark_for_deletion(item);
+		}
+	}
+}
+
+static void retain_cruft_pack(struct existing_packs *existing,
+			      struct packed_git *cruft)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct string_list_item *item;
+
+	strbuf_addstr(&buf, pack_basename(cruft));
+	strbuf_strip_suffix(&buf, ".pack");
+
+	item = string_list_lookup(&existing->cruft_packs, buf.buf);
+	if (!item)
+		BUG("could not find cruft pack '%s'", pack_basename(cruft));
+
+	pack_mark_retained(item);
+	strbuf_release(&buf);
+}
+
+static void mark_packs_for_deletion(struct existing_packs *existing,
+				    struct string_list *names)
+
+{
+	mark_packs_for_deletion_1(names, &existing->non_kept_packs);
+	mark_packs_for_deletion_1(names, &existing->cruft_packs);
+}
+
+static void remove_redundant_pack(const char *dir_name, const char *base_name)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct multi_pack_index *m = get_local_multi_pack_index(the_repository);
+	strbuf_addf(&buf, "%s.pack", base_name);
+	if (m && midx_contains_pack(m, buf.buf))
+		clear_midx_file(the_repository);
+	strbuf_insertf(&buf, 0, "%s/", dir_name);
+	unlink_pack_path(buf.buf, 1);
+	strbuf_release(&buf);
+}
+
+static void remove_redundant_packs_1(struct string_list *packs)
+{
+	struct string_list_item *item;
+	for_each_string_list_item(item, packs) {
+		if (!pack_is_marked_for_deletion(item))
+			continue;
+		remove_redundant_pack(packdir, item->string);
+	}
+}
+
+static void remove_redundant_existing_packs(struct existing_packs *existing)
+{
+	remove_redundant_packs_1(&existing->non_kept_packs);
+	remove_redundant_packs_1(&existing->cruft_packs);
+}
+
+static void existing_packs_release(struct existing_packs *existing)
+{
+	string_list_clear(&existing->kept_packs, 0);
+	string_list_clear(&existing->non_kept_packs, 0);
+	string_list_clear(&existing->cruft_packs, 0);
+}
+
+/*
+ * Adds all packs hex strings (pack-$HASH) to either packs->non_kept
+ * or packs->kept based on whether each pack has a corresponding
+ * .keep file or not.  Packs without a .keep file are not to be kept
+ * if we are going to pack everything into one file.
+ */
+static void collect_pack_filenames(struct existing_packs *existing,
+				   const struct string_list *extra_keep)
+{
+	struct packed_git *p;
+	struct strbuf buf = STRBUF_INIT;
+
+	for (p = get_all_packs(the_repository); p; p = p->next) {
+		int i;
+		const char *base;
+
+		if (!p->pack_local)
+			continue;
+
+		base = pack_basename(p);
+
+		for (i = 0; i < extra_keep->nr; i++)
+			if (!fspathcmp(base, extra_keep->items[i].string))
+				break;
+
+		strbuf_reset(&buf);
+		strbuf_addstr(&buf, base);
+		strbuf_strip_suffix(&buf, ".pack");
+
+		if ((extra_keep->nr > 0 && i < extra_keep->nr) || p->pack_keep)
+			string_list_append(&existing->kept_packs, buf.buf);
+		else if (p->is_cruft)
+			string_list_append(&existing->cruft_packs, buf.buf);
+		else
+			string_list_append(&existing->non_kept_packs, buf.buf);
+	}
+
+	string_list_sort(&existing->kept_packs);
+	string_list_sort(&existing->non_kept_packs);
+	string_list_sort(&existing->cruft_packs);
+	strbuf_release(&buf);
+}
+
+static void prepare_pack_objects(struct child_process *cmd,
+				 const struct pack_objects_args *args,
+				 const char *out)
+{
+	strvec_push(&cmd->args, "pack-objects");
+	if (args->window)
+		strvec_pushf(&cmd->args, "--window=%s", args->window);
+	if (args->window_memory)
+		strvec_pushf(&cmd->args, "--window-memory=%s", args->window_memory);
+	if (args->depth)
+		strvec_pushf(&cmd->args, "--depth=%s", args->depth);
+	if (args->threads)
+		strvec_pushf(&cmd->args, "--threads=%s", args->threads);
+	if (args->max_pack_size)
+		strvec_pushf(&cmd->args, "--max-pack-size=%lu", args->max_pack_size);
+	if (args->no_reuse_delta)
+		strvec_pushf(&cmd->args, "--no-reuse-delta");
+	if (args->no_reuse_object)
+		strvec_pushf(&cmd->args, "--no-reuse-object");
+	if (args->local)
+		strvec_push(&cmd->args,  "--local");
+	if (args->quiet)
+		strvec_push(&cmd->args,  "--quiet");
+	if (delta_base_offset)
+		strvec_push(&cmd->args,  "--delta-base-offset");
+	strvec_push(&cmd->args, out);
+	cmd->git_cmd = 1;
+	cmd->out = -1;
+}
+
+/*
+ * Write oid to the given struct child_process's stdin, starting it first if
+ * necessary.
+ */
+static int write_oid(const struct object_id *oid,
+		     struct packed_git *pack UNUSED,
+		     uint32_t pos UNUSED, void *data)
+{
+	struct child_process *cmd = data;
+
+	if (cmd->in == -1) {
+		if (start_command(cmd))
+			die(_("could not start pack-objects to repack promisor objects"));
+	}
+
+	if (write_in_full(cmd->in, oid_to_hex(oid), the_hash_algo->hexsz) < 0 ||
+	    write_in_full(cmd->in, "\n", 1) < 0)
+		die(_("failed to feed promisor objects to pack-objects"));
+	return 0;
+}
+
+static struct {
+	const char *name;
+	unsigned optional:1;
+} exts[] = {
+	{".pack"},
+	{".rev", 1},
+	{".mtimes", 1},
+	{".bitmap", 1},
+	{".promisor", 1},
+	{".idx"},
+};
+
+struct generated_pack_data {
+	struct tempfile *tempfiles[ARRAY_SIZE(exts)];
+};
+
+static struct generated_pack_data *populate_pack_exts(const char *name)
+{
+	struct stat statbuf;
+	struct strbuf path = STRBUF_INIT;
+	struct generated_pack_data *data = xcalloc(1, sizeof(*data));
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(exts); i++) {
+		strbuf_reset(&path);
+		strbuf_addf(&path, "%s-%s%s", packtmp, name, exts[i].name);
+
+		if (stat(path.buf, &statbuf))
+			continue;
+
+		data->tempfiles[i] = register_tempfile(path.buf);
+	}
+
+	strbuf_release(&path);
+	return data;
+}
+
+static int has_pack_ext(const struct generated_pack_data *data,
+			const char *ext)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(exts); i++) {
+		if (strcmp(exts[i].name, ext))
+			continue;
+		return !!data->tempfiles[i];
+	}
+	BUG("unknown pack extension: '%s'", ext);
+}
+
+static void repack_promisor_objects(const struct pack_objects_args *args,
+				    struct string_list *names)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	FILE *out;
+	struct strbuf line = STRBUF_INIT;
+
+	prepare_pack_objects(&cmd, args, packtmp);
+	cmd.in = -1;
+
+	/*
+	 * NEEDSWORK: Giving pack-objects only the OIDs without any ordering
+	 * hints may result in suboptimal deltas in the resulting pack. See if
+	 * the OIDs can be sent with fake paths such that pack-objects can use a
+	 * {type -> existing pack order} ordering when computing deltas instead
+	 * of a {type -> size} ordering, which may produce better deltas.
+	 */
+	for_each_packed_object(the_repository, write_oid, &cmd,
+			       FOR_EACH_OBJECT_PROMISOR_ONLY);
+
+	if (cmd.in == -1) {
+		/* No packed objects; cmd was never started */
+		child_process_clear(&cmd);
+		return;
+	}
+
+	close(cmd.in);
+
+	out = xfdopen(cmd.out, "r");
+	while (strbuf_getline_lf(&line, out) != EOF) {
+		struct string_list_item *item;
+		char *promisor_name;
+
+		if (line.len != the_hash_algo->hexsz)
+			die(_("repack: Expecting full hex object ID lines only from pack-objects."));
+		item = string_list_append(names, line.buf);
+
+		/*
+		 * pack-objects creates the .pack and .idx files, but not the
+		 * .promisor file. Create the .promisor file, which is empty.
+		 *
+		 * NEEDSWORK: fetch-pack sometimes generates non-empty
+		 * .promisor files containing the ref names and associated
+		 * hashes at the point of generation of the corresponding
+		 * packfile, but this would not preserve their contents. Maybe
+		 * concatenate the contents of all .promisor files instead of
+		 * just creating a new empty file.
+		 */
+		promisor_name = mkpathdup("%s-%s.promisor", packtmp,
+					  line.buf);
+		write_promisor_file(promisor_name, NULL, 0);
+
+		item->util = populate_pack_exts(item->string);
+
+		free(promisor_name);
+	}
+
+	fclose(out);
+	if (finish_command(&cmd))
+		die(_("could not finish pack-objects to repack promisor objects"));
+	strbuf_release(&line);
+}
+
+struct pack_geometry {
+	struct packed_git **pack;
+	uint32_t pack_nr, pack_alloc;
+	uint32_t split;
+
+	int split_factor;
+};
+
+static uint32_t geometry_pack_weight(struct packed_git *p)
+{
+	if (open_pack_index(p))
+		die(_("cannot open index for %s"), p->pack_name);
+	return p->num_objects;
+}
+
+static int geometry_cmp(const void *va, const void *vb)
+{
+	uint32_t aw = geometry_pack_weight(*(struct packed_git **)va),
+		 bw = geometry_pack_weight(*(struct packed_git **)vb);
+
+	if (aw < bw)
+		return -1;
+	if (aw > bw)
+		return 1;
+	return 0;
+}
+
+static void init_pack_geometry(struct pack_geometry *geometry,
+			       struct existing_packs *existing,
+			       const struct pack_objects_args *args)
+{
+	struct packed_git *p;
+	struct strbuf buf = STRBUF_INIT;
+
+	for (p = get_all_packs(the_repository); p; p = p->next) {
+		if (args->local && !p->pack_local)
+			/*
+			 * When asked to only repack local packfiles we skip
+			 * over any packfiles that are borrowed from alternate
+			 * object directories.
+			 */
+			continue;
+
+		if (!pack_kept_objects) {
+			/*
+			 * Any pack that has its pack_keep bit set will
+			 * appear in existing->kept_packs below, but
+			 * this saves us from doing a more expensive
+			 * check.
+			 */
+			if (p->pack_keep)
+				continue;
+
+			/*
+			 * The pack may be kept via the --keep-pack
+			 * option; check 'existing->kept_packs' to
+			 * determine whether to ignore it.
+			 */
+			strbuf_reset(&buf);
+			strbuf_addstr(&buf, pack_basename(p));
+			strbuf_strip_suffix(&buf, ".pack");
+
+			if (string_list_has_string(&existing->kept_packs, buf.buf))
+				continue;
+		}
+		if (p->is_cruft)
+			continue;
+
+		ALLOC_GROW(geometry->pack,
+			   geometry->pack_nr + 1,
+			   geometry->pack_alloc);
+
+		geometry->pack[geometry->pack_nr] = p;
+		geometry->pack_nr++;
+	}
+
+	QSORT(geometry->pack, geometry->pack_nr, geometry_cmp);
+	strbuf_release(&buf);
+}
+
+static void split_pack_geometry(struct pack_geometry *geometry)
+{
+	uint32_t i;
+	uint32_t split;
+	off_t total_size = 0;
+
+	if (!geometry->pack_nr) {
+		geometry->split = geometry->pack_nr;
+		return;
+	}
+
+	/*
+	 * First, count the number of packs (in descending order of size) which
+	 * already form a geometric progression.
+	 */
+	for (i = geometry->pack_nr - 1; i > 0; i--) {
+		struct packed_git *ours = geometry->pack[i];
+		struct packed_git *prev = geometry->pack[i - 1];
+
+		if (unsigned_mult_overflows(geometry->split_factor,
+					    geometry_pack_weight(prev)))
+			die(_("pack %s too large to consider in geometric "
+			      "progression"),
+			    prev->pack_name);
+
+		if (geometry_pack_weight(ours) <
+		    geometry->split_factor * geometry_pack_weight(prev))
+			break;
+	}
+
+	split = i;
+
+	if (split) {
+		/*
+		 * Move the split one to the right, since the top element in the
+		 * last-compared pair can't be in the progression. Only do this
+		 * when we split in the middle of the array (otherwise if we got
+		 * to the end, then the split is in the right place).
+		 */
+		split++;
+	}
+
+	/*
+	 * Then, anything to the left of 'split' must be in a new pack. But,
+	 * creating that new pack may cause packs in the heavy half to no longer
+	 * form a geometric progression.
+	 *
+	 * Compute an expected size of the new pack, and then determine how many
+	 * packs in the heavy half need to be joined into it (if any) to restore
+	 * the geometric progression.
+	 */
+	for (i = 0; i < split; i++) {
+		struct packed_git *p = geometry->pack[i];
+
+		if (unsigned_add_overflows(total_size, geometry_pack_weight(p)))
+			die(_("pack %s too large to roll up"), p->pack_name);
+		total_size += geometry_pack_weight(p);
+	}
+	for (i = split; i < geometry->pack_nr; i++) {
+		struct packed_git *ours = geometry->pack[i];
+
+		if (unsigned_mult_overflows(geometry->split_factor,
+					    total_size))
+			die(_("pack %s too large to roll up"), ours->pack_name);
+
+		if (geometry_pack_weight(ours) <
+		    geometry->split_factor * total_size) {
+			if (unsigned_add_overflows(total_size,
+						   geometry_pack_weight(ours)))
+				die(_("pack %s too large to roll up"),
+				    ours->pack_name);
+
+			split++;
+			total_size += geometry_pack_weight(ours);
+		} else
+			break;
+	}
+
+	geometry->split = split;
+}
+
+static struct packed_git *get_preferred_pack(struct pack_geometry *geometry)
+{
+	uint32_t i;
+
+	if (!geometry) {
+		/*
+		 * No geometry means either an all-into-one repack (in which
+		 * case there is only one pack left and it is the largest) or an
+		 * incremental one.
+		 *
+		 * If repacking incrementally, then we could check the size of
+		 * all packs to determine which should be preferred, but leave
+		 * this for later.
+		 */
+		return NULL;
+	}
+	if (geometry->split == geometry->pack_nr)
+		return NULL;
+
+	/*
+	 * The preferred pack is the largest pack above the split line. In
+	 * other words, it is the largest pack that does not get rolled up in
+	 * the geometric repack.
+	 */
+	for (i = geometry->pack_nr; i > geometry->split; i--)
+		/*
+		 * A pack that is not local would never be included in a
+		 * multi-pack index. We thus skip over any non-local packs.
+		 */
+		if (geometry->pack[i - 1]->pack_local)
+			return geometry->pack[i - 1];
+
+	return NULL;
+}
+
+static void geometry_remove_redundant_packs(struct pack_geometry *geometry,
+					    struct string_list *names,
+					    struct existing_packs *existing)
+{
+	struct strbuf buf = STRBUF_INIT;
+	uint32_t i;
+
+	for (i = 0; i < geometry->split; i++) {
+		struct packed_git *p = geometry->pack[i];
+		if (string_list_has_string(names, hash_to_hex(p->hash)))
+			continue;
+
+		strbuf_reset(&buf);
+		strbuf_addstr(&buf, pack_basename(p));
+		strbuf_strip_suffix(&buf, ".pack");
+
+		if ((p->pack_keep) ||
+		    (string_list_has_string(&existing->kept_packs, buf.buf)))
+			continue;
+
+		remove_redundant_pack(packdir, buf.buf);
+	}
+
+	strbuf_release(&buf);
+}
+
+static void free_pack_geometry(struct pack_geometry *geometry)
+{
+	if (!geometry)
+		return;
+
+	free(geometry->pack);
+}
+
+struct midx_snapshot_ref_data {
+	struct tempfile *f;
+	struct oidset seen;
+	int preferred;
+};
+
+static int midx_snapshot_ref_one(const char *refname UNUSED,
+				 const char *referent UNUSED,
+				 const struct object_id *oid,
+				 int flag UNUSED, void *_data)
+{
+	struct midx_snapshot_ref_data *data = _data;
+	struct object_id peeled;
+
+	if (!peel_iterated_oid(the_repository, oid, &peeled))
+		oid = &peeled;
+
+	if (oidset_insert(&data->seen, oid))
+		return 0; /* already seen */
+
+	if (oid_object_info(the_repository, oid, NULL) != OBJ_COMMIT)
+		return 0;
+
+	fprintf(data->f->fp, "%s%s\n", data->preferred ? "+" : "",
+		oid_to_hex(oid));
+
+	return 0;
+}
+
+static void midx_snapshot_refs(struct tempfile *f)
+{
+	struct midx_snapshot_ref_data data;
+	const struct string_list *preferred = bitmap_preferred_tips(the_repository);
+
+	data.f = f;
+	data.preferred = 0;
+	oidset_init(&data.seen, 0);
+
+	if (!fdopen_tempfile(f, "w"))
+		 die(_("could not open tempfile %s for writing"),
+		     get_tempfile_path(f));
+
+	if (preferred) {
+		struct string_list_item *item;
+
+		data.preferred = 1;
+		for_each_string_list_item(item, preferred)
+			refs_for_each_ref_in(get_main_ref_store(the_repository),
+					     item->string,
+					     midx_snapshot_ref_one, &data);
+		data.preferred = 0;
+	}
+
+	refs_for_each_ref(get_main_ref_store(the_repository),
+			  midx_snapshot_ref_one, &data);
+
+	if (close_tempfile_gently(f)) {
+		int save_errno = errno;
+		delete_tempfile(&f);
+		errno = save_errno;
+		die_errno(_("could not close refs snapshot tempfile"));
+	}
+
+	oidset_clear(&data.seen);
+}
+
+static void midx_included_packs(struct string_list *include,
+				struct existing_packs *existing,
+				struct string_list *names,
+				struct pack_geometry *geometry)
+{
+	struct string_list_item *item;
+	struct strbuf buf = STRBUF_INIT;
+
+	for_each_string_list_item(item, &existing->kept_packs) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%s.idx", item->string);
+		string_list_insert(include, buf.buf);
+	}
+
+	for_each_string_list_item(item, names) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "pack-%s.idx", item->string);
+		string_list_insert(include, buf.buf);
+	}
+
+	if (geometry->split_factor) {
+		uint32_t i;
+
+		for (i = geometry->split; i < geometry->pack_nr; i++) {
+			struct packed_git *p = geometry->pack[i];
+
+			/*
+			 * The multi-pack index never refers to packfiles part
+			 * of an alternate object database, so we skip these.
+			 * While git-multi-pack-index(1) would silently ignore
+			 * them anyway, this allows us to skip executing the
+			 * command completely when we have only non-local
+			 * packfiles.
+			 */
+			if (!p->pack_local)
+				continue;
+
+			strbuf_reset(&buf);
+			strbuf_addstr(&buf, pack_basename(p));
+			strbuf_strip_suffix(&buf, ".pack");
+			strbuf_addstr(&buf, ".idx");
+
+			string_list_insert(include, buf.buf);
+		}
+	} else {
+		for_each_string_list_item(item, &existing->non_kept_packs) {
+			if (pack_is_marked_for_deletion(item))
+				continue;
+
+			strbuf_reset(&buf);
+			strbuf_addf(&buf, "%s.idx", item->string);
+			string_list_insert(include, buf.buf);
+		}
+	}
+
+	for_each_string_list_item(item, &existing->cruft_packs) {
+		/*
+		 * When doing a --geometric repack, there is no need to check
+		 * for deleted packs, since we're by definition not doing an
+		 * ALL_INTO_ONE repack (hence no packs will be deleted).
+		 * Otherwise we must check for and exclude any packs which are
+		 * enqueued for deletion.
+		 *
+		 * So we could omit the conditional below in the --geometric
+		 * case, but doing so is unnecessary since no packs are marked
+		 * as pending deletion (since we only call
+		 * `mark_packs_for_deletion()` when doing an all-into-one
+		 * repack).
+		 */
+		if (pack_is_marked_for_deletion(item))
+			continue;
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%s.idx", item->string);
+		string_list_insert(include, buf.buf);
+	}
+
+	strbuf_release(&buf);
+}
+
+static int write_midx_included_packs(struct string_list *include,
+				     struct pack_geometry *geometry,
+				     struct string_list *names,
+				     const char *refs_snapshot,
+				     int show_progress, int write_bitmaps)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	struct string_list_item *item;
+	struct packed_git *preferred = get_preferred_pack(geometry);
+	FILE *in;
+	int ret;
+
+	if (!include->nr)
+		return 0;
+
+	cmd.in = -1;
+	cmd.git_cmd = 1;
+
+	strvec_push(&cmd.args, "multi-pack-index");
+	strvec_pushl(&cmd.args, "write", "--stdin-packs", NULL);
+
+	if (show_progress)
+		strvec_push(&cmd.args, "--progress");
+	else
+		strvec_push(&cmd.args, "--no-progress");
+
+	if (write_bitmaps)
+		strvec_push(&cmd.args, "--bitmap");
+
+	if (preferred)
+		strvec_pushf(&cmd.args, "--preferred-pack=%s",
+			     pack_basename(preferred));
+	else if (names->nr) {
+		/* The largest pack was repacked, meaning that either
+		 * one or two packs exist depending on whether the
+		 * repository has a cruft pack or not.
+		 *
+		 * Select the non-cruft one as preferred to encourage
+		 * pack-reuse among packs containing reachable objects
+		 * over unreachable ones.
+		 *
+		 * (Note we could write multiple packs here if
+		 * `--max-pack-size` was given, but any one of them
+		 * will suffice, so pick the first one.)
+		 */
+		for_each_string_list_item(item, names) {
+			struct generated_pack_data *data = item->util;
+			if (has_pack_ext(data, ".mtimes"))
+				continue;
+
+			strvec_pushf(&cmd.args, "--preferred-pack=pack-%s.pack",
+				     item->string);
+			break;
+		}
+	} else {
+		/*
+		 * No packs were kept, and no packs were written. The
+		 * only thing remaining are .keep packs (unless
+		 * --pack-kept-objects was given).
+		 *
+		 * Set the `--preferred-pack` arbitrarily here.
+		 */
+		;
+	}
+
+	if (refs_snapshot)
+		strvec_pushf(&cmd.args, "--refs-snapshot=%s", refs_snapshot);
+
+	ret = start_command(&cmd);
+	if (ret)
+		return ret;
+
+	in = xfdopen(cmd.in, "w");
+	for_each_string_list_item(item, include)
+		fprintf(in, "%s\n", item->string);
+	fclose(in);
+
+	return finish_command(&cmd);
+}
+
+static void remove_redundant_bitmaps(struct string_list *include,
+				     const char *packdir)
+{
+	struct strbuf path = STRBUF_INIT;
+	struct string_list_item *item;
+	size_t packdir_len;
+
+	strbuf_addstr(&path, packdir);
+	strbuf_addch(&path, '/');
+	packdir_len = path.len;
+
+	/*
+	 * Remove any pack bitmaps corresponding to packs which are now
+	 * included in the MIDX.
+	 */
+	for_each_string_list_item(item, include) {
+		strbuf_addstr(&path, item->string);
+		strbuf_strip_suffix(&path, ".idx");
+		strbuf_addstr(&path, ".bitmap");
+
+		if (unlink(path.buf) && errno != ENOENT)
+			warning_errno(_("could not remove stale bitmap: %s"),
+				      path.buf);
+
+		strbuf_setlen(&path, packdir_len);
+	}
+	strbuf_release(&path);
+}
+
+static int finish_pack_objects_cmd(struct child_process *cmd,
+				   struct string_list *names,
+				   int local)
+{
+	FILE *out;
+	struct strbuf line = STRBUF_INIT;
+
+	out = xfdopen(cmd->out, "r");
+	while (strbuf_getline_lf(&line, out) != EOF) {
+		struct string_list_item *item;
+
+		if (line.len != the_hash_algo->hexsz)
+			die(_("repack: Expecting full hex object ID lines only "
+			      "from pack-objects."));
+		/*
+		 * Avoid putting packs written outside of the repository in the
+		 * list of names.
+		 */
+		if (local) {
+			item = string_list_append(names, line.buf);
+			item->util = populate_pack_exts(line.buf);
+		}
+	}
+	fclose(out);
+
+	strbuf_release(&line);
+
+	return finish_command(cmd);
+}
+
+static int write_filtered_pack(const struct pack_objects_args *args,
+			       const char *destination,
+			       const char *pack_prefix,
+			       struct existing_packs *existing,
+			       struct string_list *names)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	struct string_list_item *item;
+	FILE *in;
+	int ret;
+	const char *caret;
+	const char *scratch;
+	int local = skip_prefix(destination, packdir, &scratch);
+
+	prepare_pack_objects(&cmd, args, destination);
+
+	strvec_push(&cmd.args, "--stdin-packs");
+
+	if (!pack_kept_objects)
+		strvec_push(&cmd.args, "--honor-pack-keep");
+	for_each_string_list_item(item, &existing->kept_packs)
+		strvec_pushf(&cmd.args, "--keep-pack=%s", item->string);
+
+	cmd.in = -1;
+
+	ret = start_command(&cmd);
+	if (ret)
+		return ret;
+
+	/*
+	 * Here 'names' contains only the pack(s) that were just
+	 * written, which is exactly the packs we want to keep. Also
+	 * 'existing_kept_packs' already contains the packs in
+	 * 'keep_pack_list'.
+	 */
+	in = xfdopen(cmd.in, "w");
+	for_each_string_list_item(item, names)
+		fprintf(in, "^%s-%s.pack\n", pack_prefix, item->string);
+	for_each_string_list_item(item, &existing->non_kept_packs)
+		fprintf(in, "%s.pack\n", item->string);
+	for_each_string_list_item(item, &existing->cruft_packs)
+		fprintf(in, "%s.pack\n", item->string);
+	caret = pack_kept_objects ? "" : "^";
+	for_each_string_list_item(item, &existing->kept_packs)
+		fprintf(in, "%s%s.pack\n", caret, item->string);
+	fclose(in);
+
+	return finish_pack_objects_cmd(&cmd, names, local);
+}
+
+static int existing_cruft_pack_cmp(const void *va, const void *vb)
+{
+	struct packed_git *a = *(struct packed_git **)va;
+	struct packed_git *b = *(struct packed_git **)vb;
+
+	if (a->pack_size < b->pack_size)
+		return -1;
+	if (a->pack_size > b->pack_size)
+		return 1;
+	return 0;
+}
+
+static void collapse_small_cruft_packs(FILE *in, size_t max_size,
+				       struct existing_packs *existing)
+{
+	struct packed_git **existing_cruft, *p;
+	struct strbuf buf = STRBUF_INIT;
+	size_t total_size = 0;
+	size_t existing_cruft_nr = 0;
+	size_t i;
+
+	ALLOC_ARRAY(existing_cruft, existing->cruft_packs.nr);
+
+	for (p = get_all_packs(the_repository); p; p = p->next) {
+		if (!(p->is_cruft && p->pack_local))
+			continue;
+
+		strbuf_reset(&buf);
+		strbuf_addstr(&buf, pack_basename(p));
+		strbuf_strip_suffix(&buf, ".pack");
+
+		if (!string_list_has_string(&existing->cruft_packs, buf.buf))
+			continue;
+
+		if (existing_cruft_nr >= existing->cruft_packs.nr)
+			BUG("too many cruft packs (found %"PRIuMAX", but knew "
+			    "of %"PRIuMAX")",
+			    (uintmax_t)existing_cruft_nr + 1,
+			    (uintmax_t)existing->cruft_packs.nr);
+		existing_cruft[existing_cruft_nr++] = p;
+	}
+
+	QSORT(existing_cruft, existing_cruft_nr, existing_cruft_pack_cmp);
+
+	for (i = 0; i < existing_cruft_nr; i++) {
+		size_t proposed;
+
+		p = existing_cruft[i];
+		proposed = st_add(total_size, p->pack_size);
+
+		if (proposed <= max_size) {
+			total_size = proposed;
+			fprintf(in, "-%s\n", pack_basename(p));
+		} else {
+			retain_cruft_pack(existing, p);
+			fprintf(in, "%s\n", pack_basename(p));
+		}
+	}
+
+	for (i = 0; i < existing->non_kept_packs.nr; i++)
+		fprintf(in, "-%s.pack\n",
+			existing->non_kept_packs.items[i].string);
+
+	strbuf_release(&buf);
+	free(existing_cruft);
+}
+
+static int write_cruft_pack(const struct pack_objects_args *args,
+			    const char *destination,
+			    const char *pack_prefix,
+			    const char *cruft_expiration,
+			    struct string_list *names,
+			    struct existing_packs *existing)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	struct string_list_item *item;
+	FILE *in;
+	int ret;
+	const char *scratch;
+	int local = skip_prefix(destination, packdir, &scratch);
+
+	prepare_pack_objects(&cmd, args, destination);
+
+	strvec_push(&cmd.args, "--cruft");
+	if (cruft_expiration)
+		strvec_pushf(&cmd.args, "--cruft-expiration=%s",
+			     cruft_expiration);
+
+	strvec_push(&cmd.args, "--honor-pack-keep");
+	strvec_push(&cmd.args, "--non-empty");
+
+	cmd.in = -1;
+
+	ret = start_command(&cmd);
+	if (ret)
+		return ret;
+
+	/*
+	 * names has a confusing double use: it both provides the list
+	 * of just-written new packs, and accepts the name of the cruft
+	 * pack we are writing.
+	 *
+	 * By the time it is read here, it contains only the pack(s)
+	 * that were just written, which is exactly the set of packs we
+	 * want to consider kept.
+	 *
+	 * If `--expire-to` is given, the double-use served by `names`
+	 * ensures that the pack written to `--expire-to` excludes any
+	 * objects contained in the cruft pack.
+	 */
+	in = xfdopen(cmd.in, "w");
+	for_each_string_list_item(item, names)
+		fprintf(in, "%s-%s.pack\n", pack_prefix, item->string);
+	if (args->max_pack_size && !cruft_expiration) {
+		collapse_small_cruft_packs(in, args->max_pack_size, existing);
+	} else {
+		for_each_string_list_item(item, &existing->non_kept_packs)
+			fprintf(in, "-%s.pack\n", item->string);
+		for_each_string_list_item(item, &existing->cruft_packs)
+			fprintf(in, "-%s.pack\n", item->string);
+	}
+	for_each_string_list_item(item, &existing->kept_packs)
+		fprintf(in, "%s.pack\n", item->string);
+	fclose(in);
+
+	return finish_pack_objects_cmd(&cmd, names, local);
+}
+
+static const char *find_pack_prefix(const char *packdir, const char *packtmp)
+{
+	const char *pack_prefix;
+	if (!skip_prefix(packtmp, packdir, &pack_prefix))
+		die(_("pack prefix %s does not begin with objdir %s"),
+		    packtmp, packdir);
+	if (*pack_prefix == '/')
+		pack_prefix++;
+	return pack_prefix;
+}
+
+int cmd_repack(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	struct string_list_item *item;
+	struct string_list names = STRING_LIST_INIT_DUP;
+	struct existing_packs existing = EXISTING_PACKS_INIT;
+	struct pack_geometry geometry = { 0 };
+	struct tempfile *refs_snapshot = NULL;
+	int i, ext, ret;
+	int show_progress;
+
+	/* variables to be filled by option parsing */
+	int delete_redundant = 0;
+	const char *unpack_unreachable = NULL;
+	int keep_unreachable = 0;
+	struct string_list keep_pack_list = STRING_LIST_INIT_NODUP;
+	struct pack_objects_args po_args = { 0 };
+	struct pack_objects_args cruft_po_args = { 0 };
+	int write_midx = 0;
+	const char *cruft_expiration = NULL;
+	const char *expire_to = NULL;
+	const char *filter_to = NULL;
+	const char *opt_window = NULL;
+	const char *opt_window_memory = NULL;
+	const char *opt_depth = NULL;
+	const char *opt_threads = NULL;
+
+	struct option builtin_repack_options[] = {
+		OPT_BIT('a', NULL, &pack_everything,
+				N_("pack everything in a single pack"), ALL_INTO_ONE),
+		OPT_BIT('A', NULL, &pack_everything,
+				N_("same as -a, and turn unreachable objects loose"),
+				   LOOSEN_UNREACHABLE | ALL_INTO_ONE),
+		OPT_BIT(0, "cruft", &pack_everything,
+				N_("same as -a, pack unreachable cruft objects separately"),
+				   PACK_CRUFT),
+		OPT_STRING(0, "cruft-expiration", &cruft_expiration, N_("approxidate"),
+				N_("with --cruft, expire objects older than this")),
+		OPT_MAGNITUDE(0, "max-cruft-size", &cruft_po_args.max_pack_size,
+				N_("with --cruft, limit the size of new cruft packs")),
+		OPT_BOOL('d', NULL, &delete_redundant,
+				N_("remove redundant packs, and run git-prune-packed")),
+		OPT_BOOL('f', NULL, &po_args.no_reuse_delta,
+				N_("pass --no-reuse-delta to git-pack-objects")),
+		OPT_BOOL('F', NULL, &po_args.no_reuse_object,
+				N_("pass --no-reuse-object to git-pack-objects")),
+		OPT_NEGBIT('n', NULL, &run_update_server_info,
+				N_("do not run git-update-server-info"), 1),
+		OPT__QUIET(&po_args.quiet, N_("be quiet")),
+		OPT_BOOL('l', "local", &po_args.local,
+				N_("pass --local to git-pack-objects")),
+		OPT_BOOL('b', "write-bitmap-index", &write_bitmaps,
+				N_("write bitmap index")),
+		OPT_BOOL('i', "delta-islands", &use_delta_islands,
+				N_("pass --delta-islands to git-pack-objects")),
+		OPT_STRING(0, "unpack-unreachable", &unpack_unreachable, N_("approxidate"),
+				N_("with -A, do not loosen objects older than this")),
+		OPT_BOOL('k', "keep-unreachable", &keep_unreachable,
+				N_("with -a, repack unreachable objects")),
+		OPT_STRING(0, "window", &opt_window, N_("n"),
+				N_("size of the window used for delta compression")),
+		OPT_STRING(0, "window-memory", &opt_window_memory, N_("bytes"),
+				N_("same as the above, but limit memory size instead of entries count")),
+		OPT_STRING(0, "depth", &opt_depth, N_("n"),
+				N_("limits the maximum delta depth")),
+		OPT_STRING(0, "threads", &opt_threads, N_("n"),
+				N_("limits the maximum number of threads")),
+		OPT_MAGNITUDE(0, "max-pack-size", &po_args.max_pack_size,
+				N_("maximum size of each packfile")),
+		OPT_PARSE_LIST_OBJECTS_FILTER(&po_args.filter_options),
+		OPT_BOOL(0, "pack-kept-objects", &pack_kept_objects,
+				N_("repack objects in packs marked with .keep")),
+		OPT_STRING_LIST(0, "keep-pack", &keep_pack_list, N_("name"),
+				N_("do not repack this pack")),
+		OPT_INTEGER('g', "geometric", &geometry.split_factor,
+			    N_("find a geometric progression with factor <N>")),
+		OPT_BOOL('m', "write-midx", &write_midx,
+			   N_("write a multi-pack index of the resulting packs")),
+		OPT_STRING(0, "expire-to", &expire_to, N_("dir"),
+			   N_("pack prefix to store a pack containing pruned objects")),
+		OPT_STRING(0, "filter-to", &filter_to, N_("dir"),
+			   N_("pack prefix to store a pack containing filtered out objects")),
+		OPT_END()
+	};
+
+	list_objects_filter_init(&po_args.filter_options);
+
+	git_config(repack_config, &cruft_po_args);
+
+	argc = parse_options(argc, argv, prefix, builtin_repack_options,
+				git_repack_usage, 0);
+
+	po_args.window = xstrdup_or_null(opt_window);
+	po_args.window_memory = xstrdup_or_null(opt_window_memory);
+	po_args.depth = xstrdup_or_null(opt_depth);
+	po_args.threads = xstrdup_or_null(opt_threads);
+
+	if (delete_redundant && repository_format_precious_objects)
+		die(_("cannot delete packs in a precious-objects repo"));
+
+	die_for_incompatible_opt3(unpack_unreachable || (pack_everything & LOOSEN_UNREACHABLE), "-A",
+				  keep_unreachable, "-k/--keep-unreachable",
+				  pack_everything & PACK_CRUFT, "--cruft");
+
+	if (pack_everything & PACK_CRUFT)
+		pack_everything |= ALL_INTO_ONE;
+
+	if (write_bitmaps < 0) {
+		if (!write_midx &&
+		    (!(pack_everything & ALL_INTO_ONE) || !is_bare_repository()))
+			write_bitmaps = 0;
+	}
+	if (pack_kept_objects < 0)
+		pack_kept_objects = write_bitmaps > 0 && !write_midx;
+
+	if (write_bitmaps && !(pack_everything & ALL_INTO_ONE) && !write_midx)
+		die(_(incremental_bitmap_conflict_error));
+
+	if (write_bitmaps && po_args.local && has_alt_odb(the_repository)) {
+		/*
+		 * When asked to do a local repack, but we have
+		 * packfiles that are inherited from an alternate, then
+		 * we cannot guarantee that the multi-pack-index would
+		 * have full coverage of all objects. We thus disable
+		 * writing bitmaps in that case.
+		 */
+		warning(_("disabling bitmap writing, as some objects are not being packed"));
+		write_bitmaps = 0;
+	}
+
+	if (write_midx && write_bitmaps) {
+		struct strbuf path = STRBUF_INIT;
+
+		strbuf_addf(&path, "%s/%s_XXXXXX", repo_get_object_directory(the_repository),
+			    "bitmap-ref-tips");
+
+		refs_snapshot = xmks_tempfile(path.buf);
+		midx_snapshot_refs(refs_snapshot);
+
+		strbuf_release(&path);
+	}
+
+	packdir = mkpathdup("%s/pack", repo_get_object_directory(the_repository));
+	packtmp_name = xstrfmt(".tmp-%d-pack", (int)getpid());
+	packtmp = mkpathdup("%s/%s", packdir, packtmp_name);
+
+	collect_pack_filenames(&existing, &keep_pack_list);
+
+	if (geometry.split_factor) {
+		if (pack_everything)
+			die(_("options '%s' and '%s' cannot be used together"), "--geometric", "-A/-a");
+		init_pack_geometry(&geometry, &existing, &po_args);
+		split_pack_geometry(&geometry);
+	}
+
+	prepare_pack_objects(&cmd, &po_args, packtmp);
+
+	show_progress = !po_args.quiet && isatty(2);
+
+	strvec_push(&cmd.args, "--keep-true-parents");
+	if (!pack_kept_objects)
+		strvec_push(&cmd.args, "--honor-pack-keep");
+	for (i = 0; i < keep_pack_list.nr; i++)
+		strvec_pushf(&cmd.args, "--keep-pack=%s",
+			     keep_pack_list.items[i].string);
+	strvec_push(&cmd.args, "--non-empty");
+	if (!geometry.split_factor) {
+		/*
+		 * We need to grab all reachable objects, including those that
+		 * are reachable from reflogs and the index.
+		 *
+		 * When repacking into a geometric progression of packs,
+		 * however, we ask 'git pack-objects --stdin-packs', and it is
+		 * not about packing objects based on reachability but about
+		 * repacking all the objects in specified packs and loose ones
+		 * (indeed, --stdin-packs is incompatible with these options).
+		 */
+		strvec_push(&cmd.args, "--all");
+		strvec_push(&cmd.args, "--reflog");
+		strvec_push(&cmd.args, "--indexed-objects");
+	}
+	if (repo_has_promisor_remote(the_repository))
+		strvec_push(&cmd.args, "--exclude-promisor-objects");
+	if (!write_midx) {
+		if (write_bitmaps > 0)
+			strvec_push(&cmd.args, "--write-bitmap-index");
+		else if (write_bitmaps < 0)
+			strvec_push(&cmd.args, "--write-bitmap-index-quiet");
+	}
+	if (use_delta_islands)
+		strvec_push(&cmd.args, "--delta-islands");
+
+	if (pack_everything & ALL_INTO_ONE) {
+		repack_promisor_objects(&po_args, &names);
+
+		if (has_existing_non_kept_packs(&existing) &&
+		    delete_redundant &&
+		    !(pack_everything & PACK_CRUFT)) {
+			for_each_string_list_item(item, &names) {
+				strvec_pushf(&cmd.args, "--keep-pack=%s-%s.pack",
+					     packtmp_name, item->string);
+			}
+			if (unpack_unreachable) {
+				strvec_pushf(&cmd.args,
+					     "--unpack-unreachable=%s",
+					     unpack_unreachable);
+			} else if (pack_everything & LOOSEN_UNREACHABLE) {
+				strvec_push(&cmd.args,
+					    "--unpack-unreachable");
+			} else if (keep_unreachable) {
+				strvec_push(&cmd.args, "--keep-unreachable");
+				strvec_push(&cmd.args, "--pack-loose-unreachable");
+			}
+		}
+	} else if (geometry.split_factor) {
+		strvec_push(&cmd.args, "--stdin-packs");
+		strvec_push(&cmd.args, "--unpacked");
+	} else {
+		strvec_push(&cmd.args, "--unpacked");
+		strvec_push(&cmd.args, "--incremental");
+	}
+
+	if (po_args.filter_options.choice)
+		strvec_pushf(&cmd.args, "--filter=%s",
+			     expand_list_objects_filter_spec(&po_args.filter_options));
+	else if (filter_to)
+		die(_("option '%s' can only be used along with '%s'"), "--filter-to", "--filter");
+
+	if (geometry.split_factor)
+		cmd.in = -1;
+	else
+		cmd.no_stdin = 1;
+
+	ret = start_command(&cmd);
+	if (ret)
+		goto cleanup;
+
+	if (geometry.split_factor) {
+		FILE *in = xfdopen(cmd.in, "w");
+		/*
+		 * The resulting pack should contain all objects in packs that
+		 * are going to be rolled up, but exclude objects in packs which
+		 * are being left alone.
+		 */
+		for (i = 0; i < geometry.split; i++)
+			fprintf(in, "%s\n", pack_basename(geometry.pack[i]));
+		for (i = geometry.split; i < geometry.pack_nr; i++)
+			fprintf(in, "^%s\n", pack_basename(geometry.pack[i]));
+		fclose(in);
+	}
+
+	ret = finish_pack_objects_cmd(&cmd, &names, 1);
+	if (ret)
+		goto cleanup;
+
+	if (!names.nr && !po_args.quiet)
+		printf_ln(_("Nothing new to pack."));
+
+	if (pack_everything & PACK_CRUFT) {
+		const char *pack_prefix = find_pack_prefix(packdir, packtmp);
+
+		if (!cruft_po_args.window)
+			cruft_po_args.window = xstrdup_or_null(po_args.window);
+		if (!cruft_po_args.window_memory)
+			cruft_po_args.window_memory = xstrdup_or_null(po_args.window_memory);
+		if (!cruft_po_args.depth)
+			cruft_po_args.depth = xstrdup_or_null(po_args.depth);
+		if (!cruft_po_args.threads)
+			cruft_po_args.threads = xstrdup_or_null(po_args.threads);
+		if (!cruft_po_args.max_pack_size)
+			cruft_po_args.max_pack_size = po_args.max_pack_size;
+
+		cruft_po_args.local = po_args.local;
+		cruft_po_args.quiet = po_args.quiet;
+
+		ret = write_cruft_pack(&cruft_po_args, packtmp, pack_prefix,
+				       cruft_expiration, &names,
+				       &existing);
+		if (ret)
+			goto cleanup;
+
+		if (delete_redundant && expire_to) {
+			/*
+			 * If `--expire-to` is given with `-d`, it's possible
+			 * that we're about to prune some objects. With cruft
+			 * packs, pruning is implicit: any objects from existing
+			 * packs that weren't picked up by new packs are removed
+			 * when their packs are deleted.
+			 *
+			 * Generate an additional cruft pack, with one twist:
+			 * `names` now includes the name of the cruft pack
+			 * written in the previous step. So the contents of
+			 * _this_ cruft pack exclude everything contained in the
+			 * existing cruft pack (that is, all of the unreachable
+			 * objects which are no older than
+			 * `--cruft-expiration`).
+			 *
+			 * To make this work, cruft_expiration must become NULL
+			 * so that this cruft pack doesn't actually prune any
+			 * objects. If it were non-NULL, this call would always
+			 * generate an empty pack (since every object not in the
+			 * cruft pack generated above will have an mtime older
+			 * than the expiration).
+			 */
+			ret = write_cruft_pack(&cruft_po_args, expire_to,
+					       pack_prefix,
+					       NULL,
+					       &names,
+					       &existing);
+			if (ret)
+				goto cleanup;
+		}
+	}
+
+	if (po_args.filter_options.choice) {
+		if (!filter_to)
+			filter_to = packtmp;
+
+		ret = write_filtered_pack(&po_args,
+					  filter_to,
+					  find_pack_prefix(packdir, packtmp),
+					  &existing,
+					  &names);
+		if (ret)
+			goto cleanup;
+	}
+
+	string_list_sort(&names);
+
+	close_object_store(the_repository->objects);
+
+	/*
+	 * Ok we have prepared all new packfiles.
+	 */
+	for_each_string_list_item(item, &names) {
+		struct generated_pack_data *data = item->util;
+
+		for (ext = 0; ext < ARRAY_SIZE(exts); ext++) {
+			char *fname;
+
+			fname = mkpathdup("%s/pack-%s%s",
+					packdir, item->string, exts[ext].name);
+
+			if (data->tempfiles[ext]) {
+				const char *fname_old = get_tempfile_path(data->tempfiles[ext]);
+				struct stat statbuffer;
+
+				if (!stat(fname_old, &statbuffer)) {
+					statbuffer.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+					chmod(fname_old, statbuffer.st_mode);
+				}
+
+				if (rename_tempfile(&data->tempfiles[ext], fname))
+					die_errno(_("renaming pack to '%s' failed"), fname);
+			} else if (!exts[ext].optional)
+				die(_("pack-objects did not write a '%s' file for pack %s-%s"),
+				    exts[ext].name, packtmp, item->string);
+			else if (unlink(fname) < 0 && errno != ENOENT)
+				die_errno(_("could not unlink: %s"), fname);
+
+			free(fname);
+		}
+	}
+	/* End of pack replacement. */
+
+	if (delete_redundant && pack_everything & ALL_INTO_ONE)
+		mark_packs_for_deletion(&existing, &names);
+
+	if (write_midx) {
+		struct string_list include = STRING_LIST_INIT_DUP;
+		midx_included_packs(&include, &existing, &names, &geometry);
+
+		ret = write_midx_included_packs(&include, &geometry, &names,
+						refs_snapshot ? get_tempfile_path(refs_snapshot) : NULL,
+						show_progress, write_bitmaps > 0);
+
+		if (!ret && write_bitmaps)
+			remove_redundant_bitmaps(&include, packdir);
+
+		string_list_clear(&include, 0);
+
+		if (ret)
+			goto cleanup;
+	}
+
+	reprepare_packed_git(the_repository);
+
+	if (delete_redundant) {
+		int opts = 0;
+		remove_redundant_existing_packs(&existing);
+
+		if (geometry.split_factor)
+			geometry_remove_redundant_packs(&geometry, &names,
+							&existing);
+		if (show_progress)
+			opts |= PRUNE_PACKED_VERBOSE;
+		prune_packed_objects(opts);
+
+		if (!keep_unreachable &&
+		    (!(pack_everything & LOOSEN_UNREACHABLE) ||
+		     unpack_unreachable) &&
+		    is_repository_shallow(the_repository))
+			prune_shallow(PRUNE_QUICK);
+	}
+
+	if (run_update_server_info)
+		update_server_info(the_repository, 0);
+
+	if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX, 0)) {
+		unsigned flags = 0;
+		if (git_env_bool(GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL, 0))
+			flags |= MIDX_WRITE_INCREMENTAL;
+		write_midx_file(the_repository, repo_get_object_directory(the_repository),
+				NULL, NULL, flags);
+	}
+
+cleanup:
+	string_list_clear(&keep_pack_list, 0);
+	string_list_clear(&names, 1);
+	existing_packs_release(&existing);
+	free_pack_geometry(&geometry);
+	pack_objects_args_release(&po_args);
+	pack_objects_args_release(&cruft_po_args);
+
+	return ret;
+}
diff --git a/builtin/replace.c b/builtin/replace.c
new file mode 100644
index 0000000000..a4eaadff91
--- /dev/null
+++ b/builtin/replace.c
@@ -0,0 +1,640 @@
+/*
+ * Builtin "git replace"
+ *
+ * Copyright (c) 2008 Christian Couder <chriscool@xxxxxxxxxxxxx>
+ *
+ * Based on builtin/tag.c by Kristian Høgsberg <krh@xxxxxxxxxx>
+ * and Carlos Rica <jasampler@xxxxxxxxx> that was itself based on
+ * git-tag.sh and mktag.c by Linus Torvalds.
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "editor.h"
+#include "gettext.h"
+#include "hex.h"
+#include "refs.h"
+#include "parse-options.h"
+#include "path.h"
+#include "run-command.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "replace-object.h"
+#include "tag.h"
+#include "wildmatch.h"
+
+static const char * const git_replace_usage[] = {
+	N_("git replace [-f] <object> <replacement>"),
+	N_("git replace [-f] --edit <object>"),
+	N_("git replace [-f] --graft <commit> [<parent>...]"),
+	"git replace [-f] --convert-graft-file",
+	N_("git replace -d <object>..."),
+	N_("git replace [--format=<format>] [-l [<pattern>]]"),
+	NULL
+};
+
+enum replace_format {
+	REPLACE_FORMAT_SHORT,
+	REPLACE_FORMAT_MEDIUM,
+	REPLACE_FORMAT_LONG
+};
+
+struct show_data {
+	struct repository *repo;
+	const char *pattern;
+	enum replace_format format;
+};
+
+static int show_reference(const char *refname,
+			  const char *referent UNUSED,
+			  const struct object_id *oid,
+			  int flag UNUSED, void *cb_data)
+{
+	struct show_data *data = cb_data;
+
+	if (!wildmatch(data->pattern, refname, 0)) {
+		if (data->format == REPLACE_FORMAT_SHORT)
+			printf("%s\n", refname);
+		else if (data->format == REPLACE_FORMAT_MEDIUM)
+			printf("%s -> %s\n", refname, oid_to_hex(oid));
+		else { /* data->format == REPLACE_FORMAT_LONG */
+			struct object_id object;
+			enum object_type obj_type, repl_type;
+
+			if (repo_get_oid(data->repo, refname, &object))
+				return error(_("failed to resolve '%s' as a valid ref"), refname);
+
+			obj_type = oid_object_info(data->repo, &object, NULL);
+			repl_type = oid_object_info(data->repo, oid, NULL);
+
+			printf("%s (%s) -> %s (%s)\n", refname, type_name(obj_type),
+			       oid_to_hex(oid), type_name(repl_type));
+		}
+	}
+
+	return 0;
+}
+
+static int list_replace_refs(const char *pattern, const char *format)
+{
+	struct show_data data;
+
+	data.repo = the_repository;
+	if (!pattern)
+		pattern = "*";
+	data.pattern = pattern;
+
+	if (format == NULL || *format == '\0' || !strcmp(format, "short"))
+		data.format = REPLACE_FORMAT_SHORT;
+	else if (!strcmp(format, "medium"))
+		data.format = REPLACE_FORMAT_MEDIUM;
+	else if (!strcmp(format, "long"))
+		data.format = REPLACE_FORMAT_LONG;
+	/*
+	 * Please update _git_replace() in git-completion.bash when
+	 * you add new format
+	 */
+	else
+		return error(_("invalid replace format '%s'\n"
+			       "valid formats are 'short', 'medium' and 'long'"),
+			     format);
+
+	refs_for_each_replace_ref(get_main_ref_store(the_repository),
+				  show_reference, (void *)&data);
+
+	return 0;
+}
+
+typedef int (*each_replace_name_fn)(const char *name, const char *ref,
+				    const struct object_id *oid);
+
+static int for_each_replace_name(const char **argv, each_replace_name_fn fn)
+{
+	const char **p, *full_hex;
+	struct strbuf ref = STRBUF_INIT;
+	size_t base_len;
+	int had_error = 0;
+	struct object_id oid;
+	const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
+
+	strbuf_addstr(&ref, git_replace_ref_base);
+	base_len = ref.len;
+
+	for (p = argv; *p; p++) {
+		if (repo_get_oid(the_repository, *p, &oid)) {
+			error("failed to resolve '%s' as a valid ref", *p);
+			had_error = 1;
+			continue;
+		}
+
+		strbuf_setlen(&ref, base_len);
+		strbuf_addstr(&ref, oid_to_hex(&oid));
+		full_hex = ref.buf + base_len;
+
+		if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &oid)) {
+			error(_("replace ref '%s' not found"), full_hex);
+			had_error = 1;
+			continue;
+		}
+		if (fn(full_hex, ref.buf, &oid))
+			had_error = 1;
+	}
+	strbuf_release(&ref);
+	return had_error;
+}
+
+static int delete_replace_ref(const char *name, const char *ref,
+			      const struct object_id *oid)
+{
+	if (refs_delete_ref(get_main_ref_store(the_repository), NULL, ref, oid, 0))
+		return 1;
+	printf_ln(_("Deleted replace ref '%s'"), name);
+	return 0;
+}
+
+static int check_ref_valid(struct object_id *object,
+			    struct object_id *prev,
+			    struct strbuf *ref,
+			    int force)
+{
+	const char *git_replace_ref_base = ref_namespace[NAMESPACE_REPLACE].ref;
+
+	strbuf_reset(ref);
+	strbuf_addf(ref, "%s%s", git_replace_ref_base, oid_to_hex(object));
+	if (check_refname_format(ref->buf, 0))
+		return error(_("'%s' is not a valid ref name"), ref->buf);
+
+	if (refs_read_ref(get_main_ref_store(the_repository), ref->buf, prev))
+		oidclr(prev, the_repository->hash_algo);
+	else if (!force)
+		return error(_("replace ref '%s' already exists"), ref->buf);
+	return 0;
+}
+
+static int replace_object_oid(const char *object_ref,
+			       struct object_id *object,
+			       const char *replace_ref,
+			       struct object_id *repl,
+			       int force)
+{
+	struct object_id prev;
+	enum object_type obj_type, repl_type;
+	struct strbuf ref = STRBUF_INIT;
+	struct ref_transaction *transaction;
+	struct strbuf err = STRBUF_INIT;
+	int res = 0;
+
+	obj_type = oid_object_info(the_repository, object, NULL);
+	repl_type = oid_object_info(the_repository, repl, NULL);
+	if (!force && obj_type != repl_type)
+		return error(_("Objects must be of the same type.\n"
+			       "'%s' points to a replaced object of type '%s'\n"
+			       "while '%s' points to a replacement object of "
+			       "type '%s'."),
+			     object_ref, type_name(obj_type),
+			     replace_ref, type_name(repl_type));
+
+	if (check_ref_valid(object, &prev, &ref, force)) {
+		strbuf_release(&ref);
+		return -1;
+	}
+
+	transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+						  0, &err);
+	if (!transaction ||
+	    ref_transaction_update(transaction, ref.buf, repl, &prev,
+				   NULL, NULL, 0, NULL, &err) ||
+	    ref_transaction_commit(transaction, &err))
+		res = error("%s", err.buf);
+
+	ref_transaction_free(transaction);
+	strbuf_release(&ref);
+	return res;
+}
+
+static int replace_object(const char *object_ref, const char *replace_ref, int force)
+{
+	struct object_id object, repl;
+
+	if (repo_get_oid(the_repository, object_ref, &object))
+		return error(_("failed to resolve '%s' as a valid ref"),
+			     object_ref);
+	if (repo_get_oid(the_repository, replace_ref, &repl))
+		return error(_("failed to resolve '%s' as a valid ref"),
+			     replace_ref);
+
+	return replace_object_oid(object_ref, &object, replace_ref, &repl, force);
+}
+
+/*
+ * Write the contents of the object named by "sha1" to the file "filename".
+ * If "raw" is true, then the object's raw contents are printed according to
+ * "type". Otherwise, we pretty-print the contents for human editing.
+ */
+static int export_object(const struct object_id *oid, enum object_type type,
+			  int raw, const char *filename)
+{
+	struct child_process cmd = CHILD_PROCESS_INIT;
+	int fd;
+
+	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+	if (fd < 0)
+		return error_errno(_("unable to open %s for writing"), filename);
+
+	strvec_push(&cmd.args, "--no-replace-objects");
+	strvec_push(&cmd.args, "cat-file");
+	if (raw)
+		strvec_push(&cmd.args, type_name(type));
+	else
+		strvec_push(&cmd.args, "-p");
+	strvec_push(&cmd.args, oid_to_hex(oid));
+	cmd.git_cmd = 1;
+	cmd.out = fd;
+
+	if (run_command(&cmd))
+		return error(_("cat-file reported failure"));
+	return 0;
+}
+
+/*
+ * Read a previously-exported (and possibly edited) object back from "filename",
+ * interpreting it as "type", and writing the result to the object database.
+ * The sha1 of the written object is returned via sha1.
+ */
+static int import_object(struct object_id *oid, enum object_type type,
+			  int raw, const char *filename)
+{
+	int fd;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0)
+		return error_errno(_("unable to open %s for reading"), filename);
+
+	if (!raw && type == OBJ_TREE) {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+		struct strbuf result = STRBUF_INIT;
+
+		strvec_push(&cmd.args, "mktree");
+		cmd.git_cmd = 1;
+		cmd.in = fd;
+		cmd.out = -1;
+
+		if (start_command(&cmd)) {
+			close(fd);
+			return error(_("unable to spawn mktree"));
+		}
+
+		if (strbuf_read(&result, cmd.out, the_hash_algo->hexsz + 1) < 0) {
+			error_errno(_("unable to read from mktree"));
+			close(fd);
+			close(cmd.out);
+			return -1;
+		}
+		close(cmd.out);
+
+		if (finish_command(&cmd)) {
+			strbuf_release(&result);
+			return error(_("mktree reported failure"));
+		}
+		if (get_oid_hex(result.buf, oid) < 0) {
+			strbuf_release(&result);
+			return error(_("mktree did not return an object name"));
+		}
+
+		strbuf_release(&result);
+	} else {
+		struct stat st;
+		int flags = HASH_FORMAT_CHECK | HASH_WRITE_OBJECT;
+
+		if (fstat(fd, &st) < 0) {
+			error_errno(_("unable to fstat %s"), filename);
+			close(fd);
+			return -1;
+		}
+		if (index_fd(the_repository->index, oid, fd, &st, type, NULL, flags) < 0)
+			return error(_("unable to write object to database"));
+		/* index_fd close()s fd for us */
+	}
+
+	/*
+	 * No need to close(fd) here; both run-command and index-fd
+	 * will have done it for us.
+	 */
+	return 0;
+}
+
+static int edit_and_replace(const char *object_ref, int force, int raw)
+{
+	char *tmpfile;
+	enum object_type type;
+	struct object_id old_oid, new_oid, prev;
+	struct strbuf ref = STRBUF_INIT;
+
+	if (repo_get_oid(the_repository, object_ref, &old_oid) < 0)
+		return error(_("not a valid object name: '%s'"), object_ref);
+
+	type = oid_object_info(the_repository, &old_oid, NULL);
+	if (type < 0)
+		return error(_("unable to get object type for %s"),
+			     oid_to_hex(&old_oid));
+
+	if (check_ref_valid(&old_oid, &prev, &ref, force)) {
+		strbuf_release(&ref);
+		return -1;
+	}
+	strbuf_release(&ref);
+
+	tmpfile = git_pathdup("REPLACE_EDITOBJ");
+	if (export_object(&old_oid, type, raw, tmpfile)) {
+		free(tmpfile);
+		return -1;
+	}
+	if (launch_editor(tmpfile, NULL, NULL) < 0) {
+		free(tmpfile);
+		return error(_("editing object file failed"));
+	}
+	if (import_object(&new_oid, type, raw, tmpfile)) {
+		free(tmpfile);
+		return -1;
+	}
+	free(tmpfile);
+
+	if (oideq(&old_oid, &new_oid))
+		return error(_("new object is the same as the old one: '%s'"), oid_to_hex(&old_oid));
+
+	return replace_object_oid(object_ref, &old_oid, "replacement", &new_oid, force);
+}
+
+static int replace_parents(struct strbuf *buf, int argc, const char **argv)
+{
+	struct strbuf new_parents = STRBUF_INIT;
+	const char *parent_start, *parent_end;
+	int i;
+	const unsigned hexsz = the_hash_algo->hexsz;
+
+	/* find existing parents */
+	parent_start = buf->buf;
+	parent_start += hexsz + 6; /* "tree " + "hex sha1" + "\n" */
+	parent_end = parent_start;
+
+	while (starts_with(parent_end, "parent "))
+		parent_end += hexsz + 8; /* "parent " + "hex sha1" + "\n" */
+
+	/* prepare new parents */
+	for (i = 0; i < argc; i++) {
+		struct object_id oid;
+		struct commit *commit;
+
+		if (repo_get_oid(the_repository, argv[i], &oid) < 0) {
+			strbuf_release(&new_parents);
+			return error(_("not a valid object name: '%s'"),
+				     argv[i]);
+		}
+		commit = lookup_commit_reference(the_repository, &oid);
+		if (!commit) {
+			strbuf_release(&new_parents);
+			return error(_("could not parse %s as a commit"), argv[i]);
+		}
+		strbuf_addf(&new_parents, "parent %s\n", oid_to_hex(&commit->object.oid));
+	}
+
+	/* replace existing parents with new ones */
+	strbuf_splice(buf, parent_start - buf->buf, parent_end - parent_start,
+		      new_parents.buf, new_parents.len);
+
+	strbuf_release(&new_parents);
+	return 0;
+}
+
+struct check_mergetag_data {
+	int argc;
+	const char **argv;
+};
+
+static int check_one_mergetag(struct commit *commit UNUSED,
+			       struct commit_extra_header *extra,
+			       void *data)
+{
+	struct check_mergetag_data *mergetag_data = (struct check_mergetag_data *)data;
+	const char *ref = mergetag_data->argv[0];
+	struct object_id tag_oid;
+	struct tag *tag;
+	int i;
+
+	hash_object_file(the_hash_algo, extra->value, extra->len,
+			 OBJ_TAG, &tag_oid);
+	tag = lookup_tag(the_repository, &tag_oid);
+	if (!tag)
+		return error(_("bad mergetag in commit '%s'"), ref);
+	if (parse_tag_buffer(the_repository, tag, extra->value, extra->len))
+		return error(_("malformed mergetag in commit '%s'"), ref);
+
+	/* iterate over new parents */
+	for (i = 1; i < mergetag_data->argc; i++) {
+		struct object_id oid;
+		if (repo_get_oid(the_repository, mergetag_data->argv[i], &oid) < 0)
+			return error(_("not a valid object name: '%s'"),
+				     mergetag_data->argv[i]);
+		if (oideq(get_tagged_oid(tag), &oid))
+			return 0; /* found */
+	}
+
+	return error(_("original commit '%s' contains mergetag '%s' that is "
+		       "discarded; use --edit instead of --graft"), ref,
+		     oid_to_hex(&tag_oid));
+}
+
+static int check_mergetags(struct commit *commit, int argc, const char **argv)
+{
+	struct check_mergetag_data mergetag_data;
+
+	mergetag_data.argc = argc;
+	mergetag_data.argv = argv;
+	return for_each_mergetag(check_one_mergetag, commit, &mergetag_data);
+}
+
+static int create_graft(int argc, const char **argv, int force, int gentle)
+{
+	struct object_id old_oid, new_oid;
+	const char *old_ref = argv[0];
+	struct commit *commit;
+	struct strbuf buf = STRBUF_INIT;
+	const char *buffer;
+	unsigned long size;
+
+	if (repo_get_oid(the_repository, old_ref, &old_oid) < 0)
+		return error(_("not a valid object name: '%s'"), old_ref);
+	commit = lookup_commit_reference(the_repository, &old_oid);
+	if (!commit)
+		return error(_("could not parse %s"), old_ref);
+
+	buffer = repo_get_commit_buffer(the_repository, commit, &size);
+	strbuf_add(&buf, buffer, size);
+	repo_unuse_commit_buffer(the_repository, commit, buffer);
+
+	if (replace_parents(&buf, argc - 1, &argv[1]) < 0) {
+		strbuf_release(&buf);
+		return -1;
+	}
+
+	if (remove_signature(&buf)) {
+		warning(_("the original commit '%s' has a gpg signature"), old_ref);
+		warning(_("the signature will be removed in the replacement commit!"));
+	}
+
+	if (check_mergetags(commit, argc, argv)) {
+		strbuf_release(&buf);
+		return -1;
+	}
+
+	if (write_object_file(buf.buf, buf.len, OBJ_COMMIT, &new_oid)) {
+		strbuf_release(&buf);
+		return error(_("could not write replacement commit for: '%s'"),
+			     old_ref);
+	}
+
+	strbuf_release(&buf);
+
+	if (oideq(&commit->object.oid, &new_oid)) {
+		if (gentle) {
+			warning(_("graft for '%s' unnecessary"),
+				oid_to_hex(&commit->object.oid));
+			return 0;
+		}
+		return error(_("new commit is the same as the old one: '%s'"),
+			     oid_to_hex(&commit->object.oid));
+	}
+
+	return replace_object_oid(old_ref, &commit->object.oid,
+				  "replacement", &new_oid, force);
+}
+
+static int convert_graft_file(int force)
+{
+	const char *graft_file = repo_get_graft_file(the_repository);
+	FILE *fp = fopen_or_warn(graft_file, "r");
+	struct strbuf buf = STRBUF_INIT, err = STRBUF_INIT;
+	struct strvec args = STRVEC_INIT;
+
+	if (!fp)
+		return -1;
+
+	no_graft_file_deprecated_advice = 1;
+	while (strbuf_getline(&buf, fp) != EOF) {
+		if (*buf.buf == '#')
+			continue;
+
+		strvec_split(&args, buf.buf);
+		if (args.nr && create_graft(args.nr, args.v, force, 1))
+			strbuf_addf(&err, "\n\t%s", buf.buf);
+		strvec_clear(&args);
+	}
+	fclose(fp);
+
+	strbuf_release(&buf);
+
+	if (!err.len)
+		return unlink_or_warn(graft_file);
+
+	warning(_("could not convert the following graft(s):\n%s"), err.buf);
+	strbuf_release(&err);
+
+	return -1;
+}
+
+int cmd_replace(int argc,
+		const char **argv,
+		const char *prefix,
+		struct repository *repo UNUSED)
+{
+	int force = 0;
+	int raw = 0;
+	const char *format = NULL;
+	enum {
+		MODE_UNSPECIFIED = 0,
+		MODE_LIST,
+		MODE_DELETE,
+		MODE_EDIT,
+		MODE_GRAFT,
+		MODE_CONVERT_GRAFT_FILE,
+		MODE_REPLACE
+	} cmdmode = MODE_UNSPECIFIED;
+	struct option options[] = {
+		OPT_CMDMODE('l', "list", &cmdmode, N_("list replace refs"), MODE_LIST),
+		OPT_CMDMODE('d', "delete", &cmdmode, N_("delete replace refs"), MODE_DELETE),
+		OPT_CMDMODE('e', "edit", &cmdmode, N_("edit existing object"), MODE_EDIT),
+		OPT_CMDMODE('g', "graft", &cmdmode, N_("change a commit's parents"), MODE_GRAFT),
+		OPT_CMDMODE(0, "convert-graft-file", &cmdmode, N_("convert existing graft file"), MODE_CONVERT_GRAFT_FILE),
+		OPT_BOOL_F('f', "force", &force, N_("replace the ref if it exists"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "raw", &raw, N_("do not pretty-print contents for --edit")),
+		OPT_STRING(0, "format", &format, N_("format"), N_("use this format")),
+		OPT_END()
+	};
+
+	disable_replace_refs();
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, options, git_replace_usage, 0);
+
+	if (!cmdmode)
+		cmdmode = argc ? MODE_REPLACE : MODE_LIST;
+
+	if (format && cmdmode != MODE_LIST)
+		usage_msg_opt(_("--format cannot be used when not listing"),
+			      git_replace_usage, options);
+
+	if (force &&
+	    cmdmode != MODE_REPLACE &&
+	    cmdmode != MODE_EDIT &&
+	    cmdmode != MODE_GRAFT &&
+	    cmdmode != MODE_CONVERT_GRAFT_FILE)
+		usage_msg_opt(_("-f only makes sense when writing a replacement"),
+			      git_replace_usage, options);
+
+	if (raw && cmdmode != MODE_EDIT)
+		usage_msg_opt(_("--raw only makes sense with --edit"),
+			      git_replace_usage, options);
+
+	switch (cmdmode) {
+	case MODE_DELETE:
+		if (argc < 1)
+			usage_msg_opt(_("-d needs at least one argument"),
+				      git_replace_usage, options);
+		return for_each_replace_name(argv, delete_replace_ref);
+
+	case MODE_REPLACE:
+		if (argc != 2)
+			usage_msg_opt(_("bad number of arguments"),
+				      git_replace_usage, options);
+		return replace_object(argv[0], argv[1], force);
+
+	case MODE_EDIT:
+		if (argc != 1)
+			usage_msg_opt(_("-e needs exactly one argument"),
+				      git_replace_usage, options);
+		return edit_and_replace(argv[0], force, raw);
+
+	case MODE_GRAFT:
+		if (argc < 1)
+			usage_msg_opt(_("-g needs at least one argument"),
+				      git_replace_usage, options);
+		return create_graft(argc, argv, force, 0);
+
+	case MODE_CONVERT_GRAFT_FILE:
+		if (argc != 0)
+			usage_msg_opt(_("--convert-graft-file takes no argument"),
+				      git_replace_usage, options);
+		return !!convert_graft_file(force);
+
+	case MODE_LIST:
+		if (argc > 1)
+			usage_msg_opt(_("only one pattern can be given with -l"),
+				      git_replace_usage, options);
+		return list_replace_refs(argv[0], format);
+
+	default:
+		BUG("invalid cmdmode %d", (int)cmdmode);
+	}
+}
diff --git a/builtin/replay.c b/builtin/replay.c
new file mode 100644
index 0000000000..1afc6d1ee0
--- /dev/null
+++ b/builtin/replay.c
@@ -0,0 +1,463 @@
+/*
+ * "git replay" builtin command
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+
+#include "builtin.h"
+#include "environment.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "merge-ort.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "revision.h"
+#include "strmap.h"
+#include <oidset.h>
+#include <tree.h>
+
+static const char *short_commit_name(struct commit *commit)
+{
+	return repo_find_unique_abbrev(the_repository, &commit->object.oid,
+				       DEFAULT_ABBREV);
+}
+
+static struct commit *peel_committish(const char *name)
+{
+	struct object *obj;
+	struct object_id oid;
+
+	if (repo_get_oid(the_repository, name, &oid))
+		return NULL;
+	obj = parse_object(the_repository, &oid);
+	return (struct commit *)repo_peel_to_type(the_repository, name, 0, obj,
+						  OBJ_COMMIT);
+}
+
+static char *get_author(const char *message)
+{
+	size_t len;
+	const char *a;
+
+	a = find_commit_header(message, "author", &len);
+	if (a)
+		return xmemdupz(a, len);
+
+	return NULL;
+}
+
+static struct commit *create_commit(struct tree *tree,
+				    struct commit *based_on,
+				    struct commit *parent)
+{
+	struct object_id ret;
+	struct object *obj = NULL;
+	struct commit_list *parents = NULL;
+	char *author;
+	char *sign_commit = NULL; /* FIXME: cli users might want to sign again */
+	struct commit_extra_header *extra = NULL;
+	struct strbuf msg = STRBUF_INIT;
+	const char *out_enc = get_commit_output_encoding();
+	const char *message = repo_logmsg_reencode(the_repository, based_on,
+						   NULL, out_enc);
+	const char *orig_message = NULL;
+	const char *exclude_gpgsig[] = { "gpgsig", NULL };
+
+	commit_list_insert(parent, &parents);
+	extra = read_commit_extra_headers(based_on, exclude_gpgsig);
+	find_commit_subject(message, &orig_message);
+	strbuf_addstr(&msg, orig_message);
+	author = get_author(message);
+	reset_ident_date();
+	if (commit_tree_extended(msg.buf, msg.len, &tree->object.oid, parents,
+				 &ret, author, NULL, sign_commit, extra)) {
+		error(_("failed to write commit object"));
+		goto out;
+	}
+
+	obj = parse_object(the_repository, &ret);
+
+out:
+	free_commit_extra_headers(extra);
+	free_commit_list(parents);
+	strbuf_release(&msg);
+	free(author);
+	return (struct commit *)obj;
+}
+
+struct ref_info {
+	struct commit *onto;
+	struct strset positive_refs;
+	struct strset negative_refs;
+	int positive_refexprs;
+	int negative_refexprs;
+};
+
+static void get_ref_information(struct rev_cmdline_info *cmd_info,
+				struct ref_info *ref_info)
+{
+	int i;
+
+	ref_info->onto = NULL;
+	strset_init(&ref_info->positive_refs);
+	strset_init(&ref_info->negative_refs);
+	ref_info->positive_refexprs = 0;
+	ref_info->negative_refexprs = 0;
+
+	/*
+	 * When the user specifies e.g.
+	 *   git replay origin/main..mybranch
+	 *   git replay ^origin/next mybranch1 mybranch2
+	 * we want to be able to determine where to replay the commits.  In
+	 * these examples, the branches are probably based on an old version
+	 * of either origin/main or origin/next, so we want to replay on the
+	 * newest version of that branch.  In contrast we would want to error
+	 * out if they ran
+	 *   git replay ^origin/master ^origin/next mybranch
+	 *   git replay mybranch~2..mybranch
+	 * the first of those because there's no unique base to choose, and
+	 * the second because they'd likely just be replaying commits on top
+	 * of the same commit and not making any difference.
+	 */
+	for (i = 0; i < cmd_info->nr; i++) {
+		struct rev_cmdline_entry *e = cmd_info->rev + i;
+		struct object_id oid;
+		const char *refexpr = e->name;
+		char *fullname = NULL;
+		int can_uniquely_dwim = 1;
+
+		if (*refexpr == '^')
+			refexpr++;
+		if (repo_dwim_ref(the_repository, refexpr, strlen(refexpr), &oid, &fullname, 0) != 1)
+			can_uniquely_dwim = 0;
+
+		if (e->flags & BOTTOM) {
+			if (can_uniquely_dwim)
+				strset_add(&ref_info->negative_refs, fullname);
+			if (!ref_info->negative_refexprs)
+				ref_info->onto = lookup_commit_reference_gently(the_repository,
+										&e->item->oid, 1);
+			ref_info->negative_refexprs++;
+		} else {
+			if (can_uniquely_dwim)
+				strset_add(&ref_info->positive_refs, fullname);
+			ref_info->positive_refexprs++;
+		}
+
+		free(fullname);
+	}
+}
+
+static void determine_replay_mode(struct rev_cmdline_info *cmd_info,
+				  const char *onto_name,
+				  char **advance_name,
+				  struct commit **onto,
+				  struct strset **update_refs)
+{
+	struct ref_info rinfo;
+
+	get_ref_information(cmd_info, &rinfo);
+	if (!rinfo.positive_refexprs)
+		die(_("need some commits to replay"));
+	if (onto_name && *advance_name)
+		die(_("--onto and --advance are incompatible"));
+	else if (onto_name) {
+		*onto = peel_committish(onto_name);
+		if (rinfo.positive_refexprs <
+		    strset_get_size(&rinfo.positive_refs))
+			die(_("all positive revisions given must be references"));
+	} else if (*advance_name) {
+		struct object_id oid;
+		char *fullname = NULL;
+
+		*onto = peel_committish(*advance_name);
+		if (repo_dwim_ref(the_repository, *advance_name, strlen(*advance_name),
+			     &oid, &fullname, 0) == 1) {
+			free(*advance_name);
+			*advance_name = fullname;
+		} else {
+			die(_("argument to --advance must be a reference"));
+		}
+		if (rinfo.positive_refexprs > 1)
+			die(_("cannot advance target with multiple sources because ordering would be ill-defined"));
+	} else {
+		int positive_refs_complete = (
+			rinfo.positive_refexprs ==
+			strset_get_size(&rinfo.positive_refs));
+		int negative_refs_complete = (
+			rinfo.negative_refexprs ==
+			strset_get_size(&rinfo.negative_refs));
+		/*
+		 * We need either positive_refs_complete or
+		 * negative_refs_complete, but not both.
+		 */
+		if (rinfo.negative_refexprs > 0 &&
+		    positive_refs_complete == negative_refs_complete)
+			die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
+		if (negative_refs_complete) {
+			struct hashmap_iter iter;
+			struct strmap_entry *entry;
+			const char *last_key = NULL;
+
+			if (rinfo.negative_refexprs == 0)
+				die(_("all positive revisions given must be references"));
+			else if (rinfo.negative_refexprs > 1)
+				die(_("cannot implicitly determine whether this is an --advance or --onto operation"));
+			else if (rinfo.positive_refexprs > 1)
+				die(_("cannot advance target with multiple source branches because ordering would be ill-defined"));
+
+			/* Only one entry, but we have to loop to get it */
+			strset_for_each_entry(&rinfo.negative_refs,
+					      &iter, entry) {
+				last_key = entry->key;
+			}
+
+			free(*advance_name);
+			*advance_name = xstrdup_or_null(last_key);
+		} else { /* positive_refs_complete */
+			if (rinfo.negative_refexprs > 1)
+				die(_("cannot implicitly determine correct base for --onto"));
+			if (rinfo.negative_refexprs == 1)
+				*onto = rinfo.onto;
+		}
+	}
+	if (!*advance_name) {
+		*update_refs = xcalloc(1, sizeof(**update_refs));
+		**update_refs = rinfo.positive_refs;
+		memset(&rinfo.positive_refs, 0, sizeof(**update_refs));
+	}
+	strset_clear(&rinfo.negative_refs);
+	strset_clear(&rinfo.positive_refs);
+}
+
+static struct commit *mapped_commit(kh_oid_map_t *replayed_commits,
+				    struct commit *commit,
+				    struct commit *fallback)
+{
+	khint_t pos = kh_get_oid_map(replayed_commits, commit->object.oid);
+	if (pos == kh_end(replayed_commits))
+		return fallback;
+	return kh_value(replayed_commits, pos);
+}
+
+static struct commit *pick_regular_commit(struct commit *pickme,
+					  kh_oid_map_t *replayed_commits,
+					  struct commit *onto,
+					  struct merge_options *merge_opt,
+					  struct merge_result *result)
+{
+	struct commit *base, *replayed_base;
+	struct tree *pickme_tree, *base_tree;
+
+	base = pickme->parents->item;
+	replayed_base = mapped_commit(replayed_commits, base, onto);
+
+	result->tree = repo_get_commit_tree(the_repository, replayed_base);
+	pickme_tree = repo_get_commit_tree(the_repository, pickme);
+	base_tree = repo_get_commit_tree(the_repository, base);
+
+	merge_opt->branch1 = short_commit_name(replayed_base);
+	merge_opt->branch2 = short_commit_name(pickme);
+	merge_opt->ancestor = xstrfmt("parent of %s", merge_opt->branch2);
+
+	merge_incore_nonrecursive(merge_opt,
+				  base_tree,
+				  result->tree,
+				  pickme_tree,
+				  result);
+
+	free((char*)merge_opt->ancestor);
+	merge_opt->ancestor = NULL;
+	if (!result->clean)
+		return NULL;
+	return create_commit(result->tree, pickme, replayed_base);
+}
+
+int cmd_replay(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	const char *advance_name_opt = NULL;
+	char *advance_name = NULL;
+	struct commit *onto = NULL;
+	const char *onto_name = NULL;
+	int contained = 0;
+
+	struct rev_info revs;
+	struct commit *last_commit = NULL;
+	struct commit *commit;
+	struct merge_options merge_opt;
+	struct merge_result result;
+	struct strset *update_refs = NULL;
+	kh_oid_map_t *replayed_commits;
+	int ret = 0;
+
+	const char * const replay_usage[] = {
+		N_("(EXPERIMENTAL!) git replay "
+		   "([--contained] --onto <newbase> | --advance <branch>) "
+		   "<revision-range>..."),
+		NULL
+	};
+	struct option replay_options[] = {
+		OPT_STRING(0, "advance", &advance_name_opt,
+			   N_("branch"),
+			   N_("make replay advance given branch")),
+		OPT_STRING(0, "onto", &onto_name,
+			   N_("revision"),
+			   N_("replay onto given commit")),
+		OPT_BOOL(0, "contained", &contained,
+			 N_("advance all branches contained in revision-range")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, replay_options, replay_usage,
+			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+	if (!onto_name && !advance_name_opt) {
+		error(_("option --onto or --advance is mandatory"));
+		usage_with_options(replay_usage, replay_options);
+	}
+
+	if (advance_name_opt && contained)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--advance", "--contained");
+	advance_name = xstrdup_or_null(advance_name_opt);
+
+	repo_init_revisions(the_repository, &revs, prefix);
+
+	/*
+	 * Set desired values for rev walking options here. If they
+	 * are changed by some user specified option in setup_revisions()
+	 * below, we will detect that below and then warn.
+	 *
+	 * TODO: In the future we might want to either die(), or allow
+	 * some options changing these values if we think they could
+	 * be useful.
+	 */
+	revs.reverse = 1;
+	revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+	revs.topo_order = 1;
+	revs.simplify_history = 0;
+
+	argc = setup_revisions(argc, argv, &revs, NULL);
+	if (argc > 1) {
+		ret = error(_("unrecognized argument: %s"), argv[1]);
+		goto cleanup;
+	}
+
+	/*
+	 * Detect and warn if we override some user specified rev
+	 * walking options.
+	 */
+	if (revs.reverse != 1) {
+		warning(_("some rev walking options will be overridden as "
+			  "'%s' bit in 'struct rev_info' will be forced"),
+			"reverse");
+		revs.reverse = 1;
+	}
+	if (revs.sort_order != REV_SORT_IN_GRAPH_ORDER) {
+		warning(_("some rev walking options will be overridden as "
+			  "'%s' bit in 'struct rev_info' will be forced"),
+			"sort_order");
+		revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
+	}
+	if (revs.topo_order != 1) {
+		warning(_("some rev walking options will be overridden as "
+			  "'%s' bit in 'struct rev_info' will be forced"),
+			"topo_order");
+		revs.topo_order = 1;
+	}
+	if (revs.simplify_history != 0) {
+		warning(_("some rev walking options will be overridden as "
+			  "'%s' bit in 'struct rev_info' will be forced"),
+			"simplify_history");
+		revs.simplify_history = 0;
+	}
+
+	determine_replay_mode(&revs.cmdline, onto_name, &advance_name,
+			      &onto, &update_refs);
+
+	if (!onto) /* FIXME: Should handle replaying down to root commit */
+		die("Replaying down to root commit is not supported yet!");
+
+	if (prepare_revision_walk(&revs) < 0) {
+		ret = error(_("error preparing revisions"));
+		goto cleanup;
+	}
+
+	init_basic_merge_options(&merge_opt, the_repository);
+	memset(&result, 0, sizeof(result));
+	merge_opt.show_rename_progress = 0;
+	last_commit = onto;
+	replayed_commits = kh_init_oid_map();
+	while ((commit = get_revision(&revs))) {
+		const struct name_decoration *decoration;
+		khint_t pos;
+		int hr;
+
+		if (!commit->parents)
+			die(_("replaying down to root commit is not supported yet!"));
+		if (commit->parents->next)
+			die(_("replaying merge commits is not supported yet!"));
+
+		last_commit = pick_regular_commit(commit, replayed_commits, onto,
+						  &merge_opt, &result);
+		if (!last_commit)
+			break;
+
+		/* Record commit -> last_commit mapping */
+		pos = kh_put_oid_map(replayed_commits, commit->object.oid, &hr);
+		if (hr == 0)
+			BUG("Duplicate rewritten commit: %s\n",
+			    oid_to_hex(&commit->object.oid));
+		kh_value(replayed_commits, pos) = last_commit;
+
+		/* Update any necessary branches */
+		if (advance_name)
+			continue;
+		decoration = get_name_decoration(&commit->object);
+		if (!decoration)
+			continue;
+		while (decoration) {
+			if (decoration->type == DECORATION_REF_LOCAL &&
+			    (contained || strset_contains(update_refs,
+							  decoration->name))) {
+				printf("update %s %s %s\n",
+				       decoration->name,
+				       oid_to_hex(&last_commit->object.oid),
+				       oid_to_hex(&commit->object.oid));
+			}
+			decoration = decoration->next;
+		}
+	}
+
+	/* In --advance mode, advance the target ref */
+	if (result.clean == 1 && advance_name) {
+		printf("update %s %s %s\n",
+		       advance_name,
+		       oid_to_hex(&last_commit->object.oid),
+		       oid_to_hex(&onto->object.oid));
+	}
+
+	merge_finalize(&merge_opt, &result);
+	kh_destroy_oid_map(replayed_commits);
+	if (update_refs) {
+		strset_clear(update_refs);
+		free(update_refs);
+	}
+	ret = result.clean;
+
+cleanup:
+	release_revisions(&revs);
+	free(advance_name);
+
+	/* Return */
+	if (ret < 0)
+		exit(128);
+	return ret ? 0 : 1;
+}
diff --git a/builtin/rerere.c b/builtin/rerere.c
new file mode 100644
index 0000000000..41127e24e5
--- /dev/null
+++ b/builtin/rerere.c
@@ -0,0 +1,129 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "parse-options.h"
+
+#include "string-list.h"
+#include "rerere.h"
+#include "xdiff/xdiff.h"
+#include "xdiff-interface.h"
+#include "pathspec.h"
+
+static const char * const rerere_usage[] = {
+	N_("git rerere [clear | forget <pathspec>... | diff | status | remaining | gc]"),
+	NULL,
+};
+
+static int outf(void *dummy UNUSED, mmbuffer_t *ptr, int nbuf)
+{
+	int i;
+	for (i = 0; i < nbuf; i++)
+		if (write_in_full(1, ptr[i].ptr, ptr[i].size) < 0)
+			return -1;
+	return 0;
+}
+
+static int diff_two(const char *file1, const char *label1,
+		const char *file2, const char *label2)
+{
+	xpparam_t xpp;
+	xdemitconf_t xecfg;
+	xdemitcb_t ecb = { .out_line = outf };
+	mmfile_t minus, plus;
+	int ret;
+
+	if (read_mmfile(&minus, file1) || read_mmfile(&plus, file2))
+		return -1;
+
+	printf("--- a/%s\n+++ b/%s\n", label1, label2);
+	fflush(stdout);
+	memset(&xpp, 0, sizeof(xpp));
+	xpp.flags = 0;
+	memset(&xecfg, 0, sizeof(xecfg));
+	xecfg.ctxlen = 3;
+	ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
+
+	free(minus.ptr);
+	free(plus.ptr);
+	return ret;
+}
+
+int cmd_rerere(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct string_list merge_rr = STRING_LIST_INIT_DUP;
+	int autoupdate = -1, flags = 0;
+
+	struct option options[] = {
+		OPT_SET_INT(0, "rerere-autoupdate", &autoupdate,
+			N_("register clean resolutions in index"), 1),
+		OPT_END(),
+	};
+
+	argc = parse_options(argc, argv, prefix, options, rerere_usage, 0);
+
+	git_config(git_xmerge_config, NULL);
+
+	if (autoupdate == 1)
+		flags = RERERE_AUTOUPDATE;
+	if (autoupdate == 0)
+		flags = RERERE_NOAUTOUPDATE;
+
+	if (argc < 1)
+		return repo_rerere(the_repository, flags);
+
+	if (!strcmp(argv[0], "forget")) {
+		struct pathspec pathspec;
+		int ret;
+
+		if (argc < 2)
+			warning(_("'git rerere forget' without paths is deprecated"));
+		parse_pathspec(&pathspec, 0, PATHSPEC_PREFER_CWD,
+			       prefix, argv + 1);
+
+		ret = rerere_forget(the_repository, &pathspec);
+
+		clear_pathspec(&pathspec);
+		return ret;
+	}
+
+	if (!strcmp(argv[0], "clear")) {
+		rerere_clear(the_repository, &merge_rr);
+	} else if (!strcmp(argv[0], "gc"))
+		rerere_gc(the_repository, &merge_rr);
+	else if (!strcmp(argv[0], "status")) {
+		if (setup_rerere(the_repository, &merge_rr,
+				 flags | RERERE_READONLY) < 0)
+			return 0;
+		for (size_t i = 0; i < merge_rr.nr; i++)
+			printf("%s\n", merge_rr.items[i].string);
+	} else if (!strcmp(argv[0], "remaining")) {
+		rerere_remaining(the_repository, &merge_rr);
+		for (size_t i = 0; i < merge_rr.nr; i++) {
+			if (merge_rr.items[i].util != RERERE_RESOLVED)
+				printf("%s\n", merge_rr.items[i].string);
+			else
+				/* prepare for later call to
+				 * string_list_clear() */
+				merge_rr.items[i].util = NULL;
+		}
+	} else if (!strcmp(argv[0], "diff")) {
+		if (setup_rerere(the_repository, &merge_rr,
+				 flags | RERERE_READONLY) < 0)
+			return 0;
+		for (size_t i = 0; i < merge_rr.nr; i++) {
+			const char *path = merge_rr.items[i].string;
+			const struct rerere_id *id = merge_rr.items[i].util;
+			if (diff_two(rerere_path(id, "preimage"), path, path, path))
+				die(_("unable to generate diff for '%s'"), rerere_path(id, NULL));
+		}
+	} else
+		usage_with_options(rerere_usage, options);
+
+	string_list_clear(&merge_rr, 1);
+	return 0;
+}
diff --git a/builtin/reset.c b/builtin/reset.c
new file mode 100644
index 0000000000..73b4537a9a
--- /dev/null
+++ b/builtin/reset.c
@@ -0,0 +1,534 @@
+/*
+ * "git reset" builtin command
+ *
+ * Copyright (c) 2007 Carlos Rica
+ *
+ * Based on git-reset.sh, which is
+ *
+ * Copyright (c) 2005, 2006 Linus Torvalds and Junio C Hamano
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "object.h"
+#include "pretty.h"
+#include "refs.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "tree.h"
+#include "branch.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "path.h"
+#include "repository.h"
+#include "unpack-trees.h"
+#include "cache-tree.h"
+#include "setup.h"
+#include "sparse-index.h"
+#include "submodule.h"
+#include "trace.h"
+#include "trace2.h"
+#include "dir.h"
+#include "add-interactive.h"
+
+#define REFRESH_INDEX_DELAY_WARNING_IN_MS (2 * 1000)
+
+static const char * const git_reset_usage[] = {
+	N_("git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]"),
+	N_("git reset [-q] [<tree-ish>] [--] <pathspec>..."),
+	N_("git reset [-q] [--pathspec-from-file [--pathspec-file-nul]] [<tree-ish>]"),
+	N_("git reset --patch [<tree-ish>] [--] [<pathspec>...]"),
+	NULL
+};
+
+enum reset_type { MIXED, SOFT, HARD, MERGE, KEEP, NONE };
+static const char *reset_type_names[] = {
+	N_("mixed"), N_("soft"), N_("hard"), N_("merge"), N_("keep"), NULL
+};
+
+static inline int is_merge(void)
+{
+	return !access(git_path_merge_head(the_repository), F_OK);
+}
+
+static int reset_index(const char *ref, const struct object_id *oid, int reset_type, int quiet)
+{
+	int i, nr = 0;
+	struct tree_desc desc[2];
+	struct tree *tree;
+	struct unpack_trees_options opts;
+	int ret = -1;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.head_idx = 1;
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+	opts.fn = oneway_merge;
+	opts.merge = 1;
+	init_checkout_metadata(&opts.meta, ref, oid, NULL);
+	if (!quiet)
+		opts.verbose_update = 1;
+	switch (reset_type) {
+	case KEEP:
+	case MERGE:
+		opts.update = 1;
+		opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
+		break;
+	case HARD:
+		opts.update = 1;
+		opts.reset = UNPACK_RESET_OVERWRITE_UNTRACKED;
+		opts.skip_cache_tree_update = 1;
+		break;
+	case MIXED:
+		opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
+		opts.skip_cache_tree_update = 1;
+		/* but opts.update=0, so working tree not updated */
+		break;
+	default:
+		BUG("invalid reset_type passed to reset_index");
+	}
+
+	repo_read_index_unmerged(the_repository);
+
+	if (reset_type == KEEP) {
+		struct object_id head_oid;
+		if (repo_get_oid(the_repository, "HEAD", &head_oid))
+			return error(_("You do not have a valid HEAD."));
+		if (!fill_tree_descriptor(the_repository, desc + nr, &head_oid))
+			return error(_("Failed to find tree of HEAD."));
+		nr++;
+		opts.fn = twoway_merge;
+	}
+
+	if (!fill_tree_descriptor(the_repository, desc + nr, oid)) {
+		error(_("Failed to find tree of %s."), oid_to_hex(oid));
+		goto out;
+	}
+	nr++;
+
+	if (unpack_trees(nr, desc, &opts))
+		goto out;
+
+	if (reset_type == MIXED || reset_type == HARD) {
+		tree = parse_tree_indirect(oid);
+		if (!tree) {
+			error(_("unable to read tree (%s)"), oid_to_hex(oid));
+			goto out;
+		}
+		prime_cache_tree(the_repository, the_repository->index, tree);
+	}
+
+	ret = 0;
+
+out:
+	for (i = 0; i < nr; i++)
+		free((void *)desc[i].buffer);
+	return ret;
+}
+
+static void print_new_head_line(struct commit *commit)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	printf(_("HEAD is now at %s"),
+		repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
+
+	pp_commit_easy(CMIT_FMT_ONELINE, commit, &buf);
+	if (buf.len > 0)
+		printf(" %s", buf.buf);
+	putchar('\n');
+	strbuf_release(&buf);
+}
+
+static void update_index_from_diff(struct diff_queue_struct *q,
+				   struct diff_options *opt UNUSED,
+				   void *data)
+{
+	int i;
+	int intent_to_add = *(int *)data;
+
+	for (i = 0; i < q->nr; i++) {
+		int pos;
+		struct diff_filespec *one = q->queue[i]->one;
+		int is_in_reset_tree = one->mode && !is_null_oid(&one->oid);
+		struct cache_entry *ce;
+
+		if (!is_in_reset_tree && !intent_to_add) {
+			remove_file_from_index(the_repository->index, one->path);
+			continue;
+		}
+
+		ce = make_cache_entry(the_repository->index, one->mode, &one->oid, one->path,
+				      0, 0);
+
+		/*
+		 * If the file 1) corresponds to an existing index entry with
+		 * skip-worktree set, or 2) does not exist in the index but is
+		 * outside the sparse checkout definition, add a skip-worktree bit
+		 * to the new index entry. Note that a sparse index will be expanded
+		 * if this entry is outside the sparse cone - this is necessary
+		 * to properly construct the reset sparse directory.
+		 */
+		pos = index_name_pos(the_repository->index, one->path, strlen(one->path));
+		if ((pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) ||
+		    (pos < 0 && !path_in_sparse_checkout(one->path, the_repository->index)))
+			ce->ce_flags |= CE_SKIP_WORKTREE;
+
+		if (!ce)
+			die(_("make_cache_entry failed for path '%s'"),
+			    one->path);
+		if (!is_in_reset_tree) {
+			ce->ce_flags |= CE_INTENT_TO_ADD;
+			set_object_name_for_intent_to_add_entry(ce);
+		}
+		add_index_entry(the_repository->index, ce,
+				ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
+	}
+}
+
+static int read_from_tree(const struct pathspec *pathspec,
+			  struct object_id *tree_oid,
+			  int intent_to_add)
+{
+	struct diff_options opt;
+
+	memset(&opt, 0, sizeof(opt));
+	copy_pathspec(&opt.pathspec, pathspec);
+	opt.output_format = DIFF_FORMAT_CALLBACK;
+	opt.format_callback = update_index_from_diff;
+	opt.format_callback_data = &intent_to_add;
+	opt.flags.override_submodule_config = 1;
+	opt.flags.recursive = 1;
+	opt.repo = the_repository;
+	opt.change = diff_change;
+	opt.add_remove = diff_addremove;
+
+	if (pathspec->nr && pathspec_needs_expanded_index(the_repository->index, pathspec))
+		ensure_full_index(the_repository->index);
+
+	if (do_diff_cache(tree_oid, &opt))
+		return 1;
+	diffcore_std(&opt);
+	diff_flush(&opt);
+
+	return 0;
+}
+
+static void set_reflog_message(struct strbuf *sb, const char *action,
+			       const char *rev)
+{
+	const char *rla = getenv("GIT_REFLOG_ACTION");
+
+	strbuf_reset(sb);
+	if (rla)
+		strbuf_addf(sb, "%s: %s", rla, action);
+	else if (rev)
+		strbuf_addf(sb, "reset: moving to %s", rev);
+	else
+		strbuf_addf(sb, "reset: %s", action);
+}
+
+static void die_if_unmerged_cache(int reset_type)
+{
+	if (is_merge() || unmerged_index(the_repository->index))
+		die(_("Cannot do a %s reset in the middle of a merge."),
+		    _(reset_type_names[reset_type]));
+
+}
+
+static void parse_args(struct pathspec *pathspec,
+		       const char **argv, const char *prefix,
+		       int patch_mode,
+		       const char **rev_ret)
+{
+	const char *rev = "HEAD";
+	struct object_id unused;
+	/*
+	 * Possible arguments are:
+	 *
+	 * git reset [-opts] [<rev>]
+	 * git reset [-opts] <tree> [<paths>...]
+	 * git reset [-opts] <tree> -- [<paths>...]
+	 * git reset [-opts] -- [<paths>...]
+	 * git reset [-opts] <paths>...
+	 *
+	 * At this point, argv points immediately after [-opts].
+	 */
+
+	if (argv[0]) {
+		if (!strcmp(argv[0], "--")) {
+			argv++; /* reset to HEAD, possibly with paths */
+		} else if (argv[1] && !strcmp(argv[1], "--")) {
+			rev = argv[0];
+			argv += 2;
+		}
+		/*
+		 * Otherwise, argv[0] could be either <rev> or <paths> and
+		 * has to be unambiguous. If there is a single argument, it
+		 * can not be a tree
+		 */
+		else if ((!argv[1] && !repo_get_oid_committish(the_repository, argv[0], &unused)) ||
+			 (argv[1] && !repo_get_oid_treeish(the_repository, argv[0], &unused))) {
+			/*
+			 * Ok, argv[0] looks like a commit/tree; it should not
+			 * be a filename.
+			 */
+			verify_non_filename(prefix, argv[0]);
+			rev = *argv++;
+		} else {
+			/* Otherwise we treat this as a filename */
+			verify_filename(prefix, argv[0], 1);
+		}
+	}
+
+	/* treat '@' as a shortcut for 'HEAD' */
+	*rev_ret = !strcmp("@", rev) ? "HEAD" : rev;
+
+	parse_pathspec(pathspec, 0,
+		       PATHSPEC_PREFER_FULL |
+		       (patch_mode ? PATHSPEC_PREFIX_ORIGIN : 0),
+		       prefix, argv);
+}
+
+static int reset_refs(const char *rev, const struct object_id *oid)
+{
+	int update_ref_status;
+	struct strbuf msg = STRBUF_INIT;
+	struct object_id *orig = NULL, oid_orig,
+		*old_orig = NULL, oid_old_orig;
+
+	if (!repo_get_oid(the_repository, "ORIG_HEAD", &oid_old_orig))
+		old_orig = &oid_old_orig;
+	if (!repo_get_oid(the_repository, "HEAD", &oid_orig)) {
+		orig = &oid_orig;
+		set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
+		refs_update_ref(get_main_ref_store(the_repository), msg.buf,
+				"ORIG_HEAD", orig, old_orig, 0,
+				UPDATE_REFS_MSG_ON_ERR);
+	} else if (old_orig)
+		refs_delete_ref(get_main_ref_store(the_repository), NULL,
+				"ORIG_HEAD", old_orig, 0);
+	set_reflog_message(&msg, "updating HEAD", rev);
+	update_ref_status = refs_update_ref(get_main_ref_store(the_repository),
+					    msg.buf, "HEAD", oid, orig, 0,
+					    UPDATE_REFS_MSG_ON_ERR);
+	strbuf_release(&msg);
+	return update_ref_status;
+}
+
+static int git_reset_config(const char *var, const char *value,
+			    const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "submodule.recurse"))
+		return git_default_submodule_config(var, value, cb);
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+int cmd_reset(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo UNUSED)
+{
+	int reset_type = NONE, update_ref_status = 0, quiet = 0;
+	int no_refresh = 0;
+	int patch_mode = 0, pathspec_file_nul = 0, unborn;
+	const char *rev;
+	char *pathspec_from_file = NULL;
+	struct object_id oid;
+	struct pathspec pathspec;
+	int intent_to_add = 0;
+	const struct option options[] = {
+		OPT__QUIET(&quiet, N_("be quiet, only report errors")),
+		OPT_BOOL(0, "no-refresh", &no_refresh,
+				N_("skip refreshing the index after reset")),
+		OPT_SET_INT_F(0, "mixed", &reset_type,
+			      N_("reset HEAD and index"),
+			      MIXED, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "soft", &reset_type,
+			      N_("reset only HEAD"),
+			      SOFT, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "hard", &reset_type,
+			      N_("reset HEAD, index and working tree"),
+			      HARD, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "merge", &reset_type,
+			      N_("reset HEAD, index and working tree"),
+			      MERGE, PARSE_OPT_NONEG),
+		OPT_SET_INT_F(0, "keep", &reset_type,
+			      N_("reset HEAD but keep local changes"),
+			      KEEP, PARSE_OPT_NONEG),
+		OPT_CALLBACK_F(0, "recurse-submodules", NULL,
+			       "reset", "control recursive updating of submodules",
+			       PARSE_OPT_OPTARG,
+			       option_parse_recurse_submodules_worktree_updater),
+		OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
+		OPT_BOOL('N', "intent-to-add", &intent_to_add,
+				N_("record only the fact that removed paths will be added later")),
+		OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+		OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
+		OPT_END()
+	};
+
+	git_config(git_reset_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, options, git_reset_usage,
+						PARSE_OPT_KEEP_DASHDASH);
+	parse_args(&pathspec, argv, prefix, patch_mode, &rev);
+
+	if (pathspec_from_file) {
+		if (patch_mode)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--patch");
+
+		if (pathspec.nr)
+			die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
+
+		parse_pathspec_file(&pathspec, 0,
+				    PATHSPEC_PREFER_FULL,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
+	}
+
+	unborn = !strcmp(rev, "HEAD") && repo_get_oid(the_repository, "HEAD",
+						      &oid);
+	if (unborn) {
+		/* reset on unborn branch: treat as reset to empty tree */
+		oidcpy(&oid, the_hash_algo->empty_tree);
+	} else if (!pathspec.nr && !patch_mode) {
+		struct commit *commit;
+		if (repo_get_oid_committish(the_repository, rev, &oid))
+			die(_("Failed to resolve '%s' as a valid revision."), rev);
+		commit = lookup_commit_reference(the_repository, &oid);
+		if (!commit)
+			die(_("Could not parse object '%s'."), rev);
+		oidcpy(&oid, &commit->object.oid);
+	} else {
+		struct tree *tree;
+		if (repo_get_oid_treeish(the_repository, rev, &oid))
+			die(_("Failed to resolve '%s' as a valid tree."), rev);
+		tree = parse_tree_indirect(&oid);
+		if (!tree)
+			die(_("Could not parse object '%s'."), rev);
+		oidcpy(&oid, &tree->object.oid);
+	}
+
+	if (patch_mode) {
+		if (reset_type != NONE)
+			die(_("options '%s' and '%s' cannot be used together"), "--patch", "--{hard,mixed,soft}");
+		trace2_cmd_mode("patch-interactive");
+		update_ref_status = !!run_add_p(the_repository, ADD_P_RESET, rev,
+				   &pathspec);
+		goto cleanup;
+	}
+
+	/* git reset tree [--] paths... can be used to
+	 * load chosen paths from the tree into the index without
+	 * affecting the working tree nor HEAD. */
+	if (pathspec.nr) {
+		if (reset_type == MIXED)
+			warning(_("--mixed with paths is deprecated; use 'git reset -- <paths>' instead."));
+		else if (reset_type != NONE)
+			die(_("Cannot do %s reset with paths."),
+					_(reset_type_names[reset_type]));
+	}
+	if (reset_type == NONE)
+		reset_type = MIXED; /* by default */
+
+	if (pathspec.nr)
+		trace2_cmd_mode("path");
+	else
+		trace2_cmd_mode(reset_type_names[reset_type]);
+
+	if (reset_type != SOFT && (reset_type != MIXED || repo_get_work_tree(the_repository)))
+		setup_work_tree();
+
+	if (reset_type == MIXED && is_bare_repository())
+		die(_("%s reset is not allowed in a bare repository"),
+		    _(reset_type_names[reset_type]));
+
+	if (intent_to_add && reset_type != MIXED)
+		die(_("the option '%s' requires '%s'"), "-N", "--mixed");
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	if (repo_read_index(the_repository) < 0)
+		die(_("index file corrupt"));
+
+	/* Soft reset does not touch the index file nor the working tree
+	 * at all, but requires them in a good order.  Other resets reset
+	 * the index file to the tree object we are switching to. */
+	if (reset_type == SOFT || reset_type == KEEP)
+		die_if_unmerged_cache(reset_type);
+
+	if (reset_type != SOFT) {
+		struct lock_file lock = LOCK_INIT;
+		repo_hold_locked_index(the_repository, &lock,
+				       LOCK_DIE_ON_ERROR);
+		if (reset_type == MIXED) {
+			int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
+			if (read_from_tree(&pathspec, &oid, intent_to_add)) {
+				update_ref_status = 1;
+				goto cleanup;
+			}
+			the_repository->index->updated_skipworktree = 1;
+			if (!no_refresh && repo_get_work_tree(the_repository)) {
+				uint64_t t_begin, t_delta_in_ms;
+
+				t_begin = getnanotime();
+				refresh_index(the_repository->index, flags, NULL, NULL,
+					      _("Unstaged changes after reset:"));
+				t_delta_in_ms = (getnanotime() - t_begin) / 1000000;
+				if (!quiet && advice_enabled(ADVICE_RESET_NO_REFRESH_WARNING) && t_delta_in_ms > REFRESH_INDEX_DELAY_WARNING_IN_MS) {
+					advise(_("It took %.2f seconds to refresh the index after reset.  You can use\n"
+						 "'--no-refresh' to avoid this."), t_delta_in_ms / 1000.0);
+				}
+			}
+		} else {
+			struct object_id dummy;
+			char *ref = NULL;
+			int err;
+
+			repo_dwim_ref(the_repository, rev, strlen(rev),
+				      &dummy, &ref, 0);
+			if (ref && !starts_with(ref, "refs/"))
+				FREE_AND_NULL(ref);
+
+			err = reset_index(ref, &oid, reset_type, quiet);
+			if (reset_type == KEEP && !err)
+				err = reset_index(ref, &oid, MIXED, quiet);
+			if (err)
+				die(_("Could not reset index file to revision '%s'."), rev);
+			free(ref);
+		}
+
+		if (write_locked_index(the_repository->index, &lock, COMMIT_LOCK))
+			die(_("Could not write new index file."));
+	}
+
+	if (!pathspec.nr && !unborn) {
+		/* Any resets without paths update HEAD to the head being
+		 * switched to, saving the previous head in ORIG_HEAD before. */
+		update_ref_status = reset_refs(rev, &oid);
+
+		if (reset_type == HARD && !update_ref_status && !quiet)
+			print_new_head_line(lookup_commit_reference(the_repository, &oid));
+	}
+	if (!pathspec.nr)
+		remove_branch_state(the_repository, 0);
+
+	discard_index(the_repository->index);
+
+cleanup:
+	clear_pathspec(&pathspec);
+	free(pathspec_from_file);
+	return update_ref_status;
+}
diff --git a/builtin/rev-list.c b/builtin/rev-list.c
new file mode 100644
index 0000000000..beb8c2529d
--- /dev/null
+++ b/builtin/rev-list.c
@@ -0,0 +1,831 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "commit.h"
+#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "revision.h"
+#include "list-objects.h"
+#include "list-objects-filter-options.h"
+#include "object.h"
+#include "object-name.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "pack-bitmap.h"
+#include "log-tree.h"
+#include "graph.h"
+#include "bisect.h"
+#include "progress.h"
+#include "reflog-walk.h"
+#include "oidset.h"
+#include "packfile.h"
+
+static const char rev_list_usage[] =
+"git rev-list [<options>] <commit>... [--] [<path>...]\n"
+"\n"
+"  limiting output:\n"
+"    --max-count=<n>\n"
+"    --max-age=<epoch>\n"
+"    --min-age=<epoch>\n"
+"    --sparse\n"
+"    --no-merges\n"
+"    --min-parents=<n>\n"
+"    --no-min-parents\n"
+"    --max-parents=<n>\n"
+"    --no-max-parents\n"
+"    --remove-empty\n"
+"    --all\n"
+"    --branches\n"
+"    --tags\n"
+"    --remotes\n"
+"    --stdin\n"
+"    --exclude-hidden=[fetch|receive|uploadpack]\n"
+"    --quiet\n"
+"  ordering output:\n"
+"    --topo-order\n"
+"    --date-order\n"
+"    --reverse\n"
+"  formatting output:\n"
+"    --parents\n"
+"    --children\n"
+"    --objects | --objects-edge\n"
+"    --disk-usage[=human]\n"
+"    --unpacked\n"
+"    --header | --pretty\n"
+"    --[no-]object-names\n"
+"    --abbrev=<n> | --no-abbrev\n"
+"    --abbrev-commit\n"
+"    --left-right\n"
+"    --count\n"
+"  special purpose:\n"
+"    --bisect\n"
+"    --bisect-vars\n"
+"    --bisect-all"
+;
+
+static struct progress *progress;
+static unsigned progress_counter;
+
+static struct oidset omitted_objects;
+static int arg_print_omitted; /* print objects omitted by filter */
+
+static struct oidset missing_objects;
+enum missing_action {
+	MA_ERROR = 0,    /* fail if any missing objects are encountered */
+	MA_ALLOW_ANY,    /* silently allow ALL missing objects */
+	MA_PRINT,        /* print ALL missing objects in special section */
+	MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
+};
+static enum missing_action arg_missing_action;
+
+/* display only the oid of each object encountered */
+static int arg_show_object_names = 1;
+
+#define DEFAULT_OIDSET_SIZE     (16*1024)
+
+static int show_disk_usage;
+static off_t total_disk_usage;
+static int human_readable;
+
+static off_t get_object_disk_usage(struct object *obj)
+{
+	off_t size;
+	struct object_info oi = OBJECT_INFO_INIT;
+	oi.disk_sizep = &size;
+	if (oid_object_info_extended(the_repository, &obj->oid, &oi, 0) < 0)
+		die(_("unable to get disk usage of %s"), oid_to_hex(&obj->oid));
+	return size;
+}
+
+static inline void finish_object__ma(struct object *obj)
+{
+	/*
+	 * Whether or not we try to dynamically fetch missing objects
+	 * from the server, we currently DO NOT have the object.  We
+	 * can either print, allow (ignore), or conditionally allow
+	 * (ignore) them.
+	 */
+	switch (arg_missing_action) {
+	case MA_ERROR:
+		die("missing %s object '%s'",
+		    type_name(obj->type), oid_to_hex(&obj->oid));
+		return;
+
+	case MA_ALLOW_ANY:
+		return;
+
+	case MA_PRINT:
+		oidset_insert(&missing_objects, &obj->oid);
+		return;
+
+	case MA_ALLOW_PROMISOR:
+		if (is_promisor_object(the_repository, &obj->oid))
+			return;
+		die("unexpected missing %s object '%s'",
+		    type_name(obj->type), oid_to_hex(&obj->oid));
+		return;
+
+	default:
+		BUG("unhandled missing_action");
+		return;
+	}
+}
+
+static void finish_commit(struct commit *commit)
+{
+	free_commit_list(commit->parents);
+	commit->parents = NULL;
+	free_commit_buffer(the_repository->parsed_objects,
+			   commit);
+}
+
+static void show_commit(struct commit *commit, void *data)
+{
+	struct rev_list_info *info = data;
+	struct rev_info *revs = info->revs;
+
+	display_progress(progress, ++progress_counter);
+
+	if (revs->do_not_die_on_missing_objects &&
+	    oidset_contains(&revs->missing_commits, &commit->object.oid)) {
+		finish_object__ma(&commit->object);
+		return;
+	}
+
+	if (show_disk_usage)
+		total_disk_usage += get_object_disk_usage(&commit->object);
+
+	if (info->flags & REV_LIST_QUIET) {
+		finish_commit(commit);
+		return;
+	}
+
+	graph_show_commit(revs->graph);
+
+	if (revs->count) {
+		if (commit->object.flags & PATCHSAME)
+			revs->count_same++;
+		else if (commit->object.flags & SYMMETRIC_LEFT)
+			revs->count_left++;
+		else
+			revs->count_right++;
+		finish_commit(commit);
+		return;
+	}
+
+	if (info->show_timestamp)
+		printf("%"PRItime" ", commit->date);
+	if (info->header_prefix)
+		fputs(info->header_prefix, stdout);
+
+	if (revs->include_header) {
+		if (!revs->graph)
+			fputs(get_revision_mark(revs, commit), stdout);
+		if (revs->abbrev_commit && revs->abbrev)
+			fputs(repo_find_unique_abbrev(the_repository, &commit->object.oid, revs->abbrev),
+			      stdout);
+		else
+			fputs(oid_to_hex(&commit->object.oid), stdout);
+	}
+	if (revs->print_parents) {
+		struct commit_list *parents = commit->parents;
+		while (parents) {
+			printf(" %s", oid_to_hex(&parents->item->object.oid));
+			parents = parents->next;
+		}
+	}
+	if (revs->children.name) {
+		struct commit_list *children;
+
+		children = lookup_decoration(&revs->children, &commit->object);
+		while (children) {
+			printf(" %s", oid_to_hex(&children->item->object.oid));
+			children = children->next;
+		}
+	}
+	show_decorations(revs, commit);
+	if (revs->commit_format == CMIT_FMT_ONELINE)
+		putchar(' ');
+	else if (revs->include_header)
+		putchar('\n');
+
+	if (revs->verbose_header) {
+		struct strbuf buf = STRBUF_INIT;
+		struct pretty_print_context ctx = {0};
+		ctx.abbrev = revs->abbrev;
+		ctx.date_mode = revs->date_mode;
+		ctx.date_mode_explicit = revs->date_mode_explicit;
+		ctx.fmt = revs->commit_format;
+		ctx.output_encoding = get_log_output_encoding();
+		ctx.color = revs->diffopt.use_color;
+		ctx.rev = revs;
+		pretty_print_commit(&ctx, commit, &buf);
+		if (buf.len) {
+			if (revs->commit_format != CMIT_FMT_ONELINE)
+				graph_show_oneline(revs->graph);
+
+			graph_show_commit_msg(revs->graph, stdout, &buf);
+
+			/*
+			 * Add a newline after the commit message.
+			 *
+			 * Usually, this newline produces a blank
+			 * padding line between entries, in which case
+			 * we need to add graph padding on this line.
+			 *
+			 * However, the commit message may not end in a
+			 * newline.  In this case the newline simply
+			 * ends the last line of the commit message,
+			 * and we don't need any graph output.  (This
+			 * always happens with CMIT_FMT_ONELINE, and it
+			 * happens with CMIT_FMT_USERFORMAT when the
+			 * format doesn't explicitly end in a newline.)
+			 */
+			if (buf.len && buf.buf[buf.len - 1] == '\n')
+				graph_show_padding(revs->graph);
+			putchar(info->hdr_termination);
+		} else {
+			/*
+			 * If the message buffer is empty, just show
+			 * the rest of the graph output for this
+			 * commit.
+			 */
+			if (graph_show_remainder(revs->graph))
+				putchar('\n');
+			if (revs->commit_format == CMIT_FMT_ONELINE)
+				putchar('\n');
+		}
+		strbuf_release(&buf);
+	} else {
+		if (graph_show_remainder(revs->graph))
+			putchar('\n');
+	}
+	maybe_flush_or_die(stdout, "stdout");
+	finish_commit(commit);
+}
+
+static int finish_object(struct object *obj, const char *name UNUSED,
+			 void *cb_data)
+{
+	struct rev_list_info *info = cb_data;
+	if (oid_object_info_extended(the_repository, &obj->oid, NULL, 0) < 0) {
+		finish_object__ma(obj);
+		return 1;
+	}
+	if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
+		parse_object(the_repository, &obj->oid);
+	return 0;
+}
+
+static void show_object(struct object *obj, const char *name, void *cb_data)
+{
+	struct rev_list_info *info = cb_data;
+	struct rev_info *revs = info->revs;
+
+	if (finish_object(obj, name, cb_data))
+		return;
+	display_progress(progress, ++progress_counter);
+	if (show_disk_usage)
+		total_disk_usage += get_object_disk_usage(obj);
+	if (info->flags & REV_LIST_QUIET)
+		return;
+
+	if (revs->count) {
+		/*
+		 * The object count is always accumulated in the .count_right
+		 * field for traversal that is not a left-right traversal,
+		 * and cmd_rev_list() made sure that a .count request that
+		 * wants to count non-commit objects, which is handled by
+		 * the show_object() callback, does not ask for .left_right.
+		 */
+		revs->count_right++;
+		return;
+	}
+
+	if (arg_show_object_names)
+		show_object_with_name(stdout, obj, name);
+	else
+		printf("%s\n", oid_to_hex(&obj->oid));
+}
+
+static void show_edge(struct commit *commit)
+{
+	printf("-%s\n", oid_to_hex(&commit->object.oid));
+}
+
+static void print_var_str(const char *var, const char *val)
+{
+	printf("%s='%s'\n", var, val);
+}
+
+static void print_var_int(const char *var, int val)
+{
+	printf("%s=%d\n", var, val);
+}
+
+static int show_bisect_vars(struct rev_list_info *info, int reaches, int all)
+{
+	int cnt, flags = info->flags;
+	char hex[GIT_MAX_HEXSZ + 1] = "";
+	struct commit_list *tried;
+	struct rev_info *revs = info->revs;
+
+	if (!revs->commits)
+		return 1;
+
+	revs->commits = filter_skipped(revs->commits, &tried,
+				       flags & BISECT_SHOW_ALL,
+				       NULL, NULL);
+
+	/*
+	 * revs->commits can reach "reaches" commits among
+	 * "all" commits.  If it is good, then there are
+	 * (all-reaches) commits left to be bisected.
+	 * On the other hand, if it is bad, then the set
+	 * to bisect is "reaches".
+	 * A bisect set of size N has (N-1) commits further
+	 * to test, as we already know one bad one.
+	 */
+	cnt = all - reaches;
+	if (cnt < reaches)
+		cnt = reaches;
+
+	if (revs->commits)
+		oid_to_hex_r(hex, &revs->commits->item->object.oid);
+
+	if (flags & BISECT_SHOW_ALL) {
+		traverse_commit_list(revs, show_commit, show_object, info);
+		printf("------\n");
+	}
+
+	print_var_str("bisect_rev", hex);
+	print_var_int("bisect_nr", cnt - 1);
+	print_var_int("bisect_good", all - reaches - 1);
+	print_var_int("bisect_bad", reaches - 1);
+	print_var_int("bisect_all", all);
+	print_var_int("bisect_steps", estimate_bisect_steps(all));
+
+	return 0;
+}
+
+static int show_object_fast(
+	const struct object_id *oid,
+	enum object_type type UNUSED,
+	int exclude UNUSED,
+	uint32_t name_hash UNUSED,
+	struct packed_git *found_pack UNUSED,
+	off_t found_offset UNUSED)
+{
+	fprintf(stdout, "%s\n", oid_to_hex(oid));
+	return 1;
+}
+
+static void print_disk_usage(off_t size)
+{
+	struct strbuf sb = STRBUF_INIT;
+	if (human_readable)
+		strbuf_humanise_bytes(&sb, size);
+	else
+		strbuf_addf(&sb, "%"PRIuMAX, (uintmax_t)size);
+	puts(sb.buf);
+	strbuf_release(&sb);
+}
+
+static inline int parse_missing_action_value(const char *value)
+{
+	if (!strcmp(value, "error")) {
+		arg_missing_action = MA_ERROR;
+		return 1;
+	}
+
+	if (!strcmp(value, "allow-any")) {
+		arg_missing_action = MA_ALLOW_ANY;
+		fetch_if_missing = 0;
+		return 1;
+	}
+
+	if (!strcmp(value, "print")) {
+		arg_missing_action = MA_PRINT;
+		fetch_if_missing = 0;
+		return 1;
+	}
+
+	if (!strcmp(value, "allow-promisor")) {
+		arg_missing_action = MA_ALLOW_PROMISOR;
+		fetch_if_missing = 0;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int try_bitmap_count(struct rev_info *revs,
+			    int filter_provided_objects)
+{
+	uint32_t commit_count = 0,
+		 tag_count = 0,
+		 tree_count = 0,
+		 blob_count = 0;
+	int max_count;
+	struct bitmap_index *bitmap_git;
+
+	/* This function only handles counting, not general traversal. */
+	if (!revs->count)
+		return -1;
+
+	/*
+	 * A bitmap result can't know left/right, etc, because we don't
+	 * actually traverse.
+	 */
+	if (revs->left_right || revs->cherry_mark)
+		return -1;
+
+	/*
+	 * If we're counting reachable objects, we can't handle a max count of
+	 * commits to traverse, since we don't know which objects go with which
+	 * commit.
+	 */
+	if (revs->max_count >= 0 &&
+	    (revs->tag_objects || revs->tree_objects || revs->blob_objects))
+		return -1;
+
+	/*
+	 * This must be saved before doing any walking, since the revision
+	 * machinery will count it down to zero while traversing.
+	 */
+	max_count = revs->max_count;
+
+	bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects);
+	if (!bitmap_git)
+		return -1;
+
+	count_bitmap_commit_list(bitmap_git, &commit_count,
+				 revs->tree_objects ? &tree_count : NULL,
+				 revs->blob_objects ? &blob_count : NULL,
+				 revs->tag_objects ? &tag_count : NULL);
+	if (max_count >= 0 && max_count < commit_count)
+		commit_count = max_count;
+
+	printf("%d\n", commit_count + tree_count + blob_count + tag_count);
+	free_bitmap_index(bitmap_git);
+	return 0;
+}
+
+static int try_bitmap_traversal(struct rev_info *revs,
+				int filter_provided_objects)
+{
+	struct bitmap_index *bitmap_git;
+
+	/*
+	 * We can't use a bitmap result with a traversal limit, since the set
+	 * of commits we'd get would be essentially random.
+	 */
+	if (revs->max_count >= 0)
+		return -1;
+
+	/*
+	 * We can't know which commits were left/right in a single traversal,
+	 * and we don't yet know how to traverse them separately.
+	 */
+	if (revs->left_right)
+		return -1;
+
+	bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects);
+	if (!bitmap_git)
+		return -1;
+
+	traverse_bitmap_commit_list(bitmap_git, revs, &show_object_fast);
+	free_bitmap_index(bitmap_git);
+	return 0;
+}
+
+static int try_bitmap_disk_usage(struct rev_info *revs,
+				 int filter_provided_objects)
+{
+	struct bitmap_index *bitmap_git;
+	off_t size_from_bitmap;
+
+	if (!show_disk_usage)
+		return -1;
+
+	bitmap_git = prepare_bitmap_walk(revs, filter_provided_objects);
+	if (!bitmap_git)
+		return -1;
+
+	size_from_bitmap = get_disk_usage_from_bitmap(bitmap_git, revs);
+	print_disk_usage(size_from_bitmap);
+
+	free_bitmap_index(bitmap_git);
+	return 0;
+}
+
+int cmd_rev_list(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct rev_info revs;
+	struct rev_list_info info;
+	struct setup_revision_opt s_r_opt = {
+		.allow_exclude_promisor_objects = 1,
+	};
+	int i;
+	int bisect_list = 0;
+	int bisect_show_vars = 0;
+	int bisect_find_all = 0;
+	int use_bitmap_index = 0;
+	int filter_provided_objects = 0;
+	const char *show_progress = NULL;
+	int ret = 0;
+
+	show_usage_if_asked(argc, argv, rev_list_usage);
+
+	git_config(git_default_config, NULL);
+	repo_init_revisions(the_repository, &revs, prefix);
+	revs.abbrev = DEFAULT_ABBREV;
+	revs.commit_format = CMIT_FMT_UNSPECIFIED;
+	revs.include_header = 1;
+
+	/*
+	 * Scan the argument list before invoking setup_revisions(), so that we
+	 * know if fetch_if_missing needs to be set to 0.
+	 *
+	 * "--exclude-promisor-objects" acts as a pre-filter on missing objects
+	 * by not crossing the boundary from realized objects to promisor
+	 * objects.
+	 *
+	 * Let "--missing" to conditionally set fetch_if_missing.
+	 */
+	/*
+	 * NEEDSWORK: These loops that attempt to find presence of
+	 * options without understanding that the options they are
+	 * skipping are broken (e.g., it would not know "--grep
+	 * --exclude-promisor-objects" is not triggering
+	 * "--exclude-promisor-objects" option).  We really need
+	 * setup_revisions() to have a mechanism to allow and disallow
+	 * some sets of options for different commands (like rev-list,
+	 * replay, etc). Such a mechanism should do an early parsing
+	 * of options and be able to manage the `--missing=...` and
+	 * `--exclude-promisor-objects` options below.
+	 */
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (!strcmp(arg, "--exclude-promisor-objects")) {
+			fetch_if_missing = 0;
+			revs.exclude_promisor_objects = 1;
+			break;
+		}
+	}
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (skip_prefix(arg, "--missing=", &arg)) {
+			if (revs.exclude_promisor_objects)
+				die(_("options '%s' and '%s' cannot be used together"), "--exclude-promisor-objects", "--missing");
+			if (parse_missing_action_value(arg))
+				break;
+		}
+	}
+
+	if (arg_missing_action)
+		revs.do_not_die_on_missing_objects = 1;
+
+	argc = setup_revisions(argc, argv, &revs, &s_r_opt);
+
+	memset(&info, 0, sizeof(info));
+	info.revs = &revs;
+	if (revs.bisect)
+		bisect_list = 1;
+
+	if (revs.diffopt.flags.quick)
+		info.flags |= REV_LIST_QUIET;
+	for (i = 1 ; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (!strcmp(arg, "--header")) {
+			revs.verbose_header = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--timestamp")) {
+			info.show_timestamp = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--bisect")) {
+			bisect_list = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--bisect-all")) {
+			bisect_list = 1;
+			bisect_find_all = 1;
+			info.flags |= BISECT_SHOW_ALL;
+			revs.show_decorations = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--bisect-vars")) {
+			bisect_list = 1;
+			bisect_show_vars = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--use-bitmap-index")) {
+			use_bitmap_index = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--test-bitmap")) {
+			test_bitmap_walk(&revs);
+			goto cleanup;
+		}
+		if (skip_prefix(arg, "--progress=", &arg)) {
+			show_progress = arg;
+			continue;
+		}
+		if (!strcmp(arg, "--filter-provided-objects")) {
+			filter_provided_objects = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--filter-print-omitted")) {
+			arg_print_omitted = 1;
+			continue;
+		}
+
+		if (!strcmp(arg, "--exclude-promisor-objects"))
+			continue; /* already handled above */
+		if (skip_prefix(arg, "--missing=", &arg))
+			continue; /* already handled above */
+
+		if (!strcmp(arg, ("--no-object-names"))) {
+			arg_show_object_names = 0;
+			continue;
+		}
+
+		if (!strcmp(arg, ("--object-names"))) {
+			arg_show_object_names = 1;
+			continue;
+		}
+
+		if (!strcmp(arg, ("--commit-header"))) {
+			revs.include_header = 1;
+			continue;
+		}
+
+		if (!strcmp(arg, ("--no-commit-header"))) {
+			revs.include_header = 0;
+			continue;
+		}
+
+		if (skip_prefix(arg, "--disk-usage", &arg)) {
+			if (*arg == '=') {
+				if (!strcmp(++arg, "human")) {
+					human_readable = 1;
+				} else
+					die(_("invalid value for '%s': '%s', the only allowed format is '%s'"),
+					    "--disk-usage=<format>", arg, "human");
+			} else if (*arg) {
+				/*
+				 * Arguably should goto a label to continue chain of ifs?
+				 * Doesn't matter unless we try to add --disk-usage-foo
+				 * afterwards.
+				 */
+				usage(rev_list_usage);
+			}
+			show_disk_usage = 1;
+			info.flags |= REV_LIST_QUIET;
+			continue;
+		}
+
+		usage(rev_list_usage);
+
+	}
+	if (revs.commit_format != CMIT_FMT_USERFORMAT)
+		revs.include_header = 1;
+	if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
+		/* The command line has a --pretty  */
+		info.hdr_termination = '\n';
+		if (revs.commit_format == CMIT_FMT_ONELINE || !revs.include_header)
+			info.header_prefix = "";
+		else
+			info.header_prefix = "commit ";
+	}
+	else if (revs.verbose_header)
+		/* Only --header was specified */
+		revs.commit_format = CMIT_FMT_RAW;
+
+	if ((!revs.commits && reflog_walk_empty(revs.reflog_info) &&
+	     (!(revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
+	      !revs.pending.nr) &&
+	     !revs.rev_input_given && !revs.read_from_stdin) ||
+	    revs.diff)
+		usage(rev_list_usage);
+
+	if (revs.show_notes)
+		die(_("rev-list does not support display of notes"));
+
+	if (revs.count &&
+	    (revs.tag_objects || revs.tree_objects || revs.blob_objects) &&
+	    (revs.left_right || revs.cherry_mark))
+		die(_("marked counting and '%s' cannot be used together"), "--objects");
+
+	save_commit_buffer = (revs.verbose_header ||
+			      revs.grep_filter.pattern_list ||
+			      revs.grep_filter.header_list);
+	if (bisect_list)
+		revs.limited = 1;
+
+	if (show_progress)
+		progress = start_delayed_progress(the_repository,
+						  show_progress, 0);
+
+	if (use_bitmap_index) {
+		if (!try_bitmap_count(&revs, filter_provided_objects))
+			goto cleanup;
+		if (!try_bitmap_disk_usage(&revs, filter_provided_objects))
+			goto cleanup;
+		if (!try_bitmap_traversal(&revs, filter_provided_objects))
+			goto cleanup;
+	}
+
+	if (prepare_revision_walk(&revs))
+		die("revision walk setup failed");
+	if (revs.tree_objects)
+		mark_edges_uninteresting(&revs, show_edge, 0);
+
+	if (bisect_list) {
+		int reaches, all;
+		unsigned bisect_flags = 0;
+
+		if (bisect_find_all)
+			bisect_flags |= FIND_BISECTION_ALL;
+
+		if (revs.first_parent_only)
+			bisect_flags |= FIND_BISECTION_FIRST_PARENT_ONLY;
+
+		find_bisection(&revs.commits, &reaches, &all, bisect_flags);
+
+		if (bisect_show_vars) {
+			ret = show_bisect_vars(&info, reaches, all);
+			goto cleanup;
+		}
+	}
+
+	if (filter_provided_objects) {
+		struct commit_list *c;
+		for (i = 0; i < revs.pending.nr; i++) {
+			struct object_array_entry *pending = revs.pending.objects + i;
+			pending->item->flags |= NOT_USER_GIVEN;
+		}
+		for (c = revs.commits; c; c = c->next)
+			c->item->object.flags |= NOT_USER_GIVEN;
+	}
+
+	if (arg_print_omitted)
+		oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
+	if (arg_missing_action == MA_PRINT) {
+		oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
+		/* Add missing tips */
+		oidset_insert_from_set(&missing_objects, &revs.missing_commits);
+		oidset_clear(&revs.missing_commits);
+	}
+
+	traverse_commit_list_filtered(
+		&revs, show_commit, show_object, &info,
+		(arg_print_omitted ? &omitted_objects : NULL));
+
+	if (arg_print_omitted) {
+		struct oidset_iter iter;
+		struct object_id *oid;
+		oidset_iter_init(&omitted_objects, &iter);
+		while ((oid = oidset_iter_next(&iter)))
+			printf("~%s\n", oid_to_hex(oid));
+		oidset_clear(&omitted_objects);
+	}
+	if (arg_missing_action == MA_PRINT) {
+		struct oidset_iter iter;
+		struct object_id *oid;
+		oidset_iter_init(&missing_objects, &iter);
+		while ((oid = oidset_iter_next(&iter)))
+			printf("?%s\n", oid_to_hex(oid));
+		oidset_clear(&missing_objects);
+	}
+
+	stop_progress(&progress);
+
+	if (revs.count) {
+		if (revs.left_right && revs.cherry_mark)
+			printf("%d\t%d\t%d\n", revs.count_left, revs.count_right, revs.count_same);
+		else if (revs.left_right)
+			printf("%d\t%d\n", revs.count_left, revs.count_right);
+		else if (revs.cherry_mark)
+			printf("%d\t%d\n", revs.count_left + revs.count_right, revs.count_same);
+		else
+			printf("%d\n", revs.count_left + revs.count_right);
+	}
+
+	if (show_disk_usage)
+		print_disk_usage(total_disk_usage);
+
+cleanup:
+	release_revisions(&revs);
+	return ret;
+}
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
new file mode 100644
index 0000000000..428c866c05
--- /dev/null
+++ b/builtin/rev-parse.c
@@ -0,0 +1,1177 @@
+/*
+ * rev-parse.c
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+
+#include "abspath.h"
+#include "config.h"
+#include "commit.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "refs.h"
+#include "quote.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "path.h"
+#include "diff.h"
+#include "read-cache-ll.h"
+#include "repo-settings.h"
+#include "repository.h"
+#include "revision.h"
+#include "setup.h"
+#include "split-index.h"
+#include "submodule.h"
+#include "commit-reach.h"
+#include "shallow.h"
+#include "object-file-convert.h"
+
+#define DO_REVS		1
+#define DO_NOREV	2
+#define DO_FLAGS	4
+#define DO_NONFLAGS	8
+static int filter = ~0;
+
+static const char *def;
+
+#define NORMAL 0
+#define REVERSED 1
+static int show_type = NORMAL;
+
+#define SHOW_SYMBOLIC_ASIS 1
+#define SHOW_SYMBOLIC_FULL 2
+static int symbolic;
+static int abbrev;
+static int abbrev_ref;
+static int abbrev_ref_strict;
+static int output_sq;
+
+static int stuck_long;
+static struct ref_exclusions ref_excludes = REF_EXCLUSIONS_INIT;
+
+/*
+ * Some arguments are relevant "revision" arguments,
+ * others are about output format or other details.
+ * This sorts it all out.
+ */
+static int is_rev_argument(const char *arg)
+{
+	static const char *rev_args[] = {
+		"--all",
+		"--bisect",
+		"--dense",
+		"--branches=",
+		"--branches",
+		"--header",
+		"--ignore-missing",
+		"--max-age=",
+		"--max-count=",
+		"--min-age=",
+		"--no-merges",
+		"--min-parents=",
+		"--no-min-parents",
+		"--max-parents=",
+		"--no-max-parents",
+		"--objects",
+		"--objects-edge",
+		"--parents",
+		"--pretty",
+		"--remotes=",
+		"--remotes",
+		"--glob=",
+		"--sparse",
+		"--tags=",
+		"--tags",
+		"--topo-order",
+		"--date-order",
+		"--unpacked",
+		NULL
+	};
+	const char **p = rev_args;
+
+	/* accept -<digit>, like traditional "head" */
+	if ((*arg == '-') && isdigit(arg[1]))
+		return 1;
+
+	for (;;) {
+		const char *str = *p++;
+		int len;
+		if (!str)
+			return 0;
+		len = strlen(str);
+		if (!strcmp(arg, str) ||
+		    (str[len-1] == '=' && !strncmp(arg, str, len)))
+			return 1;
+	}
+}
+
+/* Output argument as a string, either SQ or normal */
+static void show(const char *arg)
+{
+	if (output_sq) {
+		int sq = '\'', ch;
+
+		putchar(sq);
+		while ((ch = *arg++)) {
+			if (ch == sq)
+				fputs("'\\'", stdout);
+			putchar(ch);
+		}
+		putchar(sq);
+		putchar(' ');
+	}
+	else
+		puts(arg);
+}
+
+/* Like show(), but with a negation prefix according to type */
+static void show_with_type(int type, const char *arg)
+{
+	if (type != show_type)
+		putchar('^');
+	show(arg);
+}
+
+/* Output a revision, only if filter allows it */
+static void show_rev(int type, const struct object_id *oid, const char *name)
+{
+	if (!(filter & DO_REVS))
+		return;
+	def = NULL;
+
+	if ((symbolic || abbrev_ref) && name) {
+		if (symbolic == SHOW_SYMBOLIC_FULL || abbrev_ref) {
+			struct object_id discard;
+			char *full;
+
+			switch (repo_dwim_ref(the_repository, name,
+					      strlen(name), &discard, &full,
+					      0)) {
+			case 0:
+				/*
+				 * Not found -- not a ref.  We could
+				 * emit "name" here, but symbolic-full
+				 * users are interested in finding the
+				 * refs spelled in full, and they would
+				 * need to filter non-refs if we did so.
+				 */
+				break;
+			case 1: /* happy */
+				if (abbrev_ref) {
+					char *old = full;
+					full = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+									    full,
+									    abbrev_ref_strict);
+					free(old);
+				}
+				show_with_type(type, full);
+				break;
+			default: /* ambiguous */
+				error("refname '%s' is ambiguous", name);
+				break;
+			}
+			free(full);
+		} else {
+			show_with_type(type, name);
+		}
+	}
+	else if (abbrev)
+		show_with_type(type,
+			       repo_find_unique_abbrev(the_repository, oid, abbrev));
+	else
+		show_with_type(type, oid_to_hex(oid));
+}
+
+/* Output a flag, only if filter allows it. */
+static int show_flag(const char *arg)
+{
+	if (!(filter & DO_FLAGS))
+		return 0;
+	if (filter & (is_rev_argument(arg) ? DO_REVS : DO_NOREV)) {
+		show(arg);
+		return 1;
+	}
+	return 0;
+}
+
+static int show_default(void)
+{
+	const char *s = def;
+
+	if (s) {
+		struct object_id oid;
+
+		def = NULL;
+		if (!repo_get_oid(the_repository, s, &oid)) {
+			show_rev(NORMAL, &oid, s);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static int show_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+			  int flag UNUSED, void *cb_data UNUSED)
+{
+	if (ref_excluded(&ref_excludes, refname))
+		return 0;
+	show_rev(NORMAL, oid, refname);
+	return 0;
+}
+
+static int anti_reference(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+			  int flag UNUSED, void *cb_data UNUSED)
+{
+	show_rev(REVERSED, oid, refname);
+	return 0;
+}
+
+static int show_abbrev(const struct object_id *oid, void *cb_data UNUSED)
+{
+	show_rev(NORMAL, oid, NULL);
+	return 0;
+}
+
+static void show_datestring(const char *flag, const char *datestr)
+{
+	char *buffer;
+
+	/* date handling requires both flags and revs */
+	if ((filter & (DO_FLAGS | DO_REVS)) != (DO_FLAGS | DO_REVS))
+		return;
+	buffer = xstrfmt("%s%"PRItime, flag, approxidate(datestr));
+	show(buffer);
+	free(buffer);
+}
+
+static int show_file(const char *arg, int output_prefix)
+{
+	show_default();
+	if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
+		if (output_prefix) {
+			const char *prefix = startup_info->prefix;
+			char *fname = prefix_filename(prefix, arg);
+			show(fname);
+			free(fname);
+		} else
+			show(arg);
+		return 1;
+	}
+	return 0;
+}
+
+static int try_difference(const char *arg)
+{
+	char *dotdot;
+	struct object_id start_oid;
+	struct object_id end_oid;
+	const char *end;
+	const char *start;
+	int symmetric;
+	static const char head_by_default[] = "HEAD";
+
+	if (!(dotdot = strstr(arg, "..")))
+		return 0;
+	end = dotdot + 2;
+	start = arg;
+	symmetric = (*end == '.');
+
+	*dotdot = 0;
+	end += symmetric;
+
+	if (!*end)
+		end = head_by_default;
+	if (dotdot == arg)
+		start = head_by_default;
+
+	if (start == head_by_default && end == head_by_default &&
+	    !symmetric) {
+		/*
+		 * Just ".."?  That is not a range but the
+		 * pathspec for the parent directory.
+		 */
+		*dotdot = '.';
+		return 0;
+	}
+
+	if (!repo_get_oid_committish(the_repository, start, &start_oid) && !repo_get_oid_committish(the_repository, end, &end_oid)) {
+		show_rev(NORMAL, &end_oid, end);
+		show_rev(symmetric ? NORMAL : REVERSED, &start_oid, start);
+		if (symmetric) {
+			struct commit_list *exclude = NULL;
+			struct commit *a, *b;
+			a = lookup_commit_reference(the_repository, &start_oid);
+			b = lookup_commit_reference(the_repository, &end_oid);
+			if (!a || !b) {
+				*dotdot = '.';
+				return 0;
+			}
+			if (repo_get_merge_bases(the_repository, a, b, &exclude) < 0)
+				exit(128);
+			while (exclude) {
+				struct commit *commit = pop_commit(&exclude);
+				show_rev(REVERSED, &commit->object.oid, NULL);
+			}
+		}
+		*dotdot = '.';
+		return 1;
+	}
+	*dotdot = '.';
+	return 0;
+}
+
+static int try_parent_shorthands(const char *arg)
+{
+	char *dotdot;
+	struct object_id oid;
+	struct commit *commit;
+	struct commit_list *parents;
+	int parent_number;
+	int include_rev = 0;
+	int include_parents = 0;
+	int exclude_parent = 0;
+
+	if ((dotdot = strstr(arg, "^!"))) {
+		include_rev = 1;
+		if (dotdot[2])
+			return 0;
+	} else if ((dotdot = strstr(arg, "^@"))) {
+		include_parents = 1;
+		if (dotdot[2])
+			return 0;
+	} else if ((dotdot = strstr(arg, "^-"))) {
+		include_rev = 1;
+		exclude_parent = 1;
+
+		if (dotdot[2]) {
+			char *end;
+			exclude_parent = strtoul(dotdot + 2, &end, 10);
+			if (*end != '\0' || !exclude_parent)
+				return 0;
+		}
+	} else
+		return 0;
+
+	*dotdot = 0;
+	if (repo_get_oid_committish(the_repository, arg, &oid) ||
+	    !(commit = lookup_commit_reference(the_repository, &oid))) {
+		*dotdot = '^';
+		return 0;
+	}
+
+	if (exclude_parent &&
+	    exclude_parent > commit_list_count(commit->parents)) {
+		*dotdot = '^';
+		return 0;
+	}
+
+	if (include_rev)
+		show_rev(NORMAL, &oid, arg);
+	for (parents = commit->parents, parent_number = 1;
+	     parents;
+	     parents = parents->next, parent_number++) {
+		char *name = NULL;
+
+		if (exclude_parent && parent_number != exclude_parent)
+			continue;
+
+		if (symbolic)
+			name = xstrfmt("%s^%d", arg, parent_number);
+		show_rev(include_parents ? NORMAL : REVERSED,
+			 &parents->item->object.oid, name);
+		free(name);
+	}
+
+	*dotdot = '^';
+	return 1;
+}
+
+static int parseopt_dump(const struct option *o, const char *arg, int unset)
+{
+	struct strbuf *parsed = o->value;
+	if (unset)
+		strbuf_addf(parsed, " --no-%s", o->long_name);
+	else if (o->short_name && (o->long_name == NULL || !stuck_long))
+		strbuf_addf(parsed, " -%c", o->short_name);
+	else
+		strbuf_addf(parsed, " --%s", o->long_name);
+	if (arg) {
+		if (!stuck_long)
+			strbuf_addch(parsed, ' ');
+		else if (o->long_name)
+			strbuf_addch(parsed, '=');
+		sq_quote_buf(parsed, arg);
+	}
+	return 0;
+}
+
+static const char *skipspaces(const char *s)
+{
+	while (isspace(*s))
+		s++;
+	return s;
+}
+
+static char *findspace(const char *s)
+{
+	for (; *s; s++)
+		if (isspace(*s))
+			return (char*)s;
+	return NULL;
+}
+
+static int cmd_parseopt(int argc, const char **argv, const char *prefix)
+{
+	int keep_dashdash = 0, stop_at_non_option = 0;
+	char const * const parseopt_usage[] = {
+		N_("git rev-parse --parseopt [<options>] -- [<args>...]"),
+		NULL
+	};
+	struct option parseopt_opts[] = {
+		OPT_BOOL(0, "keep-dashdash", &keep_dashdash,
+					N_("keep the `--` passed as an arg")),
+		OPT_BOOL(0, "stop-at-non-option", &stop_at_non_option,
+					N_("stop parsing after the "
+					   "first non-option argument")),
+		OPT_BOOL(0, "stuck-long", &stuck_long,
+					N_("output in stuck long form")),
+		OPT_END(),
+	};
+	struct strbuf sb = STRBUF_INIT, parsed = STRBUF_INIT;
+	struct strvec longnames = STRVEC_INIT;
+	struct strvec usage = STRVEC_INIT;
+	struct option *opts = NULL;
+	size_t opts_nr = 0, opts_alloc = 0;
+
+	strbuf_addstr(&parsed, "set --");
+	argc = parse_options(argc, argv, prefix, parseopt_opts, parseopt_usage,
+	                     PARSE_OPT_KEEP_DASHDASH);
+	if (argc < 1 || strcmp(argv[0], "--"))
+		usage_with_options(parseopt_usage, parseopt_opts);
+
+	/* get the usage up to the first line with a -- on it */
+	for (;;) {
+		strbuf_reset(&sb);
+		if (strbuf_getline(&sb, stdin) == EOF)
+			die(_("premature end of input"));
+		if (!strcmp("--", sb.buf)) {
+			if (!usage.nr)
+				die(_("no usage string given before the `--' separator"));
+			break;
+		}
+
+		strvec_push(&usage, sb.buf);
+	}
+
+	/* parse: (<short>|<short>,<long>|<long>)[*=?!]*<arghint>? SP+ <help> */
+	while (strbuf_getline(&sb, stdin) != EOF) {
+		const char *s;
+		char *help;
+		struct option *o;
+
+		if (!sb.len)
+			continue;
+
+		ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
+		memset(opts + opts_nr, 0, sizeof(*opts));
+
+		o = &opts[opts_nr++];
+		help = findspace(sb.buf);
+		if (!help || sb.buf == help) {
+			o->type = OPTION_GROUP;
+			o->help = xstrdup(skipspaces(sb.buf));
+			continue;
+		}
+
+		*help = '\0';
+
+		o->type = OPTION_CALLBACK;
+		o->help = xstrdup(skipspaces(help+1));
+		o->value = &parsed;
+		o->flags = PARSE_OPT_NOARG;
+		o->callback = &parseopt_dump;
+
+		/* name(s) */
+		s = strpbrk(sb.buf, "*=?!");
+		if (!s)
+			s = help;
+
+		if (s == sb.buf)
+			die(_("missing opt-spec before option flags"));
+
+		if (s - sb.buf == 1) { /* short option only */
+			o->short_name = *sb.buf;
+		} else if (sb.buf[1] != ',') { /* long option only */
+			o->long_name = strvec_pushf(&longnames, "%.*s",
+						    (int)(s - sb.buf), sb.buf);
+		} else {
+			o->short_name = *sb.buf;
+			o->long_name = strvec_pushf(&longnames, "%.*s",
+						    (int)(s - sb.buf - 2), sb.buf + 2);
+		}
+
+		/* flags */
+		while (s < help) {
+			switch (*s++) {
+			case '=':
+				o->flags &= ~PARSE_OPT_NOARG;
+				continue;
+			case '?':
+				o->flags &= ~PARSE_OPT_NOARG;
+				o->flags |= PARSE_OPT_OPTARG;
+				continue;
+			case '!':
+				o->flags |= PARSE_OPT_NONEG;
+				continue;
+			case '*':
+				o->flags |= PARSE_OPT_HIDDEN;
+				continue;
+			}
+			s--;
+			break;
+		}
+
+		if (s < help)
+			o->argh = xmemdupz(s, help - s);
+	}
+	strbuf_release(&sb);
+
+	/* put an OPT_END() */
+	ALLOC_GROW(opts, opts_nr + 1, opts_alloc);
+	memset(opts + opts_nr, 0, sizeof(*opts));
+	argc = parse_options(argc, argv, prefix, opts, usage.v,
+			(keep_dashdash ? PARSE_OPT_KEEP_DASHDASH : 0) |
+			(stop_at_non_option ? PARSE_OPT_STOP_AT_NON_OPTION : 0) |
+			PARSE_OPT_SHELL_EVAL);
+
+	strbuf_addstr(&parsed, " --");
+	sq_quote_argv(&parsed, argv);
+	puts(parsed.buf);
+
+	strbuf_release(&parsed);
+	strbuf_release(&sb);
+	strvec_clear(&longnames);
+	strvec_clear(&usage);
+	for (size_t i = 0; i < opts_nr; i++) {
+		free((char *) opts[i].help);
+		free((char *) opts[i].argh);
+	}
+	free(opts);
+	return 0;
+}
+
+static int cmd_sq_quote(int argc, const char **argv)
+{
+	struct strbuf buf = STRBUF_INIT;
+
+	if (argc)
+		sq_quote_argv(&buf, argv);
+	printf("%s\n", buf.buf);
+	strbuf_release(&buf);
+
+	return 0;
+}
+
+static void die_no_single_rev(int quiet)
+{
+	if (quiet)
+		exit(1);
+	else
+		die(_("Needed a single revision"));
+}
+
+static const char builtin_rev_parse_usage[] =
+N_("git rev-parse --parseopt [<options>] -- [<args>...]\n"
+   "   or: git rev-parse --sq-quote [<arg>...]\n"
+   "   or: git rev-parse [<options>] [<arg>...]\n"
+   "\n"
+   "Run \"git rev-parse --parseopt -h\" for more information on the first usage.");
+
+/*
+ * Parse "opt" or "opt=<value>", setting value respectively to either
+ * NULL or the string after "=".
+ */
+static int opt_with_value(const char *arg, const char *opt, const char **value)
+{
+	if (skip_prefix(arg, opt, &arg)) {
+		if (!*arg) {
+			*value = NULL;
+			return 1;
+		}
+		if (*arg++ == '=') {
+			*value = arg;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static void handle_ref_opt(const char *pattern, const char *prefix)
+{
+	if (pattern)
+		refs_for_each_glob_ref_in(get_main_ref_store(the_repository),
+					  show_reference, pattern, prefix,
+					  NULL);
+	else
+		refs_for_each_ref_in(get_main_ref_store(the_repository),
+				     prefix, show_reference, NULL);
+	clear_ref_exclusions(&ref_excludes);
+}
+
+enum format_type {
+	/* We would like a relative path. */
+	FORMAT_RELATIVE,
+	/* We would like a canonical absolute path. */
+	FORMAT_CANONICAL,
+	/* We would like the default behavior. */
+	FORMAT_DEFAULT,
+};
+
+enum default_type {
+	/* Our default is a relative path. */
+	DEFAULT_RELATIVE,
+	/* Our default is a relative path if there's a shared root. */
+	DEFAULT_RELATIVE_IF_SHARED,
+	/* Our default is a canonical absolute path. */
+	DEFAULT_CANONICAL,
+	/* Our default is not to modify the item. */
+	DEFAULT_UNMODIFIED,
+};
+
+static void print_path(const char *path, const char *prefix, enum format_type format, enum default_type def)
+{
+	char *cwd = NULL;
+	/*
+	 * We don't ever produce a relative path if prefix is NULL, so set the
+	 * prefix to the current directory so that we can produce a relative
+	 * path whenever possible.  If we're using RELATIVE_IF_SHARED mode, then
+	 * we want an absolute path unless the two share a common prefix, so don't
+	 * set it in that case, since doing so causes a relative path to always
+	 * be produced if possible.
+	 */
+	if (!prefix && (format != FORMAT_DEFAULT || def != DEFAULT_RELATIVE_IF_SHARED))
+		prefix = cwd = xgetcwd();
+	if (format == FORMAT_DEFAULT && def == DEFAULT_UNMODIFIED) {
+		puts(path);
+	} else if (format == FORMAT_RELATIVE ||
+		  (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE)) {
+		/*
+		 * In order for relative_path to work as expected, we need to
+		 * make sure that both paths are absolute paths.  If we don't,
+		 * we can end up with an unexpected absolute path that the user
+		 * didn't want.
+		 */
+		struct strbuf buf = STRBUF_INIT, realbuf = STRBUF_INIT, prefixbuf = STRBUF_INIT;
+		if (!is_absolute_path(path)) {
+			strbuf_realpath_forgiving(&realbuf, path,  1);
+			path = realbuf.buf;
+		}
+		if (!is_absolute_path(prefix)) {
+			strbuf_realpath_forgiving(&prefixbuf, prefix, 1);
+			prefix = prefixbuf.buf;
+		}
+		puts(relative_path(path, prefix, &buf));
+		strbuf_release(&buf);
+		strbuf_release(&realbuf);
+		strbuf_release(&prefixbuf);
+	} else if (format == FORMAT_DEFAULT && def == DEFAULT_RELATIVE_IF_SHARED) {
+		struct strbuf buf = STRBUF_INIT;
+		puts(relative_path(path, prefix, &buf));
+		strbuf_release(&buf);
+	} else {
+		struct strbuf buf = STRBUF_INIT;
+		strbuf_realpath_forgiving(&buf, path, 1);
+		puts(buf.buf);
+		strbuf_release(&buf);
+	}
+	free(cwd);
+}
+
+int cmd_rev_parse(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	int i, as_is = 0, verify = 0, quiet = 0, revs_count = 0, type = 0;
+	const struct git_hash_algo *output_algo = NULL;
+	const struct git_hash_algo *compat = NULL;
+	int did_repo_setup = 0;
+	int has_dashdash = 0;
+	int output_prefix = 0;
+	struct object_id oid;
+	unsigned int flags = 0;
+	const char *name = NULL;
+	struct object_context unused;
+	struct strbuf buf = STRBUF_INIT;
+	int seen_end_of_options = 0;
+	enum format_type format = FORMAT_DEFAULT;
+
+	show_usage_if_asked(argc, argv, builtin_rev_parse_usage);
+
+	if (argc > 1 && !strcmp("--parseopt", argv[1]))
+		return cmd_parseopt(argc - 1, argv + 1, prefix);
+
+	if (argc > 1 && !strcmp("--sq-quote", argv[1]))
+		return cmd_sq_quote(argc - 2, argv + 2);
+
+	if (argc > 1 && !strcmp("-h", argv[1]))
+		usage(builtin_rev_parse_usage);
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "--")) {
+			has_dashdash = 1;
+			break;
+		}
+	}
+
+	/* No options; just report on whether we're in a git repo or not. */
+	if (argc == 1) {
+		setup_git_directory();
+		git_config(git_default_config, NULL);
+		return 0;
+	}
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (as_is) {
+			if (show_file(arg, output_prefix) && as_is < 2)
+				verify_filename(prefix, arg, 0);
+			continue;
+		}
+
+		if (!seen_end_of_options) {
+			if (!strcmp(arg, "--local-env-vars")) {
+				int i;
+				for (i = 0; local_repo_env[i]; i++)
+					printf("%s\n", local_repo_env[i]);
+				continue;
+			}
+			if (!strcmp(arg, "--resolve-git-dir")) {
+				const char *gitdir = argv[++i];
+				if (!gitdir)
+					die(_("--resolve-git-dir requires an argument"));
+				gitdir = resolve_gitdir(gitdir);
+				if (!gitdir)
+					die(_("not a gitdir '%s'"), argv[i]);
+				puts(gitdir);
+				continue;
+			}
+		}
+
+		/* The rest of the options require a git repository. */
+		if (!did_repo_setup) {
+			prefix = setup_git_directory();
+			git_config(git_default_config, NULL);
+			did_repo_setup = 1;
+
+			prepare_repo_settings(the_repository);
+			the_repository->settings.command_requires_full_index = 0;
+			compat = the_repository->compat_hash_algo;
+		}
+
+		if (!strcmp(arg, "--")) {
+			as_is = 2;
+			/* Pass on the "--" if we show anything but files.. */
+			if (filter & (DO_FLAGS | DO_REVS))
+				show_file(arg, 0);
+			continue;
+		}
+
+		if (!seen_end_of_options && *arg == '-') {
+			if (!strcmp(arg, "--git-path")) {
+				if (!argv[i + 1])
+					die(_("--git-path requires an argument"));
+				strbuf_reset(&buf);
+				print_path(git_path("%s", argv[i + 1]), prefix,
+						format,
+						DEFAULT_RELATIVE_IF_SHARED);
+				i++;
+				continue;
+			}
+			if (!strcmp(arg,"-n")) {
+				if (++i >= argc)
+					die(_("-n requires an argument"));
+				if ((filter & DO_FLAGS) && (filter & DO_REVS)) {
+					show(arg);
+					show(argv[i]);
+				}
+				continue;
+			}
+			if (starts_with(arg, "-n")) {
+				if ((filter & DO_FLAGS) && (filter & DO_REVS))
+					show(arg);
+				continue;
+			}
+			if (opt_with_value(arg, "--path-format", &arg)) {
+				if (!arg)
+					die(_("--path-format requires an argument"));
+				if (!strcmp(arg, "absolute")) {
+					format = FORMAT_CANONICAL;
+				} else if (!strcmp(arg, "relative")) {
+					format = FORMAT_RELATIVE;
+				} else {
+					die(_("unknown argument to --path-format: %s"), arg);
+				}
+				continue;
+			}
+			if (!strcmp(arg, "--default")) {
+				def = argv[++i];
+				if (!def)
+					die(_("--default requires an argument"));
+				continue;
+			}
+			if (!strcmp(arg, "--prefix")) {
+				prefix = argv[++i];
+				if (!prefix)
+					die(_("--prefix requires an argument"));
+				startup_info->prefix = prefix;
+				output_prefix = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--revs-only")) {
+				filter &= ~DO_NOREV;
+				continue;
+			}
+			if (!strcmp(arg, "--no-revs")) {
+				filter &= ~DO_REVS;
+				continue;
+			}
+			if (!strcmp(arg, "--flags")) {
+				filter &= ~DO_NONFLAGS;
+				continue;
+			}
+			if (!strcmp(arg, "--no-flags")) {
+				filter &= ~DO_FLAGS;
+				continue;
+			}
+			if (!strcmp(arg, "--verify")) {
+				filter &= ~(DO_FLAGS|DO_NOREV);
+				verify = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--quiet") || !strcmp(arg, "-q")) {
+				quiet = 1;
+				flags |= GET_OID_QUIETLY;
+				continue;
+			}
+			if (opt_with_value(arg, "--output-object-format", &arg)) {
+				if (!arg)
+					die(_("no object format specified"));
+				if (!strcmp(arg, the_hash_algo->name) ||
+				    !strcmp(arg, "storage")) {
+					flags |= GET_OID_HASH_ANY;
+					output_algo = the_hash_algo;
+					continue;
+				}
+				else if (compat && !strcmp(arg, compat->name)) {
+					flags |= GET_OID_HASH_ANY;
+					output_algo = compat;
+					continue;
+				}
+				else die(_("unsupported object format: %s"), arg);
+			}
+			if (opt_with_value(arg, "--short", &arg)) {
+				filter &= ~(DO_FLAGS|DO_NOREV);
+				verify = 1;
+				abbrev = DEFAULT_ABBREV;
+				if (!arg)
+					continue;
+				abbrev = strtoul(arg, NULL, 10);
+				if (abbrev < MINIMUM_ABBREV)
+					abbrev = MINIMUM_ABBREV;
+				else if ((int)the_hash_algo->hexsz <= abbrev)
+					abbrev = the_hash_algo->hexsz;
+				continue;
+			}
+			if (!strcmp(arg, "--sq")) {
+				output_sq = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--not")) {
+				show_type ^= REVERSED;
+				continue;
+			}
+			if (!strcmp(arg, "--symbolic")) {
+				symbolic = SHOW_SYMBOLIC_ASIS;
+				continue;
+			}
+			if (!strcmp(arg, "--symbolic-full-name")) {
+				symbolic = SHOW_SYMBOLIC_FULL;
+				continue;
+			}
+			if (opt_with_value(arg, "--abbrev-ref", &arg)) {
+				abbrev_ref = 1;
+				abbrev_ref_strict =
+					repo_settings_get_warn_ambiguous_refs(the_repository);
+				if (arg) {
+					if (!strcmp(arg, "strict"))
+						abbrev_ref_strict = 1;
+					else if (!strcmp(arg, "loose"))
+						abbrev_ref_strict = 0;
+					else
+						die(_("unknown mode for --abbrev-ref: %s"),
+						    arg);
+				}
+				continue;
+			}
+			if (!strcmp(arg, "--all")) {
+				refs_for_each_ref(get_main_ref_store(the_repository),
+						  show_reference, NULL);
+				clear_ref_exclusions(&ref_excludes);
+				continue;
+			}
+			if (skip_prefix(arg, "--disambiguate=", &arg)) {
+				repo_for_each_abbrev(the_repository, arg, the_hash_algo,
+						     show_abbrev, NULL);
+				continue;
+			}
+			if (!strcmp(arg, "--bisect")) {
+				refs_for_each_fullref_in(get_main_ref_store(the_repository),
+							 "refs/bisect/bad",
+							 NULL, show_reference,
+							 NULL);
+				refs_for_each_fullref_in(get_main_ref_store(the_repository),
+							 "refs/bisect/good",
+							 NULL, anti_reference,
+							 NULL);
+				continue;
+			}
+			if (opt_with_value(arg, "--branches", &arg)) {
+				if (ref_excludes.hidden_refs_configured)
+					return error(_("options '%s' and '%s' cannot be used together"),
+						     "--exclude-hidden", "--branches");
+				handle_ref_opt(arg, "refs/heads/");
+				continue;
+			}
+			if (opt_with_value(arg, "--tags", &arg)) {
+				if (ref_excludes.hidden_refs_configured)
+					return error(_("options '%s' and '%s' cannot be used together"),
+						     "--exclude-hidden", "--tags");
+				handle_ref_opt(arg, "refs/tags/");
+				continue;
+			}
+			if (skip_prefix(arg, "--glob=", &arg)) {
+				handle_ref_opt(arg, NULL);
+				continue;
+			}
+			if (opt_with_value(arg, "--remotes", &arg)) {
+				if (ref_excludes.hidden_refs_configured)
+					return error(_("options '%s' and '%s' cannot be used together"),
+						     "--exclude-hidden", "--remotes");
+				handle_ref_opt(arg, "refs/remotes/");
+				continue;
+			}
+			if (skip_prefix(arg, "--exclude=", &arg)) {
+				add_ref_exclusion(&ref_excludes, arg);
+				continue;
+			}
+			if (skip_prefix(arg, "--exclude-hidden=", &arg)) {
+				exclude_hidden_refs(&ref_excludes, arg);
+				continue;
+			}
+			if (!strcmp(arg, "--show-toplevel")) {
+				const char *work_tree = repo_get_work_tree(the_repository);
+				if (work_tree)
+					print_path(work_tree, prefix, format, DEFAULT_UNMODIFIED);
+				else
+					die(_("this operation must be run in a work tree"));
+				continue;
+			}
+			if (!strcmp(arg, "--show-superproject-working-tree")) {
+				struct strbuf superproject = STRBUF_INIT;
+				if (get_superproject_working_tree(&superproject))
+					print_path(superproject.buf, prefix, format, DEFAULT_UNMODIFIED);
+				strbuf_release(&superproject);
+				continue;
+			}
+			if (!strcmp(arg, "--show-prefix")) {
+				if (prefix)
+					puts(prefix);
+				else
+					putchar('\n');
+				continue;
+			}
+			if (!strcmp(arg, "--show-cdup")) {
+				const char *pfx = prefix;
+				if (!is_inside_work_tree()) {
+					const char *work_tree =
+						repo_get_work_tree(the_repository);
+					if (work_tree)
+						printf("%s\n", work_tree);
+					continue;
+				}
+				while (pfx) {
+					pfx = strchr(pfx, '/');
+					if (pfx) {
+						pfx++;
+						printf("../");
+					}
+				}
+				putchar('\n');
+				continue;
+			}
+			if (!strcmp(arg, "--git-dir") ||
+			    !strcmp(arg, "--absolute-git-dir")) {
+				const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
+				char *cwd;
+				int len;
+				enum format_type wanted = format;
+				if (arg[2] == 'g') {	/* --git-dir */
+					if (gitdir) {
+						print_path(gitdir, prefix, format, DEFAULT_UNMODIFIED);
+						continue;
+					}
+					if (!prefix) {
+						print_path(".git", prefix, format, DEFAULT_UNMODIFIED);
+						continue;
+					}
+				} else {		/* --absolute-git-dir */
+					wanted = FORMAT_CANONICAL;
+					if (!gitdir && !prefix)
+						gitdir = ".git";
+					if (gitdir) {
+						struct strbuf realpath = STRBUF_INIT;
+						strbuf_realpath(&realpath, gitdir, 1);
+						puts(realpath.buf);
+						strbuf_release(&realpath);
+						continue;
+					}
+				}
+				cwd = xgetcwd();
+				len = strlen(cwd);
+				strbuf_reset(&buf);
+				strbuf_addf(&buf, "%s%s.git", cwd, len && cwd[len-1] != '/' ? "/" : "");
+				free(cwd);
+				print_path(buf.buf, prefix, wanted, DEFAULT_CANONICAL);
+				continue;
+			}
+			if (!strcmp(arg, "--git-common-dir")) {
+				print_path(repo_get_common_dir(the_repository), prefix, format, DEFAULT_RELATIVE_IF_SHARED);
+				continue;
+			}
+			if (!strcmp(arg, "--is-inside-git-dir")) {
+				printf("%s\n", is_inside_git_dir() ? "true"
+						: "false");
+				continue;
+			}
+			if (!strcmp(arg, "--is-inside-work-tree")) {
+				printf("%s\n", is_inside_work_tree() ? "true"
+						: "false");
+				continue;
+			}
+			if (!strcmp(arg, "--is-bare-repository")) {
+				printf("%s\n", is_bare_repository() ? "true"
+						: "false");
+				continue;
+			}
+			if (!strcmp(arg, "--is-shallow-repository")) {
+				printf("%s\n",
+						is_repository_shallow(the_repository) ? "true"
+						: "false");
+				continue;
+			}
+			if (!strcmp(arg, "--shared-index-path")) {
+				if (repo_read_index(the_repository) < 0)
+					die(_("Could not read the index"));
+				if (the_repository->index->split_index) {
+					const struct object_id *oid = &the_repository->index->split_index->base_oid;
+					const char *path = git_path("sharedindex.%s", oid_to_hex(oid));
+					print_path(path, prefix, format, DEFAULT_RELATIVE);
+				}
+				continue;
+			}
+			if (skip_prefix(arg, "--since=", &arg)) {
+				show_datestring("--max-age=", arg);
+				continue;
+			}
+			if (skip_prefix(arg, "--after=", &arg)) {
+				show_datestring("--max-age=", arg);
+				continue;
+			}
+			if (skip_prefix(arg, "--before=", &arg)) {
+				show_datestring("--min-age=", arg);
+				continue;
+			}
+			if (skip_prefix(arg, "--until=", &arg)) {
+				show_datestring("--min-age=", arg);
+				continue;
+			}
+			if (opt_with_value(arg, "--show-object-format", &arg)) {
+				const char *val = arg ? arg : "storage";
+
+				if (strcmp(val, "storage") &&
+				    strcmp(val, "input") &&
+				    strcmp(val, "output"))
+					die(_("unknown mode for --show-object-format: %s"),
+					    arg);
+				puts(the_hash_algo->name);
+				continue;
+			}
+			if (!strcmp(arg, "--show-ref-format")) {
+				puts(ref_storage_format_to_name(the_repository->ref_storage_format));
+				continue;
+			}
+			if (!strcmp(arg, "--end-of-options")) {
+				seen_end_of_options = 1;
+				if (filter & (DO_FLAGS | DO_REVS))
+					show_file(arg, 0);
+				continue;
+			}
+			if (show_flag(arg) && verify)
+				die_no_single_rev(quiet);
+			continue;
+		}
+
+		/* Not a flag argument */
+		if (try_difference(arg))
+			continue;
+		if (try_parent_shorthands(arg))
+			continue;
+		name = arg;
+		type = NORMAL;
+		if (*arg == '^') {
+			name++;
+			type = REVERSED;
+		}
+		if (!get_oid_with_context(the_repository, name,
+					  flags, &oid, &unused)) {
+			object_context_release(&unused);
+			if (output_algo)
+				repo_oid_to_algop(the_repository, &oid,
+						  output_algo, &oid);
+			if (verify)
+				revs_count++;
+			else
+				show_rev(type, &oid, name);
+			continue;
+		}
+		object_context_release(&unused);
+		if (verify)
+			die_no_single_rev(quiet);
+		if (has_dashdash)
+			die(_("bad revision '%s'"), arg);
+		as_is = 1;
+		if (!show_file(arg, output_prefix))
+			continue;
+		verify_filename(prefix, arg, 1);
+	}
+	strbuf_release(&buf);
+	if (verify) {
+		if (revs_count == 1) {
+			show_rev(type, &oid, name);
+			return 0;
+		} else if (revs_count == 0 && show_default())
+			return 0;
+		die_no_single_rev(quiet);
+	} else
+		show_default();
+	return 0;
+}
diff --git a/builtin/revert.c b/builtin/revert.c
new file mode 100644
index 0000000000..aca6c293cd
--- /dev/null
+++ b/builtin/revert.c
@@ -0,0 +1,306 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "builtin.h"
+#include "parse-options.h"
+#include "diff.h"
+#include "gettext.h"
+#include "revision.h"
+#include "rerere.h"
+#include "sequencer.h"
+#include "branch.h"
+
+/*
+ * This implements the builtins revert and cherry-pick.
+ *
+ * Copyright (c) 2007 Johannes E. Schindelin
+ *
+ * Based on git-revert.sh, which is
+ *
+ * Copyright (c) 2005 Linus Torvalds
+ * Copyright (c) 2005 Junio C Hamano
+ */
+
+static const char * const revert_usage[] = {
+	N_("git revert [--[no-]edit] [-n] [-m <parent-number>] [-s] [-S[<keyid>]] <commit>..."),
+	N_("git revert (--continue | --skip | --abort | --quit)"),
+	NULL
+};
+
+static const char * const cherry_pick_usage[] = {
+	N_("git cherry-pick [--edit] [-n] [-m <parent-number>] [-s] [-x] [--ff]\n"
+	   "                [-S[<keyid>]] <commit>..."),
+	N_("git cherry-pick (--continue | --skip | --abort | --quit)"),
+	NULL
+};
+
+static const char *action_name(const struct replay_opts *opts)
+{
+	return opts->action == REPLAY_REVERT ? "revert" : "cherry-pick";
+}
+
+static const char * const *revert_or_cherry_pick_usage(struct replay_opts *opts)
+{
+	return opts->action == REPLAY_REVERT ? revert_usage : cherry_pick_usage;
+}
+
+enum empty_action {
+	EMPTY_COMMIT_UNSPECIFIED = -1,
+	STOP_ON_EMPTY_COMMIT,      /* output errors and stop in the middle of a cherry-pick */
+	DROP_EMPTY_COMMIT,         /* skip with a notice message */
+	KEEP_EMPTY_COMMIT,         /* keep recording as empty commits */
+};
+
+static int parse_opt_empty(const struct option *opt, const char *arg, int unset)
+{
+	int *opt_value = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (!strcmp(arg, "stop"))
+		*opt_value = STOP_ON_EMPTY_COMMIT;
+	else if (!strcmp(arg, "drop"))
+		*opt_value = DROP_EMPTY_COMMIT;
+	else if (!strcmp(arg, "keep"))
+		*opt_value = KEEP_EMPTY_COMMIT;
+	else
+		return error(_("invalid value for '%s': '%s'"), "--empty", arg);
+
+	return 0;
+}
+
+static int option_parse_m(const struct option *opt,
+			  const char *arg, int unset)
+{
+	struct replay_opts *replay = opt->value;
+	char *end;
+
+	if (unset) {
+		replay->mainline = 0;
+		return 0;
+	}
+
+	replay->mainline = strtol(arg, &end, 10);
+	if (*end || replay->mainline <= 0)
+		return error(_("option `%s' expects a number greater than zero"),
+			     opt->long_name);
+
+	return 0;
+}
+
+LAST_ARG_MUST_BE_NULL
+static void verify_opt_compatible(const char *me, const char *base_opt, ...)
+{
+	const char *this_opt;
+	va_list ap;
+
+	va_start(ap, base_opt);
+	while ((this_opt = va_arg(ap, const char *))) {
+		if (va_arg(ap, int))
+			break;
+	}
+	va_end(ap);
+
+	if (this_opt)
+		die(_("%s: %s cannot be used with %s"), me, this_opt, base_opt);
+}
+
+static int run_sequencer(int argc, const char **argv, const char *prefix,
+			 struct replay_opts *opts)
+{
+	const char * const * usage_str = revert_or_cherry_pick_usage(opts);
+	const char *me = action_name(opts);
+	const char *cleanup_arg = NULL;
+	const char sentinel_value;
+	const char *strategy = &sentinel_value;
+	const char *gpg_sign = &sentinel_value;
+	enum empty_action empty_opt = EMPTY_COMMIT_UNSPECIFIED;
+	int cmd = 0;
+	struct option base_options[] = {
+		OPT_CMDMODE(0, "quit", &cmd, N_("end revert or cherry-pick sequence"), 'q'),
+		OPT_CMDMODE(0, "continue", &cmd, N_("resume revert or cherry-pick sequence"), 'c'),
+		OPT_CMDMODE(0, "abort", &cmd, N_("cancel revert or cherry-pick sequence"), 'a'),
+		OPT_CMDMODE(0, "skip", &cmd, N_("skip current commit and continue"), 's'),
+		OPT_CLEANUP(&cleanup_arg),
+		OPT_BOOL('n', "no-commit", &opts->no_commit, N_("don't automatically commit")),
+		OPT_BOOL('e', "edit", &opts->edit, N_("edit the commit message")),
+		OPT_NOOP_NOARG('r', NULL),
+		OPT_BOOL('s', "signoff", &opts->signoff, N_("add a Signed-off-by trailer")),
+		OPT_CALLBACK('m', "mainline", opts, N_("parent-number"),
+			     N_("select mainline parent"), option_parse_m),
+		OPT_RERERE_AUTOUPDATE(&opts->allow_rerere_auto),
+		OPT_STRING(0, "strategy", &strategy, N_("strategy"), N_("merge strategy")),
+		OPT_STRVEC('X', "strategy-option", &opts->xopts, N_("option"),
+			N_("option for merge strategy")),
+		{ OPTION_STRING, 'S', "gpg-sign", &gpg_sign, N_("key-id"),
+		  N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
+		OPT_END()
+	};
+	struct option *options = base_options;
+
+	if (opts->action == REPLAY_PICK) {
+		struct option cp_extra[] = {
+			OPT_BOOL('x', NULL, &opts->record_origin, N_("append commit name")),
+			OPT_BOOL(0, "ff", &opts->allow_ff, N_("allow fast-forward")),
+			OPT_BOOL(0, "allow-empty", &opts->allow_empty, N_("preserve initially empty commits")),
+			OPT_BOOL(0, "allow-empty-message", &opts->allow_empty_message, N_("allow commits with empty messages")),
+			OPT_BOOL(0, "keep-redundant-commits", &opts->keep_redundant_commits, N_("deprecated: use --empty=keep instead")),
+			OPT_CALLBACK_F(0, "empty", &empty_opt, "(stop|drop|keep)",
+				       N_("how to handle commits that become empty"),
+				       PARSE_OPT_NONEG, parse_opt_empty),
+			OPT_END(),
+		};
+		options = parse_options_concat(options, cp_extra);
+	} else if (opts->action == REPLAY_REVERT) {
+		struct option cp_extra[] = {
+			OPT_BOOL(0, "reference", &opts->commit_use_reference,
+				 N_("use the 'reference' format to refer to commits")),
+			OPT_END(),
+		};
+		options = parse_options_concat(options, cp_extra);
+	}
+
+	argc = parse_options(argc, argv, prefix, options, usage_str,
+			PARSE_OPT_KEEP_ARGV0 |
+			PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	if (opts->action == REPLAY_PICK) {
+		opts->drop_redundant_commits = (empty_opt == DROP_EMPTY_COMMIT);
+		opts->keep_redundant_commits = opts->keep_redundant_commits || (empty_opt == KEEP_EMPTY_COMMIT);
+	}
+
+	/* implies allow_empty */
+	if (opts->keep_redundant_commits)
+		opts->allow_empty = 1;
+
+	if (cleanup_arg) {
+		opts->default_msg_cleanup = get_cleanup_mode(cleanup_arg, 1);
+		opts->explicit_cleanup = 1;
+	}
+
+	/* Check for incompatible command line arguments */
+	if (cmd) {
+		const char *this_operation;
+		if (cmd == 'q')
+			this_operation = "--quit";
+		else if (cmd == 'c')
+			this_operation = "--continue";
+		else if (cmd == 's')
+			this_operation = "--skip";
+		else {
+			assert(cmd == 'a');
+			this_operation = "--abort";
+		}
+
+		verify_opt_compatible(me, this_operation,
+				"--no-commit", opts->no_commit,
+				"--signoff", opts->signoff,
+				"--mainline", opts->mainline,
+				"--strategy", opts->strategy ? 1 : 0,
+				"--strategy-option", opts->xopts.nr ? 1 : 0,
+				"-x", opts->record_origin,
+				"--ff", opts->allow_ff,
+				"--rerere-autoupdate", opts->allow_rerere_auto == RERERE_AUTOUPDATE,
+				"--no-rerere-autoupdate", opts->allow_rerere_auto == RERERE_NOAUTOUPDATE,
+				"--keep-redundant-commits", opts->keep_redundant_commits,
+				"--empty", empty_opt != EMPTY_COMMIT_UNSPECIFIED,
+				NULL);
+	}
+
+	if (!opts->strategy && opts->default_strategy) {
+		opts->strategy = opts->default_strategy;
+		opts->default_strategy = NULL;
+	}
+
+	if (opts->allow_ff)
+		verify_opt_compatible(me, "--ff",
+				"--signoff", opts->signoff,
+				"--no-commit", opts->no_commit,
+				"-x", opts->record_origin,
+				"--edit", opts->edit > 0,
+				NULL);
+
+	if (cmd) {
+		opts->revs = NULL;
+	} else {
+		struct setup_revision_opt s_r_opt;
+		opts->revs = xmalloc(sizeof(*opts->revs));
+		repo_init_revisions(the_repository, opts->revs, NULL);
+		opts->revs->no_walk = 1;
+		opts->revs->unsorted_input = 1;
+		if (argc < 2)
+			usage_with_options(usage_str, options);
+		if (!strcmp(argv[1], "-"))
+			argv[1] = "@{-1}";
+		memset(&s_r_opt, 0, sizeof(s_r_opt));
+		s_r_opt.assume_dashdash = 1;
+		argc = setup_revisions(argc, argv, opts->revs, &s_r_opt);
+	}
+
+	if (argc > 1)
+		usage_with_options(usage_str, options);
+
+	/* These option values will be free()d */
+	if (gpg_sign != &sentinel_value) {
+		free(opts->gpg_sign);
+		opts->gpg_sign = xstrdup_or_null(gpg_sign);
+	}
+	if (strategy != &sentinel_value) {
+		free(opts->strategy);
+		opts->strategy = xstrdup_or_null(strategy);
+	}
+	if (!opts->strategy && getenv("GIT_TEST_MERGE_ALGORITHM"))
+		opts->strategy = xstrdup(getenv("GIT_TEST_MERGE_ALGORITHM"));
+	free(options);
+
+	if (cmd == 'q') {
+		int ret = sequencer_remove_state(opts);
+		if (!ret)
+			remove_branch_state(the_repository, 0);
+		return ret;
+	}
+	if (cmd == 'c')
+		return sequencer_continue(the_repository, opts);
+	if (cmd == 'a')
+		return sequencer_rollback(the_repository, opts);
+	if (cmd == 's')
+		return sequencer_skip(the_repository, opts);
+	return sequencer_pick_revisions(the_repository, opts);
+}
+
+int cmd_revert(int argc,
+	       const char **argv,
+	       const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct replay_opts opts = REPLAY_OPTS_INIT;
+	int res;
+
+	opts.action = REPLAY_REVERT;
+	sequencer_init_config(&opts);
+	res = run_sequencer(argc, argv, prefix, &opts);
+	if (res < 0)
+		die(_("revert failed"));
+	replay_opts_release(&opts);
+	return res;
+}
+
+int cmd_cherry_pick(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
+{
+	struct replay_opts opts = REPLAY_OPTS_INIT;
+	int res;
+
+	opts.action = REPLAY_PICK;
+	sequencer_init_config(&opts);
+	res = run_sequencer(argc, argv, prefix, &opts);
+	if (res < 0)
+		die(_("cherry-pick failed"));
+	replay_opts_release(&opts);
+	return res;
+}
diff --git a/builtin/rm.c b/builtin/rm.c
new file mode 100644
index 0000000000..12ae086a55
--- /dev/null
+++ b/builtin/rm.c
@@ -0,0 +1,449 @@
+/*
+ * "git rm" builtin command
+ *
+ * Copyright (C) Linus Torvalds 2006
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "lockfile.h"
+#include "dir.h"
+#include "gettext.h"
+#include "hash.h"
+#include "tree-walk.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "read-cache.h"
+
+#include "string-list.h"
+#include "setup.h"
+#include "sparse-index.h"
+#include "submodule.h"
+#include "pathspec.h"
+
+static const char * const builtin_rm_usage[] = {
+	N_("git rm [-f | --force] [-n] [-r] [--cached] [--ignore-unmatch]\n"
+	   "       [--quiet] [--pathspec-from-file=<file> [--pathspec-file-nul]]\n"
+	   "       [--] [<pathspec>...]"),
+	NULL
+};
+
+static struct {
+	int nr, alloc;
+	struct {
+		const char *name;
+		char is_submodule;
+	} *entry;
+} list;
+
+static int get_ours_cache_pos(const char *path, int pos)
+{
+	int i = -pos - 1;
+
+	while ((i < the_repository->index->cache_nr) && !strcmp(the_repository->index->cache[i]->name, path)) {
+		if (ce_stage(the_repository->index->cache[i]) == 2)
+			return i;
+		i++;
+	}
+	return -1;
+}
+
+static void print_error_files(struct string_list *files_list,
+			      const char *main_msg,
+			      const char *hints_msg,
+			      int *errs)
+{
+	if (files_list->nr) {
+		int i;
+		struct strbuf err_msg = STRBUF_INIT;
+
+		strbuf_addstr(&err_msg, main_msg);
+		for (i = 0; i < files_list->nr; i++)
+			strbuf_addf(&err_msg,
+				    "\n    %s",
+				    files_list->items[i].string);
+		if (advice_enabled(ADVICE_RM_HINTS))
+			strbuf_addstr(&err_msg, hints_msg);
+		*errs = error("%s", err_msg.buf);
+		strbuf_release(&err_msg);
+	}
+}
+
+static void submodules_absorb_gitdir_if_needed(void)
+{
+	int i;
+	for (i = 0; i < list.nr; i++) {
+		const char *name = list.entry[i].name;
+		int pos;
+		const struct cache_entry *ce;
+
+		pos = index_name_pos(the_repository->index, name, strlen(name));
+		if (pos < 0) {
+			pos = get_ours_cache_pos(name, pos);
+			if (pos < 0)
+				continue;
+		}
+		ce = the_repository->index->cache[pos];
+
+		if (!S_ISGITLINK(ce->ce_mode) ||
+		    !file_exists(ce->name) ||
+		    is_empty_dir(name))
+			continue;
+
+		if (!submodule_uses_gitfile(name))
+			absorb_git_dir_into_superproject(name, NULL);
+	}
+}
+
+static int check_local_mod(struct object_id *head, int index_only)
+{
+	/*
+	 * Items in list are already sorted in the cache order,
+	 * so we could do this a lot more efficiently by using
+	 * tree_desc based traversal if we wanted to, but I am
+	 * lazy, and who cares if removal of files is a tad
+	 * slower than the theoretical maximum speed?
+	 */
+	int i, no_head;
+	int errs = 0;
+	struct string_list files_staged = STRING_LIST_INIT_NODUP;
+	struct string_list files_cached = STRING_LIST_INIT_NODUP;
+	struct string_list files_local = STRING_LIST_INIT_NODUP;
+
+	no_head = is_null_oid(head);
+	for (i = 0; i < list.nr; i++) {
+		struct stat st;
+		int pos;
+		const struct cache_entry *ce;
+		const char *name = list.entry[i].name;
+		struct object_id oid;
+		unsigned short mode;
+		int local_changes = 0;
+		int staged_changes = 0;
+
+		pos = index_name_pos(the_repository->index, name, strlen(name));
+		if (pos < 0) {
+			/*
+			 * Skip unmerged entries except for populated submodules
+			 * that could lose history when removed.
+			 */
+			pos = get_ours_cache_pos(name, pos);
+			if (pos < 0)
+				continue;
+
+			if (!S_ISGITLINK(the_repository->index->cache[pos]->ce_mode) ||
+			    is_empty_dir(name))
+				continue;
+		}
+		ce = the_repository->index->cache[pos];
+
+		if (lstat(ce->name, &st) < 0) {
+			if (!is_missing_file_error(errno))
+				warning_errno(_("failed to stat '%s'"), ce->name);
+			/* It already vanished from the working tree */
+			continue;
+		}
+		else if (S_ISDIR(st.st_mode)) {
+			/* if a file was removed and it is now a
+			 * directory, that is the same as ENOENT as
+			 * far as git is concerned; we do not track
+			 * directories unless they are submodules.
+			 */
+			if (!S_ISGITLINK(ce->ce_mode))
+				continue;
+		}
+
+		/*
+		 * "rm" of a path that has changes need to be treated
+		 * carefully not to allow losing local changes
+		 * accidentally.  A local change could be (1) file in
+		 * work tree is different since the index; and/or (2)
+		 * the user staged a content that is different from
+		 * the current commit in the index.
+		 *
+		 * In such a case, you would need to --force the
+		 * removal.  However, "rm --cached" (remove only from
+		 * the index) is safe if the index matches the file in
+		 * the work tree or the HEAD commit, as it means that
+		 * the content being removed is available elsewhere.
+		 */
+
+		/*
+		 * Is the index different from the file in the work tree?
+		 * If it's a submodule, is its work tree modified?
+		 */
+		if (ie_match_stat(the_repository->index, ce, &st, 0) ||
+		    (S_ISGITLINK(ce->ce_mode) &&
+		     bad_to_remove_submodule(ce->name,
+				SUBMODULE_REMOVAL_DIE_ON_ERROR |
+				SUBMODULE_REMOVAL_IGNORE_IGNORED_UNTRACKED)))
+			local_changes = 1;
+
+		/*
+		 * Is the index different from the HEAD commit?  By
+		 * definition, before the very initial commit,
+		 * anything staged in the index is treated by the same
+		 * way as changed from the HEAD.
+		 */
+		if (no_head
+		     || get_tree_entry(the_repository, head, name, &oid, &mode)
+		     || ce->ce_mode != create_ce_mode(mode)
+		     || !oideq(&ce->oid, &oid))
+			staged_changes = 1;
+
+		/*
+		 * If the index does not match the file in the work
+		 * tree and if it does not match the HEAD commit
+		 * either, (1) "git rm" without --cached definitely
+		 * will lose information; (2) "git rm --cached" will
+		 * lose information unless it is about removing an
+		 * "intent to add" entry.
+		 */
+		if (local_changes && staged_changes) {
+			if (!index_only || !ce_intent_to_add(ce))
+				string_list_append(&files_staged, name);
+		}
+		else if (!index_only) {
+			if (staged_changes)
+				string_list_append(&files_cached, name);
+			if (local_changes)
+				string_list_append(&files_local, name);
+		}
+	}
+	print_error_files(&files_staged,
+			  Q_("the following file has staged content different "
+			     "from both the\nfile and the HEAD:",
+			     "the following files have staged content different"
+			     " from both the\nfile and the HEAD:",
+			     files_staged.nr),
+			  _("\n(use -f to force removal)"),
+			  &errs);
+	string_list_clear(&files_staged, 0);
+	print_error_files(&files_cached,
+			  Q_("the following file has changes "
+			     "staged in the index:",
+			     "the following files have changes "
+			     "staged in the index:", files_cached.nr),
+			  _("\n(use --cached to keep the file,"
+			    " or -f to force removal)"),
+			  &errs);
+	string_list_clear(&files_cached, 0);
+
+	print_error_files(&files_local,
+			  Q_("the following file has local modifications:",
+			     "the following files have local modifications:",
+			     files_local.nr),
+			  _("\n(use --cached to keep the file,"
+			    " or -f to force removal)"),
+			  &errs);
+	string_list_clear(&files_local, 0);
+
+	return errs;
+}
+
+static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
+static int ignore_unmatch = 0, pathspec_file_nul;
+static int include_sparse;
+static char *pathspec_from_file;
+
+static struct option builtin_rm_options[] = {
+	OPT__DRY_RUN(&show_only, N_("dry run")),
+	OPT__QUIET(&quiet, N_("do not list removed files")),
+	OPT_BOOL( 0 , "cached",         &index_only, N_("only remove from the index")),
+	OPT__FORCE(&force, N_("override the up-to-date check"), PARSE_OPT_NOCOMPLETE),
+	OPT_BOOL('r', NULL,             &recursive,  N_("allow recursive removal")),
+	OPT_BOOL( 0 , "ignore-unmatch", &ignore_unmatch,
+				N_("exit with a zero status even if nothing matched")),
+	OPT_BOOL(0, "sparse", &include_sparse, N_("allow updating entries outside of the sparse-checkout cone")),
+	OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+	OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
+	OPT_END(),
+};
+
+int cmd_rm(int argc,
+	   const char **argv,
+	   const char *prefix,
+	   struct repository *repo UNUSED)
+{
+	struct lock_file lock_file = LOCK_INIT;
+	int i, ret = 0;
+	struct pathspec pathspec;
+	char *seen;
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, builtin_rm_options,
+			     builtin_rm_usage, 0);
+
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_CWD,
+		       prefix, argv);
+
+	if (pathspec_from_file) {
+		if (pathspec.nr)
+			die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
+
+		parse_pathspec_file(&pathspec, 0,
+				    PATHSPEC_PREFER_CWD,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
+	}
+
+	if (!pathspec.nr)
+		die(_("No pathspec was given. Which files should I remove?"));
+
+	if (!index_only)
+		setup_work_tree();
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+
+	if (repo_read_index(the_repository) < 0)
+		die(_("index file corrupt"));
+
+	refresh_index(the_repository->index, REFRESH_QUIET|REFRESH_UNMERGED, &pathspec, NULL, NULL);
+
+	seen = xcalloc(pathspec.nr, 1);
+
+	if (pathspec_needs_expanded_index(the_repository->index, &pathspec))
+		ensure_full_index(the_repository->index);
+
+	for (i = 0; i < the_repository->index->cache_nr; i++) {
+		const struct cache_entry *ce = the_repository->index->cache[i];
+
+		if (!include_sparse &&
+		    (ce_skip_worktree(ce) ||
+		     !path_in_sparse_checkout(ce->name, the_repository->index)))
+			continue;
+		if (!ce_path_match(the_repository->index, ce, &pathspec, seen))
+			continue;
+		ALLOC_GROW(list.entry, list.nr + 1, list.alloc);
+		list.entry[list.nr].name = xstrdup(ce->name);
+		list.entry[list.nr].is_submodule = S_ISGITLINK(ce->ce_mode);
+		if (list.entry[list.nr++].is_submodule &&
+		    !is_staging_gitmodules_ok(the_repository->index))
+			die(_("please stage your changes to .gitmodules or stash them to proceed"));
+	}
+
+	if (pathspec.nr) {
+		const char *original;
+		int seen_any = 0;
+		char *skip_worktree_seen = NULL;
+		struct string_list only_match_skip_worktree = STRING_LIST_INIT_NODUP;
+
+		for (i = 0; i < pathspec.nr; i++) {
+			original = pathspec.items[i].original;
+			if (seen[i])
+				seen_any = 1;
+			else if (ignore_unmatch)
+				continue;
+			else if (!include_sparse &&
+				 matches_skip_worktree(&pathspec, i, &skip_worktree_seen))
+				string_list_append(&only_match_skip_worktree, original);
+			else
+				die(_("pathspec '%s' did not match any files"), original);
+
+			if (!recursive && seen[i] == MATCHED_RECURSIVELY)
+				die(_("not removing '%s' recursively without -r"),
+				    *original ? original : ".");
+		}
+
+		if (only_match_skip_worktree.nr) {
+			advise_on_updating_sparse_paths(&only_match_skip_worktree);
+			ret = 1;
+		}
+		free(skip_worktree_seen);
+		string_list_clear(&only_match_skip_worktree, 0);
+
+		if (!seen_any)
+			exit(ret);
+	}
+	clear_pathspec(&pathspec);
+	free(seen);
+
+	if (!index_only)
+		submodules_absorb_gitdir_if_needed();
+
+	/*
+	 * If not forced, the file, the index and the HEAD (if exists)
+	 * must match; but the file can already been removed, since
+	 * this sequence is a natural "novice" way:
+	 *
+	 *	rm F; git rm F
+	 *
+	 * Further, if HEAD commit exists, "diff-index --cached" must
+	 * report no changes unless forced.
+	 */
+	if (!force) {
+		struct object_id oid;
+		if (repo_get_oid(the_repository, "HEAD", &oid))
+			oidclr(&oid, the_repository->hash_algo);
+		if (check_local_mod(&oid, index_only))
+			exit(1);
+	}
+
+	/*
+	 * First remove the names from the index: we won't commit
+	 * the index unless all of them succeed.
+	 */
+	for (i = 0; i < list.nr; i++) {
+		const char *path = list.entry[i].name;
+		if (!quiet)
+			printf("rm '%s'\n", path);
+
+		if (remove_file_from_index(the_repository->index, path))
+			die(_("git rm: unable to remove %s"), path);
+	}
+
+	if (show_only)
+		return 0;
+
+	/*
+	 * Then, unless we used "--cached", remove the filenames from
+	 * the workspace. If we fail to remove the first one, we
+	 * abort the "git rm" (but once we've successfully removed
+	 * any file at all, we'll go ahead and commit to it all:
+	 * by then we've already committed ourselves and can't fail
+	 * in the middle)
+	 */
+	if (!index_only) {
+		int removed = 0, gitmodules_modified = 0;
+		struct strbuf buf = STRBUF_INIT;
+		int flag = force ? REMOVE_DIR_PURGE_ORIGINAL_CWD : 0;
+		for (i = 0; i < list.nr; i++) {
+			const char *path = list.entry[i].name;
+			if (list.entry[i].is_submodule) {
+				strbuf_reset(&buf);
+				strbuf_addstr(&buf, path);
+				if (remove_dir_recursively(&buf, flag))
+					die(_("could not remove '%s'"), path);
+
+				removed = 1;
+				if (!remove_path_from_gitmodules(path))
+					gitmodules_modified = 1;
+				continue;
+			}
+			if (!remove_path(path)) {
+				removed = 1;
+				continue;
+			}
+			if (!removed)
+				die_errno("git rm: '%s'", path);
+		}
+		strbuf_release(&buf);
+		if (gitmodules_modified)
+			stage_updated_gitmodules(the_repository->index);
+	}
+
+	if (write_locked_index(the_repository->index, &lock_file,
+			       COMMIT_LOCK | SKIP_IF_UNCHANGED))
+		die(_("Unable to write new index file"));
+
+	return ret;
+}
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
new file mode 100644
index 0000000000..8d461008e2
--- /dev/null
+++ b/builtin/send-pack.c
@@ -0,0 +1,350 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "hex.h"
+#include "pkt-line.h"
+#include "run-command.h"
+#include "remote.h"
+#include "connect.h"
+#include "send-pack.h"
+#include "quote.h"
+#include "transport.h"
+#include "oid-array.h"
+#include "gettext.h"
+#include "protocol.h"
+#include "parse-options.h"
+#include "write-or-die.h"
+
+static const char * const send_pack_usage[] = {
+	N_("git send-pack [--mirror] [--dry-run] [--force]\n"
+	   "              [--receive-pack=<git-receive-pack>]\n"
+	   "              [--verbose] [--thin] [--atomic]\n"
+	   "              [--[no-]signed | --signed=(true|false|if-asked)]\n"
+	   "              [<host>:]<directory> (--all | <ref>...)"),
+	NULL,
+};
+
+static struct send_pack_args args;
+
+static void print_helper_status(struct ref *ref)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct ref_push_report *report;
+
+	for (; ref; ref = ref->next) {
+		const char *msg = NULL;
+		const char *res;
+		int count = 0;
+
+		switch(ref->status) {
+		case REF_STATUS_NONE:
+			res = "error";
+			msg = "no match";
+			break;
+
+		case REF_STATUS_OK:
+			res = "ok";
+			break;
+
+		case REF_STATUS_UPTODATE:
+			res = "ok";
+			msg = "up to date";
+			break;
+
+		case REF_STATUS_REJECT_NONFASTFORWARD:
+			res = "error";
+			msg = "non-fast forward";
+			break;
+
+		case REF_STATUS_REJECT_FETCH_FIRST:
+			res = "error";
+			msg = "fetch first";
+			break;
+
+		case REF_STATUS_REJECT_NEEDS_FORCE:
+			res = "error";
+			msg = "needs force";
+			break;
+
+		case REF_STATUS_REJECT_STALE:
+			res = "error";
+			msg = "stale info";
+			break;
+
+		case REF_STATUS_REJECT_REMOTE_UPDATED:
+			res = "error";
+			msg = "remote ref updated since checkout";
+			break;
+
+		case REF_STATUS_REJECT_ALREADY_EXISTS:
+			res = "error";
+			msg = "already exists";
+			break;
+
+		case REF_STATUS_REJECT_NODELETE:
+		case REF_STATUS_REMOTE_REJECT:
+			res = "error";
+			break;
+
+		case REF_STATUS_EXPECTING_REPORT:
+			res = "error";
+			msg = "expecting report";
+			break;
+
+		default:
+			continue;
+		}
+
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "%s %s", res, ref->name);
+		if (ref->remote_status)
+			msg = ref->remote_status;
+		if (msg) {
+			strbuf_addch(&buf, ' ');
+			quote_two_c_style(&buf, "", msg, 0);
+		}
+		strbuf_addch(&buf, '\n');
+
+		if (ref->status == REF_STATUS_OK) {
+			for (report = ref->report; report; report = report->next) {
+				if (count++ > 0)
+					strbuf_addf(&buf, "ok %s\n", ref->name);
+				if (report->ref_name)
+					strbuf_addf(&buf, "option refname %s\n",
+						report->ref_name);
+				if (report->old_oid)
+					strbuf_addf(&buf, "option old-oid %s\n",
+						oid_to_hex(report->old_oid));
+				if (report->new_oid)
+					strbuf_addf(&buf, "option new-oid %s\n",
+						oid_to_hex(report->new_oid));
+				if (report->forced_update)
+					strbuf_addstr(&buf, "option forced-update\n");
+			}
+		}
+		write_or_die(1, buf.buf, buf.len);
+	}
+	strbuf_release(&buf);
+}
+
+static int send_pack_config(const char *k, const char *v,
+			    const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(k, "push.gpgsign")) {
+		switch (git_parse_maybe_bool(v)) {
+		case 0:
+			args.push_cert = SEND_PACK_PUSH_CERT_NEVER;
+			break;
+		case 1:
+			args.push_cert = SEND_PACK_PUSH_CERT_ALWAYS;
+			break;
+		default:
+			if (!strcasecmp(v, "if-asked"))
+				args.push_cert = SEND_PACK_PUSH_CERT_IF_ASKED;
+			else
+				return error(_("invalid value for '%s'"), k);
+		}
+	}
+	return git_default_config(k, v, ctx, cb);
+}
+
+int cmd_send_pack(int argc,
+		  const char **argv,
+		  const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	struct refspec rs = REFSPEC_INIT_PUSH;
+	const char *remote_name = NULL;
+	struct remote *remote = NULL;
+	const char *dest = NULL;
+	int fd[2];
+	struct child_process *conn;
+	struct oid_array extra_have = OID_ARRAY_INIT;
+	struct oid_array shallow = OID_ARRAY_INIT;
+	struct ref *remote_refs, *local_refs;
+	int ret;
+	int helper_status = 0;
+	int send_all = 0;
+	int verbose = 0;
+	const char *receivepack = "git-receive-pack";
+	unsigned dry_run = 0;
+	unsigned send_mirror = 0;
+	unsigned force_update = 0;
+	unsigned quiet = 0;
+	int push_cert = 0;
+	struct string_list push_options = STRING_LIST_INIT_NODUP;
+	unsigned use_thin_pack = 0;
+	unsigned atomic = 0;
+	unsigned stateless_rpc = 0;
+	int flags;
+	unsigned int reject_reasons;
+	int progress = -1;
+	int from_stdin = 0;
+	struct push_cas_option cas = {0};
+	int force_if_includes = 0;
+	struct packet_reader reader;
+
+	struct option options[] = {
+		OPT__VERBOSITY(&verbose),
+		OPT_STRING(0, "receive-pack", &receivepack, "receive-pack", N_("receive pack program")),
+		OPT_STRING(0, "exec", &receivepack, "receive-pack", N_("receive pack program")),
+		OPT_STRING(0, "remote", &remote_name, "remote", N_("remote name")),
+		OPT_BOOL(0, "all", &send_all, N_("push all refs")),
+		OPT_BOOL('n' , "dry-run", &dry_run, N_("dry run")),
+		OPT_BOOL(0, "mirror", &send_mirror, N_("mirror all refs")),
+		OPT_BOOL('f', "force", &force_update, N_("force updates")),
+		OPT_CALLBACK_F(0, "signed", &push_cert, "(yes|no|if-asked)", N_("GPG sign the push"),
+		  PARSE_OPT_OPTARG, option_parse_push_signed),
+		OPT_STRING_LIST(0, "push-option", &push_options,
+				N_("server-specific"),
+				N_("option to transmit")),
+		OPT_BOOL(0, "progress", &progress, N_("force progress reporting")),
+		OPT_BOOL(0, "thin", &use_thin_pack, N_("use thin pack")),
+		OPT_BOOL(0, "atomic", &atomic, N_("request atomic transaction on remote side")),
+		OPT_BOOL(0, "stateless-rpc", &stateless_rpc, N_("use stateless RPC protocol")),
+		OPT_BOOL(0, "stdin", &from_stdin, N_("read refs from stdin")),
+		OPT_BOOL(0, "helper-status", &helper_status, N_("print status from remote helper")),
+		OPT_CALLBACK_F(0, "force-with-lease", &cas, N_("<refname>:<expect>"),
+		  N_("require old value of ref to be at this value"),
+		  PARSE_OPT_OPTARG, parseopt_push_cas_option),
+		OPT_BOOL(0, TRANS_OPT_FORCE_IF_INCLUDES, &force_if_includes,
+			 N_("require remote updates to be integrated locally")),
+		OPT_END()
+	};
+
+	git_config(send_pack_config, NULL);
+	argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
+	if (argc > 0) {
+		dest = argv[0];
+		refspec_appendn(&rs, argv + 1, argc - 1);
+	}
+
+	if (!dest)
+		usage_with_options(send_pack_usage, options);
+
+	args.verbose = verbose;
+	args.dry_run = dry_run;
+	args.send_mirror = send_mirror;
+	args.force_update = force_update;
+	args.quiet = quiet;
+	args.push_cert = push_cert;
+	args.progress = progress;
+	args.use_thin_pack = use_thin_pack;
+	args.atomic = atomic;
+	args.stateless_rpc = stateless_rpc;
+	args.push_options = push_options.nr ? &push_options : NULL;
+	args.url = dest;
+
+	if (from_stdin) {
+		if (args.stateless_rpc) {
+			const char *buf;
+			while ((buf = packet_read_line(0, NULL)))
+				refspec_append(&rs, buf);
+		} else {
+			struct strbuf line = STRBUF_INIT;
+			while (strbuf_getline(&line, stdin) != EOF)
+				refspec_append(&rs, line.buf);
+			strbuf_release(&line);
+		}
+	}
+
+	/*
+	 * --all and --mirror are incompatible; neither makes sense
+	 * with any refspecs.
+	 */
+	if ((rs.nr > 0 && (send_all || args.send_mirror)) ||
+	    (send_all && args.send_mirror))
+		usage_with_options(send_pack_usage, options);
+
+	if (remote_name) {
+		remote = remote_get(remote_name);
+		if (!remote_has_url(remote, dest)) {
+			die("Destination %s is not a uri for %s",
+			    dest, remote_name);
+		}
+	}
+
+	if (progress == -1)
+		progress = !args.quiet && isatty(2);
+	args.progress = progress;
+
+	if (args.stateless_rpc) {
+		conn = NULL;
+		fd[0] = 0;
+		fd[1] = 1;
+	} else {
+		conn = git_connect(fd, dest, "git-receive-pack", receivepack,
+			args.verbose ? CONNECT_VERBOSE : 0);
+	}
+
+	packet_reader_init(&reader, fd[0], NULL, 0,
+			   PACKET_READ_CHOMP_NEWLINE |
+			   PACKET_READ_GENTLE_ON_EOF |
+			   PACKET_READ_DIE_ON_ERR_PACKET);
+
+	switch (discover_version(&reader)) {
+	case protocol_v2:
+		die("support for protocol v2 not implemented yet");
+		break;
+	case protocol_v1:
+	case protocol_v0:
+		get_remote_heads(&reader, &remote_refs, REF_NORMAL,
+				 &extra_have, &shallow);
+		break;
+	case protocol_unknown_version:
+		BUG("unknown protocol version");
+	}
+
+	local_refs = get_local_heads();
+
+	flags = MATCH_REFS_NONE;
+
+	if (send_all)
+		flags |= MATCH_REFS_ALL;
+	if (args.send_mirror)
+		flags |= MATCH_REFS_MIRROR;
+
+	/* match them up */
+	if (match_push_refs(local_refs, &remote_refs, &rs, flags))
+		return -1;
+
+	if (!is_empty_cas(&cas))
+		apply_push_cas(&cas, remote, remote_refs);
+
+	if (!is_empty_cas(&cas) && force_if_includes)
+		cas.use_force_if_includes = 1;
+
+	set_ref_status_for_push(remote_refs, args.send_mirror,
+		args.force_update);
+
+	ret = send_pack(the_repository, &args, fd, conn, remote_refs, &extra_have);
+
+	if (helper_status)
+		print_helper_status(remote_refs);
+
+	close(fd[1]);
+	close(fd[0]);
+
+	ret |= finish_connect(conn);
+
+	if (!helper_status)
+		transport_print_push_status(dest, remote_refs, args.verbose, 0, &reject_reasons);
+
+	if (!args.dry_run && remote) {
+		struct ref *ref;
+		for (ref = remote_refs; ref; ref = ref->next)
+			transport_update_tracking_ref(remote, ref, args.verbose);
+	}
+
+	if (!ret && !transport_refs_pushed(remote_refs))
+		/* stable plumbing output; do not modify or localize */
+		fprintf(stderr, "Everything up-to-date\n");
+
+	string_list_clear(&push_options, 0);
+	free_refs(remote_refs);
+	free_refs(local_refs);
+	refspec_clear(&rs);
+	oid_array_clear(&shallow);
+	clear_cas_option(&cas);
+	return ret;
+}
diff --git a/builtin/shortlog.c b/builtin/shortlog.c
new file mode 100644
index 0000000000..30075b67be
--- /dev/null
+++ b/builtin/shortlog.c
@@ -0,0 +1,534 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "config.h"
+#include "commit.h"
+#include "diff.h"
+#include "environment.h"
+#include "gettext.h"
+#include "string-list.h"
+#include "revision.h"
+#include "utf8.h"
+#include "mailmap.h"
+#include "setup.h"
+#include "shortlog.h"
+#include "parse-options.h"
+#include "trailer.h"
+#include "strmap.h"
+
+static char const * const shortlog_usage[] = {
+	N_("git shortlog [<options>] [<revision-range>] [[--] <path>...]"),
+	N_("git log --pretty=short | git shortlog [<options>]"),
+	NULL
+};
+
+/*
+ * The util field of our string_list_items will contain one of two things:
+ *
+ *   - if --summary is not in use, it will point to a string list of the
+ *     oneline subjects assigned to this author
+ *
+ *   - if --summary is in use, we don't need that list; we only need to know
+ *     its size. So we abuse the pointer slot to store our integer counter.
+ *
+ *  This macro accesses the latter.
+ */
+#define UTIL_TO_INT(x) ((intptr_t)(x)->util)
+
+static int compare_by_counter(const void *a1, const void *a2)
+{
+	const struct string_list_item *i1 = a1, *i2 = a2;
+	return UTIL_TO_INT(i2) - UTIL_TO_INT(i1);
+}
+
+static int compare_by_list(const void *a1, const void *a2)
+{
+	const struct string_list_item *i1 = a1, *i2 = a2;
+	const struct string_list *l1 = i1->util, *l2 = i2->util;
+
+	if (l1->nr < l2->nr)
+		return 1;
+	else if (l1->nr == l2->nr)
+		return 0;
+	else
+		return -1;
+}
+
+static void insert_one_record(struct shortlog *log,
+			      const char *ident,
+			      const char *oneline)
+{
+	struct string_list_item *item;
+
+	item = string_list_insert(&log->list, ident);
+
+	if (log->summary)
+		item->util = (void *)(UTIL_TO_INT(item) + 1);
+	else {
+		char *buffer;
+		struct strbuf subject = STRBUF_INIT;
+		const char *eol;
+
+		/* Skip any leading whitespace, including any blank lines. */
+		while (*oneline && isspace(*oneline))
+			oneline++;
+		eol = strchr(oneline, '\n');
+		if (!eol)
+			eol = oneline + strlen(oneline);
+		if (starts_with(oneline, "[PATCH")) {
+			char *eob = strchr(oneline, ']');
+			if (eob && (!eol || eob < eol))
+				oneline = eob + 1;
+		}
+		while (*oneline && isspace(*oneline) && *oneline != '\n')
+			oneline++;
+		format_subject(&subject, oneline, " ");
+		buffer = strbuf_detach(&subject, NULL);
+
+		if (!item->util) {
+			item->util = xmalloc(sizeof(struct string_list));
+			string_list_init_nodup(item->util);
+		}
+		string_list_append(item->util, buffer);
+	}
+}
+
+static int parse_ident(struct shortlog *log,
+		       struct strbuf *out, const char *in)
+{
+	const char *mailbuf, *namebuf;
+	size_t namelen, maillen;
+	struct ident_split ident;
+
+	if (split_ident_line(&ident, in, strlen(in)))
+		return -1;
+
+	namebuf = ident.name_begin;
+	mailbuf = ident.mail_begin;
+	namelen = ident.name_end - ident.name_begin;
+	maillen = ident.mail_end - ident.mail_begin;
+
+	map_user(&log->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
+	strbuf_add(out, namebuf, namelen);
+	if (log->email)
+		strbuf_addf(out, " <%.*s>", (int)maillen, mailbuf);
+
+	return 0;
+}
+
+static void read_from_stdin(struct shortlog *log)
+{
+	struct strbuf ident = STRBUF_INIT;
+	struct strbuf mapped_ident = STRBUF_INIT;
+	struct strbuf oneline = STRBUF_INIT;
+	static const char *author_match[2] = { "Author: ", "author " };
+	static const char *committer_match[2] = { "Commit: ", "committer " };
+	const char **match;
+
+	if (HAS_MULTI_BITS(log->groups))
+		die(_("using multiple --group options with stdin is not supported"));
+
+	switch (log->groups) {
+	case SHORTLOG_GROUP_AUTHOR:
+		match = author_match;
+		break;
+	case SHORTLOG_GROUP_COMMITTER:
+		match = committer_match;
+		break;
+	case SHORTLOG_GROUP_TRAILER:
+		die(_("using %s with stdin is not supported"), "--group=trailer");
+	case SHORTLOG_GROUP_FORMAT:
+		die(_("using %s with stdin is not supported"), "--group=format");
+	default:
+		BUG("unhandled shortlog group");
+	}
+
+	while (strbuf_getline_lf(&ident, stdin) != EOF) {
+		const char *v;
+		if (!skip_prefix(ident.buf, match[0], &v) &&
+		    !skip_prefix(ident.buf, match[1], &v))
+			continue;
+		while (strbuf_getline_lf(&oneline, stdin) != EOF &&
+		       oneline.len)
+			; /* discard headers */
+		while (strbuf_getline_lf(&oneline, stdin) != EOF &&
+		       !oneline.len)
+			; /* discard blanks */
+
+		strbuf_reset(&mapped_ident);
+		if (parse_ident(log, &mapped_ident, v) < 0)
+			continue;
+
+		insert_one_record(log, mapped_ident.buf, oneline.buf);
+	}
+	strbuf_release(&ident);
+	strbuf_release(&mapped_ident);
+	strbuf_release(&oneline);
+}
+
+static void insert_records_from_trailers(struct shortlog *log,
+					 struct strset *dups,
+					 struct commit *commit,
+					 struct pretty_print_context *ctx,
+					 const char *oneline)
+{
+	struct trailer_iterator iter;
+	const char *commit_buffer, *body;
+	struct strbuf ident = STRBUF_INIT;
+
+	if (!log->trailers.nr)
+		return;
+
+	/*
+	 * Using repo_format_commit_message("%B") would be simpler here, but
+	 * this saves us copying the message.
+	 */
+	commit_buffer = repo_logmsg_reencode(the_repository, commit, NULL,
+					     ctx->output_encoding);
+	body = strstr(commit_buffer, "\n\n");
+	if (!body)
+		return;
+
+	trailer_iterator_init(&iter, body);
+	while (trailer_iterator_advance(&iter)) {
+		const char *value = iter.val.buf;
+
+		if (!string_list_has_string(&log->trailers, iter.key.buf))
+			continue;
+
+		strbuf_reset(&ident);
+		if (!parse_ident(log, &ident, value))
+			value = ident.buf;
+
+		if (!strset_add(dups, value))
+			continue;
+		insert_one_record(log, value, oneline);
+	}
+	trailer_iterator_release(&iter);
+
+	strbuf_release(&ident);
+	repo_unuse_commit_buffer(the_repository, commit, commit_buffer);
+}
+
+static int shortlog_needs_dedup(const struct shortlog *log)
+{
+	return HAS_MULTI_BITS(log->groups) || log->format.nr > 1 || log->trailers.nr;
+}
+
+static void insert_records_from_format(struct shortlog *log,
+				       struct strset *dups,
+				       struct commit *commit,
+				       struct pretty_print_context *ctx,
+				       const char *oneline)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct string_list_item *item;
+
+	for_each_string_list_item(item, &log->format) {
+		strbuf_reset(&buf);
+
+		repo_format_commit_message(the_repository, commit,
+					   item->string, &buf, ctx);
+
+		if (!shortlog_needs_dedup(log) || strset_add(dups, buf.buf))
+			insert_one_record(log, buf.buf, oneline);
+	}
+
+	strbuf_release(&buf);
+}
+
+void shortlog_add_commit(struct shortlog *log, struct commit *commit)
+{
+	struct strbuf oneline = STRBUF_INIT;
+	struct strset dups = STRSET_INIT;
+	struct pretty_print_context ctx = {0};
+	const char *oneline_str;
+
+	ctx.fmt = CMIT_FMT_USERFORMAT;
+	ctx.abbrev = log->abbrev;
+	ctx.date_mode = log->date_mode;
+	ctx.output_encoding = get_log_output_encoding();
+
+	if (!log->summary) {
+		if (log->user_format)
+			pretty_print_commit(&ctx, commit, &oneline);
+		else
+			repo_format_commit_message(the_repository, commit,
+						   "%s", &oneline, &ctx);
+	}
+	oneline_str = oneline.len ? oneline.buf : "<none>";
+
+	insert_records_from_trailers(log, &dups, commit, &ctx, oneline_str);
+	insert_records_from_format(log, &dups, commit, &ctx, oneline_str);
+
+	strset_clear(&dups);
+	strbuf_release(&oneline);
+}
+
+static void get_from_rev(struct rev_info *rev, struct shortlog *log)
+{
+	struct commit *commit;
+
+	if (prepare_revision_walk(rev))
+		die(_("revision walk setup failed"));
+	while ((commit = get_revision(rev)) != NULL)
+		shortlog_add_commit(log, commit);
+}
+
+static int parse_uint(char const **arg, int comma, int defval)
+{
+	unsigned long ul;
+	int ret;
+	char *endp;
+
+	ul = strtoul(*arg, &endp, 10);
+	if (*endp && *endp != comma)
+		return -1;
+	if (ul > INT_MAX)
+		return -1;
+	ret = *arg == endp ? defval : (int)ul;
+	*arg = *endp ? endp + 1 : endp;
+	return ret;
+}
+
+static const char wrap_arg_usage[] = "-w[<width>[,<indent1>[,<indent2>]]]";
+#define DEFAULT_WRAPLEN 76
+#define DEFAULT_INDENT1 6
+#define DEFAULT_INDENT2 9
+
+static int parse_wrap_args(const struct option *opt, const char *arg, int unset)
+{
+	struct shortlog *log = opt->value;
+
+	log->wrap_lines = !unset;
+	if (unset)
+		return 0;
+	if (!arg) {
+		log->wrap = DEFAULT_WRAPLEN;
+		log->in1 = DEFAULT_INDENT1;
+		log->in2 = DEFAULT_INDENT2;
+		return 0;
+	}
+
+	log->wrap = parse_uint(&arg, ',', DEFAULT_WRAPLEN);
+	log->in1 = parse_uint(&arg, ',', DEFAULT_INDENT1);
+	log->in2 = parse_uint(&arg, '\0', DEFAULT_INDENT2);
+	if (log->wrap < 0 || log->in1 < 0 || log->in2 < 0)
+		return error(wrap_arg_usage);
+	if (log->wrap &&
+	    ((log->in1 && log->wrap <= log->in1) ||
+	     (log->in2 && log->wrap <= log->in2)))
+		return error(wrap_arg_usage);
+	return 0;
+}
+
+static int parse_group_option(const struct option *opt, const char *arg, int unset)
+{
+	struct shortlog *log = opt->value;
+	const char *field;
+
+	if (unset) {
+		log->groups = 0;
+		string_list_clear(&log->trailers, 0);
+		string_list_clear(&log->format, 0);
+	} else if (!strcasecmp(arg, "author"))
+		log->groups |= SHORTLOG_GROUP_AUTHOR;
+	else if (!strcasecmp(arg, "committer"))
+		log->groups |= SHORTLOG_GROUP_COMMITTER;
+	else if (skip_prefix(arg, "trailer:", &field)) {
+		log->groups |= SHORTLOG_GROUP_TRAILER;
+		string_list_append(&log->trailers, field);
+	} else if (skip_prefix(arg, "format:", &field)) {
+		log->groups |= SHORTLOG_GROUP_FORMAT;
+		string_list_append(&log->format, field);
+	} else if (strchr(arg, '%')) {
+		log->groups |= SHORTLOG_GROUP_FORMAT;
+		string_list_append(&log->format, arg);
+	} else {
+		return error(_("unknown group type: %s"), arg);
+	}
+
+	return 0;
+}
+
+
+void shortlog_init(struct shortlog *log)
+{
+	memset(log, 0, sizeof(*log));
+
+	read_mailmap(&log->mailmap);
+
+	log->list.strdup_strings = 1;
+	log->wrap = DEFAULT_WRAPLEN;
+	log->in1 = DEFAULT_INDENT1;
+	log->in2 = DEFAULT_INDENT2;
+	log->trailers.strdup_strings = 1;
+	log->trailers.cmp = strcasecmp;
+	log->format.strdup_strings = 1;
+}
+
+void shortlog_finish_setup(struct shortlog *log)
+{
+	if (log->groups & SHORTLOG_GROUP_AUTHOR)
+		string_list_append(&log->format,
+				   log->email ? "%aN <%aE>" : "%aN");
+	if (log->groups & SHORTLOG_GROUP_COMMITTER)
+		string_list_append(&log->format,
+				   log->email ? "%cN <%cE>" : "%cN");
+
+	string_list_sort(&log->trailers);
+}
+
+int cmd_shortlog(int argc,
+		 const char **argv,
+		 const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct shortlog log = { STRING_LIST_INIT_NODUP };
+	struct rev_info rev;
+	int nongit = !startup_info->have_repository;
+
+	const struct option options[] = {
+		OPT_BIT('c', "committer", &log.groups,
+			N_("group by committer rather than author"),
+			SHORTLOG_GROUP_COMMITTER),
+		OPT_BOOL('n', "numbered", &log.sort_by_number,
+			 N_("sort output according to the number of commits per author")),
+		OPT_BOOL('s', "summary", &log.summary,
+			 N_("suppress commit descriptions, only provides commit count")),
+		OPT_BOOL('e', "email", &log.email,
+			 N_("show the email address of each author")),
+		OPT_CALLBACK_F('w', NULL, &log, N_("<w>[,<i1>[,<i2>]]"),
+			N_("linewrap output"), PARSE_OPT_OPTARG,
+			&parse_wrap_args),
+		OPT_CALLBACK(0, "group", &log, N_("field"),
+			N_("group by field"), parse_group_option),
+		OPT_END(),
+	};
+
+	struct parse_opt_ctx_t ctx;
+
+	/*
+	 * NEEDSWORK: Later on we'll call parse_revision_opt which relies on
+	 * the hash algorithm being set but since we are operating outside of a
+	 * Git repository we cannot determine one. This is only needed because
+	 * parse_revision_opt expects hexsz for --abbrev which is irrelevant
+	 * for shortlog outside of a git repository. For now explicitly set
+	 * SHA1, but ideally the parsing machinery would be split between
+	 * git/nongit so that we do not have to do this.
+	 */
+	if (nongit && !the_hash_algo)
+		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
+	git_config(git_default_config, NULL);
+	shortlog_init(&log);
+	repo_init_revisions(the_repository, &rev, prefix);
+	parse_options_start(&ctx, argc, argv, prefix, options,
+			    PARSE_OPT_KEEP_DASHDASH | PARSE_OPT_KEEP_ARGV0);
+
+	for (;;) {
+		switch (parse_options_step(&ctx, options, shortlog_usage)) {
+		case PARSE_OPT_NON_OPTION:
+		case PARSE_OPT_UNKNOWN:
+			break;
+		case PARSE_OPT_HELP:
+		case PARSE_OPT_ERROR:
+		case PARSE_OPT_SUBCOMMAND:
+			exit(129);
+		case PARSE_OPT_COMPLETE:
+			exit(0);
+		case PARSE_OPT_DONE:
+			goto parse_done;
+		}
+		parse_revision_opt(&rev, &ctx, options, shortlog_usage);
+	}
+parse_done:
+	revision_opts_finish(&rev);
+	argc = parse_options_end(&ctx);
+
+	if (nongit && argc > 1) {
+		error(_("too many arguments given outside repository"));
+		usage_with_options(shortlog_usage, options);
+	}
+
+	if (!nongit && setup_revisions(argc, argv, &rev, NULL) != 1) {
+		error(_("unrecognized argument: %s"), argv[1]);
+		usage_with_options(shortlog_usage, options);
+	}
+
+	log.user_format = rev.commit_format == CMIT_FMT_USERFORMAT;
+	log.abbrev = rev.abbrev;
+	log.file = rev.diffopt.file;
+	log.date_mode = rev.date_mode;
+
+	if (!log.groups)
+		log.groups = SHORTLOG_GROUP_AUTHOR;
+	shortlog_finish_setup(&log);
+
+	/* assume HEAD if from a tty */
+	if (!nongit && !rev.pending.nr && isatty(0))
+		add_head_to_pending(&rev);
+	if (rev.pending.nr == 0) {
+		if (isatty(0))
+			fprintf(stderr, _("(reading log message from standard input)\n"));
+		read_from_stdin(&log);
+	}
+	else
+		get_from_rev(&rev, &log);
+
+	shortlog_output(&log);
+	release_revisions(&rev);
+	return 0;
+}
+
+static void add_wrapped_shortlog_msg(struct strbuf *sb, const char *s,
+				     const struct shortlog *log)
+{
+	strbuf_add_wrapped_text(sb, s, log->in1, log->in2, log->wrap);
+	strbuf_addch(sb, '\n');
+}
+
+void shortlog_output(struct shortlog *log)
+{
+	size_t i, j;
+	struct strbuf sb = STRBUF_INIT;
+
+	if (log->sort_by_number)
+		STABLE_QSORT(log->list.items, log->list.nr,
+		      log->summary ? compare_by_counter : compare_by_list);
+	for (i = 0; i < log->list.nr; i++) {
+		const struct string_list_item *item = &log->list.items[i];
+		if (log->summary) {
+			fprintf(log->file, "%6d\t%s\n",
+				(int)UTIL_TO_INT(item), item->string);
+		} else {
+			struct string_list *onelines = item->util;
+			fprintf(log->file, "%s (%"PRIuMAX"):\n",
+				item->string, (uintmax_t)onelines->nr);
+			for (j = onelines->nr; j >= 1; j--) {
+				const char *msg = onelines->items[j - 1].string;
+
+				if (log->wrap_lines) {
+					strbuf_reset(&sb);
+					add_wrapped_shortlog_msg(&sb, msg, log);
+					fwrite(sb.buf, sb.len, 1, log->file);
+				}
+				else
+					fprintf(log->file, "      %s\n", msg);
+			}
+			putc('\n', log->file);
+			onelines->strdup_strings = 1;
+			string_list_clear(onelines, 0);
+			free(onelines);
+		}
+
+		log->list.items[i].util = NULL;
+	}
+
+	strbuf_release(&sb);
+	log->list.strdup_strings = 1;
+	string_list_clear(&log->list, 1);
+	clear_mailmap(&log->mailmap);
+	string_list_clear(&log->format, 0);
+	string_list_clear(&log->trailers, 0);
+}
diff --git a/builtin/show-branch.c b/builtin/show-branch.c
new file mode 100644
index 0000000000..fce6b404e9
--- /dev/null
+++ b/builtin/show-branch.c
@@ -0,0 +1,1004 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "pretty.h"
+#include "refs.h"
+#include "color.h"
+#include "strvec.h"
+#include "object-name.h"
+#include "parse-options.h"
+
+#include "dir.h"
+#include "commit-slab.h"
+#include "date.h"
+#include "wildmatch.h"
+
+static const char* show_branch_usage[] = {
+    N_("git show-branch [-a | --all] [-r | --remotes] [--topo-order | --date-order]\n"
+       "                [--current] [--color[=<when>] | --no-color] [--sparse]\n"
+       "                [--more=<n> | --list | --independent | --merge-base]\n"
+       "                [--no-name | --sha1-name] [--topics]\n"
+       "                [(<rev> | <glob>)...]"),
+    N_("git show-branch (-g | --reflog)[=<n>[,<base>]] [--list] [<ref>]"),
+    NULL
+};
+
+static int showbranch_use_color = -1;
+
+static struct strvec default_args = STRVEC_INIT;
+
+/*
+ * TODO: convert this use of commit->object.flags to commit-slab
+ * instead to store a pointer to ref name directly. Then use the same
+ * UNINTERESTING definition from revision.h here.
+ */
+#define UNINTERESTING	01
+
+#define REV_SHIFT	 2
+#define MAX_REVS	(FLAG_BITS - REV_SHIFT) /* should not exceed bits_per_int - REV_SHIFT */
+
+#define DEFAULT_REFLOG	4
+
+static const char *get_color_code(int idx)
+{
+	if (want_color(showbranch_use_color))
+		return column_colors_ansi[idx % column_colors_ansi_max];
+	return "";
+}
+
+static const char *get_color_reset_code(void)
+{
+	if (want_color(showbranch_use_color))
+		return GIT_COLOR_RESET;
+	return "";
+}
+
+static struct commit *interesting(struct commit_list *list)
+{
+	while (list) {
+		struct commit *commit = list->item;
+		list = list->next;
+		if (commit->object.flags & UNINTERESTING)
+			continue;
+		return commit;
+	}
+	return NULL;
+}
+
+struct commit_name {
+	const char *head_name; /* which head's ancestor? */
+	int generation; /* how many parents away from head_name */
+};
+
+define_commit_slab(commit_name_slab, struct commit_name *);
+static struct commit_name_slab name_slab;
+
+static struct commit_name *commit_to_name(struct commit *commit)
+{
+	return *commit_name_slab_at(&name_slab, commit);
+}
+
+
+/* Name the commit as nth generation ancestor of head_name;
+ * we count only the first-parent relationship for naming purposes.
+ */
+static void name_commit(struct commit *commit, const char *head_name, int nth)
+{
+	struct commit_name *name;
+
+	name = *commit_name_slab_at(&name_slab, commit);
+	if (!name) {
+		name = xmalloc(sizeof(*name));
+		*commit_name_slab_at(&name_slab, commit) = name;
+	}
+	name->head_name = head_name;
+	name->generation = nth;
+}
+
+/* Parent is the first parent of the commit.  We may name it
+ * as (n+1)th generation ancestor of the same head_name as
+ * commit is nth generation ancestor of, if that generation
+ * number is better than the name it already has.
+ */
+static void name_parent(struct commit *commit, struct commit *parent)
+{
+	struct commit_name *commit_name = commit_to_name(commit);
+	struct commit_name *parent_name = commit_to_name(parent);
+	if (!commit_name)
+		return;
+	if (!parent_name ||
+	    commit_name->generation + 1 < parent_name->generation)
+		name_commit(parent, commit_name->head_name,
+			    commit_name->generation + 1);
+}
+
+static int name_first_parent_chain(struct commit *c)
+{
+	int i = 0;
+	while (c) {
+		struct commit *p;
+		if (!commit_to_name(c))
+			break;
+		if (!c->parents)
+			break;
+		p = c->parents->item;
+		if (!commit_to_name(p)) {
+			name_parent(c, p);
+			i++;
+		}
+		else
+			break;
+		c = p;
+	}
+	return i;
+}
+
+static void name_commits(struct commit_list *list,
+			 struct commit **rev,
+			 char **ref_name,
+			 int num_rev)
+{
+	struct commit_list *cl;
+	struct commit *c;
+	int i;
+
+	/* First give names to the given heads */
+	for (cl = list; cl; cl = cl->next) {
+		c = cl->item;
+		if (commit_to_name(c))
+			continue;
+		for (i = 0; i < num_rev; i++) {
+			if (rev[i] == c) {
+				name_commit(c, ref_name[i], 0);
+				break;
+			}
+		}
+	}
+
+	/* Then commits on the first parent ancestry chain */
+	do {
+		i = 0;
+		for (cl = list; cl; cl = cl->next) {
+			i += name_first_parent_chain(cl->item);
+		}
+	} while (i);
+
+	/* Finally, any unnamed commits */
+	do {
+		i = 0;
+		for (cl = list; cl; cl = cl->next) {
+			struct commit_list *parents;
+			struct commit_name *n;
+			int nth;
+			c = cl->item;
+			if (!commit_to_name(c))
+				continue;
+			n = commit_to_name(c);
+			parents = c->parents;
+			nth = 0;
+			while (parents) {
+				struct commit *p = parents->item;
+				struct strbuf newname = STRBUF_INIT;
+				parents = parents->next;
+				nth++;
+				if (commit_to_name(p))
+					continue;
+				switch (n->generation) {
+				case 0:
+					strbuf_addstr(&newname, n->head_name);
+					break;
+				case 1:
+					strbuf_addf(&newname, "%s^", n->head_name);
+					break;
+				default:
+					strbuf_addf(&newname, "%s~%d",
+						    n->head_name, n->generation);
+					break;
+				}
+				if (nth == 1)
+					strbuf_addch(&newname, '^');
+				else
+					strbuf_addf(&newname, "^%d", nth);
+				name_commit(p, strbuf_detach(&newname, NULL), 0);
+				i++;
+				name_first_parent_chain(p);
+			}
+		}
+	} while (i);
+}
+
+static int mark_seen(struct commit *commit, struct commit_list **seen_p)
+{
+	if (!commit->object.flags) {
+		commit_list_insert(commit, seen_p);
+		return 1;
+	}
+	return 0;
+}
+
+static void join_revs(struct commit_list **list_p,
+		      struct commit_list **seen_p,
+		      int num_rev, int extra)
+{
+	int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
+	int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
+
+	while (*list_p) {
+		struct commit_list *parents;
+		int still_interesting = !!interesting(*list_p);
+		struct commit *commit = pop_commit(list_p);
+		int flags = commit->object.flags & all_mask;
+
+		if (!still_interesting && extra <= 0)
+			break;
+
+		mark_seen(commit, seen_p);
+		if ((flags & all_revs) == all_revs)
+			flags |= UNINTERESTING;
+		parents = commit->parents;
+
+		while (parents) {
+			struct commit *p = parents->item;
+			int this_flag = p->object.flags;
+			parents = parents->next;
+			if ((this_flag & flags) == flags)
+				continue;
+			repo_parse_commit(the_repository, p);
+			if (mark_seen(p, seen_p) && !still_interesting)
+				extra--;
+			p->object.flags |= flags;
+			commit_list_insert_by_date(p, list_p);
+		}
+	}
+
+	/*
+	 * Postprocess to complete well-poisoning.
+	 *
+	 * At this point we have all the commits we have seen in
+	 * seen_p list.  Mark anything that can be reached from
+	 * uninteresting commits not interesting.
+	 */
+	for (;;) {
+		int changed = 0;
+		struct commit_list *s;
+		for (s = *seen_p; s; s = s->next) {
+			struct commit *c = s->item;
+			struct commit_list *parents;
+
+			if (((c->object.flags & all_revs) != all_revs) &&
+			    !(c->object.flags & UNINTERESTING))
+				continue;
+
+			/* The current commit is either a merge base or
+			 * already uninteresting one.  Mark its parents
+			 * as uninteresting commits _only_ if they are
+			 * already parsed.  No reason to find new ones
+			 * here.
+			 */
+			parents = c->parents;
+			while (parents) {
+				struct commit *p = parents->item;
+				parents = parents->next;
+				if (!(p->object.flags & UNINTERESTING)) {
+					p->object.flags |= UNINTERESTING;
+					changed = 1;
+				}
+			}
+		}
+		if (!changed)
+			break;
+	}
+}
+
+static void show_one_commit(struct commit *commit, int no_name)
+{
+	struct strbuf pretty = STRBUF_INIT;
+	const char *pretty_str = "(unavailable)";
+	struct commit_name *name = commit_to_name(commit);
+
+	if (commit->object.parsed) {
+		pp_commit_easy(CMIT_FMT_ONELINE, commit, &pretty);
+		pretty_str = pretty.buf;
+	}
+	skip_prefix(pretty_str, "[PATCH] ", &pretty_str);
+
+	if (!no_name) {
+		if (name && name->head_name) {
+			printf("[%s", name->head_name);
+			if (name->generation) {
+				if (name->generation == 1)
+					printf("^");
+				else
+					printf("~%d", name->generation);
+			}
+			printf("] ");
+		}
+		else
+			printf("[%s] ",
+			       repo_find_unique_abbrev(the_repository, &commit->object.oid,
+						       DEFAULT_ABBREV));
+	}
+	puts(pretty_str);
+	strbuf_release(&pretty);
+}
+
+static char *ref_name[MAX_REVS + 1];
+static int ref_name_cnt;
+
+static const char *find_digit_prefix(const char *s, int *v)
+{
+	const char *p;
+	int ver;
+	char ch;
+
+	for (p = s, ver = 0;
+	     '0' <= (ch = *p) && ch <= '9';
+	     p++)
+		ver = ver * 10 + ch - '0';
+	*v = ver;
+	return p;
+}
+
+
+static int version_cmp(const char *a, const char *b)
+{
+	while (1) {
+		int va, vb;
+
+		a = find_digit_prefix(a, &va);
+		b = find_digit_prefix(b, &vb);
+		if (va != vb)
+			return va - vb;
+
+		while (1) {
+			int ca = *a;
+			int cb = *b;
+			if ('0' <= ca && ca <= '9')
+				ca = 0;
+			if ('0' <= cb && cb <= '9')
+				cb = 0;
+			if (ca != cb)
+				return ca - cb;
+			if (!ca)
+				break;
+			a++;
+			b++;
+		}
+		if (!*a && !*b)
+			return 0;
+	}
+}
+
+static int compare_ref_name(const void *a_, const void *b_)
+{
+	const char * const*a = a_, * const*b = b_;
+	return version_cmp(*a, *b);
+}
+
+static void sort_ref_range(int bottom, int top)
+{
+	QSORT(ref_name + bottom, top - bottom, compare_ref_name);
+}
+
+static int append_ref(const char *refname, const struct object_id *oid,
+		      int allow_dups)
+{
+	struct commit *commit = lookup_commit_reference_gently(the_repository,
+							       oid, 1);
+	int i;
+
+	if (!commit)
+		return 0;
+
+	if (!allow_dups) {
+		/* Avoid adding the same thing twice */
+		for (i = 0; i < ref_name_cnt; i++)
+			if (!strcmp(refname, ref_name[i]))
+				return 0;
+	}
+	if (MAX_REVS <= ref_name_cnt) {
+		warning(Q_("ignoring %s; cannot handle more than %d ref",
+			   "ignoring %s; cannot handle more than %d refs",
+			   MAX_REVS), refname, MAX_REVS);
+		return 0;
+	}
+	ref_name[ref_name_cnt++] = xstrdup(refname);
+	ref_name[ref_name_cnt] = NULL;
+	return 0;
+}
+
+static int append_head_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+			   int flag UNUSED, void *cb_data UNUSED)
+{
+	struct object_id tmp;
+	int ofs = 11;
+	if (!starts_with(refname, "refs/heads/"))
+		return 0;
+	/* If both heads/foo and tags/foo exists, get_sha1 would
+	 * get confused.
+	 */
+	if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
+		ofs = 5;
+	return append_ref(refname + ofs, oid, 0);
+}
+
+static int append_remote_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+			     int flag UNUSED, void *cb_data UNUSED)
+{
+	struct object_id tmp;
+	int ofs = 13;
+	if (!starts_with(refname, "refs/remotes/"))
+		return 0;
+	/* If both heads/foo and tags/foo exists, get_sha1 would
+	 * get confused.
+	 */
+	if (repo_get_oid(the_repository, refname + ofs, &tmp) || !oideq(&tmp, oid))
+		ofs = 5;
+	return append_ref(refname + ofs, oid, 0);
+}
+
+static int append_tag_ref(const char *refname, const struct object_id *oid,
+			  int flag UNUSED, void *cb_data UNUSED)
+{
+	if (!starts_with(refname, "refs/tags/"))
+		return 0;
+	return append_ref(refname + 5, oid, 0);
+}
+
+static const char *match_ref_pattern = NULL;
+static int match_ref_slash = 0;
+
+static int append_matching_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+			       int flag, void *cb_data)
+{
+	/* we want to allow pattern hold/<asterisk> to show all
+	 * branches under refs/heads/hold/, and v0.99.9? to show
+	 * refs/tags/v0.99.9a and friends.
+	 */
+	const char *tail;
+	int slash = count_slashes(refname);
+	for (tail = refname; *tail && match_ref_slash < slash; )
+		if (*tail++ == '/')
+			slash--;
+	if (!*tail)
+		return 0;
+	if (wildmatch(match_ref_pattern, tail, 0))
+		return 0;
+	if (starts_with(refname, "refs/heads/"))
+		return append_head_ref(refname, NULL, oid, flag, cb_data);
+	if (starts_with(refname, "refs/tags/"))
+		return append_tag_ref(refname, oid, flag, cb_data);
+	return append_ref(refname, oid, 0);
+}
+
+static void snarf_refs(int head, int remotes)
+{
+	if (head) {
+		int orig_cnt = ref_name_cnt;
+
+		refs_for_each_ref(get_main_ref_store(the_repository),
+				  append_head_ref, NULL);
+		sort_ref_range(orig_cnt, ref_name_cnt);
+	}
+	if (remotes) {
+		int orig_cnt = ref_name_cnt;
+
+		refs_for_each_ref(get_main_ref_store(the_repository),
+				  append_remote_ref, NULL);
+		sort_ref_range(orig_cnt, ref_name_cnt);
+	}
+}
+
+static int rev_is_head(const char *head, const char *name)
+{
+	if (!head)
+		return 0;
+	skip_prefix(head, "refs/heads/", &head);
+	if (!skip_prefix(name, "refs/heads/", &name))
+		skip_prefix(name, "heads/", &name);
+	return !strcmp(head, name);
+}
+
+static int show_merge_base(const struct commit_list *seen, int num_rev)
+{
+	int all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
+	int all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
+	int exit_status = 1;
+
+	for (const struct commit_list *s = seen; s; s = s->next) {
+		struct commit *commit = s->item;
+		int flags = commit->object.flags & all_mask;
+		if (!(flags & UNINTERESTING) &&
+		    ((flags & all_revs) == all_revs)) {
+			puts(oid_to_hex(&commit->object.oid));
+			exit_status = 0;
+			commit->object.flags |= UNINTERESTING;
+		}
+	}
+	return exit_status;
+}
+
+static int show_independent(struct commit **rev,
+			    int num_rev,
+			    unsigned int *rev_mask)
+{
+	int i;
+
+	for (i = 0; i < num_rev; i++) {
+		struct commit *commit = rev[i];
+		unsigned int flag = rev_mask[i];
+
+		if (commit->object.flags == flag)
+			puts(oid_to_hex(&commit->object.oid));
+		commit->object.flags |= UNINTERESTING;
+	}
+	return 0;
+}
+
+static void append_one_rev(const char *av)
+{
+	struct object_id revkey;
+	if (!repo_get_oid(the_repository, av, &revkey)) {
+		append_ref(av, &revkey, 0);
+		return;
+	}
+	if (strpbrk(av, "*?[")) {
+		/* glob style match */
+		int saved_matches = ref_name_cnt;
+
+		match_ref_pattern = av;
+		match_ref_slash = count_slashes(av);
+		refs_for_each_ref(get_main_ref_store(the_repository),
+				  append_matching_ref, NULL);
+		if (saved_matches == ref_name_cnt &&
+		    ref_name_cnt < MAX_REVS)
+			error(_("no matching refs with %s"), av);
+		sort_ref_range(saved_matches, ref_name_cnt);
+		return;
+	}
+	die("bad sha1 reference %s", av);
+}
+
+static int git_show_branch_config(const char *var, const char *value,
+				  const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "showbranch.default")) {
+		if (!value)
+			return config_error_nonbool(var);
+		/*
+		 * default_arg is now passed to parse_options(), so we need to
+		 * mimic the real argv a bit better.
+		 */
+		if (!default_args.nr)
+			strvec_push(&default_args, "show-branch");
+		strvec_push(&default_args, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "color.showbranch")) {
+		showbranch_use_color = git_config_colorbool(var, value);
+		return 0;
+	}
+
+	if (git_color_config(var, value, cb) < 0)
+		return -1;
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static int omit_in_dense(struct commit *commit, struct commit **rev, int n)
+{
+	/* If the commit is tip of the named branches, do not
+	 * omit it.
+	 * Otherwise, if it is a merge that is reachable from only one
+	 * tip, it is not that interesting.
+	 */
+	int i, flag, count;
+	for (i = 0; i < n; i++)
+		if (rev[i] == commit)
+			return 0;
+	flag = commit->object.flags;
+	for (i = count = 0; i < n; i++) {
+		if (flag & (1u << (i + REV_SHIFT)))
+			count++;
+	}
+	if (count == 1)
+		return 1;
+	return 0;
+}
+
+static int reflog = 0;
+
+static int parse_reflog_param(const struct option *opt, const char *arg,
+			      int unset)
+{
+	char *ep;
+	const char **base = (const char **)opt->value;
+	BUG_ON_OPT_NEG(unset);
+	if (!arg)
+		arg = "";
+	reflog = strtoul(arg, &ep, 10);
+	if (*ep == ',')
+		*base = ep + 1;
+	else if (*ep)
+		return error("unrecognized reflog param '%s'", arg);
+	else
+		*base = NULL;
+	if (reflog <= 0)
+		reflog = DEFAULT_REFLOG;
+	return 0;
+}
+
+int cmd_show_branch(int ac,
+		const char **av,
+		const char *prefix,
+		struct repository *repo UNUSED)
+{
+	struct commit *rev[MAX_REVS], *commit;
+	char *reflog_msg[MAX_REVS] = {0};
+	struct commit_list *list = NULL, *seen = NULL;
+	unsigned int rev_mask[MAX_REVS];
+	int num_rev, i, extra = 0;
+	int all_heads = 0, all_remotes = 0;
+	int all_mask, all_revs;
+	enum rev_sort_order sort_order = REV_SORT_IN_GRAPH_ORDER;
+	char *head;
+	struct object_id head_oid;
+	int merge_base = 0;
+	int independent = 0;
+	int no_name = 0;
+	int sha1_name = 0;
+	int shown_merge_point = 0;
+	int with_current_branch = 0;
+	int head_at = -1;
+	int topics = 0;
+	int sparse = 0;
+	const char *reflog_base = NULL;
+	struct option builtin_show_branch_options[] = {
+		OPT_BOOL('a', "all", &all_heads,
+			 N_("show remote-tracking and local branches")),
+		OPT_BOOL('r', "remotes", &all_remotes,
+			 N_("show remote-tracking branches")),
+		OPT__COLOR(&showbranch_use_color,
+			    N_("color '*!+-' corresponding to the branch")),
+		{ OPTION_INTEGER, 0, "more", &extra, N_("n"),
+			    N_("show <n> more commits after the common ancestor"),
+			    PARSE_OPT_OPTARG, NULL, (intptr_t)1 },
+		OPT_SET_INT(0, "list", &extra, N_("synonym to more=-1"), -1),
+		OPT_BOOL(0, "no-name", &no_name, N_("suppress naming strings")),
+		OPT_BOOL(0, "current", &with_current_branch,
+			 N_("include the current branch")),
+		OPT_BOOL(0, "sha1-name", &sha1_name,
+			 N_("name commits with their object names")),
+		OPT_BOOL(0, "merge-base", &merge_base,
+			 N_("show possible merge bases")),
+		OPT_BOOL(0, "independent", &independent,
+			    N_("show refs unreachable from any other ref")),
+		OPT_SET_INT_F(0, "topo-order", &sort_order,
+			      N_("show commits in topological order"),
+			      REV_SORT_IN_GRAPH_ORDER, PARSE_OPT_NONEG),
+		OPT_BOOL(0, "topics", &topics,
+			 N_("show only commits not on the first branch")),
+		OPT_SET_INT(0, "sparse", &sparse,
+			    N_("show merges reachable from only one tip"), 1),
+		OPT_SET_INT_F(0, "date-order", &sort_order,
+			      N_("topologically sort, maintaining date order "
+				 "where possible"),
+			      REV_SORT_BY_COMMIT_DATE, PARSE_OPT_NONEG),
+		OPT_CALLBACK_F('g', "reflog", &reflog_base, N_("<n>[,<base>]"),
+			    N_("show <n> most recent ref-log entries starting at "
+			       "base"),
+			    PARSE_OPT_OPTARG | PARSE_OPT_NONEG,
+			    parse_reflog_param),
+		OPT_END()
+	};
+	const char **args_copy = NULL;
+	int ret;
+
+	init_commit_name_slab(&name_slab);
+
+	git_config(git_show_branch_config, NULL);
+
+	/* If nothing is specified, try the default first */
+	if (ac == 1 && default_args.nr) {
+		DUP_ARRAY(args_copy, default_args.v, default_args.nr);
+		ac = default_args.nr;
+		av = args_copy;
+	}
+
+	ac = parse_options(ac, av, prefix, builtin_show_branch_options,
+			   show_branch_usage, PARSE_OPT_STOP_AT_NON_OPTION);
+	if (all_heads)
+		all_remotes = 1;
+
+	if (extra || reflog) {
+		/* "listing" mode is incompatible with
+		 * independent nor merge-base modes.
+		 */
+		if (independent || merge_base)
+			usage_with_options(show_branch_usage,
+					   builtin_show_branch_options);
+		if (reflog && ((0 < extra) || all_heads || all_remotes))
+			/*
+			 * Asking for --more in reflog mode does not
+			 * make sense.  --list is Ok.
+			 *
+			 * Also --all and --remotes do not make sense either.
+			 */
+			die(_("options '%s' and '%s' cannot be used together"), "--reflog",
+				"--all/--remotes/--independent/--merge-base");
+	}
+
+	if (with_current_branch && reflog)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--reflog", "--current");
+
+	/* If nothing is specified, show all branches by default */
+	if (ac <= topics && all_heads + all_remotes == 0)
+		all_heads = 1;
+
+	if (reflog) {
+		struct object_id oid;
+		char *ref;
+		int base = 0;
+		unsigned int flags = 0;
+
+		if (ac == 0) {
+			static const char *fake_av[2];
+
+			fake_av[0] = refs_resolve_refdup(get_main_ref_store(the_repository),
+							 "HEAD",
+							 RESOLVE_REF_READING,
+							 &oid,
+							 NULL);
+			fake_av[1] = NULL;
+			av = fake_av;
+			ac = 1;
+			if (!*av)
+				die(_("no branches given, and HEAD is not valid"));
+		}
+		if (ac != 1)
+			die(_("--reflog option needs one branch name"));
+
+		if (MAX_REVS < reflog)
+			die(Q_("only %d entry can be shown at one time.",
+			       "only %d entries can be shown at one time.",
+			       MAX_REVS), MAX_REVS);
+		if (!repo_dwim_ref(the_repository, *av, strlen(*av), &oid,
+				   &ref, 0))
+			die(_("no such ref %s"), *av);
+
+		/* Has the base been specified? */
+		if (reflog_base) {
+			char *ep;
+			base = strtoul(reflog_base, &ep, 10);
+			if (*ep) {
+				/* Ah, that is a date spec... */
+				timestamp_t at;
+				at = approxidate(reflog_base);
+				read_ref_at(get_main_ref_store(the_repository),
+					    ref, flags, at, -1, &oid, NULL,
+					    NULL, NULL, &base);
+			}
+		}
+
+		for (i = 0; i < reflog; i++) {
+			char *logmsg = NULL;
+			char *nth_desc;
+			const char *msg;
+			char *end;
+			timestamp_t timestamp;
+			int tz;
+
+			if (read_ref_at(get_main_ref_store(the_repository),
+					ref, flags, 0, base + i, &oid, &logmsg,
+					&timestamp, &tz, NULL)) {
+				free(logmsg);
+				reflog = i;
+				break;
+			}
+
+			end = strchr(logmsg, '\n');
+			if (end)
+				*end = '\0';
+
+			msg = (*logmsg == '\0') ? "(none)" : logmsg;
+			reflog_msg[i] = xstrfmt("(%s) %s",
+						show_date(timestamp, tz,
+							  DATE_MODE(RELATIVE)),
+						msg);
+			free(logmsg);
+
+			nth_desc = xstrfmt("%s@{%d}", *av, base+i);
+			append_ref(nth_desc, &oid, 1);
+			free(nth_desc);
+		}
+		free(ref);
+	}
+	else {
+		while (0 < ac) {
+			append_one_rev(*av);
+			ac--; av++;
+		}
+		if (all_heads + all_remotes)
+			snarf_refs(all_heads, all_remotes);
+	}
+
+	head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+				   RESOLVE_REF_READING,
+				   &head_oid, NULL);
+
+	if (with_current_branch && head) {
+		int has_head = 0;
+		for (i = 0; !has_head && i < ref_name_cnt; i++) {
+			/* We are only interested in adding the branch
+			 * HEAD points at.
+			 */
+			if (rev_is_head(head, ref_name[i]))
+				has_head++;
+		}
+		if (!has_head) {
+			const char *name = head;
+			skip_prefix(name, "refs/heads/", &name);
+			append_one_rev(name);
+		}
+	}
+
+	if (!ref_name_cnt) {
+		fprintf(stderr, "No revs to be shown.\n");
+		ret = 0;
+		goto out;
+	}
+
+	for (num_rev = 0; ref_name[num_rev]; num_rev++) {
+		struct object_id revkey;
+		unsigned int flag = 1u << (num_rev + REV_SHIFT);
+
+		if (MAX_REVS <= num_rev)
+			die(Q_("cannot handle more than %d rev.",
+			       "cannot handle more than %d revs.",
+			       MAX_REVS), MAX_REVS);
+		if (repo_get_oid(the_repository, ref_name[num_rev], &revkey))
+			die(_("'%s' is not a valid ref."), ref_name[num_rev]);
+		commit = lookup_commit_reference(the_repository, &revkey);
+		if (!commit)
+			die(_("cannot find commit %s (%s)"),
+			    ref_name[num_rev], oid_to_hex(&revkey));
+		repo_parse_commit(the_repository, commit);
+		mark_seen(commit, &seen);
+
+		/* rev#0 uses bit REV_SHIFT, rev#1 uses bit REV_SHIFT+1,
+		 * and so on.  REV_SHIFT bits from bit 0 are used for
+		 * internal bookkeeping.
+		 */
+		commit->object.flags |= flag;
+		if (commit->object.flags == flag)
+			commit_list_insert_by_date(commit, &list);
+		rev[num_rev] = commit;
+	}
+	for (i = 0; i < num_rev; i++)
+		rev_mask[i] = rev[i]->object.flags;
+
+	if (0 <= extra)
+		join_revs(&list, &seen, num_rev, extra);
+
+	commit_list_sort_by_date(&seen);
+
+	if (merge_base) {
+		ret = show_merge_base(seen, num_rev);
+		goto out;
+	}
+
+	if (independent) {
+		ret = show_independent(rev, num_rev, rev_mask);
+		goto out;
+	}
+
+	/* Show list; --more=-1 means list-only */
+	if (1 < num_rev || extra < 0) {
+		for (i = 0; i < num_rev; i++) {
+			int j;
+			int is_head = rev_is_head(head, ref_name[i]) &&
+				      oideq(&head_oid, &rev[i]->object.oid);
+			if (extra < 0)
+				printf("%c [%s] ",
+				       is_head ? '*' : ' ', ref_name[i]);
+			else {
+				for (j = 0; j < i; j++)
+					putchar(' ');
+				printf("%s%c%s [%s] ",
+				       get_color_code(i),
+				       is_head ? '*' : '!',
+				       get_color_reset_code(), ref_name[i]);
+			}
+
+			if (!reflog) {
+				/* header lines never need name */
+				show_one_commit(rev[i], 1);
+			}
+			else
+				puts(reflog_msg[i]);
+
+			if (is_head)
+				head_at = i;
+		}
+		if (0 <= extra) {
+			for (i = 0; i < num_rev; i++)
+				putchar('-');
+			putchar('\n');
+		}
+	}
+	if (extra < 0) {
+		ret = 0;
+		goto out;
+	}
+
+	/* Sort topologically */
+	sort_in_topological_order(&seen, sort_order);
+
+	/* Give names to commits */
+	if (!sha1_name && !no_name)
+		name_commits(seen, rev, ref_name, num_rev);
+
+	all_mask = ((1u << (REV_SHIFT + num_rev)) - 1);
+	all_revs = all_mask & ~((1u << REV_SHIFT) - 1);
+
+	for (struct commit_list *l = seen; l; l = l->next) {
+		struct commit *commit = l->item;
+		int this_flag = commit->object.flags;
+		int is_merge_point = ((this_flag & all_revs) == all_revs);
+
+		shown_merge_point |= is_merge_point;
+
+		if (1 < num_rev) {
+			int is_merge = !!(commit->parents &&
+					  commit->parents->next);
+			if (topics &&
+			    !is_merge_point &&
+			    (this_flag & (1u << REV_SHIFT)))
+				continue;
+			if (!sparse && is_merge &&
+			    omit_in_dense(commit, rev, num_rev))
+				continue;
+			for (i = 0; i < num_rev; i++) {
+				int mark;
+				if (!(this_flag & (1u << (i + REV_SHIFT))))
+					mark = ' ';
+				else if (is_merge)
+					mark = '-';
+				else if (i == head_at)
+					mark = '*';
+				else
+					mark = '+';
+				if (mark == ' ')
+					putchar(mark);
+				else
+					printf("%s%c%s",
+					       get_color_code(i),
+					       mark, get_color_reset_code());
+			}
+			putchar(' ');
+		}
+		show_one_commit(commit, no_name);
+
+		if (shown_merge_point && --extra < 0)
+			break;
+	}
+
+	ret = 0;
+
+out:
+	for (size_t i = 0; i < ARRAY_SIZE(reflog_msg); i++)
+		free(reflog_msg[i]);
+	free_commit_list(seen);
+	free_commit_list(list);
+	free(args_copy);
+	free(head);
+	return ret;
+}
diff --git a/builtin/show-index.c b/builtin/show-index.c
new file mode 100644
index 0000000000..756d632b51
--- /dev/null
+++ b/builtin/show-index.c
@@ -0,0 +1,125 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "pack.h"
+#include "parse-options.h"
+
+static const char *const show_index_usage[] = {
+	"git show-index [--object-format=<hash-algorithm>]",
+	NULL
+};
+
+int cmd_show_index(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	int i;
+	unsigned nr;
+	unsigned int version;
+	static unsigned int top_index[256];
+	unsigned hashsz;
+	const char *hash_name = NULL;
+	int hash_algo;
+	const struct option show_index_options[] = {
+		OPT_STRING(0, "object-format", &hash_name, N_("hash-algorithm"),
+			   N_("specify the hash algorithm to use")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, show_index_options, show_index_usage, 0);
+
+	if (hash_name) {
+		hash_algo = hash_algo_by_name(hash_name);
+		if (hash_algo == GIT_HASH_UNKNOWN)
+			die(_("Unknown hash algorithm"));
+		repo_set_hash_algo(the_repository, hash_algo);
+	}
+
+	/*
+	 * Fallback to SHA1 if we are running outside of a repository.
+	 *
+	 * TODO: Figure out and implement a way to detect the hash algorithm in use by the
+	 *       the index file passed in and use that instead.
+	 */
+	if (!the_hash_algo)
+		repo_set_hash_algo(the_repository, GIT_HASH_SHA1);
+
+	hashsz = the_hash_algo->rawsz;
+
+	if (fread(top_index, 2 * 4, 1, stdin) != 1)
+		die("unable to read header");
+	if (top_index[0] == htonl(PACK_IDX_SIGNATURE)) {
+		version = ntohl(top_index[1]);
+		if (version < 2 || version > 2)
+			die("unknown index version");
+		if (fread(top_index, 256 * 4, 1, stdin) != 1)
+			die("unable to read index");
+	} else {
+		version = 1;
+		if (fread(&top_index[2], 254 * 4, 1, stdin) != 1)
+			die("unable to read index");
+	}
+	nr = 0;
+	for (i = 0; i < 256; i++) {
+		unsigned n = ntohl(top_index[i]);
+		if (n < nr)
+			die("corrupt index file");
+		nr = n;
+	}
+	if (version == 1) {
+		for (i = 0; i < nr; i++) {
+			unsigned int offset, entry[(GIT_MAX_RAWSZ + 4) / sizeof(unsigned int)];
+
+			if (fread(entry, 4 + hashsz, 1, stdin) != 1)
+				die("unable to read entry %u/%u", i, nr);
+			offset = ntohl(entry[0]);
+			printf("%u %s\n", offset, hash_to_hex((void *)(entry+1)));
+		}
+	} else {
+		unsigned off64_nr = 0;
+		struct {
+			struct object_id oid;
+			uint32_t crc;
+			uint32_t off;
+		} *entries;
+		ALLOC_ARRAY(entries, nr);
+		for (i = 0; i < nr; i++) {
+			if (fread(entries[i].oid.hash, hashsz, 1, stdin) != 1)
+				die("unable to read sha1 %u/%u", i, nr);
+			entries[i].oid.algo = hash_algo_by_ptr(the_hash_algo);
+		}
+		for (i = 0; i < nr; i++)
+			if (fread(&entries[i].crc, 4, 1, stdin) != 1)
+				die("unable to read crc %u/%u", i, nr);
+		for (i = 0; i < nr; i++)
+			if (fread(&entries[i].off, 4, 1, stdin) != 1)
+				die("unable to read 32b offset %u/%u", i, nr);
+		for (i = 0; i < nr; i++) {
+			uint64_t offset;
+			uint32_t off = ntohl(entries[i].off);
+			if (!(off & 0x80000000)) {
+				offset = off;
+			} else {
+				uint32_t off64[2];
+				if ((off & 0x7fffffff) != off64_nr)
+					die("inconsistent 64b offset index");
+				if (fread(off64, 8, 1, stdin) != 1)
+					die("unable to read 64b offset %u", off64_nr);
+				offset = (((uint64_t)ntohl(off64[0])) << 32) |
+						     ntohl(off64[1]);
+				off64_nr++;
+			}
+			printf("%" PRIuMAX " %s (%08"PRIx32")\n",
+			       (uintmax_t) offset,
+			       oid_to_hex(&entries[i].oid),
+			       ntohl(entries[i].crc));
+		}
+		free(entries);
+	}
+	return 0;
+}
diff --git a/builtin/show-ref.c b/builtin/show-ref.c
new file mode 100644
index 0000000000..285cd3e433
--- /dev/null
+++ b/builtin/show-ref.c
@@ -0,0 +1,343 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "refs/refs-internal.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "object.h"
+#include "string-list.h"
+#include "parse-options.h"
+
+static const char * const show_ref_usage[] = {
+	N_("git show-ref [--head] [-d | --dereference]\n"
+	   "             [-s | --hash[=<n>]] [--abbrev[=<n>]] [--branches] [--tags]\n"
+	   "             [--] [<pattern>...]"),
+	N_("git show-ref --verify [-q | --quiet] [-d | --dereference]\n"
+	   "             [-s | --hash[=<n>]] [--abbrev[=<n>]]\n"
+	   "             [--] [<ref>...]"),
+	N_("git show-ref --exclude-existing[=<pattern>]"),
+	N_("git show-ref --exists <ref>"),
+	NULL
+};
+
+struct show_one_options {
+	int quiet;
+	int hash_only;
+	int abbrev;
+	int deref_tags;
+};
+
+static void show_one(const struct show_one_options *opts,
+		     const char *refname, const struct object_id *oid)
+{
+	const char *hex;
+	struct object_id peeled;
+
+	if (!repo_has_object_file(the_repository, oid))
+		die("git show-ref: bad ref %s (%s)", refname,
+		    oid_to_hex(oid));
+
+	if (opts->quiet)
+		return;
+
+	hex = repo_find_unique_abbrev(the_repository, oid, opts->abbrev);
+	if (opts->hash_only)
+		printf("%s\n", hex);
+	else
+		printf("%s %s\n", hex, refname);
+
+	if (!opts->deref_tags)
+		return;
+
+	if (!peel_iterated_oid(the_repository, oid, &peeled)) {
+		hex = repo_find_unique_abbrev(the_repository, &peeled, opts->abbrev);
+		printf("%s %s^{}\n", hex, refname);
+	}
+}
+
+struct show_ref_data {
+	const struct show_one_options *show_one_opts;
+	const char **patterns;
+	int found_match;
+	int show_head;
+};
+
+static int show_ref(const char *refname, const char *referent UNUSED, const struct object_id *oid,
+		    int flag UNUSED, void *cbdata)
+{
+	struct show_ref_data *data = cbdata;
+
+	if (data->show_head && !strcmp(refname, "HEAD"))
+		goto match;
+
+	if (data->patterns) {
+		int reflen = strlen(refname);
+		const char **p = data->patterns, *m;
+		while ((m = *p++) != NULL) {
+			int len = strlen(m);
+			if (len > reflen)
+				continue;
+			if (memcmp(m, refname + reflen - len, len))
+				continue;
+			if (len == reflen)
+				goto match;
+			if (refname[reflen - len - 1] == '/')
+				goto match;
+		}
+		return 0;
+	}
+
+match:
+	data->found_match++;
+
+	show_one(data->show_one_opts, refname, oid);
+
+	return 0;
+}
+
+static int add_existing(const char *refname,
+			const char *referent UNUSED,
+			const struct object_id *oid UNUSED,
+			int flag UNUSED, void *cbdata)
+{
+	struct string_list *list = (struct string_list *)cbdata;
+	string_list_insert(list, refname);
+	return 0;
+}
+
+struct exclude_existing_options {
+	/*
+	 * We need an explicit `enabled` field because it is perfectly valid
+	 * for `pattern` to be `NULL` even if `--exclude-existing` was given.
+	 */
+	int enabled;
+	const char *pattern;
+};
+
+/*
+ * read "^(?:<anything>\s)?<refname>(?:\^\{\})?$" from the standard input,
+ * and
+ * (1) strip "^{}" at the end of line if any;
+ * (2) ignore if match is provided and does not head-match refname;
+ * (3) warn if refname is not a well-formed refname and skip;
+ * (4) ignore if refname is a ref that exists in the local repository;
+ * (5) otherwise output the line.
+ */
+static int cmd_show_ref__exclude_existing(const struct exclude_existing_options *opts)
+{
+	struct string_list existing_refs = STRING_LIST_INIT_DUP;
+	char buf[1024];
+	int patternlen = opts->pattern ? strlen(opts->pattern) : 0;
+
+	refs_for_each_ref(get_main_ref_store(the_repository), add_existing,
+			  &existing_refs);
+	while (fgets(buf, sizeof(buf), stdin)) {
+		char *ref;
+		int len = strlen(buf);
+
+		if (len > 0 && buf[len - 1] == '\n')
+			buf[--len] = '\0';
+		if (3 <= len && !strcmp(buf + len - 3, "^{}")) {
+			len -= 3;
+			buf[len] = '\0';
+		}
+		for (ref = buf + len; buf < ref; ref--)
+			if (isspace(ref[-1]))
+				break;
+		if (opts->pattern) {
+			int reflen = buf + len - ref;
+			if (reflen < patternlen)
+				continue;
+			if (strncmp(ref, opts->pattern, patternlen))
+				continue;
+		}
+		if (check_refname_format(ref, 0)) {
+			warning("ref '%s' ignored", ref);
+			continue;
+		}
+		if (!string_list_has_string(&existing_refs, ref)) {
+			printf("%s\n", buf);
+		}
+	}
+
+	string_list_clear(&existing_refs, 0);
+	return 0;
+}
+
+static int cmd_show_ref__verify(const struct show_one_options *show_one_opts,
+				const char **refs)
+{
+	if (!refs || !*refs)
+		die("--verify requires a reference");
+
+	while (*refs) {
+		struct object_id oid;
+
+		if ((starts_with(*refs, "refs/") || refname_is_safe(*refs)) &&
+		    !refs_read_ref(get_main_ref_store(the_repository), *refs, &oid)) {
+			show_one(show_one_opts, *refs, &oid);
+		}
+		else if (!show_one_opts->quiet)
+			die("'%s' - not a valid ref", *refs);
+		else
+			return 1;
+		refs++;
+	}
+
+	return 0;
+}
+
+struct patterns_options {
+	int show_head;
+	int branches_only;
+	int tags_only;
+};
+
+static int cmd_show_ref__patterns(const struct patterns_options *opts,
+				  const struct show_one_options *show_one_opts,
+				  const char **patterns)
+{
+	struct show_ref_data show_ref_data = {
+		.show_one_opts = show_one_opts,
+		.show_head = opts->show_head,
+	};
+
+	if (patterns && *patterns)
+		show_ref_data.patterns = patterns;
+
+	if (opts->show_head)
+		refs_head_ref(get_main_ref_store(the_repository), show_ref,
+			      &show_ref_data);
+	if (opts->branches_only || opts->tags_only) {
+		if (opts->branches_only)
+			refs_for_each_fullref_in(get_main_ref_store(the_repository),
+						 "refs/heads/", NULL,
+						 show_ref, &show_ref_data);
+		if (opts->tags_only)
+			refs_for_each_fullref_in(get_main_ref_store(the_repository),
+						 "refs/tags/", NULL, show_ref,
+						 &show_ref_data);
+	} else {
+		refs_for_each_ref(get_main_ref_store(the_repository),
+				  show_ref, &show_ref_data);
+	}
+	if (!show_ref_data.found_match)
+		return 1;
+
+	return 0;
+}
+
+static int cmd_show_ref__exists(const char **refs)
+{
+	struct strbuf unused_referent = STRBUF_INIT;
+	struct object_id unused_oid;
+	unsigned int unused_type;
+	int failure_errno = 0;
+	const char *ref;
+	int ret = 0;
+
+	if (!refs || !*refs)
+		die("--exists requires a reference");
+	ref = *refs++;
+	if (*refs)
+		die("--exists requires exactly one reference");
+
+	if (refs_read_raw_ref(get_main_ref_store(the_repository), ref,
+			      &unused_oid, &unused_referent, &unused_type,
+			      &failure_errno)) {
+		if (failure_errno == ENOENT || failure_errno == EISDIR) {
+			error(_("reference does not exist"));
+			ret = 2;
+		} else {
+			errno = failure_errno;
+			error_errno(_("failed to look up reference"));
+			ret = 1;
+		}
+
+		goto out;
+	}
+
+out:
+	strbuf_release(&unused_referent);
+	return ret;
+}
+
+static int hash_callback(const struct option *opt, const char *arg, int unset)
+{
+	struct show_one_options *opts = opt->value;
+	struct option abbrev_opt = *opt;
+
+	opts->hash_only = 1;
+	/* Use full length SHA1 if no argument */
+	if (!arg)
+		return 0;
+
+	abbrev_opt.value = &opts->abbrev;
+	return parse_opt_abbrev_cb(&abbrev_opt, arg, unset);
+}
+
+static int exclude_existing_callback(const struct option *opt, const char *arg,
+				     int unset)
+{
+	struct exclude_existing_options *opts = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	opts->enabled = 1;
+	opts->pattern = arg;
+	return 0;
+}
+
+int cmd_show_ref(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
+{
+	struct exclude_existing_options exclude_existing_opts = {0};
+	struct patterns_options patterns_opts = {0};
+	struct show_one_options show_one_opts = {0};
+	int verify = 0, exists = 0;
+	const struct option show_ref_options[] = {
+		OPT_BOOL(0, "tags", &patterns_opts.tags_only, N_("only show tags (can be combined with --branches)")),
+		OPT_BOOL(0, "branches", &patterns_opts.branches_only, N_("only show branches (can be combined with --tags)")),
+		OPT_HIDDEN_BOOL(0, "heads", &patterns_opts.branches_only,
+				N_("deprecated synonym for --branches")),
+		OPT_BOOL(0, "exists", &exists, N_("check for reference existence without resolving")),
+		OPT_BOOL(0, "verify", &verify, N_("stricter reference checking, "
+			    "requires exact ref path")),
+		OPT_HIDDEN_BOOL('h', NULL, &patterns_opts.show_head,
+				N_("show the HEAD reference, even if it would be filtered out")),
+		OPT_BOOL(0, "head", &patterns_opts.show_head,
+		  N_("show the HEAD reference, even if it would be filtered out")),
+		OPT_BOOL('d', "dereference", &show_one_opts.deref_tags,
+			    N_("dereference tags into object IDs")),
+		OPT_CALLBACK_F('s', "hash", &show_one_opts, N_("n"),
+			       N_("only show SHA1 hash using <n> digits"),
+			       PARSE_OPT_OPTARG, &hash_callback),
+		OPT__ABBREV(&show_one_opts.abbrev),
+		OPT__QUIET(&show_one_opts.quiet,
+			   N_("do not print results to stdout (useful with --verify)")),
+		OPT_CALLBACK_F(0, "exclude-existing", &exclude_existing_opts,
+			       N_("pattern"), N_("show refs from stdin that aren't in local repository"),
+			       PARSE_OPT_OPTARG | PARSE_OPT_NONEG, exclude_existing_callback),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, show_ref_options,
+			     show_ref_usage, 0);
+
+	die_for_incompatible_opt3(exclude_existing_opts.enabled, "--exclude-existing",
+				  verify, "--verify",
+				  exists, "--exists");
+
+	if (exclude_existing_opts.enabled)
+		return cmd_show_ref__exclude_existing(&exclude_existing_opts);
+	else if (verify)
+		return cmd_show_ref__verify(&show_one_opts, argv);
+	else if (exists)
+		return cmd_show_ref__exists(argv);
+	else
+		return cmd_show_ref__patterns(&patterns_opts, &show_one_opts, argv);
+}
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
new file mode 100644
index 0000000000..14dcace5f8
--- /dev/null
+++ b/builtin/sparse-checkout.c
@@ -0,0 +1,1090 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "pathspec.h"
+#include "strbuf.h"
+#include "string-list.h"
+#include "lockfile.h"
+#include "unpack-trees.h"
+#include "quote.h"
+#include "setup.h"
+#include "sparse-index.h"
+#include "worktree.h"
+
+static const char *empty_base = "";
+
+static char const * const builtin_sparse_checkout_usage[] = {
+	N_("git sparse-checkout (init | list | set | add | reapply | disable | check-rules) [<options>]"),
+	NULL
+};
+
+static void write_patterns_to_file(FILE *fp, struct pattern_list *pl)
+{
+	int i;
+
+	for (i = 0; i < pl->nr; i++) {
+		struct path_pattern *p = pl->patterns[i];
+
+		if (p->flags & PATTERN_FLAG_NEGATIVE)
+			fprintf(fp, "!");
+
+		fprintf(fp, "%s", p->pattern);
+
+		if (p->flags & PATTERN_FLAG_MUSTBEDIR)
+			fprintf(fp, "/");
+
+		fprintf(fp, "\n");
+	}
+}
+
+static char const * const builtin_sparse_checkout_list_usage[] = {
+	"git sparse-checkout list",
+	NULL
+};
+
+static int sparse_checkout_list(int argc, const char **argv, const char *prefix,
+				struct repository *repo UNUSED)
+{
+	static struct option builtin_sparse_checkout_list_options[] = {
+		OPT_END(),
+	};
+	struct pattern_list pl;
+	char *sparse_filename;
+	int res;
+
+	setup_work_tree();
+	if (!core_apply_sparse_checkout)
+		die(_("this worktree is not sparse"));
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_sparse_checkout_list_options,
+			     builtin_sparse_checkout_list_usage, 0);
+
+	memset(&pl, 0, sizeof(pl));
+
+	pl.use_cone_patterns = core_sparse_checkout_cone;
+
+	sparse_filename = get_sparse_checkout_filename();
+	res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
+	free(sparse_filename);
+
+	if (res < 0) {
+		warning(_("this worktree is not sparse (sparse-checkout file may not exist)"));
+		return 0;
+	}
+
+	if (pl.use_cone_patterns) {
+		int i;
+		struct pattern_entry *pe;
+		struct hashmap_iter iter;
+		struct string_list sl = STRING_LIST_INIT_DUP;
+
+		hashmap_for_each_entry(&pl.recursive_hashmap, &iter, pe, ent) {
+			/* pe->pattern starts with "/", skip it */
+			string_list_insert(&sl, pe->pattern + 1);
+		}
+
+		string_list_sort(&sl);
+
+		for (i = 0; i < sl.nr; i++) {
+			quote_c_style(sl.items[i].string, NULL, stdout, 0);
+			printf("\n");
+		}
+
+		string_list_clear(&sl, 0);
+	} else {
+		write_patterns_to_file(stdout, &pl);
+	}
+
+	clear_pattern_list(&pl);
+
+	return 0;
+}
+
+static void clean_tracked_sparse_directories(struct repository *r)
+{
+	int i, was_full = 0;
+	struct strbuf path = STRBUF_INIT;
+	size_t pathlen;
+	struct string_list_item *item;
+	struct string_list sparse_dirs = STRING_LIST_INIT_DUP;
+
+	/*
+	 * If we are not using cone mode patterns, then we cannot
+	 * delete directories outside of the sparse cone.
+	 */
+	if (!r || !r->index || !r->worktree)
+		return;
+	if (init_sparse_checkout_patterns(r->index) ||
+	    !r->index->sparse_checkout_patterns->use_cone_patterns)
+		return;
+
+	/*
+	 * Use the sparse index as a data structure to assist finding
+	 * directories that are safe to delete. This conversion to a
+	 * sparse index will not delete directories that contain
+	 * conflicted entries or submodules.
+	 */
+	if (r->index->sparse_index == INDEX_EXPANDED) {
+		/*
+		 * If something, such as a merge conflict or other concern,
+		 * prevents us from converting to a sparse index, then do
+		 * not try deleting files.
+		 */
+		if (convert_to_sparse(r->index, SPARSE_INDEX_MEMORY_ONLY))
+			return;
+		was_full = 1;
+	}
+
+	strbuf_addstr(&path, r->worktree);
+	strbuf_complete(&path, '/');
+	pathlen = path.len;
+
+	/*
+	 * Collect directories that have gone out of scope but also
+	 * exist on disk, so there is some work to be done. We need to
+	 * store the entries in a list before exploring, since that might
+	 * expand the sparse-index again.
+	 */
+	for (i = 0; i < r->index->cache_nr; i++) {
+		struct cache_entry *ce = r->index->cache[i];
+
+		if (S_ISSPARSEDIR(ce->ce_mode) &&
+		    repo_file_exists(r, ce->name))
+			string_list_append(&sparse_dirs, ce->name);
+	}
+
+	for_each_string_list_item(item, &sparse_dirs) {
+		struct dir_struct dir = DIR_INIT;
+		struct pathspec p = { 0 };
+		struct strvec s = STRVEC_INIT;
+
+		strbuf_setlen(&path, pathlen);
+		strbuf_addstr(&path, item->string);
+
+		dir.flags |= DIR_SHOW_IGNORED_TOO;
+
+		setup_standard_excludes(&dir);
+		strvec_push(&s, path.buf);
+
+		parse_pathspec(&p, PATHSPEC_GLOB, 0, NULL, s.v);
+		fill_directory(&dir, r->index, &p);
+
+		if (dir.nr) {
+			warning(_("directory '%s' contains untracked files,"
+				  " but is not in the sparse-checkout cone"),
+				item->string);
+		} else if (remove_dir_recursively(&path, 0)) {
+			/*
+			 * Removal is "best effort". If something blocks
+			 * the deletion, then continue with a warning.
+			 */
+			warning(_("failed to remove directory '%s'"),
+				item->string);
+		}
+
+		strvec_clear(&s);
+		clear_pathspec(&p);
+		dir_clear(&dir);
+	}
+
+	string_list_clear(&sparse_dirs, 0);
+	strbuf_release(&path);
+
+	if (was_full)
+		ensure_full_index(r->index);
+}
+
+static int update_working_directory(struct pattern_list *pl)
+{
+	enum update_sparsity_result result;
+	struct unpack_trees_options o;
+	struct lock_file lock_file = LOCK_INIT;
+	struct repository *r = the_repository;
+	struct pattern_list *old_pl;
+
+	/* If no branch has been checked out, there are no updates to make. */
+	if (is_index_unborn(r->index))
+		return UPDATE_SPARSITY_SUCCESS;
+
+	old_pl = r->index->sparse_checkout_patterns;
+	r->index->sparse_checkout_patterns = pl;
+
+	memset(&o, 0, sizeof(o));
+	o.verbose_update = isatty(2);
+	o.update = 1;
+	o.head_idx = -1;
+	o.src_index = r->index;
+	o.dst_index = r->index;
+	o.skip_sparse_checkout = 0;
+
+	setup_work_tree();
+
+	repo_hold_locked_index(r, &lock_file, LOCK_DIE_ON_ERROR);
+
+	setup_unpack_trees_porcelain(&o, "sparse-checkout");
+	result = update_sparsity(&o, pl);
+	clear_unpack_trees_porcelain(&o);
+
+	if (result == UPDATE_SPARSITY_WARNINGS)
+		/*
+		 * We don't do any special handling of warnings from untracked
+		 * files in the way or dirty entries that can't be removed.
+		 */
+		result = UPDATE_SPARSITY_SUCCESS;
+	if (result == UPDATE_SPARSITY_SUCCESS)
+		write_locked_index(r->index, &lock_file, COMMIT_LOCK);
+	else
+		rollback_lock_file(&lock_file);
+
+	clean_tracked_sparse_directories(r);
+
+	if (r->index->sparse_checkout_patterns != pl) {
+		clear_pattern_list(r->index->sparse_checkout_patterns);
+		FREE_AND_NULL(r->index->sparse_checkout_patterns);
+	}
+	r->index->sparse_checkout_patterns = old_pl;
+
+	return result;
+}
+
+static char *escaped_pattern(char *pattern)
+{
+	char *p = pattern;
+	struct strbuf final = STRBUF_INIT;
+
+	while (*p) {
+		if (is_glob_special(*p))
+			strbuf_addch(&final, '\\');
+
+		strbuf_addch(&final, *p);
+		p++;
+	}
+
+	return strbuf_detach(&final, NULL);
+}
+
+static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
+{
+	int i;
+	struct pattern_entry *pe;
+	struct hashmap_iter iter;
+	struct string_list sl = STRING_LIST_INIT_DUP;
+	struct strbuf parent_pattern = STRBUF_INIT;
+
+	hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent) {
+		if (hashmap_get_entry(&pl->recursive_hashmap, pe, ent, NULL))
+			continue;
+
+		if (!hashmap_contains_parent(&pl->recursive_hashmap,
+					     pe->pattern,
+					     &parent_pattern))
+			string_list_insert(&sl, pe->pattern);
+	}
+
+	string_list_sort(&sl);
+	string_list_remove_duplicates(&sl, 0);
+
+	fprintf(fp, "/*\n!/*/\n");
+
+	for (i = 0; i < sl.nr; i++) {
+		char *pattern = escaped_pattern(sl.items[i].string);
+
+		if (strlen(pattern))
+			fprintf(fp, "%s/\n!%s/*/\n", pattern, pattern);
+		free(pattern);
+	}
+
+	string_list_clear(&sl, 0);
+
+	hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent) {
+		if (!hashmap_contains_parent(&pl->recursive_hashmap,
+					     pe->pattern,
+					     &parent_pattern))
+			string_list_insert(&sl, pe->pattern);
+	}
+
+	strbuf_release(&parent_pattern);
+
+	string_list_sort(&sl);
+	string_list_remove_duplicates(&sl, 0);
+
+	for (i = 0; i < sl.nr; i++) {
+		char *pattern = escaped_pattern(sl.items[i].string);
+		fprintf(fp, "%s/\n", pattern);
+		free(pattern);
+	}
+
+	string_list_clear(&sl, 0);
+}
+
+static int write_patterns_and_update(struct pattern_list *pl)
+{
+	char *sparse_filename;
+	FILE *fp;
+	struct lock_file lk = LOCK_INIT;
+	int result;
+
+	sparse_filename = get_sparse_checkout_filename();
+
+	if (safe_create_leading_directories(sparse_filename))
+		die(_("failed to create directory for sparse-checkout file"));
+
+	hold_lock_file_for_update(&lk, sparse_filename, LOCK_DIE_ON_ERROR);
+
+	result = update_working_directory(pl);
+	if (result) {
+		rollback_lock_file(&lk);
+		update_working_directory(NULL);
+		goto out;
+	}
+
+	fp = fdopen_lock_file(&lk, "w");
+	if (!fp)
+		die_errno(_("unable to fdopen %s"), get_lock_file_path(&lk));
+
+	if (core_sparse_checkout_cone)
+		write_cone_to_file(fp, pl);
+	else
+		write_patterns_to_file(fp, pl);
+
+	if (commit_lock_file(&lk))
+		die_errno(_("unable to write %s"), sparse_filename);
+
+out:
+	clear_pattern_list(pl);
+	free(sparse_filename);
+	return result;
+}
+
+enum sparse_checkout_mode {
+	MODE_NO_PATTERNS = 0,
+	MODE_ALL_PATTERNS = 1,
+	MODE_CONE_PATTERNS = 2,
+};
+
+static int set_config(enum sparse_checkout_mode mode)
+{
+	/* Update to use worktree config, if not already. */
+	if (init_worktree_config(the_repository)) {
+		error(_("failed to initialize worktree config"));
+		return 1;
+	}
+
+	if (repo_config_set_worktree_gently(the_repository,
+					    "core.sparseCheckout",
+					    mode ? "true" : "false") ||
+	    repo_config_set_worktree_gently(the_repository,
+					    "core.sparseCheckoutCone",
+					    mode == MODE_CONE_PATTERNS ?
+						"true" : "false"))
+		return 1;
+
+	if (mode == MODE_NO_PATTERNS)
+		return set_sparse_index_config(the_repository, 0);
+
+	return 0;
+}
+
+static enum sparse_checkout_mode update_cone_mode(int *cone_mode) {
+	/* If not specified, use previous definition of cone mode */
+	if (*cone_mode == -1 && core_apply_sparse_checkout)
+		*cone_mode = core_sparse_checkout_cone;
+
+	/* Set cone/non-cone mode appropriately */
+	core_apply_sparse_checkout = 1;
+	if (*cone_mode == 1 || *cone_mode == -1) {
+		core_sparse_checkout_cone = 1;
+		return MODE_CONE_PATTERNS;
+	}
+	core_sparse_checkout_cone = 0;
+	return MODE_ALL_PATTERNS;
+}
+
+static int update_modes(int *cone_mode, int *sparse_index)
+{
+	int mode, record_mode;
+
+	/* Determine if we need to record the mode; ensure sparse checkout on */
+	record_mode = (*cone_mode != -1) || !core_apply_sparse_checkout;
+
+	mode = update_cone_mode(cone_mode);
+	if (record_mode && set_config(mode))
+		return 1;
+
+	/* Set sparse-index/non-sparse-index mode if specified */
+	if (*sparse_index >= 0) {
+		if (set_sparse_index_config(the_repository, *sparse_index) < 0)
+			die(_("failed to modify sparse-index config"));
+
+		/* force an index rewrite */
+		repo_read_index(the_repository);
+		the_repository->index->updated_workdir = 1;
+
+		if (!*sparse_index)
+			ensure_full_index(the_repository->index);
+	}
+
+	return 0;
+}
+
+static char const * const builtin_sparse_checkout_init_usage[] = {
+	"git sparse-checkout init [--cone] [--[no-]sparse-index]",
+	NULL
+};
+
+static struct sparse_checkout_init_opts {
+	int cone_mode;
+	int sparse_index;
+} init_opts;
+
+static int sparse_checkout_init(int argc, const char **argv, const char *prefix,
+				struct repository *repo UNUSED)
+{
+	struct pattern_list pl;
+	char *sparse_filename;
+	int res;
+	struct object_id oid;
+
+	static struct option builtin_sparse_checkout_init_options[] = {
+		OPT_BOOL(0, "cone", &init_opts.cone_mode,
+			 N_("initialize the sparse-checkout in cone mode")),
+		OPT_BOOL(0, "sparse-index", &init_opts.sparse_index,
+			 N_("toggle the use of a sparse index")),
+		OPT_END(),
+	};
+
+	setup_work_tree();
+	repo_read_index(the_repository);
+
+	init_opts.cone_mode = -1;
+	init_opts.sparse_index = -1;
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_sparse_checkout_init_options,
+			     builtin_sparse_checkout_init_usage, 0);
+
+	if (update_modes(&init_opts.cone_mode, &init_opts.sparse_index))
+		return 1;
+
+	memset(&pl, 0, sizeof(pl));
+
+	sparse_filename = get_sparse_checkout_filename();
+	res = add_patterns_from_file_to_list(sparse_filename, "", 0, &pl, NULL, 0);
+
+	/* If we already have a sparse-checkout file, use it. */
+	if (res >= 0) {
+		free(sparse_filename);
+		clear_pattern_list(&pl);
+		return update_working_directory(NULL);
+	}
+
+	if (repo_get_oid(the_repository, "HEAD", &oid)) {
+		FILE *fp;
+
+		/* assume we are in a fresh repo, but update the sparse-checkout file */
+		if (safe_create_leading_directories(sparse_filename))
+			die(_("unable to create leading directories of %s"),
+			    sparse_filename);
+		fp = xfopen(sparse_filename, "w");
+		if (!fp)
+			die(_("failed to open '%s'"), sparse_filename);
+
+		free(sparse_filename);
+		fprintf(fp, "/*\n!/*/\n");
+		fclose(fp);
+		return 0;
+	}
+
+	free(sparse_filename);
+
+	add_pattern("/*", empty_base, 0, &pl, 0);
+	add_pattern("!/*/", empty_base, 0, &pl, 0);
+	pl.use_cone_patterns = init_opts.cone_mode;
+
+	return write_patterns_and_update(&pl);
+}
+
+static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *path)
+{
+	struct pattern_entry *e = xmalloc(sizeof(*e));
+	e->patternlen = path->len;
+	e->pattern = strbuf_detach(path, NULL);
+	hashmap_entry_init(&e->ent, fspathhash(e->pattern));
+
+	hashmap_add(&pl->recursive_hashmap, &e->ent);
+
+	while (e->patternlen) {
+		char *slash = strrchr(e->pattern, '/');
+		char *oldpattern = e->pattern;
+		size_t newlen;
+		struct pattern_entry *dup;
+
+		if (!slash || slash == e->pattern)
+			break;
+
+		newlen = slash - e->pattern;
+		e = xmalloc(sizeof(struct pattern_entry));
+		e->patternlen = newlen;
+		e->pattern = xstrndup(oldpattern, newlen);
+		hashmap_entry_init(&e->ent, fspathhash(e->pattern));
+
+		dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
+		if (!dup) {
+			hashmap_add(&pl->parent_hashmap, &e->ent);
+		} else {
+			free(e->pattern);
+			free(e);
+			e = dup;
+		}
+	}
+}
+
+static void strbuf_to_cone_pattern(struct strbuf *line, struct pattern_list *pl)
+{
+	strbuf_trim(line);
+
+	strbuf_trim_trailing_dir_sep(line);
+
+	if (strbuf_normalize_path(line))
+		die(_("could not normalize path %s"), line->buf);
+
+	if (!line->len)
+		return;
+
+	if (line->buf[0] != '/')
+		strbuf_insertstr(line, 0, "/");
+
+	insert_recursive_pattern(pl, line);
+}
+
+static void add_patterns_from_input(struct pattern_list *pl,
+				    int argc, const char **argv,
+				    FILE *file)
+{
+	int i;
+	if (core_sparse_checkout_cone) {
+		struct strbuf line = STRBUF_INIT;
+
+		hashmap_init(&pl->recursive_hashmap, pl_hashmap_cmp, NULL, 0);
+		hashmap_init(&pl->parent_hashmap, pl_hashmap_cmp, NULL, 0);
+		pl->use_cone_patterns = 1;
+
+		if (file) {
+			struct strbuf unquoted = STRBUF_INIT;
+			while (!strbuf_getline(&line, file)) {
+				if (line.buf[0] == '"') {
+					strbuf_reset(&unquoted);
+					if (unquote_c_style(&unquoted, line.buf, NULL))
+						die(_("unable to unquote C-style string '%s'"),
+						line.buf);
+
+					strbuf_swap(&unquoted, &line);
+				}
+
+				strbuf_to_cone_pattern(&line, pl);
+			}
+
+			strbuf_release(&unquoted);
+		} else {
+			for (i = 0; i < argc; i++) {
+				strbuf_setlen(&line, 0);
+				strbuf_addstr(&line, argv[i]);
+				strbuf_to_cone_pattern(&line, pl);
+			}
+		}
+		strbuf_release(&line);
+	} else {
+		if (file) {
+			struct strbuf line = STRBUF_INIT;
+
+			while (!strbuf_getline(&line, file))
+				add_pattern(line.buf, empty_base, 0, pl, 0);
+
+			strbuf_release(&line);
+		} else {
+			for (i = 0; i < argc; i++)
+				add_pattern(argv[i], empty_base, 0, pl, 0);
+		}
+	}
+}
+
+enum modify_type {
+	REPLACE,
+	ADD,
+};
+
+static void add_patterns_cone_mode(int argc, const char **argv,
+				   struct pattern_list *pl,
+				   int use_stdin)
+{
+	struct strbuf buffer = STRBUF_INIT;
+	struct pattern_entry *pe;
+	struct hashmap_iter iter;
+	struct pattern_list existing;
+	char *sparse_filename = get_sparse_checkout_filename();
+
+	add_patterns_from_input(pl, argc, argv,
+				use_stdin ? stdin : NULL);
+
+	memset(&existing, 0, sizeof(existing));
+	existing.use_cone_patterns = core_sparse_checkout_cone;
+
+	if (add_patterns_from_file_to_list(sparse_filename, "", 0,
+					   &existing, NULL, 0))
+		die(_("unable to load existing sparse-checkout patterns"));
+	free(sparse_filename);
+
+	if (!existing.use_cone_patterns)
+		die(_("existing sparse-checkout patterns do not use cone mode"));
+
+	hashmap_for_each_entry(&existing.recursive_hashmap, &iter, pe, ent) {
+		if (!hashmap_contains_parent(&pl->recursive_hashmap,
+					pe->pattern, &buffer) ||
+		    !hashmap_contains_parent(&pl->parent_hashmap,
+					pe->pattern, &buffer)) {
+			strbuf_reset(&buffer);
+			strbuf_addstr(&buffer, pe->pattern);
+			insert_recursive_pattern(pl, &buffer);
+		}
+	}
+
+	clear_pattern_list(&existing);
+	strbuf_release(&buffer);
+}
+
+static void add_patterns_literal(int argc, const char **argv,
+				 struct pattern_list *pl,
+				 int use_stdin)
+{
+	char *sparse_filename = get_sparse_checkout_filename();
+	if (add_patterns_from_file_to_list(sparse_filename, "", 0,
+					   pl, NULL, 0))
+		die(_("unable to load existing sparse-checkout patterns"));
+	free(sparse_filename);
+	add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
+}
+
+static int modify_pattern_list(struct strvec *args, int use_stdin,
+			       enum modify_type m)
+{
+	int result;
+	int changed_config = 0;
+	struct pattern_list *pl = xcalloc(1, sizeof(*pl));
+
+	switch (m) {
+	case ADD:
+		if (core_sparse_checkout_cone)
+			add_patterns_cone_mode(args->nr, args->v, pl, use_stdin);
+		else
+			add_patterns_literal(args->nr, args->v, pl, use_stdin);
+		break;
+
+	case REPLACE:
+		add_patterns_from_input(pl, args->nr, args->v,
+					use_stdin ? stdin : NULL);
+		break;
+	}
+
+	if (!core_apply_sparse_checkout) {
+		set_config(MODE_ALL_PATTERNS);
+		core_apply_sparse_checkout = 1;
+		changed_config = 1;
+	}
+
+	result = write_patterns_and_update(pl);
+
+	if (result && changed_config)
+		set_config(MODE_NO_PATTERNS);
+
+	clear_pattern_list(pl);
+	free(pl);
+	return result;
+}
+
+static void sanitize_paths(struct strvec *args,
+			   const char *prefix, int skip_checks)
+{
+	int i;
+
+	if (!args->nr)
+		return;
+
+	if (prefix && *prefix && core_sparse_checkout_cone) {
+		/*
+		 * The args are not pathspecs, so unfortunately we
+		 * cannot imitate how cmd_add() uses parse_pathspec().
+		 */
+		int prefix_len = strlen(prefix);
+
+		for (i = 0; i < args->nr; i++) {
+			char *prefixed_path = prefix_path(prefix, prefix_len, args->v[i]);
+			strvec_replace(args, i, prefixed_path);
+			free(prefixed_path);
+		}
+	}
+
+	if (skip_checks)
+		return;
+
+	if (prefix && *prefix && !core_sparse_checkout_cone)
+		die(_("please run from the toplevel directory in non-cone mode"));
+
+	if (core_sparse_checkout_cone) {
+		for (i = 0; i < args->nr; i++) {
+			if (args->v[i][0] == '/')
+				die(_("specify directories rather than patterns (no leading slash)"));
+			if (args->v[i][0] == '!')
+				die(_("specify directories rather than patterns.  If your directory starts with a '!', pass --skip-checks"));
+			if (strpbrk(args->v[i], "*?[]"))
+				die(_("specify directories rather than patterns.  If your directory really has any of '*?[]\\' in it, pass --skip-checks"));
+		}
+	}
+
+	for (i = 0; i < args->nr; i++) {
+		struct cache_entry *ce;
+		struct index_state *index = the_repository->index;
+		int pos = index_name_pos(index, args->v[i], strlen(args->v[i]));
+
+		if (pos < 0)
+			continue;
+		ce = index->cache[pos];
+		if (S_ISSPARSEDIR(ce->ce_mode))
+			continue;
+
+		if (core_sparse_checkout_cone)
+			die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), args->v[i]);
+		else
+			warning(_("pass a leading slash before paths such as '%s' if you want a single file (see NON-CONE PROBLEMS in the git-sparse-checkout manual)."), args->v[i]);
+	}
+}
+
+static char const * const builtin_sparse_checkout_add_usage[] = {
+	N_("git sparse-checkout add [--skip-checks] (--stdin | <patterns>)"),
+	NULL
+};
+
+static struct sparse_checkout_add_opts {
+	int skip_checks;
+	int use_stdin;
+} add_opts;
+
+static int sparse_checkout_add(int argc, const char **argv, const char *prefix,
+			       struct repository *repo UNUSED)
+{
+	static struct option builtin_sparse_checkout_add_options[] = {
+		OPT_BOOL_F(0, "skip-checks", &add_opts.skip_checks,
+			   N_("skip some sanity checks on the given paths that might give false positives"),
+			   PARSE_OPT_NONEG),
+		OPT_BOOL(0, "stdin", &add_opts.use_stdin,
+			 N_("read patterns from standard in")),
+		OPT_END(),
+	};
+	struct strvec patterns = STRVEC_INIT;
+	int ret;
+
+	setup_work_tree();
+	if (!core_apply_sparse_checkout)
+		die(_("no sparse-checkout to add to"));
+
+	repo_read_index(the_repository);
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_sparse_checkout_add_options,
+			     builtin_sparse_checkout_add_usage, 0);
+
+	for (int i = 0; i < argc; i++)
+		strvec_push(&patterns, argv[i]);
+	sanitize_paths(&patterns, prefix, add_opts.skip_checks);
+
+	ret = modify_pattern_list(&patterns, add_opts.use_stdin, ADD);
+
+	strvec_clear(&patterns);
+	return ret;
+}
+
+static char const * const builtin_sparse_checkout_set_usage[] = {
+	N_("git sparse-checkout set [--[no-]cone] [--[no-]sparse-index] [--skip-checks] (--stdin | <patterns>)"),
+	NULL
+};
+
+static struct sparse_checkout_set_opts {
+	int cone_mode;
+	int sparse_index;
+	int skip_checks;
+	int use_stdin;
+} set_opts;
+
+static int sparse_checkout_set(int argc, const char **argv, const char *prefix,
+			       struct repository *repo UNUSED)
+{
+	int default_patterns_nr = 2;
+	const char *default_patterns[] = {"/*", "!/*/", NULL};
+
+	static struct option builtin_sparse_checkout_set_options[] = {
+		OPT_BOOL(0, "cone", &set_opts.cone_mode,
+			 N_("initialize the sparse-checkout in cone mode")),
+		OPT_BOOL(0, "sparse-index", &set_opts.sparse_index,
+			 N_("toggle the use of a sparse index")),
+		OPT_BOOL_F(0, "skip-checks", &set_opts.skip_checks,
+			   N_("skip some sanity checks on the given paths that might give false positives"),
+			   PARSE_OPT_NONEG),
+		OPT_BOOL_F(0, "stdin", &set_opts.use_stdin,
+			   N_("read patterns from standard in"),
+			   PARSE_OPT_NONEG),
+		OPT_END(),
+	};
+	struct strvec patterns = STRVEC_INIT;
+	int ret;
+
+	setup_work_tree();
+	repo_read_index(the_repository);
+
+	set_opts.cone_mode = -1;
+	set_opts.sparse_index = -1;
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_sparse_checkout_set_options,
+			     builtin_sparse_checkout_set_usage, 0);
+
+	if (update_modes(&set_opts.cone_mode, &set_opts.sparse_index))
+		return 1;
+
+	/*
+	 * Cone mode automatically specifies the toplevel directory.  For
+	 * non-cone mode, if nothing is specified, manually select just the
+	 * top-level directory (much as 'init' would do).
+	 */
+	if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
+		for (int i = 0; i < default_patterns_nr; i++)
+			strvec_push(&patterns, default_patterns[i]);
+	} else {
+		for (int i = 0; i < argc; i++)
+			strvec_push(&patterns, argv[i]);
+		sanitize_paths(&patterns, prefix, set_opts.skip_checks);
+	}
+
+	ret = modify_pattern_list(&patterns, set_opts.use_stdin, REPLACE);
+
+	strvec_clear(&patterns);
+	return ret;
+}
+
+static char const * const builtin_sparse_checkout_reapply_usage[] = {
+	"git sparse-checkout reapply [--[no-]cone] [--[no-]sparse-index]",
+	NULL
+};
+
+static struct sparse_checkout_reapply_opts {
+	int cone_mode;
+	int sparse_index;
+} reapply_opts;
+
+static int sparse_checkout_reapply(int argc, const char **argv,
+				   const char *prefix,
+				   struct repository *repo UNUSED)
+{
+	static struct option builtin_sparse_checkout_reapply_options[] = {
+		OPT_BOOL(0, "cone", &reapply_opts.cone_mode,
+			 N_("initialize the sparse-checkout in cone mode")),
+		OPT_BOOL(0, "sparse-index", &reapply_opts.sparse_index,
+			 N_("toggle the use of a sparse index")),
+		OPT_END(),
+	};
+
+	setup_work_tree();
+	if (!core_apply_sparse_checkout)
+		die(_("must be in a sparse-checkout to reapply sparsity patterns"));
+
+	reapply_opts.cone_mode = -1;
+	reapply_opts.sparse_index = -1;
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_sparse_checkout_reapply_options,
+			     builtin_sparse_checkout_reapply_usage, 0);
+
+	repo_read_index(the_repository);
+
+	if (update_modes(&reapply_opts.cone_mode, &reapply_opts.sparse_index))
+		return 1;
+
+	return update_working_directory(NULL);
+}
+
+static char const * const builtin_sparse_checkout_disable_usage[] = {
+	"git sparse-checkout disable",
+	NULL
+};
+
+static int sparse_checkout_disable(int argc, const char **argv,
+				   const char *prefix,
+				   struct repository *repo UNUSED)
+{
+	static struct option builtin_sparse_checkout_disable_options[] = {
+		OPT_END(),
+	};
+	struct pattern_list pl;
+
+	/*
+	 * We do not exit early if !core_apply_sparse_checkout; due to the
+	 * ability for users to manually muck things up between
+	 *   direct editing of .git/info/sparse-checkout
+	 *   running read-tree -m u HEAD or update-index --skip-worktree
+	 *   direct toggling of config options
+	 * users might end up with an index with SKIP_WORKTREE bit set on
+	 * some files and not know how to undo it.  So, here we just
+	 * forcibly return to a dense checkout regardless of initial state.
+	 */
+
+	setup_work_tree();
+	argc = parse_options(argc, argv, prefix,
+			     builtin_sparse_checkout_disable_options,
+			     builtin_sparse_checkout_disable_usage, 0);
+
+	/*
+	 * Disable the advice message for expanding a sparse index, as we
+	 * are expecting to do that when disabling sparse-checkout.
+	 */
+	give_advice_on_expansion = 0;
+	repo_read_index(the_repository);
+
+	memset(&pl, 0, sizeof(pl));
+	hashmap_init(&pl.recursive_hashmap, pl_hashmap_cmp, NULL, 0);
+	hashmap_init(&pl.parent_hashmap, pl_hashmap_cmp, NULL, 0);
+	pl.use_cone_patterns = 0;
+	core_apply_sparse_checkout = 1;
+
+	add_pattern("/*", empty_base, 0, &pl, 0);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.sparse_index = 0;
+
+	if (update_working_directory(&pl))
+		die(_("error while refreshing working directory"));
+
+	clear_pattern_list(&pl);
+	return set_config(MODE_NO_PATTERNS);
+}
+
+static char const * const builtin_sparse_checkout_check_rules_usage[] = {
+	N_("git sparse-checkout check-rules [-z] [--skip-checks]"
+	   "[--[no-]cone] [--rules-file <file>]"),
+	NULL
+};
+
+static struct sparse_checkout_check_rules_opts {
+	int cone_mode;
+	int null_termination;
+	char *rules_file;
+} check_rules_opts;
+
+static int check_rules(struct pattern_list *pl, int null_terminated) {
+	struct strbuf line = STRBUF_INIT;
+	struct strbuf unquoted = STRBUF_INIT;
+	char *path;
+	int line_terminator = null_terminated ? 0 : '\n';
+	strbuf_getline_fn getline_fn = null_terminated ? strbuf_getline_nul
+		: strbuf_getline;
+	the_repository->index->sparse_checkout_patterns = pl;
+	while (!getline_fn(&line, stdin)) {
+		path = line.buf;
+		if (!null_terminated && line.buf[0] == '"') {
+			strbuf_reset(&unquoted);
+			if (unquote_c_style(&unquoted, line.buf, NULL))
+				die(_("unable to unquote C-style string '%s'"),
+					line.buf);
+
+			path = unquoted.buf;
+		}
+
+		if (path_in_sparse_checkout(path, the_repository->index))
+			write_name_quoted(path, stdout, line_terminator);
+	}
+	strbuf_release(&line);
+	strbuf_release(&unquoted);
+
+	return 0;
+}
+
+static int sparse_checkout_check_rules(int argc, const char **argv, const char *prefix,
+				       struct repository *repo UNUSED)
+{
+	static struct option builtin_sparse_checkout_check_rules_options[] = {
+		OPT_BOOL('z', NULL, &check_rules_opts.null_termination,
+			 N_("terminate input and output files by a NUL character")),
+		OPT_BOOL(0, "cone", &check_rules_opts.cone_mode,
+			 N_("when used with --rules-file interpret patterns as cone mode patterns")),
+		OPT_FILENAME(0, "rules-file", &check_rules_opts.rules_file,
+			 N_("use patterns in <file> instead of the current ones.")),
+		OPT_END(),
+	};
+
+	FILE *fp;
+	int ret;
+	struct pattern_list pl = {0};
+	char *sparse_filename;
+	check_rules_opts.cone_mode = -1;
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_sparse_checkout_check_rules_options,
+			     builtin_sparse_checkout_check_rules_usage, 0);
+
+	if (check_rules_opts.rules_file && check_rules_opts.cone_mode < 0)
+		check_rules_opts.cone_mode = 1;
+
+	update_cone_mode(&check_rules_opts.cone_mode);
+	pl.use_cone_patterns = core_sparse_checkout_cone;
+	if (check_rules_opts.rules_file) {
+		fp = xfopen(check_rules_opts.rules_file, "r");
+		add_patterns_from_input(&pl, argc, argv, fp);
+		fclose(fp);
+	} else {
+		sparse_filename = get_sparse_checkout_filename();
+		if (add_patterns_from_file_to_list(sparse_filename, "", 0, &pl,
+						   NULL, 0))
+			die(_("unable to load existing sparse-checkout patterns"));
+		free(sparse_filename);
+	}
+
+	ret = check_rules(&pl, check_rules_opts.null_termination);
+	clear_pattern_list(&pl);
+	free(check_rules_opts.rules_file);
+	return ret;
+}
+
+int cmd_sparse_checkout(int argc,
+			const char **argv,
+			const char *prefix,
+			struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option builtin_sparse_checkout_options[] = {
+		OPT_SUBCOMMAND("list", &fn, sparse_checkout_list),
+		OPT_SUBCOMMAND("init", &fn, sparse_checkout_init),
+		OPT_SUBCOMMAND("set", &fn, sparse_checkout_set),
+		OPT_SUBCOMMAND("add", &fn, sparse_checkout_add),
+		OPT_SUBCOMMAND("reapply", &fn, sparse_checkout_reapply),
+		OPT_SUBCOMMAND("disable", &fn, sparse_checkout_disable),
+		OPT_SUBCOMMAND("check-rules", &fn, sparse_checkout_check_rules),
+		OPT_END(),
+	};
+
+	argc = parse_options(argc, argv, prefix,
+			     builtin_sparse_checkout_options,
+			     builtin_sparse_checkout_usage, 0);
+
+	git_config(git_default_config, NULL);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/stash.c b/builtin/stash.c
new file mode 100644
index 0000000000..dbaa999cf1
--- /dev/null
+++ b/builtin/stash.c
@@ -0,0 +1,1948 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "abspath.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "refs.h"
+#include "lockfile.h"
+#include "cache-tree.h"
+#include "unpack-trees.h"
+#include "merge-recursive.h"
+#include "merge-ort-wrappers.h"
+#include "strvec.h"
+#include "run-command.h"
+#include "dir.h"
+#include "entry.h"
+#include "preload-index.h"
+#include "read-cache.h"
+#include "repository.h"
+#include "rerere.h"
+#include "revision.h"
+#include "setup.h"
+#include "sparse-index.h"
+#include "log-tree.h"
+#include "diffcore.h"
+#include "reflog.h"
+#include "add-interactive.h"
+
+#define INCLUDE_ALL_FILES 2
+
+#define BUILTIN_STASH_LIST_USAGE \
+	N_("git stash list [<log-options>]")
+#define BUILTIN_STASH_SHOW_USAGE \
+	N_("git stash show [-u | --include-untracked | --only-untracked] [<diff-options>] [<stash>]")
+#define BUILTIN_STASH_DROP_USAGE \
+	N_("git stash drop [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_POP_USAGE \
+	N_("git stash pop [--index] [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_APPLY_USAGE \
+	N_("git stash apply [--index] [-q | --quiet] [<stash>]")
+#define BUILTIN_STASH_BRANCH_USAGE \
+	N_("git stash branch <branchname> [<stash>]")
+#define BUILTIN_STASH_STORE_USAGE \
+	N_("git stash store [(-m | --message) <message>] [-q | --quiet] <commit>")
+#define BUILTIN_STASH_PUSH_USAGE \
+	N_("git stash [push [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
+	   "          [-u | --include-untracked] [-a | --all] [(-m | --message) <message>]\n" \
+	   "          [--pathspec-from-file=<file> [--pathspec-file-nul]]\n" \
+	   "          [--] [<pathspec>...]]")
+#define BUILTIN_STASH_SAVE_USAGE \
+	N_("git stash save [-p | --patch] [-S | --staged] [-k | --[no-]keep-index] [-q | --quiet]\n" \
+	   "          [-u | --include-untracked] [-a | --all] [<message>]")
+#define BUILTIN_STASH_CREATE_USAGE \
+	N_("git stash create [<message>]")
+#define BUILTIN_STASH_CLEAR_USAGE \
+	"git stash clear"
+
+static const char * const git_stash_usage[] = {
+	BUILTIN_STASH_LIST_USAGE,
+	BUILTIN_STASH_SHOW_USAGE,
+	BUILTIN_STASH_DROP_USAGE,
+	BUILTIN_STASH_POP_USAGE,
+	BUILTIN_STASH_APPLY_USAGE,
+	BUILTIN_STASH_BRANCH_USAGE,
+	BUILTIN_STASH_PUSH_USAGE,
+	BUILTIN_STASH_SAVE_USAGE,
+	BUILTIN_STASH_CLEAR_USAGE,
+	BUILTIN_STASH_CREATE_USAGE,
+	BUILTIN_STASH_STORE_USAGE,
+	NULL
+};
+
+static const char * const git_stash_list_usage[] = {
+	BUILTIN_STASH_LIST_USAGE,
+	NULL
+};
+
+static const char * const git_stash_show_usage[] = {
+	BUILTIN_STASH_SHOW_USAGE,
+	NULL
+};
+
+static const char * const git_stash_drop_usage[] = {
+	BUILTIN_STASH_DROP_USAGE,
+	NULL
+};
+
+static const char * const git_stash_pop_usage[] = {
+	BUILTIN_STASH_POP_USAGE,
+	NULL
+};
+
+static const char * const git_stash_apply_usage[] = {
+	BUILTIN_STASH_APPLY_USAGE,
+	NULL
+};
+
+static const char * const git_stash_branch_usage[] = {
+	BUILTIN_STASH_BRANCH_USAGE,
+	NULL
+};
+
+static const char * const git_stash_clear_usage[] = {
+	BUILTIN_STASH_CLEAR_USAGE,
+	NULL
+};
+
+static const char * const git_stash_store_usage[] = {
+	BUILTIN_STASH_STORE_USAGE,
+	NULL
+};
+
+static const char * const git_stash_push_usage[] = {
+	BUILTIN_STASH_PUSH_USAGE,
+	NULL
+};
+
+static const char * const git_stash_save_usage[] = {
+	BUILTIN_STASH_SAVE_USAGE,
+	NULL
+};
+
+static const char ref_stash[] = "refs/stash";
+static struct strbuf stash_index_path = STRBUF_INIT;
+
+/*
+ * w_commit is set to the commit containing the working tree
+ * b_commit is set to the base commit
+ * i_commit is set to the commit containing the index tree
+ * u_commit is set to the commit containing the untracked files tree
+ * w_tree is set to the working tree
+ * b_tree is set to the base tree
+ * i_tree is set to the index tree
+ * u_tree is set to the untracked files tree
+ */
+struct stash_info {
+	struct object_id w_commit;
+	struct object_id b_commit;
+	struct object_id i_commit;
+	struct object_id u_commit;
+	struct object_id w_tree;
+	struct object_id b_tree;
+	struct object_id i_tree;
+	struct object_id u_tree;
+	struct strbuf revision;
+	int is_stash_ref;
+	int has_u;
+};
+
+#define STASH_INFO_INIT { \
+	.revision = STRBUF_INIT, \
+}
+
+static void free_stash_info(struct stash_info *info)
+{
+	strbuf_release(&info->revision);
+}
+
+static void assert_stash_like(struct stash_info *info, const char *revision)
+{
+	if (get_oidf(&info->b_commit, "%s^1", revision) ||
+	    get_oidf(&info->w_tree, "%s:", revision) ||
+	    get_oidf(&info->b_tree, "%s^1:", revision) ||
+	    get_oidf(&info->i_tree, "%s^2:", revision))
+		die(_("'%s' is not a stash-like commit"), revision);
+}
+
+static int get_stash_info(struct stash_info *info, int argc, const char **argv)
+{
+	int ret;
+	char *end_of_rev;
+	char *expanded_ref;
+	const char *revision;
+	const char *commit = NULL;
+	struct object_id dummy;
+	struct strbuf symbolic = STRBUF_INIT;
+
+	if (argc > 1) {
+		int i;
+		struct strbuf refs_msg = STRBUF_INIT;
+
+		for (i = 0; i < argc; i++)
+			strbuf_addf(&refs_msg, " '%s'", argv[i]);
+
+		fprintf_ln(stderr, _("Too many revisions specified:%s"),
+			   refs_msg.buf);
+		strbuf_release(&refs_msg);
+
+		return -1;
+	}
+
+	if (argc == 1)
+		commit = argv[0];
+
+	if (!commit) {
+		if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash)) {
+			fprintf_ln(stderr, _("No stash entries found."));
+			return -1;
+		}
+
+		strbuf_addf(&info->revision, "%s@{0}", ref_stash);
+	} else if (strspn(commit, "0123456789") == strlen(commit)) {
+		strbuf_addf(&info->revision, "%s@{%s}", ref_stash, commit);
+	} else {
+		strbuf_addstr(&info->revision, commit);
+	}
+
+	revision = info->revision.buf;
+
+	if (repo_get_oid(the_repository, revision, &info->w_commit))
+		return error(_("%s is not a valid reference"), revision);
+
+	assert_stash_like(info, revision);
+
+	info->has_u = !get_oidf(&info->u_tree, "%s^3:", revision);
+
+	end_of_rev = strchrnul(revision, '@');
+	strbuf_add(&symbolic, revision, end_of_rev - revision);
+
+	ret = repo_dwim_ref(the_repository, symbolic.buf, symbolic.len,
+			    &dummy, &expanded_ref, 0);
+	strbuf_release(&symbolic);
+	switch (ret) {
+	case 0: /* Not found, but valid ref */
+		info->is_stash_ref = 0;
+		break;
+	case 1:
+		info->is_stash_ref = !strcmp(expanded_ref, ref_stash);
+		break;
+	default: /* Invalid or ambiguous */
+		break;
+	}
+
+	free(expanded_ref);
+	return !(ret == 0 || ret == 1);
+}
+
+static int do_clear_stash(void)
+{
+	struct object_id obj;
+	if (repo_get_oid(the_repository, ref_stash, &obj))
+		return 0;
+
+	return refs_delete_ref(get_main_ref_store(the_repository), NULL,
+			       ref_stash, &obj, 0);
+}
+
+static int clear_stash(int argc, const char **argv, const char *prefix,
+		       struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_stash_clear_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (argc)
+		return error(_("git stash clear with arguments is "
+			       "unimplemented"));
+
+	return do_clear_stash();
+}
+
+static int reset_tree(struct object_id *i_tree, int update, int reset)
+{
+	int nr_trees = 1;
+	struct unpack_trees_options opts;
+	struct tree_desc t[MAX_UNPACK_TREES];
+	struct tree *tree;
+	struct lock_file lock_file = LOCK_INIT;
+
+	repo_read_index_preload(the_repository, NULL, 0);
+	if (refresh_index(the_repository->index, REFRESH_QUIET, NULL, NULL, NULL))
+		return -1;
+
+	repo_hold_locked_index(the_repository, &lock_file, LOCK_DIE_ON_ERROR);
+
+	memset(&opts, 0, sizeof(opts));
+
+	tree = parse_tree_indirect(i_tree);
+	if (parse_tree(tree))
+		return -1;
+
+	init_tree_desc(t, &tree->object.oid, tree->buffer, tree->size);
+
+	opts.head_idx = 1;
+	opts.src_index = the_repository->index;
+	opts.dst_index = the_repository->index;
+	opts.merge = 1;
+	opts.reset = reset ? UNPACK_RESET_PROTECT_UNTRACKED : 0;
+	opts.update = update;
+	if (update)
+		opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
+	opts.fn = oneway_merge;
+
+	if (unpack_trees(nr_trees, t, &opts))
+		return -1;
+
+	if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+		return error(_("unable to write new index file"));
+
+	return 0;
+}
+
+static int diff_tree_binary(struct strbuf *out, struct object_id *w_commit)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+	const char *w_commit_hex = oid_to_hex(w_commit);
+
+	/*
+	 * Diff-tree would not be very hard to replace with a native function,
+	 * however it should be done together with apply_cached.
+	 */
+	cp.git_cmd = 1;
+	strvec_pushl(&cp.args, "diff-tree", "--binary", NULL);
+	strvec_pushf(&cp.args, "%s^2^..%s^2", w_commit_hex, w_commit_hex);
+
+	return pipe_command(&cp, NULL, 0, out, 0, NULL, 0);
+}
+
+static int apply_cached(struct strbuf *out)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	/*
+	 * Apply currently only reads either from stdin or a file, thus
+	 * apply_all_patches would have to be updated to optionally take a
+	 * buffer.
+	 */
+	cp.git_cmd = 1;
+	strvec_pushl(&cp.args, "apply", "--cached", NULL);
+	return pipe_command(&cp, out->buf, out->len, NULL, 0, NULL, 0);
+}
+
+static int reset_head(void)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	/*
+	 * Reset is overall quite simple, however there is no current public
+	 * API for resetting.
+	 */
+	cp.git_cmd = 1;
+	strvec_pushl(&cp.args, "reset", "--quiet", "--refresh", NULL);
+
+	return run_command(&cp);
+}
+
+static int is_path_a_directory(const char *path)
+{
+	/*
+	 * This function differs from abspath.c:is_directory() in that
+	 * here we use lstat() instead of stat(); we do not want to
+	 * follow symbolic links here.
+	 */
+	struct stat st;
+	return (!lstat(path, &st) && S_ISDIR(st.st_mode));
+}
+
+static void add_diff_to_buf(struct diff_queue_struct *q,
+			    struct diff_options *options UNUSED,
+			    void *data)
+{
+	int i;
+
+	for (i = 0; i < q->nr; i++) {
+		if (is_path_a_directory(q->queue[i]->one->path))
+			continue;
+
+		strbuf_addstr(data, q->queue[i]->one->path);
+
+		/* NUL-terminate: will be fed to update-index -z */
+		strbuf_addch(data, '\0');
+	}
+}
+
+static int restore_untracked(struct object_id *u_tree)
+{
+	int res;
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	/*
+	 * We need to run restore files from a given index, but without
+	 * affecting the current index, so we use GIT_INDEX_FILE with
+	 * run_command to fork processes that will not interfere.
+	 */
+	cp.git_cmd = 1;
+	strvec_push(&cp.args, "read-tree");
+	strvec_push(&cp.args, oid_to_hex(u_tree));
+	strvec_pushf(&cp.env, "GIT_INDEX_FILE=%s",
+		     stash_index_path.buf);
+	if (run_command(&cp)) {
+		remove_path(stash_index_path.buf);
+		return -1;
+	}
+
+	child_process_init(&cp);
+	cp.git_cmd = 1;
+	strvec_pushl(&cp.args, "checkout-index", "--all", NULL);
+	strvec_pushf(&cp.env, "GIT_INDEX_FILE=%s",
+		     stash_index_path.buf);
+
+	res = run_command(&cp);
+	remove_path(stash_index_path.buf);
+	return res;
+}
+
+static void unstage_changes_unless_new(struct object_id *orig_tree)
+{
+	/*
+	 * When we enter this function, there has been a clean merge of
+	 * relevant trees, and the merge logic always stages whatever merges
+	 * cleanly.  We want to unstage those changes, unless it corresponds
+	 * to a file that didn't exist as of orig_tree.
+	 *
+	 * However, if any SKIP_WORKTREE path is modified relative to
+	 * orig_tree, then we want to clear the SKIP_WORKTREE bit and write
+	 * it to the worktree before unstaging.
+	 */
+
+	struct checkout state = CHECKOUT_INIT;
+	struct diff_options diff_opts;
+	struct lock_file lock = LOCK_INIT;
+	int i;
+
+	/* If any entries have skip_worktree set, we'll have to check 'em out */
+	state.force = 1;
+	state.quiet = 1;
+	state.refresh_cache = 1;
+	state.istate = the_repository->index;
+
+	/*
+	 * Step 1: get a difference between orig_tree (which corresponding
+	 * to the index before a merge was run) and the current index
+	 * (reflecting the changes brought in by the merge).
+	 */
+	repo_diff_setup(the_repository, &diff_opts);
+	diff_opts.flags.recursive = 1;
+	diff_opts.detect_rename = 0;
+	diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
+	diff_setup_done(&diff_opts);
+
+	do_diff_cache(orig_tree, &diff_opts);
+	diffcore_std(&diff_opts);
+
+	/* Iterate over the paths that changed due to the merge... */
+	for (i = 0; i < diff_queued_diff.nr; i++) {
+		struct diff_filepair *p;
+		struct cache_entry *ce;
+		int pos;
+
+		/* Look up the path's position in the current index. */
+		p = diff_queued_diff.queue[i];
+		pos = index_name_pos(the_repository->index, p->two->path,
+				     strlen(p->two->path));
+
+		/*
+		 * Step 2: Place changes in the working tree
+		 *
+		 * Stash is about restoring changes *to the working tree*.
+		 * So if the merge successfully got a new version of some
+		 * path, but left it out of the working tree, then clear the
+		 * SKIP_WORKTREE bit and write it to the working tree.
+		 */
+		if (pos >= 0 && ce_skip_worktree(the_repository->index->cache[pos])) {
+			struct stat st;
+
+			ce = the_repository->index->cache[pos];
+			if (!lstat(ce->name, &st)) {
+				/* Conflicting path present; relocate it */
+				struct strbuf new_path = STRBUF_INIT;
+				int fd;
+
+				strbuf_addf(&new_path,
+					    "%s.stash.XXXXXX", ce->name);
+				fd = xmkstemp(new_path.buf);
+				close(fd);
+				printf(_("WARNING: Untracked file in way of "
+					 "tracked file!  Renaming\n "
+					 "           %s -> %s\n"
+					 "         to make room.\n"),
+				       ce->name, new_path.buf);
+				if (rename(ce->name, new_path.buf))
+					die("Failed to move %s to %s",
+					    ce->name, new_path.buf);
+				strbuf_release(&new_path);
+			}
+			checkout_entry(ce, &state, NULL, NULL);
+			ce->ce_flags &= ~CE_SKIP_WORKTREE;
+		}
+
+		/*
+		 * Step 3: "unstage" changes, as long as they are still tracked
+		 */
+		if (p->one->oid_valid) {
+			/*
+			 * Path existed in orig_tree; restore index entry
+			 * from that tree in order to "unstage" the changes.
+			 */
+			int option = ADD_CACHE_OK_TO_REPLACE;
+			if (pos < 0)
+				option = ADD_CACHE_OK_TO_ADD;
+
+			ce = make_cache_entry(the_repository->index,
+					      p->one->mode,
+					      &p->one->oid,
+					      p->one->path,
+					      0, 0);
+			add_index_entry(the_repository->index, ce, option);
+		}
+	}
+	diff_flush(&diff_opts);
+
+	/*
+	 * Step 4: write the new index to disk
+	 */
+	repo_hold_locked_index(the_repository, &lock, LOCK_DIE_ON_ERROR);
+	if (write_locked_index(the_repository->index, &lock,
+			       COMMIT_LOCK | SKIP_IF_UNCHANGED))
+		die(_("could not write index"));
+}
+
+static int do_apply_stash(const char *prefix, struct stash_info *info,
+			  int index, int quiet)
+{
+	int clean, ret;
+	int has_index = index;
+	struct merge_options o;
+	struct object_id c_tree;
+	struct object_id index_tree;
+	struct tree *head, *merge, *merge_base;
+	struct lock_file lock = LOCK_INIT;
+
+	repo_read_index_preload(the_repository, NULL, 0);
+	if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+					 NULL, NULL, NULL))
+		return error(_("could not write index"));
+
+	if (write_index_as_tree(&c_tree, the_repository->index,
+				repo_get_index_file(the_repository), 0, NULL))
+		return error(_("cannot apply a stash in the middle of a merge"));
+
+	if (index) {
+		if (oideq(&info->b_tree, &info->i_tree) ||
+		    oideq(&c_tree, &info->i_tree)) {
+			has_index = 0;
+		} else {
+			struct strbuf out = STRBUF_INIT;
+
+			if (diff_tree_binary(&out, &info->w_commit)) {
+				strbuf_release(&out);
+				return error(_("could not generate diff %s^!."),
+					     oid_to_hex(&info->w_commit));
+			}
+
+			ret = apply_cached(&out);
+			strbuf_release(&out);
+			if (ret)
+				return error(_("conflicts in index. "
+					       "Try without --index."));
+
+			discard_index(the_repository->index);
+			repo_read_index(the_repository);
+			if (write_index_as_tree(&index_tree, the_repository->index,
+						repo_get_index_file(the_repository), 0, NULL))
+				return error(_("could not save index tree"));
+
+			reset_head();
+			discard_index(the_repository->index);
+			repo_read_index(the_repository);
+		}
+	}
+
+	init_ui_merge_options(&o, the_repository);
+
+	o.branch1 = "Updated upstream";
+	o.branch2 = "Stashed changes";
+	o.ancestor = "Stash base";
+
+	if (oideq(&info->b_tree, &c_tree))
+		o.branch1 = "Version stash was based on";
+
+	if (quiet)
+		o.verbosity = 0;
+
+	if (o.verbosity >= 3)
+		printf_ln(_("Merging %s with %s"), o.branch1, o.branch2);
+
+	head = lookup_tree(o.repo, &c_tree);
+	merge = lookup_tree(o.repo, &info->w_tree);
+	merge_base = lookup_tree(o.repo, &info->b_tree);
+
+	repo_hold_locked_index(o.repo, &lock, LOCK_DIE_ON_ERROR);
+	clean = merge_ort_nonrecursive(&o, head, merge, merge_base);
+
+	/*
+	 * If 'clean' >= 0, reverse the value for 'ret' so 'ret' is 0 when the
+	 * merge was clean, and nonzero if the merge was unclean or encountered
+	 * an error.
+	 */
+	ret = clean >= 0 ? !clean : clean;
+
+	if (ret < 0)
+		rollback_lock_file(&lock);
+	else if (write_locked_index(o.repo->index, &lock,
+				      COMMIT_LOCK | SKIP_IF_UNCHANGED))
+		ret = error(_("could not write index"));
+
+	if (ret) {
+		repo_rerere(the_repository, 0);
+
+		if (index)
+			fprintf_ln(stderr, _("Index was not unstashed."));
+
+		goto restore_untracked;
+	}
+
+	if (has_index) {
+		if (reset_tree(&index_tree, 0, 0))
+			ret = -1;
+	} else {
+		unstage_changes_unless_new(&c_tree);
+	}
+
+restore_untracked:
+	if (info->has_u && restore_untracked(&info->u_tree))
+		ret = error(_("could not restore untracked files from stash"));
+
+	if (!quiet) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+
+		/*
+		 * Status is quite simple and could be replaced with calls to
+		 * wt_status in the future, but it adds complexities which may
+		 * require more tests.
+		 */
+		cp.git_cmd = 1;
+		cp.dir = prefix;
+		strvec_pushf(&cp.env, GIT_WORK_TREE_ENVIRONMENT"=%s",
+			     absolute_path(repo_get_work_tree(the_repository)));
+		strvec_pushf(&cp.env, GIT_DIR_ENVIRONMENT"=%s",
+			     absolute_path(repo_get_git_dir(the_repository)));
+		strvec_push(&cp.args, "status");
+		run_command(&cp);
+	}
+
+	return ret;
+}
+
+static int apply_stash(int argc, const char **argv, const char *prefix,
+		       struct repository *repo UNUSED)
+{
+	int ret = -1;
+	int quiet = 0;
+	int index = 0;
+	struct stash_info info = STASH_INFO_INIT;
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("be quiet, only report errors")),
+		OPT_BOOL(0, "index", &index,
+			 N_("attempt to recreate the index")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_stash_apply_usage, 0);
+
+	if (get_stash_info(&info, argc, argv))
+		goto cleanup;
+
+	ret = do_apply_stash(prefix, &info, index, quiet);
+cleanup:
+	free_stash_info(&info);
+	return ret;
+}
+
+static int reject_reflog_ent(struct object_id *ooid UNUSED,
+			     struct object_id *noid UNUSED,
+			     const char *email UNUSED,
+			     timestamp_t timestamp UNUSED,
+			     int tz UNUSED, const char *message UNUSED,
+			     void *cb_data UNUSED)
+{
+	return 1;
+}
+
+static int reflog_is_empty(const char *refname)
+{
+	return !refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+					 refname, reject_reflog_ent, NULL);
+}
+
+static int do_drop_stash(struct stash_info *info, int quiet)
+{
+	if (!reflog_delete(info->revision.buf,
+			   EXPIRE_REFLOGS_REWRITE | EXPIRE_REFLOGS_UPDATE_REF,
+			   0)) {
+		if (!quiet)
+			printf_ln(_("Dropped %s (%s)"), info->revision.buf,
+				  oid_to_hex(&info->w_commit));
+	} else {
+		return error(_("%s: Could not drop stash entry"),
+			     info->revision.buf);
+	}
+
+	if (reflog_is_empty(ref_stash))
+		do_clear_stash();
+
+	return 0;
+}
+
+static int get_stash_info_assert(struct stash_info *info, int argc,
+				 const char **argv)
+{
+	int ret = get_stash_info(info, argc, argv);
+
+	if (ret < 0)
+		return ret;
+
+	if (!info->is_stash_ref)
+		return error(_("'%s' is not a stash reference"), info->revision.buf);
+
+	return 0;
+}
+
+static int drop_stash(int argc, const char **argv, const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	int ret = -1;
+	int quiet = 0;
+	struct stash_info info = STASH_INFO_INIT;
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("be quiet, only report errors")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_stash_drop_usage, 0);
+
+	if (get_stash_info_assert(&info, argc, argv))
+		goto cleanup;
+
+	ret = do_drop_stash(&info, quiet);
+cleanup:
+	free_stash_info(&info);
+	return ret;
+}
+
+static int pop_stash(int argc, const char **argv, const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	int ret = -1;
+	int index = 0;
+	int quiet = 0;
+	struct stash_info info = STASH_INFO_INIT;
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("be quiet, only report errors")),
+		OPT_BOOL(0, "index", &index,
+			 N_("attempt to recreate the index")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_stash_pop_usage, 0);
+
+	if (get_stash_info_assert(&info, argc, argv))
+		goto cleanup;
+
+	if ((ret = do_apply_stash(prefix, &info, index, quiet)))
+		printf_ln(_("The stash entry is kept in case "
+			    "you need it again."));
+	else
+		ret = do_drop_stash(&info, quiet);
+
+cleanup:
+	free_stash_info(&info);
+	return ret;
+}
+
+static int branch_stash(int argc, const char **argv, const char *prefix,
+			struct repository *repo UNUSED)
+{
+	int ret = -1;
+	const char *branch = NULL;
+	struct stash_info info = STASH_INFO_INIT;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	struct option options[] = {
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_stash_branch_usage, 0);
+
+	if (!argc) {
+		fprintf_ln(stderr, _("No branch name specified"));
+		return -1;
+	}
+
+	branch = argv[0];
+
+	if (get_stash_info(&info, argc - 1, argv + 1))
+		goto cleanup;
+
+	cp.git_cmd = 1;
+	strvec_pushl(&cp.args, "checkout", "-b", NULL);
+	strvec_push(&cp.args, branch);
+	strvec_push(&cp.args, oid_to_hex(&info.b_commit));
+	ret = run_command(&cp);
+	if (!ret)
+		ret = do_apply_stash(prefix, &info, 1, 0);
+	if (!ret && info.is_stash_ref)
+		ret = do_drop_stash(&info, 0);
+
+cleanup:
+	free_stash_info(&info);
+	return ret;
+}
+
+static int list_stash(int argc, const char **argv, const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+	struct option options[] = {
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_stash_list_usage,
+			     PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+	if (!refs_ref_exists(get_main_ref_store(the_repository), ref_stash))
+		return 0;
+
+	cp.git_cmd = 1;
+	strvec_pushl(&cp.args, "log", "--format=%gd: %gs", "-g",
+		     "--first-parent", NULL);
+	strvec_pushv(&cp.args, argv);
+	strvec_push(&cp.args, ref_stash);
+	strvec_push(&cp.args, "--");
+	return run_command(&cp);
+}
+
+static int show_stat = 1;
+static int show_patch;
+static int show_include_untracked;
+
+static int git_stash_config(const char *var, const char *value,
+			    const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "stash.showstat")) {
+		show_stat = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "stash.showpatch")) {
+		show_patch = git_config_bool(var, value);
+		return 0;
+	}
+	if (!strcmp(var, "stash.showincludeuntracked")) {
+		show_include_untracked = git_config_bool(var, value);
+		return 0;
+	}
+	return git_diff_basic_config(var, value, ctx, cb);
+}
+
+static void diff_include_untracked(const struct stash_info *info, struct diff_options *diff_opt)
+{
+	const struct object_id *oid[] = { &info->w_commit, &info->u_tree };
+	struct tree *tree[ARRAY_SIZE(oid)];
+	struct tree_desc tree_desc[ARRAY_SIZE(oid)];
+	struct unpack_trees_options unpack_tree_opt = { 0 };
+
+	for (size_t i = 0; i < ARRAY_SIZE(oid); i++) {
+		tree[i] = parse_tree_indirect(oid[i]);
+		if (parse_tree(tree[i]) < 0)
+			die(_("failed to parse tree"));
+		init_tree_desc(&tree_desc[i], &tree[i]->object.oid,
+			       tree[i]->buffer, tree[i]->size);
+	}
+
+	unpack_tree_opt.head_idx = -1;
+	unpack_tree_opt.src_index = the_repository->index;
+	unpack_tree_opt.dst_index = the_repository->index;
+	unpack_tree_opt.merge = 1;
+	unpack_tree_opt.fn = stash_worktree_untracked_merge;
+
+	if (unpack_trees(ARRAY_SIZE(tree_desc), tree_desc, &unpack_tree_opt))
+		die(_("failed to unpack trees"));
+
+	do_diff_cache(&info->b_commit, diff_opt);
+}
+
+static int show_stash(int argc, const char **argv, const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	int i;
+	int ret = -1;
+	struct stash_info info = STASH_INFO_INIT;
+	struct rev_info rev;
+	struct strvec stash_args = STRVEC_INIT;
+	struct strvec revision_args = STRVEC_INIT;
+	enum {
+		UNTRACKED_NONE,
+		UNTRACKED_INCLUDE,
+		UNTRACKED_ONLY
+	} show_untracked = show_include_untracked ? UNTRACKED_INCLUDE : UNTRACKED_NONE;
+	struct option options[] = {
+		OPT_SET_INT('u', "include-untracked", &show_untracked,
+			    N_("include untracked files in the stash"),
+			    UNTRACKED_INCLUDE),
+		OPT_SET_INT_F(0, "only-untracked", &show_untracked,
+			      N_("only show untracked files in the stash"),
+			      UNTRACKED_ONLY, PARSE_OPT_NONEG),
+		OPT_END()
+	};
+	int do_usage = 0;
+
+	init_diff_ui_defaults();
+	git_config(git_diff_ui_config, NULL);
+	repo_init_revisions(the_repository, &rev, prefix);
+
+	argc = parse_options(argc, argv, prefix, options, git_stash_show_usage,
+			     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN_OPT |
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	strvec_push(&revision_args, argv[0]);
+	for (i = 1; i < argc; i++) {
+		if (argv[i][0] != '-')
+			strvec_push(&stash_args, argv[i]);
+		else
+			strvec_push(&revision_args, argv[i]);
+	}
+
+	if (get_stash_info(&info, stash_args.nr, stash_args.v))
+		goto cleanup;
+
+	/*
+	 * The config settings are applied only if there are not passed
+	 * any options.
+	 */
+	if (revision_args.nr == 1) {
+		if (show_stat)
+			rev.diffopt.output_format = DIFF_FORMAT_DIFFSTAT;
+
+		if (show_patch)
+			rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+
+		if (!show_stat && !show_patch) {
+			ret = 0;
+			goto cleanup;
+		}
+	}
+
+	argc = setup_revisions(revision_args.nr, revision_args.v, &rev, NULL);
+	if (argc > 1)
+		goto usage;
+	if (!rev.diffopt.output_format) {
+		rev.diffopt.output_format = DIFF_FORMAT_PATCH;
+		diff_setup_done(&rev.diffopt);
+	}
+
+	rev.diffopt.flags.recursive = 1;
+	setup_diff_pager(&rev.diffopt);
+	switch (show_untracked) {
+	case UNTRACKED_NONE:
+		diff_tree_oid(&info.b_commit, &info.w_commit, "", &rev.diffopt);
+		break;
+	case UNTRACKED_ONLY:
+		if (info.has_u)
+			diff_root_tree_oid(&info.u_tree, "", &rev.diffopt);
+		break;
+	case UNTRACKED_INCLUDE:
+		if (info.has_u)
+			diff_include_untracked(&info, &rev.diffopt);
+		else
+			diff_tree_oid(&info.b_commit, &info.w_commit, "", &rev.diffopt);
+		break;
+	}
+	log_tree_diff_flush(&rev);
+
+	ret = diff_result_code(&rev);
+
+cleanup:
+	strvec_clear(&revision_args);
+	strvec_clear(&stash_args);
+	free_stash_info(&info);
+	release_revisions(&rev);
+	if (do_usage)
+		usage_with_options(git_stash_show_usage, options);
+	return ret;
+usage:
+	do_usage = 1;
+	goto cleanup;
+}
+
+static int do_store_stash(const struct object_id *w_commit, const char *stash_msg,
+			  int quiet)
+{
+	struct stash_info info;
+	char revision[GIT_MAX_HEXSZ];
+
+	oid_to_hex_r(revision, w_commit);
+	assert_stash_like(&info, revision);
+
+	if (!stash_msg)
+		stash_msg = "Created via \"git stash store\".";
+
+	if (refs_update_ref(get_main_ref_store(the_repository), stash_msg, ref_stash, w_commit, NULL,
+			    REF_FORCE_CREATE_REFLOG,
+			    quiet ? UPDATE_REFS_QUIET_ON_ERR :
+			    UPDATE_REFS_MSG_ON_ERR)) {
+		if (!quiet) {
+			fprintf_ln(stderr, _("Cannot update %s with %s"),
+				   ref_stash, oid_to_hex(w_commit));
+		}
+		return -1;
+	}
+
+	return 0;
+}
+
+static int store_stash(int argc, const char **argv, const char *prefix,
+		       struct repository *repo UNUSED)
+{
+	int quiet = 0;
+	const char *stash_msg = NULL;
+	struct object_id obj;
+	struct object_context dummy = {0};
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("be quiet")),
+		OPT_STRING('m', "message", &stash_msg, "message",
+			   N_("stash message")),
+		OPT_END()
+	};
+	int ret;
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_stash_store_usage,
+			     PARSE_OPT_KEEP_UNKNOWN_OPT);
+
+	if (argc != 1) {
+		if (!quiet)
+			fprintf_ln(stderr, _("\"git stash store\" requires one "
+					     "<commit> argument"));
+		return -1;
+	}
+
+	if (get_oid_with_context(the_repository,
+				 argv[0], quiet ? GET_OID_QUIETLY : 0, &obj,
+				 &dummy)) {
+		if (!quiet)
+			fprintf_ln(stderr, _("Cannot update %s with %s"),
+					     ref_stash, argv[0]);
+		ret = -1;
+		goto out;
+	}
+
+	ret = do_store_stash(&obj, stash_msg, quiet);
+
+out:
+	object_context_release(&dummy);
+	return ret;
+}
+
+static void add_pathspecs(struct strvec *args,
+			  const struct pathspec *ps) {
+	int i;
+
+	for (i = 0; i < ps->nr; i++)
+		strvec_push(args, ps->items[i].original);
+}
+
+/*
+ * `untracked_files` will be filled with the names of untracked files.
+ * The return value is:
+ *
+ * = 0 if there are not any untracked files
+ * > 0 if there are untracked files
+ */
+static int get_untracked_files(const struct pathspec *ps, int include_untracked,
+			       struct strbuf *untracked_files)
+{
+	int i;
+	int found = 0;
+	struct dir_struct dir = DIR_INIT;
+
+	if (include_untracked != INCLUDE_ALL_FILES)
+		setup_standard_excludes(&dir);
+
+	fill_directory(&dir, the_repository->index, ps);
+	for (i = 0; i < dir.nr; i++) {
+		struct dir_entry *ent = dir.entries[i];
+		found++;
+		strbuf_addstr(untracked_files, ent->name);
+		/* NUL-terminate: will be fed to update-index -z */
+		strbuf_addch(untracked_files, '\0');
+	}
+
+	dir_clear(&dir);
+	return found;
+}
+
+/*
+ * The return value of `check_changes_tracked_files()` can be:
+ *
+ * < 0 if there was an error
+ * = 0 if there are no changes.
+ * > 0 if there are changes.
+ */
+static int check_changes_tracked_files(const struct pathspec *ps)
+{
+	struct rev_info rev;
+	struct object_id dummy;
+	int ret = 0;
+
+	/* No initial commit. */
+	if (repo_get_oid(the_repository, "HEAD", &dummy))
+		return -1;
+
+	if (repo_read_index(the_repository) < 0)
+		return -1;
+
+	repo_init_revisions(the_repository, &rev, NULL);
+	copy_pathspec(&rev.prune_data, ps);
+
+	rev.diffopt.flags.quick = 1;
+	rev.diffopt.flags.ignore_submodules = 1;
+	rev.abbrev = 0;
+
+	add_head_to_pending(&rev);
+	diff_setup_done(&rev.diffopt);
+
+	run_diff_index(&rev, DIFF_INDEX_CACHED);
+	if (diff_result_code(&rev)) {
+		ret = 1;
+		goto done;
+	}
+
+	run_diff_files(&rev, 0);
+	if (diff_result_code(&rev)) {
+		ret = 1;
+		goto done;
+	}
+
+done:
+	release_revisions(&rev);
+	return ret;
+}
+
+/*
+ * The function will fill `untracked_files` with the names of untracked files
+ * It will return 1 if there were any changes and 0 if there were not.
+ */
+static int check_changes(const struct pathspec *ps, int include_untracked,
+			 struct strbuf *untracked_files)
+{
+	int ret = 0;
+	if (check_changes_tracked_files(ps))
+		ret = 1;
+
+	if (include_untracked && get_untracked_files(ps, include_untracked,
+						     untracked_files))
+		ret = 1;
+
+	return ret;
+}
+
+static int save_untracked_files(struct stash_info *info, struct strbuf *msg,
+				struct strbuf files)
+{
+	int ret = 0;
+	struct strbuf untracked_msg = STRBUF_INIT;
+	struct child_process cp_upd_index = CHILD_PROCESS_INIT;
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
+
+	cp_upd_index.git_cmd = 1;
+	strvec_pushl(&cp_upd_index.args, "update-index", "-z", "--add",
+		     "--remove", "--stdin", NULL);
+	strvec_pushf(&cp_upd_index.env, "GIT_INDEX_FILE=%s",
+			 stash_index_path.buf);
+
+	strbuf_addf(&untracked_msg, "untracked files on %s\n", msg->buf);
+	if (pipe_command(&cp_upd_index, files.buf, files.len, NULL, 0,
+			 NULL, 0)) {
+		ret = -1;
+		goto done;
+	}
+
+	if (write_index_as_tree(&info->u_tree, &istate, stash_index_path.buf, 0,
+				NULL)) {
+		ret = -1;
+		goto done;
+	}
+
+	if (commit_tree(untracked_msg.buf, untracked_msg.len,
+			&info->u_tree, NULL, &info->u_commit, NULL, NULL)) {
+		ret = -1;
+		goto done;
+	}
+
+done:
+	release_index(&istate);
+	strbuf_release(&untracked_msg);
+	remove_path(stash_index_path.buf);
+	return ret;
+}
+
+static int stash_staged(struct stash_info *info, struct strbuf *out_patch,
+			int quiet)
+{
+	int ret = 0;
+	struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
+
+	if (write_index_as_tree(&info->w_tree, &istate, the_repository->index_file,
+				0, NULL)) {
+		ret = -1;
+		goto done;
+	}
+
+	cp_diff_tree.git_cmd = 1;
+	strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "--binary",
+		     "-U1", "HEAD", oid_to_hex(&info->w_tree), "--", NULL);
+	if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) {
+		ret = -1;
+		goto done;
+	}
+
+	if (!out_patch->len) {
+		if (!quiet)
+			fprintf_ln(stderr, _("No staged changes"));
+		ret = 1;
+	}
+
+done:
+	release_index(&istate);
+	return ret;
+}
+
+static int stash_patch(struct stash_info *info, const struct pathspec *ps,
+		       struct strbuf *out_patch, int quiet)
+{
+	int ret = 0;
+	struct child_process cp_read_tree = CHILD_PROCESS_INIT;
+	struct child_process cp_diff_tree = CHILD_PROCESS_INIT;
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
+	char *old_index_env = NULL, *old_repo_index_file;
+
+	remove_path(stash_index_path.buf);
+
+	cp_read_tree.git_cmd = 1;
+	strvec_pushl(&cp_read_tree.args, "read-tree", "HEAD", NULL);
+	strvec_pushf(&cp_read_tree.env, "GIT_INDEX_FILE=%s",
+		     stash_index_path.buf);
+	if (run_command(&cp_read_tree)) {
+		ret = -1;
+		goto done;
+	}
+
+	/* Find out what the user wants. */
+	old_repo_index_file = the_repository->index_file;
+	the_repository->index_file = stash_index_path.buf;
+	old_index_env = xstrdup_or_null(getenv(INDEX_ENVIRONMENT));
+	setenv(INDEX_ENVIRONMENT, the_repository->index_file, 1);
+
+	ret = !!run_add_p(the_repository, ADD_P_STASH, NULL, ps);
+
+	the_repository->index_file = old_repo_index_file;
+	if (old_index_env && *old_index_env)
+		setenv(INDEX_ENVIRONMENT, old_index_env, 1);
+	else
+		unsetenv(INDEX_ENVIRONMENT);
+	FREE_AND_NULL(old_index_env);
+
+	/* State of the working tree. */
+	if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0,
+				NULL)) {
+		ret = -1;
+		goto done;
+	}
+
+	cp_diff_tree.git_cmd = 1;
+	strvec_pushl(&cp_diff_tree.args, "diff-tree", "-p", "-U1", "HEAD",
+		     oid_to_hex(&info->w_tree), "--", NULL);
+	if (pipe_command(&cp_diff_tree, NULL, 0, out_patch, 0, NULL, 0)) {
+		ret = -1;
+		goto done;
+	}
+
+	if (!out_patch->len) {
+		if (!quiet)
+			fprintf_ln(stderr, _("No changes selected"));
+		ret = 1;
+	}
+
+done:
+	release_index(&istate);
+	remove_path(stash_index_path.buf);
+	return ret;
+}
+
+static int stash_working_tree(struct stash_info *info, const struct pathspec *ps)
+{
+	int ret = 0;
+	struct rev_info rev;
+	struct child_process cp_upd_index = CHILD_PROCESS_INIT;
+	struct strbuf diff_output = STRBUF_INIT;
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
+
+	repo_init_revisions(the_repository, &rev, NULL);
+	copy_pathspec(&rev.prune_data, ps);
+
+	set_alternate_index_output(stash_index_path.buf);
+	if (reset_tree(&info->i_tree, 0, 0)) {
+		ret = -1;
+		goto done;
+	}
+	set_alternate_index_output(NULL);
+
+	rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = add_diff_to_buf;
+	rev.diffopt.format_callback_data = &diff_output;
+
+	if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
+		ret = -1;
+		goto done;
+	}
+
+	add_pending_object(&rev, parse_object(the_repository, &info->b_commit),
+			   "");
+	run_diff_index(&rev, 0);
+
+	cp_upd_index.git_cmd = 1;
+	strvec_pushl(&cp_upd_index.args, "update-index",
+		     "--ignore-skip-worktree-entries",
+		     "-z", "--add", "--remove", "--stdin", NULL);
+	strvec_pushf(&cp_upd_index.env, "GIT_INDEX_FILE=%s",
+		     stash_index_path.buf);
+
+	if (pipe_command(&cp_upd_index, diff_output.buf, diff_output.len,
+			 NULL, 0, NULL, 0)) {
+		ret = -1;
+		goto done;
+	}
+
+	if (write_index_as_tree(&info->w_tree, &istate, stash_index_path.buf, 0,
+				NULL)) {
+		ret = -1;
+		goto done;
+	}
+
+done:
+	release_index(&istate);
+	release_revisions(&rev);
+	strbuf_release(&diff_output);
+	remove_path(stash_index_path.buf);
+	return ret;
+}
+
+static int do_create_stash(const struct pathspec *ps, struct strbuf *stash_msg_buf,
+			   int include_untracked, int patch_mode, int only_staged,
+			   struct stash_info *info, struct strbuf *patch,
+			   int quiet)
+{
+	int ret = 0;
+	int flags = 0;
+	int untracked_commit_option = 0;
+	const char *head_short_sha1 = NULL;
+	const char *branch_ref = NULL;
+	const char *branch_name = "(no branch)";
+	struct commit *head_commit = NULL;
+	struct commit_list *parents = NULL;
+	struct strbuf msg = STRBUF_INIT;
+	struct strbuf commit_tree_label = STRBUF_INIT;
+	struct strbuf untracked_files = STRBUF_INIT;
+
+	prepare_fallback_ident("git stash", "git@stash");
+
+	repo_read_index_preload(the_repository, NULL, 0);
+	if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+					 NULL, NULL, NULL) < 0) {
+		ret = error(_("could not write index"));
+		goto done;
+	}
+
+	if (repo_get_oid(the_repository, "HEAD", &info->b_commit)) {
+		if (!quiet)
+			fprintf_ln(stderr, _("You do not have "
+					     "the initial commit yet"));
+		ret = -1;
+		goto done;
+	} else {
+		head_commit = lookup_commit(the_repository, &info->b_commit);
+	}
+
+	if (!check_changes(ps, include_untracked, &untracked_files)) {
+		ret = 1;
+		goto done;
+	}
+
+	branch_ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+					     "HEAD", 0, NULL, &flags);
+	if (flags & REF_ISSYMREF)
+		skip_prefix(branch_ref, "refs/heads/", &branch_name);
+	head_short_sha1 = repo_find_unique_abbrev(the_repository,
+						  &head_commit->object.oid,
+						  DEFAULT_ABBREV);
+	strbuf_addf(&msg, "%s: %s ", branch_name, head_short_sha1);
+	pp_commit_easy(CMIT_FMT_ONELINE, head_commit, &msg);
+
+	strbuf_addf(&commit_tree_label, "index on %s\n", msg.buf);
+	commit_list_insert(head_commit, &parents);
+	if (write_index_as_tree(&info->i_tree, the_repository->index,
+				repo_get_index_file(the_repository), 0, NULL) ||
+	    commit_tree(commit_tree_label.buf, commit_tree_label.len,
+			&info->i_tree, parents, &info->i_commit, NULL, NULL)) {
+		if (!quiet)
+			fprintf_ln(stderr, _("Cannot save the current "
+					     "index state"));
+		ret = -1;
+		goto done;
+	}
+
+	free_commit_list(parents);
+	parents = NULL;
+
+	if (include_untracked) {
+		if (save_untracked_files(info, &msg, untracked_files)) {
+			if (!quiet)
+				fprintf_ln(stderr, _("Cannot save "
+						     "the untracked files"));
+			ret = -1;
+			goto done;
+		}
+		untracked_commit_option = 1;
+	}
+	if (patch_mode) {
+		ret = stash_patch(info, ps, patch, quiet);
+		if (ret < 0) {
+			if (!quiet)
+				fprintf_ln(stderr, _("Cannot save the current "
+						     "worktree state"));
+			goto done;
+		} else if (ret > 0) {
+			goto done;
+		}
+	} else if (only_staged) {
+		ret = stash_staged(info, patch, quiet);
+		if (ret < 0) {
+			if (!quiet)
+				fprintf_ln(stderr, _("Cannot save the current "
+						     "staged state"));
+			goto done;
+		} else if (ret > 0) {
+			goto done;
+		}
+	} else {
+		if (stash_working_tree(info, ps)) {
+			if (!quiet)
+				fprintf_ln(stderr, _("Cannot save the current "
+						     "worktree state"));
+			ret = -1;
+			goto done;
+		}
+	}
+
+	if (!stash_msg_buf->len)
+		strbuf_addf(stash_msg_buf, "WIP on %s", msg.buf);
+	else
+		strbuf_insertf(stash_msg_buf, 0, "On %s: ", branch_name);
+
+	if (untracked_commit_option)
+		commit_list_insert(lookup_commit(the_repository,
+						 &info->u_commit),
+				   &parents);
+	commit_list_insert(lookup_commit(the_repository, &info->i_commit),
+			   &parents);
+	commit_list_insert(head_commit, &parents);
+
+	if (commit_tree(stash_msg_buf->buf, stash_msg_buf->len, &info->w_tree,
+			parents, &info->w_commit, NULL, NULL)) {
+		if (!quiet)
+			fprintf_ln(stderr, _("Cannot record "
+					     "working tree state"));
+		ret = -1;
+		goto done;
+	}
+
+done:
+	strbuf_release(&commit_tree_label);
+	strbuf_release(&msg);
+	strbuf_release(&untracked_files);
+	free_commit_list(parents);
+	return ret;
+}
+
+static int create_stash(int argc, const char **argv, const char *prefix UNUSED,
+			struct repository *repo UNUSED)
+{
+	int ret;
+	struct strbuf stash_msg_buf = STRBUF_INIT;
+	struct stash_info info = STASH_INFO_INIT;
+	struct pathspec ps;
+
+	/* Starting with argv[1], since argv[0] is "create" */
+	strbuf_join_argv(&stash_msg_buf, argc - 1, ++argv, ' ');
+
+	memset(&ps, 0, sizeof(ps));
+	if (!check_changes_tracked_files(&ps))
+		return 0;
+
+	ret = do_create_stash(&ps, &stash_msg_buf, 0, 0, 0, &info,
+			      NULL, 0);
+	if (!ret)
+		printf_ln("%s", oid_to_hex(&info.w_commit));
+
+	free_stash_info(&info);
+	strbuf_release(&stash_msg_buf);
+	return ret;
+}
+
+static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int quiet,
+			 int keep_index, int patch_mode, int include_untracked, int only_staged)
+{
+	int ret = 0;
+	struct stash_info info = STASH_INFO_INIT;
+	struct strbuf patch = STRBUF_INIT;
+	struct strbuf stash_msg_buf = STRBUF_INIT;
+	struct strbuf untracked_files = STRBUF_INIT;
+	struct strbuf out = STRBUF_INIT;
+
+	if (patch_mode && keep_index == -1)
+		keep_index = 1;
+
+	if (patch_mode && include_untracked) {
+		fprintf_ln(stderr, _("Can't use --patch and --include-untracked"
+				     " or --all at the same time"));
+		ret = -1;
+		goto done;
+	}
+
+	/* --patch overrides --staged */
+	if (patch_mode)
+		only_staged = 0;
+
+	if (only_staged && include_untracked) {
+		fprintf_ln(stderr, _("Can't use --staged and --include-untracked"
+				     " or --all at the same time"));
+		ret = -1;
+		goto done;
+	}
+
+	repo_read_index_preload(the_repository, NULL, 0);
+	if (!include_untracked && ps->nr) {
+		char *ps_matched = xcalloc(ps->nr, 1);
+
+		/* TODO: audit for interaction with sparse-index. */
+		ensure_full_index(the_repository->index);
+		for (size_t i = 0; i < the_repository->index->cache_nr; i++)
+			ce_path_match(the_repository->index, the_repository->index->cache[i], ps,
+				      ps_matched);
+
+		if (report_path_error(ps_matched, ps)) {
+			fprintf_ln(stderr, _("Did you forget to 'git add'?"));
+			ret = -1;
+			free(ps_matched);
+			goto done;
+		}
+		free(ps_matched);
+	}
+
+	if (repo_refresh_and_write_index(the_repository, REFRESH_QUIET, 0, 0,
+					 NULL, NULL, NULL)) {
+		ret = error(_("could not write index"));
+		goto done;
+	}
+
+	if (!check_changes(ps, include_untracked, &untracked_files)) {
+		if (!quiet)
+			printf_ln(_("No local changes to save"));
+		goto done;
+	}
+
+	if (!refs_reflog_exists(get_main_ref_store(the_repository), ref_stash) && do_clear_stash()) {
+		ret = -1;
+		if (!quiet)
+			fprintf_ln(stderr, _("Cannot initialize stash"));
+		goto done;
+	}
+
+	if (stash_msg)
+		strbuf_addstr(&stash_msg_buf, stash_msg);
+	if (do_create_stash(ps, &stash_msg_buf, include_untracked, patch_mode, only_staged,
+			    &info, &patch, quiet)) {
+		ret = -1;
+		goto done;
+	}
+
+	if (do_store_stash(&info.w_commit, stash_msg_buf.buf, 1)) {
+		ret = -1;
+		if (!quiet)
+			fprintf_ln(stderr, _("Cannot save the current status"));
+		goto done;
+	}
+
+	if (!quiet)
+		printf_ln(_("Saved working directory and index state %s"),
+			  stash_msg_buf.buf);
+
+	if (!(patch_mode || only_staged)) {
+		if (include_untracked && !ps->nr) {
+			struct child_process cp = CHILD_PROCESS_INIT;
+
+			cp.git_cmd = 1;
+			if (startup_info->original_cwd) {
+				cp.dir = startup_info->original_cwd;
+				strvec_pushf(&cp.env, "%s=%s",
+					     GIT_WORK_TREE_ENVIRONMENT,
+					     the_repository->worktree);
+			}
+			strvec_pushl(&cp.args, "clean", "--force",
+				     "--quiet", "-d", ":/", NULL);
+			if (include_untracked == INCLUDE_ALL_FILES)
+				strvec_push(&cp.args, "-x");
+			if (run_command(&cp)) {
+				ret = -1;
+				goto done;
+			}
+		}
+		discard_index(the_repository->index);
+		if (ps->nr) {
+			struct child_process cp_add = CHILD_PROCESS_INIT;
+			struct child_process cp_diff = CHILD_PROCESS_INIT;
+			struct child_process cp_apply = CHILD_PROCESS_INIT;
+
+			cp_add.git_cmd = 1;
+			strvec_push(&cp_add.args, "add");
+			if (!include_untracked)
+				strvec_push(&cp_add.args, "-u");
+			if (include_untracked == INCLUDE_ALL_FILES)
+				strvec_push(&cp_add.args, "--force");
+			strvec_push(&cp_add.args, "--");
+			add_pathspecs(&cp_add.args, ps);
+			if (run_command(&cp_add)) {
+				ret = -1;
+				goto done;
+			}
+
+			cp_diff.git_cmd = 1;
+			strvec_pushl(&cp_diff.args, "diff-index", "-p",
+				     "--cached", "--binary", "HEAD", "--",
+				     NULL);
+			add_pathspecs(&cp_diff.args, ps);
+			if (pipe_command(&cp_diff, NULL, 0, &out, 0, NULL, 0)) {
+				ret = -1;
+				goto done;
+			}
+
+			cp_apply.git_cmd = 1;
+			strvec_pushl(&cp_apply.args, "apply", "--index",
+				     "-R", NULL);
+			if (pipe_command(&cp_apply, out.buf, out.len, NULL, 0,
+					 NULL, 0)) {
+				ret = -1;
+				goto done;
+			}
+		} else {
+			struct child_process cp = CHILD_PROCESS_INIT;
+			cp.git_cmd = 1;
+			/* BUG: this nukes untracked files in the way */
+			strvec_pushl(&cp.args, "reset", "--hard", "-q",
+				     "--no-recurse-submodules", NULL);
+			if (run_command(&cp)) {
+				ret = -1;
+				goto done;
+			}
+		}
+
+		/*
+		 * When keeping staged entries, we need to reset the working
+		 * directory to match the state of our index. This can be
+		 * skipped when the index is the empty tree, because there is
+		 * nothing to reset in that case:
+		 *
+		 *   - When the index has any file, regardless of whether
+		 *     staged or not, the tree cannot be empty by definition
+		 *     and thus we enter the condition.
+		 *
+		 *   - When the index has no files, the only thing we need to
+		 *     care about is untracked files when `--include-untracked`
+		 *     is given. But as we already execute git-clean(1) further
+		 *     up to delete such untracked files we don't have to do
+		 *     anything here, either.
+		 *
+		 * We thus skip calling git-checkout(1) in this case, also
+		 * because running it on an empty tree will cause it to fail
+		 * due to the pathspec not matching anything.
+		 */
+		if (keep_index == 1 && !is_null_oid(&info.i_tree) &&
+		    !is_empty_tree_oid(&info.i_tree, the_repository->hash_algo)) {
+			struct child_process cp = CHILD_PROCESS_INIT;
+
+			cp.git_cmd = 1;
+			strvec_pushl(&cp.args, "checkout", "--no-overlay",
+				     oid_to_hex(&info.i_tree), "--", NULL);
+			if (!ps->nr)
+				strvec_push(&cp.args, ":/");
+			else
+				add_pathspecs(&cp.args, ps);
+			if (run_command(&cp)) {
+				ret = -1;
+				goto done;
+			}
+		}
+		goto done;
+	} else {
+		struct child_process cp = CHILD_PROCESS_INIT;
+
+		cp.git_cmd = 1;
+		strvec_pushl(&cp.args, "apply", "-R", NULL);
+
+		if (pipe_command(&cp, patch.buf, patch.len, NULL, 0, NULL, 0)) {
+			if (!quiet)
+				fprintf_ln(stderr, _("Cannot remove "
+						     "worktree changes"));
+			ret = -1;
+			goto done;
+		}
+
+		if (keep_index < 1) {
+			struct child_process cp = CHILD_PROCESS_INIT;
+
+			cp.git_cmd = 1;
+			strvec_pushl(&cp.args, "reset", "-q", "--refresh", "--",
+				     NULL);
+			add_pathspecs(&cp.args, ps);
+			if (run_command(&cp)) {
+				ret = -1;
+				goto done;
+			}
+		}
+		goto done;
+	}
+
+done:
+	strbuf_release(&patch);
+	strbuf_release(&out);
+	free_stash_info(&info);
+	strbuf_release(&stash_msg_buf);
+	strbuf_release(&untracked_files);
+	return ret;
+}
+
+static int push_stash(int argc, const char **argv, const char *prefix,
+		      int push_assumed)
+{
+	int force_assume = 0;
+	int keep_index = -1;
+	int only_staged = 0;
+	int patch_mode = 0;
+	int include_untracked = 0;
+	int quiet = 0;
+	int pathspec_file_nul = 0;
+	const char *stash_msg = NULL;
+	char *pathspec_from_file = NULL;
+	struct pathspec ps;
+	struct option options[] = {
+		OPT_BOOL('k', "keep-index", &keep_index,
+			 N_("keep index")),
+		OPT_BOOL('S', "staged", &only_staged,
+			 N_("stash staged changes only")),
+		OPT_BOOL('p', "patch", &patch_mode,
+			 N_("stash in patch mode")),
+		OPT__QUIET(&quiet, N_("quiet mode")),
+		OPT_BOOL('u', "include-untracked", &include_untracked,
+			 N_("include untracked files in stash")),
+		OPT_SET_INT('a', "all", &include_untracked,
+			    N_("include ignore files"), 2),
+		OPT_STRING('m', "message", &stash_msg, N_("message"),
+			   N_("stash message")),
+		OPT_PATHSPEC_FROM_FILE(&pathspec_from_file),
+		OPT_PATHSPEC_FILE_NUL(&pathspec_file_nul),
+		OPT_END()
+	};
+	int ret;
+
+	if (argc) {
+		force_assume = !strcmp(argv[0], "-p");
+		argc = parse_options(argc, argv, prefix, options,
+				     push_assumed ? git_stash_usage :
+				     git_stash_push_usage,
+				     PARSE_OPT_KEEP_DASHDASH);
+	}
+
+	if (argc) {
+		if (!strcmp(argv[0], "--")) {
+			argc--;
+			argv++;
+		} else if (push_assumed && !force_assume) {
+			die("subcommand wasn't specified; 'push' can't be assumed due to unexpected token '%s'",
+			    argv[0]);
+		}
+	}
+
+	parse_pathspec(&ps, 0, PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
+		       prefix, argv);
+
+	if (pathspec_from_file) {
+		if (patch_mode)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--patch");
+
+		if (only_staged)
+			die(_("options '%s' and '%s' cannot be used together"), "--pathspec-from-file", "--staged");
+
+		if (ps.nr)
+			die(_("'%s' and pathspec arguments cannot be used together"), "--pathspec-from-file");
+
+		parse_pathspec_file(&ps, 0,
+				    PATHSPEC_PREFER_FULL | PATHSPEC_PREFIX_ORIGIN,
+				    prefix, pathspec_from_file, pathspec_file_nul);
+	} else if (pathspec_file_nul) {
+		die(_("the option '%s' requires '%s'"), "--pathspec-file-nul", "--pathspec-from-file");
+	}
+
+	ret = do_push_stash(&ps, stash_msg, quiet, keep_index, patch_mode,
+			    include_untracked, only_staged);
+
+	clear_pathspec(&ps);
+	free(pathspec_from_file);
+	return ret;
+}
+
+static int push_stash_unassumed(int argc, const char **argv, const char *prefix,
+				struct repository *repo UNUSED)
+{
+	return push_stash(argc, argv, prefix, 0);
+}
+
+static int save_stash(int argc, const char **argv, const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	int keep_index = -1;
+	int only_staged = 0;
+	int patch_mode = 0;
+	int include_untracked = 0;
+	int quiet = 0;
+	int ret = 0;
+	const char *stash_msg = NULL;
+	struct pathspec ps;
+	struct strbuf stash_msg_buf = STRBUF_INIT;
+	struct option options[] = {
+		OPT_BOOL('k', "keep-index", &keep_index,
+			 N_("keep index")),
+		OPT_BOOL('S', "staged", &only_staged,
+			 N_("stash staged changes only")),
+		OPT_BOOL('p', "patch", &patch_mode,
+			 N_("stash in patch mode")),
+		OPT__QUIET(&quiet, N_("quiet mode")),
+		OPT_BOOL('u', "include-untracked", &include_untracked,
+			 N_("include untracked files in stash")),
+		OPT_SET_INT('a', "all", &include_untracked,
+			    N_("include ignore files"), 2),
+		OPT_STRING('m', "message", &stash_msg, "message",
+			   N_("stash message")),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options,
+			     git_stash_save_usage,
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	if (argc)
+		stash_msg = strbuf_join_argv(&stash_msg_buf, argc, argv, ' ');
+
+	memset(&ps, 0, sizeof(ps));
+	ret = do_push_stash(&ps, stash_msg, quiet, keep_index,
+			    patch_mode, include_untracked, only_staged);
+
+	strbuf_release(&stash_msg_buf);
+	return ret;
+}
+
+int cmd_stash(int argc,
+	      const char **argv,
+	      const char *prefix,
+	      struct repository *repo)
+{
+	pid_t pid = getpid();
+	const char *index_file;
+	struct strvec args = STRVEC_INIT;
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("apply", &fn, apply_stash),
+		OPT_SUBCOMMAND("clear", &fn, clear_stash),
+		OPT_SUBCOMMAND("drop", &fn, drop_stash),
+		OPT_SUBCOMMAND("pop", &fn, pop_stash),
+		OPT_SUBCOMMAND("branch", &fn, branch_stash),
+		OPT_SUBCOMMAND("list", &fn, list_stash),
+		OPT_SUBCOMMAND("show", &fn, show_stash),
+		OPT_SUBCOMMAND("store", &fn, store_stash),
+		OPT_SUBCOMMAND("create", &fn, create_stash),
+		OPT_SUBCOMMAND("push", &fn, push_stash_unassumed),
+		OPT_SUBCOMMAND_F("save", &fn, save_stash, PARSE_OPT_NOCOMPLETE),
+		OPT_END()
+	};
+	const char **args_copy;
+	int ret;
+
+	git_config(git_stash_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, options, git_stash_usage,
+			     PARSE_OPT_SUBCOMMAND_OPTIONAL |
+			     PARSE_OPT_KEEP_UNKNOWN_OPT |
+			     PARSE_OPT_KEEP_DASHDASH);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	index_file = repo_get_index_file(the_repository);
+	strbuf_addf(&stash_index_path, "%s.stash.%" PRIuMAX, index_file,
+		    (uintmax_t)pid);
+
+	if (fn)
+		return !!fn(argc, argv, prefix, repo);
+	else if (!argc)
+		return !!push_stash_unassumed(0, NULL, prefix, repo);
+
+	/* Assume 'stash push' */
+	strvec_push(&args, "push");
+	strvec_pushv(&args, argv);
+
+	/*
+	 * `push_stash()` ends up modifying the array, which causes memory
+	 * leaks if we didn't copy the array here.
+	 */
+	DUP_ARRAY(args_copy, args.v, args.nr);
+
+	ret = !!push_stash(args.nr, args_copy, prefix, 1);
+
+	strvec_clear(&args);
+	free(args_copy);
+	return ret;
+}
diff --git a/builtin/stripspace.c b/builtin/stripspace.c
new file mode 100644
index 0000000000..e147f3ff92
--- /dev/null
+++ b/builtin/stripspace.c
@@ -0,0 +1,73 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "write-or-die.h"
+
+static void comment_lines(struct strbuf *buf)
+{
+	char *msg;
+	size_t len;
+
+	msg = strbuf_detach(buf, &len);
+	strbuf_add_commented_lines(buf, msg, len, comment_line_str);
+	free(msg);
+}
+
+static const char * const stripspace_usage[] = {
+	"git stripspace [-s | --strip-comments]",
+	"git stripspace [-c | --comment-lines]",
+	NULL
+};
+
+enum stripspace_mode {
+	STRIP_DEFAULT = 0,
+	STRIP_COMMENTS,
+	COMMENT_LINES
+};
+
+int cmd_stripspace(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	struct strbuf buf = STRBUF_INIT;
+	enum stripspace_mode mode = STRIP_DEFAULT;
+	int nongit;
+
+	const struct option options[] = {
+		OPT_CMDMODE('s', "strip-comments", &mode,
+			    N_("skip and remove all lines starting with comment character"),
+			    STRIP_COMMENTS),
+		OPT_CMDMODE('c', "comment-lines", &mode,
+			    N_("prepend comment character and space to each line"),
+			    COMMENT_LINES),
+		OPT_END()
+	};
+
+	argc = parse_options(argc, argv, prefix, options, stripspace_usage, 0);
+	if (argc)
+		usage_with_options(stripspace_usage, options);
+
+	if (mode == STRIP_COMMENTS || mode == COMMENT_LINES) {
+		setup_git_directory_gently(&nongit);
+		git_config(git_default_config, NULL);
+	}
+
+	if (strbuf_read(&buf, 0, 1024) < 0)
+		die_errno("could not read the input");
+
+	if (mode == STRIP_DEFAULT || mode == STRIP_COMMENTS)
+		strbuf_stripspace(&buf,
+			  mode == STRIP_COMMENTS ? comment_line_str : NULL);
+	else
+		comment_lines(&buf);
+
+	write_or_die(1, buf.buf, buf.len);
+	strbuf_release(&buf);
+	return 0;
+}
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
new file mode 100644
index 0000000000..f9b970f8a6
--- /dev/null
+++ b/builtin/submodule--helper.c
@@ -0,0 +1,3601 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "abspath.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+
+#include "config.h"
+#include "parse-options.h"
+#include "quote.h"
+#include "path.h"
+#include "pathspec.h"
+#include "preload-index.h"
+#include "dir.h"
+#include "read-cache.h"
+#include "setup.h"
+#include "sparse-index.h"
+#include "submodule.h"
+#include "submodule-config.h"
+#include "string-list.h"
+#include "run-command.h"
+#include "remote.h"
+#include "refs.h"
+#include "refspec.h"
+#include "revision.h"
+#include "diffcore.h"
+#include "diff.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "advice.h"
+#include "branch.h"
+#include "list-objects-filter-options.h"
+
+#define OPT_QUIET (1 << 0)
+#define OPT_CACHED (1 << 1)
+#define OPT_RECURSIVE (1 << 2)
+#define OPT_FORCE (1 << 3)
+
+typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
+				  void *cb_data);
+
+static int repo_get_default_remote(struct repository *repo, char **default_remote)
+{
+	char *dest = NULL;
+	struct strbuf sb = STRBUF_INIT;
+	struct ref_store *store = get_main_ref_store(repo);
+	const char *refname = refs_resolve_ref_unsafe(store, "HEAD", 0, NULL,
+						      NULL);
+
+	if (!refname)
+		return die_message(_("No such ref: %s"), "HEAD");
+
+	/* detached HEAD */
+	if (!strcmp(refname, "HEAD")) {
+		*default_remote = xstrdup("origin");
+		return 0;
+	}
+
+	if (!skip_prefix(refname, "refs/heads/", &refname))
+		return die_message(_("Expecting a full ref name, got %s"),
+				   refname);
+
+	strbuf_addf(&sb, "branch.%s.remote", refname);
+	if (repo_config_get_string(repo, sb.buf, &dest))
+		*default_remote = xstrdup("origin");
+	else
+		*default_remote = dest;
+
+	strbuf_release(&sb);
+	return 0;
+}
+
+static int get_default_remote_submodule(const char *module_path, char **default_remote)
+{
+	struct repository subrepo;
+	int ret;
+
+	if (repo_submodule_init(&subrepo, the_repository, module_path,
+				null_oid()) < 0)
+		return die_message(_("could not get a repository handle for submodule '%s'"),
+				   module_path);
+	ret = repo_get_default_remote(&subrepo, default_remote);
+	repo_clear(&subrepo);
+
+	return ret;
+}
+
+static char *get_default_remote(void)
+{
+	char *default_remote;
+	int code = repo_get_default_remote(the_repository, &default_remote);
+
+	if (code)
+		exit(code);
+
+	return default_remote;
+}
+
+static char *resolve_relative_url(const char *rel_url, const char *up_path, int quiet)
+{
+	char *remoteurl, *resolved_url;
+	char *remote = get_default_remote();
+	struct strbuf remotesb = STRBUF_INIT;
+
+	strbuf_addf(&remotesb, "remote.%s.url", remote);
+	if (git_config_get_string(remotesb.buf, &remoteurl)) {
+		if (!quiet)
+			warning(_("could not look up configuration '%s'. "
+				  "Assuming this repository is its own "
+				  "authoritative upstream."),
+				remotesb.buf);
+		remoteurl = xgetcwd();
+	}
+	resolved_url = relative_url(remoteurl, rel_url, up_path);
+
+	free(remote);
+	free(remoteurl);
+	strbuf_release(&remotesb);
+
+	return resolved_url;
+}
+
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix,
+				       const char *super_prefix)
+{
+	if (prefix && super_prefix) {
+		BUG("cannot have prefix '%s' and superprefix '%s'",
+		    prefix, super_prefix);
+	} else if (prefix) {
+		struct strbuf sb = STRBUF_INIT;
+		char *displaypath = xstrdup(relative_path(path, prefix, &sb));
+		strbuf_release(&sb);
+		return displaypath;
+	} else if (super_prefix) {
+		return xstrfmt("%s%s", super_prefix, path);
+	} else {
+		return xstrdup(path);
+	}
+}
+
+static char *compute_rev_name(const char *sub_path, const char* object_id)
+{
+	struct strbuf sb = STRBUF_INIT;
+	const char ***d;
+
+	static const char *describe_bare[] = { NULL };
+
+	static const char *describe_tags[] = { "--tags", NULL };
+
+	static const char *describe_contains[] = { "--contains", NULL };
+
+	static const char *describe_all_always[] = { "--all", "--always", NULL };
+
+	static const char **describe_argv[] = { describe_bare, describe_tags,
+						describe_contains,
+						describe_all_always, NULL };
+
+	for (d = describe_argv; *d; d++) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+		prepare_submodule_repo_env(&cp.env);
+		cp.dir = sub_path;
+		cp.git_cmd = 1;
+		cp.no_stderr = 1;
+
+		strvec_push(&cp.args, "describe");
+		strvec_pushv(&cp.args, *d);
+		strvec_push(&cp.args, object_id);
+
+		if (!capture_command(&cp, &sb, 0)) {
+			strbuf_strip_suffix(&sb, "\n");
+			return strbuf_detach(&sb, NULL);
+		}
+	}
+
+	strbuf_release(&sb);
+	return NULL;
+}
+
+struct module_list {
+	const struct cache_entry **entries;
+	int alloc, nr;
+};
+#define MODULE_LIST_INIT { 0 }
+
+static void module_list_release(struct module_list *ml)
+{
+	free(ml->entries);
+}
+
+static int module_list_compute(const char **argv,
+			       const char *prefix,
+			       struct pathspec *pathspec,
+			       struct module_list *list)
+{
+	int result = 0;
+	char *ps_matched = NULL;
+
+	parse_pathspec(pathspec, 0,
+		       PATHSPEC_PREFER_FULL,
+		       prefix, argv);
+
+	if (pathspec->nr)
+		ps_matched = xcalloc(pathspec->nr, 1);
+
+	if (repo_read_index(the_repository) < 0)
+		die(_("index file corrupt"));
+
+	for (size_t i = 0; i < the_repository->index->cache_nr; i++) {
+		const struct cache_entry *ce = the_repository->index->cache[i];
+
+		if (!match_pathspec(the_repository->index, pathspec, ce->name, ce_namelen(ce),
+				    0, ps_matched, 1) ||
+		    !S_ISGITLINK(ce->ce_mode))
+			continue;
+
+		ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
+		list->entries[list->nr++] = ce;
+		while (i + 1 < the_repository->index->cache_nr &&
+		       !strcmp(ce->name, the_repository->index->cache[i + 1]->name))
+			/*
+			 * Skip entries with the same name in different stages
+			 * to make sure an entry is returned only once.
+			 */
+			i++;
+	}
+
+	if (ps_matched && report_path_error(ps_matched, pathspec))
+		result = -1;
+
+	free(ps_matched);
+
+	return result;
+}
+
+static void module_list_active(struct module_list *list)
+{
+	int i;
+	struct module_list active_modules = MODULE_LIST_INIT;
+
+	for (i = 0; i < list->nr; i++) {
+		const struct cache_entry *ce = list->entries[i];
+
+		if (!is_submodule_active(the_repository, ce->name))
+			continue;
+
+		ALLOC_GROW(active_modules.entries,
+			   active_modules.nr + 1,
+			   active_modules.alloc);
+		active_modules.entries[active_modules.nr++] = ce;
+	}
+
+	module_list_release(list);
+	*list = active_modules;
+}
+
+static char *get_up_path(const char *path)
+{
+	struct strbuf sb = STRBUF_INIT;
+
+	strbuf_addstrings(&sb, "../", count_slashes(path));
+
+	/*
+	 * Check if 'path' ends with slash or not
+	 * for having the same output for dir/sub_dir
+	 * and dir/sub_dir/
+	 */
+	if (!is_dir_sep(path[strlen(path) - 1]))
+		strbuf_addstr(&sb, "../");
+
+	return strbuf_detach(&sb, NULL);
+}
+
+static void for_each_listed_submodule(const struct module_list *list,
+				      each_submodule_fn fn, void *cb_data)
+{
+	int i;
+
+	for (i = 0; i < list->nr; i++)
+		fn(list->entries[i], cb_data);
+}
+
+struct foreach_cb {
+	int argc;
+	const char **argv;
+	const char *prefix;
+	const char *super_prefix;
+	int quiet;
+	int recursive;
+};
+#define FOREACH_CB_INIT { 0 }
+
+static void runcommand_in_submodule_cb(const struct cache_entry *list_item,
+				       void *cb_data)
+{
+	struct foreach_cb *info = cb_data;
+	const char *path = list_item->name;
+	const struct object_id *ce_oid = &list_item->oid;
+	const struct submodule *sub;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	char *displaypath;
+
+	if (validate_submodule_path(path) < 0)
+		exit(128);
+
+	displaypath = get_submodule_displaypath(path, info->prefix,
+						info->super_prefix);
+
+	sub = submodule_from_path(the_repository, null_oid(), path);
+
+	if (!sub)
+		die(_("No url found for submodule path '%s' in .gitmodules"),
+			displaypath);
+
+	if (!is_submodule_populated_gently(path, NULL))
+		goto cleanup;
+
+	prepare_submodule_repo_env(&cp.env);
+
+	/*
+	 * For the purpose of executing <command> in the submodule,
+	 * separate shell is used for the purpose of running the
+	 * child process.
+	 */
+	cp.use_shell = 1;
+	cp.dir = path;
+
+	/*
+	 * NEEDSWORK: the command currently has access to the variables $name,
+	 * $sm_path, $displaypath, $sha1 and $toplevel only when the command
+	 * contains a single argument. This is done for maintaining a faithful
+	 * translation from shell script.
+	 */
+	if (info->argc == 1) {
+		char *toplevel = xgetcwd();
+		struct strbuf sb = STRBUF_INIT;
+
+		strvec_pushf(&cp.env, "name=%s", sub->name);
+		strvec_pushf(&cp.env, "sm_path=%s", path);
+		strvec_pushf(&cp.env, "displaypath=%s", displaypath);
+		strvec_pushf(&cp.env, "sha1=%s",
+			     oid_to_hex(ce_oid));
+		strvec_pushf(&cp.env, "toplevel=%s", toplevel);
+
+		/*
+		 * Since the path variable was accessible from the script
+		 * before porting, it is also made available after porting.
+		 * The environment variable "PATH" has a very special purpose
+		 * on windows. And since environment variables are
+		 * case-insensitive in windows, it interferes with the
+		 * existing PATH variable. Hence, to avoid that, we expose
+		 * path via the args strvec and not via env.
+		 */
+		sq_quote_buf(&sb, path);
+		strvec_pushf(&cp.args, "path=%s; %s",
+			     sb.buf, info->argv[0]);
+		strbuf_release(&sb);
+		free(toplevel);
+	} else {
+		strvec_pushv(&cp.args, info->argv);
+	}
+
+	if (!info->quiet)
+		printf(_("Entering '%s'\n"), displaypath);
+
+	if (info->argv[0]) {
+		if (run_command(&cp))
+			die(_("run_command returned non-zero status for %s\n."),
+			    displaypath);
+	} else {
+		child_process_clear(&cp);
+	}
+
+	if (info->recursive) {
+		struct child_process cpr = CHILD_PROCESS_INIT;
+
+		cpr.git_cmd = 1;
+		cpr.dir = path;
+		prepare_submodule_repo_env(&cpr.env);
+
+		strvec_pushl(&cpr.args, "submodule--helper", "foreach", "--recursive",
+			     NULL);
+		strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath);
+
+		if (info->quiet)
+			strvec_push(&cpr.args, "--quiet");
+
+		strvec_push(&cpr.args, "--");
+		strvec_pushv(&cpr.args, info->argv);
+
+		if (run_command(&cpr))
+			die(_("run_command returned non-zero status while "
+				"recursing in the nested submodules of %s\n."),
+				displaypath);
+	}
+
+cleanup:
+	free(displaypath);
+}
+
+static int module_foreach(int argc, const char **argv, const char *prefix,
+			  struct repository *repo UNUSED)
+{
+	struct foreach_cb info = FOREACH_CB_INIT;
+	struct pathspec pathspec = { 0 };
+	struct module_list list = MODULE_LIST_INIT;
+	struct option module_foreach_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
+		OPT__QUIET(&info.quiet, N_("suppress output of entering each submodule command")),
+		OPT_BOOL(0, "recursive", &info.recursive,
+			 N_("recurse into nested submodules")),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule foreach [--quiet] [--recursive] [--] <command>"),
+		NULL
+	};
+	int ret = 1;
+
+	argc = parse_options(argc, argv, prefix, module_foreach_options,
+			     git_submodule_helper_usage, 0);
+
+	if (module_list_compute(NULL, prefix, &pathspec, &list) < 0)
+		goto cleanup;
+
+	info.argc = argc;
+	info.argv = argv;
+	info.prefix = prefix;
+
+	for_each_listed_submodule(&list, runcommand_in_submodule_cb, &info);
+
+	ret = 0;
+cleanup:
+	module_list_release(&list);
+	clear_pathspec(&pathspec);
+	return ret;
+}
+
+static int starts_with_dot_slash(const char *const path)
+{
+	return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_SLASH |
+				PATH_MATCH_XPLATFORM);
+}
+
+static int starts_with_dot_dot_slash(const char *const path)
+{
+	return path_match_flags(path, PATH_MATCH_STARTS_WITH_DOT_DOT_SLASH |
+				PATH_MATCH_XPLATFORM);
+}
+
+struct init_cb {
+	const char *prefix;
+	const char *super_prefix;
+	unsigned int flags;
+};
+#define INIT_CB_INIT { 0 }
+
+static void init_submodule(const char *path, const char *prefix,
+			   const char *super_prefix,
+			   unsigned int flags)
+{
+	const struct submodule *sub;
+	struct strbuf sb = STRBUF_INIT;
+	const char *upd;
+	char *url = NULL, *displaypath;
+
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
+
+	sub = submodule_from_path(the_repository, null_oid(), path);
+
+	if (!sub)
+		die(_("No url found for submodule path '%s' in .gitmodules"),
+			displaypath);
+
+	/*
+	 * NEEDSWORK: In a multi-working-tree world, this needs to be
+	 * set in the per-worktree config.
+	 *
+	 * Set active flag for the submodule being initialized
+	 */
+	if (!is_submodule_active(the_repository, path)) {
+		strbuf_addf(&sb, "submodule.%s.active", sub->name);
+		git_config_set_gently(sb.buf, "true");
+		strbuf_reset(&sb);
+	}
+
+	/*
+	 * Copy url setting when it is not set yet.
+	 * To look up the url in .git/config, we must not fall back to
+	 * .gitmodules, so look it up directly.
+	 */
+	strbuf_addf(&sb, "submodule.%s.url", sub->name);
+	if (git_config_get_string(sb.buf, &url)) {
+		if (!sub->url)
+			die(_("No url found for submodule path '%s' in .gitmodules"),
+				displaypath);
+
+		url = xstrdup(sub->url);
+
+		/* Possibly a url relative to parent */
+		if (starts_with_dot_dot_slash(url) ||
+		    starts_with_dot_slash(url)) {
+			char *oldurl = url;
+
+			url = resolve_relative_url(oldurl, NULL, 0);
+			free(oldurl);
+		}
+
+		if (git_config_set_gently(sb.buf, url))
+			die(_("Failed to register url for submodule path '%s'"),
+			    displaypath);
+		if (!(flags & OPT_QUIET))
+			fprintf(stderr,
+				_("Submodule '%s' (%s) registered for path '%s'\n"),
+				sub->name, url, displaypath);
+	}
+	strbuf_reset(&sb);
+
+	/* Copy "update" setting when it is not set yet */
+	strbuf_addf(&sb, "submodule.%s.update", sub->name);
+	if (git_config_get_string_tmp(sb.buf, &upd) &&
+	    sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
+		if (sub->update_strategy.type == SM_UPDATE_COMMAND) {
+			fprintf(stderr, _("warning: command update mode suggested for submodule '%s'\n"),
+				sub->name);
+			upd = "none";
+		} else {
+			upd = submodule_update_type_to_string(sub->update_strategy.type);
+		}
+
+		if (git_config_set_gently(sb.buf, upd))
+			die(_("Failed to register update mode for submodule path '%s'"), displaypath);
+	}
+	strbuf_release(&sb);
+	free(displaypath);
+	free(url);
+}
+
+static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
+{
+	struct init_cb *info = cb_data;
+
+	init_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
+}
+
+static int module_init(int argc, const char **argv, const char *prefix,
+		       struct repository *repo UNUSED)
+{
+	struct init_cb info = INIT_CB_INIT;
+	struct pathspec pathspec = { 0 };
+	struct module_list list = MODULE_LIST_INIT;
+	int quiet = 0;
+	struct option module_init_options[] = {
+		OPT__QUIET(&quiet, N_("suppress output for initializing a submodule")),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule init [<options>] [<path>]"),
+		NULL
+	};
+	int ret = 1;
+
+	argc = parse_options(argc, argv, prefix, module_init_options,
+			     git_submodule_helper_usage, 0);
+
+	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
+		goto cleanup;
+
+	/*
+	 * If there are no path args and submodule.active is set then,
+	 * by default, only initialize 'active' modules.
+	 */
+	if (!argc && !git_config_get("submodule.active"))
+		module_list_active(&list);
+
+	info.prefix = prefix;
+	if (quiet)
+		info.flags |= OPT_QUIET;
+
+	for_each_listed_submodule(&list, init_submodule_cb, &info);
+
+	ret = 0;
+cleanup:
+	module_list_release(&list);
+	clear_pathspec(&pathspec);
+	return ret;
+}
+
+struct status_cb {
+	const char *prefix;
+	const char *super_prefix;
+	unsigned int flags;
+};
+#define STATUS_CB_INIT { 0 }
+
+static void print_status(unsigned int flags, char state, const char *path,
+			 const struct object_id *oid, const char *displaypath)
+{
+	if (flags & OPT_QUIET)
+		return;
+
+	printf("%c%s %s", state, oid_to_hex(oid), displaypath);
+
+	if (state == ' ' || state == '+') {
+		char *name = compute_rev_name(path, oid_to_hex(oid));
+
+		if (name)
+			printf(" (%s)", name);
+		free(name);
+	}
+
+	printf("\n");
+}
+
+static int handle_submodule_head_ref(const char *refname UNUSED,
+				     const char *referent UNUSED,
+				     const struct object_id *oid,
+				     int flags UNUSED,
+				     void *cb_data)
+{
+	struct object_id *output = cb_data;
+
+	if (oid)
+		oidcpy(output, oid);
+
+	return 0;
+}
+
+static void status_submodule(const char *path, const struct object_id *ce_oid,
+			     unsigned int ce_flags, const char *prefix,
+			     const char *super_prefix, unsigned int flags)
+{
+	char *displaypath;
+	struct strvec diff_files_args = STRVEC_INIT;
+	struct rev_info rev = REV_INFO_INIT;
+	struct strbuf buf = STRBUF_INIT;
+	const char *git_dir;
+	struct setup_revision_opt opt = {
+		.free_removed_argv_elements = 1,
+	};
+
+	if (validate_submodule_path(path) < 0)
+		exit(128);
+
+	if (!submodule_from_path(the_repository, null_oid(), path))
+		die(_("no submodule mapping found in .gitmodules for path '%s'"),
+		      path);
+
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
+
+	if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
+		print_status(flags, 'U', path, null_oid(), displaypath);
+		goto cleanup;
+	}
+
+	strbuf_addf(&buf, "%s/.git", path);
+	git_dir = read_gitfile(buf.buf);
+	if (!git_dir)
+		git_dir = buf.buf;
+
+	if (!is_submodule_active(the_repository, path) ||
+	    !is_git_directory(git_dir)) {
+		print_status(flags, '-', path, ce_oid, displaypath);
+		strbuf_release(&buf);
+		goto cleanup;
+	}
+	strbuf_release(&buf);
+
+	strvec_pushl(&diff_files_args, "diff-files",
+		     "--ignore-submodules=dirty", "--quiet", "--",
+		     path, NULL);
+
+	git_config(git_diff_basic_config, NULL);
+
+	repo_init_revisions(the_repository, &rev, NULL);
+	rev.abbrev = 0;
+	setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt);
+	run_diff_files(&rev, 0);
+
+	if (!diff_result_code(&rev)) {
+		print_status(flags, ' ', path, ce_oid,
+			     displaypath);
+	} else if (!(flags & OPT_CACHED)) {
+		struct object_id oid;
+		struct ref_store *refs = repo_get_submodule_ref_store(the_repository,
+								      path);
+
+		if (!refs) {
+			print_status(flags, '-', path, ce_oid, displaypath);
+			goto cleanup;
+		}
+		if (refs_head_ref(refs, handle_submodule_head_ref, &oid))
+			die(_("could not resolve HEAD ref inside the "
+			      "submodule '%s'"), path);
+
+		print_status(flags, '+', path, &oid, displaypath);
+	} else {
+		print_status(flags, '+', path, ce_oid, displaypath);
+	}
+
+	if (flags & OPT_RECURSIVE) {
+		struct child_process cpr = CHILD_PROCESS_INIT;
+		int res;
+
+		cpr.git_cmd = 1;
+		cpr.dir = path;
+		prepare_submodule_repo_env(&cpr.env);
+
+		strvec_pushl(&cpr.args, "submodule--helper", "status",
+			     "--recursive", NULL);
+		strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath);
+
+		if (flags & OPT_CACHED)
+			strvec_push(&cpr.args, "--cached");
+
+		if (flags & OPT_QUIET)
+			strvec_push(&cpr.args, "--quiet");
+
+		res = run_command(&cpr);
+		if (res == SIGPIPE + 128)
+			raise(SIGPIPE);
+		else if (res)
+			die(_("failed to recurse into submodule '%s'"), path);
+	}
+
+cleanup:
+	strvec_clear(&diff_files_args);
+	free(displaypath);
+	release_revisions(&rev);
+}
+
+static void status_submodule_cb(const struct cache_entry *list_item,
+				void *cb_data)
+{
+	struct status_cb *info = cb_data;
+
+	status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
+			 info->prefix, info->super_prefix, info->flags);
+}
+
+static int module_status(int argc, const char **argv, const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	struct status_cb info = STATUS_CB_INIT;
+	struct pathspec pathspec = { 0 };
+	struct module_list list = MODULE_LIST_INIT;
+	int quiet = 0;
+	struct option module_status_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
+		OPT__QUIET(&quiet, N_("suppress submodule status output")),
+		OPT_BIT(0, "cached", &info.flags, N_("use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
+		OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
+		NULL
+	};
+	int ret = 1;
+
+	argc = parse_options(argc, argv, prefix, module_status_options,
+			     git_submodule_helper_usage, 0);
+
+	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
+		goto cleanup;
+
+	info.prefix = prefix;
+	if (quiet)
+		info.flags |= OPT_QUIET;
+
+	for_each_listed_submodule(&list, status_submodule_cb, &info);
+
+	ret = 0;
+cleanup:
+	module_list_release(&list);
+	clear_pathspec(&pathspec);
+	return ret;
+}
+
+struct module_cb {
+	unsigned int mod_src;
+	unsigned int mod_dst;
+	struct object_id oid_src;
+	struct object_id oid_dst;
+	char status;
+	char *sm_path;
+};
+#define MODULE_CB_INIT { 0 }
+
+static void module_cb_release(struct module_cb *mcb)
+{
+	free(mcb->sm_path);
+}
+
+struct module_cb_list {
+	struct module_cb **entries;
+	int alloc, nr;
+};
+#define MODULE_CB_LIST_INIT { 0 }
+
+static void module_cb_list_release(struct module_cb_list *mcbl)
+{
+	int i;
+
+	for (i = 0; i < mcbl->nr; i++) {
+		struct module_cb *mcb = mcbl->entries[i];
+
+		module_cb_release(mcb);
+		free(mcb);
+	}
+	free(mcbl->entries);
+}
+
+struct summary_cb {
+	int argc;
+	const char **argv;
+	const char *prefix;
+	const char *super_prefix;
+	unsigned int cached: 1;
+	unsigned int for_status: 1;
+	unsigned int files: 1;
+	int summary_limit;
+};
+#define SUMMARY_CB_INIT { 0 }
+
+enum diff_cmd {
+	DIFF_INDEX,
+	DIFF_FILES
+};
+
+static char *verify_submodule_committish(const char *sm_path,
+					 const char *committish)
+{
+	struct child_process cp_rev_parse = CHILD_PROCESS_INIT;
+	struct strbuf result = STRBUF_INIT;
+
+	cp_rev_parse.git_cmd = 1;
+	cp_rev_parse.dir = sm_path;
+	prepare_submodule_repo_env(&cp_rev_parse.env);
+	strvec_pushl(&cp_rev_parse.args, "rev-parse", "-q", "--short", NULL);
+	strvec_pushf(&cp_rev_parse.args, "%s^0", committish);
+	strvec_push(&cp_rev_parse.args, "--");
+
+	if (capture_command(&cp_rev_parse, &result, 0))
+		return NULL;
+
+	strbuf_trim_trailing_newline(&result);
+	return strbuf_detach(&result, NULL);
+}
+
+static void print_submodule_summary(struct summary_cb *info, const char *errmsg,
+				    int total_commits, const char *displaypath,
+				    const char *src_abbrev, const char *dst_abbrev,
+				    struct module_cb *p)
+{
+	if (p->status == 'T') {
+		if (S_ISGITLINK(p->mod_dst))
+			printf(_("* %s %s(blob)->%s(submodule)"),
+				 displaypath, src_abbrev, dst_abbrev);
+		else
+			printf(_("* %s %s(submodule)->%s(blob)"),
+				 displaypath, src_abbrev, dst_abbrev);
+	} else {
+		printf("* %s %s...%s",
+			displaypath, src_abbrev, dst_abbrev);
+	}
+
+	if (total_commits < 0)
+		printf(":\n");
+	else
+		printf(" (%d):\n", total_commits);
+
+	if (errmsg) {
+		printf(_("%s"), errmsg);
+	} else if (total_commits > 0) {
+		struct child_process cp_log = CHILD_PROCESS_INIT;
+
+		cp_log.git_cmd = 1;
+		cp_log.dir = p->sm_path;
+		prepare_submodule_repo_env(&cp_log.env);
+		strvec_pushl(&cp_log.args, "log", NULL);
+
+		if (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst)) {
+			if (info->summary_limit > 0)
+				strvec_pushf(&cp_log.args, "-%d",
+					     info->summary_limit);
+
+			strvec_pushl(&cp_log.args, "--pretty=  %m %s",
+				     "--first-parent", NULL);
+			strvec_pushf(&cp_log.args, "%s...%s",
+				     src_abbrev, dst_abbrev);
+		} else if (S_ISGITLINK(p->mod_dst)) {
+			strvec_pushl(&cp_log.args, "--pretty=  > %s",
+				     "-1", dst_abbrev, NULL);
+		} else {
+			strvec_pushl(&cp_log.args, "--pretty=  < %s",
+				     "-1", src_abbrev, NULL);
+		}
+		run_command(&cp_log);
+	}
+	printf("\n");
+}
+
+static void generate_submodule_summary(struct summary_cb *info,
+				       struct module_cb *p)
+{
+	char *displaypath, *src_abbrev = NULL, *dst_abbrev;
+	int missing_src = 0, missing_dst = 0;
+	struct strbuf errmsg = STRBUF_INIT;
+	int total_commits = -1;
+
+	if (!info->cached && oideq(&p->oid_dst, null_oid())) {
+		if (S_ISGITLINK(p->mod_dst)) {
+			struct ref_store *refs = repo_get_submodule_ref_store(the_repository,
+									      p->sm_path);
+
+			if (refs)
+				refs_head_ref(refs, handle_submodule_head_ref, &p->oid_dst);
+		} else if (S_ISLNK(p->mod_dst) || S_ISREG(p->mod_dst)) {
+			struct stat st;
+			int fd = open(p->sm_path, O_RDONLY);
+
+			if (fd < 0 || fstat(fd, &st) < 0 ||
+			    index_fd(the_repository->index, &p->oid_dst, fd, &st, OBJ_BLOB,
+				     p->sm_path, 0))
+				error(_("couldn't hash object from '%s'"), p->sm_path);
+		} else {
+			/* for a submodule removal (mode:0000000), don't warn */
+			if (p->mod_dst)
+				warning(_("unexpected mode %o"), p->mod_dst);
+		}
+	}
+
+	if (S_ISGITLINK(p->mod_src)) {
+		if (p->status != 'D')
+			src_abbrev = verify_submodule_committish(p->sm_path,
+								 oid_to_hex(&p->oid_src));
+		if (!src_abbrev) {
+			missing_src = 1;
+			/*
+			 * As `rev-parse` failed, we fallback to getting
+			 * the abbreviated hash using oid_src. We do
+			 * this as we might still need the abbreviated
+			 * hash in cases like a submodule type change, etc.
+			 */
+			src_abbrev = xstrndup(oid_to_hex(&p->oid_src), 7);
+		}
+	} else {
+		/*
+		 * The source does not point to a submodule.
+		 * So, we fallback to getting the abbreviation using
+		 * oid_src as we might still need the abbreviated
+		 * hash in cases like submodule add, etc.
+		 */
+		src_abbrev = xstrndup(oid_to_hex(&p->oid_src), 7);
+	}
+
+	if (S_ISGITLINK(p->mod_dst)) {
+		dst_abbrev = verify_submodule_committish(p->sm_path,
+							 oid_to_hex(&p->oid_dst));
+		if (!dst_abbrev) {
+			missing_dst = 1;
+			/*
+			 * As `rev-parse` failed, we fallback to getting
+			 * the abbreviated hash using oid_dst. We do
+			 * this as we might still need the abbreviated
+			 * hash in cases like a submodule type change, etc.
+			 */
+			dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
+		}
+	} else {
+		/*
+		 * The destination does not point to a submodule.
+		 * So, we fallback to getting the abbreviation using
+		 * oid_dst as we might still need the abbreviated
+		 * hash in cases like a submodule removal, etc.
+		 */
+		dst_abbrev = xstrndup(oid_to_hex(&p->oid_dst), 7);
+	}
+
+	displaypath = get_submodule_displaypath(p->sm_path, info->prefix,
+						info->super_prefix);
+
+	if (!missing_src && !missing_dst) {
+		struct child_process cp_rev_list = CHILD_PROCESS_INIT;
+		struct strbuf sb_rev_list = STRBUF_INIT;
+
+		strvec_pushl(&cp_rev_list.args, "rev-list",
+			     "--first-parent", "--count", NULL);
+		if (S_ISGITLINK(p->mod_src) && S_ISGITLINK(p->mod_dst))
+			strvec_pushf(&cp_rev_list.args, "%s...%s",
+				     src_abbrev, dst_abbrev);
+		else
+			strvec_push(&cp_rev_list.args, S_ISGITLINK(p->mod_src) ?
+				    src_abbrev : dst_abbrev);
+		strvec_push(&cp_rev_list.args, "--");
+
+		cp_rev_list.git_cmd = 1;
+		cp_rev_list.dir = p->sm_path;
+		prepare_submodule_repo_env(&cp_rev_list.env);
+
+		if (!capture_command(&cp_rev_list, &sb_rev_list, 0))
+			total_commits = atoi(sb_rev_list.buf);
+
+		strbuf_release(&sb_rev_list);
+	} else {
+		/*
+		 * Don't give error msg for modification whose dst is not
+		 * submodule, i.e., deleted or changed to blob
+		 */
+		if (S_ISGITLINK(p->mod_dst)) {
+			if (missing_src && missing_dst) {
+				strbuf_addf(&errmsg, "  Warn: %s doesn't contain commits %s and %s\n",
+					    displaypath, oid_to_hex(&p->oid_src),
+					    oid_to_hex(&p->oid_dst));
+			} else {
+				strbuf_addf(&errmsg, "  Warn: %s doesn't contain commit %s\n",
+					    displaypath, missing_src ?
+					    oid_to_hex(&p->oid_src) :
+					    oid_to_hex(&p->oid_dst));
+			}
+		}
+	}
+
+	print_submodule_summary(info, errmsg.len ? errmsg.buf : NULL,
+				total_commits, displaypath, src_abbrev,
+				dst_abbrev, p);
+
+	free(displaypath);
+	free(src_abbrev);
+	free(dst_abbrev);
+	strbuf_release(&errmsg);
+}
+
+static void prepare_submodule_summary(struct summary_cb *info,
+				      struct module_cb_list *list)
+{
+	int i;
+	for (i = 0; i < list->nr; i++) {
+		const struct submodule *sub;
+		struct module_cb *p = list->entries[i];
+		struct strbuf sm_gitdir = STRBUF_INIT;
+
+		if (p->status == 'D' || p->status == 'T') {
+			generate_submodule_summary(info, p);
+			continue;
+		}
+
+		if (info->for_status && p->status != 'A' &&
+		    (sub = submodule_from_path(the_repository,
+					       null_oid(), p->sm_path))) {
+			char *config_key = NULL;
+			const char *value;
+			int ignore_all = 0;
+
+			config_key = xstrfmt("submodule.%s.ignore",
+					     sub->name);
+			if (!git_config_get_string_tmp(config_key, &value))
+				ignore_all = !strcmp(value, "all");
+			else if (sub->ignore)
+				ignore_all = !strcmp(sub->ignore, "all");
+
+			free(config_key);
+			if (ignore_all)
+				continue;
+		}
+
+		/* Also show added or modified modules which are checked out */
+		strbuf_addstr(&sm_gitdir, p->sm_path);
+		if (is_nonbare_repository_dir(&sm_gitdir))
+			generate_submodule_summary(info, p);
+		strbuf_release(&sm_gitdir);
+	}
+}
+
+static void submodule_summary_callback(struct diff_queue_struct *q,
+				       struct diff_options *options UNUSED,
+				       void *data)
+{
+	int i;
+	struct module_cb_list *list = data;
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		struct module_cb *temp;
+
+		if (!S_ISGITLINK(p->one->mode) && !S_ISGITLINK(p->two->mode))
+			continue;
+		temp = (struct module_cb*)malloc(sizeof(struct module_cb));
+		temp->mod_src = p->one->mode;
+		temp->mod_dst = p->two->mode;
+		temp->oid_src = p->one->oid;
+		temp->oid_dst = p->two->oid;
+		temp->status = p->status;
+		temp->sm_path = xstrdup(p->one->path);
+
+		ALLOC_GROW(list->entries, list->nr + 1, list->alloc);
+		list->entries[list->nr++] = temp;
+	}
+}
+
+static const char *get_diff_cmd(enum diff_cmd diff_cmd)
+{
+	switch (diff_cmd) {
+	case DIFF_INDEX: return "diff-index";
+	case DIFF_FILES: return "diff-files";
+	default: BUG("bad diff_cmd value %d", diff_cmd);
+	}
+}
+
+static int compute_summary_module_list(struct object_id *head_oid,
+				       struct summary_cb *info,
+				       enum diff_cmd diff_cmd)
+{
+	struct strvec diff_args = STRVEC_INIT;
+	struct rev_info rev;
+	struct setup_revision_opt opt = {
+		.free_removed_argv_elements = 1,
+	};
+	struct module_cb_list list = MODULE_CB_LIST_INIT;
+	int ret = 0;
+
+	strvec_push(&diff_args, get_diff_cmd(diff_cmd));
+	if (info->cached)
+		strvec_push(&diff_args, "--cached");
+	strvec_pushl(&diff_args, "--ignore-submodules=dirty", "--raw", NULL);
+	if (head_oid)
+		strvec_push(&diff_args, oid_to_hex(head_oid));
+	strvec_push(&diff_args, "--");
+	if (info->argc)
+		strvec_pushv(&diff_args, info->argv);
+
+	git_config(git_diff_basic_config, NULL);
+	repo_init_revisions(the_repository, &rev, info->prefix);
+	rev.abbrev = 0;
+	precompose_argv_prefix(diff_args.nr, diff_args.v, NULL);
+	setup_revisions(diff_args.nr, diff_args.v, &rev, &opt);
+	rev.diffopt.output_format = DIFF_FORMAT_NO_OUTPUT | DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = submodule_summary_callback;
+	rev.diffopt.format_callback_data = &list;
+
+	if (!info->cached) {
+		if (diff_cmd == DIFF_INDEX)
+			setup_work_tree();
+		if (repo_read_index_preload(the_repository, &rev.diffopt.pathspec, 0) < 0) {
+			perror("repo_read_index_preload");
+			ret = -1;
+			goto cleanup;
+		}
+	} else if (repo_read_index(the_repository) < 0) {
+		perror("repo_read_cache");
+		ret = -1;
+		goto cleanup;
+	}
+
+	if (diff_cmd == DIFF_INDEX)
+		run_diff_index(&rev, info->cached ? DIFF_INDEX_CACHED : 0);
+	else
+		run_diff_files(&rev, 0);
+	prepare_submodule_summary(info, &list);
+cleanup:
+	strvec_clear(&diff_args);
+	release_revisions(&rev);
+	module_cb_list_release(&list);
+	return ret;
+}
+
+static int module_summary(int argc, const char **argv, const char *prefix,
+			  struct repository *repo UNUSED)
+{
+	struct summary_cb info = SUMMARY_CB_INIT;
+	int cached = 0;
+	int for_status = 0;
+	int files = 0;
+	int summary_limit = -1;
+	enum diff_cmd diff_cmd = DIFF_INDEX;
+	struct object_id head_oid;
+	int ret;
+	struct option module_summary_options[] = {
+		OPT_BOOL(0, "cached", &cached,
+			 N_("use the commit stored in the index instead of the submodule HEAD")),
+		OPT_BOOL(0, "files", &files,
+			 N_("compare the commit in the index with that in the submodule HEAD")),
+		OPT_BOOL(0, "for-status", &for_status,
+			 N_("skip submodules with 'ignore_config' value set to 'all'")),
+		OPT_INTEGER('n', "summary-limit", &summary_limit,
+			     N_("limit the summary size")),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule summary [<options>] [<commit>] [--] [<path>]"),
+		NULL
+	};
+
+	argc = parse_options(argc, argv, prefix, module_summary_options,
+			     git_submodule_helper_usage, 0);
+
+	if (!summary_limit)
+		return 0;
+
+	if (!repo_get_oid(the_repository, argc ? argv[0] : "HEAD", &head_oid)) {
+		if (argc) {
+			argv++;
+			argc--;
+		}
+	} else if (!argc || !strcmp(argv[0], "HEAD")) {
+		/* before the first commit: compare with an empty tree */
+		oidcpy(&head_oid, the_hash_algo->empty_tree);
+		if (argc) {
+			argv++;
+			argc--;
+		}
+	} else {
+		if (repo_get_oid(the_repository, "HEAD", &head_oid))
+			die(_("could not fetch a revision for HEAD"));
+	}
+
+	if (files) {
+		if (cached)
+			die(_("options '%s' and '%s' cannot be used together"), "--cached", "--files");
+		diff_cmd = DIFF_FILES;
+	}
+
+	info.argc = argc;
+	info.argv = argv;
+	info.prefix = prefix;
+	info.cached = !!cached;
+	info.files = !!files;
+	info.for_status = !!for_status;
+	info.summary_limit = summary_limit;
+
+	ret = compute_summary_module_list((diff_cmd == DIFF_INDEX) ? &head_oid : NULL,
+					  &info, diff_cmd);
+	return ret;
+}
+
+struct sync_cb {
+	const char *prefix;
+	const char *super_prefix;
+	unsigned int flags;
+};
+#define SYNC_CB_INIT { 0 }
+
+static void sync_submodule(const char *path, const char *prefix,
+			   const char *super_prefix, unsigned int flags)
+{
+	const struct submodule *sub;
+	char *remote_key = NULL;
+	char *sub_origin_url, *super_config_url, *displaypath, *default_remote;
+	struct strbuf sb = STRBUF_INIT;
+	char *sub_config_path = NULL;
+	int code;
+
+	if (!is_submodule_active(the_repository, path))
+		return;
+
+	if (validate_submodule_path(path) < 0)
+		exit(128);
+
+	sub = submodule_from_path(the_repository, null_oid(), path);
+
+	if (sub && sub->url) {
+		if (starts_with_dot_dot_slash(sub->url) ||
+		    starts_with_dot_slash(sub->url)) {
+			char *up_path = get_up_path(path);
+
+			sub_origin_url = resolve_relative_url(sub->url, up_path, 1);
+			super_config_url = resolve_relative_url(sub->url, NULL, 1);
+			free(up_path);
+		} else {
+			sub_origin_url = xstrdup(sub->url);
+			super_config_url = xstrdup(sub->url);
+		}
+	} else {
+		sub_origin_url = xstrdup("");
+		super_config_url = xstrdup("");
+	}
+
+	displaypath = get_submodule_displaypath(path, prefix, super_prefix);
+
+	if (!(flags & OPT_QUIET))
+		printf(_("Synchronizing submodule url for '%s'\n"),
+			 displaypath);
+
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "submodule.%s.url", sub->name);
+	if (git_config_set_gently(sb.buf, super_config_url))
+		die(_("failed to register url for submodule path '%s'"),
+		      displaypath);
+
+	if (!is_submodule_populated_gently(path, NULL))
+		goto cleanup;
+
+	strbuf_reset(&sb);
+	code = get_default_remote_submodule(path, &default_remote);
+	if (code)
+		exit(code);
+
+	remote_key = xstrfmt("remote.%s.url", default_remote);
+	free(default_remote);
+
+	submodule_to_gitdir(&sb, path);
+	strbuf_addstr(&sb, "/config");
+
+	if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url))
+		die(_("failed to update remote for submodule '%s'"),
+		      path);
+
+	if (flags & OPT_RECURSIVE) {
+		struct child_process cpr = CHILD_PROCESS_INIT;
+
+		cpr.git_cmd = 1;
+		cpr.dir = path;
+		prepare_submodule_repo_env(&cpr.env);
+
+		strvec_pushl(&cpr.args, "submodule--helper", "sync",
+			     "--recursive", NULL);
+		strvec_pushf(&cpr.args, "--super-prefix=%s/", displaypath);
+
+		if (flags & OPT_QUIET)
+			strvec_push(&cpr.args, "--quiet");
+
+		if (run_command(&cpr))
+			die(_("failed to recurse into submodule '%s'"),
+			      path);
+	}
+
+cleanup:
+	free(super_config_url);
+	free(sub_origin_url);
+	strbuf_release(&sb);
+	free(remote_key);
+	free(displaypath);
+	free(sub_config_path);
+}
+
+static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)
+{
+	struct sync_cb *info = cb_data;
+
+	sync_submodule(list_item->name, info->prefix, info->super_prefix,
+		       info->flags);
+}
+
+static int module_sync(int argc, const char **argv, const char *prefix,
+		       struct repository *repo UNUSED)
+{
+	struct sync_cb info = SYNC_CB_INIT;
+	struct pathspec pathspec = { 0 };
+	struct module_list list = MODULE_LIST_INIT;
+	int quiet = 0;
+	int recursive = 0;
+	struct option module_sync_options[] = {
+		OPT__SUPER_PREFIX(&info.super_prefix),
+		OPT__QUIET(&quiet, N_("suppress output of synchronizing submodule url")),
+		OPT_BOOL(0, "recursive", &recursive,
+			N_("recurse into nested submodules")),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule sync [--quiet] [--recursive] [<path>]"),
+		NULL
+	};
+	int ret = 1;
+
+	argc = parse_options(argc, argv, prefix, module_sync_options,
+			     git_submodule_helper_usage, 0);
+
+	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
+		goto cleanup;
+
+	info.prefix = prefix;
+	if (quiet)
+		info.flags |= OPT_QUIET;
+	if (recursive)
+		info.flags |= OPT_RECURSIVE;
+
+	for_each_listed_submodule(&list, sync_submodule_cb, &info);
+
+	ret = 0;
+cleanup:
+	module_list_release(&list);
+	clear_pathspec(&pathspec);
+	return ret;
+}
+
+struct deinit_cb {
+	const char *prefix;
+	unsigned int flags;
+};
+#define DEINIT_CB_INIT { 0 }
+
+static void deinit_submodule(const char *path, const char *prefix,
+			     unsigned int flags)
+{
+	const struct submodule *sub;
+	char *displaypath = NULL;
+	struct child_process cp_config = CHILD_PROCESS_INIT;
+	struct strbuf sb_config = STRBUF_INIT;
+	char *sub_git_dir = xstrfmt("%s/.git", path);
+
+	if (validate_submodule_path(path) < 0)
+		exit(128);
+
+	sub = submodule_from_path(the_repository, null_oid(), path);
+
+	if (!sub || !sub->name)
+		goto cleanup;
+
+	displaypath = get_submodule_displaypath(path, prefix, NULL);
+
+	/* remove the submodule work tree (unless the user already did it) */
+	if (is_directory(path)) {
+		struct strbuf sb_rm = STRBUF_INIT;
+		const char *format;
+
+		if (is_directory(sub_git_dir)) {
+			if (!(flags & OPT_QUIET))
+				warning(_("Submodule work tree '%s' contains a .git "
+					  "directory. This will be replaced with a "
+					  ".git file by using absorbgitdirs."),
+					displaypath);
+
+			absorb_git_dir_into_superproject(path, NULL);
+
+		}
+
+		if (!(flags & OPT_FORCE)) {
+			struct child_process cp_rm = CHILD_PROCESS_INIT;
+
+			cp_rm.git_cmd = 1;
+			strvec_pushl(&cp_rm.args, "rm", "-qn",
+				     path, NULL);
+
+			if (run_command(&cp_rm))
+				die(_("Submodule work tree '%s' contains local "
+				      "modifications; use '-f' to discard them"),
+				      displaypath);
+		}
+
+		strbuf_addstr(&sb_rm, path);
+
+		if (!remove_dir_recursively(&sb_rm, 0))
+			format = _("Cleared directory '%s'\n");
+		else
+			format = _("Could not remove submodule work tree '%s'\n");
+
+		if (!(flags & OPT_QUIET))
+			printf(format, displaypath);
+
+		submodule_unset_core_worktree(sub);
+
+		strbuf_release(&sb_rm);
+	}
+
+	if (mkdir(path, 0777))
+		printf(_("could not create empty submodule directory %s"),
+		      displaypath);
+
+	cp_config.git_cmd = 1;
+	strvec_pushl(&cp_config.args, "config", "--get-regexp", NULL);
+	strvec_pushf(&cp_config.args, "submodule.%s\\.", sub->name);
+
+	/* remove the .git/config entries (unless the user already did it) */
+	if (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {
+		char *sub_key = xstrfmt("submodule.%s", sub->name);
+
+		/*
+		 * remove the whole section so we have a clean state when
+		 * the user later decides to init this submodule again
+		 */
+		repo_config_rename_section_in_file(the_repository, NULL, sub_key, NULL);
+		if (!(flags & OPT_QUIET))
+			printf(_("Submodule '%s' (%s) unregistered for path '%s'\n"),
+				 sub->name, sub->url, displaypath);
+		free(sub_key);
+	}
+
+cleanup:
+	free(displaypath);
+	free(sub_git_dir);
+	strbuf_release(&sb_config);
+}
+
+static void deinit_submodule_cb(const struct cache_entry *list_item,
+				void *cb_data)
+{
+	struct deinit_cb *info = cb_data;
+	deinit_submodule(list_item->name, info->prefix, info->flags);
+}
+
+static int module_deinit(int argc, const char **argv, const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	struct deinit_cb info = DEINIT_CB_INIT;
+	struct pathspec pathspec = { 0 };
+	struct module_list list = MODULE_LIST_INIT;
+	int quiet = 0;
+	int force = 0;
+	int all = 0;
+	struct option module_deinit_options[] = {
+		OPT__QUIET(&quiet, N_("suppress submodule status output")),
+		OPT__FORCE(&force, N_("remove submodule working trees even if they contain local changes"), 0),
+		OPT_BOOL(0, "all", &all, N_("unregister all submodules")),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"),
+		NULL
+	};
+	int ret = 1;
+
+	argc = parse_options(argc, argv, prefix, module_deinit_options,
+			     git_submodule_helper_usage, 0);
+
+	if (all && argc) {
+		error("pathspec and --all are incompatible");
+		usage_with_options(git_submodule_helper_usage,
+				   module_deinit_options);
+	}
+
+	if (!argc && !all)
+		die(_("Use '--all' if you really want to deinitialize all submodules"));
+
+	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
+		goto cleanup;
+
+	info.prefix = prefix;
+	if (quiet)
+		info.flags |= OPT_QUIET;
+	if (force)
+		info.flags |= OPT_FORCE;
+
+	for_each_listed_submodule(&list, deinit_submodule_cb, &info);
+
+	ret = 0;
+cleanup:
+	module_list_release(&list);
+	clear_pathspec(&pathspec);
+	return ret;
+}
+
+struct module_clone_data {
+	const char *prefix;
+	const char *path;
+	const char *name;
+	const char *url;
+	int depth;
+	struct list_objects_filter_options *filter_options;
+	enum ref_storage_format ref_storage_format;
+	unsigned int quiet: 1;
+	unsigned int progress: 1;
+	unsigned int dissociate: 1;
+	unsigned int require_init: 1;
+	int single_branch;
+};
+#define MODULE_CLONE_DATA_INIT { \
+	.single_branch = -1, \
+	.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
+}
+
+struct submodule_alternate_setup {
+	const char *submodule_name;
+	enum SUBMODULE_ALTERNATE_ERROR_MODE {
+		SUBMODULE_ALTERNATE_ERROR_DIE,
+		SUBMODULE_ALTERNATE_ERROR_INFO,
+		SUBMODULE_ALTERNATE_ERROR_IGNORE
+	} error_mode;
+	struct string_list *reference;
+};
+#define SUBMODULE_ALTERNATE_SETUP_INIT { \
+	.error_mode = SUBMODULE_ALTERNATE_ERROR_IGNORE, \
+}
+
+static const char alternate_error_advice[] = N_(
+"An alternate computed from a superproject's alternate is invalid.\n"
+"To allow Git to clone without an alternate in such a case, set\n"
+"submodule.alternateErrorStrategy to 'info' or, equivalently, clone with\n"
+"'--reference-if-able' instead of '--reference'."
+);
+
+static int add_possible_reference_from_superproject(
+		struct object_directory *odb, void *sas_cb)
+{
+	struct submodule_alternate_setup *sas = sas_cb;
+	size_t len;
+
+	/*
+	 * If the alternate object store is another repository, try the
+	 * standard layout with .git/(modules/<name>)+/objects
+	 */
+	if (strip_suffix(odb->path, "/objects", &len)) {
+		struct repository alternate;
+		char *sm_alternate;
+		struct strbuf sb = STRBUF_INIT;
+		struct strbuf err = STRBUF_INIT;
+		strbuf_add(&sb, odb->path, len);
+
+		if (repo_init(&alternate, sb.buf, NULL) < 0)
+			die(_("could not get a repository handle for gitdir '%s'"),
+			    sb.buf);
+
+		/*
+		 * We need to end the new path with '/' to mark it as a dir,
+		 * otherwise a submodule name containing '/' will be broken
+		 * as the last part of a missing submodule reference would
+		 * be taken as a file name.
+		 */
+		strbuf_reset(&sb);
+		submodule_name_to_gitdir(&sb, &alternate, sas->submodule_name);
+		strbuf_addch(&sb, '/');
+		repo_clear(&alternate);
+
+		sm_alternate = compute_alternate_path(sb.buf, &err);
+		if (sm_alternate) {
+			char *p = strbuf_detach(&sb, NULL);
+
+			string_list_append(sas->reference, p)->util = p;
+			free(sm_alternate);
+		} else {
+			switch (sas->error_mode) {
+			case SUBMODULE_ALTERNATE_ERROR_DIE:
+				if (advice_enabled(ADVICE_SUBMODULE_ALTERNATE_ERROR_STRATEGY_DIE))
+					advise(_(alternate_error_advice));
+				die(_("submodule '%s' cannot add alternate: %s"),
+				    sas->submodule_name, err.buf);
+			case SUBMODULE_ALTERNATE_ERROR_INFO:
+				fprintf_ln(stderr, _("submodule '%s' cannot add alternate: %s"),
+					sas->submodule_name, err.buf);
+			case SUBMODULE_ALTERNATE_ERROR_IGNORE:
+				; /* nothing */
+			}
+		}
+
+		strbuf_release(&err);
+		strbuf_release(&sb);
+	}
+
+	return 0;
+}
+
+static void prepare_possible_alternates(const char *sm_name,
+		struct string_list *reference)
+{
+	char *sm_alternate = NULL, *error_strategy = NULL;
+	struct submodule_alternate_setup sas = SUBMODULE_ALTERNATE_SETUP_INIT;
+
+	git_config_get_string("submodule.alternateLocation", &sm_alternate);
+	if (!sm_alternate)
+		return;
+
+	git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
+
+	if (!error_strategy)
+		error_strategy = xstrdup("die");
+
+	sas.submodule_name = sm_name;
+	sas.reference = reference;
+	if (!strcmp(error_strategy, "die"))
+		sas.error_mode = SUBMODULE_ALTERNATE_ERROR_DIE;
+	else if (!strcmp(error_strategy, "info"))
+		sas.error_mode = SUBMODULE_ALTERNATE_ERROR_INFO;
+	else if (!strcmp(error_strategy, "ignore"))
+		sas.error_mode = SUBMODULE_ALTERNATE_ERROR_IGNORE;
+	else
+		die(_("Value '%s' for submodule.alternateErrorStrategy is not recognized"), error_strategy);
+
+	if (!strcmp(sm_alternate, "superproject"))
+		foreach_alt_odb(add_possible_reference_from_superproject, &sas);
+	else if (!strcmp(sm_alternate, "no"))
+		; /* do nothing */
+	else
+		die(_("Value '%s' for submodule.alternateLocation is not recognized"), sm_alternate);
+
+	free(sm_alternate);
+	free(error_strategy);
+}
+
+static char *clone_submodule_sm_gitdir(const char *name)
+{
+	struct strbuf sb = STRBUF_INIT;
+	char *sm_gitdir;
+
+	submodule_name_to_gitdir(&sb, the_repository, name);
+	sm_gitdir = absolute_pathdup(sb.buf);
+	strbuf_release(&sb);
+
+	return sm_gitdir;
+}
+
+static int dir_contains_only_dotgit(const char *path)
+{
+	DIR *dir = opendir(path);
+	struct dirent *e;
+	int ret = 1;
+
+	if (!dir)
+		return 0;
+
+	e = readdir_skip_dot_and_dotdot(dir);
+	if (!e)
+		ret = 0;
+	else if (strcmp(DEFAULT_GIT_DIR_ENVIRONMENT, e->d_name) ||
+		 (e = readdir_skip_dot_and_dotdot(dir))) {
+		error("unexpected item '%s' in '%s'", e->d_name, path);
+		ret = 0;
+	}
+
+	closedir(dir);
+	return ret;
+}
+
+static int clone_submodule(const struct module_clone_data *clone_data,
+			   struct string_list *reference)
+{
+	char *p;
+	char *sm_gitdir = clone_submodule_sm_gitdir(clone_data->name);
+	char *sm_alternate = NULL, *error_strategy = NULL;
+	struct stat st;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	const char *clone_data_path = clone_data->path;
+	char *to_free = NULL;
+
+	if (validate_submodule_path(clone_data_path) < 0)
+		exit(128);
+
+	if (!is_absolute_path(clone_data->path))
+		clone_data_path = to_free = xstrfmt("%s/%s", repo_get_work_tree(the_repository),
+						    clone_data->path);
+
+	if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
+		die(_("refusing to create/use '%s' in another submodule's "
+		      "git dir"), sm_gitdir);
+
+	if (!file_exists(sm_gitdir)) {
+		if (clone_data->require_init && !stat(clone_data_path, &st) &&
+		    !is_empty_dir(clone_data_path))
+			die(_("directory not empty: '%s'"), clone_data_path);
+
+		if (safe_create_leading_directories_const(sm_gitdir) < 0)
+			die(_("could not create directory '%s'"), sm_gitdir);
+
+		prepare_possible_alternates(clone_data->name, reference);
+
+		strvec_push(&cp.args, "clone");
+		strvec_push(&cp.args, "--no-checkout");
+		if (clone_data->quiet)
+			strvec_push(&cp.args, "--quiet");
+		if (clone_data->progress)
+			strvec_push(&cp.args, "--progress");
+		if (clone_data->depth > 0)
+			strvec_pushf(&cp.args, "--depth=%d", clone_data->depth);
+		if (reference->nr) {
+			struct string_list_item *item;
+
+			for_each_string_list_item(item, reference)
+				strvec_pushl(&cp.args, "--reference",
+					     item->string, NULL);
+		}
+		if (clone_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+			strvec_pushf(&cp.args, "--ref-format=%s",
+				     ref_storage_format_to_name(clone_data->ref_storage_format));
+		if (clone_data->dissociate)
+			strvec_push(&cp.args, "--dissociate");
+		if (sm_gitdir && *sm_gitdir)
+			strvec_pushl(&cp.args, "--separate-git-dir", sm_gitdir, NULL);
+		if (clone_data->filter_options && clone_data->filter_options->choice)
+			strvec_pushf(&cp.args, "--filter=%s",
+				     expand_list_objects_filter_spec(
+					     clone_data->filter_options));
+		if (clone_data->single_branch >= 0)
+			strvec_push(&cp.args, clone_data->single_branch ?
+				    "--single-branch" :
+				    "--no-single-branch");
+
+		strvec_push(&cp.args, "--");
+		strvec_push(&cp.args, clone_data->url);
+		strvec_push(&cp.args, clone_data_path);
+
+		cp.git_cmd = 1;
+		prepare_submodule_repo_env(&cp.env);
+		cp.no_stdin = 1;
+
+		if(run_command(&cp))
+			die(_("clone of '%s' into submodule path '%s' failed"),
+			    clone_data->url, clone_data_path);
+
+		if (clone_data->require_init && !stat(clone_data_path, &st) &&
+		    !dir_contains_only_dotgit(clone_data_path)) {
+			char *dot_git = xstrfmt("%s/.git", clone_data_path);
+			unlink(dot_git);
+			free(dot_git);
+			die(_("directory not empty: '%s'"), clone_data_path);
+		}
+	} else {
+		char *path;
+
+		if (clone_data->require_init && !stat(clone_data_path, &st) &&
+		    !is_empty_dir(clone_data_path))
+			die(_("directory not empty: '%s'"), clone_data_path);
+		if (safe_create_leading_directories_const(clone_data_path) < 0)
+			die(_("could not create directory '%s'"), clone_data_path);
+		path = xstrfmt("%s/index", sm_gitdir);
+		unlink_or_warn(path);
+		free(path);
+	}
+
+	/*
+	 * We already performed this check at the beginning of this function,
+	 * before cloning the objects. This tries to detect racy behavior e.g.
+	 * in parallel clones, where another process could easily have made the
+	 * gitdir nested _after_ it was created.
+	 *
+	 * To prevent further harm coming from this unintentionally-nested
+	 * gitdir, let's disable it by deleting the `HEAD` file.
+	 */
+	if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0) {
+		char *head = xstrfmt("%s/HEAD", sm_gitdir);
+		unlink(head);
+		free(head);
+		die(_("refusing to create/use '%s' in another submodule's "
+		      "git dir"), sm_gitdir);
+	}
+
+	connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);
+
+	p = git_pathdup_submodule(clone_data_path, "config");
+	if (!p)
+		die(_("could not get submodule directory for '%s'"), clone_data_path);
+
+	/* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
+	git_config_get_string("submodule.alternateLocation", &sm_alternate);
+	if (sm_alternate)
+		git_config_set_in_file(p, "submodule.alternateLocation",
+				       sm_alternate);
+	git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
+	if (error_strategy)
+		git_config_set_in_file(p, "submodule.alternateErrorStrategy",
+				       error_strategy);
+
+	free(sm_alternate);
+	free(error_strategy);
+
+	free(sm_gitdir);
+	free(p);
+	free(to_free);
+	return 0;
+}
+
+static int module_clone(int argc, const char **argv, const char *prefix,
+			struct repository *repo UNUSED)
+{
+	int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
+	struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
+	struct string_list reference = STRING_LIST_INIT_NODUP;
+	struct list_objects_filter_options filter_options =
+		LIST_OBJECTS_FILTER_INIT;
+	const char *ref_storage_format = NULL;
+
+	struct option module_clone_options[] = {
+		OPT_STRING(0, "prefix", &clone_data.prefix,
+			   N_("path"),
+			   N_("alternative anchor for relative paths")),
+		OPT_STRING(0, "path", &clone_data.path,
+			   N_("path"),
+			   N_("where the new submodule will be cloned to")),
+		OPT_STRING(0, "name", &clone_data.name,
+			   N_("string"),
+			   N_("name of the new submodule")),
+		OPT_STRING(0, "url", &clone_data.url,
+			   N_("string"),
+			   N_("url where to clone the submodule from")),
+		OPT_STRING_LIST(0, "reference", &reference,
+			   N_("repo"),
+			   N_("reference repository")),
+		OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+			   N_("specify the reference format to use")),
+		OPT_BOOL(0, "dissociate", &dissociate,
+			   N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &clone_data.depth,
+			   N_("depth for shallow clones")),
+		OPT__QUIET(&quiet, "suppress output for cloning a submodule"),
+		OPT_BOOL(0, "progress", &progress,
+			   N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &require_init,
+			   N_("disallow cloning into non-empty directory")),
+		OPT_BOOL(0, "single-branch", &clone_data.single_branch,
+			 N_("clone only one branch, HEAD or --branch")),
+		OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule--helper clone [--prefix=<path>] [--quiet] "
+		   "[--reference <repository>] [--name <name>] [--depth <depth>] "
+		   "[--single-branch] [--filter <filter-spec>] "
+		   "--url <url> --path <path>"),
+		NULL
+	};
+
+	argc = parse_options(argc, argv, prefix, module_clone_options,
+			     git_submodule_helper_usage, 0);
+
+	if (ref_storage_format) {
+		clone_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+		if (clone_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown ref storage format '%s'"), ref_storage_format);
+	}
+	clone_data.dissociate = !!dissociate;
+	clone_data.quiet = !!quiet;
+	clone_data.progress = !!progress;
+	clone_data.require_init = !!require_init;
+	clone_data.filter_options = &filter_options;
+
+	if (argc || !clone_data.url || !clone_data.path || !*(clone_data.path))
+		usage_with_options(git_submodule_helper_usage,
+				   module_clone_options);
+
+	clone_submodule(&clone_data, &reference);
+	list_objects_filter_release(&filter_options);
+	string_list_clear(&reference, 1);
+	return 0;
+}
+
+static int determine_submodule_update_strategy(struct repository *r,
+					       int just_cloned,
+					       const char *path,
+					       enum submodule_update_type update,
+					       struct submodule_update_strategy *out)
+{
+	const struct submodule *sub = submodule_from_path(r, null_oid(), path);
+	char *key;
+	const char *val;
+	int ret;
+
+	key = xstrfmt("submodule.%s.update", sub->name);
+
+	if (update) {
+		out->type = update;
+	} else if (!repo_config_get_string_tmp(r, key, &val)) {
+		if (parse_submodule_update_strategy(val, out) < 0) {
+			ret = die_message(_("Invalid update mode '%s' configured for submodule path '%s'"),
+					  val, path);
+			goto cleanup;
+		}
+	} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
+		if (sub->update_strategy.type == SM_UPDATE_COMMAND)
+			BUG("how did we read update = !command from .gitmodules?");
+		out->type = sub->update_strategy.type;
+		out->command = sub->update_strategy.command;
+	} else
+		out->type = SM_UPDATE_CHECKOUT;
+
+	if (just_cloned &&
+	    (out->type == SM_UPDATE_MERGE ||
+	     out->type == SM_UPDATE_REBASE ||
+	     out->type == SM_UPDATE_NONE))
+		out->type = SM_UPDATE_CHECKOUT;
+
+	ret = 0;
+cleanup:
+	free(key);
+	return ret;
+}
+
+struct update_clone_data {
+	const struct submodule *sub;
+	struct object_id oid;
+	unsigned just_cloned;
+};
+
+struct submodule_update_clone {
+	/* index into 'update_data.list', the list of submodules to look into for cloning */
+	int current;
+
+	/* configuration parameters which are passed on to the children */
+	const struct update_data *update_data;
+
+	/* to be consumed by update_submodule() */
+	struct update_clone_data *update_clone;
+	int update_clone_nr; int update_clone_alloc;
+
+	/* If we want to stop as fast as possible and return an error */
+	unsigned quickstop : 1;
+
+	/* failed clones to be retried again */
+	const struct cache_entry **failed_clones;
+	int failed_clones_nr, failed_clones_alloc;
+};
+#define SUBMODULE_UPDATE_CLONE_INIT { 0 }
+
+static void submodule_update_clone_release(struct submodule_update_clone *suc)
+{
+	free(suc->update_clone);
+	free(suc->failed_clones);
+}
+
+struct update_data {
+	const char *prefix;
+	const char *super_prefix;
+	char *displaypath;
+	enum submodule_update_type update_default;
+	struct object_id suboid;
+	struct string_list references;
+	struct submodule_update_strategy update_strategy;
+	struct list_objects_filter_options *filter_options;
+	struct module_list list;
+	enum ref_storage_format ref_storage_format;
+	int depth;
+	int max_jobs;
+	int single_branch;
+	int recommend_shallow;
+	unsigned int require_init;
+	unsigned int force;
+	unsigned int quiet;
+	unsigned int nofetch;
+	unsigned int remote;
+	unsigned int progress;
+	unsigned int dissociate;
+	unsigned int init;
+	unsigned int warn_if_uninitialized;
+	unsigned int recursive;
+
+	/* copied over from update_clone_data */
+	struct object_id oid;
+	unsigned int just_cloned;
+	const char *sm_path;
+};
+#define UPDATE_DATA_INIT { \
+	.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
+	.list = MODULE_LIST_INIT, \
+	.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
+	.recommend_shallow = -1, \
+	.references = STRING_LIST_INIT_DUP, \
+	.single_branch = -1, \
+	.max_jobs = 1, \
+}
+
+static void update_data_release(struct update_data *ud)
+{
+	free(ud->displaypath);
+	submodule_update_strategy_release(&ud->update_strategy);
+	module_list_release(&ud->list);
+}
+
+static void next_submodule_warn_missing(struct submodule_update_clone *suc,
+		struct strbuf *out, const char *displaypath)
+{
+	/*
+	 * Only mention uninitialized submodules when their
+	 * paths have been specified.
+	 */
+	if (suc->update_data->warn_if_uninitialized) {
+		strbuf_addf(out,
+			_("Submodule path '%s' not initialized"),
+			displaypath);
+		strbuf_addch(out, '\n');
+		strbuf_addstr(out,
+			_("Maybe you want to use 'update --init'?"));
+		strbuf_addch(out, '\n');
+	}
+}
+
+/**
+ * Determine whether 'ce' needs to be cloned. If so, prepare the 'child' to
+ * run the clone. Returns 1 if 'ce' needs to be cloned, 0 otherwise.
+ */
+static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
+					   struct child_process *child,
+					   struct submodule_update_clone *suc,
+					   struct strbuf *out)
+{
+	const struct submodule *sub = NULL;
+	const char *url = NULL;
+	const char *update_string;
+	enum submodule_update_type update_type;
+	char *key;
+	const struct update_data *ud = suc->update_data;
+	char *displaypath = get_submodule_displaypath(ce->name, ud->prefix,
+						      ud->super_prefix);
+	struct strbuf sb = STRBUF_INIT;
+	int needs_cloning = 0;
+	int need_free_url = 0;
+
+	if (ce_stage(ce)) {
+		strbuf_addf(out, _("Skipping unmerged submodule %s"), displaypath);
+		strbuf_addch(out, '\n');
+		goto cleanup;
+	}
+
+	sub = submodule_from_path(the_repository, null_oid(), ce->name);
+
+	if (!sub) {
+		next_submodule_warn_missing(suc, out, displaypath);
+		goto cleanup;
+	}
+
+	key = xstrfmt("submodule.%s.update", sub->name);
+	if (!repo_config_get_string_tmp(the_repository, key, &update_string)) {
+		update_type = parse_submodule_update_type(update_string);
+	} else {
+		update_type = sub->update_strategy.type;
+	}
+	free(key);
+
+	if (suc->update_data->update_strategy.type == SM_UPDATE_NONE
+	    || (suc->update_data->update_strategy.type == SM_UPDATE_UNSPECIFIED
+		&& update_type == SM_UPDATE_NONE)) {
+		strbuf_addf(out, _("Skipping submodule '%s'"), displaypath);
+		strbuf_addch(out, '\n');
+		goto cleanup;
+	}
+
+	/* Check if the submodule has been initialized. */
+	if (!is_submodule_active(the_repository, ce->name)) {
+		next_submodule_warn_missing(suc, out, displaypath);
+		goto cleanup;
+	}
+
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "submodule.%s.url", sub->name);
+	if (repo_config_get_string_tmp(the_repository, sb.buf, &url)) {
+		if (sub->url && (starts_with_dot_slash(sub->url) ||
+				 starts_with_dot_dot_slash(sub->url))) {
+			url = resolve_relative_url(sub->url, NULL, 0);
+			need_free_url = 1;
+		} else
+			url = sub->url;
+	}
+
+	if (!url)
+		die(_("cannot clone submodule '%s' without a URL"), sub->name);
+
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/.git", ce->name);
+	needs_cloning = !file_exists(sb.buf);
+
+	ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1,
+		   suc->update_clone_alloc);
+	oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid);
+	suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning;
+	suc->update_clone[suc->update_clone_nr].sub = sub;
+	suc->update_clone_nr++;
+
+	if (!needs_cloning)
+		goto cleanup;
+
+	child->git_cmd = 1;
+	child->no_stdin = 1;
+	child->stdout_to_stderr = 1;
+	child->err = -1;
+	strvec_push(&child->args, "submodule--helper");
+	strvec_push(&child->args, "clone");
+	if (suc->update_data->progress)
+		strvec_push(&child->args, "--progress");
+	if (suc->update_data->quiet)
+		strvec_push(&child->args, "--quiet");
+	if (suc->update_data->prefix)
+		strvec_pushl(&child->args, "--prefix", suc->update_data->prefix, NULL);
+	if (suc->update_data->recommend_shallow && sub->recommend_shallow == 1)
+		strvec_push(&child->args, "--depth=1");
+	else if (suc->update_data->depth)
+		strvec_pushf(&child->args, "--depth=%d", suc->update_data->depth);
+	if (suc->update_data->filter_options && suc->update_data->filter_options->choice)
+		strvec_pushf(&child->args, "--filter=%s",
+			     expand_list_objects_filter_spec(suc->update_data->filter_options));
+	if (suc->update_data->require_init)
+		strvec_push(&child->args, "--require-init");
+	if (suc->update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+		strvec_pushf(&child->args, "--ref-format=%s",
+			     ref_storage_format_to_name(suc->update_data->ref_storage_format));
+	strvec_pushl(&child->args, "--path", sub->path, NULL);
+	strvec_pushl(&child->args, "--name", sub->name, NULL);
+	strvec_pushl(&child->args, "--url", url, NULL);
+	if (suc->update_data->references.nr) {
+		struct string_list_item *item;
+
+		for_each_string_list_item(item, &suc->update_data->references)
+			strvec_pushl(&child->args, "--reference", item->string, NULL);
+	}
+	if (suc->update_data->dissociate)
+		strvec_push(&child->args, "--dissociate");
+	if (suc->update_data->single_branch >= 0)
+		strvec_push(&child->args, suc->update_data->single_branch ?
+					      "--single-branch" :
+					      "--no-single-branch");
+
+cleanup:
+	free(displaypath);
+	strbuf_release(&sb);
+	if (need_free_url)
+		free((void*)url);
+
+	return needs_cloning;
+}
+
+static int update_clone_get_next_task(struct child_process *child,
+				      struct strbuf *err,
+				      void *suc_cb,
+				      void **idx_task_cb)
+{
+	struct submodule_update_clone *suc = suc_cb;
+	const struct cache_entry *ce;
+	int index;
+
+	for (; suc->current < suc->update_data->list.nr; suc->current++) {
+		ce = suc->update_data->list.entries[suc->current];
+		if (prepare_to_clone_next_submodule(ce, child, suc, err)) {
+			int *p = xmalloc(sizeof(*p));
+
+			*p = suc->current;
+			*idx_task_cb = p;
+			suc->current++;
+			return 1;
+		}
+	}
+
+	/*
+	 * The loop above tried cloning each submodule once, now try the
+	 * stragglers again, which we can imagine as an extension of the
+	 * entry list.
+	 */
+	index = suc->current - suc->update_data->list.nr;
+	if (index < suc->failed_clones_nr) {
+		int *p;
+
+		ce = suc->failed_clones[index];
+		if (!prepare_to_clone_next_submodule(ce, child, suc, err)) {
+			suc->current ++;
+			strbuf_addstr(err, "BUG: submodule considered for "
+					   "cloning, doesn't need cloning "
+					   "any more?\n");
+			return 0;
+		}
+		p = xmalloc(sizeof(*p));
+		*p = suc->current;
+		*idx_task_cb = p;
+		suc->current ++;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int update_clone_start_failure(struct strbuf *err UNUSED,
+				      void *suc_cb,
+				      void *idx_task_cb UNUSED)
+{
+	struct submodule_update_clone *suc = suc_cb;
+
+	suc->quickstop = 1;
+	return 1;
+}
+
+static int update_clone_task_finished(int result,
+				      struct strbuf *err,
+				      void *suc_cb,
+				      void *idx_task_cb)
+{
+	const struct cache_entry *ce;
+	struct submodule_update_clone *suc = suc_cb;
+	int *idxP = idx_task_cb;
+	int idx = *idxP;
+
+	free(idxP);
+
+	if (!result)
+		return 0;
+
+	if (idx < suc->update_data->list.nr) {
+		ce  = suc->update_data->list.entries[idx];
+		strbuf_addf(err, _("Failed to clone '%s'. Retry scheduled"),
+			    ce->name);
+		strbuf_addch(err, '\n');
+		ALLOC_GROW(suc->failed_clones,
+			   suc->failed_clones_nr + 1,
+			   suc->failed_clones_alloc);
+		suc->failed_clones[suc->failed_clones_nr++] = ce;
+		return 0;
+	} else {
+		idx -= suc->update_data->list.nr;
+		ce  = suc->failed_clones[idx];
+		strbuf_addf(err, _("Failed to clone '%s' a second time, aborting"),
+			    ce->name);
+		strbuf_addch(err, '\n');
+		suc->quickstop = 1;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int git_update_clone_config(const char *var, const char *value,
+				   const struct config_context *ctx,
+				   void *cb)
+{
+	int *max_jobs = cb;
+
+	if (!strcmp(var, "submodule.fetchjobs"))
+		*max_jobs = parse_submodule_fetchjobs(var, value, ctx->kvi);
+	return 0;
+}
+
+static int is_tip_reachable(const char *path, const struct object_id *oid)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+	struct strbuf rev = STRBUF_INIT;
+	char *hex = oid_to_hex(oid);
+	int reachable;
+
+	cp.git_cmd = 1;
+	cp.dir = path;
+	cp.no_stderr = 1;
+	strvec_pushl(&cp.args, "rev-list", "-n", "1", hex, "--not", "--all", NULL);
+
+	prepare_submodule_repo_env(&cp.env);
+
+	if (capture_command(&cp, &rev, GIT_MAX_HEXSZ + 1) || rev.len)
+		reachable = 0;
+	else
+		reachable = 1;
+
+	strbuf_release(&rev);
+	return reachable;
+}
+
+static int fetch_in_submodule(const char *module_path, int depth, int quiet,
+			      const struct object_id *oid)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	prepare_submodule_repo_env(&cp.env);
+	cp.git_cmd = 1;
+	cp.dir = module_path;
+
+	strvec_push(&cp.args, "fetch");
+	if (quiet)
+		strvec_push(&cp.args, "--quiet");
+	if (depth)
+		strvec_pushf(&cp.args, "--depth=%d", depth);
+	if (oid) {
+		char *hex = oid_to_hex(oid);
+		char *remote;
+		int code;
+
+		code = get_default_remote_submodule(module_path, &remote);
+		if (code) {
+			child_process_clear(&cp);
+			return code;
+		}
+
+		strvec_pushl(&cp.args, remote, hex, NULL);
+		free(remote);
+	}
+
+	return run_command(&cp);
+}
+
+static int run_update_command(const struct update_data *ud, int subforce)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+	char *oid = oid_to_hex(&ud->oid);
+	int ret;
+
+	switch (ud->update_strategy.type) {
+	case SM_UPDATE_CHECKOUT:
+		cp.git_cmd = 1;
+		strvec_pushl(&cp.args, "checkout", "-q", NULL);
+		if (subforce)
+			strvec_push(&cp.args, "-f");
+		break;
+	case SM_UPDATE_REBASE:
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "rebase");
+		if (ud->quiet)
+			strvec_push(&cp.args, "--quiet");
+		break;
+	case SM_UPDATE_MERGE:
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "merge");
+		if (ud->quiet)
+			strvec_push(&cp.args, "--quiet");
+		break;
+	case SM_UPDATE_COMMAND:
+		cp.use_shell = 1;
+		strvec_push(&cp.args, ud->update_strategy.command);
+		break;
+	default:
+		BUG("unexpected update strategy type: %d",
+		    ud->update_strategy.type);
+	}
+	strvec_push(&cp.args, oid);
+
+	cp.dir = ud->sm_path;
+	prepare_submodule_repo_env(&cp.env);
+	if ((ret = run_command(&cp))) {
+		switch (ud->update_strategy.type) {
+		case SM_UPDATE_CHECKOUT:
+			die_message(_("Unable to checkout '%s' in submodule path '%s'"),
+				    oid, ud->displaypath);
+			/* No "ret" assignment, use "git checkout"'s */
+			break;
+		case SM_UPDATE_REBASE:
+			ret = die_message(_("Unable to rebase '%s' in submodule path '%s'"),
+					  oid, ud->displaypath);
+			break;
+		case SM_UPDATE_MERGE:
+			ret = die_message(_("Unable to merge '%s' in submodule path '%s'"),
+					  oid, ud->displaypath);
+			break;
+		case SM_UPDATE_COMMAND:
+			ret = die_message(_("Execution of '%s %s' failed in submodule path '%s'"),
+					  ud->update_strategy.command, oid, ud->displaypath);
+			break;
+		default:
+			BUG("unexpected update strategy type: %d",
+			    ud->update_strategy.type);
+		}
+
+		return ret;
+	}
+
+	if (ud->quiet)
+		return 0;
+
+	switch (ud->update_strategy.type) {
+	case SM_UPDATE_CHECKOUT:
+		printf(_("Submodule path '%s': checked out '%s'\n"),
+		       ud->displaypath, oid);
+		break;
+	case SM_UPDATE_REBASE:
+		printf(_("Submodule path '%s': rebased into '%s'\n"),
+		       ud->displaypath, oid);
+		break;
+	case SM_UPDATE_MERGE:
+		printf(_("Submodule path '%s': merged in '%s'\n"),
+		       ud->displaypath, oid);
+		break;
+	case SM_UPDATE_COMMAND:
+		printf(_("Submodule path '%s': '%s %s'\n"),
+		       ud->displaypath, ud->update_strategy.command, oid);
+		break;
+	default:
+		BUG("unexpected update strategy type: %d",
+		    ud->update_strategy.type);
+	}
+
+	return 0;
+}
+
+static int run_update_procedure(const struct update_data *ud)
+{
+	int subforce = is_null_oid(&ud->suboid) || ud->force;
+
+	if (!ud->nofetch) {
+		/*
+		 * Run fetch only if `oid` isn't present or it
+		 * is not reachable from a ref.
+		 */
+		if (!is_tip_reachable(ud->sm_path, &ud->oid) &&
+		    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, NULL) &&
+		    !ud->quiet)
+			fprintf_ln(stderr,
+				   _("Unable to fetch in submodule path '%s'; "
+				     "trying to directly fetch %s:"),
+				   ud->displaypath, oid_to_hex(&ud->oid));
+		/*
+		 * Now we tried the usual fetch, but `oid` may
+		 * not be reachable from any of the refs.
+		 */
+		if (!is_tip_reachable(ud->sm_path, &ud->oid) &&
+		    fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid))
+			return die_message(_("Fetched in submodule path '%s', but it did not "
+					     "contain %s. Direct fetching of that commit failed."),
+					   ud->displaypath, oid_to_hex(&ud->oid));
+	}
+
+	return run_update_command(ud, subforce);
+}
+
+static int remote_submodule_branch(const char *path, const char **branch)
+{
+	const struct submodule *sub;
+	char *key;
+	*branch = NULL;
+
+	sub = submodule_from_path(the_repository, null_oid(), path);
+	if (!sub)
+		return die_message(_("could not initialize submodule at path '%s'"),
+				   path);
+
+	key = xstrfmt("submodule.%s.branch", sub->name);
+	if (repo_config_get_string_tmp(the_repository, key, branch))
+		*branch = sub->branch;
+	free(key);
+
+	if (!*branch) {
+		*branch = "HEAD";
+		return 0;
+	}
+
+	if (!strcmp(*branch, ".")) {
+		const char *refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+							      "HEAD", 0, NULL,
+							      NULL);
+
+		if (!refname)
+			return die_message(_("No such ref: %s"), "HEAD");
+
+		/* detached HEAD */
+		if (!strcmp(refname, "HEAD"))
+			return die_message(_("Submodule (%s) branch configured to inherit "
+					     "branch from superproject, but the superproject "
+					     "is not on any branch"), sub->name);
+
+		if (!skip_prefix(refname, "refs/heads/", &refname))
+			return die_message(_("Expecting a full ref name, got %s"),
+					   refname);
+
+		*branch = refname;
+		return 0;
+	}
+
+	/* Our "branch" is coming from repo_config_get_string_tmp() */
+	return 0;
+}
+
+static int ensure_core_worktree(const char *path)
+{
+	const char *cw;
+	struct repository subrepo;
+
+	if (repo_submodule_init(&subrepo, the_repository, path, null_oid()))
+		return die_message(_("could not get a repository handle for submodule '%s'"),
+				   path);
+
+	if (!repo_config_get_string_tmp(&subrepo, "core.worktree", &cw)) {
+		char *cfg_file, *abs_path;
+		const char *rel_path;
+		struct strbuf sb = STRBUF_INIT;
+
+		cfg_file = repo_git_path(&subrepo, "config");
+
+		abs_path = absolute_pathdup(path);
+		rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
+
+		git_config_set_in_file(cfg_file, "core.worktree", rel_path);
+
+		free(cfg_file);
+		free(abs_path);
+		strbuf_release(&sb);
+	}
+
+	repo_clear(&subrepo);
+	return 0;
+}
+
+static const char *submodule_update_type_to_label(enum submodule_update_type type)
+{
+	switch (type) {
+	case SM_UPDATE_CHECKOUT:
+		return "checkout";
+	case SM_UPDATE_MERGE:
+		return "merge";
+	case SM_UPDATE_REBASE:
+		return "rebase";
+	case SM_UPDATE_UNSPECIFIED:
+	case SM_UPDATE_NONE:
+	case SM_UPDATE_COMMAND:
+		break;
+	}
+	BUG("unreachable with type %d", type);
+}
+
+static void update_data_to_args(const struct update_data *update_data,
+				struct strvec *args)
+{
+	enum submodule_update_type update_type = update_data->update_default;
+
+	strvec_pushl(args, "submodule--helper", "update", "--recursive", NULL);
+	if (update_data->displaypath)
+		strvec_pushf(args, "--super-prefix=%s/",
+			     update_data->displaypath);
+	strvec_pushf(args, "--jobs=%d", update_data->max_jobs);
+	if (update_data->quiet)
+		strvec_push(args, "--quiet");
+	if (update_data->force)
+		strvec_push(args, "--force");
+	if (update_data->init)
+		strvec_push(args, "--init");
+	if (update_data->remote)
+		strvec_push(args, "--remote");
+	if (update_data->nofetch)
+		strvec_push(args, "--no-fetch");
+	if (update_data->dissociate)
+		strvec_push(args, "--dissociate");
+	if (update_data->progress)
+		strvec_push(args, "--progress");
+	if (update_data->require_init)
+		strvec_push(args, "--require-init");
+	if (update_data->depth)
+		strvec_pushf(args, "--depth=%d", update_data->depth);
+	if (update_type != SM_UPDATE_UNSPECIFIED)
+		strvec_pushf(args, "--%s",
+			     submodule_update_type_to_label(update_type));
+
+	if (update_data->references.nr) {
+		struct string_list_item *item;
+
+		for_each_string_list_item(item, &update_data->references)
+			strvec_pushl(args, "--reference", item->string, NULL);
+	}
+	if (update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
+		strvec_pushf(args, "--ref-format=%s",
+			     ref_storage_format_to_name(update_data->ref_storage_format));
+	if (update_data->filter_options && update_data->filter_options->choice)
+		strvec_pushf(args, "--filter=%s",
+				expand_list_objects_filter_spec(
+					update_data->filter_options));
+	if (update_data->recommend_shallow == 0)
+		strvec_push(args, "--no-recommend-shallow");
+	else if (update_data->recommend_shallow == 1)
+		strvec_push(args, "--recommend-shallow");
+	if (update_data->single_branch >= 0)
+		strvec_push(args, update_data->single_branch ?
+				    "--single-branch" :
+				    "--no-single-branch");
+}
+
+static int update_submodule(struct update_data *update_data)
+{
+	int ret;
+
+	if (validate_submodule_path(update_data->sm_path) < 0)
+		return -1;
+
+	ret = determine_submodule_update_strategy(the_repository,
+						  update_data->just_cloned,
+						  update_data->sm_path,
+						  update_data->update_default,
+						  &update_data->update_strategy);
+	if (ret)
+		return ret;
+
+	if (update_data->just_cloned)
+		oidcpy(&update_data->suboid, null_oid());
+	else if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
+					  "HEAD", &update_data->suboid))
+		return die_message(_("Unable to find current revision in submodule path '%s'"),
+				   update_data->displaypath);
+
+	if (update_data->remote) {
+		char *remote_name;
+		const char *branch;
+		char *remote_ref;
+		int code;
+
+		code = get_default_remote_submodule(update_data->sm_path, &remote_name);
+		if (code)
+			return code;
+		code = remote_submodule_branch(update_data->sm_path, &branch);
+		if (code)
+			return code;
+		remote_ref = xstrfmt("refs/remotes/%s/%s", remote_name, branch);
+
+		free(remote_name);
+
+		if (!update_data->nofetch) {
+			if (fetch_in_submodule(update_data->sm_path, update_data->depth,
+					      0, NULL)) {
+				free(remote_ref);
+				return die_message(_("Unable to fetch in submodule path '%s'"),
+						   update_data->sm_path);
+			}
+		}
+
+		if (repo_resolve_gitlink_ref(the_repository, update_data->sm_path,
+					     remote_ref, &update_data->oid)) {
+			ret = die_message(_("Unable to find %s revision in submodule path '%s'"),
+					  remote_ref, update_data->sm_path);
+			free(remote_ref);
+			return ret;
+		}
+
+		free(remote_ref);
+	}
+
+	if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force) {
+		ret = run_update_procedure(update_data);
+		if (ret)
+			return ret;
+	}
+
+	if (update_data->recursive) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+		struct update_data next = *update_data;
+
+		next.prefix = NULL;
+		oidcpy(&next.oid, null_oid());
+		oidcpy(&next.suboid, null_oid());
+
+		cp.dir = update_data->sm_path;
+		cp.git_cmd = 1;
+		prepare_submodule_repo_env(&cp.env);
+		update_data_to_args(&next, &cp.args);
+
+		ret = run_command(&cp);
+		if (ret)
+			die_message(_("Failed to recurse into submodule path '%s'"),
+				    update_data->displaypath);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int update_submodules(struct update_data *update_data)
+{
+	int i, ret = 0;
+	struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
+	const struct run_process_parallel_opts opts = {
+		.tr2_category = "submodule",
+		.tr2_label = "parallel/update",
+
+		.processes = update_data->max_jobs,
+
+		.get_next_task = update_clone_get_next_task,
+		.start_failure = update_clone_start_failure,
+		.task_finished = update_clone_task_finished,
+		.data = &suc,
+	};
+
+	suc.update_data = update_data;
+	run_processes_parallel(&opts);
+
+	/*
+	 * We saved the output and put it out all at once now.
+	 * That means:
+	 * - the listener does not have to interleave their (checkout)
+	 *   work with our fetching.  The writes involved in a
+	 *   checkout involve more straightforward sequential I/O.
+	 * - the listener can avoid doing any work if fetching failed.
+	 */
+	if (suc.quickstop) {
+		ret = 1;
+		goto cleanup;
+	}
+
+	for (i = 0; i < suc.update_clone_nr; i++) {
+		struct update_clone_data ucd = suc.update_clone[i];
+		int code = 128;
+
+		oidcpy(&update_data->oid, &ucd.oid);
+		update_data->just_cloned = ucd.just_cloned;
+		update_data->sm_path = ucd.sub->path;
+
+		/*
+		 * Verify that the submodule path does not contain any
+		 * symlinks; if it does, it might have been tampered with.
+		 * TODO: allow exempting it via
+		 * `safe.submodule.path` or something
+		 */
+		if (validate_submodule_path(update_data->sm_path) < 0)
+			goto fail;
+
+		code = ensure_core_worktree(update_data->sm_path);
+		if (code)
+			goto fail;
+
+		update_data->displaypath = get_submodule_displaypath(
+			update_data->sm_path, update_data->prefix,
+			update_data->super_prefix);
+		code = update_submodule(update_data);
+		FREE_AND_NULL(update_data->displaypath);
+fail:
+		if (!code)
+			continue;
+		ret = code;
+		if (ret == 128)
+			goto cleanup;
+	}
+
+cleanup:
+	submodule_update_clone_release(&suc);
+	string_list_clear(&update_data->references, 0);
+	return ret;
+}
+
+static int module_update(int argc, const char **argv, const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	struct pathspec pathspec = { 0 };
+	struct pathspec pathspec2 = { 0 };
+	struct update_data opt = UPDATE_DATA_INIT;
+	struct list_objects_filter_options filter_options =
+		LIST_OBJECTS_FILTER_INIT;
+	const char *ref_storage_format = NULL;
+	int ret;
+	struct option module_update_options[] = {
+		OPT__SUPER_PREFIX(&opt.super_prefix),
+		OPT__FORCE(&opt.force, N_("force checkout updates"), 0),
+		OPT_BOOL(0, "init", &opt.init,
+			 N_("initialize uninitialized submodules before update")),
+		OPT_BOOL(0, "remote", &opt.remote,
+			 N_("use SHA-1 of submodule's remote tracking branch")),
+		OPT_BOOL(0, "recursive", &opt.recursive,
+			 N_("traverse submodules recursively")),
+		OPT_BOOL('N', "no-fetch", &opt.nofetch,
+			 N_("don't fetch new objects from the remote site")),
+		OPT_SET_INT(0, "checkout", &opt.update_default,
+			N_("use the 'checkout' update strategy (default)"),
+			SM_UPDATE_CHECKOUT),
+		OPT_SET_INT('m', "merge", &opt.update_default,
+			N_("use the 'merge' update strategy"),
+			SM_UPDATE_MERGE),
+		OPT_SET_INT('r', "rebase", &opt.update_default,
+			N_("use the 'rebase' update strategy"),
+			SM_UPDATE_REBASE),
+		OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
+			   N_("reference repository")),
+		OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+			   N_("specify the reference format to use")),
+		OPT_BOOL(0, "dissociate", &opt.dissociate,
+			   N_("use --reference only while cloning")),
+		OPT_INTEGER(0, "depth", &opt.depth,
+			   N_("create a shallow clone truncated to the "
+			      "specified number of revisions")),
+		OPT_INTEGER('j', "jobs", &opt.max_jobs,
+			    N_("parallel jobs")),
+		OPT_BOOL(0, "recommend-shallow", &opt.recommend_shallow,
+			    N_("whether the initial clone should follow the shallow recommendation")),
+		OPT__QUIET(&opt.quiet, N_("don't print cloning progress")),
+		OPT_BOOL(0, "progress", &opt.progress,
+			    N_("force cloning progress")),
+		OPT_BOOL(0, "require-init", &opt.require_init,
+			   N_("disallow cloning into non-empty directory, implies --init")),
+		OPT_BOOL(0, "single-branch", &opt.single_branch,
+			 N_("clone only one branch, HEAD or --branch")),
+		OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule [--quiet] update"
+		" [--init [--filter=<filter-spec>]] [--remote]"
+		" [-N|--no-fetch] [-f|--force]"
+		" [--checkout|--merge|--rebase]"
+		" [--[no-]recommend-shallow] [--reference <repository>]"
+		" [--recursive] [--[no-]single-branch] [--] [<path>...]"),
+		NULL
+	};
+
+	update_clone_config_from_gitmodules(&opt.max_jobs);
+	git_config(git_update_clone_config, &opt.max_jobs);
+
+	argc = parse_options(argc, argv, prefix, module_update_options,
+			     git_submodule_helper_usage, 0);
+
+	if (opt.require_init)
+		opt.init = 1;
+
+	if (filter_options.choice && !opt.init) {
+		usage_with_options(git_submodule_helper_usage,
+				   module_update_options);
+	}
+
+	if (ref_storage_format) {
+		opt.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+		if (opt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown ref storage format '%s'"), ref_storage_format);
+	}
+
+	opt.filter_options = &filter_options;
+	opt.prefix = prefix;
+
+	if (opt.update_default)
+		opt.update_strategy.type = opt.update_default;
+
+	if (module_list_compute(argv, prefix, &pathspec, &opt.list) < 0) {
+		ret = 1;
+		goto cleanup;
+	}
+
+	if (pathspec.nr)
+		opt.warn_if_uninitialized = 1;
+
+	if (opt.init) {
+		struct module_list list = MODULE_LIST_INIT;
+		struct init_cb info = INIT_CB_INIT;
+
+		if (module_list_compute(argv, opt.prefix,
+					&pathspec2, &list) < 0) {
+			module_list_release(&list);
+			ret = 1;
+			goto cleanup;
+		}
+
+		/*
+		 * If there are no path args and submodule.active is set then,
+		 * by default, only initialize 'active' modules.
+		 */
+		if (!argc && !git_config_get("submodule.active"))
+			module_list_active(&list);
+
+		info.prefix = opt.prefix;
+		info.super_prefix = opt.super_prefix;
+		if (opt.quiet)
+			info.flags |= OPT_QUIET;
+
+		for_each_listed_submodule(&list, init_submodule_cb, &info);
+		module_list_release(&list);
+	}
+
+	ret = update_submodules(&opt);
+cleanup:
+	update_data_release(&opt);
+	list_objects_filter_release(&filter_options);
+	clear_pathspec(&pathspec);
+	clear_pathspec(&pathspec2);
+	return ret;
+}
+
+static int push_check(int argc, const char **argv, const char *prefix UNUSED,
+		      struct repository *repo UNUSED)
+{
+	struct remote *remote;
+	const char *superproject_head;
+	char *head;
+	int detached_head = 0;
+	struct object_id head_oid;
+
+	if (argc < 3)
+		die("submodule--helper push-check requires at least 2 arguments");
+
+	/*
+	 * superproject's resolved head ref.
+	 * if HEAD then the superproject is in a detached head state, otherwise
+	 * it will be the resolved head ref.
+	 */
+	superproject_head = argv[1];
+	argv++;
+	argc--;
+	/* Get the submodule's head ref and determine if it is detached */
+	head = refs_resolve_refdup(get_main_ref_store(the_repository), "HEAD",
+				   0, &head_oid, NULL);
+	if (!head)
+		die(_("Failed to resolve HEAD as a valid ref."));
+	if (!strcmp(head, "HEAD"))
+		detached_head = 1;
+
+	/*
+	 * The remote must be configured.
+	 * This is to avoid pushing to the exact same URL as the parent.
+	 */
+	remote = pushremote_get(argv[1]);
+	if (!remote || remote->origin == REMOTE_UNCONFIGURED)
+		die("remote '%s' not configured", argv[1]);
+
+	/* Check the refspec */
+	if (argc > 2) {
+		int i;
+		struct ref *local_refs = get_local_heads();
+		struct refspec refspec = REFSPEC_INIT_PUSH;
+
+		refspec_appendn(&refspec, argv + 2, argc - 2);
+
+		for (i = 0; i < refspec.nr; i++) {
+			const struct refspec_item *rs = &refspec.items[i];
+
+			if (rs->pattern || rs->matching)
+				continue;
+
+			/* LHS must match a single ref */
+			switch (count_refspec_match(rs->src, local_refs, NULL)) {
+			case 1:
+				break;
+			case 0:
+				/*
+				 * If LHS matches 'HEAD' then we need to ensure
+				 * that it matches the same named branch
+				 * checked out in the superproject.
+				 */
+				if (!strcmp(rs->src, "HEAD")) {
+					if (!detached_head &&
+					    !strcmp(head, superproject_head))
+						break;
+					die("HEAD does not match the named branch in the superproject");
+				}
+				/* fallthrough */
+			default:
+				die("src refspec '%s' must name a ref",
+				    rs->src);
+			}
+		}
+
+		refspec_clear(&refspec);
+		free_refs(local_refs);
+	}
+	free(head);
+
+	return 0;
+}
+
+static int absorb_git_dirs(int argc, const char **argv, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	int i;
+	struct pathspec pathspec = { 0 };
+	struct module_list list = MODULE_LIST_INIT;
+	const char *super_prefix = NULL;
+	struct option embed_gitdir_options[] = {
+		OPT__SUPER_PREFIX(&super_prefix),
+		OPT_END()
+	};
+	const char *const git_submodule_helper_usage[] = {
+		N_("git submodule absorbgitdirs [<options>] [<path>...]"),
+		NULL
+	};
+	int ret = 1;
+
+	argc = parse_options(argc, argv, prefix, embed_gitdir_options,
+			     git_submodule_helper_usage, 0);
+
+	if (module_list_compute(argv, prefix, &pathspec, &list) < 0)
+		goto cleanup;
+
+	for (i = 0; i < list.nr; i++)
+		absorb_git_dir_into_superproject(list.entries[i]->name,
+						 super_prefix);
+
+	ret = 0;
+cleanup:
+	clear_pathspec(&pathspec);
+	module_list_release(&list);
+	return ret;
+}
+
+static int module_set_url(int argc, const char **argv, const char *prefix,
+			  struct repository *repo UNUSED)
+{
+	int quiet = 0, ret;
+	const char *newurl;
+	const char *path;
+	char *config_name;
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("suppress output for setting url of a submodule")),
+		OPT_END()
+	};
+	const char *const usage[] = {
+		N_("git submodule set-url [--quiet] <path> <newurl>"),
+		NULL
+	};
+	const struct submodule *sub;
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+	if (argc != 2 || !(path = argv[0]) || !(newurl = argv[1]))
+		usage_with_options(usage, options);
+
+	sub = submodule_from_path(the_repository, null_oid(), path);
+
+	if (!sub)
+		die(_("no submodule mapping found in .gitmodules for path '%s'"),
+		    path);
+
+	config_name = xstrfmt("submodule.%s.url", sub->name);
+	ret = config_set_in_gitmodules_file_gently(config_name, newurl);
+
+	if (!ret) {
+		repo_read_gitmodules(the_repository, 0);
+		sync_submodule(sub->path, prefix, NULL, quiet ? OPT_QUIET : 0);
+	}
+
+	free(config_name);
+	return !!ret;
+}
+
+static int module_set_branch(int argc, const char **argv, const char *prefix,
+			     struct repository *repo UNUSED)
+{
+	int opt_default = 0, ret;
+	const char *opt_branch = NULL;
+	const char *path;
+	char *config_name;
+	struct option options[] = {
+		/*
+		 * We accept the `quiet` option for uniformity across subcommands,
+		 * though there is nothing to make less verbose in this subcommand.
+		 */
+		OPT_NOOP_NOARG('q', "quiet"),
+
+		OPT_BOOL('d', "default", &opt_default,
+			N_("set the default tracking branch to master")),
+		OPT_STRING('b', "branch", &opt_branch, N_("branch"),
+			N_("set the default tracking branch")),
+		OPT_END()
+	};
+	const char *const usage[] = {
+		N_("git submodule set-branch [-q|--quiet] (-d|--default) <path>"),
+		N_("git submodule set-branch [-q|--quiet] (-b|--branch) <branch> <path>"),
+		NULL
+	};
+	const struct submodule *sub;
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+	if (!opt_branch && !opt_default)
+		die(_("--branch or --default required"));
+
+	if (opt_branch && opt_default)
+		die(_("options '%s' and '%s' cannot be used together"), "--branch", "--default");
+
+	if (argc != 1 || !(path = argv[0]))
+		usage_with_options(usage, options);
+
+	sub = submodule_from_path(the_repository, null_oid(), path);
+
+	if (!sub)
+		die(_("no submodule mapping found in .gitmodules for path '%s'"),
+		    path);
+
+	config_name = xstrfmt("submodule.%s.branch", sub->name);
+	ret = config_set_in_gitmodules_file_gently(config_name, opt_branch);
+
+	free(config_name);
+	return !!ret;
+}
+
+static int module_create_branch(int argc, const char **argv, const char *prefix,
+				struct repository *repo UNUSED)
+{
+	enum branch_track track;
+	int quiet = 0, force = 0, reflog = 0, dry_run = 0;
+	struct option options[] = {
+		OPT__QUIET(&quiet, N_("print only error messages")),
+		OPT__FORCE(&force, N_("force creation"), 0),
+		OPT_BOOL(0, "create-reflog", &reflog,
+			 N_("create the branch's reflog")),
+		OPT_CALLBACK_F('t', "track",  &track, "(direct|inherit)",
+			N_("set branch tracking configuration"),
+			PARSE_OPT_OPTARG,
+			parse_opt_tracking_mode),
+		OPT__DRY_RUN(&dry_run,
+			     N_("show whether the branch would be created")),
+		OPT_END()
+	};
+	const char *const usage[] = {
+		N_("git submodule--helper create-branch [-f|--force] [--create-reflog] [-q|--quiet] [-t|--track] [-n|--dry-run] <name> <start-oid> <start-name>"),
+		NULL
+	};
+
+	git_config(git_default_config, NULL);
+	track = git_branch_track;
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+	if (argc != 3)
+		usage_with_options(usage, options);
+
+	if (!quiet && !dry_run)
+		printf_ln(_("creating branch '%s'"), argv[0]);
+
+	create_branches_recursively(the_repository, argv[0], argv[1], argv[2],
+				    force, reflog, quiet, track, dry_run);
+	return 0;
+}
+
+struct add_data {
+	const char *prefix;
+	const char *branch;
+	const char *reference_path;
+	char *sm_path;
+	const char *sm_name;
+	const char *repo;
+	const char *realrepo;
+	enum ref_storage_format ref_storage_format;
+	int depth;
+	unsigned int force: 1;
+	unsigned int quiet: 1;
+	unsigned int progress: 1;
+	unsigned int dissociate: 1;
+};
+#define ADD_DATA_INIT { \
+	.depth = -1, \
+	.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
+}
+
+static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
+{
+	struct child_process cp_remote = CHILD_PROCESS_INIT;
+	struct strbuf sb_remote_out = STRBUF_INIT;
+
+	cp_remote.git_cmd = 1;
+	strvec_pushf(&cp_remote.env,
+		     "GIT_DIR=%s", git_dir_path);
+	strvec_push(&cp_remote.env, "GIT_WORK_TREE=.");
+	strvec_pushl(&cp_remote.args, "remote", "-v", NULL);
+	if (!capture_command(&cp_remote, &sb_remote_out, 0)) {
+		char *next_line;
+		char *line = sb_remote_out.buf;
+
+		while ((next_line = strchr(line, '\n')) != NULL) {
+			size_t len = next_line - line;
+
+			if (strip_suffix_mem(line, &len, " (fetch)"))
+				strbuf_addf(msg, "  %.*s\n", (int)len, line);
+			line = next_line + 1;
+		}
+	}
+
+	strbuf_release(&sb_remote_out);
+}
+
+static int add_submodule(const struct add_data *add_data)
+{
+	char *submod_gitdir_path;
+	struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
+	struct string_list reference = STRING_LIST_INIT_NODUP;
+	int ret = -1;
+
+	/* perhaps the path already exists and is already a git repo, else clone it */
+	if (is_directory(add_data->sm_path)) {
+		struct strbuf sm_path = STRBUF_INIT;
+		strbuf_addstr(&sm_path, add_data->sm_path);
+		submod_gitdir_path = xstrfmt("%s/.git", add_data->sm_path);
+		if (is_nonbare_repository_dir(&sm_path))
+			printf(_("Adding existing repo at '%s' to the index\n"),
+			       add_data->sm_path);
+		else
+			die(_("'%s' already exists and is not a valid git repo"),
+			    add_data->sm_path);
+		strbuf_release(&sm_path);
+		free(submod_gitdir_path);
+	} else {
+		struct child_process cp = CHILD_PROCESS_INIT;
+
+		submod_gitdir_path = xstrfmt(".git/modules/%s", add_data->sm_name);
+
+		if (is_directory(submod_gitdir_path)) {
+			if (!add_data->force) {
+				struct strbuf msg = STRBUF_INIT;
+				char *die_msg;
+
+				strbuf_addf(&msg, _("A git directory for '%s' is found "
+						    "locally with remote(s):\n"),
+					    add_data->sm_name);
+
+				append_fetch_remotes(&msg, submod_gitdir_path);
+				free(submod_gitdir_path);
+
+				strbuf_addf(&msg, _("If you want to reuse this local git "
+						    "directory instead of cloning again from\n"
+						    "  %s\n"
+						    "use the '--force' option. If the local git "
+						    "directory is not the correct repo\n"
+						    "or you are unsure what this means choose "
+						    "another name with the '--name' option."),
+					    add_data->realrepo);
+
+				die_msg = strbuf_detach(&msg, NULL);
+				die("%s", die_msg);
+			} else {
+				printf(_("Reactivating local git directory for "
+					 "submodule '%s'\n"), add_data->sm_name);
+			}
+		}
+		free(submod_gitdir_path);
+
+		clone_data.prefix = add_data->prefix;
+		clone_data.path = add_data->sm_path;
+		clone_data.name = add_data->sm_name;
+		clone_data.url = add_data->realrepo;
+		clone_data.quiet = add_data->quiet;
+		clone_data.progress = add_data->progress;
+		if (add_data->reference_path) {
+			char *p = xstrdup(add_data->reference_path);
+
+			string_list_append(&reference, p)->util = p;
+		}
+		clone_data.ref_storage_format = add_data->ref_storage_format;
+		clone_data.dissociate = add_data->dissociate;
+		if (add_data->depth >= 0)
+			clone_data.depth = add_data->depth;
+
+		if (clone_submodule(&clone_data, &reference))
+			goto cleanup;
+
+		prepare_submodule_repo_env(&cp.env);
+		cp.git_cmd = 1;
+		cp.dir = add_data->sm_path;
+		/*
+		 * NOTE: we only get here if add_data->force is true, so
+		 * passing --force to checkout is reasonable.
+		 */
+		strvec_pushl(&cp.args, "checkout", "-f", "-q", NULL);
+
+		if (add_data->branch) {
+			strvec_pushl(&cp.args, "-B", add_data->branch, NULL);
+			strvec_pushf(&cp.args, "origin/%s", add_data->branch);
+		}
+
+		if (run_command(&cp))
+			die(_("unable to checkout submodule '%s'"), add_data->sm_path);
+	}
+	ret = 0;
+
+cleanup:
+	string_list_clear(&reference, 1);
+	return ret;
+}
+
+static int config_submodule_in_gitmodules(const char *name, const char *var, const char *value)
+{
+	char *key;
+	int ret;
+
+	if (!is_writing_gitmodules_ok())
+		die(_("please make sure that the .gitmodules file is in the working tree"));
+
+	key = xstrfmt("submodule.%s.%s", name, var);
+	ret = config_set_in_gitmodules_file_gently(key, value);
+	free(key);
+
+	return ret;
+}
+
+static void configure_added_submodule(struct add_data *add_data)
+{
+	char *key;
+	struct child_process add_submod = CHILD_PROCESS_INIT;
+	struct child_process add_gitmodules = CHILD_PROCESS_INIT;
+
+	key = xstrfmt("submodule.%s.url", add_data->sm_name);
+	git_config_set_gently(key, add_data->realrepo);
+	free(key);
+
+	add_submod.git_cmd = 1;
+	strvec_pushl(&add_submod.args, "add",
+		     "--no-warn-embedded-repo", NULL);
+	if (add_data->force)
+		strvec_push(&add_submod.args, "--force");
+	strvec_pushl(&add_submod.args, "--", add_data->sm_path, NULL);
+
+	if (run_command(&add_submod))
+		die(_("Failed to add submodule '%s'"), add_data->sm_path);
+
+	if (config_submodule_in_gitmodules(add_data->sm_name, "path", add_data->sm_path) ||
+	    config_submodule_in_gitmodules(add_data->sm_name, "url", add_data->repo))
+		die(_("Failed to register submodule '%s'"), add_data->sm_path);
+
+	if (add_data->branch) {
+		if (config_submodule_in_gitmodules(add_data->sm_name,
+						   "branch", add_data->branch))
+			die(_("Failed to register submodule '%s'"), add_data->sm_path);
+	}
+
+	add_gitmodules.git_cmd = 1;
+	strvec_pushl(&add_gitmodules.args,
+		     "add", "--force", "--", ".gitmodules", NULL);
+
+	if (run_command(&add_gitmodules))
+		die(_("Failed to register submodule '%s'"), add_data->sm_path);
+
+	/*
+	 * NEEDSWORK: In a multi-working-tree world this needs to be
+	 * set in the per-worktree config.
+	 */
+	/*
+	 * NEEDSWORK: In the longer run, we need to get rid of this
+	 * pattern of querying "submodule.active" before calling
+	 * is_submodule_active(), since that function needs to find
+	 * out the value of "submodule.active" again anyway.
+	 */
+	if (!git_config_get("submodule.active")) {
+		/*
+		 * If the submodule being added isn't already covered by the
+		 * current configured pathspec, set the submodule's active flag
+		 */
+		if (!is_submodule_active(the_repository, add_data->sm_path)) {
+			key = xstrfmt("submodule.%s.active", add_data->sm_name);
+			git_config_set_gently(key, "true");
+			free(key);
+		}
+	} else {
+		key = xstrfmt("submodule.%s.active", add_data->sm_name);
+		git_config_set_gently(key, "true");
+		free(key);
+	}
+}
+
+static void die_on_index_match(const char *path, int force)
+{
+	struct pathspec ps;
+	const char *args[] = { path, NULL };
+	parse_pathspec(&ps, 0, PATHSPEC_PREFER_CWD, NULL, args);
+
+	if (repo_read_index_preload(the_repository, NULL, 0) < 0)
+		die(_("index file corrupt"));
+
+	if (ps.nr) {
+		char *ps_matched = xcalloc(ps.nr, 1);
+
+		/* TODO: audit for interaction with sparse-index. */
+		ensure_full_index(the_repository->index);
+
+		/*
+		 * Since there is only one pathspec, we just need to
+		 * check ps_matched[0] to know if a cache entry matched.
+		 */
+		for (size_t i = 0; i < the_repository->index->cache_nr; i++) {
+			ce_path_match(the_repository->index, the_repository->index->cache[i], &ps,
+				      ps_matched);
+
+			if (ps_matched[0]) {
+				if (!force)
+					die(_("'%s' already exists in the index"),
+					    path);
+				if (!S_ISGITLINK(the_repository->index->cache[i]->ce_mode))
+					die(_("'%s' already exists in the index "
+					      "and is not a submodule"), path);
+				break;
+			}
+		}
+		free(ps_matched);
+	}
+	clear_pathspec(&ps);
+}
+
+static void die_on_repo_without_commits(const char *path)
+{
+	struct strbuf sb = STRBUF_INIT;
+	strbuf_addstr(&sb, path);
+	if (is_nonbare_repository_dir(&sb)) {
+		struct object_id oid;
+		if (repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid) < 0)
+			die(_("'%s' does not have a commit checked out"), path);
+	}
+	strbuf_release(&sb);
+}
+
+static int module_add(int argc, const char **argv, const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	int force = 0, quiet = 0, progress = 0, dissociate = 0;
+	struct add_data add_data = ADD_DATA_INIT;
+	const char *ref_storage_format = NULL;
+	char *to_free = NULL;
+	struct option options[] = {
+		OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
+			   N_("branch of repository to add as submodule")),
+		OPT__FORCE(&force, N_("allow adding an otherwise ignored submodule path"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT__QUIET(&quiet, N_("print only error messages")),
+		OPT_BOOL(0, "progress", &progress, N_("force cloning progress")),
+		OPT_STRING(0, "reference", &add_data.reference_path, N_("repository"),
+			   N_("reference repository")),
+		OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
+			   N_("specify the reference format to use")),
+		OPT_BOOL(0, "dissociate", &dissociate, N_("borrow the objects from reference repositories")),
+		OPT_STRING(0, "name", &add_data.sm_name, N_("name"),
+			   N_("sets the submodule's name to the given string "
+			      "instead of defaulting to its path")),
+		OPT_INTEGER(0, "depth", &add_data.depth, N_("depth for shallow clones")),
+		OPT_END()
+	};
+	const char *const usage[] = {
+		N_("git submodule add [<options>] [--] <repository> [<path>]"),
+		NULL
+	};
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 1;
+
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+	if (!is_writing_gitmodules_ok())
+		die(_("please make sure that the .gitmodules file is in the working tree"));
+
+	if (prefix && *prefix &&
+	    add_data.reference_path && !is_absolute_path(add_data.reference_path))
+		add_data.reference_path = xstrfmt("%s%s", prefix, add_data.reference_path);
+
+	if (argc == 0 || argc > 2)
+		usage_with_options(usage, options);
+
+	if (ref_storage_format) {
+		add_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
+		if (add_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
+			die(_("unknown ref storage format '%s'"), ref_storage_format);
+	}
+
+	add_data.repo = argv[0];
+	if (argc == 1)
+		add_data.sm_path = git_url_basename(add_data.repo, 0, 0);
+	else
+		add_data.sm_path = xstrdup(argv[1]);
+
+	if (prefix && *prefix && !is_absolute_path(add_data.sm_path)) {
+		char *sm_path = add_data.sm_path;
+
+		add_data.sm_path = xstrfmt("%s%s", prefix, sm_path);
+		free(sm_path);
+	}
+
+	if (starts_with_dot_dot_slash(add_data.repo) ||
+	    starts_with_dot_slash(add_data.repo)) {
+		if (prefix)
+			die(_("Relative path can only be used from the toplevel "
+			      "of the working tree"));
+
+		/* dereference source url relative to parent's url */
+		to_free = resolve_relative_url(add_data.repo, NULL, 1);
+		add_data.realrepo = to_free;
+	} else if (is_dir_sep(add_data.repo[0]) || strchr(add_data.repo, ':')) {
+		add_data.realrepo = add_data.repo;
+	} else {
+		die(_("repo URL: '%s' must be absolute or begin with ./|../"),
+		    add_data.repo);
+	}
+
+	/*
+	 * normalize path:
+	 * multiple //; leading ./; /./; /../;
+	 */
+	normalize_path_copy(add_data.sm_path, add_data.sm_path);
+	strip_dir_trailing_slashes(add_data.sm_path);
+
+	if (validate_submodule_path(add_data.sm_path) < 0)
+		exit(128);
+
+	die_on_index_match(add_data.sm_path, force);
+	die_on_repo_without_commits(add_data.sm_path);
+
+	if (!force) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+
+		cp.git_cmd = 1;
+		cp.no_stdout = 1;
+		strvec_pushl(&cp.args, "add", "--dry-run", "--ignore-missing",
+			     "--no-warn-embedded-repo", add_data.sm_path, NULL);
+		if ((ret = pipe_command(&cp, NULL, 0, NULL, 0, &sb, 0))) {
+			strbuf_complete_line(&sb);
+			fputs(sb.buf, stderr);
+			goto cleanup;
+		}
+	}
+
+	if(!add_data.sm_name)
+		add_data.sm_name = add_data.sm_path;
+
+	if (check_submodule_name(add_data.sm_name))
+		die(_("'%s' is not a valid submodule name"), add_data.sm_name);
+
+	add_data.prefix = prefix;
+	add_data.force = !!force;
+	add_data.quiet = !!quiet;
+	add_data.progress = !!progress;
+	add_data.dissociate = !!dissociate;
+
+	if (add_submodule(&add_data))
+		goto cleanup;
+	configure_added_submodule(&add_data);
+
+	ret = 0;
+cleanup:
+	free(add_data.sm_path);
+	free(to_free);
+	strbuf_release(&sb);
+
+	return ret;
+}
+
+int cmd_submodule__helper(int argc,
+			  const char **argv,
+			  const char *prefix,
+			  struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	const char *const usage[] = {
+		N_("git submodule--helper <command>"),
+		NULL
+	};
+	struct option options[] = {
+		OPT_SUBCOMMAND("clone", &fn, module_clone),
+		OPT_SUBCOMMAND("add", &fn, module_add),
+		OPT_SUBCOMMAND("update", &fn, module_update),
+		OPT_SUBCOMMAND("foreach", &fn, module_foreach),
+		OPT_SUBCOMMAND("init", &fn, module_init),
+		OPT_SUBCOMMAND("status", &fn, module_status),
+		OPT_SUBCOMMAND("sync", &fn, module_sync),
+		OPT_SUBCOMMAND("deinit", &fn, module_deinit),
+		OPT_SUBCOMMAND("summary", &fn, module_summary),
+		OPT_SUBCOMMAND("push-check", &fn, push_check),
+		OPT_SUBCOMMAND("absorbgitdirs", &fn, absorb_git_dirs),
+		OPT_SUBCOMMAND("set-url", &fn, module_set_url),
+		OPT_SUBCOMMAND("set-branch", &fn, module_set_branch),
+		OPT_SUBCOMMAND("create-branch", &fn, module_create_branch),
+		OPT_END()
+	};
+	argc = parse_options(argc, argv, prefix, options, usage, 0);
+
+	return fn(argc, argv, prefix, repo);
+}
diff --git a/builtin/symbolic-ref.c b/builtin/symbolic-ref.c
new file mode 100644
index 0000000000..299d23d76a
--- /dev/null
+++ b/builtin/symbolic-ref.c
@@ -0,0 +1,97 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "refs.h"
+#include "parse-options.h"
+#include "strbuf.h"
+
+static const char * const git_symbolic_ref_usage[] = {
+	N_("git symbolic-ref [-m <reason>] <name> <ref>"),
+	N_("git symbolic-ref [-q] [--short] [--no-recurse] <name>"),
+	N_("git symbolic-ref --delete [-q] <name>"),
+	NULL
+};
+
+static int check_symref(const char *HEAD, int quiet, int shorten, int recurse, int print)
+{
+	int resolve_flags, flag;
+	const char *refname;
+
+	resolve_flags = (recurse ? 0 : RESOLVE_REF_NO_RECURSE);
+	refname = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+					  HEAD, resolve_flags, NULL, &flag);
+
+	if (!refname)
+		die("No such ref: %s", HEAD);
+	else if (!(flag & REF_ISSYMREF)) {
+		if (!quiet)
+			die("ref %s is not a symbolic ref", HEAD);
+		else
+			return 1;
+	}
+	if (print) {
+		char *to_free = NULL;
+		if (shorten)
+			refname = to_free = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+									 refname,
+									 0);
+		puts(refname);
+		free(to_free);
+	}
+	return 0;
+}
+
+int cmd_symbolic_ref(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	int quiet = 0, delete = 0, shorten = 0, recurse = 1, ret = 0;
+	const char *msg = NULL;
+	struct option options[] = {
+		OPT__QUIET(&quiet,
+			N_("suppress error message for non-symbolic (detached) refs")),
+		OPT_BOOL('d', "delete", &delete, N_("delete symbolic ref")),
+		OPT_BOOL(0, "short", &shorten, N_("shorten ref output")),
+		OPT_BOOL(0, "recurse", &recurse, N_("recursively dereference (default)")),
+		OPT_STRING('m', NULL, &msg, N_("reason"), N_("reason of the update")),
+		OPT_END(),
+	};
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, options,
+			     git_symbolic_ref_usage, 0);
+	if (msg && !*msg)
+		die("Refusing to perform update with empty message");
+
+	if (delete) {
+		if (argc != 1)
+			usage_with_options(git_symbolic_ref_usage, options);
+		ret = check_symref(argv[0], 1, 0, 0, 0);
+		if (ret)
+			die("Cannot delete %s, not a symbolic ref", argv[0]);
+		if (!strcmp(argv[0], "HEAD"))
+			die("deleting '%s' is not allowed", argv[0]);
+		return refs_delete_ref(get_main_ref_store(the_repository),
+				       NULL, argv[0], NULL, REF_NO_DEREF);
+	}
+
+	switch (argc) {
+	case 1:
+		ret = check_symref(argv[0], quiet, shorten, recurse, 1);
+		break;
+	case 2:
+		if (!strcmp(argv[0], "HEAD") &&
+		    !starts_with(argv[1], "refs/"))
+			die("Refusing to point HEAD outside of refs/");
+		if (check_refname_format(argv[1], REFNAME_ALLOW_ONELEVEL) < 0)
+			die("Refusing to set '%s' to invalid ref '%s'", argv[0], argv[1]);
+		ret = !!refs_update_symref(get_main_ref_store(the_repository),
+					   argv[0], argv[1], msg);
+		break;
+	default:
+		usage_with_options(git_symbolic_ref_usage, options);
+	}
+	return ret;
+}
diff --git a/builtin/tag.c b/builtin/tag.c
new file mode 100644
index 0000000000..e8a344b926
--- /dev/null
+++ b/builtin/tag.c
@@ -0,0 +1,709 @@
+/*
+ * Builtin "git tag"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@xxxxxxxxxx>,
+ *                    Carlos Rica <jasampler@xxxxxxxxx>
+ * Based on git-tag.sh and mktag.c by Linus Torvalds.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "advice.h"
+#include "config.h"
+#include "editor.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "refs.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "path.h"
+#include "tag.h"
+#include "parse-options.h"
+#include "diff.h"
+#include "revision.h"
+#include "gpg-interface.h"
+#include "oid-array.h"
+#include "column.h"
+#include "ref-filter.h"
+#include "date.h"
+#include "write-or-die.h"
+#include "object-file-convert.h"
+#include "trailer.h"
+
+static const char * const git_tag_usage[] = {
+	N_("git tag [-a | -s | -u <key-id>] [-f] [-m <msg> | -F <file>] [-e]\n"
+	   "        [(--trailer <token>[(=|:)<value>])...]\n"
+	   "        <tagname> [<commit> | <object>]"),
+	N_("git tag -d <tagname>..."),
+	N_("git tag [-n[<num>]] -l [--contains <commit>] [--no-contains <commit>]\n"
+	   "        [--points-at <object>] [--column[=<options>] | --no-column]\n"
+	   "        [--create-reflog] [--sort=<key>] [--format=<format>]\n"
+	   "        [--merged <commit>] [--no-merged <commit>] [<pattern>...]"),
+	N_("git tag -v [--format=<format>] <tagname>..."),
+	NULL
+};
+
+static unsigned int colopts;
+static int force_sign_annotate;
+static int config_sign_tag = -1; /* unspecified */
+
+static int list_tags(struct ref_filter *filter, struct ref_sorting *sorting,
+		     struct ref_format *format)
+{
+	char *to_free = NULL;
+
+	if (filter->lines == -1)
+		filter->lines = 0;
+
+	if (!format->format) {
+		if (filter->lines) {
+			to_free = xstrfmt("%s %%(contents:lines=%d)",
+					  "%(align:15)%(refname:lstrip=2)%(end)",
+					  filter->lines);
+			format->format = to_free;
+		} else
+			format->format = "%(refname:lstrip=2)";
+	}
+
+	if (verify_ref_format(format))
+		die(_("unable to parse format string"));
+	filter->with_commit_tag_algo = 1;
+	filter_and_format_refs(filter, FILTER_REFS_TAGS, sorting, format);
+
+	free(to_free);
+
+	return 0;
+}
+
+typedef int (*each_tag_name_fn)(const char *name, const char *ref,
+				const struct object_id *oid, void *cb_data);
+
+static int for_each_tag_name(const char **argv, each_tag_name_fn fn,
+			     void *cb_data)
+{
+	const char **p;
+	struct strbuf ref = STRBUF_INIT;
+	int had_error = 0;
+	struct object_id oid;
+
+	for (p = argv; *p; p++) {
+		strbuf_reset(&ref);
+		strbuf_addf(&ref, "refs/tags/%s", *p);
+		if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &oid)) {
+			error(_("tag '%s' not found."), *p);
+			had_error = 1;
+			continue;
+		}
+		if (fn(*p, ref.buf, &oid, cb_data))
+			had_error = 1;
+	}
+	strbuf_release(&ref);
+	return had_error;
+}
+
+static int collect_tags(const char *name UNUSED, const char *ref,
+			const struct object_id *oid, void *cb_data)
+{
+	struct string_list *ref_list = cb_data;
+
+	string_list_append(ref_list, ref);
+	ref_list->items[ref_list->nr - 1].util = oiddup(oid);
+	return 0;
+}
+
+static int delete_tags(const char **argv)
+{
+	int result;
+	struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
+	struct string_list_item *item;
+
+	result = for_each_tag_name(argv, collect_tags, (void *)&refs_to_delete);
+	if (refs_delete_refs(get_main_ref_store(the_repository), NULL, &refs_to_delete, REF_NO_DEREF))
+		result = 1;
+
+	for_each_string_list_item(item, &refs_to_delete) {
+		const char *name = item->string;
+		struct object_id *oid = item->util;
+		if (!refs_ref_exists(get_main_ref_store(the_repository), name))
+			printf(_("Deleted tag '%s' (was %s)\n"),
+				item->string + 10,
+				repo_find_unique_abbrev(the_repository, oid, DEFAULT_ABBREV));
+
+		free(oid);
+	}
+	string_list_clear(&refs_to_delete, 0);
+	return result;
+}
+
+static int verify_tag(const char *name, const char *ref UNUSED,
+		      const struct object_id *oid, void *cb_data)
+{
+	int flags;
+	struct ref_format *format = cb_data;
+	flags = GPG_VERIFY_VERBOSE;
+
+	if (format->format)
+		flags = GPG_VERIFY_OMIT_STATUS;
+
+	if (gpg_verify_tag(oid, name, flags))
+		return -1;
+
+	if (format->format)
+		pretty_print_ref(name, oid, format);
+
+	return 0;
+}
+
+static int do_sign(struct strbuf *buffer, struct object_id **compat_oid,
+		   struct object_id *compat_oid_buf)
+{
+	const struct git_hash_algo *compat = the_repository->compat_hash_algo;
+	struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
+	struct strbuf compat_buf = STRBUF_INIT;
+	char *keyid = get_signing_key();
+	int ret = -1;
+
+	if (sign_buffer(buffer, &sig, keyid))
+		goto out;
+
+	if (compat) {
+		const struct git_hash_algo *algo = the_repository->hash_algo;
+
+		if (convert_object_file(&compat_buf, algo, compat,
+					buffer->buf, buffer->len, OBJ_TAG, 1))
+			goto out;
+		if (sign_buffer(&compat_buf, &compat_sig, keyid))
+			goto out;
+		add_header_signature(&compat_buf, &sig, algo);
+		strbuf_addbuf(&compat_buf, &compat_sig);
+		hash_object_file(compat, compat_buf.buf, compat_buf.len,
+				 OBJ_TAG, compat_oid_buf);
+		*compat_oid = compat_oid_buf;
+	}
+
+	if (compat_sig.len)
+		add_header_signature(buffer, &compat_sig, compat);
+
+	strbuf_addbuf(buffer, &sig);
+	ret = 0;
+out:
+	strbuf_release(&sig);
+	strbuf_release(&compat_sig);
+	strbuf_release(&compat_buf);
+	free(keyid);
+	return ret;
+}
+
+static const char tag_template[] =
+	N_("\nWrite a message for tag:\n  %s\n"
+	"Lines starting with '%s' will be ignored.\n");
+
+static const char tag_template_nocleanup[] =
+	N_("\nWrite a message for tag:\n  %s\n"
+	"Lines starting with '%s' will be kept; you may remove them"
+	" yourself if you want to.\n");
+
+static int git_tag_config(const char *var, const char *value,
+			  const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "tag.gpgsign")) {
+		config_sign_tag = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "tag.sort")) {
+		if (!value)
+			return config_error_nonbool(var);
+		string_list_append(cb, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "tag.forcesignannotated")) {
+		force_sign_annotate = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (starts_with(var, "column."))
+		return git_column_config(var, value, "tag", &colopts);
+
+	if (git_color_config(var, value, cb) < 0)
+		return -1;
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static void write_tag_body(int fd, const struct object_id *oid)
+{
+	unsigned long size;
+	enum object_type type;
+	char *buf, *sp, *orig;
+	struct strbuf payload = STRBUF_INIT;
+	struct strbuf signature = STRBUF_INIT;
+
+	orig = buf = repo_read_object_file(the_repository, oid, &type, &size);
+	if (!buf)
+		return;
+	if (parse_signature(buf, size, &payload, &signature)) {
+		buf = payload.buf;
+		size = payload.len;
+	}
+	/* skip header */
+	sp = strstr(buf, "\n\n");
+
+	if (!sp || !size || type != OBJ_TAG) {
+		free(buf);
+		return;
+	}
+	sp += 2; /* skip the 2 LFs */
+	write_or_die(fd, sp, buf + size - sp);
+
+	free(orig);
+	strbuf_release(&payload);
+	strbuf_release(&signature);
+}
+
+static int build_tag_object(struct strbuf *buf, int sign, struct object_id *result)
+{
+	struct object_id *compat_oid = NULL, compat_oid_buf;
+	if (sign && do_sign(buf, &compat_oid, &compat_oid_buf) < 0)
+		return error(_("unable to sign the tag"));
+	if (write_object_file_flags(buf->buf, buf->len, OBJ_TAG, result,
+				    compat_oid, 0) < 0)
+		return error(_("unable to write tag file"));
+	return 0;
+}
+
+struct create_tag_options {
+	unsigned int message_given:1;
+	unsigned int use_editor:1;
+	unsigned int sign;
+	enum {
+		CLEANUP_NONE,
+		CLEANUP_SPACE,
+		CLEANUP_ALL
+	} cleanup_mode;
+};
+
+static const char message_advice_nested_tag[] =
+	N_("You have created a nested tag. The object referred to by your new tag is\n"
+	   "already a tag. If you meant to tag the object that it points to, use:\n"
+	   "\n"
+	   "\tgit tag -f %s %s^{}");
+
+static void create_tag(const struct object_id *object, const char *object_ref,
+		       const char *tag,
+		       struct strbuf *buf, struct create_tag_options *opt,
+		       struct object_id *prev, struct object_id *result,
+		       struct strvec *trailer_args, char *path)
+{
+	enum object_type type;
+	struct strbuf header = STRBUF_INIT;
+	int should_edit;
+
+	type = oid_object_info(the_repository, object, NULL);
+	if (type <= OBJ_NONE)
+		die(_("bad object type."));
+
+	if (type == OBJ_TAG)
+		advise_if_enabled(ADVICE_NESTED_TAG, _(message_advice_nested_tag),
+				  tag, object_ref);
+
+	strbuf_addf(&header,
+		    "object %s\n"
+		    "type %s\n"
+		    "tag %s\n"
+		    "tagger %s\n\n",
+		    oid_to_hex(object),
+		    type_name(type),
+		    tag,
+		    git_committer_info(IDENT_STRICT));
+
+	should_edit = opt->use_editor || !opt->message_given;
+	if (should_edit || trailer_args->nr) {
+		int fd;
+
+		/* write the template message before editing: */
+		fd = xopen(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
+
+		if (opt->message_given && buf->len) {
+			strbuf_complete(buf, '\n');
+			write_or_die(fd, buf->buf, buf->len);
+			strbuf_reset(buf);
+		} else if (!is_null_oid(prev)) {
+			write_tag_body(fd, prev);
+		} else {
+			struct strbuf buf = STRBUF_INIT;
+			strbuf_addch(&buf, '\n');
+			if (opt->cleanup_mode == CLEANUP_ALL)
+				strbuf_commented_addf(&buf, comment_line_str,
+				      _(tag_template), tag, comment_line_str);
+			else
+				strbuf_commented_addf(&buf, comment_line_str,
+				      _(tag_template_nocleanup), tag, comment_line_str);
+			write_or_die(fd, buf.buf, buf.len);
+			strbuf_release(&buf);
+		}
+		close(fd);
+
+		if (trailer_args->nr && amend_file_with_trailers(path, trailer_args))
+			die(_("unable to pass trailers to --trailers"));
+
+		if (should_edit) {
+			if (launch_editor(path, buf, NULL)) {
+				fprintf(stderr,
+					_("Please supply the message using either -m or -F option.\n"));
+				exit(1);
+			}
+		} else if (trailer_args->nr) {
+			strbuf_reset(buf);
+			if (strbuf_read_file(buf, path, 0) < 0)
+				die_errno(_("failed to read '%s'"), path);
+		}
+	}
+
+	if (opt->cleanup_mode != CLEANUP_NONE)
+		strbuf_stripspace(buf,
+		  opt->cleanup_mode == CLEANUP_ALL ? comment_line_str : NULL);
+
+	if (!opt->message_given && !buf->len)
+		die(_("no tag message?"));
+
+	strbuf_insert(buf, 0, header.buf, header.len);
+	strbuf_release(&header);
+
+	if (build_tag_object(buf, opt->sign, result) < 0) {
+		if (path)
+			fprintf(stderr, _("The tag message has been left in %s\n"),
+				path);
+		exit(128);
+	}
+}
+
+static void create_reflog_msg(const struct object_id *oid, struct strbuf *sb)
+{
+	enum object_type type;
+	struct commit *c;
+	char *buf;
+	unsigned long size;
+	int subject_len = 0;
+	const char *subject_start;
+
+	char *rla = getenv("GIT_REFLOG_ACTION");
+	if (rla) {
+		strbuf_addstr(sb, rla);
+	} else {
+		strbuf_addstr(sb, "tag: tagging ");
+		strbuf_add_unique_abbrev(sb, oid, DEFAULT_ABBREV);
+	}
+
+	strbuf_addstr(sb, " (");
+	type = oid_object_info(the_repository, oid, NULL);
+	switch (type) {
+	default:
+		strbuf_addstr(sb, "object of unknown type");
+		break;
+	case OBJ_COMMIT:
+		if ((buf = repo_read_object_file(the_repository, oid, &type, &size))) {
+			subject_len = find_commit_subject(buf, &subject_start);
+			strbuf_insert(sb, sb->len, subject_start, subject_len);
+		} else {
+			strbuf_addstr(sb, "commit object");
+		}
+		free(buf);
+
+		if ((c = lookup_commit_reference(the_repository, oid)))
+			strbuf_addf(sb, ", %s", show_date(c->date, 0, DATE_MODE(SHORT)));
+		break;
+	case OBJ_TREE:
+		strbuf_addstr(sb, "tree object");
+		break;
+	case OBJ_BLOB:
+		strbuf_addstr(sb, "blob object");
+		break;
+	case OBJ_TAG:
+		strbuf_addstr(sb, "other tag object");
+		break;
+	}
+	strbuf_addch(sb, ')');
+}
+
+struct msg_arg {
+	int given;
+	struct strbuf buf;
+};
+
+static int parse_msg_arg(const struct option *opt, const char *arg, int unset)
+{
+	struct msg_arg *msg = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+
+	if (!arg)
+		return -1;
+	if (msg->buf.len)
+		strbuf_addstr(&(msg->buf), "\n\n");
+	strbuf_addstr(&(msg->buf), arg);
+	msg->given = 1;
+	return 0;
+}
+
+int cmd_tag(int argc,
+	    const char **argv,
+	    const char *prefix,
+	    struct repository *repo UNUSED)
+{
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf ref = STRBUF_INIT;
+	struct strbuf reflog_msg = STRBUF_INIT;
+	struct object_id object, prev;
+	const char *object_ref, *tag;
+	struct create_tag_options opt;
+	char *cleanup_arg = NULL;
+	int create_reflog = 0;
+	int annotate = 0, force = 0;
+	int cmdmode = 0, create_tag_object = 0;
+	char *msgfile = NULL;
+	const char *keyid = NULL;
+	struct msg_arg msg = { .buf = STRBUF_INIT };
+	struct ref_transaction *transaction;
+	struct strbuf err = STRBUF_INIT;
+	struct ref_filter filter = REF_FILTER_INIT;
+	struct ref_sorting *sorting;
+	struct string_list sorting_options = STRING_LIST_INIT_DUP;
+	struct ref_format format = REF_FORMAT_INIT;
+	struct strvec trailer_args = STRVEC_INIT;
+	int icase = 0;
+	int edit_flag = 0;
+	struct option options[] = {
+		OPT_CMDMODE('l', "list", &cmdmode, N_("list tag names"), 'l'),
+		{ OPTION_INTEGER, 'n', NULL, &filter.lines, N_("n"),
+				N_("print <n> lines of each tag message"),
+				PARSE_OPT_OPTARG, NULL, 1 },
+		OPT_CMDMODE('d', "delete", &cmdmode, N_("delete tags"), 'd'),
+		OPT_CMDMODE('v', "verify", &cmdmode, N_("verify tags"), 'v'),
+
+		OPT_GROUP(N_("Tag creation options")),
+		OPT_BOOL('a', "annotate", &annotate,
+					N_("annotated tag, needs a message")),
+		OPT_CALLBACK_F('m', "message", &msg, N_("message"),
+			       N_("tag message"), PARSE_OPT_NONEG, parse_msg_arg),
+		OPT_FILENAME('F', "file", &msgfile, N_("read message from file")),
+		OPT_PASSTHRU_ARGV(0, "trailer", &trailer_args, N_("trailer"),
+				  N_("add custom trailer(s)"), PARSE_OPT_NONEG),
+		OPT_BOOL('e', "edit", &edit_flag, N_("force edit of tag message")),
+		OPT_BOOL('s', "sign", &opt.sign, N_("annotated and GPG-signed tag")),
+		OPT_CLEANUP(&cleanup_arg),
+		OPT_STRING('u', "local-user", &keyid, N_("key-id"),
+					N_("use another key to sign the tag")),
+		OPT__FORCE(&force, N_("replace the tag if exists"), 0),
+		OPT_BOOL(0, "create-reflog", &create_reflog, N_("create a reflog")),
+
+		OPT_GROUP(N_("Tag listing options")),
+		OPT_COLUMN(0, "column", &colopts, N_("show tag list in columns")),
+		OPT_CONTAINS(&filter.with_commit, N_("print only tags that contain the commit")),
+		OPT_NO_CONTAINS(&filter.no_commit, N_("print only tags that don't contain the commit")),
+		OPT_WITH(&filter.with_commit, N_("print only tags that contain the commit")),
+		OPT_WITHOUT(&filter.no_commit, N_("print only tags that don't contain the commit")),
+		OPT_MERGED(&filter, N_("print only tags that are merged")),
+		OPT_NO_MERGED(&filter, N_("print only tags that are not merged")),
+		OPT_BOOL(0, "omit-empty",  &format.array_opts.omit_empty,
+			N_("do not output a newline after empty formatted refs")),
+		OPT_REF_SORT(&sorting_options),
+		{
+			OPTION_CALLBACK, 0, "points-at", &filter.points_at, N_("object"),
+			N_("print only tags of the object"), PARSE_OPT_LASTARG_DEFAULT,
+			parse_opt_object_name, (intptr_t) "HEAD"
+		},
+		OPT_STRING(  0 , "format", &format.format, N_("format"),
+			   N_("format to use for the output")),
+		OPT__COLOR(&format.use_color, N_("respect format colors")),
+		OPT_BOOL('i', "ignore-case", &icase, N_("sorting and filtering are case insensitive")),
+		OPT_END()
+	};
+	int ret = 0;
+	const char *only_in_list = NULL;
+	char *path = NULL;
+
+	setup_ref_filter_porcelain_msg();
+
+	/*
+	 * Try to set sort keys from config. If config does not set any,
+	 * fall back on default (refname) sorting.
+	 */
+	git_config(git_tag_config, &sorting_options);
+	if (!sorting_options.nr)
+		string_list_append(&sorting_options, "refname");
+
+	memset(&opt, 0, sizeof(opt));
+	filter.lines = -1;
+	opt.sign = -1;
+
+	argc = parse_options(argc, argv, prefix, options, git_tag_usage, 0);
+
+	if (!cmdmode) {
+		if (argc == 0)
+			cmdmode = 'l';
+		else if (filter.with_commit || filter.no_commit ||
+			 filter.reachable_from || filter.unreachable_from ||
+			 filter.points_at.nr || filter.lines != -1)
+			cmdmode = 'l';
+	}
+
+	if (cmdmode == 'l')
+		setup_auto_pager("tag", 1);
+
+	if (opt.sign == -1)
+		opt.sign = cmdmode ? 0 : config_sign_tag > 0;
+
+	if (keyid) {
+		opt.sign = 1;
+		set_signing_key(keyid);
+	}
+	create_tag_object = (opt.sign || annotate || msg.given || msgfile ||
+			     edit_flag || trailer_args.nr);
+
+	if ((create_tag_object || force) && (cmdmode != 0))
+		usage_with_options(git_tag_usage, options);
+
+	finalize_colopts(&colopts, -1);
+	if (cmdmode == 'l' && filter.lines != -1) {
+		if (explicitly_enable_column(colopts))
+			die(_("options '%s' and '%s' cannot be used together"), "--column", "-n");
+		colopts = 0;
+	}
+	sorting = ref_sorting_options(&sorting_options);
+	ref_sorting_set_sort_flags_all(sorting, REF_SORTING_ICASE, icase);
+	filter.ignore_case = icase;
+	if (cmdmode == 'l') {
+		if (column_active(colopts)) {
+			struct column_options copts;
+			memset(&copts, 0, sizeof(copts));
+			copts.padding = 2;
+			if (run_column_filter(colopts, &copts))
+				die(_("could not start 'git column'"));
+		}
+		filter.name_patterns = argv;
+		ret = list_tags(&filter, sorting, &format);
+		if (column_active(colopts))
+			stop_column_filter();
+		goto cleanup;
+	}
+	if (filter.lines != -1)
+		only_in_list = "-n";
+	else if (filter.with_commit)
+		only_in_list = "--contains";
+	else if (filter.no_commit)
+		only_in_list = "--no-contains";
+	else if (filter.points_at.nr)
+		only_in_list = "--points-at";
+	else if (filter.reachable_from)
+		only_in_list = "--merged";
+	else if (filter.unreachable_from)
+		only_in_list = "--no-merged";
+	if (only_in_list)
+		die(_("the '%s' option is only allowed in list mode"), only_in_list);
+	if (cmdmode == 'd') {
+		ret = delete_tags(argv);
+		goto cleanup;
+	}
+	if (cmdmode == 'v') {
+		if (format.format && verify_ref_format(&format))
+			usage_with_options(git_tag_usage, options);
+		ret = for_each_tag_name(argv, verify_tag, &format);
+		goto cleanup;
+	}
+
+	if (msg.given || msgfile) {
+		if (msg.given && msgfile)
+			die(_("options '%s' and '%s' cannot be used together"), "-F", "-m");
+		if (msg.given)
+			strbuf_addbuf(&buf, &(msg.buf));
+		else {
+			if (!strcmp(msgfile, "-")) {
+				if (strbuf_read(&buf, 0, 1024) < 0)
+					die_errno(_("cannot read '%s'"), msgfile);
+			} else {
+				if (strbuf_read_file(&buf, msgfile, 1024) < 0)
+					die_errno(_("could not open or read '%s'"),
+						msgfile);
+			}
+		}
+	}
+
+	tag = argv[0];
+
+	object_ref = argc == 2 ? argv[1] : "HEAD";
+	if (argc > 2)
+		die(_("too many arguments"));
+
+	if (repo_get_oid(the_repository, object_ref, &object))
+		die(_("Failed to resolve '%s' as a valid ref."), object_ref);
+
+	if (check_tag_ref(&ref, tag))
+		die(_("'%s' is not a valid tag name."), tag);
+
+	if (refs_read_ref(get_main_ref_store(the_repository), ref.buf, &prev))
+		oidclr(&prev, the_repository->hash_algo);
+	else if (!force)
+		die(_("tag '%s' already exists"), tag);
+
+	opt.message_given = msg.given || msgfile;
+	opt.use_editor = edit_flag;
+
+	if (!cleanup_arg || !strcmp(cleanup_arg, "strip"))
+		opt.cleanup_mode = CLEANUP_ALL;
+	else if (!strcmp(cleanup_arg, "verbatim"))
+		opt.cleanup_mode = CLEANUP_NONE;
+	else if (!strcmp(cleanup_arg, "whitespace"))
+		opt.cleanup_mode = CLEANUP_SPACE;
+	else
+		die(_("Invalid cleanup mode %s"), cleanup_arg);
+
+	create_reflog_msg(&object, &reflog_msg);
+
+	if (create_tag_object) {
+		if (force_sign_annotate && !annotate)
+			opt.sign = 1;
+		path = git_pathdup("TAG_EDITMSG");
+		create_tag(&object, object_ref, tag, &buf, &opt, &prev, &object,
+			   &trailer_args, path);
+	}
+
+	transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+						  0, &err);
+	if (!transaction ||
+	    ref_transaction_update(transaction, ref.buf, &object, &prev,
+				   NULL, NULL,
+				   create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
+				   reflog_msg.buf, &err) ||
+	    ref_transaction_commit(transaction, &err)) {
+		if (path)
+			fprintf(stderr,
+				_("The tag message has been left in %s\n"),
+				path);
+		die("%s", err.buf);
+	}
+	if (path) {
+		unlink_or_warn(path);
+		free(path);
+	}
+	ref_transaction_free(transaction);
+	if (force && !is_null_oid(&prev) && !oideq(&prev, &object))
+		printf(_("Updated tag '%s' (was %s)\n"), tag,
+		       repo_find_unique_abbrev(the_repository, &prev, DEFAULT_ABBREV));
+
+cleanup:
+	ref_sorting_release(sorting);
+	ref_filter_clear(&filter);
+	strbuf_release(&buf);
+	strbuf_release(&ref);
+	strbuf_release(&reflog_msg);
+	strbuf_release(&msg.buf);
+	strbuf_release(&err);
+	strvec_clear(&trailer_args);
+	free(msgfile);
+	return ret;
+}
diff --git a/builtin/unpack-file.c b/builtin/unpack-file.c
new file mode 100644
index 0000000000..fb5fcbc40a
--- /dev/null
+++ b/builtin/unpack-file.c
@@ -0,0 +1,49 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "hex.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+
+static char *create_temp_file(struct object_id *oid)
+{
+	static char path[50];
+	void *buf;
+	enum object_type type;
+	unsigned long size;
+	int fd;
+
+	buf = repo_read_object_file(the_repository, oid, &type, &size);
+	if (!buf || type != OBJ_BLOB)
+		die("unable to read blob object %s", oid_to_hex(oid));
+
+	xsnprintf(path, sizeof(path), ".merge_file_XXXXXX");
+	fd = xmkstemp(path);
+	if (write_in_full(fd, buf, size) < 0)
+		die_errno("unable to write temp-file");
+	close(fd);
+	free(buf);
+	return path;
+}
+
+static const char usage_msg[] =
+"git unpack-file <blob>";
+
+int cmd_unpack_file(int argc,
+		    const char **argv,
+		    const char *prefix UNUSED,
+		    struct repository *repo UNUSED)
+{
+	struct object_id oid;
+
+	show_usage_if_asked(argc, argv, usage_msg);
+	if (argc != 2)
+		usage(usage_msg);
+	if (repo_get_oid(the_repository, argv[1], &oid))
+		die("Not a valid object name %s", argv[1]);
+
+	git_config(git_default_config, NULL);
+
+	puts(create_temp_file(&oid));
+	return 0;
+}
diff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c
new file mode 100644
index 0000000000..f6b9825fb0
--- /dev/null
+++ b/builtin/unpack-objects.c
@@ -0,0 +1,689 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "bulk-checkin.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "git-zlib.h"
+#include "hex.h"
+#include "object-store-ll.h"
+#include "object.h"
+#include "delta.h"
+#include "pack.h"
+#include "blob.h"
+#include "replace-object.h"
+#include "strbuf.h"
+#include "progress.h"
+#include "decorate.h"
+#include "fsck.h"
+#include "packfile.h"
+
+static int dry_run, quiet, recover, has_errors, strict;
+static const char unpack_usage[] = "git unpack-objects [-n] [-q] [-r] [--strict]";
+
+/* We always read in 4kB chunks. */
+static unsigned char buffer[4096];
+static unsigned int offset, len;
+static off_t consumed_bytes;
+static off_t max_input_size;
+static git_hash_ctx ctx;
+static struct fsck_options fsck_options = FSCK_OPTIONS_STRICT;
+static struct progress *progress;
+
+/*
+ * When running under --strict mode, objects whose reachability are
+ * suspect are kept in core without getting written in the object
+ * store.
+ */
+struct obj_buffer {
+	char *buffer;
+	unsigned long size;
+};
+
+static struct decoration obj_decorate;
+
+static struct obj_buffer *lookup_object_buffer(struct object *base)
+{
+	return lookup_decoration(&obj_decorate, base);
+}
+
+static void add_object_buffer(struct object *object, char *buffer, unsigned long size)
+{
+	struct obj_buffer *obj;
+	CALLOC_ARRAY(obj, 1);
+	obj->buffer = buffer;
+	obj->size = size;
+	if (add_decoration(&obj_decorate, object, obj))
+		die("object %s tried to add buffer twice!", oid_to_hex(&object->oid));
+}
+
+/*
+ * Make sure at least "min" bytes are available in the buffer, and
+ * return the pointer to the buffer.
+ */
+static void *fill(int min)
+{
+	if (min <= len)
+		return buffer + offset;
+	if (min > sizeof(buffer))
+		die("cannot fill %d bytes", min);
+	if (offset) {
+		the_hash_algo->update_fn(&ctx, buffer, offset);
+		memmove(buffer, buffer + offset, len);
+		offset = 0;
+	}
+	do {
+		ssize_t ret = xread(0, buffer + len, sizeof(buffer) - len);
+		if (ret <= 0) {
+			if (!ret)
+				die("early EOF");
+			die_errno("read error on input");
+		}
+		len += ret;
+	} while (len < min);
+	return buffer;
+}
+
+static void use(int bytes)
+{
+	if (bytes > len)
+		die("used more bytes than were available");
+	len -= bytes;
+	offset += bytes;
+
+	/* make sure off_t is sufficiently large not to wrap */
+	if (signed_add_overflows(consumed_bytes, bytes))
+		die("pack too large for current definition of off_t");
+	consumed_bytes += bytes;
+	if (max_input_size && consumed_bytes > max_input_size)
+		die(_("pack exceeds maximum allowed size"));
+	display_throughput(progress, consumed_bytes);
+}
+
+/*
+ * Decompress zstream from the standard input into a newly
+ * allocated buffer of specified size and return the buffer.
+ * The caller is responsible to free the returned buffer.
+ *
+ * But for dry_run mode, "get_data()" is only used to check the
+ * integrity of data, and the returned buffer is not used at all.
+ * Therefore, in dry_run mode, "get_data()" will release the small
+ * allocated buffer which is reused to hold temporary zstream output
+ * and return NULL instead of returning garbage data.
+ */
+static void *get_data(unsigned long size)
+{
+	git_zstream stream;
+	unsigned long bufsize = dry_run && size > 8192 ? 8192 : size;
+	void *buf = xmallocz(bufsize);
+
+	memset(&stream, 0, sizeof(stream));
+
+	stream.next_out = buf;
+	stream.avail_out = bufsize;
+	stream.next_in = fill(1);
+	stream.avail_in = len;
+	git_inflate_init(&stream);
+
+	for (;;) {
+		int ret = git_inflate(&stream, 0);
+		use(len - stream.avail_in);
+		if (stream.total_out == size && ret == Z_STREAM_END)
+			break;
+		if (ret != Z_OK) {
+			error("inflate returned %d", ret);
+			FREE_AND_NULL(buf);
+			if (!recover)
+				exit(1);
+			has_errors = 1;
+			break;
+		}
+		stream.next_in = fill(1);
+		stream.avail_in = len;
+		if (dry_run) {
+			/* reuse the buffer in dry_run mode */
+			stream.next_out = buf;
+			stream.avail_out = bufsize > size - stream.total_out ?
+						   size - stream.total_out :
+						   bufsize;
+		}
+	}
+	git_inflate_end(&stream);
+	if (dry_run)
+		FREE_AND_NULL(buf);
+	return buf;
+}
+
+struct delta_info {
+	struct object_id base_oid;
+	unsigned nr;
+	off_t base_offset;
+	unsigned long size;
+	void *delta;
+	struct delta_info *next;
+};
+
+static struct delta_info *delta_list;
+
+static void add_delta_to_list(unsigned nr, const struct object_id *base_oid,
+			      off_t base_offset,
+			      void *delta, unsigned long size)
+{
+	struct delta_info *info = xmalloc(sizeof(*info));
+
+	oidcpy(&info->base_oid, base_oid);
+	info->base_offset = base_offset;
+	info->size = size;
+	info->delta = delta;
+	info->nr = nr;
+	info->next = delta_list;
+	delta_list = info;
+}
+
+struct obj_info {
+	off_t offset;
+	struct object_id oid;
+	struct object *obj;
+};
+
+/* Remember to update object flag allocation in object.h */
+#define FLAG_OPEN (1u<<20)
+#define FLAG_WRITTEN (1u<<21)
+
+static struct obj_info *obj_list;
+static unsigned nr_objects;
+
+/*
+ * Called only from check_object() after it verified this object
+ * is Ok.
+ */
+static void write_cached_object(struct object *obj, struct obj_buffer *obj_buf)
+{
+	struct object_id oid;
+
+	if (write_object_file(obj_buf->buffer, obj_buf->size,
+			      obj->type, &oid) < 0)
+		die("failed to write object %s", oid_to_hex(&obj->oid));
+	obj->flags |= FLAG_WRITTEN;
+}
+
+/*
+ * At the very end of the processing, write_rest() scans the objects
+ * that have reachability requirements and calls this function.
+ * Verify its reachability and validity recursively and write it out.
+ */
+static int check_object(struct object *obj, enum object_type type,
+			void *data UNUSED,
+			struct fsck_options *options UNUSED)
+{
+	struct obj_buffer *obj_buf;
+
+	if (!obj)
+		return 1;
+
+	if (obj->flags & FLAG_WRITTEN)
+		return 0;
+
+	if (type != OBJ_ANY && obj->type != type)
+		die("object type mismatch");
+
+	if (!(obj->flags & FLAG_OPEN)) {
+		unsigned long size;
+		int type = oid_object_info(the_repository, &obj->oid, &size);
+		if (type != obj->type || type <= 0)
+			die("object of unexpected type");
+		obj->flags |= FLAG_WRITTEN;
+		return 0;
+	}
+
+	obj_buf = lookup_object_buffer(obj);
+	if (!obj_buf)
+		die("Whoops! Cannot find object '%s'", oid_to_hex(&obj->oid));
+	if (fsck_object(obj, obj_buf->buffer, obj_buf->size, &fsck_options))
+		die("fsck error in packed object");
+	fsck_options.walk = check_object;
+	if (fsck_walk(obj, NULL, &fsck_options))
+		die("Error on reachable objects of %s", oid_to_hex(&obj->oid));
+	write_cached_object(obj, obj_buf);
+	return 0;
+}
+
+static void write_rest(void)
+{
+	unsigned i;
+	for (i = 0; i < nr_objects; i++) {
+		if (obj_list[i].obj)
+			check_object(obj_list[i].obj, OBJ_ANY, NULL, NULL);
+	}
+}
+
+static void added_object(unsigned nr, enum object_type type,
+			 void *data, unsigned long size);
+
+/*
+ * Write out nr-th object from the list, now we know the contents
+ * of it.  Under --strict, this buffers structured objects in-core,
+ * to be checked at the end.
+ */
+static void write_object(unsigned nr, enum object_type type,
+			 void *buf, unsigned long size)
+{
+	if (!strict) {
+		if (write_object_file(buf, size, type,
+				      &obj_list[nr].oid) < 0)
+			die("failed to write object");
+		added_object(nr, type, buf, size);
+		free(buf);
+		obj_list[nr].obj = NULL;
+	} else if (type == OBJ_BLOB) {
+		struct blob *blob;
+		if (write_object_file(buf, size, type,
+				      &obj_list[nr].oid) < 0)
+			die("failed to write object");
+		added_object(nr, type, buf, size);
+		free(buf);
+
+		blob = lookup_blob(the_repository, &obj_list[nr].oid);
+		if (blob)
+			blob->object.flags |= FLAG_WRITTEN;
+		else
+			die("invalid blob object");
+		obj_list[nr].obj = NULL;
+	} else {
+		struct object *obj;
+		int eaten;
+		hash_object_file(the_hash_algo, buf, size, type,
+				 &obj_list[nr].oid);
+		added_object(nr, type, buf, size);
+		obj = parse_object_buffer(the_repository, &obj_list[nr].oid,
+					  type, size, buf,
+					  &eaten);
+		if (!obj)
+			die("invalid %s", type_name(type));
+		add_object_buffer(obj, buf, size);
+		obj->flags |= FLAG_OPEN;
+		obj_list[nr].obj = obj;
+	}
+}
+
+static void resolve_delta(unsigned nr, enum object_type type,
+			  void *base, unsigned long base_size,
+			  void *delta, unsigned long delta_size)
+{
+	void *result;
+	unsigned long result_size;
+
+	result = patch_delta(base, base_size,
+			     delta, delta_size,
+			     &result_size);
+	if (!result)
+		die("failed to apply delta");
+	free(delta);
+	write_object(nr, type, result, result_size);
+}
+
+/*
+ * We now know the contents of an object (which is nr-th in the pack);
+ * resolve all the deltified objects that are based on it.
+ */
+static void added_object(unsigned nr, enum object_type type,
+			 void *data, unsigned long size)
+{
+	struct delta_info **p = &delta_list;
+	struct delta_info *info;
+
+	while ((info = *p) != NULL) {
+		if (oideq(&info->base_oid, &obj_list[nr].oid) ||
+		    info->base_offset == obj_list[nr].offset) {
+			*p = info->next;
+			p = &delta_list;
+			resolve_delta(info->nr, type, data, size,
+				      info->delta, info->size);
+			free(info);
+			continue;
+		}
+		p = &info->next;
+	}
+}
+
+static void unpack_non_delta_entry(enum object_type type, unsigned long size,
+				   unsigned nr)
+{
+	void *buf = get_data(size);
+
+	if (buf)
+		write_object(nr, type, buf, size);
+}
+
+struct input_zstream_data {
+	git_zstream *zstream;
+	unsigned char buf[8192];
+	int status;
+};
+
+static const void *feed_input_zstream(struct input_stream *in_stream,
+				      unsigned long *readlen)
+{
+	struct input_zstream_data *data = in_stream->data;
+	git_zstream *zstream = data->zstream;
+	void *in = fill(1);
+
+	if (in_stream->is_finished) {
+		*readlen = 0;
+		return NULL;
+	}
+
+	zstream->next_out = data->buf;
+	zstream->avail_out = sizeof(data->buf);
+	zstream->next_in = in;
+	zstream->avail_in = len;
+
+	data->status = git_inflate(zstream, 0);
+
+	in_stream->is_finished = data->status != Z_OK;
+	use(len - zstream->avail_in);
+	*readlen = sizeof(data->buf) - zstream->avail_out;
+
+	return data->buf;
+}
+
+static void stream_blob(unsigned long size, unsigned nr)
+{
+	git_zstream zstream = { 0 };
+	struct input_zstream_data data = { 0 };
+	struct input_stream in_stream = {
+		.read = feed_input_zstream,
+		.data = &data,
+	};
+	struct obj_info *info = &obj_list[nr];
+
+	data.zstream = &zstream;
+	git_inflate_init(&zstream);
+
+	if (stream_loose_object(&in_stream, size, &info->oid))
+		die(_("failed to write object in stream"));
+
+	if (data.status != Z_STREAM_END)
+		die(_("inflate returned (%d)"), data.status);
+	git_inflate_end(&zstream);
+
+	if (strict) {
+		struct blob *blob = lookup_blob(the_repository, &info->oid);
+
+		if (!blob)
+			die(_("invalid blob object from stream"));
+		blob->object.flags |= FLAG_WRITTEN;
+	}
+	info->obj = NULL;
+}
+
+static int resolve_against_held(unsigned nr, const struct object_id *base,
+				void *delta_data, unsigned long delta_size)
+{
+	struct object *obj;
+	struct obj_buffer *obj_buffer;
+	obj = lookup_object(the_repository, base);
+	if (!obj)
+		return 0;
+	obj_buffer = lookup_object_buffer(obj);
+	if (!obj_buffer)
+		return 0;
+	resolve_delta(nr, obj->type, obj_buffer->buffer,
+		      obj_buffer->size, delta_data, delta_size);
+	return 1;
+}
+
+static void unpack_delta_entry(enum object_type type, unsigned long delta_size,
+			       unsigned nr)
+{
+	void *delta_data, *base;
+	unsigned long base_size;
+	struct object_id base_oid;
+
+	if (type == OBJ_REF_DELTA) {
+		oidread(&base_oid, fill(the_hash_algo->rawsz), the_repository->hash_algo);
+		use(the_hash_algo->rawsz);
+		delta_data = get_data(delta_size);
+		if (!delta_data)
+			return;
+		if (repo_has_object_file(the_repository, &base_oid))
+			; /* Ok we have this one */
+		else if (resolve_against_held(nr, &base_oid,
+					      delta_data, delta_size))
+			return; /* we are done */
+		else {
+			/* cannot resolve yet --- queue it */
+			oidclr(&obj_list[nr].oid, the_repository->hash_algo);
+			add_delta_to_list(nr, &base_oid, 0, delta_data, delta_size);
+			return;
+		}
+	} else {
+		unsigned base_found = 0;
+		unsigned char *pack, c;
+		off_t base_offset;
+		unsigned lo, mid, hi;
+
+		pack = fill(1);
+		c = *pack;
+		use(1);
+		base_offset = c & 127;
+		while (c & 128) {
+			base_offset += 1;
+			if (!base_offset || MSB(base_offset, 7))
+				die("offset value overflow for delta base object");
+			pack = fill(1);
+			c = *pack;
+			use(1);
+			base_offset = (base_offset << 7) + (c & 127);
+		}
+		base_offset = obj_list[nr].offset - base_offset;
+		if (base_offset <= 0 || base_offset >= obj_list[nr].offset)
+			die("offset value out of bound for delta base object");
+
+		delta_data = get_data(delta_size);
+		if (!delta_data)
+			return;
+		lo = 0;
+		hi = nr;
+		while (lo < hi) {
+			mid = lo + (hi - lo) / 2;
+			if (base_offset < obj_list[mid].offset) {
+				hi = mid;
+			} else if (base_offset > obj_list[mid].offset) {
+				lo = mid + 1;
+			} else {
+				oidcpy(&base_oid, &obj_list[mid].oid);
+				base_found = !is_null_oid(&base_oid);
+				break;
+			}
+		}
+		if (!base_found) {
+			/*
+			 * The delta base object is itself a delta that
+			 * has not been resolved yet.
+			 */
+			oidclr(&obj_list[nr].oid, the_repository->hash_algo);
+			add_delta_to_list(nr, null_oid(), base_offset,
+					  delta_data, delta_size);
+			return;
+		}
+	}
+
+	if (resolve_against_held(nr, &base_oid, delta_data, delta_size))
+		return;
+
+	base = repo_read_object_file(the_repository, &base_oid, &type,
+				     &base_size);
+	if (!base) {
+		error("failed to read delta-pack base object %s",
+		      oid_to_hex(&base_oid));
+		if (!recover)
+			exit(1);
+		has_errors = 1;
+		return;
+	}
+	resolve_delta(nr, type, base, base_size, delta_data, delta_size);
+	free(base);
+}
+
+static void unpack_one(unsigned nr)
+{
+	unsigned shift;
+	unsigned char *pack;
+	unsigned long size, c;
+	enum object_type type;
+
+	obj_list[nr].offset = consumed_bytes;
+
+	pack = fill(1);
+	c = *pack;
+	use(1);
+	type = (c >> 4) & 7;
+	size = (c & 15);
+	shift = 4;
+	while (c & 0x80) {
+		pack = fill(1);
+		c = *pack;
+		use(1);
+		size += (c & 0x7f) << shift;
+		shift += 7;
+	}
+
+	switch (type) {
+	case OBJ_BLOB:
+		if (!dry_run && size > big_file_threshold) {
+			stream_blob(size, nr);
+			return;
+		}
+		/* fallthrough */
+	case OBJ_COMMIT:
+	case OBJ_TREE:
+	case OBJ_TAG:
+		unpack_non_delta_entry(type, size, nr);
+		return;
+	case OBJ_REF_DELTA:
+	case OBJ_OFS_DELTA:
+		unpack_delta_entry(type, size, nr);
+		return;
+	default:
+		error("bad object type %d", type);
+		has_errors = 1;
+		if (recover)
+			return;
+		exit(1);
+	}
+}
+
+static void unpack_all(void)
+{
+	int i;
+	unsigned char *hdr = fill(sizeof(struct pack_header));
+
+	if (get_be32(hdr) != PACK_SIGNATURE)
+		die("bad pack file");
+	hdr += 4;
+	if (!pack_version_ok_native(get_be32(hdr)))
+		die("unknown pack file version %"PRIu32,
+		    get_be32(hdr));
+	hdr += 4;
+	nr_objects = get_be32(hdr);
+	use(sizeof(struct pack_header));
+
+	if (!quiet)
+		progress = start_progress(the_repository,
+					  _("Unpacking objects"), nr_objects);
+	CALLOC_ARRAY(obj_list, nr_objects);
+	begin_odb_transaction();
+	for (i = 0; i < nr_objects; i++) {
+		unpack_one(i);
+		display_progress(progress, i + 1);
+	}
+	end_odb_transaction();
+	stop_progress(&progress);
+
+	if (delta_list)
+		die("unresolved deltas left after unpacking");
+}
+
+int cmd_unpack_objects(int argc,
+		       const char **argv,
+		       const char *prefix UNUSED,
+		       struct repository *repo UNUSED)
+{
+	int i;
+	struct object_id oid;
+	git_hash_ctx tmp_ctx;
+
+	disable_replace_refs();
+
+	git_config(git_default_config, NULL);
+
+	quiet = !isatty(2);
+
+	show_usage_if_asked(argc, argv, unpack_usage);
+
+	for (i = 1 ; i < argc; i++) {
+		const char *arg = argv[i];
+
+		if (*arg == '-') {
+			if (!strcmp(arg, "-n")) {
+				dry_run = 1;
+				continue;
+			}
+			if (!strcmp(arg, "-q")) {
+				quiet = 1;
+				continue;
+			}
+			if (!strcmp(arg, "-r")) {
+				recover = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--strict")) {
+				strict = 1;
+				continue;
+			}
+			if (skip_prefix(arg, "--strict=", &arg)) {
+				strict = 1;
+				fsck_set_msg_types(&fsck_options, arg);
+				continue;
+			}
+			if (skip_prefix(arg, "--pack_header=", &arg)) {
+				if (parse_pack_header_option(arg,
+							     buffer, &len) < 0)
+					die(_("bad --pack_header: %s"), arg);
+				continue;
+			}
+			if (skip_prefix(arg, "--max-input-size=", &arg)) {
+				max_input_size = strtoumax(arg, NULL, 10);
+				continue;
+			}
+			usage(unpack_usage);
+		}
+
+		/* We don't take any non-flag arguments now.. Maybe some day */
+		usage(unpack_usage);
+	}
+	the_hash_algo->init_fn(&ctx);
+	unpack_all();
+	the_hash_algo->update_fn(&ctx, buffer, offset);
+	the_hash_algo->init_fn(&tmp_ctx);
+	the_hash_algo->clone_fn(&tmp_ctx, &ctx);
+	the_hash_algo->final_oid_fn(&oid, &tmp_ctx);
+	if (strict) {
+		write_rest();
+		if (fsck_finish(&fsck_options))
+			die(_("fsck error in pack objects"));
+	}
+	if (!hasheq(fill(the_hash_algo->rawsz), oid.hash,
+		    the_repository->hash_algo))
+		die("final sha1 did not match");
+	use(the_hash_algo->rawsz);
+
+	/* Write the last part of the buffer to stdout */
+	write_in_full(1, buffer + offset, len);
+
+	/* All done */
+	return has_errors;
+}
diff --git a/builtin/update-index.c b/builtin/update-index.c
new file mode 100644
index 0000000000..b2f6b1a3fb
--- /dev/null
+++ b/builtin/update-index.c
@@ -0,0 +1,1256 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "bulk-checkin.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "quote.h"
+#include "cache-tree.h"
+#include "tree-walk.h"
+#include "object-file.h"
+#include "refs.h"
+#include "resolve-undo.h"
+#include "parse-options.h"
+#include "pathspec.h"
+#include "dir.h"
+#include "read-cache.h"
+#include "setup.h"
+#include "sparse-index.h"
+#include "split-index.h"
+#include "symlinks.h"
+#include "fsmonitor.h"
+#include "write-or-die.h"
+
+/*
+ * Default to not allowing changes to the list of files. The
+ * tool doesn't actually care, but this makes it harder to add
+ * files to the revision control by mistake by doing something
+ * like "git update-index *" and suddenly having all the object
+ * files be revision controlled.
+ */
+static int allow_add;
+static int allow_remove;
+static int allow_replace;
+static int info_only;
+static int force_remove;
+static int verbose;
+static int mark_valid_only;
+static int mark_skip_worktree_only;
+static int mark_fsmonitor_only;
+static int ignore_skip_worktree_entries;
+#define MARK_FLAG 1
+#define UNMARK_FLAG 2
+static struct strbuf mtime_dir = STRBUF_INIT;
+
+/* Untracked cache mode */
+enum uc_mode {
+	UC_UNSPECIFIED = -1,
+	UC_DISABLE = 0,
+	UC_ENABLE,
+	UC_TEST,
+	UC_FORCE
+};
+
+__attribute__((format (printf, 1, 2)))
+static void report(const char *fmt, ...)
+{
+	va_list vp;
+
+	if (!verbose)
+		return;
+
+	/*
+	 * It is possible, though unlikely, that a caller could use the verbose
+	 * output to synchronize with addition of objects to the object
+	 * database. The current implementation of ODB transactions leaves
+	 * objects invisible while a transaction is active, so flush the
+	 * transaction here before reporting a change made by update-index.
+	 */
+	flush_odb_transaction();
+	va_start(vp, fmt);
+	vprintf(fmt, vp);
+	putchar('\n');
+	va_end(vp);
+}
+
+static void remove_test_directory(void)
+{
+	if (mtime_dir.len)
+		remove_dir_recursively(&mtime_dir, 0);
+}
+
+static const char *get_mtime_path(const char *path)
+{
+	static struct strbuf sb = STRBUF_INIT;
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/%s", mtime_dir.buf, path);
+	return sb.buf;
+}
+
+static void xmkdir(const char *path)
+{
+	path = get_mtime_path(path);
+	if (mkdir(path, 0700))
+		die_errno(_("failed to create directory %s"), path);
+}
+
+static int xstat_mtime_dir(struct stat *st)
+{
+	if (stat(mtime_dir.buf, st))
+		die_errno(_("failed to stat %s"), mtime_dir.buf);
+	return 0;
+}
+
+static int create_file(const char *path)
+{
+	int fd;
+	path = get_mtime_path(path);
+	fd = xopen(path, O_CREAT | O_RDWR, 0644);
+	return fd;
+}
+
+static void xunlink(const char *path)
+{
+	path = get_mtime_path(path);
+	if (unlink(path))
+		die_errno(_("failed to delete file %s"), path);
+}
+
+static void xrmdir(const char *path)
+{
+	path = get_mtime_path(path);
+	if (rmdir(path))
+		die_errno(_("failed to delete directory %s"), path);
+}
+
+static void avoid_racy(void)
+{
+	/*
+	 * not use if we could usleep(10) if USE_NSEC is defined. The
+	 * field nsec could be there, but the OS could choose to
+	 * ignore it?
+	 */
+	sleep(1);
+}
+
+static int test_if_untracked_cache_is_supported(void)
+{
+	struct stat st;
+	struct stat_data base;
+	int fd, ret = 0;
+	char *cwd;
+
+	strbuf_addstr(&mtime_dir, "mtime-test-XXXXXX");
+	if (!mkdtemp(mtime_dir.buf))
+		die_errno("Could not make temporary directory");
+
+	cwd = xgetcwd();
+	fprintf(stderr, _("Testing mtime in '%s' "), cwd);
+	free(cwd);
+
+	atexit(remove_test_directory);
+	xstat_mtime_dir(&st);
+	fill_stat_data(&base, &st);
+	fputc('.', stderr);
+
+	avoid_racy();
+	fd = create_file("newfile");
+	xstat_mtime_dir(&st);
+	if (!match_stat_data(&base, &st)) {
+		close(fd);
+		fputc('\n', stderr);
+		fprintf_ln(stderr,_("directory stat info does not "
+				    "change after adding a new file"));
+		goto done;
+	}
+	fill_stat_data(&base, &st);
+	fputc('.', stderr);
+
+	avoid_racy();
+	xmkdir("new-dir");
+	xstat_mtime_dir(&st);
+	if (!match_stat_data(&base, &st)) {
+		close(fd);
+		fputc('\n', stderr);
+		fprintf_ln(stderr, _("directory stat info does not change "
+				     "after adding a new directory"));
+		goto done;
+	}
+	fill_stat_data(&base, &st);
+	fputc('.', stderr);
+
+	avoid_racy();
+	write_or_die(fd, "data", 4);
+	close(fd);
+	xstat_mtime_dir(&st);
+	if (match_stat_data(&base, &st)) {
+		fputc('\n', stderr);
+		fprintf_ln(stderr, _("directory stat info changes "
+				     "after updating a file"));
+		goto done;
+	}
+	fputc('.', stderr);
+
+	avoid_racy();
+	close(create_file("new-dir/new"));
+	xstat_mtime_dir(&st);
+	if (match_stat_data(&base, &st)) {
+		fputc('\n', stderr);
+		fprintf_ln(stderr, _("directory stat info changes after "
+				     "adding a file inside subdirectory"));
+		goto done;
+	}
+	fputc('.', stderr);
+
+	avoid_racy();
+	xunlink("newfile");
+	xstat_mtime_dir(&st);
+	if (!match_stat_data(&base, &st)) {
+		fputc('\n', stderr);
+		fprintf_ln(stderr, _("directory stat info does not "
+				     "change after deleting a file"));
+		goto done;
+	}
+	fill_stat_data(&base, &st);
+	fputc('.', stderr);
+
+	avoid_racy();
+	xunlink("new-dir/new");
+	xrmdir("new-dir");
+	xstat_mtime_dir(&st);
+	if (!match_stat_data(&base, &st)) {
+		fputc('\n', stderr);
+		fprintf_ln(stderr, _("directory stat info does not "
+				     "change after deleting a directory"));
+		goto done;
+	}
+
+	if (rmdir(mtime_dir.buf))
+		die_errno(_("failed to delete directory %s"), mtime_dir.buf);
+	fprintf_ln(stderr, _(" OK"));
+	ret = 1;
+
+done:
+	strbuf_release(&mtime_dir);
+	return ret;
+}
+
+static int mark_ce_flags(const char *path, int flag, int mark)
+{
+	int namelen = strlen(path);
+	int pos = index_name_pos(the_repository->index, path, namelen);
+	if (0 <= pos) {
+		mark_fsmonitor_invalid(the_repository->index, the_repository->index->cache[pos]);
+		if (mark)
+			the_repository->index->cache[pos]->ce_flags |= flag;
+		else
+			the_repository->index->cache[pos]->ce_flags &= ~flag;
+		the_repository->index->cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
+		cache_tree_invalidate_path(the_repository->index, path);
+		the_repository->index->cache_changed |= CE_ENTRY_CHANGED;
+		return 0;
+	}
+	return -1;
+}
+
+static int remove_one_path(const char *path)
+{
+	if (!allow_remove)
+		return error("%s: does not exist and --remove not passed", path);
+	if (remove_file_from_index(the_repository->index, path))
+		return error("%s: cannot remove from the index", path);
+	return 0;
+}
+
+/*
+ * Handle a path that couldn't be lstat'ed. It's either:
+ *  - missing file (ENOENT or ENOTDIR). That's ok if we're
+ *    supposed to be removing it and the removal actually
+ *    succeeds.
+ *  - permission error. That's never ok.
+ */
+static int process_lstat_error(const char *path, int err)
+{
+	if (is_missing_file_error(err))
+		return remove_one_path(path);
+	return error("lstat(\"%s\"): %s", path, strerror(err));
+}
+
+static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st)
+{
+	int option;
+	struct cache_entry *ce;
+
+	/* Was the old index entry already up-to-date? */
+	if (old && !ce_stage(old) && !ie_match_stat(the_repository->index, old, st, 0))
+		return 0;
+
+	ce = make_empty_cache_entry(the_repository->index, len);
+	memcpy(ce->name, path, len);
+	ce->ce_flags = create_ce_flags(0);
+	ce->ce_namelen = len;
+	fill_stat_cache_info(the_repository->index, ce, st);
+	ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
+
+	if (index_path(the_repository->index, &ce->oid, path, st,
+		       info_only ? 0 : HASH_WRITE_OBJECT)) {
+		discard_cache_entry(ce);
+		return -1;
+	}
+	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
+	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
+	if (add_index_entry(the_repository->index, ce, option)) {
+		discard_cache_entry(ce);
+		return error("%s: cannot add to the index - missing --add option?", path);
+	}
+	return 0;
+}
+
+/*
+ * Handle a path that was a directory. Four cases:
+ *
+ *  - it's already a gitlink in the index, and we keep it that
+ *    way, and update it if we can (if we cannot find the HEAD,
+ *    we're going to keep it unchanged in the index!)
+ *
+ *  - it's a *file* in the index, in which case it should be
+ *    removed as a file if removal is allowed, since it doesn't
+ *    exist as such any more. If removal isn't allowed, it's
+ *    an error.
+ *
+ *    (NOTE! This is old and arguably fairly strange behaviour.
+ *    We might want to make this an error unconditionally, and
+ *    use "--force-remove" if you actually want to force removal).
+ *
+ *  - it used to exist as a subdirectory (ie multiple files with
+ *    this particular prefix) in the index, in which case it's wrong
+ *    to try to update it as a directory.
+ *
+ *  - it doesn't exist at all in the index, but it is a valid
+ *    git directory, and it should be *added* as a gitlink.
+ */
+static int process_directory(const char *path, int len, struct stat *st)
+{
+	struct object_id oid;
+	int pos = index_name_pos(the_repository->index, path, len);
+
+	/* Exact match: file or existing gitlink */
+	if (pos >= 0) {
+		const struct cache_entry *ce = the_repository->index->cache[pos];
+		if (S_ISGITLINK(ce->ce_mode)) {
+
+			/* Do nothing to the index if there is no HEAD! */
+			if (repo_resolve_gitlink_ref(the_repository, path,
+						     "HEAD", &oid) < 0)
+				return 0;
+
+			return add_one_path(ce, path, len, st);
+		}
+		/* Should this be an unconditional error? */
+		return remove_one_path(path);
+	}
+
+	/* Inexact match: is there perhaps a subdirectory match? */
+	pos = -pos-1;
+	while (pos < the_repository->index->cache_nr) {
+		const struct cache_entry *ce = the_repository->index->cache[pos++];
+
+		if (strncmp(ce->name, path, len))
+			break;
+		if (ce->name[len] > '/')
+			break;
+		if (ce->name[len] < '/')
+			continue;
+
+		/* Subdirectory match - error out */
+		return error("%s: is a directory - add individual files instead", path);
+	}
+
+	/* No match - should we add it as a gitlink? */
+	if (!repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid))
+		return add_one_path(NULL, path, len, st);
+
+	/* Error out. */
+	return error("%s: is a directory - add files inside instead", path);
+}
+
+static int process_path(const char *path, struct stat *st, int stat_errno)
+{
+	int pos, len;
+	const struct cache_entry *ce;
+
+	len = strlen(path);
+	if (has_symlink_leading_path(path, len))
+		return error("'%s' is beyond a symbolic link", path);
+
+	pos = index_name_pos(the_repository->index, path, len);
+	ce = pos < 0 ? NULL : the_repository->index->cache[pos];
+	if (ce && ce_skip_worktree(ce)) {
+		/*
+		 * working directory version is assumed "good"
+		 * so updating it does not make sense.
+		 * On the other hand, removing it from index should work
+		 */
+		if (!ignore_skip_worktree_entries && allow_remove &&
+		    remove_file_from_index(the_repository->index, path))
+			return error("%s: cannot remove from the index", path);
+		return 0;
+	}
+
+	/*
+	 * First things first: get the stat information, to decide
+	 * what to do about the pathname!
+	 */
+	if (stat_errno)
+		return process_lstat_error(path, stat_errno);
+
+	if (S_ISDIR(st->st_mode))
+		return process_directory(path, len, st);
+
+	return add_one_path(ce, path, len, st);
+}
+
+static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
+			 const char *path, int stage)
+{
+	int len, option;
+	struct cache_entry *ce;
+
+	if (!verify_path(path, mode))
+		return error("Invalid path '%s'", path);
+
+	len = strlen(path);
+	ce = make_empty_cache_entry(the_repository->index, len);
+
+	oidcpy(&ce->oid, oid);
+	memcpy(ce->name, path, len);
+	ce->ce_flags = create_ce_flags(stage);
+	ce->ce_namelen = len;
+	ce->ce_mode = create_ce_mode(mode);
+	if (assume_unchanged)
+		ce->ce_flags |= CE_VALID;
+	option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
+	option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
+	if (add_index_entry(the_repository->index, ce, option))
+		return error("%s: cannot add to the index - missing --add option?",
+			     path);
+	report("add '%s'", path);
+	return 0;
+}
+
+static void chmod_path(char flip, const char *path)
+{
+	int pos;
+	struct cache_entry *ce;
+
+	pos = index_name_pos(the_repository->index, path, strlen(path));
+	if (pos < 0)
+		goto fail;
+	ce = the_repository->index->cache[pos];
+	if (chmod_index_entry(the_repository->index, ce, flip) < 0)
+		goto fail;
+
+	report("chmod %cx '%s'", flip, path);
+	return;
+ fail:
+	die("git update-index: cannot chmod %cx '%s'", flip, path);
+}
+
+static void update_one(const char *path)
+{
+	int stat_errno = 0;
+	struct stat st;
+
+	if (mark_valid_only || mark_skip_worktree_only || force_remove ||
+	    mark_fsmonitor_only)
+		st.st_mode = 0;
+	else if (lstat(path, &st) < 0) {
+		st.st_mode = 0;
+		stat_errno = errno;
+	} /* else stat is valid */
+
+	if (!verify_path(path, st.st_mode)) {
+		fprintf(stderr, "Ignoring path %s\n", path);
+		return;
+	}
+	if (mark_valid_only) {
+		if (mark_ce_flags(path, CE_VALID, mark_valid_only == MARK_FLAG))
+			die("Unable to mark file %s", path);
+		return;
+	}
+	if (mark_skip_worktree_only) {
+		if (mark_ce_flags(path, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))
+			die("Unable to mark file %s", path);
+		return;
+	}
+	if (mark_fsmonitor_only) {
+		if (mark_ce_flags(path, CE_FSMONITOR_VALID, mark_fsmonitor_only == MARK_FLAG))
+			die("Unable to mark file %s", path);
+		return;
+	}
+
+	if (force_remove) {
+		if (remove_file_from_index(the_repository->index, path))
+			die("git update-index: unable to remove %s", path);
+		report("remove '%s'", path);
+		return;
+	}
+	if (process_path(path, &st, stat_errno))
+		die("Unable to process path %s", path);
+	report("add '%s'", path);
+}
+
+static void read_index_info(int nul_term_line)
+{
+	const int hexsz = the_hash_algo->hexsz;
+	struct strbuf buf = STRBUF_INIT;
+	struct strbuf uq = STRBUF_INIT;
+	strbuf_getline_fn getline_fn;
+
+	getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
+	while (getline_fn(&buf, stdin) != EOF) {
+		char *ptr, *tab;
+		char *path_name;
+		struct object_id oid;
+		unsigned int mode;
+		unsigned long ul;
+		int stage;
+
+		/* This reads lines formatted in one of three formats:
+		 *
+		 * (1) mode         SP sha1          TAB path
+		 * The first format is what "git apply --index-info"
+		 * reports, and used to reconstruct a partial tree
+		 * that is used for phony merge base tree when falling
+		 * back on 3-way merge.
+		 *
+		 * (2) mode SP type SP sha1          TAB path
+		 * The second format is to stuff "git ls-tree" output
+		 * into the index file.
+		 *
+		 * (3) mode         SP sha1 SP stage TAB path
+		 * This format is to put higher order stages into the
+		 * index file and matches "git ls-files --stage" output.
+		 */
+		errno = 0;
+		ul = strtoul(buf.buf, &ptr, 8);
+		if (ptr == buf.buf || *ptr != ' '
+		    || errno || (unsigned int) ul != ul)
+			goto bad_line;
+		mode = ul;
+
+		tab = strchr(ptr, '\t');
+		if (!tab || tab - ptr < hexsz + 1)
+			goto bad_line;
+
+		if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') {
+			stage = tab[-1] - '0';
+			ptr = tab + 1; /* point at the head of path */
+			tab = tab - 2; /* point at tail of sha1 */
+		}
+		else {
+			stage = 0;
+			ptr = tab + 1; /* point at the head of path */
+		}
+
+		if (get_oid_hex(tab - hexsz, &oid) ||
+			tab[-(hexsz + 1)] != ' ')
+			goto bad_line;
+
+		path_name = ptr;
+		if (!nul_term_line && path_name[0] == '"') {
+			strbuf_reset(&uq);
+			if (unquote_c_style(&uq, path_name, NULL)) {
+				die("git update-index: bad quoting of path name");
+			}
+			path_name = uq.buf;
+		}
+
+		if (!verify_path(path_name, mode)) {
+			fprintf(stderr, "Ignoring path %s\n", path_name);
+			continue;
+		}
+
+		if (!mode) {
+			/* mode == 0 means there is no such path -- remove */
+			if (remove_file_from_index(the_repository->index, path_name))
+				die("git update-index: unable to remove %s",
+				    ptr);
+		}
+		else {
+			/* mode ' ' sha1 '\t' name
+			 * ptr[-1] points at tab,
+			 * ptr[-41] is at the beginning of sha1
+			 */
+			ptr[-(hexsz + 2)] = ptr[-1] = 0;
+			if (add_cacheinfo(mode, &oid, path_name, stage))
+				die("git update-index: unable to update %s",
+				    path_name);
+		}
+		continue;
+
+	bad_line:
+		die("malformed index info %s", buf.buf);
+	}
+	strbuf_release(&buf);
+	strbuf_release(&uq);
+}
+
+static const char * const update_index_usage[] = {
+	N_("git update-index [<options>] [--] [<file>...]"),
+	NULL
+};
+
+static struct cache_entry *read_one_ent(const char *which,
+					struct object_id *ent, const char *path,
+					int namelen, int stage)
+{
+	unsigned short mode;
+	struct object_id oid;
+	struct cache_entry *ce;
+
+	if (get_tree_entry(the_repository, ent, path, &oid, &mode)) {
+		if (which)
+			error("%s: not in %s branch.", path, which);
+		return NULL;
+	}
+	if (!the_repository->index->sparse_index && mode == S_IFDIR) {
+		if (which)
+			error("%s: not a blob in %s branch.", path, which);
+		return NULL;
+	}
+	ce = make_empty_cache_entry(the_repository->index, namelen);
+
+	oidcpy(&ce->oid, &oid);
+	memcpy(ce->name, path, namelen);
+	ce->ce_flags = create_ce_flags(stage);
+	ce->ce_namelen = namelen;
+	ce->ce_mode = create_ce_mode(mode);
+	return ce;
+}
+
+static int unresolve_one(const char *path)
+{
+	struct string_list_item *item;
+	int res = 0;
+
+	if (!the_repository->index->resolve_undo)
+		return res;
+	item = string_list_lookup(the_repository->index->resolve_undo, path);
+	if (!item)
+		return res; /* no resolve-undo record for the path */
+	res = unmerge_index_entry(the_repository->index, path, item->util, 0);
+	FREE_AND_NULL(item->util);
+	return res;
+}
+
+static int do_unresolve(int ac, const char **av,
+			const char *prefix, int prefix_length)
+{
+	int i;
+	int err = 0;
+
+	for (i = 1; i < ac; i++) {
+		const char *arg = av[i];
+		char *p = prefix_path(prefix, prefix_length, arg);
+		err |= unresolve_one(p);
+		free(p);
+	}
+	return err;
+}
+
+static int do_reupdate(const char **paths,
+		       const char *prefix)
+{
+	/* Read HEAD and run update-index on paths that are
+	 * merged and already different between index and HEAD.
+	 */
+	int pos;
+	int has_head = 1;
+	struct pathspec pathspec;
+	struct object_id head_oid;
+
+	parse_pathspec(&pathspec, 0,
+		       PATHSPEC_PREFER_CWD,
+		       prefix, paths);
+
+	if (refs_read_ref(get_main_ref_store(the_repository), "HEAD", &head_oid))
+		/* If there is no HEAD, that means it is an initial
+		 * commit.  Update everything in the index.
+		 */
+		has_head = 0;
+ redo:
+	for (pos = 0; pos < the_repository->index->cache_nr; pos++) {
+		const struct cache_entry *ce = the_repository->index->cache[pos];
+		struct cache_entry *old = NULL;
+		int save_nr;
+		char *path;
+
+		if (ce_stage(ce) || !ce_path_match(the_repository->index, ce, &pathspec, NULL))
+			continue;
+		if (has_head)
+			old = read_one_ent(NULL, &head_oid,
+					   ce->name, ce_namelen(ce), 0);
+		if (old && ce->ce_mode == old->ce_mode &&
+		    oideq(&ce->oid, &old->oid)) {
+			discard_cache_entry(old);
+			continue; /* unchanged */
+		}
+
+		/* At this point, we know the contents of the sparse directory are
+		 * modified with respect to HEAD, so we expand the index and restart
+		 * to process each path individually
+		 */
+		if (S_ISSPARSEDIR(ce->ce_mode)) {
+			ensure_full_index(the_repository->index);
+			goto redo;
+		}
+
+		/* Be careful.  The working tree may not have the
+		 * path anymore, in which case, under 'allow_remove',
+		 * or worse yet 'allow_replace', active_nr may decrease.
+		 */
+		save_nr = the_repository->index->cache_nr;
+		path = xstrdup(ce->name);
+		update_one(path);
+		free(path);
+		discard_cache_entry(old);
+		if (save_nr != the_repository->index->cache_nr)
+			goto redo;
+	}
+	clear_pathspec(&pathspec);
+	return 0;
+}
+
+struct refresh_params {
+	unsigned int flags;
+	int *has_errors;
+};
+
+static int refresh(struct refresh_params *o, unsigned int flag)
+{
+	setup_work_tree();
+	repo_read_index(the_repository);
+	*o->has_errors |= refresh_index(the_repository->index, o->flags | flag, NULL,
+					NULL, NULL);
+	if (has_racy_timestamp(the_repository->index)) {
+		/*
+		 * Even if nothing else has changed, updating the file
+		 * increases the chance that racy timestamps become
+		 * non-racy, helping future run-time performance.
+		 * We do that even in case of "errors" returned by
+		 * refresh_index() as these are no actual errors.
+		 * cmd_status() does the same.
+		 */
+		the_repository->index->cache_changed |= SOMETHING_CHANGED;
+	}
+	return 0;
+}
+
+static int refresh_callback(const struct option *opt,
+				const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	return refresh(opt->value, 0);
+}
+
+static int really_refresh_callback(const struct option *opt,
+				const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	return refresh(opt->value, REFRESH_REALLY);
+}
+
+static int chmod_callback(const struct option *opt,
+				const char *arg, int unset)
+{
+	char *flip = opt->value;
+	BUG_ON_OPT_NEG(unset);
+	if ((arg[0] != '-' && arg[0] != '+') || arg[1] != 'x' || arg[2])
+		return error("option 'chmod' expects \"+x\" or \"-x\"");
+	*flip = arg[0];
+	return 0;
+}
+
+static int resolve_undo_clear_callback(const struct option *opt UNUSED,
+				const char *arg, int unset)
+{
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+	resolve_undo_clear_index(the_repository->index);
+	return 0;
+}
+
+static int parse_new_style_cacheinfo(const char *arg,
+				     unsigned int *mode,
+				     struct object_id *oid,
+				     const char **path)
+{
+	unsigned long ul;
+	char *endp;
+	const char *p;
+
+	if (!arg)
+		return -1;
+
+	errno = 0;
+	ul = strtoul(arg, &endp, 8);
+	if (errno || endp == arg || *endp != ',' || (unsigned int) ul != ul)
+		return -1; /* not a new-style cacheinfo */
+	*mode = ul;
+	endp++;
+	if (parse_oid_hex(endp, oid, &p) || *p != ',')
+		return -1;
+	*path = p + 1;
+	return 0;
+}
+
+static enum parse_opt_result cacheinfo_callback(
+	struct parse_opt_ctx_t *ctx, const struct option *opt UNUSED,
+	const char *arg, int unset)
+{
+	struct object_id oid;
+	unsigned int mode;
+	const char *path;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	if (!parse_new_style_cacheinfo(ctx->argv[1], &mode, &oid, &path)) {
+		if (add_cacheinfo(mode, &oid, path, 0))
+			die("git update-index: --cacheinfo cannot add %s", path);
+		ctx->argv++;
+		ctx->argc--;
+		return 0;
+	}
+	if (ctx->argc <= 3)
+		return error("option 'cacheinfo' expects <mode>,<sha1>,<path>");
+	if (strtoul_ui(*++ctx->argv, 8, &mode) ||
+	    get_oid_hex(*++ctx->argv, &oid) ||
+	    add_cacheinfo(mode, &oid, *++ctx->argv, 0))
+		die("git update-index: --cacheinfo cannot add %s", *ctx->argv);
+	ctx->argc -= 3;
+	return 0;
+}
+
+static enum parse_opt_result stdin_cacheinfo_callback(
+	struct parse_opt_ctx_t *ctx, const struct option *opt,
+	const char *arg, int unset)
+{
+	int *nul_term_line = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	if (ctx->argc != 1)
+		return error("option '%s' must be the last argument", opt->long_name);
+	allow_add = allow_replace = allow_remove = 1;
+	read_index_info(*nul_term_line);
+	return 0;
+}
+
+static enum parse_opt_result stdin_callback(
+	struct parse_opt_ctx_t *ctx, const struct option *opt,
+	const char *arg, int unset)
+{
+	int *read_from_stdin = opt->value;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	if (ctx->argc != 1)
+		return error("option '%s' must be the last argument", opt->long_name);
+	*read_from_stdin = 1;
+	return 0;
+}
+
+static enum parse_opt_result unresolve_callback(
+	struct parse_opt_ctx_t *ctx, const struct option *opt,
+	const char *arg, int unset)
+{
+	int *has_errors = opt->value;
+	const char *prefix = startup_info->prefix;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	/* consume remaining arguments. */
+	*has_errors = do_unresolve(ctx->argc, ctx->argv,
+				prefix, prefix ? strlen(prefix) : 0);
+	if (*has_errors)
+		the_repository->index->cache_changed = 0;
+
+	ctx->argv += ctx->argc - 1;
+	ctx->argc = 1;
+	return 0;
+}
+
+static enum parse_opt_result reupdate_callback(
+	struct parse_opt_ctx_t *ctx, const struct option *opt,
+	const char *arg, int unset)
+{
+	int *has_errors = opt->value;
+	const char *prefix = startup_info->prefix;
+
+	BUG_ON_OPT_NEG(unset);
+	BUG_ON_OPT_ARG(arg);
+
+	/* consume remaining arguments. */
+	setup_work_tree();
+	*has_errors = do_reupdate(ctx->argv + 1, prefix);
+	if (*has_errors)
+		the_repository->index->cache_changed = 0;
+
+	ctx->argv += ctx->argc - 1;
+	ctx->argc = 1;
+	return 0;
+}
+
+int cmd_update_index(int argc,
+		     const char **argv,
+		     const char *prefix,
+		     struct repository *repo UNUSED)
+{
+	int newfd, entries, has_errors = 0, nul_term_line = 0;
+	enum uc_mode untracked_cache = UC_UNSPECIFIED;
+	int read_from_stdin = 0;
+	int prefix_length = prefix ? strlen(prefix) : 0;
+	int preferred_index_format = 0;
+	char set_executable_bit = 0;
+	struct refresh_params refresh_args = {0, &has_errors};
+	int lock_error = 0;
+	int split_index = -1;
+	int force_write = 0;
+	int fsmonitor = -1;
+	struct lock_file lock_file = LOCK_INIT;
+	struct parse_opt_ctx_t ctx;
+	strbuf_getline_fn getline_fn;
+	int parseopt_state = PARSE_OPT_UNKNOWN;
+	struct repository *r = the_repository;
+	struct option options[] = {
+		OPT_BIT('q', NULL, &refresh_args.flags,
+			N_("continue refresh even when index needs update"),
+			REFRESH_QUIET),
+		OPT_BIT(0, "ignore-submodules", &refresh_args.flags,
+			N_("refresh: ignore submodules"),
+			REFRESH_IGNORE_SUBMODULES),
+		OPT_SET_INT(0, "add", &allow_add,
+			N_("do not ignore new files"), 1),
+		OPT_SET_INT(0, "replace", &allow_replace,
+			N_("let files replace directories and vice-versa"), 1),
+		OPT_SET_INT(0, "remove", &allow_remove,
+			N_("notice files missing from worktree"), 1),
+		OPT_BIT(0, "unmerged", &refresh_args.flags,
+			N_("refresh even if index contains unmerged entries"),
+			REFRESH_UNMERGED),
+		OPT_CALLBACK_F(0, "refresh", &refresh_args, NULL,
+			N_("refresh stat information"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			refresh_callback),
+		OPT_CALLBACK_F(0, "really-refresh", &refresh_args, NULL,
+			N_("like --refresh, but ignore assume-unchanged setting"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			really_refresh_callback),
+		{OPTION_LOWLEVEL_CALLBACK, 0, "cacheinfo", NULL,
+			N_("<mode>,<object>,<path>"),
+			N_("add the specified entry to the index"),
+			PARSE_OPT_NOARG | /* disallow --cacheinfo=<mode> form */
+			PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,
+			NULL, 0,
+			cacheinfo_callback},
+		OPT_CALLBACK_F(0, "chmod", &set_executable_bit, "(+|-)x",
+			N_("override the executable bit of the listed files"),
+			PARSE_OPT_NONEG,
+			chmod_callback),
+		{OPTION_SET_INT, 0, "assume-unchanged", &mark_valid_only, NULL,
+			N_("mark files as \"not changing\""),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
+		{OPTION_SET_INT, 0, "no-assume-unchanged", &mark_valid_only, NULL,
+			N_("clear assumed-unchanged bit"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
+		{OPTION_SET_INT, 0, "skip-worktree", &mark_skip_worktree_only, NULL,
+			N_("mark files as \"index-only\""),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
+		{OPTION_SET_INT, 0, "no-skip-worktree", &mark_skip_worktree_only, NULL,
+			N_("clear skip-worktree bit"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
+		OPT_BOOL(0, "ignore-skip-worktree-entries", &ignore_skip_worktree_entries,
+			 N_("do not touch index-only entries")),
+		OPT_SET_INT(0, "info-only", &info_only,
+			N_("add to index only; do not add content to object database"), 1),
+		OPT_SET_INT(0, "force-remove", &force_remove,
+			N_("remove named paths even if present in worktree"), 1),
+		OPT_BOOL('z', NULL, &nul_term_line,
+			 N_("with --stdin: input lines are terminated by null bytes")),
+		{OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL,
+			N_("read list of paths to be updated from standard input"),
+			PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+			NULL, 0, stdin_callback},
+		{OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL,
+			N_("add entries from standard input to the index"),
+			PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+			NULL, 0, stdin_cacheinfo_callback},
+		{OPTION_LOWLEVEL_CALLBACK, 0, "unresolve", &has_errors, NULL,
+			N_("repopulate stages #2 and #3 for the listed paths"),
+			PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+			NULL, 0, unresolve_callback},
+		{OPTION_LOWLEVEL_CALLBACK, 'g', "again", &has_errors, NULL,
+			N_("only update entries that differ from HEAD"),
+			PARSE_OPT_NONEG | PARSE_OPT_NOARG,
+			NULL, 0, reupdate_callback},
+		OPT_BIT(0, "ignore-missing", &refresh_args.flags,
+			N_("ignore files missing from worktree"),
+			REFRESH_IGNORE_MISSING),
+		OPT_SET_INT(0, "verbose", &verbose,
+			N_("report actions to standard output"), 1),
+		OPT_CALLBACK_F(0, "clear-resolve-undo", NULL, NULL,
+			N_("(for porcelains) forget saved unresolved conflicts"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG,
+			resolve_undo_clear_callback),
+		OPT_INTEGER(0, "index-version", &preferred_index_format,
+			N_("write index in this format")),
+		OPT_SET_INT(0, "show-index-version", &preferred_index_format,
+			    N_("report on-disk index format version"), -1),
+		OPT_BOOL(0, "split-index", &split_index,
+			N_("enable or disable split index")),
+		OPT_BOOL(0, "untracked-cache", &untracked_cache,
+			N_("enable/disable untracked cache")),
+		OPT_SET_INT(0, "test-untracked-cache", &untracked_cache,
+			    N_("test if the filesystem supports untracked cache"), UC_TEST),
+		OPT_SET_INT(0, "force-untracked-cache", &untracked_cache,
+			    N_("enable untracked cache without testing the filesystem"), UC_FORCE),
+		OPT_SET_INT(0, "force-write-index", &force_write,
+			N_("write out the index even if is not flagged as changed"), 1),
+		OPT_BOOL(0, "fsmonitor", &fsmonitor,
+			N_("enable or disable file system monitor")),
+		{OPTION_SET_INT, 0, "fsmonitor-valid", &mark_fsmonitor_only, NULL,
+			N_("mark files as fsmonitor valid"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
+		{OPTION_SET_INT, 0, "no-fsmonitor-valid", &mark_fsmonitor_only, NULL,
+			N_("clear fsmonitor valid bit"),
+			PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
+		OPT_END()
+	};
+
+	show_usage_with_options_if_asked(argc, argv,
+					 update_index_usage, options);
+
+	git_config(git_default_config, NULL);
+
+	prepare_repo_settings(r);
+	the_repository->settings.command_requires_full_index = 0;
+
+	/* we will diagnose later if it turns out that we need to update it */
+	newfd = repo_hold_locked_index(the_repository, &lock_file, 0);
+	if (newfd < 0)
+		lock_error = errno;
+
+	entries = repo_read_index(the_repository);
+	if (entries < 0)
+		die("cache corrupted");
+
+	the_repository->index->updated_skipworktree = 1;
+
+	/*
+	 * Custom copy of parse_options() because we want to handle
+	 * filename arguments as they come.
+	 */
+	parse_options_start(&ctx, argc, argv, prefix,
+			    options, PARSE_OPT_STOP_AT_NON_OPTION);
+
+	/*
+	 * Allow the object layer to optimize adding multiple objects in
+	 * a batch.
+	 */
+	begin_odb_transaction();
+	while (ctx.argc) {
+		if (parseopt_state != PARSE_OPT_DONE)
+			parseopt_state = parse_options_step(&ctx, options,
+							    update_index_usage);
+		if (!ctx.argc)
+			break;
+		switch (parseopt_state) {
+		case PARSE_OPT_HELP:
+		case PARSE_OPT_ERROR:
+			exit(129);
+		case PARSE_OPT_COMPLETE:
+			exit(0);
+		case PARSE_OPT_NON_OPTION:
+		case PARSE_OPT_DONE:
+		{
+			const char *path = ctx.argv[0];
+			char *p;
+
+			setup_work_tree();
+			p = prefix_path(prefix, prefix_length, path);
+			update_one(p);
+			if (set_executable_bit)
+				chmod_path(set_executable_bit, p);
+			free(p);
+			ctx.argc--;
+			ctx.argv++;
+			break;
+		}
+		case PARSE_OPT_UNKNOWN:
+			if (ctx.argv[0][1] == '-')
+				error("unknown option '%s'", ctx.argv[0] + 2);
+			else
+				error("unknown switch '%c'", *ctx.opt);
+			usage_with_options(update_index_usage, options);
+		}
+	}
+	argc = parse_options_end(&ctx);
+
+	getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
+	if (preferred_index_format) {
+		if (preferred_index_format < 0) {
+			printf(_("%d\n"), the_repository->index->version);
+		} else if (preferred_index_format < INDEX_FORMAT_LB ||
+			   INDEX_FORMAT_UB < preferred_index_format) {
+			die("index-version %d not in range: %d..%d",
+			    preferred_index_format,
+			    INDEX_FORMAT_LB, INDEX_FORMAT_UB);
+		} else {
+			if (the_repository->index->version != preferred_index_format)
+				the_repository->index->cache_changed |= SOMETHING_CHANGED;
+			report(_("index-version: was %d, set to %d"),
+			       the_repository->index->version, preferred_index_format);
+			the_repository->index->version = preferred_index_format;
+		}
+	}
+
+	if (read_from_stdin) {
+		struct strbuf buf = STRBUF_INIT;
+		struct strbuf unquoted = STRBUF_INIT;
+
+		setup_work_tree();
+		while (getline_fn(&buf, stdin) != EOF) {
+			char *p;
+			if (!nul_term_line && buf.buf[0] == '"') {
+				strbuf_reset(&unquoted);
+				if (unquote_c_style(&unquoted, buf.buf, NULL))
+					die("line is badly quoted");
+				strbuf_swap(&buf, &unquoted);
+			}
+			p = prefix_path(prefix, prefix_length, buf.buf);
+			update_one(p);
+			if (set_executable_bit)
+				chmod_path(set_executable_bit, p);
+			free(p);
+		}
+		strbuf_release(&unquoted);
+		strbuf_release(&buf);
+	}
+
+	/*
+	 * By now we have added all of the new objects
+	 */
+	end_odb_transaction();
+
+	if (split_index > 0) {
+		if (repo_config_get_split_index(the_repository) == 0)
+			warning(_("core.splitIndex is set to false; "
+				  "remove or change it, if you really want to "
+				  "enable split index"));
+		if (the_repository->index->split_index)
+			the_repository->index->cache_changed |= SPLIT_INDEX_ORDERED;
+		else
+			add_split_index(the_repository->index);
+	} else if (!split_index) {
+		if (repo_config_get_split_index(the_repository) == 1)
+			warning(_("core.splitIndex is set to true; "
+				  "remove or change it, if you really want to "
+				  "disable split index"));
+		remove_split_index(the_repository->index);
+	}
+
+	prepare_repo_settings(r);
+	switch (untracked_cache) {
+	case UC_UNSPECIFIED:
+		break;
+	case UC_DISABLE:
+		if (r->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE)
+			warning(_("core.untrackedCache is set to true; "
+				  "remove or change it, if you really want to "
+				  "disable the untracked cache"));
+		remove_untracked_cache(the_repository->index);
+		report(_("Untracked cache disabled"));
+		break;
+	case UC_TEST:
+		setup_work_tree();
+		return !test_if_untracked_cache_is_supported();
+	case UC_ENABLE:
+	case UC_FORCE:
+		if (r->settings.core_untracked_cache == UNTRACKED_CACHE_REMOVE)
+			warning(_("core.untrackedCache is set to false; "
+				  "remove or change it, if you really want to "
+				  "enable the untracked cache"));
+		add_untracked_cache(the_repository->index);
+		report(_("Untracked cache enabled for '%s'"), repo_get_work_tree(the_repository));
+		break;
+	default:
+		BUG("bad untracked_cache value: %d", untracked_cache);
+	}
+
+	if (fsmonitor > 0) {
+		enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+		enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+		/*
+		 * The user wants to turn on FSMonitor using the command
+		 * line argument.  (We don't know (or care) whether that
+		 * is the IPC or HOOK version.)
+		 *
+		 * Use one of the __get routines to force load the FSMonitor
+		 * config settings into the repo-settings.  That will detect
+		 * whether the file system is compatible so that we can stop
+		 * here with a nice error message.
+		 */
+		if (reason > FSMONITOR_REASON_OK)
+			die("%s",
+			    fsm_settings__get_incompatible_msg(r, reason));
+
+		if (fsm_mode == FSMONITOR_MODE_DISABLED) {
+			warning(_("core.fsmonitor is unset; "
+				"set it if you really want to "
+				"enable fsmonitor"));
+		}
+		add_fsmonitor(the_repository->index);
+		report(_("fsmonitor enabled"));
+	} else if (!fsmonitor) {
+		enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+		if (fsm_mode > FSMONITOR_MODE_DISABLED)
+			warning(_("core.fsmonitor is set; "
+				"remove it if you really want to "
+				"disable fsmonitor"));
+		remove_fsmonitor(the_repository->index);
+		report(_("fsmonitor disabled"));
+	}
+
+	if (the_repository->index->cache_changed || force_write) {
+		if (newfd < 0) {
+			if (refresh_args.flags & REFRESH_QUIET)
+				exit(128);
+			unable_to_lock_die(repo_get_index_file(the_repository), lock_error);
+		}
+		if (write_locked_index(the_repository->index, &lock_file, COMMIT_LOCK))
+			die("Unable to write new index file");
+	}
+
+	rollback_lock_file(&lock_file);
+
+	return has_errors ? 1 : 0;
+}
diff --git a/builtin/update-ref.c b/builtin/update-ref.c
new file mode 100644
index 0000000000..4d35bdc4b4
--- /dev/null
+++ b/builtin/update-ref.c
@@ -0,0 +1,805 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "hash.h"
+#include "refs.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "quote.h"
+
+static const char * const git_update_ref_usage[] = {
+	N_("git update-ref [<options>] -d <refname> [<old-oid>]"),
+	N_("git update-ref [<options>]    <refname> <new-oid> [<old-oid>]"),
+	N_("git update-ref [<options>] --stdin [-z]"),
+	NULL
+};
+
+static char line_termination = '\n';
+static unsigned int update_flags;
+static unsigned int default_flags;
+static unsigned create_reflog_flag;
+static const char *msg;
+
+/*
+ * Parse one whitespace- or NUL-terminated, possibly C-quoted argument
+ * and append the result to arg.  Return a pointer to the terminator.
+ * Die if there is an error in how the argument is C-quoted.  This
+ * function is only used if not -z.
+ */
+static const char *parse_arg(const char *next, struct strbuf *arg)
+{
+	if (*next == '"') {
+		const char *orig = next;
+
+		if (unquote_c_style(arg, next, &next))
+			die("badly quoted argument: %s", orig);
+		if (*next && !isspace(*next))
+			die("unexpected character after quoted argument: %s", orig);
+	} else {
+		while (*next && !isspace(*next))
+			strbuf_addch(arg, *next++);
+	}
+
+	return next;
+}
+
+/*
+ * Parse the reference name immediately after "command SP".  If not
+ * -z, then handle C-quoting.  Return a pointer to a newly allocated
+ * string containing the name of the reference, or NULL if there was
+ * an error.  Update *next to point at the character that terminates
+ * the argument.  Die if C-quoting is malformed or the reference name
+ * is invalid.
+ */
+static char *parse_refname(const char **next)
+{
+	struct strbuf ref = STRBUF_INIT;
+
+	if (line_termination) {
+		/* Without -z, use the next argument */
+		*next = parse_arg(*next, &ref);
+	} else {
+		/* With -z, use everything up to the next NUL */
+		strbuf_addstr(&ref, *next);
+		*next += ref.len;
+	}
+
+	if (!ref.len) {
+		strbuf_release(&ref);
+		return NULL;
+	}
+
+	if (check_refname_format(ref.buf, REFNAME_ALLOW_ONELEVEL))
+		die("invalid ref format: %s", ref.buf);
+
+	return strbuf_detach(&ref, NULL);
+}
+
+/*
+ * Wrapper around parse_refname which skips the next delimiter.
+ */
+static char *parse_next_refname(const char **next)
+{
+	if (line_termination) {
+		/* Without -z, consume SP and use next argument */
+		if (!**next || **next == line_termination)
+			return NULL;
+		if (**next != ' ')
+			die("expected SP but got: %s", *next);
+	} else {
+		/* With -z, read the next NUL-terminated line */
+		if (**next)
+			return NULL;
+	}
+	/* Skip the delimiter */
+	(*next)++;
+
+	return parse_refname(next);
+}
+
+/*
+ * Wrapper around parse_arg which skips the next delimiter.
+ */
+static char *parse_next_arg(const char **next)
+{
+	struct strbuf arg = STRBUF_INIT;
+
+	if (line_termination) {
+		/* Without -z, consume SP and use next argument */
+		if (!**next || **next == line_termination)
+			return NULL;
+		if (**next != ' ')
+			die("expected SP but got: %s", *next);
+	} else {
+		/* With -z, read the next NUL-terminated line */
+		if (**next)
+			return NULL;
+	}
+	/* Skip the delimiter */
+	(*next)++;
+
+	if (line_termination) {
+		/* Without -z, use the next argument */
+		*next = parse_arg(*next, &arg);
+	} else {
+		/* With -z, use everything up to the next NUL */
+		strbuf_addstr(&arg, *next);
+		*next += arg.len;
+	}
+
+	if (arg.len)
+		return strbuf_detach(&arg, NULL);
+
+	strbuf_release(&arg);
+	return NULL;
+}
+
+/*
+ * The value being parsed is <old-oid> (as opposed to <new-oid>; the
+ * difference affects which error messages are generated):
+ */
+#define PARSE_SHA1_OLD 0x01
+
+/*
+ * For backwards compatibility, accept an empty string for update's
+ * <new-oid> in binary mode to be equivalent to specifying zeros.
+ */
+#define PARSE_SHA1_ALLOW_EMPTY 0x02
+
+/*
+ * Parse an argument separator followed by the next argument, if any.
+ * If there is an argument, convert it to a SHA-1, write it to sha1,
+ * set *next to point at the character terminating the argument, and
+ * return 0.  If there is no argument at all (not even the empty
+ * string), return 1 and leave *next unchanged.  If the value is
+ * provided but cannot be converted to a SHA-1, die.  flags can
+ * include PARSE_SHA1_OLD and/or PARSE_SHA1_ALLOW_EMPTY.
+ */
+static int parse_next_oid(const char **next, const char *end,
+			  struct object_id *oid,
+			  const char *command, const char *refname,
+			  int flags)
+{
+	struct strbuf arg = STRBUF_INIT;
+	int ret = 0;
+
+	if (*next == end)
+		goto eof;
+
+	if (line_termination) {
+		/* Without -z, consume SP and use next argument */
+		if (!**next || **next == line_termination)
+			return 1;
+		if (**next != ' ')
+			die("%s %s: expected SP but got: %s",
+			    command, refname, *next);
+		(*next)++;
+		*next = parse_arg(*next, &arg);
+		if (arg.len) {
+			if (repo_get_oid(the_repository, arg.buf, oid))
+				goto invalid;
+		} else {
+			/* Without -z, an empty value means all zeros: */
+			oidclr(oid, the_repository->hash_algo);
+		}
+	} else {
+		/* With -z, read the next NUL-terminated line */
+		if (**next)
+			die("%s %s: expected NUL but got: %s",
+			    command, refname, *next);
+		(*next)++;
+		if (*next == end)
+			goto eof;
+		strbuf_addstr(&arg, *next);
+		*next += arg.len;
+
+		if (arg.len) {
+			if (repo_get_oid(the_repository, arg.buf, oid))
+				goto invalid;
+		} else if (flags & PARSE_SHA1_ALLOW_EMPTY) {
+			/* With -z, treat an empty value as all zeros: */
+			warning("%s %s: missing <new-oid>, treating as zero",
+				command, refname);
+			oidclr(oid, the_repository->hash_algo);
+		} else {
+			/*
+			 * With -z, an empty non-required value means
+			 * unspecified:
+			 */
+			ret = 1;
+		}
+	}
+
+	strbuf_release(&arg);
+
+	return ret;
+
+ invalid:
+	die(flags & PARSE_SHA1_OLD ?
+	    "%s %s: invalid <old-oid>: %s" :
+	    "%s %s: invalid <new-oid>: %s",
+	    command, refname, arg.buf);
+
+ eof:
+	die(flags & PARSE_SHA1_OLD ?
+	    "%s %s: unexpected end of input when reading <old-oid>" :
+	    "%s %s: unexpected end of input when reading <new-oid>",
+	    command, refname);
+}
+
+
+/*
+ * The following five parse_cmd_*() functions parse the corresponding
+ * command.  In each case, next points at the character following the
+ * command name and the following space.  They each return a pointer
+ * to the character terminating the command, and die with an
+ * explanatory message if there are any parsing problems.  All of
+ * these functions handle either text or binary format input,
+ * depending on how line_termination is set.
+ */
+
+static void parse_cmd_update(struct ref_transaction *transaction,
+			     const char *next, const char *end)
+{
+	struct strbuf err = STRBUF_INIT;
+	char *refname;
+	struct object_id new_oid, old_oid;
+	int have_old;
+
+	refname = parse_refname(&next);
+	if (!refname)
+		die("update: missing <ref>");
+
+	if (parse_next_oid(&next, end, &new_oid, "update", refname,
+			   PARSE_SHA1_ALLOW_EMPTY))
+		die("update %s: missing <new-oid>", refname);
+
+	have_old = !parse_next_oid(&next, end, &old_oid, "update", refname,
+				   PARSE_SHA1_OLD);
+
+	if (*next != line_termination)
+		die("update %s: extra input: %s", refname, next);
+
+	if (ref_transaction_update(transaction, refname,
+				   &new_oid, have_old ? &old_oid : NULL,
+				   NULL, NULL,
+				   update_flags | create_reflog_flag,
+				   msg, &err))
+		die("%s", err.buf);
+
+	update_flags = default_flags;
+	free(refname);
+	strbuf_release(&err);
+}
+
+static void parse_cmd_symref_update(struct ref_transaction *transaction,
+				    const char *next, const char *end UNUSED)
+{
+	char *refname, *new_target, *old_arg;
+	char *old_target = NULL;
+	struct strbuf err = STRBUF_INIT;
+	struct object_id old_oid;
+	int have_old_oid = 0;
+
+	refname = parse_refname(&next);
+	if (!refname)
+		die("symref-update: missing <ref>");
+
+	new_target = parse_next_refname(&next);
+	if (!new_target)
+		die("symref-update %s: missing <new-target>", refname);
+
+	old_arg = parse_next_arg(&next);
+	if (old_arg) {
+		old_target = parse_next_arg(&next);
+		if (!old_target)
+			die("symref-update %s: expected old value", refname);
+
+		if (!strcmp(old_arg, "oid")) {
+			if (repo_get_oid(the_repository, old_target, &old_oid))
+				die("symref-update %s: invalid oid: %s", refname, old_target);
+
+			have_old_oid = 1;
+		} else if (!strcmp(old_arg, "ref")) {
+			if (check_refname_format(old_target, REFNAME_ALLOW_ONELEVEL))
+				die("symref-update %s: invalid ref: %s", refname, old_target);
+		} else {
+			die("symref-update %s: invalid arg '%s' for old value", refname, old_arg);
+		}
+	}
+
+	if (*next != line_termination)
+		die("symref-update %s: extra input: %s", refname, next);
+
+	if (ref_transaction_update(transaction, refname, NULL,
+				   have_old_oid ? &old_oid : NULL,
+				   new_target,
+				   have_old_oid ? NULL : old_target,
+				   update_flags | create_reflog_flag,
+				   msg, &err))
+		die("%s", err.buf);
+
+	update_flags = default_flags;
+	free(refname);
+	free(old_arg);
+	free(old_target);
+	free(new_target);
+	strbuf_release(&err);
+}
+
+static void parse_cmd_create(struct ref_transaction *transaction,
+			     const char *next, const char *end)
+{
+	struct strbuf err = STRBUF_INIT;
+	char *refname;
+	struct object_id new_oid;
+
+	refname = parse_refname(&next);
+	if (!refname)
+		die("create: missing <ref>");
+
+	if (parse_next_oid(&next, end, &new_oid, "create", refname, 0))
+		die("create %s: missing <new-oid>", refname);
+
+	if (is_null_oid(&new_oid))
+		die("create %s: zero <new-oid>", refname);
+
+	if (*next != line_termination)
+		die("create %s: extra input: %s", refname, next);
+
+	if (ref_transaction_create(transaction, refname, &new_oid, NULL,
+				   update_flags | create_reflog_flag,
+				   msg, &err))
+		die("%s", err.buf);
+
+	update_flags = default_flags;
+	free(refname);
+	strbuf_release(&err);
+}
+
+
+static void parse_cmd_symref_create(struct ref_transaction *transaction,
+				    const char *next, const char *end UNUSED)
+{
+	struct strbuf err = STRBUF_INIT;
+	char *refname, *new_target;
+
+	refname = parse_refname(&next);
+	if (!refname)
+		die("symref-create: missing <ref>");
+
+	new_target = parse_next_refname(&next);
+	if (!new_target)
+		die("symref-create %s: missing <new-target>", refname);
+
+	if (*next != line_termination)
+		die("symref-create %s: extra input: %s", refname, next);
+
+	if (ref_transaction_create(transaction, refname, NULL, new_target,
+				   update_flags | create_reflog_flag,
+				   msg, &err))
+		die("%s", err.buf);
+
+	update_flags = default_flags;
+	free(refname);
+	free(new_target);
+	strbuf_release(&err);
+}
+
+static void parse_cmd_delete(struct ref_transaction *transaction,
+			     const char *next, const char *end)
+{
+	struct strbuf err = STRBUF_INIT;
+	char *refname;
+	struct object_id old_oid;
+	int have_old;
+
+	refname = parse_refname(&next);
+	if (!refname)
+		die("delete: missing <ref>");
+
+	if (parse_next_oid(&next, end, &old_oid, "delete", refname,
+			   PARSE_SHA1_OLD)) {
+		have_old = 0;
+	} else {
+		if (is_null_oid(&old_oid))
+			die("delete %s: zero <old-oid>", refname);
+		have_old = 1;
+	}
+
+	if (*next != line_termination)
+		die("delete %s: extra input: %s", refname, next);
+
+	if (ref_transaction_delete(transaction, refname,
+				   have_old ? &old_oid : NULL,
+				   NULL, update_flags, msg, &err))
+		die("%s", err.buf);
+
+	update_flags = default_flags;
+	free(refname);
+	strbuf_release(&err);
+}
+
+
+static void parse_cmd_symref_delete(struct ref_transaction *transaction,
+				    const char *next, const char *end UNUSED)
+{
+	struct strbuf err = STRBUF_INIT;
+	char *refname, *old_target;
+
+	if (!(update_flags & REF_NO_DEREF))
+		die("symref-delete: cannot operate with deref mode");
+
+	refname = parse_refname(&next);
+	if (!refname)
+		die("symref-delete: missing <ref>");
+
+	old_target = parse_next_refname(&next);
+
+	if (*next != line_termination)
+		die("symref-delete %s: extra input: %s", refname, next);
+
+	if (ref_transaction_delete(transaction, refname, NULL,
+				   old_target, update_flags, msg, &err))
+		die("%s", err.buf);
+
+	update_flags = default_flags;
+	free(refname);
+	free(old_target);
+	strbuf_release(&err);
+}
+
+
+static void parse_cmd_verify(struct ref_transaction *transaction,
+			     const char *next, const char *end)
+{
+	struct strbuf err = STRBUF_INIT;
+	char *refname;
+	struct object_id old_oid;
+
+	refname = parse_refname(&next);
+	if (!refname)
+		die("verify: missing <ref>");
+
+	if (parse_next_oid(&next, end, &old_oid, "verify", refname,
+			   PARSE_SHA1_OLD))
+		oidclr(&old_oid, the_repository->hash_algo);
+
+	if (*next != line_termination)
+		die("verify %s: extra input: %s", refname, next);
+
+	if (ref_transaction_verify(transaction, refname, &old_oid,
+				   NULL, update_flags, &err))
+		die("%s", err.buf);
+
+	update_flags = default_flags;
+	free(refname);
+	strbuf_release(&err);
+}
+
+static void parse_cmd_symref_verify(struct ref_transaction *transaction,
+				    const char *next, const char *end UNUSED)
+{
+	struct strbuf err = STRBUF_INIT;
+	struct object_id old_oid;
+	char *refname, *old_target;
+
+	if (!(update_flags & REF_NO_DEREF))
+		die("symref-verify: cannot operate with deref mode");
+
+	refname = parse_refname(&next);
+	if (!refname)
+		die("symref-verify: missing <ref>");
+
+	/*
+	 * old_ref is optional, if not provided, we need to ensure that the
+	 * ref doesn't exist.
+	 */
+	old_target = parse_next_refname(&next);
+	if (!old_target)
+		oidcpy(&old_oid, null_oid());
+
+	if (*next != line_termination)
+		die("symref-verify %s: extra input: %s", refname, next);
+
+	if (ref_transaction_verify(transaction, refname,
+				   old_target ? NULL : &old_oid,
+				   old_target, update_flags, &err))
+		die("%s", err.buf);
+
+	update_flags = default_flags;
+	free(refname);
+	free(old_target);
+	strbuf_release(&err);
+}
+
+static void report_ok(const char *command)
+{
+	fprintf(stdout, "%s: ok\n", command);
+	fflush(stdout);
+}
+
+static void parse_cmd_option(struct ref_transaction *transaction UNUSED,
+			     const char *next, const char *end UNUSED)
+{
+	const char *rest;
+	if (skip_prefix(next, "no-deref", &rest) && *rest == line_termination)
+		update_flags |= REF_NO_DEREF;
+	else
+		die("option unknown: %s", next);
+}
+
+static void parse_cmd_start(struct ref_transaction *transaction UNUSED,
+			    const char *next, const char *end UNUSED)
+{
+	if (*next != line_termination)
+		die("start: extra input: %s", next);
+	report_ok("start");
+}
+
+static void parse_cmd_prepare(struct ref_transaction *transaction,
+			      const char *next, const char *end UNUSED)
+{
+	struct strbuf error = STRBUF_INIT;
+	if (*next != line_termination)
+		die("prepare: extra input: %s", next);
+	if (ref_transaction_prepare(transaction, &error))
+		die("prepare: %s", error.buf);
+	report_ok("prepare");
+}
+
+static void parse_cmd_abort(struct ref_transaction *transaction,
+			    const char *next, const char *end UNUSED)
+{
+	struct strbuf error = STRBUF_INIT;
+	if (*next != line_termination)
+		die("abort: extra input: %s", next);
+	if (ref_transaction_abort(transaction, &error))
+		die("abort: %s", error.buf);
+	report_ok("abort");
+}
+
+static void parse_cmd_commit(struct ref_transaction *transaction,
+			     const char *next, const char *end UNUSED)
+{
+	struct strbuf error = STRBUF_INIT;
+	if (*next != line_termination)
+		die("commit: extra input: %s", next);
+	if (ref_transaction_commit(transaction, &error))
+		die("commit: %s", error.buf);
+	report_ok("commit");
+	ref_transaction_free(transaction);
+}
+
+enum update_refs_state {
+	/* Non-transactional state open for updates. */
+	UPDATE_REFS_OPEN,
+	/* A transaction has been started. */
+	UPDATE_REFS_STARTED,
+	/* References are locked and ready for commit */
+	UPDATE_REFS_PREPARED,
+	/* Transaction has been committed or closed. */
+	UPDATE_REFS_CLOSED,
+};
+
+static const struct parse_cmd {
+	const char *prefix;
+	void (*fn)(struct ref_transaction *, const char *, const char *);
+	unsigned args;
+	enum update_refs_state state;
+} command[] = {
+	{ "update",        parse_cmd_update,        3, UPDATE_REFS_OPEN },
+	{ "create",        parse_cmd_create,        2, UPDATE_REFS_OPEN },
+	{ "delete",        parse_cmd_delete,        2, UPDATE_REFS_OPEN },
+	{ "verify",        parse_cmd_verify,        2, UPDATE_REFS_OPEN },
+	{ "symref-update", parse_cmd_symref_update, 4, UPDATE_REFS_OPEN },
+	{ "symref-create", parse_cmd_symref_create, 2, UPDATE_REFS_OPEN },
+	{ "symref-delete", parse_cmd_symref_delete, 2, UPDATE_REFS_OPEN },
+	{ "symref-verify", parse_cmd_symref_verify, 2, UPDATE_REFS_OPEN },
+	{ "option",        parse_cmd_option,        1, UPDATE_REFS_OPEN },
+	{ "start",         parse_cmd_start,         0, UPDATE_REFS_STARTED },
+	{ "prepare",       parse_cmd_prepare,       0, UPDATE_REFS_PREPARED },
+	{ "abort",         parse_cmd_abort,         0, UPDATE_REFS_CLOSED },
+	{ "commit",        parse_cmd_commit,        0, UPDATE_REFS_CLOSED },
+};
+
+static void update_refs_stdin(void)
+{
+	struct strbuf input = STRBUF_INIT, err = STRBUF_INIT;
+	enum update_refs_state state = UPDATE_REFS_OPEN;
+	struct ref_transaction *transaction;
+	int i, j;
+
+	transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+						  0, &err);
+	if (!transaction)
+		die("%s", err.buf);
+
+	/* Read each line dispatch its command */
+	while (!strbuf_getwholeline(&input, stdin, line_termination)) {
+		const struct parse_cmd *cmd = NULL;
+
+		if (*input.buf == line_termination)
+			die("empty command in input");
+		else if (isspace(*input.buf))
+			die("whitespace before command: %s", input.buf);
+
+		for (i = 0; i < ARRAY_SIZE(command); i++) {
+			const char *prefix = command[i].prefix;
+			char c;
+
+			if (!starts_with(input.buf, prefix))
+				continue;
+
+			/*
+			 * If the command has arguments, verify that it's
+			 * followed by a space. Otherwise, it shall be followed
+			 * by a line terminator.
+			 */
+			c = command[i].args ? ' ' : line_termination;
+			if (input.buf[strlen(prefix)] != c)
+				continue;
+
+			cmd = &command[i];
+			break;
+		}
+		if (!cmd)
+			die("unknown command: %s", input.buf);
+
+		/*
+		 * Read additional arguments if NUL-terminated. Do not raise an
+		 * error in case there is an early EOF to let the command
+		 * handle missing arguments with a proper error message.
+		 */
+		for (j = 1; line_termination == '\0' && j < cmd->args; j++)
+			if (strbuf_appendwholeline(&input, stdin, line_termination))
+				break;
+
+		switch (state) {
+		case UPDATE_REFS_OPEN:
+		case UPDATE_REFS_STARTED:
+			if (state == UPDATE_REFS_STARTED && cmd->state == UPDATE_REFS_STARTED)
+				die("cannot restart ongoing transaction");
+			/* Do not downgrade a transaction to a non-transaction. */
+			if (cmd->state >= state)
+				state = cmd->state;
+			break;
+		case UPDATE_REFS_PREPARED:
+			if (cmd->state != UPDATE_REFS_CLOSED)
+				die("prepared transactions can only be closed");
+			state = cmd->state;
+			break;
+		case UPDATE_REFS_CLOSED:
+			if (cmd->state != UPDATE_REFS_STARTED)
+				die("transaction is closed");
+
+			/*
+			 * Open a new transaction if we're currently closed and
+			 * get a "start".
+			 */
+			state = cmd->state;
+			transaction = ref_store_transaction_begin(get_main_ref_store(the_repository),
+								  0, &err);
+			if (!transaction)
+				die("%s", err.buf);
+
+			break;
+		}
+
+		cmd->fn(transaction, input.buf + strlen(cmd->prefix) + !!cmd->args,
+			input.buf + input.len);
+	}
+
+	switch (state) {
+	case UPDATE_REFS_OPEN:
+		/* Commit by default if no transaction was requested. */
+		if (ref_transaction_commit(transaction, &err))
+			die("%s", err.buf);
+		ref_transaction_free(transaction);
+		break;
+	case UPDATE_REFS_STARTED:
+	case UPDATE_REFS_PREPARED:
+		/* If using a transaction, we want to abort it. */
+		if (ref_transaction_abort(transaction, &err))
+			die("%s", err.buf);
+		break;
+	case UPDATE_REFS_CLOSED:
+		/* Otherwise no need to do anything, the transaction was closed already. */
+		break;
+	}
+
+	strbuf_release(&err);
+	strbuf_release(&input);
+}
+
+int cmd_update_ref(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	const char *refname, *oldval;
+	struct object_id oid, oldoid;
+	int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
+	int create_reflog = 0;
+	struct option options[] = {
+		OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
+		OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
+		OPT_BOOL( 0 , "no-deref", &no_deref,
+					N_("update <refname> not the one it points to")),
+		OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
+		OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
+		OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create a reflog")),
+		OPT_END(),
+	};
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, options, git_update_ref_usage,
+			     0);
+	if (msg && !*msg)
+		die("Refusing to perform update with empty message.");
+
+	create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0;
+
+	if (no_deref) {
+		default_flags = REF_NO_DEREF;
+		update_flags = default_flags;
+	}
+
+	if (read_stdin) {
+		if (delete || argc > 0)
+			usage_with_options(git_update_ref_usage, options);
+		if (end_null)
+			line_termination = '\0';
+		update_refs_stdin();
+		return 0;
+	}
+
+	if (end_null)
+		usage_with_options(git_update_ref_usage, options);
+
+	if (delete) {
+		if (argc < 1 || argc > 2)
+			usage_with_options(git_update_ref_usage, options);
+		refname = argv[0];
+		oldval = argv[1];
+	} else {
+		const char *value;
+		if (argc < 2 || argc > 3)
+			usage_with_options(git_update_ref_usage, options);
+		refname = argv[0];
+		value = argv[1];
+		oldval = argv[2];
+		if (repo_get_oid(the_repository, value, &oid))
+			die("%s: not a valid SHA1", value);
+	}
+
+	if (oldval) {
+		if (!*oldval)
+			/*
+			 * The empty string implies that the reference
+			 * must not already exist:
+			 */
+			oidclr(&oldoid, the_repository->hash_algo);
+		else if (repo_get_oid(the_repository, oldval, &oldoid))
+			die("%s: not a valid old SHA1", oldval);
+	}
+
+	if (delete)
+		/*
+		 * For purposes of backwards compatibility, we treat
+		 * NULL_SHA1 as "don't care" here:
+		 */
+		return refs_delete_ref(get_main_ref_store(the_repository),
+				       msg, refname,
+				       (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
+				       default_flags);
+	else
+		return refs_update_ref(get_main_ref_store(the_repository),
+				       msg, refname, &oid,
+				       oldval ? &oldoid : NULL,
+				       default_flags | create_reflog_flag,
+				       UPDATE_REFS_DIE_ON_ERR);
+}
diff --git a/builtin/update-server-info.c b/builtin/update-server-info.c
new file mode 100644
index 0000000000..47a3f0bdd9
--- /dev/null
+++ b/builtin/update-server-info.c
@@ -0,0 +1,31 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "parse-options.h"
+#include "server-info.h"
+
+static const char * const update_server_info_usage[] = {
+	"git update-server-info [-f | --force]",
+	NULL
+};
+
+int cmd_update_server_info(int argc,
+			   const char **argv,
+			   const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	int force = 0;
+	struct option options[] = {
+		OPT__FORCE(&force, N_("update the info files from scratch"), 0),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, options,
+			     update_server_info_usage, 0);
+	if (argc > 0)
+		usage_with_options(update_server_info_usage, options);
+
+	return !!update_server_info(the_repository, force);
+}
diff --git a/builtin/upload-archive.c b/builtin/upload-archive.c
new file mode 100644
index 0000000000..97d7c9522f
--- /dev/null
+++ b/builtin/upload-archive.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2006 Franck Bui-Huu
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "archive.h"
+#include "path.h"
+#include "pkt-line.h"
+#include "sideband.h"
+#include "run-command.h"
+#include "strvec.h"
+
+static const char upload_archive_usage[] =
+	"git upload-archive <repository>";
+
+static const char deadchild[] =
+"git upload-archive: archiver died with error";
+
+#define MAX_ARGS (64)
+
+int cmd_upload_archive_writer(int argc,
+			      const char **argv,
+			      const char *prefix,
+			      struct repository *repo UNUSED)
+{
+	struct strvec sent_argv = STRVEC_INIT;
+	const char *arg_cmd = "argument ";
+	int ret;
+
+	show_usage_if_asked(argc, argv, upload_archive_usage);
+	if (argc != 2)
+		usage(upload_archive_usage);
+
+	if (!enter_repo(argv[1], 0))
+		die("'%s' does not appear to be a git repository", argv[1]);
+
+	init_archivers();
+
+	/* put received options in sent_argv[] */
+	strvec_push(&sent_argv, "git-upload-archive");
+	for (;;) {
+		char *buf = packet_read_line(0, NULL);
+		if (!buf)
+			break;	/* got a flush */
+		if (sent_argv.nr > MAX_ARGS)
+			die("Too many options (>%d)", MAX_ARGS - 1);
+
+		if (!starts_with(buf, arg_cmd))
+			die("'argument' token or flush expected");
+		strvec_push(&sent_argv, buf + strlen(arg_cmd));
+	}
+
+	/* parse all options sent by the client */
+	ret = write_archive(sent_argv.nr, sent_argv.v, prefix,
+			    the_repository, NULL, 1);
+
+	strvec_clear(&sent_argv);
+	return ret;
+}
+
+__attribute__((format (printf, 1, 2)))
+static void error_clnt(const char *fmt, ...)
+{
+	struct strbuf buf = STRBUF_INIT;
+	va_list params;
+
+	va_start(params, fmt);
+	strbuf_vaddf(&buf, fmt, params);
+	va_end(params);
+	send_sideband(1, 3, buf.buf, buf.len, LARGE_PACKET_MAX);
+	die("sent error to the client: %s", buf.buf);
+}
+
+static ssize_t process_input(int child_fd, int band)
+{
+	char buf[16384];
+	ssize_t sz = read(child_fd, buf, sizeof(buf));
+	if (sz < 0) {
+		if (errno != EAGAIN && errno != EINTR)
+			error_clnt("read error: %s\n", strerror(errno));
+		return sz;
+	}
+	send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
+	return sz;
+}
+
+int cmd_upload_archive(int argc,
+const char **argv,
+const char *prefix,
+struct repository *repo UNUSED)
+{
+	struct child_process writer = CHILD_PROCESS_INIT;
+
+	BUG_ON_NON_EMPTY_PREFIX(prefix);
+
+	show_usage_if_asked(argc, argv, upload_archive_usage);
+
+	/*
+	 * Set up sideband subprocess.
+	 *
+	 * We (parent) monitor and read from child, sending its fd#1 and fd#2
+	 * multiplexed out to our fd#1.  If the child dies, we tell the other
+	 * end over channel #3.
+	 */
+	writer.out = writer.err = -1;
+	writer.git_cmd = 1;
+	strvec_push(&writer.args, "upload-archive--writer");
+	strvec_pushv(&writer.args, argv + 1);
+	if (start_command(&writer)) {
+		int err = errno;
+		packet_write_fmt(1, "NACK unable to spawn subprocess\n");
+		die("upload-archive: %s", strerror(err));
+	}
+
+	packet_write_fmt(1, "ACK\n");
+	packet_flush(1);
+
+	while (1) {
+		struct pollfd pfd[2];
+
+		pfd[0].fd = writer.out;
+		pfd[0].events = POLLIN;
+		pfd[1].fd = writer.err;
+		pfd[1].events = POLLIN;
+		if (poll(pfd, 2, -1) < 0) {
+			if (errno != EINTR) {
+				error_errno("poll failed resuming");
+				sleep(1);
+			}
+			continue;
+		}
+		if (pfd[1].revents & POLLIN)
+			/* Status stream ready */
+			if (process_input(pfd[1].fd, 2))
+				continue;
+		if (pfd[0].revents & POLLIN)
+			/* Data stream ready */
+			if (process_input(pfd[0].fd, 1))
+				continue;
+
+		if (finish_command(&writer))
+			error_clnt("%s", deadchild);
+		packet_flush(1);
+		break;
+	}
+	return 0;
+}
diff --git a/builtin/upload-pack.c b/builtin/upload-pack.c
new file mode 100644
index 0000000000..c2bbc035ab
--- /dev/null
+++ b/builtin/upload-pack.c
@@ -0,0 +1,89 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+#include "exec-cmd.h"
+#include "gettext.h"
+#include "pkt-line.h"
+#include "parse-options.h"
+#include "path.h"
+#include "protocol.h"
+#include "replace-object.h"
+#include "upload-pack.h"
+#include "serve.h"
+#include "commit.h"
+#include "environment.h"
+
+static const char * const upload_pack_usage[] = {
+	N_("git-upload-pack [--[no-]strict] [--timeout=<n>] [--stateless-rpc]\n"
+	   "                [--advertise-refs] <directory>"),
+	NULL
+};
+
+int cmd_upload_pack(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
+{
+	const char *dir;
+	int strict = 0;
+	int advertise_refs = 0;
+	int stateless_rpc = 0;
+	int timeout = 0;
+	struct option options[] = {
+		OPT_BOOL(0, "stateless-rpc", &stateless_rpc,
+			 N_("quit after a single request/response exchange")),
+		OPT_HIDDEN_BOOL(0, "http-backend-info-refs", &advertise_refs,
+				N_("serve up the info/refs for git-http-backend")),
+		OPT_ALIAS(0, "advertise-refs", "http-backend-info-refs"),
+		OPT_BOOL(0, "strict", &strict,
+			 N_("do not try <directory>/.git/ if <directory> is no Git directory")),
+		OPT_INTEGER(0, "timeout", &timeout,
+			    N_("interrupt transfer after <n> seconds of inactivity")),
+		OPT_END()
+	};
+	unsigned enter_repo_flags = ENTER_REPO_ANY_OWNER_OK;
+
+	packet_trace_identity("upload-pack");
+	disable_replace_refs();
+	save_commit_buffer = 0;
+	xsetenv(NO_LAZY_FETCH_ENVIRONMENT, "1", 0);
+
+	argc = parse_options(argc, argv, prefix, options, upload_pack_usage, 0);
+
+	if (argc != 1)
+		usage_with_options(upload_pack_usage, options);
+
+	setup_path();
+
+	dir = argv[0];
+
+	if (strict)
+		enter_repo_flags |= ENTER_REPO_STRICT;
+	if (!enter_repo(dir, enter_repo_flags))
+		die("'%s' does not appear to be a git repository", dir);
+
+	switch (determine_protocol_version_server()) {
+	case protocol_v2:
+		if (advertise_refs)
+			protocol_v2_advertise_capabilities(the_repository);
+		else
+			protocol_v2_serve_loop(the_repository, stateless_rpc);
+		break;
+	case protocol_v1:
+		/*
+		 * v1 is just the original protocol with a version string,
+		 * so just fall through after writing the version string.
+		 */
+		if (advertise_refs || !stateless_rpc)
+			packet_write_fmt(1, "version 1\n");
+
+		/* fallthrough */
+	case protocol_v0:
+		upload_pack(advertise_refs, stateless_rpc, timeout);
+		break;
+	case protocol_unknown_version:
+		BUG("unknown protocol version");
+	}
+
+	return 0;
+}
diff --git a/builtin/var.c b/builtin/var.c
new file mode 100644
index 0000000000..ada642a9fe
--- /dev/null
+++ b/builtin/var.c
@@ -0,0 +1,247 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Eric Biederman, 2005
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "builtin.h"
+
+#include "attr.h"
+#include "config.h"
+#include "editor.h"
+#include "ident.h"
+#include "pager.h"
+#include "refs.h"
+#include "path.h"
+#include "strbuf.h"
+#include "run-command.h"
+
+static const char var_usage[] = "git var (-l | <variable>)";
+
+static char *committer(int ident_flag)
+{
+	return xstrdup_or_null(git_committer_info(ident_flag));
+}
+
+static char *author(int ident_flag)
+{
+	return xstrdup_or_null(git_author_info(ident_flag));
+}
+
+static char *editor(int ident_flag UNUSED)
+{
+	return xstrdup_or_null(git_editor());
+}
+
+static char *sequence_editor(int ident_flag UNUSED)
+{
+	return xstrdup_or_null(git_sequence_editor());
+}
+
+static char *pager(int ident_flag UNUSED)
+{
+	const char *pgm = git_pager(the_repository, 1);
+
+	if (!pgm)
+		pgm = "cat";
+	return xstrdup(pgm);
+}
+
+static char *default_branch(int ident_flag UNUSED)
+{
+	return repo_default_branch_name(the_repository, 1);
+}
+
+static char *shell_path(int ident_flag UNUSED)
+{
+	return git_shell_path();
+}
+
+static char *git_attr_val_system(int ident_flag UNUSED)
+{
+	if (git_attr_system_is_enabled()) {
+		char *file = xstrdup(git_attr_system_file());
+		normalize_path_copy(file, file);
+		return file;
+	}
+	return NULL;
+}
+
+static char *git_attr_val_global(int ident_flag UNUSED)
+{
+	char *file = xstrdup_or_null(git_attr_global_file());
+	if (file) {
+		normalize_path_copy(file, file);
+		return file;
+	}
+	return NULL;
+}
+
+static char *git_config_val_system(int ident_flag UNUSED)
+{
+	if (git_config_system()) {
+		char *file = git_system_config();
+		normalize_path_copy(file, file);
+		return file;
+	}
+	return NULL;
+}
+
+static char *git_config_val_global(int ident_flag UNUSED)
+{
+	struct strbuf buf = STRBUF_INIT;
+	char *user, *xdg;
+	size_t unused;
+
+	git_global_config_paths(&user, &xdg);
+	if (xdg && *xdg) {
+		normalize_path_copy(xdg, xdg);
+		strbuf_addf(&buf, "%s\n", xdg);
+	}
+	if (user && *user) {
+		normalize_path_copy(user, user);
+		strbuf_addf(&buf, "%s\n", user);
+	}
+	free(xdg);
+	free(user);
+	strbuf_trim_trailing_newline(&buf);
+	if (buf.len == 0) {
+		strbuf_release(&buf);
+		return NULL;
+	}
+	return strbuf_detach(&buf, &unused);
+}
+
+struct git_var {
+	const char *name;
+	char *(*read)(int);
+	int multivalued;
+};
+static struct git_var git_vars[] = {
+	{
+		.name = "GIT_COMMITTER_IDENT",
+		.read = committer,
+	},
+	{
+		.name = "GIT_AUTHOR_IDENT",
+		.read = author,
+	},
+	{
+		.name = "GIT_EDITOR",
+		.read = editor,
+	},
+	{
+		.name = "GIT_SEQUENCE_EDITOR",
+		.read = sequence_editor,
+	},
+	{
+		.name = "GIT_PAGER",
+		.read = pager,
+	},
+	{
+		.name = "GIT_DEFAULT_BRANCH",
+		.read = default_branch,
+	},
+	{
+		.name = "GIT_SHELL_PATH",
+		.read = shell_path,
+	},
+	{
+		.name = "GIT_ATTR_SYSTEM",
+		.read = git_attr_val_system,
+	},
+	{
+		.name = "GIT_ATTR_GLOBAL",
+		.read = git_attr_val_global,
+	},
+	{
+		.name = "GIT_CONFIG_SYSTEM",
+		.read = git_config_val_system,
+	},
+	{
+		.name = "GIT_CONFIG_GLOBAL",
+		.read = git_config_val_global,
+		.multivalued = 1,
+	},
+	{
+		.name = "",
+		.read = NULL,
+	},
+};
+
+static void list_vars(void)
+{
+	struct git_var *ptr;
+	char *val;
+
+	for (ptr = git_vars; ptr->read; ptr++)
+		if ((val = ptr->read(0))) {
+			if (ptr->multivalued && *val) {
+				struct string_list list = STRING_LIST_INIT_DUP;
+
+				string_list_split(&list, val, '\n', -1);
+				for (size_t i = 0; i < list.nr; i++)
+					printf("%s=%s\n", ptr->name, list.items[i].string);
+				string_list_clear(&list, 0);
+			} else {
+				printf("%s=%s\n", ptr->name, val);
+			}
+			free(val);
+		}
+}
+
+static const struct git_var *get_git_var(const char *var)
+{
+	struct git_var *ptr;
+	for (ptr = git_vars; ptr->read; ptr++) {
+		if (strcmp(var, ptr->name) == 0) {
+			return ptr;
+		}
+	}
+	return NULL;
+}
+
+static int show_config(const char *var, const char *value,
+		       const struct config_context *ctx, void *cb)
+{
+	if (value)
+		printf("%s=%s\n", var, value);
+	else
+		printf("%s\n", var);
+	return git_default_config(var, value, ctx, cb);
+}
+
+int cmd_var(int argc,
+	    const char **argv,
+	    const char *prefix UNUSED,
+	    struct repository *repo UNUSED)
+{
+	const struct git_var *git_var;
+	char *val;
+
+	show_usage_if_asked(argc, argv, var_usage);
+	if (argc != 2)
+		usage(var_usage);
+
+	if (strcmp(argv[1], "-l") == 0) {
+		git_config(show_config, NULL);
+		list_vars();
+		return 0;
+	}
+	git_config(git_default_config, NULL);
+
+	git_var = get_git_var(argv[1]);
+	if (!git_var)
+		usage(var_usage);
+
+	val = git_var->read(IDENT_STRICT);
+	if (!val)
+		return 1;
+
+	printf("%s\n", val);
+	free(val);
+
+	return 0;
+}
diff --git a/builtin/verify-commit.c b/builtin/verify-commit.c
new file mode 100644
index 0000000000..779b7988ca
--- /dev/null
+++ b/builtin/verify-commit.c
@@ -0,0 +1,84 @@
+/*
+ * Builtin "git commit-commit"
+ *
+ * Copyright (c) 2014 Michael J Gruber <git@xxxxxxxxxxxxxxxxxxxx>
+ *
+ * Based on git-verify-tag
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "object-name.h"
+#include "commit.h"
+#include "parse-options.h"
+#include "gpg-interface.h"
+
+static const char * const verify_commit_usage[] = {
+		N_("git verify-commit [-v | --verbose] [--raw] <commit>..."),
+		NULL
+};
+
+static int run_gpg_verify(struct commit *commit, unsigned flags)
+{
+	struct signature_check signature_check;
+	int ret;
+
+	memset(&signature_check, 0, sizeof(signature_check));
+
+	ret = check_commit_signature(commit, &signature_check);
+	print_signature_buffer(&signature_check, flags);
+
+	signature_check_clear(&signature_check);
+	return ret;
+}
+
+static int verify_commit(const char *name, unsigned flags)
+{
+	struct object_id oid;
+	struct object *obj;
+
+	if (repo_get_oid(the_repository, name, &oid))
+		return error("commit '%s' not found.", name);
+
+	obj = parse_object(the_repository, &oid);
+	if (!obj)
+		return error("%s: unable to read file.", name);
+	if (obj->type != OBJ_COMMIT)
+		return error("%s: cannot verify a non-commit object of type %s.",
+				name, type_name(obj->type));
+
+	return run_gpg_verify((struct commit *)obj, flags);
+}
+
+int cmd_verify_commit(int argc,
+		      const char **argv,
+		      const char *prefix,
+		      struct repository *repo UNUSED)
+{
+	int i = 1, verbose = 0, had_error = 0;
+	unsigned flags = 0;
+	const struct option verify_commit_options[] = {
+		OPT__VERBOSE(&verbose, N_("print commit contents")),
+		OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, verify_commit_options,
+			     verify_commit_usage, PARSE_OPT_KEEP_ARGV0);
+	if (argc <= i)
+		usage_with_options(verify_commit_usage, verify_commit_options);
+
+	if (verbose)
+		flags |= GPG_VERIFY_VERBOSE;
+
+	/* sometimes the program was terminated because this signal
+	 * was received in the process of writing the gpg input: */
+	signal(SIGPIPE, SIG_IGN);
+	while (i < argc)
+		if (verify_commit(argv[i++], flags))
+			had_error = 1;
+	return had_error;
+}
diff --git a/builtin/verify-pack.c b/builtin/verify-pack.c
new file mode 100644
index 0000000000..34e4ed715f
--- /dev/null
+++ b/builtin/verify-pack.c
@@ -0,0 +1,95 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "run-command.h"
+#include "parse-options.h"
+#include "strbuf.h"
+
+#define VERIFY_PACK_VERBOSE 01
+#define VERIFY_PACK_STAT_ONLY 02
+
+static int verify_one_pack(const char *path, unsigned int flags, const char *hash_algo)
+{
+	struct child_process index_pack = CHILD_PROCESS_INIT;
+	struct strvec *argv = &index_pack.args;
+	struct strbuf arg = STRBUF_INIT;
+	int verbose = flags & VERIFY_PACK_VERBOSE;
+	int stat_only = flags & VERIFY_PACK_STAT_ONLY;
+	int err;
+
+	strvec_push(argv, "index-pack");
+
+	if (stat_only)
+		strvec_push(argv, "--verify-stat-only");
+	else if (verbose)
+		strvec_push(argv, "--verify-stat");
+	else
+		strvec_push(argv, "--verify");
+
+	if (hash_algo)
+		strvec_pushf(argv, "--object-format=%s", hash_algo);
+
+	/*
+	 * In addition to "foo.pack" we accept "foo.idx" and "foo";
+	 * normalize these forms to "foo.pack" for "index-pack --verify".
+	 */
+	strbuf_addstr(&arg, path);
+	if (strbuf_strip_suffix(&arg, ".idx") ||
+	    !ends_with(arg.buf, ".pack"))
+		strbuf_addstr(&arg, ".pack");
+	strvec_push(argv, arg.buf);
+
+	index_pack.git_cmd = 1;
+
+	err = run_command(&index_pack);
+
+	if (verbose || stat_only) {
+		if (err)
+			printf("%s: bad\n", arg.buf);
+		else {
+			if (!stat_only)
+				printf("%s: ok\n", arg.buf);
+		}
+	}
+	strbuf_release(&arg);
+
+	return err;
+}
+
+static const char * const verify_pack_usage[] = {
+	N_("git verify-pack [-v | --verbose] [-s | --stat-only] [--] <pack>.idx..."),
+	NULL
+};
+
+int cmd_verify_pack(int argc,
+		    const char **argv,
+		    const char *prefix,
+		    struct repository *repo UNUSED)
+{
+	int err = 0;
+	unsigned int flags = 0;
+	const char *object_format = NULL;
+	int i;
+	const struct option verify_pack_options[] = {
+		OPT_BIT('v', "verbose", &flags, N_("verbose"),
+			VERIFY_PACK_VERBOSE),
+		OPT_BIT('s', "stat-only", &flags, N_("show statistics only"),
+			VERIFY_PACK_STAT_ONLY),
+		OPT_STRING(0, "object-format", &object_format, N_("hash"),
+			   N_("specify the hash algorithm to use")),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, prefix, verify_pack_options,
+			     verify_pack_usage, 0);
+	if (argc < 1)
+		usage_with_options(verify_pack_usage, verify_pack_options);
+	for (i = 0; i < argc; i++) {
+		if (verify_one_pack(argv[i], flags, object_format))
+			err = 1;
+	}
+
+	return err;
+}
diff --git a/builtin/verify-tag.c b/builtin/verify-tag.c
new file mode 100644
index 0000000000..f6b97048a5
--- /dev/null
+++ b/builtin/verify-tag.c
@@ -0,0 +1,73 @@
+/*
+ * Builtin "git verify-tag"
+ *
+ * Copyright (c) 2007 Carlos Rica <jasampler@xxxxxxxxx>
+ *
+ * Based on git-verify-tag.sh
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "tag.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "gpg-interface.h"
+#include "ref-filter.h"
+
+static const char * const verify_tag_usage[] = {
+		N_("git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>..."),
+		NULL
+};
+
+int cmd_verify_tag(int argc,
+		   const char **argv,
+		   const char *prefix,
+		   struct repository *repo UNUSED)
+{
+	int i = 1, verbose = 0, had_error = 0;
+	unsigned flags = 0;
+	struct ref_format format = REF_FORMAT_INIT;
+	const struct option verify_tag_options[] = {
+		OPT__VERBOSE(&verbose, N_("print tag contents")),
+		OPT_BIT(0, "raw", &flags, N_("print raw gpg status output"), GPG_VERIFY_RAW),
+		OPT_STRING(0, "format", &format.format, N_("format"), N_("format to use for the output")),
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+
+	argc = parse_options(argc, argv, prefix, verify_tag_options,
+			     verify_tag_usage, PARSE_OPT_KEEP_ARGV0);
+	if (argc <= i)
+		usage_with_options(verify_tag_usage, verify_tag_options);
+
+	if (verbose)
+		flags |= GPG_VERIFY_VERBOSE;
+
+	if (format.format) {
+		if (verify_ref_format(&format))
+			usage_with_options(verify_tag_usage,
+					   verify_tag_options);
+		flags |= GPG_VERIFY_OMIT_STATUS;
+	}
+
+	while (i < argc) {
+		struct object_id oid;
+		const char *name = argv[i++];
+
+		if (repo_get_oid(the_repository, name, &oid)) {
+			had_error = !!error("tag '%s' not found.", name);
+			continue;
+		}
+
+		if (gpg_verify_tag(&oid, name, flags)) {
+			had_error = 1;
+			continue;
+		}
+
+		if (format.format)
+			pretty_print_ref(name, &oid, &format);
+	}
+	return had_error;
+}
diff --git a/builtin/worktree.c b/builtin/worktree.c
new file mode 100644
index 0000000000..c043d4d523
--- /dev/null
+++ b/builtin/worktree.c
@@ -0,0 +1,1441 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "builtin.h"
+#include "abspath.h"
+#include "advice.h"
+#include "checkout.h"
+#include "config.h"
+#include "copy.h"
+#include "dir.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-file.h"
+#include "object-name.h"
+#include "parse-options.h"
+#include "path.h"
+#include "strvec.h"
+#include "branch.h"
+#include "read-cache-ll.h"
+#include "refs.h"
+#include "remote.h"
+#include "run-command.h"
+#include "hook.h"
+#include "sigchain.h"
+#include "submodule.h"
+#include "utf8.h"
+#include "worktree.h"
+#include "quote.h"
+
+#define BUILTIN_WORKTREE_ADD_USAGE \
+	N_("git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]]\n" \
+	   "                 [--orphan] [(-b | -B) <new-branch>] <path> [<commit-ish>]")
+
+#define BUILTIN_WORKTREE_LIST_USAGE \
+	N_("git worktree list [-v | --porcelain [-z]]")
+#define BUILTIN_WORKTREE_LOCK_USAGE \
+	N_("git worktree lock [--reason <string>] <worktree>")
+#define BUILTIN_WORKTREE_MOVE_USAGE \
+	N_("git worktree move <worktree> <new-path>")
+#define BUILTIN_WORKTREE_PRUNE_USAGE \
+	N_("git worktree prune [-n] [-v] [--expire <expire>]")
+#define BUILTIN_WORKTREE_REMOVE_USAGE \
+	N_("git worktree remove [-f] <worktree>")
+#define BUILTIN_WORKTREE_REPAIR_USAGE \
+	N_("git worktree repair [<path>...]")
+#define BUILTIN_WORKTREE_UNLOCK_USAGE \
+	N_("git worktree unlock <worktree>")
+
+#define WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT \
+	_("No possible source branch, inferring '--orphan'")
+
+#define WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT \
+	_("If you meant to create a worktree containing a new unborn branch\n" \
+	"(branch with no commits) for this repository, you can do so\n" \
+	"using the --orphan flag:\n" \
+	"\n" \
+	"    git worktree add --orphan -b %s %s\n")
+
+#define WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT \
+	_("If you meant to create a worktree containing a new unborn branch\n" \
+	"(branch with no commits) for this repository, you can do so\n" \
+	"using the --orphan flag:\n" \
+	"\n" \
+	"    git worktree add --orphan %s\n")
+
+static const char * const git_worktree_usage[] = {
+	BUILTIN_WORKTREE_ADD_USAGE,
+	BUILTIN_WORKTREE_LIST_USAGE,
+	BUILTIN_WORKTREE_LOCK_USAGE,
+	BUILTIN_WORKTREE_MOVE_USAGE,
+	BUILTIN_WORKTREE_PRUNE_USAGE,
+	BUILTIN_WORKTREE_REMOVE_USAGE,
+	BUILTIN_WORKTREE_REPAIR_USAGE,
+	BUILTIN_WORKTREE_UNLOCK_USAGE,
+	NULL
+};
+
+static const char * const git_worktree_add_usage[] = {
+	BUILTIN_WORKTREE_ADD_USAGE,
+	NULL,
+};
+
+static const char * const git_worktree_list_usage[] = {
+	BUILTIN_WORKTREE_LIST_USAGE,
+	NULL
+};
+
+static const char * const git_worktree_lock_usage[] = {
+	BUILTIN_WORKTREE_LOCK_USAGE,
+	NULL
+};
+
+static const char * const git_worktree_move_usage[] = {
+	BUILTIN_WORKTREE_MOVE_USAGE,
+	NULL
+};
+
+static const char * const git_worktree_prune_usage[] = {
+	BUILTIN_WORKTREE_PRUNE_USAGE,
+	NULL
+};
+
+static const char * const git_worktree_remove_usage[] = {
+	BUILTIN_WORKTREE_REMOVE_USAGE,
+	NULL
+};
+
+static const char * const git_worktree_repair_usage[] = {
+	BUILTIN_WORKTREE_REPAIR_USAGE,
+	NULL
+};
+
+static const char * const git_worktree_unlock_usage[] = {
+	BUILTIN_WORKTREE_UNLOCK_USAGE,
+	NULL
+};
+
+struct add_opts {
+	int force;
+	int detach;
+	int quiet;
+	int checkout;
+	int orphan;
+	int relative_paths;
+	const char *keep_locked;
+};
+
+static int show_only;
+static int verbose;
+static int guess_remote;
+static int use_relative_paths;
+static timestamp_t expire;
+
+static int git_worktree_config(const char *var, const char *value,
+			       const struct config_context *ctx, void *cb)
+{
+	if (!strcmp(var, "worktree.guessremote")) {
+		guess_remote = git_config_bool(var, value);
+		return 0;
+	} else if (!strcmp(var, "worktree.userelativepaths")) {
+		use_relative_paths = git_config_bool(var, value);
+		return 0;
+	}
+
+	return git_default_config(var, value, ctx, cb);
+}
+
+static int delete_git_dir(const char *id)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret;
+
+	strbuf_addstr(&sb, git_common_path("worktrees/%s", id));
+	ret = remove_dir_recursively(&sb, 0);
+	if (ret < 0 && errno == ENOTDIR)
+		ret = unlink(sb.buf);
+	if (ret)
+		error_errno(_("failed to delete '%s'"), sb.buf);
+	strbuf_release(&sb);
+	return ret;
+}
+
+static void delete_worktrees_dir_if_empty(void)
+{
+	rmdir(git_path("worktrees")); /* ignore failed removal */
+}
+
+static void prune_worktree(const char *id, const char *reason)
+{
+	if (show_only || verbose)
+		fprintf_ln(stderr, _("Removing %s/%s: %s"), "worktrees", id, reason);
+	if (!show_only)
+		delete_git_dir(id);
+}
+
+static int prune_cmp(const void *a, const void *b)
+{
+	const struct string_list_item *x = a;
+	const struct string_list_item *y = b;
+	int c;
+
+	if ((c = fspathcmp(x->string, y->string)))
+	    return c;
+	/*
+	 * paths same; prune_dupes() removes all but the first worktree entry
+	 * having the same path, so sort main worktree ('util' is NULL) above
+	 * linked worktrees ('util' not NULL) since main worktree can't be
+	 * removed
+	 */
+	if (!x->util)
+		return -1;
+	if (!y->util)
+		return 1;
+	/* paths same; sort by .git/worktrees/<id> */
+	return strcmp(x->util, y->util);
+}
+
+static void prune_dups(struct string_list *l)
+{
+	int i;
+
+	QSORT(l->items, l->nr, prune_cmp);
+	for (i = 1; i < l->nr; i++) {
+		if (!fspathcmp(l->items[i].string, l->items[i - 1].string))
+			prune_worktree(l->items[i].util, "duplicate entry");
+	}
+}
+
+static void prune_worktrees(void)
+{
+	struct strbuf reason = STRBUF_INIT;
+	struct strbuf main_path = STRBUF_INIT;
+	struct string_list kept = STRING_LIST_INIT_DUP;
+	DIR *dir = opendir(git_path("worktrees"));
+	struct dirent *d;
+	if (!dir)
+		return;
+	while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) {
+		char *path;
+		strbuf_reset(&reason);
+		if (should_prune_worktree(d->d_name, &reason, &path, expire))
+			prune_worktree(d->d_name, reason.buf);
+		else if (path)
+			string_list_append_nodup(&kept, path)->util = xstrdup(d->d_name);
+	}
+	closedir(dir);
+
+	strbuf_add_absolute_path(&main_path, repo_get_common_dir(the_repository));
+	/* massage main worktree absolute path to match 'gitdir' content */
+	strbuf_strip_suffix(&main_path, "/.");
+	string_list_append_nodup(&kept, strbuf_detach(&main_path, NULL));
+	prune_dups(&kept);
+	string_list_clear(&kept, 1);
+
+	if (!show_only)
+		delete_worktrees_dir_if_empty();
+	strbuf_release(&reason);
+}
+
+static int prune(int ac, const char **av, const char *prefix,
+		 struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT__DRY_RUN(&show_only, N_("do not remove, show only")),
+		OPT__VERBOSE(&verbose, N_("report pruned working trees")),
+		OPT_EXPIRY_DATE(0, "expire", &expire,
+				N_("expire working trees older than <time>")),
+		OPT_END()
+	};
+
+	expire = TIME_MAX;
+	ac = parse_options(ac, av, prefix, options, git_worktree_prune_usage,
+			   0);
+	if (ac)
+		usage_with_options(git_worktree_prune_usage, options);
+	prune_worktrees();
+	return 0;
+}
+
+static char *junk_work_tree;
+static char *junk_git_dir;
+static int is_junk;
+static pid_t junk_pid;
+
+static void remove_junk(void)
+{
+	struct strbuf sb = STRBUF_INIT;
+	if (!is_junk || getpid() != junk_pid)
+		return;
+	if (junk_git_dir) {
+		strbuf_addstr(&sb, junk_git_dir);
+		remove_dir_recursively(&sb, 0);
+		strbuf_reset(&sb);
+	}
+	if (junk_work_tree) {
+		strbuf_addstr(&sb, junk_work_tree);
+		remove_dir_recursively(&sb, 0);
+	}
+	strbuf_release(&sb);
+}
+
+static void remove_junk_on_signal(int signo)
+{
+	remove_junk();
+	sigchain_pop(signo);
+	raise(signo);
+}
+
+static const char *worktree_basename(const char *path, int *olen)
+{
+	const char *name;
+	int len;
+
+	len = strlen(path);
+	while (len && is_dir_sep(path[len - 1]))
+		len--;
+
+	for (name = path + len - 1; name > path; name--)
+		if (is_dir_sep(*name)) {
+			name++;
+			break;
+		}
+
+	*olen = len;
+	return name;
+}
+
+/* check that path is viable location for worktree */
+static void check_candidate_path(const char *path,
+				 int force,
+				 struct worktree **worktrees,
+				 const char *cmd)
+{
+	struct worktree *wt;
+	int locked;
+
+	if (file_exists(path) && !is_empty_dir(path))
+		die(_("'%s' already exists"), path);
+
+	wt = find_worktree_by_path(worktrees, path);
+	if (!wt)
+		return;
+
+	locked = !!worktree_lock_reason(wt);
+	if ((!locked && force) || (locked && force > 1)) {
+		if (delete_git_dir(wt->id))
+		    die(_("unusable worktree destination '%s'"), path);
+		return;
+	}
+
+	if (locked)
+		die(_("'%s' is a missing but locked worktree;\nuse '%s -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear"), path, cmd);
+	else
+		die(_("'%s' is a missing but already registered worktree;\nuse '%s -f' to override, or 'prune' or 'remove' to clear"), path, cmd);
+}
+
+static void copy_sparse_checkout(const char *worktree_git_dir)
+{
+	char *from_file = git_pathdup("info/sparse-checkout");
+	char *to_file = xstrfmt("%s/info/sparse-checkout", worktree_git_dir);
+
+	if (file_exists(from_file)) {
+		if (safe_create_leading_directories(to_file) ||
+			copy_file(to_file, from_file, 0666))
+			error(_("failed to copy '%s' to '%s'; sparse-checkout may not work correctly"),
+				from_file, to_file);
+	}
+
+	free(from_file);
+	free(to_file);
+}
+
+static void copy_filtered_worktree_config(const char *worktree_git_dir)
+{
+	char *from_file = git_pathdup("config.worktree");
+	char *to_file = xstrfmt("%s/config.worktree", worktree_git_dir);
+
+	if (file_exists(from_file)) {
+		struct config_set cs = { { 0 } };
+		int bare;
+
+		if (safe_create_leading_directories(to_file) ||
+			copy_file(to_file, from_file, 0666)) {
+			error(_("failed to copy worktree config from '%s' to '%s'"),
+				from_file, to_file);
+			goto worktree_copy_cleanup;
+		}
+
+		git_configset_init(&cs);
+		git_configset_add_file(&cs, from_file);
+
+		if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
+			bare &&
+			git_config_set_multivar_in_file_gently(
+				to_file, "core.bare", NULL, "true", NULL, 0))
+			error(_("failed to unset '%s' in '%s'"),
+				"core.bare", to_file);
+		if (!git_configset_get(&cs, "core.worktree") &&
+			git_config_set_in_file_gently(to_file,
+							"core.worktree", NULL, NULL))
+			error(_("failed to unset '%s' in '%s'"),
+				"core.worktree", to_file);
+
+		git_configset_clear(&cs);
+	}
+
+worktree_copy_cleanup:
+	free(from_file);
+	free(to_file);
+}
+
+static int checkout_worktree(const struct add_opts *opts,
+			     struct strvec *child_env)
+{
+	struct child_process cp = CHILD_PROCESS_INIT;
+	cp.git_cmd = 1;
+	strvec_pushl(&cp.args, "reset", "--hard", "--no-recurse-submodules", NULL);
+	if (opts->quiet)
+		strvec_push(&cp.args, "--quiet");
+	strvec_pushv(&cp.env, child_env->v);
+	return run_command(&cp);
+}
+
+static int make_worktree_orphan(const char * ref, const struct add_opts *opts,
+				struct strvec *child_env)
+{
+	struct strbuf symref = STRBUF_INIT;
+	struct child_process cp = CHILD_PROCESS_INIT;
+
+	validate_new_branchname(ref, &symref, 0);
+	strvec_pushl(&cp.args, "symbolic-ref", "HEAD", symref.buf, NULL);
+	if (opts->quiet)
+		strvec_push(&cp.args, "--quiet");
+	strvec_pushv(&cp.env, child_env->v);
+	strbuf_release(&symref);
+	cp.git_cmd = 1;
+	return run_command(&cp);
+}
+
+static int add_worktree(const char *path, const char *refname,
+			const struct add_opts *opts)
+{
+	struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
+	struct strbuf sb = STRBUF_INIT;
+	const char *name;
+	struct strvec child_env = STRVEC_INIT;
+	unsigned int counter = 0;
+	int len, ret;
+	struct strbuf symref = STRBUF_INIT;
+	struct commit *commit = NULL;
+	int is_branch = 0;
+	struct strbuf sb_name = STRBUF_INIT;
+	struct worktree **worktrees, *wt = NULL;
+	struct ref_store *wt_refs;
+
+	worktrees = get_worktrees();
+	check_candidate_path(path, opts->force, worktrees, "add");
+	free_worktrees(worktrees);
+	worktrees = NULL;
+
+	/* is 'refname' a branch or commit? */
+	if (!opts->detach && !check_branch_ref(&symref, refname) &&
+	    refs_ref_exists(get_main_ref_store(the_repository), symref.buf)) {
+		is_branch = 1;
+		if (!opts->force)
+			die_if_checked_out(symref.buf, 0);
+	}
+	commit = lookup_commit_reference_by_name(refname);
+	if (!commit && !opts->orphan)
+		die(_("invalid reference: %s"), refname);
+
+	name = worktree_basename(path, &len);
+	strbuf_add(&sb, name, path + len - name);
+	sanitize_refname_component(sb.buf, &sb_name);
+	if (!sb_name.len)
+		BUG("How come '%s' becomes empty after sanitization?", sb.buf);
+	strbuf_reset(&sb);
+	name = sb_name.buf;
+	git_path_buf(&sb_repo, "worktrees/%s", name);
+	len = sb_repo.len;
+	if (safe_create_leading_directories_const(sb_repo.buf))
+		die_errno(_("could not create leading directories of '%s'"),
+			  sb_repo.buf);
+
+	while (mkdir(sb_repo.buf, 0777)) {
+		counter++;
+		if ((errno != EEXIST) || !counter /* overflow */)
+			die_errno(_("could not create directory of '%s'"),
+				  sb_repo.buf);
+		strbuf_setlen(&sb_repo, len);
+		strbuf_addf(&sb_repo, "%d", counter);
+	}
+	name = strrchr(sb_repo.buf, '/') + 1;
+
+	junk_pid = getpid();
+	atexit(remove_junk);
+	sigchain_push_common(remove_junk_on_signal);
+
+	junk_git_dir = xstrdup(sb_repo.buf);
+	is_junk = 1;
+
+	/*
+	 * lock the incomplete repo so prune won't delete it, unlock
+	 * after the preparation is over.
+	 */
+	strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+	if (opts->keep_locked)
+		write_file(sb.buf, "%s", opts->keep_locked);
+	else
+		write_file(sb.buf, _("initializing"));
+
+	strbuf_addf(&sb_git, "%s/.git", path);
+	if (safe_create_leading_directories_const(sb_git.buf))
+		die_errno(_("could not create leading directories of '%s'"),
+			  sb_git.buf);
+	junk_work_tree = xstrdup(path);
+
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
+	write_worktree_linking_files(sb_git, sb, opts->relative_paths);
+	strbuf_reset(&sb);
+	strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
+	write_file(sb.buf, "../..");
+
+	/*
+	 * Set up the ref store of the worktree and create the HEAD reference.
+	 */
+	wt = get_linked_worktree(name, 1);
+	if (!wt) {
+		ret = error(_("could not find created worktree '%s'"), name);
+		goto done;
+	}
+	wt_refs = get_worktree_ref_store(wt);
+
+	ret = ref_store_create_on_disk(wt_refs, REF_STORE_CREATE_ON_DISK_IS_WORKTREE, &sb);
+	if (ret)
+		goto done;
+
+	if (!is_branch && commit)
+		ret = refs_update_ref(wt_refs, NULL, "HEAD", &commit->object.oid,
+				      NULL, 0, UPDATE_REFS_MSG_ON_ERR);
+	else
+		ret = refs_update_symref(wt_refs, "HEAD", symref.buf, NULL);
+	if (ret)
+		goto done;
+
+	/*
+	 * If the current worktree has sparse-checkout enabled, then copy
+	 * the sparse-checkout patterns from the current worktree.
+	 */
+	if (core_apply_sparse_checkout)
+		copy_sparse_checkout(sb_repo.buf);
+
+	/*
+	 * If we are using worktree config, then copy all current config
+	 * values from the current worktree into the new one, that way the
+	 * new worktree behaves the same as this one.
+	 */
+	if (the_repository->repository_format_worktree_config)
+		copy_filtered_worktree_config(sb_repo.buf);
+
+	strvec_pushf(&child_env, "%s=%s", GIT_DIR_ENVIRONMENT, sb_git.buf);
+	strvec_pushf(&child_env, "%s=%s", GIT_WORK_TREE_ENVIRONMENT, path);
+
+	if (opts->orphan &&
+	    (ret = make_worktree_orphan(refname, opts, &child_env)))
+		goto done;
+
+	if (opts->checkout &&
+	    (ret = checkout_worktree(opts, &child_env)))
+		goto done;
+
+	is_junk = 0;
+	FREE_AND_NULL(junk_work_tree);
+	FREE_AND_NULL(junk_git_dir);
+
+done:
+	if (ret || !opts->keep_locked) {
+		strbuf_reset(&sb);
+		strbuf_addf(&sb, "%s/locked", sb_repo.buf);
+		unlink_or_warn(sb.buf);
+	}
+
+	/*
+	 * Hook failure does not warrant worktree deletion, so run hook after
+	 * is_junk is cleared, but do return appropriate code when hook fails.
+	 */
+	if (!ret && opts->checkout && !opts->orphan) {
+		struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+
+		strvec_pushl(&opt.env, "GIT_DIR", "GIT_WORK_TREE", NULL);
+		strvec_pushl(&opt.args,
+			     oid_to_hex(null_oid()),
+			     oid_to_hex(&commit->object.oid),
+			     "1",
+			     NULL);
+		opt.dir = path;
+
+		ret = run_hooks_opt(the_repository, "post-checkout", &opt);
+	}
+
+	strvec_clear(&child_env);
+	strbuf_release(&sb);
+	strbuf_release(&symref);
+	strbuf_release(&sb_repo);
+	strbuf_release(&sb_git);
+	strbuf_release(&sb_name);
+	free_worktree(wt);
+	return ret;
+}
+
+static void print_preparing_worktree_line(int detach,
+					  const char *branch,
+					  const char *new_branch,
+					  int force_new_branch)
+{
+	if (force_new_branch) {
+		struct commit *commit = lookup_commit_reference_by_name(new_branch);
+		if (!commit)
+			fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
+		else
+			fprintf_ln(stderr, _("Preparing worktree (resetting branch '%s'; was at %s)"),
+				  new_branch,
+				  repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
+	} else if (new_branch) {
+		fprintf_ln(stderr, _("Preparing worktree (new branch '%s')"), new_branch);
+	} else {
+		struct strbuf s = STRBUF_INIT;
+		if (!detach && !check_branch_ref(&s, branch) &&
+		    refs_ref_exists(get_main_ref_store(the_repository), s.buf))
+			fprintf_ln(stderr, _("Preparing worktree (checking out '%s')"),
+				  branch);
+		else {
+			struct commit *commit = lookup_commit_reference_by_name(branch);
+			if (!commit)
+				BUG(_("unreachable: invalid reference: %s"), branch);
+			fprintf_ln(stderr, _("Preparing worktree (detached HEAD %s)"),
+				  repo_find_unique_abbrev(the_repository, &commit->object.oid, DEFAULT_ABBREV));
+		}
+		strbuf_release(&s);
+	}
+}
+
+/**
+ * Callback to short circuit iteration over refs on the first reference
+ * corresponding to a valid oid.
+ *
+ * Returns 0 on failure and non-zero on success.
+ */
+static int first_valid_ref(const char *refname UNUSED,
+			   const char *referent UNUSED,
+			   const struct object_id *oid UNUSED,
+			   int flags UNUSED,
+			   void *cb_data UNUSED)
+{
+	return 1;
+}
+
+/**
+ * Verifies HEAD and determines whether there exist any valid local references.
+ *
+ * - Checks whether HEAD points to a valid reference.
+ *
+ * - Checks whether any valid local branches exist.
+ *
+ * - Emits a warning if there exist any valid branches but HEAD does not point
+ *   to a valid reference.
+ *
+ * Returns 1 if any of the previous checks are true, otherwise returns 0.
+ */
+static int can_use_local_refs(const struct add_opts *opts)
+{
+	if (refs_head_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
+		return 1;
+	} else if (refs_for_each_branch_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
+		if (!opts->quiet) {
+			struct strbuf path = STRBUF_INIT;
+			struct strbuf contents = STRBUF_INIT;
+
+			strbuf_add_real_path(&path, get_worktree_git_dir(NULL));
+			strbuf_addstr(&path, "/HEAD");
+			strbuf_read_file(&contents, path.buf, 64);
+			strbuf_stripspace(&contents, NULL);
+			strbuf_strip_suffix(&contents, "\n");
+
+			warning(_("HEAD points to an invalid (or orphaned) reference.\n"
+				  "HEAD path: '%s'\n"
+				  "HEAD contents: '%s'"),
+				  path.buf, contents.buf);
+			strbuf_release(&path);
+			strbuf_release(&contents);
+		}
+		return 1;
+	}
+	return 0;
+}
+
+/**
+ * Reports whether the necessary flags were set and whether the repository has
+ * remote references to attempt DWIM tracking of upstream branches.
+ *
+ * 1. Checks that `--guess-remote` was used or `worktree.guessRemote = true`.
+ *
+ * 2. Checks whether any valid remote branches exist.
+ *
+ * 3. Checks that there exists at least one remote and emits a warning/error
+ *    if both checks 1. and 2. are false (can be bypassed with `--force`).
+ *
+ * Returns 1 if checks 1. and 2. are true, otherwise 0.
+ */
+static int can_use_remote_refs(const struct add_opts *opts)
+{
+	if (!guess_remote) {
+		return 0;
+	} else if (refs_for_each_remote_ref(get_main_ref_store(the_repository), first_valid_ref, NULL)) {
+		return 1;
+	} else if (!opts->force && remote_get(NULL)) {
+		die(_("No local or remote refs exist despite at least one remote\n"
+		      "present, stopping; use 'add -f' to override or fetch a remote first"));
+	}
+	return 0;
+}
+
+/**
+ * Determines whether `--orphan` should be inferred in the evaluation of
+ * `worktree add path/` or `worktree add -b branch path/` and emits an error
+ * if the supplied arguments would produce an illegal combination when the
+ * `--orphan` flag is included.
+ *
+ * `opts` and `opt_track` contain the other options & flags supplied to the
+ * command.
+ *
+ * remote determines whether to check `can_use_remote_refs()` or not. This
+ * is primarily to differentiate between the basic `add` DWIM and `add -b`.
+ *
+ * Returns 1 when inferring `--orphan`, 0 otherwise, and emits an error when
+ * `--orphan` is inferred but doing so produces an illegal combination of
+ * options and flags. Additionally produces an error when remote refs are
+ * checked and the repo is in a state that looks like the user added a remote
+ * but forgot to fetch (and did not override the warning with -f).
+ */
+static int dwim_orphan(const struct add_opts *opts, int opt_track, int remote)
+{
+	if (can_use_local_refs(opts)) {
+		return 0;
+	} else if (remote && can_use_remote_refs(opts)) {
+		return 0;
+	} else if (!opts->quiet) {
+		fprintf_ln(stderr, WORKTREE_ADD_DWIM_ORPHAN_INFER_TEXT);
+	}
+
+	if (opt_track) {
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--orphan", "--track");
+	} else if (!opts->checkout) {
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--orphan", "--no-checkout");
+	}
+	return 1;
+}
+
+static char *dwim_branch(const char *path, char **new_branch)
+{
+	int n;
+	int branch_exists;
+	const char *s = worktree_basename(path, &n);
+	char *branchname = xstrndup(s, n);
+	struct strbuf ref = STRBUF_INIT;
+
+	branch_exists = !check_branch_ref(&ref, branchname) &&
+			refs_ref_exists(get_main_ref_store(the_repository),
+					ref.buf);
+	strbuf_release(&ref);
+	if (branch_exists)
+		return branchname;
+
+	*new_branch = branchname;
+	if (guess_remote) {
+		struct object_id oid;
+		char *remote = unique_tracking_name(*new_branch, &oid, NULL);
+		return remote;
+	}
+	return NULL;
+}
+
+static int add(int ac, const char **av, const char *prefix,
+	       struct repository *repo UNUSED)
+{
+	struct add_opts opts;
+	const char *new_branch_force = NULL;
+	char *path;
+	const char *branch;
+	char *branch_to_free = NULL;
+	char *new_branch_to_free = NULL;
+	const char *new_branch = NULL;
+	char *opt_track = NULL;
+	const char *lock_reason = NULL;
+	int keep_locked = 0;
+	int used_new_branch_options;
+	struct option options[] = {
+		OPT__FORCE(&opts.force,
+			   N_("checkout <branch> even if already checked out in other worktree"),
+			   PARSE_OPT_NOCOMPLETE),
+		OPT_STRING('b', NULL, &new_branch, N_("branch"),
+			   N_("create a new branch")),
+		OPT_STRING('B', NULL, &new_branch_force, N_("branch"),
+			   N_("create or reset a branch")),
+		OPT_BOOL(0, "orphan", &opts.orphan, N_("create unborn branch")),
+		OPT_BOOL('d', "detach", &opts.detach, N_("detach HEAD at named commit")),
+		OPT_BOOL(0, "checkout", &opts.checkout, N_("populate the new working tree")),
+		OPT_BOOL(0, "lock", &keep_locked, N_("keep the new working tree locked")),
+		OPT_STRING(0, "reason", &lock_reason, N_("string"),
+			   N_("reason for locking")),
+		OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
+		OPT_PASSTHRU(0, "track", &opt_track, NULL,
+			     N_("set up tracking mode (see git-branch(1))"),
+			     PARSE_OPT_NOARG | PARSE_OPT_OPTARG),
+		OPT_BOOL(0, "guess-remote", &guess_remote,
+			 N_("try to match the new branch name with a remote-tracking branch")),
+		OPT_BOOL(0, "relative-paths", &opts.relative_paths,
+			 N_("use relative paths for worktrees")),
+		OPT_END()
+	};
+	int ret;
+
+	memset(&opts, 0, sizeof(opts));
+	opts.checkout = 1;
+	opts.relative_paths = use_relative_paths;
+	ac = parse_options(ac, av, prefix, options, git_worktree_add_usage, 0);
+	if (!!opts.detach + !!new_branch + !!new_branch_force > 1)
+		die(_("options '%s', '%s', and '%s' cannot be used together"), "-b", "-B", "--detach");
+	if (opts.detach && opts.orphan)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--orphan", "--detach");
+	if (opts.orphan && opt_track)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--orphan", "--track");
+	if (opts.orphan && !opts.checkout)
+		die(_("options '%s' and '%s' cannot be used together"),
+		    "--orphan", "--no-checkout");
+	if (opts.orphan && ac == 2)
+		die(_("option '%s' and commit-ish cannot be used together"),
+		    "--orphan");
+	if (lock_reason && !keep_locked)
+		die(_("the option '%s' requires '%s'"), "--reason", "--lock");
+	if (lock_reason)
+		opts.keep_locked = lock_reason;
+	else if (keep_locked)
+		opts.keep_locked = _("added with --lock");
+
+	if (ac < 1 || ac > 2)
+		usage_with_options(git_worktree_add_usage, options);
+
+	path = prefix_filename(prefix, av[0]);
+	branch = ac < 2 ? "HEAD" : av[1];
+	used_new_branch_options = new_branch || new_branch_force;
+
+	if (!strcmp(branch, "-"))
+		branch = "@{-1}";
+
+	if (new_branch_force) {
+		struct strbuf symref = STRBUF_INIT;
+
+		new_branch = new_branch_force;
+
+		if (!opts.force &&
+		    !check_branch_ref(&symref, new_branch) &&
+		    refs_ref_exists(get_main_ref_store(the_repository), symref.buf))
+			die_if_checked_out(symref.buf, 0);
+		strbuf_release(&symref);
+	}
+
+	if (opts.orphan && !new_branch) {
+		int n;
+		const char *s = worktree_basename(path, &n);
+		new_branch = new_branch_to_free = xstrndup(s, n);
+	} else if (opts.orphan) {
+		; /* no-op */
+	} else if (opts.detach) {
+		/* Check HEAD */
+		if (!strcmp(branch, "HEAD"))
+			can_use_local_refs(&opts);
+	} else if (ac < 2 && new_branch) {
+		/* DWIM: Infer --orphan when repo has no refs. */
+		opts.orphan = dwim_orphan(&opts, !!opt_track, 0);
+	} else if (ac < 2) {
+		/* DWIM: Guess branch name from path. */
+		char *s = dwim_branch(path, &new_branch_to_free);
+		if (s)
+			branch = branch_to_free = s;
+		new_branch = new_branch_to_free;
+
+		/* DWIM: Infer --orphan when repo has no refs. */
+		opts.orphan = (!s) && dwim_orphan(&opts, !!opt_track, 1);
+	} else if (ac == 2) {
+		struct object_id oid;
+		struct commit *commit;
+		char *remote;
+
+		commit = lookup_commit_reference_by_name(branch);
+		if (!commit) {
+			remote = unique_tracking_name(branch, &oid, NULL);
+			if (remote) {
+				new_branch = branch;
+				branch = new_branch_to_free = remote;
+			}
+		}
+
+		if (!strcmp(branch, "HEAD"))
+			can_use_local_refs(&opts);
+
+	}
+
+	if (!opts.orphan && !lookup_commit_reference_by_name(branch)) {
+		int attempt_hint = !opts.quiet && (ac < 2);
+		if (attempt_hint && used_new_branch_options) {
+			advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN,
+				WORKTREE_ADD_ORPHAN_WITH_DASH_B_HINT_TEXT,
+				new_branch, path);
+		} else if (attempt_hint) {
+			advise_if_enabled(ADVICE_WORKTREE_ADD_ORPHAN,
+				WORKTREE_ADD_ORPHAN_NO_DASH_B_HINT_TEXT, path);
+		}
+		die(_("invalid reference: %s"), branch);
+	}
+
+	if (!opts.quiet)
+		print_preparing_worktree_line(opts.detach, branch, new_branch, !!new_branch_force);
+
+	if (opts.orphan) {
+		branch = new_branch;
+	} else if (new_branch) {
+		struct child_process cp = CHILD_PROCESS_INIT;
+		cp.git_cmd = 1;
+		strvec_push(&cp.args, "branch");
+		if (new_branch_force)
+			strvec_push(&cp.args, "--force");
+		if (opts.quiet)
+			strvec_push(&cp.args, "--quiet");
+		strvec_push(&cp.args, new_branch);
+		strvec_push(&cp.args, branch);
+		if (opt_track)
+			strvec_push(&cp.args, opt_track);
+		if (run_command(&cp))
+			return -1;
+		branch = new_branch;
+	} else if (opt_track) {
+		die(_("--[no-]track can only be used if a new branch is created"));
+	}
+
+	ret = add_worktree(path, branch, &opts);
+	free(path);
+	free(opt_track);
+	free(branch_to_free);
+	free(new_branch_to_free);
+	return ret;
+}
+
+static void show_worktree_porcelain(struct worktree *wt, int line_terminator)
+{
+	const char *reason;
+
+	printf("worktree %s%c", wt->path, line_terminator);
+	if (wt->is_bare)
+		printf("bare%c", line_terminator);
+	else {
+		printf("HEAD %s%c", oid_to_hex(&wt->head_oid), line_terminator);
+		if (wt->is_detached)
+			printf("detached%c", line_terminator);
+		else if (wt->head_ref)
+			printf("branch %s%c", wt->head_ref, line_terminator);
+	}
+
+	reason = worktree_lock_reason(wt);
+	if (reason) {
+		fputs("locked", stdout);
+		if (*reason) {
+			fputc(' ', stdout);
+			write_name_quoted(reason, stdout, line_terminator);
+		} else {
+			fputc(line_terminator, stdout);
+		}
+	}
+
+	reason = worktree_prune_reason(wt, expire);
+	if (reason)
+		printf("prunable %s%c", reason, line_terminator);
+
+	fputc(line_terminator, stdout);
+}
+
+static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int cur_path_len = strlen(wt->path);
+	int path_adj = cur_path_len - utf8_strwidth(wt->path);
+	const char *reason;
+
+	strbuf_addf(&sb, "%-*s ", 1 + path_maxlen + path_adj, wt->path);
+	if (wt->is_bare)
+		strbuf_addstr(&sb, "(bare)");
+	else {
+		strbuf_addf(&sb, "%-*s ", abbrev_len,
+				repo_find_unique_abbrev(the_repository, &wt->head_oid, DEFAULT_ABBREV));
+		if (wt->is_detached)
+			strbuf_addstr(&sb, "(detached HEAD)");
+		else if (wt->head_ref) {
+			char *ref = refs_shorten_unambiguous_ref(get_main_ref_store(the_repository),
+								 wt->head_ref,
+								 0);
+			strbuf_addf(&sb, "[%s]", ref);
+			free(ref);
+		} else
+			strbuf_addstr(&sb, "(error)");
+	}
+
+	reason = worktree_lock_reason(wt);
+	if (verbose && reason && *reason)
+		strbuf_addf(&sb, "\n\tlocked: %s", reason);
+	else if (reason)
+		strbuf_addstr(&sb, " locked");
+
+	reason = worktree_prune_reason(wt, expire);
+	if (verbose && reason)
+		strbuf_addf(&sb, "\n\tprunable: %s", reason);
+	else if (reason)
+		strbuf_addstr(&sb, " prunable");
+
+	printf("%s\n", sb.buf);
+	strbuf_release(&sb);
+}
+
+static void measure_widths(struct worktree **wt, int *abbrev, int *maxlen)
+{
+	int i;
+
+	for (i = 0; wt[i]; i++) {
+		int sha1_len;
+		int path_len = strlen(wt[i]->path);
+
+		if (path_len > *maxlen)
+			*maxlen = path_len;
+		sha1_len = strlen(repo_find_unique_abbrev(the_repository, &wt[i]->head_oid, *abbrev));
+		if (sha1_len > *abbrev)
+			*abbrev = sha1_len;
+	}
+}
+
+static int pathcmp(const void *a_, const void *b_)
+{
+	const struct worktree *const *a = a_;
+	const struct worktree *const *b = b_;
+	return fspathcmp((*a)->path, (*b)->path);
+}
+
+static void pathsort(struct worktree **wt)
+{
+	int n = 0;
+	struct worktree **p = wt;
+
+	while (*p++)
+		n++;
+	QSORT(wt, n, pathcmp);
+}
+
+static int list(int ac, const char **av, const char *prefix,
+		struct repository *repo UNUSED)
+{
+	int porcelain = 0;
+	int line_terminator = '\n';
+
+	struct option options[] = {
+		OPT_BOOL(0, "porcelain", &porcelain, N_("machine-readable output")),
+		OPT__VERBOSE(&verbose, N_("show extended annotations and reasons, if available")),
+		OPT_EXPIRY_DATE(0, "expire", &expire,
+				N_("add 'prunable' annotation to worktrees older than <time>")),
+		OPT_SET_INT('z', NULL, &line_terminator,
+			    N_("terminate records with a NUL character"), '\0'),
+		OPT_END()
+	};
+
+	expire = TIME_MAX;
+	ac = parse_options(ac, av, prefix, options, git_worktree_list_usage, 0);
+	if (ac)
+		usage_with_options(git_worktree_list_usage, options);
+	else if (verbose && porcelain)
+		die(_("options '%s' and '%s' cannot be used together"), "--verbose", "--porcelain");
+	else if (!line_terminator && !porcelain)
+		die(_("the option '%s' requires '%s'"), "-z", "--porcelain");
+	else {
+		struct worktree **worktrees = get_worktrees();
+		int path_maxlen = 0, abbrev = DEFAULT_ABBREV, i;
+
+		/* sort worktrees by path but keep main worktree at top */
+		pathsort(worktrees + 1);
+
+		if (!porcelain)
+			measure_widths(worktrees, &abbrev, &path_maxlen);
+
+		for (i = 0; worktrees[i]; i++) {
+			if (porcelain)
+				show_worktree_porcelain(worktrees[i],
+							line_terminator);
+			else
+				show_worktree(worktrees[i], path_maxlen, abbrev);
+		}
+		free_worktrees(worktrees);
+	}
+	return 0;
+}
+
+static int lock_worktree(int ac, const char **av, const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	const char *reason = "", *old_reason;
+	struct option options[] = {
+		OPT_STRING(0, "reason", &reason, N_("string"),
+			   N_("reason for locking")),
+		OPT_END()
+	};
+	struct worktree **worktrees, *wt;
+
+	ac = parse_options(ac, av, prefix, options, git_worktree_lock_usage, 0);
+	if (ac != 1)
+		usage_with_options(git_worktree_lock_usage, options);
+
+	worktrees = get_worktrees();
+	wt = find_worktree(worktrees, prefix, av[0]);
+	if (!wt)
+		die(_("'%s' is not a working tree"), av[0]);
+	if (is_main_worktree(wt))
+		die(_("The main working tree cannot be locked or unlocked"));
+
+	old_reason = worktree_lock_reason(wt);
+	if (old_reason) {
+		if (*old_reason)
+			die(_("'%s' is already locked, reason: %s"),
+			    av[0], old_reason);
+		die(_("'%s' is already locked"), av[0]);
+	}
+
+	write_file(git_common_path("worktrees/%s/locked", wt->id),
+		   "%s", reason);
+	free_worktrees(worktrees);
+	return 0;
+}
+
+static int unlock_worktree(int ac, const char **av, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	struct option options[] = {
+		OPT_END()
+	};
+	struct worktree **worktrees, *wt;
+	int ret;
+
+	ac = parse_options(ac, av, prefix, options, git_worktree_unlock_usage, 0);
+	if (ac != 1)
+		usage_with_options(git_worktree_unlock_usage, options);
+
+	worktrees = get_worktrees();
+	wt = find_worktree(worktrees, prefix, av[0]);
+	if (!wt)
+		die(_("'%s' is not a working tree"), av[0]);
+	if (is_main_worktree(wt))
+		die(_("The main working tree cannot be locked or unlocked"));
+	if (!worktree_lock_reason(wt))
+		die(_("'%s' is not locked"), av[0]);
+	ret = unlink_or_warn(git_common_path("worktrees/%s/locked", wt->id));
+	free_worktrees(worktrees);
+	return ret;
+}
+
+static void validate_no_submodules(const struct worktree *wt)
+{
+	struct index_state istate = INDEX_STATE_INIT(the_repository);
+	struct strbuf path = STRBUF_INIT;
+	int i, found_submodules = 0;
+
+	if (is_directory(worktree_git_path(the_repository, wt, "modules"))) {
+		/*
+		 * There could be false positives, e.g. the "modules"
+		 * directory exists but is empty. But it's a rare case and
+		 * this simpler check is probably good enough for now.
+		 */
+		found_submodules = 1;
+	} else if (read_index_from(&istate, worktree_git_path(the_repository, wt, "index"),
+				   get_worktree_git_dir(wt)) > 0) {
+		for (i = 0; i < istate.cache_nr; i++) {
+			struct cache_entry *ce = istate.cache[i];
+			int err;
+
+			if (!S_ISGITLINK(ce->ce_mode))
+				continue;
+
+			strbuf_reset(&path);
+			strbuf_addf(&path, "%s/%s", wt->path, ce->name);
+			if (!is_submodule_populated_gently(path.buf, &err))
+				continue;
+
+			found_submodules = 1;
+			break;
+		}
+	}
+	discard_index(&istate);
+	strbuf_release(&path);
+
+	if (found_submodules)
+		die(_("working trees containing submodules cannot be moved or removed"));
+}
+
+static int move_worktree(int ac, const char **av, const char *prefix,
+			 struct repository *repo UNUSED)
+{
+	int force = 0;
+	struct option options[] = {
+		OPT__FORCE(&force,
+			 N_("force move even if worktree is dirty or locked"),
+			 PARSE_OPT_NOCOMPLETE),
+		OPT_BOOL(0, "relative-paths", &use_relative_paths,
+			 N_("use relative paths for worktrees")),
+		OPT_END()
+	};
+	struct worktree **worktrees, *wt;
+	struct strbuf dst = STRBUF_INIT;
+	struct strbuf errmsg = STRBUF_INIT;
+	const char *reason = NULL;
+	char *path;
+
+	ac = parse_options(ac, av, prefix, options, git_worktree_move_usage,
+			   0);
+	if (ac != 2)
+		usage_with_options(git_worktree_move_usage, options);
+
+	path = prefix_filename(prefix, av[1]);
+	strbuf_addstr(&dst, path);
+	free(path);
+
+	worktrees = get_worktrees();
+	wt = find_worktree(worktrees, prefix, av[0]);
+	if (!wt)
+		die(_("'%s' is not a working tree"), av[0]);
+	if (is_main_worktree(wt))
+		die(_("'%s' is a main working tree"), av[0]);
+	if (is_directory(dst.buf)) {
+		const char *sep = find_last_dir_sep(wt->path);
+
+		if (!sep)
+			die(_("could not figure out destination name from '%s'"),
+			    wt->path);
+		strbuf_trim_trailing_dir_sep(&dst);
+		strbuf_addstr(&dst, sep);
+	}
+	check_candidate_path(dst.buf, force, worktrees, "move");
+
+	validate_no_submodules(wt);
+
+	if (force < 2)
+		reason = worktree_lock_reason(wt);
+	if (reason) {
+		if (*reason)
+			die(_("cannot move a locked working tree, lock reason: %s\nuse 'move -f -f' to override or unlock first"),
+			    reason);
+		die(_("cannot move a locked working tree;\nuse 'move -f -f' to override or unlock first"));
+	}
+	if (validate_worktree(wt, &errmsg, 0))
+		die(_("validation failed, cannot move working tree: %s"),
+		    errmsg.buf);
+	strbuf_release(&errmsg);
+
+	if (rename(wt->path, dst.buf) == -1)
+		die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf);
+
+	update_worktree_location(wt, dst.buf, use_relative_paths);
+
+	strbuf_release(&dst);
+	free_worktrees(worktrees);
+	return 0;
+}
+
+/*
+ * Note, "git status --porcelain" is used to determine if it's safe to
+ * delete a whole worktree. "git status" does not ignore user
+ * configuration, so if a normal "git status" shows "clean" for the
+ * user, then it's ok to remove it.
+ *
+ * This assumption may be a bad one. We may want to ignore
+ * (potentially bad) user settings and only delete a worktree when
+ * it's absolutely safe to do so from _our_ point of view because we
+ * know better.
+ */
+static void check_clean_worktree(struct worktree *wt,
+				 const char *original_path)
+{
+	struct child_process cp;
+	char buf[1];
+	int ret;
+
+	/*
+	 * Until we sort this out, all submodules are "dirty" and
+	 * will abort this function.
+	 */
+	validate_no_submodules(wt);
+
+	child_process_init(&cp);
+	strvec_pushf(&cp.env, "%s=%s/.git",
+		     GIT_DIR_ENVIRONMENT, wt->path);
+	strvec_pushf(&cp.env, "%s=%s",
+		     GIT_WORK_TREE_ENVIRONMENT, wt->path);
+	strvec_pushl(&cp.args, "status",
+		     "--porcelain", "--ignore-submodules=none",
+		     NULL);
+	cp.git_cmd = 1;
+	cp.dir = wt->path;
+	cp.out = -1;
+	ret = start_command(&cp);
+	if (ret)
+		die_errno(_("failed to run 'git status' on '%s'"),
+			  original_path);
+	ret = xread(cp.out, buf, sizeof(buf));
+	if (ret)
+		die(_("'%s' contains modified or untracked files, use --force to delete it"),
+		    original_path);
+	close(cp.out);
+	ret = finish_command(&cp);
+	if (ret)
+		die_errno(_("failed to run 'git status' on '%s', code %d"),
+			  original_path, ret);
+}
+
+static int delete_git_work_tree(struct worktree *wt)
+{
+	struct strbuf sb = STRBUF_INIT;
+	int ret = 0;
+
+	strbuf_addstr(&sb, wt->path);
+	if (remove_dir_recursively(&sb, 0)) {
+		error_errno(_("failed to delete '%s'"), sb.buf);
+		ret = -1;
+	}
+	strbuf_release(&sb);
+	return ret;
+}
+
+static int remove_worktree(int ac, const char **av, const char *prefix,
+			   struct repository *repo UNUSED)
+{
+	int force = 0;
+	struct option options[] = {
+		OPT__FORCE(&force,
+			 N_("force removal even if worktree is dirty or locked"),
+			 PARSE_OPT_NOCOMPLETE),
+		OPT_END()
+	};
+	struct worktree **worktrees, *wt;
+	struct strbuf errmsg = STRBUF_INIT;
+	const char *reason = NULL;
+	int ret = 0;
+
+	ac = parse_options(ac, av, prefix, options, git_worktree_remove_usage, 0);
+	if (ac != 1)
+		usage_with_options(git_worktree_remove_usage, options);
+
+	worktrees = get_worktrees();
+	wt = find_worktree(worktrees, prefix, av[0]);
+	if (!wt)
+		die(_("'%s' is not a working tree"), av[0]);
+	if (is_main_worktree(wt))
+		die(_("'%s' is a main working tree"), av[0]);
+	if (force < 2)
+		reason = worktree_lock_reason(wt);
+	if (reason) {
+		if (*reason)
+			die(_("cannot remove a locked working tree, lock reason: %s\nuse 'remove -f -f' to override or unlock first"),
+			    reason);
+		die(_("cannot remove a locked working tree;\nuse 'remove -f -f' to override or unlock first"));
+	}
+	if (validate_worktree(wt, &errmsg, WT_VALIDATE_WORKTREE_MISSING_OK))
+		die(_("validation failed, cannot remove working tree: %s"),
+		    errmsg.buf);
+	strbuf_release(&errmsg);
+
+	if (file_exists(wt->path)) {
+		if (!force)
+			check_clean_worktree(wt, av[0]);
+
+		ret |= delete_git_work_tree(wt);
+	}
+	/*
+	 * continue on even if ret is non-zero, there's no going back
+	 * from here.
+	 */
+	ret |= delete_git_dir(wt->id);
+	delete_worktrees_dir_if_empty();
+
+	free_worktrees(worktrees);
+	return ret;
+}
+
+static void report_repair(int iserr, const char *path, const char *msg, void *cb_data)
+{
+	if (!iserr) {
+		fprintf_ln(stderr, _("repair: %s: %s"), msg, path);
+	} else {
+		int *exit_status = (int *)cb_data;
+		fprintf_ln(stderr, _("error: %s: %s"), msg, path);
+		*exit_status = 1;
+	}
+}
+
+static int repair(int ac, const char **av, const char *prefix,
+		  struct repository *repo UNUSED)
+{
+	const char **p;
+	const char *self[] = { ".", NULL };
+	struct option options[] = {
+		OPT_BOOL(0, "relative-paths", &use_relative_paths,
+			 N_("use relative paths for worktrees")),
+		OPT_END()
+	};
+	int rc = 0;
+
+	ac = parse_options(ac, av, prefix, options, git_worktree_repair_usage, 0);
+	p = ac > 0 ? av : self;
+	for (; *p; p++)
+		repair_worktree_at_path(*p, report_repair, &rc, use_relative_paths);
+	repair_worktrees(report_repair, &rc, use_relative_paths);
+	return rc;
+}
+
+int cmd_worktree(int ac,
+		 const char **av,
+		 const char *prefix,
+		 struct repository *repo)
+{
+	parse_opt_subcommand_fn *fn = NULL;
+	struct option options[] = {
+		OPT_SUBCOMMAND("add", &fn, add),
+		OPT_SUBCOMMAND("prune", &fn, prune),
+		OPT_SUBCOMMAND("list", &fn, list),
+		OPT_SUBCOMMAND("lock", &fn, lock_worktree),
+		OPT_SUBCOMMAND("unlock", &fn, unlock_worktree),
+		OPT_SUBCOMMAND("move", &fn, move_worktree),
+		OPT_SUBCOMMAND("remove", &fn, remove_worktree),
+		OPT_SUBCOMMAND("repair", &fn, repair),
+		OPT_END()
+	};
+
+	git_config(git_worktree_config, NULL);
+
+	if (!prefix)
+		prefix = "";
+
+	ac = parse_options(ac, av, prefix, options, git_worktree_usage, 0);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	return fn(ac, av, prefix, repo);
+}
diff --git a/builtin/write-tree.c b/builtin/write-tree.c
new file mode 100644
index 0000000000..43f233e69b
--- /dev/null
+++ b/builtin/write-tree.c
@@ -0,0 +1,66 @@
+/*
+ * GIT - The information manager from hell
+ *
+ * Copyright (C) Linus Torvalds, 2005
+ */
+#define USE_THE_REPOSITORY_VARIABLE
+#include "builtin.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "tree.h"
+#include "cache-tree.h"
+#include "parse-options.h"
+
+static const char * const write_tree_usage[] = {
+	N_("git write-tree [--missing-ok] [--prefix=<prefix>/]"),
+	NULL
+};
+
+int cmd_write_tree(int argc,
+		   const char **argv,
+		   const char *cmd_prefix,
+		   struct repository *repo UNUSED)
+{
+	int flags = 0, ret;
+	const char *tree_prefix = NULL;
+	struct object_id oid;
+	const char *me = "git-write-tree";
+	struct option write_tree_options[] = {
+		OPT_BIT(0, "missing-ok", &flags, N_("allow missing objects"),
+			WRITE_TREE_MISSING_OK),
+		OPT_STRING(0, "prefix", &tree_prefix, N_("<prefix>/"),
+			   N_("write tree object for a subdirectory <prefix>")),
+		{ OPTION_BIT, 0, "ignore-cache-tree", &flags, NULL,
+		  N_("only useful for debugging"),
+		  PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, NULL,
+		  WRITE_TREE_IGNORE_CACHE_TREE },
+		OPT_END()
+	};
+
+	git_config(git_default_config, NULL);
+	argc = parse_options(argc, argv, cmd_prefix, write_tree_options,
+			     write_tree_usage, 0);
+
+	prepare_repo_settings(the_repository);
+	the_repository->settings.command_requires_full_index = 0;
+
+	ret = write_index_as_tree(&oid, the_repository->index,
+				  repo_get_index_file(the_repository),
+				  flags, tree_prefix);
+	switch (ret) {
+	case 0:
+		printf("%s\n", oid_to_hex(&oid));
+		break;
+	case WRITE_TREE_UNREADABLE_INDEX:
+		die("%s: error reading the index", me);
+		break;
+	case WRITE_TREE_UNMERGED_INDEX:
+		die("%s: error building trees", me);
+		break;
+	case WRITE_TREE_PREFIX_ERROR:
+		die("%s: prefix %s not found", me, tree_prefix);
+		break;
+	}
+	return ret;
+}
diff --git a/bulk-checkin.c b/bulk-checkin.c
new file mode 100644
index 0000000000..5044cb7fa0
--- /dev/null
+++ b/bulk-checkin.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2011, Google Inc.
+ */
+
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "bulk-checkin.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "repository.h"
+#include "csum-file.h"
+#include "pack.h"
+#include "strbuf.h"
+#include "tmp-objdir.h"
+#include "packfile.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+
+static int odb_transaction_nesting;
+
+static struct tmp_objdir *bulk_fsync_objdir;
+
+static struct bulk_checkin_packfile {
+	char *pack_tmp_name;
+	struct hashfile *f;
+	off_t offset;
+	struct pack_idx_option pack_idx_opts;
+
+	struct pack_idx_entry **written;
+	uint32_t alloc_written;
+	uint32_t nr_written;
+} bulk_checkin_packfile;
+
+static void finish_tmp_packfile(struct strbuf *basename,
+				const char *pack_tmp_name,
+				struct pack_idx_entry **written_list,
+				uint32_t nr_written,
+				struct pack_idx_option *pack_idx_opts,
+				unsigned char hash[])
+{
+	char *idx_tmp_name = NULL;
+
+	stage_tmp_packfiles(basename, pack_tmp_name, written_list, nr_written,
+			    NULL, pack_idx_opts, hash, &idx_tmp_name);
+	rename_tmp_packfile_idx(basename, &idx_tmp_name);
+
+	free(idx_tmp_name);
+}
+
+static void flush_bulk_checkin_packfile(struct bulk_checkin_packfile *state)
+{
+	unsigned char hash[GIT_MAX_RAWSZ];
+	struct strbuf packname = STRBUF_INIT;
+	int i;
+
+	if (!state->f)
+		return;
+
+	if (state->nr_written == 0) {
+		close(state->f->fd);
+		free_hashfile(state->f);
+		unlink(state->pack_tmp_name);
+		goto clear_exit;
+	} else if (state->nr_written == 1) {
+		finalize_hashfile(state->f, hash, FSYNC_COMPONENT_PACK,
+				  CSUM_HASH_IN_STREAM | CSUM_FSYNC | CSUM_CLOSE);
+	} else {
+		int fd = finalize_hashfile(state->f, hash, FSYNC_COMPONENT_PACK, 0);
+		fixup_pack_header_footer(fd, hash, state->pack_tmp_name,
+					 state->nr_written, hash,
+					 state->offset);
+		close(fd);
+	}
+
+	strbuf_addf(&packname, "%s/pack/pack-%s.", repo_get_object_directory(the_repository),
+		    hash_to_hex(hash));
+	finish_tmp_packfile(&packname, state->pack_tmp_name,
+			    state->written, state->nr_written,
+			    &state->pack_idx_opts, hash);
+	for (i = 0; i < state->nr_written; i++)
+		free(state->written[i]);
+
+clear_exit:
+	free(state->pack_tmp_name);
+	free(state->written);
+	memset(state, 0, sizeof(*state));
+
+	strbuf_release(&packname);
+	/* Make objects we just wrote available to ourselves */
+	reprepare_packed_git(the_repository);
+}
+
+/*
+ * Cleanup after batch-mode fsync_object_files.
+ */
+static void flush_batch_fsync(void)
+{
+	struct strbuf temp_path = STRBUF_INIT;
+	struct tempfile *temp;
+
+	if (!bulk_fsync_objdir)
+		return;
+
+	/*
+	 * Issue a full hardware flush against a temporary file to ensure
+	 * that all objects are durable before any renames occur. The code in
+	 * fsync_loose_object_bulk_checkin has already issued a writeout
+	 * request, but it has not flushed any writeback cache in the storage
+	 * hardware or any filesystem logs. This fsync call acts as a barrier
+	 * to ensure that the data in each new object file is durable before
+	 * the final name is visible.
+	 */
+	strbuf_addf(&temp_path, "%s/bulk_fsync_XXXXXX", repo_get_object_directory(the_repository));
+	temp = xmks_tempfile(temp_path.buf);
+	fsync_or_die(get_tempfile_fd(temp), get_tempfile_path(temp));
+	delete_tempfile(&temp);
+	strbuf_release(&temp_path);
+
+	/*
+	 * Make the object files visible in the primary ODB after their data is
+	 * fully durable.
+	 */
+	tmp_objdir_migrate(bulk_fsync_objdir);
+	bulk_fsync_objdir = NULL;
+}
+
+static int already_written(struct bulk_checkin_packfile *state, struct object_id *oid)
+{
+	int i;
+
+	/* The object may already exist in the repository */
+	if (repo_has_object_file(the_repository, oid))
+		return 1;
+
+	/* Might want to keep the list sorted */
+	for (i = 0; i < state->nr_written; i++)
+		if (oideq(&state->written[i]->oid, oid))
+			return 1;
+
+	/* This is a new object we need to keep */
+	return 0;
+}
+
+/*
+ * Read the contents from fd for size bytes, streaming it to the
+ * packfile in state while updating the hash in ctx. Signal a failure
+ * by returning a negative value when the resulting pack would exceed
+ * the pack size limit and this is not the first object in the pack,
+ * so that the caller can discard what we wrote from the current pack
+ * by truncating it and opening a new one. The caller will then call
+ * us again after rewinding the input fd.
+ *
+ * The already_hashed_to pointer is kept untouched by the caller to
+ * make sure we do not hash the same byte when we are called
+ * again. This way, the caller does not have to checkpoint its hash
+ * status before calling us just in case we ask it to call us again
+ * with a new pack.
+ */
+static int stream_blob_to_pack(struct bulk_checkin_packfile *state,
+			       git_hash_ctx *ctx, off_t *already_hashed_to,
+			       int fd, size_t size, const char *path,
+			       unsigned flags)
+{
+	git_zstream s;
+	unsigned char ibuf[16384];
+	unsigned char obuf[16384];
+	unsigned hdrlen;
+	int status = Z_OK;
+	int write_object = (flags & HASH_WRITE_OBJECT);
+	off_t offset = 0;
+
+	git_deflate_init(&s, pack_compression_level);
+
+	hdrlen = encode_in_pack_object_header(obuf, sizeof(obuf), OBJ_BLOB, size);
+	s.next_out = obuf + hdrlen;
+	s.avail_out = sizeof(obuf) - hdrlen;
+
+	while (status != Z_STREAM_END) {
+		if (size && !s.avail_in) {
+			ssize_t rsize = size < sizeof(ibuf) ? size : sizeof(ibuf);
+			ssize_t read_result = read_in_full(fd, ibuf, rsize);
+			if (read_result < 0)
+				die_errno("failed to read from '%s'", path);
+			if (read_result != rsize)
+				die("failed to read %d bytes from '%s'",
+				    (int)rsize, path);
+			offset += rsize;
+			if (*already_hashed_to < offset) {
+				size_t hsize = offset - *already_hashed_to;
+				if (rsize < hsize)
+					hsize = rsize;
+				if (hsize)
+					the_hash_algo->update_fn(ctx, ibuf, hsize);
+				*already_hashed_to = offset;
+			}
+			s.next_in = ibuf;
+			s.avail_in = rsize;
+			size -= rsize;
+		}
+
+		status = git_deflate(&s, size ? 0 : Z_FINISH);
+
+		if (!s.avail_out || status == Z_STREAM_END) {
+			if (write_object) {
+				size_t written = s.next_out - obuf;
+
+				/* would we bust the size limit? */
+				if (state->nr_written &&
+				    pack_size_limit_cfg &&
+				    pack_size_limit_cfg < state->offset + written) {
+					git_deflate_abort(&s);
+					return -1;
+				}
+
+				hashwrite(state->f, obuf, written);
+				state->offset += written;
+			}
+			s.next_out = obuf;
+			s.avail_out = sizeof(obuf);
+		}
+
+		switch (status) {
+		case Z_OK:
+		case Z_BUF_ERROR:
+		case Z_STREAM_END:
+			continue;
+		default:
+			die("unexpected deflate failure: %d", status);
+		}
+	}
+	git_deflate_end(&s);
+	return 0;
+}
+
+/* Lazily create backing packfile for the state */
+static void prepare_to_stream(struct bulk_checkin_packfile *state,
+			      unsigned flags)
+{
+	if (!(flags & HASH_WRITE_OBJECT) || state->f)
+		return;
+
+	state->f = create_tmp_packfile(&state->pack_tmp_name);
+	reset_pack_idx_option(&state->pack_idx_opts);
+
+	/* Pretend we are going to write only one object */
+	state->offset = write_pack_header(state->f, 1);
+	if (!state->offset)
+		die_errno("unable to write pack header");
+}
+
+static int deflate_blob_to_pack(struct bulk_checkin_packfile *state,
+				struct object_id *result_oid,
+				int fd, size_t size,
+				const char *path, unsigned flags)
+{
+	off_t seekback, already_hashed_to;
+	git_hash_ctx ctx;
+	unsigned char obuf[16384];
+	unsigned header_len;
+	struct hashfile_checkpoint checkpoint = {0};
+	struct pack_idx_entry *idx = NULL;
+
+	seekback = lseek(fd, 0, SEEK_CUR);
+	if (seekback == (off_t) -1)
+		return error("cannot find the current offset");
+
+	header_len = format_object_header((char *)obuf, sizeof(obuf),
+					  OBJ_BLOB, size);
+	the_hash_algo->init_fn(&ctx);
+	the_hash_algo->update_fn(&ctx, obuf, header_len);
+	the_hash_algo->unsafe_init_fn(&checkpoint.ctx);
+
+	/* Note: idx is non-NULL when we are writing */
+	if ((flags & HASH_WRITE_OBJECT) != 0)
+		CALLOC_ARRAY(idx, 1);
+
+	already_hashed_to = 0;
+
+	while (1) {
+		prepare_to_stream(state, flags);
+		if (idx) {
+			hashfile_checkpoint(state->f, &checkpoint);
+			idx->offset = state->offset;
+			crc32_begin(state->f);
+		}
+		if (!stream_blob_to_pack(state, &ctx, &already_hashed_to,
+					 fd, size, path, flags))
+			break;
+		/*
+		 * Writing this object to the current pack will make
+		 * it too big; we need to truncate it, start a new
+		 * pack, and write into it.
+		 */
+		if (!idx)
+			BUG("should not happen");
+		hashfile_truncate(state->f, &checkpoint);
+		state->offset = checkpoint.offset;
+		flush_bulk_checkin_packfile(state);
+		if (lseek(fd, seekback, SEEK_SET) == (off_t) -1)
+			return error("cannot seek back");
+	}
+	the_hash_algo->final_oid_fn(result_oid, &ctx);
+	if (!idx)
+		return 0;
+
+	idx->crc32 = crc32_end(state->f);
+	if (already_written(state, result_oid)) {
+		hashfile_truncate(state->f, &checkpoint);
+		state->offset = checkpoint.offset;
+		free(idx);
+	} else {
+		oidcpy(&idx->oid, result_oid);
+		ALLOC_GROW(state->written,
+			   state->nr_written + 1,
+			   state->alloc_written);
+		state->written[state->nr_written++] = idx;
+	}
+	return 0;
+}
+
+void prepare_loose_object_bulk_checkin(void)
+{
+	/*
+	 * We lazily create the temporary object directory
+	 * the first time an object might be added, since
+	 * callers may not know whether any objects will be
+	 * added at the time they call begin_odb_transaction.
+	 */
+	if (!odb_transaction_nesting || bulk_fsync_objdir)
+		return;
+
+	bulk_fsync_objdir = tmp_objdir_create(the_repository, "bulk-fsync");
+	if (bulk_fsync_objdir)
+		tmp_objdir_replace_primary_odb(bulk_fsync_objdir, 0);
+}
+
+void fsync_loose_object_bulk_checkin(int fd, const char *filename)
+{
+	/*
+	 * If we have an active ODB transaction, we issue a call that
+	 * cleans the filesystem page cache but avoids a hardware flush
+	 * command. Later on we will issue a single hardware flush
+	 * before renaming the objects to their final names as part of
+	 * flush_batch_fsync.
+	 */
+	if (!bulk_fsync_objdir ||
+	    git_fsync(fd, FSYNC_WRITEOUT_ONLY) < 0) {
+		if (errno == ENOSYS)
+			warning(_("core.fsyncMethod = batch is unsupported on this platform"));
+		fsync_or_die(fd, filename);
+	}
+}
+
+int index_blob_bulk_checkin(struct object_id *oid,
+			    int fd, size_t size,
+			    const char *path, unsigned flags)
+{
+	int status = deflate_blob_to_pack(&bulk_checkin_packfile, oid, fd, size,
+					  path, flags);
+	if (!odb_transaction_nesting)
+		flush_bulk_checkin_packfile(&bulk_checkin_packfile);
+	return status;
+}
+
+void begin_odb_transaction(void)
+{
+	odb_transaction_nesting += 1;
+}
+
+void flush_odb_transaction(void)
+{
+	flush_batch_fsync();
+	flush_bulk_checkin_packfile(&bulk_checkin_packfile);
+}
+
+void end_odb_transaction(void)
+{
+	odb_transaction_nesting -= 1;
+	if (odb_transaction_nesting < 0)
+		BUG("Unbalanced ODB transaction nesting");
+
+	if (odb_transaction_nesting)
+		return;
+
+	flush_odb_transaction();
+}
diff --git a/bulk-checkin.h b/bulk-checkin.h
new file mode 100644
index 0000000000..aa7286a7b3
--- /dev/null
+++ b/bulk-checkin.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011, Google Inc.
+ */
+#ifndef BULK_CHECKIN_H
+#define BULK_CHECKIN_H
+
+#include "object.h"
+
+void prepare_loose_object_bulk_checkin(void);
+void fsync_loose_object_bulk_checkin(int fd, const char *filename);
+
+int index_blob_bulk_checkin(struct object_id *oid,
+			    int fd, size_t size,
+			    const char *path, unsigned flags);
+
+/*
+ * Tell the object database to optimize for adding
+ * multiple objects. end_odb_transaction must be called
+ * to make new objects visible. Transactions can be nested,
+ * and objects are only visible after the outermost transaction
+ * is complete or the transaction is flushed.
+ */
+void begin_odb_transaction(void);
+
+/*
+ * Make any objects that are currently part of a pending object
+ * database transaction visible. It is valid to call this function
+ * even if no transaction is active.
+ */
+void flush_odb_transaction(void);
+
+/*
+ * Tell the object database to make any objects from the
+ * current transaction visible if this is the final nested
+ * transaction.
+ */
+void end_odb_transaction(void);
+
+#endif
diff --git a/bundle-uri.c b/bundle-uri.c
new file mode 100644
index 0000000000..744257c49c
--- /dev/null
+++ b/bundle-uri.c
@@ -0,0 +1,954 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "bundle-uri.h"
+#include "bundle.h"
+#include "copy.h"
+#include "gettext.h"
+#include "refs.h"
+#include "run-command.h"
+#include "hashmap.h"
+#include "pkt-line.h"
+#include "config.h"
+#include "fetch-pack.h"
+#include "remote.h"
+#include "trace2.h"
+#include "object-store-ll.h"
+
+static struct {
+	enum bundle_list_heuristic heuristic;
+	const char *name;
+} heuristics[BUNDLE_HEURISTIC__COUNT] = {
+	{ BUNDLE_HEURISTIC_NONE, ""},
+	{ BUNDLE_HEURISTIC_CREATIONTOKEN, "creationToken" },
+};
+
+static int compare_bundles(const void *hashmap_cmp_fn_data UNUSED,
+			   const struct hashmap_entry *he1,
+			   const struct hashmap_entry *he2,
+			   const void *id)
+{
+	const struct remote_bundle_info *e1 =
+		container_of(he1, const struct remote_bundle_info, ent);
+	const struct remote_bundle_info *e2 =
+		container_of(he2, const struct remote_bundle_info, ent);
+
+	return strcmp(e1->id, id ? (const char *)id : e2->id);
+}
+
+void init_bundle_list(struct bundle_list *list)
+{
+	memset(list, 0, sizeof(*list));
+
+	/* Implied defaults. */
+	list->mode = BUNDLE_MODE_ALL;
+	list->version = 1;
+
+	hashmap_init(&list->bundles, compare_bundles, NULL, 0);
+}
+
+static int clear_remote_bundle_info(struct remote_bundle_info *bundle,
+				    void *data UNUSED)
+{
+	FREE_AND_NULL(bundle->id);
+	FREE_AND_NULL(bundle->uri);
+	FREE_AND_NULL(bundle->file);
+	bundle->unbundled = 0;
+	return 0;
+}
+
+void clear_bundle_list(struct bundle_list *list)
+{
+	if (!list)
+		return;
+
+	for_all_bundles_in_list(list, clear_remote_bundle_info, NULL);
+	hashmap_clear_and_free(&list->bundles, struct remote_bundle_info, ent);
+	free(list->baseURI);
+}
+
+int for_all_bundles_in_list(struct bundle_list *list,
+			    bundle_iterator iter,
+			    void *data)
+{
+	struct remote_bundle_info *info;
+	struct hashmap_iter i;
+
+	hashmap_for_each_entry(&list->bundles, &i, info, ent) {
+		int result = iter(info, data);
+
+		if (result)
+			return result;
+	}
+
+	return 0;
+}
+
+static int summarize_bundle(struct remote_bundle_info *info, void *data)
+{
+	FILE *fp = data;
+	fprintf(fp, "[bundle \"%s\"]\n", info->id);
+	fprintf(fp, "\turi = %s\n", info->uri);
+
+	if (info->creationToken)
+		fprintf(fp, "\tcreationToken = %"PRIu64"\n", info->creationToken);
+	return 0;
+}
+
+void print_bundle_list(FILE *fp, struct bundle_list *list)
+{
+	const char *mode;
+
+	switch (list->mode) {
+	case BUNDLE_MODE_ALL:
+		mode = "all";
+		break;
+
+	case BUNDLE_MODE_ANY:
+		mode = "any";
+		break;
+
+	case BUNDLE_MODE_NONE:
+	default:
+		mode = "<unknown>";
+	}
+
+	fprintf(fp, "[bundle]\n");
+	fprintf(fp, "\tversion = %d\n", list->version);
+	fprintf(fp, "\tmode = %s\n", mode);
+
+	if (list->heuristic) {
+		int i;
+		for (i = 0; i < BUNDLE_HEURISTIC__COUNT; i++) {
+			if (heuristics[i].heuristic == list->heuristic) {
+				printf("\theuristic = %s\n",
+				       heuristics[list->heuristic].name);
+				break;
+			}
+		}
+	}
+
+	for_all_bundles_in_list(list, summarize_bundle, fp);
+}
+
+/**
+ * Given a key-value pair, update the state of the given bundle list.
+ * Returns 0 if the key-value pair is understood. Returns -1 if the key
+ * is not understood or the value is malformed.
+ */
+static int bundle_list_update(const char *key, const char *value,
+			      struct bundle_list *list)
+{
+	struct strbuf id = STRBUF_INIT;
+	struct remote_bundle_info lookup = REMOTE_BUNDLE_INFO_INIT;
+	struct remote_bundle_info *bundle;
+	const char *subsection, *subkey;
+	size_t subsection_len;
+
+	if (parse_config_key(key, "bundle", &subsection, &subsection_len, &subkey))
+		return -1;
+
+	if (!subsection_len) {
+		if (!strcmp(subkey, "version")) {
+			int version;
+			if (!git_parse_int(value, &version))
+				return -1;
+			if (version != 1)
+				return -1;
+
+			list->version = version;
+			return 0;
+		}
+
+		if (!strcmp(subkey, "mode")) {
+			if (!strcmp(value, "all"))
+				list->mode = BUNDLE_MODE_ALL;
+			else if (!strcmp(value, "any"))
+				list->mode = BUNDLE_MODE_ANY;
+			else
+				return -1;
+			return 0;
+		}
+
+		if (!strcmp(subkey, "heuristic")) {
+			int i;
+			for (i = 0; i < BUNDLE_HEURISTIC__COUNT; i++) {
+				if (heuristics[i].heuristic &&
+				    heuristics[i].name &&
+				    !strcmp(value, heuristics[i].name)) {
+					list->heuristic = heuristics[i].heuristic;
+					return 0;
+				}
+			}
+
+			/* Ignore unknown heuristics. */
+			return 0;
+		}
+
+		/* Ignore other unknown global keys. */
+		return 0;
+	}
+
+	strbuf_add(&id, subsection, subsection_len);
+
+	/*
+	 * Check for an existing bundle with this <id>, or create one
+	 * if necessary.
+	 */
+	lookup.id = id.buf;
+	hashmap_entry_init(&lookup.ent, strhash(lookup.id));
+	if (!(bundle = hashmap_get_entry(&list->bundles, &lookup, ent, NULL))) {
+		CALLOC_ARRAY(bundle, 1);
+		bundle->id = strbuf_detach(&id, NULL);
+		hashmap_entry_init(&bundle->ent, strhash(bundle->id));
+		hashmap_add(&list->bundles, &bundle->ent);
+	}
+	strbuf_release(&id);
+
+	if (!strcmp(subkey, "uri")) {
+		if (bundle->uri)
+			return -1;
+		bundle->uri = relative_url(list->baseURI, value, NULL);
+		return 0;
+	}
+
+	if (!strcmp(subkey, "creationtoken")) {
+		if (sscanf(value, "%"PRIu64, &bundle->creationToken) != 1)
+			warning(_("could not parse bundle list key %s with value '%s'"),
+				"creationToken", value);
+		return 0;
+	}
+
+	/*
+	 * At this point, we ignore any information that we don't
+	 * understand, assuming it to be hints for a heuristic the client
+	 * does not currently understand.
+	 */
+	return 0;
+}
+
+static int config_to_bundle_list(const char *key, const char *value,
+				 const struct config_context *ctx UNUSED,
+				 void *data)
+{
+	struct bundle_list *list = data;
+	return bundle_list_update(key, value, list);
+}
+
+int bundle_uri_parse_config_format(const char *uri,
+				   const char *filename,
+				   struct bundle_list *list)
+{
+	int result;
+	struct config_options opts = {
+		.error_action = CONFIG_ERROR_ERROR,
+	};
+
+	if (!list->baseURI) {
+		struct strbuf baseURI = STRBUF_INIT;
+		strbuf_addstr(&baseURI, uri);
+
+		/*
+		 * If the URI does not end with a trailing slash, then
+		 * remove the filename portion of the path. This is
+		 * important for relative URIs.
+		 */
+		strbuf_strip_file_from_path(&baseURI);
+		list->baseURI = strbuf_detach(&baseURI, NULL);
+	}
+	result = git_config_from_file_with_options(config_to_bundle_list,
+						   filename, list,
+						   CONFIG_SCOPE_UNKNOWN,
+						   &opts);
+
+	if (!result && list->mode == BUNDLE_MODE_NONE) {
+		warning(_("bundle list at '%s' has no mode"), uri);
+		result = 1;
+	}
+
+	return result;
+}
+
+static char *find_temp_filename(void)
+{
+	int fd;
+	struct strbuf name = STRBUF_INIT;
+	/*
+	 * Find a temporary filename that is available. This is briefly
+	 * racy, but unlikely to collide.
+	 */
+	fd = odb_mkstemp(&name, "bundles/tmp_uri_XXXXXX");
+	if (fd < 0) {
+		warning(_("failed to create temporary file"));
+		return NULL;
+	}
+
+	close(fd);
+	unlink(name.buf);
+	return strbuf_detach(&name, NULL);
+}
+
+static int download_https_uri_to_file(const char *file, const char *uri)
+{
+	int result = 0;
+	struct child_process cp = CHILD_PROCESS_INIT;
+	FILE *child_in = NULL, *child_out = NULL;
+	struct strbuf line = STRBUF_INIT;
+	int found_get = 0;
+
+	strvec_pushl(&cp.args, "git-remote-https", uri, NULL);
+	cp.err = -1;
+	cp.in = -1;
+	cp.out = -1;
+
+	if (start_command(&cp))
+		return 1;
+
+	child_in = fdopen(cp.in, "w");
+	if (!child_in) {
+		result = 1;
+		goto cleanup;
+	}
+
+	child_out = fdopen(cp.out, "r");
+	if (!child_out) {
+		result = 1;
+		goto cleanup;
+	}
+
+	fprintf(child_in, "capabilities\n");
+	fflush(child_in);
+
+	while (!strbuf_getline(&line, child_out)) {
+		if (!line.len)
+			break;
+		if (!strcmp(line.buf, "get"))
+			found_get = 1;
+	}
+	strbuf_release(&line);
+
+	if (!found_get) {
+		result = error(_("insufficient capabilities"));
+		goto cleanup;
+	}
+
+	fprintf(child_in, "get %s %s\n\n", uri, file);
+
+cleanup:
+	if (child_in)
+		fclose(child_in);
+	if (finish_command(&cp))
+		return 1;
+	if (child_out)
+		fclose(child_out);
+	return result;
+}
+
+static int copy_uri_to_file(const char *filename, const char *uri)
+{
+	const char *out;
+
+	if (starts_with(uri, "https:") ||
+	    starts_with(uri, "http:"))
+		return download_https_uri_to_file(filename, uri);
+
+	if (skip_prefix(uri, "file://", &out))
+		uri = out;
+
+	/* Copy as a file */
+	return copy_file(filename, uri, 0);
+}
+
+static int unbundle_from_file(struct repository *r, const char *file)
+{
+	int result = 0;
+	int bundle_fd;
+	struct bundle_header header = BUNDLE_HEADER_INIT;
+	struct string_list_item *refname;
+	struct strbuf bundle_ref = STRBUF_INIT;
+	size_t bundle_prefix_len;
+	struct unbundle_opts opts = {
+		.flags = VERIFY_BUNDLE_QUIET |
+			 (fetch_pack_fsck_objects() ? VERIFY_BUNDLE_FSCK : 0),
+	};
+
+	bundle_fd = read_bundle_header(file, &header);
+	if (bundle_fd < 0) {
+		result = 1;
+		goto cleanup;
+	}
+
+	/*
+	 * Skip the reachability walk here, since we will be adding
+	 * a reachable ref pointing to the new tips, which will reach
+	 * the prerequisite commits.
+	 */
+	result = unbundle(r, &header, bundle_fd, NULL, &opts);
+	if (result) {
+		result = 1;
+		goto cleanup;
+	}
+
+	/*
+	 * Convert all refs/heads/ from the bundle into refs/bundles/
+	 * in the local repository.
+	 */
+	strbuf_addstr(&bundle_ref, "refs/bundles/");
+	bundle_prefix_len = bundle_ref.len;
+
+	for_each_string_list_item(refname, &header.references) {
+		struct object_id *oid = refname->util;
+		struct object_id old_oid;
+		const char *branch_name;
+		int has_old;
+
+		if (!skip_prefix(refname->string, "refs/heads/", &branch_name))
+			continue;
+
+		strbuf_setlen(&bundle_ref, bundle_prefix_len);
+		strbuf_addstr(&bundle_ref, branch_name);
+
+		has_old = !refs_read_ref(get_main_ref_store(the_repository),
+					 bundle_ref.buf, &old_oid);
+		refs_update_ref(get_main_ref_store(the_repository),
+				"fetched bundle", bundle_ref.buf, oid,
+				has_old ? &old_oid : NULL,
+				0, UPDATE_REFS_MSG_ON_ERR);
+	}
+
+cleanup:
+	strbuf_release(&bundle_ref);
+	bundle_header_release(&header);
+	return result;
+}
+
+struct bundle_list_context {
+	struct repository *r;
+	struct bundle_list *list;
+	enum bundle_list_mode mode;
+	int count;
+	int depth;
+};
+
+/*
+ * This early definition is necessary because we use indirect recursion:
+ *
+ * While iterating through a bundle list that was downloaded as part
+ * of fetch_bundle_uri_internal(), iterator methods eventually call it
+ * again, but with depth + 1.
+ */
+static int fetch_bundle_uri_internal(struct repository *r,
+				     struct remote_bundle_info *bundle,
+				     int depth,
+				     struct bundle_list *list);
+
+static int download_bundle_to_file(struct remote_bundle_info *bundle, void *data)
+{
+	int res;
+	struct bundle_list_context *ctx = data;
+
+	if (ctx->mode == BUNDLE_MODE_ANY && ctx->count)
+		return 0;
+
+	res = fetch_bundle_uri_internal(ctx->r, bundle, ctx->depth + 1, ctx->list);
+
+	/*
+	 * Only increment count if the download succeeded. If our mode is
+	 * BUNDLE_MODE_ANY, then we will want to try other URIs in the
+	 * list in case they work instead.
+	 */
+	if (!res)
+		ctx->count++;
+
+	/*
+	 * To be opportunistic as possible, we continue iterating and
+	 * download as many bundles as we can, so we can apply the ones
+	 * that work, even in BUNDLE_MODE_ALL mode.
+	 */
+	return 0;
+}
+
+struct bundles_for_sorting {
+	struct remote_bundle_info **items;
+	size_t alloc;
+	size_t nr;
+};
+
+static int append_bundle(struct remote_bundle_info *bundle, void *data)
+{
+	struct bundles_for_sorting *list = data;
+	list->items[list->nr++] = bundle;
+	return 0;
+}
+
+/**
+ * For use in QSORT() to get a list sorted by creationToken
+ * in decreasing order.
+ */
+static int compare_creation_token_decreasing(const void *va, const void *vb)
+{
+	const struct remote_bundle_info * const *a = va;
+	const struct remote_bundle_info * const *b = vb;
+
+	if ((*a)->creationToken > (*b)->creationToken)
+		return -1;
+	if ((*a)->creationToken < (*b)->creationToken)
+		return 1;
+	return 0;
+}
+
+static int fetch_bundles_by_token(struct repository *r,
+				  struct bundle_list *list)
+{
+	int cur;
+	int move_direction = 0;
+	const char *creationTokenStr;
+	uint64_t maxCreationToken = 0, newMaxCreationToken = 0;
+	struct bundle_list_context ctx = {
+		.r = r,
+		.list = list,
+		.mode = list->mode,
+	};
+	struct bundles_for_sorting bundles = {
+		.alloc = hashmap_get_size(&list->bundles),
+	};
+
+	ALLOC_ARRAY(bundles.items, bundles.alloc);
+
+	for_all_bundles_in_list(list, append_bundle, &bundles);
+
+	if (!bundles.nr) {
+		free(bundles.items);
+		return 0;
+	}
+
+	QSORT(bundles.items, bundles.nr, compare_creation_token_decreasing);
+
+	/*
+	 * If fetch.bundleCreationToken exists, parses to a uint64t, and
+	 * is not strictly smaller than the maximum creation token in the
+	 * bundle list, then do not download any bundles.
+	 */
+	if (!repo_config_get_value(r,
+				   "fetch.bundlecreationtoken",
+				   &creationTokenStr) &&
+	    sscanf(creationTokenStr, "%"PRIu64, &maxCreationToken) == 1 &&
+	    bundles.items[0]->creationToken <= maxCreationToken) {
+		free(bundles.items);
+		return 0;
+	}
+
+	/*
+	 * Attempt to download and unbundle the minimum number of bundles by
+	 * creationToken in decreasing order. If we fail to unbundle (after
+	 * a successful download) then move to the next non-downloaded bundle
+	 * and attempt downloading. Once we succeed in applying a bundle,
+	 * move to the previous unapplied bundle and attempt to unbundle it
+	 * again.
+	 *
+	 * In the case of a fresh clone, we will likely download all of the
+	 * bundles before successfully unbundling the oldest one, then the
+	 * rest of the bundles unbundle successfully in increasing order
+	 * of creationToken.
+	 *
+	 * If there are existing objects, then this process may terminate
+	 * early when all required commits from "new" bundles exist in the
+	 * repo's object store.
+	 */
+	cur = 0;
+	while (cur >= 0 && cur < bundles.nr) {
+		struct remote_bundle_info *bundle = bundles.items[cur];
+
+		/*
+		 * If we need to dig into bundles below the previous
+		 * creation token value, then likely we are in an erroneous
+		 * state due to missing or invalid bundles. Halt the process
+		 * instead of continuing to download extra data.
+		 */
+		if (bundle->creationToken <= maxCreationToken)
+			break;
+
+		if (!bundle->file) {
+			/*
+			 * Not downloaded yet. Try downloading.
+			 *
+			 * Note that bundle->file is non-NULL if a download
+			 * was attempted, even if it failed to download.
+			 */
+			if (fetch_bundle_uri_internal(ctx.r, bundle, ctx.depth + 1, ctx.list)) {
+				/* Mark as unbundled so we do not retry. */
+				bundle->unbundled = 1;
+
+				/* Try looking deeper in the list. */
+				move_direction = 1;
+				goto move;
+			}
+
+			/* We expect bundles when using creationTokens. */
+			if (!is_bundle(bundle->file, 1)) {
+				warning(_("file downloaded from '%s' is not a bundle"),
+					bundle->uri);
+				break;
+			}
+		}
+
+		if (bundle->file && !bundle->unbundled) {
+			/*
+			 * This was downloaded, but not successfully
+			 * unbundled. Try unbundling again.
+			 */
+			if (unbundle_from_file(ctx.r, bundle->file)) {
+				/* Try looking deeper in the list. */
+				move_direction = 1;
+			} else {
+				/*
+				 * Succeeded in unbundle. Retry bundles
+				 * that previously failed to unbundle.
+				 */
+				move_direction = -1;
+				bundle->unbundled = 1;
+
+				if (bundle->creationToken > newMaxCreationToken)
+					newMaxCreationToken = bundle->creationToken;
+			}
+		}
+
+		/*
+		 * Else case: downloaded and unbundled successfully.
+		 * Skip this by moving in the same direction as the
+		 * previous step.
+		 */
+
+move:
+		/* Move in the specified direction and repeat. */
+		cur += move_direction;
+	}
+
+	/*
+	 * We succeed if the loop terminates because 'cur' drops below
+	 * zero. The other case is that we terminate because 'cur'
+	 * reaches the end of the list, so we have a failure no matter
+	 * which bundles we apply from the list.
+	 */
+	if (cur < 0) {
+		struct strbuf value = STRBUF_INIT;
+		strbuf_addf(&value, "%"PRIu64"", newMaxCreationToken);
+		if (repo_config_set_multivar_gently(ctx.r,
+						    "fetch.bundleCreationToken",
+						    value.buf, NULL, 0))
+			warning(_("failed to store maximum creation token"));
+
+		strbuf_release(&value);
+	}
+
+	free(bundles.items);
+	return cur >= 0;
+}
+
+static int download_bundle_list(struct repository *r,
+				struct bundle_list *local_list,
+				struct bundle_list *global_list,
+				int depth)
+{
+	struct bundle_list_context ctx = {
+		.r = r,
+		.list = global_list,
+		.depth = depth + 1,
+		.mode = local_list->mode,
+	};
+
+	return for_all_bundles_in_list(local_list, download_bundle_to_file, &ctx);
+}
+
+static int fetch_bundle_list_in_config_format(struct repository *r,
+					      struct bundle_list *global_list,
+					      struct remote_bundle_info *bundle,
+					      int depth)
+{
+	int result;
+	struct bundle_list list_from_bundle;
+
+	init_bundle_list(&list_from_bundle);
+
+	if ((result = bundle_uri_parse_config_format(bundle->uri,
+						     bundle->file,
+						     &list_from_bundle)))
+		goto cleanup;
+
+	if (list_from_bundle.mode == BUNDLE_MODE_NONE) {
+		warning(_("unrecognized bundle mode from URI '%s'"),
+			bundle->uri);
+		result = -1;
+		goto cleanup;
+	}
+
+	/*
+	 * If this list uses the creationToken heuristic, then the URIs
+	 * it advertises are expected to be bundles, not nested lists.
+	 * We can drop 'global_list' and 'depth'.
+	 */
+	if (list_from_bundle.heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN) {
+		result = fetch_bundles_by_token(r, &list_from_bundle);
+		global_list->heuristic = BUNDLE_HEURISTIC_CREATIONTOKEN;
+	} else if ((result = download_bundle_list(r, &list_from_bundle,
+					   global_list, depth)))
+		goto cleanup;
+
+cleanup:
+	clear_bundle_list(&list_from_bundle);
+	return result;
+}
+
+/**
+ * This limits the recursion on fetch_bundle_uri_internal() when following
+ * bundle lists.
+ */
+static int max_bundle_uri_depth = 4;
+
+/**
+ * Recursively download all bundles advertised at the given URI
+ * to files. If the file is a bundle, then add it to the given
+ * 'list'. Otherwise, expect a bundle list and recurse on the
+ * URIs in that list according to the list mode (ANY or ALL).
+ */
+static int fetch_bundle_uri_internal(struct repository *r,
+				     struct remote_bundle_info *bundle,
+				     int depth,
+				     struct bundle_list *list)
+{
+	int result = 0;
+	struct remote_bundle_info *bcopy;
+
+	if (depth >= max_bundle_uri_depth) {
+		warning(_("exceeded bundle URI recursion limit (%d)"),
+			max_bundle_uri_depth);
+		return -1;
+	}
+
+	if (!bundle->file &&
+	    !(bundle->file = find_temp_filename())) {
+		result = -1;
+		goto cleanup;
+	}
+
+	if ((result = copy_uri_to_file(bundle->file, bundle->uri))) {
+		warning(_("failed to download bundle from URI '%s'"), bundle->uri);
+		goto cleanup;
+	}
+
+	if ((result = !is_bundle(bundle->file, 1))) {
+		result = fetch_bundle_list_in_config_format(
+				r, list, bundle, depth);
+		if (result)
+			warning(_("file at URI '%s' is not a bundle or bundle list"),
+				bundle->uri);
+		goto cleanup;
+	}
+
+	/* Copy the bundle and insert it into the global list. */
+	CALLOC_ARRAY(bcopy, 1);
+	bcopy->id = xstrdup(bundle->id);
+	bcopy->file = xstrdup(bundle->file);
+	hashmap_entry_init(&bcopy->ent, strhash(bcopy->id));
+	hashmap_add(&list->bundles, &bcopy->ent);
+
+cleanup:
+	if (result && bundle->file)
+		unlink(bundle->file);
+	return result;
+}
+
+/**
+ * This loop iterator breaks the loop with nonzero return code on the
+ * first successful unbundling of a bundle.
+ */
+static int attempt_unbundle(struct remote_bundle_info *info, void *data)
+{
+	struct repository *r = data;
+
+	if (!info->file || info->unbundled)
+		return 0;
+
+	if (!unbundle_from_file(r, info->file)) {
+		info->unbundled = 1;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int unbundle_all_bundles(struct repository *r,
+				struct bundle_list *list)
+{
+	/*
+	 * Iterate through all bundles looking for ones that can
+	 * successfully unbundle. If any succeed, then perhaps another
+	 * will succeed in the next attempt.
+	 *
+	 * Keep in mind that a non-zero result for the loop here means
+	 * the loop terminated early on a successful unbundling, which
+	 * signals that we can try again.
+	 */
+	while (for_all_bundles_in_list(list, attempt_unbundle, r)) ;
+
+	return 0;
+}
+
+static int unlink_bundle(struct remote_bundle_info *info, void *data UNUSED)
+{
+	if (info->file)
+		unlink_or_warn(info->file);
+	return 0;
+}
+
+int fetch_bundle_uri(struct repository *r, const char *uri,
+		     int *has_heuristic)
+{
+	int result;
+	struct bundle_list list;
+	struct remote_bundle_info bundle = {
+		.uri = xstrdup(uri),
+		.id = xstrdup(""),
+	};
+
+	trace2_region_enter("fetch", "fetch-bundle-uri", the_repository);
+
+	init_bundle_list(&list);
+
+	/*
+	 * Do not fetch an empty bundle URI. An empty bundle URI
+	 * could signal that a configured bundle URI has been disabled.
+	 */
+	if (!*uri) {
+		result = 0;
+		goto cleanup;
+	}
+
+	/* If a bundle is added to this global list, then it is required. */
+	list.mode = BUNDLE_MODE_ALL;
+
+	if ((result = fetch_bundle_uri_internal(r, &bundle, 0, &list)))
+		goto cleanup;
+
+	result = unbundle_all_bundles(r, &list);
+
+cleanup:
+	if (has_heuristic)
+		*has_heuristic = (list.heuristic != BUNDLE_HEURISTIC_NONE);
+	for_all_bundles_in_list(&list, unlink_bundle, NULL);
+	clear_bundle_list(&list);
+	clear_remote_bundle_info(&bundle, NULL);
+	trace2_region_leave("fetch", "fetch-bundle-uri", the_repository);
+	return result;
+}
+
+int fetch_bundle_list(struct repository *r, struct bundle_list *list)
+{
+	int result;
+	struct bundle_list global_list;
+
+	/*
+	 * If the creationToken heuristic is used, then the URIs
+	 * advertised by 'list' are not nested lists and instead
+	 * direct bundles. We do not need to use global_list.
+	 */
+	if (list->heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN)
+		return fetch_bundles_by_token(r, list);
+
+	init_bundle_list(&global_list);
+
+	/* If a bundle is added to this global list, then it is required. */
+	global_list.mode = BUNDLE_MODE_ALL;
+
+	if ((result = download_bundle_list(r, list, &global_list, 0)))
+		goto cleanup;
+
+	if (list->heuristic == BUNDLE_HEURISTIC_CREATIONTOKEN)
+		result = fetch_bundles_by_token(r, list);
+	else
+		result = unbundle_all_bundles(r, &global_list);
+
+cleanup:
+	for_all_bundles_in_list(&global_list, unlink_bundle, NULL);
+	clear_bundle_list(&global_list);
+	return result;
+}
+
+/**
+ * API for serve.c.
+ */
+
+int bundle_uri_advertise(struct repository *r, struct strbuf *value UNUSED)
+{
+	static int advertise_bundle_uri = -1;
+
+	if (advertise_bundle_uri != -1)
+		goto cached;
+
+	advertise_bundle_uri = 0;
+	repo_config_get_maybe_bool(r, "uploadpack.advertisebundleuris", &advertise_bundle_uri);
+
+cached:
+	return advertise_bundle_uri;
+}
+
+static int config_to_packet_line(const char *key, const char *value,
+				 const struct config_context *ctx UNUSED,
+				 void *data)
+{
+	struct packet_reader *writer = data;
+
+	if (starts_with(key, "bundle."))
+		packet_write_fmt(writer->fd, "%s=%s", key, value);
+
+	return 0;
+}
+
+int bundle_uri_command(struct repository *r,
+		       struct packet_reader *request)
+{
+	struct packet_writer writer;
+	packet_writer_init(&writer, 1);
+
+	while (packet_reader_read(request) == PACKET_READ_NORMAL)
+		die(_("bundle-uri: unexpected argument: '%s'"), request->line);
+	if (request->status != PACKET_READ_FLUSH)
+		die(_("bundle-uri: expected flush after arguments"));
+
+	/*
+	 * Read all "bundle.*" config lines to the client as key=value
+	 * packet lines.
+	 */
+	repo_config(r, config_to_packet_line, &writer);
+
+	packet_writer_flush(&writer);
+
+	return 0;
+}
+
+/**
+ * General API for {transport,connect}.c etc.
+ */
+int bundle_uri_parse_line(struct bundle_list *list, const char *line)
+{
+	int result;
+	const char *equals;
+	struct strbuf key = STRBUF_INIT;
+
+	if (!strlen(line))
+		return error(_("bundle-uri: got an empty line"));
+
+	equals = strchr(line, '=');
+
+	if (!equals)
+		return error(_("bundle-uri: line is not of the form 'key=value'"));
+	if (line == equals || !*(equals + 1))
+		return error(_("bundle-uri: line has empty key or value"));
+
+	strbuf_add(&key, line, equals - line);
+	result = bundle_list_update(key.buf, equals + 1, list);
+	strbuf_release(&key);
+
+	return result;
+}
diff --git a/bundle-uri.h b/bundle-uri.h
new file mode 100644
index 0000000000..6dbc780f66
--- /dev/null
+++ b/bundle-uri.h
@@ -0,0 +1,168 @@
+#ifndef BUNDLE_URI_H
+#define BUNDLE_URI_H
+
+#include "hashmap.h"
+#include "strbuf.h"
+
+struct packet_reader;
+struct repository;
+struct string_list;
+
+/**
+ * The remote_bundle_info struct contains information for a single bundle
+ * URI. This may be initialized simply by a given URI or might have
+ * additional metadata associated with it if the bundle was advertised by
+ * a bundle list.
+ */
+struct remote_bundle_info {
+	struct hashmap_entry ent;
+
+	/**
+	 * The 'id' is a name given to the bundle for reference
+	 * by other bundle infos.
+	 */
+	char *id;
+
+	/**
+	 * The 'uri' is the location of the remote bundle so
+	 * it can be downloaded on-demand. This will be NULL
+	 * if there was no table of contents.
+	 */
+	char *uri;
+
+	/**
+	 * If the bundle has been downloaded, then 'file' is a
+	 * filename storing its contents. Otherwise, 'file' is
+	 * NULL.
+	 */
+	char *file;
+
+	/**
+	 * If the bundle has been unbundled successfully, then
+	 * this boolean is true.
+	 */
+	unsigned unbundled:1;
+
+	/**
+	 * If the bundle is part of a list with the creationToken
+	 * heuristic, then we use this member for sorting the bundles.
+	 */
+	uint64_t creationToken;
+};
+
+#define REMOTE_BUNDLE_INFO_INIT { 0 }
+
+enum bundle_list_mode {
+	BUNDLE_MODE_NONE = 0,
+	BUNDLE_MODE_ALL,
+	BUNDLE_MODE_ANY
+};
+
+enum bundle_list_heuristic {
+	BUNDLE_HEURISTIC_NONE = 0,
+	BUNDLE_HEURISTIC_CREATIONTOKEN,
+
+	/* Must be last. */
+	BUNDLE_HEURISTIC__COUNT
+};
+
+/**
+ * A bundle_list contains an unordered set of remote_bundle_info structs,
+ * as well as information about the bundle listing, such as version and
+ * mode.
+ */
+struct bundle_list {
+	int version;
+	enum bundle_list_mode mode;
+	struct hashmap bundles;
+
+	/**
+	 * The baseURI of a bundle_list is the URI that provided the list.
+	 *
+	 * In the case of the 'bundle-uri' protocol v2 command, the base
+	 * URI is the URI of the Git remote.
+	 *
+	 * Otherwise, the bundle list was downloaded over HTTP from some
+	 * known URI. 'baseURI' is set to that value.
+	 *
+	 * The baseURI is used as the base for any relative URIs
+	 * advertised by the bundle list at that location.
+	 */
+	char *baseURI;
+
+	/**
+	 * A list can have a heuristic, which helps reduce the number of
+	 * downloaded bundles.
+	 */
+	enum bundle_list_heuristic heuristic;
+};
+
+void init_bundle_list(struct bundle_list *list);
+void clear_bundle_list(struct bundle_list *list);
+
+typedef int (*bundle_iterator)(struct remote_bundle_info *bundle,
+			       void *data);
+
+int for_all_bundles_in_list(struct bundle_list *list,
+			    bundle_iterator iter,
+			    void *data);
+
+struct FILE;
+void print_bundle_list(FILE *fp, struct bundle_list *list);
+
+/**
+ * A bundle URI may point to a bundle list where the key=value
+ * pairs are provided in config file format. This method is
+ * exposed publicly for testing purposes.
+ */
+int bundle_uri_parse_config_format(const char *uri,
+				   const char *filename,
+				   struct bundle_list *list);
+
+/**
+ * Fetch data from the given 'uri' and unbundle the bundle data found
+ * based on that information.
+ *
+ * Returns non-zero if no bundle information is found at the given 'uri'.
+ *
+ * If the pointer 'has_heuristic' is non-NULL, then the value it points to
+ * will be set to be non-zero if and only if the fetched list has a
+ * heuristic value. Such a value indicates that the list was designed for
+ * incremental fetches.
+ */
+int fetch_bundle_uri(struct repository *r, const char *uri,
+		     int *has_heuristic);
+
+/**
+ * Given a bundle list that was already advertised (likely by the
+ * bundle-uri protocol v2 verb) at the given uri, fetch and unbundle the
+ * bundles according to the bundle strategy of that list.
+ *
+ * It is expected that the given 'list' is initialized, including its
+ * 'baseURI' value.
+ *
+ * Returns non-zero if there was an error trying to download the list
+ * or any of its advertised bundles.
+ */
+int fetch_bundle_list(struct repository *r,
+		      struct bundle_list *list);
+
+/**
+ * API for serve.c.
+ */
+int bundle_uri_advertise(struct repository *r, struct strbuf *value);
+int bundle_uri_command(struct repository *r, struct packet_reader *request);
+
+/**
+ * General API for {transport,connect}.c etc.
+ */
+
+/**
+ * Parse a "key=value" packet line from the bundle-uri verb.
+ *
+ * Returns 0 on success and non-zero on error.
+ */
+int bundle_uri_parse_line(struct bundle_list *list,
+			  const char *line);
+
+#endif
diff --git a/bundle.c b/bundle.c
new file mode 100644
index 0000000000..f18f98fec9
--- /dev/null
+++ b/bundle.c
@@ -0,0 +1,632 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "lockfile.h"
+#include "bundle.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "object-store-ll.h"
+#include "repository.h"
+#include "object.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "list-objects.h"
+#include "run-command.h"
+#include "refs.h"
+#include "strvec.h"
+#include "list-objects-filter-options.h"
+#include "connected.h"
+#include "write-or-die.h"
+
+static const char v2_bundle_signature[] = "# v2 git bundle\n";
+static const char v3_bundle_signature[] = "# v3 git bundle\n";
+static struct {
+	int version;
+	const char *signature;
+} bundle_sigs[] = {
+	{ 2, v2_bundle_signature },
+	{ 3, v3_bundle_signature },
+};
+
+void bundle_header_init(struct bundle_header *header)
+{
+	struct bundle_header blank = BUNDLE_HEADER_INIT;
+	memcpy(header, &blank, sizeof(*header));
+}
+
+void bundle_header_release(struct bundle_header *header)
+{
+	string_list_clear(&header->prerequisites, 1);
+	string_list_clear(&header->references, 1);
+	list_objects_filter_release(&header->filter);
+}
+
+static int parse_capability(struct bundle_header *header, const char *capability)
+{
+	const char *arg;
+	if (skip_prefix(capability, "object-format=", &arg)) {
+		int algo = hash_algo_by_name(arg);
+		if (algo == GIT_HASH_UNKNOWN)
+			return error(_("unrecognized bundle hash algorithm: %s"), arg);
+		header->hash_algo = &hash_algos[algo];
+		return 0;
+	}
+	if (skip_prefix(capability, "filter=", &arg)) {
+		parse_list_objects_filter(&header->filter, arg);
+		return 0;
+	}
+	return error(_("unknown capability '%s'"), capability);
+}
+
+static int parse_bundle_signature(struct bundle_header *header, const char *line)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(bundle_sigs); i++) {
+		if (!strcmp(line, bundle_sigs[i].signature)) {
+			header->version = bundle_sigs[i].version;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+int read_bundle_header_fd(int fd, struct bundle_header *header,
+			  const char *report_path)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int status = 0;
+
+	/* The bundle header begins with the signature */
+	if (strbuf_getwholeline_fd(&buf, fd, '\n') ||
+	    parse_bundle_signature(header, buf.buf)) {
+		if (report_path)
+			error(_("'%s' does not look like a v2 or v3 bundle file"),
+			      report_path);
+		status = -1;
+		goto abort;
+	}
+
+	/*
+	 * The default hash format for bundles is SHA1, unless told otherwise
+	 * by an "object-format=" capability, which is being handled in
+	 * `parse_capability()`.
+	 */
+	header->hash_algo = &hash_algos[GIT_HASH_SHA1];
+
+	/* The bundle header ends with an empty line */
+	while (!strbuf_getwholeline_fd(&buf, fd, '\n') &&
+	       buf.len && buf.buf[0] != '\n') {
+		struct object_id oid;
+		int is_prereq = 0;
+		const char *p;
+
+		strbuf_rtrim(&buf);
+
+		if (header->version == 3 && *buf.buf == '@') {
+			if (parse_capability(header, buf.buf + 1)) {
+				status = -1;
+				break;
+			}
+			continue;
+		}
+
+		if (*buf.buf == '-') {
+			is_prereq = 1;
+			strbuf_remove(&buf, 0, 1);
+		}
+
+		/*
+		 * Tip lines have object name, SP, and refname.
+		 * Prerequisites have object name that is optionally
+		 * followed by SP and subject line.
+		 */
+		if (parse_oid_hex_algop(buf.buf, &oid, &p, header->hash_algo) ||
+		    (*p && !isspace(*p)) ||
+		    (!is_prereq && !*p)) {
+			if (report_path)
+				error(_("unrecognized header: %s%s (%d)"),
+				      (is_prereq ? "-" : ""), buf.buf, (int)buf.len);
+			status = -1;
+			break;
+		} else {
+			struct object_id *dup = oiddup(&oid);
+			if (is_prereq)
+				string_list_append(&header->prerequisites, "")->util = dup;
+			else
+				string_list_append(&header->references, p + 1)->util = dup;
+		}
+	}
+
+ abort:
+	if (status) {
+		close(fd);
+		fd = -1;
+	}
+	strbuf_release(&buf);
+	return fd;
+}
+
+int read_bundle_header(const char *path, struct bundle_header *header)
+{
+	int fd = open(path, O_RDONLY);
+
+	if (fd < 0)
+		return error(_("could not open '%s'"), path);
+	return read_bundle_header_fd(fd, header, path);
+}
+
+int is_bundle(const char *path, int quiet)
+{
+	struct bundle_header header = BUNDLE_HEADER_INIT;
+	int fd = open(path, O_RDONLY);
+
+	if (fd < 0)
+		return 0;
+	fd = read_bundle_header_fd(fd, &header, quiet ? NULL : path);
+	if (fd >= 0)
+		close(fd);
+	bundle_header_release(&header);
+	return (fd >= 0);
+}
+
+static int list_refs(struct string_list *r, int argc, const char **argv)
+{
+	int i;
+
+	for (i = 0; i < r->nr; i++) {
+		struct object_id *oid;
+		const char *name;
+
+		if (argc > 1) {
+			int j;
+			for (j = 1; j < argc; j++)
+				if (!strcmp(r->items[i].string, argv[j]))
+					break;
+			if (j == argc)
+				continue;
+		}
+
+		oid = r->items[i].util;
+		name = r->items[i].string;
+		printf("%s %s\n", oid_to_hex(oid), name);
+	}
+	return 0;
+}
+
+/* Remember to update object flag allocation in object.h */
+#define PREREQ_MARK (1u<<16)
+
+struct string_list_iterator {
+	struct string_list *list;
+	size_t cur;
+};
+
+static const struct object_id *iterate_ref_map(void *cb_data)
+{
+	struct string_list_iterator *iter = cb_data;
+
+	if (iter->cur >= iter->list->nr)
+		return NULL;
+
+	return iter->list->items[iter->cur++].util;
+}
+
+int verify_bundle(struct repository *r,
+		  struct bundle_header *header,
+		  enum verify_bundle_flags flags)
+{
+	/*
+	 * Do fast check, then if any prereqs are missing then go line by line
+	 * to be verbose about the errors
+	 */
+	struct string_list *p = &header->prerequisites;
+	int i, ret = 0;
+	const char *message = _("Repository lacks these prerequisite commits:");
+	struct string_list_iterator iter = {
+		.list = p,
+	};
+	struct check_connected_options opts = {
+		.quiet = 1,
+	};
+
+	if (!r || !r->objects || !r->objects->odb)
+		return error(_("need a repository to verify a bundle"));
+
+	for (i = 0; i < p->nr; i++) {
+		struct string_list_item *e = p->items + i;
+		const char *name = e->string;
+		struct object_id *oid = e->util;
+		struct object *o = parse_object(r, oid);
+		if (o)
+			continue;
+		ret++;
+		if (flags & VERIFY_BUNDLE_QUIET)
+			continue;
+		if (ret == 1)
+			error("%s", message);
+		error("%s %s", oid_to_hex(oid), name);
+	}
+	if (ret)
+		goto cleanup;
+
+	if ((ret = check_connected(iterate_ref_map, &iter, &opts)))
+		error(_("some prerequisite commits exist in the object store, "
+			"but are not connected to the repository's history"));
+
+	/* TODO: preserve this verbose language. */
+	if (flags & VERIFY_BUNDLE_VERBOSE) {
+		struct string_list *r;
+
+		r = &header->references;
+		printf_ln(Q_("The bundle contains this ref:",
+			     "The bundle contains these %"PRIuMAX" refs:",
+			     r->nr),
+			  (uintmax_t)r->nr);
+		list_refs(r, 0, NULL);
+
+		r = &header->prerequisites;
+		if (!r->nr) {
+			printf_ln(_("The bundle records a complete history."));
+		} else {
+			printf_ln(Q_("The bundle requires this ref:",
+				     "The bundle requires these %"PRIuMAX" refs:",
+				     r->nr),
+				  (uintmax_t)r->nr);
+			list_refs(r, 0, NULL);
+		}
+
+		printf_ln(_("The bundle uses this hash algorithm: %s"),
+			  header->hash_algo->name);
+		if (header->filter.choice)
+			printf_ln(_("The bundle uses this filter: %s"),
+				  list_objects_filter_spec(&header->filter));
+	}
+cleanup:
+	return ret;
+}
+
+int list_bundle_refs(struct bundle_header *header, int argc, const char **argv)
+{
+	return list_refs(&header->references, argc, argv);
+}
+
+static int is_tag_in_date_range(struct object *tag, struct rev_info *revs)
+{
+	unsigned long size;
+	enum object_type type;
+	char *buf = NULL, *line, *lineend;
+	timestamp_t date;
+	int result = 1;
+
+	if (revs->max_age == -1 && revs->min_age == -1)
+		goto out;
+
+	buf = repo_read_object_file(the_repository, &tag->oid, &type, &size);
+	if (!buf)
+		goto out;
+	line = memmem(buf, size, "\ntagger ", 8);
+	if (!line++)
+		goto out;
+	lineend = memchr(line, '\n', buf + size - line);
+	line = memchr(line, '>', lineend ? lineend - line : buf + size - line);
+	if (!line++)
+		goto out;
+	date = parse_timestamp(line, NULL, 10);
+	result = (revs->max_age == -1 || revs->max_age < date) &&
+		(revs->min_age == -1 || revs->min_age > date);
+out:
+	free(buf);
+	return result;
+}
+
+
+/* Write the pack data to bundle_fd */
+static int write_pack_data(int bundle_fd, struct rev_info *revs, struct strvec *pack_options)
+{
+	struct child_process pack_objects = CHILD_PROCESS_INIT;
+	int i;
+
+	strvec_pushl(&pack_objects.args,
+		     "pack-objects",
+		     "--stdout", "--thin", "--delta-base-offset",
+		     NULL);
+	strvec_pushv(&pack_objects.args, pack_options->v);
+	if (revs->filter.choice)
+		strvec_pushf(&pack_objects.args, "--filter=%s",
+			     list_objects_filter_spec(&revs->filter));
+	pack_objects.in = -1;
+	pack_objects.out = bundle_fd;
+	pack_objects.git_cmd = 1;
+
+	/*
+	 * start_command() will close our descriptor if it's >1. Duplicate it
+	 * to avoid surprising the caller.
+	 */
+	if (pack_objects.out > 1) {
+		pack_objects.out = dup(pack_objects.out);
+		if (pack_objects.out < 0) {
+			error_errno(_("unable to dup bundle descriptor"));
+			child_process_clear(&pack_objects);
+			return -1;
+		}
+	}
+
+	if (start_command(&pack_objects))
+		return error(_("Could not spawn pack-objects"));
+
+	for (i = 0; i < revs->pending.nr; i++) {
+		struct object *object = revs->pending.objects[i].item;
+		if (object->flags & UNINTERESTING)
+			write_or_die(pack_objects.in, "^", 1);
+		write_or_die(pack_objects.in, oid_to_hex(&object->oid), the_hash_algo->hexsz);
+		write_or_die(pack_objects.in, "\n", 1);
+	}
+	close(pack_objects.in);
+	if (finish_command(&pack_objects))
+		return error(_("pack-objects died"));
+	return 0;
+}
+
+/*
+ * Write out bundle refs based on the tips already
+ * parsed into revs.pending. As a side effect, may
+ * manipulate revs.pending to include additional
+ * necessary objects (like tags).
+ *
+ * Returns the number of refs written, or negative
+ * on error.
+ */
+static int write_bundle_refs(int bundle_fd, struct rev_info *revs)
+{
+	int i;
+	int ref_count = 0;
+
+	for (i = 0; i < revs->pending.nr; i++) {
+		struct object_array_entry *e = revs->pending.objects + i;
+		struct object_id oid;
+		char *ref;
+		const char *display_ref;
+		int flag;
+
+		if (e->item->flags & UNINTERESTING)
+			continue;
+		if (repo_dwim_ref(the_repository, e->name, strlen(e->name),
+				  &oid, &ref, 0) != 1)
+			goto skip_write_ref;
+		if (refs_read_ref_full(get_main_ref_store(the_repository), e->name, RESOLVE_REF_READING, &oid, &flag))
+			flag = 0;
+		display_ref = (flag & REF_ISSYMREF) ? e->name : ref;
+
+		if (e->item->type == OBJ_TAG &&
+				!is_tag_in_date_range(e->item, revs)) {
+			e->item->flags |= UNINTERESTING;
+			goto skip_write_ref;
+		}
+
+		/*
+		 * Make sure the refs we wrote out is correct; --max-count and
+		 * other limiting options could have prevented all the tips
+		 * from getting output.
+		 *
+		 * Non commit objects such as tags and blobs do not have
+		 * this issue as they are not affected by those extra
+		 * constraints.
+		 */
+		if (!(e->item->flags & SHOWN) && e->item->type == OBJ_COMMIT) {
+			warning(_("ref '%s' is excluded by the rev-list options"),
+				e->name);
+			goto skip_write_ref;
+		}
+
+		ref_count++;
+		write_or_die(bundle_fd, oid_to_hex(&e->item->oid), the_hash_algo->hexsz);
+		write_or_die(bundle_fd, " ", 1);
+		write_or_die(bundle_fd, display_ref, strlen(display_ref));
+		write_or_die(bundle_fd, "\n", 1);
+ skip_write_ref:
+		free(ref);
+	}
+
+	/* end header */
+	write_or_die(bundle_fd, "\n", 1);
+	return ref_count;
+}
+
+struct bundle_prerequisites_info {
+	struct object_array *pending;
+	int fd;
+};
+
+static void write_bundle_prerequisites(struct commit *commit, void *data)
+{
+	struct bundle_prerequisites_info *bpi = data;
+	struct object *object;
+	struct pretty_print_context ctx = { 0 };
+	struct strbuf buf = STRBUF_INIT;
+
+	if (!(commit->object.flags & BOUNDARY))
+		return;
+	strbuf_addf(&buf, "-%s ", oid_to_hex(&commit->object.oid));
+	write_or_die(bpi->fd, buf.buf, buf.len);
+
+	ctx.fmt = CMIT_FMT_ONELINE;
+	ctx.output_encoding = get_log_output_encoding();
+	strbuf_reset(&buf);
+	pretty_print_commit(&ctx, commit, &buf);
+	strbuf_trim(&buf);
+
+	object = (struct object *)commit;
+	object->flags |= UNINTERESTING;
+	add_object_array_with_path(object, buf.buf, bpi->pending, S_IFINVALID,
+				   NULL);
+	strbuf_addch(&buf, '\n');
+	write_or_die(bpi->fd, buf.buf, buf.len);
+	strbuf_release(&buf);
+}
+
+int create_bundle(struct repository *r, const char *path,
+		  int argc, const char **argv, struct strvec *pack_options, int version)
+{
+	struct lock_file lock = LOCK_INIT;
+	int bundle_fd = -1;
+	int bundle_to_stdout;
+	int ref_count = 0;
+	struct rev_info revs, revs_copy;
+	int min_version = 2;
+	struct bundle_prerequisites_info bpi;
+	int ret;
+	int i;
+
+	/* init revs to list objects for pack-objects later */
+	save_commit_buffer = 0;
+	repo_init_revisions(r, &revs, NULL);
+
+	/*
+	 * Pre-initialize the '--objects' flag so we can parse a
+	 * --filter option successfully.
+	 */
+	revs.tree_objects = revs.blob_objects = 1;
+
+	argc = setup_revisions(argc, argv, &revs, NULL);
+
+	/*
+	 * Reasons to require version 3:
+	 *
+	 * 1. @object-format is required because our hash algorithm is not
+	 *    SHA1.
+	 * 2. @filter is required because we parsed an object filter.
+	 */
+	if (the_hash_algo != &hash_algos[GIT_HASH_SHA1] || revs.filter.choice)
+		min_version = 3;
+
+	if (argc > 1) {
+		ret = error(_("unrecognized argument: %s"), argv[1]);
+		goto out;
+	}
+
+	bundle_to_stdout = !strcmp(path, "-");
+	if (bundle_to_stdout)
+		bundle_fd = 1;
+	else
+		bundle_fd = hold_lock_file_for_update(&lock, path,
+						      LOCK_DIE_ON_ERROR);
+
+	if (version == -1)
+		version = min_version;
+
+	if (version < 2 || version > 3) {
+		die(_("unsupported bundle version %d"), version);
+	} else if (version < min_version) {
+		die(_("cannot write bundle version %d with algorithm %s"), version, the_hash_algo->name);
+	} else if (version == 2) {
+		write_or_die(bundle_fd, v2_bundle_signature, strlen(v2_bundle_signature));
+	} else {
+		const char *capability = "@object-format=";
+		write_or_die(bundle_fd, v3_bundle_signature, strlen(v3_bundle_signature));
+		write_or_die(bundle_fd, capability, strlen(capability));
+		write_or_die(bundle_fd, the_hash_algo->name, strlen(the_hash_algo->name));
+		write_or_die(bundle_fd, "\n", 1);
+
+		if (revs.filter.choice) {
+			const char *value = expand_list_objects_filter_spec(&revs.filter);
+			capability = "@filter=";
+			write_or_die(bundle_fd, capability, strlen(capability));
+			write_or_die(bundle_fd, value, strlen(value));
+			write_or_die(bundle_fd, "\n", 1);
+		}
+	}
+
+	/* save revs.pending in revs_copy for later use */
+	memcpy(&revs_copy, &revs, sizeof(revs));
+	revs_copy.pending.nr = 0;
+	revs_copy.pending.alloc = 0;
+	revs_copy.pending.objects = NULL;
+	for (i = 0; i < revs.pending.nr; i++) {
+		struct object_array_entry *e = revs.pending.objects + i;
+		if (e)
+			add_object_array_with_path(e->item, e->name,
+						   &revs_copy.pending,
+						   e->mode, e->path);
+	}
+
+	/* write prerequisites */
+	revs.boundary = 1;
+	if (prepare_revision_walk(&revs))
+		die("revision walk setup failed");
+	bpi.fd = bundle_fd;
+	bpi.pending = &revs_copy.pending;
+
+	/*
+	 * Remove any object walking here. We only care about commits and
+	 * tags here. The revs_copy has the right instances of these values.
+	 */
+	revs.blob_objects = revs.tree_objects = 0;
+	traverse_commit_list(&revs, write_bundle_prerequisites, NULL, &bpi);
+	object_array_remove_duplicates(&revs_copy.pending);
+
+	/* write bundle refs */
+	ref_count = write_bundle_refs(bundle_fd, &revs_copy);
+	if (!ref_count) {
+		die(_("Refusing to create empty bundle."));
+	} else if (ref_count < 0) {
+		ret = -1;
+		goto out;
+	}
+
+	/* write pack */
+	if (write_pack_data(bundle_fd, &revs_copy, pack_options)) {
+		ret = -1;
+		goto out;
+	}
+
+	if (!bundle_to_stdout) {
+		if (commit_lock_file(&lock))
+			die_errno(_("cannot create '%s'"), path);
+	}
+
+	ret = 0;
+
+out:
+	object_array_clear(&revs_copy.pending);
+	release_revisions(&revs);
+	rollback_lock_file(&lock);
+	return ret;
+}
+
+int unbundle(struct repository *r, struct bundle_header *header,
+	     int bundle_fd, struct strvec *extra_index_pack_args,
+	     struct unbundle_opts *opts)
+{
+	struct child_process ip = CHILD_PROCESS_INIT;
+	struct unbundle_opts opts_fallback = { 0 };
+
+	if (!opts)
+		opts = &opts_fallback;
+
+	if (verify_bundle(r, header, opts->flags))
+		return -1;
+
+	strvec_pushl(&ip.args, "index-pack", "--fix-thin", "--stdin", NULL);
+
+	/* If there is a filter, then we need to create the promisor pack. */
+	if (header->filter.choice)
+		strvec_push(&ip.args, "--promisor=from-bundle");
+
+	if (opts->flags & VERIFY_BUNDLE_FSCK)
+		strvec_pushf(&ip.args, "--fsck-objects%s",
+			     opts->fsck_msg_types ? opts->fsck_msg_types : "");
+
+	if (extra_index_pack_args)
+		strvec_pushv(&ip.args, extra_index_pack_args->v);
+
+	ip.in = bundle_fd;
+	ip.no_stdout = 1;
+	ip.git_cmd = 1;
+	if (run_command(&ip))
+		return error(_("index-pack died"));
+	return 0;
+}
diff --git a/bundle.h b/bundle.h
new file mode 100644
index 0000000000..a80aa8ad9b
--- /dev/null
+++ b/bundle.h
@@ -0,0 +1,72 @@
+#ifndef BUNDLE_H
+#define BUNDLE_H
+
+#include "strvec.h"
+#include "string-list.h"
+#include "list-objects-filter-options.h"
+
+struct bundle_header {
+	unsigned version;
+	struct string_list prerequisites;
+	struct string_list references;
+	const struct git_hash_algo *hash_algo;
+	struct list_objects_filter_options filter;
+};
+
+#define BUNDLE_HEADER_INIT \
+{ \
+	.prerequisites = STRING_LIST_INIT_DUP, \
+	.references = STRING_LIST_INIT_DUP, \
+	.filter = LIST_OBJECTS_FILTER_INIT, \
+}
+void bundle_header_init(struct bundle_header *header);
+void bundle_header_release(struct bundle_header *header);
+
+int is_bundle(const char *path, int quiet);
+int read_bundle_header(const char *path, struct bundle_header *header);
+int read_bundle_header_fd(int fd, struct bundle_header *header,
+			  const char *report_path);
+int create_bundle(struct repository *r, const char *path,
+		  int argc, const char **argv, struct strvec *pack_options,
+		  int version);
+
+enum verify_bundle_flags {
+	VERIFY_BUNDLE_VERBOSE = (1 << 0),
+	VERIFY_BUNDLE_QUIET = (1 << 1),
+	VERIFY_BUNDLE_FSCK = (1 << 2),
+};
+
+int verify_bundle(struct repository *r, struct bundle_header *header,
+		  enum verify_bundle_flags flags);
+
+struct unbundle_opts {
+	enum verify_bundle_flags flags;
+	/*
+	 * fsck_msg_types may optionally contain fsck message severity
+	 * configuration. If present, this configuration gets directly appended
+	 * to a '--fsck-objects' option and therefore must be prefixed with '='.
+	 * (E.g. "=missingEmail=ignore,gitmodulesUrl=ignore")
+	 */
+	const char *fsck_msg_types;
+};
+
+/**
+ * Unbundle after reading the header with read_bundle_header().
+ *
+ * We'll invoke "git index-pack --stdin --fix-thin" for you on the
+ * provided `bundle_fd` from read_bundle_header().
+ *
+ * Provide "extra_index_pack_args" to pass any extra arguments
+ * (e.g. "-v" for verbose/progress), NULL otherwise. The provided
+ * "extra_index_pack_args" (if any) will be strvec_clear()'d for you.
+ *
+ * Before unbundling, this method will call verify_bundle() with 'flags'
+ * provided in 'opts'.
+ */
+int unbundle(struct repository *r, struct bundle_header *header,
+	     int bundle_fd, struct strvec *extra_index_pack_args,
+	     struct unbundle_opts *opts);
+int list_bundle_refs(struct bundle_header *header,
+		int argc, const char **argv);
+
+#endif
diff --git a/cache-tree.c b/cache-tree.c
new file mode 100644
index 0000000000..bcbcad3d61
--- /dev/null
+++ b/cache-tree.c
@@ -0,0 +1,1028 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "gettext.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "tree.h"
+#include "tree-walk.h"
+#include "cache-tree.h"
+#include "bulk-checkin.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "read-cache-ll.h"
+#include "replace-object.h"
+#include "repository.h"
+#include "promisor-remote.h"
+#include "trace.h"
+#include "trace2.h"
+
+#ifndef DEBUG_CACHE_TREE
+#define DEBUG_CACHE_TREE 0
+#endif
+
+struct cache_tree *cache_tree(void)
+{
+	struct cache_tree *it = xcalloc(1, sizeof(struct cache_tree));
+	it->entry_count = -1;
+	return it;
+}
+
+void cache_tree_free(struct cache_tree **it_p)
+{
+	int i;
+	struct cache_tree *it = *it_p;
+
+	if (!it)
+		return;
+	for (i = 0; i < it->subtree_nr; i++)
+		if (it->down[i]) {
+			cache_tree_free(&it->down[i]->cache_tree);
+			free(it->down[i]);
+		}
+	free(it->down);
+	free(it);
+	*it_p = NULL;
+}
+
+static int subtree_name_cmp(const char *one, int onelen,
+			    const char *two, int twolen)
+{
+	if (onelen < twolen)
+		return -1;
+	if (twolen < onelen)
+		return 1;
+	return memcmp(one, two, onelen);
+}
+
+int cache_tree_subtree_pos(struct cache_tree *it, const char *path, int pathlen)
+{
+	struct cache_tree_sub **down = it->down;
+	int lo, hi;
+	lo = 0;
+	hi = it->subtree_nr;
+	while (lo < hi) {
+		int mi = lo + (hi - lo) / 2;
+		struct cache_tree_sub *mdl = down[mi];
+		int cmp = subtree_name_cmp(path, pathlen,
+					   mdl->name, mdl->namelen);
+		if (!cmp)
+			return mi;
+		if (cmp < 0)
+			hi = mi;
+		else
+			lo = mi + 1;
+	}
+	return -lo-1;
+}
+
+static struct cache_tree_sub *find_subtree(struct cache_tree *it,
+					   const char *path,
+					   int pathlen,
+					   int create)
+{
+	struct cache_tree_sub *down;
+	int pos = cache_tree_subtree_pos(it, path, pathlen);
+	if (0 <= pos)
+		return it->down[pos];
+	if (!create)
+		return NULL;
+
+	pos = -pos-1;
+	ALLOC_GROW(it->down, it->subtree_nr + 1, it->subtree_alloc);
+	it->subtree_nr++;
+
+	FLEX_ALLOC_MEM(down, name, path, pathlen);
+	down->cache_tree = NULL;
+	down->namelen = pathlen;
+
+	if (pos < it->subtree_nr)
+		MOVE_ARRAY(it->down + pos + 1, it->down + pos,
+			   it->subtree_nr - pos - 1);
+	it->down[pos] = down;
+	return down;
+}
+
+struct cache_tree_sub *cache_tree_sub(struct cache_tree *it, const char *path)
+{
+	int pathlen = strlen(path);
+	return find_subtree(it, path, pathlen, 1);
+}
+
+static int do_invalidate_path(struct cache_tree *it, const char *path)
+{
+	/* a/b/c
+	 * ==> invalidate self
+	 * ==> find "a", have it invalidate "b/c"
+	 * a
+	 * ==> invalidate self
+	 * ==> if "a" exists as a subtree, remove it.
+	 */
+	const char *slash;
+	int namelen;
+	struct cache_tree_sub *down;
+
+#if DEBUG_CACHE_TREE
+	fprintf(stderr, "cache-tree invalidate <%s>\n", path);
+#endif
+
+	if (!it)
+		return 0;
+	slash = strchrnul(path, '/');
+	namelen = slash - path;
+	it->entry_count = -1;
+	if (!*slash) {
+		int pos;
+		pos = cache_tree_subtree_pos(it, path, namelen);
+		if (0 <= pos) {
+			cache_tree_free(&it->down[pos]->cache_tree);
+			free(it->down[pos]);
+			/* 0 1 2 3 4 5
+			 *       ^     ^subtree_nr = 6
+			 *       pos
+			 * move 4 and 5 up one place (2 entries)
+			 * 2 = 6 - 3 - 1 = subtree_nr - pos - 1
+			 */
+			MOVE_ARRAY(it->down + pos, it->down + pos + 1,
+				   it->subtree_nr - pos - 1);
+			it->subtree_nr--;
+		}
+		return 1;
+	}
+	down = find_subtree(it, path, namelen, 0);
+	if (down)
+		do_invalidate_path(down->cache_tree, slash + 1);
+	return 1;
+}
+
+void cache_tree_invalidate_path(struct index_state *istate, const char *path)
+{
+	if (do_invalidate_path(istate->cache_tree, path))
+		istate->cache_changed |= CACHE_TREE_CHANGED;
+}
+
+static int verify_cache(struct index_state *istate, int flags)
+{
+	unsigned i, funny;
+	int silent = flags & WRITE_TREE_SILENT;
+
+	/* Verify that the tree is merged */
+	funny = 0;
+	for (i = 0; i < istate->cache_nr; i++) {
+		const struct cache_entry *ce = istate->cache[i];
+		if (ce_stage(ce)) {
+			if (silent)
+				return -1;
+			if (10 < ++funny) {
+				fprintf(stderr, "...\n");
+				break;
+			}
+			fprintf(stderr, "%s: unmerged (%s)\n",
+				ce->name, oid_to_hex(&ce->oid));
+		}
+	}
+	if (funny)
+		return -1;
+
+	/* Also verify that the cache does not have path and path/file
+	 * at the same time.  At this point we know the cache has only
+	 * stage 0 entries.
+	 */
+	funny = 0;
+	for (i = 0; i + 1 < istate->cache_nr; i++) {
+		/* path/file always comes after path because of the way
+		 * the cache is sorted.  Also path can appear only once,
+		 * which means conflicting one would immediately follow.
+		 */
+		const struct cache_entry *this_ce = istate->cache[i];
+		const struct cache_entry *next_ce = istate->cache[i + 1];
+		const char *this_name = this_ce->name;
+		const char *next_name = next_ce->name;
+		int this_len = ce_namelen(this_ce);
+		if (this_len < ce_namelen(next_ce) &&
+		    next_name[this_len] == '/' &&
+		    strncmp(this_name, next_name, this_len) == 0) {
+			if (10 < ++funny) {
+				fprintf(stderr, "...\n");
+				break;
+			}
+			fprintf(stderr, "You have both %s and %s\n",
+				this_name, next_name);
+		}
+	}
+	if (funny)
+		return -1;
+	return 0;
+}
+
+static void discard_unused_subtrees(struct cache_tree *it)
+{
+	struct cache_tree_sub **down = it->down;
+	int nr = it->subtree_nr;
+	int dst, src;
+	for (dst = src = 0; src < nr; src++) {
+		struct cache_tree_sub *s = down[src];
+		if (s->used)
+			down[dst++] = s;
+		else {
+			cache_tree_free(&s->cache_tree);
+			free(s);
+			it->subtree_nr--;
+		}
+	}
+}
+
+int cache_tree_fully_valid(struct cache_tree *it)
+{
+	int i;
+	if (!it)
+		return 0;
+	if (it->entry_count < 0 || !repo_has_object_file(the_repository, &it->oid))
+		return 0;
+	for (i = 0; i < it->subtree_nr; i++) {
+		if (!cache_tree_fully_valid(it->down[i]->cache_tree))
+			return 0;
+	}
+	return 1;
+}
+
+static int must_check_existence(const struct cache_entry *ce)
+{
+	return !(repo_has_promisor_remote(the_repository) && ce_skip_worktree(ce));
+}
+
+static int update_one(struct cache_tree *it,
+		      struct cache_entry **cache,
+		      int entries,
+		      const char *base,
+		      int baselen,
+		      int *skip_count,
+		      int flags)
+{
+	struct strbuf buffer;
+	int missing_ok = flags & WRITE_TREE_MISSING_OK;
+	int dryrun = flags & WRITE_TREE_DRY_RUN;
+	int repair = flags & WRITE_TREE_REPAIR;
+	int to_invalidate = 0;
+	int i;
+
+	assert(!(dryrun && repair));
+
+	*skip_count = 0;
+
+	/*
+	 * If the first entry of this region is a sparse directory
+	 * entry corresponding exactly to 'base', then this cache_tree
+	 * struct is a "leaf" in the data structure, pointing to the
+	 * tree OID specified in the entry.
+	 */
+	if (entries > 0) {
+		const struct cache_entry *ce = cache[0];
+
+		if (S_ISSPARSEDIR(ce->ce_mode) &&
+		    ce->ce_namelen == baselen &&
+		    !strncmp(ce->name, base, baselen)) {
+			it->entry_count = 1;
+			oidcpy(&it->oid, &ce->oid);
+			return 1;
+		}
+	}
+
+	if (0 <= it->entry_count && repo_has_object_file(the_repository, &it->oid))
+		return it->entry_count;
+
+	/*
+	 * We first scan for subtrees and update them; we start by
+	 * marking existing subtrees -- the ones that are unmarked
+	 * should not be in the result.
+	 */
+	for (i = 0; i < it->subtree_nr; i++)
+		it->down[i]->used = 0;
+
+	/*
+	 * Find the subtrees and update them.
+	 */
+	i = 0;
+	while (i < entries) {
+		const struct cache_entry *ce = cache[i];
+		struct cache_tree_sub *sub;
+		const char *path, *slash;
+		int pathlen, sublen, subcnt, subskip;
+
+		path = ce->name;
+		pathlen = ce_namelen(ce);
+		if (pathlen <= baselen || memcmp(base, path, baselen))
+			break; /* at the end of this level */
+
+		slash = strchr(path + baselen, '/');
+		if (!slash) {
+			i++;
+			continue;
+		}
+		/*
+		 * a/bbb/c (base = a/, slash = /c)
+		 * ==>
+		 * path+baselen = bbb/c, sublen = 3
+		 */
+		sublen = slash - (path + baselen);
+		sub = find_subtree(it, path + baselen, sublen, 1);
+		if (!sub->cache_tree)
+			sub->cache_tree = cache_tree();
+		subcnt = update_one(sub->cache_tree,
+				    cache + i, entries - i,
+				    path,
+				    baselen + sublen + 1,
+				    &subskip,
+				    flags);
+		if (subcnt < 0)
+			return subcnt;
+		if (!subcnt)
+			die("index cache-tree records empty sub-tree");
+		i += subcnt;
+		sub->count = subcnt; /* to be used in the next loop */
+		*skip_count += subskip;
+		sub->used = 1;
+	}
+
+	discard_unused_subtrees(it);
+
+	/*
+	 * Then write out the tree object for this level.
+	 */
+	strbuf_init(&buffer, 8192);
+
+	i = 0;
+	while (i < entries) {
+		const struct cache_entry *ce = cache[i];
+		struct cache_tree_sub *sub = NULL;
+		const char *path, *slash;
+		int pathlen, entlen;
+		const struct object_id *oid;
+		unsigned mode;
+		int expected_missing = 0;
+		int contains_ita = 0;
+		int ce_missing_ok;
+
+		path = ce->name;
+		pathlen = ce_namelen(ce);
+		if (pathlen <= baselen || memcmp(base, path, baselen))
+			break; /* at the end of this level */
+
+		slash = strchr(path + baselen, '/');
+		if (slash) {
+			entlen = slash - (path + baselen);
+			sub = find_subtree(it, path + baselen, entlen, 0);
+			if (!sub)
+				die("cache-tree.c: '%.*s' in '%s' not found",
+				    entlen, path + baselen, path);
+			i += sub->count;
+			oid = &sub->cache_tree->oid;
+			mode = S_IFDIR;
+			contains_ita = sub->cache_tree->entry_count < 0;
+			if (contains_ita) {
+				to_invalidate = 1;
+				expected_missing = 1;
+			}
+		}
+		else {
+			oid = &ce->oid;
+			mode = ce->ce_mode;
+			entlen = pathlen - baselen;
+			i++;
+		}
+
+		ce_missing_ok = mode == S_IFGITLINK || missing_ok ||
+			!must_check_existence(ce);
+		if (is_null_oid(oid) ||
+		    (!ce_missing_ok && !repo_has_object_file(the_repository, oid))) {
+			strbuf_release(&buffer);
+			if (expected_missing)
+				return -1;
+			return error("invalid object %06o %s for '%.*s'",
+				mode, oid_to_hex(oid), entlen+baselen, path);
+		}
+
+		/*
+		 * CE_REMOVE entries are removed before the index is
+		 * written to disk. Skip them to remain consistent
+		 * with the future on-disk index.
+		 */
+		if (ce->ce_flags & CE_REMOVE) {
+			*skip_count = *skip_count + 1;
+			continue;
+		}
+
+		/*
+		 * CE_INTENT_TO_ADD entries exist in on-disk index but
+		 * they are not part of generated trees. Invalidate up
+		 * to root to force cache-tree users to read elsewhere.
+		 */
+		if (!sub && ce_intent_to_add(ce)) {
+			to_invalidate = 1;
+			continue;
+		}
+
+		/*
+		 * "sub" can be an empty tree if all subentries are i-t-a.
+		 */
+		if (contains_ita && is_empty_tree_oid(oid, the_repository->hash_algo))
+			continue;
+
+		strbuf_grow(&buffer, entlen + 100);
+		strbuf_addf(&buffer, "%o %.*s%c", mode, entlen, path + baselen, '\0');
+		strbuf_add(&buffer, oid->hash, the_hash_algo->rawsz);
+
+#if DEBUG_CACHE_TREE
+		fprintf(stderr, "cache-tree update-one %o %.*s\n",
+			mode, entlen, path + baselen);
+#endif
+	}
+
+	if (repair) {
+		struct object_id oid;
+		hash_object_file(the_hash_algo, buffer.buf, buffer.len,
+				 OBJ_TREE, &oid);
+		if (repo_has_object_file_with_flags(the_repository, &oid, OBJECT_INFO_SKIP_FETCH_OBJECT))
+			oidcpy(&it->oid, &oid);
+		else
+			to_invalidate = 1;
+	} else if (dryrun) {
+		hash_object_file(the_hash_algo, buffer.buf, buffer.len,
+				 OBJ_TREE, &it->oid);
+	} else if (write_object_file_flags(buffer.buf, buffer.len, OBJ_TREE,
+					   &it->oid, NULL, flags & WRITE_TREE_SILENT
+					   ? HASH_SILENT : 0)) {
+		strbuf_release(&buffer);
+		return -1;
+	}
+
+	strbuf_release(&buffer);
+	it->entry_count = to_invalidate ? -1 : i - *skip_count;
+#if DEBUG_CACHE_TREE
+	fprintf(stderr, "cache-tree update-one (%d ent, %d subtree) %s\n",
+		it->entry_count, it->subtree_nr,
+		oid_to_hex(&it->oid));
+#endif
+	return i;
+}
+
+int cache_tree_update(struct index_state *istate, int flags)
+{
+	int skip, i;
+
+	i = verify_cache(istate, flags);
+
+	if (i)
+		return i;
+
+	if (!istate->cache_tree)
+		istate->cache_tree = cache_tree();
+
+	if (!(flags & WRITE_TREE_MISSING_OK) && repo_has_promisor_remote(the_repository))
+		prefetch_cache_entries(istate, must_check_existence);
+
+	trace_performance_enter();
+	trace2_region_enter("cache_tree", "update", the_repository);
+	begin_odb_transaction();
+	i = update_one(istate->cache_tree, istate->cache, istate->cache_nr,
+		       "", 0, &skip, flags);
+	end_odb_transaction();
+	trace2_region_leave("cache_tree", "update", the_repository);
+	trace_performance_leave("cache_tree_update");
+	if (i < 0)
+		return i;
+	istate->cache_changed |= CACHE_TREE_CHANGED;
+	return 0;
+}
+
+static void write_one(struct strbuf *buffer, struct cache_tree *it,
+		      const char *path, int pathlen)
+{
+	int i;
+
+	/* One "cache-tree" entry consists of the following:
+	 * path (NUL terminated)
+	 * entry_count, subtree_nr ("%d %d\n")
+	 * tree-sha1 (missing if invalid)
+	 * subtree_nr "cache-tree" entries for subtrees.
+	 */
+	strbuf_grow(buffer, pathlen + 100);
+	strbuf_add(buffer, path, pathlen);
+	strbuf_addf(buffer, "%c%d %d\n", 0, it->entry_count, it->subtree_nr);
+
+#if DEBUG_CACHE_TREE
+	if (0 <= it->entry_count)
+		fprintf(stderr, "cache-tree <%.*s> (%d ent, %d subtree) %s\n",
+			pathlen, path, it->entry_count, it->subtree_nr,
+			oid_to_hex(&it->oid));
+	else
+		fprintf(stderr, "cache-tree <%.*s> (%d subtree) invalid\n",
+			pathlen, path, it->subtree_nr);
+#endif
+
+	if (0 <= it->entry_count) {
+		strbuf_add(buffer, it->oid.hash, the_hash_algo->rawsz);
+	}
+	for (i = 0; i < it->subtree_nr; i++) {
+		struct cache_tree_sub *down = it->down[i];
+		if (i) {
+			struct cache_tree_sub *prev = it->down[i-1];
+			if (subtree_name_cmp(down->name, down->namelen,
+					     prev->name, prev->namelen) <= 0)
+				die("fatal - unsorted cache subtree");
+		}
+		write_one(buffer, down->cache_tree, down->name, down->namelen);
+	}
+}
+
+void cache_tree_write(struct strbuf *sb, struct cache_tree *root)
+{
+	trace2_region_enter("cache_tree", "write", the_repository);
+	write_one(sb, root, "", 0);
+	trace2_region_leave("cache_tree", "write", the_repository);
+}
+
+static struct cache_tree *read_one(const char **buffer, unsigned long *size_p)
+{
+	const char *buf = *buffer;
+	unsigned long size = *size_p;
+	const char *cp;
+	char *ep;
+	struct cache_tree *it;
+	int i, subtree_nr;
+	const unsigned rawsz = the_hash_algo->rawsz;
+
+	it = NULL;
+	/* skip name, but make sure name exists */
+	while (size && *buf) {
+		size--;
+		buf++;
+	}
+	if (!size)
+		goto free_return;
+	buf++; size--;
+	it = cache_tree();
+
+	cp = buf;
+	it->entry_count = strtol(cp, &ep, 10);
+	if (cp == ep)
+		goto free_return;
+	cp = ep;
+	subtree_nr = strtol(cp, &ep, 10);
+	if (cp == ep)
+		goto free_return;
+	while (size && *buf && *buf != '\n') {
+		size--;
+		buf++;
+	}
+	if (!size)
+		goto free_return;
+	buf++; size--;
+	if (0 <= it->entry_count) {
+		if (size < rawsz)
+			goto free_return;
+		oidread(&it->oid, (const unsigned char *)buf,
+			the_repository->hash_algo);
+		buf += rawsz;
+		size -= rawsz;
+	}
+
+#if DEBUG_CACHE_TREE
+	if (0 <= it->entry_count)
+		fprintf(stderr, "cache-tree <%s> (%d ent, %d subtree) %s\n",
+			*buffer, it->entry_count, subtree_nr,
+			oid_to_hex(&it->oid));
+	else
+		fprintf(stderr, "cache-tree <%s> (%d subtrees) invalid\n",
+			*buffer, subtree_nr);
+#endif
+
+	/*
+	 * Just a heuristic -- we do not add directories that often but
+	 * we do not want to have to extend it immediately when we do,
+	 * hence +2.
+	 */
+	it->subtree_alloc = subtree_nr + 2;
+	CALLOC_ARRAY(it->down, it->subtree_alloc);
+	for (i = 0; i < subtree_nr; i++) {
+		/* read each subtree */
+		struct cache_tree *sub;
+		struct cache_tree_sub *subtree;
+		const char *name = buf;
+
+		sub = read_one(&buf, &size);
+		if (!sub)
+			goto free_return;
+		subtree = cache_tree_sub(it, name);
+		subtree->cache_tree = sub;
+	}
+	if (subtree_nr != it->subtree_nr)
+		die("cache-tree: internal error");
+	*buffer = buf;
+	*size_p = size;
+	return it;
+
+ free_return:
+	cache_tree_free(&it);
+	return NULL;
+}
+
+struct cache_tree *cache_tree_read(const char *buffer, unsigned long size)
+{
+	struct cache_tree *result;
+
+	if (buffer[0])
+		return NULL; /* not the whole tree */
+
+	trace2_region_enter("cache_tree", "read", the_repository);
+	result = read_one(&buffer, &size);
+	trace2_region_leave("cache_tree", "read", the_repository);
+
+	return result;
+}
+
+static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *path)
+{
+	if (!it)
+		return NULL;
+	while (*path) {
+		const char *slash;
+		struct cache_tree_sub *sub;
+
+		slash = strchrnul(path, '/');
+		/*
+		 * Between path and slash is the name of the subtree
+		 * to look for.
+		 */
+		sub = find_subtree(it, path, slash - path, 0);
+		if (!sub)
+			return NULL;
+		it = sub->cache_tree;
+
+		path = slash;
+		while (*path == '/')
+			path++;
+	}
+	return it;
+}
+
+static int write_index_as_tree_internal(struct object_id *oid,
+					struct index_state *index_state,
+					int cache_tree_valid,
+					int flags,
+					const char *prefix)
+{
+	if (flags & WRITE_TREE_IGNORE_CACHE_TREE) {
+		cache_tree_free(&index_state->cache_tree);
+		cache_tree_valid = 0;
+	}
+
+	if (!cache_tree_valid && cache_tree_update(index_state, flags) < 0)
+		return WRITE_TREE_UNMERGED_INDEX;
+
+	if (prefix) {
+		struct cache_tree *subtree;
+		subtree = cache_tree_find(index_state->cache_tree, prefix);
+		if (!subtree)
+			return WRITE_TREE_PREFIX_ERROR;
+		oidcpy(oid, &subtree->oid);
+	}
+	else
+		oidcpy(oid, &index_state->cache_tree->oid);
+
+	return 0;
+}
+
+struct tree* write_in_core_index_as_tree(struct repository *repo) {
+	struct object_id o;
+	int was_valid, ret;
+
+	struct index_state *index_state	= repo->index;
+	was_valid = index_state->cache_tree &&
+		    cache_tree_fully_valid(index_state->cache_tree);
+
+	ret = write_index_as_tree_internal(&o, index_state, was_valid, 0, NULL);
+	if (ret == WRITE_TREE_UNMERGED_INDEX) {
+		int i;
+		bug("there are unmerged index entries:");
+		for (i = 0; i < index_state->cache_nr; i++) {
+			const struct cache_entry *ce = index_state->cache[i];
+			if (ce_stage(ce))
+				bug("%d %.*s", ce_stage(ce),
+				    (int)ce_namelen(ce), ce->name);
+		}
+		BUG("unmerged index entries when writing in-core index");
+	}
+
+	return lookup_tree(repo, &index_state->cache_tree->oid);
+}
+
+
+int write_index_as_tree(struct object_id *oid, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
+{
+	int entries, was_valid;
+	struct lock_file lock_file = LOCK_INIT;
+	int ret;
+
+	hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
+
+	entries = read_index_from(index_state, index_path,
+				  repo_get_git_dir(the_repository));
+	if (entries < 0) {
+		ret = WRITE_TREE_UNREADABLE_INDEX;
+		goto out;
+	}
+
+	was_valid = !(flags & WRITE_TREE_IGNORE_CACHE_TREE) &&
+		    index_state->cache_tree &&
+		    cache_tree_fully_valid(index_state->cache_tree);
+
+	ret = write_index_as_tree_internal(oid, index_state, was_valid, flags,
+					   prefix);
+	if (!ret && !was_valid) {
+		write_locked_index(index_state, &lock_file, COMMIT_LOCK);
+		/* Not being able to write is fine -- we are only interested
+		 * in updating the cache-tree part, and if the next caller
+		 * ends up using the old index with unupdated cache-tree part
+		 * it misses the work we did here, but that is just a
+		 * performance penalty and not a big deal.
+		 */
+	}
+
+out:
+	rollback_lock_file(&lock_file);
+	return ret;
+}
+
+static void prime_cache_tree_sparse_dir(struct cache_tree *it,
+					struct tree *tree)
+{
+
+	oidcpy(&it->oid, &tree->object.oid);
+	it->entry_count = 1;
+}
+
+static void prime_cache_tree_rec(struct repository *r,
+				 struct cache_tree *it,
+				 struct tree *tree,
+				 struct strbuf *tree_path)
+{
+	struct tree_desc desc;
+	struct name_entry entry;
+	int cnt;
+	size_t base_path_len = tree_path->len;
+
+	oidcpy(&it->oid, &tree->object.oid);
+
+	init_tree_desc(&desc, &tree->object.oid, tree->buffer, tree->size);
+	cnt = 0;
+	while (tree_entry(&desc, &entry)) {
+		if (!S_ISDIR(entry.mode))
+			cnt++;
+		else {
+			struct cache_tree_sub *sub;
+			struct tree *subtree = lookup_tree(r, &entry.oid);
+
+			if (parse_tree(subtree) < 0)
+				exit(128);
+			sub = cache_tree_sub(it, entry.path);
+			sub->cache_tree = cache_tree();
+
+			/*
+			 * Recursively-constructed subtree path is only needed when working
+			 * in a sparse index (where it's used to determine whether the
+			 * subtree is a sparse directory in the index).
+			 */
+			if (r->index->sparse_index) {
+				strbuf_setlen(tree_path, base_path_len);
+				strbuf_add(tree_path, entry.path, entry.pathlen);
+				strbuf_addch(tree_path, '/');
+			}
+
+			/*
+			 * If a sparse index is in use, the directory being processed may be
+			 * sparse. To confirm that, we can check whether an entry with that
+			 * exact name exists in the index. If it does, the created subtree
+			 * should be sparse. Otherwise, cache tree expansion should continue
+			 * as normal.
+			 */
+			if (r->index->sparse_index &&
+			    index_entry_exists(r->index, tree_path->buf, tree_path->len))
+				prime_cache_tree_sparse_dir(sub->cache_tree, subtree);
+			else
+				prime_cache_tree_rec(r, sub->cache_tree, subtree, tree_path);
+			cnt += sub->cache_tree->entry_count;
+		}
+	}
+
+	it->entry_count = cnt;
+}
+
+void prime_cache_tree(struct repository *r,
+		      struct index_state *istate,
+		      struct tree *tree)
+{
+	struct strbuf tree_path = STRBUF_INIT;
+
+	trace2_region_enter("cache-tree", "prime_cache_tree", r);
+	cache_tree_free(&istate->cache_tree);
+	istate->cache_tree = cache_tree();
+
+	prime_cache_tree_rec(r, istate->cache_tree, tree, &tree_path);
+	strbuf_release(&tree_path);
+	istate->cache_changed |= CACHE_TREE_CHANGED;
+	trace2_region_leave("cache-tree", "prime_cache_tree", r);
+}
+
+/*
+ * find the cache_tree that corresponds to the current level without
+ * exploding the full path into textual form.  The root of the
+ * cache tree is given as "root", and our current level is "info".
+ * (1) When at root level, info->prev is NULL, so it is "root" itself.
+ * (2) Otherwise, find the cache_tree that corresponds to one level
+ *     above us, and find ourselves in there.
+ */
+static struct cache_tree *find_cache_tree_from_traversal(struct cache_tree *root,
+							 struct traverse_info *info)
+{
+	struct cache_tree *our_parent;
+
+	if (!info->prev)
+		return root;
+	our_parent = find_cache_tree_from_traversal(root, info->prev);
+	return cache_tree_find(our_parent, info->name);
+}
+
+int cache_tree_matches_traversal(struct cache_tree *root,
+				 struct name_entry *ent,
+				 struct traverse_info *info)
+{
+	struct cache_tree *it;
+
+	it = find_cache_tree_from_traversal(root, info);
+	it = cache_tree_find(it, ent->path);
+	if (it && it->entry_count > 0 && oideq(&ent->oid, &it->oid))
+		return it->entry_count;
+	return 0;
+}
+
+static int verify_one_sparse(struct index_state *istate,
+			     struct strbuf *path,
+			     int pos)
+{
+	struct cache_entry *ce = istate->cache[pos];
+	if (!S_ISSPARSEDIR(ce->ce_mode))
+		return error(_("directory '%s' is present in index, but not sparse"),
+			     path->buf);
+	return 0;
+}
+
+/*
+ * Returns:
+ *  0 - Verification completed.
+ *  1 - Restart verification - a call to ensure_full_index() freed the cache
+ *      tree that is being verified and verification needs to be restarted from
+ *      the new toplevel cache tree.
+ *  -1 - Verification failed.
+ */
+static int verify_one(struct repository *r,
+		      struct index_state *istate,
+		      struct cache_tree *it,
+		      struct strbuf *path)
+{
+	int i, pos, len = path->len;
+	struct strbuf tree_buf = STRBUF_INIT;
+	struct object_id new_oid;
+	int ret;
+
+	for (i = 0; i < it->subtree_nr; i++) {
+		strbuf_addf(path, "%s/", it->down[i]->name);
+		ret = verify_one(r, istate, it->down[i]->cache_tree, path);
+		if (ret)
+			goto out;
+
+		strbuf_setlen(path, len);
+	}
+
+	if (it->entry_count < 0 ||
+	    /* no verification on tests (t7003) that replace trees */
+	    lookup_replace_object(r, &it->oid) != &it->oid) {
+		ret = 0;
+		goto out;
+	}
+
+	if (path->len) {
+		/*
+		 * If the index is sparse and the cache tree is not
+		 * index_name_pos() may trigger ensure_full_index() which will
+		 * free the tree that is being verified.
+		 */
+		int is_sparse = istate->sparse_index;
+		pos = index_name_pos(istate, path->buf, path->len);
+		if (is_sparse && !istate->sparse_index) {
+			ret = 1;
+			goto out;
+		}
+
+		if (pos >= 0) {
+			ret = verify_one_sparse(istate, path, pos);
+			goto out;
+		}
+
+		pos = -pos - 1;
+	} else {
+		pos = 0;
+	}
+
+	if (it->entry_count + pos > istate->cache_nr) {
+		ret = error(_("corrupted cache-tree has entries not present in index"));
+		goto out;
+	}
+
+	i = 0;
+	while (i < it->entry_count) {
+		struct cache_entry *ce = istate->cache[pos + i];
+		const char *slash;
+		struct cache_tree_sub *sub = NULL;
+		const struct object_id *oid;
+		const char *name;
+		unsigned mode;
+		int entlen;
+
+		if (ce->ce_flags & (CE_STAGEMASK | CE_INTENT_TO_ADD | CE_REMOVE)) {
+			ret = error(_("%s with flags 0x%x should not be in cache-tree"),
+				    ce->name, ce->ce_flags);
+			goto out;
+		}
+
+		name = ce->name + path->len;
+		slash = strchr(name, '/');
+		if (slash) {
+			entlen = slash - name;
+
+			sub = find_subtree(it, ce->name + path->len, entlen, 0);
+			if (!sub || sub->cache_tree->entry_count < 0) {
+				ret = error(_("bad subtree '%.*s'"), entlen, name);
+				goto out;
+			}
+
+			oid = &sub->cache_tree->oid;
+			mode = S_IFDIR;
+			i += sub->cache_tree->entry_count;
+		} else {
+			oid = &ce->oid;
+			mode = ce->ce_mode;
+			entlen = ce_namelen(ce) - path->len;
+			i++;
+		}
+		strbuf_addf(&tree_buf, "%o %.*s%c", mode, entlen, name, '\0');
+		strbuf_add(&tree_buf, oid->hash, r->hash_algo->rawsz);
+	}
+
+	hash_object_file(r->hash_algo, tree_buf.buf, tree_buf.len, OBJ_TREE,
+			 &new_oid);
+
+	if (!oideq(&new_oid, &it->oid)) {
+		ret = error(_("cache-tree for path %.*s does not match. "
+			      "Expected %s got %s"), len, path->buf,
+			    oid_to_hex(&new_oid), oid_to_hex(&it->oid));
+		goto out;
+	}
+
+	ret = 0;
+out:
+	strbuf_setlen(path, len);
+	strbuf_release(&tree_buf);
+	return ret;
+}
+
+int cache_tree_verify(struct repository *r, struct index_state *istate)
+{
+	struct strbuf path = STRBUF_INIT;
+	int ret;
+
+	if (!istate->cache_tree) {
+		ret = 0;
+		goto out;
+	}
+
+	ret = verify_one(r, istate, istate->cache_tree, &path);
+	if (ret < 0)
+		goto out;
+	if (ret > 0) {
+		strbuf_reset(&path);
+
+		ret = verify_one(r, istate, istate->cache_tree, &path);
+		if (ret < 0)
+			goto out;
+		if (ret > 0)
+			BUG("ensure_full_index() called twice while verifying cache tree");
+	}
+
+	ret = 0;
+
+out:
+	strbuf_release(&path);
+	return ret;
+}
diff --git a/cache-tree.h b/cache-tree.h
new file mode 100644
index 0000000000..b82c4963e7
--- /dev/null
+++ b/cache-tree.h
@@ -0,0 +1,55 @@
+#ifndef CACHE_TREE_H
+#define CACHE_TREE_H
+
+#include "tree.h"
+#include "tree-walk.h"
+
+struct cache_tree;
+struct cache_tree_sub {
+	struct cache_tree *cache_tree;
+	int count;		/* internally used by update_one() */
+	int namelen;
+	int used;
+	char name[FLEX_ARRAY];
+};
+
+struct cache_tree {
+	int entry_count; /* negative means "invalid" */
+	struct object_id oid;
+	int subtree_nr;
+	int subtree_alloc;
+	struct cache_tree_sub **down;
+};
+
+struct cache_tree *cache_tree(void);
+void cache_tree_free(struct cache_tree **);
+void cache_tree_invalidate_path(struct index_state *, const char *);
+struct cache_tree_sub *cache_tree_sub(struct cache_tree *, const char *);
+
+int cache_tree_subtree_pos(struct cache_tree *it, const char *path, int pathlen);
+
+void cache_tree_write(struct strbuf *, struct cache_tree *root);
+struct cache_tree *cache_tree_read(const char *buffer, unsigned long size);
+
+int cache_tree_fully_valid(struct cache_tree *);
+int cache_tree_update(struct index_state *, int);
+int cache_tree_verify(struct repository *, struct index_state *);
+
+/* bitmasks to write_index_as_tree flags */
+#define WRITE_TREE_MISSING_OK 1
+#define WRITE_TREE_IGNORE_CACHE_TREE 2
+#define WRITE_TREE_DRY_RUN 4
+#define WRITE_TREE_SILENT 8
+#define WRITE_TREE_REPAIR 16
+
+/* error return codes */
+#define WRITE_TREE_UNREADABLE_INDEX (-1)
+#define WRITE_TREE_UNMERGED_INDEX (-2)
+#define WRITE_TREE_PREFIX_ERROR (-3)
+
+struct tree* write_in_core_index_as_tree(struct repository *repo);
+int write_index_as_tree(struct object_id *oid, struct index_state *index_state, const char *index_path, int flags, const char *prefix);
+void prime_cache_tree(struct repository *, struct index_state *, struct tree *);
+
+int cache_tree_matches_traversal(struct cache_tree *, struct name_entry *ent, struct traverse_info *info);
+#endif
diff --git a/cbtree.c b/cbtree.c
new file mode 100644
index 0000000000..cf8cf75b89
--- /dev/null
+++ b/cbtree.c
@@ -0,0 +1,136 @@
+/*
+ * crit-bit tree implementation, does no allocations internally
+ * For more information on crit-bit trees: https://cr.yp.to/critbit.html
+ * Based on Adam Langley's adaptation of Dan Bernstein's public domain code
+ * git clone https://github.com/agl/critbit.git
+ */
+#include "git-compat-util.h"
+#include "cbtree.h"
+
+static struct cb_node *cb_node_of(const void *p)
+{
+	return (struct cb_node *)((uintptr_t)p - 1);
+}
+
+/* locate the best match, does not do a final comparison */
+static struct cb_node *cb_internal_best_match(struct cb_node *p,
+					const uint8_t *k, size_t klen)
+{
+	while (1 & (uintptr_t)p) {
+		struct cb_node *q = cb_node_of(p);
+		uint8_t c = q->byte < klen ? k[q->byte] : 0;
+		size_t direction = (1 + (q->otherbits | c)) >> 8;
+
+		p = q->child[direction];
+	}
+	return p;
+}
+
+/* returns NULL if successful, existing cb_node if duplicate */
+struct cb_node *cb_insert(struct cb_tree *t, struct cb_node *node, size_t klen)
+{
+	size_t newbyte, newotherbits;
+	uint8_t c;
+	int newdirection;
+	struct cb_node **wherep, *p;
+
+	assert(!((uintptr_t)node & 1)); /* allocations must be aligned */
+
+	if (!t->root) {		/* insert into empty tree */
+		t->root = node;
+		return NULL;	/* success */
+	}
+
+	/* see if a node already exists */
+	p = cb_internal_best_match(t->root, node->k, klen);
+
+	/* find first differing byte */
+	for (newbyte = 0; newbyte < klen; newbyte++) {
+		if (p->k[newbyte] != node->k[newbyte])
+			goto different_byte_found;
+	}
+	return p;	/* element exists, let user deal with it */
+
+different_byte_found:
+	newotherbits = p->k[newbyte] ^ node->k[newbyte];
+	newotherbits |= newotherbits >> 1;
+	newotherbits |= newotherbits >> 2;
+	newotherbits |= newotherbits >> 4;
+	newotherbits = (newotherbits & ~(newotherbits >> 1)) ^ 255;
+	c = p->k[newbyte];
+	newdirection = (1 + (newotherbits | c)) >> 8;
+
+	node->byte = newbyte;
+	node->otherbits = newotherbits;
+	node->child[1 - newdirection] = node;
+
+	/* find a place to insert it */
+	wherep = &t->root;
+	for (;;) {
+		struct cb_node *q;
+		size_t direction;
+
+		p = *wherep;
+		if (!(1 & (uintptr_t)p))
+			break;
+		q = cb_node_of(p);
+		if (q->byte > newbyte)
+			break;
+		if (q->byte == newbyte && q->otherbits > newotherbits)
+			break;
+		c = q->byte < klen ? node->k[q->byte] : 0;
+		direction = (1 + (q->otherbits | c)) >> 8;
+		wherep = q->child + direction;
+	}
+
+	node->child[newdirection] = *wherep;
+	*wherep = (struct cb_node *)(1 + (uintptr_t)node);
+
+	return NULL; /* success */
+}
+
+struct cb_node *cb_lookup(struct cb_tree *t, const uint8_t *k, size_t klen)
+{
+	struct cb_node *p = cb_internal_best_match(t->root, k, klen);
+
+	return p && !memcmp(p->k, k, klen) ? p : NULL;
+}
+
+static enum cb_next cb_descend(struct cb_node *p, cb_iter fn, void *arg)
+{
+	if (1 & (uintptr_t)p) {
+		struct cb_node *q = cb_node_of(p);
+		enum cb_next n = cb_descend(q->child[0], fn, arg);
+
+		return n == CB_BREAK ? n : cb_descend(q->child[1], fn, arg);
+	} else {
+		return fn(p, arg);
+	}
+}
+
+void cb_each(struct cb_tree *t, const uint8_t *kpfx, size_t klen,
+			cb_iter fn, void *arg)
+{
+	struct cb_node *p = t->root;
+	struct cb_node *top = p;
+	size_t i = 0;
+
+	if (!p) return; /* empty tree */
+
+	/* Walk tree, maintaining top pointer */
+	while (1 & (uintptr_t)p) {
+		struct cb_node *q = cb_node_of(p);
+		uint8_t c = q->byte < klen ? kpfx[q->byte] : 0;
+		size_t direction = (1 + (q->otherbits | c)) >> 8;
+
+		p = q->child[direction];
+		if (q->byte < klen)
+			top = p;
+	}
+
+	for (i = 0; i < klen; i++) {
+		if (p->k[i] != kpfx[i])
+			return; /* "best" match failed */
+	}
+	cb_descend(top, fn, arg);
+}
diff --git a/cbtree.h b/cbtree.h
new file mode 100644
index 0000000000..43193abdda
--- /dev/null
+++ b/cbtree.h
@@ -0,0 +1,54 @@
+/*
+ * crit-bit tree implementation, does no allocations internally
+ * For more information on crit-bit trees: https://cr.yp.to/critbit.html
+ * Based on Adam Langley's adaptation of Dan Bernstein's public domain code
+ * git clone https://github.com/agl/critbit.git
+ *
+ * This is adapted to store arbitrary data (not just NUL-terminated C strings
+ * and allocates no memory internally.  The user needs to allocate
+ * "struct cb_node" and fill cb_node.k[] with arbitrary match data
+ * for memcmp.
+ * If "klen" is variable, then it should be embedded into "c_node.k[]"
+ * Recursion is bound by the maximum value of "klen" used.
+ */
+#ifndef CBTREE_H
+#define CBTREE_H
+
+struct cb_node;
+struct cb_node {
+	struct cb_node *child[2];
+	/*
+	 * n.b. uint32_t for `byte' is excessive for OIDs,
+	 * we may consider shorter variants if nothing else gets stored.
+	 */
+	uint32_t byte;
+	uint8_t otherbits;
+	uint8_t k[FLEX_ARRAY]; /* arbitrary data, unaligned */
+};
+
+struct cb_tree {
+	struct cb_node *root;
+};
+
+enum cb_next {
+	CB_CONTINUE = 0,
+	CB_BREAK = 1
+};
+
+#define CBTREE_INIT { 0 }
+
+static inline void cb_init(struct cb_tree *t)
+{
+	struct cb_tree blank = CBTREE_INIT;
+	memcpy(t, &blank, sizeof(*t));
+}
+
+struct cb_node *cb_lookup(struct cb_tree *, const uint8_t *k, size_t klen);
+struct cb_node *cb_insert(struct cb_tree *, struct cb_node *, size_t klen);
+
+typedef enum cb_next (*cb_iter)(struct cb_node *, void *arg);
+
+void cb_each(struct cb_tree *, const uint8_t *kpfx, size_t klen,
+		cb_iter, void *arg);
+
+#endif /* CBTREE_H */
diff --git a/chdir-notify.c b/chdir-notify.c
new file mode 100644
index 0000000000..0d7bc04607
--- /dev/null
+++ b/chdir-notify.c
@@ -0,0 +1,96 @@
+#include "git-compat-util.h"
+#include "abspath.h"
+#include "chdir-notify.h"
+#include "list.h"
+#include "path.h"
+#include "strbuf.h"
+#include "trace.h"
+
+struct chdir_notify_entry {
+	const char *name;
+	chdir_notify_callback cb;
+	void *data;
+	struct list_head list;
+};
+static LIST_HEAD(chdir_notify_entries);
+
+void chdir_notify_register(const char *name,
+			   chdir_notify_callback cb,
+			   void *data)
+{
+	struct chdir_notify_entry *e = xmalloc(sizeof(*e));
+	e->name = name;
+	e->cb = cb;
+	e->data = data;
+	list_add_tail(&e->list, &chdir_notify_entries);
+}
+
+static void reparent_cb(const char *name,
+			const char *old_cwd,
+			const char *new_cwd,
+			void *data)
+{
+	char **path = data;
+	char *tmp = *path;
+
+	if (!tmp)
+		return;
+
+	*path = reparent_relative_path(old_cwd, new_cwd, tmp);
+	free(tmp);
+
+	if (name) {
+		trace_printf_key(&trace_setup_key,
+				 "setup: reparent %s to '%s'",
+				 name, *path);
+	}
+}
+
+void chdir_notify_reparent(const char *name, char **path)
+{
+	chdir_notify_register(name, reparent_cb, path);
+}
+
+int chdir_notify(const char *new_cwd)
+{
+	struct strbuf old_cwd = STRBUF_INIT;
+	struct list_head *pos;
+
+	if (strbuf_getcwd(&old_cwd) < 0)
+		return -1;
+	if (chdir(new_cwd) < 0) {
+		int saved_errno = errno;
+		strbuf_release(&old_cwd);
+		errno = saved_errno;
+		return -1;
+	}
+
+	trace_printf_key(&trace_setup_key,
+			 "setup: chdir from '%s' to '%s'",
+			 old_cwd.buf, new_cwd);
+
+	list_for_each(pos, &chdir_notify_entries) {
+		struct chdir_notify_entry *e =
+			list_entry(pos, struct chdir_notify_entry, list);
+		e->cb(e->name, old_cwd.buf, new_cwd, e->data);
+	}
+
+	strbuf_release(&old_cwd);
+	return 0;
+}
+
+char *reparent_relative_path(const char *old_cwd,
+			     const char *new_cwd,
+			     const char *path)
+{
+	char *ret, *full;
+
+	if (is_absolute_path(path))
+		return xstrdup(path);
+
+	full = xstrfmt("%s/%s", old_cwd, path);
+	ret = xstrdup(remove_leading_path(full, new_cwd));
+	free(full);
+
+	return ret;
+}
diff --git a/chdir-notify.h b/chdir-notify.h
new file mode 100644
index 0000000000..366e4c1ee9
--- /dev/null
+++ b/chdir-notify.h
@@ -0,0 +1,73 @@
+#ifndef CHDIR_NOTIFY_H
+#define CHDIR_NOTIFY_H
+
+/*
+ * An API to let code "subscribe" to changes to the current working directory.
+ * The general idea is that some code asks to be notified when the working
+ * directory changes, and other code that calls chdir uses a special wrapper
+ * that notifies everyone.
+ */
+
+/*
+ * Callers who need to know about changes can do:
+ *
+ *   void foo(const char *old_path, const char *new_path, void *data)
+ *   {
+ *	warning("switched from %s to %s!", old_path, new_path);
+ *   }
+ *   ...
+ *   chdir_notify_register("description", foo, data);
+ *
+ * In practice most callers will want to move a relative path to the new root;
+ * they can use the reparent_relative_path() helper for that. If that's all
+ * you're doing, you can also use the convenience function:
+ *
+ *   chdir_notify_reparent("description", &my_path);
+ *
+ * Whenever a chdir event occurs, that will update my_path (if it's relative)
+ * to adjust for the new cwd by freeing any existing string and allocating a
+ * new one.
+ *
+ * Registered functions are called in the order in which they were added. Note
+ * that there's currently no way to remove a function, so make sure that the
+ * data parameter remains valid for the rest of the program.
+ *
+ * The "name" argument is used only for printing trace output from
+ * $GIT_TRACE_SETUP. It may be NULL, but if non-NULL should point to
+ * storage which lasts as long as the registration is active.
+ */
+typedef void (*chdir_notify_callback)(const char *name,
+				      const char *old_cwd,
+				      const char *new_cwd,
+				      void *data);
+void chdir_notify_register(const char *name, chdir_notify_callback cb, void *data);
+void chdir_notify_reparent(const char *name, char **path);
+
+/*
+ *
+ * Callers that want to chdir:
+ *
+ *   chdir_notify(new_path);
+ *
+ * to switch to the new path and notify any callbacks.
+ *
+ * Note that you don't need to chdir_notify() if you're just temporarily moving
+ * to a directory and back, as long as you don't call any subscribed code in
+ * between (but it should be safe to do so if you're unsure).
+ */
+int chdir_notify(const char *new_cwd);
+
+/*
+ * Reparent a relative path from old_root to new_root. For example:
+ *
+ *   reparent_relative_path("/a", "/a/b", "b/rel");
+ *
+ * would return the (newly allocated) string "rel". Note that we may return an
+ * absolute path in some cases (e.g., if the resulting path is not inside
+ * new_cwd).
+ */
+char *reparent_relative_path(const char *old_cwd,
+			     const char *new_cwd,
+			     const char *path);
+
+#endif /* CHDIR_NOTIFY_H */
diff --git a/check-builtins.sh b/check-builtins.sh
new file mode 100755
index 0000000000..a0aaf3a347
--- /dev/null
+++ b/check-builtins.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+{
+	cat <<\EOF
+sayIt:
+	$(foreach b,$(BUILT_INS),echo XXX $(b:$X=) YYY;)
+EOF
+	cat Makefile
+} |
+make -f - sayIt 2>/dev/null |
+sed -n -e 's/.*XXX \(.*\) YYY.*/\1/p' |
+sort |
+{
+    bad=0
+    while read builtin
+    do
+	base=$(expr "$builtin" : 'git-\(.*\)')
+	x=$(sed -ne 's/.*{ "'$base'", \(cmd_[^, ]*\).*/'$base'	\1/p' git.c)
+	if test -z "$x"
+	then
+		echo "$base is builtin but not listed in git.c command list"
+		bad=1
+	fi
+	for sfx in sh perl py
+	do
+		if test -f "$builtin.$sfx"
+		then
+			echo "$base is builtin but $builtin.$sfx still exists"
+			bad=1
+		fi
+	done
+    done
+    exit $bad
+}
diff --git a/checkout.c b/checkout.c
new file mode 100644
index 0000000000..0b1cf8b40b
--- /dev/null
+++ b/checkout.c
@@ -0,0 +1,75 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "object-name.h"
+#include "remote.h"
+#include "refspec.h"
+#include "repository.h"
+#include "checkout.h"
+#include "config.h"
+#include "strbuf.h"
+
+struct tracking_name_data {
+	/* const */ char *src_ref;
+	char *dst_ref;
+	struct object_id *dst_oid;
+	int num_matches;
+	const char *default_remote;
+	char *default_dst_ref;
+	struct object_id *default_dst_oid;
+};
+
+#define TRACKING_NAME_DATA_INIT { 0 }
+
+static int check_tracking_name(struct remote *remote, void *cb_data)
+{
+	struct tracking_name_data *cb = cb_data;
+	struct refspec_item query;
+	memset(&query, 0, sizeof(struct refspec_item));
+	query.src = cb->src_ref;
+	if (remote_find_tracking(remote, &query) ||
+	    repo_get_oid(the_repository, query.dst, cb->dst_oid)) {
+		free(query.dst);
+		return 0;
+	}
+	cb->num_matches++;
+	if (cb->default_remote && !strcmp(remote->name, cb->default_remote)) {
+		struct object_id *dst = xmalloc(sizeof(*cb->default_dst_oid));
+		cb->default_dst_ref = xstrdup(query.dst);
+		oidcpy(dst, cb->dst_oid);
+		cb->default_dst_oid = dst;
+	}
+	if (cb->dst_ref) {
+		free(query.dst);
+		return 0;
+	}
+	cb->dst_ref = query.dst;
+	return 0;
+}
+
+char *unique_tracking_name(const char *name, struct object_id *oid,
+			   int *dwim_remotes_matched)
+{
+	struct tracking_name_data cb_data = TRACKING_NAME_DATA_INIT;
+	const char *default_remote = NULL;
+	if (!git_config_get_string_tmp("checkout.defaultremote", &default_remote))
+		cb_data.default_remote = default_remote;
+	cb_data.src_ref = xstrfmt("refs/heads/%s", name);
+	cb_data.dst_oid = oid;
+	for_each_remote(check_tracking_name, &cb_data);
+	if (dwim_remotes_matched)
+		*dwim_remotes_matched = cb_data.num_matches;
+	free(cb_data.src_ref);
+	if (cb_data.num_matches == 1) {
+		free(cb_data.default_dst_ref);
+		free(cb_data.default_dst_oid);
+		return cb_data.dst_ref;
+	}
+	free(cb_data.dst_ref);
+	if (cb_data.default_dst_ref) {
+		oidcpy(oid, cb_data.default_dst_oid);
+		free(cb_data.default_dst_oid);
+		return cb_data.default_dst_ref;
+	}
+	return NULL;
+}
diff --git a/checkout.h b/checkout.h
new file mode 100644
index 0000000000..55920e7aeb
--- /dev/null
+++ b/checkout.h
@@ -0,0 +1,15 @@
+#ifndef CHECKOUT_H
+#define CHECKOUT_H
+
+#include "hash.h"
+
+/*
+ * Check if the branch name uniquely matches a branch name on a remote
+ * tracking branch.  Return the name of the remote if such a branch
+ * exists, NULL otherwise.
+ */
+char *unique_tracking_name(const char *name,
+			   struct object_id *oid,
+			   int *dwim_remotes_matched);
+
+#endif /* CHECKOUT_H */
diff --git a/chunk-format.c b/chunk-format.c
new file mode 100644
index 0000000000..51b5a2c959
--- /dev/null
+++ b/chunk-format.c
@@ -0,0 +1,215 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "chunk-format.h"
+#include "csum-file.h"
+#include "gettext.h"
+#include "hash.h"
+#include "trace2.h"
+
+/*
+ * When writing a chunk-based file format, collect the chunks in
+ * an array of chunk_info structs. The size stores the _expected_
+ * amount of data that will be written by write_fn.
+ */
+struct chunk_info {
+	uint32_t id;
+	uint64_t size;
+	chunk_write_fn write_fn;
+
+	const void *start;
+};
+
+struct chunkfile {
+	struct hashfile *f;
+
+	struct chunk_info *chunks;
+	size_t chunks_nr;
+	size_t chunks_alloc;
+};
+
+struct chunkfile *init_chunkfile(struct hashfile *f)
+{
+	struct chunkfile *cf = xcalloc(1, sizeof(*cf));
+	cf->f = f;
+	return cf;
+}
+
+void free_chunkfile(struct chunkfile *cf)
+{
+	if (!cf)
+		return;
+	free(cf->chunks);
+	free(cf);
+}
+
+int get_num_chunks(struct chunkfile *cf)
+{
+	return cf->chunks_nr;
+}
+
+void add_chunk(struct chunkfile *cf,
+	       uint32_t id,
+	       size_t size,
+	       chunk_write_fn fn)
+{
+	ALLOC_GROW(cf->chunks, cf->chunks_nr + 1, cf->chunks_alloc);
+
+	cf->chunks[cf->chunks_nr].id = id;
+	cf->chunks[cf->chunks_nr].write_fn = fn;
+	cf->chunks[cf->chunks_nr].size = size;
+	cf->chunks_nr++;
+}
+
+int write_chunkfile(struct chunkfile *cf, void *data)
+{
+	int i, result = 0;
+	uint64_t cur_offset = hashfile_total(cf->f);
+
+	trace2_region_enter("chunkfile", "write", the_repository);
+
+	/* Add the table of contents to the current offset */
+	cur_offset += (cf->chunks_nr + 1) * CHUNK_TOC_ENTRY_SIZE;
+
+	for (i = 0; i < cf->chunks_nr; i++) {
+		hashwrite_be32(cf->f, cf->chunks[i].id);
+		hashwrite_be64(cf->f, cur_offset);
+
+		cur_offset += cf->chunks[i].size;
+	}
+
+	/* Trailing entry marks the end of the chunks */
+	hashwrite_be32(cf->f, 0);
+	hashwrite_be64(cf->f, cur_offset);
+
+	for (i = 0; i < cf->chunks_nr; i++) {
+		off_t start_offset = hashfile_total(cf->f);
+		result = cf->chunks[i].write_fn(cf->f, data);
+
+		if (result)
+			goto cleanup;
+
+		if (hashfile_total(cf->f) - start_offset != cf->chunks[i].size)
+			BUG("expected to write %"PRId64" bytes to chunk %"PRIx32", but wrote %"PRId64" instead",
+			    cf->chunks[i].size, cf->chunks[i].id,
+			    hashfile_total(cf->f) - start_offset);
+	}
+
+cleanup:
+	trace2_region_leave("chunkfile", "write", the_repository);
+	return result;
+}
+
+int read_table_of_contents(struct chunkfile *cf,
+			   const unsigned char *mfile,
+			   size_t mfile_size,
+			   uint64_t toc_offset,
+			   int toc_length,
+			   unsigned expected_alignment)
+{
+	int i;
+	uint32_t chunk_id;
+	const unsigned char *table_of_contents = mfile + toc_offset;
+
+	ALLOC_GROW(cf->chunks, toc_length, cf->chunks_alloc);
+
+	while (toc_length--) {
+		uint64_t chunk_offset, next_chunk_offset;
+
+		chunk_id = get_be32(table_of_contents);
+		chunk_offset = get_be64(table_of_contents + 4);
+
+		if (!chunk_id) {
+			error(_("terminating chunk id appears earlier than expected"));
+			return 1;
+		}
+		if (chunk_offset % expected_alignment != 0) {
+			error(_("chunk id %"PRIx32" not %d-byte aligned"),
+			      chunk_id, expected_alignment);
+			return 1;
+		}
+
+		table_of_contents += CHUNK_TOC_ENTRY_SIZE;
+		next_chunk_offset = get_be64(table_of_contents + 4);
+
+		if (next_chunk_offset < chunk_offset ||
+		    next_chunk_offset > mfile_size - the_hash_algo->rawsz) {
+			error(_("improper chunk offset(s) %"PRIx64" and %"PRIx64""),
+			      chunk_offset, next_chunk_offset);
+			return -1;
+		}
+
+		for (i = 0; i < cf->chunks_nr; i++) {
+			if (cf->chunks[i].id == chunk_id) {
+				error(_("duplicate chunk ID %"PRIx32" found"),
+					chunk_id);
+				return -1;
+			}
+		}
+
+		cf->chunks[cf->chunks_nr].id = chunk_id;
+		cf->chunks[cf->chunks_nr].start = mfile + chunk_offset;
+		cf->chunks[cf->chunks_nr].size = next_chunk_offset - chunk_offset;
+		cf->chunks_nr++;
+	}
+
+	chunk_id = get_be32(table_of_contents);
+	if (chunk_id) {
+		error(_("final chunk has non-zero id %"PRIx32""), chunk_id);
+		return -1;
+	}
+
+	return 0;
+}
+
+struct pair_chunk_data {
+	const unsigned char **p;
+	size_t *size;
+};
+
+static int pair_chunk_fn(const unsigned char *chunk_start,
+			 size_t chunk_size,
+			 void *data)
+{
+	struct pair_chunk_data *pcd = data;
+	*pcd->p = chunk_start;
+	*pcd->size = chunk_size;
+	return 0;
+}
+
+int pair_chunk(struct chunkfile *cf,
+	       uint32_t chunk_id,
+	       const unsigned char **p,
+	       size_t *size)
+{
+	struct pair_chunk_data pcd = { .p = p, .size = size };
+	return read_chunk(cf, chunk_id, pair_chunk_fn, &pcd);
+}
+
+int read_chunk(struct chunkfile *cf,
+	       uint32_t chunk_id,
+	       chunk_read_fn fn,
+	       void *data)
+{
+	int i;
+
+	for (i = 0; i < cf->chunks_nr; i++) {
+		if (cf->chunks[i].id == chunk_id)
+			return fn(cf->chunks[i].start, cf->chunks[i].size, data);
+	}
+
+	return CHUNK_NOT_FOUND;
+}
+
+uint8_t oid_version(const struct git_hash_algo *algop)
+{
+	switch (hash_algo_by_ptr(algop)) {
+	case GIT_HASH_SHA1:
+		return 1;
+	case GIT_HASH_SHA256:
+		return 2;
+	default:
+		die(_("invalid hash version"));
+	}
+}
diff --git a/chunk-format.h b/chunk-format.h
new file mode 100644
index 0000000000..212a0a6af1
--- /dev/null
+++ b/chunk-format.h
@@ -0,0 +1,73 @@
+#ifndef CHUNK_FORMAT_H
+#define CHUNK_FORMAT_H
+
+#include "hash.h"
+
+struct hashfile;
+struct chunkfile;
+
+#define CHUNK_TOC_ENTRY_SIZE (sizeof(uint32_t) + sizeof(uint64_t))
+
+/*
+ * Initialize a 'struct chunkfile' for writing _or_ reading a file
+ * with the chunk format.
+ *
+ * If writing a file, supply a non-NULL 'struct hashfile *' that will
+ * be used to write.
+ *
+ * If reading a file, use a NULL 'struct hashfile *' and then call
+ * read_table_of_contents(). Supply the memory-mapped data to the
+ * pair_chunk() or read_chunk() methods, as appropriate.
+ *
+ * DO NOT MIX THESE MODES. Use different 'struct chunkfile' instances
+ * for reading and writing.
+ */
+struct chunkfile *init_chunkfile(struct hashfile *f);
+void free_chunkfile(struct chunkfile *cf);
+int get_num_chunks(struct chunkfile *cf);
+typedef int (*chunk_write_fn)(struct hashfile *f, void *data);
+void add_chunk(struct chunkfile *cf,
+	       uint32_t id,
+	       size_t size,
+	       chunk_write_fn fn);
+int write_chunkfile(struct chunkfile *cf, void *data);
+
+int read_table_of_contents(struct chunkfile *cf,
+			   const unsigned char *mfile,
+			   size_t mfile_size,
+			   uint64_t toc_offset,
+			   int toc_length,
+			   unsigned expected_alignment);
+
+#define CHUNK_NOT_FOUND (-2)
+
+/*
+ * Find 'chunk_id' in the given chunkfile and assign the
+ * given pointer to the position in the mmap'd file where
+ * that chunk begins. Likewise the "size" parameter is filled
+ * with the size of the chunk.
+ *
+ * Returns CHUNK_NOT_FOUND if the chunk does not exist.
+ */
+int pair_chunk(struct chunkfile *cf,
+	       uint32_t chunk_id,
+	       const unsigned char **p,
+	       size_t *size);
+
+typedef int (*chunk_read_fn)(const unsigned char *chunk_start,
+			     size_t chunk_size, void *data);
+/*
+ * Find 'chunk_id' in the given chunkfile and call the
+ * given chunk_read_fn method with the information for
+ * that chunk.
+ *
+ * Returns CHUNK_NOT_FOUND if the chunk does not exist.
+ */
+int read_chunk(struct chunkfile *cf,
+	       uint32_t chunk_id,
+	       chunk_read_fn fn,
+	       void *data);
+
+uint8_t oid_version(const struct git_hash_algo *algop);
+
+#endif
diff --git a/ci/check-directional-formatting.bash b/ci/check-directional-formatting.bash
new file mode 100755
index 0000000000..3cbbb7030e
--- /dev/null
+++ b/ci/check-directional-formatting.bash
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+# This script verifies that the non-binary files tracked in the Git index do
+# not contain any Unicode directional formatting: such formatting could be used
+# to deceive reviewers into interpreting code differently from the compiler.
+# This is intended to run on an Ubuntu agent in a GitHub workflow.
+#
+# To allow translated messages to introduce such directional formatting in the
+# future, we exclude the `.po` files from this validation.
+#
+# Neither GNU grep nor `git grep` (not even with `-P`) handle `\u` as a way to
+# specify UTF-8.
+#
+# To work around that, we use `printf` to produce the pattern as a byte
+# sequence, and then feed that to `git grep` as a byte sequence (setting
+# `LC_CTYPE` to make sure that the arguments are interpreted as intended).
+#
+# Note: we need to use Bash here because its `printf` interprets `\uNNNN` as
+# UTF-8 code points, as desired. Running this script through Ubuntu's `dash`,
+# for example, would use a `printf` that does not understand that syntax.
+
+# U+202a..U+2a2e: LRE, RLE, PDF, LRO and RLO
+# U+2066..U+2069: LRI, RLI, FSI and PDI
+regex='(\u202a|\u202b|\u202c|\u202d|\u202e|\u2066|\u2067|\u2068|\u2069)'
+
+! LC_CTYPE=C git grep -El "$(LC_CTYPE=C.UTF-8 printf "$regex")" \
+	-- ':(exclude,attr:binary)' ':(exclude)*.po'
diff --git a/ci/check-whitespace.sh b/ci/check-whitespace.sh
new file mode 100755
index 0000000000..c40804394c
--- /dev/null
+++ b/ci/check-whitespace.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+#
+# Check that commits after a specified point do not contain new or modified
+# lines with whitespace errors. An optional formatted summary can be generated
+# by providing an output file path and url as additional arguments.
+#
+
+baseCommit=$1
+outputFile=$2
+url=$3
+
+if test "$#" -ne 1 && test "$#" -ne 3 || test -z "$1"
+then
+	echo "USAGE: $0 <BASE_COMMIT> [<OUTPUT_FILE> <URL>]"
+	exit 1
+fi
+
+problems=()
+commit=
+commitText=
+commitTextmd=
+goodParent=
+
+if ! git rev-parse --quiet --verify "${baseCommit}"
+then
+    echo "Invalid <BASE_COMMIT> '${baseCommit}'"
+    exit 1
+fi
+
+while read dash sha etc
+do
+	case "${dash}" in
+	"---") # Line contains commit information.
+		if test -z "${goodParent}"
+		then
+			# Assume the commit has no whitespace errors until detected otherwise.
+			goodParent=${sha}
+		fi
+
+		commit="${sha}"
+		commitText="${sha} ${etc}"
+		commitTextmd="[${sha}](${url}/commit/${sha}) ${etc}"
+		;;
+	"")
+		;;
+	*) # Line contains whitespace error information for current commit.
+		if test -n "${goodParent}"
+		then
+			problems+=("1) --- ${commitTextmd}")
+			echo ""
+			echo "--- ${commitText}"
+			goodParent=
+		fi
+
+		case "${dash}" in
+		*:[1-9]*:) # contains file and line number information
+			dashend=${dash#*:}
+			problems+=("[${dash}](${url}/blob/${commit}/${dash%%:*}#L${dashend%:}) ${sha} ${etc}")
+			;;
+		*)
+			problems+=("\`${dash} ${sha} ${etc}\`")
+			;;
+		esac
+		echo "${dash} ${sha} ${etc}"
+		;;
+	esac
+done <<< "$(git log --check --pretty=format:"---% h% s" "${baseCommit}"..)"
+
+if test ${#problems[*]} -gt 0
+then
+	if test -z "${goodParent}"
+	then
+		goodParent=${baseCommit: 0:7}
+	fi
+
+	echo "A whitespace issue was found in one or more of the commits."
+	echo "Run the following command to resolve whitespace issues:"
+	echo "git rebase --whitespace=fix ${goodParent}"
+
+	# If target output file is provided, write formatted output.
+	if test -n "$outputFile"
+	then
+		echo "🛑 Please review the Summary output for further information."
+		(
+			echo "### :x: A whitespace issue was found in one or more of the commits."
+			echo ""
+			echo "Run these commands to correct the problem:"
+			echo "1. \`git rebase --whitespace=fix ${goodParent}\`"
+			echo "1. \`git push --force\`"
+			echo ""
+			echo "Errors:"
+
+			for i in "${problems[@]}"
+			do
+				echo "${i}"
+			done
+		) >"$outputFile"
+	fi
+
+	exit 2
+fi
diff --git a/ci/config/README b/ci/config/README
new file mode 100644
index 0000000000..8de3a04e32
--- /dev/null
+++ b/ci/config/README
@@ -0,0 +1,14 @@
+You can configure some aspects of the GitHub Actions-based CI on a
+per-repository basis by setting "variables" and "secrets" from with the
+GitHub web interface. These can be found at:
+
+  https://github.com/<user>/git/settings/secrets/actions
+
+The following variables can be used:
+
+ - CI_BRANCHES
+
+   By default, CI is run when any branch is pushed. If this variable is
+   non-empty, then only the branches it lists will run CI. Branch names
+   should be separated by spaces, and should use their shortened form
+   (e.g., "main", not "refs/heads/main").
diff --git a/ci/install-dependencies.sh b/ci/install-dependencies.sh
new file mode 100755
index 0000000000..d1cb9fa878
--- /dev/null
+++ b/ci/install-dependencies.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+#
+# Install dependencies required to build and test Git on Linux and macOS
+#
+
+. ${0%/*}/lib.sh
+
+begin_group "Install dependencies"
+
+P4WHENCE=https://cdist2.perforce.com/perforce/r23.2
+LFSWHENCE=https://github.com/github/git-lfs/releases/download/v$LINUX_GIT_LFS_VERSION
+JGITWHENCE=https://repo.eclipse.org/content/groups/releases//org/eclipse/jgit/org.eclipse.jgit.pgm/6.8.0.202311291450-r/org.eclipse.jgit.pgm-6.8.0.202311291450-r.sh
+
+# Make sudo a no-op and execute the command directly when running as root.
+# While using sudo would be fine on most platforms when we are root already,
+# some platforms like e.g. Alpine Linux do not have sudo available by default
+# and would thus break.
+if test "$(id -u)" -eq 0
+then
+	sudo () {
+		"$@"
+	}
+fi
+
+case "$distro" in
+alpine-*)
+	apk add --update shadow sudo build-base curl-dev openssl-dev expat-dev gettext \
+		pcre2-dev python3 musl-libintl perl-utils ncurses \
+		apache2 apache2-http2 apache2-proxy apache2-ssl apache2-webdav apr-util-dbd_sqlite3 \
+		bash cvs gnupg perl-cgi perl-dbd-sqlite perl-io-tty >/dev/null
+	;;
+fedora-*|almalinux-*)
+	dnf -yq update >/dev/null &&
+	dnf -yq install make gcc findutils diffutils perl python3 gettext zlib-devel expat-devel openssl-devel curl-devel pcre2-devel >/dev/null
+	;;
+ubuntu-*|ubuntu32-*|debian-*)
+	# Required so that apt doesn't wait for user input on certain packages.
+	export DEBIAN_FRONTEND=noninteractive
+
+	case "$distro" in
+	ubuntu-*)
+		SVN='libsvn-perl subversion'
+		LANGUAGES='language-pack-is'
+		;;
+	ubuntu32-*)
+		SVN=
+		LANGUAGES='language-pack-is'
+		;;
+	*)
+		SVN='libsvn-perl subversion'
+		LANGUAGES='locales-all'
+		;;
+	esac
+
+	sudo apt-get -q update
+	sudo apt-get -q -y install \
+		$LANGUAGES apache2 cvs cvsps git gnupg $SVN \
+		make libssl-dev libcurl4-openssl-dev libexpat-dev wget sudo default-jre \
+		tcl tk gettext zlib1g-dev perl-modules liberror-perl libauthen-sasl-perl \
+		libemail-valid-perl libio-pty-perl libio-socket-ssl-perl libnet-smtp-ssl-perl libdbd-sqlite3-perl libcgi-pm-perl \
+		libpcre2-dev meson ninja-build pkg-config \
+		${CC_PACKAGE:-${CC:-gcc}} $PYTHON_PACKAGE
+
+	case "$distro" in
+	ubuntu-*)
+		mkdir --parents "$CUSTOM_PATH"
+
+		wget --quiet --directory-prefix="$CUSTOM_PATH" \
+			"$P4WHENCE/bin.linux26x86_64/p4d" "$P4WHENCE/bin.linux26x86_64/p4"
+		chmod a+x "$CUSTOM_PATH/p4d" "$CUSTOM_PATH/p4"
+
+		wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
+		tar -xzf "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz" \
+			-C "$CUSTOM_PATH" --strip-components=1 "git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs"
+		rm "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
+
+		wget --quiet "$JGITWHENCE" --output-document="$CUSTOM_PATH/jgit"
+		chmod a+x "$CUSTOM_PATH/jgit"
+		;;
+	esac
+	;;
+macos-*)
+	export HOMEBREW_NO_AUTO_UPDATE=1 HOMEBREW_NO_INSTALL_CLEANUP=1
+	# Uncomment this if you want to run perf tests:
+	# brew install gnu-time
+	brew link --force gettext
+
+	mkdir -p "$CUSTOM_PATH"
+	wget -q "$P4WHENCE/bin.macosx1015x86_64/helix-core-server.tgz" &&
+	tar -xf helix-core-server.tgz -C "$CUSTOM_PATH" p4 p4d &&
+	sudo xattr -d com.apple.quarantine "$CUSTOM_PATH/p4" "$CUSTOM_PATH/p4d" 2>/dev/null || true
+	rm helix-core-server.tgz
+
+	case "$jobname" in
+	osx-meson)
+		brew install meson ninja pcre2
+		;;
+	esac
+
+	if test -n "$CC_PACKAGE"
+	then
+		BREW_PACKAGE=${CC_PACKAGE/-/@}
+		brew install "$BREW_PACKAGE"
+		brew link "$BREW_PACKAGE"
+	fi
+	;;
+esac
+
+case "$jobname" in
+ClangFormat)
+	sudo apt-get -q update
+	sudo apt-get -q -y install clang-format
+	;;
+StaticAnalysis)
+	sudo apt-get -q update
+	sudo apt-get -q -y install coccinelle libcurl4-openssl-dev libssl-dev \
+		libexpat-dev gettext make
+	;;
+sparse)
+	sudo apt-get -q update -q
+	sudo apt-get -q -y install libssl-dev libcurl4-openssl-dev \
+		libexpat-dev gettext zlib1g-dev
+	;;
+Documentation)
+	sudo apt-get -q update
+	sudo apt-get -q -y install asciidoc xmlto docbook-xsl-ns make
+
+	test -n "$ALREADY_HAVE_ASCIIDOCTOR" ||
+	sudo gem install --version 1.5.8 asciidoctor
+	sudo gem install concurrent-ruby
+	;;
+esac
+
+if type p4d >/dev/null 2>&1 && type p4 >/dev/null 2>&1
+then
+	echo "$(tput setaf 6)Perforce Server Version$(tput sgr0)"
+	p4d -V
+	echo "$(tput setaf 6)Perforce Client Version$(tput sgr0)"
+	p4 -V
+else
+	echo >&2 "WARNING: perforce wasn't installed, see above for clues why"
+fi
+
+if type git-lfs >/dev/null 2>&1
+then
+	echo "$(tput setaf 6)Git-LFS Version$(tput sgr0)"
+	git-lfs version
+else
+	echo >&2 "WARNING: git-lfs wasn't installed, see above for clues why"
+fi
+
+if type jgit >/dev/null 2>&1
+then
+	echo "$(tput setaf 6)JGit Version$(tput sgr0)"
+	jgit version
+else
+	echo >&2 "WARNING: JGit wasn't installed, see above for clues why"
+fi
+
+end_group "Install dependencies"
diff --git a/ci/install-sdk.ps1 b/ci/install-sdk.ps1
new file mode 100755
index 0000000000..66f24838a4
--- /dev/null
+++ b/ci/install-sdk.ps1
@@ -0,0 +1,12 @@
+param(
+    [string]$directory='git-sdk',
+    [string]$url='https://github.com/git-for-windows/git-sdk-64/releases/download/ci-artifacts/git-sdk-x86_64-minimal.zip'
+)
+
+Invoke-WebRequest "$url" -OutFile git-sdk.zip
+Expand-Archive -LiteralPath git-sdk.zip -DestinationPath "$directory"
+Remove-Item -Path git-sdk.zip
+
+New-Item -Path .git/info -ItemType Directory -Force
+New-Item -Path .git/info/exclude -ItemType File -Force
+Add-Content -Path .git/info/exclude -Value "/$directory"
diff --git a/ci/lib.sh b/ci/lib.sh
new file mode 100755
index 0000000000..8885ee3c3f
--- /dev/null
+++ b/ci/lib.sh
@@ -0,0 +1,399 @@
+# Library of functions shared by all CI scripts
+
+if test true = "$GITHUB_ACTIONS"
+then
+	begin_group () {
+		need_to_end_group=t
+		echo "::group::$1" >&2
+		set -x
+	}
+
+	end_group () {
+		test -n "$need_to_end_group" || return 0
+		set +x
+		need_to_end_group=
+		echo '::endgroup::' >&2
+	}
+elif test true = "$GITLAB_CI"
+then
+	begin_group () {
+		need_to_end_group=t
+		printf '\e[0Ksection_start:%s:%s[collapsed=true]\r\e[0K%s\n' \
+			"$(date +%s)" "$(echo "$1" | tr ' ' _)" "$1"
+		trap "end_group '$1'" EXIT
+		set -x
+	}
+
+	end_group () {
+		test -n "$need_to_end_group" || return 0
+		set +x
+		need_to_end_group=
+		printf '\e[0Ksection_end:%s:%s\r\e[0K\n' \
+			"$(date +%s)" "$(echo "$1" | tr ' ' _)"
+		trap - EXIT
+	}
+else
+	begin_group () { :; }
+	end_group () { :; }
+
+	set -x
+fi
+
+group () {
+	group="$1"
+	shift
+	begin_group "$group"
+
+	# work around `dash` not supporting `set -o pipefail`
+	(
+		"$@" 2>&1
+		echo $? >exit.status
+	) |
+	sed 's/^\(\([^ ]*\):\([0-9]*\):\([0-9]*:\) \)\(error\|warning\): /::\5 file=\2,line=\3::\1/'
+	res=$(cat exit.status)
+	rm exit.status
+
+	end_group "$group"
+	return $res
+}
+
+begin_group "CI setup via $(basename $0)"
+
+# Set 'exit on error' for all CI scripts to let the caller know that
+# something went wrong.
+#
+# We already enabled tracing executed commands earlier. This helps by showing
+# how # environment variables are set and dependencies are installed.
+set -e
+
+skip_branch_tip_with_tag () {
+	# Sometimes, a branch is pushed at the same time the tag that points
+	# at the same commit as the tip of the branch is pushed, and building
+	# both at the same time is a waste.
+	#
+	# When the build is triggered by a push to a tag, $CI_BRANCH will
+	# have that tagname, e.g. v2.14.0.  Let's see if $CI_BRANCH is
+	# exactly at a tag, and if so, if it is different from $CI_BRANCH.
+	# That way, we can tell if we are building the tip of a branch that
+	# is tagged and we can skip the build because we won't be skipping a
+	# build of a tag.
+
+	if TAG=$(git describe --exact-match "$CI_BRANCH" 2>/dev/null) &&
+		test "$TAG" != "$CI_BRANCH"
+	then
+		echo "$(tput setaf 2)Tip of $CI_BRANCH is exactly at $TAG$(tput sgr0)"
+		exit 0
+	fi
+}
+
+# Check whether we can use the path passed via the first argument as Git
+# repository.
+is_usable_git_repository () {
+	# We require Git in our PATH, otherwise we cannot access repositories
+	# at all.
+	if ! command -v git >/dev/null
+	then
+		return 1
+	fi
+
+	# And the target directory needs to be a proper Git repository.
+	if ! git -C "$1" rev-parse 2>/dev/null
+	then
+		return 1
+	fi
+}
+
+# Save some info about the current commit's tree, so we can skip the build
+# job if we encounter the same tree again and can provide a useful info
+# message.
+save_good_tree () {
+	if ! is_usable_git_repository .
+	then
+		return
+	fi
+
+	echo "$(git rev-parse $CI_COMMIT^{tree}) $CI_COMMIT $CI_JOB_NUMBER $CI_JOB_ID" >>"$good_trees_file"
+	# limit the file size
+	tail -1000 "$good_trees_file" >"$good_trees_file".tmp
+	mv "$good_trees_file".tmp "$good_trees_file"
+}
+
+# Skip the build job if the same tree has already been built and tested
+# successfully before (e.g. because the branch got rebased, changing only
+# the commit messages).
+skip_good_tree () {
+	if test true = "$GITHUB_ACTIONS"
+	then
+		return
+	fi
+
+	if ! is_usable_git_repository .
+	then
+		return
+	fi
+
+	if ! good_tree_info="$(grep "^$(git rev-parse $CI_COMMIT^{tree}) " "$good_trees_file")"
+	then
+		# Haven't seen this tree yet, or no cached good trees file yet.
+		# Continue the build job.
+		return
+	fi
+
+	echo "$good_tree_info" | {
+		read tree prev_good_commit prev_good_job_number prev_good_job_id
+
+		if test "$CI_JOB_ID" = "$prev_good_job_id"
+		then
+			cat <<-EOF
+			$(tput setaf 2)Skipping build job for commit $CI_COMMIT.$(tput sgr0)
+			This commit has already been built and tested successfully by this build job.
+			To force a re-build delete the branch's cache and then hit 'Restart job'.
+			EOF
+		else
+			cat <<-EOF
+			$(tput setaf 2)Skipping build job for commit $CI_COMMIT.$(tput sgr0)
+			This commit's tree has already been built and tested successfully in build job $prev_good_job_number for commit $prev_good_commit.
+			The log of that build job is available at $SYSTEM_TASKDEFINITIONSURI$SYSTEM_TEAMPROJECT/_build/results?buildId=$prev_good_job_id
+			To force a re-build delete the branch's cache and then hit 'Restart job'.
+			EOF
+		fi
+	}
+
+	exit 0
+}
+
+check_unignored_build_artifacts () {
+	if ! is_usable_git_repository .
+	then
+		return
+	fi
+
+	! git ls-files --other --exclude-standard --error-unmatch \
+		-- ':/*' 2>/dev/null ||
+	{
+		echo "$(tput setaf 1)error: found unignored build artifacts$(tput sgr0)"
+		false
+	}
+}
+
+handle_failed_tests () {
+	return 1
+}
+
+create_failed_test_artifacts () {
+	mkdir -p "${TEST_OUTPUT_DIRECTORY:-t}"/failed-test-artifacts
+
+	for test_exit in "${TEST_OUTPUT_DIRECTORY:-t}"/test-results/*.exit
+	do
+		test 0 != "$(cat "$test_exit")" || continue
+
+		test_name="${test_exit%.exit}"
+		test_name="${test_name##*/}"
+		printf "\\e[33m\\e[1m=== Failed test: ${test_name} ===\\e[m\\n"
+		echo "The full logs are in the 'print test failures' step below."
+		echo "See also the 'failed-tests-*' artifacts attached to this run."
+		cat "${TEST_OUTPUT_DIRECTORY:-t}/test-results/$test_name.markup"
+
+		trash_dir="${TEST_OUTPUT_DIRECTORY:-t}/trash directory.$test_name"
+		cp "${TEST_OUTPUT_DIRECTORY:-t}/test-results/$test_name.out" "${TEST_OUTPUT_DIRECTORY:-t}"/failed-test-artifacts/
+		tar czf "${TEST_OUTPUT_DIRECTORY:-t}/failed-test-artifacts/$test_name.trash.tar.gz" "$trash_dir"
+	done
+}
+
+# GitHub Action doesn't set TERM, which is required by tput
+export TERM=${TERM:-dumb}
+
+# Clear MAKEFLAGS that may come from the outside world.
+export MAKEFLAGS=
+
+if test -n "$SYSTEM_COLLECTIONURI" || test -n "$SYSTEM_TASKDEFINITIONSURI"
+then
+	CI_TYPE=azure-pipelines
+	# We are running in Azure Pipelines
+	CI_BRANCH="$BUILD_SOURCEBRANCH"
+	CI_COMMIT="$BUILD_SOURCEVERSION"
+	CI_JOB_ID="$BUILD_BUILDID"
+	CI_JOB_NUMBER="$BUILD_BUILDNUMBER"
+	CI_OS_NAME="$(echo "$AGENT_OS" | tr A-Z a-z)"
+	test darwin != "$CI_OS_NAME" || CI_OS_NAME=osx
+	CI_REPO_SLUG="$(expr "$BUILD_REPOSITORY_URI" : '.*/\([^/]*/[^/]*\)$')"
+	CC="${CC:-gcc}"
+
+	# use a subdirectory of the cache dir (because the file share is shared
+	# among *all* phases)
+	cache_dir="$HOME/test-cache/$SYSTEM_PHASENAME"
+
+	GIT_TEST_OPTS="--write-junit-xml"
+	JOBS=10
+elif test true = "$GITHUB_ACTIONS"
+then
+	CI_TYPE=github-actions
+	CI_BRANCH="$GITHUB_REF"
+	CI_COMMIT="$GITHUB_SHA"
+	CI_OS_NAME="$(echo "$RUNNER_OS" | tr A-Z a-z)"
+	test macos != "$CI_OS_NAME" || CI_OS_NAME=osx
+	CI_REPO_SLUG="$GITHUB_REPOSITORY"
+	CI_JOB_ID="$GITHUB_RUN_ID"
+	CC="${CC_PACKAGE:-${CC:-gcc}}"
+	DONT_SKIP_TAGS=t
+	handle_failed_tests () {
+		echo "FAILED_TEST_ARTIFACTS=${TEST_OUTPUT_DIRECTORY:-t}/failed-test-artifacts" >>$GITHUB_ENV
+		create_failed_test_artifacts
+		return 1
+	}
+
+	cache_dir="$HOME/none"
+
+	GIT_TEST_OPTS="--github-workflow-markup"
+	JOBS=10
+elif test true = "$GITLAB_CI"
+then
+	CI_TYPE=gitlab-ci
+	CI_BRANCH="$CI_COMMIT_REF_NAME"
+	CI_COMMIT="$CI_COMMIT_SHA"
+
+	case "$OS,$CI_JOB_IMAGE" in
+	Windows_NT,*)
+		CI_OS_NAME=windows
+		JOBS=$NUMBER_OF_PROCESSORS
+		;;
+	*,macos-*)
+		# GitLab CI has Python installed via multiple package managers,
+		# most notably via asdf and Homebrew. Ensure that our builds
+		# pick up the Homebrew one by prepending it to our PATH as the
+		# asdf one breaks tests.
+		export PATH="$(brew --prefix)/bin:$PATH"
+
+		CI_OS_NAME=osx
+		JOBS=$(nproc)
+		;;
+	*,alpine:*|*,fedora:*|*,ubuntu:*)
+		CI_OS_NAME=linux
+		JOBS=$(nproc)
+		;;
+	*)
+		echo "Could not identify OS image" >&2
+		env >&2
+		exit 1
+		;;
+	esac
+	CI_REPO_SLUG="$CI_PROJECT_PATH"
+	CI_JOB_ID="$CI_JOB_ID"
+	CC="${CC_PACKAGE:-${CC:-gcc}}"
+	DONT_SKIP_TAGS=t
+
+	handle_failed_tests () {
+		create_failed_test_artifacts
+		return 1
+	}
+
+	cache_dir="$HOME/none"
+
+	distro=$(echo "$CI_JOB_IMAGE" | tr : -)
+else
+	echo "Could not identify CI type" >&2
+	env >&2
+	exit 1
+fi
+
+MAKEFLAGS="$MAKEFLAGS --jobs=$JOBS"
+GIT_PROVE_OPTS="--timer --jobs $JOBS"
+
+GIT_TEST_OPTS="$GIT_TEST_OPTS --verbose-log -x"
+case "$CI_OS_NAME" in
+windows|windows_nt)
+	GIT_TEST_OPTS="$GIT_TEST_OPTS --no-chain-lint --no-bin-wrappers"
+	;;
+esac
+
+export GIT_TEST_OPTS
+export GIT_PROVE_OPTS
+
+good_trees_file="$cache_dir/good-trees"
+
+mkdir -p "$cache_dir"
+
+test -n "${DONT_SKIP_TAGS-}" ||
+skip_branch_tip_with_tag
+skip_good_tree
+
+if test -z "$jobname"
+then
+	jobname="$CI_OS_NAME-$CC"
+fi
+
+export DEVELOPER=1
+export DEFAULT_TEST_TARGET=prove
+export GIT_TEST_CLONE_2GB=true
+export SKIP_DASHED_BUILT_INS=YesPlease
+
+case "$distro" in
+ubuntu-*)
+	if test "$jobname" = "linux-gcc-default"
+	then
+		break
+	fi
+
+	# Python 2 is end of life, and Ubuntu 23.04 and newer don't actually
+	# have it anymore. We thus only test with Python 2 on older LTS
+	# releases.
+	if test "$distro" = "ubuntu-20.04"
+	then
+		PYTHON_PACKAGE=python2
+	else
+		PYTHON_PACKAGE=python3
+	fi
+	MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/$PYTHON_PACKAGE"
+
+	case "$distro" in
+	ubuntu-16.04)
+		# Apache is too old for HTTP/2.
+		;;
+	*)
+		export GIT_TEST_HTTPD=true
+		;;
+	esac
+
+	# The Linux build installs the defined dependency versions below.
+	# The OS X build installs much more recent versions, whichever
+	# were recorded in the Homebrew database upon creating the OS X
+	# image.
+	# Keep that in mind when you encounter a broken OS X build!
+	export LINUX_GIT_LFS_VERSION="1.5.2"
+	;;
+macos-*)
+	MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=$(which python3)"
+	if [ "$jobname" != osx-gcc ]
+	then
+		MAKEFLAGS="$MAKEFLAGS APPLE_COMMON_CRYPTO_SHA1=Yes"
+	fi
+	;;
+esac
+
+CUSTOM_PATH="${CUSTOM_PATH:-$HOME/path}"
+export PATH="$CUSTOM_PATH:$PATH"
+
+case "$jobname" in
+linux32)
+	CC=gcc
+	;;
+linux-musl)
+	CC=gcc
+	MAKEFLAGS="$MAKEFLAGS PYTHON_PATH=/usr/bin/python3 USE_LIBPCRE2=Yes"
+	MAKEFLAGS="$MAKEFLAGS NO_REGEX=Yes ICONV_OMITS_BOM=Yes"
+	MAKEFLAGS="$MAKEFLAGS GIT_TEST_UTF8_LOCALE=C.UTF-8"
+	;;
+linux-leaks|linux-reftable-leaks)
+	export SANITIZE=leak
+	;;
+linux-asan-ubsan)
+	export SANITIZE=address,undefined
+	export NO_SVN_TESTS=LetsSaveSomeTime
+	MAKEFLAGS="$MAKEFLAGS NO_PYTHON=YepBecauseP4FlakesTooOften"
+	;;
+esac
+
+MAKEFLAGS="$MAKEFLAGS CC=${CC:-cc}"
+
+end_group "CI setup via $(basename $0)"
+set -x
diff --git a/ci/make-test-artifacts.sh b/ci/make-test-artifacts.sh
new file mode 100755
index 0000000000..74141af0cc
--- /dev/null
+++ b/ci/make-test-artifacts.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# Build Git and store artifacts for testing
+#
+
+mkdir -p "$1" # in case ci/lib.sh decides to quit early
+
+. ${0%/*}/lib.sh
+
+group Build make artifacts-tar ARTIFACTS_DIRECTORY="$1"
+
+check_unignored_build_artifacts
diff --git a/ci/mount-fileshare.sh b/ci/mount-fileshare.sh
new file mode 100755
index 0000000000..26b58a8096
--- /dev/null
+++ b/ci/mount-fileshare.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+die () {
+	echo "$*" >&2
+	exit 1
+}
+
+test $# = 4 ||
+die "Usage: $0 <share> <username> <password> <mountpoint>"
+
+mkdir -p "$4" || die "Could not create $4"
+
+case "$(uname -s)" in
+Linux)
+	sudo mount -t cifs -o vers=3.0,username="$2",password="$3",dir_mode=0777,file_mode=0777,serverino "$1" "$4"
+	;;
+Darwin)
+	pass="$(echo "$3" | sed -e 's/\//%2F/g' -e 's/+/%2B/g')" &&
+	mount -t smbfs,soft "smb://$2:$pass@${1#//}" "$4"
+	;;
+*)
+	die "No support for $(uname -s)"
+	;;
+esac ||
+die "Could not mount $4"
diff --git a/ci/print-test-failures.sh b/ci/print-test-failures.sh
new file mode 100755
index 0000000000..655687dd82
--- /dev/null
+++ b/ci/print-test-failures.sh
@@ -0,0 +1,94 @@
+#!/bin/sh
+#
+# Print output of failing tests
+#
+
+. ${0%/*}/lib.sh
+
+# Tracing executed commands would produce too much noise in the loop below.
+set +x
+
+cd "${TEST_OUTPUT_DIRECTORY:-t/}"
+
+if ! ls test-results/*.exit >/dev/null 2>/dev/null
+then
+	echo "Build job failed before the tests could have been run"
+	exit
+fi
+
+case "$jobname" in
+osx-clang|osx-gcc)
+	# base64 in OSX doesn't wrap its output at 76 columns by
+	# default, but prints a single, very long line.
+	base64_opts="-b 76"
+	;;
+esac
+
+combined_trash_size=0
+for TEST_EXIT in test-results/*.exit
+do
+	if [ "$(cat "$TEST_EXIT")" != "0" ]
+	then
+		TEST_OUT="${TEST_EXIT%exit}out"
+		echo "------------------------------------------------------------------------"
+		echo "$(tput setaf 1)${TEST_OUT}...$(tput sgr0)"
+		echo "------------------------------------------------------------------------"
+		cat "${TEST_OUT}"
+
+		test_name="${TEST_EXIT%.exit}"
+		test_name="${test_name##*/}"
+		trash_dir="trash directory.$test_name"
+		case "$CI_TYPE" in
+		azure-pipelines)
+			mkdir -p failed-test-artifacts
+			mv "$trash_dir" failed-test-artifacts
+			continue
+			;;
+		github-actions)
+			mkdir -p failed-test-artifacts
+			echo "FAILED_TEST_ARTIFACTS=${TEST_OUTPUT_DIRECTORY:t}/failed-test-artifacts" >>$GITHUB_ENV
+			cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/
+			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
+			continue
+			;;
+		gitlab-ci)
+			mkdir -p failed-test-artifacts
+			cp "${TEST_EXIT%.exit}.out" failed-test-artifacts/
+			tar czf failed-test-artifacts/"$test_name".trash.tar.gz "$trash_dir"
+			continue
+			;;
+		*)
+			echo "Unhandled CI type: $CI_TYPE" >&2
+			exit 1
+			;;
+		esac
+		trash_tgz_b64="trash.$test_name.base64"
+		if [ -d "$trash_dir" ]
+		then
+			tar czp "$trash_dir" |base64 $base64_opts >"$trash_tgz_b64"
+
+			trash_size=$(wc -c <"$trash_tgz_b64")
+			if [ $trash_size -gt 1048576 ]
+			then
+				# larger than 1MB
+				echo "$(tput setaf 1)Didn't include the trash directory of '$test_name' in the trace log, it's too big$(tput sgr0)"
+				continue
+			fi
+
+			new_combined_trash_size=$(($combined_trash_size + $trash_size))
+			if [ $new_combined_trash_size -gt 1048576 ]
+			then
+				echo "$(tput setaf 1)Didn't include the trash directory of '$test_name' in the trace log, there is plenty of trash in there already.$(tput sgr0)"
+				continue
+			fi
+			combined_trash_size=$new_combined_trash_size
+
+			# DO NOT modify these two 'echo'-ed strings below
+			# without updating 'ci/util/extract-trash-dirs.sh'
+			# as well.
+			echo "$(tput setaf 1)Start of trash directory of '$test_name':$(tput sgr0)"
+			cat "$trash_tgz_b64"
+			echo "$(tput setaf 1)End of trash directory of '$test_name'$(tput sgr0)"
+		fi
+	fi
+done
diff --git a/ci/run-build-and-minimal-fuzzers.sh b/ci/run-build-and-minimal-fuzzers.sh
new file mode 100755
index 0000000000..e7b97952e7
--- /dev/null
+++ b/ci/run-build-and-minimal-fuzzers.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# Build and test Git's fuzzers
+#
+
+. ${0%/*}/lib.sh
+
+group "Build fuzzers" make \
+	NO_CURL=NoThanks \
+	CC=clang \
+	FUZZ_CXX=clang++ \
+	CFLAGS="-fsanitize=fuzzer-no-link,address" \
+	LIB_FUZZING_ENGINE="-fsanitize=fuzzer,address" \
+	fuzz-all
+
+fuzzers="
+commit-graph
+config
+credential-from-url-gently
+date
+pack-headers
+pack-idx
+parse-attr-line
+url-decode-mem
+"
+
+for fuzzer in $fuzzers; do
+	begin_group "fuzz-$fuzzer"
+	./oss-fuzz/fuzz-$fuzzer -verbosity=0 -runs=1 || exit 1
+	end_group "fuzz-$fuzzer"
+done
diff --git a/ci/run-build-and-tests.sh b/ci/run-build-and-tests.sh
new file mode 100755
index 0000000000..76667a1277
--- /dev/null
+++ b/ci/run-build-and-tests.sh
@@ -0,0 +1,77 @@
+#!/bin/sh
+#
+# Build and test Git
+#
+
+. ${0%/*}/lib.sh
+
+case "$CI_OS_NAME" in
+windows*) cmd //c mklink //j t\\.prove "$(cygpath -aw "$cache_dir/.prove")";;
+*) ln -s "$cache_dir/.prove" t/.prove;;
+esac
+
+run_tests=t
+
+case "$jobname" in
+linux-gcc)
+	export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+	;;
+linux-TEST-vars)
+	export OPENSSL_SHA1_UNSAFE=YesPlease
+	export GIT_TEST_SPLIT_INDEX=yes
+	export GIT_TEST_MERGE_ALGORITHM=recursive
+	export GIT_TEST_FULL_IN_PACK_ARRAY=true
+	export GIT_TEST_OE_SIZE=10
+	export GIT_TEST_OE_DELTA_SIZE=5
+	export GIT_TEST_COMMIT_GRAPH=1
+	export GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1
+	export GIT_TEST_MULTI_PACK_INDEX=1
+	export GIT_TEST_MULTI_PACK_INDEX_WRITE_INCREMENTAL=1
+	export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master
+	export GIT_TEST_NO_WRITE_REV_INDEX=1
+	export GIT_TEST_CHECKOUT_WORKERS=2
+	export GIT_TEST_PACK_USE_BITMAP_BOUNDARY_TRAVERSAL=1
+	;;
+linux-clang)
+	export GIT_TEST_DEFAULT_HASH=sha1
+	;;
+linux-sha256)
+	export GIT_TEST_DEFAULT_HASH=sha256
+	;;
+linux-reftable|linux-reftable-leaks|osx-reftable)
+	export GIT_TEST_DEFAULT_REF_FORMAT=reftable
+	;;
+pedantic)
+	# Don't run the tests; we only care about whether Git can be
+	# built.
+	export DEVOPTS=pedantic
+	run_tests=
+	;;
+esac
+
+case "$jobname" in
+*-meson)
+	group "Configure" meson setup build . \
+		--warnlevel 2 --werror \
+		--wrap-mode nofallback
+	group "Build" meson compile -C build --
+	if test -n "$run_tests"
+	then
+		group "Run tests" meson test -C build --print-errorlogs --test-args="$GIT_TEST_OPTS" || (
+			./t/aggregate-results.sh "${TEST_OUTPUT_DIRECTORY:-t}/test-results"
+			handle_failed_tests
+		)
+	fi
+	;;
+*)
+	group Build make
+	if test -n "$run_tests"
+	then
+		group "Run tests" make test ||
+		handle_failed_tests
+	fi
+	;;
+esac
+
+check_unignored_build_artifacts
+save_good_tree
diff --git a/ci/run-static-analysis.sh b/ci/run-static-analysis.sh
new file mode 100755
index 0000000000..0d51e5ce0e
--- /dev/null
+++ b/ci/run-static-analysis.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# Perform various static code analysis checks
+#
+
+. ${0%/*}/lib.sh
+
+make coccicheck
+
+set +x
+
+fail=
+for cocci_patch in contrib/coccinelle/*.patch
+do
+	if test -s "$cocci_patch"
+	then
+		echo "$(tput setaf 1)Coccinelle suggests the following changes in '$cocci_patch':$(tput sgr0)"
+		cat "$cocci_patch"
+		fail=UnfortunatelyYes
+	fi
+done
+
+if test -n "$fail"
+then
+	echo "$(tput setaf 1)error: Coccinelle suggested some changes$(tput sgr0)"
+	exit 1
+fi
+
+make hdr-check ||
+exit 1
+
+make check-pot
+
+save_good_tree
diff --git a/ci/run-style-check.sh b/ci/run-style-check.sh
new file mode 100755
index 0000000000..6cd4b1d934
--- /dev/null
+++ b/ci/run-style-check.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Perform style check
+#
+
+baseCommit=$1
+
+# Remove optional braces of control statements (if, else, for, and while)
+# according to the LLVM coding style. This avoids braces on simple
+# single-statement bodies of statements but keeps braces if one side of
+# if/else if/.../else cascade has multi-statement body.
+#
+# As this rule comes with a warning [1], we want to experiment with it
+# before adding it in-tree. since the CI job for the style check is allowed
+# to fail, appending the rule here allows us to validate its efficacy.
+# While also ensuring that end-users are not affected directly.
+#
+# [1]: https://clang.llvm.org/docs/ClangFormatStyleOptions.html#removebracesllvm
+{
+	cat .clang-format
+	echo "RemoveBracesLLVM: true"
+} >/tmp/clang-format-rules
+
+git clang-format --style=file:/tmp/clang-format-rules \
+	--diff --extensions c,h "$baseCommit"
diff --git a/ci/run-test-slice.sh b/ci/run-test-slice.sh
new file mode 100755
index 0000000000..e167e646f7
--- /dev/null
+++ b/ci/run-test-slice.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# Test Git in parallel
+#
+
+. ${0%/*}/lib.sh
+
+case "$CI_OS_NAME" in
+windows*) cmd //c mklink //j t\\.prove "$(cygpath -aw "$cache_dir/.prove")";;
+*) ln -s "$cache_dir/.prove" t/.prove;;
+esac
+
+group "Run tests" make --quiet -C t T="$(cd t &&
+	./helper/test-tool path-utils slice-tests "$1" "$2" t[0-9]*.sh |
+	tr '\n' ' ')" ||
+handle_failed_tests
+
+# We only have one unit test at the moment, so run it in the first slice
+if [ "$1" == "0" ] ; then
+	group "Run unit tests" make --quiet -C t unit-tests-test-tool
+fi
+
+check_unignored_build_artifacts
diff --git a/ci/test-documentation.sh b/ci/test-documentation.sh
new file mode 100755
index 0000000000..6c018b673e
--- /dev/null
+++ b/ci/test-documentation.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+#
+# Perform sanity checks on documentation and build it.
+#
+
+. ${0%/*}/lib.sh
+
+filter_log () {
+	sed -e '/^GIT_VERSION=/d' \
+	    -e "/constant Gem::ConfigMap is deprecated/d" \
+	    -e '/^    \* new asciidoc flags$/d' \
+	    -e '/stripped namespace before processing/d' \
+	    -e '/Attributed.*IDs for element/d' \
+	    -e '/SyntaxWarning: invalid escape sequence/d' \
+	    "$1"
+}
+
+make check-builtins
+make check-docs
+
+# Build docs with AsciiDoc
+make doc > >(tee stdout.log) 2> >(tee stderr.raw >&2)
+cat stderr.raw
+filter_log stderr.raw >stderr.log
+test ! -s stderr.log
+test -s Documentation/git.html
+test -s Documentation/git.xml
+test -s Documentation/git.1
+grep '<meta name="generator" content="AsciiDoc ' Documentation/git.html
+
+rm -f stdout.log stderr.log stderr.raw
+check_unignored_build_artifacts
+
+# Build docs with AsciiDoctor
+make clean
+make USE_ASCIIDOCTOR=1 doc > >(tee stdout.log) 2> >(tee stderr.raw >&2)
+cat stderr.raw
+filter_log stderr.raw >stderr.log
+test ! -s stderr.log
+test -s Documentation/git.html
+grep '<meta name="generator" content="Asciidoctor ' Documentation/git.html
+
+rm -f stdout.log stderr.log stderr.raw
+check_unignored_build_artifacts
+
+save_good_tree
diff --git a/ci/util/extract-trash-dirs.sh b/ci/util/extract-trash-dirs.sh
new file mode 100755
index 0000000000..8e67bec21a
--- /dev/null
+++ b/ci/util/extract-trash-dirs.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+error () {
+	echo >&2 "error: $@"
+	exit 1
+}
+
+find_embedded_trash () {
+	while read -r line
+	do
+		case "$line" in
+		*Start\ of\ trash\ directory\ of\ \'t[0-9][0-9][0-9][0-9]-*\':*)
+			test_name="${line#*\'}"
+			test_name="${test_name%\'*}"
+
+			return 0
+		esac
+	done
+
+	return 1
+}
+
+extract_embedded_trash () {
+	while read -r line
+	do
+		case "$line" in
+		*End\ of\ trash\ directory\ of\ \'$test_name\'*)
+			return
+			;;
+		*)
+			printf '%s\n' "$line"
+			;;
+		esac
+	done
+
+	error "unexpected end of input"
+}
+
+# Raw logs from Linux build jobs have CRLF line endings, while OSX
+# build jobs mostly have CRCRLF, except an odd line every now and
+# then that has CRCRCRLF.  'base64 -d' from 'coreutils' doesn't like
+# CRs and complains about "invalid input", so remove all CRs at the
+# end of lines.
+sed -e 's/\r*$//' | \
+while find_embedded_trash
+do
+	echo "Extracting trash directory of '$test_name'"
+
+	extract_embedded_trash |base64 -d |tar xzp
+done
diff --git a/color.c b/color.c
new file mode 100644
index 0000000000..7df8862c71
--- /dev/null
+++ b/color.c
@@ -0,0 +1,489 @@
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "color.h"
+#include "editor.h"
+#include "gettext.h"
+#include "hex-ll.h"
+#include "pager.h"
+#include "strbuf.h"
+
+static int git_use_color_default = GIT_COLOR_AUTO;
+int color_stdout_is_tty = -1;
+
+/*
+ * The list of available column colors.
+ */
+const char *column_colors_ansi[] = {
+	GIT_COLOR_RED,
+	GIT_COLOR_GREEN,
+	GIT_COLOR_YELLOW,
+	GIT_COLOR_BLUE,
+	GIT_COLOR_MAGENTA,
+	GIT_COLOR_CYAN,
+	GIT_COLOR_BOLD_RED,
+	GIT_COLOR_BOLD_GREEN,
+	GIT_COLOR_BOLD_YELLOW,
+	GIT_COLOR_BOLD_BLUE,
+	GIT_COLOR_BOLD_MAGENTA,
+	GIT_COLOR_BOLD_CYAN,
+	GIT_COLOR_RESET,
+};
+
+enum {
+	COLOR_BACKGROUND_OFFSET = 10,
+	COLOR_FOREGROUND_ANSI = 30,
+	COLOR_FOREGROUND_RGB = 38,
+	COLOR_FOREGROUND_256 = 38,
+	COLOR_FOREGROUND_BRIGHT_ANSI = 90,
+};
+
+/* Ignore the RESET at the end when giving the size */
+const int column_colors_ansi_max = ARRAY_SIZE(column_colors_ansi) - 1;
+
+/* An individual foreground or background color. */
+struct color {
+	enum {
+		COLOR_UNSPECIFIED = 0,
+		COLOR_NORMAL,
+		COLOR_ANSI, /* basic 0-7 ANSI colors + "default" (value = 9) */
+		COLOR_256,
+		COLOR_RGB
+	} type;
+	/* The numeric value for ANSI and 256-color modes */
+	unsigned char value;
+	/* 24-bit RGB color values */
+	unsigned char red, green, blue;
+};
+
+/*
+ * "word" is a buffer of length "len"; does it match the NUL-terminated
+ * "match" exactly?
+ */
+static int match_word(const char *word, int len, const char *match)
+{
+	return !strncasecmp(word, match, len) && !match[len];
+}
+
+static int get_hex_color(const char **inp, int width, unsigned char *out)
+{
+	const char *in = *inp;
+	unsigned int val;
+
+	assert(width == 1 || width == 2);
+	val = (hexval(in[0]) << 4) | hexval(in[width - 1]);
+	if (val & ~0xff)
+		return -1;
+	*inp += width;
+	*out = val;
+	return 0;
+}
+
+/*
+ * If an ANSI color is recognized in "name", fill "out" and return 0.
+ * Otherwise, leave out unchanged and return -1.
+ */
+static int parse_ansi_color(struct color *out, const char *name, int len)
+{
+	/* Positions in array must match ANSI color codes */
+	static const char * const color_names[] = {
+		"black", "red", "green", "yellow",
+		"blue", "magenta", "cyan", "white"
+	};
+	int i;
+	int color_offset = COLOR_FOREGROUND_ANSI;
+
+	if (match_word(name, len, "default")) {
+		/*
+		 * Restores to the terminal's default color, which may not be
+		 * the same as explicitly setting "white" or "black".
+		 *
+		 * ECMA-48 - Control Functions \
+		 *  for Coded Character Sets, 5th edition (June 1991):
+		 * > 39 default display colour (implementation-defined)
+		 * > 49 default background colour (implementation-defined)
+		 *
+		 * Although not supported /everywhere/--according to terminfo,
+		 * some terminals define "op" (original pair) as a blunt
+		 * "set to white on black", or even "send full SGR reset"--
+		 * it's standard and well-supported enough that if a user
+		 * asks for it in their config this will do the right thing.
+		 */
+		out->type = COLOR_ANSI;
+		out->value = 9 + color_offset;
+		return 0;
+	}
+
+	if (strncasecmp(name, "bright", 6) == 0) {
+		color_offset = COLOR_FOREGROUND_BRIGHT_ANSI;
+		name += 6;
+		len -= 6;
+	}
+	for (i = 0; i < ARRAY_SIZE(color_names); i++) {
+		if (match_word(name, len, color_names[i])) {
+			out->type = COLOR_ANSI;
+			out->value = i + color_offset;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+static int parse_color(struct color *out, const char *name, int len)
+{
+	char *end;
+	long val;
+
+	/* First try the special word "normal"... */
+	if (match_word(name, len, "normal")) {
+		out->type = COLOR_NORMAL;
+		return 0;
+	}
+
+	/* Try a 24- or 12-bit RGB value prefixed with '#' */
+	if ((len == 7 || len == 4) && name[0] == '#') {
+		int width_per_color = (len == 7) ? 2 : 1;
+		const char *color = name + 1;
+
+		if (!get_hex_color(&color, width_per_color, &out->red) &&
+		    !get_hex_color(&color, width_per_color, &out->green) &&
+		    !get_hex_color(&color, width_per_color, &out->blue)) {
+			out->type = COLOR_RGB;
+			return 0;
+		}
+	}
+
+	/* Then pick from our human-readable color names... */
+	if (parse_ansi_color(out, name, len) == 0) {
+		return 0;
+	}
+
+	/* And finally try a literal 256-color-mode number */
+	val = strtol(name, &end, 10);
+	if (end - name == len) {
+		/*
+		 * Allow "-1" as an alias for "normal", but other negative
+		 * numbers are bogus.
+		 */
+		if (val < -1)
+			; /* fall through to error */
+		else if (val < 0) {
+			out->type = COLOR_NORMAL;
+			return 0;
+		/* Rewrite 0-7 as more-portable standard colors. */
+		} else if (val < 8) {
+			out->type = COLOR_ANSI;
+			out->value = val + COLOR_FOREGROUND_ANSI;
+			return 0;
+		/* Rewrite 8-15 as more-portable aixterm colors. */
+		} else if (val < 16) {
+			out->type = COLOR_ANSI;
+			out->value = val - 8 + COLOR_FOREGROUND_BRIGHT_ANSI;
+			return 0;
+		} else if (val < 256) {
+			out->type = COLOR_256;
+			out->value = val;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+static int parse_attr(const char *name, size_t len)
+{
+	static const struct {
+		const char *name;
+		size_t len;
+		int val, neg;
+	} attrs[] = {
+#define ATTR(x, val, neg) { (x), sizeof(x)-1, (val), (neg) }
+		ATTR("bold",      1, 22),
+		ATTR("dim",       2, 22),
+		ATTR("italic",    3, 23),
+		ATTR("ul",        4, 24),
+		ATTR("blink",     5, 25),
+		ATTR("reverse",   7, 27),
+		ATTR("strike",    9, 29)
+#undef ATTR
+	};
+	int negate = 0;
+	int i;
+
+	if (skip_prefix_mem(name, len, "no", &name, &len)) {
+		skip_prefix_mem(name, len, "-", &name, &len);
+		negate = 1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(attrs); i++) {
+		if (attrs[i].len == len && !memcmp(attrs[i].name, name, len))
+			return negate ? attrs[i].neg : attrs[i].val;
+	}
+	return -1;
+}
+
+int color_parse(const char *value, char *dst)
+{
+	return color_parse_mem(value, strlen(value), dst);
+}
+
+/*
+ * Write the ANSI color codes for "c" to "out"; the string should
+ * already have the ANSI escape code in it. "out" should have enough
+ * space in it to fit any color.
+ */
+static char *color_output(char *out, int len, const struct color *c, int background)
+{
+	int offset = 0;
+
+	if (background)
+		offset = COLOR_BACKGROUND_OFFSET;
+	switch (c->type) {
+	case COLOR_UNSPECIFIED:
+	case COLOR_NORMAL:
+		break;
+	case COLOR_ANSI:
+		out += xsnprintf(out, len, "%d", c->value + offset);
+		break;
+	case COLOR_256:
+		out += xsnprintf(out, len, "%d;5;%d", COLOR_FOREGROUND_256 + offset,
+				 c->value);
+		break;
+	case COLOR_RGB:
+		out += xsnprintf(out, len, "%d;2;%d;%d;%d",
+				 COLOR_FOREGROUND_RGB + offset,
+				 c->red, c->green, c->blue);
+		break;
+	}
+	return out;
+}
+
+static int color_empty(const struct color *c)
+{
+	return c->type <= COLOR_NORMAL;
+}
+
+int color_parse_mem(const char *value, int value_len, char *dst)
+{
+	const char *ptr = value;
+	int len = value_len;
+	char *end = dst + COLOR_MAXLEN;
+	unsigned int has_reset = 0;
+	unsigned int attr = 0;
+	struct color fg = { COLOR_UNSPECIFIED };
+	struct color bg = { COLOR_UNSPECIFIED };
+
+	while (len > 0 && isspace(*ptr)) {
+		ptr++;
+		len--;
+	}
+
+	if (!len) {
+		dst[0] = '\0';
+		return 0;
+	}
+
+	/* [reset] [fg [bg]] [attr]... */
+	while (len > 0) {
+		const char *word = ptr;
+		struct color c = { COLOR_UNSPECIFIED };
+		int val, wordlen = 0;
+
+		while (len > 0 && !isspace(word[wordlen])) {
+			wordlen++;
+			len--;
+		}
+
+		ptr = word + wordlen;
+		while (len > 0 && isspace(*ptr)) {
+			ptr++;
+			len--;
+		}
+
+		if (match_word(word, wordlen, "reset")) {
+			has_reset = 1;
+			continue;
+		}
+
+		if (!parse_color(&c, word, wordlen)) {
+			if (fg.type == COLOR_UNSPECIFIED) {
+				fg = c;
+				continue;
+			}
+			if (bg.type == COLOR_UNSPECIFIED) {
+				bg = c;
+				continue;
+			}
+			goto bad;
+		}
+		val = parse_attr(word, wordlen);
+		if (0 <= val)
+			attr |= (1 << val);
+		else
+			goto bad;
+	}
+
+#undef OUT
+#define OUT(x) do { \
+	if (dst == end) \
+		BUG("color parsing ran out of space"); \
+	*dst++ = (x); \
+} while(0)
+
+	if (has_reset || attr || !color_empty(&fg) || !color_empty(&bg)) {
+		int sep = 0;
+		int i;
+
+		OUT('\033');
+		OUT('[');
+
+		if (has_reset)
+			sep++;
+
+		for (i = 0; attr; i++) {
+			unsigned bit = (1 << i);
+			if (!(attr & bit))
+				continue;
+			attr &= ~bit;
+			if (sep++)
+				OUT(';');
+			dst += xsnprintf(dst, end - dst, "%d", i);
+		}
+		if (!color_empty(&fg)) {
+			if (sep++)
+				OUT(';');
+			dst = color_output(dst, end - dst, &fg, 0);
+		}
+		if (!color_empty(&bg)) {
+			if (sep++)
+				OUT(';');
+			dst = color_output(dst, end - dst, &bg, 1);
+		}
+		OUT('m');
+	}
+	OUT(0);
+	return 0;
+bad:
+	return error(_("invalid color value: %.*s"), value_len, value);
+#undef OUT
+}
+
+int git_config_colorbool(const char *var, const char *value)
+{
+	if (value) {
+		if (!strcasecmp(value, "never"))
+			return 0;
+		if (!strcasecmp(value, "always"))
+			return 1;
+		if (!strcasecmp(value, "auto"))
+			return GIT_COLOR_AUTO;
+	}
+
+	if (!var)
+		return -1;
+
+	/* Missing or explicit false to turn off colorization */
+	if (!git_config_bool(var, value))
+		return 0;
+
+	/* any normal truth value defaults to 'auto' */
+	return GIT_COLOR_AUTO;
+}
+
+static int check_auto_color(int fd)
+{
+	static int color_stderr_is_tty = -1;
+	int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
+	if (*is_tty_p < 0)
+		*is_tty_p = isatty(fd);
+	if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
+		if (!is_terminal_dumb())
+			return 1;
+	}
+	return 0;
+}
+
+int want_color_fd(int fd, int var)
+{
+	/*
+	 * NEEDSWORK: This function is sometimes used from multiple threads, and
+	 * we end up using want_auto racily. That "should not matter" since
+	 * we always write the same value, but it's still wrong. This function
+	 * is listed in .tsan-suppressions for the time being.
+	 */
+
+	static int want_auto[3] = { -1, -1, -1 };
+
+	if (fd < 1 || fd >= ARRAY_SIZE(want_auto))
+		BUG("file descriptor out of range: %d", fd);
+
+	if (var < 0)
+		var = git_use_color_default;
+
+	if (var == GIT_COLOR_AUTO) {
+		if (want_auto[fd] < 0)
+			want_auto[fd] = check_auto_color(fd);
+		return want_auto[fd];
+	}
+	return var;
+}
+
+int git_color_config(const char *var, const char *value, void *cb UNUSED)
+{
+	if (!strcmp(var, "color.ui")) {
+		git_use_color_default = git_config_colorbool(var, value);
+		return 0;
+	}
+
+	return 0;
+}
+
+void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb)
+{
+	if (*color)
+		fprintf(fp, "%s", color);
+	fprintf(fp, "%s", sb->buf);
+	if (*color)
+		fprintf(fp, "%s", GIT_COLOR_RESET);
+}
+
+static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
+		va_list args, const char *trail)
+{
+	int r = 0;
+
+	if (*color)
+		r += fprintf(fp, "%s", color);
+	r += vfprintf(fp, fmt, args);
+	if (*color)
+		r += fprintf(fp, "%s", GIT_COLOR_RESET);
+	if (trail)
+		r += fprintf(fp, "%s", trail);
+	return r;
+}
+
+int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
+{
+	va_list args;
+	int r;
+	va_start(args, fmt);
+	r = color_vfprintf(fp, color, fmt, args, NULL);
+	va_end(args);
+	return r;
+}
+
+int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
+{
+	va_list args;
+	int r;
+	va_start(args, fmt);
+	r = color_vfprintf(fp, color, fmt, args, "\n");
+	va_end(args);
+	return r;
+}
+
+int color_is_nil(const char *c)
+{
+	return !strcmp(c, "NIL");
+}
diff --git a/color.h b/color.h
new file mode 100644
index 0000000000..7ed259a35b
--- /dev/null
+++ b/color.h
@@ -0,0 +1,140 @@
+#ifndef COLOR_H
+#define COLOR_H
+
+struct strbuf;
+
+/*
+ * The maximum length of ANSI color sequence we would generate:
+ * - leading ESC '['            2
+ * - reset ';' .................1
+ * - attr + ';'                 2 * num_attr (e.g. "1;")
+ * - no-attr + ';'              3 * num_attr (e.g. "22;")
+ * - fg color + ';'             17 (e.g. "38;2;255;255;255;")
+ * - bg color + ';'             17 (e.g. "48;2;255;255;255;")
+ * - terminating 'm' NUL        2
+ *
+ * The above overcounts by one semicolon but it is close enough.
+ *
+ * The space for attributes is also slightly overallocated, as
+ * the negation for some attributes is the same (e.g., nobold and nodim).
+ *
+ * We allocate space for 7 attributes.
+ */
+#define COLOR_MAXLEN 75
+
+#define GIT_COLOR_NORMAL	""
+#define GIT_COLOR_RESET		"\033[m"
+#define GIT_COLOR_BOLD		"\033[1m"
+#define GIT_COLOR_BLACK		"\033[30m"
+#define GIT_COLOR_RED		"\033[31m"
+#define GIT_COLOR_GREEN		"\033[32m"
+#define GIT_COLOR_YELLOW	"\033[33m"
+#define GIT_COLOR_BLUE		"\033[34m"
+#define GIT_COLOR_MAGENTA	"\033[35m"
+#define GIT_COLOR_CYAN		"\033[36m"
+#define GIT_COLOR_WHITE		"\033[37m"
+#define GIT_COLOR_DEFAULT	"\033[39m"
+#define GIT_COLOR_BOLD_BLACK	"\033[1;30m"
+#define GIT_COLOR_BOLD_RED	"\033[1;31m"
+#define GIT_COLOR_BOLD_GREEN	"\033[1;32m"
+#define GIT_COLOR_BOLD_YELLOW	"\033[1;33m"
+#define GIT_COLOR_BOLD_BLUE	"\033[1;34m"
+#define GIT_COLOR_BOLD_MAGENTA	"\033[1;35m"
+#define GIT_COLOR_BOLD_CYAN	"\033[1;36m"
+#define GIT_COLOR_BOLD_WHITE	"\033[1;37m"
+#define GIT_COLOR_BOLD_DEFAULT	"\033[1;39m"
+#define GIT_COLOR_FAINT_BLACK	"\033[2;30m"
+#define GIT_COLOR_FAINT_RED	"\033[2;31m"
+#define GIT_COLOR_FAINT_GREEN	"\033[2;32m"
+#define GIT_COLOR_FAINT_YELLOW	"\033[2;33m"
+#define GIT_COLOR_FAINT_BLUE	"\033[2;34m"
+#define GIT_COLOR_FAINT_MAGENTA	"\033[2;35m"
+#define GIT_COLOR_FAINT_CYAN	"\033[2;36m"
+#define GIT_COLOR_FAINT_WHITE	"\033[2;37m"
+#define GIT_COLOR_FAINT_DEFAULT	"\033[2;39m"
+#define GIT_COLOR_BG_BLACK	"\033[40m"
+#define GIT_COLOR_BG_RED	"\033[41m"
+#define GIT_COLOR_BG_GREEN	"\033[42m"
+#define GIT_COLOR_BG_YELLOW	"\033[43m"
+#define GIT_COLOR_BG_BLUE	"\033[44m"
+#define GIT_COLOR_BG_MAGENTA	"\033[45m"
+#define GIT_COLOR_BG_CYAN	"\033[46m"
+#define GIT_COLOR_BG_WHITE	"\033[47m"
+#define GIT_COLOR_BG_DEFAULT	"\033[49m"
+#define GIT_COLOR_FAINT		"\033[2m"
+#define GIT_COLOR_FAINT_ITALIC	"\033[2;3m"
+#define GIT_COLOR_REVERSE	"\033[7m"
+
+/* A special value meaning "no color selected" */
+#define GIT_COLOR_NIL "NIL"
+
+/*
+ * The first three are chosen to match common usage in the code, and what is
+ * returned from git_config_colorbool. The "auto" value can be returned from
+ * config_colorbool, and will be converted by want_color() into either 0 or 1.
+ */
+#define GIT_COLOR_UNKNOWN -1
+#define GIT_COLOR_NEVER  0
+#define GIT_COLOR_ALWAYS 1
+#define GIT_COLOR_AUTO   2
+
+/* A default list of colors to use for commit graphs and show-branch output */
+extern const char *column_colors_ansi[];
+extern const int column_colors_ansi_max;
+
+/*
+ * Generally the color code will lazily figure this out itself, but
+ * this provides a mechanism for callers to override autodetection.
+ */
+extern int color_stdout_is_tty;
+
+/* Parse color config. */
+int git_color_config(const char *var, const char *value, void *cb);
+
+/*
+ * Parse a config option, which can be a boolean or one of
+ * "never", "auto", "always". Return a constant of
+ * GIT_COLOR_NEVER for "never" or negative boolean,
+ * GIT_COLOR_ALWAYS for "always" or a positive boolean,
+ * and GIT_COLOR_AUTO for "auto".
+ */
+int git_config_colorbool(const char *var, const char *value);
+
+/*
+ * Return a boolean whether to use color, where the argument 'var' is
+ * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.
+ */
+int want_color_fd(int fd, int var);
+#define want_color(colorbool) want_color_fd(1, (colorbool))
+#define want_color_stderr(colorbool) want_color_fd(2, (colorbool))
+
+/*
+ * Translate a Git color from 'value' into a string that the terminal can
+ * interpret and store it into 'dst'. The Git color values are of the form
+ * "foreground [background] [attr]" where fore- and background can be a color
+ * name ("red"), a RGB code (#FF0000 or #F00) or a 256-color-mode from the
+ * terminal.
+ */
+int color_parse(const char *value, char *dst);
+int color_parse_mem(const char *value, int len, char *dst);
+
+/*
+ * Output the formatted string in the specified color (and then reset to normal
+ * color so subsequent output is uncolored). Omits the color encapsulation if
+ * `color` is NULL. The `color_fprintf_ln` prints a new line after resetting
+ * the color.  The `color_print_strbuf` prints the contents of the given
+ * strbuf (BUG: but only up to its first NUL character).
+ */
+__attribute__((format (printf, 3, 4)))
+int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
+__attribute__((format (printf, 3, 4)))
+int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
+void color_print_strbuf(FILE *fp, const char *color, const struct strbuf *sb);
+
+/*
+ * Check if the given color is GIT_COLOR_NIL that means "no color selected".
+ * The caller needs to replace the color with the actual desired color.
+ */
+int color_is_nil(const char *color);
+
+#endif /* COLOR_H */
diff --git a/column.c b/column.c
new file mode 100644
index 0000000000..93fae316b4
--- /dev/null
+++ b/column.c
@@ -0,0 +1,412 @@
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "column.h"
+#include "string-list.h"
+#include "pager.h"
+#include "parse-options.h"
+#include "run-command.h"
+#include "utf8.h"
+
+#define XY2LINEAR(d, x, y) (COL_LAYOUT((d)->colopts) == COL_COLUMN ? \
+			    (x) * (d)->rows + (y) : \
+			    (y) * (d)->cols + (x))
+
+struct column_data {
+	const struct string_list *list;
+	unsigned int colopts;
+	struct column_options opts;
+
+	int rows, cols;
+	int *len;		/* cell length */
+	int *width;	      /* index to the longest row in column */
+};
+
+/* return length of 's' in letters, ANSI escapes stripped */
+static int item_length(const char *s)
+{
+	return utf8_strnwidth(s, strlen(s), 1);
+}
+
+/*
+ * Calculate cell width, rows and cols for a table of equal cells, given
+ * table width and how many spaces between cells.
+ */
+static void layout(struct column_data *data, int *width)
+{
+	int i;
+
+	*width = 0;
+	for (i = 0; i < data->list->nr; i++)
+		if (*width < data->len[i])
+			*width = data->len[i];
+
+	*width += data->opts.padding;
+
+	data->cols = (data->opts.width - strlen(data->opts.indent)) / *width;
+	if (data->cols == 0)
+		data->cols = 1;
+
+	data->rows = DIV_ROUND_UP(data->list->nr, data->cols);
+}
+
+static void compute_column_width(struct column_data *data)
+{
+	int i, x, y;
+	for (x = 0; x < data->cols; x++) {
+		data->width[x] = XY2LINEAR(data, x, 0);
+		for (y = 0; y < data->rows; y++) {
+			i = XY2LINEAR(data, x, y);
+			if (i < data->list->nr &&
+			    data->len[data->width[x]] < data->len[i])
+				data->width[x] = i;
+		}
+	}
+}
+
+/*
+ * Shrink all columns by shortening them one row each time (and adding
+ * more columns along the way). Hopefully the longest cell will be
+ * moved to the next column, column is shrunk so we have more space
+ * for new columns. The process ends when the whole thing no longer
+ * fits in data->total_width.
+ */
+static void shrink_columns(struct column_data *data)
+{
+	REALLOC_ARRAY(data->width, data->cols);
+	while (data->rows > 1) {
+		int x, total_width, cols, rows;
+		rows = data->rows;
+		cols = data->cols;
+
+		data->rows--;
+		data->cols = DIV_ROUND_UP(data->list->nr, data->rows);
+		if (data->cols != cols)
+			REALLOC_ARRAY(data->width, data->cols);
+		compute_column_width(data);
+
+		total_width = strlen(data->opts.indent);
+		for (x = 0; x < data->cols; x++) {
+			total_width += data->len[data->width[x]];
+			total_width += data->opts.padding;
+		}
+		if (total_width > data->opts.width) {
+			data->rows = rows;
+			data->cols = cols;
+			break;
+		}
+	}
+	compute_column_width(data);
+}
+
+/* Display without layout when not enabled */
+static void display_plain(const struct string_list *list,
+			  const char *indent, const char *nl)
+{
+	int i;
+
+	for (i = 0; i < list->nr; i++)
+		printf("%s%s%s", indent, list->items[i].string, nl);
+}
+
+/* Print a cell to stdout with all necessary leading/trailing space */
+static int display_cell(struct column_data *data, int initial_width,
+			const char *empty_cell, int x, int y)
+{
+	int i, len, newline;
+
+	i = XY2LINEAR(data, x, y);
+	if (i >= data->list->nr)
+		return -1;
+
+	len = data->len[i];
+	if (data->width && data->len[data->width[x]] < initial_width) {
+		/*
+		 * empty_cell has initial_width chars, if real column
+		 * is narrower, increase len a bit so we fill less
+		 * space.
+		 */
+		len += initial_width - data->len[data->width[x]];
+		len -= data->opts.padding;
+	}
+
+	if (COL_LAYOUT(data->colopts) == COL_COLUMN)
+		newline = i + data->rows >= data->list->nr;
+	else
+		newline = x == data->cols - 1 || i == data->list->nr - 1;
+
+	printf("%s%s%s",
+	       x == 0 ? data->opts.indent : "",
+	       data->list->items[i].string,
+	       newline ? data->opts.nl : empty_cell + len);
+	return 0;
+}
+
+/* Display COL_COLUMN or COL_ROW */
+static void display_table(const struct string_list *list,
+			  unsigned int colopts,
+			  const struct column_options *opts)
+{
+	struct column_data data;
+	int x, y, i, initial_width;
+	char *empty_cell;
+
+	memset(&data, 0, sizeof(data));
+	data.list = list;
+	data.colopts = colopts;
+	data.opts = *opts;
+
+	ALLOC_ARRAY(data.len, list->nr);
+	for (i = 0; i < list->nr; i++)
+		data.len[i] = item_length(list->items[i].string);
+
+	layout(&data, &initial_width);
+
+	if (colopts & COL_DENSE)
+		shrink_columns(&data);
+
+	empty_cell = xmallocz(initial_width);
+	memset(empty_cell, ' ', initial_width);
+	for (y = 0; y < data.rows; y++) {
+		for (x = 0; x < data.cols; x++)
+			if (display_cell(&data, initial_width, empty_cell, x, y))
+				break;
+	}
+
+	free(data.len);
+	free(data.width);
+	free(empty_cell);
+}
+
+void print_columns(const struct string_list *list, unsigned int colopts,
+		   const struct column_options *opts)
+{
+	struct column_options nopts;
+
+	if (opts && (0 > opts->padding))
+		BUG("padding must be non-negative");
+	if (!list->nr)
+		return;
+	assert((colopts & COL_ENABLE_MASK) != COL_AUTO);
+
+	memset(&nopts, 0, sizeof(nopts));
+	nopts.indent = opts && opts->indent ? opts->indent : "";
+	nopts.nl = opts && opts->nl ? opts->nl : "\n";
+	nopts.padding = opts ? opts->padding : 1;
+	nopts.width = opts && opts->width ? opts->width : term_columns() - 1;
+	if (!column_active(colopts)) {
+		display_plain(list, "", "\n");
+		return;
+	}
+	switch (COL_LAYOUT(colopts)) {
+	case COL_PLAIN:
+		display_plain(list, nopts.indent, nopts.nl);
+		break;
+	case COL_ROW:
+	case COL_COLUMN:
+		display_table(list, colopts, &nopts);
+		break;
+	default:
+		BUG("invalid layout mode %d", COL_LAYOUT(colopts));
+	}
+}
+
+int finalize_colopts(unsigned int *colopts, int stdout_is_tty)
+{
+	if ((*colopts & COL_ENABLE_MASK) == COL_AUTO) {
+		if (stdout_is_tty < 0)
+			stdout_is_tty = isatty(1);
+		*colopts &= ~COL_ENABLE_MASK;
+		if (stdout_is_tty || pager_in_use())
+			*colopts |= COL_ENABLED;
+	}
+	return 0;
+}
+
+struct colopt {
+	const char *name;
+	unsigned int value;
+	unsigned int mask;
+};
+
+#define LAYOUT_SET 1
+#define ENABLE_SET 2
+
+static int parse_option(const char *arg, int len, unsigned int *colopts,
+			int *group_set)
+{
+	struct colopt opts[] = {
+		{ "always", COL_ENABLED,  COL_ENABLE_MASK },
+		{ "never",  COL_DISABLED, COL_ENABLE_MASK },
+		{ "auto",   COL_AUTO,     COL_ENABLE_MASK },
+		{ "plain",  COL_PLAIN,    COL_LAYOUT_MASK },
+		{ "column", COL_COLUMN,   COL_LAYOUT_MASK },
+		{ "row",    COL_ROW,      COL_LAYOUT_MASK },
+		{ "dense",  COL_DENSE,    0 },
+	};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(opts); i++) {
+		int set = 1, arg_len = len, name_len;
+		const char *arg_str = arg;
+
+		if (!opts[i].mask) {
+			if (arg_len > 2 && !strncmp(arg_str, "no", 2)) {
+				arg_str += 2;
+				arg_len -= 2;
+				set = 0;
+			}
+		}
+
+		name_len = strlen(opts[i].name);
+		if (arg_len != name_len ||
+		    strncmp(arg_str, opts[i].name, name_len))
+			continue;
+
+		switch (opts[i].mask) {
+		case COL_ENABLE_MASK:
+			*group_set |= ENABLE_SET;
+			break;
+		case COL_LAYOUT_MASK:
+			*group_set |= LAYOUT_SET;
+			break;
+		}
+
+		if (opts[i].mask)
+			*colopts = (*colopts & ~opts[i].mask) | opts[i].value;
+		else {
+			if (set)
+				*colopts |= opts[i].value;
+			else
+				*colopts &= ~opts[i].value;
+		}
+		return 0;
+	}
+
+	return error("unsupported option '%s'", arg);
+}
+
+static int parse_config(unsigned int *colopts, const char *value)
+{
+	const char *sep = " ,";
+	int group_set = 0;
+
+	while (*value) {
+		int len = strcspn(value, sep);
+		if (len) {
+			if (parse_option(value, len, colopts, &group_set))
+				return -1;
+
+			value += len;
+		}
+		value += strspn(value, sep);
+	}
+	/*
+	 * If none of "always", "never", and "auto" is specified, then setting
+	 * layout implies "always".
+	 *
+	 * Current value in COL_ENABLE_MASK is disregarded. This means if
+	 * you set column.ui = auto and pass --column=row, then "auto"
+	 * will become "always".
+	 */
+	if ((group_set & LAYOUT_SET) && !(group_set & ENABLE_SET))
+		*colopts = (*colopts & ~COL_ENABLE_MASK) | COL_ENABLED;
+	return 0;
+}
+
+static int column_config(const char *var, const char *value,
+			 const char *key, unsigned int *colopts)
+{
+	if (!value)
+		return config_error_nonbool(var);
+	if (parse_config(colopts, value))
+		return error("invalid column.%s mode %s", key, value);
+	return 0;
+}
+
+int git_column_config(const char *var, const char *value,
+		      const char *command, unsigned int *colopts)
+{
+	const char *it;
+
+	if (!skip_prefix(var, "column.", &it))
+		return 0;
+
+	if (!strcmp(it, "ui"))
+		return column_config(var, value, "ui", colopts);
+
+	if (command && !strcmp(it, command))
+		return column_config(var, value, it, colopts);
+
+	return 0;
+}
+
+int parseopt_column_callback(const struct option *opt,
+			     const char *arg, int unset)
+{
+	unsigned int *colopts = opt->value;
+	*colopts |= COL_PARSEOPT;
+	*colopts &= ~COL_ENABLE_MASK;
+	if (unset)		/* --no-column == never */
+		return 0;
+	/* --column == always unless "arg" states otherwise */
+	*colopts |= COL_ENABLED;
+	if (arg)
+		return parse_config(colopts, arg);
+
+	return 0;
+}
+
+static int fd_out = -1;
+static struct child_process column_process = CHILD_PROCESS_INIT;
+
+int run_column_filter(int colopts, const struct column_options *opts)
+{
+	struct strvec *argv;
+
+	if (opts && (0 > opts->padding))
+		BUG("padding must be non-negative");
+	if (fd_out != -1)
+		return -1;
+
+	child_process_init(&column_process);
+	argv = &column_process.args;
+
+	strvec_push(argv, "column");
+	strvec_pushf(argv, "--raw-mode=%d", colopts);
+	if (opts && opts->width)
+		strvec_pushf(argv, "--width=%d", opts->width);
+	if (opts && opts->indent)
+		strvec_pushf(argv, "--indent=%s", opts->indent);
+	if (opts && opts->padding)
+		strvec_pushf(argv, "--padding=%d", opts->padding);
+
+	fflush(stdout);
+	column_process.in = -1;
+	column_process.out = dup(1);
+	column_process.git_cmd = 1;
+
+	if (start_command(&column_process))
+		return -2;
+
+	fd_out = dup(1);
+	close(1);
+	dup2(column_process.in, 1);
+	close(column_process.in);
+	return 0;
+}
+
+int stop_column_filter(void)
+{
+	if (fd_out == -1)
+		return -1;
+
+	fflush(stdout);
+	close(1);
+	finish_command(&column_process);
+	dup2(fd_out, 1);
+	close(fd_out);
+	fd_out = -1;
+	return 0;
+}
diff --git a/column.h b/column.h
new file mode 100644
index 0000000000..448c7440b3
--- /dev/null
+++ b/column.h
@@ -0,0 +1,46 @@
+#ifndef COLUMN_H
+#define COLUMN_H
+
+#define COL_LAYOUT_MASK   0x000F
+#define COL_ENABLE_MASK   0x0030   /* always, never or auto */
+#define COL_PARSEOPT      0x0040   /* --column is given from cmdline */
+#define COL_DENSE         0x0080   /* Shrink columns when possible,
+				      making space for more columns */
+
+#define COL_DISABLED      0x0000   /* must be zero */
+#define COL_ENABLED       0x0010
+#define COL_AUTO          0x0020
+
+#define COL_LAYOUT(c) ((c) & COL_LAYOUT_MASK)
+#define COL_COLUMN             0   /* Fill columns before rows */
+#define COL_ROW                1   /* Fill rows before columns */
+#define COL_PLAIN             15   /* one column */
+
+#define explicitly_enable_column(c) \
+	(((c) & COL_PARSEOPT) && column_active(c))
+
+struct column_options {
+	int width;
+	int padding;
+	const char *indent;
+	const char *nl;
+};
+
+struct option;
+int parseopt_column_callback(const struct option *, const char *, int);
+int git_column_config(const char *var, const char *value,
+		      const char *command, unsigned int *colopts);
+int finalize_colopts(unsigned int *colopts, int stdout_is_tty);
+static inline int column_active(unsigned int colopts)
+{
+	return (colopts & COL_ENABLE_MASK) == COL_ENABLED;
+}
+
+struct string_list;
+void print_columns(const struct string_list *list, unsigned int colopts,
+		   const struct column_options *opts);
+
+int run_column_filter(int colopts, const struct column_options *);
+int stop_column_filter(void);
+
+#endif
diff --git a/combine-diff.c b/combine-diff.c
new file mode 100644
index 0000000000..641bc92dbd
--- /dev/null
+++ b/combine-diff.c
@@ -0,0 +1,1669 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "object-store-ll.h"
+#include "commit.h"
+#include "convert.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "environment.h"
+#include "hex.h"
+#include "object-name.h"
+#include "quote.h"
+#include "xdiff-interface.h"
+#include "xdiff/xmacros.h"
+#include "log-tree.h"
+#include "refs.h"
+#include "tree.h"
+#include "userdiff.h"
+#include "oid-array.h"
+#include "revision.h"
+
+static int compare_paths(const struct combine_diff_path *one,
+			  const struct diff_filespec *two)
+{
+	if (!S_ISDIR(one->mode) && !S_ISDIR(two->mode))
+		return strcmp(one->path, two->path);
+
+	return base_name_compare(one->path, strlen(one->path), one->mode,
+				 two->path, strlen(two->path), two->mode);
+}
+
+static int filename_changed(char status)
+{
+	return status == 'R' || status == 'C';
+}
+
+static struct combine_diff_path *intersect_paths(
+	struct combine_diff_path *curr,
+	int n,
+	int num_parent,
+	int combined_all_paths)
+{
+	struct diff_queue_struct *q = &diff_queued_diff;
+	struct combine_diff_path *p, **tail = &curr;
+	int i, j, cmp;
+
+	if (!n) {
+		for (i = 0; i < q->nr; i++) {
+			int len;
+			const char *path;
+			if (diff_unmodified_pair(q->queue[i]))
+				continue;
+			path = q->queue[i]->two->path;
+			len = strlen(path);
+			p = xmalloc(combine_diff_path_size(num_parent, len));
+			p->path = (char *) &(p->parent[num_parent]);
+			memcpy(p->path, path, len);
+			p->path[len] = 0;
+			p->next = NULL;
+			memset(p->parent, 0,
+			       sizeof(p->parent[0]) * num_parent);
+
+			oidcpy(&p->oid, &q->queue[i]->two->oid);
+			p->mode = q->queue[i]->two->mode;
+			oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
+			p->parent[n].mode = q->queue[i]->one->mode;
+			p->parent[n].status = q->queue[i]->status;
+
+			if (combined_all_paths &&
+			    filename_changed(p->parent[n].status)) {
+				strbuf_init(&p->parent[n].path, 0);
+				strbuf_addstr(&p->parent[n].path,
+					      q->queue[i]->one->path);
+			}
+			*tail = p;
+			tail = &p->next;
+		}
+		return curr;
+	}
+
+	/*
+	 * paths in curr (linked list) and q->queue[] (array) are
+	 * both sorted in the tree order.
+	 */
+	i = 0;
+	while ((p = *tail) != NULL) {
+		cmp = ((i >= q->nr)
+		       ? -1 : compare_paths(p, q->queue[i]->two));
+
+		if (cmp < 0) {
+			/* p->path not in q->queue[]; drop it */
+			*tail = p->next;
+			for (j = 0; j < num_parent; j++)
+				if (combined_all_paths &&
+				    filename_changed(p->parent[j].status))
+					strbuf_release(&p->parent[j].path);
+			free(p);
+			continue;
+		}
+
+		if (cmp > 0) {
+			/* q->queue[i] not in p->path; skip it */
+			i++;
+			continue;
+		}
+
+		oidcpy(&p->parent[n].oid, &q->queue[i]->one->oid);
+		p->parent[n].mode = q->queue[i]->one->mode;
+		p->parent[n].status = q->queue[i]->status;
+		if (combined_all_paths &&
+		    filename_changed(p->parent[n].status))
+			strbuf_addstr(&p->parent[n].path,
+				      q->queue[i]->one->path);
+
+		tail = &p->next;
+		i++;
+	}
+	return curr;
+}
+
+/* Lines lost from parent */
+struct lline {
+	struct lline *next, *prev;
+	int len;
+	unsigned long parent_map;
+	char line[FLEX_ARRAY];
+};
+
+/* Lines lost from current parent (before coalescing) */
+struct plost {
+	struct lline *lost_head, *lost_tail;
+	int len;
+};
+
+/* Lines surviving in the merge result */
+struct sline {
+	/* Accumulated and coalesced lost lines */
+	struct lline *lost;
+	int lenlost;
+	struct plost plost;
+	char *bol;
+	int len;
+	/* bit 0 up to (N-1) are on if the parent has this line (i.e.
+	 * we did not change it).
+	 * bit N is used for "interesting" lines, including context.
+	 * bit (N+1) is used for "do not show deletion before this".
+	 */
+	unsigned long flag;
+	unsigned long *p_lno;
+};
+
+static int match_string_spaces(const char *line1, int len1,
+			       const char *line2, int len2,
+			       long flags)
+{
+	if (flags & XDF_WHITESPACE_FLAGS) {
+		for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
+		for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
+	}
+
+	if (!(flags & (XDF_IGNORE_WHITESPACE | XDF_IGNORE_WHITESPACE_CHANGE)))
+		return (len1 == len2 && !memcmp(line1, line2, len1));
+
+	while (len1 > 0 && len2 > 0) {
+		len1--;
+		len2--;
+		if (XDL_ISSPACE(line1[len1]) || XDL_ISSPACE(line2[len2])) {
+			if ((flags & XDF_IGNORE_WHITESPACE_CHANGE) &&
+			    (!XDL_ISSPACE(line1[len1]) || !XDL_ISSPACE(line2[len2])))
+				return 0;
+
+			for (; len1 > 0 && XDL_ISSPACE(line1[len1]); len1--);
+			for (; len2 > 0 && XDL_ISSPACE(line2[len2]); len2--);
+		}
+		if (line1[len1] != line2[len2])
+			return 0;
+	}
+
+	if (flags & XDF_IGNORE_WHITESPACE) {
+		/* Consume remaining spaces */
+		for (; len1 > 0 && XDL_ISSPACE(line1[len1 - 1]); len1--);
+		for (; len2 > 0 && XDL_ISSPACE(line2[len2 - 1]); len2--);
+	}
+
+	/* We matched full line1 and line2 */
+	if (!len1 && !len2)
+		return 1;
+
+	return 0;
+}
+
+enum coalesce_direction { MATCH, BASE, NEW };
+
+/* Coalesce new lines into base by finding LCS */
+static struct lline *coalesce_lines(struct lline *base, int *lenbase,
+				    struct lline *newline, int lennew,
+				    unsigned long parent, long flags)
+{
+	int **lcs;
+	enum coalesce_direction **directions;
+	struct lline *baseend, *newend = NULL;
+	int i, j, origbaselen = *lenbase;
+
+	if (!newline)
+		return base;
+
+	if (!base) {
+		*lenbase = lennew;
+		return newline;
+	}
+
+	/*
+	 * Coalesce new lines into base by finding the LCS
+	 * - Create the table to run dynamic programming
+	 * - Compute the LCS
+	 * - Then reverse read the direction structure:
+	 *   - If we have MATCH, assign parent to base flag, and consume
+	 *   both baseend and newend
+	 *   - Else if we have BASE, consume baseend
+	 *   - Else if we have NEW, insert newend lline into base and
+	 *   consume newend
+	 */
+	CALLOC_ARRAY(lcs, st_add(origbaselen, 1));
+	CALLOC_ARRAY(directions, st_add(origbaselen, 1));
+	for (i = 0; i < origbaselen + 1; i++) {
+		CALLOC_ARRAY(lcs[i], st_add(lennew, 1));
+		CALLOC_ARRAY(directions[i], st_add(lennew, 1));
+		directions[i][0] = BASE;
+	}
+	for (j = 1; j < lennew + 1; j++)
+		directions[0][j] = NEW;
+
+	for (i = 1, baseend = base; i < origbaselen + 1; i++) {
+		for (j = 1, newend = newline; j < lennew + 1; j++) {
+			if (match_string_spaces(baseend->line, baseend->len,
+						newend->line, newend->len, flags)) {
+				lcs[i][j] = lcs[i - 1][j - 1] + 1;
+				directions[i][j] = MATCH;
+			} else if (lcs[i][j - 1] >= lcs[i - 1][j]) {
+				lcs[i][j] = lcs[i][j - 1];
+				directions[i][j] = NEW;
+			} else {
+				lcs[i][j] = lcs[i - 1][j];
+				directions[i][j] = BASE;
+			}
+			if (newend->next)
+				newend = newend->next;
+		}
+		if (baseend->next)
+			baseend = baseend->next;
+	}
+
+	for (i = 0; i < origbaselen + 1; i++)
+		free(lcs[i]);
+	free(lcs);
+
+	/* At this point, baseend and newend point to the end of each lists */
+	i--;
+	j--;
+	while (i != 0 || j != 0) {
+		if (directions[i][j] == MATCH) {
+			baseend->parent_map |= 1<<parent;
+			baseend = baseend->prev;
+			newend = newend->prev;
+			i--;
+			j--;
+		} else if (directions[i][j] == NEW) {
+			struct lline *lline;
+
+			lline = newend;
+			/* Remove lline from new list and update newend */
+			if (lline->prev)
+				lline->prev->next = lline->next;
+			else
+				newline = lline->next;
+			if (lline->next)
+				lline->next->prev = lline->prev;
+
+			newend = lline->prev;
+			j--;
+
+			/* Add lline to base list */
+			if (baseend) {
+				lline->next = baseend->next;
+				lline->prev = baseend;
+				if (lline->prev)
+					lline->prev->next = lline;
+			}
+			else {
+				lline->next = base;
+				base = lline;
+			}
+			(*lenbase)++;
+
+			if (lline->next)
+				lline->next->prev = lline;
+
+		} else {
+			baseend = baseend->prev;
+			i--;
+		}
+	}
+
+	newend = newline;
+	while (newend) {
+		struct lline *lline = newend;
+		newend = newend->next;
+		free(lline);
+	}
+
+	for (i = 0; i < origbaselen + 1; i++)
+		free(directions[i]);
+	free(directions);
+
+	return base;
+}
+
+static char *grab_blob(struct repository *r,
+		       const struct object_id *oid, unsigned int mode,
+		       unsigned long *size, struct userdiff_driver *textconv,
+		       const char *path)
+{
+	char *blob;
+	enum object_type type;
+
+	if (S_ISGITLINK(mode)) {
+		struct strbuf buf = STRBUF_INIT;
+		strbuf_addf(&buf, "Subproject commit %s\n", oid_to_hex(oid));
+		*size = buf.len;
+		blob = strbuf_detach(&buf, NULL);
+	} else if (is_null_oid(oid)) {
+		/* deleted blob */
+		*size = 0;
+		return xcalloc(1, 1);
+	} else if (textconv) {
+		struct diff_filespec *df = alloc_filespec(path);
+		fill_filespec(df, oid, 1, mode);
+		*size = fill_textconv(r, textconv, df, &blob);
+		free_filespec(df);
+	} else {
+		blob = repo_read_object_file(r, oid, &type, size);
+		if (!blob)
+			die(_("unable to read %s"), oid_to_hex(oid));
+		if (type != OBJ_BLOB)
+			die("object '%s' is not a blob!", oid_to_hex(oid));
+	}
+	return blob;
+}
+
+static void append_lost(struct sline *sline, int n, const char *line, int len)
+{
+	struct lline *lline;
+	unsigned long this_mask = (1UL<<n);
+	if (line[len-1] == '\n')
+		len--;
+
+	FLEX_ALLOC_MEM(lline, line, line, len);
+	lline->len = len;
+	lline->next = NULL;
+	lline->prev = sline->plost.lost_tail;
+	if (lline->prev)
+		lline->prev->next = lline;
+	else
+		sline->plost.lost_head = lline;
+	sline->plost.lost_tail = lline;
+	sline->plost.len++;
+	lline->parent_map = this_mask;
+}
+
+struct combine_diff_state {
+	unsigned int lno;
+	int ob, on, nb, nn;
+	unsigned long nmask;
+	int num_parent;
+	int n;
+	struct sline *sline;
+	struct sline *lost_bucket;
+};
+
+static void consume_hunk(void *state_,
+			 long ob, long on,
+			 long nb, long nn,
+			 const char *func UNUSED, long funclen UNUSED)
+{
+	struct combine_diff_state *state = state_;
+
+	state->ob = ob;
+	state->on = on;
+	state->nb = nb;
+	state->nn = nn;
+	state->lno = state->nb;
+	if (state->nn == 0) {
+		/* @@ -X,Y +N,0 @@ removed Y lines
+		 * that would have come *after* line N
+		 * in the result.  Our lost buckets hang
+		 * to the line after the removed lines,
+		 *
+		 * Note that this is correct even when N == 0,
+		 * in which case the hunk removes the first
+		 * line in the file.
+		 */
+		state->lost_bucket = &state->sline[state->nb];
+		if (!state->nb)
+			state->nb = 1;
+	} else {
+		state->lost_bucket = &state->sline[state->nb-1];
+	}
+	if (!state->sline[state->nb-1].p_lno)
+		CALLOC_ARRAY(state->sline[state->nb - 1].p_lno,
+			     state->num_parent);
+	state->sline[state->nb-1].p_lno[state->n] = state->ob;
+}
+
+static int consume_line(void *state_, char *line, unsigned long len)
+{
+	struct combine_diff_state *state = state_;
+	if (!state->lost_bucket)
+		return 0; /* not in any hunk yet */
+	switch (line[0]) {
+	case '-':
+		append_lost(state->lost_bucket, state->n, line+1, len-1);
+		break;
+	case '+':
+		state->sline[state->lno-1].flag |= state->nmask;
+		state->lno++;
+		break;
+	}
+	return 0;
+}
+
+static void combine_diff(struct repository *r,
+			 const struct object_id *parent, unsigned int mode,
+			 mmfile_t *result_file,
+			 struct sline *sline, unsigned int cnt, int n,
+			 int num_parent, int result_deleted,
+			 struct userdiff_driver *textconv,
+			 const char *path, long flags)
+{
+	unsigned int p_lno, lno;
+	unsigned long nmask = (1UL << n);
+	xpparam_t xpp;
+	xdemitconf_t xecfg;
+	mmfile_t parent_file;
+	struct combine_diff_state state;
+	unsigned long sz;
+
+	if (result_deleted)
+		return; /* result deleted */
+
+	parent_file.ptr = grab_blob(r, parent, mode, &sz, textconv, path);
+	parent_file.size = sz;
+	memset(&xpp, 0, sizeof(xpp));
+	xpp.flags = flags;
+	memset(&xecfg, 0, sizeof(xecfg));
+	memset(&state, 0, sizeof(state));
+	state.nmask = nmask;
+	state.sline = sline;
+	state.lno = 1;
+	state.num_parent = num_parent;
+	state.n = n;
+
+	if (xdi_diff_outf(&parent_file, result_file, consume_hunk,
+			  consume_line, &state, &xpp, &xecfg))
+		die("unable to generate combined diff for %s",
+		    oid_to_hex(parent));
+	free(parent_file.ptr);
+
+	/* Assign line numbers for this parent.
+	 *
+	 * sline[lno].p_lno[n] records the first line number
+	 * (counting from 1) for parent N if the final hunk display
+	 * started by showing sline[lno] (possibly showing the lost
+	 * lines attached to it first).
+	 */
+	for (lno = 0,  p_lno = 1; lno <= cnt; lno++) {
+		struct lline *ll;
+		sline[lno].p_lno[n] = p_lno;
+
+		/* Coalesce new lines */
+		if (sline[lno].plost.lost_head) {
+			struct sline *sl = &sline[lno];
+			sl->lost = coalesce_lines(sl->lost, &sl->lenlost,
+						  sl->plost.lost_head,
+						  sl->plost.len, n, flags);
+			sl->plost.lost_head = sl->plost.lost_tail = NULL;
+			sl->plost.len = 0;
+		}
+
+		/* How many lines would this sline advance the p_lno? */
+		ll = sline[lno].lost;
+		while (ll) {
+			if (ll->parent_map & nmask)
+				p_lno++; /* '-' means parent had it */
+			ll = ll->next;
+		}
+		if (lno < cnt && !(sline[lno].flag & nmask))
+			p_lno++; /* no '+' means parent had it */
+	}
+	sline[lno].p_lno[n] = p_lno; /* trailer */
+}
+
+static unsigned long context = 3;
+static char combine_marker = '@';
+
+static int interesting(struct sline *sline, unsigned long all_mask)
+{
+	/* If some parents lost lines here, or if we have added to
+	 * some parent, it is interesting.
+	 */
+	return ((sline->flag & all_mask) || sline->lost);
+}
+
+static unsigned long adjust_hunk_tail(struct sline *sline,
+				      unsigned long all_mask,
+				      unsigned long hunk_begin,
+				      unsigned long i)
+{
+	/* i points at the first uninteresting line.  If the last line
+	 * of the hunk was interesting only because it has some
+	 * deletion, then it is not all that interesting for the
+	 * purpose of giving trailing context lines.  This is because
+	 * we output '-' line and then unmodified sline[i-1] itself in
+	 * that case which gives us one extra context line.
+	 */
+	if ((hunk_begin + 1 <= i) && !(sline[i-1].flag & all_mask))
+		i--;
+	return i;
+}
+
+static unsigned long find_next(struct sline *sline,
+			       unsigned long mark,
+			       unsigned long i,
+			       unsigned long cnt,
+			       int look_for_uninteresting)
+{
+	/* We have examined up to i-1 and are about to look at i.
+	 * Find next interesting or uninteresting line.  Here,
+	 * "interesting" does not mean interesting(), but marked by
+	 * the give_context() function below (i.e. it includes context
+	 * lines that are not interesting to interesting() function
+	 * that are surrounded by interesting() ones.
+	 */
+	while (i <= cnt)
+		if (look_for_uninteresting
+		    ? !(sline[i].flag & mark)
+		    : (sline[i].flag & mark))
+			return i;
+		else
+			i++;
+	return i;
+}
+
+static int give_context(struct sline *sline, unsigned long cnt, int num_parent)
+{
+	unsigned long all_mask = (1UL<<num_parent) - 1;
+	unsigned long mark = (1UL<<num_parent);
+	unsigned long no_pre_delete = (2UL<<num_parent);
+	unsigned long i;
+
+	/* Two groups of interesting lines may have a short gap of
+	 * uninteresting lines.  Connect such groups to give them a
+	 * bit of context.
+	 *
+	 * We first start from what the interesting() function says,
+	 * and mark them with "mark", and paint context lines with the
+	 * mark.  So interesting() would still say false for such context
+	 * lines but they are treated as "interesting" in the end.
+	 */
+	i = find_next(sline, mark, 0, cnt, 0);
+	if (cnt < i)
+		return 0;
+
+	while (i <= cnt) {
+		unsigned long j = (context < i) ? (i - context) : 0;
+		unsigned long k;
+
+		/* Paint a few lines before the first interesting line. */
+		while (j < i) {
+			if (!(sline[j].flag & mark))
+				sline[j].flag |= no_pre_delete;
+			sline[j++].flag |= mark;
+		}
+
+	again:
+		/* we know up to i is to be included.  where does the
+		 * next uninteresting one start?
+		 */
+		j = find_next(sline, mark, i, cnt, 1);
+		if (cnt < j)
+			break; /* the rest are all interesting */
+
+		/* lookahead context lines */
+		k = find_next(sline, mark, j, cnt, 0);
+		j = adjust_hunk_tail(sline, all_mask, i, j);
+
+		if (k < j + context) {
+			/* k is interesting and [j,k) are not, but
+			 * paint them interesting because the gap is small.
+			 */
+			while (j < k)
+				sline[j++].flag |= mark;
+			i = k;
+			goto again;
+		}
+
+		/* j is the first uninteresting line and there is
+		 * no overlap beyond it within context lines.  Paint
+		 * the trailing edge a bit.
+		 */
+		i = k;
+		k = (j + context < cnt+1) ? j + context : cnt+1;
+		while (j < k)
+			sline[j++].flag |= mark;
+	}
+	return 1;
+}
+
+static int make_hunks(struct sline *sline, unsigned long cnt,
+		       int num_parent, int dense)
+{
+	unsigned long all_mask = (1UL<<num_parent) - 1;
+	unsigned long mark = (1UL<<num_parent);
+	unsigned long i;
+	int has_interesting = 0;
+
+	for (i = 0; i <= cnt; i++) {
+		if (interesting(&sline[i], all_mask))
+			sline[i].flag |= mark;
+		else
+			sline[i].flag &= ~mark;
+	}
+	if (!dense)
+		return give_context(sline, cnt, num_parent);
+
+	/* Look at each hunk, and if we have changes from only one
+	 * parent, or the changes are the same from all but one
+	 * parent, mark that uninteresting.
+	 */
+	i = 0;
+	while (i <= cnt) {
+		unsigned long j, hunk_begin, hunk_end;
+		unsigned long same_diff;
+		while (i <= cnt && !(sline[i].flag & mark))
+			i++;
+		if (cnt < i)
+			break; /* No more interesting hunks */
+		hunk_begin = i;
+		for (j = i + 1; j <= cnt; j++) {
+			if (!(sline[j].flag & mark)) {
+				/* Look beyond the end to see if there
+				 * is an interesting line after this
+				 * hunk within context span.
+				 */
+				unsigned long la; /* lookahead */
+				int contin = 0;
+				la = adjust_hunk_tail(sline, all_mask,
+						     hunk_begin, j);
+				la = (la + context < cnt + 1) ?
+					(la + context) : cnt + 1;
+				while (la && j <= --la) {
+					if (sline[la].flag & mark) {
+						contin = 1;
+						break;
+					}
+				}
+				if (!contin)
+					break;
+				j = la;
+			}
+		}
+		hunk_end = j;
+
+		/* [i..hunk_end) are interesting.  Now is it really
+		 * interesting?  We check if there are only two versions
+		 * and the result matches one of them.  That is, we look
+		 * at:
+		 *   (+) line, which records lines added to which parents;
+		 *       this line appears in the result.
+		 *   (-) line, which records from what parents the line
+		 *       was removed; this line does not appear in the result.
+		 * then check the set of parents the result has difference
+		 * from, from all lines.  If there are lines that has
+		 * different set of parents that the result has differences
+		 * from, that means we have more than two versions.
+		 *
+		 * Even when we have only two versions, if the result does
+		 * not match any of the parents, the it should be considered
+		 * interesting.  In such a case, we would have all '+' line.
+		 * After passing the above "two versions" test, that would
+		 * appear as "the same set of parents" to be "all parents".
+		 */
+		same_diff = 0;
+		has_interesting = 0;
+		for (j = i; j < hunk_end && !has_interesting; j++) {
+			unsigned long this_diff = sline[j].flag & all_mask;
+			struct lline *ll = sline[j].lost;
+			if (this_diff) {
+				/* This has some changes.  Is it the
+				 * same as others?
+				 */
+				if (!same_diff)
+					same_diff = this_diff;
+				else if (same_diff != this_diff) {
+					has_interesting = 1;
+					break;
+				}
+			}
+			while (ll && !has_interesting) {
+				/* Lost this line from these parents;
+				 * who are they?  Are they the same?
+				 */
+				this_diff = ll->parent_map;
+				if (!same_diff)
+					same_diff = this_diff;
+				else if (same_diff != this_diff) {
+					has_interesting = 1;
+				}
+				ll = ll->next;
+			}
+		}
+
+		if (!has_interesting && same_diff != all_mask) {
+			/* This hunk is not that interesting after all */
+			for (j = hunk_begin; j < hunk_end; j++)
+				sline[j].flag &= ~mark;
+		}
+		i = hunk_end;
+	}
+
+	has_interesting = give_context(sline, cnt, num_parent);
+	return has_interesting;
+}
+
+static void show_parent_lno(struct sline *sline, unsigned long l0, unsigned long l1, int n, unsigned long null_context)
+{
+	l0 = sline[l0].p_lno[n];
+	l1 = sline[l1].p_lno[n];
+	printf(" -%lu,%lu", l0, l1-l0-null_context);
+}
+
+static int hunk_comment_line(const char *bol)
+{
+	int ch;
+
+	if (!bol)
+		return 0;
+	ch = *bol & 0xff;
+	return (isalpha(ch) || ch == '_' || ch == '$');
+}
+
+static void show_line_to_eol(const char *line, int len, const char *reset)
+{
+	int saw_cr_at_eol = 0;
+	if (len < 0)
+		len = strlen(line);
+	saw_cr_at_eol = (len && line[len-1] == '\r');
+
+	printf("%.*s%s%s\n", len - saw_cr_at_eol, line,
+	       reset,
+	       saw_cr_at_eol ? "\r" : "");
+}
+
+static void dump_sline(struct sline *sline, const char *line_prefix,
+		       unsigned long cnt, int num_parent,
+		       int use_color, int result_deleted)
+{
+	unsigned long mark = (1UL<<num_parent);
+	unsigned long no_pre_delete = (2UL<<num_parent);
+	int i;
+	unsigned long lno = 0;
+	const char *c_frag = diff_get_color(use_color, DIFF_FRAGINFO);
+	const char *c_func = diff_get_color(use_color, DIFF_FUNCINFO);
+	const char *c_new = diff_get_color(use_color, DIFF_FILE_NEW);
+	const char *c_old = diff_get_color(use_color, DIFF_FILE_OLD);
+	const char *c_context = diff_get_color(use_color, DIFF_CONTEXT);
+	const char *c_reset = diff_get_color(use_color, DIFF_RESET);
+
+	if (result_deleted)
+		return; /* result deleted */
+
+	while (1) {
+		unsigned long hunk_end;
+		unsigned long rlines;
+		const char *hunk_comment = NULL;
+		unsigned long null_context = 0;
+
+		while (lno <= cnt && !(sline[lno].flag & mark)) {
+			if (hunk_comment_line(sline[lno].bol))
+				hunk_comment = sline[lno].bol;
+			lno++;
+		}
+		if (cnt < lno)
+			break;
+		else {
+			for (hunk_end = lno + 1; hunk_end <= cnt; hunk_end++)
+				if (!(sline[hunk_end].flag & mark))
+					break;
+		}
+		rlines = hunk_end - lno;
+		if (cnt < hunk_end)
+			rlines--; /* pointing at the last delete hunk */
+
+		if (!context) {
+			/*
+			 * Even when running with --unified=0, all
+			 * lines in the hunk needs to be processed in
+			 * the loop below in order to show the
+			 * deletion recorded in lost_head.  However,
+			 * we do not want to show the resulting line
+			 * with all blank context markers in such a
+			 * case.  Compensate.
+			 */
+			unsigned long j;
+			for (j = lno; j < hunk_end; j++)
+				if (!(sline[j].flag & (mark-1)))
+					null_context++;
+			rlines -= null_context;
+		}
+
+		printf("%s%s", line_prefix, c_frag);
+		for (i = 0; i <= num_parent; i++) putchar(combine_marker);
+		for (i = 0; i < num_parent; i++)
+			show_parent_lno(sline, lno, hunk_end, i, null_context);
+		printf(" +%lu,%lu ", lno+1, rlines);
+		for (i = 0; i <= num_parent; i++) putchar(combine_marker);
+
+		if (hunk_comment) {
+			int comment_end = 0;
+			for (i = 0; i < 40; i++) {
+				int ch = hunk_comment[i] & 0xff;
+				if (!ch || ch == '\n')
+					break;
+				if (!isspace(ch))
+				    comment_end = i;
+			}
+			if (comment_end)
+				printf("%s%s %s%s", c_reset,
+						    c_context, c_reset,
+						    c_func);
+			for (i = 0; i < comment_end; i++)
+				putchar(hunk_comment[i]);
+		}
+
+		printf("%s\n", c_reset);
+		while (lno < hunk_end) {
+			struct lline *ll;
+			int j;
+			unsigned long p_mask;
+			struct sline *sl = &sline[lno++];
+			ll = (sl->flag & no_pre_delete) ? NULL : sl->lost;
+			while (ll) {
+				printf("%s%s", line_prefix, c_old);
+				for (j = 0; j < num_parent; j++) {
+					if (ll->parent_map & (1UL<<j))
+						putchar('-');
+					else
+						putchar(' ');
+				}
+				show_line_to_eol(ll->line, -1, c_reset);
+				ll = ll->next;
+			}
+			if (cnt < lno)
+				break;
+			p_mask = 1;
+			fputs(line_prefix, stdout);
+			if (!(sl->flag & (mark-1))) {
+				/*
+				 * This sline was here to hang the
+				 * lost lines in front of it.
+				 */
+				if (!context)
+					continue;
+				fputs(c_context, stdout);
+			}
+			else
+				fputs(c_new, stdout);
+			for (j = 0; j < num_parent; j++) {
+				if (p_mask & sl->flag)
+					putchar('+');
+				else
+					putchar(' ');
+				p_mask <<= 1;
+			}
+			show_line_to_eol(sl->bol, sl->len, c_reset);
+		}
+	}
+}
+
+static void reuse_combine_diff(struct sline *sline, unsigned long cnt,
+			       int i, int j)
+{
+	/* We have already examined parent j and we know parent i
+	 * and parent j are the same, so reuse the combined result
+	 * of parent j for parent i.
+	 */
+	unsigned long lno, imask, jmask;
+	imask = (1UL<<i);
+	jmask = (1UL<<j);
+
+	for (lno = 0; lno <= cnt; lno++) {
+		struct lline *ll = sline->lost;
+		sline->p_lno[i] = sline->p_lno[j];
+		while (ll) {
+			if (ll->parent_map & jmask)
+				ll->parent_map |= imask;
+			ll = ll->next;
+		}
+		if (sline->flag & jmask)
+			sline->flag |= imask;
+		sline++;
+	}
+	/* the overall size of the file (sline[cnt]) */
+	sline->p_lno[i] = sline->p_lno[j];
+}
+
+static void dump_quoted_path(const char *head,
+			     const char *prefix,
+			     const char *path,
+			     const char *line_prefix,
+			     const char *c_meta, const char *c_reset)
+{
+	static struct strbuf buf = STRBUF_INIT;
+
+	strbuf_reset(&buf);
+	strbuf_addstr(&buf, line_prefix);
+	strbuf_addstr(&buf, c_meta);
+	strbuf_addstr(&buf, head);
+	quote_two_c_style(&buf, prefix, path, 0);
+	strbuf_addstr(&buf, c_reset);
+	puts(buf.buf);
+}
+
+static void show_combined_header(struct combine_diff_path *elem,
+				 int num_parent,
+				 struct rev_info *rev,
+				 const char *line_prefix,
+				 int mode_differs,
+				 int show_file_header)
+{
+	struct diff_options *opt = &rev->diffopt;
+	int abbrev = opt->flags.full_index ? the_hash_algo->hexsz : DEFAULT_ABBREV;
+	const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/";
+	const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/";
+	const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO);
+	const char *c_reset = diff_get_color_opt(opt, DIFF_RESET);
+	const char *abb;
+	int added = 0;
+	int deleted = 0;
+	int i;
+	int dense = rev->dense_combined_merges;
+
+	if (rev->loginfo && !rev->no_commit_id)
+		show_log(rev);
+
+	dump_quoted_path(dense ? "diff --cc " : "diff --combined ",
+			 "", elem->path, line_prefix, c_meta, c_reset);
+	printf("%s%sindex ", line_prefix, c_meta);
+	for (i = 0; i < num_parent; i++) {
+		abb = repo_find_unique_abbrev(the_repository,
+					      &elem->parent[i].oid, abbrev);
+		printf("%s%s", i ? "," : "", abb);
+	}
+	abb = repo_find_unique_abbrev(the_repository, &elem->oid, abbrev);
+	printf("..%s%s\n", abb, c_reset);
+
+	if (mode_differs) {
+		deleted = !elem->mode;
+
+		/* We say it was added if nobody had it */
+		added = !deleted;
+		for (i = 0; added && i < num_parent; i++)
+			if (elem->parent[i].status !=
+			    DIFF_STATUS_ADDED)
+				added = 0;
+		if (added)
+			printf("%s%snew file mode %06o",
+			       line_prefix, c_meta, elem->mode);
+		else {
+			if (deleted)
+				printf("%s%sdeleted file ",
+				       line_prefix, c_meta);
+			printf("mode ");
+			for (i = 0; i < num_parent; i++) {
+				printf("%s%06o", i ? "," : "",
+				       elem->parent[i].mode);
+			}
+			if (elem->mode)
+				printf("..%06o", elem->mode);
+		}
+		printf("%s\n", c_reset);
+	}
+
+	if (!show_file_header)
+		return;
+
+	if (rev->combined_all_paths) {
+		for (i = 0; i < num_parent; i++) {
+			char *path = filename_changed(elem->parent[i].status)
+				? elem->parent[i].path.buf : elem->path;
+			if (elem->parent[i].status == DIFF_STATUS_ADDED)
+				dump_quoted_path("--- ", "", "/dev/null",
+						 line_prefix, c_meta, c_reset);
+			else
+				dump_quoted_path("--- ", a_prefix, path,
+						 line_prefix, c_meta, c_reset);
+		}
+	} else {
+		if (added)
+			dump_quoted_path("--- ", "", "/dev/null",
+					 line_prefix, c_meta, c_reset);
+		else
+			dump_quoted_path("--- ", a_prefix, elem->path,
+					 line_prefix, c_meta, c_reset);
+	}
+	if (deleted)
+		dump_quoted_path("+++ ", "", "/dev/null",
+				 line_prefix, c_meta, c_reset);
+	else
+		dump_quoted_path("+++ ", b_prefix, elem->path,
+				 line_prefix, c_meta, c_reset);
+}
+
+static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
+			    int working_tree_file,
+			    struct rev_info *rev)
+{
+	struct diff_options *opt = &rev->diffopt;
+	unsigned long result_size, cnt, lno;
+	int result_deleted = 0;
+	char *result, *cp;
+	struct sline *sline; /* survived lines */
+	int mode_differs = 0;
+	int i, show_hunks;
+	mmfile_t result_file;
+	struct userdiff_driver *userdiff;
+	struct userdiff_driver *textconv = NULL;
+	int is_binary;
+	const char *line_prefix = diff_line_prefix(opt);
+
+	context = opt->context;
+	userdiff = userdiff_find_by_path(opt->repo->index, elem->path);
+	if (!userdiff)
+		userdiff = userdiff_find_by_name("default");
+	if (opt->flags.allow_textconv)
+		textconv = userdiff_get_textconv(opt->repo, userdiff);
+
+	/* Read the result of merge first */
+	if (!working_tree_file)
+		result = grab_blob(opt->repo, &elem->oid, elem->mode, &result_size,
+				   textconv, elem->path);
+	else {
+		/* Used by diff-tree to read from the working tree */
+		struct stat st;
+		int fd = -1;
+
+		if (lstat(elem->path, &st) < 0)
+			goto deleted_file;
+
+		if (S_ISLNK(st.st_mode)) {
+			struct strbuf buf = STRBUF_INIT;
+
+			if (strbuf_readlink(&buf, elem->path, st.st_size) < 0) {
+				error_errno("readlink(%s)", elem->path);
+				return;
+			}
+			result_size = buf.len;
+			result = strbuf_detach(&buf, NULL);
+			elem->mode = canon_mode(st.st_mode);
+		} else if (S_ISDIR(st.st_mode)) {
+			struct object_id oid;
+			if (repo_resolve_gitlink_ref(the_repository, elem->path,
+						     "HEAD", &oid) < 0)
+				result = grab_blob(opt->repo, &elem->oid,
+						   elem->mode, &result_size,
+						   NULL, NULL);
+			else
+				result = grab_blob(opt->repo, &oid, elem->mode,
+						   &result_size, NULL, NULL);
+		} else if (textconv) {
+			struct diff_filespec *df = alloc_filespec(elem->path);
+			fill_filespec(df, null_oid(), 0, st.st_mode);
+			result_size = fill_textconv(opt->repo, textconv, df, &result);
+			free_filespec(df);
+		} else if (0 <= (fd = open(elem->path, O_RDONLY))) {
+			size_t len = xsize_t(st.st_size);
+			ssize_t done;
+			int is_file, i;
+
+			elem->mode = canon_mode(st.st_mode);
+			/* if symlinks don't work, assume symlink if all parents
+			 * are symlinks
+			 */
+			is_file = has_symlinks;
+			for (i = 0; !is_file && i < num_parent; i++)
+				is_file = !S_ISLNK(elem->parent[i].mode);
+			if (!is_file)
+				elem->mode = canon_mode(S_IFLNK);
+
+			result_size = len;
+			result = xmallocz(len);
+
+			done = read_in_full(fd, result, len);
+			if (done < 0)
+				die_errno("read error '%s'", elem->path);
+			else if (done < len)
+				die("early EOF '%s'", elem->path);
+
+			/* If not a fake symlink, apply filters, e.g. autocrlf */
+			if (is_file) {
+				struct strbuf buf = STRBUF_INIT;
+
+				if (convert_to_git(rev->diffopt.repo->index,
+						   elem->path, result, len, &buf, global_conv_flags_eol)) {
+					free(result);
+					result = strbuf_detach(&buf, &len);
+					result_size = len;
+				}
+			}
+		}
+		else {
+		deleted_file:
+			result_deleted = 1;
+			result_size = 0;
+			elem->mode = 0;
+			result = xcalloc(1, 1);
+		}
+
+		if (0 <= fd)
+			close(fd);
+	}
+
+	for (i = 0; i < num_parent; i++) {
+		if (elem->parent[i].mode != elem->mode) {
+			mode_differs = 1;
+			break;
+		}
+	}
+
+	if (textconv)
+		is_binary = 0;
+	else if (userdiff->binary != -1)
+		is_binary = userdiff->binary;
+	else {
+		is_binary = buffer_is_binary(result, result_size);
+		for (i = 0; !is_binary && i < num_parent; i++) {
+			char *buf;
+			unsigned long size;
+			buf = grab_blob(opt->repo,
+					&elem->parent[i].oid,
+					elem->parent[i].mode,
+					&size, NULL, NULL);
+			if (buffer_is_binary(buf, size))
+				is_binary = 1;
+			free(buf);
+		}
+	}
+	if (is_binary) {
+		show_combined_header(elem, num_parent, rev,
+				     line_prefix, mode_differs, 0);
+		printf("Binary files differ\n");
+		free(result);
+		return;
+	}
+
+	for (cnt = 0, cp = result; cp < result + result_size; cp++) {
+		if (*cp == '\n')
+			cnt++;
+	}
+	if (result_size && result[result_size-1] != '\n')
+		cnt++; /* incomplete line */
+
+	CALLOC_ARRAY(sline, st_add(cnt, 2));
+	sline[0].bol = result;
+	for (lno = 0, cp = result; cp < result + result_size; cp++) {
+		if (*cp == '\n') {
+			sline[lno].len = cp - sline[lno].bol;
+			lno++;
+			if (lno < cnt)
+				sline[lno].bol = cp + 1;
+		}
+	}
+	if (result_size && result[result_size-1] != '\n')
+		sline[cnt-1].len = result_size - (sline[cnt-1].bol - result);
+
+	result_file.ptr = result;
+	result_file.size = result_size;
+
+	/*
+	 * Even p_lno[cnt+1] is valid -- that is for the end line number
+	 * for deletion hunk at the end.
+	 */
+	CALLOC_ARRAY(sline[0].p_lno, st_mult(st_add(cnt, 2), num_parent));
+	for (lno = 0; lno <= cnt; lno++)
+		sline[lno+1].p_lno = sline[lno].p_lno + num_parent;
+
+	for (i = 0; i < num_parent; i++) {
+		int j;
+		for (j = 0; j < i; j++) {
+			if (oideq(&elem->parent[i].oid,
+				  &elem->parent[j].oid)) {
+				reuse_combine_diff(sline, cnt, i, j);
+				break;
+			}
+		}
+		if (i <= j)
+			combine_diff(opt->repo,
+				     &elem->parent[i].oid,
+				     elem->parent[i].mode,
+				     &result_file, sline,
+				     cnt, i, num_parent, result_deleted,
+				     textconv, elem->path, opt->xdl_opts);
+	}
+
+	show_hunks = make_hunks(sline, cnt, num_parent, rev->dense_combined_merges);
+
+	if (show_hunks || mode_differs || working_tree_file) {
+		show_combined_header(elem, num_parent, rev,
+				     line_prefix, mode_differs, 1);
+		dump_sline(sline, line_prefix, cnt, num_parent,
+			   opt->use_color, result_deleted);
+	}
+	free(result);
+
+	for (lno = 0; lno < cnt + 2; lno++) {
+		if (sline[lno].lost) {
+			struct lline *ll = sline[lno].lost;
+			while (ll) {
+				struct lline *tmp = ll;
+				ll = ll->next;
+				free(tmp);
+			}
+		}
+	}
+	free(sline[0].p_lno);
+	free(sline);
+}
+
+static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct rev_info *rev)
+{
+	struct diff_options *opt = &rev->diffopt;
+	int line_termination, inter_name_termination, i;
+	const char *line_prefix = diff_line_prefix(opt);
+
+	line_termination = opt->line_termination;
+	inter_name_termination = '\t';
+	if (!line_termination)
+		inter_name_termination = 0;
+
+	if (rev->loginfo && !rev->no_commit_id)
+		show_log(rev);
+
+
+	if (opt->output_format & DIFF_FORMAT_RAW) {
+		printf("%s", line_prefix);
+
+		/* As many colons as there are parents */
+		for (i = 0; i < num_parent; i++)
+			putchar(':');
+
+		/* Show the modes */
+		for (i = 0; i < num_parent; i++)
+			printf("%06o ", p->parent[i].mode);
+		printf("%06o", p->mode);
+
+		/* Show sha1's */
+		for (i = 0; i < num_parent; i++)
+			printf(" %s", diff_aligned_abbrev(&p->parent[i].oid,
+							  opt->abbrev));
+		printf(" %s ", diff_aligned_abbrev(&p->oid, opt->abbrev));
+	}
+
+	if (opt->output_format & (DIFF_FORMAT_RAW | DIFF_FORMAT_NAME_STATUS)) {
+		for (i = 0; i < num_parent; i++)
+			putchar(p->parent[i].status);
+		putchar(inter_name_termination);
+	}
+
+	for (i = 0; i < num_parent; i++)
+		if (rev->combined_all_paths) {
+			if (filename_changed(p->parent[i].status))
+				write_name_quoted(p->parent[i].path.buf, stdout,
+						  inter_name_termination);
+			else
+				write_name_quoted(p->path, stdout,
+						  inter_name_termination);
+		}
+	write_name_quoted(p->path, stdout, line_termination);
+}
+
+/*
+ * The result (p->elem) is from the working tree and their
+ * parents are typically from multiple stages during a merge
+ * (i.e. diff-files) or the state in HEAD and in the index
+ * (i.e. diff-index).
+ */
+void show_combined_diff(struct combine_diff_path *p,
+		       int num_parent,
+		       struct rev_info *rev)
+{
+	struct diff_options *opt = &rev->diffopt;
+
+	if (opt->output_format & (DIFF_FORMAT_RAW |
+				  DIFF_FORMAT_NAME |
+				  DIFF_FORMAT_NAME_STATUS))
+		show_raw_diff(p, num_parent, rev);
+	else if (opt->output_format & DIFF_FORMAT_PATCH)
+		show_patch_diff(p, num_parent, 1, rev);
+}
+
+static void free_combined_pair(struct diff_filepair *pair)
+{
+	free(pair->two);
+	free(pair);
+}
+
+/*
+ * A combine_diff_path expresses N parents on the LHS against 1 merge
+ * result. Synthesize a diff_filepair that has N entries on the "one"
+ * side and 1 entry on the "two" side.
+ *
+ * In the future, we might want to add more data to combine_diff_path
+ * so that we can fill fields we are ignoring (most notably, size) here,
+ * but currently nobody uses it, so this should suffice for now.
+ */
+static struct diff_filepair *combined_pair(struct combine_diff_path *p,
+					   int num_parent)
+{
+	int i;
+	struct diff_filepair *pair;
+	struct diff_filespec *pool;
+
+	pair = xmalloc(sizeof(*pair));
+	CALLOC_ARRAY(pool, st_add(num_parent, 1));
+	pair->one = pool + 1;
+	pair->two = pool;
+
+	for (i = 0; i < num_parent; i++) {
+		pair->one[i].path = p->path;
+		pair->one[i].mode = p->parent[i].mode;
+		oidcpy(&pair->one[i].oid, &p->parent[i].oid);
+		pair->one[i].oid_valid = !is_null_oid(&p->parent[i].oid);
+		pair->one[i].has_more_entries = 1;
+	}
+	pair->one[num_parent - 1].has_more_entries = 0;
+
+	pair->two->path = p->path;
+	pair->two->mode = p->mode;
+	oidcpy(&pair->two->oid, &p->oid);
+	pair->two->oid_valid = !is_null_oid(&p->oid);
+	return pair;
+}
+
+static void handle_combined_callback(struct diff_options *opt,
+				     struct combine_diff_path *paths,
+				     int num_parent,
+				     int num_paths)
+{
+	struct combine_diff_path *p;
+	struct diff_queue_struct q;
+	int i;
+
+	CALLOC_ARRAY(q.queue, num_paths);
+	q.alloc = num_paths;
+	q.nr = num_paths;
+	for (i = 0, p = paths; p; p = p->next)
+		q.queue[i++] = combined_pair(p, num_parent);
+	opt->format_callback(&q, opt, opt->format_callback_data);
+	for (i = 0; i < num_paths; i++)
+		free_combined_pair(q.queue[i]);
+	free(q.queue);
+}
+
+static const char *path_path(void *obj)
+{
+	struct combine_diff_path *path = (struct combine_diff_path *)obj;
+
+	return path->path;
+}
+
+/*
+ * Diff stat formats which we always compute solely against the first parent.
+ */
+#define STAT_FORMAT_MASK (DIFF_FORMAT_NUMSTAT \
+			  | DIFF_FORMAT_SHORTSTAT \
+			  | DIFF_FORMAT_SUMMARY \
+			  | DIFF_FORMAT_DIRSTAT \
+			  | DIFF_FORMAT_DIFFSTAT)
+
+/* find set of paths that every parent touches */
+static struct combine_diff_path *find_paths_generic(const struct object_id *oid,
+	const struct oid_array *parents,
+	struct diff_options *opt,
+	int combined_all_paths)
+{
+	struct combine_diff_path *paths = NULL;
+	int i, num_parent = parents->nr;
+	int output_format = opt->output_format;
+	char *orderfile = opt->orderfile;
+
+	opt->output_format = DIFF_FORMAT_NO_OUTPUT;
+	/* tell diff_tree to emit paths in sorted (=tree) order */
+	opt->orderfile = NULL;
+
+	/* D(A,P1...Pn) = D(A,P1) ^ ... ^ D(A,Pn)  (wrt paths) */
+	for (i = 0; i < num_parent; i++) {
+		/*
+		 * show stat against the first parent even when doing
+		 * combined diff.
+		 */
+		int stat_opt = output_format & STAT_FORMAT_MASK;
+		if (i == 0 && stat_opt)
+			opt->output_format = stat_opt;
+		else
+			opt->output_format = DIFF_FORMAT_NO_OUTPUT;
+		diff_tree_oid(&parents->oid[i], oid, "", opt);
+		diffcore_std(opt);
+		paths = intersect_paths(paths, i, num_parent,
+					combined_all_paths);
+
+		/* if showing diff, show it in requested order */
+		if (opt->output_format != DIFF_FORMAT_NO_OUTPUT &&
+		    orderfile) {
+			diffcore_order(orderfile);
+		}
+
+		diff_flush(opt);
+	}
+
+	opt->output_format = output_format;
+	opt->orderfile = orderfile;
+	return paths;
+}
+
+
+/*
+ * find set of paths that everybody touches, assuming diff is run without
+ * rename/copy detection, etc, comparing all trees simultaneously (= faster).
+ */
+static struct combine_diff_path *find_paths_multitree(
+	const struct object_id *oid, const struct oid_array *parents,
+	struct diff_options *opt)
+{
+	int i, nparent = parents->nr;
+	const struct object_id **parents_oid;
+	struct combine_diff_path paths_head;
+	struct strbuf base;
+
+	ALLOC_ARRAY(parents_oid, nparent);
+	for (i = 0; i < nparent; i++)
+		parents_oid[i] = &parents->oid[i];
+
+	/* fake list head, so worker can assume it is non-NULL */
+	paths_head.next = NULL;
+
+	strbuf_init(&base, PATH_MAX);
+	diff_tree_paths(&paths_head, oid, parents_oid, nparent, &base, opt);
+
+	strbuf_release(&base);
+	free(parents_oid);
+	return paths_head.next;
+}
+
+static int match_objfind(struct combine_diff_path *path,
+			 int num_parent,
+			 const struct oidset *set)
+{
+	int i;
+	if (oidset_contains(set, &path->oid))
+		return 1;
+	for (i = 0; i < num_parent; i++) {
+		if (oidset_contains(set, &path->parent[i].oid))
+			return 1;
+	}
+	return 0;
+}
+
+static struct combine_diff_path *combined_objfind(struct diff_options *opt,
+						  struct combine_diff_path *paths,
+						  int num_parent)
+{
+	struct combine_diff_path *ret = NULL, **tail = &ret;
+	struct combine_diff_path *p = paths;
+
+	while (p) {
+		struct combine_diff_path *next = p->next;
+
+		if (match_objfind(p, num_parent, opt->objfind)) {
+			p->next = NULL;
+			*tail = p;
+			tail = &p->next;
+		} else {
+			free(p);
+		}
+		p = next;
+	}
+
+	return ret;
+}
+
+void diff_tree_combined(const struct object_id *oid,
+			const struct oid_array *parents,
+			struct rev_info *rev)
+{
+	struct diff_options *opt = &rev->diffopt;
+	struct diff_options diffopts;
+	struct combine_diff_path *p, *paths;
+	int i, num_paths, needsep, show_log_first, num_parent = parents->nr;
+	int need_generic_pathscan;
+
+	if (opt->ignore_regex_nr)
+		die("combined diff and '%s' cannot be used together",
+		    "--ignore-matching-lines");
+	if (opt->close_file)
+		die("combined diff and '%s' cannot be used together",
+		    "--output");
+
+	/* nothing to do, if no parents */
+	if (!num_parent)
+		return;
+
+	show_log_first = !!rev->loginfo && !rev->no_commit_id;
+	needsep = 0;
+	if (show_log_first) {
+		show_log(rev);
+
+		if (rev->verbose_header && opt->output_format &&
+		    opt->output_format != DIFF_FORMAT_NO_OUTPUT &&
+		    !commit_format_is_empty(rev->commit_format))
+			printf("%s%c", diff_line_prefix(opt),
+			       opt->line_termination);
+	}
+
+	diffopts = *opt;
+	copy_pathspec(&diffopts.pathspec, &opt->pathspec);
+	diffopts.flags.recursive = 1;
+	diffopts.flags.allow_external = 0;
+
+	/* find set of paths that everybody touches
+	 *
+	 * NOTE
+	 *
+	 * Diffcore transformations are bound to diff_filespec and logic
+	 * comparing two entries - i.e. they do not apply directly to combine
+	 * diff.
+	 *
+	 * If some of such transformations is requested - we launch generic
+	 * path scanning, which works significantly slower compared to
+	 * simultaneous all-trees-in-one-go scan in find_paths_multitree().
+	 *
+	 * TODO some of the filters could be ported to work on
+	 * combine_diff_paths - i.e. all functionality that skips paths, so in
+	 * theory, we could end up having only multitree path scanning.
+	 *
+	 * NOTE please keep this semantically in sync with diffcore_std()
+	 */
+	need_generic_pathscan = opt->skip_stat_unmatch	||
+			opt->flags.follow_renames	||
+			opt->break_opt != -1	||
+			opt->detect_rename	||
+			(opt->pickaxe_opts &
+			 (DIFF_PICKAXE_KINDS_MASK & ~DIFF_PICKAXE_KIND_OBJFIND)) ||
+			opt->filter;
+
+	if (need_generic_pathscan) {
+		/*
+		 * NOTE generic case also handles --stat, as it computes
+		 * diff(sha1,parent_i) for all i to do the job, specifically
+		 * for parent0.
+		 */
+		paths = find_paths_generic(oid, parents, &diffopts,
+					   rev->combined_all_paths);
+	}
+	else {
+		int stat_opt;
+		paths = find_paths_multitree(oid, parents, &diffopts);
+
+		if (opt->pickaxe_opts & DIFF_PICKAXE_KIND_OBJFIND)
+			paths = combined_objfind(opt, paths, num_parent);
+
+		/*
+		 * show stat against the first parent even
+		 * when doing combined diff.
+		 */
+		stat_opt = opt->output_format & STAT_FORMAT_MASK;
+		if (stat_opt) {
+			diffopts.output_format = stat_opt;
+
+			diff_tree_oid(&parents->oid[0], oid, "", &diffopts);
+			diffcore_std(&diffopts);
+			if (opt->orderfile)
+				diffcore_order(opt->orderfile);
+			diff_flush(&diffopts);
+		}
+	}
+
+	/* find out number of surviving paths */
+	for (num_paths = 0, p = paths; p; p = p->next)
+		num_paths++;
+
+	/* order paths according to diffcore_order */
+	if (opt->orderfile && num_paths) {
+		struct obj_order *o;
+
+		ALLOC_ARRAY(o, num_paths);
+		for (i = 0, p = paths; p; p = p->next, i++)
+			o[i].obj = p;
+		order_objects(opt->orderfile, path_path, o, num_paths);
+		for (i = 0; i < num_paths - 1; i++) {
+			p = o[i].obj;
+			p->next = o[i+1].obj;
+		}
+
+		p = o[num_paths-1].obj;
+		p->next = NULL;
+		paths = o[0].obj;
+		free(o);
+	}
+
+
+	if (num_paths) {
+		if (opt->output_format & (DIFF_FORMAT_RAW |
+					  DIFF_FORMAT_NAME |
+					  DIFF_FORMAT_NAME_STATUS)) {
+			for (p = paths; p; p = p->next)
+				show_raw_diff(p, num_parent, rev);
+			needsep = 1;
+		}
+		else if (opt->output_format & STAT_FORMAT_MASK)
+			needsep = 1;
+		else if (opt->output_format & DIFF_FORMAT_CALLBACK)
+			handle_combined_callback(opt, paths, num_parent, num_paths);
+
+		if (opt->output_format & DIFF_FORMAT_PATCH) {
+			if (needsep)
+				printf("%s%c", diff_line_prefix(opt),
+				       opt->line_termination);
+			for (p = paths; p; p = p->next)
+				show_patch_diff(p, num_parent, 0, rev);
+		}
+	}
+
+	/* Clean things up */
+	while (paths) {
+		struct combine_diff_path *tmp = paths;
+		paths = paths->next;
+		for (i = 0; i < num_parent; i++)
+			if (rev->combined_all_paths &&
+			    filename_changed(tmp->parent[i].status))
+				strbuf_release(&tmp->parent[i].path);
+		free(tmp);
+	}
+
+	clear_pathspec(&diffopts.pathspec);
+}
+
+void diff_tree_combined_merge(const struct commit *commit,
+			      struct rev_info *rev)
+{
+	struct commit_list *parent = get_saved_parents(rev, commit);
+	struct oid_array parents = OID_ARRAY_INIT;
+
+	while (parent) {
+		oid_array_append(&parents, &parent->item->object.oid);
+		parent = parent->next;
+	}
+	diff_tree_combined(&commit->object.oid, &parents, rev);
+	oid_array_clear(&parents);
+}
diff --git a/command-list.txt b/command-list.txt
new file mode 100644
index 0000000000..e0bb87b3b5
--- /dev/null
+++ b/command-list.txt
@@ -0,0 +1,242 @@
+# Command classification list
+# ---------------------------
+# All supported commands, builtin or external, must be described in
+# here. This info is used to list commands in various places. Each
+# command is on one line followed by one or more attributes.
+#
+# The first attribute group is mandatory and indicates the command
+# type. This group includes:
+#
+#   mainporcelain
+#   ancillarymanipulators
+#   ancillaryinterrogators
+#   foreignscminterface
+#   plumbingmanipulators
+#   plumbinginterrogators
+#   synchingrepositories
+#   synchelpers
+#   purehelpers
+#
+# The type names are self explanatory. But if you want to see what
+# command belongs to what group to get a better picture, have a look
+# at "git" man page, "GIT COMMANDS" section.
+#
+# Commands of type mainporcelain can also optionally have one of these
+# attributes:
+#
+#   init
+#   worktree
+#   info
+#   history
+#   remote
+#
+# These commands are considered "common" and will show up in "git
+# help" output in groups. Uncommon porcelain commands must not
+# specify any of these attributes.
+#
+# "complete" attribute is used to mark that the command should be
+# completable by git-completion.bash. Note that by default,
+# mainporcelain commands are completable so you don't need this
+# attribute.
+#
+# As part of the Git man page list, the man(5/7) guides are also
+# specified here, which can only have "guide" attribute and nothing
+# else.
+#
+# User-facing repository, command and file interfaces such as
+# documentation for the .gitmodules, .mailmap etc. files lives in man
+# sections 5 and 7. These entries can only have the "userinterfaces"
+# attribute and nothing else.
+#
+# Git's file formats and protocols, such as documentation for the
+# *.bundle format lives in man section 5. These entries can only have
+# the "developerinterfaces" attribute and nothing else.
+#
+### command list (do not change this line)
+# command name                          category [category] [category]
+git-add                                 mainporcelain           worktree
+git-am                                  mainporcelain
+git-annotate                            ancillaryinterrogators
+git-apply                               plumbingmanipulators            complete
+git-archimport                          foreignscminterface
+git-archive                             mainporcelain
+git-bisect                              mainporcelain           info
+git-blame                               ancillaryinterrogators          complete
+git-branch                              mainporcelain           history
+git-bugreport                           ancillaryinterrogators
+git-bundle                              mainporcelain
+git-cat-file                            plumbinginterrogators
+git-check-attr                          purehelpers
+git-check-ignore                        purehelpers
+git-check-mailmap                       purehelpers
+git-check-ref-format                    purehelpers
+git-checkout                            mainporcelain
+git-checkout-index                      plumbingmanipulators
+git-cherry                              plumbinginterrogators          complete
+git-cherry-pick                         mainporcelain
+git-citool                              mainporcelain
+git-clean                               mainporcelain
+git-clone                               mainporcelain           init
+git-column                              purehelpers
+git-commit                              mainporcelain           history
+git-commit-graph                        plumbingmanipulators
+git-commit-tree                         plumbingmanipulators
+git-config                              ancillarymanipulators           complete
+git-count-objects                       ancillaryinterrogators
+git-credential                          purehelpers
+git-credential-cache                    purehelpers
+git-credential-store                    purehelpers
+git-cvsexportcommit                     foreignscminterface
+git-cvsimport                           foreignscminterface
+git-cvsserver                           foreignscminterface
+git-daemon                              synchingrepositories
+git-describe                            mainporcelain
+git-diagnose                            ancillaryinterrogators
+git-diff                                mainporcelain           info
+git-diff-files                          plumbinginterrogators
+git-diff-index                          plumbinginterrogators
+git-diff-tree                           plumbinginterrogators
+git-difftool                            ancillaryinterrogators          complete
+git-fast-export                         ancillarymanipulators
+git-fast-import                         ancillarymanipulators
+git-fetch                               mainporcelain           remote
+git-fetch-pack                          synchingrepositories
+git-filter-branch                       ancillarymanipulators
+git-fmt-merge-msg                       purehelpers
+git-for-each-ref                        plumbinginterrogators
+git-for-each-repo                       plumbinginterrogators
+git-format-patch                        mainporcelain
+git-fsck                                ancillaryinterrogators          complete
+git-gc                                  mainporcelain
+git-get-tar-commit-id                   plumbinginterrogators
+git-grep                                mainporcelain           info
+git-gui                                 mainporcelain
+git-hash-object                         plumbingmanipulators
+git-help                                ancillaryinterrogators          complete
+git-hook                                purehelpers
+git-http-backend                        synchingrepositories
+git-http-fetch                          synchelpers
+git-http-push                           synchelpers
+git-imap-send                           foreignscminterface
+git-index-pack                          plumbingmanipulators
+git-init                                mainporcelain           init
+git-instaweb                            ancillaryinterrogators          complete
+git-interpret-trailers                  purehelpers
+git-log                                 mainporcelain           info
+git-ls-files                            plumbinginterrogators
+git-ls-remote                           plumbinginterrogators
+git-ls-tree                             plumbinginterrogators
+git-mailinfo                            purehelpers
+git-mailsplit                           purehelpers
+git-maintenance                         mainporcelain
+git-merge                               mainporcelain           history
+git-merge-base                          plumbinginterrogators
+git-merge-file                          plumbingmanipulators
+git-merge-index                         plumbingmanipulators
+git-merge-one-file                      purehelpers
+git-merge-tree                          ancillaryinterrogators
+git-mergetool                           ancillarymanipulators           complete
+git-mktag                               plumbingmanipulators
+git-mktree                              plumbingmanipulators
+git-multi-pack-index                    plumbingmanipulators
+git-mv                                  mainporcelain           worktree
+git-name-rev                            plumbinginterrogators
+git-notes                               mainporcelain
+git-p4                                  foreignscminterface
+git-pack-objects                        plumbingmanipulators
+git-pack-redundant                      plumbinginterrogators
+git-pack-refs                           ancillarymanipulators
+git-patch-id                            purehelpers
+git-prune                               ancillarymanipulators   complete
+git-prune-packed                        plumbingmanipulators
+git-pull                                mainporcelain           remote
+git-push                                mainporcelain           remote
+git-quiltimport                         foreignscminterface
+git-range-diff                          mainporcelain
+git-read-tree                           plumbingmanipulators
+git-rebase                              mainporcelain           history
+git-receive-pack                        synchelpers
+git-reflog                              ancillarymanipulators           complete
+git-refs                                ancillarymanipulators           complete
+git-remote                              ancillarymanipulators           complete
+git-repack                              ancillarymanipulators           complete
+git-replace                             ancillarymanipulators           complete
+git-replay                              plumbingmanipulators
+git-request-pull                        foreignscminterface             complete
+git-rerere                              ancillaryinterrogators
+git-reset                               mainporcelain           history
+git-restore                             mainporcelain           worktree
+git-rev-list                            plumbinginterrogators
+git-rev-parse                           plumbinginterrogators
+git-revert                              mainporcelain
+git-rm                                  mainporcelain           worktree
+git-send-email                          foreignscminterface             complete
+git-send-pack                           synchingrepositories
+git-sh-i18n                             purehelpers
+git-sh-setup                            purehelpers
+git-shell                               synchelpers
+git-shortlog                            mainporcelain
+git-show                                mainporcelain           info
+git-show-branch                         ancillaryinterrogators          complete
+git-show-index                          plumbinginterrogators
+git-show-ref                            plumbinginterrogators
+git-sparse-checkout                     mainporcelain
+git-stage                                                               complete
+git-stash                               mainporcelain
+git-status                              mainporcelain           info
+git-stripspace                          purehelpers
+git-submodule                           mainporcelain
+git-svn                                 foreignscminterface
+git-switch                              mainporcelain           history
+git-symbolic-ref                        plumbingmanipulators
+git-tag                                 mainporcelain           history
+git-unpack-file                         plumbinginterrogators
+git-unpack-objects                      plumbingmanipulators
+git-update-index                        plumbingmanipulators
+git-update-ref                          plumbingmanipulators
+git-update-server-info                  synchingrepositories
+git-upload-archive                      synchelpers
+git-upload-pack                         synchelpers
+git-var                                 plumbinginterrogators
+git-verify-commit                       ancillaryinterrogators
+git-verify-pack                         plumbinginterrogators
+git-verify-tag                          ancillaryinterrogators
+git-version                             ancillaryinterrogators
+git-whatchanged                         ancillaryinterrogators          complete
+git-worktree                            mainporcelain
+git-write-tree                          plumbingmanipulators
+gitattributes                           userinterfaces
+gitcli                                  userinterfaces
+gitcore-tutorial                        guide
+gitcredentials                          guide
+gitcvs-migration                        guide
+gitdiffcore                             guide
+giteveryday                             guide
+gitfaq                                  guide
+gitformat-bundle                        developerinterfaces
+gitformat-chunk                         developerinterfaces
+gitformat-commit-graph                  developerinterfaces
+gitformat-index                         developerinterfaces
+gitformat-pack                          developerinterfaces
+gitformat-signature                     developerinterfaces
+gitglossary                             guide
+githooks                                userinterfaces
+gitignore                               userinterfaces
+gitk                                    mainporcelain
+gitmailmap                              userinterfaces
+gitmodules                              userinterfaces
+gitnamespaces                           guide
+gitprotocol-capabilities                developerinterfaces
+gitprotocol-common                      developerinterfaces
+gitprotocol-http                        developerinterfaces
+gitprotocol-pack                        developerinterfaces
+gitprotocol-v2                          developerinterfaces
+gitremote-helpers                       guide
+gitrepository-layout                    userinterfaces
+gitrevisions                            userinterfaces
+gitsubmodules                           guide
+gittutorial                             guide
+gittutorial-2                           guide
+gitweb                                  ancillaryinterrogators
+gitworkflows                            guide
+scalar                                  mainporcelain
diff --git a/commit-graph.c b/commit-graph.c
new file mode 100644
index 0000000000..2a2999a6b8
--- /dev/null
+++ b/commit-graph.c
@@ -0,0 +1,2924 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "csum-file.h"
+#include "gettext.h"
+#include "hex.h"
+#include "lockfile.h"
+#include "packfile.h"
+#include "commit.h"
+#include "object.h"
+#include "refs.h"
+#include "hash-lookup.h"
+#include "commit-graph.h"
+#include "object-file.h"
+#include "object-store-ll.h"
+#include "oid-array.h"
+#include "path.h"
+#include "alloc.h"
+#include "hashmap.h"
+#include "replace-object.h"
+#include "progress.h"
+#include "bloom.h"
+#include "commit-slab.h"
+#include "shallow.h"
+#include "json-writer.h"
+#include "trace2.h"
+#include "tree.h"
+#include "chunk-format.h"
+
+void git_test_write_commit_graph_or_die(void)
+{
+	int flags = 0;
+	if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))
+		return;
+
+	if (git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
+		flags = COMMIT_GRAPH_WRITE_BLOOM_FILTERS;
+
+	if (write_commit_graph_reachable(the_repository->objects->odb,
+					 flags, NULL))
+		die("failed to write commit-graph under GIT_TEST_COMMIT_GRAPH");
+}
+
+#define GRAPH_SIGNATURE 0x43475048 /* "CGPH" */
+#define GRAPH_CHUNKID_OIDFANOUT 0x4f494446 /* "OIDF" */
+#define GRAPH_CHUNKID_OIDLOOKUP 0x4f49444c /* "OIDL" */
+#define GRAPH_CHUNKID_DATA 0x43444154 /* "CDAT" */
+#define GRAPH_CHUNKID_GENERATION_DATA 0x47444132 /* "GDA2" */
+#define GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW 0x47444f32 /* "GDO2" */
+#define GRAPH_CHUNKID_EXTRAEDGES 0x45444745 /* "EDGE" */
+#define GRAPH_CHUNKID_BLOOMINDEXES 0x42494458 /* "BIDX" */
+#define GRAPH_CHUNKID_BLOOMDATA 0x42444154 /* "BDAT" */
+#define GRAPH_CHUNKID_BASE 0x42415345 /* "BASE" */
+
+#define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)
+
+#define GRAPH_VERSION_1 0x1
+#define GRAPH_VERSION GRAPH_VERSION_1
+
+#define GRAPH_EXTRA_EDGES_NEEDED 0x80000000
+#define GRAPH_EDGE_LAST_MASK 0x7fffffff
+#define GRAPH_PARENT_NONE 0x70000000
+
+#define GRAPH_LAST_EDGE 0x80000000
+
+#define GRAPH_HEADER_SIZE 8
+#define GRAPH_FANOUT_SIZE (4 * 256)
+#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE \
+			+ GRAPH_FANOUT_SIZE + the_hash_algo->rawsz)
+
+#define CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW (1ULL << 31)
+
+/* Remember to update object flag allocation in object.h */
+#define REACHABLE       (1u<<15)
+
+define_commit_slab(topo_level_slab, uint32_t);
+
+/* Keep track of the order in which commits are added to our list. */
+define_commit_slab(commit_pos, int);
+static struct commit_pos commit_pos = COMMIT_SLAB_INIT(1, commit_pos);
+
+static void set_commit_pos(struct repository *r, const struct object_id *oid)
+{
+	static int32_t max_pos;
+	struct commit *commit = lookup_commit(r, oid);
+
+	if (!commit)
+		return; /* should never happen, but be lenient */
+
+	*commit_pos_at(&commit_pos, commit) = max_pos++;
+}
+
+static int commit_pos_cmp(const void *va, const void *vb)
+{
+	const struct commit *a = *(const struct commit **)va;
+	const struct commit *b = *(const struct commit **)vb;
+	return commit_pos_at(&commit_pos, a) -
+	       commit_pos_at(&commit_pos, b);
+}
+
+define_commit_slab(commit_graph_data_slab, struct commit_graph_data);
+static struct commit_graph_data_slab commit_graph_data_slab =
+	COMMIT_SLAB_INIT(1, commit_graph_data_slab);
+
+static int get_configured_generation_version(struct repository *r)
+{
+	int version = 2;
+	repo_config_get_int(r, "commitgraph.generationversion", &version);
+	return version;
+}
+
+uint32_t commit_graph_position(const struct commit *c)
+{
+	struct commit_graph_data *data =
+		commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+	return data ? data->graph_pos : COMMIT_NOT_FROM_GRAPH;
+}
+
+timestamp_t commit_graph_generation(const struct commit *c)
+{
+	struct commit_graph_data *data =
+		commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+	if (data && data->generation)
+		return data->generation;
+
+	return GENERATION_NUMBER_INFINITY;
+}
+
+static timestamp_t commit_graph_generation_from_graph(const struct commit *c)
+{
+	struct commit_graph_data *data =
+		commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+	if (!data || data->graph_pos == COMMIT_NOT_FROM_GRAPH)
+		return GENERATION_NUMBER_INFINITY;
+	return data->generation;
+}
+
+static struct commit_graph_data *commit_graph_data_at(const struct commit *c)
+{
+	unsigned int i, nth_slab;
+	struct commit_graph_data *data =
+		commit_graph_data_slab_peek(&commit_graph_data_slab, c);
+
+	if (data)
+		return data;
+
+	nth_slab = c->index / commit_graph_data_slab.slab_size;
+	data = commit_graph_data_slab_at(&commit_graph_data_slab, c);
+
+	/*
+	 * commit-slab initializes elements with zero, overwrite this with
+	 * COMMIT_NOT_FROM_GRAPH for graph_pos.
+	 *
+	 * We avoid initializing generation with checking if graph position
+	 * is not COMMIT_NOT_FROM_GRAPH.
+	 */
+	for (i = 0; i < commit_graph_data_slab.slab_size; i++) {
+		commit_graph_data_slab.slab[nth_slab][i].graph_pos =
+			COMMIT_NOT_FROM_GRAPH;
+	}
+
+	return data;
+}
+
+/*
+ * Should be used only while writing commit-graph as it compares
+ * generation value of commits by directly accessing commit-slab.
+ */
+static int commit_gen_cmp(const void *va, const void *vb)
+{
+	const struct commit *a = *(const struct commit **)va;
+	const struct commit *b = *(const struct commit **)vb;
+
+	const timestamp_t generation_a = commit_graph_data_at(a)->generation;
+	const timestamp_t generation_b = commit_graph_data_at(b)->generation;
+	/* lower generation commits first */
+	if (generation_a < generation_b)
+		return -1;
+	else if (generation_a > generation_b)
+		return 1;
+
+	/* use date as a heuristic when generations are equal */
+	if (a->date < b->date)
+		return -1;
+	else if (a->date > b->date)
+		return 1;
+	return 0;
+}
+
+char *get_commit_graph_filename(struct object_directory *obj_dir)
+{
+	return xstrfmt("%s/info/commit-graph", obj_dir->path);
+}
+
+static char *get_split_graph_filename(struct object_directory *odb,
+				      const char *oid_hex)
+{
+	return xstrfmt("%s/info/commit-graphs/graph-%s.graph", odb->path,
+		       oid_hex);
+}
+
+char *get_commit_graph_chain_filename(struct object_directory *odb)
+{
+	return xstrfmt("%s/info/commit-graphs/commit-graph-chain", odb->path);
+}
+
+static struct commit_graph *alloc_commit_graph(void)
+{
+	struct commit_graph *g = xcalloc(1, sizeof(*g));
+
+	return g;
+}
+
+static int commit_graph_compatible(struct repository *r)
+{
+	if (!r->gitdir)
+		return 0;
+
+	if (replace_refs_enabled(r)) {
+		prepare_replace_object(r);
+		if (hashmap_get_size(&r->objects->replace_map->map))
+			return 0;
+	}
+
+	prepare_commit_graft(r);
+	if (r->parsed_objects &&
+	    (r->parsed_objects->grafts_nr || r->parsed_objects->substituted_parent))
+		return 0;
+	if (is_repository_shallow(r))
+		return 0;
+
+	return 1;
+}
+
+int open_commit_graph(const char *graph_file, int *fd, struct stat *st)
+{
+	*fd = git_open(graph_file);
+	if (*fd < 0)
+		return 0;
+	if (fstat(*fd, st)) {
+		close(*fd);
+		return 0;
+	}
+	return 1;
+}
+
+struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
+						 int fd, struct stat *st,
+						 struct object_directory *odb)
+{
+	void *graph_map;
+	size_t graph_size;
+	struct commit_graph *ret;
+
+	graph_size = xsize_t(st->st_size);
+
+	if (graph_size < GRAPH_MIN_SIZE) {
+		close(fd);
+		error(_("commit-graph file is too small"));
+		return NULL;
+	}
+	graph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	close(fd);
+	prepare_repo_settings(r);
+	ret = parse_commit_graph(&r->settings, graph_map, graph_size);
+
+	if (ret)
+		ret->odb = odb;
+	else
+		munmap(graph_map, graph_size);
+
+	return ret;
+}
+
+static int graph_read_oid_fanout(const unsigned char *chunk_start,
+				 size_t chunk_size, void *data)
+{
+	struct commit_graph *g = data;
+	int i;
+
+	if (chunk_size != 256 * sizeof(uint32_t))
+		return error(_("commit-graph oid fanout chunk is wrong size"));
+	g->chunk_oid_fanout = (const uint32_t *)chunk_start;
+	g->num_commits = ntohl(g->chunk_oid_fanout[255]);
+
+	for (i = 0; i < 255; i++) {
+		uint32_t oid_fanout1 = ntohl(g->chunk_oid_fanout[i]);
+		uint32_t oid_fanout2 = ntohl(g->chunk_oid_fanout[i + 1]);
+
+		if (oid_fanout1 > oid_fanout2) {
+			error(_("commit-graph fanout values out of order"));
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int graph_read_oid_lookup(const unsigned char *chunk_start,
+				 size_t chunk_size, void *data)
+{
+	struct commit_graph *g = data;
+	g->chunk_oid_lookup = chunk_start;
+	if (chunk_size / g->hash_len != g->num_commits)
+		return error(_("commit-graph OID lookup chunk is the wrong size"));
+	return 0;
+}
+
+static int graph_read_commit_data(const unsigned char *chunk_start,
+				  size_t chunk_size, void *data)
+{
+	struct commit_graph *g = data;
+	if (chunk_size / GRAPH_DATA_WIDTH != g->num_commits)
+		return error(_("commit-graph commit data chunk is wrong size"));
+	g->chunk_commit_data = chunk_start;
+	return 0;
+}
+
+static int graph_read_generation_data(const unsigned char *chunk_start,
+				      size_t chunk_size, void *data)
+{
+	struct commit_graph *g = data;
+	if (chunk_size / sizeof(uint32_t) != g->num_commits)
+		return error(_("commit-graph generations chunk is wrong size"));
+	g->chunk_generation_data = chunk_start;
+	return 0;
+}
+
+static int graph_read_bloom_index(const unsigned char *chunk_start,
+				  size_t chunk_size, void *data)
+{
+	struct commit_graph *g = data;
+	if (chunk_size / 4 != g->num_commits) {
+		warning(_("commit-graph changed-path index chunk is too small"));
+		return -1;
+	}
+	g->chunk_bloom_indexes = chunk_start;
+	return 0;
+}
+
+static int graph_read_bloom_data(const unsigned char *chunk_start,
+				  size_t chunk_size, void *data)
+{
+	struct commit_graph *g = data;
+
+	if (chunk_size < BLOOMDATA_CHUNK_HEADER_SIZE) {
+		warning(_("ignoring too-small changed-path chunk"
+			" (%"PRIuMAX" < %"PRIuMAX") in commit-graph file"),
+			(uintmax_t)chunk_size,
+			(uintmax_t)BLOOMDATA_CHUNK_HEADER_SIZE);
+		return -1;
+	}
+
+	g->chunk_bloom_data = chunk_start;
+	g->chunk_bloom_data_size = chunk_size;
+
+	g->bloom_filter_settings = xmalloc(sizeof(struct bloom_filter_settings));
+	g->bloom_filter_settings->hash_version = get_be32(chunk_start);
+	g->bloom_filter_settings->num_hashes = get_be32(chunk_start + 4);
+	g->bloom_filter_settings->bits_per_entry = get_be32(chunk_start + 8);
+	g->bloom_filter_settings->max_changed_paths = DEFAULT_BLOOM_MAX_CHANGES;
+
+	return 0;
+}
+
+struct commit_graph *parse_commit_graph(struct repo_settings *s,
+					void *graph_map, size_t graph_size)
+{
+	const unsigned char *data;
+	struct commit_graph *graph;
+	uint32_t graph_signature;
+	unsigned char graph_version, hash_version;
+	struct chunkfile *cf = NULL;
+
+	if (!graph_map)
+		return NULL;
+
+	if (graph_size < GRAPH_MIN_SIZE)
+		return NULL;
+
+	data = (const unsigned char *)graph_map;
+
+	graph_signature = get_be32(data);
+	if (graph_signature != GRAPH_SIGNATURE) {
+		error(_("commit-graph signature %X does not match signature %X"),
+		      graph_signature, GRAPH_SIGNATURE);
+		return NULL;
+	}
+
+	graph_version = *(unsigned char*)(data + 4);
+	if (graph_version != GRAPH_VERSION) {
+		error(_("commit-graph version %X does not match version %X"),
+		      graph_version, GRAPH_VERSION);
+		return NULL;
+	}
+
+	hash_version = *(unsigned char*)(data + 5);
+	if (hash_version != oid_version(the_hash_algo)) {
+		error(_("commit-graph hash version %X does not match version %X"),
+		      hash_version, oid_version(the_hash_algo));
+		return NULL;
+	}
+
+	graph = alloc_commit_graph();
+
+	graph->hash_len = the_hash_algo->rawsz;
+	graph->num_chunks = *(unsigned char*)(data + 6);
+	graph->data = graph_map;
+	graph->data_len = graph_size;
+
+	if (graph_size < GRAPH_HEADER_SIZE +
+			 (graph->num_chunks + 1) * CHUNK_TOC_ENTRY_SIZE +
+			 GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {
+		error(_("commit-graph file is too small to hold %u chunks"),
+		      graph->num_chunks);
+		free(graph);
+		return NULL;
+	}
+
+	cf = init_chunkfile(NULL);
+
+	if (read_table_of_contents(cf, graph->data, graph_size,
+				   GRAPH_HEADER_SIZE, graph->num_chunks, 1))
+		goto free_and_return;
+
+	if (read_chunk(cf, GRAPH_CHUNKID_OIDFANOUT, graph_read_oid_fanout, graph)) {
+		error(_("commit-graph required OID fanout chunk missing or corrupted"));
+		goto free_and_return;
+	}
+	if (read_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, graph_read_oid_lookup, graph)) {
+		error(_("commit-graph required OID lookup chunk missing or corrupted"));
+		goto free_and_return;
+	}
+	if (read_chunk(cf, GRAPH_CHUNKID_DATA, graph_read_commit_data, graph)) {
+		error(_("commit-graph required commit data chunk missing or corrupted"));
+		goto free_and_return;
+	}
+
+	pair_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES, &graph->chunk_extra_edges,
+		   &graph->chunk_extra_edges_size);
+	pair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs,
+		   &graph->chunk_base_graphs_size);
+
+	if (s->commit_graph_generation_version >= 2) {
+		read_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
+			   graph_read_generation_data, graph);
+		pair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
+			   &graph->chunk_generation_data_overflow,
+			   &graph->chunk_generation_data_overflow_size);
+
+		if (graph->chunk_generation_data)
+			graph->read_generation_data = 1;
+	}
+
+	if (s->commit_graph_changed_paths_version) {
+		read_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
+			   graph_read_bloom_index, graph);
+		read_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,
+			   graph_read_bloom_data, graph);
+	}
+
+	if (graph->chunk_bloom_indexes && graph->chunk_bloom_data) {
+		init_bloom_filters();
+	} else {
+		/* We need both the bloom chunks to exist together. Else ignore the data */
+		graph->chunk_bloom_indexes = NULL;
+		graph->chunk_bloom_data = NULL;
+		FREE_AND_NULL(graph->bloom_filter_settings);
+	}
+
+	oidread(&graph->oid, graph->data + graph->data_len - graph->hash_len,
+		the_repository->hash_algo);
+
+	free_chunkfile(cf);
+	return graph;
+
+free_and_return:
+	free_chunkfile(cf);
+	free(graph->bloom_filter_settings);
+	free(graph);
+	return NULL;
+}
+
+static struct commit_graph *load_commit_graph_one(struct repository *r,
+						  const char *graph_file,
+						  struct object_directory *odb)
+{
+
+	struct stat st;
+	int fd;
+	struct commit_graph *g;
+	int open_ok = open_commit_graph(graph_file, &fd, &st);
+
+	if (!open_ok)
+		return NULL;
+
+	g = load_commit_graph_one_fd_st(r, fd, &st, odb);
+
+	if (g)
+		g->filename = xstrdup(graph_file);
+
+	return g;
+}
+
+static struct commit_graph *load_commit_graph_v1(struct repository *r,
+						 struct object_directory *odb)
+{
+	char *graph_name = get_commit_graph_filename(odb);
+	struct commit_graph *g = load_commit_graph_one(r, graph_name, odb);
+	free(graph_name);
+
+	return g;
+}
+
+/*
+ * returns 1 if and only if all graphs in the chain have
+ * corrected commit dates stored in the generation_data chunk.
+ */
+static int validate_mixed_generation_chain(struct commit_graph *g)
+{
+	int read_generation_data = 1;
+	struct commit_graph *p = g;
+
+	while (read_generation_data && p) {
+		read_generation_data = p->read_generation_data;
+		p = p->base_graph;
+	}
+
+	if (read_generation_data)
+		return 1;
+
+	while (g) {
+		g->read_generation_data = 0;
+		g = g->base_graph;
+	}
+
+	return 0;
+}
+
+static void validate_mixed_bloom_settings(struct commit_graph *g)
+{
+	struct bloom_filter_settings *settings = NULL;
+	for (; g; g = g->base_graph) {
+		if (!g->bloom_filter_settings)
+			continue;
+		if (!settings) {
+			settings = g->bloom_filter_settings;
+			continue;
+		}
+
+		if (g->bloom_filter_settings->bits_per_entry != settings->bits_per_entry ||
+		    g->bloom_filter_settings->num_hashes != settings->num_hashes ||
+		    g->bloom_filter_settings->hash_version != settings->hash_version) {
+			g->chunk_bloom_indexes = NULL;
+			g->chunk_bloom_data = NULL;
+			FREE_AND_NULL(g->bloom_filter_settings);
+
+			warning(_("disabling Bloom filters for commit-graph "
+				  "layer '%s' due to incompatible settings"),
+				oid_to_hex(&g->oid));
+		}
+	}
+}
+
+static int add_graph_to_chain(struct commit_graph *g,
+			      struct commit_graph *chain,
+			      struct object_id *oids,
+			      int n)
+{
+	struct commit_graph *cur_g = chain;
+
+	if (n && !g->chunk_base_graphs) {
+		warning(_("commit-graph has no base graphs chunk"));
+		return 0;
+	}
+
+	if (g->chunk_base_graphs_size / g->hash_len < n) {
+		warning(_("commit-graph base graphs chunk is too small"));
+		return 0;
+	}
+
+	while (n) {
+		n--;
+
+		if (!cur_g ||
+		    !oideq(&oids[n], &cur_g->oid) ||
+		    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n),
+			    the_repository->hash_algo)) {
+			warning(_("commit-graph chain does not match"));
+			return 0;
+		}
+
+		cur_g = cur_g->base_graph;
+	}
+
+	if (chain) {
+		if (unsigned_add_overflows(chain->num_commits,
+					   chain->num_commits_in_base)) {
+			warning(_("commit count in base graph too high: %"PRIuMAX),
+				(uintmax_t)chain->num_commits_in_base);
+			return 0;
+		}
+		g->num_commits_in_base = chain->num_commits + chain->num_commits_in_base;
+	}
+
+	g->base_graph = chain;
+
+	return 1;
+}
+
+int open_commit_graph_chain(const char *chain_file,
+			    int *fd, struct stat *st)
+{
+	*fd = git_open(chain_file);
+	if (*fd < 0)
+		return 0;
+	if (fstat(*fd, st)) {
+		close(*fd);
+		return 0;
+	}
+	if (st->st_size < the_hash_algo->hexsz) {
+		close(*fd);
+		if (!st->st_size) {
+			/* treat empty files the same as missing */
+			errno = ENOENT;
+		} else {
+			warning(_("commit-graph chain file too small"));
+			errno = EINVAL;
+		}
+		return 0;
+	}
+	return 1;
+}
+
+struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,
+						   int fd, struct stat *st,
+						   int *incomplete_chain)
+{
+	struct commit_graph *graph_chain = NULL;
+	struct strbuf line = STRBUF_INIT;
+	struct object_id *oids;
+	int i = 0, valid = 1, count;
+	FILE *fp = xfdopen(fd, "r");
+
+	count = st->st_size / (the_hash_algo->hexsz + 1);
+	CALLOC_ARRAY(oids, count);
+
+	prepare_alt_odb(r);
+
+	for (i = 0; i < count; i++) {
+		struct object_directory *odb;
+
+		if (strbuf_getline_lf(&line, fp) == EOF)
+			break;
+
+		if (get_oid_hex(line.buf, &oids[i])) {
+			warning(_("invalid commit-graph chain: line '%s' not a hash"),
+				line.buf);
+			valid = 0;
+			break;
+		}
+
+		valid = 0;
+		for (odb = r->objects->odb; odb; odb = odb->next) {
+			char *graph_name = get_split_graph_filename(odb, line.buf);
+			struct commit_graph *g = load_commit_graph_one(r, graph_name, odb);
+
+			free(graph_name);
+
+			if (g) {
+				if (add_graph_to_chain(g, graph_chain, oids, i)) {
+					graph_chain = g;
+					valid = 1;
+				} else {
+					free_commit_graph(g);
+				}
+
+				break;
+			}
+		}
+
+		if (!valid) {
+			warning(_("unable to find all commit-graph files"));
+			break;
+		}
+	}
+
+	validate_mixed_generation_chain(graph_chain);
+	validate_mixed_bloom_settings(graph_chain);
+
+	free(oids);
+	fclose(fp);
+	strbuf_release(&line);
+
+	*incomplete_chain = !valid;
+	return graph_chain;
+}
+
+static struct commit_graph *load_commit_graph_chain(struct repository *r,
+						    struct object_directory *odb)
+{
+	char *chain_file = get_commit_graph_chain_filename(odb);
+	struct stat st;
+	int fd;
+	struct commit_graph *g = NULL;
+
+	if (open_commit_graph_chain(chain_file, &fd, &st)) {
+		int incomplete;
+		/* ownership of fd is taken over by load function */
+		g = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);
+	}
+
+	free(chain_file);
+	return g;
+}
+
+struct commit_graph *read_commit_graph_one(struct repository *r,
+					   struct object_directory *odb)
+{
+	struct commit_graph *g = load_commit_graph_v1(r, odb);
+
+	if (!g)
+		g = load_commit_graph_chain(r, odb);
+
+	return g;
+}
+
+static void prepare_commit_graph_one(struct repository *r,
+				     struct object_directory *odb)
+{
+
+	if (r->objects->commit_graph)
+		return;
+
+	r->objects->commit_graph = read_commit_graph_one(r, odb);
+}
+
+/*
+ * Return 1 if commit_graph is non-NULL, and 0 otherwise.
+ *
+ * On the first invocation, this function attempts to load the commit
+ * graph if the_repository is configured to have one.
+ */
+static int prepare_commit_graph(struct repository *r)
+{
+	struct object_directory *odb;
+
+	/*
+	 * Early return if there is no git dir or if the commit graph is
+	 * disabled.
+	 *
+	 * This must come before the "already attempted?" check below, because
+	 * we want to disable even an already-loaded graph file.
+	 */
+	if (!r->gitdir || r->commit_graph_disabled)
+		return 0;
+
+	if (r->objects->commit_graph_attempted)
+		return !!r->objects->commit_graph;
+	r->objects->commit_graph_attempted = 1;
+
+	prepare_repo_settings(r);
+
+	if (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
+	    r->settings.core_commit_graph != 1)
+		/*
+		 * This repository is not configured to use commit graphs, so
+		 * do not load one. (But report commit_graph_attempted anyway
+		 * so that commit graph loading is not attempted again for this
+		 * repository.)
+		 */
+		return 0;
+
+	if (!commit_graph_compatible(r))
+		return 0;
+
+	prepare_alt_odb(r);
+	for (odb = r->objects->odb;
+	     !r->objects->commit_graph && odb;
+	     odb = odb->next)
+		prepare_commit_graph_one(r, odb);
+	return !!r->objects->commit_graph;
+}
+
+int generation_numbers_enabled(struct repository *r)
+{
+	uint32_t first_generation;
+	struct commit_graph *g;
+	if (!prepare_commit_graph(r))
+	       return 0;
+
+	g = r->objects->commit_graph;
+
+	if (!g->num_commits)
+		return 0;
+
+	first_generation = get_be32(g->chunk_commit_data +
+				    g->hash_len + 8) >> 2;
+
+	return !!first_generation;
+}
+
+int corrected_commit_dates_enabled(struct repository *r)
+{
+	struct commit_graph *g;
+	if (!prepare_commit_graph(r))
+		return 0;
+
+	g = r->objects->commit_graph;
+
+	if (!g->num_commits)
+		return 0;
+
+	return g->read_generation_data;
+}
+
+struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r)
+{
+	struct commit_graph *g = r->objects->commit_graph;
+	while (g) {
+		if (g->bloom_filter_settings)
+			return g->bloom_filter_settings;
+		g = g->base_graph;
+	}
+	return NULL;
+}
+
+void close_commit_graph(struct raw_object_store *o)
+{
+	if (!o->commit_graph)
+		return;
+
+	clear_commit_graph_data_slab(&commit_graph_data_slab);
+	deinit_bloom_filters();
+	free_commit_graph(o->commit_graph);
+	o->commit_graph = NULL;
+}
+
+static int bsearch_graph(struct commit_graph *g, const struct object_id *oid, uint32_t *pos)
+{
+	return bsearch_hash(oid->hash, g->chunk_oid_fanout,
+			    g->chunk_oid_lookup, g->hash_len, pos);
+}
+
+static void load_oid_from_graph(struct commit_graph *g,
+				uint32_t pos,
+				struct object_id *oid)
+{
+	uint32_t lex_index;
+
+	while (g && pos < g->num_commits_in_base)
+		g = g->base_graph;
+
+	if (!g)
+		BUG("NULL commit-graph");
+
+	if (pos >= g->num_commits + g->num_commits_in_base)
+		die(_("invalid commit position. commit-graph is likely corrupt"));
+
+	lex_index = pos - g->num_commits_in_base;
+
+	oidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index),
+		the_repository->hash_algo);
+}
+
+static struct commit_list **insert_parent_or_die(struct repository *r,
+						 struct commit_graph *g,
+						 uint32_t pos,
+						 struct commit_list **pptr)
+{
+	struct commit *c;
+	struct object_id oid;
+
+	if (pos >= g->num_commits + g->num_commits_in_base)
+		die("invalid parent position %"PRIu32, pos);
+
+	load_oid_from_graph(g, pos, &oid);
+	c = lookup_commit(r, &oid);
+	if (!c)
+		die(_("could not find commit %s"), oid_to_hex(&oid));
+	commit_graph_data_at(c)->graph_pos = pos;
+	return &commit_list_insert(c, pptr)->next;
+}
+
+static void fill_commit_graph_info(struct commit *item, struct commit_graph *g, uint32_t pos)
+{
+	const unsigned char *commit_data;
+	struct commit_graph_data *graph_data;
+	uint32_t lex_index, offset_pos;
+	uint64_t date_high, date_low, offset;
+
+	while (pos < g->num_commits_in_base)
+		g = g->base_graph;
+
+	if (pos >= g->num_commits + g->num_commits_in_base)
+		die(_("invalid commit position. commit-graph is likely corrupt"));
+
+	lex_index = pos - g->num_commits_in_base;
+	commit_data = g->chunk_commit_data + st_mult(GRAPH_DATA_WIDTH, lex_index);
+
+	graph_data = commit_graph_data_at(item);
+	graph_data->graph_pos = pos;
+
+	date_high = get_be32(commit_data + g->hash_len + 8) & 0x3;
+	date_low = get_be32(commit_data + g->hash_len + 12);
+	item->date = (timestamp_t)((date_high << 32) | date_low);
+
+	if (g->read_generation_data) {
+		offset = (timestamp_t)get_be32(g->chunk_generation_data + st_mult(sizeof(uint32_t), lex_index));
+
+		if (offset & CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW) {
+			if (!g->chunk_generation_data_overflow)
+				die(_("commit-graph requires overflow generation data but has none"));
+
+			offset_pos = offset ^ CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW;
+			if (g->chunk_generation_data_overflow_size / sizeof(uint64_t) <= offset_pos)
+				die(_("commit-graph overflow generation data is too small"));
+			graph_data->generation = item->date +
+				get_be64(g->chunk_generation_data_overflow + sizeof(uint64_t) * offset_pos);
+		} else
+			graph_data->generation = item->date + offset;
+	} else
+		graph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;
+
+	if (g->topo_levels)
+		*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_len + 8) >> 2;
+}
+
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+	c->maybe_tree = t;
+}
+
+static int fill_commit_in_graph(struct repository *r,
+				struct commit *item,
+				struct commit_graph *g, uint32_t pos)
+{
+	uint32_t edge_value;
+	uint32_t parent_data_pos;
+	struct commit_list **pptr;
+	const unsigned char *commit_data;
+	uint32_t lex_index;
+
+	while (pos < g->num_commits_in_base)
+		g = g->base_graph;
+
+	fill_commit_graph_info(item, g, pos);
+
+	lex_index = pos - g->num_commits_in_base;
+	commit_data = g->chunk_commit_data + st_mult(g->hash_len + 16, lex_index);
+
+	item->object.parsed = 1;
+
+	set_commit_tree(item, NULL);
+
+	pptr = &item->parents;
+
+	edge_value = get_be32(commit_data + g->hash_len);
+	if (edge_value == GRAPH_PARENT_NONE)
+		return 1;
+	pptr = insert_parent_or_die(r, g, edge_value, pptr);
+
+	edge_value = get_be32(commit_data + g->hash_len + 4);
+	if (edge_value == GRAPH_PARENT_NONE)
+		return 1;
+	if (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {
+		pptr = insert_parent_or_die(r, g, edge_value, pptr);
+		return 1;
+	}
+
+	parent_data_pos = edge_value & GRAPH_EDGE_LAST_MASK;
+	do {
+		if (g->chunk_extra_edges_size / sizeof(uint32_t) <= parent_data_pos) {
+			error(_("commit-graph extra-edges pointer out of bounds"));
+			free_commit_list(item->parents);
+			item->parents = NULL;
+			item->object.parsed = 0;
+			return 0;
+		}
+		edge_value = get_be32(g->chunk_extra_edges +
+				      sizeof(uint32_t) * parent_data_pos);
+		pptr = insert_parent_or_die(r, g,
+					    edge_value & GRAPH_EDGE_LAST_MASK,
+					    pptr);
+		parent_data_pos++;
+	} while (!(edge_value & GRAPH_LAST_EDGE));
+
+	return 1;
+}
+
+static int search_commit_pos_in_graph(const struct object_id *id, struct commit_graph *g, uint32_t *pos)
+{
+	struct commit_graph *cur_g = g;
+	uint32_t lex_index;
+
+	while (cur_g && !bsearch_graph(cur_g, id, &lex_index))
+		cur_g = cur_g->base_graph;
+
+	if (cur_g) {
+		*pos = lex_index + cur_g->num_commits_in_base;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int find_commit_pos_in_graph(struct commit *item, struct commit_graph *g, uint32_t *pos)
+{
+	uint32_t graph_pos = commit_graph_position(item);
+	if (graph_pos != COMMIT_NOT_FROM_GRAPH) {
+		*pos = graph_pos;
+		return 1;
+	} else {
+		return search_commit_pos_in_graph(&item->object.oid, g, pos);
+	}
+}
+
+int repo_find_commit_pos_in_graph(struct repository *r, struct commit *c,
+				  uint32_t *pos)
+{
+	if (!prepare_commit_graph(r))
+		return 0;
+	return find_commit_pos_in_graph(c, r->objects->commit_graph, pos);
+}
+
+struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id)
+{
+	static int commit_graph_paranoia = -1;
+	struct commit *commit;
+	uint32_t pos;
+
+	if (commit_graph_paranoia == -1)
+		commit_graph_paranoia = git_env_bool(GIT_COMMIT_GRAPH_PARANOIA, 0);
+
+	if (!prepare_commit_graph(repo))
+		return NULL;
+	if (!search_commit_pos_in_graph(id, repo->objects->commit_graph, &pos))
+		return NULL;
+	if (commit_graph_paranoia && !has_object(repo, id, 0))
+		return NULL;
+
+	commit = lookup_commit(repo, id);
+	if (!commit)
+		return NULL;
+	if (commit->object.parsed)
+		return commit;
+
+	if (!fill_commit_in_graph(repo, commit, repo->objects->commit_graph, pos))
+		return NULL;
+
+	return commit;
+}
+
+static int parse_commit_in_graph_one(struct repository *r,
+				     struct commit_graph *g,
+				     struct commit *item)
+{
+	uint32_t pos;
+
+	if (item->object.parsed)
+		return 1;
+
+	if (find_commit_pos_in_graph(item, g, &pos))
+		return fill_commit_in_graph(r, item, g, pos);
+
+	return 0;
+}
+
+int parse_commit_in_graph(struct repository *r, struct commit *item)
+{
+	static int checked_env = 0;
+
+	if (!checked_env &&
+	    git_env_bool(GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE, 0))
+		die("dying as requested by the '%s' variable on commit-graph parse!",
+		    GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE);
+	checked_env = 1;
+
+	if (!prepare_commit_graph(r))
+		return 0;
+	return parse_commit_in_graph_one(r, r->objects->commit_graph, item);
+}
+
+void load_commit_graph_info(struct repository *r, struct commit *item)
+{
+	uint32_t pos;
+	if (repo_find_commit_pos_in_graph(r, item, &pos))
+		fill_commit_graph_info(item, r->objects->commit_graph, pos);
+}
+
+static struct tree *load_tree_for_commit(struct repository *r,
+					 struct commit_graph *g,
+					 struct commit *c)
+{
+	struct object_id oid;
+	const unsigned char *commit_data;
+	uint32_t graph_pos = commit_graph_position(c);
+
+	while (graph_pos < g->num_commits_in_base)
+		g = g->base_graph;
+
+	commit_data = g->chunk_commit_data +
+			st_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base);
+
+	oidread(&oid, commit_data, the_repository->hash_algo);
+	set_commit_tree(c, lookup_tree(r, &oid));
+
+	return c->maybe_tree;
+}
+
+static struct tree *get_commit_tree_in_graph_one(struct repository *r,
+						 struct commit_graph *g,
+						 const struct commit *c)
+{
+	if (c->maybe_tree)
+		return c->maybe_tree;
+	if (commit_graph_position(c) == COMMIT_NOT_FROM_GRAPH)
+		BUG("get_commit_tree_in_graph_one called from non-commit-graph commit");
+
+	return load_tree_for_commit(r, g, (struct commit *)c);
+}
+
+struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)
+{
+	return get_commit_tree_in_graph_one(r, r->objects->commit_graph, c);
+}
+
+struct packed_commit_list {
+	struct commit **list;
+	size_t nr;
+	size_t alloc;
+};
+
+struct write_commit_graph_context {
+	struct repository *r;
+	struct object_directory *odb;
+	char *graph_name;
+	struct oid_array oids;
+	struct packed_commit_list commits;
+	int num_extra_edges;
+	int num_generation_data_overflows;
+	unsigned long approx_nr_objects;
+	struct progress *progress;
+	int progress_done;
+	uint64_t progress_cnt;
+
+	char *base_graph_name;
+	int num_commit_graphs_before;
+	int num_commit_graphs_after;
+	char **commit_graph_filenames_before;
+	char **commit_graph_filenames_after;
+	char **commit_graph_hash_after;
+	uint32_t new_num_commits_in_base;
+	struct commit_graph *new_base_graph;
+
+	unsigned append:1,
+		 report_progress:1,
+		 split:1,
+		 changed_paths:1,
+		 order_by_pack:1,
+		 write_generation_data:1,
+		 trust_generation_numbers:1;
+
+	struct topo_level_slab *topo_levels;
+	const struct commit_graph_opts *opts;
+	size_t total_bloom_filter_data_size;
+	const struct bloom_filter_settings *bloom_settings;
+
+	int count_bloom_filter_computed;
+	int count_bloom_filter_not_computed;
+	int count_bloom_filter_trunc_empty;
+	int count_bloom_filter_trunc_large;
+	int count_bloom_filter_upgraded;
+};
+
+static int write_graph_chunk_fanout(struct hashfile *f,
+				    void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	int i, count = 0;
+	struct commit **list = ctx->commits.list;
+
+	/*
+	 * Write the first-level table (the list is sorted,
+	 * but we use a 256-entry lookup to be able to avoid
+	 * having to do eight extra binary search iterations).
+	 */
+	for (i = 0; i < 256; i++) {
+		while (count < ctx->commits.nr) {
+			if ((*list)->object.oid.hash[0] != i)
+				break;
+			display_progress(ctx->progress, ++ctx->progress_cnt);
+			count++;
+			list++;
+		}
+
+		hashwrite_be32(f, count);
+	}
+
+	return 0;
+}
+
+static int write_graph_chunk_oids(struct hashfile *f,
+				  void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	struct commit **list = ctx->commits.list;
+	int count;
+	for (count = 0; count < ctx->commits.nr; count++, list++) {
+		display_progress(ctx->progress, ++ctx->progress_cnt);
+		hashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);
+	}
+
+	return 0;
+}
+
+static const struct object_id *commit_to_oid(size_t index, const void *table)
+{
+	const struct commit * const *commits = table;
+	return &commits[index]->object.oid;
+}
+
+static int write_graph_chunk_data(struct hashfile *f,
+				  void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	struct commit **list = ctx->commits.list;
+	struct commit **last = ctx->commits.list + ctx->commits.nr;
+	uint32_t num_extra_edges = 0;
+
+	while (list < last) {
+		struct commit_list *parent;
+		struct object_id *tree;
+		int edge_value;
+		uint32_t packedDate[2];
+		display_progress(ctx->progress, ++ctx->progress_cnt);
+
+		if (repo_parse_commit_no_graph(ctx->r, *list))
+			die(_("unable to parse commit %s"),
+				oid_to_hex(&(*list)->object.oid));
+		tree = get_commit_tree_oid(*list);
+		hashwrite(f, tree->hash, the_hash_algo->rawsz);
+
+		parent = (*list)->parents;
+
+		if (!parent)
+			edge_value = GRAPH_PARENT_NONE;
+		else {
+			edge_value = oid_pos(&parent->item->object.oid,
+					     ctx->commits.list,
+					     ctx->commits.nr,
+					     commit_to_oid);
+
+			if (edge_value >= 0)
+				edge_value += ctx->new_num_commits_in_base;
+			else if (ctx->new_base_graph) {
+				uint32_t pos;
+				if (find_commit_pos_in_graph(parent->item,
+							     ctx->new_base_graph,
+							     &pos))
+					edge_value = pos;
+			}
+
+			if (edge_value < 0)
+				BUG("missing parent %s for commit %s",
+				    oid_to_hex(&parent->item->object.oid),
+				    oid_to_hex(&(*list)->object.oid));
+		}
+
+		hashwrite_be32(f, edge_value);
+
+		if (parent)
+			parent = parent->next;
+
+		if (!parent)
+			edge_value = GRAPH_PARENT_NONE;
+		else if (parent->next)
+			edge_value = GRAPH_EXTRA_EDGES_NEEDED | num_extra_edges;
+		else {
+			edge_value = oid_pos(&parent->item->object.oid,
+					     ctx->commits.list,
+					     ctx->commits.nr,
+					     commit_to_oid);
+
+			if (edge_value >= 0)
+				edge_value += ctx->new_num_commits_in_base;
+			else if (ctx->new_base_graph) {
+				uint32_t pos;
+				if (find_commit_pos_in_graph(parent->item,
+							     ctx->new_base_graph,
+							     &pos))
+					edge_value = pos;
+			}
+
+			if (edge_value < 0)
+				BUG("missing parent %s for commit %s",
+				    oid_to_hex(&parent->item->object.oid),
+				    oid_to_hex(&(*list)->object.oid));
+		}
+
+		hashwrite_be32(f, edge_value);
+
+		if (edge_value & GRAPH_EXTRA_EDGES_NEEDED) {
+			do {
+				num_extra_edges++;
+				parent = parent->next;
+			} while (parent);
+		}
+
+		if (sizeof((*list)->date) > 4)
+			packedDate[0] = htonl(((*list)->date >> 32) & 0x3);
+		else
+			packedDate[0] = 0;
+
+		packedDate[0] |= htonl(*topo_level_slab_at(ctx->topo_levels, *list) << 2);
+
+		packedDate[1] = htonl((*list)->date);
+		hashwrite(f, packedDate, 8);
+
+		list++;
+	}
+
+	return 0;
+}
+
+static int write_graph_chunk_generation_data(struct hashfile *f,
+					     void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	int i, num_generation_data_overflows = 0;
+
+	for (i = 0; i < ctx->commits.nr; i++) {
+		struct commit *c = ctx->commits.list[i];
+		timestamp_t offset;
+		repo_parse_commit(ctx->r, c);
+		offset = commit_graph_data_at(c)->generation - c->date;
+		display_progress(ctx->progress, ++ctx->progress_cnt);
+
+		if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) {
+			offset = CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW | num_generation_data_overflows;
+			num_generation_data_overflows++;
+		}
+
+		hashwrite_be32(f, offset);
+	}
+
+	return 0;
+}
+
+static int write_graph_chunk_generation_data_overflow(struct hashfile *f,
+						      void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	int i;
+	for (i = 0; i < ctx->commits.nr; i++) {
+		struct commit *c = ctx->commits.list[i];
+		timestamp_t offset = commit_graph_data_at(c)->generation - c->date;
+		display_progress(ctx->progress, ++ctx->progress_cnt);
+
+		if (offset > GENERATION_NUMBER_V2_OFFSET_MAX) {
+			hashwrite_be32(f, offset >> 32);
+			hashwrite_be32(f, (uint32_t) offset);
+		}
+	}
+
+	return 0;
+}
+
+static int write_graph_chunk_extra_edges(struct hashfile *f,
+					 void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	struct commit **list = ctx->commits.list;
+	struct commit **last = ctx->commits.list + ctx->commits.nr;
+	struct commit_list *parent;
+
+	while (list < last) {
+		int num_parents = 0;
+
+		display_progress(ctx->progress, ++ctx->progress_cnt);
+
+		for (parent = (*list)->parents; num_parents < 3 && parent;
+		     parent = parent->next)
+			num_parents++;
+
+		if (num_parents <= 2) {
+			list++;
+			continue;
+		}
+
+		/* Since num_parents > 2, this initializer is safe. */
+		for (parent = (*list)->parents->next; parent; parent = parent->next) {
+			int edge_value = oid_pos(&parent->item->object.oid,
+						 ctx->commits.list,
+						 ctx->commits.nr,
+						 commit_to_oid);
+
+			if (edge_value >= 0)
+				edge_value += ctx->new_num_commits_in_base;
+			else if (ctx->new_base_graph) {
+				uint32_t pos;
+				if (find_commit_pos_in_graph(parent->item,
+							     ctx->new_base_graph,
+							     &pos))
+					edge_value = pos;
+			}
+
+			if (edge_value < 0)
+				BUG("missing parent %s for commit %s",
+				    oid_to_hex(&parent->item->object.oid),
+				    oid_to_hex(&(*list)->object.oid));
+			else if (!parent->next)
+				edge_value |= GRAPH_LAST_EDGE;
+
+			hashwrite_be32(f, edge_value);
+		}
+
+		list++;
+	}
+
+	return 0;
+}
+
+static int write_graph_chunk_bloom_indexes(struct hashfile *f,
+					   void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	struct commit **list = ctx->commits.list;
+	struct commit **last = ctx->commits.list + ctx->commits.nr;
+	uint32_t cur_pos = 0;
+
+	while (list < last) {
+		struct bloom_filter *filter = get_bloom_filter(ctx->r, *list);
+		size_t len = filter ? filter->len : 0;
+		cur_pos += len;
+		display_progress(ctx->progress, ++ctx->progress_cnt);
+		hashwrite_be32(f, cur_pos);
+		list++;
+	}
+
+	return 0;
+}
+
+static void trace2_bloom_filter_settings(struct write_commit_graph_context *ctx)
+{
+	struct json_writer jw = JSON_WRITER_INIT;
+
+	jw_object_begin(&jw, 0);
+	jw_object_intmax(&jw, "hash_version", ctx->bloom_settings->hash_version);
+	jw_object_intmax(&jw, "num_hashes", ctx->bloom_settings->num_hashes);
+	jw_object_intmax(&jw, "bits_per_entry", ctx->bloom_settings->bits_per_entry);
+	jw_object_intmax(&jw, "max_changed_paths", ctx->bloom_settings->max_changed_paths);
+	jw_end(&jw);
+
+	trace2_data_json("bloom", ctx->r, "settings", &jw);
+
+	jw_release(&jw);
+}
+
+static int write_graph_chunk_bloom_data(struct hashfile *f,
+					void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	struct commit **list = ctx->commits.list;
+	struct commit **last = ctx->commits.list + ctx->commits.nr;
+
+	trace2_bloom_filter_settings(ctx);
+
+	hashwrite_be32(f, ctx->bloom_settings->hash_version);
+	hashwrite_be32(f, ctx->bloom_settings->num_hashes);
+	hashwrite_be32(f, ctx->bloom_settings->bits_per_entry);
+
+	while (list < last) {
+		struct bloom_filter *filter = get_bloom_filter(ctx->r, *list);
+		size_t len = filter ? filter->len : 0;
+
+		display_progress(ctx->progress, ++ctx->progress_cnt);
+		if (len)
+			hashwrite(f, filter->data, len * sizeof(unsigned char));
+		list++;
+	}
+
+	return 0;
+}
+
+static int add_packed_commits(const struct object_id *oid,
+			      struct packed_git *pack,
+			      uint32_t pos,
+			      void *data)
+{
+	struct write_commit_graph_context *ctx = (struct write_commit_graph_context*)data;
+	enum object_type type;
+	off_t offset = nth_packed_object_offset(pack, pos);
+	struct object_info oi = OBJECT_INFO_INIT;
+
+	if (ctx->progress)
+		display_progress(ctx->progress, ++ctx->progress_done);
+
+	oi.typep = &type;
+	if (packed_object_info(ctx->r, pack, offset, &oi) < 0)
+		die(_("unable to get type of object %s"), oid_to_hex(oid));
+
+	if (type != OBJ_COMMIT)
+		return 0;
+
+	oid_array_append(&ctx->oids, oid);
+	set_commit_pos(ctx->r, oid);
+
+	return 0;
+}
+
+static void add_missing_parents(struct write_commit_graph_context *ctx, struct commit *commit)
+{
+	struct commit_list *parent;
+	for (parent = commit->parents; parent; parent = parent->next) {
+		if (!(parent->item->object.flags & REACHABLE)) {
+			oid_array_append(&ctx->oids, &parent->item->object.oid);
+			parent->item->object.flags |= REACHABLE;
+		}
+	}
+}
+
+static void close_reachable(struct write_commit_graph_context *ctx)
+{
+	int i;
+	struct commit *commit;
+	enum commit_graph_split_flags flags = ctx->opts ?
+		ctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
+
+	if (ctx->report_progress)
+		ctx->progress = start_delayed_progress(
+					the_repository,
+					_("Loading known commits in commit graph"),
+					ctx->oids.nr);
+	for (i = 0; i < ctx->oids.nr; i++) {
+		display_progress(ctx->progress, i + 1);
+		commit = lookup_commit(ctx->r, &ctx->oids.oid[i]);
+		if (commit)
+			commit->object.flags |= REACHABLE;
+	}
+	stop_progress(&ctx->progress);
+
+	/*
+	 * As this loop runs, ctx->oids.nr may grow, but not more
+	 * than the number of missing commits in the reachable
+	 * closure.
+	 */
+	if (ctx->report_progress)
+		ctx->progress = start_delayed_progress(
+					the_repository,
+					_("Expanding reachable commits in commit graph"),
+					0);
+	for (i = 0; i < ctx->oids.nr; i++) {
+		display_progress(ctx->progress, i + 1);
+		commit = lookup_commit(ctx->r, &ctx->oids.oid[i]);
+
+		if (!commit)
+			continue;
+		if (ctx->split) {
+			if ((!repo_parse_commit(ctx->r, commit) &&
+			     commit_graph_position(commit) == COMMIT_NOT_FROM_GRAPH) ||
+			    flags == COMMIT_GRAPH_SPLIT_REPLACE)
+				add_missing_parents(ctx, commit);
+		} else if (!repo_parse_commit_no_graph(ctx->r, commit))
+			add_missing_parents(ctx, commit);
+	}
+	stop_progress(&ctx->progress);
+
+	if (ctx->report_progress)
+		ctx->progress = start_delayed_progress(
+					the_repository,
+					_("Clearing commit marks in commit graph"),
+					ctx->oids.nr);
+	for (i = 0; i < ctx->oids.nr; i++) {
+		display_progress(ctx->progress, i + 1);
+		commit = lookup_commit(ctx->r, &ctx->oids.oid[i]);
+
+		if (commit)
+			commit->object.flags &= ~REACHABLE;
+	}
+	stop_progress(&ctx->progress);
+}
+
+struct compute_generation_info {
+	struct repository *r;
+	struct packed_commit_list *commits;
+	struct progress *progress;
+	int progress_cnt;
+
+	timestamp_t (*get_generation)(struct commit *c, void *data);
+	void (*set_generation)(struct commit *c, timestamp_t gen, void *data);
+	void *data;
+};
+
+static timestamp_t compute_generation_from_max(struct commit *c,
+					       timestamp_t max_gen,
+					       int generation_version)
+{
+	switch (generation_version) {
+	case 1: /* topological levels */
+		if (max_gen > GENERATION_NUMBER_V1_MAX - 1)
+			max_gen = GENERATION_NUMBER_V1_MAX - 1;
+		return max_gen + 1;
+
+	case 2: /* corrected commit date */
+		if (c->date && c->date > max_gen)
+			max_gen = c->date - 1;
+		return max_gen + 1;
+
+	default:
+		BUG("attempting unimplemented version");
+	}
+}
+
+static void compute_reachable_generation_numbers(
+			struct compute_generation_info *info,
+			int generation_version)
+{
+	int i;
+	struct commit_list *list = NULL;
+
+	for (i = 0; i < info->commits->nr; i++) {
+		struct commit *c = info->commits->list[i];
+		timestamp_t gen;
+		repo_parse_commit(info->r, c);
+		gen = info->get_generation(c, info->data);
+		display_progress(info->progress, ++info->progress_cnt);
+
+		if (gen != GENERATION_NUMBER_ZERO && gen != GENERATION_NUMBER_INFINITY)
+			continue;
+
+		commit_list_insert(c, &list);
+		while (list) {
+			struct commit *current = list->item;
+			struct commit_list *parent;
+			int all_parents_computed = 1;
+			uint32_t max_gen = 0;
+
+			for (parent = current->parents; parent; parent = parent->next) {
+				repo_parse_commit(info->r, parent->item);
+				gen = info->get_generation(parent->item, info->data);
+
+				if (gen == GENERATION_NUMBER_ZERO) {
+					all_parents_computed = 0;
+					commit_list_insert(parent->item, &list);
+					break;
+				}
+
+				if (gen > max_gen)
+					max_gen = gen;
+			}
+
+			if (all_parents_computed) {
+				pop_commit(&list);
+				gen = compute_generation_from_max(
+						current, max_gen,
+						generation_version);
+				info->set_generation(current, gen, info->data);
+			}
+		}
+	}
+}
+
+static timestamp_t get_topo_level(struct commit *c, void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	return *topo_level_slab_at(ctx->topo_levels, c);
+}
+
+static void set_topo_level(struct commit *c, timestamp_t t, void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	*topo_level_slab_at(ctx->topo_levels, c) = (uint32_t)t;
+}
+
+static void compute_topological_levels(struct write_commit_graph_context *ctx)
+{
+	struct compute_generation_info info = {
+		.r = ctx->r,
+		.commits = &ctx->commits,
+		.get_generation = get_topo_level,
+		.set_generation = set_topo_level,
+		.data = ctx,
+	};
+
+	if (ctx->report_progress)
+		info.progress = ctx->progress
+			      = start_delayed_progress(
+					the_repository,
+					_("Computing commit graph topological levels"),
+					ctx->commits.nr);
+
+	compute_reachable_generation_numbers(&info, 1);
+
+	stop_progress(&ctx->progress);
+}
+
+static timestamp_t get_generation_from_graph_data(struct commit *c,
+						  void *data UNUSED)
+{
+	return commit_graph_data_at(c)->generation;
+}
+
+static void set_generation_v2(struct commit *c, timestamp_t t,
+			      void *data UNUSED)
+{
+	struct commit_graph_data *g = commit_graph_data_at(c);
+	g->generation = t;
+}
+
+static void compute_generation_numbers(struct write_commit_graph_context *ctx)
+{
+	int i;
+	struct compute_generation_info info = {
+		.r = ctx->r,
+		.commits = &ctx->commits,
+		.get_generation = get_generation_from_graph_data,
+		.set_generation = set_generation_v2,
+	};
+
+	if (ctx->report_progress)
+		info.progress = ctx->progress
+			      = start_delayed_progress(
+					the_repository,
+					_("Computing commit graph generation numbers"),
+					ctx->commits.nr);
+
+	if (!ctx->trust_generation_numbers) {
+		for (i = 0; i < ctx->commits.nr; i++) {
+			struct commit *c = ctx->commits.list[i];
+			repo_parse_commit(ctx->r, c);
+			commit_graph_data_at(c)->generation = GENERATION_NUMBER_ZERO;
+		}
+	}
+
+	compute_reachable_generation_numbers(&info, 2);
+
+	for (i = 0; i < ctx->commits.nr; i++) {
+		struct commit *c = ctx->commits.list[i];
+		timestamp_t offset = commit_graph_data_at(c)->generation - c->date;
+		if (offset > GENERATION_NUMBER_V2_OFFSET_MAX)
+			ctx->num_generation_data_overflows++;
+	}
+	stop_progress(&ctx->progress);
+}
+
+static void set_generation_in_graph_data(struct commit *c, timestamp_t t,
+					 void *data UNUSED)
+{
+	commit_graph_data_at(c)->generation = t;
+}
+
+/*
+ * After this method, all commits reachable from those in the given
+ * list will have non-zero, non-infinite generation numbers.
+ */
+void ensure_generations_valid(struct repository *r,
+			      struct commit **commits, size_t nr)
+{
+	int generation_version = get_configured_generation_version(r);
+	struct packed_commit_list list = {
+		.list = commits,
+		.alloc = nr,
+		.nr = nr,
+	};
+	struct compute_generation_info info = {
+		.r = r,
+		.commits = &list,
+		.get_generation = get_generation_from_graph_data,
+		.set_generation = set_generation_in_graph_data,
+	};
+
+	compute_reachable_generation_numbers(&info, generation_version);
+}
+
+static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)
+{
+	trace2_data_intmax("commit-graph", ctx->r, "filter-computed",
+			   ctx->count_bloom_filter_computed);
+	trace2_data_intmax("commit-graph", ctx->r, "filter-not-computed",
+			   ctx->count_bloom_filter_not_computed);
+	trace2_data_intmax("commit-graph", ctx->r, "filter-trunc-empty",
+			   ctx->count_bloom_filter_trunc_empty);
+	trace2_data_intmax("commit-graph", ctx->r, "filter-trunc-large",
+			   ctx->count_bloom_filter_trunc_large);
+	trace2_data_intmax("commit-graph", ctx->r, "filter-upgraded",
+			   ctx->count_bloom_filter_upgraded);
+}
+
+static void compute_bloom_filters(struct write_commit_graph_context *ctx)
+{
+	int i;
+	struct progress *progress = NULL;
+	struct commit **sorted_commits;
+	int max_new_filters;
+
+	init_bloom_filters();
+
+	if (ctx->report_progress)
+		progress = start_delayed_progress(
+			the_repository,
+			_("Computing commit changed paths Bloom filters"),
+			ctx->commits.nr);
+
+	DUP_ARRAY(sorted_commits, ctx->commits.list, ctx->commits.nr);
+
+	if (ctx->order_by_pack)
+		QSORT(sorted_commits, ctx->commits.nr, commit_pos_cmp);
+	else
+		QSORT(sorted_commits, ctx->commits.nr, commit_gen_cmp);
+
+	max_new_filters = ctx->opts && ctx->opts->max_new_filters >= 0 ?
+		ctx->opts->max_new_filters : ctx->commits.nr;
+
+	for (i = 0; i < ctx->commits.nr; i++) {
+		enum bloom_filter_computed computed = 0;
+		struct commit *c = sorted_commits[i];
+		struct bloom_filter *filter = get_or_compute_bloom_filter(
+			ctx->r,
+			c,
+			ctx->count_bloom_filter_computed < max_new_filters,
+			ctx->bloom_settings,
+			&computed);
+		if (computed & BLOOM_COMPUTED) {
+			ctx->count_bloom_filter_computed++;
+			if (computed & BLOOM_TRUNC_EMPTY)
+				ctx->count_bloom_filter_trunc_empty++;
+			if (computed & BLOOM_TRUNC_LARGE)
+				ctx->count_bloom_filter_trunc_large++;
+		} else if (computed & BLOOM_UPGRADED) {
+			ctx->count_bloom_filter_upgraded++;
+		} else if (computed & BLOOM_NOT_COMPUTED)
+			ctx->count_bloom_filter_not_computed++;
+		ctx->total_bloom_filter_data_size += filter
+			? sizeof(unsigned char) * filter->len : 0;
+		display_progress(progress, i + 1);
+	}
+
+	if (trace2_is_enabled())
+		trace2_bloom_filter_write_statistics(ctx);
+
+	free(sorted_commits);
+	stop_progress(&progress);
+}
+
+struct refs_cb_data {
+	struct oidset *commits;
+	struct progress *progress;
+};
+
+static int add_ref_to_set(const char *refname UNUSED,
+			  const char *referent UNUSED,
+			  const struct object_id *oid,
+			  int flags UNUSED, void *cb_data)
+{
+	struct object_id peeled;
+	struct refs_cb_data *data = (struct refs_cb_data *)cb_data;
+
+	if (!peel_iterated_oid(the_repository, oid, &peeled))
+		oid = &peeled;
+	if (oid_object_info(the_repository, oid, NULL) == OBJ_COMMIT)
+		oidset_insert(data->commits, oid);
+
+	display_progress(data->progress, oidset_size(data->commits));
+
+	return 0;
+}
+
+int write_commit_graph_reachable(struct object_directory *odb,
+				 enum commit_graph_write_flags flags,
+				 const struct commit_graph_opts *opts)
+{
+	struct oidset commits = OIDSET_INIT;
+	struct refs_cb_data data;
+	int result;
+
+	memset(&data, 0, sizeof(data));
+	data.commits = &commits;
+	if (flags & COMMIT_GRAPH_WRITE_PROGRESS)
+		data.progress = start_delayed_progress(
+			the_repository,
+			_("Collecting referenced commits"), 0);
+
+	refs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set,
+			  &data);
+
+	stop_progress(&data.progress);
+
+	result = write_commit_graph(odb, NULL, &commits,
+				    flags, opts);
+
+	oidset_clear(&commits);
+	return result;
+}
+
+static int fill_oids_from_packs(struct write_commit_graph_context *ctx,
+				const struct string_list *pack_indexes)
+{
+	uint32_t i;
+	struct strbuf progress_title = STRBUF_INIT;
+	struct strbuf packname = STRBUF_INIT;
+	int dirlen;
+	int ret = 0;
+
+	strbuf_addf(&packname, "%s/pack/", ctx->odb->path);
+	dirlen = packname.len;
+	if (ctx->report_progress) {
+		strbuf_addf(&progress_title,
+			    Q_("Finding commits for commit graph in %"PRIuMAX" pack",
+			       "Finding commits for commit graph in %"PRIuMAX" packs",
+			       pack_indexes->nr),
+			    (uintmax_t)pack_indexes->nr);
+		ctx->progress = start_delayed_progress(the_repository,
+						       progress_title.buf, 0);
+		ctx->progress_done = 0;
+	}
+	for (i = 0; i < pack_indexes->nr; i++) {
+		struct packed_git *p;
+		strbuf_setlen(&packname, dirlen);
+		strbuf_addstr(&packname, pack_indexes->items[i].string);
+		p = add_packed_git(ctx->r, packname.buf, packname.len, 1);
+		if (!p) {
+			ret = error(_("error adding pack %s"), packname.buf);
+			goto cleanup;
+		}
+		if (open_pack_index(p)) {
+			ret = error(_("error opening index for %s"), packname.buf);
+			goto cleanup;
+		}
+		for_each_object_in_pack(p, add_packed_commits, ctx,
+					FOR_EACH_OBJECT_PACK_ORDER);
+		close_pack(p);
+		free(p);
+	}
+
+cleanup:
+	stop_progress(&ctx->progress);
+	strbuf_release(&progress_title);
+	strbuf_release(&packname);
+
+	return ret;
+}
+
+static int fill_oids_from_commits(struct write_commit_graph_context *ctx,
+				  struct oidset *commits)
+{
+	struct oidset_iter iter;
+	struct object_id *oid;
+
+	if (!oidset_size(commits))
+		return 0;
+
+	oidset_iter_init(commits, &iter);
+	while ((oid = oidset_iter_next(&iter))) {
+		oid_array_append(&ctx->oids, oid);
+	}
+
+	return 0;
+}
+
+static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
+{
+	if (ctx->report_progress)
+		ctx->progress = start_delayed_progress(
+			the_repository,
+			_("Finding commits for commit graph among packed objects"),
+			ctx->approx_nr_objects);
+	for_each_packed_object(ctx->r, add_packed_commits, ctx,
+			       FOR_EACH_OBJECT_PACK_ORDER);
+	if (ctx->progress_done < ctx->approx_nr_objects)
+		display_progress(ctx->progress, ctx->approx_nr_objects);
+	stop_progress(&ctx->progress);
+}
+
+static void copy_oids_to_commits(struct write_commit_graph_context *ctx)
+{
+	uint32_t i;
+	enum commit_graph_split_flags flags = ctx->opts ?
+		ctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;
+
+	ctx->num_extra_edges = 0;
+	if (ctx->report_progress)
+		ctx->progress = start_delayed_progress(
+			the_repository,
+			_("Finding extra edges in commit graph"),
+			ctx->oids.nr);
+	oid_array_sort(&ctx->oids);
+	for (i = 0; i < ctx->oids.nr; i = oid_array_next_unique(&ctx->oids, i)) {
+		unsigned int num_parents;
+
+		display_progress(ctx->progress, i + 1);
+
+		ALLOC_GROW(ctx->commits.list, ctx->commits.nr + 1, ctx->commits.alloc);
+		ctx->commits.list[ctx->commits.nr] = lookup_commit(ctx->r, &ctx->oids.oid[i]);
+
+		if (ctx->split && flags != COMMIT_GRAPH_SPLIT_REPLACE &&
+		    commit_graph_position(ctx->commits.list[ctx->commits.nr]) != COMMIT_NOT_FROM_GRAPH)
+			continue;
+
+		if (ctx->split && flags == COMMIT_GRAPH_SPLIT_REPLACE)
+			repo_parse_commit(ctx->r, ctx->commits.list[ctx->commits.nr]);
+		else
+			repo_parse_commit_no_graph(ctx->r, ctx->commits.list[ctx->commits.nr]);
+
+		num_parents = commit_list_count(ctx->commits.list[ctx->commits.nr]->parents);
+		if (num_parents > 2)
+			ctx->num_extra_edges += num_parents - 1;
+
+		ctx->commits.nr++;
+	}
+	stop_progress(&ctx->progress);
+}
+
+static int write_graph_chunk_base_1(struct hashfile *f,
+				    struct commit_graph *g)
+{
+	int num = 0;
+
+	if (!g)
+		return 0;
+
+	num = write_graph_chunk_base_1(f, g->base_graph);
+	hashwrite(f, g->oid.hash, the_hash_algo->rawsz);
+	return num + 1;
+}
+
+static int write_graph_chunk_base(struct hashfile *f,
+				    void *data)
+{
+	struct write_commit_graph_context *ctx = data;
+	int num = write_graph_chunk_base_1(f, ctx->new_base_graph);
+
+	if (num != ctx->num_commit_graphs_after - 1) {
+		error(_("failed to write correct number of base graph ids"));
+		return -1;
+	}
+
+	return 0;
+}
+
+static int write_commit_graph_file(struct write_commit_graph_context *ctx)
+{
+	uint32_t i;
+	struct hashfile *f;
+	struct tempfile *graph_layer; /* when ctx->split is non-zero */
+	struct lock_file lk = LOCK_INIT;
+	const unsigned hashsz = the_hash_algo->rawsz;
+	struct strbuf progress_title = STRBUF_INIT;
+	struct chunkfile *cf;
+	unsigned char file_hash[GIT_MAX_RAWSZ];
+
+	if (ctx->split) {
+		struct strbuf tmp_file = STRBUF_INIT;
+
+		strbuf_addf(&tmp_file,
+			    "%s/info/commit-graphs/tmp_graph_XXXXXX",
+			    ctx->odb->path);
+		ctx->graph_name = strbuf_detach(&tmp_file, NULL);
+	} else {
+		ctx->graph_name = get_commit_graph_filename(ctx->odb);
+	}
+
+	if (safe_create_leading_directories(ctx->graph_name)) {
+		error(_("unable to create leading directories of %s"),
+			ctx->graph_name);
+		return -1;
+	}
+
+	if (ctx->split) {
+		char *lock_name = get_commit_graph_chain_filename(ctx->odb);
+
+		hold_lock_file_for_update_mode(&lk, lock_name,
+					       LOCK_DIE_ON_ERROR, 0444);
+		free(lock_name);
+
+		graph_layer = mks_tempfile_m(ctx->graph_name, 0444);
+		if (!graph_layer) {
+			error(_("unable to create temporary graph layer"));
+			return -1;
+		}
+
+		if (adjust_shared_perm(get_tempfile_path(graph_layer))) {
+			error(_("unable to adjust shared permissions for '%s'"),
+			      get_tempfile_path(graph_layer));
+			return -1;
+		}
+
+		f = hashfd(get_tempfile_fd(graph_layer), get_tempfile_path(graph_layer));
+	} else {
+		hold_lock_file_for_update_mode(&lk, ctx->graph_name,
+					       LOCK_DIE_ON_ERROR, 0444);
+		f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
+	}
+
+	cf = init_chunkfile(f);
+
+	add_chunk(cf, GRAPH_CHUNKID_OIDFANOUT, GRAPH_FANOUT_SIZE,
+		  write_graph_chunk_fanout);
+	add_chunk(cf, GRAPH_CHUNKID_OIDLOOKUP, st_mult(hashsz, ctx->commits.nr),
+		  write_graph_chunk_oids);
+	add_chunk(cf, GRAPH_CHUNKID_DATA, st_mult(hashsz + 16, ctx->commits.nr),
+		  write_graph_chunk_data);
+
+	if (ctx->write_generation_data)
+		add_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,
+			  st_mult(sizeof(uint32_t), ctx->commits.nr),
+			  write_graph_chunk_generation_data);
+	if (ctx->num_generation_data_overflows)
+		add_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,
+			  st_mult(sizeof(timestamp_t), ctx->num_generation_data_overflows),
+			  write_graph_chunk_generation_data_overflow);
+	if (ctx->num_extra_edges)
+		add_chunk(cf, GRAPH_CHUNKID_EXTRAEDGES,
+			  st_mult(4, ctx->num_extra_edges),
+			  write_graph_chunk_extra_edges);
+	if (ctx->changed_paths) {
+		add_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,
+			  st_mult(sizeof(uint32_t), ctx->commits.nr),
+			  write_graph_chunk_bloom_indexes);
+		add_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,
+			  st_add(sizeof(uint32_t) * 3,
+				 ctx->total_bloom_filter_data_size),
+			  write_graph_chunk_bloom_data);
+	}
+	if (ctx->num_commit_graphs_after > 1)
+		add_chunk(cf, GRAPH_CHUNKID_BASE,
+			  st_mult(hashsz, ctx->num_commit_graphs_after - 1),
+			  write_graph_chunk_base);
+
+	hashwrite_be32(f, GRAPH_SIGNATURE);
+
+	hashwrite_u8(f, GRAPH_VERSION);
+	hashwrite_u8(f, oid_version(the_hash_algo));
+	hashwrite_u8(f, get_num_chunks(cf));
+	hashwrite_u8(f, ctx->num_commit_graphs_after - 1);
+
+	if (ctx->report_progress) {
+		strbuf_addf(&progress_title,
+			    Q_("Writing out commit graph in %d pass",
+			       "Writing out commit graph in %d passes",
+			       get_num_chunks(cf)),
+			    get_num_chunks(cf));
+		ctx->progress = start_delayed_progress(
+			the_repository,
+			progress_title.buf,
+			st_mult(get_num_chunks(cf), ctx->commits.nr));
+	}
+
+	write_chunkfile(cf, ctx);
+
+	stop_progress(&ctx->progress);
+	strbuf_release(&progress_title);
+
+	if (ctx->split && ctx->base_graph_name && ctx->num_commit_graphs_after > 1) {
+		char *new_base_hash = xstrdup(oid_to_hex(&ctx->new_base_graph->oid));
+		char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb, new_base_hash);
+
+		free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2]);
+		free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2]);
+		ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2] = new_base_name;
+		ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2] = new_base_hash;
+	}
+
+	close_commit_graph(ctx->r->objects);
+	finalize_hashfile(f, file_hash, FSYNC_COMPONENT_COMMIT_GRAPH,
+			  CSUM_HASH_IN_STREAM | CSUM_FSYNC);
+	free_chunkfile(cf);
+
+	if (ctx->split) {
+		FILE *chainf = fdopen_lock_file(&lk, "w");
+		char *final_graph_name;
+		int result;
+
+		if (!chainf) {
+			error(_("unable to open commit-graph chain file"));
+			return -1;
+		}
+
+		if (ctx->base_graph_name) {
+			const char *dest;
+			int idx = ctx->num_commit_graphs_after - 1;
+			if (ctx->num_commit_graphs_after > 1)
+				idx--;
+
+			dest = ctx->commit_graph_filenames_after[idx];
+
+			if (strcmp(ctx->base_graph_name, dest)) {
+				result = rename(ctx->base_graph_name, dest);
+
+				if (result) {
+					error(_("failed to rename base commit-graph file"));
+					return -1;
+				}
+			}
+		} else {
+			char *graph_name = get_commit_graph_filename(ctx->odb);
+			unlink(graph_name);
+			free(graph_name);
+		}
+
+		free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
+		ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(hash_to_hex(file_hash));
+		final_graph_name = get_split_graph_filename(ctx->odb,
+					ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
+		free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1]);
+		ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
+
+		result = rename_tempfile(&graph_layer, final_graph_name);
+
+		for (i = 0; i < ctx->num_commit_graphs_after; i++)
+			fprintf(get_lock_file_fp(&lk), "%s\n", ctx->commit_graph_hash_after[i]);
+
+		if (result) {
+			error(_("failed to rename temporary commit-graph file"));
+			return -1;
+		}
+	}
+
+	commit_lock_file(&lk);
+
+	return 0;
+}
+
+static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
+{
+	struct commit_graph *g;
+	uint32_t num_commits;
+	enum commit_graph_split_flags flags = COMMIT_GRAPH_SPLIT_UNSPECIFIED;
+	uint32_t i;
+
+	int max_commits = 0;
+	int size_mult = 2;
+
+	if (ctx->opts) {
+		max_commits = ctx->opts->max_commits;
+
+		if (ctx->opts->size_multiple)
+			size_mult = ctx->opts->size_multiple;
+
+		flags = ctx->opts->split_flags;
+	}
+
+	g = ctx->r->objects->commit_graph;
+	num_commits = ctx->commits.nr;
+	if (flags == COMMIT_GRAPH_SPLIT_REPLACE)
+		ctx->num_commit_graphs_after = 1;
+	else
+		ctx->num_commit_graphs_after = ctx->num_commit_graphs_before + 1;
+
+	if (flags != COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED &&
+	    flags != COMMIT_GRAPH_SPLIT_REPLACE) {
+		while (g && (g->num_commits <= st_mult(size_mult, num_commits) ||
+			    (max_commits && num_commits > max_commits))) {
+			if (g->odb != ctx->odb)
+				break;
+
+			if (unsigned_add_overflows(num_commits, g->num_commits))
+				die(_("cannot merge graphs with %"PRIuMAX", "
+				      "%"PRIuMAX" commits"),
+				    (uintmax_t)num_commits,
+				    (uintmax_t)g->num_commits);
+			num_commits += g->num_commits;
+			g = g->base_graph;
+
+			ctx->num_commit_graphs_after--;
+		}
+	}
+
+	if (flags != COMMIT_GRAPH_SPLIT_REPLACE)
+		ctx->new_base_graph = g;
+	else if (ctx->num_commit_graphs_after != 1)
+		BUG("split_graph_merge_strategy: num_commit_graphs_after "
+		    "should be 1 with --split=replace");
+
+	if (ctx->num_commit_graphs_after == 2) {
+		char *old_graph_name = get_commit_graph_filename(g->odb);
+
+		if (!strcmp(g->filename, old_graph_name) &&
+		    g->odb != ctx->odb) {
+			ctx->num_commit_graphs_after = 1;
+			ctx->new_base_graph = NULL;
+		}
+
+		free(old_graph_name);
+	}
+
+	CALLOC_ARRAY(ctx->commit_graph_filenames_after, ctx->num_commit_graphs_after);
+	CALLOC_ARRAY(ctx->commit_graph_hash_after, ctx->num_commit_graphs_after);
+
+	for (i = 0; i < ctx->num_commit_graphs_after &&
+		    i < ctx->num_commit_graphs_before; i++)
+		ctx->commit_graph_filenames_after[i] = xstrdup(ctx->commit_graph_filenames_before[i]);
+
+	i = ctx->num_commit_graphs_before - 1;
+	g = ctx->r->objects->commit_graph;
+
+	while (g) {
+		if (i < ctx->num_commit_graphs_after)
+			ctx->commit_graph_hash_after[i] = xstrdup(oid_to_hex(&g->oid));
+
+		/*
+		 * If the topmost remaining layer has generation data chunk, the
+		 * resultant layer also has generation data chunk.
+		 */
+		if (i == ctx->num_commit_graphs_after - 2)
+			ctx->write_generation_data = !!g->chunk_generation_data;
+
+		i--;
+		g = g->base_graph;
+	}
+}
+
+static void merge_commit_graph(struct write_commit_graph_context *ctx,
+			       struct commit_graph *g)
+{
+	uint32_t i;
+	uint32_t offset = g->num_commits_in_base;
+
+	if (unsigned_add_overflows(ctx->commits.nr, g->num_commits))
+		die(_("cannot merge graph %s, too many commits: %"PRIuMAX),
+		    oid_to_hex(&g->oid),
+		    (uintmax_t)st_add(ctx->commits.nr, g->num_commits));
+
+	ALLOC_GROW(ctx->commits.list, ctx->commits.nr + g->num_commits, ctx->commits.alloc);
+
+	for (i = 0; i < g->num_commits; i++) {
+		struct object_id oid;
+		struct commit *result;
+
+		display_progress(ctx->progress, i + 1);
+
+		load_oid_from_graph(g, i + offset, &oid);
+
+		/* only add commits if they still exist in the repo */
+		result = lookup_commit_reference_gently(ctx->r, &oid, 1);
+
+		if (result) {
+			ctx->commits.list[ctx->commits.nr] = result;
+			ctx->commits.nr++;
+		}
+	}
+}
+
+static int commit_compare(const void *_a, const void *_b)
+{
+	const struct commit *a = *(const struct commit **)_a;
+	const struct commit *b = *(const struct commit **)_b;
+	return oidcmp(&a->object.oid, &b->object.oid);
+}
+
+static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx)
+{
+	uint32_t i, dedup_i = 0;
+
+	if (ctx->report_progress)
+		ctx->progress = start_delayed_progress(
+					the_repository,
+					_("Scanning merged commits"),
+					ctx->commits.nr);
+
+	QSORT(ctx->commits.list, ctx->commits.nr, commit_compare);
+
+	ctx->num_extra_edges = 0;
+	for (i = 0; i < ctx->commits.nr; i++) {
+		display_progress(ctx->progress, i + 1);
+
+		if (i && oideq(&ctx->commits.list[i - 1]->object.oid,
+			  &ctx->commits.list[i]->object.oid)) {
+			/*
+			 * Silently ignore duplicates. These were likely
+			 * created due to a commit appearing in multiple
+			 * layers of the chain, which is unexpected but
+			 * not invalid. We should make sure there is a
+			 * unique copy in the new layer.
+			 */
+		} else {
+			unsigned int num_parents;
+
+			ctx->commits.list[dedup_i] = ctx->commits.list[i];
+			dedup_i++;
+
+			num_parents = commit_list_count(ctx->commits.list[i]->parents);
+			if (num_parents > 2)
+				ctx->num_extra_edges += num_parents - 1;
+		}
+	}
+
+	ctx->commits.nr = dedup_i;
+
+	stop_progress(&ctx->progress);
+}
+
+static void merge_commit_graphs(struct write_commit_graph_context *ctx)
+{
+	struct commit_graph *g = ctx->r->objects->commit_graph;
+	uint32_t current_graph_number = ctx->num_commit_graphs_before;
+
+	while (g && current_graph_number >= ctx->num_commit_graphs_after) {
+		current_graph_number--;
+
+		if (ctx->report_progress)
+			ctx->progress = start_delayed_progress(the_repository,
+							       _("Merging commit-graph"), 0);
+
+		merge_commit_graph(ctx, g);
+		stop_progress(&ctx->progress);
+
+		g = g->base_graph;
+	}
+
+	if (g) {
+		ctx->new_base_graph = g;
+		ctx->new_num_commits_in_base = g->num_commits + g->num_commits_in_base;
+	}
+
+	if (ctx->new_base_graph)
+		ctx->base_graph_name = xstrdup(ctx->new_base_graph->filename);
+
+	sort_and_scan_merged_commits(ctx);
+}
+
+static void mark_commit_graphs(struct write_commit_graph_context *ctx)
+{
+	uint32_t i;
+	time_t now = time(NULL);
+
+	for (i = ctx->num_commit_graphs_after - 1; i < ctx->num_commit_graphs_before; i++) {
+		struct stat st;
+		struct utimbuf updated_time;
+
+		if (stat(ctx->commit_graph_filenames_before[i], &st) < 0)
+			continue;
+
+		updated_time.actime = st.st_atime;
+		updated_time.modtime = now;
+		utime(ctx->commit_graph_filenames_before[i], &updated_time);
+	}
+}
+
+static void expire_commit_graphs(struct write_commit_graph_context *ctx)
+{
+	struct strbuf path = STRBUF_INIT;
+	DIR *dir;
+	struct dirent *de;
+	size_t dirnamelen;
+	timestamp_t expire_time = time(NULL);
+
+	if (ctx->opts && ctx->opts->expire_time)
+		expire_time = ctx->opts->expire_time;
+	if (!ctx->split) {
+		char *chain_file_name = get_commit_graph_chain_filename(ctx->odb);
+		unlink(chain_file_name);
+		free(chain_file_name);
+		ctx->num_commit_graphs_after = 0;
+	}
+
+	strbuf_addstr(&path, ctx->odb->path);
+	strbuf_addstr(&path, "/info/commit-graphs");
+	dir = opendir(path.buf);
+
+	if (!dir)
+		goto out;
+
+	strbuf_addch(&path, '/');
+	dirnamelen = path.len;
+	while ((de = readdir(dir)) != NULL) {
+		struct stat st;
+		uint32_t i, found = 0;
+
+		strbuf_setlen(&path, dirnamelen);
+		strbuf_addstr(&path, de->d_name);
+
+		if (stat(path.buf, &st) < 0)
+			continue;
+
+		if (st.st_mtime > expire_time)
+			continue;
+		if (path.len < 6 || strcmp(path.buf + path.len - 6, ".graph"))
+			continue;
+
+		for (i = 0; i < ctx->num_commit_graphs_after; i++) {
+			if (!strcmp(ctx->commit_graph_filenames_after[i],
+				    path.buf)) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found)
+			unlink(path.buf);
+	}
+
+out:
+	if(dir)
+		closedir(dir);
+	strbuf_release(&path);
+}
+
+int write_commit_graph(struct object_directory *odb,
+		       const struct string_list *const pack_indexes,
+		       struct oidset *commits,
+		       enum commit_graph_write_flags flags,
+		       const struct commit_graph_opts *opts)
+{
+	struct repository *r = the_repository;
+	struct write_commit_graph_context *ctx;
+	uint32_t i;
+	int res = 0;
+	int replace = 0;
+	struct bloom_filter_settings bloom_settings = DEFAULT_BLOOM_FILTER_SETTINGS;
+	struct topo_level_slab topo_levels;
+
+	prepare_repo_settings(r);
+	if (!r->settings.core_commit_graph) {
+		warning(_("attempting to write a commit-graph, but 'core.commitGraph' is disabled"));
+		return 0;
+	}
+	if (!commit_graph_compatible(r))
+		return 0;
+	if (r->settings.commit_graph_changed_paths_version < -1
+	    || r->settings.commit_graph_changed_paths_version > 2) {
+		warning(_("attempting to write a commit-graph, but "
+			  "'commitGraph.changedPathsVersion' (%d) is not supported"),
+			r->settings.commit_graph_changed_paths_version);
+		return 0;
+	}
+
+	CALLOC_ARRAY(ctx, 1);
+	ctx->r = r;
+	ctx->odb = odb;
+	ctx->append = flags & COMMIT_GRAPH_WRITE_APPEND ? 1 : 0;
+	ctx->report_progress = flags & COMMIT_GRAPH_WRITE_PROGRESS ? 1 : 0;
+	ctx->split = flags & COMMIT_GRAPH_WRITE_SPLIT ? 1 : 0;
+	ctx->opts = opts;
+	ctx->total_bloom_filter_data_size = 0;
+	ctx->write_generation_data = (get_configured_generation_version(r) == 2);
+	ctx->num_generation_data_overflows = 0;
+
+	bloom_settings.hash_version = r->settings.commit_graph_changed_paths_version;
+	bloom_settings.bits_per_entry = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_BITS_PER_ENTRY",
+						      bloom_settings.bits_per_entry);
+	bloom_settings.num_hashes = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_NUM_HASHES",
+						  bloom_settings.num_hashes);
+	bloom_settings.max_changed_paths = git_env_ulong("GIT_TEST_BLOOM_SETTINGS_MAX_CHANGED_PATHS",
+							 bloom_settings.max_changed_paths);
+	ctx->bloom_settings = &bloom_settings;
+
+	init_topo_level_slab(&topo_levels);
+	ctx->topo_levels = &topo_levels;
+
+	prepare_commit_graph(ctx->r);
+	if (ctx->r->objects->commit_graph) {
+		struct commit_graph *g = ctx->r->objects->commit_graph;
+
+		while (g) {
+			g->topo_levels = &topo_levels;
+			g = g->base_graph;
+		}
+	}
+
+	if (flags & COMMIT_GRAPH_WRITE_BLOOM_FILTERS)
+		ctx->changed_paths = 1;
+	if (!(flags & COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS)) {
+		struct commit_graph *g;
+
+		g = ctx->r->objects->commit_graph;
+
+		/* We have changed-paths already. Keep them in the next graph */
+		if (g && g->bloom_filter_settings) {
+			ctx->changed_paths = 1;
+
+			/* don't propagate the hash_version unless unspecified */
+			if (bloom_settings.hash_version == -1)
+				bloom_settings.hash_version = g->bloom_filter_settings->hash_version;
+			bloom_settings.bits_per_entry = g->bloom_filter_settings->bits_per_entry;
+			bloom_settings.num_hashes = g->bloom_filter_settings->num_hashes;
+			bloom_settings.max_changed_paths = g->bloom_filter_settings->max_changed_paths;
+		}
+	}
+
+	bloom_settings.hash_version = bloom_settings.hash_version == 2 ? 2 : 1;
+
+	if (ctx->split) {
+		struct commit_graph *g = ctx->r->objects->commit_graph;
+
+		while (g) {
+			ctx->num_commit_graphs_before++;
+			g = g->base_graph;
+		}
+
+		if (ctx->num_commit_graphs_before) {
+			ALLOC_ARRAY(ctx->commit_graph_filenames_before, ctx->num_commit_graphs_before);
+			i = ctx->num_commit_graphs_before;
+			g = ctx->r->objects->commit_graph;
+
+			while (g) {
+				ctx->commit_graph_filenames_before[--i] = xstrdup(g->filename);
+				g = g->base_graph;
+			}
+		}
+
+		if (ctx->opts)
+			replace = ctx->opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;
+	}
+
+	ctx->approx_nr_objects = repo_approximate_object_count(the_repository);
+
+	if (ctx->append && ctx->r->objects->commit_graph) {
+		struct commit_graph *g = ctx->r->objects->commit_graph;
+		for (i = 0; i < g->num_commits; i++) {
+			struct object_id oid;
+			oidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),
+				the_repository->hash_algo);
+			oid_array_append(&ctx->oids, &oid);
+		}
+	}
+
+	if (pack_indexes) {
+		ctx->order_by_pack = 1;
+		if ((res = fill_oids_from_packs(ctx, pack_indexes)))
+			goto cleanup;
+	}
+
+	if (commits) {
+		if ((res = fill_oids_from_commits(ctx, commits)))
+			goto cleanup;
+	}
+
+	if (!pack_indexes && !commits) {
+		ctx->order_by_pack = 1;
+		fill_oids_from_all_packs(ctx);
+	}
+
+	close_reachable(ctx);
+
+	copy_oids_to_commits(ctx);
+
+	if (ctx->commits.nr >= GRAPH_EDGE_LAST_MASK) {
+		error(_("too many commits to write graph"));
+		res = -1;
+		goto cleanup;
+	}
+
+	if (!ctx->commits.nr && !replace)
+		goto cleanup;
+
+	if (ctx->split) {
+		split_graph_merge_strategy(ctx);
+
+		if (!replace)
+			merge_commit_graphs(ctx);
+	} else
+		ctx->num_commit_graphs_after = 1;
+
+	ctx->trust_generation_numbers = validate_mixed_generation_chain(ctx->r->objects->commit_graph);
+
+	compute_topological_levels(ctx);
+	if (ctx->write_generation_data)
+		compute_generation_numbers(ctx);
+
+	if (ctx->changed_paths)
+		compute_bloom_filters(ctx);
+
+	res = write_commit_graph_file(ctx);
+
+	if (ctx->changed_paths)
+		deinit_bloom_filters();
+
+	if (ctx->split)
+		mark_commit_graphs(ctx);
+
+	expire_commit_graphs(ctx);
+
+cleanup:
+	free(ctx->graph_name);
+	free(ctx->base_graph_name);
+	free(ctx->commits.list);
+	oid_array_clear(&ctx->oids);
+	clear_topo_level_slab(&topo_levels);
+
+	for (i = 0; i < ctx->num_commit_graphs_before; i++)
+		free(ctx->commit_graph_filenames_before[i]);
+	free(ctx->commit_graph_filenames_before);
+
+	for (i = 0; i < ctx->num_commit_graphs_after; i++) {
+		free(ctx->commit_graph_filenames_after[i]);
+		free(ctx->commit_graph_hash_after[i]);
+	}
+	free(ctx->commit_graph_filenames_after);
+	free(ctx->commit_graph_hash_after);
+
+	free(ctx);
+
+	return res;
+}
+
+#define VERIFY_COMMIT_GRAPH_ERROR_HASH 2
+static int verify_commit_graph_error;
+
+__attribute__((format (printf, 1, 2)))
+static void graph_report(const char *fmt, ...)
+{
+	va_list ap;
+
+	verify_commit_graph_error = 1;
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+static int commit_graph_checksum_valid(struct commit_graph *g)
+{
+	return hashfile_checksum_valid(g->data, g->data_len);
+}
+
+static int verify_one_commit_graph(struct repository *r,
+				   struct commit_graph *g,
+				   struct progress *progress,
+				   uint64_t *seen)
+{
+	uint32_t i, cur_fanout_pos = 0;
+	struct object_id prev_oid, cur_oid;
+	struct commit *seen_gen_zero = NULL;
+	struct commit *seen_gen_non_zero = NULL;
+
+	if (!commit_graph_checksum_valid(g)) {
+		graph_report(_("the commit-graph file has incorrect checksum and is likely corrupt"));
+		verify_commit_graph_error = VERIFY_COMMIT_GRAPH_ERROR_HASH;
+	}
+
+	for (i = 0; i < g->num_commits; i++) {
+		struct commit *graph_commit;
+
+		oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),
+			the_repository->hash_algo);
+
+		if (i && oidcmp(&prev_oid, &cur_oid) >= 0)
+			graph_report(_("commit-graph has incorrect OID order: %s then %s"),
+				     oid_to_hex(&prev_oid),
+				     oid_to_hex(&cur_oid));
+
+		oidcpy(&prev_oid, &cur_oid);
+
+		while (cur_oid.hash[0] > cur_fanout_pos) {
+			uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
+
+			if (i != fanout_value)
+				graph_report(_("commit-graph has incorrect fanout value: fanout[%d] = %u != %u"),
+					     cur_fanout_pos, fanout_value, i);
+			cur_fanout_pos++;
+		}
+
+		graph_commit = lookup_commit(r, &cur_oid);
+		if (!parse_commit_in_graph_one(r, g, graph_commit))
+			graph_report(_("failed to parse commit %s from commit-graph"),
+				     oid_to_hex(&cur_oid));
+	}
+
+	while (cur_fanout_pos < 256) {
+		uint32_t fanout_value = get_be32(g->chunk_oid_fanout + cur_fanout_pos);
+
+		if (g->num_commits != fanout_value)
+			graph_report(_("commit-graph has incorrect fanout value: fanout[%d] = %u != %u"),
+				     cur_fanout_pos, fanout_value, i);
+
+		cur_fanout_pos++;
+	}
+
+	if (verify_commit_graph_error & ~VERIFY_COMMIT_GRAPH_ERROR_HASH)
+		return verify_commit_graph_error;
+
+	for (i = 0; i < g->num_commits; i++) {
+		struct commit *graph_commit, *odb_commit;
+		struct commit_list *graph_parents, *odb_parents;
+		timestamp_t max_generation = 0;
+		timestamp_t generation;
+
+		display_progress(progress, ++(*seen));
+		oidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),
+			the_repository->hash_algo);
+
+		graph_commit = lookup_commit(r, &cur_oid);
+		odb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));
+		if (repo_parse_commit_internal(r, odb_commit, 0, 0)) {
+			graph_report(_("failed to parse commit %s from object database for commit-graph"),
+				     oid_to_hex(&cur_oid));
+			continue;
+		}
+
+		if (!oideq(&get_commit_tree_in_graph_one(r, g, graph_commit)->object.oid,
+			   get_commit_tree_oid(odb_commit)))
+			graph_report(_("root tree OID for commit %s in commit-graph is %s != %s"),
+				     oid_to_hex(&cur_oid),
+				     oid_to_hex(get_commit_tree_oid(graph_commit)),
+				     oid_to_hex(get_commit_tree_oid(odb_commit)));
+
+		graph_parents = graph_commit->parents;
+		odb_parents = odb_commit->parents;
+
+		while (graph_parents) {
+			if (!odb_parents) {
+				graph_report(_("commit-graph parent list for commit %s is too long"),
+					     oid_to_hex(&cur_oid));
+				break;
+			}
+
+			/* parse parent in case it is in a base graph */
+			parse_commit_in_graph_one(r, g, graph_parents->item);
+
+			if (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))
+				graph_report(_("commit-graph parent for %s is %s != %s"),
+					     oid_to_hex(&cur_oid),
+					     oid_to_hex(&graph_parents->item->object.oid),
+					     oid_to_hex(&odb_parents->item->object.oid));
+
+			generation = commit_graph_generation_from_graph(graph_parents->item);
+			if (generation > max_generation)
+				max_generation = generation;
+
+			graph_parents = graph_parents->next;
+			odb_parents = odb_parents->next;
+		}
+
+		if (odb_parents)
+			graph_report(_("commit-graph parent list for commit %s terminates early"),
+				     oid_to_hex(&cur_oid));
+
+		if (commit_graph_generation_from_graph(graph_commit))
+			seen_gen_non_zero = graph_commit;
+		else
+			seen_gen_zero = graph_commit;
+
+		if (seen_gen_zero)
+			continue;
+
+		/*
+		 * If we are using topological level and one of our parents has
+		 * generation GENERATION_NUMBER_V1_MAX, then our generation is
+		 * also GENERATION_NUMBER_V1_MAX. Decrement to avoid extra logic
+		 * in the following condition.
+		 */
+		if (!g->read_generation_data && max_generation == GENERATION_NUMBER_V1_MAX)
+			max_generation--;
+
+		generation = commit_graph_generation(graph_commit);
+		if (generation < max_generation + 1)
+			graph_report(_("commit-graph generation for commit %s is %"PRItime" < %"PRItime),
+				     oid_to_hex(&cur_oid),
+				     generation,
+				     max_generation + 1);
+
+		if (graph_commit->date != odb_commit->date)
+			graph_report(_("commit date for commit %s in commit-graph is %"PRItime" != %"PRItime),
+				     oid_to_hex(&cur_oid),
+				     graph_commit->date,
+				     odb_commit->date);
+	}
+
+	if (seen_gen_zero && seen_gen_non_zero)
+		graph_report(_("commit-graph has both zero and non-zero "
+			       "generations (e.g., commits '%s' and '%s')"),
+			     oid_to_hex(&seen_gen_zero->object.oid),
+			     oid_to_hex(&seen_gen_non_zero->object.oid));
+
+	return verify_commit_graph_error;
+}
+
+int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)
+{
+	struct progress *progress = NULL;
+	int local_error = 0;
+	uint64_t seen = 0;
+
+	if (!g) {
+		graph_report("no commit-graph file loaded");
+		return 1;
+	}
+
+	if (flags & COMMIT_GRAPH_WRITE_PROGRESS) {
+		uint64_t total = g->num_commits;
+		if (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))
+			total += g->num_commits_in_base;
+
+		progress = start_progress(the_repository,
+					  _("Verifying commits in commit graph"),
+					  total);
+	}
+
+	for (; g; g = g->base_graph) {
+		local_error |= verify_one_commit_graph(r, g, progress, &seen);
+		if (flags & COMMIT_GRAPH_VERIFY_SHALLOW)
+			break;
+	}
+
+	stop_progress(&progress);
+
+	return local_error;
+}
+
+void free_commit_graph(struct commit_graph *g)
+{
+	while (g) {
+		struct commit_graph *next = g->base_graph;
+
+		if (g->data)
+			munmap((void *)g->data, g->data_len);
+		free(g->filename);
+		free(g->bloom_filter_settings);
+		free(g);
+
+		g = next;
+	}
+}
+
+void disable_commit_graph(struct repository *r)
+{
+	r->commit_graph_disabled = 1;
+}
diff --git a/commit-graph.h b/commit-graph.h
new file mode 100644
index 0000000000..6781940195
--- /dev/null
+++ b/commit-graph.h
@@ -0,0 +1,216 @@
+#ifndef COMMIT_GRAPH_H
+#define COMMIT_GRAPH_H
+
+#include "object-store-ll.h"
+#include "oidset.h"
+
+#define GIT_TEST_COMMIT_GRAPH "GIT_TEST_COMMIT_GRAPH"
+#define GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE "GIT_TEST_COMMIT_GRAPH_DIE_ON_PARSE"
+#define GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS "GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS"
+
+/*
+ * This environment variable controls whether commits looked up via the
+ * commit graph will be double checked to exist in the object database.
+ */
+#define GIT_COMMIT_GRAPH_PARANOIA "GIT_COMMIT_GRAPH_PARANOIA"
+
+/*
+ * This method is only used to enhance coverage of the commit-graph
+ * feature in the test suite with the GIT_TEST_COMMIT_GRAPH and
+ * GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS environment variables. Do not
+ * call this method oustide of a builtin, and only if you know what
+ * you are doing!
+ */
+void git_test_write_commit_graph_or_die(void);
+
+struct commit;
+struct bloom_filter_settings;
+struct repository;
+struct raw_object_store;
+struct string_list;
+
+char *get_commit_graph_filename(struct object_directory *odb);
+char *get_commit_graph_chain_filename(struct object_directory *odb);
+int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
+int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st);
+
+/*
+ * Given a commit struct, try to fill the commit struct info, including:
+ *  1. tree object
+ *  2. date
+ *  3. parents.
+ *
+ * Returns 1 if and only if the commit was found in the packed graph.
+ *
+ * See parse_commit_buffer() for the fallback after this call.
+ */
+int parse_commit_in_graph(struct repository *r, struct commit *item);
+
+/*
+ * Fills `*pos` with the graph position of `c`, and returns 1 if `c` is
+ * found in the commit-graph belonging to `r`, or 0 otherwise.
+ * Initializes the commit-graph belonging to `r` if it hasn't been
+ * already.
+ *
+ * Note: this is a low-level helper that does not alter any slab data
+ * associated with `c`. Useful in circumstances where the slab data is
+ * already being modified (e.g., writing the commit-graph itself).
+ *
+ * In most cases, callers should use `parse_commit_in_graph()` instead.
+ */
+int repo_find_commit_pos_in_graph(struct repository *r, struct commit *c,
+				  uint32_t *pos);
+
+/*
+ * Look up the given commit ID in the commit-graph. This will only return a
+ * commit if the ID exists both in the graph and in the object database such
+ * that we don't return commits whose object has been pruned. Otherwise, this
+ * function returns `NULL`.
+ */
+struct commit *lookup_commit_in_graph(struct repository *repo, const struct object_id *id);
+
+/*
+ * It is possible that we loaded commit contents from the commit buffer,
+ * but we also want to ensure the commit-graph content is correctly
+ * checked and filled. Fill the graph_pos and generation members of
+ * the given commit.
+ */
+void load_commit_graph_info(struct repository *r, struct commit *item);
+
+struct tree *get_commit_tree_in_graph(struct repository *r,
+				      const struct commit *c);
+
+struct commit_graph {
+	const unsigned char *data;
+	size_t data_len;
+
+	unsigned char hash_len;
+	unsigned char num_chunks;
+	uint32_t num_commits;
+	struct object_id oid;
+	char *filename;
+	struct object_directory *odb;
+
+	uint32_t num_commits_in_base;
+	unsigned int read_generation_data;
+	struct commit_graph *base_graph;
+
+	const uint32_t *chunk_oid_fanout;
+	const unsigned char *chunk_oid_lookup;
+	const unsigned char *chunk_commit_data;
+	const unsigned char *chunk_generation_data;
+	const unsigned char *chunk_generation_data_overflow;
+	size_t chunk_generation_data_overflow_size;
+	const unsigned char *chunk_extra_edges;
+	size_t chunk_extra_edges_size;
+	const unsigned char *chunk_base_graphs;
+	size_t chunk_base_graphs_size;
+	const unsigned char *chunk_bloom_indexes;
+	const unsigned char *chunk_bloom_data;
+	size_t chunk_bloom_data_size;
+
+	struct topo_level_slab *topo_levels;
+	struct bloom_filter_settings *bloom_filter_settings;
+};
+
+struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,
+						 int fd, struct stat *st,
+						 struct object_directory *odb);
+struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,
+						   int fd, struct stat *st,
+						   int *incomplete_chain);
+struct commit_graph *read_commit_graph_one(struct repository *r,
+					   struct object_directory *odb);
+
+struct repo_settings;
+
+/*
+ * Callers should initialize the repo_settings with prepare_repo_settings()
+ * prior to calling parse_commit_graph().
+ */
+struct commit_graph *parse_commit_graph(struct repo_settings *s,
+					void *graph_map, size_t graph_size);
+
+/*
+ * Return 1 if and only if the repository has a commit-graph
+ * file and generation numbers are computed in that file.
+ */
+int generation_numbers_enabled(struct repository *r);
+
+/*
+ * Return 1 if and only if the repository has a commit-graph
+ * file and generation data chunk has been written for the file.
+ */
+int corrected_commit_dates_enabled(struct repository *r);
+
+struct bloom_filter_settings *get_bloom_filter_settings(struct repository *r);
+
+enum commit_graph_write_flags {
+	COMMIT_GRAPH_WRITE_APPEND     = (1 << 0),
+	COMMIT_GRAPH_WRITE_PROGRESS   = (1 << 1),
+	COMMIT_GRAPH_WRITE_SPLIT      = (1 << 2),
+	COMMIT_GRAPH_WRITE_BLOOM_FILTERS = (1 << 3),
+	COMMIT_GRAPH_NO_WRITE_BLOOM_FILTERS = (1 << 4),
+};
+
+enum commit_graph_split_flags {
+	COMMIT_GRAPH_SPLIT_UNSPECIFIED      = 0,
+	COMMIT_GRAPH_SPLIT_MERGE_PROHIBITED = 1,
+	COMMIT_GRAPH_SPLIT_REPLACE          = 2
+};
+
+struct commit_graph_opts {
+	int size_multiple;
+	int max_commits;
+	timestamp_t expire_time;
+	enum commit_graph_split_flags split_flags;
+	int max_new_filters;
+};
+
+/*
+ * The write_commit_graph* methods return zero on success
+ * and a negative value on failure. Note that if the repository
+ * is not compatible with the commit-graph feature, then the
+ * methods will return 0 without writing a commit-graph.
+ */
+int write_commit_graph_reachable(struct object_directory *odb,
+				 enum commit_graph_write_flags flags,
+				 const struct commit_graph_opts *opts);
+int write_commit_graph(struct object_directory *odb,
+		       const struct string_list *pack_indexes,
+		       struct oidset *commits,
+		       enum commit_graph_write_flags flags,
+		       const struct commit_graph_opts *opts);
+
+#define COMMIT_GRAPH_VERIFY_SHALLOW	(1 << 0)
+
+int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags);
+
+void close_commit_graph(struct raw_object_store *);
+void free_commit_graph(struct commit_graph *);
+
+/*
+ * Disable further use of the commit graph in this process when parsing a
+ * "struct commit".
+ */
+void disable_commit_graph(struct repository *r);
+
+struct commit_graph_data {
+	uint32_t graph_pos;
+	timestamp_t generation;
+};
+
+/*
+ * Commits should be parsed before accessing generation, graph positions.
+ */
+timestamp_t commit_graph_generation(const struct commit *);
+uint32_t commit_graph_position(const struct commit *);
+
+/*
+ * After this method, all commits reachable from those in the given
+ * list will have non-zero, non-infinite generation numbers.
+ */
+void ensure_generations_valid(struct repository *r,
+			      struct commit **commits, size_t nr);
+
+#endif
diff --git a/commit-reach.c b/commit-reach.c
new file mode 100644
index 0000000000..a339e41aa4
--- /dev/null
+++ b/commit-reach.c
@@ -0,0 +1,1363 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "commit.h"
+#include "commit-graph.h"
+#include "decorate.h"
+#include "hex.h"
+#include "prio-queue.h"
+#include "ref-filter.h"
+#include "revision.h"
+#include "tag.h"
+#include "commit-reach.h"
+#include "ewah/ewok.h"
+
+/* Remember to update object flag allocation in object.h */
+#define PARENT1		(1u<<16)
+#define PARENT2		(1u<<17)
+#define STALE		(1u<<18)
+#define RESULT		(1u<<19)
+
+static const unsigned all_flags = (PARENT1 | PARENT2 | STALE | RESULT);
+
+static int compare_commits_by_gen(const void *_a, const void *_b)
+{
+	const struct commit *a = *(const struct commit * const *)_a;
+	const struct commit *b = *(const struct commit * const *)_b;
+
+	timestamp_t generation_a = commit_graph_generation(a);
+	timestamp_t generation_b = commit_graph_generation(b);
+
+	if (generation_a < generation_b)
+		return -1;
+	if (generation_a > generation_b)
+		return 1;
+	if (a->date < b->date)
+		return -1;
+	if (a->date > b->date)
+		return 1;
+	return 0;
+}
+
+static int queue_has_nonstale(struct prio_queue *queue)
+{
+	for (size_t i = 0; i < queue->nr; i++) {
+		struct commit *commit = queue->array[i].data;
+		if (!(commit->object.flags & STALE))
+			return 1;
+	}
+	return 0;
+}
+
+/* all input commits in one and twos[] must have been parsed! */
+static int paint_down_to_common(struct repository *r,
+				struct commit *one, int n,
+				struct commit **twos,
+				timestamp_t min_generation,
+				int ignore_missing_commits,
+				struct commit_list **result)
+{
+	struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
+	int i;
+	timestamp_t last_gen = GENERATION_NUMBER_INFINITY;
+
+	if (!min_generation && !corrected_commit_dates_enabled(r))
+		queue.compare = compare_commits_by_commit_date;
+
+	one->object.flags |= PARENT1;
+	if (!n) {
+		commit_list_append(one, result);
+		return 0;
+	}
+	prio_queue_put(&queue, one);
+
+	for (i = 0; i < n; i++) {
+		twos[i]->object.flags |= PARENT2;
+		prio_queue_put(&queue, twos[i]);
+	}
+
+	while (queue_has_nonstale(&queue)) {
+		struct commit *commit = prio_queue_get(&queue);
+		struct commit_list *parents;
+		int flags;
+		timestamp_t generation = commit_graph_generation(commit);
+
+		if (min_generation && generation > last_gen)
+			BUG("bad generation skip %"PRItime" > %"PRItime" at %s",
+			    generation, last_gen,
+			    oid_to_hex(&commit->object.oid));
+		last_gen = generation;
+
+		if (generation < min_generation)
+			break;
+
+		flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
+		if (flags == (PARENT1 | PARENT2)) {
+			if (!(commit->object.flags & RESULT)) {
+				commit->object.flags |= RESULT;
+				commit_list_insert_by_date(commit, result);
+			}
+			/* Mark parents of a found merge stale */
+			flags |= STALE;
+		}
+		parents = commit->parents;
+		while (parents) {
+			struct commit *p = parents->item;
+			parents = parents->next;
+			if ((p->object.flags & flags) == flags)
+				continue;
+			if (repo_parse_commit(r, p)) {
+				clear_prio_queue(&queue);
+				free_commit_list(*result);
+				*result = NULL;
+				/*
+				 * At this stage, we know that the commit is
+				 * missing: `repo_parse_commit()` uses
+				 * `OBJECT_INFO_DIE_IF_CORRUPT` and therefore
+				 * corrupt commits would already have been
+				 * dispatched with a `die()`.
+				 */
+				if (ignore_missing_commits)
+					return 0;
+				return error(_("could not parse commit %s"),
+					     oid_to_hex(&p->object.oid));
+			}
+			p->object.flags |= flags;
+			prio_queue_put(&queue, p);
+		}
+	}
+
+	clear_prio_queue(&queue);
+	return 0;
+}
+
+static int merge_bases_many(struct repository *r,
+			    struct commit *one, int n,
+			    struct commit **twos,
+			    struct commit_list **result)
+{
+	struct commit_list *list = NULL;
+	int i;
+
+	for (i = 0; i < n; i++) {
+		if (one == twos[i]) {
+			/*
+			 * We do not mark this even with RESULT so we do not
+			 * have to clean it up.
+			 */
+			*result = commit_list_insert(one, result);
+			return 0;
+		}
+	}
+
+	if (!one)
+		return 0;
+	if (repo_parse_commit(r, one))
+		return error(_("could not parse commit %s"),
+			     oid_to_hex(&one->object.oid));
+	for (i = 0; i < n; i++) {
+		if (!twos[i])
+			return 0;
+		if (repo_parse_commit(r, twos[i]))
+			return error(_("could not parse commit %s"),
+				     oid_to_hex(&twos[i]->object.oid));
+	}
+
+	if (paint_down_to_common(r, one, n, twos, 0, 0, &list)) {
+		free_commit_list(list);
+		return -1;
+	}
+
+	while (list) {
+		struct commit *commit = pop_commit(&list);
+		if (!(commit->object.flags & STALE))
+			commit_list_insert_by_date(commit, result);
+	}
+	return 0;
+}
+
+int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result)
+{
+	struct commit_list *i, *j, *k;
+
+	if (!in)
+		return 0;
+
+	commit_list_insert(in->item, result);
+
+	for (i = in->next; i; i = i->next) {
+		struct commit_list *new_commits = NULL, *end = NULL;
+
+		for (j = *result; j; j = j->next) {
+			struct commit_list *bases = NULL;
+			if (repo_get_merge_bases(the_repository, i->item,
+						 j->item, &bases) < 0) {
+				free_commit_list(bases);
+				free_commit_list(*result);
+				*result = NULL;
+				return -1;
+			}
+			if (!new_commits)
+				new_commits = bases;
+			else
+				end->next = bases;
+			for (k = bases; k; k = k->next)
+				end = k;
+		}
+		free_commit_list(*result);
+		*result = new_commits;
+	}
+	return 0;
+}
+
+static int remove_redundant_no_gen(struct repository *r,
+				   struct commit **array,
+				   size_t cnt, size_t *dedup_cnt)
+{
+	struct commit **work;
+	unsigned char *redundant;
+	size_t *filled_index;
+	size_t i, j, filled;
+
+	CALLOC_ARRAY(work, cnt);
+	redundant = xcalloc(cnt, 1);
+	ALLOC_ARRAY(filled_index, cnt - 1);
+
+	for (i = 0; i < cnt; i++)
+		repo_parse_commit(r, array[i]);
+	for (i = 0; i < cnt; i++) {
+		struct commit_list *common = NULL;
+		timestamp_t min_generation = commit_graph_generation(array[i]);
+
+		if (redundant[i])
+			continue;
+		for (j = filled = 0; j < cnt; j++) {
+			timestamp_t curr_generation;
+			if (i == j || redundant[j])
+				continue;
+			filled_index[filled] = j;
+			work[filled++] = array[j];
+
+			curr_generation = commit_graph_generation(array[j]);
+			if (curr_generation < min_generation)
+				min_generation = curr_generation;
+		}
+		if (paint_down_to_common(r, array[i], filled,
+					 work, min_generation, 0, &common)) {
+			clear_commit_marks(array[i], all_flags);
+			clear_commit_marks_many(filled, work, all_flags);
+			free_commit_list(common);
+			free(work);
+			free(redundant);
+			free(filled_index);
+			return -1;
+		}
+		if (array[i]->object.flags & PARENT2)
+			redundant[i] = 1;
+		for (j = 0; j < filled; j++)
+			if (work[j]->object.flags & PARENT1)
+				redundant[filled_index[j]] = 1;
+		clear_commit_marks(array[i], all_flags);
+		clear_commit_marks_many(filled, work, all_flags);
+		free_commit_list(common);
+	}
+
+	/* Now collect the result */
+	COPY_ARRAY(work, array, cnt);
+	for (i = filled = 0; i < cnt; i++)
+		if (!redundant[i])
+			array[filled++] = work[i];
+	*dedup_cnt = filled;
+	free(work);
+	free(redundant);
+	free(filled_index);
+	return 0;
+}
+
+static int remove_redundant_with_gen(struct repository *r,
+				     struct commit **array, size_t cnt,
+				     size_t *dedup_cnt)
+{
+	size_t i, count_non_stale = 0, count_still_independent = cnt;
+	timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
+	struct commit **walk_start, **sorted;
+	size_t walk_start_nr = 0, walk_start_alloc = cnt;
+	size_t min_gen_pos = 0;
+
+	/*
+	 * Sort the input by generation number, ascending. This allows
+	 * us to increase the "min_generation" limit when we discover
+	 * the commit with lowest generation is STALE. The index
+	 * min_gen_pos points to the current position within 'array'
+	 * that is not yet known to be STALE.
+	 */
+	DUP_ARRAY(sorted, array, cnt);
+	QSORT(sorted, cnt, compare_commits_by_gen);
+	min_generation = commit_graph_generation(sorted[0]);
+
+	ALLOC_ARRAY(walk_start, walk_start_alloc);
+
+	/* Mark all parents of the input as STALE */
+	for (i = 0; i < cnt; i++) {
+		struct commit_list *parents;
+
+		repo_parse_commit(r, array[i]);
+		array[i]->object.flags |= RESULT;
+		parents = array[i]->parents;
+
+		while (parents) {
+			repo_parse_commit(r, parents->item);
+			if (!(parents->item->object.flags & STALE)) {
+				parents->item->object.flags |= STALE;
+				ALLOC_GROW(walk_start, walk_start_nr + 1, walk_start_alloc);
+				walk_start[walk_start_nr++] = parents->item;
+			}
+			parents = parents->next;
+		}
+	}
+
+	QSORT(walk_start, walk_start_nr, compare_commits_by_gen);
+
+	/* remove STALE bit for now to allow walking through parents */
+	for (i = 0; i < walk_start_nr; i++)
+		walk_start[i]->object.flags &= ~STALE;
+
+	/*
+	 * Start walking from the highest generation. Hopefully, it will
+	 * find all other items during the first-parent walk, and we can
+	 * terminate early. Otherwise, we will do the same amount of work
+	 * as before.
+	 */
+	for (i = walk_start_nr; i && count_still_independent > 1; i--) {
+		/* push the STALE bits up to min generation */
+		struct commit_list *stack = NULL;
+
+		commit_list_insert(walk_start[i - 1], &stack);
+		walk_start[i - 1]->object.flags |= STALE;
+
+		while (stack) {
+			struct commit_list *parents;
+			struct commit *c = stack->item;
+
+			repo_parse_commit(r, c);
+
+			if (c->object.flags & RESULT) {
+				c->object.flags &= ~RESULT;
+				if (--count_still_independent <= 1)
+					break;
+				if (oideq(&c->object.oid, &sorted[min_gen_pos]->object.oid)) {
+					while (min_gen_pos < cnt - 1 &&
+					       (sorted[min_gen_pos]->object.flags & STALE))
+						min_gen_pos++;
+					min_generation = commit_graph_generation(sorted[min_gen_pos]);
+				}
+			}
+
+			if (commit_graph_generation(c) < min_generation) {
+				pop_commit(&stack);
+				continue;
+			}
+
+			parents = c->parents;
+			while (parents) {
+				if (!(parents->item->object.flags & STALE)) {
+					parents->item->object.flags |= STALE;
+					commit_list_insert(parents->item, &stack);
+					break;
+				}
+				parents = parents->next;
+			}
+
+			/* pop if all parents have been visited already */
+			if (!parents)
+				pop_commit(&stack);
+		}
+		free_commit_list(stack);
+	}
+	free(sorted);
+
+	/* clear result */
+	for (i = 0; i < cnt; i++)
+		array[i]->object.flags &= ~RESULT;
+
+	/* rearrange array */
+	for (i = count_non_stale = 0; i < cnt; i++) {
+		if (!(array[i]->object.flags & STALE))
+			array[count_non_stale++] = array[i];
+	}
+
+	/* clear marks */
+	clear_commit_marks_many(walk_start_nr, walk_start, STALE);
+	free(walk_start);
+
+	*dedup_cnt = count_non_stale;
+	return 0;
+}
+
+static int remove_redundant(struct repository *r, struct commit **array,
+			    size_t cnt, size_t *dedup_cnt)
+{
+	/*
+	 * Some commit in the array may be an ancestor of
+	 * another commit.  Move the independent commits to the
+	 * beginning of 'array' and return their number. Callers
+	 * should not rely upon the contents of 'array' after
+	 * that number.
+	 */
+	if (generation_numbers_enabled(r)) {
+		/*
+		 * If we have a single commit with finite generation
+		 * number, then the _with_gen algorithm is preferred.
+		 */
+		for (size_t i = 0; i < cnt; i++) {
+			if (commit_graph_generation(array[i]) < GENERATION_NUMBER_INFINITY)
+				return remove_redundant_with_gen(r, array, cnt, dedup_cnt);
+		}
+	}
+
+	return remove_redundant_no_gen(r, array, cnt, dedup_cnt);
+}
+
+static int get_merge_bases_many_0(struct repository *r,
+				  struct commit *one,
+				  size_t n,
+				  struct commit **twos,
+				  int cleanup,
+				  struct commit_list **result)
+{
+	struct commit_list *list;
+	struct commit **rslt;
+	size_t cnt, i;
+	int ret;
+
+	if (merge_bases_many(r, one, n, twos, result) < 0)
+		return -1;
+	for (i = 0; i < n; i++) {
+		if (one == twos[i])
+			return 0;
+	}
+	if (!*result || !(*result)->next) {
+		if (cleanup) {
+			clear_commit_marks(one, all_flags);
+			clear_commit_marks_many(n, twos, all_flags);
+		}
+		return 0;
+	}
+
+	/* There are more than one */
+	cnt = commit_list_count(*result);
+	CALLOC_ARRAY(rslt, cnt);
+	for (list = *result, i = 0; list; list = list->next)
+		rslt[i++] = list->item;
+	free_commit_list(*result);
+	*result = NULL;
+
+	clear_commit_marks(one, all_flags);
+	clear_commit_marks_many(n, twos, all_flags);
+
+	ret = remove_redundant(r, rslt, cnt, &cnt);
+	if (ret < 0) {
+		free(rslt);
+		return -1;
+	}
+	for (i = 0; i < cnt; i++)
+		commit_list_insert_by_date(rslt[i], result);
+	free(rslt);
+	return 0;
+}
+
+int repo_get_merge_bases_many(struct repository *r,
+			      struct commit *one,
+			      size_t n,
+			      struct commit **twos,
+			      struct commit_list **result)
+{
+	return get_merge_bases_many_0(r, one, n, twos, 1, result);
+}
+
+int repo_get_merge_bases_many_dirty(struct repository *r,
+				    struct commit *one,
+				    size_t n,
+				    struct commit **twos,
+				    struct commit_list **result)
+{
+	return get_merge_bases_many_0(r, one, n, twos, 0, result);
+}
+
+int repo_get_merge_bases(struct repository *r,
+			 struct commit *one,
+			 struct commit *two,
+			 struct commit_list **result)
+{
+	return get_merge_bases_many_0(r, one, 1, &two, 1, result);
+}
+
+/*
+ * Is "commit" a descendant of one of the elements on the "with_commit" list?
+ */
+int repo_is_descendant_of(struct repository *r,
+			  struct commit *commit,
+			  struct commit_list *with_commit)
+{
+	if (!with_commit)
+		return 1;
+
+	if (generation_numbers_enabled(r)) {
+		struct commit_list *from_list = NULL;
+		int result;
+		commit_list_insert(commit, &from_list);
+		result = can_all_from_reach(from_list, with_commit, 0);
+		free_commit_list(from_list);
+		return result;
+	} else {
+		while (with_commit) {
+			struct commit *other;
+			int ret;
+
+			other = with_commit->item;
+			with_commit = with_commit->next;
+			ret = repo_in_merge_bases_many(r, other, 1, &commit, 0);
+			if (ret)
+				return ret;
+		}
+		return 0;
+	}
+}
+
+/*
+ * Is "commit" an ancestor of one of the "references"?
+ */
+int repo_in_merge_bases_many(struct repository *r, struct commit *commit,
+			     int nr_reference, struct commit **reference,
+			     int ignore_missing_commits)
+{
+	struct commit_list *bases = NULL;
+	int ret = 0, i;
+	timestamp_t generation, max_generation = GENERATION_NUMBER_ZERO;
+
+	if (repo_parse_commit(r, commit))
+		return ignore_missing_commits ? 0 : -1;
+	for (i = 0; i < nr_reference; i++) {
+		if (repo_parse_commit(r, reference[i]))
+			return ignore_missing_commits ? 0 : -1;
+
+		generation = commit_graph_generation(reference[i]);
+		if (generation > max_generation)
+			max_generation = generation;
+	}
+
+	generation = commit_graph_generation(commit);
+	if (generation > max_generation)
+		return ret;
+
+	if (paint_down_to_common(r, commit,
+				 nr_reference, reference,
+				 generation, ignore_missing_commits, &bases))
+		ret = -1;
+	else if (commit->object.flags & PARENT2)
+		ret = 1;
+	clear_commit_marks(commit, all_flags);
+	clear_commit_marks_many(nr_reference, reference, all_flags);
+	free_commit_list(bases);
+	return ret;
+}
+
+/*
+ * Is "commit" an ancestor of (i.e. reachable from) the "reference"?
+ */
+int repo_in_merge_bases(struct repository *r,
+			struct commit *commit,
+			struct commit *reference)
+{
+	int res;
+	struct commit_list *list = NULL;
+	struct commit_list **next = &list;
+
+	next = commit_list_append(commit, next);
+	res = repo_is_descendant_of(r, reference, list);
+	free_commit_list(list);
+
+	return res;
+}
+
+struct commit_list *reduce_heads(struct commit_list *heads)
+{
+	struct commit_list *p;
+	struct commit_list *result = NULL, **tail = &result;
+	struct commit **array;
+	size_t num_head, i;
+	int ret;
+
+	if (!heads)
+		return NULL;
+
+	/* Uniquify */
+	for (p = heads; p; p = p->next)
+		p->item->object.flags &= ~STALE;
+	for (p = heads, num_head = 0; p; p = p->next) {
+		if (p->item->object.flags & STALE)
+			continue;
+		p->item->object.flags |= STALE;
+		num_head++;
+	}
+	CALLOC_ARRAY(array, num_head);
+	for (p = heads, i = 0; p; p = p->next) {
+		if (p->item->object.flags & STALE) {
+			array[i++] = p->item;
+			p->item->object.flags &= ~STALE;
+		}
+	}
+
+	ret = remove_redundant(the_repository, array, num_head, &num_head);
+	if (ret < 0) {
+		free(array);
+		return NULL;
+	}
+
+	for (i = 0; i < num_head; i++)
+		tail = &commit_list_insert(array[i], tail)->next;
+	free(array);
+	return result;
+}
+
+void reduce_heads_replace(struct commit_list **heads)
+{
+	struct commit_list *result = reduce_heads(*heads);
+	free_commit_list(*heads);
+	*heads = result;
+}
+
+int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid)
+{
+	struct object *o;
+	struct commit *old_commit, *new_commit;
+	struct commit_list *old_commit_list = NULL;
+	int ret;
+
+	/*
+	 * Both new_commit and old_commit must be commit-ish and new_commit is descendant of
+	 * old_commit.  Otherwise we require --force.
+	 */
+	o = deref_tag(the_repository, parse_object(the_repository, old_oid),
+		      NULL, 0);
+	if (!o || o->type != OBJ_COMMIT)
+		return 0;
+	old_commit = (struct commit *) o;
+
+	o = deref_tag(the_repository, parse_object(the_repository, new_oid),
+		      NULL, 0);
+	if (!o || o->type != OBJ_COMMIT)
+		return 0;
+	new_commit = (struct commit *) o;
+
+	if (repo_parse_commit(the_repository, new_commit) < 0)
+		return 0;
+
+	commit_list_insert(old_commit, &old_commit_list);
+	ret = repo_is_descendant_of(the_repository,
+				    new_commit, old_commit_list);
+	if (ret < 0)
+		exit(128);
+	free_commit_list(old_commit_list);
+	return ret;
+}
+
+/*
+ * Mimicking the real stack, this stack lives on the heap, avoiding stack
+ * overflows.
+ *
+ * At each recursion step, the stack items points to the commits whose
+ * ancestors are to be inspected.
+ */
+struct contains_stack {
+	int nr, alloc;
+	struct contains_stack_entry {
+		struct commit *commit;
+		struct commit_list *parents;
+	} *contains_stack;
+};
+
+static int in_commit_list(const struct commit_list *want, struct commit *c)
+{
+	for (; want; want = want->next)
+		if (oideq(&want->item->object.oid, &c->object.oid))
+			return 1;
+	return 0;
+}
+
+/*
+ * Test whether the candidate is contained in the list.
+ * Do not recurse to find out, though, but return -1 if inconclusive.
+ */
+static enum contains_result contains_test(struct commit *candidate,
+					  const struct commit_list *want,
+					  struct contains_cache *cache,
+					  timestamp_t cutoff)
+{
+	enum contains_result *cached = contains_cache_at(cache, candidate);
+
+	/* If we already have the answer cached, return that. */
+	if (*cached)
+		return *cached;
+
+	/* or are we it? */
+	if (in_commit_list(want, candidate)) {
+		*cached = CONTAINS_YES;
+		return CONTAINS_YES;
+	}
+
+	/* Otherwise, we don't know; prepare to recurse */
+	parse_commit_or_die(candidate);
+
+	if (commit_graph_generation(candidate) < cutoff)
+		return CONTAINS_NO;
+
+	return CONTAINS_UNKNOWN;
+}
+
+static void push_to_contains_stack(struct commit *candidate, struct contains_stack *contains_stack)
+{
+	ALLOC_GROW(contains_stack->contains_stack, contains_stack->nr + 1, contains_stack->alloc);
+	contains_stack->contains_stack[contains_stack->nr].commit = candidate;
+	contains_stack->contains_stack[contains_stack->nr++].parents = candidate->parents;
+}
+
+static enum contains_result contains_tag_algo(struct commit *candidate,
+					      const struct commit_list *want,
+					      struct contains_cache *cache)
+{
+	struct contains_stack contains_stack = { 0, 0, NULL };
+	enum contains_result result;
+	timestamp_t cutoff = GENERATION_NUMBER_INFINITY;
+	const struct commit_list *p;
+
+	for (p = want; p; p = p->next) {
+		timestamp_t generation;
+		struct commit *c = p->item;
+		load_commit_graph_info(the_repository, c);
+		generation = commit_graph_generation(c);
+		if (generation < cutoff)
+			cutoff = generation;
+	}
+
+	result = contains_test(candidate, want, cache, cutoff);
+	if (result != CONTAINS_UNKNOWN)
+		return result;
+
+	push_to_contains_stack(candidate, &contains_stack);
+	while (contains_stack.nr) {
+		struct contains_stack_entry *entry = &contains_stack.contains_stack[contains_stack.nr - 1];
+		struct commit *commit = entry->commit;
+		struct commit_list *parents = entry->parents;
+
+		if (!parents) {
+			*contains_cache_at(cache, commit) = CONTAINS_NO;
+			contains_stack.nr--;
+		}
+		/*
+		 * If we just popped the stack, parents->item has been marked,
+		 * therefore contains_test will return a meaningful yes/no.
+		 */
+		else switch (contains_test(parents->item, want, cache, cutoff)) {
+		case CONTAINS_YES:
+			*contains_cache_at(cache, commit) = CONTAINS_YES;
+			contains_stack.nr--;
+			break;
+		case CONTAINS_NO:
+			entry->parents = parents->next;
+			break;
+		case CONTAINS_UNKNOWN:
+			push_to_contains_stack(parents->item, &contains_stack);
+			break;
+		}
+	}
+	free(contains_stack.contains_stack);
+	return contains_test(candidate, want, cache, cutoff);
+}
+
+int commit_contains(struct ref_filter *filter, struct commit *commit,
+		    struct commit_list *list, struct contains_cache *cache)
+{
+	if (filter->with_commit_tag_algo)
+		return contains_tag_algo(commit, list, cache) == CONTAINS_YES;
+	return repo_is_descendant_of(the_repository, commit, list);
+}
+
+int can_all_from_reach_with_flag(struct object_array *from,
+				 unsigned int with_flag,
+				 unsigned int assign_flag,
+				 timestamp_t min_commit_date,
+				 timestamp_t min_generation)
+{
+	struct commit **list = NULL;
+	size_t i;
+	size_t nr_commits;
+	int result = 1;
+
+	ALLOC_ARRAY(list, from->nr);
+	nr_commits = 0;
+	for (i = 0; i < from->nr; i++) {
+		struct object *from_one = from->objects[i].item;
+
+		if (!from_one || from_one->flags & assign_flag)
+			continue;
+
+		from_one = deref_tag(the_repository, from_one,
+				     "a from object", 0);
+		if (!from_one || from_one->type != OBJ_COMMIT) {
+			/*
+			 * no way to tell if this is reachable by
+			 * looking at the ancestry chain alone, so
+			 * leave a note to ourselves not to worry about
+			 * this object anymore.
+			 */
+			from->objects[i].item->flags |= assign_flag;
+			continue;
+		}
+
+		list[nr_commits] = (struct commit *)from_one;
+		if (repo_parse_commit(the_repository, list[nr_commits]) ||
+		    commit_graph_generation(list[nr_commits]) < min_generation) {
+			result = 0;
+			goto cleanup;
+		}
+
+		nr_commits++;
+	}
+
+	QSORT(list, nr_commits, compare_commits_by_gen);
+
+	for (i = 0; i < nr_commits; i++) {
+		/* DFS from list[i] */
+		struct commit_list *stack = NULL;
+
+		list[i]->object.flags |= assign_flag;
+		commit_list_insert(list[i], &stack);
+
+		while (stack) {
+			struct commit_list *parent;
+
+			if (stack->item->object.flags & (with_flag | RESULT)) {
+				pop_commit(&stack);
+				if (stack)
+					stack->item->object.flags |= RESULT;
+				continue;
+			}
+
+			for (parent = stack->item->parents; parent; parent = parent->next) {
+				if (parent->item->object.flags & (with_flag | RESULT))
+					stack->item->object.flags |= RESULT;
+
+				if (!(parent->item->object.flags & assign_flag)) {
+					parent->item->object.flags |= assign_flag;
+
+					if (repo_parse_commit(the_repository, parent->item) ||
+					    parent->item->date < min_commit_date ||
+					    commit_graph_generation(parent->item) < min_generation)
+						continue;
+
+					commit_list_insert(parent->item, &stack);
+					break;
+				}
+			}
+
+			if (!parent)
+				pop_commit(&stack);
+		}
+
+		if (!(list[i]->object.flags & (with_flag | RESULT))) {
+			result = 0;
+			goto cleanup;
+		}
+	}
+
+cleanup:
+	clear_commit_marks_many(nr_commits, list, RESULT | assign_flag);
+	free(list);
+
+	for (i = 0; i < from->nr; i++) {
+		struct object *from_one = from->objects[i].item;
+
+		if (from_one)
+			from_one->flags &= ~assign_flag;
+	}
+
+	return result;
+}
+
+int can_all_from_reach(struct commit_list *from, struct commit_list *to,
+		       int cutoff_by_min_date)
+{
+	struct object_array from_objs = OBJECT_ARRAY_INIT;
+	struct commit_list *from_iter = from, *to_iter = to;
+	int result;
+	timestamp_t min_commit_date = cutoff_by_min_date ? from->item->date : 0;
+	timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
+
+	while (from_iter) {
+		add_object_array(&from_iter->item->object, NULL, &from_objs);
+
+		if (!repo_parse_commit(the_repository, from_iter->item)) {
+			timestamp_t generation;
+			if (from_iter->item->date < min_commit_date)
+				min_commit_date = from_iter->item->date;
+
+			generation = commit_graph_generation(from_iter->item);
+			if (generation < min_generation)
+				min_generation = generation;
+		}
+
+		from_iter = from_iter->next;
+	}
+
+	while (to_iter) {
+		if (!repo_parse_commit(the_repository, to_iter->item)) {
+			timestamp_t generation;
+			if (to_iter->item->date < min_commit_date)
+				min_commit_date = to_iter->item->date;
+
+			generation = commit_graph_generation(to_iter->item);
+			if (generation < min_generation)
+				min_generation = generation;
+		}
+
+		to_iter->item->object.flags |= PARENT2;
+
+		to_iter = to_iter->next;
+	}
+
+	result = can_all_from_reach_with_flag(&from_objs, PARENT2, PARENT1,
+					      min_commit_date, min_generation);
+
+	while (from) {
+		clear_commit_marks(from->item, PARENT1);
+		from = from->next;
+	}
+
+	while (to) {
+		clear_commit_marks(to->item, PARENT2);
+		to = to->next;
+	}
+
+	object_array_clear(&from_objs);
+	return result;
+}
+
+struct commit_list *get_reachable_subset(struct commit **from, size_t nr_from,
+					 struct commit **to, size_t nr_to,
+					 unsigned int reachable_flag)
+{
+	struct commit **item;
+	struct commit *current;
+	struct commit_list *found_commits = NULL;
+	struct commit **to_last = to + nr_to;
+	struct commit **from_last = from + nr_from;
+	timestamp_t min_generation = GENERATION_NUMBER_INFINITY;
+	int num_to_find = 0;
+
+	struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
+
+	for (item = to; item < to_last; item++) {
+		timestamp_t generation;
+		struct commit *c = *item;
+
+		repo_parse_commit(the_repository, c);
+		generation = commit_graph_generation(c);
+		if (generation < min_generation)
+			min_generation = generation;
+
+		if (!(c->object.flags & PARENT1)) {
+			c->object.flags |= PARENT1;
+			num_to_find++;
+		}
+	}
+
+	for (item = from; item < from_last; item++) {
+		struct commit *c = *item;
+		if (!(c->object.flags & PARENT2)) {
+			c->object.flags |= PARENT2;
+			repo_parse_commit(the_repository, c);
+
+			prio_queue_put(&queue, *item);
+		}
+	}
+
+	while (num_to_find && (current = prio_queue_get(&queue)) != NULL) {
+		struct commit_list *parents;
+
+		if (current->object.flags & PARENT1) {
+			current->object.flags &= ~PARENT1;
+			current->object.flags |= reachable_flag;
+			commit_list_insert(current, &found_commits);
+			num_to_find--;
+		}
+
+		for (parents = current->parents; parents; parents = parents->next) {
+			struct commit *p = parents->item;
+
+			repo_parse_commit(the_repository, p);
+
+			if (commit_graph_generation(p) < min_generation)
+				continue;
+
+			if (p->object.flags & PARENT2)
+				continue;
+
+			p->object.flags |= PARENT2;
+			prio_queue_put(&queue, p);
+		}
+	}
+
+	clear_prio_queue(&queue);
+
+	clear_commit_marks_many(nr_to, to, PARENT1);
+	clear_commit_marks_many(nr_from, from, PARENT2);
+
+	return found_commits;
+}
+
+define_commit_slab(bit_arrays, struct bitmap *);
+static struct bit_arrays bit_arrays;
+
+static void insert_no_dup(struct prio_queue *queue, struct commit *c)
+{
+	if (c->object.flags & PARENT2)
+		return;
+	prio_queue_put(queue, c);
+	c->object.flags |= PARENT2;
+}
+
+static struct bitmap *get_bit_array(struct commit *c, int width)
+{
+	struct bitmap **bitmap = bit_arrays_at(&bit_arrays, c);
+	if (!*bitmap)
+		*bitmap = bitmap_word_alloc(width);
+	return *bitmap;
+}
+
+static void free_bit_array(struct commit *c)
+{
+	struct bitmap **bitmap = bit_arrays_at(&bit_arrays, c);
+	if (!*bitmap)
+		return;
+	bitmap_free(*bitmap);
+	*bitmap = NULL;
+}
+
+void ahead_behind(struct repository *r,
+		  struct commit **commits, size_t commits_nr,
+		  struct ahead_behind_count *counts, size_t counts_nr)
+{
+	struct prio_queue queue = { .compare = compare_commits_by_gen_then_commit_date };
+	size_t width = DIV_ROUND_UP(commits_nr, BITS_IN_EWORD);
+
+	if (!commits_nr || !counts_nr)
+		return;
+
+	for (size_t i = 0; i < counts_nr; i++) {
+		counts[i].ahead = 0;
+		counts[i].behind = 0;
+	}
+
+	ensure_generations_valid(r, commits, commits_nr);
+
+	init_bit_arrays(&bit_arrays);
+
+	for (size_t i = 0; i < commits_nr; i++) {
+		struct commit *c = commits[i];
+		struct bitmap *bitmap = get_bit_array(c, width);
+
+		bitmap_set(bitmap, i);
+		insert_no_dup(&queue, c);
+	}
+
+	while (queue_has_nonstale(&queue)) {
+		struct commit *c = prio_queue_get(&queue);
+		struct commit_list *p;
+		struct bitmap *bitmap_c = get_bit_array(c, width);
+
+		for (size_t i = 0; i < counts_nr; i++) {
+			int reach_from_tip = !!bitmap_get(bitmap_c, counts[i].tip_index);
+			int reach_from_base = !!bitmap_get(bitmap_c, counts[i].base_index);
+
+			if (reach_from_tip ^ reach_from_base) {
+				if (reach_from_base)
+					counts[i].behind++;
+				else
+					counts[i].ahead++;
+			}
+		}
+
+		for (p = c->parents; p; p = p->next) {
+			struct bitmap *bitmap_p;
+
+			repo_parse_commit(r, p->item);
+
+			bitmap_p = get_bit_array(p->item, width);
+			bitmap_or(bitmap_p, bitmap_c);
+
+			/*
+			 * If this parent is reachable from every starting
+			 * commit, then none of its ancestors can contribute
+			 * to the ahead/behind count. Mark it as STALE, so
+			 * we can stop the walk when every commit in the
+			 * queue is STALE.
+			 */
+			if (bitmap_popcount(bitmap_p) == commits_nr)
+				p->item->object.flags |= STALE;
+
+			insert_no_dup(&queue, p->item);
+		}
+
+		free_bit_array(c);
+	}
+
+	/* STALE is used here, PARENT2 is used by insert_no_dup(). */
+	repo_clear_commit_marks(r, PARENT2 | STALE);
+	while (prio_queue_peek(&queue)) {
+		struct commit *c = prio_queue_get(&queue);
+		free_bit_array(c);
+	}
+	clear_bit_arrays(&bit_arrays);
+	clear_prio_queue(&queue);
+}
+
+struct commit_and_index {
+	struct commit *commit;
+	unsigned int index;
+	timestamp_t generation;
+};
+
+static int compare_commit_and_index_by_generation(const void *va, const void *vb)
+{
+	const struct commit_and_index *a = (const struct commit_and_index *)va;
+	const struct commit_and_index *b = (const struct commit_and_index *)vb;
+
+	if (a->generation > b->generation)
+		return 1;
+	if (a->generation < b->generation)
+		return -1;
+	return 0;
+}
+
+void tips_reachable_from_bases(struct repository *r,
+			       struct commit_list *bases,
+			       struct commit **tips, size_t tips_nr,
+			       int mark)
+{
+	struct commit_and_index *commits;
+	size_t min_generation_index = 0;
+	timestamp_t min_generation;
+	struct commit_list *stack = NULL;
+
+	if (!bases || !tips || !tips_nr)
+		return;
+
+	/*
+	 * Do a depth-first search starting at 'bases' to search for the
+	 * tips. Stop at the lowest (un-found) generation number. When
+	 * finding the lowest commit, increase the minimum generation
+	 * number to the next lowest (un-found) generation number.
+	 */
+
+	CALLOC_ARRAY(commits, tips_nr);
+
+	for (size_t i = 0; i < tips_nr; i++) {
+		commits[i].commit = tips[i];
+		commits[i].index = i;
+		commits[i].generation = commit_graph_generation(tips[i]);
+	}
+
+	/* Sort with generation number ascending. */
+	QSORT(commits, tips_nr, compare_commit_and_index_by_generation);
+	min_generation = commits[0].generation;
+
+	while (bases) {
+		repo_parse_commit(r, bases->item);
+		commit_list_insert(bases->item, &stack);
+		bases = bases->next;
+	}
+
+	while (stack) {
+		int explored_all_parents = 1;
+		struct commit_list *p;
+		struct commit *c = stack->item;
+		timestamp_t c_gen = commit_graph_generation(c);
+
+		/* Does it match any of our tips? */
+		for (size_t j = min_generation_index; j < tips_nr; j++) {
+			if (c_gen < commits[j].generation)
+				break;
+
+			if (commits[j].commit == c) {
+				tips[commits[j].index]->object.flags |= mark;
+
+				if (j == min_generation_index) {
+					unsigned int k = j + 1;
+					while (k < tips_nr &&
+					       (tips[commits[k].index]->object.flags & mark))
+						k++;
+
+					/* Terminate early if all found. */
+					if (k >= tips_nr)
+						goto done;
+
+					min_generation_index = k;
+					min_generation = commits[k].generation;
+				}
+			}
+		}
+
+		for (p = c->parents; p; p = p->next) {
+			repo_parse_commit(r, p->item);
+
+			/* Have we already explored this parent? */
+			if (p->item->object.flags & SEEN)
+				continue;
+
+			/* Is it below the current minimum generation? */
+			if (commit_graph_generation(p->item) < min_generation)
+				continue;
+
+			/* Ok, we will explore from here on. */
+			p->item->object.flags |= SEEN;
+			explored_all_parents = 0;
+			commit_list_insert(p->item, &stack);
+			break;
+		}
+
+		if (explored_all_parents)
+			pop_commit(&stack);
+	}
+
+done:
+	free(commits);
+	repo_clear_commit_marks(r, SEEN);
+	free_commit_list(stack);
+}
+
+/*
+ * This slab initializes integers to zero, so use "-1" for "tip is best" and
+ * "i + 1" for "bases[i] is best".
+ */
+define_commit_slab(best_branch_base, int);
+static struct best_branch_base best_branch_base;
+#define get_best(c) (*best_branch_base_at(&best_branch_base, (c)))
+#define set_best(c,v) (*best_branch_base_at(&best_branch_base, (c)) = (v))
+
+int get_branch_base_for_tip(struct repository *r,
+			    struct commit *tip,
+			    struct commit **bases,
+			    size_t bases_nr)
+{
+	int best_index = -1;
+	struct commit *branch_point = NULL;
+	struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
+	int found_missing_gen = 0;
+
+	if (!bases_nr)
+		return -1;
+
+	repo_parse_commit(r, tip);
+	if (commit_graph_generation(tip) == GENERATION_NUMBER_INFINITY)
+		found_missing_gen = 1;
+
+	/* Check for missing generation numbers. */
+	for (size_t i = 0; i < bases_nr; i++) {
+		struct commit *c = bases[i];
+		repo_parse_commit(r, c);
+		if (commit_graph_generation(c) == GENERATION_NUMBER_INFINITY)
+			found_missing_gen = 1;
+	}
+
+	if (found_missing_gen) {
+		struct commit **commits;
+		size_t commits_nr = bases_nr + 1;
+
+		CALLOC_ARRAY(commits, commits_nr);
+		COPY_ARRAY(commits, bases, bases_nr);
+		commits[bases_nr] = tip;
+		ensure_generations_valid(r, commits, commits_nr);
+		free(commits);
+	}
+
+	/* Initialize queue and slab now that generations are guaranteed. */
+	init_best_branch_base(&best_branch_base);
+	set_best(tip, -1);
+	prio_queue_put(&queue, tip);
+
+	for (size_t i = 0; i < bases_nr; i++) {
+		struct commit *c = bases[i];
+		int best = get_best(c);
+
+		/* Has this already been marked as best by another commit? */
+		if (best) {
+			if (best == -1) {
+				/* We agree at this position. Stop now. */
+				best_index = i + 1;
+				goto cleanup;
+			}
+			continue;
+		}
+
+		set_best(c, i + 1);
+		prio_queue_put(&queue, c);
+	}
+
+	while (queue.nr) {
+		struct commit *c = prio_queue_get(&queue);
+		int best_for_c = get_best(c);
+		int best_for_p, positive;
+		struct commit *parent;
+
+		/* Have we reached a known branch point? It's optimal. */
+		if (c == branch_point)
+			break;
+
+		repo_parse_commit(r, c);
+		if (!c->parents)
+			continue;
+
+		parent = c->parents->item;
+		repo_parse_commit(r, parent);
+		best_for_p = get_best(parent);
+
+		if (!best_for_p) {
+			/* 'parent' is new, so pass along best_for_c. */
+			set_best(parent, best_for_c);
+			prio_queue_put(&queue, parent);
+			continue;
+		}
+
+		if (best_for_p > 0 && best_for_c > 0) {
+			/* Collision among bases. Minimize. */
+			if (best_for_c < best_for_p)
+				set_best(parent, best_for_c);
+			continue;
+		}
+
+		/*
+		 * At this point, we have reached a commit that is reachable
+		 * from the tip, either from 'c' or from an earlier commit to
+		 * have 'parent' as its first parent.
+		 *
+		 * Update 'best_index' to match the minimum of all base indices
+		 * to reach 'parent'.
+		 */
+
+		/* Exactly one is positive due to initial conditions. */
+		positive = (best_for_c < 0) ? best_for_p : best_for_c;
+
+		if (best_index < 0 || positive < best_index)
+			best_index = positive;
+
+		/* No matter what, track that the parent is reachable from tip. */
+		set_best(parent, -1);
+		branch_point = parent;
+	}
+
+cleanup:
+	clear_best_branch_base(&best_branch_base);
+	clear_prio_queue(&queue);
+	return best_index > 0 ? best_index - 1 : -1;
+}
diff --git a/commit-reach.h b/commit-reach.h
new file mode 100644
index 0000000000..6012402dfc
--- /dev/null
+++ b/commit-reach.h
@@ -0,0 +1,159 @@
+#ifndef COMMIT_REACH_H
+#define COMMIT_REACH_H
+
+#include "commit.h"
+#include "commit-slab.h"
+
+struct commit_list;
+struct ref_filter;
+struct object_id;
+struct object_array;
+
+int repo_get_merge_bases(struct repository *r,
+			 struct commit *rev1,
+			 struct commit *rev2,
+			 struct commit_list **result);
+int repo_get_merge_bases_many(struct repository *r,
+			      struct commit *one, size_t n,
+			      struct commit **twos,
+			      struct commit_list **result);
+/* To be used only when object flags after this call no longer matter */
+int repo_get_merge_bases_many_dirty(struct repository *r,
+				    struct commit *one, size_t n,
+				    struct commit **twos,
+				    struct commit_list **result);
+
+int get_octopus_merge_bases(struct commit_list *in, struct commit_list **result);
+
+int repo_is_descendant_of(struct repository *r,
+			  struct commit *commit,
+			  struct commit_list *with_commit);
+int repo_in_merge_bases(struct repository *r,
+			struct commit *commit,
+			struct commit *reference);
+int repo_in_merge_bases_many(struct repository *r,
+			     struct commit *commit,
+			     int nr_reference, struct commit **reference,
+			     int ignore_missing_commits);
+
+/*
+ * Takes a list of commits and returns a new list where those
+ * have been removed that can be reached from other commits in
+ * the list. It is useful for, e.g., reducing the commits
+ * randomly thrown at the git-merge command and removing
+ * redundant commits that the user shouldn't have given to it.
+ *
+ * This function destroys the STALE bit of the commit objects'
+ * flags.
+ */
+struct commit_list *reduce_heads(struct commit_list *heads);
+
+/*
+ * Like `reduce_heads()`, except it replaces the list. Use this
+ * instead of `foo = reduce_heads(foo);` to avoid memory leaks.
+ */
+void reduce_heads_replace(struct commit_list **heads);
+
+int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
+
+/*
+ * Unknown has to be "0" here, because that's the default value for
+ * contains_cache slab entries that have not yet been assigned.
+ */
+enum contains_result {
+	CONTAINS_UNKNOWN = 0,
+	CONTAINS_NO,
+	CONTAINS_YES
+};
+
+define_commit_slab(contains_cache, enum contains_result);
+
+int commit_contains(struct ref_filter *filter, struct commit *commit,
+		    struct commit_list *list, struct contains_cache *cache);
+
+/*
+ * Determine if every commit in 'from' can reach at least one commit
+ * that is marked with 'with_flag'. As we traverse, use 'assign_flag'
+ * as a marker for commits that are already visited. Do not walk
+ * commits with date below 'min_commit_date' or generation below
+ * 'min_generation'.
+ */
+int can_all_from_reach_with_flag(struct object_array *from,
+				 unsigned int with_flag,
+				 unsigned int assign_flag,
+				 timestamp_t min_commit_date,
+				 timestamp_t min_generation);
+int can_all_from_reach(struct commit_list *from, struct commit_list *to,
+		       int commit_date_cutoff);
+
+
+/*
+ * Return a list of commits containing the commits in the 'to' array
+ * that are reachable from at least one commit in the 'from' array.
+ * Also add the given 'flag' to each of the commits in the returned list.
+ *
+ * This method uses the PARENT1 and PARENT2 flags during its operation,
+ * so be sure these flags are not set before calling the method.
+ */
+struct commit_list *get_reachable_subset(struct commit **from, size_t nr_from,
+					 struct commit **to, size_t nr_to,
+					 unsigned int reachable_flag);
+
+struct ahead_behind_count {
+	/**
+	 * As input, the *_index members indicate which positions in
+	 * the 'tips' array correspond to the tip and base of this
+	 * comparison.
+	 */
+	size_t tip_index;
+	size_t base_index;
+
+	/**
+	 * These values store the computed counts for each side of the
+	 * symmetric difference:
+	 *
+	 * 'ahead' stores the number of commits reachable from the tip
+	 * and not reachable from the base.
+	 *
+	 * 'behind' stores the number of commits reachable from the base
+	 * and not reachable from the tip.
+	 */
+	unsigned int ahead;
+	unsigned int behind;
+};
+
+/*
+ * Given an array of commits and an array of ahead_behind_count pairs,
+ * compute the ahead/behind counts for each pair.
+ */
+void ahead_behind(struct repository *r,
+		  struct commit **commits, size_t commits_nr,
+		  struct ahead_behind_count *counts, size_t counts_nr);
+
+/*
+ * For all tip commits, add 'mark' to their flags if and only if they
+ * are reachable from one of the commits in 'bases'.
+ */
+void tips_reachable_from_bases(struct repository *r,
+			       struct commit_list *bases,
+			       struct commit **tips, size_t tips_nr,
+			       int mark);
+
+/*
+ * Given a 'tip' commit and a list potential 'bases', return the index 'i' that
+ * minimizes the number of commits in the first-parent history of 'tip' and not
+ * in the first-parent history of 'bases[i]'.
+ *
+ * Among a list of long-lived branches that are updated only by merges (with the
+ * first parent being the previous position of the branch), this would inform
+ * which branch was used to create the tip reference.
+ *
+ * Returns -1 if no common point is found in first-parent histories, which is
+ * rare, but possible with multiple root commits.
+ */
+int get_branch_base_for_tip(struct repository *r,
+			    struct commit *tip,
+			    struct commit **bases,
+			    size_t bases_nr);
+
+#endif
diff --git a/commit-slab-decl.h b/commit-slab-decl.h
new file mode 100644
index 0000000000..98de2c970c
--- /dev/null
+++ b/commit-slab-decl.h
@@ -0,0 +1,44 @@
+#ifndef COMMIT_SLAB_DECL_H
+#define COMMIT_SLAB_DECL_H
+
+/* allocate ~512kB at once, allowing for malloc overhead */
+#ifndef COMMIT_SLAB_SIZE
+#define COMMIT_SLAB_SIZE (512*1024-32)
+#endif
+
+#define declare_commit_slab(slabname, elemtype) 			\
+									\
+struct slabname {							\
+	unsigned slab_size;						\
+	unsigned stride;						\
+	unsigned slab_count;						\
+	elemtype **slab;						\
+}
+
+/*
+ * Statically initialize a commit slab named "var". Note that this
+ * evaluates "stride" multiple times! Example:
+ *
+ *   struct indegree indegrees = COMMIT_SLAB_INIT(1, indegrees);
+ *
+ */
+#define COMMIT_SLAB_INIT(stride, var) { \
+	COMMIT_SLAB_SIZE / sizeof(**((var).slab)) / (stride), \
+	(stride), 0, NULL \
+}
+
+#define declare_commit_slab_prototypes(slabname, elemtype)		\
+									\
+void init_ ##slabname## _with_stride(struct slabname *s, unsigned stride); \
+void init_ ##slabname(struct slabname *s);				\
+void clear_ ##slabname(struct slabname *s);				\
+void deep_clear_ ##slabname(struct slabname *s, void (*free_fn)(elemtype *ptr)); \
+elemtype *slabname## _at_peek(struct slabname *s, const struct commit *c, int add_if_missing); \
+elemtype *slabname## _at(struct slabname *s, const struct commit *c);	\
+elemtype *slabname## _peek(struct slabname *s, const struct commit *c)
+
+#define define_shared_commit_slab(slabname, elemtype) \
+	declare_commit_slab(slabname, elemtype); \
+	declare_commit_slab_prototypes(slabname, elemtype)
+
+#endif /* COMMIT_SLAB_DECL_H */
diff --git a/commit-slab-impl.h b/commit-slab-impl.h
new file mode 100644
index 0000000000..4a414ee905
--- /dev/null
+++ b/commit-slab-impl.h
@@ -0,0 +1,105 @@
+#ifndef COMMIT_SLAB_IMPL_H
+#define COMMIT_SLAB_IMPL_H
+
+#define implement_static_commit_slab(slabname, elemtype) \
+	implement_commit_slab(slabname, elemtype, MAYBE_UNUSED static)
+
+#define implement_shared_commit_slab(slabname, elemtype) \
+	implement_commit_slab(slabname, elemtype, )
+
+#define implement_commit_slab(slabname, elemtype, scope)		\
+									\
+scope void init_ ##slabname## _with_stride(struct slabname *s,		\
+						   unsigned stride)	\
+{									\
+	unsigned int elem_size;						\
+	if (!stride)							\
+		stride = 1;						\
+	s->stride = stride;						\
+	elem_size = sizeof(elemtype) * stride;				\
+	s->slab_size = COMMIT_SLAB_SIZE / elem_size;			\
+	s->slab_count = 0;						\
+	s->slab = NULL;							\
+}									\
+									\
+scope void init_ ##slabname(struct slabname *s)				\
+{									\
+	init_ ##slabname## _with_stride(s, 1);				\
+}									\
+									\
+scope void clear_ ##slabname(struct slabname *s)			\
+{									\
+	unsigned int i;							\
+	for (i = 0; i < s->slab_count; i++)				\
+		free(s->slab[i]);					\
+	s->slab_count = 0;						\
+	FREE_AND_NULL(s->slab);						\
+}									\
+									\
+scope void deep_clear_ ##slabname(struct slabname *s, void (*free_fn)(elemtype *)) \
+{									\
+	unsigned int i;							\
+	for (i = 0; i < s->slab_count; i++) {				\
+		unsigned int j;						\
+		if (!s->slab[i])					\
+			continue;					\
+		for (j = 0; j < s->slab_size; j++)			\
+			free_fn(&s->slab[i][j * s->stride]);		\
+	}								\
+	clear_ ##slabname(s);						\
+}									\
+									\
+scope elemtype *slabname## _at_peek(struct slabname *s,			\
+						  const struct commit *c, \
+						  int add_if_missing)   \
+{									\
+	unsigned int nth_slab, nth_slot;				\
+									\
+	nth_slab = c->index / s->slab_size;				\
+	nth_slot = c->index % s->slab_size;				\
+									\
+	if (s->slab_count <= nth_slab) {				\
+		unsigned int i;						\
+		if (!add_if_missing)					\
+			return NULL;					\
+		REALLOC_ARRAY(s->slab, nth_slab + 1);			\
+		for (i = s->slab_count; i <= nth_slab; i++)		\
+			s->slab[i] = NULL;				\
+		s->slab_count = nth_slab + 1;				\
+	}								\
+	if (!s->slab[nth_slab]) {					\
+		if (!add_if_missing)					\
+			return NULL;					\
+		s->slab[nth_slab] = xcalloc(s->slab_size,		\
+					    sizeof(**s->slab) * s->stride);		\
+	}								\
+	return &s->slab[nth_slab][nth_slot * s->stride];		\
+}									\
+									\
+scope elemtype *slabname## _at(struct slabname *s,			\
+					     const struct commit *c)	\
+{									\
+	return slabname##_at_peek(s, c, 1);				\
+}									\
+									\
+scope elemtype *slabname## _peek(struct slabname *s,			\
+					     const struct commit *c)	\
+{									\
+	return slabname##_at_peek(s, c, 0);				\
+}									\
+									\
+struct slabname
+
+/*
+ * Note that this redundant forward declaration is required
+ * to allow a terminating semicolon, which makes instantiations look
+ * like function declarations.  I.e., the expansion of
+ *
+ *    implement_commit_slab(indegree, int, static);
+ *
+ * ends in 'struct indegree;'.  This would otherwise
+ * be a syntax error according (at least) to ISO C.  It's hard to
+ * catch because GCC silently parses it by default.
+ */
+
+#endif	/* COMMIT_SLAB_IMPL_H */
diff --git a/commit-slab.h b/commit-slab.h
new file mode 100644
index 0000000000..8e72a30536
--- /dev/null
+++ b/commit-slab.h
@@ -0,0 +1,66 @@
+#ifndef COMMIT_SLAB_H
+#define COMMIT_SLAB_H
+
+#include "commit-slab-decl.h"
+#include "commit-slab-impl.h"
+
+/*
+ * define_commit_slab(slabname, elemtype) creates boilerplate code to define
+ * a new struct (struct slabname) that is used to associate a piece of data
+ * of elemtype to commits, and a few functions to use that struct.
+ *
+ * After including this header file, using:
+ *
+ * define_commit_slab(indegree, int);
+ *
+ * will let you call the following functions:
+ *
+ * - int *indegree_at(struct indegree *, struct commit *);
+ *
+ *   This function locates the data associated with the given commit in
+ *   the indegree slab, and returns the pointer to it.  The location to
+ *   store the data is allocated as necessary.
+ *
+ * - int *indegree_peek(struct indegree *, struct commit *);
+ *
+ *   This function is similar to indegree_at(), but it will return NULL
+ *   if the location to store the data associated with the given commit
+ *   has not been allocated yet.
+ *   Note that the location to store the data might have already been
+ *   allocated even if no indegree_at() call has been made for that commit
+ *   yet; in this case this function returns a pointer to a
+ *   zero-initialized location.
+ *
+ * - void init_indegree(struct indegree *);
+ *   void init_indegree_with_stride(struct indegree *, int);
+ *
+ *   Initializes the indegree slab that associates an array of integers
+ *   to each commit. 'stride' specifies how big each array is.  The slab
+ *   that is initialized by the variant without "_with_stride" associates
+ *   each commit with an array of one integer.
+ *
+ * - void clear_indegree(struct indegree *);
+ *
+ *   Empties the slab.  The slab can be reused with the same stride
+ *   without calling init_indegree() again or can be reconfigured to a
+ *   different stride by calling init_indegree_with_stride().
+ *
+ *   Call this function before the slab falls out of scope to avoid
+ *   leaking memory.
+ *
+ * - void deep_clear_indegree(struct indegree *, void (*free_fn)(int*))
+ *
+ *   Empties the slab, similar to clear_indegree(), but in addition it
+ *   calls the given 'free_fn' for each slab entry to release any
+ *   additional memory that might be owned by the entry (but not the
+ *   entry itself!).
+ *   Note that 'free_fn' might be called even for entries for which no
+ *   indegree_at() call has been made; in this case 'free_fn' is invoked
+ *   with a pointer to a zero-initialized location.
+ */
+
+#define define_commit_slab(slabname, elemtype) \
+	declare_commit_slab(slabname, elemtype); \
+	implement_static_commit_slab(slabname, elemtype)
+
+#endif /* COMMIT_SLAB_H */
diff --git a/commit.c b/commit.c
new file mode 100644
index 0000000000..540660359d
--- /dev/null
+++ b/commit.c
@@ -0,0 +1,1961 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "tag.h"
+#include "commit.h"
+#include "commit-graph.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hex.h"
+#include "repository.h"
+#include "object-name.h"
+#include "object-store-ll.h"
+#include "utf8.h"
+#include "diff.h"
+#include "revision.h"
+#include "notes.h"
+#include "alloc.h"
+#include "gpg-interface.h"
+#include "mergesort.h"
+#include "commit-slab.h"
+#include "prio-queue.h"
+#include "hash-lookup.h"
+#include "wt-status.h"
+#include "advice.h"
+#include "refs.h"
+#include "commit-reach.h"
+#include "setup.h"
+#include "shallow.h"
+#include "tree.h"
+#include "hook.h"
+#include "parse.h"
+#include "object-file-convert.h"
+
+static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
+
+int save_commit_buffer = 1;
+int no_graft_file_deprecated_advice;
+
+const char *commit_type = "commit";
+
+struct commit *lookup_commit_reference_gently(struct repository *r,
+		const struct object_id *oid, int quiet)
+{
+	struct object *obj = deref_tag(r,
+				       parse_object(r, oid),
+				       NULL, 0);
+
+	if (!obj)
+		return NULL;
+	return object_as_type(obj, OBJ_COMMIT, quiet);
+}
+
+struct commit *lookup_commit_reference(struct repository *r, const struct object_id *oid)
+{
+	return lookup_commit_reference_gently(r, oid, 0);
+}
+
+struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name)
+{
+	struct commit *c = lookup_commit_reference(the_repository, oid);
+	if (!c)
+		die(_("could not parse %s"), ref_name);
+	if (!oideq(oid, &c->object.oid)) {
+		warning(_("%s %s is not a commit!"),
+			ref_name, oid_to_hex(oid));
+	}
+	return c;
+}
+
+struct commit *lookup_commit_object(struct repository *r,
+				    const struct object_id *oid)
+{
+	struct object *obj = parse_object(r, oid);
+	return obj ? object_as_type(obj, OBJ_COMMIT, 0) : NULL;
+
+}
+
+struct commit *lookup_commit(struct repository *r, const struct object_id *oid)
+{
+	struct object *obj = lookup_object(r, oid);
+	if (!obj)
+		return create_object(r, oid, alloc_commit_node(r));
+	return object_as_type(obj, OBJ_COMMIT, 0);
+}
+
+struct commit *lookup_commit_reference_by_name(const char *name)
+{
+	return lookup_commit_reference_by_name_gently(name, 0);
+}
+
+struct commit *lookup_commit_reference_by_name_gently(const char *name,
+						      int quiet)
+{
+	struct object_id oid;
+	struct commit *commit;
+
+	if (repo_get_oid_committish(the_repository, name, &oid))
+		return NULL;
+	commit = lookup_commit_reference_gently(the_repository, &oid, quiet);
+	if (repo_parse_commit(the_repository, commit))
+		return NULL;
+	return commit;
+}
+
+static timestamp_t parse_commit_date(const char *buf, const char *tail)
+{
+	const char *dateptr;
+	const char *eol;
+
+	if (buf + 6 >= tail)
+		return 0;
+	if (memcmp(buf, "author", 6))
+		return 0;
+	while (buf < tail && *buf++ != '\n')
+		/* nada */;
+	if (buf + 9 >= tail)
+		return 0;
+	if (memcmp(buf, "committer", 9))
+		return 0;
+
+	/*
+	 * Jump to end-of-line so that we can walk backwards to find the
+	 * end-of-email ">". This is more forgiving of malformed cases
+	 * because unexpected characters tend to be in the name and email
+	 * fields.
+	 */
+	eol = memchr(buf, '\n', tail - buf);
+	if (!eol)
+		return 0;
+	dateptr = eol;
+	while (dateptr > buf && dateptr[-1] != '>')
+		dateptr--;
+	if (dateptr == buf)
+		return 0;
+
+	/*
+	 * Trim leading whitespace, but make sure we have at least one
+	 * non-whitespace character, as parse_timestamp() will otherwise walk
+	 * right past the newline we found in "eol" when skipping whitespace
+	 * itself.
+	 *
+	 * In theory it would be sufficient to allow any character not matched
+	 * by isspace(), but there's a catch: our isspace() does not
+	 * necessarily match the behavior of parse_timestamp(), as the latter
+	 * is implemented by system routines which match more exotic control
+	 * codes, or even locale-dependent sequences.
+	 *
+	 * Since we expect the timestamp to be a number, we can check for that.
+	 * Anything else (e.g., a non-numeric token like "foo") would just
+	 * cause parse_timestamp() to return 0 anyway.
+	 */
+	while (dateptr < eol && isspace(*dateptr))
+		dateptr++;
+	if (!isdigit(*dateptr) && *dateptr != '-')
+		return 0;
+
+	/*
+	 * We know there is at least one digit (or dash), so we'll begin
+	 * parsing there and stop at worst case at eol.
+	 *
+	 * Note that we may feed parse_timestamp() extra characters here if the
+	 * commit is malformed, and it will parse as far as it can. For
+	 * example, "123foo456" would return "123". That might be questionable
+	 * (versus returning "0"), but it would help in a hypothetical case
+	 * like "123456+0100", where the whitespace from the timezone is
+	 * missing. Since such syntactic errors may be baked into history and
+	 * hard to correct now, let's err on trying to make our best guess
+	 * here, rather than insist on perfect syntax.
+	 */
+	return parse_timestamp(dateptr, NULL, 10);
+}
+
+static const struct object_id *commit_graft_oid_access(size_t index, const void *table)
+{
+	const struct commit_graft * const *commit_graft_table = table;
+	return &commit_graft_table[index]->oid;
+}
+
+int commit_graft_pos(struct repository *r, const struct object_id *oid)
+{
+	return oid_pos(oid, r->parsed_objects->grafts,
+		       r->parsed_objects->grafts_nr,
+		       commit_graft_oid_access);
+}
+
+void unparse_commit(struct repository *r, const struct object_id *oid)
+{
+	struct commit *c = lookup_commit(r, oid);
+
+	if (!c->object.parsed)
+		return;
+	free_commit_list(c->parents);
+	c->parents = NULL;
+	c->object.parsed = 0;
+}
+
+int register_commit_graft(struct repository *r, struct commit_graft *graft,
+			  int ignore_dups)
+{
+	int pos = commit_graft_pos(r, &graft->oid);
+
+	if (0 <= pos) {
+		if (ignore_dups)
+			free(graft);
+		else {
+			free(r->parsed_objects->grafts[pos]);
+			r->parsed_objects->grafts[pos] = graft;
+		}
+		return 1;
+	}
+	pos = -pos - 1;
+	ALLOC_GROW(r->parsed_objects->grafts,
+		   r->parsed_objects->grafts_nr + 1,
+		   r->parsed_objects->grafts_alloc);
+	r->parsed_objects->grafts_nr++;
+	if (pos < r->parsed_objects->grafts_nr)
+		memmove(r->parsed_objects->grafts + pos + 1,
+			r->parsed_objects->grafts + pos,
+			(r->parsed_objects->grafts_nr - pos - 1) *
+			sizeof(*r->parsed_objects->grafts));
+	r->parsed_objects->grafts[pos] = graft;
+	unparse_commit(r, &graft->oid);
+	return 0;
+}
+
+struct commit_graft *read_graft_line(struct strbuf *line)
+{
+	/* The format is just "Commit Parent1 Parent2 ...\n" */
+	int i, phase;
+	const char *tail = NULL;
+	struct commit_graft *graft = NULL;
+	struct object_id dummy_oid, *oid;
+
+	strbuf_rtrim(line);
+	if (!line->len || line->buf[0] == '#')
+		return NULL;
+	/*
+	 * phase 0 verifies line, counts hashes in line and allocates graft
+	 * phase 1 fills graft
+	 */
+	for (phase = 0; phase < 2; phase++) {
+		oid = graft ? &graft->oid : &dummy_oid;
+		if (parse_oid_hex(line->buf, oid, &tail))
+			goto bad_graft_data;
+		for (i = 0; *tail != '\0'; i++) {
+			oid = graft ? &graft->parent[i] : &dummy_oid;
+			if (!isspace(*tail++) || parse_oid_hex(tail, oid, &tail))
+				goto bad_graft_data;
+		}
+		if (!graft) {
+			graft = xmalloc(st_add(sizeof(*graft),
+					       st_mult(sizeof(struct object_id), i)));
+			graft->nr_parent = i;
+		}
+	}
+	return graft;
+
+bad_graft_data:
+	error("bad graft data: %s", line->buf);
+	assert(!graft);
+	return NULL;
+}
+
+static int read_graft_file(struct repository *r, const char *graft_file)
+{
+	FILE *fp = fopen_or_warn(graft_file, "r");
+	struct strbuf buf = STRBUF_INIT;
+	if (!fp)
+		return -1;
+	if (!no_graft_file_deprecated_advice &&
+	    advice_enabled(ADVICE_GRAFT_FILE_DEPRECATED))
+		advise(_("Support for <GIT_DIR>/info/grafts is deprecated\n"
+			 "and will be removed in a future Git version.\n"
+			 "\n"
+			 "Please use \"git replace --convert-graft-file\"\n"
+			 "to convert the grafts into replace refs.\n"
+			 "\n"
+			 "Turn this message off by running\n"
+			 "\"git config set advice.graftFileDeprecated false\""));
+	while (!strbuf_getwholeline(&buf, fp, '\n')) {
+		/* The format is just "Commit Parent1 Parent2 ...\n" */
+		struct commit_graft *graft = read_graft_line(&buf);
+		if (!graft)
+			continue;
+		if (register_commit_graft(r, graft, 1))
+			error("duplicate graft data: %s", buf.buf);
+	}
+	fclose(fp);
+	strbuf_release(&buf);
+	return 0;
+}
+
+void prepare_commit_graft(struct repository *r)
+{
+	const char *graft_file;
+
+	if (r->parsed_objects->commit_graft_prepared)
+		return;
+	if (!startup_info->have_repository)
+		return;
+
+	graft_file = repo_get_graft_file(r);
+	read_graft_file(r, graft_file);
+	/* make sure shallows are read */
+	is_repository_shallow(r);
+	r->parsed_objects->commit_graft_prepared = 1;
+}
+
+struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid)
+{
+	int pos;
+	prepare_commit_graft(r);
+	pos = commit_graft_pos(r, oid);
+	if (pos < 0)
+		return NULL;
+	return r->parsed_objects->grafts[pos];
+}
+
+int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
+{
+	int i, ret;
+	for (i = ret = 0; i < the_repository->parsed_objects->grafts_nr && !ret; i++)
+		ret = fn(the_repository->parsed_objects->grafts[i], cb_data);
+	return ret;
+}
+
+struct commit_buffer {
+	void *buffer;
+	unsigned long size;
+};
+define_commit_slab(buffer_slab, struct commit_buffer);
+
+struct buffer_slab *allocate_commit_buffer_slab(void)
+{
+	struct buffer_slab *bs = xmalloc(sizeof(*bs));
+	init_buffer_slab(bs);
+	return bs;
+}
+
+void free_commit_buffer_slab(struct buffer_slab *bs)
+{
+	clear_buffer_slab(bs);
+	free(bs);
+}
+
+void set_commit_buffer(struct repository *r, struct commit *commit, void *buffer, unsigned long size)
+{
+	struct commit_buffer *v = buffer_slab_at(
+		r->parsed_objects->buffer_slab, commit);
+	v->buffer = buffer;
+	v->size = size;
+}
+
+const void *get_cached_commit_buffer(struct repository *r, const struct commit *commit, unsigned long *sizep)
+{
+	struct commit_buffer *v = buffer_slab_peek(
+		r->parsed_objects->buffer_slab, commit);
+	if (!v) {
+		if (sizep)
+			*sizep = 0;
+		return NULL;
+	}
+	if (sizep)
+		*sizep = v->size;
+	return v->buffer;
+}
+
+const void *repo_get_commit_buffer(struct repository *r,
+				   const struct commit *commit,
+				   unsigned long *sizep)
+{
+	const void *ret = get_cached_commit_buffer(r, commit, sizep);
+	if (!ret) {
+		enum object_type type;
+		unsigned long size;
+		ret = repo_read_object_file(r, &commit->object.oid, &type, &size);
+		if (!ret)
+			die("cannot read commit object %s",
+			    oid_to_hex(&commit->object.oid));
+		if (type != OBJ_COMMIT)
+			die("expected commit for %s, got %s",
+			    oid_to_hex(&commit->object.oid), type_name(type));
+		if (sizep)
+			*sizep = size;
+	}
+	return ret;
+}
+
+void repo_unuse_commit_buffer(struct repository *r,
+			      const struct commit *commit,
+			      const void *buffer)
+{
+	struct commit_buffer *v = buffer_slab_peek(
+		r->parsed_objects->buffer_slab, commit);
+	if (!(v && v->buffer == buffer))
+		free((void *)buffer);
+}
+
+void free_commit_buffer(struct parsed_object_pool *pool, struct commit *commit)
+{
+	struct commit_buffer *v = buffer_slab_peek(
+		pool->buffer_slab, commit);
+	if (v) {
+		FREE_AND_NULL(v->buffer);
+		v->size = 0;
+	}
+}
+
+static inline void set_commit_tree(struct commit *c, struct tree *t)
+{
+	c->maybe_tree = t;
+}
+
+struct tree *repo_get_commit_tree(struct repository *r,
+				  const struct commit *commit)
+{
+	if (commit->maybe_tree || !commit->object.parsed)
+		return commit->maybe_tree;
+
+	if (commit_graph_position(commit) != COMMIT_NOT_FROM_GRAPH)
+		return get_commit_tree_in_graph(r, commit);
+
+	return NULL;
+}
+
+struct object_id *get_commit_tree_oid(const struct commit *commit)
+{
+	struct tree *tree = repo_get_commit_tree(the_repository, commit);
+	return tree ? &tree->object.oid : NULL;
+}
+
+void release_commit_memory(struct parsed_object_pool *pool, struct commit *c)
+{
+	set_commit_tree(c, NULL);
+	free_commit_buffer(pool, c);
+	c->index = 0;
+	free_commit_list(c->parents);
+
+	c->object.parsed = 0;
+}
+
+const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
+{
+	struct commit_buffer *v = buffer_slab_peek(
+		the_repository->parsed_objects->buffer_slab, commit);
+	void *ret;
+
+	if (!v) {
+		if (sizep)
+			*sizep = 0;
+		return NULL;
+	}
+	ret = v->buffer;
+	if (sizep)
+		*sizep = v->size;
+
+	v->buffer = NULL;
+	v->size = 0;
+	return ret;
+}
+
+int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph)
+{
+	const char *tail = buffer;
+	const char *bufptr = buffer;
+	struct object_id parent;
+	struct commit_list **pptr;
+	struct commit_graft *graft;
+	const int tree_entry_len = the_hash_algo->hexsz + 5;
+	const int parent_entry_len = the_hash_algo->hexsz + 7;
+	struct tree *tree;
+
+	if (item->object.parsed)
+		return 0;
+	/*
+	 * Presumably this is leftover from an earlier failed parse;
+	 * clear it out in preparation for us re-parsing (we'll hit the
+	 * same error, but that's good, since it lets our caller know
+	 * the result cannot be trusted.
+	 */
+	free_commit_list(item->parents);
+	item->parents = NULL;
+
+	tail += size;
+	if (tail <= bufptr + tree_entry_len + 1 || memcmp(bufptr, "tree ", 5) ||
+			bufptr[tree_entry_len] != '\n')
+		return error("bogus commit object %s", oid_to_hex(&item->object.oid));
+	if (get_oid_hex(bufptr + 5, &parent) < 0)
+		return error("bad tree pointer in commit %s",
+			     oid_to_hex(&item->object.oid));
+	tree = lookup_tree(r, &parent);
+	if (!tree)
+		return error("bad tree pointer %s in commit %s",
+			     oid_to_hex(&parent),
+			     oid_to_hex(&item->object.oid));
+	set_commit_tree(item, tree);
+	bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
+	pptr = &item->parents;
+
+	graft = lookup_commit_graft(r, &item->object.oid);
+	if (graft)
+		r->parsed_objects->substituted_parent = 1;
+	while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
+		struct commit *new_parent;
+
+		if (tail <= bufptr + parent_entry_len + 1 ||
+		    get_oid_hex(bufptr + 7, &parent) ||
+		    bufptr[parent_entry_len] != '\n')
+			return error("bad parents in commit %s", oid_to_hex(&item->object.oid));
+		bufptr += parent_entry_len + 1;
+		/*
+		 * The clone is shallow if nr_parent < 0, and we must
+		 * not traverse its real parents even when we unhide them.
+		 */
+		if (graft && (graft->nr_parent < 0 || !grafts_keep_true_parents))
+			continue;
+		new_parent = lookup_commit(r, &parent);
+		if (!new_parent)
+			return error("bad parent %s in commit %s",
+				     oid_to_hex(&parent),
+				     oid_to_hex(&item->object.oid));
+		pptr = &commit_list_insert(new_parent, pptr)->next;
+	}
+	if (graft) {
+		int i;
+		struct commit *new_parent;
+		for (i = 0; i < graft->nr_parent; i++) {
+			new_parent = lookup_commit(r,
+						   &graft->parent[i]);
+			if (!new_parent)
+				return error("bad graft parent %s in commit %s",
+					     oid_to_hex(&graft->parent[i]),
+					     oid_to_hex(&item->object.oid));
+			pptr = &commit_list_insert(new_parent, pptr)->next;
+		}
+	}
+	item->date = parse_commit_date(bufptr, tail);
+
+	if (check_graph)
+		load_commit_graph_info(r, item);
+
+	item->object.parsed = 1;
+	return 0;
+}
+
+int repo_parse_commit_internal(struct repository *r,
+			       struct commit *item,
+			       int quiet_on_missing,
+			       int use_commit_graph)
+{
+	enum object_type type;
+	void *buffer;
+	unsigned long size;
+	struct object_info oi = {
+		.typep = &type,
+		.sizep = &size,
+		.contentp = &buffer,
+	};
+	/*
+	 * Git does not support partial clones that exclude commits, so set
+	 * OBJECT_INFO_SKIP_FETCH_OBJECT to fail fast when an object is missing.
+	 */
+	int flags = OBJECT_INFO_LOOKUP_REPLACE | OBJECT_INFO_SKIP_FETCH_OBJECT |
+		OBJECT_INFO_DIE_IF_CORRUPT;
+	int ret;
+
+	if (!item)
+		return -1;
+	if (item->object.parsed)
+		return 0;
+	if (use_commit_graph && parse_commit_in_graph(r, item)) {
+		static int commit_graph_paranoia = -1;
+
+		if (commit_graph_paranoia == -1)
+			commit_graph_paranoia = git_env_bool(GIT_COMMIT_GRAPH_PARANOIA, 0);
+
+		if (commit_graph_paranoia && !has_object(r, &item->object.oid, 0)) {
+			unparse_commit(r, &item->object.oid);
+			return quiet_on_missing ? -1 :
+				error(_("commit %s exists in commit-graph but not in the object database"),
+				      oid_to_hex(&item->object.oid));
+		}
+
+		return 0;
+	}
+
+	if (oid_object_info_extended(r, &item->object.oid, &oi, flags) < 0)
+		return quiet_on_missing ? -1 :
+			error("Could not read %s",
+			     oid_to_hex(&item->object.oid));
+	if (type != OBJ_COMMIT) {
+		free(buffer);
+		return error("Object %s not a commit",
+			     oid_to_hex(&item->object.oid));
+	}
+
+	ret = parse_commit_buffer(r, item, buffer, size, 0);
+	if (save_commit_buffer && !ret &&
+	    !get_cached_commit_buffer(r, item, NULL)) {
+		set_commit_buffer(r, item, buffer, size);
+		return 0;
+	}
+	free(buffer);
+	return ret;
+}
+
+int repo_parse_commit_gently(struct repository *r,
+			     struct commit *item, int quiet_on_missing)
+{
+	return repo_parse_commit_internal(r, item, quiet_on_missing, 1);
+}
+
+void parse_commit_or_die(struct commit *item)
+{
+	if (repo_parse_commit(the_repository, item))
+		die("unable to parse commit %s",
+		    item ? oid_to_hex(&item->object.oid) : "(null)");
+}
+
+int find_commit_subject(const char *commit_buffer, const char **subject)
+{
+	const char *eol;
+	const char *p = commit_buffer;
+
+	while (*p && (*p != '\n' || p[1] != '\n'))
+		p++;
+	if (*p) {
+		p = skip_blank_lines(p + 2);
+		eol = strchrnul(p, '\n');
+	} else
+		eol = p;
+
+	*subject = p;
+
+	return eol - p;
+}
+
+size_t commit_subject_length(const char *body)
+{
+	const char *p = body;
+	while (*p) {
+		const char *next = skip_blank_lines(p);
+		if (next != p)
+			break;
+		p = strchrnul(p, '\n');
+		if (*p)
+			p++;
+	}
+	return p - body;
+}
+
+struct commit_list *commit_list_insert(struct commit *item, struct commit_list **list_p)
+{
+	struct commit_list *new_list = xmalloc(sizeof(struct commit_list));
+	new_list->item = item;
+	new_list->next = *list_p;
+	*list_p = new_list;
+	return new_list;
+}
+
+int commit_list_contains(struct commit *item, struct commit_list *list)
+{
+	while (list) {
+		if (list->item == item)
+			return 1;
+		list = list->next;
+	}
+
+	return 0;
+}
+
+unsigned commit_list_count(const struct commit_list *l)
+{
+	unsigned c = 0;
+	for (; l; l = l->next )
+		c++;
+	return c;
+}
+
+struct commit_list *copy_commit_list(const struct commit_list *list)
+{
+	struct commit_list *head = NULL;
+	struct commit_list **pp = &head;
+	while (list) {
+		pp = commit_list_append(list->item, pp);
+		list = list->next;
+	}
+	return head;
+}
+
+struct commit_list *reverse_commit_list(struct commit_list *list)
+{
+	struct commit_list *next = NULL, *current, *backup;
+	for (current = list; current; current = backup) {
+		backup = current->next;
+		current->next = next;
+		next = current;
+	}
+	return next;
+}
+
+void free_commit_list(struct commit_list *list)
+{
+	while (list)
+		pop_commit(&list);
+}
+
+struct commit_list * commit_list_insert_by_date(struct commit *item, struct commit_list **list)
+{
+	struct commit_list **pp = list;
+	struct commit_list *p;
+	while ((p = *pp) != NULL) {
+		if (p->item->date < item->date) {
+			break;
+		}
+		pp = &p->next;
+	}
+	return commit_list_insert(item, pp);
+}
+
+static int commit_list_compare_by_date(const struct commit_list *a,
+				       const struct commit_list *b)
+{
+	timestamp_t a_date = a->item->date;
+	timestamp_t b_date = b->item->date;
+	if (a_date < b_date)
+		return 1;
+	if (a_date > b_date)
+		return -1;
+	return 0;
+}
+
+DEFINE_LIST_SORT(static, commit_list_sort, struct commit_list, next);
+
+void commit_list_sort_by_date(struct commit_list **list)
+{
+	commit_list_sort(list, commit_list_compare_by_date);
+}
+
+struct commit *pop_most_recent_commit(struct commit_list **list,
+				      unsigned int mark)
+{
+	struct commit *ret = pop_commit(list);
+	struct commit_list *parents = ret->parents;
+
+	while (parents) {
+		struct commit *commit = parents->item;
+		if (!repo_parse_commit(the_repository, commit) && !(commit->object.flags & mark)) {
+			commit->object.flags |= mark;
+			commit_list_insert_by_date(commit, list);
+		}
+		parents = parents->next;
+	}
+	return ret;
+}
+
+static void clear_commit_marks_1(struct commit_list **plist,
+				 struct commit *commit, unsigned int mark)
+{
+	while (commit) {
+		struct commit_list *parents;
+
+		if (!(mark & commit->object.flags))
+			return;
+
+		commit->object.flags &= ~mark;
+
+		parents = commit->parents;
+		if (!parents)
+			return;
+
+		while ((parents = parents->next)) {
+			if (parents->item->object.flags & mark)
+				commit_list_insert(parents->item, plist);
+		}
+
+		commit = commit->parents->item;
+	}
+}
+
+void clear_commit_marks_many(size_t nr, struct commit **commit, unsigned int mark)
+{
+	struct commit_list *list = NULL;
+
+	for (size_t i = 0; i < nr; i++) {
+		clear_commit_marks_1(&list, *commit, mark);
+		commit++;
+	}
+	while (list)
+		clear_commit_marks_1(&list, pop_commit(&list), mark);
+}
+
+void clear_commit_marks(struct commit *commit, unsigned int mark)
+{
+	clear_commit_marks_many(1, &commit, mark);
+}
+
+struct commit *pop_commit(struct commit_list **stack)
+{
+	struct commit_list *top = *stack;
+	struct commit *item = top ? top->item : NULL;
+
+	if (top) {
+		*stack = top->next;
+		free(top);
+	}
+	return item;
+}
+
+/*
+ * Topological sort support
+ */
+
+/* count number of children that have not been emitted */
+define_commit_slab(indegree_slab, int);
+
+define_commit_slab(author_date_slab, timestamp_t);
+
+void record_author_date(struct author_date_slab *author_date,
+			struct commit *commit)
+{
+	const char *buffer = repo_get_commit_buffer(the_repository, commit,
+						    NULL);
+	struct ident_split ident;
+	const char *ident_line;
+	size_t ident_len;
+	char *date_end;
+	timestamp_t date;
+
+	ident_line = find_commit_header(buffer, "author", &ident_len);
+	if (!ident_line)
+		goto fail_exit; /* no author line */
+	if (split_ident_line(&ident, ident_line, ident_len) ||
+	    !ident.date_begin || !ident.date_end)
+		goto fail_exit; /* malformed "author" line */
+
+	date = parse_timestamp(ident.date_begin, &date_end, 10);
+	if (date_end != ident.date_end)
+		goto fail_exit; /* malformed date */
+	*(author_date_slab_at(author_date, commit)) = date;
+
+fail_exit:
+	repo_unuse_commit_buffer(the_repository, commit, buffer);
+}
+
+int compare_commits_by_author_date(const void *a_, const void *b_,
+				   void *cb_data)
+{
+	const struct commit *a = a_, *b = b_;
+	struct author_date_slab *author_date = cb_data;
+	timestamp_t a_date = *(author_date_slab_at(author_date, a));
+	timestamp_t b_date = *(author_date_slab_at(author_date, b));
+
+	/* newer commits with larger date first */
+	if (a_date < b_date)
+		return 1;
+	else if (a_date > b_date)
+		return -1;
+	return 0;
+}
+
+int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_,
+					    void *unused UNUSED)
+{
+	const struct commit *a = a_, *b = b_;
+	const timestamp_t generation_a = commit_graph_generation(a),
+			  generation_b = commit_graph_generation(b);
+
+	/* newer commits first */
+	if (generation_a < generation_b)
+		return 1;
+	else if (generation_a > generation_b)
+		return -1;
+
+	/* use date as a heuristic when generations are equal */
+	if (a->date < b->date)
+		return 1;
+	else if (a->date > b->date)
+		return -1;
+	return 0;
+}
+
+int compare_commits_by_commit_date(const void *a_, const void *b_,
+				   void *unused UNUSED)
+{
+	const struct commit *a = a_, *b = b_;
+	/* newer commits with larger date first */
+	if (a->date < b->date)
+		return 1;
+	else if (a->date > b->date)
+		return -1;
+	return 0;
+}
+
+/*
+ * Performs an in-place topological sort on the list supplied.
+ */
+void sort_in_topological_order(struct commit_list **list, enum rev_sort_order sort_order)
+{
+	struct commit_list *next, *orig = *list;
+	struct commit_list **pptr;
+	struct indegree_slab indegree;
+	struct prio_queue queue;
+	struct commit *commit;
+	struct author_date_slab author_date;
+
+	if (!orig)
+		return;
+	*list = NULL;
+
+	init_indegree_slab(&indegree);
+	memset(&queue, '\0', sizeof(queue));
+
+	switch (sort_order) {
+	default: /* REV_SORT_IN_GRAPH_ORDER */
+		queue.compare = NULL;
+		break;
+	case REV_SORT_BY_COMMIT_DATE:
+		queue.compare = compare_commits_by_commit_date;
+		break;
+	case REV_SORT_BY_AUTHOR_DATE:
+		init_author_date_slab(&author_date);
+		queue.compare = compare_commits_by_author_date;
+		queue.cb_data = &author_date;
+		break;
+	}
+
+	/* Mark them and clear the indegree */
+	for (next = orig; next; next = next->next) {
+		struct commit *commit = next->item;
+		*(indegree_slab_at(&indegree, commit)) = 1;
+		/* also record the author dates, if needed */
+		if (sort_order == REV_SORT_BY_AUTHOR_DATE)
+			record_author_date(&author_date, commit);
+	}
+
+	/* update the indegree */
+	for (next = orig; next; next = next->next) {
+		struct commit_list *parents = next->item->parents;
+		while (parents) {
+			struct commit *parent = parents->item;
+			int *pi = indegree_slab_at(&indegree, parent);
+
+			if (*pi)
+				(*pi)++;
+			parents = parents->next;
+		}
+	}
+
+	/*
+	 * find the tips
+	 *
+	 * tips are nodes not reachable from any other node in the list
+	 *
+	 * the tips serve as a starting set for the work queue.
+	 */
+	for (next = orig; next; next = next->next) {
+		struct commit *commit = next->item;
+
+		if (*(indegree_slab_at(&indegree, commit)) == 1)
+			prio_queue_put(&queue, commit);
+	}
+
+	/*
+	 * This is unfortunate; the initial tips need to be shown
+	 * in the order given from the revision traversal machinery.
+	 */
+	if (sort_order == REV_SORT_IN_GRAPH_ORDER)
+		prio_queue_reverse(&queue);
+
+	/* We no longer need the commit list */
+	free_commit_list(orig);
+
+	pptr = list;
+	*list = NULL;
+	while ((commit = prio_queue_get(&queue)) != NULL) {
+		struct commit_list *parents;
+
+		for (parents = commit->parents; parents ; parents = parents->next) {
+			struct commit *parent = parents->item;
+			int *pi = indegree_slab_at(&indegree, parent);
+
+			if (!*pi)
+				continue;
+
+			/*
+			 * parents are only enqueued for emission
+			 * when all their children have been emitted thereby
+			 * guaranteeing topological order.
+			 */
+			if (--(*pi) == 1)
+				prio_queue_put(&queue, parent);
+		}
+		/*
+		 * all children of commit have already been
+		 * emitted. we can emit it now.
+		 */
+		*(indegree_slab_at(&indegree, commit)) = 0;
+
+		pptr = &commit_list_insert(commit, pptr)->next;
+	}
+
+	clear_indegree_slab(&indegree);
+	clear_prio_queue(&queue);
+	if (sort_order == REV_SORT_BY_AUTHOR_DATE)
+		clear_author_date_slab(&author_date);
+}
+
+struct rev_collect {
+	struct commit **commit;
+	int nr;
+	int alloc;
+	unsigned int initial : 1;
+};
+
+static void add_one_commit(struct object_id *oid, struct rev_collect *revs)
+{
+	struct commit *commit;
+
+	if (is_null_oid(oid))
+		return;
+
+	commit = lookup_commit(the_repository, oid);
+	if (!commit ||
+	    (commit->object.flags & TMP_MARK) ||
+	    repo_parse_commit(the_repository, commit))
+		return;
+
+	ALLOC_GROW(revs->commit, revs->nr + 1, revs->alloc);
+	revs->commit[revs->nr++] = commit;
+	commit->object.flags |= TMP_MARK;
+}
+
+static int collect_one_reflog_ent(struct object_id *ooid, struct object_id *noid,
+				  const char *ident UNUSED,
+				  timestamp_t timestamp UNUSED, int tz UNUSED,
+				  const char *message UNUSED, void *cbdata)
+{
+	struct rev_collect *revs = cbdata;
+
+	if (revs->initial) {
+		revs->initial = 0;
+		add_one_commit(ooid, revs);
+	}
+	add_one_commit(noid, revs);
+	return 0;
+}
+
+struct commit *get_fork_point(const char *refname, struct commit *commit)
+{
+	struct object_id oid;
+	struct rev_collect revs;
+	struct commit_list *bases = NULL;
+	int i;
+	struct commit *ret = NULL;
+	char *full_refname;
+
+	switch (repo_dwim_ref(the_repository, refname, strlen(refname), &oid,
+			      &full_refname, 0)) {
+	case 0:
+		die("No such ref: '%s'", refname);
+	case 1:
+		break; /* good */
+	default:
+		die("Ambiguous refname: '%s'", refname);
+	}
+
+	memset(&revs, 0, sizeof(revs));
+	revs.initial = 1;
+	refs_for_each_reflog_ent(get_main_ref_store(the_repository),
+				 full_refname, collect_one_reflog_ent, &revs);
+
+	if (!revs.nr)
+		add_one_commit(&oid, &revs);
+
+	for (i = 0; i < revs.nr; i++)
+		revs.commit[i]->object.flags &= ~TMP_MARK;
+
+	if (repo_get_merge_bases_many(the_repository, commit, revs.nr,
+				      revs.commit, &bases) < 0)
+		exit(128);
+
+	/*
+	 * There should be one and only one merge base, when we found
+	 * a common ancestor among reflog entries.
+	 */
+	if (!bases || bases->next)
+		goto cleanup_return;
+
+	/* And the found one must be one of the reflog entries */
+	for (i = 0; i < revs.nr; i++)
+		if (&bases->item->object == &revs.commit[i]->object)
+			break; /* found */
+	if (revs.nr <= i)
+		goto cleanup_return;
+
+	ret = bases->item;
+
+cleanup_return:
+	free(revs.commit);
+	free_commit_list(bases);
+	free(full_refname);
+	return ret;
+}
+
+/*
+ * Indexed by hash algorithm identifier.
+ */
+static const char *gpg_sig_headers[] = {
+	NULL,
+	"gpgsig",
+	"gpgsig-sha256",
+};
+
+int add_header_signature(struct strbuf *buf, struct strbuf *sig, const struct git_hash_algo *algo)
+{
+	int inspos, copypos;
+	const char *eoh;
+	const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algo)];
+	int gpg_sig_header_len = strlen(gpg_sig_header);
+
+	/* find the end of the header */
+	eoh = strstr(buf->buf, "\n\n");
+	if (!eoh)
+		inspos = buf->len;
+	else
+		inspos = eoh - buf->buf + 1;
+
+	for (copypos = 0; sig->buf[copypos]; ) {
+		const char *bol = sig->buf + copypos;
+		const char *eol = strchrnul(bol, '\n');
+		int len = (eol - bol) + !!*eol;
+
+		if (!copypos) {
+			strbuf_insert(buf, inspos, gpg_sig_header, gpg_sig_header_len);
+			inspos += gpg_sig_header_len;
+		}
+		strbuf_insertstr(buf, inspos++, " ");
+		strbuf_insert(buf, inspos, bol, len);
+		inspos += len;
+		copypos += len;
+	}
+	return 0;
+}
+
+static int sign_commit_to_strbuf(struct strbuf *sig, struct strbuf *buf, const char *keyid)
+{
+	char *keyid_to_free = NULL;
+	int ret = 0;
+	if (!keyid || !*keyid)
+		keyid = keyid_to_free = get_signing_key();
+	if (sign_buffer(buf, sig, keyid))
+		ret = -1;
+	free(keyid_to_free);
+	return ret;
+}
+
+int parse_signed_commit(const struct commit *commit,
+			struct strbuf *payload, struct strbuf *signature,
+			const struct git_hash_algo *algop)
+{
+	unsigned long size;
+	const char *buffer = repo_get_commit_buffer(the_repository, commit,
+						    &size);
+	int ret = parse_buffer_signed_by_header(buffer, size, payload, signature, algop);
+
+	repo_unuse_commit_buffer(the_repository, commit, buffer);
+	return ret;
+}
+
+int parse_buffer_signed_by_header(const char *buffer,
+				  unsigned long size,
+				  struct strbuf *payload,
+				  struct strbuf *signature,
+				  const struct git_hash_algo *algop)
+{
+	int in_signature = 0, saw_signature = 0, other_signature = 0;
+	const char *line, *tail, *p;
+	const char *gpg_sig_header = gpg_sig_headers[hash_algo_by_ptr(algop)];
+
+	line = buffer;
+	tail = buffer + size;
+	while (line < tail) {
+		const char *sig = NULL;
+		const char *next = memchr(line, '\n', tail - line);
+
+		next = next ? next + 1 : tail;
+		if (in_signature && line[0] == ' ')
+			sig = line + 1;
+		else if (skip_prefix(line, gpg_sig_header, &p) &&
+			 *p == ' ') {
+			sig = line + strlen(gpg_sig_header) + 1;
+			other_signature = 0;
+		}
+		else if (starts_with(line, "gpgsig"))
+			other_signature = 1;
+		else if (other_signature && line[0] != ' ')
+			other_signature = 0;
+		if (sig) {
+			strbuf_add(signature, sig, next - sig);
+			saw_signature = 1;
+			in_signature = 1;
+		} else {
+			if (*line == '\n')
+				/* dump the whole remainder of the buffer */
+				next = tail;
+			if (!other_signature)
+				strbuf_add(payload, line, next - line);
+			in_signature = 0;
+		}
+		line = next;
+	}
+	return saw_signature;
+}
+
+int remove_signature(struct strbuf *buf)
+{
+	const char *line = buf->buf;
+	const char *tail = buf->buf + buf->len;
+	int in_signature = 0;
+	struct sigbuf {
+		const char *start;
+		const char *end;
+	} sigs[2], *sigp = &sigs[0];
+	int i;
+	const char *orig_buf = buf->buf;
+
+	memset(sigs, 0, sizeof(sigs));
+
+	while (line < tail) {
+		const char *next = memchr(line, '\n', tail - line);
+		next = next ? next + 1 : tail;
+
+		if (in_signature && line[0] == ' ')
+			sigp->end = next;
+		else if (starts_with(line, "gpgsig")) {
+			int i;
+			for (i = 1; i < GIT_HASH_NALGOS; i++) {
+				const char *p;
+				if (skip_prefix(line, gpg_sig_headers[i], &p) &&
+				    *p == ' ') {
+					sigp->start = line;
+					sigp->end = next;
+					in_signature = 1;
+				}
+			}
+		} else {
+			if (*line == '\n')
+				/* dump the whole remainder of the buffer */
+				next = tail;
+			if (in_signature && sigp - sigs != ARRAY_SIZE(sigs))
+				sigp++;
+			in_signature = 0;
+		}
+		line = next;
+	}
+
+	for (i = ARRAY_SIZE(sigs) - 1; i >= 0; i--)
+		if (sigs[i].start)
+			strbuf_remove(buf, sigs[i].start - orig_buf, sigs[i].end - sigs[i].start);
+
+	return sigs[0].start != NULL;
+}
+
+static void handle_signed_tag(const struct commit *parent, struct commit_extra_header ***tail)
+{
+	struct merge_remote_desc *desc;
+	struct commit_extra_header *mergetag;
+	char *buf;
+	unsigned long size;
+	enum object_type type;
+	struct strbuf payload = STRBUF_INIT;
+	struct strbuf signature = STRBUF_INIT;
+
+	desc = merge_remote_util(parent);
+	if (!desc || !desc->obj)
+		return;
+	buf = repo_read_object_file(the_repository, &desc->obj->oid, &type,
+				    &size);
+	if (!buf || type != OBJ_TAG)
+		goto free_return;
+	if (!parse_signature(buf, size, &payload, &signature))
+		goto free_return;
+	/*
+	 * We could verify this signature and either omit the tag when
+	 * it does not validate, but the integrator may not have the
+	 * public key of the signer of the tag being merged, while a
+	 * later auditor may have it while auditing, so let's not run
+	 * verify-signed-buffer here for now...
+	 *
+	 * if (verify_signed_buffer(buf, len, buf + len, size - len, ...))
+	 *	warn("warning: signed tag unverified.");
+	 */
+	CALLOC_ARRAY(mergetag, 1);
+	mergetag->key = xstrdup("mergetag");
+	mergetag->value = buf;
+	mergetag->len = size;
+
+	**tail = mergetag;
+	*tail = &mergetag->next;
+	strbuf_release(&payload);
+	strbuf_release(&signature);
+	return;
+
+free_return:
+	free(buf);
+}
+
+int check_commit_signature(const struct commit *commit, struct signature_check *sigc)
+{
+	struct strbuf payload = STRBUF_INIT;
+	struct strbuf signature = STRBUF_INIT;
+	int ret = 1;
+
+	sigc->result = 'N';
+
+	if (parse_signed_commit(commit, &payload, &signature, the_hash_algo) <= 0)
+		goto out;
+
+	sigc->payload_type = SIGNATURE_PAYLOAD_COMMIT;
+	sigc->payload = strbuf_detach(&payload, &sigc->payload_len);
+	ret = check_signature(sigc, signature.buf, signature.len);
+
+ out:
+	strbuf_release(&payload);
+	strbuf_release(&signature);
+
+	return ret;
+}
+
+void verify_merge_signature(struct commit *commit, int verbosity,
+			    int check_trust)
+{
+	char hex[GIT_MAX_HEXSZ + 1];
+	struct signature_check signature_check;
+	int ret;
+	memset(&signature_check, 0, sizeof(signature_check));
+
+	ret = check_commit_signature(commit, &signature_check);
+
+	repo_find_unique_abbrev_r(the_repository, hex, &commit->object.oid,
+				  DEFAULT_ABBREV);
+	switch (signature_check.result) {
+	case 'G':
+		if (ret || (check_trust && signature_check.trust_level < TRUST_MARGINAL))
+			die(_("Commit %s has an untrusted GPG signature, "
+			      "allegedly by %s."), hex, signature_check.signer);
+		break;
+	case 'B':
+		die(_("Commit %s has a bad GPG signature "
+		      "allegedly by %s."), hex, signature_check.signer);
+	default: /* 'N' */
+		die(_("Commit %s does not have a GPG signature."), hex);
+	}
+	if (verbosity >= 0 && signature_check.result == 'G')
+		printf(_("Commit %s has a good GPG signature by %s\n"),
+		       hex, signature_check.signer);
+
+	signature_check_clear(&signature_check);
+}
+
+void append_merge_tag_headers(const struct commit_list *parents,
+			      struct commit_extra_header ***tail)
+{
+	while (parents) {
+		const struct commit *parent = parents->item;
+		handle_signed_tag(parent, tail);
+		parents = parents->next;
+	}
+}
+
+static int convert_commit_extra_headers(const struct commit_extra_header *orig,
+					struct commit_extra_header **result)
+{
+	const struct git_hash_algo *compat = the_repository->compat_hash_algo;
+	const struct git_hash_algo *algo = the_repository->hash_algo;
+	struct commit_extra_header *extra = NULL, **tail = &extra;
+	struct strbuf out = STRBUF_INIT;
+	while (orig) {
+		struct commit_extra_header *new;
+		CALLOC_ARRAY(new, 1);
+		if (!strcmp(orig->key, "mergetag")) {
+			if (convert_object_file(&out, algo, compat,
+						orig->value, orig->len,
+						OBJ_TAG, 1)) {
+				free(new);
+				free_commit_extra_headers(extra);
+				return -1;
+			}
+			new->key = xstrdup("mergetag");
+			new->value = strbuf_detach(&out, &new->len);
+		} else {
+			new->key = xstrdup(orig->key);
+			new->len = orig->len;
+			new->value = xmemdupz(orig->value, orig->len);
+		}
+		*tail = new;
+		tail = &new->next;
+		orig = orig->next;
+	}
+	*result = extra;
+	return 0;
+}
+
+static void add_extra_header(struct strbuf *buffer,
+			     const struct commit_extra_header *extra)
+{
+	strbuf_addstr(buffer, extra->key);
+	if (extra->len)
+		strbuf_add_lines(buffer, " ", extra->value, extra->len);
+	else
+		strbuf_addch(buffer, '\n');
+}
+
+struct commit_extra_header *read_commit_extra_headers(struct commit *commit,
+						      const char **exclude)
+{
+	struct commit_extra_header *extra = NULL;
+	unsigned long size;
+	const char *buffer = repo_get_commit_buffer(the_repository, commit,
+						    &size);
+	extra = read_commit_extra_header_lines(buffer, size, exclude);
+	repo_unuse_commit_buffer(the_repository, commit, buffer);
+	return extra;
+}
+
+int for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data)
+{
+	struct commit_extra_header *extra, *to_free;
+	int res = 0;
+
+	to_free = read_commit_extra_headers(commit, NULL);
+	for (extra = to_free; !res && extra; extra = extra->next) {
+		if (strcmp(extra->key, "mergetag"))
+			continue; /* not a merge tag */
+		res = fn(commit, extra, data);
+	}
+	free_commit_extra_headers(to_free);
+	return res;
+}
+
+static inline int standard_header_field(const char *field, size_t len)
+{
+	return ((len == 4 && !memcmp(field, "tree", 4)) ||
+		(len == 6 && !memcmp(field, "parent", 6)) ||
+		(len == 6 && !memcmp(field, "author", 6)) ||
+		(len == 9 && !memcmp(field, "committer", 9)) ||
+		(len == 8 && !memcmp(field, "encoding", 8)));
+}
+
+static int excluded_header_field(const char *field, size_t len, const char **exclude)
+{
+	if (!exclude)
+		return 0;
+
+	while (*exclude) {
+		size_t xlen = strlen(*exclude);
+		if (len == xlen && !memcmp(field, *exclude, xlen))
+			return 1;
+		exclude++;
+	}
+	return 0;
+}
+
+static struct commit_extra_header *read_commit_extra_header_lines(
+	const char *buffer, size_t size,
+	const char **exclude)
+{
+	struct commit_extra_header *extra = NULL, **tail = &extra, *it = NULL;
+	const char *line, *next, *eof, *eob;
+	struct strbuf buf = STRBUF_INIT;
+
+	for (line = buffer, eob = line + size;
+	     line < eob && *line != '\n';
+	     line = next) {
+		next = memchr(line, '\n', eob - line);
+		next = next ? next + 1 : eob;
+		if (*line == ' ') {
+			/* continuation */
+			if (it)
+				strbuf_add(&buf, line + 1, next - (line + 1));
+			continue;
+		}
+		if (it)
+			it->value = strbuf_detach(&buf, &it->len);
+		strbuf_reset(&buf);
+		it = NULL;
+
+		eof = memchr(line, ' ', next - line);
+		if (!eof)
+			eof = next;
+		else if (standard_header_field(line, eof - line) ||
+			 excluded_header_field(line, eof - line, exclude))
+			continue;
+
+		CALLOC_ARRAY(it, 1);
+		it->key = xmemdupz(line, eof-line);
+		*tail = it;
+		tail = &it->next;
+		if (eof + 1 < next)
+			strbuf_add(&buf, eof + 1, next - (eof + 1));
+	}
+	if (it)
+		it->value = strbuf_detach(&buf, &it->len);
+	return extra;
+}
+
+void free_commit_extra_headers(struct commit_extra_header *extra)
+{
+	while (extra) {
+		struct commit_extra_header *next = extra->next;
+		free(extra->key);
+		free(extra->value);
+		free(extra);
+		extra = next;
+	}
+}
+
+int commit_tree(const char *msg, size_t msg_len, const struct object_id *tree,
+		const struct commit_list *parents, struct object_id *ret,
+		const char *author, const char *sign_commit)
+{
+	struct commit_extra_header *extra = NULL, **tail = &extra;
+	int result;
+
+	append_merge_tag_headers(parents, &tail);
+	result = commit_tree_extended(msg, msg_len, tree, parents, ret, author,
+				      NULL, sign_commit, extra);
+	free_commit_extra_headers(extra);
+	return result;
+}
+
+static int find_invalid_utf8(const char *buf, int len)
+{
+	int offset = 0;
+	static const unsigned int max_codepoint[] = {
+		0x7f, 0x7ff, 0xffff, 0x10ffff
+	};
+
+	while (len) {
+		unsigned char c = *buf++;
+		int bytes, bad_offset;
+		unsigned int codepoint;
+		unsigned int min_val, max_val;
+
+		len--;
+		offset++;
+
+		/* Simple US-ASCII? No worries. */
+		if (c < 0x80)
+			continue;
+
+		bad_offset = offset-1;
+
+		/*
+		 * Count how many more high bits set: that's how
+		 * many more bytes this sequence should have.
+		 */
+		bytes = 0;
+		while (c & 0x40) {
+			c <<= 1;
+			bytes++;
+		}
+
+		/*
+		 * Must be between 1 and 3 more bytes.  Longer sequences result in
+		 * codepoints beyond U+10FFFF, which are guaranteed never to exist.
+		 */
+		if (bytes < 1 || 3 < bytes)
+			return bad_offset;
+
+		/* Do we *have* that many bytes? */
+		if (len < bytes)
+			return bad_offset;
+
+		/*
+		 * Place the encoded bits at the bottom of the value and compute the
+		 * valid range.
+		 */
+		codepoint = (c & 0x7f) >> bytes;
+		min_val = max_codepoint[bytes-1] + 1;
+		max_val = max_codepoint[bytes];
+
+		offset += bytes;
+		len -= bytes;
+
+		/* And verify that they are good continuation bytes */
+		do {
+			codepoint <<= 6;
+			codepoint |= *buf & 0x3f;
+			if ((*buf++ & 0xc0) != 0x80)
+				return bad_offset;
+		} while (--bytes);
+
+		/* Reject codepoints that are out of range for the sequence length. */
+		if (codepoint < min_val || codepoint > max_val)
+			return bad_offset;
+		/* Surrogates are only for UTF-16 and cannot be encoded in UTF-8. */
+		if ((codepoint & 0x1ff800) == 0xd800)
+			return bad_offset;
+		/* U+xxFFFE and U+xxFFFF are guaranteed non-characters. */
+		if ((codepoint & 0xfffe) == 0xfffe)
+			return bad_offset;
+		/* So are anything in the range U+FDD0..U+FDEF. */
+		if (codepoint >= 0xfdd0 && codepoint <= 0xfdef)
+			return bad_offset;
+	}
+	return -1;
+}
+
+/*
+ * This verifies that the buffer is in proper utf8 format.
+ *
+ * If it isn't, it assumes any non-utf8 characters are Latin1,
+ * and does the conversion.
+ */
+static int verify_utf8(struct strbuf *buf)
+{
+	int ok = 1;
+	long pos = 0;
+
+	for (;;) {
+		int bad;
+		unsigned char c;
+		unsigned char replace[2];
+
+		bad = find_invalid_utf8(buf->buf + pos, buf->len - pos);
+		if (bad < 0)
+			return ok;
+		pos += bad;
+		ok = 0;
+		c = buf->buf[pos];
+		strbuf_remove(buf, pos, 1);
+
+		/* We know 'c' must be in the range 128-255 */
+		replace[0] = 0xc0 + (c >> 6);
+		replace[1] = 0x80 + (c & 0x3f);
+		strbuf_insert(buf, pos, replace, 2);
+		pos += 2;
+	}
+}
+
+static const char commit_utf8_warn[] =
+N_("Warning: commit message did not conform to UTF-8.\n"
+   "You may want to amend it after fixing the message, or set the config\n"
+   "variable i18n.commitEncoding to the encoding your project uses.\n");
+
+static void write_commit_tree(struct strbuf *buffer, const char *msg, size_t msg_len,
+			      const struct object_id *tree,
+			      const struct object_id *parents, size_t parents_len,
+			      const char *author, const char *committer,
+			      const struct commit_extra_header *extra)
+{
+	int encoding_is_utf8;
+	size_t i;
+
+	/* Not having i18n.commitencoding is the same as having utf-8 */
+	encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
+
+	strbuf_grow(buffer, 8192); /* should avoid reallocs for the headers */
+	strbuf_addf(buffer, "tree %s\n", oid_to_hex(tree));
+
+	/*
+	 * NOTE! This ordering means that the same exact tree merged with a
+	 * different order of parents will be a _different_ changeset even
+	 * if everything else stays the same.
+	 */
+	for (i = 0; i < parents_len; i++)
+		strbuf_addf(buffer, "parent %s\n", oid_to_hex(&parents[i]));
+
+	/* Person/date information */
+	if (!author)
+		author = git_author_info(IDENT_STRICT);
+	strbuf_addf(buffer, "author %s\n", author);
+	if (!committer)
+		committer = git_committer_info(IDENT_STRICT);
+	strbuf_addf(buffer, "committer %s\n", committer);
+	if (!encoding_is_utf8)
+		strbuf_addf(buffer, "encoding %s\n", git_commit_encoding);
+
+	while (extra) {
+		add_extra_header(buffer, extra);
+		extra = extra->next;
+	}
+	strbuf_addch(buffer, '\n');
+
+	/* And add the comment */
+	strbuf_add(buffer, msg, msg_len);
+}
+
+int commit_tree_extended(const char *msg, size_t msg_len,
+			 const struct object_id *tree,
+			 const struct commit_list *parents, struct object_id *ret,
+			 const char *author, const char *committer,
+			 const char *sign_commit,
+			 const struct commit_extra_header *extra)
+{
+	struct repository *r = the_repository;
+	int result = 0;
+	int encoding_is_utf8;
+	struct strbuf buffer = STRBUF_INIT, compat_buffer = STRBUF_INIT;
+	struct strbuf sig = STRBUF_INIT, compat_sig = STRBUF_INIT;
+	struct object_id *parent_buf = NULL, *compat_oid = NULL;
+	struct object_id compat_oid_buf;
+	size_t i, nparents;
+
+	/* Not having i18n.commitencoding is the same as having utf-8 */
+	encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
+
+	assert_oid_type(tree, OBJ_TREE);
+
+	if (memchr(msg, '\0', msg_len))
+		return error("a NUL byte in commit log message not allowed.");
+
+	nparents = commit_list_count(parents);
+	CALLOC_ARRAY(parent_buf, nparents);
+	i = 0;
+	for (const struct commit_list *p = parents; p; p = p->next)
+		oidcpy(&parent_buf[i++], &p->item->object.oid);
+
+	write_commit_tree(&buffer, msg, msg_len, tree, parent_buf, nparents, author, committer, extra);
+	if (sign_commit && sign_commit_to_strbuf(&sig, &buffer, sign_commit)) {
+		result = -1;
+		goto out;
+	}
+	if (r->compat_hash_algo) {
+		struct commit_extra_header *compat_extra = NULL;
+		struct object_id mapped_tree;
+		struct object_id *mapped_parents;
+
+		CALLOC_ARRAY(mapped_parents, nparents);
+
+		if (repo_oid_to_algop(r, tree, r->compat_hash_algo, &mapped_tree)) {
+			result = -1;
+			free(mapped_parents);
+			goto out;
+		}
+		for (i = 0; i < nparents; i++)
+			if (repo_oid_to_algop(r, &parent_buf[i], r->compat_hash_algo, &mapped_parents[i])) {
+				result = -1;
+				free(mapped_parents);
+				goto out;
+			}
+		if (convert_commit_extra_headers(extra, &compat_extra)) {
+			result = -1;
+			free(mapped_parents);
+			goto out;
+		}
+		write_commit_tree(&compat_buffer, msg, msg_len, &mapped_tree,
+				  mapped_parents, nparents, author, committer, compat_extra);
+		free_commit_extra_headers(compat_extra);
+		free(mapped_parents);
+
+		if (sign_commit && sign_commit_to_strbuf(&compat_sig, &compat_buffer, sign_commit)) {
+			result = -1;
+			goto out;
+		}
+	}
+
+	if (sign_commit) {
+		struct sig_pairs {
+			struct strbuf *sig;
+			const struct git_hash_algo *algo;
+		} bufs [2] = {
+			{ &compat_sig, r->compat_hash_algo },
+			{ &sig, r->hash_algo },
+		};
+
+		/*
+		 * We write algorithms in the order they were implemented in
+		 * Git to produce a stable hash when multiple algorithms are
+		 * used.
+		 */
+		if (r->compat_hash_algo && hash_algo_by_ptr(bufs[0].algo) > hash_algo_by_ptr(bufs[1].algo))
+			SWAP(bufs[0], bufs[1]);
+
+		/*
+		 * We traverse each algorithm in order, and apply the signature
+		 * to each buffer.
+		 */
+		for (size_t i = 0; i < ARRAY_SIZE(bufs); i++) {
+			if (!bufs[i].algo)
+				continue;
+			add_header_signature(&buffer, bufs[i].sig, bufs[i].algo);
+			if (r->compat_hash_algo)
+				add_header_signature(&compat_buffer, bufs[i].sig, bufs[i].algo);
+		}
+	}
+
+	/* And check the encoding. */
+	if (encoding_is_utf8 && (!verify_utf8(&buffer) || !verify_utf8(&compat_buffer)))
+		fprintf(stderr, _(commit_utf8_warn));
+
+	if (r->compat_hash_algo) {
+		hash_object_file(r->compat_hash_algo, compat_buffer.buf, compat_buffer.len,
+			OBJ_COMMIT, &compat_oid_buf);
+		compat_oid = &compat_oid_buf;
+	}
+
+	result = write_object_file_flags(buffer.buf, buffer.len, OBJ_COMMIT,
+					 ret, compat_oid, 0);
+out:
+	free(parent_buf);
+	strbuf_release(&buffer);
+	strbuf_release(&compat_buffer);
+	strbuf_release(&sig);
+	strbuf_release(&compat_sig);
+	return result;
+}
+
+define_commit_slab(merge_desc_slab, struct merge_remote_desc *);
+static struct merge_desc_slab merge_desc_slab = COMMIT_SLAB_INIT(1, merge_desc_slab);
+
+struct merge_remote_desc *merge_remote_util(const struct commit *commit)
+{
+	return *merge_desc_slab_at(&merge_desc_slab, commit);
+}
+
+void set_merge_remote_desc(struct commit *commit,
+			   const char *name, struct object *obj)
+{
+	struct merge_remote_desc *desc;
+	FLEX_ALLOC_STR(desc, name, name);
+	desc->obj = obj;
+	*merge_desc_slab_at(&merge_desc_slab, commit) = desc;
+}
+
+struct commit *get_merge_parent(const char *name)
+{
+	struct object *obj;
+	struct commit *commit;
+	struct object_id oid;
+	if (repo_get_oid(the_repository, name, &oid))
+		return NULL;
+	obj = parse_object(the_repository, &oid);
+	commit = (struct commit *)repo_peel_to_type(the_repository, name, 0,
+						    obj, OBJ_COMMIT);
+	if (commit && !merge_remote_util(commit))
+		set_merge_remote_desc(commit, name, obj);
+	return commit;
+}
+
+/*
+ * Append a commit to the end of the commit_list.
+ *
+ * next starts by pointing to the variable that holds the head of an
+ * empty commit_list, and is updated to point to the "next" field of
+ * the last item on the list as new commits are appended.
+ *
+ * Usage example:
+ *
+ *     struct commit_list *list;
+ *     struct commit_list **next = &list;
+ *
+ *     next = commit_list_append(c1, next);
+ *     next = commit_list_append(c2, next);
+ *     assert(commit_list_count(list) == 2);
+ *     return list;
+ */
+struct commit_list **commit_list_append(struct commit *commit,
+					struct commit_list **next)
+{
+	struct commit_list *new_commit = xmalloc(sizeof(struct commit_list));
+	new_commit->item = commit;
+	*next = new_commit;
+	new_commit->next = NULL;
+	return &new_commit->next;
+}
+
+const char *find_commit_header(const char *msg, const char *key, size_t *out_len)
+{
+	int key_len = strlen(key);
+	const char *line = msg;
+
+	while (line) {
+		const char *eol = strchrnul(line, '\n');
+
+		if (line == eol)
+			return NULL;
+
+		if (eol - line > key_len &&
+		    !strncmp(line, key, key_len) &&
+		    line[key_len] == ' ') {
+			*out_len = eol - line - key_len - 1;
+			return line + key_len + 1;
+		}
+		line = *eol ? eol + 1 : NULL;
+	}
+	return NULL;
+}
+
+/*
+ * Inspect the given string and determine the true "end" of the log message, in
+ * order to find where to put a new Signed-off-by trailer.  Ignored are
+ * trailing comment lines and blank lines.  To support "git commit -s
+ * --amend" on an existing commit, we also ignore "Conflicts:".  To
+ * support "git commit -v", we truncate at cut lines.
+ *
+ * Returns the number of bytes from the tail to ignore, to be fed as
+ * the second parameter to append_signoff().
+ */
+size_t ignored_log_message_bytes(const char *buf, size_t len)
+{
+	size_t boc = 0;
+	size_t bol = 0;
+	int in_old_conflicts_block = 0;
+	size_t cutoff = wt_status_locate_end(buf, len);
+
+	while (bol < cutoff) {
+		const char *next_line = memchr(buf + bol, '\n', len - bol);
+
+		if (!next_line)
+			next_line = buf + len;
+		else
+			next_line++;
+
+		if (starts_with_mem(buf + bol, cutoff - bol, comment_line_str) ||
+		    buf[bol] == '\n') {
+			/* is this the first of the run of comments? */
+			if (!boc)
+				boc = bol;
+			/* otherwise, it is just continuing */
+		} else if (starts_with(buf + bol, "Conflicts:\n")) {
+			in_old_conflicts_block = 1;
+			if (!boc)
+				boc = bol;
+		} else if (in_old_conflicts_block && buf[bol] == '\t') {
+			; /* a pathname in the conflicts block */
+		} else if (boc) {
+			/* the previous was not trailing comment */
+			boc = 0;
+			in_old_conflicts_block = 0;
+		}
+		bol = next_line - buf;
+	}
+	return boc ? len - boc : len - cutoff;
+}
+
+int run_commit_hook(int editor_is_used, const char *index_file,
+		    int *invoked_hook, const char *name, ...)
+{
+	struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
+	va_list args;
+	const char *arg;
+
+	strvec_pushf(&opt.env, "GIT_INDEX_FILE=%s", index_file);
+
+	/*
+	 * Let the hook know that no editor will be launched.
+	 */
+	if (!editor_is_used)
+		strvec_push(&opt.env, "GIT_EDITOR=:");
+
+	va_start(args, name);
+	while ((arg = va_arg(args, const char *)))
+		strvec_push(&opt.args, arg);
+	va_end(args);
+
+	opt.invoked_hook = invoked_hook;
+	return run_hooks_opt(the_repository, name, &opt);
+}
diff --git a/commit.h b/commit.h
new file mode 100644
index 0000000000..70c870dae4
--- /dev/null
+++ b/commit.h
@@ -0,0 +1,376 @@
+#ifndef COMMIT_H
+#define COMMIT_H
+
+#include "object.h"
+
+struct signature_check;
+struct strbuf;
+struct tree;
+
+#define COMMIT_NOT_FROM_GRAPH 0xFFFFFFFF
+#define GENERATION_NUMBER_INFINITY ((1ULL << 63) - 1)
+#define GENERATION_NUMBER_V1_MAX 0x3FFFFFFF
+#define GENERATION_NUMBER_ZERO 0
+#define GENERATION_NUMBER_V2_OFFSET_MAX ((1ULL << 31) - 1)
+
+struct commit_list {
+	struct commit *item;
+	struct commit_list *next;
+};
+
+/*
+ * The size of this struct matters in full repo walk operations like
+ * 'git clone' or 'git gc'. Consider using commit-slab to attach data
+ * to a commit instead of adding new fields here.
+ */
+struct commit {
+	struct object object;
+	timestamp_t date;
+	struct commit_list *parents;
+
+	/*
+	 * If the commit is loaded from the commit-graph file, then this
+	 * member may be NULL. Only access it through repo_get_commit_tree()
+	 * or get_commit_tree_oid().
+	 */
+	struct tree *maybe_tree;
+	unsigned int index;
+};
+
+extern int save_commit_buffer;
+extern int no_graft_file_deprecated_advice;
+extern const char *commit_type;
+
+/* While we can decorate any object with a name, it's only used for commits.. */
+struct name_decoration {
+	struct name_decoration *next;
+	int type;
+	char name[FLEX_ARRAY];
+};
+
+enum decoration_type {
+	DECORATION_NONE = 0,
+	DECORATION_REF_LOCAL,
+	DECORATION_REF_REMOTE,
+	DECORATION_REF_TAG,
+	DECORATION_REF_STASH,
+	DECORATION_REF_HEAD,
+	DECORATION_GRAFTED,
+};
+
+void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);
+const struct name_decoration *get_name_decoration(const struct object *obj);
+
+/*
+ * Look up commit named by "oid" respecting replacement objects.
+ * Returns NULL if "oid" is not a commit or does not exist.
+ */
+struct commit *lookup_commit_object(struct repository *r, const struct object_id *oid);
+
+/*
+ * Look up commit named by "oid" without replacement objects or
+ * checking for object existence. Returns the requested commit if it
+ * is found in the object cache, NULL if "oid" is in the object cache
+ * but is not a commit and a newly allocated unparsed commit object if
+ * "oid" is not in the object cache.
+ */
+struct commit *lookup_commit(struct repository *r, const struct object_id *oid);
+struct commit *lookup_commit_reference(struct repository *r,
+				       const struct object_id *oid);
+struct commit *lookup_commit_reference_gently(struct repository *r,
+					      const struct object_id *oid,
+					      int quiet);
+struct commit *lookup_commit_reference_by_name(const char *name);
+struct commit *lookup_commit_reference_by_name_gently(const char *name,
+						      int quiet);
+
+/*
+ * Look up object named by "oid", dereference tag as necessary,
+ * get a commit and return it. If "oid" does not dereference to
+ * a commit, use ref_name to report an error and die.
+ */
+struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref_name);
+
+int parse_commit_buffer(struct repository *r, struct commit *item, const void *buffer, unsigned long size, int check_graph);
+int repo_parse_commit_internal(struct repository *r, struct commit *item,
+			       int quiet_on_missing, int use_commit_graph);
+int repo_parse_commit_gently(struct repository *r,
+			     struct commit *item,
+			     int quiet_on_missing);
+static inline int repo_parse_commit(struct repository *r, struct commit *item)
+{
+	return repo_parse_commit_gently(r, item, 0);
+}
+
+static inline int repo_parse_commit_no_graph(struct repository *r,
+					     struct commit *commit)
+{
+	return repo_parse_commit_internal(r, commit, 0, 0);
+}
+
+void parse_commit_or_die(struct commit *item);
+
+void unparse_commit(struct repository *r, const struct object_id *oid);
+
+struct buffer_slab;
+struct buffer_slab *allocate_commit_buffer_slab(void);
+void free_commit_buffer_slab(struct buffer_slab *bs);
+
+/*
+ * Associate an object buffer with the commit. The ownership of the
+ * memory is handed over to the commit, and must be free()-able.
+ */
+void set_commit_buffer(struct repository *r, struct commit *, void *buffer, unsigned long size);
+
+/*
+ * Get any cached object buffer associated with the commit. Returns NULL
+ * if none. The resulting memory should not be freed.
+ */
+const void *get_cached_commit_buffer(struct repository *, const struct commit *, unsigned long *size);
+
+/*
+ * Get the commit's object contents, either from cache or by reading the object
+ * from disk. The resulting memory should not be modified, and must be given
+ * to repo_unuse_commit_buffer when the caller is done.
+ */
+const void *repo_get_commit_buffer(struct repository *r,
+				   const struct commit *,
+				   unsigned long *size);
+
+/*
+ * Tell the commit subsystem that we are done with a particular commit buffer.
+ * The commit and buffer should be the input and return value, respectively,
+ * from an earlier call to repo_get_commit_buffer.  The buffer may or may not be
+ * freed by this call; callers should not access the memory afterwards.
+ */
+void repo_unuse_commit_buffer(struct repository *r,
+			      const struct commit *,
+			      const void *buffer);
+
+/*
+ * Free any cached object buffer associated with the commit.
+ */
+void free_commit_buffer(struct parsed_object_pool *pool, struct commit *);
+
+struct tree *repo_get_commit_tree(struct repository *, const struct commit *);
+struct object_id *get_commit_tree_oid(const struct commit *);
+
+/*
+ * Release memory related to a commit, including the parent list and
+ * any cached object buffer.
+ */
+void release_commit_memory(struct parsed_object_pool *pool, struct commit *c);
+
+/*
+ * Disassociate any cached object buffer from the commit, but do not free it.
+ * The buffer (or NULL, if none) is returned.
+ */
+const void *detach_commit_buffer(struct commit *, unsigned long *sizep);
+
+/* Find beginning and length of commit subject. */
+int find_commit_subject(const char *commit_buffer, const char **subject);
+
+/* Return length of the commit subject from commit log message. */
+size_t commit_subject_length(const char *body);
+
+struct commit_list *commit_list_insert(struct commit *item,
+					struct commit_list **list);
+int commit_list_contains(struct commit *item,
+			 struct commit_list *list);
+struct commit_list **commit_list_append(struct commit *commit,
+					struct commit_list **next);
+unsigned commit_list_count(const struct commit_list *l);
+struct commit_list *commit_list_insert_by_date(struct commit *item,
+				    struct commit_list **list);
+void commit_list_sort_by_date(struct commit_list **list);
+
+/* Shallow copy of the input list */
+struct commit_list *copy_commit_list(const struct commit_list *list);
+
+/* Modify list in-place to reverse it, returning new head; list will be tail */
+struct commit_list *reverse_commit_list(struct commit_list *list);
+
+void free_commit_list(struct commit_list *list);
+
+struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */
+
+const char *repo_logmsg_reencode(struct repository *r,
+				 const struct commit *commit,
+				 char **commit_encoding,
+				 const char *output_encoding);
+
+const char *skip_blank_lines(const char *msg);
+
+/** Removes the first commit from a list sorted by date, and adds all
+ * of its parents.
+ **/
+struct commit *pop_most_recent_commit(struct commit_list **list,
+				      unsigned int mark);
+
+struct commit *pop_commit(struct commit_list **stack);
+
+void clear_commit_marks(struct commit *commit, unsigned int mark);
+void clear_commit_marks_many(size_t nr, struct commit **commit, unsigned int mark);
+
+
+enum rev_sort_order {
+	REV_SORT_IN_GRAPH_ORDER = 0,
+	REV_SORT_BY_COMMIT_DATE,
+	REV_SORT_BY_AUTHOR_DATE
+};
+
+/*
+ * Performs an in-place topological sort of list supplied.
+ *
+ *   invariant of resulting list is:
+ *      a reachable from b => ord(b) < ord(a)
+ *   sort_order further specifies:
+ *   REV_SORT_IN_GRAPH_ORDER: try to show a commit on a single-parent
+ *                            chain together.
+ *   REV_SORT_BY_COMMIT_DATE: show eligible commits in committer-date order.
+ */
+void sort_in_topological_order(struct commit_list **, enum rev_sort_order);
+
+struct commit_graft {
+	struct object_id oid;
+	int nr_parent; /* < 0 if shallow commit */
+	struct object_id parent[FLEX_ARRAY]; /* more */
+};
+typedef int (*each_commit_graft_fn)(const struct commit_graft *, void *);
+
+struct commit_graft *read_graft_line(struct strbuf *line);
+/* commit_graft_pos returns an index into r->parsed_objects->grafts. */
+int commit_graft_pos(struct repository *r, const struct object_id *oid);
+int register_commit_graft(struct repository *r, struct commit_graft *, int);
+void prepare_commit_graft(struct repository *r);
+struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid);
+
+struct commit *get_fork_point(const char *refname, struct commit *commit);
+
+/* largest positive number a signed 32-bit integer can contain */
+#define INFINITE_DEPTH 0x7fffffff
+
+struct oid_array;
+struct ref;
+int for_each_commit_graft(each_commit_graft_fn, void *);
+
+int interactive_add(struct repository *repo,
+		    const char **argv,
+		    const char *prefix,
+		    int patch);
+
+struct commit_extra_header {
+	struct commit_extra_header *next;
+	char *key;
+	char *value;
+	size_t len;
+};
+
+void append_merge_tag_headers(const struct commit_list *parents,
+			      struct commit_extra_header ***tail);
+
+int commit_tree(const char *msg, size_t msg_len,
+		const struct object_id *tree,
+		const struct commit_list *parents, struct object_id *ret,
+		const char *author, const char *sign_commit);
+
+int commit_tree_extended(const char *msg, size_t msg_len,
+			 const struct object_id *tree,
+			 const struct commit_list *parents, struct object_id *ret,
+			 const char *author, const char *committer,
+			 const char *sign_commit, const struct commit_extra_header *);
+
+struct commit_extra_header *read_commit_extra_headers(struct commit *, const char **);
+
+void free_commit_extra_headers(struct commit_extra_header *extra);
+
+/*
+ * Search the commit object contents given by "msg" for the header "key".
+ * Returns a pointer to the start of the header contents, or NULL. The length
+ * of the header, up to the first newline, is returned via out_len.
+ *
+ * Note that some headers (like mergetag) may be multi-line. It is the caller's
+ * responsibility to parse further in this case!
+ */
+const char *find_commit_header(const char *msg, const char *key,
+			       size_t *out_len);
+
+/* Find the number of bytes to ignore from the end of a log message. */
+size_t ignored_log_message_bytes(const char *buf, size_t len);
+
+typedef int (*each_mergetag_fn)(struct commit *commit, struct commit_extra_header *extra,
+				void *cb_data);
+
+int for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *data);
+
+struct merge_remote_desc {
+	struct object *obj; /* the named object, could be a tag */
+	char name[FLEX_ARRAY];
+};
+struct merge_remote_desc *merge_remote_util(const struct commit *);
+void set_merge_remote_desc(struct commit *commit,
+			   const char *name, struct object *obj);
+
+/*
+ * Given "name" from the command line to merge, find the commit object
+ * and return it, while storing merge_remote_desc in its ->util field,
+ * to allow callers to tell if we are told to merge a tag.
+ */
+struct commit *get_merge_parent(const char *name);
+
+int parse_signed_commit(const struct commit *commit,
+			struct strbuf *message, struct strbuf *signature,
+			const struct git_hash_algo *algop);
+int remove_signature(struct strbuf *buf);
+
+/*
+ * Check the signature of the given commit. The result of the check is stored
+ * in sig->check_result, 'G' for a good signature, 'U' for a good signature
+ * from an untrusted signer, 'B' for a bad signature and 'N' for no signature
+ * at all.  This may allocate memory for sig->gpg_output, sig->gpg_status,
+ * sig->signer and sig->key.
+ */
+int check_commit_signature(const struct commit *commit, struct signature_check *sigc);
+
+/* record author-date for each commit object */
+struct author_date_slab;
+void record_author_date(struct author_date_slab *author_date,
+			struct commit *commit);
+
+int compare_commits_by_author_date(const void *a_, const void *b_, void *unused);
+
+/*
+ * Verify a single commit with check_commit_signature() and die() if it is not
+ * a good signature. This isn't really suitable for general use, but is a
+ * helper to implement consistent logic for pull/merge --verify-signatures.
+ *
+ * The check_trust parameter is meant for backward-compatibility.  The GPG
+ * interface verifies key trust with a default trust level that is below the
+ * default trust level for merge operations.  Its value should be non-zero if
+ * the user hasn't set a minimum trust level explicitly in their configuration.
+ *
+ * If the user has set a minimum trust level, then that value should be obeyed
+ * and check_trust should be zero, even if the configured trust level is below
+ * the default trust level for merges.
+ */
+void verify_merge_signature(struct commit *commit, int verbose,
+			    int check_trust);
+
+int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused);
+int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused);
+
+LAST_ARG_MUST_BE_NULL
+int run_commit_hook(int editor_is_used, const char *index_file,
+		    int *invoked_hook, const char *name, ...);
+
+/* Sign a commit or tag buffer, storing the result in a header. */
+int sign_with_header(struct strbuf *buf, const char *keyid);
+/* Parse the signature out of a header. */
+int parse_buffer_signed_by_header(const char *buffer,
+				  unsigned long size,
+				  struct strbuf *payload,
+				  struct strbuf *signature,
+				  const struct git_hash_algo *algop);
+int add_header_signature(struct strbuf *buf, struct strbuf *sig, const struct git_hash_algo *algo);
+
+#endif /* COMMIT_H */
diff --git a/common-main.c b/common-main.c
new file mode 100644
index 0000000000..8e68ac9e42
--- /dev/null
+++ b/common-main.c
@@ -0,0 +1,92 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "exec-cmd.h"
+#include "gettext.h"
+#include "attr.h"
+#include "repository.h"
+#include "setup.h"
+#include "strbuf.h"
+#include "trace2.h"
+
+/*
+ * Many parts of Git have subprograms communicate via pipe, expect the
+ * upstream of a pipe to die with SIGPIPE when the downstream of a
+ * pipe does not need to read all that is written.  Some third-party
+ * programs that ignore or block SIGPIPE for their own reason forget
+ * to restore SIGPIPE handling to the default before spawning Git and
+ * break this carefully orchestrated machinery.
+ *
+ * Restore the way SIGPIPE is handled to default, which is what we
+ * expect.
+ */
+static void restore_sigpipe_to_default(void)
+{
+	sigset_t unblock;
+
+	sigemptyset(&unblock);
+	sigaddset(&unblock, SIGPIPE);
+	sigprocmask(SIG_UNBLOCK, &unblock, NULL);
+	signal(SIGPIPE, SIG_DFL);
+}
+
+int main(int argc, const char **argv)
+{
+	int result;
+	struct strbuf tmp = STRBUF_INIT;
+
+	trace2_initialize_clock();
+
+	/*
+	 * Always open file descriptors 0/1/2 to avoid clobbering files
+	 * in die().  It also avoids messing up when the pipes are dup'ed
+	 * onto stdin/stdout/stderr in the child processes we spawn.
+	 */
+	sanitize_stdfds();
+	restore_sigpipe_to_default();
+
+	git_resolve_executable_dir(argv[0]);
+
+	setlocale(LC_CTYPE, "");
+	git_setup_gettext();
+
+	initialize_repository(the_repository);
+
+	attr_start();
+
+	trace2_initialize();
+	trace2_cmd_start(argv);
+	trace2_collect_process_info(TRACE2_PROCESS_INFO_STARTUP);
+
+	if (!strbuf_getcwd(&tmp))
+		tmp_original_cwd = strbuf_detach(&tmp, NULL);
+
+	result = cmd_main(argc, argv);
+
+	/* Not exit(3), but a wrapper calling our common_exit() */
+	exit(result);
+}
+
+static void check_bug_if_BUG(void)
+{
+	if (!bug_called_must_BUG)
+		return;
+	BUG("on exit(): had bug() call(s) in this process without explicit BUG_if_bug()");
+}
+
+/* We wrap exit() to call common_exit() in git-compat-util.h */
+int common_exit(const char *file, int line, int code)
+{
+	/*
+	 * For non-POSIX systems: Take the lowest 8 bits of the "code"
+	 * to e.g. turn -1 into 255. On a POSIX system this is
+	 * redundant, see exit(3) and wait(2), but as it doesn't harm
+	 * anything there we don't need to guard this with an "ifdef".
+	 */
+	code &= 0xff;
+
+	check_bug_if_BUG();
+	trace2_cmd_exit_fl(file, line, code);
+
+	return code;
+}
diff --git a/compat/.gitattributes b/compat/.gitattributes
new file mode 100644
index 0000000000..40dbfb170d
--- /dev/null
+++ b/compat/.gitattributes
@@ -0,0 +1 @@
+/zlib-uncompress2.c	whitespace=-indent-with-non-tab,-trailing-space
diff --git a/compat/access.c b/compat/access.c
new file mode 100644
index 0000000000..19fda3e877
--- /dev/null
+++ b/compat/access.c
@@ -0,0 +1,31 @@
+#define COMPAT_CODE_ACCESS
+#include "../git-compat-util.h"
+
+/* Do the same thing access(2) does, but use the effective uid,
+ * and don't make the mistake of telling root that any file is
+ * executable.  This version uses stat(2).
+ */
+int git_access(const char *path, int mode)
+{
+	struct stat st;
+
+	/* do not interfere a normal user */
+	if (geteuid())
+		return access(path, mode);
+
+	if (stat(path, &st) < 0)
+		return -1;
+
+	/* Root can read or write any file. */
+	if (!(mode & X_OK))
+		return 0;
+
+	/* Root can execute any file that has any one of the execute
+	 * bits set.
+	 */
+	if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+		return 0;
+
+	errno = EACCES;
+	return -1;
+}
diff --git a/compat/apple-common-crypto.h b/compat/apple-common-crypto.h
new file mode 100644
index 0000000000..11727f3e1e
--- /dev/null
+++ b/compat/apple-common-crypto.h
@@ -0,0 +1,96 @@
+/* suppress inclusion of conflicting openssl functions */
+#define OPENSSL_NO_MD5
+#define HEADER_HMAC_H
+#define HEADER_SHA_H
+#include <CommonCrypto/CommonHMAC.h>
+#define EVP_md5(...) kCCHmacAlgMD5
+/* CCHmac doesn't take md_len and the return type is void */
+#define HMAC git_CC_HMAC
+static inline unsigned char *git_CC_HMAC(CCHmacAlgorithm alg,
+		const void *key, int key_len,
+		const unsigned char *data, size_t data_len,
+		unsigned char *md, unsigned int *md_len)
+{
+	CCHmac(alg, key, key_len, data, data_len, md);
+	return md;
+}
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
+#define APPLE_LION_OR_NEWER
+#include <Security/Security.h>
+/* Apple's TYPE_BOOL conflicts with config.c */
+#undef TYPE_BOOL
+#endif
+
+#ifndef SHA1_MAX_BLOCK_SIZE
+#error Using Apple Common Crypto library requires setting SHA1_MAX_BLOCK_SIZE
+#endif
+
+#ifdef APPLE_LION_OR_NEWER
+#define git_CC_error_check(pattern, err) \
+	do { \
+		if (err) { \
+			die(pattern, (long)CFErrorGetCode(err)); \
+		} \
+	} while(0)
+
+#define EVP_EncodeBlock git_CC_EVP_EncodeBlock
+static inline int git_CC_EVP_EncodeBlock(unsigned char *out,
+		const unsigned char *in, int inlen)
+{
+	CFErrorRef err;
+	SecTransformRef encoder;
+	CFDataRef input, output;
+	CFIndex length;
+
+	encoder = SecEncodeTransformCreate(kSecBase64Encoding, &err);
+	git_CC_error_check("SecEncodeTransformCreate failed: %ld", err);
+
+	input = CFDataCreate(kCFAllocatorDefault, in, inlen);
+	SecTransformSetAttribute(encoder, kSecTransformInputAttributeName,
+			input, &err);
+	git_CC_error_check("SecTransformSetAttribute failed: %ld", err);
+
+	output = SecTransformExecute(encoder, &err);
+	git_CC_error_check("SecTransformExecute failed: %ld", err);
+
+	length = CFDataGetLength(output);
+	CFDataGetBytes(output, CFRangeMake(0, length), out);
+
+	CFRelease(output);
+	CFRelease(input);
+	CFRelease(encoder);
+
+	return (int)strlen((const char *)out);
+}
+
+#define EVP_DecodeBlock git_CC_EVP_DecodeBlock
+static int inline git_CC_EVP_DecodeBlock(unsigned char *out,
+		const unsigned char *in, int inlen)
+{
+	CFErrorRef err;
+	SecTransformRef decoder;
+	CFDataRef input, output;
+	CFIndex length;
+
+	decoder = SecDecodeTransformCreate(kSecBase64Encoding, &err);
+	git_CC_error_check("SecEncodeTransformCreate failed: %ld", err);
+
+	input = CFDataCreate(kCFAllocatorDefault, in, inlen);
+	SecTransformSetAttribute(decoder, kSecTransformInputAttributeName,
+			input, &err);
+	git_CC_error_check("SecTransformSetAttribute failed: %ld", err);
+
+	output = SecTransformExecute(decoder, &err);
+	git_CC_error_check("SecTransformExecute failed: %ld", err);
+
+	length = CFDataGetLength(output);
+	CFDataGetBytes(output, CFRangeMake(0, length), out);
+
+	CFRelease(output);
+	CFRelease(input);
+	CFRelease(decoder);
+
+	return (int)strlen((const char *)out);
+}
+#endif /* APPLE_LION_OR_NEWER */
diff --git a/compat/basename.c b/compat/basename.c
new file mode 100644
index 0000000000..c33579ef61
--- /dev/null
+++ b/compat/basename.c
@@ -0,0 +1,83 @@
+#include "../git-compat-util.h"
+#include "../strbuf.h"
+
+/* Adapted from libiberty's basename.c.  */
+char *gitbasename (char *path)
+{
+	const char *base;
+
+	if (path)
+		skip_dos_drive_prefix(&path);
+
+	if (!path || !*path)
+		/*
+		 * basename(3P) is mis-specified because it returns a
+		 * non-constant pointer even though it is specified to return a
+		 * pointer to internal memory at times. The cast is a result of
+		 * that.
+		 */
+		return (char *) ".";
+
+	for (base = path; *path; path++) {
+		if (!is_dir_sep(*path))
+			continue;
+		do {
+			path++;
+		} while (is_dir_sep(*path));
+		if (*path)
+			base = path;
+		else
+			while (--path != base && is_dir_sep(*path))
+				*path = '\0';
+	}
+	return (char *)base;
+}
+
+char *gitdirname(char *path)
+{
+	static struct strbuf buf = STRBUF_INIT;
+	char *p = path, *slash = NULL, c;
+	int dos_drive_prefix;
+
+	if (!p)
+		/*
+		 * dirname(3P) is mis-specified because it returns a
+		 * non-constant pointer even though it is specified to return a
+		 * pointer to internal memory at times. The cast is a result of
+		 * that.
+		 */
+		return (char *) ".";
+
+	if ((dos_drive_prefix = skip_dos_drive_prefix(&p)) && !*p)
+		goto dot;
+
+	/*
+	 * POSIX.1-2001 says dirname("/") should return "/", and dirname("//")
+	 * should return "//", but dirname("///") should return "/" again.
+	 */
+	if (is_dir_sep(*p)) {
+		if (!p[1] || (is_dir_sep(p[1]) && !p[2]))
+			return path;
+		slash = ++p;
+	}
+	while ((c = *(p++)))
+		if (is_dir_sep(c)) {
+			char *tentative = p - 1;
+
+			/* POSIX.1-2001 says to ignore trailing slashes */
+			while (is_dir_sep(*p))
+				p++;
+			if (*p)
+				slash = tentative;
+		}
+
+	if (slash) {
+		*slash = '\0';
+		return path;
+	}
+
+dot:
+	strbuf_reset(&buf);
+	strbuf_addf(&buf, "%.*s.", dos_drive_prefix, path);
+	return buf.buf;
+}
diff --git a/compat/bswap.h b/compat/bswap.h
new file mode 100644
index 0000000000..b34054f2bd
--- /dev/null
+++ b/compat/bswap.h
@@ -0,0 +1,193 @@
+#ifndef COMPAT_BSWAP_H
+#define COMPAT_BSWAP_H
+
+/*
+ * Let's make sure we always have a sane definition for ntohl()/htonl().
+ * Some libraries define those as a function call, just to perform byte
+ * shifting, bringing significant overhead to what should be a simple
+ * operation.
+ */
+
+/*
+ * Default version that the compiler ought to optimize properly with
+ * constant values.
+ */
+static inline uint32_t default_swab32(uint32_t val)
+{
+	return (((val & 0xff000000) >> 24) |
+		((val & 0x00ff0000) >>  8) |
+		((val & 0x0000ff00) <<  8) |
+		((val & 0x000000ff) << 24));
+}
+
+static inline uint64_t default_bswap64(uint64_t val)
+{
+	return (((val & (uint64_t)0x00000000000000ffULL) << 56) |
+		((val & (uint64_t)0x000000000000ff00ULL) << 40) |
+		((val & (uint64_t)0x0000000000ff0000ULL) << 24) |
+		((val & (uint64_t)0x00000000ff000000ULL) <<  8) |
+		((val & (uint64_t)0x000000ff00000000ULL) >>  8) |
+		((val & (uint64_t)0x0000ff0000000000ULL) >> 24) |
+		((val & (uint64_t)0x00ff000000000000ULL) >> 40) |
+		((val & (uint64_t)0xff00000000000000ULL) >> 56));
+}
+
+#undef bswap32
+#undef bswap64
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+#define bswap32 git_bswap32
+static inline uint32_t git_bswap32(uint32_t x)
+{
+	uint32_t result;
+	if (__builtin_constant_p(x))
+		result = default_swab32(x);
+	else
+		__asm__("bswap %0" : "=r" (result) : "0" (x));
+	return result;
+}
+
+#define bswap64 git_bswap64
+#if defined(__x86_64__)
+static inline uint64_t git_bswap64(uint64_t x)
+{
+	uint64_t result;
+	if (__builtin_constant_p(x))
+		result = default_bswap64(x);
+	else
+		__asm__("bswap %q0" : "=r" (result) : "0" (x));
+	return result;
+}
+#else
+static inline uint64_t git_bswap64(uint64_t x)
+{
+	union { uint64_t i64; uint32_t i32[2]; } tmp, result;
+	if (__builtin_constant_p(x))
+		result.i64 = default_bswap64(x);
+	else {
+		tmp.i64 = x;
+		result.i32[0] = git_bswap32(tmp.i32[1]);
+		result.i32[1] = git_bswap32(tmp.i32[0]);
+	}
+	return result.i64;
+}
+#endif
+
+#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64))
+
+#include <stdlib.h>
+
+#define bswap32(x) _byteswap_ulong(x)
+#define bswap64(x) _byteswap_uint64(x)
+
+#endif
+
+#if defined(bswap32)
+
+#undef ntohl
+#undef htonl
+#define ntohl(x) bswap32(x)
+#define htonl(x) bswap32(x)
+
+#endif
+
+#if defined(bswap64)
+
+#undef ntohll
+#undef htonll
+#define ntohll(x) bswap64(x)
+#define htonll(x) bswap64(x)
+
+#else
+
+#undef ntohll
+#undef htonll
+
+#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN)
+
+# define GIT_BYTE_ORDER __BYTE_ORDER
+# define GIT_LITTLE_ENDIAN __LITTLE_ENDIAN
+# define GIT_BIG_ENDIAN __BIG_ENDIAN
+
+#elif defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
+
+# define GIT_BYTE_ORDER BYTE_ORDER
+# define GIT_LITTLE_ENDIAN LITTLE_ENDIAN
+# define GIT_BIG_ENDIAN BIG_ENDIAN
+
+#else
+
+# define GIT_BIG_ENDIAN 4321
+# define GIT_LITTLE_ENDIAN 1234
+
+# if defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
+#  define GIT_BYTE_ORDER GIT_BIG_ENDIAN
+# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+#  define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN
+# elif defined(__THW_BIG_ENDIAN__) && !defined(__THW_LITTLE_ENDIAN__)
+#  define GIT_BYTE_ORDER GIT_BIG_ENDIAN
+# elif defined(__THW_LITTLE_ENDIAN__) && !defined(__THW_BIG_ENDIAN__)
+#  define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN
+# else
+#  error "Cannot determine endianness"
+# endif
+
+#endif
+
+#if GIT_BYTE_ORDER == GIT_BIG_ENDIAN
+# define ntohll(n) (n)
+# define htonll(n) (n)
+#else
+# define ntohll(n) default_bswap64(n)
+# define htonll(n) default_bswap64(n)
+#endif
+
+#endif
+
+static inline uint16_t get_be16(const void *ptr)
+{
+	const unsigned char *p = ptr;
+	return	(uint16_t)p[0] << 8 |
+		(uint16_t)p[1] << 0;
+}
+
+static inline uint32_t get_be32(const void *ptr)
+{
+	const unsigned char *p = ptr;
+	return	(uint32_t)p[0] << 24 |
+		(uint32_t)p[1] << 16 |
+		(uint32_t)p[2] <<  8 |
+		(uint32_t)p[3] <<  0;
+}
+
+static inline uint64_t get_be64(const void *ptr)
+{
+	const unsigned char *p = ptr;
+	return	(uint64_t)get_be32(&p[0]) << 32 |
+		(uint64_t)get_be32(&p[4]) <<  0;
+}
+
+static inline void put_be32(void *ptr, uint32_t value)
+{
+	unsigned char *p = ptr;
+	p[0] = (value >> 24) & 0xff;
+	p[1] = (value >> 16) & 0xff;
+	p[2] = (value >>  8) & 0xff;
+	p[3] = (value >>  0) & 0xff;
+}
+
+static inline void put_be64(void *ptr, uint64_t value)
+{
+	unsigned char *p = ptr;
+	p[0] = (value >> 56) & 0xff;
+	p[1] = (value >> 48) & 0xff;
+	p[2] = (value >> 40) & 0xff;
+	p[3] = (value >> 32) & 0xff;
+	p[4] = (value >> 24) & 0xff;
+	p[5] = (value >> 16) & 0xff;
+	p[6] = (value >>  8) & 0xff;
+	p[7] = (value >>  0) & 0xff;
+}
+
+#endif /* COMPAT_BSWAP_H */
diff --git a/compat/compiler.h b/compat/compiler.h
new file mode 100644
index 0000000000..e12e426404
--- /dev/null
+++ b/compat/compiler.h
@@ -0,0 +1,40 @@
+#ifndef COMPILER_H
+#define COMPILER_H
+
+#include "strbuf.h"
+
+#ifdef __GLIBC__
+#include <gnu/libc-version.h>
+#endif
+
+static inline void get_compiler_info(struct strbuf *info)
+{
+	size_t len = info->len;
+#ifdef __clang__
+	strbuf_addf(info, "clang: %s\n", __clang_version__);
+#elif defined(__GNUC__)
+	strbuf_addf(info, "gnuc: %d.%d\n", __GNUC__, __GNUC_MINOR__);
+#endif
+
+#ifdef _MSC_VER
+	strbuf_addf(info, "MSVC version: %02d.%02d.%05d\n",
+		    _MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000);
+#endif
+
+	if (len == info->len)
+		strbuf_addstr(info, _("no compiler information available\n"));
+}
+
+static inline void get_libc_info(struct strbuf *info)
+{
+	size_t len = info->len;
+
+#ifdef __GLIBC__
+	strbuf_addf(info, "glibc: %s\n", gnu_get_libc_version());
+#endif
+
+	if (len == info->len)
+		strbuf_addstr(info, _("no libc information available\n"));
+}
+
+#endif /* COMPILER_H */
diff --git a/compat/disk.h b/compat/disk.h
new file mode 100644
index 0000000000..23bc1bef86
--- /dev/null
+++ b/compat/disk.h
@@ -0,0 +1,57 @@
+#ifndef COMPAT_DISK_H
+#define COMPAT_DISK_H
+
+#include "abspath.h"
+#include "gettext.h"
+
+static int get_disk_info(struct strbuf *out)
+{
+	struct strbuf buf = STRBUF_INIT;
+	int res = 0;
+
+#ifdef GIT_WINDOWS_NATIVE
+	char volume_name[MAX_PATH], fs_name[MAX_PATH];
+	DWORD serial_number, component_length, flags;
+	ULARGE_INTEGER avail2caller, total, avail;
+
+	strbuf_realpath(&buf, ".", 1);
+	if (!GetDiskFreeSpaceExA(buf.buf, &avail2caller, &total, &avail)) {
+		error(_("could not determine free disk size for '%s'"),
+		      buf.buf);
+		res = -1;
+		goto cleanup;
+	}
+
+	strbuf_setlen(&buf, offset_1st_component(buf.buf));
+	if (!GetVolumeInformationA(buf.buf, volume_name, sizeof(volume_name),
+				   &serial_number, &component_length, &flags,
+				   fs_name, sizeof(fs_name))) {
+		error(_("could not get info for '%s'"), buf.buf);
+		res = -1;
+		goto cleanup;
+	}
+	strbuf_addf(out, "Available space on '%s': ", buf.buf);
+	strbuf_humanise_bytes(out, avail2caller.QuadPart);
+	strbuf_addch(out, '\n');
+#else
+	struct statvfs stat;
+
+	strbuf_realpath(&buf, ".", 1);
+	if (statvfs(buf.buf, &stat) < 0) {
+		error_errno(_("could not determine free disk size for '%s'"),
+			    buf.buf);
+		res = -1;
+		goto cleanup;
+	}
+
+	strbuf_addf(out, "Available space on '%s': ", buf.buf);
+	strbuf_humanise_bytes(out, (off_t)stat.f_bsize * (off_t)stat.f_bavail);
+	strbuf_addf(out, " (mount flags 0x%lx)\n", stat.f_flag);
+#endif
+
+cleanup:
+	strbuf_release(&buf);
+	return res;
+}
+
+#endif /* COMPAT_DISK_H */
diff --git a/compat/fileno.c b/compat/fileno.c
new file mode 100644
index 0000000000..8e80ef335d
--- /dev/null
+++ b/compat/fileno.c
@@ -0,0 +1,7 @@
+#define COMPAT_CODE_FILENO
+#include "../git-compat-util.h"
+
+int git_fileno(FILE *stream)
+{
+	return fileno(stream);
+}
diff --git a/compat/fopen.c b/compat/fopen.c
new file mode 100644
index 0000000000..107b3e8182
--- /dev/null
+++ b/compat/fopen.c
@@ -0,0 +1,37 @@
+/*
+ *  The order of the following two lines is important.
+ *
+ *  SUPPRESS_FOPEN_REDEFINITION is defined before including git-compat-util.h
+ *  to avoid the redefinition of fopen within git-compat-util.h. This is
+ *  necessary since fopen is a macro on some platforms which may be set
+ *  based on compiler options. For example, on AIX fopen is set to fopen64
+ *  when _LARGE_FILES is defined. The previous technique of merely undefining
+ *  fopen after including git-compat-util.h is inadequate in this case.
+ */
+#define SUPPRESS_FOPEN_REDEFINITION
+#include "../git-compat-util.h"
+
+FILE *git_fopen(const char *path, const char *mode)
+{
+	FILE *fp;
+	struct stat st;
+
+	if (mode[0] == 'w' || mode[0] == 'a')
+		return fopen(path, mode);
+
+	if (!(fp = fopen(path, mode)))
+		return NULL;
+
+	if (fstat(fileno(fp), &st)) {
+		fclose(fp);
+		return NULL;
+	}
+
+	if (S_ISDIR(st.st_mode)) {
+		fclose(fp);
+		errno = EISDIR;
+		return NULL;
+	}
+
+	return fp;
+}
diff --git a/compat/fsmonitor/fsm-darwin-gcc.h b/compat/fsmonitor/fsm-darwin-gcc.h
new file mode 100644
index 0000000000..3496e29b3a
--- /dev/null
+++ b/compat/fsmonitor/fsm-darwin-gcc.h
@@ -0,0 +1,90 @@
+#ifndef FSM_DARWIN_GCC_H
+#define FSM_DARWIN_GCC_H
+
+#ifndef __clang__
+/*
+ * It is possible to #include CoreFoundation/CoreFoundation.h when compiling
+ * with clang, but not with GCC as of time of writing.
+ *
+ * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93082 for details.
+ */
+typedef unsigned int FSEventStreamCreateFlags;
+#define kFSEventStreamEventFlagNone               0x00000000
+#define kFSEventStreamEventFlagMustScanSubDirs    0x00000001
+#define kFSEventStreamEventFlagUserDropped        0x00000002
+#define kFSEventStreamEventFlagKernelDropped      0x00000004
+#define kFSEventStreamEventFlagEventIdsWrapped    0x00000008
+#define kFSEventStreamEventFlagHistoryDone        0x00000010
+#define kFSEventStreamEventFlagRootChanged        0x00000020
+#define kFSEventStreamEventFlagMount              0x00000040
+#define kFSEventStreamEventFlagUnmount            0x00000080
+#define kFSEventStreamEventFlagItemCreated        0x00000100
+#define kFSEventStreamEventFlagItemRemoved        0x00000200
+#define kFSEventStreamEventFlagItemInodeMetaMod   0x00000400
+#define kFSEventStreamEventFlagItemRenamed        0x00000800
+#define kFSEventStreamEventFlagItemModified       0x00001000
+#define kFSEventStreamEventFlagItemFinderInfoMod  0x00002000
+#define kFSEventStreamEventFlagItemChangeOwner    0x00004000
+#define kFSEventStreamEventFlagItemXattrMod       0x00008000
+#define kFSEventStreamEventFlagItemIsFile         0x00010000
+#define kFSEventStreamEventFlagItemIsDir          0x00020000
+#define kFSEventStreamEventFlagItemIsSymlink      0x00040000
+#define kFSEventStreamEventFlagOwnEvent           0x00080000
+#define kFSEventStreamEventFlagItemIsHardlink     0x00100000
+#define kFSEventStreamEventFlagItemIsLastHardlink 0x00200000
+#define kFSEventStreamEventFlagItemCloned         0x00400000
+
+typedef struct __FSEventStream *FSEventStreamRef;
+typedef const FSEventStreamRef ConstFSEventStreamRef;
+
+typedef unsigned int CFStringEncoding;
+#define kCFStringEncodingUTF8 0x08000100
+
+typedef const struct __CFString *CFStringRef;
+typedef const struct __CFArray *CFArrayRef;
+typedef const struct __CFRunLoop *CFRunLoopRef;
+
+struct FSEventStreamContext {
+    long long version;
+    void *cb_data, *retain, *release, *copy_description;
+};
+
+typedef struct FSEventStreamContext FSEventStreamContext;
+typedef unsigned int FSEventStreamEventFlags;
+#define kFSEventStreamCreateFlagNoDefer 0x02
+#define kFSEventStreamCreateFlagWatchRoot 0x04
+#define kFSEventStreamCreateFlagFileEvents 0x10
+
+typedef unsigned long long FSEventStreamEventId;
+#define kFSEventStreamEventIdSinceNow 0xFFFFFFFFFFFFFFFFULL
+
+typedef void (*FSEventStreamCallback)(ConstFSEventStreamRef streamRef,
+				      void *context,
+				      __SIZE_TYPE__ num_of_events,
+				      void *event_paths,
+				      const FSEventStreamEventFlags event_flags[],
+				      const FSEventStreamEventId event_ids[]);
+typedef double CFTimeInterval;
+FSEventStreamRef FSEventStreamCreate(void *allocator,
+				     FSEventStreamCallback callback,
+				     FSEventStreamContext *context,
+				     CFArrayRef paths_to_watch,
+				     FSEventStreamEventId since_when,
+				     CFTimeInterval latency,
+				     FSEventStreamCreateFlags flags);
+CFStringRef CFStringCreateWithCString(void *allocator, const char *string,
+				      CFStringEncoding encoding);
+CFArrayRef CFArrayCreate(void *allocator, const void **items, long long count,
+			 void *callbacks);
+void CFRunLoopRun(void);
+void CFRunLoopStop(CFRunLoopRef run_loop);
+CFRunLoopRef CFRunLoopGetCurrent(void);
+extern CFStringRef kCFRunLoopDefaultMode;
+void FSEventStreamSetDispatchQueue(FSEventStreamRef stream, dispatch_queue_t q);
+unsigned char FSEventStreamStart(FSEventStreamRef stream);
+void FSEventStreamStop(FSEventStreamRef stream);
+void FSEventStreamInvalidate(FSEventStreamRef stream);
+void FSEventStreamRelease(FSEventStreamRef stream);
+
+#endif /* !clang */
+#endif /* FSM_DARWIN_GCC_H */
diff --git a/compat/fsmonitor/fsm-health-darwin.c b/compat/fsmonitor/fsm-health-darwin.c
new file mode 100644
index 0000000000..c2afcbe6c8
--- /dev/null
+++ b/compat/fsmonitor/fsm-health-darwin.c
@@ -0,0 +1,24 @@
+#include "git-compat-util.h"
+#include "config.h"
+#include "fsmonitor-ll.h"
+#include "fsm-health.h"
+#include "fsmonitor--daemon.h"
+
+int fsm_health__ctor(struct fsmonitor_daemon_state *state UNUSED)
+{
+	return 0;
+}
+
+void fsm_health__dtor(struct fsmonitor_daemon_state *state UNUSED)
+{
+	return;
+}
+
+void fsm_health__loop(struct fsmonitor_daemon_state *state UNUSED)
+{
+	return;
+}
+
+void fsm_health__stop_async(struct fsmonitor_daemon_state *state UNUSED)
+{
+}
diff --git a/compat/fsmonitor/fsm-health-win32.c b/compat/fsmonitor/fsm-health-win32.c
new file mode 100644
index 0000000000..2aa8c219ac
--- /dev/null
+++ b/compat/fsmonitor/fsm-health-win32.c
@@ -0,0 +1,280 @@
+#include "git-compat-util.h"
+#include "config.h"
+#include "fsmonitor-ll.h"
+#include "fsm-health.h"
+#include "fsmonitor--daemon.h"
+#include "gettext.h"
+#include "simple-ipc.h"
+
+/*
+ * Every minute wake up and test our health.
+ */
+#define WAIT_FREQ_MS (60 * 1000)
+
+/*
+ * State machine states for each of the interval functions
+ * used for polling our health.
+ */
+enum interval_fn_ctx {
+	CTX_INIT = 0,
+	CTX_TERM,
+	CTX_TIMER
+};
+
+typedef int (interval_fn)(struct fsmonitor_daemon_state *state,
+			  enum interval_fn_ctx ctx);
+
+struct fsm_health_data
+{
+	HANDLE hEventShutdown;
+
+	HANDLE hHandles[1]; /* the array does not own these handles */
+#define HEALTH_SHUTDOWN 0
+	int nr_handles; /* number of active event handles */
+
+	struct wt_moved
+	{
+		wchar_t wpath[MAX_PATH + 1];
+		BY_HANDLE_FILE_INFORMATION bhfi;
+	} wt_moved;
+};
+
+/*
+ * Lookup the system unique ID for the path.  This is as close as
+ * we get to an inode number, but this also contains volume info,
+ * so it is a little stronger.
+ */
+static int lookup_bhfi(wchar_t *wpath,
+		       BY_HANDLE_FILE_INFORMATION *bhfi)
+{
+	DWORD desired_access = FILE_LIST_DIRECTORY;
+	DWORD share_mode =
+		FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
+	HANDLE hDir;
+
+	hDir = CreateFileW(wpath, desired_access, share_mode, NULL,
+			   OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+	if (hDir == INVALID_HANDLE_VALUE) {
+		error(_("[GLE %ld] health thread could not open '%ls'"),
+		      GetLastError(), wpath);
+		return -1;
+	}
+
+	if (!GetFileInformationByHandle(hDir, bhfi)) {
+		error(_("[GLE %ld] health thread getting BHFI for '%ls'"),
+		      GetLastError(), wpath);
+		CloseHandle(hDir);
+		return -1;
+	}
+
+	CloseHandle(hDir);
+	return 0;
+}
+
+/*
+ * Compare the relevant fields from two system unique IDs.
+ * We use this to see if two different handles to the same
+ * path actually refer to the same *instance* of the file
+ * or directory.
+ */
+static int bhfi_eq(const BY_HANDLE_FILE_INFORMATION *bhfi_1,
+		   const BY_HANDLE_FILE_INFORMATION *bhfi_2)
+{
+	return (bhfi_1->dwVolumeSerialNumber == bhfi_2->dwVolumeSerialNumber &&
+		bhfi_1->nFileIndexHigh == bhfi_2->nFileIndexHigh &&
+		bhfi_1->nFileIndexLow == bhfi_2->nFileIndexLow);
+}
+
+/*
+ * Shutdown if the original worktree root directory been deleted,
+ * moved, or renamed?
+ *
+ * Since the main thread did a "chdir(getenv($HOME))" and our CWD
+ * is not in the worktree root directory and because the listener
+ * thread added FILE_SHARE_DELETE to the watch handle, it is possible
+ * for the root directory to be moved or deleted while we are still
+ * watching it.  We want to detect that here and force a shutdown.
+ *
+ * Granted, a delete MAY cause some operations to fail, such as
+ * GetOverlappedResult(), but it is not guaranteed.  And because
+ * ReadDirectoryChangesW() only reports on changes *WITHIN* the
+ * directory, not changes *ON* the directory, our watch will not
+ * receive a delete event for it.
+ *
+ * A move/rename of the worktree root will also not generate an event.
+ * And since the listener thread already has an open handle, it may
+ * continue to receive events for events within the directory.
+ * However, the pathname of the named-pipe was constructed using the
+ * original location of the worktree root.  (Remember named-pipes are
+ * stored in the NPFS and not in the actual file system.)  Clients
+ * trying to talk to the worktree after the move/rename will not
+ * reach our daemon process, since we're still listening on the
+ * pipe with original path.
+ *
+ * Furthermore, if the user does something like:
+ *
+ *   $ mv repo repo.old
+ *   $ git init repo
+ *
+ * A new daemon cannot be started in the new instance of "repo"
+ * because the named-pipe is still being used by the daemon on
+ * the original instance.
+ *
+ * So, detect move/rename/delete and shutdown.  This should also
+ * handle unsafe drive removal.
+ *
+ * We use the file system unique ID to distinguish the original
+ * directory instance from a new instance and force a shutdown
+ * if the unique ID changes.
+ *
+ * Since a worktree move/rename/delete/unmount doesn't happen
+ * that often (and we can't get an immediate event anyway), we
+ * use a timeout and periodically poll it.
+ */
+static int has_worktree_moved(struct fsmonitor_daemon_state *state,
+			      enum interval_fn_ctx ctx)
+{
+	struct fsm_health_data *data = state->health_data;
+	BY_HANDLE_FILE_INFORMATION bhfi;
+	int r;
+
+	switch (ctx) {
+	case CTX_TERM:
+		return 0;
+
+	case CTX_INIT:
+		if (xutftowcs_path(data->wt_moved.wpath,
+				   state->path_worktree_watch.buf) < 0) {
+			error(_("could not convert to wide characters: '%s'"),
+			      state->path_worktree_watch.buf);
+			return -1;
+		}
+
+		/*
+		 * On the first call we lookup the unique sequence ID for
+		 * the worktree root directory.
+		 */
+		return lookup_bhfi(data->wt_moved.wpath, &data->wt_moved.bhfi);
+
+	case CTX_TIMER:
+		r = lookup_bhfi(data->wt_moved.wpath, &bhfi);
+		if (r)
+			return r;
+		if (!bhfi_eq(&data->wt_moved.bhfi, &bhfi)) {
+			error(_("BHFI changed '%ls'"), data->wt_moved.wpath);
+			return -1;
+		}
+		return 0;
+
+	default:
+		die(_("unhandled case in 'has_worktree_moved': %d"),
+		    (int)ctx);
+	}
+
+	return 0;
+}
+
+
+int fsm_health__ctor(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_health_data *data;
+
+	CALLOC_ARRAY(data, 1);
+
+	data->hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+	data->hHandles[HEALTH_SHUTDOWN] = data->hEventShutdown;
+	data->nr_handles++;
+
+	state->health_data = data;
+	return 0;
+}
+
+void fsm_health__dtor(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_health_data *data;
+
+	if (!state || !state->health_data)
+		return;
+
+	data = state->health_data;
+
+	CloseHandle(data->hEventShutdown);
+
+	FREE_AND_NULL(state->health_data);
+}
+
+/*
+ * A table of the polling functions.
+ */
+static interval_fn *table[] = {
+	has_worktree_moved,
+	NULL, /* must be last */
+};
+
+/*
+ * Call all of the polling functions in the table.
+ * Shortcut and return first error.
+ *
+ * Return 0 if all succeeded.
+ */
+static int call_all(struct fsmonitor_daemon_state *state,
+		    enum interval_fn_ctx ctx)
+{
+	int k;
+
+	for (k = 0; table[k]; k++) {
+		int r = table[k](state, ctx);
+		if (r)
+			return r;
+	}
+
+	return 0;
+}
+
+void fsm_health__loop(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_health_data *data = state->health_data;
+	int r;
+
+	r = call_all(state, CTX_INIT);
+	if (r < 0)
+		goto force_error_stop;
+	if (r > 0)
+		goto force_shutdown;
+
+	for (;;) {
+		DWORD dwWait = WaitForMultipleObjects(data->nr_handles,
+						      data->hHandles,
+						      FALSE, WAIT_FREQ_MS);
+
+		if (dwWait == WAIT_OBJECT_0 + HEALTH_SHUTDOWN)
+			goto clean_shutdown;
+
+		if (dwWait == WAIT_TIMEOUT) {
+			r = call_all(state, CTX_TIMER);
+			if (r < 0)
+				goto force_error_stop;
+			if (r > 0)
+				goto force_shutdown;
+			continue;
+		}
+
+		error(_("health thread wait failed [GLE %ld]"),
+		      GetLastError());
+		goto force_error_stop;
+	}
+
+force_error_stop:
+	state->health_error_code = -1;
+force_shutdown:
+	ipc_server_stop_async(state->ipc_server_data);
+clean_shutdown:
+	call_all(state, CTX_TERM);
+	return;
+}
+
+void fsm_health__stop_async(struct fsmonitor_daemon_state *state)
+{
+	SetEvent(state->health_data->hHandles[HEALTH_SHUTDOWN]);
+}
diff --git a/compat/fsmonitor/fsm-health.h b/compat/fsmonitor/fsm-health.h
new file mode 100644
index 0000000000..45547ba938
--- /dev/null
+++ b/compat/fsmonitor/fsm-health.h
@@ -0,0 +1,47 @@
+#ifndef FSM_HEALTH_H
+#define FSM_HEALTH_H
+
+/* This needs to be implemented by each backend */
+
+#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
+
+struct fsmonitor_daemon_state;
+
+/*
+ * Initialize platform-specific data for the fsmonitor health thread.
+ * This will be called from the main thread PRIOR to staring the
+ * thread.
+ *
+ * Returns 0 if successful.
+ * Returns -1 otherwise.
+ */
+int fsm_health__ctor(struct fsmonitor_daemon_state *state);
+
+/*
+ * Cleanup platform-specific data for the health thread.
+ * This will be called from the main thread AFTER joining the thread.
+ */
+void fsm_health__dtor(struct fsmonitor_daemon_state *state);
+
+/*
+ * The main body of the platform-specific event loop to monitor the
+ * health of the daemon process.  This will run in the health thread.
+ *
+ * The health thread should call `ipc_server_stop_async()` if it needs
+ * to cause a shutdown.  (It should NOT do so if it receives a shutdown
+ * shutdown signal.)
+ *
+ * It should set `state->health_error_code` to -1 if the daemon should exit
+ * with an error.
+ */
+void fsm_health__loop(struct fsmonitor_daemon_state *state);
+
+/*
+ * Gently request that the health thread shutdown.
+ * It does not wait for it to stop.  The caller should do a JOIN
+ * to wait for it.
+ */
+void fsm_health__stop_async(struct fsmonitor_daemon_state *state);
+
+#endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
+#endif /* FSM_HEALTH_H */
diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c
new file mode 100644
index 0000000000..fe149a1b37
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-darwin.c
@@ -0,0 +1,59 @@
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "gettext.h"
+#include "hex.h"
+#include "path.h"
+#include "repository.h"
+#include "strbuf.h"
+#include "fsmonitor-ll.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-path-utils.h"
+
+static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc")
+
+const char *fsmonitor_ipc__get_path(struct repository *r)
+{
+	static const char *ipc_path = NULL;
+	git_SHA_CTX sha1ctx;
+	char *sock_dir = NULL;
+	struct strbuf ipc_file = STRBUF_INIT;
+	unsigned char hash[GIT_SHA1_RAWSZ];
+
+	if (!r)
+		BUG("No repository passed into fsmonitor_ipc__get_path");
+
+	if (ipc_path)
+		return ipc_path;
+
+
+	/* By default the socket file is created in the .git directory */
+	if (fsmonitor__is_fs_remote(r->gitdir) < 1) {
+		ipc_path = fsmonitor_ipc__get_default_path();
+		return ipc_path;
+	}
+
+	git_SHA1_Init(&sha1ctx);
+	git_SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree));
+	git_SHA1_Final(hash, &sha1ctx);
+
+	repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir);
+
+	/* Create the socket file in either socketDir or $HOME */
+	if (sock_dir && *sock_dir) {
+		strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s",
+			    sock_dir, hash_to_hex_algop(hash, &hash_algos[GIT_HASH_SHA1]));
+	} else {
+		strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s",
+			    hash_to_hex_algop(hash, &hash_algos[GIT_HASH_SHA1]));
+	}
+	free(sock_dir);
+
+	ipc_path = interpolate_path(ipc_file.buf, 1);
+	if (!ipc_path)
+		die(_("Invalid path: %s"), ipc_file.buf);
+
+	strbuf_release(&ipc_file);
+	return ipc_path;
+}
diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c
new file mode 100644
index 0000000000..41984ea48e
--- /dev/null
+++ b/compat/fsmonitor/fsm-ipc-win32.c
@@ -0,0 +1,11 @@
+#include "git-compat-util.h"
+#include "config.h"
+#include "fsmonitor-ipc.h"
+#include "path.h"
+
+const char *fsmonitor_ipc__get_path(struct repository *r) {
+	static char *ret;
+	if (!ret)
+		ret = repo_git_path(r, "fsmonitor--daemon.ipc");
+	return ret;
+}
diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c
new file mode 100644
index 0000000000..43c3a915a0
--- /dev/null
+++ b/compat/fsmonitor/fsm-listen-darwin.c
@@ -0,0 +1,545 @@
+#ifndef __clang__
+#include <dispatch/dispatch.h>
+#include "fsm-darwin-gcc.h"
+#else
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreServices/CoreServices.h>
+
+#ifndef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
+/*
+ * This enum value was added in 10.13 to:
+ *
+ * /Applications/Xcode.app/Contents/Developer/Platforms/ \
+ *    MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/ \
+ *    Library/Frameworks/CoreServices.framework/Frameworks/ \
+ *    FSEvents.framework/Versions/Current/Headers/FSEvents.h
+ *
+ * If we're compiling against an older SDK, this symbol won't be
+ * present.  Silently define it here so that we don't have to ifdef
+ * the logging or masking below.  This should be harmless since older
+ * versions of macOS won't ever emit this FS event anyway.
+ */
+#define kFSEventStreamEventFlagItemCloned         0x00400000
+#endif
+#endif
+
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
+#include "fsm-listen.h"
+#include "fsmonitor--daemon.h"
+#include "fsmonitor-path-utils.h"
+#include "gettext.h"
+#include "simple-ipc.h"
+#include "string-list.h"
+#include "trace.h"
+
+struct fsm_listen_data
+{
+	CFStringRef cfsr_worktree_path;
+	CFStringRef cfsr_gitdir_path;
+
+	CFArrayRef cfar_paths_to_watch;
+	int nr_paths_watching;
+
+	FSEventStreamRef stream;
+
+	dispatch_queue_t dq;
+	pthread_cond_t dq_finished;
+	pthread_mutex_t dq_lock;
+
+	enum shutdown_style {
+		SHUTDOWN_EVENT = 0,
+		FORCE_SHUTDOWN,
+		FORCE_ERROR_STOP,
+	} shutdown_style;
+
+	unsigned int stream_scheduled:1;
+	unsigned int stream_started:1;
+};
+
+static void log_flags_set(const char *path, const FSEventStreamEventFlags flag)
+{
+	struct strbuf msg = STRBUF_INIT;
+
+	if (flag & kFSEventStreamEventFlagMustScanSubDirs)
+		strbuf_addstr(&msg, "MustScanSubDirs|");
+	if (flag & kFSEventStreamEventFlagUserDropped)
+		strbuf_addstr(&msg, "UserDropped|");
+	if (flag & kFSEventStreamEventFlagKernelDropped)
+		strbuf_addstr(&msg, "KernelDropped|");
+	if (flag & kFSEventStreamEventFlagEventIdsWrapped)
+		strbuf_addstr(&msg, "EventIdsWrapped|");
+	if (flag & kFSEventStreamEventFlagHistoryDone)
+		strbuf_addstr(&msg, "HistoryDone|");
+	if (flag & kFSEventStreamEventFlagRootChanged)
+		strbuf_addstr(&msg, "RootChanged|");
+	if (flag & kFSEventStreamEventFlagMount)
+		strbuf_addstr(&msg, "Mount|");
+	if (flag & kFSEventStreamEventFlagUnmount)
+		strbuf_addstr(&msg, "Unmount|");
+	if (flag & kFSEventStreamEventFlagItemChangeOwner)
+		strbuf_addstr(&msg, "ItemChangeOwner|");
+	if (flag & kFSEventStreamEventFlagItemCreated)
+		strbuf_addstr(&msg, "ItemCreated|");
+	if (flag & kFSEventStreamEventFlagItemFinderInfoMod)
+		strbuf_addstr(&msg, "ItemFinderInfoMod|");
+	if (flag & kFSEventStreamEventFlagItemInodeMetaMod)
+		strbuf_addstr(&msg, "ItemInodeMetaMod|");
+	if (flag & kFSEventStreamEventFlagItemIsDir)
+		strbuf_addstr(&msg, "ItemIsDir|");
+	if (flag & kFSEventStreamEventFlagItemIsFile)
+		strbuf_addstr(&msg, "ItemIsFile|");
+	if (flag & kFSEventStreamEventFlagItemIsHardlink)
+		strbuf_addstr(&msg, "ItemIsHardlink|");
+	if (flag & kFSEventStreamEventFlagItemIsLastHardlink)
+		strbuf_addstr(&msg, "ItemIsLastHardlink|");
+	if (flag & kFSEventStreamEventFlagItemIsSymlink)
+		strbuf_addstr(&msg, "ItemIsSymlink|");
+	if (flag & kFSEventStreamEventFlagItemModified)
+		strbuf_addstr(&msg, "ItemModified|");
+	if (flag & kFSEventStreamEventFlagItemRemoved)
+		strbuf_addstr(&msg, "ItemRemoved|");
+	if (flag & kFSEventStreamEventFlagItemRenamed)
+		strbuf_addstr(&msg, "ItemRenamed|");
+	if (flag & kFSEventStreamEventFlagItemXattrMod)
+		strbuf_addstr(&msg, "ItemXattrMod|");
+	if (flag & kFSEventStreamEventFlagOwnEvent)
+		strbuf_addstr(&msg, "OwnEvent|");
+	if (flag & kFSEventStreamEventFlagItemCloned)
+		strbuf_addstr(&msg, "ItemCloned|");
+
+	trace_printf_key(&trace_fsmonitor, "fsevent: '%s', flags=0x%x %s",
+			 path, flag, msg.buf);
+
+	strbuf_release(&msg);
+}
+
+static int ef_is_root_changed(const FSEventStreamEventFlags ef)
+{
+	return (ef & kFSEventStreamEventFlagRootChanged);
+}
+
+static int ef_is_root_delete(const FSEventStreamEventFlags ef)
+{
+	return (ef & kFSEventStreamEventFlagItemIsDir &&
+		ef & kFSEventStreamEventFlagItemRemoved);
+}
+
+static int ef_is_root_renamed(const FSEventStreamEventFlags ef)
+{
+	return (ef & kFSEventStreamEventFlagItemIsDir &&
+		ef & kFSEventStreamEventFlagItemRenamed);
+}
+
+static int ef_is_dropped(const FSEventStreamEventFlags ef)
+{
+	return (ef & kFSEventStreamEventFlagMustScanSubDirs ||
+		ef & kFSEventStreamEventFlagKernelDropped ||
+		ef & kFSEventStreamEventFlagUserDropped);
+}
+
+/*
+ * If an `xattr` change is the only reason we received this event,
+ * then silently ignore it.  Git doesn't care about xattr's.  We
+ * have to be careful here because the kernel can combine multiple
+ * events for a single path.  And because events always have certain
+ * bits set, such as `ItemIsFile` or `ItemIsDir`.
+ *
+ * Return 1 if we should ignore it.
+ */
+static int ef_ignore_xattr(const FSEventStreamEventFlags ef)
+{
+	static const FSEventStreamEventFlags mask =
+		kFSEventStreamEventFlagItemChangeOwner |
+		kFSEventStreamEventFlagItemCreated |
+		kFSEventStreamEventFlagItemFinderInfoMod |
+		kFSEventStreamEventFlagItemInodeMetaMod |
+		kFSEventStreamEventFlagItemModified |
+		kFSEventStreamEventFlagItemRemoved |
+		kFSEventStreamEventFlagItemRenamed |
+		kFSEventStreamEventFlagItemXattrMod |
+		kFSEventStreamEventFlagItemCloned;
+
+	return ((ef & mask) == kFSEventStreamEventFlagItemXattrMod);
+}
+
+/*
+ * On MacOS we have to adjust for Unicode composition insensitivity
+ * (where NFC and NFD spellings are not respected).  The different
+ * spellings are essentially aliases regardless of how the path is
+ * actually stored on the disk.
+ *
+ * This is related to "core.precomposeUnicode" (which wants to try
+ * to hide NFD completely and treat everything as NFC).  Here, we
+ * don't know what the value the client has (or will have) for this
+ * config setting when they make a query, so assume the worst and
+ * emit both when the OS gives us an NFD path.
+ */
+static void my_add_path(struct fsmonitor_batch *batch, const char *path)
+{
+	char *composed;
+
+	/* add the NFC or NFD path as received from the OS */
+	fsmonitor_batch__add_path(batch, path);
+
+	/* if NFD, also add the corresponding NFC spelling */
+	composed = (char *)precompose_string_if_needed(path);
+	if (!composed || composed == path)
+		return;
+
+	fsmonitor_batch__add_path(batch, composed);
+	free(composed);
+}
+
+
+static void fsevent_callback(ConstFSEventStreamRef streamRef UNUSED,
+			     void *ctx,
+			     size_t num_of_events,
+			     void *event_paths,
+			     const FSEventStreamEventFlags event_flags[],
+			     const FSEventStreamEventId event_ids[] UNUSED)
+{
+	struct fsmonitor_daemon_state *state = ctx;
+	struct fsm_listen_data *data = state->listen_data;
+	char **paths = (char **)event_paths;
+	struct fsmonitor_batch *batch = NULL;
+	struct string_list cookie_list = STRING_LIST_INIT_DUP;
+	const char *path_k;
+	const char *slash;
+	char *resolved = NULL;
+	struct strbuf tmp = STRBUF_INIT;
+
+	/*
+	 * Build a list of all filesystem changes into a private/local
+	 * list and without holding any locks.
+	 */
+	for (size_t k = 0; k < num_of_events; k++) {
+		/*
+		 * On Mac, we receive an array of absolute paths.
+		 */
+		free(resolved);
+		resolved = fsmonitor__resolve_alias(paths[k], &state->alias);
+		if (resolved)
+			path_k = resolved;
+		else
+			path_k = paths[k];
+
+		/*
+		 * If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR.
+		 * Please don't log them to Trace2.
+		 *
+		 * trace_printf_key(&trace_fsmonitor, "Path: '%s'", path_k);
+		 */
+
+		/*
+		 * If event[k] is marked as dropped, we assume that we have
+		 * lost sync with the filesystem and should flush our cached
+		 * data.  We need to:
+		 *
+		 * [1] Abort/wake any client threads waiting for a cookie and
+		 *     flush the cached state data (the current token), and
+		 *     create a new token.
+		 *
+		 * [2] Discard the batch that we were locally building (since
+		 *     they are conceptually relative to the just flushed
+		 *     token).
+		 */
+		if (ef_is_dropped(event_flags[k])) {
+			if (trace_pass_fl(&trace_fsmonitor))
+				log_flags_set(path_k, event_flags[k]);
+
+			fsmonitor_force_resync(state);
+			fsmonitor_batch__free_list(batch);
+			string_list_clear(&cookie_list, 0);
+			batch = NULL;
+
+			/*
+			 * We assume that any events that we received
+			 * in this callback after this dropped event
+			 * may still be valid, so we continue rather
+			 * than break.  (And just in case there is a
+			 * delete of ".git" hiding in there.)
+			 */
+			continue;
+		}
+
+		if (ef_is_root_changed(event_flags[k])) {
+			/*
+			 * The spelling of the pathname of the root directory
+			 * has changed.  This includes the name of the root
+			 * directory itself or of any parent directory in the
+			 * path.
+			 *
+			 * (There may be other conditions that throw this,
+			 * but I couldn't find any information on it.)
+			 *
+			 * Force a shutdown now and avoid things getting
+			 * out of sync.  The Unix domain socket is inside
+			 * the .git directory and a spelling change will make
+			 * it hard for clients to rendezvous with us.
+			 */
+			trace_printf_key(&trace_fsmonitor,
+					 "event: root changed");
+			goto force_shutdown;
+		}
+
+		if (ef_ignore_xattr(event_flags[k])) {
+			trace_printf_key(&trace_fsmonitor,
+					 "ignore-xattr: '%s', flags=0x%x",
+					 path_k, event_flags[k]);
+			continue;
+		}
+
+		switch (fsmonitor_classify_path_absolute(state, path_k)) {
+
+		case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX:
+		case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX:
+			/* special case cookie files within .git or gitdir */
+
+			/* Use just the filename of the cookie file. */
+			slash = find_last_dir_sep(path_k);
+			string_list_append(&cookie_list,
+					   slash ? slash + 1 : path_k);
+			break;
+
+		case IS_INSIDE_DOT_GIT:
+		case IS_INSIDE_GITDIR:
+			/* ignore all other paths inside of .git or gitdir */
+			break;
+
+		case IS_DOT_GIT:
+		case IS_GITDIR:
+			/*
+			 * If .git directory is deleted or renamed away,
+			 * we have to quit.
+			 */
+			if (ef_is_root_delete(event_flags[k])) {
+				trace_printf_key(&trace_fsmonitor,
+						 "event: gitdir removed");
+				goto force_shutdown;
+			}
+			if (ef_is_root_renamed(event_flags[k])) {
+				trace_printf_key(&trace_fsmonitor,
+						 "event: gitdir renamed");
+				goto force_shutdown;
+			}
+			break;
+
+		case IS_WORKDIR_PATH:
+			/* try to queue normal pathnames */
+
+			if (trace_pass_fl(&trace_fsmonitor))
+				log_flags_set(path_k, event_flags[k]);
+
+			/*
+			 * Because of the implicit "binning" (the
+			 * kernel calls us at a given frequency) and
+			 * de-duping (the kernel is free to combine
+			 * multiple events for a given pathname), an
+			 * individual fsevent could be marked as both
+			 * a file and directory.  Add it to the queue
+			 * with both spellings so that the client will
+			 * know how much to invalidate/refresh.
+			 */
+
+			if (event_flags[k] & (kFSEventStreamEventFlagItemIsFile | kFSEventStreamEventFlagItemIsSymlink)) {
+				const char *rel = path_k +
+					state->path_worktree_watch.len + 1;
+
+				if (!batch)
+					batch = fsmonitor_batch__new();
+				my_add_path(batch, rel);
+			}
+
+			if (event_flags[k] & kFSEventStreamEventFlagItemIsDir) {
+				const char *rel = path_k +
+					state->path_worktree_watch.len + 1;
+
+				strbuf_reset(&tmp);
+				strbuf_addstr(&tmp, rel);
+				strbuf_addch(&tmp, '/');
+
+				if (!batch)
+					batch = fsmonitor_batch__new();
+				my_add_path(batch, tmp.buf);
+			}
+
+			break;
+
+		case IS_OUTSIDE_CONE:
+		default:
+			trace_printf_key(&trace_fsmonitor,
+					 "ignoring '%s'", path_k);
+			break;
+		}
+	}
+
+	free(resolved);
+	fsmonitor_publish(state, batch, &cookie_list);
+	string_list_clear(&cookie_list, 0);
+	strbuf_release(&tmp);
+	return;
+
+force_shutdown:
+	free(resolved);
+	fsmonitor_batch__free_list(batch);
+	string_list_clear(&cookie_list, 0);
+
+	pthread_mutex_lock(&data->dq_lock);
+	data->shutdown_style = FORCE_SHUTDOWN;
+	pthread_cond_broadcast(&data->dq_finished);
+	pthread_mutex_unlock(&data->dq_lock);
+
+	strbuf_release(&tmp);
+	return;
+}
+
+/*
+ * In the call to `FSEventStreamCreate()` to setup our watch, the
+ * `latency` argument determines the frequency of calls to our callback
+ * with new FS events.  Too slow and events get dropped; too fast and
+ * we burn CPU unnecessarily.  Since it is rather obscure, I don't
+ * think this needs to be a config setting.  I've done extensive
+ * testing on my systems and chosen the value below.  It gives good
+ * results and I've not seen any dropped events.
+ *
+ * With a latency of 0.1, I was seeing lots of dropped events during
+ * the "touch 100000" files test within t/perf/p7519, but with a
+ * latency of 0.001 I did not see any dropped events.  So I'm going
+ * to assume that this is the "correct" value.
+ *
+ * https://developer.apple.com/documentation/coreservices/1443980-fseventstreamcreate
+ */
+
+int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
+{
+	FSEventStreamCreateFlags flags = kFSEventStreamCreateFlagNoDefer |
+		kFSEventStreamCreateFlagWatchRoot |
+		kFSEventStreamCreateFlagFileEvents;
+	FSEventStreamContext ctx = {
+		0,
+		state,
+		NULL,
+		NULL,
+		NULL
+	};
+	struct fsm_listen_data *data;
+	const void *dir_array[2];
+
+	CALLOC_ARRAY(data, 1);
+	state->listen_data = data;
+
+	data->cfsr_worktree_path = CFStringCreateWithCString(
+		NULL, state->path_worktree_watch.buf, kCFStringEncodingUTF8);
+	dir_array[data->nr_paths_watching++] = data->cfsr_worktree_path;
+
+	if (state->nr_paths_watching > 1) {
+		data->cfsr_gitdir_path = CFStringCreateWithCString(
+			NULL, state->path_gitdir_watch.buf,
+			kCFStringEncodingUTF8);
+		dir_array[data->nr_paths_watching++] = data->cfsr_gitdir_path;
+	}
+
+	data->cfar_paths_to_watch = CFArrayCreate(NULL, dir_array,
+						  data->nr_paths_watching,
+						  NULL);
+	data->stream = FSEventStreamCreate(NULL, fsevent_callback, &ctx,
+					   data->cfar_paths_to_watch,
+					   kFSEventStreamEventIdSinceNow,
+					   0.001, flags);
+	if (!data->stream)
+		goto failed;
+
+	return 0;
+
+failed:
+	error(_("Unable to create FSEventStream."));
+
+	FREE_AND_NULL(state->listen_data);
+	return -1;
+}
+
+void fsm_listen__dtor(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_listen_data *data;
+
+	if (!state || !state->listen_data)
+		return;
+
+	data = state->listen_data;
+
+	if (data->stream) {
+		if (data->stream_started)
+			FSEventStreamStop(data->stream);
+		if (data->stream_scheduled)
+			FSEventStreamInvalidate(data->stream);
+		FSEventStreamRelease(data->stream);
+	}
+
+	if (data->dq)
+		dispatch_release(data->dq);
+	pthread_cond_destroy(&data->dq_finished);
+	pthread_mutex_destroy(&data->dq_lock);
+
+	FREE_AND_NULL(state->listen_data);
+}
+
+void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_listen_data *data;
+
+	data = state->listen_data;
+
+	pthread_mutex_lock(&data->dq_lock);
+	data->shutdown_style = SHUTDOWN_EVENT;
+	pthread_cond_broadcast(&data->dq_finished);
+	pthread_mutex_unlock(&data->dq_lock);
+}
+
+void fsm_listen__loop(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_listen_data *data;
+
+	data = state->listen_data;
+
+	pthread_mutex_init(&data->dq_lock, NULL);
+	pthread_cond_init(&data->dq_finished, NULL);
+	data->dq = dispatch_queue_create("FSMonitor", NULL);
+
+	FSEventStreamSetDispatchQueue(data->stream, data->dq);
+	data->stream_scheduled = 1;
+
+	if (!FSEventStreamStart(data->stream)) {
+		error(_("Failed to start the FSEventStream"));
+		goto force_error_stop_without_loop;
+	}
+	data->stream_started = 1;
+
+	/*
+	 * Our fs event listener is now running, so it's safe to start
+	 * serving client requests.
+	 */
+	ipc_server_start_async(state->ipc_server_data);
+
+	pthread_mutex_lock(&data->dq_lock);
+	pthread_cond_wait(&data->dq_finished, &data->dq_lock);
+	pthread_mutex_unlock(&data->dq_lock);
+
+	switch (data->shutdown_style) {
+	case FORCE_ERROR_STOP:
+		state->listen_error_code = -1;
+		/* fall thru */
+	case FORCE_SHUTDOWN:
+		ipc_server_stop_async(state->ipc_server_data);
+		/* fall thru */
+	case SHUTDOWN_EVENT:
+	default:
+		break;
+	}
+	return;
+
+force_error_stop_without_loop:
+	state->listen_error_code = -1;
+	ipc_server_stop_async(state->ipc_server_data);
+	return;
+}
diff --git a/compat/fsmonitor/fsm-listen-win32.c b/compat/fsmonitor/fsm-listen-win32.c
new file mode 100644
index 0000000000..9a6efc9bea
--- /dev/null
+++ b/compat/fsmonitor/fsm-listen-win32.c
@@ -0,0 +1,879 @@
+#include "git-compat-util.h"
+#include "config.h"
+#include "fsmonitor-ll.h"
+#include "fsm-listen.h"
+#include "fsmonitor--daemon.h"
+#include "gettext.h"
+#include "simple-ipc.h"
+#include "trace2.h"
+
+/*
+ * The documentation of ReadDirectoryChangesW() states that the maximum
+ * buffer size is 64K when the monitored directory is remote.
+ *
+ * Larger buffers may be used when the monitored directory is local and
+ * will help us receive events faster from the kernel and avoid dropped
+ * events.
+ *
+ * So we try to use a very large buffer and silently fallback to 64K if
+ * we get an error.
+ */
+#define MAX_RDCW_BUF_FALLBACK (65536)
+#define MAX_RDCW_BUF          (65536 * 8)
+
+struct one_watch
+{
+	char buffer[MAX_RDCW_BUF];
+	DWORD buf_len;
+	DWORD count;
+
+	struct strbuf path;
+	wchar_t wpath_longname[MAX_PATH + 1];
+	DWORD wpath_longname_len;
+
+	HANDLE hDir;
+	HANDLE hEvent;
+	OVERLAPPED overlapped;
+
+	/*
+	 * Is there an active ReadDirectoryChangesW() call pending.  If so, we
+	 * need to later call GetOverlappedResult() and possibly CancelIoEx().
+	 */
+	BOOL is_active;
+
+	/*
+	 * Are shortnames enabled on the containing drive?  This is
+	 * always true for "C:/" drives and usually never true for
+	 * other drives.
+	 *
+	 * We only set this for the worktree because we only need to
+	 * convert shortname paths to longname paths for items we send
+	 * to clients.  (We don't care about shortname expansion for
+	 * paths inside a GITDIR because we never send them to
+	 * clients.)
+	 */
+	BOOL has_shortnames;
+	BOOL has_tilde;
+	wchar_t dotgit_shortname[16]; /* for 8.3 name */
+};
+
+struct fsm_listen_data
+{
+	struct one_watch *watch_worktree;
+	struct one_watch *watch_gitdir;
+
+	HANDLE hEventShutdown;
+
+	HANDLE hListener[3]; /* we don't own these handles */
+#define LISTENER_SHUTDOWN 0
+#define LISTENER_HAVE_DATA_WORKTREE 1
+#define LISTENER_HAVE_DATA_GITDIR 2
+	int nr_listener_handles;
+};
+
+/*
+ * Convert the WCHAR path from the event into UTF8 and normalize it.
+ *
+ * `wpath_len` is in WCHARS not bytes.
+ */
+static int normalize_path_in_utf8(wchar_t *wpath, DWORD wpath_len,
+				  struct strbuf *normalized_path)
+{
+	int reserve;
+	int len = 0;
+
+	strbuf_reset(normalized_path);
+	if (!wpath_len)
+		goto normalize;
+
+	/*
+	 * Pre-reserve enough space in the UTF8 buffer for
+	 * each Unicode WCHAR character to be mapped into a
+	 * sequence of 2 UTF8 characters.  That should let us
+	 * avoid ERROR_INSUFFICIENT_BUFFER 99.9+% of the time.
+	 */
+	reserve = 2 * wpath_len + 1;
+	strbuf_grow(normalized_path, reserve);
+
+	for (;;) {
+		len = WideCharToMultiByte(CP_UTF8, 0,
+					  wpath, wpath_len,
+					  normalized_path->buf,
+					  strbuf_avail(normalized_path) - 1,
+					  NULL, NULL);
+		if (len > 0)
+			goto normalize;
+		if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+			error(_("[GLE %ld] could not convert path to UTF-8: '%.*ls'"),
+			      GetLastError(), (int)wpath_len, wpath);
+			return -1;
+		}
+
+		strbuf_grow(normalized_path,
+			    strbuf_avail(normalized_path) + reserve);
+	}
+
+normalize:
+	strbuf_setlen(normalized_path, len);
+	return strbuf_normalize_path(normalized_path);
+}
+
+/*
+ * See if the worktree root directory has shortnames enabled.
+ * This will help us decide if we need to do an expensive shortname
+ * to longname conversion on every notification event.
+ *
+ * We do not want to create a file to test this, so we assume that the
+ * root directory contains a ".git" file or directory.  (Our caller
+ * only calls us for the worktree root, so this should be fine.)
+ *
+ * Remember the spelling of the shortname for ".git" if it exists.
+ */
+static void check_for_shortnames(struct one_watch *watch)
+{
+	wchar_t buf_in[MAX_PATH + 1];
+	wchar_t buf_out[MAX_PATH + 1];
+	wchar_t *last;
+	wchar_t *p;
+
+	/* build L"<wt-root-path>/.git" */
+	swprintf(buf_in, ARRAY_SIZE(buf_in) - 1, L"%ls.git",
+		 watch->wpath_longname);
+
+	if (!GetShortPathNameW(buf_in, buf_out, ARRAY_SIZE(buf_out)))
+		return;
+
+	/*
+	 * Get the final filename component of the shortpath.
+	 * We know that the path does not have a final slash.
+	 */
+	for (last = p = buf_out; *p; p++)
+		if (*p == L'/' || *p == '\\')
+			last = p + 1;
+
+	if (!wcscmp(last, L".git"))
+		return;
+
+	watch->has_shortnames = 1;
+	wcsncpy(watch->dotgit_shortname, last,
+		ARRAY_SIZE(watch->dotgit_shortname));
+
+	/*
+	 * The shortname for ".git" is usually of the form "GIT~1", so
+	 * we should be able to avoid shortname to longname mapping on
+	 * every notification event if the source string does not
+	 * contain a "~".
+	 *
+	 * However, the documentation for GetLongPathNameW() says
+	 * that there are filesystems that don't follow that pattern
+	 * and warns against this optimization.
+	 *
+	 * Lets test this.
+	 */
+	if (wcschr(watch->dotgit_shortname, L'~'))
+		watch->has_tilde = 1;
+}
+
+enum get_relative_result {
+	GRR_NO_CONVERSION_NEEDED,
+	GRR_HAVE_CONVERSION,
+	GRR_SHUTDOWN,
+};
+
+/*
+ * Info notification paths are relative to the root of the watch.
+ * If our CWD is still at the root, then we can use relative paths
+ * to convert from shortnames to longnames.  If our process has a
+ * different CWD, then we need to construct an absolute path, do
+ * the conversion, and then return the root-relative portion.
+ *
+ * We use the longname form of the root as our basis and assume that
+ * it already has a trailing slash.
+ *
+ * `wpath_len` is in WCHARS not bytes.
+ */
+static enum get_relative_result get_relative_longname(
+	struct one_watch *watch,
+	const wchar_t *wpath, DWORD wpath_len,
+	wchar_t *wpath_longname, size_t bufsize_wpath_longname)
+{
+	wchar_t buf_in[2 * MAX_PATH + 1];
+	wchar_t buf_out[MAX_PATH + 1];
+	DWORD root_len;
+	DWORD out_len;
+
+	/*
+	 * Build L"<wt-root-path>/<event-rel-path>"
+	 * Note that the <event-rel-path> might not be null terminated
+	 * so we avoid swprintf() constructions.
+	 */
+	root_len = watch->wpath_longname_len;
+	if (root_len + wpath_len >= ARRAY_SIZE(buf_in)) {
+		/*
+		 * This should not happen.  We cannot append the observed
+		 * relative path onto the end of the worktree root path
+		 * without overflowing the buffer.  Just give up.
+		 */
+		return GRR_SHUTDOWN;
+	}
+	wcsncpy(buf_in, watch->wpath_longname, root_len);
+	wcsncpy(buf_in + root_len, wpath, wpath_len);
+	buf_in[root_len + wpath_len] = 0;
+
+	/*
+	 * We don't actually know if the source pathname is a
+	 * shortname or a longname.  This Windows routine allows
+	 * either to be given as input.
+	 */
+	out_len = GetLongPathNameW(buf_in, buf_out, ARRAY_SIZE(buf_out));
+	if (!out_len) {
+		/*
+		 * The shortname to longname conversion can fail for
+		 * various reasons, for example if the file has been
+		 * deleted.  (That is, if we just received a
+		 * delete-file notification event and the file is
+		 * already gone, we can't ask the file system to
+		 * lookup the longname for it.  Likewise, for moves
+		 * and renames where we are given the old name.)
+		 *
+		 * Since deleting or moving a file or directory by its
+		 * shortname is rather obscure, I'm going ignore the
+		 * failure and ask the caller to report the original
+		 * relative path.  This seems kinder than failing here
+		 * and forcing a resync.  Besides, forcing a resync on
+		 * every file/directory delete would effectively
+		 * cripple monitoring.
+		 *
+		 * We might revisit this in the future.
+		 */
+		return GRR_NO_CONVERSION_NEEDED;
+	}
+
+	if (!wcscmp(buf_in, buf_out)) {
+		/*
+		 * The path does not have a shortname alias.
+		 */
+		return GRR_NO_CONVERSION_NEEDED;
+	}
+
+	if (wcsncmp(buf_in, buf_out, root_len)) {
+		/*
+		 * The spelling of the root directory portion of the computed
+		 * longname has changed.  This should not happen.  Basically,
+		 * it means that we don't know where (without recomputing the
+		 * longname of just the root directory) to split out the
+		 * relative path.  Since this should not happen, I'm just
+		 * going to let this fail and force a shutdown (because all
+		 * subsequent events are probably going to see the same
+		 * mismatch).
+		 */
+		return GRR_SHUTDOWN;
+	}
+
+	if (out_len - root_len >= bufsize_wpath_longname) {
+		/*
+		 * This should not happen.  We cannot copy the root-relative
+		 * portion of the path into the provided buffer without an
+		 * overrun.  Just give up.
+		 */
+		return GRR_SHUTDOWN;
+	}
+
+	/* Return the worktree root-relative portion of the longname. */
+
+	wcscpy(wpath_longname, buf_out + root_len);
+	return GRR_HAVE_CONVERSION;
+}
+
+void fsm_listen__stop_async(struct fsmonitor_daemon_state *state)
+{
+	SetEvent(state->listen_data->hListener[LISTENER_SHUTDOWN]);
+}
+
+static struct one_watch *create_watch(const char *path)
+{
+	struct one_watch *watch = NULL;
+	DWORD desired_access = FILE_LIST_DIRECTORY;
+	DWORD share_mode =
+		FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE;
+	HANDLE hDir;
+	DWORD len_longname;
+	wchar_t wpath[MAX_PATH + 1];
+	wchar_t wpath_longname[MAX_PATH + 1];
+
+	if (xutftowcs_path(wpath, path) < 0) {
+		error(_("could not convert to wide characters: '%s'"), path);
+		return NULL;
+	}
+
+	hDir = CreateFileW(wpath,
+			   desired_access, share_mode, NULL, OPEN_EXISTING,
+			   FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
+			   NULL);
+	if (hDir == INVALID_HANDLE_VALUE) {
+		error(_("[GLE %ld] could not watch '%s'"),
+		      GetLastError(), path);
+		return NULL;
+	}
+
+	len_longname = GetLongPathNameW(wpath, wpath_longname,
+					ARRAY_SIZE(wpath_longname));
+	if (!len_longname) {
+		error(_("[GLE %ld] could not get longname of '%s'"),
+		      GetLastError(), path);
+		CloseHandle(hDir);
+		return NULL;
+	}
+
+	if (wpath_longname[len_longname - 1] != L'/' &&
+	    wpath_longname[len_longname - 1] != L'\\') {
+		wpath_longname[len_longname++] = L'/';
+		wpath_longname[len_longname] = 0;
+	}
+
+	CALLOC_ARRAY(watch, 1);
+
+	watch->buf_len = sizeof(watch->buffer); /* assume full MAX_RDCW_BUF */
+
+	strbuf_init(&watch->path, 0);
+	strbuf_addstr(&watch->path, path);
+
+	wcscpy(watch->wpath_longname, wpath_longname);
+	watch->wpath_longname_len = len_longname;
+
+	watch->hDir = hDir;
+	watch->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+	return watch;
+}
+
+static void destroy_watch(struct one_watch *watch)
+{
+	if (!watch)
+		return;
+
+	strbuf_release(&watch->path);
+	if (watch->hDir != INVALID_HANDLE_VALUE)
+		CloseHandle(watch->hDir);
+	if (watch->hEvent != INVALID_HANDLE_VALUE)
+		CloseHandle(watch->hEvent);
+
+	free(watch);
+}
+
+static int start_rdcw_watch(struct one_watch *watch)
+{
+	DWORD dwNotifyFilter =
+		FILE_NOTIFY_CHANGE_FILE_NAME |
+		FILE_NOTIFY_CHANGE_DIR_NAME |
+		FILE_NOTIFY_CHANGE_ATTRIBUTES |
+		FILE_NOTIFY_CHANGE_SIZE |
+		FILE_NOTIFY_CHANGE_LAST_WRITE |
+		FILE_NOTIFY_CHANGE_CREATION;
+
+	ResetEvent(watch->hEvent);
+
+	memset(&watch->overlapped, 0, sizeof(watch->overlapped));
+	watch->overlapped.hEvent = watch->hEvent;
+
+	/*
+	 * Queue an async call using Overlapped IO.  This returns immediately.
+	 * Our event handle will be signalled when the real result is available.
+	 *
+	 * The return value here just means that we successfully queued it.
+	 * We won't know if the Read...() actually produces data until later.
+	 */
+	watch->is_active = ReadDirectoryChangesW(
+		watch->hDir, watch->buffer, watch->buf_len, TRUE,
+		dwNotifyFilter, &watch->count, &watch->overlapped, NULL);
+
+	if (watch->is_active)
+		return 0;
+
+	error(_("ReadDirectoryChangedW failed on '%s' [GLE %ld]"),
+	      watch->path.buf, GetLastError());
+	return -1;
+}
+
+static int recv_rdcw_watch(struct one_watch *watch)
+{
+	DWORD gle;
+
+	watch->is_active = FALSE;
+
+	/*
+	 * The overlapped result is ready.  If the Read...() was successful
+	 * we finally receive the actual result into our buffer.
+	 */
+	if (GetOverlappedResult(watch->hDir, &watch->overlapped, &watch->count,
+				TRUE))
+		return 0;
+
+	gle = GetLastError();
+	if (gle == ERROR_INVALID_PARAMETER &&
+	    /*
+	     * The kernel throws an invalid parameter error when our
+	     * buffer is too big and we are pointed at a remote
+	     * directory (and possibly for other reasons).  Quietly
+	     * set it down and try again.
+	     *
+	     * See note about MAX_RDCW_BUF at the top.
+	     */
+	    watch->buf_len > MAX_RDCW_BUF_FALLBACK) {
+		watch->buf_len = MAX_RDCW_BUF_FALLBACK;
+		return -2;
+	}
+
+	/*
+	 * GetOverlappedResult() fails if the watched directory is
+	 * deleted while we were waiting for an overlapped IO to
+	 * complete.  The documentation did not list specific errors,
+	 * but I observed ERROR_ACCESS_DENIED (0x05) errors during
+	 * testing.
+	 *
+	 * Note that we only get notification events for events
+	 * *within* the directory, not *on* the directory itself.
+	 * (These might be properties of the parent directory, for
+	 * example).
+	 *
+	 * NEEDSWORK: We might try to check for the deleted directory
+	 * case and return a better error message, but I'm not sure it
+	 * is worth it.
+	 *
+	 * Shutdown if we get any error.
+	 */
+
+	error(_("GetOverlappedResult failed on '%s' [GLE %ld]"),
+	      watch->path.buf, gle);
+	return -1;
+}
+
+static void cancel_rdcw_watch(struct one_watch *watch)
+{
+	DWORD count;
+
+	if (!watch || !watch->is_active)
+		return;
+
+	/*
+	 * The calls to ReadDirectoryChangesW() and GetOverlappedResult()
+	 * form a "pair" (my term) where we queue an IO and promise to
+	 * hang around and wait for the kernel to give us the result.
+	 *
+	 * If for some reason after we queue the IO, we have to quit
+	 * or otherwise not stick around for the second half, we must
+	 * tell the kernel to abort the IO.  This prevents the kernel
+	 * from writing to our buffer and/or signalling our event
+	 * after we free them.
+	 *
+	 * (Ask me how much fun it was to track that one down).
+	 */
+	CancelIoEx(watch->hDir, &watch->overlapped);
+	GetOverlappedResult(watch->hDir, &watch->overlapped, &count, TRUE);
+	watch->is_active = FALSE;
+}
+
+/*
+ * Process a single relative pathname event.
+ * Return 1 if we should shutdown.
+ */
+static int process_1_worktree_event(
+	struct string_list *cookie_list,
+	struct fsmonitor_batch **batch,
+	const struct strbuf *path,
+	enum fsmonitor_path_type t,
+	DWORD info_action)
+{
+	const char *slash;
+
+	switch (t) {
+	case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX:
+		/* special case cookie files within .git */
+
+		/* Use just the filename of the cookie file. */
+		slash = find_last_dir_sep(path->buf);
+		string_list_append(cookie_list,
+				   slash ? slash + 1 : path->buf);
+		break;
+
+	case IS_INSIDE_DOT_GIT:
+		/* ignore everything inside of "<worktree>/.git/" */
+		break;
+
+	case IS_DOT_GIT:
+		/* "<worktree>/.git" was deleted (or renamed away) */
+		if ((info_action == FILE_ACTION_REMOVED) ||
+		    (info_action == FILE_ACTION_RENAMED_OLD_NAME)) {
+			trace2_data_string("fsmonitor", NULL,
+					   "fsm-listen/dotgit",
+					   "removed");
+			return 1;
+		}
+		break;
+
+	case IS_WORKDIR_PATH:
+		/* queue normal pathname */
+		if (!*batch)
+			*batch = fsmonitor_batch__new();
+		fsmonitor_batch__add_path(*batch, path->buf);
+		break;
+
+	case IS_GITDIR:
+	case IS_INSIDE_GITDIR:
+	case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX:
+	default:
+		BUG("unexpected path classification '%d' for '%s'",
+		    t, path->buf);
+	}
+
+	return 0;
+}
+
+/*
+ * Process filesystem events that happen anywhere (recursively) under the
+ * <worktree> root directory.  For a normal working directory, this includes
+ * both version controlled files and the contents of the .git/ directory.
+ *
+ * If <worktree>/.git is a file, then we only see events for the file
+ * itself.
+ */
+static int process_worktree_events(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_listen_data *data = state->listen_data;
+	struct one_watch *watch = data->watch_worktree;
+	struct strbuf path = STRBUF_INIT;
+	struct string_list cookie_list = STRING_LIST_INIT_DUP;
+	struct fsmonitor_batch *batch = NULL;
+	const char *p = watch->buffer;
+	wchar_t wpath_longname[MAX_PATH + 1];
+
+	/*
+	 * If the kernel gets more events than will fit in the kernel
+	 * buffer associated with our RDCW handle, it drops them and
+	 * returns a count of zero.
+	 *
+	 * Yes, the call returns WITHOUT error and with length zero.
+	 * This is the documented behavior.  (My testing has confirmed
+	 * that it also sets the last error to ERROR_NOTIFY_ENUM_DIR,
+	 * but we do not rely on that since the function did not
+	 * return an error and it is not documented.)
+	 *
+	 * (The "overflow" case is not ambiguous with the "no data" case
+	 * because we did an INFINITE wait.)
+	 *
+	 * This means we have a gap in coverage.  Tell the daemon layer
+	 * to resync.
+	 */
+	if (!watch->count) {
+		trace2_data_string("fsmonitor", NULL, "fsm-listen/kernel",
+				   "overflow");
+		fsmonitor_force_resync(state);
+		return LISTENER_HAVE_DATA_WORKTREE;
+	}
+
+	/*
+	 * On Windows, `info` contains an "array" of paths that are
+	 * relative to the root of whichever directory handle received
+	 * the event.
+	 */
+	for (;;) {
+		FILE_NOTIFY_INFORMATION *info = (void *)p;
+		wchar_t *wpath = info->FileName;
+		DWORD wpath_len = info->FileNameLength / sizeof(WCHAR);
+		enum fsmonitor_path_type t;
+		enum get_relative_result grr;
+
+		if (watch->has_shortnames) {
+			if (!wcscmp(wpath, watch->dotgit_shortname)) {
+				/*
+				 * This event exactly matches the
+				 * spelling of the shortname of
+				 * ".git", so we can skip some steps.
+				 *
+				 * (This case is odd because the user
+				 * can "rm -rf GIT~1" and we cannot
+				 * use the filesystem to map it back
+				 * to ".git".)
+				 */
+				strbuf_reset(&path);
+				strbuf_addstr(&path, ".git");
+				t = IS_DOT_GIT;
+				goto process_it;
+			}
+
+			if (watch->has_tilde && !wcschr(wpath, L'~')) {
+				/*
+				 * Shortnames on this filesystem have tildes
+				 * and the notification path does not have
+				 * one, so we assume that it is a longname.
+				 */
+				goto normalize_it;
+			}
+
+			grr = get_relative_longname(watch, wpath, wpath_len,
+						    wpath_longname,
+						    ARRAY_SIZE(wpath_longname));
+			switch (grr) {
+			case GRR_NO_CONVERSION_NEEDED: /* use info buffer as is */
+				break;
+			case GRR_HAVE_CONVERSION:
+				wpath = wpath_longname;
+				wpath_len = wcslen(wpath);
+				break;
+			default:
+			case GRR_SHUTDOWN:
+				goto force_shutdown;
+			}
+		}
+
+normalize_it:
+		if (normalize_path_in_utf8(wpath, wpath_len, &path) == -1)
+			goto skip_this_path;
+
+		t = fsmonitor_classify_path_workdir_relative(path.buf);
+
+process_it:
+		if (process_1_worktree_event(&cookie_list, &batch, &path, t,
+					     info->Action))
+			goto force_shutdown;
+
+skip_this_path:
+		if (!info->NextEntryOffset)
+			break;
+		p += info->NextEntryOffset;
+	}
+
+	fsmonitor_publish(state, batch, &cookie_list);
+	batch = NULL;
+	string_list_clear(&cookie_list, 0);
+	strbuf_release(&path);
+	return LISTENER_HAVE_DATA_WORKTREE;
+
+force_shutdown:
+	fsmonitor_batch__free_list(batch);
+	string_list_clear(&cookie_list, 0);
+	strbuf_release(&path);
+	return LISTENER_SHUTDOWN;
+}
+
+/*
+ * Process filesystem events that happened anywhere (recursively) under the
+ * external <gitdir> (such as non-primary worktrees or submodules).
+ * We only care about cookie files that our client threads created here.
+ *
+ * Note that we DO NOT get filesystem events on the external <gitdir>
+ * itself (it is not inside something that we are watching).  In particular,
+ * we do not get an event if the external <gitdir> is deleted.
+ *
+ * Also, we do not care about shortnames within the external <gitdir>, since
+ * we never send these paths to clients.
+ */
+static int process_gitdir_events(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_listen_data *data = state->listen_data;
+	struct one_watch *watch = data->watch_gitdir;
+	struct strbuf path = STRBUF_INIT;
+	struct string_list cookie_list = STRING_LIST_INIT_DUP;
+	const char *p = watch->buffer;
+
+	if (!watch->count) {
+		trace2_data_string("fsmonitor", NULL, "fsm-listen/kernel",
+				   "overflow");
+		fsmonitor_force_resync(state);
+		return LISTENER_HAVE_DATA_GITDIR;
+	}
+
+	for (;;) {
+		FILE_NOTIFY_INFORMATION *info = (void *)p;
+		const char *slash;
+		enum fsmonitor_path_type t;
+
+		if (normalize_path_in_utf8(
+			    info->FileName,
+			    info->FileNameLength / sizeof(WCHAR),
+			    &path) == -1)
+			goto skip_this_path;
+
+		t = fsmonitor_classify_path_gitdir_relative(path.buf);
+
+		switch (t) {
+		case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX:
+			/* special case cookie files within gitdir */
+
+			/* Use just the filename of the cookie file. */
+			slash = find_last_dir_sep(path.buf);
+			string_list_append(&cookie_list,
+					   slash ? slash + 1 : path.buf);
+			break;
+
+		case IS_INSIDE_GITDIR:
+			goto skip_this_path;
+
+		default:
+			BUG("unexpected path classification '%d' for '%s'",
+			    t, path.buf);
+		}
+
+skip_this_path:
+		if (!info->NextEntryOffset)
+			break;
+		p += info->NextEntryOffset;
+	}
+
+	fsmonitor_publish(state, NULL, &cookie_list);
+	string_list_clear(&cookie_list, 0);
+	strbuf_release(&path);
+	return LISTENER_HAVE_DATA_GITDIR;
+}
+
+void fsm_listen__loop(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_listen_data *data = state->listen_data;
+	DWORD dwWait;
+	int result;
+
+	state->listen_error_code = 0;
+
+	if (start_rdcw_watch(data->watch_worktree) == -1)
+		goto force_error_stop;
+
+	if (data->watch_gitdir &&
+	    start_rdcw_watch(data->watch_gitdir) == -1)
+		goto force_error_stop;
+
+	/*
+	 * Now that we've established the rdcw watches, we can start
+	 * serving clients.
+	 */
+	ipc_server_start_async(state->ipc_server_data);
+
+	for (;;) {
+		dwWait = WaitForMultipleObjects(data->nr_listener_handles,
+						data->hListener,
+						FALSE, INFINITE);
+
+		if (dwWait == WAIT_OBJECT_0 + LISTENER_HAVE_DATA_WORKTREE) {
+			result = recv_rdcw_watch(data->watch_worktree);
+			if (result == -1) {
+				/* hard error */
+				goto force_error_stop;
+			}
+			if (result == -2) {
+				/* retryable error */
+				if (start_rdcw_watch(data->watch_worktree) == -1)
+					goto force_error_stop;
+				continue;
+			}
+
+			/* have data */
+			if (process_worktree_events(state) == LISTENER_SHUTDOWN)
+				goto force_shutdown;
+			if (start_rdcw_watch(data->watch_worktree) == -1)
+				goto force_error_stop;
+			continue;
+		}
+
+		if (dwWait == WAIT_OBJECT_0 + LISTENER_HAVE_DATA_GITDIR) {
+			result = recv_rdcw_watch(data->watch_gitdir);
+			if (result == -1) {
+				/* hard error */
+				goto force_error_stop;
+			}
+			if (result == -2) {
+				/* retryable error */
+				if (start_rdcw_watch(data->watch_gitdir) == -1)
+					goto force_error_stop;
+				continue;
+			}
+
+			/* have data */
+			if (process_gitdir_events(state) == LISTENER_SHUTDOWN)
+				goto force_shutdown;
+			if (start_rdcw_watch(data->watch_gitdir) == -1)
+				goto force_error_stop;
+			continue;
+		}
+
+		if (dwWait == WAIT_OBJECT_0 + LISTENER_SHUTDOWN)
+			goto clean_shutdown;
+
+		error(_("could not read directory changes [GLE %ld]"),
+		      GetLastError());
+		goto force_error_stop;
+	}
+
+force_error_stop:
+	state->listen_error_code = -1;
+
+force_shutdown:
+	/*
+	 * Tell the IPC thead pool to stop (which completes the await
+	 * in the main thread (which will also signal this thread (if
+	 * we are still alive))).
+	 */
+	ipc_server_stop_async(state->ipc_server_data);
+
+clean_shutdown:
+	cancel_rdcw_watch(data->watch_worktree);
+	cancel_rdcw_watch(data->watch_gitdir);
+}
+
+int fsm_listen__ctor(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_listen_data *data;
+
+	CALLOC_ARRAY(data, 1);
+
+	data->hEventShutdown = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+	data->watch_worktree = create_watch(state->path_worktree_watch.buf);
+	if (!data->watch_worktree)
+		goto failed;
+
+	check_for_shortnames(data->watch_worktree);
+
+	if (state->nr_paths_watching > 1) {
+		data->watch_gitdir = create_watch(state->path_gitdir_watch.buf);
+		if (!data->watch_gitdir)
+			goto failed;
+	}
+
+	data->hListener[LISTENER_SHUTDOWN] = data->hEventShutdown;
+	data->nr_listener_handles++;
+
+	data->hListener[LISTENER_HAVE_DATA_WORKTREE] =
+		data->watch_worktree->hEvent;
+	data->nr_listener_handles++;
+
+	if (data->watch_gitdir) {
+		data->hListener[LISTENER_HAVE_DATA_GITDIR] =
+			data->watch_gitdir->hEvent;
+		data->nr_listener_handles++;
+	}
+
+	state->listen_data = data;
+	return 0;
+
+failed:
+	CloseHandle(data->hEventShutdown);
+	destroy_watch(data->watch_worktree);
+	destroy_watch(data->watch_gitdir);
+
+	return -1;
+}
+
+void fsm_listen__dtor(struct fsmonitor_daemon_state *state)
+{
+	struct fsm_listen_data *data;
+
+	if (!state || !state->listen_data)
+		return;
+
+	data = state->listen_data;
+
+	CloseHandle(data->hEventShutdown);
+	destroy_watch(data->watch_worktree);
+	destroy_watch(data->watch_gitdir);
+
+	FREE_AND_NULL(state->listen_data);
+}
diff --git a/compat/fsmonitor/fsm-listen.h b/compat/fsmonitor/fsm-listen.h
new file mode 100644
index 0000000000..41650bf897
--- /dev/null
+++ b/compat/fsmonitor/fsm-listen.h
@@ -0,0 +1,49 @@
+#ifndef FSM_LISTEN_H
+#define FSM_LISTEN_H
+
+/* This needs to be implemented by each backend */
+
+#ifdef HAVE_FSMONITOR_DAEMON_BACKEND
+
+struct fsmonitor_daemon_state;
+
+/*
+ * Initialize platform-specific data for the fsmonitor listener thread.
+ * This will be called from the main thread PRIOR to staring the
+ * fsmonitor_fs_listener thread.
+ *
+ * Returns 0 if successful.
+ * Returns -1 otherwise.
+ */
+int fsm_listen__ctor(struct fsmonitor_daemon_state *state);
+
+/*
+ * Cleanup platform-specific data for the fsmonitor listener thread.
+ * This will be called from the main thread AFTER joining the listener.
+ */
+void fsm_listen__dtor(struct fsmonitor_daemon_state *state);
+
+/*
+ * The main body of the platform-specific event loop to watch for
+ * filesystem events.  This will run in the fsmonitor_fs_listen thread.
+ *
+ * It should call `ipc_server_stop_async()` if the listener thread
+ * prematurely terminates (because of a filesystem error or if it
+ * detects that the .git directory has been deleted).  (It should NOT
+ * do so if the listener thread receives a normal shutdown signal from
+ * the IPC layer.)
+ *
+ * It should set `state->listen_error_code` to -1 if the daemon should exit
+ * with an error.
+ */
+void fsm_listen__loop(struct fsmonitor_daemon_state *state);
+
+/*
+ * Gently request that the fsmonitor listener thread shutdown.
+ * It does not wait for it to stop.  The caller should do a JOIN
+ * to wait for it.
+ */
+void fsm_listen__stop_async(struct fsmonitor_daemon_state *state);
+
+#endif /* HAVE_FSMONITOR_DAEMON_BACKEND */
+#endif /* FSM_LISTEN_H */
diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c
new file mode 100644
index 0000000000..049f97eaaf
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-darwin.c
@@ -0,0 +1,138 @@
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
+#include "fsmonitor-path-utils.h"
+#include "gettext.h"
+#include "trace.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+	struct statfs fs;
+	if (statfs(path, &fs) == -1) {
+		int saved_errno = errno;
+		trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
+				 path, strerror(saved_errno));
+		errno = saved_errno;
+		return -1;
+	}
+
+	trace_printf_key(&trace_fsmonitor,
+			 "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
+			 path, fs.f_type, fs.f_flags, fs.f_fstypename);
+
+	if (!(fs.f_flags & MNT_LOCAL))
+		fs_info->is_remote = 1;
+	else
+		fs_info->is_remote = 0;
+
+	fs_info->typename = xstrdup(fs.f_fstypename);
+
+	trace_printf_key(&trace_fsmonitor,
+				"'%s' is_remote: %d",
+				path, fs_info->is_remote);
+	return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+	struct fs_info fs;
+	if (fsmonitor__get_fs_info(path, &fs))
+		return -1;
+
+	free(fs.typename);
+
+	return fs.is_remote;
+}
+
+/*
+ * Scan the root directory for synthetic firmlinks that when resolved
+ * are a prefix of the path, stopping at the first one found.
+ *
+ * Some information about firmlinks and synthetic firmlinks:
+ * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/
+ *
+ * macOS no longer allows symlinks in the root directory; any link found
+ * there is therefore a synthetic firmlink.
+ *
+ * If this function gets called often, will want to cache all the firmlink
+ * information, but for now there is only one caller of this function.
+ *
+ * If there is more than one alias for the path, that is another
+ * matter altogether.
+ */
+int fsmonitor__get_alias(const char *path, struct alias_info *info)
+{
+	DIR *dir;
+	int retval = -1;
+	const char *const root = "/";
+	struct stat st;
+	struct dirent *de;
+	struct strbuf alias;
+	struct strbuf points_to = STRBUF_INIT;
+
+	dir = opendir(root);
+	if (!dir)
+		return error_errno(_("opendir('%s') failed"), root);
+
+	strbuf_init(&alias, 256);
+
+	while ((de = readdir(dir)) != NULL) {
+		strbuf_reset(&alias);
+		strbuf_addf(&alias, "%s%s", root, de->d_name);
+
+		if (lstat(alias.buf, &st) < 0) {
+			error_errno(_("lstat('%s') failed"), alias.buf);
+			goto done;
+		}
+
+		if (!S_ISLNK(st.st_mode))
+			continue;
+
+		if (strbuf_readlink(&points_to, alias.buf, st.st_size) < 0) {
+			error_errno(_("strbuf_readlink('%s') failed"), alias.buf);
+			goto done;
+		}
+
+		if (!strncmp(points_to.buf, path, points_to.len) &&
+			(path[points_to.len] == '/')) {
+			strbuf_addbuf(&info->alias, &alias);
+			strbuf_addbuf(&info->points_to, &points_to);
+			trace_printf_key(&trace_fsmonitor,
+				"Found alias for '%s' : '%s' -> '%s'",
+				path, info->alias.buf, info->points_to.buf);
+			retval = 0;
+			goto done;
+		}
+	}
+	retval = 0; /* no alias */
+
+done:
+	strbuf_release(&alias);
+	strbuf_release(&points_to);
+	if (closedir(dir) < 0)
+		return error_errno(_("closedir('%s') failed"), root);
+	return retval;
+}
+
+char *fsmonitor__resolve_alias(const char *path,
+	const struct alias_info *info)
+{
+	if (!info->alias.len)
+		return NULL;
+
+	if ((!strncmp(info->alias.buf, path, info->alias.len))
+		&& path[info->alias.len] == '/') {
+		struct strbuf tmp = STRBUF_INIT;
+		const char *remainder = path + info->alias.len;
+
+		strbuf_addbuf(&tmp, &info->points_to);
+		strbuf_add(&tmp, remainder, strlen(remainder));
+		return strbuf_detach(&tmp, NULL);
+	}
+
+	return NULL;
+}
diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c
new file mode 100644
index 0000000000..f4f9cc1f33
--- /dev/null
+++ b/compat/fsmonitor/fsm-path-utils-win32.c
@@ -0,0 +1,148 @@
+#include "git-compat-util.h"
+#include "fsmonitor-ll.h"
+#include "fsmonitor-path-utils.h"
+#include "gettext.h"
+#include "trace.h"
+
+/*
+ * Check remote working directory protocol.
+ *
+ * Return -1 if client machine cannot get remote protocol information.
+ */
+static int check_remote_protocol(wchar_t *wpath)
+{
+	HANDLE h;
+	FILE_REMOTE_PROTOCOL_INFO proto_info;
+
+	h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
+			FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+	if (h == INVALID_HANDLE_VALUE) {
+		error(_("[GLE %ld] unable to open for read '%ls'"),
+		      GetLastError(), wpath);
+		return -1;
+	}
+
+	if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo,
+		&proto_info, sizeof(proto_info))) {
+		error(_("[GLE %ld] unable to get protocol information for '%ls'"),
+		      GetLastError(), wpath);
+		CloseHandle(h);
+		return -1;
+	}
+
+	CloseHandle(h);
+
+	trace_printf_key(&trace_fsmonitor,
+				"check_remote_protocol('%ls') remote protocol %#8.8lx",
+				wpath, proto_info.Protocol);
+
+	return 0;
+}
+
+/*
+ * Notes for testing:
+ *
+ * (a) Windows allows a network share to be mapped to a drive letter.
+ *     (This is the normal method to access it.)
+ *
+ *     $ NET USE Z: \\server\share
+ *     $ git -C Z:/repo status
+ *
+ * (b) Windows allows a network share to be referenced WITHOUT mapping
+ *     it to drive letter.
+ *
+ *     $ NET USE \\server\share\dir
+ *     $ git -C //server/share/repo status
+ *
+ * (c) Windows allows "SUBST" to create a fake drive mapping to an
+ *     arbitrary path (which may be remote)
+ *
+ *     $ SUBST Q: Z:\repo
+ *     $ git -C Q:/ status
+ *
+ * (d) Windows allows a directory symlink to be created on a local
+ *     file system that points to a remote repo.
+ *
+ *     $ mklink /d ./link //server/share/repo
+ *     $ git -C ./link status
+ */
+int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info)
+{
+	wchar_t wpath[MAX_PATH];
+	wchar_t wfullpath[MAX_PATH];
+	size_t wlen;
+	UINT driveType;
+
+	/*
+	 * Do everything in wide chars because the drive letter might be
+	 * a multi-byte sequence.  See win32_has_dos_drive_prefix().
+	 */
+	if (xutftowcs_path(wpath, path) < 0) {
+		return -1;
+	}
+
+	/*
+	 * GetDriveTypeW() requires a final slash.  We assume that the
+	 * worktree pathname points to an actual directory.
+	 */
+	wlen = wcslen(wpath);
+	if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') {
+		wpath[wlen++] = L'\\';
+		wpath[wlen] = 0;
+	}
+
+	/*
+	 * Normalize the path.  If nothing else, this converts forward
+	 * slashes to backslashes.  This is essential to get GetDriveTypeW()
+	 * correctly handle some UNC "\\server\share\..." paths.
+	 */
+	if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) {
+		return -1;
+	}
+
+	driveType = GetDriveTypeW(wfullpath);
+	trace_printf_key(&trace_fsmonitor,
+			 "DriveType '%s' L'%ls' (%u)",
+			 path, wfullpath, driveType);
+
+	if (driveType == DRIVE_REMOTE) {
+		fs_info->is_remote = 1;
+		if (check_remote_protocol(wfullpath) < 0)
+			return -1;
+	} else {
+		fs_info->is_remote = 0;
+	}
+
+	trace_printf_key(&trace_fsmonitor,
+				"'%s' is_remote: %d",
+				path, fs_info->is_remote);
+
+	return 0;
+}
+
+int fsmonitor__is_fs_remote(const char *path)
+{
+	struct fs_info fs;
+	if (fsmonitor__get_fs_info(path, &fs))
+		return -1;
+	return fs.is_remote;
+}
+
+/*
+ * No-op for now.
+ */
+int fsmonitor__get_alias(const char *path UNUSED,
+			 struct alias_info *info UNUSED)
+{
+	return 0;
+}
+
+/*
+ * No-op for now.
+ */
+char *fsmonitor__resolve_alias(const char *path UNUSED,
+			       const struct alias_info *info UNUSED)
+{
+	return NULL;
+}
diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c
new file mode 100644
index 0000000000..a382590635
--- /dev/null
+++ b/compat/fsmonitor/fsm-settings-darwin.c
@@ -0,0 +1,63 @@
+#include "git-compat-util.h"
+#include "config.h"
+#include "fsmonitor-ll.h"
+#include "fsmonitor-ipc.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
+
+ /*
+ * For the builtin FSMonitor, we create the Unix domain socket for the
+ * IPC in the .git directory.  If the working directory is remote,
+ * then the socket will be created on the remote file system.  This
+ * can fail if the remote file system does not support UDS file types
+ * (e.g. smbfs to a Windows server) or if the remote kernel does not
+ * allow a non-local process to bind() the socket.  (These problems
+ * could be fixed by moving the UDS out of the .git directory and to a
+ * well-known local directory on the client machine, but care should
+ * be taken to ensure that $HOME is actually local and not a managed
+ * file share.)
+ *
+ * FAT32 and NTFS working directories are problematic too.
+ *
+ * The builtin FSMonitor uses a Unix domain socket in the .git
+ * directory for IPC.  These Windows drive formats do not support
+ * Unix domain sockets, so mark them as incompatible for the daemon.
+ *
+ */
+static enum fsmonitor_reason check_uds_volume(struct repository *r)
+{
+	struct fs_info fs;
+	const char *ipc_path = fsmonitor_ipc__get_path(r);
+	struct strbuf path = STRBUF_INIT;
+	strbuf_add(&path, ipc_path, strlen(ipc_path));
+
+	if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) {
+		strbuf_release(&path);
+		return FSMONITOR_REASON_ERROR;
+	}
+
+	strbuf_release(&path);
+
+	if (fs.is_remote ||
+		!strcmp(fs.typename, "msdos") ||
+		!strcmp(fs.typename, "ntfs")) {
+		free(fs.typename);
+		return FSMONITOR_REASON_NOSOCKETS;
+	}
+
+	free(fs.typename);
+	return FSMONITOR_REASON_OK;
+}
+
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc)
+{
+	enum fsmonitor_reason reason;
+
+	if (ipc) {
+		reason = check_uds_volume(r);
+		if (reason != FSMONITOR_REASON_OK)
+			return reason;
+	}
+
+	return FSMONITOR_REASON_OK;
+}
diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c
new file mode 100644
index 0000000000..0f2aa321f6
--- /dev/null
+++ b/compat/fsmonitor/fsm-settings-win32.c
@@ -0,0 +1,37 @@
+#include "git-compat-util.h"
+#include "config.h"
+#include "repository.h"
+#include "fsmonitor-ll.h"
+#include "fsmonitor-settings.h"
+#include "fsmonitor-path-utils.h"
+
+/*
+ * VFS for Git is incompatible with FSMonitor.
+ *
+ * Granted, core Git does not know anything about VFS for Git and we
+ * shouldn't make assumptions about a downstream feature, but users
+ * can install both versions.  And this can lead to incorrect results
+ * from core Git commands.  So, without bringing in any of the VFS for
+ * Git code, do a simple config test for a published config setting.
+ * (We do not look at the various *_TEST_* environment variables.)
+ */
+static enum fsmonitor_reason check_vfs4git(struct repository *r)
+{
+	const char *const_str;
+
+	if (!repo_config_get_value(r, "core.virtualfilesystem", &const_str))
+		return FSMONITOR_REASON_VFS4GIT;
+
+	return FSMONITOR_REASON_OK;
+}
+
+enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc UNUSED)
+{
+	enum fsmonitor_reason reason;
+
+	reason = check_vfs4git(r);
+	if (reason != FSMONITOR_REASON_OK)
+		return reason;
+
+	return FSMONITOR_REASON_OK;
+}
diff --git a/compat/hstrerror.c b/compat/hstrerror.c
new file mode 100644
index 0000000000..b85a2fa956
--- /dev/null
+++ b/compat/hstrerror.c
@@ -0,0 +1,21 @@
+#include <string.h>
+#include <stdio.h>
+#include <netdb.h>
+
+const char *githstrerror(int err)
+{
+	static char buffer[48];
+	switch (err)
+	{
+	case HOST_NOT_FOUND:
+		return "Authoritative answer: host not found";
+	case NO_DATA:
+		return "Valid name, no data record of requested type";
+	case NO_RECOVERY:
+		return "Non recoverable errors, FORMERR, REFUSED, NOTIMP";
+	case TRY_AGAIN:
+		return "Non-authoritative \"host not found\", or SERVERFAIL";
+	}
+	snprintf(buffer, sizeof(buffer), "Name resolution error %d", err);
+	return buffer;
+}
diff --git a/compat/inet_ntop.c b/compat/inet_ntop.c
new file mode 100644
index 0000000000..68307262be
--- /dev/null
+++ b/compat/inet_ntop.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "../git-compat-util.h"
+
+#ifndef NS_INADDRSZ
+#define NS_INADDRSZ	4
+#endif
+#ifndef NS_IN6ADDRSZ
+#define NS_IN6ADDRSZ	16
+#endif
+#ifndef NS_INT16SZ
+#define NS_INT16SZ	2
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ *	format an IPv4 address
+ * return:
+ *	`dst' (as a const)
+ * notes:
+ *	(1) uses no statics
+ *	(2) takes a u_char* not an in_addr as input
+ * author:
+ *	Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const u_char *src, char *dst, size_t size)
+{
+	static const char fmt[] = "%u.%u.%u.%u";
+	char tmp[sizeof "255.255.255.255"];
+	int nprinted;
+
+	nprinted = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+	if (nprinted < 0)
+		return (NULL);	/* we assume "errno" was set by "snprintf()" */
+	if ((size_t)nprinted >= size) {
+		errno = ENOSPC;
+		return (NULL);
+	}
+	strlcpy(dst, tmp, size);
+	return (dst);
+}
+
+#ifndef NO_IPV6
+/* const char *
+ * inet_ntop6(src, dst, size)
+ *	convert IPv6 binary address into presentation (printable) format
+ * author:
+ *	Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(const u_char *src, char *dst, size_t size)
+{
+	/*
+	 * Note that int32_t and int16_t need only be "at least" large enough
+	 * to contain a value of the specified size.  On some systems, like
+	 * Crays, there is no such thing as an integer variable with 16 bits.
+	 * Keep this in mind if you think this function should have been coded
+	 * to use pointer overlays.  All the world's not a VAX.
+	 */
+	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
+	struct { int base, len; } best, cur;
+	unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ];
+	int i;
+
+	/*
+	 * Preprocess:
+	 *	Copy the input (bytewise) array into a wordwise array.
+	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
+	 */
+	memset(words, '\0', sizeof words);
+	for (i = 0; i < NS_IN6ADDRSZ; i++)
+		words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+	best.base = -1;
+	best.len = 0;
+	cur.base = -1;
+	cur.len = 0;
+	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+		if (words[i] == 0) {
+			if (cur.base == -1)
+				cur.base = i, cur.len = 1;
+			else
+				cur.len++;
+		} else {
+			if (cur.base != -1) {
+				if (best.base == -1 || cur.len > best.len)
+					best = cur;
+				cur.base = -1;
+			}
+		}
+	}
+	if (cur.base != -1) {
+		if (best.base == -1 || cur.len > best.len)
+			best = cur;
+	}
+	if (best.base != -1 && best.len < 2)
+		best.base = -1;
+
+	/*
+	 * Format the result.
+	 */
+	tp = tmp;
+	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
+		/* Are we inside the best run of 0x00's? */
+		if (best.base != -1 && i >= best.base &&
+		    i < (best.base + best.len)) {
+			if (i == best.base)
+				*tp++ = ':';
+			continue;
+		}
+		/* Are we following an initial run of 0x00s or any real hex? */
+		if (i != 0)
+			*tp++ = ':';
+		/* Is this address an encapsulated IPv4? */
+		if (i == 6 && best.base == 0 &&
+		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+			if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
+				return (NULL);
+			tp += strlen(tp);
+			break;
+		}
+		tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]);
+	}
+	/* Was it a trailing run of 0x00's? */
+	if (best.base != -1 && (best.base + best.len) ==
+	    (NS_IN6ADDRSZ / NS_INT16SZ))
+		*tp++ = ':';
+	*tp++ = '\0';
+
+	/*
+	 * Check for overflow, copy, and we're done.
+	 */
+	if ((size_t)(tp - tmp) > size) {
+		errno = ENOSPC;
+		return (NULL);
+	}
+	strlcpy(dst, tmp, size);
+	return (dst);
+}
+#endif
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ *	convert a network format address to presentation format.
+ * return:
+ *	pointer to presentation format address (`dst'), or NULL (see errno).
+ * author:
+ *	Paul Vixie, 1996.
+ */
+const char *
+inet_ntop(int af, const void *src, char *dst, size_t size)
+{
+	switch (af) {
+	case AF_INET:
+		return (inet_ntop4(src, dst, size));
+#ifndef NO_IPV6
+	case AF_INET6:
+		return (inet_ntop6(src, dst, size));
+#endif
+	default:
+		errno = EAFNOSUPPORT;
+		return (NULL);
+	}
+	/* NOTREACHED */
+}
diff --git a/compat/inet_pton.c b/compat/inet_pton.c
new file mode 100644
index 0000000000..2b9a0a4e22
--- /dev/null
+++ b/compat/inet_pton.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 1996-2001  Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "../git-compat-util.h"
+
+#ifndef NS_INT16SZ
+#define NS_INT16SZ       2
+#endif
+
+#ifndef NS_INADDRSZ
+#define NS_INADDRSZ      4
+#endif
+
+#ifndef NS_IN6ADDRSZ
+#define NS_IN6ADDRSZ    16
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifndef NO_IPV6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton4(src, dst)
+ *      like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *      1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *      does not touch `dst' unless it's returning 1.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+        static const char digits[] = "0123456789";
+        int saw_digit, octets, ch;
+        unsigned char tmp[NS_INADDRSZ], *tp;
+
+        saw_digit = 0;
+        octets = 0;
+        *(tp = tmp) = 0;
+        while ((ch = *src++) != '\0') {
+                const char *pch;
+
+                if ((pch = strchr(digits, ch)) != NULL) {
+                        unsigned int new = *tp * 10 + (pch - digits);
+
+                        if (new > 255)
+                                return (0);
+                        *tp = new;
+                        if (! saw_digit) {
+                                if (++octets > 4)
+                                        return (0);
+                                saw_digit = 1;
+                        }
+                } else if (ch == '.' && saw_digit) {
+                        if (octets == 4)
+                                return (0);
+                        *++tp = 0;
+                        saw_digit = 0;
+                } else
+                        return (0);
+        }
+        if (octets < 4)
+                return (0);
+        memcpy(dst, tmp, NS_INADDRSZ);
+        return (1);
+}
+
+/* int
+ * inet_pton6(src, dst)
+ *      convert presentation level address to network order binary form.
+ * return:
+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *      (1) does not touch `dst' unless it's returning 1.
+ *      (2) :: in a full address is silently ignored.
+ * credit:
+ *      inspired by Mark Andrews.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+
+#ifndef NO_IPV6
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+        static const char xdigits_l[] = "0123456789abcdef",
+                          xdigits_u[] = "0123456789ABCDEF";
+        unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+        const char *xdigits, *curtok;
+        int ch, saw_xdigit;
+        unsigned int val;
+
+        memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+        endp = tp + NS_IN6ADDRSZ;
+        colonp = NULL;
+        /* Leading :: requires some special handling. */
+        if (*src == ':')
+                if (*++src != ':')
+                        return (0);
+        curtok = src;
+        saw_xdigit = 0;
+        val = 0;
+        while ((ch = *src++) != '\0') {
+                const char *pch;
+
+                if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+                        pch = strchr((xdigits = xdigits_u), ch);
+                if (pch != NULL) {
+                        val <<= 4;
+                        val |= (pch - xdigits);
+                        if (val > 0xffff)
+                                return (0);
+                        saw_xdigit = 1;
+                        continue;
+                }
+                if (ch == ':') {
+                        curtok = src;
+                        if (!saw_xdigit) {
+                                if (colonp)
+                                        return (0);
+                                colonp = tp;
+                                continue;
+                        }
+                        if (tp + NS_INT16SZ > endp)
+                                return (0);
+                        *tp++ = (unsigned char) (val >> 8) & 0xff;
+                        *tp++ = (unsigned char) val & 0xff;
+                        saw_xdigit = 0;
+                        val = 0;
+                        continue;
+                }
+                if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+                    inet_pton4(curtok, tp) > 0) {
+                        tp += NS_INADDRSZ;
+                        saw_xdigit = 0;
+                        break;  /* '\0' was seen by inet_pton4(). */
+                }
+                return (0);
+        }
+        if (saw_xdigit) {
+                if (tp + NS_INT16SZ > endp)
+                        return (0);
+                *tp++ = (unsigned char) (val >> 8) & 0xff;
+                *tp++ = (unsigned char) val & 0xff;
+        }
+        if (colonp != NULL) {
+                /*
+                 * Since some memmove()'s erroneously fail to handle
+                 * overlapping regions, we'll do the shift by hand.
+                 */
+                const int n = tp - colonp;
+                int i;
+
+                for (i = 1; i <= n; i++) {
+                        endp[- i] = colonp[n - i];
+                        colonp[n - i] = 0;
+                }
+                tp = endp;
+        }
+        if (tp != endp)
+                return (0);
+        memcpy(dst, tmp, NS_IN6ADDRSZ);
+        return (1);
+}
+#endif
+
+/* int
+ * isc_net_pton(af, src, dst)
+ *      convert from presentation format (which usually means ASCII printable)
+ *      to network format (which is usually some kind of binary format).
+ * return:
+ *      1 if the address was valid for the specified address family
+ *      0 if the address wasn't valid (`dst' is untouched in this case)
+ *      -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *      Paul Vixie, 1996.
+ */
+int
+inet_pton(int af, const char *src, void *dst)
+{
+        switch (af) {
+        case AF_INET:
+                return (inet_pton4(src, dst));
+#ifndef NO_IPV6
+        case AF_INET6:
+                return (inet_pton6(src, dst));
+#endif
+        default:
+                errno = EAFNOSUPPORT;
+                return (-1);
+        }
+        /* NOTREACHED */
+}
diff --git a/compat/linux/procinfo.c b/compat/linux/procinfo.c
new file mode 100644
index 0000000000..4bb2d66227
--- /dev/null
+++ b/compat/linux/procinfo.c
@@ -0,0 +1,176 @@
+#include "git-compat-util.h"
+
+#include "strbuf.h"
+#include "strvec.h"
+#include "trace2.h"
+
+/*
+ * We need more complex parsing in stat_parent_pid() and
+ * parse_proc_stat() below than a dumb fscanf(). That's because while
+ * the statcomm field is surrounded by parentheses, the process itself
+ * is free to insert any arbitrary byte sequence its its name. That
+ * can include newlines, spaces, closing parentheses etc.
+ *
+ * See do_task_stat() in fs/proc/array.c in linux.git, this is in
+ * contrast with the escaped version of the name found in
+ * /proc/%d/status.
+ *
+ * So instead of using fscanf() we'll read N bytes from it, look for
+ * the first "(", and then the last ")", anything in-between is our
+ * process name.
+ *
+ * How much N do we need? On Linux /proc/sys/kernel/pid_max is 2^15 by
+ * default, but it can be raised set to values of up to 2^22. So
+ * that's 7 digits for a PID. We have 2 PIDs in the first four fields
+ * we're interested in, so 2 * 7 = 14.
+ *
+ * We then have 3 spaces between those four values, and we'd like to
+ * get to the space between the 4th and the 5th (the "pgrp" field) to
+ * make sure we read the entire "ppid" field. So that brings us up to
+ * 14 + 3 + 1 = 18. Add the two parentheses around the "comm" value
+ * and it's 20. The "state" value itself is then one character (now at
+ * 21).
+ *
+ * Finally the maximum length of the "comm" name itself is 15
+ * characters, e.g. a setting of "123456789abcdefg" will be truncated
+ * to "123456789abcdef". See PR_SET_NAME in prctl(2). So all in all
+ * we'd need to read 21 + 15 = 36 bytes.
+ *
+ * Let's just read 2^6 (64) instead for good measure. If PID_MAX ever
+ * grows past 2^22 we'll be future-proof. We'll then anchor at the
+ * last ")" we find to locate the parent PID.
+ */
+#define STAT_PARENT_PID_READ_N 64
+
+static int parse_proc_stat(struct strbuf *sb, struct strbuf *name,
+			    int *statppid)
+{
+	const char *comm_lhs = strchr(sb->buf, '(');
+	const char *comm_rhs = strrchr(sb->buf, ')');
+	const char *ppid_lhs, *ppid_rhs;
+	char *p;
+	pid_t ppid;
+
+	if (!comm_lhs || !comm_rhs)
+		goto bad_kernel;
+
+	/*
+	 * We're at the ")", that's followed by " X ", where X is a
+	 * single "state" character. So advance by 4 bytes.
+	 */
+	ppid_lhs = comm_rhs + 4;
+
+	/*
+	 * Read until the space between the "ppid" and "pgrp" fields
+	 * to make sure we're anchored after the untruncated "ppid"
+	 * field..
+	 */
+	ppid_rhs = strchr(ppid_lhs, ' ');
+	if (!ppid_rhs)
+		goto bad_kernel;
+
+	ppid = strtol(ppid_lhs, &p, 10);
+	if (ppid_rhs == p) {
+		const char *comm = comm_lhs + 1;
+		size_t commlen = comm_rhs - comm;
+
+		strbuf_add(name, comm, commlen);
+		*statppid = ppid;
+
+		return 0;
+	}
+
+bad_kernel:
+	/*
+	 * We were able to read our STAT_PARENT_PID_READ_N bytes from
+	 * /proc/%d/stat, but the content is bad. Broken kernel?
+	 * Should not happen, but handle it gracefully.
+	 */
+	return -1;
+}
+
+static int stat_parent_pid(pid_t pid, struct strbuf *name, int *statppid)
+{
+	struct strbuf procfs_path = STRBUF_INIT;
+	struct strbuf sb = STRBUF_INIT;
+	FILE *fp;
+	int ret = -1;
+
+	/* try to use procfs if it's present. */
+	strbuf_addf(&procfs_path, "/proc/%d/stat", pid);
+	fp = fopen(procfs_path.buf, "r");
+	if (!fp)
+		goto cleanup;
+
+	/*
+	 * We could be more strict here and assert that we read at
+	 * least STAT_PARENT_PID_READ_N. My reading of procfs(5) is
+	 * that on any modern kernel (at least since 2.6.0 released in
+	 * 2003) even if all the mandatory numeric fields were zero'd
+	 * out we'd get at least 100 bytes, but let's just check that
+	 * we got anything at all and trust the parse_proc_stat()
+	 * function to handle its "Bad Kernel?" error checking.
+	 */
+	if (!strbuf_fread(&sb, STAT_PARENT_PID_READ_N, fp))
+		goto cleanup;
+	if (parse_proc_stat(&sb, name, statppid) < 0)
+		goto cleanup;
+
+	ret = 0;
+cleanup:
+	if (fp)
+		fclose(fp);
+	strbuf_release(&procfs_path);
+	strbuf_release(&sb);
+
+	return ret;
+}
+
+static void push_ancestry_name(struct strvec *names, pid_t pid)
+{
+	struct strbuf name = STRBUF_INIT;
+	int ppid;
+
+	if (stat_parent_pid(pid, &name, &ppid) < 0)
+		goto cleanup;
+
+	strvec_push(names, name.buf);
+
+	/*
+	 * Both errors and reaching the end of the process chain are
+	 * reported as fields of 0 by proc(5)
+	 */
+	if (ppid)
+		push_ancestry_name(names, ppid);
+cleanup:
+	strbuf_release(&name);
+
+	return;
+}
+
+void trace2_collect_process_info(enum trace2_process_info_reason reason)
+{
+	struct strvec names = STRVEC_INIT;
+
+	if (!trace2_is_enabled())
+		return;
+
+	switch (reason) {
+	case TRACE2_PROCESS_INFO_EXIT:
+		/*
+		 * The Windows version of this calls its
+		 * get_peak_memory_info() here. We may want to insert
+		 * similar process-end statistics here in the future.
+		 */
+		break;
+	case TRACE2_PROCESS_INFO_STARTUP:
+		push_ancestry_name(&names, getppid());
+
+		if (names.nr)
+			trace2_cmd_ancestry(names.v);
+		strvec_clear(&names);
+		break;
+	}
+
+	return;
+}
diff --git a/compat/memmem.c b/compat/memmem.c
new file mode 100644
index 0000000000..56bcb4277f
--- /dev/null
+++ b/compat/memmem.c
@@ -0,0 +1,32 @@
+#include "../git-compat-util.h"
+
+void *gitmemmem(const void *haystack, size_t haystack_len,
+                const void *needle, size_t needle_len)
+{
+	const char *begin = haystack;
+	const char *last_possible = begin + haystack_len - needle_len;
+	const char *tail = needle;
+	char point;
+
+	/*
+	 * The first occurrence of the empty string is deemed to occur at
+	 * the beginning of the string.
+	 */
+	if (needle_len == 0)
+		return (void *)begin;
+
+	/*
+	 * Sanity check, otherwise the loop might search through the whole
+	 * memory.
+	 */
+	if (haystack_len < needle_len)
+		return NULL;
+
+	point = *tail++;
+	for (; begin <= last_possible; begin++) {
+		if (*begin == point && !memcmp(begin + 1, tail, needle_len - 1))
+			return (void *)begin;
+	}
+
+	return NULL;
+}
diff --git a/compat/mingw.c b/compat/mingw.c
new file mode 100644
index 0000000000..1d5b211b54
--- /dev/null
+++ b/compat/mingw.c
@@ -0,0 +1,3338 @@
+#define USE_THE_REPOSITORY_VARIABLE
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "../git-compat-util.h"
+#include "win32.h"
+#include <aclapi.h>
+#include <sddl.h>
+#include <conio.h>
+#include <wchar.h>
+#include "../strbuf.h"
+#include "../run-command.h"
+#include "../abspath.h"
+#include "../alloc.h"
+#include "win32/lazyload.h"
+#include "../config.h"
+#include "../environment.h"
+#include "../trace2.h"
+#include "../symlinks.h"
+#include "../wrapper.h"
+#include "dir.h"
+#include "gettext.h"
+#define SECURITY_WIN32
+#include <sspi.h>
+
+#define HCAST(type, handle) ((type)(intptr_t)handle)
+
+static const int delay[] = { 0, 1, 10, 20, 40 };
+
+void open_in_gdb(void)
+{
+	static struct child_process cp = CHILD_PROCESS_INIT;
+
+	strvec_pushl(&cp.args, "mintty", "gdb", NULL);
+	strvec_pushf(&cp.args, "--pid=%d", getpid());
+	cp.clean_on_exit = 1;
+	if (start_command(&cp) < 0)
+		die_errno("Could not start gdb");
+	sleep(1);
+}
+
+int err_win_to_posix(DWORD winerr)
+{
+	int error = ENOSYS;
+	switch(winerr) {
+	case ERROR_ACCESS_DENIED: error = EACCES; break;
+	case ERROR_ACCOUNT_DISABLED: error = EACCES; break;
+	case ERROR_ACCOUNT_RESTRICTION: error = EACCES; break;
+	case ERROR_ALREADY_ASSIGNED: error = EBUSY; break;
+	case ERROR_ALREADY_EXISTS: error = EEXIST; break;
+	case ERROR_ARITHMETIC_OVERFLOW: error = ERANGE; break;
+	case ERROR_BAD_COMMAND: error = EIO; break;
+	case ERROR_BAD_DEVICE: error = ENODEV; break;
+	case ERROR_BAD_DRIVER_LEVEL: error = ENXIO; break;
+	case ERROR_BAD_EXE_FORMAT: error = ENOEXEC; break;
+	case ERROR_BAD_FORMAT: error = ENOEXEC; break;
+	case ERROR_BAD_LENGTH: error = EINVAL; break;
+	case ERROR_BAD_PATHNAME: error = ENOENT; break;
+	case ERROR_BAD_PIPE: error = EPIPE; break;
+	case ERROR_BAD_UNIT: error = ENODEV; break;
+	case ERROR_BAD_USERNAME: error = EINVAL; break;
+	case ERROR_BROKEN_PIPE: error = EPIPE; break;
+	case ERROR_BUFFER_OVERFLOW: error = ENAMETOOLONG; break;
+	case ERROR_BUSY: error = EBUSY; break;
+	case ERROR_BUSY_DRIVE: error = EBUSY; break;
+	case ERROR_CALL_NOT_IMPLEMENTED: error = ENOSYS; break;
+	case ERROR_CANNOT_MAKE: error = EACCES; break;
+	case ERROR_CANTOPEN: error = EIO; break;
+	case ERROR_CANTREAD: error = EIO; break;
+	case ERROR_CANTWRITE: error = EIO; break;
+	case ERROR_CRC: error = EIO; break;
+	case ERROR_CURRENT_DIRECTORY: error = EACCES; break;
+	case ERROR_DEVICE_IN_USE: error = EBUSY; break;
+	case ERROR_DEV_NOT_EXIST: error = ENODEV; break;
+	case ERROR_DIRECTORY: error = EINVAL; break;
+	case ERROR_DIR_NOT_EMPTY: error = ENOTEMPTY; break;
+	case ERROR_DISK_CHANGE: error = EIO; break;
+	case ERROR_DISK_FULL: error = ENOSPC; break;
+	case ERROR_DRIVE_LOCKED: error = EBUSY; break;
+	case ERROR_ENVVAR_NOT_FOUND: error = EINVAL; break;
+	case ERROR_EXE_MARKED_INVALID: error = ENOEXEC; break;
+	case ERROR_FILENAME_EXCED_RANGE: error = ENAMETOOLONG; break;
+	case ERROR_FILE_EXISTS: error = EEXIST; break;
+	case ERROR_FILE_INVALID: error = ENODEV; break;
+	case ERROR_FILE_NOT_FOUND: error = ENOENT; break;
+	case ERROR_GEN_FAILURE: error = EIO; break;
+	case ERROR_HANDLE_DISK_FULL: error = ENOSPC; break;
+	case ERROR_INSUFFICIENT_BUFFER: error = ENOMEM; break;
+	case ERROR_INVALID_ACCESS: error = EACCES; break;
+	case ERROR_INVALID_ADDRESS: error = EFAULT; break;
+	case ERROR_INVALID_BLOCK: error = EFAULT; break;
+	case ERROR_INVALID_DATA: error = EINVAL; break;
+	case ERROR_INVALID_DRIVE: error = ENODEV; break;
+	case ERROR_INVALID_EXE_SIGNATURE: error = ENOEXEC; break;
+	case ERROR_INVALID_FLAGS: error = EINVAL; break;
+	case ERROR_INVALID_FUNCTION: error = ENOSYS; break;
+	case ERROR_INVALID_HANDLE: error = EBADF; break;
+	case ERROR_INVALID_LOGON_HOURS: error = EACCES; break;
+	case ERROR_INVALID_NAME: error = EINVAL; break;
+	case ERROR_INVALID_OWNER: error = EINVAL; break;
+	case ERROR_INVALID_PARAMETER: error = EINVAL; break;
+	case ERROR_INVALID_PASSWORD: error = EPERM; break;
+	case ERROR_INVALID_PRIMARY_GROUP: error = EINVAL; break;
+	case ERROR_INVALID_SIGNAL_NUMBER: error = EINVAL; break;
+	case ERROR_INVALID_TARGET_HANDLE: error = EIO; break;
+	case ERROR_INVALID_WORKSTATION: error = EACCES; break;
+	case ERROR_IO_DEVICE: error = EIO; break;
+	case ERROR_IO_INCOMPLETE: error = EINTR; break;
+	case ERROR_LOCKED: error = EBUSY; break;
+	case ERROR_LOCK_VIOLATION: error = EACCES; break;
+	case ERROR_LOGON_FAILURE: error = EACCES; break;
+	case ERROR_MAPPED_ALIGNMENT: error = EINVAL; break;
+	case ERROR_META_EXPANSION_TOO_LONG: error = E2BIG; break;
+	case ERROR_MORE_DATA: error = EPIPE; break;
+	case ERROR_NEGATIVE_SEEK: error = ESPIPE; break;
+	case ERROR_NOACCESS: error = EFAULT; break;
+	case ERROR_NONE_MAPPED: error = EINVAL; break;
+	case ERROR_NOT_ENOUGH_MEMORY: error = ENOMEM; break;
+	case ERROR_NOT_READY: error = EAGAIN; break;
+	case ERROR_NOT_SAME_DEVICE: error = EXDEV; break;
+	case ERROR_NO_DATA: error = EPIPE; break;
+	case ERROR_NO_MORE_SEARCH_HANDLES: error = EIO; break;
+	case ERROR_NO_PROC_SLOTS: error = EAGAIN; break;
+	case ERROR_NO_SUCH_PRIVILEGE: error = EACCES; break;
+	case ERROR_OPEN_FAILED: error = EIO; break;
+	case ERROR_OPEN_FILES: error = EBUSY; break;
+	case ERROR_OPERATION_ABORTED: error = EINTR; break;
+	case ERROR_OUTOFMEMORY: error = ENOMEM; break;
+	case ERROR_PASSWORD_EXPIRED: error = EACCES; break;
+	case ERROR_PATH_BUSY: error = EBUSY; break;
+	case ERROR_PATH_NOT_FOUND: error = ENOENT; break;
+	case ERROR_PIPE_BUSY: error = EBUSY; break;
+	case ERROR_PIPE_CONNECTED: error = EPIPE; break;
+	case ERROR_PIPE_LISTENING: error = EPIPE; break;
+	case ERROR_PIPE_NOT_CONNECTED: error = EPIPE; break;
+	case ERROR_PRIVILEGE_NOT_HELD: error = EACCES; break;
+	case ERROR_READ_FAULT: error = EIO; break;
+	case ERROR_SEEK: error = EIO; break;
+	case ERROR_SEEK_ON_DEVICE: error = ESPIPE; break;
+	case ERROR_SHARING_BUFFER_EXCEEDED: error = ENFILE; break;
+	case ERROR_SHARING_VIOLATION: error = EACCES; break;
+	case ERROR_STACK_OVERFLOW: error = ENOMEM; break;
+	case ERROR_SUCCESS: BUG("err_win_to_posix() called without an error!");
+	case ERROR_SWAPERROR: error = ENOENT; break;
+	case ERROR_TOO_MANY_MODULES: error = EMFILE; break;
+	case ERROR_TOO_MANY_OPEN_FILES: error = EMFILE; break;
+	case ERROR_UNRECOGNIZED_MEDIA: error = ENXIO; break;
+	case ERROR_UNRECOGNIZED_VOLUME: error = ENODEV; break;
+	case ERROR_WAIT_NO_CHILDREN: error = ECHILD; break;
+	case ERROR_WRITE_FAULT: error = EIO; break;
+	case ERROR_WRITE_PROTECT: error = EROFS; break;
+	}
+	return error;
+}
+
+static inline int is_file_in_use_error(DWORD errcode)
+{
+	switch (errcode) {
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_ACCESS_DENIED:
+		return 1;
+	}
+
+	return 0;
+}
+
+static int read_yes_no_answer(void)
+{
+	char answer[1024];
+
+	if (fgets(answer, sizeof(answer), stdin)) {
+		size_t answer_len = strlen(answer);
+		int got_full_line = 0, c;
+
+		/* remove the newline */
+		if (answer_len >= 2 && answer[answer_len-2] == '\r') {
+			answer[answer_len-2] = '\0';
+			got_full_line = 1;
+		} else if (answer_len >= 1 && answer[answer_len-1] == '\n') {
+			answer[answer_len-1] = '\0';
+			got_full_line = 1;
+		}
+		/* flush the buffer in case we did not get the full line */
+		if (!got_full_line)
+			while ((c = getchar()) != EOF && c != '\n')
+				;
+	} else
+		/* we could not read, return the
+		 * default answer which is no */
+		return 0;
+
+	if (tolower(answer[0]) == 'y' && !answer[1])
+		return 1;
+	if (!strncasecmp(answer, "yes", sizeof(answer)))
+		return 1;
+	if (tolower(answer[0]) == 'n' && !answer[1])
+		return 0;
+	if (!strncasecmp(answer, "no", sizeof(answer)))
+		return 0;
+
+	/* did not find an answer we understand */
+	return -1;
+}
+
+static int ask_yes_no_if_possible(const char *format, ...)
+{
+	char question[4096];
+	const char *retry_hook;
+	va_list args;
+
+	va_start(args, format);
+	vsnprintf(question, sizeof(question), format, args);
+	va_end(args);
+
+	retry_hook = mingw_getenv("GIT_ASK_YESNO");
+	if (retry_hook) {
+		struct child_process cmd = CHILD_PROCESS_INIT;
+
+		strvec_pushl(&cmd.args, retry_hook, question, NULL);
+		return !run_command(&cmd);
+	}
+
+	if (!isatty(_fileno(stdin)) || !isatty(_fileno(stderr)))
+		return 0;
+
+	while (1) {
+		int answer;
+		fprintf(stderr, "%s (y/n) ", question);
+
+		if ((answer = read_yes_no_answer()) >= 0)
+			return answer;
+
+		fprintf(stderr, "Sorry, I did not understand your answer. "
+				"Please type 'y' or 'n'\n");
+	}
+}
+
+/* Windows only */
+enum hide_dotfiles_type {
+	HIDE_DOTFILES_FALSE = 0,
+	HIDE_DOTFILES_TRUE,
+	HIDE_DOTFILES_DOTGITONLY
+};
+
+static int core_restrict_inherited_handles = -1;
+static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+static char *unset_environment_variables;
+
+int mingw_core_config(const char *var, const char *value,
+		      const struct config_context *ctx UNUSED,
+		      void *cb UNUSED)
+{
+	if (!strcmp(var, "core.hidedotfiles")) {
+		if (value && !strcasecmp(value, "dotgitonly"))
+			hide_dotfiles = HIDE_DOTFILES_DOTGITONLY;
+		else
+			hide_dotfiles = git_config_bool(var, value);
+		return 0;
+	}
+
+	if (!strcmp(var, "core.unsetenvvars")) {
+		if (!value)
+			return config_error_nonbool(var);
+		free(unset_environment_variables);
+		unset_environment_variables = xstrdup(value);
+		return 0;
+	}
+
+	if (!strcmp(var, "core.restrictinheritedhandles")) {
+		if (value && !strcasecmp(value, "auto"))
+			core_restrict_inherited_handles = -1;
+		else
+			core_restrict_inherited_handles =
+				git_config_bool(var, value);
+		return 0;
+	}
+
+	return 0;
+}
+
+/* Normalizes NT paths as returned by some low-level APIs. */
+static wchar_t *normalize_ntpath(wchar_t *wbuf)
+{
+	int i;
+	/* fix absolute path prefixes */
+	if (wbuf[0] == '\\') {
+		/* strip NT namespace prefixes */
+		if (!wcsncmp(wbuf, L"\\??\\", 4) ||
+		    !wcsncmp(wbuf, L"\\\\?\\", 4))
+			wbuf += 4;
+		else if (!wcsnicmp(wbuf, L"\\DosDevices\\", 12))
+			wbuf += 12;
+		/* replace remaining '...UNC\' with '\\' */
+		if (!wcsnicmp(wbuf, L"UNC\\", 4)) {
+			wbuf += 2;
+			*wbuf = '\\';
+		}
+	}
+	/* convert backslashes to slashes */
+	for (i = 0; wbuf[i]; i++)
+		if (wbuf[i] == '\\')
+			wbuf[i] = '/';
+	return wbuf;
+}
+
+int mingw_unlink(const char *pathname)
+{
+	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
+
+	if (DeleteFileW(wpathname))
+		return 0;
+
+	/* read-only files cannot be removed */
+	_wchmod(wpathname, 0666);
+	while ((ret = _wunlink(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+		if (!is_file_in_use_error(GetLastError()))
+			break;
+		/*
+		 * We assume that some other process had the source or
+		 * destination file open at the wrong moment and retry.
+		 * In order to give the other process a higher chance to
+		 * complete its operation, we give up our time slice now.
+		 * If we have to retry again, we do sleep a bit.
+		 */
+		Sleep(delay[tries]);
+		tries++;
+	}
+	while (ret == -1 && is_file_in_use_error(GetLastError()) &&
+	       ask_yes_no_if_possible("Unlink of file '%s' failed. "
+			"Should I try again?", pathname))
+	       ret = _wunlink(wpathname);
+	return ret;
+}
+
+static int is_dir_empty(const wchar_t *wpath)
+{
+	WIN32_FIND_DATAW findbuf;
+	HANDLE handle;
+	wchar_t wbuf[MAX_PATH + 2];
+	wcscpy(wbuf, wpath);
+	wcscat(wbuf, L"\\*");
+	handle = FindFirstFileW(wbuf, &findbuf);
+	if (handle == INVALID_HANDLE_VALUE)
+		return GetLastError() == ERROR_NO_MORE_FILES;
+
+	while (!wcscmp(findbuf.cFileName, L".") ||
+			!wcscmp(findbuf.cFileName, L".."))
+		if (!FindNextFileW(handle, &findbuf)) {
+			DWORD err = GetLastError();
+			FindClose(handle);
+			return err == ERROR_NO_MORE_FILES;
+		}
+	FindClose(handle);
+	return 0;
+}
+
+int mingw_rmdir(const char *pathname)
+{
+	int ret, tries = 0;
+	wchar_t wpathname[MAX_PATH];
+	struct stat st;
+
+	/*
+	 * Contrary to Linux' `rmdir()`, Windows' _wrmdir() and _rmdir()
+	 * (and `RemoveDirectoryW()`) will attempt to remove the target of a
+	 * symbolic link (if it points to a directory).
+	 *
+	 * This behavior breaks the assumption of e.g. `remove_path()` which
+	 * upon successful deletion of a file will attempt to remove its parent
+	 * directories recursively until failure (which usually happens when
+	 * the directory is not empty).
+	 *
+	 * Therefore, before calling `_wrmdir()`, we first check if the path is
+	 * a symbolic link. If it is, we exit and return the same error as
+	 * Linux' `rmdir()` would, i.e. `ENOTDIR`.
+	 */
+	if (!mingw_lstat(pathname, &st) && S_ISLNK(st.st_mode)) {
+		errno = ENOTDIR;
+		return -1;
+	}
+
+	if (xutftowcs_path(wpathname, pathname) < 0)
+		return -1;
+
+	while ((ret = _wrmdir(wpathname)) == -1 && tries < ARRAY_SIZE(delay)) {
+		if (!is_file_in_use_error(GetLastError()))
+			errno = err_win_to_posix(GetLastError());
+		if (errno != EACCES)
+			break;
+		if (!is_dir_empty(wpathname)) {
+			errno = ENOTEMPTY;
+			break;
+		}
+		/*
+		 * We assume that some other process had the source or
+		 * destination file open at the wrong moment and retry.
+		 * In order to give the other process a higher chance to
+		 * complete its operation, we give up our time slice now.
+		 * If we have to retry again, we do sleep a bit.
+		 */
+		Sleep(delay[tries]);
+		tries++;
+	}
+	while (ret == -1 && errno == EACCES && is_file_in_use_error(GetLastError()) &&
+	       ask_yes_no_if_possible("Deletion of directory '%s' failed. "
+			"Should I try again?", pathname))
+	       ret = _wrmdir(wpathname);
+	if (!ret)
+		invalidate_lstat_cache();
+	return ret;
+}
+
+static inline int needs_hiding(const char *path)
+{
+	const char *basename;
+
+	if (hide_dotfiles == HIDE_DOTFILES_FALSE)
+		return 0;
+
+	/* We cannot use basename(), as it would remove trailing slashes */
+	win32_skip_dos_drive_prefix((char **)&path);
+	if (!*path)
+		return 0;
+
+	for (basename = path; *path; path++)
+		if (is_dir_sep(*path)) {
+			do {
+				path++;
+			} while (is_dir_sep(*path));
+			/* ignore trailing slashes */
+			if (*path)
+				basename = path;
+			else
+				break;
+		}
+
+	if (hide_dotfiles == HIDE_DOTFILES_TRUE)
+		return *basename == '.';
+
+	assert(hide_dotfiles == HIDE_DOTFILES_DOTGITONLY);
+	return !strncasecmp(".git", basename, 4) &&
+		(!basename[4] || is_dir_sep(basename[4]));
+}
+
+static int set_hidden_flag(const wchar_t *path, int set)
+{
+	DWORD original = GetFileAttributesW(path), modified;
+	if (set)
+		modified = original | FILE_ATTRIBUTE_HIDDEN;
+	else
+		modified = original & ~FILE_ATTRIBUTE_HIDDEN;
+	if (original == modified || SetFileAttributesW(path, modified))
+		return 0;
+	errno = err_win_to_posix(GetLastError());
+	return -1;
+}
+
+int mingw_mkdir(const char *path, int mode UNUSED)
+{
+	int ret;
+	wchar_t wpath[MAX_PATH];
+
+	if (!is_valid_win32_path(path, 0)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (xutftowcs_path(wpath, path) < 0)
+		return -1;
+	ret = _wmkdir(wpath);
+	if (!ret && needs_hiding(path))
+		return set_hidden_flag(wpath, 1);
+	return ret;
+}
+
+/*
+ * Calling CreateFile() using FILE_APPEND_DATA and without FILE_WRITE_DATA
+ * is documented in [1] as opening a writable file handle in append mode.
+ * (It is believed that) this is atomic since it is maintained by the
+ * kernel unlike the O_APPEND flag which is racily maintained by the CRT.
+ *
+ * [1] https://docs.microsoft.com/en-us/windows/desktop/fileio/file-access-rights-constants
+ *
+ * This trick does not appear to work for named pipes.  Instead it creates
+ * a named pipe client handle that cannot be written to.  Callers should
+ * just use the regular _wopen() for them.  (And since client handle gets
+ * bound to a unique server handle, it isn't really an issue.)
+ */
+static int mingw_open_append(wchar_t const *wfilename, int oflags, ...)
+{
+	HANDLE handle;
+	int fd;
+	DWORD create = (oflags & O_CREAT) ? OPEN_ALWAYS : OPEN_EXISTING;
+
+	/* only these flags are supported */
+	if ((oflags & ~O_CREAT) != (O_WRONLY | O_APPEND))
+		return errno = ENOSYS, -1;
+
+	/*
+	 * FILE_SHARE_WRITE is required to permit child processes
+	 * to append to the file.
+	 */
+	handle = CreateFileW(wfilename, FILE_APPEND_DATA,
+			FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+			NULL, create, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (handle == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+
+		/*
+		 * Some network storage solutions (e.g. Isilon) might return
+		 * ERROR_INVALID_PARAMETER instead of expected error
+		 * ERROR_PATH_NOT_FOUND, which results in an unknown error. If
+		 * so, let's turn the error to ERROR_PATH_NOT_FOUND instead.
+		 */
+		if (err == ERROR_INVALID_PARAMETER)
+			err = ERROR_PATH_NOT_FOUND;
+
+		errno = err_win_to_posix(err);
+		return -1;
+	}
+
+	/*
+	 * No O_APPEND here, because the CRT uses it only to reset the
+	 * file pointer to EOF before each write(); but that is not
+	 * necessary (and may lead to races) for a file created with
+	 * FILE_APPEND_DATA.
+	 */
+	fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+	if (fd < 0)
+		CloseHandle(handle);
+	return fd;
+}
+
+/*
+ * Ideally, we'd use `_wopen()` to implement this functionality so that we
+ * don't have to reimplement it, but unfortunately we do not have tight control
+ * over the share mode there. And while `_wsopen()` and friends exist that give
+ * us _some_ control over the share mode, this family of functions doesn't give
+ * us the ability to enable FILE_SHARE_DELETE, either. But this is a strict
+ * requirement for us though so that we can unlink or rename over files that
+ * are held open by another process.
+ *
+ * We are thus forced to implement our own emulation of `open()`. To make our
+ * life simpler we only implement basic support for this, namely opening
+ * existing files for reading and/or writing. This means that newly created
+ * files won't have their sharing mode set up correctly, but for now I couldn't
+ * find any case where this matters. We may have to revisit that in the future
+ * though based on our needs.
+ */
+static int mingw_open_existing(const wchar_t *filename, int oflags, ...)
+{
+	SECURITY_ATTRIBUTES security_attributes = {
+		.nLength = sizeof(security_attributes),
+		.bInheritHandle = !(oflags & O_NOINHERIT),
+	};
+	HANDLE handle;
+	DWORD access;
+	int fd;
+
+	/* We only support basic flags. */
+	if (oflags & ~(O_ACCMODE | O_NOINHERIT)) {
+		errno = ENOSYS;
+		return -1;
+	}
+
+	switch (oflags & O_ACCMODE) {
+	case O_RDWR:
+		access = GENERIC_READ | GENERIC_WRITE;
+		break;
+	case O_WRONLY:
+		access = GENERIC_WRITE;
+		break;
+	default:
+		access = GENERIC_READ;
+		break;
+	}
+
+	handle = CreateFileW(filename, access,
+			     FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+			     &security_attributes, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (handle == INVALID_HANDLE_VALUE) {
+		DWORD err = GetLastError();
+
+		/* See `mingw_open_append()` for why we have this conversion. */
+		if (err == ERROR_INVALID_PARAMETER)
+			err = ERROR_PATH_NOT_FOUND;
+
+		errno = err_win_to_posix(err);
+		return -1;
+	}
+
+	fd = _open_osfhandle((intptr_t)handle, oflags | O_BINARY);
+	if (fd < 0)
+		CloseHandle(handle);
+	return fd;
+}
+
+/*
+ * Does the pathname map to the local named pipe filesystem?
+ * That is, does it have a "//./pipe/" prefix?
+ */
+static int is_local_named_pipe_path(const char *filename)
+{
+	return (is_dir_sep(filename[0]) &&
+		is_dir_sep(filename[1]) &&
+		filename[2] == '.'  &&
+		is_dir_sep(filename[3]) &&
+		!strncasecmp(filename+4, "pipe", 4) &&
+		is_dir_sep(filename[8]) &&
+		filename[9]);
+}
+
+int mingw_open (const char *filename, int oflags, ...)
+{
+	typedef int (*open_fn_t)(wchar_t const *wfilename, int oflags, ...);
+	va_list args;
+	unsigned mode;
+	int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
+	wchar_t wfilename[MAX_PATH];
+	open_fn_t open_fn;
+
+	va_start(args, oflags);
+	mode = va_arg(args, int);
+	va_end(args);
+
+	if (!is_valid_win32_path(filename, !create)) {
+		errno = create ? EINVAL : ENOENT;
+		return -1;
+	}
+
+	if ((oflags & O_APPEND) && !is_local_named_pipe_path(filename))
+		open_fn = mingw_open_append;
+	else if (!(oflags & ~(O_ACCMODE | O_NOINHERIT)))
+		open_fn = mingw_open_existing;
+	else
+		open_fn = _wopen;
+
+	if (filename && !strcmp(filename, "/dev/null"))
+		wcscpy(wfilename, L"nul");
+	else if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+
+	fd = open_fn(wfilename, oflags, mode);
+
+	if (fd < 0 && (oflags & O_ACCMODE) != O_RDONLY && errno == EACCES) {
+		DWORD attrs = GetFileAttributesW(wfilename);
+		if (attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY))
+			errno = EISDIR;
+	}
+	if ((oflags & O_CREAT) && needs_hiding(filename)) {
+		/*
+		 * Internally, _wopen() uses the CreateFile() API which errors
+		 * out with an ERROR_ACCESS_DENIED if CREATE_ALWAYS was
+		 * specified and an already existing file's attributes do not
+		 * match *exactly*. As there is no mode or flag we can set that
+		 * would correspond to FILE_ATTRIBUTE_HIDDEN, let's just try
+		 * again *without* the O_CREAT flag (that corresponds to the
+		 * CREATE_ALWAYS flag of CreateFile()).
+		 */
+		if (fd < 0 && errno == EACCES)
+			fd = open_fn(wfilename, oflags & ~O_CREAT, mode);
+		if (fd >= 0 && set_hidden_flag(wfilename, 1))
+			warning("could not mark '%s' as hidden.", filename);
+	}
+	return fd;
+}
+
+static BOOL WINAPI ctrl_ignore(DWORD type UNUSED)
+{
+	return TRUE;
+}
+
+#undef fgetc
+int mingw_fgetc(FILE *stream)
+{
+	int ch;
+	if (!isatty(_fileno(stream)))
+		return fgetc(stream);
+
+	SetConsoleCtrlHandler(ctrl_ignore, TRUE);
+	while (1) {
+		ch = fgetc(stream);
+		if (ch != EOF || GetLastError() != ERROR_OPERATION_ABORTED)
+			break;
+
+		/* Ctrl+C was pressed, simulate SIGINT and retry */
+		mingw_raise(SIGINT);
+	}
+	SetConsoleCtrlHandler(ctrl_ignore, FALSE);
+	return ch;
+}
+
+#undef fopen
+FILE *mingw_fopen (const char *filename, const char *otype)
+{
+	int hide = needs_hiding(filename);
+	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
+	if (filename && !strcmp(filename, "/dev/null"))
+		wcscpy(wfilename, L"nul");
+	else if (!is_valid_win32_path(filename, 1)) {
+		int create = otype && strchr(otype, 'w');
+		errno = create ? EINVAL : ENOENT;
+		return NULL;
+	} else if (xutftowcs_path(wfilename, filename) < 0)
+		return NULL;
+
+	if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+
+	if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) {
+		error("could not unhide %s", filename);
+		return NULL;
+	}
+	file = _wfopen(wfilename, wotype);
+	if (!file && GetLastError() == ERROR_INVALID_NAME)
+		errno = ENOENT;
+	if (file && hide && set_hidden_flag(wfilename, 1))
+		warning("could not mark '%s' as hidden.", filename);
+	return file;
+}
+
+FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream)
+{
+	int hide = needs_hiding(filename);
+	FILE *file;
+	wchar_t wfilename[MAX_PATH], wotype[4];
+	if (filename && !strcmp(filename, "/dev/null"))
+		wcscpy(wfilename, L"nul");
+	else if (!is_valid_win32_path(filename, 1)) {
+		int create = otype && strchr(otype, 'w');
+		errno = create ? EINVAL : ENOENT;
+		return NULL;
+	} else if (xutftowcs_path(wfilename, filename) < 0)
+		return NULL;
+
+	if (xutftowcs(wotype, otype, ARRAY_SIZE(wotype)) < 0)
+		return NULL;
+
+	if (hide && !access(filename, F_OK) && set_hidden_flag(wfilename, 0)) {
+		error("could not unhide %s", filename);
+		return NULL;
+	}
+	file = _wfreopen(wfilename, wotype, stream);
+	if (file && hide && set_hidden_flag(wfilename, 1))
+		warning("could not mark '%s' as hidden.", filename);
+	return file;
+}
+
+#undef fflush
+int mingw_fflush(FILE *stream)
+{
+	int ret = fflush(stream);
+
+	/*
+	 * write() is used behind the scenes of stdio output functions.
+	 * Since git code does not check for errors after each stdio write
+	 * operation, it can happen that write() is called by a later
+	 * stdio function even if an earlier write() call failed. In the
+	 * case of a pipe whose readable end was closed, only the first
+	 * call to write() reports EPIPE on Windows. Subsequent write()
+	 * calls report EINVAL. It is impossible to notice whether this
+	 * fflush invocation triggered such a case, therefore, we have to
+	 * catch all EINVAL errors whole-sale.
+	 */
+	if (ret && errno == EINVAL)
+		errno = EPIPE;
+
+	return ret;
+}
+
+#undef write
+ssize_t mingw_write(int fd, const void *buf, size_t len)
+{
+	ssize_t result = write(fd, buf, len);
+
+	if (result < 0 && (errno == EINVAL || errno == ENOSPC) && buf) {
+		int orig = errno;
+
+		/* check if fd is a pipe */
+		HANDLE h = (HANDLE) _get_osfhandle(fd);
+		if (GetFileType(h) != FILE_TYPE_PIPE)
+			errno = orig;
+		else if (orig == EINVAL)
+			errno = EPIPE;
+		else {
+			DWORD buf_size;
+
+			if (!GetNamedPipeInfo(h, NULL, NULL, &buf_size, NULL))
+				buf_size = 4096;
+			if (len > buf_size)
+				return write(fd, buf, buf_size);
+			errno = orig;
+		}
+	}
+
+	return result;
+}
+
+int mingw_access(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (!strcmp("nul", filename) || !strcmp("/dev/null", filename))
+		return 0;
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	/* X_OK is not supported by the MSVCRT version */
+	return _waccess(wfilename, mode & ~X_OK);
+}
+
+int mingw_chdir(const char *dirname)
+{
+	wchar_t wdirname[MAX_PATH];
+	if (xutftowcs_path(wdirname, dirname) < 0)
+		return -1;
+	return _wchdir(wdirname);
+}
+
+int mingw_chmod(const char *filename, int mode)
+{
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, filename) < 0)
+		return -1;
+	return _wchmod(wfilename, mode);
+}
+
+/*
+ * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC.
+ * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch.
+ */
+static inline long long filetime_to_hnsec(const FILETIME *ft)
+{
+	long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime;
+	/* Windows to Unix Epoch conversion */
+	return winTime - 116444736000000000LL;
+}
+
+static inline void filetime_to_timespec(const FILETIME *ft, struct timespec *ts)
+{
+	long long hnsec = filetime_to_hnsec(ft);
+	ts->tv_sec = (time_t)(hnsec / 10000000);
+	ts->tv_nsec = (hnsec % 10000000) * 100;
+}
+
+/**
+ * Verifies that safe_create_leading_directories() would succeed.
+ */
+static int has_valid_directory_prefix(wchar_t *wfilename)
+{
+	size_t n = wcslen(wfilename);
+
+	while (n > 0) {
+		wchar_t c = wfilename[--n];
+		DWORD attributes;
+
+		if (!is_dir_sep(c))
+			continue;
+
+		wfilename[n] = L'\0';
+		attributes = GetFileAttributesW(wfilename);
+		wfilename[n] = c;
+		if (attributes &
+		    (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE))
+			return 1;
+		if (attributes == INVALID_FILE_ATTRIBUTES)
+			switch (GetLastError()) {
+			case ERROR_PATH_NOT_FOUND:
+				continue;
+			case ERROR_FILE_NOT_FOUND:
+				/* This implies parent directory exists. */
+				return 1;
+			}
+		return 0;
+	}
+	return 1;
+}
+
+/* We keep the do_lstat code in a separate function to avoid recursion.
+ * When a path ends with a slash, the stat will fail with ENOENT. In
+ * this case, we strip the trailing slashes and stat again.
+ *
+ * If follow is true then act like stat() and report on the link
+ * target. Otherwise report on the link itself.
+ */
+static int do_lstat(int follow, const char *file_name, struct stat *buf)
+{
+	WIN32_FILE_ATTRIBUTE_DATA fdata;
+	wchar_t wfilename[MAX_PATH];
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
+
+	if (GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata)) {
+		buf->st_ino = 0;
+		buf->st_gid = 0;
+		buf->st_uid = 0;
+		buf->st_nlink = 1;
+		buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
+		buf->st_size = fdata.nFileSizeLow |
+			(((off_t)fdata.nFileSizeHigh)<<32);
+		buf->st_dev = buf->st_rdev = 0; /* not used by Git */
+		filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
+		filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
+		filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
+		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+			WIN32_FIND_DATAW findbuf;
+			HANDLE handle = FindFirstFileW(wfilename, &findbuf);
+			if (handle != INVALID_HANDLE_VALUE) {
+				if ((findbuf.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
+						(findbuf.dwReserved0 == IO_REPARSE_TAG_SYMLINK)) {
+					if (follow) {
+						char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+						buf->st_size = readlink(file_name, buffer, MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
+					} else {
+						buf->st_mode = S_IFLNK;
+					}
+					buf->st_mode |= S_IREAD;
+					if (!(findbuf.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
+						buf->st_mode |= S_IWRITE;
+				}
+				FindClose(handle);
+			}
+		}
+		return 0;
+	}
+	switch (GetLastError()) {
+	case ERROR_ACCESS_DENIED:
+	case ERROR_SHARING_VIOLATION:
+	case ERROR_LOCK_VIOLATION:
+	case ERROR_SHARING_BUFFER_EXCEEDED:
+		errno = EACCES;
+		break;
+	case ERROR_BUFFER_OVERFLOW:
+		errno = ENAMETOOLONG;
+		break;
+	case ERROR_NOT_ENOUGH_MEMORY:
+		errno = ENOMEM;
+		break;
+	case ERROR_PATH_NOT_FOUND:
+		if (!has_valid_directory_prefix(wfilename)) {
+			errno = ENOTDIR;
+			break;
+		}
+		/* fallthru */
+	default:
+		errno = ENOENT;
+		break;
+	}
+	return -1;
+}
+
+/* We provide our own lstat/fstat functions, since the provided
+ * lstat/fstat functions are so slow. These stat functions are
+ * tailored for Git's usage (read: fast), and are not meant to be
+ * complete. Note that Git stat()s are redirected to mingw_lstat()
+ * too, since Windows doesn't really handle symlinks that well.
+ */
+static int do_stat_internal(int follow, const char *file_name, struct stat *buf)
+{
+	size_t namelen;
+	char alt_name[PATH_MAX];
+
+	if (!do_lstat(follow, file_name, buf))
+		return 0;
+
+	/* if file_name ended in a '/', Windows returned ENOENT;
+	 * try again without trailing slashes
+	 */
+	if (errno != ENOENT)
+		return -1;
+
+	namelen = strlen(file_name);
+	if (namelen && file_name[namelen-1] != '/')
+		return -1;
+	while (namelen && file_name[namelen-1] == '/')
+		--namelen;
+	if (!namelen || namelen >= PATH_MAX)
+		return -1;
+
+	memcpy(alt_name, file_name, namelen);
+	alt_name[namelen] = 0;
+	return do_lstat(follow, alt_name, buf);
+}
+
+static int get_file_info_by_handle(HANDLE hnd, struct stat *buf)
+{
+	BY_HANDLE_FILE_INFORMATION fdata;
+
+	if (!GetFileInformationByHandle(hnd, &fdata)) {
+		errno = err_win_to_posix(GetLastError());
+		return -1;
+	}
+
+	buf->st_ino = 0;
+	buf->st_gid = 0;
+	buf->st_uid = 0;
+	buf->st_nlink = 1;
+	buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
+	buf->st_size = fdata.nFileSizeLow |
+		(((off_t)fdata.nFileSizeHigh)<<32);
+	buf->st_dev = buf->st_rdev = 0; /* not used by Git */
+	filetime_to_timespec(&(fdata.ftLastAccessTime), &(buf->st_atim));
+	filetime_to_timespec(&(fdata.ftLastWriteTime), &(buf->st_mtim));
+	filetime_to_timespec(&(fdata.ftCreationTime), &(buf->st_ctim));
+	return 0;
+}
+
+int mingw_lstat(const char *file_name, struct stat *buf)
+{
+	return do_stat_internal(0, file_name, buf);
+}
+int mingw_stat(const char *file_name, struct stat *buf)
+{
+	return do_stat_internal(1, file_name, buf);
+}
+
+int mingw_fstat(int fd, struct stat *buf)
+{
+	HANDLE fh = (HANDLE)_get_osfhandle(fd);
+	DWORD avail, type = GetFileType(fh) & ~FILE_TYPE_REMOTE;
+
+	switch (type) {
+	case FILE_TYPE_DISK:
+		return get_file_info_by_handle(fh, buf);
+
+	case FILE_TYPE_CHAR:
+	case FILE_TYPE_PIPE:
+		/* initialize stat fields */
+		memset(buf, 0, sizeof(*buf));
+		buf->st_nlink = 1;
+
+		if (type == FILE_TYPE_CHAR) {
+			buf->st_mode = _S_IFCHR;
+		} else {
+			buf->st_mode = _S_IFIFO;
+			if (PeekNamedPipe(fh, NULL, 0, NULL, &avail, NULL))
+				buf->st_size = avail;
+		}
+		return 0;
+
+	default:
+		errno = EBADF;
+		return -1;
+	}
+}
+
+static inline void time_t_to_filetime(time_t t, FILETIME *ft)
+{
+	long long winTime = t * 10000000LL + 116444736000000000LL;
+	ft->dwLowDateTime = winTime;
+	ft->dwHighDateTime = winTime >> 32;
+}
+
+int mingw_utime (const char *file_name, const struct utimbuf *times)
+{
+	FILETIME mft, aft;
+	int rc;
+	DWORD attrs;
+	wchar_t wfilename[MAX_PATH];
+	HANDLE osfilehandle;
+
+	if (xutftowcs_path(wfilename, file_name) < 0)
+		return -1;
+
+	/* must have write permission */
+	attrs = GetFileAttributesW(wfilename);
+	if (attrs != INVALID_FILE_ATTRIBUTES &&
+	    (attrs & FILE_ATTRIBUTE_READONLY)) {
+		/* ignore errors here; open() will report them */
+		SetFileAttributesW(wfilename, attrs & ~FILE_ATTRIBUTE_READONLY);
+	}
+
+	osfilehandle = CreateFileW(wfilename,
+				   FILE_WRITE_ATTRIBUTES,
+				   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+				   NULL,
+				   OPEN_EXISTING,
+				   (attrs != INVALID_FILE_ATTRIBUTES &&
+					(attrs & FILE_ATTRIBUTE_DIRECTORY)) ?
+					FILE_FLAG_BACKUP_SEMANTICS : 0,
+				   NULL);
+	if (osfilehandle == INVALID_HANDLE_VALUE) {
+		errno = err_win_to_posix(GetLastError());
+		rc = -1;
+		goto revert_attrs;
+	}
+
+	if (times) {
+		time_t_to_filetime(times->modtime, &mft);
+		time_t_to_filetime(times->actime, &aft);
+	} else {
+		GetSystemTimeAsFileTime(&mft);
+		aft = mft;
+	}
+
+	if (!SetFileTime(osfilehandle, NULL, &aft, &mft)) {
+		errno = EINVAL;
+		rc = -1;
+	} else
+		rc = 0;
+
+	if (osfilehandle != INVALID_HANDLE_VALUE)
+		CloseHandle(osfilehandle);
+
+revert_attrs:
+	if (attrs != INVALID_FILE_ATTRIBUTES &&
+	    (attrs & FILE_ATTRIBUTE_READONLY)) {
+		/* ignore errors again */
+		SetFileAttributesW(wfilename, attrs);
+	}
+	return rc;
+}
+
+#undef strftime
+size_t mingw_strftime(char *s, size_t max,
+		      const char *format, const struct tm *tm)
+{
+	/* a pointer to the original strftime in case we can't find the UCRT version */
+	static size_t (*fallback)(char *, size_t, const char *, const struct tm *) = strftime;
+	size_t ret;
+	DECLARE_PROC_ADDR(ucrtbase.dll, size_t, __cdecl, strftime, char *, size_t,
+		const char *, const struct tm *);
+
+	if (INIT_PROC_ADDR(strftime))
+		ret = strftime(s, max, format, tm);
+	else
+		ret = fallback(s, max, format, tm);
+
+	if (!ret && errno == EINVAL)
+		die("invalid strftime format: '%s'", format);
+	return ret;
+}
+
+unsigned int sleep (unsigned int seconds)
+{
+	Sleep(seconds*1000);
+	return 0;
+}
+
+char *mingw_mktemp(char *template)
+{
+	wchar_t wtemplate[MAX_PATH];
+	if (xutftowcs_path(wtemplate, template) < 0)
+		return NULL;
+	if (!_wmktemp(wtemplate))
+		return NULL;
+	if (xwcstoutf(template, wtemplate, strlen(template) + 1) < 0)
+		return NULL;
+	return template;
+}
+
+int mkstemp(char *template)
+{
+	return git_mkstemp_mode(template, 0600);
+}
+
+int gettimeofday(struct timeval *tv, void *tz UNUSED)
+{
+	FILETIME ft;
+	long long hnsec;
+
+	GetSystemTimeAsFileTime(&ft);
+	hnsec = filetime_to_hnsec(&ft);
+	tv->tv_sec = hnsec / 10000000;
+	tv->tv_usec = (hnsec % 10000000) / 10;
+	return 0;
+}
+
+int pipe(int filedes[2])
+{
+	HANDLE h[2];
+
+	/* this creates non-inheritable handles */
+	if (!CreatePipe(&h[0], &h[1], NULL, 8192)) {
+		errno = err_win_to_posix(GetLastError());
+		return -1;
+	}
+	filedes[0] = _open_osfhandle(HCAST(int, h[0]), O_NOINHERIT);
+	if (filedes[0] < 0) {
+		CloseHandle(h[0]);
+		CloseHandle(h[1]);
+		return -1;
+	}
+	filedes[1] = _open_osfhandle(HCAST(int, h[1]), O_NOINHERIT);
+	if (filedes[1] < 0) {
+		close(filedes[0]);
+		CloseHandle(h[1]);
+		return -1;
+	}
+	return 0;
+}
+
+#ifndef __MINGW64__
+struct tm *gmtime_r(const time_t *timep, struct tm *result)
+{
+	if (gmtime_s(result, timep) == 0)
+		return result;
+	return NULL;
+}
+
+struct tm *localtime_r(const time_t *timep, struct tm *result)
+{
+	if (localtime_s(result, timep) == 0)
+		return result;
+	return NULL;
+}
+#endif
+
+char *mingw_getcwd(char *pointer, int len)
+{
+	wchar_t cwd[MAX_PATH], wpointer[MAX_PATH];
+	DWORD ret = GetCurrentDirectoryW(ARRAY_SIZE(cwd), cwd);
+
+	if (!ret || ret >= ARRAY_SIZE(cwd)) {
+		errno = ret ? ENAMETOOLONG : err_win_to_posix(GetLastError());
+		return NULL;
+	}
+	ret = GetLongPathNameW(cwd, wpointer, ARRAY_SIZE(wpointer));
+	if (!ret && GetLastError() == ERROR_ACCESS_DENIED) {
+		HANDLE hnd = CreateFileW(cwd, 0,
+			FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
+			OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+		if (hnd == INVALID_HANDLE_VALUE)
+			return NULL;
+		ret = GetFinalPathNameByHandleW(hnd, wpointer, ARRAY_SIZE(wpointer), 0);
+		CloseHandle(hnd);
+		if (!ret || ret >= ARRAY_SIZE(wpointer))
+			return NULL;
+		if (xwcstoutf(pointer, normalize_ntpath(wpointer), len) < 0)
+			return NULL;
+		return pointer;
+	}
+	if (!ret || ret >= ARRAY_SIZE(wpointer))
+		return NULL;
+	if (GetFileAttributesW(wpointer) == INVALID_FILE_ATTRIBUTES) {
+		errno = ENOENT;
+		return NULL;
+	}
+	if (xwcstoutf(pointer, wpointer, len) < 0)
+		return NULL;
+	convert_slashes(pointer);
+	return pointer;
+}
+
+/*
+ * See "Parsing C++ Command-Line Arguments" at Microsoft's Docs:
+ * https://docs.microsoft.com/en-us/cpp/cpp/parsing-cpp-command-line-arguments
+ */
+static const char *quote_arg_msvc(const char *arg)
+{
+	/* count chars to quote */
+	int len = 0, n = 0;
+	int force_quotes = 0;
+	char *q, *d;
+	const char *p = arg;
+	if (!*p) force_quotes = 1;
+	while (*p) {
+		if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
+			force_quotes = 1;
+		else if (*p == '"')
+			n++;
+		else if (*p == '\\') {
+			int count = 0;
+			while (*p == '\\') {
+				count++;
+				p++;
+				len++;
+			}
+			if (*p == '"' || !*p)
+				n += count*2 + 1;
+			continue;
+		}
+		len++;
+		p++;
+	}
+	if (!force_quotes && n == 0)
+		return arg;
+
+	/* insert \ where necessary */
+	d = q = xmalloc(st_add3(len, n, 3));
+	*d++ = '"';
+	while (*arg) {
+		if (*arg == '"')
+			*d++ = '\\';
+		else if (*arg == '\\') {
+			int count = 0;
+			while (*arg == '\\') {
+				count++;
+				*d++ = *arg++;
+			}
+			if (*arg == '"' || !*arg) {
+				while (count-- > 0)
+					*d++ = '\\';
+				/* don't escape the surrounding end quote */
+				if (!*arg)
+					break;
+				*d++ = '\\';
+			}
+		}
+		*d++ = *arg++;
+	}
+	*d++ = '"';
+	*d++ = '\0';
+	return q;
+}
+
+#include "quote.h"
+
+static const char *quote_arg_msys2(const char *arg)
+{
+	struct strbuf buf = STRBUF_INIT;
+	const char *p2 = arg, *p;
+
+	for (p = arg; *p; p++) {
+		int ws = isspace(*p);
+		if (!ws && *p != '\\' && *p != '"' && *p != '{' && *p != '\'' &&
+		    *p != '?' && *p != '*' && *p != '~')
+			continue;
+		if (!buf.len)
+			strbuf_addch(&buf, '"');
+		if (p != p2)
+			strbuf_add(&buf, p2, p - p2);
+		if (*p == '\\' || *p == '"')
+			strbuf_addch(&buf, '\\');
+		p2 = p;
+	}
+
+	if (p == arg)
+		strbuf_addch(&buf, '"');
+	else if (!buf.len)
+		return arg;
+	else
+		strbuf_add(&buf, p2, p - p2);
+
+	strbuf_addch(&buf, '"');
+	return strbuf_detach(&buf, 0);
+}
+
+static const char *parse_interpreter(const char *cmd)
+{
+	static char buf[100];
+	char *p, *opt;
+	ssize_t n; /* read() can return negative values */
+	int fd;
+
+	/* don't even try a .exe */
+	n = strlen(cmd);
+	if (n >= 4 && !strcasecmp(cmd+n-4, ".exe"))
+		return NULL;
+
+	fd = open(cmd, O_RDONLY);
+	if (fd < 0)
+		return NULL;
+	n = read(fd, buf, sizeof(buf)-1);
+	close(fd);
+	if (n < 4)	/* at least '#!/x' and not error */
+		return NULL;
+
+	if (buf[0] != '#' || buf[1] != '!')
+		return NULL;
+	buf[n] = '\0';
+	p = buf + strcspn(buf, "\r\n");
+	if (!*p)
+		return NULL;
+
+	*p = '\0';
+	if (!(p = strrchr(buf+2, '/')) && !(p = strrchr(buf+2, '\\')))
+		return NULL;
+	/* strip options */
+	if ((opt = strchr(p+1, ' ')))
+		*opt = '\0';
+	return p+1;
+}
+
+/*
+ * exe_only means that we only want to detect .exe files, but not scripts
+ * (which do not have an extension)
+ */
+static char *lookup_prog(const char *dir, int dirlen, const char *cmd,
+			 int isexe, int exe_only)
+{
+	char path[MAX_PATH];
+	wchar_t wpath[MAX_PATH];
+	snprintf(path, sizeof(path), "%.*s\\%s.exe", dirlen, dir, cmd);
+
+	if (xutftowcs_path(wpath, path) < 0)
+		return NULL;
+
+	if (!isexe && _waccess(wpath, F_OK) == 0)
+		return xstrdup(path);
+	wpath[wcslen(wpath)-4] = '\0';
+	if ((!exe_only || isexe) && _waccess(wpath, F_OK) == 0) {
+		if (!(GetFileAttributesW(wpath) & FILE_ATTRIBUTE_DIRECTORY)) {
+			path[strlen(path)-4] = '\0';
+			return xstrdup(path);
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Determines the absolute path of cmd using the split path in path.
+ * If cmd contains a slash or backslash, no lookup is performed.
+ */
+static char *path_lookup(const char *cmd, int exe_only)
+{
+	const char *path;
+	char *prog = NULL;
+	size_t len = strlen(cmd);
+	int isexe = len >= 4 && !strcasecmp(cmd+len-4, ".exe");
+
+	if (strpbrk(cmd, "/\\"))
+		return xstrdup(cmd);
+
+	path = mingw_getenv("PATH");
+	if (!path)
+		return NULL;
+
+	while (!prog) {
+		const char *sep = strchrnul(path, ';');
+		int dirlen = sep - path;
+		if (dirlen)
+			prog = lookup_prog(path, dirlen, cmd, isexe, exe_only);
+		if (!*sep)
+			break;
+		path = sep + 1;
+	}
+
+	return prog;
+}
+
+char *mingw_locate_in_PATH(const char *cmd)
+{
+	return path_lookup(cmd, 0);
+}
+
+static const wchar_t *wcschrnul(const wchar_t *s, wchar_t c)
+{
+	while (*s && *s != c)
+		s++;
+	return s;
+}
+
+/* Compare only keys */
+static int wenvcmp(const void *a, const void *b)
+{
+	wchar_t *p = *(wchar_t **)a, *q = *(wchar_t **)b;
+	size_t p_len, q_len;
+
+	/* Find the keys */
+	p_len = wcschrnul(p, L'=') - p;
+	q_len = wcschrnul(q, L'=') - q;
+
+	/* If the length differs, include the shorter key's NUL */
+	if (p_len < q_len)
+		p_len++;
+	else if (p_len > q_len)
+		p_len = q_len + 1;
+
+	return _wcsnicmp(p, q, p_len);
+}
+
+/*
+ * Build an environment block combining the inherited environment
+ * merged with the given list of settings.
+ *
+ * Values of the form "KEY=VALUE" in deltaenv override inherited values.
+ * Values of the form "KEY" in deltaenv delete inherited values.
+ *
+ * Multiple entries in deltaenv for the same key are explicitly allowed.
+ *
+ * We return a contiguous block of UNICODE strings with a final trailing
+ * zero word.
+ */
+static wchar_t *make_environment_block(char **deltaenv)
+{
+	wchar_t *wenv = GetEnvironmentStringsW(), *wdeltaenv, *result, *p;
+	size_t wlen, s, delta_size, size;
+
+	wchar_t **array = NULL;
+	size_t alloc = 0, nr = 0, i;
+
+	size = 1; /* for extra NUL at the end */
+
+	/* If there is no deltaenv to apply, simply return a copy. */
+	if (!deltaenv || !*deltaenv) {
+		for (p = wenv; p && *p; ) {
+			size_t s = wcslen(p) + 1;
+			size += s;
+			p += s;
+		}
+
+		DUP_ARRAY(result, wenv, size);
+		FreeEnvironmentStringsW(wenv);
+		return result;
+	}
+
+	/*
+	 * If there is a deltaenv, let's accumulate all keys into `array`,
+	 * sort them using the stable git_stable_qsort() and then copy,
+	 * skipping duplicate keys
+	 */
+	for (p = wenv; p && *p; ) {
+		ALLOC_GROW(array, nr + 1, alloc);
+		s = wcslen(p) + 1;
+		array[nr++] = p;
+		p += s;
+		size += s;
+	}
+
+	/* (over-)assess size needed for wchar version of deltaenv */
+	for (delta_size = 0, i = 0; deltaenv[i]; i++)
+		delta_size += strlen(deltaenv[i]) * 2 + 1;
+	ALLOC_ARRAY(wdeltaenv, delta_size);
+
+	/* convert the deltaenv, appending to array */
+	for (i = 0, p = wdeltaenv; deltaenv[i]; i++) {
+		ALLOC_GROW(array, nr + 1, alloc);
+		wlen = xutftowcs(p, deltaenv[i], wdeltaenv + delta_size - p);
+		array[nr++] = p;
+		p += wlen + 1;
+	}
+
+	git_stable_qsort(array, nr, sizeof(*array), wenvcmp);
+	ALLOC_ARRAY(result, size + delta_size);
+
+	for (p = result, i = 0; i < nr; i++) {
+		/* Skip any duplicate keys; last one wins */
+		while (i + 1 < nr && !wenvcmp(array + i, array + i + 1))
+		       i++;
+
+		/* Skip "to delete" entry */
+		if (!wcschr(array[i], L'='))
+			continue;
+
+		size = wcslen(array[i]) + 1;
+		COPY_ARRAY(p, array[i], size);
+		p += size;
+	}
+	*p = L'\0';
+
+	free(array);
+	free(wdeltaenv);
+	FreeEnvironmentStringsW(wenv);
+	return result;
+}
+
+static void do_unset_environment_variables(void)
+{
+	static int done;
+	char *p = unset_environment_variables;
+
+	if (done || !p)
+		return;
+	done = 1;
+
+	for (;;) {
+		char *comma = strchr(p, ',');
+
+		if (comma)
+			*comma = '\0';
+		unsetenv(p);
+		if (!comma)
+			break;
+		p = comma + 1;
+	}
+}
+
+struct pinfo_t {
+	struct pinfo_t *next;
+	pid_t pid;
+	HANDLE proc;
+};
+static struct pinfo_t *pinfo = NULL;
+CRITICAL_SECTION pinfo_cs;
+
+/* Used to match and chomp off path components */
+static inline int match_last_path_component(const char *path, size_t *len,
+					    const char *component)
+{
+	size_t component_len = strlen(component);
+	if (*len < component_len + 1 ||
+	    !is_dir_sep(path[*len - component_len - 1]) ||
+	    fspathncmp(path + *len - component_len, component, component_len))
+		return 0;
+	*len -= component_len + 1;
+	/* chomp off repeated dir separators */
+	while (*len > 0 && is_dir_sep(path[*len - 1]))
+		(*len)--;
+	return 1;
+}
+
+static int is_msys2_sh(const char *cmd)
+{
+	if (!cmd)
+		return 0;
+
+	if (!strcmp(cmd, "sh")) {
+		static int ret = -1;
+		char *p;
+
+		if (ret >= 0)
+			return ret;
+
+		p = path_lookup(cmd, 0);
+		if (!p)
+			ret = 0;
+		else {
+			size_t len = strlen(p);
+
+			ret = match_last_path_component(p, &len, "sh.exe") &&
+				match_last_path_component(p, &len, "bin") &&
+				match_last_path_component(p, &len, "usr");
+			free(p);
+		}
+		return ret;
+	}
+
+	if (ends_with(cmd, "\\sh.exe") || ends_with(cmd, "/sh.exe")) {
+		static char *sh;
+
+		if (!sh)
+			sh = path_lookup("sh", 0);
+
+		return !fspathcmp(cmd, sh);
+	}
+
+	return 0;
+}
+
+static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaenv,
+			      const char *dir,
+			      int prepend_cmd, int fhin, int fhout, int fherr)
+{
+	static int restrict_handle_inheritance = -1;
+	STARTUPINFOEXW si;
+	PROCESS_INFORMATION pi;
+	LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
+	HANDLE stdhandles[3];
+	DWORD stdhandles_count = 0;
+	SIZE_T size;
+	struct strbuf args;
+	wchar_t wcmd[MAX_PATH], wdir[MAX_PATH], *wargs, *wenvblk = NULL;
+	unsigned flags = CREATE_UNICODE_ENVIRONMENT;
+	BOOL ret;
+	HANDLE cons;
+	const char *(*quote_arg)(const char *arg) =
+		is_msys2_sh(cmd ? cmd : *argv) ?
+		quote_arg_msys2 : quote_arg_msvc;
+	const char *strace_env;
+
+	/* Make sure to override previous errors, if any */
+	errno = 0;
+
+	if (restrict_handle_inheritance < 0)
+		restrict_handle_inheritance = core_restrict_inherited_handles;
+	/*
+	 * The following code to restrict which handles are inherited seems
+	 * to work properly only on Windows 7 and later, so let's disable it
+	 * on Windows Vista and 2008.
+	 */
+	if (restrict_handle_inheritance < 0)
+		restrict_handle_inheritance = GetVersion() >> 16 >= 7601;
+
+	do_unset_environment_variables();
+
+	/* Determine whether or not we are associated to a console */
+	cons = CreateFileW(L"CONOUT$", GENERIC_WRITE,
+			FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+			FILE_ATTRIBUTE_NORMAL, NULL);
+	if (cons == INVALID_HANDLE_VALUE) {
+		/* There is no console associated with this process.
+		 * Since the child is a console process, Windows
+		 * would normally create a console window. But
+		 * since we'll be redirecting std streams, we do
+		 * not need the console.
+		 * It is necessary to use DETACHED_PROCESS
+		 * instead of CREATE_NO_WINDOW to make ssh
+		 * recognize that it has no console.
+		 */
+		flags |= DETACHED_PROCESS;
+	} else {
+		/* There is already a console. If we specified
+		 * DETACHED_PROCESS here, too, Windows would
+		 * disassociate the child from the console.
+		 * The same is true for CREATE_NO_WINDOW.
+		 * Go figure!
+		 */
+		CloseHandle(cons);
+	}
+	memset(&si, 0, sizeof(si));
+	si.StartupInfo.cb = sizeof(si);
+	si.StartupInfo.hStdInput = winansi_get_osfhandle(fhin);
+	si.StartupInfo.hStdOutput = winansi_get_osfhandle(fhout);
+	si.StartupInfo.hStdError = winansi_get_osfhandle(fherr);
+
+	/* The list of handles cannot contain duplicates */
+	if (si.StartupInfo.hStdInput != INVALID_HANDLE_VALUE)
+		stdhandles[stdhandles_count++] = si.StartupInfo.hStdInput;
+	if (si.StartupInfo.hStdOutput != INVALID_HANDLE_VALUE &&
+	    si.StartupInfo.hStdOutput != si.StartupInfo.hStdInput)
+		stdhandles[stdhandles_count++] = si.StartupInfo.hStdOutput;
+	if (si.StartupInfo.hStdError != INVALID_HANDLE_VALUE &&
+	    si.StartupInfo.hStdError != si.StartupInfo.hStdInput &&
+	    si.StartupInfo.hStdError != si.StartupInfo.hStdOutput)
+		stdhandles[stdhandles_count++] = si.StartupInfo.hStdError;
+	if (stdhandles_count)
+		si.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+	if (*argv && !strcmp(cmd, *argv))
+		wcmd[0] = L'\0';
+	else if (xutftowcs_path(wcmd, cmd) < 0)
+		return -1;
+	if (dir && xutftowcs_path(wdir, dir) < 0)
+		return -1;
+
+	/* concatenate argv, quoting args as we go */
+	strbuf_init(&args, 0);
+	if (prepend_cmd) {
+		char *quoted = (char *)quote_arg(cmd);
+		strbuf_addstr(&args, quoted);
+		if (quoted != cmd)
+			free(quoted);
+	}
+	for (; *argv; argv++) {
+		char *quoted = (char *)quote_arg(*argv);
+		if (*args.buf)
+			strbuf_addch(&args, ' ');
+		strbuf_addstr(&args, quoted);
+		if (quoted != *argv)
+			free(quoted);
+	}
+
+	strace_env = getenv("GIT_STRACE_COMMANDS");
+	if (strace_env) {
+		char *p = path_lookup("strace.exe", 1);
+		if (!p)
+			return error("strace not found!");
+		if (xutftowcs_path(wcmd, p) < 0) {
+			free(p);
+			return -1;
+		}
+		free(p);
+		if (!strcmp("1", strace_env) ||
+		    !strcasecmp("yes", strace_env) ||
+		    !strcasecmp("true", strace_env))
+			strbuf_insert(&args, 0, "strace ", 7);
+		else {
+			const char *quoted = quote_arg(strace_env);
+			struct strbuf buf = STRBUF_INIT;
+			strbuf_addf(&buf, "strace -o %s ", quoted);
+			if (quoted != strace_env)
+				free((char *)quoted);
+			strbuf_insert(&args, 0, buf.buf, buf.len);
+			strbuf_release(&buf);
+		}
+	}
+
+	ALLOC_ARRAY(wargs, st_add(st_mult(2, args.len), 1));
+	xutftowcs(wargs, args.buf, 2 * args.len + 1);
+	strbuf_release(&args);
+
+	wenvblk = make_environment_block(deltaenv);
+
+	memset(&pi, 0, sizeof(pi));
+	if (restrict_handle_inheritance && stdhandles_count &&
+	    (InitializeProcThreadAttributeList(NULL, 1, 0, &size) ||
+	     GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
+	    (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST)
+			(HeapAlloc(GetProcessHeap(), 0, size))) &&
+	    InitializeProcThreadAttributeList(attr_list, 1, 0, &size) &&
+	    UpdateProcThreadAttribute(attr_list, 0,
+				      PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+				      stdhandles,
+				      stdhandles_count * sizeof(HANDLE),
+				      NULL, NULL)) {
+		si.lpAttributeList = attr_list;
+		flags |= EXTENDED_STARTUPINFO_PRESENT;
+	}
+
+	ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
+			     stdhandles_count ? TRUE : FALSE,
+			     flags, wenvblk, dir ? wdir : NULL,
+			     &si.StartupInfo, &pi);
+
+	/*
+	 * On Windows 2008 R2, it seems that specifying certain types of handles
+	 * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
+	 * error. Rather than playing finicky and fragile games, let's just try
+	 * to detect this situation and simply try again without restricting any
+	 * handle inheritance. This is still better than failing to create
+	 * processes.
+	 */
+	if (!ret && restrict_handle_inheritance && stdhandles_count) {
+		DWORD err = GetLastError();
+		struct strbuf buf = STRBUF_INIT;
+
+		if (err != ERROR_NO_SYSTEM_RESOURCES &&
+		    /*
+		     * On Windows 7 and earlier, handles on pipes and character
+		     * devices are inherited automatically, and cannot be
+		     * specified in the thread handle list. Rather than trying
+		     * to catch each and every corner case (and running the
+		     * chance of *still* forgetting a few), let's just fall
+		     * back to creating the process without trying to limit the
+		     * handle inheritance.
+		     */
+		    !(err == ERROR_INVALID_PARAMETER &&
+		      GetVersion() >> 16 < 9200) &&
+		    !getenv("SUPPRESS_HANDLE_INHERITANCE_WARNING")) {
+			DWORD fl = 0;
+			int i;
+
+			setenv("SUPPRESS_HANDLE_INHERITANCE_WARNING", "1", 1);
+
+			for (i = 0; i < stdhandles_count; i++) {
+				HANDLE h = stdhandles[i];
+				strbuf_addf(&buf, "handle #%d: %p (type %lx, "
+					    "handle info (%d) %lx\n", i, h,
+					    GetFileType(h),
+					    GetHandleInformation(h, &fl),
+					    fl);
+			}
+			strbuf_addstr(&buf, "\nThis is a bug; please report it "
+				      "at\nhttps://github.com/git-for-windows/";
+				      "git/issues/new\n\n"
+				      "To suppress this warning, please set "
+				      "the environment variable\n\n"
+				      "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
+				      "\n");
+		}
+		restrict_handle_inheritance = 0;
+		flags &= ~EXTENDED_STARTUPINFO_PRESENT;
+		ret = CreateProcessW(*wcmd ? wcmd : NULL, wargs, NULL, NULL,
+				     TRUE, flags, wenvblk, dir ? wdir : NULL,
+				     &si.StartupInfo, &pi);
+		if (!ret)
+			errno = err_win_to_posix(GetLastError());
+		if (ret && buf.len) {
+			warning("failed to restrict file handles (%ld)\n\n%s",
+				err, buf.buf);
+		}
+		strbuf_release(&buf);
+	} else if (!ret)
+		errno = err_win_to_posix(GetLastError());
+
+	if (si.lpAttributeList)
+		DeleteProcThreadAttributeList(si.lpAttributeList);
+	if (attr_list)
+		HeapFree(GetProcessHeap(), 0, attr_list);
+
+	free(wenvblk);
+	free(wargs);
+
+	if (!ret)
+		return -1;
+
+	CloseHandle(pi.hThread);
+
+	/*
+	 * The process ID is the human-readable identifier of the process
+	 * that we want to present in log and error messages. The handle
+	 * is not useful for this purpose. But we cannot close it, either,
+	 * because it is not possible to turn a process ID into a process
+	 * handle after the process terminated.
+	 * Keep the handle in a list for waitpid.
+	 */
+	EnterCriticalSection(&pinfo_cs);
+	{
+		struct pinfo_t *info = xmalloc(sizeof(struct pinfo_t));
+		info->pid = pi.dwProcessId;
+		info->proc = pi.hProcess;
+		info->next = pinfo;
+		pinfo = info;
+	}
+	LeaveCriticalSection(&pinfo_cs);
+
+	return (pid_t)pi.dwProcessId;
+}
+
+static pid_t mingw_spawnv(const char *cmd, const char **argv, int prepend_cmd)
+{
+	return mingw_spawnve_fd(cmd, argv, NULL, NULL, prepend_cmd, 0, 1, 2);
+}
+
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **deltaenv,
+		     const char *dir,
+		     int fhin, int fhout, int fherr)
+{
+	pid_t pid;
+	char *prog = path_lookup(cmd, 0);
+
+	if (!prog) {
+		errno = ENOENT;
+		pid = -1;
+	}
+	else {
+		const char *interpr = parse_interpreter(prog);
+
+		if (interpr) {
+			const char *argv0 = argv[0];
+			char *iprog = path_lookup(interpr, 1);
+			argv[0] = prog;
+			if (!iprog) {
+				errno = ENOENT;
+				pid = -1;
+			}
+			else {
+				pid = mingw_spawnve_fd(iprog, argv, deltaenv, dir, 1,
+						       fhin, fhout, fherr);
+				free(iprog);
+			}
+			argv[0] = argv0;
+		}
+		else
+			pid = mingw_spawnve_fd(prog, argv, deltaenv, dir, 0,
+					       fhin, fhout, fherr);
+		free(prog);
+	}
+	return pid;
+}
+
+static int try_shell_exec(const char *cmd, char *const *argv)
+{
+	const char *interpr = parse_interpreter(cmd);
+	char *prog;
+	int pid = 0;
+
+	if (!interpr)
+		return 0;
+	prog = path_lookup(interpr, 1);
+	if (prog) {
+		int exec_id;
+		int argc = 0;
+		char **argv2;
+		while (argv[argc]) argc++;
+		ALLOC_ARRAY(argv2, argc + 1);
+		argv2[0] = (char *)cmd;	/* full path to the script file */
+		COPY_ARRAY(&argv2[1], &argv[1], argc);
+		exec_id = trace2_exec(prog, (const char **)argv2);
+		pid = mingw_spawnv(prog, (const char **)argv2, 1);
+		if (pid >= 0) {
+			int status;
+			if (waitpid(pid, &status, 0) < 0)
+				status = 255;
+			trace2_exec_result(exec_id, status);
+			exit(status);
+		}
+		trace2_exec_result(exec_id, -1);
+		pid = 1;	/* indicate that we tried but failed */
+		free(prog);
+		free(argv2);
+	}
+	return pid;
+}
+
+int mingw_execv(const char *cmd, char *const *argv)
+{
+	/* check if git_command is a shell script */
+	if (!try_shell_exec(cmd, argv)) {
+		int pid, status;
+		int exec_id;
+
+		exec_id = trace2_exec(cmd, (const char **)argv);
+		pid = mingw_spawnv(cmd, (const char **)argv, 0);
+		if (pid < 0) {
+			trace2_exec_result(exec_id, -1);
+			return -1;
+		}
+		if (waitpid(pid, &status, 0) < 0)
+			status = 255;
+		trace2_exec_result(exec_id, status);
+		exit(status);
+	}
+	return -1;
+}
+
+int mingw_execvp(const char *cmd, char *const *argv)
+{
+	char *prog = path_lookup(cmd, 0);
+
+	if (prog) {
+		mingw_execv(prog, argv);
+		free(prog);
+	} else
+		errno = ENOENT;
+
+	return -1;
+}
+
+int mingw_kill(pid_t pid, int sig)
+{
+	if (pid > 0 && sig == SIGTERM) {
+		HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, pid);
+
+		if (TerminateProcess(h, -1)) {
+			CloseHandle(h);
+			return 0;
+		}
+
+		errno = err_win_to_posix(GetLastError());
+		CloseHandle(h);
+		return -1;
+	} else if (pid > 0 && sig == 0) {
+		HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
+		if (h) {
+			CloseHandle(h);
+			return 0;
+		}
+	}
+
+	errno = EINVAL;
+	return -1;
+}
+
+/*
+ * UTF-8 versions of getenv(), putenv() and unsetenv().
+ * Internally, they use the CRT's stock UNICODE routines
+ * to avoid data loss.
+ */
+char *mingw_getenv(const char *name)
+{
+#define GETENV_MAX_RETAIN 64
+	static char *values[GETENV_MAX_RETAIN];
+	static int value_counter;
+	size_t len_key, len_value;
+	wchar_t *w_key;
+	char *value;
+	wchar_t w_value[32768];
+
+	if (!name || !*name)
+		return NULL;
+
+	len_key = strlen(name) + 1;
+	/* We cannot use xcalloc() here because that uses getenv() itself */
+	w_key = calloc(len_key, sizeof(wchar_t));
+	if (!w_key)
+		die("Out of memory, (tried to allocate %"PRIuMAX" wchar_t's)",
+			(uintmax_t)len_key);
+	xutftowcs(w_key, name, len_key);
+	/* GetEnvironmentVariableW() only sets the last error upon failure */
+	SetLastError(ERROR_SUCCESS);
+	len_value = GetEnvironmentVariableW(w_key, w_value, ARRAY_SIZE(w_value));
+	if (!len_value && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
+		free(w_key);
+		return NULL;
+	}
+	free(w_key);
+
+	len_value = len_value * 3 + 1;
+	/* We cannot use xcalloc() here because that uses getenv() itself */
+	value = calloc(len_value, sizeof(char));
+	if (!value)
+		die("Out of memory, (tried to allocate %"PRIuMAX" bytes)",
+			(uintmax_t)len_value);
+	xwcstoutf(value, w_value, len_value);
+
+	/*
+	 * We return `value` which is an allocated value and the caller is NOT
+	 * expecting to have to free it, so we keep a round-robin array,
+	 * invalidating the buffer after GETENV_MAX_RETAIN getenv() calls.
+	 */
+	free(values[value_counter]);
+	values[value_counter++] = value;
+	if (value_counter >= ARRAY_SIZE(values))
+		value_counter = 0;
+
+	return value;
+}
+
+int mingw_putenv(const char *namevalue)
+{
+	size_t size;
+	wchar_t *wide, *equal;
+	BOOL result;
+
+	if (!namevalue || !*namevalue)
+		return 0;
+
+	size = strlen(namevalue) * 2 + 1;
+	wide = calloc(size, sizeof(wchar_t));
+	if (!wide)
+		die("Out of memory, (tried to allocate %" PRIuMAX " wchar_t's)",
+		    (uintmax_t)size);
+	xutftowcs(wide, namevalue, size);
+	equal = wcschr(wide, L'=');
+	if (!equal)
+		result = SetEnvironmentVariableW(wide, NULL);
+	else {
+		*equal = L'\0';
+		result = SetEnvironmentVariableW(wide, equal + 1);
+	}
+	free(wide);
+
+	if (!result)
+		errno = err_win_to_posix(GetLastError());
+
+	return result ? 0 : -1;
+}
+
+static void ensure_socket_initialization(void)
+{
+	WSADATA wsa;
+	static int initialized = 0;
+
+	if (initialized)
+		return;
+
+	if (WSAStartup(MAKEWORD(2,2), &wsa))
+		die("unable to initialize winsock subsystem, error %d",
+			WSAGetLastError());
+
+	atexit((void(*)(void)) WSACleanup);
+	initialized = 1;
+}
+
+#undef gethostname
+int mingw_gethostname(char *name, int namelen)
+{
+    ensure_socket_initialization();
+    return gethostname(name, namelen);
+}
+
+#undef gethostbyname
+struct hostent *mingw_gethostbyname(const char *host)
+{
+	ensure_socket_initialization();
+	return gethostbyname(host);
+}
+
+#undef getaddrinfo
+int mingw_getaddrinfo(const char *node, const char *service,
+		      const struct addrinfo *hints, struct addrinfo **res)
+{
+	ensure_socket_initialization();
+	return getaddrinfo(node, service, hints, res);
+}
+
+int mingw_socket(int domain, int type, int protocol)
+{
+	int sockfd;
+	SOCKET s;
+
+	ensure_socket_initialization();
+	s = WSASocket(domain, type, protocol, NULL, 0, 0);
+	if (s == INVALID_SOCKET) {
+		/*
+		 * WSAGetLastError() values are regular BSD error codes
+		 * biased by WSABASEERR.
+		 * However, strerror() does not know about networking
+		 * specific errors, which are values beginning at 38 or so.
+		 * Therefore, we choose to leave the biased error code
+		 * in errno so that _if_ someone looks up the code somewhere,
+		 * then it is at least the number that are usually listed.
+		 */
+		errno = WSAGetLastError();
+		return -1;
+	}
+	/* convert into a file descriptor */
+	if ((sockfd = _open_osfhandle(s, O_RDWR|O_BINARY)) < 0) {
+		closesocket(s);
+		return error("unable to make a socket file descriptor: %s",
+			strerror(errno));
+	}
+	return sockfd;
+}
+
+#undef connect
+int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
+{
+	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+	return connect(s, sa, sz);
+}
+
+#undef bind
+int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz)
+{
+	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+	return bind(s, sa, sz);
+}
+
+#undef setsockopt
+int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen)
+{
+	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+	return setsockopt(s, lvl, optname, (const char*)optval, optlen);
+}
+
+#undef shutdown
+int mingw_shutdown(int sockfd, int how)
+{
+	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+	return shutdown(s, how);
+}
+
+#undef listen
+int mingw_listen(int sockfd, int backlog)
+{
+	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
+	return listen(s, backlog);
+}
+
+#undef accept
+int mingw_accept(int sockfd1, struct sockaddr *sa, socklen_t *sz)
+{
+	int sockfd2;
+
+	SOCKET s1 = (SOCKET)_get_osfhandle(sockfd1);
+	SOCKET s2 = accept(s1, sa, sz);
+
+	/* convert into a file descriptor */
+	if ((sockfd2 = _open_osfhandle(s2, O_RDWR|O_BINARY)) < 0) {
+		int err = errno;
+		closesocket(s2);
+		return error("unable to make a socket file descriptor: %s",
+			strerror(err));
+	}
+	return sockfd2;
+}
+
+#undef rename
+int mingw_rename(const char *pold, const char *pnew)
+{
+	static int supports_file_rename_info_ex = 1;
+	DWORD attrs, gle;
+	int tries = 0;
+	wchar_t wpold[MAX_PATH], wpnew[MAX_PATH];
+	int wpnew_len;
+
+	if (xutftowcs_path(wpold, pold) < 0)
+		return -1;
+	wpnew_len = xutftowcs_path(wpnew, pnew);
+	if (wpnew_len < 0)
+		return -1;
+
+	/*
+	 * Try native rename() first to get errno right.
+	 * It is based on MoveFile(), which cannot overwrite existing files.
+	 */
+	if (!_wrename(wpold, wpnew))
+		return 0;
+	if (errno != EEXIST)
+		return -1;
+
+repeat:
+	if (supports_file_rename_info_ex) {
+		/*
+		 * Our minimum required Windows version is still set to Windows
+		 * Vista. We thus have to declare required infrastructure for
+		 * FileRenameInfoEx ourselves until we bump _WIN32_WINNT to
+		 * 0x0A00. Furthermore, we have to handle cases where the
+		 * FileRenameInfoEx call isn't supported yet.
+		 */
+#define FILE_RENAME_FLAG_REPLACE_IF_EXISTS                  0x00000001
+#define FILE_RENAME_FLAG_POSIX_SEMANTICS                    0x00000002
+		FILE_INFO_BY_HANDLE_CLASS FileRenameInfoEx = 22;
+		struct {
+			/*
+			 * This is usually an unnamed union, but that is not
+			 * part of ISO C99. We thus inline the field, as we
+			 * really only care for the Flags field anyway.
+			 */
+			DWORD Flags;
+			HANDLE RootDirectory;
+			DWORD FileNameLength;
+			/*
+			 * The actual structure is defined with a single-character
+			 * flex array so that the structure has to be allocated on
+			 * the heap. As we declare this structure ourselves though
+			 * we can avoid the allocation and define FileName to have
+			 * MAX_PATH bytes.
+			 */
+			WCHAR FileName[MAX_PATH];
+		} rename_info = { 0 };
+		HANDLE old_handle = INVALID_HANDLE_VALUE;
+		BOOL success;
+
+		old_handle = CreateFileW(wpold, DELETE,
+					 FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
+					 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+		if (old_handle == INVALID_HANDLE_VALUE) {
+			errno = err_win_to_posix(GetLastError());
+			return -1;
+		}
+
+		rename_info.Flags = FILE_RENAME_FLAG_REPLACE_IF_EXISTS |
+				    FILE_RENAME_FLAG_POSIX_SEMANTICS;
+		rename_info.FileNameLength = wpnew_len * sizeof(WCHAR);
+		memcpy(rename_info.FileName, wpnew, wpnew_len * sizeof(WCHAR));
+
+		success = SetFileInformationByHandle(old_handle, FileRenameInfoEx,
+						     &rename_info, sizeof(rename_info));
+		gle = GetLastError();
+		CloseHandle(old_handle);
+		if (success)
+			return 0;
+
+		/*
+		 * When we see ERROR_INVALID_PARAMETER we can assume that the
+		 * current system doesn't support FileRenameInfoEx. Keep us
+		 * from using it in future calls and retry.
+		 */
+		if (gle == ERROR_INVALID_PARAMETER) {
+			supports_file_rename_info_ex = 0;
+			goto repeat;
+		}
+
+		/*
+		 * In theory, we shouldn't get ERROR_ACCESS_DENIED because we
+		 * always open files with FILE_SHARE_DELETE But in practice we
+		 * cannot assume that Git is the only one accessing files, and
+		 * other applications may not set FILE_SHARE_DELETE. So we have
+		 * to retry.
+		 */
+	} else {
+		if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
+			return 0;
+		gle = GetLastError();
+	}
+
+	/* TODO: translate more errors */
+	if (gle == ERROR_ACCESS_DENIED &&
+	    (attrs = GetFileAttributesW(wpnew)) != INVALID_FILE_ATTRIBUTES) {
+		if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
+			DWORD attrsold = GetFileAttributesW(wpold);
+			if (attrsold == INVALID_FILE_ATTRIBUTES ||
+			    !(attrsold & FILE_ATTRIBUTE_DIRECTORY))
+				errno = EISDIR;
+			else if (!_wrmdir(wpnew))
+				goto repeat;
+			return -1;
+		}
+		if ((attrs & FILE_ATTRIBUTE_READONLY) &&
+		    SetFileAttributesW(wpnew, attrs & ~FILE_ATTRIBUTE_READONLY)) {
+			if (MoveFileExW(wpold, wpnew, MOVEFILE_REPLACE_EXISTING))
+				return 0;
+			gle = GetLastError();
+			/* revert file attributes on failure */
+			SetFileAttributesW(wpnew, attrs);
+		}
+	}
+	if (tries < ARRAY_SIZE(delay) && gle == ERROR_ACCESS_DENIED) {
+		/*
+		 * We assume that some other process had the source or
+		 * destination file open at the wrong moment and retry.
+		 * In order to give the other process a higher chance to
+		 * complete its operation, we give up our time slice now.
+		 * If we have to retry again, we do sleep a bit.
+		 */
+		Sleep(delay[tries]);
+		tries++;
+		goto repeat;
+	}
+	if (gle == ERROR_ACCESS_DENIED &&
+	       ask_yes_no_if_possible("Rename from '%s' to '%s' failed. "
+		       "Should I try again?", pold, pnew))
+		goto repeat;
+
+	errno = EACCES;
+	return -1;
+}
+
+/*
+ * Note that this doesn't return the actual pagesize, but
+ * the allocation granularity. If future Windows specific git code
+ * needs the real getpagesize function, we need to find another solution.
+ */
+int mingw_getpagesize(void)
+{
+	SYSTEM_INFO si;
+	GetSystemInfo(&si);
+	return si.dwAllocationGranularity;
+}
+
+/* See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724435.aspx */
+enum EXTENDED_NAME_FORMAT {
+	NameDisplay = 3,
+	NameUserPrincipal = 8
+};
+
+static char *get_extended_user_info(enum EXTENDED_NAME_FORMAT type)
+{
+	DECLARE_PROC_ADDR(secur32.dll, BOOL, SEC_ENTRY, GetUserNameExW,
+		enum EXTENDED_NAME_FORMAT, LPCWSTR, PULONG);
+	static wchar_t wbuffer[1024];
+	DWORD len;
+
+	if (!INIT_PROC_ADDR(GetUserNameExW))
+		return NULL;
+
+	len = ARRAY_SIZE(wbuffer);
+	if (GetUserNameExW(type, wbuffer, &len)) {
+		char *converted = xmalloc((len *= 3));
+		if (xwcstoutf(converted, wbuffer, len) >= 0)
+			return converted;
+		free(converted);
+	}
+
+	return NULL;
+}
+
+char *mingw_query_user_email(void)
+{
+	return get_extended_user_info(NameUserPrincipal);
+}
+
+struct passwd *getpwuid(int uid UNUSED)
+{
+	static unsigned initialized;
+	static char user_name[100];
+	static struct passwd *p;
+	wchar_t buf[100];
+	DWORD len;
+
+	if (initialized)
+		return p;
+
+	len = ARRAY_SIZE(buf);
+	if (!GetUserNameW(buf, &len)) {
+		initialized = 1;
+		return NULL;
+	}
+
+	if (xwcstoutf(user_name, buf, sizeof(user_name)) < 0) {
+		initialized = 1;
+		return NULL;
+	}
+
+	p = xmalloc(sizeof(*p));
+	p->pw_name = user_name;
+	p->pw_gecos = get_extended_user_info(NameDisplay);
+	if (!p->pw_gecos)
+		/*
+		 * Data returned by getpwuid(3P) is treated as internal and
+		 * must never be written to or freed.
+		 */
+		p->pw_gecos = (char *) "unknown";
+	p->pw_dir = NULL;
+
+	initialized = 1;
+	return p;
+}
+
+static HANDLE timer_event;
+static HANDLE timer_thread;
+static int timer_interval;
+static int one_shot;
+static sig_handler_t timer_fn = SIG_DFL, sigint_fn = SIG_DFL;
+
+/* The timer works like this:
+ * The thread, ticktack(), is a trivial routine that most of the time
+ * only waits to receive the signal to terminate. The main thread tells
+ * the thread to terminate by setting the timer_event to the signalled
+ * state.
+ * But ticktack() interrupts the wait state after the timer's interval
+ * length to call the signal handler.
+ */
+
+static unsigned __stdcall ticktack(void *dummy UNUSED)
+{
+	while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
+		mingw_raise(SIGALRM);
+		if (one_shot)
+			break;
+	}
+	return 0;
+}
+
+static int start_timer_thread(void)
+{
+	timer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+	if (timer_event) {
+		timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL);
+		if (!timer_thread )
+			return errno = ENOMEM,
+				error("cannot start timer thread");
+	} else
+		return errno = ENOMEM,
+			error("cannot allocate resources for timer");
+	return 0;
+}
+
+static void stop_timer_thread(void)
+{
+	if (timer_event)
+		SetEvent(timer_event);	/* tell thread to terminate */
+	if (timer_thread) {
+		int rc = WaitForSingleObject(timer_thread, 10000);
+		if (rc == WAIT_TIMEOUT)
+			error("timer thread did not terminate timely");
+		else if (rc != WAIT_OBJECT_0)
+			error("waiting for timer thread failed: %lu",
+			      GetLastError());
+		CloseHandle(timer_thread);
+	}
+	if (timer_event)
+		CloseHandle(timer_event);
+	timer_event = NULL;
+	timer_thread = NULL;
+}
+
+static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2)
+{
+	return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
+}
+
+int setitimer(int type UNUSED, struct itimerval *in, struct itimerval *out)
+{
+	static const struct timeval zero;
+	static int atexit_done;
+
+	if (out)
+		return errno = EINVAL,
+			error("setitimer param 3 != NULL not implemented");
+	if (!is_timeval_eq(&in->it_interval, &zero) &&
+	    !is_timeval_eq(&in->it_interval, &in->it_value))
+		return errno = EINVAL,
+			error("setitimer: it_interval must be zero or eq it_value");
+
+	if (timer_thread)
+		stop_timer_thread();
+
+	if (is_timeval_eq(&in->it_value, &zero) &&
+	    is_timeval_eq(&in->it_interval, &zero))
+		return 0;
+
+	timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000;
+	one_shot = is_timeval_eq(&in->it_interval, &zero);
+	if (!atexit_done) {
+		atexit(stop_timer_thread);
+		atexit_done = 1;
+	}
+	return start_timer_thread();
+}
+
+int sigaction(int sig, struct sigaction *in, struct sigaction *out)
+{
+	if (sig != SIGALRM)
+		return errno = EINVAL,
+			error("sigaction only implemented for SIGALRM");
+	if (out)
+		return errno = EINVAL,
+			error("sigaction: param 3 != NULL not implemented");
+
+	timer_fn = in->sa_handler;
+	return 0;
+}
+
+#undef signal
+sig_handler_t mingw_signal(int sig, sig_handler_t handler)
+{
+	sig_handler_t old;
+
+	switch (sig) {
+	case SIGALRM:
+		old = timer_fn;
+		timer_fn = handler;
+		break;
+
+	case SIGINT:
+		old = sigint_fn;
+		sigint_fn = handler;
+		break;
+
+	default:
+		return signal(sig, handler);
+	}
+
+	return old;
+}
+
+#undef raise
+int mingw_raise(int sig)
+{
+	switch (sig) {
+	case SIGALRM:
+		if (timer_fn == SIG_DFL) {
+			if (isatty(STDERR_FILENO))
+				fputs("Alarm clock\n", stderr);
+			exit(128 + SIGALRM);
+		} else if (timer_fn != SIG_IGN)
+			timer_fn(SIGALRM);
+		return 0;
+
+	case SIGINT:
+		if (sigint_fn == SIG_DFL)
+			exit(128 + SIGINT);
+		else if (sigint_fn != SIG_IGN)
+			sigint_fn(SIGINT);
+		return 0;
+
+#if defined(_MSC_VER)
+	case SIGILL:
+	case SIGFPE:
+	case SIGSEGV:
+	case SIGTERM:
+	case SIGBREAK:
+	case SIGABRT:
+	case SIGABRT_COMPAT:
+		/*
+		 * The <signal.h> header in the MS C Runtime defines 8 signals
+		 * as being supported on the platform. Anything else causes an
+		 * "Invalid signal or error" (which in DEBUG builds causes the
+		 * Abort/Retry/Ignore dialog). We by-pass the CRT for things we
+		 * already know will fail.
+		 */
+		return raise(sig);
+	default:
+		errno = EINVAL;
+		return -1;
+
+#else
+
+	default:
+		return raise(sig);
+
+#endif
+
+	}
+}
+
+int link(const char *oldpath, const char *newpath)
+{
+	wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+	if (xutftowcs_path(woldpath, oldpath) < 0 ||
+		xutftowcs_path(wnewpath, newpath) < 0)
+		return -1;
+
+	if (!CreateHardLinkW(wnewpath, woldpath, NULL)) {
+		errno = err_win_to_posix(GetLastError());
+		return -1;
+	}
+	return 0;
+}
+
+pid_t waitpid(pid_t pid, int *status, int options)
+{
+	HANDLE h = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
+	    FALSE, pid);
+	if (!h) {
+		errno = ECHILD;
+		return -1;
+	}
+
+	if (pid > 0 && options & WNOHANG) {
+		if (WAIT_OBJECT_0 != WaitForSingleObject(h, 0)) {
+			CloseHandle(h);
+			return 0;
+		}
+		options &= ~WNOHANG;
+	}
+
+	if (options == 0) {
+		struct pinfo_t **ppinfo;
+		if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
+			CloseHandle(h);
+			return 0;
+		}
+
+		if (status)
+			GetExitCodeProcess(h, (LPDWORD)status);
+
+		EnterCriticalSection(&pinfo_cs);
+
+		ppinfo = &pinfo;
+		while (*ppinfo) {
+			struct pinfo_t *info = *ppinfo;
+			if (info->pid == pid) {
+				CloseHandle(info->proc);
+				*ppinfo = info->next;
+				free(info);
+				break;
+			}
+			ppinfo = &info->next;
+		}
+
+		LeaveCriticalSection(&pinfo_cs);
+
+		CloseHandle(h);
+		return pid;
+	}
+	CloseHandle(h);
+
+	errno = EINVAL;
+	return -1;
+}
+
+int xutftowcsn(wchar_t *wcs, const char *utfs, size_t wcslen, int utflen)
+{
+	int upos = 0, wpos = 0;
+	const unsigned char *utf = (const unsigned char*) utfs;
+	if (!utf || !wcs || wcslen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	/* reserve space for \0 */
+	wcslen--;
+	if (utflen < 0)
+		utflen = INT_MAX;
+
+	while (upos < utflen) {
+		int c = utf[upos++] & 0xff;
+		if (utflen == INT_MAX && c == 0)
+			break;
+
+		if (wpos >= wcslen) {
+			wcs[wpos] = 0;
+			errno = ERANGE;
+			return -1;
+		}
+
+		if (c < 0x80) {
+			/* ASCII */
+			wcs[wpos++] = c;
+		} else if (c >= 0xc2 && c < 0xe0 && upos < utflen &&
+				(utf[upos] & 0xc0) == 0x80) {
+			/* 2-byte utf-8 */
+			c = ((c & 0x1f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xe0 && c < 0xf0 && upos + 1 < utflen &&
+				!(c == 0xe0 && utf[upos] < 0xa0) && /* over-long encoding */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80) {
+			/* 3-byte utf-8 */
+			c = ((c & 0x0f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			wcs[wpos++] = c;
+		} else if (c >= 0xf0 && c < 0xf5 && upos + 2 < utflen &&
+				wpos + 1 < wcslen &&
+				!(c == 0xf0 && utf[upos] < 0x90) && /* over-long encoding */
+				!(c == 0xf4 && utf[upos] >= 0x90) && /* > \u10ffff */
+				(utf[upos] & 0xc0) == 0x80 &&
+				(utf[upos + 1] & 0xc0) == 0x80 &&
+				(utf[upos + 2] & 0xc0) == 0x80) {
+			/* 4-byte utf-8: convert to \ud8xx \udcxx surrogate pair */
+			c = ((c & 0x07) << 18);
+			c |= ((utf[upos++] & 0x3f) << 12);
+			c |= ((utf[upos++] & 0x3f) << 6);
+			c |= (utf[upos++] & 0x3f);
+			c -= 0x10000;
+			wcs[wpos++] = 0xd800 | (c >> 10);
+			wcs[wpos++] = 0xdc00 | (c & 0x3ff);
+		} else if (c >= 0xa0) {
+			/* invalid utf-8 byte, printable unicode char: convert 1:1 */
+			wcs[wpos++] = c;
+		} else {
+			/* invalid utf-8 byte, non-printable unicode: convert to hex */
+			static const char *hex = "0123456789abcdef";
+			wcs[wpos++] = hex[c >> 4];
+			if (wpos < wcslen)
+				wcs[wpos++] = hex[c & 0x0f];
+		}
+	}
+	wcs[wpos] = 0;
+	return wpos;
+}
+
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen)
+{
+	if (!wcs || !utf || utflen < 1) {
+		errno = EINVAL;
+		return -1;
+	}
+	utflen = WideCharToMultiByte(CP_UTF8, 0, wcs, -1, utf, utflen, NULL, NULL);
+	if (utflen)
+		return utflen - 1;
+	errno = ERANGE;
+	return -1;
+}
+
+static void setup_windows_environment(void)
+{
+	char *tmp = getenv("TMPDIR");
+
+	/* on Windows it is TMP and TEMP */
+	if (!tmp) {
+		if (!(tmp = getenv("TMP")))
+			tmp = getenv("TEMP");
+		if (tmp) {
+			setenv("TMPDIR", tmp, 1);
+			tmp = getenv("TMPDIR");
+		}
+	}
+
+	if (tmp) {
+		/*
+		 * Convert all dir separators to forward slashes,
+		 * to help shell commands called from the Git
+		 * executable (by not mistaking the dir separators
+		 * for escape characters).
+		 */
+		convert_slashes(tmp);
+	}
+
+	/* simulate TERM to enable auto-color (see color.c) */
+	if (!getenv("TERM"))
+		setenv("TERM", "cygwin", 1);
+
+	/* calculate HOME if not set */
+	if (!getenv("HOME")) {
+		/*
+		 * try $HOMEDRIVE$HOMEPATH - the home share may be a network
+		 * location, thus also check if the path exists (i.e. is not
+		 * disconnected)
+		 */
+		if ((tmp = getenv("HOMEDRIVE"))) {
+			struct strbuf buf = STRBUF_INIT;
+			strbuf_addstr(&buf, tmp);
+			if ((tmp = getenv("HOMEPATH"))) {
+				strbuf_addstr(&buf, tmp);
+				if (is_directory(buf.buf))
+					setenv("HOME", buf.buf, 1);
+				else
+					tmp = NULL; /* use $USERPROFILE */
+			}
+			strbuf_release(&buf);
+		}
+		/* use $USERPROFILE if the home share is not available */
+		if (!tmp && (tmp = getenv("USERPROFILE")))
+			setenv("HOME", tmp, 1);
+	}
+}
+
+static PSID get_current_user_sid(void)
+{
+	HANDLE token;
+	DWORD len = 0;
+	PSID result = NULL;
+
+	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
+		return NULL;
+
+	if (!GetTokenInformation(token, TokenUser, NULL, 0, &len)) {
+		TOKEN_USER *info = xmalloc((size_t)len);
+		if (GetTokenInformation(token, TokenUser, info, len, &len)) {
+			len = GetLengthSid(info->User.Sid);
+			result = xmalloc(len);
+			if (!CopySid(len, result, info->User.Sid)) {
+				error(_("failed to copy SID (%ld)"),
+				      GetLastError());
+				FREE_AND_NULL(result);
+			}
+		}
+		FREE_AND_NULL(info);
+	}
+	CloseHandle(token);
+
+	return result;
+}
+
+static BOOL user_sid_to_user_name(PSID sid, LPSTR *str)
+{
+	SID_NAME_USE pe_use;
+	DWORD len_user = 0, len_domain = 0;
+	BOOL translate_sid_to_user;
+
+	/*
+	 * returns only FALSE, because the string pointers are NULL
+	 */
+	LookupAccountSidA(NULL, sid, NULL, &len_user, NULL, &len_domain,
+			  &pe_use);
+	/*
+	 * Alloc needed space of the strings
+	 */
+	ALLOC_ARRAY((*str), (size_t)len_domain + (size_t)len_user);
+	translate_sid_to_user = LookupAccountSidA(NULL, sid,
+	    (*str) + len_domain, &len_user, *str, &len_domain, &pe_use);
+	if (!translate_sid_to_user)
+		FREE_AND_NULL(*str);
+	else
+		(*str)[len_domain] = '/';
+	return translate_sid_to_user;
+}
+
+static int acls_supported(const char *path)
+{
+	size_t offset = offset_1st_component(path);
+	WCHAR wroot[MAX_PATH];
+	DWORD file_system_flags;
+
+	if (offset &&
+	    xutftowcsn(wroot, path, MAX_PATH, offset) > 0 &&
+	    GetVolumeInformationW(wroot, NULL, 0, NULL, NULL,
+				  &file_system_flags, NULL, 0))
+		return !!(file_system_flags & FILE_PERSISTENT_ACLS);
+
+	return 0;
+}
+
+int is_path_owned_by_current_sid(const char *path, struct strbuf *report)
+{
+	WCHAR wpath[MAX_PATH];
+	PSID sid = NULL;
+	PSECURITY_DESCRIPTOR descriptor = NULL;
+	DWORD err;
+
+	static wchar_t home[MAX_PATH];
+
+	int result = 0;
+
+	if (xutftowcs_path(wpath, path) < 0)
+		return 0;
+
+	/*
+	 * On Windows, the home directory is owned by the administrator, but for
+	 * all practical purposes, it belongs to the user. Do pretend that it is
+	 * owned by the user.
+	 */
+	if (!*home) {
+		DWORD size = ARRAY_SIZE(home);
+		DWORD len = GetEnvironmentVariableW(L"HOME", home, size);
+		if (!len || len > size)
+			wcscpy(home, L"::N/A::");
+	}
+	if (!wcsicmp(wpath, home))
+		return 1;
+
+	/* Get the owner SID */
+	err = GetNamedSecurityInfoW(wpath, SE_FILE_OBJECT,
+				    OWNER_SECURITY_INFORMATION |
+				    DACL_SECURITY_INFORMATION,
+				    &sid, NULL, NULL, NULL, &descriptor);
+
+	if (err != ERROR_SUCCESS)
+		error(_("failed to get owner for '%s' (%ld)"), path, err);
+	else if (sid && IsValidSid(sid)) {
+		/* Now, verify that the SID matches the current user's */
+		static PSID current_user_sid;
+		BOOL is_member;
+
+		if (!current_user_sid)
+			current_user_sid = get_current_user_sid();
+
+		if (current_user_sid &&
+		    IsValidSid(current_user_sid) &&
+		    EqualSid(sid, current_user_sid))
+			result = 1;
+		else if (IsWellKnownSid(sid, WinBuiltinAdministratorsSid) &&
+			 CheckTokenMembership(NULL, sid, &is_member) &&
+			 is_member)
+			/*
+			 * If owned by the Administrators group, and the
+			 * current user is an administrator, we consider that
+			 * okay, too.
+			 */
+			result = 1;
+		else if (report &&
+			 IsWellKnownSid(sid, WinWorldSid) &&
+			 !acls_supported(path)) {
+			/*
+			 * On FAT32 volumes, ownership is not actually recorded.
+			 */
+			strbuf_addf(report, "'%s' is on a file system that does "
+				    "not record ownership\n", path);
+		} else if (report) {
+			PCSTR str1, str2, str3, str4;
+			LPSTR to_free1 = NULL, to_free3 = NULL,
+			    to_local_free2 = NULL, to_local_free4 = NULL;
+
+			if (user_sid_to_user_name(sid, &to_free1))
+				str1 = to_free1;
+			else
+				str1 = "(inconvertible)";
+			if (ConvertSidToStringSidA(sid, &to_local_free2))
+				str2 = to_local_free2;
+			else
+				str2 = "(inconvertible)";
+
+			if (!current_user_sid) {
+				str3 = "(none)";
+				str4 = "(none)";
+			}
+			else if (!IsValidSid(current_user_sid)) {
+				str3 = "(invalid)";
+				str4 = "(invalid)";
+			} else {
+				if (user_sid_to_user_name(current_user_sid,
+							  &to_free3))
+					str3 = to_free3;
+				else
+					str3 = "(inconvertible)";
+				if (ConvertSidToStringSidA(current_user_sid,
+							   &to_local_free4))
+					str4 = to_local_free4;
+				else
+					str4 = "(inconvertible)";
+			}
+			strbuf_addf(report,
+				    "'%s' is owned by:\n"
+				    "\t%s (%s)\nbut the current user is:\n"
+				    "\t%s (%s)\n",
+				    path, str1, str2, str3, str4);
+			free(to_free1);
+			LocalFree(to_local_free2);
+			free(to_free3);
+			LocalFree(to_local_free4);
+		}
+	}
+
+	/*
+	 * We can release the security descriptor struct only now because `sid`
+	 * actually points into this struct.
+	 */
+	if (descriptor)
+		LocalFree(descriptor);
+
+	return result;
+}
+
+int is_valid_win32_path(const char *path, int allow_literal_nul)
+{
+	const char *p = path;
+	int preceding_space_or_period = 0, i = 0, periods = 0;
+
+	if (!protect_ntfs)
+		return 1;
+
+	skip_dos_drive_prefix((char **)&path);
+	goto segment_start;
+
+	for (;;) {
+		char c = *(path++);
+		switch (c) {
+		case '\0':
+		case '/': case '\\':
+			/* cannot end in ` ` or `.`, except for `.` and `..` */
+			if (preceding_space_or_period &&
+			    (i != periods || periods > 2))
+				return 0;
+			if (!c)
+				return 1;
+
+			i = periods = preceding_space_or_period = 0;
+
+segment_start:
+			switch (*path) {
+			case 'a': case 'A': /* AUX */
+				if (((c = path[++i]) != 'u' && c != 'U') ||
+				    ((c = path[++i]) != 'x' && c != 'X')) {
+not_a_reserved_name:
+					path += i;
+					continue;
+				}
+				break;
+			case 'c': case 'C':
+				/* COM1 ... COM9, CON, CONIN$, CONOUT$ */
+				if ((c = path[++i]) != 'o' && c != 'O')
+					goto not_a_reserved_name;
+				c = path[++i];
+				if (c == 'm' || c == 'M') { /* COM1 ... COM9 */
+					c = path[++i];
+					if (c < '1' || c > '9')
+						goto not_a_reserved_name;
+				} else if (c == 'n' || c == 'N') { /* CON */
+					c = path[i + 1];
+					if ((c == 'i' || c == 'I') &&
+					    ((c = path[i + 2]) == 'n' ||
+					     c == 'N') &&
+					    path[i + 3] == '$')
+						i += 3; /* CONIN$ */
+					else if ((c == 'o' || c == 'O') &&
+						 ((c = path[i + 2]) == 'u' ||
+						  c == 'U') &&
+						 ((c = path[i + 3]) == 't' ||
+						  c == 'T') &&
+						 path[i + 4] == '$')
+						i += 4; /* CONOUT$ */
+				} else
+					goto not_a_reserved_name;
+				break;
+			case 'l': case 'L': /* LPT<N> */
+				if (((c = path[++i]) != 'p' && c != 'P') ||
+				    ((c = path[++i]) != 't' && c != 'T') ||
+				    !isdigit(path[++i]))
+					goto not_a_reserved_name;
+				break;
+			case 'n': case 'N': /* NUL */
+				if (((c = path[++i]) != 'u' && c != 'U') ||
+				    ((c = path[++i]) != 'l' && c != 'L') ||
+				    (allow_literal_nul &&
+				     !path[i + 1] && p == path))
+					goto not_a_reserved_name;
+				break;
+			case 'p': case 'P': /* PRN */
+				if (((c = path[++i]) != 'r' && c != 'R') ||
+				    ((c = path[++i]) != 'n' && c != 'N'))
+					goto not_a_reserved_name;
+				break;
+			default:
+				continue;
+			}
+
+			/*
+			 * So far, this looks like a reserved name. Let's see
+			 * whether it actually is one: trailing spaces, a file
+			 * extension, or an NTFS Alternate Data Stream do not
+			 * matter, the name is still reserved if any of those
+			 * follow immediately after the actual name.
+			 */
+			i++;
+			if (path[i] == ' ') {
+				preceding_space_or_period = 1;
+				while (path[++i] == ' ')
+					; /* skip all spaces */
+			}
+
+			c = path[i];
+			if (c && c != '.' && c != ':' && !is_xplatform_dir_sep(c))
+				goto not_a_reserved_name;
+
+			/* contains reserved name */
+			return 0;
+		case '.':
+			periods++;
+			/* fallthru */
+		case ' ':
+			preceding_space_or_period = 1;
+			i++;
+			continue;
+		case ':': /* DOS drive prefix was already skipped */
+		case '<': case '>': case '"': case '|': case '?': case '*':
+			/* illegal character */
+			return 0;
+		default:
+			if (c > '\0' && c < '\x20')
+				/* illegal character */
+				return 0;
+		}
+		preceding_space_or_period = 0;
+		i++;
+	}
+}
+
+#if !defined(_MSC_VER)
+/*
+ * Disable MSVCRT command line wildcard expansion (__getmainargs called from
+ * mingw startup code, see init.c in mingw runtime).
+ */
+int _CRT_glob = 0;
+#endif
+
+static NORETURN void die_startup(void)
+{
+	fputs("fatal: not enough memory for initialization", stderr);
+	exit(128);
+}
+
+static void *malloc_startup(size_t size)
+{
+	void *result = malloc(size);
+	if (!result)
+		die_startup();
+	return result;
+}
+
+static char *wcstoutfdup_startup(char *buffer, const wchar_t *wcs, size_t len)
+{
+	len = xwcstoutf(buffer, wcs, len) + 1;
+	return memcpy(malloc_startup(len), buffer, len);
+}
+
+static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
+				      DWORD desired_access, DWORD flags)
+{
+	DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
+	wchar_t buf[MAX_PATH];
+	DWORD max = ARRAY_SIZE(buf);
+	HANDLE handle;
+	DWORD ret = GetEnvironmentVariableW(key, buf, max);
+
+	if (!ret || ret >= max)
+		return;
+
+	/* make sure this does not leak into child processes */
+	SetEnvironmentVariableW(key, NULL);
+	if (!wcscmp(buf, L"off")) {
+		close(fd);
+		handle = GetStdHandle(std_id);
+		if (handle != INVALID_HANDLE_VALUE)
+			CloseHandle(handle);
+		return;
+	}
+	if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) {
+		handle = GetStdHandle(STD_OUTPUT_HANDLE);
+		if (handle == INVALID_HANDLE_VALUE) {
+			close(fd);
+			handle = GetStdHandle(std_id);
+			if (handle != INVALID_HANDLE_VALUE)
+				CloseHandle(handle);
+		} else {
+			int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+			SetStdHandle(std_id, handle);
+			dup2(new_fd, fd);
+			/* do *not* close the new_fd: that would close stdout */
+		}
+		return;
+	}
+	handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
+			     flags, NULL);
+	if (handle != INVALID_HANDLE_VALUE) {
+		int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+		SetStdHandle(std_id, handle);
+		dup2(new_fd, fd);
+		close(new_fd);
+	}
+}
+
+static void maybe_redirect_std_handles(void)
+{
+	maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
+				  GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
+	maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
+				  GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
+	maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
+				  GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
+}
+
+#ifdef _MSC_VER
+#ifdef _DEBUG
+#include <crtdbg.h>
+#endif
+#endif
+
+/*
+ * We implement wmain() and compile with -municode, which would
+ * normally ignore main(), but we call the latter from the former
+ * so that we can handle non-ASCII command-line parameters
+ * appropriately.
+ *
+ * To be more compatible with the core git code, we convert
+ * argv into UTF8 and pass them directly to main().
+ */
+int wmain(int argc, const wchar_t **wargv)
+{
+	int i, exit_status;
+	size_t maxlen;
+	char *buffer, **save;
+	const char **argv;
+
+	trace2_initialize_clock();
+
+#ifdef _MSC_VER
+#ifdef _DEBUG
+	_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
+#endif
+
+#ifdef USE_MSVC_CRTDBG
+	_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+#endif
+
+	maybe_redirect_std_handles();
+
+	/* determine size of argv and environ conversion buffer */
+	maxlen = wcslen(wargv[0]);
+	for (i = 1; i < argc; i++)
+		maxlen = max(maxlen, wcslen(wargv[i]));
+
+	/* allocate buffer (wchar_t encodes to max 3 UTF-8 bytes) */
+	maxlen = 3 * maxlen + 1;
+	buffer = malloc_startup(maxlen);
+
+	/*
+	 * Create a UTF-8 version of w_argv. Also create a "save" copy
+	 * to remember all the string pointers because parse_options()
+	 * will remove claimed items from the argv that we pass down.
+	 */
+	ALLOC_ARRAY(argv, argc + 1);
+	ALLOC_ARRAY(save, argc + 1);
+	for (i = 0; i < argc; i++)
+		argv[i] = save[i] = wcstoutfdup_startup(buffer, wargv[i], maxlen);
+	argv[i] = save[i] = NULL;
+	free(buffer);
+
+	/* fix Windows specific environment settings */
+	setup_windows_environment();
+
+	unset_environment_variables = xstrdup("PERL5LIB");
+
+	/* initialize critical section for waitpid pinfo_t list */
+	InitializeCriticalSection(&pinfo_cs);
+
+	/* set up default file mode and file modes for stdin/out/err */
+	_fmode = _O_BINARY;
+	_setmode(_fileno(stdin), _O_BINARY);
+	_setmode(_fileno(stdout), _O_BINARY);
+	_setmode(_fileno(stderr), _O_BINARY);
+
+	/* initialize Unicode console */
+	winansi_init();
+
+	/* invoke the real main() using our utf8 version of argv. */
+	exit_status = main(argc, argv);
+
+	for (i = 0; i < argc; i++)
+		free(save[i]);
+	free(save);
+	free(argv);
+
+	return exit_status;
+}
+
+int uname(struct utsname *buf)
+{
+	unsigned v = (unsigned)GetVersion();
+	memset(buf, 0, sizeof(*buf));
+	xsnprintf(buf->sysname, sizeof(buf->sysname), "Windows");
+	xsnprintf(buf->release, sizeof(buf->release),
+		 "%u.%u", v & 0xff, (v >> 8) & 0xff);
+	/* assuming NT variants only.. */
+	xsnprintf(buf->version, sizeof(buf->version),
+		  "%u", (v >> 16) & 0x7fff);
+	return 0;
+}
+
+#ifndef NO_UNIX_SOCKETS
+int mingw_have_unix_sockets(void)
+{
+	SC_HANDLE scm, srvc;
+	SERVICE_STATUS_PROCESS status;
+	DWORD bytes;
+	int ret = 0;
+	scm = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT);
+	if (scm) {
+		srvc = OpenServiceA(scm, "afunix", SERVICE_QUERY_STATUS);
+		if (srvc) {
+			if(QueryServiceStatusEx(srvc, SC_STATUS_PROCESS_INFO, (LPBYTE)&status, sizeof(SERVICE_STATUS_PROCESS), &bytes))
+				ret = status.dwCurrentState == SERVICE_RUNNING;
+			CloseServiceHandle(srvc);
+		}
+		CloseServiceHandle(scm);
+	}
+	return ret;
+}
+#endif
diff --git a/compat/mingw.h b/compat/mingw.h
new file mode 100644
index 0000000000..ebfb8ba423
--- /dev/null
+++ b/compat/mingw.h
@@ -0,0 +1,639 @@
+#ifdef __MINGW64_VERSION_MAJOR
+#include <stdint.h>
+#include <wchar.h>
+typedef _sigset_t sigset_t;
+#endif
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+/* MinGW-w64 reports to have flockfile, but it does not actually have it. */
+#ifdef __MINGW64_VERSION_MAJOR
+#undef _POSIX_THREAD_SAFE_FUNCTIONS
+#endif
+
+struct config_context;
+int mingw_core_config(const char *var, const char *value,
+		      const struct config_context *ctx, void *cb);
+#define platform_core_config mingw_core_config
+
+/*
+ * things that are not available in header files
+ */
+
+typedef int uid_t;
+typedef int socklen_t;
+#ifndef __MINGW64_VERSION_MAJOR
+typedef int pid_t;
+#define hstrerror strerror
+#endif
+
+#define S_IFLNK    0120000 /* Symbolic link */
+#define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK)
+#define S_ISSOCK(x) 0
+
+#ifndef S_IRWXG
+#define S_IRGRP 0
+#define S_IWGRP 0
+#define S_IXGRP 0
+#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+#endif
+#ifndef S_IRWXO
+#define S_IROTH 0
+#define S_IWOTH 0
+#define S_IXOTH 0
+#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#endif
+
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#define WIFEXITED(x) 1
+#define WIFSIGNALED(x) 0
+#define WEXITSTATUS(x) ((x) & 0xff)
+#define WTERMSIG(x) SIGTERM
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK EAGAIN
+#endif
+#ifndef ELOOP
+#define ELOOP EMLINK
+#endif
+#define SHUT_WR SD_SEND
+
+#define SIGHUP 1
+#define SIGQUIT 3
+#define SIGKILL 9
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGCHLD 17
+
+#define F_GETFD 1
+#define F_SETFD 2
+#define FD_CLOEXEC 0x1
+
+#if !defined O_CLOEXEC && defined O_NOINHERIT
+#define O_CLOEXEC	O_NOINHERIT
+#endif
+
+#ifndef EAFNOSUPPORT
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+#ifndef ECONNABORTED
+#define ECONNABORTED WSAECONNABORTED
+#endif
+#ifndef ENOTSOCK
+#define ENOTSOCK WSAENOTSOCK
+#endif
+
+struct passwd {
+	char *pw_name;
+	char *pw_gecos;
+	char *pw_dir;
+};
+
+typedef void (__cdecl *sig_handler_t)(int);
+struct sigaction {
+	sig_handler_t sa_handler;
+	unsigned sa_flags;
+};
+#define SA_RESTART 0
+
+struct itimerval {
+	struct timeval it_value, it_interval;
+};
+#define ITIMER_REAL 0
+
+struct utsname {
+	char sysname[16];
+	char nodename[1];
+	char release[16];
+	char version[16];
+	char machine[1];
+};
+
+/*
+ * sanitize preprocessor namespace polluted by Windows headers defining
+ * macros which collide with git local versions
+ */
+#undef HELP_COMMAND /* from winuser.h */
+
+/*
+ * trivial stubs
+ */
+
+static inline int readlink(const char *path UNUSED, char *buf UNUSED, size_t bufsiz UNUSED)
+{ errno = ENOSYS; return -1; }
+static inline int symlink(const char *oldpath UNUSED, const char *newpath UNUSED)
+{ errno = ENOSYS; return -1; }
+static inline int fchmod(int fildes UNUSED, mode_t mode UNUSED)
+{ errno = ENOSYS; return -1; }
+#ifndef __MINGW64_VERSION_MAJOR
+static inline pid_t fork(void)
+{ errno = ENOSYS; return -1; }
+#endif
+static inline unsigned int alarm(unsigned int seconds UNUSED)
+{ return 0; }
+static inline int fsync(int fd)
+{ return _commit(fd); }
+static inline void sync(void)
+{}
+static inline uid_t getuid(void)
+{ return 1; }
+static inline struct passwd *getpwnam(const char *name UNUSED)
+{ return NULL; }
+static inline int fcntl(int fd UNUSED, int cmd, ...)
+{
+	if (cmd == F_GETFD || cmd == F_SETFD)
+		return 0;
+	errno = EINVAL;
+	return -1;
+}
+
+#define sigemptyset(x) (void)0
+static inline int sigaddset(sigset_t *set UNUSED, int signum UNUSED)
+{ return 0; }
+#define SIG_BLOCK 0
+#define SIG_UNBLOCK 0
+static inline int sigprocmask(int how UNUSED, const sigset_t *set UNUSED, sigset_t *oldset UNUSED)
+{ return 0; }
+static inline pid_t getppid(void)
+{ return 1; }
+static inline pid_t getpgid(pid_t pid)
+{ return pid == 0 ? getpid() : pid; }
+static inline pid_t tcgetpgrp(int fd UNUSED)
+{ return getpid(); }
+
+/*
+ * simple adaptors
+ */
+
+int mingw_mkdir(const char *path, int mode);
+#define mkdir mingw_mkdir
+
+#define WNOHANG 1
+pid_t waitpid(pid_t pid, int *status, int options);
+
+#define kill mingw_kill
+int mingw_kill(pid_t pid, int sig);
+
+#define locate_in_PATH mingw_locate_in_PATH
+char *mingw_locate_in_PATH(const char *cmd);
+
+#ifndef NO_OPENSSL
+#include <openssl/ssl.h>
+static inline int mingw_SSL_set_fd(SSL *ssl, int fd)
+{
+	return SSL_set_fd(ssl, _get_osfhandle(fd));
+}
+#define SSL_set_fd mingw_SSL_set_fd
+
+static inline int mingw_SSL_set_rfd(SSL *ssl, int fd)
+{
+	return SSL_set_rfd(ssl, _get_osfhandle(fd));
+}
+#define SSL_set_rfd mingw_SSL_set_rfd
+
+static inline int mingw_SSL_set_wfd(SSL *ssl, int fd)
+{
+	return SSL_set_wfd(ssl, _get_osfhandle(fd));
+}
+#define SSL_set_wfd mingw_SSL_set_wfd
+#endif
+
+/*
+ * implementations of missing functions
+ */
+
+int pipe(int filedes[2]);
+unsigned int sleep (unsigned int seconds);
+int mkstemp(char *template);
+int gettimeofday(struct timeval *tv, void *tz);
+#ifndef __MINGW64_VERSION_MAJOR
+struct tm *gmtime_r(const time_t *timep, struct tm *result);
+struct tm *localtime_r(const time_t *timep, struct tm *result);
+#endif
+int getpagesize(void);	/* defined in MinGW's libgcc.a */
+struct passwd *getpwuid(uid_t uid);
+int setitimer(int type, struct itimerval *in, struct itimerval *out);
+int sigaction(int sig, struct sigaction *in, struct sigaction *out);
+int link(const char *oldpath, const char *newpath);
+int uname(struct utsname *buf);
+
+/*
+ * replacements of existing functions
+ */
+
+int mingw_unlink(const char *pathname);
+#define unlink mingw_unlink
+
+int mingw_rmdir(const char *path);
+#define rmdir mingw_rmdir
+
+int mingw_open (const char *filename, int oflags, ...);
+#define open mingw_open
+#undef OPEN_RETURNS_EINTR
+
+int mingw_fgetc(FILE *stream);
+#define fgetc mingw_fgetc
+
+FILE *mingw_fopen (const char *filename, const char *otype);
+#define fopen mingw_fopen
+
+FILE *mingw_freopen (const char *filename, const char *otype, FILE *stream);
+#define freopen mingw_freopen
+
+int mingw_fflush(FILE *stream);
+#define fflush mingw_fflush
+
+ssize_t mingw_write(int fd, const void *buf, size_t len);
+#define write mingw_write
+
+int mingw_access(const char *filename, int mode);
+#undef access
+#define access mingw_access
+
+int mingw_chdir(const char *dirname);
+#define chdir mingw_chdir
+
+int mingw_chmod(const char *filename, int mode);
+#define chmod mingw_chmod
+
+char *mingw_mktemp(char *template);
+#define mktemp mingw_mktemp
+
+char *mingw_getcwd(char *pointer, int len);
+#define getcwd mingw_getcwd
+
+#ifdef NO_UNSETENV
+#error "NO_UNSETENV is incompatible with the Windows-specific startup code!"
+#endif
+
+/*
+ * We bind *env() routines (even the mingw_ ones) to private mingw_ versions.
+ * These talk to the CRT using UNICODE/wchar_t, but maintain the original
+ * narrow-char API.
+ *
+ * Note that the MSCRT maintains both ANSI (getenv()) and UNICODE (_wgetenv())
+ * routines and stores both versions of each environment variable in parallel
+ * (and secretly updates both when you set one or the other), but it uses CP_ACP
+ * to do the conversion rather than CP_UTF8.
+ *
+ * Since everything in the git code base is UTF8, we define the mingw_ routines
+ * to access the CRT using the UNICODE routines and manually convert them to
+ * UTF8.  This also avoids round-trip problems.
+ *
+ * This also helps with our linkage, since "_wenviron" is publicly exported
+ * from the CRT.  But to access "_environ" we would have to statically link
+ * to the CRT (/MT).
+ *
+ * We require NO_SETENV (and let gitsetenv() call our mingw_putenv).
+ */
+#define getenv       mingw_getenv
+#define putenv       mingw_putenv
+#define unsetenv     mingw_putenv
+char *mingw_getenv(const char *name);
+int   mingw_putenv(const char *name);
+
+int mingw_gethostname(char *host, int namelen);
+#define gethostname mingw_gethostname
+
+struct hostent *mingw_gethostbyname(const char *host);
+#define gethostbyname mingw_gethostbyname
+
+int mingw_getaddrinfo(const char *node, const char *service,
+		      const struct addrinfo *hints, struct addrinfo **res);
+#define getaddrinfo mingw_getaddrinfo
+
+int mingw_socket(int domain, int type, int protocol);
+#define socket mingw_socket
+
+int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz);
+#define connect mingw_connect
+
+int mingw_bind(int sockfd, struct sockaddr *sa, size_t sz);
+#define bind mingw_bind
+
+int mingw_setsockopt(int sockfd, int lvl, int optname, void *optval, int optlen);
+#define setsockopt mingw_setsockopt
+
+int mingw_shutdown(int sockfd, int how);
+#define shutdown mingw_shutdown
+
+int mingw_listen(int sockfd, int backlog);
+#define listen mingw_listen
+
+int mingw_accept(int sockfd, struct sockaddr *sa, socklen_t *sz);
+#define accept mingw_accept
+
+int mingw_rename(const char*, const char*);
+#define rename mingw_rename
+
+#if defined(USE_WIN32_MMAP) || defined(_MSC_VER)
+int mingw_getpagesize(void);
+#define getpagesize mingw_getpagesize
+#endif
+
+int win32_fsync_no_flush(int fd);
+#define fsync_no_flush win32_fsync_no_flush
+
+#define FSYNC_COMPONENTS_PLATFORM_DEFAULT (FSYNC_COMPONENTS_DEFAULT | FSYNC_COMPONENT_LOOSE_OBJECT)
+#define FSYNC_METHOD_DEFAULT (FSYNC_METHOD_BATCH)
+
+struct rlimit {
+	unsigned int rlim_cur;
+};
+#define RLIMIT_NOFILE 0
+
+static inline int getrlimit(int resource, struct rlimit *rlp)
+{
+	if (resource != RLIMIT_NOFILE) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	rlp->rlim_cur = 2048;
+	return 0;
+}
+
+/*
+ * Use mingw specific stat()/lstat()/fstat() implementations on Windows,
+ * including our own struct stat with 64 bit st_size and nanosecond-precision
+ * file times.
+ */
+#ifndef __MINGW64_VERSION_MAJOR
+#define off_t off64_t
+#define lseek _lseeki64
+#ifndef _MSC_VER
+struct timespec {
+	time_t tv_sec;
+	long tv_nsec;
+};
+#endif
+#endif
+
+struct mingw_stat {
+    _dev_t st_dev;
+    _ino_t st_ino;
+    _mode_t st_mode;
+    short st_nlink;
+    short st_uid;
+    short st_gid;
+    _dev_t st_rdev;
+    off64_t st_size;
+    struct timespec st_atim;
+    struct timespec st_mtim;
+    struct timespec st_ctim;
+};
+
+#define st_atime st_atim.tv_sec
+#define st_mtime st_mtim.tv_sec
+#define st_ctime st_ctim.tv_sec
+
+#ifdef stat
+#undef stat
+#endif
+#define stat mingw_stat
+int mingw_lstat(const char *file_name, struct stat *buf);
+int mingw_stat(const char *file_name, struct stat *buf);
+int mingw_fstat(int fd, struct stat *buf);
+#ifdef fstat
+#undef fstat
+#endif
+#define fstat mingw_fstat
+#ifdef lstat
+#undef lstat
+#endif
+#define lstat mingw_lstat
+
+
+int mingw_utime(const char *file_name, const struct utimbuf *times);
+#define utime mingw_utime
+size_t mingw_strftime(char *s, size_t max,
+		   const char *format, const struct tm *tm);
+#define strftime mingw_strftime
+
+pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
+		     const char *dir,
+		     int fhin, int fhout, int fherr);
+int mingw_execvp(const char *cmd, char *const *argv);
+#define execvp mingw_execvp
+int mingw_execv(const char *cmd, char *const *argv);
+#define execv mingw_execv
+
+static inline unsigned int git_ntohl(unsigned int x)
+{ return (unsigned int)ntohl(x); }
+#define ntohl git_ntohl
+
+sig_handler_t mingw_signal(int sig, sig_handler_t handler);
+#define signal mingw_signal
+
+int mingw_raise(int sig);
+#define raise mingw_raise
+
+/*
+ * ANSI emulation wrappers
+ */
+
+int winansi_isatty(int fd);
+#define isatty winansi_isatty
+
+int winansi_dup2(int oldfd, int newfd);
+#define dup2 winansi_dup2
+
+void winansi_init(void);
+HANDLE winansi_get_osfhandle(int fd);
+
+/*
+ * git specific compatibility
+ */
+
+static inline void convert_slashes(char *path)
+{
+	for (; *path; path++)
+		if (*path == '\\')
+			*path = '/';
+}
+#define PATH_SEP ';'
+char *mingw_query_user_email(void);
+#define query_user_email mingw_query_user_email
+#if !defined(__MINGW64_VERSION_MAJOR) && (!defined(_MSC_VER) || _MSC_VER < 1800)
+#define PRIuMAX "I64u"
+#define PRId64 "I64d"
+#else
+#include <inttypes.h>
+#endif
+
+/**
+ * Verifies that the specified path is owned by the user running the
+ * current process.
+ */
+int is_path_owned_by_current_sid(const char *path, struct strbuf *report);
+#define is_path_owned_by_current_user is_path_owned_by_current_sid
+
+/**
+ * Verifies that the given path is a valid one on Windows.
+ *
+ * In particular, path segments are disallowed which
+ *
+ * - end in a period or a space (except the special directories `.` and `..`).
+ *
+ * - contain any of the reserved characters, e.g. `:`, `;`, `*`, etc
+ *
+ * - correspond to reserved names (such as `AUX`, `PRN`, etc)
+ *
+ * The `allow_literal_nul` parameter controls whether the path `NUL` should
+ * be considered valid (this makes sense e.g. before opening files, as it is
+ * perfectly legitimate to open `NUL` on Windows, just as it is to open
+ * `/dev/null` on Unix/Linux).
+ *
+ * Returns 1 upon success, otherwise 0.
+ */
+int is_valid_win32_path(const char *path, int allow_literal_nul);
+#define is_valid_path(path) is_valid_win32_path(path, 0)
+
+/**
+ * Converts UTF-8 encoded string to UTF-16LE.
+ *
+ * To support repositories with legacy-encoded file names, invalid UTF-8 bytes
+ * 0xa0 - 0xff are converted to corresponding printable Unicode chars \u00a0 -
+ * \u00ff, and invalid UTF-8 bytes 0x80 - 0x9f (which would make non-printable
+ * Unicode) are converted to hex-code.
+ *
+ * Lead-bytes not followed by an appropriate number of trail-bytes, over-long
+ * encodings and 4-byte encodings > \u10ffff are detected as invalid UTF-8.
+ *
+ * Maximum space requirement for the target buffer is two wide chars per UTF-8
+ * char (((strlen(utf) * 2) + 1) [* sizeof(wchar_t)]).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * invalid UTF-8 bytes in range 0x80-0x9f, as per the following table:
+ *
+ *               |                   | UTF-8 | UTF-16 |
+ *   Code point  |  UTF-8 sequence   | bytes | words  | ratio
+ * --------------+-------------------+-------+--------+-------
+ * 000000-00007f | 0-7f              |   1   |   1    |  1
+ * 000080-0007ff | c2-df + 80-bf     |   2   |   1    |  0.5
+ * 000800-00ffff | e0-ef + 2 * 80-bf |   3   |   1    |  0.33
+ * 010000-10ffff | f0-f4 + 3 * 80-bf |   4   |  2 (a) |  0.5
+ * invalid       | 80-9f             |   1   |  2 (b) |  2
+ * invalid       | a0-ff             |   1   |   1    |  1
+ *
+ * (a) encoded as UTF-16 surrogate pair
+ * (b) encoded as two hex digits
+ *
+ * Note that, while the UTF-8 encoding scheme can be extended to 5-byte, 6-byte
+ * or even indefinite-byte sequences, the largest valid code point \u10ffff
+ * encodes as only 4 UTF-8 bytes.
+ *
+ * Parameters:
+ * wcs: wide char target buffer
+ * utf: string to convert
+ * wcslen: size of target buffer (in wchar_t's)
+ * utflen: size of string to convert, or -1 if 0-terminated
+ *
+ * Returns:
+ * length of converted string (_wcslen(wcs)), or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xutftowcsn(wchar_t *wcs, const char *utf, size_t wcslen, int utflen);
+
+/**
+ * Simplified variant of xutftowcsn, assumes input string is \0-terminated.
+ */
+static inline int xutftowcs(wchar_t *wcs, const char *utf, size_t wcslen)
+{
+	return xutftowcsn(wcs, utf, wcslen, -1);
+}
+
+/**
+ * Simplified file system specific variant of xutftowcsn, assumes output
+ * buffer size is MAX_PATH wide chars and input string is \0-terminated,
+ * fails with ENAMETOOLONG if input string is too long.
+ */
+static inline int xutftowcs_path(wchar_t *wcs, const char *utf)
+{
+	int result = xutftowcsn(wcs, utf, MAX_PATH, -1);
+	if (result < 0 && errno == ERANGE)
+		errno = ENAMETOOLONG;
+	return result;
+}
+
+/**
+ * Converts UTF-16LE encoded string to UTF-8.
+ *
+ * Maximum space requirement for the target buffer is three UTF-8 chars per
+ * wide char ((_wcslen(wcs) * 3) + 1).
+ *
+ * The maximum space is needed only if the entire input string consists of
+ * UTF-16 words in range 0x0800-0xd7ff or 0xe000-0xffff (i.e. \u0800-\uffff
+ * modulo surrogate pairs), as per the following table:
+ *
+ *               |                       | UTF-16 | UTF-8 |
+ *   Code point  |  UTF-16 sequence      | words  | bytes | ratio
+ * --------------+-----------------------+--------+-------+-------
+ * 000000-00007f | 0000-007f             |   1    |   1   |  1
+ * 000080-0007ff | 0080-07ff             |   1    |   2   |  2
+ * 000800-00ffff | 0800-d7ff / e000-ffff |   1    |   3   |  3
+ * 010000-10ffff | d800-dbff + dc00-dfff |   2    |   4   |  2
+ *
+ * Note that invalid code points > 10ffff cannot be represented in UTF-16.
+ *
+ * Parameters:
+ * utf: target buffer
+ * wcs: wide string to convert
+ * utflen: size of target buffer
+ *
+ * Returns:
+ * length of converted string, or -1 on failure
+ *
+ * Errors:
+ * EINVAL: one of the input parameters is invalid (e.g. NULL)
+ * ERANGE: the output buffer is too small
+ */
+int xwcstoutf(char *utf, const wchar_t *wcs, size_t utflen);
+
+/*
+ * A critical section used in the implementation of the spawn
+ * functions (mingw_spawnv[p]e()) and waitpid(). Initialised in
+ * the replacement main() macro below.
+ */
+extern CRITICAL_SECTION pinfo_cs;
+
+/*
+ * Git, like most portable C applications, implements a main() function. On
+ * Windows, this main() function would receive parameters encoded in the
+ * current locale, but Git for Windows would prefer UTF-8 encoded  parameters.
+ *
+ * To make that happen, we still declare main() here, and then declare and
+ * implement wmain() (which is the Unicode variant of main()) and compile with
+ * -municode. This wmain() function reencodes the parameters from UTF-16 to
+ * UTF-8 format, sets up a couple of other things as required on Windows, and
+ * then hands off to the main() function.
+ */
+int wmain(int argc, const wchar_t **w_argv);
+int main(int argc, const char **argv);
+
+/*
+ * For debugging: if a problem occurs, say, in a Git process that is spawned
+ * from another Git process which in turn is spawned from yet another Git
+ * process, it can be quite daunting to figure out what is going on.
+ *
+ * Call this function to open a new MinTTY (this assumes you are in Git for
+ * Windows' SDK) with a GDB that attaches to the current process right away.
+ */
+void open_in_gdb(void);
+
+/*
+ * Used by Pthread API implementation for Windows
+ */
+int err_win_to_posix(DWORD winerr);
+
+#ifndef NO_UNIX_SOCKETS
+int mingw_have_unix_sockets(void);
+#undef have_unix_sockets
+#define have_unix_sockets mingw_have_unix_sockets
+#endif
diff --git a/compat/mkdir.c b/compat/mkdir.c
new file mode 100644
index 0000000000..02aea3b32e
--- /dev/null
+++ b/compat/mkdir.c
@@ -0,0 +1,24 @@
+#include "../git-compat-util.h"
+#undef mkdir
+
+/* for platforms that can't deal with a trailing '/' */
+int compat_mkdir_wo_trailing_slash(const char *dir, mode_t mode)
+{
+	int retval;
+	char *tmp_dir = NULL;
+	size_t len = strlen(dir);
+
+	if (len && dir[len-1] == '/') {
+		if (!(tmp_dir = strdup(dir)))
+			return -1;
+		tmp_dir[len-1] = '\0';
+	}
+	else
+		tmp_dir = (char *)dir;
+
+	retval = mkdir(tmp_dir, mode);
+	if (tmp_dir != dir)
+		free(tmp_dir);
+
+	return retval;
+}
diff --git a/compat/mkdtemp.c b/compat/mkdtemp.c
new file mode 100644
index 0000000000..1136119592
--- /dev/null
+++ b/compat/mkdtemp.c
@@ -0,0 +1,8 @@
+#include "../git-compat-util.h"
+
+char *gitmkdtemp(char *template)
+{
+	if (!*mktemp(template) || mkdir(template, 0700))
+		return NULL;
+	return template;
+}
diff --git a/compat/mmap.c b/compat/mmap.c
new file mode 100644
index 0000000000..2fe1c7732e
--- /dev/null
+++ b/compat/mmap.c
@@ -0,0 +1,45 @@
+#include "../git-compat-util.h"
+
+void *git_mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset)
+{
+	size_t n = 0;
+
+	if (start != NULL || flags != MAP_PRIVATE || prot != PROT_READ)
+		die("Invalid usage of mmap when built with NO_MMAP");
+
+	if (length == 0) {
+		errno = EINVAL;
+		return MAP_FAILED;
+	}
+
+	start = malloc(length);
+	if (!start) {
+		errno = ENOMEM;
+		return MAP_FAILED;
+	}
+
+	while (n < length) {
+		ssize_t count = xpread(fd, (char *)start + n, length - n, offset + n);
+
+		if (count == 0) {
+			memset((char *)start+n, 0, length-n);
+			break;
+		}
+
+		if (count < 0) {
+			free(start);
+			errno = EACCES;
+			return MAP_FAILED;
+		}
+
+		n += count;
+	}
+
+	return start;
+}
+
+int git_munmap(void *start, size_t length)
+{
+	free(start);
+	return 0;
+}
diff --git a/compat/msvc.c b/compat/msvc.c
new file mode 100644
index 0000000000..71843d7eef
--- /dev/null
+++ b/compat/msvc.c
@@ -0,0 +1,6 @@
+#include "../git-compat-util.h"
+#include "win32.h"
+#include <conio.h>
+#include "../strbuf.h"
+
+#include "mingw.c"
diff --git a/compat/msvc.h b/compat/msvc.h
new file mode 100644
index 0000000000..1d7a8c6145
--- /dev/null
+++ b/compat/msvc.h
@@ -0,0 +1,33 @@
+#ifndef __MSVC__HEAD
+#define __MSVC__HEAD
+
+#include <direct.h>
+#include <process.h>
+#include <malloc.h>
+#include <io.h>
+
+#pragma warning(disable: 4018) /* signed/unsigned comparison */
+#pragma warning(disable: 4244) /* type conversion, possible loss of data */
+#pragma warning(disable: 4090) /* 'function' : different 'const' qualifiers (ALLOC_GROW etc.)*/
+
+/* porting function */
+#define inline __inline
+#define __inline__ __inline
+#define __attribute__(x)
+#define strcasecmp   _stricmp
+#define strncasecmp  _strnicmp
+#define ftruncate    _chsize
+#define strtoull     _strtoui64
+#define strtoll      _strtoi64
+
+#undef ERROR
+
+#define ftello _ftelli64
+
+typedef int sigset_t;
+/* open for reading, writing, or both (not in fcntl.h) */
+#define O_ACCMODE     (_O_RDONLY | _O_WRONLY | _O_RDWR)
+
+#include "compat/mingw.h"
+
+#endif
diff --git a/compat/nedmalloc/License.txt b/compat/nedmalloc/License.txt
new file mode 100644
index 0000000000..36b7cd93cd
--- /dev/null
+++ b/compat/nedmalloc/License.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/compat/nedmalloc/Readme.txt b/compat/nedmalloc/Readme.txt
new file mode 100644
index 0000000000..07cbf50c0f
--- /dev/null
+++ b/compat/nedmalloc/Readme.txt
@@ -0,0 +1,136 @@
+nedalloc v1.05 15th June 2008:
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+by Niall Douglas (http://www.nedprod.com/programs/portable/nedmalloc/)
+
+Enclosed is nedalloc, an alternative malloc implementation for multiple
+threads without lock contention based on dlmalloc v2.8.4. It is more
+or less a newer implementation of ptmalloc2, the standard allocator in
+Linux (which is based on dlmalloc v2.7.0) but also contains a per-thread
+cache for maximum CPU scalability.
+
+It is licensed under the Boost Software License which basically means
+you can do anything you like with it. This does not apply to the malloc.c.h
+file which remains copyright to others.
+
+It has been tested on win32 (x86), win64 (x64), Linux (x64), FreeBSD (x64)
+and Apple MacOS X (x86). It works very well on all of these and is very
+significantly faster than the system allocator on all of these platforms.
+
+By literally dropping in this allocator as a replacement for your system
+allocator, you can see real world improvements of up to three times in normal
+code!
+
+To use:
+-=-=-=-
+Drop in nedmalloc.h, nedmalloc.c and malloc.c.h into your project.
+Configure using the instructions in nedmalloc.h. Run and enjoy.
+
+To test, compile test.c. It will run a comparison between your system
+allocator and nedalloc and tell you how much faster nedalloc is. It also
+serves as an example of usage.
+
+Notes:
+-=-=-=
+If you want the very latest version of this allocator, get it from the
+TnFOX SVN repository at svn://svn.berlios.de/viewcvs/tnfox/trunk/src/nedmalloc
+
+Because of how nedalloc allocates an mspace per thread, it can cause
+severe bloating of memory usage under certain allocation patterns.
+You can substantially reduce this wastage by setting MAXTHREADSINPOOL
+or the threads parameter to nedcreatepool() to a fraction of the number of
+threads which would normally be in a pool at once. This will reduce
+bloating at the cost of an increase in lock contention. If allocated size
+is less than THREADCACHEMAX, locking is avoided 90-99% of the time and
+if most of your allocations are below this value, you can safely set
+MAXTHREADSINPOOL to one.
+
+You will suffer memory leakage unless you call neddisablethreadcache()
+per pool for every thread which exits. This is because nedalloc cannot
+portably know when a thread exits and thus when its thread cache can
+be returned for use by other code. Don't forget pool zero, the system pool.
+
+For C++ type allocation patterns (where the same sizes of memory are
+regularly allocated and deallocated as objects are created and destroyed),
+the threadcache always benefits performance. If however your allocation
+patterns are different, searching the threadcache may significantly slow
+down your code - as a rule of thumb, if cache utilisation is below 80%
+(see the source for neddisablethreadcache() for how to enable debug
+printing in release mode) then you should disable the thread cache for
+that thread. You can compile out the threadcache code by setting
+THREADCACHEMAX to zero.
+
+Speed comparisons:
+-=-=-=-=-=-=-=-=-=
+See Benchmarks.xls for details.
+
+The enclosed test.c can do two things: it can be a torture test or a speed
+test. The speed test is designed to be a representative synthetic
+memory allocator test. It works by randomly mixing allocations with frees
+with half of the allocation sizes being a two power multiple less than
+512 bytes (to mimic C++ stack instantiated objects) and the other half
+being a simple random value less than 16Kb.
+
+The real world code results are from Tn's TestIO benchmark. This is a
+heavily multithreaded and memory intensive benchmark with a lot of branching
+and other stuff modern processors don't like so much. As you'll note, the
+test doesn't show the benefits of the threadcache mostly due to the saturation
+of the memory bus being the limiting factor.
+
+ChangeLog:
+-=-=-=-=-=
+v1.05 15th June 2008:
+ * { 1042 } Added error check for TLSSET() and TLSFREE() macros. Thanks to
+Markus Elfring for reporting this.
+ * { 1043 } Fixed a segfault when freeing memory allocated using
+nedindependent_comalloc(). Thanks to Pavel Vozenilek for reporting this.
+
+v1.04 14th July 2007:
+ * Fixed a bug with the new optimised implementation that failed to lock
+on a realloc under certain conditions.
+ * Fixed lack of thread synchronisation in InitPool() causing pool corruption
+ * Fixed a memory leak of thread cache contents on disabling. Thanks to Earl
+Chew for reporting this.
+ * Added a sanity check for freed blocks being valid.
+ * Reworked test.c into being a torture test.
+ * Fixed GCC assembler optimisation misspecification
+
+v1.04alpha_svn915 7th October 2006:
+ * Fixed failure to unlock thread cache list if allocating a new list failed.
+Thanks to Dmitry Chichkov for reporting this. Further thanks to Aleksey Sanin.
+ * Fixed realloc(0, <size>) segfaulting. Thanks to Dmitry Chichkov for
+reporting this.
+ * Made config defines #ifndef so they can be overridden by the build system.
+Thanks to Aleksey Sanin for suggesting this.
+ * Fixed deadlock in nedprealloc() due to unnecessary locking of preferred
+thread mspace when mspace_realloc() always uses the original block's mspace
+anyway. Thanks to Aleksey Sanin for reporting this.
+ * Made some speed improvements by hacking mspace_malloc() to no longer lock
+its mspace, thus allowing the recursive mutex implementation to be removed
+with an associated speed increase. Thanks to Aleksey Sanin for suggesting this.
+ * Fixed a bug where allocating mspaces overran its max limit. Thanks to
+Aleksey Sanin for reporting this.
+
+v1.03 10th July 2006:
+ * Fixed memory corruption bug in threadcache code which only appeared with >4
+threads and in heavy use of the threadcache.
+
+v1.02 15th May 2006:
+ * Integrated dlmalloc v2.8.4, fixing the win32 memory release problem and
+improving performance still further. Speed is now up to twice the speed of v1.01
+(average is 67% faster).
+ * Fixed win32 critical section implementation. Thanks to Pavel Kuznetsov
+for reporting this.
+ * Wasn't locking mspace if all mspaces were locked. Thanks to Pavel Kuznetsov
+for reporting this.
+ * Added Apple Mac OS X support.
+
+v1.01 24th February 2006:
+ * Fixed multiprocessor scaling problems by removing sources of cache sloshing
+ * Earl Chew <earl_chew <at> agilent <dot> com> sent patches for the following:
+   1. size2binidx() wasn't working for default code path (non x86)
+   2. Fixed failure to release mspace lock under certain circumstances which
+      caused a deadlock
+
+v1.00 1st January 2006:
+ * First release
diff --git a/compat/nedmalloc/malloc.c.h b/compat/nedmalloc/malloc.c.h
new file mode 100644
index 0000000000..814845d4b3
--- /dev/null
+++ b/compat/nedmalloc/malloc.c.h
@@ -0,0 +1,5761 @@
+/*
+  This is a version (aka dlmalloc) of malloc/free/realloc written by
+  Doug Lea and released to the public domain, as explained at
+  http://creativecommons.org/licenses/publicdomain.  Send questions,
+  comments, complaints, performance data, etc to dl@xxxxxxxxxxxxx
+
+* Version pre-2.8.4 Mon Nov 27 11:22:37 2006    (dl at gee)
+
+   Note: There may be an updated version of this malloc obtainable at
+	   ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+	 Check before installing!
+
+* Quickstart
+
+  This library is all in one file to simplify the most common usage:
+  ftp it, compile it (-O3), and link it into another program. All of
+  the compile-time options default to reasonable values for use on
+  most platforms.  You might later want to step through various
+  compile-time and dynamic tuning options.
+
+  For convenience, an include file for code using this malloc is at:
+     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.4.h
+  You don't really need this .h file unless you call functions not
+  defined in your system include files.  The .h file contains only the
+  excerpts from this file needed for using this malloc on ANSI C/C++
+  systems, so long as you haven't changed compile-time options about
+  naming and tuning parameters.  If you do, then you can create your
+  own malloc.h that does include all settings by cutting at the point
+  indicated below. Note that you may already by default be using a C
+  library containing a malloc that is based on some version of this
+  malloc (for example in linux). You might still want to use the one
+  in this file to customize settings or to avoid overheads associated
+  with library versions.
+
+* Vital statistics:
+
+  Supported pointer/size_t representation:       4 or 8 bytes
+       size_t MUST be an unsigned type of the same width as
+       pointers. (If you are using an ancient system that declares
+       size_t as a signed type, or need it to be a different width
+       than pointers, you can use a previous release of this malloc
+       (e.g. 2.7.2) supporting these.)
+
+  Alignment:                                     8 bytes (default)
+       This suffices for nearly all current machines and C compilers.
+       However, you can define MALLOC_ALIGNMENT to be wider than this
+       if necessary (up to 128bytes), at the expense of using more space.
+
+  Minimum overhead per allocated chunk:   4 or  8 bytes (if 4byte sizes)
+					  8 or 16 bytes (if 8byte sizes)
+       Each malloced chunk has a hidden word of overhead holding size
+       and status information, and additional cross-check word
+       if FOOTERS is defined.
+
+  Minimum allocated size: 4-byte ptrs:  16 bytes    (including overhead)
+			  8-byte ptrs:  32 bytes    (including overhead)
+
+       Even a request for zero bytes (i.e., malloc(0)) returns a
+       pointer to something of the minimum allocatable size.
+       The maximum overhead wastage (i.e., number of extra bytes
+       allocated than were requested in malloc) is less than or equal
+       to the minimum size, except for requests >= mmap_threshold that
+       are serviced via mmap(), where the worst case wastage is about
+       32 bytes plus the remainder from a system page (the minimal
+       mmap unit); typically 4096 or 8192 bytes.
+
+  Security: static-safe; optionally more or less
+       The "security" of malloc refers to the ability of malicious
+       code to accentuate the effects of errors (for example, freeing
+       space that is not currently malloc'ed or overwriting past the
+       ends of chunks) in code that calls malloc.  This malloc
+       guarantees not to modify any memory locations below the base of
+       heap, i.e., static variables, even in the presence of usage
+       errors.  The routines additionally detect most improper frees
+       and reallocs.  All this holds as long as the static bookkeeping
+       for malloc itself is not corrupted by some other means.  This
+       is only one aspect of security -- these checks do not, and
+       cannot, detect all possible programming errors.
+
+       If FOOTERS is defined nonzero, then each allocated chunk
+       carries an additional check word to verify that it was malloced
+       from its space.  These check words are the same within each
+       execution of a program using malloc, but differ across
+       executions, so externally crafted fake chunks cannot be
+       freed. This improves security by rejecting frees/reallocs that
+       could corrupt heap memory, in addition to the checks preventing
+       writes to statics that are always on.  This may further improve
+       security at the expense of time and space overhead.  (Note that
+       FOOTERS may also be worth using with MSPACES.)
+
+       By default detected errors cause the program to abort (calling
+       "abort()"). You can override this to instead proceed past
+       errors by defining PROCEED_ON_ERROR.  In this case, a bad free
+       has no effect, and a malloc that encounters a bad address
+       caused by user overwrites will ignore the bad address by
+       dropping pointers and indices to all known memory. This may
+       be appropriate for programs that should continue if at all
+       possible in the face of programming errors, although they may
+       run out of memory because dropped memory is never reclaimed.
+
+       If you don't like either of these options, you can define
+       CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
+       else. And if you are sure that your program using malloc has
+       no errors or vulnerabilities, you can define INSECURE to 1,
+       which might (or might not) provide a small performance improvement.
+
+  Thread-safety: NOT thread-safe unless USE_LOCKS defined
+       When USE_LOCKS is defined, each public call to malloc, free,
+       etc is surrounded with either a pthread mutex or a win32
+       spinlock (depending on WIN32). This is not especially fast, and
+       can be a major bottleneck.  It is designed only to provide
+       minimal protection in concurrent environments, and to provide a
+       basis for extensions.  If you are using malloc in a concurrent
+       program, consider instead using nedmalloc
+       (http://www.nedprod.com/programs/portable/nedmalloc/) or
+       ptmalloc (See http://www.malloc.de), which are derived
+       from versions of this malloc.
+
+  System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
+       This malloc can use unix sbrk or any emulation (invoked using
+       the CALL_MORECORE macro) and/or mmap/munmap or any emulation
+       (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
+       memory.  On most unix systems, it tends to work best if both
+       MORECORE and MMAP are enabled.  On Win32, it uses emulations
+       based on VirtualAlloc. It also uses common C library functions
+       like memset.
+
+  Compliance: I believe it is compliant with the Single Unix Specification
+       (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
+       others as well.
+
+* Overview of algorithms
+
+  This is not the fastest, most space-conserving, most portable, or
+  most tunable malloc ever written. However it is among the fastest
+  while also being among the most space-conserving, portable and
+  tunable.  Consistent balance across these factors results in a good
+  general-purpose allocator for malloc-intensive programs.
+
+  In most ways, this malloc is a best-fit allocator. Generally, it
+  chooses the best-fitting existing chunk for a request, with ties
+  broken in approximately least-recently-used order. (This strategy
+  normally maintains low fragmentation.) However, for requests less
+  than 256bytes, it deviates from best-fit when there is not an
+  exactly fitting available chunk by preferring to use space adjacent
+  to that used for the previous small request, as well as by breaking
+  ties in approximately most-recently-used order. (These enhance
+  locality of series of small allocations.)  And for very large requests
+  (>= 256Kb by default), it relies on system memory mapping
+  facilities, if supported.  (This helps avoid carrying around and
+  possibly fragmenting memory used only for large chunks.)
+
+  All operations (except malloc_stats and mallinfo) have execution
+  times that are bounded by a constant factor of the number of bits in
+  a size_t, not counting any clearing in calloc or copying in realloc,
+  or actions surrounding MORECORE and MMAP that have times
+  proportional to the number of non-contiguous regions returned by
+  system allocation routines, which is often just 1. In real-time
+  applications, you can optionally suppress segment traversals using
+  NO_SEGMENT_TRAVERSAL, which assures bounded execution even when
+  system allocators return non-contiguous spaces, at the typical
+  expense of carrying around more memory and increased fragmentation.
+
+  The implementation is not very modular and seriously overuses
+  macros. Perhaps someday all C compilers will do as good a job
+  inlining modular code as can now be done by brute-force expansion,
+  but now, enough of them seem not to.
+
+  Some compilers issue a lot of warnings about code that is
+  dead/unreachable only on some platforms, and also about intentional
+  uses of negation on unsigned types. All known cases of each can be
+  ignored.
+
+  For a longer but out of date high-level description, see
+     http://gee.cs.oswego.edu/dl/html/malloc.html
+
+* MSPACES
+  If MSPACES is defined, then in addition to malloc, free, etc.,
+  this file also defines mspace_malloc, mspace_free, etc. These
+  are versions of malloc routines that take an "mspace" argument
+  obtained using create_mspace, to control all internal bookkeeping.
+  If ONLY_MSPACES is defined, only these versions are compiled.
+  So if you would like to use this allocator for only some allocations,
+  and your system malloc for others, you can compile with
+  ONLY_MSPACES and then do something like...
+    static mspace mymspace = create_mspace(0,0); // for example
+    #define mymalloc(bytes)  mspace_malloc(mymspace, bytes)
+
+  (Note: If you only need one instance of an mspace, you can instead
+  use "USE_DL_PREFIX" to relabel the global malloc.)
+
+  You can similarly create thread-local allocators by storing
+  mspaces as thread-locals. For example:
+    static __thread mspace tlms = 0;
+    void*  tlmalloc(size_t bytes) {
+      if (tlms == 0) tlms = create_mspace(0, 0);
+      return mspace_malloc(tlms, bytes);
+    }
+    void  tlfree(void* mem) { mspace_free(tlms, mem); }
+
+  Unless FOOTERS is defined, each mspace is completely independent.
+  You cannot allocate from one and free to another (although
+  conformance is only weakly checked, so usage errors are not always
+  caught). If FOOTERS is defined, then each chunk carries around a tag
+  indicating its originating mspace, and frees are directed to their
+  originating spaces.
+
+ -------------------------  Compile-time options ---------------------------
+
+Be careful in setting #define values for numerical constants of type
+size_t. On some systems, literal values are not automatically extended
+to size_t precision unless they are explicitly casted. You can also
+use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.
+
+WIN32                    default: defined if _WIN32 defined
+  Defining WIN32 sets up defaults for MS environment and compilers.
+  Otherwise defaults are for unix. Beware that there seem to be some
+  cases where this malloc might not be a pure drop-in replacement for
+  Win32 malloc: Random-looking failures from Win32 GDI API's (eg;
+  SetDIBits()) may be due to bugs in some video driver implementations
+  when pixel buffers are malloc()ed, and the region spans more than
+  one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)
+  default granularity, pixel buffers may straddle virtual allocation
+  regions more often than when using the Microsoft allocator.  You can
+  avoid this by using VirtualAlloc() and VirtualFree() for all pixel
+  buffers rather than using malloc().  If this is not possible,
+  recompile this malloc with a larger DEFAULT_GRANULARITY.
+
+MALLOC_ALIGNMENT         default: (size_t)8
+  Controls the minimum alignment for malloc'ed chunks.  It must be a
+  power of two and at least 8, even on machines for which smaller
+  alignments would suffice. It may be defined as larger than this
+  though. Note however that code and data structures are optimized for
+  the case of 8-byte alignment.
+
+MSPACES                  default: 0 (false)
+  If true, compile in support for independent allocation spaces.
+  This is only supported if HAVE_MMAP is true.
+
+ONLY_MSPACES             default: 0 (false)
+  If true, only compile in mspace versions, not regular versions.
+
+USE_LOCKS                default: 0 (false)
+  Causes each call to each public routine to be surrounded with
+  pthread or WIN32 mutex lock/unlock. (If set true, this can be
+  overridden on a per-mspace basis for mspace versions.) If set to a
+  non-zero value other than 1, locks are used, but their
+  implementation is left out, so lock functions must be supplied manually.
+
+USE_SPIN_LOCKS           default: 1 iff USE_LOCKS and on x86 using gcc or MSC
+  If true, uses custom spin locks for locking. This is currently
+  supported only for x86 platforms using gcc or recent MS compilers.
+  Otherwise, posix locks or win32 critical sections are used.
+
+FOOTERS                  default: 0
+  If true, provide extra checking and dispatching by placing
+  information in the footers of allocated chunks. This adds
+  space and time overhead.
+
+INSECURE                 default: 0
+  If true, omit checks for usage errors and heap space overwrites.
+
+USE_DL_PREFIX            default: NOT defined
+  Causes compiler to prefix all public routines with the string 'dl'.
+  This can be useful when you only want to use this malloc in one part
+  of a program, using your regular system malloc elsewhere.
+
+ABORT                    default: defined as abort()
+  Defines how to abort on failed checks.  On most systems, a failed
+  check cannot die with an "assert" or even print an informative
+  message, because the underlying print routines in turn call malloc,
+  which will fail again.  Generally, the best policy is to simply call
+  abort(). It's not very useful to do more than this because many
+  errors due to overwriting will show up as address faults (null, odd
+  addresses etc) rather than malloc-triggered checks, so will also
+  abort.  Also, most compilers know that abort() does not return, so
+  can better optimize code conditionally calling it.
+
+PROCEED_ON_ERROR           default: defined as 0 (false)
+  Controls whether detected bad addresses cause them to bypassed
+  rather than aborting. If set, detected bad arguments to free and
+  realloc are ignored. And all bookkeeping information is zeroed out
+  upon a detected overwrite of freed heap space, thus losing the
+  ability to ever return it from malloc again, but enabling the
+  application to proceed. If PROCEED_ON_ERROR is defined, the
+  static variable malloc_corruption_error_count is compiled in
+  and can be examined to see if errors have occurred. This option
+  generates slower code than the default abort policy.
+
+DEBUG                    default: NOT defined
+  The DEBUG setting is mainly intended for people trying to modify
+  this code or diagnose problems when porting to new platforms.
+  However, it may also be able to better isolate user errors than just
+  using runtime checks.  The assertions in the check routines spell
+  out in more detail the assumptions and invariants underlying the
+  algorithms.  The checking is fairly extensive, and will slow down
+  execution noticeably. Calling malloc_stats or mallinfo with DEBUG
+  set will attempt to check every non-mmapped allocated and free chunk
+  in the course of computing the summaries.
+
+ABORT_ON_ASSERT_FAILURE   default: defined as 1 (true)
+  Debugging assertion failures can be nearly impossible if your
+  version of the assert macro causes malloc to be called, which will
+  lead to a cascade of further failures, blowing the runtime stack.
+  ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
+  which will usually make debugging easier.
+
+MALLOC_FAILURE_ACTION     default: sets errno to ENOMEM, or no-op on win32
+  The action to take before "return 0" when malloc fails to be able to
+  return memory because there is none available.
+
+HAVE_MORECORE             default: 1 (true) unless win32 or ONLY_MSPACES
+  True if this system supports sbrk or an emulation of it.
+
+MORECORE                  default: sbrk
+  The name of the sbrk-style system routine to call to obtain more
+  memory.  See below for guidance on writing custom MORECORE
+  functions. The type of the argument to sbrk/MORECORE varies across
+  systems.  It cannot be size_t, because it supports negative
+  arguments, so it is normally the signed type of the same width as
+  size_t (sometimes declared as "intptr_t").  It doesn't much matter
+  though. Internally, we only call it with arguments less than half
+  the max value of a size_t, which should work across all reasonable
+  possibilities, although sometimes generating compiler warnings.
+
+MORECORE_CONTIGUOUS       default: 1 (true) if HAVE_MORECORE
+  If true, take advantage of fact that consecutive calls to MORECORE
+  with positive arguments always return contiguous increasing
+  addresses.  This is true of unix sbrk. It does not hurt too much to
+  set it true anyway, since malloc copes with non-contiguities.
+  Setting it false when definitely non-contiguous saves time
+  and possibly wasted space it would take to discover this though.
+
+MORECORE_CANNOT_TRIM      default: NOT defined
+  True if MORECORE cannot release space back to the system when given
+  negative arguments. This is generally necessary only if you are
+  using a hand-crafted MORECORE function that cannot handle negative
+  arguments.
+
+NO_SEGMENT_TRAVERSAL       default: 0
+  If non-zero, suppresses traversals of memory segments
+  returned by either MORECORE or CALL_MMAP. This disables
+  merging of segments that are contiguous, and selectively
+  releasing them to the OS if unused, but bounds execution times.
+
+HAVE_MMAP                 default: 1 (true)
+  True if this system supports mmap or an emulation of it.  If so, and
+  HAVE_MORECORE is not true, MMAP is used for all system
+  allocation. If set and HAVE_MORECORE is true as well, MMAP is
+  primarily used to directly allocate very large blocks. It is also
+  used as a backup strategy in cases where MORECORE fails to provide
+  space from system. Note: A single call to MUNMAP is assumed to be
+  able to unmap memory that may have be allocated using multiple calls
+  to MMAP, so long as they are adjacent.
+
+HAVE_MREMAP               default: 1 on linux, else 0
+  If true realloc() uses mremap() to re-allocate large blocks and
+  extend or shrink allocation spaces.
+
+MMAP_CLEARS               default: 1 except on WINCE.
+  True if mmap clears memory so calloc doesn't need to. This is true
+  for standard unix mmap using /dev/zero and on WIN32 except for WINCE.
+
+USE_BUILTIN_FFS            default: 0 (i.e., not used)
+  Causes malloc to use the builtin ffs() function to compute indices.
+  Some compilers may recognize and intrinsify ffs to be faster than the
+  supplied C version. Also, the case of x86 using gcc is special-cased
+  to an asm instruction, so is already as fast as it can be, and so
+  this setting has no effect. Similarly for Win32 under recent MS compilers.
+  (On most x86s, the asm version is only slightly faster than the C version.)
+
+malloc_getpagesize         default: derive from system includes, or 4096.
+  The system page size. To the extent possible, this malloc manages
+  memory from the system in page-size units.  This may be (and
+  usually is) a function rather than a constant. This is ignored
+  if WIN32, where page size is determined using getSystemInfo during
+  initialization.
+
+USE_DEV_RANDOM             default: 0 (i.e., not used)
+  Causes malloc to use /dev/random to initialize secure magic seed for
+  stamping footers. Otherwise, the current time is used.
+
+NO_MALLINFO                default: 0
+  If defined, don't compile "mallinfo". This can be a simple way
+  of dealing with mismatches between system declarations and
+  those in this file.
+
+MALLINFO_FIELD_TYPE        default: size_t
+  The type of the fields in the mallinfo struct. This was originally
+  defined as "int" in SVID etc, but is more usefully defined as
+  size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set
+
+REALLOC_ZERO_BYTES_FREES    default: not defined
+  This should be set if a call to realloc with zero bytes should
+  be the same as a call to free. Some people think it should. Otherwise,
+  since this malloc returns a unique pointer for malloc(0), so does
+  realloc(p, 0).
+
+LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
+LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H,  LACKS_ERRNO_H
+LACKS_STDLIB_H                default: NOT defined unless on WIN32
+  Define these if your system does not have these header files.
+  You might need to manually insert some of the declarations they provide.
+
+DEFAULT_GRANULARITY        default: page size if MORECORE_CONTIGUOUS,
+				system_info.dwAllocationGranularity in WIN32,
+				otherwise 64K.
+      Also settable using mallopt(M_GRANULARITY, x)
+  The unit for allocating and deallocating memory from the system.  On
+  most systems with contiguous MORECORE, there is no reason to
+  make this more than a page. However, systems with MMAP tend to
+  either require or encourage larger granularities.  You can increase
+  this value to prevent system allocation functions to be called so
+  often, especially if they are slow.  The value must be at least one
+  page and must be a power of two.  Setting to 0 causes initialization
+  to either page size or win32 region size.  (Note: In previous
+  versions of malloc, the equivalent of this option was called
+  "TOP_PAD")
+
+DEFAULT_TRIM_THRESHOLD    default: 2MB
+      Also settable using mallopt(M_TRIM_THRESHOLD, x)
+  The maximum amount of unused top-most memory to keep before
+  releasing via malloc_trim in free().  Automatic trimming is mainly
+  useful in long-lived programs using contiguous MORECORE.  Because
+  trimming via sbrk can be slow on some systems, and can sometimes be
+  wasteful (in cases where programs immediately afterward allocate
+  more large chunks) the value should be high enough so that your
+  overall system performance would improve by releasing this much
+  memory.  As a rough guide, you might set to a value close to the
+  average size of a process (program) running on your system.
+  Releasing this much memory would allow such a process to run in
+  memory.  Generally, it is worth tuning trim thresholds when a
+  program undergoes phases where several large chunks are allocated
+  and released in ways that can reuse each other's storage, perhaps
+  mixed with phases where there are no such chunks at all. The trim
+  value must be greater than page size to have any useful effect.  To
+  disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
+  some people use of mallocing a huge space and then freeing it at
+  program startup, in an attempt to reserve system memory, doesn't
+  have the intended effect under automatic trimming, since that memory
+  will immediately be returned to the system.
+
+DEFAULT_MMAP_THRESHOLD       default: 256K
+      Also settable using mallopt(M_MMAP_THRESHOLD, x)
+  The request size threshold for using MMAP to directly service a
+  request. Requests of at least this size that cannot be allocated
+  using already-existing space will be serviced via mmap.  (If enough
+  normal freed space already exists it is used instead.)  Using mmap
+  segregates relatively large chunks of memory so that they can be
+  individually obtained and released from the host system. A request
+  serviced through mmap is never reused by any other request (at least
+  not directly; the system may just so happen to remap successive
+  requests to the same locations).  Segregating space in this way has
+  the benefits that: Mmapped space can always be individually released
+  back to the system, which helps keep the system level memory demands
+  of a long-lived program low.  Also, mapped memory doesn't become
+  `locked' between other chunks, as can happen with normally allocated
+  chunks, which means that even trimming via malloc_trim would not
+  release them.  However, it has the disadvantage that the space
+  cannot be reclaimed, consolidated, and then used to service later
+  requests, as happens with normal chunks.  The advantages of mmap
+  nearly always outweigh disadvantages for "large" chunks, but the
+  value of "large" may vary across systems.  The default is an
+  empirically derived value that works well in most systems. You can
+  disable mmap by setting to MAX_SIZE_T.
+
+MAX_RELEASE_CHECK_RATE   default: 4095 unless not HAVE_MMAP
+  The number of consolidated frees between checks to release
+  unused segments when freeing. When using non-contiguous segments,
+  especially with multiple mspaces, checking only for topmost space
+  doesn't always suffice to trigger trimming. To compensate for this,
+  free() will, with a period of MAX_RELEASE_CHECK_RATE (or the
+  current number of segments, if greater) try to release unused
+  segments to the OS when freeing chunks that result in
+  consolidation. The best value for this parameter is a compromise
+  between slowing down frees with relatively costly checks that
+  rarely trigger versus holding on to unused memory. To effectively
+  disable, set to MAX_SIZE_T. This may lead to a very slight speed
+  improvement at the expense of carrying around more memory.
+*/
+
+/* Version identifier to allow people to support multiple versions */
+#ifndef DLMALLOC_VERSION
+#define DLMALLOC_VERSION 20804
+#endif /* DLMALLOC_VERSION */
+
+#if defined(linux)
+#define _GNU_SOURCE 1
+#endif
+
+#ifndef WIN32
+#ifdef _WIN32
+#define WIN32 1
+#endif  /* _WIN32 */
+#ifdef _WIN32_WCE
+#define LACKS_FCNTL_H
+#define WIN32 1
+#endif /* _WIN32_WCE */
+#endif  /* WIN32 */
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x403
+#endif
+#include <windows.h>
+#define HAVE_MMAP 1
+#define HAVE_MORECORE 0
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+#define LACKS_SYS_MMAN_H
+#define LACKS_STRING_H
+#define LACKS_STRINGS_H
+#define LACKS_SYS_TYPES_H
+#define LACKS_ERRNO_H
+#ifndef MALLOC_FAILURE_ACTION
+#define MALLOC_FAILURE_ACTION
+#endif /* MALLOC_FAILURE_ACTION */
+#ifdef _WIN32_WCE /* WINCE reportedly does not clear */
+#define MMAP_CLEARS 0
+#else
+#define MMAP_CLEARS 1
+#endif /* _WIN32_WCE */
+#endif  /* WIN32 */
+
+#if defined(DARWIN) || defined(_DARWIN)
+/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
+#ifndef HAVE_MORECORE
+#define HAVE_MORECORE 0
+#define HAVE_MMAP 1
+/* OSX allocators provide 16 byte alignment */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)16U)
+#endif
+#endif  /* HAVE_MORECORE */
+#endif  /* DARWIN */
+
+#ifndef LACKS_SYS_TYPES_H
+#include <sys/types.h>  /* For size_t */
+#endif  /* LACKS_SYS_TYPES_H */
+
+/* The maximum possible size_t value has all bits set */
+#define MAX_SIZE_T           (~(size_t)0)
+
+#ifndef ONLY_MSPACES
+#define ONLY_MSPACES 0     /* define to a value */
+#else
+#define ONLY_MSPACES 1
+#endif  /* ONLY_MSPACES */
+#ifndef MSPACES
+#if ONLY_MSPACES
+#define MSPACES 1
+#else   /* ONLY_MSPACES */
+#define MSPACES 0
+#endif  /* ONLY_MSPACES */
+#endif  /* MSPACES */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)8U)
+#endif  /* MALLOC_ALIGNMENT */
+#ifndef FOOTERS
+#define FOOTERS 0
+#endif  /* FOOTERS */
+#ifndef ABORT
+#define ABORT  abort()
+#endif  /* ABORT */
+#ifndef ABORT_ON_ASSERT_FAILURE
+#define ABORT_ON_ASSERT_FAILURE 1
+#endif  /* ABORT_ON_ASSERT_FAILURE */
+#ifndef PROCEED_ON_ERROR
+#define PROCEED_ON_ERROR 0
+#endif  /* PROCEED_ON_ERROR */
+#ifndef USE_LOCKS
+#define USE_LOCKS 0
+#endif  /* USE_LOCKS */
+#ifndef USE_SPIN_LOCKS
+#if USE_LOCKS && (defined(__GNUC__) && ((defined(__i386__) || defined(__x86_64__)))) || (defined(_MSC_VER) && _MSC_VER>=1310)
+#define USE_SPIN_LOCKS 1
+#else
+#define USE_SPIN_LOCKS 0
+#endif /* USE_LOCKS && ... */
+#endif /* USE_SPIN_LOCKS */
+#ifndef INSECURE
+#define INSECURE 0
+#endif  /* INSECURE */
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif  /* HAVE_MMAP */
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif  /* MMAP_CLEARS */
+#ifndef HAVE_MREMAP
+#ifdef linux
+#define HAVE_MREMAP 1
+#else   /* linux */
+#define HAVE_MREMAP 0
+#endif  /* linux */
+#endif  /* HAVE_MREMAP */
+#ifndef MALLOC_FAILURE_ACTION
+#define MALLOC_FAILURE_ACTION  errno = ENOMEM;
+#endif  /* MALLOC_FAILURE_ACTION */
+#ifndef HAVE_MORECORE
+#if ONLY_MSPACES
+#define HAVE_MORECORE 0
+#else   /* ONLY_MSPACES */
+#define HAVE_MORECORE 1
+#endif  /* ONLY_MSPACES */
+#endif  /* HAVE_MORECORE */
+#if !HAVE_MORECORE
+#define MORECORE_CONTIGUOUS 0
+#else   /* !HAVE_MORECORE */
+#define MORECORE_DEFAULT sbrk
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif  /* MORECORE_CONTIGUOUS */
+#endif  /* HAVE_MORECORE */
+#ifndef DEFAULT_GRANULARITY
+#if (MORECORE_CONTIGUOUS || defined(WIN32))
+#define DEFAULT_GRANULARITY (0)  /* 0 means to compute in init_mparams */
+#else   /* MORECORE_CONTIGUOUS */
+#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
+#endif  /* MORECORE_CONTIGUOUS */
+#endif  /* DEFAULT_GRANULARITY */
+#ifndef DEFAULT_TRIM_THRESHOLD
+#ifndef MORECORE_CANNOT_TRIM
+#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
+#else   /* MORECORE_CANNOT_TRIM */
+#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
+#endif  /* MORECORE_CANNOT_TRIM */
+#endif  /* DEFAULT_TRIM_THRESHOLD */
+#ifndef DEFAULT_MMAP_THRESHOLD
+#if HAVE_MMAP
+#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
+#else   /* HAVE_MMAP */
+#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
+#endif  /* HAVE_MMAP */
+#endif  /* DEFAULT_MMAP_THRESHOLD */
+#ifndef MAX_RELEASE_CHECK_RATE
+#if HAVE_MMAP
+#define MAX_RELEASE_CHECK_RATE 4095
+#else
+#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T
+#endif /* HAVE_MMAP */
+#endif /* MAX_RELEASE_CHECK_RATE */
+#ifndef USE_BUILTIN_FFS
+#define USE_BUILTIN_FFS 0
+#endif  /* USE_BUILTIN_FFS */
+#ifndef USE_DEV_RANDOM
+#define USE_DEV_RANDOM 0
+#endif  /* USE_DEV_RANDOM */
+#ifndef NO_MALLINFO
+#define NO_MALLINFO 0
+#endif  /* NO_MALLINFO */
+#ifndef MALLINFO_FIELD_TYPE
+#define MALLINFO_FIELD_TYPE size_t
+#endif  /* MALLINFO_FIELD_TYPE */
+#ifndef NO_SEGMENT_TRAVERSAL
+#define NO_SEGMENT_TRAVERSAL 0
+#endif /* NO_SEGMENT_TRAVERSAL */
+
+/*
+  mallopt tuning options.  SVID/XPG defines four standard parameter
+  numbers for mallopt, normally defined in malloc.h.  None of these
+  are used in this malloc, so setting them has no effect. But this
+  malloc does support the following options.
+*/
+
+#define M_TRIM_THRESHOLD     (-1)
+#define M_GRANULARITY        (-2)
+#define M_MMAP_THRESHOLD     (-3)
+
+/* ------------------------ Mallinfo declarations ------------------------ */
+
+#if !NO_MALLINFO
+/*
+  This version of malloc supports the standard SVID/XPG mallinfo
+  routine that returns a struct containing usage properties and
+  statistics. It should work on any system that has a
+  /usr/include/malloc.h defining struct mallinfo.  The main
+  declaration needed is the mallinfo struct that is returned (by-copy)
+  by mallinfo().  The malloinfo struct contains a bunch of fields that
+  are not even meaningful in this version of malloc.  These fields are
+  are instead filled by mallinfo() with other numbers that might be of
+  interest.
+
+  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+  /usr/include/malloc.h file that includes a declaration of struct
+  mallinfo.  If so, it is included; else a compliant version is
+  declared below.  These must be precisely the same for mallinfo() to
+  work.  The original SVID version of this struct, defined on most
+  systems with mallinfo, declares all fields as ints. But some others
+  define as unsigned long. If your system defines the fields using a
+  type of different width than listed here, you MUST #include your
+  system version and #define HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#ifdef HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else /* HAVE_USR_INCLUDE_MALLOC_H */
+#ifndef STRUCT_MALLINFO_DECLARED
+#define STRUCT_MALLINFO_DECLARED 1
+struct mallinfo {
+  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
+  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
+  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
+  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
+  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
+  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
+  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
+  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+  MALLINFO_FIELD_TYPE fordblks; /* total free space */
+  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+#endif /* STRUCT_MALLINFO_DECLARED */
+#endif /* HAVE_USR_INCLUDE_MALLOC_H */
+#endif /* NO_MALLINFO */
+
+/*
+  Try to persuade compilers to inline. The most critical functions for
+  inlining are defined as macros, so these aren't used for them.
+*/
+
+#ifdef __MINGW64_VERSION_MAJOR
+#undef FORCEINLINE
+#endif
+#ifndef FORCEINLINE
+  #if defined(__GNUC__)
+#define FORCEINLINE __inline __attribute__ ((always_inline))
+  #elif defined(_MSC_VER)
+    #define FORCEINLINE __forceinline
+  #endif
+#endif
+#ifndef NOINLINE
+  #if defined(__GNUC__)
+    #define NOINLINE __attribute__ ((noinline))
+  #elif defined(_MSC_VER)
+    #define NOINLINE __declspec(noinline)
+  #else
+    #define NOINLINE
+  #endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#ifndef FORCEINLINE
+ #define FORCEINLINE inline
+#endif
+#endif /* __cplusplus */
+#ifndef FORCEINLINE
+ #define FORCEINLINE
+#endif
+
+#if !ONLY_MSPACES
+
+/* ------------------- Declarations of public routines ------------------- */
+
+#ifndef USE_DL_PREFIX
+#define dlcalloc               calloc
+#define dlfree                 free
+#define dlmalloc               malloc
+#define dlmemalign             memalign
+#define dlrealloc              realloc
+#define dlvalloc               valloc
+#define dlpvalloc              pvalloc
+#define dlmallinfo             mallinfo
+#define dlmallopt              mallopt
+#define dlmalloc_trim          malloc_trim
+#define dlmalloc_stats         malloc_stats
+#define dlmalloc_usable_size   malloc_usable_size
+#define dlmalloc_footprint     malloc_footprint
+#define dlmalloc_max_footprint malloc_max_footprint
+#define dlindependent_calloc   independent_calloc
+#define dlindependent_comalloc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+  malloc(size_t n)
+  Returns a pointer to a newly allocated chunk of at least n bytes, or
+  null if no space is available, in which case errno is set to ENOMEM
+  on ANSI C systems.
+
+  If n is zero, malloc returns a minimum-sized chunk. (The minimum
+  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
+  systems.)  Note that size_t is an unsigned type, so calls with
+  arguments that would be negative if signed are interpreted as
+  requests for huge amounts of space, which will often fail. The
+  maximum supported value of n differs across systems, but is in all
+  cases less than the maximum representable value of a size_t.
+*/
+void* dlmalloc(size_t);
+
+/*
+  free(void* p)
+  Releases the chunk of memory pointed to by p, that had been previously
+  allocated using malloc or a related routine such as realloc.
+  It has no effect if p is null. If p was not malloced or already
+  freed, free(p) will by default cause the current program to abort.
+*/
+void  dlfree(void*);
+
+/*
+  calloc(size_t n_elements, size_t element_size);
+  Returns a pointer to n_elements * element_size bytes, with all locations
+  set to zero.
+*/
+void* dlcalloc(size_t, size_t);
+
+/*
+  realloc(void* p, size_t n)
+  Returns a pointer to a chunk of size n that contains the same data
+  as does chunk p up to the minimum of (n, p's size) bytes, or null
+  if no space is available.
+
+  The returned pointer may or may not be the same as p. The algorithm
+  prefers extending p in most cases when possible, otherwise it
+  employs the equivalent of a malloc-copy-free sequence.
+
+  If p is null, realloc is equivalent to malloc.
+
+  If space is not available, realloc returns null, errno is set (if on
+  ANSI) and p is NOT freed.
+
+  if n is for fewer bytes than already held by p, the newly unused
+  space is lopped off and freed if possible.  realloc with a size
+  argument of zero (re)allocates a minimum-sized chunk.
+
+  The old unix realloc convention of allowing the last-free'd chunk
+  to be used as an argument to realloc is not supported.
+*/
+
+void* dlrealloc(void*, size_t);
+
+/*
+  memalign(size_t alignment, size_t n);
+  Returns a pointer to a newly allocated chunk of n bytes, aligned
+  in accord with the alignment argument.
+
+  The alignment argument should be a power of two. If the argument is
+  not a power of two, the nearest greater power is used.
+  8-byte alignment is guaranteed by normal malloc calls, so don't
+  bother calling memalign with an argument of 8 or less.
+
+  Overreliance on memalign is a sure way to fragment space.
+*/
+void* dlmemalign(size_t, size_t);
+
+/*
+  valloc(size_t n);
+  Equivalent to memalign(pagesize, n), where pagesize is the page
+  size of the system. If the pagesize is unknown, 4096 is used.
+*/
+void* dlvalloc(size_t);
+
+/*
+  mallopt(int parameter_number, int parameter_value)
+  Sets tunable parameters The format is to provide a
+  (parameter-number, parameter-value) pair.  mallopt then sets the
+  corresponding parameter to the argument value if it can (i.e., so
+  long as the value is meaningful), and returns 1 if successful else
+  0.  To workaround the fact that mallopt is specified to use int,
+  not size_t parameters, the value -1 is specially treated as the
+  maximum unsigned size_t value.
+
+  SVID/XPG/ANSI defines four standard param numbers for mallopt,
+  normally defined in malloc.h.  None of these are use in this malloc,
+  so setting them has no effect. But this malloc also supports other
+  options in mallopt. See below for details.  Briefly, supported
+  parameters are as follows (listed defaults are for "typical"
+  configurations).
+
+  Symbol            param #  default    allowed param values
+  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (-1 disables)
+  M_GRANULARITY        -2     page size   any power of 2 >= page size
+  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)
+*/
+int dlmallopt(int, int);
+
+/*
+  malloc_footprint();
+  Returns the number of bytes obtained from the system.  The total
+  number of bytes allocated by malloc, realloc etc., is less than this
+  value. Unlike mallinfo, this function returns only a precomputed
+  result, so can be called frequently to monitor memory consumption.
+  Even if locks are otherwise defined, this function does not use them,
+  so results might not be up to date.
+*/
+size_t dlmalloc_footprint(void);
+
+/*
+  malloc_max_footprint();
+  Returns the maximum number of bytes obtained from the system. This
+  value will be greater than current footprint if deallocated space
+  has been reclaimed by the system. The peak number of bytes allocated
+  by malloc, realloc etc., is less than this value. Unlike mallinfo,
+  this function returns only a precomputed result, so can be called
+  frequently to monitor memory consumption.  Even if locks are
+  otherwise defined, this function does not use them, so results might
+  not be up to date.
+*/
+size_t dlmalloc_max_footprint(void);
+
+#if !NO_MALLINFO
+/*
+  mallinfo()
+  Returns (by copy) a struct containing various summary statistics:
+
+  arena:     current total non-mmapped bytes allocated from system
+  ordblks:   the number of free chunks
+  smblks:    always zero.
+  hblks:     current number of mmapped regions
+  hblkhd:    total bytes held in mmapped regions
+  usmblks:   the maximum total allocated space. This will be greater
+		than current total if trimming has occurred.
+  fsmblks:   always zero
+  uordblks:  current total allocated space (normal or mmapped)
+  fordblks:  total free space
+  keepcost:  the maximum number of bytes that could ideally be released
+	       back to system via malloc_trim. ("ideally" means that
+	       it ignores page restrictions etc.)
+
+  Because these fields are ints, but internal bookkeeping may
+  be kept as longs, the reported values may wrap around zero and
+  thus be inaccurate.
+*/
+struct mallinfo dlmallinfo(void);
+#endif /* NO_MALLINFO */
+
+/*
+  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
+
+  independent_calloc is similar to calloc, but instead of returning a
+  single cleared space, it returns an array of pointers to n_elements
+  independent elements that can hold contents of size elem_size, each
+  of which starts out cleared, and can be independently freed,
+  realloc'ed etc. The elements are guaranteed to be adjacently
+  allocated (this is not guaranteed to occur with multiple callocs or
+  mallocs), which may also improve cache locality in some
+  applications.
+
+  The "chunks" argument is optional (i.e., may be null, which is
+  probably the most typical usage). If it is null, the returned array
+  is itself dynamically allocated and should also be freed when it is
+  no longer needed. Otherwise, the chunks array must be of at least
+  n_elements in length. It is filled in with the pointers to the
+  chunks.
+
+  In either case, independent_calloc returns this pointer array, or
+  null if the allocation failed.  If n_elements is zero and "chunks"
+  is null, it returns a chunk representing an array with zero elements
+  (which should be freed if not wanted).
+
+  Each element must be individually freed when it is no longer
+  needed. If you'd like to instead be able to free all at once, you
+  should instead use regular calloc and assign pointers into this
+  space to represent elements.  (In this case though, you cannot
+  independently free elements.)
+
+  independent_calloc simplifies and speeds up implementations of many
+  kinds of pools.  It may also be useful when constructing large data
+  structures that initially have a fixed number of fixed-sized nodes,
+  but the number is not known at compile time, and some of the nodes
+  may later need to be freed. For example:
+
+  struct Node { int item; struct Node* next; };
+
+  struct Node* build_list() {
+    struct Node** pool;
+    int n = read_number_of_nodes_needed();
+    if (n <= 0) return 0;
+    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+    if (pool == 0) die();
+    // organize into a linked list...
+    struct Node* first = pool[0];
+    for (i = 0; i < n-1; ++i)
+      pool[i]->next = pool[i+1];
+    free(pool);     // Can now free the array (or not, if it is needed later)
+    return first;
+  }
+*/
+void** dlindependent_calloc(size_t, size_t, void**);
+
+/*
+  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
+
+  independent_comalloc allocates, all at once, a set of n_elements
+  chunks with sizes indicated in the "sizes" array.    It returns
+  an array of pointers to these elements, each of which can be
+  independently freed, realloc'ed etc. The elements are guaranteed to
+  be adjacently allocated (this is not guaranteed to occur with
+  multiple callocs or mallocs), which may also improve cache locality
+  in some applications.
+
+  The "chunks" argument is optional (i.e., may be null). If it is null
+  the returned array is itself dynamically allocated and should also
+  be freed when it is no longer needed. Otherwise, the chunks array
+  must be of at least n_elements in length. It is filled in with the
+  pointers to the chunks.
+
+  In either case, independent_comalloc returns this pointer array, or
+  null if the allocation failed.  If n_elements is zero and chunks is
+  null, it returns a chunk representing an array with zero elements
+  (which should be freed if not wanted).
+
+  Each element must be individually freed when it is no longer
+  needed. If you'd like to instead be able to free all at once, you
+  should instead use a single regular malloc, and assign pointers at
+  particular offsets in the aggregate space. (In this case though, you
+  cannot independently free elements.)
+
+  independent_comallac differs from independent_calloc in that each
+  element may have a different size, and also that it does not
+  automatically clear elements.
+
+  independent_comalloc can be used to speed up allocation in cases
+  where several structs or objects must always be allocated at the
+  same time.  For example:
+
+  struct Head { ... }
+  struct Foot { ... }
+
+  void send_message(char* msg) {
+    int msglen = strlen(msg);
+    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+    void* chunks[3];
+    if (independent_comalloc(3, sizes, chunks) == 0)
+      die();
+    struct Head* head = (struct Head*)(chunks[0]);
+    char*        body = (char*)(chunks[1]);
+    struct Foot* foot = (struct Foot*)(chunks[2]);
+    // ...
+  }
+
+  In general though, independent_comalloc is worth using only for
+  larger values of n_elements. For small values, you probably won't
+  detect enough difference from series of malloc calls to bother.
+
+  Overuse of independent_comalloc can increase overall memory usage,
+  since it cannot reuse existing noncontiguous small chunks that
+  might be available for some of the elements.
+*/
+void** dlindependent_comalloc(size_t, size_t*, void**);
+
+
+/*
+  pvalloc(size_t n);
+  Equivalent to valloc(minimum-page-that-holds(n)), that is,
+  round up n to nearest pagesize.
+ */
+void*  dlpvalloc(size_t);
+
+/*
+  malloc_trim(size_t pad);
+
+  If possible, gives memory back to the system (via negative arguments
+  to sbrk) if there is unused memory at the `high' end of the malloc
+  pool or in unused MMAP segments. You can call this after freeing
+  large blocks of memory to potentially reduce the system-level memory
+  requirements of a program. However, it cannot guarantee to reduce
+  memory. Under some allocation patterns, some large free blocks of
+  memory will be locked between two used chunks, so they cannot be
+  given back to the system.
+
+  The `pad' argument to malloc_trim represents the amount of free
+  trailing space to leave untrimmed. If this argument is zero, only
+  the minimum amount of memory to maintain internal data structures
+  will be left. Non-zero arguments can be supplied to maintain enough
+  trailing space to service future expected allocations without having
+  to re-obtain memory from the system.
+
+  Malloc_trim returns 1 if it actually released any memory, else 0.
+*/
+int  dlmalloc_trim(size_t);
+
+/*
+  malloc_stats();
+  Prints on stderr the amount of space obtained from the system (both
+  via sbrk and mmap), the maximum amount (which may be more than
+  current if malloc_trim and/or munmap got called), and the current
+  number of bytes allocated via malloc (or realloc, etc) but not yet
+  freed. Note that this is the number of bytes allocated, not the
+  number requested. It will be larger than the number requested
+  because of alignment and bookkeeping overhead. Because it includes
+  alignment wastage as being in use, this figure may be greater than
+  zero even when no user-level chunks are allocated.
+
+  The reported current and maximum system memory can be inaccurate if
+  a program makes other calls to system memory allocation functions
+  (normally sbrk) outside of malloc.
+
+  malloc_stats prints only the most commonly interesting statistics.
+  More information can be obtained by calling mallinfo.
+*/
+void  dlmalloc_stats(void);
+
+#endif /* ONLY_MSPACES */
+
+/*
+  malloc_usable_size(void* p);
+
+  Returns the number of bytes you can actually use in
+  an allocated chunk, which may be more than you requested (although
+  often not) due to alignment and minimum size constraints.
+  You can use this many bytes without worrying about
+  overwriting other allocated objects. This is not a particularly great
+  programming practice. malloc_usable_size can be more useful in
+  debugging and assertions, for example:
+
+  p = malloc(n);
+  assert(malloc_usable_size(p) >= 256);
+*/
+size_t dlmalloc_usable_size(void*);
+
+
+#if MSPACES
+
+/*
+  mspace is an opaque type representing an independent
+  region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+  create_mspace creates and returns a new independent space with the
+  given initial capacity, or, if 0, the default granularity size.  It
+  returns null if there is no system memory available to create the
+  space.  If argument locked is non-zero, the space uses a separate
+  lock to control access. The capacity of the space will grow
+  dynamically as needed to service mspace_malloc requests.  You can
+  control the sizes of incremental increases of this space by
+  compiling with a different DEFAULT_GRANULARITY or dynamically
+  setting with mallopt(M_GRANULARITY, value).
+*/
+mspace create_mspace(size_t capacity, int locked);
+
+/*
+  destroy_mspace destroys the given space, and attempts to return all
+  of its memory back to the system, returning the total number of
+  bytes freed. After destruction, the results of access to all memory
+  used by the space become undefined.
+*/
+size_t destroy_mspace(mspace msp);
+
+/*
+  create_mspace_with_base uses the memory supplied as the initial base
+  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+  space is used for bookkeeping, so the capacity must be at least this
+  large. (Otherwise 0 is returned.) When this initial space is
+  exhausted, additional memory will be obtained from the system.
+  Destroying this space will deallocate all additionally allocated
+  space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked);
+
+/*
+  mspace_mmap_large_chunks controls whether requests for large chunks
+  are allocated in their own mmapped regions, separate from others in
+  this mspace. By default this is enabled, which reduces
+  fragmentation. However, such chunks are not necessarily released to
+  the system upon destroy_mspace.  Disabling by setting to false may
+  increase fragmentation, but avoids leakage when relying on
+  destroy_mspace to release all memory allocated using this space.
+*/
+int mspace_mmap_large_chunks(mspace msp, int enable);
+
+
+/*
+  mspace_malloc behaves as malloc, but operates within
+  the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+  mspace_free behaves as free, but operates within
+  the given space.
+
+  If compiled with FOOTERS==1, mspace_free is not actually needed.
+  free may be called instead of mspace_free because freed chunks from
+  any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+  mspace_realloc behaves as realloc, but operates within
+  the given space.
+
+  If compiled with FOOTERS==1, mspace_realloc is not actually
+  needed.  realloc may be called instead of mspace_realloc because
+  realloced chunks from any space are handled by their originating
+  spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+  mspace_calloc behaves as calloc, but operates within
+  the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+  mspace_memalign behaves as memalign, but operates within
+  the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+  mspace_independent_calloc behaves as independent_calloc, but
+  operates within the given space.
+*/
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+				 size_t elem_size, void* chunks[]);
+
+/*
+  mspace_independent_comalloc behaves as independent_comalloc, but
+  operates within the given space.
+*/
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+				   size_t sizes[], void* chunks[]);
+
+/*
+  mspace_footprint() returns the number of bytes obtained from the
+  system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+/*
+  mspace_max_footprint() returns the peak number of bytes obtained from the
+  system for this space.
+*/
+size_t mspace_max_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+  mspace_mallinfo behaves as mallinfo, but reports properties of
+  the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+  malloc_usable_size(void* p) behaves the same as malloc_usable_size;
+*/
+  size_t mspace_usable_size(void* mem);
+
+/*
+  mspace_malloc_stats behaves as malloc_stats, but reports
+  properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+  mspace_trim behaves as malloc_trim, but
+  operates within the given space.
+*/
+int mspace_trim(mspace msp, size_t pad);
+
+/*
+  An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#endif /* MSPACES */
+
+#ifdef __cplusplus
+};  /* end of extern "C" */
+#endif /* __cplusplus */
+
+/*
+  ========================================================================
+  To make a fully customizable malloc.h header file, cut everything
+  above this line, put into file malloc.h, edit to suit, and #include it
+  on the next line, as well as in programs that use this malloc.
+  ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/*------------------------------ internal #includes ---------------------- */
+
+#ifdef WIN32
+#ifndef __GNUC__
+#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
+#endif
+#endif /* WIN32 */
+
+#include <stdio.h>       /* for printing in malloc_stats */
+
+#ifndef LACKS_ERRNO_H
+#include <errno.h>       /* for MALLOC_FAILURE_ACTION */
+#endif /* LACKS_ERRNO_H */
+#if FOOTERS
+#include <time.h>        /* for magic initialization */
+#endif /* FOOTERS */
+#ifndef LACKS_STDLIB_H
+#include <stdlib.h>      /* for abort() */
+#endif /* LACKS_STDLIB_H */
+#ifdef DEBUG
+#if ABORT_ON_ASSERT_FAILURE
+#define assert(x) if(!(x)) ABORT
+#else /* ABORT_ON_ASSERT_FAILURE */
+#include <assert.h>
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#else  /* DEBUG */
+#ifndef assert
+#define assert(x)
+#endif
+#define DEBUG 0
+#endif /* DEBUG */
+#ifndef LACKS_STRING_H
+#include <string.h>      /* for memset etc */
+#endif  /* LACKS_STRING_H */
+#if USE_BUILTIN_FFS
+#ifndef LACKS_STRINGS_H
+#include <strings.h>     /* for ffs */
+#endif /* LACKS_STRINGS_H */
+#endif /* USE_BUILTIN_FFS */
+#if HAVE_MMAP
+#ifndef LACKS_SYS_MMAN_H
+#include <sys/mman.h>    /* for mmap */
+#endif /* LACKS_SYS_MMAN_H */
+#ifndef LACKS_FCNTL_H
+#include <fcntl.h>
+#endif /* LACKS_FCNTL_H */
+#endif /* HAVE_MMAP */
+#ifndef LACKS_UNISTD_H
+#include <unistd.h>     /* for sbrk, sysconf */
+#else /* LACKS_UNISTD_H */
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+extern void*     sbrk(ptrdiff_t);
+#endif /* FreeBSD etc */
+#endif /* LACKS_UNISTD_H */
+
+/* Declarations for locking */
+#if USE_LOCKS
+#ifndef WIN32
+#include <pthread.h>
+#if defined (__SVR4) && defined (__sun)  /* solaris */
+#include <thread.h>
+#endif /* solaris */
+#else
+#ifndef _M_AMD64
+/* These are already defined on AMD64 builds */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#ifndef __MINGW32__
+LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);
+LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
+#endif
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _M_AMD64 */
+#ifndef __MINGW32__
+#pragma intrinsic (_InterlockedCompareExchange)
+#pragma intrinsic (_InterlockedExchange)
+#else
+  /* --[ start GCC compatibility ]----------------------------------------------
+   * Compatibility <intrin_x86.h> header for GCC -- GCC equivalents of intrinsic
+   * Microsoft Visual C++ functions. Originally developed for the ReactOS
+   * (<http://www.reactos.org/>) and TinyKrnl (<http://www.tinykrnl.org/>)
+   * projects.
+   *
+   * Copyright (c) 2006 KJK::Hyperion <hackbunny@xxxxxxxxxxx>
+   *
+   * Permission is hereby granted, free of charge, to any person obtaining a
+   * copy of this software and associated documentation files (the "Software"),
+   * to deal in the Software without restriction, including without limitation
+   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+   * and/or sell copies of the Software, and to permit persons to whom the
+   * Software is furnished to do so, subject to the following conditions:
+   *
+   * The above copyright notice and this permission notice shall be included in
+   * all copies or substantial portions of the Software.
+   *
+   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+   * DEALINGS IN THE SOFTWARE.
+   */
+
+  /*** Atomic operations ***/
+  #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
+    #undef _ReadWriteBarrier
+    #define _ReadWriteBarrier() __sync_synchronize()
+  #else
+    static __inline__ __attribute__((always_inline)) long __sync_lock_test_and_set(volatile long * const Target, const long Value)
+    {
+      long res;
+      __asm__ __volatile__("xchg%z0 %2, %0" : "=g" (*(Target)), "=r" (res) : "1" (Value));
+      return res;
+    }
+    static void __inline__ __attribute__((always_inline)) _MemoryBarrier(void)
+    {
+      __asm__ __volatile__("" : : : "memory");
+    }
+    #define _ReadWriteBarrier() _MemoryBarrier()
+  #endif
+  /* BUGBUG: GCC only supports full barriers */
+  static __inline__ __attribute__((always_inline)) long _InterlockedExchange(volatile long * const Target, const long Value)
+  {
+    /* NOTE: __sync_lock_test_and_set would be an acquire barrier, so we force a full barrier */
+    _ReadWriteBarrier();
+    return __sync_lock_test_and_set(Target, Value);
+  }
+  /* --[ end GCC compatibility ]---------------------------------------------- */
+#endif
+#define interlockedcompareexchange _InterlockedCompareExchange
+#define interlockedexchange _InterlockedExchange
+#endif /* Win32 */
+#endif /* USE_LOCKS */
+
+/* Declarations for bit scanning on win32 */
+#if defined(_MSC_VER) && _MSC_VER>=1300
+#ifndef BitScanForward	/* Try to avoid pulling in WinNT.h */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+unsigned char _BitScanForward(unsigned long *index, unsigned long mask);
+unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#define BitScanForward _BitScanForward
+#define BitScanReverse _BitScanReverse
+#pragma intrinsic(_BitScanForward)
+#pragma intrinsic(_BitScanReverse)
+#endif /* BitScanForward */
+#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */
+
+#ifndef WIN32
+#ifndef malloc_getpagesize
+#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
+#    ifndef _SC_PAGE_SIZE
+#      define _SC_PAGE_SIZE _SC_PAGESIZE
+#    endif
+#  endif
+#  ifdef _SC_PAGE_SIZE
+#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+#  else
+#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+       extern size_t getpagesize();
+#      define malloc_getpagesize getpagesize()
+#    else
+#      ifdef WIN32 /* use supplied emulation of getpagesize */
+#        define malloc_getpagesize getpagesize()
+#      else
+#        ifndef LACKS_SYS_PARAM_H
+#          include <sys/param.h>
+#        endif
+#        ifdef EXEC_PAGESIZE
+#          define malloc_getpagesize EXEC_PAGESIZE
+#        else
+#          ifdef NBPG
+#            ifndef CLSIZE
+#              define malloc_getpagesize NBPG
+#            else
+#              define malloc_getpagesize (NBPG * CLSIZE)
+#            endif
+#          else
+#            ifdef NBPC
+#              define malloc_getpagesize NBPC
+#            else
+#              ifdef PAGESIZE
+#                define malloc_getpagesize PAGESIZE
+#              else /* just guess */
+#                define malloc_getpagesize ((size_t)4096U)
+#              endif
+#            endif
+#          endif
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+#endif
+
+
+
+/* ------------------- size_t and alignment properties -------------------- */
+
+/* The byte and bit size of a size_t */
+#define SIZE_T_SIZE         (sizeof(size_t))
+#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)
+
+/* Some constants coerced to size_t */
+/* Annoying but necessary to avoid errors on some platforms */
+#define SIZE_T_ZERO         ((size_t)0)
+#define SIZE_T_ONE          ((size_t)1)
+#define SIZE_T_TWO          ((size_t)2)
+#define SIZE_T_FOUR         ((size_t)4)
+#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)
+#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)
+#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
+#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)
+
+/* The bit mask value corresponding to MALLOC_ALIGNMENT */
+#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)
+
+/* True if address a has acceptable alignment */
+#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
+
+/* the number of bytes to offset an address to align it */
+#define align_offset(A)\
+ ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
+  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
+
+/* -------------------------- MMAP preliminaries ------------------------- */
+
+/*
+   If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
+   checks to fail so compiler optimizer can delete code rather than
+   using so many "#if"s.
+*/
+
+
+/* MORECORE and MMAP must return MFAIL on failure */
+#define MFAIL                ((void*)(MAX_SIZE_T))
+#define CMFAIL               ((char*)(MFAIL)) /* defined for convenience */
+
+#if HAVE_MMAP
+
+#ifndef WIN32
+#define MUNMAP_DEFAULT(a, s)  munmap((a), (s))
+#define MMAP_PROT            (PROT_READ|PROT_WRITE)
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS        MAP_ANON
+#endif /* MAP_ANON */
+#ifdef MAP_ANONYMOUS
+#define MMAP_FLAGS           (MAP_PRIVATE|MAP_ANONYMOUS)
+#define MMAP_DEFAULT(s)       mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
+#else /* MAP_ANONYMOUS */
+/*
+   Nearly all versions of mmap support MAP_ANONYMOUS, so the following
+   is unlikely to be needed, but is supplied just in case.
+*/
+#define MMAP_FLAGS           (MAP_PRIVATE)
+static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
+#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
+	   (dev_zero_fd = open("/dev/zero", O_RDWR), \
+	    mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
+	    mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
+#endif /* MAP_ANONYMOUS */
+
+#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
+
+#else /* WIN32 */
+
+/* Win32 MMAP via VirtualAlloc */
+static FORCEINLINE void* win32mmap(size_t size) {
+  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
+  return (ptr != 0)? ptr: MFAIL;
+}
+
+/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
+static FORCEINLINE void* win32direct_mmap(size_t size) {
+  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
+			   PAGE_READWRITE);
+  return (ptr != 0)? ptr: MFAIL;
+}
+
+/* This function supports releasing coalesced segments */
+static FORCEINLINE int win32munmap(void* ptr, size_t size) {
+  MEMORY_BASIC_INFORMATION minfo;
+  char* cptr = (char*)ptr;
+  while (size) {
+    if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
+      return -1;
+    if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
+	minfo.State != MEM_COMMIT || minfo.RegionSize > size)
+      return -1;
+    if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
+      return -1;
+    cptr += minfo.RegionSize;
+    size -= minfo.RegionSize;
+  }
+  return 0;
+}
+
+#define MMAP_DEFAULT(s)             win32mmap(s)
+#define MUNMAP_DEFAULT(a, s)        win32munmap((a), (s))
+#define DIRECT_MMAP_DEFAULT(s)      win32direct_mmap(s)
+#endif /* WIN32 */
+#endif /* HAVE_MMAP */
+
+#if HAVE_MREMAP
+#ifndef WIN32
+#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
+#endif /* WIN32 */
+#endif /* HAVE_MREMAP */
+
+
+/**
+ * Define CALL_MORECORE
+ */
+#if HAVE_MORECORE
+    #ifdef MORECORE
+	#define CALL_MORECORE(S)    MORECORE(S)
+    #else  /* MORECORE */
+	#define CALL_MORECORE(S)    MORECORE_DEFAULT(S)
+    #endif /* MORECORE */
+#else  /* HAVE_MORECORE */
+    #define CALL_MORECORE(S)        MFAIL
+#endif /* HAVE_MORECORE */
+
+/**
+ * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP
+ */
+#if HAVE_MMAP
+    #define IS_MMAPPED_BIT          (SIZE_T_ONE)
+    #define USE_MMAP_BIT            (SIZE_T_ONE)
+
+    #ifdef MMAP
+	#define CALL_MMAP(s)        MMAP(s)
+    #else /* MMAP */
+	#define CALL_MMAP(s)        MMAP_DEFAULT(s)
+    #endif /* MMAP */
+    #ifdef MUNMAP
+	#define CALL_MUNMAP(a, s)   MUNMAP((a), (s))
+    #else /* MUNMAP */
+	#define CALL_MUNMAP(a, s)   MUNMAP_DEFAULT((a), (s))
+    #endif /* MUNMAP */
+    #ifdef DIRECT_MMAP
+	#define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
+    #else /* DIRECT_MMAP */
+	#define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)
+    #endif /* DIRECT_MMAP */
+#else  /* HAVE_MMAP */
+    #define IS_MMAPPED_BIT          (SIZE_T_ZERO)
+    #define USE_MMAP_BIT            (SIZE_T_ZERO)
+
+    #define MMAP(s)                 MFAIL
+    #define MUNMAP(a, s)            (-1)
+    #define DIRECT_MMAP(s)          MFAIL
+    #define CALL_DIRECT_MMAP(s)     DIRECT_MMAP(s)
+    #define CALL_MMAP(s)            MMAP(s)
+    #define CALL_MUNMAP(a, s)       MUNMAP((a), (s))
+#endif /* HAVE_MMAP */
+
+/**
+ * Define CALL_MREMAP
+ */
+#if HAVE_MMAP && HAVE_MREMAP
+    #ifdef MREMAP
+	#define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
+    #else /* MREMAP */
+	#define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
+    #endif /* MREMAP */
+#else  /* HAVE_MMAP && HAVE_MREMAP */
+    #define CALL_MREMAP(addr, osz, nsz, mv)     MFAIL
+#endif /* HAVE_MMAP && HAVE_MREMAP */
+
+/* mstate bit set if contiguous morecore disabled or failed */
+#define USE_NONCONTIGUOUS_BIT (4U)
+
+/* segment bit set in create_mspace_with_base */
+#define EXTERN_BIT            (8U)
+
+
+/* --------------------------- Lock preliminaries ------------------------ */
+
+/*
+  When locks are defined, there is one global lock, plus
+  one per-mspace lock.
+
+  The global lock_ensures that mparams.magic and other unique
+  mparams values are initialized only once. It also protects
+  sequences of calls to MORECORE.  In many cases sys_alloc requires
+  two calls, that should not be interleaved with calls by other
+  threads.  This does not protect against direct calls to MORECORE
+  by other threads not using this lock, so there is still code to
+  cope the best we can on interference.
+
+  Per-mspace locks surround calls to malloc, free, etc.  To enable use
+  in layered extensions, per-mspace locks are reentrant.
+
+  Because lock-protected regions generally have bounded times, it is
+  OK to use the supplied simple spinlocks in the custom versions for
+  x86.
+
+  If USE_LOCKS is > 1, the definitions of lock routines here are
+  bypassed, in which case you will need to define at least
+  INITIAL_LOCK, ACQUIRE_LOCK, RELEASE_LOCK and possibly TRY_LOCK
+  (which is not used in this malloc, but commonly needed in
+  extensions.)
+*/
+
+#if USE_LOCKS == 1
+
+#if USE_SPIN_LOCKS
+#ifndef WIN32
+
+/* Custom pthread-style spin locks on x86 and x64 for gcc */
+struct pthread_mlock_t {
+  volatile unsigned int l;
+  volatile unsigned int c;
+  volatile pthread_t threadid;
+};
+#define MLOCK_T struct        pthread_mlock_t
+#define CURRENT_THREAD        pthread_self()
+#define INITIAL_LOCK(sl)      (memset(sl, 0, sizeof(MLOCK_T)), 0)
+#define ACQUIRE_LOCK(sl)      pthread_acquire_lock(sl)
+#define RELEASE_LOCK(sl)      pthread_release_lock(sl)
+#define TRY_LOCK(sl)          pthread_try_lock(sl)
+#define SPINS_PER_YIELD       63
+
+static MLOCK_T malloc_global_mutex = { 0, 0, 0};
+
+static FORCEINLINE int pthread_acquire_lock (MLOCK_T *sl) {
+  int spins = 0;
+  volatile unsigned int* lp = &sl->l;
+  for (;;) {
+    if (*lp != 0) {
+      if (sl->threadid == CURRENT_THREAD) {
+	++sl->c;
+	return 0;
+      }
+    }
+    else {
+      /* place args to cmpxchgl in locals to evade oddities in some gccs */
+      int cmp = 0;
+      int val = 1;
+      int ret;
+      __asm__ __volatile__  ("lock; cmpxchgl %1, %2"
+			     : "=a" (ret)
+			     : "r" (val), "m" (*(lp)), "0"(cmp)
+			     : "memory", "cc");
+      if (!ret) {
+	assert(!sl->threadid);
+	sl->c = 1;
+	sl->threadid = CURRENT_THREAD;
+	return 0;
+      }
+      if ((++spins & SPINS_PER_YIELD) == 0) {
+#if defined (__SVR4) && defined (__sun) /* solaris */
+	thr_yield();
+#else
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+	sched_yield();
+#else  /* no-op yield on unknown systems */
+	;
+#endif /* __linux__ || __FreeBSD__ || __APPLE__ */
+#endif /* solaris */
+      }
+    }
+  }
+}
+
+static FORCEINLINE void pthread_release_lock (MLOCK_T *sl) {
+  assert(sl->l != 0);
+  assert(sl->threadid == CURRENT_THREAD);
+  if (--sl->c == 0) {
+    volatile unsigned int* lp = &sl->l;
+    int prev = 0;
+    int ret;
+    sl->threadid = 0;
+    __asm__ __volatile__ ("lock; xchgl %0, %1"
+			  : "=r" (ret)
+			  : "m" (*(lp)), "0"(prev)
+			  : "memory");
+  }
+}
+
+static FORCEINLINE int pthread_try_lock (MLOCK_T *sl) {
+  volatile unsigned int* lp = &sl->l;
+  if (*lp != 0) {
+      if (sl->threadid == CURRENT_THREAD) {
+	++sl->c;
+	return 1;
+      }
+  }
+  else {
+    int cmp = 0;
+    int val = 1;
+    int ret;
+    __asm__ __volatile__  ("lock; cmpxchgl %1, %2"
+			   : "=a" (ret)
+			   : "r" (val), "m" (*(lp)), "0"(cmp)
+			   : "memory", "cc");
+    if (!ret) {
+      assert(!sl->threadid);
+      sl->c = 1;
+      sl->threadid = CURRENT_THREAD;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+
+#else /* WIN32 */
+/* Custom win32-style spin locks on x86 and x64 for MSC */
+struct win32_mlock_t
+{
+  volatile long l;
+  volatile unsigned int c;
+  volatile long threadid;
+};
+
+static inline int return_0(int i) { return 0; }
+#define MLOCK_T               struct win32_mlock_t
+#define CURRENT_THREAD        win32_getcurrentthreadid()
+#define INITIAL_LOCK(sl)      (memset(sl, 0, sizeof(MLOCK_T)), return_0(0))
+#define ACQUIRE_LOCK(sl)      win32_acquire_lock(sl)
+#define RELEASE_LOCK(sl)      win32_release_lock(sl)
+#define TRY_LOCK(sl)          win32_try_lock(sl)
+#define SPINS_PER_YIELD       63
+
+static MLOCK_T malloc_global_mutex = { 0, 0, 0};
+
+static FORCEINLINE long win32_getcurrentthreadid(void) {
+#ifdef _MSC_VER
+#if defined(_M_IX86)
+  long *threadstruct=(long *)__readfsdword(0x18);
+  long threadid=threadstruct[0x24/sizeof(long)];
+  return threadid;
+#elif defined(_M_X64)
+  /* todo */
+  return GetCurrentThreadId();
+#else
+  return GetCurrentThreadId();
+#endif
+#else
+  return GetCurrentThreadId();
+#endif
+}
+
+static FORCEINLINE int win32_acquire_lock (MLOCK_T *sl) {
+  int spins = 0;
+  for (;;) {
+    if (sl->l != 0) {
+      if (sl->threadid == CURRENT_THREAD) {
+	++sl->c;
+	return 0;
+      }
+    }
+    else {
+      if (!interlockedexchange(&sl->l, 1)) {
+	assert(!sl->threadid);
+		sl->c=CURRENT_THREAD;
+	sl->threadid = CURRENT_THREAD;
+	sl->c = 1;
+	return 0;
+      }
+    }
+    if ((++spins & SPINS_PER_YIELD) == 0)
+      SleepEx(0, FALSE);
+  }
+}
+
+static FORCEINLINE void win32_release_lock (MLOCK_T *sl) {
+  assert(sl->threadid == CURRENT_THREAD);
+  assert(sl->l != 0);
+  if (--sl->c == 0) {
+    sl->threadid = 0;
+    interlockedexchange (&sl->l, 0);
+  }
+}
+
+static FORCEINLINE int win32_try_lock (MLOCK_T *sl) {
+  if(sl->l != 0) {
+      if (sl->threadid == CURRENT_THREAD) {
+	++sl->c;
+	return 1;
+      }
+  }
+  else {
+    if (!interlockedexchange(&sl->l, 1)){
+      assert(!sl->threadid);
+      sl->threadid = CURRENT_THREAD;
+      sl->c = 1;
+      return 1;
+    }
+  }
+  return 0;
+}
+
+#endif /* WIN32 */
+#else /* USE_SPIN_LOCKS */
+
+#ifndef WIN32
+/* pthreads-based locks */
+
+#define MLOCK_T               pthread_mutex_t
+#define CURRENT_THREAD        pthread_self()
+#define INITIAL_LOCK(sl)      pthread_init_lock(sl)
+#define ACQUIRE_LOCK(sl)      pthread_mutex_lock(sl)
+#define RELEASE_LOCK(sl)      pthread_mutex_unlock(sl)
+#define TRY_LOCK(sl)          (!pthread_mutex_trylock(sl))
+
+static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Cope with old-style linux recursive lock initialization by adding */
+/* skipped internal declaration from pthread.h */
+#ifdef linux
+#ifndef PTHREAD_MUTEX_RECURSIVE
+extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,
+					   int __kind));
+#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)
+#endif
+#endif
+
+static int pthread_init_lock (MLOCK_T *sl) {
+  pthread_mutexattr_t attr;
+  if (pthread_mutexattr_init(&attr)) return 1;
+  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;
+  if (pthread_mutex_init(sl, &attr)) return 1;
+  if (pthread_mutexattr_destroy(&attr)) return 1;
+  return 0;
+}
+
+#else /* WIN32 */
+/* Win32 critical sections */
+#define MLOCK_T               CRITICAL_SECTION
+#define CURRENT_THREAD        GetCurrentThreadId()
+#define INITIAL_LOCK(s)       (!InitializeCriticalSectionAndSpinCount((s), 0x80000000|4000))
+#define ACQUIRE_LOCK(s)       (EnterCriticalSection(s), 0)
+#define RELEASE_LOCK(s)       LeaveCriticalSection(s)
+#define TRY_LOCK(s)           TryEnterCriticalSection(s)
+#define NEED_GLOBAL_LOCK_INIT
+
+static MLOCK_T malloc_global_mutex;
+static volatile long malloc_global_mutex_status;
+
+/* Use spin loop to initialize global lock */
+static void init_malloc_global_mutex() {
+  for (;;) {
+    long stat = malloc_global_mutex_status;
+    if (stat > 0)
+      return;
+    /* transition to < 0 while initializing, then to > 0) */
+    if (stat == 0 &&
+	interlockedcompareexchange(&malloc_global_mutex_status, -1, 0) == 0) {
+      InitializeCriticalSection(&malloc_global_mutex);
+      interlockedexchange(&malloc_global_mutex_status,1);
+      return;
+    }
+    SleepEx(0, FALSE);
+  }
+}
+
+#endif /* WIN32 */
+#endif /* USE_SPIN_LOCKS */
+#endif /* USE_LOCKS == 1 */
+
+/* -----------------------  User-defined locks ------------------------ */
+
+#if USE_LOCKS > 1
+/* Define your own lock implementation here */
+/* #define INITIAL_LOCK(sl)  ... */
+/* #define ACQUIRE_LOCK(sl)  ... */
+/* #define RELEASE_LOCK(sl)  ... */
+/* #define TRY_LOCK(sl) ... */
+/* static MLOCK_T malloc_global_mutex = ... */
+#endif /* USE_LOCKS > 1 */
+
+/* -----------------------  Lock-based state ------------------------ */
+
+#if USE_LOCKS
+#define USE_LOCK_BIT               (2U)
+#else  /* USE_LOCKS */
+#define USE_LOCK_BIT               (0U)
+#define INITIAL_LOCK(l)
+#endif /* USE_LOCKS */
+
+#if USE_LOCKS
+#define ACQUIRE_MALLOC_GLOBAL_LOCK()  ACQUIRE_LOCK(&malloc_global_mutex);
+#define RELEASE_MALLOC_GLOBAL_LOCK()  RELEASE_LOCK(&malloc_global_mutex);
+#else  /* USE_LOCKS */
+#define ACQUIRE_MALLOC_GLOBAL_LOCK()
+#define RELEASE_MALLOC_GLOBAL_LOCK()
+#endif /* USE_LOCKS */
+
+
+/* -----------------------  Chunk representations ------------------------ */
+
+/*
+  (The following includes lightly edited explanations by Colin Plumb.)
+
+  The malloc_chunk declaration below is misleading (but accurate and
+  necessary).  It declares a "view" into memory allowing access to
+  necessary fields at known offsets from a given base.
+
+  Chunks of memory are maintained using a `boundary tag' method as
+  originally described by Knuth.  (See the paper by Paul Wilson
+  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
+  techniques.)  Sizes of free chunks are stored both in the front of
+  each chunk and at the end.  This makes consolidating fragmented
+  chunks into bigger chunks fast.  The head fields also hold bits
+  representing whether chunks are free or in use.
+
+  Here are some pictures to make it clearer.  They are "exploded" to
+  show that the state of a chunk can be thought of as extending from
+  the high 31 bits of the head field of its header through the
+  prev_foot and PINUSE_BIT bit of the following chunk header.
+
+  A chunk that's in use looks like:
+
+   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	   | Size of previous chunk (if P = 0)                             |
+	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+	 | Size of this chunk                                         1| +-+
+   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	 |                                                               |
+	 +-                                                             -+
+	 |                                                               |
+	 +-                                                             -+
+	 |                                                               :
+	 +-      size - sizeof(size_t) available payload bytes          -+
+	 :                                                               |
+ chunk-> +-                                                             -+
+	 |                                                               |
+	 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
+       | Size of next chunk (may or may not be in use)               | +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+    And if it's free, it looks like this:
+
+   chunk-> +-                                                             -+
+	   | User payload (must be in use, or we would have merged!)       |
+	   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+	 | Size of this chunk                                         0| +-+
+   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	 | Next pointer                                                  |
+	 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	 | Prev pointer                                                  |
+	 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	 |                                                               :
+	 +-      size - sizeof(struct chunk) unused bytes               -+
+	 :                                                               |
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	 | Size of this chunk                                            |
+	 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
+       | Size of next chunk (must be in use, or we would have merged)| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+       |                                                               :
+       +- User payload                                                -+
+       :                                                               |
+       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+								     |0|
+								     +-+
+  Note that since we always merge adjacent free chunks, the chunks
+  adjacent to a free chunk must be in use.
+
+  Given a pointer to a chunk (which can be derived trivially from the
+  payload pointer) we can, in O(1) time, find out whether the adjacent
+  chunks are free, and if so, unlink them from the lists that they
+  are on and merge them with the current chunk.
+
+  Chunks always begin on even word boundaries, so the mem portion
+  (which is returned to the user) is also on an even word boundary, and
+  thus at least double-word aligned.
+
+  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
+  chunk size (which is always a multiple of two words), is an in-use
+  bit for the *previous* chunk.  If that bit is *clear*, then the
+  word before the current chunk size contains the previous chunk
+  size, and can be used to find the front of the previous chunk.
+  The very first chunk allocated always has this bit set, preventing
+  access to non-existent (or non-owned) memory. If pinuse is set for
+  any given chunk, then you CANNOT determine the size of the
+  previous chunk, and might even get a memory addressing fault when
+  trying to do so.
+
+  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
+  the chunk size redundantly records whether the current chunk is
+  inuse. This redundancy enables usage checks within free and realloc,
+  and reduces indirection when freeing and consolidating chunks.
+
+  Each freshly allocated chunk must have both cinuse and pinuse set.
+  That is, each allocated chunk borders either a previously allocated
+  and still in-use chunk, or the base of its memory arena. This is
+  ensured by making all allocations from the `lowest' part of any
+  found chunk.  Further, no free chunk physically borders another one,
+  so each free chunk is known to be preceded and followed by either
+  inuse chunks or the ends of memory.
+
+  Note that the `foot' of the current chunk is actually represented
+  as the prev_foot of the NEXT chunk. This makes it easier to
+  deal with alignments etc but can be very confusing when trying
+  to extend or adapt this code.
+
+  The exceptions to all this are
+
+     1. The special chunk `top' is the top-most available chunk (i.e.,
+	the one bordering the end of available memory). It is treated
+	specially.  Top is never included in any bin, is used only if
+	no other chunk is available, and is released back to the
+	system if it is very large (see M_TRIM_THRESHOLD).  In effect,
+	the top chunk is treated as larger (and thus less well
+	fitting) than any other available chunk.  The top chunk
+	doesn't update its trailing size field since there is no next
+	contiguous chunk that would have to index off it. However,
+	space is still allocated for it (TOP_FOOT_SIZE) to enable
+	separation or merging when space is extended.
+
+     3. Chunks allocated via mmap, which have the lowest-order bit
+	(IS_MMAPPED_BIT) set in their prev_foot fields, and do not set
+	PINUSE_BIT in their head fields.  Because they are allocated
+	one-by-one, each must carry its own prev_foot field, which is
+	also used to hold the offset this chunk has within its mmapped
+	region, which is needed to preserve alignment. Each mmapped
+	chunk is trailed by the first two fields of a fake next-chunk
+	for sake of usage checks.
+
+*/
+
+struct malloc_chunk {
+  size_t               prev_foot;  /* Size of previous chunk (if free).  */
+  size_t               head;       /* Size and inuse bits. */
+  struct malloc_chunk* fd;         /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk  mchunk;
+typedef struct malloc_chunk* mchunkptr;
+typedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */
+typedef unsigned int bindex_t;         /* Described below */
+typedef unsigned int binmap_t;         /* Described below */
+typedef unsigned int flag_t;           /* The type of various bit flag sets */
+
+/* ------------------- Chunks sizes and alignments ----------------------- */
+
+#define MCHUNK_SIZE         (sizeof(mchunk))
+
+#if FOOTERS
+#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)
+#else /* FOOTERS */
+#define CHUNK_OVERHEAD      (SIZE_T_SIZE)
+#endif /* FOOTERS */
+
+/* MMapped chunks need a second word of overhead ... */
+#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
+/* ... and additional padding for fake next-chunk at foot */
+#define MMAP_FOOT_PAD       (FOUR_SIZE_T_SIZES)
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+#define MIN_CHUNK_SIZE\
+  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* conversion from malloc headers to user pointers, and back */
+#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))
+#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
+/* chunk associated with aligned address A */
+#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))
+
+/* Bounds on request (not chunk) sizes. */
+#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)
+#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
+
+/* pad request bytes into a usable size */
+#define pad_request(req) \
+   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* pad request, checking for minimum (but not maximum) */
+#define request2size(req) \
+  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
+
+
+/* ------------------ Operations on head and foot fields ----------------- */
+
+/*
+  The head field of a chunk is or'ed with PINUSE_BIT when previous
+  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
+  use. If the chunk was obtained with mmap, the prev_foot field has
+  IS_MMAPPED_BIT set, otherwise holding the offset of the base of the
+  mmapped region to the base of the chunk.
+
+  FLAG4_BIT is not used by this malloc, but might be useful in extensions.
+*/
+
+#define PINUSE_BIT          (SIZE_T_ONE)
+#define CINUSE_BIT          (SIZE_T_TWO)
+#define FLAG4_BIT           (SIZE_T_FOUR)
+#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)
+#define FLAG_BITS           (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)
+
+/* Head value for fenceposts */
+#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)
+
+/* extraction of fields from head words */
+#define cinuse(p)           ((p)->head & CINUSE_BIT)
+#define pinuse(p)           ((p)->head & PINUSE_BIT)
+#define chunksize(p)        ((p)->head & ~(FLAG_BITS))
+
+#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)
+#define clear_cinuse(p)     ((p)->head &= ~CINUSE_BIT)
+
+/* Treat space at ptr +/- offset as a chunk */
+#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
+#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
+
+/* Ptr to next or previous physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
+
+/* extract next chunk's pinuse bit */
+#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)
+
+/* Get/set size at footer */
+#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)
+#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
+
+/* Set size, pinuse bit, and foot */
+#define set_size_and_pinuse_of_free_chunk(p, s)\
+  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
+
+/* Set size, pinuse bit, foot, and clear next pinuse */
+#define set_free_with_pinuse(p, s, n)\
+  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
+
+#define is_mmapped(p)\
+  (!((p)->head & PINUSE_BIT) && ((p)->prev_foot & IS_MMAPPED_BIT))
+
+/* Get the internal overhead associated with chunk p */
+#define overhead_for(p)\
+ (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
+
+/* Return true if malloced space is not necessarily cleared */
+#if MMAP_CLEARS
+#define calloc_must_clear(p) (!is_mmapped(p))
+#else /* MMAP_CLEARS */
+#define calloc_must_clear(p) (1)
+#endif /* MMAP_CLEARS */
+
+/* ---------------------- Overlaid data structures ----------------------- */
+
+/*
+  When chunks are not in use, they are treated as nodes of either
+  lists or trees.
+
+  "Small"  chunks are stored in circular doubly-linked lists, and look
+  like this:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of previous chunk                            |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Forward pointer to next chunk in list             |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Back pointer to previous chunk in list            |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Unused space (may be 0 bytes long)                .
+	    .                                                               .
+	    .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Larger chunks are kept in a form of bitwise digital trees (aka
+  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for
+  free chunks greater than 256 bytes, their size doesn't impose any
+  constraints on user chunk sizes.  Each node looks like:
+
+    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Size of previous chunk                            |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `head:' |             Size of chunk, in bytes                         |P|
+      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Forward pointer to next chunk of same size        |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Back pointer to previous chunk of same size       |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Pointer to left child (child[0])                  |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Pointer to right child (child[1])                 |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Pointer to parent                                 |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             bin index of this chunk                           |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+	    |             Unused space                                      .
+	    .                                                               |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+    `foot:' |             Size of chunk, in bytes                           |
+	    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks
+  of the same size are arranged in a circularly-linked list, with only
+  the oldest chunk (the next to be used, in our FIFO ordering)
+  actually in the tree.  (Tree members are distinguished by a non-null
+  parent pointer.)  If a chunk with the same size as an existing node
+  is inserted, it is linked off the existing node using pointers that
+  work in the same way as fd/bk pointers of small chunks.
+
+  Each tree contains a power of 2 sized range of chunk sizes (the
+  smallest is 0x100 <= x < 0x180), which is divided in half at each
+  tree level, with the chunks in the smaller half of the range (0x100
+  <= x < 0x140 for the top nose) in the left subtree and the larger
+  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,
+  done by inspecting individual bits.
+
+  Using these rules, each node's left subtree contains all smaller
+  sizes than its right subtree.  However, the node at the root of each
+  subtree has no particular ordering relationship to either.  (The
+  dividing line between the subtree sizes is based on trie relation.)
+  If we remove the last chunk of a given size from the interior of the
+  tree, we need to replace it with a leaf node.  The tree ordering
+  rules permit a node to be replaced by any leaf below it.
+
+  The smallest chunk in a tree (a common operation in a best-fit
+  allocator) can be found by walking a path to the leftmost leaf in
+  the tree.  Unlike a usual binary tree, where we follow left child
+  pointers until we reach a null, here we follow the right child
+  pointer any time the left one is null, until we reach a leaf with
+  both child pointers null. The smallest chunk in the tree will be
+  somewhere along that path.
+
+  The worst case number of steps to add, find, or remove a node is
+  bounded by the number of bits differentiating chunks within
+  bins. Under current bin calculations, this ranges from 6 up to 21
+  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
+  is of course much better.
+*/
+
+struct malloc_tree_chunk {
+  /* The first four fields must be compatible with malloc_chunk */
+  size_t                    prev_foot;
+  size_t                    head;
+  struct malloc_tree_chunk* fd;
+  struct malloc_tree_chunk* bk;
+
+  struct malloc_tree_chunk* child[2];
+  struct malloc_tree_chunk* parent;
+  bindex_t                  index;
+};
+
+typedef struct malloc_tree_chunk  tchunk;
+typedef struct malloc_tree_chunk* tchunkptr;
+typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
+
+/* A little helper macro for trees */
+#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
+
+/* ----------------------------- Segments -------------------------------- */
+
+/*
+  Each malloc space may include non-contiguous segments, held in a
+  list headed by an embedded malloc_segment record representing the
+  top-most space. Segments also include flags holding properties of
+  the space. Large chunks that are directly allocated by mmap are not
+  included in this list. They are instead independently created and
+  destroyed without otherwise keeping track of them.
+
+  Segment management mainly comes into play for spaces allocated by
+  MMAP.  Any call to MMAP might or might not return memory that is
+  adjacent to an existing segment.  MORECORE normally contiguously
+  extends the current space, so this space is almost always adjacent,
+  which is simpler and faster to deal with. (This is why MORECORE is
+  used preferentially to MMAP when both are available -- see
+  sys_alloc.)  When allocating using MMAP, we don't use any of the
+  hinting mechanisms (inconsistently) supported in various
+  implementations of unix mmap, or distinguish reserving from
+  committing memory. Instead, we just ask for space, and exploit
+  contiguity when we get it.  It is probably possible to do
+  better than this on some systems, but no general scheme seems
+  to be significantly better.
+
+  Management entails a simpler variant of the consolidation scheme
+  used for chunks to reduce fragmentation -- new adjacent memory is
+  normally prepended or appended to an existing segment. However,
+  there are limitations compared to chunk consolidation that mostly
+  reflect the fact that segment processing is relatively infrequent
+  (occurring only when getting memory from system) and that we
+  don't expect to have huge numbers of segments:
+
+  * Segments are not indexed, so traversal requires linear scans.  (It
+    would be possible to index these, but is not worth the extra
+    overhead and complexity for most programs on most platforms.)
+  * New segments are only appended to old ones when holding top-most
+    memory; if they cannot be prepended to others, they are held in
+    different segments.
+
+  Except for the top-most segment of an mstate, each segment record
+  is kept at the tail of its segment. Segments are added by pushing
+  segment records onto the list headed by &mstate.seg for the
+  containing mstate.
+
+  Segment flags control allocation/merge/deallocation policies:
+  * If EXTERN_BIT set, then we did not allocate this segment,
+    and so should not try to deallocate or merge with others.
+    (This currently holds only for the initial segment passed
+    into create_mspace_with_base.)
+  * If IS_MMAPPED_BIT set, the segment may be merged with
+    other surrounding mmapped segments and trimmed/de-allocated
+    using munmap.
+  * If neither bit is set, then the segment was obtained using
+    MORECORE so can be merged with surrounding MORECORE'd segments
+    and deallocated/trimmed using MORECORE with negative arguments.
+*/
+
+struct malloc_segment {
+  char*        base;             /* base address */
+  size_t       size;             /* allocated size */
+  struct malloc_segment* next;   /* ptr to next segment */
+  flag_t       sflags;           /* mmap and extern flag */
+};
+
+#define is_mmapped_segment(S)  ((S)->sflags & IS_MMAPPED_BIT)
+#define is_extern_segment(S)   ((S)->sflags & EXTERN_BIT)
+
+typedef struct malloc_segment  msegment;
+typedef struct malloc_segment* msegmentptr;
+
+/* ---------------------------- malloc_state ----------------------------- */
+
+/*
+   A malloc_state holds all of the bookkeeping for a space.
+   The main fields are:
+
+  Top
+    The topmost chunk of the currently active segment. Its size is
+    cached in topsize.  The actual size of topmost space is
+    topsize+TOP_FOOT_SIZE, which includes space reserved for adding
+    fenceposts and segment records if necessary when getting more
+    space from the system.  The size at which to autotrim top is
+    cached from mparams in trim_check, except that it is disabled if
+    an autotrim fails.
+
+  Designated victim (dv)
+    This is the preferred chunk for servicing small requests that
+    don't have exact fits.  It is normally the chunk split off most
+    recently to service another small request.  Its size is cached in
+    dvsize. The link fields of this chunk are not maintained since it
+    is not kept in a bin.
+
+  SmallBins
+    An array of bin headers for free chunks.  These bins hold chunks
+    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
+    chunks of all the same size, spaced 8 bytes apart.  To simplify
+    use in double-linked lists, each bin header acts as a malloc_chunk
+    pointing to the real first node, if it exists (else pointing to
+    itself).  This avoids special-casing for headers.  But to avoid
+    waste, we allocate only the fd/bk pointers of bins, and then use
+    repositioning tricks to treat these as the fields of a chunk.
+
+  TreeBins
+    Treebins are pointers to the roots of trees holding a range of
+    sizes. There are 2 equally spaced treebins for each power of two
+    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
+    larger.
+
+  Bin maps
+    There is one bit map for small bins ("smallmap") and one for
+    treebins ("treemap).  Each bin sets its bit when non-empty, and
+    clears the bit when empty.  Bit operations are then used to avoid
+    bin-by-bin searching -- nearly all "search" is done without ever
+    looking at bins that won't be selected.  The bit maps
+    conservatively use 32 bits per map word, even if on 64bit system.
+    For a good description of some of the bit-based techniques used
+    here, see Henry S. Warren Jr's book "Hacker's Delight" (and
+    supplement at http://hackersdelight.org/). Many of these are
+    intended to reduce the branchiness of paths through malloc etc, as
+    well as to reduce the number of memory locations read or written.
+
+  Segments
+    A list of segments headed by an embedded malloc_segment record
+    representing the initial space.
+
+  Address check support
+    The least_addr field is the least address ever obtained from
+    MORECORE or MMAP. Attempted frees and reallocs of any address less
+    than this are trapped (unless INSECURE is defined).
+
+  Magic tag
+    A cross-check field that should always hold same value as mparams.magic.
+
+  Flags
+    Bits recording whether to use MMAP, locks, or contiguous MORECORE
+
+  Statistics
+    Each space keeps track of current and maximum system memory
+    obtained via MORECORE or MMAP.
+
+  Trim support
+    Fields holding the amount of unused topmost memory that should trigger
+    timing, and a counter to force periodic scanning to release unused
+    non-topmost segments.
+
+  Locking
+    If USE_LOCKS is defined, the "mutex" lock is acquired and released
+    around every public call using this mspace.
+
+  Extension support
+    A void* pointer and a size_t field that can be used to help implement
+    extensions to this malloc.
+*/
+
+/* Bin types, widths and sizes */
+#define NSMALLBINS        (32U)
+#define NTREEBINS         (32U)
+#define SMALLBIN_SHIFT    (3U)
+#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)
+#define TREEBIN_SHIFT     (8U)
+#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)
+#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)
+#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
+
+struct malloc_state {
+  binmap_t   smallmap;
+  binmap_t   treemap;
+  size_t     dvsize;
+  size_t     topsize;
+  char*      least_addr;
+  mchunkptr  dv;
+  mchunkptr  top;
+  size_t     trim_check;
+  size_t     release_checks;
+  size_t     magic;
+  mchunkptr  smallbins[(NSMALLBINS+1)*2];
+  tbinptr    treebins[NTREEBINS];
+  size_t     footprint;
+  size_t     max_footprint;
+  flag_t     mflags;
+#if USE_LOCKS
+  MLOCK_T    mutex;     /* locate lock among fields that rarely change */
+#endif /* USE_LOCKS */
+  msegment   seg;
+  void*      extp;      /* Unused but available for extensions */
+  size_t     exts;
+};
+
+typedef struct malloc_state*    mstate;
+
+/* ------------- Global malloc_state and malloc_params ------------------- */
+
+/*
+  malloc_params holds global properties, including those that can be
+  dynamically set using mallopt. There is a single instance, mparams,
+  initialized in init_mparams. Note that the non-zeroness of "magic"
+  also serves as an initialization flag.
+*/
+
+struct malloc_params {
+  volatile size_t magic;
+  size_t page_size;
+  size_t granularity;
+  size_t mmap_threshold;
+  size_t trim_threshold;
+  flag_t default_mflags;
+};
+
+static struct malloc_params mparams;
+
+/* Ensure mparams initialized */
+#define ensure_initialization() ((void)(mparams.magic != 0 || init_mparams()))
+
+#if !ONLY_MSPACES
+
+/* The global malloc_state used for all non-"mspace" calls */
+static struct malloc_state _gm_;
+#define gm                 (&_gm_)
+#define is_global(M)       ((M) == &_gm_)
+
+#endif /* !ONLY_MSPACES */
+
+#define is_initialized(M)  ((M)->top != 0)
+
+/* -------------------------- system alloc setup ------------------------- */
+
+/* Operations on mflags */
+
+#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)
+#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)
+#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)
+
+#define use_mmap(M)           ((M)->mflags &   USE_MMAP_BIT)
+#define enable_mmap(M)        ((M)->mflags |=  USE_MMAP_BIT)
+#define disable_mmap(M)       ((M)->mflags &= ~USE_MMAP_BIT)
+
+#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)
+#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)
+
+#define set_lock(M,L)\
+ ((M)->mflags = (L)?\
+  ((M)->mflags | USE_LOCK_BIT) :\
+  ((M)->mflags & ~USE_LOCK_BIT))
+
+/* page-align a size */
+#define page_align(S)\
+ (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
+
+/* granularity-align a size */
+#define granularity_align(S)\
+  (((S) + (mparams.granularity - SIZE_T_ONE))\
+   & ~(mparams.granularity - SIZE_T_ONE))
+
+
+/* For mmap, use granularity alignment on windows, else page-align */
+#ifdef WIN32
+#define mmap_align(S) granularity_align(S)
+#else
+#define mmap_align(S) page_align(S)
+#endif
+
+/* For sys_alloc, enough padding to ensure can malloc request on success */
+#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)
+
+#define is_page_aligned(S)\
+   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
+#define is_granularity_aligned(S)\
+   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
+
+/*  True if segment S holds address A */
+#define segment_holds(S, A)\
+  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
+
+/* Return segment holding given address */
+static msegmentptr segment_holding(mstate m, char* addr) {
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if (addr >= sp->base && addr < sp->base + sp->size)
+      return sp;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+
+/* Return true if segment contains a segment link */
+static int has_segment_link(mstate m, msegmentptr ss) {
+  msegmentptr sp = &m->seg;
+  for (;;) {
+    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
+      return 1;
+    if ((sp = sp->next) == 0)
+      return 0;
+  }
+}
+
+#ifndef MORECORE_CANNOT_TRIM
+#define should_trim(M,s)  ((s) > (M)->trim_check)
+#else  /* MORECORE_CANNOT_TRIM */
+#define should_trim(M,s)  (0)
+#endif /* MORECORE_CANNOT_TRIM */
+
+/*
+  TOP_FOOT_SIZE is padding at the end of a segment, including space
+  that may be needed to place segment records and fenceposts when new
+  noncontiguous segments are added.
+*/
+#define TOP_FOOT_SIZE\
+  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
+
+
+/* -------------------------------  Hooks -------------------------------- */
+
+/*
+  PREACTION should be defined to return 0 on success, and nonzero on
+  failure. If you are not using locking, you can redefine these to do
+  anything you like.
+*/
+
+#if USE_LOCKS
+
+#define PREACTION(M)  ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
+#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
+#else /* USE_LOCKS */
+
+#ifndef PREACTION
+#define PREACTION(M) (0)
+#endif  /* PREACTION */
+
+#ifndef POSTACTION
+#define POSTACTION(M)
+#endif  /* POSTACTION */
+
+#endif /* USE_LOCKS */
+
+/*
+  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
+  USAGE_ERROR_ACTION is triggered on detected bad frees and
+  reallocs. The argument p is an address that might have triggered the
+  fault. It is ignored by the two predefined actions, but might be
+  useful in custom actions that try to help diagnose errors.
+*/
+
+#if PROCEED_ON_ERROR
+
+/* A count of the number of corruption errors causing resets */
+int malloc_corruption_error_count;
+
+/* default corruption action */
+static void reset_on_error(mstate m);
+
+#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)
+#define USAGE_ERROR_ACTION(m, p)
+
+#else /* PROCEED_ON_ERROR */
+
+#ifndef CORRUPTION_ERROR_ACTION
+#define CORRUPTION_ERROR_ACTION(m) ABORT
+#endif /* CORRUPTION_ERROR_ACTION */
+
+#ifndef USAGE_ERROR_ACTION
+#define USAGE_ERROR_ACTION(m,p) ABORT
+#endif /* USAGE_ERROR_ACTION */
+
+#endif /* PROCEED_ON_ERROR */
+
+/* -------------------------- Debugging setup ---------------------------- */
+
+#if ! DEBUG
+
+#define check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)
+#define check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P)
+#define check_malloc_state(M)
+#define check_top_chunk(M,P)
+
+#else /* DEBUG */
+#define check_free_chunk(M,P)       do_check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)
+#define check_top_chunk(M,P)        do_check_top_chunk(M,P)
+#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P)    do_check_mmapped_chunk(M,P)
+#define check_malloc_state(M)       do_check_malloc_state(M)
+
+static void   do_check_any_chunk(mstate m, mchunkptr p);
+static void   do_check_top_chunk(mstate m, mchunkptr p);
+static void   do_check_mmapped_chunk(mstate m, mchunkptr p);
+static void   do_check_inuse_chunk(mstate m, mchunkptr p);
+static void   do_check_free_chunk(mstate m, mchunkptr p);
+static void   do_check_malloced_chunk(mstate m, void* mem, size_t s);
+static void   do_check_tree(mstate m, tchunkptr t);
+static void   do_check_treebin(mstate m, bindex_t i);
+static void   do_check_smallbin(mstate m, bindex_t i);
+static void   do_check_malloc_state(mstate m);
+static int    bin_find(mstate m, mchunkptr x);
+static size_t traverse_and_check(mstate m);
+#endif /* DEBUG */
+
+/* ---------------------------- Indexing Bins ---------------------------- */
+
+#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
+#define small_index(s)      ((s)  >> SMALLBIN_SHIFT)
+#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)
+#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))
+
+/* addressing by index. See above about smallbin repositioning */
+#define smallbin_at(M, i)   ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
+#define treebin_at(M,i)     (&((M)->treebins[i]))
+
+/* assign tree index for size S to variable I. Use x86 asm if possible  */
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define compute_tree_index(S, I)\
+{\
+  unsigned int X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int K;\
+    __asm__("bsrl\t%1, %0\n\t" : "=r" (K) : "rm"  (X));\
+    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+  }\
+}
+
+#elif defined (__INTEL_COMPILER)
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int K = _bit_scan_reverse (X); \
+    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+  }\
+}
+
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int K;\
+    _BitScanReverse((DWORD *) &K, X);\
+    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+  }\
+}
+
+#else /* GNUC */
+#define compute_tree_index(S, I)\
+{\
+  size_t X = S >> TREEBIN_SHIFT;\
+  if (X == 0)\
+    I = 0;\
+  else if (X > 0xFFFF)\
+    I = NTREEBINS-1;\
+  else {\
+    unsigned int Y = (unsigned int)X;\
+    unsigned int N = ((Y - 0x100) >> 16) & 8;\
+    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
+    N += K;\
+    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
+    K = 14 - N + ((Y <<= K) >> 15);\
+    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
+  }\
+}
+#endif /* GNUC */
+
+/* Bit representing maximum resolved size in a treebin at i */
+#define bit_for_tree_index(i) \
+   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
+
+/* Shift placing maximum resolved bit in a treebin at i as sign bit */
+#define leftshift_for_tree_index(i) \
+   ((i == NTREEBINS-1)? 0 : \
+    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
+
+/* The size of the smallest chunk held in bin with index i */
+#define minsize_for_tree_index(i) \
+   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \
+   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
+
+
+/* ------------------------ Operations on bin maps ----------------------- */
+
+/* bit corresponding to given index */
+#define idx2bit(i)              ((binmap_t)(1) << (i))
+
+/* Mark/Clear bits with given index */
+#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))
+#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))
+#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))
+
+#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))
+#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))
+#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))
+
+/* isolate the least set bit of a bitmap */
+#define least_bit(x)         ((x) & -(x))
+
+/* mask with all bits to left of least bit of x on */
+#define left_bits(x)         ((x<<1) | -(x<<1))
+
+/* mask with all bits to left of or equal to least bit of x on */
+#define same_or_left_bits(x) ((x) | -(x))
+
+/* index corresponding to given bit. Use x86 asm if possible */
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int J;\
+  __asm__("bsfl\t%1, %0\n\t" : "=r" (J) : "rm" (X));\
+  I = (bindex_t)J;\
+}
+
+#elif defined (__INTEL_COMPILER)
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int J;\
+  J = _bit_scan_forward (X); \
+  I = (bindex_t)J;\
+}
+
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int J;\
+  _BitScanForward((DWORD *) &J, X);\
+  I = (bindex_t)J;\
+}
+
+#elif USE_BUILTIN_FFS
+#define compute_bit2idx(X, I) I = ffs(X)-1
+
+#else
+#define compute_bit2idx(X, I)\
+{\
+  unsigned int Y = X - 1;\
+  unsigned int K = Y >> (16-4) & 16;\
+  unsigned int N = K;        Y >>= K;\
+  N += K = Y >> (8-3) &  8;  Y >>= K;\
+  N += K = Y >> (4-2) &  4;  Y >>= K;\
+  N += K = Y >> (2-1) &  2;  Y >>= K;\
+  N += K = Y >> (1-0) &  1;  Y >>= K;\
+  I = (bindex_t)(N + Y);\
+}
+#endif /* GNUC */
+
+
+/* ----------------------- Runtime Check Support ------------------------- */
+
+/*
+  For security, the main invariant is that malloc/free/etc never
+  writes to a static address other than malloc_state, unless static
+  malloc_state itself has been corrupted, which cannot occur via
+  malloc (because of these checks). In essence this means that we
+  believe all pointers, sizes, maps etc held in malloc_state, but
+  check all of those linked or offsetted from other embedded data
+  structures.  These checks are interspersed with main code in a way
+  that tends to minimize their run-time cost.
+
+  When FOOTERS is defined, in addition to range checking, we also
+  verify footer fields of inuse chunks, which can be used guarantee
+  that the mstate controlling malloc/free is intact.  This is a
+  streamlined version of the approach described by William Robertson
+  et al in "Run-time Detection of Heap-based Overflows" LISA'03
+  http://www.usenix.org/events/lisa03/tech/robertson.html The footer
+  of an inuse chunk holds the xor of its mstate and a random seed,
+  that is checked upon calls to free() and realloc().  This is
+  (probablistically) unguessable from outside the program, but can be
+  computed by any code successfully malloc'ing any chunk, so does not
+  itself provide protection against code that has already broken
+  security through some other means.  Unlike Robertson et al, we
+  always dynamically check addresses of all offset chunks (previous,
+  next, etc). This turns out to be cheaper than relying on hashes.
+*/
+
+#if !INSECURE
+/* Check if address a is at least as high as any from MORECORE or MMAP */
+#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
+/* Check if address of next chunk n is higher than base chunk p */
+#define ok_next(p, n)    ((char*)(p) < (char*)(n))
+/* Check if p has its cinuse bit on */
+#define ok_cinuse(p)     cinuse(p)
+/* Check if p has its pinuse bit on */
+#define ok_pinuse(p)     pinuse(p)
+
+#else /* !INSECURE */
+#define ok_address(M, a) (1)
+#define ok_next(b, n)    (1)
+#define ok_cinuse(p)     (1)
+#define ok_pinuse(p)     (1)
+#endif /* !INSECURE */
+
+#if (FOOTERS && !INSECURE)
+/* Check if (alleged) mstate m has expected magic field */
+#define ok_magic(M)      ((M)->magic == mparams.magic)
+#else  /* (FOOTERS && !INSECURE) */
+#define ok_magic(M)      (1)
+#endif /* (FOOTERS && !INSECURE) */
+
+
+/* In gcc, use __builtin_expect to minimize impact of checks */
+#if !INSECURE
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define RTCHECK(e)  __builtin_expect(e, 1)
+#else /* GNUC */
+#define RTCHECK(e)  (e)
+#endif /* GNUC */
+#else /* !INSECURE */
+#define RTCHECK(e)  (1)
+#endif /* !INSECURE */
+
+/* macros to set up inuse chunks with or without footers */
+
+#if !FOOTERS
+
+#define mark_inuse_foot(M,p,s)
+
+/* Set cinuse bit and pinuse bit of next chunk */
+#define set_inuse(M,p,s)\
+  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
+#define set_inuse_and_pinuse(M,p,s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set size, cinuse and pinuse bit of this chunk */
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
+
+#else /* FOOTERS */
+
+/* Set foot of inuse chunk to be xor of mstate and seed */
+#define mark_inuse_foot(M,p,s)\
+  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
+
+#define get_mstate_for(p)\
+  ((mstate)(((mchunkptr)((char*)(p) +\
+    (chunksize(p))))->prev_foot ^ mparams.magic))
+
+#define set_inuse(M,p,s)\
+  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
+  mark_inuse_foot(M,p,s))
+
+#define set_inuse_and_pinuse(M,p,s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
+ mark_inuse_foot(M,p,s))
+
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+  mark_inuse_foot(M, p, s))
+
+#endif /* !FOOTERS */
+
+/* ---------------------------- setting mparams -------------------------- */
+
+/* Initialize mparams */
+static int init_mparams(void) {
+#ifdef NEED_GLOBAL_LOCK_INIT
+  if (malloc_global_mutex_status <= 0)
+    init_malloc_global_mutex();
+#endif
+
+  ACQUIRE_MALLOC_GLOBAL_LOCK();
+  if (mparams.magic == 0) {
+    size_t magic;
+    size_t psize;
+    size_t gsize;
+
+#ifndef WIN32
+    psize = malloc_getpagesize;
+    gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);
+#else /* WIN32 */
+    {
+      SYSTEM_INFO system_info;
+      GetSystemInfo(&system_info);
+      psize = system_info.dwPageSize;
+      gsize = ((DEFAULT_GRANULARITY != 0)?
+	       DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
+    }
+#endif /* WIN32 */
+
+    /* Sanity-check configuration:
+       size_t must be unsigned and as wide as pointer type.
+       ints must be at least 4 bytes.
+       alignment must be at least 8.
+       Alignment, min chunk size, and page size must all be powers of 2.
+    */
+    if ((sizeof(size_t) != sizeof(char*)) ||
+	(MAX_SIZE_T < MIN_CHUNK_SIZE)  ||
+	(sizeof(int) < 4)  ||
+	(MALLOC_ALIGNMENT < (size_t)8U) ||
+	((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
+	((MCHUNK_SIZE      & (MCHUNK_SIZE-SIZE_T_ONE))      != 0) ||
+	((gsize            & (gsize-SIZE_T_ONE))            != 0) ||
+	((psize            & (psize-SIZE_T_ONE))            != 0))
+      ABORT;
+
+    mparams.granularity = gsize;
+    mparams.page_size = psize;
+    mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+    mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
+#if MORECORE_CONTIGUOUS
+    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
+#else  /* MORECORE_CONTIGUOUS */
+    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
+#endif /* MORECORE_CONTIGUOUS */
+
+#if !ONLY_MSPACES
+    /* Set up lock for main malloc area */
+    gm->mflags = mparams.default_mflags;
+    (void)INITIAL_LOCK(&gm->mutex);
+#endif
+
+#if (FOOTERS && !INSECURE)
+    {
+#if USE_DEV_RANDOM
+      int fd;
+      unsigned char buf[sizeof(size_t)];
+      /* Try to use /dev/urandom, else fall back on using time */
+      if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
+	  read(fd, buf, sizeof(buf)) == sizeof(buf)) {
+	magic = *((size_t *) buf);
+	close(fd);
+      }
+      else
+#endif /* USE_DEV_RANDOM */
+#ifdef WIN32
+	magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
+#else
+      magic = (size_t)(time(0) ^ (size_t)0x55555555U);
+#endif
+      magic |= (size_t)8U;    /* ensure nonzero */
+      magic &= ~(size_t)7U;   /* improve chances of fault for bad values */
+    }
+#else /* (FOOTERS && !INSECURE) */
+    magic = (size_t)0x58585858U;
+#endif /* (FOOTERS && !INSECURE) */
+
+    mparams.magic = magic;
+  }
+
+  RELEASE_MALLOC_GLOBAL_LOCK();
+  return 1;
+}
+
+/* support for mallopt */
+static int change_mparam(int param_number, int value) {
+  size_t val = (value == -1)? MAX_SIZE_T : (size_t)value;
+  ensure_initialization();
+  switch(param_number) {
+  case M_TRIM_THRESHOLD:
+    mparams.trim_threshold = val;
+    return 1;
+  case M_GRANULARITY:
+    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
+      mparams.granularity = val;
+      return 1;
+    }
+    else
+      return 0;
+  case M_MMAP_THRESHOLD:
+    mparams.mmap_threshold = val;
+    return 1;
+  default:
+    return 0;
+  }
+}
+
+#if DEBUG
+/* ------------------------- Debugging Support --------------------------- */
+
+/* Check properties of any chunk, whether free, inuse, mmapped etc  */
+static void do_check_any_chunk(mstate m, mchunkptr p) {
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+}
+
+/* Check properties of top chunk */
+static void do_check_top_chunk(mstate m, mchunkptr p) {
+  msegmentptr sp = segment_holding(m, (char*)p);
+  size_t  sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */
+  assert(sp != 0);
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+  assert(sz == m->topsize);
+  assert(sz > 0);
+  assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
+  assert(pinuse(p));
+  assert(!pinuse(chunk_plus_offset(p, sz)));
+}
+
+/* Check properties of (inuse) mmapped chunks */
+static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
+  size_t  sz = chunksize(p);
+  size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD);
+  assert(is_mmapped(p));
+  assert(use_mmap(m));
+  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+  assert(ok_address(m, p));
+  assert(!is_small(sz));
+  assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
+  assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
+  assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
+}
+
+/* Check properties of inuse chunks */
+static void do_check_inuse_chunk(mstate m, mchunkptr p) {
+  do_check_any_chunk(m, p);
+  assert(cinuse(p));
+  assert(next_pinuse(p));
+  /* If not pinuse and not mmapped, previous chunk has OK offset */
+  assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
+  if (is_mmapped(p))
+    do_check_mmapped_chunk(m, p);
+}
+
+/* Check properties of free chunks */
+static void do_check_free_chunk(mstate m, mchunkptr p) {
+  size_t sz = chunksize(p);
+  mchunkptr next = chunk_plus_offset(p, sz);
+  do_check_any_chunk(m, p);
+  assert(!cinuse(p));
+  assert(!next_pinuse(p));
+  assert (!is_mmapped(p));
+  if (p != m->dv && p != m->top) {
+    if (sz >= MIN_CHUNK_SIZE) {
+      assert((sz & CHUNK_ALIGN_MASK) == 0);
+      assert(is_aligned(chunk2mem(p)));
+      assert(next->prev_foot == sz);
+      assert(pinuse(p));
+      assert (next == m->top || cinuse(next));
+      assert(p->fd->bk == p);
+      assert(p->bk->fd == p);
+    }
+    else  /* markers are always of size SIZE_T_SIZE */
+      assert(sz == SIZE_T_SIZE);
+  }
+}
+
+/* Check properties of malloced chunks at the point they are malloced */
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT);
+    do_check_inuse_chunk(m, p);
+    assert((sz & CHUNK_ALIGN_MASK) == 0);
+    assert(sz >= MIN_CHUNK_SIZE);
+    assert(sz >= s);
+    /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
+    assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
+  }
+}
+
+/* Check a tree and its subtrees.  */
+static void do_check_tree(mstate m, tchunkptr t) {
+  tchunkptr head = 0;
+  tchunkptr u = t;
+  bindex_t tindex = t->index;
+  size_t tsize = chunksize(t);
+  bindex_t idx;
+  compute_tree_index(tsize, idx);
+  assert(tindex == idx);
+  assert(tsize >= MIN_LARGE_SIZE);
+  assert(tsize >= minsize_for_tree_index(idx));
+  assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
+
+  do { /* traverse through chain of same-sized nodes */
+    do_check_any_chunk(m, ((mchunkptr)u));
+    assert(u->index == tindex);
+    assert(chunksize(u) == tsize);
+    assert(!cinuse(u));
+    assert(!next_pinuse(u));
+    assert(u->fd->bk == u);
+    assert(u->bk->fd == u);
+    if (u->parent == 0) {
+      assert(u->child[0] == 0);
+      assert(u->child[1] == 0);
+    }
+    else {
+      assert(head == 0); /* only one node on chain has parent */
+      head = u;
+      assert(u->parent != u);
+      assert (u->parent->child[0] == u ||
+	      u->parent->child[1] == u ||
+	      *((tbinptr*)(u->parent)) == u);
+      if (u->child[0] != 0) {
+	assert(u->child[0]->parent == u);
+	assert(u->child[0] != u);
+	do_check_tree(m, u->child[0]);
+      }
+      if (u->child[1] != 0) {
+	assert(u->child[1]->parent == u);
+	assert(u->child[1] != u);
+	do_check_tree(m, u->child[1]);
+      }
+      if (u->child[0] != 0 && u->child[1] != 0) {
+	assert(chunksize(u->child[0]) < chunksize(u->child[1]));
+      }
+    }
+    u = u->fd;
+  } while (u != t);
+  assert(head != 0);
+}
+
+/*  Check all the chunks in a treebin.  */
+static void do_check_treebin(mstate m, bindex_t i) {
+  tbinptr* tb = treebin_at(m, i);
+  tchunkptr t = *tb;
+  int empty = (m->treemap & (1U << i)) == 0;
+  if (t == 0)
+    assert(empty);
+  if (!empty)
+    do_check_tree(m, t);
+}
+
+/*  Check all the chunks in a smallbin.  */
+static void do_check_smallbin(mstate m, bindex_t i) {
+  sbinptr b = smallbin_at(m, i);
+  mchunkptr p = b->bk;
+  unsigned int empty = (m->smallmap & (1U << i)) == 0;
+  if (p == b)
+    assert(empty);
+  if (!empty) {
+    for (; p != b; p = p->bk) {
+      size_t size = chunksize(p);
+      mchunkptr q;
+      /* each chunk claims to be free */
+      do_check_free_chunk(m, p);
+      /* chunk belongs in bin */
+      assert(small_index(size) == i);
+      assert(p->bk == b || chunksize(p->bk) == chunksize(p));
+      /* chunk is followed by an inuse chunk */
+      q = next_chunk(p);
+      if (q->head != FENCEPOST_HEAD)
+	do_check_inuse_chunk(m, q);
+    }
+  }
+}
+
+/* Find x in a bin. Used in other check functions. */
+static int bin_find(mstate m, mchunkptr x) {
+  size_t size = chunksize(x);
+  if (is_small(size)) {
+    bindex_t sidx = small_index(size);
+    sbinptr b = smallbin_at(m, sidx);
+    if (smallmap_is_marked(m, sidx)) {
+      mchunkptr p = b;
+      do {
+	if (p == x)
+	  return 1;
+      } while ((p = p->fd) != b);
+    }
+  }
+  else {
+    bindex_t tidx;
+    compute_tree_index(size, tidx);
+    if (treemap_is_marked(m, tidx)) {
+      tchunkptr t = *treebin_at(m, tidx);
+      size_t sizebits = size << leftshift_for_tree_index(tidx);
+      while (t != 0 && chunksize(t) != size) {
+	t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+	sizebits <<= 1;
+      }
+      if (t != 0) {
+	tchunkptr u = t;
+	do {
+	  if (u == (tchunkptr)x)
+	    return 1;
+	} while ((u = u->fd) != t);
+      }
+    }
+  }
+  return 0;
+}
+
+/* Traverse each chunk and check it; return total */
+static size_t traverse_and_check(mstate m) {
+  size_t sum = 0;
+  if (is_initialized(m)) {
+    msegmentptr s = &m->seg;
+    sum += m->topsize + TOP_FOOT_SIZE;
+    while (s != 0) {
+      mchunkptr q = align_as_chunk(s->base);
+      mchunkptr lastq = 0;
+      assert(pinuse(q));
+      while (segment_holds(s, q) &&
+	     q != m->top && q->head != FENCEPOST_HEAD) {
+	sum += chunksize(q);
+	if (cinuse(q)) {
+	  assert(!bin_find(m, q));
+	  do_check_inuse_chunk(m, q);
+	}
+	else {
+	  assert(q == m->dv || bin_find(m, q));
+	  assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */
+	  do_check_free_chunk(m, q);
+	}
+	lastq = q;
+	q = next_chunk(q);
+      }
+      s = s->next;
+    }
+  }
+  return sum;
+}
+
+/* Check all properties of malloc_state. */
+static void do_check_malloc_state(mstate m) {
+  bindex_t i;
+  size_t total;
+  /* check bins */
+  for (i = 0; i < NSMALLBINS; ++i)
+    do_check_smallbin(m, i);
+  for (i = 0; i < NTREEBINS; ++i)
+    do_check_treebin(m, i);
+
+  if (m->dvsize != 0) { /* check dv chunk */
+    do_check_any_chunk(m, m->dv);
+    assert(m->dvsize == chunksize(m->dv));
+    assert(m->dvsize >= MIN_CHUNK_SIZE);
+    assert(bin_find(m, m->dv) == 0);
+  }
+
+  if (m->top != 0) {   /* check top chunk */
+    do_check_top_chunk(m, m->top);
+    /*assert(m->topsize == chunksize(m->top)); redundant */
+    assert(m->topsize > 0);
+    assert(bin_find(m, m->top) == 0);
+  }
+
+  total = traverse_and_check(m);
+  assert(total <= m->footprint);
+  assert(m->footprint <= m->max_footprint);
+}
+#endif /* DEBUG */
+
+/* ----------------------------- statistics ------------------------------ */
+
+#if !NO_MALLINFO
+static struct mallinfo internal_mallinfo(mstate m) {
+  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+  ensure_initialization();
+  if (!PREACTION(m)) {
+    check_malloc_state(m);
+    if (is_initialized(m)) {
+      size_t nfree = SIZE_T_ONE; /* top always free */
+      size_t mfree = m->topsize + TOP_FOOT_SIZE;
+      size_t sum = mfree;
+      msegmentptr s = &m->seg;
+      while (s != 0) {
+	mchunkptr q = align_as_chunk(s->base);
+	while (segment_holds(s, q) &&
+	       q != m->top && q->head != FENCEPOST_HEAD) {
+	  size_t sz = chunksize(q);
+	  sum += sz;
+	  if (!cinuse(q)) {
+	    mfree += sz;
+	    ++nfree;
+	  }
+	  q = next_chunk(q);
+	}
+	s = s->next;
+      }
+
+      nm.arena    = sum;
+      nm.ordblks  = nfree;
+      nm.hblkhd   = m->footprint - sum;
+      nm.usmblks  = m->max_footprint;
+      nm.uordblks = m->footprint - mfree;
+      nm.fordblks = mfree;
+      nm.keepcost = m->topsize;
+    }
+
+    POSTACTION(m);
+  }
+  return nm;
+}
+#endif /* !NO_MALLINFO */
+
+static void internal_malloc_stats(mstate m) {
+  ensure_initialization();
+  if (!PREACTION(m)) {
+    size_t maxfp = 0;
+    size_t fp = 0;
+    size_t used = 0;
+    check_malloc_state(m);
+    if (is_initialized(m)) {
+      msegmentptr s = &m->seg;
+      maxfp = m->max_footprint;
+      fp = m->footprint;
+      used = fp - (m->topsize + TOP_FOOT_SIZE);
+
+      while (s != 0) {
+	mchunkptr q = align_as_chunk(s->base);
+	while (segment_holds(s, q) &&
+	       q != m->top && q->head != FENCEPOST_HEAD) {
+	  if (!cinuse(q))
+	    used -= chunksize(q);
+	  q = next_chunk(q);
+	}
+	s = s->next;
+      }
+    }
+
+    fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
+    fprintf(stderr, "system bytes     = %10lu\n", (unsigned long)(fp));
+    fprintf(stderr, "in use bytes     = %10lu\n", (unsigned long)(used));
+
+    POSTACTION(m);
+  }
+}
+
+/* ----------------------- Operations on smallbins ----------------------- */
+
+/*
+  Various forms of linking and unlinking are defined as macros.  Even
+  the ones for trees, which are very long but have very short typical
+  paths.  This is ugly but reduces reliance on inlining support of
+  compilers.
+*/
+
+/* Link a free chunk into a smallbin  */
+#define insert_small_chunk(M, P, S) {\
+  bindex_t I  = small_index(S);\
+  mchunkptr B = smallbin_at(M, I);\
+  mchunkptr F = B;\
+  assert(S >= MIN_CHUNK_SIZE);\
+  if (!smallmap_is_marked(M, I))\
+    mark_smallmap(M, I);\
+  else if (RTCHECK(ok_address(M, B->fd)))\
+    F = B->fd;\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+  B->fd = P;\
+  F->bk = P;\
+  P->fd = F;\
+  P->bk = B;\
+}
+
+/* Unlink a chunk from a smallbin  */
+#define unlink_small_chunk(M, P, S) {\
+  mchunkptr F = P->fd;\
+  mchunkptr B = P->bk;\
+  bindex_t I = small_index(S);\
+  assert(P != B);\
+  assert(P != F);\
+  assert(chunksize(P) == small_index2size(I));\
+  if (F == B)\
+    clear_smallmap(M, I);\
+  else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
+		   (B == smallbin_at(M,I) || ok_address(M, B)))) {\
+    F->bk = B;\
+    B->fd = F;\
+  }\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+}
+
+/* Unlink the first chunk from a smallbin */
+#define unlink_first_small_chunk(M, B, P, I) {\
+  mchunkptr F = P->fd;\
+  assert(P != B);\
+  assert(P != F);\
+  assert(chunksize(P) == small_index2size(I));\
+  if (B == F)\
+    clear_smallmap(M, I);\
+  else if (RTCHECK(ok_address(M, F))) {\
+    B->fd = F;\
+    F->bk = B;\
+  }\
+  else {\
+    CORRUPTION_ERROR_ACTION(M);\
+  }\
+}
+
+
+
+/* Replace dv node, binning the old one */
+/* Used only when dvsize known to be small */
+#define replace_dv(M, P, S) {\
+  size_t DVS = M->dvsize;\
+  if (DVS != 0) {\
+    mchunkptr DV = M->dv;\
+    assert(is_small(DVS));\
+    insert_small_chunk(M, DV, DVS);\
+  }\
+  M->dvsize = S;\
+  M->dv = P;\
+}
+
+/* ------------------------- Operations on trees ------------------------- */
+
+/* Insert chunk into tree */
+#define insert_large_chunk(M, X, S) {\
+  tbinptr* H;\
+  bindex_t I;\
+  compute_tree_index(S, I);\
+  H = treebin_at(M, I);\
+  X->index = I;\
+  X->child[0] = X->child[1] = 0;\
+  if (!treemap_is_marked(M, I)) {\
+    mark_treemap(M, I);\
+    *H = X;\
+    X->parent = (tchunkptr)H;\
+    X->fd = X->bk = X;\
+  }\
+  else {\
+    tchunkptr T = *H;\
+    size_t K = S << leftshift_for_tree_index(I);\
+    for (;;) {\
+      if (chunksize(T) != S) {\
+	tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
+	K <<= 1;\
+	if (*C != 0)\
+	  T = *C;\
+	else if (RTCHECK(ok_address(M, C))) {\
+	  *C = X;\
+	  X->parent = T;\
+	  X->fd = X->bk = X;\
+	  break;\
+	}\
+	else {\
+	  CORRUPTION_ERROR_ACTION(M);\
+	  break;\
+	}\
+      }\
+      else {\
+	tchunkptr F = T->fd;\
+	if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
+	  T->fd = F->bk = X;\
+	  X->fd = F;\
+	  X->bk = T;\
+	  X->parent = 0;\
+	  break;\
+	}\
+	else {\
+	  CORRUPTION_ERROR_ACTION(M);\
+	  break;\
+	}\
+      }\
+    }\
+  }\
+}
+
+/*
+  Unlink steps:
+
+  1. If x is a chained node, unlink it from its same-sized fd/bk links
+     and choose its bk node as its replacement.
+  2. If x was the last node of its size, but not a leaf node, it must
+     be replaced with a leaf node (not merely one with an open left or
+     right), to make sure that lefts and rights of descendants
+     correspond properly to bit masks.  We use the rightmost descendant
+     of x.  We could use any other leaf, but this is easy to locate and
+     tends to counteract removal of leftmosts elsewhere, and so keeps
+     paths shorter than minimally guaranteed.  This doesn't loop much
+     because on average a node in a tree is near the bottom.
+  3. If x is the base of a chain (i.e., has parent links) relink
+     x's parent and children to x's replacement (or null if none).
+*/
+
+#define unlink_large_chunk(M, X) {\
+  tchunkptr XP = X->parent;\
+  tchunkptr R;\
+  if (X->bk != X) {\
+    tchunkptr F = X->fd;\
+    R = X->bk;\
+    if (RTCHECK(ok_address(M, F))) {\
+      F->bk = R;\
+      R->fd = F;\
+    }\
+    else {\
+      CORRUPTION_ERROR_ACTION(M);\
+    }\
+  }\
+  else {\
+    tchunkptr* RP;\
+    if (((R = *(RP = &(X->child[1]))) != 0) ||\
+	((R = *(RP = &(X->child[0]))) != 0)) {\
+      tchunkptr* CP;\
+      while ((*(CP = &(R->child[1])) != 0) ||\
+	     (*(CP = &(R->child[0])) != 0)) {\
+	R = *(RP = CP);\
+      }\
+      if (RTCHECK(ok_address(M, RP)))\
+	*RP = 0;\
+      else {\
+	CORRUPTION_ERROR_ACTION(M);\
+      }\
+    }\
+  }\
+  if (XP != 0) {\
+    tbinptr* H = treebin_at(M, X->index);\
+    if (X == *H) {\
+      if ((*H = R) == 0) \
+	clear_treemap(M, X->index);\
+    }\
+    else if (RTCHECK(ok_address(M, XP))) {\
+      if (XP->child[0] == X) \
+	XP->child[0] = R;\
+      else \
+	XP->child[1] = R;\
+    }\
+    else\
+      CORRUPTION_ERROR_ACTION(M);\
+    if (R != 0) {\
+      if (RTCHECK(ok_address(M, R))) {\
+	tchunkptr C0, C1;\
+	R->parent = XP;\
+	if ((C0 = X->child[0]) != 0) {\
+	  if (RTCHECK(ok_address(M, C0))) {\
+	    R->child[0] = C0;\
+	    C0->parent = R;\
+	  }\
+	  else\
+	    CORRUPTION_ERROR_ACTION(M);\
+	}\
+	if ((C1 = X->child[1]) != 0) {\
+	  if (RTCHECK(ok_address(M, C1))) {\
+	    R->child[1] = C1;\
+	    C1->parent = R;\
+	  }\
+	  else\
+	    CORRUPTION_ERROR_ACTION(M);\
+	}\
+      }\
+      else\
+	CORRUPTION_ERROR_ACTION(M);\
+    }\
+  }\
+}
+
+/* Relays to large vs small bin operations */
+
+#define insert_chunk(M, P, S)\
+  if (is_small(S)) insert_small_chunk(M, P, S)\
+  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
+
+#define unlink_chunk(M, P, S)\
+  if (is_small(S)) unlink_small_chunk(M, P, S)\
+  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
+
+
+/* Relays to internal calls to malloc/free from realloc, memalign etc */
+
+#if ONLY_MSPACES
+#define internal_malloc(m, b) mspace_malloc(m, b)
+#define internal_free(m, mem) mspace_free(m,mem);
+#else /* ONLY_MSPACES */
+#if MSPACES
+#define internal_malloc(m, b)\
+   (m == gm)? dlmalloc(b) : mspace_malloc(m, b)
+#define internal_free(m, mem)\
+   if (m == gm) dlfree(mem); else mspace_free(m,mem);
+#else /* MSPACES */
+#define internal_malloc(m, b) dlmalloc(b)
+#define internal_free(m, mem) dlfree(mem)
+#endif /* MSPACES */
+#endif /* ONLY_MSPACES */
+
+/* -----------------------  Direct-mmapping chunks ----------------------- */
+
+/*
+  Directly mmapped chunks are set up with an offset to the start of
+  the mmapped region stored in the prev_foot field of the chunk. This
+  allows reconstruction of the required argument to MUNMAP when freed,
+  and also allows adjustment of the returned chunk to meet alignment
+  requirements (especially in memalign).  There is also enough space
+  allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain
+  the PINUSE bit so frees can be checked.
+*/
+
+/* Malloc using mmap */
+static void* mmap_alloc(mstate m, size_t nb) {
+  size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+  if (mmsize > nb) {     /* Check for wrap around 0 */
+    char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));
+    if (mm != CMFAIL) {
+      size_t offset = align_offset(chunk2mem(mm));
+      size_t psize = mmsize - offset - MMAP_FOOT_PAD;
+      mchunkptr p = (mchunkptr)(mm + offset);
+      p->prev_foot = offset | IS_MMAPPED_BIT;
+      (p)->head = (psize|CINUSE_BIT);
+      mark_inuse_foot(m, p, psize);
+      chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
+      chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
+
+      if (mm < m->least_addr)
+	m->least_addr = mm;
+      if ((m->footprint += mmsize) > m->max_footprint)
+	m->max_footprint = m->footprint;
+      assert(is_aligned(chunk2mem(p)));
+      check_mmapped_chunk(m, p);
+      return chunk2mem(p);
+    }
+  }
+  return 0;
+}
+
+/* Realloc using mmap */
+static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) {
+  size_t oldsize = chunksize(oldp);
+  if (is_small(nb)) /* Can't shrink mmap regions below small size */
+    return 0;
+  /* Keep old chunk if big enough but not too big */
+  if (oldsize >= nb + SIZE_T_SIZE &&
+      (oldsize - nb) <= (mparams.granularity << 1))
+    return oldp;
+  else {
+    size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT;
+    size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
+    size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+    char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
+				  oldmmsize, newmmsize, 1);
+    if (cp != CMFAIL) {
+      mchunkptr newp = (mchunkptr)(cp + offset);
+      size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
+      newp->head = (psize|CINUSE_BIT);
+      mark_inuse_foot(m, newp, psize);
+      chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
+      chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
+
+      if (cp < m->least_addr)
+	m->least_addr = cp;
+      if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
+	m->max_footprint = m->footprint;
+      check_mmapped_chunk(m, newp);
+      return newp;
+    }
+  }
+  return 0;
+}
+
+/* -------------------------- mspace management -------------------------- */
+
+/* Initialize top chunk and its size */
+static void init_top(mstate m, mchunkptr p, size_t psize) {
+  /* Ensure alignment */
+  size_t offset = align_offset(chunk2mem(p));
+  p = (mchunkptr)((char*)p + offset);
+  psize -= offset;
+
+  m->top = p;
+  m->topsize = psize;
+  p->head = psize | PINUSE_BIT;
+  /* set size of fake trailing chunk holding overhead space only once */
+  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
+  m->trim_check = mparams.trim_threshold; /* reset on each update */
+}
+
+/* Initialize bins for a new mstate that is otherwise zeroed out */
+static void init_bins(mstate m) {
+  /* Establish circular links for smallbins */
+  bindex_t i;
+  for (i = 0; i < NSMALLBINS; ++i) {
+    sbinptr bin = smallbin_at(m,i);
+    bin->fd = bin->bk = bin;
+  }
+}
+
+#if PROCEED_ON_ERROR
+
+/* default corruption action */
+static void reset_on_error(mstate m) {
+  int i;
+  ++malloc_corruption_error_count;
+  /* Reinitialize fields to forget about all memory */
+  m->smallbins = m->treebins = 0;
+  m->dvsize = m->topsize = 0;
+  m->seg.base = 0;
+  m->seg.size = 0;
+  m->seg.next = 0;
+  m->top = m->dv = 0;
+  for (i = 0; i < NTREEBINS; ++i)
+    *treebin_at(m, i) = 0;
+  init_bins(m);
+}
+#endif /* PROCEED_ON_ERROR */
+
+/* Allocate chunk and prepend remainder with chunk in successor base. */
+static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
+			   size_t nb) {
+  mchunkptr p = align_as_chunk(newbase);
+  mchunkptr oldfirst = align_as_chunk(oldbase);
+  size_t psize = (char*)oldfirst - (char*)p;
+  mchunkptr q = chunk_plus_offset(p, nb);
+  size_t qsize = psize - nb;
+  set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+
+  assert((char*)oldfirst > (char*)q);
+  assert(pinuse(oldfirst));
+  assert(qsize >= MIN_CHUNK_SIZE);
+
+  /* consolidate remainder with first chunk of old base */
+  if (oldfirst == m->top) {
+    size_t tsize = m->topsize += qsize;
+    m->top = q;
+    q->head = tsize | PINUSE_BIT;
+    check_top_chunk(m, q);
+  }
+  else if (oldfirst == m->dv) {
+    size_t dsize = m->dvsize += qsize;
+    m->dv = q;
+    set_size_and_pinuse_of_free_chunk(q, dsize);
+  }
+  else {
+    if (!cinuse(oldfirst)) {
+      size_t nsize = chunksize(oldfirst);
+      unlink_chunk(m, oldfirst, nsize);
+      oldfirst = chunk_plus_offset(oldfirst, nsize);
+      qsize += nsize;
+    }
+    set_free_with_pinuse(q, qsize, oldfirst);
+    insert_chunk(m, q, qsize);
+    check_free_chunk(m, q);
+  }
+
+  check_malloced_chunk(m, chunk2mem(p), nb);
+  return chunk2mem(p);
+}
+
+/* Add a segment to hold a new noncontiguous region */
+static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
+  /* Determine locations and sizes of segment, fenceposts, old top */
+  char* old_top = (char*)m->top;
+  msegmentptr oldsp = segment_holding(m, old_top);
+  char* old_end = oldsp->base + oldsp->size;
+  size_t ssize = pad_request(sizeof(struct malloc_segment));
+  char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+  size_t offset = align_offset(chunk2mem(rawsp));
+  char* asp = rawsp + offset;
+  char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
+  mchunkptr sp = (mchunkptr)csp;
+  msegmentptr ss = (msegmentptr)(chunk2mem(sp));
+  mchunkptr tnext = chunk_plus_offset(sp, ssize);
+  mchunkptr p = tnext;
+  int nfences = 0;
+
+  /* reset top to new space */
+  init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+
+  /* Set up segment record */
+  assert(is_aligned(ss));
+  set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
+  *ss = m->seg; /* Push current record */
+  m->seg.base = tbase;
+  m->seg.size = tsize;
+  m->seg.sflags = mmapped;
+  m->seg.next = ss;
+
+  /* Insert trailing fenceposts */
+  for (;;) {
+    mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
+    p->head = FENCEPOST_HEAD;
+    ++nfences;
+    if ((char*)(&(nextp->head)) < old_end)
+      p = nextp;
+    else
+      break;
+  }
+  assert(nfences >= 2);
+
+  /* Insert the rest of old top into a bin as an ordinary free chunk */
+  if (csp != old_top) {
+    mchunkptr q = (mchunkptr)old_top;
+    size_t psize = csp - old_top;
+    mchunkptr tn = chunk_plus_offset(q, psize);
+    set_free_with_pinuse(q, psize, tn);
+    insert_chunk(m, q, psize);
+  }
+
+  check_top_chunk(m, m->top);
+}
+
+/* -------------------------- System allocation -------------------------- */
+
+/* Get memory from system using MORECORE or MMAP */
+static void* sys_alloc(mstate m, size_t nb) {
+  char* tbase = CMFAIL;
+  size_t tsize = 0;
+  flag_t mmap_flag = 0;
+
+  ensure_initialization();
+
+  /* Directly map large chunks */
+  if (use_mmap(m) && nb >= mparams.mmap_threshold) {
+    void* mem = mmap_alloc(m, nb);
+    if (mem != 0)
+      return mem;
+  }
+
+  /*
+    Try getting memory in any of three ways (in most-preferred to
+    least-preferred order):
+    1. A call to MORECORE that can normally contiguously extend memory.
+       (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
+       main space is mmapped or a previous contiguous call failed)
+    2. A call to MMAP new space (disabled if not HAVE_MMAP).
+       Note that under the default settings, if MORECORE is unable to
+       fulfill a request, and HAVE_MMAP is true, then mmap is
+       used as a noncontiguous system allocator. This is a useful backup
+       strategy for systems with holes in address spaces -- in this case
+       sbrk cannot contiguously expand the heap, but mmap may be able to
+       find space.
+    3. A call to MORECORE that cannot usually contiguously extend memory.
+       (disabled if not HAVE_MORECORE)
+
+   In all cases, we need to request enough bytes from system to ensure
+   we can malloc nb bytes upon success, so pad with enough space for
+   top_foot, plus alignment-pad to make sure we don't lose bytes if
+   not on boundary, and round this up to a granularity unit.
+  */
+
+  if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
+    char* br = CMFAIL;
+    msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
+    size_t asize = 0;
+    ACQUIRE_MALLOC_GLOBAL_LOCK();
+
+    if (ss == 0) {  /* First time through or recovery */
+      char* base = (char*)CALL_MORECORE(0);
+      if (base != CMFAIL) {
+	asize = granularity_align(nb + SYS_ALLOC_PADDING);
+	/* Adjust to end on a page boundary */
+	if (!is_page_aligned(base))
+	  asize += (page_align((size_t)base) - (size_t)base);
+	/* Can't call MORECORE if size is negative when treated as signed */
+	if (asize < HALF_MAX_SIZE_T &&
+	    (br = (char*)(CALL_MORECORE(asize))) == base) {
+	  tbase = base;
+	  tsize = asize;
+	}
+      }
+    }
+    else {
+      /* Subtract out existing available top space from MORECORE request. */
+      asize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
+      /* Use mem here only if it did continuously extend old space */
+      if (asize < HALF_MAX_SIZE_T &&
+	  (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) {
+	tbase = br;
+	tsize = asize;
+      }
+    }
+
+    if (tbase == CMFAIL) {    /* Cope with partial failure */
+      if (br != CMFAIL) {    /* Try to use/extend the space we did get */
+	if (asize < HALF_MAX_SIZE_T &&
+	    asize < nb + SYS_ALLOC_PADDING) {
+	  size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - asize);
+	  if (esize < HALF_MAX_SIZE_T) {
+	    char* end = (char*)CALL_MORECORE(esize);
+	    if (end != CMFAIL)
+	      asize += esize;
+	    else {            /* Can't use; try to release */
+	      (void) CALL_MORECORE(-asize);
+	      br = CMFAIL;
+	    }
+	  }
+	}
+      }
+      if (br != CMFAIL) {    /* Use the space we did get */
+	tbase = br;
+	tsize = asize;
+      }
+      else
+	disable_contiguous(m); /* Don't try contiguous path in the future */
+    }
+
+    RELEASE_MALLOC_GLOBAL_LOCK();
+  }
+
+  if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */
+    size_t rsize = granularity_align(nb + SYS_ALLOC_PADDING);
+    if (rsize > nb) { /* Fail if wraps around zero */
+      char* mp = (char*)(CALL_MMAP(rsize));
+      if (mp != CMFAIL) {
+	tbase = mp;
+	tsize = rsize;
+	mmap_flag = IS_MMAPPED_BIT;
+      }
+    }
+  }
+
+  if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
+    size_t asize = granularity_align(nb + SYS_ALLOC_PADDING);
+    if (asize < HALF_MAX_SIZE_T) {
+      char* br = CMFAIL;
+      char* end = CMFAIL;
+      ACQUIRE_MALLOC_GLOBAL_LOCK();
+      br = (char*)(CALL_MORECORE(asize));
+      end = (char*)(CALL_MORECORE(0));
+      RELEASE_MALLOC_GLOBAL_LOCK();
+      if (br != CMFAIL && end != CMFAIL && br < end) {
+	size_t ssize = end - br;
+	if (ssize > nb + TOP_FOOT_SIZE) {
+	  tbase = br;
+	  tsize = ssize;
+	}
+      }
+    }
+  }
+
+  if (tbase != CMFAIL) {
+
+    if ((m->footprint += tsize) > m->max_footprint)
+      m->max_footprint = m->footprint;
+
+    if (!is_initialized(m)) { /* first-time initialization */
+      m->seg.base = m->least_addr = tbase;
+      m->seg.size = tsize;
+      m->seg.sflags = mmap_flag;
+      m->magic = mparams.magic;
+      m->release_checks = MAX_RELEASE_CHECK_RATE;
+      init_bins(m);
+#if !ONLY_MSPACES
+      if (is_global(m))
+	init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+      else
+#endif
+      {
+	/* Offset top by embedded malloc_state */
+	mchunkptr mn = next_chunk(mem2chunk(m));
+	init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
+      }
+    }
+
+    else {
+      /* Try to merge with an existing segment */
+      msegmentptr sp = &m->seg;
+      /* Only consider most recent segment if traversal suppressed */
+      while (sp != 0 && tbase != sp->base + sp->size)
+	sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
+      if (sp != 0 &&
+	  !is_extern_segment(sp) &&
+	  (sp->sflags & IS_MMAPPED_BIT) == mmap_flag &&
+	  segment_holds(sp, m->top)) { /* append */
+	sp->size += tsize;
+	init_top(m, m->top, m->topsize + tsize);
+      }
+      else {
+	if (tbase < m->least_addr)
+	  m->least_addr = tbase;
+	sp = &m->seg;
+	while (sp != 0 && sp->base != tbase + tsize)
+	  sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
+	if (sp != 0 &&
+	    !is_extern_segment(sp) &&
+	    (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) {
+	  char* oldbase = sp->base;
+	  sp->base = tbase;
+	  sp->size += tsize;
+	  return prepend_alloc(m, tbase, oldbase, nb);
+	}
+	else
+	  add_segment(m, tbase, tsize, mmap_flag);
+      }
+    }
+
+    if (nb < m->topsize) { /* Allocate from new or extended top space */
+      size_t rsize = m->topsize -= nb;
+      mchunkptr p = m->top;
+      mchunkptr r = m->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+      check_top_chunk(m, m->top);
+      check_malloced_chunk(m, chunk2mem(p), nb);
+      return chunk2mem(p);
+    }
+  }
+
+  MALLOC_FAILURE_ACTION;
+  return 0;
+}
+
+/* -----------------------  system deallocation -------------------------- */
+
+/* Unmap and unlink any mmapped segments that don't contain used chunks */
+static size_t release_unused_segments(mstate m) {
+  size_t released = 0;
+  int nsegs = 0;
+  msegmentptr pred = &m->seg;
+  msegmentptr sp = pred->next;
+  while (sp != 0) {
+    char* base = sp->base;
+    size_t size = sp->size;
+    msegmentptr next = sp->next;
+    ++nsegs;
+    if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
+      mchunkptr p = align_as_chunk(base);
+      size_t psize = chunksize(p);
+      /* Can unmap if first chunk holds entire segment and not pinned */
+      if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
+	tchunkptr tp = (tchunkptr)p;
+	assert(segment_holds(sp, (char*)sp));
+	if (p == m->dv) {
+	  m->dv = 0;
+	  m->dvsize = 0;
+	}
+	else {
+	  unlink_large_chunk(m, tp);
+	}
+	if (CALL_MUNMAP(base, size) == 0) {
+	  released += size;
+	  m->footprint -= size;
+	  /* unlink obsoleted record */
+	  sp = pred;
+	  sp->next = next;
+	}
+	else { /* back out if cannot unmap */
+	  insert_large_chunk(m, tp, psize);
+	}
+      }
+    }
+    if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */
+      break;
+    pred = sp;
+    sp = next;
+  }
+  /* Reset check counter */
+  m->release_checks = ((nsegs > MAX_RELEASE_CHECK_RATE)?
+		       nsegs : MAX_RELEASE_CHECK_RATE);
+  return released;
+}
+
+static int sys_trim(mstate m, size_t pad) {
+  size_t released = 0;
+  ensure_initialization();
+  if (pad < MAX_REQUEST && is_initialized(m)) {
+    pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
+
+    if (m->topsize > pad) {
+      /* Shrink top space in granularity-size units, keeping at least one */
+      size_t unit = mparams.granularity;
+      size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
+		      SIZE_T_ONE) * unit;
+      msegmentptr sp = segment_holding(m, (char*)m->top);
+
+      if (!is_extern_segment(sp)) {
+	if (is_mmapped_segment(sp)) {
+	  if (HAVE_MMAP &&
+	      sp->size >= extra &&
+	      !has_segment_link(m, sp)) { /* can't shrink if pinned */
+	    size_t newsize = sp->size - extra;
+	    /* Prefer mremap, fall back to munmap */
+	    if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
+		(CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
+	      released = extra;
+	    }
+	  }
+	}
+	else if (HAVE_MORECORE) {
+	  if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
+	    extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
+	  ACQUIRE_MALLOC_GLOBAL_LOCK();
+	  {
+	    /* Make sure end of memory is where we last set it. */
+	    char* old_br = (char*)(CALL_MORECORE(0));
+	    if (old_br == sp->base + sp->size) {
+	      char* rel_br = (char*)(CALL_MORECORE(-extra));
+	      char* new_br = (char*)(CALL_MORECORE(0));
+	      if (rel_br != CMFAIL && new_br < old_br)
+		released = old_br - new_br;
+	    }
+	  }
+	  RELEASE_MALLOC_GLOBAL_LOCK();
+	}
+      }
+
+      if (released != 0) {
+	sp->size -= released;
+	m->footprint -= released;
+	init_top(m, m->top, m->topsize - released);
+	check_top_chunk(m, m->top);
+      }
+    }
+
+    /* Unmap any unused mmapped segments */
+    if (HAVE_MMAP)
+      released += release_unused_segments(m);
+
+    /* On failure, disable autotrim to avoid repeated failed future calls */
+    if (released == 0 && m->topsize > m->trim_check)
+      m->trim_check = MAX_SIZE_T;
+  }
+
+  return (released != 0)? 1 : 0;
+}
+
+
+/* ---------------------------- malloc support --------------------------- */
+
+/* allocate a large request from the best fitting chunk in a treebin */
+static void* tmalloc_large(mstate m, size_t nb) {
+  tchunkptr v = 0;
+  size_t rsize = -nb; /* Unsigned negation */
+  tchunkptr t;
+  bindex_t idx;
+  compute_tree_index(nb, idx);
+  if ((t = *treebin_at(m, idx)) != 0) {
+    /* Traverse tree for this bin looking for node with size == nb */
+    size_t sizebits = nb << leftshift_for_tree_index(idx);
+    tchunkptr rst = 0;  /* The deepest untaken right subtree */
+    for (;;) {
+      tchunkptr rt;
+      size_t trem = chunksize(t) - nb;
+      if (trem < rsize) {
+	v = t;
+	if ((rsize = trem) == 0)
+	  break;
+      }
+      rt = t->child[1];
+      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+      if (rt != 0 && rt != t)
+	rst = rt;
+      if (t == 0) {
+	t = rst; /* set t to least subtree holding sizes > nb */
+	break;
+      }
+      sizebits <<= 1;
+    }
+  }
+  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
+    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
+    if (leftbits != 0) {
+      bindex_t i;
+      binmap_t leastbit = least_bit(leftbits);
+      compute_bit2idx(leastbit, i);
+      t = *treebin_at(m, i);
+    }
+  }
+
+  while (t != 0) { /* find smallest of tree or subtree */
+    size_t trem = chunksize(t) - nb;
+    if (trem < rsize) {
+      rsize = trem;
+      v = t;
+    }
+    t = leftmost_child(t);
+  }
+
+  /*  If dv is a better fit, return 0 so malloc will use it */
+  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
+    if (RTCHECK(ok_address(m, v))) { /* split */
+      mchunkptr r = chunk_plus_offset(v, nb);
+      assert(chunksize(v) == rsize + nb);
+      if (RTCHECK(ok_next(v, r))) {
+	unlink_large_chunk(m, v);
+	if (rsize < MIN_CHUNK_SIZE)
+	  set_inuse_and_pinuse(m, v, (rsize + nb));
+	else {
+	  set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+	  set_size_and_pinuse_of_free_chunk(r, rsize);
+	  insert_chunk(m, r, rsize);
+	}
+	return chunk2mem(v);
+      }
+    }
+    CORRUPTION_ERROR_ACTION(m);
+  }
+  return 0;
+}
+
+/* allocate a small request from the best fitting chunk in a treebin */
+static void* tmalloc_small(mstate m, size_t nb) {
+  tchunkptr t, v;
+  size_t rsize;
+  bindex_t i;
+  binmap_t leastbit = least_bit(m->treemap);
+  compute_bit2idx(leastbit, i);
+  v = t = *treebin_at(m, i);
+  rsize = chunksize(t) - nb;
+
+  while ((t = leftmost_child(t)) != 0) {
+    size_t trem = chunksize(t) - nb;
+    if (trem < rsize) {
+      rsize = trem;
+      v = t;
+    }
+  }
+
+  if (RTCHECK(ok_address(m, v))) {
+    mchunkptr r = chunk_plus_offset(v, nb);
+    assert(chunksize(v) == rsize + nb);
+    if (RTCHECK(ok_next(v, r))) {
+      unlink_large_chunk(m, v);
+      if (rsize < MIN_CHUNK_SIZE)
+	set_inuse_and_pinuse(m, v, (rsize + nb));
+      else {
+	set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+	set_size_and_pinuse_of_free_chunk(r, rsize);
+	replace_dv(m, r, rsize);
+      }
+      return chunk2mem(v);
+    }
+  }
+
+  CORRUPTION_ERROR_ACTION(m);
+  return 0;
+}
+
+/* --------------------------- realloc support --------------------------- */
+
+static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
+  if (bytes >= MAX_REQUEST) {
+    MALLOC_FAILURE_ACTION;
+    return 0;
+  }
+  if (!PREACTION(m)) {
+    mchunkptr oldp = mem2chunk(oldmem);
+    size_t oldsize = chunksize(oldp);
+    mchunkptr next = chunk_plus_offset(oldp, oldsize);
+    mchunkptr newp = 0;
+    void* extra = 0;
+
+    /* Try to either shrink or extend into top. Else malloc-copy-free */
+
+    if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&
+		ok_next(oldp, next) && ok_pinuse(next))) {
+      size_t nb = request2size(bytes);
+      if (is_mmapped(oldp))
+	newp = mmap_resize(m, oldp, nb);
+      else if (oldsize >= nb) { /* already big enough */
+	size_t rsize = oldsize - nb;
+	newp = oldp;
+	if (rsize >= MIN_CHUNK_SIZE) {
+	  mchunkptr remainder = chunk_plus_offset(newp, nb);
+	  set_inuse(m, newp, nb);
+	  set_inuse(m, remainder, rsize);
+	  extra = chunk2mem(remainder);
+	}
+      }
+      else if (next == m->top && oldsize + m->topsize > nb) {
+	/* Expand into top */
+	size_t newsize = oldsize + m->topsize;
+	size_t newtopsize = newsize - nb;
+	mchunkptr newtop = chunk_plus_offset(oldp, nb);
+	set_inuse(m, oldp, nb);
+	newtop->head = newtopsize |PINUSE_BIT;
+	m->top = newtop;
+	m->topsize = newtopsize;
+	newp = oldp;
+      }
+    }
+    else {
+      USAGE_ERROR_ACTION(m, oldmem);
+      POSTACTION(m);
+      return 0;
+    }
+
+    POSTACTION(m);
+
+    if (newp != 0) {
+      if (extra != 0) {
+	internal_free(m, extra);
+      }
+      check_inuse_chunk(m, newp);
+      return chunk2mem(newp);
+    }
+    else {
+      void* newmem = internal_malloc(m, bytes);
+      if (newmem != 0) {
+	size_t oc = oldsize - overhead_for(oldp);
+	memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
+	internal_free(m, oldmem);
+      }
+      return newmem;
+    }
+  }
+  return 0;
+}
+
+/* --------------------------- memalign support -------------------------- */
+
+static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
+  if (alignment <= MALLOC_ALIGNMENT)    /* Can just use malloc */
+    return internal_malloc(m, bytes);
+  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
+    alignment = MIN_CHUNK_SIZE;
+  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
+    size_t a = MALLOC_ALIGNMENT << 1;
+    while (a < alignment) a <<= 1;
+    alignment = a;
+  }
+
+  if (bytes >= MAX_REQUEST - alignment) {
+    if (m != 0)  { /* Test isn't needed but avoids compiler warning */
+      MALLOC_FAILURE_ACTION;
+    }
+  }
+  else {
+    size_t nb = request2size(bytes);
+    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
+    char* mem = (char*)internal_malloc(m, req);
+    if (mem != 0) {
+      void* leader = 0;
+      void* trailer = 0;
+      mchunkptr p = mem2chunk(mem);
+
+      if (PREACTION(m)) return 0;
+      if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
+	/*
+	  Find an aligned spot inside chunk.  Since we need to give
+	  back leading space in a chunk of at least MIN_CHUNK_SIZE, if
+	  the first calculation places us at a spot with less than
+	  MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
+	  We've allocated enough total room so that this is always
+	  possible.
+	*/
+	char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
+						       alignment -
+						       SIZE_T_ONE)) &
+					     -alignment));
+	char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
+	  br : br+alignment;
+	mchunkptr newp = (mchunkptr)pos;
+	size_t leadsize = pos - (char*)(p);
+	size_t newsize = chunksize(p) - leadsize;
+
+	if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
+	  newp->prev_foot = p->prev_foot + leadsize;
+	  newp->head = (newsize|CINUSE_BIT);
+	}
+	else { /* Otherwise, give back leader, use the rest */
+	  set_inuse(m, newp, newsize);
+	  set_inuse(m, p, leadsize);
+	  leader = chunk2mem(p);
+	}
+	p = newp;
+      }
+
+      /* Give back spare room at the end */
+      if (!is_mmapped(p)) {
+	size_t size = chunksize(p);
+	if (size > nb + MIN_CHUNK_SIZE) {
+	  size_t remainder_size = size - nb;
+	  mchunkptr remainder = chunk_plus_offset(p, nb);
+	  set_inuse(m, p, nb);
+	  set_inuse(m, remainder, remainder_size);
+	  trailer = chunk2mem(remainder);
+	}
+      }
+
+      assert (chunksize(p) >= nb);
+      assert((((size_t)(chunk2mem(p))) % alignment) == 0);
+      check_inuse_chunk(m, p);
+      POSTACTION(m);
+      if (leader != 0) {
+	internal_free(m, leader);
+      }
+      if (trailer != 0) {
+	internal_free(m, trailer);
+      }
+      return chunk2mem(p);
+    }
+  }
+  return 0;
+}
+
+/* ------------------------ comalloc/coalloc support --------------------- */
+
+static void** ialloc(mstate m,
+		     size_t n_elements,
+		     size_t* sizes,
+		     int opts,
+		     void* chunks[]) {
+  /*
+    This provides common support for independent_X routines, handling
+    all of the combinations that can result.
+
+    The opts arg has:
+    bit 0 set if all elements are same size (using sizes[0])
+    bit 1 set if elements should be zeroed
+  */
+
+  size_t    element_size;   /* chunksize of each element, if all same */
+  size_t    contents_size;  /* total size of elements */
+  size_t    array_size;     /* request size of pointer array */
+  void*     mem;            /* malloced aggregate space */
+  mchunkptr p;              /* corresponding chunk */
+  size_t    remainder_size; /* remaining bytes while splitting */
+  void**    marray;         /* either "chunks" or malloced ptr array */
+  mchunkptr array_chunk;    /* chunk for malloced ptr array */
+  flag_t    was_enabled;    /* to disable mmap */
+  size_t    size;
+  size_t    i;
+
+  ensure_initialization();
+  /* compute array length, if needed */
+  if (chunks != 0) {
+    if (n_elements == 0)
+      return chunks; /* nothing to do */
+    marray = chunks;
+    array_size = 0;
+  }
+  else {
+    /* if empty req, must still return chunk representing empty array */
+    if (n_elements == 0)
+      return (void**)internal_malloc(m, 0);
+    marray = 0;
+    array_size = request2size(n_elements * (sizeof(void*)));
+  }
+
+  /* compute total element size */
+  if (opts & 0x1) { /* all-same-size */
+    element_size = request2size(*sizes);
+    contents_size = n_elements * element_size;
+  }
+  else { /* add up all the sizes */
+    element_size = 0;
+    contents_size = 0;
+    for (i = 0; i != n_elements; ++i)
+      contents_size += request2size(sizes[i]);
+  }
+
+  size = contents_size + array_size;
+
+  /*
+     Allocate the aggregate chunk.  First disable direct-mmapping so
+     malloc won't use it, since we would not be able to later
+     free/realloc space internal to a segregated mmap region.
+  */
+  was_enabled = use_mmap(m);
+  disable_mmap(m);
+  mem = internal_malloc(m, size - CHUNK_OVERHEAD);
+  if (was_enabled)
+    enable_mmap(m);
+  if (mem == 0)
+    return 0;
+
+  if (PREACTION(m)) return 0;
+  p = mem2chunk(mem);
+  remainder_size = chunksize(p);
+
+  assert(!is_mmapped(p));
+
+  if (opts & 0x2) {       /* optionally clear the elements */
+    memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
+  }
+
+  /* If not provided, allocate the pointer array as final part of chunk */
+  if (marray == 0) {
+    size_t  array_chunk_size;
+    array_chunk = chunk_plus_offset(p, contents_size);
+    array_chunk_size = remainder_size - contents_size;
+    marray = (void**) (chunk2mem(array_chunk));
+    set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
+    remainder_size = contents_size;
+  }
+
+  /* split out elements */
+  for (i = 0; ; ++i) {
+    marray[i] = chunk2mem(p);
+    if (i != n_elements-1) {
+      if (element_size != 0)
+	size = element_size;
+      else
+	size = request2size(sizes[i]);
+      remainder_size -= size;
+      set_size_and_pinuse_of_inuse_chunk(m, p, size);
+      p = chunk_plus_offset(p, size);
+    }
+    else { /* the final element absorbs any overallocation slop */
+      set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
+      break;
+    }
+  }
+
+#if DEBUG
+  if (marray != chunks) {
+    /* final element must have exactly exhausted chunk */
+    if (element_size != 0) {
+      assert(remainder_size == element_size);
+    }
+    else {
+      assert(remainder_size == request2size(sizes[i]));
+    }
+    check_inuse_chunk(m, mem2chunk(marray));
+  }
+  for (i = 0; i != n_elements; ++i)
+    check_inuse_chunk(m, mem2chunk(marray[i]));
+
+#endif /* DEBUG */
+
+  POSTACTION(m);
+  return marray;
+}
+
+
+/* -------------------------- public routines ---------------------------- */
+
+#if !ONLY_MSPACES
+
+void* dlmalloc(size_t bytes) {
+  /*
+     Basic algorithm:
+     If a small request (< 256 bytes minus per-chunk overhead):
+       1. If one exists, use a remainderless chunk in associated smallbin.
+	  (Remainderless means that there are too few excess bytes to
+	  represent as a chunk.)
+       2. If it is big enough, use the dv chunk, which is normally the
+	  chunk adjacent to the one used for the most recent small request.
+       3. If one exists, split the smallest available chunk in a bin,
+	  saving remainder in dv.
+       4. If it is big enough, use the top chunk.
+       5. If available, get memory from system and use it
+     Otherwise, for a large request:
+       1. Find the smallest available binned chunk that fits, and use it
+	  if it is better fitting than dv chunk, splitting if necessary.
+       2. If better fitting than any binned chunk, use the dv chunk.
+       3. If it is big enough, use the top chunk.
+       4. If request size >= mmap threshold, try to directly mmap this chunk.
+       5. If available, get memory from system and use it
+
+     The ugly goto's here ensure that postaction occurs along all paths.
+  */
+
+#if USE_LOCKS
+  ensure_initialization(); /* initialize in sys_alloc if not using locks */
+#endif
+
+  if (!PREACTION(gm)) {
+    void* mem;
+    size_t nb;
+    if (bytes <= MAX_SMALL_REQUEST) {
+      bindex_t idx;
+      binmap_t smallbits;
+      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+      idx = small_index(nb);
+      smallbits = gm->smallmap >> idx;
+
+      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+	mchunkptr b, p;
+	idx += ~smallbits & 1;       /* Uses next bin if idx empty */
+	b = smallbin_at(gm, idx);
+	p = b->fd;
+	assert(chunksize(p) == small_index2size(idx));
+	unlink_first_small_chunk(gm, b, p, idx);
+	set_inuse_and_pinuse(gm, p, small_index2size(idx));
+	mem = chunk2mem(p);
+	check_malloced_chunk(gm, mem, nb);
+	goto postaction;
+      }
+
+      else if (nb > gm->dvsize) {
+	if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+	  mchunkptr b, p, r;
+	  size_t rsize;
+	  bindex_t i;
+	  binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+	  binmap_t leastbit = least_bit(leftbits);
+	  compute_bit2idx(leastbit, i);
+	  b = smallbin_at(gm, i);
+	  p = b->fd;
+	  assert(chunksize(p) == small_index2size(i));
+	  unlink_first_small_chunk(gm, b, p, i);
+	  rsize = small_index2size(i) - nb;
+	  /* Fit here cannot be remainderless if 4byte sizes */
+	  if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+	    set_inuse_and_pinuse(gm, p, small_index2size(i));
+	  else {
+	    set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+	    r = chunk_plus_offset(p, nb);
+	    set_size_and_pinuse_of_free_chunk(r, rsize);
+	    replace_dv(gm, r, rsize);
+	  }
+	  mem = chunk2mem(p);
+	  check_malloced_chunk(gm, mem, nb);
+	  goto postaction;
+	}
+
+	else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
+	  check_malloced_chunk(gm, mem, nb);
+	  goto postaction;
+	}
+      }
+    }
+    else if (bytes >= MAX_REQUEST)
+      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+    else {
+      nb = pad_request(bytes);
+      if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
+	check_malloced_chunk(gm, mem, nb);
+	goto postaction;
+      }
+    }
+
+    if (nb <= gm->dvsize) {
+      size_t rsize = gm->dvsize - nb;
+      mchunkptr p = gm->dv;
+      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+	mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
+	gm->dvsize = rsize;
+	set_size_and_pinuse_of_free_chunk(r, rsize);
+	set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+      }
+      else { /* exhaust dv */
+	size_t dvs = gm->dvsize;
+	gm->dvsize = 0;
+	gm->dv = 0;
+	set_inuse_and_pinuse(gm, p, dvs);
+      }
+      mem = chunk2mem(p);
+      check_malloced_chunk(gm, mem, nb);
+      goto postaction;
+    }
+
+    else if (nb < gm->topsize) { /* Split top */
+      size_t rsize = gm->topsize -= nb;
+      mchunkptr p = gm->top;
+      mchunkptr r = gm->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+      mem = chunk2mem(p);
+      check_top_chunk(gm, gm->top);
+      check_malloced_chunk(gm, mem, nb);
+      goto postaction;
+    }
+
+    mem = sys_alloc(gm, nb);
+
+  postaction:
+    POSTACTION(gm);
+    return mem;
+  }
+
+  return 0;
+}
+
+void dlfree(void* mem) {
+  /*
+     Consolidate freed chunks with preceding or succeeding bordering
+     free chunks, if they exist, and then place in a bin.  Intermixed
+     with special cases for top, dv, mmapped chunks, and usage errors.
+  */
+
+  if (mem != 0) {
+    mchunkptr p  = mem2chunk(mem);
+#if FOOTERS
+    mstate fm = get_mstate_for(p);
+    if (!ok_magic(fm)) {
+      USAGE_ERROR_ACTION(fm, p);
+      return;
+    }
+#else /* FOOTERS */
+#define fm gm
+#endif /* FOOTERS */
+    if (!PREACTION(fm)) {
+      check_inuse_chunk(fm, p);
+      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
+	size_t psize = chunksize(p);
+	mchunkptr next = chunk_plus_offset(p, psize);
+	if (!pinuse(p)) {
+	  size_t prevsize = p->prev_foot;
+	  if ((prevsize & IS_MMAPPED_BIT) != 0) {
+	    prevsize &= ~IS_MMAPPED_BIT;
+	    psize += prevsize + MMAP_FOOT_PAD;
+	    if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+	      fm->footprint -= psize;
+	    goto postaction;
+	  }
+	  else {
+	    mchunkptr prev = chunk_minus_offset(p, prevsize);
+	    psize += prevsize;
+	    p = prev;
+	    if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+	      if (p != fm->dv) {
+		unlink_chunk(fm, p, prevsize);
+	      }
+	      else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+		fm->dvsize = psize;
+		set_free_with_pinuse(p, psize, next);
+		goto postaction;
+	      }
+	    }
+	    else
+	      goto erroraction;
+	  }
+	}
+
+	if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+	  if (!cinuse(next)) {  /* consolidate forward */
+	    if (next == fm->top) {
+	      size_t tsize = fm->topsize += psize;
+	      fm->top = p;
+	      p->head = tsize | PINUSE_BIT;
+	      if (p == fm->dv) {
+		fm->dv = 0;
+		fm->dvsize = 0;
+	      }
+	      if (should_trim(fm, tsize))
+		sys_trim(fm, 0);
+	      goto postaction;
+	    }
+	    else if (next == fm->dv) {
+	      size_t dsize = fm->dvsize += psize;
+	      fm->dv = p;
+	      set_size_and_pinuse_of_free_chunk(p, dsize);
+	      goto postaction;
+	    }
+	    else {
+	      size_t nsize = chunksize(next);
+	      psize += nsize;
+	      unlink_chunk(fm, next, nsize);
+	      set_size_and_pinuse_of_free_chunk(p, psize);
+	      if (p == fm->dv) {
+		fm->dvsize = psize;
+		goto postaction;
+	      }
+	    }
+	  }
+	  else
+	    set_free_with_pinuse(p, psize, next);
+
+	  if (is_small(psize)) {
+	    insert_small_chunk(fm, p, psize);
+	    check_free_chunk(fm, p);
+	  }
+	  else {
+	    tchunkptr tp = (tchunkptr)p;
+	    insert_large_chunk(fm, tp, psize);
+	    check_free_chunk(fm, p);
+	    if (--fm->release_checks == 0)
+	      release_unused_segments(fm);
+	  }
+	  goto postaction;
+	}
+      }
+    erroraction:
+      USAGE_ERROR_ACTION(fm, p);
+    postaction:
+      POSTACTION(fm);
+    }
+  }
+#if !FOOTERS
+#undef fm
+#endif /* FOOTERS */
+}
+
+void* dlcalloc(size_t n_elements, size_t elem_size) {
+  void* mem;
+  size_t req = 0;
+  if (n_elements != 0) {
+    req = n_elements * elem_size;
+    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+	(req / n_elements != elem_size))
+      req = MAX_SIZE_T; /* force downstream failure on overflow */
+  }
+  mem = dlmalloc(req);
+  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+    memset(mem, 0, req);
+  return mem;
+}
+
+void* dlrealloc(void* oldmem, size_t bytes) {
+  if (oldmem == 0)
+    return dlmalloc(bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) {
+    dlfree(oldmem);
+    return 0;
+  }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+  else {
+#if ! FOOTERS
+    mstate m = gm;
+#else /* FOOTERS */
+    mstate m = get_mstate_for(mem2chunk(oldmem));
+    if (!ok_magic(m)) {
+      USAGE_ERROR_ACTION(m, oldmem);
+      return 0;
+    }
+#endif /* FOOTERS */
+    return internal_realloc(m, oldmem, bytes);
+  }
+}
+
+void* dlmemalign(size_t alignment, size_t bytes) {
+  return internal_memalign(gm, alignment, bytes);
+}
+
+void** dlindependent_calloc(size_t n_elements, size_t elem_size,
+				 void* chunks[]) {
+  size_t sz = elem_size; /* serves as 1-element array */
+  return ialloc(gm, n_elements, &sz, 3, chunks);
+}
+
+void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
+				   void* chunks[]) {
+  return ialloc(gm, n_elements, sizes, 0, chunks);
+}
+
+void* dlvalloc(size_t bytes) {
+  size_t pagesz;
+  ensure_initialization();
+  pagesz = mparams.page_size;
+  return dlmemalign(pagesz, bytes);
+}
+
+void* dlpvalloc(size_t bytes) {
+  size_t pagesz;
+  ensure_initialization();
+  pagesz = mparams.page_size;
+  return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
+}
+
+int dlmalloc_trim(size_t pad) {
+  ensure_initialization();
+  int result = 0;
+  if (!PREACTION(gm)) {
+    result = sys_trim(gm, pad);
+    POSTACTION(gm);
+  }
+  return result;
+}
+
+size_t dlmalloc_footprint(void) {
+  return gm->footprint;
+}
+
+size_t dlmalloc_max_footprint(void) {
+  return gm->max_footprint;
+}
+
+#if !NO_MALLINFO
+struct mallinfo dlmallinfo(void) {
+  return internal_mallinfo(gm);
+}
+#endif /* NO_MALLINFO */
+
+void dlmalloc_stats() {
+  internal_malloc_stats(gm);
+}
+
+int dlmallopt(int param_number, int value) {
+  return change_mparam(param_number, value);
+}
+
+#endif /* !ONLY_MSPACES */
+
+size_t dlmalloc_usable_size(void* mem) {
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    if (cinuse(p))
+      return chunksize(p) - overhead_for(p);
+  }
+  return 0;
+}
+
+/* ----------------------------- user mspaces ---------------------------- */
+
+#if MSPACES
+
+static mstate init_user_mstate(char* tbase, size_t tsize) {
+  size_t msize = pad_request(sizeof(struct malloc_state));
+  mchunkptr mn;
+  mchunkptr msp = align_as_chunk(tbase);
+  mstate m = (mstate)(chunk2mem(msp));
+  memset(m, 0, msize);
+  (void)INITIAL_LOCK(&m->mutex);
+  msp->head = (msize|PINUSE_BIT|CINUSE_BIT);
+  m->seg.base = m->least_addr = tbase;
+  m->seg.size = m->footprint = m->max_footprint = tsize;
+  m->magic = mparams.magic;
+  m->release_checks = MAX_RELEASE_CHECK_RATE;
+  m->mflags = mparams.default_mflags;
+  m->extp = 0;
+  m->exts = 0;
+  disable_contiguous(m);
+  init_bins(m);
+  mn = next_chunk(mem2chunk(m));
+  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
+  check_top_chunk(m, m->top);
+  return m;
+}
+
+mspace create_mspace(size_t capacity, int locked) {
+  mstate m = 0;
+  size_t msize;
+  ensure_initialization();
+  msize = pad_request(sizeof(struct malloc_state));
+  if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+    size_t rs = ((capacity == 0)? mparams.granularity :
+		 (capacity + TOP_FOOT_SIZE + msize));
+    size_t tsize = granularity_align(rs);
+    char* tbase = (char*)(CALL_MMAP(tsize));
+    if (tbase != CMFAIL) {
+      m = init_user_mstate(tbase, tsize);
+      m->seg.sflags = IS_MMAPPED_BIT;
+      set_lock(m, locked);
+    }
+  }
+  return (mspace)m;
+}
+
+mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
+  mstate m = 0;
+  size_t msize;
+  ensure_initialization();
+  msize = pad_request(sizeof(struct malloc_state));
+  if (capacity > msize + TOP_FOOT_SIZE &&
+      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+    m = init_user_mstate((char*)base, capacity);
+    m->seg.sflags = EXTERN_BIT;
+    set_lock(m, locked);
+  }
+  return (mspace)m;
+}
+
+int mspace_mmap_large_chunks(mspace msp, int enable) {
+  int ret = 0;
+  mstate ms = (mstate)msp;
+  if (!PREACTION(ms)) {
+    if (use_mmap(ms))
+      ret = 1;
+    if (enable)
+      enable_mmap(ms);
+    else
+      disable_mmap(ms);
+    POSTACTION(ms);
+  }
+  return ret;
+}
+
+size_t destroy_mspace(mspace msp) {
+  size_t freed = 0;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    msegmentptr sp = &ms->seg;
+    while (sp != 0) {
+      char* base = sp->base;
+      size_t size = sp->size;
+      flag_t flag = sp->sflags;
+      sp = sp->next;
+      if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) &&
+	  CALL_MUNMAP(base, size) == 0)
+	freed += size;
+    }
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return freed;
+}
+
+/*
+  mspace versions of routines are near-clones of the global
+  versions. This is not so nice but better than the alternatives.
+*/
+
+
+void* mspace_malloc(mspace msp, size_t bytes) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  if (!PREACTION(ms)) {
+    void* mem;
+    size_t nb;
+    if (bytes <= MAX_SMALL_REQUEST) {
+      bindex_t idx;
+      binmap_t smallbits;
+      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+      idx = small_index(nb);
+      smallbits = ms->smallmap >> idx;
+
+      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+	mchunkptr b, p;
+	idx += ~smallbits & 1;       /* Uses next bin if idx empty */
+	b = smallbin_at(ms, idx);
+	p = b->fd;
+	assert(chunksize(p) == small_index2size(idx));
+	unlink_first_small_chunk(ms, b, p, idx);
+	set_inuse_and_pinuse(ms, p, small_index2size(idx));
+	mem = chunk2mem(p);
+	check_malloced_chunk(ms, mem, nb);
+	goto postaction;
+      }
+
+      else if (nb > ms->dvsize) {
+	if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+	  mchunkptr b, p, r;
+	  size_t rsize;
+	  bindex_t i;
+	  binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+	  binmap_t leastbit = least_bit(leftbits);
+	  compute_bit2idx(leastbit, i);
+	  b = smallbin_at(ms, i);
+	  p = b->fd;
+	  assert(chunksize(p) == small_index2size(i));
+	  unlink_first_small_chunk(ms, b, p, i);
+	  rsize = small_index2size(i) - nb;
+	  /* Fit here cannot be remainderless if 4byte sizes */
+	  if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+	    set_inuse_and_pinuse(ms, p, small_index2size(i));
+	  else {
+	    set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+	    r = chunk_plus_offset(p, nb);
+	    set_size_and_pinuse_of_free_chunk(r, rsize);
+	    replace_dv(ms, r, rsize);
+	  }
+	  mem = chunk2mem(p);
+	  check_malloced_chunk(ms, mem, nb);
+	  goto postaction;
+	}
+
+	else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
+	  check_malloced_chunk(ms, mem, nb);
+	  goto postaction;
+	}
+      }
+    }
+    else if (bytes >= MAX_REQUEST)
+      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+    else {
+      nb = pad_request(bytes);
+      if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
+	check_malloced_chunk(ms, mem, nb);
+	goto postaction;
+      }
+    }
+
+    if (nb <= ms->dvsize) {
+      size_t rsize = ms->dvsize - nb;
+      mchunkptr p = ms->dv;
+      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+	mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
+	ms->dvsize = rsize;
+	set_size_and_pinuse_of_free_chunk(r, rsize);
+	set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+      }
+      else { /* exhaust dv */
+	size_t dvs = ms->dvsize;
+	ms->dvsize = 0;
+	ms->dv = 0;
+	set_inuse_and_pinuse(ms, p, dvs);
+      }
+      mem = chunk2mem(p);
+      check_malloced_chunk(ms, mem, nb);
+      goto postaction;
+    }
+
+    else if (nb < ms->topsize) { /* Split top */
+      size_t rsize = ms->topsize -= nb;
+      mchunkptr p = ms->top;
+      mchunkptr r = ms->top = chunk_plus_offset(p, nb);
+      r->head = rsize | PINUSE_BIT;
+      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+      mem = chunk2mem(p);
+      check_top_chunk(ms, ms->top);
+      check_malloced_chunk(ms, mem, nb);
+      goto postaction;
+    }
+
+    mem = sys_alloc(ms, nb);
+
+  postaction:
+    POSTACTION(ms);
+    return mem;
+  }
+
+  return 0;
+}
+
+void mspace_free(mspace msp, void* mem) {
+  if (mem != 0) {
+    mchunkptr p  = mem2chunk(mem);
+#if FOOTERS
+    mstate fm = get_mstate_for(p);
+#else /* FOOTERS */
+    mstate fm = (mstate)msp;
+#endif /* FOOTERS */
+    if (!ok_magic(fm)) {
+      USAGE_ERROR_ACTION(fm, p);
+      return;
+    }
+    if (!PREACTION(fm)) {
+      check_inuse_chunk(fm, p);
+      if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
+	size_t psize = chunksize(p);
+	mchunkptr next = chunk_plus_offset(p, psize);
+	if (!pinuse(p)) {
+	  size_t prevsize = p->prev_foot;
+	  if ((prevsize & IS_MMAPPED_BIT) != 0) {
+	    prevsize &= ~IS_MMAPPED_BIT;
+	    psize += prevsize + MMAP_FOOT_PAD;
+	    if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+	      fm->footprint -= psize;
+	    goto postaction;
+	  }
+	  else {
+	    mchunkptr prev = chunk_minus_offset(p, prevsize);
+	    psize += prevsize;
+	    p = prev;
+	    if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+	      if (p != fm->dv) {
+		unlink_chunk(fm, p, prevsize);
+	      }
+	      else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+		fm->dvsize = psize;
+		set_free_with_pinuse(p, psize, next);
+		goto postaction;
+	      }
+	    }
+	    else
+	      goto erroraction;
+	  }
+	}
+
+	if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+	  if (!cinuse(next)) {  /* consolidate forward */
+	    if (next == fm->top) {
+	      size_t tsize = fm->topsize += psize;
+	      fm->top = p;
+	      p->head = tsize | PINUSE_BIT;
+	      if (p == fm->dv) {
+		fm->dv = 0;
+		fm->dvsize = 0;
+	      }
+	      if (should_trim(fm, tsize))
+		sys_trim(fm, 0);
+	      goto postaction;
+	    }
+	    else if (next == fm->dv) {
+	      size_t dsize = fm->dvsize += psize;
+	      fm->dv = p;
+	      set_size_and_pinuse_of_free_chunk(p, dsize);
+	      goto postaction;
+	    }
+	    else {
+	      size_t nsize = chunksize(next);
+	      psize += nsize;
+	      unlink_chunk(fm, next, nsize);
+	      set_size_and_pinuse_of_free_chunk(p, psize);
+	      if (p == fm->dv) {
+		fm->dvsize = psize;
+		goto postaction;
+	      }
+	    }
+	  }
+	  else
+	    set_free_with_pinuse(p, psize, next);
+
+	  if (is_small(psize)) {
+	    insert_small_chunk(fm, p, psize);
+	    check_free_chunk(fm, p);
+	  }
+	  else {
+	    tchunkptr tp = (tchunkptr)p;
+	    insert_large_chunk(fm, tp, psize);
+	    check_free_chunk(fm, p);
+	    if (--fm->release_checks == 0)
+	      release_unused_segments(fm);
+	  }
+	  goto postaction;
+	}
+      }
+    erroraction:
+      USAGE_ERROR_ACTION(fm, p);
+    postaction:
+      POSTACTION(fm);
+    }
+  }
+}
+
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
+  void* mem;
+  size_t req = 0;
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  if (n_elements != 0) {
+    req = n_elements * elem_size;
+    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+	(req / n_elements != elem_size))
+      req = MAX_SIZE_T; /* force downstream failure on overflow */
+  }
+  mem = internal_malloc(ms, req);
+  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+    memset(mem, 0, req);
+  return mem;
+}
+
+void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
+  if (oldmem == 0)
+    return mspace_malloc(msp, bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+  if (bytes == 0) {
+    mspace_free(msp, oldmem);
+    return 0;
+  }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+  else {
+#if FOOTERS
+    mchunkptr p  = mem2chunk(oldmem);
+    mstate ms = get_mstate_for(p);
+#else /* FOOTERS */
+    mstate ms = (mstate)msp;
+#endif /* FOOTERS */
+    if (!ok_magic(ms)) {
+      USAGE_ERROR_ACTION(ms,ms);
+      return 0;
+    }
+    return internal_realloc(ms, oldmem, bytes);
+  }
+}
+
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return internal_memalign(ms, alignment, bytes);
+}
+
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+				 size_t elem_size, void* chunks[]) {
+  size_t sz = elem_size; /* serves as 1-element array */
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return ialloc(ms, n_elements, &sz, 3, chunks);
+}
+
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+				   size_t sizes[], void* chunks[]) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+    return 0;
+  }
+  return ialloc(ms, n_elements, sizes, 0, chunks);
+}
+
+int mspace_trim(mspace msp, size_t pad) {
+  int result = 0;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    if (!PREACTION(ms)) {
+      result = sys_trim(ms, pad);
+      POSTACTION(ms);
+    }
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return result;
+}
+
+void mspace_malloc_stats(mspace msp) {
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    internal_malloc_stats(ms);
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+}
+
+size_t mspace_footprint(mspace msp) {
+  size_t result = 0;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    result = ms->footprint;
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return result;
+}
+
+
+size_t mspace_max_footprint(mspace msp) {
+  size_t result = 0;
+  mstate ms = (mstate)msp;
+  if (ok_magic(ms)) {
+    result = ms->max_footprint;
+  }
+  else {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return result;
+}
+
+
+#if !NO_MALLINFO
+struct mallinfo mspace_mallinfo(mspace msp) {
+  mstate ms = (mstate)msp;
+  if (!ok_magic(ms)) {
+    USAGE_ERROR_ACTION(ms,ms);
+  }
+  return internal_mallinfo(ms);
+}
+#endif /* NO_MALLINFO */
+
+size_t mspace_usable_size(void* mem) {
+  if (mem != 0) {
+    mchunkptr p = mem2chunk(mem);
+    if (cinuse(p))
+      return chunksize(p) - overhead_for(p);
+  }
+  return 0;
+}
+
+int mspace_mallopt(int param_number, int value) {
+  return change_mparam(param_number, value);
+}
+
+#endif /* MSPACES */
+
+/* -------------------- Alternative MORECORE functions ------------------- */
+
+/*
+  Guidelines for creating a custom version of MORECORE:
+
+  * For best performance, MORECORE should allocate in multiples of pagesize.
+  * MORECORE may allocate more memory than requested. (Or even less,
+      but this will usually result in a malloc failure.)
+  * MORECORE must not allocate memory when given argument zero, but
+      instead return one past the end address of memory from previous
+      nonzero call.
+  * For best performance, consecutive calls to MORECORE with positive
+      arguments should return increasing addresses, indicating that
+      space has been contiguously extended.
+  * Even though consecutive calls to MORECORE need not return contiguous
+      addresses, it must be OK for malloc'ed chunks to span multiple
+      regions in those cases where they do happen to be contiguous.
+  * MORECORE need not handle negative arguments -- it may instead
+      just return MFAIL when given negative arguments.
+      Negative arguments are always multiples of pagesize. MORECORE
+      must not misinterpret negative args as large positive unsigned
+      args. You can suppress all such calls from even occurring by defining
+      MORECORE_CANNOT_TRIM,
+
+  As an example alternative MORECORE, here is a custom allocator
+  kindly contributed for pre-OSX macOS.  It uses virtually but not
+  necessarily physically contiguous non-paged memory (locked in,
+  present and won't get swapped out).  You can use it by uncommenting
+  this section, adding some #includes, and setting up the appropriate
+  defines above:
+
+      #define MORECORE osMoreCore
+
+  There is also a shutdown routine that should somehow be called for
+  cleanup upon program exit.
+
+  #define MAX_POOL_ENTRIES 100
+  #define MINIMUM_MORECORE_SIZE  (64 * 1024U)
+  static int next_os_pool;
+  void *our_os_pools[MAX_POOL_ENTRIES];
+
+  void *osMoreCore(int size)
+  {
+    void *ptr = 0;
+    static void *sbrk_top = 0;
+
+    if (size > 0)
+    {
+      if (size < MINIMUM_MORECORE_SIZE)
+	 size = MINIMUM_MORECORE_SIZE;
+      if (CurrentExecutionLevel() == kTaskLevel)
+	 ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+      if (ptr == 0)
+      {
+	return (void *) MFAIL;
+      }
+      // save ptrs so they can be freed during cleanup
+      our_os_pools[next_os_pool] = ptr;
+      next_os_pool++;
+      ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+      sbrk_top = (char *) ptr + size;
+      return ptr;
+    }
+    else if (size < 0)
+    {
+      // we don't currently support shrink behavior
+      return (void *) MFAIL;
+    }
+    else
+    {
+      return sbrk_top;
+    }
+  }
+
+  // cleanup any allocated memory pools
+  // called as last thing before shutting down driver
+
+  void osCleanupMem(void)
+  {
+    void **ptr;
+
+    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+      if (*ptr)
+      {
+	 PoolDeallocate(*ptr);
+	 *ptr = 0;
+      }
+  }
+
+*/
+
+
+/* -----------------------------------------------------------------------
+History:
+    V2.8.4 (not yet released)
+      * Add mspace_mmap_large_chunks; thanks to Jean Brouwers
+      * Fix insufficient sys_alloc padding when using 16byte alignment
+      * Fix bad error check in mspace_footprint
+      * Adaptations for ptmalloc, courtesy of Wolfram Gloger.
+      * Reentrant spin locks, courtesy of Earl Chew and others
+      * Win32 improvements, courtesy of Niall Douglas and Earl Chew
+      * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options
+      * Extension hook in malloc_state
+      * Various small adjustments to reduce warnings on some compilers
+      * Various configuration extensions/changes for more platforms. Thanks
+	 to all who contributed these.
+
+    V2.8.3 Thu Sep 22 11:16:32 2005  Doug Lea  (dl at gee)
+      * Add max_footprint functions
+      * Ensure all appropriate literals are size_t
+      * Fix conditional compilation problem for some #define settings
+      * Avoid concatenating segments with the one provided
+	in create_mspace_with_base
+      * Rename some variables to avoid compiler shadowing warnings
+      * Use explicit lock initialization.
+      * Better handling of sbrk interference.
+      * Simplify and fix segment insertion, trimming and mspace_destroy
+      * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
+      * Thanks especially to Dennis Flanagan for help on these.
+
+    V2.8.2 Sun Jun 12 16:01:10 2005  Doug Lea  (dl at gee)
+      * Fix memalign brace error.
+
+    V2.8.1 Wed Jun  8 16:11:46 2005  Doug Lea  (dl at gee)
+      * Fix improper #endif nesting in C++
+      * Add explicit casts needed for C++
+
+    V2.8.0 Mon May 30 14:09:02 2005  Doug Lea  (dl at gee)
+      * Use trees for large bins
+      * Support mspaces
+      * Use segments to unify sbrk-based and mmap-based system allocation,
+	removing need for emulation on most platforms without sbrk.
+      * Default safety checks
+      * Optional footer checks. Thanks to William Robertson for the idea.
+      * Internal code refactoring
+      * Incorporate suggestions and platform-specific changes.
+	Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
+	Aaron Bachmann,  Emery Berger, and others.
+      * Speed up non-fastbin processing enough to remove fastbins.
+      * Remove useless cfree() to avoid conflicts with other apps.
+      * Remove internal memcpy, memset. Compilers handle builtins better.
+      * Remove some options that no one ever used and rename others.
+
+    V2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)
+      * Fix malloc_state bitmap array misdeclaration
+
+    V2.7.1 Thu Jul 25 10:58:03 2002  Doug Lea  (dl at gee)
+      * Allow tuning of FIRST_SORTED_BIN_SIZE
+      * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
+      * Better detection and support for non-contiguousness of MORECORE.
+	Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
+      * Bypass most of malloc if no frees. Thanks To Emery Berger.
+      * Fix freeing of old top non-contiguous chunk im sysmalloc.
+      * Raised default trim and map thresholds to 256K.
+      * Fix mmap-related #defines. Thanks to Lubos Lunak.
+      * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
+      * Branch-free bin calculation
+      * Default trim and mmap thresholds now 256K.
+
+    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)
+      * Introduce independent_comalloc and independent_calloc.
+	Thanks to Michael Pachos for motivation and help.
+      * Make optional .h file available
+      * Allow > 2GB requests on 32bit systems.
+      * new WIN32 sbrk, mmap, munmap, lock code from <Walter@xxxxxxxxxxxx>.
+	Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
+	and Anonymous.
+      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
+	helping test this.)
+      * memalign: check alignment arg
+      * realloc: don't try to shift chunks backwards, since this
+	leads to  more fragmentation in some programs and doesn't
+	seem to help in any others.
+      * Collect all cases in malloc requiring system memory into sysmalloc
+      * Use mmap as backup to sbrk
+      * Place all internal state in malloc_state
+      * Introduce fastbins (although similar to 2.5.1)
+      * Many minor tunings and cosmetic improvements
+      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
+      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
+	Thanks to Tony E. Bennett <tbennett@xxxxxxxxxx> and others.
+      * Include errno.h to support default failure action.
+
+    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
+      * return null for negative arguments
+      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
+	 * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+	  (e.g. WIN32 platforms)
+	 * Cleanup header file inclusion for WIN32 platforms
+	 * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+	 * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+	   memory allocation routines
+	 * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+	 * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+	   usage of 'assert' in non-WIN32 code
+	 * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+	   avoid infinite loop
+      * Always call 'fREe()' rather than 'free()'
+
+    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
+      * Fixed ordering problem with boundary-stamping
+
+    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
+      * Added pvalloc, as recommended by H.J. Liu
+      * Added 64bit pointer support mainly from Wolfram Gloger
+      * Added anonymously donated WIN32 sbrk emulation
+      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+      * malloc_extend_top: fix mask error that caused wastage after
+	foreign sbrks
+      * Add linux mremap support code from HJ Liu
+
+    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
+      * Integrated most documentation with the code.
+      * Add support for mmap, with help from
+	Wolfram Gloger (Gloger@xxxxxxxxxxxxxxxxxxx).
+      * Use last_remainder in more cases.
+      * Pack bins using idea from  colin@xxxxxxxxxxxxxxx
+      * Use ordered bins instead of best-fit threshold
+      * Eliminate block-local decls to simplify tracing and debugging.
+      * Support another case of realloc via move into top
+      * Fix error occurring when initial sbrk_base not word-aligned.
+      * Rely on page size for units instead of SBRK_UNIT to
+	avoid surprises about sbrk alignment conventions.
+      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+	(raymond@xxxxxxxxxxxxx) for the suggestion.
+      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+      * More precautions for cases where other routines call sbrk,
+	courtesy of Wolfram Gloger (Gloger@xxxxxxxxxxxxxxxxxxx).
+      * Added macros etc., allowing use in linux libc from
+	H.J. Lu (hjl@xxxxxxxxxxxxxx)
+      * Inverted this history list
+
+    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
+      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+      * Removed all preallocation code since under current scheme
+	the work required to undo bad preallocations exceeds
+	the work saved in good cases for most test programs.
+      * No longer use return list or unconsolidated bins since
+	no scheme using them consistently outperforms those that don't
+	given above changes.
+      * Use best fit for very large chunks to prevent some worst-cases.
+      * Added some support for debugging
+
+    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
+      * Removed footers when chunks are in use. Thanks to
+	Paul Wilson (wilson@xxxxxxxxxxxx) for the suggestion.
+
+    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
+      * Added malloc_trim, with help from Wolfram Gloger
+	(wmglo@xxxxxxxxxxxxxxxxxxxxxxxx).
+
+    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
+
+    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
+      * realloc: try to expand in both directions
+      * malloc: swap order of clean-bin strategy;
+      * realloc: only conditionally expand backwards
+      * Try not to scavenge used bins
+      * Use bin counts as a guide to preallocation
+      * Occasionally bin return list chunks in first scan
+      * Add a few optimizations from colin@xxxxxxxxxxxxxxx
+
+    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
+      * faster bin computation & slightly different binning
+      * merged all consolidations to one part of malloc proper
+	 (eliminating old malloc_find_space & malloc_clean_bin)
+      * Scan 2 returns chunks (not just 1)
+      * Propagate failure in realloc if malloc returns 0
+      * Add stuff to allow compilation on non-ANSI compilers
+	  from kpv@xxxxxxxxxxxxxxxx
+
+    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
+      * removed potential for odd address access in prev_chunk
+      * removed dependency on getpagesize.h
+      * misc cosmetics and a bit more internal documentation
+      * anticosmetics: mangled names in macros to evade debugger strangeness
+      * tested on sparc, hp-700, dec-mips, rs6000
+	  with gcc & native cc (hp, dec only) allowing
+	  Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
+      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+	 structure of old version,  but most details differ.)
+
+*/
diff --git a/compat/nedmalloc/nedmalloc.c b/compat/nedmalloc/nedmalloc.c
new file mode 100644
index 0000000000..145255da43
--- /dev/null
+++ b/compat/nedmalloc/nedmalloc.c
@@ -0,0 +1,954 @@
+/* Alternative malloc implementation for multiple threads without
+lock contention based on dlmalloc. (C) 2005-2006 Niall Douglas
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef _MSC_VER
+/* Enable full aliasing on MSVC */
+/*#pragma optimize("a", on)*/
+#endif
+
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+/*#define FULLSANITYCHECKS*/
+
+#include "nedmalloc.h"
+#if defined(WIN32)
+ #include <malloc.h>
+#endif
+#define MSPACES 1
+#define ONLY_MSPACES 1
+#ifndef USE_LOCKS
+ #define USE_LOCKS 1
+#endif
+#define FOOTERS 1           /* Need to enable footers so frees lock the right mspace */
+#undef DEBUG				/* dlmalloc wants DEBUG either 0 or 1 */
+#ifdef _DEBUG
+ #define DEBUG 1
+#else
+ #define DEBUG 0
+#endif
+#ifdef NDEBUG               /* Disable assert checking on release builds */
+ #undef DEBUG
+#endif
+/* The default of 64Kb means we spend too much time kernel-side */
+#ifndef DEFAULT_GRANULARITY
+#define DEFAULT_GRANULARITY (1*1024*1024)
+#endif
+/*#define USE_SPIN_LOCKS 0*/
+
+
+/*#define FORCEINLINE*/
+#include "malloc.c.h"
+#ifdef NDEBUG               /* Disable assert checking on release builds */
+ #undef DEBUG
+#endif
+
+/* The maximum concurrent threads in a pool possible */
+#ifndef MAXTHREADSINPOOL
+#define MAXTHREADSINPOOL 16
+#endif
+/* The maximum number of threadcaches which can be allocated */
+#ifndef THREADCACHEMAXCACHES
+#define THREADCACHEMAXCACHES 256
+#endif
+/* The maximum size to be allocated from the thread cache */
+#ifndef THREADCACHEMAX
+#define THREADCACHEMAX 8192
+#endif
+#if 0
+/* The number of cache entries for finer grained bins. This is (topbitpos(THREADCACHEMAX)-4)*2 */
+#define THREADCACHEMAXBINS ((13-4)*2)
+#else
+/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */
+#define THREADCACHEMAXBINS (13-4)
+#endif
+/* Point at which the free space in a thread cache is garbage collected */
+#ifndef THREADCACHEMAXFREESPACE
+#define THREADCACHEMAXFREESPACE (512*1024)
+#endif
+
+
+#ifdef WIN32
+ #define TLSVAR			DWORD
+ #define TLSALLOC(k)	(*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k))
+ #define TLSFREE(k)		(!TlsFree(k))
+ #define TLSGET(k)		TlsGetValue(k)
+ #define TLSSET(k, a)	(!TlsSetValue(k, a))
+ #ifdef DEBUG
+static LPVOID ChkedTlsGetValue(DWORD idx)
+{
+	LPVOID ret=TlsGetValue(idx);
+	assert(S_OK==GetLastError());
+	return ret;
+}
+  #undef TLSGET
+  #define TLSGET(k) ChkedTlsGetValue(k)
+ #endif
+#else
+ #define TLSVAR			pthread_key_t
+ #define TLSALLOC(k)	pthread_key_create(k, 0)
+ #define TLSFREE(k)		pthread_key_delete(k)
+ #define TLSGET(k)		pthread_getspecific(k)
+ #define TLSSET(k, a)	pthread_setspecific(k, a)
+#endif
+
+#if 0
+/* Only enable if testing with valgrind. Causes misoperation */
+#define mspace_malloc(p, s) malloc(s)
+#define mspace_realloc(p, m, s) realloc(m, s)
+#define mspace_calloc(p, n, s) calloc(n, s)
+#define mspace_free(p, m) free(m)
+#endif
+
+
+#if defined(__cplusplus)
+#if !defined(NO_NED_NAMESPACE)
+namespace nedalloc {
+#else
+extern "C" {
+#endif
+#endif
+
+size_t nedblksize(void *mem) THROWSPEC
+{
+#if 0
+	/* Only enable if testing with valgrind. Causes misoperation */
+	return THREADCACHEMAX;
+#else
+	if(mem)
+	{
+		mchunkptr p=mem2chunk(mem);
+		assert(cinuse(p));	/* If this fails, someone tried to free a block twice */
+		if(cinuse(p))
+			return chunksize(p)-overhead_for(p);
+	}
+	return 0;
+#endif
+}
+
+void nedsetvalue(void *v) THROWSPEC					{ nedpsetvalue(0, v); }
+void * nedmalloc(size_t size) THROWSPEC				{ return nedpmalloc(0, size); }
+void * nedcalloc(size_t no, size_t size) THROWSPEC	{ return nedpcalloc(0, no, size); }
+void * nedrealloc(void *mem, size_t size) THROWSPEC	{ return nedprealloc(0, mem, size); }
+void   nedfree(void *mem) THROWSPEC					{ nedpfree(0, mem); }
+void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign(0, alignment, bytes); }
+#if !NO_MALLINFO
+struct mallinfo nedmallinfo(void) THROWSPEC			{ return nedpmallinfo(0); }
+#endif
+int    nedmallopt(int parno, int value) THROWSPEC	{ return nedpmallopt(0, parno, value); }
+int    nedmalloc_trim(size_t pad) THROWSPEC			{ return nedpmalloc_trim(0, pad); }
+void   nedmalloc_stats(void) THROWSPEC					{ nedpmalloc_stats(0); }
+size_t nedmalloc_footprint(void) THROWSPEC				{ return nedpmalloc_footprint(0); }
+void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC	{ return nedpindependent_calloc(0, elemsno, elemsize, chunks); }
+void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC	{ return nedpindependent_comalloc(0, elems, sizes, chunks); }
+
+struct threadcacheblk_t;
+typedef struct threadcacheblk_t threadcacheblk;
+struct threadcacheblk_t
+{	/* Keep less than 16 bytes on 32 bit systems and 32 bytes on 64 bit systems */
+#ifdef FULLSANITYCHECKS
+	unsigned int magic;
+#endif
+	unsigned int lastUsed, size;
+	threadcacheblk *next, *prev;
+};
+typedef struct threadcache_t
+{
+#ifdef FULLSANITYCHECKS
+	unsigned int magic1;
+#endif
+	int mymspace;						/* Last mspace entry this thread used */
+	long threadid;
+	unsigned int mallocs, frees, successes;
+	size_t freeInCache;					/* How much free space is stored in this cache */
+	threadcacheblk *bins[(THREADCACHEMAXBINS+1)*2];
+#ifdef FULLSANITYCHECKS
+	unsigned int magic2;
+#endif
+} threadcache;
+struct nedpool_t
+{
+	MLOCK_T mutex;
+	void *uservalue;
+	int threads;						/* Max entries in m to use */
+	threadcache *caches[THREADCACHEMAXCACHES];
+	TLSVAR mycache;						/* Thread cache for this thread. 0 for unset, negative for use mspace-1 directly, otherwise is cache-1 */
+	mstate m[MAXTHREADSINPOOL+1];		/* mspace entries for this pool */
+};
+static nedpool syspool;
+
+static FORCEINLINE unsigned int size2binidx(size_t _size) THROWSPEC
+{	/* 8=1000	16=10000	20=10100	24=11000	32=100000	48=110000	4096=1000000000000 */
+	unsigned int topbit, size=(unsigned int)(_size>>4);
+	/* 16=1		20=1	24=1	32=10	48=11	64=100	96=110	128=1000	4096=100000000 */
+
+#if defined(__GNUC__)
+	topbit = sizeof(size)*__CHAR_BIT__ - 1 - __builtin_clz(size);
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+	{
+	    unsigned long bsrTopBit;
+
+	    _BitScanReverse(&bsrTopBit, size);
+
+	    topbit = bsrTopBit;
+	}
+#else
+#if 0
+	union {
+		unsigned asInt[2];
+		double asDouble;
+	};
+	int n;
+
+	asDouble = (double)size + 0.5;
+	topbit = (asInt[!FOX_BIGENDIAN] >> 20) - 1023;
+#else
+	{
+		unsigned int x=size;
+		x = x | (x >> 1);
+		x = x | (x >> 2);
+		x = x | (x >> 4);
+		x = x | (x >> 8);
+		x = x | (x >>16);
+		x = ~x;
+		x = x - ((x >> 1) & 0x55555555);
+		x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+		x = (x + (x >> 4)) & 0x0F0F0F0F;
+		x = x + (x << 8);
+		x = x + (x << 16);
+		topbit=31 - (x >> 24);
+	}
+#endif
+#endif
+	return topbit;
+}
+
+
+#ifdef FULLSANITYCHECKS
+static void tcsanitycheck(threadcacheblk **ptr) THROWSPEC
+{
+	assert((ptr[0] && ptr[1]) || (!ptr[0] && !ptr[1]));
+	if(ptr[0] && ptr[1])
+	{
+		assert(nedblksize(ptr[0])>=sizeof(threadcacheblk));
+		assert(nedblksize(ptr[1])>=sizeof(threadcacheblk));
+		assert(*(unsigned int *) "NEDN"==ptr[0]->magic);
+		assert(*(unsigned int *) "NEDN"==ptr[1]->magic);
+		assert(!ptr[0]->prev);
+		assert(!ptr[1]->next);
+		if(ptr[0]==ptr[1])
+		{
+			assert(!ptr[0]->next);
+			assert(!ptr[1]->prev);
+		}
+	}
+}
+static void tcfullsanitycheck(threadcache *tc) THROWSPEC
+{
+	threadcacheblk **tcbptr=tc->bins;
+	int n;
+	for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
+	{
+		threadcacheblk *b, *ob=0;
+		tcsanitycheck(tcbptr);
+		for(b=tcbptr[0]; b; ob=b, b=b->next)
+		{
+			assert(*(unsigned int *) "NEDN"==b->magic);
+			assert(!ob || ob->next==b);
+			assert(!ob || b->prev==ob);
+		}
+	}
+}
+#endif
+
+static NOINLINE void RemoveCacheEntries(nedpool *p, threadcache *tc, unsigned int age) THROWSPEC
+{
+#ifdef FULLSANITYCHECKS
+	tcfullsanitycheck(tc);
+#endif
+	if(tc->freeInCache)
+	{
+		threadcacheblk **tcbptr=tc->bins;
+		int n;
+		for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
+		{
+			threadcacheblk **tcb=tcbptr+1;		/* come from oldest end of list */
+			/*tcsanitycheck(tcbptr);*/
+			for(; *tcb && tc->frees-(*tcb)->lastUsed>=age; )
+			{
+				threadcacheblk *f=*tcb;
+				size_t blksize=f->size; /*nedblksize(f);*/
+				assert(blksize<=nedblksize(f));
+				assert(blksize);
+#ifdef FULLSANITYCHECKS
+				assert(*(unsigned int *) "NEDN"==(*tcb)->magic);
+#endif
+				*tcb=(*tcb)->prev;
+				if(*tcb)
+					(*tcb)->next=0;
+				else
+					*tcbptr=0;
+				tc->freeInCache-=blksize;
+				assert((long) tc->freeInCache>=0);
+				mspace_free(0, f);
+				/*tcsanitycheck(tcbptr);*/
+			}
+		}
+	}
+#ifdef FULLSANITYCHECKS
+	tcfullsanitycheck(tc);
+#endif
+}
+static void DestroyCaches(nedpool *p) THROWSPEC
+{
+	{
+		threadcache *tc;
+		int n;
+		for(n=0; n<THREADCACHEMAXCACHES; n++)
+		{
+			if((tc=p->caches[n]))
+			{
+				tc->frees++;
+				RemoveCacheEntries(p, tc, 0);
+				assert(!tc->freeInCache);
+				tc->mymspace=-1;
+				tc->threadid=0;
+				mspace_free(0, tc);
+				p->caches[n]=0;
+			}
+		}
+	}
+}
+
+static NOINLINE threadcache *AllocCache(nedpool *p) THROWSPEC
+{
+	threadcache *tc=0;
+	int n, end;
+	ACQUIRE_LOCK(&p->mutex);
+	for(n=0; n<THREADCACHEMAXCACHES && p->caches[n]; n++);
+	if(THREADCACHEMAXCACHES==n)
+	{	/* List exhausted, so disable for this thread */
+		RELEASE_LOCK(&p->mutex);
+		return 0;
+	}
+	tc=p->caches[n]=(threadcache *) mspace_calloc(p->m[0], 1, sizeof(threadcache));
+	if(!tc)
+	{
+		RELEASE_LOCK(&p->mutex);
+		return 0;
+	}
+#ifdef FULLSANITYCHECKS
+	tc->magic1=*(unsigned int *)"NEDMALC1";
+	tc->magic2=*(unsigned int *)"NEDMALC2";
+#endif
+	tc->threadid=(long)(size_t)CURRENT_THREAD;
+	for(end=0; p->m[end]; end++);
+	tc->mymspace=tc->threadid % end;
+	RELEASE_LOCK(&p->mutex);
+	if(TLSSET(p->mycache, (void *)(size_t)(n+1))) abort();
+	return tc;
+}
+
+static void *threadcache_malloc(nedpool *p, threadcache *tc, size_t *size) THROWSPEC
+{
+	void *ret=0;
+	unsigned int bestsize;
+	unsigned int idx=size2binidx(*size);
+	size_t blksize=0;
+	threadcacheblk *blk, **binsptr;
+#ifdef FULLSANITYCHECKS
+	tcfullsanitycheck(tc);
+#endif
+	/* Calculate best fit bin size */
+	bestsize=1<<(idx+4);
+#if 0
+	/* Finer grained bin fit */
+	idx<<=1;
+	if(*size>bestsize)
+	{
+		idx++;
+		bestsize+=bestsize>>1;
+	}
+	if(*size>bestsize)
+	{
+		idx++;
+		bestsize=1<<(4+(idx>>1));
+	}
+#else
+	if(*size>bestsize)
+	{
+		idx++;
+		bestsize<<=1;
+	}
+#endif
+	assert(bestsize>=*size);
+	if(*size<bestsize) *size=bestsize;
+	assert(*size<=THREADCACHEMAX);
+	assert(idx<=THREADCACHEMAXBINS);
+	binsptr=&tc->bins[idx*2];
+	/* Try to match close, but move up a bin if necessary */
+	blk=*binsptr;
+	if(!blk || blk->size<*size)
+	{	/* Bump it up a bin */
+		if(idx<THREADCACHEMAXBINS)
+		{
+			idx++;
+			binsptr+=2;
+			blk=*binsptr;
+		}
+	}
+	if(blk)
+	{
+		blksize=blk->size; /*nedblksize(blk);*/
+		assert(nedblksize(blk)>=blksize);
+		assert(blksize>=*size);
+		if(blk->next)
+			blk->next->prev=0;
+		*binsptr=blk->next;
+		if(!*binsptr)
+			binsptr[1]=0;
+#ifdef FULLSANITYCHECKS
+		blk->magic=0;
+#endif
+		assert(binsptr[0]!=blk && binsptr[1]!=blk);
+		assert(nedblksize(blk)>=sizeof(threadcacheblk) && nedblksize(blk)<=THREADCACHEMAX+CHUNK_OVERHEAD);
+		/*printf("malloc: %p, %p, %p, %lu\n", p, tc, blk, (long) size);*/
+		ret=(void *) blk;
+	}
+	++tc->mallocs;
+	if(ret)
+	{
+		assert(blksize>=*size);
+		++tc->successes;
+		tc->freeInCache-=blksize;
+		assert((long) tc->freeInCache>=0);
+	}
+#if defined(DEBUG) && 0
+	if(!(tc->mallocs & 0xfff))
+	{
+		printf("*** threadcache=%u, mallocs=%u (%f), free=%u (%f), freeInCache=%u\n", (unsigned int) tc->threadid, tc->mallocs,
+			(float) tc->successes/tc->mallocs, tc->frees, (float) tc->successes/tc->frees, (unsigned int) tc->freeInCache);
+	}
+#endif
+#ifdef FULLSANITYCHECKS
+	tcfullsanitycheck(tc);
+#endif
+	return ret;
+}
+static NOINLINE void ReleaseFreeInCache(nedpool *p, threadcache *tc, int mymspace) THROWSPEC
+{
+	unsigned int age=THREADCACHEMAXFREESPACE/8192;
+	/*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/
+	while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE)
+	{
+		RemoveCacheEntries(p, tc, age);
+		/*printf("*** Removing cache entries older than %u (%u)\n", age, (unsigned int) tc->freeInCache);*/
+		age>>=1;
+	}
+	/*RELEASE_LOCK(&p->m[mymspace]->mutex);*/
+}
+static void threadcache_free(nedpool *p, threadcache *tc, int mymspace, void *mem, size_t size) THROWSPEC
+{
+	unsigned int bestsize;
+	unsigned int idx=size2binidx(size);
+	threadcacheblk **binsptr, *tck=(threadcacheblk *) mem;
+	assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD);
+#ifdef DEBUG
+	{	/* Make sure this is a valid memory block */
+	    mchunkptr p  = mem2chunk(mem);
+	    mstate fm = get_mstate_for(p);
+	    if (!ok_magic(fm)) {
+	      USAGE_ERROR_ACTION(fm, p);
+	      return;
+	    }
+	}
+#endif
+#ifdef FULLSANITYCHECKS
+	tcfullsanitycheck(tc);
+#endif
+	/* Calculate best fit bin size */
+	bestsize=1<<(idx+4);
+#if 0
+	/* Finer grained bin fit */
+	idx<<=1;
+	if(size>bestsize)
+	{
+		unsigned int biggerbestsize=bestsize+bestsize<<1;
+		if(size>=biggerbestsize)
+		{
+			idx++;
+			bestsize=biggerbestsize;
+		}
+	}
+#endif
+	if(bestsize!=size)	/* dlmalloc can round up, so we round down to preserve indexing */
+		size=bestsize;
+	binsptr=&tc->bins[idx*2];
+	assert(idx<=THREADCACHEMAXBINS);
+	if(tck==*binsptr)
+	{
+		fprintf(stderr, "Attempt to free already freed memory block %p - aborting!\n", (void *)tck);
+		abort();
+	}
+#ifdef FULLSANITYCHECKS
+	tck->magic=*(unsigned int *) "NEDN";
+#endif
+	tck->lastUsed=++tc->frees;
+	tck->size=(unsigned int) size;
+	tck->next=*binsptr;
+	tck->prev=0;
+	if(tck->next)
+		tck->next->prev=tck;
+	else
+		binsptr[1]=tck;
+	assert(!*binsptr || (*binsptr)->size==tck->size);
+	*binsptr=tck;
+	assert(tck==tc->bins[idx*2]);
+	assert(tc->bins[idx*2+1]==tck || binsptr[0]->next->prev==tck);
+	/*printf("free: %p, %p, %p, %lu\n", p, tc, mem, (long) size);*/
+	tc->freeInCache+=size;
+#ifdef FULLSANITYCHECKS
+	tcfullsanitycheck(tc);
+#endif
+#if 1
+	if(tc->freeInCache>=THREADCACHEMAXFREESPACE)
+		ReleaseFreeInCache(p, tc, mymspace);
+#endif
+}
+
+
+
+
+static NOINLINE int InitPool(nedpool *p, size_t capacity, int threads) THROWSPEC
+{	/* threads is -1 for system pool */
+	ensure_initialization();
+	ACQUIRE_MALLOC_GLOBAL_LOCK();
+	if(p->threads) goto done;
+	if(INITIAL_LOCK(&p->mutex)) goto err;
+	if(TLSALLOC(&p->mycache)) goto err;
+	if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err;
+	p->m[0]->extp=p;
+	p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads;
+done:
+	RELEASE_MALLOC_GLOBAL_LOCK();
+	return 1;
+err:
+	if(threads<0)
+		abort();			/* If you can't allocate for system pool, we're screwed */
+	DestroyCaches(p);
+	if(p->m[0])
+	{
+		destroy_mspace(p->m[0]);
+		p->m[0]=0;
+	}
+	if(p->mycache)
+	{
+		if(TLSFREE(p->mycache)) abort();
+		p->mycache=0;
+	}
+	RELEASE_MALLOC_GLOBAL_LOCK();
+	return 0;
+}
+static NOINLINE mstate FindMSpace(nedpool *p, threadcache *tc, int *lastUsed, size_t size) THROWSPEC
+{	/* Gets called when thread's last used mspace is in use. The strategy
+	is to run through the list of all available mspaces looking for an
+	unlocked one and if we fail, we create a new one so long as we don't
+	exceed p->threads */
+	int n, end;
+	for(n=end=*lastUsed+1; p->m[n]; end=++n)
+	{
+		if(TRY_LOCK(&p->m[n]->mutex)) goto found;
+	}
+	for(n=0; n<*lastUsed && p->m[n]; n++)
+	{
+		if(TRY_LOCK(&p->m[n]->mutex)) goto found;
+	}
+	if(end<p->threads)
+	{
+		mstate temp;
+		if(!(temp=(mstate) create_mspace(size, 1)))
+			goto badexit;
+		/* Now we're ready to modify the lists, we lock */
+		ACQUIRE_LOCK(&p->mutex);
+		while(p->m[end] && end<p->threads)
+			end++;
+		if(end>=p->threads)
+		{	/* Drat, must destroy it now */
+			RELEASE_LOCK(&p->mutex);
+			destroy_mspace((mspace) temp);
+			goto badexit;
+		}
+		/* We really want to make sure this goes into memory now but we
+		have to be careful of breaking aliasing rules, so write it twice */
+		{
+			volatile struct malloc_state **_m=(volatile struct malloc_state **) &p->m[end];
+			*_m=(p->m[end]=temp);
+		}
+		ACQUIRE_LOCK(&p->m[end]->mutex);
+		/*printf("Created mspace idx %d\n", end);*/
+		RELEASE_LOCK(&p->mutex);
+		n=end;
+		goto found;
+	}
+	/* Let it lock on the last one it used */
+badexit:
+	ACQUIRE_LOCK(&p->m[*lastUsed]->mutex);
+	return p->m[*lastUsed];
+found:
+	*lastUsed=n;
+	if(tc)
+		tc->mymspace=n;
+	else
+	{
+		if(TLSSET(p->mycache, (void *)(size_t)(-(n+1)))) abort();
+	}
+	return p->m[n];
+}
+
+nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC
+{
+	nedpool *ret;
+	if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) return 0;
+	if(!InitPool(ret, capacity, threads))
+	{
+		nedpfree(0, ret);
+		return 0;
+	}
+	return ret;
+}
+void neddestroypool(nedpool *p) THROWSPEC
+{
+	int n;
+	ACQUIRE_LOCK(&p->mutex);
+	DestroyCaches(p);
+	for(n=0; p->m[n]; n++)
+	{
+		destroy_mspace(p->m[n]);
+		p->m[n]=0;
+	}
+	RELEASE_LOCK(&p->mutex);
+	if(TLSFREE(p->mycache)) abort();
+	nedpfree(0, p);
+}
+
+void nedpsetvalue(nedpool *p, void *v) THROWSPEC
+{
+	if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+	p->uservalue=v;
+}
+void *nedgetvalue(nedpool **p, void *mem) THROWSPEC
+{
+	nedpool *np=0;
+	mchunkptr mcp=mem2chunk(mem);
+	mstate fm;
+	if(!(is_aligned(chunk2mem(mcp))) && mcp->head != FENCEPOST_HEAD) return 0;
+	if(!cinuse(mcp)) return 0;
+	if(!next_pinuse(mcp)) return 0;
+	if(!is_mmapped(mcp) && !pinuse(mcp))
+	{
+		if(next_chunk(prev_chunk(mcp))!=mcp) return 0;
+	}
+	fm=get_mstate_for(mcp);
+	if(!ok_magic(fm)) return 0;
+	if(!ok_address(fm, mcp)) return 0;
+	if(!fm->extp) return 0;
+	np=(nedpool *) fm->extp;
+	if(p) *p=np;
+	return np->uservalue;
+}
+
+void neddisablethreadcache(nedpool *p) THROWSPEC
+{
+	int mycache;
+	if(!p)
+	{
+		p=&syspool;
+		if(!syspool.threads) InitPool(&syspool, 0, -1);
+	}
+	mycache=(int)(size_t) TLSGET(p->mycache);
+	if(!mycache)
+	{	/* Set to mspace 0 */
+		if(TLSSET(p->mycache, (void *)-1)) abort();
+	}
+	else if(mycache>0)
+	{	/* Set to last used mspace */
+		threadcache *tc=p->caches[mycache-1];
+#if defined(DEBUG)
+		printf("Threadcache utilisation: %lf%% in cache with %lf%% lost to other threads\n",
+			100.0*tc->successes/tc->mallocs, 100.0*((double) tc->mallocs-tc->frees)/tc->mallocs);
+#endif
+		if(TLSSET(p->mycache, (void *)(size_t)(-tc->mymspace))) abort();
+		tc->frees++;
+		RemoveCacheEntries(p, tc, 0);
+		assert(!tc->freeInCache);
+		tc->mymspace=-1;
+		tc->threadid=0;
+		mspace_free(0, p->caches[mycache-1]);
+		p->caches[mycache-1]=0;
+	}
+}
+
+#define GETMSPACE(m,p,tc,ms,s,action)           \
+  do                                            \
+  {                                             \
+    mstate m = GetMSpace((p),(tc),(ms),(s));    \
+    action;                                     \
+    RELEASE_LOCK(&m->mutex);                    \
+  } while (0)
+
+static FORCEINLINE mstate GetMSpace(nedpool *p, threadcache *tc, int mymspace, size_t size) THROWSPEC
+{	/* Returns a locked and ready for use mspace */
+	mstate m=p->m[mymspace];
+	assert(m);
+	if(!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size);\
+	/*assert(IS_LOCKED(&p->m[mymspace]->mutex));*/
+	return m;
+}
+static FORCEINLINE void GetThreadCache(nedpool **p, threadcache **tc, int *mymspace, size_t *size) THROWSPEC
+{
+	int mycache;
+	if(size && *size<sizeof(threadcacheblk)) *size=sizeof(threadcacheblk);
+	if(!*p)
+	{
+		*p=&syspool;
+		if(!syspool.threads) InitPool(&syspool, 0, -1);
+	}
+	mycache=(int)(size_t) TLSGET((*p)->mycache);
+	if(mycache>0)
+	{
+		*tc=(*p)->caches[mycache-1];
+		*mymspace=(*tc)->mymspace;
+	}
+	else if(!mycache)
+	{
+		*tc=AllocCache(*p);
+		if(!*tc)
+		{	/* Disable */
+			if(TLSSET((*p)->mycache, (void *)-1)) abort();
+			*mymspace=0;
+		}
+		else
+			*mymspace=(*tc)->mymspace;
+	}
+	else
+	{
+		*tc=0;
+		*mymspace=-mycache-1;
+	}
+	assert(*mymspace>=0);
+	assert((long)(size_t)CURRENT_THREAD==(*tc)->threadid);
+#ifdef FULLSANITYCHECKS
+	if(*tc)
+	{
+		if(*(unsigned int *)"NEDMALC1"!=(*tc)->magic1 || *(unsigned int *)"NEDMALC2"!=(*tc)->magic2)
+		{
+			abort();
+		}
+	}
+#endif
+}
+
+void * nedpmalloc(nedpool *p, size_t size) THROWSPEC
+{
+	void *ret=0;
+	threadcache *tc;
+	int mymspace;
+	GetThreadCache(&p, &tc, &mymspace, &size);
+#if THREADCACHEMAX
+	if(tc && size<=THREADCACHEMAX)
+	{	/* Use the thread cache */
+		ret=threadcache_malloc(p, tc, &size);
+	}
+#endif
+	if(!ret)
+	{	/* Use this thread's mspace */
+	GETMSPACE(m, p, tc, mymspace, size,
+		  ret=mspace_malloc(m, size));
+	}
+	return ret;
+}
+void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC
+{
+	size_t rsize=size*no;
+	void *ret=0;
+	threadcache *tc;
+	int mymspace;
+	GetThreadCache(&p, &tc, &mymspace, &rsize);
+#if THREADCACHEMAX
+	if(tc && rsize<=THREADCACHEMAX)
+	{	/* Use the thread cache */
+		if((ret=threadcache_malloc(p, tc, &rsize)))
+			memset(ret, 0, rsize);
+	}
+#endif
+	if(!ret)
+	{	/* Use this thread's mspace */
+	GETMSPACE(m, p, tc, mymspace, rsize,
+		  ret=mspace_calloc(m, 1, rsize));
+	}
+	return ret;
+}
+void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC
+{
+	void *ret=0;
+	threadcache *tc;
+	int mymspace;
+	if(!mem) return nedpmalloc(p, size);
+	GetThreadCache(&p, &tc, &mymspace, &size);
+#if THREADCACHEMAX
+	if(tc && size && size<=THREADCACHEMAX)
+	{	/* Use the thread cache */
+		size_t memsize=nedblksize(mem);
+		assert(memsize);
+		if((ret=threadcache_malloc(p, tc, &size)))
+		{
+			memcpy(ret, mem, memsize<size ? memsize : size);
+			if(memsize<=THREADCACHEMAX)
+				threadcache_free(p, tc, mymspace, mem, memsize);
+			else
+				mspace_free(0, mem);
+		}
+	}
+#endif
+	if(!ret)
+	{	/* Reallocs always happen in the mspace they happened in, so skip
+		locking the preferred mspace for this thread */
+		ret=mspace_realloc(0, mem, size);
+	}
+	return ret;
+}
+void   nedpfree(nedpool *p, void *mem) THROWSPEC
+{	/* Frees always happen in the mspace they happened in, so skip
+	locking the preferred mspace for this thread */
+	threadcache *tc;
+	int mymspace;
+	size_t memsize;
+	assert(mem);
+	GetThreadCache(&p, &tc, &mymspace, 0);
+#if THREADCACHEMAX
+	memsize=nedblksize(mem);
+	assert(memsize);
+	if(mem && tc && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
+		threadcache_free(p, tc, mymspace, mem, memsize);
+	else
+#endif
+		mspace_free(0, mem);
+}
+void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC
+{
+	void *ret;
+	threadcache *tc;
+	int mymspace;
+	GetThreadCache(&p, &tc, &mymspace, &bytes);
+	{	/* Use this thread's mspace */
+	GETMSPACE(m, p, tc, mymspace, bytes,
+		  ret=mspace_memalign(m, alignment, bytes));
+	}
+	return ret;
+}
+#if !NO_MALLINFO
+struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC
+{
+	int n;
+	struct mallinfo ret={0};
+	if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+	for(n=0; p->m[n]; n++)
+	{
+		struct mallinfo t=mspace_mallinfo(p->m[n]);
+		ret.arena+=t.arena;
+		ret.ordblks+=t.ordblks;
+		ret.hblkhd+=t.hblkhd;
+		ret.usmblks+=t.usmblks;
+		ret.uordblks+=t.uordblks;
+		ret.fordblks+=t.fordblks;
+		ret.keepcost+=t.keepcost;
+	}
+	return ret;
+}
+#endif
+int    nedpmallopt(nedpool *p, int parno, int value) THROWSPEC
+{
+	return mspace_mallopt(parno, value);
+}
+int    nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
+{
+	int n, ret=0;
+	if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+	for(n=0; p->m[n]; n++)
+	{
+		ret+=mspace_trim(p->m[n], pad);
+	}
+	return ret;
+}
+void   nedpmalloc_stats(nedpool *p) THROWSPEC
+{
+	int n;
+	if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+	for(n=0; p->m[n]; n++)
+	{
+		mspace_malloc_stats(p->m[n]);
+	}
+}
+size_t nedpmalloc_footprint(nedpool *p) THROWSPEC
+{
+	size_t ret=0;
+	int n;
+	if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+	for(n=0; p->m[n]; n++)
+	{
+		ret+=mspace_footprint(p->m[n]);
+	}
+	return ret;
+}
+void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC
+{
+	void **ret;
+	threadcache *tc;
+	int mymspace;
+	GetThreadCache(&p, &tc, &mymspace, &elemsize);
+    GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
+	      ret=mspace_independent_calloc(m, elemsno, elemsize, chunks));
+	return ret;
+}
+void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC
+{
+	void **ret;
+	threadcache *tc;
+	int mymspace;
+	size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t));
+	if(!adjustedsizes) return 0;
+	for(i=0; i<elems; i++)
+		adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i];
+	GetThreadCache(&p, &tc, &mymspace, 0);
+	GETMSPACE(m, p, tc, mymspace, 0,
+	      ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks));
+	return ret;
+}
+
+#if defined(__cplusplus)
+}
+#endif
diff --git a/compat/nedmalloc/nedmalloc.h b/compat/nedmalloc/nedmalloc.h
new file mode 100644
index 0000000000..f960e66063
--- /dev/null
+++ b/compat/nedmalloc/nedmalloc.h
@@ -0,0 +1,180 @@
+/* nedalloc, an alternative malloc implementation for multiple threads without
+lock contention based on dlmalloc v2.8.3. (C) 2005 Niall Douglas
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef NEDMALLOC_H
+#define NEDMALLOC_H
+
+
+/* See malloc.c.h for what each function does.
+
+REPLACE_SYSTEM_ALLOCATOR causes nedalloc's functions to be called malloc,
+free etc. instead of nedmalloc, nedfree etc. You may or may not want this.
+
+NO_NED_NAMESPACE prevents the functions from being defined in the nedalloc
+namespace when in C++ (uses the global namespace instead).
+
+EXTSPEC can be defined to be __declspec(dllexport) or
+__attribute__ ((visibility("default"))) or whatever you like. It defaults
+to extern.
+
+USE_LOCKS can be 2 if you want to define your own MLOCK_T, INITIAL_LOCK,
+ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
+
+*/
+
+#include <stddef.h>   /* for size_t */
+
+#ifndef EXTSPEC
+ #define EXTSPEC extern
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER>=1400
+ #define MALLOCATTR __declspec(restrict)
+#endif
+#ifdef __GNUC__
+ #define MALLOCATTR __attribute__ ((malloc))
+#endif
+#ifndef MALLOCATTR
+ #define MALLOCATTR
+#endif
+
+#ifdef REPLACE_SYSTEM_ALLOCATOR
+ #define nedmalloc               malloc
+ #define nedcalloc               calloc
+ #define nedrealloc              realloc
+ #define nedfree                 free
+ #define nedmemalign             memalign
+ #define nedmallinfo             mallinfo
+ #define nedmallopt              mallopt
+ #define nedmalloc_trim          malloc_trim
+ #define nedmalloc_stats         malloc_stats
+ #define nedmalloc_footprint     malloc_footprint
+ #define nedindependent_calloc   independent_calloc
+ #define nedindependent_comalloc independent_comalloc
+ #ifdef _MSC_VER
+  #define nedblksize              _msize
+ #endif
+#endif
+
+#ifndef NO_MALLINFO
+#define NO_MALLINFO 0
+#endif
+
+#if !NO_MALLINFO
+struct mallinfo;
+#endif
+
+#if defined(__cplusplus)
+ #if !defined(NO_NED_NAMESPACE)
+namespace nedalloc {
+ #else
+extern "C" {
+ #endif
+ #define THROWSPEC throw()
+#else
+ #define THROWSPEC
+#endif
+
+/* These are the global functions */
+
+/* Gets the usable size of an allocated block. Note this will always be bigger than what was
+asked for due to rounding etc.
+*/
+EXTSPEC size_t nedblksize(void *mem) THROWSPEC;
+
+EXTSPEC void nedsetvalue(void *v) THROWSPEC;
+
+EXTSPEC MALLOCATTR void * nedmalloc(size_t size) THROWSPEC;
+EXTSPEC MALLOCATTR void * nedcalloc(size_t no, size_t size) THROWSPEC;
+EXTSPEC MALLOCATTR void * nedrealloc(void *mem, size_t size) THROWSPEC;
+EXTSPEC void   nedfree(void *mem) THROWSPEC;
+EXTSPEC MALLOCATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC;
+#if !NO_MALLINFO
+EXTSPEC struct mallinfo nedmallinfo(void) THROWSPEC;
+#endif
+EXTSPEC int    nedmallopt(int parno, int value) THROWSPEC;
+EXTSPEC int    nedmalloc_trim(size_t pad) THROWSPEC;
+EXTSPEC void   nedmalloc_stats(void) THROWSPEC;
+EXTSPEC size_t nedmalloc_footprint(void) THROWSPEC;
+EXTSPEC MALLOCATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
+EXTSPEC MALLOCATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC;
+
+/* These are the pool functions */
+struct nedpool_t;
+typedef struct nedpool_t nedpool;
+
+/* Creates a memory pool for use with the nedp* functions below.
+Capacity is how much to allocate immediately (if you know you'll be allocating a lot
+of memory very soon) which you can leave at zero. Threads specifies how many threads
+will *normally* be accessing the pool concurrently. Setting this to zero means it
+extends on demand, but be careful of this as it can rapidly consume system resources
+where bursts of concurrent threads use a pool at once.
+*/
+EXTSPEC MALLOCATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC;
+
+/* Destroys a memory pool previously created by nedcreatepool().
+*/
+EXTSPEC void neddestroypool(nedpool *p) THROWSPEC;
+
+/* Sets a value to be associated with a pool. You can retrieve this value by passing
+any memory block allocated from that pool.
+*/
+EXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC;
+/* Gets a previously set value using nedpsetvalue() or zero if memory is unknown.
+Optionally can also retrieve pool.
+*/
+EXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC;
+
+/* Disables the thread cache for the calling thread, returning any existing cache
+data to the central pool.
+*/
+EXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC;
+
+EXTSPEC MALLOCATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC;
+EXTSPEC MALLOCATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC;
+EXTSPEC MALLOCATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC;
+EXTSPEC void   nedpfree(nedpool *p, void *mem) THROWSPEC;
+EXTSPEC MALLOCATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC;
+#if !NO_MALLINFO
+EXTSPEC struct mallinfo nedpmallinfo(nedpool *p) THROWSPEC;
+#endif
+EXTSPEC int    nedpmallopt(nedpool *p, int parno, int value) THROWSPEC;
+EXTSPEC int    nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC;
+EXTSPEC void   nedpmalloc_stats(nedpool *p) THROWSPEC;
+EXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC;
+EXTSPEC MALLOCATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
+EXTSPEC MALLOCATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#undef MALLOCATTR
+#undef EXTSPEC
+
+#endif
diff --git a/compat/nonblock.c b/compat/nonblock.c
new file mode 100644
index 0000000000..5b51195c32
--- /dev/null
+++ b/compat/nonblock.c
@@ -0,0 +1,50 @@
+#include "git-compat-util.h"
+#include "nonblock.h"
+
+#ifdef O_NONBLOCK
+
+int enable_pipe_nonblock(int fd)
+{
+	int flags = fcntl(fd, F_GETFL);
+	if (flags < 0)
+		return -1;
+	flags |= O_NONBLOCK;
+	return fcntl(fd, F_SETFL, flags);
+}
+
+#elif defined(GIT_WINDOWS_NATIVE)
+
+#include "win32.h"
+
+int enable_pipe_nonblock(int fd)
+{
+	HANDLE h = (HANDLE)_get_osfhandle(fd);
+	DWORD mode;
+	DWORD type = GetFileType(h);
+	if (type == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) {
+		errno = EBADF;
+		return -1;
+	}
+	if (type != FILE_TYPE_PIPE)
+		BUG("unsupported file type: %lu", type);
+	if (!GetNamedPipeHandleState(h, &mode, NULL, NULL, NULL, NULL, 0)) {
+		errno = err_win_to_posix(GetLastError());
+		return -1;
+	}
+	mode |= PIPE_NOWAIT;
+	if (!SetNamedPipeHandleState(h, &mode, NULL, NULL)) {
+		errno = err_win_to_posix(GetLastError());
+		return -1;
+	}
+	return 0;
+}
+
+#else
+
+int enable_pipe_nonblock(int fd UNUSED)
+{
+	errno = ENOSYS;
+	return -1;
+}
+
+#endif
diff --git a/compat/nonblock.h b/compat/nonblock.h
new file mode 100644
index 0000000000..af1a331301
--- /dev/null
+++ b/compat/nonblock.h
@@ -0,0 +1,9 @@
+#ifndef COMPAT_NONBLOCK_H
+#define COMPAT_NONBLOCK_H
+
+/*
+ * Enable non-blocking I/O for the pipe specified by the passed-in descriptor.
+ */
+int enable_pipe_nonblock(int fd);
+
+#endif
diff --git a/compat/obstack.c b/compat/obstack.c
new file mode 100644
index 0000000000..27cd5c1ea1
--- /dev/null
+++ b/compat/obstack.c
@@ -0,0 +1,413 @@
+/* obstack.c - subroutines used implicitly by object stack macros
+   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "git-compat-util.h"
+#include <gettext.h>
+#include "obstack.h"
+
+/* NOTE BEFORE MODIFYING THIS FILE: This version number must be
+   incremented whenever callers compiled using an old obstack.h can no
+   longer properly call the functions in this obstack.c.  */
+#define OBSTACK_INTERFACE_VERSION 1
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+   actually compiling the library itself, and the installed library
+   supports the same library interface we do.  This code is part of the GNU
+   C Library, but also included in many other GNU distributions.  Compiling
+   and linking in this code is a waste when using the GNU C library
+   (especially if it is a shared library).  Rather than having every GNU
+   program understand `configure --with-gnu-libc' and omit the object
+   files, it is simpler to just do this in the source for each such file.  */
+
+#include <stdio.h>		/* Random thing to get __GNU_LIBRARY__.  */
+#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
+# include <gnu-versions.h>
+# if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION
+#  define ELIDE_CODE
+# endif
+#endif
+
+#include <stddef.h>
+
+#ifndef ELIDE_CODE
+
+
+# if HAVE_INTTYPES_H
+#  include <inttypes.h>
+# endif
+# if HAVE_STDINT_H || defined _LIBC
+#  include <stdint.h>
+# endif
+
+/* Determine default alignment.  */
+union fooround
+{
+  uintmax_t i;
+  long double d;
+  void *p;
+};
+struct fooalign
+{
+  char c;
+  union fooround u;
+};
+/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT.
+   But in fact it might be less smart and round addresses to as much as
+   DEFAULT_ROUNDING.  So we prepare for it to do that.  */
+enum
+  {
+    DEFAULT_ALIGNMENT = offsetof (struct fooalign, u),
+    DEFAULT_ROUNDING = sizeof (union fooround)
+  };
+
+/* When we copy a long block of data, this is the unit to do it with.
+   On some machines, copying successive ints does not work;
+   in such a case, redefine COPYING_UNIT to `long' (if that works)
+   or `char' as a last resort.  */
+# ifndef COPYING_UNIT
+#  define COPYING_UNIT int
+# endif
+
+
+/* The functions allocating more room by calling `obstack_chunk_alloc'
+   jump to the handler pointed to by `obstack_alloc_failed_handler'.
+   This can be set to a user defined function which should either
+   abort gracefully or use longjump - but shouldn't return.  This
+   variable by default points to the internal function
+   `print_and_abort'.  */
+static void print_and_abort (void);
+void (*obstack_alloc_failed_handler) (void) = print_and_abort;
+
+# ifdef _LIBC
+#  if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3_4)
+/* A looong time ago (before 1994, anyway; we're not sure) this global variable
+   was used by non-GNU-C macros to avoid multiple evaluation.  The GNU C
+   library still exports it because somebody might use it.  */
+struct obstack *_obstack_compat;
+compat_symbol (libc, _obstack_compat, _obstack, GLIBC_2_0);
+#  endif
+# endif
+
+/* Define a macro that either calls functions with the traditional malloc/free
+   calling interface, or calls functions with the mmalloc/mfree interface
+   (that adds an extra first argument), based on the state of use_extra_arg.
+   For free, do not use ?:, since some compilers, like the MIPS compilers,
+   do not allow (expr) ? void : void.  */
+
+# define CALL_CHUNKFUN(h, size) \
+  (((h) -> use_extra_arg) \
+   ? (*(h)->chunkfun.extra) ((h)->extra_arg, (size)) \
+   : (*(h)->chunkfun.plain) ((size)))
+
+# define CALL_FREEFUN(h, old_chunk) \
+  do { \
+    if ((h) -> use_extra_arg) \
+      (*(h)->freefun.extra) ((h)->extra_arg, (old_chunk)); \
+    else \
+      (*(h)->freefun.plain) ((old_chunk)); \
+  } while (0)
+
+
+/* Initialize an obstack H for use.  Specify chunk size SIZE (0 means default).
+   Objects start on multiples of ALIGNMENT (0 means use default).
+   CHUNKFUN is the function to use to allocate chunks,
+   and FREEFUN the function to free them.
+
+   Return nonzero if successful, calls obstack_alloc_failed_handler if
+   allocation fails.  */
+
+int
+_obstack_begin (struct obstack *h,
+		int size, int alignment,
+		void *(*chunkfun) (long),
+		void (*freefun) (void *))
+{
+  register struct _obstack_chunk *chunk; /* points to new chunk */
+
+  if (alignment == 0)
+    alignment = DEFAULT_ALIGNMENT;
+  if (size == 0)
+    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
+    {
+      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+	 Use the values for range checking, because if range checking is off,
+	 the extra bytes won't be missed terribly, but if range checking is on
+	 and we used a larger request, a whole extra 4096 bytes would be
+	 allocated.
+
+	 These number are irrelevant to the new GNU malloc.  I suspect it is
+	 less sensitive to the size of the request.  */
+      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+		    + 4 + DEFAULT_ROUNDING - 1)
+		   & ~(DEFAULT_ROUNDING - 1));
+      size = 4096 - extra;
+    }
+
+  h->chunkfun.plain = chunkfun;
+  h->freefun.plain = freefun;
+  h->chunk_size = size;
+  h->alignment_mask = alignment - 1;
+  h->use_extra_arg = 0;
+
+  chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+  if (!chunk)
+    (*obstack_alloc_failed_handler) ();
+  h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
+					       alignment - 1);
+  h->chunk_limit = chunk->limit
+    = (char *) chunk + h->chunk_size;
+  chunk->prev = NULL;
+  /* The initial chunk now contains no empty object.  */
+  h->maybe_empty_object = 0;
+  h->alloc_failed = 0;
+  return 1;
+}
+
+int
+_obstack_begin_1 (struct obstack *h, int size, int alignment,
+		  void *(*chunkfun) (void *, long),
+		  void (*freefun) (void *, void *),
+		  void *arg)
+{
+  register struct _obstack_chunk *chunk; /* points to new chunk */
+
+  if (alignment == 0)
+    alignment = DEFAULT_ALIGNMENT;
+  if (size == 0)
+    /* Default size is what GNU malloc can fit in a 4096-byte block.  */
+    {
+      /* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc.
+	 Use the values for range checking, because if range checking is off,
+	 the extra bytes won't be missed terribly, but if range checking is on
+	 and we used a larger request, a whole extra 4096 bytes would be
+	 allocated.
+
+	 These number are irrelevant to the new GNU malloc.  I suspect it is
+	 less sensitive to the size of the request.  */
+      int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1))
+		    + 4 + DEFAULT_ROUNDING - 1)
+		   & ~(DEFAULT_ROUNDING - 1));
+      size = 4096 - extra;
+    }
+
+  h->chunkfun.extra = (struct _obstack_chunk * (*)(void *,long)) chunkfun;
+  h->freefun.extra = (void (*) (void *, struct _obstack_chunk *)) freefun;
+
+  h->chunk_size = size;
+  h->alignment_mask = alignment - 1;
+  h->extra_arg = arg;
+  h->use_extra_arg = 1;
+
+  chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size);
+  if (!chunk)
+    (*obstack_alloc_failed_handler) ();
+  h->next_free = h->object_base = __PTR_ALIGN ((char *) chunk, chunk->contents,
+					       alignment - 1);
+  h->chunk_limit = chunk->limit
+    = (char *) chunk + h->chunk_size;
+  chunk->prev = NULL;
+  /* The initial chunk now contains no empty object.  */
+  h->maybe_empty_object = 0;
+  h->alloc_failed = 0;
+  return 1;
+}
+
+/* Allocate a new current chunk for the obstack *H
+   on the assumption that LENGTH bytes need to be added
+   to the current object, or a new object of length LENGTH allocated.
+   Copies any partial object from the end of the old chunk
+   to the beginning of the new one.  */
+
+void
+_obstack_newchunk (struct obstack *h, int length)
+{
+  register struct _obstack_chunk *old_chunk = h->chunk;
+  register struct _obstack_chunk *new_chunk;
+  register long	new_size;
+  register long obj_size = h->next_free - h->object_base;
+  register long i;
+  long already;
+  char *object_base;
+
+  /* Compute size for new chunk.  */
+  new_size = (obj_size + length) + (obj_size >> 3) + h->alignment_mask + 100;
+  if (new_size < h->chunk_size)
+    new_size = h->chunk_size;
+
+  /* Allocate and initialize the new chunk.  */
+  new_chunk = CALL_CHUNKFUN (h, new_size);
+  if (!new_chunk)
+    (*obstack_alloc_failed_handler) ();
+  h->chunk = new_chunk;
+  new_chunk->prev = old_chunk;
+  new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size;
+
+  /* Compute an aligned object_base in the new chunk */
+  object_base =
+    __PTR_ALIGN ((char *) new_chunk, new_chunk->contents, h->alignment_mask);
+
+  /* Move the existing object to the new chunk.
+     Word at a time is fast and is safe if the object
+     is sufficiently aligned.  */
+  if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT)
+    {
+      for (i = obj_size / sizeof (COPYING_UNIT) - 1;
+	   i >= 0; i--)
+	((COPYING_UNIT *)object_base)[i]
+	  = ((COPYING_UNIT *)h->object_base)[i];
+      /* We used to copy the odd few remaining bytes as one extra COPYING_UNIT,
+	 but that can cross a page boundary on a machine
+	 which does not do strict alignment for COPYING_UNITS.  */
+      already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT);
+    }
+  else
+    already = 0;
+  /* Copy remaining bytes one by one.  */
+  for (i = already; i < obj_size; i++)
+    object_base[i] = h->object_base[i];
+
+  /* If the object just copied was the only data in OLD_CHUNK,
+     free that chunk and remove it from the chain.
+     But not if that chunk might contain an empty object.  */
+  if (! h->maybe_empty_object
+      && (h->object_base
+	  == __PTR_ALIGN ((char *) old_chunk, old_chunk->contents,
+			  h->alignment_mask)))
+    {
+      new_chunk->prev = old_chunk->prev;
+      CALL_FREEFUN (h, old_chunk);
+    }
+
+  h->object_base = object_base;
+  h->next_free = h->object_base + obj_size;
+  /* The new chunk certainly contains no empty object yet.  */
+  h->maybe_empty_object = 0;
+}
+# ifdef _LIBC
+libc_hidden_def (_obstack_newchunk)
+# endif
+
+/* Return nonzero if object OBJ has been allocated from obstack H.
+   This is here for debugging.
+   If you use it in a program, you are probably losing.  */
+
+/* Suppress -Wmissing-prototypes warning.  We don't want to declare this in
+   obstack.h because it is just for debugging.  */
+int _obstack_allocated_p (struct obstack *h, void *obj);
+
+int
+_obstack_allocated_p (struct obstack *h, void *obj)
+{
+  register struct _obstack_chunk *lp;	/* below addr of any objects in this chunk */
+  register struct _obstack_chunk *plp;	/* point to previous chunk if any */
+
+  lp = (h)->chunk;
+  /* We use >= rather than > since the object cannot be exactly at
+     the beginning of the chunk but might be an empty object exactly
+     at the end of an adjacent chunk.  */
+  while (lp != NULL && ((void *) lp >= obj || (void *) (lp)->limit < obj))
+    {
+      plp = lp->prev;
+      lp = plp;
+    }
+  return lp != NULL;
+}
+
+/* Free objects in obstack H, including OBJ and everything allocate
+   more recently than OBJ.  If OBJ is zero, free everything in H.  */
+
+# undef obstack_free
+
+void
+obstack_free (struct obstack *h, void *obj)
+{
+  register struct _obstack_chunk *lp;	/* below addr of any objects in this chunk */
+  register struct _obstack_chunk *plp;	/* point to previous chunk if any */
+
+  lp = h->chunk;
+  /* We use >= because there cannot be an object at the beginning of a chunk.
+     But there can be an empty object at that address
+     at the end of another chunk.  */
+  while (lp != NULL && ((void *) lp >= obj || (void *) (lp)->limit < obj))
+    {
+      plp = lp->prev;
+      CALL_FREEFUN (h, lp);
+      lp = plp;
+      /* If we switch chunks, we can't tell whether the new current
+	 chunk contains an empty object, so assume that it may.  */
+      h->maybe_empty_object = 1;
+    }
+  if (lp)
+    {
+      h->object_base = h->next_free = (char *) (obj);
+      h->chunk_limit = lp->limit;
+      h->chunk = lp;
+    }
+  else if (obj != NULL)
+    /* obj is not in any of the chunks! */
+    abort ();
+}
+
+# ifdef _LIBC
+/* Older versions of libc used a function _obstack_free intended to be
+   called by non-GCC compilers.  */
+strong_alias (obstack_free, _obstack_free)
+# endif
+
+int
+_obstack_memory_used (struct obstack *h)
+{
+  register struct _obstack_chunk* lp;
+  register int nbytes = 0;
+
+  for (lp = h->chunk; lp != NULL; lp = lp->prev)
+    {
+      nbytes += lp->limit - (char *) lp;
+    }
+  return nbytes;
+}
+
+# ifdef _LIBC
+#  include <libio/iolibio.h>
+# endif
+
+# ifndef __attribute__
+/* This feature is available in gcc versions 2.5 and later.  */
+#  if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#   define __attribute__(Spec) /* empty */
+#  endif
+# endif
+
+static void
+print_and_abort (void)
+{
+  /* Don't change any of these strings.  Yes, it would be possible to add
+     the newline to the string and use fputs or so.  But this must not
+     happen because the "memory exhausted" message appears in other places
+     like this and the translation should be reused instead of creating
+     a very similar string which requires a separate translation.  */
+# ifdef _LIBC
+  (void) __fxprintf (NULL, "%s\n", _("memory exhausted"));
+# else
+  fprintf (stderr, "%s\n", _("memory exhausted"));
+# endif
+  exit (1);
+}
+
+#endif	/* !ELIDE_CODE */
diff --git a/compat/obstack.h b/compat/obstack.h
new file mode 100644
index 0000000000..f90a46d9b9
--- /dev/null
+++ b/compat/obstack.h
@@ -0,0 +1,511 @@
+/* obstack.h - object stack macros
+   Copyright (C) 1988-1994,1996-1999,2003,2004,2005,2009
+	Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* Summary:
+
+All the apparent functions defined here are macros. The idea
+is that you would use these pre-tested macros to solve a
+very specific set of problems, and they would run fast.
+Caution: no side-effects in arguments please!! They may be
+evaluated MANY times!!
+
+These macros operate a stack of objects.  Each object starts life
+small, and may grow to maturity.  (Consider building a word syllable
+by syllable.)  An object can move while it is growing.  Once it has
+been "finished" it never changes address again.  So the "top of the
+stack" is typically an immature growing object, while the rest of the
+stack is of mature, fixed size and fixed address objects.
+
+These routines grab large chunks of memory, using a function you
+supply, called `obstack_chunk_alloc'.  On occasion, they free chunks,
+by calling `obstack_chunk_free'.  You must define them and declare
+them before using any obstack macros.
+
+Each independent stack is represented by a `struct obstack'.
+Each of the obstack macros expects a pointer to such a structure
+as the first argument.
+
+One motivation for this package is the problem of growing char strings
+in symbol tables.  Unless you are "fascist pig with a read-only mind"
+--Gosper's immortal quote from HAKMEM item 154, out of context--you
+would not like to put any arbitrary upper limit on the length of your
+symbols.
+
+In practice this often means you will build many short symbols and a
+few long symbols.  At the time you are reading a symbol you don't know
+how long it is.  One traditional method is to read a symbol into a
+buffer, realloc()ating the buffer every time you try to read a symbol
+that is longer than the buffer.  This is beaut, but you still will
+want to copy the symbol from the buffer to a more permanent
+symbol-table entry say about half the time.
+
+With obstacks, you can work differently.  Use one obstack for all symbol
+names.  As you read a symbol, grow the name in the obstack gradually.
+When the name is complete, finalize it.  Then, if the symbol exists already,
+free the newly read name.
+
+The way we do this is to take a large chunk, allocating memory from
+low addresses.  When you want to build a symbol in the chunk you just
+add chars above the current "high water mark" in the chunk.  When you
+have finished adding chars, because you got to the end of the symbol,
+you know how long the chars are, and you can create a new object.
+Mostly the chars will not burst over the highest address of the chunk,
+because you would typically expect a chunk to be (say) 100 times as
+long as an average object.
+
+In case that isn't clear, when we have enough chars to make up
+the object, THEY ARE ALREADY CONTIGUOUS IN THE CHUNK (guaranteed)
+so we just point to it where it lies.  No moving of chars is
+needed and this is the second win: potentially long strings need
+never be explicitly shuffled. Once an object is formed, it does not
+change its address during its lifetime.
+
+When the chars burst over a chunk boundary, we allocate a larger
+chunk, and then copy the partly formed object from the end of the old
+chunk to the beginning of the new larger chunk.  We then carry on
+accrediting characters to the end of the object as we normally would.
+
+A special macro is provided to add a single char at a time to a
+growing object.  This allows the use of register variables, which
+break the ordinary 'growth' macro.
+
+Summary:
+	We allocate large chunks.
+	We carve out one object at a time from the current chunk.
+	Once carved, an object never moves.
+	We are free to append data of any size to the currently
+	  growing object.
+	Exactly one object is growing in an obstack at any one time.
+	You can run one obstack per control block.
+	You may have as many control blocks as you dare.
+	Because of the way we do it, you can `unwind' an obstack
+	  back to a previous state. (You may remove objects much
+	  as you would with a stack.)
+*/
+
+
+/* Don't do the contents of this file more than once.  */
+
+#ifndef _OBSTACK_H
+#define _OBSTACK_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* We need the type of a pointer subtraction.  If __PTRDIFF_TYPE__ is
+   defined, as with GNU C, use that; that way we don't pollute the
+   namespace with <stddef.h>'s symbols.  Otherwise, include <stddef.h>
+   and use ptrdiff_t.  */
+
+#ifdef __PTRDIFF_TYPE__
+# define PTR_INT_TYPE __PTRDIFF_TYPE__
+#else
+# include <stddef.h>
+# define PTR_INT_TYPE ptrdiff_t
+#endif
+
+/* If B is the base of an object addressed by P, return the result of
+   aligning P to the next multiple of A + 1.  B and P must be of type
+   char *.  A + 1 must be a power of 2.  */
+
+#define __BPTR_ALIGN(B, P, A) ((B) + (((P) - (B) + (A)) & ~(A)))
+
+/* Similar to _BPTR_ALIGN (B, P, A), except optimize the common case
+   where pointers can be converted to integers, aligned as integers,
+   and converted back again.  If PTR_INT_TYPE is narrower than a
+   pointer (e.g., the AS/400), play it safe and compute the alignment
+   relative to B.  Otherwise, use the faster strategy of computing the
+   alignment relative to 0.  */
+
+#define __PTR_ALIGN(B, P, A)						    \
+  (sizeof (PTR_INT_TYPE) < sizeof(void *) ?                                 \
+   __BPTR_ALIGN((B), (P), (A)) :                                            \
+   (void *)__BPTR_ALIGN((PTR_INT_TYPE)(void *)0, (PTR_INT_TYPE)(P), (A))            \
+  )
+
+#include <string.h>
+
+struct _obstack_chunk		/* Lives at front of each chunk. */
+{
+  char  *limit;			/* 1 past end of this chunk */
+  struct _obstack_chunk *prev;	/* address of prior chunk or NULL */
+  char	contents[4];		/* objects begin here */
+};
+
+struct obstack		/* control current object in current chunk */
+{
+  long	chunk_size;		/* preferred size to allocate chunks in */
+  struct _obstack_chunk *chunk;	/* address of current struct obstack_chunk */
+  char	*object_base;		/* address of object we are building */
+  char	*next_free;		/* where to add next char to current object */
+  char	*chunk_limit;		/* address of char after current chunk */
+  union
+  {
+    PTR_INT_TYPE tempint;
+    void *tempptr;
+  } temp;			/* Temporary for some macros.  */
+  int   alignment_mask;		/* Mask of alignment for each object. */
+  /* These prototypes vary based on `use_extra_arg'. */
+  union {
+    void *(*plain) (long);
+    struct _obstack_chunk *(*extra) (void *, long);
+  } chunkfun;
+  union {
+    void (*plain) (void *);
+    void (*extra) (void *, struct _obstack_chunk *);
+  } freefun;
+  void *extra_arg;		/* first arg for chunk alloc/dealloc funcs */
+  unsigned use_extra_arg:1;	/* chunk alloc/dealloc funcs take extra arg */
+  unsigned maybe_empty_object:1;/* There is a possibility that the current
+				   chunk contains a zero-length object.  This
+				   prevents freeing the chunk if we allocate
+				   a bigger chunk to replace it. */
+  unsigned alloc_failed:1;	/* No longer used, as we now call the failed
+				   handler on error, but retained for binary
+				   compatibility.  */
+};
+
+/* Declare the external functions we use; they are in obstack.c.  */
+
+extern void _obstack_newchunk (struct obstack *, int);
+extern int _obstack_begin (struct obstack *, int, int,
+			    void *(*) (long), void (*) (void *));
+extern int _obstack_begin_1 (struct obstack *, int, int,
+			     void *(*) (void *, long),
+			     void (*) (void *, void *), void *);
+extern int _obstack_memory_used (struct obstack *);
+
+void obstack_free (struct obstack *, void *);
+
+
+/* Error handler called when `obstack_chunk_alloc' failed to allocate
+   more memory.  This can be set to a user defined function which
+   should either abort gracefully or use longjump - but shouldn't
+   return.  The default action is to print a message and abort.  */
+extern void (*obstack_alloc_failed_handler) (void);
+
+/* Pointer to beginning of object being allocated or to be allocated next.
+   Note that this might not be the final address of the object
+   because a new chunk might be needed to hold the final size.  */
+
+#define obstack_base(h) ((void *) (h)->object_base)
+
+/* Size for allocating ordinary chunks.  */
+
+#define obstack_chunk_size(h) ((h)->chunk_size)
+
+/* Pointer to next byte not yet allocated in current chunk.  */
+
+#define obstack_next_free(h)	((h)->next_free)
+
+/* Mask specifying low bits that should be clear in address of an object.  */
+
+#define obstack_alignment_mask(h) ((h)->alignment_mask)
+
+/* To prevent prototype warnings provide complete argument list.  */
+#define obstack_init(h)						\
+  _obstack_begin ((h), 0, 0,					\
+		  (void *(*) (long)) obstack_chunk_alloc,	\
+		  (void (*) (void *)) obstack_chunk_free)
+
+#define obstack_begin(h, size)					\
+  _obstack_begin ((h), (size), 0,				\
+		  (void *(*) (long)) obstack_chunk_alloc,	\
+		  (void (*) (void *)) obstack_chunk_free)
+
+#define obstack_specify_allocation(h, size, alignment, chunkfun, freefun)  \
+  _obstack_begin ((h), (size), (alignment),				   \
+		  (void *(*) (long)) (chunkfun),			   \
+		  (void (*) (void *)) (freefun))
+
+#define obstack_specify_allocation_with_arg(h, size, alignment, chunkfun, freefun, arg) \
+  _obstack_begin_1 ((h), (size), (alignment),				\
+		    (void *(*) (void *, long)) (chunkfun),		\
+		    (void (*) (void *, void *)) (freefun), (arg))
+
+#define obstack_chunkfun(h, newchunkfun) \
+  ((h)->chunkfun.extra = (struct _obstack_chunk *(*)(void *, long)) (newchunkfun))
+
+#define obstack_freefun(h, newfreefun) \
+  ((h)->freefun.extra = (void (*)(void *, struct _obstack_chunk *)) (newfreefun))
+
+#define obstack_1grow_fast(h,achar) (*((h)->next_free)++ = (achar))
+
+#define obstack_blank_fast(h,n) ((h)->next_free += (n))
+
+#define obstack_memory_used(h) _obstack_memory_used (h)
+
+#if defined __GNUC__ && defined __STDC__ && __STDC__
+/* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and
+   does not implement __extension__.  But that compiler doesn't define
+   __GNUC_MINOR__.  */
+# if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__)
+#  define __extension__
+# endif
+
+/* For GNU C, if not -traditional,
+   we can define these macros to compute all args only once
+   without using a global variable.
+   Also, we can avoid using the `temp' slot, to make faster code.  */
+
+# define obstack_object_size(OBSTACK)					\
+  __extension__								\
+  ({ struct obstack const *__o = (OBSTACK);				\
+     (unsigned) (__o->next_free - __o->object_base); })
+
+# define obstack_room(OBSTACK)						\
+  __extension__								\
+  ({ struct obstack const *__o = (OBSTACK);				\
+     (unsigned) (__o->chunk_limit - __o->next_free); })
+
+# define obstack_make_room(OBSTACK,length)				\
+__extension__								\
+({ struct obstack *__o = (OBSTACK);					\
+   int __len = (length);						\
+   if (__o->chunk_limit - __o->next_free < __len)			\
+     _obstack_newchunk (__o, __len);					\
+   (void) 0; })
+
+# define obstack_empty_p(OBSTACK)					\
+  __extension__								\
+  ({ struct obstack const *__o = (OBSTACK);				\
+     (__o->chunk->prev == 0						\
+      && __o->next_free == __PTR_ALIGN ((char *) __o->chunk,		\
+					__o->chunk->contents,		\
+					__o->alignment_mask)); })
+
+# define obstack_grow(OBSTACK,where,length)				\
+__extension__								\
+({ struct obstack *__o = (OBSTACK);					\
+   int __len = (length);						\
+   if (__o->next_free + __len > __o->chunk_limit)			\
+     _obstack_newchunk (__o, __len);					\
+   memcpy (__o->next_free, where, __len);				\
+   __o->next_free += __len;						\
+   (void) 0; })
+
+# define obstack_grow0(OBSTACK,where,length)				\
+__extension__								\
+({ struct obstack *__o = (OBSTACK);					\
+   int __len = (length);						\
+   if (__o->next_free + __len + 1 > __o->chunk_limit)			\
+     _obstack_newchunk (__o, __len + 1);				\
+   memcpy (__o->next_free, where, __len);				\
+   __o->next_free += __len;						\
+   *(__o->next_free)++ = 0;						\
+   (void) 0; })
+
+# define obstack_1grow(OBSTACK,datum)					\
+__extension__								\
+({ struct obstack *__o = (OBSTACK);					\
+   if (__o->next_free + 1 > __o->chunk_limit)				\
+     _obstack_newchunk (__o, 1);					\
+   obstack_1grow_fast (__o, datum);					\
+   (void) 0; })
+
+/* These assume that the obstack alignment is good enough for pointers
+   or ints, and that the data added so far to the current object
+   shares that much alignment.  */
+
+# define obstack_ptr_grow(OBSTACK,datum)				\
+__extension__								\
+({ struct obstack *__o = (OBSTACK);					\
+   if (__o->next_free + sizeof (void *) > __o->chunk_limit)		\
+     _obstack_newchunk (__o, sizeof (void *));				\
+   obstack_ptr_grow_fast (__o, datum); })				\
+
+# define obstack_int_grow(OBSTACK,datum)				\
+__extension__								\
+({ struct obstack *__o = (OBSTACK);					\
+   if (__o->next_free + sizeof (int) > __o->chunk_limit)		\
+     _obstack_newchunk (__o, sizeof (int));				\
+   obstack_int_grow_fast (__o, datum); })
+
+# define obstack_ptr_grow_fast(OBSTACK,aptr)				\
+__extension__								\
+({ struct obstack *__o1 = (OBSTACK);					\
+   *(const void **) __o1->next_free = (aptr);				\
+   __o1->next_free += sizeof (const void *);				\
+   (void) 0; })
+
+# define obstack_int_grow_fast(OBSTACK,aint)				\
+__extension__								\
+({ struct obstack *__o1 = (OBSTACK);					\
+   *(int *) __o1->next_free = (aint);					\
+   __o1->next_free += sizeof (int);					\
+   (void) 0; })
+
+# define obstack_blank(OBSTACK,length)					\
+__extension__								\
+({ struct obstack *__o = (OBSTACK);					\
+   int __len = (length);						\
+   if (__o->chunk_limit - __o->next_free < __len)			\
+     _obstack_newchunk (__o, __len);					\
+   obstack_blank_fast (__o, __len);					\
+   (void) 0; })
+
+# define obstack_alloc(OBSTACK,length)					\
+__extension__								\
+({ struct obstack *__h = (OBSTACK);					\
+   obstack_blank (__h, (length));					\
+   obstack_finish (__h); })
+
+# define obstack_copy(OBSTACK,where,length)				\
+__extension__								\
+({ struct obstack *__h = (OBSTACK);					\
+   obstack_grow (__h, (where), (length));				\
+   obstack_finish (__h); })
+
+# define obstack_copy0(OBSTACK,where,length)				\
+__extension__								\
+({ struct obstack *__h = (OBSTACK);					\
+   obstack_grow0 (__h, (where), (length));				\
+   obstack_finish (__h); })
+
+/* The local variable is named __o1 to avoid a name conflict
+   when obstack_blank is called.  */
+# define obstack_finish(OBSTACK)					\
+__extension__								\
+({ struct obstack *__o1 = (OBSTACK);					\
+   void *__value = (void *) __o1->object_base;				\
+   if (__o1->next_free == __value)					\
+     __o1->maybe_empty_object = 1;					\
+   __o1->next_free							\
+     = __PTR_ALIGN (__o1->object_base, __o1->next_free,			\
+		    __o1->alignment_mask);				\
+   if (__o1->next_free - (char *)__o1->chunk				\
+       > __o1->chunk_limit - (char *)__o1->chunk)			\
+     __o1->next_free = __o1->chunk_limit;				\
+   __o1->object_base = __o1->next_free;					\
+   __value; })
+
+# define obstack_free(OBSTACK, OBJ)					\
+__extension__								\
+({ struct obstack *__o = (OBSTACK);					\
+   void *__obj = (OBJ);							\
+   if (__obj > (void *)__o->chunk && __obj < (void *)__o->chunk_limit)  \
+     __o->next_free = __o->object_base = (char *)__obj;			\
+   else (obstack_free) (__o, __obj); })
+
+#else /* not __GNUC__ or not __STDC__ */
+
+# define obstack_object_size(h) \
+ (unsigned) ((h)->next_free - (h)->object_base)
+
+# define obstack_room(h)		\
+ (unsigned) ((h)->chunk_limit - (h)->next_free)
+
+# define obstack_empty_p(h) \
+ ((h)->chunk->prev == 0							\
+  && (h)->next_free == __PTR_ALIGN ((char *) (h)->chunk,		\
+				    (h)->chunk->contents,		\
+				    (h)->alignment_mask))
+
+/* Note that the call to _obstack_newchunk is enclosed in (..., 0)
+   so that we can avoid having void expressions
+   in the arms of the conditional expression.
+   Casting the third operand to void was tried before,
+   but some compilers won't accept it.  */
+
+# define obstack_make_room(h,length)					\
+( (h)->temp.tempint = (length),						\
+  (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)		\
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0))
+
+# define obstack_grow(h,where,length)					\
+( (h)->temp.tempint = (length),						\
+  (((h)->next_free + (h)->temp.tempint > (h)->chunk_limit)		\
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),		\
+  memcpy ((h)->next_free, where, (h)->temp.tempint),			\
+  (h)->next_free += (h)->temp.tempint)
+
+# define obstack_grow0(h,where,length)					\
+( (h)->temp.tempint = (length),						\
+  (((h)->next_free + (h)->temp.tempint + 1 > (h)->chunk_limit)		\
+   ? (_obstack_newchunk ((h), (h)->temp.tempint + 1), 0) : 0),		\
+  memcpy ((h)->next_free, where, (h)->temp.tempint),			\
+  (h)->next_free += (h)->temp.tempint,					\
+  *((h)->next_free)++ = 0)
+
+# define obstack_1grow(h,datum)						\
+( (((h)->next_free + 1 > (h)->chunk_limit)				\
+   ? (_obstack_newchunk ((h), 1), 0) : 0),				\
+  obstack_1grow_fast (h, datum))
+
+# define obstack_ptr_grow(h,datum)					\
+( (((h)->next_free + sizeof (char *) > (h)->chunk_limit)		\
+   ? (_obstack_newchunk ((h), sizeof (char *)), 0) : 0),		\
+  obstack_ptr_grow_fast (h, datum))
+
+# define obstack_int_grow(h,datum)					\
+( (((h)->next_free + sizeof (int) > (h)->chunk_limit)			\
+   ? (_obstack_newchunk ((h), sizeof (int)), 0) : 0),			\
+  obstack_int_grow_fast (h, datum))
+
+# define obstack_ptr_grow_fast(h,aptr)					\
+  (((const void **) ((h)->next_free += sizeof (void *)))[-1] = (aptr))
+
+# define obstack_int_grow_fast(h,aint)					\
+  (((int *) ((h)->next_free += sizeof (int)))[-1] = (aint))
+
+# define obstack_blank(h,length)					\
+( (h)->temp.tempint = (length),						\
+  (((h)->chunk_limit - (h)->next_free < (h)->temp.tempint)		\
+   ? (_obstack_newchunk ((h), (h)->temp.tempint), 0) : 0),		\
+  obstack_blank_fast (h, (h)->temp.tempint))
+
+# define obstack_alloc(h,length)					\
+ (obstack_blank ((h), (length)), obstack_finish ((h)))
+
+# define obstack_copy(h,where,length)					\
+ (obstack_grow ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_copy0(h,where,length)					\
+ (obstack_grow0 ((h), (where), (length)), obstack_finish ((h)))
+
+# define obstack_finish(h)						\
+( ((h)->next_free == (h)->object_base					\
+   ? (((h)->maybe_empty_object = 1), 0)					\
+   : 0),								\
+  (h)->temp.tempptr = (h)->object_base,					\
+  (h)->next_free							\
+    = __PTR_ALIGN ((h)->object_base, (h)->next_free,			\
+		   (h)->alignment_mask),				\
+  (((h)->next_free - (char *) (h)->chunk				\
+    > (h)->chunk_limit - (char *) (h)->chunk)				\
+   ? ((h)->next_free = (h)->chunk_limit) : 0),				\
+  (h)->object_base = (h)->next_free,					\
+  (h)->temp.tempptr)
+
+# define obstack_free(h,obj)						\
+( (h)->temp.tempint = (char *) (obj) - (char *) (h)->chunk,		\
+  ((((h)->temp.tempint > 0						\
+    && (h)->temp.tempint < (h)->chunk_limit - (char *) (h)->chunk))	\
+   ? (ptrdiff_t) ((h)->next_free = (h)->object_base				\
+	    = (h)->temp.tempint + (char *) (h)->chunk)			\
+   : (((obstack_free) ((h), (h)->temp.tempint + (char *) (h)->chunk), 0), 0)))
+
+#endif /* not __GNUC__ or not __STDC__ */
+
+#ifdef __cplusplus
+}	/* C++ */
+#endif
+
+#endif /* obstack.h */
diff --git a/compat/open.c b/compat/open.c
new file mode 100644
index 0000000000..eb3754a23b
--- /dev/null
+++ b/compat/open.c
@@ -0,0 +1,25 @@
+#include "git-compat-util.h"
+
+#undef open
+int git_open_with_retry(const char *path, int flags, ...)
+{
+	mode_t mode = 0;
+	int ret;
+
+	/*
+	 * Also O_TMPFILE would take a mode, but it isn't defined everywhere.
+	 * And anyway, we don't use it in our code base.
+	 */
+	if (flags & O_CREAT) {
+		va_list ap;
+		va_start(ap, flags);
+		mode = va_arg(ap, int);
+		va_end(ap);
+	}
+
+	do {
+		ret = open(path, flags, mode);
+	} while (ret < 0 && errno == EINTR);
+
+	return ret;
+}
diff --git a/compat/poll/poll.c b/compat/poll/poll.c
new file mode 100644
index 0000000000..a2becd16cd
--- /dev/null
+++ b/compat/poll/poll.c
@@ -0,0 +1,610 @@
+/* Emulation for poll(2)
+   Contributed by Paolo Bonzini.
+
+   Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc.
+
+   This file is part of gnulib.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+/* To bump the minimum Windows version to Windows Vista */
+#include "git-compat-util.h"
+
+/* Tell gcc not to warn about the (nfd < 0) tests, below.  */
+#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+#if defined(WIN32)
+# include <malloc.h>
+#endif
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <assert.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+# define WIN32_NATIVE
+# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
+#  define _WIN32_WINNT 0x0502
+# endif
+# include <winsock2.h>
+# include <windows.h>
+# include <io.h>
+# include <stdio.h>
+# include <conio.h>
+#else
+# include <sys/time.h>
+# include <sys/socket.h>
+# ifndef NO_SYS_SELECT_H
+#  include <sys/select.h>
+# endif
+# include <unistd.h>
+#endif
+
+/* Specification.  */
+#include "poll.h"
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+
+#include <time.h>
+
+#ifndef INFTIM
+# define INFTIM (-1)
+#endif
+
+/* BeOS does not have MSG_PEEK.  */
+#ifndef MSG_PEEK
+# define MSG_PEEK 0
+#endif
+
+#ifdef WIN32_NATIVE
+
+#define IsConsoleHandle(h) (((long) (intptr_t) (h) & 3) == 3)
+
+static BOOL
+IsSocketHandle (HANDLE h)
+{
+  WSANETWORKEVENTS ev;
+
+  if (IsConsoleHandle (h))
+    return FALSE;
+
+  /* Under Wine, it seems that getsockopt returns 0 for pipes too.
+     WSAEnumNetworkEvents instead distinguishes the two correctly.  */
+  ev.lNetworkEvents = 0xDEADBEEF;
+  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+  return ev.lNetworkEvents != 0xDEADBEEF;
+}
+
+/* Declare data structures for ntdll functions.  */
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+  ULONG NamedPipeType;
+  ULONG NamedPipeConfiguration;
+  ULONG MaximumInstances;
+  ULONG CurrentInstances;
+  ULONG InboundQuota;
+  ULONG ReadDataAvailable;
+  ULONG OutboundQuota;
+  ULONG WriteQuotaAvailable;
+  ULONG NamedPipeState;
+  ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+typedef struct _IO_STATUS_BLOCK
+{
+  union {
+    DWORD Status;
+    PVOID Pointer;
+  } u;
+  ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+  FilePipeLocalInformation = 24
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef DWORD (WINAPI *PNtQueryInformationFile)
+	 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
+
+# ifndef PIPE_BUF
+#  define PIPE_BUF      512
+# endif
+
+/* Compute revents values for file handle H.  If some events cannot happen
+   for the handle, eliminate them from *P_SOUGHT.  */
+
+static int
+win32_compute_revents (HANDLE h, int *p_sought)
+{
+  int i, ret, happened;
+  INPUT_RECORD *irbuffer;
+  DWORD avail, nbuffer;
+  BOOL bRet;
+
+  switch (GetFileType (h))
+    {
+    case FILE_TYPE_PIPE:
+      happened = 0;
+      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
+	{
+	  if (avail)
+	    happened |= *p_sought & (POLLIN | POLLRDNORM);
+	}
+      else if (GetLastError () == ERROR_BROKEN_PIPE)
+	happened |= POLLHUP;
+
+      else
+	{
+	  /* It was the write-end of the pipe. Unfortunately there is no
+	     reliable way of knowing if it can be written without blocking.
+	     Just say that it's all good. */
+	    happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+	}
+      return happened;
+
+    case FILE_TYPE_CHAR:
+      ret = WaitForSingleObject (h, 0);
+      if (!IsConsoleHandle (h))
+	return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
+
+      nbuffer = avail = 0;
+      bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
+      if (bRet)
+	{
+	  /* Input buffer.  */
+	  *p_sought &= POLLIN | POLLRDNORM;
+	  if (nbuffer == 0)
+	    return POLLHUP;
+	  if (!*p_sought)
+	    return 0;
+
+	  irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
+	  bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
+	  if (!bRet || avail == 0)
+	    return POLLHUP;
+
+	  for (i = 0; i < avail; i++)
+	    if (irbuffer[i].EventType == KEY_EVENT)
+	      return *p_sought;
+	  return 0;
+	}
+      else
+	{
+	  /* Screen buffer.  */
+	  *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
+	  return *p_sought;
+	}
+
+    default:
+      ret = WaitForSingleObject (h, 0);
+      if (ret == WAIT_OBJECT_0)
+	return *p_sought & ~(POLLPRI | POLLRDBAND);
+
+      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
+    }
+}
+
+/* Convert fd_sets returned by select into revents values.  */
+
+static int
+win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
+{
+  int happened = 0;
+
+  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
+    happened |= (POLLIN | POLLRDNORM) & sought;
+
+  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
+    {
+      int r, error;
+
+      char data[64];
+      WSASetLastError (0);
+      r = recv (h, data, sizeof (data), MSG_PEEK);
+      error = WSAGetLastError ();
+      WSASetLastError (0);
+
+      if (r > 0 || error == WSAENOTCONN)
+	happened |= (POLLIN | POLLRDNORM) & sought;
+
+      /* Distinguish hung-up sockets from other errors.  */
+      else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
+	       || error == WSAECONNABORTED || error == WSAENETRESET)
+	happened |= POLLHUP;
+
+      else
+	happened |= POLLERR;
+    }
+
+  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
+    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+  if (lNetworkEvents & FD_OOB)
+    happened |= (POLLPRI | POLLRDBAND) & sought;
+
+  return happened;
+}
+
+#else /* !MinGW */
+
+/* Convert select(2) returned fd_sets into poll(2) revents values.  */
+static int
+compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
+{
+  int happened = 0;
+  if (FD_ISSET (fd, rfds))
+    {
+      int r;
+      int socket_errno;
+
+# if defined __MACH__ && defined __APPLE__
+      /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
+	 for some kinds of descriptors.  Detect if this descriptor is a
+	 connected socket, a server socket, or something else using a
+	 0-byte recv, and use ioctl(2) to detect POLLHUP.  */
+      r = recv (fd, NULL, 0, MSG_PEEK);
+      socket_errno = (r < 0) ? errno : 0;
+      if (r == 0 || socket_errno == ENOTSOCK)
+	ioctl (fd, FIONREAD, &r);
+# else
+      char data[64];
+      r = recv (fd, data, sizeof (data), MSG_PEEK);
+      socket_errno = (r < 0) ? errno : 0;
+# endif
+      if (r == 0)
+	happened |= POLLHUP;
+
+      /* If the event happened on an unconnected server socket,
+	 that's fine. */
+      else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
+	happened |= (POLLIN | POLLRDNORM) & sought;
+
+      /* Distinguish hung-up sockets from other errors.  */
+      else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
+	       || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
+	happened |= POLLHUP;
+
+      /* some systems can't use recv() on non-socket, including HP NonStop */
+      else if (/* (r == -1) && */ socket_errno == ENOTSOCK)
+	happened |= (POLLIN | POLLRDNORM) & sought;
+
+      else
+	happened |= POLLERR;
+    }
+
+  if (FD_ISSET (fd, wfds))
+    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
+
+  if (FD_ISSET (fd, efds))
+    happened |= (POLLPRI | POLLRDBAND) & sought;
+
+  return happened;
+}
+#endif /* !MinGW */
+
+int
+poll (struct pollfd *pfd, nfds_t nfd, int timeout)
+{
+#ifndef WIN32_NATIVE
+  fd_set rfds, wfds, efds;
+  struct timeval tv;
+  struct timeval *ptv;
+  int maxfd, rc;
+  nfds_t i;
+
+# ifdef _SC_OPEN_MAX
+  static int sc_open_max = -1;
+
+  if (nfd < 0
+      || (nfd > sc_open_max
+	  && (sc_open_max != -1
+	      || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
+    {
+      errno = EINVAL;
+      return -1;
+    }
+# else /* !_SC_OPEN_MAX */
+#  ifdef OPEN_MAX
+  if (nfd < 0 || nfd > OPEN_MAX)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+#  endif /* OPEN_MAX -- else, no check is needed */
+# endif /* !_SC_OPEN_MAX */
+
+  /* EFAULT is not necessary to implement, but let's do it in the
+     simplest case. */
+  if (!pfd && nfd)
+    {
+      errno = EFAULT;
+      return -1;
+    }
+
+  /* convert timeout number into a timeval structure */
+  if (timeout == 0)
+    {
+      ptv = &tv;
+      ptv->tv_sec = 0;
+      ptv->tv_usec = 0;
+    }
+  else if (timeout > 0)
+    {
+      ptv = &tv;
+      ptv->tv_sec = timeout / 1000;
+      ptv->tv_usec = (timeout % 1000) * 1000;
+    }
+  else if (timeout == INFTIM)
+    /* wait forever */
+    ptv = NULL;
+  else
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  /* create fd sets and determine max fd */
+  maxfd = -1;
+  FD_ZERO (&rfds);
+  FD_ZERO (&wfds);
+  FD_ZERO (&efds);
+  for (i = 0; i < nfd; i++)
+    {
+      if (pfd[i].fd < 0)
+	continue;
+
+      if (pfd[i].events & (POLLIN | POLLRDNORM))
+	FD_SET (pfd[i].fd, &rfds);
+
+      /* see select(2): "the only exceptional condition detectable
+	 is out-of-band data received on a socket", hence we push
+	 POLLWRBAND events onto wfds instead of efds. */
+      if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
+	FD_SET (pfd[i].fd, &wfds);
+      if (pfd[i].events & (POLLPRI | POLLRDBAND))
+	FD_SET (pfd[i].fd, &efds);
+      if (pfd[i].fd >= maxfd
+	  && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
+			       | POLLRDNORM | POLLRDBAND
+			       | POLLWRNORM | POLLWRBAND)))
+	{
+	  maxfd = pfd[i].fd;
+	  if (maxfd > FD_SETSIZE)
+	    {
+	      errno = EOVERFLOW;
+	      return -1;
+	    }
+	}
+    }
+
+  /* examine fd sets */
+  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
+  if (rc < 0)
+    return rc;
+
+  /* establish results */
+  rc = 0;
+  for (i = 0; i < nfd; i++)
+    if (pfd[i].fd < 0)
+      pfd[i].revents = 0;
+    else
+      {
+	int happened = compute_revents (pfd[i].fd, pfd[i].events,
+					&rfds, &wfds, &efds);
+	if (happened)
+	  {
+	    pfd[i].revents = happened;
+	    rc++;
+	  }
+	else
+	  {
+	    pfd[i].revents = 0;
+	  }
+      }
+
+  return rc;
+#else
+  static struct timeval tv0;
+  static HANDLE hEvent;
+  WSANETWORKEVENTS ev;
+  HANDLE h, handle_array[FD_SETSIZE + 2];
+  DWORD ret, wait_timeout, nhandles, orig_timeout = 0;
+  ULONGLONG start = 0;
+  fd_set rfds, wfds, xfds;
+  BOOL poll_again;
+  MSG msg;
+  int rc = 0;
+  nfds_t i;
+
+  if (nfd < 0 || timeout < -1)
+    {
+      errno = EINVAL;
+      return -1;
+    }
+
+  if (timeout != INFTIM)
+    {
+      orig_timeout = timeout;
+      start = GetTickCount64();
+    }
+
+  if (!hEvent)
+    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+
+restart:
+  handle_array[0] = hEvent;
+  nhandles = 1;
+  FD_ZERO (&rfds);
+  FD_ZERO (&wfds);
+  FD_ZERO (&xfds);
+
+  /* Classify socket handles and create fd sets. */
+  for (i = 0; i < nfd; i++)
+    {
+      int sought = pfd[i].events;
+      pfd[i].revents = 0;
+      if (pfd[i].fd < 0)
+	continue;
+      if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
+		      | POLLPRI | POLLRDBAND)))
+	continue;
+
+      h = (HANDLE) _get_osfhandle (pfd[i].fd);
+      assert (h != NULL);
+      if (IsSocketHandle (h))
+	{
+	  int requested = FD_CLOSE;
+
+	  /* see above; socket handles are mapped onto select.  */
+	  if (sought & (POLLIN | POLLRDNORM))
+	    {
+	      requested |= FD_READ | FD_ACCEPT;
+	      FD_SET ((SOCKET) h, &rfds);
+	    }
+	  if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
+	    {
+	      requested |= FD_WRITE | FD_CONNECT;
+	      FD_SET ((SOCKET) h, &wfds);
+	    }
+	  if (sought & (POLLPRI | POLLRDBAND))
+	    {
+	      requested |= FD_OOB;
+	      FD_SET ((SOCKET) h, &xfds);
+	    }
+
+	  if (requested)
+	    WSAEventSelect ((SOCKET) h, hEvent, requested);
+	}
+      else
+	{
+	  /* Poll now.  If we get an event, do not poll again.  Also,
+	     screen buffer handles are waitable, and they'll block until
+	     a character is available.  win32_compute_revents eliminates
+	     bits for the "wrong" direction. */
+	  pfd[i].revents = win32_compute_revents (h, &sought);
+	  if (sought)
+	    handle_array[nhandles++] = h;
+	  if (pfd[i].revents)
+	    timeout = 0;
+	}
+    }
+
+  if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
+    {
+      /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
+	 no need to call select again.  */
+      poll_again = FALSE;
+      wait_timeout = 0;
+    }
+  else
+    {
+      poll_again = TRUE;
+      if (timeout == INFTIM)
+	wait_timeout = INFINITE;
+      else
+	wait_timeout = timeout;
+    }
+
+  for (;;)
+    {
+      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
+				       wait_timeout, QS_ALLINPUT);
+
+      if (ret == WAIT_OBJECT_0 + nhandles)
+	{
+	  /* new input of some other kind */
+	  BOOL bRet;
+	  while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
+	    {
+	      TranslateMessage (&msg);
+	      DispatchMessage (&msg);
+	    }
+	}
+      else
+	break;
+    }
+
+  if (poll_again)
+    select (0, &rfds, &wfds, &xfds, &tv0);
+
+  /* Place a sentinel at the end of the array.  */
+  handle_array[nhandles] = NULL;
+  nhandles = 1;
+  for (i = 0; i < nfd; i++)
+    {
+      int happened;
+
+      if (pfd[i].fd < 0)
+	continue;
+      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
+			     POLLOUT | POLLWRNORM | POLLWRBAND)))
+	continue;
+
+      h = (HANDLE) _get_osfhandle (pfd[i].fd);
+      if (h != handle_array[nhandles])
+	{
+	  /* It's a socket.  */
+	  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
+	  WSAEventSelect ((SOCKET) h, NULL, 0);
+
+	  /* If we're lucky, WSAEnumNetworkEvents already provided a way
+	     to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */
+	  if (FD_ISSET ((SOCKET) h, &rfds)
+	      && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
+	    ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
+	  if (FD_ISSET ((SOCKET) h, &wfds))
+	    ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
+	  if (FD_ISSET ((SOCKET) h, &xfds))
+	    ev.lNetworkEvents |= FD_OOB;
+
+	  happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
+						   ev.lNetworkEvents);
+	}
+      else
+	{
+	  /* Not a socket.  */
+	  int sought = pfd[i].events;
+	  happened = win32_compute_revents (h, &sought);
+	  nhandles++;
+	}
+
+       if ((pfd[i].revents |= happened) != 0)
+	rc++;
+    }
+
+  if (!rc && orig_timeout && timeout != INFTIM)
+    {
+      ULONGLONG elapsed = GetTickCount64() - start;
+      timeout = elapsed >= orig_timeout ? 0 : (int)(orig_timeout - elapsed);
+    }
+
+  if (!rc && timeout)
+    {
+      SleepEx (1, TRUE);
+      goto restart;
+    }
+
+  return rc;
+#endif
+}
diff --git a/compat/poll/poll.h b/compat/poll/poll.h
new file mode 100644
index 0000000000..1e1597360f
--- /dev/null
+++ b/compat/poll/poll.h
@@ -0,0 +1,67 @@
+/* Header for poll(2) emulation
+   Contributed by Paolo Bonzini.
+
+   Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc.
+
+   This file is part of gnulib.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _GL_POLL_H
+#define _GL_POLL_H
+
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
+/* Vista has its own, socket-only poll() */
+#undef POLLIN
+#undef POLLPRI
+#undef POLLOUT
+#undef POLLERR
+#undef POLLHUP
+#undef POLLNVAL
+#undef POLLRDNORM
+#undef POLLRDBAND
+#undef POLLWRNORM
+#undef POLLWRBAND
+#define pollfd compat_pollfd
+#endif
+
+/* fake a poll(2) environment */
+#define POLLIN      0x0001      /* any readable data available   */
+#define POLLPRI     0x0002      /* OOB/Urgent readable data      */
+#define POLLOUT     0x0004      /* file descriptor is writeable  */
+#define POLLERR     0x0008      /* some poll error occurred      */
+#define POLLHUP     0x0010      /* file descriptor was "hung up" */
+#define POLLNVAL    0x0020      /* requested events "invalid"    */
+#define POLLRDNORM  0x0040
+#define POLLRDBAND  0x0080
+#define POLLWRNORM  0x0100
+#define POLLWRBAND  0x0200
+
+struct pollfd
+{
+  int fd;                       /* which file descriptor to poll */
+  short events;                 /* events we are interested in   */
+  short revents;                /* events found on return        */
+};
+
+typedef unsigned long nfds_t;
+
+extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout);
+
+/* Define INFTIM only if doing so conforms to POSIX.  */
+#if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE)
+#define INFTIM (-1)
+#endif
+
+#endif /* _GL_POLL_H */
diff --git a/compat/pread.c b/compat/pread.c
new file mode 100644
index 0000000000..484e6d4c71
--- /dev/null
+++ b/compat/pread.c
@@ -0,0 +1,19 @@
+#include "../git-compat-util.h"
+#include "../wrapper.h"
+
+ssize_t git_pread(int fd, void *buf, size_t count, off_t offset)
+{
+        off_t current_offset;
+        ssize_t rc;
+
+        current_offset = lseek(fd, 0, SEEK_CUR);
+
+        if (lseek(fd, offset, SEEK_SET) < 0)
+                return -1;
+
+        rc = read_in_full(fd, buf, count);
+
+        if (current_offset != lseek(fd, current_offset, SEEK_SET))
+                return -1;
+        return rc;
+}
diff --git a/compat/precompose_utf8.c b/compat/precompose_utf8.c
new file mode 100644
index 0000000000..f7cc7b3be5
--- /dev/null
+++ b/compat/precompose_utf8.c
@@ -0,0 +1,202 @@
+/*
+ * Converts filenames from decomposed unicode into precomposed unicode.
+ * Used on MacOS X.
+ */
+
+#define PRECOMPOSE_UNICODE_C
+#define USE_THE_REPOSITORY_VARIABLE
+
+#include "git-compat-util.h"
+#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "path.h"
+#include "strbuf.h"
+#include "utf8.h"
+#include "precompose_utf8.h"
+
+typedef char *iconv_ibp;
+static const char *repo_encoding = "UTF-8";
+static const char *path_encoding = "UTF-8-MAC";
+
+static size_t has_non_ascii(const char *s, size_t maxlen, size_t *strlen_c)
+{
+	const uint8_t *ptr = (const uint8_t *)s;
+	size_t strlen_chars = 0;
+	size_t ret = 0;
+
+	if (!ptr || !*ptr)
+		return 0;
+
+	while (*ptr && maxlen) {
+		if (*ptr & 0x80)
+			ret++;
+		strlen_chars++;
+		ptr++;
+		maxlen--;
+	}
+	if (strlen_c)
+		*strlen_c = strlen_chars;
+
+	return ret;
+}
+
+
+void probe_utf8_pathname_composition(void)
+{
+	struct strbuf path = STRBUF_INIT;
+	static const char *auml_nfc = "\xc3\xa4";
+	static const char *auml_nfd = "\x61\xcc\x88";
+	int output_fd;
+	if (precomposed_unicode != -1)
+		return; /* We found it defined in the global config, respect it */
+	git_path_buf(&path, "%s", auml_nfc);
+	output_fd = open(path.buf, O_CREAT|O_EXCL|O_RDWR, 0600);
+	if (output_fd >= 0) {
+		close(output_fd);
+		git_path_buf(&path, "%s", auml_nfd);
+		precomposed_unicode = access(path.buf, R_OK) ? 0 : 1;
+		git_config_set("core.precomposeunicode",
+			       precomposed_unicode ? "true" : "false");
+		git_path_buf(&path, "%s", auml_nfc);
+		if (unlink(path.buf))
+			die_errno(_("failed to unlink '%s'"), path.buf);
+	}
+	strbuf_release(&path);
+}
+
+const char *precompose_string_if_needed(const char *in)
+{
+	size_t inlen;
+	size_t outlen;
+	if (!in)
+		return NULL;
+	if (has_non_ascii(in, (size_t)-1, &inlen)) {
+		iconv_t ic_prec;
+		char *out;
+		if (precomposed_unicode < 0)
+			git_config_get_bool("core.precomposeunicode", &precomposed_unicode);
+		if (precomposed_unicode != 1)
+			return in;
+		ic_prec = iconv_open(repo_encoding, path_encoding);
+		if (ic_prec == (iconv_t) -1)
+			return in;
+
+		out = reencode_string_iconv(in, inlen, ic_prec, 0, &outlen);
+		if (out) {
+			if (outlen == inlen && !memcmp(in, out, outlen))
+				free(out); /* no need to return indentical */
+			else
+				in = out;
+		}
+		iconv_close(ic_prec);
+
+	}
+	return in;
+}
+
+const char *precompose_argv_prefix(int argc, const char **argv, const char *prefix)
+{
+	int i = 0;
+
+	while (i < argc) {
+		argv[i] = precompose_string_if_needed(argv[i]);
+		i++;
+	}
+	return precompose_string_if_needed(prefix);
+}
+
+
+PREC_DIR *precompose_utf8_opendir(const char *dirname)
+{
+	PREC_DIR *prec_dir = xmalloc(sizeof(PREC_DIR));
+	prec_dir->dirent_nfc = xmalloc(sizeof(dirent_prec_psx));
+	prec_dir->dirent_nfc->max_name_len = sizeof(prec_dir->dirent_nfc->d_name);
+
+	prec_dir->dirp = opendir(dirname);
+	if (!prec_dir->dirp) {
+		free(prec_dir->dirent_nfc);
+		free(prec_dir);
+		return NULL;
+	} else {
+		int ret_errno = errno;
+		prec_dir->ic_precompose = iconv_open(repo_encoding, path_encoding);
+		/* if iconv_open() fails, die() in readdir() if needed */
+		errno = ret_errno;
+	}
+
+	return prec_dir;
+}
+
+struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *prec_dir)
+{
+	struct dirent *res;
+	res = readdir(prec_dir->dirp);
+	if (res) {
+		size_t namelenz = strlen(res->d_name) + 1; /* \0 */
+		size_t new_maxlen = namelenz;
+
+		int ret_errno = errno;
+
+		if (new_maxlen > prec_dir->dirent_nfc->max_name_len) {
+			size_t new_len = sizeof(dirent_prec_psx) + new_maxlen -
+				sizeof(prec_dir->dirent_nfc->d_name);
+
+			prec_dir->dirent_nfc = xrealloc(prec_dir->dirent_nfc, new_len);
+			prec_dir->dirent_nfc->max_name_len = new_maxlen;
+		}
+
+		prec_dir->dirent_nfc->d_ino  = res->d_ino;
+		prec_dir->dirent_nfc->d_type = res->d_type;
+
+		if ((precomposed_unicode == 1) && has_non_ascii(res->d_name, (size_t)-1, NULL)) {
+			if (prec_dir->ic_precompose == (iconv_t)-1) {
+				die("iconv_open(%s,%s) failed, but needed:\n"
+						"    precomposed unicode is not supported.\n"
+						"    If you want to use decomposed unicode, run\n"
+						"    \"git config core.precomposeunicode false\"\n",
+						repo_encoding, path_encoding);
+			} else {
+				iconv_ibp	cp = (iconv_ibp)res->d_name;
+				size_t inleft = namelenz;
+				char *outpos = &prec_dir->dirent_nfc->d_name[0];
+				size_t outsz = prec_dir->dirent_nfc->max_name_len;
+				errno = 0;
+				iconv(prec_dir->ic_precompose, &cp, &inleft, &outpos, &outsz);
+				if (errno || inleft) {
+					/*
+					 * iconv() failed and errno could be E2BIG, EILSEQ, EINVAL, EBADF
+					 * MacOS X avoids illegal byte sequences.
+					 * If they occur on a mounted drive (e.g. NFS) it is not worth to
+					 * die() for that, but rather let the user see the original name
+					*/
+					namelenz = 0; /* trigger strlcpy */
+				}
+			}
+		} else
+			namelenz = 0;
+
+		if (!namelenz)
+			strlcpy(prec_dir->dirent_nfc->d_name, res->d_name,
+							prec_dir->dirent_nfc->max_name_len);
+
+		errno = ret_errno;
+		return prec_dir->dirent_nfc;
+	}
+	return NULL;
+}
+
+
+int precompose_utf8_closedir(PREC_DIR *prec_dir)
+{
+	int ret_value;
+	int ret_errno;
+	ret_value = closedir(prec_dir->dirp);
+	ret_errno = errno;
+	if (prec_dir->ic_precompose != (iconv_t)-1)
+		iconv_close(prec_dir->ic_precompose);
+	free(prec_dir->dirent_nfc);
+	free(prec_dir);
+	errno = ret_errno;
+	return ret_value;
+}
diff --git a/compat/precompose_utf8.h b/compat/precompose_utf8.h
new file mode 100644
index 0000000000..fea06cf28a
--- /dev/null
+++ b/compat/precompose_utf8.h
@@ -0,0 +1,47 @@
+#ifndef PRECOMPOSE_UNICODE_H
+#define PRECOMPOSE_UNICODE_H
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <iconv.h>
+
+
+typedef struct dirent_prec_psx {
+	ino_t d_ino;            /* Posix */
+	size_t max_name_len;    /* See below */
+	unsigned char d_type;   /* available on all systems git runs on */
+
+	/*
+	 * See http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/dirent.h.html
+	 * NAME_MAX + 1 should be enough, but some systems have
+	 * NAME_MAX=255 and strlen(d_name) may return 508 or 510
+	 * Solution: allocate more when needed, see precompose_utf8_readdir()
+	 */
+	char   d_name[NAME_MAX+1];
+} dirent_prec_psx;
+
+
+typedef struct {
+	iconv_t ic_precompose;
+	DIR *dirp;
+	struct dirent_prec_psx *dirent_nfc;
+} PREC_DIR;
+
+const char *precompose_argv_prefix(int argc, const char **argv, const char *prefix);
+const char *precompose_string_if_needed(const char *in);
+void probe_utf8_pathname_composition(void);
+
+PREC_DIR *precompose_utf8_opendir(const char *dirname);
+struct dirent_prec_psx *precompose_utf8_readdir(PREC_DIR *dirp);
+int precompose_utf8_closedir(PREC_DIR *dirp);
+
+#ifndef PRECOMPOSE_UNICODE_C
+#define dirent dirent_prec_psx
+#define opendir(n) precompose_utf8_opendir(n)
+#define readdir(d) precompose_utf8_readdir(d)
+#define closedir(d) precompose_utf8_closedir(d)
+#define DIR PREC_DIR
+#endif /* PRECOMPOSE_UNICODE_C */
+
+#endif /* PRECOMPOSE_UNICODE_H */
diff --git a/compat/qsort_s.c b/compat/qsort_s.c
new file mode 100644
index 0000000000..0f7ff30f5f
--- /dev/null
+++ b/compat/qsort_s.c
@@ -0,0 +1,63 @@
+#include "../git-compat-util.h"
+
+/*
+ * A merge sort implementation, simplified from the qsort implementation
+ * by Mike Haertel, which is a part of the GNU C Library.
+ * Added context pointer, safety checks and return value.
+ */
+
+static void msort_with_tmp(void *b, size_t n, size_t s,
+			   int (*cmp)(const void *, const void *, void *),
+			   char *t, void *ctx)
+{
+	char *tmp;
+	char *b1, *b2;
+	size_t n1, n2;
+
+	if (n <= 1)
+		return;
+
+	n1 = n / 2;
+	n2 = n - n1;
+	b1 = b;
+	b2 = (char *)b + (n1 * s);
+
+	msort_with_tmp(b1, n1, s, cmp, t, ctx);
+	msort_with_tmp(b2, n2, s, cmp, t, ctx);
+
+	tmp = t;
+
+	while (n1 > 0 && n2 > 0) {
+		if (cmp(b1, b2, ctx) <= 0) {
+			memcpy(tmp, b1, s);
+			tmp += s;
+			b1 += s;
+			--n1;
+		} else {
+			memcpy(tmp, b2, s);
+			tmp += s;
+			b2 += s;
+			--n2;
+		}
+	}
+	if (n1 > 0)
+		memcpy(tmp, b1, n1 * s);
+	memcpy(b, t, (n - n2) * s);
+}
+
+int git_qsort_s(void *b, size_t n, size_t s,
+		int (*cmp)(const void *, const void *, void *), void *ctx)
+{
+	const size_t size = st_mult(n, s);
+	char *tmp;
+
+	if (!n)
+		return 0;
+	if (!b || !cmp)
+		return -1;
+
+	tmp = xmalloc(size);
+	msort_with_tmp(b, n, s, cmp, tmp, ctx);
+	free(tmp);
+	return 0;
+}
diff --git a/compat/regcomp_enhanced.c b/compat/regcomp_enhanced.c
new file mode 100644
index 0000000000..84193ce53b
--- /dev/null
+++ b/compat/regcomp_enhanced.c
@@ -0,0 +1,9 @@
+#include "../git-compat-util.h"
+#undef regcomp
+
+int git_regcomp(regex_t *preg, const char *pattern, int cflags)
+{
+	if (!(cflags & REG_EXTENDED))
+		cflags |= REG_ENHANCED;
+	return regcomp(preg, pattern, cflags);
+}
diff --git a/compat/regex/regcomp.c b/compat/regex/regcomp.c
new file mode 100644
index 0000000000..8d93a9b93f
--- /dev/null
+++ b/compat/regex/regcomp.c
@@ -0,0 +1,3893 @@
+/* Extended regular expression matching and search library.
+   Copyright (C) 2002-2007,2009,2010 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Isamu Hasegawa <isamu@xxxxxxxxxxxxxx>.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+
+#if defined __TANDEM
+ /* This is currently duplicated from git-compat-utils.h */
+# ifdef NO_INTPTR_T
+ typedef long intptr_t;
+ typedef unsigned long uintptr_t;
+# endif
+#endif
+
+static reg_errcode_t re_compile_internal (regex_t *preg, const char * pattern,
+					  size_t length, reg_syntax_t syntax);
+static void re_compile_fastmap_iter (regex_t *bufp,
+				     const re_dfastate_t *init_state,
+				     char *fastmap);
+static reg_errcode_t init_dfa (re_dfa_t *dfa, size_t pat_len);
+#ifdef RE_ENABLE_I18N
+static void free_charset (re_charset_t *cset);
+#endif /* RE_ENABLE_I18N */
+static void free_workarea_compile (regex_t *preg);
+static reg_errcode_t create_initial_state (re_dfa_t *dfa);
+#ifdef RE_ENABLE_I18N
+static void optimize_utf8 (re_dfa_t *dfa);
+#endif
+static reg_errcode_t analyze (regex_t *preg);
+static reg_errcode_t preorder (bin_tree_t *root,
+			       reg_errcode_t (fn (void *, bin_tree_t *)),
+			       void *extra);
+static reg_errcode_t postorder (bin_tree_t *root,
+				reg_errcode_t (fn (void *, bin_tree_t *)),
+				void *extra);
+static reg_errcode_t optimize_subexps (void *extra, bin_tree_t *node);
+static reg_errcode_t lower_subexps (void *extra, bin_tree_t *node);
+static bin_tree_t *lower_subexp (reg_errcode_t *err, regex_t *preg,
+				 bin_tree_t *node);
+static reg_errcode_t calc_first (void *extra, bin_tree_t *node);
+static reg_errcode_t calc_next (void *extra, bin_tree_t *node);
+static reg_errcode_t link_nfa_nodes (void *extra, bin_tree_t *node);
+static int duplicate_node (re_dfa_t *dfa, int org_idx, unsigned int constraint);
+static int search_duplicated_node (const re_dfa_t *dfa, int org_node,
+				   unsigned int constraint);
+static reg_errcode_t calc_eclosure (re_dfa_t *dfa);
+static reg_errcode_t calc_eclosure_iter (re_node_set *new_set, re_dfa_t *dfa,
+					 int node, int root);
+static reg_errcode_t calc_inveclosure (re_dfa_t *dfa);
+static int fetch_number (re_string_t *input, re_token_t *token,
+			 reg_syntax_t syntax);
+static int peek_token (re_token_t *token, re_string_t *input,
+			reg_syntax_t syntax) internal_function;
+static bin_tree_t *parse (re_string_t *regexp, regex_t *preg,
+			  reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_reg_exp (re_string_t *regexp, regex_t *preg,
+				  re_token_t *token, reg_syntax_t syntax,
+				  int nest, reg_errcode_t *err);
+static bin_tree_t *parse_branch (re_string_t *regexp, regex_t *preg,
+				 re_token_t *token, reg_syntax_t syntax,
+				 int nest, reg_errcode_t *err);
+static bin_tree_t *parse_expression (re_string_t *regexp, regex_t *preg,
+				     re_token_t *token, reg_syntax_t syntax,
+				     int nest, reg_errcode_t *err);
+static bin_tree_t *parse_sub_exp (re_string_t *regexp, regex_t *preg,
+				  re_token_t *token, reg_syntax_t syntax,
+				  int nest, reg_errcode_t *err);
+static bin_tree_t *parse_dup_op (bin_tree_t *dup_elem, re_string_t *regexp,
+				 re_dfa_t *dfa, re_token_t *token,
+				 reg_syntax_t syntax, reg_errcode_t *err);
+static bin_tree_t *parse_bracket_exp (re_string_t *regexp, re_dfa_t *dfa,
+				      re_token_t *token, reg_syntax_t syntax,
+				      reg_errcode_t *err);
+static reg_errcode_t parse_bracket_element (bracket_elem_t *elem,
+					    re_string_t *regexp,
+					    re_token_t *token, int token_len,
+					    re_dfa_t *dfa,
+					    reg_syntax_t syntax,
+					    int accept_hyphen);
+static reg_errcode_t parse_bracket_symbol (bracket_elem_t *elem,
+					  re_string_t *regexp,
+					  re_token_t *token);
+#ifdef RE_ENABLE_I18N
+static reg_errcode_t build_equiv_class (bitset_t sbcset,
+					re_charset_t *mbcset,
+					int *equiv_class_alloc,
+					const unsigned char *name);
+static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
+				      bitset_t sbcset,
+				      re_charset_t *mbcset,
+				      int *char_class_alloc,
+				      const char *class_name,
+				      reg_syntax_t syntax);
+#else  /* not RE_ENABLE_I18N */
+static reg_errcode_t build_equiv_class (bitset_t sbcset,
+					const unsigned char *name);
+static reg_errcode_t build_charclass (RE_TRANSLATE_TYPE trans,
+				      bitset_t sbcset,
+				      const char *class_name,
+				      reg_syntax_t syntax);
+#endif /* not RE_ENABLE_I18N */
+static bin_tree_t *build_charclass_op (re_dfa_t *dfa,
+				       RE_TRANSLATE_TYPE trans,
+				       const char *class_name,
+				       const char *extra,
+				       int non_match, reg_errcode_t *err);
+static bin_tree_t *create_tree (re_dfa_t *dfa,
+				bin_tree_t *left, bin_tree_t *right,
+				re_token_type_t type);
+static bin_tree_t *create_token_tree (re_dfa_t *dfa,
+				      bin_tree_t *left, bin_tree_t *right,
+				      const re_token_t *token);
+static bin_tree_t *duplicate_tree (const bin_tree_t *src, re_dfa_t *dfa);
+static void free_token (re_token_t *node);
+static reg_errcode_t free_tree (void *extra, bin_tree_t *node);
+static reg_errcode_t mark_opt_subexp (void *extra, bin_tree_t *node);
+
+/* This table gives an error message for each of the error codes listed
+   in regex.h.  Obviously the order here has to be same as there.
+   POSIX doesn't require that we do anything for REG_NOERROR,
+   but why not be nice?  */
+
+const char __re_error_msgid[] attribute_hidden =
+  {
+#define REG_NOERROR_IDX	0
+    gettext_noop ("Success")	/* REG_NOERROR */
+    "\0"
+#define REG_NOMATCH_IDX (REG_NOERROR_IDX + sizeof "Success")
+    gettext_noop ("No match")	/* REG_NOMATCH */
+    "\0"
+#define REG_BADPAT_IDX	(REG_NOMATCH_IDX + sizeof "No match")
+    gettext_noop ("Invalid regular expression") /* REG_BADPAT */
+    "\0"
+#define REG_ECOLLATE_IDX (REG_BADPAT_IDX + sizeof "Invalid regular expression")
+    gettext_noop ("Invalid collation character") /* REG_ECOLLATE */
+    "\0"
+#define REG_ECTYPE_IDX	(REG_ECOLLATE




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux